CINXE.COM

<!DOCTYPE html> <html lang="en-US" > <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover" /> <meta http-equiv="x-dns-prefetch-control" content="on" /> <title class="notranslate">MechHub</title> <meta name="keywords" content="MechHub"> <meta name="description" content="MechHub"> <meta http-equiv="x-dns-prefetch-control" content="on"> <link rel="dns-prefetch" href="https://static.staticxt.com"> <link rel="canonical" href="http://mechhub.ishoptop.com/"> <link rel="shortcut icon" href="https://cdn-shoptop-com.oss-accelerate.aliyuncs.com/1805808998836047873.jpg"> <meta name="format-detection" content="telephone=no, email=no"> <meta property="og:site_name" content="MechHub>"> <meta property="og:url" content="http://mechhub.ishoptop.com/"> <meta property="og:title" content="MechHub"> <meta property="og:type" content="website"> <meta property="og:description" content="MechHub"> <meta name="twitter:card" content="summary_large_image"> <meta name="twitter:title" content="MechHub"> <meta name="twitter:description" content="MechHub"> <style> :root { --font-body-family: Archivo,sans-serif; --font-body-style: normal; --font-body-weight: 400; --font-body-weight-bold: 700; --font-heading-family: Exo 2,sans-serif; --font-heading-style: normal; --font-heading-weight: 600; --font-base-scale: 1; --font-heading-scale: 1.05; --color-base-bg: 255,255,255; --color-base-text: 8,36,87; --color-btn-bg: 228,102,42; --color-btn-text: 8,36,87; --color-secondary-btn-text: 7,69,184; --color-shadow-base: 195,195,195; --color-discount-price: 105,105,105; --color-off-tag-bg: 102,102,102; --color-off-tag-text: 255,255,255; --color-sold-out-bg: 227,227,227; --color-sold-out-text: 153,153,153; --color-bg-1: 242,243,245; --color-bg-gradient-1: #F2F3F5; --color-text-1: 8,36,87; --color-btn-bg-1: 8,36,87; --color-btn-text-1: 228,102,42; --color-secondary-btn-text-1: 241,84,10; --color-shadow-1: 104,104,104; --color-bg-2: 8,36,87; --color-bg-gradient-2: #082457; --color-text-2: 255,255,255; --color-btn-bg-2: 228,102,42; --color-btn-text-2: 255,255,255; --color-secondary-btn-text-2: 248,89,5; --color-shadow-2: 116,116,116; --color-bg-3: 228,102,42; --color-bg-gradient-3: #E4662A; --color-text-3: 255,255,255; --color-btn-bg-3: 8,36,87; --color-btn-text-3: 255,255,255; --color-secondary-btn-text-3: 8,36,87; --color-shadow-3: 144,144,144; --color-bg-4: 224,224,224; --color-bg-gradient-4: #E0E0E0; --color-text-4: 8,36,87; --color-btn-bg-4: 255,160,0; --color-btn-text-4: 55,176,143; --color-secondary-btn-text-4: 0,0,0; --color-shadow-4: 255,255,255; --media-padding: px; --media-border-opacity: 0.2; --media-border-width: 0px; --media-radius: 8px; --media-shadow-opacity: 0.2; --media-shadow-horizontal-offset: 0px; --media-shadow-vertical-offset: 0px; --media-shadow-blur-radius: 5px; --media-shadow-visible: 1; --page-width: 140rem; --page-width-margin: 0rem; --product-card-image-padding: 0rem; --product-card-corner-radius: 0.4rem; --product-card-text-alignment: center; --product-card-border-width: 0.1rem; --product-card-border-opacity: 0.1; --product-card-shadow-opacity: 0.1; --product-card-shadow-visible: 1; --product-card-shadow-horizontal-offset: 0rem; --product-card-shadow-vertical-offset: 0rem; --product-card-shadow-blur-radius: 1rem; --collection-card-image-padding: 0rem; --collection-card-corner-radius: 0.4rem; --collection-card-text-alignment: center; --collection-card-border-width: 0.1rem; --collection-card-border-opacity: 0.05; --collection-card-shadow-opacity: 0.05; --collection-card-shadow-visible: 1; --collection-card-shadow-horizontal-offset: 0rem; --collection-card-shadow-vertical-offset: 0rem; --collection-card-shadow-blur-radius: 1rem; --blog-card-image-padding: 0rem; --blog-card-corner-radius: 0.2rem; --blog-card-text-alignment: left; --blog-card-border-width: 0.1rem; --blog-card-border-opacity: 0.45; --blog-card-shadow-opacity: 0.1; --blog-card-shadow-visible: 1; --blog-card-shadow-horizontal-offset: 0rem; --blog-card-shadow-vertical-offset: 0rem; --blog-card-shadow-blur-radius: 0rem; --badge-corner-radius: 4rem; --popup-border-width: 1px; --popup-border-opacity: 0.1; --popup-corner-radius: 0px; --popup-shadow-opacity: 0; --popup-shadow-horizontal-offset: 0px; --popup-shadow-vertical-offset: 0px; --popup-shadow-blur-radius: 0px; --drawer-border-width: 0px; --drawer-border-opacity: 0; --drawer-shadow-opacity: 0; --drawer-shadow-horizontal-offset: 0px; --drawer-shadow-vertical-offset: 0px; --drawer-shadow-blur-radius: 0px; --spacing-sections-desktop: 0px; --spacing-sections-mobile: 0px; --grid-desktop-vertical-spacing: 24px; --grid-desktop-horizontal-spacing: 24px; --grid-mobile-vertical-spacing: 12px; --grid-mobile-horizontal-spacing: 12px; --text-boxes-border-opacity: 0.15; --text-boxes-border-width: 0px; --text-boxes-radius: 6px; --text-boxes-shadow-opacity: 0; --text-boxes-shadow-visible: 0; --text-boxes-shadow-horizontal-offset: 0px; --text-boxes-shadow-vertical-offset: 0px; --text-boxes-shadow-blur-radius: 0px; --buttons-radius: 6px; --buttons-radius-outset: 7px; --buttons-border-width: 1px; --buttons-border-opacity: 0.5; --buttons-shadow-opacity: 0.3; --buttons-shadow-visible: 1; --buttons-shadow-horizontal-offset: 4px; --buttons-shadow-vertical-offset: 4px; --buttons-shadow-blur-radius: 0px; --buttons-border-offset: 0.6px; --inputs-radius: 8px; --inputs-border-width: 1px; --inputs-border-opacity: 0.2; --inputs-shadow-opacity: 0.2; --inputs-shadow-horizontal-offset: 0px; --inputs-margin-offset: 0px; --inputs-shadow-vertical-offset: 0px; --inputs-shadow-blur-radius: 0px; --inputs-radius-outset:9px; --variant-pills-radius: 40px; --variant-pills-border-width: 1px; --variant-pills-border-opacity: 0.55; --variant-pills-shadow-opacity: 0.95; --variant-pills-shadow-horizontal-offset: 0px; --variant-pills-shadow-vertical-offset: 0px; --variant-pills-shadow-blur-radius: 10px; } *, *::before, *::after { box-sizing: inherit; } html { box-sizing: border-box; font-size: calc(var(--font-base-scale) * 62.5%); height: 100%; } body { display: grid; grid-template-rows: auto auto 1fr auto; grid-template-columns: 100%; min-height: 100%; margin: 0; font-size: 1.5rem; letter-spacing: 0.06rem; line-height: calc(1 + 0.8 / var(--font-base-scale)); font-family: var(--font-body-family); font-style: var(--font-body-style); font-weight: var(--font-body-weight); } @media screen and (min-width: 750px) { body { font-size: 1.6rem; } } @font-face { font-family: 'Exo 2'; font-style: normal; font-weight: 600; font-display: swap; src: url(https://fonts.gstatic.com/s/exo2/v19/7cH1v4okm5zmbvwkAx_sfcEuiD8jYPWsOdC_.woff2) format('woff2');} @font-face { font-family: 'Archivo'; font-style: normal; font-weight: 400; font-stretch: normal; font-display: swap; src: url(https://fonts.gstatic.com/s/archivo/v16/k3k6o8UDI-1M0wlSV9XAw6lQkqWY8Q82sJaRE-NWIDdgffTTNDNZ9xdp.woff2) format('woff2');} </style> <script> window.breakpoint = 768; window.STORE_PARAMS = { shopId: '195905', symbolLeft: '$', symbolRight: '', symbol: '$', shopName: 'MechHub', shopCurrency: 'USD', defaultImage: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==', imageDomain: 'https://img.staticxt.com', cdnDomain: 'https://static.staticxt.com', templateType: '1', templateName: 'index', templateSuffix: '', paymentSettings: { paypalJs: '', loginAuthority: 'all', merchantId: '' } } window.theme = {} </script> <script>window.SHOPTOP={ saSdkUrl:"https://static.staticxt.com", saServerUrl:"https://r.shoptop.com", asstetsUrl:"https://assets.staticxt.com", theme: {"name":"rapid-fly","id":"3"},locale:"en_US",}</script><script>(function () { function asyncLoad() { var urls = ["cart_active-1d42d7e5.js","xt-shipping-time-97a8d7e7.js","translate-232a1f69.js","social_login-def52ec4.js"]; for (var i = 0; i < urls.length; i++) { var s = document.createElement('script'); s.type = 'text/javascript'; s.async = true; s.src = STORE_PARAMS.cdnDomain + "/apps/" + urls[i]; var x = document.getElementsByTagName('script')[0]; x.parentNode.insertBefore(s, x); } }; if (window.attachEvent) { window.attachEvent('onload', asyncLoad); } else { window.addEventListener('load', asyncLoad, false); } })();</script><script>!function(){"use strict";function n(n,t){var e,r=Object.keys(n);return Object.getOwnPropertySymbols&&(e=Object.getOwnPropertySymbols(n),t&&(e=e.filter(function(t){return Object.getOwnPropertyDescriptor(n,t).enumerable})),r.push.apply(r,e)),r}function e(r){for(var t=1;t<arguments.length;t++){var o=null!=arguments[t]?arguments[t]:{};t%2?n(Object(o),!0).forEach(function(t){var n,e;n=r,e=o[t=t],t in n?Object.defineProperty(n,t,{value:e,enumerable:!0,configurable:!0,writable:!0}):n[t]=e}):Object.getOwnPropertyDescriptors?Object.defineProperties(r,Object.getOwnPropertyDescriptors(o)):n(Object(o)).forEach(function(t){Object.defineProperty(r,t,Object.getOwnPropertyDescriptor(o,t))})}return r}function _(){_=function(){return a};var a={},t=Object.prototype,s=t.hasOwnProperty,n="function"==typeof Symbol?Symbol:{},r=n.iterator||"@@iterator",e=n.asyncIterator||"@@asyncIterator",o=n.toStringTag||"@@toStringTag";function i(t,n,e){return Object.defineProperty(t,n,{value:e,enumerable:!0,configurable:!0,writable:!0}),t[n]}try{i({},"")}catch(a){i=function(t,n,e){return t[n]=e}}function c(t,n,e,r){var o,i,a,c,n=n&&n.prototype instanceof p?n:p,n=Object.create(n.prototype),r=new b(r||[]);return n._invoke=(o=t,i=e,a=r,c="suspendedStart",function(t,n){if("executing"===c)throw new Error("Generator is already running");if("completed"===c){if("throw"===t)throw n;return O()}for(a.method=t,a.arg=n;;){var e=a.delegate;if(e){e=function t(n,e){var r=n.iterator[e.method];if(void 0===r){if(e.delegate=null,"throw"===e.method){if(n.iterator.return&&(e.method="return",e.arg=void 0,t(n,e),"throw"===e.method))return l;e.method="throw",e.arg=new TypeError("The iterator does not provide a 'throw' method")}return l}r=u(r,n.iterator,e.arg);if("throw"===r.type)return e.method="throw",e.arg=r.arg,e.delegate=null,l;r=r.arg;return r?r.done?(e[n.resultName]=r.value,e.next=n.nextLoc,"return"!==e.method&&(e.method="next",e.arg=void 0),e.delegate=null,l):r:(e.method="throw",e.arg=new TypeError("iterator result is not an object"),e.delegate=null,l)}(e,a);if(e){if(e===l)continue;return e}}if("next"===a.method)a.sent=a._sent=a.arg;else if("throw"===a.method){if("suspendedStart"===c)throw c="completed",a.arg;a.dispatchException(a.arg)}else"return"===a.method&&a.abrupt("return",a.arg);c="executing";e=u(o,i,a);if("normal"===e.type){if(c=a.done?"completed":"suspendedYield",e.arg===l)continue;return{value:e.arg,done:a.done}}"throw"===e.type&&(c="completed",a.method="throw",a.arg=e.arg)}}),n}function u(t,n,e){try{return{type:"normal",arg:t.call(n,e)}}catch(t){return{type:"throw",arg:t}}}a.wrap=c;var l={};function p(){}function f(){}function h(){}var n={},d=(i(n,r,function(){return this}),Object.getPrototypeOf),d=d&&d(d(x([]))),g=(d&&d!==t&&s.call(d,r)&&(n=d),h.prototype=p.prototype=Object.create(n));function y(t){["next","throw","return"].forEach(function(n){i(t,n,function(t){return this._invoke(n,t)})})}function m(a,c){var n;this._invoke=function(e,r){function t(){return new c(function(t,n){!function n(t,e,r,o){var i,t=u(a[t],a,e);if("throw"!==t.type)return(e=(i=t.arg).value)&&"object"==typeof e&&s.call(e,"__await")?c.resolve(e.__await).then(function(t){n("next",t,r,o)},function(t){n("throw",t,r,o)}):c.resolve(e).then(function(t){i.value=t,r(i)},function(t){return n("throw",t,r,o)});o(t.arg)}(e,r,t,n)})}return n=n?n.then(t,t):t()}}function v(t){var n={tryLoc:t[0]};1 in t&&(n.catchLoc=t[1]),2 in t&&(n.finallyLoc=t[2],n.afterLoc=t[3]),this.tryEntries.push(n)}function w(t){var n=t.completion||{};n.type="normal",delete n.arg,t.completion=n}function b(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(v,this),this.reset(!0)}function x(n){if(n){var e,t=n[r];if(t)return t.call(n);if("function"==typeof n.next)return n;if(!isNaN(n.length))return e=-1,(t=function t(){for(;++e<n.length;)if(s.call(n,e))return t.value=n[e],t.done=!1,t;return t.value=void 0,t.done=!0,t}).next=t}return{next:O}}function O(){return{value:void 0,done:!0}}return i(g,"constructor",f.prototype=h),i(h,"constructor",f),f.displayName=i(h,o,"GeneratorFunction"),a.isGeneratorFunction=function(t){t="function"==typeof t&&t.constructor;return!!t&&(t===f||"GeneratorFunction"===(t.displayName||t.name))},a.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,h):(t.__proto__=h,i(t,o,"GeneratorFunction")),t.prototype=Object.create(g),t},a.awrap=function(t){return{__await:t}},y(m.prototype),i(m.prototype,e,function(){return this}),a.AsyncIterator=m,a.async=function(t,n,e,r,o){void 0===o&&(o=Promise);var i=new m(c(t,n,e,r),o);return a.isGeneratorFunction(n)?i:i.next().then(function(t){return t.done?t.value:i.next()})},y(g),i(g,o,"Generator"),i(g,r,function(){return this}),i(g,"toString",function(){return"[object Generator]"}),a.keys=function(e){var t,r=[];for(t in e)r.push(t);return r.reverse(),function t(){for(;r.length;){var n=r.pop();if(n in e)return t.value=n,t.done=!1,t}return t.done=!0,t}},a.values=x,b.prototype={constructor:b,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=void 0,this.done=!1,this.delegate=null,this.method="next",this.arg=void 0,this.tryEntries.forEach(w),!t)for(var n in this)"t"===n.charAt(0)&&s.call(this,n)&&!isNaN(+n.slice(1))&&(this[n]=void 0)},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(e){if(this.done)throw e;var r=this;function t(t,n){return i.type="throw",i.arg=e,r.next=t,n&&(r.method="next",r.arg=void 0),!!n}for(var n=this.tryEntries.length-1;0<=n;--n){var o=this.tryEntries[n],i=o.completion;if("root"===o.tryLoc)return t("end");if(o.tryLoc<=this.prev){var a=s.call(o,"catchLoc"),c=s.call(o,"finallyLoc");if(a&&c){if(this.prev<o.catchLoc)return t(o.catchLoc,!0);if(this.prev<o.finallyLoc)return t(o.finallyLoc)}else if(a){if(this.prev<o.catchLoc)return t(o.catchLoc,!0)}else{if(!c)throw new Error("try statement without catch or finally");if(this.prev<o.finallyLoc)return t(o.finallyLoc)}}}},abrupt:function(t,n){for(var e=this.tryEntries.length-1;0<=e;--e){var r=this.tryEntries[e];if(r.tryLoc<=this.prev&&s.call(r,"finallyLoc")&&this.prev<r.finallyLoc){var o=r;break}}var i=(o=o&&("break"===t||"continue"===t)&&o.tryLoc<=n&&n<=o.finallyLoc?null:o)?o.completion:{};return i.type=t,i.arg=n,o?(this.method="next",this.next=o.finallyLoc,l):this.complete(i)},complete:function(t,n){if("throw"===t.type)throw t.arg;return"break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&n&&(this.next=n),l},finish:function(t){for(var n=this.tryEntries.length-1;0<=n;--n){var e=this.tryEntries[n];if(e.finallyLoc===t)return this.complete(e.completion,e.afterLoc),w(e),l}},catch:function(t){for(var n=this.tryEntries.length-1;0<=n;--n){var e,r,o=this.tryEntries[n];if(o.tryLoc===t)return"throw"===(e=o.completion).type&&(r=e.arg,w(o)),r}throw new Error("illegal catch attempt")},delegateYield:function(t,n,e){return this.delegate={iterator:x(t),resultName:n,nextLoc:e},"next"===this.method&&(this.arg=void 0),l}},a}function s(t,n,e,r,o,i,a){try{var c=t[i](a),s=c.value}catch(t){return e(t)}c.done?n(s):Promise.resolve(s).then(r,o)}function r(t,n){if(!(t instanceof n))throw new TypeError("Cannot call a class as a function")}function o(t,n){for(var e=0;e<n.length;e++){var r=n[e];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}function t(t,n,e){n&&o(t.prototype,n),e&&o(t,e),Object.defineProperty(t,"prototype",{writable:!1})}function i(t,n){if("function"!=typeof n&&null!==n)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(n&&n.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),n&&c(t,n)}function a(t){return(a=Object.setPrototypeOf?Object.getPrototypeOf.bind():function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function c(t,n){return(c=Object.setPrototypeOf?Object.setPrototypeOf.bind():function(t,n){return t.__proto__=n,t})(t,n)}function u(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],function(){})),!0}catch(t){return!1}}function l(t,n,e){return(l=u()?Reflect.construct.bind():function(t,n,e){var r=[null],n=(r.push.apply(r,n),new(Function.bind.apply(t,r)));return e&&c(n,e.prototype),n}).apply(null,arguments)}function p(t){var e="function"==typeof Map?new Map:void 0;return(p=function(t){if(null===t||-1===Function.toString.call(t).indexOf("[native code]"))return t;if("function"!=typeof t)throw new TypeError("Super expression must either be null or a function");if(void 0!==e){if(e.has(t))return e.get(t);e.set(t,n)}function n(){return l(t,arguments,a(this).constructor)}return n.prototype=Object.create(t.prototype,{constructor:{value:n,enumerable:!1,writable:!0,configurable:!0}}),c(n,t)})(t)}function f(e){var r=u();return function(){var t,n=a(e),n=(t=r?(t=a(this).constructor,Reflect.construct(n,arguments,t)):n.apply(this,arguments),this);if(t&&("object"==typeof t||"function"==typeof t))return t;if(void 0!==t)throw new TypeError("Derived constructors may only return object or undefined");if(void 0===(t=n))throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}}window.Shoptop||(window.Shoptop={});var h={hub:Object.create(null),emit:function(t,n){(this.hub[t]||[]).forEach(function(t){return t(n)})},on:function(t,n){this.hub[t]||(this.hub[t]=[]),this.hub[t].push(n)}};function d(){var t;document.querySelector(".j-plugin-wrappers")||(t=(t=document.querySelector(".product-info__header_price-wrapper"))?t:document.querySelector(".product-info__variants-wrap")).insertAdjacentHTML("afterend",'<div class="j-plugin-wrappers"></div>')}window.Shoptop.event=h,window._XT_=function(t,n){this[t]=n},h.on("shoptop:product:change",function(t){window._XT_["xt.product"]=t}),window.Shoptop.APPS_EVENT={getProduct:function(){return"hope"===SHOPTOP.theme.name?$(document).data("xtproduct"):window._XT_["xt.product"]||""},globalFinance:function(t,n){return n=n||"amount",STORE_PARAMS.symbol+(t=parseFloat(t)/100,e="\\d(?=(\\d{"+((n={amount:{n:2,x:3,s:",",c:"."},amount_no_decimals:{n:0,x:3,s:",",c:""},amount_with_comma_separator:{n:2,x:3,s:".",c:","},amount_no_decimals_with_comma_separator:{n:0,x:3,s:".",c:""},amount_with_apostrophe_separator:{n:2,x:3,s:"'",c:"."}}[n]||"amount").x||3)+"})+"+(0<n.n?"\\D":"$")+")",t=0===n.n?t.toFixed(0):t.toFixed(n.n+1).slice(0,-1),(n.c?t.replace(".",n.c):t).replace(new RegExp(e,"g"),"$&"+(n.s||",")));var e},toast:{defaultOptions:{content:"Success",type:"info",timeOut:2500,scrollHide:!1},show:function(t){t=e(e({},this.defaultOptions),t);t=document.createRange().createContextualFragment('<shoptop-global-toast type="'.concat(t.type,'" scrollHide="').concat(t.scrollHide,'" timeOut="').concat(t.timeOut,'">').concat(t.content,"</shoptop-global-toast>"));document.body.appendChild(t)},success:function(t){this.show({type:"success",content:t})},error:function(t){this.show({type:"error",content:t})},warning:function(t){this.show({type:"warning",content:t})},info:function(t){this.show({type:"info",content:t})}},loading:{state:0,show:function(){var t;return 0===this.state&&(t=document.createRange().createContextualFragment("<shoptop-global-loading></shoptop-global-loading>"),document.body.appendChild(t),this.state=1),this},hide:function(){return 1===this.state&&(document.querySelector("shoptop-global-loading").remove(),this.state=0),this},getState:function(){return this.state}},cookie:{get:function(t){return"; ".concat(document.cookie).split("; ".concat(t,"=")).pop().split(";").shift()}},date:{format:function(t){var n,e;return t=t,n="YYYY-MM-DD"===(1<arguments.length&&void 0!==arguments[1]?arguments[1]:"YYYY-MM-DD")?{year:"numeric",month:"long",day:"numeric"}:{year:"numeric",month:"long",day:"numeric",hour:"2-digit",minute:"2-digit",second:"2-digit"},e=(e=document.documentElement.lang||"en-US").replace(/_/g,"-"),t=new Date(t).getTime()-288e5,t=new Date(t),new Intl.DateTimeFormat(e,n).format(t)},ISO:function(t){t=new Date(t).getTime()-288e5;return new Date(t).toISOString()}}},window.Shoptop.APPS_PLUGINS={plugins:[],validate:function(){var o=this,c=_().mark(function t(){var n,e,r;return _().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:n=[],e=o,t.t0=_().keys(e.plugins);case 3:if((t.t1=t.t0()).done){t.next=11;break}return r=t.t1.value,t.next=7,e.plugins[r].plugin.validate();case 7:r=t.sent,n.push(r),t.next=3;break;case 11:return t.abrupt("return",n);case 12:case"end":return t.stop()}},t)});return function(){var t=this,a=arguments;return new Promise(function(n,e){var r=c.apply(t,a);function o(t){s(r,n,e,o,i,"next",t)}function i(t){s(r,n,e,o,i,"throw",t)}o(void 0)})}()},add:function(t,n){this.plugins.push({name:t,plugin:n})},remove:function(t){delete this.plugins[t]}},window.addEventListener("DOMContentLoaded",function(){"product"===STORE_PARAMS.templateName&&d(),document.addEventListener("shoptop:section:load",function(){"product"===STORE_PARAMS.templateName&&d()})});i(y,p(HTMLElement)),g=f(y),t(y,[{key:"hide",value:function(){var t=this;setTimeout(function(){t.remove()},750)}},{key:"getIcons",value:function(t){return{info:"",warning:'<div class="toast-svg" warning>\n <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd"></path></svg>\n </div>',success:'<div class="toast-svg" success>\n <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"></path></svg>\n </div>',error:'<div class="toast-svg" error>\n <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"></path></svg>\n </div>'}[t]}},{key:"getTemplate",value:function(){var t=this.getIcons(this.type);return'\n <style>\n .fade-in-top {\n -webkit-animation: fade-in-top 0.6s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;\n animation: fade-in-top 0.6s cubic-bezier(0.390, 0.575, 0.565, 1.000) both;\n }\n @-webkit-keyframes fade-in-top {\n 0% {\n -webkit-transform: translateY(-50px);\n transform: translateY(-50px);\n opacity: 0;\n }\n 100% {\n -webkit-transform: translateY(0);\n transform: translateY(0);\n opacity: 1;\n }\n }\n @keyframes fade-in-top {\n 0% {\n -webkit-transform: translateY(-50px);\n transform: translateY(-50px);\n opacity: 0;\n }\n 100% {\n -webkit-transform: translateY(0);\n transform: translateY(0);\n opacity: 1;\n }\n }\n .fade-out-top {\n -webkit-animation: fade-out-top 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;\n animation: fade-out-top 0.7s cubic-bezier(0.250, 0.460, 0.450, 0.940) both;\n }\n @-webkit-keyframes fade-out-top {\n 0% {\n -webkit-transform: translateY(0);\n transform: translateY(0);\n opacity: 1;\n }\n 100% {\n -webkit-transform: translateY(-50px);\n transform: translateY(-50px);\n opacity: 0;\n }\n }\n @keyframes fade-out-top {\n 0% {\n -webkit-transform: translateY(0);\n transform: translateY(0);\n opacity: 1;\n }\n 100% {\n -webkit-transform: translateY(-50px);\n transform: translateY(-50px);\n opacity: 0;\n }\n }\n .toast {\n position: fixed;\n top: 30px;\n right: 0;\n left: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n z-index: 1050;\n }\n .toast-wrap {\n display: flex;\n align-items: center;\n padding: 16px;\n margin-bottom: 16px;\n width: 100%;\n max-width: 388px;\n color: rgb(107, 114, 128);\n background: #fff;\n box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\n border-radius: 8px;\n }\n .toast-svg {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border-radius: 8px;\n margin-right: 12px;\n }\n .toast-svg[warning] {\n color: rgb(249, 115, 22);\n background: rgb(255, 237, 213);\n }\n .toast-svg[success] {\n color: rgb(34, 197, 94);\n background: rgb(220, 252, 231);\n }\n .toast-svg[error] {\n color: rgb(239, 68, 68);\n background: rgb(254, 226, 226);\n }\n .toast-svg svg {\n width: 20px;\n height: 20px;\n }\n .toast-content {\n font-size: 14px;\n line-height: 20px;\n font-weight: 400;\n }\n </style>\n <div class="toast fade-in-top">\n <div class="toast-wrap">\n '.concat(t,'\n <div class="toast-content"><slot></slot></div>\n </div>\n </div>')}}]);var g,h=y;function y(){r(this,y),(t=g.call(this))._root=t.attachShadow({mode:"open"}),t.type=t.getAttribute("type")||"info",t.timeOut=t.getAttribute("timeOut")||2500;var t,n=t.getTemplate();return t._root.innerHTML=n,setTimeout(function(){t._root.querySelector(".toast").classList.add("fade-out-top"),t.hide()},t.timeOut),t}customElements.define("shoptop-global-toast",h);i(v,p(HTMLElement)),m=f(v),t(v,[{key:"getTemplate",value:function(){return'<style>\n .loading-wrap {\n position: fixed;\n left: 0;\n right: 0;\n top: 0;\n bottom: 0;\n display: flex;\n justify-content: center;\n align-items: center;\n background: rgba(0, 0, 0, 0.3);\n z-index: 1070;\n }\n .loading {\n width: 20px;\n height: 20px;\n border: 2px solid #fff;\n border-top-color: transparent;\n border-radius: 100%;\n animation: circle infinite 0.75s linear;\n }\n\n @keyframes circle {\n 0% {\n transform: rotate(0);\n }\n 100% {\n transform: rotate(360deg);\n }\n }\n </style>\n <div class="loading-wrap">\n <div>\n <div class="loading"></div>\n </div>\n </div>'}}]);var m,h=v;function v(){r(this,v),(t=m.call(this))._root=t.attachShadow({mode:"open"});var t,n=t.getTemplate();return t._root.innerHTML=n,t}customElements.define("shoptop-global-loading",h)}(); </script><script>!function(){"use strict";function T(){T=function(){return c};var c={},t=Object.prototype,s=t.hasOwnProperty,e="function"==typeof Symbol?Symbol:{},r=e.iterator||"@@iterator",n=e.asyncIterator||"@@asyncIterator",i=e.toStringTag||"@@toStringTag";function o(t,e,n){return Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{o({},"")}catch(c){o=function(t,e,n){return t[e]=n}}function a(t,e,n,r){var i,o,c,a,e=e&&e.prototype instanceof p?e:p,e=Object.create(e.prototype),r=new I(r||[]);return e._invoke=(i=t,o=n,c=r,a="suspendedStart",function(t,e){if("executing"===a)throw new Error("Generator is already running");if("completed"===a){if("throw"===t)throw e;return w()}for(c.method=t,c.arg=e;;){var n=c.delegate;if(n){n=function t(e,n){var r=e.iterator[n.method];if(void 0===r){if(n.delegate=null,"throw"===n.method){if(e.iterator.return&&(n.method="return",n.arg=void 0,t(e,n),"throw"===n.method))return d;n.method="throw",n.arg=new TypeError("The iterator does not provide a 'throw' method")}return d}r=u(r,e.iterator,n.arg);if("throw"===r.type)return n.method="throw",n.arg=r.arg,n.delegate=null,d;r=r.arg;return r?r.done?(n[e.resultName]=r.value,n.next=e.nextLoc,"return"!==n.method&&(n.method="next",n.arg=void 0),n.delegate=null,d):r:(n.method="throw",n.arg=new TypeError("iterator result is not an object"),n.delegate=null,d)}(n,c);if(n){if(n===d)continue;return n}}if("next"===c.method)c.sent=c._sent=c.arg;else if("throw"===c.method){if("suspendedStart"===a)throw a="completed",c.arg;c.dispatchException(c.arg)}else"return"===c.method&&c.abrupt("return",c.arg);a="executing";n=u(i,o,c);if("normal"===n.type){if(a=c.done?"completed":"suspendedYield",n.arg===d)continue;return{value:n.arg,done:c.done}}"throw"===n.type&&(a="completed",c.method="throw",c.arg=n.arg)}}),e}function u(t,e,n){try{return{type:"normal",arg:t.call(e,n)}}catch(t){return{type:"throw",arg:t}}}c.wrap=a;var d={};function p(){}function l(){}function h(){}var e={},f=(o(e,r,function(){return this}),Object.getPrototypeOf),f=f&&f(f(k([]))),_=(f&&f!==t&&s.call(f,r)&&(e=f),h.prototype=p.prototype=Object.create(e));function m(t){["next","throw","return"].forEach(function(e){o(t,e,function(t){return this._invoke(e,t)})})}function y(c,a){var e;this._invoke=function(n,r){function t(){return new a(function(t,e){!function e(t,n,r,i){var o,t=u(c[t],c,n);if("throw"!==t.type)return(n=(o=t.arg).value)&&"object"==typeof n&&s.call(n,"__await")?a.resolve(n.__await).then(function(t){e("next",t,r,i)},function(t){e("throw",t,r,i)}):a.resolve(n).then(function(t){o.value=t,r(o)},function(t){return e("throw",t,r,i)});i(t.arg)}(n,r,t,e)})}return e=e?e.then(t,t):t()}}function v(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function g(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function I(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(v,this),this.reset(!0)}function k(e){if(e){var n,t=e[r];if(t)return t.call(e);if("function"==typeof e.next)return e;if(!isNaN(e.length))return n=-1,(t=function t(){for(;++n<e.length;)if(s.call(e,n))return t.value=e[n],t.done=!1,t;return t.value=void 0,t.done=!0,t}).next=t}return{next:w}}function w(){return{value:void 0,done:!0}}return o(_,"constructor",l.prototype=h),o(h,"constructor",l),l.displayName=o(h,i,"GeneratorFunction"),c.isGeneratorFunction=function(t){t="function"==typeof t&&t.constructor;return!!t&&(t===l||"GeneratorFunction"===(t.displayName||t.name))},c.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,h):(t.__proto__=h,o(t,i,"GeneratorFunction")),t.prototype=Object.create(_),t},c.awrap=function(t){return{__await:t}},m(y.prototype),o(y.prototype,n,function(){return this}),c.AsyncIterator=y,c.async=function(t,e,n,r,i){void 0===i&&(i=Promise);var o=new y(a(t,e,n,r),i);return c.isGeneratorFunction(e)?o:o.next().then(function(t){return t.done?t.value:o.next()})},m(_),o(_,i,"Generator"),o(_,r,function(){return this}),o(_,"toString",function(){return"[object Generator]"}),c.keys=function(n){var t,r=[];for(t in n)r.push(t);return r.reverse(),function t(){for(;r.length;){var e=r.pop();if(e in n)return t.value=e,t.done=!1,t}return t.done=!0,t}},c.values=k,I.prototype={constructor:I,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=void 0,this.done=!1,this.delegate=null,this.method="next",this.arg=void 0,this.tryEntries.forEach(g),!t)for(var e in this)"t"===e.charAt(0)&&s.call(this,e)&&!isNaN(+e.slice(1))&&(this[e]=void 0)},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(n){if(this.done)throw n;var r=this;function t(t,e){return o.type="throw",o.arg=n,r.next=t,e&&(r.method="next",r.arg=void 0),!!e}for(var e=this.tryEntries.length-1;0<=e;--e){var i=this.tryEntries[e],o=i.completion;if("root"===i.tryLoc)return t("end");if(i.tryLoc<=this.prev){var c=s.call(i,"catchLoc"),a=s.call(i,"finallyLoc");if(c&&a){if(this.prev<i.catchLoc)return t(i.catchLoc,!0);if(this.prev<i.finallyLoc)return t(i.finallyLoc)}else if(c){if(this.prev<i.catchLoc)return t(i.catchLoc,!0)}else{if(!a)throw new Error("try statement without catch or finally");if(this.prev<i.finallyLoc)return t(i.finallyLoc)}}}},abrupt:function(t,e){for(var n=this.tryEntries.length-1;0<=n;--n){var r=this.tryEntries[n];if(r.tryLoc<=this.prev&&s.call(r,"finallyLoc")&&this.prev<r.finallyLoc){var i=r;break}}var o=(i=i&&("break"===t||"continue"===t)&&i.tryLoc<=e&&e<=i.finallyLoc?null:i)?i.completion:{};return o.type=t,o.arg=e,i?(this.method="next",this.next=i.finallyLoc,d):this.complete(o)},complete:function(t,e){if("throw"===t.type)throw t.arg;return"break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&e&&(this.next=e),d},finish:function(t){for(var e=this.tryEntries.length-1;0<=e;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),g(n),d}},catch:function(t){for(var e=this.tryEntries.length-1;0<=e;--e){var n,r,i=this.tryEntries[e];if(i.tryLoc===t)return"throw"===(n=i.completion).type&&(r=n.arg,g(i)),r}throw new Error("illegal catch attempt")},delegateYield:function(t,e,n){return this.delegate={iterator:k(t),resultName:e,nextLoc:n},"next"===this.method&&(this.arg=void 0),d}},c}function s(t,e,n,r,i,o,c){try{var a=t[o](c),s=a.value}catch(t){return n(t)}a.done?e(s):Promise.resolve(s).then(r,i)}function r(a){return function(){var t=this,c=arguments;return new Promise(function(e,n){var r=a.apply(t,c);function i(t){s(r,e,n,i,o,"next",t)}function o(t){s(r,e,n,i,o,"throw",t)}i(void 0)})}}function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function o(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}function e(t,e,n){e&&o(t.prototype,e),n&&o(t,n),Object.defineProperty(t,"prototype",{writable:!1})}function a(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function c(t){for(var e=document.cookie.split(";"),n=0;n<e.length;n++){var r=e[n].split("="),i=decodeURIComponent(r[0].trim()),r=1<r.length?r[1]:"";if(i==t)return decodeURIComponent(r)}return""}function u(t,e,n){t=encodeURIComponent(t)+"="+encodeURIComponent(e);(n=(n=n instanceof Date?{expires:n}:n)||{}).expires&&((e=new Date).setDate(e.getDate()+n.expires),t+="; expires="+e.toUTCString()),n.path?t+="; path="+n.path:t+="; path=/",n.domain&&(t+="; domain="+n.domain.toString()),n.secure&&(t+="; secure"),document.cookie=t}function d(t,e){window.Shoptop.event.on(t,function(t){e(t)})}var p="dataTrack:productView",l="dataTrack:search",h="dataTrack:addToCart",f="dataTrack:initiateCheckout",_="dataTrack:checkoutStepPayment",m="dataTrack:purchase",y="dataTrack:signUp";function v(t){return{namespace:t.split(":")[1],timeStamp:(new Date).getTime()}}e(x,[{key:"init",value:(K=r(T().mark(function t(){var i,n,r;return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:r=function(e,n,r){i.forEach(function(t){r?fbq("trackSingle",t,e,n,r):fbq("trackSingle",t,e,n)})},i=window.AD_TRACK_FP_MULTI_PIXEL_ID,n=this.shopCurrency,d(p,function(t){var e=v(p),t={content_type:"product",content_ids:[t.selected.skuId||t.skus[0].skuId],value:(t.selected||t).price/100,content_name:t.goodsTitle,currency:n,content_category:""};r("ViewContent",t,{eventID:e.namespace+e.timeStamp})}),d(l,function(t){var e=v(l);r("Search",{search_string:t.searchString},{eventID:e.namespace+e.timeStamp})}),d(h,function(t){var e=v(h),t={content_ids:t.skuId,content_type:"product",content_name:t.goodsTitle,content_category:"",currency:n,value:t.price*t.quantity/100,num_items:t.quantity};r("AddToCart",t,{eventID:e.namespace+e.timeStamp})}),d(f,function(t){var e=v(f),t={content_ids:t.items.map(function(t){return t.variantId}),content_type:"product_group",currency:n,value:t.total/100,num_items:t.items.length};r("InitiateCheckout",t,{eventID:e.namespace+e.timeStamp})}),d(_,function(t){var e=v(_),t={currency:n,value:t.total/100};r("AddPaymentInfo",t,{eventID:e.namespace+e.timeStamp})}),d(m,function(t){var e=v(m),t={shoptop_order_token:t.id,value:t.orderInfo.total/100,currency:n,content_type:"product",content_name:"",content_ids:t.lineItems.map(function(t){return t.variantId}),num_items:t.lineItems.length};r("Purchase",t,{eventID:e.namespace+e.timeStamp})}),d(y,function(){var t=v(y);r("CompleteRegistration",{value:0,currency:n,content_name:"",status:"register"},{eventID:t.namespace+t.timeStamp})});case 10:case"end":return t.stop()}},t,this)})),function(){return K.apply(this,arguments)})}]);var n,g,F,j,U,G,W,M,B,X,$,K,H=x,V=(e(A,[{key:"loadEvent",value:function(){var t,e;this.isLoaded||(t=STORE_PARAMS.customer&&STORE_PARAMS.customer.email||window.ORDER&&window.ORDER.orderEmail||"",e=window.AD_PINTEREST_PIXEL_ID,pintrk("load",e,{em:t}),this.isLoaded=!0)}},{key:"init",value:($=r(T().mark(function t(){var i,o=this;return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:n=e=void 0,window.pintrk||(window.pintrk=function(){window.pintrk.queue.push(Array.prototype.slice.call(arguments))},(e=window.pintrk).queue=[],e.version="3.0",(e=document.createElement("script")).async=!0,e.src="https://s.pinimg.com/ct/core.js",(n=document.getElementsByTagName("script")[0]).parentNode.insertBefore(e,n)),window.addEventListener("load",function(){o.loadEvent(),pintrk("page"),0!=(window.location.pathname||"").indexOf("/products/")&&pintrk("track","pagevisit"),0==(window.location.pathname||"").indexOf("/collections/")&&pintrk("track","viewcategory")},!1),i=this.shopCurrency,d(p,function(t){var e=t.product,t=t.selected,t=t&&t.skuId?t:e.skus[0],e={currency:i,product_ids:[e.spuId],line_items:[{product_category:"",product_id:t.spuId,product_variant_id:t.skuId,product_name:e.goodsTitle,product_price:t.price/100}]};o.loadEvent(),pintrk("track","pagevisit",e)}),d(l,function(t){o.loadEvent(),pintrk("track","search",{search_query:t.searchString})}),d(h,function(t){t={value:parseFloat(t.price*t.quantity/100).toFixed(2),currency:i,line_items:[{product_category:"",product_id:t.skuId,product_name:t.goodsTitle,product_price:Number(t.price),product_quantity:Number(t.quantity||1)}],product_ids:[t.skuId]};o.loadEvent(),pintrk("track","addtocart",t)}),d(m,function(t){var e=0,n=[],r=t.lineItems.map(function(t){return e+=t.quantity,n.push(t.variantId),{product_name:t.variantTitle,product_id:t.variantId,product_quantity:Number(t.quantity),product_price:Number(t.price),product_category:""}}),t={order_id:t.orderInfo.id,value:t.orderInfo.total/100,order_quantity:Number(e),currency:i,line_items:r,product_ids:n};o.loadEvent(),pintrk("track","checkout",t)});case 7:case"end":return t.stop()}var e,n},t,this)})),function(){return $.apply(this,arguments)})}]),A),Y=(e(P,[{key:"init",value:(X=r(T().mark(function t(){var i,e;return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:e=function(t){var e=0;return t.items.forEach(function(t){e+=t.quantity}),{price:Number(t.total)/100,currency:i,item_ids:t.items.map(function(t){return t.variantId}),item_category:"",number_items:e,payment_info_available:0}},i=this.shopCurrency,d(p,function(t){var e=t.product,t=t.selected,t=t&&t.skuId?t:e.skus[0],e={price:t.price/100,item_ids:[t.skuId],item_category:"products",currency:i,number_items:1};snaptr("track","VIEW_CONTENT",e)}),d(l,function(t){snaptr("track","SEARCH",{search_string:t.searchString})}),d(h,function(t){t={price:parseFloat(t.price*t.quantity/100).toFixed(2),currency:i,item_ids:[t.skuId],number_items:t.quantity,item_category:""};snaptr("track","ADD_CART",t)}),d(f,function(t){t=e(t);snaptr("track","START_CHECKOUT",t)}),d(_,function(t){t=e(t);t.payment_info_available=1,snaptr("track","ADD_BILLING",t)}),d(m,function(t){var e=0,n=[],r=[],t=(t.lineItems.forEach(function(t){e+=t.quantity,r.push(t.variantId),n.push({variant_id:t.variantId,sku:t.sku,variant_title:t.variantTitle,quantity:t.quantity,price:t.price})}),{price:t.orderInfo.total/100,currency:i,item_ids:r,item_category:"",number_items:e,payment_info_available:1,transaction_id:t.orderInfo.id,description:JSON.stringify(n)});snaptr("track","PURCHASE",t)});case 8:case"end":return t.stop()}},t,this)})),function(){return X.apply(this,arguments)})}]),P),z=(e(E,[{key:"init",value:(B=r(T().mark(function t(){var n,r,e;return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:e=function(t){return{contents:t.items.map(function(t){return{content_id:t.productId,content_type:"product",content_name:t.productHandle,quantity:t.quantity,price:Number(t.price/100)}}),content_category:"",currency:r,value:Number(t.total)/100,query:""}},n=window.AD_TIKTOK_PIXEL_ID,r=this.shopCurrency,d(p,function(t){var e=t.product,t=t.selected,t=t&&t.skuId?t:e.skus[0],e={content_type:"product",content_id:t.spuId,content_category:e.type||"",content_name:e.goodsTitle,currency:r,value:t.price/100,quantity:1,price:t.price/100,query:""};ttq.instance(n).track("ViewContent",e)}),d(l,function(t){t={content_type:"product",content_id:"",content_category:"",content_name:"",currency:r,value:0,quantity:0,price:0,query:t.searchString};ttq.instance(n).track("Search",t)}),d(h,function(t){t={content_type:"product",content_id:t.spuId,content_category:"",content_name:t.goodsTitle,currency:r,value:t.price*t.quantity/100,quantity:t.quantity,price:t.price/100,query:""};ttq.instance(n).track("AddToCart",t)}),d(f,function(t){t=e(t);ttq.instance(n).track("Checkout",t)}),d(_,function(t){t=e(t);t.content_category="contact_information",ttq.instance(n).track("AddBilling",t)}),d(m,function(t){t={contents:t.lineItems.map(function(t,e){return{content_id:t.productId,content_type:"product",content_name:t.productTitle,quantity:t.quantity,price:Number(t.price/100)}}),content_category:"checkout_result",currency:r,value:t.orderInfo.total/100,query:""};ttq.instance(n).track("Purchase",t)}),d(y,function(){ttq.instance(n).track("Registration")});case 10:case"end":return t.stop()}},t,this)})),function(){return B.apply(this,arguments)})}]),E),J=(e(S,[{key:"init",value:(M=r(T().mark(function t(){var e,n,r,i,o,c=this;return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:o=function(t){return t.map(function(t,e){return{id:t.productId,name:t.productTitle,brand:"",category:"",variant:t.variantId,list_position:e,price:Number(t.price/100),quantity:t.quantity,google_business_vertical:"retail"}})},e=window.location.pathname||"",n="/"==e||e.startsWith("/home")||e.startsWith("/index")?"index":e.startsWith("/products/")?"product":e.startsWith("/collections/")||e.startsWith("/products")?"product_group":e.startsWith("/promotions/")?"activity":e.startsWith("/search")?"search":e.startsWith("/checkout/")?"checkout":"other",r=this.shopCurrency,i=this.clientId-1!==["product_group","activity"].indexOf(n)&&gtag("event","view_item_list",{currency:r,user_id:i,items:[]}),d(p,function(t){var e=t.product,t=t.selected,t=t&&t.skuId?t:e.skus[0],e={currency:r,user_id:i,items:[{id:e.spuId,name:e.goodsTitle,list_name:"product",brand:"",category:"",variant:t.skuId,price:t.price/100,quantity:1,google_business_vertical:"retail"}]};gtag("event","view_item",e)}),d(l,function(t){gtag("event","search",{user_id:i,search_term:t.searchString})}),d(h,function(t){t={currency:r,user_id:i,items:[{id:t.spuId,name:t.goodsTitle,list_name:n,brand:"",category:"",variant:"",list_position:"",price:parseFloat(t.price*t.quantity/100).toFixed(2),quantity:t.quantity||1,google_business_vertical:"retail"}]};gtag("event","add_to_cart",t)}),d("dataTrack:removeFromCart",function(t){t=t.map(function(t){return{id:t.spuId,name:t.goodsTitle,list_name:n,brand:"",category:"",variant:"",list_position:"",price:t.price/100,quantity:t.quantity||1,google_business_vertical:"retail"}});gtag("event","remove_from_cart",{user_id:i,items:t})}),d(f,function(t){var e=o(t.items),t=a({coupon:t.discountCode,currency:r,user_id:i,items:e},"coupon","");gtag("event","begin_checkout",t)}),d("dataTrack:checkoutStepAddress",function(){gtag("event","set_checkout_option",{user_id:i,checkout_step:2,checkout_option:"content_address",value:""})}),d(_,function(t){var e=o(t.items),t=a({coupon:t.discountCode,currency:r,user_id:i,items:e},"coupon","");gtag("track","checkout_progress",t)}),d(m,function(t){var e=t.orderInfo,t=t.lineItems,t=o(t),e={transaction_id:e.id,affiliation:c.shopId,value:e.total/100,currency:r,user_id:i,tax:e.taxTotal,shipping:e.shippingTotal,coupon:e.discountCode,items:t};gtag("event","purchase",e)});case 13:case"end":return t.stop()}},t,this)})),function(){return M.apply(this,arguments)})}]),S),Q=(e(b,[{key:"init",value:(W=r(T().mark(function t(){var i;return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:i=this.shopCurrency,d(p,function(t){var e=t.product,t=t.selected,t=t&&t.skuId?t:e.skus[0],t={content_id:[t.spuId],content_type:"product",value:t.price/100,content_name:e.goodsTitle,currency:i};twq("track","ViewContent",t)}),d(h,function(t){t={content_id:t.spuId,content_type:"product",value:t.price*t.quantity/100,content_name:t.goodsTitle,currency:i};twq("track","AddToCart",t)}),d(f,function(t){var e=0,n=[],r=[],t=(t.items.forEach(function(t){e+=t.quantity,n.push(t.productId),r.push(t.productTitle)}),{content_type:"product_group",content_id:n,currency:i,value:Number(t.total)/100,num_items:e,content_name:r});twq("track","InitiateCheckout",t)}),d(m,function(t){var e,n=[],t=(t.lineItems.forEach(function(t){n.push(t.productId),e+=t.quantity}),{currency:i,value:t.orderInfo.total/100,content_id:n,content_type:"product_group",num_items:e});twq("track","Purchase",t)});case 5:case"end":return t.stop()}},t,this)})),function(){return W.apply(this,arguments)})}]),b),Z=(e(w,[{key:"init",value:(G=r(T().mark(function t(){var r,i;return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:r=window.AD_TABOOLA_PIXEL_ID,i=this.shopCurrency,d(p,function(t){var e=t.product,t=t.selected,t=(t&&t.skuId?t:e.skus[0]).price/100;_tfa.push({notify:"event",name:"view_content",id:r,revenue:t,currency:i,quantity:1})}),d(h,function(t){var e=t.price*t.quantity/100;_tfa.push({notify:"event",name:"add_to_cart",id:r,revenue:e,currency:i,quantity:t.quantity})}),d(f,function(t){var e=0,t=(t.items.forEach(function(t){e+=t.quantity}),Number(t.total)/100);_tfa.push({notify:"event",name:"start_checkout",id:r,revenue:t,currency:i,quantity:e})}),d(m,function(t){var e=0,n=(t.lineItems.forEach(function(t){e+=t.quantity}),t.orderInfo.total/100);_tfa.push({notify:"event",name:"make_purchase",id:r,revenue:n,currency:i,quantity:e,orderid:t.orderInfo.id})}),d(l,function(t){_tfa.push({notify:"event",name:"search",id:r})}),d(y,function(){_tfa.push({notify:"event",name:"complete_registration",id:r})});case 8:case"end":return t.stop()}},t,this)})),function(){return G.apply(this,arguments)})}]),w),tt=(e(k,[{key:"init",value:(U=r(T().mark(function t(){var e,r,i,n;return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:n=window.AD_GOOGLE_ADS_MULTI_PIXEL_ID,e=["","page","home","addToCart","initiateCheckout","purchase","completeRegistration"],r={page:[],home:[],addToCart:[],initiateCheckout:[],purchase:[],completeRegistration:[]},n.forEach(function(t){r[e[t.trackType]].push(t)}),i=this.shopCurrency,r.page.forEach(function(t){gtag("event","conversion",{send_to:"AW-".concat(t.pixelId,"/").concat(t.accessToken)})}),"/"!==(n=window.location.pathname)&&"/index"!==n||r.home.forEach(function(t){gtag("event","conversion",{send_to:"AW-".concat(t.pixelId,"/").concat(t.accessToken)})}),d(h,function(t){var e=t.price*t.quantity/100;r.addToCart.forEach(function(t){gtag("event","conversion",{send_to:"AW-".concat(t.pixelId,"/").concat(t.accessToken),value:e,currency:i})})}),d(f,function(t){var e=Number(t.total)/100;r.initiateCheckout.forEach(function(t){gtag("event","conversion",{send_to:"AW-".concat(t.pixelId,"/").concat(t.accessToken),value:e,Currency:i})})}),d(m,function(e){var n=e.orderInfo.total/100;r.purchase.forEach(function(t){gtag("event","conversion",{send_to:"AW-".concat(t.pixelId,"/").concat(t.accessToken),value:n,Currency:i,transaction_id:e.orderInfo.id})})}),d(y,function(){r.completeRegistration.forEach(function(t){gtag("event","conversion",{send_to:"AW-".concat(t.pixelId,"/").concat(t.accessToken)})})});case 12:case"end":return t.stop()}},t,this)})),function(){return U.apply(this,arguments)})}]),k),et=(e(I,[{key:"init",value:(j=r(T().mark(function t(){var e;return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,this.setSaEvent();case 2:return t.next=4,this.getLoginInfo();case 4:e=t.sent,this.login(e),this.initSaData(),window.AD_TRACK_FP_CONVERSION_API&&sa.registerPage({isOpen:1}),sa.quick("autoTrack"),this.setDomEvent(),this.loadOtherPixel();case 11:case"end":return t.stop()}},t,this)})),function(){return j.apply(this,arguments)})},{key:"loadOtherPixel",value:(F=r(T().mark(function t(){var e;return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:e={shopId:this.shopId,clientId:this.clientId,currency:this.shopCurrency};try{window.AD_TRACK_FP_MULTI_PIXEL_ID&&new H(e),window.AD_PINTEREST_PIXEL_ID&&new V(e),window.AD_SNAPCHAT_PIXEL_ID&&new Y(e),window.AD_TIKTOK_PIXEL_ID&&new z(e),window.AD_TRACK_GA_PIXEL_ID&&new J(e),window.AD_TWITTER_PIXEL_ID&&new Q(e),window.AD_TABOOLA_PIXEL_ID&&new Z(e),window.AD_GOOGLE_ADS_MULTI_PIXEL_ID&&new tt(e)}catch(t){console.error("analysis error",t)}case 2:case"end":return t.stop()}},t,this)})),function(){return F.apply(this,arguments)})},{key:"getClientId",value:function(){var t=c("client_id");return t||u("client_id",t=(new Date).getTime().toString()+(400*Math.random().toFixed(2)+100).toString(),{expires:365,path:"/"}),t}},{key:"initSaData",value:function(){this.setOrderSource();var t=navigator.userAgent,e=document.referrer,n=c("shoptop_source"),n=n?JSON.parse(decodeURI(n)).$latest_referrer_host:"",e={shopId:this.shopId,client:/(Android|webOS|iPhone|iPod|tablet|BlackBerry|Mobile)/i.test(t)?"mobile":"pc",clientId:c("client_id"),$referrer:e,$referrer_host:e?e.split("/")[2]:"",$title:document.title,$url:location.href,$url_path:location.pathname,user_agent:t,language:"",order_source:n,$timezone_offset:(new Date).getTimezoneOffset(),event_id:(new Date).getTime().toString()+(400*Math.random().toFixed(2)+100).toString()};sa.registerPage(e)}},{key:"login",value:function(t){t?(sa.login(t),sa.registerPage({logined:1})):(sa.identify(this.clientId),sa.registerPage({logined:0}))}},{key:"getLoginInfo",value:(g=r(T().mark(function t(){return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:if(window.STORE_PARAMS.customer&&window.STORE_PARAMS.customer.userId)return t.abrupt("return",window.STORE_PARAMS.customer.userId);t.next=4;break;case 4:return t.abrupt("return",!1);case 5:case"end":return t.stop()}},t)})),function(){return g.apply(this,arguments)})},{key:"setDomEvent",value:function(){window.Shoptop.event.on("shoptop:product:skuChange",function(t){window.Shoptop.event.emit(p,t)})}},{key:"setSaEvent",value:(n=r(T().mark(function t(){var r,i=this;return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:r=this.shopCurrency,this.addListener(p,function(t){var e=v(p),n=t.product,t=t.selected,t=t&&t.skuId?t:n.skus[0],n={spuId:t.spuId,skuId:t.skuId,price:t.price/100,value:t.price/100,goodsTitle:n.goodsTitle,goodsHandle:n.handle,currency:r,content_category:"",event_id:e.namespace+e.timeStamp,TP_fbc:c("_fbc")||i.getAdFbc(),TP_fbp:c("_fbp"),TP_content_type:"product",TP_content_ids:t.skuId};sa.track("productView",n)}),this.addListener(l,function(t){var e=v(l),t={search_string:t.searchString,has_result:0<t.hasResult,event_id:e.namespace+e.timeStamp};sa.track("productSearch",t)}),this.addListener(h,function(t){var e=v(h),e={spuId:t.spuId,skuId:t.skuId,price:t.price/100,value:t.price*t.quantity/100,num_items:t.quantity,goodsTitle:t.goodsTitle,goodsHandle:t.handle,currency:r,event_id:e.namespace+e.timeStamp,TP_fbc:c("_fbc")||i.getAdFbc(),TP_fbp:c("_fbp"),TP_content_type:"product",TP_content_ids:[t.skuId]};sa.track("addToCart",e)}),this.addListener(f,function(t){var e=v(f),e={order_id:t.id,currency:r,num_items:t.items.length,value:t.total/100,event_id:e.namespace+e.timeStamp,TP_content_type:"product_group",TP_fbc:c("_fbc")||i.getAdFbc(),TP_fbp:c("_fbp"),TP_content_ids:t.items.map(function(t){return t.variantId})};sa.track("initiateCheckout",e)}),this.addListener(_,function(t){var e=v(_),t={order_id:t.id,currency:r,value:t.total,event_id:e.namespace+e.timeStamp,TP_fbc:c("_fbc")||i.getAdFbc(),TP_fbp:c("_fbp")};sa.track("checkoutStepPayment",t)}),this.addListener(m,function(t){var e=v(m),n=t.shippingAddress,e={order_id:t.orderInfo.id,currency:r,num_items:t.lineItems.length,value:t.orderInfo.total/100,event_id:e.namespace+e.timeStamp,TP_content_type:"product",TP_content_ids:t.lineItems.map(function(t){return t.variantId}),TP_em:n.email||"",TP_fn:n.firstName||"",TP_ln:n.lastName||"",TP_ph:n.phone||"",TP_ct:n.city||"",TP_st:n.provinceCode||"",TP_zp:n.zip||"",TP_cc:n.countryCode||"",TP_fbc:c("_fbc")||i.getAdFbc(),TP_fbp:c("_fbp")};sa.track("purchase",e)}),this.addListener(y,function(){var t=v(y),t={currency:r,event_id:t.namespace+t.timeStamp};sa.track("completeRegistration",t)}),this.addListener("dataTrack:logout",function(){sa.logout()});case 9:case"end":return t.stop()}},t,this)})),function(){return n.apply(this,arguments)})},{key:"addListener",value:function(t,n){var e;window.Shoptop.event.on(t,(e=r(T().mark(function t(e){return T().wrap(function(t){for(;;)switch(t.prev=t.next){case 0:n(e);case 1:case"end":return t.stop()}},t)})),function(t){return e.apply(this,arguments)}))}},{key:"setOrderSource",value:function(){var e=document.referrer,n=location.href,r=navigator.userAgent,t=([["Facebook",/(facebook)|(fbclid=.+)/i,/fbclid=.+/,/FBAV|FBAN|FBIOS/i],["GoogleAds",/gclid=.+/i,/gclid=.+/i,0],["Google",/google/i,0,0],["Instagram",/instagram/i,0,/instagram/i],["Pinterest",/(pinterest)|(epik=.+)/i,/epik=.+/i,/pinterest/i],["Snapchat",/snapchat/i,0,/snapchat/i],["TikTok",/ads.tiktok/i,0,/tiktok/i],["Mailchimp",/mc_cid=.+/i,0,0],["Baidu",/baidu/i,0,0],["YouTube",/youtube/i,0,/youtube/i],["Twitter",/(twitter)|(t.co)/i,0,/twitter/i],["LinkedIn",/linkedin/i,0,/linkedin/i],["WhatsApp",/whatsapp/i,0,/whatsapp/i],["Reddit",/reddit/i,0,0],["Yahoo",/yahoo/i,0,0],["Bing",/bing/i,0,0],["Yandex",/yandex/i,0,0]].find(function(t){return t[1]&&t[1].test(e)||t[2]&&t[2].test(n)||t[3]&&t[3].test(r)})||[""])[0],i="shoptop_source",o=new Date((new Date).getTime()+6048e5);if(!c(i)){u(i,encodeURI(JSON.stringify({$first_visit_url:n,$latest_referrer_host:t,expire:o.getTime()})),{expires:7,path:"/"});try{localStorage[i]=c(i)}catch(e){}}if(c(i)||!localStorage[i]||!((t=JSON.parse(localStorage[i]))&&t.expire)<(new Date).getTime()&&u(i,localStorage[i],{expires:7,path:"/"}),c(i)&&!localStorage[i])try{localStorage[i]=c(i)}catch(e){}}},{key:"i",value:function(t,e,n){var r=new Date;return r.setTime(r.getTime()+31536e6),document.cookie=t+"="+encodeURIComponent(e)+";expires="+(n||r).toGMTString()+";domain="+location.host.split(".").map(function(t,e,n){return 0==e&&2<n.length?"":t}).join(".")+";path=/",!0}},{key:"getAdFbc",value:function(){var e=new RegExp("(^|&)fbclid=([^&]*)(&|$)"),e=window.location.search.substr(1).match(e);return null!=e&&t?(e="fb.1."+t+"."+e[2],this.i("fbclid",e),decodeURIComponent(e)):c("fbclid")||""}}]),I);function I(){i(this,I),window.log=function(){Array.prototype.slice.call(arguments)},this.shopCurrency=STORE_PARAMS.shopCurrency,this.shopId=STORE_PARAMS.shopId,this.clientId=this.getClientId(),this.timer=null,this.init()}function k(t){var e=t.currency,n=t.clientId,t=t.shopId;i(this,k),this.shopCurrency=e,this.shopId=t,this.clientId=n,this.init()}function w(t){var e=t.currency,n=t.clientId,t=t.shopId;i(this,w),this.shopCurrency=e,this.shopId=t,this.clientId=n,this.init()}function b(t){var e=t.currency,n=t.clientId,t=t.shopId;i(this,b),this.shopCurrency=e,this.shopId=t,this.clientId=n,this.init()}function S(t){var e=t.currency,n=t.clientId,t=t.shopId;i(this,S),this.shopCurrency=e,this.shopId=t,this.clientId=n,this.init()}function E(t){var e=t.currency,n=t.clientId,t=t.shopId;i(this,E),this.shopCurrency=e,this.shopId=t,this.clientId=n,this.init()}function P(t){var e=t.currency,n=t.clientId,t=t.shopId;i(this,P),this.shopCurrency=e,this.shopId=t,this.clientId=n,this.init()}function A(t){var e=t.currency,n=t.clientId,t=t.shopId;i(this,A),this.shopCurrency=e,this.shopId=t,this.clientId=n,this.isLoaded=!1,this.init()}function x(t){var e=t.currency,n=t.clientId,t=t.shopId;i(this,x),this.shopCurrency=e,this.shopId=t,this.clientId=n,this.init()}var q={sdk_url:"https://static.staticxt.com/oss/sensorsdata.min.js",name:"sa",server_url:"".concat(SHOPTOP.saServerUrl,"/api/mbr/statistics/collect/sa?project=production"),show_log:!1},nt=q.sdk_url,C=q.name,L=window,rt=document,D=null,O=null;if(void 0===L.sensorsDataAnalytic201505){L.sensorsDataAnalytic201505=C,L[C]=L[C]||function(t){return function(){(L[C]._q=L[C]._q||[]).push([t,arguments])}};for(var R=["track","quick","register","registerPage","registerOnce","trackSignup","trackAbtest","setProfile","setOnceProfile","appendProfile","incrementProfile","deleteProfile","unsetProfile","identify","login","logout","trackLink","clearAllRegister","getAppStatus"],N=0;N<R.length;N++)L[C][R[N]]=L[C].call(null,R[N]);L[C]._t||(D=rt.createElement("script"),O=rt.getElementsByTagName("script")[0],D.async=1,D.src=nt,D.setAttribute("charset","UTF-8"),L[C].para=q,O.parentNode.insertBefore(D,O))}new et}(); </script> <style> .z-0{z-index:0}.z-1{z-index:1}.cursor-pointer{cursor:pointer}.relative{position:relative}.absolute{position:absolute}.fixed{position:fixed}.max-w-full{max-width:100%}.w-3r{width:calc(var(--font-heading-scale)*3rem)}.w-full{width:100%}.w-11\/12{width:91.666667%}.h-full{height:100%}.h-auto{height:auto}.h-3r{height:calc(var(--font-heading-scale)*3rem)}.min-height{min-height:100%}.block{display:block}.flex{display:flex}.inline-block{display:inline-block}.hidden{display:none}[hidden]{display:none!important}@media screen and (min-width:750px){.md\:flex{display:flex}.md\:block{display:block}.md\:hidden{display:none}}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.flex-wrap-reverse{flex-wrap:wrap-reverse}.flex-nowrap{flex-wrap:nowrap}@media screen and (min-width:750px){.md\:flex-row{flex-direction:row}.md\:flex-nowrap{flex-wrap:nowrap}}.flex-1{flex:1 1 0%}.flex-shrink-0{flex-shrink:0}.grow{flex-grow:1}.justify-left,.justify-start{justify-content:flex-start}.justify-center{justify-content:center}.justify-end,.justify-right{justify-content:flex-end}.justify-between{justify-content:space-between}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.gap-12{gap:3rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}@media screen and (min-width:750px){.md\:text-left{text-align:left}.md\:text-center{text-align:center}.md\:text-right{text-align:right}}.no-underline{text-decoration-line:none}@media screen and (min-width:750px){.md\:flex{display:flex}.md\:justify-start{justify-content:flex-start}.md\:justify-center{justify-content:center}.md\:justify-end{justify-content:flex-end}.md\:items-start{align-items:flex-start}}.inset{inset:0}.top-0{top:0}.left-0{left:0}.top-9{top:2.25rem}.right-9{right:2.25rem}@media screen and (min-width:750px){.md\:right-20{right:5rem}}.m-0{margin:0}.mt-0{margin-top:0}.ml-3\.5{margin-left:.875rem}.mt-4{margin-top:1rem}.mr-4{margin-right:1rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mb-0{margin-bottom:0}.mb-2\.5{margin-bottom:.625rem}.mb-4{margin-bottom:1rem}.mb-4r{margin-bottom:calc(var(--font-heading-scale)*1rem)}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mx-10{margin-left:2.5rem;margin-right:2.5rem}.mt-12{margin-top:3rem}.mb-12{margin-bottom:3rem}.mb-14{margin-bottom:3.5rem}.mx-auto{margin-left:auto;margin-right:auto}@media screen and (min-width:750px){.md\:mb-8{margin-bottom:2rem}.md\:mt-16{margin-top:4rem}}.px-8{padding-left:2rem;padding-right:2rem}.pt-10{padding-top:2.5rem}.pb-8{padding-bottom:2rem}@media screen and (min-width:750px){.md\:pl-20{padding-left:5rem}[dir=rtl] .md\:pl-20{padding-left:0;padding-right:5rem}.md\:pr-20{padding-right:5rem}[dir=rtl] .md\:pr-20{padding-left:5rem;padding-right:0}}.object-cover{object-fit:cover}.object-contain{object-fit:contain}.object-bottom{object-position:bottom}.object-center{object-position:center}.object-left{object-position:left}.object-left-bottom{object-position:left bottom}.object-left-top{object-position:left top}.object-right{object-position:right}.object-right-bottom{object-position:right bottom}.object-right-top{object-position:right top}.object-top{object-position:top}.overflow-hidden{overflow:hidden}.text-inherit{font-size:inherit}.bg-cover{background-size:cover}.rotate-90{transform:rotate(90deg)}.-rotate-90{transform:rotate(-90deg)}.opacity-70{opacity:.7}.pointer-events-none{pointer-events:none}.pointer-events-auto{pointer-events:auto}.text-base{color:rgb(var(--color-base-text))}.text-btn{color:var(--color-btn-text)}.text-secondary-btn{color:var(--color-secondary-btn-text)}.text-discount{color:var(--color-discount-price)}.text-off-tag{color:var(--color-off-tag-text)}.text-sold-out{color:var(--color-sold-out-text)}.bg-base{background-color:var(--color-base-bg)}.bg-btn{background-color:var(--color-btn-bg)}.bg-off-tag{background-color:var(--color-off-tag-bg)}.bg-sold-out{background-color:var(--color-sold-out-bg)}.color-none,:root{--color-foreground:var(--color-base-text);--color-background:var(--color-base-bg);--gradient-background:rgb(var(--color-base-bg));--color-button:var(--color-btn-bg);--color-button-text:var(--color-btn-text);--color-secondary-button-text:var(--color-secondary-btn-text);--color-shadow:var(--color-shadow-base)}.color-options-1{--color-foreground:var(--color-text-1);--color-background:var(--color-bg-1);--gradient-background:var(--color-bg-gradient-1);--color-button:var(--color-btn-bg-1);--color-button-text:var(--color-btn-text-1);--color-secondary-button-text:var(--color-secondary-btn-text-1);--color-shadow:var(--color-shadow-1)}.color-options-2{--color-foreground:var(--color-text-2);--color-background:var(--color-bg-2);--gradient-background:var(--color-bg-gradient-2);--color-button:var(--color-btn-bg-2);--color-button-text:var(--color-btn-text-2);--color-secondary-button-text:var(--color-secondary-btn-text-2);--color-shadow:var(--color-shadow-2)}.color-options-3{--color-foreground:var(--color-text-3);--color-background:var(--color-bg-3);--gradient-background:var(--color-bg-gradient-3);--color-button:var(--color-btn-bg-3);--color-button-text:var(--color-btn-text-3);--color-secondary-button-text:var(--color-secondary-btn-text-3);--color-shadow:var(--color-shadow-3)}.color-options-4{--color-foreground:var(--color-text-4);--color-background:var(--color-bg-4);--gradient-background:var(--color-bg-gradient-4);--color-button:var(--color-btn-bg-4);--color-button-text:var(--color-btn-text-4);--color-secondary-button-text:var(--color-secondary-btn-text-4);--color-shadow:var(--color-shadow-4)}.color-options-1,.color-options-2,.color-options-3,.color-options-4,:root{--alpha-button-background:var(--buttons-border-opacity);--alpha-button-border:1}.g-button-primary{background-color:rgba(var(--color-button),var(--alpha-button-background));border-color:rgba(var(--color-button),var(--alpha-button-background));border-radius:var(--buttons-radius-outset);color:rgb(var(--color-button-text))}.g-button-secondary{background:transparent;border-color:rgb(var(--color-secondary-button-text));border-radius:var(--buttons-radius);color:rgb(var(--color-secondary-button-text))}.button--secondary,.color-none .button--secondary,.color-options-1 .button--secondary,.color-options-2 .button--secondary,.color-options-3 .button--secondary,.color-options-4 .button--secondary{--color-button:var(--color-background);--color-button-text:var(--color-secondary-button-text)}.color-none,.color-options-1,.color-options-2,.color-options-3,.color-options-4,body{background-color:rgb(var(--color-background));color:rgba(var(--color-foreground),.75)}.g-card-product--var{--border-radius:var(--product-card-corner-radius);--border-width:var(--product-card-border-width);--border-opacity:var(--product-card-border-opacity);--shadow-horizontal-offset:var(--product-card-shadow-horizontal-offset);--shadow-vertical-offset:var(--product-card-shadow-vertical-offset);--shadow-blur-radius:var(--product-card-shadow-blur-radius);--shadow-opacity:var(--product-card-shadow-opacity);--shadow-visible:var(--product-card-shadow-visible);--image-padding:var(--product-card-image-padding);--text-alignment:var(--product-card-text-alignment)}.g-card-product--filter{background-color:transparent;border:0;filter:drop-shadow(var(--shadow-horizontal-offset) var(--shadow-vertical-offset) var(--shadow-blur-radius) rgba(var(--color-shadow),var(--shadow-opacity)))}.g-card-product:after{border-radius:var(--border-radius);box-shadow:var(--shadow-horizontal-offset) var(--shadow-vertical-offset) var(--shadow-blur-radius) rgba(var(--color-shadow),var(--shadow-opacity));content:"";height:calc(var(--border-width)*2 + 100%);left:calc(var(--border-width)*-1);position:absolute;top:calc(var(--border-width)*-1);width:calc(var(--border-width)*2 + 100%);z-index:-1}.product-card--card,.product-card--standard .g-card-product{border:var(--border-width) solid rgba(var(--color-foreground),var(--border-opacity));border-radius:var(--border-radius);box-sizing:border-box;position:relative}.g-card-product,.g-card-product--card{text-align:var(--product-card-text-alignment)}.g-card-product--card{border-radius:var(--product-card-corner-radius);position:relative}.g-card-product--card:after,.g-card-product--standard:after{border-radius:var(--product-card-corner-radius);box-shadow:var(--product-card-shadow-horizontal-offset) var(--product-card-shadow-vertical-offset) var(--product-card-shadow-blur-radius) rgba(var(--color-shadow),var(--product-card-shadow-opacity));content:"";height:calc(var(--product-card-border-width)*2 + 100%);left:calc(var(--product-card-border-width)*-1);position:absolute;top:calc(var(--product-card-border-width)*-1);width:calc(var(--product-card-border-width)*2 + 100%);z-index:-1}.g-card-collection{border:var(--collection-card-border-width) solid rgba(var(--color-foreground),var(--collection-card-border-opacity));border-radius:var(--collection-card-corner-radius);box-shadow:var(--collection-card-shadow-horizontal-offset) var(--collection-card-shadow-vertical-offset) var(--collection-card-shadow-blur-radius) rgba(var(--color-shadow),var(--collection-card-shadow-opacity))}.g-card-collection--card .g-card-collection-img,.g-card-collection--card img,.g-card-collection--standard .g-card-collection-img,.g-card-collection--standard img{padding:var(--collection-card-image-padding)}.g-card-collection--card{border:var(--collection-card-border-width) solid rgba(var(--color-foreground),var(--collection-card-border-opacity));border-radius:var(--collection-card-corner-radius);position:relative;text-align:var(--collection-card-text-alignment)}.g-card-collection--card:after,.g-card-collection--standard:after{border-radius:var(--collection-card-corner-radius);box-shadow:var(--collection-card-shadow-horizontal-offset) var(--collection-card-shadow-vertical-offset) var(--collection-card-shadow-blur-radius) rgba(var(--color-shadow),var(--collection-card-shadow-opacity));content:"";height:calc(var(--collection-card-border-width)*2 + 100%);left:calc(var(--collection-card-border-width)*-1);position:absolute;top:calc(var(--collection-card-border-width)*-1);width:calc(var(--collection-card-border-width)*2 + 100%);z-index:-1}.g-article-card-wrapper .card,.g-contains-card--article{--border-radius:var(--blog-card-corner-radius);--border-width:var(--blog-card-border-width);--border-opacity:var(--blog-card-border-opacity);--shadow-horizontal-offset:var(--blog-card-shadow-horizontal-offset);--shadow-vertical-offset:var(--blog-card-shadow-vertical-offset);--shadow-blur-radius:var(--blog-card-shadow-blur-radius);--shadow-opacity:var(--blog-card-shadow-opacity);--shadow-visible:var(--blog-card-shadow-visible);--image-padding:var(--blog-card-image-padding);--text-alignment:var(--blog-card-text-alignment)}.g-card-article--card,.g-card-article--standard{border:var(--blog-card-border-width) solid rgba(var(--color-foreground),var(--blog-card-border-opacity));border-radius:var(--blog-card-corner-radius);position:relative;text-align:var(--blog-card-text-alignment)}.g-card-article--card .g-card-article-img,.g-card-article--card img,.g-card-article--standard .g-card-article-img,.g-card-article--standard img{padding:var(--blog-card-image-padding)}.g-card-article--card:after,.g-card-article--standard:after{border-radius:var(--blog-card-corner-radius);box-shadow:var(--blog-card-shadow-horizontal-offset) var(--blog-card-shadow-vertical-offset) var(--blog-card-shadow-blur-radius) rgba(var(--color-shadow),var(--blog-card-shadow-opacity));content:"";height:calc(var(--blog-card-border-width)*2 + 100%);left:calc(var(--blog-card-border-width)*-1);position:absolute;top:calc(var(--blog-card-border-width)*-1);width:calc(var(--blog-card-border-width)*2 + 100%);z-index:-1}.g-card-content{--border-radius:var(--text-boxes-radius);--border-width:var(--text-boxes-border-width);--border-opacity:var(--text-boxes-border-opacity);--shadow-horizontal-offset:var(--text-boxes-shadow-horizontal-offset);--shadow-vertical-offset:var(--text-boxes-shadow-vertical-offset);--shadow-blur-radius:var(--text-boxes-shadow-blur-radius);--shadow-opacity:var(--text-boxes-shadow-opacity);--shadow-visible:var(--text-boxes-shadow-visible);border:var(--text-boxes-border-width) solid rgba(var(--color-foreground),var(--text-boxes-border-opacity));border-radius:var(--text-boxes-radius);position:relative}.g-card-content:after{border-radius:var(--text-boxes-radius);bottom:calc(var(--text-boxes-border-width)*-1);box-shadow:var(--text-boxes-shadow-horizontal-offset) var(--text-boxes-shadow-vertical-offset) var(--text-boxes-shadow-blur-radius) rgba(var(--color-shadow),var(--text-boxes-shadow-opacity));content:"";left:calc(var(--text-boxes-border-width)*-1);position:absolute;right:calc(var(--text-boxes-border-width)*-1);top:calc(var(--text-boxes-border-width)*-1);z-index:-1}.g-card-content,.g-card-content-y{border:var(--text-boxes-border-width) solid rgba(var(--color-foreground),var(--text-boxes-border-opacity));border-radius:var(--text-boxes-radius);position:relative}.g-card-content-y{border-left:none;border-radius:0;border-right:none}.g-card-content-y:after{bottom:0;box-shadow:var(--text-boxes-shadow-horizontal-offset) var(--text-boxes-shadow-vertical-offset) var(--text-boxes-shadow-blur-radius) rgba(var(--color-shadow),var(--text-boxes-shadow-opacity));content:"";left:0;pointer-events:none;position:absolute;right:0;top:0}.g-card-content--full-width:after{border-radius:0;left:0;right:0}@media screen and (max-width:749px){.g-card-content--full-width-mobile{border-left:none;border-radius:0;border-right:none}.g-card-content--full-width-mobile:after{display:none}}.g-card-media{background-color:rgb(var(--color-background));border:var(--media-border-width) solid rgba(var(--color-foreground),var(--media-border-opacity));border-radius:var(--media-radius);overflow:visible!important;position:relative;z-index:0}.g-card-media:after{border-radius:var(--media-radius);bottom:calc(var(--media-border-width)*-1);box-shadow:var(--media-shadow-horizontal-offset) var(--media-shadow-vertical-offset) var(--media-shadow-blur-radius) rgba(var(--color-shadow),var(--media-shadow-opacity));content:"";left:calc(var(--media-border-width)*-1);pointer-events:none;position:absolute;right:calc(var(--media-border-width)*-1);top:calc(var(--media-border-width)*-1);z-index:-1}.g-card-media--no-shadow:after{content:none}.g-card-media iframe,.g-card-media img,.g-card-media model-viewer,.g-card-media video{border-radius:calc(var(--media-radius) - var(--media-border-width))}.g-card-media--full-width,.g-card-media--full-width iframe,.g-card-media--full-width img,.g-card-media--full-width video{border-left:none;border-radius:0;border-right:none}.variant-shadow:before{border-radius:var(--variant-pills-radius);bottom:calc(var(--variant-pills-border-width)*-1);box-shadow:var(--variant-pills-shadow-horizontal-offset) var(--variant-pills-shadow-vertical-offset) var(--variant-pills-shadow-blur-radius) rgba(var(--color-shadow),var(--variant-pills-shadow-opacity));content:"";left:calc(var(--variant-pills-border-width)*-1);position:absolute;right:calc(var(--variant-pills-border-width)*-1);top:calc(var(--variant-pills-border-width)*-1);z-index:-1}.g-card-popup{border-color:rgba(var(--color-foreground),var(--popup-border-opacity));border-radius:var(--popup-corner-radius);border-style:solid;border-width:var(--popup-border-width);box-shadow:var(--popup-shadow-horizontal-offset) var(--popup-shadow-vertical-offset) var(--popup-shadow-blur-radius) rgba(var(--color-shadow),var(--popup-shadow-opacity))}.badge{border:1px solid transparent;border-radius:var(--badge-corner-radius);font-size:1.2rem;letter-spacing:.1rem;line-height:1;padding:.5rem 1.3rem;text-align:center;word-break:break-word}.badge--sale{background:rgb(var(--color-off-tag-bg));border-color:rgb(var(--color-off-tag-bg));color:rgb(var(--color-off-tag-text))}.badge--sold-out{background:rgb(var(--color-sold-out-bg));border-color:rgb(var(--color-sold-out-bg));color:rgb(var(--color-sold-out-text))}.accordion .icon-accordion,.icon-with-text .icon{color:rgb(var(--color-foreground))}.shape--arch{clip-path:url(#Shape-Arch)}.shape--chevronleft{clip-path:polygon(100% 0,85% 50%,100% 100%,15% 100%,0 50%,15% 0)}.shape--chevronright{clip-path:polygon(85% 0,100% 50%,85% 100%,0 100%,15% 50%,0 0)}.shape--circle{clip-path:ellipse(45% 45% at 50% 50%)}.shape--diamond{clip-path:polygon(50% 0,100% 50%,50% 100%,0 50%)}.shape--parallelogram{clip-path:polygon(15% 0,100% 0,85% 100%,0 100%)}.paypal-buttons{z-index:0}.line-clamp-one{display:block;overflow:hidden;overflow-wrap:break-word;text-overflow:ellipsis;white-space:nowrap}.line-clamp-two{-webkit-box-orient:vertical;-webkit-line-clamp:2;display:-webkit-box!important;overflow:hidden}.hide-scrollbar::-webkit-scrollbar{display:none}.no-scroll-bar{-webkit-scrollbar:none;scrollbar-width:none}.no-scroll-bar::-webkit-scrollbar{width:0}.product-card-wrap .product-card-content{--border-radius:var(--product-card-corner-radius);--border-width:var(--product-card-border-width);--border-opacity:var(--product-card-border-opacity);--shadow-horizontal-offset:var(--product-card-shadow-horizontal-offset);--shadow-vertical-offset:var(--product-card-shadow-vertical-offset);--shadow-blur-radius:var(--product-card-shadow-blur-radius);--shadow-opacity:var(--product-card-shadow-opacity);--shadow-visible:var(--product-card-shadow-visible);--image-padding:var(--product-card-image-padding);--text-alignment:var(--product-card-text-alignment)}.page-width{margin:0 auto;max-width:var(--page-width);padding:0 1.5rem}.page-width.drawer-menu{max-width:100%}.page-width-desktop{margin:0 auto;padding:0}@media screen and (min-width:750px){.page-width{padding:0 5rem}.header.page-width{padding-left:3.2rem;padding-right:3.2rem}.page-width--narrow{padding:0 9rem}.page-width-desktop{padding:0}.page-width-tablet{padding:0 5rem}}@media screen and (min-width:990px){.header:not(.drawer-menu).page-width{padding-left:5rem;padding-right:5rem}.page-width--narrow{max-width:72.6rem;padding:0}.page-width-desktop{max-width:var(--page-width);padding:0 5rem}}.xt-section{margin-top:var(--section-m-margin-top)}@media screen and (min-width:750px){.xt-section{margin-top:var(--section-margin-top)}}.color-options-1,.color-options-2,.color-options-3,.color-options-4,body{background-color:rgb(var(--color-background));color:rgba(var(--color-foreground),.75)}.background-secondary{background-color:rgba(var(--color-foreground),.04)}.list-unstyled{list-style:none;margin:0;padding:0}.visually-hidden{clip:rect(0 0 0 0);word-wrap:normal!important;border:0;height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute!important;width:1px}.text-body{font-family:var(--font-body-family);font-size:1.5rem;font-style:var(--font-body-style);font-weight:var(--font-body-weight);letter-spacing:.06rem;line-height:calc(1 + .8/var(--font-base-scale))}.h0,.h1,.h2,.h3,.h4,.h5,h1,h2,h3,h4,h5{color:rgb(var(--color-foreground));font-family:var(--font-heading-family);font-style:var(--font-heading-style);font-weight:var(--font-heading-weight);letter-spacing:calc(var(--font-heading-scale)*.06rem);line-height:calc(1 + .3/max(1, var(--font-heading-scale)));word-break:break-word}.hxl{font-size:calc(var(--font-heading-scale)*5rem)}@media only screen and (min-width:750px){.hxl{font-size:calc(var(--font-heading-scale)*6.2rem)}}.h0{font-size:calc(var(--font-heading-scale)*4rem)}@media only screen and (min-width:750px){.h0{font-size:calc(var(--font-heading-scale)*5.2rem)}}.h1,h1{font-size:calc(var(--font-heading-scale)*3rem)}@media only screen and (min-width:750px){.h1,h1{font-size:calc(var(--font-heading-scale)*4rem)}}.h2,h2{font-size:calc(var(--font-heading-scale)*2rem)}@media only screen and (min-width:750px){.h2,h2{font-size:calc(var(--font-heading-scale)*2.4rem)}}.h3,h3{font-size:calc(var(--font-heading-scale)*1.7rem)}@media only screen and (min-width:750px){.h3,h3{font-size:calc(var(--font-heading-scale)*1.8rem)}}.h4,h4{font-family:var(--font-heading-family);font-size:calc(var(--font-heading-scale)*1.5rem);font-style:var(--font-heading-style)}.h5,h5{font-size:calc(var(--font-heading-scale)*1.2rem)}@media only screen and (min-width:750px){.h5,h5{font-size:calc(var(--font-heading-scale)*1.3rem)}}.h6,h6{margin-block-end:1.67em;margin-block-start:1.67em}.h6,blockquote,h6{color:rgba(var(--color-foreground),.75)}blockquote{border-left:.2rem solid rgba(var(--color-foreground),.2);font-style:italic;padding-left:1rem}@media screen and (min-width:750px){blockquote{padding-left:1.5rem}}.caption{font-size:1rem;letter-spacing:.07rem;line-height:calc(1 + .7/var(--font-base-scale))}@media screen and (min-width:750px){.caption{font-size:1.2rem}}.caption-with-letter-spacing{letter-spacing:.13rem;line-height:calc(1 + .2/var(--font-base-scale));text-transform:uppercase}.caption-with-letter-spacing--small{font-size:1rem;letter-spacing:.13rem}.caption-with-letter-spacing--medium{font-size:1.2rem;letter-spacing:.16rem}.caption-with-letter-spacing--large{font-size:1.4rem;letter-spacing:.18rem}.caption-large,.customer .field input,.customer select,.field__input,.form__label,.select__select{font-size:1.3rem;letter-spacing:.04rem;line-height:calc(1 + .5/var(--font-base-scale))}.color-foreground{color:rgb(var(--color-foreground))}table:not([class]){border-collapse:collapse;border-style:hidden;box-shadow:0 0 0 .1rem rgba(var(--color-foreground),.2);font-size:1.4rem;table-layout:fixed}table:not([class]) td,table:not([class]) th{border:.1rem solid rgba(var(--color-foreground),.2);padding:1em}@media screen and (max-width:749px){.small-hide{display:none!important}}@media screen and (min-width:750px) and (max-width:989px){.medium-hide{display:none!important}}@media screen and (min-width:990px){.large-up-hide{display:none!important}}.uppercase{text-transform:uppercase}.light{opacity:.7}.predictive-search:empty,a:empty,article:empty,dl:empty,h1:empty,h2:empty,h3:empty,h4:empty,h5:empty,h6:empty,p:empty,section:empty,ul:empty{display:none}.customer a,.link{background-color:transparent;border:none;box-shadow:none;color:rgb(var(--color-link));cursor:pointer;display:inline-block;font-family:inherit;font-size:1.4rem;text-decoration:underline;text-underline-offset:.3rem}.link--text{color:rgb(var(--color-foreground))}.link--text:hover{color:rgba(var(--color-foreground),.75)}.link-with-icon{display:inline-flex;font-size:1.4rem;font-weight:600;letter-spacing:.1rem;margin-bottom:4.5rem;text-decoration:none;white-space:nowrap}.link-with-icon .icon{margin-left:1rem;width:1.5rem}a:not([href]){cursor:not-allowed}.circle-divider:after{content:"\2022";margin:0 1.3rem 0 1.5rem}.circle-divider:last-of-type:after{display:none}hr{background-color:rgba(var(--color-foreground),.2);border:none;display:block;height:.1rem;margin:5rem 0}@media screen and (min-width:750px){hr{margin:7rem 0}}.full-unstyled-link{color:currentColor;display:block;text-decoration:none}.placeholder{fill:rgba(var(--color-foreground),.55);background-color:rgba(var(--color-foreground),.04);color:rgba(var(--color-foreground),.55)}details>*{box-sizing:border-box}.break{word-break:break-word}.visibility-hidden{visibility:hidden}@media (prefers-reduced-motion){.motion-reduce{animation:none!important;transition:none!important}}:root{--duration-short:100ms;--duration-default:200ms;--duration-long:500ms}.customer a,.inline-richtext a,.underlined-link{text-decoration-thickness:.1rem;text-underline-offset:.3rem;transition:text-decoration-thickness .1s ease}.customer a,.underlined-link{color:rgba(var(--color-link),var(--alpha-link))}.inline-richtext a,.rte.inline-richtext a{color:currentColor}.customer a:hover,.inline-richtext a:hover,.underlined-link:hover{color:rgb(var(--color-link));text-decoration-thickness:.2rem}.icon-arrow{width:1.5rem}.h3 .icon-arrow,h3 .icon-arrow{width:calc(var(--font-heading-scale)*1.5rem)}.animate-arrow .icon-arrow path{transform:translateX(-.25rem);transition:transform var(--duration-short) ease}.animate-arrow:hover .icon-arrow path{transform:translateX(-.05rem)}summary{cursor:pointer;list-style:none;position:relative}summary::-webkit-details-marker{display:none}:focus{box-shadow:none;outline:0}.focused{box-shadow:0 0 0 .3rem rgb(var(--color-background)),0 0 .5rem .4rem rgba(var(--color-foreground),.3);outline:.2rem solid rgba(var(--color-foreground),.5);outline-offset:.3rem}.focus-inset:focus-visible{box-shadow:0 0 .2rem 0 rgba(var(--color-foreground),.3);outline:.2rem solid rgba(var(--color-foreground),.5);outline-offset:-.2rem}.focused.focus-inset{box-shadow:0 0 .2rem 0 rgba(var(--color-foreground),.3);outline:.2rem solid rgba(var(--color-foreground),.5);outline-offset:-.2rem}.title,.title-wrapper-with-link{margin:3rem 0 2rem}.title-no-margin .title{margin:0}.title-no-mt .title{margin-top:0}.title-wrapper-with-link .title{margin:0}.title .link{font-size:inherit}.title-wrapper{margin-bottom:3rem}.title-wrapper-with-link{align-items:flex-end;display:flex;flex-wrap:wrap;gap:1rem;justify-content:space-between;margin-bottom:3rem}.title--primary{margin:4rem 0}@media screen and (min-width:990px){.title,.title-wrapper-with-link{margin:5rem 0 3rem}.title--primary{margin:2rem 0}.title-wrapper-with-link{align-items:center}.title-wrapper-with-link .title{margin-bottom:0}}.title-wrapper-with-link .link-with-icon{align-items:center;display:flex;flex-shrink:0;margin:0}.title-wrapper-with-link .link-with-icon svg{width:1.5rem}.title-wrapper-with-link a{flex-shrink:0;margin-top:0}.subtitle{color:rgba(var(--color-foreground),.7);font-size:1.8rem;letter-spacing:.06rem;line-height:calc(1 + .8/var(--font-base-scale))}.subtitle--small{font-size:1.4rem;letter-spacing:.1rem}.subtitle--medium{font-size:1.6rem;letter-spacing:.08rem}.media{background-color:rgba(var(--color-foreground),.1);display:block;overflow:hidden;position:relative}.media--square{padding-bottom:100%}.media--portrait{padding-bottom:125%}.media--landscape{padding-bottom:66.6%}.media--cropped{padding-bottom:56%}.media--16-9{padding-bottom:56.25%}.media--circle{border-radius:50%;padding-bottom:100%}@media screen and (min-width:990px){.media--cropped{padding-bottom:63%}}.media model-viewer,.media>:not(.zoom):not(.deferred-media__poster-button){display:block;height:100%;left:0;max-width:100%;position:absolute;top:0;width:100%}.media--transparent{background-color:transparent}button *{pointer-events:none}.button,.customer button{--shadow-horizontal-offset:var(--buttons-shadow-horizontal-offset);--shadow-vertical-offset:var(--buttons-shadow-vertical-offset);--shadow-blur-radius:var(--buttons-shadow-blur-radius);--shadow-opacity:var(--buttons-shadow-opacity);--shadow-visible:var(--buttons-shadow-visible);--border-offset:var(--buttons-border-offset);--border-opacity:calc(1 - var(--buttons-border-opacity));align-items:center;-webkit-appearance:none;appearance:none;background-color:rgba(var(--color-button),var(--alpha-button-background));border:0;border-radius:var(--buttons-radius-outset);color:rgb(var(--color-button-text));cursor:pointer;display:inline-flex;font:inherit;font-size:1.5rem;justify-content:center;min-height:calc(4.5rem + var(--buttons-border-width)*2);min-width:calc(12rem + var(--buttons-border-width)*2);padding:0 3rem;position:relative;text-decoration:none;transition:box-shadow var(--duration-short) ease}.button:before,.customer button:before{border-radius:var(--buttons-radius-outset);bottom:0;box-shadow:var(--shadow-horizontal-offset) var(--shadow-vertical-offset) var(--shadow-blur-radius) rgba(var(--color-shadow),var(--shadow-opacity));content:"";left:0;position:absolute;right:0;top:0;z-index:-1}.button:after,.customer button:after{border-radius:var(--buttons-radius);bottom:var(--buttons-border-width);box-shadow:0 0 0 calc(var(--buttons-border-width) + var(--border-offset)) rgba(var(--color-button-text),var(--border-opacity)),0 0 0 var(--buttons-border-width) rgba(var(--color-button),var(--alpha-button-background));content:"";left:var(--buttons-border-width);position:absolute;right:var(--buttons-border-width);top:var(--buttons-border-width);transition:box-shadow var(--duration-short) ease;z-index:1}.button:not([disabled]):hover:after,.customer button:hover:after{--border-offset:1.3px;box-shadow:0 0 0 calc(var(--buttons-border-width) + var(--border-offset)) rgba(var(--color-button-text),var(--border-opacity)),0 0 0 calc(var(--buttons-border-width) + 1px) rgba(var(--color-button),var(--alpha-button-background))}.button--secondary:after{--border-opacity:var(--buttons-border-opacity)}.button.focused,.button:focus,.button:focus-visible{box-shadow:0 0 0 .3rem rgb(var(--color-background)),0 0 0 .5rem rgba(var(--color-foreground),.5),0 0 .5rem .4rem rgba(var(--color-foreground),.3);outline:0}.button:focus:not(:focus-visible):not(.focused){box-shadow:inherit}.button::selection,.customer button::selection{background-color:rgba(var(--color-button-text),.3)}.button,.button-label,.customer button{font-size:1.5rem;letter-spacing:.1rem;line-height:calc(1 + .2/var(--font-base-scale))}.button--tertiary{font-size:1.2rem;min-height:calc(3.5rem + var(--buttons-border-width)*2);min-width:calc(9rem + var(--buttons-border-width)*2);padding:1rem 1.5rem}.button--small{padding:1.2rem 2.6rem}.button.disabled,.button:disabled,.button[aria-disabled=true],.customer button.disabled,.customer button:disabled,.customer button[aria-disabled=true],.quantity__button.disabled{cursor:not-allowed;opacity:.5}button.loading{color:transparent!important;cursor:default;pointer-events:none;position:relative}button.loading:before{-webkit-animation:spin 1s linear infinite;animation:spin 1s linear infinite;background-color:#fff;bottom:0;content:"";height:20px;left:0;margin:auto;-webkit-mask:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cpath d='M512 1024q-104 0-199-40-92-39-163-110T40 711Q0 616 0 512q0-15 10.5-25.5T36 476t25.5 10.5T72 512q0 90 35 171 33 79 94 140t140 95q81 34 171 34t171-35q79-33 140-94t95-140q34-81 34-171t-35-171q-33-79-94-140t-140-95q-81-34-171-34-15 0-25.5-10.5T476 36t10.5-25.5T512 0q104 0 199 40 92 39 163 110t110 163q40 95 40 199t-40 199q-39 92-110 163T711 984q-95 40-199 40z' fill='%232a80eb'/%3E%3C/svg%3E") no-repeat;mask:url("data:image/svg+xml;charset=utf-8,%3Csvg viewBox='0 0 1024 1024' xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cpath d='M512 1024q-104 0-199-40-92-39-163-110T40 711Q0 616 0 512q0-15 10.5-25.5T36 476t25.5 10.5T72 512q0 90 35 171 33 79 94 140t140 95q81 34 171 34t171-35q79-33 140-94t95-140q34-81 34-171t-35-171q-33-79-94-140t-140-95q-81-34-171-34-15 0-25.5-10.5T476 36t10.5-25.5T512 0q104 0 199 40 92 39 163 110t110 163q40 95 40 199t-40 199q-39 92-110 163T711 984q-95 40-199 40z' fill='%232a80eb'/%3E%3C/svg%3E") no-repeat;-webkit-mask-size:100% 100%;mask-size:100% 100%;position:absolute;right:0;top:0;width:20px;z-index:99}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(1turn)}}.spinner{animation:loading 3s linear infinite}.spinner .path{stroke-dashoffset:0;stroke-dasharray:300;stroke-width:10;stroke-miterlimit:10;stroke-linecap:round;fill:transparent;animation:loading-circle 2s linear infinite}.button.loading>.loading-overlay__spinner .path{stroke:rgb(var(--color-foreground))}@keyframes loading{0%{transform:rotate(0)}to{transform:rotate(1turn)}}@keyframes loading-circle{0%{stroke-dashoffset:0}to{stroke-dashoffset:-600}}.customer .field input,.customer select,.field__input,.field__select,.select__select{-webkit-appearance:none;appearance:none;background-color:rgb(var(--color-background));background-color:var(--color-background);border:0;border-radius:var(--inputs-radius);box-sizing:border-box;color:rgb(var(--color-foreground));font-size:1.6rem;height:4.5rem;min-height:calc(var(--inputs-border-width)*2);min-width:calc(7rem + var(--inputs-border-width)*2);position:relative;transition:box-shadow var(--duration-short) ease;width:100%}.customer .field:before,.customer select:before,.field:before,.select:before{border-radius:var(--inputs-radius-outset);bottom:0;box-shadow:var(--inputs-shadow-horizontal-offset) var(--inputs-shadow-vertical-offset) var(--inputs-shadow-blur-radius) rgba(var(--color-shadow),var(--inputs-shadow-opacity));content:"";left:0;pointer-events:none;position:absolute;right:0;top:0}.customer .field:after,.customer select:after,.field:after,.select:after{border:.1rem solid transparent;border-radius:var(--inputs-radius);bottom:var(--inputs-border-width);box-shadow:0 0 0 var(--inputs-border-width) rgba(var(--color-foreground),var(--inputs-border-opacity));content:"";left:var(--inputs-border-width);pointer-events:none;position:absolute;right:var(--inputs-border-width);top:var(--inputs-border-width);transition:box-shadow var(--duration-short) ease;z-index:1}.select__select{color:rgba(var(--color-foreground),.75);font-family:var(--font-body-family);font-size:1.4rem;font-style:var(--font-body-style);font-weight:var(--font-body-weight)}.customer .field:hover.field:after,.customer select:hover.select:after,.field:hover.field:after,.select:hover.select:after,.select__select:hover.select__select:after{border-radius:var(--inputs-radius);box-shadow:0 0 0 calc(.1rem + var(--inputs-border-width)) rgba(var(--color-foreground),var(--inputs-border-opacity));outline:0}.customer .field input:focus-visible,.customer select:focus-visible,.field__input:focus-visible,.field__select:focus-visible,.select__select:focus-visible{border-radius:var(--inputs-radius);box-shadow:0 0 0 calc(.1rem + var(--inputs-border-width)) rgba(var(--color-foreground));outline:0}.customer .field input:focus,.customer select:focus,.field__input:focus,.field__select:focus,.select__select:focus{border-radius:var(--inputs-radius);box-shadow:0 0 0 calc(.1rem + var(--inputs-border-width)) rgba(var(--color-foreground));outline:0}.select,.text-area{display:flex;position:relative;width:100%}.select .icon-caret,select+svg{height:.6rem;pointer-events:none;position:absolute;right:calc(var(--inputs-border-width) + 1.5rem);top:calc(50% - .2rem)}[dir=rtl] .select .icon-caret,[dir=rtl] select+svg{left:calc(var(--inputs-border-width) + 1.5rem);right:auto}.field{position:relative;transition:box-shadow var(--duration-short) ease;width:100%}.customer .field,.field{display:flex}.field--with-error{flex-wrap:wrap}.customer .field input,.field__input,.field__select{flex-grow:1;margin:var(--inputs-border-width);padding:1.5rem;transition:box-shadow var(--duration-short) ease}.customer .field label,.field__label{color:rgba(var(--color-foreground),.75);font-size:1.6rem;left:calc(var(--inputs-border-width) + 1.2rem);letter-spacing:.1rem;line-height:1.5;margin-bottom:0;pointer-events:none;position:absolute;top:calc(1rem + var(--inputs-border-width));transition:top var(--duration-short) ease,font-size var(--duration-short) ease}[dir=rtl] .customer .field label,[dir=rtl] .field__label{left:auto;right:calc(var(--inputs-border-width) + 1.2rem)}.customer .field input:-webkit-autofill~label,.customer .field input:focus~label,.customer .field input:not(:placeholder-shown)~label,.customer .field select:-webkit-autofill~label,.customer .field select:focus~label,.customer .field select:not(:placeholder-shown)~label,.field__input:-webkit-autofill~.field__label,.field__input:focus~.field__label,.field__input:not(:placeholder-shown)~.field__label{font-size:1rem;left:calc(var(--inputs-border-width) + 1.2rem);letter-spacing:.04rem;top:calc(var(--inputs-border-width) + .5rem)}.customer .field input:-webkit-autofill,.customer .field input:focus,.customer .field input:not(:placeholder-shown),.field__input:-webkit-autofill,.field__input:focus,.field__input:not(:placeholder-shown){margin:var(--inputs-border-width);padding:2.2rem 1.2rem .8rem}.customer .field select:-webkit-autofill,.customer .field select:focus,.customer .field select:not(:placeholder-shown){margin:var(--inputs-border-width);padding:1.8rem 1.2rem .6rem}.customer select{appearance:none;-moz-appearance:none;-webkit-appearance:none;background:#fff url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkiIGhlaWdodD0iMTIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0ibTEwLjU4OSAxMC45MTUgOC4wOTktOS4yNTZBMSAxIDAgMCAwIDE3LjkzNSAwSDEuNzM3YTEgMSAwIDAgMC0uNzUzIDEuNjU5bDguMSA5LjI1NmExIDEgMCAwIDAgMS41MDUgMHoiIGZpbGw9IiM3NzciIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvc3ZnPg==) no-repeat 95%;background-position:right 12px center;background-size:10px 6px}.customer .field input::-webkit-search-cancel-button,.field__input::-webkit-search-cancel-button{display:none}.customer .field input::placeholder,.field__input::placeholder{opacity:0}.field__button{align-items:center;background-color:transparent;border:0;color:currentColor;cursor:pointer;height:4.4rem;justify-content:center;overflow:hidden;padding:0;position:absolute;right:0;top:0;width:4.4rem}[dir=rtl] .field__button{left:0;right:auto}.field__button>svg{height:2.5rem;width:2.5rem}.customer .field input:-webkit-autofill~label,.field__input:-webkit-autofill~.field__button,.field__input:-webkit-autofill~.field__label{color:#000}.text-area{font-family:var(--font-body-family);font-style:var(--font-body-style);font-weight:var(--font-body-weight);min-height:10rem;resize:none}input[type=checkbox]{display:inline-block;margin-right:.5rem;width:auto}.quantity{border-radius:var(--inputs-radius);color:rgba(var(--color-foreground));display:flex;min-height:calc(var(--inputs-border-width)*2 + 4.5rem);position:relative;width:calc(14rem/var(--font-base-scale) + var(--inputs-border-width)*2)}.quantity:after{border:.1rem solid transparent;border-radius:var(--inputs-radius);bottom:var(--inputs-border-width);box-shadow:0 0 0 var(--inputs-border-width) rgba(var(--color-foreground),var(--inputs-border-opacity));content:"";left:var(--inputs-border-width);pointer-events:none;position:absolute;right:var(--inputs-border-width);top:var(--inputs-border-width);transition:box-shadow var(--duration-short) ease;z-index:1}.quantity__input{-webkit-appearance:none;appearance:none;color:currentColor;flex-grow:1;font-size:1.4rem;font-weight:500;opacity:.85;padding:0 .5rem;text-align:center;width:100%}.quantity__button,.quantity__input{background-color:transparent;border:0}.quantity__button{align-items:center;color:rgb(var(--color-foreground));cursor:pointer;display:flex;flex-shrink:0;font-size:1.8rem;justify-content:center;padding:0;width:calc(4.5rem/var(--font-base-scale))}.quantity__button:first-child{margin-left:calc(var(--inputs-border-width))}.quantity__button:last-child{margin-right:calc(var(--inputs-border-width))}.quantity__button svg{pointer-events:none;width:1rem}.quantity__button:focus-visible,.quantity__input:focus-visible{z-index:2}.quantity__button:focus,.quantity__input:focus{z-index:2}.quantity__button:not(:focus-visible):not(.focused),.quantity__input:not(:focus-visible):not(.focused){background-color:inherit;box-shadow:inherit}.quantity__input:-webkit-autofill,.quantity__input:-webkit-autofill:active,.quantity__input:-webkit-autofill:hover{box-shadow:0 0 0 10rem rgb(var(--color-background)) inset!important;-webkit-box-shadow:0 0 0 10rem rgb(var(--color-background)) inset!important}.quantity__input::-webkit-inner-spin-button,.quantity__input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.quantity__input[type=number]{-moz-appearance:textfield}.modal__toggle{list-style-type:none}.modal__toggle-close{display:none}.modal__toggle-open{display:flex}.modal__close-button.link{align-items:center;background-color:transparent;display:flex;height:4.4rem;justify-content:center;padding:0;width:4.4rem}.modal__close-button .icon{height:1.7rem;width:1.7rem}.modal__content{align-items:center;background:rgb(var(--color-background));bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:4}.media-modal{cursor:zoom-out}.media-modal .deferred-media{cursor:auto}.media>img{object-fit:cover;object-position:center center;transition:opacity .4s cubic-bezier(.25,.46,.45,.94)}.rte:after{clear:both;content:"";display:block}.rte p{word-wrap:break-word}.rte>p:first-child{margin-top:0}.rte>p:last-child{margin-bottom:0}.rte table{table-layout:fixed}@media screen and (min-width:750px){.rte table td{padding-left:1.2rem;padding-right:1.2rem}}.rte img{border:var(--media-border-width) solid rgba(var(--color-foreground),var(--media-border-opacity));border-radius:var(--media-radius);box-shadow:var(--media-shadow-horizontal-offset) var(--media-shadow-vertical-offset) var(--media-shadow-blur-radius) rgba(var(--color-shadow),var(--media-shadow-opacity));height:auto;margin-bottom:var(--media-shadow-vertical-offset);max-width:100%}.rte ol,.rte ul{list-style-position:inside;padding-left:2rem}.rte li{list-style:inherit}.rte li:last-child{margin-bottom:0}.rte a{color:rgba(var(--color-link),var(--alpha-link));text-decoration-thickness:.1rem;text-underline-offset:.3rem;transition:text-decoration-thickness var(--duration-short) ease}.rte a:hover{color:rgb(var(--color-link));text-decoration-thickness:.2rem}.rte blockquote{display:inline-flex}.rte blockquote>*{margin:-.5rem 0}.rte video{height:auto;max-width:100%}@media (prefers-reduced-motion:no-preference){.animate--ambient>img,.animate--ambient>svg{animation:animateAmbient 30s linear infinite}@keyframes animateAmbient{0%{transform:rotate(0deg) translateX(1em) rotate(0deg) scale(1.2)}to{transform:rotate(1turn) translateX(1em) rotate(-1turn) scale(1.2)}}}.toast{align-items:center;border-radius:4px;box-sizing:border-box;color:#333639;display:flex;left:50%;max-width:calc(100% - 32px);opacity:0;padding:6px 20px;pointer-events:all;position:fixed;top:8%;transform:translate(-50%,-50%);transition:opacity .3s,transform .4s,top .4s;width:fit-content;z-index:2002}.toast-info{background-color:#f0f9eb;color:#67c23a;opacity:1}.toast-error{background-color:#fef0f0;color:#f56c6c;opacity:1}.toast-hidden{opacity:0}.cart-count-bubble{align-items:center;background-color:rgb(var(--color-button));border-radius:100%;bottom:.8rem;color:rgb(var(--color-button-text));display:flex;font-size:.9rem;height:1.7rem;justify-content:center;left:2.2rem;line-height:calc(1 + .1/var(--font-body-scale));position:absolute;width:1.7rem}.cart-count-hidden{display:none}.card-wrapper{color:inherit;height:100%;position:relative}.card,.card-wrapper{text-decoration:none}.card{text-align:var(--text-alignment)}.card--card{height:100%}.card--card,.card--standard .card__inner{border:var(--border-width) solid rgba(var(--color-foreground),var(--border-opacity));border-radius:var(--border-radius);box-sizing:border-box;position:relative}.card--card:after,.card--standard .card__inner:after{border-radius:var(--border-radius);box-shadow:var(--shadow-horizontal-offset) var(--shadow-vertical-offset) var(--shadow-blur-radius) rgba(var(--color-shadow),var(--shadow-opacity));content:"";height:calc(var(--border-width)*2 + 100%);left:calc(var(--border-width)*-1);position:absolute;top:calc(var(--border-width)*-1);width:calc(var(--border-width)*2 + 100%);z-index:-1}.card .card__inner .card__media{border-radius:calc(var(--border-radius) - var(--border-width) - var(--image-padding));overflow:hidden;z-index:0}.card--card .card__inner .card__media{border-bottom-left-radius:0;border-bottom-right-radius:0}.card--standard.card--text{background-color:transparent}.card-information{text-align:var(--text-alignment)}.card .media,.card__media{bottom:0;position:absolute;top:0}.card .media{width:100%}.card__media{width:calc(100% - var(--image-padding)*2)}.card--standard .card__media,.card__media{margin:var(--image-padding)}.card__inner{width:100%}.card--media .card__inner .card__content{padding:calc(var(--image-padding) + 1rem);position:relative}.card__content{display:grid;flex-grow:1;grid-template-rows:minmax(0,1fr) max-content minmax(0,1fr);padding:1rem;width:100%}.card__content--auto-margins{grid-template-rows:minmax(0,auto) max-content minmax(0,auto)}.card__information{grid-row-start:2;padding:1.3rem 1rem}@media screen and (min-width:750px){.card__information{padding-bottom:1.7rem;padding-top:1.7rem}}.card__badge{align-self:flex-end;grid-row-start:3;justify-self:flex-start}.card__badge.top{align-self:flex-start;grid-row-start:1}.card__badge.right{justify-self:flex-end}.card__media .media img{height:100%;object-fit:cover;object-position:center center;width:100%}.card__heading{margin-top:0}.card__heading,.card__heading:last-child{margin-bottom:0}.card--card.card--media>.card__content{margin-top:calc(0rem - var(--image-padding))}.card--card .card__heading a:after,.card--standard.card--text a:after{bottom:calc(var(--border-width)*-1);left:calc(var(--border-width)*-1);right:calc(var(--border-width)*-1);top:calc(var(--border-width)*-1)}.card__heading a:after{bottom:0;content:"";left:0;outline-offset:.3rem;position:absolute;right:0;top:0;z-index:1}.card__heading a:focus:after{box-shadow:0 0 0 .3rem rgb(var(--color-background)),0 0 .5rem .4rem rgba(var(--color-foreground),.3);outline:.2rem solid rgba(var(--color-foreground),.5)}.card__heading a:focus-visible:after{box-shadow:0 0 0 .3rem rgb(var(--color-background)),0 0 .5rem .4rem rgba(var(--color-foreground),.3);outline:.2rem solid rgba(var(--color-foreground),.5)}.card__heading a:focus:not(:focus-visible):after{box-shadow:none;outline:0}.card__heading a:focus{box-shadow:none;outline:0}@media screen and (min-width:990px){.card .media.media--hover-effect>img:only-child,.card-wrapper .media.media--hover-effect>img:only-child{transition:transform var(--duration-long) ease}.card-wrapper:hover .media.media--hover-effect>img:first-child:only-child,.card:hover .media.media--hover-effect>img:first-child:only-child{transform:scale(1.03)}.card-wrapper:hover .media.media--hover-effect>img:first-child:not(:only-child){opacity:0}.card-wrapper:hover .media.media--hover-effect>img+img{opacity:1;transform:scale(1.03);transition:transform var(--duration-long) ease}.underline-links-hover:hover a{text-decoration:underline;text-underline-offset:.3rem}}.card--standard.card--media .card__inner .card__information,.card--standard.card--text.article-card>.card__content .card__information,.card--standard>.card__content .card__caption{display:none}.card--standard>.card__content{padding:0}.card--standard>.card__content .card__information{padding-left:0;padding-right:0}.card--card.card--media .card__inner .card__information,.card--card.card--media>.card__content .card__badge,.card--card.card--text .card__inner{display:none}.card--extend-height{height:100%}.card--extend-height.card--media,.card--extend-height.card--standard.card--text{display:flex;flex-direction:column}.card--extend-height.card--media .card__inner,.card--extend-height.card--standard.card--text .card__inner{flex-grow:1}.card .icon-wrap{margin-left:.8rem;overflow:hidden;transition:transform var(--duration-short) ease;white-space:nowrap}.card-information>*+*{margin-top:.5rem}.card-information{width:100%}.card-information>*{line-height:calc(1 + .4/var(--font-body-scale))}.card-information>*,.card-information>.price{color:rgb(var(--color-foreground))}.card-information>.rating{margin-top:.4rem}.card-information>:not(.visually-hidden:first-child)+:not(.rating){margin-top:.7rem}.card-information .caption{letter-spacing:.07rem}.card-article-info{margin-top:1rem}.text-1\.2{font-size:1.2rem}.text-1\.3{font-size:1.3rem}@media screen and (min-width:750px){.md\:text-1\.6{font-size:1.6rem}}.leading-1\.5{line-height:1.5}.leading-1\.6{line-height:1.6}.shoptop-section-header-sticky{position:sticky;top:0}.shoptop-section-header-hidden{top:calc(var(--header-height)*-1)}.gradient{background:rgb(var(--color-background));background:var(--gradient-background);background-attachment:fixed}.global-settings-popup,.header__submenu.global-settings-popup{border-color:rgba(var(--color-foreground),var(--popup-border-opacity));border-radius:var(--popup-corner-radius);border-style:solid;border-width:var(--popup-border-width);box-shadow:var(--popup-shadow-horizontal-offset) var(--popup-shadow-vertical-offset) var(--popup-shadow-blur-radius) rgba(var(--color-shadow),var(--popup-shadow-opacity));z-index:-1}.section-header.animate{transition:top .15s ease-out}.header-wrapper--border-bottom{border-bottom:.1rem solid rgba(0,0,0,.08)}.header-wrapper{background-color:rgb(var(--color-background));display:block;position:relative;transition:background .4s cubic-bezier(.165,.84,.44,1)}.header{align-items:center;display:grid;grid-template-areas:"left-icons heading icons";grid-template-columns:1fr 2fr 1fr}details-disclosure>details,header-menu>details{position:relative}.header__menu-item{color:rgba(var(--color-foreground),.75);padding:1.2rem;text-decoration:none}summary.list-menu__item{padding-right:2.7rem}[dir=rtl] summary.list-menu__item{padding-left:2.7rem;padding-right:1.2rem}.list-menu__item{align-items:center;display:flex;line-height:calc(1 + .3/var(--font-base-scale))}@media screen and (min-width:750px){.header{padding-left:3.2rem;padding-right:3.2rem}}@media screen and (min-width:990px){.header{grid-template-columns:1fr auto 1fr;padding-left:5rem;padding-right:5rem}.header--middle-left:not(.header--has-menu),.header--top-left{grid-template-areas:"heading icons" "navigation navigation";grid-template-columns:1fr auto}.header--middle-left.drawer-menu,.header--top-left.drawer-menu{column-gap:1rem;grid-template-areas:"navigation heading icons";grid-template-columns:auto 1fr auto}.header--middle-left{column-gap:2rem;grid-template-areas:"heading navigation icons";grid-template-columns:auto auto 1fr}.header--middle-center:not(.drawer-menu){column-gap:2rem;grid-template-areas:"navigation heading icons";grid-template-columns:1fr auto 1fr}.header--middle-center a.header__heading-link{text-align:center}.header--top-center{grid-template-areas:"left-icons heading icons" "navigation navigation navigation"}.header--top-center.drawer-menu{grid-template-areas:"left-icons heading icons";grid-template-columns:1fr auto 1fr}.header:not(.header--middle-left,.header--middle-center) .header__inline-menu{margin-top:1.05rem}}@media screen and (max-width:989px){.header--mobile-left .header__heading,.header--mobile-left .header__heading-link{justify-self:start;text-align:left}.header--mobile-left{grid-template-columns:auto 2fr 1fr}}.header__heading{line-height:0;margin:0}.header__heading-link{display:inline-block;padding:.75rem;text-decoration:none;word-break:break-word}.header__heading,.header__heading-link{grid-area:heading;justify-self:center}.header__heading-logo-wrapper{display:inline-block;transition:width .3s cubic-bezier(.52,0,.61,.99);width:100%}.header__heading-logo{max-width:100%}@media screen and (min-width:990px){.header__heading,.header__heading-link{justify-self:start}}details[open]>.header__submenu{animation:animateMenuOpen var(--duration-default) ease;animation-fill-mode:forwards;z-index:1}@media (prefers-reduced-motion){details[open]>.header__submenu{opacity:1;transform:translateY(0)}}@keyframes animateMenuOpen{0%{opacity:0;transform:translateY(-1.5rem)}to{opacity:1;transform:translateY(0)}}details>.header__submenu{opacity:0;transform:translateY(-1.5rem)}.header__submenu.list-menu{padding:2.4rem 0}.header__submenu .header__submenu{background-color:var(--color-foreground);margin:.5rem 0;padding:.5rem 0}.header__icons{display:flex;grid-area:icons;justify-self:end}.header__icon{height:4.4rem;padding:0;position:relative;width:4.4rem}.header__icon span{align-items:center;display:flex;height:100%;justify-content:center}.header__icon .icon{fill:none;height:2rem;width:2rem}.header__search{display:inline-flex;line-height:0}.header__icon--account,.header__icon--search{align-items:center;display:flex;justify-content:center}.header__icon--cart .icon{height:4.4rem;padding:0;width:4.4rem}.header>.header__search{grid-area:left-icons;justify-self:start}.header--top-center header-drawer{grid-area:left-icons}details[open]>.search-modal{animation:animateMenuOpen var(--duration-default) ease;opacity:1}details[open] .modal-overlay{display:block}details[open] .modal-overlay:after{background-color:rgb(var(--color-foreground),.5);content:"";height:100vh;left:0;position:absolute;right:0;top:100%}.search-modal{border-bottom:.1rem solid rgba(var(--color-foreground),.08);height:100%;min-height:calc(100% + var(--inputs-margin-offset) + var(--inputs-border-width)*2);opacity:0}.search-modal__content{align-items:center;display:flex;height:100%;justify-content:center;line-height:calc(1 + .8/var(--font-base-scale));padding:0 5rem 0 1rem;width:100%}.search-modal__content-bottom{bottom:calc(var(--inputs-margin-offset)/2)}.search-modal__content-top{top:calc(var(--inputs-margin-offset)/2)}.search-modal__form{width:100%}.search-modal__form .icon-search{color:rgba(var(--color-foreground),1)}.search-modal__close-button{position:absolute;right:.3rem}@media screen and (min-width:990px){.search-modal__content{position:relative}.search-modal__form{max-width:74.2rem}.search-modal__close-button{margin-left:.5rem;position:static}}.reset__button:not(:focus):after{border-right:.1rem solid rgba(var(--color-foreground),.08);content:"";display:block;height:calc(100% - 1.8rem);position:absolute;right:0}.reset__button{right:calc(var(--inputs-border-width) + 4.4rem);top:var(--inputs-border-width)}.reset__button .icon.icon-close{stroke-width:.1rem;height:1.8rem;width:1.8rem}.header__inline-menu{display:none;grid-area:navigation;margin-left:-1.2rem}.header--top-center .header__heading-link,.header--top-center .header__inline-menu{margin-left:0}@media screen and (min-width:990px){.header__inline-menu{display:block}.header--top-center .header__inline-menu{justify-self:center}.header--top-center .header__inline-menu>.list-menu--inline{justify-content:center}.header--middle-left .header__inline-menu{margin-left:0}}.header--top-center>.header__search{display:none}.header--top-center *>.header__search{display:inline-flex}@media screen and (min-width:990px){.header--top-center>.header__search,.header:not(.header--top-center) *>.header__search{display:inline-flex}.header--top-center *>.header__search,.header:not(.header--top-center)>.header__search{display:none}}summary .icon-caret{height:.6rem;position:absolute;right:1.5rem;top:calc(50% - .2rem)}.header__menu-item .icon-caret{right:.8rem}[dir=rtl] summary .icon-caret{left:1.5rem;right:auto}[dir=rtl] .header__menu-item .icon-caret{left:.8rem;right:auto}.header--top-left .header__heading{justify-self:start}@media screen and (min-width:990px){.header--top-left .header__heading-link{margin-left:-.75rem}}.header--top-center.drawer-menu>.header__search{margin-left:3.2rem}.header__icon--menu[aria-expanded=true]:before{background:rgba(0,0,0,.5);content:"";display:block;height:calc(var(--viewport-height, 100vh) - var(--header-bottom-position, 100%));left:0;position:absolute;top:100%;width:100%}details:not([open])>.header__icon--menu .icon-close,details[open]>.header__icon--menu .icon-hamburger{opacity:0;transform:scale(.8);visibility:hidden}.header__icon--menu .icon{display:block;opacity:1;position:absolute;transform:scale(1);transition:transform .15s ease,opacity .15s ease}.overflow-hidden-desktop,.overflow-hidden-mobile,.overflow-hidden-tablet{overflow:hidden}@media screen and (min-width:750px){.overflow-hidden-mobile{overflow:auto}}@media screen and (min-width:990px){.overflow-hidden-tablet{overflow:auto}}.social-list{display:flex;flex-wrap:wrap;margin-left:-1.3rem;margin-right:-1.3rem}.social-list .social-list__link{align-items:center;color:rgb(var(--color-foreground));display:flex;padding:1.3rem}.social-list .icon{height:1.8rem;width:1.8rem}.max-w-xl{max-width:36rem}.newsletter-form__button{height:100%;margin:0;right:var(--inputs-border-width);top:0;width:4.4rem;z-index:2}.newsletter-form__button .icon{height:2.5rem;width:1.5rem}.newsletter-form__message{display:none;font-size:1.4rem;line-height:1}.newsletter-form__message .icon{display:none;flex-shrink:0;height:1.8rem;margin-right:.5rem;width:1.8rem}.newsletter-form__message[data-status=success]{color:#5ead60;display:flex}.newsletter-form__message[data-status=success] .icon-success{display:block}.newsletter-form__message[data-status=error]{color:#f86262;display:flex}.newsletter-form__message[data-status=error] .icon-error{display:block}.newsletter__wrap{padding-left:calc(4rem/var(--font-base-scale));padding-right:calc(4rem/var(--font-base-scale))}@media screen and (min-width:750px){.newsletter__wrap{padding-left:9rem;padding-right:9rem}.contact__fields{grid-column-gap:24px;display:grid;grid-template-columns:repeat(2,1fr)}}.contact .field{margin-bottom:1.5rem}@media screen and (min-width:750px){.contact .field{margin-bottom:2rem}}:root{--swiper-theme-color:#007aff}.swiper,swiper-container{display:block;list-style:none;margin-left:auto;margin-right:auto;overflow:hidden;padding:0;position:relative;z-index:1}.swiper-vertical>.swiper-wrapper{flex-direction:column}.swiper-wrapper{box-sizing:content-box;display:flex;height:100%;position:relative;transition-property:transform;transition-timing-function:var(--swiper-wrapper-transition-timing-function,initial);width:100%;z-index:1}.swiper-horizontal{touch-action:pan-y}.swiper-vertical{touch-action:pan-x}.swiper-slide,swiper-slide{box-sizing:border-box;display:block;flex-shrink:0;height:100%;position:relative;transition-property:transform;width:100%}.swiper-slide-invisible-blank{visibility:hidden}.swiper-autoheight,.swiper-autoheight .swiper-slide{height:auto}.swiper-autoheight .swiper-wrapper{align-items:flex-start;transition-property:transform,height}.swiper-backface-hidden .swiper-slide{-webkit-backface-visibility:hidden;backface-visibility:hidden;transform:translateZ(0)}.swiper-3d.swiper-css-mode .swiper-wrapper{perspective:1200px}.swiper-3d .swiper-wrapper{transform-style:preserve-3d}.swiper-3d{perspective:1200px}.swiper-3d .swiper-cube-shadow,.swiper-3d .swiper-slide,.swiper-3d .swiper-slide-shadow,.swiper-3d .swiper-slide-shadow-bottom,.swiper-3d .swiper-slide-shadow-left,.swiper-3d .swiper-slide-shadow-right,.swiper-3d .swiper-slide-shadow-top{transform-style:preserve-3d}.swiper-3d .swiper-slide-shadow,.swiper-3d .swiper-slide-shadow-bottom,.swiper-3d .swiper-slide-shadow-left,.swiper-3d .swiper-slide-shadow-right,.swiper-3d .swiper-slide-shadow-top{height:100%;left:0;pointer-events:none;position:absolute;top:0;width:100%;z-index:10}.swiper-3d .swiper-slide-shadow{background:rgba(0,0,0,.15)}.swiper-3d .swiper-slide-shadow-left{background-image:linear-gradient(270deg,rgba(0,0,0,.5),transparent)}.swiper-3d .swiper-slide-shadow-right{background-image:linear-gradient(90deg,rgba(0,0,0,.5),transparent)}.swiper-3d .swiper-slide-shadow-top{background-image:linear-gradient(0deg,rgba(0,0,0,.5),transparent)}.swiper-3d .swiper-slide-shadow-bottom{background-image:linear-gradient(180deg,rgba(0,0,0,.5),transparent)}.swiper-css-mode>.swiper-wrapper{-ms-overflow-style:none;overflow:auto;scrollbar-width:none}.swiper-css-mode>.swiper-wrapper::-webkit-scrollbar{display:none}.swiper-css-mode>.swiper-wrapper>.swiper-slide{scroll-snap-align:start start}.swiper-horizontal.swiper-css-mode>.swiper-wrapper{scroll-snap-type:x mandatory}.swiper-vertical.swiper-css-mode>.swiper-wrapper{scroll-snap-type:y mandatory}.swiper-css-mode.swiper-free-mode>.swiper-wrapper{scroll-snap-type:none}.swiper-css-mode.swiper-free-mode>.swiper-wrapper>.swiper-slide{scroll-snap-align:none}.swiper-centered>.swiper-wrapper:before{content:"";flex-shrink:0;order:9999}.swiper-centered>.swiper-wrapper>.swiper-slide{scroll-snap-align:center center;scroll-snap-stop:always}.swiper-centered.swiper-horizontal>.swiper-wrapper>.swiper-slide:first-child{margin-inline-start:var(--swiper-centered-offset-before)}.swiper-centered.swiper-horizontal>.swiper-wrapper:before{height:100%;min-height:1px;width:var(--swiper-centered-offset-after)}.swiper-centered.swiper-vertical>.swiper-wrapper>.swiper-slide:first-child{margin-block-start:var(--swiper-centered-offset-before)}.swiper-centered.swiper-vertical>.swiper-wrapper:before{height:var(--swiper-centered-offset-after);min-width:1px;width:100%}.swiper-lazy-preloader{border:4px solid var(--swiper-preloader-color,var(--swiper-theme-color));border-radius:50%;border-top:4px solid transparent;box-sizing:border-box;height:42px;left:50%;margin-left:-21px;margin-top:-21px;position:absolute;top:50%;transform-origin:50%;width:42px;z-index:10}.swiper-watch-progress .swiper-slide-visible .swiper-lazy-preloader,.swiper:not(.swiper-watch-progress) .swiper-lazy-preloader,swiper-container:not(.swiper-watch-progress) .swiper-lazy-preloader{animation:swiper-preloader-spin 1s linear infinite}.swiper-lazy-preloader-white{--swiper-preloader-color:#fff}.swiper-lazy-preloader-black{--swiper-preloader-color:#000}@keyframes swiper-preloader-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}:root{--swiper-navigation-size:44px}.swiper-button-next,.swiper-button-prev{align-items:center;color:var(--swiper-navigation-color,var(--swiper-theme-color));cursor:pointer;display:flex;height:var(--swiper-navigation-size);justify-content:center;margin-top:calc(0px - var(--swiper-navigation-size)/2);position:absolute;top:var(--swiper-navigation-top-offset,50%);width:calc(var(--swiper-navigation-size)/44*27);z-index:10}.swiper-button-next.swiper-button-disabled,.swiper-button-prev.swiper-button-disabled{cursor:auto;opacity:.35;pointer-events:none}.swiper-button-next.swiper-button-hidden,.swiper-button-prev.swiper-button-hidden{cursor:auto;opacity:0;pointer-events:none}.swiper-navigation-disabled .swiper-button-next,.swiper-navigation-disabled .swiper-button-prev{display:none!important}.swiper-button-next:after,.swiper-button-prev:after{font-family:swiper-icons;font-size:var(--swiper-navigation-size);font-variant:normal;letter-spacing:0;line-height:1;text-transform:none!important}.swiper-button-prev,.swiper-rtl .swiper-button-next{left:var(--swiper-navigation-sides-offset,10px);right:auto}.swiper-button-prev:after,.swiper-rtl .swiper-button-next:after{content:"prev"}.swiper-button-next,.swiper-rtl .swiper-button-prev{left:auto;right:var(--swiper-navigation-sides-offset,10px)}.swiper-button-next:after,.swiper-rtl .swiper-button-prev:after{content:"next"}.swiper-button-lock{display:none}.swiper-pagination{position:absolute;text-align:center;transition:opacity .3s;z-index:10}.swiper-pagination.swiper-pagination-hidden{opacity:0}.swiper-pagination-disabled>.swiper-pagination,.swiper-pagination.swiper-pagination-disabled{display:none!important}.swiper-horizontal>.swiper-pagination-bullets,.swiper-pagination-bullets.swiper-pagination-horizontal,.swiper-pagination-custom,.swiper-pagination-fraction{bottom:var(--swiper-pagination-bottom,8px);left:0;top:var(--swiper-pagination-top,auto);width:100%}.swiper-pagination-bullets-dynamic{font-size:0;overflow:hidden}.swiper-pagination-bullets-dynamic .swiper-pagination-bullet{position:relative;transform:scale(.33)}.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active,.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-main{transform:scale(1)}.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-prev{transform:scale(.66)}.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-prev-prev{transform:scale(.33)}.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-next{transform:scale(.66)}.swiper-pagination-bullets-dynamic .swiper-pagination-bullet-active-next-next{transform:scale(.33)}.swiper-pagination-bullet{background:var(--swiper-pagination-bullet-inactive-color,#000);border-radius:var(--swiper-pagination-bullet-border-radius,50%);display:inline-block;height:var(--swiper-pagination-bullet-height,var(--swiper-pagination-bullet-size,8px));opacity:var(--swiper-pagination-bullet-inactive-opacity,.2);width:var(--swiper-pagination-bullet-width,var(--swiper-pagination-bullet-size,8px))}button.swiper-pagination-bullet{-webkit-appearance:none;appearance:none;border:none;box-shadow:none;margin:0;padding:0}.swiper-pagination-clickable .swiper-pagination-bullet{cursor:pointer}.swiper-pagination-bullet:only-child{display:none!important}.swiper-pagination-bullet-active{background:var(--swiper-pagination-color,var(--swiper-theme-color));opacity:var(--swiper-pagination-bullet-opacity,1)}.swiper-pagination-vertical.swiper-pagination-bullets,.swiper-vertical>.swiper-pagination-bullets{left:var(--swiper-pagination-left,auto);right:var(--swiper-pagination-right,8px);top:50%;transform:translate3d(0,-50%,0)}.swiper-pagination-vertical.swiper-pagination-bullets .swiper-pagination-bullet,.swiper-vertical>.swiper-pagination-bullets .swiper-pagination-bullet{display:block;margin:var(--swiper-pagination-bullet-vertical-gap,6px) 0}.swiper-pagination-vertical.swiper-pagination-bullets.swiper-pagination-bullets-dynamic,.swiper-vertical>.swiper-pagination-bullets.swiper-pagination-bullets-dynamic{top:50%;transform:translateY(-50%);width:8px}.swiper-pagination-vertical.swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet,.swiper-vertical>.swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet{display:inline-block;transition:transform .2s,top .2s}.swiper-horizontal>.swiper-pagination-bullets .swiper-pagination-bullet,.swiper-pagination-horizontal.swiper-pagination-bullets .swiper-pagination-bullet{margin:0 var(--swiper-pagination-bullet-horizontal-gap,4px)}.swiper-horizontal>.swiper-pagination-bullets.swiper-pagination-bullets-dynamic,.swiper-pagination-horizontal.swiper-pagination-bullets.swiper-pagination-bullets-dynamic{left:50%;transform:translateX(-50%);white-space:nowrap}.swiper-horizontal>.swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet,.swiper-pagination-horizontal.swiper-pagination-bullets.swiper-pagination-bullets-dynamic .swiper-pagination-bullet{transition:transform .2s,left .2s}.swiper-horizontal.swiper-rtl>.swiper-pagination-bullets-dynamic .swiper-pagination-bullet,:host(.swiper-horizontal.swiper-rtl) .swiper-pagination-bullets-dynamic .swiper-pagination-bullet{transition:transform .2s,right .2s}.swiper-pagination-fraction{color:var(--swiper-pagination-fraction-color,inherit)}.swiper-pagination-progressbar{background:var(--swiper-pagination-progressbar-bg-color,rgba(0,0,0,.25));position:absolute}.swiper-pagination-progressbar .swiper-pagination-progressbar-fill{background:var(--swiper-pagination-color,var(--swiper-theme-color));height:100%;left:0;position:absolute;top:0;transform:scale(0);transform-origin:left top;width:100%}.swiper-rtl .swiper-pagination-progressbar .swiper-pagination-progressbar-fill{transform-origin:right top}.swiper-horizontal>.swiper-pagination-progressbar,.swiper-pagination-progressbar.swiper-pagination-horizontal,.swiper-pagination-progressbar.swiper-pagination-vertical.swiper-pagination-progressbar-opposite,.swiper-vertical>.swiper-pagination-progressbar.swiper-pagination-progressbar-opposite{height:var(--swiper-pagination-progressbar-size,4px);left:0;top:0;width:100%}.swiper-horizontal>.swiper-pagination-progressbar.swiper-pagination-progressbar-opposite,.swiper-pagination-progressbar.swiper-pagination-horizontal.swiper-pagination-progressbar-opposite,.swiper-pagination-progressbar.swiper-pagination-vertical,.swiper-vertical>.swiper-pagination-progressbar{height:100%;left:0;top:0;width:var(--swiper-pagination-progressbar-size,4px)}.swiper-pagination-lock{display:none}.swiper-zoom-container{align-items:center;display:flex;height:100%;justify-content:center;text-align:center;width:100%}.swiper-zoom-container>canvas,.swiper-zoom-container>img,.swiper-zoom-container>svg{max-height:100%;max-width:100%;object-fit:contain}.swiper-slide-zoomed{cursor:move;touch-action:none}.swiper-grid>.swiper-wrapper{flex-wrap:wrap}.swiper-grid-column>.swiper-wrapper{flex-direction:column;flex-wrap:wrap}.slider-container{display:block;list-style:none;margin-left:auto;margin-right:auto;padding:0;position:relative;z-index:1}.slider-wrap{display:flex;height:100%;z-index:1}.slider-slide,.slider-wrap{position:relative;transition-property:transform;width:100%}.slider-slide{display:block;flex-shrink:0;max-width:100%}.slideshow__controls{align-items:center;display:flex;justify-content:center}@media screen and (min-width:750px){.slideshow__controls.md\:hidden{display:none}}.slider-counter{min-width:4.4rem}.slider-button,.slider-counter{display:flex;justify-content:center}.slider-button{align-items:center;background:transparent;border:none;color:rgba(var(--color-foreground),.75);cursor:pointer;height:44px;width:44px}.slider-button svg{height:.6rem}[dir=rtl] .slider-button{rotate:180deg}.slider-button-disabled{cursor:auto;opacity:.35;pointer-events:none}.slider-button-prev svg{transform:rotate(90deg)}.slider-button-next svg{transform:rotate(-90deg)}.banner__media,.banner__media img{height:100%;left:0;position:absolute;top:0;width:100%}.banner__media img{display:block;max-width:100%;transition:opacity .4s cubic-bezier(.25,.46,.45,.94)}.media .sideshow__bg{background:#000;display:block;height:100%;opacity:0;position:absolute;top:0;width:100%;z-index:1}.banner__content{display:flex;justify-content:center;padding:0;z-index:2}.banner__container,.banner__content{align-items:center;position:relative;width:100%}.banner__container{word-wrap:break-word;height:fit-content;padding:4rem 3.5rem;text-align:center;z-index:1}.banner__box>:first-child{margin-top:0}@media screen and (min-width:750px){.banner__container{max-width:71rem;min-width:45rem;width:auto}}@media screen and (min-width:1400px){.banner__container{max-width:90rem}}@media screen and (min-width:750px){.banner--small:not(.banner--adapt){min-height:42rem}.banner--medium:not(.banner--adapt){min-height:56rem}.banner--large:not(.banner--adapt){min-height:72rem}.banner__content--top-left{align-items:flex-start;justify-content:flex-start}.banner__content--top-center{align-items:flex-start;justify-content:center}.banner__content--top-right{align-items:flex-start;justify-content:flex-end}.banner__content--middle-left{align-items:center;justify-content:flex-start}.banner__content--middle-center{align-items:center;justify-content:center}.banner__content--middle-right{align-items:center;justify-content:flex-end}.banner__content--bottom-left{align-items:flex-end;justify-content:flex-start}.banner__content--bottom-center{align-items:flex-end;justify-content:center}.banner__content--bottom-right{align-items:flex-end;justify-content:flex-end}}.slideshow__text-wrap.banner__content{height:100%;padding:5rem}.slideshow__text-wrap .banner__container{display:flex;flex-direction:column;justify-content:center;max-width:54.5rem}.slider-counter__link--dots .dot{border:.1rem solid rgba(var(--color-foreground),.5);border-radius:50%;display:block;height:1rem;padding:0;width:1rem}.slider-counter__link--active.slider-counter__link--dots .dot{background-color:rgb(var(--color-foreground))}.slideshow__play .icon.icon-pause,.slideshow__play .icon.icon-play{display:block;height:1.2rem;opacity:1;position:absolute;transform:scale(1);transition:transform .15s ease,opacity .15s ease;width:.8rem}.slideshow__play--paused .icon-pause,.slideshow__play:not(.slideshow__play--paused) .icon-play{opacity:0;transform:scale(.8);visibility:hidden}.slideshow__play:hover svg.icon{transform:scale(1.1)}.slideshow--adapt_image .slideshow__media{position:relative}.slideshow--adapt_image .slideshow__text-wrap{position:absolute;top:0}.slideshow-wrap .swiper-slide{box-sizing:border-box;height:auto}.slideshow-object-bottom{object-position:bottom!important}.slideshow-object-center{object-position:center!important}.slideshow-object-left{object-position:left!important}.slideshow-object-left-bottom{object-position:left bottom!important}.slideshow-object-left-top{object-position:left top!important}.slideshow-object-right{object-position:right!important}.slideshow-object-right-bottom{object-position:right bottom!important}.slideshow-object-right-top{object-position:right top!important}.slideshow-object-top{object-position:top!important}@media screen and (max-width:749px){.slideshow--small,.slideshow--small .banner__media{min-height:28rem}.slideshow--small.slideshow--bottom .slideshow__media{height:28rem}.slideshow--medium,.slideshow--medium .banner__media{min-height:34rem}.slideshow--medium.slideshow--bottom .slideshow__media{height:34rem}.slideshow--large,.slideshow--large .banner__media{min-height:39rem}.slideshow--large.slideshow--bottom .slideshow__media{height:39rem}.slideshow--bottom .slideshow__media{position:relative}.slideshow--bottom .slideshow__text-wrap.banner__content{height:auto}.slideshow--bottom .swiper-slide{display:flex;flex-direction:column}.slideshow--bottom .slideshow__text-wrap{flex-grow:1}.slideshow--bottom .banner__container{height:100%;max-width:100%}.slideshow--center .banner__container{border:none;border-radius:0;box-shadow:none}.slideshow--adapt_image.slideshow--bottom .slideshow__media{height:auto}.slideshow--adapt_image.slideshow--bottom .slideshow__text-wrap{position:relative}.slideshow__text-wrap.banner__content{padding:0}.slideshow-wrap .swiper-wrapper:not(.slideshow--bottom) .banner__container{--color-foreground:255,255,255;--color-button:255,255,255;--color-button-text:0,0,0;background:transparent}.slideshow-wrap .swiper-wrapper:not(.slideshow--bottom) .button--secondary{--color-button:255,255,255;--color-button-text:255,255,255;--alpha-button-background:0}.slideshow__media.has-second-image img:first-child{display:none}}@media screen and (min-width:750px){.slideshow__media.has-second-image img:first-child{display:block}.slideshow__media.has-second-image img:nth-child(2){display:none}.slideshow--small,.slideshow--small .banner__media{min-height:42rem}.slideshow--medium,.slideshow--medium .banner__media{min-height:56rem}.slideshow--large,.slideshow--large .banner__media{min-height:72rem}.slideshow__autoplay.slider-button{border-left:.1rem solid rgba(var(--color-foreground),.08);margin-left:.6rem;padding:0 0 0 .6rem;position:inherit}.hide_banner_content .banner__container{--color-foreground:255,255,255;--color-button:255,255,255;--color-button-text:0,0,0;background:transparent;border:none;border-radius:0;box-shadow:none;max-width:89rem}.hide_banner_content .banner__container:after{display:none}}.banner:after,.section-img-banner .banner__media:after{background:#000;content:"";height:100%;opacity:0;position:absolute;top:0;width:100%;z-index:1}.banner__buttons{display:inline-flex;flex-wrap:wrap;gap:1rem;max-width:45rem;word-break:break-word}@media screen and (max-width:749px){.banner__container .text-center .banner__buttons--multiple>*{flex-grow:1;min-width:22rem}.banner__container .text-right .banner__buttons--multiple{justify-content:flex-end}}@media screen and (min-width:750px){.banner__container .md\:text-center .banner__buttons--multiple>*{flex-grow:1;min-width:22rem}.banner__container .md\:text-right .banner__buttons--multiple{justify-content:flex-end}}[data-section-type=slideshow] .swiper-slide video{object-fit:cover}.slideshow__image-link:after{content:"";height:100%;left:0;position:absolute;top:0;width:100%}.accordion summary{display:flex;line-height:1;padding:1.5rem 0;position:relative}.accordion .summary__title{display:flex;flex:1}.accordion .summary__title+.icon-caret{height:calc(var(--font-heading-scale)*.6rem);transition:all .2s ease-in}.accordion+.accordion{border-top:none;margin-top:0}.accordion{border-bottom:.1rem solid rgba(var(--color-foreground),.08);border-top:.1rem solid rgba(var(--color-foreground),.08);margin-bottom:0;margin-top:2.5rem}.accordion__title{display:inline-block;margin:0;max-width:calc(100% - 6rem);min-height:1.6rem;word-break:break-word}.accordion .icon-accordion{fill:rgb(var(--color-foreground));align-self:center;height:calc(var(--font-heading-scale)*2rem);margin-right:calc(var(--font-heading-scale)*1rem);width:calc(var(--font-heading-scale)*2rem)}.accordion details[open]>summary .icon-caret{transform:rotate(180deg)}.accordion__content{overflow-x:auto;padding:0 .6rem 1.5rem;word-break:break-word}.accordion__content img{max-width:100%}.rdfy-dialog{background-color:transparent;border:none;display:grid;height:100%;inset:0;justify-items:center;margin:0;max-height:none;max-width:none;opacity:0;overflow-y:hidden;overscroll-behavior:contain;padding:0;pointer-events:none;position:fixed;transition-duration:.2s;transition-property:transform,opacity,visibility;transition-timing-function:cubic-bezier(.4,0,.2,1);width:100%;z-index:999}.rdfy-dialog[open]{opacity:1;pointer-events:auto;visibility:visible}.modal-backdrop{background-color:rgba(var(--color-foreground),.2);display:grid;grid-column-start:1;grid-row-start:1;height:100%;position:absolute;width:100%;z-index:-1}.modal-backdrop button{background:transparent;border:none;outline:none}@keyframes modal-pop{0%{opacity:0}}.grid{column-gap:var(--grid-mobile-horizontal-spacing);display:flex;flex-wrap:wrap;list-style:none;margin-bottom:2rem;padding:0;row-gap:var(--grid-mobile-vertical-spacing)}@media screen and (min-width:750px){.grid{column-gap:var(--grid-desktop-horizontal-spacing);row-gap:var(--grid-desktop-vertical-spacing)}}.grid__item{flex-grow:1;flex-shrink:0;max-width:calc(25% - var(--grid-mobile-horizontal-spacing)*3/4);width:calc(25% - var(--grid-mobile-horizontal-spacing)*3/4)}.grid-cols--1 .grid__item{max-width:100%;width:100%}.grid-cols--2 .grid__item{max-width:calc(50% - var(--grid-mobile-horizontal-spacing)/2);width:calc(50% - var(--grid-mobile-horizontal-spacing)/2)}.grid-cols--3 .grid__item{max-width:calc(33.33% - var(--grid-mobile-horizontal-spacing)*2/3);width:calc(33.33% - var(--grid-mobile-horizontal-spacing)*2/3)}@media screen and (max-width:749px){.grid-cols--swiper{column-gap:0;flex-wrap:nowrap!important}.grid-cols--swiper .grid__item{max-width:100%;width:90%}}@media screen and (min-width:750px){.md\:grid-cols--1 .grid__item{max-width:100%;width:100%}.md\:grid-cols--2 .grid__item{max-width:calc(50% - var(--grid-desktop-horizontal-spacing)/2);width:calc(50% - var(--grid-desktop-horizontal-spacing)/2)}.md\:grid-cols--3 .grid__item{max-width:calc(33.33% - var(--grid-desktop-horizontal-spacing)*2/3);width:calc(33.33% - var(--grid-desktop-horizontal-spacing)*2/3)}.md\:grid-cols--4 .grid__item{max-width:calc(25% - var(--grid-desktop-horizontal-spacing)*3/4);width:calc(25% - var(--grid-desktop-horizontal-spacing)*3/4)}}@media screen and (min-width:990px){.lg\:grid-cols--6 .grid__item{max-width:calc(16.66% - var(--grid-desktop-horizontal-spacing)*5/6);width:calc(16.66% - var(--grid-desktop-horizontal-spacing)*5/6)}.lg\:grid-cols--5 .grid__item{max-width:calc(20% - var(--grid-desktop-horizontal-spacing)*4/5);width:calc(20% - var(--grid-desktop-horizontal-spacing)*4/5)}.lg\:grid-cols--4 .grid__item{max-width:calc(25% - var(--grid-desktop-horizontal-spacing)*3/4);width:calc(25% - var(--grid-desktop-horizontal-spacing)*3/4)}.lg\:grid-cols--3 .grid__item{max-width:calc(33.33% - var(--grid-desktop-horizontal-spacing)*2/3);width:calc(33.33% - var(--grid-desktop-horizontal-spacing)*2/3)}.lg\:grid-cols--2 .grid__item{max-width:calc(50% - var(--grid-desktop-horizontal-spacing)/2);width:calc(50% - var(--grid-desktop-horizontal-spacing)/2)}.lg\:grid-cols--1 .grid__item{max-width:100%;width:100%}}.grid:last-child{margin-bottom:0}.grid--gapless.grid{column-gap:0;row-gap:0}@media screen and (max-width:749px){.grid__item.slider__slide--full-width{max-width:none;width:100%}}.grid--1-col .grid__item{max-width:100%;width:100%}.grid--3-col .grid__item{width:calc(33.33% - var(--grid-mobile-horizontal-spacing)*2/3)}@media screen and (min-width:750px){.grid--3-col .grid__item{width:calc(33.33% - var(--grid-desktop-horizontal-spacing)*2/3)}}.grid--2-col .grid__item{width:calc(50% - var(--grid-mobile-horizontal-spacing)/2)}@media screen and (min-width:750px){.grid--2-col .grid__item{width:calc(50% - var(--grid-desktop-horizontal-spacing)/2)}.grid--4-col-tablet .grid__item{width:calc(25% - var(--grid-desktop-horizontal-spacing)*3/4)}.grid--3-col-tablet .grid__item{width:calc(33.33% - var(--grid-desktop-horizontal-spacing)*2/3)}.grid--2-col-tablet .grid__item{width:calc(50% - var(--grid-desktop-horizontal-spacing)/2)}}@media screen and (max-width:989px){.grid--1-col-tablet-down .grid__item{max-width:100%;width:100%}.slider--tablet.grid--peek{margin:0;width:100%}.slider--tablet.grid--peek .grid__item{box-sizing:content-box;margin:0}}@media screen and (min-width:990px){.grid--6-col-desktop .grid__item{max-width:calc(16.66% - var(--grid-desktop-horizontal-spacing)*5/6);width:calc(16.66% - var(--grid-desktop-horizontal-spacing)*5/6)}.grid--5-col-desktop .grid__item{max-width:calc(20% - var(--grid-desktop-horizontal-spacing)*4/5);width:calc(20% - var(--grid-desktop-horizontal-spacing)*4/5)}.grid--4-col-desktop .grid__item{max-width:calc(25% - var(--grid-desktop-horizontal-spacing)*3/4);width:calc(25% - var(--grid-desktop-horizontal-spacing)*3/4)}.grid--3-col-desktop .grid__item{max-width:calc(33.33% - var(--grid-desktop-horizontal-spacing)*2/3);width:calc(33.33% - var(--grid-desktop-horizontal-spacing)*2/3)}.grid--2-col-desktop .grid__item{max-width:calc(50% - var(--grid-desktop-horizontal-spacing)/2);width:calc(50% - var(--grid-desktop-horizontal-spacing)/2)}.grid--1-col-desktop{flex:0 0 100%;max-width:100%}.grid--1-col-desktop .grid__item{max-width:100%;width:100%}}@media screen and (max-width:749px){.grid--peek.slider--mobile{margin:0;width:100%}.grid--peek.slider--mobile .grid__item{box-sizing:content-box;margin:0}.grid--peek .grid__item{min-width:35%}.grid--peek.slider .grid__item:first-of-type{margin-left:1.5rem}.grid--peek.slider:after{margin-left:calc(var(--grid-mobile-horizontal-spacing)*-1)}.grid--2-col-tablet-down .grid__item{width:calc(50% - var(--grid-mobile-horizontal-spacing)/2)}.grid--peek .grid__item,.slider--tablet.grid--peek.grid--2-col-tablet-down .grid__item{width:calc(50% - var(--grid-mobile-horizontal-spacing) - 3rem)}.slider--mobile.grid--peek.grid--1-col-tablet-down .grid__item,.slider--tablet.grid--peek.grid--1-col-tablet-down .grid__item{width:calc(100% - var(--grid-mobile-horizontal-spacing) - 3rem)}}@media screen and (min-width:750px) and (max-width:989px){.slider--tablet.grid--peek .grid__item{width:calc(25% - var(--grid-desktop-horizontal-spacing) - 3rem)}.slider--tablet.grid--peek.grid--3-col-tablet .grid__item{width:calc(33.33% - var(--grid-desktop-horizontal-spacing) - 3rem)}.slider--tablet.grid--peek.grid--2-col-tablet .grid__item,.slider--tablet.grid--peek.grid--2-col-tablet-down .grid__item{width:calc(50% - var(--grid-desktop-horizontal-spacing) - 3rem)}.slider--tablet.grid--peek .grid__item:first-of-type{margin-left:1.5rem}.grid--2-col-tablet-down .grid__item{width:calc(50% - var(--grid-desktop-horizontal-spacing)/2)}.grid--1-col-tablet-down.grid--peek .grid__item{width:calc(100% - var(--grid-desktop-horizontal-spacing) - 3rem)}}@supports not (inset:10px){.grid{margin-left:calc(var(--grid-mobile-horizontal-spacing)*-1)}.grid__item{padding-bottom:var(--grid-mobile-vertical-spacing);padding-left:var(--grid-mobile-horizontal-spacing)}@media screen and (min-width:750px){.grid{margin-left:calc(var(--grid-desktop-horizontal-spacing)*-1)}.grid__item{padding-bottom:var(--grid-desktop-vertical-spacing);padding-left:var(--grid-desktop-horizontal-spacing)}}.grid--gapless .grid__item{padding-bottom:0;padding-left:0}@media screen and (min-width:749px){.grid--peek .grid__item{padding-left:var(--grid-mobile-horizontal-spacing)}}.product-grid .grid__item{padding-bottom:var(--grid-mobile-vertical-spacing)}@media screen and (min-width:750px){.product-grid .grid__item{padding-bottom:var(--grid-desktop-vertical-spacing)}}}.image-with-text .grid{margin-bottom:0}.image-with-text .grid__item{position:relative}@media screen and (min-width:750px){.image-with-text__grid--reverse{flex-direction:row-reverse}}.image-with-text__media{min-height:100%;overflow:visible}.image-with-text__media--small{height:19.4rem}.image-with-text__media--medium{height:29.6rem}.image-with-text__media--large{height:43.5rem}@media screen and (min-width:750px){.image-with-text__media--small{height:31.4rem}.image-with-text__media--medium{height:46rem}.image-with-text__media--large{height:69.5rem}}.image-with-text__media--placeholder{overflow:hidden;position:relative}.image-with-text__media--placeholder:after{background:rgba(var(--color-foreground),.04);content:"";height:100%;position:absolute;width:100%}.image-with-text__media--placeholder.image-with-text__media--adapt{height:20rem}@media screen and (min-width:750px){.image-with-text__media--placeholder.image-with-text__media--adapt{height:30rem}}.image-with-text__media--placeholder>svg{fill:currentColor;left:50%;max-width:80rem;position:absolute;top:50%;transform:translate(-50%,-50%);width:100%}.image-with-text__content{align-items:flex-start;align-self:center;display:flex;flex-direction:column;height:100%;justify-content:center;padding:4rem calc(4rem/var(--font-base-scale)) 5rem;position:relative;z-index:1}.image-with-text .grid__item:after{content:"";height:100%;left:0;position:absolute;top:0;width:100%;z-index:-1}.image-with-text:not(.image-with-text--overlap) .image-with-text__media-item:after{border-radius:var(--media-radius);box-shadow:var(--media-shadow-horizontal-offset) var(--media-shadow-vertical-offset) var(--media-shadow-blur-radius) rgba(var(--color-shadow),var(--media-shadow-opacity))}.image-with-text:not(.image-with-text--overlap) .image-with-text__text-item:after{border-radius:var(--text-boxes-radius);box-shadow:var(--text-boxes-shadow-horizontal-offset) var(--text-boxes-shadow-vertical-offset) var(--text-boxes-shadow-blur-radius) rgba(var(--color-shadow),var(--text-boxes-shadow-opacity))}.image-with-text .image-with-text__media-item>*{border-radius:var(--media-radius);box-shadow:var(--media-shadow-horizontal-offset) var(--media-shadow-vertical-offset) var(--media-shadow-blur-radius) rgba(var(--color-shadow),var(--media-shadow-opacity));overflow:hidden}.image-with-text .g-card-media{overflow:hidden!important}.image-with-text .image-with-text__text-item>*{border-radius:var(--text-boxes-radius);box-shadow:var(--text-boxes-shadow-horizontal-offset) var(--text-boxes-shadow-vertical-offset) var(--text-boxes-shadow-blur-radius) rgba(var(--color-shadow),var(--text-boxes-shadow-opacity));overflow:hidden}.image-with-text:not(.image-with-text--overlap) .image-with-text__media-item>*,.image-with-text:not(.image-with-text--overlap) .image-with-text__text-item>*{box-shadow:none}@media screen and (max-width:749px){.image-with-text.collapse-corners:not(.image-with-text--overlap) .grid__item .image-with-text__media,.image-with-text.collapse-corners:not(.image-with-text--overlap) .image-with-text__media img,.image-with-text.collapse-corners:not(.image-with-text--overlap) .image-with-text__media-item:after{border-bottom-left-radius:0;border-bottom-right-radius:0}.image-with-text.collapse-corners:not(.image-with-text--overlap) .grid__item .image-with-text__content,.image-with-text.collapse-corners:not(.image-with-text--overlap) .image-with-text__text-item:after{border-top-left-radius:0;border-top-right-radius:0}.image-with-text.collapse-borders:not(.image-with-text--overlap) .image-with-text__content{border-top:0}}.image-with-text__content--mobile-right>*{align-self:flex-end;text-align:right}.image-with-text__content--mobile-center>*{align-self:center;text-align:center}.image-with-text--overlap .image-with-text__content{margin:-3rem auto 0;width:90%}@media screen and (min-width:750px){.image-with-text__grid--reverse .image-with-text__content{margin-left:auto}.image-with-text__content--bottom{align-self:flex-end;justify-content:flex-end}.image-with-text__content--top{align-self:flex-start;justify-content:flex-start}.image-with-text__content--desktop-right>*{align-self:flex-end;text-align:right}.image-with-text__content--desktop-left>*{align-self:flex-start;text-align:left}.image-with-text__content--desktop-center>*{align-self:center;text-align:center}.image-with-text--overlap .image-with-text__text-item{display:flex;padding:3rem 0}.image-with-text--overlap .image-with-text__content{height:auto;margin-left:-4rem;margin-top:0;min-width:calc(100% + 4rem);width:calc(100% + 4rem)}.image-with-text--overlap .image-with-text__grid--reverse .image-with-text__content{margin-left:0;margin-right:-4rem}.image-with-text--overlap .image-with-text__grid--reverse .image-with-text__text-item{justify-content:flex-end}.image-with-text--overlap .image-with-text__media-item--top{align-self:flex-start}.image-with-text--overlap .image-with-text__media-item--middle{align-self:center}.image-with-text--overlap .image-with-text__media-item--bottom{align-self:flex-end}.image-with-text__media-item--large+.image-with-text__text-item,.image-with-text__media-item--small{flex-grow:0}.image-with-text.collapse-corners:not(.image-with-text--overlap) .grid:not(.image-with-text__grid--reverse) .image-with-text__media,.image-with-text.collapse-corners:not(.image-with-text--overlap) .grid:not(.image-with-text__grid--reverse) .image-with-text__media img,.image-with-text.collapse-corners:not(.image-with-text--overlap) .grid:not(.image-with-text__grid--reverse) .image-with-text__media-item:after,.image-with-text.collapse-corners:not(.image-with-text--overlap) .image-with-text__grid--reverse .image-with-text__content,.image-with-text.collapse-corners:not(.image-with-text--overlap) .image-with-text__grid--reverse .image-with-text__content:after,.image-with-text.collapse-corners:not(.image-with-text--overlap) .image-with-text__grid--reverse .image-with-text__text-item:after{border-bottom-right-radius:0;border-top-right-radius:0}.image-with-text.collapse-corners:not(.image-with-text--overlap) .grid:not(.image-with-text__grid--reverse) .image-with-text__content,.image-with-text.collapse-corners:not(.image-with-text--overlap) .grid:not(.image-with-text__grid--reverse) .image-with-text__content:after,.image-with-text.collapse-corners:not(.image-with-text--overlap) .grid:not(.image-with-text__grid--reverse) .image-with-text__text-item:after,.image-with-text.collapse-corners:not(.image-with-text--overlap) .image-with-text__grid--reverse .image-with-text__media,.image-with-text.collapse-corners:not(.image-with-text--overlap) .image-with-text__grid--reverse .image-with-text__media img,.image-with-text.collapse-corners:not(.image-with-text--overlap) .image-with-text__grid--reverse .image-with-text__media-item:after{border-bottom-left-radius:0;border-top-left-radius:0}.image-with-text.collapse-borders:not(.image-with-text--overlap) .grid:not(.image-with-text__grid--reverse) .image-with-text__content{border-left:0}.image-with-text.collapse-borders:not(.image-with-text--overlap) .image-with-text__grid--reverse .image-with-text__content{border-right:0}}.image-with-text:not(.collapse-corners,.image-with-text--overlap) .image-with-text__media-item{z-index:2}.image-with-text__content{border-radius:var(--text-boxes-radius);box-shadow:var(--text-boxes-shadow-horizontal-offset) var(--text-boxes-shadow-vertical-offset) var(--text-boxes-shadow-blur-radius) rgba(var(--color-shadow),var(--text-boxes-shadow-opacity));word-break:break-word}@media screen and (min-width:990px){.image-with-text__content{padding:6rem 7rem 7rem}}.image-with-text__content>*+*,.image-with-text__content>.image-with-text__text:empty~a{margin-top:2rem}.image-with-text__content>:first-child:is(.image-with-text__heading),.image-with-text__text--caption+.image-with-text__heading,.image-with-text__text--caption:first-child{margin-top:0}.image-with-text__content :last-child:is(.image-with-text__heading),.image-with-text__text--caption{margin-bottom:0}.image-with-text__content .button+.image-with-text__text{margin-top:2rem}.image-with-text__content .image-with-text__text+.button{margin-top:3rem}.image-with-text__heading{margin-bottom:0}.image-with-text__text p{margin-bottom:1rem;margin-top:0}@media screen and (max-width:749px){.collapse-padding .image-with-text__grid .image-with-text__content{padding-left:0;padding-right:0}}@media screen and (min-width:750px){.collapse-padding .image-with-text__grid:not(.image-with-text__grid--reverse) .image-with-text__content:not(.image-with-text__content--desktop-center){padding-right:0}.collapse-padding .image-with-text__grid--reverse .image-with-text__content:not(.image-with-text__content--desktop-center){padding-left:0}}@supports not (inset:10px){.image-with-text .grid{margin-left:0}}.multirow__inner{display:flex;flex-direction:column;row-gap:var(--grid-mobile-vertical-spacing)}@media screen and (min-width:750px){.multirow__inner{row-gap:var(--grid-desktop-vertical-spacing)}}.product-card-ratio{align-items:stretch;display:flex}.product-card-ratio:before{content:"";height:0;padding-bottom:var(--ratio-percent);width:0}.product-card .media{bottom:0;position:absolute;top:0;width:100%}.product-card .product-card__img{display:block;height:100%;left:0;max-width:100%;object-fit:cover;object-position:center center;position:absolute;top:0;transition:transform .5s ease;width:100%}.media.media--hover-effect .product-card__img-second{opacity:0}.product-card__sale{display:grid;grid-template-rows:minmax(0,1fr) max-content minmax(0,1fr);height:100%;left:0;padding:calc(1rem + var(--image-padding));position:absolute;top:0;width:100%}.product-card__badge{align-self:flex-end;grid-row-start:3;justify-self:flex-start}.product-card__badge.top-left,.product-card__badge.top-right{align-self:flex-start;grid-row-start:1}.product-card__badge.top-right{justify-self:flex-end}.product-card__badge.bottom-left{text-align:left}.product-card__badge.bottom-right{justify-self:flex-end}.product-card__heading a:after{bottom:0;content:"";left:0;position:absolute;right:0;top:0;z-index:1}.product-card-content .quick-add{grid-row-start:4;margin:0 0 1rem;position:relative;z-index:1}.product-card-content .quick-add__submit{box-sizing:border-box;min-width:100%;padding:.8rem}@media screen and (min-width:990px){.product-card:hover .media--hover-effect>.product-card__img:first-child:only-child{transform:scale(1.051)}.product-card:hover .media--hover-effect>img:first-child:not(:only-child){opacity:0}.product-card:hover .product-card__img-second{opacity:1;transform:scale(1.05)}}.product-card__info{padding:1.3rem 1rem}.product-card__info .product-card__heading{margin-bottom:0;margin-top:0}.product-card--standard .product-card__info{padding-left:0;padding-right:0}.product-card--card .product-card__bottom{padding:1rem}.product-card__price-wrap{margin-top:.7rem}.product-card--card .product-block__swatch{flex-wrap:wrap;padding:0 1rem}.product-card--card .quick-add{margin:0 1.3rem 1rem}.product-card-content{border-radius:calc(var(--border-radius) - var(--border-width) - var(--product-card-image-padding));display:flex;flex-direction:column;justify-content:space-between}.product-card-content.product-card-content_card{overflow:hidden}.product-card__media{border-radius:calc(var(--product-card-corner-radius) - var(--product-card-border-width) - var(--product-card-image-padding));margin:var(--product-card-image-padding);overflow:hidden;width:calc(100% - var(--product-card-image-padding)*2)}.product-card--standard .product-card__media{overflow:hidden}.product-card__media_top_radius .product-card__media{border-top-left-radius:calc(var(--product-card-corner-radius) - var(--product-card-border-width) - var(--product-card-image-padding));border-top-right-radius:calc(var(--product-card-corner-radius) - var(--product-card-border-width) - var(--product-card-image-padding))}.product-card--card .product-card__media_top_radius .product-card__media{border-bottom-left-radius:0;border-bottom-right-radius:0}.product-card--card{position:relative;z-index:1}.product-card__top{width:100%;z-index:1}.product-card--card:after{border-radius:var(--border-radius);box-shadow:var(--shadow-horizontal-offset) var(--shadow-vertical-offset) var(--shadow-blur-radius) rgba(var(--color-shadow),var(--shadow-opacity));content:"";height:calc(var(--border-width)*2 + 100%);left:calc(var(--border-width)*-1);position:absolute;top:calc(var(--border-width)*-1);width:calc(var(--border-width)*2 + 100%);z-index:-1}.product-popup-dialog__close{align-items:center;background-color:rgb(var(--color-background));border:.1rem solid rgba(var(--color-foreground),.1);border-radius:50%;color:rgba(var(--color-foreground),.55);cursor:pointer;display:flex;height:4rem;justify-content:center;margin:0 0 0 auto;padding:1.2rem;position:sticky;width:4rem;z-index:2}.product-popup-dialog__close svg{height:15px;width:15px}.product-info__variants-swatch label{background:none;border:2px solid var(--color-select-border);border:2px solid rgba(var(--color-foreground),.15);border-radius:var(--color-card-style-radius);font-size:0;margin:10px 10px 0 0;min-width:0;padding:2px}.product-info__variants-swatch label span{background-position:50%;background-repeat:no-repeat;background-size:cover;border-radius:var(--color-card-style-radius);cursor:pointer;display:inline-block;overflow:hidden}.product-info__variants-swatch-modal label{border-width:1px;margin:0 6px 0 0}.product-info__variants-swatch-modal[data-checked] label{border-color:rgba(var(--color-foreground))}.product__variants-swatch-info{height:var(--color-card-detail-m-size);width:var(--color-card-detail-m-size)}.product__variants-swatch-list{height:var(--color-card-list-m-size);width:var(--color-card-list-m-size)}@media (min-width:768px){.product__variants-swatch-info{height:var(--color-card-detail-p-size);width:var(--color-card-detail-p-size)}.product__variants-swatch-list{height:var(--color-card-list-p-size);width:var(--color-card-list-p-size)}}.product-info__variants_radio:checked~.product-info__thumbnail,.product-info__variants_radio:checked~.product-info__variants_label{background-color:var(--color-primary-btn-bg);border-color:var(--color-primary-btn-bg);color:var(--color-primary-btn-text)}.product-info__thumbnail:hover,.product-info__variants-swatch_label:hover{background:rgba(0,0,0,.05);cursor:pointer}.product-info__variants_radio:checked~.product-info__variants-swatch_label{background:none;border-color:var(--general-text-color)}.customer:not(.account):not(.order){margin:0 auto;max-width:100%;padding-left:1.5rem;padding-right:1.5rem;text-align:center}@media screen and (min-width:750px){.customer:not(.account):not(.order){max-width:47.8rem}}.alert{background:rgba(255,0,0,.07);border-radius:2px;color:var(--color-button);display:block;font-size:14px;padding:12px 30px;text-align:left;white-space:normal;word-break:break-all;word-break:break-word}.alert li{line-height:26px}.alert:last-child{margin-bottom:0}.alert--error{color:red}.alert a{text-decoration:underline;transition:color .2s ease-in-out}.customer{padding-bottom:36px;padding-top:36px}.customer a{display:block}.customer a:hover,a:active,a:focus,a:link,a:visited{-webkit-tap-highlight-color:rgba(255,255,255,0);-moz-user-focus:none;-webkit-user-select:none;-moz-user-select:none}.customer input{-webkit-tap-highlight-color:rgba(0,0,0,0)}.customer>h1,.customer__title{margin-bottom:1rem;margin-top:0}.customer form{margin-top:4rem}.customer button{margin:4rem 0 1.5rem}.customer p{margin:1.5rem 0}.customer ul{margin-bottom:4rem;text-align:left}.customer ul a{display:inline}.customer strong{font-weight:400}.customer .field{margin:2rem 0 0}.customer .field:first-of-type{margin-top:0}.login a{display:block;margin:0 auto;width:fit-content}.login a[href="#recover"]{margin-left:0;margin-right:0}.login .field+a{margin-top:1rem}.login h3{font-size:calc(var(--font-heading-scale)*1.6rem);margin-top:1.5rem;text-align:left}.login #recove{margin-left:0;margin-right:0}.order-layout{display:block;padding-bottom:27px;padding-top:27px}.account__order-header{align-items:center;display:flex;justify-content:space-between}.account__order-header a{align-items:center;color:var(--color-button);display:inline-flex}.account__order-header svg{margin-bottom:-.03rem;margin-right:1rem;width:1.5rem}.account_order-navbar{align-items:center;border-bottom:1px solid #eaecec;display:flex;justify-content:space-between;margin-bottom:2.5rem;position:sticky;z-index:2}.account_order-navbar .navbar{overflow-x:auto;white-space:nowrap}.account_order-navbar .navbar__item{color:rgba(41,37,44,.4);display:inline-block;font-size:1.95rem;font-weight:700;line-height:60px;text-decoration:none}.account_order-navbar .active{border-bottom:2px solid #29252c;color:#29252c}.account_order-navbar .navbar__item:first-child{margin-right:4rem}[dir=rtl] .account_order-navbar .navbar__item:first-child{margin-left:4rem;margin-right:0}.account__order-list{display:flex;flex-direction:row}.account__order-tabs{margin-left:0;margin-right:5rem;margin-top:0;padding:0;position:sticky;top:90px;width:20rem}[dir=rtl] .account__order-tabs{margin-left:5rem;margin-right:0}[dir=rtl] .account__order-tabs svg{rotate:180deg}.account__order-tabs li{align-items:center;border-style:solid;border-width:0;color:#64748b;cursor:pointer;display:flex;font-size:1rem;font-size:1.5rem;justify-content:space-between;line-height:1.5rem;padding-bottom:18px;padding-top:18px}.account__order-tabs .active{color:var(--color-button)}.account__order-items{flex-grow:1}.account__order-items li{list-style:none}.account__order-items .item__header{align-items:center;background-color:#f4f4f5;color:#333;display:flex;justify-content:space-between;padding:1rem 1.5rem}.account__order-items .item__number{font-size:1.375rem;line-height:1.5rem}.account__order-items .item__status{font-size:1.375rem;font-weight:600}.account__address-list{text-align:center}.account__address-list .button{margin-bottom:0;margin-top:2rem;min-height:48px}.address__area-phone{align-items:center;display:flex}.address__area-select{margin-right:2rem!important;margin-top:2rem!important;width:20rem}.customer__addesss-province{margin-top:2rem}.address__area-checkbox{-webkit-appearance:none;-moz-appearance:none;-o-appearance:none;appearance:none;background-color:#fff!important;border:1px solid #d9d9d9!important;border-radius:2px!important;cursor:pointer!important;height:18px!important;padding:0;position:relative;transition:all .1s ease-in-out;vertical-align:middle!important;width:18px!important}.address__area-checkbox:checked{background-color:#000!important;border-color:#000!important}.address__area-checkbox:checked:after{opacity:1;transform:scale(1);transition-delay:.1s}.address__area-checkbox:after{background-image:url(//static.shoptop.com/admin/checkbox-tick.svg),none;content:"";display:block;height:8px;left:50%;margin-left:-5px;margin-top:-4px;opacity:0;position:absolute;top:50%;transform:scale(.2);transition:all .1s ease-in-out;width:10px}.address__checkbox{align-items:center;display:flex;margin-top:2rem;text-align:left;transition:all .1s ease-in-out}.addount__order-empty{margin-bottom:2.5rem;margin-top:2.5rem}.addount__order-item{display:grid;gap:1.5rem;grid-template-columns:repeat(3,minmax(0,1fr));margin-bottom:3.5rem;margin-top:2.5rem}.addount__order-item .item-box{border:1px solid #e5e7eb;border-radius:6px;line-height:1.25rem;overflow:hidden;padding:30px;text-align:left}.addount__order-item .item-name{display:flex;font-size:1.75rem;justify-content:space-between;line-height:1.5rem}.addount__order-item .item-default{color:#333;font-weight:500}.addount__order-item .default-flag{background-color:rgba(var(--color-button),var(--alpha-button-background));border-radius:var(--buttons-radius-outset);color:rgb(var(--color-button-text));font-size:12px;font-weight:400;margin-left:6px;padding:4px 12px}.addount__order-item .item-info{color:rgba(51,51,51,.7)}.addount__order-item .item-text{padding-top:1.5rem}.addount__order-item .item-footer{font-size:1.5rem;line-height:2rem;margin-top:2rem;text-align:right}.addount__order-item .item-footer a{color:var(--color-button)}.addount__order-item .item-footer-line{margin-left:.5rem;margin-right:.5rem}.order__items_empty{align-items:center;display:flex;flex-direction:column;justify-content:center}.order__items_empty a{min-height:48px}.order__items_empty .empty__text{font-size:1.75rem;margin-bottom:2.5rem;margin-top:0}.account__order-item{width:100%}.account__orders-info{margin-bottom:0;margin-top:0;padding:0}.account__orders-info .order-list{list-style-type:none}.account__orders-info .order__list-header{align-items:center;background-color:#fbfcfc;border-radius:2px;color:#333;display:flex;font-size:1.45rem;justify-content:space-between;padding:1rem 1.25rem}.account__orders-info .order__header-number{padding-left:2rem}.account__orders-info .order__header-status{font-weight:600}.account__orders-info .order__list-product{align-items:center;display:flex;flex-direction:row;flex-wrap:nowrap;justify-content:space-between;margin-left:auto;margin-right:auto;padding-bottom:1.25rem;padding-top:1.25rem}.account__orders-info .order__product-image{display:flex;flex-wrap:wrap;width:65%}.account__orders-info .order__image-info{height:70px;margin-bottom:.75rem;margin-right:.75rem;position:relative;width:70px}.account__orders-info .order__image-url{background:none scroll no-repeat 50%/contain;border-radius:2px;display:block;height:100%;width:100%}.account__orders-info .order__product-payment{color:#333;font-size:1.375rem;line-height:1.5rem;padding-left:1.25rem;width:30%}.account__orders-info .order__payment-flex{align-items:center;display:flex}.account__orders-info .order__shipping-flex{align-items:center;display:flex;margin-top:.25rem}.account__orders-info .order__product-margin{margin:1rem}.account__orders-info .order__product-total{font-size:1.375rem;line-height:1.5rem;padding-right:1.25rem;text-align:right;width:160px}.account__orders-info .order__list-footer{align-items:center;border-top:1px solid #e2e8f0;display:flex;justify-content:flex-end;margin-left:auto;margin-right:auto;padding-bottom:1.75rem;padding-top:1.75rem}.account__orders-info .order__list-footer a,.account__orders-info button{margin-left:20px;min-height:48px}.order__detail-product{border:1px solid rgba(33,43,54,.05);display:flex;flex-direction:column;margin-top:1rem}.order__detail-product .order__product-header{background-color:initial;display:flex;padding:1rem 2rem}.order__detail-product .order__product-mobile{display:none}.order__detail-product .product-col{text-align:center;width:14%}.order__detail-product .product-first{flex-grow:1}.order__detail-product .product-row{align-items:center;border:0 solid rgba(33,43,54,.05);border-top:rgba(33,43,54,.05);display:flex;justify-content:center}.order__product-row{padding:1rem}.product-row-image{display:flex;flex-grow:1;width:min-content}.order__detail-product .product-row-mobile{display:none}.order__detail-product .product-row-specs dl{margin:.6rem 0 0;max-width:30rem}.product-image__media{align-items:center;display:flex;margin-right:2rem}[dir=rtl] .product-image__media{margin-left:2rem;margin-right:0}.product-image-container{align-items:flex-start;display:inline-flex;position:relative}.product-image__round{display:none}.product-item__image{height:auto}.order__detail-product .product-total{align-items:center;border-top:1px solid rgba(33,43,54,.05);display:flex;flex-direction:row;justify-content:space-between;padding:1rem 2rem}.order__detail-product .product-total-info{width:auto}.order__detail-product .product-total-right{align-items:center;display:flex;justify-content:space-between;margin-top:0;width:auto}.order__detail-product .total-amount{font-size:16px;margin-right:.5rem}[dir=rtl] .order__detail-product .total-amount{margin-left:.5rem;margin-right:0}.order__detail-product .total-number{font-size:24px;margin-left:.5rem}.order__detail-product .product-total-item{display:flex;justify-content:space-between}.order__detail-product .product-total-title{margin-right:1rem;width:150px}.order__detail-sepcs{display:flex;justify-content:space-between;margin-top:1rem}.order__spec-first{margin-left:130px}.order__spec-mobile{display:none}.order__detail-back{background-color:unset;padding-bottom:1rem}.order__detail-back a{color:var(--color-btn-text);text-decoration:none}.order__detail-back svg{transform:rotate(180deg);-webkit-transform:rotate(180deg);vertical-align:middle}.order__detail-info{border:1px solid rgba(33,43,54,.05);display:flex;flex-direction:row;margin-top:1rem;padding:1rem}.order__detail-info .container-status{align-items:center;display:flex;flex-direction:column;justify-content:center;text-align:center}.order__detail-info .container-item{border-right:1px solid rgba(33,43,54,.05);padding:1rem 2rem}.order__detail-info .container-item:last-child{border-right:none}.order__detail-info .container-warning{color:#f05c5d}.order__detail-info .container-item .button{margin-left:0;margin-top:2rem;min-height:42px;min-width:100px}.order__detail-info .container-item .item-status{color:var(--color-base-text)}.order__detail-info .container-item .item-start{align-items:flex-start;display:flex;font-size:1.475rem;justify-content:space-between;line-height:3rem}.order__detail-info .gif-card-wrap{font-size:14px;line-height:20px;margin-bottom:4px;text-align:right}.container-text-right{text-align:right}.order__detail-info .gif-card__item{color:var(--color-base-text);margin-bottom:.25rem}.order__detail-info .col-md-2{width:20%}.order__detail-info .col-md-4{width:33.333333%}.order__detail-info .item-status{font-size:1.85rem}.order__detail-shipment{border:1px solid rgba(33,43,54,.05);border-top:none;display:flex;flex-direction:column}.product-row-specs{font-size:.75rem;padding-top:1rem}.product-row-quant{display:block;text-align:right;width:6rem}.order-shipment-header{align-items:center;background-color:#fbfcfc;display:flex;justify-content:space-between;margin-left:0;margin-right:0;padding:1rem 2rem}.order-shipment-header .shipment-title{display:flex;justify-content:flex-start}.order-shipment-header .shipment-status{align-items:center;display:flex;margin-left:1rem}.order-shipment-header .shipment-round{background-color:rgb(var(--color-button-text));border-radius:9999px;height:1rem;margin-left:1rem;margin-right:.8rem;width:1rem}.order-shipment-track{padding-left:2rem;padding-right:2rem}.order-shipment-track:last-child{margin-bottom:1rem}.order-shipment-product{border-top:1px solid rgba(33,43,54,.05);padding-bottom:1rem;padding-left:0;padding-right:0}.order-shipment-product .order-product-items{align-items:center;display:flex;justify-content:space-between;padding:1rem}.shipment-button{display:none}.shipment-button .button{margin-left:1rem;min-height:38px;min-width:100px;padding:0 1rem}.order-shipment-header .shipment-button{display:block}.order__shipment-list{list-style:none;margin:0;overflow:auto;padding:8px 0}.order__shipment-item{border-left:1px solid rgba(50,57,61,.15);margin-left:7px;position:relative}.order__shipment-first .order__shipment-round{background:#0682fe}.order__shipment-first .order__shipment-info{color:#010101}.order__shipment-round{background:#fff;border:1px solid #0682fe;border-radius:50%;height:13px;left:-7px;position:absolute;top:-2px;width:13px}.order__shipment-info{color:#a8a8a8;font-size:14px;line-height:20px;padding-bottom:20px;padding-left:20px;transform:translateY(-6px)}.order-shipment-product{text-align:right;width:100%}.order-shipment-virtual{padding:1rem 2rem}.order-shipment-product .shipment-virtual{align-items:center;appearance:none;background-color:rgba(var(--color-button),var(--alpha-button-background));border:0;border-radius:var(--buttons-radius-outset);color:rgb(var(--color-button-text));cursor:pointer;display:inline-flex;font-size:1.25rem;justify-content:center;min-height:calc(3rem + var(--buttons-border-width)*2);padding:0 1.5rem;position:relative;text-decoration:none}.plugin__virtual-container{margin-top:20px}.plugin__virtual-stock{background:rgba(var(--color-button),var(--alpha-button-background));border-radius:4px;color:rgb(var(--color-button-text));font-size:16px;overflow:hidden;padding:15px}.plugin__virtual-content{display:flex;justify-content:space-between;overflow:hidden;width:100%}.plugin__virtual-content button{background:rgba(var(--color-button),var(--alpha-button-background));border:none;color:#fff}.plugin__virtual-content .customer-pointer{cursor:pointer}.plugin__virtual-remark{font-size:16px;margin-top:20px}.overlay-modal{align-items:center;background-color:rgba(0,0,0,.4);bottom:0;display:flex;height:100%;justify-content:center;left:0;position:fixed;right:0;top:0;transition:opacity .3s;width:100%;z-index:1111}.modal-content{background-color:#fff;border-radius:4px;box-shadow:0 2px 6px rgba(0,0,0,.2);padding:20px;position:absolute;transition:opacity .5s,transform .5s;z-index:10000}.modal-dialog{width:520px}.modal__close{align-items:center;background-color:transparent;border:none;border-radius:4px;color:#666;cursor:pointer;display:flex;font-size:18px;height:22px;justify-content:center;margin:10px 26px 0 0;outline:none;padding:0;position:absolute;right:0;top:14px;transition:background-color .3s cubic-bezier(.4,0,.2,1),color .3s cubic-bezier(.4,0,.2,1);width:22px;z-index:1}[dir=rtl] .modal__close{left:0;margin:10px 0 0 26px;right:auto}.modal__close:before{border-radius:inherit;content:"";height:22px;left:50%;position:absolute;top:50%;transform:translateY(-50%) translateX(-50%);transition:inherit;width:22px}.modal__close:hover:before{background-color:rgba(0,0,0,.09)}.modal__close svg{fill:currentColor;display:inline-block;height:1em;position:relative;text-align:center;transform:translateZ(0);width:1em}.dialog__title{align-items:center;border-bottom:1px solid #e1ebf0;color:#1f2225;display:flex;font-size:1.875rem;font-weight:500;padding-bottom:14px}.dialog__content{margin:8px 0 16px;max-height:485px;overflow-y:auto;padding-bottom:20px;padding-left:0!important;padding-right:0!important;padding-top:20px;position:relative;word-break:break-word}.dialog__content form{margin-top:0}.dialog__action{border-top:1px solid #e1ebf0;display:flex;justify-content:flex-end;padding-top:15px}.dialog__action button:first-child{cursor:pointer;margin-bottom:0;margin-right:15px;min-width:100px}.dialog__action button:last-child{cursor:pointer;margin-bottom:0;min-width:100px;z-index:99}@media screen and (max-width:990px){.order-layout{overflow-x:hidden;padding-bottom:0}.overlay-modal{align-items:flex-end}.modal-dialog{width:100%}.account_order-navbar{margin-bottom:0;margin-left:-1.5rem;margin-right:-2rem;padding-left:1.5rem}.account__order-tabs{border-bottom:1px solid #eaecec;display:flex;overflow:auto;width:100%}.account__order-tabs li{font-size:1.275rem;margin-left:14px;white-space:nowrap}.account__order-tabs .active{border-bottom:2px solid #29252c}.account__order-tabs li:first-child{margin-left:0}.account__order-tabs li svg{display:none}.addount__order-item{grid-template-columns:repeat(1,minmax(0,1fr))}.account__order-list{flex-direction:column}.account__orders-info .order__list-header{font-size:1.275rem;margin-left:-20px;margin-right:-20px;padding-left:20px;padding-right:20px}.account__orders-info .order__header-number{padding-left:0}.account__orders-info .order__header-left{display:flex;flex-direction:column}.account__orders-info .order__list-product{flex-direction:column}.account__orders-info .order__product-image{width:100%}.account__orders-info .order__product-payment{padding-left:0;width:100%}.account__orders-info .order__product-total{text-align:right;width:100%}.account__orders-info .order__list-footer{flex-wrap:wrap;padding-top:0}.account__orders-info .order__list-footer .button,.account__orders-info .order__list-footer a{margin-bottom:1.75rem}.order__detail-info{border:none;flex-direction:column;margin-top:0;padding:0}.order__detail-info .container-item{border-bottom:1px solid rgba(33,43,54,.05);border-right:none;padding:1rem 0;width:100%}.order__detail-product{border:none}.order__detail-product .order__product-header{display:none}.order__detail-product .order__product-mobile{display:block;padding-bottom:1rem}.order__detail-product .product-col,.product-row-quant{display:none}.order__product-row{padding:0}.order__detail-product .product-row{padding:1rem 0}.product-item__image{width:6rem}.order__detail-product .product-row-mobile{display:block}.product-row-mobile .product-row-total{font-size:1.75rem}.order__detail-product .product-mobile-status{border-color:var(--general-text-color);border-radius:2px;border-style:solid;border-width:1px;color:var(--general-text-color);padding:.2rem .5rem;width:fit-content}.order__detail-product .product-total{align-items:inherit;flex-direction:column;justify-content:space-between;padding:1rem 0}.product-image__round{background:hsla(0,0%,45%,.9);border-radius:50%;color:#fff;display:block;font-size:.875rem;height:1.75rem;line-height:1.75rem;position:absolute;right:0;text-align:center;top:-10px;width:1.75rem}.shipment-button{border-top:1px solid rgba(33,43,54,.05);display:block;text-align:right}.order-shipment-header .shipment-button{display:none}.order__detail-shipment{border:none}.order-shipment-track{padding:0}.order-shipment-header{margin:0 -2rem}.order-shipment-header .shipment-title{justify-content:space-between;width:100%}.order-shipment-product .order-product-items{padding:1rem 0}.product-row-image{justify-content:space-between;margin-left:0}.order__spec-mobile{display:block}}.loading-cover{align-items:center;background-color:rgba(0,0,0,.3);display:flex;height:100%;justify-content:center;left:0;position:fixed;top:0;width:100%;z-index:9999}.loading-spinner{height:3.5rem;margin-left:auto;margin-right:auto;position:relative;text-align:center;width:3.5rem}.loading-bounce1{animation:rotate .8s ease infinite;-webkit-animation:rotate .8s ease infinite;border:3px solid #fff;border-left:3px solid transparent!important;border-radius:50%;border-right:3px solid transparent!important;border-top:3px solid transparent!important}.loading-bounce1,.loading-bounce2{box-sizing:border-box;display:block!important;height:100%;position:absolute;width:100%}.loading-bounce2{animation:rotate .8s linear infinite;-webkit-animation:rotate .8s linear infinite;border:3px dashed #fff;border-left:3px solid transparent!important;border-radius:50%;border-right:3px solid transparent!important;border-top:3px solid transparent!important;top:0}@-webkit-keyframes rotate{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}@keyframes rotate{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.cart-layout{display:block;padding-top:27px}.cart__warnings{padding:3rem 0;text-align:center}.cart__items{border-bottom:.1rem solid hsla(0,0%,7%,.08);padding-bottom:3rem;position:relative}.cart-opacity{opacity:.5}.cart-image__media{position:relative}.cart-items th{font-weight:400;line-height:5rem;opacity:.85;text-align:left}.cart-item__quantity-wrapper{display:flex;margin-top:1rem}.cart-item__totals{position:relative}.cart-items .right{text-align:right}.cart-item__image-container{align-items:flex-start;display:inline-flex}.cart-item__image-container:after{content:none}.cart-item__image{height:auto;max-width:10rem}.cart__discount-container{margin-bottom:1rem}@media screen and (min-width:750px){.cart-item__image{max-width:100%}}.cart-item__details{font-size:1.6rem;grid-column:2/6;line-height:1.4;padding-left:14px}.cart-item__variants{font-size:1.6rem;line-height:1.4;width:35rem}.cart-item__details>*,.cart-item__variants>*{margin:0}.cart-item__details>*+*,.cart-item__variants>*+*{margin-top:.8rem}.cart-item__media{position:relative}.cart-item__link{bottom:0;display:block;height:100%;left:0;position:absolute;right:0;top:0;width:100%}.cart-item__name{display:block;text-decoration:none}.cart-item__name:hover{text-decoration:underline;text-decoration-thickness:.2rem;text-underline-offset:.3rem}.cart-item__price-wrapper>*{display:block;margin:0;padding:0}.cart-item__discounted-prices dd{margin:0}.cart-item__discounted-prices .cart-item__old-price{font-size:1.4rem}.cart-item__old-price{opacity:.7}.cart-item__final-price{font-weight:400}.product-compare,.product-price{color:rgb(var(--color-base-text));font-size:1.4rem;font-weight:500;line-height:20px}.product-compare{margin-left:4px;opacity:.75;text-decoration-line:line-through}.product-option{color:rgb(var(--color-base-text));font-size:1.4rem;line-height:20px;opacity:.5;word-break:break-word}.cart-item cart-remove-button{display:flex;margin-left:1rem}@media screen and (min-width:750px) and (max-width:989px){.cart-item cart-remove-button{height:4.5rem;width:4.5rem}}cart-remove-button .button{background:none;color:inherit;margin:0 .1rem .1rem 0;min-height:4.5rem;min-width:4.5rem;padding:0}cart-remove-button .button:after,cart-remove-button .button:before{content:none}@media screen and (min-width:750px){cart-remove-button .button{min-height:3.5rem;min-width:3.5rem}}cart-remove-button .icon-remove{height:20px;width:20px}.cart-item .loading-overlay{bottom:0;left:auto;padding:0;right:auto;top:0}.cart-item .loading-overlay .path{stroke-width:6px}@media screen and (min-width:750px){.cart-item .loading-overlay{bottom:auto;padding-top:5.2rem;right:0}}.cart-item .loading-overlay:not(.hidden)~*{visibility:hidden}.product-option+.product-option{margin-top:.4rem}.product-option *{display:inline;margin:0}.cart-items thead th{text-transform:uppercase}.cart__footer{padding:2rem 0}.cart__footer>div:only-child{margin-left:auto}.totals{align-items:flex-end;display:flex;justify-content:center}.totals *{line-height:1}.totals>*{font-size:1.6rem;margin:0}.totals>h2{font-size:calc(var(--font-heading-scale)*1.4rem)}.totals>*+*{margin-left:2rem}.totals__subtotal-value{font-size:calc(var(--font-heading-scale)*1.4rem)}.totals__discount{margin-bottom:2rem}.tax-note{display:block;margin:2.2rem 0 1.6rem auto;text-align:center}.cart__ctas{margin-top:1rem;text-align:center}.cart__ctas button{width:100%}.cart__ctas a{margin-bottom:1rem;width:100%}@media screen and (max-width:749px){.cart-items,.cart-items tbody,.cart-items thead{display:block;width:100%}.cart-item__variants{grid-column:2/6;width:auto}.cart-item{display:grid;gap:1.5rem;grid-template:repeat(2,auto) /repeat(4,1fr)}.cart-items thead tr{border-bottom:.1rem solid hsla(0,0%,7%,.2);display:flex;justify-content:space-between;margin-bottom:4rem}.cart-item:last-child{margin-bottom:0}.cart-item__media{width:100px}.cart-item__details{padding-left:0}.cart-item__quantity{grid-column:2/5}.cart-item__quantity-wrapper{flex-wrap:wrap}.cart__ctas button{margin-bottom:2rem}.cart-item__totals{display:none}.cart__attach-list{width:fit-content!important}.cart__spec-option{display:flex;justify-content:space-between}.cart__spec-image{display:none}.cart__spec-name,.cart__spec-price,.cart__spec-quant{padding-left:0!important}}.cart-item__error-text+svg{margin-top:.4rem}@media screen and (min-width:750px){.cart-items{border-collapse:separate;border-spacing:0;box-shadow:none;display:table;width:100%}.cart-items th{border-bottom:.1rem solid hsla(0,0%,7%,.08)}.cart-items thead th:first-child{width:50%}.cart-items th+th{padding-left:4rem}.cart-items td{padding-top:3rem;vertical-align:top}.cart-item{display:table-row}.cart-item__media{width:100px}.cart-image__media{width:10rem}.cart-item cart-remove-button{margin:.5rem 0 0 1.5rem}.cart-item__price-wrapper>:only-child:not(.cart-item__discounted-prices){margin-top:1rem}.cart__footer{border:0;display:flex;justify-content:space-between}.cart__footer>*{width:35rem}.totals{justify-content:flex-end}.tax-note{margin-bottom:2.2rem;text-align:right}.cart__ctas{display:flex;flex-direction:column;gap:1rem}.cart__checkout-button{margin-bottom:1rem;width:100%}.cart__ctas button{margin-left:0;width:100%}}.cart__spec-name{padding-left:4rem}.cart__spec-quant{padding-left:6rem}.cart__spec-price{padding-left:6.7rem;text-align:right}.cart__spec-option td{padding-top:2rem}.cart__order-attach{max-width:0;padding-top:1rem!important}.cart__attach-list{background-color:#f9fbfc;border:1px solid #e2e8f0;color:#878da3;padding:1rem;width:500px}.cart__attach-list a{color:var(--color-base-text);cursor:pointer;line-height:1.7;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.cart__attach-list a:hover{color:#333}.order__product-attachment{padding:1rem}@media screen and (min-width:990px){.cart-item .cart-item__quantity,.cart-items .cart-items__heading--wide{padding-left:6rem}.cart-items thead th:first-child{width:60%}}.loading-overlay{position:absolute;width:1.8rem;z-index:1}@media screen and (max-width:749px){.loading-overlay{right:0;top:0}}@media screen and (min-width:750px){.loading-overlay{left:0}}.loading-overlay__spinner{width:1.8rem}.spinner{animation:rotator 1.4s linear infinite}@keyframes rotator{0%{transform:rotate(0deg)}to{transform:rotate(270deg)}}.path{stroke-dasharray:280;stroke-dashoffset:0;stroke:rgb(var(--color-foreground));animation:dash 1.4s ease-in-out infinite;transform-origin:center}@media screen and (forced-colors:active){.path{stroke:CanvasText}}@keyframes dash{0%{stroke-dashoffset:280}50%{stroke-dashoffset:75;transform:rotate(135deg)}to{stroke-dashoffset:280;transform:rotate(450deg)}}.loading-overlay:not(.hidden)+.cart-item__price-wrapper,.loading-overlay:not(.hidden)~cart-remove-button{opacity:50%}.loading-overlay:not(.hidden)~cart-remove-button{cursor:default;pointer-events:none}.drawer{background-color:rgba(var(--color-foreground),.5);justify-content:flex-end;left:0;position:fixed;top:0;transition:visibility var(--duration-default) ease;width:100vw}.drawer,.drawer__inner{display:flex;height:100%}.drawer__inner{background-color:#fff;border-right:0;flex-direction:column;max-width:calc(100vw - 3rem);overflow:hidden;padding:0 1.5rem;transform:translate(100%);transition:transform .3s ease;width:400px}[dir=rtl] .drawer__inner{transform:translate(-100%)}.drawer__contain{overflow-x:hidden;overflow-y:auto}.cart-drawer-show .drawer__inner{transform:translate(0)}.drawer__inner-empty{background-color:#fff;margin-top:100%}.cart-drawer__warnings{display:flex;flex-direction:column;justify-content:center;text-align:center}cart-drawer.is-empty .drawer__inner{align-items:center;display:grid;grid-template-rows:1fr;padding:0}.cart-drawer .large-up-hide{display:block!important}cart-drawer.is-empty .drawer__header{display:none}.cart-drawer__warnings--has-collection .cart__login-title{margin-top:2.5rem}.drawer__header{align-items:center;background-color:#fff;display:flex;justify-content:space-between;padding:1.5rem 0 0;position:relative}.drawer__heading{font-size:calc(var(--font-heading-scale)*1.4rem);line-height:24px;margin:0}.drawer__close{background-color:transparent;border:none;box-shadow:0 0 0 .2rem rgba(var(--color-button),0);color:rgb(var(--color-foreground));cursor:pointer;display:inline-block;min-height:4rem;min-width:4rem;padding:0;position:absolute;right:-10px;top:10px}[dir=rtl] .drawer__close{left:0;right:auto}.cart-drawer__warnings .drawer__close{right:5px}.drawer__close svg{height:1.5rem;width:1.5rem}.drawer__contents{display:flex;flex:1;flex-direction:column;flex-grow:1;overflow:hidden}.drawer__footer{background-color:#fff;border-top:.1rem solid rgba(var(--color-foreground),.2);padding:1.5rem 0}cart-drawer-items.is-empty+.drawer__footer{display:none}.drawer__footer>details{border-bottom:.1rem solid rgba(var(--color-foreground),.2);margin-top:-1.5rem}.drawer__footer>details[open]{padding-bottom:1.5rem}.drawer__footer summary{display:flex;line-height:1;padding:1.5rem 0;position:relative}.drawer__footer>details+.cart-drawer__footer{padding-top:1.5rem}cart-drawer{left:0;position:fixed;top:0;visibility:hidden;width:100vw;z-index:999}.cart-drawer-show{height:100%;visibility:visible;z-index:10}.cart-drawer__overlay{bottom:0;left:0;position:fixed;right:0;top:0}.cart-drawer__overlay:empty{display:block}.cart-drawer__form{display:flex;flex-grow:1;flex-wrap:wrap}.cart-drawer__collection{margin:0 2.5rem 1.5rem}.cart-drawer .drawer__cart-items-wrapper{flex-grow:1}.cart-drawer .cart-items,.cart-drawer tbody{display:grid;width:100%}.cart-drawer thead{background-color:#fff;display:inline-table;position:sticky;top:0;width:100%;z-index:2}cart-drawer-items{flex:1;overflow:auto}@media screen and (max-height:650px){cart-drawer-items{overflow:visible}}.cart-drawer .cart-item{display:grid;margin-bottom:0}.cart-drawer .cart-item:last-child{margin-bottom:1rem}.cart-drawer .cart-item__image{max-width:100%}.cart-drawer .cart-items thead{font-size:14px;margin-bottom:.5rem}.cart-drawer .cart-items thead th:nth-child(2){padding-left:0;width:50%}.cart-drawer .cart-items thead tr{display:table-row;margin-bottom:0}.cart-drawer .cart-items th{border-bottom:.1rem solid rgba(var(--color-foreground),.08)}.cart-drawer .cart-item:last-child{margin-bottom:1.5rem}.cart-drawer .cart-item .loading-overlay{padding-top:2.5rem;right:5px}.cart-drawer .cart-items td{padding-top:2rem}.cart-drawer .cart-item__totals{align-items:flex-start;display:none;justify-content:flex-end;pointer-events:none}.cart-drawer.cart-drawer .cart-item__price-wrapper>:only-child{margin-top:0}.cart-drawer .cart-item__price-wrapper .cart-item__discounted-prices{display:flex;flex-direction:column;gap:.6rem}.cart-drawer .unit-price{margin-top:.6rem}@media screen and (max-width:749px){.cart-drawer .cart-item cart-remove-button{margin-left:0}}.cart-drawer__footer>*+*{margin-top:1rem}.cart-drawer .totals{justify-content:space-between}.cart-drawer .price{line-height:1}.cart-drawer .tax-note{color:var(--color-text);margin:1.2rem 0 1rem auto;opacity:.75;text-align:left}.cart-drawer .product-option dd{word-break:break-word}.cart-drawer details[open]>summary .icon-caret{transform:rotate(180deg)}.cart-drawer .cart__checkout-button{max-width:none}.drawer__footer .cart__dynamic-checkout-buttons{max-width:100%}.drawer__footer #dynamic-checkout-cart ul{flex-direction:row!important;flex-wrap:wrap!important;gap:.5rem;margin:.5rem -.5rem 0 0!important}.drawer__footer [data-shopify-buttoncontainer]{justify-content:flex-start}.drawer__footer #dynamic-checkout-cart ul>li{flex-basis:calc(50% - 0.5rem)!important;margin:0!important}.drawer__footer #dynamic-checkout-cart ul>li:only-child{flex-basis:100%!important;margin-right:.5rem!important}@media screen and (min-width:750px){.drawer__footer #dynamic-checkout-cart ul>li{flex-basis:calc(33.33333% - 0.5rem)!important;margin:0!important}.drawer__footer #dynamic-checkout-cart ul>li:first-child:nth-last-child(2),.drawer__footer #dynamic-checkout-cart ul>li:first-child:nth-last-child(2)~li,.drawer__footer #dynamic-checkout-cart ul>li:first-child:nth-last-child(4),.drawer__footer #dynamic-checkout-cart ul>li:first-child:nth-last-child(4)~li{flex-basis:calc(50% - 0.5rem)!important}}cart-drawer-items::-webkit-scrollbar{width:3px}cart-drawer-items::-webkit-scrollbar-thumb{background-color:rgba(var(--color-foreground),.7);border-radius:100px}cart-drawer-items::-webkit-scrollbar-track-piece{margin-top:31px}.drawer__recommend{background-color:#f9fafb;padding:1rem}.drawer__recommend h3{font-size:calc(var(--font-heading-scale)*1.4rem);font-weight:600;margin-bottom:1rem;margin-top:.5rem;text-transform:uppercase}.drawer__recommend .drawer-item{display:flex;margin-bottom:15px}.drawer__recommend .drawer-link{display:inline-block;flex-shrink:0;margin-right:14px;width:100px}[dir=rtl] .drawer__recommend .drawer-link{margin-left:14px;margin-right:0}.drawer__recommend .drawer-link img{height:auto;max-width:100%;width:100%}.drawer__recommend .drawer-title{color:rgb(var(--color-base-text));display:block;font-size:calc(var(--font-heading-scale)*1.5rem);text-decoration:none}.drawer__recommend .drawer-title:hover{text-decoration:underline}.cart-notification-wrapper{position:relative}.cart-notification-wrapper .cart-notification{display:block}.cart-notification{background:#fff;border-bottom-left-radius:var(--popup-corner-radius);border-bottom-right-radius:var(--popup-corner-radius);border-color:rgba(var(--color-foreground),var(--popup-border-opacity));border-style:solid;border-width:0 0 var(--popup-border-width);box-shadow:var(--popup-shadow-horizontal-offset) var(--popup-shadow-vertical-offset) var(--popup-shadow-blur-radius) rgba(var(--color-shadow),var(--popup-shadow-opacity));padding:2rem;position:absolute;right:0;transform:translateY(-100%);visibility:hidden;width:100%;z-index:-1}.cart-notification.focused{box-shadow:0 0 .2rem 0 rgba(var(--color-foreground),.3),var(--popup-shadow-horizontal-offset) var(--popup-shadow-vertical-offset) var(--popup-shadow-blur-radius) rgba(var(--color-shadow),var(--popup-shadow-opacity))}.cart-notification:focus-visible{box-shadow:0 0 .2rem 0 rgba(var(--color-foreground),.3),var(--popup-shadow-horizontal-offset) var(--popup-shadow-vertical-offset) var(--popup-shadow-blur-radius) rgba(var(--color-shadow),var(--popup-shadow-opacity))}@media screen and (min-width:750px){.header-wrapper:not(.header-wrapper--border-bottom)+cart-notification .cart-notification{border-top-width:var(--popup-border-width)}.cart-notification{border-width:0 var(--popup-border-width) var(--popup-border-width);max-width:36.8rem;right:2.2rem}}@media screen and (min-width:990px){.cart-notification-wrapper:is(.page-width)>.cart-notification{right:5rem}}.cart-notification.animate{transition:transform var(--duration-short) ease,visibility 0s var(--duration-short) ease}.cart-notification.active{transform:translateY(0);transition:transform var(--duration-default) ease,visibility 0s;visibility:visible}.cart-notification__header{align-items:flex-start;display:flex}.cart-notification__heading{align-items:center;display:flex;flex-grow:1;margin-bottom:0;margin-top:-6px}.cart-notification__heading .icon-checkmark{color:rgb(var(--color-foreground));margin-right:1rem;width:1.3rem}.cart-notification__close{margin-right:-2rem;margin-top:-2rem}.cart-notification__links{text-align:center}.cart-notification__links button{margin-top:1rem}.cart-notification__links .button,.cart-notification__links button{width:100%}.cart-notification-product{align-items:flex-start;display:flex;padding-bottom:3rem;padding-top:2rem}.cart-notification-product dl{margin-bottom:0;margin-top:0}.cart-notification-product__image{display:inline-flex;margin-right:1.5rem;margin-top:.5rem}.cart-notification-product__image:after{content:none}.cart-notification-product__name{margin-bottom:.5rem;margin-top:0}.rating{display:inline-flex;position:relative}.rating input:checked~input{background:var(--radf-rate-default,#e8e8e8)}.rating input{-moz-appearance:none;appearance:none;-webkit-appearance:none;background-color:var(--radf-rate-selected,#fadb14);border-radius:0;color:inherit;cursor:pointer;height:1.6rem;margin:0;-webkit-mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkyIiBoZWlnaHQ9IjE4MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtOTYgMTUzLjA0NC01OC43NzkgMjYuMjQzIDcuMDItNjMuNTEzTC44OTQgNjguNDgxbDYzLjExNy0xMy4wMUw5NiAwbDMxLjk4OSA1NS40NzIgNjMuMTE3IDEzLjAxLTQzLjM0NyA0Ny4yOTIgNy4wMiA2My41MTN6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=);mask-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTkyIiBoZWlnaHQ9IjE4MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtOTYgMTUzLjA0NC01OC43NzkgMjYuMjQzIDcuMDItNjMuNTEzTC44OTQgNjguNDgxbDYzLjExNy0xMy4wMUw5NiAwbDMxLjk4OSA1NS40NzIgNjMuMTE3IDEzLjAxLTQzLjM0NyA0Ny4yOTIgNy4wMiA2My41MTN6IiBmaWxsLXJ1bGU9ImV2ZW5vZGQiLz48L3N2Zz4=);padding:0;width:1.6rem}.mask{-webkit-mask-position:center;mask-position:center;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain} </style> <script> const trapFocusHandlers = {}; function isMobile() { return window.matchMedia('(max-width: 750px)').matches } function getFocusableElements(container) { return Array.from( container.querySelectorAll( "summary, a[href], button:enabled, [tabindex]:not([tabindex^='-']), [draggable], area, input:not([type=hidden]):enabled, select:enabled, textarea:enabled, object, iframe" ) ); } function trapFocus(container, elementToFocus = container) { var elements = getFocusableElements(container); var first = elements[0]; var last = elements[elements.length - 1]; removeTrapFocus(); trapFocusHandlers.focusin = (event) => { if ( event.target !== container && event.target !== last && event.target !== first ) return; document.addEventListener('keydown', trapFocusHandlers.keydown); }; trapFocusHandlers.focusout = function () { document.removeEventListener('keydown', trapFocusHandlers.keydown); }; trapFocusHandlers.keydown = function (event) { if (event.code.toUpperCase() !== 'TAB') return; // If not TAB key // On the last focusable element and tab forward, focus the first element. if (event.target === last && !event.shiftKey) { event.preventDefault(); first.focus(); } // On the first focusable element and tab backward, focus the last element. if ( (event.target === container || event.target === first) && event.shiftKey ) { event.preventDefault(); last.focus(); } }; document.addEventListener('focusout', trapFocusHandlers.focusout); document.addEventListener('focusin', trapFocusHandlers.focusin); elementToFocus.focus(); if (elementToFocus.tagName === 'INPUT' && ['search', 'text', 'email', 'url'].includes(elementToFocus.type) && elementToFocus.value) { elementToFocus.setSelectionRange(0, elementToFocus.value.length); } } function removeTrapFocus(elementToFocus = null) { document.removeEventListener('focusin', trapFocusHandlers.focusin); document.removeEventListener('focusout', trapFocusHandlers.focusout); document.removeEventListener('keydown', trapFocusHandlers.keydown); if (elementToFocus) elementToFocus.focus(); } function urlParams(url) { url = url || window.location.href var params = {} url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function (str, key, value) { try { params[key] = decodeURIComponent(value) } catch (e) { params[key] = value } }) return params } function getCookie(sName) { var oCrumbles = document.cookie.split(';') for (var i = 0; i < oCrumbles.length; i++) { var oPair = oCrumbles[i].split('=') var sKey = decodeURIComponent(oPair[0].trim()) var sValue = oPair.length > 1 ? oPair[1] : '' if (sKey == sName) { return decodeURIComponent(sValue) } } return '' } function setCookie(sName, sValue, options) { var sCookie = encodeURIComponent(sName) + '=' + encodeURIComponent(sValue) if (options instanceof Date) { options = { expires: options } } options = options || {} if (options.expires) { sCookie += '; expires=' + options.expires } if (options.path) { sCookie += '; path=' + options.path.toString() } if (options.domain) { sCookie += '; domain=' + options.domain.toString() } if (options.secure) { sCookie += '; secure' } document.cookie = sCookie } function delCookie(sName) { document.cookie = sName + "=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; }; function showToast(message, type = 'info', duration = 3000) { var toast = document.createElement('div') toast.classList.add('toast', 'toast-' + type) toast.textContent = message document.body.appendChild(toast) setTimeout(function () { toast.classList.add('toast-hidden') setTimeout(function () { document.body.removeChild(toast) }, 3500) }, duration) } function showLoading() { const loadingCover = document.createElement('div') loadingCover.id = 'loadingCover' loadingCover.className = 'loading-cover' const loadingSpinner = document.createElement('div') loadingSpinner.className = 'loading-spinner' const bounce1Element = document.createElement('div') bounce1Element.className = 'loading-bounce1' const bounce2Element = document.createElement('div') bounce2Element.className = 'loading-bounce2' loadingSpinner.appendChild(bounce1Element) loadingSpinner.appendChild(bounce2Element) loadingCover.appendChild(loadingSpinner) document.body.appendChild(loadingCover) } function hideLoading() { const loadingCover = document.getElementById('loadingCover') document.body.removeChild(loadingCover) } function debounce(fn, wait) { let t return (...args) => { clearTimeout(t) t = setTimeout(() => fn.apply(this, args), wait) } } function fetchConfig(method = 'POST', type = 'json') { let contentType let userAgents = getCookie('User-Agents') let bearerToken = userAgents ? `Bearer ${userAgents}` : '' if (type === 'json') { contentType = 'application/json' } const headers = { Authorization: bearerToken, 'store-locale': SHOPTOP.locale } if (contentType) { headers['Content-Type'] = contentType } return { headers, method: method } } function validateForm(formData, rules) { const errors = [] for (let field in rules) { if (rules.hasOwnProperty(field)) { const fieldRules = rules[field] const value = formData[field] for (let i = 0; i < fieldRules.length; i++) { const rule = fieldRules[i] if (rule.required && !value) { errors.push(rule.message) break } if (rule.minLength && value.length < rule.minLength) { errors.push(rule.message) break } if (rule.maxLength && value.length > rule.maxLength) { errors.push(rule.message) break } if (rule.some && formData.password != formData.confirmPw) { errors.push(rule.message) break } if (rule.pattern instanceof RegExp) { if (rule.type && rule.pattern.test(value)) { errors.push(rule.message) } if (!rule.type && !rule.pattern.test(value)) { errors.push(rule.message) } break } } } } return [...new Set(errors)] } function throttle(func, delay) { let timeoutId; return function () { const context = this; const args = arguments; if (!timeoutId) { timeoutId = setTimeout(function () { func.apply(context, args); timeoutId = null; }, delay) } }; } /* * Shoptop Common JS * */ </script> </head> <body class="gradient"> <script> /* eslint-disable */ window.lazySizesConfig = window.lazySizesConfig || {}; window.lazySizesConfig.rias = window.lazySizesConfig.rias || {}; window.lazySizesConfig.rias.widths = [48, 180, 360, 540, 720, 900, 1024, 1280, 1366, 1440, 1536, 1600, 1920, 2056]; window.lazySizesConfig.rias.modifyOptions = function (data) { data.detail.width = data.detail.widths.filter(function (w) { return w > ((window.devicePixelRatio || 1) + 1) / 2 * Math.max(data.target.offsetWidth, parseInt(data.target.getAttribute("width")) || 0); })[0]; }; /*! lazysizes - v5.1.0 */ !function (a, b) { var c = b(a, a.document); a.lazySizes = c, "object" == typeof module && module.exports && (module.exports = c) }("undefined" != typeof window ? window : {}, function (a, b) { "use strict"; var c, d; if (function () { var b, c = { lazyClass: "lazyload", loadedClass: "lazyloaded", loadingClass: "lazyloading", preloadClass: "lazypreload", errorClass: "lazyerror", autosizesClass: "lazyautosizes", srcAttr: "data-src", srcsetAttr: "data-srcset", sizesAttr: "data-sizes", minSize: 40, customMedia: {}, init: !0, expFactor: 1.5, hFac: .8, loadMode: 2, loadHidden: !0, ricTimeout: 0, throttleDelay: 125 }; d = a.lazySizesConfig || a.lazysizesConfig || {}; for (b in c) b in d || (d[b] = c[b]) }(), !b || !b.getElementsByClassName) return { init: function () { }, cfg: d, noSupport: !0 }; var e = b.documentElement, f = a.Date, g = a.HTMLPictureElement, h = "addEventListener", i = "getAttribute", j = a[h], k = a.setTimeout, l = a.requestAnimationFrame || k, m = a.requestIdleCallback, n = /^picture$/i, o = ["load", "error", "lazyincluded", "_lazyloaded"], p = {}, q = Array.prototype.forEach, r = function (a, b) { return p[b] || (p[b] = new RegExp("(\\s|^)" + b + "(\\s|$)")), p[b].test(a[i]("class") || "") && p[b] }, s = function (a, b) { r(a, b) || a.setAttribute("class", (a[i]("class") || "").trim() + " " + b) }, t = function (a, b) { var c; (c = r(a, b)) && a.setAttribute("class", (a[i]("class") || "").replace(c, " ")) }, u = function (a, b, c) { var d = c ? h : "removeEventListener"; c && u(a, b), o.forEach(function (c) { a[d](c, b) }) }, v = function (a, d, e, f, g) { var h = b.createEvent("Event"); return e || (e = {}), e.instance = c, h.initEvent(d, !f, !g), h.detail = e, a.dispatchEvent(h), h }, w = function (b, c) { var e; !g && (e = a.picturefill || d.pf) ? (c && c.src && !b[i]("srcset") && b.setAttribute("srcset", c.src), e({ reevaluate: !0, elements: [b] })) : c && c.src && (b.src = c.src) }, x = function (a, b) { return (getComputedStyle(a, null) || {})[b] }, y = function (a, b, c) { for (c = c || a.offsetWidth; c < d.minSize && b && !a._lazysizesWidth;)c = b.offsetWidth, b = b.parentNode; return c }, z = function () { var a, c, d = [], e = [], f = d, g = function () { var b = f; for (f = d.length ? e : d, a = !0, c = !1; b.length;)b.shift()(); a = !1 }, h = function (d, e) { a && !e ? d.apply(this, arguments) : (f.push(d), c || (c = !0, (b.hidden ? k : l)(g))) }; return h._lsFlush = g, h }(), A = function (a, b) { return b ? function () { z(a) } : function () { var b = this, c = arguments; z(function () { a.apply(b, c) }) } }, B = function (a) { var b, c = 0, e = d.throttleDelay, g = d.ricTimeout, h = function () { b = !1, c = f.now(), a() }, i = m && g > 49 ? function () { m(h, { timeout: g }), g !== d.ricTimeout && (g = d.ricTimeout) } : A(function () { k(h) }, !0); return function (a) { var d; (a = !0 === a) && (g = 33), b || (b = !0, d = e - (f.now() - c), d < 0 && (d = 0), a || d < 9 ? i() : k(i, d)) } }, C = function (a) { var b, c, d = 99, e = function () { b = null, a() }, g = function () { var a = f.now() - c; a < d ? k(g, d - a) : (m || e)(e) }; return function () { c = f.now(), b || (b = k(g, d)) } }, D = function () { var g, l, m, o, p, y, D, F, G, H, I, J, K = /^img$/i, L = /^iframe$/i, M = "onscroll" in a && !/(gle|ing)bot/.test(navigator.userAgent), N = 0, O = 0, P = 0, Q = -1, R = function (a) { P--, (!a || P < 0 || !a.target) && (P = 0) }, S = function (a) { return null == J && (J = "hidden" == x(b.body, "visibility")), J || "hidden" != x(a.parentNode, "visibility") && "hidden" != x(a, "visibility") }, T = function (a, c) { var d, f = a, g = S(a); for (F -= c, I += c, G -= c, H += c; g && (f = f.offsetParent) && f != b.body && f != e;)(g = (x(f, "opacity") || 1) > 0) && "visible" != x(f, "overflow") && (d = f.getBoundingClientRect(), g = H > d.left && G < d.right && I > d.top - 1 && F < d.bottom + 1); return g }, U = function () { var a, f, h, j, k, m, n, p, q, r, s, t, u = c.elements; if ((o = d.loadMode) && P < 8 && (a = u.length)) { for (f = 0, Q++; f < a; f++)if (u[f] && !u[f]._lazyRace) if (!M || c.prematureUnveil && c.prematureUnveil(u[f])) aa(u[f]); else if ((p = u[f][i]("data-expand")) && (m = 1 * p) || (m = O), r || (r = !d.expand || d.expand < 1 ? e.clientHeight > 500 && e.clientWidth > 500 ? 500 : 370 : d.expand, c._defEx = r, s = r * d.expFactor, t = d.hFac, J = null, O < s && P < 1 && Q > 2 && o > 2 && !b.hidden ? (O = s, Q = 0) : O = o > 1 && Q > 1 && P < 6 ? r : N), q !== m && (y = innerWidth + m * t, D = innerHeight + m, n = -1 * m, q = m), h = u[f].getBoundingClientRect(), (I = h.bottom) >= n && (F = h.top) <= D && (H = h.right) >= n * t && (G = h.left) <= y && (I || H || G || F) && (d.loadHidden || S(u[f])) && (l && P < 3 && !p && (o < 3 || Q < 4) || T(u[f], m))) { if (aa(u[f]), k = !0, P > 9) break } else !k && l && !j && P < 4 && Q < 4 && o > 2 && (g[0] || d.preloadAfterLoad) && (g[0] || !p && (I || H || G || F || "auto" != u[f][i](d.sizesAttr))) && (j = g[0] || u[f]); j && !k && aa(j) } }, V = B(U), W = function (a) { var b = a.target; if (b._lazyCache) return void delete b._lazyCache; R(a), s(b, d.loadedClass), t(b, d.loadingClass), u(b, Y), v(b, "lazyloaded") }, X = A(W), Y = function (a) { X({ target: a.target }) }, Z = function (a, b) { try { a.contentWindow.location.replace(b) } catch (c) { a.src = b } }, $ = function (a) { var b, c = a[i](d.srcsetAttr); (b = d.customMedia[a[i]("data-media") || a[i]("media")]) && a.setAttribute("media", b), c && a.setAttribute("srcset", c) }, _ = A(function (a, b, c, e, f) { var g, h, j, l, o, p; (o = v(a, "lazybeforeunveil", b)).defaultPrevented || (e && (c ? s(a, d.autosizesClass) : a.setAttribute("sizes", e)), h = a[i](d.srcsetAttr), g = a[i](d.srcAttr), f && (j = a.parentNode, l = j && n.test(j.nodeName || "")), p = b.firesLoad || "src" in a && (h || g || l), o = { target: a }, s(a, d.loadingClass), p && (clearTimeout(m), m = k(R, 2500), u(a, Y, !0)), l && q.call(j.getElementsByTagName("source"), $), h ? a.setAttribute("srcset", h) : g && !l && (L.test(a.nodeName) ? Z(a, g) : a.src = g), f && (h || l) && w(a, { src: g })), a._lazyRace && delete a._lazyRace, t(a, d.lazyClass), z(function () { var b = a.complete && a.naturalWidth > 1; p && !b || (b && s(a, "ls-is-cached"), W(o), a._lazyCache = !0, k(function () { "_lazyCache" in a && delete a._lazyCache }, 9)), "lazy" == a.loading && P-- }, !0) }), aa = function (a) { if (!a._lazyRace) { var b, c = K.test(a.nodeName), e = c && (a[i](d.sizesAttr) || a[i]("sizes")), f = "auto" == e; (!f && l || !c || !a[i]("src") && !a.srcset || a.complete || r(a, d.errorClass) || !r(a, d.lazyClass)) && (b = v(a, "lazyunveilread").detail, f && E.updateElem(a, !0, a.offsetWidth), a._lazyRace = !0, P++, _(a, b, f, e, c)) } }, ba = C(function () { d.loadMode = 3, V() }), ca = function () { 3 == d.loadMode && (d.loadMode = 2), ba() }, da = function () { if (!l) { if (f.now() - p < 999) return void k(da, 999); l = !0, d.loadMode = 3, V(), j("scroll", ca, !0) } }; return { _: function () { p = f.now(), c.elements = b.getElementsByClassName(d.lazyClass), g = b.getElementsByClassName(d.lazyClass + " " + d.preloadClass), j("scroll", V, !0), j("resize", V, !0), a.MutationObserver ? new MutationObserver(V).observe(e, { childList: !0, subtree: !0, attributes: !0 }) : (e[h]("DOMNodeInserted", V, !0), e[h]("DOMAttrModified", V, !0), setInterval(V, 999)), j("hashchange", V, !0), ["focus", "mouseover", "click", "load", "transitionend", "animationend"].forEach(function (a) { b[h](a, V, !0) }), /d$|^c/.test(b.readyState) ? da() : (j("load", da), b[h]("DOMContentLoaded", V), k(da, 2e4)), c.elements.length ? (U(), z._lsFlush()) : V() }, checkElems: V, unveil: aa, _aLSL: ca } }(), E = function () { var a, c = A(function (a, b, c, d) { var e, f, g; if (a._lazysizesWidth = d, d += "px", a.setAttribute("sizes", d), n.test(b.nodeName || "")) for (e = b.getElementsByTagName("source"), f = 0, g = e.length; f < g; f++)e[f].setAttribute("sizes", d); c.detail.dataAttr || w(a, c.detail) }), e = function (a, b, d) { var e, f = a.parentNode; f && (d = y(a, f, d), e = v(a, "lazybeforesizes", { width: d, dataAttr: !!b }), e.defaultPrevented || (d = e.detail.width) && d !== a._lazysizesWidth && c(a, f, e, d)) }, f = function () { var b, c = a.length; if (c) for (b = 0; b < c; b++)e(a[b]) }, g = C(f); return { _: function () { a = b.getElementsByClassName(d.autosizesClass), j("resize", g) }, checkElems: g, updateElem: e } }(), F = function () { !F.i && b.getElementsByClassName && (F.i = !0, E._(), D._()) }; return k(function () { d.init && F() }), c = { cfg: d, autoSizer: E, loader: D, init: F, uP: w, aC: s, rC: t, hC: r, fire: v, gW: y, rAF: z } }); /*! lazysizes-rias - v5.1.0 */ !function (a, b) { var c = function () { b(a.lazySizes), a.removeEventListener("lazyunveilread", c, !0) }; b = b.bind(null, a, a.document), "object" == typeof module && module.exports ? b(require("lazysizes")) : a.lazySizes ? c() : a.addEventListener("lazyunveilread", c, !0) }(window, function (a, b, c) { "use strict"; function d(b, c) { var d, e, f, g, h = a.getComputedStyle(b); e = b.parentNode, g = { isPicture: !(!e || !n.test(e.nodeName || "")) }, f = function (a, c) { var d = b.getAttribute("data-" + a); if (!d) { var e = h.getPropertyValue("--ls-" + a); e && (d = e.trim()) } if (d) { if ("true" == d) d = !0; else if ("false" == d) d = !1; else if (m.test(d)) d = parseFloat(d); else if ("function" == typeof j[a]) d = j[a](b, d); else if (r.test(d)) try { d = JSON.parse(d) } catch (a) { } g[a] = d } else a in j && "function" != typeof j[a] ? g[a] = j[a] : c && "function" == typeof j[a] && (g[a] = j[a](b, d)) }; for (d in j) f(d); return c.replace(q, function (a, b) { b in g || f(b, !0) }), g } function e(a, b) { var c = [], d = function (a, c) { return l[typeof b[c]] ? b[c] : a }; return c.srcset = [], b.absUrl && (t.setAttribute("href", a), a = t.href), a = ((b.prefix || "") + a + (b.postfix || "")).replace(q, d), b.widths.forEach(function (d) { var e = b.widthmap[d] || d, f = b.aspectratio || b.ratio, g = !b.aspectratio && j.traditionalRatio, h = { u: a.replace(o, e).replace(p, f ? g ? Math.round(d * f) : Math.round(d / f) : ""), w: d }; c.push(h), c.srcset.push(h.c = h.u + " " + d + "w") }), c } function f(a, c, d) { var f = 0, g = 0, h = d; if (a) { if ("container" === c.ratio) { for (f = h.scrollWidth, g = h.scrollHeight; !(f && g || h === b);)h = h.parentNode, f = h.scrollWidth, g = h.scrollHeight; f && g && (c.ratio = g / f) } a = e(a, c), a.isPicture = c.isPicture, v && "IMG" == d.nodeName.toUpperCase() ? d.removeAttribute(i.srcsetAttr) : d.setAttribute(i.srcsetAttr, a.srcset.join(", ")), Object.defineProperty(d, "_lazyrias", { value: a, writable: !0 }) } } function g(a, b) { var e = d(a, b); return j.modifyOptions.call(a, { target: a, details: e, detail: e }), c.fire(a, "lazyriasmodifyoptions", e), e } function h(a) { return a.getAttribute(a.getAttribute("data-srcattr") || j.srcAttr) || a.getAttribute(i.srcsetAttr) || a.getAttribute(i.srcAttr) || a.getAttribute("data-pfsrcset") || "" } var i, j, k = c.cfg, l = { string: 1, number: 1 }, m = /^\-*\+*\d+\.*\d*$/, n = /^picture$/i, o = /\s*\{\s*width\s*\}\s*/i, p = /\s*\{\s*height\s*\}\s*/i, q = /\s*\{\s*([a-z0-9]+)\s*\}\s*/gi, r = /^\[.*\]|\{.*\}$/, s = /^(?:auto|\d+(px)?)$/, t = b.createElement("a"), u = b.createElement("img"), v = "srcset" in u && !("sizes" in u), w = !!a.HTMLPictureElement && !v; !function () { var a, b = function () { }, d = { prefix: "", postfix: "", srcAttr: "data-src", absUrl: !1, modifyOptions: b, widthmap: {}, ratio: !1, traditionalRatio: !1, aspectratio: !1 }; i = c && c.cfg, i.supportsType || (i.supportsType = function (a) { return !a }), i.rias || (i.rias = {}), "widths" in (j = i.rias) || (j.widths = [], function (a) { for (var b, c = 0; !b || b < 3e3;)c += 5, c > 30 && (c += 1), b = 36 * c, a.push(b) }(j.widths)); for (a in d) a in j || (j[a] = d[a]) }(), addEventListener("lazybeforesizes", function (a) { if (a.detail.instance == c) { var b, d, e, k, l, m, n, p, q, r, t, u, v; if (b = a.target, a.detail.dataAttr && !a.defaultPrevented && !j.disabled && (q = b.getAttribute(i.sizesAttr) || b.getAttribute("sizes")) && s.test(q)) { if (d = h(b), e = g(b, d), t = o.test(e.prefix) || o.test(e.postfix), e.isPicture && (k = b.parentNode)) for (l = k.getElementsByTagName("source"), m = 0, n = l.length; m < n; m++)(t || o.test(p = h(l[m]))) && (f(p, e, l[m]), u = !0); t || o.test(d) ? (f(d, e, b), u = !0) : u && (v = [], v.srcset = [], v.isPicture = !0, Object.defineProperty(b, "_lazyrias", { value: v, writable: !0 })), u && (w ? b.removeAttribute(i.srcAttr) : "auto" != q && (r = { width: parseInt(q, 10) }, x({ target: b, detail: r }))) } } }, !0); var x = function () { var d = function (a, b) { return a.w - b.w }, e = function (a) { var b, c, d = a.length, e = a[d - 1], f = 0; for (f; f < d; f++)if (e = a[f], e.d = e.w / a.w, e.d >= a.d) { !e.cached && (b = a[f - 1]) && b.d > a.d - .13 * Math.pow(a.d, 2.2) && (c = Math.pow(b.d - .6, 1.6), b.cached && (b.d += .15 * c), b.d + (e.d - a.d) * c > a.d && (e = b)); break } return e }, f = function (a, b) { var d; return !a._lazyrias && c.pWS && (d = c.pWS(a.getAttribute(i.srcsetAttr || ""))).length && (Object.defineProperty(a, "_lazyrias", { value: d, writable: !0 }), b && a.parentNode && (d.isPicture = "PICTURE" == a.parentNode.nodeName.toUpperCase())), a._lazyrias }, g = function (b) { var d = a.devicePixelRatio || 1, e = c.getX && c.getX(b); return Math.min(e || d, 2.4, d) }, h = function (b, c) { var h, i, j, k, l, m; if (l = b._lazyrias, l.isPicture && a.matchMedia) for (i = 0, h = b.parentNode.getElementsByTagName("source"), j = h.length; i < j; i++)if (f(h[i]) && !h[i].getAttribute("type") && (!(k = h[i].getAttribute("media")) || (matchMedia(k) || {}).matches)) { l = h[i]._lazyrias; break } return (!l.w || l.w < c) && (l.w = c, l.d = g(b), m = e(l.sort(d))), m }, j = function (d) { if (d.detail.instance == c) { var e, g = d.target; if (!v && (a.respimage || a.picturefill || k.pf)) return void b.removeEventListener("lazybeforesizes", j); ("_lazyrias" in g || d.detail.dataAttr && f(g, !0)) && (e = h(g, d.detail.width)) && e.u && g._lazyrias.cur != e.u && (g._lazyrias.cur = e.u, e.cached = !0, c.rAF(function () { g.setAttribute(i.srcAttr, e.u), g.setAttribute("src", e.u) })) } }; return w ? j = function () { } : addEventListener("lazybeforesizes", j), j }() }); /*! lazysizes-data-bgset - v5.1.0 */ !function (a, b) { var c = function () { b(a.lazySizes), a.removeEventListener("lazyunveilread", c, !0) }; b = b.bind(null, a, a.document), "object" == typeof module && module.exports ? b(require("lazysizes")) : a.lazySizes ? c() : a.addEventListener("lazyunveilread", c, !0) }(window, function (a, b, c) { "use strict"; if (a.addEventListener) { var d = c.cfg, e = /\s+/g, f = /\s*\|\s+|\s+\|\s*/g, g = /^(.+?)(?:\s+\[\s*(.+?)\s*\])(?:\s+\[\s*(.+?)\s*\])?$/, h = /^\s*\(*\s*type\s*:\s*(.+?)\s*\)*\s*$/, i = /\(|\)|'/, j = { contain: 1, cover: 1 }, k = function (a) { var b = c.gW(a, a.parentNode); return (!a._lazysizesWidth || b > a._lazysizesWidth) && (a._lazysizesWidth = b), a._lazysizesWidth }, l = function (a) { var b; return b = (getComputedStyle(a) || { getPropertyValue: function () { } }).getPropertyValue("background-size"), !j[b] && j[a.style.backgroundSize] && (b = a.style.backgroundSize), b }, m = function (a, b) { if (b) { var c = b.match(h); c && c[1] ? a.setAttribute("type", c[1]) : a.setAttribute("media", d.customMedia[b] || b) } }, n = function (a, c, h) { var i = b.createElement("picture"), j = c.getAttribute(d.sizesAttr), k = c.getAttribute("data-ratio"), l = c.getAttribute("data-optimumx"); c._lazybgset && c._lazybgset.parentNode == c && c.removeChild(c._lazybgset), Object.defineProperty(h, "_lazybgset", { value: c, writable: !0 }), Object.defineProperty(c, "_lazybgset", { value: i, writable: !0 }), a = a.replace(e, " ").split(f), i.style.display = "none", h.className = d.lazyClass, 1 != a.length || j || (j = "auto"), a.forEach(function (a) { var c, e = b.createElement("source"); j && "auto" != j && e.setAttribute("sizes", j), (c = a.match(g)) ? (e.setAttribute(d.srcsetAttr, c[1]), m(e, c[2]), m(e, c[3])) : e.setAttribute(d.srcsetAttr, a), i.appendChild(e) }), j && (h.setAttribute(d.sizesAttr, j), c.removeAttribute(d.sizesAttr), c.removeAttribute("sizes")), l && h.setAttribute("data-optimumx", l), k && h.setAttribute("data-ratio", k), i.appendChild(h), c.appendChild(i) }, o = function (a) { if (a.target._lazybgset) { var b = a.target, d = b._lazybgset, e = b.currentSrc || b.src; if (e) { var f = c.fire(d, "bgsetproxy", { src: e, useSrc: i.test(e) ? JSON.stringify(e) : e }); f.defaultPrevented || (d.style.backgroundImage = "url(" + f.detail.useSrc + ")") } b._lazybgsetLoading && (c.fire(d, "_lazyloaded", {}, !1, !0), delete b._lazybgsetLoading) } }; addEventListener("lazybeforeunveil", function (a) { var d, e, f; !a.defaultPrevented && (d = a.target.getAttribute("data-bgset")) && (f = a.target, e = b.createElement("img"), e.alt = "", e._lazybgsetLoading = !0, a.detail.firesLoad = !0, n(d, f, e), setTimeout(function () { c.loader.unveil(e), c.rAF(function () { c.fire(e, "_lazyloaded", {}, !0, !0), e.complete && o({ target: e }) }) })) }), b.addEventListener("load", o, !0), a.addEventListener("lazybeforesizes", function (a) { if (a.detail.instance == c && a.target._lazybgset && a.detail.dataAttr) { var b = a.target._lazybgset, d = l(b); j[d] && (a.target._lazysizesParentFit = d, c.rAF(function () { a.target.setAttribute("data-parent-fit", d), a.target._lazysizesParentFit && delete a.target._lazysizesParentFit })) } }, !0), b.documentElement.addEventListener("lazybeforesizes", function (a) { !a.defaultPrevented && a.target._lazybgset && a.detail.instance == c && (a.detail.width = k(a.target._lazybgset)) }) } }); /*! lazysizes data-srcs data-bgs plugin */ document.addEventListener('lazybeforesizes', function (e) { var attrVal = e.target.getAttribute('data-srcs'); var targetWidth = e.target.clientWidth; if (!attrVal) return; var srcs = attrVal.split(","); var widths = [48, 180, 360 ,540, 720, 900, 1024, 1280, 1366, 1440, 1536, 1600, 1920, 2056]; srcs = [srcs[0] || srcs[1], srcs[1] || srcs[0]]; var availableWidths = widths.filter(function (w) { return w <= Math.max(targetWidth, widths[0]) * window.devicePixelRatio; }); var srcset = availableWidths.map(function (w) { return srcs[window.innerWidth <= (window.breakpoint || 768) ? 0 : 1].replace('{width}', w) + " " + w + "w" }).join(", "); e.target.setAttribute("srcset", srcset); e.target.setAttribute("size", targetWidth + "px"); }); </script> <style> webcom-media-3d model-viewer { width: 100%; height: 100%; background-color: #eee; } .webcom-media-3d-loadding svg{ width: 100px; height: 100px; animation: webcomMedia3dLoadding 2s ease-out infinite; } webcom-media-3d .player { position: absolute; width: 60px; height: 60px; border-radius: 4px; background-color: rgba(0, 0, 0, 0.75); color: white; left: 50%; bottom: 20%; transform: translateX(-50%); cursor: pointer; display: flex; justify-content: center; align-items: center; } webcom-media-3d .player:hover { box-shadow: 0 0 1px 1px rgba(0, 0, 0, 1); } webcom-media-3d .player > svg { width: 28px; height: 28px; } @keyframes webcomMedia3dLoadding { 0% { color: grey; transform: rotate(-45deg) } 65% { color: white; transform: rotate(-135deg) } 100% { color: grey; transform: rotate(-45deg) } } </style> <style> .webcom-media-3d-container { width: 100%; height: 100%; overflow: hidden; position: relative; background-color: #eee; border-radius: calc(var(--media-radius) - var(--media-border-width)); } .webcom-media-3d-container img { position: absolute; height: 100%; left: 50%; top: 0; transform: translateX(-50%); } .webcom-media-3d-controls { display: none; position: absolute; bottom: 1rem; right: 1rem; } webcom-media-3d.is-playing:hover .webcom-media-3d-controls { display: block; } @media screen and (max-width: 1000px) { webcom-media-3d.is-playing .webcom-media-3d-controls { display: block; } } .webcom-media-3d-controls > div { background-color: black; color: white; width: 46px; height: 46px; line-height: 46px; text-align: center; border: 1px solid white; padding: 0 0.5rem; cursor: pointer; position: relative; } .webcom-media-3d-controls svg { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) } </style> <style> .image-3d-icon { position: absolute; display: flex !important; justify-content: center; align-items: center; color: white; background-color: rgba(0, 0, 0, 0.75); top: auto !important; left: auto !important; right: 4px !important; bottom: 4px !important; width: 25px !important; height: 25px !important; border-radius: 4px; } .image-3d-icon > svg { width: 13px; height: 13px; } </style> <!-- ************************** script ************************** --> <!-- ************************** script ************************** --> <script> window.customElements.define('webcom-media-3d', class extends HTMLElement { static observedAttributes = ['shown']; $observe = null constructor() { super() const script_uid = "webcom-media-3d-script" const isSdkNotExist = !document.querySelector(`#${script_uid}`) // 注意 triger 组件可能正在加载 sdk // const isFirstMedia = document.querySelectorAll(`webcom-media-3d`).length <= 1 // 注意多个组件可能正在同步加载 sdk if (isSdkNotExist) { const $sdk = document.createElement('script'); $sdk.defer = true $sdk.setAttribute('id', script_uid); $sdk.setAttribute('type', `module`); $sdk.setAttribute('src', `https://static.shoptop.com/npm/3d-model/model-viewer.min.js`); $sdk.onload = (e) => { document.querySelectorAll('webcom-media-3d').forEach(elem => { elem?.observeOnce() }) } $sdk.onerror = (e) => console("webcom-media-3d: sdk load error") document.body.appendChild($sdk) } else { this.observeOnce() } } connectedCallback() { // https://dev-static-shoptop-com.oss-cn-shanghai.aliyuncs.com/WoodHouse.glb // https://dev-static-shoptop-com.oss-cn-shanghai.aliyuncs.com/toy_biplane_idle.usdz this.sources = this.getAttribute('sources') this.poster = this.getAttribute('poster') this.alt = this.getAttribute('alt') } /** * @shown 可以通过 shown 属性外部控制模型的渲染 * @shown 但是需要注意触发的时候有可能 sdk 还没加载好 */ attributeChangedCallback(name, oldValue, newValue) { const isMatch = name === 'shown' && newValue === 'true' isMatch && this.observeOnce() } observeOnce() { const rect = this.getBoundingClientRect() const unexpect = rect.width * rect.height === 0 if (unexpect) this._render() else { this.$observe?.unobserve(this) this.$observe = new IntersectionObserver(entries => { const shown = entries && entries[0]?.isIntersecting; if (!shown && !unexpect) return this._render() this.$observe.unobserve(this) this.$observe = null }); this.$observe.observe(this) } } _render(){ this.poster = this.getAttribute('poster') const shown = this.getAttribute('shown') === 'true' if (!shown) return const isFullScreenAble = document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled || document.msFullscreenEnabled const inner = [ `<div class="webcom-media-3d-container">`, this.poster ? `<img src=${this.poster} alt=${this.alt}></img>` : this._get3DViewer().str, `<div class="webcom-media-3d-controls">`, `<div class="plus"><svg viewBox="0 0 24 24" fill="none"><path d="M4 12H20M12 4V20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>`, `<div class="minus"><svg viewBox="0 0 24 24" fill="none"><path d="M6 12L18 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></div>`, isFullScreenAble ? `<div class="full-screen"><svg viewBox="0 0 32 32" fill="none" stroke="currentcolor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="M4 12 L4 4 12 4 M20 4 L28 4 28 12 M4 20 L4 28 12 28 M28 20 L28 28 20 28" /></svg></div>` : '', `</div>`, `</div>`, ] // 有预览的时候,需要有播放按钮 if (this.poster) { inner.splice(2, 0, [ `<div class="player">`, `<svg viewBox="0 0 1024 1024">`, `<path d="M897.969231 362.653538L591.950769 529.092923c-28.199385 14.729846-45.449846 44.819692-45.449846 78.769231v321.220923c0 34.579692 33.870769 57.580308 62.070154 41.590154l305.939692-166.360616c27.490462-14.729846 45.371077-44.898462 45.371077-78.76923v-320.59077c0-35.209846-33.870769-57.659077-62.070154-42.299077zM431.891692 528.541538L126.109538 362.653538c-28.199385-14.651077-62.070154 6.459077-62.070153 41.668924v322.56c0 33.870769 17.250462 63.960615 45.371077 79.320615l305.939692 165.100308c28.199385 15.36 62.070154-7.640615 62.070154-42.220308V607.153231c0-33.240615-17.329231-63.960615-44.819693-78.769231h-0.630153z m437.799385-240.64c14.729846-7.719385 21.110154-20.48 19.849846-33.319384 1.260308-12.760615-5.750154-25.6-19.849846-33.240616L558.08 58.683077A97.910154 97.910154 0 0 0 512 47.812923a97.910154 97.910154 0 0 0-46.710154 10.870154L152.969846 220.632615a35.209846 35.209846 0 0 0-19.849846 33.240616 35.209846 35.209846 0 0 0 19.219692 33.870769L464.659692 449.772308c13.390769 7.719385 30.089846 10.948923 46.710154 10.948923 16.620308 0 33.240615-3.229538 46.710154-10.948923l311.689846-161.87077z" fill="currentColor" p-id="7457"></path>`, `</svg>`, `</div>` ].join("")) this.innerHTML = inner.join("") const $player = this.querySelector(".player") $player?.addEventListener('click', (e)=>{ this.addEventListener("click",e => e.stopPropagation()) this.addEventListener("pointerdown",e => e.stopPropagation()) this.addEventListener("touchstart",e => e.stopPropagation()) const $viewer = this._get3DViewer().node const $poster = this.querySelector('img') this.querySelector(".webcom-media-3d-container")?.replaceChild($viewer, $poster); this.querySelector(".plus")?.addEventListener('click', ()=> $viewer.zoom(5)) this.querySelector(".minus")?.addEventListener('click', ()=> $viewer.zoom(-5)) this.querySelector(".full-screen")?.addEventListener('click', ()=> { if (document.fullscreenElement) document.exitFullscreen(); else this.requestFullscreen(); }) this.classList.add("is-playing") $player.style['display'] = 'none' }) } // 没有预览就会直接播放 else { this.classList.add("is-playing") } } _get3DViewer(){ const $element = document.createElement('model-viewer') $element.setAttribute("camera-controls", "") $element.setAttribute("touch-action", "pan-y") $element.setAttribute("src", this.sources) $element.setAttribute("alt", this.alt) return { node: $element, str: `<model-viewer camera-controls touch-action=pan-y src=${this.sources} alt=${this.alt}></model-viewer>`, } } _loading(isClear = false){ this.$mask.innerHTML = isClear ? "" : [ "<div class='webcom-media-3d-loadding'>", "<svg fill=currentColor viewBox='0 0 344.339 344.339'>", "<g>", "<path d='M331.957,132.201h-12.214v-24.325c0-7.617-4.095-18.717-11.709-18.717H19.167C11.542,89.159,0,100.259,0,107.876v132.982 c0,7.62,11.542,14.321,19.167,14.321h288.867c7.614,0,11.709-6.701,11.709-14.321v-28.721h12.214c7.626,0,12.382-1.946,12.382-9.56 V146.16C344.339,138.542,339.583,132.201,331.957,132.201z M288.999,146.16v56.418v21.857h-39.14L144.476,119.904h144.523V146.16z' />", "</g>", "</svg>", "</div>", ].join("") } }); </script> <style> [data-type="compact"] .announcement-bar-wrap .swiper-slide{ flex:1; } [data-type="tiling"] .announcement-bar-wrap { flex-direction: column; } .announcement-bar-wrap a { text-decoration: none; } .announcement-division-bottom:after { background-color: rgba(var(--color-foreground)); bottom: 0; content: ""; height: 1px; left: 0; position: absolute; width: 100%; } </style> <div class="xt-section section-announcement-bar" data-section-type="announcement-bar" data-section-id="announcement-bar"> <rdfy-announcement data-type="horizontal"> <div class="swiper announcement-bar-swiper"> <div class="swiper-wrapper announcement-bar-wrap"> <div class="swiper-slide color-none gradient text-center announcement-division-bottom"> <a href="/pages/contact" class="link link--text"> <p class="h5">021-2312-0688</p> </a> </div> <div class="swiper-slide color-options-1 gradient text-center announcement-division-bottom"> <a href="/pages/contact" class="link link--text"> <p class="h5"><span class="__cf_email__" data-cfemail="90a6a7a8a1a9a0a2a8d0f7fdf1f9fcbef3fffd">[email&#160;protected]</span></p> </a> </div> <div class="swiper-slide color-options-4 gradient text-center announcement-division-bottom"> <a href="/pages/contact" class="link link--text"> <p class="h5">Service hours 9:00~17:30</p> </a> </div> </div> </div> </rdfy-announcement> </div> <div class="xt-section section-header" data-section-type="header" data-section-id="header"> <style> header-drawer { justify-self: start; margin-left: -1.2rem; } .header { padding-top: 10px; padding-bottom: 10px; } .section-header { z-index: 3; margin-bottom: 0px; } .scrolled-shrink-logo .header__heading-logo-wrapper { width: 75%; } @media screen and (min-width: 990px) { header-drawer { display: none; } } .menu-drawer-container { display: flex; } .list-menu { list-style: none; padding: 0; margin: 0; } .list-menu--inline { display: inline-flex; flex-wrap: wrap; } .list-menu__item { display: flex; align-items: center; line-height: calc(1 + 0.3 / var(--font-base-scale)); } .list-menu__item--link { text-decoration: none; padding-bottom: 1rem; padding-top: 1rem; line-height: calc(1 + 0.8 / var(--font-base-scale)); } @media screen and (min-width: 750px) { .section-header { margin-bottom: 0px; } .list-menu__item--link { padding-bottom: 0.5rem; padding-top: 0.5rem; } } @media screen and (min-width: 990px) { .header { padding-top: 20px; padding-bottom: 20px; } } </style> <!-- 超级菜单 --> <style> .mega-menu { position: static; } .mega-menu__content { background-color: rgb(var(--color-background)); border-left: 0; border-radius: 0; border-right: 0; left: 0; overflow-y: auto; padding-bottom: 2.4rem; padding-top: 2.4rem; position: absolute; right: 0; top: 100%; } .mega-menu__link { color: rgba(var(--color-foreground), .75); } .mega-menu__list { display: grid; gap: 2.4rem 4rem; grid-template-columns: repeat(6, minmax(0, 1fr)); list-style: none; } </style> <!-- 下拉菜单类型导航 --> <style> .list-menu--right { right: 0; } .list-menu--disclosure { position: absolute; min-width: 100%; width: 20rem; border: 1px solid rgba(var(--color-foreground), 0.2); } .list-menu--disclosure:focus { outline: none; } .list-menu__item--active { text-decoration: underline; text-underline-offset: 0.3rem; } .list-menu__item--active:hover { text-decoration-thickness: 0.2rem; } .list-menu--disclosure.localization-selector { max-height: 18rem; overflow: auto; width: 10rem; padding: 0.5rem; } .list-menu--disclosure { position: absolute; min-width: 100%; width: 20rem; border: 1px solid rgba(var(--color-foreground), 0.2); } </style> <!-- 抽屉 --> <style> .header__icon--menu { position: initial; } menu-drawer > details > summary::before, menu-drawer > details[open]:not(.menu-opening) > summary::before { content: ''; position: absolute; cursor: default; width: 100%; height: calc(100vh - 100%); height: calc( var(--viewport-height, 100vh) - (var(--header-bottom-position, 100%))); top: 100%; left: 0; background: rgba(var(--color-foreground), 0.5); opacity: 0; visibility: hidden; z-index: 2; transition: opacity 0s, visibility 0s; } menu-drawer > details[open] > summary::before { visibility: visible; opacity: 1; transition: opacity var(--duration-default) ease, visibility var(--duration-default) ease; } .menu-drawer { position: absolute; transform: translateX(-100%); visibility: hidden; z-index: 3; left: 0; top: 100%; width: calc(100vw - 4rem); padding: 0; border-width: 0 var(--drawer-border-width) 0 0; background-color: rgb(var(--color-background)); overflow-x: hidden; border-style: solid; border-color: rgba(var(--color-foreground), var(--drawer-border-opacity)); filter: drop-shadow( var(--drawer-shadow-horizontal-offset) var(--drawer-shadow-vertical-offset) var(--drawer-shadow-blur-radius) rgba(var(--color-shadow), var(--drawer-shadow-opacity)) ); } [dir="rtl"] .menu-drawer { border-width: 0 0 0 var(--drawer-border-width); transform: translateX(0); } .menu-drawer { height: calc(100vh - 100%); height: calc( var(--viewport-height, 100vh) - (var(--header-bottom-position, 100%)) ); } details[open] > .menu-drawer, details[open] > .menu-drawer__submenu { transition: transform var(--duration-default) ease, visibility var(--duration-default) ease; } details[open].menu-opening > .menu-drawer, details[open].menu-opening > .menu-drawer__submenu { transform: translateX(0); visibility: visible; } .menu-drawer__navigation .submenu-open { visibility: hidden; /* hide menus from screen readers when hidden by submenu */ } @media screen and (min-width: 750px) { .menu-drawer { width: 40rem; } } .menu-drawer__inner-container { position: relative; height: 100%; } .menu-drawer__navigation-container { display: grid; grid-template-rows: 1fr auto; align-content: space-between; overflow-y: auto; height: 100%; } .menu-drawer__navigation { padding: 5.6rem 0; } .menu-drawer__inner-submenu { height: 100%; overflow-x: hidden; overflow-y: auto; } .menu-drawer__menu li { margin-bottom: 0.2rem; } .menu-drawer__menu-item { padding: 1.1rem 3.2rem; text-decoration: none; font-size: 1.8rem; } .menu-drawer summary.menu-drawer__menu-item { padding-right: 5.2rem; } .menu-drawer__menu-item--active, .menu-drawer__menu-item:focus, .menu-drawer__close-button:focus, .menu-drawer__menu-item:hover, .menu-drawer__close-button:hover { color: rgb(var(--color-foreground)); background-color: rgba(var(--color-foreground), 0.04); } .menu-drawer__menu-item--active:hover { background-color: rgba(var(--color-foreground), 0.08); } .menu-drawer__menu-item .icon-caret { display: none; } .menu-drawer__menu-item > .icon-arrow { position: absolute; right: 2.5rem; top: 50%; transform: translateY(-50%); } .menu-drawer__submenu { position: absolute; top: 0; width: 100%; bottom: 0; left: 0; background-color: rgb(var(--color-background)); border-left: 0.1rem solid rgba(var(--color-foreground), 0.2); z-index: 1; transform: translateX(100%); visibility: hidden; } .menu-drawer__submenu .menu-drawer__submenu { overflow-y: auto; } .menu-drawer__close-button { margin-top: 1.5rem; padding: 1.2rem 2.6rem; text-decoration: none; display: flex; align-items: center; font-size: 1.4rem; width: 100%; background-color: transparent; font-family: var(--font-body-family); font-style: var(--font-body-style); text-align: left; } .no-js .menu-drawer__close-button { display: none; } .menu-drawer__close-button .icon-arrow { transform: rotate(180deg); margin-right: 1rem; } .menu-drawer__utility-links { padding: 2rem; background-color: rgba(var(--color-foreground), 0.03); position: relative; } .menu-drawer__account { display: inline-flex; align-items: center; text-decoration: none; padding: 1.2rem; font-size: 1.4rem; color: rgb(var(--color-foreground)); } .menu-drawer__utility-links:has(ul:empty) .menu-drawer__account, .menu-drawer__utility-links:has(.menu-drawer__localization) .menu-drawer__account { margin-bottom: 0; } @media screen and (min-width: 750px) { .menu-drawer__utility-links:has(ul:nth-child(2):empty) { display: none; } } .menu-drawer__account .icon-account { height: 2rem; width: 2rem; margin-right: 1rem; } .menu-drawer__account:hover .icon-account { transform: scale(1.07); } .menu-drawer .list-social { justify-content: flex-start; } .menu-drawer .list-social:empty { display: none; } .menu-drawer .list-social__link { padding: 1.3rem 1.25rem; } </style> <!-- 搜索框 --> <style> @media screen and (min-width: 750px) { .predictive-search { border-top: none; width: calc(100% + 0.2rem); } .header header-search-result { position: relative; } } .predictive-search { position: absolute; width: 100%; top: calc(100% + 0.1rem); left: -0.1rem; border-width: var(--popup-border-width); border-style: solid; border-color: rgba(var(--color-foreground), var(--popup-border-opacity)); background-color: rgb(var(--color-background)); z-index: 3; border-bottom-right-radius: var(--popup-corner-radius); border-bottom-left-radius: var(--popup-corner-radius); box-shadow: var(--popup-shadow-horizontal-offset) var(--popup-shadow-vertical-offset) var(--popup-shadow-blur-radius) rgba(var(--color-shadow), var(--popup-shadow-opacity)); overflow-y: auto; -webkit-overflow-scrolling: touch; } .predictive-search ul,.predictive-search li { margin: 0; padding: 0; list-style: none; } .predictive-search__item { padding: 1rem 2rem; text-align: left; text-decoration: none; width: 100%; display: grid; grid-template-columns: 5rem 1fr; grid-column-gap: 2rem; grid-template-areas: "product-image product-content"; } .predictive-search__item:hover { color: rgb(var(--color-foreground)); background-color: rgba(var(--color-foreground),.04); } .predictive-search__image { grid-area: product-image; object-fit: contain; font-family: "object-fit: contain"; } .predictive-search__content { grid-area: product-content; display: flex; flex-direction: column; justify-content: center; } .predictive-search__btn { display: flex; text-align: left; text-decoration: none; width: 100%; justify-content: space-between; align-items: center; padding: 1.3rem 2rem; word-break: break-all; line-height: calc(1 + .4 / var(--font-base-scale)); } .predictive-search ul { border-bottom: .1rem solid rgba(var(--color-foreground),.08); padding-bottom: 1rem; } .predictive-search__price{ color: rgba(var(--color-foreground),.5); font-size: 1.2rem; display: inline-block; margin: 0 1rem 0 0; line-height: calc(1 + .5 / var(--font-base-scale)) } .predictive-search__origin-price{ text-decoration: line-through; color: rgba(var(--color-foreground),.75); font-size: 1.3rem; line-height: calc(1 + .5 / var(--font-base-scale)) } @media screen and (min-width: 750px) { .predictive-search__btn { padding-top: 1rem; padding-bottom: 1rem; } } </style> <svg xmlns="http://www.w3.org/2000/svg" class="hidden"> <symbol id="icon-search" viewbox="0 0 18 19" fill="none"> <path fill-rule="evenodd" clip-rule="evenodd" d="M11.03 11.68A5.784 5.784 0 112.85 3.5a5.784 5.784 0 018.18 8.18zm.26 1.12a6.78 6.78 0 11.72-.7l5.4 5.4a.5.5 0 11-.71.7l-5.41-5.4z" fill="currentColor" /> </symbol> <symbol id="icon-reset" class="icon icon-close" fill="none" viewBox="0 0 18 18" stroke="currentColor"> <circle r="8.5" cy="9" cx="9" stroke-opacity="0.2" /> <path d="M6.82972 6.82915L1.17193 1.17097" stroke-linecap="round" stroke-linejoin="round" transform="translate(5 5)" /> <path d="M1.22896 6.88502L6.77288 1.11523" stroke-linecap="round" stroke-linejoin="round" transform="translate(5 5)" /> </symbol> <symbol id="icon-close" class="icon icon-close" fill="none" viewBox="0 0 18 17"> <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"> </symbol> </svg> <sticky-header data-sticky-type=reduce-logo-size class="sticky_index-color header-wrapper color-none gradient header-wrapper--border-bottom"> <header class="header header--middle-left header--mobile-center page-width header--has-menu"> <!-- 移动端导航 抽屉导航 --> <header-drawer data-breakpoint="tablet"> <details id="Details-menu-drawer-container" class="menu-drawer-container"> <summary class="header__icon header__icon--menu header__icon--summary link focus-inset" aria-label="Menu"> <span> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" class="icon icon-hamburger" fill="none" viewBox="0 0 18 16"> <path d="M1 .5a.5.5 0 100 1h15.71a.5.5 0 000-1H1zM.5 8a.5.5 0 01.5-.5h15.71a.5.5 0 010 1H1A.5.5 0 01.5 8zm0 7a.5.5 0 01.5-.5h15.71a.5.5 0 010 1H1a.5.5 0 01-.5-.5z" fill="currentColor"> </svg> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" class="icon icon-close" fill="none" viewBox="0 0 18 17" > <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"> </svg> </span> </summary> <div id="menu-drawer" class="gradient menu-drawer motion-reduce" tabindex="-1"> <div class="menu-drawer__inner-container"> <div class="menu-drawer__navigation-container"> <nav class="menu-drawer__navigation"> <ul class="menu-drawer__menu has-submenu list-menu" role="list"> <li> <a href="/" class="menu-drawer__menu-item list-menu__item link link--text focus-inset header-menu-levels-1"> Home </a> </li> <li> <a href="/pages/about-us" class="menu-drawer__menu-item list-menu__item link link--text focus-inset header-menu-levels-1"> Who We Are </a> </li> <li> <details id="Details-menu-drawer-menu-item-2"> <summary class="menu-drawer__menu-item list-menu__item link link--text focus-inset header-menu-levels-1"> What We Do <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </svg> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </summary> <div id="link-{{ link.handle | escape }}" class="menu-drawer__submenu has-submenu gradient motion-reduce" tabindex="-1"> <div class="menu-drawer__inner-submenu"> <button class="menu-drawer__close-button link link--text focus-inset" aria-expanded="true"> <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </svg> What We Do </button> <ul class="menu-drawer__menu list-menu" role="list" tabindex="-1"> <li> <details id="Details-menu-drawer-submenu-0"> <summary class="menu-drawer__menu-item link link--text list-menu__item focus-inset"> Our Products <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </svg> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </summary> <div id="childlink-{{ childlink.handle | escape }}" class="menu-drawer__submenu has-submenu gradient motion-reduce"> <button class="menu-drawer__close-button link link--text focus-inset" aria-expanded="true"> <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </svg> Our Products </button> <ul class="menu-drawer__menu list-menu" role="list" tabindex="-1"> <li> <a href="javascript:;" class="menu-drawer__menu-item link link--text list-menu__item focus-inset"> ALL PRODUCTS </a> </li> <li> <a href="/collections/engine" class="menu-drawer__menu-item link link--text list-menu__item focus-inset"> ENGINE </a> </li> <li> <a href="/collections/generator-set" class="menu-drawer__menu-item link link--text list-menu__item focus-inset"> ENGINE SET </a> </li> <li> <a href="/collections/engine-components" class="menu-drawer__menu-item link link--text list-menu__item focus-inset"> ENGINE COMPONENTS </a> </li> <li> <a href="/collections/system-products" class="menu-drawer__menu-item link link--text list-menu__item focus-inset"> SYSTEM PRODUCTS </a> </li> </ul> </div> </details> </li> <li> <details id="Details-menu-drawer-submenu-1"> <summary class="menu-drawer__menu-item link link--text list-menu__item focus-inset"> Service Area <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </svg> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </summary> <div id="childlink-{{ childlink.handle | escape }}" class="menu-drawer__submenu has-submenu gradient motion-reduce"> <button class="menu-drawer__close-button link link--text focus-inset" aria-expanded="true"> <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </svg> Service Area </button> <ul class="menu-drawer__menu list-menu" role="list" tabindex="-1"> <li> <a href="/collections/agriculture" class="menu-drawer__menu-item link link--text list-menu__item focus-inset"> Agriculture Area </a> </li> <li> <a href="/collections/mining-area" class="menu-drawer__menu-item link link--text list-menu__item focus-inset"> Mining Area </a> </li> <li> <a href="/collections/road-construction-area" class="menu-drawer__menu-item link link--text list-menu__item focus-inset"> Road Construction Area </a> </li> <li> <a href="/collections/shipping-area" class="menu-drawer__menu-item link link--text list-menu__item focus-inset"> Shipping Area </a> </li> </ul> </div> </details> </li> </ul> </div> </div> </details> </li> <li> <a href="/blogs/news" class="menu-drawer__menu-item list-menu__item link link--text focus-inset header-menu-levels-1"> News </a> </li> <li> <a href="/pages/contact" class="menu-drawer__menu-item list-menu__item link link--text focus-inset header-menu-levels-1"> Contact </a> </li> </ul> </nav> <div class="menu-drawer__utility-links flex flex-col"> <a href="/account/login" class="menu-drawer__account link focus-inset h5 medium-hide large-up-hide"> Login </a> <a href="/account/register" class="menu-drawer__account link focus-inset h5 medium-hide large-up-hide"> Register </a> <div class="menu-drawer__localization header__localization large-up-hide link--text"> <div class="plugin__localization-translate mt-8"></div> </div> </div> </div> </div> </div> </details> </header-drawer> <!-- 搜索 --> <!-- LOGO --> <h1 class="header__heading"> <a href="/" class="header__heading-link link link--text focus-inset"> <div class="header__heading-logo-wrapper"> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="MechHub" class="header__heading-logo motion-reduce h-auto lazyload" style="max-height: 30.666666666666664px;" width="240" height="30.666666666666664" data-sizes="auto" itemprop="logo" data-src="https://img.staticxt.com/1800410653875466242.png?x-oss-process=style/{width}x" /> </div> </a> </h1> <!-- 导航 --> <nav class="header__inline-menu"> <ul class="list-menu list-menu--inline" role="list"> <li> <a href="/" class="header__menu-item list-menu__item link link--text focus-inset header-menu-levels-1"> <span>Home</span> </a> </li> <li> <a href="/pages/about-us" class="header__menu-item list-menu__item link link--text focus-inset header-menu-levels-1"> <span>Who We Are</span> </a> </li> <li> <header-menu> <details id="Details-HeaderMenu-2"> <summary class="header__menu-item list-menu__item link focus-inset header-menu-levels-1"> <span>What We Do</span> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </summary> <ul class="header__submenu list-menu list-menu--disclosure gradient caption-large motion-reduce global-settings-popup" role="list" tabindex="-1"> <li> <details id="Details-HeaderSubMenu-0"> <summary class="header__menu-item link link--text list-menu__item focus-inset caption-large"> <span>Our Products</span> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </summary> <ul class="header__submenu list-menu motion-reduce"> <li> <a href="javascript:;" class="header__menu-item list-menu__item link link--text focus-inset caption-large"> ALL PRODUCTS </a> </li> <li> <a href="/collections/engine" class="header__menu-item list-menu__item link link--text focus-inset caption-large"> ENGINE </a> </li> <li> <a href="/collections/generator-set" class="header__menu-item list-menu__item link link--text focus-inset caption-large"> ENGINE SET </a> </li> <li> <a href="/collections/engine-components" class="header__menu-item list-menu__item link link--text focus-inset caption-large"> ENGINE COMPONENTS </a> </li> <li> <a href="/collections/system-products" class="header__menu-item list-menu__item link link--text focus-inset caption-large"> SYSTEM PRODUCTS </a> </li> </ul> </details> </li> <li> <details id="Details-HeaderSubMenu-1"> <summary class="header__menu-item link link--text list-menu__item focus-inset caption-large"> <span>Service Area</span> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </summary> <ul class="header__submenu list-menu motion-reduce"> <li> <a href="/collections/agriculture" class="header__menu-item list-menu__item link link--text focus-inset caption-large"> Agriculture Area </a> </li> <li> <a href="/collections/mining-area" class="header__menu-item list-menu__item link link--text focus-inset caption-large"> Mining Area </a> </li> <li> <a href="/collections/road-construction-area" class="header__menu-item list-menu__item link link--text focus-inset caption-large"> Road Construction Area </a> </li> <li> <a href="/collections/shipping-area" class="header__menu-item list-menu__item link link--text focus-inset caption-large"> Shipping Area </a> </li> </ul> </details> </li> </ul> </details> </header-menu> </li> <li> <a href="/blogs/news" class="header__menu-item list-menu__item link link--text focus-inset header-menu-levels-1"> <span>News</span> </a> </li> <li> <a href="/pages/contact" class="header__menu-item list-menu__item link link--text focus-inset header-menu-levels-1"> <span>Contact</span> </a> </li> </ul> </nav> <!-- logo --> <div class="header__icons"> <div class="desktop-localization-wrapper flex items-center"> <div class="menu-drawer__localization header__localization hidden md:flex"> <div class="plugin__localization-translate-header"></div> </div> </div> <details-modal class="header__search"> <details> <summary class="header__icon header__icon--search header__icon--summary link focus-inset modal__toggle" aria-haspopup="dialog" aria-label=""> <span> <svg class="modal__toggle-open icon icon-search" aria-hidden="true" focusable="false"> <use href="#icon-search"> </svg> <svg class="modal__toggle-close icon icon-close" aria-hidden="true" focusable="false"> <use href="#icon-close"> </svg> </span> </summary> <div class="search-modal modal__content gradient" role="dialog" aria-modal="true" aria-label="Search"> <div class="modal-overlay"></div> <div class="search-modal__content" tabindex="-1"> <header-search-result class="search-modal__form" data-loading-text="loading"> <form action="/search" method="get" role="search" class="search search-modal__form"> <div class="field"> <input class="search__input field__input" id="Search-In-Modal" type="search" name="q" value="" placeholder="Search" role="combobox" aria-expanded="false" aria-owns="predictive-search-results" aria-controls="predictive-search-results" aria-haspopup="listbox" aria-autocomplete="list" autocorrect="off" autocomplete="off" autocapitalize="off" spellcheck="false" > <label class="field__label" for="Search-In-Modal">Search</label> <button type="reset" class="reset__button field__button flex hidden" aria-label="Search"> <svg class="icon icon-close" aria-hidden="true" focusable="false"> <use xlink:href="#icon-reset"> </svg> </button> <button class="search__button field__button flex" aria-label="Search"> <svg class="icon icon-search" aria-hidden="true" focusable="false"> <use href="#icon-search"> </svg> </button> </div> <div class="predictive-search" tabindex="-1"></div> </form> </header-search-result> <button type="button" class="search-modal__close-button modal__close-button link link--text focus-inset" aria-label="close"> <svg class="icon icon-close" aria-hidden="true" focusable="false"> <use href="#icon-close"> </svg> </button> </div> </div> </details> </details-modal> <a href="/account/login" class="header__icon header__icon--account link focus-inset small-hide"> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" class="icon icon-account" fill="none" viewBox="0 0 18 19"> <path fill-rule="evenodd" clip-rule="evenodd" d="M6 4.5a3 3 0 116 0 3 3 0 01-6 0zm3-4a4 4 0 100 8 4 4 0 000-8zm5.58 12.15c1.12.82 1.83 2.24 1.91 4.85H1.51c.08-2.6.79-4.03 1.9-4.85C4.66 11.75 6.5 11.5 9 11.5s4.35.26 5.58 1.15zM9 10.5c-2.5 0-4.65.24-6.17 1.35C1.27 12.98.5 14.93.5 18v.5h17V18c0-3.07-.77-5.02-2.33-6.15-1.52-1.1-3.67-1.35-6.17-1.35z" fill="currentColor"> </svg> <span class="visually-hidden">Login</span> </a> <a href="javascript:;" class="header__icon header__icon--cart link focus-inset" id="cart-icon-bubble"> <svg class="icon icon-cart" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" fill="none"> <path d="m15.75 11.8h-3.16l-.77 11.6a5 5 0 0 0 4.99 5.34h7.38a5 5 0 0 0 4.99-5.33l-.78-11.61zm0 1h-2.22l-.71 10.67a4 4 0 0 0 3.99 4.27h7.38a4 4 0 0 0 4-4.27l-.72-10.67h-2.22v.63a4.75 4.75 0 1 1 -9.5 0zm8.5 0h-7.5v.63a3.75 3.75 0 1 0 7.5 0z" fill="currentColor" fill-rule="evenodd"></path> </svg> <span class="visually-hidden">Shopping Cart</span> <div class="cart-count-bubble cart-count-hidden"> <span aria-hidden="true" id="cartCount"></span> <span class="visually-hidden">Item</span> </div> </a> </div> </header> </sticky-header data-sticky-type=reduce-logo-size> <cart-notification class="cart-notification-info"></cart-notification> <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script id="cart-notice-art-tpl" type="text/html"> <div class="cart-notification-wrapper page-width"> <div class="cart-notification gradient" id="cart-notification"> <div class="cart-notification__header"> <h2 class="cart-notification__heading caption-large text-body"> <svg class="icon icon-checkmark" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 9" fill="none" > <path fill-rule="evenodd" clip-rule="evenodd" d="M11.35.643a.5.5 0 01.006.707l-6.77 6.886a.5.5 0 01-.719-.006L.638 4.845a.5.5 0 11.724-.69l2.872 3.011 6.41-6.517a.5.5 0 01.707-.006h-.001z" fill="currentColor"/> </svg> Item </h2> <button type="button" class="cart-notification__close modal__close-button link link--text focus-inset"> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" class="icon icon-close" fill="none" viewBox="0 0 18 17" > <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"> </svg> </button> </div> {{if cartItems}} <div class="cart-notification-product"> <div class="cart-notification-product__image g-card-media"> <img width="70" height="70" class="lazyload" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="{{formatImageSrc(cartItems.image,'srcUrl')}}" /> </div> <div> <h3 class="cart-notification-product__name h4">{{cartItems.productTitle}}</h3> <dl> {{each cartItems.options option}} <div class="product-option"> <dt>{{option.specName}}:</dt> <dd>{{option.specValue}}</dd> </div> {{/each}} </dl> </div> </div> {{/if }} <div class="cart-notification__links"> <a href="/cart" class="button button--secondary button--full-width"> View Cart {{ if cartCount != 0}} ({{cartCount}}) {{ /if }} </a> <cart-checkout> <button class="button button--primary button--full-width" name="checkout">Checkout</button> </cart-checkout> </div> </div> </div> </script> <script id="search-product-art-tpl" type="text/html"> {{if products.length }} <ul> {{each products product index}} {{set isShowOriginPrice = product.compareAtPrice > product.price }} {{set from_on = product.priceMax != product.priceMin}} {{ set show_price = false }} <li class=""> <a href="{{ $imports.formatProductUrl(product.handle) }}" class="predictive-search__item predictive-search__item--link-with-thumbnail link link--text" tabindex="-1"> <img class="predictive-search__image lazyload" data-src="{{$imports.formatFileImageUrl(product.goodsImage.url, 180)}}" alt="{{ product.goodsImage.alt || product.goodsTitle }}" width="50" height="50"> <div class="predictive-search__content"> <p class="predictive-search__title h5">{{product.goodsTitle}}</p> {{if show_price}} <div class="predictive-search__price"> {{if from_on}} <span class="text-base">from</span> {{/if}} <span class="money predictive-search__price money">{{$imports.moneyWithSymbol(product.price)}}</span> {{if isShowOriginPrice}} <del class="money predictive-search__origin-price money">{{$imports.moneyWithSymbol(product.compareAtPrice)}}</del> {{/if}} </div> {{/if}} </div> </a> </li> {{/each}} </ul> {{/if}} <div class="predictive-search__search-page"> <a class="predictive-search__btn link link--text" tabindex="-1" role="option" aria-selected="false"> <span data-search-text="">Search for “{{keywords}}”</span> <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </path> </svg> </a> </div> </script> <script type="application/ld+json"> { "@context": "http://schema.org", "@type": "Organization", "name": "MechHub", "logo": "https://img.staticxt.com/1800410653875466242.png?x-oss-process=style/540x", "sameAs": [ "111", "111", "111", "", "111", "111", "", "", "111", "", "" ], "url": "http://mechhub.ishoptop.com" } </script> <script type="application/ld+json"> { "@context": "http://schema.org", "@type": "WebSite", "name": "MechHub", "potentialAction": { "@type": "SearchAction", "target": "http://mechhub.ishoptop.com/search?q={search_term_string}", "query-input": "required name=search_term_string" }, "url": "http://mechhub.ishoptop.com" } </script> </div> <main id="main-content"> <div class="xt-section section-1718083647203432" data-section-type="slideshow" data-section-id="1718083647203432"> <style> .section-1718083647203432 { --section-m-margin-top: 0px; --section-margin-top: 0px; } .section-1718083647203432 .slideshow--adapt_image .slideshow__media:before { padding-bottom: 37.5%; content: ''; display: block; } @media screen and (max-width: 749px) { } </style> <slideshow-component data-section-id="1718083647203432" data-delay="7000" data-autoplay="true" aria-label=""> <div class=""> <div class="swiper slideshow-wrap slideshow-1718083647203432" style="box-sizing: border-box;"> <div class="swiper-wrapper slideshow--adapt_image slideshow--bottom"> <div class="swiper-slide"> <div class="slideshow__media banner__media media animate--none"> <img class="slideshow-object-center lazyload" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="https://img.staticxt.com/1800803102456033281.jpg?x-oss-process=style/{width}x" alt=""> <a href="/pages/about-us" class="slideshow__image-link"></a> </div> </div> <div class="swiper-slide"> <div class="slideshow__media banner__media media animate--none"> <img class="slideshow-object-center lazyload" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="https://img.staticxt.com/1801139207537700866.jpg?x-oss-process=style/{width}x" alt=""> <a href="/collections/all-products" class="slideshow__image-link"></a> </div> </div> <div class="swiper-slide"> <div class="slideshow__media banner__media media animate--none"> <img class="slideshow-object-center lazyload" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="https://img.staticxt.com/1800803102439469057.jpg?x-oss-process=style/{width}x" alt=""> <a href="/pages/contact" class="slideshow__image-link"></a> </div> </div> </div> </div> </div> </slideshow-component> </div> <div class="xt-section section-1718072981826420" data-section-type="rich-text" data-section-id="1718072981826420"> <style> .section-1718072981826420 { --section-m-margin-top: 0px; --section-margin-top: 0px; } .section-1718072981826420 .rich-text-container{ padding-top:36px; padding-bottom:64px; display: flex; justify-content: flex-start ; } .rich-text-content{ width: 100%; display: flex; flex-wrap: wrap; } .rich-text-content--narrow { width: 78%; } .rich-text-content h2,.rich-text-content p{ margin-top: 0; margin-bottom: 0; } .rich-text-content-item{ width: 100%; } .rich-text-item-text,.rich-text-item-buttons,.rich-text-item-subtitle{ padding-top: 20px; } .rich-text-btn-box { display: inline-flex; flex-wrap: wrap; gap: 1rem; width: 100%; max-width: 45rem; word-break: break-word; } .rich-text-btn-box--multiple>* { flex-grow: 1; min-width: 22rem; } @media screen and (max-width: 749px) { .section-1718072981826420 .rich-text-container{ padding-top:18px; padding-bottom:32px; } .rich-text-content{ width: 100%; padding: 0 15px; display: flex; flex-wrap: wrap; } .rich-text-btn-box .button{ width: 100%; } } </style> <div class="rich-text-1718072981826420 color-options-2 gradient g-card-content-y"> <div class="rich-text-container page-width"> <div class="rich-text-content text-left"> <div class="rich-text-content-item rich-text-item-subtitle"> <div class="uppercase caption-with-letter-spacing--medium">Introduction</div> </div> <div class="rich-text-content-item rich-text-item-text"> <div><p>MechHub is a leading brand in the industry, specializing in the manufacturing and distribution of large-scale industrial and agricultural equipment, as well as power generation machinery. With a commitment to innovation and quality, MechHub has established itself as a reliable partner for businesses seeking robust and efficient solutions.</p></div> </div> <div class="rich-text-content-item rich-text-item-text"> <div><p>We are committed to providing our customers with complete product and service solutions to achieve a cleaner, better and longer future.</p></div> </div> <div class="rich-text-content-item rich-text-item-buttons"> <div class="rich-text-btn-box relative z-1 justify-left "> <a role="link" aria-disabled="false" href=/pages/about-us class="button button--">MORE ABOUT</a> </div> </div> </div> </div> </div> </div> <div class="xt-section section-1718160326438356" data-section-type="collection-list" data-section-id="1718160326438356"> <style> .section-1718160326438356 { --section-m-margin-top: 0px; --section-margin-top: 0px; } .collection-list-1718160326438356 .color-none{ background: none; } .collection-list-1718160326438356 .collection_list_container{ padding-top:64px; padding-bottom:24px; } .collection_list_title{ margin: 0 0 30px 0; } .collection_list_container .swiper{ overflow: unset; } .collection_list_item_wrap,.collection_list_item_wrap.no_collection_wrap{ position: relative; width: 100%; height: auto; } .no_collection_wrap{ height: 0; padding-bottom: calc(100% - var(--collection-card-border-width) * 2); position: relative; } .collection_list_item_wrap.no_collection_wrap_card{ height: 100%; border-radius: calc(var(--collection-card-corner-radius) - var(--collection-card-border-width)); } .no_collection_Box{ position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; align-items: center; box-sizing: border-box; } .collection_list_item_box{ padding:17px 10px; } .collection_list_item_box::after{ bottom: 0; content: ""; left: 0; position: absolute; right: 0; top: 0; z-index: 1; } .collection_list_item_img{ position: absolute; width: calc(100% - var(--collection-card-image-padding)*2); height: calc(100% - var(--collection-card-image-padding)*2); margin:var(--collection-card-image-padding); box-sizing: border-box; overflow: hidden; } .collection_list_item_img.collection_list_item_img_adapt{ position: relative; } .collection_list_item_img_box{ width: 100%; overflow: hidden; } .collection_list_item_img_adapt{ display: flex; } .collection_list_img_adapt{ width: 100%; } .collection_list_item_img_portrait{ padding-bottom: 125%; position: relative; } .collection_list_item_img_square{ padding-bottom: 100%; position: relative; } .collection_list_img_portrait{ width: 100%; height: 100%; position: absolute; left: 0; top: 0; } .collection_list_img_square{ width: 100%; height: 100%; } .collection_list_img{ transition: transform var(--duration-long) ease; transform: scale(1); } .collection_list_item:hover .collection_list_img{ transform: scale(1.03); } .collection_list-pagination{ display: none; } .collection-slider-button--prev .icon { transform: rotate(90deg); } .collection-slider-button--next .icon { transform: rotate(-90deg); } .slider-button[disabled] .icon { color: rgba(var(--color-foreground),.3); cursor: not-allowed; } .collection_list_item_border{ box-sizing: border-box; border-radius: var(--collection-card-corner-radius); border: var(--collection-card-border-width) solid rgba(var(--color-foreground),var(--collection-card-border-opacity)); box-shadow: var(--collection-card-shadow-horizontal-offset) var(--collection-card-shadow-vertical-offset) var(--collection-card-shadow-blur-radius) rgba(var(--color-shadow), var(--collection-card-shadow-opacity)); } .collection_list_radius{ border-radius: calc(var(--collection-card-corner-radius) - var(--collection-card-border-width)); } .collection_list_img_top_radius{ border-top-left-radius:calc(var(--collection-card-corner-radius) - var(--collection-card-border-width) - var(--collection-card-image-padding)); border-top-right-radius:calc(var(--collection-card-corner-radius) - var(--collection-card-border-width) - var(--collection-card-image-padding)); } .collection_list_img_radius{ border-radius: calc(var(--collection-card-corner-radius) - var(--collection-card-border-width) - var(--collection-card-image-padding)); } @media screen and (max-width: 749px) { .collection-list-1718160326438356 .collection_list_container{ padding-top:32px; padding-bottom:12px; overflow-x: hidden; } .collection-list-1718160326438356 .collection_list-pagination{ display: flex; align-items: center; justify-content: center; } .collection_list_true{ flex-wrap: nowrap; column-gap: 0; row-gap: 0; } } </style> <div class="collection-list-1718160326438356 color-none gradient"> <div class="collection_list_container page-width"> <h2 class="collection_list_title h1">WE SUPPLY</h2> <main-collection-list-container swiper="true" column="1"> <div class="swiper collection_list_swiper"> <ul class="collection_list_true collection_list swiper-wrapper grid product-grid list-unstyled grid-cols--1 md:grid-cols--4"> <li class="collection_list_item_true swiper-slide grid__item"> <div class=""> <div class="collection_list_item_wrap collection_list_radius " style="height:100%;"> <div class="collection_list_item_img_box collection_list_item_border collection_list_item_img_box_adapt gradient color-options-1"> <div class="collection_list_item_img collection_list_item_img_adapt shape--default "> <div class="relative w-full" style="padding-bottom:65.63%"> <img class="object-cover absolute left-0 top-0 w-full h-full lazyload collection_list_img collection_list_img_adapt collection_list_img_radius" alt="ENGINE" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-sizes="auto" data-src="https://img.staticxt.com/1800814628751765507.jpg?x-oss-process=style/{width}x"> </div> </div> </div> <a href=/collections/engine class="full-unstyled-link collection_list_item_box "> <p style="margin:0;text-align: var(--collection-card-text-alignment);width:100%;"> ENGINE <span class="icon-wrap"> <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"></path> </svg> </span> </p> </a> </div> </div> </li> <li class="collection_list_item_true swiper-slide grid__item"> <div class=""> <div class="collection_list_item_wrap collection_list_radius " style="height:100%;"> <div class="collection_list_item_img_box collection_list_item_border collection_list_item_img_box_adapt gradient color-options-1"> <div class="collection_list_item_img collection_list_item_img_adapt shape--default "> <div class="relative w-full" style="padding-bottom:65.63%"> <img class="object-cover absolute left-0 top-0 w-full h-full lazyload collection_list_img collection_list_img_adapt collection_list_img_radius" alt="ENGINE SET" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-sizes="auto" data-src="https://img.staticxt.com/1800814628751765506.jpg?x-oss-process=style/{width}x"> </div> </div> </div> <a href=/collections/generator-set class="full-unstyled-link collection_list_item_box "> <p style="margin:0;text-align: var(--collection-card-text-alignment);width:100%;"> ENGINE SET <span class="icon-wrap"> <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"></path> </svg> </span> </p> </a> </div> </div> </li> <li class="collection_list_item_true swiper-slide grid__item"> <div class=""> <div class="collection_list_item_wrap collection_list_radius " style="height:100%;"> <div class="collection_list_item_img_box collection_list_item_border collection_list_item_img_box_adapt gradient color-options-1"> <div class="collection_list_item_img collection_list_item_img_adapt shape--default "> <div class="relative w-full" style="padding-bottom:65.63%"> <img class="object-cover absolute left-0 top-0 w-full h-full lazyload collection_list_img collection_list_img_adapt collection_list_img_radius" alt="ENGINE COMPONENTS" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-sizes="auto" data-src="https://img.staticxt.com/1800822256395366402.jpg?x-oss-process=style/{width}x"> </div> </div> </div> <a href=/collections/engine-components class="full-unstyled-link collection_list_item_box "> <p style="margin:0;text-align: var(--collection-card-text-alignment);width:100%;"> ENGINE COMPONENTS <span class="icon-wrap"> <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"></path> </svg> </span> </p> </a> </div> </div> </li> <li class="collection_list_item_true swiper-slide grid__item"> <div class=""> <div class="collection_list_item_wrap collection_list_radius " style="height:100%;"> <div class="collection_list_item_img_box collection_list_item_border collection_list_item_img_box_adapt gradient color-options-1"> <div class="collection_list_item_img collection_list_item_img_adapt shape--default "> <div class="relative w-full" style="padding-bottom:65.63%"> <img class="object-cover absolute left-0 top-0 w-full h-full lazyload collection_list_img collection_list_img_adapt collection_list_img_radius" alt="SYSTEM PRODUCTS" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-sizes="auto" data-src="https://img.staticxt.com/1800822256395366403.jpg?x-oss-process=style/{width}x"> </div> </div> </div> <a href=/collections/system-products class="full-unstyled-link collection_list_item_box "> <p style="margin:0;text-align: var(--collection-card-text-alignment);width:100%;"> SYSTEM PRODUCTS <span class="icon-wrap"> <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"></path> </svg> </span> </p> </a> </div> </div> </li> </ul> <div class="collection_list-pagination"> <button type="button" class="slider-button collection-slider-button--prev" name="previous" aria-label="Slide left"> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </path> </svg> </button> <div class="slider-counter caption"> <span class="slider-counter--current">2</span> <span aria-hidden="true"> / </span> <span class="visually-hidden">of</span> <span class="slider-counter--total">4</span> </div> <button type="button" class="slider-button collection-slider-button--next" name="next" aria-label="Slide right"> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </path> </svg> </button> </div> </div> </main-collection-list-container> </div> </div> </div> <div class="xt-section section-1718182697427224" data-section-type="image-with-text" data-section-id="1718182697427224"> <style> .section-1718182697427224 { --section-m-margin-top: 0px; --section-margin-top: 0px; } .image-with-text-1718182697427224 { padding-top: 24px; padding-bottom: 32px; } @media screen and (max-width: 750px) { .image-with-text-1718182697427224 { padding-top: 12px; padding-bottom: 16px; } } .banner__heading p{ margin: 0; } </style> <div class="image-with-text image-with-text-1718182697427224 image-with-text--no-overlap page-width isolate collapse-borders collapse-corners"> <div class="image-with-text__grid grid grid--gapless grid--1-col grid--3-col-tablet "> <div class="image-with-text__media-item image-with-text__media-item--medium image-with-text__media-item--top grid__item"> <div class="image-with-text__media image-with-text__media--adapt gradient color-options-1 g-card-media placeholder " style="padding-bottom: 133.33%"> <img class="lazyload absolute left-0 top-0 w-full h-full object-cover object-center" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="https://img.staticxt.com/1801154963549728770.png?x-oss-process=style/{width}x" alt="MechHub" > </div> </div> <div class="image-with-text__text-item grid__item"> <div class="image-with-text__content image-with-text__content--top image-with-text__content--desktop-left image-with-text__content--mobile-left image-with-text__content--adapt gradient color-options-1 content-container"> <p class="image-with-text__text image-with-text__text--caption caption-with-letter-spacing caption-with-letter-spacing--medium">Leader in power generation equipment</p> <div class="banner__heading inline-richtext h1"> <p>MECHHUB&nbsp;</p> </div> <div class="banner__text rte body"> <p><p>In the dynamic landscape of industry, the heart of every operation is its engine&mdash;the core systems and processes that drive productivity and innovation. At MECHHUB, we understand the importance of robust engine support to keep your business running at peak efficiency.</p> <p>We are your dedicated engine support, fueling your ambitions and powering your path to success. With&nbsp; MECHHUB by your side, you can focus on what matters most&mdash;realizing your vision and achieving your goals.</p></p> </div> <div class="banner__buttons banner__buttons--multiple"> <a role="link" aria-disabled="false" href=/pages/about-us class="button">ABOUT US</a> </div> </div> </div> </div> </div> </div> <div class="xt-section section-1718086850236112" data-section-type="multi-column" data-section-id="1718086850236112"> <style> .section-1718086850236112 { --section-m-margin-top: 0px; --section-margin-top: 0px; } .multi-column-1718086850236112 { padding-top: 18px; padding-bottom: 0px; overflow: hidden; } @media screen and (min-width: 750px) { .multi-column-1718086850236112 { padding-top: 36px; padding-bottom: 0px; } } .multi-column-card__info>:nth-child(2) { margin-top: 1rem; } .multi-column-card__image-wrap--third { width: 33%; } .multi-column-card__image-wrap--half { width: 50%; } .multi-column-list__item.text-center .multi-column-card__image-wrap:not(.multi-column-card__image-wrap--full) { margin-left: auto; margin-right: auto; } .multi-column-list__item.text-right .multi-column-card__image-wrap:not(.multi-column-card__image-wrap--full) { margin-left: auto; } .multi-column.background-primary .multi-column-card { background: rgb(var(--color-background)) linear-gradient(rgba(var(--color-foreground), 0.04), rgba(var(--color-foreground), 0.04)); } .multi-column-card__image-wrap { margin-left: 2.5rem; margin-right: 2.5rem; } .multi-column-card__info { padding: 2.5rem; } .multi-column-card__btn:first-child:only-child { margin-top: 0; } .background-none .multi-column-card__image-wrap { padding-top: 1.5rem; } .multi-column .multi-column-card__image-wrap.multi-column-card__image-wrap--full{ border-top-left-radius: calc(var(--text-boxes-radius) - var(--text-boxes-border-width)); border-top-right-radius: calc(var(--text-boxes-radius) - var(--text-boxes-border-width)); overflow: hidden; padding-top:0; margin-left: 0; margin-right: 0; } .background-none .multi-column-card__image-wrap { margin-left: 1.5rem; margin-right: 1.5rem; } .background-none .multi-column-card__info { padding-left: 1.5rem; padding-right: 1.5rem; } @media screen and (max-width: 750px) { .multi-column--swiper .slider-container{ margin-left: -15px; margin-right: -15px; } .section-1718086850236112 .multi-column .grid-cols--swiper .grid__item{ padding-left: 1.5rem; width: 90%; } } </style> <div class="multi-column color-none gradient multi-column--swiper background-none"> <div class="page-width multi-column-1718086850236112"> <slider-container class="slider-container" enabled="false" data-slides-per-view="1"> <div class="slider-wrap grid mb-0 grid-cols--swiper lg:grid-cols--3"> <div class="slider-slide multi-column-list__item grid__item text-left"> <div class="multi-column-card g-card-content relative "> <div class="multi-column-card__info"> <h3 class="m-0 leading-1.5">1、Predictive Maintenance</h3> <div class="rte"><p>Utilizing data analytics and IoT sensors to predict equipment failures before they occur, reducing downtime and maintenance costs.</p></div> </div> </div> </div> <div class="slider-slide multi-column-list__item grid__item text-left"> <div class="multi-column-card g-card-content relative "> <div class="multi-column-card__info"> <h3 class="m-0 leading-1.5">2、Comprehensive Diagnostics</h3> <div class="rte"><p>Advanced tools and software to perform in-depth analysis of engine performance, identifying potential issues and recommending corrective actions.</p></div> </div> </div> </div> <div class="slider-slide multi-column-list__item grid__item text-left"> <div class="multi-column-card g-card-content relative "> <div class="multi-column-card__info"> <h3 class="m-0 leading-1.5">3、On-Demand Technical Support</h3> <div class="rte"><p>Access to a team of experts for immediate assistance with troubleshooting and resolving engine-related issues.</p></div> </div> </div> </div> <div class="slider-slide multi-column-list__item grid__item text-left"> <div class="multi-column-card g-card-content relative "> <div class="multi-column-card__info"> <h3 class="m-0 leading-1.5">4、Upgrade and Modernization Services</h3> <div class="rte"><p>Offering solutions for upgrading existing systems to the latest technology, improving efficiency and reducing the environmental footprint.</p></div> </div> </div> </div> <div class="slider-slide multi-column-list__item grid__item text-left"> <div class="multi-column-card g-card-content relative "> <div class="multi-column-card__image-wrap mx-10 multi-column-card__image-wrap--full"> <div class="media media--transparent relative media--adapt" style="padding-bottom:50%" > <img class="absolute left-0 top-0 w-full h-full object-cover object-center lazyload" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="https://img.staticxt.com/1801162467101077505.png?x-oss-process=style/{width}x" alt=""> </div> </div> <div class="multi-column-card__info"> </div> </div> </div> <div class="slider-slide multi-column-list__item grid__item text-left"> <div class="multi-column-card g-card-content relative "> <div class="multi-column-card__info"> <h3 class="m-0 leading-1.5">5、Remote Monitoring and Control</h3> <div class="rte"><p>Real-time monitoring of engine performance from a remote location, allowing for proactive management and quick response to any issues.</p></div> </div> </div> </div> </div> <div class="slideshow__controls md:hidden"> <button class="slider-button slider-button-prev" name="prev"> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </button> <div class="slider-counter caption" data-pagination-type="counter"> <span class="slider-counter--current">1</span> <span aria-hidden="true"> / </span> <span class="visually-hidden">of</span> <span class="slider-counter--total">6</span> </div> <button class="slider-button slider-button-next" name="next"> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </button> </div> </slider-container> </div> </div> </div> <div class="xt-section section-1718271675456136" data-section-type="img-banner" data-section-id="1718271675456136"> <style> .section-1718271675456136 { --section-m-margin-top: 0px; --section-margin-top: 0px; } .section-1718271675456136 .banner:after{ opacity: 0; } .section-1718271675456136 .slideshow--adapt .slideshow__media:before { padding-bottom: 2.5%; content: ''; display: block; } .section-img-banner .banner__content { height: auto; } .banner__media-half { width: 50%; } .banner__media-half+.banner__media-half { right: 0; left: auto; } .section-img-banner .slideshow--adapt { height: auto; } .banner__heading p { margin: 0; padding: 0; } @media screen and (max-width: 749px) { .section-img-banner .slideshow--center .banner__media { position: relative; } .section-img-banner .slideshow--center .banner__content { position: absolute; height: auto; } .section-img-banner .slideshow--center .banner__container { background: transparent; --color-foreground: 255, 255, 255; --color-button: 255, 255, 255; --color-button-text: 0, 0, 0; max-width: 89rem; border: none; border-radius: 0; box-shadow: none; } .banner { position: relative; flex-direction: column; } .banner:not(.banner--stacked){ flex-direction: row; flex-wrap: wrap; } .banner--stacked .banner__media-half { width: 100%; } .banner--stacked .banner__media-half+.banner__media-half { order: 1; } .section-1718271675456136 .slideshow--adapt .banner__content::before { padding-bottom: 2.5%; content: ''; display: block; } .section-1718271675456136 .slideshow--bottom.slideshow--adapt .banner__content::before { display: none; } .section-img-banner .slideshow--adapt:not(.slideshow--bottom) .banner__content{ position: relative; } .section-img-banner .slideshow--adapt:not(.slideshow--bottom) .banner__media{ position: absolute; } .section-img-banner .slideshow--adapt:not(.slideshow--bottom).banner--stacked .banner__content { position: absolute; } .section-img-banner .slideshow--adapt:not(.slideshow--bottom).banner--stacked .banner__media{ position: relative; } } @media screen and (min-width: 749.98px) { .section-1718271675456136 .section-img-banner .slideshow--adapt::before { padding-bottom: 2.5%; content: ''; display: block; } } </style> <div class="section-img-banner"> <div class="banner relative flex slideshow--adapt slideshow--center banner--"> <div class="slideshow__media banner__media media animate--none w-full h-full"> <img class="slideshow-object-block.settings.image_pos lazyload" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="https://img.staticxt.com/1801187424195325953.jpg?x-oss-process=style/{width}x" alt=""> </div> </div> </div> </div> <div class="xt-section section-1718270812467216" data-section-type="multi-video-column" data-section-id="1718270812467216"> <radf-muti-video-column enable-preview-image="" section-id="1718270812467216" column-count="4" swiper-time="2"> <style> .multi-video-column-container { display: flex; } .multi-video-column-item { overflow: visible !important; } .multi-video-column-item-image-fixed { position: fixed; top: 0; left: 0; z-index: 999; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.875); } .multi-video-column-item-image-fixed .fixed-close { display: flex; padding: 30px; cursor: pointer; } .multi-video-column-item-image-fixed .fixed-close svg { width: 30px; height: 30px; stroke: #fff; margin-left: auto; } .section-1718270812467216 { overflow: hidden; box-sizing: content-box; padding-top: 0px; } @media screen and (max-width: 750px) { .section-1718270812467216 { padding-top: 0px; } } .multi-1718270812467216-video-column .g-card-content { box-shadow: var(--text-boxes-shadow-horizontal-offset) var(--text-boxes-shadow-vertical-offset) var(--text-boxes-shadow-blur-radius) rgba(187,187,187,0); } .multi-1718270812467216-video-column .g-card-content:after { box-shadow: var(--text-boxes-shadow-horizontal-offset) var(--text-boxes-shadow-vertical-offset) var(--text-boxes-shadow-blur-radius) rgba(187,187,187,0); } .multi-1718270812467216-video-column .g-card-media { box-shadow: var(--media-shadow-horizontal-offset) var(--media-shadow-vertical-offset) var(--media-shadow-blur-radius) rgba(187,187,187,0.2); } .multi-1718270812467216-video-column .g-card-media:after { box-shadow: var(--media-shadow-horizontal-offset) var(--media-shadow-vertical-offset) var(--media-shadow-blur-radius) rgba(187,187,187,0.2); } .multi-1718270812467216-video-column>.swiper-button { display: flex; flex-direction: column; justify-content: center; } .multi-1718270812467216-video-column>.page-width>div { border-radius: var(--text-boxes-radius); } .multi-1718270812467216-video-column .multi-video-column-item-shadow { box-shadow: 4px 10px 20px 1px rgba(187,187,187,0.2); } .multi-1718270812467216-video-column .multi-video-column-item-image { margin-bottom: 20px; background-color: ; overflow: hidden; position: relative; padding-bottom: 55.55555555555556%; height: auto; width: 100%; } .multi-1718270812467216-video-column .multi-video-column-item-image>svg { left: 0; top: 50%; transform: translate(0, -50%); } .multi-1718270812467216-video-column .multi-video-column-item-image>div[layout=play] { width: 6.2rem; height: 6.2rem; position: absolute; z-index: 1; left: 50%; top: 50%; transform: translate(-50%, -50%); cursor: pointer; border-radius: 50%; color: rgb(var(--color-foreground)); background-color: rgb(var(--color-background)); border: 0.1rem solid rgba(var(--color-foreground), .1); display: flex; align-items: center; justify-content: center; } .multi-1718270812467216-video-column .multi-video-column-item-image>div[layout=play]>svg { height: 50%; width: 50%; top: 0; left: 0; } .multi-1718270812467216-video-column .multi-video-column-item { overflow: hidden; text-align: left; } #multi-video-column-1718270812467216-controls .swiper-pagination-bullet { background-color: #082457; } #multi-video-column-1718270812467216-controls .prev { transform: rotate(90deg); width: 12px; } #multi-video-column-1718270812467216-controls .next { transform: rotate(-90deg); width: 12px; } @media screen and (max-width: 750px) {} </style> <style> .multi-1718270812467216-video-column { background-color: #FFFFFF; padding: 24px 0 16px; } .multi-1718270812467216-video-column .multi-video-column-item { width: calc(100% / 4 - 25px) } .multi-1718270812467216-video-column .g-card-content > .multi-video-column-item-image { border-radius: calc(var(--text-boxes-radius) - var(--text-boxes-border-width)) calc(var(--text-boxes-radius) - var(--text-boxes-border-width)) 0 0; } </style> <!-- ************************** SECTION ************************** --> <!-- ************************** SECTION ************************** --> <div class="multi-1718270812467216-video-column py-9"> <div class="page-width" style="box-sizing: border-box;"> <div class="" style="background: ;"> <div style="overflow: visible; padding: 0 0; border-radius: calc(var(--text-boxes-radius));"> <div class="mb-14 text-center h2" style="color:#082457;"> </div> <!-- swiper --> <div class="swiper-1718270812467216" xt-preview-image> <div class="multi-video-column-container swiper-wrapper"> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide " play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative g-card-media" xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1801191196682366979.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide " play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative g-card-media" xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1801191196690755585.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide " play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative g-card-media" xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1801191196690968578.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide " play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative g-card-media" xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1801191196690968579.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide " play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative g-card-media" xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1801191196682366978.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide " play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative g-card-media" xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1801193289870749698.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> </div> </div> <!-- swiper end --> <div id="multi-video-column-1718270812467216-controls" class="flex items-center relative" style="padding: 15px; color: #082457"> <div class="cursor-pointer swiper-button prev"><svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg></div> <div class="swiper-1718270812467216-pagination swiper-pagination flex items-center justify-center" style="position: initial; z-index: 2;"></div> <div class="cursor-pointer swiper-button next"><svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg></div> </div> </div> </div> </div> </div> </radf-muti-video-column> </div> <div class="xt-section section-1718072966685204" data-section-type="newsletter" data-section-id="1718072966685204"> <style> .section-1718072966685204 { --section-m-margin-top: 0px; --section-margin-top: 0px; } .newsletter-1718072966685204 { padding-top: 20px; padding-bottom: 26px; } @media screen and (min-width: 750px) { .newsletter-1718072966685204 { padding-top: 40px; padding-bottom: 52px; } } .newsletter__wrap > * { margin-top: 0; margin-bottom: 0; } .newsletter__wrap > * + * { margin-top: 2rem; } </style> <div class="newsletter text-center"> <div class="newsletter__wrap color-options-2 gradient g-card-content relative z-0 newsletter-1718072966685204 g-card-content-y g-card-content--full-width"> <h2 class="inline-richtext h2">“Powering Progress: Your Engine Support Solution”</h2> <div> <contact-form data-lang-success="Thank you for contacting us. We will get back to you as soon as possible." data-lang-error="Please adjust the following:"> <form method="post" action="/api/mbr/customer/newsletter" id="newsletter-1718072966685204" class="newsletter-form flex flex-col justify-center items-center w-full relative md:item-start max-w-xl mx-auto"> <input type="hidden" name="form_type" value="customer"> <input type="hidden" name="contact[tags]" value="newsletter"> <div class="newsletter-form__field-wrap w-full max-w-xl"> <div class="field"> <input id="newsletter-email--1718072966685204" type="email" name="contact[email]" class="field__input" value="" aria-required="true" autocorrect="off" autocapitalize="off" autocomplete="email" placeholder="Email" required=""> <label class="field__label" for="newsletter-email--1718072966685204">Email</label> <button type="submit" class="newsletter-form__button field__button flex" name="commit" id="Subscribe" aria-label="Subscribe"> <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </svg> </button> </div> </div> <h3 class="newsletter-form__message flex"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon icon-success"> <path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zm13.36-1.814a.75.75 0 10-1.22-.872l-3.236 4.53L9.53 12.22a.75.75 0 00-1.06 1.06l2.25 2.25a.75.75 0 001.14-.094l3.75-5.25z" clip-rule="evenodd" /> </svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon icon-error"> <path fill-rule="evenodd" d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25zm-1.72 6.97a.75.75 0 10-1.06 1.06L10.94 12l-1.72 1.72a.75.75 0 101.06 1.06L12 13.06l1.72 1.72a.75.75 0 101.06-1.06L13.06 12l1.72-1.72a.75.75 0 10-1.06-1.06L12 10.94l-1.72-1.72z" clip-rule="evenodd" /> </svg> <span class="newsletter-form__message-text">Thanks for subscribing</span> </h3> </form> </contact-form> </div> <div class="newsletter__subheading rte"><p>Need more collections and exclusive offers?Contact Us <a href="https://mechhub.ishoptop.com/pages/about-us">HERE</a></p></div> </div> </div> </div> <div class="xt-section section-1718267790723420" data-section-type="multi-column" data-section-id="1718267790723420"> <style> .section-1718267790723420 { --section-m-margin-top: 0px; --section-margin-top: 0px; } .multi-column-1718267790723420 { padding-top: 24px; padding-bottom: 6px; overflow: hidden; } @media screen and (min-width: 750px) { .multi-column-1718267790723420 { padding-top: 48px; padding-bottom: 12px; } } .multi-column-card__info>:nth-child(2) { margin-top: 1rem; } .multi-column-card__image-wrap--third { width: 33%; } .multi-column-card__image-wrap--half { width: 50%; } .multi-column-list__item.text-center .multi-column-card__image-wrap:not(.multi-column-card__image-wrap--full) { margin-left: auto; margin-right: auto; } .multi-column-list__item.text-right .multi-column-card__image-wrap:not(.multi-column-card__image-wrap--full) { margin-left: auto; } .multi-column.background-primary .multi-column-card { background: rgb(var(--color-background)) linear-gradient(rgba(var(--color-foreground), 0.04), rgba(var(--color-foreground), 0.04)); } .multi-column-card__image-wrap { margin-left: 2.5rem; margin-right: 2.5rem; } .multi-column-card__info { padding: 2.5rem; } .multi-column-card__btn:first-child:only-child { margin-top: 0; } .background-none .multi-column-card__image-wrap { padding-top: 1.5rem; } .multi-column .multi-column-card__image-wrap.multi-column-card__image-wrap--full{ border-top-left-radius: calc(var(--text-boxes-radius) - var(--text-boxes-border-width)); border-top-right-radius: calc(var(--text-boxes-radius) - var(--text-boxes-border-width)); overflow: hidden; padding-top:0; margin-left: 0; margin-right: 0; } .background-none .multi-column-card__image-wrap { margin-left: 1.5rem; margin-right: 1.5rem; } .background-none .multi-column-card__info { padding-left: 1.5rem; padding-right: 1.5rem; } @media screen and (max-width: 750px) { .multi-column--swiper .slider-container{ margin-left: -15px; margin-right: -15px; } .section-1718267790723420 .multi-column .grid-cols--swiper .grid__item{ padding-left: 1.5rem; width: 90%; } } </style> <div class="multi-column color-none gradient multi-column--swiper background-primary"> <div class="page-width multi-column-1718267790723420"> <div class="multi-column__title-wrap mb-12 title-no-mt"> <h2 class="title m-0 h1">WE WORK WITH</h2> </div> <slider-container class="slider-container" enabled="false" data-slides-per-view="1"> <div class="slider-wrap grid mb-0 grid-cols--swiper lg:grid-cols--2"> <div class="slider-slide multi-column-list__item grid__item text-left"> <div class="multi-column-card g-card-content relative h-full"> <div class="multi-column-card__image-wrap mx-10 multi-column-card__image-wrap--full"> <div class="media media--transparent relative media--adapt" style="padding-bottom:35%" > <img class="absolute left-0 top-0 w-full h-full object-cover object-center lazyload" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="https://img.staticxt.com/1801205206475829249.jpg?x-oss-process=style/{width}x" alt=""> </div> </div> <div class="multi-column-card__info"> <h3 class="m-0 leading-1.5">Agriculture Area</h3> <div class="rte"><p>Engines power a wide range of agricultural machinery, including tractors, harvesters, and irrigation systems, enabling efficient farming practices.</p></div> <a class="multi-column-card__btn link animate-arrow no-underline mt-6 text-inherit" href="/collections/agriculture" >Introduction<span class="icon-wrap ml-3.5"><svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </svg></span></a> </div> </div> </div> <div class="slider-slide multi-column-list__item grid__item text-left"> <div class="multi-column-card g-card-content relative h-full"> <div class="multi-column-card__image-wrap mx-10 multi-column-card__image-wrap--full"> <div class="media media--transparent relative media--adapt" style="padding-bottom:35%" > <img class="absolute left-0 top-0 w-full h-full object-cover object-center lazyload" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="https://img.staticxt.com/1801205206500782083.jpg?x-oss-process=style/{width}x" alt=""> </div> </div> <div class="multi-column-card__info"> <h3 class="m-0 leading-1.5">Mining Area</h3> <div class="rte"><p>Engines are integral to mining equipment such as excavators, drills, and haul trucks, facilitating the extraction and transportation of minerals.</p></div> <a class="multi-column-card__btn link animate-arrow no-underline mt-6 text-inherit" href="/collections/mining-area" >Introduction<span class="icon-wrap ml-3.5"><svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </svg></span></a> </div> </div> </div> <div class="slider-slide multi-column-list__item grid__item text-left"> <div class="multi-column-card g-card-content relative h-full"> <div class="multi-column-card__image-wrap mx-10 multi-column-card__image-wrap--full"> <div class="media media--transparent relative media--adapt" style="padding-bottom:35%" > <img class="absolute left-0 top-0 w-full h-full object-cover object-center lazyload" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="https://img.staticxt.com/1801205206500782082.jpg?x-oss-process=style/{width}x" alt=""> </div> </div> <div class="multi-column-card__info"> <h3 class="m-0 leading-1.5">Road Construction Area</h3> <div class="rte"><p>Engines drive construction vehicles like bulldozers, pavers, and compactors, which are essential for road building and maintenance.</p></div> <a class="multi-column-card__btn link animate-arrow no-underline mt-6 text-inherit" href="/collections/road-construction-area" >Introduction<span class="icon-wrap ml-3.5"><svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </svg></span></a> </div> </div> </div> <div class="slider-slide multi-column-list__item grid__item text-left"> <div class="multi-column-card g-card-content relative h-full"> <div class="multi-column-card__image-wrap mx-10 multi-column-card__image-wrap--full"> <div class="media media--transparent relative media--adapt" style="padding-bottom:35%" > <img class="absolute left-0 top-0 w-full h-full object-cover object-center lazyload" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="https://img.staticxt.com/1801205206475829250.jpg?x-oss-process=style/{width}x" alt=""> </div> </div> <div class="multi-column-card__info"> <h3 class="m-0 leading-1.5">Shipping Area</h3> <div class="rte"><p>Engines propel a variety of marine vessels, from cargo ships to cruise liners, and also power onboard systems.</p></div> <a class="multi-column-card__btn link animate-arrow no-underline mt-6 text-inherit" href="/collections/shipping-area" >Introduction<span class="icon-wrap ml-3.5"><svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow" xmlns="http://www.w3.org/2000/svg"> <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"> </svg></span></a> </div> </div> </div> </div> <div class="slideshow__controls md:hidden"> <button class="slider-button slider-button-prev" name="prev"> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </button> <div class="slider-counter caption" data-pagination-type="counter"> <span class="slider-counter--current">1</span> <span aria-hidden="true"> / </span> <span class="visually-hidden">of</span> <span class="slider-counter--total">4</span> </div> <button class="slider-button slider-button-next" name="next"> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </button> </div> </slider-container> </div> </div> </div> <div class="xt-section section-1718271347764288" data-section-type="img-banner" data-section-id="1718271347764288"> <style> .section-1718271347764288 { --section-m-margin-top: 0px; --section-margin-top: 0px; } .section-1718271347764288 .banner:after{ opacity: 0; } .section-1718271347764288 .slideshow--adapt .slideshow__media:before { padding-bottom: 2.5%; content: ''; display: block; } .section-img-banner .banner__content { height: auto; } .banner__media-half { width: 50%; } .banner__media-half+.banner__media-half { right: 0; left: auto; } .section-img-banner .slideshow--adapt { height: auto; } .banner__heading p { margin: 0; padding: 0; } @media screen and (max-width: 749px) { .section-img-banner .slideshow--center .banner__media { position: relative; } .section-img-banner .slideshow--center .banner__content { position: absolute; height: auto; } .section-img-banner .slideshow--center .banner__container { background: transparent; --color-foreground: 255, 255, 255; --color-button: 255, 255, 255; --color-button-text: 0, 0, 0; max-width: 89rem; border: none; border-radius: 0; box-shadow: none; } .banner { position: relative; flex-direction: column; } .banner:not(.banner--stacked){ flex-direction: row; flex-wrap: wrap; } .banner--stacked .banner__media-half { width: 100%; } .banner--stacked .banner__media-half+.banner__media-half { order: 1; } .section-1718271347764288 .slideshow--adapt .banner__content::before { padding-bottom: 2.5%; content: ''; display: block; } .section-1718271347764288 .slideshow--bottom.slideshow--adapt .banner__content::before { display: none; } .section-img-banner .slideshow--adapt:not(.slideshow--bottom) .banner__content{ position: relative; } .section-img-banner .slideshow--adapt:not(.slideshow--bottom) .banner__media{ position: absolute; } .section-img-banner .slideshow--adapt:not(.slideshow--bottom).banner--stacked .banner__content { position: absolute; } .section-img-banner .slideshow--adapt:not(.slideshow--bottom).banner--stacked .banner__media{ position: relative; } } @media screen and (min-width: 749.98px) { .section-1718271347764288 .section-img-banner .slideshow--adapt::before { padding-bottom: 2.5%; content: ''; display: block; } } </style> <div class="section-img-banner"> <div class="banner relative flex slideshow--adapt slideshow--center banner--"> <div class="slideshow__media banner__media media animate--none w-full h-full"> <img class="slideshow-object-block.settings.image_pos lazyload" data-sizes="auto" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-src="https://img.staticxt.com/1801187424195325953.jpg?x-oss-process=style/{width}x" alt=""> </div> </div> </div> </div> <div class="xt-section section-1718185439769208" data-section-type="multi-video-column" data-section-id="1718185439769208"> <radf-muti-video-column enable-preview-image="" section-id="1718185439769208" column-count="5" swiper-time="3"> <style> .multi-video-column-container { display: flex; } .multi-video-column-item { overflow: visible !important; } .multi-video-column-item-image-fixed { position: fixed; top: 0; left: 0; z-index: 999; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.875); } .multi-video-column-item-image-fixed .fixed-close { display: flex; padding: 30px; cursor: pointer; } .multi-video-column-item-image-fixed .fixed-close svg { width: 30px; height: 30px; stroke: #fff; margin-left: auto; } .section-1718185439769208 { overflow: hidden; box-sizing: content-box; padding-top: 0px; } @media screen and (max-width: 750px) { .section-1718185439769208 { padding-top: 0px; } } .multi-1718185439769208-video-column .g-card-content { box-shadow: var(--text-boxes-shadow-horizontal-offset) var(--text-boxes-shadow-vertical-offset) var(--text-boxes-shadow-blur-radius) rgba(187,187,187,0); } .multi-1718185439769208-video-column .g-card-content:after { box-shadow: var(--text-boxes-shadow-horizontal-offset) var(--text-boxes-shadow-vertical-offset) var(--text-boxes-shadow-blur-radius) rgba(187,187,187,0); } .multi-1718185439769208-video-column .g-card-media { box-shadow: var(--media-shadow-horizontal-offset) var(--media-shadow-vertical-offset) var(--media-shadow-blur-radius) rgba(187,187,187,0.2); } .multi-1718185439769208-video-column .g-card-media:after { box-shadow: var(--media-shadow-horizontal-offset) var(--media-shadow-vertical-offset) var(--media-shadow-blur-radius) rgba(187,187,187,0.2); } .multi-1718185439769208-video-column>.swiper-button { display: flex; flex-direction: column; justify-content: center; } .multi-1718185439769208-video-column>.page-width>div { border-radius: var(--text-boxes-radius); } .multi-1718185439769208-video-column .multi-video-column-item-shadow { box-shadow: 4px 10px 20px 1px rgba(187,187,187,0.2); } .multi-1718185439769208-video-column .multi-video-column-item-image { margin-bottom: 20px; background-color: ; overflow: hidden; position: relative; padding-bottom: 43.47826086956522%; height: auto; width: 100%; } .multi-1718185439769208-video-column .multi-video-column-item-image>svg { left: 0; top: 50%; transform: translate(0, -50%); } .multi-1718185439769208-video-column .multi-video-column-item-image>div[layout=play] { width: 6.2rem; height: 6.2rem; position: absolute; z-index: 1; left: 50%; top: 50%; transform: translate(-50%, -50%); cursor: pointer; border-radius: 50%; color: rgb(var(--color-foreground)); background-color: rgb(var(--color-background)); border: 0.1rem solid rgba(var(--color-foreground), .1); display: flex; align-items: center; justify-content: center; } .multi-1718185439769208-video-column .multi-video-column-item-image>div[layout=play]>svg { height: 50%; width: 50%; top: 0; left: 0; } .multi-1718185439769208-video-column .multi-video-column-item { overflow: hidden; text-align: left; } #multi-video-column-1718185439769208-controls .swiper-pagination-bullet { background-color: #082457; } #multi-video-column-1718185439769208-controls .prev { transform: rotate(90deg); width: 12px; } #multi-video-column-1718185439769208-controls .next { transform: rotate(-90deg); width: 12px; } @media screen and (max-width: 750px) {} </style> <style> .multi-1718185439769208-video-column { background-color: #FFFFFF; padding: 48px 0 0px; } .multi-1718185439769208-video-column .multi-video-column-item { width: calc(100% / 5 - 25px) } .multi-1718185439769208-video-column .g-card-content > .multi-video-column-item-image { border-radius: calc(var(--text-boxes-radius) - var(--text-boxes-border-width)) calc(var(--text-boxes-radius) - var(--text-boxes-border-width)) 0 0; } </style> <!-- ************************** SECTION ************************** --> <!-- ************************** SECTION ************************** --> <div class="multi-1718185439769208-video-column py-9"> <div class="page-width" style="box-sizing: border-box;"> <div class="" style="background: ;"> <div style="overflow: visible; padding: 0 0; border-radius: calc(var(--text-boxes-radius));"> <div class="mb-14 text-center h2" style="color:#082457;"> PARTNERS </div> <!-- swiper --> <div class="swiper-1718185439769208" xt-preview-image> <div class="multi-video-column-container swiper-wrapper"> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide g-card-content" play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative " xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1800828837996539906.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide g-card-content" play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative " xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1800828837996752898.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide g-card-content" play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative " xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1800828837984169986.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide g-card-content" play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative " xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1800828838009335809.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide g-card-content" play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative " xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1800828838004928513.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide g-card-content" play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative " xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1800828837983956994.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> <!-- 新的mp4视频渲染逻辑 --> <div class="multi-video-column-item swiper-slide g-card-content" play_url="" aria-label=""> <!-- for item --> <div class="multi-video-column-item-image relative " xt-preview-image> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" xt-preview-image-item data-src="https://img.staticxt.com/1800828837996539905.jpg?x-oss-process=style/{width}x" data-sizes="auto" alt="" style="object-position: center;" class="absolute left-0 top-0 w-full h-full object-cover lazyload"> </div> <!-- for item end --> </div> </div> </div> <!-- swiper end --> <div id="multi-video-column-1718185439769208-controls" class="flex items-center relative" style="padding: 15px; color: #082457"> <div class="cursor-pointer swiper-button prev"><svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg></div> <div class="swiper-1718185439769208-pagination swiper-pagination flex items-center justify-center" style="position: initial; z-index: 2;"></div> <div class="cursor-pointer swiper-button next"><svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg></div> </div> </div> </div> </div> </div> </radf-muti-video-column> </div> <div class="xt-section section-1718095163686376" data-section-type="blog-post" data-section-id="1718095163686376"> <style> .section-1718095163686376 { --section-m-margin-top: 0px; --section-margin-top: 0px; } .section-1718095163686376 .gradient{ background-attachment: initial; } .blogpost-1718095163686376 { padding-top: 36px; padding-bottom: 16px; } .blogpost-1718095163686376 .w50 { width: 50%; } .blogpost-1718095163686376 .blog-placeholder { padding-bottom: 66.6%; position: relative; } .blogpost-1718095163686376 .placeholder-svg { display: block; max-width: 100%; position: absolute; top: 0; left: 0; height: 100%; width: 100%; } .placeholder-text { padding: 30px; background-color: rgb(var(--color-foreground), 0.04); } .blogpost-1718095163686376 .blog-content { padding: 2rem; } .blogpost-1718095163686376 .card__inner { width: 100%; display: flex; align-items: stretch; padding-bottom: 60%; } @media screen and (max-width: 750px) { .blogpost-1718095163686376 { padding-top: 18px; padding-bottom: 8px; } .blogpost-1718095163686376 .blog-list { display: flex; } .blogpost-1718095163686376 .grid-cols--swiper .grid__item{ padding-left: 1.5rem; } .blogpost-1718095163686376 .slider-container{ margin-left: -15px; margin-right: -15px; } } .article-media .article-content { background: transparent; } .blogpost .title-wrapper-with-link { margin-top: 0; } .blogpost .title p { margin: 0; } </style> <div class="blogpost blogpost-1718095163686376 color-none gradient"> <div class="page-width"> <div class="title-wrapper-with-link mb-12"> <h2 class="title m-0 h2"> <p>Explore More</p> </h2> </div> <slider-container class="slider-container overflow-hidden" enabled="false"> <div class="slider-wrap g-article-card-wrapper grid blog-list grid-cols--swiper md:grid-cols--3"> <div class="slider-slide grid__item underline-links-hover article-media "> <a class="full-unstyled-link blog-link card card--standard " href=/blog/why-is-the-engine-so-noisyhow-to-solve-it > <div class="card__inner flex relative gradient color-options-1"> <div class="article-card__image-wrapper card__media"> <div class="article-card__image media media--hover-effect"> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="MechHub" class="lazyload" data-sizes="auto" data-src="https://img.staticxt.com/1800444017634406401.jpg?x-oss-process=style/{width}x" > </div> </div> </div> <div class="blog-content article-content g-card-article--"> <h2 class="mt-0 h3 line-clamp-two"> Why is the engine so noisy? How to solve it? </h2> <div class="article__date text-xs leading-1.5 text-article-date-color"> <time datetime="2017-12-12T16:00:00Z">Dec 12, 2017</time> </div> <div class="rte article__content line-clamp-two"></div> </div> </a> </div> <div class="slider-slide grid__item underline-links-hover article-media "> <a class="full-unstyled-link blog-link card card--standard " href=/blog/what-is-the-difference-between-a-diesel-engine-and-a-gasoline-engine > <div class="card__inner flex relative gradient color-options-1"> <div class="article-card__image-wrapper card__media"> <div class="article-card__image media media--hover-effect"> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="MechHub" class="lazyload" data-sizes="auto" data-src="https://img.staticxt.com/1800444017625804802.jpg?x-oss-process=style/{width}x" > </div> </div> </div> <div class="blog-content article-content g-card-article--"> <h2 class="mt-0 h3 line-clamp-two"> What is the difference between a diesel engine and a gasoline engine? </h2> <div class="article__date text-xs leading-1.5 text-article-date-color"> <time datetime="2022-10-26T16:00:00Z">Oct 26, 2022</time> </div> <div class="rte article__content line-clamp-two"></div> </div> </a> </div> <div class="slider-slide grid__item underline-links-hover article-media "> <a class="full-unstyled-link blog-link card card--standard " href=/blog/why-mechhub-stands-out-the-difference-between-our-brand-and-the-rest > <div class="card__inner flex relative gradient color-options-1"> <div class="article-card__image-wrapper card__media"> <div class="article-card__image media media--hover-effect"> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="MechHub" class="lazyload" data-sizes="auto" data-src="https://img.staticxt.com/1806223389561688066.jpg?x-oss-process=style/{width}x" > </div> </div> </div> <div class="blog-content article-content g-card-article--"> <h2 class="mt-0 h3 line-clamp-two"> Why MechHub Stands Out: The Difference Between Our Brand and the Rest </h2> <div class="article__date text-xs leading-1.5 text-article-date-color"> <time datetime="2024-06-27T07:00:00Z">Jun 27, 2024</time> </div> <div class="rte article__content line-clamp-two">In the world of kinetic energy systems and mechanical engineering, there are countless brands vying for attention. At MechHub, we take pride in not just being another name in the industry, but in being a beacon of innovation, quality, and service. Here's </div> </div> </a> </div> </div> <div class="slideshow__controls md:hidden"> <button class="slider-button slider-button-prev" name="prev"> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </button> <div class="slider-counter caption" data-pagination-type="counter"> <span class="slider-counter--current">1</span> <span aria-hidden="true"> / </span> <span class="visually-hidden">of</span> <span class="slider-counter--total">3</span> </div> <button class="slider-button slider-button-next" name="next"> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </button> </div> </slider-container> </div> </div> </div> <div class="xt-section section-1718276609724356" data-section-type="rich-text" data-section-id="1718276609724356"> <style> .section-1718276609724356 { --section-m-margin-top: 0px; --section-margin-top: 0px; } .section-1718276609724356 .rich-text-container{ padding-top:36px; padding-bottom:64px; display: flex; justify-content: center ; } .rich-text-content{ width: 100%; display: flex; flex-wrap: wrap; } .rich-text-content--narrow { width: 78%; } .rich-text-content h2,.rich-text-content p{ margin-top: 0; margin-bottom: 0; } .rich-text-content-item{ width: 100%; } .rich-text-item-text,.rich-text-item-buttons,.rich-text-item-subtitle{ padding-top: 20px; } .rich-text-btn-box { display: inline-flex; flex-wrap: wrap; gap: 1rem; width: 100%; max-width: 45rem; word-break: break-word; } .rich-text-btn-box--multiple>* { flex-grow: 1; min-width: 22rem; } @media screen and (max-width: 749px) { .section-1718276609724356 .rich-text-container{ padding-top:18px; padding-bottom:32px; } .rich-text-content{ width: 100%; padding: 0 15px; display: flex; flex-wrap: wrap; } .rich-text-btn-box .button{ width: 100%; } } </style> <div class="rich-text-1718276609724356 color-options-1 gradient g-card-content-y"> <div class="rich-text-container page-width"> <div class="rich-text-content rich-text-content--narrow text-center"> <div class="rich-text-content-item rich-text-item-text"> <div><p>Engines are the heartbeat of heavy industries, providing the power necessary for a range of operations. Their continuous development in terms of efficiency, power, and environmental friendliness makes them an essential asset in various sectors.</p></div> </div> <div class="rich-text-content-item rich-text-item-buttons"> <div class="rich-text-btn-box relative z-1 justify-center rich-text-btn-box--multiple"> <a role="link" aria-disabled="false" href=/collections/all-products class="button button--secondary">ALL PRODUCTS</a> <a role="link" aria-disabled="false" href=/pages/contact class="button button--secondary"> CONTACT US</a> </div> </div> </div> </div> </div> </div> </main> <div class="xt-section section-footer" data-section-type="footer" data-section-id="footer"> <style> .footer-footer { padding-top: 18px; padding-bottom: 18px; margin-top: 0px; } @media screen and (min-width: 750px) { .footer-footer { padding-top: 36px; padding-bottom: 36px; margin-top: 0px; } } .footer__content-top { padding-bottom: 5rem; display: block; } .footer__content-bottom { border-top: solid .1rem rgba(var(--color-foreground), .08); padding-top: 3rem; } .footer-block__image-wrap img { display: block; height: auto; max-width: 100%; } .footer-block__heading { margin-bottom: 2rem; margin-top: 0; font-size: calc(var(--font-heading-scale) * 1.6rem); } .footer-copyright__content { font-size: 1.1rem; } .footer__payment-list { display: flex; flex-direction: column; justify-content: center; align-items: center; padding-left: 2rem; padding-right: 2rem; } .footer__payment-list li { padding: 0.5rem; } .footer__payment-list img { width: 38px; height: auto; } .footer__localization:empty+.footer__payment-list { align-items: center; } .footer-block__newsletter-wrap { margin-top: 3rem; flex-direction: column; align-items: center; } @media screen and (max-width: 749px) { .footer__content-top { padding-bottom: 3rem; padding-left: calc(4rem / var(--font-base-scale)); padding-right: calc(4rem / var(--font-base-scale)); } .footer-block__newsletter { width: 100%; text-align: center; } contact-form { display: flex; justify-content: center; } contact-form form { flex: 1; } .footer-block.grid__item { padding: 0; margin: 4rem 0; width: 100%; } .footer__content-bottom { padding: 0; } .footer .grid { display: block; } .footer .grid__item { width: 100%; max-width: 100%; } } @media screen and (min-width: 990px) { .footer-block__heading { font-size: calc(var(--font-heading-scale) * 1.8rem); } } @media screen and (min-width: 750px) { .footer-block:only-child:last-child { text-align: center; max-width: 76rem; margin: 0 auto; } .footer__content-top .grid { row-gap: 6rem; margin-bottom: 0; } .footer__payment-list { padding-left: 0; padding-right: 0; align-items: flex-end; } .footer-block__newsletter-wrap { flex-wrap: nowrap; justify-content: center; align-items: flex-end; flex-direction: row; } .footer-block:only-child .footer-block__brand-info { display: flex; flex-direction: column; align-items: center; } .footer-block:only-child ul.footer-block__content { display: flex; flex-wrap: wrap; justify-content: center; } .footer-block:only-child li { display: inline; flex-shrink: 0; } .footer-block__content > li:not(:last-child) { margin-right: 1.5rem; } } </style> <style> .footer summary { display: none; } .footer .footer-block:not(.accordion) { border: none; } @media screen and (max-width: 749px) { .footer-block-accordion summary { display: block; } .footer-block-accordion summary+h2 { display: none; } .footer-block-accordion .summary__title h2 { display: block; margin: 0; } .footer-block-accordion .footer-block__content { padding-bottom: 20px; } .footer-block-accordion .footer-brand-title { display: none; } .footer-block-accordion.accordion { margin: 0; } } @media screen and (min-width: 750px) { .footer-block-accordion { border: none; margin: 0; } } </style> <footer class="footer color-options-2 gradient footer-footer"> <radf-footer> <div class="footer__content-top page-width"> <div class="footer__blocks-wrapper grid grid-cols--1 grid-cols--2 md:grid-cols--3 block md:flex"> <div class="footer-block grid__item footer-block--menu"> <ul class="footer-block__content list-unstyled"> <li> <a href="/" class="link link--text list-menu__item list-menu__item--link">HOME</a> </li> <li> <a href="/pages/about-us" class="link link--text list-menu__item list-menu__item--link">ABOUT MECHHUB</a> </li> <li> <a href="/blogs/news" class="link link--text list-menu__item list-menu__item--link">NEWS</a> </li> </ul> </div> <div class="footer-block grid__item footer-block--menu accordion footer-block-accordion"> <details open> <summary> <div class="summary__title flex"> <h2 class="h4 accordion__title footer-block__heading inline-richtext">PRODUCTS</h2> </div> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </summary> <h2 class="footer-block__heading inline-richtext">PRODUCTS</h2> <ul class="footer-block__content list-unstyled"> <li> <a href="/collections/engine" class="link link--text list-menu__item list-menu__item--link">ENGINE</a> </li> <li> <a href="/collections/generator-set" class="link link--text list-menu__item list-menu__item--link">ENGINE SET</a> </li> <li> <a href="/collections/engine-components" class="link link--text list-menu__item list-menu__item--link">ENGINE COMPONENTS</a> </li> <li> <a href="/collections/system-products" class="link link--text list-menu__item list-menu__item--link">SYSTEM PRODUCTS</a> </li> </ul> </details> </div> <div class="footer-block grid__item footer-block--menu accordion footer-block-accordion"> <details open> <summary> <div class="summary__title flex"> <h2 class="h4 accordion__title footer-block__heading inline-richtext">SERVICE &amp; SUPPORT</h2> </div> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </summary> <h2 class="footer-block__heading inline-richtext">SERVICE &amp; SUPPORT</h2> <ul class="footer-block__content list-unstyled"> <li> <a href="/pages/tech-support" class="link link--text list-menu__item list-menu__item--link">TECH SUPPORT</a> </li> <li> <a href="/pages/after-sales" class="link link--text list-menu__item list-menu__item--link">AFTER-SALES</a> </li> </ul> </details> </div> <div class="footer-block grid__item accordion footer-block-accordion"> <details open> <summary> <div class="summary__title flex"> <h2 class="h4 accordion__title footer-block__heading inline-richtext">WE AIM TO</h2> </div> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </summary> <h2 class="footer-block__heading inline-richtext">WE AIM TO</h2> <div class="footer-block__content rte"><p>Empowering Progress,<br />Together We Thrive!</p></div> </details> </div> <div class="footer-block grid__item"> <div class="footer-block__brand-info"> <div class="rte"><p>Service hours &nbsp;9:00~17:30</p> <p>Tel: 021-2312-0688<br />Email:<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="3204050a030b02000a72555f535b5e1c515d5f">[email&#160;protected]</a></p></div> </div> </div> <div class="footer-block grid__item"> <div class="footer-block__brand-info"> <div class="footer-block__image-wrap g-media-settings mb-8" style="max-width: min(100%, 210px);"> <img class="lazyload" data-sizes="auto" data-src="https://img.staticxt.com/1800734967254446082.png?x-oss-process=style/{width}x" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="" width="2960" height="376"> </div> <div><ul class="footer__social-list list-unstyled social-list"> <li class="social-list__item"> <a href="111" class="link social-list__link"> <svg xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 24 24" class="icon icon-facebook"> <path d="M22.675 0h-21.35c-.732 0-1.325.593-1.325 1.325v21.351c0 .731.593 1.324 1.325 1.324h11.495v-9.294h-3.128v-3.622h3.128v-2.671c0-3.1 1.893-4.788 4.659-4.788 1.325 0 2.463.099 2.795.143v3.24l-1.918.001c-1.504 0-1.795.715-1.795 1.763v2.313h3.587l-.467 3.622h-3.12v9.293h6.116c.73 0 1.323-.593 1.323-1.325v-21.35c0-.732-.593-1.325-1.325-1.325z"></path> </svg> <span class="visually-hidden">Facebook</span> </a> </li> <li class="social-list__item"> <a href="111" class="link social-list__link"> <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-instagram" fill="currentColor" viewBox="0 0 24 24"> <path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z" /> </svg> <span class="visually-hidden">Instagram</span> </a> </li> <li class="social-list__item"> <a href="111" class="link social-list__link"> <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-youtube" fill="currentColor" viewBox="0 0 24 24"> <path d="M19.615 3.184c-3.604-.246-11.631-.245-15.23 0-3.897.266-4.356 2.62-4.385 8.816.029 6.185.484 8.549 4.385 8.816 3.6.245 11.626.246 15.23 0 3.897-.266 4.356-2.62 4.385-8.816-.029-6.185-.484-8.549-4.385-8.816zm-10.615 12.816v-8l8 3.993-8 4.007z" /> </svg> <span class="visually-hidden">Youtube</span> </a> </li> <li class="social-list__item"> <a href="111" class="link social-list__link"> <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-twitter" fill="currentColor" viewBox="0 0 24 24"> <path d="M24 4.557c-.883.392-1.832.656-2.828.775 1.017-.609 1.798-1.574 2.165-2.724-.951.564-2.005.974-3.127 1.195-.897-.957-2.178-1.555-3.594-1.555-3.179 0-5.515 2.966-4.797 6.045-4.091-.205-7.719-2.165-10.148-5.144-1.29 2.213-.669 5.108 1.523 6.574-.806-.026-1.566-.247-2.229-.616-.054 2.281 1.581 4.415 3.949 4.89-.693.188-1.452.232-2.224.084.626 1.956 2.444 3.379 4.6 3.419-2.07 1.623-4.678 2.348-7.29 2.04 2.179 1.397 4.768 2.212 7.548 2.212 9.142 0 14.307-7.721 13.995-14.646.962-.695 1.797-1.562 2.457-2.549z" /> </svg> <span class="visually-hidden">Twitter</span> </a> </li> <li class="social-list__item"> <a href="111" class="link social-list__link"> <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-pinterest" fill="currentColor" viewBox="0 0 24 24"> <path d="M12 0c-6.627 0-12 5.372-12 12 0 5.084 3.163 9.426 7.627 11.174-.105-.949-.2-2.405.042-3.441.218-.937 1.407-5.965 1.407-5.965s-.359-.719-.359-1.782c0-1.668.967-2.914 2.171-2.914 1.023 0 1.518.769 1.518 1.69 0 1.029-.655 2.568-.994 3.995-.283 1.194.599 2.169 1.777 2.169 2.133 0 3.772-2.249 3.772-5.495 0-2.873-2.064-4.882-5.012-4.882-3.414 0-5.418 2.561-5.418 5.207 0 1.031.397 2.138.893 2.738.098.119.112.224.083.345l-.333 1.36c-.053.22-.174.267-.402.161-1.499-.698-2.436-2.889-2.436-4.649 0-3.785 2.75-7.262 7.929-7.262 4.163 0 7.398 2.967 7.398 6.931 0 4.136-2.607 7.464-6.227 7.464-1.216 0-2.359-.631-2.75-1.378l-.748 2.853c-.271 1.043-1.002 2.35-1.492 3.146 1.124.347 2.317.535 3.554.535 6.627 0 12-5.373 12-12 0-6.628-5.373-12-12-12z" fill-rule="evenodd" clip-rule="evenodd" /> </svg> <span class="visually-hidden">Pinterest</span> </a> </li> <li class="social-list__item"> <a href="111" class="link social-list__link"> <svg class="icon icon-vimeo" viewBox="0 0 100 87"> <path fill-rule="evenodd" d="M100 20.4c-.5 9.7-7.3 23-20.4 40C66 78.1 54.5 87 45 87c-5.8 0-10.7-5.4-14.7-16.2l-8.1-29.6C19.2 30.4 16 25 12.6 25c-.8 0-3.4 1.6-7.9 4.7l-4.7-6 14.6-13c6.6-5.8 11.5-8.8 14.8-9C37.2.8 42 6.1 43.8 17.5c2 12.3 3.3 20 4 23 2.3 10.2 4.7 15.3 7.4 15.3 2.1 0 5.3-3.3 9.5-10a39.2 39.2 0 006.7-15c.6-5.8-1.7-8.7-6.7-8.7-2.4 0-4.9.6-7.4 1.7C62.2 7.7 71.6-.1 85.4.4c10.3.3 15.1 7 14.6 20" fill="currentColor"> </svg> <span class="visually-hidden">Viemo</span> </a> </li> </ul></div> </div> </div> </div> <div class="footer-block__newsletter-wrap flex gap-12"> </div> </div> <radf-footer> <div class="footer__content-bottom"> <div class="footer__content-bottom-wrap page-width flex flex-col md:flex-row"> </div> <div class="footer__content-bottom-wrap page-width flex justify-center"> <div class="footer-copyright caption text-center mt-6"> <small class="footer-copyright__content">&copy; 2025 MechHub <a target='_blank' class='tw-no-underline' href='https://www.Shoptop.com' style='color:inherit;'>Powered by Shoptop</a></small> </div> </div> </div> </footer> </div> <svg class="shape--mask" width="0" height="0" viewBox="0 0 100 100"> <clipPath id="Shape-Arch" clipPathUnits="objectBoundingBox" transform="scale(0.01, 0.01)"> <path fill-rule="evenodd" clip-rule="evenodd" d="M100 50C100 22.3858 77.6142 0 50 0C22.3858 0 0 22.3858 0 50V100H50H100V50Z"></path> </clipPath> </svg> <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script><script> /*! art-template@4.13.1 for browser | https://github.com/aui/art-template */ !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.template=t():e.template=t()}("undefined"!=typeof self?self:this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};return t.m=e,t.c=n,t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e["default"]}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=4)}([function(e,t,n){"use strict";var r=n(6),i=n(2),o=n(22),s=function(e,t){t.onerror(e,t);var n=function(){return"{Template Error}"};return n.mappings=[],n.sourcesContent=[],n},a=function u(e){var t=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{};"string"!=typeof e?t=e:t.source=e,t=i.$extend(t),e=t.source,!0===t.debug&&(t.cache=!1,t.minimize=!1,t.compileDebug=!0),t.compileDebug&&(t.minimize=!1),t.filename&&(t.filename=t.resolveFilename(t.filename,t));var n=t.filename,a=t.cache,c=t.caches;if(a&&n){var l=c.get(n);if(l)return l}if(!e)try{e=t.loader(n,t),t.source=e}catch(m){var f=new o({name:"CompileError",path:n,message:"template not found: "+m.message,stack:m.stack});if(t.bail)throw f;return s(f,t)}var p=void 0,h=new r(t);try{p=h.build()}catch(f){if(f=new o(f),t.bail)throw f;return s(f,t)}var d=function(e,n){try{return p(e,n)}catch(f){if(!t.compileDebug)return t.cache=!1,t.compileDebug=!0,u(t)(e,n);if(f=new o(f),t.bail)throw f;return s(f,t)()}};return d.mappings=p.mappings,d.sourcesContent=p.sourcesContent,d.toString=function(){return p.toString()},a&&n&&c.set(n,d),d};a.Compiler=r,e.exports=a},function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t["default"]=/((['"])(?:(?!\2|\\).|\\(?:\r\n|[\s\S]))*(\2)?|`(?:[^`\\$]|\\[\s\S]|\$(?!\{)|\$\{(?:[^{}]|\{[^}]*\}?)*\}?)*(`)?)|(\/\/.*)|(\/\*(?:[^*]|\*(?!\/))*(\*\/)?)|(\/(?!\*)(?:\[(?:(?![\]\\]).|\\.)*\]|(?![\/\]\\]).|\\.)+\/(?:(?!\s*(?:\b|[\u0080-\uFFFF$\\'"~({]|[+\-!](?!=)|\.?\d))|[gmiyu]{1,5}\b(?![\u0080-\uFFFF$\\]|\s*(?:[+\-*%&|^<>!=?({]|\/(?![\/*])))))|(0[xX][\da-fA-F]+|0[oO][0-7]+|0[bB][01]+|(?:\d*\.\d+|\d+\.?)(?:[eE][+-]?\d+)?)|((?!\d)(?:(?!\s)[$\w\u0080-\uFFFF]|\\u[\da-fA-F]{4}|\\u\{[\da-fA-F]+\})+)|(--|\+\+|&&|\|\||=>|\.{3}|(?:[+\-\/%&|^]|\*{1,2}|<{1,2}|>{1,3}|!=?|={1,2})=?|[?~.,:;[\](){}])|(\s+)|(^$|[\s\S])/g,t.matchToToken=function(e){var t={type:"invalid",value:e[0]};return e[1]?(t.type="string",t.closed=!(!e[3]&&!e[4])):e[5]?t.type="comment":e[6]?(t.type="comment",t.closed=!!e[7]):e[8]?t.type="regex":e[9]?t.type="number":e[10]?t.type="name":e[11]?t.type="punctuator":e[12]&&(t.type="whitespace"),t}},function(e,t,n){"use strict";function r(){this.$extend=function(e){return e=e||{},o(e,e instanceof r?e:this)}}var i=n(10),o=n(12),s=n(13),a=n(14),u=n(15),c=n(16),l=n(17),f=n(18),p=n(19),h=n(21),d="undefined"==typeof window,m={source:null,filename:null,rules:[f,l],escape:!0,debug:!!d&&"production"!==process.env.NODE_ENV,bail:!0,cache:!0,minimize:!0,compileDebug:!1,resolveFilename:h,include:s,htmlMinifier:p,htmlMinifierOptions:{collapseWhitespace:!0,minifyCSS:!0,minifyJS:!0,ignoreCustomFragments:[]},onerror:a,loader:c,caches:u,root:"/",extname:".art",ignore:[],imports:i};r.prototype=m,e.exports=new r},function(e,t){},function(e,t,n){"use strict";var r=n(5),i=n(0),o=n(23),s=function(e,t){return t instanceof Object?r({filename:e},t):i({filename:e,source:t})};s.render=r,s.compile=i,s.defaults=o,e.exports=s},function(e,t,n){"use strict";var r=n(0),i=function(e,t,n){return r(e,n)(t)};e.exports=i},function(e,t,n){"use strict";function r(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var s=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),a=n(7),u=n(9),c="$data",l="$imports",f="print",p="include",h="extend",d="block",m="$$out",v="$$line",g="$$blocks",y="$$slice",b="$$from",w="$$options",x=function(e,t){return Object.hasOwnProperty.call(e,t)},k=JSON.stringify,E=function(){function e(t){var n,s,a=this;o(this,e);var x=t.source,k=t.minimize,E=t.htmlMinifier;if(this.options=t,this.stacks=[],this.context=[],this.scripts=[],this.CONTEXT_MAP={},this.ignore=[c,l,w].concat(i(t.ignore)),this.internal=(n={},r(n,m,"''"),r(n,v,"[0,0]"),r(n,g,"arguments[1]||{}"),r(n,b,"null"),r(n,f,"function(){var s=''.concat.apply('',arguments);"+m+"+=s;return s}"),r(n,p,"function(src,data){var s="+w+".include(src,data||"+c+",arguments[2]||"+g+","+w+");"+m+"+=s;return s}"),r(n,h,"function(from){"+b+"=from}"),r(n,y,"function(c,p,s){p="+m+";"+m+"='';c();s="+m+";"+m+"=p+s;return s}"),r(n,d,"function(){var a=arguments,s;if(typeof a[0]==='function'){return "+y+"(a[0])}else if("+b+"){if(!"+g+"[a[0]]){"+g+"[a[0]]="+y+"(a[1])}else{"+m+"+="+g+"[a[0]]}}else{s="+g+"[a[0]];if(typeof s==='string'){"+m+"+=s}else{s="+y+"(a[1])}return s}}"),n),this.dependencies=(s={},r(s,f,[m]),r(s,p,[m,w,c,g]),r(s,h,[b,p]),r(s,d,[y,b,m,g]),s),this.importContext(m),t.compileDebug&&this.importContext(v),k)try{x=E(x,t)}catch(T){}this.source=x,this.getTplTokens(x,t.rules,this).forEach(function(e){e.type===u.TYPE_STRING?a.parseString(e):a.parseExpression(e)})}return s(e,[{key:"getTplTokens",value:function(){return u.apply(undefined,arguments)}},{key:"getEsTokens",value:function(e){return a(e)}},{key:"getVariables",value:function(e){var t=!1;return e.filter(function(e){return"whitespace"!==e.type&&"comment"!==e.type}).filter(function(e){return"name"===e.type&&!t||(t="punctuator"===e.type&&"."===e.value,!1)}).map(function(e){return e.value})}},{key:"importContext",value:function(e){var t=this,n="",r=this.internal,i=this.dependencies,o=this.ignore,s=this.context,a=this.options,u=a.imports,f=this.CONTEXT_MAP;x(f,e)||-1!==o.indexOf(e)||(x(r,e)?(n=r[e],x(i,e)&&i[e].forEach(function(e){return t.importContext(e)})):n="$escape"===e||"$each"===e||x(u,e)?l+"."+e:c+"."+e,f[e]=n,s.push({name:e,value:n}))}},{key:"parseString",value:function(e){var t=e.value;if(t){var n=m+"+="+k(t);this.scripts.push({source:t,tplToken:e,code:n})}}},{key:"parseExpression",value:function(e){var t=this,n=e.value,r=e.script,i=r.output,o=this.options.escape,s=r.code;i&&(s=!1===o||i===u.TYPE_RAW?m+"+="+r.code:m+"+=$escape("+r.code+")");var a=this.getEsTokens(s);this.getVariables(a).forEach(function(e){return t.importContext(e)}),this.scripts.push({source:n,tplToken:e,code:s})}},{key:"checkExpression",value:function(e){for(var t=[[/^\s*}[\w\W]*?{?[\s;]*$/,""],[/(^[\w\W]*?\([\w\W]*?(?:=>|\([\w\W]*?\))\s*{[\s;]*$)/,"$1})"],[/(^[\w\W]*?\([\w\W]*?\)\s*{[\s;]*$)/,"$1}"]],n=0;n<t.length;){if(t[n][0].test(e)){var r;e=(r=e).replace.apply(r,i(t[n]));break}n++}try{return new Function(e),!0}catch(o){return!1}}},{key:"build",value:function(){var e=this.options,t=this.context,n=this.scripts,r=this.stacks,i=this.source,o=e.filename,s=e.imports,a=[],f=x(this.CONTEXT_MAP,h),d=0,y=function(e,t){var n=t.line,i=t.start,o={generated:{line:r.length+d+1,column:1},original:{line:n+1,column:i+1}};return d+=e.split(/\n/).length-1,o},E=function(e){return e.replace(/^[\t ]+|[\t ]$/g,"")};r.push("function("+c+"){"),r.push("'use strict'"),r.push(c+"="+c+"||{}"),r.push("var "+t.map(function(e){return e.name+"="+e.value}).join(",")),e.compileDebug?(r.push("try{"),n.forEach(function(e){e.tplToken.type===u.TYPE_EXPRESSION&&r.push(v+"=["+[e.tplToken.line,e.tplToken.start].join(",")+"]"),a.push(y(e.code,e.tplToken)),r.push(E(e.code))}),r.push("}catch(error){"),r.push("throw {"+["name:'RuntimeError'","path:"+k(o),"message:error.message","line:"+v+"[0]+1","column:"+v+"[1]+1","source:"+k(i),"stack:error.stack"].join(",")+"}"),r.push("}")):n.forEach(function(e){a.push(y(e.code,e.tplToken)),r.push(E(e.code))}),f&&(r.push(m+"=''"),r.push(p+"("+b+","+c+","+g+")")),r.push("return "+m),r.push("}");var T=r.join("\n");try{var O=new Function(l,w,"return "+T)(s,e);return O.mappings=a,O.sourcesContent=[i],O}catch(P){for(var $=0,j=0,_=0,S=void 0;$<n.length;){var C=n[$];if(!this.checkExpression(C.code)){j=C.tplToken.line,_=C.tplToken.start,S=C.code;break}$++}throw{name:"CompileError",path:o,message:P.message,line:j+1,column:_+1,source:i,generated:S,stack:P.stack}}}}]),e}();E.CONSTS={DATA:c,IMPORTS:l,PRINT:f,INCLUDE:p,EXTEND:h,BLOCK:d,OPTIONS:w,OUT:m,LINE:v,BLOCKS:g,SLICE:y,FROM:b,ESCAPE:"$escape",EACH:"$each"},e.exports=E},function(e,t,n){"use strict";var r=n(8),i=n(1)["default"],o=n(1).matchToToken,s=function(e){return e.match(i).map(function(e){return i.lastIndex=0,o(i.exec(e))}).map(function(e){return"name"===e.type&&r(e.value)&&(e.type="keyword"),e})};e.exports=s},function(e,t,n){"use strict";var r={"abstract":!0,await:!0,"boolean":!0,"break":!0,"byte":!0,"case":!0,"catch":!0,"char":!0,"class":!0,"const":!0,"continue":!0,"debugger":!0,"default":!0,"delete":!0,"do":!0,"double":!0,"else":!0,"enum":!0,"export":!0,"extends":!0,"false":!0,"final":!0,"finally":!0,"float":!0,"for":!0,"function":!0,"goto":!0,"if":!0,"implements":!0,"import":!0,"in":!0,"instanceof":!0,"int":!0,"interface":!0,"let":!0,"long":!0,"native":!0,"new":!0,"null":!0,"package":!0,"private":!0,"protected":!0,"public":!0,"return":!0,"short":!0,"static":!0,"super":!0,"switch":!0,"synchronized":!0,"this":!0,"throw":!0,"transient":!0,"true":!0,"try":!0,"typeof":!0,"var":!0,"void":!0,"volatile":!0,"while":!0,"with":!0,"yield":!0};e.exports=function(e){return r.hasOwnProperty(e)}},function(e,t,n){"use strict";function r(e){var t=new String(e.value);return t.line=e.line,t.start=e.start,t.end=e.end,t}function i(e,t,n){this.type=e,this.value=t,this.script=null,n?(this.line=n.line+n.value.split(/\n/).length-1,this.line===n.line?this.start=n.end:this.start=n.value.length-n.value.lastIndexOf("\n")-1):(this.line=0,this.start=0),this.end=this.start+this.value.length}var o=function(e,t){for(var n=arguments.length>2&&arguments[2]!==undefined?arguments[2]:{},o=[new i("string",e)],s=0;s<t.length;s++)for(var a=t[s],u=a.test.ignoreCase?"ig":"g",c=new RegExp(a.test.source,u),l=0;l<o.length;l++){var f=o[l],p=o[l-1];if("string"===f.type){for(var h=void 0,d=0,m=[],v=f.value;null!==(h=c.exec(v));)h.index>d&&(p=new i("string",v.slice(d,h.index),p),m.push(p)),p=new i("expression",h[0],p),h[0]=r(p),p.script=a.use.apply(n,h),m.push(p),d=h.index+h[0].length;d<v.length&&(p=new i("string",v.slice(d),p),m.push(p)),o.splice.apply(o,[l,1].concat(m)),l+=m.length-1}}return o};o.TYPE_STRING="string",o.TYPE_EXPRESSION="expression",o.TYPE_RAW="raw",o.TYPE_ESCAPE="escape",e.exports=o},function(e,t,n){"use strict";(function(t){function n(e){return"string"!=typeof e&&(e=e===undefined||null===e?"":"function"==typeof e?n(e.call(e)):JSON.stringify(e)),e}function r(e){var t=""+e,n=s.exec(t);if(!n)return e;var r="",i=void 0,o=void 0,a=void 0;for(i=n.index,o=0;i<t.length;i++){switch(t.charCodeAt(i)){case 34:a="&#34;";break;case 38:a="&#38;";break;case 39:a="&#39;";break;case 60:a="&#60;";break;case 62:a="&#62;";break;default:continue}o!==i&&(r+=t.substring(o,i)),o=i+1,r+=a}return o!==i?r+t.substring(o,i):r}/*! art-template@runtime | https://github.com/aui/art-template */ var i="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==t?t:{},o=Object.create(i),s=/["&'<>]/;o.$escape=function(e){return r(n(e))},o.$each=function(e,t){if(Array.isArray(e))for(var n=0,r=e.length;n<r;n++)t(e[n],n);else for(var i in e)t(e[i],i)},e.exports=o}).call(t,n(11))},function(e,t){var n;n=function(){return this}();try{n=n||Function("return this")()||(0,eval)("this")}catch(r){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){"use strict";var r=Object.prototype.toString,i=function(e){return null===e?"Null":r.call(e).slice(8,-1)},o=function s(e,t){var n=void 0,r=i(e);if("Object"===r?n=Object.create(t||{}):"Array"===r&&(n=[].concat(t||[])),n){for(var o in e)Object.hasOwnProperty.call(e,o)&&(n[o]=s(e[o],n[o]));return n}return e};e.exports=o},function(e,t,n){"use strict";var r=function(e,t,r,i){var o=n(0);return i=i.$extend({filename:i.resolveFilename(e,i),bail:!0,source:null}),o(i)(t,r)};e.exports=r},function(e,t,n){"use strict";var r=function(e){console.error(e.name,e.message)};e.exports=r},function(e,t,n){"use strict";var r={__data:Object.create(null),set:function(e,t){this.__data[e]=t},get:function(e){return this.__data[e]},reset:function(){this.__data={}}};e.exports=r},function(e,t,n){"use strict";var r="undefined"==typeof window,i=function(e){if(r){return n(3).readFileSync(e,"utf8")}var t=document.getElementById(e);return t.value||t.innerHTML};e.exports=i},function(e,t,n){"use strict";var r={test:/{{([@#]?)[ \t]*(\/?)([\w\W]*?)[ \t]*}}/,use:function(e,t,n,i){var o=this,s=o.options,a=o.getEsTokens(i),u=a.map(function(e){return e.value}),c={},l=void 0,f=!!t&&"raw",p=n+u.shift(),h=function(t,n){console.warn((s.filename||"anonymous")+":"+(e.line+1)+":"+(e.start+1)+"\nTemplate upgrade: {{"+t+"}} -> {{"+n+"}}")};switch("#"===t&&h("#value","@value"),p){case"set":i="var "+u.join("").trim();break;case"if":i="if("+u.join("").trim()+"){";break;case"else":var d=u.indexOf("if");~d?(u.splice(0,d+1),i="}else if("+u.join("").trim()+"){"):i="}else{";break;case"/if":i="}";break;case"each":l=r._split(a),l.shift(),"as"===l[1]&&(h("each object as value index","each object value index"),l.splice(1,1));i="$each("+(l[0]||"$data")+",function("+(l[1]||"$value")+","+(l[2]||"$index")+"){";break;case"/each":i="})";break;case"block":l=r._split(a),l.shift(),i="block("+l.join(",").trim()+",function(){";break;case"/block":i="})";break;case"echo":p="print",h("echo value","value");case"print":case"include":case"extend":if(0!==u.join("").trim().indexOf("(")){l=r._split(a),l.shift(),i=p+"("+l.join(",")+")";break}default:if(~u.indexOf("|")){var m=a.reduce(function(e,t){var n=t.value,r=t.type;return"|"===n?e.push([]):"whitespace"!==r&&"comment"!==r&&(e.length||e.push([]),":"===n&&1===e[e.length-1].length?h("value | filter: argv","value | filter argv"):e[e.length-1].push(t)),e},[]).map(function(e){return r._split(e)});i=m.reduce(function(e,t){var n=t.shift();return t.unshift(e),"$imports."+n+"("+t.join(",")+")"},m.shift().join(" ").trim())}f=f||"escape"}return c.code=i,c.output=f,c},_split:function(e){e=e.filter(function(e){var t=e.type;return"whitespace"!==t&&"comment"!==t});for(var t=0,n=e.shift(),r=/\]|\)/,i=[[n]];t<e.length;){var o=e[t];"punctuator"===o.type||"punctuator"===n.type&&!r.test(n.value)?i[i.length-1].push(o):i.push([o]),n=o,t++}return i.map(function(e){return e.map(function(e){return e.value}).join("")})}};e.exports=r},function(e,t,n){"use strict";var r={test:/<%(#?)((?:==|=#|[=-])?)[ \t]*([\w\W]*?)[ \t]*(-?)%>/,use:function(e,t,n,r){return n={"-":"raw","=":"escape","":!1,"==":"raw","=#":"raw"}[n],t&&(r="/*"+r+"*/",n=!1),{code:r,output:n}}};e.exports=r},function(e,t,n){"use strict";function r(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}var i="undefined"==typeof window,o=function(e,t){if(i){var o,s=n(20).minify,a=t.htmlMinifierOptions,u=t.rules.map(function(e){return e.test});(o=a.ignoreCustomFragments).push.apply(o,r(u)),e=s(e,a)}return e};e.exports=o},function(e,t){!function(e){e.noop=function(){}}("object"==typeof e&&"object"==typeof e.exports?e.exports:window)},function(e,t,n){"use strict";var r="undefined"==typeof window,i=/^\.+\//,o=function(e,t){if(r){var o=n(3),s=t.root,a=t.extname;if(i.test(e)){var u=t.filename,c=!u||e===u,l=c?s:o.dirname(u);e=o.resolve(l,e)}else e=o.resolve(s,e);o.extname(e)||(e+=a)}return e};e.exports=o},function(e,t,n){"use strict";function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function o(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function s(e){var t=e.name,n=e.source,r=e.path,i=e.line,o=e.column,s=e.generated,a=e.message;if(!n)return a;var u=n.split(/\n/),c=Math.max(i-3,0),l=Math.min(u.length,i+3),f=u.slice(c,l).map(function(e,t){var n=t+c+1;return(n===i?" >> ":" ")+n+"| "+e}).join("\n");return(r||"anonymous")+":"+i+":"+o+"\n"+f+"\n\n"+t+": "+a+(s?"\n generated: "+s:"")}var a=function(e){function t(e){r(this,t);var n=i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e.message));return n.name="TemplateError",n.message=s(e),Error.captureStackTrace&&Error.captureStackTrace(n,n.constructor),n}return o(t,e),t}(Error);e.exports=a},function(e,t,n){"use strict";e.exports=n(2)}])}); template.defaults.cache = false var rule = template.defaults.rules[0]; rule.test = new RegExp(rule.test.source.replace('<%', '<\\\?').replace('%>', '\\\?>')); // 插件 window.template.defaults.imports.mathRound = function (num1,num2) { return Math.round((num1/num2)*100)/100 }; window.template.defaults.imports.formatProductUrl = function (handle) { return "/products/" + handle }; window.template.defaults.imports.formatArticleUrl = function (handle) { return "/blog/" + handle }; window.template.defaults.imports.formatFileImageUrl = function(image, size) { if (!image) { return '' } if (image.indexOf('mp4') < 0) { return `${STORE_PARAMS.imageDomain}/${image}?x-oss-process=style/${size}x` } else { let arr = image.split('?') return `${STORE_PARAMS.imageDomain}/${arr[0]}?x-oss-process=style/${size}x&${arr[1]}` } } window.template.defaults.imports.formatImageSrc = function (image,path,width) { var imagePath = '' if( typeof image === 'string' ) { imagePath = image }else { imagePath = path ? path : image.url ? 'url' : image.src ? 'src' : '' } var imageWidth = width ? width : '{width}' if (!imagePath || !image[imagePath]) return STORE_PARAMS.defaultImage if (image[imagePath].indexOf('svg') > 0) { return `${STORE_PARAMS.imageDomain}/${image[imagePath]}` } if (image[imagePath].indexOf('mp4') < 0) { // 图片数据 return `${STORE_PARAMS.imageDomain}/${image[imagePath]}?x-oss-process=style/${imageWidth}x` } else { // 新视频数据 let arr = image[imagePath].split('?') return `${STORE_PARAMS.imageDomain}/${arr[0]}?x-oss-process=style/${imageWidth}x&${arr[1]}` } }; window.template.defaults.imports.formatImgSrc = function(imagePath, width) { if (!imagePath) return STORE_PARAMS.defaultImage if( imagePath.indexOf("svg") > 0 ) { return imagePath } if (imagePath.indexOf('mp4') < 0) { // 图片数据 return `${imagePath}?x-oss-process=style/${width}x` } else { // 新视频数据 let arr = imagePath.split('?') return `${arr[0]}?x-oss-process=style/${width}x&${arr[1]}` } } window.template.defaults.imports.moneyWithSymbol = function (price, type) { // return $.globalFinance(price) return window.template.defaults.imports.financeMoneyWithShopSymbol(price); }; window.template.defaults.imports.financeMoneyWithShopSymbol= function (num, type) { type = type || 'amount' return Shoptop.APPS_EVENT.globalFinance(num, type) } window.template.defaults.imports.format = function (number, type) { var formatMap = { amount: { n: 2, x: 3, s: ',', c: '.' }, amount_no_decimals: { n: 0, x: 3, s: ',', c: '' }, amount_with_comma_separator: { n: 2, x: 3, s: '.', c: ',' }, amount_no_decimals_with_comma_separator: { n: 0, x: 3, s: '.', c: '' }, amount_with_apostrophe_separator: { n: 2, x: 3, s: "'", c: '.' } } var config = formatMap[type] || 'amount' var re = '\\d(?=(\\d{' + (config.x || 3) + '})+' + (config.n > 0 ? '\\D' : '$') + ')' var num if (config.n === 0) { num = number.toFixed(0) } else { num = number.toFixed(config.n + 1).slice(0, -1) } return (config.c ? num.replace('.', config.c) : num).replace(new RegExp(re, 'g'), '$&' + (config.s || ',')) }; window.template.defaults.imports.times = function(val1, val2) { return val1 * val2 } window.template.defaults.imports.floor = function(val) { return Math.floor(val) } window.template.defaults.imports.getSecondImage = function(product) { try{ var secondImage = null if( product.images.length > 1 ) { secondImage = product.images[1].imageData if( secondImage.url.indexOf("video=") >= 0) { if(product.images.length >2 ) { secondImage = product.images[1].imageData }else { secondImage = null } } } return secondImage }catch(error) { return '' } } window.template.defaults.imports.getImagePaddingBottom = function (width, height) { if (width === undefined || height === undefined) { return '100%' } else { return Math.round((height / width) * 10000) / 100 + '%' } } window.template.defaults.imports.JSON_Stringify = function (value) { if( value ) { return JSON.stringify(value) } return '' } window.template.defaults.imports.JSON_PARSE = function (value) { if( value ) { return JSON.parse(value) } return '' } window.template.defaults.imports.bgset = function(image,path){ var scope = [48, 180, 360, 540, 720, 900, 1024, 1280, 1366, 1440, 1536, 1600, 1920, 2056] var str = '' var imageUrl = window.template.defaults.imports.formatImageSrc(image,path) for (var i = 0; i < scope.length; i++) { var item = scope[i] str += `${imageUrl.replace('{width}', item)} ${item}w,` } return str } window.template.defaults.imports.getI18n = function (label, obj) { var keys = Object.keys(obj); for (var i in keys) { label = label.replace(keys[i], obj[keys[i]]); } return label; }; window.template.defaults.imports.t = function(keyStr, result) { try { var str = keyStr if (!result) return str return str.replace(/{{(.+?)}}/g, (_, g1) => { if (result[g1.trim()] == 0) { return result[g1.trim()] } else { return result[g1.trim()] || g1 } }) } catch (error) { return '' } } </script> <yn-lg-cars-right-fixed-btn></yn-lg-cars-right-fixed-btn> <script> class YnLgCarsRightFixedBtn extends HTMLElement { constructor() { super() this._root = this.attachShadow({ mode: 'open' }) const html = this.getTemplate() this._root.innerHTML = html } getTemplate() { return ` <style> .fixed-right-icons { left: auto; top: auto; position: fixed; z-index: 2000; right: 0; bottom: 40%; } .fixed-right-icons ul { list-style: none; margin: 0; padding: 0; } .fixed-right-icons ul li { position: relative; width: 52px; height: 52px; background-color: rgba(0, 0, 0, 0.5); } .fixed-right-icons a { width: 100%; height: 100%; color: #fff; position: absolute; top: 0; right: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; overflow-y: hidden; overflow: initial; text-decoration: none; } .fixed-right-icons svg { width: 24px; height: 24px; } .fixed-right-icons i { display: inline-block; } .fixed-right-icons .sidetitle { display: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 16px; color: #fff; } .fixed-right-icons .displayText { display: none; } .fixed-right-icons .sideicon { height: 24px; width: 24px; } .fixed-right-icons ul li .sideitem.sidebox:hover { background-color: rgb(51,128,245,1); width: 332px; transition: width .1s; justify-content: normal; align-items: center; flex-direction: row; } .fixed-right-icons ul li .sideitem.sidebox:hover .sideicon { margin: 0 10px; float: left; } .fixed-right-icons ul li .sideitem.sidebox:hover .sidetitle { display: block; } </style> <div class="fixed-right-icons"> <ul> <li> <a class="sidebox sideitem" href="tel:861000000016" target=""> <i class="sideicon"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <path fill="#ffffff" d="M21.2 11c-.14 0-.28-.02-.42-.06-.45-.11-.74-.46-.98-.7l-.18-.17c-.27-.26-.6-.52-.92-.78a14.44 14.44 0 0 0-3.2-1.85c-2.67-1.1-8.13-.14-9.85 1.71-1.25 1.33-2.24 1.88-3.2 1.82-.74-.06-1.42-.49-2.02-1.33-1.1-1.53.15-3.4 1.04-4.3C3.8 3.16 12.05 2.5 17.32 3.36c2.24.4 5.07 1.21 6.02 3 .33.64.69 1.45.66 2.35a2.26 2.26 0 0 1-1.37 1.96c-.3.15-.6.2-.87.26l-.06.03c-.16.02-.33.03-.5.03Z" /> <path fill="#ffffff" d="m21.21 14.49-4.1-5.42A5.72 5.72 0 0 0 12.5 7c-1.9 0-3.65.78-4.61 2.07L3.78 14.5a3.54 3.54 0 0 0-.44 3.72C4.15 19.9 6.14 21 8.42 21h8.21c2.3 0 4.27-1.1 5.02-2.79.59-1.23.43-2.59-.44-3.72Zm-8.53 1.58c-.42 0-.83-.13-1.18-.37a2.19 2.19 0 0 1-.77-.99 2.29 2.29 0 0 1 .45-2.4c.3-.3.68-.51 1.09-.6.4-.08.83-.04 1.22.13.39.16.72.45.95.8a2.27 2.27 0 0 1-.27 2.79c-.4.41-.93.64-1.5.64Z" /> </svg> </i> <p class="displayText">电话</p> <p class="sidetitle">021-2312-0688</p> </a> </li> <li> <a class="sidebox sideitem" href="javascript:;" target="_parent"> <i class="sideicon"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M11.9975 2H12.0025C17.5167 2 22 6.48583 22 12C22 17.5142 17.5158 22 12.0025 22C9.96917 22 8.08251 21.3942 6.50251 20.3483L2.65834 21.5767L3.90418 17.8608C2.66378 16.1587 1.99691 14.1061 2.00001 12C2.00001 6.48583 6.48418 2 11.9975 2ZM9.13667 7.49667C8.94584 7.04083 8.80084 7.02333 8.51167 7.01167C8.40181 7.00452 8.29177 7.00063 8.18167 7C7.80501 7 7.41167 7.11 7.17334 7.3525C6.88584 7.64667 6.16668 8.33333 6.16668 9.74417C6.16668 11.1533 7.19751 12.5167 7.33584 12.7075C7.48084 12.8975 9.34584 15.8325 12.24 17.0283C14.5042 17.9642 15.1758 17.8775 15.6917 17.7675C16.4442 17.6058 17.3875 17.0508 17.625 16.3817C17.8625 15.7108 17.8625 15.1392 17.7933 15.0175C17.7233 14.8967 17.5325 14.8275 17.2433 14.6825C16.9533 14.5383 15.5467 13.845 15.28 13.7525C15.0192 13.655 14.7708 13.6892 14.5742 13.9667C14.2958 14.3533 14.0242 14.7467 13.8033 14.9833C13.63 15.1683 13.3458 15.1917 13.1092 15.0933C12.7908 14.96 11.8992 14.6483 10.7983 13.6717C9.94751 12.915 9.36834 11.9733 9.20084 11.6908C9.03251 11.4017 9.18334 11.2342 9.31667 11.0783C9.46084 10.8992 9.60001 10.7725 9.74501 10.605C9.89001 10.4375 9.97001 10.3508 10.0633 10.1542C10.1617 9.96333 10.0925 9.76667 10.0225 9.6225C9.95334 9.47833 9.37417 8.06833 9.13667 7.4975V7.49667Z" fill="#ffffff" /> </svg> </i> <p class="displayText">Whatsapp</p> <p class="sidetitle">+86 345234652347</p> </a> </li> <li> <a class="sidebox sideitem" href="mailto:anshanfan@vip.163.com" target="_parent"> <i class="sideicon"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"> <path fill="#ffffff" fill-rule="evenodd" d="M20 5H4c-.8 0-1.56.3-2.12.83a2.74 2.74 0 0 0-.88 2v10.35c0 .75.32 1.46.88 2A3.1 3.1 0 0 0 4 21h16c.8 0 1.56-.3 2.12-.83s.88-1.24.88-2V7.83a2.68 2.68 0 0 0-.88-2A3.02 3.02 0 0 0 20 5Zm-.44 4.04a.53.53 0 0 0-.48.04l-7.06 4.2-7.1-4.2-.05-.03a.53.53 0 0 0-.48.03.76.76 0 0 0-.34.43c-.06.2-.07.42 0 .61.06.2.17.36.33.45l7.37 4.35.07.04c.15.06.33.05.48-.04l7.33-4.36.05-.04c.15-.1.25-.28.3-.48.04-.2.02-.42-.06-.6a.71.71 0 0 0-.36-.4Z" clip-rule="evenodd" /> </svg> </i> <p class="displayText">邮箱</p> <p class="sidetitle"> 67819028@gmail.com</p> </a> </li> <li> <a class="sideitem" href="javascript:window.scrollTo({left:0,top:0,behavior:'smooth'})" target=""> <i class="sideicon"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 22 22"> <g clip-path="url(#a)"> <path fill="#ffffff" fill-rule="evenodd" d="M0 11a11 11 0 1 1 22 0 11 11 0 0 1-22 0Zm15.03.97-3.5-3.5a.75.75 0 0 0-1.06 0l-3.5 3.5a.75.75 0 1 0 1.06 1.06l2.22-2.22V16a.75.75 0 0 0 1.5 0v-5.19l2.22 2.22a.75.75 0 1 0 1.06-1.06ZM6.75 6a.75.75 0 0 0 0 1.5h8.5a.75.75 0 0 0 0-1.5h-8.5Z" clip-rule="evenodd" /> </g> <defs> <clipPath id="a"> <path fill="#ffffff" d="M0 0h22v22H0z" /> </clipPath> </defs> </svg> </i> <p class="displayText">返回顶部</p> <p class="sidetitle"></p> </a> </li> </ul> </div>` } } customElements.define("yn-lg-cars-right-fixed-btn", YnLgCarsRightFixedBtn) </script><script>(function () { var level2 = []; var level3 = ["enquiry-4c97b424.js"]; function asyncLoad(urls) { for (var i = 0; i < urls.length; i++) { var s = document.createElement('script'); s.type = 'text/javascript'; s.defer = true; s.src = STORE_PARAMS.cdnDomain + "/apps/" + urls[i]; var x = document.querySelector('body'); x.appendChild(s); } }; asyncLoad(level2) document.addEventListener('DOMContentLoaded', function() {asyncLoad(level3)}); })();</script> </body> <script src="https://static.staticxt.com/npm/swiper@8.4.6/swiper-bundle.min.js"></script> <script src="https://static.staticxt.com/npm/jquery@2.2.3/jquery.min.js"></script> <script src="https://static.staticxt.com/npm/countup.js@2.7.0/countUp.min.js"></script> <script src="https://static.staticxt.com/npm/countup.js@2.7.0/countUp.min.js"></script> <script> // class DetailsDisclosure extends HTMLElement { // constructor() { // super(); // this.$mainDetails = this.querySelector('details'); // this.content = this.$mainDetails.querySelector('summary').nextElementSibling; // this.$mainDetails.addEventListener('focusout', this.onFocusOut.bind(this)); // this.$mainDetails.addEventListener('toggle', this.onToggle.bind(this)); // } // onFocusOut() { // setTimeout(() => { // if (!this.contains(document.activeElement)) this.close(); // }) // } // onToggle() { // if (!this.animations) this.animations = this.content.getAnimations(); // if (this.$mainDetails.hasAttribute('open')) { // this.animations.forEach(animation => animation.play()); // } else { // this.animations.forEach(animation => animation.cancel()); // } // } // close() { // this.$mainDetails.removeAttribute('open'); // this.$mainDetails.querySelector('summary').setAttribute('aria-expanded', false); // } // } // customElements.define('details-disclosure', DetailsDisclosure); // class HeaderMenu extends DetailsDisclosure { // constructor() { // super(); // this.header = document.querySelector('.header-wrapper'); // } // onToggle() { // if (!this.header) return; // this.header.preventHide = this.$mainDetails.open; // if (document.documentElement.style.getPropertyValue('--header-bottom-position-desktop') !== '') return; // document.documentElement.style.setProperty('--header-bottom-position-desktop', `${Math.floor(this.header.getBoundingClientRect().bottom)}px`); // } // } // customElements.define('header-menu', HeaderMenu); class HeaderMenu extends HTMLElement { constructor() { super(); this.$mainDetails = this.querySelector('details'); this.header = document.querySelector('.header-wrapper'); this.content = this.$mainDetails.querySelector('summary').nextElementSibling; this.$mainDetails.addEventListener('focusout', this.onFocusOut.bind(this)); this.$mainDetails.addEventListener('toggle', this.onToggle.bind(this)); } onFocusOut() { setTimeout(() => { if (!this.contains(document.activeElement)) this.close(); }) } onToggle() { if (!this.animations) this.animations = this.content.getAnimations(); if (this.$mainDetails.hasAttribute('open')) { this.animations.forEach(animation => animation.play()); } else { this.animations.forEach(animation => animation.cancel()); } if (!this.header) return; this.header.preventHide = this.$mainDetails.open; if (document.documentElement.style.getPropertyValue('--header-bottom-position-desktop') !== '') return; document.documentElement.style.setProperty('--header-bottom-position-desktop', `${Math.floor(this.header.getBoundingClientRect().bottom)}px`); } close() { this.$mainDetails.removeAttribute('open'); this.$mainDetails.querySelector('summary').setAttribute('aria-expanded', false); } } customElements.define('header-menu', HeaderMenu); </script> <style> .pagination__item { color: rgb(var(--color-foreground)); display: inline-flex; justify-content: center; align-items: center; position: relative; height: 4.4rem; width: 100%; padding: 0; text-decoration: none; } .pagination-page.link { cursor: pointer; } .pagination__item svg { width: 1.2rem; } .pagination--active .pagination__item:after { content: ""; display: block; width: 2rem; position: absolute; bottom: 8px; left: 50%; transform: translate(-50%); background-color: currentColor; } .pagination__item:after { height: .1rem; } .jump { flex: 1 0 4.4rem; max-width: 4.4rem; } .cursor-pointer .link { cursor: pointer; } .pagination-more { flex: 1 0 4.4rem; max-width: 4.4rem; } </style> <div class="pagination-wrap my-5"></div> <script type="text/html" id="pagination_art_tpl"> <div class="flex justify-center notranslate"> <span class="jump {{prePage ? 'cursor-pointer' : 'disabled'}}"> <a class="link pagination__item rotate-90 pagination-prev"><svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg></a> </span> {{each showPageBtn}} {{if($value > 0)}} <span class="jump {{current == $value ? 'pagination--active' : '' }}"> <a class="link pagination__item pagination-page" data-index="{{$value}}">{{$value}}</a> </span> {{else}} <span class="jump opacity-70 pagination-more"> <a class="link pagination__item">•••</a> </span> {{/if}} {{/each}} <span class="jump {{nextPage ? 'cursor-pointer' : 'disabled'}}"> <a class="link pagination__item -rotate-90 pagination-next"><svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg></a> </span> </div> </script> <script type="text/html" id="product-art-tpl"> {{ set obj = { square:1, portrait:1.25 } }} {{ set paddingBottom = '100%' }} {{ set goodsImage = product_card.goodsImage }} {{ set scale = image_ratio == 'adapt' ? $imports.mathRound(goodsImage.height,goodsImage.width) : obj[image_ratio] }} {{ set paddingBottom = (scale || 1) * 100 + "%" }} {{ set secondImage = show_secondary_image ? $imports.getSecondImage(product_card) : "" }} {{ set imageClass = "" }} {{ set secondImageClass = "" }} {{ set productHref = '/products/' + product_card.handle }} {{ set from_on = product_card.priceMax != product_card.priceMin}} {{ set isShowOriginPrice = product_card.compareAtPrice > product_card.price }} {{ set sale_label_enabled = false }} {{ set sold_label_enabled = false }} {{ set card_text_alignment = "center" }} {{ set card_style = "card" }} {{ set card_color_scheme = "none" }} {{ set card_color_class = "color-none" }} {{ set hide_price = true }} {{ set badge_position = "bottom-left" }} {{ set sale_badge_color_scheme = "" }} <div class="product-card-wrap h-full g-card-product--var"> <div class=" h-full flex flex-col justify-between relative product-card--{{card_style}} {{card_style == 'card' ? 'gradient ' + card_color_class :''}}"> <div class="product-card-content product-card-content_{{card_style}}"> <div class="product-card relative"> <div class="product-card__top relative product-card-ratio {{card_style != 'card' ? 'gradient color-'+card_color_scheme : 'product-card__media_top_radius'}} {{card_style == 'card' ? '' : image_shape != 'default' ? 'g-card-product--filter' : 'g-card-product'}}" style="--ratio-percent:{{paddingBottom}}"> <div class="product-card__media relative shape--{{image_shape}}"> <div class="media media--transparent media--hover-effect"> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" data-swatch-image="{{goodsImage.url}}" alt="{{goodsImage.alt || product_card.goodsTitle}}" data-sizes="auto" data-src="{{$imports.formatImageSrc(goodsImage)}}" class="product-card__img lazyload {{imageClass}}"> {{if secondImage}} <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==" alt="{{goodsImage.alt || product_card.goodsTitle}}" data-sizes="auto" data-src="{{$imports.formatImageSrc(secondImage)}}" class="product-card__img product-card__img-second lazyload {{secondImageClass}}"> {{/if}} </div> </div> <div class="product-card__sale"> <div class="product-card__badge {{badge_position}}"> {{if product_card.available }} {{if sale_label_enabled && isShowOriginPrice}} <span class="badge inline-block badge--sale">Sale</span> {{/if}} {{else}} {{if sold_label_enabled}} <span class="badge inline-block badge--sold-out">Sold Out</span> {{/if}} {{/if}} </div> </div> </div> <div class="product-card__bottom text-{{card_text_alignment}}"> <div class="product-card__info"> <h3 class="product-card__heading h5"> <a class="full-unstyled-link line-clamp-two" href="{{productHref}}">{{product_card.goodsTitle}}</a> </h3> {{if show_vendor && product_card.vendorName}} <div class="caption-with-letter-spacing light line-clamp-one">{{product_card.vendorName}}</div> {{/if}} {{if !hide_price}} <div class="product-card__price-wrap"> {{if isShowOriginPrice}} <span><s class="price-item price-item--regular money">{{$imports.moneyWithSymbol(product_card.compareAtPrice)}}</s></span> {{/if}} <span class="price-item price-item--sale price-item--last"> {{if from_on}} <span>from</span> {{/if}} <span class="money">{{$imports.moneyWithSymbol(product_card.price)}}</span> </span> </div> {{/if}} </div> </div> </div> {{if product_card.extend && product_card.extend.colorCard && product_card.extend.colorCard.length}} <product-card-swatch> <div class="product-block__swatch flex justify-{{card_text_alignment}} mt-4 mb-4" data-spu-id="{{product_card.spuId}}"> <? var items = product_card.extend.colorCard[0].items; var itemsLen = items.length; var arrLen = itemsLen > 4 ? 4 : itemsLen; var specName = product_card.extend.colorCard[0].specName var position = product_card.specs.find(item => item.spuSpecName == specName).position ?> <? for (let index = 0; index < arrLen; index++) { ?> <? const element = items[index]; ?> <? var selectedItem = product_card.skus.find(atr => atr[`specOption${position}`] == element.specValue); var dataImage = selectedItem ? $imports.JSON_Stringify({ skuId: selectedItem.skuId, skuImage: selectedItem.skuImage }) : '' ?> <a href="<?= selectedItem ? `${productHref}?variant=${selectedItem.skuId}` : productHref ?>" class="product-info__variants-swatch product-info__variants-swatch-modal" data-swatch-skus="{{dataImage}}"> <input type="radio" class="hidden product-info__variants_radio" value="{{element.specValue}}"> <label class="product-info__variants-swatch_label border border-solid border-option transition-colors flex items-center justify-center rounded-global-1/2 cursor-pointer"> <span class="product__variants-swatch-list" style="<?= element.showType == 2 ? `background-image: url('${$imports.formatFileImageUrl(element.showValue, 180)}')` : `background-color:${element.showValue}` ?>"></span> </label> </a> <?}?> {{if itemsLen > 4}} <a href="{{productHref}}" class="mt-2.5 mx-1 text-xs leading-none text-current no-underline flex items-center justify-center"> <span>+ {{itemsLen - 4}}</span> </a> {{/if}} </div> </product-card-swatch> {{/if}} {{if show_quick_add}} <div class="quick-add"> <rdfy-quick-buy data-spu-id="{{product_card.spuId}}"> <button type="submit" name="add" class="quick-add__submit button w-full flex button--secondary"> Choose options <div class="loading-overlay__spinner hidden"> <svg class="spinner" x="0px" y="0px" viewBox="0 0 150 150"> <circle class="path" cx="75" cy="75" r="60" /> </svg> </div> </button> </rdfy-quick-buy> </div> {{/if}} </div> </div> </div> </script> <style> .quick-buy-modal__content { background: rgb(var(--color-background)); max-width: var(--page-width); max-height: 85vh; overflow-y: auto; overflow: hidden; } .quick-buy-modal__media { max-width: 54%; width: calc(54% - var(--grid-desktop-horizontal-spacing) / 2); max-height: 85vh; overflow-y: scroll; } .quick-buy-modal__info { padding-left: 4rem; max-width: 45%; width: calc(45% - var(--grid-desktop-horizontal-spacing) / 2); max-height: 85vh; overflow-y: scroll; } [dir="rtl"] .quick-buy-modal__info { padding-left: 0; padding-right: 4rem; } .quick-buy-modal__content-wrap { padding: 4rem 2.5rem 2.5rem 2.5rem; display: flex; max-height: 75vh; } .quick-buy-modal__content .product-popup-dialog__close-wrap { position: absolute; right: 1rem; top: 1rem; z-index: 99; } .quick-buy-modal__container > * + * { margin: 1.5rem 0; } .quick-buy-modal__content { width: 70%; max-height: 85vh; } @media screen and (min-width: 750px) { .quick-buy-modal__swiper .loading-overlay__spinner { top: 50%; left: 50%; transform: translate(-50%,-50%); position: absolute; display: flex; align-items: center; height: 48px; width: 48px; } .quick-buy-modal__swiper .loading-overlay__spinner .path { stroke: rgb(var(--color-base-accent-1)); opacity: 0.75; } .spinner { animation: rotator 1.4s linear infinite; } } @media screen and (max-width: 990px) { .quick-buy-modal__content-wrap { overflow-y: scroll; } .quick-buy-modal__content { width: 95%; } .quick-buy-modal__media { width: 100%; max-width: 100%; } .quick-buy-modal__info { width: 100%; max-width: 100%; padding: 0; padding-top: 4rem; } } .image-magnify-full-size { cursor: zoom-out; z-index: 1; margin: 0; border-radius: calc(var(--media-radius) - var(--media-border-width)); } .quick-buy-modal__swiper-button button { position: absolute; top: 50%; width: 4rem; height: 4rem; color: rgb(var(--color-secondary-button-text)); border: 1px solid rgb(var(--color-secondary-button-text)); background-color: rgba(var(--color-background),.1); border-radius: 50%; transition: all .3s ease; transform: translateY(-2rem); cursor: pointer; } .quick-buy-modal__swiper-next { right: 2rem; } .quick-buy-modal__swiper-prev { left: 2rem; } .quick-buy-modal__swiper-button button[disabled] { opacity: .3; cursor: not-allowed; } .swiper-zoom-container video { max-height: 80%; } </style> <script type="text/html" id="quick-buy-modal-tpl"> {{ set addToCartLan = "Add to Cart" }} {{ set soldOutLan = "Sold Out" }} <style> .product-media-container.constrain-height .media { padding-top: calc(1 / var(--ratio) * 100%) } </style> <dialog class="rdfy-dialog modal items-center" id="quickBuy-{{product.spuId}}"> <div class="quick-buy-modal__content relative g-card-popup"> <form method="dialog" class="product-popup-dialog__close-wrap"> <button class="product-popup-dialog__close"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" class="icon icon-close" fill="none" viewBox="0 0 18 17" > <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"> </svg> </button> </form> <div class="quick-buy-modal__content-wrap flex flex-wrap md:flex-nowrap"> <div class="quick-buy-modal__media no-scroll-bar"> <rdfy-quick-buy-media> <div class="swiper quick-buy-modal__swiper"> <div class="swiper-wrapper media-fit-cover"> {{each product.images image imageIndex}} <div class="swiper-slide"> <div class="product-media-container media-type-image g-card-media g-card-media--no-shadow gradient constrain-height" style="--ratio:{{image.imageData.width/image.imageData.height}}"> <div class="product__media media media--transparent relative"> <radf-media class="block media media--transparent" media-url="{{ image.imageData.url }}" media-alt="{{ image.imageData.alt }}" match="{{ image.imageData.url }}"> </radf-media> </div> <div class="loading-overlay__spinner hidden"> <svg aria-hidden="true" focusable="false" class="spinner" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg"> <circle class="path" fill="none" stroke-width="4" cx="33" cy="33" r="30"></circle> </svg> </div> </div> </div> {{/each}} </div> <div class="quick-buy-modal__swiper-button"> <button class="quick-buy-modal__swiper-prev flex items-center justify-center z-1" aria-label="Previous slide"> <svg aria-hidden="true" focusable="false" width="16" height="16" class="icon icon-caret rotate-90" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"></path> </svg> </button> <button class="quick-buy-modal__swiper-next flex items-center justify-center z-1" aria-label="Previous slide"> <svg aria-hidden="true" focusable="false" width="16" height="16" class="icon icon-caret -rotate-90" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"></path> </svg> </button> </div> </div> </rdfy-quick-buy-media> </div> <div class="quick-buy-modal__info no-scroll-bar"> <product-info mode="quick-buy" class="quick-buy-modal__container"> <!-- 标题 --> <div class="product__title"> <h1 class="m-0">{{product.goodsTitle}}</h1> </div> <!-- 副标题 --> <div class="product__subtitle">{{product.goodsBrief}}</div> <!-- 价格 --> <div class="product-info__header_price-wrapper price--large"> <div class="flex"> <div class="price__container flex"> <div class="product-info__header_price money text-1.3 md:text-1.6 leading-1.5 mr-4">{{$imports.moneyWithSymbol(selectedSku.price)}}</div> <del class="product-info__header_compare-at-price money mr-4 {{selectedSku.compareAtPrice > selectedSku.price ? '' :'hidden'}}">{{$imports.moneyWithSymbol(selectedSku.compareAtPrice)}}</del> </div> <span class="badge inline-block badge--sale price__badge-sale {{selectedSku.price < selectedSku.compareAtPrice ? '' : 'hidden'}}">Sale</span> <span class="badge inline-block badge--sold-out price__badge-sold-out {{selectedSku.available ? ' hidden' : ''}}">Sold Out</span> </div> </div> <!-- SKU选择器 --> {{@ include('product-variant-picker-tpl', { product:product, selectedSku: selectedSku })}} <!-- 数量选择器 --> <div class="product-form__quantity product-info__qty_container"> <label for="quantity__label" class="tracking-tighter leading-1.5 text-1.3 mb-2.5">Qty</label> <quantity-input class="quantity"> <button class="quantity__button disabled" name="minus" type="button"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-minus" fill="none" viewBox="0 0 10 2"> <path fill-rule="evenodd" clip-rule="evenodd" d="M.5 1C.5.7.7.5 1 .5h8a.5.5 0 110 1H1A.5.5 0 01.5 1z" fill="currentColor"> </svg></button> <input class="quantity__input" type="number" name="quantity" id="product-info-quantity" data-min="1" min="1" step="1" value="1" form="product-detail__model-form" max="null"> <button class="quantity__button" name="plus" type="button"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-plus" fill="none" viewBox="0 0 10 10"> <path fill-rule="evenodd" clip-rule="evenodd" d="M1 4.51a.5.5 0 000 1h3.5l.01 3.5a.5.5 0 001-.01V5.5l3.5-.01a.5.5 0 00-.01-1H5.5L5.49.99a.5.5 0 00-1 .01v3.5l-3.5.01H1z" fill="currentColor"> </svg></button> </quantity-input> </div> <!-- 购买按钮 --> <div class="product-info__btn"> <product-form mode="quick-buy" class=""> <div class="product-form__msg-wrap flex items-center text-1.2 hidden"> <svg class="mr-4" width="18" height="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="#EB001B"> <path fill-rule="evenodd" d="M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zM12 8.25a.75.75 0 01.75.75v3.75a.75.75 0 01-1.5 0V9a.75.75 0 01.75-.75zm0 8.25a.75.75 0 100-1.5.75.75 0 000 1.5z" clip-rule="evenodd" /> </svg> <span class="product-form__msg-content"></span> </div> <form id="product-detail__model-form" data-type="add-to-cart-form"> <input type="hidden" name="spuId" value="{{product.spuId}}"> <input type="hidden" name="skuId" value="{{selectedSku.skuId}}"> <input type="hidden" name="merchantId" value=""> <div> <button type="submit" class="product-form__submit button button--secondary flex w-full mb-4" data-click="addToCart" data-on-sale="Add to Cart" data-adding="Adding" data-added="Added" {{product.available ? '' :'disabled'}} > <span>{{ product.available ? addToCartLan : soldOutLan }}</span> </button> <button type="button" class="product-form__payment button g-button-primary w-full mb-4 {{product.available ? '' : 'is-hidden'}}" data-click="submit">Buy Now</button> <radf-paypal-component data-id="product-dialog-paypal-id"> <div class="btn-paypal" id="product-dialog-paypal-id"></div> </radf-paypal-component> </div> </form> </product-form> </div> <a href="/products/{{product.handle}}" class="link product__view-details animate-arrow">View More Products <svg viewBox="0 0 14 10" fill="none" aria-hidden="true" focusable="false" class="icon icon-arrow ml-3.5" xmlns="http://www.w3.org/2000/svg"> <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"> </path> </svg> </a> </product-info> </div> </div> </div> <form method="dialog" class="modal-backdrop"><button></button></form> </dialog> </script> <script type="text/html" id="product-variant-picker-tpl"> <style> .product-form__input { flex: 0 0 100%; padding: 0; margin: 0 0 1.2rem 0; max-width: 44rem; min-width: fit-content; border: none; flex-wrap: wrap; } .product-form__input .select { max-width: 25rem; } .product-form__input input[type='radio'] { clip: rect(0, 0, 0, 0); overflow: hidden; position: absolute; height: 1px; width: 1px; } .product-form__input input[type='radio']+label { border: var(--variant-pills-border-width) solid rgba(var(--color-foreground), var(--variant-pills-border-opacity)); background-color: rgb(var(--color-background)); color: rgba(var(--color-foreground)); border-radius: var(--variant-pills-radius); color: rgb(var(--color-foreground)); display: inline-block; margin: 0.7rem 0.5rem 0.2rem 0; padding: 1rem 2rem; font-size: 1.4rem; letter-spacing: 0.1rem; line-height: 1; text-align: center; transition: border var(--duration-short) ease; cursor: pointer; position: relative; } .product-form__input input[type='radio']+label:hover { border-color: rgb(var(--color-foreground)); } .product-form__input input[type='radio']:checked+label { background-color: rgb(var(--color-foreground)); color: rgb(var(--color-background)); } .product-info__variants-swatch input[type='radio']+label { background: none; border: 2px solid rgba(var(--color-foreground), .15); border-radius: var(--color-card-style-radius); font-size: 0; margin: 10px 10px 0 0; min-width: 0; padding: 2px; } .product-info__variants-swatch label span { background-position: 50%; background-repeat: no-repeat; background-size: cover; border-radius: var(--color-card-style-radius); cursor: pointer; display: inline-block; overflow: hidden; } .product__variants-swatch-info { height: var(--color-card-detail-m-size); width: var(--color-card-detail-m-size) } .product__variants-swatch-list { height: var(--color-card-list-m-size); width: var(--color-card-list-m-size) } @media (min-width: 768px) { .product__variants-swatch-info { height: var(--color-card-detail-p-size); width: var(--color-card-detail-p-size) } .product__variants-swatch-list { height: var(--color-card-list-p-size); width: var(--color-card-list-p-size) } } .product-info__variants_radio:checked~.product-info__variants-swatch_label { background: none !important; border-color: rgb(var(--color-foreground)); } </style> {{ set variantStyle = "dropdown" }} <variants-picker class="product-info__variants-wrap"> <div class="space-y-6 product-info__variants"> {{each product.specs item specsIndex}} {{if item.colorCardIndex >= 0 }} <fieldset class="product-form__input flex"> <legend class="form__label product-info__variants_title" style="width:100%;" for="{{`${product.spuId}-${specsIndex}`}}">{{item.spuSpecName}}</legend> {{each product.extend.colorCard[item.colorCardIndex].items element index}} <div class="relative flex items-center product-info__variants_value product-info__variants-swatch"> <input type="radio" form="product-detail__page-form" class="hidden product-info__variants_radio" name="{{`option-${specsIndex}-${product.spuId}`}}" value="{{element.specValue}}" id="{{`${product.spuId}-${specsIndex}-opt-${index}`}}" {{element.specValue == selectedSku[`specOption${item.position}`] ? "checked" :''}}> <label for="{{`${product.spuId}-${specsIndex}-opt-${index}`}}" data-variants-value="{{element.specValue}}" class="product-info__variants-swatch_label text-xs border border-solid border-option transition-colors flex items-center justify-center cursor-pointer"> <span class="product__variants-swatch-info" style="{{ element.showType == 2 ? 'background-image: url(' + $imports.formatFileImageUrl(element.showValue,180) + ')' : 'background-color:' + element.showValue }}"></span> </label> </div> {{/each}} </fieldset> {{else if variantStyle == "button"}} <fieldset class="product-form__input"> <legend class="form__label product-info__variants_title" style="width:100%;" for="{{`${product.spuId}-${specsIndex}`}}">{{item.spuSpecName}}</legend> {{each item.spuSpecValues element index}} <input type="radio" form="product-detail__page-form" name="{{`option-${specsIndex}-${product.spuId}`}}" value="{{element}}" id="{{`${product.spuId}-${specsIndex}-opt-${index}`}}" {{element == selectedSku[`specOption${item.position}`] ? "checked" :''}}> <label for="{{`${product.spuId}-${specsIndex}-opt-${index}`}}" data-variants-value="{{element}}">{{element}}</label> {{/each}} </fieldset> {{else}} <div class="product-form__input product-form__input--dropdown mb-6"> <label class="block mb-2.5 product-info__variants_title" style="width:100%;" for="{{`${product.spuId}-${specsIndex}`}}">{{item.spuSpecName}}</label> <div class="select"> <select class="select__select px-8" form="product-detail__page-form"> {{each item.spuSpecValues element index}} <option name="{{`option-${specsIndex}-${product.spuId}`}}" id="{{`${product.spuId}-${specsIndex}-opt-${index}`}}" class=" product-info__variants_value" value="{{element}}"> {{element}} </option> {{/each}} </select> <svg aria-hidden="true" focusable="false" class="icon icon-caret" viewBox="0 0 10 6"> <path fill-rule="evenodd" clip-rule="evenodd" d="M9.354.646a.5.5 0 00-.708 0L5 4.293 1.354.646a.5.5 0 00-.708.708l4 4a.5.5 0 00.708 0l4-4a.5.5 0 000-.708z" fill="currentColor"> </svg> </div> </div> {{/if}} {{/each}} </div> <div class="plugin__size_guide"></div> </variants-picker> </script> <script type="text/html" id="video-modal-tpl"> <style> .modal-video { background: rgba(var(--color-foreground), 0.2); box-sizing: border-box; height: 100%; left: 0; margin: 0 auto; opacity: 0; overflow: auto; position: fixed; top: 0; /* visibility: hidden; */ width: 100%; z-index: -1; } .modal-video[open] { opacity: 1; visibility: visible; z-index: 101; } .modal-video__content { background-color: rgb(var(--color-background)); height: 100%; margin: 0; overflow: auto; padding: 0; position: absolute; width: 100%; } .modal-video__toggle { align-items: center; background-color: rgb(var(--color-background)); border-radius: 50%; border: 0.1rem solid rgba(var(--color-foreground), 0.1); color: rgba(var(--color-foreground), 0.55); cursor: pointer; display: flex; justify-content: center; margin: 0 0 0 auto; padding: 1.2rem; position: fixed; right: 0.5rem; top: 2rem; width: 4rem; z-index: 2; } @media screen and (min-width: 750px) { .modal-video__toggle { right: 4.8rem; top: 3.5rem; } } @media screen and (min-width: 990px) { .modal-video__toggle { right: 4.3rem; top: 3rem; } } .modal-video__toggle .icon { height: auto; margin: 0; width: 2.2rem; } .modal-video__content-info { height: calc(100% - 6rem); margin: 0 auto; padding-top: 8rem; width: calc(100% - 1rem); } @media screen and (min-width: 750px) { .modal-video__content-info { height: calc(100% - 7.5rem); padding-top: 9.5rem; width: calc(100% - 9.6rem); } } @media screen and (min-width: 990px) { .modal-video__content-info { height: calc(100% - 7rem); padding-top: 9rem; width: calc(100% - 8.6rem); } } .modal-video__video, .modal-video__video iframe { height: 100%; width: 100%; } .modal-video__video iframe { position: static; border: 0; } </style> <div id="PopupModal" class="modal-video media-modal color-background-1" open=""> <div class="modal-video__content" role="dialog" aria-label="Describe the video" aria-modal="true" tabindex="-1"> <button id="ModalClose" type="button" class="modal-video__toggle" aria-label="Close"> <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" class="icon icon-close" fill="none" viewBox="0 0 18 17"> <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"> </path> </svg> </button> <div class="modal-video__content-info"> <deferred-media class="modal-video__video template-popup" loaded="true"> <template> <iframe src="{{video.url}}" class="js-youtube" allow="autoplay; encrypted-media" allowfullscreen="" title="Describe the video"></iframe> </template> <iframe src="{{video.url}}" class="js-youtube" allow="autoplay; encrypted-media" allowfullscreen="" title="Describe the video"></iframe> </deferred-media> </div> </div> </div> </script> <script> const theme = { api: { addToCart: '/api/mbr/shopping/cart/add', batchCart: '/api/mbr/shopping/cart/batchAdd', preOrder: '/api/mbr/checkout/preOrder', syncCheckout: '/api/mbr/checkout/sync', cancelOrder: '/api/mbr/checkout/cancelOrder', search: '/api/mbr/goods/list', newsletters: '/api/mbr/user/newsletters', similarProducts: '/api/mbr/goods/similar', productDetail: '/api/mbr/goods', blogList: '/api/mbr/blog/articlePageByTopic', collectionProductList: '/api/mbr/collection/filters/cps', collectionFilterList: '/api/mbr/collection/filters', aliSign: '/api/mbr/file/ali/sign', createReview: '/api/mbr/goods/comment', productStar: '/api/mbr/goods/comment/count/star', reviewConfig: '/api/mbr/goods/comment/config' }, toggleModalStatus: function(status = true) { if (status) { document.body.classList.add('overflow-hidden') } else { document.body.classList.remove('overflow-hidden') } }, toQuery: function(obj) { const result = [] for (var k in obj) { result.push(encodeURIComponent(k) + '=' + encodeURIComponent(obj[k])) } return result.join('&') }, params: function(url) { url = url || window.location.href var params = {} url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(str, key, value) { try { params[key] = decodeURIComponent(value) } catch (e) { params[key] = value } }) return params }, isMobile: function() { return window.matchMedia('(max-width: 750px)').matches }, quickBuyProduct: {}, product: {}, getCookie: function(sName) { var oCrumbles = document.cookie.split(';') for (var i = 0; i < oCrumbles.length; i++) { var oPair = oCrumbles[i].split('=') var sKey = decodeURIComponent(oPair[0].trim()) var sValue = oPair.length > 1 ? oPair[1] : '' if (sKey == sName) { return decodeURIComponent(sValue) } } return '' }, ajaxError: function(response) { switch (response.errorCode) { case 401: window.safeHref = '/account/login?return_url=' + encodeURI(window.location.pathname) break default: // TODO 增加提示弹窗 // $.toast.show({ // content: response.msg, // type: 'error' // }); Promise.reject(`${response.errorCode} ${response.msg}`) } }, /** 临时从 url 上解析详细媒体信息,以后可能还会变 * @resource 文件资源,如 glb 等文件 * @poster 图片资源 */ mediaParse: function(url) { const result = { file: "", image: "", type: "" } const dto = this.params(String(url)) const fileName = url.split('?')[0] if (dto.media_type === "model3d") { result.image = `${STORE_PARAMS.imageDomain}/${fileName}` result.file = `${STORE_PARAMS.imageDomain}/${dto.sources}` result.type = "3d" } else if (dto.videosrc) { result.image = `${STORE_PARAMS.imageDomain}/${fileName}` result.file = `${STORE_PARAMS.imageDomain}/${dto.videosrc}.${dto.ext}` result.type = "video" } else { result.image = `${STORE_PARAMS.imageDomain}/${fileName}` result.file = `` result.type = "image" } return result }, rte: { wrapVideo: function(options) { var videoWrapClass = typeof options.videoWrapClass === "undefined" ? '' : options.videoWrapClass; for (var i = 0; i < options.$videos.length; i++) { var $videos = options.$videos[i] const params = theme.params($videos.getAttribute("data-src")) const videoSrc = `${STORE_PARAMS.imageDomain}/${params.videosrc}.${params.ext}` const poster = $videos.getAttribute("data-src") const html = `<video src="${videoSrc}" poster="${poster}" width="${params.width}" height="${params.height}" style="width: 100%;cursor: pointer;" muted autoplay loop x5-playsinline='true' playsinline='true' webkit-playsinline='true'></video>` const hNode = document.createRange().createContextualFragment(html) $videos.parentNode.replaceChild(hNode, $videos) } } }, headers: { 'Content-Type': 'application/json', 'store-locale': SHOPTOP.locale } } const UserAgents = theme.getCookie('User-Agents') || '' UserAgents && (theme.headers.Authorization = `Bearer ${UserAgents}`); // 富文本图片转视频 window.addEventListener('DOMContentLoaded', () => { const videoSelectors = '.rte img[data-src*="&ext=mp4"]' theme.rte.wrapVideo({ $videos: document.querySelectorAll(videoSelectors), videoWrapClass: 'rte__video-wrap' }) }) const createEventHub = () => ({ hub: Object.create(null), emit(event, data) { ; (this.hub[event] || []).forEach(handler => handler(data)) }, on(event, handler) { if (!this.hub[event]) this.hub[event] = [] this.hub[event].push(handler) }, off(event, handler) { const i = (this.hub[event] || []).findIndex(h => h === handler) if (i > -1) this.hub[event].splice(i, 1) if (this.hub[event].length === 0) delete this.hub[event] } }) window.RDFY_HUB = createEventHub() function redirectionPage() { // 保证C端加载 const key = 'decoratorId' const params = theme.params() const shop_env = params[key] if (!window.safeHref && !shop_env) { // if里面的代码针对C端,B端逻辑部分在owl中 Object.defineProperty(window, 'safeHref', { get: function() { return location.href }, set: function(value) { location.href = value }, configurable: true }) } } redirectionPage() function debounce(fn, wait) { let t return (...args) => { clearTimeout(t) t = setTimeout(() => fn.apply(this, args), wait) } } function throttle(fn, hold = 500) { let timeout let start = new Date() return function() { let context = this let args = arguments let curr = new Date() - 0 clearTimeout(timeout) if (curr - start >= hold) { fn.apply(context, args) start = curr } else { timeout = setTimeout(function() { fn.apply(context, args) }, hold) } } } document.querySelectorAll('[id^="Details-"] summary').forEach(summary => { summary.setAttribute('role', 'button') summary.setAttribute('aria-expanded', summary.parentNode.hasAttribute('open')) if (summary.nextElementSibling.getAttribute('id')) { summary.setAttribute('aria-controls', summary.nextElementSibling.id) } summary.addEventListener('click', event => { event.currentTarget.setAttribute('aria-expanded', !event.currentTarget.closest('details').hasAttribute('open')) }) if (summary.closest('header-drawer')) return summary.parentElement.addEventListener('keyup', onKeyUpEscape) }) function onKeyUpEscape(event) { if (event.code.toUpperCase() !== 'ESCAPE') return const openDetailsElement = event.target.closest('details[open]') if (!openDetailsElement) return const summaryElement = openDetailsElement.querySelector('summary') openDetailsElement.removeAttribute('open') summaryElement.setAttribute('aria-expanded', false) summaryElement.focus() } class MenuDrawer extends HTMLElement { constructor() { super() this.mainDetailsToggle = this.querySelector('details') this.bindEvents() } bindEvents() { this.querySelectorAll('summary').forEach(summary => summary.addEventListener('click', this.onSummaryClick.bind(this))) this.querySelectorAll('button:not(.localization-selector)').forEach(button => button.addEventListener('click', this.onCloseButtonClick.bind(this)) ) } onKeyUp(event) { if (event.code.toUpperCase() !== 'ESCAPE') return const openDetailsElement = event.target.closest('details[open]') if (!openDetailsElement) return openDetailsElement === this.mainDetailsToggle ? this.closeMenuDrawer(event, this.mainDetailsToggle.querySelector('summary')) : this.closeSubmenu(openDetailsElement) } onSummaryClick(event) { const summaryElement = event.currentTarget const detailsElement = summaryElement.parentNode const parentMenuElement = detailsElement.closest('.has-submenu') const isOpen = detailsElement.hasAttribute('open') const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)') if (detailsElement === this.mainDetailsToggle) { if (isOpen) event.preventDefault() isOpen ? this.closeMenuDrawer(event, summaryElement) : this.openMenuDrawer(summaryElement) if (window.matchMedia('(max-width: 990px)')) { document.documentElement.style.setProperty('--viewport-height', `${window.innerHeight}px`) document.documentElement.style.setProperty('--viewport-height', `${window.innerHeight}px`) } } else { setTimeout(() => { detailsElement.classList.add('menu-opening') summaryElement.setAttribute('aria-expanded', true) parentMenuElement && parentMenuElement.classList.add('submenu-open') }, 100) } } openMenuDrawer(summaryElement) { setTimeout(() => { this.mainDetailsToggle.classList.add('menu-opening') }) summaryElement.setAttribute('aria-expanded', true) theme.toggleModalStatus(true) } closeMenuDrawer(event, elementToFocus = false) { if (event === undefined) return this.mainDetailsToggle.classList.remove('menu-opening') this.mainDetailsToggle.querySelectorAll('details').forEach(details => { details.removeAttribute('open') details.classList.remove('menu-opening') }) this.mainDetailsToggle.querySelectorAll('.submenu-open').forEach(submenu => { submenu.classList.remove('submenu-open') }) theme.toggleModalStatus(false) elementToFocus.setAttribute('aria-expanded', false) this.closeAnimation(this.mainDetailsToggle) } onCloseButtonClick(event) { const detailsElement = event.currentTarget.closest('details') this.closeSubmenu(detailsElement) } closeSubmenu(detailsElement) { const parentMenuElement = detailsElement.closest('.submenu-open') parentMenuElement && parentMenuElement.classList.remove('submenu-open') detailsElement.classList.remove('menu-opening') detailsElement.querySelector('summary').setAttribute('aria-expanded', false) this.closeAnimation(detailsElement) } closeAnimation(detailsElement) { let animationStart const handleAnimation = time => { if (animationStart === undefined) { animationStart = time } const elapsedTime = time - animationStart if (elapsedTime < 400) { window.requestAnimationFrame(handleAnimation) } else { detailsElement.removeAttribute('open') } } window.requestAnimationFrame(handleAnimation) } } customElements.define('menu-drawer', MenuDrawer) class HeaderDrawer extends MenuDrawer { constructor() { super() } openMenuDrawer(summaryElement) { this.header = this.header || document.querySelector('.section-header') this.borderOffset = this.borderOffset || this.closest('.header-wrapper').classList.contains('header-wrapper--border-bottom') ? 1 : 0 this.setDrawerH() this.header.classList.add('menu-open') setTimeout(() => { this.mainDetailsToggle.classList.add('menu-opening') }) summaryElement.setAttribute('aria-expanded', true) window.addEventListener('resize', this.onResize) theme.toggleModalStatus(true) } closeMenuDrawer(event, elementToFocus) { if (!elementToFocus) return super.closeMenuDrawer(event, elementToFocus) this.header.classList.remove('menu-open') window.removeEventListener('resize', this.onResize) theme.toggleModalStatus(false) } setDrawerH() { let h = 0 if (document.querySelector('sticky-header')) { h = document.querySelector('.section-header').getBoundingClientRect().bottom } else { h = this.header.getBoundingClientRect().bottom } document.documentElement.style.setProperty( '--header-bottom-position', `${parseInt(h - this.borderOffset)}px` ) } onResize = () => { this.header && this.setDrawerH(); document.documentElement.style.setProperty('--viewport-height', `${window.innerHeight}px`) } } customElements.define('header-drawer', HeaderDrawer) // 搜索建议 class SearchForm extends HTMLElement { constructor() { super() this.$form = this.querySelector('form') this.input = this.querySelector('input[type="search"]') this.resetBtn = this.querySelector('button[type="reset"]') this.$form.addEventListener('submit', this.handleSubmit.bind(this)) if (this.input) { this.input.form.addEventListener('reset', this.handleFormReset.bind(this)) this.input.addEventListener( 'input', debounce(event => { this.onChange(event) }, 300).bind(this) ) } } onChange() { this.toggleResetBtn() } getInputVal() { return this.input.value } toggleResetBtn() { const resetBtnIsHide = this.resetBtn.classList.contains('hidden', this.close.bind(this)) if (this.getInputVal().length > 0) { this.resetBtn.classList.remove('hidden') } else { this.resetBtn.classList.add('hidden') } } handleFormReset(event) { event.preventDefault() this.input.value = '' this.input.focus() this.toggleResetBtn() } handleSubmit(event) { event.preventDefault() const inputVal = this.querySelector('input').value window.safeHref = `/search?q=${inputVal}` } } customElements.define('search-from', SearchForm) // 搜索列表 class HeaderSearchResult extends SearchForm { constructor() { super() } onChange() { super.onChange() const searchKey = this.getInputVal() if (!searchKey) { this.clearSearchResults() } else { this.fetchSearchResult(searchKey) } } handleFormReset(event) { super.handleFormReset(event) this.searchTerm = '' this.clearSearchKey() this.clearSearchResults() } clearSearchKey() { this.input.value = '' this.removeAttribute('results') } clearSearchResults() { this.querySelector('.predictive-search').innerHTML = '' } fetchSearchResult(searchKey) { const _this = this fetch(theme.api.search, { method: 'POST', headers: theme.headers, body: JSON.stringify({ keyword: searchKey, pageSize: 5, pageNo: 1 }) }) .then(response => response.json()) .then(res => { // 头部搜索 if (res.code == 0) { let searcHtml = '' if (res.data.list && res.data.list.length > 0) { searcHtml = window.template('search-product-art-tpl', { products: res.data.list, keywords: searchKey }) } else { searcHtml = window.template('search-product-art-tpl', { products: [], keywords: searchKey }) } _this.querySelector('.predictive-search').innerHTML = searcHtml this.toSeasrchPageBtn = this.querySelector('.predictive-search__btn') this.toSeasrchPageBtn.href = `/search?q=${searchKey}` } }) .catch(error => console.error(error)) } close() { this.removeAttribute('loading') this.removeAttribute('open') this.clearSearchResults() this.input.setAttribute('aria-expanded', false) } } customElements.define('header-search-result', HeaderSearchResult) class DetailsModal extends HTMLElement { constructor() { super() this.$detailsContainer = this.querySelector('details') this.$summaryToggle = this.querySelector('summary') this.setEvent() this.$summaryToggle.setAttribute('role', 'button') } setEvent() { this.$detailsContainer.addEventListener('keyup', event => event.code.toUpperCase() === 'ESCAPE' && this.close()) this.$summaryToggle.addEventListener('click', this.onSummaryClick.bind(this)) this.querySelector('button[type="button"]').addEventListener('click', this.close.bind(this)) } isOpen() { return this.$detailsContainer.hasAttribute('open') } onSummaryClick(event) { event.preventDefault() event.target.closest('details').hasAttribute('open') ? this.close() : this.open(event) } onBodyClick(event) { if (!this.contains(event.target) || event.target.classList.contains('modal-overlay')) this.close(false) } open(event) { this.onBodyClickEvent = this.onBodyClickEvent || this.onBodyClick.bind(this) event.target.closest('details').setAttribute('open', true) document.body.addEventListener('click', this.onBodyClickEvent) theme.toggleModalStatus(true) } close(focusToggle = true) { this.$detailsContainer.removeAttribute('open') document.body.removeEventListener('click', this.onBodyClickEvent) theme.toggleModalStatus(false) } } customElements.define('details-modal', DetailsModal) // 粘性页头 class StickyHeader extends HTMLElement { constructor() { super() } connectedCallback() { this.$header = document.querySelector('.section-header') this.stickyType = this.getAttribute('data-sticky-type') this.setHeaderHeight() window.matchMedia('(max-width: 990px)').addEventListener('change', this.setHeaderHeight.bind(this)) this.currentScrollTop = 0 this.createObserver() if (this.stickyType == 'always' || this.stickyType == 'reduce-logo-size') { this.$header.classList.add('shoptop-section-header-sticky') } window.addEventListener('scroll', this.handleScroll.bind(this)) } setHeaderHeight() { let h = this.$header.offsetHeight || document.querySelector('.header-wrapper').offsetHeight let offsetT = this.$header.offsetTop || document.querySelector('.header-wrapper').offsetTop document.documentElement.style.setProperty('--header-height', `${h + offsetT}px`) } createObserver() { let observer = new IntersectionObserver((entries, observer) => { this.headerRect = entries[0].intersectionRect observer.disconnect() }) observer.observe(this.$header) } handleScroll() { const scrollTop = window.pageYOffset || document.documentElement.scrollTop if (scrollTop > this.currentScrollTop && scrollTop > this.headerRect.bottom) { // 向下滚动 this.$header.classList.add('scrolled-shrink-logo') if (this.stickyType != 'always' && this.stickyType != 'reduce-logo-size') { this.$header.classList.add('shoptop-section-header-hidden', 'shoptop-section-header-sticky') } } else if (scrollTop < this.currentScrollTop && scrollTop > this.headerRect.bottom) { // 向上滚动 this.$header.classList.add('scrolled-shrink-logo') if (this.stickyType == 'on-scroll-up') { this.$header.classList.add('shoptop-section-header-sticky', 'animate') this.$header.classList.remove('shoptop-section-header-hidden') } } else if (scrollTop <= this.headerRect.top) { this.$header.classList.remove('scrolled-shrink-logo') } this.currentScrollTop = scrollTop } } customElements.define('sticky-header', StickyHeader) // 联系表 class ContactForm extends HTMLElement { constructor() { super() this.$form = this.querySelector('form') this.successLan = this.getAttribute('data-lang-success') this.errorLan = this.getAttribute('data-lang-error') this.$message = this.querySelector('.newsletter-form__message') this.$text = this.querySelector('.newsletter-form__message-text') this.handleEvent() } handleEvent() { const _this = this const selectList = this.querySelectorAll(".field__select") selectList.forEach(item => { item.addEventListener('change', function(event) { event.target.classList.add("field__select-selected") }) }) this.$form.addEventListener('submit', function(event) { event.preventDefault() const formData = new FormData(_this.$form) // 获取表单数据 const url = _this.$form.action fetch(url, { method: 'POST', body: formData }) .then(response => response.json()) .then(res => { if (res.code == 0) { _this.$message.setAttribute('data-status', 'success') _this.$text.textContent = _this.successLan _this.$form.reset() } else { _this.$message.setAttribute('data-status', 'error') _this.$text.textContent = `${_this.errorLan} ${res.msg}` } }) .catch(error => { // 处理捕获的错误 console.error('Error:', error) }) }) } } window.customElements.define('contact-form', ContactForm) class SliderContainer extends HTMLElement { constructor() { super() this.slidePrevClass = 'slider-slide-prev' this.slideNextClass = 'slider-slide-next' this.slideActiveClass = 'slider-slide-active' this.slideWrap = this.querySelector('.slider-wrap') this.slideItems = this.querySelectorAll('.slider-slide') this.prevButton = this.querySelector('.slider-button-prev') this.nextButton = this.querySelector('.slider-button-next') this.slidesPerView = this.getAttribute('data-slides-per-view') || 1 //列数 this.$total = this.querySelector('.slider-counter--total') // 总数dom // 长滑动时间 this.sliderStatus = false this.delay = this.getAttribute('data-delay') this.longSwipesMs = 300 this.edgeSwipeThreshold = 20 this.currentIndex = 0 // 监听移动端的触摸事件 this.touchStartX = 0 this.touchStartY = 0 this.maxIndex = this.slideItems.length - this.slidesPerView this.sliderX = 0 if (this.slidesPerView > 1 && this.$total) this.$total.innerHTML = this.maxIndex + 1 // 多列轮播重新 算下总数 this.initSlideSize() this.slideChange() const resizeObserver = new ResizeObserver(entries => this.initSlideSize()) resizeObserver.observe(this.slideWrap) this.bindEvent() this.currentDom = this.querySelector('.slider-counter--current') } static get observedAttributes() { return ['enabled', 'mode'] } get enabled() { return this.getAttribute('enabled') === 'true' } get mode() { return this.getAttribute('mode') } set enabled(value) { this.setAttribute('enabled', value) } bindEvent() { this.prevButton && this.prevButton.addEventListener('click', this.onButtonClick.bind(this)) this.nextButton && this.nextButton.addEventListener('click', this.onButtonClick.bind(this)) this.touchMoveEvent = this.handleTouchMove.bind(this) this.touchMOveEndEvent = this.handleTouchMoveEnd.bind(this) this.autoplay = this.getAttribute('data-autoplay') == 'true' this.slideWrap.addEventListener( 'touchstart', e => { // event.preventDefault(); this.touchStartX = e.touches[0].clientX this.touchStartY = e.touches[0].clientY this.touchStartTime = new Date().getTime() this.pause() document.addEventListener('touchmove', this.touchMoveEvent, { passive: true }) document.addEventListener('touchend', this.touchMOveEndEvent, { passive: true }) }, { passive: true } ) window.addEventListener('resize', throttle(this.windowResize.bind(this))) } windowResize() { if (window.innerWidth > 750) { this.querySelectorAll('.slider-wrap').forEach(item => { item.removeAttribute('style') }) } } isVerticalSwipe(touchEndX, touchEndY) { return Math.abs(touchEndY - this.touchStartY) > Math.abs(touchEndX - this.touchStartX) } handleTouchMove(event) { if (this.enabled) return let touchMoveX = event.touches[0].clientX let touchMoveY = event.touches[0].clientY if (!this.isVerticalSwipe(touchMoveX, touchMoveY)) { event.preventDefault() const x = touchMoveX - this.touchStartX this.slideWrap.style.transform = `translate3d(${-this.sliderX + x}px, 0px, 0px)` } } handleTouchMoveEnd(event) { if (this.enabled) return // event.preventDefault(); let touchEndX = event.changedTouches[0].clientX const t = new Date().getTime() - this.touchStartTime let index = this.currentIndex touchEndX > this.touchStartX ? (index -= 1) : (index += 1) const num = Math.abs(touchEndX - this.touchStartX) if (num > this.edgeSwipeThreshold) { if (t <= this.longSwipesMs) { this.slideTo(index) } else { if (num > this.slideWidthList[this.currentIndex] / 2) { this.slideTo(index) } else { this.slideTo(this.currentIndex) } } } else { this.slideTo(this.currentIndex) } // 重新启动自动播放 this.initAutoplay() document.removeEventListener('touchmove', this.touchMoveEvent) document.removeEventListener('touchend', this.touchMOveEndEvent) } initAutoplay() { this.sliderStatus = true this.lastTime = new Date().getTime() } play() { const _this = this this.sliderStatus = true // 启动自动播放 this.lastTime = new Date().getTime() requestAnimationFrame(() => tick()) const tick = function() { if (!_this.sliderStatus) return const timestamp = new Date().getTime() if (timestamp - _this.lastTime >= _this.delay) { _this.slideNext() _this.lastTime = timestamp } requestAnimationFrame(() => tick()) } } pause() { this.sliderStatus = false //pause } removeClass(aClass) { this.querySelector('.' + aClass) && this.querySelector('.' + aClass).classList.remove(aClass) } slideChange() { const currentSlideItem = this.slideItems[this.currentIndex] this.removeClass(this.slideActiveClass) currentSlideItem.classList.add(this.slideActiveClass) } accumulateBeforeIndex(index) { const arr = this.slideWidthList let total = 0 for (let i = 0; i < index; i++) { total += arr[i] } return total } slideTo(index, speed = 300) { let newIndex = index if (index >= this.maxIndex) { newIndex = this.maxIndex } if (index < 0) { newIndex = 0 } if (this.mode != 'fade') { this.sliderX = this.accumulateBeforeIndex(newIndex) this.slideWrap.style.transitionDuration = `${speed}ms` this.slideWrap.style.transform = `translate3d(-${this.sliderX}px, 0px, 0px)` } this.currentIndex = newIndex this.clearDuration() this.update() this.currentDom && (this.currentDom.textContent = this.currentIndex + 1) } update() { const currentSlideItem = this.slideItems[this.currentIndex] this.removeClass(this.slideActiveClass) currentSlideItem.classList.add(this.slideActiveClass) } slideNext(speed = 300, callback) { let index = this.currentIndex + 1 > this.maxIndex ? 0 : this.currentIndex + 1 this.slideTo(index, speed) callback && callback() } initSlideSize() { this.slideWidthList = Array.from(this.slideItems).map((element, index) => { const eWidth = element.clientWidth return eWidth }) this.slideTo(this.currentIndex) } onButtonClick(event) { if (this.enabled) return event.preventDefault() let index = 0 if (event.currentTarget.name === 'next') { index = this.currentIndex + 1 } else { index = this.currentIndex - 1 } this.slideTo(index) this.initAutoplay() } clearDuration() { this.clearDurationTime && clearTimeout(this.clearDurationTime) this.clearDurationTime = setTimeout(() => { this.slideWrap.style.transitionDuration = '0ms' }, 310) } } customElements.define('slider-container', SliderContainer) class SlideshowContainer extends SliderContainer { constructor() { super() this.sliderControlLinksArray = Array.from(this.querySelector('.slideshow__counter-content').querySelectorAll('.slider-counter__link')) this.sliderControlLinksArray.forEach((link, index) => link.addEventListener('click', this.linkToSlide.bind(this, link, index))) this.playBtn = this.querySelector('.slideshow__play') if (this.autoplay) { this.setPlaySatus() } } update() { super.update() this.sliderControlButtons = this.querySelectorAll('.slider-counter__link') if (!this.sliderControlButtons.length) return this.sliderControlButtons.forEach(link => { link.classList.remove('slider-counter__link--active') }) this.sliderControlButtons[this.currentIndex].classList.add('slider-counter__link--active') } linkToSlide(event, index) { this.slideTo(index) } setPlaySatus() { this.play() this.playBtn.addEventListener('click', this.autoPlayToggle.bind(this)) } autoPlayToggle() { this.togglePlayBtnState() this.sliderStatus ? this.pause() : this.play() } togglePlayBtnState() { if (this.sliderStatus) { this.playBtn.classList.add('slideshow__play--paused') } else { this.playBtn.classList.remove('slideshow__play--paused') } } } customElements.define('slideshow-container', SlideshowContainer) // 幻灯片 class SlideshowComponent extends HTMLElement { constructor() { super() } get autoplay() { return this.getAttribute('data-autoplay') == 'true' } get delay() { return this.getAttribute('data-delay') } connectedCallback() { const _this = this this.sectionId = this.getAttribute('data-section-id') this.$current = this.querySelector('.slider-counter--current') const swiperOptions = { autoplay: this.autoplay ? { delay: this.delay } : false, navigation: { nextEl: `.slider-button-next[data-section-id="${this.sectionId}"]`, prevEl: `.slider-button-prev[data-section-id="${this.sectionId}"]` }, on: { init: function() { const sSlide = this.el.querySelectorAll('.swiper-slide')[this.activeIndex] _this.renderVideo(sSlide) }, slideChange: function(e) { _this.updateDot(this.activeIndex) if (_this.$current) { _this.$current.innerText = this.activeIndex + 1 } const sSlide = this.el.querySelectorAll('.swiper-slide')[this.activeIndex] _this.renderVideo(sSlide) } } } this.mySwiper = new Swiper(`.slideshow-${this.sectionId}`, swiperOptions) this.handleAutoPlay() this.handleDot() this.handlePlayVideo() } renderVideo(sSlide) { const $tempalte = sSlide.querySelector('template') if ($tempalte && !$tempalte.getAttribute('data-render')) { const video = $tempalte.content.firstElementChild.cloneNode(true) const $play = sSlide.querySelector('.video_js_play_btn') if (video.tagName === "VIDEO" && $play) return sSlide.querySelector('.slideshow__media').appendChild($tempalte.content.firstElementChild.cloneNode(true)); $tempalte.setAttribute('data-render', 1) } } handleAutoPlay() { if (this.autoplay) { this.sliderStatus = true this.playBtn = this.querySelector('.slideshow__play') if (!this.playBtn) return this.playBtn.addEventListener('click', event => { if (this.sliderStatus) { this.sliderStatus = false this.mySwiper.autoplay.stop() this.playBtn.classList.add('slideshow__play--paused') } else { this.sliderStatus = true this.mySwiper.autoplay.start() this.playBtn.classList.remove('slideshow__play--paused') } }) } } updateDot(index) { this.sliderControlButtons = this.querySelectorAll('.slider-counter__link') if (!this.sliderControlButtons.length) return this.sliderControlButtons.forEach(link => { link.classList.remove('slider-counter__link--active') }) this.sliderControlButtons[index].classList.add('slider-counter__link--active') } handleDot() { const _this = this const $sliderCounter = this.querySelector('.slider-counter') if ($sliderCounter && $sliderCounter.getAttribute('data-pagination-type') == 'dots') { this.sliderControlLinksArray = Array.from( this.querySelector('.slideshow__counter-content').querySelectorAll('.slider-counter__link') ) this.sliderControlLinksArray.forEach((link, index) => link.addEventListener('click', () => { _this.mySwiper.slideTo(index) }) ) } } handlePlayVideo() { const _this = this this.querySelectorAll(".video_js_play_btn").forEach(function($btn) { $btn.addEventListener("click", function($el) { const $slide = $el.target.parentNode const $video = $slide.querySelector("video") if ($video) { $video.style.display = 'block' $video.play() } else { const $tempalte = $slide.querySelector("template") $slide.appendChild($tempalte.content.firstElementChild.cloneNode(true)); _this.handleVideoStop($el) } $el.target.style.display = "none" }) }) } handleVideoStop($event) { const $parent = $event.target.parentElement const $video = $parent.querySelector("video") if (!$video) return $video.addEventListener("ended", () => { $video.style.display = 'none' $parent.querySelector(".video_js_play_btn").style.display = "block" }) } } customElements.define('slideshow-component', SlideshowComponent) // 打开弹窗 class RdfyDialogButton extends HTMLElement { constructor() { super() } connectedCallback() { const $btn = this.querySelector('.open-button') if (!$btn) return const id = this.getAttribute('data-modal') let modal = document.querySelector(id) if (!modal) return $btn.addEventListener('click', () => { modal = document.querySelector(id) modal.show($btn) modal.dispatchEvent( new Event('open', { bubbles: true }) ) theme.toggleModalStatus(true) }) modal.addEventListener('close', () => { theme.toggleModalStatus(false) }) } } customElements.define('rdfy-dialog-button', RdfyDialogButton) // 商品详情 class ProductInfo extends HTMLElement { constructor() { super() // 判断商品详情类型 if (this.getAttribute('mode')) { this.rafyProduct = theme.quickBuyProduct } else { const productStr = document.querySelector('#product-json').textContent this.rafyProduct = { product: JSON.parse(productStr) } Shoptop.event.emit('shoptop:product:change', this.rafyProduct) } } connectedCallback() { const $form = this.querySelector('product-form form') const obj = {} // 遍历 FormData 对象中的键值对 const formData = new FormData($form) const item = this.rafyProduct.product.skus.find(item => item.skuId == formData.get('skuId')) this.rafyProduct.selected = item this.rafyProduct.quantity = formData.get('quantity') Shoptop.event.emit('dataTrack:productView', this.rafyProduct) // 监听数量变化事件 this.updateQuantity() this.handleQuantityChange() this.handleSkuChange() } handleQuantityChange() { const $quantity = this.querySelector('.quantity__input') if ($quantity) { $quantity.addEventListener('change', event => { this.rafyProduct.quantity = parseInt(event.target.value) window.Shoptop.event.emit('shoptop:product:qtyChange', this.rafyProduct) }) } } handleSkuChange() { const $variant = this.querySelector('variants-picker') if (!$variant) return $variant.addEventListener('skuChange', event => { this.rafyProduct = event.detail this.rafyProduct.quantity = 1 this.updateQuantity() this.updatePrice(this.rafyProduct.selected) this.updateSku() window.history.replaceState( null, '', '?' + theme.toQuery({ ...theme.params(), ...{ variant: this.rafyProduct.selected.skuId } }) ) window.Shoptop.event.emit('shoptop:product:skuChange', this.rafyProduct) }) } getMaxStock(productData) { //inventoryQuantity --- 总库存 inventoryTracking --- 是否跟踪库存 inventoryPolicy --- 跟踪库存策略 1 --- 库存为0时不允许购买 2 --- 库存为0时购买 3 --- 库存为0自动下架 if (productData.product.inventoryTracking) { if (productData.product.inventoryPolicy == 2) { return 1000000 } else { return productData.selected.inventoryQuantity } } else { return 1000000 } } updateQuantity() { const $quantity = this.querySelector('.quantity__input') if ($quantity) { const max = this.getMaxStock(this.rafyProduct) $quantity.max = max $quantity.value = 1 } } updateSku() { const $sku = this.querySelector('.product__sku-text') if ($sku) { $sku.innerText = this.rafyProduct.selected.sku } } updatePrice(sku) { const $priceWrap = this.querySelector('.product-info__header_price-wrapper') if (!$priceWrap) return const $price = $priceWrap.querySelector('.product-info__header_price') const $compareAtPrice = $priceWrap.querySelector('.product-info__header_compare-at-price') const $badgeSale = $priceWrap.querySelector('.price__badge-sale') const $badgeSoldOut = $priceWrap.querySelector('.price__badge-sold-out') const imports = template.defaults.imports $price.innerText = imports.moneyWithSymbol(sku.price) if (sku.available) { $badgeSoldOut.classList.add('hidden') if (sku.price < sku.compareAtPrice) { $compareAtPrice.classList.remove('hidden') $compareAtPrice.innerText = imports.moneyWithSymbol(sku.compareAtPrice) $badgeSale.classList.remove('hidden') } else { $compareAtPrice.classList.add('hidden') } } else { $badgeSale.classList.add('hidden') $badgeSoldOut.classList.remove('hidden') } } getProduct() { return this.rafyProduct } setProduct(data) { this.rafyProduct = data } } customElements.define('product-info', ProductInfo) // 色卡切换 class VariantsPicker extends HTMLElement { constructor() { super() this.addEventListener('change', this.onVariantChange) } onVariantChange() { const options = this.querySelectorAll('[name^=option]:checked') const $product = this.parentNode const productData = $product.getProduct() let skus = productData.product.skus let specs = productData.product.specs options.forEach(option => { // ['1453662483775504386', '0', 'opt', '0'] 商品spuId 商品sku类型下标 固定字符串 sku属性下标 const indexes = option.id.split('-') const optKey = `specOption${parseInt(indexes[1]) + 1}` skus = skus.filter(sku => sku[optKey] == specs[indexes[1]].spuSpecValues[indexes[3]]) }) document .querySelectorAll('product-info #product-detail__page-form input[name=skuId]') .forEach(item => item.setAttribute('value', skus[0] ? skus[0].skuId : '')) // this.updatePrice(skus[0]) this.updateInventory(skus[0]) const data = { ...productData, ...{ quantity: 1, selected: skus[0] } } const customEvent = new CustomEvent('skuChange', { bubbles: true, cancelable: true, detail: data }) this.dispatchEvent(customEvent) // $product.setProduct(productData) // Shoptop.event.emit("shoptop:product:skuChange", productData) } updateInventory(sku) { const $wrap = document.querySelector('product-info .inventory-satus') } } customElements.define('variants-picker', VariantsPicker) // 购买操作 class ProductForm extends HTMLElement { constructor() { super() this.$form = this.querySelector('form') this.$atc = this.querySelector('.product-form__submit') this.$payment = this.querySelector('.product-form__payment') this.$errorWrap = this.querySelector('.product-form__msg-wrap') this.$errorText = this.$errorWrap.querySelector('.product-form__msg-content') this.mode = this.getAttribute('mode') this.$form.addEventListener('submit', this.handleSubmit.bind(this)) this.$payment && this.$payment.addEventListener('click', this.handlePayment.bind(this)) this.submitButton = this.querySelector('[type="submit"]') const $variant = this.closest('product-info').querySelector('variants-picker') $variant && $variant.addEventListener('skuChange', this.handleVariantChange.bind(this)) } getFormParams() { const obj = {} const formData = new FormData(this.$form) // 遍历 FormData 对象中的键值对 for (var pair of formData.entries()) { obj[pair[0]] = pair[1] } return obj } handleVariantChange(evt) { const data = evt.detail if (data.selected.available) { this.$atc && this.$atc.classList.remove('disabled') this.$payment && this.$payment.classList.remove('disabled') } else { this.$atc && this.$atc.classList.add('disabled') this.$payment && this.$payment.classList.add('disabled') } // 更新选中的sku let $input = this.querySelector('input[name="skuId"]') $input && ($input.value = data.selected.skuId) } isQuickBuy() { return this.mode === 'quick-buy' } async handleSubmit(event) { event.preventDefault() let cartBatch = false const options = this.getFormParams() let addParams = { goodsId: options.skuId, productId: options.spuId, goodsNum: options.quantity || 1 } if (!this.isQuickBuy()) { var appsObj = await window.Shoptop.APPS_PLUGINS.validate() if (!appsObj.every(e => e.status)) return // 校验应用插件是否通过 this.submitButton && this.submitButton.classList.add('loading') for (let apps in appsObj) { if (appsObj[apps].value) { if (appsObj[apps].key === 'ProductWholesale') { if (appsObj[apps].applyType === 1) { cartBatch = true const cartItems = new FormData() appsObj[apps].value.forEach((item, index) => { cartItems.append(`lineItems[${index}].goodsId`, item.goodsId) cartItems.append(`lineItems[${index}].goodsNum`, item.goodsNum) cartItems.append(`lineItems[${index}].productId`, item.productId) }) addParams = cartItems } if (appsObj[apps].applyType === 2) { addParams.goodsNum = appsObj[apps].value } } else { addParams[appsObj[apps].key] = appsObj[apps].value } } } } const cartItem = document.querySelector('cart-notification') || document.querySelector('cart-drawer') fetch(cartBatch ? theme.api.batchCart : theme.api.addToCart, { method: 'POST', headers: cartBatch ? undefined : theme.headers, processData: false, contentType: cartBatch ? false : undefined, body: cartBatch ? addParams : JSON.stringify(addParams) // 将数据转换为 JSON 字符串 }) .then(response => response.json()) .then(data => { // 处理响应数据 if (data.code === 0 && data.data) { const productData = this.parentNode.parentNode.getProduct() window.Shoptop.event.emit('dataTrack:addToCart', { spuId: options.spuId, skuId: options.skuId, quantity: options.quantity, price: productData.selected.price, goodsTitle: productData.product.goodsTitle, goodsHandle: productData.product.handle }) if (cartItem) { cartItem.setActiveElement(document.activeElement) const $selector = document.querySelector(`#quickBuy-${options.spuId}`) if ($selector) { $selector.remove() } } else { window.safeHref = '/cart' } } }) .catch(error => { // 处理错误 console.log(error) }) .finally(() => { this.submitButton && this.submitButton.classList.remove('loading') }) } handlePayment(evt) { if (!this.$form.checkValidity()) { event.preventDefault() return } this.fetchPayment() } async fetchPayment() { var appsObj = await window.Shoptop.APPS_PLUGINS.validate() if (!appsObj.every(e => e.status)) return // 校验应用插件是否通过 let formBatch = false const options = this.getFormParams() let formQuant = options?.quantity || 1 const productData = this.parentNode.parentNode.getProduct() const formData = new FormData() const distribution_id = getCookie('_distribution') || '' const product_refer = (theme.params().sales_pop && 'sales_pop') || '' if (distribution_id) { formData.append('distributorId', distribution_id) } if (product_refer) { formData.append('referInfo.productReferer', product_refer) } if (appsObj.length) { for (let apps in appsObj) { if (appsObj[apps].value) { if (appsObj[apps].key === 'attachments') { formData.append(`lineItems[${0}].attachments`, appsObj[apps].value) } else if (appsObj[apps].key === 'ProductWholesale') { if (appsObj[apps].applyType === 1) { formBatch = true appsObj[apps].value.forEach((item, index) => { formData.append(`lineItems[${index}].goodsId`, item.goodsId) formData.append(`lineItems[${index}].goodsNum`, item.goodsNum) formData.append(`lineItems[${index}].productId`, item.productId) }) } if (appsObj[apps].applyType === 2) { formQuant = appsObj[apps].value } } else { formData.append(`lineItems[${0}].${appsObj[apps].key}`, appsObj[apps].value) } } } } // paypal 数据 formData.append('accountNo', options.merchantId) formData.append('referInfo.source', 'buy_now') formData.append('referInfo.device', isMobile() ? 'mobile' : 'pc') if (!formBatch) { formData.append(`lineItems[${0}].goodsId`, options.skuId) formData.append(`lineItems[${0}].productId`, options.spuId) formData.append(`lineItems[${0}].goodsNum`, formQuant) } window.Shoptop.event.emit('dataTrack:addToCart', { spuId: options.spuId, skuId: options.skuId, price: productData.selected.price, quantity: options.quantity, goodsTitle: productData.product.goodsTitle, goodsHandle: productData.product.handle }) fetch(theme.api.preOrder, { method: 'POST', body: formData }) .then(response => response.json()) .then(res => { const data = res.readyState ? res.responseJSON : res if (data.code === 0 && data.data) { return (window.safeHref = '/checkout/' + data.data.orderToken) } else { // TODO 增加错误提示 this.$errorWrap.classList.remove('hidden') this.$errorText.textContent = data.msg } }) .catch(error => { // 处理错误 this.$errorWrap.classList.remove('hidden') this.$errorText.textContent = error }) .finally(() => {}) } } customElements.define('product-form', ProductForm) // 数量选择器 class QuantityInput extends HTMLElement { constructor() { super() this.$input = this.querySelector('input') this.$input.addEventListener('change', this.handleInputChange.bind(this)) this.querySelectorAll('button').forEach(btn => btn.addEventListener('click', this.handleBtnClick.bind(this))) this.changeEvent = new Event('change', { bubbles: true }) } handleInputChange(evt) { this.updateQuantity() } handleBtnClick(evt) { evt.preventDefault() const value = this.$input.value const name = evt.target.name name === 'plus' ? this.$input.stepUp() : this.$input.stepDown() const newValue = this.$input.value if (value !== newValue) { this.$input.dispatchEvent(this.changeEvent) } } updateQuantity() { const value = parseInt(this.$input.value) if (this.$input.min) { const min = parseInt(this.$input.min) const $btnMinus = this.querySelector(".quantity__button[name='minus']") $btnMinus.classList.toggle('disabled', value <= min) } if (this.$input.max) { const max = parseInt(this.$input.max) const $btnPlus = this.querySelector(".quantity__button[name='plus']") $btnPlus.classList.toggle('disabled', value >= max) } } } customElements.define('quantity-input', QuantityInput) // 库存提示 class InventoryComponent extends HTMLElement { constructor() { super() } get threshold() { return this.getAttribute('data-threshold') } get defaultLang() { return this.getAttribute('data-lang-default') } get continueLang() { return this.getAttribute('data-lang-continue') } get soldOutLang() { return this.getAttribute('data-lang-sold_out') } get showInventoryQuantity() { return this.getAttribute('data-show-inventory-quantity') } getProduct() { return this.parentElement.getProduct() } connectedCallback() { this.$text = this.querySelector('.product-inventory__text') this.$svgWrap = this.querySelector('.product-inventory__svg') this.changeInventory() const $variantPicker = this.parentElement.querySelector('variants-picker') $variantPicker.addEventListener('change', () => { this.changeInventory() }) } changeInventory() { const product = this.getProduct() // inventoryQuantity --- 总库存 inventoryTracking --- 是否跟踪库存 inventoryPolicy --- 跟踪库存策略 1 --- 库存为0时不允许购买 2 --- 库存为0时购买 3 --- 库存为0自动下架 const t = template.defaults.imports.t if (product.selected.available) { const inventoryQuantity = product.selected.inventoryQuantity if (inventoryQuantity <= 0) { this.$text.innerText = t(this.defaultLang, { count: '' }) this.$svgWrap.setAttribute('data-status', 'stock') return } if (inventoryQuantity >= this.threshold) { this.$text.innerText = t(this.defaultLang, { count: this.showInventoryQuantity == 'true' ? inventoryQuantity : '' }) this.$svgWrap.setAttribute('data-status', 'stock') } else { this.$text.innerText = t(this.continueLang, { count: this.showInventoryQuantity == 'true' ? inventoryQuantity : '' }) this.$svgWrap.setAttribute('data-status', 'continue') } } else { this.$text.innerText = this.soldOutLang this.$svgWrap.setAttribute('data-status', 'none') } } } customElements.define('inventory-component', InventoryComponent) class MediaCommComponent extends HTMLElement { constructor() { super() this.selectedImage = null } moveWithHover(overlay, image, event, zoomRatio) { // calculate mouse position const ratio = image.height / image.width const container = event.target.getBoundingClientRect() const xPosition = event.clientX - container.left const yPosition = event.clientY - container.top const xPercent = `${xPosition / (image.clientWidth / 100)}%` const yPercent = `${yPosition / ((image.clientWidth * ratio) / 100)}%` // determine what to show in the frame overlay.style.backgroundPosition = `${xPercent} ${yPercent}` overlay.style.backgroundSize = `${image.width * zoomRatio}px` } getOverlay(imageSrc) { const container = document.createElement('div') container.setAttribute('class', 'image-magnify-full-size max-w-full absolute top-0 left-0 h-full w-full') container.setAttribute('aria-hidden', 'true') container.style.display = 'block' container.style.backgroundImage = `url('${imageSrc}')` container.style.backgroundColor = 'var(--gradient-background)' return container } createZoomImage($image) { const zoomImage = document.createElement('img') const url = $image?.getAttribute('data-media-url') if (!url) return const imageSrc = `${STORE_PARAMS.imageDomain}/${url}?x-oss-process=style/1920x` this.overlay = this.getOverlay(imageSrc) zoomImage.setAttribute('src', `${imageSrc}`) $image.style.opacity = '50%' zoomImage.onload = () => { $image.parentElement.insertBefore(this.overlay, $image) $image.style.opacity = '100%' } } magnify($image, zoomRatio) { this.createZoomImage($image) this.overlay.onclick = event => this.overlay.remove() this.overlay.onmousemove = event => this.moveWithHover(this.overlay, $image, event, zoomRatio) this.overlay.onmouseleave = () => this.overlay.remove() } enableZoomOnHover(selector) { this.lightboxType = this.getAttribute('lightbox-type') if (this.lightboxType == 'none') return document.querySelectorAll(`${selector} .swiper-slide`).forEach((slide, index) => { slide.addEventListener('click', event => { if (this.lightboxType == 'hover' && !theme.isMobile()) { if (event.target.classList.contains('image-magnify-full-size')) return const image = slide.querySelector('img') this.magnify(image, 2) this.moveWithHover(this.overlay, image, event, 2) } else { const $media = slide.querySelector('radf-media') if (!$media) return this.selectedImage = $media.getAttribute('match') const target = event.target.closest('.product-media-container').querySelector('rdfy-dialog-button .open-button') if (target) { const event = new Event('click') target.dispatchEvent(event) } } }) }) } toggleLoadingSpinner(image) { const loadingSpinner = image.parentElement.parentElement.parentElement.querySelector('.loading-overlay__spinner') loadingSpinner.classList.toggle('hidden') } } customElements.define('media-comm-component', MediaCommComponent) // 商品详情页媒体文件 class MediaComponent extends MediaCommComponent { constructor() { super() this.hideVariants = this.getAttribute('data-hide-variants') } connectedCallback() { this.sliderLayout = this.getAttribute('slider-layout') this.mSliderLayout = this.getAttribute('m-slider-layout') this.initSwiper() window.matchMedia('(max-width: 750px)').addEventListener('change', this.changeSlider.bind(this)) // 监听sku切换事件 this.$sku = this.parentElement.parentElement.querySelector('variants-picker') this.$sku.addEventListener('skuChange', this.handleSkuChange.bind(this)) this.changeLightbox() } changeLightbox() { this.enableZoomOnHover('.slider-master-image') // 图片放大弹窗 const $lightbox = document.querySelector('#product-medial-lightbox') const $scrollWrap = $lightbox.querySelector('.product-media-lightbox__wrap') $lightbox.addEventListener('open', evt => { // stacked columns // const selectedImageUrl = this.querySelector(".slider-master-image .swiper-slide-active img").getAttribute("data-media-url") const $mediaList = $scrollWrap.querySelectorAll('radf-media') let sIndex = 0 for (let i = 0; i < $mediaList.length; i++) { const $media = $mediaList[i] if ($media.getAttribute('match') === this.selectedImage) { sIndex = i break } } this.zoomSwiper.slideTo(sIndex) }) $lightbox.addEventListener('close', evt => { console.log('关闭') }) } initSwiper() { // stacked columns thumbnail thumbnail_slider // columns show hide this.initThumbailSwiper() const gap = this.getSwiperGap() const $currentText = this.querySelector('.slider-counter--current') const showSpaceBetween = this.sliderLayout == 'thumbnail' || this.sliderLayout == 'thumbnail_slider' ? true : false const masterSwiperOptions = { slidesPerView: this.mSliderLayout == 'columns' ? '2.1' : '1', spaceBetween: gap.mobile, breakpoints: { 750: { slidesPerView: 1, spaceBetween: showSpaceBetween ? gap.desktop : 0 } }, navigation: { nextEl: '.slider-master-image .slider-button-next', prevEl: '.slider-master-image .slider-button-prev' }, on: { slideChange: function() { $currentText.innerText = this.activeIndex + 1 } } } if (this.thumbnailSwiper) { masterSwiperOptions.thumbs = { swiper: this.thumbnailSwiper } } if (this.sliderLayout !== 'columns' && this.sliderLayout !== 'stacked') { masterSwiperOptions.autoHeight = true } this.masterSwiper = new Swiper('.slider-master-image', masterSwiperOptions) this.changeSlider() if (this.sliderLayout == 'thumbnail') { this.thumbnailClick() } this.zoomSwiper = new Swiper('.zoom-image-swiper', { slidesPerView: 1, zoom: true }) } getSwiperGap() { const computedStyle = window.getComputedStyle(this) return { desktop: parseFloat(computedStyle.getPropertyValue('--grid-desktop-horizontal-spacing')), mobile: parseFloat(computedStyle.getPropertyValue('--grid-mobile-horizontal-spacing')) } } initThumbailSwiper() { if (!this.querySelector('.product-media-thumbnails')) return const thumbnailOptions = { slidesPerView: 3, spaceBetween: 10, noSwiping: true, navigation: { nextEl: '.product-thumbnails--next', prevEl: '.product-thumbnails--prev' } } if (this.sliderLayout == 'thumbnail' || this.sliderLayout == 'thumbnail_slider') { thumbnailOptions.breakpoints = { 750: { slidesPerView: 4, spaceBetween: this.sliderLayout == 'thumbnail_slider' ? 10 : 0 }, 950: { slidesPerView: 5, spaceBetween: this.sliderLayout == 'thumbnail_slider' ? 10 : 0 } } } this.thumbnailSwiper = new Swiper('.product-media-thumbnails', thumbnailOptions) } thumbnailClick() { const _this = this document.querySelectorAll('.product-media-thumbnails .swiper-slide').forEach((item, index) => { item.addEventListener('click', event => { const target = event.target _this.masterSwiper.slideTo(index, 0) }) }) } changeSlider() { const $thumbnails = this.querySelector('.product-media-thumbnails') if (window.matchMedia('(max-width: 750px)').matches) { this.masterSwiper && this.masterSwiper.enable() this.thumbnailSwiper && this.thumbnailSwiper.enable() $thumbnails && $thumbnails.classList.remove('swiper-no-swiping') } else { if (this.sliderLayout == 'stacked' || this.sliderLayout == 'columns') { this.masterSwiper.slideTo(0, 0) this.masterSwiper.disable() $thumbnails && $thumbnails.classList.add('swiper-no-swiping') } if (this.sliderLayout == 'thumbnail') { this.thumbnailSwiper.slideTo(0, 0) this.thumbnailSwiper.disable() $thumbnails && $thumbnails.classList.add('swiper-no-swiping') } } } updateSize() { if (this.masterSwiper.activeIndex == 0) { this.masterSwiper.update() } } handleSkuChange(evt) { const data = evt.detail const needVariantImage = data.product.needVariantImage if (!needVariantImage) return const skuImage = data.selected.skuImage const sliderSlide = this.querySelectorAll('.slider-master-image .swiper-slide') const $thumbnails = this.querySelector('.product-media-thumbnails') const addedImage = {} if (this.hideVariants === 'true') { // 主图区域 sliderSlide[0].querySelector('.product-media-container').style.cssText = `--ratio:${skuImage.width / skuImage.height}` const $media = this.querySelector('radf-media') if ($media) { $media.setAttribute('data-width', skuImage.width) $media.setAttribute('data-height', skuImage.height) $media.setAttribute('media-url', skuImage.url) } // 缩略图区域 if ($thumbnails) { const thumbnails = $thumbnails.querySelectorAll('.swiper-slide') this.changeImage(thumbnails[0].querySelector('img'), skuImage) } // 灯箱区域 const $lightboxContent = document.querySelector('.product-media-lightbox__content') if ($lightboxContent) { const $img = $lightboxContent.querySelector(`[data-media-url="${skuImage.url}"]`) if (!$img) { const sImg = $lightboxContent.querySelectorAll('.swiper-slide')[0].querySelector('img') this.changeImage(sImg, skuImage) } } } else { let sIndex = null for (let index = 0; index < sliderSlide.length; index++) { let item = sliderSlide[index] if (item.querySelector('radf-media').getAttribute('match') == skuImage.url) { sIndex = index break } } if ((this.sliderLayout == 'stacked' || this.sliderLayout == 'columns') && !theme.isMobile()) { this.masterSwiper.prependSlide(this.masterSwiper.slides[sIndex]); return } else { this.masterSwiper.slideTo(sIndex, 0) if ($thumbnails) { this.thumbnailSwiper.slideTo(sIndex, 0) } } } } changeImage($img, image) { $img.setAttribute('data-src', `${STORE_PARAMS.imageDomain}/${image.url}?x-oss-process=style/{width}x`) $img.setAttribute('data-media-url', image.url) $img.setAttribute('width', image.width) $img.setAttribute('height', image.height) $img.classList.remove('lazyautosizes') $img.classList.remove('lazyloaded') $img.classList.add('lazyload') } } customElements.define('media-component', MediaComponent) // 媒体文件 class RadfMedia extends HTMLElement { constructor() { super() } static get observedAttributes() { return ['media-url'] } attributeChangedCallback(name, oldVal, newVal) { if (name == 'media-url') { this.parentElement.style['--ratio'] = this.dataHeight / this.dataWidth this.mediaChange(newVal) this.closest('media-component')?.updateSize() } } get mediaUrl() { return this.getAttribute('media-url') } get mediaAlt() { return this.getAttribute('media-alt') } get dataWidth() { return this.getAttribute('data-width') } get dataHeight() { return this.getAttribute('data-height') } mediaChange(value) { const dto = theme.mediaParse(this.mediaUrl) const res = { html: "" } switch (dto.type) { case "image": { res.html = [ `<img class="absolute left-0 top-0 w-full h-full object-contain object-center lazyload"`, `src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg=="`, `data-src="${dto.image}"`, `alt="${this.mediaAlt}"`, `data-sizes=auto />`, ].join("") break; } case "video": { res.html = [ `<video class="absolute inset-0 m-auto h-full w-full object-contain slider-zoom isVideo cursor-default z-10"`, `x5-playsinline playsinline controls webkit-playsinline preload muted`, `poster="${dto.image}"`, `alt="${this.mediaAlt}"`, `>`, `<source src="${dto.file}" type="video/mp4">`, `</video>` ].join("") break; } case "3d": { res.html = [ `<webcom-media-3d class="absolute w-full h-full rate-able bg-body"`, `sources="${dto.file}"`, `poster="${dto.image}"`, `alt="${this.mediaAlt}"`, `shown=true`, `>`, `</webcom-media-3d>` ].join("") break; } } this.innerHTML = res.html } } customElements.define('radf-media', RadfMedia) // 视频 class VideoPlayer extends HTMLElement { constructor() { super() this.$playBtn = this.querySelector('.play-content') this.$container = this.querySelector('.video-section') this.$videoBox = this.querySelector('.video-box') const videoId = this.getAttribute("data-video-id") if (!videoId) return this.$playBtn.addEventListener("click", this.loadVideo.bind(this)) } loadVideo() { // window.pauseAllMedia(); if (!this.getAttribute('loaded')) { const content = document.createElement('div'); content.appendChild(this.querySelector('template').content.firstElementChild.cloneNode(true)); this.setAttribute('loaded', true); this.$playBtn.style.display = 'none' const deferredElement = this.$videoBox.appendChild(content.querySelector('video, iframe')); if (focus) deferredElement.focus(); if (deferredElement.nodeName == 'VIDEO' && deferredElement.getAttribute('autoplay')) { // force autoplay for safari deferredElement.play(); } } } } customElements.define('video-player', VideoPlayer) // 可折叠内容 class CollapsibleList extends HTMLElement { constructor() { super() this.$firstCollapsible = this.querySelector('.collapsible-item') // 第一个是否默认展开 if (this.$firstCollapsible.dataset.status == 'expand') { this.$firstCollapsible.querySelector('.collapsible-content').classList.add('show') this.$firstCollapsible.querySelector('.collapsible-content').classList.remove('hide') this.$firstCollapsible.querySelector('.arrow').classList.add('rotate') } // 展开折叠操作 this.querySelectorAll('.collapsible-item').forEach(item => item.addEventListener('click', () => { if (item.dataset.status == 'expand') { item.dataset.status = 'fold' item.querySelector('.collapsible-content').classList.remove('show') item.querySelector('.collapsible-content').classList.add('hide') item.querySelector('.arrow').classList.remove('rotate') } else { item.dataset.status = 'expand' item.querySelector('.collapsible-content').classList.add('show') item.querySelector('.collapsible-content').classList.remove('hide') item.querySelector('.arrow').classList.add('rotate') } }) ) } } customElements.define('collapsible-list', CollapsibleList) class RadfPagination extends HTMLElement { constructor() { super() this.init() } static get observedAttributes() { return ['current', 'total', 'limit'] } get current() { return this.getAttribute('current') } set current(value) { this.setAttribute('current', value) } get total() { return this.getAttribute('total') } set total(value) { this.setAttribute('total', value) } get limit() { return this.getAttribute('limit') } set limit(value) { this.setAttribute('limit', value) } init() { this.renderNode() this.bindEvent() } update(options) { options && options.total && (this.total = options.total) options && options.limit && (this.limit = options.limit) options && options.current && (this.current = options.current) this.renderNode() } renderNode() { var params = this.getBtnList() if (params.showPageBtn.length == 1) { this.innerHTML = '' } else { var html = window.template('pagination_art_tpl', params) this.innerHTML = html } } handleChange(value) { const customEvent = new CustomEvent('change', { bubbles: true, cancelable: true, detail: { current: value } }) this.dispatchEvent(customEvent) } bindEvent() { this.addEventListener('click', event => { const target = event.target if (target.matches('.pagination-prev') || target.closest('.pagination-prev')) { // 处理点击事件的逻辑 if (!this.prePage) return this.current = Number(this.current) - 1 || 1 this.handleChange(this.current) this.update() return } if (target.matches('.pagination-next') || target.closest('.pagination-next')) { if (!this.nextPage) return this.current = Number(this.current) + 1 this.handleChange(this.current) this.update() return } if (target.matches('.pagination-page') || target.closest('.pagination-page')) { const dataIndex = target.getAttribute('data-index') this.current = dataIndex this.handleChange(this.current) this.update() return } }) } getBtnList() { var current = Number(this.current) var limit = Number(this.limit) var total = Number(this.total) var offset = (current - 1) * limit //上一页是否可用 var prePage = offset !== 0 //下一页是否可用 var nextPage = offset + limit < total var totalPage = Math.ceil(total / limit) var currentPage = Math.ceil(offset / limit) + 1 this.prePage = prePage this.nextPage = nextPage function getShowBtn() { var pageNum = totalPage var index = currentPage if (pageNum <= 5) return [...new Array(pageNum)].map((v, i) => i + 1) if (index <= 2) return [1, 2, 3, 0, pageNum] if (index >= pageNum - 1) return [1, 0, pageNum - 2, pageNum - 1, pageNum] if (index === 3) return [1, 2, 3, 4, 0, pageNum] if (index === pageNum - 2) return [1, 0, pageNum - 3, pageNum - 2, pageNum - 1, pageNum] return [1, 0, index - 1, index, index + 1, 0, pageNum] } return { prePage, nextPage, showPageBtn: getShowBtn(), current: current } } } customElements.define('radf-pagination', RadfPagination) class RadfSearchPagination extends RadfPagination { constructor() { super() this.$productWrap = document.querySelector('.search-product-wrap .product-grid') } handleChange(value) { super.handleChange() this.fetchData() } fetchData() { fetch(theme.api.search, { method: 'POST', headers: theme.headers, body: JSON.stringify({ keyword: '', pageSize: 24, pageNo: this.current }) }) .then(response => response.json()) .then(res => { const data = res.readyState ? res.responseJSON : res if (data.code === 0 && data.data) { try { const html = window.template('search-result-art-tpl', { products: data.data.list }) this.$productWrap.innerHTML = html } catch (err) { console.log('err', err) } } else {} }) .catch(error => { // 处理错误 }) } } customElements.define('radf-search-pagination', RadfSearchPagination) class RadfBlogPagination extends RadfPagination { constructor() { super() this.$blogWrap = document.querySelector('.main-blog .blog-articles') this.handle = this.getAttribute('data-handle') } handleChange(value) { super.handleChange() this.fetchData() } fetchData() { fetch(theme.api.blogList, { method: 'PUT', headers: theme.headers, body: JSON.stringify({ pageNo: Number(this.current), pageSize: 12, handle: this.handle, status: 1 }) }) .then(response => response.json()) .then(res => { const data = res.readyState ? res.responseJSON : res if (data.code === 0 && data.data) { try { const html = window.template('blog-art-tpl', { list: data.data.list }) this.$blogWrap.innerHTML = html this.$blogWrap.scrollIntoView({ behavior: 'smooth', block: 'start' }) } catch (err) { console.log('err', err) } } else {} }) .catch(error => { // 处理错误 }) } } customElements.define('radf-blog-pagination', RadfBlogPagination) class RdfyQuickBuymedia extends MediaCommComponent { constructor() { super() } connectedCallback() { // 监听sku切换事件 this.$sku = this.parentElement.parentElement.querySelector('variants-picker') this.$sku.addEventListener('skuChange', this.handleSkuChange.bind(this)) this.initSwiper() this.zoomImage() } handleSkuChange(evt) { const data = evt.detail const skuImage = data.selected.skuImage if (skuImage) { const sliderSlide = this.querySelectorAll('.quick-buy-modal__swiper .swiper-slide') let sIndex = null for (let index = 0; index < sliderSlide.length; index++) { let item = sliderSlide[index] if (item.querySelector('radf-media').getAttribute('match') == skuImage.url) { sIndex = index break } } this.masterSwiper.slideTo(sIndex, 0) } } initSwiper() { const masterSwiperOptions = { slidesPerView: 1, spaceBetween: 10, autoHeight: true, navigation: { nextEl: '.quick-buy-modal__swiper-next', prevEl: '.quick-buy-modal__swiper-prev' } } this.masterSwiper = new Swiper('.quick-buy-modal__swiper', masterSwiperOptions) } zoomImage() { document.querySelectorAll(`.quick-buy-modal__swiper .swiper-slide`).forEach((slide, index) => { slide.addEventListener('click', event => { if (event.target.classList.contains('image-magnify-full-size')) return const image = slide.querySelector('img') this.magnify(image, 2) this.moveWithHover(this.overlay, image, event, 2) }) }) } } customElements.define('rdfy-quick-buy-media', RdfyQuickBuymedia) class RdfyQuickBuy extends HTMLElement { constructor() { super() } connectedCallback() { this.spuId = this.getAttribute('data-spu-id') this.$body = document.querySelector('body') this.$btn = this.querySelector('button') this.addEventListener('click', this.handleClick.bind(this)) } handleClick(event) { this.$btn.classList.add('loading') this.fetchData() } fetchData() { fetch(`${theme.api.productDetail}?spuId=${this.spuId}`, { headers: theme.headers }) .finally(() => this.$btn.classList.remove('loading')) .then(response => response.json()) .then(res => { try { var resData = res && res.data // 色卡数据预处理 if (res.data?.extend?.colorCard && res.data?.extend?.colorCard.length) { res.data.specs.forEach(item => { const index = res.data.extend.colorCard.findIndex(atr => atr.specName == item.spuSpecName) item.colorCardIndex = index }) } // 色卡数据预处理 END const selected = resData.skus.filter(function(item) { return item.inventoryQuantity > 0 })[0] || resData.skus[0] const html = window.template('quick-buy-modal-tpl', { product: resData, selectedSku: selected }) theme.quickBuyProduct = { product: resData, selected, quantity: 1 } // 记录历史商品数据 const $productDetail = document.querySelector('.product__info-wrap product-info') const oldProductData = $productDetail ? $productDetail.getProduct() : '' this.$body.insertAdjacentHTML('beforeend', html) const modal = document.querySelector(`#quickBuy-${res.data.spuId}`) modal.show(this) modal.dispatchEvent( new Event('open', { bubbles: true }) ) theme.toggleModalStatus(true) modal.addEventListener('close', () => { theme.toggleModalStatus(false) this.$body.removeChild(modal) }) } catch (err) { console.log('err', err) } }) } } customElements.define('rdfy-quick-buy', RdfyQuickBuy) class RadfPaypalComponent extends HTMLElement { constructor() { super() } connectedCallback() { const paypalJs = STORE_PARAMS.paymentSettings.paypalJs if (!paypalJs) return this.paypalId = this.getAttribute('data-id') this.paypalBtnStyle = { height: 44, layout: 'horizontal', size: 'responsive', shape: 'rect', color: 'gold', tagline: !1 } this.loadPaypalSdk(paypalJs).then(res => { window.paypal .Buttons({ style: this.paypalBtnStyle, onClick: () => this.onClick(), createOrder: async () => this.createOrder(), onApprove: data => this.onApprove(data), onCancel: data => this.onCancel(data) }) .render('#' + this.paypalId) .then(() => {}) .catch(err => {}) }) } async onClick() { let appsObj = await window.Shoptop.APPS_PLUGINS.validate() // 预览模式下禁止下单 if (window.location.pathname.indexOf('/preview/') == 0) { this.$toast(this, 'order') return false } if (!appsObj.every(e => e.status)) return false // 校验应用插件是否通过 if (STORE_PARAMS.paymentSettings.loginAuthority == 'register') { // 判断是否登录 if (window.SHOPTOP?.userId) { return true } else { window.safeHref = '/account/login' } } else { return true } } getParentSelector(element, selector) { var currentElement = element; while (currentElement && currentElement.tagName !== selector) { currentElement = currentElement.parentElement; } return currentElement; } getProductData() { const $productInfo = this.getParentSelector(this, 'PRODUCT-INFO') return $productInfo.getProduct() } getCartItems() { return this.previousElementSibling.getCartItems() } async createOrder() { const _this = this return new Promise(async (resolve, reject) => { var formBatch = false var pathname = location.pathname var source = pathname === '/cart' ? 'cart' : 'buy_now' var appsObj = await window.Shoptop.APPS_PLUGINS.validate() var xtproduct = source !== "cart" ? this.getProductData() : {} var CartItems = source !== "cart" ? {} : this.getCartItems() if (source === 'buy_now' && !xtproduct.selected.skuId) { // $.toast.show({ // type: "error", // content: "Please select a variant at least" // }); return reject('options rejected') } if (source === 'buy_now' && !xtproduct.selected.available) { return reject('product not available') } // 获取自定义参数 // $.loading.show(); var formQuant = xtproduct.quantity || 1 var formData = new FormData() var product_refer = (theme.params().sales_pop && 'sales_pop') || '' var distribution_id = theme.getCookie('_distribution') || '' if (appsObj.length) { for (let apps in appsObj) { if (appsObj[apps].value) { if (appsObj[apps].key === 'attachments') { formData.append(`lineItems[${0}].attachments`, appsObj[apps].value) } else if (appsObj[apps].key === 'moreOptions') { // productVariant formData.append(`lineItems[${0}].moreOptions`, appsObj[apps].value) } else if (appsObj[apps].key === 'ProductWholesale') { if (appsObj[apps].applyType === 1) { formBatch = true appsObj[apps].value.forEach((item, index) => { formData.append(`lineItems[${index}].goodsId`, item.goodsId) formData.append(`lineItems[${index}].goodsNum`, item.goodsNum) formData.append(`lineItems[${index}].productId`, item.productId) }) } if (appsObj[apps].applyType === 2) { formQuant = appsObj[apps].value } } else { formData.append(appsObj[apps].key, appsObj[apps].value) } } } } if (formBatch) return formData.append('accountNo', STORE_PARAMS.paymentSettings.merchantId) formData.append('referInfo.payMethod', 'paypal') formData.append('referInfo.source', source) formData.append('distributorId', distribution_id) formData.append('referInfo.productReferer', product_refer) formData.append('referInfo.device', theme.isMobile() ? 'mobile' : 'pc') if (source === 'buy_now' && !formBatch) { formData.append(`lineItems[${0}].goodsNum`, formQuant) formData.append(`lineItems[${0}].goodsId`, xtproduct.selected.skuId) formData.append(`lineItems[${0}].productId`, xtproduct.selected.spuId) } if (source === 'cart') { CartItems.forEach((item, newIndex) => { const attachments = item.attachments ? item.attachments : [] if (item.moreOptions) { formData.append(`lineItems[${newIndex}].moreOptions`, item.moreOptions) } if (attachments && attachments.length) { formData.append(`lineItems[${newIndex}].attachments`, attachments) } formData.append(`lineItems[${newIndex}].cartId`, item.id) formData.append(`lineItems[${newIndex}].goodsNum`, item.quantity) formData.append(`lineItems[${newIndex}].goodsId`, item.variantId) formData.append(`lineItems[${newIndex}].productId`, item.productId) }) } // 发送POST请求 await fetch(theme.api.preOrder, { method: 'POST', body: formData }) .then(response => response.json()) // 假设服务器返回JSON数据 .then(res => { // 在这里处理服务器返回的数据 // TODO 立即购买事件 if (res.code === 0 && res.data) { resolve(res.data.tradeId) _this.orderToken = res.data.orderToken } else { reject(false) // $.loading.hide(); theme.ajaxError(data) } }) .catch(error => { // 处理错误 console.error('Error:', error) }) }) } onApprove(data) { const orderToken = this.orderToken const params = { orderToken: this.orderToken, tradNo: data.orderID } fetch(theme.api.syncCheckout, { method: 'POST', headers: theme.headers, body: JSON.stringify(params) }) .then(response => response.json()) .then(res => { if (res.code === 0 && res.data) { // $.loading.hide(); window.safeHref = `/checkout/${orderToken}` } else { // $.loading.hide(); theme.ajaxError(res) } }) .catch(err => { // TODO 错误弹窗 }) } onCancel(data) { let tranId = JSON.parse(JSON.stringify(data)).orderID fetch(theme.api.cancelOrder, { method: 'POST', headers: theme.headers, body: JSON.stringify({ tradeId: tranId }) }) .then(res => { if (res.code === 0 && res.data) { // $.loading.hide(); console.log(`Cancel PayPal OrderId: ${tranId}`) } else { // $.loading.hide(); console.log(`Error Cancel PayPal OrderId: ${tranId}`) } }) .catch(err => { // TODO 错误弹窗 }) } loadPaypalSdk(url) { var id = 'paypal-sdk' var paypalScript = document.getElementById(id) return new Promise((resolve, reject) => { if (paypalScript) { resolve(true) } else { //创建script标签 var script = document.createElement('script') script.type = 'text/javascript' script.src = url script.id = id //添加标签到body尾部 document.head.appendChild(script) script.onload = () => { resolve(true) } script.onerror = () => { reject(false) } } }) } } customElements.define('radf-paypal-component', RadfPaypalComponent) // 专辑详情产品网格组件 class CollectionGrid extends HTMLElement { constructor() { super() this.current = theme.params().pageNo || 1 this.pageSize = this.getAttribute('pagesize') this.collectionId = this.getAttribute('id') this.count = this.getAttribute('count') // 商品总数量 this.$productWrap = this.querySelector('.collection__product-list') this.$filterWraps = this.querySelectorAll('.collection-filter_container') this.drawerWrapIsOpen = false // 抽屉弹窗是否打开 this.drawerWrapOpenItem = '' // 抽屉弹窗打开的子组件 this.paramsData = [] // 筛选项的值 this.sortBy = 'default-default' // 排序 默认推荐 this.priceBlurDom = '' this.openList = [] this.init() } init() { // this.fetchData(true) this.getUrlParams() this.getFilterList(this.pageSize) // 设置筛选 this.itemDomEvent() this.bindEvent() } fetchData(first) { this.setNewUrl() // 设置url let paramsData = { collectionId: this.collectionId, pageNo: this.current, pageSize: this.pageSize, sortBy: this.sortBy } let paramsStr = theme.toQuery(paramsData) let paramsArr = [] this.paramsData.forEach(item => { if (item.type === 'price_range') { // 价格需要*100 paramsArr.push(`${item.name}=${item.value * 100}`) } else { paramsArr.push(`${item.name}=${item.value}`) } }) if (paramsArr.length > 0) { paramsStr += '&' + paramsArr.join('&') } fetch(theme.api.collectionProductList + '?' + paramsStr, { method: 'GET' }) .then(response => response.json()) .then(res => { const data = res.readyState ? res.responseJSON : res if (data.code === 0 && data.data) { try { const html = window.template('collection-art-tpl', { products: data.data.list }) this.$productWrap.innerHTML = html // 分页 const pagination = window.template('collection__pagination_tpl', { total: data.data.total, pageNo: this.current, pageSize: this.pageSize }) this.querySelector('.collection__pagination').innerHTML = pagination // 分页切换页 的回调 this.querySelector('radf-pagination') && this.querySelector('radf-pagination').addEventListener('change', v => { this.current = v.detail.current this.fetchData() }) // this.getFilterList(data.data.total) // 设置筛选 } catch (err) { console.log('err', err) } } else {} }) .catch(error => { // 处理错误 }) } // 获取筛选 getFilterList(total) { let paramsData = { collectionId: this.collectionId } let paramsStr = theme.toQuery(paramsData) let paramsArr = [] let isParams = false // 是否有筛选参数 this.paramsData.forEach(item => { isParams = true if (item.type === 'price_range') { // 价格需要*100 paramsArr.push(`${item.name}=${item.value * 100}`) } else { paramsArr.push(`${item.name}=${item.value}`) } }) if (paramsArr.length > 0) { paramsStr += '&' + paramsArr.join('&') } fetch(theme.api.collectionFilterList + '?' + paramsStr, { method: 'GET' }) .then(response => response.json()) .then(res => { const data = res.readyState ? res.responseJSON : res if (data.code === 0 && data.data) { try { let priceData = {} const imports = template.defaults.imports data.data.map(item => { // 获取最大价格 if (item.type == 'price_range') { item.rangeMax = imports.moneyWithSymbol(item.rangeMax) priceData.rangeMax = item.rangeMax priceData.lteVal = item.rangeMax priceData.gteVal = imports.moneyWithSymbol(0) } }) let selectedData = {} // 每个筛选项的已选数量 this.paramsData.forEach(item => { // 将价格的值合并 if (item.type === 'price_range') { priceData.label = item.label if (item.value) { if (item.name == 'filter.v.price.lte') { priceData.lteVal = imports.moneyWithSymbol(item.value * 100) } else { priceData.gteVal = imports.moneyWithSymbol(item.value * 100) } } } else { selectedData[item.label] = selectedData[item.label] ? selectedData[item.label] + 1 : 1 } }) const stock_msg = { 1: 'in_stock', 0: 'out_of_stock' } // 渲染筛选组件 const html = window.template('collection-filter-tpl', { filters: data.data || [], paramsData: this.paramsData, openList: this.openList, priceData, stock_msg, selectedData, drawerWrapIsOpen: this.drawerWrapIsOpen, drawerWrapOpenItem: this.drawerWrapOpenItem }) this.$filterWraps.forEach((item, index) => { item.innerHTML = html }) // 渲染已选筛选的box const html2 = window.template('collection-filter-selected-tpl', { paramsData: this.paramsData, priceData, stock_msg }) this.querySelector('.collection-filter-selected_box').innerHTML = html2 if (this.priceBlurDom) { // 是否获取输入框的索引 let dom = this.querySelector(this.priceBlurDom) let pldVal = dom.value dom.value = '1' dom.focus() dom.value = pldVal } // 设置排序的值 let sortBox = this.querySelectorAll('.facet-filters__sort') sortBox.forEach((item, index) => { item.value = this.sortBy }) // 设置当前筛选数量和总商品数量 let $product_count = this.querySelectorAll('.current_product_count') $product_count.forEach((item, index) => { item.innerHTML = this.count + ' products' if (isParams && total) { item.innerHTML = total + ' of ' + this.count + ' products' } }) this.itemDomEvent() } catch (err) { console.log('err', err) } } else {} }) .catch(error => { // 处理错误 }) } bindEvent() { const that = this // 排序选择 let sortBox = this.querySelector('.collection-grid-sort-box-wrap .facet-filters__sort') sortBox && sortBox.addEventListener('change', function(event) { that.sortBy = this.value that.current = 1 that.fetchData() event.stopPropagation() }) // 分页切换页 的回调 this.querySelector('radf-pagination') && this.querySelector('radf-pagination').addEventListener('change', v => { this.current = v.detail.current this.fetchData() }) } itemDomEvent() { const that = this // 水平布局筛选事件 this.querySelectorAll('.level_filter_box .level_filter_item').forEach((item, index) => { let type = item.getAttribute('type') let paramName = item.getAttribute('name') let label = item.getAttribute('label') let $modal = item.querySelector('.level_filter_item_modal') let $level_item_after = item.querySelector('.level_filter_item_after') let $level_item_checkbox = item.querySelectorAll('.level_filter_item_options') // 复选框 // 展开筛选项 item.addEventListener('click', function(event) { $modal = this.querySelector('.level_filter_item_modal') $modal.classList.remove('hidden') $modal.style.display = 'block' $level_item_after.style.display = 'block' that.openList.push(paramName) // 记录展开筛选项 }) // 筛选项外层的 点击关闭选项弹出层 $level_item_after.addEventListener('click', function(event) { this.style.display = 'none' $modal.style.display = 'none' that.openList = that.openList.filter(item => item != paramName) // 移除关闭的筛选项 event.stopPropagation() }) if (type === 'price_range') { // 价格筛选 let $from_price_ipt = item.querySelector('.from_price_ipt.field__input') // 价格输入框 let $to_price_ipt = item.querySelector('.to_price_ipt.field__input') // 价格输入框 // 开始价格 $from_price_ipt.addEventListener( 'input', debounce(event => { that.setParamsData(type, event, label, '.level_filter_box .level_filter_item') // 筛选修改 }, 300).bind(this) ) // 结束价格 $to_price_ipt.addEventListener( 'input', debounce(event => { that.setParamsData(type, event, label, '.level_filter_box .level_filter_item') // 筛选修改 }, 300).bind(this) ) } else { // 价格之外的筛选 // 复选框 $level_item_checkbox.forEach((item2, index) => { item2.addEventListener('click', function(event) { if (item2.className.includes('disabled')) return let $svg = item2.querySelector('svg') if ($svg.style.display == 'block') { $svg.style.display = 'none' } else { $svg.style.display = 'block' } that.setParamsData(type, this, label) // 筛选修改 }) }) } }) // 垂直布局筛选事件 this.querySelectorAll('.vertical_filter_box .vertical_filter_item').forEach((item, index) => { let $head = item.querySelector('.vertical_filter_item_head') let $content = item.querySelector('.vertical_filter_item_content') let $level_item_checkbox = item.querySelectorAll('.level_filter_item_options') // 复选框 let type = item.getAttribute('type') let paramName = item.getAttribute('name') let label = item.getAttribute('label') $content.style.animation = 'animateMenuOpen var(--duration-default) ease;' // 展开筛选项 $head.addEventListener('click', function(event) { if ($content.style.display === 'block') { $content.style.display = 'none' that.openList = that.openList.filter(item => item != paramName) // 移除关闭的筛选项 } else { $content.style.display = 'block' that.openList.push(paramName) // 记录展开筛选项 } }) if (type === 'price_range') { // 价格筛选 let $from_price_ipt = item.querySelector('.from_price_ipt.field__input') // 价格输入框 let $to_price_ipt = item.querySelector('.to_price_ipt.field__input') // 价格输入框 // 开始价格 $from_price_ipt.addEventListener( 'input', debounce(event => { that.setParamsData(type, event, label, '.vertical_filter_box .vertical_filter_item') // 筛选修改 }, 300).bind(this) ) // 结束价格 $to_price_ipt.addEventListener( 'input', debounce(event => { that.setParamsData(type, event, label, '.vertical_filter_box .vertical_filter_item') // 筛选修改 }, 300).bind(this) ) } else { // 价格之外的筛选 // 复选框 $level_item_checkbox.forEach((item2, index) => { item2.addEventListener('click', function(event) { if (item2.className.includes('disabled')) return let $svg = item2.querySelector('svg') if ($svg.style.display == 'block') { $svg.style.display = 'none' } else { $svg.style.display = 'block' } that.setParamsData(type, this, label) // 筛选修改 }) }) } }) // 抽屉布局事件 let $drawer_filter_box = this.querySelectorAll('.drawer_filter_box') let $drawer_filter_wrap = this.querySelectorAll('.drawer_filter_wrap') let $drawer_facets__inner = this.querySelectorAll('.mobile-facets__inner') let $close = this.querySelectorAll('.mobile-facets__close,.mobile-facets__close2') let $drawer_filter_item_after = this.querySelectorAll('.drawer_filter_item_after') // 打卡弹窗 $drawer_filter_box.forEach((item, index) => { item.addEventListener('click', function(event) { $drawer_filter_wrap.forEach((item2, index2) => { item2.style.display = 'block' }) setTimeout(() => { $drawer_facets__inner.forEach((item2, index2) => { item2.style.transform = 'translate(0)' }) }, 100) $drawer_filter_item_after.forEach((item2, index2) => { item2.style.display = 'block' }) that.drawerWrapIsOpen = true }) }) // 关闭弹窗 $close.forEach((item, index) => { item.addEventListener('click', function(event) { $drawer_filter_wrap.forEach((item2, index2) => { item2.style.display = 'none' }) setTimeout(() => { $drawer_facets__inner.forEach((item2, index2) => { item2.style.transform = 'translate(105vw)' }) }, 100) $drawer_filter_item_after.forEach((item2, index2) => { item2.style.display = 'none' }) that.drawerWrapIsOpen = false // 关闭弹窗 并把子项都还原位置 let $item_modals = that.querySelectorAll('.mobile-facets__submenu.gradient') // 关闭选项弹窗 $item_modals.forEach((item, index) => { item.style.transform = 'translate(105vw)' }) that.drawerWrapOpenItem = '' }) }) // 关闭弹窗 $drawer_filter_item_after.forEach((item2, index2) => { item2.addEventListener('click', function(event) { $drawer_facets__inner.forEach((item2, index2) => { item2.style.transform = 'translate(105vw)' }) setTimeout(() => { $drawer_filter_wrap.forEach((item2, index2) => { item2.style.display = 'none' }) }, 100) }) }) this.querySelectorAll('.mobile-facets__summary.focus-inset').forEach((item, index) => { let $item_modal = this.querySelectorAll('.mobile-facets__submenu.gradient')[index] let $back_btn = $item_modal.querySelector('.mobile-facets__close-button') // 划出选项弹窗 item.addEventListener('click', function(event) { let label = this.getAttribute('label') $item_modal.style.transform = 'translate(0)' that.drawerWrapOpenItem = label }) // 关闭选项弹窗 $back_btn.addEventListener('click', function(event) { $item_modal.style.transform = 'translate(105vw)' that.drawerWrapOpenItem = '' }) }) this.querySelectorAll('.drawer_filter_item').forEach((item, index) => { let $level_item_checkbox = item.querySelectorAll('.level_filter_item_options') // 复选框 let type = item.getAttribute('type') let paramName = item.getAttribute('name') let label = item.getAttribute('label') if (type === 'price_range') { // 价格筛选 let $from_price_ipt = item.querySelector('.from_price_ipt.field__input') // 价格输入框 let $to_price_ipt = item.querySelector('.to_price_ipt.field__input') // 价格输入框 // 开始价格 $from_price_ipt.addEventListener( 'input', debounce(event => { that.setParamsData(type, event, label, '.drawer_filter_item') // 筛选修改 }, 300).bind(this) ) // 结束价格 $to_price_ipt.addEventListener( 'input', debounce(event => { that.setParamsData(type, event, label, '.drawer_filter_item') // 筛选修改 }, 300).bind(this) ) } else { // 价格之外的筛选 // 复选框 $level_item_checkbox.forEach((item2, index) => { item2.addEventListener('click', function(event) { if (item2.className.includes('disabled')) return let $svg = item2.querySelector('svg') if ($svg.style.display == 'block') { $svg.style.display = 'none' } else { $svg.style.display = 'block' } that.setParamsData(type, this, label) // 筛选修改 }) }) } }) // 清除选中和清除全部的事件 let $reset_btn = this.querySelectorAll('.level_filter_reset_btn') // 重置 // 重置价格 $reset_btn.forEach((item, index) => { // 清除单个 item.addEventListener('click', function(event) { let label = this.getAttribute('label') that.resetParams(label) // 重置 event.stopPropagation() }) }) // 重置其他 let $selected_filter = this.querySelectorAll('.selected_filter_item') $selected_filter.forEach((item, index) => { // 清除单个 item.addEventListener('click', function(event) { let label = this.getAttribute('label') let value = this.getAttribute('value') that.resetParams(label, value) // 重置 event.stopPropagation() }) }) let $filter_remove_all = this.querySelectorAll('.filter_remove_all') // 清除全部 $filter_remove_all.forEach((item, index) => { // 清除全部 item.addEventListener('click', function(event) { that.resetParams() // 重置 event.stopPropagation() }) }) // 排序选择 let sortBox = this.querySelector('.drawer_filter_wrap .facet-filters__sort') sortBox && sortBox.addEventListener('change', function(event) { that.sortBy = this.value that.current = 1 that.fetchData() event.stopPropagation() }) } // 获取新的url参数 getUrlParams() { let urlParams = decodeURIComponent(window.location.href) if (urlParams.split('?').length > 1) { let arr = urlParams.split('?')[1].split('&') arr.forEach(item => { let key = item.split('=')[0] let value = decodeURIComponent(decodeURIComponent(item.split('=')[1])) if (key) { if (key == 'pageNo') { this.pageNo = value || this.pageNo } else if (key == 'sortBy') { this.sortBy = value || this.sortBy } else { let obj = { name: key } let flag = false if (key == 'filter.v.price.gte' || key == 'filter.v.price.lte') { obj.label = key.split('.')[2] obj.type = 'price_range' obj.value = value || '' } else { obj.label = key.split('.')[2] obj.value = value || '' flag = obj.value.split(',').length > 1 } if (obj.label) { if (!flag) { this.paramsData.push(obj) } else { let values = obj.value.split(',') values.forEach(item2 => { this.paramsData.push({ name: obj.name, label: obj.label, type: obj.type, value: item2 }) }) } } } } }) } } // 设置新的url setNewUrl() { // let paramsArr = [] let obj = {} this.paramsData.forEach(item => { if (item.type === 'price_range') { // 价格 if (item.value) { // paramsArr.push(`${item.name}=${item.value}`) obj[item.name] ? obj[item.name].push(item.value) : (obj[item.name] = [item.value]) } } else { obj[item.name] ? obj[item.name].push(item.value) : (obj[item.name] = [item.value]) // paramsArr.push(`${item.name}=${item.value}`) } }) let newUrl = theme.toQuery({ // ...theme.params(), pageSize: this.pageSize, pageNo: this.current, sortBy: this.sortBy, ...obj }) window.history.replaceState(null, '', '?' + newUrl) // } } // 重置当前 resetParams(label, value) { if (label) { if (value) { this.paramsData = this.paramsData.filter(item => item.label + item.value !== label + value) } else { this.paramsData = this.paramsData.filter(item => item.label !== label) } } else { this.paramsData = [] } this.current = 1 this.fetchData() } /** * 修改筛选的参数 * @param {*} type // 类型price_range是价格 list是多选 * @param {*} el // 操作的dom * @returns */ setParamsData(type, el, label, parentClass) { let obj = { label: label, type } this.priceBlurDom = '' if (type == 'price_range') { const paramName = el.target.getAttribute('name') // name obj.name = paramName // name obj.value = el.target.value this.priceBlurDom = parentClass + ' .field__input[name="' + paramName + '"]' let arr = this.paramsData.filter(item => item.name === obj.name) if (arr.length > 0) { this.paramsData.map(item => { if (item.name === obj.name) { item.value = obj.value } }) } else { this.paramsData.push(obj) } } else { const paramName = el.getAttribute('name') // name const value = el.getAttribute('value') obj.name = paramName // name obj.value = value let arr = this.paramsData.filter(item => item.name + item.value === obj.name + obj.value) if (arr.length > 0) { this.paramsData = this.paramsData.filter(item => item.name + item.value !== obj.name + obj.value) } else { this.paramsData.push(obj) } } this.current = 1 this.fetchData() } } customElements.define('collection-grid', CollectionGrid) // 商品色卡 class ProdcutCardSwatch extends HTMLElement { constructor() { super() } connectedCallback() { this.$swatchs = this.querySelectorAll('.product-info__variants-swatch[data-swatch-skus') this.productSwatchInfo = {} this.spuId = this.getAttribute('data-spu-id') this.$swatchs.forEach($swatch => { $swatch.addEventListener('mouseenter', evt => { const swatchSkus = JSON.parse(evt.target.getAttribute('data-swatch-skus')) if (!swatchSkus) return if (this.productSwatchInfo[this.spuId] == swatchSkus.skuId) return const $firstImage = this.getFirstImage() const masterImage = $firstImage.getAttribute('data-swatch-image') this.clearSelected() evt.target.setAttribute('data-checked', 1) if (swatchSkus && swatchSkus.skuImage && swatchSkus.skuImage.url) { this.productSwatchInfo[this.spuId] = swatchSkus.skuId const data_src = window.template.defaults.imports.formatImageSrc(swatchSkus.skuImage, 'url') this.changeImage($firstImage, data_src, masterImage) } }) $swatch.addEventListener('mouseleave', evt => { const target = evt.target if (target.getAttribute('data-checked')) { const $firstImage = this.getFirstImage() const masterImage = $firstImage.getAttribute('data-swatch-image') this.productSwatchInfo[this.spuId] = null const data_src = window.template.defaults.imports.formatImageSrc({ url: masterImage }, 'url' ) this.changeImage($firstImage, data_src, masterImage) } }) }) } changeImage($image, dataSrc, masterImage) { $image.setAttribute('data-src', dataSrc) $image.setAttribute('data-swatch-image', masterImage) $image.classList.remove('lazyloaded') $image.classList.add('lazyload') } getFirstImage() { return this.previousElementSibling.querySelectorAll('.product-card__media img')[0] } clearSelected() { this.$swatchs.forEach($swatch => $swatch.removeAttribute('data-checked')) } } customElements.define('product-card-swatch', ProdcutCardSwatch) class ModalDialog extends HTMLElement { constructor() { super() this.$container = this.querySelector('.video-section') this.$playBtn = this.querySelector('.deferred-media__poster') // 视频链接 this.videoUrl = this.$container.dataset.url this.selectionId = this.$container.dataset.id // 是否是YouTube this.isYoutube = this.videoUrl.indexOf('www.youtube.com') != -1 || this.videoUrl.indexOf('youtu.be') != -1 ? true : false this.$playBtn.addEventListener('click', this.play.bind(this)) } play() { const html = window.template('video-modal-tpl', { video: { url: this.isYoutube ? `https://www.youtube.com/embed/${this.getYoutubeLink(this.videoUrl)}?enablejsapi=1&autoplay=1` : `https://player.vimeo.com/video/${this.vimeoUrl}`, selectionId: this.selectionId } }) const nodeDiv = document.createElement('div') nodeDiv.id = 'modelVideo' + this.selectionId nodeDiv.innerHTML = html document.body.appendChild(nodeDiv) this.$ModalClose = document.querySelector('#ModalClose') this.$ModalClose.addEventListener('click', this.removeVideo.bind(this)) } removeVideo() { var element = document.getElementById('modelVideo' + this.selectionId) element.remove() } getYoutubeLink(url) { const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/ const match = url?.match(regExp) const videoId = match && match[2].length === 11 ? match[2] : null return videoId } } customElements.define('modal-dialog', ModalDialog) // 商品详情的相关产品组件 class MainRelatedProducts extends HTMLElement { constructor() { super() this.$productWrap = this.querySelector('.related-products-list') this.size = this.getAttribute('size') this.spuId = this.getAttribute('id') this.init() } init() { this.fetchData() } fetchData() { let paramsData = { size: this.size, spuId: this.spuId, type: '1' } let paramsStr = theme.toQuery(paramsData) fetch(theme.api.similarProducts + '?' + paramsStr, { method: 'GET' }) .then(response => response.json()) .then(res => { const data = res.readyState ? res.responseJSON : res if (data.code === 0 && data.data) { try { const html = window.template('related-products-art-tpl', { products: data.data }) this.$productWrap.innerHTML = html } catch (err) { console.log('err', err) } } else {} }) .catch(error => { // 处理错误 }) } } customElements.define('main-related-products', MainRelatedProducts) // 专辑列表组件 class MainCollectionListContainer extends HTMLElement { constructor() { super() this.isSwiper = this.getAttribute('swiper') this.total = this.getAttribute('total') this.$current = this.querySelector('.slider-counter--current') this.newSwiper = undefined } connectedCallback() { this.gap = this.getSwiperGap() if (this.isSwiper == 'true') { this.initSwiper() this.bindEvent() } } initSwiper() { const that = this this.$current.innerHTML = 1 this.newSwiper = new Swiper(that.querySelector('.collection_list_swiper'), { loop: false, slidesPerView: that.getAttribute('column'), spaceBetween: this.gap, speed: 500, pagination: { clickable: true }, navigation: { nextEl: that.querySelector('.collection-slider-button--next'), prevEl: that.querySelector('.collection-slider-button--prev') }, on: { slideChange: function() { that.$current.innerHTML = this.activeIndex + 1 } } }) } getSwiperGap() { const computedStyle = window.getComputedStyle(this) return parseFloat(computedStyle.getPropertyValue('--grid-mobile-horizontal-spacing')) } windowResize() { if (window.matchMedia('(min-width: 750px)').matches) { this.newSwiper && this.newSwiper.destroy() this.newSwiper = undefined this.querySelectorAll('.swiper-wrapper').forEach(item => { item.setAttribute('style', '') }) this.querySelectorAll('.swiper-slide').forEach(item => { item.setAttribute('style', '') }) } else { if (!this.newSwiper) { this.initSwiper() } } } bindEvent() { this.windowResize() window.addEventListener('resize', () => { this.windowResize() }) } } customElements.define('main-collection-list-container', MainCollectionListContainer) // 公告栏 class RdfyAnnouncement extends HTMLElement { constructor() { super() this.type = this.getAttribute('data-type') } connectedCallback() { if (this.type != 'vertical' && this.type != 'horizontal') return if (this.querySelectorAll('.swiper-slide').length < 2) return this.initSwiper() } initSwiper() { const $swiper = this.querySelector('.announcement-bar-swiper') $swiper.style.height = $swiper.offsetHeight + 'px' const mySwiper = new Swiper('.announcement-bar-swiper', { direction: this.type, autoplay: true, loop: true }) } } customElements.define('rdfy-announcement', RdfyAnnouncement) class RadfRate extends HTMLElement { constructor() { super() this.rate = this.getAttribute('rate') this.isFixed = this.getAttribute('fixed') || false } connectedCallback() { const html = this.render() this.innerHTML = html if (this.isFixed) return this.bindEvent() } uncheckSiblings() { this.querySelectorAll('input').forEach(item => { item.checked = false }) } bindEvent() { this.querySelectorAll('input').forEach(($input, index) => { $input.addEventListener('click', event => { this.rate = index + 1 this.setAttribute('rate', this.rate) }) $input.addEventListener('mouseenter', event => { this.uncheckSiblings() event.target.checked = true $input.setAttribute('disabled', true) }) }) this.querySelector('.rating').addEventListener('mouseleave', event => { this.uncheckSiblings() event.target.children[this.rate - 1].checked = true }) } render() { const aRate = Math.ceil(this.rate) let str = '' for (let index = 1; index <= 5; index++) { str += `<input type="radio" class="mask" ${this.isFixed ? 'disabled' : ''} ${aRate == index ? 'checked' : ''}>` } return `<div class="rating" name="rating-4">${str}</div>` } } customElements.define('radf-rate', RadfRate) class RadfProgress extends HTMLElement { constructor() { super() this.size = this.getAttribute('size') this.value = this.getAttribute('value') const html = this.render() this.innerHTML = html } render() { const v = (this.value / this.size) * 100 return `<div class="radf-progress-wrap"> <div class="radf-progress-content" style=";"> <div class="radf-progress-inner" style="width: ${v}%"> </div> </div> </div>` } } customElements.define('radf-progress', RadfProgress) class RadfReviewLike extends HTMLElement { constructor() { super() this.commentId = this.getAttribute('data-comment-id') } connectedCallback() { this.bindEvent() } putReview(type) { fetch('/api/mbr/goods/comment/remark', { method: 'PUT', headers: theme.headers, body: JSON.stringify({ remarkType: type, commentId: this.commentId }) }) .then(response => response.json()) .then(res => {}) } putCancelReview(type) { fetch('/api/mbr/goods/comment/cancel-remark', { method: 'PUT', headers: theme.headers, body: JSON.stringify({ remarkType: type, commentId: this.commentId }) }) .then(response => response.json()) .then(res => {}) } bindEvent() { const $reviewLike = this.querySelector('.review-like') $reviewLike.addEventListener('click', event => { if ($reviewLike.getAttribute('like') == '0') { this.putReview('upvote') this.querySelector('.review-like-count').innerText = Number($reviewLike.dataset.count) + 1 $reviewLike.dataset.count = Number($reviewLike.dataset.count) + 1 $reviewLike.setAttribute('like', 1) $reviewLike.classList.add('radf-review-like') $reviewLike.classList.remove('radf-review-unlike') } else { this.putCancelReview('upvote') this.querySelector('.review-like-count').innerText = Number($reviewLike.dataset.count) - 1 $reviewLike.dataset.count = Number($reviewLike.dataset.count) - 1 $reviewLike.setAttribute('like', 0) $reviewLike.classList.add('radf-review-unlike') $reviewLike.classList.remove('radf-review-like') } }) } } customElements.define('radf-review-like', RadfReviewLike) class RadfProductReviews extends HTMLElement { constructor() { super() this.spuId = this.getAttribute('data-spu-id') this.reviewsConfig = {} } connectedCallback() { this.fetchReviewsConfig().then(res => { if (this.reviewsConfig.openStatus == 1) { Promise.all([this.fetchLanguage(), this.fetchReviewsDetail()]).then(res => { this.renderContainer() this.handleAddReviews() }) } }) } renderContainer() { const reviewsHtml = window.template('radf-reviews_art_tpl', { language: this.language, reviewsDetail: this.reviewsDetail }) document.querySelector('radf-product-reviews').innerHTML = reviewsHtml } handleAddReviews() { // 新增弹窗 this.querySelectorAll('.radf-reviews-button').forEach(item => { item.addEventListener('click', event => { const reviewFormHtml = window.template('radf-reviews-write_art_tpl', { language: this.language, }) var div = document.createElement('div') div.classList.add('reviews-form-modal') div.innerHTML = reviewFormHtml document.body.appendChild(div) }) }) } handlePreviewImage() { // 评论图片预览 const $imageDom = this.querySelectorAll('.radf-reviews-tab-bodyer-img') $imageDom.forEach(item => { item.addEventListener('click', event => { this.previewReviewsImage(Number(item.dataset.imageIndex), this.reviewsList.list[Number(item.dataset.reviewIndex)].commentImages) }) }) } fetchLanguage() { return fetch('/api/mbr/global/remind/catalog-query', { method: 'POST', headers: theme.headers, body: JSON.stringify({ catalogs: ['comment', ''] }) }) .then(response => response.json()) .then(res => { if (res.code == 0) { this.language = res.data.comment return Promise.resolve(res.data) } else { return Promise.reject() } }) } // 获取评论统计数据 fetchReviewsDetail() { return fetch(`/api/mbr/goods/comment/count/star/${this.spuId}`, { method: 'GET' }) .then(response => response.json()) .then(res => { if (res.code == 0) { res.data.starDetail = res.data.starDetail.reverse() this.reviewsDetail = res.data return Promise.resolve(res.data) } else { return Promise.reject() } }) } fetchReviewsConfig() { return fetch(theme.api.reviewConfig, { method: 'GET' }) .then(response => response.json()) .then(res => { if (res.code == 0) { this.reviewsConfig = res.data // this.pageSize = this.reviewsConfig.commentPageLimit return Promise.resolve(res.data) } else { return Promise.reject() } }) } } customElements.define('radf-product-reviews', RadfProductReviews) class RadfReviewsTabs extends HTMLElement { constructor() { super() this.parent = this.closest('radf-product-reviews') this.params = { spuId: this.parent.spuId, status: 1, pageNo: 1, pageSize: this.parent.reviewsConfig.commentPageLimit, sortBy: 'comment_date', haveImage: '', sortDirection: 'descend' } this.total = 0 this.reviewsList = [] this.language = this.parent.language } connectedCallback() { this.renderContent() this.bindEvent() } bindEvent() { const tabs = this.querySelectorAll('.radf-reviews-tab') tabs.forEach($tab => { $tab.addEventListener('click', event => { tabs.forEach(item => { item.setAttribute('active', false) }) event.target.setAttribute('active', true) this.params.pageNo = 1 this.params.haveImage = $tab.dataset.reviewtype === '1' ? $tab.dataset.reviewtype : '' this.renderContent() }) }) // pc排序切换 this.querySelector(".radf-reviews-sort select").addEventListener('change', event => { this.params.sortBy = event.target.value this.params.pageNo = 1 this.renderContent() }) // 移动端排序点击 this.querySelector(".radf-reviews-sort__mobile").addEventListener("click", event => { document.querySelector("radf-reviews-sort-drawer").open() }) } sortDrawerChange(value) { this.params.sortBy = value this.params.pageNo = 1 this.renderContent() } queryParams(obj) { return Object.keys(obj).map(key => `${key}=${obj[key]}`).join('&'); } async renderContent() { const query = this.queryParams(this.params) const res = await fetch(`/api/mbr/goods/comment/list?${query}`).then(response => response.json()) if (res.code !== 0 || !res.data) return this.reviewsList = res.data.list this.total = Number(res.data.total) const tem = document.querySelector('#radf-reviews-list_art_tpl') const reviewsListHtml = window.template('radf-reviews-list_art_tpl', { reviewsList: this.reviewsList, language: this.language, // haveImage: this.haveImage, current: this.params.pageNo, total: this.total, pageSize: this.params.pageSize, // haveReviews: this.total > 0 ? true : false, }) this.querySelector('.radf-reviews-tab-inner').innerHTML = reviewsListHtml this.handlePreviewImage() } async paginationChange(index) { this.params.pageNo = index await this.renderContent() this.scrollToElementIfNeeded(this.querySelector('.radf-reviews-tabs-nav')) } scrollToElementIfNeeded(element) { const rect = element.getBoundingClientRect(); const windowHeight = window.innerHeight || document.documentElement.clientHeight; const isInViewport = (rect.top >= 0 && rect.bottom <= windowHeight); if (!isInViewport) { const targetPosition = window.scrollY + rect.top - windowHeight / 4; window.scrollTo({ top: targetPosition, behavior: 'smooth' }); } } handlePreviewImage() { const $imageDom = this.querySelectorAll('.radf-reviews-tab-bodyer-img') $imageDom.forEach($li => { $li.addEventListener('click', () => { this.previewImage((Number($li.dataset.imageIndex)), Number($li.dataset.reviewIndex)) }) }) } previewImage(imageIndex, dataIndex) { const imageData = this.reviewsList[dataIndex].commentImages if (imageData.length == 0) return var html = window.template('radf-preview_image_art-tpl', { imageList: imageData, imageIndex: imageIndex }) const $previewBox = document.querySelector('#radf-preview-image') $previewBox.innerHTML = html } } customElements.define('radf-reviews-tabs', RadfReviewsTabs) class RadfReviewsSortDrawer extends HTMLElement { constructor() { super() } connectedCallback() { this.$root = this.querySelector(".radf-reviews-sort-drawer__root") this.$tabs = document.querySelector("radf-reviews-tabs") this.querySelector(".radf-reviews-sort-drawer__close").addEventListener("click", () => { this.close() }) this.querySelector(".radf-reviews-sort-drawer__mask").addEventListener("click",()=> { this.close() }) this.querySelectorAll("li").forEach($el => { $el.addEventListener("click", () => { const value = $el.getAttribute("value") this.change(value) this.$tabs.sortDrawerChange(value) this.close() }) }) } open() { this.$root.style.display = 'block' } close() { this.$root.style.display = 'none' } change(value) { this.querySelectorAll("li").forEach(item => { item.removeAttribute("selected") }) this.querySelector(`li[value="${value}"]`).setAttribute("selected", 'true') } } customElements.define('radf-reviews-sort-drawer', RadfReviewsSortDrawer) class RadfReviewsPreviewImage extends HTMLElement { constructor() { super() this.imageLen = this.getAttribute('data-image-len') this.selectedIndex = this.getAttribute('data-selected-index') } connectedCallback() { this.mySwiper = new window.Swiper(this.querySelector('.reviews-swiper-container'), { loop: false, autoHeight: false, initialSlide: this.selectedIndex, navigation: { nextEl: '.slide-next-btn', prevEl: '.slide-prev-btn' }, grabCursor: true, updateOnWindowResize: true }) const $previewBox = document.querySelector('#radf-preview-image') $previewBox.style.display = 'block' this.querySelector('.radf-preview-close-btn').addEventListener('click', event => { $previewBox.style.display = 'none' }) } } customElements.define('radf-reviews-preview-image', RadfReviewsPreviewImage) class RadfReviewsPagination extends RadfPagination { constructor() { super() } handleChange(value) { super.handleChange() // this.closest('radf-product-reviews').changePageNo(this.current) this.closest('radf-reviews-tabs').paginationChange(this.current) } } customElements.define('radf-reviews-pagination', RadfReviewsPagination) class RadfReviewsForm extends RadfProductReviews { constructor() { super() this.spuId = this.getAttribute('data-spu-id') this.reviewForm = { title: '', commentImages: [], content: '', star: 5, type: 1, userEmail: '', anonymously: 0 } this.checkUserEmail = true this.errorData = {} this.fileNameList = [] this.$modelForm = this.querySelector('#RadfReviewsForm') this.language = document.querySelector('radf-product-reviews').language this.bindEvent() } bindEvent() { this.querySelector('.radf-reviews-uploader').addEventListener('click', event => { const $uploadBtn = this.querySelector('#reviewUploadPhoto') $uploadBtn.value = ''; $uploadBtn.click() }) this.querySelector('#reviewUploadPhoto').addEventListener('change', event => { event.stopPropagation() this.uploadFileChange(event, '') }) this.querySelector(".username").addEventListener("input", (event) => { if (event.target.value) { this.$usernameError.style.display = 'none' } else { this.$usernameError.style.display = 'block' } }) this.querySelector('.userEmail').addEventListener('input', event => { var reg = /^\w+((.\w+)|(-\w+))@[A-Za-z0-9]+((.|-)[A-Za-z0-9]+).[A-Za-z0-9]+$/ if (!reg.test(event.target.value) || !event.target.value) { this.$emailError.style.display = 'block' this.checkUserEmail = false return } else { this.$emailError.style.display = 'none' this.checkUserEmail = true } }) } connectedCallback() { this.$usernameError = this.querySelector('.radf-reviews-from-username .radf-form-error') this.$emailError = this.querySelector('.radf-reviews-form-email .radf-form-error') this.$confirm = this.querySelector('.radf-reviews-write') this.$cancel = this.querySelector('.radf-reviews-cancel') this.$close = this.querySelector('.radf-reviews-modal__close') const $ModelDom = document.getElementsByClassName('reviews-form-modal') this.$close.addEventListener('click', event => { document.body.removeChild($ModelDom[0]) }) this.$cancel.addEventListener('click', event => { document.body.removeChild($ModelDom[0]) }) this.$confirm.addEventListener('click', event => { const elements = this.$modelForm.elements for (let i = 0; i < elements.length; i++) { const element = elements[i] if (element.name == 'anonymously') { this.reviewForm[element.name] = element.checked ? 1 : 0 } else { this.reviewForm[element.name] = element.value } } const data = { ...this.reviewForm, spuId: this.spuId, commentImages: this.fileNameList, star: this.querySelector('radf-rate').getAttribute('rate') } if (!this.reviewForm.username) { this.$usernameError.style.display = 'block' return } if (this.reviewForm.userEmail == '' || !this.checkUserEmail) { this.$emailError.style.display = 'block' return } fetch(theme.api.createReview, { method: 'POST', body: JSON.stringify(data), headers: theme.headers }) .then(response => response.json()) .then(res => { if (res.code === 0) { document.body.removeChild(document.querySelector('.reviews-form-modal')) this.pageNo = 1 document.querySelector('radf-product-reviews').connectedCallback() } else { Shoptop.APPS_EVENT.toast.error(res.msg) } }) }) } validFileType(files, parent = '') { let flag = true for (const key in files) { if (Object.hasOwnProperty.call(files, key)) { const file = files[key] if (file.type.indexOf('image/') != 0) { flag = false Shoptop.APPS_EVENT.toast.error(this.language.comment_format_error) break } const isLt10M = file.size / 1024 / 1024 < 10 if (!isLt10M) { flag = false Shoptop.APPS_EVENT.toast.error(this.language.comment_size_error) break } } } return flag } setUploaderError(msg, parent) { let box = parent.find('.form-error') box.show() box.html(msg) } uploadFileChange(e, parent) { const files = e.target.files // 文件格式校验 大小校验 let maxCount = 5 let filesLen = files.length let fileListLen = this.reviewForm.commentImages.length if (filesLen == 0) { return } if (filesLen + fileListLen > maxCount) { filesLen = fileListLen return } if (!this.validFileType(files, parent)) return // 获取图片上传签证 fetch(theme.api.aliSign, { method: 'POST', body: JSON.stringify({ fileSize: filesLen }), headers: theme.headers }) .then(response => response.json()) .then(data => { if (data.code != 0) return const ossToken = data.data let index = 0 const promises = [] for (const key in files) { if (Object.hasOwnProperty.call(files, key)) { const element = files[key] const { name, size, type } = element const fileId = ossToken.fileIds[index] if (!fileId) break this.reviewForm.commentImages.push({ name: name + Math.random(0, 9999), size: size, url: '', type: type, state: 'loading', pId: fileId }) const promise = this.ossUpload(element, ossToken, fileId) .then(res => { let nowData = this.reviewForm.commentImages.find(item => item.pId == fileId) nowData.url = res.url nowData.state = 'success' this.uploaderRender() const $removeImgBtn = this.querySelectorAll('.radf-review-remove-image-btn') $removeImgBtn.forEach((item, i) => { item.addEventListener('click', event => { this.deleteImage(item.getAttribute('data-url')) }) }) }) .catch(err => { console.error(err) let index = this.reviewForm.commentImages.findIndex(item => item.pId == fileId) this.deleteImage(index) }) index++ promises.push(promise) } } }) } // 上传文件列表的渲染 uploaderRender() { const $imageBox = this.querySelector('.radf-review-upload-image-box') const $uploadBtn = this.querySelector('.radf-reviews-uploader') $imageBox.innerHTML = '' let len = this.reviewForm.commentImages.length let html = '' this.reviewForm.commentImages.forEach((item, i) => { html += ` <div class="radf-reviews-uploader-list-item"> <img class="img" src="${window.STORE_PARAMS.imageDomain}/${item.url}" /> <span class="radf-review-remove-image-btn" data-url="${item.url}">×</span> </div>` }) $imageBox.innerHTML = html if (len >= 5) { $uploadBtn.style.display = 'none' } else { $uploadBtn.style.display = 'block' } } deleteImage(url) { const $imageBox = this.querySelector('.radf-review-upload-image-box') const $imageList = this.querySelectorAll('.radf-reviews-uploader-list-item') let index = this.reviewForm.commentImages.findIndex(item => item.url == url) this.reviewForm.commentImages.splice(index, 1) this.fileNameList.splice(index, 1) $imageBox.removeChild($imageList[index]) const $uploadBtn = this.querySelector('.radf-reviews-uploader') $uploadBtn.style.display = 'block' } ossUpload(file, ossToken, fileId) { const filename = fileId + this.get_suffix(file.name) const formData = new FormData() //注意formData里append添加的键的大小写 formData.append('key', ossToken.dir + filename) //存储在oss的文件路径 formData.append('OSSAccessKeyId', ossToken.accessId) //accessKeyId formData.append('policy', ossToken.policy) //policy formData.append('signature', ossToken.signature) //签名 formData.append('success_action_status', 200) //成功后返回的操作码 //如果是base64文件,那么直接把base64字符串转成blob对象进行上传就可以了 formData.append('file', file) this.fileNameList.push(filename) return new Promise((resolve, reject) => { fetch(ossToken.host, { method: 'POST', body: formData }).then(() => { resolve({ url: filename }) }) }) } get_suffix(filename) { let pos = filename.lastIndexOf('.') let suffix = '' if (pos != -1) { suffix = filename.substring(pos) } return suffix } } customElements.define('radf-reviews-form', RadfReviewsForm) class ProductInfoRatingExtension extends HTMLElement { constructor() { super() this.spuId = this.getAttribute('spuId') } connectedCallback() { // 判断当前页面是否有评论模块 const reviewsLen = document.querySelectorAll('radf-product-reviews') if (reviewsLen.length) return Promise.all([this.fetchReviewsDetail(), this.fetchLanguage()]).then(res => { if (this.reviewsDetail.commentAvgStar && this.reviewsDetail.publishedCount) { this.renderHtml({ rate: this.reviewsDetail.commentAvgStar, count: this.reviewsDetail.publishedCount, lang: this.language.comment_num }) } }) } fetchLanguage() { return fetch('/api/mbr/global/remind/catalog-query', { method: 'POST', headers: theme.headers, body: JSON.stringify({ catalogs: ['comment'] }) }) .then(response => response.json()) .then(res => { if (res.code == 0) { this.language = res.data.comment return Promise.resolve(res.data) } else { return Promise.reject() } }) } // 获取评论统计数据 fetchReviewsDetail() { return fetch(`/api/mbr/goods/comment/count/star/${this.spuId}`, { method: 'GET' }) .then(response => response.json()) .then(res => { if (res.code == 0) { this.reviewsDetail = res.data return Promise.resolve(res.data) } else { return Promise.reject() } }) } static get observedAttributes() { return ['data-render'] } get dataRender() { this.getAttribute('data-render') } attributeChangedCallback(name, oldVal, newVal) { if (name == 'data-render') { if (window.radfReviewsDetail.detail.commentAvgStar && window.radfReviewsDetail.detail.publishedCount) { this.renderHtml({ rate: window.radfReviewsDetail.detail.commentAvgStar, count: window.radfReviewsDetail.detail.publishedCount, lang: window.radfReviewsDetail.language.comment_num }) return } } } renderHtml({ rate, count, lang }) { const str = `<div class="flex items-center"><radf-rate class="mr-4" rate="${rate}" fixed="true"></radf-rate><span>${count}&nbsp;&nbsp;${lang}</span><div>` this.innerHTML = str } } customElements.define('product-info-rating-extension', ProductInfoRatingExtension) // 数字滚动效果 class NumberScroll extends HTMLElement { constructor() { super() this.$numBox = this.querySelector('.num-box') this.number = this.getAttribute('data-num') this.animationTime = this.getAttribute('data-animation-time') // 控制动画执行次数 this.showAnimation = true this.countAnimation() window.addEventListener('scroll', throttle(this.countAnimation.bind(this))) } countAnimation() { if (this.isElementInViewport() && this.showAnimation) { window.removeEventListener('scroll', this.countAnimation, false) this.showAnimation = false const countUp = new CountUp(this.$numBox, this.number, { duration: this.animationTime }) if (!countUp.error) { countUp.start() } else { // 非数字直接展示 this.$numBox.innerText = this.number } } } isElementInViewport() { const viewWidth = window.innerWidth || document.documentElement.clientWidth const viewHeight = window.innerHeight || document.documentElement.clientHeight const { top, right, bottom, left } = this.$numBox.getBoundingClientRect() return top >= 0 && left >= 0 && right <= viewWidth && bottom <= viewHeight } } customElements.define('number-scroll', NumberScroll) //时间线 class TimelineContainer extends HTMLElement { constructor() { super() // this.$current = this.querySelector('.slider-counter--current') this.newSwiper = undefined } connectedCallback() { this.initSwiper() } initSwiper() { const that = this // this.$current.innerHTML = 1 this.newSwiper = new Swiper(that.querySelector('.timeline_list'), { loop: false, speed: 1000, effect: 'fade', on: { slideChange: function() { // that.$current.innerHTML = this.activeIndex + 1 } } }) this.querySelectorAll('.timeline_page_item').forEach((item, i) => { item.addEventListener('click', function(event) { that.newSwiper.slideTo(i, 1000, false) //切换到第一个slide,速度为1秒 that.querySelectorAll('.timeline_page_item').forEach((item2, i2) => { item2.classList.remove('active') }) item.classList.add('active') }) }) } } customElements.define('timeline-container', TimelineContainer) // 商品列表 class FeaturedCollectionContent extends HTMLElement { constructor() { super() this.isMobileSwiper = this.getAttribute('mobile-swiper') == 'true' this.isPcSwiper = this.getAttribute('pc-swiper') == 'true' this.$current = this.querySelector('.slider-counter--current') this.max_num = Number(this.getAttribute('max-num') || 0) this.length = Number(this.getAttribute('length') || 0) this.newSwiper = undefined } connectedCallback() { this.bindEvent() } initSwiper(column, gap) { const that = this this.$current.innerHTML = 1 // this.querySelector('.slider-counter--total').innerHTML = (this.max_num > this.length ? this.length : this.max_num) - (column - 1) var $pagination = this.querySelector('.featured_collection-pagination') if (this.max_num > column) { $pagination && ($pagination.style.display = 'flex') } else { $pagination && ($pagination.style.display = 'none') } this.newSwiper = new Swiper(that.querySelector('.featured_collection_list_swiper'), { loop: false, slidesPerView: column, // spaceBetween: 15, spaceBetween: gap, speed: 500, pagination: { clickable: true }, navigation: { nextEl: that.querySelector('.collection-slider-button--next'), prevEl: that.querySelector('.collection-slider-button--prev') }, on: { slideChange: function() { that.$current.innerHTML = this.activeIndex + 1 } } }) } getSwiperGap() { const computedStyle = window.getComputedStyle(this) return { desktop: parseFloat(computedStyle.getPropertyValue('--grid-desktop-horizontal-spacing')), mobile: parseFloat(computedStyle.getPropertyValue('--grid-mobile-horizontal-spacing')) } } windowResize() { if (!this.innerWidth) { this.innerWidth = window.innerWidth } if ((this.innerWidth > 750 && window.innerWidth < 750) || (this.innerWidth < 750 && window.innerWidth > 750)) { this.newSwiper && this.newSwiper.destroy() this.newSwiper = undefined var $pagination = this.querySelector('.featured_collection-pagination') $pagination && ($pagination.style.display = 'none') this.querySelectorAll('.swiper-wrapper').forEach(item => { item.setAttribute('style', '') }) this.querySelectorAll('.swiper-slide').forEach(item => { item.setAttribute('style', '') }) this.innerWidth = window.innerWidth } const gap = this.getSwiperGap() if (window.innerWidth > 750) { if (this.isPcSwiper) { if (!this.newSwiper) { this.initSwiper(this.getAttribute('pc-column'), gap.desktop) } } } else { if (this.isMobileSwiper) { if (!this.newSwiper) { this.initSwiper(this.getAttribute('mobile-column'), gap.mobile) } } } } bindEvent() { this.windowResize() window.addEventListener('resize', throttle(this.windowResize.bind(this))) } } customElements.define('featured-collection-content', FeaturedCollectionContent) // 分享按钮 class ShareButton extends HTMLElement { constructor() { super() this.title = this.getAttribute('title') this.elements = { shareButton: this.querySelector('button'), closeButton: this.querySelector('.share-button__close'), successMessage: this.querySelector('[id^="ShareMessage"]'), urlInput: this.querySelector('input'), label: this.querySelector('label'), share_button_wrap: this.querySelector('.share-button__fallback') } this.elements.urlInput.value = document.location.href this.urlToShare = document.location.href this.bindEvent() } bindEvent() { const that = this if (navigator.share) { this.elements.shareButton.addEventListener('click', () => { navigator.share({ url: this.urlToShare, title: document.title }) }) } else { this.elements.shareButton.addEventListener('click', function(event) { that.elements.share_button_wrap.style.display = 'flex' that.elements.closeButton.classList.add('hidden') }) this.querySelector('.share-button__copy').addEventListener('click', this.copyToClipboard.bind(this)) this.querySelector('.share-button__close').addEventListener('click', this.close.bind(this)) } } copyToClipboard() { navigator.clipboard.writeText(this.elements.urlInput.value).then(() => { this.elements.successMessage.classList.remove('hidden') this.elements.label.style.marginLeft = this.elements.successMessage.clientWidth + 'px' this.elements.closeButton.classList.remove('hidden') this.elements.closeButton.focus() }) } close() { this.elements.successMessage.classList.add('hidden') this.elements.share_button_wrap.style.display = 'none' this.elements.closeButton.classList.add('hidden') this.elements.label.style.marginLeft = '0' } } customElements.define('share-button', ShareButton) class RadfBlogPost extends HTMLElement { constructor() { super() this.sectionId = this.getAttribute('section-id') } connectedCallback() { this.mySwiper = new Swiper(`.slideshow-${this.sectionId}`, {}) } } customElements.define('radf-blog-post', RadfBlogPost) // 处理多列放大功能 class heZoomImage extends HTMLElement { constructor(imageSrc) { super() } connectedCallback() { this.imageSrc = this.getAttribute("data-image-src") const templateElem = document.querySelector("#he-zoom-image-template") const content = templateElem.content.cloneNode(true); content.querySelector("img").src = this.imageSrc this.appendChild(content); this.$zoom = this.querySelector(".he-zoom__btn") this.$zoomIn = this.querySelector(".he-zoom__btn-in") this.$zoomOut = this.querySelector(".he-zoom__btn-out") this.$close = this.querySelector(".he-zoom__btn-close") this.zoomSwiper = new Swiper('.he-zoom-image-swiper', { zoom: true, //开启缩放功能 }) this.bindEvent() } bindEvent() { this.querySelector(".swiper-zoom-bg").addEventListener("click", () => { if (this.zoomSwiper.zoom.scale == 1) { this.remove() } }) this.$close.addEventListener("click", () => this.remove()) this.zoomSwiper.on("zoomChange", () => { if (this.zoomSwiper.zoom.scale == 1) { this.zoomOut() } else { this.zoomIn() } }) this.$zoom.addEventListener("click", (e) => { const dataZoom = e.target.getAttribute("data-zoom") if (dataZoom == 'in') { this.zoomSwiper.zoom.in(); this.zoomOut() } else { this.zoomSwiper.zoom.out(); this.zoomIn() } }) } zoomIn() { this.$zoom.setAttribute("data-zoom", 'in') this.$zoomIn.classList.remove("hidden") this.$zoomOut.classList.add('hidden') } zoomOut() { this.$zoom.setAttribute("data-zoom", 'out') this.$zoomIn.classList.add("hidden") this.$zoomOut.classList.remove('hidden') } } window.customElements.define('he-zoom-image', heZoomImage); class xtLightbox { constructor({ gallery }) { console.log(11111111111) this.targetTag = "xt-preview-image-item" this.originSrc = null gallery.addEventListener('click', (e) => { console.log("xtLightbox",e) if (e.target.hasAttribute(this.targetTag)) { e.preventDefault() this.parseImageSrc(e.target) } }) } render() { const mask = document.createElement('he-zoom-image') mask.setAttribute("data-image-src", this.originSrc) // 添加在body下 document.body.appendChild(mask) } parseImageSrc(target) { this.originSrc = target.getAttribute("srcset").split(",")[0].split("?")[0] const img = new Image() img.src = this.originSrc this.render() } } class RadfMutiVideoColumn extends HTMLElement { constructor() { super() this.sectionId = this.getAttribute('section-id') this.mvc_columns_desktop = this.getAttribute('column-count') this.swiper_time = Number(this.getAttribute('swiper-time')) || 0 this.enableZoomImage = this.getAttribute('enable-preview-image') === "true" } connectedCallback() { const element = this.querySelector(`.swiper-${this.sectionId}`) this.swiper = new Swiper(element, { slidesPerView: 1, spaceBetween: 25, autoplay: this.swiper_time > 0 ? { delay: this.swiper_time * 1000 } : false, navigation: { nextEl: `#multi-video-column-${this.sectionId}-controls .next`, prevEl: `#multi-video-column-${this.sectionId}-controls .prev`, }, pagination: { el: `.swiper-${this.sectionId}-pagination`, clickable: true, }, breakpoints: { 750: { slidesPerView: parseInt(this.mvc_columns_desktop), }, }, }) this.listen() } listen() { this.querySelectorAll('.multi-video-column-item').forEach((elem, index) => { const item = elem.querySelector('.multi-video-column-item-image') if(!item?.querySelector('div[layout=play]')) return item?.querySelector('div[layout=play]')?.addEventListener('click', () => { const video_wrap = document.createElement('div') video_wrap.classList.add('multi-video-column-item-image-fixed') video_wrap.addEventListener('click', (event) => (event.target === video_wrap) && document.body.removeChild(video_wrap)) const closeButton = document.createElement('div') closeButton.classList.add('fixed-close') closeButton.innerHTML = `<svg aria-hidden="true" focusable="false" role="presentation" viewBox="0 0 24 24" fill="#fff"><path d="M18 6L6 18M6 6l12 12"></path></svg>` closeButton.addEventListener('click', (event) => document.body.removeChild(video_wrap)) const mobile_width = this.getBoundingClientRect().width const play_url = elem?.getAttribute('play_url') || '' const play_css = `position: absolute; width: 80%; height: 80%; max-height: 80%; top: 50%; left: 50%; transform: translate(-50%, -50%);` const isYoutube = (play_url.indexOf('www.youtube.com') != -1 || play_url.indexOf('youtu.be') != -1) ? true : false const isVimeo = play_url.indexOf('vimeo.com') > -1 if (isYoutube) { const container = document.createElement('div') container.style.cssText = play_css if (mobile_width < 750) { container.style['width'] = `100%`; container.style['height'] = `${mobile_width}px`; } else { container.style['height'] = `${mobile_width * 0.5625}px`; } const iframe = this.getIframe(`https://www.youtube.com/embed/${this.getYoutubeLink(play_url)}?enablejsapi=1&autoplay=1&loop=1&playlist=${this.getYoutubeLink(play_url)}`) iframe.style.cssText = `width: 100%; height: 100%;` container.appendChild(iframe) video_wrap.appendChild(closeButton) video_wrap.appendChild(container) } else if (isVimeo) { const container = document.createElement('div') container.style.cssText = play_css if (mobile_width < 750) { container.style['width'] = `100%`; container.style['height'] = `${mobile_width}px`; } else { container.style['height'] = `${mobile_width * 0.5625}px`; } const iframe = this.getIframe(`https://player.vimeo.com/video/${play_url.split('https://vimeo.com/')[1]}?loop=1`) iframe.style.cssText = `width: 100%; height: 100%;` container.appendChild(iframe) video_wrap.appendChild(closeButton) video_wrap.appendChild(container) } else { const container = document.createElement('div') container.style.cssText = play_css // const source = document.createElement('source') // source.setAttribute('type', 'video/mp4') // source.setAttribute('src', play_url) // const video = document.createElement('video') // video.style.cssText = play_css // video.style['height'] = "auto"; // video.controls = true // video.muted = true // video.autoplay = true // video.setAttribute('preload', 'metadata') // video.setAttribute('playsinline', 'true') // video.setAttribute('x5-playsinline', 'true') // video.setAttribute('webkit-playsinline', 'true') // video.addEventListener('click', (_event) => _event.stopPropagation()) // 为了兼容IOS, 一定要阻止冒泡 // video.appendChild(source) const $video = document.getElementById(`multi-video-mp4-template-${index}-${this.sectionId}`)?.content?.querySelector('video') if ($video) { $video.style.cssText = `width: 100%; height: 100%;` $video.setAttribute('playsinline', 'true') $video.setAttribute('x5-playsinline', 'true') $video.setAttribute('webkit-playsinline', 'true') container.appendChild($video.cloneNode(true)) setTimeout(() => $video.play(), 255) } if (mobile_width < 750) { container.style['width'] = `100%`; } video_wrap.appendChild(closeButton) video_wrap.appendChild(container) } // 清除浮层 document.body.appendChild(video_wrap) }) }) if(this.enableZoomImage ) { // 图片放大功能 new xtLightbox({ gallery: this }) } } getYoutubeLink(url) { const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/; const match = url?.match(regExp); const videoId = (match && match[2].length === 11) ? match[2] : null; return videoId } getIframe(src) { const iframe = document.createElement('iframe') iframe.setAttribute('src', src) iframe.setAttribute('frameborder', "0") iframe.setAttribute('loop', "true") iframe.setAttribute('allowfullscreen', "true") iframe.setAttribute('allow', "autoplay; encrypted-media; loop;") return iframe } } customElements.define('radf-muti-video-column', RadfMutiVideoColumn) class RadfProductDesc extends HTMLElement { constructor() { super() } connectedCallback() { const $wrap = this.querySelector("ul") const type = this.getAttribute("data-type") if (type !== 'tab') return this.hdClass = 'accordion-hd-active' this.bdClass = 'accordion-bd-active' this.getAllLi().forEach(($li, index) => { $li.addEventListener("click", (event) => { this.calearHdActive() event.target.classList.add(this.hdClass) this.handleClick(index) }) }) } handleClick(index) { const $accordions = this.querySelectorAll(".product__accordion") const sItem = $accordions[index] $accordions.forEach($accordion => { $accordion.classList.remove(this.bdClass) }) sItem.querySelector("details").open = true sItem.classList.add(this.bdClass) } getAllLi() { return this.querySelectorAll("ul li") } calearHdActive() { this.getAllLi().forEach($li => { $li.classList.remove(this.hdClass) }) } } customElements.define("radf-product-desc", RadfProductDesc) class RadfFooter extends HTMLElement { constructor() { super() // this.enableAccordion = this.getAttribute("data-accordion") === 'true' // if(this.enableAccordion) { this.mediaChange() window.matchMedia('(max-width: 750px)').addEventListener('change', this.mediaChange.bind(this)) // } } mediaChange() { if (window.matchMedia('(max-width: 750px)').matches) { this.getAllDetails().forEach($el => { $el.removeAttribute('open') }) } else { this.getAllDetails().forEach($el => { $el.setAttribute('open', true) }) } } getAllDetails() { return this.querySelectorAll("details") } } customElements.define("radf-footer", RadfFooter) </script> <script> const customer = { api: { login: '/api/mbr/login', register: '/api/mbr/user/register', sendCode: '/api/mbr/user/safety-code', resetPasd: '/api/mbr/user/forget-password', getAreas: '/api/mbr/phone/area/list', getCountry: '/api/mbr/country/all', getCartNum: '/api/mbr/shopping/cart', formAddress: '/api/mbr/customer/address', getAddress: '/api/mbr/customer/address/page', addressProvince: '/api/mbr/province/list-code2/', deleAddress: '/api/mbr/customer/address/delete/', batchOrders: '/api/mbr/shopping/cart/batchAdd', commonOrder: `/api/mbr/order/`, signOutUser: '/api/mbr/logout', accountOrder: '/api/mbr/order/page', orderLanguage: '/api/mbr/global/remind', orderTracking: '/api/mbr/shipping/track/standard' }, rules: { login: { email: [ { required: true, message: "Email is required" }, { type: false, message: "Please enter a valid email.", pattern: /^[a-zA-Z0-9!#$%&'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/ } ], password: [ { required: true, message: "Password is required." }, { minLength: 6, message: "Password must be between 7-16 characters long." }, { maxLength: 16, message: "Password must be between 7-16 characters long." } ] }, register: { firstName: [ { required: true, message: "First name is required." }, { maxLength: 50, message: "Cannot exceed 50 characters ." }, { type: true, message: "Contains invalid characters", pattern: /[~!@#$%^&*()_+<>?:"{}\/;[\]\s]/ } ], lastName: [ { required: true, message: "Last name is required." }, { maxLength: 50, message: "Cannot exceed 50 characters ." }, { type: true, message: "Contains invalid characters", pattern: /[~!@#$%^&*()_+<>?:"{}\/;[\]\s]/ } ] }, resetPasd: { password: [ { required: true, message: "Password is required." }, { minLength: 6, message: "Password must be between 7-16 characters long." }, { maxLength: 16, message: "Password must be between 7-16 characters long." } ], confirmPw: [ { some: true, message: "Your password and confirmation password do not match" } ] }, addressModal: { countryCode: [ { required: true, message: "Please select your country" } ], email: [ { required: true, message: "Email is required" }, { type: false, message: "Please enter a valid email.", pattern: /^[a-zA-Z0-9!#$%&'*+\\/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+\\/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/ } ] } }, loadScript: function () { var script = document.createElement('script') script.type = 'text/javascript' script.src = 'https://static.shoptop.com/npm/js-sha256@0.9.0/sha256.min.js' document.getElementsByTagName('head')[0].appendChild(script) }, fetchError(response) { const { msg, code, data, errorCode } = response if (code === 1) { if (!data) { showToast(msg, 'error') if (document.getElementById('loadingCover')) { hideLoading() } } } if (errorCode === 401) { window.safeHref = `/account/login?return_url=${encodeURI(window.location.pathname)}` } if (data && code === 0) { return data } } } /* CONTENT COPY */ function copyContent(text) { var tempInput = document.createElement('input') tempInput.value = text document.body.appendChild(tempInput) tempInput.select() document.execCommand('copy') document.body.removeChild(tempInput) showToast('Copy successfully') } /* DOWNLOAD FILES */ function downFile(src, name) { const x = new window.XMLHttpRequest() x.open('GET', src, true) x.responseType = 'blob' x.onload = () => { const url = window.URL.createObjectURL(x.response) const a = document.createElement('a') a.href = url a.download = name a.click() } x.send() } class CustomerLogin extends HTMLElement { constructor() { super() this.listenerForm() customer.loadScript() this.returnUrl = '/' if (JSON.stringify(urlParams()) !== '{}' && urlParams().return_url) { this.returnUrl = urlParams().return_url } } listenerForm() { var _self = this document.getElementById('customer_login').addEventListener('submit', function (event) { event.preventDefault() var formJson = {} var formData = new FormData(event.target) formData.forEach(function (value, key) { formJson[key] = value }) var errors = validateForm(formJson, customer.rules.login) if (errors.length) { var errElement = event.target.querySelector('.errors') errElement.innerHTML = '' errors.forEach(item => { var li = document.createElement('li') li.textContent = item errElement.appendChild(li) }) } else { formJson.password = formJson.password ? sha256(formJson.password) : '' _self.loginParams(formJson, event.target) } }) } loginParams(data, event) { var loading = event.querySelector('button') var errElement = event.querySelector('.errors') errElement.innerHTML = '' loading.classList.add('loading') fetch(customer.api.login, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }) .then(response => response.json()) .then(res => { loading.classList.remove('loading') const { code, msg, data } = res if (code == 0) { window.Shoptop.event.emit('dataTrack:login') setCookie('User-Agents', data.access_token, { path: '/', expires: Number(data.expires_in) / 86400 }) window.safeHref = this.returnUrl } else { showToast(msg, 'error') } }) .catch(error => { loading.classList.remove('loading') }) } } customElements.define('customer-login', CustomerLogin) class CustomerSignOut extends HTMLElement { constructor() { super() this.addEventListener('click', event => { event.preventDefault() fetch(customer.api.signOutUser, fetchConfig('DELETE')) .then(response => response.json()) .then(res => { if (res.code === 0) { window.Shoptop.event.emit('dataTrack:logout') delCookie('User-Agents') delete window.Shoptop.userId window.safeHref = '/' } }) .catch(error => { console.error(error) showToast(error, 'error') }) .finally(() => { }) }) } } customElements.define('customer-signout', CustomerSignOut) class CustomerRegister extends HTMLElement { constructor() { super() this.listenerForm() customer.loadScript() } listenerForm() { const _self = this document.getElementById('customer_register').addEventListener('submit', function (event) { event.preventDefault() const formJson = {} const formData = new FormData(event.target) formData.forEach(function (value, key) { formJson[key] = value }) const rules = Object.assign(customer.rules.register, customer.rules.login) const errors = validateForm(formJson, rules) const errElement = event.target.querySelector('.errors') const loading = event.target.querySelector('button') if (errors.length) { errElement.innerHTML = '' errors.forEach(item => { const li = document.createElement('li') li.textContent = item errElement.appendChild(li) }) } else { formJson.subscribed = 0 formJson.password = formJson.password ? sha256(formJson.password) : '' _self.registerParams(formJson, event.target) } }) } registerParams(data, event) { const _self = this const loading = event.querySelector('button') const errElement = event.querySelector('.errors') errElement.innerHTML = '' loading.classList.add('loading') fetch(customer.api.register, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }) .then(response => response.json()) .then(res => { loading.classList.remove('loading') if (res.code == 0) { window.Shoptop.event.emit('dataTrack:signUp') setCookie('User-Agents', res.data.access_token, { path: '/', expires: Number(res.data.expires_in) / 86400 }) window.safeHref = '/' } else { showToast(error, 'error') } }) .catch(error => { console.error(error) loading.classList.remove('loading') }) } } customElements.define('customer-register', CustomerRegister) class CustomerResetPasd extends HTMLElement { constructor() { super() this.listenerForm() customer.loadScript() } listenerForm() { const _self = this document.getElementById('customer_reset').addEventListener('submit', function (event) { event.preventDefault() const formJson = {} const formData = new FormData(event.target) formData.forEach(function (value, key) { formJson[key] = value }) const rules = { email: customer.rules.login.email } const errors = validateForm(formJson, rules) if (errors.length) { const errElement = event.target.querySelector('.errors') errElement.innerHTML = '' errors.forEach(item => { const li = document.createElement('li') li.textContent = item errElement.appendChild(li) }) } else { formJson.type = 1 const loading = event.target.querySelector('button') const errElement = event.target.querySelector('.errors') errElement.innerHTML = '' loading.classList.add('loading') fetch(customer.api.sendCode, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formJson) }) .then(response => response.json()) .then(res => { loading.classList.remove('loading') if (res.code == 0) { event.target.style.display = 'none' _self.resetPassword(formJson.email) showToast("Retrieved password mail successfully", 'error') } else { showToast(error, 'error') } }) .catch(error => { console.error(error) loading.classList.remove('loading') }) } }) } resetPassword(email) { document.getElementById('customer_resetpw').style.display = 'block' document.getElementById('customer_resetpw').addEventListener('submit', function (event) { event.preventDefault() const formJson = {} const formData = new FormData(event.target) formData.forEach(function (value, key) { formJson[key] = value }) const errors = validateForm(formJson, customer.rules.resetPasd) if (errors.length) { const errElement = event.target.querySelector('.errors') errElement.innerHTML = '' errors.forEach(item => { const li = document.createElement('li') li.textContent = item errElement.appendChild(li) }) } else { const loading = event.target.querySelector('button') const errElement = event.target.querySelector('.errors') const formParams = { email: email, safetyCode: formJson.safetyCode, password: sha256(formJson.password) } errElement.innerHTML = '' loading.classList.add('loading') fetch(customer.api.resetPasd, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(formParams) }) .then(response => response.json()) .then(res => { loading.classList.remove('loading') if (res.code == 0) { window.safeHref = '/account/login' } else { showToast(error, 'error') } }) .catch(error => { console.error(error) loading.classList.remove('loading') }) } }) } } customElements.define('customer-reset', CustomerResetPasd) class CustomerAddress extends HTMLElement { constructor() { super() showLoading() this.addressModel = { address: {}, provinces: [], countrys: [], areaList: [] } this.getAddressList() this.multipleApis() .then(results => { this.addressModel.areaList = results[0]?.data || [] this.addressModel.countrys = results[1]?.data || [] }) .catch(error => { console.error('Failed to fetch APIs:', error) }) } async multipleApis() { const urls = [customer.api.getAreas, customer.api.getCountry] const fetchPromises = urls.map(url => fetch(url)) try { const responses = await Promise.all(fetchPromises) const dataPromises = responses.map(response => response.json()) const results = await Promise.all(dataPromises) return results } catch (error) { console.error('Error:', error) throw error } } getAddressList() { fetch(customer.api.getAddress, fetchConfig('GET')) .then(response => response.json()) .then(res => { const data = customer.fetchError(res) if (data) { const addressHtml = window.template('address-art-tpl', { addressList: res.data.list || [] }) document.querySelector('.account__order-address').innerHTML = addressHtml this.eventButton() } }) .catch(error => { console.error(error) showToast(error, 'error') }) .finally(() => { if (document.getElementById('loadingCover')) { hideLoading() } }) } eventButton() { this.querySelectorAll('a[href="javascript:;"]').forEach(button => button.addEventListener('click', event => { const data = event.target.closest('a').dataset; if (data.type === 'delete') { this.removeAddress(data.id) } else if (data.type === 'edit') { this.getAddressInfo(data.id) } else { this.renderAddress() } }) ) } renderAddress(data) { const render = document.querySelector('.customer__addesss-modal') const addressModal = window.template('cart-address-modal-tpl', this.addressModel) render.innerHTML = addressModal document.body.classList.add('overflow-hidden') render.querySelectorAll('button').forEach(button => button.addEventListener('click', event => { const id = this.addressModel.address?.id || null const button = event.target.closest('button').dataset; const type = button.type || 'cancel' if (type === 'confirm') { this.updataAddress(id, render, event.target.classList) } else { render.innerHTML = '' document.body.classList.remove('overflow-hidden') } }) ) render.querySelectorAll('select').forEach(select => select.addEventListener('change', event => { const select = event.target.closest('select').dataset const type = select.type const option = event.target.selectedOptions[0] if (type === 'country') { this.addressModel.address.country = option.label this.addressModel.address.countryCode = option.value this.getProvinces(option.value) } }) ) } getAddressInfo(id) { fetch(`${customer.api.formAddress}/${id}`, fetchConfig('GET')) .then(response => response.json()) .then(res => { if (res.code === 0) { this.addressModel.address = { id: id, zip: res.data.zip, city: res.data.city, phone: res.data.phone, email: res.data.email, company: res.data.company, country: res.data.country, address: res.data.address, lastName: res.data.lastName, province: res.data.province, address1: res.data.address1, firstName: res.data.firstName, countryCode: res.data.countryCode, provinceCode: res.data.provinceCode, phoneAreaCode: res.data.phoneAreaCode, defaultFlag: res.data.defaultFlag == 1 ? true : false } this.renderAddress() this.getProvinces(res.data.countryCode) } }) .catch(error => { console.error(error) }) .finally(() => { }) } getProvinces(country) { fetch(customer.api.addressProvince + country, fetchConfig('GET')) .then(response => response.json()) .then(res => { if (res.code === 0) { const provinces = res.data || [] const render = document.querySelector('.customer__addesss-province') const provincesSelect = window.template('cart-address-province-tpl', { provinces, address: this.addressModel.address }) render.innerHTML = provincesSelect render.querySelectorAll('select').forEach(select => select.addEventListener('change', event => { const select = event.target.closest('select').dataset const type = select.type || 'province' const option = event.target.selectedOptions[0] if (type === 'province') { this.addressModel.address.province = option.label this.addressModel.address.provinceCode = option.value } }) ) } }) .catch(error => { console.error(error) }) .finally(() => { }) } updataAddress(id, render, button) { const formJson = {} button.add('loading') const formMethod = id ? 'PUT' : 'POST' const formUrl = id ? `${customer.api.formAddress}/update` : `${customer.api.formAddress}/add` const form = document.getElementById('customer__address-form') const formData = new FormData(form); formData.forEach(function (value, key) { formJson[key] = value }) formJson.id = this.addressModel.address.id formJson.defaultFlag = formJson.defaultFlag ? 1 : 0 formJson.country = this.addressModel.address.country formJson.province = this.addressModel.address.province formJson.countryCode = this.addressModel.address.countryCode formJson.provinceCode = this.addressModel.address.provinceCode const errors = validateForm(formJson, customer.rules.addressModal) if (errors.length) { const errElement = render.querySelector('.errors') errElement.innerHTML = '' errors.forEach(item => { const li = document.createElement('li') li.textContent = item errElement.appendChild(li) }) button.remove('loading') return } fetch(formUrl, { ...fetchConfig(formMethod), ...{ body: JSON.stringify(formJson) } }) .then(response => response.json()) .then(res => { if (res.code === 0) { render.innerHTML = '' button.remove('loading') this.getAddressList() document.body.classList.remove('overflow-hidden') } else { button.remove('loading') showToast(res.msg, 'error') } }) .catch(error => { console.error(error) showToast(res.msg, 'error') }) .finally(() => { }) } removeAddress(id) { const result = window.confirm("Are you sure you wish to delete this address?") if (result) { fetch(customer.api.deleAddress + id, fetchConfig('DELETE')) .then(response => response.json()) .then(res => { if (res.code === 0) { this.getAddressList() } }) .catch(error => { console.error(error) }) .finally(() => { }) } } } customElements.define('customer-address', CustomerAddress) class CustomerOrder extends HTMLElement { constructor() { super() showLoading() this.tabIndex = 1 const tabsMap = [ 'All Order', 'Awaiting Payment', 'Awaiting Shipment', 'Shipping', 'Payment Pending', 'Completed', 'Post-sale' ] const orderTabs = window.template('order-art-tpl', { tabsMap: tabsMap }) document.querySelector('.account__order-left').innerHTML = orderTabs this.eventListener('init') } eventListener(type) { if (type && type === 'init') { this.querySelector('.account__order-tabs li').classList.add('active') } this.querySelector('.account__order-tabs') .querySelectorAll('li') .forEach(li => { li.addEventListener('click', event => { const clickedLi = event.currentTarget const allLis = Array.from(li.parentElement.children) const orderItem = document.querySelector('customer-order-item') allLis.forEach(li => li.classList.remove('active')) clickedLi.classList.add('active') this.tabIndex = clickedLi.dataset.index orderItem.pageNo = 1 orderItem.hasMore = false orderItem.orderModel.orderList = [] orderItem.getOrderList(clickedLi.dataset.index) }) }) } } customElements.define('customer-order', CustomerOrder) class CustomerOrderItem extends HTMLElement { constructor() { super() this.pageNo = 1 this.pageSize = 10 this.hasMore = false this.orderModel = { orderList: [], orderStatus: [ '', "Pending", "Active", "Cancelled", "Completed" ], payStatus: [ "Awaiting Payment", "Payment Pending", "Paid", "Cancelled", "Failed", "Awaiting Refund", "Refund Failure", "Refunded", "Partially refunded", "Partial payment" ], shipStatus: [ "None", "Awaiting Shipment", "Partially Shipped", "All Shipped", "Partially Delivered", "All Delivered", "Cancelled", "Awaiting Return", "Return" ] } this.getOrderList(1) window.addEventListener('scroll', throttle(this.handleScroll.bind(this), 200)) } handleScroll() { const scrollTop = window.scrollY const windowHeight = window.innerHeight const index = document.querySelector('customer-order').tabIndex const scrollHeight = document.querySelector('.order-layout').scrollHeight const headHeight = Math.max(document.querySelector('header').offsetHeight, 50) document.querySelector('.account__order-tabs').style.top = headHeight + 'px' document.querySelector('.account_order-navbar').style.top = 0 + 'px' if (scrollTop + windowHeight >= scrollHeight && this.hasMore) { this.pageNo = this.pageNo + 1 this.getOrderList(index) } } getOrderList(status) { const orderUrl = `${customer.api.accountOrder}?pageNo=${this.pageNo}&pageSize=${this.pageSize}&queryStatus=${status}` fetch(orderUrl, fetchConfig('GET')) .then(response => response.json()) .then(res => { const data = customer.fetchError(res) const list = data?.list || [] this.orderModel.orderList = [...this.orderModel.orderList, ...list] this.hasMore = Number(data.total) > this.pageNo * this.pageSize const orderHtml = window.template('order-items-art-tpl', this.orderModel) document.querySelector('.account__order-item').innerHTML = orderHtml }) .catch(error => { console.error(error) showToast(error, 'error') }) .finally(() => { if (document.getElementById('loadingCover')) { hideLoading() } }) } } customElements.define('customer-order-item', CustomerOrderItem) class CustomerOrderButton extends HTMLElement { constructor() { super() this.orderId = this.getAttribute('data-id') this.name = this.getAttribute('data-name') // 获取当前 orderId 所指定的数据 this.orderDetail = null this.products = null // 订单状态 this.orderStatus = null // 支付状态 this.payStatus = null // 支付方式 this.paymentMethod = null // 物流状态 this.shippingStatus = null // 售后状态 this.postSaleStatus = null this.setData() this.renderContent() } setData() { if (this.name === 'order') { const endpoint = 'customer-order-item' this.orderDetail = document.querySelector(endpoint).orderModel.orderList.find(v => v.orderToken === this.orderId) this.products = this.orderDetail.lineItems this.orderStatus = this.orderDetail.orderStatus this.payStatus = this.orderDetail.financialStatus this.paymentMethod = this.orderDetail.paymentMethod this.shippingStatus = this.orderDetail.fulfillmentStatus this.postSaleStatus = this.orderDetail.postSaleStatus } else if (this.name === 'orderDetail') { const endpoint = 'customer-order-detail' this.orderDetail = document.querySelector(endpoint).orderDetail this.products = this.orderDetail.products const { orderInfo, payments } = this.orderDetail this.orderStatus = orderInfo.status this.payStatus = orderInfo.financialStatus this.paymentMethod = payments && payments.paymentMethod this.shippingStatus = orderInfo.fulfillmentStatus this.postSaleStatus = orderInfo.postSaleStatus } } renderContent() { const template = document.querySelector("#order-anction-template") const content = template.content.cloneNode(true); const renderObj = { cancel: this.isCancel(), delete: this.isDelete(), addtocart: this.isAddToCart(), payNow: this.isPayNow(), } content.querySelectorAll('[data-type]').forEach($el => { const type = $el.getAttribute('data-type') if (type === 'payNow' && this.paymentMethod === 'offline') { $el.href = `/checkout/${this.orderId}/detail` } if (!renderObj[type]) return $el.removeAttribute('hidden') if ($el.tagName === 'A') return $el.addEventListener('click', event => { if (type === 'addtocart') { this.addCarts($el) } if (type === 'cancel' || type === 'delete') { this.handleOrder($el, this.name, type, this.orderId) } }) }) content.querySelectorAll('a').forEach($el => { const href = $el.href $el.href = href.replace(/\${orderId}/g, this.orderId) }) this.appendChild(content) } isCancel() { if (this.orderStatus === 1 && (this.postSaleStatus === null || this.postSaleStatus === 3)) { const payStatus = [1, 5, 6, 7, 8, 9] if (payStatus.includes(this.payStatus)) return false if (this.shippingStatus !== 0 && this.shippingStatus !== 1) return false return true } else { return false } } isDelete() { return this.orderStatus === 3 || this.orderStatus === 4 } isAddToCart() { return (this.orderStatus === 3 || this.payStatus === 4) && this.postSaleStatus === null } isPayNow() { if (this.paymentMethod === 'offline') { return this.payStatus === 0 && this.orderStatus === 2 } else { return this.orderStatus === 1 && (this.payStatus === 0 || this.payStatus === 3 || this.payStatus === 4) && this.paymentMethod !== 'cod' } } async addCarts(event) { event.classList.add('loading') if (!this.products.length) return const cartItems = new FormData() this.products.forEach((item, index) => { cartItems.append(`lineItems[${index}].goodsId`, item.variantId) cartItems.append(`lineItems[${index}].productId`, item.productId) cartItems.append(`lineItems[${index}].goodsNum`, item.quantity) cartItems.append(`lineItems[${index}].moreOptions`, item.moreOptions) cartItems.append(`lineItems[${index}].attachments`, item.attachments) }) try { const response = await fetch(customer.api.batchOrders, { ...fetchConfig('POST', 'form'), ...{ body: cartItems } }) const res = await response.json() const data = customer.fetchError(res) if (data) { this.getCartTotal() event.classList.remove('loading') } } catch (error) { console.error(error) showToast(error, 'error') event.classList.remove('loading') } } handleOrder(event, name, type, id) { const result = window.confirm( { cancel: "Cancelled orders cannot be recovered. &lt;br/&gt;Do you still want to continue?", delete: "Deleted order cannot be recovered. &lt;br/&gt;Do you still want to continue?" }[type] ) if (result) { event.classList.add('loading') const method = type === 'delete' ? 'DELETE' : 'POST' const path = type === 'delete' ? `/api/mbr/order/${id}` : `/api/mbr/order/${id}/cancel` fetch(path, fetchConfig(method)) .then(response => response.json()) .then(res => { const data = customer.fetchError(res) if (name === 'order') { const index = document.querySelector('customer-order').tabIndex document.querySelector('customer-order-item').getOrderList(index) } if (name === 'orderDetail') { showLoading() document.querySelector('customer-order-detail').getOrderDetail() } }) .catch(error => { console.error(error) showToast(error, 'error') }) .finally(() => { event.classList.remove('loading') }) } } getCartTotal() { fetch(customer.api.getCartNum, fetchConfig('GET')) .then(response => response.json()) .then(res => { const { code, data } = res if (code === 0) { const cartCount = data?.itemCount || 0 const cartCountElement = document.getElementById('cartCount') const cartCountBubble = document.querySelector('.cart-count-bubble') cartCount === 0 ? cartCountBubble.classList.add('hidden') : ((cartCountElement.innerHTML = cartCount), cartCountBubble.classList.remove('hidden')) } }) .catch(error => { console.error(error) showToast(error, 'error') }) .finally(() => { }) } } customElements.define('customer-order-button', CustomerOrderButton) class CustomerOrderDetail extends HTMLElement { constructor() { super() showLoading() const splittedUrl = location.pathname.split('/') this.orderId = splittedUrl[splittedUrl.length - 1] this.initDetail() this.orderLanguage() this.getOrderDetail() } initDetail() { this.orderDetail = { appLang: [], orderShip: [], giftCards: [], products: [], orderInfo: {}, payments: [], customer: [], orderStatus: [ '', "Pending", "Active", "Cancelled", "Completed" ], payStatus: [ "Awaiting Payment", "Payment Pending", "Paid", "Cancelled", "Failed", "Awaiting Refund", "Refund Failure", "Refunded", "Partially refunded", "Partial payment" ], shipStatus: [ "None", "Awaiting Shipment", "Partially Shipped", "All Shipped", "Partially Delivered", "All Delivered", "Cancelled", "Awaiting Return", "Return" ], productShip: [ "Awaiting Shipment", "Shipped", "Delivered", "Cancelled" ], afterSales: [ "POST-SALE", "POST-SALE", "POST-SALE" ] } } orderLanguage() { const urls = [customer.api.orderLanguage + '?catalog=productUnreal', customer.api.orderLanguage + '?catalog=B2BAssistant']; const requests = urls.map(url => fetch(url)); Promise.all(requests) .then(responses => { return Promise.all(responses.map(response => response.json())); }) .then(dataArray => { let languages = {} dataArray.forEach(lang => { languages = Object.assign(languages, lang.data.settings) }) this.orderDetail.appLang = languages }) .catch(error => { console.log('GET LANGUAGE ERROR', error); }); } getOrderDetail() { fetch(customer.api.commonOrder + `/${this.orderId}`, fetchConfig('GET')) .then(response => response.json()) .then(res => { const data = customer.fetchError(res) if (!data) return const giftCards = data.paymentLines ? data.paymentLines .filter(v => v.paymentMethod === 'gift_card') .map(item => ({ realPaidTotal: item.realPaidTotal, name: item.creditCardNumber.substr(-4).toUpperCase(), balance: JSON.parse(item.extraInfo).currentBalance, currency: JSON.parse(item.extraInfo).realAmountCurrency })) : [] if (data.orderInfo.discountTotal < 0) { data.orderInfo.absDiscountTotal = Math.abs(data.orderInfo.discountTotal) } if (data.orderInfo.b2bDiscount < 0) { data.orderInfo.absB2bDiscount = Math.abs(data.orderInfo.b2bDiscount) } this.orderDetail.giftCards = giftCards this.orderDetail.products = data.lineItems this.orderDetail.orderInfo = data.orderInfo this.orderDetail.payments = data.paymentLine this.orderDetail.customer = data.shippingAddress this.getOrderLogist(this.orderId) }) .catch(error => { console.error(error) showToast(error, 'error') }) .finally(() => { }) } getOrderLogist(id) { fetch(customer.api.commonOrder + `/${id}/fulfillments`, fetchConfig('GET')) .then(response => response.json()) .then(res => { const data = customer.fetchError(res) if (!data) return if (data && data.fulfillments.length) { var newLists = [] var fillMents = data.fulfillments.map(list => { list.lineItems.find(item => { this.orderDetail.products.filter(line => { if (line.virtualInfo && line.id == item.id) { item.virtualInfo = line.virtualInfo } }) newLists.push(item) }) list.showShipping = !list.lineItems.every(v => v.requiresShipping == 0) return list }) this.orderDetail.orderShip = fillMents } else { this.orderDetail.orderShip = [] } this.orderDetailRender() }) .catch(error => { console.error(error) showToast(error, 'error') }) .finally(() => { if (document.getElementById('loadingCover')) { hideLoading() } }) } orderDetailRender() { var detailHtml = window.template('order__detail-art-tpl', this.orderDetail) document.querySelector('.order__detail-container').innerHTML = detailHtml this.eventButton() } eventButton() { this.querySelectorAll('a[href="javascript:;"]').forEach(button => button.addEventListener('click', event => { const data = event.target.closest('a').dataset; if (data.type === 'confirm') { this.handleShipment(data.id) } if (data.type === 'shipment') { this.renderShipment(data) } if (data.type === 'virtual') { this.renderVirtual(JSON.parse(data.product)) } }) ) } renderVirtual(product) { document.body.classList.add('overflow-hidden') const virtualDemo = document.querySelector('#shipmentVirtual') const virtualHtml = window.template('order-detail-virtual-tpl', { product: product, appLang: this.orderDetail.appLang, virtual: JSON.parse(product.virtualInfo) }) virtualDemo.innerHTML = virtualHtml virtualDemo.querySelectorAll('button[data-name="click"]').forEach(button => button.addEventListener('click', event => { const data = event.target.closest('button').dataset const type = data.action || 'close' if (type === 'close') { virtualDemo.innerHTML = '' document.body.classList.remove('overflow-hidden') } if (type === 'copy') { copyContent(data.content) } if (type === 'download') { downFile(data.src, data.file) } }) ) } handleShipment(id) { const result = window.confirm("Do you receive all the products you purchase") if (result) { showLoading() fetch(customer.api.commonOrder + `${this.orderId}/fulfillment/${id}/finish`, fetchConfig('PUT')) .then(response => response.json()) .then(res => { const data = customer.fetchError(res) if (data) { this.getOrderDetail() } }) .catch(error => { hideLoading() }) .finally(() => { }) } } renderShipment(data) { const { trackNumber, trackCode } = data document.body.classList.add('overflow-hidden') fetch(customer.api.orderTracking + `?number=${trackNumber}&company=${trackCode}`, fetchConfig('GET')) .then(response => response.json()) .then(res => { const data = res.data?.data || [] const renderLogist = document.querySelector('.order__shipment-modal') const shipmentModal = window.template('order-detail-logist-tpl', { shipments: data }) renderLogist.innerHTML = shipmentModal renderLogist.querySelectorAll('button').forEach(button => button.addEventListener('click', event => { const data = event.target.closest('button').dataset const type = data.type || 'cancel' if (type === 'cancel') { renderLogist.innerHTML = '' document.body.classList.remove('overflow-hidden') } }) ) }) .catch(error => { showToast(error, 'error') }) .finally(() => { }) } } customElements.define('customer-order-detail', CustomerOrderDetail) </script> <script> const cartType = 'notification' const cartLink = document.querySelector('#cart-icon-bubble') const cartRender = { api: { getCarts: '/api/mbr/shopping/cart', updataCart: '/api/mbr/shopping/cart/update', removeCart: '/api/mbr/shopping/cart/remove', checkoutCart: '/api/mbr/checkout/preOrder', recommendCart: '/api/mbr/goods/similar' }, cartItems: [], enableLoading: function (index) { const cartItemElements = document.querySelectorAll(`#CartItem-${index} .loading-overlay`) cartItemElements.forEach(overlay => overlay.classList.remove('hidden')) }, disableLoading: function (index) { const cartItemElements = document.querySelectorAll(`#CartItem-${index} .loading-overlay`) cartItemElements.forEach(overlay => overlay.classList.add('hidden')) }, cartActive: function () { if (location.pathname === '/cart') { window.CART_ACTIVES() } }, getCartList: function (type, init) { fetch(cartRender.api.getCarts + `?r=${Math.random().toString(36).slice(-4)}`, fetchConfig('GET')) .then(response => response.json()) .then(res => { const { code, data } = res if (code === 0) { const cartCount = Math.min(data?.itemCount || 0, 99) this.cartItems = data?.lineItems || [] const cartInfo = { count: cartCount, items: data?.lineItems || [], totalPrice: data?.totalPrice || 0, totalDiscount: data?.totalDiscount || 0 } if (type === 'cart' || type === 'cart-drawer') { const elementSelector = type === 'cart' ? '.cart-layout' : '.cart-drawer-layout' const templateName = type === 'cart' ? 'cart-art-tpl' : 'cart-drawer-art-tpl' const cartHtml = window.template(templateName, { cartInfo: cartInfo }) document.querySelector(elementSelector).innerHTML = cartHtml if (init && init === 'init') { document.querySelector('cart-drawer').initData() } } if (type === 'notice') { const noticeHtml = window.template('cart-notice-art-tpl', { cartItems: this.cartItems[0], cartCount: cartCount }) document.querySelector('.cart-notification-info').innerHTML = noticeHtml document.querySelector('cart-notification').initData() } if (!cartLink) return const cartCountBubble = document.querySelector('.cart-count-bubble') const cartCountElement = document.getElementById('cartCount') cartCount === 0 ? cartCountBubble.classList.add('cart-count-hidden') : ((cartCountElement.innerHTML = cartCount), cartCountBubble.classList.remove('cart-count-hidden')) } }) .catch(error => { console.error(error) showToast(error, 'error') }) .finally(() => { if (type && document.getElementById('loadingCover')) { hideLoading() } }) }, updateQuantity: function (index, quantity, name, type) { this.enableLoading(index) const items = this.cartItems const lines = items[parseInt(index) - 1] const body = JSON.stringify({ cartId: lines.id, variantId: lines.variantId, productId: lines.productId, selected: items.map(item => item.variantId), selectedCartId: items.map(item => item.id), quantity: Number(quantity) }) fetch(cartRender.api.updataCart, { ...fetchConfig('PUT'), ...{ body } }) .then(response => response.json()) .then(res => { if (res.code === 0) { this.cartActive() this.getCartList(type) } }) .catch(error => { console.error(error) showToast(error, 'error') }) .finally(() => { this.disableLoading(index) }) }, removeCartItem(items, data, index, type) { this.enableLoading(index) const body = JSON.stringify(data) fetch(cartRender.api.removeCart, { ...fetchConfig('POST'), ...{ body } }) .then(response => response.json()) .then(res => { if (res.code === 0) { this.cartActive() this.getCartList(type) const removeForm = { spuId: items.variantId, skuId: items.id, quantity: items.quantity, price: items.price, goodsTitle: items.productTitle, goodsHandle: items.productHandle } window.Shoptop.event.emit('dataTrack:removeFromCart', [removeForm]) } }) .catch(error => { console.error(error) showToast(error, 'error') }) .finally(() => { this.disableLoading(index) }) } } if (cartLink) { if (location.pathname != '/cart') { cartRender.getCartList() } cartLink.addEventListener('click', event => { if (cartType === 'drawer') { event.preventDefault() cartRender.getCartList('cart-drawer', 'init') } else { window.safeHref = '/cart' } }) } /* CART COUNT */ window.Shoptop.event.on('shoptop:cart:count', async function () { try { const response = await fetch(cartRender.api.getCarts + `?r=${Math.random().toString(36).slice(-4)}`, fetchConfig('GET')) if (!response.ok) { throw new Error('GET CART COUNT ERROR') } const count = await response.json() if (count.code === 1) return const cartCount = Math.min(count.data?.itemCount || 0, 99) const cartCountBubble = document.querySelector('.cart-count-bubble') const cartCountElement = document.getElementById('cartCount') cartCount === 0 ? cartCountBubble.classList.add('cart-count-hidden') : ((cartCountElement.innerHTML = cartCount), cartCountBubble.classList.remove('cart-count-hidden')) } catch (error) {} }) class CartRemoveButton extends HTMLElement { constructor() { super() this.addEventListener('click', event => { event.preventDefault() const target = event.target.closest('a') const index = target.getAttribute('data-key') const data = { removeCarts: [{ cartId: target.getAttribute('data-cartId'), variantId: target.getAttribute('data-variantId') }] } const items = cartRender.cartItems.filter(v => v.id === target.getAttribute('data-cartId'))[0] if (this.closest('cart-items')) { cartRender.removeCartItem(items, data, index, 'cart') } if (this.closest('cart-drawer')) { cartRender.removeCartItem(items, data, index, 'cart-drawer') } }) } } customElements.define('cart-remove-button', CartRemoveButton) class CartItems extends HTMLElement { constructor() { super() this.cartName = this.getAttribute('name') if (this.cartName === 'cart') { showLoading() } cartRender.getCartList('cart') const debouncedOnChange = debounce(event => { this.onChange(event) }, 300) this.addEventListener('change', debouncedOnChange.bind(this)) } onChange(event) { cartRender.updateQuantity(event.target.dataset.index, event.target.value, document.activeElement.getAttribute('name'), 'cart') } } customElements.define('cart-items', CartItems) class CartQuantityInput extends HTMLElement { constructor() { super() this.input = this.querySelector('input') this.changeEvent = new Event('change', { bubbles: true }) this.input.addEventListener('change', this.onInputChange.bind(this)) this.querySelectorAll('button').forEach(button => button.addEventListener('click', this.onButtonClick.bind(this))) } onInputChange(event) { this.validateQtyRules() } validateQtyRules() { const value = parseInt(this.input.value) if (this.input.min) { const min = parseInt(this.input.min) const buttonMinus = this.querySelector(".quantity__button[name='minus']") buttonMinus.classList.toggle('disabled', value <= min) } if (this.input.max) { const max = parseInt(this.input.max) const buttonPlus = this.querySelector(".quantity__button[name='plus']") buttonPlus.classList.toggle('disabled', value >= max) } } onButtonClick(event) { event.preventDefault() const previousValue = this.input.value event.target.name === 'plus' ? this.input.stepUp() : this.input.stepDown() if (previousValue !== this.input.value) this.input.dispatchEvent(this.changeEvent) } } customElements.define('cart-quantity-input', CartQuantityInput) class CartCheckout extends HTMLElement { constructor() { super() this.addEventListener('click', event => { event.preventDefault() const target = event.target if (target.classList.contains('loading')) return target.classList.add('loading') this.preOrder(target) }) } preOrder(event) { const CartItems = cartRender.cartItems const formData = new FormData() const distribution_id = getCookie('_distribution') || '' const activityIds = CartItems.map(i => i.activityId).filter(i => i) if (distribution_id) { formData.append('distributorId', distribution_id) } formData.append('referInfo.source', 'cart') formData.append('activityIds', activityIds) formData.append('referInfo.device', isMobile() ? 'mobile' : 'pc') formData.append('accountNo', '') CartItems.forEach((item, newIndex) => { const attachments = item.attachments ? item.attachments : [] if (item.moreOptions) { formData.append(`lineItems[${newIndex}].moreOptions`, item.moreOptions) } if (attachments && attachments.length) { formData.append(`lineItems[${newIndex}].attachments`, attachments) } formData.append(`lineItems[${newIndex}].cartId`, item.id) formData.append(`lineItems[${newIndex}].goodsNum`, item.quantity) formData.append(`lineItems[${newIndex}].goodsId`, item.variantId) formData.append(`lineItems[${newIndex}].productId`, item.productId) }) fetch(cartRender.api.checkoutCart, { ...fetchConfig('POST', 'form'), ...{ body: formData } }) .then(response => response.json()) .then(res => { if (res.code === 0) { window.location.href = `/checkout/${res.data.orderToken}` } }) .catch(error => { console.error(error) event.classList.remove('loading') showToast(error, 'error') }) .finally(() => { event.classList.remove('loading') }) } getCartItems() { return cartRender.cartItems } } customElements.define('cart-checkout', CartCheckout) class CartDrawer extends HTMLElement { constructor() { super() this.addEventListener('keyup', evt => evt.code === 'Escape' && this.close()) } initData() { this.openDrawer() if (!this.eventListenersBound) { const debouncedOnChange = debounce(event => { this.onChange(event) }, 300) this.eventListenersBound = true this.addEventListener('change', debouncedOnChange.bind(this)) this.querySelector('#CartDrawer-Overlay').addEventListener('click', this.close.bind(this)) } } onChange(event) { cartRender.updateQuantity(event.target.dataset.index, event.target.value, document.activeElement.getAttribute('name'), 'cart-drawer') } openDrawer() { const itemDrawer = document.querySelector('.cart-drawer-layout') document.body.classList.add('overflow-hidden') setTimeout(() => { itemDrawer.classList.add('cart-drawer-show') }, 200) } close() { removeTrapFocus(this.activeElement) const cartDrawerLayout = document.querySelector('.cart-drawer-layout') cartDrawerLayout.classList.remove('cart-drawer-show') document.body.classList.remove('overflow-hidden') } setActiveElement(element) { if (!cartLink) return this.activeElement = element cartRender.getCartList('cart-drawer', 'init') } } customElements.define('cart-drawer', CartDrawer) class CartNotification extends HTMLElement { constructor() { super() } close() { this.notification.classList.remove('active') document.body.removeEventListener('click', this.onBodyClick) removeTrapFocus(this.activeElement) } initData() { this.notification = document.getElementById('cart-notification') this.onBodyClick = this.handleBodyClick.bind(this) this.notification.addEventListener('keyup', evt => evt.code === 'Escape' && this.close()) this.querySelectorAll('button[type="button"]').forEach(closeButton => closeButton.addEventListener('click', this.close.bind(this))) setTimeout(() => { this.notification.classList.add('animate', 'active') }, 100) this.notification.addEventListener( 'transitionend', () => { this.notification.focus() trapFocus(this.notification) }, { once: true } ) document.body.addEventListener('click', this.onBodyClick) } handleBodyClick(evt) { const target = evt.target if (target !== this.notification && !target.closest('cart-notification')) { const disclosure = target.closest('details-disclosure, header-menu') this.activeElement = disclosure ? disclosure.querySelector('summary') : null this.close() } } setActiveElement(element) { if (!cartLink) return this.activeElement = element cartRender.getCartList('notice') } } customElements.define('cart-notification', CartNotification) /* 抽屉猜你喜欢 */ class CartRecommend extends HTMLElement { constructor() { super() this.getRecommend() } async getRecommend() { const response = await fetch(cartRender.api.recommendCart + `?type=2&size=5&r=${Math.random().toString(36).slice(-4)}`, fetchConfig('GET')) if (!response.ok) { throw new Error('GET CART COUNT ERROR') } const res = await response.json() if (res.code === 1 || !res.data.length) return let heading = "You May Also Like" let defaultImage = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAABlBMVEXx8fH///8wmV1OAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAACklEQVQImWNgAAAAAgAB9HFkpgAAAABJRU5ErkJggg==' let dynamicStyle = `<div class="drawer__recommend"> <h3> ${heading} </h3> <div class="drawer-items">` res.data.forEach(item => { dynamicStyle += `<div class="drawer-item"> <a class="drawer-link" href="/products/${item.handle}"> <img class="lazyload" data-sizes="auto" src="${defaultImage}" data-src="${window.template.defaults.imports.formatImageSrc( item.goodsImage )}" /> </a><div> <a href="/products/${item.handle}" class="drawer-title"> ${item.goodsTitle} </a> <div> <span class="product-price money">${window.template.defaults.imports.moneyWithSymbol(item.price)}</span> </div> </div> </div>` }) dynamicStyle += `</div></div>` document.querySelector('#cartRecommend').innerHTML = dynamicStyle } } customElements.define('cart-recommend', CartRecommend) </script> <template id="he-zoom-image-template"> <style> .he-zoom-image-wrap { position: fixed; left: 0; right: 0; top: 0; bottom: 0; z-index: 999; User-select: none; } .he-zoom-image-bg { background-color: rgba(0, 0, 0, 0.7); position: absolute; left: 0; right: 0; top: 0; bottom: 0; } .he-zoom-image-swiper { width: 100%; height: 100%; } .swiper-zoom-container { position: relative; width: 100%; height: 100%; } .swiper-zoom-bg { position: absolute; left: 0; right: 0; top: 0; bottom: 0; } .zoom-slide-img { display: block; position: absolute; left: 0; right: 0; top: 0; bottom: 0; margin: auto; max-height: 100%; } .he-zoom-image-controller { display: flex; justify-content: flex-end; height: 60px; position: absolute; width: 100%; top: 0; z-index: 1; } .he-zoom__btn, .he-zoom__btn-close { display: flex; justify-content: center; align-items: center; background-color: rgba(0, 0, 0, 0.5); color: #fff; cursor: pointer; width: 50px; height: 60px; } .he-zoom__btn-in { width: 24px; height: 24px; pointer-events: none; } .he-zoom__btn-out { width: 24px; height: 24px; pointer-events: none; } .he-zoom__btn-close span {} </style> <div class="he-zoom-image-wrap"> <div class="he-zoom-image-bg"></div> <div class="he-zoom-image-swiper"> <div class="swiper-wrapper"> <div class="swiper-slide"> <div class="swiper-zoom-container"> <div class="swiper-zoom-bg"></div> <img src="" class="zoom-slide-img"> </div> </div> </div> </div> <div class="he-zoom-image-controller"> <div style="display:flex;"> <div class="he-zoom__btn" data-zoom='in'> <span class="he-zoom__btn-in"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607zM10.5 7.5v6m3-3h-6" /> </svg> </span> <span class="he-zoom__btn-out hidden"> <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor"> <path stroke-linecap="round" stroke-linejoin="round" d="M21 21l-5.197-5.197m0 0A7.5 7.5 0 105.196 5.196a7.5 7.5 0 0010.607 10.607zM13.5 10.5h-6" /> </svg> </span> </div> <div class="he-zoom__btn-close" style="color: #fff;"> <span style="display:inline-block;width: 24px;height: 24px;"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"> <path fill-rule="evenodd" d="M5.47 5.47a.75.75 0 011.06 0L12 10.94l5.47-5.47a.75.75 0 111.06 1.06L13.06 12l5.47 5.47a.75.75 0 11-1.06 1.06L12 13.06l-5.47 5.47a.75.75 0 01-1.06-1.06L10.94 12 5.47 6.53a.75.75 0 010-1.06z" clip-rule="evenodd" /> </svg> </span> </div> </div> </div> </div> </template> </html>

Pages: 1 2 3 4 5 6 7 8 9 10