1<!doctype html> 2<html class="no-js" lang="en"> 3 <head> 4 5 6
6<script type='text/javascript'>var easylockdownLocationDisabled = true;</script>
6
6<script type='text/javascript'> window.easyLockdownLoginMode = 'classic'; var isShopifyPreviewHost = window.location.hostname.indexOf('shopifypreview.com') !== -1; if( isShopifyPreviewHost ) { window.easyLockdownLoginMode = 'classic'; } </script>
6
6<script type='text/javascript' src='//revitin.com/apps/easylockdown/easylockdown-1.0.8.min.js?v=202609170844' data-no-instant></script>
6
6<script type='text/javascript'>document.addEventListener('easylockdown_loaded', function() { if(typeof InstantClick == 'object') easylockdown.clearData(); }, {once: true});</script>
6
6<script type='text/javascript'>(function() { function tryFallback() { if(typeof easylockdown == 'object' && typeof easylockdown.onLoaded != 'function') { var event = document.createEvent('Event'); event.initEvent('easylockdown_loaded', true, true); document.dispatchEvent(event); return true; } return typeof easylockdown == 'object'; } function onReady() { if(!tryFallback()) { var attempts = 0; var interval = setInterval(function() { if(tryFallback() || ++attempts >= 10) clearInterval(interval); }, 100); } } if(document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', onReady, {once: true}); } else { onReady(); } })();</script>
6 <style type="text/css" id="easylockdown-plugin-style">#easylockdown-password-form{padding:30px 0;text-align:center}#easylockdown-wrapper,.easylockdown-form-holder{display:inline-block}#easylockdown-password{vertical-align:top;margin-bottom:16px;padding:8px 15px;line-height:1.2em;outline:0;box-shadow:none}#easylockdown-password-error{display:none;color:#fb8077;text-align:left}#easylockdown-password-error.easylockdown-error{border:1px solid #fb8077}#easylockdown-password-form-button:not(.easylockdown-native-styles){vertical-align:top;display:inline-block!important;height:auto!important;padding:8px 15px;background:#777;border-radius:3px;color:#fff!important;line-height:1.2em;text-decoration:none!important}.easylockdown-instantclick-fix,.easylockdown-item-selector{position:absolute;z-index:-999;display:none;height:0;width:0;font-size:0;line-height:0}.easylockdown-collection-item[data-eld-loc-can],.easylockdown-item-selector+*,.easylockdown-item[data-eld-loc-can]{display:none}.easylockdown404-content-container{padding:50px;text-align:center}.easylockdown404-title-holder .easylockdown-title-404{display:block;margin:0 0 1rem;font-size:2rem;line-height:2.5rem}</style> 7 8 9 10 11 12 13
14<script type='text/javascript'> if(typeof easylockdown == 'object') { easylockdown.hideLinks.push('*[href$="/products/"],*[href*="/products//"],*[href*="/products/?"],*[href*="/products/#"],*[data-eld-product-handle=""]');}</script>
14 15 16 17 18 19
20<script type='text/javascript'> if(typeof easylockdown == 'object') { easylockdown.hideLinks.push('*[href$="/collections/professionals"],*[data-eld-collection-handle="professionals"]');}</script>
20 21 22 23 24 25
26<script type='text/javascript'> 27 document.addEventListener('easylockdown_loaded', function() { 28 easylockdown.localeRootUrl = ''; 29 easylockdown.routerByLocation(); 30 31 easylockdown.onReady(function(e){ 32 setTimeout(function() { 33 easylockdown.hideAllLinks(); 34 }, 0); 35 }); 36 }, {once: true}); 37</script>
37 38 39<!-- Start of Shoplift scripts --> 40 <!-- 2026-09-10T11:45:02.6702537Z --> 41<style>.shoplift-hide { opacity: 0 !important; }</style> 42<style id="sl-preview-bar-hide">#preview-bar-iframe, #PBarNextFrameWrapper { display: none !important; }</style>
43<script type="text/javascript">(function(rootPath, template, themeRole, themeId, isThemePreview){ /* Generated on 2026-09-30T13:45:02.8931035Z */(function(){"use strict";var te=document.createElement("style");te.textContent=`#shoplift-preview-control{position:fixed;max-width:332px;height:56px;background-color:#141414;z-index:9999;bottom:20px;display:flex;border-radius:8px;box-shadow:13px 22px 7px #0000,9px 14px 7px #00000003,5px 8px 6px #0000000d,2px 4px 4px #00000017,1px 1px 2px #0000001a,0 0 #0000001a;align-items:center;margin:0 auto;left:16px;right:16px;opacity:0;transform:translateY(20px);visibility:hidden;transition:opacity .4s ease-in-out,transform .4s ease-in-out,visibility 0s .4s}#shoplift-preview-control.visible{opacity:1;transform:translateY(0);visibility:visible;transition:opacity .4s ease-in-out,transform .4s ease-in-out,visibility 0s 0s}#shoplift-preview-control *{font-family:Inter,sans-serif;color:#fff;box-sizing:border-box;font-size:16px}#shoplift-preview-variant-title{font-weight:400;line-height:140%;font-size:16px;text-align:start;letter-spacing:-.16px;flex-grow:1;text-wrap:nowrap;overflow:hidden;text-overflow:ellipsis}#shoplift-preview-variant-selector{position:relative;display:block;padding:6px 0;height:100%;min-width:0;flex:1 1 auto}#shoplift-preview-variant-menu-trigger{border:none;cursor:pointer;width:100%;background-color:transparent;padding:0 16px;border-left:1px solid #333;border-right:1px solid #333;height:100%;display:flex;align-items:center;justify-content:start;gap:8px}#shoplift-preview-variant-selector .menu-variant-label{width:24px;height:24px;border-radius:50%;padding:6px;display:flex;justify-content:center;align-items:center;font-size:12px;font-style:normal;font-weight:600;line-height:100%;letter-spacing:-.12px;flex-shrink:0}#shoplift-preview-variant-selector .preview-variant-menu{position:absolute;bottom:110%;transform:translate3d(0,20px,0);visibility:hidden;pointer-events:none;opacity:0;cursor:pointer;background-color:#141414;border:1px solid #141414;border-radius:6px;width:100%;max-height:156px;overflow-y:auto;box-shadow:0 8px 16px #0003;z-index:1;transition:opacity .3s ease-in-out,transform .3s ease-in-out,visibility 0s .3s}#shoplift-preview-variant-selector .preview-variant-menu.preview-variant-menu__visible{visibility:visible;pointer-events:auto;opacity:100;transform:translateZ(0);transition:opacity .3s ease-in-out,transform .3s ease-in-out,visibility 0s 0s}@media screen and (max-width:400px){#shoplift-preview-variant-selector .preview-variant-menu{position:fixed;left:0;right:0;width:auto;bottom:110%}}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item{padding:12px 16px;display:flex;overflow:hidden}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item .menu-variant-label{margin-right:6px}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item span{overflow:hidden;text-overflow:ellipsis;text-wrap:nowrap;white-space:nowrap;color:#f6f6f6;font-size:14px;font-style:normal;font-weight:500}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item:hover{background-color:#545454}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item:last-of-type{border-bottom-left-radius:6px;border-bottom-right-radius:6px}#shoplift-preview-variant-selector .preview-variant-menu .preview-variant-menu--item:first-of-type{border-top-left-radius:6px;border-top-right-radius:6px}#shoplift-preview-control div:has(#shoplift-exit-preview-button){padding:0 16px}#shoplift-exit-preview-button{padding:6px 8px;font-weight:500;line-height:75%;border-radius:4px;background-color:transparent;border:none;text-decoration:none}#shoplift-exit-preview-button:hover{cursor:pointer;background-color:#333}#shoplift-preview-subscription-warning{position:relative;display:flex;align-items:center;gap:6px;padding:6px 10px;margin:0 4px;border-left:1px solid #333;cursor:help;outline:none}#shoplift-preview-subscription-warning__icon{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:50%;background-color:#f59e0b;color:#141414!important;font-weight:700;font-size:12px!important;line-height:1;flex-shrink:0}#shoplift-preview-subscription-warning__label{font-size:13px!important;font-weight:500;color:#fbbf24!important;text-wrap:nowrap;white-space:nowrap}#shoplift-preview-subscription-warning__tooltip{position:absolute;bottom:calc(100% + 8px);right:0;max-width:320px;width:max-content;padding:10px 12px;border-radius:6px;background-color:#1f1f1f;color:#fff!important;font-size:12px!important;line-height:1.4!important;box-shadow:0 8px 16px #0000004d;z-index:10000;opacity:0;visibility:hidden;transform:translateY(4px);transition:opacity .2s ease-in-out,transform .2s ease-in-out,visibility 0s .2s;pointer-events:none}#shoplift-preview-subscription-warning__tooltip.shoplift-preview-subscription-warning__tooltip--visible{opacity:1;visibility:visible;transform:translateY(0);transition:opacity .2s ease-in-out,transform .2s ease-in-out,visibility 0s 0s}#shoplift-preview-subscription-warning:focus-visible{box-shadow:inset 0 0 0 2px #f59e0b;border-radius:4px}#shoplift-preview-control:has(#shoplift-preview-subscription-warning){max-width:480px}/*$vite$:1*/`,document.head.appendChild(te);var fe=" daum[ /]| deusu/|(?:^|[^g])news(?!sapphire)|(?<! channel/|google/)google(?!(?:wv|app|/google| pixel))|(?<! cu)bots?(?:\\b|_)|(?<!cam)scan|(?<!lib)http|24x
437|;\\s\\w+;$|@[a-z][\\w-]+\\.|\\(\\)|\\.com\\b|\\b\\w+/1\\.0;|\\bbw/|\\bdlc\\b|\\bort/|\\bperl\\b|\\btime/|\\||^[<\\(;]|^[\\w \\.\\-\\(?:\\):%]+(?:/v?\\d+(?:\\.\\d+)?(?:\\.\\d{1,10})*?)?(?:,|$)|^[\\w\\-]+/[\\w]+$|^[^ ]{50,}$|^\\d+\\b|^\\w*search\\b|^\\w+/[\\w\\(\\)]*$|^\\w+/\\d\\.\\d\\s\\([\\w@]+\\)$|^active|^ad muncher|^amaya|^apache/|^avsdevicesdk/|^azure|^biglotron|^blackbox exporter|^bot|^clamav[ /]|^claude-code/|^client/|^cobweb/|^custom|^ddg[_-]android|^discourse|^dispatch/\\d|^downcast/|^duckduckgo|^email|^exodusmovement|^facebook|^getright/|^gozilla/|^hobbit|^hotzonu|^hwcdn/|^igetter/|^jeode/|^jetty/|^jigsaw|^microsoft bits|^movabletype|^mozilla/\\d\\.\\d\\s[\\w\\.-]+$|^mozilla/\\d\\.\\d\\s\\((?:compatible;)?(?:\\s?[\\w\\d-.]+\\/\\d+\\.\\d+)?\\)$|^navermailapp|^netsurf|^offline|^openai/|^owler|^php|^postman|^ps_daily/|^python|^rank|^read|^reed|^remove\\.bg/|^rest|^rss|^snapchat|^sora |^space bison|^stape/|^svn|^swcd |^taringa|^thumbor/|^track|^w3c|^webbandit/|^webcopier|^wget|^whatsapp|^wordpress|^xenu link sleuth|^yahoo|^yandex|^zdm/\\d|^zoom marketplace/|abuse|advisor|agent\\b|analyzer|archive|ask jeeves/teoma|attracta|audit|bluecoat drtr|browsex|burpcollaborator|capture|catch|check\\b|checker|chrome-lighthouse|chromeframe|classifier|cloudflare|collapsify\\b|convertify|cookiehubverify/|crawl|cursor/|cypress/|dareboost|datanyze|dejaclick|detect|discovery|dmbrowser|download|exaleadcloudview|feed|firephp|foregenix|functionize|grab|hardenize\\b|headless|hotjar|httrack|hubspot marketing grader|ibisbrowser|infrawatch|insight|inspect|iplabel|java(?!;)|library|linkcheck|linktiger|mail\\.ru/|manager|manus-user/|marketgoo/|measure|monitor\\b|neustar wpm|node\\b|nutch|offbyone|openvas|optimize|pageburst|pagespeed|parser|phantomjs|pingdom|playwright|powermarks|preview|productfinder|prospectingstudio|proxy|ptst[ /]\\d|radar|readable/|retriever|rexx;|rigor|rss\\b|scrape|securityheaders|selenium|server|silktide|sindup/|sogou|sparkler/|speedcurve|spider|splash|statuscake|supercleaner|synapse|synthetic|testlocally|tools|torrent|transcoder|url|validator|virtuoso|wappalyzer|watchtowr|webglance|webkit2png|whatcms/|xtate/",ge=/bot|crawl|http|lighthouse|scan|search|spider/i,z;function me(){if(z instanceof RegExp)return z;try{z=new RegExp(fe,"i")}catch{z=ge}return z}var ye=a=>typeof a=="string"&&a!=="";function ve(a){return ye(a)&&me().test(a)}var we=ve;class X{timestamp;constructor(){this.timestamp=new Date}}class be extends X{type;testId;hypothesisId;constructor(e,t,i){super(),this.type=3,this.testId=e,this.hypothesisId=t,this.timestamp=i}}class Se extends X{type;path;constructor(e){super(),this.type=4,this.path=e}}class Ce extends X{type;cart;constructor(e){super(),this.type=5,this.cart=e}}class ie extends Error{isBot;constructor(){super(),this.isBot=!0}}function Te(a,e,t){for(const i of e.selectors){const s=a.querySelectorAll(i.cssSelector);for(let r=0;r<s.length;r++)t(e.testId,e.hypothesisId)}re(a,e,(i,s,r,o,n)=>n(s,r),t)}function U(a,e,t){for(const i of e.selectors)ne(a,e.testId,e.hypothesisId,i,t??(()=>{}));re(a,e,ne,t??(()=>{}))}function se(a){return a.urlPatterns.reduce((e,t)=>{switch(t.operator){case"contains":return e+`.*${t}.*`;case"endsWith":return e+`.*${t}`;case"startsWith":return e+`${t}.*`}},"")}function re(a,e,t,i){new MutationObserver(()=>{for(const r of e.selectors)t(a,e.testId,e.hypothesisId,r,i)}).observe(a.documentElement,{childList:!0,subtree:!0})}function ne(a,e,t,i,s){const r=a.querySelectorAll(i.cssSelector);for(let o=0;o<r.length;o++){let n=r.item(o);if(n instanceof HTMLElement&&n.dataset.shoplift!==""){n.dataset.shoplift="";for(const l of i.actions.sort(Re))n=Ie(a,i.cssSelector,n,l)}}return r.length>0&&s?(s(e,t),!0):!1}function Ie(a,e,t,i){switch(i.type){case"innerHtml":t.innerHTML=i.value;break;case"attribute":Pe(t,i.scope,i.value);break;case"css":Ae(a,e,i.value);break;case"js":ke(a,t,i);break;case"copy":return Ee(t);case"remove":xe(t);break;case"move":_e(t,parseInt(i.value));break}return t}function Pe(a,e,t){a.setAttribute(e,t)}function Ae(a,e,t){const i=a.createElement("style");i.innerHTML=`${e} { ${t} }`,a.getElementsByTagName("head")[0]?.appendChild(i)}function ke(a,e,t){Function("document","element",`"use strict"; ${t.value}`)(a,e)}function Ee(a){const e=a.cloneNode(!0);if(!a.parentNode)throw"Can't copy node outside of DOM";return a.parentNode.insertBefore(e,a.nextSibling),e}function xe(a){a.remove()}function _e(a,e){if(e===0)return;const t=Array.prototype.slice.call(a.parentElement.children).indexOf(a),i=Math.min(Math.max(t+e,0),a.parentElement.children.length-1);a.parentElement.children.item(i).insertAdjacentElement(e>0?"afterend":"beforebegin",a)}function Re(a,e){return oe(a)-oe(e)}function oe(a){return a.type==="copy"||a.type==="remove"?0:1}
43const M={Template:0,UrlRedirect:2,Script:3,Price:5},De="data:image/svg+xml,%3csvg%20width='12'%20height='12'%20viewBox='0%200%2012%2012'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M9.96001%207.90004C9.86501%207.90004%209.77001%207.86504%209.69501%207.79004L6.43501%204.53004C6.19501%204.29004%205.80501%204.29004%205.56501%204.53004L2.30501%207.79004C2.16001%207.93504%201.92001%207.93504%201.77501%207.79004C1.63001%207.64504%201.63001%207.40504%201.77501%207.26004L5.03501%204.00004C5.56501%203.47004%206.43001%203.47004%206.96501%204.00004L10.225%207.26004C10.37%207.40504%2010.37%207.64504%2010.225%207.79004C10.15%207.86004%2010.055%207.90004%209.96001%207.90004Z'%20fill='white'/%3e%3c/svg%3e",Ve="data:image/svg+xml,%3csvg%20width='14'%20height='24'%20viewBox='0%200%2014%2024'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M12.3976%2014.5255C12.2833%2013.8788%2012.0498%2013.3024%2011.6952%2012.7961C11.3416%2012.2898%2010.9209%2011.8353%2010.4353%2011.4317C9.94868%2011.0291%209.43546%2010.6488%208.89565%2010.292C8.48487%2010.049%208.09577%209.78565%207.72637%209.50402C7.35697%209.2224%207.08016%208.89503%206.89694%208.51987C6.71273%208.14471%206.67826%207.69533%206.79055%207.1697C6.86345%206.83216%206.97476%206.54647%207.12351%206.31162C7.27324%206.07778%207.47124%205.89986%207.7175%205.77684C7.96377%205.65483%208.21989%205.59383%208.48389%205.59383C8.88087%205.59383%209.17639%205.7016%209.3734%205.91714C9.56943%206.13268%209.68271%206.42345%209.71424%206.78946C9.74576%207.15547%209.72015%207.55401%209.63839%207.98509C9.55663%208.41617%209.43645%208.84724%209.27687%209.27934L13.5127%208.80149C13.9638%207.52656%2014.1017%206.42447%2013.9264%205.49725C13.751%204.56901%2013.2664%203.85122%2012.4724%203.34491C12.239%203.19648%2011.9779%203.07041%2011.6893%202.96569L12.0026%201.50979L9.86397%200L7.3875%201.50979L7.11169%202.78878C6.65166%202.8874%206.21724%203.01957%205.8114%203.19038C4.85292%203.594%204.06684%204.15115%203.45117%204.86385C2.83452%205.57655%202.42571%206.40108%202.22378%207.33847C2.06616%208.06947%202.04942%208.70796%202.17551%209.25087C2.30061%209.7948%202.52028%2010.2828%202.8355%2010.7139C3.14974%2011.145%203.51816%2011.5344%203.93977%2011.881C4.36039%2012.2288%204.782%2012.5521%205.20164%2012.851C5.68334%2013.1702%206.13844%2013.5169%206.56497%2013.8921C6.99052%2014.2672%207.31954%2014.7125%207.55004%2015.228C7.78055%2015.7445%207.81502%2016.3769%207.65347%2017.1262C7.56482%2017.5389%207.43676%2017.8765%207.27028%2018.1388C7.10381%2018.4011%206.89596%2018.5983%206.64772%2018.7295C6.3985%2018.8606%206.12071%2018.9267%205.8114%2018.9267C5.21641%2018.9267%204.79776%2018.6034%204.62833%2018.1632C4.4589%2017.7229%204.47367%2017.2583%204.60075%2016.5639C4.72782%2015.8705%205.05092%2015.1395%205.37107%2014.3699H1.17665C1.17665%2014.3699%200.207341%2016.1115%200.0310135%2017.6762C-0.0655232%2018.5302%200.0635208%2019.2653%200.41519%2019.8844C0.76686%2020.5036%201.33032%2020.9814%202.10655%2021.319C2.39222%2021.443%202.7104%2021.5447%203.05813%2021.623L2.54589%2024H7.17473L7.7047%2021.5386C8.08493%2021.442%208.43857%2021.3231%208.76562%2021.1787C9.73985%2020.7476%2010.52%2020.1427%2011.1071%2019.3649C11.6932%2018.5871%2012.0873%2017.7291%2012.2892%2016.7917C12.4744%2015.9295%2012.5099%2015.1741%2012.3966%2014.5275L12.3976%2014.5255Z'%20fill='white'/%3e%3c/svg%3e";async function Oe(a){let e=a.replace(/-/g,"+").replace(/_/g,"/");for(;e.length%4;)e+="=";const t=atob(e),i=Uint8Array.from(t,o=>
43o.charCodeAt(0)),s=new Blob([i]).stream().pipeThrough(new DecompressionStream("gzip")),r=await new Response(s).text();return JSON.parse(r)}function F(a,e){return typeof e=="string"&&/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d+(?:Z|[+-]\d+)/.test(e)?new Date(e):e}function ee(a,e){return e}function q(a,e=!1,t=!1,i=","){const s=a/100;if(t){const o=Math.round(s).toLocaleString("en-US");return i!==","?o.replace(/,/g,i):o}else{const r=e?",":".",o=s.toFixed(2).split("."),n=parseInt(o[0],10),l=o[1]??"00",c=n.toLocaleString("en-US");return i!==","?`${c.replace(/,/g,i)}${r}${l}`:e?`${c.replace(/,/g,".")}${r}${l}`:`${c}${r}${l}`}}function H(a,e,t,i){const s=e.replace("{{amount}}",q(a,!1,!1)).replace("{{amount_no_decimals}}",q(a,!1,!0)).replace("{{amount_with_comma_separator}}",q(a,!0,!1)).replace("{{amount_no_decimals_with_comma_separator}}",q(a,!0,!0)).replace("{{amount_with_space_separator}}",q(a,!1,!1," ")).replace("{{amount_no_decimals_with_space_separator}}",q(a,!1,!0," ")).replace("{{amount_with_apostrophe_separator}}",q(a,!1,!1,"'")).replace("{{amount_no_decimals_with_apostrophe_separator}}",q(a,!1,!0,"'")).replace("{{amount_with_period_and_space_separator}}",q(a,!1,!1,". ")).replace("{{amount_no_decimals_with_period_and_space_separator}}",q(a,!1,!0,". "));return i?`${s} ${t}`:s}function ae(a){return a.replace(/[^\d.,\s-]/g,"").trim()}function j(a){const e=new Map;for(const[t,i,s]of a.variants)e.set(t,{priceInCents:i,compareAtPriceInCents:s});return e}function Le(a,e,t,i){const{priceInCents:s,compareAtPriceInCents:r}=t,{moneyFormat:o,currency:n,currencyCodeEnabled:l}=i;if(a.getAttribute("data-sl-attribute-p")===e)a.innerHTML=H(s,o,n,l);else if(a.getAttribute("data-sl-attribute-cap")===e)r<=0||r<=s?a.remove():a.innerHTML=H(r,o,n,l);else if(a.getAttribute("data-sl-attribute-discount")===e&&!(r<=0||r<=s)){const d=Math.round((r-s)/r*100),u=ae(H(r-s,o,n,!1)),h=a.getAttribute("data-sl-format")||"percent";h==="percent"?a.textContent=`-${d}%`:h==="amount"?a.textContent=`-${u}`:h==="both"&&(a.textContent=`-${d}% (-${u})`)}}function $e(a){const e=[],t={id:"url-pattern",operator:"contains",value:"/"};for(const[i,s,r]of a.variants){e.push({id:`p-${i}`,cssSelector:`[data-sl-attribute-p="${i}"]`,urlPatterns:[t],actions:[{id:`p-action-${i}`,type:"innerHtml",scope:"price",value:H(s,a.moneyFormat,a.currency,a.currencyCodeEnabled)}]});const o=r<=0||r<=s;if(e.push({id:`cap-${i}`,cssSelector:`[data-sl-attribute-cap="${i}"]`,urlPatterns:[t],actions:[{id:`cap-action-${i}`,type:o?"remove":"innerHtml",scope:"compare-at-price",value:o?"":H(r,a.moneyFormat,a.currency,a.currencyCodeEnabled)}]}),!o&&r>s){const n=Math.round((r-s)/r*100),l=ae(H(r-s,a.moneyFormat,a.currency,!1));e.push({id:`d-${i}`,cssSelector:`[data-sl-attribute-discount="${i}"]`,urlPatterns:[t],actions:[{id:`d-action-${i}`,type:"js",scope:null,value:`var format = element.getAttribute('data-sl-format') || 'percent'; if (format === 'percent') { element.textContent = '-${n}%'; } else if (format === 'amount') { element.textContent = '-${l}'; } else if (format === 'both') { element.textContent = '-${n}% (-${l})'; }`}]})}}return e}const Me=a=>{let e=5381;for(let t=0;t<a.length;t++)e=(e*33^a.charCodeAt(t))>>>0;return e.toString(36)},qe=()=>Math.random().toString(36).slice(2,10)+Date.now().toString(36).slice(-4),He=a=>btoa(JSON.stringify(a)).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,""),K=a=>a.replace(/#slr-[a-z0-9]+$/,""),tt="modulepreload",it=function(a){return"/"+a},st={},Ne=function(e,t,i){let s=Promise.resolve();function r(o){const n=new Event("vite:preloadError",{cancelable:!0});if(n.payload=o,window.dispatchEvent(n),!n.defaultPrevented)throw o}return s.then(o=>{for(const n of o||[])n.status==="rejected"&&r(n.reason);return e().catch(r)})};function le(a,e,t){const i=t?a.plans.filter(c=>!c.variantId||c.variantId===t):a.plans,s=[],r=[];for(const c of i)c.direction==="decrease"?(s.push(c.existingShopifyPlanId),r.push(c.createdShopifyPlanId)):(s.push(c.createdShopifyPlanId),r.push(c.existingShopifyPlanId));const o=e?s:r,n=e?r:s;if(t)for(const c of a.plans)for(const d of[c.existingShopifyPlanId,c.createdShopifyPlanId])d&&!o.includes(d)&&!n.includes(d)&&n.push(d);const l={};for(let c=0;c<n.length;c++){const d=n[c],u=o[c];d&&u&&(l[d]=u)}return{showPlanIds:o,hidePlanIds:n,swapMap:l}}function ce(a,e,t){const i=e?a.plans.find(r=>r.variantId===e):void 0;if(i)return i.direction;if(t){const r=a.plans.find(o=>o.productId===t);if(r)return r.direction}return a.plans.find(r=>!r.variantId)?.direction??null}function J(a,e){const t=e?a.plans.filter(r=>!r.productId||r.productId===e):a.plans,i={};for(const r of t)i[r.existingShopifyPlanId]=r.existingDiscountAmount,i[r.createdShopifyPlanId]=r.existingDiscountAmount;
43const s=Math.max(...Object.values(i),0);return{discountMap:i,maxDiscount:s}}function W(a){const e=document.querySelector('form[action*="/cart/add"] input[name="product-id"]')?.value;if(e)return e;if(a){for(const r of Array.from(document.querySelectorAll("[data-sl-attribute-p]"))){const o=r.getAttribute("data-sl-attribute-p");if(!o)continue;const n=a.variants.find(l=>l[0]===o);if(n?.[3])return n[3]}const s=document.querySelector('form[action*="/cart/add"] input[name="id"]')?.value;if(s){const r=a.variants.find(o=>o[0]===s);if(r?.[3])return r[3]}}const t=window,i=t.ShopifyAnalytics?.meta?.product?.id??t.meta?.product?.id;return i!=null?String(i):null}function D(a,e){return a.widget.selectors[e]??[]}function N(a,e){return a.replace(/[\d.]+%/,`${e}%`)}function $(a,e){const t=document.createTreeWalker(a,NodeFilter.SHOW_TEXT);let i=t.nextNode();for(;i;){if(i.nodeValue!==null){const s=e(i.nodeValue);if(s!==i.nodeValue){i.nodeValue=s;return}}i=t.nextNode()}}function de(a,e){return a===null?!1:a==="decrease"?!e:e}async function Ue(a){if(a.subscriptionSwapDone)return;const e=a.getActiveAssignment();if(!e)return;const t=a.getHypothesis(e.hypothesisId);if(!t?.subscriptionData)return;a.subscriptionSwapDone=!0;const i=t.subscriptionData,s=t.isControl,r=[...new Set(i.plans.map(d=>d.direction))].join(",");a.log(`[SUB-SWAP] ${s?"A":"B"} side, directions=${r}`);const o=i.plans.some(d=>d.variantId);let n=!1,l=!1;function c(){if(!l){l=!0;try{const d=o?document.querySelector("select[name='id'], input[name='id']")?.value:void 0,{showPlanIds:u,hidePlanIds:h,swapMap:p}=le(i,s,d);a.swapMap=p;const b=D(i,"widgetParent"),E=D(i,"subscriptionPlans"),S=D(i,"subscriptionInput");if(!b.length||!E.length||!S.length)return;const C=document.querySelector(b[0].selector);if(!C?.shadowRoot)return;const _=C.shadowRoot.querySelector(E[0].selector);if(!_?.shadowRoot)return;const T=S[0].selector;let m=null;if(i.widget.widgetType==="buttons"||i.widget.widgetType==="radio"){const y=Array.from(_.shadowRoot.querySelectorAll(T));if(!y.length)return;for(const v of y){const g=v.closest("label");g&&(u.includes(v.value)?g.style.display="":h.includes(v.value)&&(g.style.display="none"))}const w=y.some(v=>u.includes(v.value)&&v.checked),I=y.some(v=>h.includes(v.value)&&v.checked);if((w||I)&&(n=!1),!w&&!n){n=!0;for(const v of y)if(u.includes(v.value)){v.closest("label")?.click(),v.dispatchEvent(new Event("change",{bubbles:!0}));break}}const f=y.find(v=>v.checked);m=f&&u.includes(f.value)?f.value:u[0]??null}else if(i.widget.widgetType==="dropdown"){const y=_.shadowRoot.querySelector("select");if(!y)return;for(const w of Array.from(y.options))h.includes(w.value)&&(w.style.display="none",w.disabled=!0);if(h.includes(y.value)){const w=Array.from(y.options).find(I=>u.includes(I.value));w&&(y.value=w.value,y.dispatchEvent(new Event("change",{bubbles:!0})))}m=u.includes(y.value)?y.value:u[0]??null}if(m){const y=Array.from(document.querySelectorAll('input[name="selling_plan"]'));for(const w of y)w.value!==m&&(w.value=m)}}finally{l=!1}}}if(a.subscriptionHideWrongPlans=c,a.swapMap=le(i,s).swapMap,c(),o){const d=document.querySelector("select[name='id'], input[name='id']");d&&d.addEventListener("change",c)}}function B(a){const e=D(a,"widgetParent");return e.length?document.querySelector(e[0].selector)?.shadowRoot??null:null}function Y(a,e){const t=D(a,"subscriptionPlans");return t.length?e.querySelector(t[0].selector)?.shadowRoot??null:null}function Z(a,e){const t=new URLSearchParams(window.location.search).get("variant");if(t)return t;{const i=document.querySelector('form[action*="/cart/add"] input[name="id"]')?.value;if(i)return i}return a.size>0?[...a.keys()][0]:void 0}function G(a,e){return H(a,e.moneyFormat,e.currency,e.currencyCodeEnabled)}function Fe({originalFetch:a,swapMap:e,slptValue:t,getSelectedPlanId:i,log:s}){if(window.fetch.__shoplift_intercepted)return s("[SUB-INTERCEPT] already installed â skipping"),()=>{};function r(n){if(i){const l=i();if(l)return e[l]??l}return e[n]??n}const o=function(n,l){if((typeof n=="string"?n:n instanceof URL?n.href:n.url).includes("/cart/add")&&l?.body)try{if(l.body instanceof FormData){const d=l.body.get("selling_plan");d?l.body.set("selling_plan",r(String(d))):(!d||d==="")&&t&&l.body.set("properties[_slpt]",t)}
43else if(typeof l.body=="string"){const d=JSON.parse(l.body);if(d.items)for(const u of d.items){const h=String(u.selling_plan??"");h?u.selling_plan=r(h):!u.selling_plan&&t&&(u.properties||(u.properties={}),u.properties._slpt=t)}else if(d.id){const u=String(d.selling_plan??"");u?d.selling_plan=r(u):!d.selling_plan&&t&&(d.properties||(d.properties={}),d.properties._slpt=t)}l.body=JSON.stringify(d)}}catch(d){s("[SUB-INTERCEPT] body parse failed; cart-add proceeds with un-swapped plan",d)}return a.call(window,n,l)};return o.__shoplift_intercepted=!0,window.fetch=o,function(){window.fetch===o&&(window.fetch=a)}}function Be({log:a}){if(window.fetch.__shoplift_intercepted)return a("[SUB-PREVIEW-BLOCK] already installed â skipping"),()=>{};const e=window.fetch,t=function(i,s){const r=typeof i=="string"?i:i instanceof URL?i.href:i.url;return r.includes("/cart/add")?(a("[SUB-PREVIEW-BLOCK] cart-add blocked in preview mode",{url:r}),Promise.resolve(new Response(JSON.stringify({id:0,properties:{},quantity:0,variant_id:0,key:"preview",title:"Preview â cart-add blocked",price:0,original_price:0,line_price:0,original_line_price:0,total_discount:0,discounts:[],preview:!0}),{status:200,headers:{"Content-Type":"application/json"}}))):e.call(window,i,s)};return t.__shoplift_intercepted=!0,window.fetch=t,function(){window.fetch===t&&(window.fetch=e)}}function pe({data:a,runUpdates:e,debounceMs:t=150}){let i=null;function s(){i&&clearTimeout(i),e(),i=setTimeout(e,t)}let r=null;const o=[],n={childList:!0,subtree:!0,characterData:!0,attributes:!0};function l(h){for(const p of o)p.disconnect();o.length=0;for(const p of Array.from(h.querySelectorAll("*")))if(p.shadowRoot){const b=new MutationObserver(s);b.observe(p.shadowRoot,n),o.push(b)}}function c(){const h=B(a);return h?(r&&r.disconnect(),l(h),r=new MutationObserver(p=>{p.some(b=>b.type==="childList"&&b.addedNodes.length>0)&&l(h),s()}),r.observe(h,n),!0):!1}const d=document.body||document.documentElement,u=new MutationObserver(()=>{c()&&s()});return u.observe(d,{childList:!0,subtree:!0}),c()&&s(),e(),function(){i&&(clearTimeout(i),i=null),u.disconnect(),r&&(r.disconnect(),r=null);for(const p of o)p.disconnect();o.length=0}}async function ze(a){if(a.subscriptionPriceDone)return;const e=a.getActiveAssignment(),t=e?a.getHypothesis(e.hypothesisId):void 0,i=t?.subscriptionData?null:a.findActiveSubscriptionTestControl(),s=t?.subscriptionData?t:i?.hypothesis;if(!s?.subscriptionData)return;const r=t?.subscriptionData?e.testId:i.testId;a.subscriptionPriceDone=!0;const o=s.subscriptionData,n=s.isControl,l=s.priceData,c=o.widget.widgetType;let d=W(l),u=J(o,d),h=u.discountMap,p=u.maxDiscount;function b(){const g=W(l);g!==d&&(d=g,u=J(o,d),h=u.discountMap,p=u.maxDiscount,a.log(`[SUB-PRICE] scope refreshed side=${n?"A":"B"}, currentProductId=${d??"n/a"}, maxDiscount=${p}`))}a.log(`[SUB-PRICE] side=${n?"A":"B"}, currentProductId=${d??"n/a"}, maxDiscount=${p}`),a.updatePriceTestHiddenInputs(r,n?"control":"variant",!1);function E(){if(!l)return null;const g=j(l),P=Z(g),A=ce(o,P,d);if(!de(A,n))return null;const k=P?g.get(P):void 0;return k?{formattedVariantPrice:G(k.priceInCents,l),formattedDiscounted:G(k.priceInCents*(1-p/100),l)}:null}Fe({originalFetch:a.fetch,swapMap:a.swapMap??{},slptValue:a.slptValue??void 0,log:a.log,getSelectedPlanId:()=>{const g=B(o);if(!g)return null;const P=Y(o,g);if(!P)return null;const A=D(o,"subscriptionInput"),k=A.length?A[0].selector:'input[name="rc_plan"]';return P.querySelector(`${k}:checked`)?.value??null}});function S(g){const P=D(o,"subscriptionDiscount");for(const A of P)if(A.selector.includes("badge")||A.selector.includes("__badge")){const k=g.querySelector(A.selector);k?.textContent&&!k.textContent.includes(`${p}%`)&&$(k,x=>N(x,p))}}function C(g){const P=E();if(!P)return;const A=D(o,"subscriptionCompareAt");for(const k of A){const x=g.querySelector(k.selector)||g.querySelector(`[part~="${k.selector}"]`);x?.textContent&&!x.textContent.includes(P.formattedVariantPrice)&&$(x,R=>/\d/.test(R)?P.formattedVariantPrice:R)}}function _(g,P){const A=D(o,"subscriptionCompareAt"),k=P===0?"none":"";for(const x of A){const R=g.querySelector(x.selector)||g.querySelector(`[part~="${x.selector}"]`);R&&(k==="none"?R.style.display!=="none"&&(R.style.display="none"):R.style.display==="none"&&(R.style.display=""))}}function T(g){const P=D(o,"subscriptionInput"),A=P.length?P[0].selector:'input[name="rc_plan"]',k=D(o,"subscriptionPlanDiscount"),x=k.length?k[0].selector:".rc-plans-button__discount";for(const R of Array.from(g.querySelectorAll("label"))){const O=R.querySelector(A),V=R.querySelector(x);
43if(O&&V){const L=h[O.value];if(L!==void 0){if(L===0)V.style.display!=="none"&&(V.style.display="none");else if(V.style.display==="none"&&(V.style.display=""),V.textContent){const Q=V.textContent.match(/[\d.]+%/)?.[0];Q&&Q!==`${L}%`&&$(V,et=>N(et,L))}}}}}function m(g){const P=g.querySelector("select");if(P)for(const A of Array.from(P.options)){const k=h[A.value];if(k!==void 0&&A.textContent){const x=A.textContent.match(/[\d.]+%/)?.[0];x&&x!==`${k}%`&&(A.textContent=N(A.textContent,k))}}}function y(g,P){const k=D(o,"subscriptionDiscount").filter(x=>x.selector.includes("benefit")||x.selector==="rc-benefits");for(const x of k){const R=g.querySelector(x.selector);if(R?.shadowRoot){for(const O of Array.from(R.shadowRoot.querySelectorAll("li")))if(O.textContent?.includes("Save")){const V=O;if(P===0)V.style.display!=="none"&&(V.style.display="none");else{V.style.display==="none"&&(V.style.display="");const L=O.textContent.match(/[\d.]+%/)?.[0];L&&L!==`${P}%`&&$(O,Q=>N(Q,P))}}}}}let w=!1;function I(){if(!w){w=!0;try{if(b(),d!==null&&Object.keys(h).length===0)return;const g=B(o);if(!g)return;S(g),l&&C(g);const P=Y(o,g);let A=p;if(P){const k=D(o,"subscriptionInput"),x=k.length?k[0].selector:'input[name="rc_plan"]',R=P.querySelector(`${x}:checked`);if(R){const O=h[R.value];O!==void 0&&(A=O)}c==="buttons"||c==="radio"?T(P):m(P)}_(g,A),y(g,A)}finally{w=!1}}}function f(){const g=E();if(!g)return;const P=B(o);if(!P)return;const A=D(o,"onetimeToggle"),k=A.length?A[0].selector:'input[value="onetime"]';if(!P.querySelector(k)?.checked)return;const R=D(o,"subscriptionPrice");for(const O of R){const V=P.querySelector(O.selector)||P.querySelector(`[part~="${O.selector}"]`);V?.textContent&&!V.textContent.includes(g.formattedDiscounted)&&$(V,L=>/\d/.test(L)?g.formattedDiscounted:L)}}function v(){a.subscriptionHideWrongPlans&&a.subscriptionHideWrongPlans(),I(),a.subscriptionUpdateOneTime&&a.subscriptionUpdateOneTime(),f()}pe({data:o,runUpdates:v})}async function We(a){if(a.subscriptionOneTimeDone)return;const e=a.getActiveAssignment(),t=e?a.getHypothesis(e.hypothesisId):void 0,i=!!(t?.subscriptionData&&t.priceData),s=i?null:a.findActiveSubscriptionTestControl(),r=i?t:s?.hypothesis;if(!r?.subscriptionData||!r.priceData)return;const o=i?e.testId:s.testId;a.subscriptionOneTimeDone=!0;const n=r.subscriptionData,l=r.priceData,c=j(l),d=r.isControl,u=d?"control":"variant";a.slptValue=`${o}:${u}:f`,a.updatePriceTestHiddenInputs(o,u,!1);function h(){const p=B(n);if(!p)return;const b=Z(c);if(!b)return;const E=W(l),S=ce(n,b,E);if(!de(S,d))return;const C=c.get(b);if(!C)return;const _=H(C.priceInCents,l.moneyFormat,l.currency,l.currencyCodeEnabled),T=D(n,"onetimePrice");if(!T.length)return;const m=D(n,"onetimeContainer"),y=m.length?m[0].selector:'[part~="rc-purchase-option__onetime"]',I=p.querySelector(y)??p;for(const f of T){let v=null;try{v=I.querySelector(f.selector)}catch{v=null}v??=I.querySelector(`[part~="${f.selector}"]`),v&&v.textContent&&!v.textContent.includes(_)&&$(v,g=>/\d/.test(g)?_:g)}}a.subscriptionUpdateOneTime=h,h()}async function Ge(a,e){const{subscriptionPreviewRender:t}=await Ne(async()=>{const{subscriptionPreviewRender:i}=await Promise.resolve().then(()=>Xe);return{subscriptionPreviewRender:i}},void 0);return t(a.subscriptionData,a.priceData,a.isControl,e)}function je(a,e){const t=a.widget.selectors.widgetParent??[],i=a.widget.selectors.subscriptionPlans??[],s=a.widget.selectors.subscriptionInput??[];if(!t.length||!i.length||!s.length){e("[SUB-GLOBAL-HIDE] Missing required selectors â skipping");return}const r=t[0].selector,o=i[0].selector,n=s[0].selector;let l=!1,c=null,d=!1;function u(){if(!d){d=!0;try{h()}finally{d=!1}}}function h(){const C=document.querySelector(r);if(!C?.shadowRoot)return;const _=C.shadowRoot.querySelector(o);if(!_?.shadowRoot)return;_.shadowRoot!==c&&(c=_.shadowRoot,l=!1);let T=0;if(a.widget.widgetType==="buttons"||a.widget.widgetType==="radio"){const m=Array.from(_.shadowRoot.querySelectorAll(n));for(const f of m)if(a.planIds.includes(f.value)){f.disabled||(f.disabled=!0);const v=f.closest("label");v&&v.style.display!=="none"&&(v.style.display="none",T++)}const y=m.filter(f=>!a.planIds.includes(f.value));if(!y.some(f=>f.checked)&&!l&&y.length>0){l=!0;const f=y[0];f.closest("label")?.click(),f.dispatchEvent(new Event("change",{bubbles:!0})),e(`[SUB-GLOBAL-HIDE] Preselected first visible plan input=${f.value}`)}const I=y.find(f=>f.checked)??y[0];
43if(I){const f=Array.from(document.querySelectorAll('input[name="selling_plan"]'));for(const v of f)v.value!==I.value&&(v.value=I.value,e(`[SUB-GLOBAL-HIDE] Mirrored plan id ${I.value} to form selling_plan input`))}}else if(a.widget.widgetType==="dropdown"){const m=_.shadowRoot.querySelector("select");if(!m)return;for(const I of Array.from(m.options))a.planIds.includes(I.value)&&(I.style.display!=="none"&&(I.style.display="none"),I.disabled||(I.disabled=!0),T++);const y=Array.from(m.options).filter(I=>!a.planIds.includes(I.value)),w=y.some(I=>I.value===m.value);y.length>0&&!w&&!l&&(l=!0,m.value=y[0].value,m.dispatchEvent(new Event("change",{bubbles:!0})),e(`[SUB-GLOBAL-HIDE] Preselected first visible option=${y[0].value}`))}T>0&&e(`[SUB-GLOBAL-HIDE] Hidden ${T} B-side plan buttons`)}const p={childList:!0,subtree:!0,characterData:!0};let b=null;function E(C){b?.disconnect(),b=new MutationObserver(()=>u()),b.observe(C,p)}function S(){const C=document.querySelector(r);if(!C?.shadowRoot)return!1;u(),new MutationObserver(()=>{u();const m=C.shadowRoot.querySelector(o);m?.shadowRoot&&E(m.shadowRoot)}).observe(C.shadowRoot,p);const T=C.shadowRoot.querySelector(o);return T?.shadowRoot&&E(T.shadowRoot),!0}if(!S()){e("[SUB-GLOBAL-HIDE] Widget not in DOM yet â waiting via MutationObserver");const C=new MutationObserver(()=>{S()&&C.disconnect()});C.observe(document.body??document.documentElement,{childList:!0,subtree:!0})}}const ue="Limited preview",Ke="Add-to-cart and checkout prices won't reflect this test until it launches â test selling plans are not created in your subscription app until after a test is launched.",Je=5e3;function Ye(){const a=document.createElement("div");a.id="shoplift-preview-subscription-warning";const e=document.createElement("span");e.id="shoplift-preview-subscription-warning__icon",e.setAttribute("aria-hidden","true"),e.textContent="!";const t=document.createElement("span");t.id="shoplift-preview-subscription-warning__label",t.textContent=ue;const i=document.createElement("div");i.id="shoplift-preview-subscription-warning__tooltip",i.setAttribute("role","tooltip"),i.textContent=Ke,a.appendChild(e),a.appendChild(t),a.appendChild(i),a.setAttribute("tabindex","0"),a.setAttribute("aria-describedby",i.id),a.setAttribute("aria-label",ue);let s=null;function r(){s!==null&&(clearTimeout(s),s=null)}function o(){i.classList.add("shoplift-preview-subscription-warning__tooltip--visible")}function n(){i.classList.remove("shoplift-preview-subscription-warning__tooltip--visible")}function l(){o(),r(),s=setTimeout(()=>{n(),s=null},Je)}function c(){r(),o()}function d(){s===null&&n()}a.addEventListener("mouseenter",c),a.addEventListener("mouseleave",d),a.addEventListener("focus",c),a.addEventListener("blur",d);function u(p){try{const b=p.target;if(!(b instanceof Element))return;(b.closest('form[action*="/cart/add"] button[type="submit"], form[action*="/cart/add"] input[type="submit"]')!==null||b.closest('[name="add"], button[name="add"], [data-add-to-cart], button[data-add-to-cart]')!==null)&&l()}catch{}}document.addEventListener("click",u,!0);function h(){r(),document.removeEventListener("click",u,!0),a.removeEventListener("mouseenter",c),a.removeEventListener("mouseleave",d),a.removeEventListener("focus",c),a.removeEventListener("blur",d),a.remove()}return{root:a,tooltip:i,cleanup:h}}let he=!1;class Ze{DATA_SL_ATTRIBUTE_P="data-sl-attribute-p";DATA_SL_TEST_ID="data-sl-test-id";VIEWPORT_TRACK_THRESHOLD=.5;temporarySessionKey="Shoplift_Session";essentialSessionKey="Shoplift_Essential";analyticsSessionKey="Shoplift_Analytics";priceSelectorsSessionKey="Shoplift_PriceSelectors_v2";shop;host;eventHost;disableReferrerOverride;legacySessionKey;cssHideClass;testConfigs;inactiveTestConfigs;hiddenSubscriptionPlans;testsFilteredByAudience;sendPageView;shopliftDebug;gaConfig;telemetryEnabled;getCountryTimeout;geoViaShopify;resolvedRegion=null;state;subscriptionPreviewWarningCleanup=null;shopifyAnalyticsId;cookie=document.cookie;isSyncing=!1;isSyncingGA=!1;fetch;localStorageSet;localStorageGet;sessionStorageSet=window.sessionStorage.setItem.bind(window.sessionStorage);sessionStorageGet=window.sessionStorage.getItem.bind(window.sessionStorage);
43urlParams=new URLSearchParams(window.location.search);device;logHistory;activeViewportObservers=new Map;clientIdRetryCount=0;constructor(e,t,i,s,r,o,n,l,c,d,u,h,p,b=!1){this.shop=e,this.host=t,this.eventHost=i,this.disableReferrerOverride=l,this.logHistory=[],this.legacySessionKey=`SHOPLIFT_SESSION_${this.shop}`,this.cssHideClass=s?"shoplift-hide":"",this.testConfigs=u.map(S=>({...S,startAt:new Date(S.startAt),statusHistory:S.statusHistory.map(C=>({...C,createdAt:new Date(C.createdAt)}))})),this.inactiveTestConfigs=h,this.hiddenSubscriptionPlans=p,this.sendPageView=!!r,this.shopliftDebug=o===!0,this.telemetryEnabled=c===!0,this.geoViaShopify=b===!0,this.gaConfig=n!=={"sendEvents":false,"mode":"gtag"}?n:{sendEvents:!1},this.fetch=window.fetch.bind(window),this.localStorageSet=window.localStorage.setItem.bind(window.localStorage),this.localStorageGet=window.localStorage.getItem.bind(window.localStorage);const E=this.getDeviceType();this.device=E!=="tablet"?E:"mobile",this.state=this.loadState(),this.shopifyAnalyticsId=this.getShopifyAnalyticsId(),this.testsFilteredByAudience=u.filter(S=>
43S.status=="active"),this.getCountryTimeout=d===1000?1e3:d,window.__slReadCookie=S=>{const C=this.getCookie(S);if(C===null)return null;try{return decodeURIComponent(C)}catch{return C}},this.log("State Loaded",JSON.stringify(this.state))}deriveCategoryFromExistingTests(){if(!this.state.temporary.testCategory&&this.state.essential.visitorTests.length>0){const e=this.state.essential.visitorTests.some(t=>{if(!t.hypothesisId)return!1;const i=this.getHypothesis(t.hypothesisId);return i&&["theme","basicScript","price"].includes(i.type)});this.state.temporary.testCategory=e?"global":"conditional",this.persistTemporaryState(),this.log("Derived test category from existing visitorTests: %s",this.state.temporary.testCategory)}}async init(){try{if(this.log("Shoplift script initializing"),window.Shopify&&window.Shopify.designMode){this.log("Skipping script for design mode");return}if(window.location.href.includes("slScreenshot=true")){this.log("Skipping script for screenshot");return}if(window.location.hostname.endsWith(".edgemesh.com")){this.log("Skipping script for preview");return}if(window.location.href.includes("isShopliftMerchant")){const o=this.urlParams.get("isShopliftMerchant")==="true";this.log("Setting merchant session to %s",o),this.state.temporary.isMerchant=o,this.persistTemporaryState()}if(this.state.temporary.isMerchant){this.log("Setting up preview for merchant"),typeof window.shoplift!="object"&&this.setShopliftStub(),this.state.temporary.previewConfig||this.hidePage(),await this.initPreview(),document.querySelector("#sl-preview-bar-hide")?.remove();return}if(this.state.temporary.previewConfig=void 0,we(navigator.userAgent))return;const e=Date.now(),t=!this.state.temporary.lastSeen||e-this.state.temporary.lastSeen>1800*1e3;(!this.state.temporary.entryPage||t)&&(this.state.temporary.entryPage=K(window.location.href)),this.state.temporary.lastSeen=e,this.persistTemporaryState(),window.__slEntryPage=this.state.temporary.entryPage??"";const i=this.state.essential.visitorTests.filter(o=>o.hypothesisId&&+o.createdAt>Date.now()-6e4);if(i.length===0)this.sendDiagnosticTelemetry("page-landed",null);else for(const o of i)this.sendDiagnosticTelemetry("page-landed",o.testId,{hypothesisId:o.hypothesisId,isControl:o.assignedTo==="control",testType:o.testType??"unknown"});if(navigator.userAgent.includes("Chrome/118")){this.log("Random: %o",[Math.random(),Math.random(),Math.random()]);const o=await this.makeRequest({url:`${this.eventHost}/api/v0/events/ip`,method:"get"}).then(n=>n?.json());this.log(`IP: ${o}`),this.makeRequest({url:`${this.eventHost}/api/v0/logs`,method:"post",data:JSON.stringify(this.debugState(),ee)}).catch()}if(this.shopifyAnalyticsId=this.getShopifyAnalyticsId(),this.monitorConsentChange(),this.checkForThemePreview())return;if(!this.disableReferrerOverride&&this.state.temporary.originalReferrer!=null){this.log(`Overriding referrer from '${document.referrer}' to '${this.state.temporary.originalReferrer}'`);const o=this.state.temporary.originalReferrer;delete this.state.temporary.originalReferrer,this.persistTemporaryState(),Object.defineProperty(document,"referrer",{get:()=>o,enumerable:!0,configurable:!0})}if(await this.refreshVisitor(this.shopifyAnalyticsId),await this.handleVisitorTest()){this.log("Redirecting for visitor test");return}this.setShoplift(),this.showPage(),this.ensureCartAttributesForExistingPriceTests(!1);const r=this.state.essential.visitorTests.some(o=>(o.hypothesisId?this.getHypothesis(o.hypothesisId):void 0)?.subscriptionData!=null)||Object.values(this.state.temporary.testReservations??{}).some(o=>this.getHypothesis(o.hypothesisId)?.subscriptionData!=null);this.hiddenSubscriptionPlans&&!r&&(this.log(`[SUB-GLOBAL] Visitor not in subscription test â hiding ${this.hiddenSubscriptionPlans.planIds.length} B-side plans`),je(this.hiddenSubscriptionPlans,o=>this.log(o))),await this.subscriptionSwap(),await this.subscriptionOneTimePrice(),await this.subscriptionPriceChange(),await this.finalize(),console.log("SHOPLIFT SCRIPT INITIALIZED!")}catch(e){if(e instanceof ie)return;throw e}finally{typeof window.shoplift!="object"&&this.setShopliftStub()}}getVariantColor(e){switch(e){case"a":return{text:"#141414",bg:"#E2E2E2"};case"b":return{text:"rgba(255, 255, 255, 1)",bg:"rgba(37, 99, 235, 1)"}}}getDefaultVariantTitle(e){return e.title?e.title:e.type==="price"?e.isControl?"Original prices":"Variant prices":e.isControl?"Original":"Untitled variant "+e.label.toUpperCase()}
43async initPreview(){const e=this.urlParams.get("previewConfig");if(e){this.state.temporary.previewConfig=void 0,this.log("Setting up the preview"),this.log("Found preview config, writing to temporary state");const t=await Oe(e);if(this.state.temporary.previewConfig=t,this.state.temporary.previewConfig.testTypeCategory===M.Price){this.hidePage(!0);const s=this.state.temporary.previewConfig;let r=`${this.host}/api/dom-selectors/${s.storeId}/${s.testId}/${s.isDraft||!1}`;s.shopifyProductId&&(r+=`?productId=${s.shopifyProductId}`);const o=await this.makeJsonRequest({method:"get",url:r}).catch(n=>(this.log("Error getting domSelectors",n),null));if(s.variants.forEach(n=>n.domSelectors=o[n.id]?.domSelectors),s.isDraft){const n=`${this.host}/api/dom-selectors/${s.storeId}/${s.testId}/subscription-preview`,l=await this.makeJsonRequest({method:"get",url:n}).catch(c=>(this.log("No subscription preview data for draft (test may not have a subscription widget)",c),null));l?.subscriptionData&&s.variants.forEach(c=>{c.subscriptionData=l.subscriptionData,c.priceData=l.priceData})}}this.persistTemporaryState();const i=new URL(window.location.toString());i.searchParams.delete("previewConfig"),this.queueRedirect(i)}else if(this.state.temporary.previewConfig){this.showPage();const t=this.state.temporary.previewConfig;if(t.testTypeCategory===M.Template&&this.handleTemplatePreview(t)&&this.initPreviewControls(t),t.testTypeCategory===M.UrlRedirect&&this.handleUrlPreview(t)&&this.initPreviewControls(t),t.testTypeCategory===M.Script&&this.handleScriptPreview(t)&&this.initPreviewControls(t),t.testTypeCategory===M.Price){const i=await this.handlePricePreview(t);t.isDraft?await this.handleSubscriptionPricePreview(t):await this.handleSubscriptionLivePreview(t),i&&this.initPreviewControls(t)}}}initPreviewControls(e){document.addEventListener("DOMContentLoaded",()=>{const t=e.variants.find(b=>b.id===e.currentVariant),i=t?.label||"a",s=e.variants,r=document.createElement("div");r.id="shoplift-preview-control";const o=document.createElement("div"),n=document.createElement("img");n.src=Ve,n.height=24,n.width=14,o.style.padding="0 16px",o.style.lineHeight="100%",o.appendChild(n),r.appendChild(o);const l=document.createElement("div");l.id="shoplift-preview-variant-selector";const c=document.createElement("button");c.id="shoplift-preview-variant-menu-trigger";const d=document.createElement("div");d.className="menu-variant-label",d.style.backgroundColor=this.getVariantColor(i).bg,d.style.color=this.getVariantColor(i).text,d.innerText=i.toUpperCase(),c.appendChild(d);const u=document.createElement("span");if(u.id="shoplift-preview-variant-title",u.innerText=t?this.getDefaultVariantTitle(t):"Untitled variant "+i.toUpperCase(),c.appendChild(u),s.length>1){const b=document.createElement("img");b.src=De,b.width=12,b.height=12,b.style.height="12px",b.style.width="12px",c.appendChild(b);const E=document.createElement("div");E.className="preview-variant-menu";for(const S of e.variants.filter(C=>C.id!==e.currentVariant)){const C=document.createElement("div");C.className="preview-variant-menu--item";const _=document.createElement("div");_.className="menu-variant-label",_.style.backgroundColor=this.getVariantColor(S.label).bg,_.style.color=this.getVariantColor(S.label).text,_.style.flexShrink="0",_.innerText=S.label.toUpperCase(),C.appendChild(_);const T=document.createElement("span");T.innerText=this.getDefaultVariantTitle(S),C.appendChild(T),C.addEventListener("click",()=>{this.pickVariant(S.id)}),E.appendChild(C)}l.appendChild(E),c.addEventListener("click",()=>{E.className!=="preview-variant-menu preview-variant-menu__visible"?E.classList.add("preview-variant-menu__visible"):E.classList.remove("preview-variant-menu__visible")}),document.addEventListener("click",S=>{S.target instanceof Element&&!c.contains(S.target)&&E.className==="preview-variant-menu preview-variant-menu__visible"&&E.classList.remove("preview-variant-menu__visible")})}else c.style.pointerEvents="none",d.style.margin="0";if(l.appendChild(c),r.appendChild(l),e.hasSubscription){this.subscriptionPreviewWarningCleanup?.();const b=Ye();r.appendChild(b.root),this.subscriptionPreviewWarningCleanup=b.cleanup}const h=document.createElement("div"),p=document.createElement("button");p.id="shoplift-exit-preview-button",p.innerText="Exit",h.appendChild(p),p.addEventListener("click",()=>{this.exitPreview()}),r.appendChild(h),document.body.appendChild(r),requestAnimationFrame(()=>{r.classList.add("visible")})}),this.ensureCartAttributesForExistingPriceTests(!0)}pickVariant(e){if(this.state.temporary.previewConfig){const t=this.state.temporary.previewConfig,i=new URL(window.location.toString());if(t.testTypeCategory===M.UrlRedirect){const s=t.variants.find(r=>r.id===t.currentVariant)?.redirectUrl;if(i.pathname===s){const r=t.variants.find(o=>o.id===e)?.redirectUrl;r&&(i.pathname=r)}}if(t.testTypeCategory===M.Template){const s=t.variants.find(r=>r.id===t.currentVariant)?.pathName;if(s&&i.pathname===s){const r=t.variants.find(o=>o.id===e)?.pathName;r&&r!==s&&(i.pathname=r)}}t.currentVariant=e,this.persistTemporaryState(),this.queueRedirect(i)}}exitPreview(){const e=new URL(window.location.toString());if(this.state.temporary.previewConfig?.testTypeCategory===M.Template&&e.searchParams.delete("view"),this.state.temporary.previewConfig?.testTypeCategory===M.Script&&e.searchParams.delete("slVariant"),this.state.temporary.previewConfig?.testTypeCategory===M.UrlRedirect){const i=this.state.temporary.previewConfig.variants.filter(r=>!r.isControl&&r.redirectUrl!==null).map(r=>r.redirectUrl),s=this.state.temporary.previewConfig.variants.find(r=>r.label==="a")?.redirectUrl;i.includes(e.pathname)&&s&&(e.pathname=s)}this.state.temporary.isMerchant=!1,e.searchParams.delete("isShopliftMerchant"),this.state.temporary.previewConfig=void 0,this.persistTemporaryState(),this.subscriptionPreviewWarningCleanup?.(),this.subscriptionPreviewWarningCleanup=null,this.hidePage(),this.queueRedirect(e)}handleTemplatePreview(e){const t=e.currentVariant,i=e.variants.find(l=>l.id===t);if(!i)return!1;const s=e.variants.find(l=>l.isControl);if(!s)return!1;this.log("Setting up template preview for type",s.type);
43const r=new URL(window.location.toString()),o=r.searchParams.get("view"),n=i.type===s.type;return!n&&!i.isControl&&template.suffix===s.affix&&this.typeFromTemplate()===s.type&&i.pathName!==null?(this.log("Hit control template type, redirecting to the variant url"),this.hidePage(),r.pathname=i.pathName,this.queueRedirect(r),!0):(!i.isControl&&this.typeFromTemplate()==i.type&&template.suffix===s.affix&&n&&o!==(i.affix||"__DEFAULT__")&&(this.log("Template type and affix match control, updating the view param"),r.searchParams.delete("view"),this.log("Setting the new viewParam to",i.affix||"__DEFAULT__"),this.hidePage(),r.searchParams.set("view",i.affix||"__DEFAULT__"),this.queueRedirect(r)),o!==null&&o!==(i.affix||"__DEFAULT__")&&(r.searchParams.delete("view"),this.hidePage(),this.queueRedirect(r)),!0)}handleUrlPreview(e){const t=e.currentVariant,i=e.variants.find(o=>o.id===t),s=e.variants.find(o=>o.isControl)?.redirectUrl;if(!i)return!1;this.log("Setting up URL redirect preview");const r=new URL(window.location.toString());return r.pathname===s&&!i.isControl&&i.redirectUrl!==null&&(this.log("Url matches control, redirecting"),this.hidePage(),r.pathname=i.redirectUrl,this.queueRedirect(r)),!0}handleScriptPreview(e){const t=e.currentVariant,i=e.variants.find(o=>o.id===t);if(!i)return!1;this.log("Setting up script preview");const s=new URL(window.location.toString());return s.searchParams.get("slVariant")!==i.id&&(this.log("current id doesn't match the variant, redirecting"),s.searchParams.delete("slVariant"),this.log("Setting the new slVariantParam"),this.hidePage(),s.searchParams.set("slVariant",i.id),this.queueRedirect(s)),!0}async handlePricePreview(e){const t=e.currentVariant,i=e.variants.find(s=>s.id===t);return i?(this.log("Setting up price preview"),i.domSelectors&&i.domSelectors.length>0&&(U(document,{testId:e.testId,hypothesisId:i.id,selectors:i.domSelectors}),this.ensureCartAttributesForExistingPriceTests(!0)),!0):!1}async handleSubscriptionPricePreview(e){const t=e.variants.find(i=>i.id===e.currentVariant);t?.subscriptionData&&(this.log("Setting up subscription price preview"),await Ge({id:t.id,isControl:t.isControl,subscriptionData:t.subscriptionData,priceData:t.priceData},(i,...s)=>this.log(i,...s)))}async handleSubscriptionLivePreview(e){this.testConfigs.find(s=>s.id===e.testId)?.hypotheses.find(s=>s.id===e.currentVariant)?.subscriptionData&&(this.log("Setting up subscription live preview"),this.subscriptionSwapDone=!1,this.subscriptionOneTimeDone=!1,this.subscriptionPriceDone=!1,await this.subscriptionSwap(),await this.subscriptionOneTimePrice(),await this.subscriptionPriceChange())}async finalize(){const e=await this.getCartState();e!==null&&this.queueCartUpdate(e),this.pruneStateAndSave(),await this.syncAllEvents()}setShoplift(){this.log("Setting up public API");const t=this.urlParams.get("slVariant")==="true",i=t?null:this.urlParams.get("slVariant");window.shoplift={isHypothesisActive:async s=>{if(this.log("Script checking variant for hypothesis '%s'",s),t)return this.log("Forcing variant for hypothesis '%s'",s),!0;if(i!==null)return this.log("Forcing hypothesis '%s'",i),s===i;const r=this.testConfigs.find(n=>n.hypotheses.some(l=>l.id===s));if(!r)return this.log("No test found for hypothesis '%s'",s),!1;const o=this.state.essential.visitorTests.find(n=>n.testId===r.id);return o?(this.log("Active visitor test found",s),o.hypothesisId===s):(await this.manuallySplitVisitor(r),this.testConfigs.some(n=>n.hypotheses.some(l=>l.id===s&&this.state.essential.visitorTests.some(c=>c.hypothesisId===l.id))))},setAnalyticsConsent:async s=>{await this.onConsentChange(s,!0)},getVisitorData:()=>({visitor:this.state.analytics.visitor,visitorTests:this.state.essential.visitorTests.filter(s=>!s.isInvalid).map(s=>{const{shouldSendToGa:r,savedAt:o,...n}=s;return n})})}}setShopliftStub(){this.log("Setting up stubbed public API");const t=this.urlParams.get("slVariant")==="true",i=t?null:this.urlParams.get("slVariant");window.shoplift={isHypothesisActive:s=>Promise.resolve(t||s===i),setAnalyticsConsent:()=>Promise.resolve(),getVisitorData:()=>({visitor:null,visitorTests:[]})}}async manuallySplitVisitor(e){this.log("Starting manual split for test '%s'",e.id),await this.handleVisitorTest([e]);const t=this.getReservationForTest(e.id);t&&!t.isRealized&&t.entryCriteriaKey&&(this.log("Realizing manual API reservation for test '%s'",e.id),this.realizeReservationForCriteria(t.entryCriteriaKey)),this.saveState(),this.syncAllEvents()}async handleVisitorTest(e){await this.filterTestsByAudience(this.testConfigs,this.state.analytics.visitor??this.buildBaseVisitor(),this.state.essential.visitorTests),this.pruneStaleVisitorTests(),this.deriveC
43ategoryFromExistingTests(),this.clearStaleReservations();let t=e?e.filter(i=>this.testsFilteredByAudience.some(s=>s.id===i.id)):[...this.testsForUrl(this.testsFilteredByAudience),...this.domTestsForUrl(this.testsFilteredByAudience)];try{if(t.length===0)return this.log("No tests found"),!1;this.log("Checking for existing visitor test on page");const i=this.getCurrentVisitorHypothesis(t);if(i){this.log("Found current visitor test");const l=this.considerRedirect(i);return l&&(this.log("Redirecting for current visitor test"),this.redirect(i)),l}const s=this.getReservationForCurrentPage();if(s){this.log("Found matching reservation for current page: %s",s.testId);const l=this.getHypothesis(s.hypothesisId);if(l){l.type!=="price"&&this.realizeReservationForCriteria(s.entryCriteriaKey);const c=this.considerRedirect(l);return c&&this.redirect(l),c}}this.log("No active test relation for test page");const r=this.testsForUrl(this.inactiveTestConfigs.filter(l=>this.testIsPaused(l)&&l.hypotheses.some(c=>this.state.essential.visitorTests.some(d=>d.hypothesisId===c.id)))).map(l=>l.id);if(r.length>0)return this.log("Visitor has paused tests for test page, skipping test assignment: %o",r),!1;if(!this.state.temporary.testCategory){const l=this.testsFilteredByAudience.filter(d=>this.isGlobalEntryCriteria(this.getEntryCriteriaKey(d))),c=this.testsFilteredByAudience.filter(d=>!this.isGlobalEntryCriteria(this.getEntryCriteriaKey(d)));if(this.log("Category dice roll - global tests: %o, conditional tests: %o",l.map(d=>({id:d.id,title:d.title,criteria:this.getEntryCriteriaKey(d)})),c.map(d=>({id:d.id,title:d.title,criteria:this.getEntryCriteriaKey(d)}))),l.length>0&&c.length>0){const d=l.length,u=c.length,h=d+u,p=Math.random()*h;this.state.temporary.testCategory=p<d?"global":"conditional",this.log("Category dice roll: rolled %.2f of %d (global weight: %d, conditional weight: %d), selected '%s'",p,h,d,u,this.state.temporary.testCategory)}else l.length>0?(this.state.temporary.testCategory="global",this.log("Only global tests available, setting category to global")):(this.state.temporary.testCategory="conditional",this.log("Only conditional tests available, setting category to conditional"));this.persistTemporaryState()}const o=this.state.temporary.testCategory;if(this.log("Visitor test category: %s",o),o==="global"){const l=this.testsFilteredByAudience.filter(c=>!this.isGlobalEntryCriteria(this.getEntryCriteriaKey(c)));for(const c of l)this.markTestAsBlocked(c,"category:global");t=t.filter(c=>this.isGlobalEntryCriteria(this.getEntryCriteriaKey(c)))}else{const l=this.testsFilteredByAudience.filter(c=>this.isGlobalEntryCriteria(this.getEntryCriteriaKey(c)));for(const c of l)this.markTestAsBlocked(c,"category:conditional");t=t.filter(c=>!this.isGlobalEntryCriteria(this.getEntryCriteriaKey(c)))}if(t.length===0)return this.log("No tests remaining after category filter"),!1;this.createReservations(t);const n=this.getReservationForCurrentPage();if(n&&!n.isRealized){const l=this.getHypothesis(n.hypothesisId);if(l){l.type!=="price"&&this.realizeReservationForCriteria(n.entryCriteriaKey);const c=this.considerRedirect(l);return c&&(this.log("Redirecting for new test"),this.redirect(l)),c}}return!1}finally{this.includeInDomTests(),this.saveState()}}includeInDomTests(){this.applyControlForAudienceFilteredPriceTests();const e=this.getDomTestsForCurrentUrl(),t=this.getVisitorDomHypothesis(e);for(const i of e){this.log("Evaluating dom test '%s'",i.id);const s=i.hypotheses.some(p=>p.type==="price");if(this.state.essential.visitorTests.find(p=>p.testId===i.id&&p.isInvalid&&!p.hypothesisId)){if(this.log("Visitor is blocked from test '%s', applying control prices if price test",i.id),s){const p=i.hypotheses.find(b=>b.isControl);p?.priceData&&(this.applyPriceTestWithMapLookup(i.id,p,[p],()=>{this.log("Control prices applied for blocked visitor, no metrics tracked")}),this.updatePriceTestHiddenInputs(i.id,"control",!1))}continue}const o=this.getReservationForTest(i.id);let n=null,l=!1;const c=t.find(p=>i.hypotheses.some(b=>p.id===b.id));if(o)n=this.getHypothesis(o.hypothesisId)??null,this.log("Using reserved hypothesis '%s' for test '%s'",o.hypothesisId,i.id);else if(c)n=c,this.log("Using existing hypothesis assignment for test '%s'",i.id);else if(s){const p=this.visitorActiveTestTypeWithReservations();p?(l=!0,this.log("Visitor already in test type '%s', treating as non-test for price test '%s'",p,i.id)):n=this.pickHypothesis(i)}else n=this.pickHypothesis(i);if(l&&s){const p=i.hypotheses.find(b=>b.isControl);p?.priceData&&(this.log("Applying control prices for non-test visitor on price test '%s' (Map-based)",i.id),this.applyPriceTestWithMapLookup(i.id,p,[p],()=>{this.log("Control prices applied for non-test visitor, no metrics tracked")}
43),this.updatePriceTestHiddenInputs(i.id,"control",!1));continue}if(!n){this.log("Failed to pick hypothesis for test");continue}this.sendDiagnosticTelemetry("assignment",i.id,{hypothesisId:n.id,isControl:n.isControl,testType:n.type});const d=i.bayesianRevision??4,u=n.type==="price",h=d>=5;if(u&&h){if(this.log(`Price test with Map-based lookup (v${d}): ${i.id}`),!n.priceData){this.log("No price data for hypothesis '%s', skipping",n.id);continue}const p=n.isControl?"control":"variant";this.log(`Setting up Map-based price test for ${p} (test: ${i.id})`),this.applyPriceTestWithMapLookup(i.id,n,i.hypotheses,b=>{const E=this.getReservationForTest(b);E&&!E.isRealized&&E.entryCriteriaKey?this.realizeReservationForCriteria(E.entryCriteriaKey):this.queueAddVisitorToTest(b,n),this.saveState(),this.queuePageView(window.location.pathname),this.syncAllEvents()});continue}if(u&&!h){this.log(`Price test without viewport tracking (v${d}): ${i.id}`);const p=this.getDomSelectorsForHypothesis(n);if(p.length===0)continue;U(document,{testId:i.id,hypothesisId:n.id,selectors:p},b=>{this.queueAddVisitorToTest(b,n),this.saveState(),this.queuePageView(window.location.pathname),this.syncAllEvents()});continue}if(!n.domSelectors||n.domSelectors.length===0){this.log("No selectors found, skipping hypothesis");continue}U(document,{testId:i.id,hypothesisId:n.id,selectors:n.domSelectors},p=>{this.queueAddVisitorToTest(p,n),this.saveState(),this.queuePageView(window.location.pathname),this.syncAllEvents()})}}considerRedirect(e){if(this.log("Considering redirect for hypothesis '%s'",e.id),e.isControl)return this.log("Skipping redirect for control"),!1;if(e.type==="basicScript"||e.type==="manualScript")return this.log("Skipping redirect for script test"),!1;const t=this.state.essential.visitorTests.find(o=>o.hypothesisId===e.id),i=new URL(window.location.toString()),r=new URLSearchParams(window.location.search).get("view");if(e.type==="theme"){if(!(e.themeId===themeId)){if(this.log("Theme id '%s' is not hypothesis theme ID '%s'",e.themeId,themeId),this.isAppProxyPath())return this.log("On App Proxy path, skipping theme redirect to avoid infinite loop"),!1;if(t&&t.themeId!==e.themeId&&(t.themeId===themeId||!this.isThemePreview()))this.log("On old theme, redirecting and updating local visitor"),t.themeId=e.themeId;else if(this.isThemePreview())return this.log("On non-test theme, skipping redirect"),!1;return this.log("Hiding page to redirect for theme test"),this.hidePage(),!0}return!1}else if(e.type!=="dom"&&e.type!=="price"&&e.affix!==template.suffix&&e.affix!==r||e.redirectPath&&!i.pathname.endsWith(e.redirectPath))return this.log("Hiding page to redirect for template test"),this.hidePage(),!0;return this.log("Not redirecting"),!1}redirect(e){if(this.log("Redirecting to hypothesis '%s'",e.id),e.isControl)return;const t=new URL(window.location.toString());if(t.searchParams.delete("view"),e.redirectPath){const n=RegExp("^(/w{2}-w{2})/").exec(t.pathname);if(n&&n.length>1){const l=n[1];t.pathname=`${l}${e.redirectPath}`}else t.pathname=e.redirectPath}else e.type==="theme"?(t.searchParams.set("_ab","0"),t.searchParams.set("_fd","0"),t.searchParams.set("_sc","1"),t.searchParams.set("preview_theme_id",e.themeId.toString())):e.type!=="urlRedirect"&&t.searchParams.set("view",e.affix);const i=this.state.essential.visitorTests.find(n=>n.hypothesisId===e.id)?.testId,s=t.pathname+t.search,r=window.location.pathname+window.location.search,o=K(t.hash);if(i&&s!==r&&!o){const n=qe(),l=He({v:2,t:i,n,fh:Me(window.location.pathname+window.location.search)});t.hash=`slr-${n}`;const c=new Date(Date.now()+3e4).toUTCString();document.cookie=`shoplift_redirect=${l};domain=.${window.location.hostname};path=/;SameSite=Strict;expires=${c}`}s===r&&this.showPage(),this.queueRedirect(t)}async refreshVisitor(e){if(e===null||!this.state.essential.isFirstLoad||!this.testConfigs.some(i=>i.visitorOption!=="all"))return;this.log("Refreshing visitor"),this.hidePage();const t=await this.getVisitor(e);t&&t.id&&this.updateLocalVisitor(t)}buildBaseVisitor(){return{shopifyAnalyticsId:this.shopifyAnalyticsId,device:this.device,country:null,...this.state.essential.initialState}}getInitialState(){const e=this.getUTMValue("utm_source")??"",t=this.getUTMValue("utm_medium")??"",i=this.getUTMValue("utm_campaign")??"",s=this.getUTMValue("utm_content")??"",r=window.document.referrer,o=this.device;return{createdAt:new Date,utmSource:e,utmMedium:t,utmCampaign:i,utmContent:s,referrer:r,device:o}}checkForThemePreview(){return this.log("Checking for theme preview"),window.location.hostname.endsWith(".shopifypreview.com")?(this.log("on shopify preview domain"),this.clearThemeBar(!0,!1,this.state),document.querySelector("#sl-preview-bar-hide")?.remove(),!1):this.isThemePreview()?this.state.essential.visitorTests.some(e=>e.isThemeTest&&e.hypothesisId!=null&&this.getHypothesis(e.hypothesisId)&&e.themeId===themeId)?(this.log("On active theme test, remov
43ing theme bar"),this.clearThemeBar(!1,!0,this.state),!1):this.state.essential.visitorTests.some(e=>e.isThemeTest&&e.hypothesisId!=null&&!this.getHypothesis(e.hypothesisId)&&e.themeId===themeId)?(this.log("Visitor is on an inactive theme test, redirecting to main theme"),this.redirectToMainTheme(),!0):this.state.essential.isFirstLoad?(this.log("No visitor found on theme preview, redirecting to main theme"),this.redirectToMainTheme(),!0):this.inactiveTestConfigs.some(e=>e.hypotheses.some(t=>t.themeId===themeId))?(this.log("Current theme is an inactive theme test, redirecting to main theme"),this.redirectToMainTheme(),!0):this.testConfigs.some(e=>e.hypotheses.some(t=>t.themeId===themeId))?(this.log("Falling back to clearing theme bar"),this.clearThemeBar(!1,!0,this.state),!1):(this.log("No tests on current theme, skipping script"),this.clearThemeBar(!0,!1,this.state),document.querySelector("#sl-preview-bar-hide")?.remove(),!0):(this.log("Not on theme preview"),this.clearThemeBar(!0,!1,this.state),!1)}redirectToMainTheme(){this.hidePage();const e=new URL(window.location.toString());e.searchParams.set("preview_theme_id",""),this.queueRedirect(e)}testsForUrl(e){const t=new URL(window.location.href),i=this.typeFromTemplate();return e.filter(s=>s.hypotheses.some(r=>r.type!=="dom"&&r.type!=="price"&&(r.isControl&&r.type===i&&r.affix===template.suffix||r.type==="theme"||r.isControl&&r.type==="urlRedirect"&&r.redirectPath&&t.pathname.endsWith(r.redirectPath)||r.type==="basicScript"))&&(s.ignoreTestViewParameterEnforcement||!t.searchParams.has("view")||s.hypotheses.map(r=>r.affix).includes(t.searchParams.get("view")??"")))}domTestsForUrl(e){const t=new URL(window.location.href);return e.filter(i=>i.hypotheses.some(s=>s.type!=="dom"&&s.type!=="price"?!1:s.type==="price"&&s.priceData&&s.priceData.variants.length>0?!0:s.domSelectors&&s.domSelectors.some(r=>new RegExp(se(r)).test(K(t.toString())))))}async filterTestsByAudience(e,t,i){const s=[],r=e.some(n=>(n.requiresRegion||this.geoViaShopify&&n.requiresCountry)&&!i.some(l=>l.testId===n.id));this.resolvedRegion===null&&r&&(this.log("Hiding page to wait for Shopify region resolution"),this.hidePage(),await this.waitForResolvedRegion()),window.__slRegion=this.resolvedRegion??"";let o=t.country;this.geoViaShopify?o=this.resolvedRegion?this.resolvedRegion.slice(0,2):o:!o&&e.some(n=>n.requiresCountry&&!i.some(l=>l.testId===n.id))&&(this.log("Hiding page to check geoip"),this.hidePage(),o=await this.makeJsonRequest({method:"get",url:`${this.eventHost}/api/v0/visitors/get-country`,signal:AbortSignal.timeout(this.getCountryTimeout)}).catch(n=>(this.log("Error getting country",n),null)));for(const n of e){if(this.log("Checking audience for test '%s'",n.id),this.state.essential.visitorTests.some(d=>d.testId===n.id&&d.hypothesisId==null)){console.log(`Skipping blocked test '${n.id}'`);continue}const l=this.visitorCreatedDuringTestActive(n.statusHistory);(i.some(d=>d.testId===n.id&&(n.device==="all"||n.device===t.device&&n.device===this.device))||this.isTargetAudience(n,t,l,o))&&(this.log("Visitor is in audience for test '%s'",n.id),s.push(n))}this.testsFilteredByAudience=s}async waitForResolvedRegion(e=1500,t=50){const i=Date.now();for(;this.resolvedRegion===null&&Date.now()-i<e;)await new Promise(s=>window.setTimeout(s,t))}isTargetAudience(e,t,i,s){const r=this.getChannel(t);return(e.device==="all"||e.device===t.device&&e.device===this.device)&&(e.visitorOption==="all"||e.visitorOption==="new"&&i||e.visitorOption==="returning"&&!i)&&(e.targetAudiences.length===0||e.targetAudiences.reduce((o,n)=>o||n.reduce((l,c)=>l&&c(t,i,r,s),!0),!1))}visitorCreatedDuringTestActive(e){let t="";for(const i of e){if(this.state.analytics.visitor!==null&&this.state.analytics.visitor.createdAt<i.createdAt||this.state.essential.initialState.createdAt<i.createdAt)break;t=i.status}return t==="active"}getDomTestsForCurrentUrl(){return this.domTestsForUrl(this.testsFilteredByAudience)}getCurrentVisitorHypothesis(e){return e.flatMap(t=>t.hypotheses).find(t=>t.type!=="dom"&&t.type!=="price"&&this.state.essential.visitorTests.some(i=>i.hypothesisId===t.id))}getVisitorDomHypothesis(e){return e.flatMap(t=>t.hypotheses).filter(t=>(t.type==="dom"||t.type==="price")&&this.state.essential.visitorTests.some(i=>i.hypothesisId===t.id))}getHypothesis(e){return this.testConfigs.filter(t=>t.hypotheses.some(i=>i.id===e)).map(t=>t.hypotheses.find(i=>i.id===e))[0]}getActiveAssignment(){if(this.state.temporary.isMerchant&&this.state.temporary.previewConfig){const t=this.state.temporary.previewConfig;return t.currentVariant&&t.testId?{testId:t.testId,hypothesisId:t.currentVariant}:null}const e=this.state.essential.visitorTests.find(t=>t.hypothesisId);return e?.hypothesisId?{testId:e.testId,hypothesisId:e.hypothesisId}:null}findActiveSubscriptionTestControl(){for(const e of this.testConfigs){const t=e.hypotheses.find(i=>i.isControl);if(t?.subscriptionData)return{testId:e.id,hypothesis:t}}return null}getDomSelectorsForHypothesis(e){if(!e)return[];if(e.domSelectors&&e.domSelectors.length>0)return e.domSelectors;if(e.priceData){const t=`${this.priceSelectorsSessionKey}_${e.id}`;try{const s=sessionStorage.getItem(t);if(s){const r=JSON.parse(s);return e.domSelectors=r,this.log("Loaded %d price selectors from cache for hypothesis '%s'",r.length,e.id),r}}catch{}const i=$e(e.priceData);e.domSelectors=i;try{sessionStorage.setItem(t,JSON.stringify(i)),this.log("Generated and cached %d price selectors for hypothesis '%s'",i.length,e.id)}catch{this.log("Generated %d price selectors for hypothesis '%s' (cache unavailable)",i.length,e.id)}return i}return[]}hasThemeTest(e){return e.some(t=>t.hypotheses.some(i=>i.type==="theme"))}hasTestThatIsNotThemeTest(e){return e.some(t=>t.hypotheses.some(i=>i.type!=="theme"&&i.type!=="dom"&&i.type!=="price"))}hasThemeAndOtherTestTypes(e){return this.hasThemeTest(e)&&this.hasTestThatIsNotThemeTest(e)}testIsPaused(e){return e.status==="paused"||e.status==="incompatible"||e.status==="suspended"}visitorActiveTestType(){const e=this.state.essential.visitorTests.filter(t=>this.testConfigs.some(i=>i.hypotheses.some(s=>s.id==t.hypothesisId)));return e.length===0?null:e.some(t=>t.isThemeTest)?"theme":"templateOrUrlRedirect"}getReservationType(e){return e==="price"||this.isTemplateTestType(e)?"deferred":"immediate"}isTemplateTestType(e){return["product","collection","landing","index","cart","search","blog","article","collectionList"].includes(e)}getEntryCriteriaKey(e){const t=e.hypotheses.find(i=>i.isControl);if(!t)return`unknown:${e.id}`;switch(t.type){case"theme":return"global:theme";case"basicScript":return"global:autoApi";case"price":return"global:price";case"manualScript":return`conditional:manualApi:${e.id}`;case"urlRedirect":return`conditional:url:${t.redirectPath||"unknown"}`;default:return`conditional:template:${t.type}`}}isGlobalEntryCriteria(e){return e.startsWith("global:")}groupTestsByEntryCriteria(e){const t=new Map;for(const i of e){const s=this.getEntryCriteriaKey(i),r=t.get(s)||[];r.push(i),t.set(s,r)}return t}doesCurrentPageMatchEntryCriteria(e){if(this.isGlobalEntryCriteria(e))return!0;
43if(e==="conditional:manualApi")return!1;if(e.startsWith("conditional:url:")){const t=e.replace("conditional:url:","");return window.location.pathname.endsWith(t)}if(e.startsWith("conditional:template:")){const t=e.replace("conditional:template:","");return this.typeFromTemplate()===t}return!1}hasActiveReservation(){const e=this.getActiveReservations();return Object.values(e).some(t=>!t.isRealized)}getActiveReservation(){const e=this.getActiveReservations();return Object.values(e).find(t=>!t.isRealized)??null}clearStaleReservations(){const e=this.state.temporary.testReservations;if(!e)return;let t=!1;for(const[i,s]of Object.entries(e)){const r=this.testConfigs.find(n=>n.id===s.testId);if(!r){this.log("Test '%s' no longer in config, clearing reservation for criteria '%s'",s.testId,i),delete e[i],t=!0;continue}if(r.status!=="active"){this.log("Test '%s' status is '%s', clearing reservation for criteria '%s'",s.testId,r.status,i),delete e[i],t=!0;continue}this.testsFilteredByAudience.some(n=>n.id===s.testId)||(this.log("Visitor no longer passes audience for test '%s', clearing reservation for criteria '%s'",s.testId,i),delete e[i],t=!0)}t&&this.persistTemporaryState()}createReservations(e){if(this.state.temporary.testReservations||(this.state.temporary.testReservations={}),this.state.temporary.rolledEntryCriteria||(this.state.temporary.rolledEntryCriteria=[]),this.state.temporary.testCategory==="global"){this.createSingleReservation(e,"global");return}const i=e.filter(n=>this.doesCurrentPageMatchEntryCriteria(this.getEntryCriteriaKey(n))),s=e.filter(n=>!this.doesCurrentPageMatchEntryCriteria(this.getEntryCriteriaKey(n)));this.log("Conditional tests split - matching current page: %d, not matching: %d",i.length,s.length),i.length>0&&this.log("Tests matching current page (same pool): %o",i.map(n=>({id:n.id,title:n.title,criteria:this.getEntryCriteriaKey(n)})));const r=`conditional:current-page:${this.typeFromTemplate()}`;if(i.length>0&&!this.state.temporary.rolledEntryCriteria.includes(r)){this.createSingleReservation(i,r);for(const n of i){const l=this.getEntryCriteriaKey(n);this.state.temporary.rolledEntryCriteria.includes(l)||this.state.temporary.rolledEntryCriteria.push(l)}}const o=this.groupTestsByEntryCriteria(s);for(const[n,l]of o){if(this.state.temporary.rolledEntryCriteria.includes(n)){this.log("Already rolled for criteria '%s', skipping",n);continue}if(l.some(S=>this.state.essential.visitorTests.some(C=>C.testId===S.id))){this.log("Visitor already has VT for criteria '%s', skipping",n),this.state.temporary.rolledEntryCriteria.push(n);continue}const d=[...l].sort((S,C)=>S.id.localeCompare(C.id));this.log("Test dice roll for criteria '%s' - available tests: %o",n,d.map(S=>({id:S.id,title:S.title})));const u=Math.floor(Math.random()*d.length),h=d[u];this.log("Test dice roll: picked index %d of %d, selected test '%s' (%s)",u+1,l.length,h.id,h.title);const p=this.pickHypothesis(h);if(!p){this.log("No hypothesis picked for test '%s'",h.id);continue}this.sendDiagnosticTelemetry("assignment",h.id,{hypothesisId:p.id,isControl:p.isControl,testType:p.type});const b=this.getReservationType(p.type),E={testId:h.id,hypothesisId:p.id,testType:p.type,reservationType:b,isThemeTest:p.type==="theme",themeId:p.themeId,createdAt:new Date,isRealized:!1,entryCriteriaKey:n};this.state.temporary.testReservations[n]=E,this.state.temporary.rolledEntryCriteria.push(n),this.log("Created %s reservation for test '%s' (criteria: %s)",b,h.id,n);for(const S of l)S.id!==h.id&&this.markTestAsBlocked(S,n)}this.persistTemporaryState()}createSingleReservation(e,t){if(this.state.temporary.rolledEntryCriteria.includes(t)){this.log("Already rolled for pool '%s', skipping",t);return}if(e.some(u=>this.state.essential.visitorTests.some(h=>h.testId===u.id&&!h.isInvalid))){this.log("Visitor already has VT for pool '%s', skipping",t),this.state.temporary.rolledEntryCriteria.push(t);return}if(e.length===0){this.log("No tests in pool '%s'",t);return}const s=[...e].sort((u,h)=>u.id.localeCompare(h.id));this.log("Test dice roll for pool '%s' - available tests: %o",t,s.map(u=>({id:u.id,title:u.title,criteria:this.getEntryCriteriaKey(u)})));const r=Math.floor(Math.random()*s.length),o=s[r];this.log("Test dice roll: picked index %d of %d, selected test '%s' (%s)",r,e.length,o.id,o.title);const n=this.pickHypothesis(o);if(!n){this.log("No hypothesis picked for test '%s'",o.id);return}this.sendDiagnosticTelemetry("assignment",o.id,{hypothesisId:n.id,isControl:n.isControl,testType:n.type});const l=this.getReservationType(n.type),c=this.getEntryCriteriaKey(o),d={testId:o.id,hypothesisId:n.id,testType:n.type,reservationType:l,isThemeTest:n.type==="theme",themeId:n.themeId,createdAt:new Date,isRealized:!1,entryCriteriaKey:c};this.state.temporary.testReservations[c]=d,this.state.temporary.rolledEntryCriteria.push(t),this.log("Created %s reservation for test '%s' from pool '%s' (criteria: %s)",l,o.id,t,c);for(const u of e)u.id!==o.id&&this.markTestAsBlocked(u,`pool:${t}`);this.persistTemporaryState()}markTestAsBlocked(e,t){this.state.essential.visitorTests.some(i=>i.testId===e.id)||(this.log("Blocking visitor from test '%s' (reason: %s)",e.id,t),this.state.essential.visitorTests.push({createdAt:new Date,testId:e.id,hypothesisId:null,isThemeTest:e.hypotheses.some(i=>
43i.type==="theme"),shouldSendToGa:!1,isSaved:!0,isInvalid:!0,themeId:void 0}))}realizeReservationForCriteria(e){const t=this.state.temporary.testReservations?.[e];if(!t)return this.log("No reservation found for criteria '%s'",e),!1;if(t.isRealized)return this.log("Reservation already realized for criteria '%s'",e),!1;if(this.state.essential.visitorTests.some(s=>s.testId===t.testId&&!s.isInvalid))return this.log("Visitor already assigned to test '%s'",t.testId),!1;const i=this.getHypothesis(t.hypothesisId);return i?(t.isRealized=!0,this.persistTemporaryState(),this.queueAddVisitorToTest(t.testId,i),this.saveState(),this.log("Realized reservation for test '%s' (criteria: %s)",t.testId,e),!0):(this.log("Hypothesis '%s' not found",t.hypothesisId),!1)}getActiveReservations(){return this.state.temporary.testReservations??{}}getReservationForCurrentPage(){const e=this.getActiveReservations();for(const[t,i]of Object.entries(e)){if(i.isRealized)continue;const s=this.testConfigs.find(r=>r.id===i.testId);if(!(!s||s.status!=="active")&&this.doesCurrentPageMatchEntryCriteria(t))return i}return null}getReservationForTest(e){const t=this.getActiveReservations();return Object.values(t).find(i=>i.testId===e)??null}getReservationTestType(){const e=this.getActiveReservations(),t=Object.values(e);if(t.length===0)return null;for(const i of t)if(i.isThemeTest)return"theme";for(const i of t)if(i.testType==="price")return"price";return t.some(i=>!i.isRealized)?"templateOrUrlRedirect":null}hasPriceTests(e){return e.some(t=>t.hypotheses.some(i=>i.type==="price"))}_priceTestProductIds=null;getPriceTestProductIds(){if(this._priceTestProductIds)return this._priceTestProductIds;const e=new Set;for(const t of this.testConfigs)for(const i of t.hypotheses)if(i.type==="price"){for(const s of i.domSelectors||[]){const r=s.cssSelector.match(/data-sl-attribute-(?:p|cap)="(\d+)"/);r?.[1]&&e.add(r[1])}if(i.priceData?.variants)for(const[s]of i.priceData.variants)e.add(s)}return this._priceTestProductIds=e,this.log("Built price test product ID cache with %d products",e.size),e}isProductInAnyPriceTest(e){return this.getPriceTestProductIds().has(e)}visitorActiveTestTypeWithReservations(){const e=this.getActiveReservations();for(const r of Object.values(e)){if(r.isThemeTest)return"theme";if(r.testType==="price")return"price"}if(Object.values(e).some(r=>!r.isRealized)){if(this.state.temporary.testCategory==="global")for(const o of Object.values(e)){if(o.testType==="theme")return"theme";if(o.testType==="price")return"price";if(o.testType==="basicScript")return"theme"}return"templateOrUrlRedirect"}const i=this.state.essential.visitorTests.filter(r=>!r.isInvalid&&this.testConfigs.some(o=>o.hypotheses.some(n=>n.id===r.hypothesisId)));return i.length===0?null:i.some(r=>this.getHypothesis(r.hypothesisId)?.type==="price")?"price":i.some(r=>r.isThemeTest)?"theme":"templateOrUrlRedirect"}applyControlForAudienceFilteredPriceTests(){const e=this.testConfigs.filter(s=>s.status==="active"&&s.hypotheses.some(r=>r.type==="price"));if(e.length===0)return;const t=this.testsFilteredByAudience.filter(s=>s.hypotheses.some(r=>r.type==="price")),i=e.filter(s=>!t.some(r=>r.id===s.id));if(i.length!==0){this.log("Found %d price tests filtered by audience, applying control selectors",i.length);for(const s of i){const r=s.hypotheses.find(c=>c.isControl),o=this.getDomSelectorsForHypothesis(r);if(o.length===0){this.log("No control selectors for audience-filtered price test '%s'",s.id);continue}const n=new URL(window.location.href);o.some(c=>{try{return new RegExp(se(c)).test(K(n.toString()))}catch{return!1}})&&(this.log("Applying control selectors for audience-filtered price test '%s'",s.id),U(document,{testId:s.id,hypothesisId:r.id,selectors:o},()=>{}),this.updatePriceTestHiddenInputs(s.id,"control",!1))}}}pickHypothesis(e){let t=Math.random();const i=e.hypotheses.reduce((r,o)=>r+o.visitorCount,0);return e.hypotheses.sort((r,o)=>r.isControl?o.isControl?0:-1:o.isControl?1:0).reduce((r,o)=>{if(r!==null)return r;const l=e.hypotheses.reduce((c,d)=>c&&d.visitorCount>20,!0)?o.visitorCount/i-o.trafficPercentage:0;return t<=o.trafficPercentage-l?o:(t-=o.trafficPercentage-l,null)},null)}typeFromTemplate(){switch(template.type){case"list-collections":return"collectionList";case"page":return"landing";case"article":case"blog":case"cart":case"collection":case"index":case"product":case"search":return template.type;default:return null}}queueRedirect(e){this.saveState(),this.disableReferrerOverride||(this.log(`Saving temporary referrer override '${document.referrer}'`),this.state.temporary.originalReferrer=document.referrer,this.persistTemporaryState()),window.setTimeout(()=>window.location.assign(e),0),window.setTimeout(()=>{this.syncAllEvents()},2e3)}scheduleRetrySync(){this.clientIdRetryCount>=5||(this.clientIdRetryCount++,window.setTimeout(()=>{this.syncAllEvents()},500))}async syncAllEvents(){const e=async()=>
43{if(this.isSyncing){window.setTimeout(()=>{(async()=>await e())()},500);return}try{if(this.isSyncing=!0,this.syncGAEvents(),this.shopifyAnalyticsId||(this.shopifyAnalyticsId=this.getShopifyAnalyticsId()),!this.shopifyAnalyticsId){this.scheduleRetrySync();return}await this.syncEvents()}finally{this.isSyncing=!1}};await e()}async syncEvents(){if(!this.state.essential.consentApproved||!this.shopifyAnalyticsId||this.state.analytics.queue.length===0)return;const e=this.state.analytics.queue.length,t=this.state.analytics.queue.splice(0,e);this.log("Syncing %s events",e);try{const i={shop:this.shop,visitorDetails:{shopifyAnalyticsId:this.shopifyAnalyticsId,device:this.state.analytics.visitor?.device??this.device,country:this.state.analytics.visitor?.country??null,...this.state.essential.initialState},events:this.state.essential.visitorTests.filter(r=>!r.isInvalid&&!r.isSaved&&r.hypothesisId!=null).map(r=>new be(r.testId,r.hypothesisId,r.createdAt)).concat(t)};await this.sendEvents(i);for(const r of this.state.essential.visitorTests.filter(o=>!o.isInvalid&&!o.isSaved&&o.hypothesisId!=null))this.sendDiagnosticTelemetry("event-delivered",r.testId,{hypothesisId:r.hypothesisId,isControl:r.assignedTo==="control",testType:r.testType??"unknown"});const s=await this.getVisitor(this.shopifyAnalyticsId);s!==null&&this.updateLocalVisitor(s);for(const r of this.state.essential.visitorTests.filter(o=>!o.isInvalid&&!o.isSaved))r.isSaved=!0,r.savedAt=Date.now()}catch{this.state.analytics.queue.splice(0,0,...t)}finally{this.saveState()}}syncGAEvents(){if(!this.gaConfig.sendEvents){if(he)return;he=!0,this.log("UseGtag is false â skipping GA Events");return}if(this.isSyncingGA){this.log("Already syncing GA - skipping GA events");return}const e=this.state.essential.visitorTests.filter(t=>t.shouldSendToGa);e.length!==0&&(this.isSyncingGA=!0,this.log("Syncing %s GA Events",e.length),Promise.allSettled(e.map(t=>this.sendGAEvent(t))).then(()=>this.log("All gtag events sent")).finally(()=>this.isSyncingGA=!1))}sendGAEvent(e){return new Promise(t=>{this.log("Sending GA Event for test %s, hypothesis %s",e.testId,e.hypothesisId);const i=()=>{this.log("GA acknowledged event for hypothesis %s",e.hypothesisId),e.shouldSendToGa=!1,this.persistEssentialState(),t()},s={exp_variant_string:`SL-${e.testId}-${e.hypothesisId}`};
43this.shopliftDebug&&Object.assign(s,{debug_mode:!0});function r(o,n,l){window.dataLayer=window.dataLayer||[],window.dataLayer.push(arguments)}this.gaConfig.mode==="gtag"?r("event","experience_impression",{...s,event_callback:i}):(window.dataLayer=window.dataLayer||[],window.dataLayer.push({event:"experience_impression",...s,eventCallback:i}))})}updateLocalVisitor(e){let t;({visitorTests:t,...this.state.analytics.visitor}=e),this.log("updateLocalVisitor - server returned %d tests: %o",t.length,t.map(s=>({testId:s.testId,hypothesisId:s.hypothesisId,isInvalid:s.isInvalid}))),this.log("updateLocalVisitor - local has %d tests: %o",this.state.essential.visitorTests.length,this.state.essential.visitorTests.map(s=>({testId:s.testId,hypothesisId:s.hypothesisId,isSaved:s.isSaved,isInvalid:s.isInvalid})));const i=300*1e3;for(const s of this.state.essential.visitorTests.filter(r=>r.isSaved&&(!r.savedAt||Date.now()-r.savedAt>i)&&!t.some(o=>o.testId===r.testId)))this.log("updateLocalVisitor - marking LOCAL test as INVALID (isSaved && not in server): testId=%s, hypothesisId=%s",s.testId,s.hypothesisId),s.isInvalid=!0;for(const s of t){const r=this.state.essential.visitorTests.findIndex(n=>n.testId===s.testId);if(!(r!==-1))this.log("updateLocalVisitor - ADDING server test (not found locally): testId=%s, hypothesisId=%s",s.testId,s.hypothesisId),this.state.essential.visitorTests.push(s);else{const n=this.state.essential.visitorTests.at(r);this.log("updateLocalVisitor - REPLACING local test with server test: testId=%s, local hypothesisId=%s -> server hypothesisId=%s, local isInvalid=%s -> false",s.testId,n?.hypothesisId,s.hypothesisId,n?.isInvalid),s.isInvalid=!1,s.shouldSendToGa=n?.shouldSe
43ndToGa??!1,s.testType=n?.testType,s.assignedTo=n?.assignedTo,s.testTitle=n?.testTitle,this.state.essential.visitorTests.splice(r,1,s)}}this.log("updateLocalVisitor - FINAL local tests: %o",this.state.essential.visitorTests.map(s=>({testId:s.testId,hypothesisId:s.hypothesisId,isSaved:s.isSaved,isInvalid:s.isInvalid}))),this.state.analytics.visitor.storedAt=new Date}async getVisitor(e){try{return await this.makeJsonRequest({method:"get",url:`${this.eventHost}/api/v0/visitors/by-key/${this.shop}/${e}`})}catch{return null}}async sendEvents(e){await this.makeRequest({method:"post",url:`${this.eventHost}/api/v0/events`,data:JSON.stringify(e)})}sendDiagnosticTelemetry(e,t,i){if(!this.telemetryEnabled||!navigator.sendBeacon)return;const s=this.state.essential.consentApproved,r=JSON.stringify({shop:this.shop,testId:t,checkpoint:e,device:this.device,...s?{visitorId:this.shopifyAnalyticsId??"unknown"}:{},clientTimestamp:Date.now(),consentApproved:s,hasConsentInteraction:this.state.essential.hasConsentInteraction,...i});navigator.sendBeacon(`${this.eventHost}/api/v0/telemetry`,new Blob([r],{type:"text/plain"}))}getUTMValue(e){const i=decodeURIComponent(window.location.search.substring(1)).split("&");for(let s=0;s<i.length;s++){const r=i[s].split("=");if(r[0]===e)return r[1]||null}return null}hidePage(e){this.log("Hiding page"),this.cssHideClass&&!window.document.documentElement.classList.contains(this.cssHideClass)&&(window.document.documentElement.classList.add(this.cssHideClass),e||setTimeout(this.removeAsyncHide(this.cssHideClass),2e3))}showPage(){this.cssHideClass&&this.removeAsyncHide(this.cssHideClass)()}getDeviceType(){function e(){let i=!1;return(function(s){(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(s)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(s.substr(0,4)))&&(i=!0)})(navigator.userAgent||navigator.vendor),i}function t(){let i=!1;return(function(s){(/android|ipad|playbook|silk/i.test(s)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|
43sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(s.substr(0,4)))&&(i=!0)})(navigator.userAgent||navigator.vendor),i}return e()?"mobile":t()?"tablet":"desktop"}removeAsyncHide(e){return()=>{e&&window.document.documentElement.classList.remove(e)}}async getCartState(){try{let e=await this.makeJsonRequest({method:"get",url:`${window.location.origin}/cart.js`});return e===null||(e.note===null&&(e=await this.makeJsonRequest({method:"post",url:`${window.location.origin}/cart/update.js`,data:JSON.stringify({note:""})})),e==null)?null:{token:e.token,total_price:e.total_price,total_discount:e.total_discount,currency:e.currency,items_subtotal_price:e.items_subtotal_price,items:e.items.map(t=>({quantity:t.quantity,variant_id:t.variant_id,key:t.key,price:t.price,final_line_price:t.final_line_price,sku:t.sku,product_id:t.product_id}))}}catch(e){return this.log("Error sending cart info",e),null}}ensureCartAttributesForExistingPriceTests(e){try{if(this.log("Checking visitor assignments for active price tests"),e&&this.state.temporary.previewConfig){const t=this.state.temporary.previewConfig;this.log("Using preview config for merchant:",t.testId);let i="variant";if(t.variants&&t.variants.length>0){const s=t.variants.find(r=>r.id===t.currentVariant);s&&s.isControl&&(i="control")}this.log("Merchant preview - updating hidden inputs:",t.testId,i),this.updatePriceTestHiddenInputs(t.testId,i,!0);return}for(const t of this.state.essential.visitorTests){const i=this.testConfigs.find(o=>o.id===t.testId);if(!i){this.log("Test config not found:",t.testId);continue}const s=i.hypotheses.find(o=>o.id===t.hypothesisId);if(!s||s.type!=="price")continue;const r=s.isControl?"control":"variant";this.log("Updating hidden inputs for price test:",t.testId,r),this.updatePriceTestHiddenInputs(t.testId,r,e)}}catch(t){this.log("Error ensuring cart attributes for existing price tests:",t)}}subscriptionSwapDone=!1;subscriptionHideWrongPlans=null;subscriptionPriceDone=!1;subscriptionUpdateOneTime=null;subscriptionOneTimeDone=!1;swapMap=null;slptValue=null;async subscriptionSwap(){await Ue(this)}async subscriptionPriceChange(){await ze(this)}async subscriptionOneTimePrice(){await We(this)}updatePriceTestHiddenInputs(e,t,i){try{this.cleanupPriceTestObservers();const s=`${e}:${t}:${i?"t":"f"}`,r=T=>{const m=T.getAttribute("data-sl-pid");if(!m)return!0;if(i&&this.state.temporary.previewConfig){const w=this.state.temporary.previewConfig,I=t==="control"?"a":"b",f=w.variants.find(v=>v.label===I);if(!f)return!1;for(const v of f.domSelectors||[]){const g=v.cssSelector.match(/data-sl-attribute-(?:p|cap)="(\d+)"/);if(g){const P=g[1];if(this.log(`Extracted ID from selector: ${P}, comparing to: ${m}`),P===m)return this.log("Product ID match found in preview config:",m,"variant:",f.label),!0}else this.log(`Could not extract ID from selector: ${v.cssSelector}`)}return this.log("No product ID match in preview config for:",m,"variant:",I),!1}const y=this.testConfigs.find(w=>w.id===e);if(!y)return this.log("Test config not found for testId:",e),!1;for(const w of y.hypotheses||[]){for(const I of w.domSelectors||[]){const f=I.cssSelector.match(/data-sl-attribute-(?:p|cap)="(\d+)"/);if(f&&f[1]===m)return this.log("Product ID match found in domSelectors:",m,"for test:",e),!0}if(w.priceData?.variants){for(const I of w.priceData.variants)if(I[0]===m)return this.log("Product ID match found in priceData:",m,"for test:",e),!0}}return this.log("No product ID match for:",m,"in test:",e),!1},o=new Set;let n=!1,l=null;const c=(T,m)=>{if(document.querySelectorAll("[data-sl-attribute-p]").forEach(w=>{if(w instanceof Element&&w.nodeType===Node.ELEMENT_NODE&&w.isConnected&&document.contains(w))try{T.observe(w,{childList:!0,subtree:!0,characterData:!0,characterDataOldValue:!0,attributes:!1})}catch(I){this.log(`Failed to observe element (${m}):`,I)}}),document.body&&document.body.isConnected)try{T.observe(document.body,{childList:!0,subtree:!0,characterData:!0,characterDataOldValue:!0,attributes:!1})}catch(w){this.log(`Failed to observe document.body (${m}):`,w)}},d=(T,m,y,w)=>{const I=T.filter(f=>{const v=f.cssSelector.match(/data-sl-attribute-(?:p|cap)="(\d+)"/);return v&&v[1]===w});this.log(`Applying ${y} DOM selectors, total: ${T.length}, filtered: ${I.length}`),I.length>0&&U(document,{testId:e,hypothesisId:m,selectors:I})},u=(T,m)=>{this.log(`Applying DOM selector changes for product ID: ${T}`),m.disconnect(),n=!0;try{if(i&&this.state.temporary.previewConfig){const y=t==="control"?"a":"b",w=this.state.temporary.previewConfig.variants.find(I=>I.label===y);if(!w?.domSelectors){this.log(`No DOM selectors found for preview variant: ${y}`);return}d(w.domSelectors,w.id,"preview config",T)}else{const y=this.testConfigs.find(I=>I.id===e);if(!y){this.log(`No test config found for testId: ${e}`);return}const w=y.hypotheses.find(I=>t==="control"?I.isControl:!I.isControl);if(!w?.domSelectors){this.log(`No DOM selectors found for assignment: ${t}`);return}d(w.domSelectors,w.id,"live config",T)}}finally{l!==null&&clearTimeout(l),l=window.setTimeout(()=>{n=!1,l=null,c(m,"reconnection"),this.log("Re-established innerHTML observer after DOM changes")}
43,50)}},h=new MutationObserver(T=>{if(!n)for(const m of T){if(m.type!=="childList"&&m.type!=="characterData")continue;let y=m.target;m.type==="characterData"&&(y=m.target.parentElement||m.target.parentNode);let w=y,I=w.getAttribute("data-sl-attribute-p");for(;!I&&w.parentElement;)w=w.parentElement,I=w.getAttribute("data-sl-attribute-p");if(!I)continue;const f=w.innerHTML||w.textContent||"";let v="";m.type==="characterData"&&m.oldValue!==null&&(v=m.oldValue),this.log(`innerHTML changed on element with data-sl-attribute-p="${I}"`),v&&this.log(`Previous content: "${v}"`),this.log(`Current content: "${f}"`),u(I,h)}});c(h,"initial setup"),o.add(h);const p=new MutationObserver(T=>{T.forEach(m=>{m.addedNodes.forEach(y=>{if(y.nodeType===Node.ELEMENT_NODE){const w=y;E(w);const I=w.matches('input[name="properties[_slpt]"]')?[w]:w.querySelectorAll('input[name="properties[_slpt]"]');I.length>0&&this.log(`MutationObserver found ${I.length} new hidden input(s)`),I.forEach(f=>{const v=f.getAttribute("data-sl-pid");if(this.log(`MutationObserver checking new input with data-sl-pid="${v}"`),r(f))f.value!==s&&(f.value=s,this.log("Updated newly added hidden input:",s)),S(f);else{const g=f.getAttribute("data-sl-pid");g&&this.isProductInAnyPriceTest(g)?this.log("Preserving hidden input for product ID '%s' - belongs to a different price test",g):(f.remove(),this.log("Removed newly added non-matching hidden input for product ID:",g))}})}})})});o.add(p);const b=new MutationObserver(T=>{T.forEach(m=>{if(m.type==="attributes"&&m.attributeName==="data-sl-pid"){const y=m.target;if(this.log("AttributeObserver detected data-sl-pid attribute change on:",y.tagName),y.matches('input[name="properties[_slpt]"]')){const w=y,I=m.oldValue,f=w.getAttribute("data-sl-pid");this.log(`data-sl-pid changed from "${I}" to "${f}" - triggering payment placement updates`),r(w)?(w.value!==s&&(w.value=s,this.log("Updated hidden input after data-sl-pid change:",s)),f&&u(f,h),this.log("Re-running payment placement updates after variant change"),E(document.body)):f&&this.isProductInAnyPriceTest(f)?this.log("Preserving hidden input for product ID '%s' - belongs to a different price test",f):(w.remove(),this.log("Removed non-matching hidden input after data-sl-pid change:",f))}}})});o.add(b);const E=T=>{T.tagName==="SHOPIFY-PAYMENT-TERMS"&&(this.log("MutationObserver found new shopify-payment-terms element"),this.updateShopifyPaymentTerms(e,t));const m=T.querySelectorAll("shopify-payment-terms");m.length>0&&(this.log(`MutationObserver found ${m.length} shopify-payment-terms in added node`),this.updateShopifyPaymentTerms(e,t)),T.tagName==="AFTERPAY-PLACEMENT"&&(this.log("MutationObserver found new afterpay-placement element"),this.updateAfterpayPlacements(e,t,"afterpay"));const y=T.querySelectorAll("afterpay-placement");y.length>0&&(this.log(`MutationObserver found ${y.length} afterpay-placement in added node`),this.updateAfterpayPlacements(e,t,"afterpay")),T.tagName==="SQUARE-PLACEMENT"&&(this.log("MutationObserver found new square-placement element"),this.updateAfterpayPlacements(e,t,"square"));const w=T.querySelectorAll("square-placement");w.length>0&&(this.log(`MutationObserver found ${w.length} square-placement in added node`),this.updateAfterpayPlacements(e,t,"square")),T.tagName==="KLARNA-PLACEMENT"&&(this.log("MutationObserver found new klarna-placement element"),this.updateKlarnaPlacements(e,t));const I=T.querySelectorAll("klarna-placement");I.length>0&&(this.log(`MutationObserver found ${I.length} klarna-placement in added node`),this.updateKlarnaPlacements(e,t))},S=T=>{b.observe(T,{attributes:!0,attributeFilter:["data-sl-pid"],attributeOldValue:!0,subtree:!1});const m=T.getAttribute("data-sl-pid");this.log(`Started AttributeObserver on specific input with data-sl-pid="${m}"`)},C=()=>{const T=document.querySelectorAll('input[name="properties[_slpt]"]');this.log(`Found ${T.length} existing hidden inputs to check`),T.forEach(m=>{const y=m.getAttribute("data-sl-pid");this.log(`Checking existing input with data-sl-pid="${y}"`),r(m)?(m.value=s,this.log("Updated existing hidden input:",s),y&&(this.log("Applying initial DOM selector changes for existing product"),u(y,h)),S(m)):y&&this.isProductInAnyPriceTest(y)?this.log("Preserving hidden input for product ID '%s' - belongs to a different price test",
43y):(m.remove(),this.log("Removed non-matching hidden input for product ID:",y))})},_=()=>{document.body?(p.observe(document.body,{childList:!0,subtree:!0}),this.log("Started MutationObserver on document.body"),C(),E(document.body)):document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{document.body&&(p.observe(document.body,{childList:!0,subtree:!0}),this.log("Started MutationObserver after DOMContentLoaded"),C(),E(document.body))}):(this.log("Set timeout on observer"),setTimeout(_,10))};_(),window.__shopliftPriceTestObservers=o,window.__shopliftPriceTestValue=s,this.log("Set up DOM observer for price test hidden inputs")}catch(s){this.log("Error updating price test hidden inputs:",s)}}updateKlarnaPlacements(e,t){this.updatePlacementElements(e,t,"klarna-placement",(i,s)=>{i.setAttribute("data-purchase-amount",s.toString())})}cleanupPriceTestObservers(){const e=window.__shopliftPriceTestObservers;e&&(e.forEach(t=>{t.disconnect()}),e.clear(),this.log("Cleaned up existing price test observers")),delete window.__shopliftPriceTestObservers,delete window.__shopliftPriceTestValue}updateAfterpayPlacements(e,t,i="afterpay"){const s=i==="square"?"square-placement":"afterpay-placement";if(document.querySelectorAll(s).length===0){this.log(`No ${s} elements found on page - early return`);return}this.updatePlacementElements(e,t,s,(o,n)=>{if(i==="afterpay"){const l=(n/100).toFixed(2);o.setAttribute("data-amount",l)}else o.setAttribute("data-amount",n.toString())}),this.log("updateAfterpayPlacements completed")}updatePlacementElements(e,t,i,s){const r=document.querySelectorAll(i);if(r.length===0){this.log(`No ${i} elements found - early return`);return}let o;if(this.state.temporary.isMerchant&&this.state.temporary.previewConfig){const l=t==="control"?"a":"b",c=this.state.temporary.previewConfig.variants.find(d=>d.label===l);if(!c?.domSelectors){this.log(`No variant found for label ${l} in preview config for ${i}`);return}o=c.domSelectors,this.log(`Using preview config for ${i} in merchant mode, variant: ${l}`)}else{const l=this.testConfigs.find(d=>d.id===e);if(!l){this.log(`No testConfig found for id: ${e} - early return`);return}
43const c=l.hypotheses.find(d=>t==="control"?d.isControl:!d.isControl);if(!c?.domSelectors){this.log(`No hypothesis or domSelectors found for assignment: ${t} - early return`);return}o=c.domSelectors}const n=new RegExp(`${this.DATA_SL_ATTRIBUTE_P}=["'](\\d+)["']`);r.forEach(l=>{let c=null;const d=l.parentElement;if(d&&(c=d.querySelector('input[name="properties[_slpt]"]')),c||(c=l.querySelector('input[name="properties[_slpt]"]')),!c){this.log(`No hidden input found for ${i} element`);return}const u=c.getAttribute("data-sl-pid");if(!u){this.log("Hidden input has no data-sl-pid attribute - skipping");return}const h=o.find(S=>{const C=S.cssSelector.match(n);return C&&C[1]===u});if(!h){this.log(`No matching selector found for productId: ${u} - skipping element`);return}const p=h.actions.find(S=>S.scope==="price");if(!p?.value){this.log("No price action or value found - skipping element");return}const b=parseFloat(p.value.replace(/[^0-9.]/g,""));if(Number.isNaN(b)){this.log(`Invalid price "${p.value}" for product ${u} - skipping`);return}const E=Math.round(b*100);s(l,E)}),this.log(`updatePlacementElements completed for ${i}`)}updateShopifyPaymentTerms(e,t){const i=document.querySelectorAll("shopify-payment-terms");if(i.length===0)return;this.log("Store using shopify payments");let s;if(this.state.temporary.isMerchant&&this.state.temporary.previewConfig){const o=t==="control"?"a":"b",n=this.state.temporary.previewConfig.variants.find(l=>l.label===o);if(!n||!n.domSelectors){this.log(`No variant found for label ${o} in preview config`);return}s=n.domSelectors,this.log(`Using preview config for shopify-payment-terms in merchant mode, variant: ${o}`)}else{const o=this.testConfigs.find(l=>l.id===e);if(!o)return;const n=o.hypotheses.find(l=>t==="control"?l.isControl===!0:l.isControl===!1);if(!n||!n.domSelectors)return;s=n.domSelectors}const r=new RegExp(`${this.DATA_SL_ATTRIBUTE_P}=["'](\\d+)["']`);i.forEach(o=>{const n=o.getAttribute("variant-id");if(!n)return;const l=s.find(c=>{const d=c.cssSelector.match(r);return d&&d[1]===n});if(l){const c=l.actions.find(d=>d.scope==="price");if(c&&c.value){const d=o.getAttribute("shopify-meta");if(d)try{const u=JSON.parse(d);if(u.variants&&Array.isArray(u.variants)){const h=u.variants.find(p=>p.id?.toString()===n);if(h){h.full_price=c.value;const p=parseFloat(c.value.replace(/[^0-9.]/g,""));if(h.number_of_payment_terms&&h.number_of_payment_terms>1){const b=p/h.number_of_payment_terms;h.price_per_term=`$${b.toFixed(2)}`}o.setAttribute("shopify-meta",JSON.stringify(u))}}}catch(u){this.log("Error parsing/updating shoplift-meta:",u)}}}})}async makeJsonRequest(e){const t=await this.makeRequest(e);return t===null?null:JSON.parse(await t.text(),F)}async makeRequest(e){const{url:t,method:i,headers:s,data:r,signal:o}=e,n=new Headers;if(s)for(const c in s)n.append(c,s[c]);(!s||!s.Accept)&&n.append("Accept","application/json"),(!s||!s["Content-Type"])&&n.append("Content-Type","application/json"),(this.eventHost.includes("ngrok.io")||this.eventHost.includes("ngrok-free.app"))&&n.append("ngrok-skip-browser-warning","1234");const l=await this.fetch(t,{method:i,headers:n,body:r,signal:o});if(!l.ok){if(l.status===204)return null;if(l.status===422){const c=await l.json();if(typeof c<"u"&&c.isBot)throw new ie}throw new Error(`Error sending shoplift request ${l.status}`)}return l}queueAddVisitorToTest(e,t){if(this.state.essential.visitorTests.some(s=>s.testId===e))return;const i=this.testConfigs.find(s=>s.id===e);if(this.state.essential.visitorTests.push({createdAt:new Date,testId:e,hypothesisId:t.id,isThemeTest:t.type==="theme",themeId:t.themeId,isSaved:!1,isInvalid:!1,shouldSendToGa:!0,testType:t.type,assignedTo:t.isControl?"control":"variant",testTitle:i?.title}),t.type==="price"){const s=t.isControl?"control":"variant";this.log("Price test assignment detected, updating cart attributes:",e,s),this.updatePriceTestHiddenInputs(e,s,!1)}}queueCartUpdate(e){this.queueEvent(new Ce(e))}queuePageView(e){this.queueEvent(new Se(e))}queueEvent(e){!this.state.essential.consentApproved&&this.state.essential.hasConsentInteraction||this.state.analytics.queue.length>10||this.state.analytics.queue.push(e)}legacyGetLocalStorageVisitor(){const e=this.localStorageGet(this.legacySessionKey);if(e)try{return JSON.parse(e,F)}catch{}return null}pruneStaleVisitorTests(){this.state.essential.visitorTests=this.state.essential.visitorTests.filter(e=>this.testConfigs.some(t=>t.id==e.testId)||this.inactiveTestConfigs.filter(t=>this.testIsPaused(t)).some(t=>t.id===e.testId))}pruneStateAndSave(){this.pruneStaleVisitorTests(),this.saveState()}saveState(){this.persistEssentialState(),this.persistAnalyticsState()}loadState(){const e=this.loadAnalyticsState(),t={analytics:e,essential:this.loadEssentialState(e),temporary:this.loadTemporaryState()},i=this.legacyGetLocalStorageVisitor(),s=this.legacyGetCookieVisitor(),r=[i,s].filter(o=>o!==null).sort((o,n)=>+n.storedAt-+o.storedAt)[0];return t.analytics.visitor===null&&r&&({visitorTests:t.essential.visitorTests,...t.analytics.visitor}=r,t.essential.isFirstLoad=!1,t.essential.initialState={createdAt:r.createdAt,referrer:r.referrer,utmCampaign:r.utmCampaign,utmContent:r.utmContent,utmMedium:r.utmMedium,utmSource:r.utmSource,device:r.device},this.deleteCookie("SHOPLIFT"),this.deleteLocalStorage(this.legacySessionKey)),!t.essential.consentApproved&&t.essential.hasConsentInteraction&&this.deleteLocalStorage(this.analyticsSessionKey),t}loadEssentialState(e){const t=this.loadLocalStorage(this.essentialSessionKey),i=this.loadCookie(this.essentialSessionKey),s=this.getInitialState();e.visitor?.device&&(s.device=e.visitor.device);const r={timestamp:new Date,consentApproved:!1,hasConsentInteraction:!1,debugMode:!1,initialState:s,visitorTests:[],isFirstLoad:!0},o=[t,i].filter(n=>n!==null).sort((n,l)=>+l.timestamp-+n.timestamp)[0]??r;return o.initialState||(e.visitor!==null?o.initialState=e.visitor:(o.initialState=s,o.initialState.createdAt=o.timestamp)),o}loadAnalyticsState(){const e=this.loadLocalStorage(this.analyticsSessionKey),t=this.loadCookie(this.analyticsSessionKey),i={timestamp:new Date,visitor:null,queue:[]},s=[e,t].filter(r=>r!==null).sort((r,o)=>+o.timestamp-+r.timestamp)[0]??i;return s.queue.length===0&&e&&e.queue.length>1&&(s.queue=e.queue),s}loadTemporaryState(){const e=this.sessionStorageGet(this.temporarySessionKey),t=e?JSON.parse(e,F):null,i=this.loadCookie(this.temporarySessionKey);return t??i??{isMerchant:!1,timestamp:new Date}}persistEssentialState(){this.log("Persisting essential state"),this.state.essential.isFirstLoad=!1,this.state.essential.timestamp=new Date,this.persistLocalStorageState(this.essentialSessionKey,this.state.essential),this.persist
43CookieState(this.essentialSessionKey,this.state.essential)}persistAnalyticsState(){this.log("Persisting analytics state"),this.state.essential.consentApproved&&(this.state.analytics.timestamp=new Date,this.persistLocalStorageState(this.analyticsSessionKey,this.state.analytics),this.persistCookieState(this.analyticsSessionKey,{...this.state.analytics,queue:[]}))}persistTemporaryState(){this.log("Setting temporary session state"),this.state.temporary.timestamp=new Date,this.sessionStorageSet(this.temporarySessionKey,JSON.stringify(this.state.temporary)),this.persistCookieState(this.temporarySessionKey,this.state.temporary,!0)}loadLocalStorage(e){const t=this.localStorageGet(e);if(t===null)return null;try{return JSON.parse(t,F)}catch{return null}}loadCookie(e){const t=this.getCookie(e);if(t===null)return null;try{return JSON.parse(t,F)}catch{return null}}persistLocalStorageState(e,t){this.localStorageSet(e,JSON.stringify(t))}persistCookieState(e,t,i=!1){const s=JSON.stringify(t),r=i?"":`expires=${new Date(new Date().getTime()+864e5*365).toUTCString()};`;document.cookie=`${e}=${s};domain=.${window.location.hostname};path=/;SameSite=Strict;${r}`}deleteCookie(e){const t=new Date(0).toUTCString();document.cookie=`${e}=;domain=.${window.location.hostname};path=/;expires=${t};`}deleteLocalStorage(e){window.localStorage.removeItem(e)}getChannel(e){return[{"name":"cross-network","test":(v) => new RegExp(".*cross-network.*", "i").test(v.utmCampaign)},{"name":"direct","test":(v) => v.utmSource === "" && v.utmMedium === ""},{"name":"paid-shopping","test":(v) => (new RegExp("^(?:Google|IGShopping|aax-us-east\.amazon-adsystem\.com|aax\.amazon-adsystem\.com|alibaba|alibaba\.com|amazon|amazon\.co\.uk|amazon\.com|apps\.shopify\.com|checkout\.shopify\.com|checkout\.stripe\.com|cr\.shopping\.naver\.com|cr2\.shopping\.naver\.com|ebay|ebay\.co\.uk|ebay\.com|ebay\.com\.au|ebay\.de|etsy|etsy\.com|m\.alibaba\.com|m\.shopping\.naver\.com|mercadolibre|mercadolibre\.com|mercadolibre\.com\.ar|mercadolibre\.com\.mx|message\.alibaba\.com|msearch\.shopping\.naver\.com|nl\.shopping\.net|no\.shopping\.net|offer\.alibaba\.com|one\.walmart\.com|order\.shopping\.yahoo\.co\.jp|partners\.shopify\.com|s3\.amazonaws\.com|se\.shopping\.net|shop\.app|shopify|shopify\.com|shopping\.naver\.com|shopping\.yahoo\.co\.jp|shopping\.yahoo\.com|shopzilla|shopzilla\.com|simplycodes\.com|store\.shopping\.yahoo\.co\.jp|stripe|stripe\.com|uk\.shopping\.net|walmart|walmart\.com)$", "i").test(v.utmSource) || new RegExp("^(.*(([^a-df-z]|^)shop|shopping).*)$", "i").test(v.utmCampaign)) && new RegExp("^(.*cp.*|ppc|retargeting|paid.*)$", "i").test(v.utmMedium)},{"name":"paid-search","test":(v) => new RegExp("^(?:360\.cn|alice|aol|ar\.search\.yahoo\.com|ask|at\.search\.yahoo\.com|au\.search\.yahoo\.com|auone|avg|babylon|baidu|biglobe|biglobe\.co\.jp|biglobe\.ne\.jp|bing|br\.search\.yahoo\.com|ca\.search\.yahoo\.com|centrum\.cz|ch\.search\.yahoo\.com|cl\.search\.yahoo\.com|cn\.bing\.com|cnn|co\.search\.yahoo\.com|comcast|conduit|daum|daum\.net|de\.search\.yahoo\.com|dk\.search\.yahoo\.com|dogpile|dogpile\.com|duckduckgo|ecosia\.org|email\.seznam\.cz|eniro|es\.search\.yahoo\.com|espanol\.search\.yahoo\.com|exalead\.com|excite\.com|fi\.search\.yahoo\.com|firmy\.cz|fr\.search\.yahoo\.com|globo|go\.mail\.ru|google|google-play|hk\.search\.yahoo\.com|id\.search\.yahoo\.com|in\.search\.yahoo\.com|incredimail|it\.search\.yahoo\.com|kvasir|lens\.google\.com|lite\.qwant\.com|lycos|m\.baidu\.com|m\.naver\.com|m\.search\.naver\.com|m\.sogou\.com|mail\.rambler\.ru|mail\.yandex\.ru|malaysia\.search\.yahoo\.com|msn|msn\.com|mx\.search\.yahoo\.com|najdi|naver|naver\.com|news\.google\.com|nl\.search\.yahoo\.com|no\.search\.yahoo\.com|ntp\.msn\.com|nz\.search\.yahoo\.com|onet|onet\.pl|pe\.search\.yahoo\.com|ph\.search\.yahoo\.com|pl\.search\.yahoo\.com|play\.google\.com|qwant|qwant\.com|rakuten|rakuten\.co\.jp|rambler|rambler\.ru|se\.search\.yahoo\.com|search-results|search\.aol\.co\.uk|search\.aol\.com|search\.google\.com|search\.smt\.docomo\.ne\.jp|search\.ukr\.net|secureurl\.ukr\.net|seznam|seznam\.cz|sg\.search\.yahoo\.com|so\.com|sogou|sogou\.com|sp-web\.search\.auone\.jp|startsiden|startsiden\.no|suche\.aol\.de|terra|th\.search\.yahoo\.com|tr\.search\.yahoo\.com|tut\.by|tw\.search\.yahoo\.com|uk\.search\.yahoo\.com|ukr|us\.search\.yahoo\.com|virgilio|vn\.search\.yahoo\.com|wap\.sogou\.com|webmaster\.yandex\.ru|websearch\.rakuten\.co\.jp|yahoo|yahoo\.co\.jp|yahoo\.com|yandex|yandex\.by|yandex\.com|yandex\.com\.tr|yandex\.fr|yandex\.kz|yandex\.ru|yandex\.ua|y
43andex\.uz|zen\.yandex\.ru)$", "i").test(v.utmSource) && new RegExp("^(.*cp.*|ppc|retargeting|paid.*)$", "i").test(v.utmMedium)},{"name":"paid-social","test":(v) => new RegExp("^(?:43things|43things\.com|51\.com|5ch\.net|Hatena|ImageShack|academia\.edu|activerain|activerain\.com|activeworlds|activeworlds\.com|addthis|addthis\.com|airg\.ca|allnurses\.com|allrecipes\.com|alumniclass|alumniclass\.com|ameba\.jp|ameblo\.jp|americantowns|americantowns\.com|amp\.reddit\.com|ancestry\.com|anobii|anobii\.com|answerbag|answerbag\.com|answers\.yahoo\.com|aolanswers|aolanswers\.com|apps\.facebook\.com|ar\.pinterest\.com|artstation\.com|askubuntu|askubuntu\.com|asmallworld\.com|athlinks|athlinks\.com|away\.vk\.com|awe\.sm|b\.hatena\.ne\.jp|baby-gaga|baby-gaga\.com|babyblog\.ru|badoo|badoo\.com|bebo|bebo\.com|beforeitsnews|beforeitsnews\.com|bharatstudent|bharatstudent\.com|biip\.no|biswap\.org|bit\.ly|blackcareernetwork\.com|blackplanet|blackplanet\.com|blip\.fm|blog\.com|blog\.feedspot\.com|blog\.goo\.ne\.jp|blog\.naver\.com|blog\.yahoo\.co\.jp|blogg\.no|bloggang\.com|blogger|blogger\.com|blogher|blogher\.com|bloglines|bloglines\.com|blogs\.com|blogsome|blogsome\.com|blogspot|blogspot\.com|blogster|blogster\.com|blurtit|blurtit\.com|bookmarks\.yahoo\.co\.jp|bookmarks\.yahoo\.com|br\.pinterest\.com|brightkite|brightkite\.com|brizzly|brizzly\.com|business\.facebook\.com|buzzfeed|buzzfeed\.com|buzznet|buzznet\.com|cafe\.naver\.com|cafemom|cafemom\.com|camospace|camospace\.com|canalblog\.com|care\.com|care2|care2\.com|caringbridge\.org|catster|catster\.com|cbnt\.io|cellufun|cellufun\.com|centerblog\.net|chat\.zalo\.me|chegg\.com|chicagonow|chicagonow\.com|chiebukuro\.yahoo\.co\.jp|classmates|classmates\.com|classquest|classquest\.com|co\.pinterest\.com|cocolog-nifty|cocolog-nifty\.com|copainsdavant\.linternaute\.com|couchsurfing\.org|cozycot|cozycot\.com|cross\.tv|crunchyroll|crunchyroll\.com|cyworld|cyworld\.com|cz\.pinterest\.com|d\.hatena\.ne\.jp|dailystrength\.org|deluxe\.com|deviantart|deviantart\.com|dianping|dianping\.com|digg|digg\.com|diigo|diigo\.com|discover\.hubpages\.com|disqus|disqus\.com|dogster|dogster\.com|dol2day|dol2day\.com|doostang|doostang\.com|dopplr|dopplr\.com|douban|douban\.com|draft\.blogger\.com|draugiem\.lv|drugs-forum|drugs-forum\.com|dzone|dzone\.com|edublogs\.org|elftown|elftown\.com|epicurious\.com|everforo\.com|exblog\.jp|extole|extole\.com|facebook|facebook\.com|faceparty|faceparty\.com|fandom\.com|fanpop|fanpop\.com|fark|fark\.com|fb|fb\.me|fc2|fc2\.com|feedspot|feministing|feministing\.com|filmaffinity|filmaffinity\.com|flickr|flickr\.com|flipboard|flipboard\.com|folkdirect|folkdirect\.com|foodservice|foodservice\.com|forums\.androidcentral\.com|forums\.crackberry\.com|forums\.imore\.com|forums\.nexopia\.com|forums\.webosnation\.com|forums\.wpcentral\.com|fotki|fotki\.com|fotolog|fotolog\.com|foursquare|foursquare\.com|free\.facebook\.com|friendfeed|friendfeed\.com|fruehstueckstreff\.org|fubar|fubar\.com|gaiaonline|gaiaonline\.com|gamerdna|gamerdna\.com|gather\.com|geni\.com|getpocket\.com|glassboard|glassboard\.com|glassdoor|glassdoor\.com|godtube|godtube\.com|goldenline\.pl|goldstar|goldstar\.com|goo\.gl|gooblog|goodreads|goodreads\.com|google\+|googlegroups\.com|googleplus|govloop|govloop\.com|gowalla|gowalla\.com|gree\.jp|groups\.google\.com|gulli\.com|gutefrage\.net|habbo|habbo\.com|hi5|hi5\.com|hootsuite|hootsuite\.com|houzz|houzz\.com|hoverspot|hoverspot\.com|hr\.com|hu\.pinterest\.com|hubculture|hubculture\.com|hubpages\.com|hyves\.net|hyves\.nl|ibibo|ibibo\.com|id\.pinterest\.com|identi\.ca|ig|imageshack\.com|imageshack\.us|imvu|imvu\.com|in\.pinterest\.com|insanejournal|insanejournal\.com|instagram|instagram\.com|instapaper|instapaper\.com|internations\.org|interpals\.net|intherooms|intherooms\.com|irc-galleria\.net|is\.gd|italki|italki\.com|jammerdirect|jammerdirect\.com|jappy\.com|jappy\.de|kaboodle\.com|kakao|kakao\.com|kakaocorp\.com|kaneva|kaneva\.com|kin\.naver\.com|l\.facebook\.com|l\.instagram\.com|l\.messenger\.com|last\.fm|librarything|librarything\.com|lifestream\.aol\.com|line|line\.me|linkedin|linkedin\.com|listal|listal\.com|listography|listography\.com|livedoor\.com|livedoorblog|livejournal|livejournal\.com|lm\.facebook\.com|lnkd\.in|m\.blog\.naver\.com|m\.cafe\.naver\.com|m\.facebook\.com|m\.kin\.naver\.com|m\.vk\.com|m\.yelp\.com|mbga\.jp|medium\.com|meetin\.org|meetup|meetup\.com|meinvz\.net|meneame\.net|menuism\.com|messages\.google\.com|messages\.yahoo\.co\.jp|messenger|messenger\.com|mix\.com|mixi\.jp|mobile\.facebook\.com|mocospace|mocospace\.com|mouthshut|mouthshut\.com|movabletype|movabletype\.com|mubi|mubi\.com|my\.o
43pera\.com|myanimelist\.net|myheritage|myheritage\.com|mylife|mylife\.com|mymodernmet|mymodernmet\.com|myspace|myspace\.com|netvibes|netvibes\.com|news\.ycombinator\.com|newsshowcase|nexopia|ngopost\.org|niconico|nicovideo\.jp|nightlifelink|nightlifelink\.com|ning|ning\.com|nl\.pinterest\.com|odnoklassniki\.ru|odnoklassniki\.ua|okwave\.jp|old\.reddit\.com|oneworldgroup\.org|onstartups|onstartups\.com|opendiary|opendiary\.com|oshiete\.goo\.ne\.jp|out\.reddit\.com|over-blog\.com|overblog\.com|paper\.li|partyflock\.nl|photobucket|photobucket\.com|pinboard|pinboard\.in|pingsta|pingsta\.com|pinterest|pinterest\.at|pinterest\.ca|pinterest\.ch|pinterest\.cl|pinterest\.co\.kr|pinterest\.co\.uk|pinterest\.com|pinterest\.com\.au|pinterest\.com\.mx|pinterest\.de|pinterest\.es|pinterest\.fr|pinterest\.it|pinterest\.jp|pinterest\.nz|pinterest\.ph|pinterest\.pt|pinterest\.ru|pinterest\.se|pixiv\.net|pl\.pinterest\.com|playahead\.se|plurk|plurk\.com|plus\.google\.com|plus\.url\.google\.com|pocket\.co|posterous|posterous\.com|pro\.homeadvisor\.com|pulse\.yahoo\.com|qapacity|qapacity\.com|quechup|quechup\.com|quora|quora\.com|qzone\.qq\.com|ravelry|ravelry\.com|reddit|reddit\.com|redux|redux\.com|renren|renren\.com|researchgate\.net|reunion|reunion\.com|reverbnation|reverbnation\.com|rtl\.de|ryze|ryze\.com|salespider|salespider\.com|scoop\.it|screenrant|screenrant\.com|scribd|scribd\.com|scvngr|scvngr\.com|secondlife|secondlife\.com|serverfault|serverfault\.com|shareit|sharethis|sharethis\.com|shvoong\.com|sites\.google\.com|skype|skyrock|skyrock\.com|slashdot\.org|slideshare\.net|smartnews\.com|snapchat|snapchat\.com|social|sociallife\.com\.br|socialvibe|socialvibe\.com|spaces\.live\.com|spoke|spoke\.com|spruz|spruz\.com|ssense\.com|stackapps|stackapps\.com|stackexchange|stackexchange\.com|stackoverflow|stackoverflow\.com|stardoll\.com|stickam|stickam\.com|studivz\.net|suomi24\.fi|superuser|superuser\.com|sweeva|sweeva\.com|t\.co|t\.me|tagged|tagged\.com|taggedmail|taggedmail\.com|talkbiznow|talkbiznow\.com|taringa\.net|techmeme|techmeme\.com|tencent|tencent\.com|tiktok|tiktok\.com|tinyurl|tinyurl\.com|toolbox|toolbox\.com|touch\.facebook\.com|tr\.pinterest\.com|travellerspoint|travellerspoint\.com|tripadvisor|tripadvisor\.com|trombi|trombi\.com|trustpilot|tudou|tudou\.com|tuenti|tuenti\.com|tumblr|tumblr\.com|tweetdeck|tweetdeck\.com|twitter|twitter\.com|twoo\.com|typepad|typepad\.com|unblog\.fr|urbanspoon\.com|ushareit\.com|ushi\.cn|vampirefreaks|vampirefreaks\.com|vampirerave|vampirerave\.com|vg\.no|video\.ibm\.com|vk\.com|vkontakte\.ru|wakoopa|wakoopa\.com|wattpad|wattpad\.com|web\.facebook\.com|web\.skype\.com|webshots|webshots\.com|wechat|wechat\.com|weebly|weebly\.com|weibo|weibo\.com|wer-weiss-was\.de|weread|weread\.com|whatsapp|whatsapp\.com|wiki\.answers\.com|wikihow\.com|wikitravel\.org|woot\.com|wordpress|wordpress\.com|wordpress\.org|xanga|xanga\.com|xing|xing\.com|yahoo-mbga\.jp|yammer|yammer\.com|yelp|yelp\.co\.uk|yelp\.com|youroom\.in|za\.pinterest\.com|zalo|zoo\.gr|zooppa|zooppa\.com)$", "i").test(v.utmSource) && new RegExp("^(.*cp.*|ppc|retargeting|paid.*)$", "i").test(v.utmMedium)},{"name":"paid-video","test":(v) => new RegExp("^(?:blog\.twitch\.tv|crackle|crackle\.com|curiositystream|curiositystream\.com|d\.tube|dailymotion|dailymotion\.com|dashboard\.twitch\.tv|disneyplus|disneyplus\.com|fast\.wistia\.net|help\.hulu\.com|help\.netflix\.com|hulu|hulu\.com|id\.twitch\.tv|iq\.com|iqiyi|iqiyi\.com|jobs\.netflix\.com|justin\.tv|m\.twitch\.tv|m\.youtube\.com|music\.youtube\.com|netflix|netflix\.com|player\.twitch\.tv|player\.vimeo\.com|ted|ted\.com|twitch|twitch\.tv|utreon|utreon\.com|veoh|veoh\.com|viadeo\.journaldunet\.com|vimeo|vimeo\.com|wistia|wistia\.com|youku|youku\.com|youtube|youtube\.com)$", "i").test(v.utmSource) && new RegExp("^(.*cp.*|ppc|retargeting|paid.*)$", "i").test(v.utmMedium)},{"name":"display","test":(v) => new RegExp("^(?:display|banner|expandable|interstitial|cpm)$", "i").test(v.utmMedium)},{"name":"paid-other","test":(v) => new RegExp("^(.*cp.*|ppc|retargeting|paid.*)$", "i").test(v.utmMedium)}
43,{"name":"organic-shopping","test":(v) => new RegExp("^(?:360\.cn|alice|aol|ar\.search\.yahoo\.com|ask|at\.search\.yahoo\.com|au\.search\.yahoo\.com|auone|avg|babylon|baidu|biglobe|biglobe\.co\.jp|biglobe\.ne\.jp|bing|br\.search\.yahoo\.com|ca\.search\.yahoo\.com|centrum\.cz|ch\.search\.yahoo\.com|cl\.search\.yahoo\.com|cn\.bing\.com|cnn|co\.search\.yahoo\.com|comcast|conduit|daum|daum\.net|de\.search\.yahoo\.com|dk\.search\.yahoo\.com|dogpile|dogpile\.com|duckduckgo|ecosia\.org|email\.seznam\.cz|eniro|es\.search\.yahoo\.com|espanol\.search\.yahoo\.com|exalead\.com|excite\.com|fi\.search\.yahoo\.com|firmy\.cz|fr\.search\.yahoo\.com|globo|go\.mail\.ru|google|google-play|hk\.search\.yahoo\.com|id\.search\.yahoo\.com|in\.search\.yahoo\.com|incredimail|it\.search\.yahoo\.com|kvasir|lens\.google\.com|lite\.qwant\.com|lycos|m\.baidu\.com|m\.naver\.com|m\.search\.naver\.com|m\.sogou\.com|mail\.rambler\.ru|mail\.yandex\.ru|malaysia\.search\.yahoo\.com|msn|msn\.com|mx\.search\.yahoo\.com|najdi|naver|naver\.com|news\.google\.com|nl\.search\.yahoo\.com|no\.search\.yahoo\.com|ntp\.msn\.com|nz\.search\.yahoo\.com|onet|onet\.pl|pe\.search\.yahoo\.com|ph\.search\.yahoo\.com|pl\.search\.yahoo\.com|play\.google\.com|qwant|qwant\.com|rakuten|rakuten\.co\.jp|rambler|rambler\.ru|se\.search\.yahoo\.com|search-results|search\.aol\.co\.uk|search\.aol\.com|search\.google\.com|search\.smt\.docomo\.ne\.jp|search\.ukr\.net|secureurl\.ukr\.net|seznam|seznam\.cz|sg\.search\.yahoo\.com|so\.com|sogou|sogou\.com|sp-web\.search\.auone\.jp|startsiden|startsiden\.no|suche\.aol\.de|terra|th\.search\.yahoo\.com|tr\.search\.yahoo\.com|tut\.by|tw\.search\.yahoo\.com|uk\.search\.yahoo\.com|ukr|us\.search\.yahoo\.com|virgilio|vn\.search\.yahoo\.com|wap\.sogou\.com|webmaster\.yandex\.ru|websearch\.rakuten\.co\.jp|yahoo|yahoo\.co\.jp|yahoo\.com|yandex|yandex\.by|yandex\.com|yandex\.com\.tr|yandex\.fr|yandex\.kz|yandex\.ru|yandex\.ua|yandex\.uz|zen\.yandex\.ru)$", "i").test(v.utmSource) || new RegExp("^(.*(([^a-df-z]|^)shop|shopping).*)$", "i").test(v.utmCampaign)},{"name":"organic-social","test":(v) => new RegExp("^(?:43things|43things\.com|51\.com|5ch\.net|Hatena|ImageShack|academia\.edu|activerain|activerain\.com|activeworlds|activeworlds\.com|addthis|addthis\.com|airg\.ca|allnurses\.com|allrecipes\.com|alumniclass|alumniclass\.com|ameba\.jp|ameblo\.jp|americantowns|americantowns\.com|amp\.reddit\.com|ancestry\.com|anobii|anobii\.com|answerbag|answerbag\.com|answers\.yahoo\.com|aolanswers|aolanswers\.com|apps\.facebook\.com|ar\.pinterest\.com|artstation\.com|askubuntu|askubuntu\.com|asmallworld\.com|athlinks|athlinks\.com|away\.vk\.com|awe\.sm|b\.hatena\.ne\.jp|baby-gaga|baby-gaga\.com|babyblog\.ru|badoo|badoo\.com|bebo|bebo\.com|beforeitsnews|beforeitsnews\.com|bharatstudent|bharatstudent\.com|biip\.no|biswap\.org|bit\.ly|blackcareernetwork\.com|blackplanet|blackplanet\.com|blip\.fm|blog\.com|blog\.feedspot\.com|blog\.goo\.ne\.jp|blog\.naver\.com|blog\.yahoo\.co\.jp|blogg\.no|bloggang\.com|blogger|blogger\.com|blogher|blogher\.com|bloglines|bloglines\.com|blogs\.com|blogsome|blogsome\.com|blogspot|blogspot\.com|blogster|blogster\.com|blurtit|blurtit\.com|bookmarks\.yahoo\.co\.jp|bookmarks\.yahoo\.com|br\.pinterest\.com|brightkite|brightkite\.com|brizzly|brizzly\.com|business\.facebook\.com|buzzfeed|buzzfeed\.com|buzznet|buzznet\.com|cafe\.naver\.com|cafemom|cafemom\.com|camospace|camospace\.com|canalblog\.com|care\.com|care2|care2\.com|caringbridge\.org|catster|catster\.com|cbnt\.io|cellufun|cellufun\.com|centerblog\.net|chat\.zalo\.me|chegg\.com|chicagonow|chicagonow\.com|chiebukuro\.yahoo\.co\.jp|classmates|classmates\.com|classquest|classquest\.com|co\.pinterest\.com|cocolog-nifty|cocolog-nifty\.com|copainsdavant\.linternaute\.com|couchsurfing\.org|cozycot|cozycot\.com|cross\.tv|crunchyroll|crunchyroll\.com|cyworld|cyworld\.com|cz\.pinterest\.com|d\.hatena\.ne\.jp|dailystrength\.org|deluxe\.com|deviantart|deviantart\.com|dianping|dianping\.com|digg|digg\.com|diigo|diigo\.com|discover\.hubpages\.com|disqus|disqus\.com|dogster|dogster\.com|dol2day|dol2day\.com|doostang|doostang\.com|dopplr|dopplr\.com|douban|douban\.com|draft\.blogger\.com|draugiem\.lv|drugs-forum|drugs-forum\.com|dzone|dzone\.com|edublogs\.org|elftown|elftown\.com|epicurious\.com|everforo\.com|exblog\.jp|extole|extole\.com|facebook|facebook\.com|faceparty|faceparty\.com|fandom\.com|fanpop|fanpop\.com|fark|fark\.com|fb|fb\.me|fc2|fc2\.com|feedspot|feministing|feministing\.com|filmaffinity|filmaffinity\.com|flickr|flickr\.com|flipboard|flipboard\.com|folkdirect|folkdirect\.com|foodservice|foodservice\.com|forums\.androidcentral\.com|forums\.crackberry\.com|forums\.imore\.com|forums\.nexopia\.com|forums\.webosnation\.com|forums\.wpcentral\.com|fotki|fotki\.com|fotolog|fotolog\.com|foursquare|foursquare\.com|free\.facebook\.com|friendfeed|friendfeed\.com|fruehstueckstreff\.org|fubar|fubar\.com|gaiaonline|gaiaonline\.com|gamerdna|gamerdna\.com|gather\.com|geni\.com|getpocket\.com|glassboard|glassboard\.com|glassdoor|glassdoor\.com|godtube|godtube\.com|goldenline\.pl|goldstar|goldstar\.com|goo\.gl|gooblog|goodreads|goodreads\.com|google\+|googlegroups\.com|googleplus|govloop|govloop\.com|gowalla|gowalla\.com|gree\.jp|groups\.google\.com|gulli\.com|gutefrage\.net|habbo|habbo\.com|hi5|hi5\.com|hootsuite|hootsuite\.com|houzz|houzz\.com|hoverspot|hoverspot\.com|hr\.com|hu\.pinterest\.com|hubculture|hubculture\.com|hubpages\.com|hyves\.net|hyves\.nl|ibibo|ibibo\.com|id\.pinterest\.com|identi\.ca|ig|imageshack\.com|imageshack\.us|imvu|imvu\.com|in\.pinterest\.com|insanejournal|insanejournal\.com|instagram|instagram\.com|instapaper|instapaper\.com|internations\.org|interpals\.net|intherooms|intherooms\.com|irc-galleria\.net|is\.gd|italki|italki\.com|jammerdirect|jammerdirect\.com|jappy\.com|jappy\.de|kaboodle\.com|k
43akao|kakao\.com|kakaocorp\.com|kaneva|kaneva\.com|kin\.naver\.com|l\.facebook\.com|l\.instagram\.com|l\.messenger\.com|last\.fm|librarything|librarything\.com|lifestream\.aol\.com|line|line\.me|linkedin|linkedin\.com|listal|listal\.com|listography|listography\.com|livedoor\.com|livedoorblog|livejournal|livejournal\.com|lm\.facebook\.com|lnkd\.in|m\.blog\.naver\.com|m\.cafe\.naver\.com|m\.facebook\.com|m\.kin\.naver\.com|m\.vk\.com|m\.yelp\.com|mbga\.jp|medium\.com|meetin\.org|meetup|meetup\.com|meinvz\.net|meneame\.net|menuism\.com|messages\.google\.com|messages\.yahoo\.co\.jp|messenger|messenger\.com|mix\.com|mixi\.jp|mobile\.facebook\.com|mocospace|mocospace\.com|mouthshut|mouthshut\.com|movabletype|movabletype\.com|mubi|mubi\.com|my\.opera\.com|myanimelist\.net|myheritage|myheritage\.com|mylife|mylife\.com|mymodernmet|mymodernmet\.com|myspace|myspace\.com|netvibes|netvibes\.com|news\.ycombinator\.com|newsshowcase|nexopia|ngopost\.org|niconico|nicovideo\.jp|nightlifelink|nightlifelink\.com|ning|ning\.com|nl\.pinterest\.com|odnoklassniki\.ru|odnoklassniki\.ua|okwave\.jp|old\.reddit\.com|oneworldgroup\.org|onstartups|onstartups\.com|opendiary|opendiary\.com|oshiete\.goo\.ne\.jp|out\.reddit\.com|over-blog\.com|overblog\.com|paper\.li|partyflock\.nl|photobucket|photobucket\.com|pinboard|pinboard\.in|pingsta|pingsta\.com|pinterest|pinterest\.at|pinterest\.ca|pinterest\.ch|pinterest\.cl|pinterest\.co\.kr|pinterest\.co\.uk|pinterest\.com|pinterest\.com\.au|pinterest\.com\.mx|pinterest\.de|pinterest\.es|pinterest\.fr|pinterest\.it|pinterest\.jp|pinterest\.nz|pinterest\.ph|pinterest\.pt|pinterest\.ru|pinterest\.se|pixiv\.net|pl\.pinterest\.com|playahead\.se|plurk|plurk\.com|plus\.google\.com|plus\.url\.google\.com|pocket\.co|posterous|posterous\.com|pro\.homeadvisor\.com|pulse\.yahoo\.com|qapacity|qapacity\.com|quechup|quechup\.com|quora|quora\.com|qzone\.qq\.com|ravelry|ravelry\.com|reddit|reddit\.com|redux|redux\.com|renren|renren\.com|researchgate\.net|reunion|reunion\.com|reverbnation|reverbnation\.com|rtl\.de|ryze|ryze\.com|salespider|salespider\.com|scoop\.it|screenrant|screenrant\.com|scribd|scribd\.com|scvngr|scvngr\.com|secondlife|secondlife\.com|serverfault|serverfault\.com|shareit|sharethis|sharethis\.com|shvoong\.com|sites\.google\.com|skype|skyrock|skyrock\.com|slashdot\.org|slideshare\.net|smartnews\.com|snapchat|snapchat\.com|social|sociallife\.com\.br|socialvibe|socialvibe\.com|spaces\.live\.com|spoke|spoke\.com|spruz|spruz\.com|ssense\.com|stackapps|stackapps\.com|stackexchange|stackexchange\.com|stackoverflow|stackoverflow\.com|stardoll\.com|stickam|stickam\.com|studivz\.net|suomi24\.fi|superuser|superuser\.com|sweeva|sweeva\.com|t\.co|t\.me|tagged|tagged\.com|taggedmail|taggedmail\.com|talkbiznow|talkbiznow\.com|taringa\.net|techmeme|techmeme\.com|tencent|tencent\.com|tiktok|tiktok\.com|tinyurl|tinyurl\.com|toolbox|toolbox\.com|touch\.facebook\.com|tr\.pinterest\.com|travellerspoint|travellerspoint\.com|tripadvisor|tripadvisor\.com|trombi|trombi\.com|trustpilot|tudou|tudou\.com|tuenti|tuenti\.com|tumblr|tumblr\.com|tweetdeck|tweetdeck\.com|twitter|twitter\.com|twoo\.com|typepad|typepad\.com|unblog\.fr|urbanspoon\.com|ushareit\.com|ushi\.cn|vampirefreaks|vampirefreaks\.com|vampirerave|vampirerave\.com|vg\.no|video\.ibm\.com|vk\.com|vkontakte\.ru|wakoopa|wakoopa\.com|wattpad|wattpad\.com|web\.facebook\.com|web\.skype\.com|webshots|webshots\.com|wechat|wechat\.com|weebly|weebly\.com|weibo|weibo\.com|wer-weiss-was\.de|weread|weread\.com|whatsapp|whatsapp\.com|wiki\.answers\.com|wikihow\.com|wikitravel\.org|woot\.com|wordpress|wordpress\.com|wordpress\.org|xanga|xanga\.com|xing|xing\.com|yahoo-mbga\.jp|yammer|yammer\.com|yelp|yelp\.co\.uk|yelp\.com|youroom\.in|za\.pinterest\.com|zalo|zoo\.gr|zooppa|zooppa\.com)$", "i").test(v.utmSource) || new RegExp("^(?:social|social-network|social-media|sm|social network|social media)$", "i").test(v.utmMedium)},{"name":"organic-video","test":(v) => new RegExp("^(?:blog\.twitch\.tv|crackle|crackle\.com|curiositystream|curiositystream\.com|d\.tube|dailymotion|dailymotion\.com|dashboard\.twitch\.tv|disneyplus|disneyplus\.com|fast\.wistia\.net|help\.hulu\.com|help\.netflix\.com|hulu|hulu\.com|id\.twitch\.tv|iq\.com|iqiyi|iqiyi\.com|jobs\.netflix\.com|justin\.tv|m\.twitch\.tv|m\.youtube\.com|music\.youtube\.com|netflix|netflix\.com|player\.twitch\.tv|player\.vimeo\.com|ted|ted\.com|twitch|twitch\.tv|utreon|utreon\.com|veoh|veoh\.com|viadeo\.journaldunet\.com|vimeo|vimeo\.com|wistia|wistia\.com|youku|youku\.com|youtube|youtube\.com)$", "i").test(v.utmSource) || new RegExp("^(.*video.*)$", "i").test(v.utmMedium)},{"name":"organic-search","test":(v) => new RegExp("^(?:360\.cn|alice|aol|ar\.search\.yahoo\.com|ask|at\.search\.yahoo\.com|au\.search\.yahoo\.com|auone|avg|babylon|baidu|biglobe|biglobe\.co\.jp|biglobe\.ne\.jp|bing|br\.search\.yahoo\.com|ca\.search\.yahoo\.com|centrum\.cz|ch\.search\.yahoo\.com|cl\.search\.yahoo\.com|cn\.bing\.com|cnn|co\.search\.yahoo\.com|comcast|conduit|daum|daum\.net|de\.search\.yahoo\.com|dk\.search\.yahoo\.com|dogpile|dogpile\.com|duckduckgo|ecosia\.org|email\.seznam\.cz|eniro|es\.search\.yahoo\.com|espanol\.search\.yahoo\.com|exalead\.com|excite\.com|fi\.search\.yahoo\.com|firmy\.cz|fr\.search\.yahoo\.com|globo|go\.mail\.ru|google|google-play|hk\.search\.yahoo\.com|id\.search\.yahoo\.com|in\.search\.yahoo\.com|incredimail|it\.search\.yahoo\.com|kvasir|lens\.google\.com|lite\.qwant\.com|lycos|m\.baidu\.com|m\.naver\.com|m\.search\.naver\.com|m\.sogou\.com|mail\.rambler\.ru|mail\.yandex\.ru|malaysia\.search\.yahoo\.com|msn|msn\.com|mx\.search\.yahoo\.com|najdi|naver|naver\.com|news\.google\.com|nl\.search\.yahoo\.com|no\.search\.yahoo\.com|ntp\.msn\.com|nz\.search\.yahoo\.com|onet|onet\.pl|pe\.search\.yahoo\.com|ph\.search\.yahoo\.com|pl\.search\.yahoo\.com|play\.google\.com|qwant|qwant\.com|rakuten|rakuten\.co\.jp|rambler|rambler\.ru|se\.search\.yahoo\.com|search-results|search\.aol\.co\.uk|search\.aol\.com|search\.google\.com|search\.smt\.docomo\.ne\.jp|search\.ukr\.net|secureurl\.ukr\.net|seznam|seznam\.cz|sg\.search\.yahoo\.com|so\.com|sogou|sogou\.com|sp-web\.search\.auone\.jp|startsiden|startsiden\.no|suche\.aol\.de|terra|th\.search\.yahoo\.com|tr\.search\.yahoo\.com|tut\.by|tw\.search\.yahoo\.com|uk\.search\.yahoo\.com|ukr|us\.search\.yahoo\.com|virgilio|vn\.search\.yahoo\.com|wap\.sogou\.com|webmaster\.yandex\.ru|websearch\.rakuten\.co\.jp|yahoo|yahoo\.co\.jp|yahoo\.com|yandex|yandex\.by|yandex\.com|yandex\.com\.tr|yandex\.fr|yandex\.kz|yandex\.ru|yandex\.ua|y
43andex\.uz|zen\.yandex\.ru)$", "i").test(v.utmSource) || v.utmMedium.toLowerCase() === "organic"},{"name":"referral","test":(v) => new RegExp("^(?:referral|app|link)$", "i").test(v.utmMedium)},{"name":"email","test":(v) => new RegExp("^(?:email|e-mail|e_mail|e mail)$", "i").test(v.utmMedium) || new RegExp("^(?:email|e-mail|e_mail|e mail)$", "i").test(v.utmSource)},{"name":"affiliate","test":(v) => v.utmMedium.toLowerCase() === "affiliate"},{"name":"audio","test":(v) => v.utmMedium.toLowerCase() === "audio"},{"name":"sms","test":(v) => v.utmSource.toLowerCase() === "sms" || v.utmMedium.toLowerCase() === "sms"},{"name":"mobile-push-notification","test":(v) => v.utmSource.toLowerCase() === "firebase" || new RegExp("(?:.*mobile.*|.*notification.*|push$)", "i").test(v.utmMedium)}].find(i=>i.test(e))?.name??"other"}getShopifyAnalyticsId(){const e=this.getCookie("_shopify_y");if(e)return e;try{const t=this.localStorageGet("Shoplift_ClientId");if(t)return t}catch{}return null}legacyGetCookieVisitor(){const e=this.getCookie("SHOPLIFT");return e===null?null:JSON.parse(e,F)}getCookie(e){const t=this.cookie.split("; ").filter(i=>i.split("=").at(0)===e).at(0);return t===void 0?null:t.split("=").slice(1).join("=")}monitorConsentChange(){document.addEventListener("visitorConsentCollected",e=>{(async()=>await this.onConsentChange(e.detail.analyticsAllowed,!0))()}),document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>this.loadShopifyConsentApiWithRetry()):this.loadShopifyConsentApiWithRetry()}loadShopifyConsentApiWithRetry(){let e=0;const t=()=>{this.loadShopifyConsentApi()||e++<10&&window.setTimeout(t,100)};t()}loadShopifyConsentApi(){if(window.Shopify){this.log("Loading Shopify features");const e=async()=>{if(!window.Shopify){this.log("Shopify object missing... suddenly?");return}if(window.Shopify.customerPrivacy===void 0){this.log("Shopify CustomerPrivacy api still missing, trying again in 1000ms"),t=window.setTimeout(()=>{(async()=>await e())()},1e3);return}if(this.geoViaShopify){const s=window.Shopify.customerPrivacy.getRegion?.();this.resolvedRegion=typeof s=="string"?s.replace(/-/g,""):""}const i=window.Shopify.customerPrivacy.getTrackingConsent();await this.onConsentChange(window.Shopify.customerPrivacy.analyticsProcessingAllowed(),i==="yes")};let t=window.setTimeout(()=>{(async()=>await e())()},5e3);return window.Shopify.loadFeatures([{name:"consent-tracking-api",version:"0.1"}],i=>{(async()=>{if(window.clearTimeout(t),i){this.log("Error loading consent tracking",i);return}await e()})()}),!0}return!1}async onConsentChange(e,t){try{if(this.log("Consent change detected",e,t),this.state.essential.consentApproved=e,this.state.essential.hasConsentInteraction=t,!this.state.essential.consentApproved){this.state.essential.hasConsentInteraction&&(this.state.analytics.queue.length=0),this.saveState();return}this.cookie=document.cookie,this.shopifyAnalyticsId=this.getShopifyAnalyticsId(),this.saveState(),await this.syncAllEvents()}catch(i){this.log("Error syncing on consent change",i)}}isThemePreview(){return isThemePreview||themeRole!=="main"}isAppProxyPath(){const e=["/apps/","/tools/","/a/"],t=window.location.pathname;return e.some(i=>t.startsWith(i))}clearThemeBar(e,t,i){const s=structuredClone(i);this.log("Looking for theme bar"),this.waitForElement(null,"body").then(r=>this.waitForElement(r,"#preview-bar-iframe, #PBarNextFrameWrapper").then(o=>(this.log("Found theme bar"),t&&(this.log("Removing theme bar"),o.remove()),e?this.makeRequest({url:`${this.eventHost}/api/v0/logs`,method:"post",data:JSON.stringify({...this.debugState(),stateAtEvaluation:s},ee)}):Promise.resolve(null)))).catch(r=>console.error(r))}waitForElement(e,t){return new Promise(i=>{const s=document.querySelector(t);if(s){i(s);return}const r=new MutationObserver(o=>{const n=document.querySelector(t);if(n){r.disconnect(),i(n);return}});r.observe(e??document.documentElement,{childList:!0})})}setDebug(e){this.state.essential.debugMode=e,this.saveState()}log(e,...t){let i=0;const s=e.replace(/%[sdoOfF]/g,r=>{if(i>=t.length)return r;const o=t[i++];return r==="%o"||r==="%O"?JSON.stringify(o):String(o)});this.logHistory.push(`[${new Date().toISOString()}][SL] ${s}`),!(!this.state.essential.debugMode&&!this.shopliftDebug)&&console.debug(`[SL] ${e}`,...t)}debugState(){return{state:this.state,storage:{essential:this.loadLocalStorage(this.essentialSessionKey),analytics:this.loadLocalStorage(this.analyticsSessionKey)},params:{shop:this.shop,host:this.host,eventHost:this.eventHost,cssHideClass:this.cssHideClass,testConfigs:this.testConfigs,inactiveTestConfigs:this.inactiveTestConfigs,sendPageView:this.sendPageView,isShopifyMerchantCookie
43:this.getCookie("is_shopify_merchant"),themeId,url:window.location.href,isThemePreview,themeRole,gaConfig:this.gaConfig},logHistory:this.logHistory}}createViewportObserver(e,t={}){const{threshold:i=this.VIEWPORT_TRACK_THRESHOLD,triggerOnce:s=!0}=t,r=new Set;return new IntersectionObserver(o=>{o.forEach(n=>{if(n.isIntersecting&&!r.has(n.target)){const l=n.target,c=l.getAttribute(this.DATA_SL_TEST_ID);c&&(e(c,l),s&&r.add(l))}})},{threshold:i})}applyChangesWithViewport(e,t,i,s){const r=t.selectorsForViewportTracking??t.selectors,o=n=>{if(this.state.essential.visitorTests.some(h=>h.testId===n)||this.activeViewportObservers.has(n))return;const l=[];if(r.forEach(h=>{e.querySelectorAll(h.cssSelector).forEach(b=>l.push(b))}),l.length===0)return;let c=!1;const d=()=>{c||(c=!0,i(n),u.disconnect(),this.activeViewportObservers.delete(n))},u=this.createViewportObserver(()=>{d()},{triggerOnce:!0,...s});this.activeViewportObservers.set(n,u),this.log(`Created viewport observer for test ${n}, observing ${l.length} elements`),l.forEach(h=>{h.setAttribute(this.DATA_SL_TEST_ID,String(n)),u.observe(h)}),setTimeout(()=>{c||l.forEach(h=>{const p=h.getBoundingClientRect(),b=s?.threshold??this.VIEWPORT_TRACK_THRESHOLD,E=Math.min(p.bottom,window.innerHeight)-Math.max(p.top,0),S=Math.min(p.right,window.innerWidth)-Math.max(p.left,0);p.top<window.innerHeight&&p.bottom>0&&p.left<window.innerWidth&&p.right>0&&E>0&&S>0&&E>=p.height*b&&(this.log(`Price element already visible in viewport for test ${n}:`,h),d())})},100)};t.selectors.length>0&&U(e,t,()=>{}),Te(e,{testId:t.testId,hypothesisId:t.hypothesisId,selectors:r},n=>{o(n)})}applyPriceTestWithMapLookup(e,t,i,s){if(!t.priceData){this.log("No price data for hypothesis '%s'",t.id);return}this.log("Hypothesis '%s' isControl=%s, priceData has %d variants",t.id,t.isControl,t.priceData.variants.length);const r=t.priceData.variants.slice(0,3);for(const[S,C,_]of r)this.log(" Sample priceData: variant=%s, price=%d, compareAt=%d",S,C,_);const o=j(t.priceData),n=new Set;for(const S of i)if(S.priceData)for(const[C]of S.priceData.variants)n.add(C);this.log("Price test Map lookup: %d products in hypothesis, %d total products to track",o.size,n.size);const l=t.priceData,c=new WeakSet;let d=!1;const u="[data-sl-attribute-p], [data-sl-attribute-cap], [data-sl-attribute-discount]",h=S=>{if(c.has(S))return;const C=S.getAttribute("data-sl-attribute-p"),_=S.getAttribute("data-sl-attribute-cap"),T=S.getAttribute("data-sl-attribute-discount"),m=C||_||T;if(!m||!n.has(m))return;c.add(S);const y=o.get(m);y&&(this.log("Applying price for product %s: %d cents (compare at: %d cents)",m,y.priceInCents,y.compareAtPriceInCents),Le(S,m,y,l),this.log("Applied price to element for product %s",m)),!d&&!this.state.essential.visitorTests.some(w=>w.testId===e)&&(S.setAttribute(this.DATA_SL_TEST_ID,String(e)),this.setupElementViewportTracking(S,e,()=>{d||(d=!0,s(e))}))},p=()=>{const S=document.querySelectorAll(u);this.log("Scanning for price elements, found: %d",S.length),S.forEach(h)},b=new MutationObserver(S=>{for(const C of S)C.type==="childList"&&C.addedNodes.forEach(_=>{if(_.nodeType===Node.ELEMENT_NODE){const T=_;(T.hasAttribute("data-sl-attribute-p")||T.hasAttribute("data-sl-attribute-cap")||T.hasAttribute("data-sl-attribute-discount"))&&h(T),T.querySelectorAll(u).forEach(h)}}),C.type==="attributes"&&C.target instanceof Element&&h(C.target)}),E=document.body||document.documentElement;b.observe(E,{childList:!0,subtree:!0,attributes:!0,attributeFilter:["data-sl-attribute-p","data-sl-attribute-cap","data-sl-attribute-discount"]}),this.log("MutationObserver started for price elements"),p(),document.readyState==="loading"&&document.addEventListener("DOMContentLoaded",()=>{this.log("DOMContentLoaded - rescanning for price elements"),p()}),setTimeout(()=>{this.log("Delayed rescan for price elements"),p()},100),setTimeout(()=>{this.log("Final rescan for price elements"),p()},500)}setupElementViewportTracking(e,t,i){const s=this.VIEWPORT_TRACK_THRESHOLD,r=e.getBoundingClientRect(),o=Math.min(r.bottom,window.innerHeight)-Math.max(r.top,0),n=Math.min(r.right,window.innerWidth)-Math.max(r.left,0);if(r.top<window.innerHeight&&r.bottom>0&&r.left<window.innerWidth&&r.right>0&&o>0&&n>0&&o>=r.height*s){this.log("Price element already visible for test %s",t),i();return}const c=new IntersectionObserver(d=>{for(const u of d)if(u.isIntersecting&&u.intersectionRatio>=s){this.log("Price element entered viewport for test %s",t),c.disconnect(),i();break}},{threshold:s});c.observe(e)}debug(){const e=this.debugState();console.log(JSON.stringify(e,ee,2))}}(async function(){window.shopliftInstance||(window.shopliftInstance=new Ze("revitin.myshopify.com","https://app.shoplift.ai","https://events.shoplift.ai",false,false,false,{"sendEvents":false,"mode":"gtag"},false,false,1000,[],[{"id":"019e64e9-ad77-7cf4-a909-f8c4d75ff6ca","bayesianRevision":5,"status":"cancelled","hypotheses":[{"id":"019e64e6-57b6-73d6-86b0-8faa336f3aa3","type":"theme","themeId":153996034186,"affix":"","isControl":true,"redirectPath":null},{"id":"019e64e8-705c-7c99-ac18-a4ed8c34775a","type":"theme","themeId":154185007242,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"2e9c5625-ec4d-456a-934f-31b40c7d7d44","bayesianRevision":3,"status":"cancelled","hypotheses":[{"id":"6fe99f17-afb1-4a4
436-b8ff-4cb218a0c561","type":"theme","themeId":142784397450,"affix":"","isControl":true,"redirectPath":null},{"id":"19af5f1d-8113-47e8-914e-a26ec8cd002a","type":"theme","themeId":143245672586,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"019beb7e-cb56-766e-9f1d-fcc359034aa6","bayesianRevision":5,"status":"cancelled","hypotheses":[{"id":"019beb7d-26ac-7b79-8f84-de017773cca2","type":"theme","themeId":149199421578,"affix":"","isControl":true,"redirectPath":null},{"id":"019beb7d-4ef0-7274-a5ee-16b90c94434e","type":"theme","themeId":150987178122,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"019b028d-1cdf-71bd-b451-0eed4ef409b8","bayesianRevision":5,"status":"cancelled","hypotheses":[{"id":"019b028b-c0dd-7689-a159-d038d73b9c7a","type":"theme","themeId":149199421578,"affix":"","isControl":true,"redirectPath":null},{"id":"019b028c-1fbf-77b4-a95e-1118c0568c06","type":"theme","themeId":149195653258,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"5524dab4-f662-4fdf-bad4-1f8993b0fbdd","bayesianRevision":3,"status":"cancelled","hypotheses":[{"id":"7f23efa0-c3b9-4d8e-bc8d-ce367e38cb19","type":"theme","themeId":142784397450,"affix":"","isControl":true,"redirectPath":null},{"id":"acb75071-4e66-494a-b067-0659764a3b4f","type":"theme","themeId":143254388874,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"019c8605-1b2e-784a-85b6-cbbbdac5eb0e","bayesianRevision":5,"status":"cancelled","hypotheses":[{"id":"019c806d-cfae-712a-bc57-c77fb853df85","type":"theme","themeId":151416242314,"affix":"","isControl":true,"redirectPath":null},{"id":"019c8604-be84-7a73-af35-ce1cc8fd2205","type":"theme","themeId":151890460810,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"01c5c788-303f-4467-8dc9-bfafd3155d95","bayesianRevision":4,"status":"cancelled","hypotheses":[{"id":"58615777-8062-456c-881b-204b3c835c99","type":"theme","themeId":142784397450,"affix":"","isControl":true,"redirectPath":null},{"id":"f284de3b-eb8e-4c3f-8321-e077e0374b13","type":"theme","themeId":144210133130,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"564b21f9-c88f-4af2-a688-ebd7b5127b33","bayesianRevision":4,"status":"cancelled","hypotheses":[{"id":"9d92bd30-8af2-43c1-9eab-31a0e2a427c9","type":"theme","themeId":142784397450,"affix":"","isControl":true,"redirectPath":null},{"id":"11c6ff46-c713-4196-a3ca-032dcbab6db0","type":"theme","themeId":143587246218,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"c89f76bc-0224-41e8-a078-918b1c65545b","bayesianRevision":4,"status":"cancelled","hypotheses":[{"id":"230e109e-040e-4923-9a26-24b022b5d946","type":"theme","themeId":144790487178,"affix":"","isControl":true,"redirectPath":null},{"id":"ff165228-e2fe-4037-b014-585f7f5cf86f","type":"theme","themeId":145298063498,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"4c50d46e-082c-4449-ae34-3e09724542ca","bayesianRevision":4,"status":"cancelled","hypotheses":[{"id":"70e25a68-b08d-4019-b4d3-00aefce14946","type":"theme","themeId":144790487178,"affix":"","isControl":true,"redirectPath":null},{"id":"6ffe7a37-37b0-4f8c-9306-9fff0d599d2c","type":"theme","themeId":145180655754,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"631e1f7b-be13-4500-8c37-cf2de0ec78c4","bayesianRevision":4,"status":"cancelled","hypotheses":[{"id":"4a18aa00-7c48-4f0c-b6c4-4e3e11038948","type":"theme","themeId":146684379274,"affix":"","isControl":true,"redirectPath":null},{"id":"e63193e8-0408-4cd6-a005-27f6de6a1e4c","type":"theme","themeId":146649415818,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"8f52e54d-d000-49e2-9000-d68f4f143e2d","bayesianRevision":4,"status":"cancelled","hypotheses":[{"id":"822ae8d0-27cc-4aea-a54f-d22f43bda408","type":"theme","themeId":144790487178,"affix":"","isControl":true,"redirectPath":null},{"id":"5c36149a-6035-432c-8055-6cb3ff0dec91","type":"theme","themeId":145512104074,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false}
43,{"id":"1a7d037a-961e-42a1-b86e-acc6122bae21","bayesianRevision":4,"status":"cancelled","hypotheses":[{"id":"95b400ec-b013-4fca-84b9-4faceb97bb3c","type":"theme","themeId":144790487178,"affix":"","isControl":true,"redirectPath":null},{"id":"ec79c7ef-0cc0-459c-85a7-29c14dd43805","type":"theme","themeId":145483628682,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"c7d79f11-63bb-4c56-9803-8e3cc1b9e376","bayesianRevision":4,"status":"cancelled","hypotheses":[{"id":"37b5cf95-c01f-48da-a9b8-8fac90c099f2","type":"theme","themeId":146684379274,"affix":"","isControl":true,"redirectPath":null},{"id":"6cabf295-0cb5-4e7c-b5b9-9b50ac9d8383","type":"theme","themeId":146364137610,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"3ad08a9f-4126-47bd-8259-d659dfa0c5d0","bayesianRevision":4,"status":"cancelled","hypotheses":[{"id":"bf83841a-f86d-46a3-a0ee-15ccc13ce767","type":"theme","themeId":146649415818,"affix":"","isControl":true,"redirectPath":null},{"id":"e14ae338-b593-42e9-ab99-badaa000b573","type":"theme","themeId":146809356426,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"019aa715-4316-7ea8-a024-0667ec13e1f9","bayesianRevision":4,"status":"cancelled","hypotheses":[{"id":"019aa713-49b3-72a3-aecd-fe2e45ce3905","type":"theme","themeId":149060321418,"affix":"","isControl":true,"redirectPath":null},{"id":"019aa713-63ff-73ea-9d81-a3b1ce6f27fd","type":"theme","themeId":148999635082,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"019e64ee-d0a5-7077-9d6c-dc5f255c2a5b","bayesianRevision":5,"status":"cancelled","hypotheses":[{"id":"019e64ed-c06e-7e37-90ea-05b30e0f1da6","type":"theme","themeId":153996034186,"affix":"","isControl":true,"redirectPath":null},{"id":"019e64ee-007b-7601-a160-3c4597afb609","type":"theme","themeId":154185040010,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"019aa716-5403-73df-ade6-14273ad1a69c","bayesianRevision":4,"status":"cancelled","hypotheses":[{"id":"019aa715-712f-7cd4-94b9-f708b554a4ed","type":"theme","themeId":149060321418,"affix":"","isControl":true,"redirectPath":null},{"id":"019aa715-8cef-7e37-93a5-1b83fa66f171","type":"theme","themeId":148959232138,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false},{"id":"019ef4e5-07ef-7d8e-a04c-7db4753a9faa","bayesianRevision":5,"status":"cancelled","hypotheses":[{"id":"019ef4e3-fea1-7f8b-ae63-3810652dc48a","type":"theme","themeId":153996034186,"affix":"","isControl":true,"redirectPath":null},{"id":"019ef4e4-3117-7f62-ae74-dedc7fd71d10","type":"theme","themeId":155127873674,"affix":"","isControl":false,"redirectPath":null}],"ignoreTestViewParameterEnforcement":false}],null,false),await window.shopliftInstance.init())})();async function Qe(a,e,t,i){const s=Be({log:i});if(t)return i("[SUB-PREVIEW] A side â no overlay applied; widget renders naturally"),s;const r=a.widget.widgetType,o=e?j(e):null;let n=W(e),l=J(a,n),c=l.discountMap,d=l.maxDiscount;function u(){const f=W(e);f!==n&&(n=f,l=J(a,n),c=l.discountMap,d=l.maxDiscount,i(`[SUB-PREVIEW] scope refreshed currentProductId=${n??"n/a"}, maxDiscount=${d}`))}i(`[SUB-PREVIEW] side=B, currentProductId=${n??"n/a"}, maxDiscount=${d}`);function h(f){if(!e||!o)return null;const v=Z(o),g=v?o.get(v):void 0;return g?{formattedVariantPrice:G(g.priceInCents,e),formattedDiscounted:G(g.priceInCents*(1-f/100),e)}:null}function p(f){const v=Y(a,f);if(!v)return d;const g=D(a,"subscriptionInput"),P=g.length?g[0].selector:'input[name="rc_plan"]',A=v.querySelector(`${P}:checked`);if(A){const k=c[A.value];if(k!==void 0)return k}return d}function b(f){const v=D(a,"subscriptionDiscount");for(const g of v)if(g.selector.includes("badge")||g.selector.includes("__badge")){const P=f.querySelector(g.selector);P?.textContent&&!P.textContent.includes(`${d}%`)&&$(P,A=>N(A,d))}}function E(f,v){const g=h(v);if(!g)return;const P=D(a,"subscriptionCompareAt");for(const A of P){const k=f.querySelector(A.selector)||f.querySelector(`[part~="${A.selector}"]`);k?.textContent&&!k.textContent.includes(g.formattedVariantPrice)&&$(k,x=>/\d/.test(x)?g.formattedVariantPrice:x)}}function S(f,v){const g=h(v);if(!g)return;const P=D(a,"subscriptionPrice");for(const A of P){const k=f.querySelector(A.selector)||f.querySelector(`[part~="${A.selector}"]`);k?.textContent&&!k.textContent.includes(g.formattedDiscounted)&&$(k,x=>/\d/.test(x)?g.formattedDiscounted:x)}}function C(f){const v=D(a,"subscriptionInput"),g=v.length?v[0].selector:'input[name="rc_plan"]',P=D(a,"subscriptionPlanDiscount"),A=P.length?P[0].selector:".rc-plans-button__discount";for(const k of Array.from(f.querySelectorAll("label"))){const x=k.querySelector(g),R=k.querySelector(A);if(x&&R?.textContent){const O=c[x.value];if(O!==void 0){const V=R.textContent.match(/[\d.]+%/)?.[0];V&&V!==`${O}%`&&$(R,L=>N(L,O))}}}}function _(f){const v=f.querySelector("select");if(v)for(const g of Array.from(v.options)){const P=c[g.value];if(P!==void 0&&g.textContent){const A=g.textContent.match(/[\d.]+%/)?.[0];A&&A!==`${P}%`&&(g.textContent=N(g.textContent,P))}}}function T(f){const v=D(a,"onetimePrice");if(!v.length||!e||!o)return;const g=Z(o),P=g?o.get(g):void 0;if(!P)return;const A=G(P.priceInCents,e),k=D(a,"onetimeContainer"),x=k.length?k[0].selector:'[part~="rc-purchase-option__onetime"]',R=f.querySelector(x);if(R)for(const O of v){const V=R.querySelector(`[part~="${O.selector}"]`);V?.textContent&&!V.textContent.includes(A)&&$(V,L=>/\d/.test(L)?A:L)}}function m(f,v){const P=D(a,"subscriptionDiscount").filter(A=>A.selector.includes("benefit")||A.selector==="rc-benefits");for(const A of P){const k=f.querySelector(A.selector);if(k?.shadowRoot){for(const x of Array.from(k.shadowRoot.querySelectorAll("li")))if(x.textContent?.includes("Save")){const R=x.textContent.match(/[\d.]+%/)?.[0];R&&R!==`${v}%`&&$(x,O=>N(O,v))}}}}let y=!1;function w(){if(!y){y=!0;try{u();const f=B(a);if(!f)return;const v=p(f);b(f),E(f,v),S(f,v),T(f);const g=Y(a,f);g&&(r==="buttons"||r==="radio"?C(g):_(g)),m(f,v)}finally{y=!1}}}const I=pe({data:a,runUpdates:w});return function(){I(),s()}}const Xe=Object.freeze(Object.defineProperty({__proto__:null,subscriptionPreviewRender:Qe},Symbol.toStringTag,{value:"Module"}))})(); })("/", { suffix: "", type: "product" }, "main", 153996034186, false)</script>
43 44 <!-- End of Shoplift scripts --> 45 46 <meta name="google-site-verification" content="MXnRc1jmvxm9zsLYqRnkToZnYziGVUxU09LeCl1NvfA"> 47 <meta charset="utf-8"> 48 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 49 <meta name="viewport" content="width=device-width,initial-scale=1"> 50 <meta name="theme-color" content=""> 51 52 53 54 55 <link rel="canonical" href="https://revitin.com/products/revitin-natural-toothpaste"> 56 57 58 <link rel="preconnect" href="https://cdn.shopify.com" crossorigin> 59 60 <link 61 rel="preload" 62 as="image" 63 href="https://revitin.myshopify.com/cdn/shop/t/36/assets/main-orange.png" 64 > 65 <link 66 rel="preload" 67 as="image" 68 href="https://revitin.myshopify.com/cdn/shop/t/36/assets/main-grapefruit.png" 69 > 70 <link 71 rel="preload" 72 as="image" 73 href="https://revitin.myshopify.com/cdn/shop/t/36/assets/main-papaya.png" 74 > 75 <link 76 rel="preload" 77 as="image" 78 href="https://revitin.myshopify.com/cdn/shop/t/36/assets/main-lemon.png" 79 ><link 80 rel="icon" 81 type="image/png" 82 href="//revitin.com/cdn/shop/files/citrus-logo.png?crop=center&height=32&v=1730052959&width=32" 83 ><title>Revitin | SLS-Free Toothpaste | Buy Fluoride-Free Toothpaste Online 84</title> 85 86 87 <meta name="description" content="Buy Revitin SLS-free, fluoride-free toothpaste online. Prebiotic formula with Vitamin C, CoQ10 & cranberry seed oil supports enamel & fresh breath"> 88 89 90 91 92<meta property="og:site_name" content="Revitin"> 93<meta property="og:url" content="https://revitin.com/products/revitin-natural-toothpaste"> 94<meta property="og:title" content="Revitin | SLS-Free Toothpaste | Buy Fluoride-Free Toothpaste Online"> 95<meta property="og:type" content="product"> 96<meta property="og:description" content="Buy Revitin SLS-free, fluoride-free toothpaste online. Prebiotic formula with Vitamin C, CoQ10 & cranberry seed oil supports enamel & fresh breath"><meta property="og:image" content="https://cdn.shopify.com/s/files/1/0376/8972/0970/files/Revitin_Mint_tube_box_product_shot.png?v=1790079103"> 97 <meta property="og:image:secure_url" content="https://cdn.shopify.com/s/files/1/0376/8972/0970/files/Revitin_Mint_tube_box_product_shot.png?v=1790079103"> 98 <meta property="og:image:width" content="630"> 99 <meta property="og:image:height" content="1200"><meta property="og:price:amount" content="17.00"> 100 <meta property="og:price:currency" content="USD"><meta name="twitter:card" content="summary_large_image"> 101<meta name="twitter:title" content="Revitin | SLS-Free Toothpaste | Buy Fluoride-Free Toothpaste Online"> 102<meta name="twitter:description" content="Buy Revitin SLS-free, fluoride-free toothpaste online. Prebiotic formula with Vitamin C, CoQ10 & cranberry seed oil supports enamel & fresh breath"> 103 104
104<script src="//revitin.com/cdn/shop/t/129/assets/swiper-bundle.min.js?v=87330480114418983271777542405" defer></script>
104 105
105<script src="//revitin.com/cdn/shop/t/129/assets/web-components.js?v=42699711469469777231785948103" defer></script>
105 106
106<script src="//revitin.com/cdn/shop/t/129/assets/gwp.js?v=91107431928599107341787719402" defer></script>
106<script> 107 window.RevitinGWP = Object.assign(window.RevitinGWP || {}, { 108 enabled: false, 109 isWholesale: false, 110 handle: "variety-travel-2-pack-of-1-oz", 111 productId: 9208964186250, 112 variantId: 49777251877002 113 }); 114 </script>
114 115
115<script src="//revitin.com/cdn/shop/t/129/assets/swiper.js?v=169847002317838591371777542405"></script>
115 116 117 118
118<script>window.performance && window.performance.mark && window.performance.mark('shopify.content_for_header.start');</script>
118<meta name="google-site-verification" content="TM7UwSLIsjzSApI0vz9CDDNBxARLzowvI9ah-R2lztQ"> 119<meta name="google-site-verification" content="ysyTOABQ_pw1KSMnMjHUU7SSBUlUFjbpLVl0F5TBgWU"> 120<meta id="shopify-digital-wallet" name="shopify-digital-wallet" content="/37689720970/digital_wallets/dialog"> 121<link rel="ucp" href="/.well-known/ucp" version="2026-08-25"><link rel="buy" href="/cart/45594631471242:1?ucp/version=2026-08-25&context/payment/0/handler=dev.shopify.shop_pay" payment="dev.shopify.shop_pay com.google.pay dev.shopify.card"><link rel="alternate" type="application/json+oembed" href="https://revitin.com/products/revitin-natural-toothpaste.oembed">
122<script async="async" src="/checkouts/internal/preloads.js?locale=en-US&default_configuration_id=8028298"></script>
122 123<link rel="preconnect" href="https://shop.app" crossorigin="anonymous">
124<script async="async" src="https://shop.app/checkouts/internal/preloads.js?locale=en-US&default_configuration_id=8028298&shop_id=37689720970" crossorigin="anonymous"></script>
vendor: 1 bytes, line 124
124
125<script id="apple-pay-shop-capabilities" type="application/json">{"shopId":37689720970,"countryCode":"US","currencyCode":"USD","merchantCapabilities":["supports3DS"],"merchantId":"gid:\/\/shopify\/Shop\/37689720970","merchantName":"Revitin","requiredBillingContactFields":["postalAddress","email"],"requiredShippingContactFields":["postalAddress","email"],"shippingType":"shipping","supportedNetworks":["visa","masterCard","amex","discover","elo","jcb"],"total":{"type":"pending","label":"Revitin","amount":"1.00"},"shopifyPaymentsEnabled":true,"supportsSubscriptions":true}</script>
vendor: 1 bytes, line 125
125
126<script id="shopify-features" type="application/json">{"accessToken":"a7e8321f0c73cc9d743a2fc8b66839ac","betas":["rich-media-storefront-analytics"],"domain":"revitin.com","predictiveSearch":true,"shopId":37689720970,"locale":"en"}</script>
vendor: 1 bytes, line 126
126
127<script>var Shopify = Shopify || {}; 128Shopify.shop = "revitin.myshopify.com"; 129Shopify.locale = "en"; 130Shopify.currency = {"active":"USD","rate":"1.0"}; 131Shopify.country = "US"; 132Shopify.theme = {"name":"Revitin-Shopify\/main","id":153996034186,"schema_name":"Dawn","schema_version":"6.0.2","theme_store_id":null,"role":"main"}; 133Shopify.theme.handle = "null"; 134Shopify.theme.style = {"id":null,"handle":null}; 135Shopify.cdnHost = "revitin.com/cdn"; 136Shopify.routes = Shopify.routes || {}; 137Shopify.routes.root = "/"; 138Shopify.shopJsCdnBaseUrl = "https://cdn.shopify.com/shopifycloud/shop-js"; 139Shopify.SignInWithShop = Shopify.SignInWithShop || {}; 140Shopify.SignInWithShop.User = Shopify.SignInWithShop.User || {}; 141Shopify.SignInWithShop.User.recognized = false;</script>
vendor: 1 bytes, line 141
141
142<script type="module">!function(o){(o.Shopify=o.Shopify||{}).modules=!0}(window);</script>
vendor: 1 bytes, line 142
142
143<script>!function(o){function n(){var o=[];function n(){o.push(Array.prototype.slice.apply(arguments))}return n.q=o,n}var t=o.Shopify=o.Shopify||{};t.loadFeatures=n(),t.autoloadFeatures=n()}(window);</script>
vendor: 1 bytes, line 143
143
144<script> 145 window.ShopifyPay = window.ShopifyPay || {}; 146 window.ShopifyPay.apiHost = "shop.app\/pay"; 147 window.ShopifyPay.redirectState = null; 148</script>
vendor: 1 bytes, line 148
148
149<script> 150 window.Shopify = window.Shopify || {}; 151 window.Shopify.SignInWithShop = window.Shopify.SignInWithShop || {}; 152 window.Shopify.SignInWithShop.assetMetrics = { sampleRate: 0.25 }; 153 window.Shopify.SignInWithShop.eligible = true; 154</script>
vendor: 1 bytes, line 154
154
155<script id="shop-js-analytics" type="application/json">{"pageType":"product"}</script>
vendor: 1 bytes, line 155
155
156<script defer="defer" async type="module" src="https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.init-shop-cart-sync.en.esm.js"></script>
vendor: 1 bytes, line 156
156
157<script type="module"> 158 await import("https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.init-shop-cart-sync.en.esm.js"); 159 160 window.Shopify.SignInWithShop?.initShopCartSync?.({"fedCMEnabled":true,"windoidEnabled":true}); 161 162</script>
vendor: 1 bytes, line 162
162
163<script> 164 window.Shopify = window.Shopify || {}; 165 if (!window.Shopify.featureAssets) window.Shopify.featureAssets = {}; 166 window.Shopify.featureAssets['shop-js'] = {"avatar":["modules/v2/loader.avatar.en.esm.js"],"checkout-modal":["modules/v2/loader.checkout-modal.en.esm.js"],"init-customer-accounts-sign-up":["modules/v2/loader.init-customer-accounts-sign-up.en.esm.js"],"init-customer-accounts":["modules/v2/loader.init-customer-accounts.en.esm.js"],"init-fed-cm":["modules/v2/loader.init-fed-cm.en.esm.js"],"init-shop-cart-sync":["modules/v2/loader.init-shop-cart-sync.en.esm.js"],"init-shop-email-lookup-coordinator":["modules/v2/loader.init-shop-email-lookup-coordinator.en.esm.js"],"init-shop-for-new-customer-accounts":["modules/v2/loader.init-shop-for-new-customer-accounts.en.esm.js"],"init-shop-user-recognition":["modules/v2/loader.init-shop-user-recognition.en.esm.js"],"init-windoid":["modules/v2/loader.init-windoid.en.esm.js"],"lead-capture":["modules/v2/loader.lead-capture.en.esm.js"],"listener":["modules/v2/loader.listener.en.esm.js"],"pay-button":["modules/v2/loader.pay-button.en.esm.js"],"payment-terms":["modules/v2/loader.payment-terms.en.esm.js"],"shop-button":["modules/v2/loader.shop-button.en.esm.js"],"shop-cart-sync":["modules/v2/loader.shop-cart-sync.en.esm.js"],"shop-cash-offers":["modules/v2/loader.shop-cash-offers.en.esm.js"],"shop-follow-button":["modules/v2/loader.shop-follow-button.en.esm.js"],"shop-login-button":["modules/v2/loader.shop-login-button.en.esm.js"],"shop-login":["modules/v2/loader.shop-login.en.esm.js"],"shop-toast-manager":["modules/v2/loader.shop-toast-manager.en.esm.js"],"shop-user-recognition":["modules/v2/loader.shop-user-recognition.en.esm.js"]}; 167</script>
vendor: 1 bytes, line 167
167
168<script>(function() { 169 var isLoaded = false; 170 function asyncLoad() { 171 if (isLoaded) return; 172 isLoaded = true; 173 var urls = ["https:\/\/cdn1.stamped.io\/files\/widget.min.js?shop=revitin.myshopify.com","\/\/secure.apps.shappify.com\/apps\/csp\/customer_pricing.php?shop=revitin.myshopify.com","https:\/\/cp.boldapps.net\/csp_install_check.js?shop=revitin.myshopify.com","https:\/\/cp.boldapps.net\/js\/cspqb.js?shop=revitin.myshopify.com","https:\/\/secureddatasystem.com\/ShopifyApps\/aispeed_2\/store-assets\/js\/aispeed.js?shop=revitin.myshopify.com","https:\/\/secureddatasystem.com\/ShopifyApps\/aispeed_2\/store-assets\/js\/aispeed.js?shop=revitin.myshopify.com","https:\/\/secureddatasystem.com\/ShopifyApps\/aispeed_2\/store-assets\/js\/aispeed.js?shop=revitin.myshopify.com","https:\/\/static.klaviyo.com\/onsite\/js\/klaviyo.js?company_id=YmxebZ\u0026shop=revitin.myshopify.com","https:\/\/formbuilder.hulkapps.com\/skeletopapp.js?shop=revitin.myshopify.com","https:\/\/static.klaviyo.com\/onsite\/js\/klaviyo.js?company_id=WSqXYN\u0026shop=revitin.myshopify.com","https:\/\/static.klaviyo.com\/onsite\/js\/klaviyo.js?company_id=WSqXYN\u0026shop=revitin.myshopify.com","https:\/\/static.shareasale.com\/json\/shopify\/deduplication.js?shop=revitin.myshopify.com","https:\/\/static.shareasale.com\/json\/shopify\/shareasale-tracking.js?sasmid=65308\u0026ssmtid=19038\u0026shop=revitin.myshopify.com","https:\/\/static.rechargecdn.com\/static\/js\/recharge.js?rev=b8f816a11c7e36039898a7e01ce2c51af24f486c\u0026shop=revitin.myshopify.com","https:\/\/cdn.nfcube.com\/instafeed-da16887788b96861a8e7a831fdc68a91.js?shop=revitin.myshopify.com","https:\/\/cdn-bundler.nice-team.net\/app\/js\/bundler.js?shop=revitin.myshopify.com","https:\/\/static.rechargecdn.com\/assets\/js\/widget.min.js?shop=revitin.myshopify.com","\/\/cdn.shopify.com\/proxy\/9e2536e0fa9a3978eb238b6e0ce8a737b9c337692837744cd02a0d8d36665ce1\/api.goaffpro.com\/loader.js?shop=revitin.myshopify.com\u0026sp-cache-control=cHVibGljLCBtYXgtYWdlPTkwMA","https:\/\/cdn.hextom.com\/js\/quickannouncementbar.js?shop=revitin.myshopify.com"]; 174 for (var i = 0; i < urls.length; i++) { 175 var s = document.createElement('script'); 176 s.type = 'text/javascript'; 177 s.async = true; 178 s.src = urls[i]; 179 var x = document.getElementsByTagName('script')[0]; 180 x.parentNode.insertBefore(s, x); 181 } 182 }; 183 if(window.attachEvent) { 184 window.attachEvent('onload', asyncLoad); 185 } else { 186 window.addEventListener('load', asyncLoad, false); 187 } 188})();</script>
vendor: 1 bytes, line 188
188
189<script id="__st">var __st={"a":37689720970,"offset":-14400,"reqid":"92b14f4a-92cf-4ca7-868f-2d3322189ab5-1790777238","pageurl":"revitin.com\/products\/revitin-natural-toothpaste\/Citrus","u":"b3679641a969","p":"product","rtyp":"product","rid":6606432174218};</script>
vendor: 1 bytes, line 189
189
190<script>window.ShopifyPaypalV4VisibilityTracking = true;</script>
vendor: 1 bytes, line 190
190
191<script id="form-persister">!function(){'use strict';const t='contact',e='new_comment',n=[[t,t],['blogs',e],['comments',e],[t,'customer']],o='password',r='form_key',c=['recaptcha-v3-token','g-recaptcha-response','h-captcha-response',o],s=()=>{try{return window.sessionStorage}catch{return}},i='__shopify_v',u=t=>t.elements[r],a=function(){const t=[...n].map((([t,e])=>`form[action*='/${t}']:not([data-nocaptcha='true']) input[name='form_type'][value='${e}']`)).join(',');var e;return e=t,()=>e?[...document.querySelectorAll(e)].map((t=>t.form)):[]}();function m(t){const e=u(t);a().includes(t)&&(!e||!e.value)&&function(t){try{if(!s())return;!function(t){const e=s();if(!e)return;const n=u(t);if(!n)return;const o=n.value;o&&e.removeItem(o)}(t);const e=Array.from(Array(32),(()=>Math.random().toString(36)[2])).join('');!function(t,e){u(t)||t.append(Object.assign(document.createElement('input'),{type:'hidden',name:r})),t.elements[r].value=e}(t,e),function(t,e){const n=s();if(!n)return;const r=[...t.querySelectorAll(`input[type='${o}']`)].map((({name:t})=>t)),u=[...c,...r],a={};for(const[o,c]of new FormData(t).entries())u.includes(o)||(a[o]=c);n.setItem(e,JSON.stringify({[i]:1,action:t.action,data:a}))}(t,e)}catch(e){console.error('failed to persist form',e)}}(t)}const f=t=>{if('true'===t.dataset.persistBound)return;const e=function(t,e){const n=function(t){return'function'==typeof t.submit?t.submit:HTMLFormElement.prototype.submit}(t).bind(t);return function(){let t;return()=>{t||(t=!0,(()=>{try{e(),n()}catch(t){(t=>{console.error('form submit failed',t)})(t)}})(),setTimeout((()=>t=!1),250))}}()}(t,(()=>{m(t)}));!function(t,e){if('function'==typeof t.submit&&'function'==typeof e)try{t.submit=e}catch{}}(t,e),t.addEventListener('submit',(t=>{t.preventDefault(),e()})),t.dataset.persistBound='true'};!function(){function t(t){const e=(t=>{const e=t.target;return e instanceof HTMLFormElement?e:e&&e.form})(t);e&&m(e)}document.addEventListener('submit',t),document.addEventListener('DOMContentLoaded',(()=>{const e=a();for(const t of e)f(t);var n;n=document.body,new window.MutationObserver((t=>{for(const e of t)if('childList'===e.type&&e.addedNodes.length)for(const t of e.addedNodes)1===t.nodeType&&'FORM'===t.tagName&&a().includes(t)&&f(t)})).observe(n,{childList:!0,subtree:!0,attributes:!1}),document.removeEventListener('submit',t)}))}()}();</script>
vendor: 1 bytes, line 191
191
192<script integrity="sha256-JjoPp5ZfB1sSAs5SQaol1x1GgvveM+BgmRzyDexInEQ=" data-source-attribution="shopify.loadfeatures" defer="defer" src="//revitin.com/cdn/shopifycloud/storefront/assets/storefront/load_feature-1bd60354.js" crossorigin="anonymous"></script>
vendor: 1 bytes, line 192
192
193<script>(function () {var userAgent = navigator.userAgent;var platform = navigator.platform;var maxTouchPoints = navigator.maxTouchPoints || 0;var isIOS = /iPad|iPhone|iPod/.test(platform) || (platform === 'MacIntel' && maxTouchPoints > 1);var isMacSafari = platform.indexOf('Mac') === 0 && /Safari/.test(userAgent) && !/Chrome|Chromium|CriOS|FxiOS|Edg|OPR|Android/.test(userAgent);var isAppleSafari = isIOS || isMacSafari;if (isAppleSafari) {fetch('/sf_private_access_tokens' + location.search).catch(function () {});}function browserMajorVersion(pattern) {var match = userAgent.match(pattern);return match ? parseInt(match[1], 10) : null;}function shouldLoadAutosizesPolyfill() {if (!window.PerformanceObserver?.supportedEntryTypes?.includes('paint')) {return false;}var chromeVersion = browserMajorVersion(/Chrome\/(\d+)/);if (chromeVersion !== null) {return chromeVersion < 126;}var firefoxVersion = browserMajorVersion(/Firefox\/(\d+)/);if (firefoxVersion !== null) {return firefoxVersion < 150;}var safariVersion = isAppleSafari ? browserMajorVersion(/Version\/(\d+).*Safari\//) : null;if (safariVersion !== null) {return safariVersion < 27;}return true;}if (shouldLoadAutosizesPolyfill()) {var autosizesScript = document.createElement('script');autosizesScript.async = true;autosizesScript.crossOrigin = 'anonymous';autosizesScript.src = "//revitin.com/cdn/shopifycloud/storefront/assets/storefront/autosizes-84416378.js";(document.head || document.documentElement).appendChild(autosizesScript);}window.ShopifyAnalytics = window.ShopifyAnalytics || {};window.ShopifyAnalytics.performance = window.ShopifyAnalytics.performance || {};(function () {var LONG_FRAME_THRESHOLD = 50;var longAnimationFrames = [];var activeRafId = null;function collectLongFrames() {var previousTime = null;function rafMonitor(now) {if (activeRafId === null) {return;}var delta = now - previousTime;if (delta > LONG_FRAME_THRESHOLD) {longAnimationFrames.push({startTime: previousTime,endTime: now,});}previousTime = now;activeRafId = requestAnimationFrame(rafMonitor);}previousTime = performance.now();activeRafId = requestAnimationFrame(rafMonitor);}if (!window.PerformanceObserver?.supportedEntryTypes?.includes('long-animation-frame')) {collectLongFrames();var timeoutId = setTimeout(function () {cancelAnimationFrame(activeRafId);}, 10000);window.ShopifyAnalytics.performance.getLongAnimationFrames = function (stopCollection) {if (stopCollection === undefined) {stopCollection = false;}if (stopCollection) {clearTimeout(timeoutId);cancelAnimationFrame(activeRafId);}return longAnimationFrames;};}})();})();</script>
193<script crossorigin="anonymous" defer="defer" src="//revitin.com/cdn/shopifycloud/storefront/assets/shopify_pay/storefront-616277c7.js?v=20250812"></script>
vendor: 1 bytes, line 193
193
194<script id="shopify-origin-trials" async="async" integrity="sha256-qJbe/jEZBHtr5W/BlA2cKAz3vkXu6vJQyLjgvgCC86g=" src="//cdn.shopify.com/shopifycloud/storefront/assets/storefront/origin_trials-318ab40a.js" crossorigin="anonymous" onload="window.__shopifyOriginTrialsDone = true" onerror="window.__shopifyOriginTrialsDone = true"></script>
vendor: 1 bytes, line 194
194
195<script> 196 window.Shopify = window.Shopify || {}; 197 window.Shopify.MCP = window.Shopify.MCP || {}; 198 window.Shopify.MCP.enabled = true; 199 window.Shopify.MCP.shop = "revitin.myshopify.com"; 200 window.Shopify.MCP.mcpEndpoint = "https:\/\/revitin.com\/api\/mcp"; 201 window.Shopify.MCP.tools = [{"name":"search_shop_policies_and_faqs","description":"Used to get facts about the stores policies, products, or services.\nSome examples of questions you can ask are:\n - What is your return policy?\n - What is your shipping policy?\n - What is your phone number?\n - What are your hours of operation?\"\n","inputSchema":{"$schema":"https:\/\/json-schema.org\/draft\/2020-12\/schema","type":"object","properties":{"query":{"type":"string","description":"A natural language query."},"context":{"type":"string","description":"Additional information about the request such as user demographics, mood, location, or other relevant details that could help in tailoring the response appropriately."}},"required":["query"]}}]; 202</script>
vendor: 1 bytes, line 202
202
203<script>(()=>{var d="shopify:webmcp_adapter_loaded",n=Symbol.for("shopify.webmcp_adapter_loading");function s(c,a,{win:r=window,doc:o=document}={}){function p(){try{return r.localStorage.getItem(d)==="true"}catch{return!1}}function l(){try{r.localStorage.setItem(d,"true")}catch{}}function u(){return typeof(o.modelContext||r.navigator?.modelContext)?.registerTool=="function"}function f(){if(r[n]||!u())return;let t=o.head||o.getElementsByTagName("head")[0];if(!t)return;let e=o.createElement("script");e.type="module",e.crossOrigin="anonymous",a&&(e.integrity=a),e.src=c,e.addEventListener("load",l,{once:!0}),e.addEventListener("error",()=>{r[n]=!1},{once:!0}),t.appendChild(e),r[n]=!0}function _(t){let e=o.getElementById("shopify-origin-trials");if(!e||r.__shopifyOriginTrialsDone){t();return}e.addEventListener("load",t,{once:!0}),e.addEventListener("error",t,{once:!0})}function i(){_(()=>r.setTimeout(f,0))}function m(){o.addEventListener("DOMContentLoaded",i,{once:!0})}p()?i():m()}s("\/\/revitin.com\/cdn\/shopifycloud\/storefront\/assets\/storefront\/webmcp-c6b62ece.js","sha256-ke4DDuBjdvea3vxLWxHc9E9nq8zihuG4IfYEGbb77ys=");})(); 204</script>
vendor: 1 bytes, line 204
204
205<script data-source-attribution="shopify.dynamic_checkout.dynamic.init">var Shopify=Shopify||{};Shopify.PaymentButton=Shopify.PaymentButton||{isStorefrontPortableWallets:!0,init:function(){window.Shopify.PaymentButton.init=function(){};var t=document.createElement("script");t.src="https://revitin.com/cdn/shopifycloud/portable-wallets/latest/portable-wallets.en.js",t.type="module",document.head.appendChild(t)}}; 206</script>
vendor: 1 bytes, line 206
206
207<script data-source-attribution="shopify.dynamic_checkout.buyer_consent"> 208 function portableWalletsHideBuyerConsent(e){var t=document.getElementById("shopify-buyer-consent"),n=document.getElementById("shopify-subscription-policy-button");t&&n&&(t.classList.add("hidden"),t.setAttribute("aria-hidden","true"),n.removeEventListener("click",e))}function portableWalletsShowBuyerConsent(e){var t=document.getElementById("shopify-buyer-consent"),n=document.getElementById("shopify-subscription-policy-button");t&&n&&(t.classList.remove("hidden"),t.removeAttribute("aria-hidden"),n.addEventListener("click",e))}window.Shopify?.PaymentButton&&(window.Shopify.PaymentButton.hideBuyerConsent=portableWalletsHideBuyerConsent,window.Shopify.PaymentButton.showBuyerConsent=portableWalletsShowBuyerConsent); 209</script>
vendor: 1 bytes, line 209
209
210<script data-source-attribution="shopify.dynamic_checkout.cart.bootstrap">document.addEventListener("DOMContentLoaded",(function(){function t(){return document.querySelector("shopify-accelerated-checkout-cart, shopify-accelerated-checkout")}if(t())Shopify.PaymentButton.init();else{new MutationObserver((function(e,n){t()&&(Shopify.PaymentButton.init(),n.disconnect())})).observe(document.body,{childList:!0,subtree:!0})}})); 211</script>
211 212<link id="shopify-accelerated-checkout-styles" rel="stylesheet" media="screen" href="https://revitin.com/cdn/shopifycloud/portable-wallets/latest/accelerated-checkout-backwards-compat.css" crossorigin="anonymous"> 213<style id="shopify-accelerated-checkout-cart"> 214 #shopify-buyer-consent { 215 margin-top: 1em; 216 display: inline-block; 217 width: 100%; 218} 219 220#shopify-buyer-consent.hidden { 221 display: none; 222} 223 224#shopify-subscription-policy-button { 225 background: none; 226 border: none; 227 padding: 0; 228 text-decoration: underline; 229 font-size: inherit; 230 cursor: pointer; 231} 232 233#shopify-subscription-policy-button::before { 234 box-shadow: none; 235} 236 237 </style> 238
239<script id="shopify-cfh-end">window.performance && window.performance.mark && window.performance.mark('shopify.content_for_header.end');</script>
239 240 241 <link rel="stylesheet" href="//revitin.com/cdn/shop/t/129/assets/tailwind.style.css?v=17529247885522139811786010445"> 242 <link 243 rel="preload" 244 href="//revitin.com/cdn/shop/t/129/assets/swiper-bundle.min.css?v=95102680675147881971777542404" 245 as="style" 246 onload="this.onload=null;this.rel='stylesheet'" 247 > 248 <style> 249 .form_container div input { 250 background: #FFFBEF !important; 251 } 252 253 @font-face { 254 font-family: "Basis Regular"; 255 src: url("https://cdn.shopify.com/s/files/1/0376/8972/0970/files/basis-grotesque-regular-trial.woff2?v=1724768478"); 256 font-style: normal; 257 font-weight: normal; 258 font-display: swap; 259 } 260 @font-face { 261 font-family: "Basis Medium"; 262 src: url("https://cdn.shopify.com/s/files/1/0376/8972/0970/files/basis-grotesque-medium-trial.woff2?v=1724768478"); 263 font-style: normal; 264 font-weight: normal; 265 font-display: swap; 266 } 267 @font-face { 268 font-family: "Rza Trial"; 269 src: url("https://cdn.shopify.com/s/files/1/0376/8972/0970/files/Rza-Trial-Light.woff2?v=1724768478"); 270 font-style: normal; 271 font-weight: normal; 272 font-display: swap; 273 } 274 @media (max-width: 640px){ 275 iframe#podium-bubble, iframe#podium-prompt{ 276 z-index: 99 !important; 277 } 278 /* iframe#podium-prompt { display: none !important;} */ 279 } 280 </style> 281
281<script>
vendor: 455 bytes, lines 281-291
281 282 (function (w, d, s, l, i) { 283 w[l] = w[l] || []; 284 w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' }); 285 var f = d.getElementsByTagName(s)[0], 286 j = d.createElement(s), 287 dl = l != 'dataLayer' ? '&l=' + l : ''; 288 j.async = true; 289 j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl; 290 f.parentNode.insertBefore(j, f); 291 })(window, document, 'script', 'dataLayer', '
291GTM-MX86RPVR
vendor: 8 bytes, lines 291-292
291'); 292
292</script>
vendor: 69 bytes, lines 292-294
292 293 294 <script async src="https://www.googletagmanager.com/gtag/js?id=
294G-WMDYXD9CTG
vendor: 16 bytes, lines 294-295
294"></script> 295
295<script> 296
vendor: 162 bytes, lines 296-301
296window.dataLayer = window.dataLayer || []; 297 function gtag() { 298 dataLayer.push(arguments); 299 } 300 gtag('js', new Date()); 301 gtag('config', '
301G-WMDYXD9CTG
vendor: 4 bytes, line 301
301');
301// Replace with your GA4 Measurement ID 302 </script>
302 303 304
304<script> 305 306 </script>
306 307 308
308<script> 309 window.addEventListener('klaviyoForms', function (e) { 310 if (e.detail.type == 'open' || e.detail.type == 'embedOpen') { 311 gtag('event', 'form_open', { form: 'Klaviyo form', form_id: e.detail.formId }); 312 } 313 if (e.detail.type == 'submit') { 314 gtag('event', 'form_submit', { form: 'Klaviyo form', form_id: e.detail.formId }); 315 } 316 if (e.detail.type == 'stepSubmit') { 317 gtag('event', 'form_step_submit', { form: 'Klaviyo form', step_name: e.detail.metaData.$step_name }); 318 } 319 if (e.detail.type == 'redirectedToUrl') { 320 gtag('event', 'form_url_redirect', { form: 'Klaviyo form', form_id: e.detail.formId }); 321 } 322 if (e.detail.type == 'close') { 323 gtag('event', 'form_close', { form: 'Klaviyo form', form_id: e.detail.formId }); 324 } 325 }); 326 </script>
326 327
327<script type="text/javascript"> 328 (function (c, l, a, r, i, t, y) { 329 c[a] = 330 c[a] || 331 function () { 332 (c[a].q = c[a].q || []).push(arguments); 333 }; 334 t = l.createElement(r); 335 t.async = 1; 336 t.src = 'https://www.clarity.ms/tag/' + i; 337 y = l.getElementsByTagName(r)[0]; 338 y.parentNode.insertBefore(t, y); 339 })(window, document, 'clarity', 'script', 'rbrmbn89qv'); 340 </script>
340 341 342 <!-- structured data --> 343
343<script type="application/ld+json"> 344{ 345 "@context": "https://schema.org", 346 "@type": "Organization", 347 "name": "Revitin", 348 "url": "https://revitin.com", 349 "logo": "https://revitin.com/cdn/shop/t/47/assets/citrus-logo.png?v=12133043602477412821745386983", 350 "sameAs": [ 351 "https://www.facebook.com/RevitinOralTherapy/", 352 "https://www.instagram.com/revitin/?hl=en" 353 ] 354} 355</script>
355 356 357 358
358<script type="application/ld+json"> 359 { 360 "@context": "https://schema.org", 361 "@type": "FAQPage", 362 "mainEntity": [ 363 { 364 "@type": "Question", 365 "name": "How is Revitin different from other toothpastes?", 366 "acceptedAnswer": { 367 "@type": "Answer", 368 "text": "Revitin uses all-natural ingredients for healthier teeth without the use of harsh chemicals. It supports an oral cavity with less inflammation and plaque buildup by encouraging a healthy microbial environment." 369 } 370 }, 371 { 372 "@type": "Question", 373 "name": "Can you swallow Revitin?", 374 "acceptedAnswer": { 375 "@type": "Answer", 376 "text": "Yes. Revitin is safe to swallow." 377 } 378 }, 379 { 380 "@type": "Question", 381 "name": "Is Revitin fluoride-free?", 382 "acceptedAnswer": { 383 "@type": "Answer", 384 "text": "Yes, Revitin is fluoride-free. There are no toxic ingredients in our formula." 385 } 386 }, 387 { 388 "@type": "Question", 389 "name": "What else is Revitin free from?", 390 "acceptedAnswer": { 391 "@type": "Answer", 392 "text": "Revitin is free from fluoride, SLS, gluten, dyes, peanuts, sugar, xylitol, and GMOs." 393 } 394 }, 395 { 396 "@type": "Question", 397 "name": "Does Revitin whiten teeth?", 398 "acceptedAnswer": { 399 "@type": "Answer", 400 "text": "Revitin is proven to reduce film buildup and plaque on teeth that leads to discoloration. Additionally, natural fruit enzymes like the ones in Revitin are proven to whiten teeth without harsh chemicals." 401 } 402 }, 403 { 404 "@type": "Question", 405 "name": "Is Revitin vegan?", 406 "acceptedAnswer": { 407 "@type": "Answer", 408 "text": "Yes." 409 } 410 }, 411 { 412 "@type": "Question", 413 "name": "Is Revitin safe for children?", 414 "acceptedAnswer": { 415 "@type": "Answer", 416 "text": "Yes, Revitin is a great choice for teeth brushers of all ages." 417 } 418 } 419 ] 420 } 421 </script>
421 422 423 424 425 426
426<script type="application/ld+json"> 427 428 429 430 431 { 432 "@context": "https://schema.org", 433 "@type": "BreadcrumbList", 434 "itemListElement": [ 435 { 436 "@type": "ListItem", 437 "position": 1, 438 "name": "Home", 439 "item": "https:\/\/revitin.com" 440 }, 441 { 442 "@type": "ListItem", 443 "position": 2, 444 "name": "Shop Revitin", 445 "item": "https:\/\/revitin.com\/collections\/shop-all" 446 }, 447 { 448 "@type": "ListItem", 449 "position": 3, 450 "name": "Revitin Toothpaste Single Tube", 451 "item": "https:\/\/revitin.com\/products\/revitin-natural-toothpaste" 452 } 453 ] 454 } 455 456</script>
456 457 458
459<script type="application/ld+json"> 460{ 461 "@context": "https://schema.org", 462 "@type": "Product", 463 "name": "Revitin Toothpaste Single Tube", 464 "image": [ 465 "files/citrus-gallery-render-mobile_11zon.jpg" 466 ], 467 "description": "<p>Revitin supports<span> </span><strong>strong white teeth</strong>,<span> </span><strong>healthy gums</strong>, and<span> </span><strong>fresher breath</strong>. Whatâs more, Revitin tastes great! Revitin is<span> </span><strong>fluoride-free</strong>,<span> </span><strong>without Sodium Lauryl Sulfate (SLS free)</strong>, and you won't find<span> </span><strong>Triclosan either!</strong></p>", 468 "sku": "CITRUS1", 469 "brand": { 470 "@type": "Brand", 471 "name": "Revitin® Natural Toothpaste" 472 }, 473 474 "aggregateRating": { 475 "@type": "AggregateRating", 476 "ratingValue": "4.54", 477 "reviewCount": 869 478 }, 479 480 "offers": { 481 "@type": "Offer", 482 "url": "https://revitin.com/products/revitin-natural-toothpaste", 483 "priceCurrency": "USD", 484 "price": "17.00", 485 "itemCondition": "https://schema.org/NewCondition", 486 "availability": "https://schema.org/InStock" 487 } 488} 489</script>
489 490 491 <!-- BEGIN app block: shopify://apps/klaviyo-email-marketing-sms/blocks/klaviyo-onsite-embed/2632fe16-c075-4321-a88b-50b567f42507 --> 492 493 494 495 496 497 498 499 500 501 502 503 504
504<script async src="https://static.klaviyo.com/onsite/js/YmxebZ/klaviyo.js?company_id=YmxebZ"></script>
504 505
505<script>!function(){if(!window.klaviyo){window._klOnsite=window._klOnsite||[];try{window.klaviyo=new Proxy({},{get:function(n,i){return"push"===i?function(){var n;(n=window._klOnsite).push.apply(n,arguments)}:function(){for(var n=arguments.length,o=new Array(n),w=0;w<n;w++)o[w]=arguments[w];var t="function"==typeof o[o.length-1]?o.pop():void 0,e=new Promise((function(n){window._klOnsite.push([i].concat(o,[function(i){t&&t(i),n(i)}]))}));return e}}})}catch(n){window.klaviyo=window.klaviyo||[],window.klaviyo.push=function(){var n;(n=window._klOnsite).push.apply(n,arguments)}}}}();</script>
505 506 507 508
508<script id="viewed_product"> 509 if (item == null) { 510 var _learnq = _learnq || []; 511 512 var MetafieldReviews = null 513 var MetafieldYotpoRating = null 514 var MetafieldYotpoCount = null 515 var MetafieldLooxRating = null 516 var MetafieldLooxCount = null 517 var okendoProduct = null 518 var okendoProductReviewCount = null 519 var okendoProductReviewAverageValue = null 520 try { 521 // The following fields are used for Customer Hub recently viewed in order to add reviews. 522 // This information is not part of __kla_viewed. Instead, it is part of __kla_viewed_reviewed_items 523 MetafieldReviews = {"rating":{"scale_min":"1.0","scale_max":"5.0","value":"4.54"},"rating_count":869}; 524 MetafieldYotpoRating = null 525 MetafieldYotpoCount = null 526 MetafieldLooxRating = null 527 MetafieldLooxCount = null 528 529 okendoProduct = null 530 // If the okendo metafield is not legacy, it will error, which then requires the new json formatted data 531 if (okendoProduct && 'error' in okendoProduct) { 532 okendoProduct = null 533 } 534 okendoProductReviewCount = okendoProduct ? okendoProduct.reviewCount : null 535 okendoProductReviewAverageValue = okendoProduct ? okendoProduct.reviewAverageValue : null 536 } catch (error) { 537 console.error('Error in Klaviyo onsite reviews tracking:', error); 538 } 539 540 var item = { 541 Name: "Revitin Toothpaste Single Tube", 542 ProductID: 6606432174218, 543 Categories: ["Home page","Shop Revitin","Toothpaste"], 544 ImageURL: "https://revitin.com/cdn/shop/files/citrus-gallery-render-mobile_11zon_grande.jpg?v=1742298905", 545 URL: "https://revitin.com/products/revitin-natural-toothpaste", 546 Brand: "Revitin® Natural Toothpaste", 547 Price: "$17.00", 548 Value: "17.00", 549 CompareAtPrice: "$17.00" 550 }; 551 _learnq.push(['track', 'Viewed Product', item]); 552 _learnq.push(['trackViewedItem', { 553 Title: item.Name, 554 ItemId: item.ProductID, 555 Categories: item.Categories, 556 ImageUrl: item.ImageURL, 557 Url: item.URL, 558 Metadata: { 559 Brand: item.Brand, 560 Price: item.Price, 561 Value: item.Value, 562 CompareAtPrice: item.CompareAtPrice 563 }, 564 metafields:{ 565 reviews: MetafieldReviews, 566 yotpo:{ 567 rating: MetafieldYotpoRating, 568 count: MetafieldYotpoCount, 569 }, 570 loox:{ 571 rating: MetafieldLooxRating, 572 count: MetafieldLooxCount, 573 }, 574 okendo: { 575 rating: okendoProductReviewAverageValue, 576 count: okendoProductReviewCount, 577 } 578 } 579 }]); 580 } 581 </script>
581 582 583 584 585 586 587
587<script> 588 window.klaviyoReviewsProductDesignMode = false 589 </script>
589 590 591 592 593 594 595 596 597 598 599<!-- END app block --><!-- BEGIN app block: shopify://apps/triplewhale/blocks/triple_pixel_snippet/483d496b-3f1a-4609-aea7-8eee3b6b7a2a --><link rel='preconnect dns-prefetch' href='https://api.config-security.com/' crossorigin /> 600<link rel='preconnect dns-prefetch' href='https://conf.config-security.com/' crossorigin />
601<script> 602/* >> TriplePixel :: start*/ 603window.TriplePixelData={TripleName:"revitin.myshopify.com",ver:"2.16",plat:"SHOPIFY",isHeadless:false,src:'SHOPIFY_EXT',product:{id:"6606432174218",name:`Revitin Toothpaste Single Tube`,price:"17.00",variant:"45594631471242",av:{ "45594631471242":true }},search:"",collection:"",cart:"notification",template:"product",curr:"USD" || "USD", market:"3341025418"},function(W,H,A,L,E,_,B,N){function O(U,T,P,H,R){void 0===R&&(R=!1),H=new XMLHttpRequest,P?(H.open("POST",U,!0),H.setRequestHeader("Content-Type","text/plain")):H.open("GET",U,!0),H.send(JSON.stringify(P||{})),H.onreadystatechange=function(){4===H.readyState&&200===H.status?(R=H.responseText,U.includes("/first")?eval(R):P||(N[B]=R)):(299<H.status||H.status<200)&&T&&!R&&(R=!0,O(U,T-1,P))}}if(N=window,!N[H+"sn"]){N[H+"sn"]=1,L=function(){return Date.now().toString(36)+"_"+Math.random().toString(36)};try{A.setItem(H,1+(0|A.getItem(H)||0)),(E=JSON.parse(A.getItem(H+"U")||"[]")).push({u:location.href,r:document.referrer,t:Date.now(),id:L()}),A.setItem(H+"U",JSON.stringify(E))}catch(e){}var i,m,p;A.getItem('"!nC`')||(_=A,A=N,A[H]||(E=A[H]=function(t,e,i){return void 0===i&&(i=[]),"State"==t?E.s:(W=L(),(E._q=E._q||[]).push([W,t,e].concat(i)),W)},E.s="Installed",E._q=[],E.ch=W,B="configSecurityConfModel",N[B]=1,O("https://conf.config-security.com/model",5),i=L(),m=A[atob("c2NyZWVu")],_.setItem("di_pmt_wt",i),p={id:i,action:"profile",avatar:_.getItem("auth-security_rand_salt_"),time:m[atob("d2lkdGg=")]+":"+m[atob("aGVpZ2h0")],host:A.TriplePixelData.TripleName,plat:A.TriplePixelData.plat,url:window.location.href.slice(0,500),ref:document.referrer,ver:A.TriplePixelData.ver},O("https://api.config-security.com/event",5,p),O("https://api.config-security.com/first?host=".concat(p.host,"&plat=").concat(p.plat),5)))}}("","TriplePixel",localStorage); 604/* << TriplePixel :: end*/ 605</script>
605 606 607 608 609<!-- END app block --><!-- BEGIN app block: shopify://apps/judge-me-reviews/blocks/judgeme_core/61ccd3b1-a9f2-4160-9fe9-4fec8413e5d8 --><!-- Start of Judge.me Core --> 610 611 612 613 614 615 616 617<link rel="dns-prefetch" href="https://cdn.judge.me"> 618<link rel="dns-prefetch" href="https://cdn1.judge.me"> 619<link rel="dns-prefetch" href="https://api.judge.me"> 620
621<script data-cfasync='false' class='jdgm-settings-script'>window.jdgmSettings={"pagination":5,"disable_web_reviews":false,"coupon_receiving_condition":"any_review","coupon_value_type":"percentage","coupon_value_percentage":10,"coupon_value_fixed_amount":0,"coupon_discount_type":"single","coupon_tier_text_enabled":false,"coupon_tier_text_percentage":10,"coupon_tier_text_fixed_amount":0,"coupon_tier_photo_enabled":false,"coupon_tier_photo_percentage":10,"coupon_tier_photo_fixed_amount":0,"coupon_tier_video_enabled":false,"coupon_tier_video_percentage":10,"coupon_tier_video_fixed_amount":0,"enable_coupons":false,"badge_no_review_text":"No reviews","badge_n_reviews_text":"{{ n }} review/reviews","badge_star_color":"#7E8F72","hide_badge_preview_if_no_reviews":true,"badge_hide_text":false,"enforce_center_preview_badge":false,"widget_title":"Customer Reviews","widget_open_form_text":"Write a review","widget_close_form_text":"Cancel review","widget_refresh_page_text":"Refresh page","widget_summary_text":"Based on {{ number_of_reviews }} review/reviews","widget_no_review_text":"Be the first to write a review","widget_name_field_text":"Display name","widget_verified_name_field_text":"Verified Name (public)","widget_name_placeholder_text":"Display name","widget_required_field_error_text":"This field is required.","widget_email_field_text":"Email address","widget_verified_email_field_text":"Verified Email (private, can not be edited)","widget_email_placeholder_text":"Your email address","widget_email_field_error_text":"Please enter a valid email address.","widget_rating_field_text":"Rating","widget_review_title_field_text":"Review Title","widget_review_title_placeholder_text":"Give your review a title","widget_review_body_field_text":"Review content","widget_review_body_placeholder_text":"Start writing here...","widget_pictures_field_text":"Picture/Video (optional)","widget_submit_review_text":"Submit Review","widget_submit_verified_review_text":"Submit Verified Review","widget_submit_success_msg_with_auto_publish":"Thank y
621ou! Please refresh the page in a few moments to see your review. You can remove or edit your review by logging into \u003ca href='https://judge.me/login' target='_blank' rel='nofollow noopener'\u003eJudge.me\u003c/a\u003e","widget_submit_success_msg_no_auto_publish":"Thank you! Your review will be published as soon as it is approved by the shop admin. You can remove or edit your review by logging into \u003ca href='https://judge.me/login' target='_blank' rel='nofollow noopener'\u003eJudge.me\u003c/a\u003e","widget_show_default_reviews_out_of_total_text":"Showing {{ n_reviews_shown }} out of {{ n_reviews }} reviews.","widget_show_all_link_text":"Show all","widget_show_less_link_text":"Show less","widget_author_said_text":"{{ reviewer_name }} said:","widget_days_text":"{{ n }} days ago","widget_weeks_text":"{{ n }} week/weeks ago","widget_months_text":"{{ n }} month/months ago","widget_years_text":"{{ n }} year/years ago","widget_yesterday_text":"Yesterday","widget_today_text":"Today","widget_replied_text":"\u003e\u003e {{ shop_name }} replied:","widget_read_more_text":"Read more","widget_reviewer_name_as_initial":"","widget_rating_filter_color":"#5F471D","widget_rating_filter_see_all_text":"See all reviews","widget_sorting_most_recent_text":"Most Recent","widget_sorting_highest_rating_text":"Highest Rating","widget_sorting_lowest_rating_text":"Lowest Rating","widget_sorting_with_pictures_text":"Only Pictures","widget_sorting_most_helpful_text":"Most Helpful","widget_open_question_form_text":"Ask a question","widget_reviews_subtab_text":"Reviews","widget_questions_subtab_text":"Questions","widget_question_label_text":"Question","widget_answer_label_text":"Answer","widget_question_placeholder_text":"Write your question here","widget_submit_question_text":"Submit Question","widget_question_submit_success_text":"Thank you for your question! We will notify you once it gets answered.","widget_star_color":"#7E8F72","verified_badge_text":"Verified","verified_badge_bg_color":"#FFDEA3","verified_badge_text_color":"","verified_badge_placement":"left-of-reviewer-name","widget_review_max_height":"","widget_hide_border":false,"widget_social_share":false,"widget_thumb":false,"widget_review_location_show":false,"widget_location_format":"","all_reviews_include_out_of_store_products":true,"all_reviews_out_of_store_text":"(out of store)","all_reviews_pagination":100,"all_reviews_product_name_prefix_text":"about","enable_review_pictures":true,"enable_question_anwser":false,"widget_theme":"default","review_date_format":"mm/dd/yyyy","default_sort_method":"most-recent","enable_ai_review_visibility":true,"widget_product_reviews_subtab_text":"Product Reviews","widget_shop_reviews_subtab_text":"Shop Reviews","widget_other_products_reviews_text":"Reviews for other products","widget_store_reviews_subtab_text":"Store reviews","widget_product_variant_reference_text":"Review for","widget_no_store_reviews_text":"This store hasn't received any reviews yet","widget_web_restriction_product_reviews_text":"This product hasn't received any reviews yet","widget_no_items_text":"No items found","widget_show_more_text":"Show more","widget_write_a_store_review_text":"Write a Store Review","widget_product_and_store_reviews_text":"Product and store reviews","widget_reviews_in_collection_text":"Reviews in this collection","widget_other_languages_heading":"Reviews in Other Languages","widget_translate_review_text":"Translate review to {{ language }}","widget_translating_review_text":"Translating...","widget_show_original_translation_text":"Show original ({{ language }})","widget_translate_review_failed_text":"Review couldn't be translated.","widget_translate_review_retry_text":"Retry","widget_translate_review_try_again_later_text":"Try again later","show_product_url_for_grouped_product":false,"widget_sorting_pictures_first_text":"Pictures First","show_pictures_on_all_rev_page_mobile":false,"show_pictures_on_all_rev_page_desktop":false,"floating_tab_hide_mobile_install_preference":false,"floating_tab_button_name":"â
Reviews","floating_tab_title":"Let customers speak for us","floating_tab_button_color":"","floating_tab_button_background_color":"","floating_tab_url":"","floating_tab_url_enabled":false,"floating_tab_tab_style":"text","all_reviews_text_badge_text":"Customers rate us {{ shop.metafields.judgeme.all_reviews_rating | round: 1 }}/5 based on {{ shop.metafields.judgeme.all_reviews_count }} reviews.","all_reviews_text_badge_text_branded_style":"{{ shop.metafields.judgeme.all_reviews_rating | round: 1 }} out of 5 stars based on {{ shop.metafields.judgeme.all_reviews_count }} reviews","is_all_reviews_text_badge_a_link":false,"show_stars_for_all_reviews_text_badge":false,"all_reviews_text_badge_url":"","all_reviews_text_style":"branded","all_reviews_text_color_style":"judgeme_brand_color","all_reviews_text_color":"#108474","all_reviews_text_show_jm_brand":false,"featured_carousel_show_header":true,"featured_carousel_title":"Let customers speak for us","testimonials_carousel_title":"Customers are saying","videos_carousel_title":"Real customer stories","cards_carousel_title":"Customers are saying","featured_carousel_count_text":"from {{ n }} reviews","featured_carousel_add_link_to_all_reviews_page":false,"featured_carousel_url":"","featured_carousel_show_images":true,"featured_carousel_autoslide_interval":5,"featured_carousel_arrows_on_the_sides":false,"featured_carousel_height":250,"featured_carousel_width":80,"featured_carousel_image_size":0,"featured_carousel_image_height":250,"featured_carousel_arrow_color":"#eeeeee","verified_count_badge_style":"branded","verified_count_badge_orientation":"horizontal","verified_count_badge_color_style":"judgeme_brand_color","verified_count_badge_color":"#108474","is_verified_count_badge_a_link":false,"verified_count_badge_url":"","verified_count_badge_show_jm_brand":true,"widget_rating_preset_default":5,"widget_first_sub_tab":"product-reviews","widget_show_histogram":true,"widget_histogram_use_custom_color":true,"widget_pagination_use_custom_color":true,"widget_star_use_custom_color":false,"widget_verified_badge_use_custom_color":false,"widget_write_review_use_custom_color":false,"picture_reminder_submit_button":"Upload Pictures","enable_review_videos":false,"mute_video_by_default":false,"widget_sorting_videos_first_text":"Videos First","widget_review_pending_text":"Pending","featured_carousel_items_for_large_screen":3,"social_share_options_order":"Facebook,Twitter","remove_microdata_snippet":true,"disable_json_ld":false,"enable_json_ld_products":false,"preview_badge_show_question_text":false,"preview_badge_no_question_text":"No questions","preview_badge_n_question_text":"{{ number_of_questions }} question/questions","qa_badge_show_icon":false,"qa_badge_position":"same-row","remove_judgeme_branding":true,"widget_add_search_bar":false,"widget_search_bar_placeholder":"Search","widget_sorting_verified_only_text":"Verified only","widget_sorting_most_relevant_text":"Most Relevant","featured_carousel_theme":"default","featured_carousel_show_rating":true,"featured_carousel_show_title":true,"featured_carousel_show_body":true,"featured_carousel_show_date":false,"featured_carousel_show_reviewer":true,"featured_carousel_show_product":false,"featured_carousel_header_background_color":"#108474","featured_carousel_header_text_color":"#ffffff","featured_carousel_name_product_separator":"reviewed","featured_carousel_full_star_background":"#108474","featured_carousel_empty_star_background":"#dadada","featured_carousel_vertical_theme_background":"#f9fafb","featured_carousel_verified_badge_enable":true,"featured_carousel_verified_badge_color":"#108474","featured_carousel_border_style":"round","featured_carousel_review_line_length_limit":3,"featured_carousel_more_reviews_button_text":"Read more reviews","featured_carousel_view_product_button_text":"View product","all_reviews_page_load_reviews_on":"button_click","all_reviews_page_load_more_text":"Load More","disable_fb_tab_reviews":false,"enable_ajax_cdn_cache":false,"widget_advanced_speed_features":5,"widget_public_name_text":"displayed publicly like","default_reviewer_name":"John Smith","default_reviewer_name_has_non_latin":true,"widget_reviewer_anonymous":"Anonymous","medals_widget_title":"Judge.me Review Medals","medals_widget_background_color":"#f9fafb","medals_widget_position":"footer_all_pages","medals_widget_border_color":"#f9fafb","medals_widget_verified_text_position":"left","medals_widget_use_monochromatic_version":false,"medals_widget_elements_color":"#108474","show_reviewer_avatar":false,"widget_invalid_yt_video_url_error_text":"Not a YouTube video URL","widget_max_length_field_error_text":"Please enter no more than {0} characters.","widget_show_country_flag":false,"widget_show_collected_via_shop_app":true,"widget_verified_by_shop_badge_style":"light","widget_verified_by_shop_text":"Verified by Shop","widget_show_photo_gallery":false,"widget_load_with_code_splitting":true,"widget_ugc_install_preference":false,"widget_ugc_title":"Made by us, Shared by you","widget_ugc_subt
621itle":"Tag us to see your picture featured in our page","widget_ugc_arrows_color":"#ffffff","widget_ugc_primary_button_text":"Buy Now","widget_ugc_primary_button_background_color":"#108474","widget_ugc_primary_button_text_color":"#ffffff","widget_ugc_primary_button_border_width":"0","widget_ugc_primary_button_border_style":"none","widget_ugc_primary_button_border_color":"#108474","widget_ugc_primary_button_border_radius":"25","widget_ugc_secondary_button_text":"Load More","widget_ugc_secondary_button_background_color":"#ffffff","widget_ugc_secondary_button_text_color":"#108474","widget_ugc_secondary_button_border_width":"2","widget_ugc_secondary_button_border_style":"solid","widget_ugc_secondary_button_border_color":"#108474","widget_ugc_secondary_button_border_radius":"25","widget_ugc_reviews_button_text":"View Reviews","widget_ugc_reviews_button_background_color":"#ffffff","widget_ugc_reviews_button_text_color":"#108474","widget_ugc_reviews_button_border_width":"2","widget_ugc_reviews_button_border_style":"solid","widget_ugc_reviews_button_border_color":"#108474","widget_ugc_reviews_button_border_radius":"25","widget_ugc_reviews_button_link_to":"judgeme-reviews-page","widget_ugc_show_post_date":true,"widget_ugc_max_width":"800","widget_rating_metafield_value_type":true,"widget_primary_color":"#FFDEA3","widget_enable_secondary_color":false,"widget_secondary_color":"#edf5f5","widget_summary_average_rating_text":"{{ average_rating }}","widget_media_grid_title":"Customer photos \u0026 videos","widget_media_grid_see_more_text":"See more","widget_round_style":false,"widget_show_product_medals":false,"widget_verified_by_judgeme_text":"Verified by Judge.me","widget_show_store_medals":false,"widget_verified_by_judgeme_text_in_store_medals":"Verified by Judge.me","widget_media_field_exceed_quantity_message":"Sorry, we can only accept {{ max_media }} for one review.","widget_media_field_exceed_limit_message":"{{ file_name }} is too large, please select a {{ media_type }} less than {{ size_limit }}MB.","widget_review_submitted_text":"Review Submitted!","widget_question_submitted_text":"Question Submitted!","widget_close_form_text_question":"Cancel","widget_write_your_answer_here_text":"Write your answer here","widget_enabled_branded_link":true,"widget_show_collected_by_judgeme":false,"widget_reviewer_name_color":"#5F471D","widget_write_review_text_color":"#5F471D","widget_write_review_bg_color":"#FFDEA3","widget_collected_by_judgeme_text":"collected by Judge.me","widget_pagination_type":"load_more","widget_load_more_text":"Load More","widget_load_more_color":"#FFDEA3","widget_full_review_text":"Full Review","widget_read_more_reviews_text":"Read More Reviews","widget_read_questions_text":"Read Questions","widget_questions_and_answers_text":"Questions \u0026 Answers","widget_verified_by_text":"Verified by","widget_verified_text":"Verified","widget_number_of_reviews_text":"{{ number_of_reviews }} reviews","widget_back_button_text":"Back","widget_next_button_text":"Next","widget_custom_forms_filter_button":"Filters","custom_forms_style":"horizontal","widget_show_review_information":false,"how_reviews_are_collected":"How reviews are collected?","widget_show_review_keywords":false,"widget_gdpr_statement":"How we use your data: We'll only contact you about the review you left, and only if necessary. By submitting your review, you agree to Judge.me's \u003ca href='https://judge.me/terms' target='_blank' rel='nofollow noopener'\u003eterms\u003c/a\u003e, \u003ca href='https://judge.me/privacy' target='_blank' rel='nofollow noopener'\u003eprivacy\u003c/a\u003e and \u003ca href='https://judge.me/content-policy' target='_blank' rel='nofollow noopener'\u003econtent\u003c/a\u003e policies.","widget_multilingual_sorting_enabled":false,"widget_translate_review_content_enabled":false,"widget_translate_review_content_method":"manual","popup_widget_review_selection":"automatically_with_pictures","popup_widget_round_border_style":true,"popup_widget_show_title":true,"popup_widget_show_body":true,"popup_widget_show_reviewer":false,"popup_widget_show_product":true,"popup_widget_show_pictures":true,"popup_widget_use_review_picture":true,"popup_widget_show_on_home_page":true,"popup_widget_show_on_product_page":true,"popup_widget_show_on_collection_page":true,"popup_widget_show_on_cart_page":true,"popup_widget_position":"bottom_left","popup_widget_first_review_delay":5,"popup_widget_duration":5,"popup_widget_interval":5,"popup_widget_review_count":5,"popup_widget_hide_on_mobile":true,"review_snippet_widget_round_border_style":true,"review_snippet_widget_card_color":"#FFFFFF","review_snippet_widget_text_color":"#000000","review_snippet_widget_lighter_text_color":"#7B7B7B","review_snippet_widget_slider_arrows_background_color":"#FFFFFF","review_snippet_widget_slider_arrows_color":"#000000","review_snippet_widget_star_color":"#FFDEA3","show_product_variant":false,"all_reviews_product_variant_label_text":"Variant: ","widget_show_verified_branding":false,"widget_ai_summary_title":"Customers say","widget_ai_summary_disclaimer":"AI-powered review summary based on recent customer reviews","widget_show_ai_summary":false,"widget_show_ai_summary_bg":false,"write_review_button_visibility":"everyone","store_summary_widget_heading":"Customers rate this store","store_summary_widget_button_text":"View customer reviews","store_summary_widget_button_theme_text":"See AI reviews summary","widget_show_review_title_input":true,"widget_autofill_review_title":true,"redirect_reviewers_invited_via_email":"external_form","request_store_review_after_product_review":false,"request_review_other_products_in_order":false,"review_form_color_scheme":"default","review_form_corner_style":"square","review_form_star_color":"#FFDEA3","review_form_text_color":"#333333","review_form_background_color":"#ffffff","review_form_field_background_color":"#fafafa","review_form_button_color":"#FFDEA3","review_form_button_text_color":"#ffffff","review_form_modal_overlay_color":"#000000","review_form_theme":"multi_step","review_form_location":"in_store_popup","review_form_external_page_background_color":"#C5F7F0","review_content_screen_title_text":"How would you rate this product?","review_content_introduction_text":"We would love it if you would share a bit about your experience.","store_review_form_title_text":"How would you rate this store?","store_review_form_introduction_text":"We would love it if you would share a bit about your experience.","show_review_guidance_text":true,"one_star_review_guidance_text":"Poor","five_star_review_guidance_text":"Great","customer_information_screen_title_text":"About you","customer_information_introduction_text":"Please tell us more about you.","custom_questions_screen_title_text":"Your experience in more detail","custom_questions_introduction_text":"Here are a few questions to help us understand more about your experience.","review_submitted_screen_title_text":"Thanks for your review!","review_submitted_screen_thank_you_text":"We are processing it and it will appear on the store soon.","review_submitted_screen_email_verification_text":"Please confirm your email by clicking the link we just sent you. This helps us keep reviews authentic.","confirm_email_screen_title_text":"Confirm your email","confirm_email_screen_message_text":"To help keep reviews authentic, we'll send you a secure link to continue writing your review. It only takes a moment.","check_email_screen_title_text":"Check your email","check_email_screen_message_text":"We sent you an email to {{ email }}. Click the button on the email to continue.","check_email_screen_resend_message_text":"Email resent!","check_email_resend_hint_text":"Didn't get the email? Check your spam folder or [resend the email].","verification_email_rate_limit_error_text":"You've reached the limit for review attempts on this product. Please check your inbox or try again later.","review_submitted_request_store_review_text":"Would you like to share your experience of shopping with us?","review_submitted_review_other_products_text":"Would you like to review these products?","store_review_screen_title_text":"Would you like to share your experience of shopping with us?","store_review_introduction_text":"We value your feedback and use it to improve. Please share any thoughts or suggestions you have.","reviewer_media_screen_title_picture_text":"Share a picture","reviewer_media_introduction_picture_text":"Upload a photo to support your review.","reviewer_media_screen_title_video_text":"Share a video","reviewer_media_introduction_video_text":"Upload a video to support your review.","reviewer_media_screen_title_picture_or_video_text":"Share a picture or video","reviewer_media_introduction_picture_or_video_text":"Upload a photo or video to support your review.","reviewer_media_
621youtube_url_text":"Paste your Youtube URL here","advanced_settings_next_step_button_text":"Next","advanced_settings_close_review_button_text":"Close","modal_write_review_flow":false,"write_review_flow_required_text":"Required","write_review_flow_privacy_message_text":"We respect your privacy.","write_review_flow_anonymous_text":"Post review as anonymous","write_review_flow_visibility_text":"This won't be visible to other customers.","write_review_flow_multiple_selection_help_text":"Select as many as you like","write_review_flow_single_selection_help_text":"Select one option","write_review_flow_required_field_error_text":"This field is required","write_review_flow_invalid_email_error_text":"Please enter a valid email address","write_review_flow_max_length_error_text":"Max. {{ max_length }} characters.","write_review_flow_media_upload_text":"\u003cb\u003eClick to upload\u003c/b\u003e or drag and drop","write_review_flow_gdpr_statement":"We'll only contact you about your review if necessary. By submitting your review, you agree to our \u003ca href='https://judge.me/terms' target='_blank' rel='nofollow noopener'\u003eterms and conditions\u003c/a\u003e and \u003ca href='https://judge.me/privacy' target='_blank' rel='nofollow noopener'\u003eprivacy policy\u003c/a\u003e.","rating_only_reviews_enabled":false,"show_negative_reviews_help_screen":false,"new_review_flow_help_screen_rating_threshold":3,"negative_review_resolution_screen_title_text":"Tell us more","negative_review_resolution_text":"Your experience matters to us. If there were issues with your purchase, we're here to help. Feel free to reach out to us, we'd love the opportunity to make things right.","negative_review_resolution_button_text":"Contact us","negative_review_resolution_proceed_with_review_text":"Leave a review","negative_review_resolution_subject":"Issue with purchase from {{ shop_name }}.{{ order_name }}","coupon_promo_intro_any_review_text":"Write a review and get a coupon for {{ amount }} off your next purchase","coupon_promo_intro_with_photo_text":"Write a review and add a photo or video to get a coupon for {{ amount }} off your next purchase","coupon_promo_intro_with_video_text":"Write a review and add a video to get a coupon for {{ amount }} off your next purchase","coupon_promo_intro_up_to_any_review_text":"Write a review and get a coupon for up to {{ amount }} off your next purchase","coupon_promo_intro_up_to_with_photo_text":"Write a review and add a photo or video to get a coupon for up to {{ amount }} off your next purchase","coupon_promo_intro_external_text":"Write a review and get a reward for your next purchase","coupon_promo_intro_external_with_photo_text":"Write a review and add a photo or video to get a reward for your next purchase","coupon_promo_intro_external_with_video_text":"Write a review and add a video to get a reward for your next purchase","coupon_promo_media_photo_text":"Add a photo or video and get a coupon for {{ amount }} off your next purchase","coupon_promo_media_photo_only_text":"Add a photo and get a coupon for {{ amount }} off your next purchase","coupon_promo_media_video_text":"Add a video and get a coupon for {{ amount }} off your next purchase","coupon_promo_media_external_photo_text":"Add a photo or video and get a reward for your next purchase","coupon_promo_media_external_photo_only_text":"Add a photo and get a reward for your next purchase","coupon_promo_media_external_video_text":"Add a video and get a reward for your next purchase","coupon_promo_success_text":"You've got a coupon for your next purchase at {{ shop_name }}!","coupon_promo_success_subtext":"You'll receive your coupon email within the hour.","preview_badge_collection_page_install_status":false,"widget_review_custom_css":".jdgm-rev-widg{\nmax-width: 1200px;\nmargin-left:auto;\nmargin-right:auto;\n}\n.jdgm-rev-widg__header .jdgm-row-stars{\njustify-content:space-between!important;\n}\n@media (min-width: 768px){\n.jdgm-rev-widg {\npadding-left:2.5rem;\npadding-right:2.5rem;\n}\n}\n@media only screen and (min-width: 992px) {\n.jdgm-rev-widg__title {\ntext-align: left;\n}
621\n.jdgm-rev-widg__summary,.jdgm-widget-actions-wrapper{\n width: auto!important;\n }\n.jdgm-histogram{\n width:55%!important;\n align-items:flex-start!important;\n }\n}","preview_badge_custom_css":"span.jdgm-prev-badge__stars {\n font-size: 11px;\n}\n.jdgm-prev-badge__text {\n font-size: 15px;\n margin-left: 5px;\n color: #7e8f72;\n}\n.jdgm-preview-badge .jdgm-star.jdgm-star {\n margin: 0 2px !important;\n}","preview_badge_stars_count":"5-stars","featured_carousel_custom_css":"","floating_tab_custom_css":"","all_reviews_widget_custom_css":"","medals_widget_custom_css":"","verified_badge_custom_css":"","all_reviews_text_custom_css":"","transparency_badges_collected_via_store_invite":false,"transparency_badges_from_another_provider":false,"transparency_badges_collected_from_store_visitor":false,"transparency_badges_collected_by_verified_review_provider":true,"transparency_badges_earned_reward":false,"transparency_badges_collected_via_store_invite_text":"Review collected via store invitation","transparency_badges_from_another_provider_text":"Review collected from another provider","transparency_badges_collected_from_store_visitor_text":"Review collected from a store visitor","transparency_badges_written_in_google_text":"Review written in Google","transparency_badges_written_in_etsy_text":"Review written in Etsy","transparency_badges_written_in_shop_app_text":"Review written in Shop App","transparency_badges_earned_reward_text":"Review earned a reward for future purchase","product_review_widget_per_page":6,"widget_other_languages_reviews_per_page":3,"widget_store_review_label_text":"Review about the store","widget_cart_mode_aggregate_heading_text":"Customers rate this store","checkout_comment_extension_title_on_product_page":"Customer Comments","checkout_comment_extension_num_latest_comment_show":5,"checkout_comment_extension_format":"name_and_timestamp","checkout_comment_customer_name":"last_initial","checkout_comment_comment_notification":true,"preview_badge_collection_page_install_preference":false,"preview_badge_home_page_install_preference":false,"preview_badge_product_page_install_preference":false,"review_widget_install_preference":"","review_carousel_install_preference":false,"floating_reviews_tab_install_preference":"none","verified_reviews_count_badge_install_preference":false,"all_reviews_text_install_preference":false,"review_widget_best_location":false,"judgeme_medals_install_preference":false,"review_widget_revamp_enabled":false,"review_widget_qna_enabled":false,"review_widget_header_theme":"minimal","review_widget_widget_title_enabled":true,"review_widget_header_text_size":"medium","review_widget_header_text_weight":"regular","review_widget_average_rating_style":"compact","review_widget_bar_chart_enabled":true,"review_widget_bar_chart_type":"numbers","review_widget_bar_chart_style":"standard","review_widget_expanded_media_gallery_enabled":false,"review_widget_show_review_highlights":false,"review_widget_show_review_keywords_in_gray":false,"review_widget_reviews_section_theme":"standard","review_widget_image_style":"thumbnails","review_widget_review_image_ratio":"square","review_widget_stars_size":"medium","review_widget_verified_badge":"standard_text","review_widget_review_title_text_size":"medium","review_widget_review_text_size":"medium","review_widget_review_text_length":"medium","review_widget_number_of_columns_desktop":3,"review_widget_carousel_transition_speed":5,"review_widget_custom_questions_answers_display":"always","review_widget_card_section_size":"small","review_widget_button_text_color":"#FFFFFF","review_widget_text_color":"#000000","review_widget_lighter_text_color":"#7B7B7B","review_widget_corner_styling":"soft","review_widget_review_word_singular":"review","review_widget_review_word_plural":"reviews","review_widget_voting_label":"Helpful?","review_widget_shop_reply_label":"Reply from {{ shop_name }}:","review_widget_filters_title":"Filters","review_widget_filter_rating_title":"Rating","review_widget_filter_keyword_title":"Keyword","review_widget_clear_filters_text":"Clear filters","review_widget_expand_more_text":"More","review_widget_review_highlights_title":"Review highlights","qna_widget_question_word_singular":"Question","qna_widget_question_word_plural"
621:"Questions","qna_widget_answer_reply_label":"Answer from {{ answerer_name }}:","qna_content_screen_title_text":"Ask a question about this product","qna_widget_question_required_field_error_text":"Please enter your question.","qna_widget_flow_gdpr_statement":"We'll only contact you about your question if necessary. By submitting your question, you agree to our \u003ca href='https://judge.me/terms' target='_blank' rel='nofollow noopener'\u003eterms and conditions\u003c/a\u003e and \u003ca href='https://judge.me/privacy' target='_blank' rel='nofollow noopener'\u003eprivacy policy\u003c/a\u003e.","qna_widget_question_submitted_text":"Thanks for your question!","qna_widget_close_form_text_question":"Close","qna_widget_question_submit_success_text":"Weâll notify you by email when your question is answered.","all_reviews_widget_v2025_enabled":false,"all_reviews_widget_v2025_header_theme":"default","all_reviews_widget_v2025_widget_title_enabled":true,"all_reviews_widget_v2025_header_text_size":"medium","all_reviews_widget_v2025_header_text_weight":"regular","all_reviews_widget_v2025_average_rating_style":"compact","all_reviews_widget_v2025_bar_chart_enabled":true,"all_reviews_widget_v2025_bar_chart_type":"numbers","all_reviews_widget_v2025_bar_chart_style":"standard","all_reviews_widget_v2025_expanded_media_gallery_enabled":false,"all_reviews_widget_v2025_show_store_medals":true,"all_reviews_widget_v2025_show_photo_gallery":true,"all_reviews_widget_v2025_show_review_keywords":false,"all_reviews_widget_v2025_show_ai_summary":false,"all_reviews_widget_v2025_show_ai_summary_bg":false,"all_reviews_widget_v2025_show_review_highlights":false,"all_reviews_widget_v2025_show_review_keywords_in_gray":false,"all_reviews_widget_v2025_add_search_bar":false,"all_reviews_widget_v2025_default_sort_method":"most-recent","all_reviews_widget_v2025_reviews_per_page":10,"all_reviews_widget_v2025_reviews_section_theme":"default","all_reviews_widget_v2025_image_style":"thumbnails","all_reviews_widget_v2025_review_image_ratio":"square","all_reviews_widget_v2025_stars_size":"medium","all_reviews_widget_v2025_verified_badge":"standard_text","all_reviews_widget_v2025_review_title_text_size":"medium","all_reviews_widget_v2025_review_text_size":"medium","all_reviews_widget_v2025_review_text_length":"medium","all_reviews_widget_v2025_number_of_columns_desktop":3,"all_reviews_widget_v2025_carousel_transition_speed":5,"all_reviews_widget_v2025_custom_questions_answers_display":"always","all_reviews_widget_v2025_review_dates":false,"all_reviews_widget_v2025_card_section_size":"small","all_reviews_widget_v2025_show_product_variant":false,"all_reviews_widget_v2025_show_reviewer_avatar":true,"all_reviews_widget_v2025_reviewer_name_as_initial":"","all_reviews_widget_v2025_review_location_show":false,"all_reviews_widget_v2025_location_format":"","all_reviews_widget_v2025_show_country_flag":false,"all_reviews_widget_v2025_widget_thumb":false,"all_reviews_widget_v2025_verified_by_shop_badge_style":"light","all_reviews_widget_v2025_social_share":false,"all_reviews_widget_v2025_social_share_options_order":"Facebook,Twitter,LinkedIn,Pinterest","all_reviews_widget_v2025_pagination_type":"standard","all_reviews_widget_v2025_button_text_color":"#FFFFFF","all_reviews_widget_v2025_text_color":"#000000","all_reviews_widget_v2025_lighter_text_color":"#7B7B7B","all_reviews_widget_v2025_corner_styling":"soft","all_reviews_widget_v2025_title":"Customer reviews","all_reviews_widget_v2025_ai_summary_title":"Customers say about this store","all_reviews_widget_v2025_no_review_text":"Be the first to write a review","all_reviews_widget_v2025_review_highlights_title":"Review highlights","reviews_grid_widget_show_sample_reviews":false,"reviews_grid_widget_review_selection":"all","reviews_grid_widget_select_products":[],"reviews_grid_widget_show_media_only":false,"reviews_grid_widget_display_order":"media_first","reviews_grid_widget_card_grouping":"per_media","reviews_grid_widget_columns_desktop":3,"reviews_grid_widget_rows_desktop":3,"reviews_grid_widget_columns_mobile":2,"reviews_grid_widget_rows_mobile":6,"reviews_grid_widget_show_stars":true,"reviews_grid_widget_show_reviewer_name":true,"reviews_grid_widget_show_review_title_on_hover_desktop":true,"reviews_grid_widget_corner_styling":"soft","reviews_grid_widget_card_spacing":"medium","reviews_grid_widget_header_text_color":"#000000","reviews_grid_widget_star_and_reviewer_name_color":"#F9F9F9","reviews_grid_widget_overlay_and_background_color":"#000000","reviews_grid_widget_content_color":"#F9F9F9","reviews_grid_widget_header_text":"From our customers","reviews_grid_widget_show_average_rating":true,"trust_badge_enabled":false,"trust_badge_structure":"outline","trust_badge_color":"black","trust_badge_star":"black","trust_badge_rating_display_default":"show_avg_text","platform":"shopify","branding_url":"https://app.judge.me/reviews","branding_text":"Powered by Judge.me","locale":"en","reply_name":"Revitin","shop_currency":"USD","widget_version":"3.0","footer":true,"autopublish":true,"review_dates":true,"enable_custom_form":false,"shop_locale":"en","enable_multi_locales_translations":true,"show_review_title_input":true,"autofill_review_title":true,"review_verification_email_status":"always","require_verification_before_submit":false,"sign_in_with_
621shop_enabled":false,"customer_account_validation_enabled":true,"most_relevant_sort_enabled":false,"coupon_promo_invited_eligible":true,"coupon_promo_web_eligible":false,"uses_coupon_integration":false,"uses_external_coupon":false,"can_be_branded":true,"rtl_stars_enabled_ar":true,"rtl_stars_enabled_he":true,"reply_name_text":"Revitin"};</script>
621 <style class='jdgm-settings-style'>.jdgm-xx{left:0}:root{--jdgm-primary-color: #FFDEA3;--jdgm-secondary-color: rgba(255,222,163,0.1);--jdgm-star-color: #7E8F72;--jdgm-write-review-text-color: #5F471D;--jdgm-write-review-bg-color: #FFDEA3;--jdgm-paginate-color: #FFDEA3;--jdgm-border-radius: 0;--jdgm-reviewer-name-color: #5F471D}.jdgm-histogram__bar-content{background-color:#5F471D}.jdgm-rev[data-verified-buyer=true] .jdgm-rev__icon.jdgm-rev__icon:after,.jdgm-rev__buyer-badge.jdgm-rev__buyer-badge{color:white;background-color:#FFDEA3}.jdgm-review-widget--small .jdgm-gallery.jdgm-gallery .jdgm-gallery__thumbnail-link:nth-child(8) .jdgm-gallery__thumbnail-wrapper.jdgm-gallery__thumbnail-wrapper:before{content:"See more"}@media only screen and (min-width: 768px){.jdgm-gallery.jdgm-gallery .jdgm-gallery__thumbnail-link:nth-child(8) .jdgm-gallery__thumbnail-wrapper.jdgm-gallery__thumbnail-wrapper:before{content:"See more"}}.jdgm-preview-badge .jdgm-star.jdgm-star{color:#7E8F72}.jdgm-prev-badge[data-average-rating='0.00']{display:none !important}.jdgm-rev .jdgm-rev__icon{display:none !important}.jdgm-author-all-initials{display:none !important}.jdgm-author-last-initial{display:none !important}.jdgm-rev-widg__title{visibility:hidden}.jdgm-rev-widg__summary-text{visibility:hidden}.jdgm-prev-badge__text{visibility:hidden}.jdgm-rev__prod-link-prefix:before{content:'about'}.jdgm-rev__variant-label:before{content:'Variant: '}.jdgm-rev__out-of-store-text:before{content:'(out of store)'}@media only screen and (min-width: 768px){.jdgm-rev__pics .jdgm-rev_all-rev-page-picture-separator,.jdgm-rev__pics .jdgm-rev__product-picture{display:none}}@media only screen and (max-width: 768px){.jdgm-rev__pics .jdgm-rev_all-rev-page-picture-separator,.jdgm-rev__pics .jdgm-rev__product-picture{display:none}}.jdgm-preview-badge[data-template="product"]{display:none !important}.jdgm-preview-badge[data-template="collection"]{display:none !important}.jdgm-preview-badge[data-template="index"]{display:none !important}.jdgm-review-widget[data-from-snippet="true"]{display:none !important}.jdgm-verified-count-badget[data-from-snippet="true"]{display:none !important}.jdgm-carousel-wrapper[data-from-snippet="true"]{display:none !important}.jdgm-all-reviews-text[data-from-snippet="true"]{display:none !important}.jdgm-medals-section[data-from-snippet="true"]{display:none !important}.jdgm-ugc-media-wrapper[data-from-snippet="true"]{display:none !important}.jdgm-rev__transparency-badge[data-badge-type="review_collected_via_store_invitation"]{display:none !important}.jdgm-rev__transparency-badge[data-badge-type="review_collected_from_another_provider"]{display:none !important}.jdgm-rev__transparency-badge[data-badge-type="review_collected_from_store_visitor"]{display:none !important}.jdgm-rev__transparency-badge[data-badge-type="review_earned_for_future_purchase"]{display:none !important}.jdgm-review-snippet-widget{--jdgm-snippet-card-color: #fff;--jdgm-snippet-text-color: #000;--jdgm-snippet-lighter-text-color: #7B7B7B;--jdgm-snippet-star-color: #FFDEA3;--jdgm-snippet-border-radius: 8px;--jdgm-snippet-arrows-bg-color: #fff;--jdgm-snippet-arrows-color: #000}.jdgm-review-snippet-widget .jdgm-rev-snippet-widget__cards-container .jdgm-rev-snippet-card{border-radius:8px;background:#fff}.jdgm-review-snippet-widget .jdgm-rev-snippet-widget__cards-container .jdgm-rev-snippet-card__rev-rating .jdgm-star{color:#FFDEA3}.jdgm-review-snippet-widget .jdgm-rev-snippet-widget__prev-btn,.jdgm-review-snippet-widget .jdgm-rev-snippet-widget__next-btn{border-radius:50%;background:#fff}.jdgm-review-snippet-widget .jdgm-rev-snippet-widget__prev-btn>svg,.jdgm-review-snippet-widget .jdgm-rev-snippet-widget__next-btn>svg{fill:#000}.jdgm-full-rev-modal.rev-snippet-widget .jm-mfp-container .jm-mfp-content,.jdgm-full-rev-modal.rev-snippet-widget .jm-mfp-container .jdgm-full-rev__icon,.jdgm-full-rev-modal.rev-snippet-widget .jm-mfp-container .jdgm-full-rev__pic-img,.jdgm-full-rev-modal.rev-snippet-widget .jm-mfp-container .jdgm-full-rev__reply{border-radius:8px}.jdgm-full-rev-modal.rev-snippet-widget .jm-mfp-container .jdgm-full-rev[data-verified-buyer="true"] .jdgm-full-rev__icon::after{border-radius:8px}.jdgm-full-rev-modal.rev-snippet-widget .jm-mfp-container .jdgm-full-rev .jdgm-rev__buyer-badge{border-radius:calc( 8px / 2 )}.jdgm-full-rev-modal.rev-snippet-widget .jm-mfp-container .jdgm-full-rev .jdgm-full-rev__replier::before{content:'Revitin'}.jdgm-full-rev-modal.rev-snippet-widget .jm-mfp-container .jdgm-full-rev .jdgm-full-rev__product-button{border-radius:calc( 8px * 6 )} 622</style> <style class='jdgm-settings-style'>.jdgm-review-widget .jdgm-rev-widg{max-width:1200px;margin-left:auto;margin-right:auto}.jdgm-review-widget .jdgm-rev-widg__header .jdgm-row-stars{justify-content:space-between !important}@media (min-width: 768px){.jdgm-review-widget .jdgm-rev-widg{padding-left:2.5rem;padding-right:2.5rem}}@media only screen and (min-width: 992px){.jdgm-review-widget .jdgm-rev-widg__title{text-align:left}.jdgm-review-widget .jdgm-rev-widg__summary,.jdgm-review-widget .jdgm-widget-actions-wrapper{width:auto !important}.jdgm-review-widget .jdgm-histogram{width:55% !important;align-items:flex-start !important}}.jdgm-preview-badge span.jdgm-prev-badge__stars{font-size:11px}.jdgm-preview-badge .jdgm-prev-badge__text{font-size:15px;margin-left:5px;color:#7e8f72}.jdgm-preview-badge .jdgm-preview-badge .jdgm-star.jdgm-star{margin:0 2px !important} 623</style> 624 625 626 627 628 <style class='jdgm-miracle-styles'> 629 @-webkit-keyframes jdgm-spin{0%{-webkit-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);-ms-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes jdgm-spin{0%{-webkit-transform:rotate(0deg);-ms-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);-ms-transform:rotate(359deg);transform:rotate(359deg)}}@font-face{font-family:'JudgemeStar';src:url("data:application/x-font-woff;charset=utf-8;base64,d09GRgABAAAAAAScAA0AAAAABrAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAAEgAAAABoAAAAcbyQ+3kdERUYAAARgAAAAHgAAACAAMwAGT1MvMgAAAZgAAABGAAAAVi+vS9xjbWFwAAAB8AAAAEAAAAFKwBMjvmdhc3AAAARYAAAACAAAAAj//wADZ2x5ZgAAAkAAAAEJAAABdH33LXtoZWFkAAABMAAAAC0AAAA2BroQKWhoZWEAAAFgAAAAHAAAACQD5QHQaG10eAAAAeAAAAAPAAAAFAYAAABsb2NhAAACMAAAAA4AAAAOAO4AeG1heHAAAAF8AAAAHAAAACAASgAvbmFtZQAAA0wAAADeAAABkorWfVZwb3N0AAAELAAAACkAAABEp3ubLXgBY2BkYADhPPP4OfH8Nl8ZuJkYQODS2fRrCPr/aSYGxq1ALgcDWBoAO60LkwAAAHgBY2BkYGDc+v80gx4TAwgASaAICmABAFB+Arl4AWNgZGBgYGPQYWBiAAIwyQgWc2AAAwAHVQB6eAFjYGRiYJzAwMrAwejDmMbAwOAOpb8ySDK0MDAwMbByMsCBAAMCBKS5pjA4PGB4wMR44P8BBj3GrQymQGFGkBwAjtgK
629/gAAeAFjYoAAEA1jAwAAZAAHAHgB3crBCcAwDEPRZydkih567CDdf4ZskmLwFBV8xBfCaC4BXkOUmx4sU0h2ngNb9V0vQCxaRKIAevT7fGWuBrEAAAAAAAAAAAA0AHgAugAAeAF9z79Kw1AUx/FzTm7un6QmJtwmQ5Bg1abgEGr/BAqlU6Gju+Cgg1MkQ/sA7Vj7BOnmO/gUvo2Lo14NqIO6/IazfD8HEODtmQCfoANwNsyp2/GJt3WKQrd1NLiYYWx2PBqOsmJMEOznPOTzfSCrhAtbbLdmeFLJV9eKd63WLrZcIcuaEVdssWCKM6pLCfTVOYbz/0pNSMSZKLIZpvh78sAUH6PlMrreTCabP9r+Z/puPZ2ur/RqpQHgh+MIegCnXeM4MRAPjYN//5tj4ZtTjkFqEdmeMShlEJ7tVAly2TAkx6R68Fl4E/aVvn8JqHFQ4JS1434gXKcuL31dDhzs3YbsEOAd/IU88gAAAHgBfY4xTgMxEEVfkk0AgRCioKFxQYd2ZRtpixxgRU2RfhU5q5VWseQ4JdfgAJyBlmNwAM7ABRhZQ0ORwp7nr+eZAa54YwYg9zm3ynPOeFRe8MCrciXOh/KSS76UV5L/iDmrLiS5AeU519wrL3jmSbkS5115yR2fyivJv9kx0ZMZ2RLZw27q87iNQi8EBo5FSPIMw3HqBboi5lKTGAGDp8FKXWP+t9TU01Lj5His1Ba6uM9dTEMwvrFmbf5GC/q2drW3ruXUhhsCiQOjznFlCzYhHUZp4xp76vsvQh89CQAAeAFjYGJABowM6IANLMrEyMTIzMjCXpyRWJBqZshWXJJYBKOMAFHFBucAAAAAAAAB//8AAngBY2BkYGDgA2IJBhBgAvKZGViBJAuYxwAABJsAOgAAeAFjYGBgZACCk535hiD60tn0azAaAEqpB6wAAA==") format("woff");font-weight:normal;font-style:normal}.jdgm-star{font-family:'JudgemeStar';display:inline !important;text-decoration:none !important;padding:0 4px 0 0 !important;margin:0 !important;font-weight:bold;opacity:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.jdgm-star:hover{opacity:1}.jdgm-star:last-of-type{padding:0 !important}.jdgm-star.jdgm--on:before{content:"\e000"}.jdgm-star.jdgm--off:before{content:"\e001"}.jdgm-star.jdgm--half:before{content:"\e002"}.jdgm-widget *{margin:0;line-height:1.4;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-overflow-scrolling:touch}.jdgm-hidden{display:none !important;visibility:hidden !important}.jdgm-temp-hidden{display:none}.jdgm-spinner{width:40px;height:40px;margin:auto;border-radius:50%;border-top:2px solid #eee;border-right:2px solid #eee;border-bottom:2px solid #eee;border-left:2px solid #ccc;-webkit-animation:jdgm-spin 0.8s infinite linear;animation:jdgm-spin 0.8s infinite linear}.jdgm-spinner:empty{display:block}.jdgm-prev-badge{display:block !important} 630 631</style> 632 633 634 635 636 637 638 639 640
641<script data-cfasync='false' class='jdgm-script'> 642!function(e){window.jdgm=window.jdgm||{}; 643/* INF-1976 */ 644var _jdgmBlocked=function(){var raw=(window.jdgmSettings||{}).hostname_allowlist;var list=(raw==null?"":""+raw).split(/[\s,]+/).map(function(h){return h.trim().toLowerCase().replace(/\.$/,"");}).filter(function(h){return h;});if(!list.length)return false;var host=(e.location.hostname||"").toLowerCase().replace(/\.$/,"");if(/(^|\.)shopifypreview\.com$/.test(host))return false;var bare=host.replace(/^www\./,"");for(var i=0;i<list.length;i++){var en=list[i];if(en.indexOf("*.")===0){var b=en.slice(2);if(host===b||host.slice(-(b.length+1))==="."+b)return false;}else if(bare===en.replace(/^www\./,""))return false;}return true;}(); 645if(_jdgmBlocked){jdgm._loaderExecuted=true;jdgm._blocked=true;var _jdgmS=e.createElement("style");_jdgmS.textContent='[class^="jdgm-"],[class*=" jdgm-"]{display:none !important}';(e.head||e.documentElement).appendChild(_jdgmS);return;} 646jdgm.CDN_HOST="https://cdnwidget.judge.me/",jdgm.CDN_HOST_ALT="https://cdn2.judge.me/cdn/widget_frontend/",jdgm.API_HOST="https://api.judge.me/",jdgm.CDN_BASE_URL="https://cdn.shopify.com/extensions/01a0f14c-14c3-7c54-8630-ec498be121ab/judgeme-770/assets/",jdgm.CDN_API_HOST="https://cdn.judge.me/", 647jdgm.docReady=function(d){(e.attachEvent?"complete"===e.readyState:"loading"!==e.readyState)? 648setTimeout(d,0):e.addEventListener("DOMContentLoaded",d)},jdgm.loadCSS=function(d,t,o,a){ 649!o&&jdgm.loadCSS.requestedUrls.indexOf(d)>=0||(jdgm.loadCSS.requestedUrls.push(d), 650(a=e.createElement("link")).rel="stylesheet",a.class="jdgm-stylesheet",a.media="nope!", 651a.href=d,a.onload=function(){this.media="all",t&&setTimeout(t)},e.body.appendChild(a))}, 652jdgm.loadCSS.requestedUrls=[],jdgm.loadJS=function(e,d){var t=new XMLHttpRequest; 653t.onreadystatechange=function(){4===t.readyState&&t.status>=200&&t.status<300&&(Function(t.response)(),d&&d(t.response))}, 654t.open("GET",e),t.onerror=function(){if(e.indexOf(jdgm.CDN_HOST)===0&&jdgm.CDN_HOST_ALT!==jdgm.CDN_HOST){var f=e.replace(jdgm.CDN_HOST,jdgm.CDN_HOST_ALT);jdgm.loadJS(f,d)}},t.send()},jdgm.docReady((function(){(window.jdgmLoadCSS||e.querySelectorAll( 655".jdgm-widget, .jdgm-all-reviews-page").length>0)&&(jdgmSettings.widget_load_with_code_splitting? 656parseFloat(jdgmSettings.widget_version)>=3?jdgm.loadCSS(jdgm.CDN_BASE_URL+"widget_v3_base.css"): 657jdgm.loadCSS(jdgm.CDN_BASE_URL+"widget_base.css"):jdgm.loadCSS(jdgm.CDN_BASE_URL+"shopify_v2.css") 658)}))}(document); 659</script>
659 660<noscript><link rel="stylesheet" type="text/css" media="all" href="https://cdn.shopify.com/extensions/01a0f14c-14c3-7c54-8630-ec498be121ab/judgeme-770/assets/shopify_v2.css"></noscript> 661 662<!-- BEGIN app snippet: theme_fix_tags -->
662<script> 663 (function() { 664 var jdgmThemeFixes = null; 665 if (!jdgmThemeFixes) return; 666 667 // "All themes" fix: CSS and JS applied on every theme. CSS is injected 668 // before the per-theme fix so the theme-specific CSS wins the cascade. 669 // HTML is never applied globally (too risky). 670 var allThemesFix = jdgmThemeFixes['all']; 671 if (allThemesFix && allThemesFix.css) { 672 var allStyleTag = document.createElement('style'); 673 allStyleTag.classList.add('jdgm-theme-fix-style-all'); 674 allStyleTag.innerHTML = allThemesFix.css; 675 document.head.append(allStyleTag); 676 }; 677 678 if (allThemesFix && allThemesFix.js) { 679 var allScriptTag = document.createElement('script'); 680 allScriptTag.classList.add('jdgm-theme-fix-script-all'); 681 allScriptTag.innerHTML = allThemesFix.js; 682 document.head.append(allScriptTag); 683 }; 684 685 var thisThemeFix = jdgmThemeFixes[Shopify.theme.id]; 686 if (!thisThemeFix) return; 687 688 if (thisThemeFix.html) { 689 document.addEventListener("DOMContentLoaded", function() { 690 var htmlDiv = document.createElement('div'); 691 htmlDiv.classList.add('jdgm-theme-fix-html'); 692 htmlDiv.innerHTML = thisThemeFix.html; 693 document.body.append(htmlDiv); 694 }); 695 }; 696 697 if (thisThemeFix.css) { 698 var styleTag = document.createElement('style'); 699 styleTag.classList.add('jdgm-theme-fix-style'); 700 styleTag.innerHTML = thisThemeFix.css; 701 document.head.append(styleTag); 702 }; 703 704 if (thisThemeFix.js) { 705 var scriptTag = document.createElement('script'); 706 scriptTag.classList.add('jdgm-theme-fix-script'); 707 scriptTag.innerHTML = thisThemeFix.js; 708 document.head.append(scriptTag); 709 }; 710 })(); 711</script>
711 712<!-- END app snippet --> 713<!-- End of Judge.me Core --> 714 715 716 717<!-- END app block -->
717<script src="https://cdn.shopify.com/extensions/01a0f14c-14c3-7c54-8630-ec498be121ab/judgeme-770/assets/loader.js" type="text/javascript" defer="defer"></script>
717 718<link href="https://monorail-edge.shopifysvc.com" rel="dns-prefetch">
719<script>(function(){if ("sendBeacon" in navigator && "performance" in window) {try {var session_token_from_headers = performance.getEntriesByType('navigation')[0].serverTiming.find(x => x.name == '_s').description;} catch {var session_token_from_headers = undefined;}var session_cookie_matches = document.cookie.match(/_shopify_s=([^;]*)/);var session_token_from_cookie = session_cookie_matches && session_cookie_matches.length === 2 ? session_cookie_matches[1] : "";var session_token = session_token_from_headers || session_token_from_cookie || "";function handle_abandonment_event(e) {var entries = performance.getEntries().filter(function(entry) {return /monorail-edge.shopifysvc.com/.test(entry.name);});if (!window.abandonment_tracked && entries.length === 0) {window.abandonment_tracked = true;var currentMs = Date.now();var navigation_start = performance.timing.navigationStart;var payload = {shop_id: 37689720970,url: window.location.href,navigation_start,duration: currentMs - navigation_start,session_token,page_type: "product"};window.navigator.sendBeacon("https://monorail-edge.shopifysvc.com/v1/produce", JSON.stringify({schema_id: "online_store_buyer_site_abandonment/1.1",payload: payload,metadata: {event_created_at_ms: currentMs,event_sent_at_ms: currentMs}}));}}window.addEventListener('pagehide', handle_abandonment_event);}}());</script>
vendor: 1 bytes, line 719
719
720<script> 721 window.__TREKKIE_SHIM_QUEUE = window.__TREKKIE_SHIM_QUEUE || []; 722</script>
vendor: 1 bytes, line 722
722
723<script>(function(){var wpmLoader=function(){"use strict";var e=/Googlebot|Storebot-Google|bingbot|Baiduspider|YandexBot|DuckDuckBot|Slurp|facebookexternalhit|Twitterbot|LinkedInBot|Applebot|AdsBot-Google|Mediapartners-Google|APIs-Google|PetalBot|SemrushBot|AhrefsBot|MJ12bot|DotBot|Acunetix|PerplexityBot|Perplexity-User/i,t=/bytedance/i;function i(){try{var e=document.cookie;if(!e||"string"!=typeof e)return;for(var t=0,i=e.split(";");t<i.length;t++){var n=i[t],r=n.indexOf("=");if(-1!==r){var o=n.slice(0,r).trim();if(o){var a=void 0;try{a=decodeURIComponent(o)}catch(e){a=o}if("_shopify_s"===a){var d=n.slice(r+1).trim();try{return decodeURIComponent(d)}catch(e){return d}}}}}return}catch(e){return}}function n(e){try{"undefined"!=typeof console&&"function"==typeof console.warn&&console.warn(e)}catch(e){}}function r(e,t){return"string"==typeof e&&e.length>0&&e.length<=t?e:void 0}function o(e){var t;switch(null==(t=null==e?void 0:e.navigation)?void 0:t.type){case 0:return"navigate";case 1:return"reload";case 2:return"back_forward";default:return}}function a(){var e,t,i;try{var n=null==(i=null==(t=null==(e=self.ShopifyAnalytics)?void 0:e.lib)?void 0:t.trekkie)?void 0:i.state;return"awaiting-consent"===n||"initialized"===n?n:void 0}catch(e){return}}return function(d,s,u,l){var c=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};try{var p=c.trekkieShim;!0!==p&&"true"!==p||null!=window.__TREKKIE_SHIM_QUEUE||(window.__TREKKIE_SHIM_QUEUE=[])}catch(e){}var f,v,h,y,g=(v=(f={modern:/Edge?\/(1{2}[4-9]|1[2-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Firefox\/(1{2}[4-9]|1[2-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Chrom(ium|e)\/(9{2}|\d{3,})\.\d+(\.\d+|)|(Maci|X1{2}).+ Version\/(15\.\d+|(1[6-9]|[2-9]\d|\d{3,})\.\d+)([,.]\d+|)( \(\w+\)|)( Mobile\/\w+|) Safari\/|Chrome.+OPR\/(9{2}|\d{3,})\.\d+\.\d+|(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS|CPU iPad OS)[ +]+(15[._]\d+|(1[6-9]|[2-9]\d|\d{3,})[._]\d+)([._]\d+|)|Android:?[ /-](14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})(\.\d+|)(\.\d+|)|Android.+Firefox\/(15\d|1[6-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Android.+Chrom(ium|e)\/(14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|SamsungBrowser\/([2-9]\d|\d{3,})\.\d+/,legacy:/Edge?\/(1[6-9]|[2-9]\d|\d{3,})\.\d+(\.\d+|)|Firefox\/(5[4-9]|[6-9]\d|\d{3,})\.\d+(\.\d+|)|Chrom(ium|e)\/(5[1-9]|[6-9]\d|\d{3,})\.\d+(\.\d+|)([\d.]+$|.*Safari\/(?![\d.]+ Edge\/[\d.]+$))|(Maci|X1{2}).+ Version\/(10\.\d+|(1[1-9]|[2-9]\d|\d{3,})\.\d+)([,.]\d+|)( \(\w+\)|)( Mobile\/\w+|) Safari\/|Chrome.+OPR\/(3[89]|[4-9]\d|\d{3,})\.\d+\.\d+|(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS|CPU iPad OS)[ +]+(10[._]\d+|(1[1-9]|[2-9]\d|\d{3,})[._]\d+)([._]\d+|)|Android:?[ /-](14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})(\.\d+|)(\.\d+|)|Mobile Safari.+OPR\/([89]\d|\d{3,})\.\d+\.\d+|Android.+Firefox\/(15\d|1[6-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Android.+Chrom(ium|e)\/(14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Android.+(UC? ?Browser|UCWEB|U3)[ /]?(15\.([5-9]|\d{2,})|(1[6-9]|[2-9]\d|\d{3,})\.\d+)\.\d+|SamsungBrowser\/(5\.\d+|([6-9]|\d{2,})\.\d+)|Android.+MQ{2}Browser\/(14(\.(9|\d{2,})|)|(1[5-9]|[2-9]\d|\d{3,})(\.\d+|))(\.\d+|)|K[Aa][Ii]OS\/(3\.\d+|([4-9]|\d{2,})\.\d+)(\.\d+|)/}).modern,h=f.legacy,(y=navigator.userAgent).match(e)?"bot":y.match(v)?"modern":y.match(h)?"legacy":y.match(t)?"bot":"unknown"),m=function(e){var t,i,n=r(e,128);try{var a=window.performance,d=null==(t=null==a?void 0:a.getEntriesByType)?void 0:t.call(a,"navigation")[0];if(!d)return{requestId:n,navigationType:o(a)};var s="type"in d?r(d.type,64):void 0,u="serverTiming"in d&&Array.isArray(d.serverTiming)?d.serverTiming:[];return{requestId:null!=n?n:r(null==(i=u.find(function(e){return"requestID"===e.name}))?void 0:i.description,128),navigationType:s}}catch(e){return{requestId:n}}}(c.requestId),w=function(e){var t=e.version,r=e.browserTarget,o=e.surface,a=e.shopId,d=e.monorailEndpoint,s=window.location.href;return{emit:function(e){var u=e.status,l=e.errorMsg,c=e.failureReason,p=e.useKeepaliveFallback,f=void 0!==p&&p,v=e.navigationType,h=e.pagehidePersisted,y=e.requestId,g=e.trekkieState;if(d){var m,w;try{var b=(new Date).getTime();m=JSON.stringify({metadata:{event_sent_at_ms:b},events:[{schema_id:"web_pixels_manager_load/3.3",payload:{version:t,bundle_target:r,page_url:s,status:u,surface:o,error_msg:l,failure_reason:c,navigation_type:v,pagehide_persisted:h,request_id:y,trekkie_state:g,shop_id:a,visit_token:i()},metadata:{event_created_at_ms:b}}]})}catch(e){return}try{if("function"==typeof window.navigator.sendBeacon&&-1===(w=window.navigator.userAgent).indexOf("iPhone; CPU iPhone OS 12_")&&-1===w.indexOf("iPad; CPU OS 12_")&&-1===w.indexOf("iPod touch; CPU iPhone OS 12_")&&window.navigator.sendBeacon.bind(window.navigator)(d,m))return}catch(e){}if(f)try{"function"==typeof window.fetch&&window.fetch(d,{method:"POST",headers:{"Content-Type":"text/plain"},body:m,keepalive:!0}
723).catch(function(){})}catch(e){}else try{var _=new XMLHttpRequest;_.open("POST",d,!0),_.setRequestHeader("Content-Type","text/plain"),_.send(m)}catch(e){n("[Web Pixels Manager] Got an unhandled error while logging to Monorail.")}}else n("[Web Pixels Manager] No Monorail endpoint provided, skipping logging.")}}}({version:u,browserTarget:g,surface:d.surface,shopId:d.shopId,monorailEndpoint:d.monorailEndpoint});if(Boolean(null==(_=null==(b=window.Shopify)?void 0:b.analytics)?void 0:_.replayQueue))w.emit({status:"setup-skipped",errorMsg:"replay queue already initialized."});else{var b,_;w.emit({status:"setup-started"}),window.Shopify=window.Shopify||{};var S=window.Shopify;S.analytics=S.analytics||{};var P=S.analytics;P.replayQueue=[],P.publish=function(e,t,i){return P.replayQueue.push([e,t,i]),!0};try{self.performance.mark("wpm:start")}catch(e){}var k,C="modern"===g?"modern":"legacy",E=(null!=l?l:{modern:"",legacy:""})[C],I=[(k={baseUrl:s,hashVersion:u,buildTarget:C}).baseUrl,"/wpm","/b",k.hashVersion,"modern"===k.buildTarget?"m":"l",".js"].join(""),O=!1,T=!1;try{c.browserTarget=g,function(){O=!0;try{window.addEventListener("pagehide",M)}catch(e){O=!1}}(),R(function(){try{R(x)}catch(e){D(e)}}),w.emit({status:"loading",requestId:m.requestId,navigationType:m.navigationType,trekkieState:a()})}catch(e){D(e)}}function U(){var e;if(q(),!function(){var e,t;return Boolean(null==(t=null==(e=window.Shopify)?void 0:e.analytics)?void 0:t.initialized)}()){var t,i,n;try{if("function"!=typeof(null==(e=window.webPixelsManager)?void 0:e.init))return void A();if(!(null!==(n=i=t=window.webPixelsManager.init(d))&&"function"!=typeof n&&Object(n)===n&&"publish"in i&&"function"==typeof i.publish&&"publishCustomEvent"in i&&"function"==typeof i.publishCustomEvent&&"visitor"in i&&"function"==typeof i.visitor))return void A()}catch(e){return void A(e)}var r=window.Shopify.analytics;r.replayQueue.forEach(function(e){var i=e[0],n=e[1],r=e[2];t.publishCustomEvent(i,n,r)}),r.replayQueue=[],r.publish=t.publishCustomEvent,r.visitor=t.visitor,r.initialized=!0}}function A(e){B("manager_api_unavailable",void 0===e?void 0:Q(e))}function x(){B("script_load_failed","".concat(I," has failed to load"))}function B(e,t){T||(T=!0,q(),w.emit({status:"failed",errorMsg:t,failureReason:e,requestId:m.requestId,navigationType:m.navigationType,trekkieState:a()}))}function M(e){O&&(q(),w.emit({status:"pagehide-while-loading",useKeepaliveFallback:!0,pagehidePersisted:e.persisted,requestId:m.requestId,navigationType:m.navigationType,trekkieState:a()}))}function q(){O=!1;try{window.removeEventListener("pagehide",M)}catch(e){}}function R(e){var t;!function(e){var t=e.src,i=e.async,n=void 0===i||i,r=e.onload,o=e.onerror,a=e.sri,d=e.scriptDataAttributes,s=void 0===d?{}:d,u=document.createElement("script"),l=document.querySelector("head"),c=document.querySelector("body");if(u.async=n,u.src=t,a&&(u.integrity=a,u.crossOrigin="anonymous"),s)for(var p in s)if(Object.prototype.hasOwnProperty.call(s,p))try{u.dataset[p]=String(s[p])}catch(e){}if(r&&u.addEventListener("load",r),o&&u.addEventListener("error",o),l)l.appendChild(u);else{if(!c)throw new Error("Did not find a head or body element to append the script");c.appendChild(u)}}({src:I,async:!0,onload:U,onerror:e,sri:(t=E,"string"==typeof t&&/^sha384-[A-Za-z0-9+/=]+$/.test(t)?E:""),scriptDataAttributes:c})}function D(e){B("script_append_failed",Q(e))}function Q(e){return e instanceof Error?e.message:"Unknown error"}}}();wpmLoader({shopId: 37689720970,storefrontBaseUrl: "https://revitin.com",extensionsBaseUrl: "https://extensions.shopifycdn.com/cdn/shopifycloud/web-pixels-manager",monorailEndpoint: "https://revitin.com/.well-known/shopify/monorail/unstable/produce_batch",surface: "storefront-renderer",enabledBetaFlags: ["4c64608a","16072cab","8450a54b","7ee89bf1"],webPixelsConfigList: [{"id":"2540273802","configuration":"{\"pixelCode\":\"D86B8BRC77U37PM8G87G\"}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"22e92c2ad45662f435e4801458fb78cc","type":"APP","apiClientId":4383523,"privacyPurposes":["ANALYTICS","MARKETING","SALE_OF_DATA"],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_address","read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]},"dataSharingState":"optimized"},{"id":"2094989450","configuration":"{}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"f92d7cfd1521456d481ee553d236893f","type":"APP","apiClientId":30400643073,"privacyPurposes":["ANALYTICS"],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_address","read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]}
723,"dataSharingState":"unrestricted"},{"id":"1953923210","configuration":"{\"shopId\":\"revitin.myshopify.com\"}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"7093dff47f098f6de2afb75b62011ebe","type":"APP","apiClientId":2753413,"privacyPurposes":["ANALYTICS","MARKETING"],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_address","read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]},"dataSharingState":"optimized"},{"id":"1474461834","configuration":"{\"debug\":\"false\"}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"a9a83cf44fb282052ff936f7ab101058","type":"APP","apiClientId":4539653,"privacyPurposes":["ANALYTICS"],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_address","read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]},"dataSharingState":"unrestricted"},{"id":"1439137930","configuration":"{\"accountID\":\"YmxebZ\",\"webPixelConfig\":\"eyJlbmFibGVBZGRlZFRvQ2FydEV2ZW50cyI6IHRydWV9\"}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"c63c5b72c8d77be5f2d27d14c081da38","type":"APP","apiClientId":123074,"privacyPurposes":["ANALYTICS","MARKETING"],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_address","read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]},"dataSharingState":"optimized","enabledFlags":["9a3ed68a"]},{"id":"1161724042","configuration":"{\"projectId\":\"rbrmbn89qv\"}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"d8a2bb2ccbb513dc8e8b6937f4b8033e","type":"APP","apiClientId":240074326017,"privacyPurposes":[],"capabilities":["advanced_dom_events"],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_personal_data"],"dataSharingControls":["share_all_events"]},"dataSharingState":"unrestricted"},{"id":"880607370","configuration":"{\"webPixelName\":\"Judge.me\"}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"8acc938b1a30dc7624e304493ca567d7","type":"APP","apiClientId":683015,"privacyPurposes":["ANALYTICS"],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]},"dataSharingState":"unrestricted"},{"id":"880476298","configuration":"{\"shop\":\"revitin.myshopify.com\", \"shopliftUrl\":\"https:\/\/events.shoplift.ai\/api\/events\"}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"dabcda9558be25394b12ce3ce899568b","type":"APP","apiClientId":7521861633,"privacyPurposes":["ANALYTICS"],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_address","read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]},"dataSharingState":"unrestricted"},{"id":"752156810","configuration":"{\"config\":\"{\\\"google_tag_ids\\\":[\\\"AW-16882923746\\\",\\\"GT-K522JRNQ\\\"],\\\"target_country\\\":\\\"US\\\",\\\"gtag_events\\\":[{\\\"type\\\":\\\"begin_checkout\\\",\\\"action_label\\\":\\\"AW-16882923746\\\/uL1iCIXCp6oaEOLxs_I-\\\"},{\\\"type\\\":\\\"search\\\",\\\"action_label\\\":\\\"AW-16882923746\\\/Dg4iCInDp6oaEOLxs_I-\\\"},{\\\"type\\\":\\\"view_item\\\",\\\"action_label\\\":[\\\"AW-16882923746\\\/9MT5CI7Cp6oaEOLxs_I-\\\",\\\"MC-W1XEHCZVPX\\\"]},{\\\"type\\\":\\\"purchase\\\",\\\"action_label\\\":[\\\"AW-16882923746\\\/kcG4CILCp6oaEOLxs_I-\\\",\\\"MC-W1XEHCZVPX\\\"]},{\\\"type\\\":\\\"page_view\\\",\\\"action_label\\\":[\\\"AW-16882923746\\\/y5QNCIvCp6oaEOLxs_I-\\\",\\\"MC-W1XEHCZVPX\\\"]},{\\\"type\\\":\\\"add_payment_info\\\",\\\"action_label\\\":\\\"AW-16882923746\\\/nU05CIzDp6oaEOLxs_I-\\\"},{\\\"type\\\":\\\"add_to_cart\\\",\\\"action_label\\\":\\\"AW-16882923746\\\/Ua8GCIjCp6oaEOLxs_I-\\\"}],\\\"enable_monitoring_mode\\\":false}\"}","eventPayloadVersion":"v1","runtimeContext":"OPEN","scriptVersion":"a3321ca85cf5aaf6b57585fcd8d67b3a","type":"APP","apiClientId":1780363,"privacyPurposes":[],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_address","read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]},"dataSharingState":"optimized","enabledFlags":["9a3ed68a"]},{"id":"585957514","configuration":"{\"masterTagID\":\"19038\",\"merchantID\":\"65308\",\"appPath\":\"https:\/\/daedalus.shareasale.com\",\"storeID\":\"NaN\",\"xTypeMode\":\"NaN\",\"xTypeValue\":\"NaN\",\"channelDedup\":\"NaN\"}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"f300cca684872f2df140f714437af558","type":"APP","apiClientId":4929191,"privacyPurposes":["ANALYTICS","MARKETING"],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_personal_data"],"dataSharingControls":["share_all_events"]},"dataSharingState":"optimized"},{"id":"494829706","configuration":"{\"pixel_id\":\"1036206484636196\",\"pixel_type\":\"facebook_pixel\"}","eventPayloadVersion":"v1","runtimeContext":"OPEN","scriptVersion":"96420dbe9ea96c426a1b7f364f977719","type":"APP","apiClientId":2329312,"privacyPurposes":["ANALYTICS","MARKETING","SALE_OF_DATA"],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_address","read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]},"dataSharingState":"optimized","enabledFlags":["9a3ed68a"]},{"id":"67666058","eventPayloadVersion":"v1","runtimeContext":"LAX","scriptVersion":"1","type":"CUSTOM","privacyPurposes":["ANALYTICS"],"name":"Google Analytics tag (migrated)","dataSharingAdjustments":{"protectedCustomerApprovalScopes":[],"dataSharingControls":["share_all_events"]},"dataSharingState":"optimized"}
723,{"id":"159023242","eventPayloadVersion":"1","runtimeContext":"LAX","scriptVersion":"4","type":"CUSTOM","privacyPurposes":["ANALYTICS","MARKETING","SALE_OF_DATA"],"name":"Add Shipping Info Event","dataSharingAdjustments":{"protectedCustomerApprovalScopes":[],"dataSharingControls":["share_all_events"]},"dataSharingState":"optimized"},{"id":"shopify-app-pixel","configuration":"{}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"0530","apiClientId":"shopify-pixel","type":"APP","privacyPurposes":["ANALYTICS","MARKETING"]},{"id":"shopify-custom-pixel","eventPayloadVersion":"v1","runtimeContext":"LAX","scriptVersion":"0530","apiClientId":"shopify-pixel","type":"CUSTOM","privacyPurposes":["ANALYTICS","MARKETING"]}],isMerchantRequest: false,initData: {"shop":{"name":"Revitin","paymentSettings":{"currencyCode":"USD"},"myshopifyDomain":"revitin.myshopify.com","countryCode":"US","storefrontUrl":"https:\/\/revitin.com"},"customer":null,"cart":null,"checkout":null,"productVariants":[{"price":{"amount":17.0,"currencyCode":"USD"},"product":{"title":"Revitin Toothpaste Single Tube","vendor":"Revitin® Natural Toothpaste","id":"6606432174218","untranslatedTitle":"Revitin Toothpaste Single Tube","url":"\/products\/revitin-natural-toothpaste","type":"Toothpaste"},"id":"45594631471242","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e232e154-1f22-47a5-97a3-a93e8238766d.png?v=1774337551"},"sku":"CITRUS1","title":"Citrus","untranslatedTitle":"Citrus"}],"products":[{"id":"6606432174218","handle":"revitin-natural-toothpaste","isCollective":null,"title":"Revitin Toothpaste Single Tube","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste Single Tube","url":"\/products\/revitin-natural-toothpaste","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"45594631471242","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e232e154-1f22-47a5-97a3-a93e8238766d.png?v=1774337551"},"price":{"amount":17.0,"currencyCode":"USD"},"sku":"CITRUS1","title":"Citrus","untranslatedTitle":"Citrus"}]},{"id":"9208964186250","handle":"variety-travel-2-pack-of-1-oz","isCollective":null,"title":"Variety Travel 2-Pack of 1 oz","type":null,"untranslatedTitle":"Variety Travel 2-Pack of 1 oz","url":"\/products\/variety-travel-2-pack-of-1-oz","vendor":"Revitin","remoteShopId":null,"variants":[{"id":"49777251877002","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Group248_1.png?v=1785832769"},"price":{"amount":12.0,"currencyCode":"USD"},"sku":"VarietyTravel2-pk","title":"Default Title","untranslatedTitle":"Default Title"}]},{"id":"7609245171850","handle":"revitin-toothpaste-5-tubes","isCollective":null,"title":"Revitin Toothpaste (5 Tubes)","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste (5 Tubes)","url":"\/products\/revitin-toothpaste-5-tubes","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"45594652901514","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e9fa6364-9bfe-4cd7-b0af-1a95d93ee5ba.png?v=1774337705"},"price":{"amount":70.0,"currencyCode":"USD"},"sku":"CITRUS5","title":"Citrus","untranslatedTitle":"Citrus"}]},{"id":"8334203355274","handle":"revitin-toothpaste-single-tube-mint","isCollective":null,"title":"Revitin Toothpaste Single Tube","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste Single Tube","url":"\/products\/revitin-toothpaste-single-tube-mint","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"45622706602122","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_99a4be1b-921c-4bbc-96f1-3bc4d0999926.png?v=1774337594"},"price":{"amount":17.0,"currencyCode":"USD"},"sku":"MINT1","title":"Mint","untranslatedTitle":"Mint"}]},{"id":"6606431420554","handle":"revitin-natural-toothpaste-family-pack-3tubes","isCollective":null,"title":"Revitin Toothpaste (3 Tubes)","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste (3 Tubes)","url":"\/products\/revitin-natural-toothpaste-family-pack-3tubes","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"45594633666698","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus.png?v=1773920437"},"price":{"amount":46.0,"currencyCode":"USD"},"sku":"CITRUS3","title":"Citrus","untranslatedTitle":"Citrus"}]},{"id":"8333322846346","handle":"revitin-toothpaste-3-tubes-mint","isCollective":null,"title":"Revitin Toothpaste (3 Tubes)","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste (3 Tubes)","url":"\/products\/revitin-toothpaste-3-tubes-mint","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"45618606080138","
723image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint.png?v=1774282946"},"price":{"amount":46.0,"currencyCode":"USD"},"sku":"MINT3","title":"Mint","untranslatedTitle":"Mint"}]},{"id":"8333359808650","handle":"revitin-toothpaste-5-tubes-mint","isCollective":null,"title":"Revitin Toothpaste (5 Tubes)","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste (5 Tubes)","url":"\/products\/revitin-toothpaste-5-tubes-mint","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"45618689310858","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_37b5d288-2b5a-42a4-bd87-71596a6bf4b4.png?v=1774337756"},"price":{"amount":70.0,"currencyCode":"USD"},"sku":"MINT5","title":"Mint","untranslatedTitle":"Mint"}]},{"id":"7890501009546","handle":"copy-of-revitin-toothpaste-25-tubes-gm","isCollective":null,"title":"Revitin Toothpaste (25 Tubes)","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste (25 Tubes)","url":"\/products\/copy-of-revitin-toothpaste-25-tubes-gm","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"45594657161354","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_5dd0e011-ff5d-4356-80a8-debbb8fbaa63.png?v=1774338062"},"price":{"amount":350.0,"currencyCode":"USD"},"sku":"CITRUS25","title":"Citrus","untranslatedTitle":"Citrus"}]},{"id":"8334207778954","handle":"revitin-toothpaste-25-tubes-mint","isCollective":null,"title":"Revitin Toothpaste (25 Tubes)","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste (25 Tubes)","url":"\/products\/revitin-toothpaste-25-tubes-mint","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"45622715121802","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_5fc8e8a0-5904-477c-9a1d-4ef752e21613.png?v=1774337996"},"price":{"amount":350.0,"currencyCode":"USD"},"sku":"MINT25","title":"Mint","untranslatedTitle":"Mint"}]},{"id":"8580142694538","handle":"revitin-toothpaste-travel-3-tubes","isCollective":null,"title":"Citrus Travel 3-Pack of 1oz","type":null,"untranslatedTitle":"Citrus Travel 3-Pack of 1oz","url":"\/products\/revitin-toothpaste-travel-3-tubes","vendor":"Revitin","remoteShopId":null,"variants":[{"id":"46346187341962","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Travel_Size_Citrus.png?v=1774338377"},"price":{"amount":18.0,"currencyCode":"USD"},"sku":"CitrTravel3-pk","title":"Citrus","untranslatedTitle":"Citrus"}]},{"id":"8658322555018","handle":"citrus-travel-case-100-count","
723isCollective":null,"title":"Citrus Travel Case (100 count)","type":null,"untranslatedTitle":"Citrus Travel Case (100 count)","url":"\/products\/citrus-travel-case-100-count","vendor":"Revitin","remoteShopId":null,"variants":[{"id":"46994967527562","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Travel_Size_Citrus.png?v=1774338377"},"price":{"amount":300.0,"currencyCode":"USD"},"sku":"CITRUSTRAVEL100","title":"Citrus","untranslatedTitle":"Citrus"}]},{"id":"8580143349898","handle":"revitin-toothpaste-travel-3-tubes-1","isCollective":null,"title":"Mint Travel 3-Pack of 1oz","type":null,"untranslatedTitle":"Mint Travel 3-Pack of 1oz","url":"\/products\/revitin-toothpaste-travel-3-tubes-1","vendor":"Revitin","remoteShopId":null,"variants":[{"id":"46346189045898","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Travel_Size_Mint.png?v=1774338342"},"price":{"amount":18.0,"currencyCode":"USD"},"sku":"MintTravel3-pk","title":"Mint","untranslatedTitle":"Mint"}]},{"id":"8658320261258","handle":"mint-travel-case-100-count","isCollective":null,"title":"Mint Travel Case (100 count)","type":null,"untranslatedTitle":"Mint Travel Case (100 count)","url":"\/products\/mint-travel-case-100-count","vendor":"Revitin","remoteShopId":null,"variants":[{"id":"46994955272330","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Travel_Size_Mint.png?v=1774338342"},"price":{"amount":300.0,"currencyCode":"USD"},"sku":"MINTTRAVEL100","title":"Mint","untranslatedTitle":"Mint"}]},{"id":"6803929432202","handle":"replacement-adult-brush-head","isCollective":null,"title":"Replacement Adult Brush Head","type":"Toothbrush Replacement Heads","untranslatedTitle":"Replacement Adult Brush Head","url":"\/products\/replacement-adult-brush-head","vendor":"Revitin","remoteShopId":null,"variants":[{"id":"40896700186762","image":{"src":"\/\/revitin.com\/cdn\/shop\/products\/ReplacementHead.png?v=1662485289"},"price":{"amount":5.5,"currencyCode":"USD"},"sku":"R-H6W-RH","title":"Default Title","untranslatedTitle":"Default Title"}]},{"id":"6606431617162","handle":"revitin-natural-toothpaste-fullcase-25tubes","isCollective":null,"title":"Revitin Toothpaste (25 Tubes)","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste (25 Tubes)","url":"\/products\/revitin-natural-toothpaste-fullcase-25tubes","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"39792313729162","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_75330201-6111-4242-bac7-eb4703f1b300.png?v=1774338517"},"price":{"amount":350.0,"currencyCode":"USD"},"sku":"CITRUS25","title":"Default Title","untranslatedTitle":"Default Title"}]},{"id":"8335794307210","handle":"revitin-toothpaste-25-tubes-wholesale","isCollective":null,"title":"Revitin Toothpaste (25 Tubes) Wholesale","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste (25 Tubes) Wholesale","url":"\/products\/revitin-toothpaste-25-tubes-wholesale","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"45628453814410","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_75330201-6111-4242-bac7-eb4703f1b300.png?v=1774338517"},"price":{"amount":212.5,"currencyCode":"USD"},"sku":"CITRUS25","title":"Citrus","untranslatedTitle":"Citrus"}]},{"id":"8335801548938","handle":"revitin-toothpaste-25-tubes-wholesale-mint","isCollective":null,"title":"Revitin Toothpaste (25 Tubes) Wholesale","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste (25 Tubes) Wholesale","url":"\/products\/revitin-toothpaste-25-tubes-wholesale-mint","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"45628533604490","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_1318037a-3b7a-4e15-84c3-e22323a5e8cc.png?v=1774337830"},"price":{"amount":212.5,"currencyCode":"USD"},"sku":"MINT25","title":"Mint","untranslatedTitle":"Mint"}]},{"id":"8332405899402","handle":"citrus-mint-4-tubes","isCollective":null,"title":"Revitin Toothpaste Variety 3 Tubes","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste Variety 3 Tubes","url":"\/products\/citrus-mint-4-tubes","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"46765298909322","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Variety_2citrus1mint.png?v=1774338212"},"price":{"amount":46.0,"currencyCode":"USD"},"sku":"VARIETYPACK2C-1M","title":"Citrus","untranslatedTitle":"Citrus"}]},{"id":"8645075763338","handle":"variety-pack-2-mint-1-citrus","isCollective":null,"title":"Revitin Toothpaste Variety 3 Tubes","type":"Toothpaste","untranslatedTitle":"Revitin Toothpaste Variety 3 Tubes","url":"\/products\/variety-pack-2-mint-1-citrus","vendor":"Revitin® Natural Toothpaste","remoteShopId":null,"variants":[{"id":"46765283049610","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Variety_1citrus2mint.png?v=1774338246"},"price":{"amount":46.0,"currencyCode":"USD"},"sku":"VARIETYPACK2M-1C","title":"Mint","untranslatedTitle":"Mint"}]},{"id":"8909392904330","handle":"variety-travel-4-pack-of-1-oz","
723isCollective":null,"title":"Variety Travel 4-Pack of 1 oz","type":null,"untranslatedTitle":"Variety Travel 4-Pack of 1 oz","url":"\/products\/variety-travel-4-pack-of-1-oz","vendor":"Revitin","remoteShopId":null,"variants":[{"id":"47799599759498","image":{"src":"\/\/revitin.com\/cdn\/shop\/files\/revitin2.png?v=1777964527"},"price":{"amount":24.0,"currencyCode":"USD"},"sku":"VarietyTravel4-pk","title":"Default Title","untranslatedTitle":"Default Title"}]}],"purchasingCompany":null},},"https://revitin.com/cdn","fff817eew048894c6p0347dc4em7b2d6332",{"modern":"","legacy":""},{"trekkieShim":true,"agentContext":true,"apiClientId":"580111","facebookCapiEnabled":"false","themeId":"153996034186","themePublished":"true","eventMetadataId":"f364b3b5-3c8e-4542-9bbb-e44c411d0b91","pageType":"product","resourceId":"6606432174218","shopId":"37689720970","storefrontBaseUrl":"https:\/\/revitin.com","extensionBaseUrl":"https:\/\/extensions.shopifycdn.com\/cdn\/shopifycloud\/web-pixels-manager","surface":"storefront-renderer","enabledBetaFlags":"[\"4c64608a\", \"16072cab\", \"8450a54b\", \"7ee89bf1\"]","isMerchantRequest":"false","hashVersion":"fff817eew048894c6p0347dc4em7b2d6332","publish":"custom","events":"[[\"page_viewed\",{}],[\"product_viewed\",{\"productVariant\":{\"price\":{\"amount\":17.0,\"currencyCode\":\"USD\"},\"product\":{\"title\":\"Revitin Toothpaste Single Tube\",\"vendor\":\"Revitin® Natural Toothpaste\",\"id\":\"6606432174218\",\"untranslatedTitle\":\"Revitin Toothpaste Single Tube\",\"url\":\"\/products\/revitin-natural-toothpaste\",\"type\":\"Toothpaste\"},\"id\":\"45594631471242\",\"image\":{\"src\":\"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e232e154-1f22-47a5-97a3-a93e8238766d.png?v=1774337551\"},\"sku\":\"CITRUS1\",\"title\":\"Citrus\",\"untranslatedTitle\":\"Citrus\"}}]]"});})();</script>
723<script> 724 window.ShopifyAnalytics = window.ShopifyAnalytics || {}; 725 window.ShopifyAnalytics.meta = window.ShopifyAnalytics.meta || {}; 726 window.ShopifyAnalytics.meta.currency = 'USD'; 727 var meta = {"product":{"id":6606432174218,"gid":"gid:\/\/shopify\/Product\/6606432174218","vendor":"Revitin® Natural Toothpaste","type":"Toothpaste","handle":"revitin-natural-toothpaste","variants":[{"id":45594631471242,"price":1700,"name":"Revitin Toothpaste Single Tube - Citrus","public_title":"Citrus","sku":"CITRUS1"}],"remote":false},"page":{"pageType":"product","resourceType":"product","resourceId":6606432174218,"requestId":"92b14f4a-92cf-4ca7-868f-2d3322189ab5-1790777238"}}; 728 for (var attr in meta) { 729 window.ShopifyAnalytics.meta[attr] = meta[attr]; 730 } 731</script>
vendor: 1 bytes, line 731
731
732<script class="analytics"> 733 (function () { 734 var customDocumentWrite = function(content) { 735 var jquery = null; 736 737 if (window.jQuery) { 738 jquery = window.jQuery; 739 } else if (window.Checkout && window.Checkout.$) { 740 jquery = window.Checkout.$; 741 } 742 743 if (jquery) { 744 jquery('body').append(content); 745 } 746 }; 747 748 var hasLoggedConversion = function(token) { 749 if (token) { 750 return document.cookie.indexOf('loggedConversion=' + token) !== -1; 751 } 752 return false; 753 } 754 755 var setCookieIfConversion = function(token) { 756 if (token) { 757 var twoMonthsFromNow = new Date(Date.now()); 758 twoMonthsFromNow.setMonth(twoMonthsFromNow.getMonth() + 2); 759 760 document.cookie = 'loggedConversion=' + token + '; expires=' + twoMonthsFromNow; 761 } 762 } 763 764 var trekkie = window.ShopifyAnalytics.lib = window.trekkie = window.trekkie || []; 765 window.ShopifyAnalytics.lib.trekkie = window.trekkie; 766 if (trekkie.integrations) { 767 return; 768 } 769 trekkie.methods = [ 770 'identify', 771 'page', 772 'ready', 773 'track', 774 'trackForm', 775 'trackLink' 776 ]; 777 trekkie.factory = function(method) { 778 return function() { 779 var args = Array.prototype.slice.call(arguments); 780 args.unshift(method); 781 trekkie.push(args); 782 if (method == 'track' || method == 'page') { 783 var pageUrl; 784 try { 785 pageUrl = window.location.href; 786 } catch (e) {} 787 var pageReferrer; 788 try { 789 pageReferrer = document.referrer; 790 } catch (e) {} 791 try { 792 if (window.__TREKKIE_SHIM_QUEUE == null) { 793 window.__TREKKIE_SHIM_QUEUE = []; 794 } 795 window.__TREKKIE_SHIM_QUEUE.push({ 796 from: 'trekkie-stub', 797 method: method, 798 args: args.slice(1), 799 pageContext: { 800 url: pageUrl, 801 referrer: pageReferrer 802 } 803 }); 804 } catch (e) { 805 // no-op 806 } 807 } 808 return trekkie; 809 }; 810 }; 811 for (var i = 0; i < trekkie.methods.length; i++) { 812 var key = trekkie.methods[i]; 813 trekkie[key] = trekkie.factory(key); 814 } 815 trekkie.load = function(config) { 816 trekkie.config = config || {}; 817 trekkie.config.initialDocumentCookie = document.cookie; 818 var first = document.getElementsByTagName('script')[0]; 819var script = document.createElement('script'); 820script.type = 'text/javascript'; 821script.onerror = function(e) { 822 var scriptFallback = document.createElement('script'); 823 scriptFallback.type = 'text/javascript'; 824 scriptFallback.onerror = function(error) { 825 var Monorail = { 826 produce: function produce(monorailDomain, schemaId, payload) { 827 var currentMs = new Date().getTime(); 828 var event = { 829 schema_id: schemaId, 830 payload: payload, 831 metadata: { 832 event_created_at_ms: currentMs, 833 event_sent_at_ms: currentMs 834 } 835 }; 836 return Monorail.sendRequest("https://" + monorailDomain + "/v1/produce", JSON.stringify(event)); 837 }, 838 sendRequest: function sendRequest(endpointUrl, payload) { 839 // Try the sendBeacon API 840 if (window && window.navigator && typeof window.navigator.sendBeacon === 'function' && typeof window.Blob === 'function' && !Monorail.isIos12()) { 841 var blobData = new window.Blob([payload], { 842 type: 'text/plain' 843 }); 844 845 if (window.navigator.sendBeacon(endpointUrl, blobData)) { 846 return true; 847 } // sendBeacon was not successful 848 849 } // XHR beacon 850 851 var xhr = new XMLHttpRequest(); 852 853 try { 854 xhr.open('POST', endpointUrl); 855 xhr.setRequestHeader('Content-Type', 'text/plain'); 856 xhr.send(payload); 857 } catch (e) { 858 console.log(e); 859 } 860 861 return false; 862 }, 863 isIos12: function isIos12() { 864 return window.navigator.userAgent.lastIndexOf('iPhone; CPU iPhone OS 12_') !== -1 || window.navigator.userAgent.lastIndexOf('iPad; CPU OS 12_') !== -1; 865 } 866 }; 867 Monorail.produce('monorail-edge.shopifysvc.com', 868 'trekkie_storefront_load_errors/1.1', 869 {shop_id: 37689720970, 870 theme_id: 153996034186, 871 app_name: "storefront", 872 context_url: window.location.href, 873 source_url: "//revitin.com/cdn/s/trekkie.storefront.f1ba865b3fecd812ad617f74ac079261075e9edb.min.js"}); 874 875 }; 876 scriptFallback.async = true; 877 scriptFallback.src = '//revitin.com/cdn/s/trekkie.storefront.f1ba865b3fecd812ad617f74ac079261075e9edb.min.js'; 878 first.parentNode.insertBefore(scriptFallback, first); 879}; 880script.async = true; 881script.src = '//revitin.com/cdn/s/trekkie.storefront.f1ba865b3fecd812ad617f74ac079261075e9edb.min.js'; 882first.parentNode.insertBefore(script, first); 883 884 }; 885 trekkie.load( 886 {"Trekkie":{"appName":"storefront","development":false,"defaultAttributes":{"shopId":37689720970,"isMerchantRequest":null,"themeId":153996034186,"themeCityHash":"10361271689453374424","contentLanguage":"en","currency":"USD","eventMetadataId":"f364b3b5-3c8e-4542-9bbb-e44c411d0b91"},"isServerSideCookieWritingEnabled":true,"monorailRegion":"shop_domain","enabledBetaFlags":["764d78cb","8450a54b","7ee89bf1","4c64608a"]},"Session Attribution":{},"S2S":{"facebookCapiEnabled":false,"source":"trekkie-storefront-renderer","apiClientId":580111}} 887 ); 888 889 var loaded = false;
890 trekkie.ready(function() { 891 if (loaded) return; 892 loaded = true; 893 894 window.ShopifyAnalytics.lib = window.trekkie; 895 896 var originalDocumentWrite = document.write; 897 document.write = customDocumentWrite; 898 try { window.ShopifyAnalytics.merchantGoogleAnalytics.call(this); } catch(error) {}; 899 document.write = originalDocumentWrite; 900 901 var match = window.location.pathname.match(/checkouts\/(.+)\/(thank_you|post_purchase)/) 902 var token = match? match[1]: undefined; 903 if (!hasLoggedConversion(token)) { 904 setCookieIfConversion(token); 905 window.ShopifyAnalytics.lib.track("Viewed Product",{"currency":"USD","variantId":45594631471242,"productId":6606432174218,"productGid":"gid:\/\/shopify\/Product\/6606432174218","name":"Revitin Toothpaste Single Tube - Citrus","price":"17.00","sku":"CITRUS1","brand":"Revitin® Natural Toothpaste","variant":"Citrus","category":"Toothpaste","nonInteraction":true,"remote":false,"available":true},undefined,undefined,{"shopifyEmitted":true}); 906 } 907 }); 908 909 window.ShopifyAnalytics.lib.page(null,{"pageType":"product","resourceType":"product","resourceId":6606432174218,"requestId":"92b14f4a-92cf-4ca7-868f-2d3322189ab5-1790777238","shopifyEmitted":true}); 910 911 var eventsListenerScript = document.createElement('script'); 912 eventsListenerScript.async = true; 913 eventsListenerScript.src = "//revitin.com/cdn/shopifycloud/storefront/assets/shop_events_listener-4e26a9ce.js"; 914 document.getElementsByTagName('head')[0].appendChild(eventsListenerScript); 915})();</script>
915 916
916<script> 917 if (!window.ga || (window.ga && typeof window.ga !== 'function')) { 918 window.ga = function ga() { 919 (window.ga.q = window.ga.q || []).push(arguments); 920 if (window.Shopify && window.Shopify.analytics && typeof window.Shopify.analytics.publish === 'function') { 921 window.Shopify.analytics.publish("ga_stub_called", {}, {sendTo: "google_osp_migration"}); 922 } 923 console.error("Shopify's Google Analytics stub called with:", Array.from(arguments), "\nSee https://help.shopify.com/manual/promoting-marketing/pixels/pixel-migration#google for more information."); 924 }; 925 if (window.Shopify && window.Shopify.analytics && typeof window.Shopify.analytics.publish === 'function') { 926 window.Shopify.analytics.publish("ga_stub_initialized", {}, {sendTo: "google_osp_migration"}); 927 } 928 } 929</script>
vendor: 1 bytes, line 929
929
930<script 931 defer 932 src="https://revitin.com/cdn/shopifycloud/perf-kit/shopify-perf-kit-3.9.4.min.js" 933 data-application="storefront-renderer" 934 data-shop-id="37689720970" 935 data-render-region="gcp-europe-west1" 936 data-page-type="product" 937 data-theme-instance-id="153996034186" 938 data-theme-name="Dawn" 939 data-theme-version="6.0.2" 940 data-monorail-region="shop_domain" 941 data-resource-timing-sampling-rate="10" 942 data-shs="true" 943 data-shs-beacon="true" 944 data-shs-export-with-fetch="true" 945 data-shs-logs-sample-rate="1" 946 data-shs-beacon-endpoint="https://revitin.com/api/collect" 947></script>
947 948<meta name="shopify-y" content="6c0774b0-a6f5-4fff-857b-ac1e66466252" data-expiration="1822334838000"><meta name="shopify-s" content="61d8c39a-13e1-4425-ae2e-b617443c286f" data-expiration="1790779038000"><meta name="new-cookie-storage-activated" content="t"> 949</head><body 950 class="pt-[6px] bg-light-tan text-sm lg:text-[0.9375rem]" 951 data-gwp-enabled="false" 952 > 953 <main> 954 <div class="fixed top-0 left-0 right-0 z-40 border-[3px] border-olive rounded-md"></div> 955 <div id="shopify-section-announcement" class="shopify-section"><section style="display: none;"> 956 957 <div class="announcement text-center text-brown"> 958 <p><a href="https://revitin.com/products/revitin-natural-toothpaste/Citrus" title="Revitin Travel Size">New Product Drop: Travel Size is Here</a></p> 959 </div> 960 961</section> 962 963<style> #shopify-section-announcement .announcement {background-color: #ffdea3;} #shopify-section-announcement .announcement p {padding-top: 0; padding-bottom: 0;} #shopify-section-announcement .announcement a {text-decoration: none; display: block; padding-top: 0.5rem; padding-bottom: 0.5rem;} </style></div> 964 965 <header id="shopify-section-header" class="shopify-section"><div class="site-header w-full max-w-none transition-all duration-500 ease-in-out text-primary bg-light-tan rounded-b-lg"> 966 <section> 967 <div class="announcement text-center text-brown flex items-center justify-center"> 968 <p><a href="https://revitin.com/products/revitin-natural-toothpaste/Mint" title="https://revitin.com/products/revitin-natural-toothpaste/Mint">Subscribe & Get Free Shipping on Every Order</a></p> 969 970 971 972 </div> 973 974 </section> 975 <mobile-menu> 976 <div class="h-16 lg:h-20 flex items-center lg:block"> 977 <div class="h-full site-container grid items-center transition-all grid-cols-4"> 978 <button id="hamburger-icon" class="md:hidden"> 979 <span> 980 <svg width="22" viewBox="0 0 26 26" xmlns="http://www.w3.org/2000/svg"> 981 <g fill="#5F471D" fill-rule="evenodd"> 982 <rect y="3" width="26" height="2" rx="1"/> 983 <rect y="12" width="26" height="2" rx="1"/> 984 <rect y="21" width="26" height="2" rx="1"/> 985 </g> 986 </svg> 987 </span> 988 <span> 989 <svg 990 class="relative left-[1px]" 991 width="20"
992 viewBox="0 0 20 20" 993 fill="none" 994 xmlns="http://www.w3.org/2000/svg" 995 > 996 <rect x="1.51471" y="0.100586" width="26" height="2" rx="1" transform="rotate(45 1.51471 0.100586)" fill="#5F471D" /> 997 <rect x="0.100525" y="18.4854" width="26" height="2" rx="1" transform="rotate(-45 0.100525 18.4854)" fill="#5F471D" /> 998 </svg> 999 </span> 1000 </button> 1001 1002 <nav class="hidden items-center gap-8 md:flex"> 1003 1004 <div class="shop-dropdown"> 1005 <a href=/products/revitin-natural-toothpaste/Mint> 1006 <div class="shop-dropdown-trigger flex items-center gap-2"> 1007 Shop 1008 <svg xmlns="http://www.w3.org/2000/svg" width="10" height="7" viewBox="0 0 10 7" fill="none"> 1009 <path d="M1.39036 0.421997L4.82215 3.7439L7.97438 0.539985L9.13896 1.7067L5.42193 5.48438L4.86098 6.0755L4.85086 6.06481L4.84096 6.07574L4.23631 5.4703L0.254501 1.6172L1.39036 0.421997Z" fill="#5F471D"/> 1010 </svg> 1011 </div> 1012 </a> 1013 <div class="shop-dropdown-content"> 1014 <div class="gap__box"></div> 1015 <div class="flex gap-2"> 1016 1017 <div class="shop-dropdown-item"> 1018 <a href="/products/revitin-natural-toothpaste/Citrus"> 1019 <img 1020 src="//revitin.com/cdn/shop/files/full-size.png?v=1759475549" 1021 srcset=" 1022 //revitin.com/cdn/shop/files/full-size_400x.png?v=1759475549 400w, 1023 //revitin.com/cdn/shop/files/full-size_800x.png?v=1759475549 800w, 1024 //revitin.com/cdn/shop/files/full-size_1200x.png?v=1759475549 1200w, 1025 //revitin.com/cdn/shop/files/full-size_1600x.png?v=1759475549 1600w, 1026 //revitin.com/cdn/shop/files/full-size_2000x.png?v=1759475549 2000w 1027 " 1028 sizes="100vw" 1029 alt="Full Size Toothpaste" 1030 loading="lazy" 1031 class="responsive-img" 1032 > 1033 <span class="dropdown-link-title">Full Size Toothpaste</span> 1034 </a> 1035 </div> 1036 1037 1038 1039 <div class="shop-dropdown-item"> 1040 <a href="/products/revitin-natural-toothpaste/Citrus?size=travel"> 1041 <img 1042 src="//revitin.com/cdn/shop/files/travel-size_1200x.png?v=1759475549" 1043 alt="Travel Size Toothpaste" 1044 > 1045 <span class="dropdown-link-title">Travel Size Toothpaste</span> 1046 </a> 1047 </div> 1048 1049 </div> 1050 </div> 1051 </div> 1052 1053 1054 1055 1056 1057 1058 1059 <a class="lg:hover:opacity-70 transition-opacity duration-300" href="/pages/about">About</a> 1060 1061 1062 1063 <a class="lg:hover:opacity-70 transition-opacity duration-300" href="/pages/ingredients">Ingredients</a> 1064 1065 1066 </nav> 1067 1068 <div class="col-span-2"> 1069 <a href="/" class="flex justify-center relative z-20"> 1070 <div class="w-[120px] lg:w-[140px]"> 1071 <svg 1072 xmlns="http://www.w3.org/2000/svg" 1073 x="0" 1074 y="0"
1075 viewBox="0 0 504 232.3" 1076 style="enable-background:new 0 0 504 232.3" 1077 xml:space="preserve" 1078 fill="currentColor" 1079 > 1080 <path d="M132.33 157.14c0 1.5-1.12 2.24-3.24 2.24h-10.72c-3.86 0-5.85-1.62-8.35-4.61l-30.78-36.14v30.28c0 5.36 6.23 4.36 6.23 8.47 0 1-.87 1.99-2.49 1.99H60.79c-1.62 0-2.49-1-2.49-1.99 0-3.61 6.36-2.99 6.36-8.47V82.36c0-5.36-6.36-4.36-6.36-8.47 0-1 1-1.99 2.49-1.99h29.79c24.42 0 35.89 9.22 35.89 23.68 0 11.84-8.35 21.44-32.28 22.93 3.12.87 5.24 2.37 7.23 4.49l20.81 23.93c5.74 6.47 10.1 6.47 10.1 10.21zm-53.09-44.37c2.37.37 5.11.5 7.6.5 16.07 0 23.68-5.86 23.68-17.07 0-11.46-6.6-18.32-23.43-18.32h-3.86c-2.62 0-3.99 1.37-3.99 3.61v31.28zM131.8 129.35c0-18.57 11.96-31.53 29.17-31.53 15.58 0 24.8 10.59 24.8 21.56 0 5.24-1.99 6.98-5.86 6.98h-35.64c.38 15.08 8.85 23.43 21.56 23.43 12.09 0 16.07-7.85 19.32-7.85 1.24 0 1.87 1.25.99 3.49-3.37 9.1-12.34 15.45-24.67 15.45-16.7 0-29.67-11.97-29.67-31.53zm37.02-8.85c2.37 0 3.62-1.12 3.62-3.37 0-6.98-3.37-13.58-12.46-13.58-8.6 0-14.83 5.86-15.57 16.95h24.41zM250.55 100.81c0 2.37-4.86 4.48-7.1 10.09l-19.19 46.36c-1.12 2.49-3.12 3.62-5.23 3.62-2.12 0-4.12-1.12-5.11-3.62l-19.07-46.23c-2.49-5.74-7.23-7.85-7.23-10.09 0-1 .75-1.62 2.12-1.62h22.56c1.24 0 1.87.63 1.87 1.5 0 2.37-5.36 3.74-5.36 7.98 0 1 .25 1.99.74 3.24l12.71 33.4 13.34-33.28c.5-1.37.74-2.37.74-3.49 0-3.99-4.86-5.86-4.86-7.98 0-.87.63-1.37 1.87-1.37h15.45c1.13-.01 1.75.62 1.75 1.49zM255.02 157.26c0-3.24 5.73-2.99 5.73-6.35v-36.27c0-4.49-6.85-3.24-6.85-6.85 0-1 .74-1.87 1.99-2.49l13.71-6.85c2.74-1.37 4.49-.38 4.49 2.24v50.22c0 3.36 5.6 3.11 5.6 6.35 0 1.12-1.12 2.12-2.62 2.12H257.5c-1.48 0-2.48-1-2.48-2.12zm1.37-77.51c0-5.11 4.24-9.35 9.48-9.35 5.11 0 9.34 4.24 9.34 9.35 0 5.24-4.23 9.47-9.34 9.47-5.24 0-9.48-4.24-9.48-9.47zM295.13 145.42v-37.39c0-2.24-1.24-3.49-3.49-3.49h-4.24c-3.24 0-4.24-2.74-1.62-4.86l18.44-15.08c2.12-1.87 4.24-1 4.24 1.87v12.84h18.7c1.49 0 2.24.75 2.24 2.12v1.74c0 1.37-.75 2.12-2.24 2.12h-18.7v40c0 5.49 2.37 7.6 7.98 7.6 5.11 0 7.85-1.37 9.47-1.37 1.12 0 1.62.62 1.62 1.49 0 3.49-8.6 7.85-17.57 7.85-9.34.02-14.83-4.6-14.83-15.44zM334.38 157.26c0-3.24 5.73-2.99 5.73-6.35v-36.27c0-4.49-6.85-3.24-6.85-6.85 0-1 .75-1.87 1.99-2.49l13.71-6.85c2.74-1.37 4.49-.38 4.49 2.24v50.22c0 3.36 5.61 3.11 5.61 6.35 0 1.12-1.12 2.12-2.62 2.12h-19.57c-1.49 0-2.49-1-2.49-2.12zm1.37-77.51c0-5.11 4.24-9.35 9.47-9.35 5.11 0 9.35 4.24 9.35 9.35 0 5.24-4.24 9.47-9.35 9.47a9.47 9.47 0 0 1-9.47-9.47zM432.44 157.26c0 1.12-.87 2.12-2.49 2.12h-19.57c-1.62 0-2.49-1-2.49-2.12 0-3.12 5.6-2.99 5.6-5.98v-30.91c0-9.59-2.99-12.96-10.71-12.96-4.49 0-9.6 1-15.58 3.74v40.13c0 2.74 5.61 2.87 5.61 5.98 0 1.12-.87 2.12-2.49 2.12h-19.69c-1.62 0-2.49-1-2.49-2.12 0-2.99 5.61-3.12 5.61-5.98v-36.51c0-4.61-6.73-3.62-6.73-6.85 0-.87.75-1.75 1.99-2.49l13.71-6.98c2.12-1.25 4.49-.62 4.49 2.24v5.36c7.85-4.98 17.45-8.22 24.93-8.22 9.97 0 14.7 5.73 14.7 16.08v37.39c-.01 2.72 5.6 2.97 5.6 5.96z"/> 1081 <path d="M447.66 76.53c.75.08 1.52.07 2.26.26.42.11.85.15 1.26.28.63.2 1.26.44 1.88.7.48.2.95.42 1.39.69.6.36 1.19.74 1.74 1.18.58.46 1.12.96 1.64 1.48.63.64 1.2 1.34 1.65 2.12.35.6.72 1.19 1.01 1.82.48 1.01.84 2.06 1.05 3.16.12.61.23 1.21.26 1.83.01.2.02.39.04.59.01.01.02.03.02.04v1.08c-.01.01-.02.03-.03.04-.02.88-.13 1.75-.32 2.61-.22.98-.53 1.92-.93 2.84-.45 1.03-1.01 1.99-1.71 2.87-.41.52-.84 1.04-1.3 1.51-.69.7-1.44 1.35-2.29 1.87-.6.37-1.21.74-1.84 1.05-.52.26-1.08.45-1.63.65-.45.16-.91.29-1.37.4-.4.1-.8.14-1.2.22-1.01.19-2.03.16-3.05.14-.42-.01-.84-.08-1.26-.15-.56-.09-1.12-.18-1.66-.34-.73-.22-1.45-.47-2.15-.77-.49-.21-.96-.49-1.42-.75-.39-.23-.78-.47-1.15-.72-.32-.22-.62-.46-.91-.72-.32-.28-.65-.56-.94-.87-.68-.7-1.31-1.44-1.84-2.26-.41-.63-.78-1.27-1.1-1.96-.34-.75-.66-1.51-.84-2.32-.16-.72-.31-1.43-.44-2.15-.04-.22-.03-.46-.05-.68l-.03-.48c0-.08 0-.15.01-.23v-.97c.06-.58.08-1.17.19-1.74.15-.78.33-1.55.57-2.31.2-.64.49-1.25.78-1.85.43-.9.98-1.72 1.59
1081-2.51.5-.65 1.05-1.25 1.66-1.8.55-.49 1.15-.95 1.76-1.37.48-.33.99-.6 1.5-.89.63-.35 1.3-.63 1.99-.84.45-.14.9-.27 1.36-.37.57-.12 1.15-.22 1.73-.3.35-.05.7-.06 1.05-.08.08-.01.15-.01.23-.02h.63c.06.01.13.01.21.02zm12.37 14.07c-.01-.03-.02-.05-.02-.08 0-.16.01-.33-.01-.49-.06-.45-.13-.89-.23-1.33-.12-.53-.23-1.07-.41-1.58-.23-.63-.51-1.24-.8-1.84-.2-.42-.43-.83-.69-1.21-.35-.5-.75-.96-1.13-1.44-.48-.6-1.07-1.1-1.67-1.57-.67-.53-1.37-.99-2.15-1.34-.58-.27-1.17-.54-1.77-.74a12.57 12.57 0 0 0-3.44-.62c-.04-.01-.08-.02-.11-.03-.04 0-.08 0-.11.01h-.78c-.06.01-.13.01-.19.02-.18.01-.36.02-.53.04-.61.08-1.23.12-1.83.28-.76.2-1.5.46-2.23.75-.72.29-1.4.69-2.04 1.13-.88.61-1.68 1.31-2.39 2.11-.55.61-1.03 1.27-1.45 1.97-.5.82-.9 1.7-1.19 2.61-.33 1.01-.55 2.05-.59 3.1-.04.83-.01 1.66.07 2.49.06.64.23 1.28.39 1.91.32 1.21.85 2.33 1.51 3.38.42.67.89 1.3 1.45 1.87.46.46.93.93 1.43 1.34.71.58 1.48 1.09 2.32 1.47.58.26 1.17.53 1.78.73.65.21 1.32.35 2 .48.4.08.81.08 1.22.11.01 0 .03 0 .04-.01h1.38c.01 0 .03 0 .04.01.21-.01.43 0 .64-.04.62-.11 1.24-.24 1.85-.37.7-.15 1.36-.42 2.01-.71.72-.32 1.41-.7 2.06-1.15.76-.52 1.47-1.11 2.08-1.81.46-.53.93-1.07 1.33-1.66.36-.53.65-1.11.95-1.69.36-.7.61-1.44.8-2.19.21-.83.37-1.68.4-2.54.01-.03.01-.05.02-.08v-1.27c-.01 0-.01-.01-.01-.02zM432.4 90.6v.34c.01-.12 0-.23 0-.34z"/><path class="st0" d="M432.41 91.57c0 .08 0 .15-.01.23 0-.08.01-.16.01-.23zM446.8 76.51c-.08.01-.15.01-.23.02.08-.01.15-.01.23-.02zM447.66 76.53c-.08-.01-.15-.02-.23-.02.08.01.15.01.23.02zM461.86 90.67a.076.076 0 0 1-.02-.04c0 .02.01.03.02.04zM461.84 91.8c.01-.01.02-.03.03-.04-.02.01-.02.03-.03.04zM447.7 78.36h-.11v-.03c.03.01.07.02.11.03zM446.69 78.35c-.06.01-.13.01-.19.02.06-.01.12-.02.19-.02zM460.01 91.98v-.08h.02c-.01.03-.02.06-.02.08zM460 90.6c0-.03 0-.05.01-.08.01.03.02.05.02.08H460zM447.58 78.33v.03c-.04-.01-.08-.02-.12-.02.05 0 .08 0 .12-.01zM446.84 78.34h-.08.08zM460 90.6h.03v.04c-.01-.02-.02-.03-.03-.04z"/><path class="st0" d="M460.03 91.91h-.02c.01-.01.02-.03.03-.04-.01.01-.01.02-.01.04zM446.42 104.13c.01 0 .03 0 .04-.01-.01.01-.02.01-.04.01zM447.84 104.13c.01 0 .03 0 .04.01-.01-.01-.02-.01-.04-.01zM447.73 83.5c.03.01.07.03.1.03.8 0 1.57.12 2.31.41.85.33 1.59.82 2.09 1.62.35.56.56 1.16.62 1.81.04.45.07.91.03 1.35-.06.71-.25 1.39-.68 1.99-.53.77-1.24 1.29-2.09 1.66-.01 0-.02.02-.04.04.12.24.25.49.38.73l1.17 2.16c.52.97 1.05 1.94 1.57 2.91.12.21.23.43.34.65.01.03.01.07.01.11l-.03.03c-.95 0-1.89 0-2.84-.01-.01-.01-.02-.02-.03-.02-.19-.36-.38-.73-.58-1.09-.16-.31-.33-.61-.49-.91-.3-.57-.6-1.15-.89-1.72-.29-.55-.58-1.1-.86-1.65-.09-.17-.18-.35-.26-.52-.01-.01-.02-.02-.03-.02-.58 0-1.17-.01-1.75-.01-.4 0-.8.01-1.19.01l-.03.03v.14c0 .04-.01.
108109-.01.13v5.36c0 .04.01.09.01.13 0 .05-.01.1-.01.15-.01.01-.02.02-.04.03h-2.61l-.03-.03c0-.06-.01-.12-.01-.19V83.72c0-.08-.07-.22.11-.22.06.01.11.02.17.02h5.34c.04 0 .07-.01.11-.01h.1c.01-.02.02-.02.04-.01zm-3.16 7.32.03.03h2.99c.16-.01.34.01.49-.04.35-.11.69-.24 1.02-.4.49-.23.78-.65.95-1.14.18-.5.19-1.02.12-1.54-.07-.5-.24-.95-.6-1.3-.53-.51-1.18-.7-1.9-.72-.01-.01-.03-.01-.04-.02-1.01 0-2.02 0-3.03-.01l-.03.03v.37c0 .07-.01.14-.01.2v4.12c0 .07.01.14.01.2v.22zM447.59 83.48c-.04 0-.07.01-.11.01h-5.34c-.06 0-.11-.01-.17-.02.06-.01.12-.02.18-.02h5.24c.07 0 .13.02.2.03z"/><path class="st0" d="M444.56 98.83c0-.04-.01-.09-.01-.13v-5.36c0-.04.01-.09.01-.13.01.06.03.12.03.18v5.26c0 .06-.02.12-.03.18zM444.57 93.07l.03-.03-.03.03zM447.54 93.05c.01.01.02.02.03.02-.01-.01-.02-.02-.03-.02zM447.73 83.5c-.01 0-.02-.01-.03-.01 0 0 .01 0 .03.01zM441.87 98.98l.03.03c-.01-.02-.02-.03-.03-.03zM444.51 99c.01-.01.02-.02.04-.03-.01.02-.02.03-.04.03zM450.66 98.97c.01.01.02.02.03.02-.01 0-.02-.01-.03-.02zM453.53 99l.03-.03-.03.03zM444.56 86.07c.01.05.03.11.03.16v4.21c0 .05-.02.11-.03.16 0-.07-.01-.14-.01-.2v-4.12c0-.07.01-.14.01-.21zM444.57 90.82l.03.03-.03-.03zM447.54 90.85h.04-.04zM447.66 85.7c-.01-.01-.03-.01-.04-.02.01 0 .03.01.04.02zM444.59 85.67l-.03.03c.02-.01.02-.02.03-.03z"/> 1082 </svg> 1083 </div> 1084 </a> 1085 </div> 1086 <div class="mobile-menu fixed top-[92px] left-0 w-full h-screen z-20 text-primary bg-light-tan opacity-0 invisible transition-all duration-500 ease py-8 pt-5"> 1087 <nav style="padding-left: 0px; padding-right: 0px;" class="site-container grid content-start pt-4"> 1088 1089 <a href="/products/revitin-natural-toothpaste/Mint" class="button button--light-green mx-auto"> 1090 1091 Shop Toothpaste 1092 </a> 1093 <img 1094 class="w-full h-full nav-menu-bg-img" 1095 src="//revitin.com/cdn/shop/t/129/assets/nav-menu-bg.jpg?v=89763950694445791721777542404" 1096 alt="" 1097 width="1200px" 1098 height="1200px" 1099 > 1100 <div class="border-b border-primary grid content-start gap-8 pt-8 pb-8 px-3"> 1101 <div class="grid content-start gap-4"> 1102 1103 1104 1105 <a href="https://revitin.com/products/revitin-natural-toothpaste/Citrus" class="flex justify-between items-center"> 1106 1107 1108 <div class="text-primary heading-2">Revitin Toothpaste</div> 1109 <svg 1110 width="17" 1111 height="13" 1112 viewBox="0 0 17 13" 1113 fill="none" 1114 xmlns="http://www.w3.org/2000/svg"> 1115 <path 1116 d="M1.39474 6.5H15.6053" 1117 stroke="#5F471D" 1118 stroke-width="1.5" 1119 stroke-linecap="round" /> 1120 <path 1121 d="M10 1L15.5 6.5" 1122 stroke="#5F471D" 1123 stroke-width="1.5" 1124 stroke-linecap="round" /> 1125 <path 1126 d="M10 12L15.5 6.5" 1127 stroke="#5F471D" 1128 stroke-width="1.5" 1129 stroke-linecap="round" /> 1130</svg> 1131 </a> 1132 1133 1134 <a href="/pages/about" class="flex justify-between items-center"> 1135 1136 <div class="text-primary heading-2">About Us</div> 1137 <svg 1138 width="17" 1139 height="13" 1140 viewBox="0 0 17 13" 1141 fill="none" 1142 xmlns="http://www.w3.org/2000/svg"> 1143 <path 1144 d="M1.39474 6.5H15.6053" 1145 stroke="#5F471D" 1146 stroke-width="1.5" 1147 stroke-linecap="round" /> 1148 <path 1149 d="M10 1L15.5 6.5" 1150 stroke="#5F471D" 1151 stroke-width="1.5" 1152 stroke-linecap="round" /> 1153 <path 1154 d="M10 12L15.5 6.5" 1155 stroke="#5F471D" 1156 stroke-width="1.5" 1157 stroke-linecap="round" /> 1158</svg> 1159 </a> 1160 1161 1162 <a href="/pages/ingredients" class="flex justify-between items-center"> 1163 1164 <div class="text-primary heading-2">Ingredients</div> 1165 <svg 1166 width="17" 1167 height="13" 1168 viewBox="0 0 17 13" 1169 fill="none" 1170 xmlns="http://www.w3.org/2000/svg"> 1171 <path 1172 d="M1.39474 6.5H15.6053" 1173 stroke="#5F471D" 1174 stroke-width="1.5" 1175 stroke-linecap="round" /> 1176 <path 1177 d="M10 1L15.5 6.5" 1178 stroke="#5F471D" 1179 stroke-width="1.5" 1180 stroke-linecap="round" /> 1181 <path 1182 d="M10 12L15.5 6.5" 1183 stroke="#5F471D" 1184 stroke-width="1.5" 1185 stroke-linecap="round" /> 1186</svg> 1187 </a> 1188 1189 1190 <a href="/pages/about/#meet-dr-gerry" class="flex justify-between items-center"> 1191 1192 <div class="text-primary heading-2">Meet Dr. Gerry</div> 1193 <svg 1194 width="17" 1195 height="13" 1196 viewBox="0 0 17 13" 1197 fill="none" 1198 xmlns="http://www.w3.org/2000/svg"> 1199 <path 1200 d="M1.39474 6.5H15.6053" 1201 stroke="#5F471D" 1202 stroke-width="1.5" 1203 stroke-linecap="round" /> 1204 <path 1205 d="M10 1L15.5 6.5" 1206 stroke="#5F471D" 1207 stroke-width="1.5" 1208 stroke-linecap="round" /> 1209 <path 1210 d="M10 12L15.5 6.5" 1211 stroke="#5F471D" 1212 stroke-width="1.5" 1213 stroke-linecap="round" /> 1214</svg> 1215 </a> 1216 1217 </div> 1218 </div> 1219 <div class="grid content-start gap-3 pt-8 px-3"> 1220 1221 <a href="/pages/contact-us" class="flex justify-between items-center"> 1222 <div class="text-primary text-lg">Contact Us</div> 1223 </a> 1224 1225 <a href="/pages/wholesale" class="flex justify-between items-center"> 1226 <div class="text-primary text-lg">Wholesale</div> 1227 </a> 1228 1229 <a href="/account" class="flex justify-between items-center"> 1230 <div class="text-primary text-lg">Account</div> 1231 </a> 1232 1233 <a href="/blogs/all" class="flex justify-between items-center"> 1234 <div class="text-primary text-lg">Blogs</div> 1235 </a> 1236 1237 </div> 1238 </nav> 1239</div> 1240 1241<style> 1242 .nav-menu-bg-img { 1243 width: 100%; 1244 height: 10rem; 1245 display: block; 1246 object-fit: cover; 1247 object-position: center; 1248 margin-top: 1rem; 1249 } 1250</style> 1251 <div class="md:flex md:justify-end md:gap-8"> 1252 <nav class="hidden items-center gap-8 md:flex"> 1253 <a href="/account" class="text-primary lg:hover:opacity-70 transition-opacity duration-300">Account</a> 1254 </nav> 1255 <cart-open> 1256 <div class="grid justify-end transition-all"> 1257 <cart-toggle> 1258 <button id="cart-icon-bubble" class="group"> 1259 <div class="flex items-center gap-1"> 1260 <div class="lg:group-hover:opacity-70 transition-opacity duration-300">Cart</div> 1261 <div class="w-[30px] h-[30px] text-center relative mb-1">
1262 <span class="block text-white text-[0.8125rem] font-body-medium relative z-10 h-full grid items-center"> 1263 <span class="relative top-[2px] -left-[2px] variety-cart-count [text-shadow:_0_1px_0_rgb(0_0_3_/_10%)]">0</span> 1264 </span> 1265 <img src="//revitin.com/cdn/shop/t/129/assets/citrus-logo.png?v=12133043602477412821777542404" alt="" class="absolute top-0 left-0 right-0 mx-auto h-full" /> 1266 </div> 1267 </div> 1268 </button> 1269</cart-toggle> 1270 1271 </div> 1272 </cart-open> 1273 </div> 1274 </div> 1275 </div> 1276 </mobile-menu> 1277</div> 1278 1279<style> 1280 .countdown-container { 1281 display: flex !important; 1282 gap: 11px; 1283 } 1284 1285 .timer-container { 1286 padding: 0 !important; 1287 } 1288 1289 .timer { 1290 display: flex; 1291 flex-direction: column; 1292 padding: 4px 4px !important; 1293 border: 1px solid #5F471D; 1294 width: max-content; 1295 border-radius: 5px; 1296 gap: 2px; 1297 } 1298 1299 .timer .count{ 1300 font-size: 1.4rem; 1301 line-height: 1 !important; 1302 } 1303 1304 .timer .text{ 1305 font-size: 0.6rem; 1306 line-height: 1 !important; 1307 } 1308 1309 .announcement { 1310 background-color: #ffdea3; 1311 display: flex !important; 1312 gap: 1rem; 1313 padding: 4px !important; 1314 } 1315 1316 .announcement a { 1317 text-decoration: none; 1318 display: block; 1319 padding-top: 0.5rem; 1320 padding-bottom: 0.3rem; 1321 } 1322 1323 .gap__box { 1324 width: 100%; 1325 height: 28px; 1326 background: #ff000000; 1327 flex-shrink: 0; 1328 1329 } 1330 1331 .dropdown-link-title { 1332 display: inline-block; 1333 font-size: 15.73px; 1334 padding: 12px 12px; 1335 color: #5F471D; 1336 } 1337 1338 .shop-dropdown { 1339 position: relative; 1340 display: inline-block; 1341 } 1342 .shop-dropdown-content { 1343 display: none; 1344 position: absolute; 1345 background-color: #FFFBEF; 1346 top: 100%; 1347 left: 0; 1348 width: max-content; 1349 border-radius: 0px 0px 16px 16px; 1350 z-index: 1000; 1351 flex-direction: column; 1352 } 1353 .shop-dropdown:hover .shop-dropdown-content { 1354 display: flex; 1355 gap: 2px; 1356 } 1357 .shop-dropdown-item { 1358 text-align: center; 1359 flex: 1; 1360 } 1361 .shop-dropdown-item img { 1362 max-width: 17.1rem; 1363 min-width: 17rem; 1364 } 1365 .shop-dropdown-item a { 1366 display: block; 1367 color: #333; 1368 text-decoration: none; 1369 font-weight: 500; 1370 } 1371 .shop-dropdown-trigger { 1372 cursor: pointer; 1373 font-weight: 500; 1374 } 1375 1376 @media (max-width: 768px) { 1377 .announcement { 1378 flex-direction: column; 1379 gap: 0rem; 1380 padding: 0px 0px 10px 0px !important; 1381 } 1382 } 1383</style> 1384
1385<script> 1386 document.addEventListener('DOMContentLoaded', function () { 1387 const el = document.querySelector('[data-countdown-date]'); 1388 const date = el?.dataset.countdownDate; 1389 const time = el?.dataset.countdownTime; 1390 if (!date || !time) return; 1391 1392 // Target EST datetime with proper timezone (America/New_York handles DST) 1393 const targetDate = new Date(`${date}T${time}:00`); 1394 1395 function updateCountdown() { 1396 const nowEST = new Date().toLocaleString('en-US', { timeZone: 'America/New_York' }); 1397 const now = new Date(nowEST); 1398 1399 const distance = targetDate - now; 1400 1401 if (distance <= 0) { 1402 document.querySelector('.hours').textContent = '00'; 1403 document.querySelector('.minutes').textContent = '00'; 1404 document.querySelector('.seconds').textContent = '00'; 1405 clearInterval(timer); 1406 return; 1407 } 1408 1409 const hours = Math.floor(distance / (1000 * 60 * 60)); 1410 const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60)); 1411 const seconds = Math.floor((distance % (1000 * 60)) / 1000); 1412 1413 document.querySelector('.hours').textContent = String(hours).padStart(2, '0'); 1414 document.querySelector('.minutes').textContent = String(minutes).padStart(2, '0'); 1415 document.querySelector('.seconds').textContent = String(seconds).padStart(2, '0'); 1416 } 1417 1418 updateCountdown(); 1419 const timer = setInterval(updateCountdown, 1000); 1420 }); 1421</script>
1421 1422
1423<script> 1424 const header = document.querySelector('.site-header'); 1425 1426 function handleScroll() { 1427 const scrollY = window.scrollY || window.pageYOffset; 1428 1429 if (scrollY >= 40) { 1430 header.classList.add('active'); 1431 } else { 1432 header.classList.remove('active'); 1433 } 1434 } 1435 1436 window.addEventListener('scroll', handleScroll); 1437</script>
1437 1438 1439 1440</header> 1441 1442 1443 1444 1445 1446 1447 <div class='easylockdown-content' style='display:none;'><section id="shopify-section-template--21146535100554__main" class="shopify-section product-section"><style> 1448 .jdgm-rev-widg__header { 1449 border-bottom: 1px solid; 1450 } 1451 .jdgm-review-widget .jdgm-rev-widg__title{ 1452 font-family: Rza Trial !important; 1453 font-size: 1.875rem !important; 1454 line-height: 2.25rem !important; 1455 letter-spacing: -.025em !important; 1456 } 1457 .jdgm-widget a[role="button"]:not(.jdgm-star), .jdgm-form__fieldset input[type="submit"].jdgm-btn{ 1458 border-radius: 5px !important; 1459 color: #5F471D; 1460 font-weight: 400; 1461 transition: all ease-in-out 0.3s; 1462 padding: 1rem 3rem; 1463 font-family: Basis Medium !important; 1464 } 1465 .jdgm-widget a[role="button"]:hover, .jdgm-form__fieldset input[type="submit"]:hover{ 1466 border-color: #5F471D; 1467 color: #5F471D!important; 1468 background-color: transparent !important; 1469 } 1470 span.jdgm-star, .jdgm-rev-widg__summary .jdgm-rev-widg__summary-stars .jdgm-star, .jdgm-row-stars .jdgm-histogram .jdgm-star { 1471 font-size: 11px; 1472 } 1473 .jdgm-rev-widg__body .jdgm-rev__header span.jdgm-rev__rating { 1474 display: block; 1475 } 1476 .jdgm-rev-widg__body .jdgm-rev__timestamp{ 1477 float: none; 1478 } 1479 .jdgm-rev__author{ 1480 font-family: Basis Medium !important; 1481 } 1482 .jdgm-rev__body p{ 1483 font-family: 'Open Sans', Verdana, sans-serif; 1484 } 1485 .jdgm-review-widget .jdgm-rev-widg, .jdgm-review-widget.jdgm-review-widget--small .jdgm-rev-widg, .jdgm-review-widget.jdgm-review-widget--medium .jdgm-rev-widg{ 1486 padding-top: 50px; 1487 padding-left: 16px; 1488 padding-right: 16px; 1489 } 1490 span.jdgm-rev-widg__summary-average { 1491 font-size: 30px; 1492 line-height: 30px; 1493 font-family: Basis Medium; 1494 } 1495 .jdgm-rev-widg__summary-text { 1496 clear: both; 1497 } 1498 @media (min-width: 992px){ 1499 span.jdgm-rev-widg__summary-average { 1500 float: left; 1501 padding-right: 10px; 1502 font-size: 37px; 1503 margin-bottom: 10px; 1504 } 1505 .jdgm-review-widget .jdgm-rev-widg{ 1506 padding-top: 70px; 1507 } 1508 .jdgm-rev__body p { 1509 font-size: 20px; 1510 } 1511 .jdgm-rev-widg__reviews { 1512 display: grid; 1513 grid-template-columns: repeat(2, 1fr); 1514 gap: 30px; 1515 } 1516 } 1517</style> 1518<link href="//revitin.com/cdn/shop/t/129/assets/toothpaste-slider.css?v=57238974732765893061785235958" rel="stylesheet" type="text/css" media="all" /> 1519<style> 1520 /* Custom Slider Styles */ 1521 .slides-container { 1522 position: relative; 1523 width: 100%; 1524 } 1525 1526 .slides-wrapper { 1527 height: 100%; 1528 } 1529 1530 .slide { 1531 position: absolute; 1532 top: 0; 1533 left: 0; 1534 width: 100%; 1535 height: 100%; 1536 opacity: 0; 1537 transition: opacity 0.5s ease-in-out; 1538 pointer-events: none; 1539 } 1540 1541 .slide.active { 1542 opacity: 1; 1543 position: relative; 1544 pointer-events: auto; 1545 } 1546 1547 /* Progress Dots Styles - Exact Oura Style */ 1548 .progress-slider-dots-wrapper { 1549 padding: 8px 0; 1550 } 1551 1552 .progress-slider-dots { 1553 height: 12px; 1554 } 1555 1556 .progress-slider-dot { 1557 position: relative; 1558 width: 10px; 1559 height: 10px; 1560 border-radius: 50%; 1561 border: 1.5px solid #5f471D; 1562 background: transparent; 1563 padding: 0; 1564 cursor: pointer; 1565 transition: all 0.3s ease; 1566 overflow: hidden; 1567 } 1568 1569 /* Active dot becomes a pill */ 1570 .progress-slider-dot.active { 1571 width: 52px; 1572 height: 10px; 1573 border-radius: 999px; 1574 border-color: #5f471D; 1575 background: transparent; 1576 } 1577 1578 /* Progress fill inside the dot */ 1579 .dot-progress { 1580 position: absolute; 1581 top: 0; 1582 left: 0; 1583 width: 0%; 1584 height: 100%; 1585 background: #5f471D; 1586 border-radius: inherit; 1587 z-index: 1; 1588 /* Smooth animation */ 1589 animation: none; 1590 } 1591 1592 /* Only show progress fill on active dots */ 1593 .progress-slider-dot:not(.active) .dot-progress { 1594 display: none; 1595 } 1596 1597 /* Dot hover effect */ 1598 .progress-slider-dot:hover { 1599 transform: scale(1.1); 1600 } 1601 1602 .ts-variety-selector-btn { 1603 padding: 8px 16px 8px 8px; 1604 } 1605 1606 .ts_variety_tab_btn { 1607 background: #F5EEE0; 1608 border-radius: 25px; 1609 padding: 2px 4px; 1610 } 1611 1612 .ts_variety_tab_btn img { 1613 max-width: 2.5rem; 1614 } 1615 1616 .sticky-shop-now__btn:hover { 1617 background: #5f471D !important; 1618 color: #fff !important; 1619 } 1620 1621 /* Wholesale travel: match full-size (no fade transitions) */ 1622 #pdp-container.ws-travel-no-transition [data-swap-flavor], 1623 #pdp-container.ws-travel-no-transition [data-swap-flavor] img, 1624 #pdp-container.ws-travel-no-transition .slide { 1625 transition: none !important; 1626 } 1627</style> 1628 1629 1630 1631<div id="pdp-container" class="pdp-container pb-16 lg:pb-20">
1632<script> 1633 window.RevitinGalleryRight2 = { 1634 enabled: false, 1635 citrusRight: "", 1636 citrusRightMobile: "" 1637 }; 1638</script>
1638 1639 <div class="relative pdp_slider_container"> 1640 1641 1642<div 1643 data-swap-flavor="Citrus" 1644 class="opacity-0 relative z-10 !opacity-100 transition-opacity " 1645 > 1646 <div class="lg:hidden"> 1647 <!-- Custom Slider --> 1648 <div class="custom-slider" data-slider-id="gallery_PneosD"> 1649 <!-- Slides Container --> 1650 <div class="slides-container relative overflow-hidden rounded-2xl"> 1651 <div class="slides-wrapper relative"> 1652 <!-- Slide 1 --> 1653 <div class="slide active" data-index="0"> 1654 <div class="aspect-square"> 1655 <img 1656 class="w-full h-full object-cover mobile_main_variety_image" 1657 src="//revitin.com/cdn/shop/files/citrus-gallery-render-mobile_13zon_1000x.jpg?v=1760614313" 1658 loading="lazy" 1659 alt="" 1660 > 1661 </div> 1662 </div> 1663 1664 <!-- Slide 2 --> 1665 <div class="slide" data-index="1"> 1666 <div class="aspect-square"> 1667 <img 1668 class="w-full h-full object-cover mobile_left_variety_image" 1669 src="//revitin.com/cdn/shop/files/citrus-gallery-mobile-2_11zon_1000x.jpg?v=1729883824" 1670 loading="lazy" 1671 alt="" 1672 > 1673 </div> 1674 </div> 1675 1676 <!-- Slide 3 --> 1677 <div class="slide" data-index="2"> 1678 <div class="aspect-square"> 1679 <img 1680 class="w-full h-full object-cover mobile_right_variety_image" 1681 src="//revitin.com/cdn/shop/files/citrus-gallery-mobile-3_11zon_1000x.jpg?v=1729883824" 1682 loading="lazy" 1683 alt="" 1684 > 1685 <img 1686 style="display: none;" 1687 class="absolute top-0 left-0 w-full h-full object-cover object-center rounded-2xl tote_bag_image_mobile" 1688 src="//revitin.com/cdn/shop/t/129/assets/tote-bag-banner-mobile.jpg?v=140778272410589426611777542404" 1689 alt="Free Tote Bag" 1690 > 1691 </div> 1692 </div> 1693 </div> 1694 </div> 1695 1696 <!-- Progress Dots Container --> 1697 <div class="progress-slider-dots-wrapper mt-6 mb-8"> 1698 <div class="progress-slider-dots flex justify-center items-center gap-2"> 1699 <!-- Dot 1 --> 1700 <button class="progress-slider-dot active" data-slide-index="0"> 1701 <span class="dot-progress"></span> 1702 </button> 1703 1704 <!-- Dot 2 --> 1705 <button class="progress-slider-dot" data-slide-index="1"> 1706 <span class="dot-progress"></span> 1707 </button> 1708 1709 <!-- Dot 3 --> 1710 <button class="progress-slider-dot" data-slide-index="2"> 1711 <span class="dot-progress"></span> 1712 </button> 1713 </div> 1714 </div> 1715 </div> 1716 </div> 1717 </div> 1718 1719<div 1720 data-swap-flavor="Mint" 1721 class="opacity-0 absolute top-0 left-0 w-full h-full object-cover object-center transition-opacity " 1722 > 1723 <div class="lg:hidden"> 1724 <!-- Custom Slider --> 1725 <div class="custom-slider" data-slider-id="gallery_SNeidp"> 1726 <!-- Slides Container --> 1727 <div class="slides-container relative overflow-hidden rounded-2xl"> 1728 <div class="slides-wrapper relative"> 1729 <!-- Slide 1 --> 1730 <div class="slide active" data-index="0"> 1731 <div class="aspect-square"> 1732 <img 1733 class="w-full h-full object-cover mobile_main_variety_image" 1734 src="//revitin.com/cdn/shop/files/mint-gallery-render_13zon_1000x.jpg?v=1760614345" 1735 loading="lazy" 1736 alt="" 1737 > 1738 </div> 1739 </div> 1740 1741 <!-- Slide 2 --> 1742 <div class="slide" data-index="1"> 1743 <div class="aspect-square"> 1744 <img 1745 class="w-full h-full object-cover mobile_left_variety_image" 1746 src="//revitin.com/cdn/shop/files/mint-gallery-mobile-2_11zon_1000x.jpg?v=1729883825" 1747 loading="lazy" 1748 alt="" 1749 > 1750 </div> 1751 </div> 1752 1753 <!-- Slide 3 --> 1754 <div class="slide" data-index="2"> 1755 <div class="aspect-square"> 1756 <img 1757 class="w-full h-full object-cover mobile_right_variety_image" 1758 src="//revitin.com/cdn/shop/files/mint-gallery-mobile-3_11zon_1000x.jpg?v=1729883824" 1759 loading="lazy" 1760 alt="" 1761 > 1762 <img 1763 style="display: none;" 1764 class="absolute top-0 left-0 w-full h-full object-cover object-center rounded-2xl tote_bag_image_mobile" 1765 src="//revitin.com/cdn/shop/t/129/assets/tote-bag-banner-mobile.jpg?v=140778272410589426611777542404" 1766 alt="Free Tote Bag" 1767 > 1768 </div> 1769 </div> 1770 </div> 1771 </div> 1772 1773 <!-- Progress Dots Container --> 1774 <div class="progress-slider-dots-wrapper mt-6 mb-8"> 1775 <div class="progress-slider-dots flex justify-center items-center gap-2"> 1776 <!-- Dot 1 --> 1777 <button class="progress-slider-dot active" data-sli
1777de-index="0"> 1778 <span class="dot-progress"></span> 1779 </button> 1780 1781 <!-- Dot 2 --> 1782 <button class="progress-slider-dot" data-slide-index="1"> 1783 <span class="dot-progress"></span> 1784 </button> 1785 1786 <!-- Dot 3 --> 1787 <button class="progress-slider-dot" data-slide-index="2"> 1788 <span class="dot-progress"></span> 1789 </button> 1790 </div> 1791 </div> 1792 </div> 1793 </div> 1794 </div> 1795 1796</div> 1797 1798 <div class="site-container grid lg:grid-cols-[1.25fr_1fr] lg:gap-5"> 1799 <div class="hidden lg:block"> 1800 <div class="relative image_update_container"> 1801 1802 1803<div 1804 data-swap-flavor="Citrus" 1805 class="opacity-0 relative z-10 !opacity-100 transition-opacity" 1806 > 1807 <div> 1808 <div class="aspect-[1.4] relative"> 1809 <img 1810 class="absolute top-0 left-0 w-full h-full object-cover object-center rounded-2xl main_variety_image" 1811 src="//revitin.com/cdn/shop/files/citrus-gallery-render_12zon_1600x.jpg?v=1760509789" 1812 > 1813 </div> 1814 <div class="grid grid-cols-2 mt-5 gap-6"> 1815 <div class="aspect-[0.8] relative"> 1816 <img 1817 class="absolute top-0 left-0 w-full h-full object-cover object-center rounded-2xl left_variety_image" 1818 src="//revitin.com/cdn/shop/files/citrus-gallery-2_11zon_1600x.jpg?v=1729881153" 1819 > 1820 </div> 1821 <div class="aspect-[0.8] relative"> 1822 <img 1823 class="absolute top-0 left-0 w-full h-full object-cover object-center rounded-2xl right_variety_image" 1824 src="//revitin.com/cdn/shop/files/citrus-gallery-3_11zon_1600x.jpg?v=1751389467" 1825 > 1826 <img 1827 style="display: none;" 1828 class="absolute top-0 left-0 w-full h-full object-cover object-center rounded-2xl tote_bag_image" 1829 src="//revitin.com/cdn/shop/t/129/assets/tote-bag-banner.jpg?v=134313350378901709861777542404" 1830 alt="Free Tote Bag" 1831 > 1832 </div> 1833 </div> 1834 </div> 1835 </div> 1836 1837<div 1838 data-swap-flavor="Mint" 1839 class="opacity-0 absolute top-0 left-0 w-full h-full object-cover object-center transition-opacity" 1840 > 1841 <div> 1842 <div class="aspect-[1.4] relative"> 1843 <img 1844 class="absolute top-0 left-0 w-full h-full object-cover object-center rounded-2xl main_variety_image" 1845 src="//revitin.com/cdn/shop/files/mint-render-gallery_12zon_1600x.jpg?v=1760510022" 1846 > 1847 </div> 1848 <div class="grid grid-cols-2 mt-5 gap-6"> 1849 <div class="aspect-[0.8] relative"> 1850 <img 1851 class="absolute top-0 left-0 w-full h-full object-cover object-center rounded-2xl left_variety_image" 1852 src="//revitin.com/cdn/shop/files/mint-gallery-2_11zon_1600x.jpg?v=1751389546" 1853 > 1854 </div> 1855 <div class="aspect-[0.8] relative"> 1856 <img 1857 class="absolute top-0 left-0 w-full h-full object-cover object-center rounded-2xl right_variety_image" 1858 src="//revitin.com/cdn/shop/files/mint-gallery-3_11zon_1600x.jpg?v=1729881153" 1859 > 1860 <img 1861 style="display: none;" 1862 class="absolute top-0 left-0 w-full h-full object-cover object-center rounded-2xl tote_bag_image" 1863 src="//revitin.com/cdn/shop/t/129/assets/tote-bag-banner.jpg?v=134313350378901709861777542404" 1864 alt="Free Tote Bag" 1865 > 1866 </div> 1867 </div> 1868 </div> 1869 </div> 1870 1871 </div> 1872 </div> 1873 1874 <div class="text-base lg:text-lg lg:my-24 lg:max-w-md lg:px-0 mx-auto"> 1875 <div class="pdp-headline mb-4 grid gap-3"> 1876 1877 <h3 class="text-[1.5rem] lg:text-[1.75rem] main_pdp_size_heading"> 1878 Revitin Natural Toothpaste 1879 </h3> 1880 </div> 1881 1882 <div style="display: block !important;" class="jdgm-widget jdgm-preview-badge mt-2 mb-2"> 1883 <div style='display:none' class='jdgm-prev-badge' data-average-rating='4.54' data-number-of-reviews='869' data-number-of-questions='0'> <span class='jdgm-prev-badge__stars' data-score='4.54' tabindex='0' aria-label='4.54 stars' role='button'> <span class='jdgm-star jdgm--on'></span><span class='jdgm-star jdgm--on'></span><span class='jdgm-star jdgm--on'></span><span class='jdgm-star jdgm--on'></span><span class='jdgm-star jdgm--half'></span> </span> <span class='jdgm-prev-badge__text'> 869 reviews </span> </div> 1884 </div> 1885 1886 1887 <div class="mb-6"> 1888 <p>Promote a healthy balance of your oral ecology to support oral health and wellness for whiter teeth and fresher breath.</p> 1889 </div> 1890 1891 1892 <div class="selection_btn_container pdp-size-selector"> 1893 <div> 1894 <button class="size_selection_btn full-size-btn font-body-medium text-base lg:text-lg">Full Size</button> 1895 </div> 1896 <div> 1897 <button class="size_selection_btn travel-size-btn font-body-medium text-base lg:text-lg">Travel Size</button> 1898 </div> 1899 </div> 1900 1901 <div> 1902 1903 <div class="full__size__container">
1903<script src="//revitin.com/cdn/shop/t/129/assets/web-components-product-form.js?v=118024866748551223521789645463" defer></script>
1903<style> 1904 .pos-rel { 1905 position: relative; 1906 top: 10px; 1907 } 1908 1909 .up { 1910 position: relative; 1911 top: -10px; 1912 } 1913 1914 @media screen and (max-width: 560px) { 1915 .pos-rel { 1916 position: relative; 1917 top: 4px; 1918 } 1919 } 1920</style> 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941
1941<script type="application/json" id="product-variants-test"> 1942 [{"id":6606432174218,"title":"Revitin Toothpaste Single Tube","handle":"revitin-natural-toothpaste","description":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e","published_at":"2024-10-16T06:49:11-04:00","created_at":"2021-08-06T06:37:22-04:00","vendor":"Revitin® Natural Toothpaste","type":"Toothpaste","tags":["Toothpaste","wholesale"],"price":1700,"price_min":1700,"price_max":1700,"available":true,"price_varies":false,"compare_at_price":1700,"compare_at_price_min":1700,"compare_at_price_max":1700,"compare_at_price_varies":false,"variants":[{"id":45594631471242,"title":"Citrus","option1":"Citrus","option2":null,"option3":null,"sku":"CITRUS1","requires_shipping":true,"taxable":true,"featured_image":{"id":40562040373386,"product_id":6606432174218,"position":8,"created_at":"2026-03-24T03:32:29-04:00","updated_at":"2026-03-24T03:32:31-04:00","alt":null,"width":4320,"height":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e232e154-1f22-47a5-97a3-a93e8238766d.png?v=1774337551","variant_ids":[45594631471242]},"available":true,"name":"Revitin Toothpaste Single Tube - Citrus","public_title":"Citrus","options":["Citrus"],"price":1700,"weight":136,"compare_at_price":1700,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":null,"id":31853180453002,"position":8,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e232e154-1f22-47a5-97a3-a93e8238766d.png?v=1774337551"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}}],"images":["\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-render-mobile_11zon.jpg?v=1742298905","\/\/revitin.com\/cdn\/shop\/files\/citrus-featured_11zon.jpg?v=1751389467","\/\/revitin.com\/cdn\/shop\/files\/citrus-render.png?v=1751390073","\/\/revitin.com\/cdn\/shop\/files\/citrus-featured-mobile_11zon.jpg?v=1742298805","\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-3_11zon.jpg?v=1751389467","\/\/revitin.com\/cdn\/shop\/files\/main-grapefruit_90add639-f630-489f-9558-ad382aba44cc.png?v=1741690920","\/\/revitin.com\/cdn\/shop\/files\/10001.jpg?v=1742293659","\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e232e154-1f22-47a5-97a3-a93e8238766d.png?v=1774337551"],"featured_image":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-render-mobile_11zon.jpg?v=1742298905","options":["Flavor"],"media":[{"alt":null,"id":28303268577418,"position":1,"preview_image":{"aspect_ratio":1.0,"height":1881,"width":1881,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-render-mobile_11zon.jpg?v=1742298905"},"aspect_ratio":1.0,"height":1881,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-render-mobile_11zon.jpg?v=1742298905","width":1881},{"alt":null,"id":28285089742986,"position":2,"preview_image":{"aspect_ratio":1.333,"height":1714,"width":2285,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-featured_11zon.jpg?v=1751389467"},"aspect_ratio":1.333,"height":1714,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-featured_11zon.jpg?v=1751389467","width":2285},{"alt":null,"id":28274202902666,"position":3,"preview_image":{"aspect_ratio":0.296,"height":1890,"width":560,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-render.png?v=1751390073"},"aspect_ratio":0.296,"height":1890,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-render.png?v=1751390073","width":560},{"alt":null,"id":28285201186954,"position":4,"preview_image":{"aspect_ratio":1.0,"height":1881,"width":188
19421,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-featured-mobile_11zon.jpg?v=1742298805"},"aspect_ratio":1.0,"height":1881,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-featured-mobile_11zon.jpg?v=1742298805","width":1881},{"alt":null,"id":28285089546378,"position":5,"preview_image":{"aspect_ratio":0.8,"height":1301,"width":1041,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-3_11zon.jpg?v=1751389467"},"aspect_ratio":0.8,"height":1301,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-3_11zon.jpg?v=1751389467","width":1041},{"alt":null,"id":29258749935754,"position":6,"preview_image":{"aspect_ratio":0.872,"height":825,"width":719,"src":"\/\/revitin.com\/cdn\/shop\/files\/main-grapefruit_90add639-f630-489f-9558-ad382aba44cc.png?v=1741690920"},"aspect_ratio":0.872,"height":825,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/main-grapefruit_90add639-f630-489f-9558-ad382aba44cc.png?v=1741690920","width":719},{"alt":null,"id":29315872293002,"position":7,"preview_image":{"aspect_ratio":1.333,"height":1500,"width":2000,"src":"\/\/revitin.com\/cdn\/shop\/files\/10001.jpg?v=1742293659"},"aspect_ratio":1.333,"height":1500,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/10001.jpg?v=1742293659","width":2000},{"alt":null,"id":31853180453002,"position":8,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e232e154-1f22-47a5-97a3-a93e8238766d.png?v=1774337551"},"aspect_ratio":1.0,"height":4320,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e232e154-1f22-47a5-97a3-a93e8238766d.png?v=1774337551","width":4320}],"requires_selling_plan":false,"selling_plan_groups":[],"content":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e"},{"id":8334203355274,"title":"Revitin Toothpaste Single Tube","handle":"revitin-toothpaste-single-tube-mint","description":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e","published_at":"2026-05-20T10:37:39-04:00","created_at":"2024-10-24T17:20:10-04:00","vendor":"Revitin® Natural Toothpaste","type":"Toothpaste","tags":["Toothpaste","wholesale"],"price":1700,"price_min":1700,"price_max":1700,"available":true,"price_varies":false,"compare_at_price":1700,"compare_at_price_min":1700,"compare_at_price_max":1700,"compare_at_price_varies":false,"variants":[{"id":45622706602122,"title":"Mint","option1":"Mint","option2":null,"option3":null,"sku":"MINT1","requires_shipping":true,"taxable":true,"featured_image":{"id":40562043945098,"product_id":8334203355274,"position":5,"created_at":"2026-03-24T03:33:11-04:00","updated_at":"2026-03-24T03:33:14-04:00","alt":null,"width":4320,"height":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_99a4be1b-921c-4bbc-96f1-3bc4d0999926.png?v=1774337594","variant_ids":[45622706602122]},"available":true,"name":"Revitin Toothpaste Single Tube - Mint","public_title":"Mint","options":["Mint"],"price":1700,"weight":136,"compare_at_price":1700,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":null,"id":31853183565962,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_99a4be1b-921c-4bbc-96f1-3bc4d0999926.png?v=1774337594"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}}],"images":["\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-1_11zon.jpg?v=1751389546","\/\/revitin.com\/cdn\/shop\/files\/mint-render.png?v=1751387541","\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-2_11zon.jpg?v=1751389546","\/\/revitin.com\/cdn\/shop\/files\/mint-featured_11zon.jpg?v=1751389546","\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_99a4be1b-921c-4bbc-96f1-3bc4d0999926.png?v=1774337594","\/\/revitin.com\/cdn\/shop\/files\/Screenshot_2026-05-13_at_4.25.54_PM.png?v=1778704121","\/\/revitin.com\/cdn\/shop\/files\/Screenshot_2026-05-13_at_4.33.10_PM.png?v=1778704398"],"featured_image":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-1_11zon.jpg?v=1751389546","options":["Flavor"],"media":[{"alt":null,"id":28285089611914,"position":1,"preview_image":{"aspect_ratio":1.468,"height":1281,"width":188
19421,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-1_11zon.jpg?v=1751389546"},"aspect_ratio":1.468,"height":1281,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-1_11zon.jpg?v=1751389546","width":1881},{"alt":null,"id":28274203558026,"position":2,"preview_image":{"aspect_ratio":0.296,"height":1890,"width":560,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-render.png?v=1751387541"},"aspect_ratio":0.296,"height":1890,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-render.png?v=1751387541","width":560},{"alt":null,"id":28285089579146,"position":3,"preview_image":{"aspect_ratio":0.8,"height":1301,"width":1041,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-2_11zon.jpg?v=1751389546"},"aspect_ratio":0.8,"height":1301,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-2_11zon.jpg?v=1751389546","width":1041},{"alt":null,"id":28285089775754,"position":4,"preview_image":{"aspect_ratio":1.333,"height":1714,"width":2285,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-featured_11zon.jpg?v=1751389546"},"aspect_ratio":1.333,"height":1714,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-featured_11zon.jpg?v=1751389546","width":2285},{"alt":null,"id":31853183565962,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_99a4be1b-921c-4bbc-96f1-3bc4d0999926.png?v=1774337594"},"aspect_ratio":1.0,"height":4320,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_99a4be1b-921c-4bbc-96f1-3bc4d0999926.png?v=1774337594","width":4320},{"alt":null,"id":32312983978122,"position":6,"preview_image":{"aspect_ratio":1.101,"height":456,"width":502,"src":"\/\/revitin.com\/cdn\/shop\/files\/Screenshot_2026-05-13_at_4.25.54_PM.png?v=1778704121"},"aspect_ratio":1.101,"height":456,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/Screenshot_2026-05-13_at_4.25.54_PM.png?v=1778704121","width":502},{"alt":null,"id":32313027166346,"position":7,"preview_image":{"aspect_ratio":0.672,"height":958,"width":644,"src":"\/\/revitin.com\/cdn\/shop\/files\/Screenshot_2026-05-13_at_4.33.10_PM.png?v=1778704398"},"aspect_ratio":0.672,"height":958,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/Screenshot_2026-05-13_at_4.33.10_PM.png?v=1778704398","width":644}],"requires_selling_plan":false,"selling_plan_groups":[],"content":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e"},{"id":6606431420554,"title":"Revitin Toothpaste (3 Tubes)","handle":"revitin-natural-toothpaste-family-pack-3tubes","description":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e\n","published_at":"2024-10-16T06:50:24-04:00","created_at":"2021-08-06T06:33:37-04:00","vendor":"Revitin® Natural Toothpaste","type":"Toothpaste","tags":["Toothpaste","wholesale"],"price":4600,"price_min":4600,"price_max":4600,"available":true,"price_varies":false,"compare_at_price":5100,"compare_at_price_min":5100,"compare_at_price_max":5100,"compare_at_price_varies":false,"variants":[{"id":45594633666698,"title":"Citrus","option1":"Citrus","option2":null,"option3":null,"sku":"CITRUS3","requires_shipping":true,"taxable":true,"featured_image":{"id":40538658177162,"product_id":6606431420554,"position":5,"created_at":"2026-03-19T07:40:34-04:00","updated_at":"2026-03-19T07:40:37-04:00","alt":null,"width":4320,"height":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus.png?v=1773920437","variant_ids":[45594633666698]},"available":true,"name":"Revitin Toothpaste (3 Tubes) - Citrus","public_title":"Citrus","options":["Citrus"],"price":4600,"weight":363,"compare_at_price":5100,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":null,"id":3183
19421695982730,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus.png?v=1773920437"}},"requires_selling_plan":false,"selling_plan_allocations":[{"price_adjustments":[{"position":1,"price":4200}],"price":4200,"compare_at_price":4600,"per_delivery_price":4200,"selling_plan_id":2436038794,"selling_plan_group_id":"5932612a299fdbcf90454d75cd44c2c3fb5726b3"},{"price_adjustments":[{"position":1,"price":4200}],"price":4200,"compare_at_price":4600,"per_delivery_price":4200,"selling_plan_id":2435973258,"selling_plan_group_id":"2e26c9c13ed68026e86060667b90391f07cc0bff"},{"price_adjustments":[{"position":1,"price":4200}],"price":4200,"compare_at_price":4600,"per_delivery_price":4200,"selling_plan_id":2436071562,"selling_plan_group_id":"699d3d748cc52413eab2420d291604b2288a92dc"},{"price_adjustments":[{"position":1,"price":4200}],"price":4200,"compare_at_price":4600,"per_delivery_price":4200,"selling_plan_id":2436006026,"selling_plan_group_id":"a21da03fb770221fe1d8bd17d0add53d52d1cad7"}],"quantity_rule":{"min":1,"max":null,"increment":1}}],"images":["\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073","\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-1_11zon.jpg?v=1751389467","\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-3_11zon.jpg?v=1751389467","\/\/revitin.com\/cdn\/shop\/files\/citrus-featured_11zon.jpg?v=1751389467","\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus.png?v=1773920437"],"featured_image":"\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073","options":["Flavor"],"media":[{"alt":null,"id":30027639292042,"position":1,"preview_image":{"aspect_ratio":0.296,"height":1890,"width":560,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073"},"aspect_ratio":0.296,"height":1890,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073","width":560},{"alt":null,"id":28285089644682,"position":2,"preview_image":{"aspect_ratio":1.468,"height":1281,"width":1881,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-1_11zon.jpg?v=1751389467"},"aspect_ratio":1.468,"height":1281,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-1_11zon.jpg?v=1751389467","width":1881},{"alt":null,"id":28285089546378,"position":3,"preview_image":{"aspect_ratio":0.8,"height":1301,"width":1041,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-3_11zon.jpg?v=1751389467"},"aspect_ratio":0.8,"height":1301,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-3_11zon.jpg?v=1751389467","width":1041},{"alt":null,"id":28285089742986,"position":4,"preview_image":{"aspect_ratio":1.333,"height":1714,"width":2285,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-featured_11zon.jpg?v=1751389467"},"aspect_ratio":1.333,"height":1714,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-featured_11zon.jpg?v=1751389467","width":2285},{"alt":null,"id":31831695982730,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus.png?v=1773920437"},"aspect_ratio":1.0,"height":4320,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus.png?v=1773920437","width":4320}],"requires_selling_plan":false,"selling_plan_groups":[{"id":"5932612a299fdbcf90454d75cd44c2c3fb5726b3","name":"Delivery every 1 month","options":[{"name":"Recharge Plan ID","position":1,"values":["17296259"]},{"name":"Order Frequency and Unit","position":2,"values":["1-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436038794,"name":"Delivery every 1 month","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296259"},{"name":"Order Frequency and Unit","position":2,"value":"1-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"8.69"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"},{"id":"2e26c9c13ed68026e86060667b90391f07cc0bff","name":"Delivery every 2 months","options":[{"name":"Recharge Plan ID","position":1,"values":["17296260"]},{"name":"Order Frequency and Unit","position":2,"values":["2-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2435973258,"name":"Delivery every 2 months","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296260"},{"name":"Order Frequency and Unit","position":2,"value":"2-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"8.69"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"},{"id":"699d3d748cc52413eab2420d291604b2288a92dc","name":"Delivery every 3 months","options":[{"name":"Recharge Plan ID","position":1,"values":["12148491"]},{"name":"Order Frequency and Unit","position":2,"values":["3-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436071562,"name":"Delivery every 3 months","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"12148491"},{"name":"Order Frequency and Unit","position":2,"value":"3-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"8.69"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"},{"id":"a21da03fb770221fe1d8bd17d0add53d52d1cad7","name":"Delivery every 6 months","options":[{"name":"Recharge Plan ID","position":1,"values":["17296261"]},{"name":"Order Frequency and Unit","position":2,"values":["6-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436006026,"name":"Delivery every 6 months","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296261"},{"name":"Order Frequency and Unit","position":2,"value":"6-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"8.69"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"}],"content":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e\n"},{"id":8333322846346,"title":"Revitin Toothpaste (3 Tubes)","handle":"revitin-toothpaste-3-tubes-mint","description":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e","published_at":"2024-10-23T11:54:51-04:00","created_at":"2024-10-23T11:52:39-04:00","vendor":"Revitin® Natural Toothpaste","type":"Toothpaste","tags":["Toothpaste","wholesale"],"price":4600,"price_min":4600,"price_max":4600,"available":true,"price_varies":false,"compare_at_price":5100,"compare_at_price_min":5100,"compare_at_price_max":5100,"compare_at_price_varies":false,"variants":[{"id":45618606080138,"title":"Mint","option1":"Mint","option2":null,"option3":null,"sku":"MINT3","requires_shipping":true,"taxable":true,"featured_image":{"id":40558673756298,"product_id":8333322846346,"position":5,"created_at":"2026-03-23T12:22:23-04:00","updated_at":"2026-03-23T12:22:26-04:00","alt":null,"width":4320,"height":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint.png?v=1774282946","variant_ids":[45618606080138]},"available":true,"name":"Revitin Toothpaste (3 Tubes) - Mint","public_title":"Mint","options":["Mint"],"price":4600,"weight":363,"compare_at_price":5100,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":null,"id":31850726850698,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint.png?v=1774282946"}},"requires_selling_plan":false,"selling_plan_allocations":[{"price_adjustments":[{"position":1,"price":4200}],"price":4200,"compare_at_price":4600,"per_delivery_price":4200,"selling_plan_id":2436497546,"selling_plan_group_id":"5932612a299fdbcf90454d75cd44c2c3fb5726b3"},{"price_adjustments":[{"position":1,"price":4200}],"price":4200,"compare_at_price":4600,"per_delivery_price":4200,"selling_plan_id":2436300938,"selling_plan_group_id":"2e26c9c13ed68026e86060667b90391f07cc0bff"},{"price_adjustments":[{"position":1,"price":4200}],"price":4200,"compare_at_price":4600,"per_delivery_price":4200,"selling_plan_id":2436530314,"selling_plan_group_id":"699d3d748cc52413eab2420d291604b2288a92dc"},{"price_adjustments":[{"position":1,"price":4200}],"price":4200,"compare_at_price":4600,"per_delivery_price":4200,"selling_plan_id":2436563082,"selling_plan_group_id":"a21da03fb770221fe1d8bd17d0add53d52d1cad7"}],"quantity_rule":{"min":1,"max":null,"increment":1}}],"images":["\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753","\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-1_11zon.jpg?v=1751389546","\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-2_11zon.jpg?v=1751389546","\/\/revitin.com\/cdn\/shop\/files\/mint-featured_11zon.jpg?v=1751389546","\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint.png?v=1774282946"],"featured_image":"\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753","options":["Flavor"],"media":[{"alt":null,"id":30027583029386,"position":1,"preview_image":{"aspect_ratio":0.296,"he
1942ight":1890,"width":560,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753"},"aspect_ratio":0.296,"height":1890,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753","width":560},{"alt":null,"id":28285089611914,"position":2,"preview_image":{"aspect_ratio":1.468,"height":1281,"width":1881,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-1_11zon.jpg?v=1751389546"},"aspect_ratio":1.468,"height":1281,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-1_11zon.jpg?v=1751389546","width":1881},{"alt":null,"id":28285089579146,"position":3,"preview_image":{"aspect_ratio":0.8,"height":1301,"width":1041,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-2_11zon.jpg?v=1751389546"},"aspect_ratio":0.8,"height":1301,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-2_11zon.jpg?v=1751389546","width":1041},{"alt":null,"id":28285089775754,"position":4,"preview_image":{"aspect_ratio":1.333,"height":1714,"width":2285,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-featured_11zon.jpg?v=1751389546"},"aspect_ratio":1.333,"height":1714,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-featured_11zon.jpg?v=1751389546","width":2285},{"alt":null,"id":31850726850698,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint.png?v=1774282946"},"aspect_ratio":1.0,"height":4320,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint.png?v=1774282946","width":4320}],"requires_selling_plan":false,"selling_plan_groups":[{"id":"5932612a299fdbcf90454d75cd44c2c3fb5726b3","name":"Delivery every 1 month","options":[{"name":"Recharge Plan ID","position":1,"values":["17296246"]},{"name":"Order Frequency and Unit","position":2,"values":["1-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436497546,"name":"Delivery every 1 month","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296246"},{"name":"Order Frequency and Unit","position":2,"value":"1-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"8.69"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"},{"id":"2e26c9c13ed68026e86060667b90391f07cc0bff","name":"Delivery every 2 months","options":[{"name":"Recharge Plan ID","position":1,"values":["17296247"]},{"name":"Order Frequency and Unit","position":2,"values":["2-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436300938,"name":"Delivery every 2 months","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296247"},{"name":"Order Frequency and Unit","position":2,"value":"2-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"8.69"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"},{"id":"699d3d748cc52413eab2420d291604b2288a92dc","name":"Delivery every 3 months","options":[{"name":"Recharge Plan ID","position":1,"values":["17296248"]},{"name":"Order Frequency and Unit","position":2,"values":["3-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436530314,"name":"Delivery every 3 months","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296248"},{"name":"Order Frequency and Unit","position":2,"value":"3-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"8.69"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"},{"id":"a21da03fb770221fe1d8bd17d0add53d52d1cad7","name":"Delivery every 6 months","options":[{"name":"Recharge Plan ID","position":1,"values":["17296249"]},{"name":"Order Frequency and Unit","position":2,"values":["6-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436563082,"name":"Delivery every 6 months","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296249"},{"name":"Order Frequency and Unit","position":2,"value":"6-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"8.69"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"}],"content":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e"},{"id":7609245171850,"title":"Revitin Toothpaste (5 Tubes)","handle":"revitin-toothpaste-5-tubes","description":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e","published_at":"2024-10-16T06:49:01-04:00","created_at":"2022-12-09T17:51:22-05:00","vendor":"Revitin® Natural Toothpaste","type":"Toothpaste","tags":["Subscription","Toothpaste","wholesale"],"price":7000,"price_min":7000,"price_max":7000,"available":true,"price_varies":false,"compare_at_price":8500,"compare_at_price_min":8500,"compare_at_price_max":8500,"compare_at_price_varies":false,"variants":[{"id":45594652901514,"title":"Citrus","option1":"Citrus","option2":null,"option3":null,"sku":"CITRUS5","requires_shipping":true,"taxable":true,"featured_image":{"id":40562055217290,"product_id":7609245171850,"position":5,"created_at":"2026-03-24T03:35:02-04:00","updated_at":"2026-03-24T03:35:05-04:00","alt":null,"width":4320,"height":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e9fa6364-9bfe-4cd7-b0af-1a95d93ee5ba.png?v=1774337705","variant_ids":[45594652901514]},"available":true,"name":"Revitin Toothpaste (5 Tubes) - Citrus","public_title":"Citrus","options":["Citrus"],"price":7000,"weight":136,"compare_at_price":8500,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":null,"id":31853193199754,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e9fa6364-9bfe-4cd7-b0af-1a95d93ee5ba.png?v=1774337705"}},"requires_selling_plan":false,"selling_plan_allocations":[{"price_adjustments":[{"position":1,"price":6800}],"price":6800,"compare_at_price":7000,"per_delivery_price":6800,"selling_plan_id":2436137098,"selling_plan_group_id":"5932612a299fdbcf90454d75cd44c2c3fb5726b3"},{"price_adjustments":[{"position":1,"price":6800}],"price":6800,"compare_at_price":7000,"per_delivery_price":6800,"selling_plan_id":2436104330,"selling_plan_group_id":"2e26c9c13ed68026e86060667b90391f07cc0bff"},{"price_adjustments":[{"position":1,"price":6800}],"price":6800,"compare_at_price":7000,"per_delivery_price":6800,"selling_plan_id":2436202634,"selling_plan_group_id":"699d3d748cc52413eab2420d291604b2288a92dc"},{"price_adjustments":[{"position":1,"price":6800}],"price":6800,"compare_at_price":7000,"per_delivery_price":6800,"selling_plan_id":2436169866,"selling_plan_group_id":"a21da03fb770221fe1d8bd17d0add53d52d1cad7"}],"quantity_rule":{"min":1,"max":null,"increment":1}}],"images":["\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073","\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-1_11zon.jpg?v=1751389467","\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-3_11zon.jpg?v=1751389467","\/\/revitin.com\/cdn\/shop\/files\/citrus-featured_11zon.jpg?v=1751389467","\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e9fa6364-9bfe-4cd7-b0af-1a95d93ee5ba.png?v=1774337705"],"featured_image":"\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073","options":["Flavor"],"media":[{"alt":null,"id":30027639292042,"position":1,"preview_image":{"aspect_ratio":0.296,"he
1942ight":1890,"width":560,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073"},"aspect_ratio":0.296,"height":1890,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073","width":560},{"alt":null,"id":28285089644682,"position":2,"preview_image":{"aspect_ratio":1.468,"height":1281,"width":1881,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-1_11zon.jpg?v=1751389467"},"aspect_ratio":1.468,"height":1281,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-1_11zon.jpg?v=1751389467","width":1881},{"alt":null,"id":28285089546378,"position":3,"preview_image":{"aspect_ratio":0.8,"height":1301,"width":1041,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-3_11zon.jpg?v=1751389467"},"aspect_ratio":0.8,"height":1301,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-gallery-3_11zon.jpg?v=1751389467","width":1041},{"alt":null,"id":28285089742986,"position":4,"preview_image":{"aspect_ratio":1.333,"height":1714,"width":2285,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-featured_11zon.jpg?v=1751389467"},"aspect_ratio":1.333,"height":1714,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-featured_11zon.jpg?v=1751389467","width":2285},{"alt":null,"id":31853193199754,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e9fa6364-9bfe-4cd7-b0af-1a95d93ee5ba.png?v=1774337705"},"aspect_ratio":1.0,"height":4320,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_e9fa6364-9bfe-4cd7-b0af-1a95d93ee5ba.png?v=1774337705","width":4320}],"requires_selling_plan":false,"selling_plan_groups":[{"id":"5932612a299fdbcf90454d75cd44c2c3fb5726b3","name":"Delivery every 1 month","options":[{"name":"Recharge Plan ID","position":1,"values":["17296263"]},{"name":"Order Frequency and Unit","position":2,"values":["1-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436137098,"name":"Delivery every 1 month","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296263"},{"name":"Order Frequency and Unit","position":2,"value":"1-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"2.86"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"},{"id":"2e26c9c13ed68026e86060667b90391f07cc0bff","name":"Delivery every 2 months","options":[{"name":"Recharge Plan ID","position":1,"values":["17296264"]},{"name":"Order Frequency and Unit","position":2,"values":["2-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436104330,"name":"Delivery every 2 months","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296264"},{"name":"Order Frequency and Unit","position":2,"value":"2-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"2.86"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"},{"id":"699d3d748cc52413eab2420d291604b2288a92dc","name":"Delivery every 3 months","options":[{"name":"Recharge Plan ID","position":1,"values":["17296265"]},{"name":"Order Frequency and Unit","position":2,"values":["3-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436202634,"name":"Delivery every 3 months","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296265"},{"name":"Order Frequency and Unit","position":2,"value":"3-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"2.86"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"},{"id":"a21da03fb770221fe1d8bd17d0add53d52d1cad7","name":"Delivery every 6 months","options":[{"name":"Recharge Plan ID","position":1,"values":["17296266"]},{"name":"Order Frequency and Unit","position":2,"values":["6-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436169866,"name":"Delivery every 6 months","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296266"},{"name":"Order Frequency and Unit","position":2,"value":"6-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"2.86"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"}],"content":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e"},{"id":8333359808650,"title":"Revitin Toothpaste (5 Tubes)","handle":"revitin-toothpaste-5-tubes-mint","description":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e","published_at":"2024-10-23T12:06:34-04:00","created_at":"2024-10-23T12:06:35-04:00","vendor":"Revitin® Natural Toothpaste","type":"Toothpaste","tags":["Subscription","Toothpaste","wholesale"],"price":7000,"price_min":7000,"price_max":7000,"available":true,"price_varies":false,"compare_at_price":8500,"compare_at_price_min":8500,"compare_at_price_max":8500,"compare_at_price_varies":false,"variants":[{"id":45618689310858,"title":"Mint","option1":"Mint","option2":null,"option3":null,"sku":"MINT5","requires_shipping":true,"taxable":true,"featured_image":{"id":40562064162954,"product_id":8333359808650,"position":5,"created_at":"2026-03-24T03:35:53-04:00","updated_at":"2026-03-24T03:35:56-04:00","alt":null,"width":4320,"height":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_37b5d288-2b5a-42a4-bd87-71596a6bf4b4.png?v=1774337756","variant_ids":[45618689310858]},"available":true,"name":"Revitin Toothpaste (5 Tubes) - Mint","public_title":"Mint","options":["Mint"],"price":7000,"weight":136,"compare_at_price":8500,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":null,"id":31853201653898,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_37b5d288-2b5a-42a4-bd87-71596a6bf4b4.png?v=1774337756"}},"requires_selling_plan":false,"selling_plan_allocations":[{"price_adjustments":[{"position":1,"price":6800}],"price":6800,"compare_at_price":7000,"per_delivery_price":6800,"selling_plan_id":2436333706,"selling_plan_group_id":"c0f50a62bfd9e3ac72834b6fb633f35bd3c14993"},{"price_adjustments":[{"position":1,"price":6800}],"price":6800,"compare_at_price":7000,"per_delivery_price":6800,"selling_plan_id":2436399242,"selling_plan_group_id":"7071418883f10d584b0e3b2e54d3b89463db3f25"},{"price_adjustments":[{"position":1,"price":6800}],"price":6800,"compare_at_price":7000,"per_delivery_price":6800,"selling_plan_id":2436366474,"selling_plan_group_id":"8f901073b4a7857c567b4d2de0c8c025f5fa5274"},{"price_adjustments":[{"position":1,"price":6800}],"price":6800,"compare_at_price":7000,"per_delivery_price":6800,"selling_plan_id":2436595850,"selling_plan_group_id":"13abe440ede87c4bd3a6b9bac60769eb374fc963"}],"quantity_rule":{"min":1,"max":null,"increment":1}}],"images":["\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753","\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-1_11zon.jpg?v=1751389546","\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-2_11zon.jpg?v=1751389546","\/\/revitin.com\/cdn\/shop\/files\/mint-featured_11zon.jpg?v=1751389546","\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_37b5d288-2b5a-42a4-bd87-71596a6bf4b4.png?v=1774337756"],"featured_image":"\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753","options":["Flavor"],"media":[{"alt":null,"id":30027583029386,"position":1,"preview_image":{"aspect_ratio":0.296,"he
1942ight":1890,"width":560,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753"},"aspect_ratio":0.296,"height":1890,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753","width":560},{"alt":null,"id":28285089611914,"position":2,"preview_image":{"aspect_ratio":1.468,"height":1281,"width":1881,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-1_11zon.jpg?v=1751389546"},"aspect_ratio":1.468,"height":1281,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-1_11zon.jpg?v=1751389546","width":1881},{"alt":null,"id":28285089579146,"position":3,"preview_image":{"aspect_ratio":0.8,"height":1301,"width":1041,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-2_11zon.jpg?v=1751389546"},"aspect_ratio":0.8,"height":1301,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-gallery-2_11zon.jpg?v=1751389546","width":1041},{"alt":null,"id":28285089775754,"position":4,"preview_image":{"aspect_ratio":1.333,"height":1714,"width":2285,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-featured_11zon.jpg?v=1751389546"},"aspect_ratio":1.333,"height":1714,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-featured_11zon.jpg?v=1751389546","width":2285},{"alt":null,"id":31853201653898,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_37b5d288-2b5a-42a4-bd87-71596a6bf4b4.png?v=1774337756"},"aspect_ratio":1.0,"height":4320,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_37b5d288-2b5a-42a4-bd87-71596a6bf4b4.png?v=1774337756","width":4320}],"requires_selling_plan":false,"selling_plan_groups":[{"id":"c0f50a62bfd9e3ac72834b6fb633f35bd3c14993","name":"Delivery every 1 month with 17.65% discount","options":[{"name":"Recharge Plan ID","position":1,"values":["17296301"]},{"name":"Order Frequency and Unit","position":2,"values":["1-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436333706,"name":"Delivery every 1 month with 17.65% discount","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296301"},{"name":"Order Frequency and Unit","position":2,"value":"1-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"2.86"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"},{"id":"7071418883f10d584b0e3b2e54d3b89463db3f25","name":"Delivery every 2 months with 17.65% discount","options":[{"name":"Recharge Plan ID","position":1,"values":["17296302"]},{"name":"Order Frequency and Unit","position":2,"values":["2-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436399242,"name":"Delivery every 2 months with 17.65% discount","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296302"},{"name":"Order Frequency and Unit","position":2,"value":"2-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"2.86"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"},{"id":"8f901073b4a7857c567b4d2de0c8c025f5fa5274","name":"Delivery every 3 months with 17.65% discount","options":[{"name":"Recharge Plan ID","position":1,"values":["17296303"]},{"name":"Order Frequency and Unit","position":2,"values":["3-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436366474,"name":"Delivery every 3 months with 17.65% discount","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296303"},{"name":"Order Frequency and Unit","position":2,"value":"3-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"2.86"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"}
1942,{"id":"13abe440ede87c4bd3a6b9bac60769eb374fc963","name":"Delivery every 6 months with 17.65% discount","options":[{"name":"Recharge Plan ID","position":1,"values":["17296304"]},{"name":"Order Frequency and Unit","position":2,"values":["6-month"]},{"name":"Product Quantity","position":3,"values":["0"]}],"selling_plans":[{"id":2436595850,"name":"Delivery every 6 months with 17.65% discount","description":null,"options":[{"name":"Recharge Plan ID","position":1,"value":"17296304"},{"name":"Order Frequency and Unit","position":2,"value":"6-month"},{"name":"Product Quantity","position":3,"value":"0"}],"recurring_deliveries":true,"price_adjustments":[{"order_count":null,"position":1,"value_type":"percentage","value":"2.86"}],"checkout_charge":{"value_type":"percentage","value":100}}],"app_id":"294517"}],"content":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e"},{"id":7890501009546,"title":"Revitin Toothpaste (25 Tubes)","handle":"copy-of-revitin-toothpaste-25-tubes-gm","description":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e","published_at":"2024-10-16T06:49:40-04:00","created_at":"2024-01-24T12:24:11-05:00","vendor":"Revitin® Natural Toothpaste","type":"Toothpaste","tags":["Max25","Toothpaste","wholesale"],"price":35000,"price_min":35000,"price_max":35000,"available":true,"price_varies":false,"compare_at_price":42500,"compare_at_price_min":42500,"compare_at_price_max":42500,"compare_at_price_varies":false,"variants":[{"id":45594657161354,"title":"Citrus","option1":"Citrus","option2":null,"option3":null,"sku":"CITRUS25","requires_shipping":true,"taxable":true,"featured_image":{"id":40562095194250,"product_id":7890501009546,"position":5,"created_at":"2026-03-24T03:40:59-04:00","updated_at":"2026-03-24T03:41:02-04:00","alt":null,"width":4320,"height":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_5dd0e011-ff5d-4356-80a8-debbb8fbaa63.png?v=1774338062","variant_ids":[45594657161354]},"available":true,"name":"Revitin Toothpaste (25 Tubes) - Citrus","public_title":"Citrus","options":["Citrus"],"price":35000,"weight":2939,"compare_at_price":42500,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":null,"id":31853227442314,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_5dd0e011-ff5d-4356-80a8-debbb8fbaa63.png?v=1774338062"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}}],"images":["\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073","\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A-removebg-preview_1eb996a0-5ac0-41ba-8838-5bc2ce0fc7b4.png?v=1751389901","\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A_7536a270-a73f-4686-ab65-56c666719954.jpg?v=1751389901","\/\/revitin.com\/cdn\/shop\/files\/revitin-case1_c93e3dd8-eaa7-413e-97d2-5ce9d0d257fa.jpg?v=1751389901","\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_5dd0e011-ff5d-4356-80a8-debbb8fbaa63.png?v=1774338062"],"featured_image":"\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073","options":["Flavor"],"media":[{"alt":null,"id":30027639292042,"position":1,"preview_image":{"aspect_ratio":0.296,"he
1942ight":1890,"width":560,"src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073"},"aspect_ratio":0.296,"height":1890,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/citrus-render_cream_bg.png?v=1751390073","width":560},{"alt":null,"id":25983153111178,"position":2,"preview_image":{"aspect_ratio":1.0,"height":500,"width":500,"src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A-removebg-preview_1eb996a0-5ac0-41ba-8838-5bc2ce0fc7b4.png?v=1751389901"},"aspect_ratio":1.0,"height":500,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A-removebg-preview_1eb996a0-5ac0-41ba-8838-5bc2ce0fc7b4.png?v=1751389901","width":500},{"alt":"Full Case (25 Tubes)","id":25983153143946,"position":3,"preview_image":{"aspect_ratio":1.0,"height":650,"width":650,"src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A_7536a270-a73f-4686-ab65-56c666719954.jpg?v=1751389901"},"aspect_ratio":1.0,"height":650,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A_7536a270-a73f-4686-ab65-56c666719954.jpg?v=1751389901","width":650},{"alt":null,"id":25983153275018,"position":4,"preview_image":{"aspect_ratio":1.0,"height":960,"width":960,"src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case1_c93e3dd8-eaa7-413e-97d2-5ce9d0d257fa.jpg?v=1751389901"},"aspect_ratio":1.0,"height":960,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case1_c93e3dd8-eaa7-413e-97d2-5ce9d0d257fa.jpg?v=1751389901","width":960},{"alt":null,"id":31853227442314,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_5dd0e011-ff5d-4356-80a8-debbb8fbaa63.png?v=1774338062"},"aspect_ratio":1.0,"height":4320,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Citrus_5dd0e011-ff5d-4356-80a8-debbb8fbaa63.png?v=1774338062","width":4320}],"requires_selling_plan":false,"selling_plan_groups":[],"content":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e"},{"id":8334207778954,"title":"Revitin Toothpaste (25 Tubes)","handle":"revitin-toothpaste-25-tubes-mint","description":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e","published_at":"2024-10-24T17:33:44-04:00","created_at":"2024-10-24T17:33:44-04:00","vendor":"Revitin® Natural Toothpaste","type":"Toothpaste","tags":["Max25","Toothpaste","wholesale"],"price":35000,"price_min":35000,"price_max":35000,"available":true,"price_varies":false,"compare_at_price":42500,"compare_at_price_min":42500,"compare_at_price_max":42500,"compare_at_price_varies":false,"variants":[{"id":45622715121802,"title":"Mint","option1":"Mint","option2":null,"option3":null,"sku":"MINT25","requires_shipping":true,"taxable":true,"featured_image":{"id":40562091294858,"product_id":8334207778954,"position":5,"created_at":"2026-03-24T03:39:53-04:00","updated_at":"2026-03-24T03:39:56-04:00","alt":null,"width":4320,"height":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_5fc8e8a0-5904-477c-9a1d-4ef752e21613.png?v=1774337996","variant_ids":[45622715121802]},"available":true,"name":"Revitin Toothpaste (25 Tubes) - Mint","public_title":"Mint","options":["Mint"],"price":35000,"weight":2939,"compare_at_price":42500,"inventory_management":"shopify","barcode":null,"featured_media":{"alt":null,"id":31853224460426,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_5fc8e8a0-5904-477c-9a1d-4ef752e21613.png?v=1774337996"}},"requires_selling_plan":false,"selling_plan_allocations":[],"quantity_rule":{"min":1,"max":null,"increment":1}}],"images":["\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753","\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A-removebg-preview_1eb996a0-5ac0-41ba-8838-5bc2ce0fc7b4.png?v=1751389901","\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A_7536a270-a73f-4686-ab65-56c666719954.jpg?v=1751389901","\/\/revitin.com\/cdn\/shop\/files\/revitin-case1_c93e3dd8-eaa7-413e-97d2-5ce9d0d257fa.jpg?v=1751389901","\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_5fc8e8a0-5904-477c-9a1d-4ef752e21613.png?v=1774337996"],"featured_image":"\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753","options":["Flavor"],"media":[{"alt":null,"id":30027583029386,"position":1,"preview_image":{"aspect_ratio":0.296,"he
1942ight":1890,"width":560,"src":"\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753"},"aspect_ratio":0.296,"height":1890,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/mint-render_cream_bg.png?v=1751389753","width":560},{"alt":null,"id":25983153111178,"position":2,"preview_image":{"aspect_ratio":1.0,"height":500,"width":500,"src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A-removebg-preview_1eb996a0-5ac0-41ba-8838-5bc2ce0fc7b4.png?v=1751389901"},"aspect_ratio":1.0,"height":500,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A-removebg-preview_1eb996a0-5ac0-41ba-8838-5bc2ce0fc7b4.png?v=1751389901","width":500},{"alt":"Full Case (25 Tubes)","id":25983153143946,"position":3,"preview_image":{"aspect_ratio":1.0,"height":650,"width":650,"src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A_7536a270-a73f-4686-ab65-56c666719954.jpg?v=1751389901"},"aspect_ratio":1.0,"height":650,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case-25A_7536a270-a73f-4686-ab65-56c666719954.jpg?v=1751389901","width":650},{"alt":null,"id":25983153275018,"position":4,"preview_image":{"aspect_ratio":1.0,"height":960,"width":960,"src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case1_c93e3dd8-eaa7-413e-97d2-5ce9d0d257fa.jpg?v=1751389901"},"aspect_ratio":1.0,"height":960,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/revitin-case1_c93e3dd8-eaa7-413e-97d2-5ce9d0d257fa.jpg?v=1751389901","width":960},{"alt":null,"id":31853224460426,"position":5,"preview_image":{"aspect_ratio":1.0,"height":4320,"width":4320,"src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_5fc8e8a0-5904-477c-9a1d-4ef752e21613.png?v=1774337996"},"aspect_ratio":1.0,"height":4320,"media_type":"image","src":"\/\/revitin.com\/cdn\/shop\/files\/Full_Size_Mint_5fc8e8a0-5904-477c-9a1d-4ef752e21613.png?v=1774337996","width":4320}],"requires_selling_plan":false,"selling_plan_groups":[],"content":"\u003cp\u003eRevitin supports\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003estrong white teeth\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ehealthy gums\u003c\/strong\u003e, and\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efresher breath\u003c\/strong\u003e. Whatâs more, Revitin tastes great! Revitin is\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003efluoride-free\u003c\/strong\u003e,\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003ewithout Sodium Lauryl Sulfate (SLS free)\u003c\/strong\u003e, and you won't find\u003cspan\u003e \u003c\/span\u003e\u003cstrong\u003eTriclosan either!\u003c\/strong\u003e\u003c\/p\u003e"}] 1943 1944 </script>
1944 1945 1946
1946<script type="application/json" id="product-variants"> 1947 [ 1948 1949 1950 1951 1952 1953 1954 { 1955 "variantId": 45594631471242, 1956 "productTitle": "Revitin Toothpaste Single Tube", 1957 "variantTitle": "Citrus", 1958 "variantPrice": 1700, 1959 "compareAtPrice": 1700, 1960 "sellingPlans": [] 1961 }, 1962 1963 1964 { 1965 "variantId": 45622706602122, 1966 "productTitle": "Revitin Toothpaste Single Tube", 1967 "variantTitle": "Mint", 1968 "variantPrice": 1700, 1969 "compareAtPrice": 1700, 1970 "sellingPlans": [] 1971 }, 1972 1973 1974 { 1975 "variantId": 45594633666698, 1976 "productTitle": "Revitin Toothpaste (3 Tubes)", 1977 "variantTitle": "Citrus", 1978 "variantPrice": 4600, 1979 "compareAtPrice": 5100, 1980 "sellingPlans": [{ 1981 "id": 2436038794, 1982 "price": 4200, 1983 "name": "1-month" 1984 },{ 1985 "id": 2435973258, 1986 "price": 4200, 1987 "name": "2-months" 1988 },{ 1989 "id": 2436071562, 1990 "price": 4200, 1991 "name": "3-months" 1992 },{ 1993 "id": 2436006026, 1994 "price": 4200, 1995 "name": "6-months" 1996 }] 1997 }, 1998 1999 2000 { 2001 "variantId": 45618606080138, 2002 "productTitle": "Revitin Toothpaste (3 Tubes)", 2003 "variantTitle": "Mint", 2004 "variantPrice": 4600, 2005 "compareAtPrice": 5100, 2006 "sellingPlans": [{ 2007 "id": 2436497546, 2008 "price": 4200, 2009 "name": "1-month" 2010 },{ 2011 "id": 2436300938, 2012 "price": 4200, 2013 "name": "2-months" 2014 },{ 2015 "id": 2436530314, 2016 "price": 4200, 2017 "name": "3-months" 2018 },{ 2019 "id": 2436563082, 2020 "price": 4200, 2021 "name": "6-months" 2022 }] 2023 }, 2024 2025 2026 { 2027 "variantId": 45594652901514, 2028 "productTitle": "Revitin Toothpaste (5 Tubes)", 2029 "variantTitle": "Citrus", 2030 "variantPrice": 7000, 2031 "compareAtPrice": 8500, 2032 "sellingPlans": [{ 2033 "id": 2436137098, 2034 "price": 6800, 2035 "name": "1-month" 2036 },{ 2037 "id": 2436104330, 2038 "price": 6800, 2039 "name": "2-months" 2040 },{ 2041 "id": 2436202634, 2042 "price": 6800, 2043 "name": "3-months" 2044 },{ 2045 "id": 2436169866, 2046 "price": 6800, 2047 "name": "6-months" 2048 }] 2049 }, 2050 2051 2052 { 2053 "variantId": 45618689310858, 2054 "productTitle": "Revitin Toothpaste (5 Tubes)", 2055 "variantTitle": "Mint", 2056 "variantPrice": 7000, 2057 "compareAtPrice": 8500, 2058 "sellingPlans": [{ 2059 "id": 2436333706, 2060 "price": 6800, 2061 "name": "1-month" 2062 },{ 2063 "id": 2436399242, 2064 "price": 6800, 2065 "name": "2-months" 2066 },{ 2067 "id": 2436366474, 2068 "price": 6800, 2069 "name": "3-months" 2070 },{ 2071 "id": 2436595850, 2072 "price": 6800, 2073 "name": "6-months" 2074 }] 2075 }, 2076 2077 2078 { 2079 "variantId": 45594657161354, 2080 "productTitle": "Revitin Toothpaste (25 Tubes)", 2081 "variantTitle": "Citrus", 2082 "variantPrice": 35000, 2083 "compareAtPrice": 42500, 2084 "sellingPlans": [] 2085 }, 2086 2087 2088 { 2089 "variantId": 45622715121802, 2090 "productTitle": "Revitin Toothpaste (25 Tubes)", 2091 "variantTitle": "Mint", 2092 "variantPrice": 35000, 2093 "compareAtPrice": 42500, 2094 "sellingPlans": [] 2095 } 2096 2097 ] 2098 </script>
2098 2099 2100 <product-form> 2101 <flavor-selector> 2102 <div class="w-full grid grid-flow-col justify-start gap-2 lg:gap-4 items-center flavour__selector"> 2103 <button 2104 type="button" 2105 data-flavor="Citrus" 2106 style="border: 1px solid #C6C6C6;" 2107 class="flavour-custom flex items-center gap-3 text-brown rounded-[50px] py-2 pl-2 pr-6 lg:hover:bg-gold lg:hover:border-gold transition-colors duration-300 active" 2108 > 2109 <div class="relative w-8 h-8 bg-gold rounded-full flex items-center justify-center p-0.5"> 2110 <img class="rounded-full" src="//revitin.com/cdn/shop/t/129/assets/citrus-teaser.png?v=69425243372235278621777542405" loading="lazy"> 2111 </div> 2112 <div class="font-body-medium text-sm lg:text-lg">Citrus</div> 2113 </button> 2114 <button 2115 type="button" 2116 data-flavor="Mint" 2117 style="border: 1px solid #C6C6C6;" 2118 class="flavour-custom flex items-center gap-3 text-brown rounded-[50px] py-2 pl-2 pr-6 lg:hover:bg-light-green lg:hover:border-light-green transition-colors duration-300" 2119 > 2120 <div class="relative w-8 h-8 bg-light-green rounded-full flex items-center justify-center p-0.5"> 2121 <img class="rounded-full" src="//revitin.com/cdn/shop/t/129/assets/mint-teaser.png?v=43172182657372155721777542403" loading="lazy"> 2122 </div> 2123 <div class="font-body-medium text-sm lg:text-lg">Mint</div> 2124 </button> 2125 <button 2126 type="button" 2127 data-flavor="Variety" 2128 style="border: 1px solid #C6C6C6;" 2129 class="flex items-center variety-selector-btn gap-1 text-brown rounded-[50px] py-2 pl-1 pr-6 lg:hover:bg-light-green lg:hover:border-light-green transition-colors duration-300" 2130 > 2131 <div class="relative flex items-center justify-center variety_tab_btn"> 2132 <img class="" src="//revitin.com/cdn/shop/t/129/assets/mix-match.png?v=98254657463874453371777542404" loading="lazy"> 2133 </div> 2134 <div class="font-body-medium text-sm lg:text-lg">Variety</div> 2135 </button> 2136 </div> 2137 </flavor-selector> 2138 2139 2140 2141 2142 2143 2144
2145<script type="application/json" id="all-products-json"> 2146 [ 2147 2148 { 2149 "id": "8580142694538", 2150 "title": "Citrus Travel 3-Pack of 1oz", 2151 "handle": "revitin-toothpaste-travel-3-tubes", 2152 "description": "", 2153 "vendor": "Revitin", 2154 "product_type": "", 2155 "tags": [], 2156 "url": "/products/revitin-toothpaste-travel-3-tubes", 2157 "aestheticTitle": "Revitin Travel Size Toothpaste", 2158 "homepage_image": "", 2159 "featured_image": { 2160 "src": "//revitin.com/cdn/shop/files/citrus-1oz_1ab1a647-7adc-41ce-8f84-9b64065d72a8.jpg?v=1760422500", 2161 "alt": "Citrus Travel 3-Pack of 1oz" 2162 }, 2163 2164 "images": [ 2165 2166 { 2167 "src": "//revitin.com/cdn/shop/files/citrus-1oz_1ab1a647-7adc-41ce-8f84-9b64065d72a8.jpg?v=1760422500", 2168 "alt": "Citrus Travel 3-Pack of 1oz" 2169 }, 2170 2171 { 2172 "src": "//revitin.com/cdn/shop/files/citrus-1oz-bottom.png?v=1760422500", 2173 "alt": "Citrus Travel 3-Pack of 1oz" 2174 }, 2175 2176 { 2177 "src": "//revitin.com/cdn/shop/files/glbF4rXA.jpg?v=1760615020", 2178 "alt": "Citrus Travel 3-Pack of 1oz" 2179 }, 2180 2181 { 2182 "src": "//revitin.com/cdn/shop/files/citrus-1oz-bottom-mobile.png?v=1760615020", 2183 "alt": "Citrus Travel 3-Pack of 1oz" 2184 }, 2185 2186 { 2187 "src": "//revitin.com/cdn/shop/files/Travel_Size_Citrus.png?v=1774338377", 2188 "alt": "Citrus Travel 3-Pack of 1oz" 2189 } 2190 2191 ], 2192 2193 "options": [{"name":"Flavor","position":1,"values":["Citrus"]}], 2194 2195 "variants": [ 2196 2197 { 2198 "id": "46346187341962", 2199 "title": "Citrus", 2200 "sku": "CitrTravel3-pk", 2201 "available": true, 2202 "price": "18.00", 2203 "compare_at_price": "", 2204 "inventory_quantity": "880", 2205 "sellingPlans": [] 2206 } 2207 2208 ] 2209 }, 2210 2211 { 2212 "id": "8658322555018", 2213 "title": "Citrus Travel Case (100 count)", 2214 "handle": "citrus-travel-case-100-count", 2215 "description": "", 2216 "vendor": "Revitin", 2217 "product_type": "", 2218 "tags": ["wholesale"], 2219 "url": "/products/citrus-travel-case-100-count", 2220 "aestheticTitle": "", 2221 "homepage_image": "", 2222 "featured_image": { 2223 "src": "//revitin.com/cdn/shop/files/citrus-1oz_1ab1a647-7adc-41ce-8f84-9b64065d72a8.jpg?v=1760422500", 2224 "alt": "Citrus Travel Case (100 count)" 2225 }, 2226 2227 "images": [ 2228 2229 { 2230 "src": "//revitin.com/cdn/shop/files/citrus-1oz_1ab1a647-7adc-41ce-8f84-9b64065d72a8.jpg?v=1760422500", 2231 "alt": "Citrus Travel Case (100 count)" 2232 }, 2233 2234 { 2235 "src": "//revitin.com/cdn/shop/files/Travel_Size_Citrus.png?v=1774338377", 2236 "alt": "Citrus Travel Case (100 count)" 2237 } 2238 2239 ], 2240 2241 "options": [{"name":"Flavor","position":1,"values":["Citrus"]}], 2242 2243 "variants": [ 2244 2245 { 2246 "id": "46994967527562", 2247 "title": "Citrus", 2248 "sku": "CITRUSTRAVEL100", 2249 "available": true, 2250 "price": "300.00", 2251 "compare_at_price": "600.00", 2252 "inventory_quantity": "597", 2253 "sellingPlans": [] 2254 } 2255 2256 ] 2257 }, 2258 2259 { 2260 "id": "8580143349898", 2261 "title": "Mint Travel 3-Pack of 1oz", 2262 "handle": "revitin-toothpaste-travel-3-tubes-1", 2263 "description": "", 2264 "vendor": "Revitin", 2265 "product_type": "", 2266 "tags": [], 2267 "url": "/products/revitin-toothpaste-travel-3-tubes-1", 2268 "aestheticTitle": "Revitin Travel Size Toothpaste", 2269 "homepage_image": "", 2270 "featured_image": { 2271 "src": "//revitin.com/cdn/shop/files/mint-1oz.jpg?v=1760421639", 2272 "alt": "Mint Travel 3-Pack of 1oz" 2273 }, 2274 2275 "images": [ 2276 2277 { 2278 "src": "//revitin.com/cdn/shop/files/mint-1oz.jpg?v=1760421639", 2279 "alt": "Mint Travel 3-Pack of 1oz" 2280 }, 2281 2282 { 2283 "src": "//revitin.com/cdn/shop/files/KacptZKA.jpg?v=1760614976", 2284 "alt": "Mint Travel 3-Pack of 1oz" 2285 }, 2286 2287 { 2288 "src": "//revitin.com/cdn/shop/files/XKZRPDJQ.jpg?v=1760614976", 2289 "alt": "Mint Travel 3-Pack of 1oz" 2290 }, 2291 2292 { 2293 "src": "//revitin.com/cdn/shop/files/mint-1oz-bottom-mobile.jpg?v=1760614976", 2294 "alt": "Mint Travel 3-Pack of 1oz" 2295 }, 2296 2297 { 2298 "src": "//revitin.com/cdn/shop/files/Travel_Size_Mint.png?v=1774338342", 2299 "alt": "Mint Travel 3-Pack of 1oz" 2300 } 2301 2302 ], 2303 2304 "options": [{"name":"Flavor","position":1,"values":["Mint"]}], 2305 2306 "variants": [ 2307 2308 { 2309 "id": "46346189045898", 2310 "title": "Mint", 2311 "sku": "MintTravel3-pk", 2312 "available": true, 2313 "price": "18.00", 2314 "compare_at_price": "", 2315 "inventory_quantity": "484", 2316 "sellingPlans": [] 2317 } 2318 2319 ] 2320 }, 2321 2322 { 2323 "id": "8658320261258", 2324 "title": "Mint Travel Case (100 count)", 2325 "handle": "mint-travel-case-100-count", 2326 "description": "", 2327 "vendor": "Revitin", 2328 "product_type": "", 2329 "tags": ["wholesale"], 2330 "url": "/products/mint-travel-case-100-count", 2331 "aestheticTitle": "", 2332 "homepage_image": "", 2333 "featured_image": { 2334 "src": "//revitin.com/cdn/shop/files/mint-1oz.jpg?v=1760421639", 2335 "alt": "Mint Travel Case (100 count)" 2336 }, 2337 2338 "images": [ 2339 2340 { 2341 "src": "//revitin.com/cdn/shop/files/mint-1oz.jpg?v=1760421639", 2342 "alt": "Mint Travel Case (100 count)" 2343 }, 2344 2345 { 2346 "src": "//revitin.com/cdn/shop/files/Travel_Size_Mint.png?v=1774338342", 2347 "alt": "Mint Travel Case (100 count)" 2348 } 2349 2350 ], 2351 2352 "options": [{"name":"Flavor","position":1,"values":["Mint"]}], 2353 2354 "variants": [ 2355 2356 { 2357 "id": "46994955272330", 2358 "title": "Mint", 2359 "sku": "MINTTRAVEL100", 2360 "available": true, 2361 "price": "300.00", 2362 "compare_at_price": "600.00", 2363 "inventory_quantity": "611", 2364 "sellingPlans": [] 2365 } 2366 2367 ] 2368 }, 2369 2370 { 2371 "id": "6803929432202", 2372 "title": "Replacement Adult Brush Head", 2373 "handle": "replacement-adult-brush-head", 2374 "description": "Replacement head for the Revitin Professional Sonic Toothbrush", 2375 "vendor": "Revitin", 2376 "product_type": "Toothbrush Replacement Heads", 2377 "tags": ["Replacement Heads"], 2378 "url": "/products/replacement-adult-brush-head", 2379 "aestheticTitle": "", 2380 "homepage_image": "", 2381 "featured_image": { 2382 "src": "//revitin.com/cdn/shop/products/ReplacementHead.png?v=1662485289", 2383 "alt": "Replacement Adult Brush Head" 2384 }, 2385 2386 "images": [ 2387 2388 { 2389 "src": "//revitin.com/cdn/shop/products/ReplacementHead.png?v=1662485289", 2390 "alt": "Replacement Adult Brush Head" 2391 } 2392 2393 ], 2394 2395 "options": [{"name":"Title","position":1,"values":["Default Title"]}], 2396 2397 "variants": [ 2398 2399 { 2400 "id": "40896700186762", 2401 "title": "Default Title", 2402 "sku": "R-H6W-RH", 2403 "available": true, 2404 "price": "5.50", 2405 "compare_at_price": "", 2406 "inventory_quantity": "90", 2407 "sellingPlans": [] 2408 } 2409 2410 ] 2411 }, 2412 2413 { 2414 "id": "6606431617162", 2415 "title": "Revitin Toothpaste (25 Tubes)", 2416 "handle": "revitin-natural-toothpaste-fullcase-25tubes", 2417 "description": "Revitin supports strong white teeth, healthy gums, and fresher breath. Whatâs more, Revitin tastes great! Revitin is fluoride-free, without Sodium Lauryl Sulfate (SLS free), and
2417you won't find Triclosan either!", 2418 "vendor": "Revitin® Natural Toothpaste", 2419 "product_type": "Toothpaste", 2420 "tags": ["Max25","Toothpaste","wholesale"], 2421 "url": "/products/revitin-natural-toothpaste-fullcase-25tubes", 2422 "aestheticTitle": "Revitin Natural Toothpaste", 2423 "homepage_image": "", 2424 "featured_image": { 2425 "src": "//revitin.com/cdn/shop/files/Full_Size_Citrus_75330201-6111-4242-bac7-eb4703f1b300.png?v=1774338517", 2426 "alt": "Revitin Toothpaste (25 Tubes)" 2427 }, 2428 2429 "images": [ 2430 2431 { 2432 "src": "//revitin.com/cdn/shop/files/Full_Size_Citrus_75330201-6111-4242-bac7-eb4703f1b300.png?v=1774338517", 2433 "alt": "Revitin Toothpaste (25 Tubes)" 2434 }, 2435 2436 { 2437 "src": "//revitin.com/cdn/shop/products/revitin-case-25A_3a9c3300-7f44-4a68-a2b7-0fd137cfa073-removebg-preview.png?v=1774338517", 2438 "alt": "Revitin Toothpaste (25 Tubes)" 2439 }, 2440 2441 { 2442 "src": "//revitin.com/cdn/shop/products/revitin-case-25A_3a9c3300-7f44-4a68-a2b7-0fd137cfa073.jpg?v=1774338517", 2443 "alt": "Full Case (25 Tubes)" 2444 }, 2445 2446 { 2447 "src": "//revitin.com/cdn/shop/products/revitin-case1_7bb35865-2ba5-41bb-afab-c2fcd7a697a9.jpg?v=1774338517", 2448 "alt": "Revitin Toothpaste (25 Tubes)" 2449 } 2450 2451 ], 2452 2453 "options": [{"name":"Title","position":1,"values":["Default Title"]}], 2454 2455 "variants": [ 2456 2457 { 2458 "id": "39792313729162", 2459 "title": "Default Title", 2460 "sku": "CITRUS25", 2461 "available": true, 2462 "price": "350.00", 2463 "compare_at_price": "425.00", 2464 "inventory_quantity": "1474", 2465 "sellingPlans": [] 2466 } 2467 2468 ] 2469 }, 2470 2471 { 2472 "id": "7890501009546", 2473 "title": "Revitin Toothpaste (25 Tubes)", 2474 "handle": "copy-of-revitin-toothpaste-25-tubes-gm", 2475 "description": "Revitin supports strong white teeth, healthy gums, and fresher breath. Whatâs more, Revitin tastes great! Revitin is fluoride-free, without Sodium Lauryl Sulfate (SLS free), and you won't find Triclosan either!", 2476 "vendor": "Revitin® Natural Toothpaste", 2477 "product_type": "Toothpaste", 2478 "tags": ["Max25","Toothpaste","wholesale"], 2479 "url": "/products/copy-of-revitin-toothpaste-25-tubes-gm", 2480 "aestheticTitle": "Revitin Natural Toothpaste", 2481 "homepage_image": "", 2482 "featured_image": { 2483 "src": "//revitin.com/cdn/shop/files/citrus-render_cream_bg.png?v=1751390073", 2484 "alt": "Revitin Toothpaste (25 Tubes)" 2485 }, 2486 2487 "images": [ 2488 2489 { 2490 "src": "//revitin.com/cdn/shop/files/citrus-render_cream_bg.png?v=1751390073", 2491 "alt": "Revitin Toothpaste (25 Tubes)" 2492 }, 2493 2494 { 2495 "src": "//revitin.com/cdn/shop/files/revitin-case-25A-removebg-preview_1eb996a0-5ac0-41ba-8838-5bc2ce0fc7b4.png?v=1751389901", 2496 "alt": "Revitin Toothpaste (25 Tubes)" 2497 }, 2498 2499 { 2500 "src": "//revitin.com/cdn/shop/files/revitin-case-25A_7536a270-a73f-4686-ab65-56c666719954.jpg?v=1751389901", 2501 "alt": "Full Case (25 Tubes)" 2502 }, 2503 2504 { 2505 "src": "//revitin.com/cdn/shop/files/revitin-case1_c93e3dd8-eaa7-413e-97d2-5ce9d0d257fa.jpg?v=1751389901", 2506 "alt": "Revitin Toothpaste (25 Tubes)" 2507 }, 2508 2509 { 2510 "src": "//revitin.com/cdn/shop/files/Full_Size_Citrus_5dd0e011-ff5d-4356-80a8-debbb8fbaa63.png?v=1774338062", 2511 "alt": "Revitin Toothpaste (25 Tubes)" 2512 } 2513 2514 ], 2515 2516 "options": [{"name":"Flavor","position":1,"values":["Citrus"]}], 2517 2518 "variants": [ 2519 2520 { 2521 "id": "45594657161354", 2522 "title": "Citrus", 2523 "sku": "CITRUS25", 2524 "available": true, 2525 "price": "350.00", 2526 "compare_at_price": "425.00", 2527 "inventory_quantity": "1474", 2528 "sellingPlans": [] 2529 } 2530 2531 ] 2532 }, 2533 2534 { 2535 "id": "8334207778954", 2536 "title": "Revitin Toothpaste (25 Tubes)", 2537 "handle": "revitin-toothpaste-25-tubes-mint", 2538 "description": "Revitin supports strong white teeth, healthy gums, and fresher breath. Whatâs more, Revitin tastes great! Revitin is fluoride-free, without Sodium Lauryl Sulfate (SLS free), and
2538you won't find Triclosan either!", 2539 "vendor": "Revitin® Natural Toothpaste", 2540 "product_type": "Toothpaste", 2541 "tags": ["Max25","Toothpaste","wholesale"], 2542 "url": "/products/revitin-toothpaste-25-tubes-mint", 2543 "aestheticTitle": "Revitin Natural Toothpaste", 2544 "homepage_image": "", 2545 "featured_image": { 2546 "src": "//revitin.com/cdn/shop/files/mint-render_cream_bg.png?v=1751389753", 2547 "alt": "Revitin Toothpaste (25 Tubes)" 2548 }, 2549 2550 "images": [ 2551 2552 { 2553 "src": "//revitin.com/cdn/shop/files/mint-render_cream_bg.png?v=1751389753", 2554 "alt": "Revitin Toothpaste (25 Tubes)" 2555 }, 2556 2557 { 2558 "src": "//revitin.com/cdn/shop/files/revitin-case-25A-removebg-preview_1eb996a0-5ac0-41ba-8838-5bc2ce0fc7b4.png?v=1751389901", 2559 "alt": "Revitin Toothpaste (25 Tubes)" 2560 }, 2561 2562 { 2563 "src": "//revitin.com/cdn/shop/files/revitin-case-25A_7536a270-a73f-4686-ab65-56c666719954.jpg?v=1751389901", 2564 "alt": "Full Case (25 Tubes)" 2565 }, 2566 2567 { 2568 "src": "//revitin.com/cdn/shop/files/revitin-case1_c93e3dd8-eaa7-413e-97d2-5ce9d0d257fa.jpg?v=1751389901", 2569 "alt": "Revitin Toothpaste (25 Tubes)" 2570 }, 2571 2572 { 2573 "src": "//revitin.com/cdn/shop/files/Full_Size_Mint_5fc8e8a0-5904-477c-9a1d-4ef752e21613.png?v=1774337996", 2574 "alt": "Revitin Toothpaste (25 Tubes)" 2575 } 2576 2577 ], 2578 2579 "options": [{"name":"Flavor","position":1,"values":["Mint"]}], 2580 2581 "variants": [ 2582 2583 { 2584 "id": "45622715121802", 2585 "title": "Mint", 2586 "sku": "MINT25", 2587 "available": true, 2588 "price": "350.00", 2589 "compare_at_price": "425.00", 2590 "inventory_quantity": "1889", 2591 "sellingPlans": [] 2592 } 2593 2594 ] 2595 }, 2596 2597 { 2598 "id": "8335794307210", 2599 "title": "Revitin Toothpaste (25 Tubes) Wholesale", 2600 "handle": "revitin-toothpaste-25-tubes-wholesale", 2601 "description": "Revitin supports strong white teeth, healthy gums, and fresher breath. Whatâs more, Revitin tastes great! Revitin is fluoride-free, without Sodium Lauryl Sulfate (SLS free), and you won't find Triclosan either!", 2602 "vendor": "Revitin® Natural Toothpaste", 2603 "product_type": "Toothpaste", 2604 "tags": ["Max25","Toothpaste","wholesale"], 2605 "url": "/products/revitin-toothpaste-25-tubes-wholesale", 2606 "aestheticTitle": "Revitin Natural Toothpaste", 2607 "homepage_image": "", 2608 "featured_image": { 2609 "src": "//revitin.com/cdn/shop/files/citrus-render_cream_bg.png?v=1751390073", 2610 "alt": "Revitin Toothpaste (25 Tubes) Wholesale" 2611 }, 2612 2613 "images": [ 2614 2615 { 2616 "src": "//revitin.com/cdn/shop/files/citrus-render_cream_bg.png?v=1751390073", 2617 "alt": "Revitin Toothpaste (25 Tubes) Wholesale" 2618 }, 2619 2620 { 2621 "src": "//revitin.com/cdn/shop/files/revitin-case-25A-removebg-preview_1eb996a0-5ac0-41ba-8838-5bc2ce0fc7b4.png?v=1751389901", 2622 "alt": "Revitin Toothpaste (25 Tubes) Wholesale" 2623 }, 2624 2625 { 2626 "src": "//revitin.com/cdn/shop/files/revitin-case-25A_7536a270-a73f-4686-ab65-56c666719954.jpg?v=1751389901", 2627 "alt": "Full Case (25 Tubes)" 2628 }, 2629 2630 { 2631 "src": "//revitin.com/cdn/shop/files/revitin-case1_c93e3dd8-eaa7-413e-97d2-5ce9d0d257fa.jpg?v=1751389901", 2632 "alt": "Revitin Toothpaste (25 Tubes) Wholesale" 2633 }, 2634 2635 { 2636 "src": "//revitin.com/cdn/shop/files/Full_Size_Citrus_75330201-6111-4242-bac7-eb4703f1b300.png?v=1774338517", 2637 "alt": "Revitin Toothpaste (25 Tubes) Wholesale" 2638 } 2639 2640 ], 2641 2642 "options": [{"name":"Flavor","position":1,"values":["Citrus"]}], 2643 2644 "variants": [ 2645 2646 { 2647 "id": "45628453814410", 2648 "title": "Citrus", 2649 "sku": "CITRUS25", 2650 "available": true, 2651 "price": "212.50", 2652 "compare_at_price": "425.00", 2653 "inventory_quantity": "1473", 2654 "sellingPlans": [] 2655 } 2656 2657 ] 2658 }, 2659 2660 { 2661 "id": "8335801548938", 2662 "title": "Revitin Toothpaste (25 Tubes) Wholesale", 2663 "handle": "revitin-toothpaste-25-tubes-wholesale-mint", 2664 "description": "Revitin supports strong white teeth, healthy gums, and fresher breath. Whatâs more, Revitin tastes great! Revitin is fluoride-free, without Sodium Lauryl Sulfate (SLS free), and
2664you won't find Triclosan either!", 2665 "vendor": "Revitin® Natural Toothpaste", 2666 "product_type": "Toothpaste", 2667 "tags": ["Max25","Toothpaste","wholesale"], 2668 "url": "/products/revitin-toothpaste-25-tubes-wholesale-mint", 2669 "aestheticTitle": "Revitin Natural Toothpaste", 2670 "homepage_image": "", 2671 "featured_image": { 2672 "src": "//revitin.com/cdn/shop/files/mint-render_cream_bg.png?v=1751389753", 2673 "alt": "Revitin Toothpaste (25 Tubes) Wholesale" 2674 }, 2675 2676 "images": [ 2677 2678 { 2679 "src": "//revitin.com/cdn/shop/files/mint-render_cream_bg.png?v=1751389753", 2680 "alt": "Revitin Toothpaste (25 Tubes) Wholesale" 2681 }, 2682 2683 { 2684 "src": "//revitin.com/cdn/shop/files/revitin-case-25A-removebg-preview_1eb996a0-5ac0-41ba-8838-5bc2ce0fc7b4.png?v=1751389901", 2685 "alt": "Revitin Toothpaste (25 Tubes) Wholesale" 2686 }, 2687 2688 { 2689 "src": "//revitin.com/cdn/shop/files/revitin-case-25A_7536a270-a73f-4686-ab65-56c666719954.jpg?v=1751389901", 2690 "alt": "Full Case (25 Tubes)" 2691 }, 2692 2693 { 2694 "src": "//revitin.com/cdn/shop/files/revitin-case1_c93e3dd8-eaa7-413e-97d2-5ce9d0d257fa.jpg?v=1751389901", 2695 "alt": "Revitin Toothpaste (25 Tubes) Wholesale" 2696 }, 2697 2698 { 2699 "src": "//revitin.com/cdn/shop/files/Full_Size_Mint_1318037a-3b7a-4e15-84c3-e22323a5e8cc.png?v=1774337830", 2700 "alt": "Revitin Toothpaste (25 Tubes) Wholesale" 2701 } 2702 2703 ], 2704 2705 "options": [{"name":"Flavor","position":1,"values":["Mint"]}], 2706 2707 "variants": [ 2708 2709 { 2710 "id": "45628533604490", 2711 "title": "Mint", 2712 "sku": "MINT25", 2713 "available": true, 2714 "price": "212.50", 2715 "compare_at_price": "425.00", 2716 "inventory_quantity": "1889", 2717 "sellingPlans": [] 2718 } 2719 2720 ] 2721 }, 2722 2723 { 2724 "id": "6606431420554", 2725 "title": "Revitin Toothpaste (3 Tubes)", 2726 "handle": "revitin-natural-toothpaste-family-pack-3tubes", 2727 "description": "Revitin supports strong white teeth, healthy gums, and fresher breath. Whatâs more, Revitin tastes great! Revitin is fluoride-free, without Sodium Lauryl Sulfate (SLS free), and you won't find Triclosan either!\n", 2728 "vendor": "Revitin® Natural Toothpaste", 2729 "product_type": "Toothpaste", 2730 "tags": ["Toothpaste","wholesale"], 2731 "url": "/products/revitin-natural-toothpaste-family-pack-3tubes", 2732 "aestheticTitle": "Revitin Natural Toothpaste", 2733 "homepage_image": "", 2734 "featured_image": { 2735 "src": "//revitin.com/cdn/shop/files/citrus-render_cream_bg.png?v=1751390073", 2736 "alt": "Revitin Toothpaste (3 Tubes)" 2737 }, 2738 2739 "images": [ 2740 2741 { 2742 "src": "//revitin.com/cdn/shop/files/citrus-render_cream_bg.png?v=1751390073", 2743 "alt": "Revitin Toothpaste (3 Tubes)" 2744 }, 2745 2746 { 2747 "src": "//revitin.com/cdn/shop/files/citrus-gallery-1_11zon.jpg?v=1751389467", 2748 "alt": "Revitin Toothpaste (3 Tubes)" 2749 }, 2750 2751 { 2752 "src": "//revitin.com/cdn/shop/files/citrus-gallery-3_11zon.jpg?v=1751389467", 2753 "alt": "Revitin Toothpaste (3 Tubes)" 2754 }, 2755 2756 { 2757 "src": "//revitin.com/cdn/shop/files/citrus-featured_11zon.jpg?v=1751389467", 2758 "alt": "Revitin Toothpaste (3 Tubes)" 2759 }, 2760 2761 { 2762 "src": "//revitin.com/cdn/shop/files/Full_Size_Citrus.png?v=1773920437", 2763 "alt": "Revitin Toothpaste (3 Tubes)" 2764 } 2765 2766 ], 2767 2768 "options": [{"name":"Flavor","position":1,"values":["Citrus"]}], 2769 2770 "variants": [ 2771 2772 { 2773 "id": "45594633666698", 2774 "title": "Citrus", 2775 "sku": "CITRUS3", 2776 "available": true, 2777 "price": "46.00", 2778 "compare_at_price": "51.00", 2779 "inventory_quantity": "12860", 2780 "sellingPlans": [{ 2781 "id": 2436038794, 2782 "name": "Delivery every 1 month", 2783 "price": 4200 2784 },{ 2785 "id": 2435973258, 2786 "name": "Delivery every 2 months", 2787 "price": 4200 2788 },{ 2789 "id": 2436071562, 2790 "name": "Delivery every 3 months", 2791 "price": 4200 2792 },{ 2793 "id": 2436006026, 2794 "name": "Delivery every 6 months", 2795 "price": 4200 2796 }] 2797 } 2798 2799 ] 2800 }, 2801 2802 { 2803 "id": "8333322846346", 2804 "title": "Revitin Toothpaste (3 Tubes)", 2805 "handle": "revitin-toothpaste-3-tubes-mint", 2806 "description": "Revitin supports strong white teeth, healthy gums, and fresher breath. Whatâs more, Revitin tastes great! Revitin is fluoride-free, without Sodium Lauryl Sulfate (SLS free), and
2806you won't find Triclosan either!", 2807 "vendor": "Revitin® Natural Toothpaste", 2808 "product_type": "Toothpaste", 2809 "tags": ["Toothpaste","wholesale"], 2810 "url": "/products/revitin-toothpaste-3-tubes-mint", 2811 "aestheticTitle": "Revitin Natural Toothpaste", 2812 "homepage_image": "", 2813 "featured_image": { 2814 "src": "//revitin.com/cdn/shop/files/mint-render_cream_bg.png?v=1751389753", 2815 "alt": "Revitin Toothpaste (3 Tubes)" 2816 }, 2817 2818 "images": [ 2819 2820 { 2821 "src": "//revitin.com/cdn/shop/files/mint-render_cream_bg.png?v=1751389753", 2822 "alt": "Revitin Toothpaste (3 Tubes)" 2823 }, 2824 2825 { 2826 "src": "//revitin.com/cdn/shop/files/mint-gallery-1_11zon.jpg?v=1751389546", 2827 "alt": "Revitin Toothpaste (3 Tubes)" 2828 }, 2829 2830 { 2831 "src": "//revitin.com/cdn/shop/files/mint-gallery-2_11zon.jpg?v=1751389546", 2832 "alt": "Revitin Toothpaste (3 Tubes)" 2833 }, 2834 2835 { 2836 "src": "//revitin.com/cdn/shop/files/mint-featured_11zon.jpg?v=1751389546", 2837 "alt": "Revitin Toothpaste (3 Tubes)" 2838 }, 2839 2840 { 2841 "src": "//revitin.com/cdn/shop/files/Full_Size_Mint.png?v=1774282946", 2842 "alt": "Revitin Toothpaste (3 Tubes)" 2843 } 2844 2845 ], 2846 2847 "options": [{"name":"Flavor","position":1,"values":["Mint"]}], 2848 2849 "variants": [ 2850 2851 { 2852 "id": "45618606080138", 2853 "title": "Mint", 2854 "sku": "MINT3", 2855 "available": true, 2856 "price": "46.00", 2857 "compare_at_price": "51.00", 2858 "inventory_quantity": "17282", 2859 "sellingPlans": [{ 2860 "id": 2436497546, 2861 "name": "Delivery every 1 month", 2862 "price": 4200 2863 },{ 2864 "id": 2436300938, 2865 "name": "Delivery every 2 months", 2866 "price": 4200 2867 },{ 2868 "id": 2436530314, 2869 "name": "Delivery every 3 months", 2870 "price": 4200 2871 },{ 2872 "id": 2436563082, 2873 "name": "Delivery every 6 months", 2874 "price": 4200 2875 }] 2876 } 2877 2878 ] 2879 }, 2880 2881 { 2882 "id": "7609245171850", 2883 "title": "Revitin Toothpaste (5 Tubes)", 2884 "handle": "revitin-toothpaste-5-tubes", 2885 "description": "Revitin supports strong white teeth, healthy gums, and fresher breath. Whatâs more, Revitin tastes great! Revitin is fluoride-free, without Sodium Lauryl Sulfate (SLS free), and you won't find Triclosan either!", 2886 "vendor": "Revitin® Natural Toothpaste", 2887 "product_type": "Toothpaste", 2888 "tags": ["Subscription","Toothpaste","wholesale"], 2889 "url": "/products/revitin-toothpaste-5-tubes", 2890 "aestheticTitle": "Revitin Natural Toothpaste", 2891 "homepage_image": "", 2892 "featured_image": { 2893 "src": "//revitin.com/cdn/shop/files/citrus-render_cream_bg.png?v=1751390073", 2894 "alt": "Revitin Toothpaste (5 Tubes)" 2895 }, 2896 2897 "images": [ 2898 2899 { 2900 "src": "//revitin.com/cdn/shop/files/citrus-render_cream_bg.png?v=1751390073", 2901 "alt": "Revitin Toothpaste (5 Tubes)" 2902 }, 2903 2904 { 2905 "src": "//revitin.com/cdn/shop/files/citrus-gallery-1_11zon.jpg?v=1751389467", 2906 "alt": "Revitin Toothpaste (5 Tubes)" 2907 }, 2908 2909 { 2910 "src": "//revitin.com/cdn/shop/files/citrus-gallery-3_11zon.jpg?v=1751389467", 2911 "alt": "Revitin Toothpaste (5 Tubes)" 2912 }, 2913 2914 { 2915 "src": "//revitin.com/cdn/shop/files/citrus-featured_11zon.jpg?v=1751389467", 2916 "alt": "Revitin Toothpaste (5 Tubes)" 2917 }, 2918 2919 { 2920 "src": "//revitin.com/cdn/shop/files/Full_Size_Citrus_e9fa6364-9bfe-4cd7-b0af-1a95d93ee5ba.png?v=1774337705", 2921 "alt": "Revitin Toothpaste (5 Tubes)" 2922 } 2923 2924 ], 2925 2926 "options": [{"name":"Flavor","position":1,"values":["Citrus"]}], 2927 2928 "variants": [ 2929 2930 { 2931 "id": "45594652901514", 2932 "title": "Citrus", 2933 "sku": "CITRUS5", 2934 "available": true, 2935 "price": "70.00",
2936 "compare_at_price": "85.00", 2937 "inventory_quantity": "284", 2938 "sellingPlans": [{ 2939 "id": 2436137098, 2940 "name": "Delivery every 1 month", 2941 "price": 6800 2942 },{ 2943 "id": 2436104330, 2944 "name": "Delivery every 2 months", 2945 "price": 6800 2946 },{ 2947 "id": 2436202634, 2948 "name": "Delivery every 3 months", 2949 "price": 6800 2950 },{ 2951 "id": 2436169866, 2952 "name": "Delivery every 6 months", 2953 "price": 6800 2954 }] 2955 } 2956 2957 ] 2958 }, 2959 2960 { 2961 "id": "8333359808650", 2962 "title": "Revitin Toothpaste (5 Tubes)", 2963 "handle": "revitin-toothpaste-5-tubes-mint", 2964 "description": "Revitin supports strong white teeth, healthy gums, and fresher breath. Whatâs more, Revitin tastes great! Revitin is fluoride-free, without Sodium Lauryl Sulfate (SLS free), and you won't find Triclosan either!", 2965 "vendor": "Revitin® Natural Toothpaste", 2966 "product_type": "Toothpaste", 2967 "tags": ["Subscription","Toothpaste","wholesale"], 2968 "url": "/products/revitin-toothpaste-5-tubes-mint", 2969 "aestheticTitle": "Revitin Natural Toothpaste", 2970 "homepage_image": "", 2971 "featured_image": { 2972 "src": "//revitin.com/cdn/shop/files/mint-render_cream_bg.png?v=1751389753", 2973 "alt": "Revitin Toothpaste (5 Tubes)" 2974 }, 2975 2976 "images": [ 2977 2978 { 2979 "src": "//revitin.com/cdn/shop/files/mint-render_cream_bg.png?v=1751389753", 2980 "alt": "Revitin Toothpaste (5 Tubes)" 2981 }, 2982 2983 { 2984 "src": "//revitin.com/cdn/shop/files/mint-gallery-1_11zon.jpg?v=1751389546", 2985 "alt": "Revitin Toothpaste (5 Tubes)" 2986 }, 2987 2988 { 2989 "src": "//revitin.com/cdn/shop/files/mint-gallery-2_11zon.jpg?v=1751389546", 2990 "alt": "Revitin Toothpaste (5 Tubes)" 2991 }, 2992 2993 { 2994 "src": "//revitin.com/cdn/shop/files/mint-featured_11zon.jpg?v=1751389546", 2995 "alt": "Revitin Toothpaste (5 Tubes)" 2996 }, 2997 2998 { 2999 "src": "//revitin.com/cdn/shop/files/Full_Size_Mint_37b5d288-2b5a-42a4-bd87-71596a6bf4b4.png?v=1774337756", 3000 "alt": "Revitin Toothpaste (5 Tubes)" 3001 } 3002 3003 ], 3004 3005 "options": [{"name":"Flavor","position":1,"values":["Mint"]}], 3006 3007 "variants": [ 3008 3009 { 3010 "id": "45618689310858", 3011 "title": "Mint", 3012 "sku": "MINT5", 3013 "available": true, 3014 "price": "70.00", 3015 "compare_at_price": "85.00", 3016 "inventory_quantity": "2097", 3017 "sellingPlans": [{ 3018 "id": 2436333706, 3019 "name": "Delivery every 1 month with 17.65% discount", 3020 "price": 6800 3021 },{ 3022 "id": 2436399242, 3023 "name": "Delivery every 2 months with 17.65% discount", 3024 "price": 6800 3025 },{ 3026 "id": 2436366474, 3027 "name": "Delivery every 3 months with 17.65% discount", 3028 "price": 6800 3029 },{ 3030 "id": 2436595850, 3031 "name": "Delivery every 6 months with 17.65% discount", 3032 "price": 6800 3033 }] 3034 } 3035 3036 ] 3037 }, 3038 3039 { 3040 "id": "6606432174218", 3041 "title": "Revitin Toothpaste Single Tube", 3042 "handle": "revitin-natural-toothpaste", 3043 "description": "Revitin supports strong white teeth, healthy gums, and fresher breath. Whatâs more, Revitin tastes great! Revitin is fluoride-free, without Sodium Lauryl Sulfate (SLS free), and
3043you won't find Triclosan either!", 3044 "vendor": "Revitin® Natural Toothpaste", 3045 "product_type": "Toothpaste", 3046 "tags": ["Toothpaste","wholesale"], 3047 "url": "/products/revitin-natural-toothpaste", 3048 "aestheticTitle": "Revitin Natural Toothpaste", 3049 "homepage_image": "", 3050 "featured_image": { 3051 "src": "//revitin.com/cdn/shop/files/citrus-gallery-render-mobile_11zon.jpg?v=1742298905", 3052 "alt": "Revitin Toothpaste Single Tube" 3053 }, 3054 3055 "images": [ 3056 3057 { 3058 "src": "//revitin.com/cdn/shop/files/citrus-gallery-render-mobile_11zon.jpg?v=1742298905", 3059 "alt": "Revitin Toothpaste Single Tube" 3060 }, 3061 3062 { 3063 "src": "//revitin.com/cdn/shop/files/citrus-featured_11zon.jpg?v=1751389467", 3064 "alt": "Revitin Toothpaste Single Tube" 3065 }, 3066 3067 { 3068 "src": "//revitin.com/cdn/shop/files/citrus-render.png?v=1751390073", 3069 "alt": "Revitin Toothpaste Single Tube" 3070 }, 3071 3072 { 3073 "src": "//revitin.com/cdn/shop/files/citrus-featured-mobile_11zon.jpg?v=1742298805", 3074 "alt": "Revitin Toothpaste Single Tube" 3075 }, 3076 3077 { 3078 "src": "//revitin.com/cdn/shop/files/citrus-gallery-3_11zon.jpg?v=1751389467", 3079 "alt": "Revitin Toothpaste Single Tube" 3080 }, 3081 3082 { 3083 "src": "//revitin.com/cdn/shop/files/main-grapefruit_90add639-f630-489f-9558-ad382aba44cc.png?v=1741690920", 3084 "alt": "Revitin Toothpaste Single Tube" 3085 }, 3086 3087 { 3088 "src": "//revitin.com/cdn/shop/files/10001.jpg?v=1742293659", 3089 "alt": "Revitin Toothpaste Single Tube" 3090 }, 3091 3092 { 3093 "src": "//revitin.com/cdn/shop/files/Full_Size_Citrus_e232e154-1f22-47a5-97a3-a93e8238766d.png?v=1774337551", 3094 "alt": "Revitin Toothpaste Single Tube" 3095 } 3096 3097 ], 3098 3099 "options": [{"name":"Flavor","position":1,"values":["Citrus"]}], 3100 3101 "variants": [ 3102 3103 { 3104 "id": "45594631471242", 3105 "title": "Citrus", 3106 "sku": "CITRUS1", 3107 "available": true, 3108 "price": "17.00", 3109 "compare_at_price": "17.00", 3110 "inventory_quantity": "36855", 3111 "sellingPlans": [] 3112 } 3113 3114 ] 3115 }, 3116 3117 { 3118 "id": "8334203355274", 3119 "title": "Revitin Toothpaste Single Tube", 3120 "handle": "revitin-toothpaste-single-tube-mint", 3121 "description": "Revitin supports strong white teeth, healthy gums, and fresher breath. Whatâs more, Revitin tastes great! Revitin is fluoride-free, without Sodium Lauryl Sulfate (SLS free), and you won't find Triclosan either!", 3122 "vendor": "Revitin® Natural Toothpaste", 3123 "product_type": "Toothpaste", 3124 "tags": ["Toothpaste","wholesale"], 3125 "url": "/products/revitin-toothpaste-single-tube-mint", 3126 "aestheticTitle": "Revitin Natural Toothpaste", 3127 "homepage_image": "", 3128 "featured_image": { 3129 "src": "//revitin.com/cdn/shop/files/mint-gallery-1_11zon.jpg?v=1751389546", 3130 "alt": "Revitin Toothpaste Single Tube" 3131 }, 3132 3133 "images": [ 3134 3135 { 3136 "src": "//revitin.com/cdn/shop/files/mint-gallery-1_11zon.jpg?v=1751389546", 3137 "alt": "Revitin Toothpaste Single Tube" 3138 }, 3139 3140 { 3141 "src": "//revitin.com/cdn/shop/files/mint-render.png?v=1751387541", 3142 "alt": "Revitin Toothpaste Single Tube" 3143 }, 3144 3145 { 3146 "src": "//revitin.com/cdn/shop/files/mint-gallery-2_11zon.jpg?v=1751389546", 3147 "alt": "Revitin Toothpaste Single Tube" 3148 }, 3149 3150 { 3151 "src": "//revitin.com/cdn/shop/files/mint-featured_11zon.jpg?v=1751389546", 3152 "alt": "Revitin Toothpaste Single Tube" 3153 }, 3154 3155 { 3156 "src": "//revitin.com/cdn/shop/files/Full_Size_Mint_99a4be1b-921c-4bbc-96f1-3bc4d0999926.png?v=1774337594", 3157 "alt": "Revitin Toothpaste Single Tube" 3158 }, 3159 3160 { 3161 "src": "//revitin.com/cdn/shop/files/Screenshot_2026-05-13_at_4.25.54_PM.png?v=1778704121", 3162 "alt": "Revitin Toothpaste Single Tube" 3163 }, 3164 3165 { 3166 "src": "//revitin.com/cdn/shop/files/Screenshot_2026-05-13_at_4.33.10_PM.png?v=1778704398", 3167 "alt": "Revitin Toothpaste Single Tube" 3168 } 3169 3170 ], 3171 3172 "options": [{"name":"Flavor","position":1,"values":["Mint"]}], 3173 3174 "variants": [ 3175 3176 { 3177 "id": "45622706602122", 3178 "title": "Mint", 3179 "sku": "MINT1", 3180 "available": true, 3181 "price": "17.00", 3182 "compare_at_price": "17.00", 3183 "inventory_quantity": "47196", 3184 "sellingPlans": [] 3185 } 3186 3187 ] 3188 }, 3189 3190 { 3191 "id": "8332405899402", 3192 "title": "Revitin Toothpaste Variety 3 Tubes", 3193 "handle": "citrus-mint-4-tubes", 3194 "description": "Promote a healthy balance of your oral ecology to support oral health and wellness for whiter teeth and fresher breath.", 3195 "vendor": "Revitin® Natural Toothpaste", 3196 "product_type": "Toothpaste", 3197 "tags": ["Toothpaste","wholesale"], 3198 "url": "/products/citrus-mint-4-tubes", 3199 "aestheticTitle": "2 Citrus & 1 Mint", 3200 "homepage_image": "", 3201 "featured_image": { 3202 "src": "//revitin.com/cdn/shop/files/jiCerJfg.jpg?v=1760511199", 3203 "alt": "Revitin Toothpaste Variety 3 Tubes" 3204 }, 3205 3206 "images": [ 3207 3208 { 3209 "src": "//revitin.com/cdn/shop/files/jiCerJfg.jpg?v=1760511199", 3210 "alt": "Revitin Toothpaste Variety 3 Tubes" 3211 }, 3212 3213 { 3214 "src": "//revitin.com/cdn/shop/files/IMG-0976_9e04b0b0-bc26-4aed-8d9b-0267e461713e.jpg?v=1760511199", 3215 "alt": "Revitin Toothpaste Variety 3 Tubes" 3216 }, 3217 3218 { 3219 "src": "//revitin.com/cdn/shop/files/IMG-0977_0a2566a9-f325-40ee-993e-bbdf733e13fa.jpg?v=1760511199", 3220 "alt": "Revitin Toothpaste Variety 3 Tubes" 3221 }, 3222 3223 { 3224 "src": "//revitin.com/cdn/shop/files/hm-2-citrus-1-mint.png?v=1760511199", 3225 "alt": "Revitin Toothpaste Variety 3 Tubes" 3226 }, 3227 3228 { 3229 "src": "//revitin.com/cdn/shop/files/Z9RFJa7w.jpg?v=1760614753", 3230 "alt": "Revitin Toothpaste Variety 3 Tubes" 3231 }, 3232 3233 { 3234 "src": "//revitin.com/cdn/shop/files/Full_Size_Variety_2citrus1mint.png?v=1774338212", 3235 "alt": "Revitin Toothpaste Variety 3 Tubes" 3236 }, 3237 3238 { 3239 "src": "//revitin.com/cdn/shop/files/mint-gallery-mobile-3_11zon.jpg?v=1729883824", 3240 "alt": "Revitin Toothpaste Variety 3 Tubes" 3241 } 3242 3243 ], 3244 3245 "options": [{"name":"Flavor","position":1,"values":["Citrus"]}], 3246 3247 "variants": [ 3248 3249 { 3250 "id": "46765298909322", 3251 "title": "Citrus", 3252 "sku": "VARIETYPACK2C-1M", 3253 "available": true, 3254 "price": "46.00", 3255 "compare_at_price": "51.00", 3256 "inventory_quantity": "1844", 3257 "sellingPlans": [{ 3258 "id": 2436235402, 3259 "name": "Delivery every 1 month", 3260 "price": 4200 3261 },{
3262 "id": 2436464778, 3263 "name": "Delivery every 2 months", 3264 "price": 4200 3265 },{ 3266 "id": 2436432010, 3267 "name": "Delivery every 3 months", 3268 "price": 4200 3269 },{ 3270 "id": 2436268170, 3271 "name": "Delivery every 6 months", 3272 "price": 4200 3273 }] 3274 } 3275 3276 ] 3277 }, 3278 3279 { 3280 "id": "8645075763338", 3281 "title": "Revitin Toothpaste Variety 3 Tubes", 3282 "handle": "variety-pack-2-mint-1-citrus", 3283 "description": "Promote a healthy balance of your oral ecology to support oral health and wellness for whiter teeth and fresher breath.", 3284 "vendor": "Revitin® Natural Toothpaste", 3285 "product_type": "Toothpaste", 3286 "tags": ["Toothpaste","wholesale"], 3287 "url": "/products/variety-pack-2-mint-1-citrus", 3288 "aestheticTitle": "2 Mint & 1 Citrus", 3289 "homepage_image": "", 3290 "featured_image": { 3291 "src": "//revitin.com/cdn/shop/files/R13eeryg.jpg?v=1760511151", 3292 "alt": "Revitin Toothpaste Variety 3 Tubes" 3293 }, 3294 3295 "images": [ 3296 3297 { 3298 "src": "//revitin.com/cdn/shop/files/R13eeryg.jpg?v=1760511151", 3299 "alt": "Revitin Toothpaste Variety 3 Tubes" 3300 }, 3301 3302 { 3303 "src": "//revitin.com/cdn/shop/files/IMG-0976.jpg?v=1760511151", 3304 "alt": "Revitin Toothpaste Variety 3 Tubes" 3305 }, 3306 3307 { 3308 "src": "//revitin.com/cdn/shop/files/IMG-0977.jpg?v=1760511151", 3309 "alt": "Revitin Toothpaste Variety 3 Tubes" 3310 }, 3311 3312 { 3313 "src": "//revitin.com/cdn/shop/files/hm-2-citrus-1-mint.png?v=1760511199", 3314 "alt": "Revitin Toothpaste Variety 3 Tubes" 3315 }, 3316 3317 { 3318 "src": "//revitin.com/cdn/shop/files/qpMuKh-Q.jpg?v=1760614727", 3319 "alt": "Revitin Toothpaste Variety 3 Tubes" 3320 }, 3321 3322 { 3323 "src": "//revitin.com/cdn/shop/files/Full_Size_Variety_1citrus2mint.png?v=1774338246", 3324 "alt": "Revitin Toothpaste Variety 3 Tubes" 3325 }, 3326 3327 { 3328 "src": "//revitin.com/cdn/shop/files/mint-gallery-mobile-3_11zon.jpg?v=1729883824", 3329 "alt": "Revitin Toothpaste Variety 3 Tubes" 3330 } 3331 3332 ], 3333 3334 "options": [{"name":"Flavor","position":1,"values":["Mint"]}], 3335 3336 "variants": [ 3337 3338 { 3339 "id": "46765283049610", 3340 "title": "Mint", 3341 "sku": "VARIETYPACK2M-1C", 3342 "available": true, 3343 "price": "46.00", 3344 "compare_at_price": "51.00", 3345 "inventory_quantity": "25302", 3346 "sellingPlans": [{ 3347 "id": 2436726922, 3348 "name": "Delivery every 1 month", 3349 "price": 4200 3350 },{ 3351 "id": 2436694154, 3352 "name": "Delivery every 2 months", 3353 "price": 4200 3354 },{ 3355 "id": 2436628618, 3356 "name": "Delivery every 3 months", 3357 "price": 4200 3358 },{ 3359 "id": 2436661386, 3360 "name": "Delivery every 6 months", 3361 "price": 4200 3362 }] 3363 } 3364 3365 ] 3366 }, 3367 3368 { 3369 "id": "8909392904330", 3370 "title": "Variety Travel 4-Pack of 1 oz", 3371 "handle": "variety-travel-4-pack-of-1-oz", 3372 "description": "", 3373 "vendor": "Revitin", 3374 "product_type": "", 3375 "tags": [], 3376 "url": "/products/variety-travel-4-pack-of-1-oz", 3377 "aestheticTitle": "", 3378 "homepage_image": "", 3379 "featured_image": { 3380 "src": "//revitin.com/cdn/shop/files/revitin2.png?v=1777964527", 3381 "alt": "Variety Travel 4-Pack of 1 oz" 3382 }, 3383 3384 "images": [ 3385 3386 { 3387 "src": "//revitin.com/cdn/shop/files/revitin2.png?v=1777964527", 3388 "alt": "Variety Travel 4-Pack of 1 oz" 3389 }, 3390 3391 { 3392 "src": "//revitin.com/cdn/shop/files/revitin1.png?v=1777964527", 3393 "alt": "Variety Travel 4-Pack of 1 oz" 3394 } 3395 3396 ], 3397 3398 "options": [{"name":"Title","position":1,"values":["Default Title"]}], 3399 3400 "variants": [ 3401 3402 { 3403 "id": "47799599759498", 3404 "title": "Default Title", 3405 "sku": "VarietyTravel4-pk", 3406 "available": true, 3407 "price": "24.00", 3408 "compare_at_price": "", 3409 "inventory_quantity": "518", 3410 "sellingPlans": [] 3411 } 3412 3413 ] 3414 } 3415 3416 ] 3417</script>
3417 3418 3419<div class="variety-selection-container"> 3420 <label class="variety-box variety-active" id="variety-subscribeBox"> 3421 <input class="variety-radio-input" type="radio" name="variety-purchaseType" value="subscribe" checked> 3422 <div class="variety-radio-group"> 3423 <span class="variety-radio-dot"></span> 3424 Subscribe & Save 3425 <div class="variety-save-tag subscribe-save"></div> 3426 <span class="subs-variety-price variety-price"><span class="variety-original-price opacity-50"></span></span> 3427 </div> 3428 <div class="variety-description"> 3429 <div class="variety-selling-plan-dropdown"> 3430 <label for="subscribe-selling-plan">Delivered every</label> 3431 <select id="subscribe-selling-plan" class="variety-selling-plan-select font-body-medium"></select> 3432 </div> 3433 Free shipping. Cancel anytime. 3434 </div> 3435 <div class="variety-flavor-options subs-btn" id="variety-subscribeFlavors"> 3436 3437 3438 3439 3440 3441 <button 3442 data-citrus-count="2" 3443 data-mint-count="1" 3444 class="variety-qty subs font-body-medium active" 3445 > 3446 2 Citrus & 1 Mint 3447 </button> 3448 3449 <button 3450 data-citrus-count="1" 3451 data-mint-count="2" 3452 class="variety-qty subs" 3453 > 3454 2 Mint & 1 Citrus 3455 </button> 3456 </div> 3457 </label> 3458 3459 <label class="variety-box variety-active" id="variety-oneTimeBox"> 3460 <input class="variety-radio-input" type="radio" name="variety-purchaseType" value="onetime"> 3461 <div class="variety-radio-group"> 3462 <span class="variety-radio-dot"></span> 3463 One-time Purchase 3464 <div class="variety-save-tag one-time"></div> 3465 <span class="once-variety-price variety-price"><span class="variety-original-price opacity-50"></span></span> 3466 </div> 3467 <div class="variety-flavor-options" id="variety-oneTimeFlavors"> 3468 <button data-citrus-count="2" data-mint-count="1" class="variety-qty once active font-body-medium"> 3469 2 Citrus & 1 Mint 3470 </button> 3471 <button data-citrus-count="1" data-mint-count="2" class="variety-qty once">2 Mint & 1 Citrus</button> 3472 </div> 3473 </label> 3474 3475 <!-- Add to Cart Button --> 3476 <button id="variety-add-to-cart" class="!w-full button mt-6"> 3477 <span class="variety_atc_text">Add to Cart</span> 3478 <span class="variety_atc_btn"></span> 3479 </button> 3480</div> 3481
3482<script> 3483 document.addEventListener("DOMContentLoaded", function () { 3484 const flavorButtons = document.querySelectorAll('.flavour-custom'); 3485 const varietyButton = document.querySelector('.variety-selector-btn'); 3486 const oneTimeContainer = document.querySelector('.one_time_container'); 3487 const varietySelectionContainer = document.querySelector('.variety-selection-container'); 3488 const purchaseTypeRadios = document.querySelectorAll('input[name="variety-purchaseType"]'); 3489 const addToCartButton = document.getElementById('variety-add-to-cart'); 3490 const subscribeSelectContainer = document.getElementById('subscribe-selling-plan'); 3491 const subscribeOriginalPrice = document.querySelector('.subs-variety-price'); 3492 const oneTimeOriginalPrice = document.querySelector('.once-variety-price'); 3493 const subscriptionSave = document.querySelector('.variety-save-tag.subscribe-save'); 3494 const oneTimeSave = document.querySelector('.variety-save-tag.one-time'); 3495 const activeSubscription = document.querySelector('.variety-flavor-options .variety-qty.subs.active'); 3496 3497 function lockVarietyActiveClass() { 3498 document.querySelectorAll('#variety-subscribeBox, #variety-oneTimeBox').forEach((box) => { 3499 box.classList.add('variety-active'); 3500 }); 3501 } 3502 3503 function protectVarietyActiveClass() { 3504 document.querySelectorAll('#variety-subscribeBox, #variety-oneTimeBox').forEach((box) => { 3505 lockVarietyActiveClass(); 3506 new MutationObserver(() => { 3507 if (!box.classList.contains('variety-active')) { 3508 box.classList.add('variety-active'); 3509 } 3510 }).observe(box, { attributes: true, attributeFilter: ['class'] }); 3511 }); 3512 } 3513 3514 protectVarietyActiveClass(); 3515 3516 const citrusGroupImgUrl = "//revitin.com/cdn/shop/t/129/assets/citrus-group.png?v=161376326643237091681777542403"; 3517 const citrusSeparatedImgUrl = "//revitin.com/cdn/shop/t/129/assets/citrus-separated.png?v=152161151921604416161777542404"; 3518 const mintGroupImgUrl = "//revitin.com/cdn/shop/t/129/assets/mint-group.png?v=163306762873594723801777542406"; 3519 3520 // Check for URL parameter and auto-select variety 3521 const urlParams = new URLSearchParams(window.location.search); 3522 const pathname = window.location.pathname; 3523 3524 if (urlParams.get('pack') === 'variety' || pathname.includes("variety-pack-2-mint-1-citrus")) { 3525 // Use setTimeout to ensure all elements are properly loaded 3526 setTimeout(() => { 3527 handleVarietyButtonClick(); 3528 addSubscriptionsHtml(); 3529 updateSubscriptionPrice(); 3530 updateOneTimePrice(); 3531 updateBannerImages(); 3532 }, 100); 3533 } 3534 3535 // Store product data 3536 let productsData = []; 3537 3538 function getAllProducts() { 3539 const products = JSON.parse(document.getElementById('all-products-json').textContent); 3540 3541 productsData = products.filter((item) => item.title.toLowerCase().includes("var") || item.handle.toLowerCase().includes("var")); 3542 updateAddToCartButton(); 3543 } 3544 3545 getAllProducts(); 3546 3547 const citrusImages = ["//revitin.com/cdn/shop/files/citrus-gallery-render_12zon_1600x.jpg", 3548 "//revitin.com/cdn/shop/files/citrus-gallery-2_11zon_1600x.jpg?v=1729881153", 3549 "//revitin.com/cdn/shop/files/citrus-gallery-3_11zon_1600x.jpg?v=1751389467", 3550 "//revitin.com/cdn/shop/files/citrus-render_560x.png?v=1751390073", 3551 "//revitin.com/cdn/shop/files/mint-render_560x.png?v=1751387541", 3552 "//revitin.com/cdn/shop/files/citrus-gallery-render-mobile_13zon_1000x.jpg" 3553 ]; 3554 3555 function hideSubscribeContainers(sections) { 3556 const hideFunc = () => { 3557 sections.forEach((btn) => btn.classList.add("hidden")); 3558 }; 3559 3560 // Run immediately once 3561 hideFunc(); 3562 3563 // Observe for future DOM changes 3564 const observer = new MutationObserver(() => { 3565 hideFunc(); 3566 }); 3567 3568 observer.observe(document.body, { 3569 childList: true, 3570 subtree: true, 3571 }); 3572 } 3573 3574 document.body.addEventListener("click", function (event) { 3575 if (!event.target || typeof event.target.closest !== 'function') return; 3576 if (event.target.closest('.variety-selector-btn')) { 3577 const sections = document.querySelectorAll( 3578 `.subscription-box` 3579 ); 3580 hideSubscribeContainers(sections); 3581 handleVarietyButtonClick();
3582 addSubscriptionsHtml(); 3583 updateSubscriptionPrice(); 3584 updateOneTimePrice(); 3585 updateBannerImages(); 3586 } else if (event.target.closest('.flavour-custom')) { 3587 handleFlavorButtonClick(event.target.closest('.flavour-custom')); 3588 } else if (event.target.closest('.variety-qty')) { 3589 const clickedQuantity = event.target.closest('.variety-qty'); 3590 3591 updateBannerImages(clickedQuantity); 3592 addSubscriptionsHtml(clickedQuantity); 3593 handleVarietyQtyClick(clickedQuantity); 3594 updateAddToCartButton(); 3595 } else if (event.target.closest('.variety-box')) { 3596 const varietyBox = event.target.closest('.variety-box'); 3597 if (varietyBox.id === 'variety-subscribeBox') { 3598 const subsButtons = document.querySelectorAll('#variety-subscribeFlavors .variety-qty.subs'); 3599 const hasActiveSubsButton = Array.from(subsButtons).some(btn => btn.classList.contains('active')); 3600 if (!hasActiveSubsButton) { 3601 setTimeout(() => { 3602 const citrusMintButton = document.querySelector('#variety-subscribeFlavors .variety-qty[data-citrus-count="2"][data-mint-count="1"]'); 3603 if (citrusMintButton) { 3604 citrusMintButton.click(); 3605 handleVarietyQtyClick(citrusMintButton); 3606 updateSubscriptionPrice(); 3607 updateBannerImages(citrusMintButton); 3608 addSubscriptionsHtml(citrusMintButton); 3609 updateAddToCartButton(); 3610 } 3611 }, 50); 3612 } 3613 } 3614 } 3615 }); 3616 3617 document.body.addEventListener("change", function (event) { 3618 if (event.target.name === "variety-purchaseType" && event.target.type === "radio") { 3619 handlePurchaseTypeBehaviour(event.target); 3620 handlePurchaseTypeChange(event.target.value === "subscribe"); 3621 updateAddToCartButton(); 3622 updateBannerImages(); 3623 } else if (event.target.id === "subscribe-selling-plan") { 3624 updateAddToCartButton(); 3625 updateBannerImages(); 3626 } 3627 }); 3628 3629 // Initialize on load 3630 const checkedRadio = document.querySelector('input[name="variety-purchaseType"]:checked'); 3631 if (checkedRadio) { 3632 handlePurchaseTypeChange(checkedRadio.value === "subscribe"); 3633 } 3634 3635 // Add to cart functionality 3636 addToCartButton.addEventListener('click', function() { 3637 const isSubscription = document.querySelector('input[name="variety-purchaseType"]:checked').value === "subscribe"; 3638 const activeQtyButton = document.querySelector(`.variety-flavor-options${isSubscription ? '.subs-btn' : ''} .variety-qty.${isSubscription ? "subs":"once"}.active`); 3639 const sellingPlanValue = document.getElementById('subscribe-selling-plan').value; 3640 const cartCount = document.querySelector(".variety-cart-count"); 3641 3642 const citrusCount = parseInt(activeQtyButton.dataset.citrusCount); 3643 const mintCount = parseInt(activeQtyButton.dataset.mintCount); 3644 3645 const items = []; 3646 3647 if(citrusCount === 2 && mintCount === 1){ 3648 const varietyProduct = productsData.filter((product) => product.handle === "citrus-mint-4-tubes"); 3649 3650 items.push({ 3651 id: varietyProduct?.[0]?.variants?.[0]?.id, 3652 quantity: 1, 3653 selling_plan: isSubscription ? sellingPlanValue: null 3654 }) 3655 } 3656 3657 if(citrusCount === 1 && mintCount === 2){ 3658 const varietyProduct = productsData.filter((product) => product.handle === "variety-pack-2-mint-1-citrus"); 3659 3660 items.push({ 3661 id: varietyProduct?.[0]?.variants?.[0]?.id, 3662 quantity: 1, 3663 selling_plan: isSubscription ? sellingPlanValue: null 3664 }) 3665 } 3666 3667 addMultipleItemsToCart(items); 3668 3669 }); 3670 3671 function handlePurchaseTypeBehaviour(radioBtn) { 3672 const subsButtons = document.querySelectorAll(".variety-qty.subs"); 3673 3674 if(radioBtn.value === "onetime") { 3675 subsButtons.forEach(btn => { 3676 btn.classList.remove("active", "font-body-medium"); 3677 }); 3678 } 3679 3680 if (radioBtn.value === "subscribe") { 3681 const hasActive = Array.from(subsButtons).some(btn => btn.classList.contains("active")); 3682 3683 if (!hasActive && subsButtons.length > 0) { 3684 subsButtons[0].classList.add("active", "font-body-medium"); 3685 } 3686 } 3687 } 3688 3689 function updateBannerImages(clickedQuantity = null) { 3690 const isSubscription = 3691 document.querySelector('input[name="variety-purchaseType"]:checked').value === 3692 "subscribe"; 3693 3694 const selectedQtyBtn = document.querySelector( 3695 `.variety-flavor-options${isSubscription ? ".subs-btn" : ""} .variety-qty.${ 3696 isSubscription ? "subs" : "once" 3697 }.active` 3698 ); 3699 3700 const activeQtyButton = clickedQuantity ? clickedQuantity : selectedQtyBtn; 3701 3702 const mainVarietyImage = document.querySelector(".main_variety_image"); 3703 const leftVarietyImage = document.querySelector(".left_variety_image"); 3704 const rightVarietyImage = document.querySelector(".right_variety_image"); 3705 3706 const allMainVarietyImages = document.querySelectorAll(".main_variety_image"); 3707 3708 const homePageBgCitrusImgElement = document.querySelector(".hm_bg_image_citrus"); 3709 const homePageBgMintImgElement = document.querySelector(".hm_bg_image_mint"); 3710 3711 const mobileMainVarietyImage = document.querySelector(".mobile_main_variety_image"); 3712 const mobileLeftVarietyImage = document.querySelector(".mobile_left_variety_image"); 3713 const mobileRightVarietyImage = document.querySelector(".mobile_right_variety_image"); 3714 const isTravelVarietyBtnActive = document.querySelector(".ts-flavor-btn.ts-variety.active");
3715 const isTravelVarietyUrlActive = urlParams.get('pack') === 'variety' && urlParams.get('size') === 'travel'; 3716 3717 3718 3719 const citrusCount = parseInt(activeQtyButton.dataset.citrusCount); 3720 const mintCount = parseInt(activeQtyButton.dataset.mintCount); 3721 3722 let currentProductImages = []; 3723 let currentHomePageImage = ""; 3724 let homePageDisplay = ""; 3725 let currentTravelImages = []; 3726 3727 3728 if (citrusCount === 2 && mintCount === 1) { 3729 const varietyProduct = productsData.filter( 3730 (product) => product.handle === "citrus-mint-4-tubes" 3731 ); 3732 currentHomePageImage = varietyProduct?.homepage_image; 3733 currentProductImages = varietyProduct?.[0]?.images || []; 3734 homePageDisplay = citrusGroupImgUrl; 3735 } 3736 3737 if (citrusCount === 1 && mintCount === 2) { 3738 const varietyProduct = productsData.filter( 3739 (product) => product.handle === "variety-pack-2-mint-1-citrus" 3740 ); 3741 currentHomePageImage = varietyProduct?.homepage_image; 3742 currentProductImages = varietyProduct?.[0]?.images || []; 3743 homePageDisplay = mintGroupImgUrl; 3744 } 3745 3746 if (isTravelVarietyBtnActive || isTravelVarietyUrlActive) { 3747 const varietyTravelProduct = productsData.filter( 3748 (product) => product.handle === "variety-travel-4-pack-of-1-oz" 3749 ); 3750 currentTravelImages = varietyTravelProduct?.[0]?.images || []; 3751 } 3752 3753 3754 3755 // â update DOM if images exist 3756 if (currentProductImages.length >= 3) { 3757 if(isTravelVarietyBtnActive || isTravelVarietyUrlActive) { 3758 if(mainVarietyImage) mainVarietyImage.src = currentTravelImages[0].src; 3759 if(mainVarietyImage) mainVarietyImage.alt = currentTravelImages[0].alt; 3760 } else { 3761 allMainVarietyImages.forEach((element) => { 3762 if(element) element.src = currentProductImages[0].src; 3763 if(element) element.alt = currentProductImages[0].alt; 3764 }) 3765 } 3766 3767 if(isTravelVarietyBtnActive || isTravelVarietyUrlActive) { 3768 if(mobileMainVarietyImage) mobileMainVarietyImage.src = currentTravelImages[1].src; 3769 if(mobileMainVarietyImage) mobileMainVarietyImage.alt = currentTravelImages[1].alt; 3770 } else { 3771 if(mobileMainVarietyImage) mobileMainVarietyImage.src = currentProductImages[4].src; 3772 if(mobileMainVarietyImage) mobileMainVarietyImage.alt = currentProductImages[4].alt; 3773 } 3774 3775 3776 3777 if(leftVarietyImage) leftVarietyImage.src = currentProductImages[1].src; 3778 if(leftVarietyImage) leftVarietyImage.alt = currentProductImages[1].alt; 3779 3780 if(mobileLeftVarietyImage) mobileLeftVarietyImage.src = currentProductImages[1].src; 3781 if(mobileLeftVarietyImage) mobileLeftVarietyImage.alt = currentProductImages[1].alt; 3782 3783 // Normal PDP: Variety uses Citrus gallery right-2 / right-2-mob overrides. 3784 // On travel Variety, skip these overrides so the "Right Image 2" gallery image is NOT shown. 3785 const right2 = window.RevitinGalleryRight2; 3786 const isTravelVarietyActive = isTravelVarietyBtnActive || isTravelVarietyUrlActive; 3787 const useCitrusRight2 = !isTravelVarietyActive && right2?.enabled && right2?.citrusRight; 3788 const useCitrusRight2Mobile = !isTravelVarietyActive && right2?.enabled && right2?.citrusRightMobile; 3789 3790 if (rightVarietyImage) { 3791 rightVarietyImage.src = useCitrusRight2 ? right2.citrusRight : currentProductImages[2].src; 3792 if (!useCitrusRight2) rightVarietyImage.alt = currentProductImages[2].alt; 3793 } 3794 3795 if (mobileRightVarietyImage) { 3796 mobileRightVarietyImage.src = useCitrusRight2Mobile 3797 ? right2.citrusRightMobile 3798 : currentProductImages[6].src; 3799 if (!useCitrusRight2Mobile) mobileRightVarietyImage.alt = currentProductImages[6].alt; 3800 } 3801 3802 if(homePageBgCitrusImgElement && homePageDisplay) homePageBgCitrusImgElement.src = homePageDisplay; 3803 if(homePageBgCitrusImgElement) homePageBgCitrusImgElement.classList.add("transform-image"); 3804 3805 if(homePageBgMintImgElement && homePageDisplay) homePageBgMintImgElement.src = homePageDisplay; 3806 if(homePageBgMintImgElement) homePageBgMintImgElement.classList.add("transform-image"); 3807 } 3808 } 3809 3810 function formatPrice(value) { 3811 const dollars = value / 100; 3812 return dollars % 1 === 0 ? `$${dollars.toFixed(0)}` : `$${dollars.toFixed(2)}`; 3813 } 3814 3815 function trimZeroes(price) { 3816 return Number(price) % 1 === 0 3817 ? Number(price).toString() // show as integer (51) 3818 : Number(price).toFixed(2); // keep 2 decimals if needed 3819 } 3820
3821 function addSubscriptionsHtml(clickedQuantity = null) { 3822 const activeQtyButton = clickedQuantity ? clickedQuantity : activeSubscription; 3823 const citrusCount = parseInt(activeQtyButton.dataset.citrusCount); 3824 const mintCount = parseInt(activeQtyButton.dataset.mintCount); 3825 const isSubscribedBtn = activeQtyButton.classList.contains("subs"); 3826 3827 let subscriptions = []; 3828 3829 if(citrusCount === 2 && mintCount === 1){ 3830 const varietyProduct = productsData.filter((product) => product.handle === "citrus-mint-4-tubes"); 3831 const sellingPlans = varietyProduct?.[0]?.variants?.[0]?.sellingPlans; 3832 subscriptions = sellingPlans; 3833 } 3834 3835 if(citrusCount === 1 && mintCount === 2){ 3836 const varietyProduct = productsData.filter((product) => product.handle === "variety-pack-2-mint-1-citrus"); 3837 const sellingPlans = varietyProduct?.[0]?.variants?.[0]?.sellingPlans; 3838 subscriptions = sellingPlans; 3839 } 3840 3841 if(!subscriptions?.length) return; 3842 if(!isSubscribedBtn) return; 3843 3844 const subscriptionsHtml = subscriptions.map((subscription) => { 3845 const monthFormatter = (text) => { 3846 // Extract the number from the subscription name 3847 const match = text.match(/(\d+)/); 3848 if (!match) return text; // fallback if no number found 3849 3850 const num = parseInt(match[1], 10); 3851 return num === 1 ? "month" : `${num} months`; 3852 }; 3853 3854 const formattedMonth = monthFormatter(subscription?.name); 3855 3856 // Example: select 3 months by default 3857 const isSelected = formattedMonth === "3 months"; 3858 3859 return `<option value="${subscription?.id}" ${isSelected ? "selected" : ""}>${formattedMonth}</option>`; 3860 }); 3861 3862 subscribeSelectContainer.innerHTML = subscriptionsHtml.join(""); 3863 } 3864 3865 function updateOneTimePrice() { 3866 const activeQtyButton = document.querySelector('.variety-qty.once.active'); 3867 if (!activeQtyButton) return; 3868 3869 const { compare_at_price: compareAtPrice, price } = productsData?.[0]?.variants?.[0] || {}; 3870 3871 if (!price || !compareAtPrice) return; 3872 3873 if (!oneTimeOriginalPrice) return; 3874 3875 const formatPrice = (price) => { 3876 let formatted = (typeof price === 'number' ? price.toFixed(2) : price); 3877 3878 if (formatted.endsWith('.00')) { 3879 formatted = formatted.replace('.00', ''); 3880 } 3881 3882 return formatted; 3883 }; 3884 3885 const savingPercentage = Math.round(((compareAtPrice - price) / compareAtPrice) * 100); 3886 3887 console.log("compare", compareAtPrice, price, savingPercentage); 3888 3889 if(oneTimeSave) oneTimeSave.textContent = `Save ${savingPercentage}%`; 3890 3891 oneTimeOriginalPrice.innerHTML = `$${formatPrice(price)}<span class="variety-original-price opacity-50">$${formatPrice(compareAtPrice)}</span>`; 3892 } 3893 3894 function updateSubscriptionPrice() { 3895 const { compare_at_price: compareAtPrice } = productsData?.[0]?.variants?.[0] || {}; 3896 const { price } = productsData?.[1]?.variants?.[0].sellingPlans?.[0] || {}; 3897 3898 if (!price || !compareAtPrice) return; 3899 3900 const savingPercentage = Math.round( 3901 ((compareAtPrice - price / 100) / compareAtPrice) * 100 3902 ); 3903 3904 if (!subscribeOriginalPrice) return; 3905 if(!subscriptionSave) return; 3906 3907 subscriptionSave.textContent = `Save ${savingPercentage}%`; 3908 const formatPrice = (priceInCents) => { 3909 const dollars = priceInCents / 100; 3910 return dollars % 1 === 0 ? dollars : dollars.toFixed(2); 3911 }; 3912 3913 const formatCompareAtPrice = (price) => { 3914 let formatted = (typeof price === 'number' ? price.toFixed(2) : price); 3915 3916 if (formatted.endsWith('.00')) { 3917 formatted = formatted.replace('.00', ''); 3918 } 3919 3920 return formatted; 3921 }; 3922 3923 subscribeOriginalPrice.innerHTML = `$${formatPrice(price)}<span class="variety-original-price opacity-50">$${formatCompareAtPrice(compareAtPrice)}</span>`; 3924 } 3925 3926 function addMultipleItemsToCart(items) { 3927 const cartCount = document.querySelector(".variety-cart-count"); 3928 const isSubscriptionAdd = items.some((item) => !!item.selling_plan); 3929 3930 const finalizeAdd = (payloadItems) => { 3931 fetch('/cart/add.js', { 3932 method: 'POST', 3933 headers: { 3934 'Content-Type': 'application/json' 3935 }, 3936 body: JSON.stringify({ items: payloadItems }) 3937 }) 3938 .then(response => response.json()) 3939 .then((cart) => { 3940 if (window.updateCartUI) { 3941 window.updateCartUI(cart); 3942 } else { 3943 window.dispatchEvent(new Event('cart:refresh')); 3944 } 3945 3946 if(cart.items){ 3947 document.querySelector('.site-cart').classList.add("active"); 3948 cartCount.textContent = parseInt(cartCount?.textContent) + 1; 3949 } 3950 }) 3951 .catch(error => { 3952 console.error('Error:', error); 3953 }); 3954 }; 3955 3956 // GWP: stamp line-item properties on PDP variety subscription ATC (no gift product) 3957 // Skip on wholesale / blocked landing templates 3958 if ( 3959 isSubscriptionAdd && 3960 window.RevitinGWP && 3961 window.RevitinGWP.enabled !== false && 3962 typeof window.RevitinGWP.getPdpGwpProperties === 'function' 3963 ) { 3964 fetch('/cart.js') 3965 .then((r) => r.json()) 3966 .then((cartData) => { 3967 const gwpProperties = window.RevitinGWP.getPdpGwpProperties(cartData); 3968 let stamped = false;
3969 const payloadItems = items.map((item) => { 3970 if (!item.selling_plan || !gwpProperties || stamped) return item; 3971 stamped = true; 3972 return Object.assign({}, item, { 3973 properties: Object.assign({}, item.properties || {}, gwpProperties), 3974 }); 3975 }); 3976 return { payloadItems, stamped: !!gwpProperties && stamped }; 3977 }) 3978 .then(({ payloadItems, stamped }) => { 3979 fetch('/cart/add.js', { 3980 method: 'POST', 3981 headers: { 'Content-Type': 'application/json' }, 3982 body: JSON.stringify({ items: payloadItems }), 3983 }) 3984 .then((response) => response.json()) 3985 .then(async (cart) => { 3986 if (window.updateCartUI) { 3987 window.updateCartUI(cart); 3988 } else { 3989 window.dispatchEvent(new Event('cart:refresh')); 3990 } 3991 3992 if (cart.items) { 3993 document.querySelector('.site-cart').classList.add('active'); 3994 cartCount.textContent = parseInt(cartCount?.textContent) + 1; 3995 } 3996 3997 try { 3998 if ( 3999 stamped && 4000 typeof window.RevitinGWP.ensureGiftAttributes === 'function' 4001 ) { 4002 await window.RevitinGWP.ensureGiftAttributes(); 4003 } else if ( 4004 !stamped && 4005 typeof window.RevitinGWP.markGiftFromPdp === 'function' 4006 ) { 4007 // Fallback: stamp after add if properties were not included in payload 4008 await window.RevitinGWP.markGiftFromPdp(); 4009 } 4010 } catch (_) {} 4011 }) 4012 .catch((error) => { 4013 console.error('Error:', error); 4014 }); 4015 }) 4016 .catch(() => finalizeAdd(items)); 4017 return; 4018 } 4019 4020 finalizeAdd(items); 4021 } 4022 4023 function updateAddToCartButton() {} 4024 4025 function addVarietyToUrl() { 4026 const url = new URL(window.location); 4027 url.searchParams.set('pack', 'variety'); 4028 window.history.replaceState({}, '', url); 4029 } 4030 4031 function resetSliderDots(currentTab) { 4032 // Get the main container 4033 const container = document.querySelector('.pdp_slider_container'); 4034 if (!container) return; 4035 4036 // Find both flavor sections within the container 4037 const citrusSection = container.querySelector('[data-swap-flavor="Citrus"]'); 4038 const mintSection = container.querySelector('[data-swap-flavor="Mint"]'); 4039 4040 console.log("currentTab", currentTab); 4041 4042 if(currentTab === "Variety") { 4043 mintSection.classList.remove("!opacity-100"); 4044 mintSection.classList.add("opacity-0"); 4045 4046 citrusSection.classList.add("!opacity-100"); 4047 citrusSection.classList.remove("opacity-0"); 4048 } 4049 4050 // Reset Mint dots 4051 if (mintSection) { 4052 const mintDots = mintSection.querySelectorAll('.progress-slider-dot'); 4053 mintDots.forEach(dot => { 4054 dot.classList.remove('active'); 4055 4056 // Reset the progress width to 0 4057 const progressSpan = dot.querySelector('.dot-progress'); 4058 if (progressSpan) { 4059 progressSpan.style.width = '0%'; 4060 progressSpan.style.transition = 'none'; 4061 } 4062 }); 4063 4064 // Activate the first dot in Mint 4065 if (mintDots.length > 0) { 4066 mintDots[0].classList.add('active'); 4067 mintDots[0].click(); 4068 } 4069 } 4070 4071 // Reset Citrus dots 4072 if (citrusSection) { 4073 const citrusDots = citrusSection.querySelectorAll('.progress-slider-dot'); 4074 citrusDots.forEach(dot => { 4075 dot.classList.remove('active'); 4076 4077 // Reset the progress width to 0 4078 const progressSpan = dot.querySelector('.dot-progress'); 4079 if (progressSpan) { 4080 progressSpan.style.width = '0%';
4081 progressSpan.style.transition = 'none'; 4082 } 4083 }); 4084 4085 // Activate the first dot in Citrus 4086 if (citrusDots.length > 0) { 4087 citrusDots[0].classList.add('active'); 4088 citrusDots[0].click(); 4089 } 4090 } 4091 } 4092 4093 function handleVarietyButtonClick() { 4094 varietySelectionContainer.style.display = 'block'; 4095 varietyButton.style.background = '#F5EEE0'; 4096 varietyButton.style.borderColor = '#5F471D'; 4097 document.querySelector('.main__atc__button').style.display = 'none'; 4098 const detailsLink = document.querySelector('.ts-details-link'); 4099 4100 if(detailsLink){ 4101 detailsLink.href = `/products/revitin-natural-toothpaste/Citrus?pack=variety`; 4102 } 4103 4104 if (oneTimeContainer) { 4105 oneTimeContainer.style.display = 'none'; 4106 } 4107 4108 document.querySelectorAll('.once_tube_container').forEach(el => el.classList.add('hidden')); 4109 document.querySelectorAll('.subscription-box').forEach(el => el.style.display = 'none'); 4110 4111 addVarietyToUrl(); 4112 resetFlavorButtons(); 4113 updateAddToCartButton(); 4114 resetSliderDots("Variety"); 4115 } 4116 4117 function updateDetailsLink(flavor) { 4118 const detailsLink = document.querySelector(".ts-details-link"); 4119 4120 if (detailsLink) { 4121 detailsLink.style.display = 'block'; 4122 detailsLink.href = `/products/revitin-natural-toothpaste/${flavor}`; 4123 } 4124 } 4125 4126 function handleFlavorButtonClick(clickedButton) { 4127 const mainVarietyImage = document.querySelector(".main_variety_image"); 4128 const leftVarietyImage = document.querySelector(".left_variety_image"); 4129 const rightVarietyImage = document.querySelector(".right_variety_image"); 4130 4131 const mobileMainVarietyImage = document.querySelector(".mobile_main_variety_image"); 4132 const mobileLeftVarietyImage = document.querySelector(".mobile_left_variety_image"); 4133 const mobileRightVarietyImage = document.querySelector(".mobile_right_variety_image"); 4134 4135 const homePageBgCitrusImgElement = document.querySelector(".hm_bg_image_citrus"); 4136 const homePageBgMintImgElement = document.querySelector(".hm_bg_image_mint"); 4137 4138 varietySelectionContainer.style.display = 'none'; 4139 varietyButton.classList.remove('active'); 4140 varietyButton.style.border = '1px solid #C6C6C6'; 4141 varietyButton.style.background = 'transparent'; 4142 document.querySelector('.main__atc__button').style.display = 'flex'; 4143 4144 if (oneTimeContainer) { 4145 oneTimeContainer.style.display = 'flex'; 4146 } 4147 4148 resetFlavorButtons(); 4149 resetSliderDots(); 4150 4151 clickedButton.classList.add('active'); 4152 4153 if (clickedButton.dataset.flavor === 'Citrus') { 4154 clickedButton.style.background = '#ffdea3'; 4155 clickedButton.style.borderColor = '#FFBB42'; 4156 4157 if(mainVarietyImage) mainVarietyImage.src = citrusImages?.[0]; 4158 if(leftVarietyImage) leftVarietyImage.src = citrusImages?.[1]; 4159 if(rightVarietyImage) { 4160 rightVarietyImage.src = (window.RevitinGalleryRight2?.enabled && window.RevitinGalleryRight2?.citrusRight) 4161 ? window.RevitinGalleryRight2.citrusRight 4162 : citrusImages?.[2]; 4163 } 4164 4165 4166 if(mobileMainVarietyImage) mobileMainVarietyImage.src = citrusImages?.[5]; 4167 if(mobileLeftVarietyImage) mobileLeftVarietyImage.src = citrusImages?.[1]; 4168 if(mobileRightVarietyImage) { 4169 mobileRightVarietyImage.src = (window.RevitinGalleryRight2?.enabled && window.RevitinGalleryRight2?.citrusRightMobile) 4170 ? window.RevitinGalleryRight2.citrusRightMobile 4171 : citrusImages?.[2]; 4172 } 4173 if(homePageBgCitrusImgElement) homePageBgCitrusImgElement.src = citrusImages?.[3]; 4174 if(homePageBgCitrusImgElement) homePageBgCitrusImgElement.classList.remove("transform-image"); 4175 updateDetailsLink("Citrus"); 4176 } else if (clickedButton.dataset.flavor === 'Mint') { 4177 const products = JSON.parse(document.getElementById('all-products-json').textContent); 4178 const targetProduct = products.find(product => { 4179 const productTitle = product.title?.toLowerCase(); 4180 4181 if (!productTitle?.includes("single tube")) return false;
4182 4183 return product.variants?.some(variant => 4184 variant.title?.toLowerCase().includes("mint") 4185 ); 4186 }); 4187 4188 const mintMainVarietyImage = document.querySelector( 4189 '.image_update_container [data-swap-flavor="Mint"] .main_variety_image' 4190 ); 4191 4192 console.log('productsData', targetProduct?.images?.[0]?.src); 4193 if(mintMainVarietyImage) mintMainVarietyImage.src = targetProduct?.images?.[0]?.src; 4194 4195 if(homePageBgMintImgElement) homePageBgMintImgElement.src = citrusImages?.[4]; 4196 if(homePageBgMintImgElement) homePageBgMintImgElement.classList.remove("transform-image"); 4197 clickedButton.style.background = '#e5ecd1'; 4198 clickedButton.style.borderColor = '#9ca975'; 4199 updateDetailsLink("Mint"); 4200 } 4201 } 4202 4203 function handleVarietyQtyClick(clickedButton) { 4204 const parentContainer = clickedButton.closest('.variety-flavor-options'); 4205 parentContainer.querySelectorAll('.variety-qty').forEach(btn => { 4206 btn.classList.remove('active'); 4207 btn.classList.remove('font-body-medium'); 4208 }); 4209 4210 clickedButton.classList.add('active'); 4211 clickedButton.classList.add('font-body-medium'); 4212 4213 // NEW CODE: Select the parent radio button 4214 const parentLabel = clickedButton.closest('.variety-box'); 4215 const radioInput = parentLabel.querySelector('.variety-radio-input'); 4216 if (radioInput) { 4217 radioInput.checked = true; 4218 // Trigger the change event to update the UI 4219 const event = new Event('change', { bubbles: true }); 4220 radioInput.dispatchEvent(event); 4221 } 4222 } 4223 4224 function handlePurchaseTypeChange(isSubscribe) { 4225 const subscribeBox = document.getElementById("variety-subscribeBox"); 4226 const oneTimeBox = document.getElementById("variety-oneTimeBox"); 4227 const subscribeFlavors = document.getElementById("variety-subscribeFlavors"); 4228 const oneTimeFlavors = document.getElementById("variety-oneTimeFlavors"); 4229 4230 subscribeBox.classList.add("variety-active"); 4231 oneTimeBox.classList.add("variety-active"); 4232 4233 subscribeBox.classList.toggle("transparent-box", !isSubscribe); 4234 oneTimeBox.classList.toggle("transparent-box", isSubscribe); 4235 4236 4237 if (isSubscribe) { 4238 subscribeFlavors.classList.add("variety-show"); 4239 oneTimeFlavors.classList.remove("variety-show"); 4240 } else { 4241 subscribeFlavors.classList.remove("variety-show"); 4242 oneTimeFlavors.classList.add("variety-show"); 4243 } 4244 } 4245 4246 function resetFlavorButtons() { 4247 flavorButtons.forEach(button => { 4248 button.classList.remove('active'); 4249 button.style.border = '1px solid #C6C6C6'; 4250 button.style.background = 'transparent'; 4251 4252 }); 4253 } 4254 }); 4255</script>
4255 4256 4257<style> 4258 @media (min-width: 1024px) { 4259 .transform-image { 4260 transform: scale(1.8) translate(10%, 10%); 4261 } 4262 } 4263 4264 4265 @media (max-width: 768px) { 4266 .variety-original-price { 4267 font-size: 12px !important; 4268 } 4269 4270 .variety-price { 4271 position: relative; 4272 } 4273 4274 .variety-flavor-options button { 4275 font-size: 13px !important; 4276 padding: 0.6rem 0.8rem !important; 4277 } 4278 4279 .variety-flavor-options { 4280 margin-top: 1.4rem; 4281 } 4282 } 4283 4284 4285 .variety-qty.active{ 4286 border: 1.3px solid #5F471D; 4287 } 4288 4289 .variety-selling-plan-select { 4290 outline: none; 4291 border: none; 4292 appearance: none; 4293 -webkit-appearance: none; 4294 -moz-appearance: none; 4295 padding: 0px 0px 0px 1px; 4296 background: #ff000000; 4297 text-decoration: underline; 4298 } 4299 4300 .variety-selection-container { 4301 margin-top: 2.1rem; 4302 display: none; 4303 } 4304 4305 .variety-box { 4306 display: block; 4307 border: 1px solid #5F471D; 4308 border-radius: 10px; 4309 padding: 1.1rem 1rem 1.7rem 1rem; 4310 margin-bottom: 1rem; 4311 position: relative; 4312 cursor: pointer; 4313 } 4314 4315 .variety-box.variety-active { 4316 border: 1px solid #5F471D; 4317 background-color: #F7EEDE; 4318 } 4319 4320 #variety-subscribeBox.transparent-box, 4321 #variety-oneTimeBox.transparent-box { 4322 background-color: transparent; 4323 } 4324 4325 .variety-radio-group { 4326 display: flex; 4327 align-items: center; 4328 gap: 10px; 4329 font-weight: bold; 4330 position: relative; 4331 } 4332 4333 .variety-save-tag { 4334 position: absolute; 4335 background-color: #FEFBF0; 4336 color: #5F471D; 4337 padding: 6px 9px !important; 4338 font-size: 12px; 4339 font-weight: normal; 4340 border-radius: 15px; 4341 bottom: -1.45rem; 4342 right: 0rem; 4343 line-height: 1; 4344 } 4345 4346 .variety-price { 4347 margin-left: auto; 4348 font-weight: bold; 4349 } 4350 4351 .variety-original-price { 4352 text-decoration: line-through; 4353 font-weight: normal; 4354 margin-right: 5px; 4355 font-size: 14px; 4356 padding-left: 4px; 4357 } 4358 4359 .variety-flavor-options { 4360 margin-top: 1.7rem; 4361 display: none; 4362 gap: 0.5rem; 4363 } 4364 4365 .variety-flavor-options.variety-show { 4366 display: flex; 4367 } 4368 4369 .variety-flavor-options button { 4370 padding: 0.6rem 1rem; 4371 background: rgb(255 251 239 / var(--tw-bg-opacity)); 4372 border: 1px solid #5F471D80; 4373 border-radius: 6px; 4374 cursor: pointer; 4375 font-size: 16px; 4376 line-height: 1; 4377 } 4378 4379 .variety-description { 4380 margin-top: 0.5rem; 4381 font-size: 0.9rem; 4382 } 4383 4384 .variety-radio-input { 4385 display: none; 4386 } 4387 4388 .variety-radio-dot { 4389 height: 16px; 4390 width: 16px; 4391 border-radius: 50%; 4392 border: 1px solid #5F471D; 4393 display: inline-block; 4394 position: relative; 4395 } 4396 4397 .variety-box input[type="radio"]:checked + .variety-radio-group .variety-radio-dot::after { 4398 content: ""; 4399 position: absolute; 4400 top: 50%; 4401 left: 50%; 4402 transform: translate(-50%, -50%); 4403 width: 8px; 4404 height: 8px; 4405 background: #5F471D; 4406 border-radius: 50%; 4407 } 4408 4409 .variety-selector-btn { 4410 padding: 8px 16px 8px 8px; 4411 } 4412 4413 .variety-flavor-options.subs-btn { 4414 display: flex; 4415 } 4416 4417 4418 /* Hide by default */ 4419 #variety-subscribeBox .variety-flavor-options, 4420 #variety-subscribeBox .variety-description { 4421 display: none; 4422 } 4423 4424 /* Show only when .variety-box has .variety-active */ 4425 #variety-subscribeBox.variety-active .variety-flavor-options, 4426 #variety-subscribeBox.variety-active .variety-description { 4427 display: block; 4428 } 4429 4430 #variety-oneTimeBox:not(.variety-active) .once-variety-price { 4431 transform: translateY(-4px); 4432 } 4433 4434 #variety-oneTimeBox:not(.variety-active) .variety-save-tag.one-time { 4435 bottom: -1.15rem; 4436 } 4437
4438 #variety-oneTimeBox:not(.variety-active) .variety-save-tag { 4439 background-color: #F7EEDE; 4440 } 4441</style> 4442 4443 <form> 4444 <cadence-selector> 4445 <div class="grid grid-flow-col justify-start gap-3 mt-8 hidden"> 4446 <button 4447 type="button" 4448 data-cadence="Subscribe" 4449 class="font-body-medium text-xs px-4 lg:px-6 py-2 rounded-t-md border-x border-t border-brown relative top-[1px] active" 4450 > 4451 Subscribe & Save 4452 </button> 4453 </div> 4454 </cadence-selector> 4455 <div class="rounded-r-lg rounded-b-lg product-form-container"> 4456 <variant-selector> 4457 <div class=" subscription-box hidden" data-flavor="Citrus" data-cadence="Subscribe"> 4458 <div> 4459 <div class="save_20">Subscribe & Save up to 20%</div> 4460 <div> 4461 <div class="benifit_text">Free shipping. Save on every order.</div> 4462 <div class="benifit_text">Easily edit, skip, or cancel anytime.</div> 4463 4464 </div></div> 4465 4466 4467 4468 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 <button 4500 type="button" 4501 data-variant-id="45594633666698" 4502 data-flavor="Citrus" 4503 class="variant-price-btn remove_one_time w-full" 4504 > 4505 <div class=" grid grid-cols-[16px_1fr] gap-3 items-start border-b border-brown/20 subscriptions_selection"> 4506 <div class="flex w-4 h-4 rounded-full border items-center pos-rel justify-center cursor-pointer border border-brown"> 4507 <div class="bg-transparent appearance-none rounded-full w-2 h-2 cursor-pointer"></div> 4508 </div> 4509 <div> 4510 <div class="grid grid-flow-col justify-between items-center"> 4511 <span class="text-base lg:text-lg"> 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533 4534 4535 4536 4537 4538 4539 4540 4541 4542 4543 4544 4545 4546 Trio - 3 tubes 4547 <span class="most-popular-pill">Most Popular</span> 4548 4549 </span> 4550 <div class="grid grid-flow-col gap-1 justify-end text-sm lg:text-[0.9375rem] relative"> 4551 4552 <span class="subscription_original"> 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 $42 4563 </span>
4564 <span class="line-through opacity-50">$51</span> 4565 4566 4567 4568 4569 <div class="save__amount"> 4570 <p>Save 18%</p> 4571 </div> 4572 4573 4574 4575 </div> 4576 </div> 4577 <div 4578 style="display: flex !important;" 4579 class="delivery-options flex flex-col gap-2.5 items-start hidden" 4580 > 4581 <div class="flex gap-1 month-frequency"> 4582 <label for="subscribe-plan" class="flex text-brown cursor-pointer"> 4583 <p>Delivered every</p> 4584 </label> 4585 <div class="relative"> 4586 <select-input> 4587 <div class="frequency-selector"> 4588 <select style="" class="frequency-select"> 4589 <optgroup label="Select Frequency of delivery"> 4590 4591 4592 4593 4594 4595 4596 <option 4597 value="1-month" 4598 4599 > 4600 4601 month 4602 4603 </option> 4604 4605 4606 4607 4608 4609 4610 4611 <option 4612 value="2-months" 4613 4614 > 4615 4616 2 months 4617 4618 </option> 4619 4620 4621 4622 4623 4624 4625 4626 <option 4627 value="3-months" 4628 4629 selected 4630 4631 > 4632 4633 3 months 4634 4635 </option> 4636 4637 4638 4639 4640 4641 4642 4643 <option 4644 value="6-months" 4645 4646 > 4647 4648 6 months 4649 4650 </option> 4651 4652 4653 </optgroup> 4654 </select> 4655 <div class="flex items-center gap-2.5 border-b border-sand">
4656 <span 4657 style="text-transform: lowercase; font-weight: normal;" 4658 class="select-target text-sm text-sand month_selector" 4659 > 4660 4661 4662 4663 3 months 4664 4665 </span> 4666 </div> 4667 </div> 4668 </select-input> 4669 </div> 4670 </div> 4671 <div class="flex flex-col items-start"> 4672 4673 </div> 4674 </div> 4675 </div> 4676 </div> 4677 </button> 4678 4679 4680 4681 4682 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 4725 4726 4727 4728 4729 4730 4731 4732 4733 4734 4735 4736 4737 4738 4739 4740 4741 4742 4743 4744 4745 4746 4747 4748 4749 4750 4751 4752 4753 4754 4755 4756 4757 4758 4759 4760 4761 4762 <button 4763 type="button" 4764 data-variant-id="45594652901514" 4765 data-flavor="Citrus" 4766 class="variant-price-btn remove_one_time w-full" 4767 > 4768 <div class=" grid grid-cols-[16px_1fr] gap-3 items-start border-b border-brown/20 subscriptions_selection"> 4769 <div class="flex w-4 h-4 rounded-full border items-center pos-rel justify-center cursor-pointer border border-brown"> 4770 <div class="bg-transparent appearance-none rounded-full w-2 h-2 cursor-pointer"></div> 4771 </div> 4772 <div> 4773 <div class="grid grid-flow-col justify-between items-center"> 4774 <span class="text-base lg:text-lg"> 4775 4776 4777 4778 4779 4780 4781 4782 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793 4794 4795 4796 4797 4798 4799 4800 4801 4802 4803 4804 4805 4806 4807 4808 4809 Family pack - 5 tubes 4810 4811 </span> 4812 <div class="grid grid-flow-col gap-1 justify-end text-sm lg:text-[0.9375rem] relative"> 4813
4814 <span class="subscription_original"> 4815 4816 4817 4818 4819 4820 4821 4822 4823 4824 $68 4825 </span> 4826 <span class="line-through opacity-50">$85</span> 4827 4828 4829 4830 4831 <div class="save__amount"> 4832 <p>Save 20%</p> 4833 </div> 4834 4835 4836 4837 </div> 4838 </div> 4839 <div 4840 style="display: flex !important;" 4841 class="delivery-options flex flex-col gap-2.5 items-start hidden" 4842 > 4843 <div class="flex gap-1 month-frequency"> 4844 <label for="subscribe-plan" class="flex text-brown cursor-pointer"> 4845 <p>Delivered every</p> 4846 </label> 4847 <div class="relative"> 4848 <select-input> 4849 <div class="frequency-selector"> 4850 <select style="" class="frequency-select"> 4851 <optgroup label="Select Frequency of delivery"> 4852 4853 4854 4855 4856 4857 4858 <option 4859 value="1-month" 4860 4861 > 4862 4863 month 4864 4865 </option> 4866 4867 4868 4869 4870 4871 4872 4873 <option 4874 value="2-months" 4875 4876 > 4877 4878 2 months 4879 4880 </option> 4881 4882 4883 4884 4885 4886 4887 4888 <option 4889 value="3-months" 4890 4891 selected 4892 4893 > 4894 4895 3 months 4896 4897 </option> 4898 4899 4900 4901 4902 4903 4904 4905 <option 4906 value="6-months" 4907 4908 > 4909 4910 6 months 4911 4912 </option> 4913 4914 4915 </optgroup> 4916 </select> 4917 <div class="flex items-center gap-2.5 border-b border-sand">
4918 <span 4919 style="text-transform: lowercase; font-weight: normal;" 4920 class="select-target text-sm text-sand month_selector" 4921 > 4922 4923 4924 4925 3 months 4926 4927 </span> 4928 </div> 4929 </div> 4930 </select-input> 4931 </div> 4932 </div> 4933 <div class="flex flex-col items-start"> 4934 4935 </div> 4936 </div> 4937 </div> 4938 </div> 4939 </button> 4940 4941 4942 4943 4944 4945 4946 4947 4948 4949 4950 4951 4952 4953 4954 4955 4956 4957 4958 4959 4960 4961 4962 4963 4964 4965 4966 4967 4968 4969 </div> 4970 </variant-selector> 4971 <variant-selector> 4972 <div class="subscription-box hidden" data-flavor="Mint" data-cadence="Subscribe"> 4973 <div> 4974 <div class="save_20">Subscribe & Save up to 20%</div> 4975 <div> 4976 <div class="benifit_text">Free shipping. Save on every order.</div> 4977 <div class="benifit_text">Easily edit, skip, or cancel anytime.</div> 4978 4979 </div></div> 4980 4981 4982 4983 4984 4985 4986 4987 4988 4989 4990 4991 4992 4993 4994 4995 4996 4997 4998 4999 5000 5001 5002 5003 5004 5005 5006 5007 5008 5009 5010 5011 5012 5013 5014 5015 5016 5017 5018 <button 5019 type="button" 5020 data-variant-id="45618606080138" 5021 data-flavor="Mint" 5022 class="variant-price-btn remove_one_time w-full" 5023 > 5024 <div class="grid grid-cols-[16px_1fr] gap-3 items-start border-b border-brown/20 subscriptions_selection py-3"> 5025 <div class="flex w-4 h-4 rounded-full border items-center pos-rel justify-center cursor-pointer border border-brown"> 5026 <div class="bg-transparent appearance-none rounded-full w-2 h-2 cursor-pointer"></div> 5027 </div> 5028 <div> 5029 <div class="grid grid-flow-col justify-between items-center"> 5030 <span class="text-base lg:text-lg"> 5031 5032 5033 5034 5035 5036 5037 5038 5039 5040 5041 5042 5043 5044 5045 5046 5047 5048 5049 5050 5051 5052 5053 5054 5055 5056 5057 5058 5059 5060 5061 5062 5063 5064 Trio - 3 tubes
5065 <span class="most-popular-pill">Most Popular</span> 5066 5067 </span> 5068 <div class="grid grid-flow-col gap-1 justify-end text-sm lg:text-[0.9375rem] relative"> 5069 5070 <span class="subscription_original"> 5071 5072 5073 5074 5075 5076 5077 5078 5079 5080 $42 5081 </span> 5082 <span class="line-through opacity-50">$51</span> 5083 5084 5085 5086 5087 <div class="save__amount"> 5088 <p>Save 18%</p> 5089 </div> 5090 5091 5092 5093 </div> 5094 </div> 5095 <div 5096 style="display: flex !important;" 5097 class="delivery-options flex flex-col gap-2.5 items-start hidden" 5098 > 5099 <div class="flex gap-1 month-frequency"> 5100 <label for="subscribe-plan" class="flex text-brown cursor-pointer"> 5101 <p>Delivered every</p> 5102 </label> 5103 <div class="relative"> 5104 <select-input> 5105 <div class="frequency-selector"> 5106 <select style="" class="frequency-select"> 5107 <optgroup label="Select Frequency of delivery"> 5108 5109 5110 5111 5112 5113 5114 <option 5115 value="1-month" 5116 5117 > 5118 5119 month 5120 5121 </option> 5122 5123 5124 5125 5126 5127 5128 5129 <option 5130 value="2-months" 5131 5132 > 5133 5134 2 months 5135 5136 </option> 5137 5138 5139 5140 5141 5142 5143 5144 <option 5145 value="3-months" 5146 5147 selected 5148 5149 > 5150 5151 3 months 5152 5153 </option> 5154 5155 5156 5157 5158 5159 5160 5161 <option 5162 value="6-months" 5163 5164 > 5165 5166 6 months 5167 5168 </option> 5169 5170 5171 </optgroup> 5172 </select> 5173 <div class="flex items-center gap-2.5 border-b border-sand">
5174 <span 5175 style="text-transform: lowercase; font-weight: normal;" 5176 class="select-target text-sm text-sand month_selector" 5177 > 5178 5179 5180 5181 3 months 5182 5183 </span> 5184 </div> 5185 </div> 5186 </select-input> 5187 </div> 5188 </div> 5189 <div class="flex flex-col items-start"> 5190 5191 </div> 5192 </div> 5193 </div> 5194 </div> 5195 </button> 5196 5197 5198 5199 5200 5201 5202 5203 5204 5205 5206 5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228 5229 5230 5231 5232 5233 5234 5235 5236 5237 5238 5239 5240 5241 5242 5243 5244 5245 5246 5247 5248 5249 5250 5251 5252 5253 5254 5255 5256 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272 5273 5274 5275 5276 5277 <button 5278 type="button" 5279 data-variant-id="45618689310858" 5280 data-flavor="Mint" 5281 class="variant-price-btn remove_one_time w-full" 5282 > 5283 <div class="grid grid-cols-[16px_1fr] gap-3 items-start border-b border-brown/20 subscriptions_selection py-3"> 5284 <div class="flex w-4 h-4 rounded-full border items-center pos-rel justify-center cursor-pointer border border-brown"> 5285 <div class="bg-transparent appearance-none rounded-full w-2 h-2 cursor-pointer"></div> 5286 </div> 5287 <div> 5288 <div class="grid grid-flow-col justify-between items-center"> 5289 <span class="text-base lg:text-lg"> 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 Family pack - 5 tubes 5324 5325 </span> 5326 <div class="grid grid-flow-col gap-1 justify-end text-sm lg:text-[0.9375rem] relative"> 5327
5328 <span class="subscription_original"> 5329 5330 5331 5332 5333 5334 5335 5336 5337 5338 $68 5339 </span> 5340 <span class="line-through opacity-50">$85</span> 5341 5342 5343 5344 5345 <div class="save__amount"> 5346 <p>Save 20%</p> 5347 </div> 5348 5349 5350 5351 </div> 5352 </div> 5353 <div 5354 style="display: flex !important;" 5355 class="delivery-options flex flex-col gap-2.5 items-start hidden" 5356 > 5357 <div class="flex gap-1 month-frequency"> 5358 <label for="subscribe-plan" class="flex text-brown cursor-pointer"> 5359 <p>Delivered every</p> 5360 </label> 5361 <div class="relative"> 5362 <select-input> 5363 <div class="frequency-selector"> 5364 <select style="" class="frequency-select"> 5365 <optgroup label="Select Frequency of delivery"> 5366 5367 5368 5369 5370 5371 5372 <option 5373 value="1-month" 5374 5375 > 5376 5377 month 5378 5379 </option> 5380 5381 5382 5383 5384 5385 5386 5387 <option 5388 value="2-months" 5389 5390 > 5391 5392 2 months 5393 5394 </option> 5395 5396 5397 5398 5399 5400 5401 5402 <option 5403 value="3-months" 5404 5405 selected 5406 5407 > 5408 5409 3 months 5410 5411 </option> 5412 5413 5414 5415 5416 5417 5418 5419 <option 5420 value="6-months" 5421 5422 > 5423 5424 6 months 5425 5426 </option> 5427 5428 5429 </optgroup> 5430 </select> 5431 <div class="flex items-center gap-2.5 border-b border-sand">
5432 <span 5433 style="text-transform: lowercase; font-weight: normal;" 5434 class="select-target text-sm text-sand month_selector" 5435 > 5436 5437 5438 5439 3 months 5440 5441 </span> 5442 </div> 5443 </div> 5444 </select-input> 5445 </div> 5446 </div> 5447 <div class="flex flex-col items-start"> 5448 5449 </div> 5450 </div> 5451 </div> 5452 </div> 5453 </button> 5454 5455 5456 5457 5458 5459 5460 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 </div> 5476 </variant-selector> 5477 5478 <cadence-selector> 5479 <div class="flex justify-between items-center pt-1 pb-6 bg-sand one_time_container"> 5480 <div style="margin-left: 12px; padding-top: 15px;" class="flex items-center gap-2"> 5481 <div> 5482 <!-- Radio Button --> 5483 <div class="flex w-4 h-4 rounded-full border items-center justify-center cursor-pointer border border-brown one_time_radio"> 5484 <div 5485 style="background-color: rgb(95, 71, 29);" 5486 class="bg-transparent appearance-none rounded-full w-2 h-2 cursor-pointer" 5487 ></div> 5488 </div> 5489 </div> 5490 <div class=""> 5491 <button 5492 type="button" 5493 data-cadence="Once" 5494 class="one_time_heading" 5495 > 5496 One-Time Purchase 5497 </button> 5498 </div> 5499 </div> 5500 <div 5501 style="padding: 3px 14px; transform: translateY(6px);" 5502 class="one_time_price_meta grid grid-flow-col gap-1 justify-end text-sm lg:text-[0.9375rem] relative" 5503 > 5504 <span style="font-size: 18px;" class="one_time_price font-body-medium">$17</span> 5505 <span class="line-through opacity-50 one_time_before"></span><div style="display: none;" class="save__amount one_time_saving"> 5506 <p>Save</p> 5507 </div> 5508 </div> 5509 </div> 5510 </cadence-selector> 5511 <variant-selector> 5512 <div 5513 class="flex gap-2 justify-between bg-sand once_tube_container relative" 5514 data-flavor="Mint" 5515 data-cadence="Once" 5516 > 5517 5518 5519 5520 5521 5522 5523 5524 5525 5526 5527 5528 5529 5530 5531 5532 5533 5534 5535 5536 5537 5538 5539 5540 5541 5542 5543 5544 5545 5546 5547 5548 <button 5549 style="width: 100%;" 5550 type="button" 5551 data-variant-id="45622706602122" 5552 data-flavor="Mint" 5553 data-price="1700" 5554 data-pack-size="Single Tube" 5555 data-compare-at-price="1700" 5556 class="variant-price-btn temp border-remove-btn w-full active " 5557 > 5558 <div class="tube-category"> 5559 <div class="max"> 5560 <div>
5561 <span 5562 style="width: max-content; display: inline-block;" 5563 class="font-body-medium text-xs lg:text-sm" 5564 >Single Tube</span> 5565 </div> 5566 </div></div> 5567 </button> 5568 5569 5570 5571 5572 5573 5574 5575 5576 5577 5578 5579 5580 5581 5582 5583 5584 5585 5586 5587 5588 5589 5590 5591 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 5620 5621 5622 5623 5624 5625 5626 5627 5628 5629 5630 <button 5631 style="width: 100%;" 5632 type="button" 5633 data-variant-id="45618606080138" 5634 data-flavor="Mint" 5635 data-price="4600" 5636 data-pack-size="3 Tubes" 5637 data-compare-at-price="5100" 5638 class="variant-price-btn temp border-remove-btn w-full " 5639 > 5640 <div class="tube-category"> 5641 <div class="max"> 5642 <div> 5643 <span 5644 style="width: max-content; display: inline-block;" 5645 class="font-body-medium text-xs lg:text-sm" 5646 >3 Tubes</span> 5647 </div> 5648 </div><span class="custom-badge family one_time_saving_badge">Save 10%</span></div> 5649 </button> 5650 5651 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 <button 5713 style="width: 100%;" 5714 type="button" 5715 data-variant-id="45618689310858" 5716 data-flavor="Mint" 5717 data-price="7000" 5718 data-pack-size="5 Tubes" 5719 data-compare-at-price="8500" 5720 class="variant-price-btn temp border-remove-btn w-full " 5721 > 5722 <div class="tube-category"> 5723 <div class="max"> 5724 <div> 5725 <span 5726 style="width: max-content; display: inline-block;" 5727 class="font-body-medium text-xs lg:text-sm" 5728 >5 Tubes</span> 5729 </div> 5730 </div><span class="custom-badge family one_time_saving_badge">Save 18%</span></div> 5731 </button> 5732 5733 5734 5735 5736 5737 5738 5739 5740 5741 5742 5743 5744 5745 5746 5747 5748 5749 5750 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 5766 5767 5768 5769 5770 5771 5772 5773 5774 5775 5776 5777 5778 5779 5780 5781 5782 5783 5784 5785 5786 5787 5788 5789 5790 5791 5792 5793 5794 <button 5795 style="width: 100%;" 5796 type="button" 5797 data-variant-id="45622715121802" 5798 data-flavor="Mint" 5799 data-price="35000" 5800 data-pack-size="25 Tubes" 5801 data-compare-at-price="42500" 5802 class="variant-price-btn temp border-remove-btn w-full " 5803 > 5804 <div class="tube-category"> 5805 <div class="max"> 5806 <div>
5807 <span 5808 style="width: max-content; display: inline-block;" 5809 class="font-body-medium text-xs lg:text-sm" 5810 >25 Tubes</span> 5811 </div> 5812 </div><span class="custom-badge family one_time_saving_badge">Save 18%</span></div> 5813 </button> 5814 5815 5816 5817 5818 5819 </div> 5820 </variant-selector> 5821 <variant-selector> 5822 <div 5823 class="flex gap-2 justify-between bg-sand once_tube_container relative" 5824 data-flavor="Citrus" 5825 data-cadence="Once" 5826 > 5827 5828 5829 5830 5831 5832 5833 5834 5835 5836 5837 5838 5839 5840 5841 5842 5843 5844 5845 5846 5847 <button 5848 style="width: 100%;" 5849 type="button" 5850 data-variant-id="45594631471242" 5851 data-flavor="Citrus" 5852 data-price="1700" 5853 data-pack-size="Single Tube" 5854 data-compare-at-price="1700" 5855 class="variant-price-btn border-remove-btn w-full active " 5856 > 5857 <div 5858 style="" 5859 class="tube-category" 5860 > 5861 <div class="max"> 5862 <div> 5863 <span 5864 style="width: max-content; display: inline-block;" 5865 class="font-body-medium text-xs lg:text-sm" 5866 >Single Tube</span> 5867 </div> 5868 </div></div> 5869 </button> 5870 5871 5872 5873 5874 5875 5876 5877 5878 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 5894 5895 5896 5897 5898 5899 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 5929 5930 5931 5932 <button 5933 style="width: 100%;" 5934 type="button" 5935 data-variant-id="45594633666698" 5936 data-flavor="Citrus" 5937 data-price="4600" 5938 data-pack-size="3 Tubes" 5939 data-compare-at-price="5100" 5940 class="variant-price-btn border-remove-btn w-full " 5941 > 5942 <div 5943 style="" 5944 class="tube-category" 5945 > 5946 <div class="max"> 5947 <div> 5948 <span 5949 style="width: max-content; display: inline-block;" 5950 class="font-body-medium text-xs lg:text-sm" 5951 >3 Tubes</span> 5952 </div> 5953 </div><span class="custom-badge family one_time_saving_badge">Save 10%</span></div> 5954 </button> 5955 5956 5957 5958 5959 5960 5961 5962 5963 5964 5965 5966 5967 5968 5969 5970 5971 5972 5973 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 5997 5998 5999 6000 6001 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 6017 <button 6018 style="width: 100%;" 6019 type="button" 6020 data-variant-id="45594652901514" 6021 data-flavor="Citrus"
6022 data-price="7000" 6023 data-pack-size="5 Tubes" 6024 data-compare-at-price="8500" 6025 class="variant-price-btn border-remove-btn w-full " 6026 > 6027 <div 6028 style="" 6029 class="tube-category" 6030 > 6031 <div class="max"> 6032 <div> 6033 <span 6034 style="width: max-content; display: inline-block;" 6035 class="font-body-medium text-xs lg:text-sm" 6036 >5 Tubes</span> 6037 </div> 6038 </div><span class="custom-badge family one_time_saving_badge">Save 18%</span></div> 6039 </button> 6040 6041 6042 6043 6044 6045 6046 6047 6048 6049 6050 6051 6052 6053 6054 6055 6056 6057 6058 6059 6060 6061 6062 6063 6064 6065 6066 6067 6068 6069 6070 6071 6072 6073 6074 6075 6076 6077 6078 6079 6080 6081 6082 6083 6084 6085 6086 6087 6088 6089 6090 6091 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 <button 6103 style="width: 100%;" 6104 type="button" 6105 data-variant-id="45594657161354" 6106 data-flavor="Citrus" 6107 data-price="35000" 6108 data-pack-size="25 Tubes" 6109 data-compare-at-price="42500" 6110 class="variant-price-btn border-remove-btn w-full " 6111 > 6112 <div 6113 style="" 6114 class="tube-category" 6115 > 6116 <div class="max"> 6117 <div> 6118 <span 6119 style="width: max-content; display: inline-block;" 6120 class="font-body-medium text-xs lg:text-sm" 6121 >25 Tubes</span> 6122 </div> 6123 </div><span class="custom-badge family one_time_saving_badge">Save 18%</span></div> 6124 </button> 6125 6126 6127 6128 6129 6130 6131 6132 6133 6134 6135 </div> 6136 </variant-selector> 6137 </div> 6138 <div class=""> 6139 6140 6141 6142 6143 6144 6145 6146 <cart-add> 6147 <form class=""> 6148 <input type="hidden" name="id" value="45594633666698"> 6149 6150 6151 <input 6152 type="hidden" 6153 name="selling_plan" 6154 class="cart_selling_plan" 6155 value="2436038794" 6156 > 6157 <button class="!w-full main__atc__button button button--gold mt-6 "> 6158 <span style="display: none;" class="atc-price">4200</span> 6159 <span class="atc_btn"></span> 6160 <span class="px-1">â</span><span class="atc_text">Add to Bag</span> 6161 </button> 6162 </form> 6163 </cart-add> 6164 6165 </div> 6166 </form> 6167 </product-form> 6168 6169
6170<script> 6171 document.addEventListener('DOMContentLoaded', function () { 6172 const flavorButtons = document.querySelectorAll('[data-flavor]'); 6173 var clickBtn = document.querySelectorAll('.flavour-custom'); 6174 let pricegg = document.querySelector('.atc-price'); 6175 const oneTimeContainer = document.querySelector('.one_time_container'); 6176 const onceTubeContainer = document.querySelector('.once_tube_container'); 6177 const oneTimeRadio = document.querySelector('.one_time_radio'); 6178 const oneTimeBefore = document.querySelector('.one_time_before'); 6179 const oneTimePrice = document.querySelector('.one_time_price'); 6180 const oneTimeSavings = document.querySelector('.one_time_saving'); 6181 6182 let currentUrl = window.location.pathname.split('/'); 6183 6184 let CurrentLastPart = currentUrl[currentUrl.length - 1]; 6185 6186 let urlAfter = new URL(window.location.href); 6187 let searchParamsInitial = urlAfter.search; 6188 let SearchFlavorInitial = searchParamsInitial.includes('flavor=Mint') ? 'Mint' : 'Citrus'; 6189 6190 function simulateClick(element) { 6191 if (!element) return; 6192 try { 6193 const event = new MouseEvent('click', { 6194 bubbles: true, 6195 cancelable: true, 6196 view: window, 6197 }); 6198 element.dispatchEvent(event); 6199 } catch (e) { 6200 console.warn('Click simulation encountered an issue in a listener:', e); 6201 } 6202 } 6203 6204 function getActiveFlavor() { 6205 const activeBtn = document.querySelector('.flavour-custom.active'); 6206 return activeBtn ? activeBtn.dataset.flavor : null; 6207 } 6208 6209 function getActiveOnceVariantId() { 6210 let flavorUrl = window.location.pathname.split('/'); 6211 let currentFlavor = flavorUrl[flavorUrl.length - 1]; 6212 let truncateFlavor = currentFlavor === "Mint" || currentFlavor === "Citrus" ? currentFlavor : "Citrus"; 6213 6214 const activeFlavorBtn = getActiveFlavor(); 6215 const flavourValue = activeFlavorBtn ? activeFlavorBtn : truncateFlavor; 6216 6217 const subscriptionBox = document.querySelector(`div[data-cadence="Once"][data-flavor=${flavourValue}]`); 6218 6219 if (!subscriptionBox) { 6220 console.error('Subscription box not found'); 6221 return null; 6222 } 6223 6224 const activeButton = subscriptionBox.querySelector('button.active'); 6225 6226 if (!activeButton) { 6227 console.error('No active button found in subscription box'); 6228 return null; 6229 } 6230 6231 return activeButton.getAttribute('data-variant-id'); 6232 } 6233 6234 function getVariantOncePrice(variantId) { 6235 const variantsData = JSON.parse(document.getElementById('product-variants').textContent); 6236 6237 const filteredData = variantsData.filter((item) => parseInt(item.variantId) === parseInt(variantId)); 6238 6239 const oncePrice = filteredData?.[0]?.variantPrice; 6240 6241 return oncePrice; 6242 } 6243 6244 function isSubscribed() { 6245 const subscriptionBox = document.querySelector('div[data-cadence="Subscribe"]'); 6246 6247 if (!subscriptionBox) { 6248 console.error('Subscription box not found'); 6249 return null; 6250 } 6251 6252 const activeButton = subscriptionBox.querySelector('button.active'); 6253 6254 return activeButton ? true : false; 6255 } 6256 6257 function getActiveVidBySubs(value, flavor) { 6258 const isSubscribe = value ? 'Subscribe' : 'Once'; 6259 const subscriptionBox = document.querySelector(`div[data-cadence=${isSubscribe}][data-flavor="${flavor}"]`); 6260 6261 if (!subscriptionBox) { 6262 console.error('Subscription box not found'); 6263 return null; 6264 } 6265 6266 let activeButton; 6267 if (isSubscribe === 'Once') { 6268 // For "Once", check both active class and data-flavor attribute 6269 activeButton = subscriptionBox.querySelector(`button.active[data-flavor="${flavor}"]`); 6270 } else { 6271 // For "Subscribe", just check active class 6272 activeButton = subscriptionBox.querySelector('button.active'); 6273 } 6274 6275 if (!activeButton) { 6276 console.error('No active button found in subscription box with the required criteria'); 6277 return null; 6278 } 6279 6280 return activeButton.getAttribute('data-variant-id'); 6281 } 6282 6283 oneTimeContainer?.addEventListener( 6284 'click', 6285 function () { 6286 const targetFlavor = 'Citrus'; 6287 6288 const showBox = () => { 6289 const subsBox = document.querySelector(`.subscription-box[data-flavor="${targetFlavor}"]`); 6290 if (subsBox) { 6291 subsBox.classList.remove('hidden'); 6292 } else { 6293 console.log('Subscription box not found yet'); 6294 } 6295 }; 6296 6297 // Initial attempt 6298 showBox(); 6299 6300 // Observe DOM changes if it's being injected later 6301 const observer = new MutationObserver(() => { 6302 showBox(); 6303 }); 6304 6305 observer.observe(document.body, { childList: true, subtree: true }); 6306 }, 6307 { once: true } 6308 ); 6309 6310 let isSimulating = false;
6311 6312 function simulateClickTwo(element) { 6313 if (!element) return; 6314 if (isSimulating) return; 6315 isSimulating = true; 6316 6317 try { 6318 element.click(); // or dispatch custom event 6319 } catch (e) { 6320 console.warn('Click simulation two encountered an issue:', e); 6321 } 6322 6323 setTimeout(() => { 6324 isSimulating = false; 6325 }, 0); // reset after call stack clears 6326 } 6327 6328 oneTimeContainer?.addEventListener('click', () => { 6329 const vId = getActiveOnceVariantId(); 6330 const oneTimePrice = getVariantOncePrice(vId); 6331 const mintButton = document.querySelector('.flavour-custom[data-flavor="Mint"]'); 6332 const flavorInUrl = window.location.pathname; 6333 let actualFlavour = ''; 6334 6335 if (flavorInUrl.includes('Mint')) { 6336 actualFlavour = 'Mint'; 6337 } else if (flavorInUrl.includes('Citrus')) { 6338 actualFlavour = 'Citrus'; 6339 } 6340 6341 6342 6343 oneTimeContainer.style.borderWidth = '1px 1px 0px 1px'; 6344 oneTimeContainer.style.borderRadius = '10px 10px 0px 0px'; 6345 if (oneTimeRadio) { 6346 const oTimeDiv = oneTimeRadio.querySelector('div'); 6347 if (oTimeDiv) oTimeDiv.style.backgroundColor = '#5F471D'; 6348 } 6349 document.querySelectorAll('.variant-price-btn.remove_one_time.active').forEach((el) => { 6350 el.classList.remove('active'); 6351 }); 6352 const oneTimeButton = document.querySelector('.one_time_heading'); 6353 document.querySelector('.atc_text').textContent = 'Add to Bag'; 6354 6355 document.querySelector('.atc_btn').textContent = `${formatPrice(oneTimePrice)}`; 6356 6357 simulateClickTwo(oneTimeButton); 6358 6359 if(actualFlavour === "Mint" && mintButton){ 6360 mintButton.click(); 6361 } 6362 }); 6363 6364 function updateFlavorHandle(flavor) { 6365 const currentUrl = window.location.pathname; 6366 6367 6368 let newUrl; 6369 6370 if (currentUrl == '/') { 6371 const baseUrl = 'https://revitin.com'; 6372 //newUrl = `${baseUrl}/${flavor}`; 6373 newUrl = `${baseUrl}?flavor=${flavor}`; 6374 window.history.replaceState({}, '', newUrl); 6375 } else if (currentUrl == '?flavor=Citrus' || currentUrl == '?flavor=Mint') { 6376 const baseUrl = 'https://revitin.com'; 6377 newUrl = `${baseUrl}?flavor=${flavor}`; 6378 window.history.replaceState({}, '', newUrl); 6379 } else if (currentUrl == '?flavor=Citrus' || currentUrl == '?flavor=citrus') { 6380 const baseUrl = 'https://revitin.com'; 6381 newUrl = `${baseUrl}?flavor=${flavor}`; 6382 window.history.replaceState({}, '', newUrl); 6383 } else if (currentUrl == '?flavor=Mint' || currentUrl == '?flavor=mint') { 6384 const baseUrl = 'https://revitin.com'; 6385 newUrl = `${baseUrl}?flavor=${flavor}`; 6386 window.history.replaceState({}, '', newUrl); 6387 } else { 6388 const baseUrl = '/products/revitin-natural-toothpaste'; 6389 newUrl = `${baseUrl}/${flavor}`; 6390 window.history.replaceState({}, '', newUrl); 6391 } 6392 } 6393 6394 function setActiveFlavor(flavor) { 6395 // console.log('setActiveFlavor--->',flavor) 6396 clickBtn.forEach((button) => { 6397 // Remove active class from all buttons 6398 button.classList.remove('active'); 6399 // Remove background colors 6400 if (button.dataset.flavor === 'Citrus') { 6401 button.classList.remove('bg-gold', 'border-gold'); 6402 } else if (button.dataset.flavor === 'Mint') { 6403 button.classList.remove('bg-light-green', 'border-light-green'); 6404 } 6405 6406 // Add active class to selected flavor 6407 if (button.dataset.flavor === flavor) { 6408 button.classList.add('active'); 6409 // Add background color to selected button 6410 if (flavor === 'Citrus' || flavor === 'citrus') { 6411 button.classList.add('bg-gold', 'border-gold'); 6412 } else if (flavor === 'Mint' || flavor === 'mint') { 6413 button.classList.add('bg-light-green', 'border-light-green'); 6414 // pricegg = document.querySelector('.atc-price'); 6415 6416 // pricegg.classList.add('up'); 6417 } 6418 } 6419 }); 6420 6421 const galleryElements = document.querySelectorAll('[data-swap-flavor]'); 6422 6423 6424
6425 galleryElements.forEach((element) => { 6426 // Hide all galleries 6427 element.classList.add('opacity-0'); 6428 element.classList.remove('!opacity-100', 'z-10', 'relative'); 6429 element.classList.add('absolute', 'top-0', 'left-0', 'w-full', 'h-full'); 6430 6431 // Show only the gallery that matches the selected flavor 6432 if (element.dataset.swapFlavor === flavor) { 6433 element.classList.remove('opacity-0', 'absolute', 'top-0', 'left-0'); 6434 element.classList.add('!opacity-100', 'z-10', 'relative'); 6435 } 6436 }); 6437 6438 const variantSelectors = document.querySelectorAll('variant-selector > div'); 6439 6440 // Get the current cadence from the active cadence option 6441 const activeCadenceElement = document.querySelector('.cadence-option.active'); 6442 const currentCadence = activeCadenceElement ? activeCadenceElement.dataset.cadence : 'Once'; 6443 6444 variantSelectors.forEach((selector) => { 6445 // Get the selector's flavor and cadence without converting to lowercase 6446 const selectorFlavor = selector.dataset.flavor || ''; 6447 const selectorCadence = selector.dataset.cadence; 6448 6449 // Hide the selector by default 6450 selector.classList.add('hidden'); 6451 6452 // Show only the selector that matches both the selected flavor and current cadence 6453 // Use exact case matching 6454 if (selectorFlavor === flavor && selectorCadence === currentCadence) { 6455 selector.classList.remove('hidden'); 6456 } 6457 }); 6458 } 6459 6460 function getVariantDataBySubs(variantId, value) { 6461 const variantsData = JSON.parse(document.getElementById('product-variants').textContent); 6462 6463 const filteredData = variantsData.filter((item) => parseInt(item.variantId) === parseInt(variantId)); 6464 6465 const price = value ? filteredData?.[0]?.sellingPlans?.[0]?.price : filteredData?.[0]?.variantPrice; 6466 6467 return price; 6468 } 6469 6470 function getVariantData(variantId) { 6471 const variantsData = JSON.parse(document.getElementById('product-variants').textContent); 6472 6473 const filteredData = variantsData.filter((item) => parseInt(item.variantId) === parseInt(variantId)); 6474 6475 const subscribedPrice = filteredData?.[0]?.sellingPlans?.[0]?.price; 6476 6477 return subscribedPrice; 6478 } 6479 6480 function getActiveVariantDataByFlavor(flavor) { 6481 const container = document.querySelector(`.once_tube_container[data-flavor="${flavor}"]`); 6482 if (!container) return null; 6483 6484 const activeButton = container.querySelector('button.active'); 6485 if (!activeButton) return null; 6486 6487 return activeButton.dataset; 6488 } 6489 6490 const formatPrice = (price) => { 6491 const formatted = (price / 100).toFixed(2); 6492 return formatted.endsWith('.00') 6493 ? `$${parseInt(formatted)}` 6494 : `$${formatted}`; 6495 }; 6496 6497 const mutationObserverPrice = (price, classname) => { 6498 if (price) { 6499 const observer = new MutationObserver(() => { 6500 const selectElement = document.querySelector(classname); 6501 if (selectElement) { 6502 selectElement.textContent = price; 6503 observer.disconnect(); // Stop observing after found 6504 } 6505 }); 6506 observer.observe(document.body, { childList: true, subtree: true }); 6507 } 6508 }; 6509 6510 function setActiveSubscription(currentFlavor) { 6511 // Determine the target flavor (opposite of current) 6512 const targetFlavor = currentFlavor === 'Mint' ? 'Citrus' : 'Mint'; 6513 6514 // Find the subscription box for the target flavor 6515 const targetSubscriptionBox = document.querySelector(`.subscription-box[data-flavor="${targetFlavor}"]`); 6516 6517 // Check if any button is active in the target subscription box 6518 const activeButtonInTarget = targetSubscriptionBox.querySelector('.variant-price-btn.active'); 6519 6520 // If there's an active button in the target box, we need to activate the first button in current flavor's box 6521 if (activeButtonInTarget) { 6522 // Find the current flavor's subscription box 6523 const currentSubscriptionBox = document.querySelector(`.subscription-box[data-flavor="${currentFlavor}"]`); 6524 6525 // Find all buttons in current flavor's box 6526 const buttonsInCurrent = currentSubscriptionBox.querySelectorAll('.variant-price-btn'); 6527 6528 // Remove active class from all buttons in current flavor 6529 buttonsInCurrent.forEach((btn) => btn.classList.remove('active')); 6530 6531 // Add active class to first button in current flavor 6532 if (buttonsInCurrent.length > 0) { 6533 buttonsInCurrent[0].classList.add('active'); 6534 } 6535 } 6536 } 6537 6538 const calculateSavingPercentage = (compareAtPrice, price, inCents = true) => { 6539 // Convert strings to numbers 6540 let original = typeof compareAtPrice === 'string' ? parseFloat(compareAtPrice) : compareAtPrice; 6541 let discounted = typeof price === 'string' ? parseFloat(price) : price; 6542 6543 if (inCents) { 6544 original = original / 100; 6545 discounted = discounted / 100; 6546 } 6547 6548 if (isNaN(original) || isNaN(discounted) || original === 0) return '0%'; 6549 6550 // Calculate saving percentage and round 6551 const savingPercent = Math.round(((original - discounted) / original) * 100); 6552 6553 return `${savingPercent}%`; 6554 }; 6555
6556 clickBtn.forEach((button) => { 6557 button.addEventListener('click', function () { 6558 // console.log('click') 6559 pricegg.classList.remove('up'); 6560 const flavor = this.dataset.flavor; 6561 6562 setActiveSubscription(flavor); 6563 6564 const isSubscribe = isSubscribed(); 6565 6566 const activeVid = getActiveVidBySubs(isSubscribe, flavor); 6567 6568 const activeButtonPrice = getVariantDataBySubs(activeVid, isSubscribe); 6569 6570 document.querySelector('.atc_btn').textContent = `${formatPrice(activeButtonPrice)}`; 6571 6572 const activeOneTimeButtonData = getActiveVariantDataByFlavor(flavor); 6573 6574 if (activeOneTimeButtonData.price && activeOneTimeButtonData.compareAtPrice) { 6575 oneTimePrice.textContent = formatPrice(activeOneTimeButtonData.price); 6576 6577 const savingPercentage = calculateSavingPercentage(activeOneTimeButtonData?.compareAtPrice, activeOneTimeButtonData.price); 6578 6579 if (activeOneTimeButtonData.compareAtPrice) { 6580 oneTimeBefore.textContent = 6581 activeOneTimeButtonData?.compareAtPrice === activeOneTimeButtonData.price 6582 ? '' 6583 : formatPrice(activeOneTimeButtonData.compareAtPrice); 6584 oneTimeSavings.textContent = `Save ${savingPercentage}`; 6585 oneTimeBefore.style.display = 'inline'; 6586 6587 if(savingPercentage === "0%"){ 6588 oneTimeSavings.style.display = 'none'; 6589 }else{ 6590 oneTimeSavings.style.display = 'block'; 6591 } 6592 } else { 6593 oneTimeBefore.style.display = 'none'; 6594 oneTimeSavings.style.display = 'none'; 6595 } 6596 } 6597 6598 setActiveFlavor(flavor); 6599 updateFlavorHandle(flavor); 6600 }); 6601 }); 6602 6603 let subscribeButtonUp = document.querySelector('button[data-cadence="Subscribe"]'); 6604 let oneTimeButtonUp = document.querySelector('button[data-cadence="Once"]'); 6605 let variantSelectAllBtn = document.querySelectorAll('.variant-price-btn'); 6606 let oneTimeRemoveButton = document.querySelectorAll('.remove_one_time'); 6607 let oneTimeBorderemove = document.querySelectorAll('.border-remove-btn'); 6608 const oneTimeButtonHeading = document.querySelector('.one_time_heading'); 6609 6610 function udpateBorder() { 6611 if (onceTubeContainer && onceTubeContainer.classList.contains('hidden')) { 6612 oneTimeContainer.style.borderWidth = '1px 1px 1px 1px'; 6613 oneTimeContainer.style.borderRadius = '10px 10px 10px 10px'; 6614 } else { 6615 oneTimeContainer.style.borderWidth = '1px 1px 0px 1px'; 6616 oneTimeContainer.style.borderRadius = '10px 10px 0px 0px'; 6617 } 6618 } 6619 6620 subscribeButtonUp?.addEventListener('click', () => { 6621 pricegg.classList.remove('up'); 6622 // udpateBorder(); 6623 }); 6624 6625 oneTimeButtonUp?.addEventListener('click', () => { 6626 pricegg.classList.remove('up'); 6627 // udpateBorder(); 6628 }); 6629 6630 variantSelectAllBtn?.forEach((button) => { 6631 button.addEventListener('click', () => { 6632 pricegg.classList.remove('up'); 6633 udpateBorder(); 6634 }); 6635 }); 6636 6637 oneTimeRemoveButton?.forEach((button) => { 6638 button.addEventListener('click', () => { 6639 const activeVariantId = button?.dataset?.variantId; 6640 6641 subscribeButtonUp?.click(); 6642 if (oneTimeRadio) { 6643 const radioDiv = oneTimeRadio.querySelector('div'); 6644 if (radioDiv) radioDiv.style.backgroundColor = '#f7f7f700'; 6645 } 6646 const atcTextEl = document.querySelector('.atc_text'); 6647 if (atcTextEl) atcTextEl.textContent = 'Add to Bag'; 6648 if (oneTimeContainer) { 6649 oneTimeContainer.style.borderWidth = '1px 1px 1px 1px'; 6650 oneTimeContainer.style.borderRadius = '10px 10px 10px 10px'; 6651 } 6652 6653 if (activeVariantId) { 6654 const subscribePrice = getVariantData(activeVariantId); 6655 const atcBtnEl = document.querySelector('.atc_btn'); 6656 if (atcBtnEl) atcBtnEl.textContent = `${formatPrice(subscribePrice)}`; 6657 } 6658 // udpateBorder(); 6659 }); 6660 }); 6661 6662 function updateOneTimeHeaderFromButton(button) { 6663 if (!button || !oneTimePrice) return; 6664 6665 const data = button.dataset; 6666 6667 if (data.compareAtPrice) { 6668 const savingPercentage = calculateSavingPercentage(data?.compareAtPrice, data.price); 6669 6670 oneTimeBefore.textContent = data?.compareAtPrice === data.price ? '' : formatPrice(data.compareAtPrice); 6671 oneTimeSavings.textContent = `Save ${savingPercentage}`; 6672 oneTimeBefore.style.display = 'inline'; 6673 oneTimeSavings.style.display = savingPercentage === '0%' ? 'none' : 'block'; 6674 } else { 6675 oneTimeBefore.style.display = 'none'; 6676 oneTimeSavings.style.display = 'none'; 6677 } 6678 6679 oneTimePrice.textContent = formatPrice(data.price); 6680 } 6681 6682 oneTimeBorderemove.forEach((button) => { 6683 button.addEventListener('click', () => { 6684 updateOneTimeHeaderFromButton(button); 6685 document.querySelector('.atc_text').textContent = 'Add to Cart'; 6686 mutationObserverPrice(formatPrice(button.dataset.price), '.atc_btn'); 6687 6688 // Update container styling 6689 oneTimeContainer.style.borderWidth = '1px 1px 0px 1px'; 6690 oneTimeContainer.style.borderRadius = '10px 10px 0px 0px'; 6691 }); 6692 }); 6693 6694 if ( 6695 CurrentLastPart === 'Mint' || 6696 CurrentLastPart === 'mint' || 6697 SearchFlavorInitial === 'Mint' || 6698 SearchFlavorInitial === 'mint' 6699 ) { 6700 const sellId = document.querySelectorAll('input[name="id"]'); 6701 const variantsJsonMint = document.getElementById('product-variants').innerText; 6702 6703 this.variants = JSON.parse(variantsJsonMint); 6704 6705 let mintVariantId = (this.variantId = this.variants[1].variantId); 6706 6707 this.variantInput = this.querySelector('input[name="id"]'); 6708 this.variantInput.value = mintVariantId; 6709 //console.log('VariantInputMint',this.variantInput) 6710 } 6711 6712 if ( 6713 CurrentLastPart === 'Citrus' || 6714 CurrentLastPart === 'Mint' || 6715 CurrentLastPart === 'citrus' || 6716 CurrentLastPart === 'mint' 6717 ) { 6718 let formattedFlavor = CurrentLastPart.charAt(0).toUpperCase() + CurrentLastPart.slice(1).toLowerCase(); 6719 6720 if (CurrentLastPart === 'Mint' || CurrentLastPart === 'mint') { 6721 pricegg.classList.add('up'); 6722 }
6723 setActiveFlavor(formattedFlavor); 6724 } 6725 6726 // Check URL path on page load 6727 const pathParts = window.location.pathname.split('/'); 6728 //console.log("onPageLoad--->",pathParts) 6729 const lastPart = pathParts[pathParts.length - 1]; 6730 //console.log("onPageLoadLastPart--->",lastPart); 6731 6732 const url = new URL(window.location.href); 6733 6734 const searchParams = url.search; 6735 const SearchFlavor = searchParams.includes('flavor=Mint') ? 'Mint' : 'Citrus'; 6736 // console.log('SearchFlavor:',SearchFlavor); 6737 6738 if (lastPart === 'Citrus' || lastPart === 'Mint') { 6739 const flavor = lastPart.charAt(0) + lastPart.slice(1); 6740 //console.log("Flavor from URL:", flavor); 6741 setActiveFlavor(flavor); 6742 } else if (SearchFlavor === 'Mint' || SearchFlavor === 'Citrus') { 6743 setActiveFlavor(SearchFlavor); 6744 6745 if (SearchFlavor === 'Mint') { 6746 pricegg = document.querySelector('.atc-price'); 6747 6748 pricegg.classList.add('up'); 6749 } 6750 } 6751 6752 const firstButtonCitrus = oneTimeRemoveButton[0]; 6753 const firstButtonMint = oneTimeRemoveButton[Math.ceil(oneTimeRemoveButton.length / 2)]; 6754 6755 if (firstButtonCitrus) { 6756 6757 simulateClick(firstButtonCitrus); 6758 } 6759 6760 if (firstButtonMint) { 6761 6762 simulateClick(firstButtonMint); 6763 } 6764 6765 6766 6767 6768 6769 6770const isWholesaleCustomer = false; 6771 // Back-compat alias used below (was wrongly comparing full tags string to "wholesale") 6772 const customerTag = isWholesaleCustomer ? "wholesale" : ""; 6773 6774 const pageConfigs = [ 6775 { 6776 url: "revitin-natural-toothpaste-fullcase-25tubes", 6777 flavor: "Citrus", 6778 packSize: "25 Tubes", 6779 }, 6780 { 6781 url: "copy-of-revitin-toothpaste-25-tubes-gm", 6782 flavor: "Citrus", 6783 packSize: "25 Tubes", 6784 }, 6785 { 6786 url: "revitin-natural-toothpaste-family-pack-3tubes", 6787 flavor: "Citrus", 6788 packSize: "3 Tubes", 6789 }, 6790 { 6791 url: "revitin-toothpaste-5-tubes-mint", 6792 flavor: "Mint", 6793 packSize: "5 Tubes", 6794 }, 6795 { 6796 url: "revitin-toothpaste-5-tubes", 6797 flavor: "Citrus", 6798 packSize: "5 Tubes", 6799 }, 6800 { 6801 url: "revitin-toothpaste-3-tubes-mint", 6802 flavor: "Mint", 6803 packSize: "3 Tubes", 6804 }, 6805 { 6806 url: "revitin-toothpaste-25-tubes-mint", 6807 flavor: "Mint", 6808 packSize: "25 Tubes", 6809 }, 6810 { 6811 url: "revitin-toothpaste-single-tube-mint", 6812 flavor: "Mint", 6813 packSize: "Single Tube", 6814 }, 6815 // add more URLs as needed 6816 ]; 6817 6818 const urlFState = { 6819 product: getAllProducts(), 6820 } 6821 6822 function getAllProducts() { 6823 const allProductsElement = document.getElementById('all-products-json'); 6824 const productsData = allProductsElement ? JSON.parse(allProductsElement?.textContent) : []; 6825 return productsData; 6826 } 6827 6828 // Utility functions 6829 function removeActiveClass(flavor) { 6830 document 6831 .querySelectorAll(`.variant-price-btn.remove_one_time[data-flavor="${flavor}"]`) 6832 .forEach((el) => el.classList.remove("active")); 6833 } 6834 6835 function activateOneTimeSection(flavor) { 6836 const sections = document.querySelectorAll( 6837 `.once_tube_container[data-flavor="${flavor}"]` 6838 ); 6839 sections.forEach((btn) => btn.classList.remove("hidden")); 6840 6841 const oppositeFlavor = flavor === "Citrus" ? "Mint" : "Citrus"; 6842 const oppositeSection = document.querySelector( 6843 `.once_tube_container[data-flavor="${oppositeFlavor}"]` 6844 ); 6845 oppositeSection.classList.add("hidden"); 6846 } 6847 6848 function activateSubscribeSection(flavor) { 6849 const toggleSections = () => { 6850 const sections = document.querySelectorAll( 6851 `.subscription-box[data-flavor="${flavor}"]` 6852 ); 6853 sections.forEach((btn) => btn.classList.remove("hidden")); 6854 6855 const oppositeFlavor = flavor === "Citrus" ? "Mint" : "Citrus"; 6856 const oppositeSection = document.querySelector( 6857 `.subscription-box[data-flavor="${oppositeFlavor}"]` 6858 ); 6859 6860 if (oppositeSection) { 6861 oppositeSection.classList.add("hidden"); 6862 } else { 6863 console.log("Opposite section not found yet"); 6864 } 6865 }; 6866 6867 // Run immediately once 6868 toggleSections(); 6869 6870 // Observe for future DOM changes 6871 const observer = new MutationObserver(() => { 6872 toggleSections(); 6873 }); 6874 6875 observer.observe(document.body, { 6876 childList: true, 6877 subtree: true, 6878 }); 6879 } 6880 6881 function addActiveClass(flavor, packSize) { 6882 const buttons = document.querySelectorAll( 6883 `.variant-price-btn.border-remove-btn[data-flavor="${flavor}"]` 6884 ); 6885 buttons.forEach((btn) => btn.classList.remove("active")); 6886 6887 const activeButton = document.querySelector( 6888 `.variant-price-btn.border-remove-btn[data-flavor="${flavor}"][data-pack-size="${packSize}"]` 6889 ); 6890 6891 activateOneTimeSection(flavor); 6892 activateSubscribeSection(flavor); 6893 6894 if (activeButton) { 6895 activeButton.classList.add("active"); 6896 6897 // Get price data from the active button 6898 const price = activeButton.getAttribute('data-price'); 6899 const compareAtPrice = activeButton.getAttribute('data-compare-at-price'); 6900 const variantId = activeButton.getAttribute('data-variant-id'); 6901 const sellingPlanInput = document.querySelector('.cart_selling_plan'); 6902 6903 6904 if (sellingPlanInput) { 6905 const cartForm = sellingPlanInput.closest('cart-add'); 6906 if (cartForm) { 6907 const variantInput = cartForm.querySelector('input[name="id"]'); 6908 if (variantInput && variantId) { 6909 variantInput.value = variantId; 6910 } 6911 } 6912 } 6913 6914 // Convert prices from cents to dollars and remove .00 if no cents 6915 const formatPrice = (priceInCents) => { 6916 const dollars = priceInCents / 100; 6917 // Check if it's a whole number 6918 if (dollars % 1 === 0) { 6919 return dollars.toString(); // No decimal places 6920 } else { 6921 return dollars.toFixed(2); // Keep 2 decimal places 6922 } 6923 }; 6924 6925 const priceFormatted = formatPrice(price); 6926 const compareAtPriceFormatted = compareAtPrice ? formatPrice(compareAtPrice) : null; 6927 6928 // Update current price 6929 const currentPriceElement = document.querySelector('.one_time_price'); 6930 const atcButton = document.querySelector('.atc_btn'); 6931 if (currentPriceElement) { 6932 currentPriceElement.textContent = `$${priceFormatted}`; 6933 atcButton.textContent = `$${priceFormatted}`; 6934 } 6935 6936 // Update compare-at price (if exists) 6937 const comparePriceElement = document.querySelector('.one_time_before'); 6938 if (comparePriceElement && compareAtPriceFormatted) { 6939 comparePriceElement.textContent = `$${compareAtPriceFormatted}`; 6940 comparePriceElement.style.display = 'inline'; 6941 } else if (comparePriceElement) { 6942 comparePriceElement.style.display = 'none'; 6943 } 6944 6945 // Update savings badge if both prices exist 6946 const savingsElement = document.querySelector('.one_time_saving'); 6947 if (savingsElement && compareAtPrice && price && compareAtPrice > price) { 6948 const savingsAmount = ((1 - price / compareAtPrice) * 100).toFixed(0); 6949 savingsElement.textContent = `Save ${savingsAmount}%`; 6950 savingsElement.style.display = 'block'; 6951 } else if (savingsElement) { 6952 savingsElement.style.display = 'none'; 6953 } 6954 } 6955 6956 console.log("activeButton", activeButton); 6957 } 6958 6959 function updateFlavorButtonUi(flavor){
6960 const flavorBtn = isWholesaleCustomer ? ".whole_flavor_btn" : ".flavour-custom"; 6961 6962 const oneTimeSavingBadge = document.querySelectorAll( 6963 `.variant-price-btn.border-remove-btn[data-flavor="${flavor}"] .one_time_saving_badge` 6964 ); 6965 const mainFlavorBtn = document.querySelectorAll(flavorBtn); 6966 const oneTimeSavingHeader = document.querySelector( 6967 `.one_time_saving` 6968 ); 6969 const mainAtcBtn = document.querySelector( 6970 `.main__atc__button` 6971 ); 6972 const currentFlavorBtn = document.querySelector( 6973 `${flavorBtn}[data-flavor="${flavor}"]` 6974 ); 6975 const oppositeFlavor = flavor === "Citrus" ? "Mint" : "Citrus"; 6976 const oppositeFlavorBtn = document.querySelector( 6977 `${flavorBtn}[data-flavor="${oppositeFlavor}"]` 6978 ); 6979 6980 mainFlavorBtn?.forEach((btn) => { 6981 btn.classList.remove("active"); 6982 btn.style.background = ""; 6983 btn.style.borderColor = ""; 6984 }); 6985 currentFlavorBtn?.classList.add("active"); 6986 oppositeFlavorBtn?.classList.remove("bg-gold"); 6987 oneTimeSavingBadge?.forEach((btn) => { 6988 btn.style.backgroundColor = flavor === "Mint" ? "#e6ecd3": "#FFDEA3"; 6989 }); 6990 oneTimeSavingHeader ? oneTimeSavingHeader.style.backgroundColor = flavor === "Mint" ? "#e6ecd3": "#FFDEA3" : null; 6991 mainAtcBtn ? mainAtcBtn.style.backgroundColor = flavor === "Mint" ? "#e6ecd3": "#FFDEA3" : null; 6992 } 6993 6994 function updateBannerImages(flavor) { 6995 const singleTubes = urlFState?.product.filter(p => p?.title.includes("Single")); 6996 const activeFlavour = singleTubes?.find(p => p?.variants?.[0]?.title === flavor); 6997 const activeFlavourImages = activeFlavour?.images; 6998 6999 const containers = [ 7000 document.querySelector(`.image_update_container div[data-swap-flavor="${flavor}"]`), 7001 document.querySelector(`.pdp_slider_container div[data-swap-flavor="${flavor}"]`), 7002 document.querySelector(`.pdp_banner_container img[data-swap-flavor="${flavor}"]`), 7003 ]; 7004 7005 document.querySelectorAll("[data-swap-flavor]").forEach(el => { 7006 el?.classList.add("opacity-0"); 7007 el?.classList.remove("!opacity-100", "z-10"); 7008 }); 7009 7010 containers.forEach(el => { 7011 if (!el) return; 7012 el?.classList.remove("opacity-0"); 7013 el?.classList.add("!opacity-100", "z-10"); 7014 }); 7015 7016 } 7017 7018 // Main logic 7019 const currentPath = window.location.pathname; 7020 const matchedConfig = pageConfigs.find((cfg) => currentPath.includes(cfg.url)); 7021 7022 if(isWholesaleCustomer && currentPath.includes("revitin-toothpaste-25-tubes-wholesale-mint")) { 7023 document.querySelectorAll(".wholesale_item").forEach((el) => el.classList.add("hidden")); 7024 7025 const mintProduct = document.querySelector(".wholesale_item[data-wholesale-flavor='Mint']"); 7026 if (mintProduct) mintProduct.classList.remove("hidden"); 7027 7028 updateFlavorButtonUi("Mint"); 7029 updateBannerImages("Mint"); 7030 } 7031 7032 if (matchedConfig) { 7033 const { flavor, packSize } = matchedConfig; 7034 7035 removeActiveClass(flavor); 7036 updateFlavorButtonUi(flavor); 7037 updateBannerImages(flavor); 7038 7039 // simulate click if needed (wrapped in a safe check) 7040 if (typeof simulateClickTwo === "function" && oneTimeButtonHeading) { 7041 simulateClickTwo(oneTimeButtonHeading); 7042 } 7043 7044 addActiveClass(flavor, packSize); 7045 }; 7046 7047 }); 7048</script>
7048 7049
7050<script> 7051 const flavorButtons = document.querySelectorAll('.flavour-custom'); 7052 const subscriptionBoxes = document.querySelectorAll('.subscription-box'); 7053 7054 const productPaths = [ 7055 "revitin-natural-toothpaste-fullcase-25tubes", 7056 "revitin-natural-toothpaste-family-pack-3tubes", 7057 "revitin-toothpaste-5-tubes", 7058 "copy-of-revitin-toothpaste-25-tubes-gm", 7059 "revitin-toothpaste-3-tubes-mint", 7060 "revitin-toothpaste-25-tubes-mint", 7061 "revitin-toothpaste-single-tube-mint" 7062 ]; 7063 7064 if (!productPaths.some(path => window.location.pathname.includes(path))) { 7065 flavorButtons.forEach((button) => { 7066 button.addEventListener('click', () => { 7067 // Remove 'active' class from all buttons 7068 7069 flavorButtons.forEach((btn) => btn.classList.remove('active')); 7070 7071 // Add 'active' class to the clicked one 7072 button.classList.add('active'); 7073 7074 // Get active flavor 7075 const activeFlavor = button.getAttribute('data-flavor'); 7076 7077 // Show matching subscription box, hide others 7078 subscriptionBoxes.forEach((box) => { 7079 const boxFlavor = box.getAttribute('data-flavor'); 7080 if (boxFlavor === activeFlavor) { 7081 box.style.setProperty('display', 'block', 'important'); 7082 } else { 7083 box.style.setProperty('display', 'none', 'important'); 7084 } 7085 }); 7086 7087 if (activeFlavor === 'Mint') { 7088 document 7089 .querySelectorAll('.save__amount') 7090 .forEach((el) => el.style.setProperty('background-color', '#E6ECD3', 'important')); 7091 document 7092 .querySelectorAll('.one_time_saving_badge') 7093 .forEach((el) => el.style.setProperty('background-color', '#E6ECD3', 'important')); 7094 document.querySelector('.main__atc__button').style.setProperty('background-color', '#E6ECD3', 'important'); 7095 } 7096 7097 if (activeFlavor === 'Citrus') { 7098 document 7099 .querySelectorAll('.save__amount') 7100 .forEach((el) => el.style.setProperty('background-color', '#FFDEA3', 'important')); 7101 document 7102 .querySelectorAll('.one_time_saving_badge') 7103 .forEach((el) => el.style.setProperty('background-color', '#FFDEA3', 'important')); 7104 document.querySelector('.main__atc__button').style.setProperty('background-color', '#FFDEA3', 'important'); 7105 } 7106 }); 7107 }); 7108 7109 document.addEventListener('DOMContentLoaded', function () { 7110 function getAllProducts() { 7111 const productsData = JSON.parse(document.getElementById('product-variants').textContent); 7112 return productsData; 7113 } 7114 7115 function getActiveFlavor() { 7116 const activeBtn = document.querySelector('.flavour-custom.active'); 7117 return activeBtn ? activeBtn.dataset.flavor : null; 7118 } 7119 7120 const activeFlavor = getActiveFlavor(); 7121 const flavorVal = activeFlavor ? activeFlavor : "Citrus"; 7122 7123 function activateSecondButton() { 7124 const subscriptionBoxes = document.querySelectorAll(`.subscription-box[data-flavor=${flavorVal}]`); 7125 7126 subscriptionBoxes.forEach((box) => { 7127 const buttons = box.querySelectorAll('.variant-price-btn'); 7128 7129 if (buttons.length >= 2) { 7130 const productsData = getAllProducts(); 7131 const urlFlavor = window.location.pathname.split("/").filter(Boolean).pop(); 7132 const actualFlavour = flavorVal; 7133 const secondProduct = productsData?.filter( 7134 (item) => item.productTitle.includes('3 Tubes') && item.variantTitle === actualFlavour 7135 )?.[0]; 7136 const secondVid = secondProduct?.variantId; 7137 const thirdMonthSpId = secondProduct?.sellingPlans?.[2]?.id; 7138 7139 7140 7141 // Wait a bit to ensure cart-add elements are rendered 7142 setTimeout(() => { 7143 const cartAddElements = document.querySelectorAll('cart-add'); 7144 7145 cartAddElements.forEach(cartAddElement => { 7146 const variantIdElem = cartAddElement.querySelector('input[name="id"]'); 7147 const sellingPlanIdElem = cartAddElement.querySelector('input[name="selling_plan"]'); 7148 const cartSellingPlanElem = cartAddElement.querySelector('.cart_selling_plan'); 7149 7150 if (variantIdElem && secondVid) { 7151 variantIdElem.value = secondVid; 7152 } 7153 7154 if (thirdMonthSpId) { 7155 // Set all selling plan inputs 7156 if (sellingPlanIdElem) { 7157 sellingPlanIdElem.value = thirdMonthSpId; 7158 } 7159 if (cartSellingPlanElem) { 7160 cartSellingPlanElem.value = thirdMonthSpId; 7161 } 7162
7163 // Also try to set any other selling plan inputs 7164 document.querySelectorAll('input[name="selling_plan"]').forEach(input => { 7165 input.value = thirdMonthSpId; 7166 }); 7167 document.querySelectorAll('.cart_selling_plan').forEach(input => { 7168 input.value = thirdMonthSpId; 7169 }); 7170 } 7171 }); 7172 }, 100); 7173 7174 // Update button states 7175 buttons.forEach((btn) => btn.classList.remove('active')); 7176 buttons[0].classList.add('active'); 7177 } 7178 }); 7179 } 7180 7181 // More robust observer with retry mechanism 7182 const observer = new MutationObserver(function (mutations, obs) { 7183 const citrusBoxes = document.querySelectorAll(`.subscription-box[data-flavor=${flavorVal}]`); 7184 if (citrusBoxes.length > 0) { 7185 // Try multiple times with delays to ensure elements are ready 7186 setTimeout(activateSecondButton, 100); 7187 setTimeout(activateSecondButton, 500); 7188 obs.disconnect(); 7189 } 7190 }); 7191 7192 observer.observe(document.body, { 7193 childList: true, 7194 subtree: true, 7195 }); 7196 7197 // Initial attempts with delays 7198 setTimeout(activateSecondButton, 100); 7199 setTimeout(activateSecondButton, 500); 7200 setTimeout(activateSecondButton, 1000); 7201 }); 7202 } 7203</script>
7203 7204 7205<style> 7206 .one_time_saving { 7207 font-size: 11px; 7208 padding: 1px 12px !important; 7209 transform: translate(-13px, -3px); 7210 } 7211 7212 .subscription-box:has(.variant-price-btn.active) { 7213 background-color: #f7eede; 7214 } 7215 7216 .one_time_container:has(.one_time_radio > div[style*='rgba(247, 247, 247, 0)']) { 7217 background-color: #0b070700; 7218 } 7219 7220 .one_time_container:has(.one_time_radio > div[style*='rgba(247, 247, 247, 0)']) .one_time_heading { 7221 background-color: #ff000000 !important; 7222 } 7223 7224 .border-radius-2 { 7225 border-radius: 4px; 7226 } 7227 7228 .variant-price-btn.active div { 7229 font-weight: bold; 7230 font-size: 14px; 7231 z-index: 39; 7232 } 7233 7234 .variant-price-btn { 7235 position: relative; 7236 } 7237 7238 .custom-badge { 7239 position: absolute; 7240 top: 1.6rem; 7241 left: 50%; 7242 transform: translateX(-50%); 7243 background-color: #ffdea3; 7244 padding: 5px 10px; 7245 font-size: 12px; 7246 border-radius: 11px; 7247 z-index: 10; 7248 width: max-content; 7249 height: max-content; 7250 line-height: 1; 7251 font-weight: normal !important; 7252 } 7253 7254 .one_time_heading { 7255 font-size: 18px; 7256 font-weight: bold; 7257 } 7258 7259 .once_tube_container { 7260 border-radius: 0px 0px 10px 10px; 7261 border-width: 0px 1px 1px 1px; 7262 border-style: solid; 7263 border-color: black; 7264 padding: 0rem 0.5rem 1rem 0.5rem; 7265 } 7266 7267 .one_time_container { 7268 border-radius: 10px 10px 0px 0px; 7269 border-width: 1px 1px 0px 1px; 7270 border-style: solid; 7271 border-color: black; 7272 margin-top: 10px; 7273 } 7274 7275 .subscription-box { 7276 border: 1px solid #5f471d; 7277 border-radius: 14px; 7278 margin-top: 2.1rem; 7279 padding: 12px 18px 0px 12px; 7280 background: rgba(247, 238, 222, 0); 7281 } 7282 7283 .subscription-box.active { 7284 display: block !important; 7285 } 7286 7287 .save_20 { 7288 font-weight: bold; 7289 font-size: 18px; 7290 margin-bottom: 7px; 7291 } 7292 7293 .benifit_text { 7294 font-size: 14px; 7295 line-height: 1; 7296 padding: 5.1px 0px; 7297 } 7298 7299 .month-frequency { 7300 font-size: 14px !important; 7301 font-weight: normal !important; 7302 transform: translateY(8px); 7303 } 7304 7305 .border-sand { 7306 border-color: #5f471d; 7307 } 7308 7309 .tube-category { 7310 border: 1px solid #80808052; 7311 background: #fffbef; 7312 padding: 4px 20px; 7313 border-radius: 4px; 7314 position: relative; 7315 } 7316 7317 .variant-price-btn.temp.active div { 7318 border-color: #5f471d; 7319 } 7320 7321 .frequency-select { 7322 position: absolute; 7323 transform: translateX(-29px); 7324 opacity: 0; 7325 } 7326 7327 .frequency-selector { 7328 position: relative; 7329 } 7330 7331 .frequency-label { 7332 display: block; 7333 margin-bottom: 10px; 7334 font-weight: bold; 7335 font-weight: normal; 7336 } 7337 7338 .font-italic { 7339 font-style: italic; 7340 font-size: 12px; 7341 } 7342 7343 .frequency-options { 7344 display: flex; 7345 flex-direction: column; 7346 gap: 8px; 7347 } 7348 7349 .frequency-option { 7350 display: flex; 7351 align-items: center; 7352 } 7353 7354 .frequency-radio { 7355 appearance: none; 7356 -webkit-appearance: none; 7357 width: 18px; 7358 height: 18px; 7359 border: 1px solid #ccc; 7360 border-radius: 50%; 7361 margin-right: 10px; 7362 position: relative; 7363 cursor: pointer; 7364 } 7365 7366 .frequency-radio:checked { 7367 border-color: #000; 7368 } 7369 7370 .frequency-radio:checked::after { 7371 content: ''; 7372 position: absolute; 7373 top: 3px; 7374 left: 3px; 7375 width: 10px; 7376 height: 10px; 7377 background: #000; 7378 border-radius: 50%; 7379 } 7380 7381 .frequency-option label { 7382 cursor: pointer; 7383 } 7384 7385 .frequency-dropdown-container { 7386 background: #fffbef; 7387 width: max-content; 7388 height: max-content; 7389 position: absolute; 7390 top: 0; 7391 left: 0; 7392 z-index: 1000; 7393 display: none; 7394 border-radius: 9px; 7395 padding: 5px 10px; 7396 } 7397 7398 .select_quantity { 7399 position: absolute; 7400 top: -5px; 7401 left: 50%; 7402 transform: translateX(-50%); 7403 font-size: 14px; 7404 font-weight: bold; 7405 } 7406 7407 .variant-price-btn.active.border-remove-btn { 7408 border: 1px solid #5f471d; 7409 border-radius: 5px; 7410 } 7411 7412 .save__amount { 7413 position: absolute; 7414 top: 1.7rem; 7415 right: 0px; 7416 width: max-content; 7417 background: #ffdea3; 7418 padding: 3px 11px; 7419 border-radius: 11px; 7420 } 7421 7422 .save__amount p { 7423 font-size: 12px !important; 7424 font-weight: normal !important; 7425 } 7426 7427 .subscriptions_selection { 7428 padding: 18px 0px; 7429 } 7430 .most-popular-pill { 7431 width: max-content; 7432 padding: 7px 15px; 7433 border-radius: 20px; 7434 color: #fff; 7435 font-size: 12px; 7436 line-height: 1; 7437 font-weight: normal !important; 7438 white-space: nowrap; 7439 } 7440 .subscription_original { 7441 font-size: 18px; 7442 } 7443 7444 .remove_one_time:not(.active) .subscriptions_selection { 7445 padding: 14px 0px 17px 0px; 7446 } 7447 7448 flavor-selector button[data-flavor='Citrus'].active { 7449 border-color: #ffbb42 !important; 7450 border-width: 2px; 7451 } 7452 7453 flavor-selector button[data-flavor='Mint'].active { 7454 border-color: #9ca975 !important; 7455 border-width: 2px; 7456 } 7457 7458 .remove_one_time.variant-price-btn:not(.active) .month-frequency { 7459 pointer-events: none; 7460 opacity: 0.5; /* Optional */ 7461 } 7462 7463 .main__atc__button { 7464 border-radius: 25px; 7465 } 7466 7467 #variety-add-to-cart { 7468 border-radius: 25px; 7469 background: linear-gradient(to right, #ffdea3, #ffdea3, #e6ecd3, #e6ecd3) !important; 7470 } 7471 7472 .variety_tab_btn { 7473 background: #f5eee0; 7474 border-radius: 25px; 7475 padding: 2px 4px; 7476 } 7477 7478 .variety_tab_btn img { 7479 max-width: 2.5rem; 7480 } 7481 7482 button[data-flavor='Mint'] .save__amount { 7483 background-color: rgb(230, 236, 211) !important; 7484 } 7485 7486 button[data-flavor='Citrus'] .save__amount { 7487 background-color: rgb(255, 222, 163) !important; 7488 } 7489 button[data-flavor='Mint'] .most-popular-pill { 7490 background-color: #8A9D7C; 7491 } 7492 7493 button[data-flavor='Citrus'] .most-popular-pill { 7494 background-color: #FBAA4A; 7495 } 7496 product-form:has(.flavour-custom[data-flavor='Mint'].active) .main__atc__button { 7497 background-color: #e6ecd3 !important; 7498 } 7499 7500 @media (max-width: 767px) { 7501 .one_time_heading { 7502 font-size: 14px; 7503 } 7504 7505 .once_tube_container { 7506 padding: 0.5rem 0.5rem 1.5rem 0.5rem; 7507 } 7508 7509 .custom-badge { 7510 top: 1.6rem; 7511 font-size: 11px; 7512 } 7513 7514 .product-form-container { 7515 max-width: 380px; 7516 } 7517 7518 .tube-category { 7519 padding: 4px 8px; 7520 } 7521 .most-popular-pill { 7522 padding: 5px 9px; 7523 border-radius: 14px; 7524 font-size: 10px; 7525 line-height: 1; 7526 transform: translateY(-1px); 7527 } 7528 } 7529</style> 7530 7531 </div> 7532 7533 <div class="travel__size__container" style="display:none;"> 7534 7535 <div class="ts-flavor-toggle"> 7536 <button 7537 type="button" 7538 data-flavor="Citrus"
7539 class="flex items-center gap-3 text-brown rounded-[50px] py-2 pl-2 pr-3 lg:pr-6 lg:hover:bg-gold lg:hover:border-gold transition-colors duration-300 ts-flavor-btn ts-citrus" 7540 > 7541 <div class="relative w-8 h-8 bg-gold rounded-full flex items-center justify-center p-0.5"> 7542 <img class="rounded-full" src="//revitin.com/cdn/shop/t/129/assets/citrus-teaser.png?v=69425243372235278621777542405" loading="lazy"> 7543 </div> 7544 <div class="font-body-medium text-sm lg:text-lg">Citrus</div> 7545 </button> 7546 <button 7547 type="button" 7548 data-flavor="Mint" 7549 class="flex items-center gap-3 text-brown rounded-[50px] py-2 pl-2 pr-3 lg:pr-6 lg:hover:bg-light-green lg:hover:border-light-green transition-colors duration-300 ts-flavor-btn ts-mint" 7550 > 7551 <div class="relative w-8 h-8 bg-light-green rounded-full flex items-center justify-center p-0.5"> 7552 <img class="rounded-full" src="//revitin.com/cdn/shop/t/129/assets/mint-teaser.png?v=43172182657372155721777542403" loading="lazy"> 7553 </div> 7554 <div class="font-body-medium text-sm lg:text-lg">Mint</div> 7555 </button> 7556 <button 7557 type="button" 7558 data-flavor="Variety" 7559 style="border: 1px solid #C6C6C6;" 7560 class="flex items-center variety-selector-btn gap-1 text-brown rounded-[50px] py-2 pl-1 pr-3 lg:pr-6 lg:hover:bg-light-green lg:hover:border-light-green transition-colors duration-300 ts-flavor-btn ts-variety" 7561 > 7562 <div class="relative flex items-center justify-center ts_variety_tab_btn"> 7563 <img class="" src="//revitin.com/cdn/shop/t/129/assets/mix-match.png?v=98254657463874453371777542404" loading="lazy"> 7564 </div> 7565 <div class="font-body-medium text-sm lg:text-lg">Variety</div> 7566 </button> 7567 </div> 7568 7569 <div class="ts-pack-options"> 7570 <div> 7571 <label class="flex gap-2"> 7572 <input class="travel_size_checkbox" type="radio" name="ts-pack" value="1" checked> 7573 <span class="ts-option-label font-body-medium">Citrus 3-pack</span> 7574 </label> 7575 <span class="ts-option-price font-body-medium">$16</span> 7576 </div> 7577 </div> 7578 7579 <button class="ts-add-to-bag-btn ts-citrus-btn font-body-medium">$16 â Add to Bag</button> 7580 7581 </div> 7582 </div> 7583 7584 <div class="main-product__disclaimer text-brown text-center mt-4"> 7585 <p class="text-xs">30-Day Money Back Guarantee</p> 7586 7587 </div> 7588 7589 7590 </div> 7591 </div> 7592</div> 7593
7594<script> 7595 document.addEventListener('DOMContentLoaded', function () { 7596 function roundToOneDecimal() { 7597 const ratingEl = document.querySelector('.jdgm-rev-widg__summary-average'); 7598 7599 if (ratingEl) { 7600 const text = ratingEl.textContent.trim(); 7601 const value = parseFloat(text); 7602 7603 if (!isNaN(value)) { 7604 ratingEl.textContent = value.toFixed(1); // Round to 1 decimal place 7605 } else { 7606 setTimeout(roundToOneDecimal, 300); // Retry if text isn't a number yet 7607 } 7608 } else { 7609 setTimeout(roundToOneDecimal, 300); // Retry if element not loaded yet 7610 } 7611 } 7612 7613 roundToOneDecimal(); 7614 }); 7615</script>
7615 7616
7617<script> 7618 document.addEventListener("DOMContentLoaded", () => { 7619 const flavourWrapper = document.querySelector(".flavour__selector"); 7620 if (!flavourWrapper) return; 7621 7622 flavourWrapper.addEventListener("click", (e) => { 7623 if (!e.target || typeof e.target.closest !== 'function') return; 7624 const button = e.target.closest("button"); 7625 7626 if (!button || !flavourWrapper.contains(button)) { 7627 e.stopPropagation(); 7628 return; 7629 } 7630 }); 7631 }); 7632</script>
7632 7633
7634<script> 7635 document.addEventListener('DOMContentLoaded', () => { 7636 const boxes = document.querySelectorAll('.subscription-box'); 7637 if (!boxes.length) return; 7638 7639 // Get the size selection container 7640 const sizeContainer = document.querySelector('.selection_btn_container'); 7641 // Get the flavor selector container 7642 const flavorSelector = document.querySelector('.flavour__selector'); 7643 7644 boxes.forEach((box, index) => { 7645 let lastState = null; 7646 let debounceTimer = null; 7647 7648 const getState = () => { 7649 // 1. Check subscription state (within subscription-box) 7650 const isSubscribed = box.querySelector('.variant-price-btn.remove_one_time.active') ? 'subscribed' : 'one-time'; 7651 7652 // 2. Check size selection (travel-size or full-size) 7653 const isTravelSize = sizeContainer && sizeContainer.querySelector('.travel-size-btn.active') ? 'travel-size' : 'full-size'; 7654 7655 // 3. Check if variety pack is selected 7656 const isVarietySelected = flavorSelector && flavorSelector.querySelector('[data-flavor="Variety"].active') ? 'variety' : 'single-flavor'; 7657 7658 // 4. Check if subscribe box is active in variety container 7659 const varietySubscribeBox = document.querySelector('#variety-subscribeBox'); 7660 const isVarietySubscribeActive = varietySubscribeBox && varietySubscribeBox.classList.contains('variety-active') ? 'variety-subscribed' : 'variety-one-time'; 7661 7662 // 5. Check if one-time box is active in variety container 7663 const varietyOneTimeBox = document.querySelector('#variety-oneTimeBox'); 7664 const isVarietyOneTimeActive = varietyOneTimeBox && varietyOneTimeBox.classList.contains('variety-active') ? 'one-time-active' : 'subscribe-active'; 7665 7666 return { isSubscribed, isTravelSize, isVarietySelected, isVarietySubscribeActive, isVarietyOneTimeActive }; 7667 }; 7668 7669 const logFinalState = () => { 7670 const currentState = getState(); 7671 const stateString = `${currentState.isSubscribed}-${currentState.isTravelSize}-${currentState.isVarietySelected}-${currentState.isVarietySubscribeActive}-${currentState.isVarietyOneTimeActive}`; 7672 if (stateString === lastState) return; 7673 7674 const rightImages = document.querySelectorAll('.right_variety_image'); 7675 const toteImages = document.querySelectorAll('.tote_bag_image'); 7676 const rightMobileImages = document.querySelectorAll('.mobile_right_variety_image'); 7677 const toteMobileImages = document.querySelectorAll('.tote_bag_image_mobile'); 7678 7679 // Show tote images when ALL conditions are met: 7680 // 1. User is subscribed (either regular OR variety) 7681 // 2. Full-size is selected (NOT travel-size) 7682 // 3. If variety pack: variety is selected AND variety subscribe is active 7683 // 4. NOT when variety pack is selected but one-time purchase is active 7684 7685 let showTote = false; 7686 7687 7688 7689 if (showTote) { 7690 rightImages.forEach((img) => (img.style.display = 'none')); 7691 toteImages.forEach((img) => (img.style.display = 'block')); 7692 rightMobileImages.forEach((img) => (img.style.display = 'none')); 7693 toteMobileImages.forEach((img) => (img.style.display = 'block')); 7694 } else { 7695 rightImages.forEach((img) => (img.style.display = 'block')); 7696 toteImages.forEach((img) => (img.style.display = 'none')); 7697 rightMobileImages.forEach((img) => (img.style.display = 'block')); 7698 toteMobileImages.forEach((img) => (img.style.display = 'none')); 7699 } 7700 7701 lastState = stateString; 7702 }; 7703 7704 const debounceLog = () => { 7705 clearTimeout(debounceTimer); 7706 debounceTimer = setTimeout(logFinalState, 50); 7707 }; 7708 7709 // Initial check 7710 debounceLog(); 7711 7712 // Listen to subscription box clicks 7713 box.addEventListener('click', (e) => { 7714 if (e.target && typeof e.target.closest === 'function' && e.target.closest('.variant-price-btn.remove_one_time')) { 7715 debounceLog(); 7716 } 7717 }); 7718 7719 // Listen to size button clicks if container exists 7720 if (sizeContainer) { 7721 sizeContainer.addEventListener('click', (e) => { 7722 if (e.target && typeof e.target.closest === 'function' && e.target.closest('.size_selection_btn')) { 7723 debounceLog(); 7724 } 7725 }); 7726 7727 // Observe size container for class changes 7728 const sizeObserver = new MutationObserver(debounceLog); 7729 sizeObserver.observe(sizeContainer, { 7730 attributes: true, 7731 subtree: true, 7732 attributeFilter: ['class'], 7733 }); 7734 } 7735 7736 // Listen to flavor selector clicks 7737 if (flavorSelector) { 7738 flavorSelector.addEventListener('click', (e) => { 7739 if (e.target && typeof e.target.closest === 'function' && (e.target.closest('.flavour-custom') || e.target.closest('.variety-selector-btn'))) { 7740 debounceLog(); 7741 } 7742 }); 7743 7744 // Observe flavor selector for class changes 7745 const flavorObserver = new MutationObserver(debounceLog); 7746 flavorObserver.observe(flavorSelector, { 7747 attributes: true, 7748 subtree: true, 7749 attributeFilter: ['class'], 7750 }); 7751 } 7752 7753 // Listen to variety container changes 7754 const varietyContainer = document.querySelector('.variety-selection-container'); 7755 if (varietyContainer) { 7756 varietyContainer.addEventListener('click', (e) => { 7757 if (e.target && typeof e.target.closest === 'function' && (e.target.closest('.variety-radio-input') || e.target.closest('.variety-box'))) { 7758 debounceLog(); 7759 } 7760 }); 7761 7762 // Observe variety container for changes 7763 const varietyObserver = new MutationObserver(debounceLog); 7764 varietyObserver.observe(varietyContainer, { 7765 attributes: true, 7766 subtree: true, 7767 attributeFilter: ['class'], 7768 }); 7769 } 7770 7771 // Observe subscription box for changes 7772 const observer = new MutationObserver(debounceLog); 7773 observer.observe(box, { 7774 attributes: true, 7775 subtree: true, 7776 attributeFilter: ['class'], 7777 }); 7778 }); 7779 }); 7780</script>
7780 7781
7782<script> 7783 class OuraStyleSlider { 7784 constructor(container) { 7785 this.container = container; 7786 this.slides = container.querySelectorAll('.slide'); 7787 this.dots = container.querySelectorAll('.progress-slider-dot'); 7788 this.currentIndex = 0; 7789 this.totalSlides = this.slides.length; 7790 this.progressDuration = 5000; // 5 seconds 7791 this.progressStartTime = null; 7792 this.animationFrame = null; 7793 this.isAnimating = false; 7794 7795 this.init(); 7796 } 7797 7798 init() { 7799 // Initialize first slide 7800 this.updateSlides(); 7801 7802 // Setup event listeners for dots 7803 this.dots.forEach(dot => { 7804 dot.addEventListener('click', (e) => { 7805 const index = parseInt(e.currentTarget.dataset.slideIndex); 7806 this.goToSlide(index); 7807 }); 7808 }); 7809 7810 // Setup touch/swipe events 7811 this.setupTouchEvents(); 7812 7813 // Setup mouse events (but don't pause on hover) 7814 this.setupMouseEvents(); 7815 7816 // Start autoplay - NEVER STOPS 7817 this.startAutoPlay(); 7818 } 7819 7820 goToSlide(index) { 7821 if (index === this.currentIndex) return; 7822 7823 // Stop current animation frame 7824 if (this.animationFrame) { 7825 cancelAnimationFrame(this.animationFrame); 7826 this.animationFrame = null; 7827 } 7828 7829 // Update current index 7830 this.currentIndex = index; 7831 7832 // Update slides visibility 7833 this.updateSlides(); 7834 7835 // Immediately restart autoplay - NO PAUSE 7836 this.startAutoPlay(); 7837 } 7838 7839 nextSlide() { 7840 const nextIndex = (this.currentIndex + 1) % this.totalSlides; 7841 this.goToSlide(nextIndex); 7842 } 7843 7844 prevSlide() { 7845 const prevIndex = (this.currentIndex - 1 + this.totalSlides) % this.totalSlides; 7846 this.goToSlide(prevIndex); 7847 } 7848 7849 updateSlides() { 7850 // Hide all slides
7851 this.slides.forEach(slide => { 7852 slide.classList.remove('active'); 7853 }); 7854 7855 // Remove active class from all dots 7856 this.dots.forEach(dot => { 7857 dot.classList.remove('active'); 7858 const progress = dot.querySelector('.dot-progress'); 7859 if (progress) { 7860 progress.style.width = '0%'; 7861 } 7862 }); 7863 7864 // Show current slide 7865 this.slides[this.currentIndex].classList.add('active'); 7866 7867 // Activate current dot 7868 this.dots[this.currentIndex].classList.add('active'); 7869 } 7870 7871 startAutoPlay() { 7872 // Cancel any existing animation 7873 if (this.animationFrame) { 7874 cancelAnimationFrame(this.animationFrame); 7875 } 7876 7877 const activeDot = this.dots[this.currentIndex]; 7878 const progressBar = activeDot.querySelector('.dot-progress'); 7879 7880 if (!progressBar) return; 7881 7882 // Reset progress 7883 progressBar.style.transition = 'none'; 7884 progressBar.style.width = '0%'; 7885 7886 // Force reflow 7887 progressBar.offsetHeight; 7888 7889 // Start smooth progress animation 7890 this.progressStartTime = Date.now(); 7891 this.isAnimating = true; 7892 7893 const animate = () => { 7894 if (!this.isAnimating) return; 7895 7896 const elapsed = Date.now() - this.progressStartTime; 7897 const progress = Math.min(elapsed / this.progressDuration, 1); 7898 7899 // Update width smoothly 7900 progressBar.style.width = `${progress * 100}%`; 7901 7902 if (progress < 1) { 7903 // Continue animation 7904 this.animationFrame = requestAnimationFrame(animate); 7905 } else { 7906 // Animation complete - go to next slide 7907 this.nextSlide(); 7908 } 7909 }; 7910 7911 // Start the smooth animation 7912 this.animationFrame = requestAnimationFrame(animate); 7913 } 7914 7915 stopAutoPlay() { 7916 this.isAnimating = false; 7917 if (this.animationFrame) { 7918 cancelAnimationFrame(this.animationFrame); 7919 this.animationFrame = null; 7920 } 7921 } 7922 7923 setupTouchEvents() { 7924 const slidesContainer = this.container.querySelector('.slides-container'); 7925 let touchStartX = 0; 7926 let isSwiping = false; 7927 7928 slidesContainer.addEventListener('touchstart', (e) => { 7929 touchStartX = e.touches[0].clientX; 7930 isSwiping = true; 7931 // NO PAUSE - just continue 7932 }); 7933 7934 slidesContainer.addEventListener('touchmove', (e) => { 7935 if (!isSwiping) return; 7936 e.preventDefault(); 7937 }); 7938 7939 slidesContainer.addEventListener('touchend', (e) => { 7940 if (!isSwiping) return; 7941 7942 const touchEndX = e.changedTouches[0].clientX; 7943 const diffX = touchStartX - touchEndX; 7944 const threshold = 30; 7945 7946 if (Math.abs(diffX) > threshold) { 7947 if (diffX > 0) { 7948 // Swipe left - next slide 7949 this.nextSlide(); 7950 } else { 7951 // Swipe right - previous slide 7952 this.prevSlide(); 7953 } 7954 } 7955 7956 isSwiping = false; 7957 }); 7958 } 7959 7960 setupMouseEvents() { 7961 const slidesContainer = this.container.querySelector('.slides-container'); 7962 7963 // NO PAUSE on hover - just continue playing 7964 // We still want to allow dragging/swiping with mouse 7965 7966 let isMouseDown = false; 7967 let mouseStartX = 0; 7968 7969 slidesContainer.addEventListener('mousedown', (e) => { 7970 isMouseDown = true; 7971 mouseStartX = e.clientX; 7972 e.preventDefault(); 7973 }); 7974 7975 slidesContainer.addEventListener('mousemove', (e) => { 7976 if (!isMouseDown) return; 7977 e.preventDefault(); 7978 }); 7979 7980 slidesContainer.addEventListener('mouseup', (e) => { 7981 if (!isMouseDown) return; 7982 7983 const mouseEndX = e.clientX; 7984 const diffX = mouseStartX - mouseEndX; 7985 const threshold = 30; 7986 7987 if (Math.abs(diffX) > threshold) { 7988 if (diffX > 0) { 7989 this.nextSlide(); 7990 } else { 7991 this.prevSlide(); 7992 } 7993 } 7994 7995 isMouseDown = false;
7996 }); 7997 7998 slidesContainer.addEventListener('mouseleave', () => { 7999 isMouseDown = false; 8000 }); 8001 } 8002 } 8003 8004 // Initialize all sliders when DOM is loaded 8005 document.addEventListener('DOMContentLoaded', () => { 8006 setTimeout(() => { 8007 const sliders = document.querySelectorAll('.custom-slider'); 8008 sliders.forEach(slider => { 8009 new OuraStyleSlider(slider); 8010 }); 8011 }, 100); 8012 }); 8013</script>
8013 8014 8015 8016
8017<script> 8018 8019 document.addEventListener('DOMContentLoaded', function () { 8020 const onLoadParams = new URLSearchParams(window.location.search); 8021 const isWholesaleCustomer = false; 8022 8023 if (isWholesaleCustomer && onLoadParams.get('pack') === 'variety') { 8024 onLoadParams.delete('pack'); 8025 const query = onLoadParams.toString(); 8026 window.history.replaceState({}, '', `${window.location.pathname}${query ? `?${query}` : ''}`); 8027 } 8028 8029 // Configuration and Constants 8030 const CONFIG = { 8031 flavors: isWholesaleCustomer ? ['Citrus', 'Mint'] : ['Citrus', 'Mint', 'Variety'], 8032 sizes: ['full', 'travel'], 8033 images: { 8034 Citrus: [ 8035 "//revitin.com/cdn/shop/files/citrus-gallery-render_12zon_1600x.jpg", 8036 "//revitin.com/cdn/shop/files/citrus-gallery-2_11zon_1600x.jpg?v=1729881153", 8037 8038 "//revitin.com/cdn/shop/files/citrus-gallery-3_11zon_1600x.jpg?v=1751389467", 8039 8040 ], 8041 MobileCitrus: [ 8042 "//revitin.com/cdn/shop/files/citrus-gallery-mobile-2_11zon_1000x.jpg?v=1729883824", 8043 8044 "//revitin.com/cdn/shop/files/citrus-gallery-mobile-3_11zon_1000x.jpg?v=1729883824" 8045 8046 ], 8047 Mint: [ 8048 "//revitin.com/cdn/shop/files/mint-render-gallery_11zon_1600x.jpg?v=1730192833", 8049 "//revitin.com/cdn/shop/files/mint-gallery-2_11zon_1600x.jpg?v=1751389546", 8050 "//revitin.com/cdn/shop/files/mint-gallery-3_11zon_1600x.jpg?v=1729881153", 8051 ], 8052 MobileMint: [ 8053 "//revitin.com/cdn/shop/files/mint-gallery-mobile-2_11zon_1000x.jpg?v=1729883825", 8054 "//revitin.com/cdn/shop/files/mint-gallery-mobile-3_11zon_1000x.jpg?v=1729883824" 8055 ] 8056 } 8057 }; 8058 8059 // State Management 8060 const state = { 8061 products: [], 8062 allProducts: [], 8063 selectedFlavor: 'Citrus', 8064 selectedPack: '1', 8065 selectedSize: 'full' 8066 }; 8067 8068 // DOM Elements Cache 8069 const elements = { 8070 sidebar: document.querySelector('.sb-sidebar'), 8071 openBtns: document.querySelectorAll('.sb-open-btn'), 8072 closeBtn: document.querySelector('.sb-close-btn'), 8073 sizeBtns: document.querySelectorAll('.size_selection_btn'), 8074 fullContainer: document.querySelector('.full__size__container'), 8075 travelContainer: document.querySelector('.travel__size__container'), 8076 mainPdpSizeHeading: document.querySelector('.main_pdp_size_heading'), 8077 pricingRadioTab: document.querySelector('.ts-option-price'), 8078 flavorBtns: document.querySelectorAll('.ts-flavor-btn'), 8079 addBtn: document.querySelector('.ts-add-to-bag-btn'), 8080 packOptions: document.querySelectorAll('input[name="ts-pack"]'), 8081 activePackRadioLabel: document.querySelector('.ts-option-label'), 8082 mainVarietyImage: document.querySelector(".main_variety_image"), 8083 mobileMainVarietyImage: document.querySelector(".mobile_main_variety_image"), 8084 leftVarietyImage: document.querySelector(".left_variety_image"), 8085 mobileLeftVarietyImage: document.querySelector(".mobile_left_variety_image"), 8086 rightVarietyImage: document.querySelector(".right_variety_image"), 8087 mobileRightVarietyImage: document.querySelector(".mobile_right_variety_image"), 8088 cartCount: document.querySelector(".variety-cart-count"), 8089 mainAtcBtn: document.querySelector(".main__atc__button"), 8090 pdpSellingInput: document.querySelector(".cart_selling_plan"), 8091 travelVarietyButton: document.querySelector('.ts-flavor-toggle button[data-flavor="Variety"]'), 8092 }; 8093 8094 const editorMainImages = { Citrus: {}, Mint: {} }; 8095 let wholesaleTravelFeatured = {}; 8096 8097 if (isWholesaleCustomer) { 8098 const featuredEl = document.getElementById('wholesale-travel-featured-images'); 8099 if (featuredEl) { 8100 try { 8101 wholesaleTravelFeatured = JSON.parse(featuredEl.textContent); 8102 } catch (error) { 8103 wholesaleTravelFeatured = {}; 8104 } 8105 } 8106 8107 document.querySelectorAll('[data-swap-flavor]').forEach((container) => { 8108 const flavor = container.dataset.swapFlavor; 8109 if (!flavor || flavor === 'Variety') return; 8110 8111 const main = container.querySelector('.main_variety_image'); 8112 const mobileMain = container.querySelector('.mobile_main_variety_image'); 8113 8114 if (main) editorMainImages[flavor].desktop = main.getAttribute('src'); 8115 if (mobileMain) editorMainImages[flavor].mobile = mobileMain.getAttribute('src'); 8116 }); 8117 } 8118 8119 // Utility Functions 8120 const utils = { 8121 formatPrice(price) { 8122 let formatted = (typeof price === 'number' ? price.toFixed(2) : String(price)); 8123 return formatted.endsWith('.00') ? formatted.replace('.00', '') : formatted; 8124 }, 8125 8126 getUrlParams() { 8127 return new URLSearchParams(window.location.search); 8128 }, 8129 8130 getFlavorFromPath() { 8131 const path = window.location.pathname;
8132 const parts = path.split("/").filter(Boolean); 8133 return parts[parts.length - 1]; 8134 }, 8135 8136 updateUrlParam(key, value) { 8137 const params = utils.getUrlParams(); 8138 if (value) { 8139 params.set(key, value); 8140 } else { 8141 params.delete(key); 8142 } 8143 window.history.replaceState({}, "", `${window.location.pathname}?${params.toString()}`); 8144 }, 8145 8146 updateUrlPath(flavor) { 8147 const path = window.location.pathname.split("/").filter(Boolean); 8148 if (path[0] === "products") { 8149 path[path.length - 1] = flavor; 8150 const newPath = "/" + path.join("/"); 8151 const query = window.location.search; 8152 window.history.replaceState({}, "", newPath + query); 8153 } 8154 }, 8155 8156 updateFlavorUrl(){ 8157 const currentUrl = window.location.pathname + window.location.search; 8158 8159 const [path, query] = currentUrl.split("?"); 8160 8161 const hasFlavor = /\/(Citrus|Mint)(\/|$)/i.test(path); 8162 8163 if (!hasFlavor && query === "size=travel") { 8164 const newPath = path.endsWith("/") ? `${path}Citrus` : `${path}/Citrus`; 8165 const newUrl = query ? `${newPath}?${query}` : newPath; 8166 8167 window.history.replaceState({}, "", newUrl); 8168 } 8169 } 8170 }; 8171 8172 // Product Data Management 8173 const productManager = { 8174 init() { 8175 this.loadProducts(); 8176 state.selectedFlavor = utils.getFlavorFromPath() || 'Citrus'; 8177 state.selectedSize = utils.getUrlParams().get("size") ? "travel" : "full"; 8178 }, 8179 8180 loadProducts() { 8181 try { 8182 const products = JSON.parse(document.getElementById('all-products-json').textContent); 8183 state.products = products.filter(item => 8184 item.title.toLowerCase().includes("travel") || item.handle.toLowerCase().includes("travel") 8185 ); 8186 state.allProducts = products; 8187 } catch (error) { 8188 8189 state.products = []; 8190 } 8191 }, 8192 8193 getAllProducts() { 8194 try { 8195 return JSON.parse(document.getElementById('all-products-json').textContent); 8196 } catch (error) { 8197 8198 return []; 8199 } 8200 }, 8201 8202 getProduct(flavor, size = 'travel') { 8203 if (flavor === 'Variety') { 8204 return state.allProducts.find(item => 8205 item.title.includes(flavor) && item.title.includes(size === 'travel' ? 'Travel' : '') 8206 ); 8207 } else { 8208 return state.products.find(item => 8209 item.title.includes(flavor) && item.title.includes(size === 'travel' ? 'Travel' : '') 8210 ); 8211 } 8212 }, 8213 8214 getVariantId(flavor) { 8215 const product = this.getProduct(flavor); 8216 return product ? product.variants[0].id : null; 8217 }, 8218 8219 getProductPrice(flavor, pack) { 8220 const product = this.getProduct(flavor); 8221 8222 const price = product?.variants[0]?.price || 18; // Fallback price 8223 return utils.formatPrice(price); 8224 } 8225 }; 8226 8227 // UI Update Functions 8228 const uiUpdater = { 8229 updateSidebarPdpTitle(size) { 8230 if (!elements.mainPdpSizeHeading) return; 8231 8232 const products = productManager.getAllProducts(); 8233 const travelProduct = state.products[0]; 8234 const fullProduct = products?.find(item => 8235 item.aestheticTitle && !item?.aestheticTitle.toLowerCase().includes("travel") 8236 ); 8237 8238 elements.mainPdpSizeHeading.textContent = size === "travel" 8239 ? (travelProduct?.aestheticTitle || 'Revitin Natural Toothpaste') 8240 : (fullProduct?.aestheticTitle || 'Revitin Natural Toothpaste'); 8241 }, 8242 8243 updateActiveButtons(buttons, activeButton, className = 'active') { 8244 buttons.forEach(btn => btn.classList.remove(className)); 8245 activeButton?.classList.add(className); 8246 }, 8247 8248 updateAddButton(flavor, pack) { 8249 if (!elements.addBtn) return; 8250 8251 const price = productManager.getProductPrice(flavor, pack); 8252 8253 elements.addBtn.textContent = `$${price} â Add to Bag`; 8254 elements.addBtn.className = `ts-add-to-bag-btn ts-${flavor.toLowerCase()}-btn`; 8255 8256 if (elements.pricingRadioTab) { 8257 elements.pricingRadioTab.textContent = `$${price}`; 8258 } 8259 8260 if (elements.activePackRadioLabel) { 8261 if(flavor === 'Variety') { 8262 elements.activePackRadioLabel.textContent = `2 Mint & 2 Citrus`; 8263 } else { 8264 elements.activePackRadioLabel.textContent = `${flavor} 3-pack`; 8265 } 8266 } 8267 }, 8268 8269 applyWholesaleTravelMainImage(flavor) { 8270 if (!isWholesaleCustomer) return; 8271 8272 const featuredUrl = wholesaleTravelFeatured[flavor]; 8273 if (!featuredUrl) return; 8274 8275 document.querySelectorAll(`[data-swap-flavor="${flavor}"]`).forEach((container) => { 8276 const main = container.querySelector('.main_variety_image'); 8277 const mobileMain = container.querySelector('.mobile_main_variety_image'); 8278 if (main) main.src = featuredUrl; 8279 if (mobileMain) mobileMain.src = featuredUrl; 8280 }); 8281 }, 8282 8283 restoreWholesaleEditorMainImages() { 8284 if (!isWholesaleCustomer) return; 8285
8286 Object.keys(editorMainImages).forEach((flavor) => { 8287 document.querySelectorAll(`[data-swap-flavor="${flavor}"]`).forEach((container) => { 8288 const main = container.querySelector('.main_variety_image'); 8289 const mobileMain = container.querySelector('.mobile_main_variety_image'); 8290 if (main && editorMainImages[flavor].desktop) main.src = editorMainImages[flavor].desktop; 8291 if (mobileMain && editorMainImages[flavor].mobile) mobileMain.src = editorMainImages[flavor].mobile; 8292 }); 8293 }); 8294 }, 8295 8296 setActiveFlavorImages(flavor) { 8297 // Update flavor-specific images in containers 8298 const flavorImages = document.querySelectorAll('[data-swap-flavor]'); 8299 const params = utils.getUrlParams(); 8300 const isTravelUrl = params.get('size'); 8301 8302 const refineVariety = flavor === "Variety" ? "Citrus" : flavor; 8303 8304 if(!isTravelUrl) return; 8305 8306 if (isWholesaleCustomer) { 8307 const opposite = refineVariety === 'Citrus' ? 'Mint' : 'Citrus'; 8308 document.querySelectorAll(`[data-swap-flavor="${refineVariety}"]`).forEach((el) => { 8309 el.classList.remove('opacity-0'); 8310 el.classList.add('!opacity-100', 'z-10'); 8311 }); 8312 document.querySelectorAll(`[data-swap-flavor="${opposite}"]`).forEach((el) => { 8313 el.classList.add('opacity-0'); 8314 el.classList.remove('!opacity-100', 'z-10'); 8315 }); 8316 this.applyWholesaleTravelMainImage(refineVariety); 8317 return; 8318 } 8319 8320 flavorImages.forEach(img => { 8321 const hasMainImage = img.querySelector('.main_variety_image'); 8322 const hasMobileMainImage = img.querySelector('.mobile_main_variety_image'); 8323 const swapFlav = img.dataset.swapFlavor; 8324 const isActive = swapFlav === refineVariety; 8325 8326 const parent = img.parentElement; 8327 8328 8329 8330 8331 8332 8333 if(hasMainImage || hasMobileMainImage) { 8334 if(swapFlav === "Citrus") { 8335 img.classList.remove("opacity-0"); 8336 img.classList.add("!opacity-100"); 8337 } 8338 if(swapFlav === "Mint") { 8339 img.classList.add("opacity-0"); 8340 img.classList.remove("!opacity-100"); 8341 img.classList.remove("z-10"); 8342 } 8343 }else { 8344 img.classList.toggle('!opacity-100', isActive); 8345 img.classList.toggle('opacity-0', !isActive); 8346 } 8347 }); 8348 8349 // Update variety images 8350 this.updateVarietyImages(refineVariety); 8351 }, 8352 8353 updateMainVarietyImage(flavor, newImageUrl) { 8354 const container = document.querySelector(`.image_update_container [data-swap-flavor="${flavor}"]`); 8355 if (!container) { 8356 console.warn(`Flavor "${flavor}" not found.`); 8357 return; 8358 } 8359 8360 const mainImage = container.querySelector('.main_variety_image'); 8361 if (!mainImage) { 8362 console.warn(`Main variety image not found for flavor "${flavor}".`); 8363 return; 8364 } 8365 8366 mainImage.src = newImageUrl; 8367 }, 8368 8369 updateVarietyImages(flavor) { 8370 const product = productManager.getProduct(flavor); 8371 const flavorImages = CONFIG.images[flavor]; 8372 const mobileFlavorImages = CONFIG.images[`Mobile${flavor}`]; 8373 8374 // Desktop 8375 const imgForMainVariety = product?.images?.[0]?.src; 8376 const imgForRightVariety = product?.images?.[1]?.src; 8377 const imgForLeftVariety = product?.images?.[2]?.src; 8378 8379 8380 8381 // Mobile 8382 const imgForMobileMainVariety = flavor === "Citrus" ? product?.images?.[2]?.src : product?.images?.[1]?.src; 8383 const imgForMobileBottom = product?.images?.[3]?.src; 8384 8385 if (imgForMainVariety && elements.mainVarietyImage) { 8386 elements.mainVarietyImage.src = imgForMainVariety; 8387 } 8388 8389 if (imgForMobileMainVariety && elements.mobileMainVarietyImage) { 8390 elements.mobileMainVarietyImage.src = imgForMobileMainVariety; 8391 } 8392 8393 // Travel Citrus / Variety: do NOT apply the Right Image 2 override. 8394 // Use the actual travel product image so the "Right Image 2" gallery override is skipped in travel mode. 8395 if (imgForRightVariety && elements.rightVarietyImage && flavor === 'Citrus') { 8396 elements.rightVarietyImage.src = imgForRightVariety; 8397 } 8398 8399 if (flavorImages && elements.leftVarietyImage && elements.rightVarietyImage) { 8400 if(flavor === 'Mint'){ 8401 elements.rightVarietyImage.src = flavorImages[2]; 8402 elements.leftVarietyImage.src = imgForLeftVariety; 8403 }else{ 8404 elements.leftVarietyImage.src = flavorImages[1]; 8405 } 8406 } 8407 8408 if (mobileFlavorImages && elements.mobileRightVarietyImage) { 8409 elements.mobileLeftVarietyImage.src = mobileFlavorImages[0]; 8410 // Travel Citrus / Variety: skip Right Image 2 Mobile override â use the travel product's own image. 8411 elements.mobileRightVarietyImage.src = imgForMobileBottom; 8412 } 8413 8414 }, 8415 8416 updateSizeContainers(size) { 8417 if (!elements.fullContainer || !elements.travelContainer) return; 8418 8419 const isTravel = size === 'travel'; 8420 elements.fullContainer.style.display = isTravel ? 'none' : 'block'; 8421 elements.travelContainer.style.display = isTravel ? 'block' : 'none'; 8422 } 8423 }; 8424 8425 function getCart() { 8426 return fetch('/cart.js') 8427 .then(res => res.json()); 8428 } 8429 8430 const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)); 8431 8432 // Event Handlers 8433 const eventHandlers = { 8434 addToteBag() { 8435 elements.mainAtcBtn.addEventListener('click', async () => { 8436 const sellingPlanId = elements.pdpSellingInput?.value; 8437 if (!sellingPlanId) return; 8438 8439 const cart = await getCart(); 8440 8441 const toteExists = cart.items.some(item => 8442 item.handle?.includes('tote') 8443 ); 8444 8445 if (toteExists) return; 8446 8447 const products = productManager.getAllProducts(); 8448 const freeToBag = products.find(p => 8449 p.handle?.toLowerCase().includes('tote') 8450 ); 8451 8452 const variantId = freeToBag?.variants?.[0]?.id; 8453 if (!variantId) return; 8454 8455 await sleep(1500); 8456 8457 eventHandlers.addToCart(variantId); 8458 }); 8459 }, 8460 8461 initSidebar() { 8462 if (!elements.sidebar || !elements.closeBtn) return; 8463 8464 elements.openBtns.forEach(btn => { 8465 btn.addEventListener('click', () => elements.sidebar.classList.add('sb-active')); 8466 }); 8467 8468 elements.closeBtn.addEventListener('click', () => elements.sidebar.classList.remove('sb-active')); 8469 8470 document.addEventListener('click', (event) => { 8471 if (!event.target || typeof event.target.closest !== 'function') return; 8472 if (!elements.sidebar.contains(event.target) && !event.target.closest('.sb-open-btn')) { 8473 elements.sidebar.classList.remove('sb-active'); 8474 } 8475 }); 8476 }, 8477 8478 initSizeSelection() { 8479 if (!elements.sizeBtns.length) return; 8480 utils.updateFlavorUrl(); 8481 8482 elements.sizeBtns.forEach(btn => { 8483 btn.addEventListener('click', () =>
8483 this.handleSizeSelection(btn)); 8484 }); 8485 8486 // Initialize based on URL params 8487 this.initializeSizeFromParams(); 8488 }, 8489 8490 initializeSizeFromParams() { 8491 const sizeBtn = state.selectedSize === 'travel' 8492 ? document.querySelector('.travel-size-btn') 8493 : document.querySelector('.full-size-btn'); 8494 8495 if (sizeBtn) { 8496 this.handleSizeSelection(sizeBtn, true); 8497 } 8498 }, 8499 8500 handleSizeSelection(btn, isInitial = false) { 8501 const appliedStyles = window.getComputedStyle(btn); 8502 8503 const visibleBtn = Array.from(elements.sizeBtns).find( 8504 btn => window.getComputedStyle(btn).display !== "none" 8505 ); 8506 8507 const actualButton = appliedStyles.display === "none" ? visibleBtn : btn; 8508 8509 uiUpdater.updateActiveButtons(elements.sizeBtns, actualButton); 8510 8511 const isTravel = actualButton.classList.contains('travel-size-btn'); 8512 state.selectedSize = isTravel ? 'travel' : 'full'; 8513 8514 // Wholesale travel: remove image fade transitions to match full-size feel 8515 if (isWholesaleCustomer) { 8516 const pdpContainer = document.getElementById('pdp-container'); 8517 if (pdpContainer) { 8518 pdpContainer.classList.toggle('ws-travel-no-transition', isTravel); 8519 } 8520 } 8521 8522 uiUpdater.updateSizeContainers(state.selectedSize); 8523 utils.updateUrlParam('size', isTravel ? 'travel' : ''); 8524 uiUpdater.updateSidebarPdpTitle(state.selectedSize); 8525 8526 8527 8528 // Update this section: 8529 if (isTravel) { 8530 // Get flavor from URL instead of hardcoding to Citrus 8531 utils.updateFlavorUrl(); 8532 let flavorFromUrl = utils.getFlavorFromPath() || 'Citrus'; 8533 const params = utils.getUrlParams(); 8534 const isVariety = params.get('pack'); 8535 const isTravelUrl = params.get('size'); 8536 8537 // Wholesale: inherit flavor from full-size wholesale buttons when switching to travel 8538 if (isWholesaleCustomer) { 8539 const activeFullBtn = document.querySelector('.whole_flavor_btn.active'); 8540 if (activeFullBtn?.dataset.flavor) { 8541 flavorFromUrl = activeFullBtn.dataset.flavor; 8542 } 8543 if (typeof window.__revitinSetWholesaleTravelFlavor === 'function') { 8544 window.__revitinSetWholesaleTravelFlavor(flavorFromUrl); 8545 } 8546 } 8547 8548 state.selectedFlavor = flavorFromUrl; 8549 8550 // Find and activate the correct flavor button 8551 const flavorBtn = Array.from(elements.flavorBtns).find(btn => 8552 btn.dataset.flavor === flavorFromUrl || 8553 btn.classList.contains(`ts-${flavorFromUrl.toLowerCase()}`) 8554 ); 8555 8556 uiUpdater.updateActiveButtons(elements.flavorBtns, flavorBtn); 8557 uiUpdater.setActiveFlavorImages(flavorFromUrl); 8558 if(isVariety && isTravelUrl) { 8559 utils.updateUrlParam('pack'); 8560 } 8561 } else { 8562 if (isWholesaleCustomer) { 8563 uiUpdater.restoreWholesaleEditorMainImages(); 8564 8565 // Sync full-size wholesale UI to the travel flavor that was active 8566 const travelActive = document.querySelector( 8567 '.travel__size__container .ts-flavor-btn.active' 8568 ); 8569 const flavor = 8570 travelActive?.dataset.flavor || 8571 utils.getFlavorFromPath() || 8572 'Citrus'; 8573 8574 document.querySelectorAll('.whole_flavor_btn').forEach((btn) => { 8575 btn.classList.toggle('active', btn.dataset.flavor === flavor); 8576 btn.style.background = ''; 8577 btn.style.borderColor = ''; 8578 }); 8579 document.querySelectorAll('.wholesale_item').forEach((item) => { 8580 item.classList.toggle( 8581 'hidden', 8582 item.dataset.wholesaleFlavor !== flavor 8583 ); 8584 }); 8585 document.querySelectorAll('[data-swap-flavor]').forEach((el) => { 8586 const isActive = el.getAttribute('data-swap-flavor') === flavor; 8587 el.classList.toggle('opacity-0', !isActive); 8588 el.classList.toggle('!opacity-100', isActive); 8589 el.classList.toggle('z-10', isActive); 8590 }); 8591 state.selectedFlavor = flavor; 8592 } else if (!isInitial) { 8593 this.simulateFlavourClick(); 8594 if(elements.travelVarietyButton) { 8595 elements.travelVarietyButton.classList.remove("active"); 8596 } 8597 } 8598 } 8599 8600 if (!isInitial) { 8601 uiUpdater.updateAddButton(state.selectedFlavor, state.selectedPack); 8602 } 8603 }, 8604 8605 initFlavorSelection() { 8606 if (!elements.flavorBtns.length) return; 8607 8608 elements.flavorBtns.forEach(btn => { 8609 btn.addEventListener('click', () =>
8609 this.handleFlavorSelection(btn)); 8610 }); 8611 8612 // Initialize based on URL params 8613 this.initializeFlavorFromParams(); 8614 }, 8615 8616 initializeFlavorFromParams() { 8617 const currentFlavor = utils.getFlavorFromPath(); 8618 8619 const flavorBtn = Array.from(elements.flavorBtns).find(btn => 8620 btn.dataset.flavor === currentFlavor || 8621 btn.classList.contains(`ts-${currentFlavor.toLowerCase()}`) 8622 ); 8623 8624 if (flavorBtn) { 8625 this.handleFlavorSelection(flavorBtn, true); 8626 } 8627 }, 8628 8629 handleFlavorSelection(btn, isInitial = false) { 8630 const flavor = btn.dataset.flavor; 8631 8632 if(!isWholesaleCustomer && isInitial && onLoadParams.get('pack') === "variety" && onLoadParams.get('size') === "travel") { 8633 uiUpdater.updateActiveButtons(elements.flavorBtns, elements.travelVarietyButton); 8634 8635 state.selectedFlavor = "Variety"; 8636 } else { 8637 uiUpdater.updateActiveButtons(elements.flavorBtns, btn); 8638 8639 state.selectedFlavor = flavor; 8640 } 8641 8642 uiUpdater.updateAddButton(state.selectedFlavor, state.selectedPack); 8643 8644 if (!isInitial && flavor !== 'Variety') { 8645 utils.updateUrlPath(state.selectedFlavor); 8646 utils.updateUrlParam('pack'); 8647 } 8648 8649 uiUpdater.setActiveFlavorImages(state.selectedFlavor); 8650 }, 8651 8652 initPackSelection() { 8653 if (!elements.packOptions.length) return; 8654 8655 elements.packOptions.forEach(option => { 8656 option.addEventListener('change', (e) => { 8657 state.selectedPack = e.target.value; 8658 uiUpdater.updateAddButton(state.selectedFlavor, state.selectedPack); 8659 }); 8660 }); 8661 }, 8662 8663 initAddToCart() { 8664 if (!elements.addBtn) return; 8665 8666 elements.addBtn.addEventListener('click', () => { 8667 const variantId = productManager.getVariantId(state.selectedFlavor); 8668 8669 if (variantId) { 8670 this.addToCart(variantId, parseInt(state.selectedPack)); 8671 } else { 8672 console.error('Variant not found for flavor:', state.selectedFlavor); 8673 } 8674 }); 8675 }, 8676 8677 simulateFlavourClick() { 8678 const path = window.location.pathname; 8679 const parts = path.split("/").filter(Boolean); 8680 const flavorParam = parts[parts.length - 1]; 8681 8682 let button; 8683 if (flavorParam === "Variety") { 8684 button = document.querySelector(".variety-selector-btn"); 8685 } else { 8686 button = document.querySelector(`.flavour-custom[data-flavor="${flavorParam}"]`); 8687 } 8688 8689 button?.click(); 8690 }, 8691 8692 addToCart(variantId, quantity = 1) { 8693 fetch('/cart/add.js', { 8694 method: 'POST', 8695 headers: { 'Content-Type': 'application/json' }, 8696 body: JSON.stringify({ items: [{ id: variantId, quantity }] }) 8697 }) 8698 .then(response => response.json()) 8699 .then(cart => { 8700 8701 this.handleCartUpdate(cart, quantity); 8702 return cart; 8703 }) 8704 .catch(error => console.error('Error adding to cart:', error)); 8705 }, 8706 8707 handleCartUpdate(cart, quantity) { 8708 if (window.updateCartUI) { 8709 window.updateCartUI(cart); 8710 } else { 8711 window.dispatchEvent(new Event('cart:refresh')); 8712 } 8713 8714 document.querySelector('.site-cart')?.classList.add("active"); 8715 8716 if (elements.cartCount) { 8717 const currentCount = parseInt(elements.cartCount.textContent || '0'); 8718 8719 8720 if(cart.items){ 8721 elements.cartCount.textContent = currentCount + quantity; 8722 } 8723 } 8724 }, 8725 8726 activateSubscribeSection(flavor) { 8727 const toggleSections = () => { 8728 const sections = document.querySelectorAll( 8729 `.subscription-box[data-flavor="${flavor}"]` 8730 ); 8731 sections.forEach((btn) => btn.classList.remove("hidden")); 8732 sections.forEach((btn) => btn.style.display = ""); 8733 8734 const oppositeFlavor = flavor === "Citrus" ? "Mint" : "Citrus"; 8735 const oppositeSection = document.querySelector( 8736 `.subscription-box[data-flavor="${oppositeFlavor}"]` 8737 ); 8738 8739 if (oppositeSection) { 8740 oppositeSection.classList.add("hidden"); 8741 } else { 8742 console.log("Opposite section not found yet"); 8743 } 8744 }; 8745 8746 // Run immediately once 8747 toggleSections(); 8748 8749 // Observe for future DOM changes 8750 const observer = new MutationObserver(() => { 8751 toggleSections(); 8752 }); 8753 8754 observer.observe(document.body, { 8755 childList: true, 8756 subtree: true, 8757 }); 8758 } 8759 8760 }; 8761 8762 // Main Initialization
8763 function init() { 8764 document.querySelectorAll('.flavour-custom').forEach(button => { 8765 button.addEventListener('click', (e) => { 8766 const selectedFlavor = e.currentTarget.getAttribute('data-flavor'); 8767 eventHandlers.activateSubscribeSection(selectedFlavor); 8768 elements.mainAtcBtn.style.backgroundColor = selectedFlavor === "Mint" ? "#e6ecd3": "#FFDEA3"; 8769 }); 8770 }); 8771 8772 productManager.init(); 8773 8774 eventHandlers.initSidebar(); 8775 eventHandlers.initSizeSelection(); 8776 eventHandlers.initFlavorSelection(); 8777 eventHandlers.initPackSelection(); 8778 eventHandlers.initAddToCart(); 8779 8780 8781 // Initial UI updates 8782 uiUpdater.updateSidebarPdpTitle(state.selectedSize); 8783 uiUpdater.updateAddButton(state.selectedFlavor, state.selectedPack); 8784 } 8785 8786 // Start the application 8787 init(); 8788 }); 8789</script>
8789 8790 8791 8792</section><div id="shopify-section-template--21146535100554__282fbcdf-ee69-456c-b112-cab113b9ab73" class="shopify-section"><section class="site-container bg-light-tan pb-16 lg:pb-20 text-base lg:text-lg" data-buckthorn-image="//revitin.com/cdn/shop/t/129/assets/buckthorn.png?v=74098705003111698641777542406" 8793 data-seaweed-image="//revitin.com/cdn/shop/t/129/assets/seaweed.png?v=114691001103030255781777542404"> 8794 8795 <div class="text-center pt-16 lg:pt-20 border-t border-brown"> 8796 <span class="tag bg-light-green text-green mb-5">Key Ingredients</span> 8797 </div> 8798 8799 <h3 class="heading-2 text-center mx-auto max-w-md py-5 lg:max-w-4xl !tracking-tight">Our first-of-its-kind formula is backed by 15 years of clinical research. Hereâs what goes into it:</h3> 8800 8801 <div class="grid gap-y-6 mt-8 md:grid-cols-2 lg:grid-cols-3 md:gap-y-8 md:gap-x-20 md:mt-16"> 8802 8803 <div> 8804 <h3 class="text-[1.5rem] lg:text-[1.75rem] mb-1">Vitamin C</h3> 8805 <p class="mb-4 font-body-medium"> 8806 Antioxidant 8807 </p> 8808 8809 <div class="flex gap-2.5"> 8810 <p class="w-full"> 8811 Vitamin C is an essential vitamin used by your gums and natural microbes. It demonstrates a strong defense against bacteria associated with dental decay and gingivitis. 8812 </p> 8813 8814 <div class="relative w-28"> 8815 <div> 8816 <img 8817 class="object-contain" 8818 src="//revitin.com/cdn/shop/files/grapefruit.png?v=1694011206" 8819 alt="Grapefruit illustration" 8820 width="auto" 8821 height="auto" 8822 loading="eager" /> 8823 </div> 8824 </div> 8825 </div> 8826 </div> 8827 8828 <div> 8829 <h3 class="text-[1.5rem] lg:text-[1.75rem] mb-1">CoQ10</h3> 8830 <p class="mb-4 font-body-medium"> 8831 Anti-inflammatory enzyme 8832 </p> 8833 8834 <div class="flex gap-2.5"> 8835 <p class="w-full"> 8836 Coenzyme Q10 is a naturally occurring coenzyme found in every cell on the planet. Itâs an essential factor in cellular regeneration. Increasing concentration of CoQ10 in gums supports healthy cell function and suppresses inflammation. 8837 </p> 8838 8839 <div class="relative w-28"> 8840 <div> 8841 <img 8842 class="object-contain" 8843 src="//revitin.com/cdn/shop/files/lemon_7b9db330-2efe-4537-8020-fec8e016a43a.png?v=1694011678" 8844 alt="Lemon illustration" 8845 width="auto" 8846 height="auto" 8847 loading="eager" /> 8848 </div> 8849 </div> 8850 </div> 8851 </div> 8852 8853 <div> 8854 <h3 class="text-[1.5rem] lg:text-[1.75rem] mb-1">Vitamin D</h3> 8855 <p class="mb-4 font-body-medium"> 8856 Mineralization 8857 </p> 8858 8859 <div class="flex gap-2.5"> 8860 <p class="w-full"> 8861 Vitamin D is an essential vitamin that supports the mineralization of teeth and bones by encouraging optimal absorption of calcium, iron, magnesium, phosphate, and zinc. Vitamin D also strengthens the immune system and reduces periodontal inflammation. 8862 </p> 8863 8864 <div class="relative w-28"> 8865 <div> 8866 <img 8867 class="object-contain" 8868 src="//revitin.com/cdn/shop/files/papaya.png?v=1694011600" 8869 alt="Papaya illustration" 8870 width="auto" 8871 height="auto" 8872 loading="eager" /> 8873 </div> 8874 </div> 8875 </div> 8876 </div> 8877 8878 <div> 8879 <h3 class="text-[1.5rem] lg:text-[1.75rem] mb-1">Cranberry Seed Oil</h3> 8880 <p class="mb-4 font-body-medium"> 8881 Prebiotic 8882 </p> 8883 8884 <div class="flex gap-2.5"> 8885 <p class="w-full"> 8886 Cranberry Seed oil is a prebiotic nutrient that contains essential fatty acids that support the resolution of inflamed gums and a healthy oral microbiome. 8887 </p> 8888 8889 <div class="relative w-28"> 8890 <div> 8891 <img 8892 class="object-contain" 8893 src="//revitin.com/cdn/shop/files/crans.png?v=1694011645" 8894 alt="Cranberry illustration" 8895 width="auto" 8896 height="auto" 8897 loading="eager" /> 8898 </div> 8899 </div> 8900 </div> 8901 </div> 8902 8903 <div> 8904 <h3 class="text-[1.5rem] lg:text-[1.75rem] mb-1">Quillaja Saponaria Extract</h3> 8905 <p class="mb-4 font-body-medium"> 8906 Lifting agent 8907 </p> 8908 8909 <div class="flex gap-2.5"> 8910 <p class="w-full"> 8911 Quillaja Saponaria Extract is a natural foaming agent that gives our formula a sudsy foam without soap. Itâs also a gentle cleaning agent that helps break up unhealthy biofilms. 8912 </p> 8913 8914 <div class="relative w-28"> 8915 <div> 8916 <img 8917 class="object-contain" 8918 src="//revitin.com/cdn/shop/files/tangerine.png?v=1694011108" 8919 alt="Tangerine illustration" 8920 width="auto" 8921 height="auto" 8922 loading="eager" /> 8923 </div> 8924 </div> 8925 </div> 8926 </div> 8927 8928 <div> 8929 <h3 class="text-[1.5rem] lg:text-[1.75rem] mb-1">Chondrus Crispus</h3> 8930 <p class="mb-4 font-body-medium"> 8931 Prebiotic 8932 </p> 8933 8934 <div class="flex gap-2.5"> 8935 <p class="w-full"> 8936 Otherwise known as seaweed, Chondrus Crispus is a prebiotic used to balance the oral ecology and gives our formula
8936its texture. 8937 </p> 8938 8939 <div class="relative w-28"> 8940 <div> 8941 <img 8942 class="object-contain" 8943 src="//revitin.com/cdn/shop/files/seaweed.png?v=1694011555" 8944 alt="Seaweed illustration" 8945 width="auto" 8946 height="auto" 8947 loading="eager" /> 8948 </div> 8949 </div> 8950 </div> 8951 </div> 8952 8953 </div> 8954 8955 8956 <div class="mt-10 lg:mt-16 grid md:justify-center"> 8957 <a 8958 href="/pages/ingredients" 8959 title="All ingredients" 8960 class="button button--gold">All ingredients</a> 8961 </div> 8962 8963 8964 8965</section> 8966 8967 8968
8969<script> 8970 8971 document.addEventListener('DOMContentLoaded', function() { 8972 // Get flavor buttons 8973 const flavorButtonsBellow = document.querySelectorAll('[data-flavor]'); 8974 8975 let currentUrlBellow = window.location.pathname.split('/'); 8976 let CurrentLastPartBellow = currentUrlBellow[currentUrlBellow.length - 1].toLowerCase(); 8977 8978 const sectionEl = document.querySelector('.site-container.bg-light-tan'); 8979 const buckhornImageUrl = sectionEl.dataset.buckthornImage; 8980 const seaweedImageUrl = sectionEl.dataset.seaweedImage; 8981 8982 // Function to update ingredient content based on flavor 8983 function updateIngredientContent(flavor) { 8984 8985 // Get all ingredient blocks 8986 const ingredientBlocks = document.querySelectorAll('.grid.gap-y-6 > div'); 8987 8988 // Find the specific ingredient to replace (Chondrus Crispus) 8989 ingredientBlocks.forEach(block => { 8990 const titleEl = block.querySelector('h3'); 8991 8992 // Check if this is the Chondrus Crispus block 8993 if (titleEl && titleEl.textContent.trim() === "Chondrus Crispus" || 8994 titleEl && titleEl.textContent.trim() === "Sea Buckthorn Berry") { // Also check for already changed title 8995 8996 const subheadingEl = block.querySelector('p.mb-4'); 8997 const textEl = block.querySelector('div.flex > p'); 8998 const imageEl = block.querySelector('img'); 8999 9000 if (flavor === 'Mint') { 9001 // Update to Sea Buckthorn Berry for Mint flavor 9002 titleEl.textContent = "Sea Buckthorn Berry"; 9003 if (subheadingEl) subheadingEl.textContent = "Antioxidant"; 9004 if (textEl) textEl.textContent = "Rich in vitamins, antioxidants, and essential fatty acids, Sea Buckthorn Berry supports gum health, fights oxidative stress, and promotes a balanced oral microbiome while reducing inflammation and aiding tissue repair."; 9005 if (imageEl) { 9006 imageEl.src = "//revitin.com/cdn/shop/files/buckthorn.png?v=1741083804"; // Update with correct image path 9007 imageEl.alt = "Sea Buckthorn Berry"; 9008 } 9009 } else if (flavor === 'Citrus') { 9010 // Reset to default for Citrus flavor 9011 titleEl.textContent = "Chondrus Crispus"; 9012 if (subheadingEl) subheadingEl.textContent = "Prebiotic"; 9013 if (textEl) textEl.textContent = "Otherwise known as seaweed, Chondrus Crispus is a prebiotic used to balance the oral ecology and gives our formula its texture."; 9014 if (imageEl) { 9015 imageEl.src = "//revitin.com/cdn/shop/files/seaweed.png?v=1694011555"; // Update with correct image path 9016 imageEl.alt = "Chondrus Crispus"; 9017 } 9018 } 9019 } 9020 }); 9021 } 9022 9023 // Check URL on page load 9024 if (CurrentLastPartBellow === 'citrus' || CurrentLastPartBellow === 'mint') { 9025 // Capitalize first letter of flavor 9026 const flavor = CurrentLastPartBellow.charAt(0).toUpperCase() + CurrentLastPartBellow.slice(1); 9027 updateIngredientContent(flavor); 9028 } 9029 9030 // Add click event listeners to flavor buttons 9031 flavorButtonsBellow.forEach(button => { 9032 button.addEventListener('click', function() { 9033 // Use the button's flavor attribute directly 9034 const flavorBellow = this.dataset.flavor; 9035 updateIngredientContent(flavorBellow); 9036 }); 9037 }); 9038 }); 9039</script>
9039 9040 9041 9042 9043</div><section id="shopify-section-template--21146535100554__9d3df497-edc9-4e2b-b60c-72c6fd50b533" class="shopify-section"><div class="site-container pt-5 pb-16 lg:pb-20"> 9044 <div class="relative aspect-[1.4] bg-sand rounded-2xl pdp_banner_container"> 9045 9046 <img 9047 data-swap-flavor="Citrus" 9048 class="absolute top-0 left-0 w-full h-full object-cover object-center opacity-0 !opacity-100 transition-opacity duration-300 rounded-2xl" 9049 src="//revitin.com/cdn/shop/files/citrus-featured_11zon_2000x.jpg?v=1751389467" 9050 loading="lazy" /> 9051 9052 9053 <img 9054 data-swap-flavor="Mint" 9055 class="absolute top-0 left-0 w-full h-full object-cover object-center z-10 opacity-0 transition-opacity duration-300 rounded-2xl" 9056 src="//revitin.com/cdn/shop/files/mint-featured_11zon_2000x.jpg?v=1751389546" 9057 loading="lazy" /> 9058 9059 </div> 9060 <div class="mt-4 grid md:grid-cols-2 md:gap-6 md:mt-6"> 9061 9062 <div class="site-container bg-gold text-center flex flex-col pb-2 pt-8 lg:pt-8 lg:pb-4 rounded-t-2xl lg:rounded-2xl justify-between"> 9063 <div class="order-2 md:order-1"> 9064 <div class="tag-ghost mx-auto mb-4 hidden md:block">Meet Dr. Gerry</div> 9065 <div class="text-2xl lg:text-3xl mb-4">Our Founder</div> 9066 <p class="mx-auto max-w-lg md:mb-4"> 9067 Revitin founder Dr. Gerry Curatola is an internationally renown biologic dentist and pioneering researcher of the oral microbiome. He invented Revitin because he knew there was a better way to give his patients the results they wanted. 9068 </p> 9069 </div> 9070 9071 <div class="order-1 md:order-2"> 9072 <div class="w-28 h-32 mx-auto relative"> 9073 <img class="m-auto max-h-[110px]" src="//revitin.com/cdn/shop/files/DR_G_TRANSP_RGB_200x.png?v=1695836984" loading="lazy" /> 9074 </div> 9075 </div> 9076 </div> 9077 9078 <div class="site-container bg-gold text-center flex flex-col pt-2 pb-8 lg:pt-8 lg:pb-4 rounded-b-2xl lg:rounded-2xl justify-between"> 9079 <div class="order-2 md:order-1"> 9080 <div class="tag-ghost mx-auto mb-4 hidden md:block">Backed by research</div> 9081 <div class="text-2xl lg:text-3xl mb-4">Our Mission</div> 9082 <p class="mx-auto max-w-lg md:mb-4"> 9083 Create brighter smiles, stronger teeth, and healthier lives with all natural, non-toxic ingredients. Your oral microbiome is a critical piece of overall health, and the right toothpaste makes a real difference. 9084 </p> 9085 </div> 9086 9087 <div class="order-1 md:order-2"> 9088 <div class="w-28 h-32 mx-auto relative"> 9089 <img class="m-auto max-h-[110px]" src="//revitin.com/cdn/shop/files/TOOTHBRUSH_SPARKLEB_1_200x.png?v=1695847673" loading="lazy" /> 9090 </div> 9091 </div> 9092 </div> 9093 9094 </div> 9095</div> 9096 9097 9098</section><section id="shopify-section-template--21146535100554__a40b57ad-ca7b-4ae4-ba3e-44a719073e79" class="shopify-section"><section class="bg-sand"> 9099 <div class="site-container grid lg:grid-cols-[1fr_1.625fr] gap-6 lg:justify-between py-16 lg:py-20 rounded-2xl"> 9100 <div class="grid content-start"> 9101 <div class="bg-light-green text-green tag mb-5">Youâre not alone</div> 9102 <h3 class="heading-1 font-heading text-primary"> 9103 Frequently Asked Questions 9104 </h3> 9105 </div> 9106 <div class="border-t border-primary mt-6 md:mt-0 "> 9107 <accordion-item> 9108 <div class="grid border-b border-primary"> 9109 <button type="button" class="grid grid-cols-[1fr,auto] accordion-button justify-between gap-5 items-start text-left py-4"> 9110 <h2 class="font-body-medium text-primary lg:text-base">
9110How is Revitin different from other toothpastes?</h2> 9111 <div class="grid grid-flow-col items-center justify-end gap-0 relative top-1"> 9112 <div class="w-3 h-3 relative"> 9113 <svg 9114 class="transition-all duration-300" 9115 width="12" 9116 viewBox="0 0 8 9" 9117 fill="none" 9118 xmlns="http://www.w3.org/2000/svg"> 9119 <path d="M0.096 3.552H3.328V0.32H4.656V3.552H7.888V4.832H4.656V8.048H3.328V4.832H0.096V3.552Z" fill="#5F471D" /> 9120 </svg> 9121 </div> 9122 </div> 9123 </button> 9124 <div class="text-primary max-h-0 overflow-hidden transition-all duration-200 w-full max-w-4xl"> 9125 <div class="pb-5"> 9126 <p>Revitin uses all natural ingredients for healthier teeth without the use of harsh chemicals. Revitin supports an oral cavity with less inflammation and plaque buildup by encouraging a healthy microbial environment.</p> 9127 </div> 9128 </div> 9129 </div> 9130 </accordion-item> 9131 9132 9133 <accordion-item> 9134 <div class="grid border-b border-primary"> 9135 <button type="button" class="grid grid-cols-[1fr,auto] accordion-button justify-between gap-5 items-start text-left py-4"> 9136 <h2 class="font-body-medium text-primary lg:text-base">What should I do if I accidentally swallow Revitin?</h2> 9137 <div class="grid grid-flow-col items-center justify-end gap-0 relative top-1"> 9138 <div class="w-3 h-3 relative"> 9139 <svg 9140 class="transition-all duration-300" 9141 width="12"
9142 viewBox="0 0 8 9" 9143 fill="none" 9144 xmlns="http://www.w3.org/2000/svg"> 9145 <path d="M0.096 3.552H3.328V0.32H4.656V3.552H7.888V4.832H4.656V8.048H3.328V4.832H0.096V3.552Z" fill="#5F471D" /> 9146 </svg> 9147 </div> 9148 </div> 9149 </button> 9150 <div class="text-primary max-h-0 overflow-hidden transition-all duration-200 w-full max-w-4xl"> 9151 <div class="pb-5"> 9152 <p>Revitin is designed for oral use and is safe if swallowed. Please follow the usage instructions provided with the product.</p> 9153 </div> 9154 </div> 9155 </div> 9156 </accordion-item> 9157 9158 9159 <accordion-item> 9160 <div class="grid border-b border-primary"> 9161 <button type="button" class="grid grid-cols-[1fr,auto] accordion-button justify-between gap-5 items-start text-left py-4"> 9162 <h2 class="font-body-medium text-primary lg:text-base">Is Revitin fluoride-free?</h2> 9163 <div class="grid grid-flow-col items-center justify-end gap-0 relative top-1"> 9164 <div class="w-3 h-3 relative"> 9165 <svg 9166 class="transition-all duration-300" 9167 width="12"
9168 viewBox="0 0 8 9" 9169 fill="none" 9170 xmlns="http://www.w3.org/2000/svg"> 9171 <path d="M0.096 3.552H3.328V0.32H4.656V3.552H7.888V4.832H4.656V8.048H3.328V4.832H0.096V3.552Z" fill="#5F471D" /> 9172 </svg> 9173 </div> 9174 </div> 9175 </button> 9176 <div class="text-primary max-h-0 overflow-hidden transition-all duration-200 w-full max-w-4xl"> 9177 <div class="pb-5"> 9178 <p>Yes, Revitin is fluoride-free. There are no toxic ingredients in our formula.</p> 9179 </div> 9180 </div> 9181 </div> 9182 </accordion-item> 9183 9184 9185 <accordion-item> 9186 <div class="grid border-b border-primary"> 9187 <button type="button" class="grid grid-cols-[1fr,auto] accordion-button justify-between gap-5 items-start text-left py-4"> 9188 <h2 class="font-body-medium text-primary lg:text-base">What else is Revitin free from?</h2> 9189 <div class="grid grid-flow-col items-center justify-end gap-0 relative top-1"> 9190 <div class="w-3 h-3 relative"> 9191 <svg 9192 class="transition-all duration-300" 9193 width="12"
9194 viewBox="0 0 8 9" 9195 fill="none" 9196 xmlns="http://www.w3.org/2000/svg"> 9197 <path d="M0.096 3.552H3.328V0.32H4.656V3.552H7.888V4.832H4.656V8.048H3.328V4.832H0.096V3.552Z" fill="#5F471D" /> 9198 </svg> 9199 </div> 9200 </div> 9201 </button> 9202 <div class="text-primary max-h-0 overflow-hidden transition-all duration-200 w-full max-w-4xl"> 9203 <div class="pb-5"> 9204 <p>Revitin is free from fluoride, SLS, gluten, dyes, peanuts, sugar, xylitol, and GMOs.</p> 9205 </div> 9206 </div> 9207 </div> 9208 </accordion-item> 9209 9210 9211 <accordion-item> 9212 <div class="grid border-b border-primary"> 9213 <button type="button" class="grid grid-cols-[1fr,auto] accordion-button justify-between gap-5 items-start text-left py-4"> 9214 <h2 class="font-body-medium text-primary lg:text-base">Does Revitin whiten teeth?</h2> 9215 <div class="grid grid-flow-col items-center justify-end gap-0 relative top-1"> 9216 <div class="w-3 h-3 relative"> 9217 <svg 9218 class="transition-all duration-300" 9219 width="12"
9220 viewBox="0 0 8 9" 9221 fill="none" 9222 xmlns="http://www.w3.org/2000/svg"> 9223 <path d="M0.096 3.552H3.328V0.32H4.656V3.552H7.888V4.832H4.656V8.048H3.328V4.832H0.096V3.552Z" fill="#5F471D" /> 9224 </svg> 9225 </div> 9226 </div> 9227 </button> 9228 <div class="text-primary max-h-0 overflow-hidden transition-all duration-200 w-full max-w-4xl"> 9229 <div class="pb-5"> 9230 <p>Revitin is proven to reduce film build up and plaque on teeth that leads to discoloration. Additionally, natural fruit enzymes like the ones in Revitin, are proven to whiten teeth without harsh chemicals.</p> 9231 </div> 9232 </div> 9233 </div> 9234 </accordion-item> 9235 9236 9237 <accordion-item> 9238 <div class="grid border-b border-primary"> 9239 <button type="button" class="grid grid-cols-[1fr,auto] accordion-button justify-between gap-5 items-start text-left py-4"> 9240 <h2 class="font-body-medium text-primary lg:text-base">Is Revitin vegan?</h2> 9241 <div class="grid grid-flow-col items-center justify-end gap-0 relative top-1"> 9242 <div class="w-3 h-3 relative"> 9243 <svg 9244 class="transition-all duration-300" 9245 width="12"
9246 viewBox="0 0 8 9" 9247 fill="none" 9248 xmlns="http://www.w3.org/2000/svg"> 9249 <path d="M0.096 3.552H3.328V0.32H4.656V3.552H7.888V4.832H4.656V8.048H3.328V4.832H0.096V3.552Z" fill="#5F471D" /> 9250 </svg> 9251 </div> 9252 </div> 9253 </button> 9254 <div class="text-primary max-h-0 overflow-hidden transition-all duration-200 w-full max-w-4xl"> 9255 <div class="pb-5"> 9256 <p>Yes.</p> 9257 </div> 9258 </div> 9259 </div> 9260 </accordion-item> 9261 9262 9263 <accordion-item> 9264 <div class="grid border-b border-primary"> 9265 <button type="button" class="grid grid-cols-[1fr,auto] accordion-button justify-between gap-5 items-start text-left py-4"> 9266 <h2 class="font-body-medium text-primary lg:text-base">Is Revitin safe for children?</h2> 9267 <div class="grid grid-flow-col items-center justify-end gap-0 relative top-1"> 9268 <div class="w-3 h-3 relative"> 9269 <svg 9270 class="transition-all duration-300" 9271 width="12"
9272 viewBox="0 0 8 9" 9273 fill="none" 9274 xmlns="http://www.w3.org/2000/svg"> 9275 <path d="M0.096 3.552H3.328V0.32H4.656V3.552H7.888V4.832H4.656V8.048H3.328V4.832H0.096V3.552Z" fill="#5F471D" /> 9276 </svg> 9277 </div> 9278 </div> 9279 </button> 9280 <div class="text-primary max-h-0 overflow-hidden transition-all duration-200 w-full max-w-4xl"> 9281 <div class="pb-5"> 9282 <p>Yes, Revitin is a great choice for teeth brushers of all ages.</p> 9283 </div> 9284 </div> 9285 </div> 9286 </accordion-item> 9287 9288 9289 <accordion-item> 9290 <div class="grid border-b border-primary"> 9291 <button type="button" class="grid grid-cols-[1fr,auto] accordion-button justify-between gap-5 items-start text-left py-4"> 9292 <h2 class="font-body-medium text-primary lg:text-base">Do you ship internationally?</h2> 9293 <div class="grid grid-flow-col items-center justify-end gap-0 relative top-1"> 9294 <div class="w-3 h-3 relative"> 9295 <svg 9296 class="transition-all duration-300" 9297 width="12"
9298 viewBox="0 0 8 9" 9299 fill="none" 9300 xmlns="http://www.w3.org/2000/svg"> 9301 <path d="M0.096 3.552H3.328V0.32H4.656V3.552H7.888V4.832H4.656V8.048H3.328V4.832H0.096V3.552Z" fill="#5F471D" /> 9302 </svg> 9303 </div> 9304 </div> 9305 </button> 9306 <div class="text-primary max-h-0 overflow-hidden transition-all duration-200 w-full max-w-4xl"> 9307 <div class="pb-5"> 9308 <p>Yes.</p> 9309 </div> 9310 </div> 9311 </div> 9312 </accordion-item> 9313 9314</div> 9315 </div> 9316 9317</section> 9318 9319 9320</section><div id="shopify-section-template--21146535100554__1702056462da008a1e" class="shopify-section"> 9321 9322 9323 9324</div><div id="shopify-section-template--21146535100554__judgeme_reviews_pq8yep" class="shopify-section"><section 9325 class="jm-section jm-section-template--21146535100554__judgeme_reviews_pq8yep exp-padding" 9326 data-jm-section 9327 data-shop-domain="revitin.myshopify.com" 9328 data-per-page="20" 9329> 9330 <style> 9331 :root{ 9332 --jm-bg: #E5ECD1CC; 9333 --jm-green: #C9DAB5; 9334 --jm-divider: #c8ccbe; 9335 --jm-bar-track: #d5d8ce; 9336 --jm-text: #5F471D; 9337 --jm-muted: #6b6f67; 9338 --jm-red: #b23b3b; 9339 } 9340 9341 .jm-section{ 9342 background: var(--jm-bg); 9343 padding-top: 50px; 9344 padding-bottom: 45px; 9345 border-radius: 32px; 9346 } 9347 9348 .jm-container{ 9349 max-width: 1400px; 9350 margin: 0 auto; 9351 } 9352 9353 .jm-title{ 9354 font-size: 30px; 9355 line-height: 1; 9356 text-align: center; 9357 margin: 0 0 45px; 9358 } 9359 9360 .jm-top{ 9361 display: grid; 9362 grid-template-columns: 1fr 1fr; 9363 gap: 60px; 9364 align-items: start; 9365 padding-bottom: 26px; 9366 } 9367 .jm-top-left{ 9368 display: grid; 9369 grid-template-columns: 1fr 2fr; 9370 gap:30px; 9371 } 9372 .jm-divider{ 9373 border: 0; 9374 border-top: 1px solid var(--jm-divider); 9375 margin: 0; 9376 } 9377 9378 .jm-score{ 9379 display: flex; 9380 flex-direction: column; 9381 align-items: flex-start; 9382 gap: 10px; 9383 width: fit-content; 9384 } 9385 9386 .jm-score-row{ 9387 display: flex; 9388 align-items: center; 9389 gap: 14px; 9390 } 9391 9392 .jm-score-number{ 9393 line-height: 1; 9394 font-family: "Basis Regular"; 9395 font-weight: 700; 9396 } 9397 9398 .jm-stars{ 9399 display: inline-flex; 9400 9401 transform: translateY(3px); 9402 } 9403 9404 .jm-star{ 9405 width: 20px; 9406 height: 20px; 9407 fill: #7E8F72; 9408 } 9409 9410 .jm-pill{ 9411 display: inline-flex; 9412 align-items: center; 9413 justify-content: center; 9414 background: var(--jm-green); 9415 color: #5F471D; 9416 border-radius: 4px; 9417 padding: 8px 12px; 9418 font-size: 15px; 9419 white-space: nowrap; 9420 width: 100%; 9421 } 9422 9423 .jm-breakdown{ 9424 display: flex; 9425 flex-direction: column; 9426 gap: 10px; 9427 padding-top: 6px; 9428 } 9429 9430 .jm-breakdown-row{ 9431 display: grid; 9432 grid-template-columns: 104px 1fr 35px; 9433 gap: 10px; 9434 align-items: center; 9435 font-size: 13px; 9436 color: #5F471D; 9437 } 9438 9439 .jm-breakdown-stars{ 9440 display: inline-flex; 9441 gap: 2px; 9442 justify-content: flex-end; 9443 color: #5F471D; 9444 } 9445 .jm-breakdown-stars .jm-star{ 9446 width: 20px; 9447 height: 20px; 9448 } 9449 9450 .jm-bar{ 9451 height: 16px; 9452 background: #7E8F724D; 9453 9454 overflow: hidden; 9455 position: relative; 9456 } 9457 9458 .jm-bar > span{ 9459 position: absolute; 9460 left: 0; 9461 top: 0; 9462 bottom: 0; 9463 width: 0%; 9464 background: #7E8F72; 9465 9466 } 9467 9468 .jm-count{ 9469 text-align: center; 9470 color: #5F471D99; 9471 } 9472 9473 .jm-summary{ 9474 text-align: right; 9475 display: flex; 9476 flex-direction: column; 9477 align-items: center; 9478 gap: 10px; 9479 } 9480 .jm-summary .jm-btn{ 9481 margin-top: 15px; 9482 max-width: 220px; 9483 width: 100%; 9484 padding: 10px; 9485 border: 1px solid var(--jm-text); 9486 color: var(--jm-text); 9487 } 9488 .jm-summary h3{ 9489 margin: 0; 9490 font-size: 25px; 9491 color: var(--jm-text); 9492 } 9493 9494 .jm-summary p{ 9495 margin: 0; 9496 color: var(--jm-text); 9497 text-align: center; 9498 max-width: 100%; 9499 align-self: center;
9500 line-height: 26px; 9501 font-size: 18px; 9502 } 9503 9504 .jm-btn{ 9505 display: inline-flex; 9506 align-items: center; 9507 justify-content: center; 9508 border: 1px solid var(--jm-green); 9509 background: transparent; 9510 color: var(--jm-text); 9511 border-radius: 999px; 9512 padding: 10px 24px; 9513 font-size: 14px; 9514 cursor: pointer; 9515 transition: background-color 0.2s ease, color 0.2s ease; 9516 text-decoration: none; 9517 user-select: none; 9518 } 9519 .jm-footer .jm-btn{ 9520 max-width: 330px; 9521 width: 100%; 9522 padding: 12px; 9523 font-size: 16px; 9524 line-height: 26px; 9525 border-radius: 8px; 9526 background: #C9DAB5; 9527 transition: all 0.2s ease; 9528 margin-top: 50px; 9529 } 9530 .jm-footer .jm-btn:hover{ 9531 background: transparent; 9532 border-color: var(--jm-text); 9533 } 9534 9535 .jm-btn:hover{ 9536 background: var(--jm-green); 9537 } 9538 9539 .jm-controls{ 9540 display: flex; 9541 justify-content: flex-end; 9542 padding: 16px 0 0; 9543 } 9544 9545 /* Custom select (fully styleable) */ 9546 .jm-select{ 9547 position: relative; 9548 width: 152px; 9549 9550 color: #5F471D; 9551 } 9552 .jm-select-btn{ 9553 width: 100%; 9554 display: inline-flex; 9555 align-items: center; 9556 justify-content: space-between; 9557 gap: 10px; 9558 border: 0; 9559 border-radius: 4px; 9560 padding: 12px 10px; 9561 background: #C9DAB5; 9562 color: #5F471D; 9563 cursor: pointer; 9564 user-select: none; 9565 } 9566 .jm-select-btn:focus{ 9567 outline: 2px solid rgba(95,71,29,0.25); 9568 outline-offset: 2px; 9569 } 9570 .jm-select-caret{ 9571 width: 10px; 9572 height: 5px; 9573 fill: #5F471D; 9574 transition: transform 0.15s ease; 9575 flex: 0 0 auto; 9576 } 9577 .jm-select.is-open .jm-select-caret{ transform: rotate(180deg); } 9578 .jm-select-list{ 9579 position: absolute; 9580 top: calc(100% + 2px); 9581 right: 0; 9582 width: 100%; 9583 background: #c9dab5; 9584 border: 1px solid rgba(95,71,29,0.18); 9585 border-radius: 8px; 9586 box-shadow: 0 10px 24px rgba(0,0,0,0.10); 9587 padding: 6px; 9588 margin: 0; 9589 list-style: none; 9590 display: none; 9591 z-index: 20; 9592 } 9593 .jm-select.is-open .jm-select-list{ display: block; } 9594 .jm-select-opt{ 9595 padding: 10px 10px; 9596 border-radius: 6px; 9597 cursor: pointer; 9598 font-size: 14px; 9599 color: #5F471D; 9600 } 9601 .jm-select-opt:hover{ background: rgba(95,71,29,0.08); } 9602 .jm-select-opt[aria-selected="true"]{ 9603 background: rgba(95,71,29,0.12); 9604 font-weight: 600; 9605 } 9606 9607 .jm-grid{ 9608 margin-top: 40px; 9609 display: grid; 9610 grid-template-columns: repeat(2, minmax(0, 1fr)); 9611 gap: 24px; 9612 column-gap: 50px; 9613 row-gap: 60px; 9614 } 9615 9616 .jm-card{ 9617 padding: 0; 9618 margin: 0; 9619 } 9620 9621 .jm-card-stars{ 9622 display: inline-flex; 9623 gap: 3px; 9624 } 9625 9626 .jm-card-date{ 9627 margin-top: 6px; 9628 font-size: 12px; 9629 color: #7B7B7B; 9630 } 9631 9632 .jm-card-meta{ 9633 margin-top: 8px; 9634 display: flex; 9635 flex-wrap: wrap; 9636 align-items: center; 9637 gap: 8px; 9638 9639 color: var(--jm-text); 9640 font-size: 15px; 9641 } 9642 9643 .jm-verified{ 9644 border: 0.53px solid #5F471D; 9645 border-radius: 20px; 9646 font-size: 9px; 9647 padding: 2px 6px; 9648 color: var(--jm-text); 9649 display: inline-flex; 9650 align-items: center; 9651 gap: 4px; 9652 } 9653 9654 .jm-card-title{ 9655 margin-top: 25px; 9656 font-weight: 700; 9657 font-size: 24px; 9658 color: var(--jm-text); 9659 9660 } 9661 9662 .jm-card-body{ 9663 margin-top: 25px; 9664 font-size: 20px; 9665 line-height: 1.3; 9666 white-space: pre-line; 9667 } 9668 9669 .jm-footer{ 9670 display: flex; 9671 justify-content: center; 9672 margin-top: 28px; 9673 } 9674 9675 .jm-empty, 9676 .jm-error{ 9677 text-align: center; 9678 padding: 28px 0; 9679 9680 } 9681 9682 .jm-empty{ 9683 color: var(--jm-muted); 9684 } 9685 9686 .jm-error{ 9687 color: var(--jm-red); 9688 font-size: 14px; 9689 } 9690 9691 /* Skeleton */ 9692 .jm-skeleton-grid{ 9693 margin-top: 22px; 9694 display: grid; 9695 grid-template-columns: repeat(2, minmax(0, 1fr)); 9696 gap: 24px; 9697 } 9698 9699 .jm-skel{ 9700 height: 170px; 9701 border-radius: 10px; 9702 background: rgba(0,0,0,0.06); 9703 overflow: hidden; 9704 position: relative; 9705 } 9706 9707 .jm-skel:before{ 9708 content: ""; 9709 position: absolute; 9710 inset: 0; 9711 transform: translateX(-100%); 9712 background: linear-gradient(90deg, transparent, rgba(255,255,255,0.35), transparent); 9713 animation: jm-pulse 1.2s infinite; 9714 } 9715
9716 @keyframes jm-pulse{ 9717 100% { transform: translateX(100%); } 9718 } 9719 9720 /* Write-a-review dropdown form */ 9721 .jm-form-wrap{ 9722 max-height: 0; 9723 overflow: hidden; 9724 transition: max-height 0.4s ease, opacity 0.3s ease; 9725 opacity: 0; 9726 } 9727 .jm-form-wrap.is-open{ 9728 max-height: 900px; 9729 opacity: 1; 9730 } 9731 .jm-form{ 9732 max-width: 420px; 9733 margin: 0 auto; 9734 padding: 32px 0 8px; 9735 } 9736 .jm-form-heading{ 9737 text-align: center; 9738 font-family: Georgia, "Times New Roman", Times, serif; 9739 font-style: italic; 9740 font-size: 20px; 9741 color: var(--jm-text); 9742 margin: 0 0 20px; 9743 } 9744 .jm-form-label{ 9745 display: block; 9746 text-align: center; 9747 font-size: 13px; 9748 color: var(--jm-muted); 9749 margin-bottom: 6px; 9750 9751 } 9752 .jm-form-group{ 9753 margin-bottom: 18px; 9754 } 9755 .jm-form-input, 9756 .jm-form-textarea{ 9757 width: 100%; 9758 border: 1px solid var(--jm-divider); 9759 border-radius: 6px; 9760 padding: 10px 14px; 9761 font-size: 14px; 9762 9763 color: var(--jm-text); 9764 background: #fff; 9765 box-sizing: border-box; 9766 outline: none; 9767 transition: border-color 0.2s; 9768 } 9769 .jm-form-input:focus, 9770 .jm-form-textarea:focus{ 9771 border-color: var(--jm-green); 9772 } 9773 .jm-form-textarea{ 9774 min-height: 100px; 9775 resize: vertical; 9776 } 9777 .jm-form-stars{ 9778 display: flex; 9779 justify-content: center; 9780 gap: 6px; 9781 margin-bottom: 18px; 9782 } 9783 .jm-form-star{ 9784 width: 26px; 9785 height: 26px; 9786 cursor: pointer; 9787 fill: #ccc; 9788 transition: fill 0.15s; 9789 } 9790 .jm-form-star.active{ 9791 fill: #7e8f72; 9792 } 9793 .jm-form-star:hover{ 9794 fill: var(--jm-green); 9795 } 9796 .jm-form-upload{ 9797 display: flex; 9798 flex-direction: column; 9799 align-items: center; 9800 justify-content: center; 9801 border: 2px dashed var(--jm-divider); 9802 border-radius: 8px; 9803 padding: 20px; 9804 cursor: pointer; 9805 transition: border-color 0.2s; 9806 position: relative; 9807 } 9808 .jm-form-upload:hover{ 9809 border-color: var(--jm-green); 9810 } 9811 .jm-form-upload input[type="file"]{ 9812 position: absolute; 9813 inset: 0; 9814 opacity: 0; 9815 cursor: pointer; 9816 } 9817 .jm-form-upload-icon{ 9818 width: 32px; 9819 height: 32px; 9820 color: var(--jm-muted); 9821 margin-bottom: 4px; 9822 } 9823 .jm-form-upload-text{ 9824 font-size: 12px; 9825 color: var(--jm-muted); 9826 } 9827 .jm-form-previews{ 9828 display: flex; 9829 flex-wrap: wrap; 9830 gap: 8px; 9831 margin-top: 8px; 9832 } 9833 .jm-form-previews img{ 9834 width: 56px; 9835 height: 56px; 9836 object-fit: cover; 9837 border-radius: 6px; 9838 border: 1px solid var(--jm-divider); 9839 } 9840 .jm-form-actions{ 9841 display: flex; 9842 justify-content: center; 9843 gap: 12px; 9844 margin-top: 22px; 9845 } 9846 .jm-form-cancel{ 9847 border: 1px solid var(--jm-text); 9848 background: transparent; 9849 color: var(--jm-text); 9850 border-radius: 999px; 9851 padding: 10px 22px; 9852 font-size: 14px; 9853 cursor: pointer; 9854 9855 } 9856 .jm-form-submit{ 9857 border: none; 9858 background: var(--jm-text); 9859 color: #eaefd7; 9860 border-radius: 999px; 9861 padding: 10px 22px; 9862 font-size: 14px; 9863 cursor: pointer; 9864 9865 transition: opacity 0.2s; 9866 } 9867 .jm-form-submit:disabled{ 9868 opacity: 0.5; 9869 cursor: not-allowed; 9870 } 9871 .jm-form-submit .jm-spinner{ 9872 display: none; 9873 width: 16px; 9874 height: 16px; 9875 border: 2px solid rgba(234,239,215,0.35); 9876 border-top-color: #eaefd7; 9877 border-radius: 50%; 9878 animation: jm-spin 0.6s linear infinite; 9879 margin-right: 6px; 9880 } 9881 .jm-form-submit.is-loading .jm-spinner{ display: inline-block; } 9882 .jm-form-submit.is-loading{ display: inline-flex; align-items: center; } 9883 @keyframes jm-spin{ to{ transform: rotate(360deg); } } 9884 9885 .jm-toast{ 9886 position: fixed; 9887 bottom: 30px; 9888 left: 50%; 9889 transform: translateX(-50%) translateY(20px); 9890 background: var(--jm-text, #5F471D); 9891 color: #eaefd7; 9892 padding: 12px 24px; 9893 border-radius: 8px; 9894 font-size: 14px; 9895 z-index: 9999; 9896 opacity: 0; 9897 pointer-events: none; 9898 transition: opacity 0.3s ease, transform 0.3s ease; 9899 box-shadow: 0 4px 16px rgba(0,0,0,0.18); 9900 } 9901 .jm-toast.is-visible{ 9902 opacity: 1; 9903 transform: translateX(-50%) translateY(0); 9904 } 9905 9906 .jm-form-msg{ 9907 text-align: center; 9908 font-size: 13px; 9909 margin-top: 10px; 9910 9911 } 9912 .jm-form-msg.success{ color: var(--jm-green); } 9913 .jm-form-msg.error{ color: var(--jm-red); } 9914 .jm-form-disclaimer{ 9915 text-align: center; 9916 font-size: 11px; 9917 color: var(--jm-muted); 9918 margin-top: 16px; 9919 line-height: 1.5; 9920 9921 } 9922 .jm-form-disclaimer a{ 9923 color: var(--jm-text); 9924 text-decoration: underline; 9925 } 9926 @media (max-width: 1024px){ 9927 .jm-top{ 9928 grid-template-columns: 1fr; 9929 } 9930 9931 } 9932 9933 @media (max-width: 768px){ 9934 .jm-section{ padding: 60px 20px; } 9935 .jm-top{ grid-template-columns: 1fr; text-align: left;gap: 30px; } 9936 .jm-summary{ align-items: center; text-align: center; gap: 20px; } 9937 .jm-summary p{ max-width: none; } 9938 .jm-grid{ grid-template-columns: 1fr; } 9939 .jm-skeleton-grid{ grid-template-columns: 1fr; } 9940 .jm-form{ padding: 24px 0 8px; } 9941 .jm-top-left{ 9942 display: flex; 9943 flex-direction: column; 9944 align-items: center; 9945 justify-content: center; 9946 gap: 30px; 9947 } 9948 .jm-breakdown-row,.jm-breakdown{ 9949 width: 100%; 9950 } 9951 .jm-title{ 9952 margin: 0 0 20px; 9953 } 9954 .jm-summary h3{ 9955 font-size: 18px; 9956 } 9957 .jm-summary p{ 9958 font-size: 16px; 9959 } 9960 .jm-card-title{ 9961 font-size: 18px; 9962 } 9963 .jm-card-body{ 9964 font-size: 14px; 9965 line-height: 18px; 9966 margin-top: 14px; 9967 } 9968 .jm-grid{ 9969 row-gap: 40px; 9970 } 9971 } 9972 </style> 9973 9974 <div class="jm-container"> 9975 <h2 class="jm-title font-heading">Customer Reviews</h2> 9976 9977 <div class="jm-top" data-jm-top> 9978 <div class="jm-top-left"> 9979 <div class="jm-score-container"> 9980 <div class="jm-score"> 9981 <div class="jm-score-row"> 9982 <h2 class="jm-score-number heading-1" data-jm-average>â</h2> 9983 <div class="jm-stars" aria-hidden="true" data-jm-average-stars></div> 9984 </div> 9985 <div class="jm-pill" data-jm-total>â Reviews</div> 9986 </div> 9987 </div> 9988 <div class="jm-breakdown" data-jm-breakdown> 9989 <!-- rows injected --> 9990 </div> 9991 </div> 9992 <div class="jm-summary"> 9993 <h3 class="font-heading">Reviews Summary â¨</h3> 9994 <p data-jm-summary>Most customers find Revitin toothpaste to be a refreshing alternative to conventional formulas, praising its clean, natural taste and the way their mouth feels balanced rather than stripped. Many report healthier-feeling gums, improved sensitivity, and peace of mind from the non-toxic ingredient profile, with parents noting positive experiences for their children.</p> 9995 <button type="button" class="jm-btn" data-jm-toggle-form>Write a Review</button> 9996 </div> 9997 </div> 9998 9999 <!-- Inline write-a-review dropdown --> 10000 <div class="jm-form-wrap" data-jm-form-wrap> 10001 <form class="jm-form" data-jm-form autocomplete="off" novalidate> 10002 <div class="jm-form-heading">Write a review</div> 10003 10004 <div class="jm-form-group"> 10005 <label class="jm-form-label">Rating</label> 10006 <div class="jm-form-stars" data-jm-form-stars> 10007 <svg class="jm-form-star" data-star="1" viewBox="0 0 24 24"> 10008 <path d="M12 17.3l-6.18 3.7 1.64-7.03L2 9.24l7.19-.61L12 2l2.81 6.63 7.19.61-5.46 4.73 1.64 7.03z"/> 10009 </svg> 10010 <svg class="jm-form-star" data-star="2" viewBox="0 0 24 24"> 10011 <path d="M12 17.3l-6.18 3.7 1.64-7.03L2 9.24l7.19-.61L12 2l2.81 6.63 7.19.61-5.46 4.73 1.64 7.03z"/> 10012 </svg> 10013 <svg class="jm-form-star" data-star="3" viewBox="0 0 24 24"> 10014 <path d="M12 17.3l-6.18 3.7 1.64-7.03L2 9.24l7.19-.61L12 2l2.81 6.63 7.19.61-5.46 4.73 1.64 7.03z"/> 10015 </svg> 10016 <svg class="jm-form-star" data-star="4" viewBox="0 0 24 24"> 10017 <path d="M12 17.3l-6.18 3.7 1.64-7.03L2 9.24l7.19-.61L12 2l2.81 6.63 7.19.61-5.46 4.73 1.64 7.03z"/> 10018 </svg>
10019 <svg class="jm-form-star" data-star="5" viewBox="0 0 24 24"> 10020 <path d="M12 17.3l-6.18 3.7 1.64-7.03L2 9.24l7.19-.61L12 2l2.81 6.63 7.19.61-5.46 4.73 1.64 7.03z"/> 10021 </svg> 10022 </div> 10023 </div> 10024 10025 <div class="jm-form-group"> 10026 <label class="jm-form-label" for="jm-rev-title-template--21146535100554__judgeme_reviews_pq8yep">Review Title</label> 10027 <input 10028 class="jm-form-input" 10029 id="jm-rev-title-template--21146535100554__judgeme_reviews_pq8yep" 10030 type="text" 10031 placeholder="Give your review a title" 10032 data-jm-rev-title 10033 > 10034 </div> 10035 10036 <div class="jm-form-group"> 10037 <label class="jm-form-label" for="jm-rev-body-template--21146535100554__judgeme_reviews_pq8yep">Review content</label> 10038 <textarea 10039 class="jm-form-textarea" 10040 id="jm-rev-body-template--21146535100554__judgeme_reviews_pq8yep" 10041 placeholder="Start writing here..." 10042 data-jm-rev-body 10043 ></textarea> 10044 </div> 10045 10046 <div class="jm-form-group"> 10047 <label class="jm-form-label">Picture/Video (optional)</label> 10048 <div class="jm-form-upload" data-jm-upload-zone> 10049 <input type="file" accept="image/*,video/*" multiple data-jm-file-input> 10050 <svg class="jm-form-upload-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> 10051 <path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/> 10052 </svg> 10053 <span class="jm-form-upload-text">
10053Click or drag to upload</span> 10054 </div> 10055 <div class="jm-form-previews" data-jm-previews></div> 10056 </div> 10057 10058 <div class="jm-form-group"> 10059 <label class="jm-form-label" for="jm-rev-name-template--21146535100554__judgeme_reviews_pq8yep">Display name (displayed publicly)</label> 10060 <input 10061 class="jm-form-input" 10062 id="jm-rev-name-template--21146535100554__judgeme_reviews_pq8yep" 10063 type="text" 10064 placeholder="Display name" 10065 data-jm-rev-name 10066 > 10067 </div> 10068 10069 <div class="jm-form-group"> 10070 <label class="jm-form-label" for="jm-rev-email-template--21146535100554__judgeme_reviews_pq8yep">Email address</label> 10071 <input 10072 class="jm-form-input" 10073 id="jm-rev-email-template--21146535100554__judgeme_reviews_pq8yep" 10074 type="email" 10075 placeholder="Your email address" 10076 data-jm-rev-email 10077 > 10078 </div> 10079 10080 <div style="position:absolute;left:-9999px;top:-9999px;height:0;width:0;overflow:hidden;" aria-hidden="true"> 10081 <label for="jm-hp-template--21146535100554__judgeme_reviews_pq8yep">Leave empty</label> 10082 <input type="text" id="jm-hp-template--21146535100554__judgeme_reviews_pq8yep" name="website_url" tabindex="-1" autocomplete="off" data-jm-honeypot> 10083 </div> 10084 10085 <div class="jm-form-disclaimer"> 10086 How we use your data: We'll only contact you about the review you left, and only if necessary. By submitting 10087 your review, you agree to Judge.me's 10088 <a href="https://judge.me/terms" target="_blank">terms, privacy and content policies</a>. 10089 </div> 10090 10091 <div class="jm-form-actions"> 10092 <button type="button" class="jm-form-cancel" data-jm-form-cancel>Cancel review</button> 10093 <button type="submit" class="jm-form-submit" data-jm-form-submit><span class="jm-spinner"></span>Submit Review</button> 10094 </div> 10095 10096 <div class="jm-form-msg" data-jm-form-msg></div> 10097 </form> 10098 </div> 10099 10100 <hr class="jm-divider"> 10101 10102 <div class="jm-controls"> 10103 <div class="jm-select" data-jm-sort> 10104 <button type="button" class="jm-select-btn" data-jm-sort-btn aria-haspopup="listbox" aria-expanded="false"> 10105 <span data-jm-sort-label>Highest Rating</span> 10106 <svg 10107 class="jm-select-caret" 10108 xmlns="http://www.w3.org/2000/svg" 10109 width="10" 10110 height="5"
10111 viewBox="0 0 10 5" 10112 fill="none" 10113 aria-hidden="true" 10114 > 10115 <path d="M0 0L5 5L10 0H0Z" fill="#5F471D"/> 10116 </svg> 10117 </button> 10118 <ul class="jm-select-list" data-jm-sort-list role="listbox" aria-label="Sort reviews"> 10119 <li class="jm-select-opt" role="option" tabindex="0" data-value="highest" aria-selected="true"> 10120 Highest Rating 10121 </li> 10122 <li class="jm-select-opt" role="option" tabindex="-1" data-value="lowest" aria-selected="false"> 10123 Lowest Rating 10124 </li> 10125 <li class="jm-select-opt" role="option" tabindex="-1" data-value="recent" aria-selected="false"> 10126 Most Recent 10127 </li> 10128 <li class="jm-select-opt" role="option" tabindex="-1" data-value="oldest" aria-selected="false">Oldest</li> 10129 </ul> 10130 </div> 10131 </div> 10132 10133 <div data-jm-content> 10134 <div class="jm-skeleton-grid" data-jm-skeleton> 10135 <div class="jm-skel"></div> 10136 <div class="jm-skel"></div> 10137 </div> 10138 </div> 10139 10140 <div class="jm-footer"> 10141 <button type="button" class="jm-btn" data-jm-load-more style="display:none;">Load More</button> 10142 </div> 10143 </div> 10144 10145 <div class="jm-toast" data-jm-toast></div> 10146 10147
10147<script> 10148 (function () { 10149 // Entrypoint for this section instance (scoped by `section.id` in the selector). 10150 var root = document.querySelector('.jm-section-template--21146535100554__judgeme_reviews_pq8yep'); 10151 if (!root) return; 10152 10153 // Store + section settings (passed via data-attributes / Liquid). 10154 var shopDomain = root.dataset.shopDomain; 10155 var apiToken = "mzqYkvygrnD1sGLcdnSIgK-p2lE"; 10156 // How many reviews the user sees at once in the grid / revealed per 10157 // "Load More" click. Stays small for a clean UI. 10158 var perPage = Math.max(5, Math.min(50, parseInt(root.dataset.perPage || '20', 10) || 20)); 10159 // How many reviews we actually fetch per API request. A large value means 10160 // we typically only need ONE call to cover the whole review dataset, 10161 // which makes sorting correct immediately and avoids N/10 round-trips. 10162 var FETCH_BATCH_SIZE = 250; 10163 var defaultSummaryText = "Most customers find Revitin toothpaste to be a refreshing alternative to conventional formulas, praising its clean, natural taste and the way their mouth feels balanced rather than stripped. Many report healthier-feeling gums, improved sensitivity, and peace of mind from the non-toxic ingredient profile, with parents noting positive experiences for their children."; 10164 10165 // Fetch wrapper that hard-stops slow/hanging requests. 10166 function fetchWithTimeout(url, options, timeoutMs) { 10167 var ms = timeoutMs || 15000; 10168 var controller = new AbortController(); 10169 var timer = null; 10170 10171 var timeoutPromise = new Promise(function (_, reject) { 10172 timer = setTimeout(function () { 10173 try { controller.abort(); } catch (e) {} 10174 reject(new Error('Stopped after ' + ms / 1000 + 's')); 10175 }, ms); 10176 }); 10177 10178 var fetchPromise = fetch(url, Object.assign({}, options || {}, { signal: controller.signal })).then( 10179 function (res) { if (timer) clearTimeout(timer); return res; }, 10180 function (err) { if (timer) clearTimeout(timer); throw err; } 10181 ); 10182 10183 return Promise.race([fetchPromise, timeoutPromise]); 10184 } 10185 10186 var els = { 10187 avg: root.querySelector('[data-jm-average]'), 10188 avgStars: root.querySelector('[data-jm-average-stars]'), 10189 total: root.querySelector('[data-jm-total]'), 10190 breakdown: root.querySelector('[data-jm-breakdown]'), 10191 summary: root.querySelector('[data-jm-summary]'), 10192 content: root.querySelector('[data-jm-content]'), 10193 skeleton: root.querySelector('[data-jm-skeleton]'), 10194 sort: root.querySelector('[data-jm-sort]'), 10195 sortBtn: root.querySelector('[data-jm-sort-btn]'), 10196 sortLabel: root.querySelector('[data-jm-sort-label]'), 10197 sortList: root.querySelector('[data-jm-sort-list]'), 10198 loadMore: root.querySelector('[data-jm-load-more]'), 10199 toggleFormBtns: root.querySelectorAll('[data-jm-toggle-form]'), 10200 formWrap: root.querySelector('[data-jm-form-wrap]'), 10201 form: root.querySelector('[data-jm-form]'), 10202 formStars: root.querySelector('[data-jm-form-stars]'), 10203 formTitle: root.querySelector('[data-jm-rev-title]'), 10204 formBody: root.querySelector('[data-jm-rev-body]'), 10205 formName: root.querySelector('[data-jm-rev-name]'), 10206 formEmail: root.querySelector('[data-jm-rev-email]'), 10207 formFileInput: root.querySelector('[data-jm-file-input]'), 10208 formPreviews: root.querySelector('[data-jm-previews]'), 10209 formCancel: root.querySelector('[data-jm-form-cancel]'), 10210 formSubmit: root.querySelector('[data-jm-form-submit]'), 10211 formMsg: root.querySelector('[data-jm-form-msg]'), 10212 }; 10213 10214 var state = { 10215 currentPage: 1, 10216 totalPages: 1, 10217 reviews: [], 10218 sort: 'highest', 10219 hasLoadedOnce: false, 10220 // How many reviews to show on screen right now (grows when the user 10221 // clicks "Load More"). We keep this separate from how many are loaded 10222 // into `reviews` so sorting can span the full dataset. 10223 displayCount: 0, 10224 // Whether we've finished background-prefetching every page. Until this 10225 // is true, sort/load-more might need to wait for more data. 10226 allLoaded: false, 10227 // Tracks the in-flight background prefetch promise (if any). 10228 prefetchPromise: null, 10229 // Authoritative totals / rating-breakdown captured from the Judge.me
10230 // widget header on the FIRST response. These represent the full review 10231 // dataset (e.g. 900+) and must NOT be overwritten with partial counts 10232 // from subsequent paginated responses. 10233 totalCount: 0, 10234 rawHistogram: null, // { "1": n, "2": n, ... "5": n } from API 10235 ratingAverage: null, // number from API 10236 }; 10237 10238 function escapeHtml(str) { 10239 return String(str == null ? '' : str) 10240 .replace(/&/g, '&') 10241 .replace(/</g, '<') 10242 .replace(/>/g, '>') 10243 .replace(/"/g, '"') 10244 .replace(/'/g, '''); 10245 } 10246 10247 function formatDate(iso) { 10248 try { 10249 var d = new Date(iso); 10250 if (isNaN(d.getTime())) return ''; 10251 var mm = ('0' + (d.getMonth() + 1)).slice(-2); 10252 var dd = ('0' + d.getDate()).slice(-2); 10253 var yy = String(d.getFullYear()).slice(-2); 10254 return mm + '/' + dd + '/' + yy; 10255 } catch (e) { 10256 return ''; 10257 } 10258 } 10259 10260 function starSvg(filled) { 10261 var opacity = filled ? '1' : '0.22'; 10262 return '<svg class="jm-star" viewBox="0 0 24 24" aria-hidden="true" style="opacity:' + opacity + '">' + 10263 '<path d="M12 17.3l-6.18 3.7 1.64-7.03L2 9.24l7.19-.61L12 2l2.81 6.63 7.19.61-5.46 4.73 1.64 7.03z"></path>' + 10264 '</svg>'; 10265 } 10266 10267 function starsInline(count) { 10268 var n = Math.max(0, Math.min(5, Number(count) || 0)); 10269 var html = ''; 10270 for (var i = 0; i < n; i++) html += starSvg(true); 10271 return html; 10272 } 10273
10274 function renderStarsInto(container, rating, outOf) { 10275 outOf = outOf || 5; 10276 var r = Math.max(0, Math.min(outOf, Math.round(Number(rating) || 0))); 10277 var html = ''; 10278 for (var i = 1; i <= outOf; i++) html += starSvg(i <= r); 10279 container.innerHTML = html; 10280 } 10281 10282 function showError(msg) { 10283 els.content.innerHTML = '<div class="jm-error">' + escapeHtml(msg) + '</div>'; 10284 } 10285 10286 function showEmpty() { 10287 els.content.innerHTML = 10288 '<div class="jm-empty">' + 10289 '<div>No reviews yet. Be the first to write one!</div>' + 10290 '<div style="margin-top:14px;">' + 10291 '<button type="button" class="jm-btn" data-jm-toggle-form>Write a Review</button>' + 10292 '</div>' + 10293 '</div>'; 10294 var btns = els.content.querySelectorAll('[data-jm-toggle-form]'); 10295 for (var i = 0; i < btns.length; i++) btns[i].addEventListener('click', toggleForm); 10296 } 10297 10298 function renderSkeleton(show) { 10299 if (!els.skeleton) return; 10300 els.skeleton.style.display = show ? '' : 'none'; 10301 } 10302 10303 function computeHistogram(reviews) { 10304 var counts = { 1:0, 2:0, 3:0, 4:0, 5:0 }; 10305 for (var i = 0; i < reviews.length; i++) { 10306 var rating = Math.round(Number(reviews[i].rating) || 0); 10307 if (rating >= 1 && rating <= 5) counts[rating] += 1; 10308 } 10309 return counts; 10310 } 10311 10312 function renderTop(opts) { 10313 var average = opts.average; 10314 var totalCount = opts.totalCount; 10315 var histogram = opts.histogram; 10316 var avg = (typeof average === 'number' && !isNaN(average)) ? average : null; 10317 els.avg.textContent = avg ? avg.toFixed(1) : '\u2014'; 10318 10319 if (avg) { 10320 renderStarsInto(els.avgStars, Math.round(avg)); 10321 } else { 10322 els.avgStars.innerHTML = starSvg(false) + starSvg(false) + starSvg(false) + starSvg(false) + starSvg(false); 10323 } 10324 10325 var total = Number(totalCount) || state.reviews.length; 10326 els.total.textContent = total.toLocaleString() + ' Reviews'; 10327 10328 // Bar widths are based on TOTAL reviews (total = 100%). 10329 var totalForBars = 0; 10330 for (var s = 1; s <= 5; s++) totalForBars += (histogram[s] || 0); 10331 if (!totalForBars) totalForBars = total || 1; 10332 10333 var rows = ''; 10334 for (var star = 5; star >= 1; star--) { 10335 var count = histogram[star] || 0; 10336 var pct = Math.round((count / totalForBars) * 100); 10337 rows += 10338 '<div class="jm-breakdown-row">' + 10339 '<div class="jm-breakdown-stars" aria-hidden="true">' + starsInline(star) + '</div>' + 10340 '<div class="jm-bar" aria-hidden="true"><span style="width:' + pct + '%"></span></div>' + 10341 '<div class="jm-count">' + count.toLocaleString() + '</div>' + 10342 '</div>'; 10343 } 10344 els.breakdown.innerHTML = rows; 10345 } 10346 10347 function sortReviews(reviews, sortKey) { 10348 var copy = reviews.slice(); 10349 copy.sort(function (a, b) { 10350 if (sortKey === 'highest') return (b.rating - a.rating) || (new Date(b.created_at) - new Date(a.created_at)); 10351 if (sortKey === 'lowest') return (a.rating - b.rating) || (new Date(b.created_at) - new Date(a.created_at)); 10352 if (sortKey === 'recent') return new Date(b.created_at) - new Date(a.created_at); 10353 if (sortKey === 'oldest') return new Date(a.created_at) - new Date(b.created_at); 10354 return 0; 10355 }); 10356 return copy; 10357 } 10358 10359 function renderGrid() { 10360 // Sort the full loaded dataset locally, then slice to the number of 10361 // reviews the user has asked to see. This ensures sorting applies across 10362 // ALL reviews (not just the first page), while still paginating 10 at a 10363 // time via "Load More". 10364 var sortedAll = sortReviews(state.reviews, state.sort); 10365 var limit = Math.max(0, Math.min(sortedAll.length, state.displayCount || perPage)); 10366 var sorted = sortedAll.slice(0, limit); 10367 var cards = ''; 10368 for (var i = 0; i < sorted.length; i++) { 10369 var r = sorted[i]; 10370 var created = formatDate(r.created_at); 10371 var name = escapeHtml((r.reviewer && r.reviewer.name) || r.reviewer_name || 'Anonymous'); 10372 var title = escapeHtml(r.title || ''); 10373 var body = escapeHtml(r.body || r.review || ''); 10374 var verified = !!(r.verified || r.verified_buyer); 10375 var rating = Math.max(0, Math.min(5, Math.round(Number(r.rating) || 0))); 10376 10377 var stars = ''; 10378 for (var j = 1; j <= 5; j++) stars += starSvg(j <= rating); 10379 10380 cards += 10381 '<article class="jm-card">' + 10382 '<div class="jm-card-stars" aria-hidden="true">' + stars + '</div>' + 10383 '<div class="jm-card-date">' + created + '</div>' + 10384 '<div class="jm-card-meta">' + 10385 '<span>' + name + '</span>' + 10386 (verified ? '<span class="jm-verified">Verified by shop</span>' : '') + 10387 '</div>' + 10388 (title ? '<div class="jm-card-title">' + title + '</div>' : '') + 10389 (body ? '<div class="jm-card-body">' + body + '</div>' : '') + 10390 '</article>'; 10391 } 10392 10393 els.content.innerHTML = cards ? '<div class="jm-grid">' + cards + '</div>' : ''; 10394 } 10395 10396 function updateLoadMoreVisibility() { 10397 // Show "Load More" if there are more loaded reviews to reveal OR more 10398 // pages waiting to be fetched in the background. 10399 var moreLoadedToShow = state.displayCount < state.reviews.length; 10400 var morePagesAvailable = state.currentPage < state.totalPages; 10401 var hasMore = moreLoadedToShow || morePagesAvailable; 10402 els.loadMore.style.display = hasMore ? '' : 'none'; 10403 } 10404
10405 // Background-prefetch every remaining page so local sorting covers the 10406 // entire review dataset, not just the first page. 10407 async function prefetchAllPages() { 10408 if (state.prefetchPromise) return state.prefetchPromise; 10409 10410 state.prefetchPromise = (async function () { 10411 while (state.currentPage < state.totalPages) { 10412 var nextPage = state.currentPage + 1; 10413 try { 10414 var data = await fetchReviewsPage(nextPage); 10415 var reviews = Array.isArray(data && data.reviews) ? data.reviews : []; 10416 10417 state.currentPage = Number(data && data.current_page) || nextPage; 10418 var tp = Number(data && data.total_pages) || 0; 10419 var tc = Number(data && data.total_count) || 0; 10420 if (!tp && tc > 0) tp = Math.ceil(tc / FETCH_BATCH_SIZE); 10421 if (!tp && reviews.length >= FETCH_BATCH_SIZE) tp = state.currentPage + 1; 10422 if (tp) state.totalPages = tp; 10423 if (!reviews.length) { state.totalPages = state.currentPage; break; } 10424 10425 state.reviews = state.reviews.concat(reviews); 10426 10427 // NOTE: do NOT call renderTop here. The header (total count, 10428 // average, histogram) was already populated from the 10429 // authoritative widget-header values during initialLoad, which 10430 // reflect the ENTIRE review dataset (e.g. 900 reviews). Using 10431 // state.reviews.length here would overwrite that with the 10432 // partial count we've loaded so far (e.g. 100). 10433 10434 // Re-render in case the user's current sort changes which reviews 10435 // appear in the top `displayCount` now that more data is loaded. 10436 renderGrid(); 10437 updateLoadMoreVisibility(); 10438 } catch (e) { 10439 // One page failedâstop the prefetch loop but keep what we have. 10440 break; 10441 } 10442 } 10443 state.allLoaded = true; 10444 updateLoadMoreVisibility(); 10445 })(); 10446 10447 return state.prefetchPromise; 10448 } 10449 10450 function normalizeReviewsPayload(json) { 10451 // Judge.me responses vary by endpoint; normalize to { reviews, meta }. 10452 if (!json || typeof json !== 'object') return { raw: json, reviews: [], meta: {} }; 10453 var reviews = []; 10454 if (Array.isArray(json.reviews)) reviews = json.reviews; 10455 else if (Array.isArray(json.data)) reviews = json.data; 10456 else if (Array.isArray(json.review)) reviews = json.review; 10457 return { 10458 raw: json, 10459 reviews: reviews, 10460 meta: { 10461 current_page: json.current_page != null ? json.current_page : (json.page != null ? json.page : json.currentPage), 10462 total_pages: json.total_pages != null ? json.total_pages : (json.totalPages != null ? json.totalPages : json.pages), 10463 total_count: json.total_count != null ? json.total_count : (json.total_reviews != null ? json.total_reviews : json.total), 10464 rating_average: json.rating_average != null ? json.rating_average : json.average_rating, 10465 rating_distribution: json.rating_distribution || json.ratings_breakdown, 10466 reviews_summary: json.reviews_summary || json.summary, 10467 }, 10468 }; 10469 } 10470 10471 // Judge.me's cache CDN serves widget endpoints with proper CORS headers. 10472 // This is how Judge.me's own storefront script (jdgm-widget.js) fetches reviews. 10473 var CACHE_BASE = 'https://cache.judge.me'; 10474 10475 function buildCacheUrl(widgetPath, params) { 10476 var url = new URL(CACHE_BASE + '/widgets/' + widgetPath); 10477 url.searchParams.set('shop_domain', shopDomain); 10478 url.searchParams.set('api_token', apiToken); 10479 if (params) { 10480 var keys = Object.keys(params); 10481 for (var i = 0; i < keys.length; i++) { 10482 if (params[keys[i]] != null) url.searchParams.set(keys[i], String(params[keys[i]])); 10483 } 10484 } 10485 return url.toString(); 10486 } 10487 10488 function parseWidgetHtml(html) { 10489 // Widget endpoints return HTML markup inside JSON; we parse that HTML into review objects. 10490 var doc = new DOMParser().parseFromString(html, 'text/html'); 10491 var cards = doc.querySelectorAll('.jdgm-rev'); 10492 var reviews = []; 10493 for (var i = 0; i < cards.length; i++) { 10494 var card = cards[i]; 10495 var ratingEl = card.querySelector('.jdgm-rev__rating'); 10496 var rating = ratingEl ? (ratingEl.getAttribute('data-score') || ratingEl.querySelectorAll('.jdgm-star.jdgm--on').length) : 0; 10497 var titleEl = card.querySelector('.jdgm-rev__title'); 10498 var bodyEl = card.querySelector('.jdgm-rev__body'); 10499 var authorEl = card.querySelector('.jdgm-rev__author'); 10500 var dateEl = card.querySelector('.jdgm-rev__timestamp'); 10501 var verifiedEl = card.querySelector('.jdgm-rev__buyer-badge'); 10502 var verifiedAttr = card.getAttribute('data-verified-buyer'); 10503 reviews.push({ 10504 rating: Number(rating) || 0, 10505 title: titleEl ? titleEl.textContent.trim() : '', 10506 body: bodyEl ? bodyEl.textContent.trim() : '', 10507 reviewer_name: authorEl ? authorEl.textContent.trim() : 'Anonymous', 10508 created_at: dateEl ? (dateEl.getAttribute('data-content') || dateEl.textContent.trim()) : '',
10509 verified: verifiedAttr === 'true' || !!verifiedEl, 10510 }); 10511 } 10512 return reviews; 10513 } 10514 10515 function parseWidgetHeader(html) { 10516 // Parses totals / average / histogram from the widget "header" HTML (if provided). 10517 if (!html) return {}; 10518 var doc = new DOMParser().parseFromString(html, 'text/html'); 10519 var header = doc.querySelector('.jdgm-all-reviews__header') || doc.documentElement; 10520 var totalCount = Number(header.getAttribute('data-number-of-reviews')) || 0; 10521 var average = parseFloat(header.getAttribute('data-average-rating')) || 0; 10522 var distribution = {}; 10523 var rows = doc.querySelectorAll('.jdgm-histogram__row[data-rating]'); 10524 for (var i = 0; i < rows.length; i++) { 10525 var star = rows[i].getAttribute('data-rating'); 10526 var freq = Number(rows[i].getAttribute('data-frequency')) || 0; 10527 if (star && star !== 'null') distribution[star] = freq; 10528 } 10529 return { totalCount: totalCount, average: average, distribution: distribution }; 10530 } 10531 10532 function widgetParams(page) { 10533 return { 10534 page: page, 10535 per_page: FETCH_BATCH_SIZE, 10536 review_type: 'product-reviews' 10537 }; 10538 } 10539 10540 function parseResponse(rawBody, page) { 10541 var trimmedBody = String(rawBody || '').replace(/^\uFEFF/, '').trim(); 10542 var json; 10543 try { 10544 json = JSON.parse(trimmedBody); 10545 } catch (e) { 10546 throw new Error('Invalid JSON from Judge.me'); 10547 } 10548 10549 var reviews, headerInfo; 10550 10551 if (json.all_reviews && typeof json.all_reviews === 'string') { 10552 reviews = parseWidgetHtml(json.all_reviews); 10553 headerInfo = parseWidgetHeader(json.all_reviews_header || ''); 10554 return { 10555 reviews: reviews, 10556 current_page: page, 10557 total_count: headerInfo.totalCount, 10558 rating_average: headerInfo.average, 10559 rating_distribution: headerInfo.distribution, 10560 }; 10561 } 10562 10563 var norm = normalizeReviewsPayload(json); 10564 return { 10565 reviews: norm.reviews, 10566 current_page: norm.meta.current_page || page, 10567 total_pages: norm.meta.total_pages, 10568 total_count: norm.meta.total_count, 10569 rating_average: norm.meta.rating_average, 10570 rating_distribution: norm.meta.rating_distribution, 10571 reviews_summary: norm.meta.reviews_summary, 10572 }; 10573 } 10574 10575 async function fetchReviewsPage(page) { 10576 var candidates = [ 10577 buildCacheUrl('all_reviews_page', widgetParams(page)), 10578 CACHE_BASE.replace('cache.', 'api.') + '/api/v1/widgets/all_reviews_page?shop_domain=' +
10579 encodeURIComponent(shopDomain) + '&api_token=' + encodeURIComponent(apiToken) + 10580 '&per_page=' + FETCH_BATCH_SIZE + '&page=' + page + '&review_type=product-reviews', 10581 ]; 10582 10583 var lastErr; 10584 for (var i = 0; i < candidates.length; i++) { 10585 try { 10586 var res = await fetchWithTimeout(candidates[i], { headers: { Accept: 'application/json' } }, 10000); 10587 var rawBody = await res.text(); 10588 if (!res.ok) throw new Error('HTTP ' + res.status); 10589 return parseResponse(rawBody, page); 10590 } catch (e) { 10591 lastErr = e; 10592 } 10593 } 10594 throw lastErr || new Error('Failed to fetch reviews'); 10595 } 10596 10597 function extractSummaryText(reviews) { 10598 var n = reviews.length; 10599 if (!n) return 'No reviews yet.'; 10600 var sum = 0; 10601 for (var i = 0; i < n; i++) sum += (Number(reviews[i].rating) || 0); 10602 var avg = sum / n; 10603 if (avg >= 4.6) return 'Customers love the results, especially freshness and overall mouth feel.'; 10604 if (avg >= 4.0) return 'Most customers are happy overall, with a few mixed experiences.'; 10605 return 'Reviews are mixed\u2014some customers love it, while others had issues.'; 10606 } 10607 10608 async function initialLoad() { 10609 if (!apiToken) { 10610 showError('Missing Judge.me API token. Add your public token in this sectionâs Liquid (jm_token).'); 10611 return; 10612 } 10613 10614 renderSkeleton(true); 10615 els.loadMore.style.display = 'none'; 10616 10617 try { 10618 var data = await fetchReviewsPage(1); 10619 var reviews = Array.isArray(data && data.reviews) ? data.reviews : []; 10620 10621 state.currentPage = Number(data && data.current_page) || 1; 10622 var tp = Number(data && data.total_pages) || 0; 10623 var tc = Number(data && data.total_count) || 0;
10624 // Widget endpoints often provide total_count but not total_pages â derive pages from FETCH_BATCH_SIZE. 10625 if (!tp && tc > 0) tp = Math.ceil(tc / FETCH_BATCH_SIZE); 10626 // If totals are unknown, assume "maybe more" if we received a full page. 10627 if (!tp && reviews.length >= FETCH_BATCH_SIZE) tp = state.currentPage + 1; 10628 state.totalPages = tp || 1; 10629 state.reviews = reviews; 10630 // Only reveal `perPage` reviews at a time in the UI, even though we 10631 // may have fetched up to FETCH_BATCH_SIZE of them in one call. 10632 state.displayCount = Math.min(perPage, reviews.length); 10633 state.allLoaded = state.currentPage >= state.totalPages; 10634 state.hasLoadedOnce = true; 10635 10636 renderSkeleton(false); 10637 10638 if (!reviews.length) { 10639 showEmpty(); 10640 els.summary.textContent = defaultSummaryText || 'No reviews yet.'; 10641 renderTop({ 10642 average: null, 10643 totalCount: Number(data && data.total_count) || 0, 10644 histogram: {1:0,2:0,3:0,4:0,5:0} 10645 }); 10646 updateLoadMoreVisibility(); 10647 return; 10648 } 10649 10650 var totalCount = Number(data.total_count) || Number(data.total_reviews) || reviews.length; 10651 var avg = typeof data.rating_average === 'number' 10652 ? data.rating_average 10653 : (reviews.reduce(function (a, r) { return a + (Number(r.rating) || 0); }, 0) / reviews.length); 10654 10655 var histogram = data.rating_distribution 10656 ? { 10657 1: Number(data.rating_distribution['1'] || 0), 10658 2: Number(data.rating_distribution['2'] || 0), 10659 3: Number(data.rating_distribution['3'] || 0), 10660 4: Number(data.rating_distribution['4'] || 0), 10661 5: Number(data.rating_distribution['5'] || 0), 10662 } 10663 : computeHistogram(reviews); 10664 10665 // Remember these as the authoritative store-wide totals. Later 10666 // paginated responses only give us partial data and must NOT 10667 // overwrite these values. 10668 state.totalCount = totalCount; 10669 state.rawHistogram = histogram; 10670 state.ratingAverage = avg; 10671 10672 renderTop({ average: avg, totalCount: totalCount, histogram: histogram }); 10673 els.summary.textContent = (data && data.reviews_summary) || defaultSummaryText || extractSummaryText(reviews); 10674 renderGrid(); 10675 updateLoadMoreVisibility(); 10676 10677 // Kick off background prefetch of remaining pages so that sorting 10678 // eventually covers the full dataset. 10679 if (!state.allLoaded) prefetchAllPages(); 10680 } catch (e) { 10681 renderSkeleton(false); 10682 showError('Could not load reviews.'); 10683 } 10684 } 10685 10686 async function loadMore() { 10687 // "Load More" just reveals more of the already-sorted local dataset. 10688 // If we haven't finished prefetching every page yet, we wait for enough 10689 // data to be available before revealing the next batch. 10690 var targetCount = state.displayCount + perPage; 10691 10692 if (state.reviews.length < targetCount && !state.allLoaded) { 10693 els.loadMore.disabled = true; 10694 els.loadMore.textContent = 'Loading\u2026'; 10695 try { await prefetchAllPages(); } catch (e) {} 10696 els.loadMore.disabled = false; 10697 els.loadMore.textContent = 'Load More'; 10698 } 10699 10700 state.displayCount = Math.min(targetCount, state.reviews.length); 10701 renderGrid(); 10702 updateLoadMoreVisibility(); 10703 } 10704 10705 /* ââ Write-a-review dropdown form ââ */ 10706 var formRating = 0; 10707 var formFiles = []; 10708 var formOpenedAt = 0; 10709 10710 function toggleForm() { 10711 if (!els.formWrap) return; 10712 var isOpen = els.formWrap.classList.contains('is-open'); 10713 if (isOpen) { 10714 els.formWrap.classList.remove('is-open'); 10715 } else { 10716 els.formWrap.classList.add('is-open'); 10717 formOpenedAt = Date.now(); 10718 els.formWrap.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); 10719 } 10720 } 10721 10722 function resetForm() { 10723 formRating = 0; 10724 formFiles = []; 10725 updateStarDisplay(0); 10726 if (els.form) els.form.reset(); 10727 if (els.formPreviews) els.formPreviews.innerHTML = ''; 10728 if (els.formMsg) { els.formMsg.textContent = ''; els.formMsg.className = 'jm-form-msg'; } 10729 if (els.formSubmit) els.formSubmit.disabled = false;
10730 } 10731 10732 function updateStarDisplay(rating) { 10733 if (!els.formStars) return; 10734 var stars = els.formStars.querySelectorAll('.jm-form-star'); 10735 for (var i = 0; i < stars.length; i++) { 10736 if (i < rating) { stars[i].classList.add('active'); } 10737 else { stars[i].classList.remove('active'); } 10738 } 10739 } 10740 10741 if (els.formStars) { 10742 // Click to set rating, hover to preview rating. 10743 els.formStars.addEventListener('click', function (e) { 10744 var star = e.target.closest('.jm-form-star'); 10745 if (!star) return; 10746 formRating = parseInt(star.getAttribute('data-star'), 10) || 0; 10747 updateStarDisplay(formRating); 10748 }); 10749 els.formStars.addEventListener('mouseover', function (e) { 10750 var star = e.target.closest('.jm-form-star'); 10751 if (!star) return; 10752 updateStarDisplay(parseInt(star.getAttribute('data-star'), 10) || 0); 10753 }); 10754 els.formStars.addEventListener('mouseleave', function () { 10755 updateStarDisplay(formRating); 10756 }); 10757 } 10758 10759 if (els.formFileInput) { 10760 // Optional media selection (we currently only show previews; actual upload support depends on Judge.me endpoint). 10761 els.formFileInput.addEventListener('change', function () { 10762 var files = els.formFileInput.files; 10763 if (!files || !files.length) return; 10764 for (var i = 0; i < files.length; i++) { 10765 if (formFiles.length >= 5) break; 10766 formFiles.push(files[i]); 10767 } 10768 renderPreviews(); 10769 }); 10770 } 10771 10772 function renderPreviews() { 10773 if (!els.formPreviews) return; 10774 els.formPreviews.innerHTML = ''; 10775 for (var i = 0; i < formFiles.length; i++) { 10776 var img = document.createElement('img'); 10777 img.src = URL.createObjectURL(formFiles[i]); 10778 img.alt = 'Preview'; 10779 els.formPreviews.appendChild(img); 10780 } 10781 } 10782 10783 function showFormMsg(text, type) { 10784 if (!els.formMsg) return; 10785 els.formMsg.textContent = text; 10786 els.formMsg.className = 'jm-form-msg ' + (type || ''); 10787 } 10788 10789 async function submitReview(e) { 10790 e.preventDefault(); 10791 // Basic client-side validation. 10792 var honeypot = root.querySelector('[data-jm-honeypot]'); 10793 if (honeypot && honeypot.value) return; 10794 if (formOpenedAt && (Date.now() - formOpenedAt) < 3000) { showFormMsg('Please take a moment before submitting.', 'error'); return; } 10795 if (!formRating) { showFormMsg('Please select a star rating.', 'error'); return; } 10796 var body = (els.formBody && els.formBody.value || '').trim(); 10797 if (!body) { showFormMsg('Please write your review.', 'error'); return; } 10798 var name = (els.formName && els.formName.value || '').trim(); 10799 if (!name) { showFormMsg('Please enter your display name.', 'error'); return; } 10800 var email = (els.formEmail && els.formEmail.value || '').trim(); 10801 if (!email || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) { showFormMsg('Please enter a valid email address.', 'error'); return; } 10802 10803 els.formSubmit.disabled = true; 10804 els.formSubmit.classList.add('is-loading'); 10805 showFormMsg('', ''); 10806 10807 var payload = { 10808 shop_domain: shopDomain, 10809 platform: 'shopify', 10810 name: name, 10811 email: email, 10812 rating: formRating, 10813 title: (els.formTitle && els.formTitle.value || '').trim(), 10814 body: body, 10815 }; 10816 10817 // Submit via a hidden iframe form POST (bypasses CORS; judge.me/reviews always returns 200). 10818 try { 10819 var iframeName = 'jm-submit-' + Date.now(); 10820 var iframe = document.createElement('iframe'); 10821 iframe.name = iframeName; 10822 iframe.style.cssText = 'position:absolute;left:-9999px;top:-9999px;width:0;height:0;border:0;'; 10823 document.body.appendChild(iframe); 10824 10825 var hiddenForm = document.createElement('form'); 10826 hiddenForm.method = 'POST'; 10827 hiddenForm.action = 'https://judge.me/reviews'; 10828 hiddenForm.target = iframeName; 10829 hiddenForm.style.display = 'none'; 10830 10831 var fields = { 10832 shop_domain: payload.shop_domain, 10833 platform: payload.platform, 10834 name: payload.name, 10835 email: payload.email, 10836 rating: String(payload.rating), 10837 title: payload.title, 10838 body: payload.body, 10839 }; 10840 var fieldKeys = Object.keys(fields); 10841 for (var fi = 0; fi < fieldKeys.length; fi++) { 10842 var inp = document.createElement('input'); 10843 inp.type = 'hidden'; 10844 inp.name = fieldKeys[fi]; 10845 inp.value = fields[fieldKeys[fi]] || ''; 10846 hiddenForm.appendChild(inp); 10847 } 10848 10849 document.body.appendChild(hiddenForm); 10850 hiddenForm.submit(); 10851 10852 // Show spinner for at least 1 second before closing. 10853 setTimeout(function () { 10854 els.formSubmit.classList.remove('is-loading'); 10855 resetForm(); 10856 els.formWrap.classList.remove('is-open'); 10857 10858 // Scroll to top of section after form closes. 10859 root.scrollIntoView({ behavior: 'smooth', block: 'start' }); 10860 10861 // Show toast after form is visually closed (allow 400ms for collapse animation). 10862 setTimeout(function () { 10863 var toast = root.querySelector('[data-jm-toast]') || document.querySelector('[data-jm-toast]'); 10864 if (toast) { 10865 toast.textContent = 'Review has been submitted'; 10866 toast.classList.add('is-visible'); 10867 setTimeout(function () { toast.classList.remove('is-visible'); }, 2000); 10868 } 10869 }, 400); 10870 10871 // Clean up hidden iframe/form. 10872 setTimeout(function () { 10873 try { document.body.removeChild(iframe); } catch (x) {} 10874 try { document.body.removeChild(hiddenForm); } catch (x) {} 10875 }, 3000); 10876 }, 1000); 10877 } catch (err) { 10878 els.formSubmit.classList.remove('is-loading'); 10879 showFormMsg('Could not submit review. Please try again.', 'error'); 10880 els.formSubmit.disabled = false;
10881 } 10882 } 10883 10884 var allToggleBtns = root.querySelectorAll('[data-jm-toggle-form]'); 10885 for (var i = 0; i < allToggleBtns.length; i++) allToggleBtns[i].addEventListener('click', toggleForm); 10886 if (els.formCancel) els.formCancel.addEventListener('click', function () { resetForm(); els.formWrap.classList.remove('is-open'); }); 10887 if (els.form) els.form.addEventListener('submit', submitReview); 10888 10889 if (els.sort) { 10890 // Custom dropdown open/close. 10891 function closeSort() { 10892 if (!els.sort || !els.sortBtn) return; 10893 els.sort.classList.remove('is-open'); 10894 els.sortBtn.setAttribute('aria-expanded', 'false'); 10895 } 10896 10897 function openSort() { 10898 if (!els.sort || !els.sortBtn) return; 10899 els.sort.classList.add('is-open'); 10900 els.sortBtn.setAttribute('aria-expanded', 'true'); 10901 } 10902 10903 function setSort(value, label) { 10904 var previousSort = state.sort; 10905 state.sort = value; 10906 if (els.sortLabel) els.sortLabel.textContent = label; 10907 if (els.sortList) { 10908 var opts = els.sortList.querySelectorAll('[role="option"]'); 10909 for (var i = 0; i < opts.length; i++) { 10910 var isSelected = (opts[i].getAttribute('data-value') === value); 10911 opts[i].setAttribute('aria-selected', isSelected ? 'true' : 'false'); 10912 opts[i].tabIndex = isSelected ? 0 : -1; 10913 } 10914 } 10915 10916 if (!state.hasLoadedOnce || previousSort === value) return; 10917 10918 // Re-render immediately with whatever reviews we have so far. If the 10919 // background prefetch is still running, the sorted view will update 10920 // again as more pages arrive (prefetchAllPages calls renderGrid on 10921 // each appended page). 10922 renderGrid(); 10923 updateLoadMoreVisibility(); 10924 } 10925 10926 if (els.sortBtn) { 10927 els.sortBtn.addEventListener('click', function () { 10928 var isOpen = els.sort.classList.contains('is-open'); 10929 if (isOpen) closeSort(); else openSort(); 10930 }); 10931 } 10932 10933 if (els.sortList) { 10934 els.sortList.addEventListener('click', function (e) { 10935 var opt = e.target.closest('[role="option"]'); 10936 if (!opt) return; 10937 setSort(opt.getAttribute('data-value'), opt.textContent.trim()); 10938 closeSort(); 10939 }); 10940 10941 els.sortList.addEventListener('keydown', function (e) { 10942 var opts = els.sortList.querySelectorAll('[role="option"]'); 10943 if (!opts.length) return; 10944 var current = document.activeElement && document.activeElement.getAttribute('role') === 'option' 10945 ? document.activeElement 10946 : (els.sortList.querySelector('[role="option"][aria-selected="true"]') || opts[0]); 10947 var idx = 0; 10948 for (var i = 0; i < opts.length; i++) if (opts[i] === current) idx = i; 10949 10950 if (e.key === 'Enter' || e.key === ' ') { 10951 e.preventDefault(); 10952 setSort(current.getAttribute('data-value'), current.textContent.trim()); 10953 closeSort(); 10954 if (els.sortBtn) els.sortBtn.focus(); 10955 } else if (e.key === 'Escape') { 10956 e.preventDefault(); 10957 closeSort(); 10958 if (els.sortBtn) els.sortBtn.focus(); 10959 } else if (e.key === 'ArrowDown') { 10960 e.preventDefault(); 10961 opts[Math.min(opts.length - 1, idx + 1)].focus(); 10962 } else if (e.key === 'ArrowUp') { 10963 e.preventDefault(); 10964 opts[Math.max(0, idx - 1)].focus(); 10965 } 10966 }); 10967 } 10968 10969 document.addEventListener('click', function (e) { 10970 if (!els.sort) return; 10971 if (!els.sort.contains(e.target)) closeSort(); 10972 }); 10973 10974 document.addEventListener('keydown', function (e) { 10975 if (e.key !== 'Escape') return; 10976 if (els.sort && els.sort.classList.contains('is-open')) closeSort(); 10977 }); 10978 10979 // Default sort. 10980 setSort('highest', 'Highest Rating'); 10981 } 10982 10983 if (els.loadMore) els.loadMore.addEventListener('click', loadMore); 10984 10985 initialLoad(); 10986 })(); 10987 </script>
10987 10988</section> 10989 10990 10991</div></div> 10992 <div id='easylockdown404' style='display:none;'><div class="easylockdown404-content-container"><div class="easylockdown404-content-wrapper"><div class="easylockdown404-title-holder"><span class="easylockdown-title-404"></span></div><div class="easylockdown404-content-holder rte"><div class="easylockdown-message-404"></div></div></div></div></div> 10993 10994<div id="easylockdown-password-form" style="display: none;"> 10995 <div id="easylockdown-wrapper"> 10996 10997 10998 <div class="easylockdown-form-holder"> 10999 <div id="easylockdown-password-error">Invalid password</div> 11000 <input type="password" placeholder="" id="easylockdown-password" 11001 onkeypress="if( event.keyCode == 13 && typeof easylockdown == 'object' && typeof easylockdown.checkUnlockPassword == 'function' ) { event.preventDefault(); easylockdown.checkUnlockPassword(this); }" /> 11002 <a href="javascript:void(0);" id="easylockdown-password-form-button" onclick="if( typeof easylockdown == 'object' && typeof easylockdown.checkUnlockPassword == 'function' ) easylockdown.checkUnlockPassword(this);">Enter</a> 11003 </div> 11004 </div> 11005</div> 11006 11007
11007<script type="text/javascript" id='easylockdown-helper'> 11008 var easylockdownLoaded = false; 11009 document.addEventListener('easylockdown_loaded', function() { 11010 easylockdownLoaded = true; 11011 easylockdown.clientContentToggle(true); 11012 }, {once: true}); 11013 document.addEventListener('DOMContentLoaded', function() { 11014 setTimeout(function() { 11015 if(!easylockdownLoaded) { for(var blocks=document.querySelectorAll("#easylockdown-password-form, #easylockdown-hpbtn-style, .easylockdown-auto-hl-styles, .easylockdown-custom-hl-styles, #easylockdown404"),_easylockdownElementIndex=0;_easylockdownElementIndex<blocks.length;_easylockdownElementIndex++)blocks[_easylockdownElementIndex].remove(); 11016 var elContent = document.querySelector('.easylockdown-content') 11017 if(elContent) { 11018 elContent.removeAttribute('style'); 11019 } 11020 var elStyle = document.getElementById('easylockdown-plugin-style'); 11021 if(elStyle) { 11022 elStyle.remove(); 11023 } 11024 console.info("EasyLockdown is not loaded"); 11025 } 11026 }, 350); 11027 }); 11028 </script>
11028 11029 11030 11031 11032 11033 <div id="shopify-section-footer" class="shopify-section"><footer class="bg-light-tan mt-8 lg:mt-12"> 11034 <div class="bg-sand rounded-3xl py-14 lg:py-24 middle-footer"> 11035 <div class="site-container"> 11036 <div class="grid lg:grid-cols-[1fr_2fr] lg:gap-6"> 11037 <h3 class="hidden lg:block text-[1.5rem] lg:text-[1.75rem] text-brown body-regular !leading-tight max-w-sm">The worldâs first prebiotic toothpaste. Try it today!</h3> 11038 <div class="grid lg:grid-cols-2 lg:gap-6 lg:justify-between lg:items-start"> 11039 <div class="grid grid-cols-2 order-2 mt-8 lg:order-1 lg:mt-0"> 11040 11041 11042 <div class="grid content-start"> 11043 <p class="tag mt-5 mb-2 lg:mb-5 lg:mt-0">Shop </p> 11044 11045 11046 <a href="https://revitin.com/products/revitin-natural-toothpaste" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Revitin Toothpaste</a> 11047 11048 11049 11050 11051 <a href="/pages/about" class="text-brown my-1 lg:hover:underline transition-all max-w-max">About Us</a> 11052 11053 11054 11055 11056 <a href="/pages/ingredients" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Ingredients</a> 11057 11058 11059 11060 11061 <a href="/pages/about/#meet-dr-gerry" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Meet Dr. Gerry</a> 11062 11063 11064 11065 11066 <a href="/blogs/all" class="text-brown my-1 lg:hover:underline transition-all max-w-max">The Science</a> 11067 11068 11069 11070 11071 <a href="/pages/ingredients" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Made in the USA</a> 11072 11073 11074 11075 11076 <a href="/pages/press" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Press</a> 11077 11078 11079 11080 <a href="/pages/review" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Reviews</a> 11081 <a href="/pages/faqs" class="text-brown my-1 lg:hover:underline transition-all max-w-max">FAQ</a> 11082 </div> 11083 11084 11085 <div class="grid content-start"> 11086 <p class="tag mt-5 mb-2 lg:mb-5 lg:mt-0">Orders</p> 11087 11088 11089 <a href="https://ui.awin.com/merchant-profile/89339" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Affiliates</a> 11090 11091 11092 11093 11094 <a href="/pages/shipping-policy" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Shipping Policy</a> 11095 11096 11097 11098 11099 <a href="/pages/return-and-refund-policy" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Return & Refund Policy</a> 11100 11101 11102 11103 11104 <a href="/pages/contact-us" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Contact Us</a> 11105 11106 11107 11108 11109 <a href="/pages/wholesale" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Wholesale</a> 11110 11111 11112 <a href="/pages/partner-with-us-professionally" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Professional Partnerships</a> 11113 11114 11115 11116 <a href="https://revitin.com/account" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Account</a> 11117 11118 11119 11120 <a href="/pages/review" class="text-brown my-1 lg:hover:underline transition-all max-w-max">Reviews</a> 11121 <a href="/pages/faqs" class="text-brown my-1 lg:hover:underline transition-all max-w-max">FAQ</a> 11122 </div> 11123 11124 </div> 11125 11126 <div class="flex flex-col order-1 lg:order-2"> 11127 <newsletter-form 11128 data-list-id="RCUMMs" 11129 data-loading-text="Submitting..." 11130 data-success-text=""> 11131 <div class="grid content-start order-1 lg:order-2">
11132 <span class="tag mb-2 lg:mb-5">Newsletter</span> 11133 <p class="text-brown">Receive special offers and first look at new products!</p> 11134 <div class="klaviyo-form-UR9w6e"></div> 11135 11136 <p class="success hidden text-sm mt-2">Successfully subscribed.</p> 11137 <p class="error hidden text-sm mt-2">Oops! There was an error submitting. Please try again.</p> 11138 </div> 11139 </newsletter-form> 11140 </div> 11141 </div> 11142 </div> 11143 </div> 11144 </div> 11145 <div class="bg-light-tan site-container w-full py-6 lg:py-2 lg:grid lg:grid-cols-4 lg:gap-6 footer-wrapper"> 11146 <div class="grid items-center lg:grid-flow-col lg:gap-8 lg:justify-start lg:col-span-2"> 11147 <a href="/"> 11148 <div class="w-[120px] lg:w-[140px] -ml-3.5 lg:-ml-4"> 11149 <svg xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 504 232.3" style="enable-background:new 0 0 504 232.3" xml:space="preserve" fill="currentColor"> 11150 <path d="M132.33 157.14c0 1.5-1.12 2.24-3.24 2.24h-10.72c-3.86 0-5.85-1.62-8.35-4.61l-30.78-36.14v30.28c0 5.36 6.23 4.36 6.23 8.47 0 1-.87 1.99-2.49 1.99H60.79c-1.62 0-2.49-1-2.49-1.99 0-3.61 6.36-2.99 6.36-8.47V82.36c0-5.36-6.36-4.36-6.36-8.47 0-1 1-1.99 2.49-1.99h29.79c24.42 0 35.89 9.22 35.89 23.68 0 11.84-8.35 21.44-32.28 22.93 3.12.87 5.24 2.37 7.23 4.49l20.81 23.93c5.74 6.47 10.1 6.47 10.1 10.21zm-53.09-44.37c2.37.37 5.11.5 7.6.5 16.07 0 23.68-5.86 23.68-17.07 0-11.46-6.6-18.32-23.43-18.32h-3.86c-2.62 0-3.99 1.37-3.99 3.61v31.28zM131.8 129.35c0-18.57 11.96-31.53 29.17-31.53 15.58 0 24.8 10.59 24.8 21.56 0 5.24-1.99 6.98-5.86 6.98h-35.64c.38 15.08 8.85 23.43 21.56 23.43 12.09 0 16.07-7.85 19.32-7.85 1.24 0 1.87 1.25.99 3.49-3.37 9.1-12.34 15.45-24.67 15.45-16.7 0-29.67-11.97-29.67-31.53zm37.02-8.85c2.37 0 3.62-1.12 3.62-3.37 0-6.98-3.37-13.58-12.46-13.58-8.6 0-14.83 5.86-15.57 16.95h24.41zM250.55 100.81c0 2.37-4.86 4.48-7.1 10.09l-19.19 46.36c-1.12 2.49-3.12 3.62-5.23 3.62-2.12 0-4.12-1.12-5.11-3.62l-19.07-46.23c-2.49-5.74-7.23-7.85-7.23-10.09 0-1 .75-1.62 2.12-1.62h22.56c1.24 0 1.87.63 1.87 1.5 0 2.37-5.36 3.74-5.36 7.98 0 1 .25 1.99.74 3.24l12.71 33.4 13.34-33.28c.5-1.37.74-2.37.74-3.49 0-3.99-4.86-5.86-4.86-7.98 0-.87.63-1.37 1.87-1.37h15.45c1.13-.01 1.75.62 1.75 1.49zM255.02 157.26c0-3.24 5.73-2.99 5.73-6.35v-36.27c0-4.49-6.85-3.24-6.85-6.85 0-1 .74-1.87 1.99-2.49l13.71-6.85c2.74-1.37 4.49-.38 4.49 2.24v50.22c0 3.36 5.6 3.11 5.6 6.35 0 1.12-1.12 2.12-2.62 2.12H257.5c-1.48 0-2.48-1-2.48-2.12zm1.37-77.51c0-5.11 4.24-9.35 9.48-9.35 5.11 0 9.34 4.24 9.34 9.35 0 5.24-4.23 9.47-9.34 9.47-5.24 0-9.48-4.24-9.48-9.47zM295.13 145.42v-37.39c0-2.24-1.24-3.49-3.49-3.49h-4.24c-3.24 0-4.24-2.74-1.62-4.86l18.44-15.08c2.12-1.87 4.24-1 4.24 1.87v12.84h18.7c1.49 0 2.24.75 2.24 2.12v1.74c0 1.37-.75 2.12-2.24 2.12h-18.7v40c0 5.49 2.37 7.6 7.98 7.6 5.11 0 7.85-1.37 9.47-1.37 1.12 0 1.62.62 1.62 1.49 0 3.49-8.6 7.85-17.57 7.85-9.34.02-14.83-4.6-14.83-15.44zM334.38 157.26c0-3.24 5.73-2.99 5.73-6.35v-36.27c0-4.49-6.85-3.24-6.85-6.85 0-1 .75-1.87 1.99-2.49l13.71-6.85c2.74-1.37 4.49-.38 4.49 2.24v50.22c0 3.36 5.61 3.11 5.61 6.35 0 1.12-1.12 2.12-2.62 2.12h-19.57c-1.49 0-2.49-1-2.49-2.12zm1.37-77.51c0-5.11 4.24-9.35 9.47-9.35 5.11 0 9.35 4.24 9.35 9.35 0 5.24-4.24 9.47-9.35 9.47a9.47 9.47 0 0 1-9.47-9.47zM432.44 157.26c0 1.12-.87 2.12-2.49 2.12h-19.57c-1.62 0-2.49-1-2.49-2.12 0-3.12 5.6-2.99 5.6-5.98v-30.91c0-9.59-2.99-12.96-10.71-12.96-4.49 0-9.6 1-15.58 3.74v40.13c0 2.74 5.61 2.87 5.61 5.98 0 1.12-.87 2.12-2.49 2.12h-19.69c-1.62 0-2.49-1-2.49-2.12 0-2.99 5.61-3.12 5.61-5.98v-36.51c0-4.61-6.73-3.62-6.73-6.85 0-.87.75-1.75 1.99-2.49l13.71-6.98c2.12-1.25 4.49-.62 4.49 2.24v5.36c7.85-4.98 17.45-8.22 24.93-8.22 9.97 0 14.7 5.73 14.7 16.08v37.39c-.01 2.72 5.6 2.97 5.6 5.96z"/> 11151 <path d="M447.66 76.53c.75.08 1.52.07 2.26.26.42.11.85.15 1.26.28.63.2 1.26.44 1.88.7.48.2.95.42 1.39.69.6.36 1.19.74 1.74 1.18.58.46 1.12.96 1.64 1.48.63.64 1.2 1.34 1.65 2.12.35.6.72 1.19 1.01 1.82.48 1.01.84 2.06 1.05 3.16.12.61.23 1.21.26 1.83.01.2.02.39.04.59.01.01.02.03.02.04v1.08c-.01.01-.02.03-.03.04-.02.88-.13
111511.75-.32 2.61-.22.98-.53 1.92-.93 2.84-.45 1.03-1.01 1.99-1.71 2.87-.41.52-.84 1.04-1.3 1.51-.69.7-1.44 1.35-2.29 1.87-.6.37-1.21.74-1.84 1.05-.52.26-1.08.45-1.63.65-.45.16-.91.29-1.37.4-.4.1-.8.14-1.2.22-1.01.19-2.03.16-3.05.14-.42-.01-.84-.08-1.26-.15-.56-.09-1.12-.18-1.66-.34-.73-.22-1.45-.47-2.15-.77-.49-.21-.96-.49-1.42-.75-.39-.23-.78-.47-1.15-.72-.32-.22-.62-.46-.91-.72-.32-.28-.65-.56-.94-.87-.68-.7-1.31-1.44-1.84-2.26-.41-.63-.78-1.27-1.1-1.96-.34-.75-.66-1.51-.84-2.32-.16-.72-.31-1.43-.44-2.15-.04-.22-.03-.46-.05-.68l-.03-.48c0-.08 0-.15.01-.23v-.97c.06-.58.08-1.17.19-1.74.15-.78.33-1.55.57-2.31.2-.64.49-1.25.78-1.85.43-.9.98-1.72 1.59-2.51.5-.65 1.05-1.25 1.66-1.8.55-.49 1.15-.95 1.76-1.37.48-.33.99-.6 1.5-.89.63-.35 1.3-.63 1.99-.84.45-.14.9-.27 1.36-.37.57-.12 1.15-.22 1.73-.3.35-.05.7-.06 1.05-.08.08-.01.15-.01.23-.02h.63c.06.01.13.01.21.02zm12.37 14.07c-.01-.03-.02-.05-.02-.08 0-.16.01-.33-.01-.49-.06-.45-.13-.89-.23-1.33-.12-.53-.23-1.07-.41-1.58-.23-.63-.51-1.24-.8-1.84-.2-.42-.43-.83-.69-1.21-.35-.5-.75-.96-1.13-1.44-.48-.6-1.07-1.1-1.67-1.57-.67-.53-1.37-.99-2.15-1.34-.58-.27-1.17-.54-1.77-.74a12.57 12.57 0 0 0-3.44-.62c-.04-.01-.08-.02-.11-.03-.04 0-.08 0-.11.01h-.78c-.06.01-.13.01-.19.02-.18.01-.36.02-.53.04-.61.08-1.23.12-1.83.28-.76.2-1.5.46-2.23.75-.72.29-1.4.69-2.04 1.13-.88.61-1.68 1.31-2.39 2.11-.55.61-1.03 1.27-1.45 1.97-.5.82-.9 1.7-1.19 2.61-.33 1.01-.55 2.05-.59 3.1-.04.83-.01 1.66.07 2.49.06.64.23 1.28.39 1.91.32 1.21.85 2.33 1.51 3.38.42.67.89 1.3 1.45 1.87.46.46.93.93 1.43 1.34.71.58 1.48 1.09 2.32 1.47.58.26 1.17.53 1.78.73.65.21 1.32.35 2 .48.4.08.81.08 1.22.11.01 0 .03 0 .04-.01h1.38c.01 0 .03 0 .04.01.21-.01.43 0 .64-.04.62-.11 1.24-.24 1.85-.37.7-.15 1.36-.42 2.01-.71.72-.32 1.41-.7 2.06-1.15.76-.52 1.47-1.11 2.08-1.81.46-.53.93-1.07 1.33-1.66.36-.53.65-1.11.95-1.69.36-.7.61-1.44.8-2.19.21-.83.37-1.68.4-2.54.01-.03.01-.05.02-.08v-1.27c-.01 0-.01-.01-.01-.02zM432.4 90.6v.34c.01-.12 0-.23 0-.34z"/><path class="st0" d="M432.41 91.57c0 .08 0 .15-.01.23 0-.08.01-.16.01-.23zM446.8 76.51c-.08.01-.15.01-.23.02.08-.01.15-.01.23-.02zM447.66 76.53c-.08-.01-.15-.02-.23-.02.08.01.15.01.23.02zM461.86 90.67a.076.076 0 0 1-.02-.04c0 .02.01.03.02.04zM461.84 91.8c.01-.01.02-.03.03-.04-.02.01-.02.03-.03.04zM447.7 78.36h-.11v-.03c.03.01.07.02.11.03zM446.69 78.35c-.06.01-.13.01-.19.02.06-.01.12-.02.19-.02zM460.01 91.98v-.08h.02c-.01.03-.02.06-.02.08zM460 90.6c0-.03 0-.05.01-.08.01.03.02.05.02.08H460zM447.58 78.33v.03c-.04-.01-.08-.02-.12-.02.05 0 .08 0 .12-.01zM446.84 78.34h-.08.08zM460 90.6h.03v.04c-.01-.02-.02-.03-.03-.04z"/><path class="st0" d="M460.03 91.91h-.02c.01-.01.02-.03.03-.04-.01.01-.01.02-.01.04zM446.42 104.13c.01 0 .03 0 .04-.01-.01.01-.02.01-.04.01zM447.84 104.13c.01 0 .03 0 .04.01-.01-.01-.02-.01-.04-.01zM447.73 83.5c.03.01.07.03.1.03.8 0 1.57.12 2.31.41.85.33 1.59.82 2.09 1.62.35.56.56 1.16.62 1.81.04.45.07.91.03 1.35-.06.71-.25 1.39-.68 1.99-.53.77-1.24 1.29-2.09 1.66-.01 0-.02.02-.04.04.12.24.25.49.38.73l1.17 2.16c.52.97 1.05 1.94 1.57 2.91.12.21.23.43.34.65.01.03.01.07.01.11l-.03.03c-.95 0-1.89 0-2.84-.01-.01-.01-.02-.02-.03-.02-.19-.36-.38-.73-.58-1.09-.16-.31-.33-.61-.49-.91-.3-.57-.6-1.15-.89-1.72-.29-.55-.58-1.1-.86-1.65-.09-.17-.18-.35-.26-.52-.01-.01-.02-.02-.03-.02-.58 0-1.17-.01-1.75-.01-.4 0-.8.01-1.19.01l-.03.03v.14c0 .04-.01.
1115109-.01.13v5.36c0 .04.01.09.01.13 0 .05-.01.1-.01.15-.01.01-.02.02-.04.03h-2.61l-.03-.03c0-.06-.01-.12-.01-.19V83.72c0-.08-.07-.22.11-.22.06.01.11.02.17.02h5.34c.04 0 .07-.01.11-.01h.1c.01-.02.02-.02.04-.01zm-3.16 7.32.03.03h2.99c.16-.01.34.01.49-.04.35-.11.69-.24 1.02-.4.49-.23.78-.65.95-1.14.18-.5.19-1.02.12-1.54-.07-.5-.24-.95-.6-1.3-.53-.51-1.18-.7-1.9-.72-.01-.01-.03-.01-.04-.02-1.01 0-2.02 0-3.03-.01l-.03.03v.37c0 .07-.01.14-.01.2v4.12c0 .07.01.14.01.2v.22zM447.59 83.48c-.04 0-.07.01-.11.01h-5.34c-.06 0-.11-.01-.17-.02.06-.01.12-.02.18-.02h5.24c.07 0 .13.02.2.03z"/><path class="st0" d="M444.56 98.83c0-.04-.01-.09-.01-.13v-5.36c0-.04.01-.09.01-.13.01.06.03.12.03.18v5.26c0 .06-.02.12-.03.18zM444.57 93.07l.03-.03-.03.03zM447.54 93.05c.01.01.02.02.03.02-.01-.01-.02-.02-.03-.02zM447.73 83.5c-.01 0-.02-.01-.03-.01 0 0 .01 0 .03.01zM441.87 98.98l.03.03c-.01-.02-.02-.03-.03-.03zM444.51 99c.01-.01.02-.02.04-.03-.01.02-.02.03-.04.03zM450.66 98.97c.01.01.02.02.03.02-.01 0-.02-.01-.03-.02zM453.53 99l.03-.03-.03.03zM444.56 86.07c.01.05.03.11.03.16v4.21c0 .05-.02.11-.03.16 0-.07-.01-.14-.01-.2v-4.12c0-.07.01-.14.01-.21zM444.57 90.82l.03.03-.03-.03zM447.54 90.85h.04-.04zM447.66 85.7c-.01-.01-.03-.01-.04-.02.01 0 .03.01.04.02zM444.59 85.67l-.03.03c.02-.01.02-.02.03-.03z"/> 11152 </svg> 11153 </div> 11154 </a> 11155 11156 <p class="text-brown opacity-50 text-sm">© 2026, Revitin</p> 11157 </div> 11158 <div class="flex justify-start gap-6 mt-5 lg:mt-0 lg:items-center lg:col-span-2"> 11159 <a data-acsb-custom-trigger="true" href="" class="text-brown lg:hover:underline"> 11160 Accessibility 11161 </a> 11162 <a href="/pages/privacy-policy" class="text-brown lg:hover:underline">Privacy Policy</a> 11163 <a href="/pages/terms-of-use" class="text-brown lg:hover:underline">Terms of Service</a> 11164 </div> 11165 </div> 11166 <div class="w-full h-1.5 bg-olive rounded-lg"></div> 11167</footer> 11168 11169 11170<style> 11171 .grid.grid-cols-2 > div:nth-child(2) a:nth-last-child(-n+2) { 11172 display: none; 11173 } 11174 11175 .klaviyo-form-UR9w6e > div > form { 11176 max-width: none !important; 11177 } 11178 11179 .klaviyo-form-UR9w6e > div > form > div { 11180 min-height: 68px !important; 11181 } 11182 11183 .klaviyo-form-UR9w6e input[name="email"]{ 11184 background-color: transparent !important; 11185 outline: none !important; 11186 border: none !important; 11187 font-size: 14px !important; 11188 color: #5f471d !important; 11189 height: 45px !important; 11190 } 11191 11192 .klaviyo-form-UR9w6e button[type="button"]{ 11193 font-size: 14px !important; 11194 height: 45px !important; 11195 color: #5f471d !important; 11196 font-weight: 500; 11197 padding: 0px 26px !important; 11198 background: rgb(250, 223, 170) !important; 11199 } 11200 11201 .klaviyo-form-UR9w6e div[data-testid="form-row"] { 11202 border: 1px solid #5f471d; 11203 border-radius: 6px; 11204 position: relative; 11205 background: transparent !important; 11206 transition: border-color 0.2s ease-out; 11207 } 11208 11209 /* Hide the default placeholder */ 11210 .klaviyo-form-UR9w6e input[name="email"]::placeholder { 11211 color: transparent !important; 11212 } 11213 11214 /* Style the label for floating effect */ 11215 .klaviyo-form-UR9w6e .klaviyo-sr-only { 11216 position: absolute !important; 11217 left: 16px !important; 11218 top: 50% !important; 11219 transform: translateY(-50%) !important; 11220 width: auto !important; 11221 height: auto !important; 11222 clip: auto !important; 11223 white-space: nowrap !important; 11224 background: transparent !important; 11225 padding: 0 4px !important; 11226 font-size: 14px !important; 11227 color: #5f471d !important; 11228 opacity: 0.7 !important; 11229 transition: all 0.2s ease-out !important; 11230 pointer-events: none !important; 11231 z-index: 1 !important; 11232 line-height: 1 !important; 11233 margin: 0 !important; 11234 font-weight: normal !important; 11235 } 11236 11237 /* Move the label up on focus or when input has content */ 11238 .klaviyo-form-UR9w6e div[data-testid="form-row"]:focus-within .klaviyo-sr-only, 11239 .klaviyo-form-UR9w6e input[name="email"]:not(:placeholder-shown) ~ .klaviyo-sr-only { 11240 top: 0 !important; 11241 transform: translateY(-50%) !important; 11242 font-size: 10px !important; 11243 opacity: 1 !important; 11244 background: #f7eede !important; 11245 } 11246 11247 /* Alternative approach using has-content detection */ 11248 .klaviyo-form-UR9w6e input[name="email"]:focus + .klaviyo-sr-only, 11249 .klaviyo-form-UR9w6e input[name="email"]:not(:placeholder-shown) + .klaviyo-sr-only { 11250 top: 0 !important; 11251 transform: translateY(-50%) !important; 11252 font-size: 10px !important; 11253 opacity: 1 !important; 11254 } 11255 11256 .klaviyo-form-UR9w6e div[data-testid="form-row"]:focus-within { 11257 border-color: #8b6b3c; 11258 } 11259 11260 .klaviyo-form-UR9w6e div[data-testid="form-row"] > div[data-testid="form-component"] { 11261 margin: 0 !important; 11262 padding: 0 !important; 11263 background: transparent !important; 11264 } 11265 11266 .klaviyo-form-UR9w6e div[data-testid="form-row"] > :nth-child(2) { 11267 border-radius: 6px; 11268 } 11269 11270 /* Make sure the input container is transparent */ 11271 .klaviyo-form-UR9w6e div[data-testid="form-component"] { 11272 background: transparent !important; 11273 } 11274 11275 /* Ensure the label stays transparent */ 11276 .klaviyo-form-UR9w6e label { 11277 background: #f7eede !important; 11278 } 11279 11280 /* THANK YOU MESSAGE STYLES */ 11281 11282 /* Remove borders from form rows when they contain the thank you message */
11283 .klaviyo-form-UR9w6e div[data-testid="form-row"]:has(div[id*="rich-text"]) { 11284 border: none !important; 11285 padding: 0 !important; 11286 margin: 0 !important; 11287 } 11288 11289 /* Style the thank you heading */ 11290 .klaviyo-form-UR9w6e div[id*="rich-text"] h1 { 11291 font-size: 28px !important; 11292 color: #8b6b3c !important; 11293 font-family: Nunito-Sans-Klaviyo-Hosted, Arial, 'Helvetica Neue', Helvetica, sans-serif !important; 11294 font-weight: bold !important; 11295 margin: 0 0 10px 0 !important; 11296 line-height: 1.2 !important; 11297 text-align: center !important; 11298 } 11299 11300 /* Style the thank you paragraph */ 11301 .klaviyo-form-UR9w6e div[id*="rich-text"] p { 11302 font-size: 20px !important; 11303 color: #8b6b3c !important; 11304 font-family: Nunito-Sans-Klaviyo-Hosted, Arial, 'Helvetica Neue', Helvetica, sans-serif !important; 11305 font-weight: 400 !important; 11306 margin: 0 !important; 11307 line-height: 1.4 !important; 11308 text-align: center !important; 11309 } 11310 11311 /* Remove borders from the entire form when thank you message is present */ 11312 .klaviyo-form-UR9w6e:has(div[id*="rich-text"]) div[data-testid="form-row"] { 11313 border: none !important; 11314 } 11315 11316 /* Target specific rich text containers */ 11317 .klaviyo-form-UR9w6e div[id="rich-text-01KJ4FNR00PK140PYQ20F5ZABH"], 11318 .klaviyo-form-UR9w6e div[id="rich-text-01KJ4FNR07P6Q6AMF9BGB48XH8"] { 11319 padding: 0 !important; 11320 margin: 0 !important; 11321 } 11322 11323 /* Remove any background colors from thank you message */ 11324 .klaviyo-form-UR9w6e div[id*="rich-text"] * { 11325 background: transparent !important; 11326 color: #8b6b3c !important; 11327 } 11328 11329 /* Adjust spacing for thank you message */ 11330 .klaviyo-form-UR9w6e:has(div[id*="rich-text"]) { 11331 padding: 20px !important; 11332 } 11333 11334 /* Remove borders from form rows containing rich text */ 11335 .klaviyo-form-UR9w6e div[data-testid="form-row"]:has(.go3176171171) { 11336 border: none !important; 11337 } 11338 @media (max-width: 1024px) { 11339 .footer-wrapper{ 11340 padding-bottom: 100px; 11341 } 11342 } 11343</style> 11344
11345<script> 11346(function(){ 11347 var s = document.createElement('script'); 11348 var h = document.querySelector('head') || document.body; 11349 s.src = 'https://acsbapp.com/apps/app/dist/js/app.js'; 11350 s.async = true; 11351 s.onload = function(){ 11352 acsbJS.init({ 11353 hideWidget: true 11354 }); 11355 }; 11356 h.appendChild(s); 11357})(); 11358</script>
11358 11359 11360 11361 11362 11363 11364</div> 11365 11366 </main><site-cart> 11367 <div class="site-cart fixed w-full top-0 right-0 bottom-0 opacity-0 invisible z-[100] transition-all"> 11368 <div class="bg-light-tan flyout__content absolute overflow-hidden w-full right-0 top-[6px] bottom-0 z-20 translate-x-[100%] transition-all duration-300 max-w-[500px] lg:shadow-md lg:rounded-l-xl"> 11369 <div class="cart__container h-full grid grid-rows-[auto_1fr_auto]"><div id="shopify-section-main-cart-header" class="shopify-section"><div class="site-container"> 11370 <div 11371 id="main-cart-header" 11372 class="relative flex justify-between items-center w-full bg-light-tan text-primary main-cart-header mt-5" 11373 > 11374 <div class="flex justify-between gap-3 items-center text-primary heading"> 11375 <h3 class="text-xl lg:text-xl font-heading tracking-tight">Your Cart</h3> 11376 </div> 11377 <cart-toggle> 11378 <button 11379 id="close-menu" 11380 class="w-6 h-6 flex items-center justify-end bg-transparent border-0 cursor-pointer text-white lg:w-8 lg:h-8" 11381 ><svg 11382 class="w-4" 11383 width="20" 11384 height="20" 11385 viewBox="0 0 20 20" 11386 fill="none" 11387 xmlns="http://www.w3.org/2000/svg"> 11388 <rect 11389 x="1.51471" 11390 y="0.100586" 11391 width="26" 11392 height="2" 11393 rx="1" 11394 transform="rotate(45 1.51471 0.100586)" 11395 fill="#5F471D" /> 11396 <rect 11397 x="0.100525" 11398 y="18.4854" 11399 width="26" 11400 height="2" 11401 rx="1" 11402 transform="rotate(-45 0.100525 18.4854)" 11403 fill="#5F471D" /> 11404</svg></button> 11405 </cart-toggle> 11406 </div> 11407</div> 11408 11409<style> 11410 .main-cart-header { 11411 padding: 12px 0 12px 0; 11412 border-bottom: 1px solid rgb(95 71 29 / 30%); 11413 } 11414 .max-w-\[500px\] { 11415 max-width: 500px; 11416 } 11417 .shipping-text { 11418 font-weight: bold; 11419 letter-spacing: 1.4px; 11420 margin-bottom: 7px; 11421 display: inline-block; 11422 } 11423 11424 .free-shipping-banner { 11425 background-color: #F7EEDE; 11426 padding: 16px 16px 2px 16px; 11427 border-radius: 4.66px; 11428 margin-top: 1rem; 11429 font-family: sans-serif; 11430 color: #5c4521; 11431 display: flex; 11432 gap: 1rem; 11433 justify-content: space-between; 11434 } 11435 11436 .icon-and-text { 11437 display: flex; 11438 align-items: center; 11439 gap: 10px; 11440 font-weight: 600; 11441 font-size: 15px; 11442 margin-bottom: 10px; 11443 width: max-content; 11444 } 11445 11446 .truck-icon { 11447 font-size: 20px; 11448 } 11449 11450 .progress-bar { 11451 position: relative; 11452 background-color: #f4e2bb; 11453 height: 6px; 11454 border-radius: 999px; 11455 margin-bottom: 8px; 11456 } 11457 11458 .progress-fill { 11459 background-color: #f6b439; 11460 height: 100%; 11461 width: 60%; /* Adjust this width based on cart amount */ 11462 } 11463 11464 .progress-dot { 11465 position: absolute; 11466 top: 50%; 11467 left: 60%; 11468 transform: translate(-50%, -50%); 11469 width: 14px; 11470 height: 14px; 11471 background-color: #f6b439; 11472 border-radius: 50%; 11473 } 11474 11475 .shipping-status { 11476 text-align: right; 11477 font-size: 13px; 11478 color: #8c6f4e; 11479 } 11480 11481 @media screen and (max-width: 324px) { 11482 .subscription-options { 11483 padding: 0px 6px 0px 5px !important; 11484 } 11485 } 11486 11487</style> 11488 11489 11490</div><div id="shopify-section-main-cart-items" class="shopify-section"><div id="main-cart-items" class="cart__items site-container"><div class="grid content-center justify-items-center mx-auto gap-6 py-14 bg-light-tan"> 11491 <span class="heading-3">Your cart is empty</span> 11492 <a href="/products/revitin-natural-toothpaste" class="button button--gold"> Shop Revitin </a> 11493 </div><div style="display: none;" class="free_tote_loader"> 11494 <div class="free_tote_spinner"></div> 11495 </div> 11496</div> 11497
11498<script> 11499 document.addEventListener('DOMContentLoaded', function () { 11500 // Use event delegation for better Shopify compatibility 11501 document.body.addEventListener('click', function (e) { 11502 // Check if click originated from subscription title or its children 11503 const titleElement = e.target.closest('.subscription-title'); 11504 if (!titleElement) return; 11505 11506 e.preventDefault(); 11507 e.stopPropagation(); 11508 11509 const subscriptionBox = titleElement.closest('.cart-subscription-box'); 11510 const options = subscriptionBox.querySelector('.subscription-options'); 11511 const arrow = titleElement.querySelector('svg path'); 11512 const subscribeSmallTitle = subscriptionBox.querySelector('.subscribe-save-header'); 11513 11514 // Toggle the dropdown 11515 const isOpening = !options.classList.contains('active'); 11516 options.classList.toggle('active'); 11517 11518 // Update UI based on state 11519 if (isOpening) { 11520 arrow.setAttribute('transform', 'rotate(180 7.5 4)'); 11521 subscribeSmallTitle.style.display = 'block'; 11522 subscribeSmallTitle.style.marginTop = '10px'; 11523 options.style.padding = '2px 12px 12px 19px'; 11524 } else { 11525 arrow.removeAttribute('transform'); 11526 subscribeSmallTitle.style.display = 'none'; 11527 subscribeSmallTitle.style.marginTop = '0px'; 11528 options.style.padding = '0px'; 11529 } 11530 }); 11531 }); 11532 11533 const siteCart = document.querySelector('.site-cart'); 11534 11535 const CART_SUBSCRIPTION_UPSELL_PROPERTY = '_cart_subscription_upsell'; 11536 const CART_SUBSCRIPTION_UPSELL_ORIGINAL_VARIANT = '_cart_subscription_upsell_original_variant'; 11537 const TUBE_PLAN_UPGRADED_PROPERTY = '_tube_plan_upgraded'; 11538 const TUBE_PLAN_ORIGINAL_SELLING_PLAN = '_tube_plan_original_selling_plan'; 11539 const TRAVEL_PLAN_UPGRADED_PROPERTY = '_travel_plan_upgraded'; 11540 11541 function handleSubscriptionChange(e) { 11542 const button = e.target; 11543 if (!button) return; 11544 if (button.name !== 'selling_plan') return; 11545 11546 // Get the subscription container 11547 const subscriptionContainer = button.closest('.subscription-container'); 11548 if (!subscriptionContainer) return; 11549 11550 // Disable all inputs in the container 11551 const allInputs = subscriptionContainer.querySelectorAll('input'); 11552 allInputs.forEach((input) => (input.disabled = true)); 11553 11554 // Add skeleton loading class 11555 subscriptionContainer.classList.add('loading'); 11556 11557 const radio = button; 11558 const itemKey = radio.dataset.key; 11559 const variantId = radio.dataset.variantId; 11560 const quantity = radio.dataset.quantity; 11561 const sellingPlanId = radio.dataset.sellingPlanId; 11562 11563 // Preserve GWP marker (and related props) across selling-plan swaps 11564 fetch('/cart.js') 11565 .then((r) => r.json()) 11566 .then((cart) => { 11567 const existing = (cart.items || []).find((item) => item.key === itemKey); 11568 const nextProperties = { 11569 [CART_SUBSCRIPTION_UPSELL_PROPERTY]: 'true', 11570 }; 11571 if (existing && existing.properties) { 11572 if (existing.properties._gwp === 'back_to_school_minis') { 11573 nextProperties._gwp = existing.properties._gwp; 11574 nextProperties._gwp_source = existing.properties._gwp_source || 'pdp'; 11575 } 11576 if (existing.properties[CART_SUBSCRIPTION_UPSELL_ORIGINAL_VARIANT]) { 11577 nextProperties[CART_SUBSCRIPTION_UPSELL_ORIGINAL_VARIANT] = 11578 existing.properties[CART_SUBSCRIPTION_UPSELL_ORIGINAL_VARIANT]; 11579 } 11580 } 11581 // Cart â subscription: stamp GWP if cart has no marker yet (blocked templates / wholesale skipped) 11582 const gwpAllowed = 11583 window.RevitinGWP && 11584 window.RevitinGWP.enabled !== false && 11585 typeof window.RevitinGWP.getPdpGwpProperties === 'function'; 11586 if (gwpAllowed && !nextProperties._gwp) { 11587 const gwpProps = window.RevitinGWP.getPdpGwpProperties(cart);
11588 if (gwpProps) { 11589 Object.assign(nextProperties, gwpProps, { _gwp_source: 'cart' }); 11590 } 11591 } 11592 11593 return fetch('/cart/update.js', { 11594 method: 'POST', 11595 headers: { 11596 'Content-Type': 'application/json', 11597 }, 11598 body: JSON.stringify({ 11599 updates: { 11600 [itemKey]: 0, 11601 }, 11602 }), 11603 }).then(() => nextProperties); 11604 }) 11605 .then((nextProperties) => { 11606 // Then add the new item with updated subscription 11607 return fetch('/cart/add.js', { 11608 method: 'POST', 11609 headers: { 11610 'Content-Type': 'application/json', 11611 }, 11612 body: JSON.stringify({ 11613 items: [ 11614 { 11615 id: variantId, 11616 quantity: quantity, 11617 selling_plan: sellingPlanId, 11618 properties: nextProperties, 11619 }, 11620 ], 11621 }), 11622 }); 11623 }) 11624 .then((response) => response.json()) 11625 .then((cart) => { 11626 updateCartUI(cart); 11627 showToast('Subscription updated successfully!'); 11628 }) 11629 .catch((error) => { 11630 console.error('Error:', error); 11631 showToast('Error updating subscription', true); 11632 }) 11633 .finally(() => { 11634 // Re-enable inputs and remove loading state 11635 allInputs.forEach((input) => (input.disabled = false)); 11636 subscriptionContainer.classList.remove('loading'); 11637 }); 11638 } 11639 11640 function handleSwitchToOneTime(e) { 11641 const radio = e.target.closest('.switch-one-time-label').querySelector('.switch-one-time-input'); 11642 if (!radio) return; 11643 11644 const subscriptionContainer = radio.closest('.subscription-container'); 11645 const allInputs = subscriptionContainer ? subscriptionContainer.querySelectorAll('input') : []; 11646 allInputs.forEach((input) => (input.disabled = true)); 11647 if (subscriptionContainer) subscriptionContainer.classList.add('loading'); 11648 11649 const itemKey = radio.dataset.key; 11650 const variantId = radio.dataset.variantId; 11651 const quantity = radio.dataset.quantity; 11652 const sellingPlanId = radio.dataset.sellingPlanId; 11653 11654 if (sellingPlanId) { 11655 fetch('/cart/add.js', { 11656 method: 'POST', 11657 headers: { 11658 'Content-Type': 'application/json', 11659 Accept: 'application/json', 11660 }, 11661 body: JSON.stringify({ 11662 items: [ 11663 { 11664 id: parseInt(variantId, 10), 11665 quantity: parseInt(quantity, 10) || 1, 11666 selling_plan: parseInt(sellingPlanId, 10), 11667 }, 11668 ], 11669 }), 11670 }) 11671 .then(async (response) => { 11672 const addResult = await response.json(); 11673 if (response.status === 422) { 11674 throw new Error(addResult.description); 11675 } 11676 return fetch('/cart/update.js', { 11677 method: 'POST', 11678 headers: { 11679 'Content-Type': 'application/json', 11680 }, 11681 body: JSON.stringify({ 11682 updates: { 11683 [itemKey]: 0, 11684 }, 11685 }), 11686 }); 11687 }) 11688 .then((response) => response.json()) 11689 .then((cart) => { 11690 updateCartUI(cart); 11691 showToast('Subscription updated successfully!'); 11692 }) 11693 .catch((error) => { 11694 console.error('Error:', error); 11695 showToast('Error updating subscription', true); 11696 }) 11697 .finally(() => { 11698 allInputs.forEach((input) => (input.disabled = false)); 11699 if (subscriptionContainer) subscriptionContainer.classList.remove('loading'); 11700 }); 11701 return; 11702 } 11703 11704 // Remove the existing subscription item, then re-add it as a one-time purchase (no selling_plan) 11705 fetch('/cart/update.js', { 11706 method: 'POST', 11707 headers: { 11708 'Content-Type': 'application/json', 11709 }, 11710 body: JSON.stringify({ 11711 updates: { 11712 [itemKey]: 0, 11713 }, 11714 }), 11715 }) 11716 .then(() => { 11717 return fetch('/cart/add.js', { 11718 method: 'POST', 11719 headers: { 11720 'Content-Type': 'application/json', 11721 }, 11722 body: JSON.stringify({ 11723 items: [ 11724 { 11725 id: variantId, 11726 quantity: quantity, 11727 }, 11728 ], 11729 }), 11730 }); 11731 }) 11732 .then((response) => response.json()) 11733 .then((cart) => { 11734 updateCartUI(cart); 11735 showToast('Switched to one time purchase!'); 11736 }) 11737 .catch((error) => { 11738 console.error('Error:', error); 11739 showToast('Error switching to one time purchase', true); 11740 }) 11741 .finally(() => {
11742 allInputs.forEach((input) => (input.disabled = false)); 11743 if (subscriptionContainer) subscriptionContainer.classList.remove('loading'); 11744 }); 11745 } 11746 function syncCartFlyoutLayout() { 11747 const footer = document.querySelector('#shopify-section-main-cart-footer'); 11748 const cartContainer = document.querySelector('.cart__container'); 11749 if (!footer || !cartContainer) return; 11750 11751 const height = footer.offsetHeight + 10; 11752 cartContainer.style.paddingBottom = `${height}px`; 11753 11754 // Ensure the items column can shrink inside the grid so overflow scrolls 11755 const itemsSection = document.querySelector('#shopify-section-main-cart-items'); 11756 if (itemsSection) { 11757 itemsSection.style.minHeight = '0'; 11758 } 11759 } 11760 function updateCartUI(cart) { 11761 // Update cart count in header 11762 const cartCountElements = document.querySelectorAll('.cart-count, .js-cart-count'); 11763 if (cartCountElements) { 11764 cartCountElements.forEach((el) => { 11765 el.textContent = cart.item_count; 11766 el.classList.remove('hidden'); 11767 }); 11768 } 11769 11770 // Update both cart items AND cart footer sections 11771 Promise.all([ 11772 fetch('/?section_id=main-cart-items').then((r) => r.text()), 11773 fetch('/?section_id=main-cart-footer').then((r) => r.text()), 11774 ]).then(([itemsHtml, footerHtml]) => { 11775 // Parse responses 11776 const itemsDoc = new DOMParser().parseFromString(itemsHtml, 'text/html'); 11777 const footerDoc = new DOMParser().parseFromString(footerHtml, 'text/html'); 11778 11779 // Update cart items 11780 const newItemsContent = itemsDoc.getElementById('main-cart-items'); 11781 if (newItemsContent) { 11782 document.getElementById('main-cart-items').innerHTML = newItemsContent.innerHTML; 11783 } 11784 11785 // Update cart footer (including subtotal) 11786 const newFooterContent = footerDoc.getElementById('main-cart-footer'); 11787 if (newFooterContent) { 11788 document.getElementById('main-cart-footer').innerHTML = newFooterContent.innerHTML; 11789 } 11790 // Recalc space above absolute footer so upsells aren't clipped after first add 11791 requestAnimationFrame(() => { 11792 syncCartFlyoutLayout(); 11793 requestAnimationFrame(syncCartFlyoutLayout); 11794 }); 11795 }); 11796 } 11797 window.updateCartUI = updateCartUI; 11798 window.syncCartFlyoutLayout = syncCartFlyoutLayout; 11799 11800 function updateCartSummary() { 11801 fetch('/?section_id=cart-drawer') 11802 .then((response) => response.text()) 11803 .then((text) => { 11804 const html = new DOMParser().parseFromString(text, 'text/html'); 11805 const cartDrawer = document.getElementById('cart-drawer'); 11806 11807 if (cartDrawer) { 11808 cartDrawer.innerHTML = html.getElementById('cart-drawer').innerHTML; 11809 } 11810 }); 11811 } 11812 11813 function showToast(message, isError = false) { 11814 const toast = document.createElement('div'); 11815 toast.className = `fixed bottom-4 right-4 px-4 py-2 rounded shadow-lg ${ 11816 isError ? 'bg-red-500' : 'bg-sea-green' 11817 } text-white`; 11818 toast.textContent = message; 11819 document.body.appendChild(toast); 11820 11821 setTimeout(() => { 11822 toast.style.opacity = '0'; 11823 setTimeout(() => toast.remove(), 300); 11824 }, 3000); 11825 } 11826 11827 function formatShopifyPrice(priceInCents) { 11828 const price = priceInCents / 100; 11829 const formatted = price.toFixed(2); 11830 return formatted.endsWith('.00') ? price.toFixed(0) : formatted; 11831 } 11832 11833 // Event delegation for subscribe buttons 11834 document.getElementById('main-cart-items').addEventListener('click', async (e) => { 11835 const button = e.target.closest('.subscribe-btn-js'); 11836 if (!button) return; 11837 11838 const originalText = button.textContent; 11839 button.disabled = true; 11840 button.textContent = 'Subscribing...'; 11841 11842 const variantId = button.dataset.variantId; 11843 const quantity = button.dataset.quantity; 11844 const sellingPlanId = button.dataset.sellingPlan; 11845 const originalItemKey = button.dataset.key; 11846 const originalVariantId = button.dataset.originalVariantId; 11847 const originalSellingPlanId = button.dataset.originalSellingPlan; 11848 const isTubePlanSwitch = button.dataset.tubePlanSwitch === 'true'; 11849 const isTravelPlanSwitch = button.dataset.travelPlanSwitch === 'true'; 11850 11851 if (!variantId || !sellingPlanId) { 11852 console.error('Missing variant or selling plan for subscription upsell'); 11853 button.disabled = false;
11854 button.textContent = originalText; 11855 return; 11856 } 11857 11858 try { 11859 // First add the subscription item 11860 const addItem = { 11861 id: parseInt(variantId, 10), 11862 quantity: parseInt(quantity, 10) || 1, 11863 selling_plan: parseInt(sellingPlanId, 10), 11864 }; 11865 if (isTubePlanSwitch) { 11866 addItem.properties = { 11867 [TUBE_PLAN_UPGRADED_PROPERTY]: 'true', 11868 }; 11869 // Remember original 3-tube plan so Switch to 3-tubes restores that interval 11870 if (originalSellingPlanId) { 11871 addItem.properties[TUBE_PLAN_ORIGINAL_SELLING_PLAN] = String(originalSellingPlanId); 11872 } 11873 } else if (isTravelPlanSwitch) { 11874 addItem.properties = { 11875 [TRAVEL_PLAN_UPGRADED_PROPERTY]: 'true', 11876 }; 11877 } else { 11878 addItem.properties = { 11879 [CART_SUBSCRIPTION_UPSELL_PROPERTY]: 'true', 11880 }; 11881 // Single Tube upsells to 3 Tubes â remember original so OTP can revert 11882 if (originalVariantId) { 11883 addItem.properties[CART_SUBSCRIPTION_UPSELL_ORIGINAL_VARIANT] = String(originalVariantId); 11884 } 11885 } 11886 11887 // Stamp GWP on cart subscription upsell when allowed and not already marked 11888 try { 11889 if ( 11890 window.RevitinGWP && 11891 window.RevitinGWP.enabled !== false && 11892 typeof window.RevitinGWP.getPdpGwpProperties === 'function' 11893 ) { 11894 const cartBefore = await fetch('/cart.js').then((r) => r.json()); 11895 const gwpProps = window.RevitinGWP.getPdpGwpProperties(cartBefore);
11896 if (gwpProps) { 11897 addItem.properties = Object.assign({}, addItem.properties || {}, gwpProps, { 11898 _gwp_source: 'cart', 11899 }); 11900 } 11901 } 11902 } catch (_) {} 11903 11904 const addResponse = await fetch('/cart/add.js', { 11905 method: 'POST', 11906 headers: { 11907 'Content-Type': 'application/json', 11908 Accept: 'application/json', 11909 }, 11910 body: JSON.stringify({ 11911 items: [addItem], 11912 }), 11913 }); 11914 11915 const addResult = await addResponse.json(); 11916 if (addResponse.status === 422) { 11917 throw new Error(addResult.description); 11918 } 11919 11920 // Then remove the original non-subscription item 11921 const updateResponse = await fetch('/cart/update.js', { 11922 method: 'POST', 11923 headers: { 11924 'Content-Type': 'application/json', 11925 Accept: 'application/json', 11926 }, 11927 body: JSON.stringify({ 11928 updates: { 11929 [originalItemKey]: 0, 11930 }, 11931 }), 11932 }); 11933 11934 const updateResult = await updateResponse.json(); 11935 updateCartUI(updateResult); 11936 showToast('Subscription updated successfully!'); 11937 } catch (error) { 11938 console.error('Error:', error); 11939 const errorElement = document.createElement('div'); 11940 errorElement.className = 'text-red-500 text-xs mt-1'; 11941 errorElement.textContent = 'Error adding subscription. Please try again.'; 11942 button.parentNode.appendChild(errorElement); 11943 setTimeout(() => errorElement.remove(), 3000); 11944 } finally { 11945 button.disabled = false; 11946 button.textContent = originalText; 11947 } 11948 }); 11949 11950 function addToCartHandler(e) { 11951 e.preventDefault(); 11952 e.stopPropagation(); 11953 e.stopImmediatePropagation(); 11954 11955 const button = e.target.closest('.add-to-cart-btn') || e.target; 11956 const variantId = button.dataset.variantId; 11957 const sellingPlanId = button.dataset.sellingPlan; 11958 const isUpsell = button.dataset.upsell === 'true' || !!button.closest('.you-may-also-like'); 11959 11960 button.disabled = true; 11961 const originalText = button.textContent; 11962 button.textContent = 'Adding...'; 11963 11964 const itemData = { 11965 id: variantId, 11966 quantity: 1, 11967 }; 11968 11969 if (sellingPlanId) { 11970 itemData.selling_plan = sellingPlanId; 11971 } 11972 11973 if (isUpsell) { 11974 itemData.properties = { 11975 '_upsell-product': 'true', 11976 }; 11977 if (button.dataset.subscriptionUpsell === 'true') { 11978 itemData.properties[CART_SUBSCRIPTION_UPSELL_PROPERTY] = 'true'; 11979 } 11980 } 11981 11982 fetch('/cart/add.js', { 11983 method: 'POST', 11984 headers: { 11985 'Content-Type': 'application/json', 11986 }, 11987 body: JSON.stringify({ 11988 items: [itemData], 11989 }), 11990 }) 11991 .then((response) => response.json()) 11992 .then((data) => { 11993 if (data.description) throw new Error(data.description); 11994 showToast('Item added to cart!'); 11995 updateCartUI(data); 11996 }) 11997 .catch((error) => { 11998 console.error('Error:', error); 11999 showToast('Error adding item to cart', true); 12000 }) 12001 .finally(() => { 12002 button.disabled = false; 12003 button.textContent = originalText; 12004 }); 12005 } 12006 12007 // Initialize on DOM load 12008 document.addEventListener('DOMContentLoaded', function () { 12009 syncCartFlyoutLayout(); 12010 // Set up event delegation for any dynamically added add-to-cart buttons 12011 document.body.addEventListener('click', function (e) { 12012 if (e.target.closest('.add-to-cart-btn')) { 12013 addToCartHandler(e); 12014 } 12015 12016 if (e.target.closest('.option-label')) { 12017 handleSubscriptionChange(e); 12018 } 12019 12020 if (e.target.closest('.switch-one-time-label')) { 12021 handleSwitchToOneTime(e); 12022 } 12023 }); 12024 }); 12025 // Keep layout in sync when cart opens (empty â first item is the common failure case) 12026 document.addEventListener('click', function (e) { 12027 if (e.target.closest('cart-toggle') || e.target.closest('.site-cart')) { 12028 requestAnimationFrame(syncCartFlyoutLayout); 12029 } 12030 }); 12031</script>
12031 12032
12033<script> 12034 const TOTE_HANDLE = 'free-tote'; 12035 const freeProductLoader = document.querySelector(`.free_tote_loader`); 12036 12037 // --- CORE HELPERS (unchanged for stability) --- 12038 const fetchJSON = (url, options = {}) => 12039 fetch(url, { 12040 credentials: 'same-origin', 12041 headers: { 'Content-Type': 'application/json' }, 12042 ...options, 12043 }).then((res) => res.json()); 12044 const getCart = () => fetchJSON('/cart.js'); 12045 const isSubscriptionItem = (item) => item.selling_plan_allocation != null; 12046 const isToteItem = (item) => item.handle === TOTE_HANDLE || item.product_handle === TOTE_HANDLE; 12047 12048 let toteVariantId = null; 12049 async function getToteVariantId() { 12050 if (toteVariantId) return toteVariantId; 12051 const product = await fetchJSON(`/products/${TOTE_HANDLE}.js`); 12052 toteVariantId = product?.variants?.[0]?.id || null; 12053 return toteVariantId; 12054 } 12055 12056 // --- OPTIMIZED CART LOGIC --- 12057 let isProcessing = false; 12058 let lastCartState = null; 12059 12060 function updateUi(count, handle, action) { 12061 const cartCount = document.querySelector('.variety-cart-count'); 12062 const freeCartItem = document.querySelector(`.cart-item[data-handle=${handle}]`); 12063 12064 if (freeCartItem && action) { 12065 if (action === 'add') { 12066 freeCartItem.style.display = 'block'; 12067 } 12068 12069 if (action === 'remove') { 12070 freeCartItem.style.display = 'none'; 12071 } 12072 } 12073 cartCount.textContent = count ? count : 0; 12074 } 12075 12076 async function enforceToteRule() { 12077 // Prevent multiple simultaneous runs 12078 if (isProcessing) return; 12079 isProcessing = true; 12080 12081 console.log('EnforeRule Start'); 12082 12083 try { 12084 const cart = await getCart(); 12085 const cartStateKey = JSON.stringify(cart.items.map((i) => ({ id: i.id, q: i.quantity }))); 12086 12087 // Skip if cart state hasn't changed 12088 if (lastCartState === cartStateKey) { 12089 isProcessing = false; 12090 return; 12091 } 12092 lastCartState = cartStateKey; 12093 12094 const hasSubscription = cart.items.some(isSubscriptionItem); 12095 const toteItems = cart.items.filter(isToteItem); 12096 const hasTote = toteItems.length > 0; 12097 const toteNeedsNormalize = hasTote && (toteItems.length > 1 || toteItems[0].quantity > 1); 12098 12099 let action = null; 12100 if (hasSubscription && !hasTote) action = 'add'; 12101 else if (hasSubscription && toteNeedsNormalize) action = 'normalize'; 12102 else if (!hasSubscription && hasTote) action = 'remove'; 12103 12104 function whenElementReady(selector, callback, timeout = 5000) { 12105 const start = Date.now(); 12106 12107 (function check() { 12108 const el = document.querySelector(selector); 12109 if (el) { 12110 callback(el); 12111 return; 12112 } 12113 if (Date.now() - start < timeout) { 12114 requestAnimationFrame(check); 12115 } 12116 })(); 12117 } 12118 12119 function applyFreeProductStyle(action) { 12120 if (action !== 'add') return; 12121 12122 whenElementReady('.free_tote_loader', function (loader) { 12123 loader.setAttribute( 12124 'style', 12125 'display: flex; align-items: center; justify-content: center; margin-top: 12px;' 12126 ); 12127 }); 12128 } 12129 12130 if (action === 'add' && freeProductLoader) { 12131 applyFreeProductStyle('add'); 12132 } 12133 12134 updateUi(cart.item_count, TOTE_HANDLE, action); 12135 12136 if (action) { 12137 switch (action) { 12138 case 'add': 12139 const variantId = await getToteVariantId(); 12140 if (variantId) 12141 await fetchJSON('/cart/add.js', { 12142 method: 'POST', 12143 body: JSON.stringify({ items: [{ id: variantId, quantity: 1 }] }), 12144 }); 12145 break; 12146 case 'remove': 12147 const toteItem = toteItems[0]; 12148 await fetchJSON('/cart/update.js', { 12149 method: 'POST', 12150 body: JSON.stringify({ updates: { [toteItem.key]: 0 } }), 12151 }); 12152 break; 12153 case 'normalize': 12154 const normItem = toteItems[0]; 12155 await fetchJSON('/cart/update.js', { 12156 method: 'POST', 12157 body: JSON.stringify({ updates: { [normItem.key]: 1 } }), 12158 }); 12159 break; 12160 } 12161 // Update UI immediately after cart change 12162 freeProductLoader.style.display = 'none'; 12163 triggerCartRefresh(); 12164 } 12165 } catch (error) { 12166 console.error('Tote rule error:', error); 12167 } finally { 12168 isProcessing = false;
12169 } 12170 } 12171 12172 function triggerCartRefresh() { 12173 getCart().then((cart) => { 12174 if (window.updateCartUI) window.updateCartUI(cart); 12175 if (window.updateCartSummary) window.updateCartSummary(); 12176 }); 12177 } 12178 12179 // --- OPTIMIZED EVENT MONITORING --- 12180 12181</script>
12181 12182 12183<style> 12184 /* .cart__items:has(.subscription-container:not(.hidden)) .you-may-also-like { 12185 display: none; 12186 } */ 12187 12188 .free_tote_badge { 12189 padding: 3px 10px; 12190 font-size: 14px; 12191 background: #fadfaa; 12192 border-radius: 5px; 12193 height: max-content; 12194 } 12195 12196 .delete-icon { 12197 max-width: 18cm; 12198 } 12199 12200 .subscription-container.loading { 12201 position: relative; 12202 pointer-events: none; 12203 opacity: 0.7; 12204 } 12205 12206 .subscription-container.loading::after { 12207 content: ''; 12208 position: absolute; 12209 top: 0; 12210 left: 0; 12211 right: 0; 12212 bottom: 0; 12213 background: linear-gradient(90deg, #f6e8cf 25%, #f7eede 50%, #f7eede 75%); 12214 background-size: 200% 100%; 12215 animation: shimmer 1.5s infinite; 12216 border-radius: 4px; 12217 z-index: 10; 12218 } 12219 12220 @keyframes shimmer { 12221 0% { 12222 background-position: 200% 0; 12223 } 12224 100% { 12225 background-position: -200% 0; 12226 } 12227 } 12228 12229 .rc-form { 12230 width: 100%; 12231 display: flex; 12232 justify-content: end; 12233 align-items: end; 12234 } 12235 12236 .rc-form .rc-container-wrapper { 12237 display: none; 12238 } 12239 12240 .alt-product-container { 12241 border-radius: 4px; 12242 } 12243 12244 .you-may-also-like { 12245 padding-top: 12px; 12246 background: #fffbef; 12247 } 12248 12249 .you-may-also-like__heading { 12250 font-size: 14px; 12251 margin-bottom: 8px; 12252 color: #5f471d; 12253 } 12254 12255 .you-may-also-like__cards { 12256 display: flex; 12257 flex-direction: column; 12258 gap: 12px; 12259 } 12260 12261 .cart-upsell-card { 12262 position: relative; 12263 border-radius: 8px; 12264 padding: 15px 14px 14px; 12265 overflow: hidden; 12266 } 12267 12268 .cart-upsell-badge { 12269 12270 12271 12272 z-index: 2; 12273 display: inline-flex; 12274 align-items: center; 12275 gap: 4px; 12276 padding: 6px 10px; 12277 border-radius: 999px; 12278 font-size: 11px; 12279 line-height: 1; 12280 font-weight: 500; 12281 color: #fff; 12282 margin-bottom: 10px; 12283 } 12284 12285 .cart-upsell-badge--citrus { 12286 background: #fbaa4a; 12287 } 12288 12289 .cart-upsell-badge--mint { 12290 background: #7e8f72; 12291 } 12292 12293 .cart-upsell-badge--variety { 12294 background: linear-gradient(to right, #ffdea3, #ffdea3, #e6ecd3, #e6ecd3); 12295 color: #5f471d !important; 12296 } 12297 12298 .cart-upsell-badge--variety .cart-upsell-badge__icon { 12299 color: #5f471d; 12300 } 12301 .cart-upsell-badge__icon { 12302 flex-shrink: 0; 12303 color: #fff; 12304 } 12305 12306 .cart-upsell-card__body { 12307 display: grid; 12308 grid-template-columns: 72px 1fr; 12309 gap: 12px; 12310 align-items: start; 12311 } 12312 12313 .cart-upsell-card__image { 12314 display: flex; 12315 align-items: center; 12316 justify-content: center; 12317 min-height: 72px; 12318 } 12319 12320 .cart-upsell-card__image img { 12321 width: 100%; 12322 max-height: 72px; 12323 object-fit: contain; 12324 } 12325 12326 .cart-upsell-card__content { 12327 display: flex; 12328 flex-direction: column; 12329 gap: 4px; 12330 min-width: 0; 12331 } 12332 12333 .cart-upsell-card__header { 12334 display: flex; 12335 justify-content: space-between; 12336 align-items: flex-start; 12337 gap: 10px; 12338 } 12339 12340 .cart-upsell-card__title { 12341 font-size: 15px; 12342 line-height: 1.25; 12343 margin: 0; 12344 color: #5f471d; 12345 } 12346 12347 .cart-upsell-card__title a { 12348 color: inherit; 12349 text-decoration: none; 12350 } 12351 12352 .cart-upsell-card__price { 12353 display: flex; 12354 align-items: center; 12355 gap: 6px; 12356 flex-shrink: 0; 12357 font-size: 15px; 12358 color: #5f471d; 12359 white-space: nowrap; 12360 } 12361 12362 .cart-upsell-card__compare { 12363 font-size: 14px; 12364 } 12365 12366 .cart-upsell-card__flavor { 12367 margin: 0; 12368 font-size: 13px; 12369 line-height: 1.35; 12370 color: #5f471d; 12371 } 12372 12373 .cart-upsell-card__description { 12374 margin: 2px 0 0; 12375 font-size: 12px; 12376 line-height: 1.4; 12377 color: #5f471d; 12378 opacity: 0.85; 12379 } 12380 12381 .cart-upsell-card__footer { 12382 display: flex; 12383 justify-content: flex-end; 12384 margin-top: 6px; 12385 } 12386 .cart-upsell-card__footer button { 12387 width: 180px; 12388 transition: all ease 0.2s; 12389 background: rgba(244, 220, 179, 0); 12390 border: 1px solid rgb(95 71 29); 12391 } 12392 .cart-upsell-card__footer button:hover { 12393 background: #ffdea3; 12394 border: 1px solid #ffdea3; 12395 } 12396 .cart-upsell-card__add { 12397 padding: 7px 28px; 12398 border-radius: 10px; 12399 width: 180px; 12400 } 12401 12402 .you-may-also-like h3 { 12403 font-size: 14px; 12404 margin-bottom: 6px; 12405 } 12406 12407 .add-to-cart-btn { 12408 padding: 7px 34px; 12409 border-radius: 0.5em; 12410 margin-left: auto; 12411 } 12412 12413 .product_ad_flavour { 12414 font-size: 14px; 12415 } 12416 12417 .subscribe_save { 12418 margin-top: 1.3rem; 12419 border-radius: 0.5em; 12420 text-align: center; 12421 padding: 12px 0px; 12422 cursor: pointer; 12423 width: 100%; 12424 background: rgba(244, 220, 179, 0); 12425 border: 1px solid rgb(95 71 29); 12426 transition: all ease 0.2s; 12427 } 12428 12429 .subscribe_save:hover { 12430 border: none; 12431 background: #ffdea3; 12432 border: 1px solid #ffdea3; 12433 transition: all ease 0.2s; 12434 } 12435 12436 .cart-item { 12437 padding: 11px 0px 20px 0px; 12438 } 12439 12440 .product-card { 12441 display: flex; 12442 gap: 4px; 12443 width: 100%; 12444 border-radius: 5px; 12445 } 12446 12447 .product-image { 12448 width: 6rem; 12449 display: flex; 12450 justify-content: center;
12451 align-items: center; 12452 max-height: 5.5rem; 12453 } 12454 12455 .product-details-main { 12456 display: flex; 12457 justify-content: space-between; 12458 } 12459 12460 .product-details { 12461 width: 100%; 12462 } 12463 12464 div#shopify-section-main-cart-items { 12465 height: 100%; 12466 min-height: 0; 12467 overflow: auto; 12468 -webkit-overflow-scrolling: touch; 12469 } 12470 .cart__container { 12471 min-height: 0; 12472 } 12473 12474 .cart__container > #shopify-section-main-cart-items, 12475 .cart__container .cart__items-wrapper { 12476 min-height: 0; 12477 } 12478 12479 /* Let the section be the single scroll container so first-add height is reliable */ 12480 #main-cart-items > .cart__items.overflow-y-scroll { 12481 overflow-y: visible; 12482 } 12483 12484 .free_tote_spinner { 12485 width: 40px; 12486 height: 40px; 12487 border: 4px solid rgba(255, 222, 163, 0.35); /* light ring */ 12488 border-top-color: #ffdea3; /* theme color */ 12489 border-radius: 50%; 12490 animation: spin 0.9s linear infinite; 12491 } 12492 .subscribe-upsell-card { 12493 padding: 12px; 12494 background: #f7eede; 12495 border-radius: 5px; 12496 margin-top: 20px; 12497 } 12498 .subscribe-upsell-title { 12499 font-weight: 500; 12500 font-size: 14px; 12501 line-height: 20px; 12502 letter-spacing: 0; 12503 } 12504 .subscribe-upsell-list { 12505 margin-top: 10px; 12506 } 12507 .subscribe-upsell-list li { 12508 list-style: disc; 12509 margin-left: 25px; 12510 font-weight: 400; 12511 font-size: 14px; 12512 line-height: 19.25px; 12513 letter-spacing: 0; 12514 } 12515 .subscription-delivery-text { 12516 font-weight: 400; 12517 font-size: 12px; 12518 line-height: 16.5px; 12519 letter-spacing: 0; 12520 margin-bottom: 5px; 12521 } 12522 .switch-one-time-label { 12523 font-weight: 400; 12524 font-size: 12px; 12525 line-height: 16.5px; 12526 letter-spacing: 0; 12527 text-decoration: underline; 12528 text-decoration-style: solid; 12529 text-decoration-offset: 0%; 12530 text-decoration-thickness: 0%; 12531 } 12532 @keyframes spin { 12533 to { 12534 transform: rotate(360deg); 12535 } 12536 } 12537 12538 @media (max-width: 768px) { 12539 .subscription-title { 12540 font-size: 14px; 12541 padding: 12px; 12542 } 12543 12544 .shipping-text { 12545 font-size: 13px; 12546 letter-spacing: 0px; 12547 } 12548 12549 .current-plan { 12550 font-size: 14px; 12551 } 12552 12553 .truck-icon { 12554 max-width: 2rem; 12555 } 12556 12557 .free-shipping-banner { 12558 padding: 16px 14px 2px 14px; 12559 } 12560 } 12561 12562 .cart-item[data-handle='free-tote'], 12563 .cart-item[data-handle='variety-travel-2-pack-of-1-oz'], 12564 .cart-item--gwp, 12565 .cart-item[data-gwp-visual='true'] { 12566 pointer-events: none; 12567 } 12568 12569 @media (max-height: 700px) { 12570 .cart-upsell-card { 12571 padding: 24px 10px 10px; 12572 } 12573 12574 .cart-upsell-card__body { 12575 grid-template-columns: 60px 1fr; 12576 gap: 10px; 12577 } 12578 12579 .cart-upsell-card__title { 12580 font-size: 13px; 12581 } 12582 12583 .cart-upsell-card__image img { 12584 max-height: 60px; 12585 } 12586 12587 .cart-upsell-card__add { 12588 font-size: 12px; 12589 padding: 7px 18px; 12590 } 12591 12592 .product-card { 12593 padding: 8px 6px 5px 6px; 12594 } 12595 12596 .product-details-main h4 { 12597 font-size: 13px !important; 12598 } 12599 12600 .product-image { 12601 width: 5rem; 12602 } 12603 12604 .product-image a img { 12605 max-height: 5rem !important; 12606 } 12607 12608 .product-details-main .price span:first-child { 12609 display: none; 12610 } 12611 12612 .add-to-cart-btn { 12613 font-size: 12px; 12614 padding: 7px 18px; 12615 } 12616 12617 .subscription-title { 12618 padding: 9px; 12619 } 12620 12621 .current-plan { 12622 font-size: 13px; 12623 } 12624 } 12625</style> 12626 12627 12628</div><div id="shopify-section-main-cart-footer" class="shopify-section cart__footer-wrapper"><div data-id="main-cart-footer" class="bg-sand py-5 lg:py-8 rounded-t-3xl" id="cart__footer"> 12629 <div id="main-cart-footer" class="site-container"> 12630 <div> 12631 <div> 12632 <div class="totals flex justify-between mb-6"> 12633 <h3>Subtotal</h3> 12634 <p class="font-body-medium">$0</p> 12635 12636 </div> 12637 12638 </div> 12639 <div> 12640 <a href="/checkout" class="button button--gold !w-full">Checkout</a> 12641 </div> 12642 <small class="block text-center mt-3.5 text-primary text-sm">Taxes and <a href="/policies/shipping-policy">shipping</a> calculated at checkout 12643</small> 12644 </div> 12645 </div> 12646</div> 12647<style> 12648div#shopify-section-main-cart-footer { 12649 bottom: 0; 12650 position: absolute; 12651 left: 0; 12652 right: 0; 12653} 12654</style> 12655 12656</div></div> 12657 </div> 12658 <cart-toggle> 12659 <button class="flyout__veil absolute opacity-0 invisible top-0 bottom-0 left-0 w-full h-full z-10 cursor-pointer bg-transparent border-0 outline-none transition-all duration-500 ease-in-out"></button> 12660 </cart-toggle> 12661 </div> 12662</site-cart>
12662<script> 12663 setTimeout(function () { 12664 var script = document.createElement('script'); 12665 script.src = 'https://connect.podium.com/widget.js#ORG_TOKEN=26e5de10-54f2-4772-b419-ec6a202d561a'; 12666 script.async = true; 12667 document.body.appendChild(script); 12668 }, 6000); // 8-second delay 12669 12670 document.addEventListener('DOMContentLoaded', () => { 12671 const filterButtons = document.querySelectorAll('.filter-button'); 12672 const allItems = Array.from(document.querySelectorAll('.js-blog-item')); 12673 const pagerContainer = document.querySelector('.blog-pagination'); 12674 const pageSize = 4; 12675 let filteredItems = [...allItems]; 12676 let currentPage = 1; 12677 12678 // Show a slice of filteredItems, rebuild pager 12679 function showPage(page) { 12680 currentPage = page; 12681 const start = (page - 1) * pageSize; 12682 const end = start + pageSize; 12683 12684 // hide everything, then show just this pageâs slice 12685 allItems.forEach((i) => (i.style.display = 'none')); 12686 filteredItems.slice(start, end).forEach((i) => (i.style.display = '')); 12687 12688 renderPager(); 12689 window.scrollTo({ top: 0, behavior: 'smooth' }); 12690 } 12691 12692 // Build the âPrevious 1 2 3 Nextâ buttons 12693 function renderPager() { 12694 const totalPages = Math.ceil(filteredItems.length / pageSize); 12695 if (pagerContainer) pagerContainer.innerHTML = ''; 12696 12697 // Previous btn 12698 const prev = document.createElement('button'); 12699 prev.textContent = 'Previous'; 12700 prev.className = 'page-btn'; 12701 prev.disabled = currentPage === 1; 12702 prev.addEventListener('click', () => showPage(currentPage - 1)); 12703 if (pagerContainer) pagerContainer.appendChild(prev); 12704 12705 // Page numbers 12706 for (let i = 1; i <= totalPages; i++) { 12707 const btn = document.createElement('button'); 12708 btn.textContent = i; 12709 btn.className = 'page-btn' + (i === currentPage ? ' active' : ''); 12710 btn.addEventListener('click', () => showPage(i)); 12711 if (pagerContainer) pagerContainer.appendChild(btn); 12712 } 12713 12714 // Next btn 12715 const next = document.createElement('button'); 12716 next.textContent = 'Next'; 12717 next.className = 'page-btn'; 12718 next.disabled = currentPage === totalPages; 12719 next.addEventListener('click', () => showPage(currentPage + 1)); 12720 if (pagerContainer) pagerContainer.appendChild(next); 12721 } 12722 12723 // Filter handlerâupdates filteredItems and resets to page 1 12724 filterButtons.forEach((btn) => { 12725 btn.addEventListener('click', () => { 12726 // highlight the pill 12727 filterButtons.forEach((b) => b.classList.remove('active')); 12728 btn.classList.add('active'); 12729
12730 const filter = btn.dataset.filter; 12731 filteredItems = allItems.filter((item) => filter === 'all' || item.dataset.filter === filter); 12732 12733 showPage(1); 12734 }); 12735 }); 12736 12737 // kick it off 12738 showPage(1); 12739 }); 12740 </script>
vendor: 88 bytes, lines 12740-12744
12740 12741 12742 <noscript 12743 ><iframe 12744 src="https://www.googletagmanager.com/ns.html?id=
12744GTM-MX86RPVR
vendor: 124 bytes, lines 12744-12751
12744" 12745 height="0" 12746 width="0" 12747 style="display:none;visibility:hidden" 12748 ></iframe 12749 ></noscript> 12750 12751
12751<script> 12752 document.addEventListener('DOMContentLoaded', function () { 12753 let path = window.location.pathname; 12754 12755 if (path === '/cart') { 12756 sessionStorage.setItem('openCartOnHome', 'true'); 12757 12758 window.location.href = '/'; 12759 } 12760 12761 if (path === '/') { 12762 if (sessionStorage.getItem('openCartOnHome') === 'true') { 12763 sessionStorage.removeItem('openCartOnHome'); 12764 12765 let siteCart = document.querySelector('.site-cart'); 12766 if (siteCart) { 12767 siteCart.classList.add('active'); 12768 } 12769 } 12770 } 12771 }); 12772 </script>
12772 12773 12774 12775 12776 <div id="shopify-block-AVElYbHJnemxjbVVrN__10840395464443086010" class="shopify-block shopify-app-block"> 12777 12778
12779<script> 12780 console.log("[Alia app extension] v1.0.5"); 12781 12782 const BACKEND_URL = "https://backend.alia-prod.com"; 12783 12784 window.ALIA_SHOPIFY_EXTENSION_INFO = { 12785 customerID: "", 12786 country: "US", 12787 market: "us", 12788 language: "en" 12789 } 12790 12791 if (document.readyState !== "loading") { 12792 initAlia(); 12793 } else { 12794 document.addEventListener("DOMContentLoaded", () => initAlia(), { once: true }); 12795 } 12796 12797 async function initAlia() { 12798 const url = BACKEND_URL + "/public/launcher.js?shopifyUrl=revitin.myshopify.com"; 12799 const script = document.createElement("script"); 12800 script.src = url; 12801 script.async = true; 12802 document.head.appendChild(script); 12803 } 12804</script>
12804 12805 12806</div>
12806<script src="https://cdn.shopify.com/storefront/standard-actions.js" type="module" data-source-attribution="shopify.standard_actions"></script>
12806 12807</body> 12808</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.