1<!DOCTYPE html><html lang="en-US"><head><meta charset="UTF-8">
1<script 2 type="text/javascript" 3 src="https://mystashhq.com/wp-content/litespeed/js/49991c80d1d5eb16aa67fd69bb1f0aa3.js?ver=f0aa3"></script>
3<meta name='robots' content='index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1' /><meta name="viewport" content="width=device-width, initial-scale=1"><title>About Us - MyStash AI</title><meta name="description" content="Learn how MyStash AI was born from real loss to become a privacy-first, AI-powered home inventory platform built to protect what matters most." /><link rel="canonical" href="https://mystashhq.com/about/" /><meta property="og:locale" content="en_US" /><meta property="og:type" content="article" /><meta property="og:title" content="About Us - MyStash AI" /><meta property="og:description" content="Learn how MyStash AI was born from real loss to become a privacy-first, AI-powered home inventory platform built to protect what matters most." /><meta property="og:url" content="https://mystashhq.com/about/" /><meta property="og:site_name" content="MyStash AI" /><meta property="article:modified_time" content="2026-07-16T05:34:54+00:00" /><meta property="og:image" content="https://mystashhq.com/wp-content/uploads/2025/08/Our-Story.png" /><meta name="twitter:card" content="summary_large_image" /><meta name="twitter:label1" content="Est. reading time" /><meta name="twitter:data1" content="5 minutes" />
3<script type="application/ld+json" class="yoast-schema-graph">{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/mystashhq.com\/about\/","url":"https:\/\/mystashhq.com\/about\/","name":"About Us - MyStash AI","isPartOf":{"@id":"https:\/\/mystashhq.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/mystashhq.com\/about\/#primaryimage"},"image":{"@id":"https:\/\/mystashhq.com\/about\/#primaryimage"},"thumbnailUrl":"https:\/\/mystashhq.com\/wp-content\/uploads\/2025\/08\/Our-Story.png","datePublished":"2025-07-18T18:24:13+00:00","dateModified":"2026-07-16T05:34:54+00:00","description":"Learn how MyStash AI was born from real loss to become a privacy-first, AI-powered home inventory platform built to protect what matters most.","breadcrumb":{"@id":"https:\/\/mystashhq.com\/about\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/mystashhq.com\/about\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/mystashhq.com\/about\/#primaryimage","url":"https:\/\/mystashhq.com\/wp-content\/uploads\/2025\/08\/Our-Story.png","contentUrl":"https:\/\/mystashhq.com\/wp-content\/uploads\/2025\/08\/Our-Story.png","width":1536,"height":1024},{"@type":"BreadcrumbList","@id":"https:\/\/mystashhq.com\/about\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/mystashhq.com\/"},{"@type":"ListItem","position":2,"name":"About Us"}]},{"@type":"WebSite","@id":"https:\/\/mystashhq.com\/#website","url":"https:\/\/mystashhq.com\/","name":"MyStash AI","description":"","publisher":{"@id":"https:\/\/mystashhq.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/mystashhq.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/mystashhq.com\/#organization","name":"MyStash AI","url":"https:\/\/mystashhq.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/mystashhq.com\/#\/schema\/logo\/image\/","url":"https:\/\/mystashhq.com\/wp-content\/uploads\/2025\/07\/Icono-Text-MyStash.svg","contentUrl":"https:\/\/mystashhq.com\/wp-content\/uploads\/2025\/07\/Icono-Text-MyStash.svg","caption":"MyStash AI"},"image":{"@id":"https:\/\/mystashhq.com\/#\/schema\/logo\/image\/"}}]}</script>
3 <link rel='dns-prefetch' href='//www.googletagmanager.com' /><link rel="alternate" type="application/rss+xml" title="MyStash AI » Feed" href="https://mystashhq.com/feed/" /><link rel="alternate" type="application/rss+xml" title="MyStash AI » Comments Feed" href="https://mystashhq.com/comments/feed/" /><link rel="alternate" title="oEmbed (JSON)" type="application/json+oembed" href="https://mystashhq.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fmystashhq.com%2Fabout%2F" /><link rel="alternate" title="oEmbed (XML)" type="text/xml+oembed" href="https://mystashhq.com/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fmystashhq.com%2Fabout%2F&format=xml" /><link data-optimized="2" rel="stylesheet" href="https://mystashhq.com/wp-content/litespeed/css/a98c4d4d3d49c39cf0ae79b3ea0004db.css?ver=aab85" />
3<script data-optimized="1" id="bodhi-dompurify-library-js" src="https://mystashhq.com/wp-content/litespeed/js/6ee81d36c1b4894ab27a224806f4b765.js?ver=82d8c"></script>
3
3<script id="jquery-core-js" src="https://mystashhq.com/wp-includes/js/jquery/jquery.min.js?ver=3.7.1"></script>
3
3<script data-optimized="1" id="jquery-migrate-js" src="https://mystashhq.com/wp-content/litespeed/js/0401c89eaaf1b0e3bb17d87e28ab1b99.js?ver=2fac4"></script>
3
3<script data-optimized="1" id="dracula-dark-mode-js-extra">var dracula={"homeUrl":"https://mystashhq.com","adminUrl":"https://mystashhq.com/wp-admin/","ajaxUrl":"https://mystashhq.com/wp-admin/admin-ajax.php","pluginUrl":"https://mystashhq.com/wp-content/plugins/dracula-dark-mode","settings":{"frontendDarkMode":!0,"toggleStyle":2,"showToggle":!0},"isPro":"","nonce":"5c1f43969f","switches":{"1":"\u003Cdiv class=\"toggle-icon-wrap dracula-ignore\"\u003E \u003Cdiv class=\"toggle-icon __dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"toggle-icon __light\"\u003E\u003C/div\u003E \u003C/div\u003E","2":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"dracula-toggle-label\"\u003E \u003Cspan class=\"--light\"\u003ELight\u003C/span\u003E \u003Cspan class=\"--dark\"\u003EDark\u003C/span\u003E \u003C/div\u003E","3":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","4":"\u003Cdiv class=\"prefix-icon\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"suffix-icon\"\u003E\u003C/div\u003E","5":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E","6":"\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E","7":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","8":"\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","9":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","10":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","11":"\u003Cdiv class=\"toggle-prefix\"\u003ELight\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-suffix\"\u003EDark\u003C/div\u003E","12":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","13":"\u003Cspan class=\"toggle-prefix-icon\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-prefix-text\"\u003EDark Mode\u003C/span\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","14":"\u003Cspan class=\"dracula-toggle-icon\"\u003E\u003C/span\u003E \u003Cdiv class=\"toggle-modal dracula-ignore\"\u003E \u003Cdiv class=\"toggle-modal-content\"\u003E \u003Cdiv class=\"toggle-option light\"\u003E \u003Cspan class=\"toggle-option-icon --light\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003ELight Mode\u003C/span\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-option dark\"\u003E \u003Cspan class=\"toggle-option-icon --dark\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003EDark Mode\u003C/span\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-option auto\"\u003E \u003Cspan class=\"toggle-option-icon --auto\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003ESystem Mode\u003C/span\u003E \u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-modal-arrow\"\u003E\u003C/div\u003E \u003C/div\u003E","15":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\u003C/div\u003E","16":"\u003Cspan class=\"toggle-prefix-icon\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-prefix-text dracula-toggle-text\"\u003ELight Mode\u003C/span\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","17":"\u003Cbutton class=\"dracula-toggle-icon --typography\"\u003E\u003C/button\u003E \u003Cbutton class=\"dracula-toggle-icon --light\"\u003E\u003C/button\u003E","18":"\u003Cbutton type=\"button\" class=\"dracula-toggle-icon --light\"\u003E\u003C/button\u003E \u003Cbutton type=\"button\" class=\"dracula-toggle-icon --typography\"\u003E\u003C/button\u003E"},"customSwitches":{"1":"\u003Cdiv class=\"toggle-icon-wrap\"\u003E\n\t\t\t\t\u003Cspan class=\"toggle-icon __dark\"\u003E\u003C/span\u003E\n\t\t\t\t\u003Cspan class=\"toggle-icon __light\"\u003E\u003C/span\u003E\n\t\t\t\u003C/div\u003E","2":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon position-before\"\u003E\u003C/div\u003E\n\t\t\t\u003Cdiv class=\"dracula-toggle-label\"\u003E\n \u003Cspan class=\"--light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"--dark\"\u003E\u003C/span\u003E\n \u003C/div\u003E\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon position-after\"\u003E\u003C/div\u003E\n\t\t","3":"\n\t\t\t\u003Cdiv class=\"toggle-prefix\"\u003E\u003C/div\u003E\n \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n \u003Cdiv class=\"toggle-suffix\"\u003E\u003C/div\u003E\n\t\t","4":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n\n \u003Cdiv class=\"dracula-toggle-label\"\u003E\n \u003Cspan class=\"--light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"--dark\"\u003E\u003C/span\u003E\n \u003C/div\u003E\n\t\t","5":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n\n \u003Cspan class=\"dracula-toggle-label --light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"dracula-toggle-label --dark\"\u003E\u003C/span\u003E\n\t\t"},"presets":[{"key":"default","label":"Default","colors":{"bg":"#181a1b","text":"#e8e6e3","secondary_bg":"#202324","link":"#6ea5d9","link_hover":"#88b9e3","btn_bg":"#3b6f99","btn_text":"#dcdcdc","btn_text_hover":"#f0f0f0","btn_hover_bg":"#325d80","input_text":"#e8e6e3","input_bg":"#1f2223","input_placeholder":"#8c8c8c","border":"#2d2d2d"}},{"key":"dracula","label":"Dracula","colors":{"bg":"#282b36","text":"#e8e6e3","secondary_bg":"#343746","link":"#9a87cc","link_hover":"#b79ce2","btn_bg":"#5a6288","btn_text":"#dedede","btn_text_hover":"#f0f0f0","btn_hover_bg":"#4b5274","input_text":"#e8e6e3","input_bg":"#3a3c4e","input_placeholder":"#8b8b9c","border":"#45475a"}},{"key":"catppuccin","label":"Catppuccin","isPro":!0,"colors":{"bg":"#161320","text":"#d9e0ee","secondary_bg":"#1e1a2e","link":"#b69ad8","link_hover":"#c5b0e1","btn_bg":"#8a74b8","btn_text":"#d9e0ee","btn_text_hover":"#ffffff","btn_hover_bg":"#7a66a3","input_text":"#d9e0ee","input_bg":"#1e1a2e","input_placeholder":"#8e89a3","border":"#2a2438"}},{"key":"gruvbox","label":"Gruvbox","isPro":!0,"colors":{"bg":"#282828","text":"#ebdbb2","secondary_bg":"#32302f","link":"#d4a73c","link_hover":"#e0b252","btn_bg":"#a97e2c","btn_text":"#ebdbb2","btn_text_hover":"#ffffff","btn_hover_bg":"#8f6a25","input_text":"#ebdbb2","input_bg":"#32302f","input_placeholder":"#a89984","border":"#504945"}},{"key":"nord","label":"Nord","isPro":!0,"colors":{"bg":"#2e3440","text":"#eceff4","secondary_bg":"#3b4252","link":"#88c0d0","link_hover":"#a3d1dc","btn_bg":"#5e81ac","btn_text":"#eceff4","btn_text_hover":"#ffffff","btn_hover_bg":"#4c6a92","input_text":"#eceff4","input_bg":"#434c5e","input_placeholder":"#9aa0a6","border":"#4c566a"}},{"key":"rosePine","label":"Rose Pine","isPro":!0,"colors":{"bg":"#191724","text":"#e0def4","secondary_bg":"#1f1d2e","link":"#d2879d","link_hover":"#e2a3b7","btn_bg":"#6d879c","btn_text":"#e0def4","btn_text_hover":"#ffffff","btn_hover_bg":"#5a6f81","input_text":"#e0def4","input_bg":"#26233a","input_placeholder":"#908caa","border":"#524f67"}},{"key":"solarized","label":"Solarized","isPro":!0,"colors":{"bg":"#002b36","text":"#93a1a1","secondary_bg":"#073642","link":"#6aa6a6","link_hover":"#82bcbc","btn_bg":"#2f5f66","btn_text":"#cfe3e3","btn_text_hover":"#e6f0f0","btn_hover_bg":"#2a5359","input_text":"#a7b6b6","input_bg":"#0d3944","input_placeholder":"#6f8383","border":"#0f3a44"}},{"key":"tokyoNight","label":"Tokyo Night","colors":{"bg":"#1a1b26","text":"#a9b1d6","secondary_bg":"#1f2230","link":"#7aa2f7","link_hover":"#8fb5ff","btn_bg":"#3b4a7a","btn_text":"#cfd6f2","btn_text_hover":"#ffffff","btn_hover_bg":"#323f68","input_text":"#b7bfe1","input_bg":"#212335","input_placeholder":"#7c85a9","border":"#2a2e42"}},{"key":"monokai","label":"Monokai","colors":{"bg":"#272822","text":"#f8f8f2","secondary_bg":"#2f302a","link":"#8fc66a","link_hover":"#a1d57a","btn_bg":"#5b6e4a","btn_text":"#e6f1dd","btn_text_hover":"#ffffff","btn_hover_bg":"#4d5e3f","input_text":"#efeede","input_bg":"#303126","input_placeholder":"#9aa08f","border":"#3a3b33"}},{"key":"ayuMirage","label":"Ayu Mirage","colors":{"bg":"#1f2430","text":"#cbccc6","secondary_bg":"#252b39","link":"#9ccfd8","link_hover":"#b7e0e6","btn_bg":"#5f7890","btn_text":"#dfe2e0","btn_text_hover":"#ffffff","btn_hover_bg":"#50677d","input_text":"#d5d6d0","input_bg":"#262d3b","input_placeholder":"#8d94a1","border":"#2c3443"}},{"key":"ayuDark","label":"Ayu Dark","colors":{"bg":"#0a0e14","text":"#b3b1ad","secondary_bg":"#121721","link":"#5aa7c8","link_hover":"#72b8d5","btn_bg":"#3a6075","btn_text":"#cfd6da","btn_text_hover":"#e7eef2","btn_hover_bg":"#314f61","input_text":"#c2c0bc","input_bg":"#121722","input_placeholder":"#808693","border":"#1b2230"}},{"key":"material","label":"Material","colors":{"bg":"#263238","text":"#eceff1","secondary_bg":"#2e3b41","link":"#82b1ff","link_hover":"#9bbfff","btn_bg":"#546e7a","btn_text":"#e6eff3","btn_text_hover":"#ffffff","btn_hover_bg":"#465c65","input_text":"#e4eaee","input_bg":"#2b3940","input_placeholder":"#9aaab1","border":"#31434a"}},{"key":"oneDark","label":"One Dark","colors":{"bg":"#282c34","text":"#abb2bf","secondary_bg":"#2f3440","link":"#6fb4f0","link_hover":"#89c2f4","btn_bg":"#3d5872","btn_text":"#cfd6e2","btn_text_hover":"#eaf1fb","btn_hover_bg":"#334a60","input_text":"#b9c0cd","input_bg":"#2c303a","input_placeholder":"#8a909c","border":"#3a3f4a"}},{"key":"oceanicNext","label":"Oceanic Next","colors":{"bg":"#1B2B34","text":"#CDD3DE","secondary_bg":"#203340","link":"#5fb3b3","link_hover":"#77c4c4","btn_bg":"#3f6d6d","btn_text":"#d8e4e4","btn_text_hover":"#f0f7f7","btn_hover_bg":"#355c5c","input_text":"#d2d8e1","input_bg":"#223746","input_placeholder":"#8ca1ad","border":"#2a4050"}},{"key":"cityLights","label":"City Lights","colors":{"bg":"#1d252c","text":"#b6bfc4","secondary_bg":"#232c34","link":"#76a8d9","link_hover":"#8bb9e3","btn_bg":"#3e5f7a","btn_text":"#d4dde2","btn_text_hover":"#f0f6fb","btn_hover_bg":"#344f66","input_text":"#c2cbd0","input_bg":"#232c34","input_placeholder":"#8b97a0","border":"#2a343e"}},{"key":"nightOwl","label":"Night Owl","colors":{"bg":"#011627","text":"#d6deeb","secondary_bg":"#071d33","link":"#82aaff","link_hover":"#9bb6ff","btn_bg":"#425b8a","btn_text":"#e4ecfa","btn_text_hover":"#ffffff","btn_hover_bg":"#394f78","input_text":"#dbe3f0","input_bg":"#0a1f36","input_placeholder":"#8aa0be","border":"#0f2740"}},{"key":"youtube","label":"YouTube","colors":{"bg":"#181818","text":"#ffffff","secondary_bg":"#202020","link":"#e05a5a","link_hover":"#ff6b6b","btn_bg":"#8a2b2b","btn_text":"#f2f2f2","btn_text_hover":"#ffffff","btn_hover_bg":"#722424","input_text":"#f0f0f0","input_bg":"#222222","input_placeholder":"#9a9a9a","border":"#2a2a2a"}},{"key":"twitter","label":"Twitter","colors":{"bg":"#15202b","text":"#ffffff","secondary_bg":"#1b2733","link":"#69b3ff","link_hover":"#8cc6ff","btn_bg":"#3a6fa1","btn_text":"#e8f3ff","btn_text_hover":"#ffffff","btn_hover_bg":"#325f8a","input_text":"#eef6ff","input_bg":"#1e2a36","input_placeholder":"#8ea5bd","border":"#263544"}},{"key":"reddit","label":"Reddit (Night mode)","colors":{"bg":"#1a1a1b","text":"#d7dadc","secondary_bg":"#202021","link":"#ff9566","link_hover":"#ffb187","btn_bg":"#7a4a2e","btn_text":"#efd9cf","btn_text_hover":"#ffffff","btn_hover_bg":"#693f27","input_text":"#e3e6e8","input_bg":"#222223","input_placeholder":"#9aa0a3","border":"#2a2a2b"}},{"key":"discord","label":"Discord","colors":{"bg":"#36393f","text":"#dcddde","secondary_bg":"#3c4047","link":"#8ea1e1","link_hover":"#a5b3ea","btn_bg":"#4957d6","btn_text":"#e7e9ff","btn_text_hover":"#ffffff","btn_hover_bg":"#3f4bc0","input_text":"#e3e4e6","input_bg":"#40444b","input_placeholder":"#9aa1ae","border":"#454a52"}},{"key":"slack","label":"Slack","colors":{"bg":"#1d1c1d","text":"#e7e7e7","secondary_bg":"#232223","link":"#cf8fb6","link_hover":"#dda6c5","btn_bg":"#6b5a6e","btn_text":"#efe3ef","btn_text_hover":"#ffffff","btn_hover_bg":"#5b4d5d","input_text":"#ededed","input_bg":"#242324","input_placeholder":"#9a969b","border":"#2a292a"}},{"key":"whatsapp","label":"WhatsApp","colors":{"bg":"#121212","text":"#e6e5e4","secondary_bg":"#161616","link":"#67b97a","link_hover":"#7acc8d","btn_bg":"#2f6b3e","btn_text":"#d8f0df","btn_text_hover":"#f2fff6","btn_hover_bg":"#285b35","input_text":"#ecebe9","input_bg":"#1a1a1a","input_placeholder":"#8d8d8d","border":"#222222"}},{"key":"github","label":"GitHub","colors":{"bg":"#0d1117","text":"#c9d1d9","secondary_bg":"#11161e","link":"#6aa6ff","link_hover":"#8abaff","btn_bg":"#2f3a4a","btn_text":"#d8e2ec","btn_text_hover":"#ffffff","btn_hover_bg":"#26303d","input_text":"#d3dbe2","input_bg":"#0f1420","input_placeholder":"#8894a1","border":"#1a2230"}},{"key":"stackoverflow","label":"StackOverflow","colors":{"bg":"#2d2d2d","text":"#f2f2f2","secondary_bg":"#333333","link":"#ffa654","link_hover":"#ffbb7a","btn_bg":"#7a4e1f","btn_text":"#fdeedd","btn_text_hover":"#ffffff","btn_hover_bg":"#683f18","input_text":"#f0f0f0","input_bg":"#353535","input_placeholder":"#9a9a9a","border":"#3c3c3c"}}]};var dracula={"homeUrl":"https://mystashhq.com","adminUrl":"https://mystashhq.com/wp-admin/","ajaxUrl":"https://mystashhq.com/wp-admin/admin-ajax.php","pluginUrl":"https://mystashhq.com/wp-content/plugins/dracula-dark-mode","settings":{"frontendDarkMode":!0,"toggleStyle":2,"showToggle":!0},"isPro":"","nonce":"5c1f43969f","switches":{"1":"\u003Cdiv class=\"toggle-icon-wrap dracula-ignore\"\u003E \u003Cdiv class=\"toggle-icon __dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"toggle-icon __light\"\u003E\u003C/div\u003E \u003C/div\u003E","2":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"dracula-toggle-label\"\u003E \u003Cspan class=\"--light\"\u003ELight\u003C/span\u003E \u003Cspan class=\"--dark\"\u003EDark\u003C/span\u003E \u003C/div\u003E","3":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","4":"\u003Cdiv class=\"prefix-icon\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"suffix-icon\"\u003E\u003C/div\u003E","5":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E","6":"\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E","7":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","8":"\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","9":"\u
3003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","10":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","11":"\u003Cdiv class=\"toggle-prefix\"\u003ELight\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-suffix\"\u003EDark\u003C/div\u003E","12":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","13":"\u003Cspan class=\"toggle-prefix-icon\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-prefix-text\"\u003EDark Mode\u003C/span\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","14":"\u003Cspan class=\"dracula-toggle-icon\"\u003E\u003C/span\u003E \u003Cdiv class=\"toggle-modal dracula-ignore\"\u003E \u003Cdiv class=\"toggle-modal-content\"\u003E \u003Cdiv class=\"toggle-option light\"\u003E \u003Cspan class=\"toggle-option-icon --light\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003ELight Mode\u003C/span\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-option dark\"\u003E \u003Cspan class=\"toggle-option-icon --dark\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003EDark Mode\u003C/span\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-option auto\"\u003E \u003Cspan class=\"toggle-option-icon --auto\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003ESystem Mode\u003C/span\u003E \u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-modal-arrow\"\u003E\u003C/div\u003E \u003C/div\u003E","15":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\u003C/div\u003E","16":"\u003Cspan class=\"toggle-prefix-icon\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-prefix-text dracula-toggle-text\"\u003ELight Mode\u003C/span\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","17":"\u003Cbutton class=\"dracula-toggle-icon --typography\"\u003E\u003C/button\u003E \u003Cbutton class=\"dracula-toggle-icon --light\"\u003E\u003C/button\u003E","18":"\u003Cbutton type=\"button\" class=\"dracula-toggle-icon --light\"\u003E\u003C/button\u003E \u003Cbutton type=\"button\" class=\"dracula-toggle-icon --typography\"\u003E\u003C/button\u003E"},"customSwitches":{"1":"\u003Cdiv class=\"toggle-icon-wrap\"\u003E\n\t\t\t\t\u003Cspan class=\"toggle-icon __dark\"\u003E\u003C/span\u003E\n\t\t\t\t\u003Cspan class=\"toggle-icon __light\"\u003E\u003C/span\u003E\n\t\t\t\u003C/div\u003E","2":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon position-before\"\u003E\u003C/div\u003E\n\t\t\t\u003Cdiv class=\"dracula-toggle-label\"\u003E\n \u003Cspan class=\"--light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"--dark\"\u003E\u003C/span\u003E\n \u003C/div\u003E\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon position-after\"\u003E\u003C/div\u003E\n\t\t","3":"\n\t\t\t\u003Cdiv class=\"toggle-prefix\"\u003E\u003C/div\u003E\n \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n \u003Cdiv class=\"toggle-suffix\"\u003E\u003C/div\u003E\n\t\t","4":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n\n \u003Cdiv class=\"dracula-toggle-label\"\u003E\n \u003Cspan class=\"--light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"--dark\"\u003E\u003C/span\u003E\n \u003C/div\u003E\n\t\t","5":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n\n \u003Cspan class=\"dracula-toggle-label --light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"dracula-toggle-label --dark\"\u003E\u003C/span\u003E\n\t\t"},"presets":[{"key":"default","label":"Default","colors":{"bg":"#181a1b","text":"#e8e6e3","secondary_bg":"#202324","link":"#6ea5d9","link_hover":"#88b9e3","btn_bg":"#3b6f99","btn_text":"#dcdcdc","btn_text_hover":"#f0f0f0","btn_hover_bg":"#325d80","input_text":"#e8e6e3","input_bg":"#1f2223","input_placeholder":"#8c8c8c","border":"#2d2d2d"}},{"key":"dracula","label":"Dracula","colors":{"bg":"#282b36","text":"#e8e6e3","secondary_bg":"#343746","link":"#9a87cc","link_hover":"#b79ce2","btn_bg":"#5a6288","btn_text":"#dedede","btn_text_hover":"#f0f0f0","btn_hover_bg":"#4b5274","input_text":"#e8e6e3","input_bg":"#3a3c4e","input_placeholder":"#8b8b9c","border":"#45475a"}},{"key":"catppuccin","label":"Catppuccin","isPro":!0,"colors":{"bg":"#161320","text":"#d9e0ee","secondary_bg":"#1e1a2e","link":"#b69ad8","link_hover":"#c5b0e1","btn_bg":"#8a74b8","btn_text":"#d9e0ee","btn_text_hover":"#ffffff","btn_hover_bg":"#7a66a3","input_text":"#d9e0ee","input_bg":"#1e1a2e","input_placeholder":"#8e89a3","border":"#2a2438"}},{"key":"gruvbox","label":"Gruvbox","isPro":!0,"colors":{"bg":"#282828","text":"#ebdbb2","secondary_bg":"#32302f","link":"#d4a73c","link_hover":"#e0b252","btn_bg":"#a97e2c","btn_text":"#ebdbb2","btn_text_hover":"#ffffff","btn_hover_bg":"#8f6a25","input_text":"#ebdbb2","input_bg":"#32302f","input_placeholder":"#a89984","border":"#504945"}},{"key":"nord","label":"Nord","isPro":!0,"colors":{"bg":"#2e3440","text":"#eceff4","secondary_bg":"#3b4252","link":"#88c0d0","link_hover":"#a3d1dc","btn_bg":"#5e81ac","btn_text":"#eceff4","btn_text_hover":"#ffffff","btn_hover_bg":"#4c6a92","input_text":"#eceff4","input_bg":"#434c5e","input_placeholder":"#9aa0a6","border":"#4c566a"}},{"key":"rosePine","label":"Rose Pine","isPro":!0,"colors":{"bg":"#191724","text":"#e0def4","secondary_bg":"#1f1d2e","link":"#d2879d","link_hover":"#e2a3b7","btn_bg":"#6d879c","btn_text":"#e0def4","btn_text_hover":"#ffffff","btn_hover_bg":"#5a6f81","input_text":"#e0def4","input_bg":"#26233a","input_placeholder":"#908caa","border":"#524f67"}},{"key":"solarized","label":"Solarized","isPro":!0,"colors":{"bg":"#002b36","text":"#93a1a1","secondary_bg":"#073642","link":"#6aa6a6","link_hover":"#82bcbc","btn_bg":"#2f5f66","btn_text":"#cfe3e3","btn_text_hover":"#e6f0f0","btn_hover_bg":"#2a5359","input_text":"#a7b6b6","input_bg":"#0d3944","input_placeholder":"#6f8383","border":"#0f3a44"}},{"key":"tokyoNight","label":"Tokyo Night","colors":{"bg":"#1a1b26","text":"#a9b1d6","secondary_bg":"#1f2230","link":"#7aa2f7","link_hover":"#8fb5ff","btn_bg":"#3b4a7a","btn_text":"#cfd6f2","btn_text_hover":"#ffffff","btn_hover_bg":"#323f68","input_text":"#b7bfe1","input_bg":"#212335","input_placeholder":"#7c85a9","border":"#2a2e42"}},{"key":"monokai","label":"Monokai","colors":{"bg":"#272822","text":"#f8f8f2","secondary_bg":"#2f302a","link":"#8fc66a","link_hover":"#a1d57a","btn_bg":"#5b6e4a","btn_text":"#e6f1dd","btn_text_hover":"#ffffff","btn_hover_bg":"#4d5e3f","input_text":"#efeede","input_bg":"#303126","input_placeholder":"#9aa08f","border":"#3a3b33"}},{"key":"ayuMirage","label":"Ayu Mirage","colors":{"bg":"#1f2430","text":"#cbccc6","secondary_bg":"#252b39","link":"#9ccfd8","link_hover":"#b7e0e6","btn_bg":"#5f7890","btn_text":"#dfe2e0","btn_text_hover":"#ffffff","btn_hover_bg":"#50677d","input_text":"#d5d6d0","input_bg":"#262d3b","input_placeholder":"#8d94a1","border":"#2c3443"}},{"key":"ayuDark","label":"Ayu Dark","colors":{"bg":"#0a0e14","text":"#b3b1ad","secondary_bg":"#121721","link":"#5aa7c8","link_hover":"#72b8d5","btn_bg":"#3a6075","btn_text":"#cfd6da","btn_text_hover":"#e7eef2","btn_hover_bg":"#314f61","input_text":"#c2c0bc","input_bg":"#121722","input_placeholder":"#808693","border":"#1b2230"}},{"key":"material","label":"Material","colors":{"bg":"#263238","text":"#eceff1","secondary_bg":"#2e3b41","link":"#82b1ff","link_hover":"#9bbfff","btn_bg":"#546e7a","btn_text":"#e6eff3","btn_text_hover":"#ffffff","btn_hover_bg":"#465c65","input_text":"#e4eaee","input_bg":"#2b3940","input_placeholder":"#9aaab1","border":"#31434a"}},{"key":"oneDark","label":"One Dark","colors":{"bg":"#282c34","text":"#abb2bf","secondary_bg":"#2f3440","link":"#6fb4f0","link_hover":"#89c2f4","btn_bg":"#3d5872","btn_text":"#cfd6e2","btn_text_hover":"#eaf1fb","btn_hover_bg":"#334a60","input_text":"#b9c0cd","input_bg":"#2c303a","input_placeholder":"#8a909c","border":"#3a3f4a"}},{"key":"oceanicNext","label":"Oceanic Next","colors":{"bg":"#1B2B34","text":"#CDD3DE","secondary_bg":"#203340","link":"#5fb3b3","link_hover":"#77c4c4","btn_bg":"#3f6d6d","btn_text":"#d8e4e4","btn_text_hover":"#f0f7f7","btn_hover_bg":"#355c5c","input_text":"#d2d8e1","input_bg":"#223746","input_placeholder":"#8ca1ad","border":"#2a4050"}},{"key":"cityLights","label":"City Lights","colors":{"bg":"#1d252c","text":"#b6bfc4","secondary_bg":"#232c34","link":"#76a8d9","link_hover":"#8bb9e3","btn_bg":"#3e5f7a","btn_text":"#d4dde2","btn_text_hover":"#f0f6fb","btn_hover_bg":"#344f66","input_text":"#c2cbd0","input_bg":"#232c34","input_placeholder":"#8b97a0","border":"#2a343e"}},{"key":"nightOwl","label":"Night Owl","colors":{"bg":"#011627","text":"#d6deeb","secondary_bg":"#071d33","link":"#82aaff","link_hover":"#9bb6ff","btn_bg":"#425b8a","btn_text":"#e4ecfa","btn_text_hover":"#ffffff","btn_hover_bg":"#394f78","input_text":"#dbe3f0","input_bg":"#0a1f36","input_placeholder":"#8aa0be","border":"#0f2740"}},{"key":"youtube","label":"YouTube","colors":{"bg":"#181818","text":"#ffffff","secondary_bg":"#202020","link":"#e05a5a","link_hover":"#ff6b6b","btn_bg":"#8a2b2b","btn_text":"#f2f2f2","btn_text_hover":"#ffffff","btn_hover_bg":"#722424","input_text":"#f0f0f0","input_bg":"#222222","input_placeholder":"#9a9a9a","border":"#2a2a2a"}},{"key":"twitter","label":"Twitter","colors":{"bg":"#15202b","text":"#ffffff","secondary_bg":"#1b2733","link":"#69b3ff","link_hover":"#8cc6ff","btn_bg":"#3a6fa1","btn_text":"#e8f3ff","btn_text_hover":"#ffffff","btn_hover_bg":"#325f8a","input_text":"#eef6ff","input_bg":"#1e2a36","input_placeholder":"#8ea5bd","border":"#263544"}},{"key":"reddit","label":"Reddit (Night mode)","colors":{"bg":"#1a1a1b","text":"#d7dadc","secondary_bg":"#202021","link":"#ff9566","link_hover":"#ffb187","btn_bg":"#7a4a2e","btn_text":"#efd9cf","btn_text_hover":"#ffffff","btn_hover_bg":"#693f27","input_text":"#e3e6e8","input_bg":"#222223","input_placeholder":"#9aa0a3","border":"#2a2a2b"}},{"key":"discord","label":"Discord","colors":{"bg":"#36393f","text":"#dcddde","secondary_bg":"#3c4047","link":"#8ea1e1","link_hover":"#a5b3ea","btn_bg":"#4957d6","btn_text":"#e7e9ff","btn_text_hover":"#ffffff","btn_hover_bg":"#3f4bc0","input_text":"#e3e4e6","input_bg":"#40444b","input_placeholder":"#9aa1ae","border":"#454a52"}},{"key":"slack","label":"Slack","colors":{"bg":"#1d1c1d","text":"#e7e7e7","secondary_bg":"#232223","link":"#cf8fb6","link_hover":"#dda6c5","btn_bg":"#6b5a6e","btn_text":"#efe3ef","btn_text_hover":"#ffffff","btn_hover_bg":"#5b4d5d","input_text":"#ededed","input_bg":"#242324","input_placeholder":"#9a969b","border":"#2a292a"}},{"key":"whatsapp","label":"WhatsApp","colors":{"bg":"#121212","text":"#e6e5e4","secondary_bg":"#161616","link":"#67b97a","link_hover":"#7acc8d","btn_bg":"#2f6b3e","btn_text":"#d8f0df","btn_text_hover":"#f2fff6","btn_hover_bg":"#285b35","input_text":"#ecebe9","input_bg":"#1a1a1a","input_placeholder":"#8d8d8d","border":"#222222"}},{"key":"github","label":"GitHub","colors":{"bg":"#0d1117","text":"#c9d1d9","secondary_bg":"#11161e","link":"#6aa6ff","link_hover":"#8abaff","btn_bg":"#2f3a4a","btn_text":"#d8e2ec","btn_text_hover":"#ffffff","btn_hover_bg":"#26303d","input_text":"#d3dbe2","input_bg":"#0f1420","input_placeholder":"#8894a1","border":"#1a2230"}},{"key":"stackoverflow","label":"StackOverflow","colors":{"bg":"#2d2d2d","text":"#f2f2f2","secondary_bg":"#333333","link":"#ffa654","link_hover":"#ffbb7a","btn_bg":"#7a4e1f","btn_text":"#fdeedd","btn_text_hover":"#ffffff","btn_hover_bg":"#683f18","input_text":"#f0f0f0","input_bg":"#353535","input_placeholder":"#9a9a9a","border":"#3c3c3c"}}]}</script>
3
3<script data-optimized="1" id="dracula-dark-mode-js" src="https://mystashhq.com/wp-content/litespeed/js/29575c8ef1fde1578ae148e301141a48.js?ver=d268c"></script>
3
3<script data-optimized="1" id="bodhi_svg_inline-js-extra">var svgSettings={"skipNested":""}</script>
3
3<script data-optimized="1" id="bodhi_svg_inline-js" src="https://mystashhq.com/wp-content/litespeed/js/81abe138826b300d1bf3c47c950a4d4e.js?ver=e05a2"></script>
3
3<script data-optimized="1" id="bodhi_svg_inline-js-after">cssTarget={"Bodhi":"img.style-svg","ForceInlineSVG":"style-svg"};ForceInlineSVGActive="false";frontSanitizationEnabled="on"</script>
3
3<script data-optimized="1" id="wp-weglot-js-js" src="https://mystashhq.com/wp-content/litespeed/js/65f0af7c2447b974812574017d1ceb14.js?ver=9b78e"></script>
vendor: 82 bytes, lines 3-4
3 4 <script id="google_gtagjs-js" src="https://www.googletagmanager.com/gtag/js?id=
4GT-MBLLM6XC
vendor: 18 bytes, line 4
4" async></script>
4<script id="google_gtagjs-js-after">window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);} 5gtag("set","linker",{"domains":["mystashhq.com"]}); 6gtag("js", new Date()); 7gtag("set", "developer_id.dZTNiMT", true); 8gtag("config", "GT-MBLLM6XC"); 9 window._googlesitekit = window._googlesitekit || {}; window._googlesitekit.throttledEvents = []; window._googlesitekit.gtagEvent = (name, data) => { var key = JSON.stringify( { name, data } ); if ( !! window._googlesitekit.throttledEvents[ key ] ) { return; } window._googlesitekit.throttledEvents[ key ] = true; setTimeout( () => { delete window._googlesitekit.throttledEvents[ key ]; }, 5 ); gtag( "event", name, { ...data, event_source: "site-kit" } ); }; 10//# sourceURL=google_gtagjs-js-after</script>
10 <link rel="https://api.w.org/" href="https://mystashhq.com/wp-json/" /><link rel="alternate" title="JSON" type="application/json" href="https://mystashhq.com/wp-json/wp/v2/pages/1578" /><link rel="EditURI" type="application/rsd+xml" title="RSD" href="https://mystashhq.com/xmlrpc.php?rsd" /><meta name="generator" content="WordPress 7.1.1" /><link rel='shortlink' href='https://mystashhq.com/?p=1578' />
10<script>const isPerformanceMode=!1;const isStatic=!1;const isDefaultMode=!1;const isAuto=!0;const isTimeBasedMode=!1;const timeBasedModeStart="19:00";const timeBasedModeEnd="07:00";const urlParameterEnabled=!1;const draculaConfig={"mode":1,"brightness":100,"contrast":90,"sepia":10,"grayscale":0,"excludes":".dracula-ignore","darkenBackgroundImages":!0,"textStroke":"0","scrollbarColor":"auto"};function initDraculaDarkMode(){const draculaDarkMode=window.draculaDarkMode;if(isDefaultMode){window.draculaMode='dark'} 11const savedMode=localStorage.getItem('dracula_mode');if(savedMode){window.draculaMode=savedMode} 12if('dark'===window.draculaMode){draculaDarkMode?.enable(draculaConfig)}else if('auto'===savedMode||(isAuto&&!savedMode)){draculaDarkMode?.auto(draculaConfig)} 13if(draculaDarkMode?.isEnabled()){jQuery(document).ready(function(){const toggleTextElements=document.querySelectorAll('.toggle-prefix-text');toggleTextElements.forEach(el=>{el.textContent="Dark Mode"});if(dracula.isPro&&dracula.settings.enableAnalytics){wp.ajax.post('dracula_track_analytics',{type:'dark_view'})}})}else{const toggleTextElements=document.querySelectorAll('.toggle-prefix-text');toggleTextElements.forEach(el=>{el.textContent="Light Mode"})}} 14if(isPerformanceMode){}else{initDraculaDarkMode()}</script>
14<meta name="generator" content="Site Kit by Google 1.187.0" /><link rel="alternate" href="https://mystashhq.com/about/" hreflang="en"/><link rel="alternate" href="https://mystashhq.com/fr/about/" hreflang="fr"/>
14<script type="application/json" id="weglot-data">{"website":null,"uid":"f687f5fd75","project_slug":"p-f687f5fd75","deleted_at":null,"language_from":"en","language_from_custom_flag":null,"language_from_custom_name":null,"auto_switch":false,"auto_switch_fallback":null,"translation_engine":3,"excluded_paths":[],"excluded_blocks":[{"value":".msa-header","description":"NAV BAR"}],"dynamics":[],"custom_settings":{"button_style":{"is_dropdown":true,"flag_type":"rectangle_mat","with_name":true,"custom_css":"","with_flags":false,"full_name":false},"wp_user_version":"6.2","translate_email":false,"translate_search":false,"translate_amp":false,"switchers":[{"templates":{"name":"default","hash":"63e0a1891f5522181649c08d955b777e4a36bcb6"},"location":[],"style":{"with_flags":false,"flag_type":"rectangle_mat","with_name":true,"full_name":false,"is_dropdown":true}}],"definitions":[]},"media_enabled":false,"external_enabled":false,"page_views_enabled":false,"versions":{"translation":1789444522},"pending_translation_enabled":false,"curl_ssl_check_enabled":true,"custom_css":null,"languages":[{"language_to":"fr","custom_code":null,"custom_name":null,"custom_local_name":null,"provider":null,"enabled":true,"automatic_translation_enabled":true,"deleted_at":null,"connect_host_destination":null,"custom_flag":null}],"category":1,"organization_slug":"w-776c649f8c","trial_ends_at":1790654122,"technology_id":1,"technology_name":"WordPress","api_domain":"cdn-api-weglot.com","api_base_url":"https:\/\/cdn-api-weglot.com","product":"1.0","current_language":"en","switcher_links":{"en":"https:\/\/mystashhq.com\/about\/","fr":"https:\/\/mystashhq.com\/fr\/about\/"},"original_path":"\/about\/"}</script>
14
14<script>document.documentElement.className=document.documentElement.className.replace('no-js','js')</script>
14 <meta name="generator" content="Elementor 4.2.4; features: e_font_icon_svg, additional_custom_breakpoints; settings: css_print_method-external, google_font-enabled, font_display-auto">
14<script>document.addEventListener('DOMContentLoaded',function(){const audienceInput=document.getElementById('mspAudienceIndex');const conversionInput=document.getElementById('mspConversionRate');const audienceValue=document.getElementById('mspAudienceValue');const conversionValue=document.getElementById('mspConversionValue');const convertedUsers=document.getElementById('mspConvertedUsers');const monthlyEarnings=document.getElementById('mspMonthlyEarnings');const yearlyEarnings=document.getElementById('mspYearlyEarnings');const calcNote=document.getElementById('mspCalcNote');const potentialBadge=document.getElementById('mspPotentialBadge');const pricePerUser=19;const partnerShare=0.20;function getAudienceFromIndex(index){index=Number(index);if(index<=49)return 1000+(index*1000);if(index<=79)return 50000+((index-49)*5000);return 200000+((index-79)*10000)} 15function formatNumber(num){return Number(num).toLocaleString('en-US')} 16function updateCalculator(){const audience=getAudienceFromIndex(audienceInput.value);const conversion=Number(conversionInput.value);const payingUsers=Math.floor(audience*(conversion/100));const grossMonthlyRevenue=payingUsers*pricePerUser;const monthly=Math.floor(grossMonthlyRevenue*partnerShare);const yearly=monthly*12;audienceValue.textContent=formatNumber(audience);conversionValue.textContent=conversion.toFixed(1)+'%';convertedUsers.textContent=formatNumber(payingUsers);monthlyEarnings.textContent=formatNumber(monthly);yearlyEarnings.textContent=formatNumber(yearly);if(payingUsers<10){calcNote.innerHTML='<i class="ri-information-line"></i><span>Scale your audience or conversion to increase earnings.</span>'}else{calcNote.innerHTML='<i class="ri-checkbox-circle-line"></i><span>Based on '+formatNumber(payingUsers)+' paying users at $'+pricePerUser+'/mo and a 20% partner share. This grows as your audience and content scale.</span>'} 17if(audience>50000||conversion>2.0){potentialBadge.classList.add('is-visible')}else{potentialBadge.classList.remove('is-visible')}} 18if(audienceInput&&conversionInput){audienceInput.addEventListener('input',updateCalculator);conversionInput.addEventListener('input',updateCalculator);updateCalculator()} 19document.querySelectorAll('.msp-scroll').forEach(function(link){link.addEventListener('click',function(e){const targetId=this.getAttribute('href');const target=document.querySelector(targetId);if(target){e.preventDefault();target.scrollIntoView({behavior:'smooth',block:'start'})}})})})</script>
19<link rel="icon" href="https://mystashhq.com/wp-content/uploads/2025/07/Icono-App-MyStash-IconTag.png" sizes="32x32" /><link rel="icon" href="https://mystashhq.com/wp-content/uploads/2025/07/Icono-App-MyStash-IconTag.png" sizes="192x192" /><link rel="apple-touch-icon" href="https://mystashhq.com/wp-content/uploads/2025/07/Icono-App-MyStash-IconTag.png" /><meta name="msapplication-TileImage" content="https://mystashhq.com/wp-content/uploads/2025/07/Icono-App-MyStash-IconTag.png" /><meta property="og:image" content="https://mystashhq.com/wp-content/uploads/2026/01/Icono-Text-MyStash-BGW-1.png"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:image" content="https://mystashhq.com/wp-content/uploads/2026/01/Icono-Text-MyStash-BGW-1.png"></head><body class="wp-singular page-template page-template-elementor_header_footer page page-id-1578 wp-custom-logo wp-embed-responsive wp-theme-generatepress rttpg rttpg-7.9.5 radius-frontend rttpg-body-wrap rttpg-flaticon mystash-custom-nav-active no-sidebar nav-below-header separate-containers header-aligned-center dropdown-hover full-width-content elementor-default elementor-template-full-width elementor-kit-2233 elementor-page elementor-page-1578" itemtype="https://schema.org/WebPage" itemscope><header 20class="msa-header notranslate" 21data-wg-notranslate 22translate="no" 23><div class="msa-header-inner"><a 24href="https://mystashhq.com/" 25class="msa-brand" 26><img 27data-src="https://mystashhq.com/wp-content/uploads/2025/07/Icono-App-MyStash.svg" 28alt="MyStash AI" 29class="msa-brand-logo lazyload" 30src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg=="><div class="msa-brand-text"><span class="msa-brand-title"> 31MyStash AI </span><span class="msa-brand-subtitle"> 32🚀 Now live </span></div></a><nav 33class="msa-nav desktop-nav" 34aria-label="Main navigation" 35><a 36href="https://mystashhq.com/" 37class="" 38><span> 39Home </span></a><a 40href="https://mystashhq.com/solutions/" 41class="" 42><span> 43Solutions </span></a><a 44href="https://mystashhq.com/pricing/" 45class="" 46><span> 47Pricing </span></a><a 48href="https://mystashhq.com/partners/" 49class="" 50><span> 51Partners </span></a><a 52href="https://mystashhq.com/france/" 53class="msa-campaign-link msa-nav-hidden" 54> 55<span 56class="msa-campaign-icon" 57aria-hidden="true" 58> 59ð¥ 60</span><span> 61Protect France </span></a></nav><div class="msa-header-actions"><div 62class="msa-language-switcher" 63aria-label="Language selector" 64><button 65type="button" 66class="msa-language-option msa-language-en is-current" 67data-language="en" 68data-language-url="https://mystashhq.com/about/" 69aria-label="English" 70aria-pressed="true" 71> 72EN 73</button><button 74type="button" 75class="msa-language-option msa-language-fr " 76data-language="fr" 77data-language-url="https://mystashhq.com/fr/about/" 78aria-label="Français" 79aria-pressed="false" 80> 81FR 82</button></div><button 83type="button" 84class="msa-menu-toggle" 85aria-label="Open menu" 86aria-expanded="false" 87aria-controls="msa-mobile-menu" 88><span></span> 89<span></span> 90<span></span></button></div></div><div 91class="msa-mobile-menu" 92id="msa-mobile-menu" 93><nav 94class="msa-mobile-nav" 95aria-label="Mobile navigation" 96><a 97href="https://mystashhq.com/" 98class="" 99><span> 100Home </span></a><a 101href="https://mystashhq.com/solutions/" 102class="" 103><span> 104Solutions </span></a><a 105href="https://mystashhq.com/pricing/" 106class="" 107><span> 108Pricing </span></a><a 109href="https://mystashhq.com/partners/" 110class="" 111><span> 112Partners </span></a><a 113href="https://mystashhq.com/france/" 114class="msa-campaign-link msa-nav-hidden" 115> 116<span 117class="msa-campaign-icon" 118aria-hidden="true" 119> 120ð¥ 121</span><span> 122Protect France </span></a></nav></div></header><a class="screen-reader-text skip-link" href="#content" title="Skip to content">Skip to content</a><header class="site-header" id="masthead" aria-label="Site" itemtype="https://schema.org/WPHeader" itemscope><div class="inside-header"><div class="site-logo"> 123<a href="https://mystashhq.com/" rel="home"> 124<img class="header-image is-logo-image lazyload" alt="MyStash AI" data-src="https://mystashhq.com/wp-content/uploads/2025/07/Icono-Text-MyStash.svg" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==" /> 125</a></div></div></header>
125<nav class="main-navigation nav-align-center sub-menu-right" id="site-navigation" aria-label="Primary" itemtype="https://schema.org/SiteNavigationElement" itemscope><div class="inside-navigation"> 126<button class="menu-toggle" aria-controls="primary-menu" aria-expanded="false"> 127<span class="gp-icon icon-menu-bars"><svg viewBox="0 0 512 512" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em"><path d="M0 96c0-13.255 10.745-24 24-24h464c13.255 0 24 10.745 24 24s-10.745 24-24 24H24c-13.255 0-24-10.745-24-24zm0 160c0-13.255 10.745-24 24-24h464c13.255 0 24 10.745 24 24s-10.745 24-24 24H24c-13.255 0-24-10.745-24-24zm0 160c0-13.255 10.745-24 24-24h464c13.255 0 24 10.745 24 24s-10.745 24-24 24H24c-13.255 0-24-10.745-24-24z" /></svg><svg viewBox="0 0 512 512" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em"><path d="M71.029 71.029c9.373-9.372 24.569-9.372 33.942 0L256 222.059l151.029-151.03c9.373-9.372 24.569-9.372 33.942 0 9.372 9.373 9.372 24.569 0 33.942L289.941 256l151.03 151.029c9.372 9.373 9.372 24.569 0 33.942-9.373 9.372-24.569 9.372-33.942 0L256 289.941l-151.029 151.03c-9.373 9.372-24.569 9.372-33.942 0-9.372-9.373-9.372-24.569 0-33.942L222.059 256 71.029 104.971c-9.372-9.373-9.372-24.569 0-33.942z" /></svg></span><span class="mobile-menu">Menu</span> </button><div id="primary-menu" class="main-nav"><ul id="menu-menu" class=" menu sf-menu"><li id="menu-item-2384" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-home menu-item-2384"><a href="https://mystashhq.com/">Home</a></li><li id="menu-item-2340" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-2340"><a href="https://mystashhq.com/solutions/">Solutions</a></li><li id="menu-item-2339" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-2339"><a href="https://mystashhq.com/pricing/">Pricing</a></li><li id="menu-item-5695" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-5695"><a href="https://mystashhq.com/?page_id=5679">Protect France</a></li></ul></div></div></nav><div class="site grid-container container hfeed" id="page"><div class="site-content" id="content"><div data-elementor-type="wp-page" data-elementor-id="1578" class="elementor elementor-1578"><div class="elementor-element elementor-element-bde328c e-flex e-con-boxed e-con e-parent" data-id="bde328c" data-element_type="container" data-e-type="container"><div class="e-con-inner"><div class="elementor-element elementor-element-b94c517 elementor-widget elementor-widget-html" data-id="b94c517" data-element_type="widget" data-e-type="widget" data-widget_type="html.default"><div class="elementor-widget-container"> 128<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>MyStash AI - About</title></head><body><div class="ms-about-page"><div class="msa-topbar"><div class="msa-wrap"><div class="msa-brand">MyStash <span>About</span></div> 129<a href="#msa-download" class="msa-btn msa-btn-dark">Download the app</a></div></div><section class="msa-hero"><div class="msa-wrap msa-wrap-narrow msa-center"><div class="msa-badge">Built for resilience</div><h1>About MyStash AI</h1><p class="msa-hero-text"> 130Our mission is to make home inventory management accessible, ethical, and human â 131so people can prepare earlier, recover faster, and protect what matters most.</p><div class="msa-hero-actions"> 132<a href="#msa-story" class="msa-btn msa-btn-dark msa-btn-lg">Our Story <i class="ri-arrow-right-line"></i></a></div><p class="msa-hero-note"> 133Not hype. Not noise. Just a better way to document and protect your life at home.</p><div class="msa-hero-panel"><div class="msa-hero-panel-card"><div class="msa-panel-head"><div><div class="msa-kicker">What defines us</div><div class="msa-panel-title">Preparedness, privacy, recovery, and real-world usefulness</div></div><div class="msa-panel-pill"> 134<i class="ri-shield-check-line"></i> 135Human-centered by design</div></div><div class="msa-pillars-grid"><div class="msa-pillar-card"> 136<i class="ri-home-heart-line"></i> 137<span>Protect households</span></div><div class="msa-pillar-card"> 138<i class="ri-lock-line"></i> 139<span>Respect user data</span></div><div class="msa-pillar-card"> 140<i class="ri-flashlight-line"></i> 141<span>Be ready before crisis</span></div><div class="msa-pillar-card"> 142<i class="ri-line-chart-line"></i> 143<span>Set a new standard</span></div></div></div></div></div></section><section class="msa-story" id="msa-story"><div class="msa-wrap"><div class="msa-section-head msa-center"><h2>Our Story</h2><p>Why MyStash AI exists and why this problem matters so much to us.</p></div><div class="msa-split-grid"><div class="msa-copy-block"><p> 144MyStash AI was born from a personal crisis. After experiencing a home disaster, 145our founder discovered the painful reality of trying to document lost possessions from memory alone.</p><p> 146What began as a simple tool to help people catalog their belongings evolved into a broader resilience platform. 147We built MyStash AI for people like us â people who understand that preparation is not fear, it is practicality.</p><p> 148As an underdog in tech, we chose to solve a real-life problem instead of chasing trends. 149Our goal has always been to combine powerful AI with intuitive design so inventory management becomes something people can actually use.</p></div><div class="msa-visual-card"> 150<img decoding="async" data-src="https://mystashhq.com/wp-content/uploads/2025/08/Our-Story.png" alt="Our Story - MyStash AI" class="msa-visual-image lazyload" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==" style="--smush-placeholder-width: 1536px; --smush-placeholder-aspect-ratio: 1536/1024;"></div></div></div></section><section class="msa-mission"><div class="msa-wrap"><div class="msa-split-grid msa-split-reverse"><div class="msa-visual-card"> 151<img decoding="async" data-src="https://mystashhq.com/wp-content/uploads/2025/08/Our-Mission.png" alt="Our Mission - MyStash AI" class="msa-visual-image lazyload" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==" style="--smush-placeholder-width: 1536px; --smush-placeholder-aspect-ratio: 1536/1024;"></div><div class="msa-copy-block"><div class="msa-section-head msa-left"><h2>Our Mission</h2><p>Make resilience more accessible for everyday families and vulnerable communities.</p></div><p>
152We believe resilience should not be a luxury. That is why MyStash AI is designed to be useful for individuals and families of all backgrounds, 153regardless of technical experience or financial situation.</p><p> 154We are actively working toward a future where preparedness tools can help people in vulnerable communities protect what matters most 155and recover faster after catastrophic events.</p><p> 156As we grow, we remain committed to building responsibly â with privacy, dignity, accessibility, and trust at the core of everything we do.</p><div class="msa-chip-row"><div class="msa-chip"> 157<i class="ri-community-fill"></i> 158<span>Community Support</span></div><div class="msa-chip"> 159<i class="ri-hand-heart-line"></i> 160<span>Disaster Relief</span></div><div class="msa-chip"> 161<i class="ri-open-source-line"></i> 162<span>Open Collaboration</span></div></div></div></div></div></section><section class="msa-ethics"><div class="msa-wrap"><div class="msa-section-head msa-center"><h2>Our Ethics</h2><p>We believe trust must be earned through product choices, not just promises.</p></div><div class="msa-ethics-grid"><div class="msa-ethics-main"><div class="msa-ethics-copy"><p> 163Your data belongs to you â period. MyStash AI is built with privacy as a foundational principle, not an afterthought. 164Your inventory data is meant to help you, not to become a product for someone else.</p><p> 165Our AI is designed to serve, not surveil. We use machine learning to help people catalog faster and organize better, 166while maintaining clear boundaries around how data is handled and protected.</p><p> 167We believe in transparency. We want our users to understand how we think, how we build, and why trust is central to the future of this platform.</p></div><div class="msa-ethics-points"><div class="msa-benefit-row"> 168<i class="ri-lock-line"></i><div><h4>End-to-End Protection Mindset</h4><p>Security and privacy are considered from the start, not added later.</p></div></div><div class="msa-benefit-row"> 169<i class="ri-shield-check-line"></i><div><h4>Data Ownership</h4><p>Your inventory exists to support your recovery, organization, and peace of mind.</p></div></div><div class="msa-benefit-row"> 170<i class="ri-file-list-3-line"></i><div><h4>Clarity and Transparency</h4><p>We aim to communicate responsibly, clearly, and in language real people can understand.</p></div></div></div></div><div class="msa-ethics-visual"><div class="msa-visual-card msa-visual-card-dark"> 171<img decoding="async" data-src="https://mystashhq.com/wp-content/uploads/2025/08/Our-Ethics.png" alt="Our Ethics - MyStash AI" class="msa-visual-image lazyload" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==" style="--smush-placeholder-width: 1536px; --smush-placeholder-aspect-ratio: 1536/1024;"></div></div></div></div></section><section class="msa-standard"><div class="msa-wrap"><div class="msa-split-grid msa-split-reverse"><div class="msa-visual-card"> 172<img decoding="async" data-src="https://mystashhq.com/wp-content/uploads/2025/08/Digital-Inentory-Standard.png" alt="The Digital Inventory Standard - MyStash AI" class="msa-visual-image lazyload" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==" style="--smush-placeholder-width: 1536px; --smush-placeholder-aspect-ratio: 1536/1024;"></div><div class="msa-copy-block"><div class="msa-section-head msa-left"><h2>The Digital Inventory Standard</h2><p>We are not just building an app. We are helping define a better category.</p></div><p> 173Our vision is bigger than storage or item lists. We want to help establish a universal, practical, and trustworthy standard 174for documenting, valuing, and protecting personal possessions.</p><p> 175Over time, digital inventory can become an essential layer of financial, insurance, and family preparedness â 176something as useful as any other core household record.</p><p> 177We believe the future should prioritize portability, autonomy, and user control, 178so people are never trapped by a tool when what they really need is long-term protection.</p></div></div></div></section><section class="msa-quote"><div class="msa-wrap"><div class="msa-quote-card"><div class="msa-quote-grid"><div class="msa-quote-copy"><div class="msa-badge msa-badge-dark">Built to protect people like us</div><h2>Why this matters personally</h2><p> 179âWhen someone close to me lost everything in a house fire, I saw firsthand how devastating it was â 180not just emotionally, but practically. Insurance required documentation they no longer had. 181Trying to remember every item after a disaster is almost impossible.â</p><p> 182âThat experience became the spark for MyStash AI. I wanted to build something that helps people protect what matters before it is too late â 183not just for peace of mind, but for real recovery when life goes wrong.â</p><p> 184âWe are not trying to become noise in the tech industry. We are building something useful, trustworthy, and durable â 185something that can genuinely help people when they need it most.â</p><div class="msa-signature">â Your Team at MyStash AI</div></div><div class="msa-quote-visual"><div class="msa-visual-card"> 186<img decoding="async" data-src="https://mystashhq.com/wp-content/uploads/2025/08/Protect.png" alt="Built to protect people like us - MyStash AI" class="msa-visual-image lazyload" src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==" style="--smush-placeholder-width: 1536px; --smush-placeholder-aspect-ratio: 1536/1024;"></div></div></div></div></div></section><section class="msa-cta" id="msa-cta"><div class="msa-wrap msa-wrap-narrow msa-center"><div class="msa-cta-badge">Preparedness starts now</div><h2>Download MyStash AI and Start Protecting What Matters</h2><p> 187Create your account directly in the app, choose your plan, 188and begin organizing your home inventory in minutes.</p><div class="msa-download-buttons" id="msa-download"> 189<a 190href="https://apps.apple.com/us/app/mystash-ai/id6757621719" 191target="_blank" 192rel="noopener noreferrer" 193aria-label="Download MyStash AI on the App Store" 194> 195<img decoding="async" 196data-src="https://mystashhq.com/wp-content/uploads/2026/03/Download-AppStore.png" 197alt="Download on the App Store" 198src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==" class="lazyload" style="--smush-placeholder-width: 1003px; --smush-placeholder-aspect-ratio: 1003/350;"> 199</a><a 200href="https://play.google.com/store/apps/details?id=com.underdogs.mystashai" 201target="_blank" 202rel="noopener noreferrer" 203aria-label="Get MyStash AI on Google Play" 204> 205<img decoding="async" 206data-src="https://mystashhq.com/wp-content/uploads/2026/03/Download-PlayStore.png" 207alt="Get it on Google Play" 208src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==" class="lazyload" style="--smush-placeholder-width: 5986px;
208 --smush-placeholder-aspect-ratio: 5986/2088;"> 209</a></div><p class="msa-hero-note"> 210Account creation and plan selection happen directly inside the app.</p></div></section></div><footer class="footer-section"><div class="footer-container"><div class="footer-brand"><div class="footer-logo">MyStash AI</div><p>The resilience platform that helps you protect what matters most through AI-powered home inventory management.</p><div class="social-icons"> 211<a href="https://www.instagram.com/mystash_ai?igsh=bmJ3MTY5a2xuZDh0" target="_blank" rel="noopener noreferrer"><i class="ri-instagram-line"></i></a> 212<a href="https://www.youtube.com/@MyStashAI" target="_blank" rel="noopener noreferrer"><i class="ri-youtube-fill"></i></a> 213<a href="https://www.tiktok.com/@mystash.ai" target="_blank" rel="noopener noreferrer"><i class="ri-tiktok-fill"></i></a></div></div><div class="footer-links"><div><h4>Product</h4> 214<a href="https://mystashhq.com/solutions/" target="_blank" rel="noopener noreferrer">Solutions</a> <br> 215<a href="https://mystashhq.com/pricing/" target="_blank" rel="noopener noreferrer">Pricing</a></div><div><h4>Company</h4> 216<a href="https://mystashhq.com/about/" target="_blank" rel="noopener noreferrer">About Us</a> <br> 217<a href="https://mystashhq.com/contact/" target="_blank" rel="noopener noreferrer">Contact</a></div><div><h4>Resources</h4> 218<a href="https://mystashhq.com/resources/" target="_blank" rel="noopener noreferrer">Latest Articles</a> <br> 219<a href="https://mystashhq.com/partners/" target="_blank" rel="noopener noreferrer">Partners</a></div></div></div><div class="footer-bottom"> 220© 2026 MyStash AI. All rights reserved. | 221<a href="https://mystashhq.com/privacy-policy/" target="_blank" rel="noopener noreferrer">Privacy Policy</a> | 222<a href="https://mystashhq.com/terms-of-service/" target="_blank" rel="noopener noreferrer">Terms & Conditions</a> | 223<a href="https://mystashhq.com/cookie-policy/" target="_blank" rel="noopener noreferrer">Cookie Policy</a> | 224<a href="https://mystashhq.com/disclaimer/" target="_blank" rel="noopener noreferrer">Disclaimer</a> | 225<a href="https://mystashhq.com/acceptable-use-policy/" target="_blank" rel="noopener noreferrer">Acceptable Use</a> | 226<a href="https://mystashhq.com/return-policy/" target="_blank" rel="noopener noreferrer">Return Policy</a> | 227<a href="https://mystashhq.com/license-agreement/" target="_blank" rel="noopener noreferrer">License Agreement</a></div></footer>
227<script>document.addEventListener("DOMContentLoaded",function(){document.querySelectorAll('.ms-about-page a[href^="#"]').forEach(function(link){link.addEventListener("click",function(event){const targetId=link.getAttribute("href");if(!targetId||targetId==="#"){return} 228const target=document.querySelector(targetId);if(!target){return} 229event.preventDefault();target.scrollIntoView({behavior:"smooth",block:"start"})})})})</script>
229 <aside data-wg-notranslate="" class="country-selector weglot-dropdown close_outside_click closed weglot-default wg-" tabindex="0" aria-expanded="false" aria-label="Language selected: English"><input id="wg6ab530ac8827f3.767013521790259372799" class="weglot_choice" type="checkbox" name="menu"/><label data-l="en" tabindex="-1" for="wg6ab530ac8827f3.767013521790259372799" class="wgcurrent wg-li weglot-lang weglot-language flag-0 wg-en" data-code-language="wg-en" data-name-language="EN"><span class="wglanguage-name">EN</span></label><ul role="none"><li data-l="fr" class="wg-li weglot-lang weglot-language flag-0 wg-fr" data-code-language="fr" role="option"><a title="Language switcher : French" class="weglot-language-fr" role="option" data-wg-notranslate="" href="https://mystashhq.com/fr/about/">FR</a></li></ul></aside></body></html></div></div><div class="elementor-element elementor-element-ca67eb4 elementor-widget elementor-widget-html" data-id="ca67eb4" data-element_type="widget" data-e-type="widget" data-widget_type="html.default"><div class="elementor-widget-container"></div></div></div></div></div></div></div><div class="site-footer"><footer class="site-info" aria-label="Site" itemtype="https://schema.org/WPFooter" itemscope><div class="inside-site-info"><div class="copyright-bar"> 230<span class="copyright">© 2026 MyStash AI</span> • Built with <a href="https://generatepress.com" itemprop="url">GeneratePress</a></div></div></footer></div>
230<script type="speculationrules">{"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/generatepress/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]}</script>
230 <div class="dracula-toggle-wrap floating position-right" data-style="2"></div>
230<script data-optimized="1" id="generate-a11y">!function(){"use strict";if("querySelector"in document&&"addEventListener"in window){var e=document.body;e.addEventListener("pointerdown",(function(){e.classList.add("using-mouse")}),{passive:!0}),e.addEventListener("keydown",(function(){e.classList.remove("using-mouse")}),{passive:!0})}}()</script>
230
230<script>(()=>{const lazyloadRunObserver=()=>{const lazyloadBackgrounds=document.querySelectorAll(`.e-con.e-parent:not(.e-lazyloaded)`);const lazyloadBackgroundObserver=new IntersectionObserver((entries)=>{entries.forEach((entry)=>{if(entry.isIntersecting){let lazyloadBackground=entry.target;if(lazyloadBackground){lazyloadBackground.classList.add('e-lazyloaded')} 231lazyloadBackgroundObserver.unobserve(entry.target)}})},{rootMargin:'200px 0px 200px 0px'});lazyloadBackgrounds.forEach((lazyloadBackground)=>{lazyloadBackgroundObserver.observe(lazyloadBackground)})};const events=['DOMContentLoaded','elementor/lazyload/observe',];events.forEach((event)=>{document.addEventListener(event,lazyloadRunObserver)})})()</script>
231
231<script>(function(){if(window.__MS_SIGNUP_SNIPPET__)return;window.__MS_SIGNUP_SNIPPET__=!0;const root=document.getElementById("ms-signup");if(!root)return;const el=(id)=>document.getElementById(id);const showMsg=(text,kind)=>{const m=el("ms-msg");if(!m)return;m.className="msg show"+(kind?" "+kind:"");m.textContent=text||""};const clearMsg=()=>{const m=el("ms-msg");if(!m)return;m.className="msg";m.textContent=""};const nextPaint=()=>new Promise((r)=>requestAnimationFrame(()=>requestAnimationFrame(r)));function cleanErrorMessage(raw){let s=String(raw||"Unknown error");s=s.replace(/^Firebase:\s*/i,"");s=s.replace(/\s*\((auth|functions)\/[^\)]+\)\s*\.?/gi,"");s=s.replace(/^(auth|functions)\/[a-z0-9-]+:\s*/i,"");s=s.replace(/\s{2,}/g," ").trim();return s} 232function userFacingAuthError(e){const code=String(e&&e.code?e.code:"");if(code==="auth/invalid-credential"||code==="auth/wrong-password"||code==="auth/user-not-found")return"Incorrect email or password.";if(code==="auth/email-already-in-use")return"This email is already registered. Please sign in.";if(code==="auth/invalid-email")return"That email address looks invalid.";if(code==="auth/weak-password")return"Password is too weak. Use at least 8 characters.";if(code==="auth/too-many-requests")return"Too many attempts. Please wait and try again.";if(code==="auth/network-request-failed")return"Connection issue. Please check your internet and try again.";if(code==="auth/popup-blocked")return"Popup blocked. Please allow popups and try again.";if(code==="auth/popup-closed-by-user")return"Sign-up canceled.";if(code==="auth/account-exists-with-different-credential") 233return"This email is linked to a different sign-in method. Try another option.";const msg=cleanErrorMessage(e&&e.message?e.message:"");const details=cleanErrorMessage(e&&e.details?e.details:"");return(details?(msg?(msg+" â "+details):details):msg)||"Something went wrong. Please try again."} 234function sanitizeRef(raw){return String(raw||"").toUpperCase().replace(/[^A-Z0-9]/g,"").slice(0,10)} 235function setBtnLoading(btn,loading){if(!btn)return;if(loading){btn.classList.add("loading");btn.disabled=!0;return} 236btn.classList.remove("loading");btn.disabled=!1} 237async function withWatchdog(promise,ms=25000){let done=!1;const timer=setTimeout(()=>{if(!done)showMsg("This is taking longer than expected. Please try again.","err");},ms);try{const r=await promise;done=!0;clearTimeout(timer);return r}catch(e){done=!0;clearTimeout(timer);throw e}} 238function getNextPath(){const p=new URLSearchParams(window.location.search);const next=String(p.get("next")||"/account/").trim();return next.startsWith("/")?next:"/account/"} 239const pageParams=new URLSearchParams(window.location.search);const isAppFlow=String(pageParams.get("source")||"").toLowerCase()==="app";const BOOT_RETRY_KEY="ms_signup_boot_retry";const BOOT_QUERY_KEY="msfb";function getBootstrapRetryCount(){return Number(sessionStorage.getItem(BOOT_RETRY_KEY)||"0")} 240function clearBootstrapRetryCount(){sessionStorage.removeItem(BOOT_RETRY_KEY)} 241function retryBootstrapReload(maxRetries=4,delayMs=350){if(!shouldUseHardReloadRecovery())return!1;const count=getBootstrapRetryCount();if(count>=maxRetries)return!1;sessionStorage.setItem(BOOT_RETRY_KEY,String(count+1));const url=new URL(window.location.href);url.searchParams.set(BOOT_QUERY_KEY,String(Date.now()));setTimeout(()=>{window.location.replace(url.toString())},delayMs);return!0} 242function isSafariBrowser(){const ua=navigator.userAgent||"";return/Safari/i.test(ua)&&!/Chrome|CriOS|Edg|OPR|Firefox|FxiOS|Android/i.test(ua)} 243function isMobileBrowser(){const ua=navigator.userAgent||"";return/Android|iPhone|iPad|iPod|Mobile/i.test(ua)} 244function shouldUseHardReloadRecovery(){return isSafariBrowser()||isMobileBrowser()||isAppFlow} 245function setBootVisibility(isReady){if(!root)return;root.style.transition="opacity .18s ease";root.style.opacity=isReady?"1":"0";root.style.pointerEvents=isReady?"":"none"} 246function cleanupBootstrapQueryParam(){try{const url=new URL(window.location.href);if(!url.searchParams.has(BOOT_QUERY_KEY))return;url.searchParams.delete(BOOT_QUERY_KEY);window.history.replaceState({},document.title,url.toString())}catch(_){}} 247function sleep(ms){return new Promise((resolve)=>setTimeout(resolve,ms))} 248window.addEventListener("pageshow",function(event){if(!isSafariBrowser())return;if(!event.persisted)return;const count=getBootstrapRetryCount();if(count>=8)return;const url=new URL(window.location.href);
248url.searchParams.set(BOOT_QUERY_KEY,String(Date.now()));sessionStorage.setItem(BOOT_RETRY_KEY,String(count+1));window.location.replace(url.toString())});const linksBlock=root.querySelector(".links");if(isAppFlow&&linksBlock){linksBlock.style.display="none"} 249const signInUrl="https://mystashhq.com/sign-in/";const accountActivationUrl="https://mystashhq.com/account/?activation=required";const authActionUrl=isAppFlow?"https://mystashhq.com/auth/?source=app":"https://mystashhq.com/auth/";function goAfterSignup(email){const safeEmail=String(email||"").trim();if(isAppFlow){openAppOrFallback("signup",safeEmail,signInUrl);return} 250window.location.replace(accountActivationUrl)} 251const ua=navigator.userAgent||"";const isAndroid=/Android/i.test(ua);const isIOS=/iPhone|iPad|iPod/i.test(ua);function escapeHtml(v){return String(v||"").replace(/[&<>"']/g,(ch)=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[ch]))} 252function providerLabelFromUser(user){const pid=String((user?.providerData?.[0]?.providerId)||"").toLowerCase();if(pid.includes("google"))return"Google";if(pid.includes("apple"))return"Apple";return"your provider"} 253function scrollSignupToTop(){const run=()=>{try{window.scrollTo({top:0,left:0,behavior:"smooth"})}catch(_){window.scrollTo(0,0)} 254try{document.documentElement.scrollTop=0}catch(_){} 255try{document.body.scrollTop=0}catch(_){} 256try{root.scrollIntoView({behavior:"smooth",block:"start"})}catch(_){}};run();setTimeout(run,80);setTimeout(run,240);setTimeout(run,520)} 257function openAppOrFallback(mode,email,fallbackUrl=signInUrl){const modeSafe=encodeURIComponent(mode||"signup");const emailPart=email?`&email=${encodeURIComponent(email)}`:"";const deep=`mystashai://signup-complete?mode=${modeSafe}${emailPart}`;if(isAndroid){window.location.href=`intent://signup-complete?mode=${modeSafe}${emailPart}`+`#Intent;scheme=mystashai;package=com.underdogs.mystashai;`+`S.browser_fallback_url=${encodeURIComponent(fallbackUrl)};end`;return} 258if(isIOS){window.location.href=deep;setTimeout(()=>{window.location.href=fallbackUrl},1200);return} 259window.location.href=fallbackUrl} 260function renderPostSignupState({title,subtitle,message,kind="ok",primaryText,primaryHref,primaryHandler,secondaryText,secondaryHref,footnote}){const titleEl=root.querySelector(".title");const subEl=root.querySelector(".sub");const authBlock=root.querySelector(".auth-block");const links=root.querySelector(".links");const foot=root.querySelector(".footnote");if(titleEl)titleEl.textContent=title||"";if(subEl)subEl.textContent=subtitle||"";if(authBlock)authBlock.style.display="none";showMsg(message||"",kind);if(links){const actions=[];if(primaryText&&(primaryHref||primaryHandler)){actions.push(`<a class="btn primary" href="${primaryHref || "#"}" id="ms-primary-action">${escapeHtml(primaryText)}</a>`)} 261if(secondaryText&&secondaryHref){actions.push(`<a class="btn btn-secondary" href="${secondaryHref}">${escapeHtml(secondaryText)}</a>`)} 262links.innerHTML=actions.join("")} 263if(foot){foot.textContent=footnote||""} 264const primary=document.getElementById("ms-primary-action");if(primary&&typeof primaryHandler==="function"){primary.addEventListener("click",(ev)=>{ev.preventDefault();primaryHandler()})} 265setTimeout(()=>{scrollSignupToTop()},0)} 266function renderVerifyState(email){const safeEmail=String(email||"").trim();renderPostSignupState({title:"Verify your email",subtitle:"We created your account. Please verify your email before signing in.",message:safeEmail?`We sent a verification email to ${safeEmail}. After verifying, return to MyStash AI.`:"We sent you a verification email. After verifying, return to MyStash AI.",kind:"ok",primaryText:isAppFlow?"Return to MyStash AI":"Go to Sign in",primaryHref:isAppFlow?"#":signInUrl,primaryHandler:isAppFlow?()=>openAppOrFallback("signup",safeEmail,signInUrl):null,secondaryText:isAppFlow?"Go to Sign in":"",secondaryHref:isAppFlow?signInUrl:"",footnote:isAppFlow?"You can close this window after returning to the app.":"After verifying your email, sign in to continue."})}
267function renderSocialSignupState(email,providerLabel){const safeEmail=String(email||"").trim();const safeProvider=providerLabel||"your provider";renderPostSignupState({title:"Account ready",subtitle:`Your account was created with ${safeProvider}.`,message:safeEmail?`Your ${safeProvider} account (${safeEmail}) is ready. Return to MyStash AI and sign in.`:`Your ${safeProvider} account is ready. Return to MyStash AI and sign in.`,kind:"ok",primaryText:isAppFlow?"Return to MyStash AI":"Go to Sign in",primaryHref:isAppFlow?"#":signInUrl,primaryHandler:isAppFlow?()=>openAppOrFallback("signup",safeEmail,signInUrl):null,secondaryText:isAppFlow?"Go to Sign in":"",secondaryHref:isAppFlow?signInUrl:"",footnote:isAppFlow?"You can close this window after returning to the app.":"Sign in to continue."})} 268const FIREBASE_VERSION="10.12.5";const LOCAL_BASE=`/wp-content/uploads/ms/firebase/${FIREBASE_VERSION}/`;const GSTATIC_BASE=`https://www.gstatic.com/firebasejs/${FIREBASE_VERSION}/`;const SDK_FILES=["firebase-app-compat.js","firebase-auth-compat.js","firebase-firestore-compat.js"];function buildScriptUrl(base,file){const sep=base.includes("?")?"&":"?";const boot=pageParams.get(BOOT_QUERY_KEY)||String(Date.now());return `${base}${file}${sep}v=${encodeURIComponent(FIREBASE_VERSION)}&boot=${encodeURIComponent(boot)}`} 269function sdkReadyFor(file){if(file==="firebase-app-compat.js"){return!!(window.firebase&&firebase.initializeApp)} 270if(file==="firebase-auth-compat.js"){return!!(window.firebase&&firebase.auth)} 271if(file==="firebase-firestore-compat.js"){return!!(window.firebase&&firebase.firestore)} 272return!1} 273function waitForReady(check,timeoutMs=15000,stepMs=50){return new Promise((resolve,reject)=>{const start=Date.now();(function tick(){if(check())return resolve();if(Date.now()-start>=timeoutMs){return reject(new Error("Firebase not available."))} 274setTimeout(tick,stepMs)})()})} 275function loadScriptOnce(url,readyCheck,timeoutMs=15000){return new Promise((resolve,reject)=>{if(readyCheck()){resolve();return} 276let script=Array.from(document.scripts||[]).find((s)=>{try{const existing=new URL(s.src,window.location.origin);const incoming=new URL(url,window.location.origin);return existing.origin===incoming.origin&&existing.pathname===incoming.pathname}catch(_){return s.src===url}});const finalize=()=>{waitForReady(readyCheck,timeoutMs).then(resolve).catch(()=>reject(new Error(`Timeout loading: ${url}`)))};if(script){finalize();return} 277script=document.createElement("script");script.src=url;script.async=!1;script.defer=!1;script.setAttribute("data-cfasync","false");script.addEventListener("load",finalize,{once:!0});script.addEventListener("error",()=>reject(new Error(`Failed loading: ${url}`)),{once:!0});document.head.appendChild(script)})} 278async function loadWithFallback(file){const readyCheck=()=>sdkReadyFor(file);if(isSafariBrowser()){await loadScriptOnce(buildScriptUrl(GSTATIC_BASE,file),readyCheck);return} 279try{await loadScriptOnce(buildScriptUrl(LOCAL_BASE,file),readyCheck)}catch(_){await loadScriptOnce(buildScriptUrl(GSTATIC_BASE,file),readyCheck)}} 280async function ensureFirebaseLoaded(){if(window.firebase&&firebase.initializeApp&&firebase.auth&&firebase.firestore){return} 281if(window.__MS_FIREBASE_READY__&&typeof window.__MS_FIREBASE_READY__.then==="function"){return window.__MS_FIREBASE_READY__} 282window.__MS_FIREBASE_READY__=(async()=>{for(const f of SDK_FILES){await loadWithFallback(f)} 283if(!window.firebase||!firebase.initializeApp||!firebase.auth||!firebase.firestore){throw new Error("Firebase not available.")}})();try{await window.__MS_FIREBASE_READY__}catch(e){window.__MS_FIREBASE_READY__=null;throw e}} 284function removeFirebaseBootScripts(){const targets=[`firebase-app-compat.js`,`firebase-auth-compat.js`,`firebase-firestore-compat.js`];Array.from(document.scripts||[]).forEach((s)=>{const src=String(s.src||"");const isFirebaseSdk=targets.some((name)=>src.includes(name))&&(src.includes(`/wp-content/uploads/ms/firebase/${FIREBASE_VERSION}/`)||src.includes(`https://www.gstatic.com/firebasejs/${FIREBASE_VERSION}/`));if(isFirebaseSdk){try{s.remove()}catch(_){}}})} 285async function ensureFirebaseLoadedWithRecovery(){const inPlaceAttempts=shouldUseHardReloadRecovery()?1:3;let lastError=null;for(let i=0;i<inPlaceAttempts;i++){try{await ensureFirebaseLoaded();return}catch(e){lastError=e;window.__MS_FIREBASE_READY__=null;removeFirebaseBootScripts();if(i<inPlaceAttempts-1){await sleep(250*(i+1))}}} 286throw lastError||new Error("Firebase not available.")} 287async function ensureUserDocSignup(db,user,desiredName,usedReferralCode){if(!user||!user.uid)return;const ref=db.collection("users").doc(user.uid);const snap=await ref.get();const now=new Date();const emailLower=user.email?String(user.email).toLowerCase():null;if(!snap.exists){await ref.set({uid:user.uid,email:emailLower,name:desiredName||user.displayName||null,language:"en",currency:"USD",trialUsed:!1,subscriptionStatus:"free",subscriptionType:"free",accessStatus:"pending_activation",activationStartedAt:now,activationCompletedAt:null,trialStartedAt:null,trialEndsAt:null,lifecycleEmails:{activation24QueuedAt:null,activation24SentAt:null,activation72QueuedAt:null,activation72SentAt:null},usedReferralCode:usedReferralCode||null,createdAt:now,},{merge:!0});return} 288const data=snap.data()||{};const patch={};if(!data.language)patch.language="en";if(!data.currency)patch.currency="USD";
288if(!data.trialUsed&&data.trialUsed!==!1)patch.trialUsed=!1;if(!data.subscriptionStatus)patch.subscriptionStatus="free";if(!data.subscriptionType)patch.subscriptionType="free";const statusNow=String(data.subscriptionStatus||"free").toLowerCase();const typeNow=String(data.subscriptionType||"free").toLowerCase();const hasActiveAccess=["active","trialing","lifetime"].includes(statusNow)||["lifetime","influencer","owner"].includes(typeNow)||data.lifetimeActive===!0||data.influencerActive===!0||data.ownerActive===!0;if(!hasActiveAccess&&!data.accessStatus){patch.accessStatus="pending_activation";patch.activationStartedAt=data.createdAt||now;patch.activationCompletedAt=null;patch.trialStartedAt=null;patch.trialEndsAt=null} 289if(!data.lifecycleEmails){patch.lifecycleEmails={activation24QueuedAt:null,activation24SentAt:null,activation72QueuedAt:null,activation72SentAt:null}} 290if(!data.subscriptionTier)patch.subscriptionTier="free";if(!data.subscriptionRenews)patch.subscriptionRenews="free";if(!data.email&&emailLower)patch.email=emailLower;if(!data.name){const nm=desiredName||user.displayName||null;if(nm)patch.name=nm} 291if(usedReferralCode&&!data.usedReferralCode)patch.usedReferralCode=usedReferralCode;if(Object.keys(patch).length){patch.updatedAt=new Date();await ref.set(patch,{merge:!0})}} 292async function validateReferralIfAny(db,rawRef){const ref=sanitizeRef(rawRef);if(!ref)return null;if(!/^[A-Z0-9]{10}$/.test(ref)){throw new Error("Creator code must be 10 letters/numbers.")} 293const rSnap=await db.collection("referralCodes").doc(ref).get();if(!rSnap.exists){throw new Error("That creator code doesn't exist.")} 294return ref} 295function ensureReferralPromptStyles(){if(document.getElementById("ms-referral-prompt-style"))return;const style=document.createElement("style");style.id="ms-referral-prompt-style";style.textContent=` 296 .ms-referral-overlay{ 297 position: fixed !important; 298 inset: 0 !important; 299 background: rgba(17,17,17,.48) !important; 300 display: flex !important; 301 align-items: center !important; 302 justify-content: center !important; 303 padding: 18px !important; 304 z-index: 999999 !important; 305 } 306 307 .ms-referral-modal{ 308 width: 100% !important; 309 max-width: 420px !important; 310 background: #fff !important; 311 border-radius: 28px !important; 312 border: 1px solid rgba(17,17,17,.10) !important; 313 box-shadow: 0 24px 50px rgba(0,0,0,.20) !important; 314 padding: 22px !important; 315 color: #111111 !important; 316 font-family: Arial, sans-serif !important; 317 } 318 319 .ms-referral-title{ 320 margin: 0 0 8px !important; 321 font-size: 26px !important; 322 line-height: 1.05 !important; 323 font-weight: 1000 !important; 324 letter-spacing: -.8px !important; 325 color: #111111 !important; 326 } 327 328 .ms-referral-sub{ 329 margin: 0 0 16px !important; 330 color: #6b7280 !important; 331 font-size: 14px !important; 332 line-height: 1.55 !important; 333 font-weight: 700 !important; 334 } 335 336 .ms-referral-label{ 337 display: block !important; 338 font-size: 12px !important; 339 font-weight: 900 !important; 340 letter-spacing: .7px !important; 341 text-transform: uppercase !important; 342 color: rgba(17,17,17,.62) !important; 343 margin: 0 0 8px !important; 344 } 345 346 .ms-referral-input{ 347 width: 100% !important; 348 height: 56px !important; 349 border-radius: 18px !important; 350 border: 1.5px solid rgba(17,17,17,.14) !important; 351 padding: 0 16px !important; 352 font-weight: 800 !important; 353 font-size: 15px !important; 354 outline: none !important; 355 background: #fff !important; 356 color: #111111 !important; 357 text-transform: uppercase !important; 358 box-shadow: none !important; 359 appearance: none !important; 360 -webkit-appearance: none !important; 361 } 362 363 .ms-referral-input:focus{ 364 border-color: rgba(17,17,17,.42) !important; 365 box-shadow: 0 0 0 4px rgba(17,17,17,.06) !important; 366 } 367 368 .ms-referral-input[readonly]{ 369 background: #f0fdf4 !important; 370 border-color: rgba(22,163,74,.34) !important; 371 color: #166534 !important; 372 box-shadow: 0 0 0 3px rgba(22,163,74,.08) !important;
373 cursor: not-allowed !important; 374 } 375 376 .ms-referral-error{ 377 min-height: 20px !important; 378 margin-top: 10px !important; 379 color: rgba(180,35,24,.95) !important; 380 font-size: 13px !important; 381 font-weight: 800 !important; 382 line-height: 1.35 !important; 383 } 384 385 .ms-referral-actions{ 386 display: grid !important; 387 gap: 12px !important; 388 margin-top: 8px !important; 389 } 390 391 .ms-referral-btn{ 392 width: 100% !important; 393 min-height: 54px !important; 394 border-radius: 18px !important; 395 border: 1px solid rgba(17,17,17,.16) !important; 396 background: #fff !important; 397 color: #111111 !important; 398 font-weight: 900 !important; 399 font-size: 15px !important; 400 cursor: pointer !important; 401 transition: background .16s ease, border-color .16s ease, transform .16s ease, box-shadow .16s ease !important; 402 box-shadow: none !important; 403 appearance: none !important; 404 -webkit-appearance: none !important; 405 } 406 407 .ms-referral-btn:hover{ 408 transform: translateY(-1px) !important; 409 } 410 411 .ms-referral-btn.primary{ 412 background: #111111 !important; 413 color: #fff !important; 414 border-color: #111111 !important; 415 box-shadow: 0 14px 30px rgba(0,0,0,.12) !important; 416 } 417 418 .ms-referral-btn.secondary{ 419 background: #fff !important; 420 color: #111111 !important; 421 border-color: rgba(17,17,17,.16) !important; 422 } 423 424 .ms-referral-btn.cancel{ 425 background: transparent !important; 426 color: #6b7280 !important; 427 border-color: transparent !important; 428 min-height: 42px !important; 429 border-radius: 14px !important; 430 } 431 432 .ms-referral-btn.cancel:active, 433 .ms-referral-btn.cancel:focus{ 434 background: rgba(17,17,17,.05) !important; 435 color: #111111 !important; 436 outline: none !important; 437 box-shadow: none !important; 438 } 439 `;document.head.appendChild(style)} 440function promptReferralCodeOptional(initialRaw="",lockedByLink=!1){ensureReferralPromptStyles();return new Promise((resolve)=>{const initialCode=sanitizeRef(initialRaw||"");const autoLocked=!!lockedByLink&&/^[A-Z0-9]{10}$/.test(initialCode);const overlay=document.createElement("div");overlay.className="ms-referral-overlay";overlay.innerHTML=` 441 <div class="ms-referral-modal" role="dialog" aria-modal="true" aria-labelledby="ms-referral-title"> 442 <h3 class="ms-referral-title" id="ms-referral-title"> 443 ${autoLocked ? "Creator code detected" : "Creator code"} 444 </h3> 445 446 <p class="ms-referral-sub"> 447 ${ 448 autoLocked 449 ? `This sign up is already linked to creator code "${initialCode}".` 450 : "If you have a creator code, enter it now before continuing with sign up. This step is optional." 451 } 452 </p> 453 454 <label class="ms-referral-label" for="ms-referral-popup-input"> 455 ${autoLocked ? "Creator code" : "Creator code (optional)"} 456 </label> 457 458 <input 459 id="ms-referral-popup-input" 460 class="ms-referral-input" 461 type="text" 462 maxlength="10" 463 autocomplete="off" 464 placeholder="${autoLocked ? "" : "XXXXXXXXXX"}" 465 ${autoLocked ? "readonly" : ""} 466 /> 467 468 <div class="ms-referral-error" id="ms-referral-popup-error"></div> 469 470 <div class="ms-referral-actions"> 471 <button type="button" class="ms-referral-btn primary" id="ms-referral-popup-continue">Continue</button> 472 ${autoLocked ? "" : `<button type="button" class="ms-referral-btn secondary" id="ms-referral-popup-skip">Skip</button>`} 473 <button type="button" class="ms-referral-btn cancel" id="ms-referral-popup-cancel">Cancel</button> 474 </div> 475 </div> 476 `;document.body.appendChild(overlay);const input=overlay.querySelector("#ms-referral-popup-input");const error=overlay.querySelector("#ms-referral-popup-error");const btnContinue=overlay.querySelector("#ms-referral-popup-continue");const btnSkip=overlay.querySelector("#ms-referral-popup-skip");const btnCancel=overlay.querySelector("#ms-referral-popup-cancel");input.value=initialCode;if(!autoLocked){input.focus()}
477input.addEventListener("input",()=>{if(autoLocked)return;input.value=sanitizeRef(input.value);error.textContent=""});function close(result){document.removeEventListener("keydown",onKeyDown);overlay.remove();resolve(result)} 478function onKeyDown(e){if(e.key==="Escape")close(null);} 479document.addEventListener("keydown",onKeyDown);overlay.addEventListener("click",(e)=>{if(e.target===overlay)close(null);});btnCancel.addEventListener("click",()=>close(null));if(btnSkip){btnSkip.addEventListener("click",()=>close(""))} 480btnContinue.addEventListener("click",()=>{const code=sanitizeRef(input.value);if(code&&!/^[A-Z0-9]{10}$/.test(code)){error.textContent="Creator code must be 10 letters/numbers.";return} 481close(code)})})} 482function savePendingSocialSignup(data){try{sessionStorage.setItem("ms_pending_social_signup",JSON.stringify(data||{}))}catch(_){}} 483function readPendingSocialSignup(){try{return JSON.parse(sessionStorage.getItem("ms_pending_social_signup")||"null")}catch(_){return null}} 484function clearPendingSocialSignup(){try{sessionStorage.removeItem("ms_pending_social_signup")}catch(_){}} 485setBootVisibility(!1);(async function main(){try{await ensureFirebaseLoadedWithRecovery();clearBootstrapRetryCount();cleanupBootstrapQueryParam();setBootVisibility(!0)}catch(e){const msg=cleanErrorMessage(e.message);const low=msg.toLowerCase();const isBootstrapFailure=low.includes("firebase not available")||low.includes("timeout loading")||low.includes("failed loading");if(isBootstrapFailure&&retryBootstrapReload(4,350))return;setBootVisibility(!0);showMsg("Failed to load scripts: "+msg,"err");return} 486const firebaseConfig={apiKey:"AIzaSyDX4poDTm4JGThAdahQZpQqloU-3VuudjM",authDomain:"mystash-ai-hq.firebaseapp.com",projectId:"mystash-ai-hq",storageBucket:"mystash-ai-hq.firebasestorage.app",messagingSenderId:"878663821352",appId:"1:878663821352:web:ca329fe14bf4a2d578ed1d",measurementId:"G-PDBG58WNRM",};if(!firebase.apps||firebase.apps.length===0)firebase.initializeApp(firebaseConfig);const auth=firebase.auth();const db=firebase.firestore();const ajaxUrl=new URL("/wp-admin/admin-ajax.php",location.origin).toString();async function postAjax(action,payloadObj){const body=new URLSearchParams({action,...payloadObj});const res=await fetch(ajaxUrl,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:body.toString(),credentials:"include",cache:"no-store",});const json=await res.json().catch(()=>null);if(!json||typeof json!=="object")throw new Error("bad-json");if(json.success)return json.data;const msg=(json.data&&json.data.message)?String(json.data.message):"Request failed";throw new Error(msg)} 487async function sendWelcomeEmail(user,name){if(!user)throw new Error("missing-user");const idToken=await user.getIdToken(!0);await postAjax("mystash_send_welcome_email",{idToken:idToken,name:String(name||"").trim(),})} 488auth.languageCode="en";try{await auth.setPersistence(firebase.auth.Auth.Persistence.LOCAL)}catch(_){} 489const btnCreate=el("ms-create-btn");const btnGoogle=el("ms-google");const btnApple=el("ms-apple");if(!btnCreate){showMsg("UI bindings missing. Your /sign-up HTML IDs don't match.","err");return} 490try{const rr=await auth.getRedirectResult();if(rr&&rr.user){const pending=readPendingSocialSignup()||{};const desiredName=String(el("ms-name")?.value||pending.desiredName||rr.user.displayName||"").trim();const rawRef=String(el("ms-creator-code")?.value||pending.rawRef||"");let usedRef=pending.usedRef||null;if(!usedRef){try{usedRef=await validateReferralIfAny(db,rawRef)}catch(_){usedRef=null}} 491await ensureUserDocSignup(db,rr.user,desiredName||null,usedRef);try{await sendWelcomeEmail(rr.user,desiredName||rr.user.displayName||"")}catch(_){} 492clearPendingSocialSignup();goAfterSignup(rr.user.email||"");return}}catch(e){clearPendingSocialSignup();showMsg(userFacingAuthError(e),"err")} 493function fallbackNameFromEmail(email){const local=String(email||"").split("@")[0].trim();if(!local)return"";return local.replace(/[._-]+/g," ").replace(/\s+/g," ").trim()} 494function appleNameFromCredential(cred){const profile=cred?.additionalUserInfo?.profile;if(!profile||typeof profile!=="object")return"";const first=profile?.name?.firstName||profile?.given_name||profile?.firstName||"";
494const last=profile?.name?.lastName||profile?.family_name||profile?.lastName||"";const joined=[first,last].filter(Boolean).join(" ").trim();if(joined)return joined;if(typeof profile?.name==="string"&&profile.name.trim()){return profile.name.trim()} 495return""} 496async function startOAuth(btn,providerFactory){if(!btn)return;clearMsg();setBtnLoading(btn,!0);await nextPaint();const desiredName=String(el("ms-name")?.value||"").trim();const creatorInput=el("ms-creator-code");const modalRef=await promptReferralCodeOptional(String(creatorInput?.value||""),!!creatorInput?.readOnly);if(modalRef===null){setBtnLoading(btn,!1);return} 497if(creatorInput){creatorInput.value=modalRef;creatorInput.dispatchEvent(new Event("input",{bubbles:!0}));creatorInput.dispatchEvent(new Event("change",{bubbles:!0}))} 498const rawRef=modalRef;let usedRef=null;try{usedRef=await validateReferralIfAny(db,rawRef)}catch(e){setBtnLoading(btn,!1);showMsg(cleanErrorMessage(e.message),"err");return} 499const provider=providerFactory();savePendingSocialSignup({desiredName:desiredName||"",rawRef:rawRef||"",usedRef:usedRef||null,providerId:String(provider?.providerId||"")});try{const cred=await withWatchdog(auth.signInWithPopup(provider));const user=cred?.user;if(!user)throw new Error("Could not complete sign up.");const providerId=String(provider?.providerId||"").toLowerCase();const providerName=providerId==="apple.com"?appleNameFromCredential(cred):(user.displayName||"");const nameFinal=providerName||desiredName||user.displayName||fallbackNameFromEmail(user.email);if(!user.displayName&&nameFinal){try{await user.updateProfile({displayName:nameFinal})}catch(_){}} 500await ensureUserDocSignup(db,user,nameFinal||null,usedRef);try{await sendWelcomeEmail(user,nameFinal)}catch(_){} 501clearPendingSocialSignup();setBtnLoading(btn,!1);goAfterSignup(user.email||"");return}catch(e){const code=String(e&&e.code?e.code:"");if(code==="auth/popup-closed-by-user"){clearPendingSocialSignup();setBtnLoading(btn,!1);showMsg("Sign-up canceled.","err");return} 502try{await auth.signInWithRedirect(provider);return}catch(e2){clearPendingSocialSignup();setBtnLoading(btn,!1);showMsg(userFacingAuthError(e2),"err");return}}} 503if(btnGoogle){btnGoogle.addEventListener("click",()=>startOAuth(btnGoogle,()=>{const p=new firebase.auth.GoogleAuthProvider();p.setCustomParameters({prompt:"select_account"});return p}))} 504if(btnApple){btnApple.addEventListener("click",()=>startOAuth(btnApple,()=>{const p=new firebase.auth.OAuthProvider("apple.com");p.addScope("email");p.addScope("name");return p}))} 505btnCreate.addEventListener("click",async()=>{clearMsg();const name=String(el("ms-name")?.value||"").trim();const refRaw=String(el("ms-creator-code")?.value||"");const email=String(el("ms-email")?.value||"").trim();const pass=String(el("ms-pass")?.value||"");if(!name)return showMsg("Please enter your name.","err");if(!email||!pass)return showMsg("Please enter email and password.","err");if(pass.length<8)return showMsg("Password must be at least 8 characters.","err");const ref=sanitizeRef(refRaw);if(ref&&!/^[A-Z0-9]{10}$/.test(ref)){return showMsg("Creator code must be 10 letters/numbers.","err")} 506setBtnLoading(btnCreate,!0);await nextPaint();let createdUser=null;let userDocSaved=!1;try{const methods=await auth.fetchSignInMethodsForEmail(email);if(methods&&methods.length){showMsg("This email is already registered. Please sign in.","err");return} 507let usedReferralCode=null;if(ref){const rSnap=await db.collection("referralCodes").doc(ref).get();if(!rSnap.exists){showMsg("That creator code doesn't exist.","err");return} 508usedReferralCode=ref} 509const cred=await auth.createUserWithEmailAndPassword(email,pass);const user=cred?.user;if(!user)throw new Error("Could not create account.");createdUser=user;try{await user.updateProfile({displayName:name})}catch(_){} 510const now=new Date();await db.collection("users").doc(user.uid).set({uid:user.uid,email:String(email).toLowerCase(),name,language:"en",currency:"USD",trialUsed:!1,subscriptionStatus:"free",subscriptionType:"free",subscriptionTier:"free",subscriptionRenews:"free",accessStatus:"pending_activation",activationStartedAt:now,activationCompletedAt:null,trialStartedAt:null,trialEndsAt:null,lifecycleEmails:{activation24QueuedAt:null,activation24SentAt:null,activation72QueuedAt:null,activation72SentAt:null},usedReferralCode,createdAt:now,updatedAt:now,},{merge:!0});userDocSaved=!0;try{await user.sendEmailVerification({url:authActionUrl,handleCodeInApp:!1,})}catch(_){} 511goAfterSignup(email);return}catch(e){if(createdUser&&!userDocSaved){try{await createdUser.delete()}catch(_){} 512try{await auth.signOut()}catch(_){}}
513showMsg(userFacingAuthError(e),"err")}finally{setBtnLoading(btnCreate,!1)}})})()})()</script>
513<script>(function(){if(window.__MS_SIGNIN_SNIPPET__)return;window.__MS_SIGNIN_SNIPPET__=!0;const root=document.getElementById("ms-signin");if(!root)return;const el=(id)=>document.getElementById(id);const showMsg=(text,kind)=>{const m=el("ms-msg");if(!m)return;m.className="msg show"+(kind?" "+kind:"");m.textContent=text||""};const clearMsg=()=>{const m=el("ms-msg");if(!m)return;m.className="msg";m.textContent=""};const nextPaint=()=>new Promise((r)=>requestAnimationFrame(()=>requestAnimationFrame(r)));const pageParams=new URLSearchParams(window.location.search);const BOOT_RETRY_KEY="ms_signin_boot_retry";const BOOT_QUERY_KEY="msfb";function getBootstrapRetryCount(){return Number(sessionStorage.getItem(BOOT_RETRY_KEY)||"0")} 514function clearBootstrapRetryCount(){sessionStorage.removeItem(BOOT_RETRY_KEY)} 515function retryBootstrapReload(maxRetries=4,delayMs=350){if(!shouldUseHardReloadRecovery())return!1;const count=getBootstrapRetryCount();if(count>=maxRetries)return!1;sessionStorage.setItem(BOOT_RETRY_KEY,String(count+1));const url=new URL(window.location.href);url.searchParams.set(BOOT_QUERY_KEY,String(Date.now()));setTimeout(()=>{window.location.replace(url.toString())},delayMs);return!0} 516function isSafariBrowser(){const ua=navigator.userAgent||"";return/Safari/i.test(ua)&&!/Chrome|CriOS|Edg|OPR|Firefox|FxiOS|Android/i.test(ua)} 517const isAppFlow=String(pageParams.get("source")||"").toLowerCase()==="app";function isMobileBrowser(){const ua=navigator.userAgent||"";return/Android|iPhone|iPad|iPod|Mobile/i.test(ua)} 518function shouldUseHardReloadRecovery(){return isSafariBrowser()||isMobileBrowser()||isAppFlow} 519function setBootVisibility(isReady){if(!root)return;root.style.transition="opacity .18s ease";root.style.opacity=isReady?"1":"0";root.style.pointerEvents=isReady?"":"none"} 520function cleanupBootstrapQueryParam(){try{const url=new URL(window.location.href);if(!url.searchParams.has(BOOT_QUERY_KEY))return;url.searchParams.delete(BOOT_QUERY_KEY);window.history.replaceState({},document.title,url.toString())}catch(_){}} 521function sleep(ms){return new Promise((resolve)=>setTimeout(resolve,ms))} 522window.addEventListener("pageshow",function(event){if(!isSafariBrowser())return;if(!event.persisted)return;const count=getBootstrapRetryCount();if(count>=8)return;const url=new URL(window.location.href);url.searchParams.set(BOOT_QUERY_KEY,String(Date.now()));sessionStorage.setItem(BOOT_RETRY_KEY,String(count+1));window.location.replace(url.toString())});function cleanErrorMessage(raw){let s=String(raw||"Unknown error");s=s.replace(/^Firebase:\s*/i,"");s=s.replace(/\s*\((auth|functions)\/[^\)]+\)\s*\.?/gi,"");s=s.replace(/^(auth|functions)\/[a-z0-9-]+:\s*/i,"");s=s.replace(/\s{2,}/g," ").trim();return s} 523function userFacingAuthError(e){const code=String(e&&e.code?e.code:"");if(code==="auth/invalid-credential"||code==="auth/wrong-password"||code==="auth/user-not-found")return"Incorrect email or password.";if(code==="auth/too-many-requests")return"Too many attempts. Please wait and try again.";if(code==="auth/network-request-failed")return"Connection issue. Please check your internet and try again.";if(code==="auth/popup-blocked")return"Popup blocked. Please allow popups and try again.";if(code==="auth/popup-closed-by-user")return"Sign-in canceled.";if(code==="auth/account-exists-with-different-credential") 524return"This email is linked to a different sign-in method. Try another option.";const msg=cleanErrorMessage(e&&e.message?e.message:"");const details=cleanErrorMessage(e&&e.details?e.details:"");return(details?(msg?(msg+" â "+details):details):msg)||"Something went wrong. Please try again."} 525function setBtnLoading(btn,loading){if(!btn)return;if(loading){btn.classList.add("loading");btn.disabled=!0;return} 526btn.classList.remove("loading");btn.disabled=!1} 527const FIREBASE_VERSION="10.12.5";const LOCAL_BASE=`/wp-content/uploads/ms/firebase/${FIREBASE_VERSION}/`;const GSTATIC_BASE=`https://www.gstatic.com/firebasejs/${FIREBASE_VERSION}/`;const SDK_FILES=["firebase-app-compat.js","firebase-auth-compat.js","firebase-firestore-compat.js"];function buildScriptUrl(base,file){const sep=base.includes("?")?"&":"?";const boot=pageParams.get("msfb")||String(Date.now());return `${base}${file}${sep}v=${encodeURIComponent(FIREBASE_VERSION)}&boot=${encodeURIComponent(boot)}`} 528function sdkReadyFor(file){if(file==="firebase-app-compat.js"){return!!(window.firebase&&firebase.initializeApp)} 529if(file==="firebase-auth-compat.js"){return!!(window.firebase&&firebase.auth)} 530if(file==="firebase-firestore-compat.js"){return!!(window.firebase&&firebase.firestore)} 531return!1} 532function waitForReady(check,timeoutMs=15000,stepMs=50){return new Promise((resolve,reject)=>{const start=Date.now();(function tick(){if(check())return resolve();if(Date.now()-start>=timeoutMs){return reject(new Error("Firebase not available."))} 533setTimeout(tick,stepMs)})()})} 534function loadScriptOnce(url,readyCheck,timeoutMs=15000){return new Promise((resolve,reject)=>{if(readyCheck()){resolve();return} 535let script=Array.from(document.scripts||[]).find((s)=>{try{const existing=new URL(s.src,window.location.origin);const incoming=new URL(url,window.location.origin);return existing.origin===incoming.origin&&existing.pathname===incoming.pathname}catch(_){return s.src===url}});const finalize=()=>
535{waitForReady(readyCheck,timeoutMs).then(resolve).catch(()=>reject(new Error(`Timeout loading: ${url}`)))};if(script){finalize();return} 536script=document.createElement("script");script.src=url;script.async=!1;script.defer=!1;script.setAttribute("data-cfasync","false");script.addEventListener("load",finalize,{once:!0});script.addEventListener("error",()=>reject(new Error(`Failed loading: ${url}`)),{once:!0});document.head.appendChild(script)})} 537async function loadWithFallback(file){const readyCheck=()=>sdkReadyFor(file);if(isSafariBrowser()){await loadScriptOnce(buildScriptUrl(GSTATIC_BASE,file),readyCheck);return} 538try{await loadScriptOnce(buildScriptUrl(LOCAL_BASE,file),readyCheck)}catch(_){await loadScriptOnce(buildScriptUrl(GSTATIC_BASE,file),readyCheck)}} 539async function ensureFirebaseLoaded(){if(window.firebase&&firebase.initializeApp&&firebase.auth&&firebase.firestore){return} 540if(window.__MS_FIREBASE_READY__&&typeof window.__MS_FIREBASE_READY__.then==="function"){return window.__MS_FIREBASE_READY__} 541window.__MS_FIREBASE_READY__=(async()=>{for(const f of SDK_FILES){await loadWithFallback(f)} 542if(!window.firebase||!firebase.initializeApp||!firebase.auth||!firebase.firestore){throw new Error("Firebase not available.")}})();try{await window.__MS_FIREBASE_READY__}catch(e){window.__MS_FIREBASE_READY__=null;throw e}} 543function removeFirebaseBootScripts(){const targets=["firebase-app-compat.js","firebase-auth-compat.js","firebase-firestore-compat.js"];Array.from(document.scripts||[]).forEach((s)=>{const src=String(s.src||"");const isFirebaseSdk=targets.some((name)=>src.includes(name))&&(src.includes(`/wp-content/uploads/ms/firebase/${FIREBASE_VERSION}/`)||src.includes(`https://www.gstatic.com/firebasejs/${FIREBASE_VERSION}/`));if(isFirebaseSdk){try{s.remove()}catch(_){}}})} 544async function ensureFirebaseLoadedWithRecovery(){const inPlaceAttempts=shouldUseHardReloadRecovery()?1:3;let lastError=null;for(let i=0;i<inPlaceAttempts;i++){try{await ensureFirebaseLoaded();return}catch(e){lastError=e;window.__MS_FIREBASE_READY__=null;removeFirebaseBootScripts();if(i<inPlaceAttempts-1){await sleep(250*(i+1))}}} 545throw lastError||new Error("Firebase not available.")} 546function getNextPath(){const p=new URLSearchParams(window.location.search);const rawNext=String(p.get("next")||"").trim();const defaultNext="/account/?activation=required";if(!rawNext)return defaultNext;try{const url=new URL(rawNext,window.location.origin);if(url.origin!==window.location.origin){return defaultNext} 547return url.pathname+url.search+url.hash}catch(_){if(rawNext.startsWith("/")&&!rawNext.startsWith("//")){return rawNext} 548return defaultNext}} 549async function ensureUserDocDefaults(db,user){if(!user||!user.uid)return;const ref=db.collection("users").doc(user.uid);const snap=await ref.get();if(!snap.exists){await ref.set({uid:user.uid,email:String(user.email||"").toLowerCase(),name:user.displayName||null,language:"en",currency:"USD",createdAt:firebase.firestore.FieldValue.serverTimestamp(),},{merge:!0});return} 550const data=snap.data()||{};const patch={};if(!data.language)patch.language="en";if(!data.currency)patch.currency="USD";if(!data.email&&user.email)patch.email=String(user.email).toLowerCase();if(!data.name&&user.displayName)patch.name=user.displayName;if(Object.keys(patch).length){patch.updatedAt=firebase.firestore.FieldValue.serverTimestamp();await ref.set(patch,{merge:!0})}} 551async function withWatchdog(promise,ms=25000){let done=!1;const timer=setTimeout(()=>{if(!done)showMsg("Sign-in timed out. Please try again.","err");},ms);try{const r=await promise;done=!0;clearTimeout(timer);return r}catch(e){done=!0;clearTimeout(timer);throw e}} 552setBootVisibility(!1);(async function main(){try{await ensureFirebaseLoadedWithRecovery();clearBootstrapRetryCount();cleanupBootstrapQueryParam();setBootVisibility(!0)}catch(e){const msg=cleanErrorMessage(e.message);const low=msg.toLowerCase();const isBootstrapFailure=low.includes("firebase not available")||low.includes("timeout loading")||low.includes("failed loading");if(isBootstrapFailure&&retryBootstrapReload(4,350))return;setBootVisibility(!0);showMsg("Failed to load scripts: "+msg,"err");return} 553const firebaseConfig={apiKey:"AIzaSyDX4poDTm4JGThAdahQZpQqloU-3VuudjM",authDomain:"mystash-ai-hq.firebaseapp.com",projectId:"mystash-ai-hq",storageBucket:"mystash-ai-hq.firebasestorage.app",messagingSenderId:"878663821352",appId:"1:878663821352:web:ca329fe14bf4a2d578ed1d",measurementId:"G-PDBG58WNRM",};if(!firebase.apps||firebase.apps.length===0)firebase.initializeApp(firebaseConfig);const auth=firebase.auth();const db=firebase.firestore();let emailPasswordSigninInProgress=!1;async function finishSignedInUser(user){if(!user)return;try{await ensureUserDocDefaults(db,user)}catch(_){} 554window.location.replace(getNextPath())} 555function hasPasswordProvider(user){return!!(user&&Array.isArray(user.providerData)&&user.providerData.some((p)=>p&&p.providerId==="password"))} 556auth.languageCode="en";try{await auth.setPersistence(firebase.auth.Auth.Persistence.LOCAL)}catch(_){} 557try{await auth.getRedirectResult()}catch(_){} 558auth.onAuthStateChanged(async(user)=>{if(!user)return;if(emailPasswordSigninInProgress)return;await finishSignedInUser(user)});const btnGoogle=el("ms-google");const btnApple=el("ms-apple");const btnSignin=el("ms-signin-btn");const btnForgot=el("ms-forgot");if(!btnGoogle||!btnApple||!btnSignin){showMsg("UI bindings missing. Your /sign-in HTML IDs don't match.","err");return} 559if(btnForgot){btnForgot.addEventListener("click",async()=>{clearMsg();const emailEl=el("ms-email");const email=String(emailEl?.value||"").trim();if(!email){showMsg("Enter your email above to reset your password.","err");try{emailEl&&emailEl.focus()}catch(_){} 560return} 561const oldText=btnForgot.textContent||"Forgot password?";btnForgot.disabled=!0;btnForgot.textContent="Sendingâ¦";const actionCodeSettings={url:"https://mystashhq.com/auth/",handleCodeInApp:!1,};let timedOut=!1;const t=setTimeout(()=>{timedOut=!0;showMsg("Still working⦠If nothing happens, try again.","err")},12000);try{await auth.sendPasswordResetEmail(email,actionCodeSettings);showMsg("If an account exists for this email, we sent a password reset link. Check your inbox (and spam).","ok")}catch(e){const code=String(e&&e.code?e.code:"");
561if(code==="auth/invalid-email"){showMsg("That email address looks invalid. Please check it and try again.","err")}else if(code==="auth/too-many-requests"){showMsg("Too many requests. Please wait a bit and try again.","err")}else if(code==="auth/network-request-failed"){showMsg("Connection issue. Please check your internet and try again.","err")}else if(code==="auth/user-not-found"){showMsg("If an account exists for this email, we sent a password reset link. Check your inbox (and spam).","ok")}else{showMsg("We couldn't send the reset email right now. Please try again.","err")} 562try{console.error("[MyStash Sign-in] sendPasswordResetEmail",e)}catch(_){}}finally{clearTimeout(t);btnForgot.disabled=!1;btnForgot.textContent=oldText;if(timedOut){}}})} 563async function startOAuth(btn,providerFactory){clearMsg();setBtnLoading(btn,!0);await nextPaint();const provider=providerFactory();try{await withWatchdog(auth.signInWithPopup(provider));setBtnLoading(btn,!1);return}catch(e){const code=String(e&&e.code?e.code:"");if(code==="auth/popup-closed-by-user"){setBtnLoading(btn,!1);showMsg("Sign-in canceled.","err");return} 564try{await auth.signInWithRedirect(provider);return}catch(e2){setBtnLoading(btn,!1);showMsg(userFacingAuthError(e2),"err")}}} 565btnGoogle.addEventListener("click",()=>startOAuth(btnGoogle,()=>{const p=new firebase.auth.GoogleAuthProvider();p.setCustomParameters({prompt:"select_account"});return p}));btnApple.addEventListener("click",()=>startOAuth(btnApple,()=>{const p=new firebase.auth.OAuthProvider("apple.com");p.addScope("email");p.addScope("name");return p}));btnSignin.addEventListener("click",async()=>{clearMsg();const email=String(el("ms-email")?.value||"").trim();const pass=String(el("ms-pass")?.value||"");if(!email||!pass){return showMsg("Please enter email and password.","err")} 566emailPasswordSigninInProgress=!0;setBtnLoading(btnSignin,!0);await nextPaint();try{const cred=await auth.signInWithEmailAndPassword(email,pass);const user=cred?.user;if(!user){throw new Error("Could not sign in.")} 567try{await user.reload()}catch(_){} 568const freshUser=auth.currentUser||user;if(hasPasswordProvider(freshUser)&&!freshUser.emailVerified){try{await auth.signOut()}catch(_){} 569showMsg("Your email has not been verified yet. Please check your inbox and verify your email before signing in.","err");return} 570await finishSignedInUser(freshUser)}catch(e){showMsg(userFacingAuthError(e),"err")}finally{emailPasswordSigninInProgress=!1;setBtnLoading(btnSignin,!1)}})})()})()</script>
570<script>(function () { 571 if (window.MS_ACCOUNT_BOOT) return; 572 window.MS_ACCOUNT_BOOT = true; 573 574 const domReady = () => 575 new Promise((resolve) => { 576 if ( 577 document.readyState === "complete" || 578 document.readyState === "interactive" 579 ) 580 resolve(); 581 else document.addEventListener("DOMContentLoaded", resolve, { once: true }); 582 }); 583 584 const el = (id) => document.getElementById(id); 585 586 const showMsg = (id, text, kind) => { 587 const m = el(id); 588 if (!m) return; 589 m.className = "ms-msg show" + (kind ? " " + kind : ""); 590 m.textContent = text || ""; 591 }; 592 593 const clearMsg = (id) => { 594 const m = el(id); 595 if (!m) return; 596 m.className = "ms-msg"; 597 m.textContent = ""; 598 }; 599 600 const nextPaint = () => 601 new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(r))); 602 603 function cleanErrorMessage(raw) { 604 const DEBUG = new URLSearchParams(location.search).get("debug") === "1"; 605 let s = String(raw || "Unknown error"); 606 s = s.replace(/^Firebase:\s*/i, ""); 607 s = s.replace(/\s*\((auth|functions)\/[^\)]+\)\s*$/i, ""); 608 s = s.replace(/^(auth|functions)\/[a-z0-9-]+:\s*/i, ""); 609 s = s.replace(/\s+/g, " ").trim(); 610 611 if (!DEBUG && s.toUpperCase() === "INTERNAL") { 612 s = "Temporary server error. Please try again."; 613 } 614 615 return s.trim(); 616 } 617 618 function extractErr(e) { 619 const DEBUG = new URLSearchParams(location.search).get("debug") === "1"; 620 const msg = cleanErrorMessage(e && e.message ? e.message : ""); 621 const details = e && e.details ? cleanErrorMessage(e.details) : ""; 622 const code = e && e.code ? String(e.code) : ""; 623 const finalMsg = details && details !== msg ? details : msg || "Something went wrong."; 624 625 if (DEBUG && code) return `${finalMsg} (${code})`; 626 return finalMsg; 627 } 628 629 function setBtnLoading(btn, loading) { 630 if (!btn) return; 631 if (loading) { 632 btn.dataset.prevDisabled = btn.disabled ? "1" : "0"; 633 btn.classList.add("loading"); 634 btn.disabled = true; 635 btn.setAttribute("aria-busy", "true"); 636 return; 637 } 638 btn.classList.remove("loading"); 639 btn.setAttribute("aria-busy", "false"); 640 const prevDisabled = btn.dataset.prevDisabled === "1"; 641 const lockedDisabled = 642 btn.classList.contains("disabled-portal") || 643 btn.dataset.lockedDisabled === "1"; 644 btn.disabled = lockedDisabled ? true : prevDisabled; 645 delete btn.dataset.prevDisabled; 646 } 647 648 // ------------------------- 649 // Firebase compat loader 650 // ------------------------- 651 const FIREBASE_VERSION = "10.12.5"; 652 const LOCAL_BASE = `/wp-content/uploads/ms/firebase/${FIREBASE_VERSION}/`; 653 const GSTATIC_BASE = `https://www.gstatic.com/firebasejs/${FIREBASE_VERSION}/`; 654 const SDK_FILES = [ 655 "firebase-app-compat.js", 656 "firebase-auth-compat.js", 657 "firebase-functions-compat.js", 658 "firebase-firestore-compat.js", 659 ]; 660 661 function loadScriptOnce(url, timeoutMs = 15000) { 662 return new Promise((resolve, reject) => { 663 const existing = Array.from(document.scripts || []).find( 664 (s) => s.src === url 665 ); 666 if (existing) return resolve({ url, reused: true }); 667 668 const s = document.createElement("script"); 669 s.src = url; 670 s.async = false; 671 s.defer = false; 672 s.setAttribute("data-cfasync", "false"); 673 674 const t = setTimeout(() => { 675 s.onerror = null; 676 s.onload = null; 677 reject(new Error(`Timeout loading: ${url}`)); 678 }, timeoutMs); 679 680 s.onload = () => { 681 clearTimeout(t); 682 resolve({ url, reused: false }); 683 }; 684 s.onerror = () => { 685 clearTimeout(t); 686 reject(new Error(`Failed loading: ${url}`)); 687 }; 688 689 document.head.appendChild(s); 690 }); 691 } 692 693 async function loadWithFallback(file) { 694 const localUrl = LOCAL_BASE + file; 695 const gstaticUrl = GSTATIC_BASE + file; 696 try { 697 return await loadScriptOnce(localUrl); 698 } catch (e1) { 699 try { 700 return await loadScriptOnce(gstaticUrl); 701 } catch (e2) { 702 const err = new Error( 703 `Could not load ${file}.\nLocal: ${localUrl}\nGstatic: ${gstaticUrl}\n` + 704 `LocalErr: ${e1.message}\nGstaticErr: ${e2.message}` 705 ); 706 err._local = e1; 707 err._gstatic = e2; 708 throw err; 709 } 710 } 711 } 712 713 async function ensureFirebaseCompatLoaded() { 714 if ( 715 window.firebase && 716 window.firebase.initializeApp && 717 window.firebase.auth && 718 window.firebase.firestore 719 ) { 720 return { already: true }; 721 } 722 for (const f of SDK_FILES) await loadWithFallback(f); 723 if (!window.firebase || !window.firebase.initializeApp) 724 throw new Error("Firebase global not available."); 725 if ( 726 !window.firebase.auth || 727 !window.firebase.firestore || 728 !window.firebase.functions 729 ) { 730 throw new Error("Firebase modules missing (auth/firestore/functions)."); 731 } 732 return { already: false }; 733 } 734 735 // ------------------------- 736 // MAIN 737 // ------------------------- 738 (async function main() { 739 await domReady(); 740 await nextPaint(); 741 const DEBUG = new URLSearchParams(location.search).get("debug") === "1"; 742 743 // Canonical /account/ 744 function computeCanonicalUrl() { 745 const u = new URL(window.location.href); 746 if (u.protocol !== "https:") u.protocol = "https:"; 747 if (u.pathname === "/account") u.pathname = "/account/"; 748 if (u.pathname === "/account/index.php") u.pathname = "/account/"; 749 return u; 750 } 751 752 function ensureCanonicalNow() { 753 const target = computeCanonicalUrl().toString(); 754 if (target !== window.location.href) { 755 window.location.replace(target); 756 return true; 757 } 758 return false;
759 } 760 761 if (ensureCanonicalNow()) return; 762 763 // UI 764 const pill = el("ms-pill"); 765 const subtitle = el("ms-subtitle"); 766 const guestCard = el("ms-guest-card"); 767 const accountCard = el("ms-account-card"); 768 const goSignin = el("ms-go-signin"); 769 770 const btnSignout = el("ms-signout"); 771 const btnRefresh = el("ms-refresh"); 772 const btnPortal = el("ms-portal"); 773 const btnUnlock = el("ms-unlock"); 774 const btnCheckout = el("ms-checkout"); 775 776 const invoicesNote = el("ms-invoices-note"); 777 778 const plansMainWrap = el("ms-plans-main"); 779 const promosSectionWrap = el("ms-promos-wrap"); 780 const promosWrap = el("ms-plans-promos"); 781 const promosTitle = el("ms-promos-title"); 782 const specialWrap = el("ms-plans-special"); 783 784 const tabMonthly = el("ms-tab-monthly"); 785 const tabAnnual = el("ms-tab-annual"); 786 787 const slotsTextEl = el("ms-slots-text"); 788 const slotsNextEl = el("ms-slots-next"); 789 const slotsPriceEl = el("ms-slots-price"); 790 const slotsMsgEl = el("ms-slots-msg"); 791 const btnSlotsBuy = el("ms-slots-buy"); 792 const btnSlotsManage = el("ms-slots-manage"); 793 794 // Modal 795 const addonsModal = el("ms-addons-modal"); 796 const btnAddonsClose = el("ms-addons-close"); 797 const pickerWrap = el("ms-addon-picker"); 798 const propsListEl = el("ms-props-list"); 799 const btnPickerBack = el("ms-picker-back"); 800 const btnPickerConfirm = el("ms-picker-confirm"); 801 const addonsListEl = el("ms-addons-list"); 802 803 const addonsTitleEl = el("ms-addons-title"); 804 const addonsNoteEl = el("ms-addons-note"); 805 806 const pickerHead = el("ms-picker-head"); 807 const pickerEyebrow = el("ms-picker-eyebrow"); 808 const pickerTitle = el("ms-picker-title"); 809 const pickerSub = el("ms-picker-sub"); 810 811 // Load Firebase 812 try { 813 if (pill) { 814 pill.className = "ms-pill"; 815 pill.textContent = "Loadingâ¦"; 816 } 817 await ensureFirebaseCompatLoaded(); 818 } catch (e) { 819 console.error("[ms-account] Firebase SDK load error:", e); 820 if (pill) { 821 pill.className = "ms-pill warn"; 822 pill.textContent = "Error"; 823 } 824 if (guestCard) guestCard.style.display = ""; 825 showMsg( 826 "ms-guest-msg", 827 "Could not load sign-in scripts.\n\n" + cleanErrorMessage(e.message), 828 "err" 829 ); 830 return; 831 } 832 833 // Firebase init 834 const firebaseConfig = { 835 apiKey: "AIzaSyDX4poDTm4JGThAdahQZpQqloU-3VuudjM", 836 authDomain: "mystash-ai-hq.firebaseapp.com", 837 projectId: "mystash-ai-hq", 838 storageBucket: "mystash-ai-hq.firebasestorage.app", 839 messagingSenderId: "878663821352", 840 appId: "1:878663821352:web:ca329fe14bf4a2d578ed1d", 841 measurementId: "G-PDBG58WNRM", 842 }; 843 844 if (!firebase.apps || firebase.apps.length === 0) 845 firebase.initializeApp(firebaseConfig); 846 847 const auth = firebase.auth(); 848 const db = firebase.firestore(); 849 850 auth.languageCode = "en"; 851 852 try { 853 await auth.setPersistence(firebase.auth.Auth.Persistence.LOCAL); 854 } catch (e1) { 855 try { 856 await auth.setPersistence(firebase.auth.Auth.Persistence.SESSION); 857 } catch (_) {} 858 } 859 860 const functions = firebase.app().functions("us-central1"); 861 862 const fnCreateCheckoutSession = functions.httpsCallable("createCheckoutSession"); 863 const fnFinalizeCheckoutSession = functions.httpsCallable("finalizeCheckoutSession"); 864 const fnSyncStripe = functions.httpsCallable("syncStripe"); 865 const fnCreateBillingPortalSession = functions.httpsCallable("createBillingPortalSession"); 866 const fnGetLifetimeConfig = functions.httpsCallable("getLifetimeConfig"); 867 const fnRedeemSpecialAccessCode = functions.httpsCallable("redeemSpecialAccessCode"); 868 const fnStartInfluencerPurchase = functions.httpsCallable("startInfluencerPurchase"); 869 const fnStartOwnerPurchase = functions.httpsCallable("startOwnerPurchase"); 870 871 const fnGetSlotsSummary = functions.httpsCallable("getSlotsSummary"); 872 const fnReconcileAddonsAndProperties = functions.httpsCallable("reconcileAddonsAndProperties"); 873 const fnRefreshAddonsMirror = functions.httpsCallable("refreshAddonsMirror"); 874 const fnPreviewAddonProration = functions.httpsCallable("previewAddonProration"); 875 const fnScheduleAddonCancelForProperty = functions.httpsCallable("scheduleAddonCancelForProperty"); 876 const fnSchedulePlanReductionWeb = functions.httpsCallable("schedulePlanReductionWeb"); 877 const fnClearPendingPlanReductionWeb = functions.httpsCallable("clearPendingPlanReductionWeb"); 878 879 const params = new URLSearchParams(window.location.search); 880 const accountRoot = el("ms-account"); 881 const trialGate = el("ms-trial-gate"); 882 883 function injectAccountActivationStyles() { 884 if (document.getElementById("ms-account-activation-style")) return; 885 886 const style = document.createElement("style"); 887 style.id = "ms-account-activation-style"; 888 style.textContent = ` 889 #ms-account.ms-account-preparing #ms-account-card { 890 display: none !important; 891 } 892 893 #ms-account .ms-trial { 894 display: none !important; 895 } 896 897 #ms-account.ms-pending-activation .ms-block-top { 898 padding: 14px 18px !important; 899 } 900 901 #ms-account.ms-pending-activation .ms-kv { 902 display: grid !important; 903 grid-template-columns: minmax(280px, 1fr) minmax(220px, 260px) !important; 904 gap: 16px !important; 905 align-items: center !important; 906 } 907 908 #ms-account.ms-pending-activation .ms-panel-user { 909 min-height: 58px !important; 910 display: flex !important; 911 align-items: center !important; 912 justify-self: start !important; 913 width: 100% !important; 914 max-width: 420px !important; 915 padding: 14px 16px !important; 916 } 917 918 #ms-account.ms-pending-activation .ms-panel-status { 919 display: none !important; 920 } 921 922 #ms-account.ms-pending-activation .ms-panel-user .ms-small { 923 display: none !important; 924 } 925 926 #ms-account.ms-pending-activation .ms-actions { 927 display: flex !important; 928 justify-content: flex-end !important; 929 align-items: center !important; 930 justify-self: end !important; 931 width: 100% !important; 932 max-width: 260px !important; 933 } 934 935 #ms-account.ms-pending-activation #ms-refresh, 936 #ms-account.ms-pending-activation #ms-portal { 937 display: none !important; 938 } 939 940 #ms-account.ms-pending-activation #ms-signout { 941 width: 100% !important; 942 max-width: 220px !important; 943 margin-left: auto !important; 944 background: linear-gradient(180deg, #d92d20, #b42318) !important; 945 color: #fff !important; 946 border: 0 !important; 947 box-shadow: 0 14px 30px rgba(180, 35, 24, 0.16) !important; 948 } 949 950 @media (max-width: 860px) { 951 #ms-account.ms-pending-activation .ms-kv { 952 grid-template-columns: 1fr !important; 953 gap: 12px !important; 954 } 955 956 #ms-account.ms-pending-activation .ms-panel-user { 957 max-width: 100% !important; 958 } 959 960 #ms-account.ms-pending-activation .ms-actions { 961 max-width: 100% !important; 962 justify-content: stretch !important; 963 } 964 965 #ms-account.ms-pending-activation #ms-signout { 966 max-width: 100% !important; 967 width: 100% !important; 968 margin-left: 0 !important; 969 } 970 } 971 `; 972 973 document.head.appendChild(style); 974 } 975 976 function setAccountPreparing(isPreparing) { 977 if (!accountRoot) return; 978 accountRoot.classList.toggle("ms-account-preparing", !!isPreparing); 979 } 980 981 function revealAccountAfterAccessLoaded() {
982 setAccountPreparing(false); 983 if (auth.currentUser && accountCard) { 984 accountCard.style.display = ""; 985 } 986 } 987 988 injectAccountActivationStyles(); 989 setAccountPreparing(true); 990 991 function forceRevealPendingActivationUI(reason) { 992 if (!auth.currentUser) return; 993 994 try { 995 const safeData = getSafeAccountData(lastUserData || {}); 996 safeData.subscriptionStatus = safeData.subscriptionStatus || "free"; 997 safeData.subscriptionType = safeData.subscriptionType || "free"; 998 safeData.subscriptionTier = safeData.subscriptionTier || "free"; 999 safeData.accessStatus = safeData.accessStatus || "pending_activation"; 1000 1001 paintAccountFromUserData(safeData, { refreshBilling: false }); 1002 } catch (_) { 1003 try { 1004 renderAllPlans(); 1005 } catch (_) {} 1006 1007 try { 1008 applyAccountActivationMode(getSafeAccountData(lastUserData || {})); 1009 } catch (_) {} 1010 } 1011 1012 try { 1013 revealAccountAfterAccessLoaded(); 1014 } catch (_) { 1015 setAccountPreparing(false); 1016 if (accountCard) accountCard.style.display = ""; 1017 } 1018 1019 showMsg( 1020 "ms-checkout-msg", 1021 "Weâre still checking access in the background. You can choose a plan now.", 1022 "" 1023 ); 1024 } 1025 1026 setTimeout(() => { 1027 if (!accountRoot) return; 1028 if (!accountRoot.classList.contains("ms-account-preparing")) return; 1029 forceRevealPendingActivationUI("preparing-timeout"); 1030 }, 7000); 1031 1032 // ------------------------- 1033 // Auto-refresh after external Stripe invoice 1034 // ------------------------- 1035 let msAutoRefreshTimer = null; 1036 let msAutoRefreshUntil = 0; 1037 let msAutoRefreshInFlight = false; 1038 1039 function stopAutoRefreshAccess() { 1040 if (msAutoRefreshTimer) { 1041 try { 1042 clearInterval(msAutoRefreshTimer); 1043 } catch (_) {} 1044 } 1045 msAutoRefreshTimer = null; 1046 msAutoRefreshUntil = 0; 1047 msAutoRefreshInFlight = false; 1048 } 1049 1050 function startAutoRefreshAccess({ everyMs = 30000, maxMinutes = 8 } = {}) { 1051 stopAutoRefreshAccess(); 1052 msAutoRefreshUntil = Date.now() + maxMinutes * 60 * 1000; 1053 1054 msAutoRefreshTimer = setInterval(async () => { 1055 if (Date.now() > msAutoRefreshUntil) { 1056 stopAutoRefreshAccess(); 1057 return; 1058 } 1059 if (msAutoRefreshInFlight) return; 1060 if (!auth.currentUser) return; 1061 1062 msAutoRefreshInFlight = true; 1063 try { 1064 await refreshAccess(); 1065 try { 1066 await refreshSlotsUI(); 1067 } catch (_) {} 1068 } catch (_) { 1069 // ignore 1070 } finally { 1071 msAutoRefreshInFlight = false; 1072 } 1073 }, everyMs); 1074 } 1075 1076 // ------------------------- 1077 // Money helpers 1078 // ------------------------- 1079 const PLAN_PROPERTY_LIMITS = { 1080 solo_monthly: 1, 1081 solo_annual: 1, 1082 home_monthly: 2, 1083 home_annual: 2, 1084 estate_monthly: 5, 1085 estate_annual: 5, 1086 lifetime_promo1: 1, 1087 lifetime_promo2: 1, 1088 }; 1089 1090 function getPlanPropertyLimit(planKey) { 1091 return PLAN_PROPERTY_LIMITS[String(planKey || "").toLowerCase()] ?? null; 1092 } 1093 1094 function getPlanDisplayName(planKey) { 1095 const allPlans = [
1096 ...PLANS_MONTHLY, 1097 ...PLANS_ANNUAL, 1098 ...Object.values(PROMO_CARDS), 1099 ...(specialUnlocked?.card ? [specialUnlocked.card] : []), 1100 ]; 1101 1102 const found = allPlans.find((p) => p.key === planKey); 1103 return found?.title || planKey; 1104 } 1105 1106 function getActivePropertiesForGuard() { 1107 return (propsLive || []).filter((p) => { 1108 return ( 1109 p && p.active !== false && p.disabled !== true && p.archived !== true 1110 ); 1111 }); 1112 } 1113 1114 function getPlanReductionGuard(planKey) { 1115 const allowed = getPlanPropertyLimit(planKey); 1116 if (!Number.isFinite(allowed)) return null; 1117 1118 const activeProps = getActivePropertiesForGuard(); 1119 if (activeProps.length <= allowed) return null; 1120 1121 return { 1122 planKey, 1123 allowed, 1124 activeProps, 1125 needToRemove: activeProps.length - allowed, 1126 }; 1127 } 1128 1129 function toNumberMaybe(v) { 1130 if (v === null || v === undefined) return null; 1131 if (typeof v === "number") return Number.isFinite(v) ? v : null; 1132 const s = String(v).trim(); 1133 if (!s) return null; 1134 const cleaned = s.replace(/,/g, ""); 1135 const n = Number(cleaned); 1136 return Number.isFinite(n) ? n : null; 1137 } 1138 1139 function pickFirstNumber(obj, keys) { 1140 for (const k of keys) { 1141 const n = toNumberMaybe(obj?.[k]); 1142 if (n !== null) return n; 1143 } 1144 return null; 1145 } 1146 1147 function formatMoneyAuto(raw, currency) { 1148 const cur = String(currency || "usd").toUpperCase(); 1149 const n = toNumberMaybe(raw); 1150 if (n === null) return "â"; 1151 const s = String(raw); 1152 const looksMajor = s.includes(".") || (Math.abs(n) < 1 && n !== 0); 1153 const major = looksMajor ? n : n / 100; 1154 return new Intl.NumberFormat("en-US", { 1155 style: "currency", 1156 currency: cur, 1157 minimumFractionDigits: 2, 1158 maximumFractionDigits: 2, 1159 }).format(major); 1160 } 1161 1162 function intervalSuffix(interval) { 1163 return interval === "year" ? "per year" : "per month"; 1164 } 1165 1166 // ------------------------- 1167 // Plans data 1168 // ------------------------- 1169 const CHECK = ` 1170 <svg width="18" height="18" viewBox="0 0 24 24" fill="none" aria-hidden="true"> 1171 <path d="M20 6 9 17l-5-5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> 1172 </svg>`; 1173 1174 const BASE_PRICE_CENTS = { 1175 solo_monthly: 1499, 1176 home_monthly: 1999, 1177 estate_monthly: 2999, 1178 solo_annual: 9999, 1179 home_annual: 13999, 1180 estate_annual: 20999, 1181 lifetime_promo1: 5000, 1182 lifetime_promo2: 10000, 1183 }; 1184 1185 function formatUSDForPlan(planKey, cents) { 1186 const k = String(planKey || ""); 1187 const base = Number(cents || 0); 1188 if (k.endsWith("_annual")) { 1189 return new Intl.NumberFormat("en-US", { 1190 style: "currency", 1191 currency: "USD", 1192 }).format(base / 100); 1193 } 1194 if (k.startsWith("lifetime_")) { 1195 return new Intl.NumberFormat("en-US", { 1196 style: "currency", 1197 currency: "USD", 1198 }).format(Math.max(0, base - 1) / 100); 1199 } 1200 return new Intl.NumberFormat("en-US", { 1201 style: "currency", 1202 currency: "USD", 1203 }).format(base / 100); 1204 } 1205 1206 function isLifetimePlan(planKey) { 1207 return String(planKey || "").startsWith("lifetime_"); 1208 } 1209 1210 function hasKnownPlanPrice(planKey) { 1211 return typeof BASE_PRICE_CENTS[String(planKey || "")] === "number"; 1212 } 1213 1214 function getDisplayCentsForPlan(planKey) { 1215 const key = String(planKey || ""); 1216 const base = Number(BASE_PRICE_CENTS[key] || 0); 1217 1218 if (isLifetimePlan(key)) { 1219 return Math.max(0, base - 1); 1220 } 1221 1222 return base; 1223 } 1224 1225 function formatUsdCents(cents) { 1226 return new Intl.NumberFormat("en-US", { 1227 style: "currency", 1228 currency: "USD", 1229 minimumFractionDigits: 2, 1230 maximumFractionDigits: 2, 1231 }).format(Number(cents || 0) / 100); 1232 } 1233 1234 function getTrialDueDateLabel() { 1235 const d = new Date(); 1236 d.setDate(d.getDate() + 7); 1237 1238 return new Intl.DateTimeFormat("en-US", { 1239 month: "short", 1240 day: "numeric", 1241 year: "numeric", 1242 }).format(d); 1243 } 1244 1245 function escText(value) { 1246 return String(value ?? "").replace(/[&<>"']/g, (c) => ({ 1247 "&": "&", 1248 "<": "<", 1249 ">": ">", 1250 '"': """, 1251 "'": "'", 1252 })[c]); 1253 } 1254 1255 function getPlanMarketingCopy(planKey) {
1256 const key = String(planKey || ""); 1257 1258 if (key.startsWith("solo_")) { 1259 return "AI-powered home inventory for one property binder, with rooms, assets, receipts, and claim-ready exports."; 1260 } 1261 1262 if (key.startsWith("home_")) { 1263 return "AI-powered home inventory for multiple spaces, family homes, rentals, and organized insurance documentation."; 1264 } 1265 1266 if (key.startsWith("estate_")) { 1267 return "AI-powered home inventory for multi-home families, small landlords, and larger property documentation needs."; 1268 } 1269 1270 if (key.startsWith("lifetime_")) { 1271 return "One-time access for one property binder, built for long-term home inventory and insurance-ready records."; 1272 } 1273 1274 return "AI-powered home inventory with rooms, assets, receipts, reports, and insurance-ready documentation."; 1275 } 1276 1277 function getSelectedPlanObject() { 1278 const allPlans = [ 1279 ...PLANS_MONTHLY, 1280 ...PLANS_ANNUAL, 1281 ...Object.values(PROMO_CARDS), 1282 ...(specialUnlocked?.card ? [specialUnlocked.card] : []), 1283 ]; 1284 1285 return allPlans.find((p) => p.key === selectedPlanKey) || null; 1286 } 1287 1288 function ensurePlanBillingSummary() { 1289 if (!footerCta || !btnCheckout) return null; 1290 1291 let summary = document.getElementById("ms-plan-billing-summary"); 1292 1293 if (!summary) { 1294 summary = document.createElement("div"); 1295 summary.id = "ms-plan-billing-summary"; 1296 summary.className = "ms-plan-billing-summary"; 1297 btnCheckout.parentNode.insertBefore(summary, btnCheckout); 1298 } 1299 1300 return summary; 1301 } 1302 1303 const PLANS_MONTHLY = [ 1304 { 1305 key: "solo_monthly", 1306 badge: null, 1307 title: "Solo", 1308 subtitle: "1 Property Binder", 1309 per: "per month", 1310 alt: "or $99.99/year", 1311 bullets: [ 1312 "Unlimited rooms & assets", 1313 "Disaster Mode + AI reports", 1314 "Claim-ready exports", 1315 ], 1316 }, 1317 { 1318 key: "home_monthly", 1319 badge: "Most Popular", 1320 title: "Home", 1321 subtitle: "Up to 2 Property Binders", 1322 per: "per month", 1323 alt: "or $139.99/year", 1324 bullets: [ 1325 "Everything in Solo", 1326 "Manage multiple homes", 1327 "Summer/rental property support", 1328 ], 1329 }, 1330 { 1331 key: "estate_monthly", 1332 badge: null, 1333 title: "Estate", 1334 subtitle: "Up to 5 Property Binders", 1335 per: "per month", 1336 alt: "or $209.99/year", 1337 bullets: [ 1338 "Everything in Home", 1339 "Perfect for multi-family homes", 1340 "Small landlord ready", 1341 ], 1342 }, 1343 ]; 1344 1345 const PLANS_ANNUAL = [ 1346 { 1347 key: "solo_annual", 1348 badge: null, 1349 title: "Solo", 1350 subtitle: "1 Property Binder", 1351 per: "per year", 1352 alt: "or $14.99/mo", 1353 bullets: [ 1354 "Unlimited rooms & assets", 1355 "Disaster Mode + AI reports", 1356 "Claim-ready exports", 1357 ], 1358 }, 1359 { 1360 key: "home_annual", 1361 badge: "Most Popular", 1362 title: "Home", 1363 subtitle: "Up to 2 Property Binders", 1364 per: "per year", 1365 alt: "or $19.99/mo", 1366 bullets: [ 1367 "Everything in Solo", 1368 "Manage multiple homes", 1369 "Summer/rental property support", 1370 ], 1371 }, 1372 { 1373 key: "estate_annual", 1374 badge: null, 1375 title: "Estate", 1376 subtitle: "Up to 5 Property Binders", 1377 per: "per year", 1378 alt: "or $29.99/mo", 1379 bullets: [ 1380 "Everything in Home", 1381 "Perfect for multi-home families", 1382 "Small landlord ready", 1383 ], 1384 }, 1385 ]; 1386 1387 const PROMO_CARDS = { 1388 lifetime_promo1: { 1389 key: "lifetime_promo1", 1390 chip: "Limited Time", 1391 title: "Lifetime Solo", 1392 subtitle: "1 Property Binder", 1393 per: "one-time payment", 1394 alt: "Available Dec 18, 2025 â Jan 7, 2026", 1395 bullets: [ 1396 "Everything in Solo", 1397 "Lifetime access with a single payment", 1398 "No upgrades or extra property slots", 1399 "Limited-time promo", 1400 ], 1401 }, 1402 lifetime_promo2: { 1403 key: "lifetime_promo2", 1404 chip: "Limited Time", 1405 title: "Lifetime Solo", 1406 subtitle: "1 Property Binder", 1407 per: "one-time payment", 1408 alt: "Available until May 10, 2026", 1409 bullets: [ 1410 "Everything in Solo", 1411 "Lifetime access with a single payment", 1412 "No upgrades or extra property slots", 1413 "Limited-time promo", 1414 ], 1415 }, 1416 }; 1417 1418 let selectedPlanKey = "home_monthly"; 1419 let trialUsed = false;
1420 let planView = "monthly"; 1421 let activePromoKey = null; 1422 let specialUnlocked = null; 1423 let specialUnlockedCode = ""; 1424 let lastUserData = null; 1425 1426 let msTrialGateState = "off"; 1427 let msTrialGateCompleted = false; 1428 1429 function isPaidOrTrialAccess(data) { 1430 const st = String(data?.subscriptionStatus || "free").toLowerCase(); 1431 const type = String(data?.subscriptionType || "free").toLowerCase(); 1432 const renews = String(data?.subscriptionRenews || "").toLowerCase(); 1433 1434 return ( 1435 ["active", "trialing", "lifetime"].includes(st) || 1436 ["lifetime", "influencer", "owner"].includes(type) || 1437 renews === "lifetime" || 1438 data?.lifetimeActive === true || 1439 data?.influencerActive === true || 1440 data?.ownerActive === true 1441 ); 1442 } 1443 1444 function ensureActivationNote() { 1445 const plansBlock = document.querySelector("#ms-account .ms-block-plans"); 1446 if (!plansBlock) return; 1447 1448 let note = el("ms-activation-note"); 1449 if (note) return; 1450 1451 note = document.createElement("div"); 1452 note.id = "ms-activation-note"; 1453 note.className = "ms-note"; 1454 note.style.margin = "0 0 16px"; 1455 note.innerHTML = ` 1456 <div class="ms-strong" style="margin-bottom:4px;">Choose your MyStash AI plan.</div> 1457 <div> 1458 Select the plan that fits your home, activate access, and start protecting your belongings before you ever need proof. 1459 </div> 1460 `; 1461 1462 const seg = plansBlock.querySelector(".ms-seg"); 1463 if (seg && seg.parentNode) { 1464 seg.parentNode.insertBefore(note, seg); 1465 } else { 1466 plansBlock.insertBefore(note, plansBlock.firstChild); 1467 } 1468 } 1469 1470 function removeActivationNote() { 1471 const note = el("ms-activation-note"); 1472 if (note) note.remove(); 1473 } 1474 1475 function updateCheckoutCopyForActivation() { 1476 const txt = btnCheckout ? btnCheckout.querySelector(".ms-btn-text") : null; 1477 const note = document.querySelector("#ms-account .ms-center-note"); 1478 const trialToggle = el("ms-use-trial"); 1479 const trialCard = trialToggle ? trialToggle.closest(".ms-trial-toggle-card") : null; 1480 const trialTitle = trialCard ? trialCard.querySelector("strong") : null; 1481 const trialSub = trialCard ? trialCard.querySelector("span:not(.ms-trial-switch-ui)") : null; 1482 1483 const planKey = String(selectedPlanKey || ""); 1484 const isLifetime = isLifetimePlan(planKey); 1485 const useTrial = !isLifetime && (!trialToggle || trialToggle.checked !== false); 1486 const summary = ensurePlanBillingSummary(); 1487 1488 if (footerCta) { 1489 footerCta.classList.toggle("ms-lifetime-selected", isLifetime); 1490 } 1491 1492 if (trialCard) { 1493 if (isLifetime) { 1494 trialCard.style.setProperty("display", "none", "important"); 1495 } else { 1496 trialCard.style.removeProperty("display"); 1497 1498 if (trialTitle) { 1499 trialTitle.textContent = useTrial 1500 ? "Free trial enabled" 1501 : "Not sure? Enable free trial"; 1502 } 1503 1504 if (trialSub) { 1505 trialSub.textContent = useTrial 1506 ? "7 days free. No charge today for recurring plans." 1507 : "Skip trial and start your subscription today."; 1508 } 1509 } 1510 } 1511 1512 if (summary) { 1513 if (!hasKnownPlanPrice(planKey)) { 1514 summary.style.display = "none"; 1515 summary.innerHTML = ""; 1516 } else { 1517 summary.style.display = ""; 1518 1519 const regularPrice = formatUsdCents(getDisplayCentsForPlan(planKey)); 1520 const dueDate = getTrialDueDateLabel(); 1521 1522 if (isLifetime) { 1523 summary.innerHTML = ` 1524 <div class="ms-paywall-timeline"> 1525 <div class="ms-paywall-timeline-line"></div> 1526 1527 <div class="ms-paywall-row"> 1528 <div> 1529 <span class="ms-paywall-dot checked"></span> 1530 <strong>Today</strong> 1531 </div> 1532 <b>${regularPrice} USD</b> 1533 </div> 1534 1535 <div class="ms-paywall-row"> 1536 <div> 1537 <span class="ms-paywall-dot checked"></span> 1538 <strong>Access starts today</strong> 1539 </div> 1540 <b>Lifetime access</b> 1541 </div> 1542 </div> 1543 `; 1544 } else if (useTrial) { 1545 summary.innerHTML = ` 1546 <div class="ms-paywall-timeline"> 1547 <div class="ms-paywall-timeline-line"></div> 1548 1549 <div class="ms-paywall-row"> 1550 <div> 1551 <span class="ms-paywall-dot"></span> 1552 <strong>Today</strong> 1553 </div> 1554 <b><span class="ms-paywall-red">7 days free</span> · $0.00 USD</b>
1555 </div> 1556 1557 <div class="ms-paywall-row muted"> 1558 <div> 1559 <span class="ms-paywall-dot hollow"></span> 1560 <strong>Due ${dueDate}</strong> 1561 </div> 1562 <b>${regularPrice} USD</b> 1563 </div> 1564 </div> 1565 `; 1566 } else { 1567 summary.innerHTML = ` 1568 <div class="ms-paywall-timeline"> 1569 <div class="ms-paywall-timeline-line"></div> 1570 1571 <div class="ms-paywall-row"> 1572 <div> 1573 <span class="ms-paywall-dot checked"></span> 1574 <strong>Today</strong> 1575 </div> 1576 <b>${regularPrice} USD</b> 1577 </div> 1578 1579 <div class="ms-paywall-row"> 1580 <div> 1581 <span class="ms-paywall-dot checked"></span> 1582 <strong>Access starts today</strong> 1583 </div> 1584 <b>Subscription active</b> 1585 </div> 1586 </div> 1587 `; 1588 } 1589 } 1590 } 1591 1592 if (txt) { 1593 if (isLifetime) { 1594 txt.textContent = "Buy Lifetime Solo"; 1595 } else { 1596 txt.textContent = useTrial 1597 ? "Start 7-day free trial" 1598 : "Continue to checkout"; 1599 } 1600 } 1601 1602 if (note) { 1603 if (isLifetime) { 1604 note.textContent = "Secure one-time payment by Stripe."; 1605 } else { 1606 note.textContent = useTrial 1607 ? "Secure checkout by Stripe. No charge today for recurring plans." 1608 : "Secure checkout by Stripe. Your subscription starts today."; 1609 } 1610 } 1611 } 1612 1613 1614 1615 function applyAccountActivationMode(data) { 1616 const active = isPaidOrTrialAccess(data); 1617 const titleEl = document.querySelector("#ms-account .ms-title"); 1618 const statusPanel = document.querySelector("#ms-account .ms-panel-status"); 1619 const userPanel = document.querySelector("#ms-account .ms-panel-user"); 1620 const uidLine = userPanel ? userPanel.querySelector(".ms-small") : null; 1621 const addonsBlock = document.querySelector("#ms-account .ms-block-addons"); 1622 const specialBlock = document.querySelector("#ms-account .ms-block-special"); 1623 1624 if (accountRoot) { 1625 accountRoot.classList.toggle("ms-pending-activation", !active); 1626 accountRoot.classList.toggle("ms-active-member", active); 1627 } 1628 1629 if (active) { 1630 disableTrialGate(); 1631 1632 if (titleEl) titleEl.textContent = "MyStash AI â Account"; 1633 if (subtitle) 1634 subtitle.textContent = 1635 "Your access is active. Open the app or manage your account below."; 1636 1637 removeActivationNote(); 1638 1639 if (statusPanel) statusPanel.style.display = ""; 1640 if (uidLine) uidLine.style.display = ""; 1641 if (addonsBlock) addonsBlock.style.display = ""; 1642 if (specialBlock) specialBlock.style.display = ""; 1643 1644 if (btnRefresh) btnRefresh.style.display = ""; 1645 if (btnPortal) btnPortal.style.display = ""; 1646 if (btnSignout) btnSignout.style.display = ""; 1647 1648 return; 1649 } 1650 1651 if (titleEl) titleEl.textContent = "Start your 7-day free trial"; 1652 if (subtitle) { 1653 subtitle.textContent = 1654 "Choose your plan to activate MyStash AI. No charge today. Cancel anytime before the trial ends."; 1655 } 1656 1657 if (pill) { 1658 pill.className = "ms-pill warn"; 1659 pill.textContent = "Activation required"; 1660 } 1661 1662 ensureActivationNote(); 1663 updateCheckoutCopyForActivation(); 1664 1665 if (statusPanel) statusPanel.style.display = "none"; 1666 if (uidLine) uidLine.style.display = "none"; 1667 if (addonsBlock) addonsBlock.style.display = "none"; 1668 1669 if (specialBlock) { 1670 specialBlock.style.display = params.get("special") === "1" ? "" : "none"; 1671 } 1672 1673 if (btnRefresh) btnRefresh.style.display = "none"; 1674 if (btnPortal) btnPortal.style.display = "none"; 1675 if (btnSignout) btnSignout.style.display = ""; 1676 } 1677 1678 const PAIR = { 1679 solo_monthly: "solo_annual", 1680 home_monthly: "home_annual", 1681 estate_monthly: "estate_annual", 1682 solo_annual: "solo_monthly", 1683 home_annual: "home_monthly", 1684 estate_annual: "estate_monthly", 1685 }; 1686 1687 const footerCta = el("ms-footer-cta"); 1688 const footerHome = document.createElement("div"); 1689 footerHome.id = "ms-checkout-home"; 1690 if (footerCta && footerCta.parentNode) { 1691 footerCta.parentNode.insertBefore(footerHome, footerCta); 1692 footerHome.appendChild(footerCta); 1693 } 1694 1695 function mountCheckoutBelowSelectedCard() { 1696 if (!footerCta) return; 1697 const sel = document.querySelector(`.ms-plan[data-plan-key="${selectedPlanKey}"]`); 1698 if (sel) sel.appendChild(footerCta); 1699 else if (footerHome) footerHome.appendChild(footerCta); 1700 } 1701 1702 function renderPlanCard(p, opts) { 1703 const div = document.createElement("div"); 1704 div.className = "ms-plan ms-paywall-plan" + (p.key === selectedPlanKey ? " sel" : ""); 1705 div.dataset.planKey = p.key; 1706 1707 const isHome = String(p.key || "").startsWith("home_"); 1708 const isPromo = isLifetimePlan(p.key); 1709 const isLifetime = isLifetimePlan(p.key); 1710 1711 if (isHome || (isPromo && p.chip)) { 1712 const b = document.createElement("div"); 1713 b.className = "ms-badge"; 1714 b.textContent = isHome ? "Most Popular" : p.chip; 1715 div.appendChild(b); 1716 } 1717
1718 const cents = hasKnownPlanPrice(p.key) ? getDisplayCentsForPlan(p.key) : null; 1719 const price = cents !== null ? formatUsdCents(cents) : "â"; 1720 const planName = String(p.title || "Plan"); 1721 1722 const productName = isLifetime 1723 ? "MYSTASH AI LIFETIME SOLO" 1724 : `MYSTASH AI ${planName.toUpperCase()}`; 1725 1726 const billingLabel = isLifetime 1727 ? "one-time payment" 1728 : p.key.endsWith("_annual") 1729 ? "per year" 1730 : "per month"; 1731 1732 const featureRows = (p.bullets || []) 1733 .map((line) => ` 1734 <div class="ms-paywall-box-feature"> 1735 <span>â</span> 1736 <p>${escText(line)}</p> 1737 </div> 1738 `) 1739 .join(""); 1740 1741 const body = document.createElement("div"); 1742 body.className = "ms-paywall-plan-body"; 1743 body.innerHTML = ` 1744 <div class="ms-paywall-ready">Ready to protect with</div> 1745 <h3 class="ms-paywall-title">${escText(planName)}</h3> 1746 1747 <div class="ms-paywall-product-box"> 1748 <div class="ms-paywall-product-top"> 1749 <div> 1750 <div class="ms-paywall-product-name">${escText(productName)}</div> 1751 <div class="ms-paywall-product-sub">${escText(p.subtitle || "")}</div> 1752 </div> 1753 1754 <div class="ms-paywall-price-chip"> 1755 <strong>${price}</strong> 1756 <span>${escText(billingLabel)}</span> 1757 </div> 1758 </div> 1759 1760 <div class="ms-paywall-box-features"> 1761 ${featureRows} 1762 </div> 1763 </div> 1764 `; 1765 1766 div.appendChild(body); 1767 1768 div.addEventListener("click", () => { 1769 selectedPlanKey = p.key; 1770 renderAllPlans(); 1771 }); 1772 1773 return div; 1774 } 1775 1776 function renderAllPlans() { 1777 if (!plansMainWrap || !promosSectionWrap || !promosWrap || !specialWrap || !promosTitle) return; 1778 1779 if (footerCta && footerHome) footerHome.appendChild(footerCta); 1780 1781 plansMainWrap.innerHTML = ""; 1782 promosWrap.innerHTML = ""; 1783 specialWrap.innerHTML = ""; 1784 1785 const list = planView === "annual" ? PLANS_ANNUAL : PLANS_MONTHLY; 1786 1787 list.forEach((p) => { 1788 plansMainWrap.appendChild(renderPlanCard(p, { showTrial: false })); 1789 }); 1790 1791 if (activePromoKey && PROMO_CARDS[activePromoKey]) { 1792 promosSectionWrap.style.display = ""; 1793 promosTitle.style.display = ""; 1794 promosWrap.style.display = ""; 1795 promosWrap.className = "ms-grid-1"; 1796 promosWrap.appendChild( 1797 renderPlanCard(PROMO_CARDS[activePromoKey], { showTrial: false }) 1798 ); 1799 } else { 1800 promosSectionWrap.style.display = "none"; 1801 promosTitle.style.display = "none"; 1802 promosWrap.style.display = "none"; 1803 } 1804 1805 if (specialUnlocked && specialUnlocked.card) { 1806 specialWrap.className = "ms-grid-1"; 1807 specialWrap.appendChild(renderPlanCard(specialUnlocked.card, { showTrial: false })); 1808 } 1809 1810 mountCheckoutBelowSelectedCard(); 1811 1812 if (lastUserData) { 1813 applyAccountActivationMode(lastUserData); 1814 } 1815 } 1816 1817 async function loadUserDoc(uid) { 1818 const snap = await db.collection("users").doc(uid).get(); 1819 return snap.exists ? snap.data() : null; 1820 } 1821 1822 function getSafeAccountData(data) { 1823 return { 1824 subscriptionStatus: "free", 1825 subscriptionType: "free", 1826 subscriptionTier: "free", 1827 subscriptionRenews: "free", 1828 trialUsed: false, 1829 accessStatus: "pending_activation", 1830 hasPaymentMethod: false, 1831 ...(data || {}), 1832 }; 1833 } 1834 1835 function isTrialGateEligible(data) { 1836 if (!data) return false; 1837 1838 const safe = getSafeAccountData(data); 1839 const st = String(safe.subscriptionStatus || "free").toLowerCase(); 1840 1841 if (isPaidOrTrialAccess(safe)) return false; 1842 if (st === "trialing") return false; 1843 if (safe.trialUsed === true) return false; 1844 1845 return true; 1846 } 1847 1848 function setTrialGateState(nextState) { 1849 if (!accountRoot) return; 1850 1851 if (!trialGate) { 1852 disableTrialGate(); 1853 return; 1854 } 1855 1856 msTrialGateState = nextState; 1857 1858 const isIntro = nextState === "intro1" || nextState === "intro2"; 1859 1860 accountRoot.classList.toggle("ms-trial-gated", isIntro); 1861 accountRoot.classList.toggle("ms-gate-intro", isIntro); 1862 accountRoot.classList.remove("ms-gate-plans"); 1863 1864 if (isIntro) { 1865 setAccountPreparing(false); 1866 1867 if (accountCard) { 1868 accountCard.style.display = ""; 1869 } 1870
1871 trialGate.style.display = "block"; 1872 } else { 1873 trialGate.style.display = "none"; 1874 } 1875 1876 trialGate.querySelectorAll(".ms-trial-gate-screen").forEach((screen) => { 1877 const screenId = Number(screen.dataset.msGateScreen || "0"); 1878 const shouldShow = 1879 (nextState === "intro1" && screenId === 1) || 1880 (nextState === "intro2" && screenId === 2); 1881 1882 screen.classList.toggle("is-active", shouldShow); 1883 }); 1884 1885 if (isIntro) { 1886 window.scrollTo({ top: 0, behavior: "auto" }); 1887 } 1888 } 1889 1890 function maybeShowTrialGate(data) { 1891 if (!trialGate) return; 1892 if (msTrialGateCompleted) return; 1893 if (msTrialGateState !== "off") return; 1894 1895 if (!isTrialGateEligible(data)) { 1896 disableTrialGate(); 1897 return; 1898 } 1899 1900 setTrialGateState("intro1"); 1901 } 1902 1903 function disableTrialGate() { 1904 if (!accountRoot || !trialGate) return; 1905 1906 msTrialGateState = "off"; 1907 1908 accountRoot.classList.remove("ms-trial-gated"); 1909 accountRoot.classList.remove("ms-gate-intro"); 1910 accountRoot.classList.remove("ms-gate-plans"); 1911 1912 trialGate.style.display = "none"; 1913 } 1914 1915 function hasStripeCustomer(data) { 1916 return !!String( 1917 data?.stripeId || 1918 data?.stripeCustomerId || 1919 data?.stripeCustomer || 1920 "" 1921 ).trim(); 1922 } 1923 1924 function sleep(ms) { 1925 return new Promise((resolve) => setTimeout(resolve, ms)); 1926 } 1927 1928 async function waitForStripeCustomer(uid, options = {}) { 1929 const maxMs = Number(options.maxMs || 18000); 1930 const intervalMs = Number(options.intervalMs || 900); 1931 const started = Date.now(); 1932 1933 let lastData = null; 1934 1935 while (Date.now() - started < maxMs) { 1936 const data = await loadUserDoc(uid); 1937 lastData = data; 1938 1939 if (hasStripeCustomer(data)) { 1940 return data; 1941 } 1942 1943 await sleep(intervalMs); 1944 } 1945 1946 return lastData; 1947 } 1948 1949 function setPreparingAccountUI() { 1950 const titleEl = document.querySelector("#ms-account .ms-title"); 1951 1952 if (titleEl) titleEl.textContent = "Preparing your account..."; 1953 if (subtitle) subtitle.textContent = "Preparing your account..."; 1954 1955 if (pill) { 1956 pill.className = "ms-pill"; 1957 pill.textContent = "Checking access..."; 1958 } 1959 } 1960 1961 function paintAccountFromUserData(data, options = {}) { 1962 const shouldRefreshBilling = options.refreshBilling !== false; 1963 1964 lastUserData = getSafeAccountData(data); 1965 1966 const stEl = el("ms-status"); 1967 const tierEl = el("ms-tier"); 1968 const typeEl = el("ms-type"); 1969 1970 if (stEl) stEl.textContent = lastUserData.subscriptionStatus || "free"; 1971 if (tierEl) tierEl.textContent = lastUserData.subscriptionTier || "free"; 1972 if (typeEl) typeEl.textContent = lastUserData.subscriptionType || "free"; 1973 1974 trialUsed = lastUserData.trialUsed === true; 1975 1976 if (shouldRefreshBilling) { 1977 setBillingAvailability(lastUserData); 1978 } 1979 1980 const st = String(lastUserData.subscriptionStatus || "free").toLowerCase(); 1981 1982 if (pill) { 1983 if (["active", "trialing", "lifetime"].includes(st)) { 1984 pill.className = "ms-pill ok"; 1985 pill.textContent = "Access active"; 1986 } else { 1987 pill.className = "ms-pill warn"; 1988 pill.textContent = "Activation required"; 1989 } 1990 } 1991 1992 renderAllPlans(); 1993 applyAccountActivationMode(lastUserData); 1994 maybeShowTrialGate(lastUserData); 1995 } 1996 1997 function setSignedOutUI() { 1998 disableTrialGate(); 1999 setAccountPreparing(false); 2000 2001 if (accountRoot) { 2002 accountRoot.classList.remove("ms-pending-activation"); 2003 accountRoot.classList.remove("ms-active-member"); 2004 } 2005 2006 if (accountCard) accountCard.style.display = "none"; 2007 if (guestCard) guestCard.style.display = ""; 2008 2009 if (pill) { 2010 pill.className = "ms-pill warn"; 2011 pill.textContent = "Signed out"; 2012 } 2013 2014 if (subtitle) subtitle.textContent = "Sign in to view your account."; 2015 2016 clearMsg("ms-guest-msg"); 2017 2018 if (goSignin) { 2019 const next = encodeURIComponent(window.location.pathname + window.location.search); 2020 goSignin.setAttribute("href", "/sign-in/?next=" + next); 2021 } 2022 } 2023 2024 function setSignedInUI(user) {
2025 setAccountPreparing(true); 2026 2027 if (guestCard) guestCard.style.display = "none"; 2028 if (accountCard) accountCard.style.display = ""; 2029 2030 if (pill) { 2031 pill.className = "ms-pill"; 2032 pill.textContent = "Checking accessâ¦"; 2033 } 2034 2035 if (subtitle) subtitle.textContent = "Preparing your accountâ¦"; 2036 2037 const titleEl = document.querySelector("#ms-account .ms-title"); 2038 if (titleEl) titleEl.textContent = "Preparing your accountâ¦"; 2039 2040 const emailEl = el("ms-user-email"); 2041 const uidEl = el("ms-user-uid"); 2042 2043 if (emailEl) emailEl.textContent = user.email || "â"; 2044 if (uidEl) uidEl.textContent = user.uid || "â"; 2045 } 2046 2047 function parseSlotsSummary(sum) { 2048 const base = Number(sum?.baseLimit ?? sum?.base ?? NaN); 2049 const addon = Number( 2050 sum?.addonQtyStripe ?? 2051 sum?.activeAddons ?? 2052 sum?.effectiveAddons ?? 2053 sum?.addonQty ?? 2054 sum?.addons ?? 2055 0 2056 ); 2057 const limit = Number( 2058 sum?.limitNow ?? sum?.limit ?? (Number.isFinite(base) ? base + addon : NaN) 2059 ); 2060 const used = Number(sum?.used ?? NaN); 2061 const remaining = Number( 2062 sum?.freeNow ?? 2063 sum?.free ?? 2064 (Number.isFinite(limit) && Number.isFinite(used) 2065 ? Math.max(0, limit - used) 2066 : NaN) 2067 ); 2068 const nextLimit = Number(sum?.limitNext ?? NaN); 2069 return { base, addon, limit, used, remaining, nextLimit }; 2070 } 2071 2072 async function refreshSlotsUI(userData) { 2073 if (!slotsTextEl) return; 2074 2075 const data = userData || lastUserData || {}; 2076 const st = String(data.subscriptionStatus || "free").toLowerCase(); 2077 const type = String(data.subscriptionType || "").toLowerCase(); 2078 const renews = String(data.subscriptionRenews || "").toLowerCase(); 2079 2080 const nonRecurring = 2081 renews === "lifetime" || 2082 renews === "non_recurring" || 2083 type === "lifetime" || 2084 type === "influencer" || 2085 type === "owner" || 2086 data.lifetimeActive === true || 2087 data.influencerActive === true || 2088 data.ownerActive === true; 2089 2090 const hasRecurringPlan = !nonRecurring && (st === "active" || st === "trialing"); 2091 2092 if (slotsNextEl) slotsNextEl.textContent = ""; 2093 if (slotsPriceEl) slotsPriceEl.textContent = ""; 2094 if (btnSlotsBuy) btnSlotsBuy.disabled = true; 2095 2096 try { 2097 const res = await fnGetSlotsSummary({}); 2098 const sum = res?.data || {}; 2099 const p = parseSlotsSummary(sum); 2100 2101 try { 2102 localStorage.setItem( 2103 "msLastAddonQty", 2104 String(Number.isFinite(p.addon) ? p.addon : 0) 2105 ); 2106 } catch (_) {} 2107 2108 try { 2109 const pending = localStorage.getItem("msAddonPending") === "1"; 2110 if (pending) { 2111 const base = parseInt(localStorage.getItem("msAddonBaseline") || "0", 10); 2112 const nowAddon = Number.isFinite(p.addon) ? p.addon : 0; 2113 2114 if (nowAddon > base) { 2115 localStorage.removeItem("msAddonPending"); 2116 localStorage.removeItem("msAddonBaseline"); 2117 localStorage.removeItem("msAddonPendingAt"); 2118 stopAutoRefreshAccess(); 2119 2120 if (slotsMsgEl) { 2121 showMsg( 2122 "ms-slots-msg", 2123 "Payment confirmed. Your extra slot is now active.", 2124 "ok" 2125 ); 2126 } 2127 } 2128 2129 const startedAt = parseInt( 2130 localStorage.getItem("msAddonPendingAt") || "0", 2131 10 2132 ); 2133 if (startedAt && Date.now() - startedAt > 12 * 60 * 1000) { 2134 localStorage.removeItem("msAddonPending"); 2135 localStorage.removeItem("msAddonBaseline"); 2136 localStorage.removeItem("msAddonPendingAt"); 2137 stopAutoRefreshAccess(); 2138 } 2139 } 2140 } catch (_) {} 2141 2142 const parts = []; 2143 if (Number.isFinite(p.limit)) parts.push(`Now: ${p.limit} slots`); 2144 if (Number.isFinite(p.used)) parts.push(`Used: ${p.used}`); 2145 if (Number.isFinite(p.remaining)) parts.push(`Remaining: ${p.remaining}`); 2146 if (Number.isFinite(p.base)) parts.push(`Base: ${p.base}`); 2147 if (Number.isFinite(p.addon)) parts.push(`Add-ons: ${p.addon}`); 2148 2149 slotsTextEl.textContent = parts.length ? parts.join(" ⢠") : "â"; 2150 if (slotsNextEl && Number.isFinite(p.nextLimit)) 2151 slotsNextEl.textContent = `Next cycle: ${p.nextLimit} slots`; 2152 2153 const inTrial = sum?.inTrial === true; 2154 const canBuySlots = !nonRecurring && st === "active" && !inTrial; 2155 2156 if (btnSlotsBuy) { 2157 const t = btnSlotsBuy.querySelector(".ms-btn-text"); 2158 btnSlotsBuy.disabled = !canBuySlots; 2159 if (t) t.textContent = inTrial ? "Available after trial" : "Buy +1 slot"; 2160 } 2161 2162 if (slotsPriceEl) { 2163 if (nonRecurring) { 2164 slotsPriceEl.textContent = 2165 "Extra property slots arenât available on Lifetime/Promo/Special plans."; 2166 } else if (!hasRecurringPlan) { 2167 slotsPriceEl.textContent = 2168 "Upgrade to an active recurring plan to add extra property slots."; 2169 } else if (inTrial) { 2170 slotsPriceEl.textContent = 2171 "Add-ons can be purchased after your trial ends."; 2172 } else { 2173 try { 2174 const pr = await fnPreviewAddonProration({}); 2175 const d = pr?.data || {}; 2176 2177 const unitRaw = pickFirstNumber(d, [
2178 "unitAmountCents", 2179 "unit_amount", 2180 "unitAmount", 2181 "unit_amount_cents", 2182 "priceUnitAmountCents", 2183 ]); 2184 const dueRaw = pickFirstNumber(d, [ 2185 "amountDueCents", 2186 "amount_due", 2187 "amountDue", 2188 "amount_due_cents", 2189 "amountDueNowCents", 2190 "amount_due_today_cents", 2191 "amountDueTodayCents", 2192 ]); 2193 2194 const cur = d.currency || "USD"; 2195 const regular = formatMoneyAuto(unitRaw, cur); 2196 const today = formatMoneyAuto(dueRaw, cur); 2197 const suf = intervalSuffix(String(d.interval || "month").toLowerCase()); 2198 2199 slotsPriceEl.innerHTML = 2200 `<b>Regular price:</b> ${regular} ${suf}. ` + 2201 `<b>Today:</b> ${today} (prorated).<br>` + 2202 `On your next renewal, youâll be charged an additional <b>${regular}</b> ${suf} on top of your plan.`; 2203 } catch (e2) { 2204 slotsPriceEl.textContent = 2205 "Pricing details are temporarily unavailable. Please try again."; 2206 } 2207 } 2208 } 2209 } catch (e) { 2210 slotsTextEl.textContent = hasRecurringPlan 2211 ? "Could not load slot info. Try Refresh access." 2212 : "Slots are available with an active recurring plan."; 2213 if (btnSlotsBuy) btnSlotsBuy.disabled = true; 2214 if (slotsPriceEl) slotsPriceEl.textContent = ""; 2215 } 2216 } 2217 2218 function setBillingAvailability(data) { 2219 const type = String(data.subscriptionType || "").toLowerCase(); 2220 const renews = String(data.subscriptionRenews || "").toLowerCase(); 2221 2222 const nonRecurring = 2223 renews === "lifetime" || 2224 renews === "non_recurring" || 2225 type === "lifetime" || 2226 type === "influencer" || 2227 type === "owner" || 2228 data.lifetimeActive === true || 2229 data.influencerActive === true || 2230 data.ownerActive === true; 2231 2232 const t = btnPortal ? btnPortal.querySelector(".ms-btn-text") : null; 2233 2234 if (btnPortal) { 2235 if (nonRecurring) { 2236 btnPortal.disabled = true; 2237 btnPortal.classList.add("disabled-portal"); 2238 btnPortal.dataset.lockedDisabled = "1"; 2239 if (t) t.textContent = "Billing not available"; 2240 } else { 2241 btnPortal.disabled = false; 2242 btnPortal.classList.remove("disabled-portal"); 2243 delete btnPortal.dataset.lockedDisabled; 2244 if (t) t.textContent = "Manage billing"; 2245 } 2246 } 2247 2248 if (invoicesNote) { 2249 if (nonRecurring) { 2250 invoicesNote.style.display = ""; 2251 invoicesNote.innerHTML = 2252 "<b>Invoices:</b> For Lifetime/Promo/Special plans, invoices are handled by support. " + 2253 "Open the app â <b>Settings</b> â <b>Get support</b>."; 2254 } else { 2255 invoicesNote.style.display = "none"; 2256 invoicesNote.textContent = ""; 2257 } 2258 } 2259 2260 refreshSlotsUI(data).catch(() => {}); 2261 } 2262 2263 async function refreshAccess() { 2264 clearMsg("ms-checkout-msg"); 2265 setBtnLoading(btnRefresh, true); 2266 await nextPaint(); 2267 2268 try { 2269 const u = auth.currentUser; 2270 2271 if (!u) { 2272 setSignedOutUI(); 2273 return; 2274 } 2275 2276 let preData = await loadUserDoc(u.uid); 2277 lastUserData = getSafeAccountData(preData); 2278 2279 if (!hasStripeCustomer(lastUserData)) { 2280 setPreparingAccountUI(); 2281 2282 showMsg( 2283 "ms-checkout-msg", 2284 "Preparing your secure checkout. This can take a few secondsâ¦", 2285 "" 2286 ); 2287 2288 preData = await waitForStripeCustomer(u.uid, { 2289 maxMs: 18000, 2290 intervalMs: 900, 2291 }); 2292 2293 lastUserData = getSafeAccountData(preData); 2294 2295 if (!hasStripeCustomer(lastUserData)) { 2296 paintAccountFromUserData(lastUserData, { refreshBilling: false }); 2297 2298 showMsg( 2299 "ms-checkout-msg", 2300 "Your account is still being prepared. Please wait a few seconds and tap Refresh access.", 2301 "" 2302 ); 2303 2304 return; 2305 } 2306 } 2307 2308 await fnSyncStripe({}); 2309 2310 const data = await loadUserDoc(u.uid); 2311 paintAccountFromUserData(data, { refreshBilling: true }); 2312 } catch (e) { 2313 showMsg("ms-checkout-msg", "Refresh failed: " + extractErr(e), "err"); 2314 } finally { 2315 setBtnLoading(btnRefresh, false); 2316 revealAccountAfterAccessLoaded(); 2317 } 2318 } 2319 2320 async function loadLifetimePromoFromBackend() { 2321 activePromoKey = null;
2322 try { 2323 const res = await fnGetLifetimeConfig({}); 2324 const cfg = res && res.data ? res.data : {}; 2325 const p1 = !!( 2326 cfg.lifetimePromo1Enabled ?? 2327 cfg.promo1Enabled ?? 2328 cfg.promo1 ?? 2329 cfg.LIFETIME_PROMO1_ENABLED 2330 ); 2331 const p2 = !!( 2332 cfg.lifetimePromo2Enabled ?? 2333 cfg.promo2Enabled ?? 2334 cfg.promo2 ?? 2335 cfg.LIFETIME_PROMO2_ENABLED 2336 ); 2337 2338 if (p1) activePromoKey = "lifetime_promo1"; 2339 else if (p2) activePromoKey = "lifetime_promo2"; 2340 } catch (_) { 2341 activePromoKey = null; 2342 } 2343 } 2344 2345 function setPlanView(next) { 2346 planView = next === "annual" ? "annual" : "monthly"; 2347 if (tabMonthly) tabMonthly.classList.toggle("active", planView === "monthly"); 2348 if (tabAnnual) tabAnnual.classList.toggle("active", planView === "annual"); 2349 if (tabMonthly) 2350 tabMonthly.setAttribute("aria-selected", planView === "monthly" ? "true" : "false"); 2351 if (tabAnnual) 2352 tabAnnual.setAttribute("aria-selected", planView === "annual" ? "true" : "false"); 2353 2354 const isSelectedInView = 2355 planView === "annual" 2356 ? selectedPlanKey.endsWith("_annual") 2357 : selectedPlanKey.endsWith("_monthly"); 2358 if (!isSelectedInView && PAIR[selectedPlanKey]) 2359 selectedPlanKey = PAIR[selectedPlanKey]; 2360 2361 if (!selectedPlanKey.endsWith(planView === "annual" ? "_annual" : "_monthly")) { 2362 selectedPlanKey = planView === "annual" ? "home_annual" : "home_monthly"; 2363 } 2364 renderAllPlans(); 2365 } 2366 2367 if (tabMonthly) 2368 tabMonthly.addEventListener("click", () => setPlanView("monthly")); 2369 if (tabAnnual) 2370 tabAnnual.addEventListener("click", () => setPlanView("annual")); 2371 const trialToggleEl = el("ms-use-trial"); 2372 if (trialToggleEl) { 2373 trialToggleEl.addEventListener("change", updateCheckoutCopyForActivation); 2374 } 2375 2376 if (trialGate) { 2377 trialGate.querySelectorAll("[data-ms-gate-next]").forEach((btn) => { 2378 btn.addEventListener("click", () => { 2379 if (msTrialGateState === "intro1") { 2380 setTrialGateState("intro2"); 2381 return; 2382 } 2383 2384 if (msTrialGateState === "intro2") { 2385 msTrialGateCompleted = true; 2386 2387 /* 2388 Regresa al /account normal: 2389 planes, header, estado, sign out y demás bloques como antes. 2390 */ 2391 disableTrialGate(); 2392 renderAllPlans(); 2393 2394 setTimeout(() => { 2395 const plansBlock = document.querySelector("#ms-account .ms-block-plans"); 2396 const plansRoot = document.getElementById("ms-plans-main"); 2397 const selected = document.querySelector("#ms-account .ms-plan.sel"); 2398 2399 if (selected && plansRoot) { 2400 const left = 2401 selected.offsetLeft - 2402 (plansRoot.clientWidth - selected.clientWidth) / 2; 2403 2404 plansRoot.scrollLeft = Math.max(0, left); 2405 } 2406 2407 if (plansBlock && window.matchMedia("(max-width: 860px)").matches) { 2408 const y = 2409 window.scrollY + 2410 plansBlock.getBoundingClientRect().top - 2411 88; 2412 2413 window.scrollTo({ 2414 top: Math.max(0, y), 2415 behavior: "smooth" 2416 }); 2417 } 2418 }, 120); 2419 } 2420 }); 2421 }); 2422 } 2423 2424 // ------------------------- 2425 // Actions 2426 // ------------------------- 2427 if (btnSignout) { 2428 btnSignout.addEventListener("click", async () => { 2429 setBtnLoading(btnSignout, true); 2430 await nextPaint(); 2431 try { 2432 await auth.signOut(); 2433 } finally { 2434 setBtnLoading(btnSignout, false); 2435 } 2436 }); 2437 } 2438 2439 if (btnRefresh) btnRefresh.addEventListener("click", refreshAccess); 2440 2441 if (btnPortal) { 2442 btnPortal.addEventListener("click", async () => { 2443 if (btnPortal.disabled) return; 2444 clearMsg("ms-checkout-msg"); 2445 setBtnLoading(btnPortal, true); 2446 await nextPaint(); 2447 showMsg("ms-checkout-msg", "Opening billing portalâ¦", ""); 2448 2449 try { 2450 const returnUrl = window.location.origin + "/account/?portal_return=1"; 2451 const res = await fnCreateBillingPortalSession({ returnUrl }); 2452 const url = res && res.data && res.data.url; 2453 if (!url) throw new Error("No portal URL returned"); 2454 window.location.href = url; 2455 } catch (e) { 2456 showMsg( 2457 "ms-checkout-msg", 2458 "Could not open billing portal: " + extractErr(e), 2459 "err" 2460 ); 2461 } finally { 2462 setBtnLoading(btnPortal, false); 2463 } 2464 }); 2465 } 2466 2467 if (btnSlotsBuy) { 2468 btnSlotsBuy.addEventListener("click", async () => { 2469 if (btnSlotsBuy.disabled) return; 2470 if (slotsMsgEl) clearMsg("ms-slots-msg"); 2471 2472 setBtnLoading(btnSlotsBuy, true); 2473 await nextPaint(); 2474 2475 let payWin = null; 2476 try { 2477 payWin = window.open("about:blank", "_blank"); 2478 } catch (_) { 2479 payWin = null; 2480 } 2481 2482 if (!payWin) { 2483 setBtnLoading(btnSlotsBuy, false); 2484 showMsg( 2485 "ms-slots-msg", 2486 "Your browser blocked the payment tab.\n\nPlease allow pop-ups for this site and try again.", 2487 "err" 2488 ); 2489 return; 2490 } 2491 2492 let baseline = 0; 2493 try { 2494 baseline = parseInt(localStorage.getItem("msLastAddonQty") || "0", 10) || 0; 2495 } catch (_) {} 2496 2497 try { 2498 localStorage.setItem("msAddonPending", "1"); 2499 localStorage.setItem("msAddonBaseline", String(baseline)); 2500 localStorage.setItem("msAddonPendingAt", String(Date.now())); 2501 } catch (_) {} 2502 2503 try { 2504 startAutoRefreshAccess({ everyMs: 30000, maxMinutes: 8 }); 2505 } catch (_) {} 2506 2507 showMsg( 2508 "ms-slots-msg", 2509 "A secure payment tab has been opened.\n\nKeep this Account page open.\nAfter you complete payment, come back here and tap âRefresh accessâ.", 2510 "ok" 2511 ); 2512 2513 const runnerHtml = `<!doctype html>`; 2514 try { 2515 payWin.document.open(); 2516 payWin.document.write(runnerHtml); 2517 payWin.document.close(); 2518 try { 2519 payWin.focus(); 2520 } catch (_) {} 2521 } catch (e) { 2522 try { 2523 payWin.close(); 2524 } catch (_) {} 2525 showMsg( 2526 "ms-slots-msg", 2527 "Could not open payment tab: " + extractErr(e), 2528 "err" 2529 ); 2530 } finally { 2531 setBtnLoading(btnSlotsBuy, false); 2532 } 2533 }); 2534 } 2535 2536 function isAddonsModalOpen() { 2537 return addonsModal && addonsModal.style.display !== "none"; 2538 } 2539 2540 function fmtDate(ms) { 2541 if (!ms) return "â";
2542 try { 2543 return new Intl.DateTimeFormat("en-US", { 2544 year: "numeric", 2545 month: "short", 2546 day: "numeric", 2547 }).format(new Date(ms)); 2548 } catch (_) { 2549 return new Date(ms).toDateString(); 2550 } 2551 } 2552 2553 function propNameById(pid) { 2554 if (!pid) return null; 2555 const p = propsLive.find((x) => x.id === pid); 2556 return p ? p.name : pid.slice(0, 6); 2557 } 2558 2559 function getScheduledAddonConflictForProperty(propertyId) { 2560 const pid = String(propertyId || "").trim(); 2561 if (!pid) return null; 2562 2563 return ( 2564 (addonsLive || []).find((a) => { 2565 return ( 2566 a && 2567 a.id !== managingAddonId && 2568 a.cancelAtEnd === true && 2569 String(a.propertyId || "").trim() === pid 2570 ); 2571 }) || null 2572 ); 2573 } 2574 2575 function isPropertyBlockedForAddonCancel(propertyId) { 2576 return !!getScheduledAddonConflictForProperty(propertyId); 2577 } 2578 2579 function openAddonsModal() { 2580 if (addonsTitleEl) { 2581 addonsTitleEl.textContent = "Manage add-ons"; 2582 } 2583 2584 if (addonsNoteEl) { 2585 addonsNoteEl.style.display = ""; 2586 addonsNoteEl.innerHTML = 2587 "<b>Heads up:</b> This will disable the selected property at the end of the billing cycle. This canât be undone."; 2588 } 2589 2590 if (!addonsModal) return; 2591 2592 modalMode = "addons"; 2593 resetReductionState(); 2594 2595 addonsModal.style.display = "flex"; 2596 addonsModal.setAttribute("aria-hidden", "false"); 2597 2598 managingAddonId = null; 2599 selectedPropertyId = null; 2600 2601 if (pickerWrap) pickerWrap.style.display = "none"; 2602 if (addonsListEl) addonsListEl.style.display = ""; 2603 clearMsg("ms-addons-msg"); 2604 2605 setPickerChromeForAddons(); 2606 renderAddonsList(); 2607 } 2608 2609 function esc(s) { 2610 return String(s ?? "").replace(/[&<>"']/g, (c) => ({ 2611 "&": "&", 2612 "<": "<", 2613 ">": ">", 2614 '"': """, 2615 "'": "'", 2616 })[c]); 2617 } 2618 2619 function isPropertySelectableForReduction(p) { 2620 if (!p) return false; 2621 if (p.disabled === true) return false; 2622 if (p.archived === true) return false; 2623 if (p.active === false) return false; 2624 return true; 2625 } 2626 2627 function resetReductionState() { 2628 reductionGuardState = null; 2629 reductionSelectedIds = new Set(); 2630 } 2631 2632 function setPickerChromeForAddons() { 2633 if (pickerHead) pickerHead.style.display = "none"; 2634 if (pickerEyebrow) { 2635 pickerEyebrow.textContent = ""; 2636 pickerEyebrow.style.display = "none"; 2637 } 2638 if (pickerTitle) pickerTitle.textContent = ""; 2639 if (pickerSub) pickerSub.textContent = ""; 2640 2641 if (btnPickerConfirm) { 2642 const t = btnPickerConfirm.querySelector(".ms-btn-text"); 2643 btnPickerConfirm.disabled = !selectedPropertyId; 2644 if (t) t.textContent = "Yes, schedule cancel"; 2645 } 2646 } 2647 2648 function setPickerChromeForReduction() { 2649 if (!reductionGuardState) return; 2650 2651 const { allowed, activeProps, needToRemove } = reductionGuardState; 2652 const selectedCount = reductionSelectedIds.size; 2653 2654 if (pickerHead) pickerHead.style.display = ""; 2655 if (pickerEyebrow) pickerEyebrow.textContent = "Plan reduction"; 2656 if (pickerTitle) pickerTitle.textContent = "Choose properties to remove"; 2657 if (pickerSub) { 2658 pickerSub.textContent = 2659 `This plan allows ${allowed} ${ 2660 allowed === 1 ? "property" : "properties" 2661 }. ` + 2662 `You currently have ${activeProps.length}. Select ${needToRemove} to continue.`; 2663 } 2664 2665 if (btnPickerConfirm) { 2666 const t = btnPickerConfirm.querySelector(".ms-btn-text"); 2667 btnPickerConfirm.disabled = selectedCount !== needToRemove; 2668 if (t) { 2669 t.textContent = 2670 selectedCount === needToRemove 2671 ? "Continue to checkout" 2672 : `Select ${needToRemove - selectedCount} more`; 2673 } 2674 } 2675 } 2676 2677 function renderReductionPicker() { 2678 if (!propsListEl || !reductionGuardState) return; 2679 2680 const { planKey, allowed, activeProps, needToRemove } = reductionGuardState; 2681 propsListEl.innerHTML = ""; 2682 clearMsg("ms-addons-msg"); 2683 2684 const selectedCount = reductionSelectedIds.size; 2685 const planName = esc(getPlanDisplayName(planKey)); 2686 2687 const summary = document.createElement("div"); 2688 summary.className = "ms-reduction-summary"; 2689 summary.innerHTML = ` 2690 <div class="ms-reduction-summary-top"> 2691 <div class="ms-reduction-summary-title">${planName} reduction</div> 2692 <div class="ms-reduction-count">${selectedCount}/${needToRemove}</div> 2693 </div> 2694 <div class="ms-reduction-meta"> 2695 <div class="ms-reduction-chip">Allowed: ${allowed}</div> 2696 <div class="ms-reduction-chip">Active now: ${activeProps.length}</div> 2697 <div class="ms-reduction-chip">To remove: ${needToRemove}</div> 2698 </div> 2699 `; 2700 propsListEl.appendChild(summary); 2701 2702 const list = document.createElement("div"); 2703 list.className = "ms-options"; 2704 2705 activeProps.forEach((p, idx) => { 2706 const selectable = isPropertySelectableForReduction(p); 2707 const on = reductionSelectedIds.has(p.id); 2708 const propertyName = esc(p.name || `Property ${idx + 1}`); 2709
2710 const row = document.createElement("button"); 2711 row.type = "button"; 2712 row.className = "ms-option ms-option-property" + (on ? " on" : ""); 2713 row.disabled = !selectable; 2714 2715 row.innerHTML = ` 2716 <div> 2717 <div class="t">${propertyName}</div> 2718 <div class="m">${ 2719 on 2720 ? "This property will be removed when you continue." 2721 : "Select this property to remove it from your current limit." 2722 }</div> 2723 <div class="ms-option-badges"> 2724 <span class="ms-option-badge">Active property</span> 2725 ${on ? `<span class="ms-option-badge warn">Will be removed</span>` : ``} 2726 </div> 2727 </div> 2728 <div class="ms-option-right"> 2729 <span class="ms-option-check">${on ? "Selected" : "Select"}</span> 2730 <span class="dot" aria-hidden="true"></span> 2731 </div> 2732 `; 2733 2734 row.addEventListener("click", () => { 2735 clearMsg("ms-addons-msg"); 2736 2737 if (on) { 2738 reductionSelectedIds.delete(p.id); 2739 renderReductionPicker(); 2740 setPickerChromeForReduction(); 2741 return; 2742 } 2743 2744 if (needToRemove === 1) { 2745 reductionSelectedIds = new Set([p.id]); 2746 renderReductionPicker(); 2747 setPickerChromeForReduction(); 2748 return; 2749 } 2750 2751 if (reductionSelectedIds.size >= needToRemove) { 2752 return; 2753 } 2754 2755 reductionSelectedIds.add(p.id); 2756 renderReductionPicker(); 2757 setPickerChromeForReduction(); 2758 }); 2759 2760 list.appendChild(row); 2761 }); 2762 2763 propsListEl.appendChild(list); 2764 } 2765 2766 function renderAddonsList() { 2767 if (!addonsListEl) return; 2768 2769 addonsListEl.innerHTML = ""; 2770 2771 if (!addonsLive || addonsLive.length === 0) { 2772 const empty = document.createElement("div"); 2773 empty.className = "ms-addon-picker-note"; 2774 empty.innerHTML = `<b>No active add-ons to manage.</b><br>Add an extra slot first, then come back here if you need to schedule a cancellation.`; 2775 addonsListEl.appendChild(empty); 2776 return; 2777 } 2778 2779 const wrap = document.createElement("div"); 2780 wrap.style.display = "grid"; 2781 wrap.style.gap = "12px"; 2782 2783 addonsLive.forEach((a) => { 2784 const endMs = a.disableAtMs || a.expiresAtMs || null; 2785 const linkedName = a.propertyId ? propNameById(a.propertyId) : null; 2786 2787 const card = document.createElement("div"); 2788 card.className = "ms-addon-card"; 2789 2790 const top = document.createElement("div"); 2791 top.className = "ms-addon-top"; 2792 2793 const left = document.createElement("div"); 2794 left.className = "ms-addon-left"; 2795 2796 const title = document.createElement("div"); 2797 title.className = "ms-addon-name"; 2798 title.textContent = "Extra property slot"; 2799 left.appendChild(title); 2800 2801 const sub = document.createElement("div"); 2802 sub.className = "ms-addon-sub"; 2803 sub.textContent = a.cancelAtEnd 2804 ? "This add-on is already scheduled to end with your current billing cycle." 2805 : "Choose which property should lose this extra slot at the end of the cycle."; 2806 left.appendChild(sub); 2807 2808 const lines = document.createElement("div"); 2809 lines.className = "ms-addon-lines"; 2810 2811 const l1 = document.createElement("div"); 2812 l1.className = "ms-kvline"; 2813 l1.innerHTML = `<span class="k">Linked:</span> ${ 2814 linkedName ? esc(linkedName) : "â (choose a property)" 2815 }`; 2816 lines.appendChild(l1); 2817 2818 const l2 = document.createElement("div"); 2819 l2.className = "ms-kvline"; 2820 if (a.cancelAtEnd) { 2821 l2.innerHTML = `<span class="k">Status:</span> Cancellation scheduled for <b>${esc( 2822 fmtDate(endMs) 2823 )}</b>.`; 2824 } else { 2825 l2.innerHTML = `<span class="k">Cycle ends:</span> <b>${esc( 2826 fmtDate(endMs) 2827 )}</b>.`; 2828 } 2829 lines.appendChild(l2); 2830 2831 left.appendChild(lines); 2832 2833 const right = document.createElement("div"); 2834 right.className = "ms-addon-actions"; 2835 2836 if (a.cancelAtEnd) { 2837 const pillEl = document.createElement("span"); 2838 pillEl.className = "ms-addon-tag warn"; 2839 pillEl.textContent = "Cancel scheduled"; 2840 right.appendChild(pillEl); 2841 } else { 2842 const btn = document.createElement("button"); 2843 btn.type = "button"; 2844 btn.className = "ms-btn ms-btn-danger ms-btn-sm"; 2845 btn.innerHTML = `<span class="ms-btn-text">Schedule cancel</span>`;
2846 btn.addEventListener("click", () => { 2847 managingAddonId = a.id; 2848 selectedPropertyId = null; 2849 2850 if (addonsListEl) addonsListEl.style.display = "none"; 2851 if (pickerWrap) pickerWrap.style.display = ""; 2852 if (btnPickerConfirm) btnPickerConfirm.disabled = true; 2853 2854 clearMsg("ms-addons-msg"); 2855 renderPropsPicker(endMs); 2856 setPickerChromeForAddons(); 2857 }); 2858 right.appendChild(btn); 2859 } 2860 2861 top.appendChild(left); 2862 top.appendChild(right); 2863 card.appendChild(top); 2864 2865 wrap.appendChild(card); 2866 }); 2867 2868 addonsListEl.appendChild(wrap); 2869 } 2870 2871 function renderPropsPicker(endMs) { 2872 if (!propsListEl) return; 2873 propsListEl.innerHTML = ""; 2874 clearMsg("ms-addons-msg"); 2875 2876 if (!propsLive || propsLive.length === 0) { 2877 const empty = document.createElement("div"); 2878 empty.className = "ms-addon-picker-summary"; 2879 empty.innerHTML = ` 2880 <div class="ms-addon-picker-title">No properties found</div> 2881 <div class="ms-addon-picker-copy"> 2882 Create a property in the app first, then return to manage this add-on. 2883 </div> 2884 `; 2885 propsListEl.appendChild(empty); 2886 2887 selectedPropertyId = null; 2888 if (btnPickerConfirm) btnPickerConfirm.disabled = true; 2889 setPickerChromeForAddons(); 2890 return; 2891 } 2892 2893 if (selectedPropertyId && isPropertyBlockedForAddonCancel(selectedPropertyId)) { 2894 selectedPropertyId = null; 2895 } 2896 2897 const selectableProps = propsLive.filter( 2898 (p) => !isPropertyBlockedForAddonCancel(p.id) 2899 ); 2900 2901 const summary = document.createElement("div"); 2902 summary.className = "ms-addon-picker-summary"; 2903 summary.innerHTML = ` 2904 <div class="ms-addon-picker-title">Choose a property to disable</div> 2905 <div class="ms-addon-picker-copy"> 2906 ${ 2907 endMs 2908 ? `This will take effect on <b>${esc(fmtDate(endMs))}</b>.` 2909 : `This will take effect at the end of the billing cycle.` 2910 } 2911 Choose the property that should be disabled when this extra slot expires. 2912 </div> 2913 `; 2914 propsListEl.appendChild(summary); 2915 2916 if (selectableProps.length === 0) { 2917 const warn = document.createElement("div"); 2918 warn.className = "ms-msg show err"; 2919 warn.textContent = 2920 "All available properties are already scheduled to be disabled by another add-on."; 2921 propsListEl.appendChild(warn); 2922 2923 selectedPropertyId = null; 2924 if (btnPickerConfirm) btnPickerConfirm.disabled = true; 2925 setPickerChromeForAddons(); 2926 return; 2927 } 2928 2929 const list = document.createElement("div"); 2930 list.className = "ms-options"; 2931 2932 propsLive.forEach((p) => { 2933 const blocked = isPropertyBlockedForAddonCancel(p.id); 2934 const on = selectedPropertyId === p.id && !blocked; 2935 2936 const row = document.createElement("button"); 2937 row.type = "button"; 2938 row.className = "ms-option ms-option-addon" + (on ? " on" : ""); 2939 row.disabled = blocked; 2940 2941 row.innerHTML = ` 2942 <div> 2943 <div class="t">${esc(p.name)}</div> 2944 <div class="m">${ 2945 blocked 2946 ? "This property is already scheduled to be disabled by another add-on." 2947 : on 2948 ? "This property will be disabled at the end of the cycle." 2949 : "Select this property for the scheduled cancellation." 2950 }</div> 2951 <div class="ms-addon-choice-meta"> 2952 <span class="ms-addon-choice-pill">Active property</span> 2953 ${ 2954 blocked 2955 ? `<span class="ms-addon-choice-pill warn">Already scheduled</span>` 2956 : on 2957 ? `<span class="ms-addon-choice-pill warn">Selected for cancel</span>` 2958 : `` 2959 } 2960 </div> 2961 </div> 2962 <div class="ms-option-addon-right"> 2963 <span class="ms-option-addon-check">${ 2964 blocked ? "Unavailable" : on ? "Selected" : "Select" 2965 }</span>
2966 <span class="dot" aria-hidden="true"></span> 2967 </div> 2968 `; 2969 2970 if (!blocked) { 2971 row.addEventListener("click", () => { 2972 selectedPropertyId = p.id; 2973 if (btnPickerConfirm) btnPickerConfirm.disabled = false; 2974 renderPropsPicker(endMs); 2975 setPickerChromeForAddons(); 2976 }); 2977 } 2978 2979 list.appendChild(row); 2980 }); 2981 2982 propsListEl.appendChild(list); 2983 2984 if (btnPickerConfirm) { 2985 btnPickerConfirm.disabled = !selectedPropertyId; 2986 } 2987 setPickerChromeForAddons(); 2988 } 2989 2990 function openPlanReductionModal({ planKey, allowed, activeProps, needToRemove }) { 2991 if (!addonsModal) return; 2992 2993 modalMode = "reduction"; 2994 reductionGuardState = { 2995 planKey, 2996 allowed, 2997 activeProps: (activeProps || []).filter(isPropertySelectableForReduction), 2998 needToRemove, 2999 }; 3000 reductionSelectedIds = new Set(); 3001 3002 if (addonsTitleEl) addonsTitleEl.textContent = "Plan reduction"; 3003 3004 if (addonsNoteEl) { 3005 addonsNoteEl.innerHTML = ""; 3006 addonsNoteEl.style.display = "none"; 3007 } 3008 3009 clearMsg("ms-addons-msg"); 3010 3011 if (addonsListEl) addonsListEl.style.display = "none"; 3012 if (pickerWrap) pickerWrap.style.display = ""; 3013 3014 addonsModal.style.display = "flex"; 3015 addonsModal.setAttribute("aria-hidden", "false"); 3016 3017 renderReductionPicker(); 3018 setPickerChromeForReduction(); 3019 } 3020 3021 if (btnSlotsManage) { 3022 btnSlotsManage.addEventListener("click", async () => { 3023 if (!auth.currentUser) return; 3024 3025 clearMsg("ms-slots-msg"); 3026 setBtnLoading(btnSlotsManage, true); 3027 await nextPaint(); 3028 3029 try { 3030 try { 3031 await fnReconcileAddonsAndProperties({}); 3032 } catch (_) {} 3033 try { 3034 await fnRefreshAddonsMirror({}); 3035 } catch (_) {} 3036 3037 openAddonsModal(); 3038 } catch (e) { 3039 showMsg( 3040 "ms-slots-msg", 3041 "Could not open add-ons manager: " + extractErr(e), 3042 "err" 3043 ); 3044 } finally { 3045 setBtnLoading(btnSlotsManage, false); 3046 } 3047 }); 3048 } 3049 3050 // ------------------------- 3051 // Add-ons modal 3052 // ------------------------- 3053 let unsubAddons = null; 3054 let unsubProps = null; 3055 let addonsLive = []; 3056 let propsLive = []; 3057 3058 let modalMode = "addons"; 3059 let managingAddonId = null; 3060 let selectedPropertyId = null; 3061 3062 let reductionGuardState = null; 3063 let reductionSelectedIds = new Set(); 3064 3065 function cleanupAddonListeners() { 3066 try { 3067 unsubAddons && unsubAddons(); 3068 } catch (_) {} 3069 try { 3070 unsubProps && unsubProps(); 3071 } catch (_) {} 3072 unsubAddons = null; 3073 unsubProps = null; 3074 addonsLive = []; 3075 propsLive = []; 3076 } 3077 3078 function closeAddonsModal() { 3079 if (!addonsModal) return; 3080 3081 addonsModal.style.display = "none"; 3082 addonsModal.setAttribute("aria-hidden", "true"); 3083 3084 modalMode = "addons"; 3085 managingAddonId = null; 3086 selectedPropertyId = null; 3087 resetReductionState(); 3088 3089 if (addonsNoteEl) addonsNoteEl.style.display = ""; 3090 if (pickerWrap) pickerWrap.style.display = "none"; 3091 if (addonsListEl) addonsListEl.style.display = ""; 3092 clearMsg("ms-addons-msg"); 3093 } 3094 3095 function startAddonListeners(uid) { 3096 cleanupAddonListeners(); 3097 3098 unsubAddons = db 3099 .collection("users") 3100 .doc(uid) 3101 .collection("addons") 3102 .onSnapshot((qs) => { 3103 const now = Date.now(); 3104 const list = []; 3105 qs.forEach((d) => { 3106 const x = d.data() || {}; 3107 const type = String(x.type || "").toLowerCase(); 3108 if (type !== "property_slot") return; 3109 3110 const cancelAtEnd = x.cancelAtEnd === true; 3111 const status = String(x.status || "").toLowerCase(); 3112 if (status === "revoked") return; 3113 3114 const exp = x.expiresAt?.toMillis ? x.expiresAt.toMillis() : 0; 3115 const active = exp > now; 3116 3117 if (!active && !cancelAtEnd) return; 3118 3119 const disableAt = x.disableAt?.toMillis ? x.disableAt.toMillis() : null; 3120 3121 list.push({ 3122 id: d.id, 3123 propertyId: x.propertyId || null, 3124 cancelAtEnd, 3125 disableAtMs: disableAt, 3126 expiresAtMs: exp, 3127 }); 3128 }); 3129 addonsLive = list; 3130 3131 if ( 3132 isAddonsModalOpen() && 3133 pickerWrap && 3134 pickerWrap.style.display === "none" 3135 ) { 3136 renderAddonsList(); 3137 } 3138 }); 3139 3140 unsubProps = db 3141 .collection("users") 3142 .doc(uid) 3143 .collection("properties") 3144 .onSnapshot((qs) => { 3145 const list = [];
3146 qs.forEach((d) => { 3147 const x = d.data() || {}; 3148 list.push({ 3149 id: d.id, 3150 name: x.name || d.id.slice(0, 6), 3151 disabled: x.disabled === true || x.isDisabled === true, 3152 archived: x.archived === true, 3153 active: x.active !== false, 3154 }); 3155 }); 3156 propsLive = list; 3157 3158 if ( 3159 isAddonsModalOpen() && 3160 pickerWrap && 3161 pickerWrap.style.display !== "none" 3162 ) { 3163 const a = addonsLive.find((x) => x.id === managingAddonId); 3164 const endMs = a ? a.disableAtMs || a.expiresAtMs || null : null; 3165 renderPropsPicker(endMs); 3166 } else if (isAddonsModalOpen()) { 3167 renderAddonsList(); 3168 } 3169 }); 3170 } 3171 3172 if (btnAddonsClose) btnAddonsClose.addEventListener("click", closeAddonsModal); 3173 if (addonsModal) 3174 addonsModal.addEventListener("click", (e) => { 3175 if (e.target === addonsModal) closeAddonsModal(); 3176 }); 3177 document.addEventListener("keydown", (e) => { 3178 if ( 3179 e.key === "Escape" && 3180 addonsModal && 3181 addonsModal.style.display !== "none" 3182 ) 3183 closeAddonsModal(); 3184 }); 3185 3186 if (btnPickerBack) { 3187 btnPickerBack.addEventListener("click", () => { 3188 clearMsg("ms-addons-msg"); 3189 3190 if (modalMode === "reduction") { 3191 closeAddonsModal(); 3192 return; 3193 } 3194 3195 managingAddonId = null; 3196 selectedPropertyId = null; 3197 3198 if (pickerWrap) pickerWrap.style.display = "none"; 3199 if (addonsListEl) addonsListEl.style.display = ""; 3200 3201 setPickerChromeForAddons(); 3202 renderAddonsList(); 3203 }); 3204 } 3205 3206 if (btnPickerConfirm) { 3207 btnPickerConfirm.addEventListener("click", async () => { 3208 clearMsg("ms-addons-msg"); 3209 setBtnLoading(btnPickerConfirm, true); 3210 await nextPaint(); 3211 3212 try { 3213 if (modalMode === "reduction") { 3214 if (!reductionGuardState) return; 3215 3216 const picked = Array.from(reductionSelectedIds); 3217 const needToRemove = reductionGuardState.needToRemove; 3218 3219 if (picked.length !== needToRemove) { 3220 showMsg( 3221 "ms-addons-msg", 3222 `You must select exactly ${needToRemove} ${ 3223 needToRemove === 1 ? "property" : "properties" 3224 } to continue.`, 3225 "err" 3226 ); 3227 return; 3228 } 3229 3230 showMsg("ms-addons-msg", "Saving reduction selectionâ¦", ""); 3231 3232 await fnSchedulePlanReductionWeb({ 3233 targetPlanKey: selectedPlanKey, 3234 propertyIds: picked, 3235 }); 3236 3237 showMsg("ms-addons-msg", "Opening Stripe Checkoutâ¦", ""); 3238 3239 localStorage.setItem("msCheckoutPending", "1"); 3240 localStorage.setItem("msCheckoutStartedAt", String(Date.now())); 3241 3242 const res = await fnCreateCheckoutSession({ 3243 planKey: selectedPlanKey, 3244 reductionPropertyIds: picked, 3245 }); 3246 3247 const url = res && res.data && res.data.url; 3248 if (!url) throw new Error("No checkout URL returned"); 3249 window.location.href = url; 3250 return; 3251 } 3252 3253 if (!managingAddonId || !selectedPropertyId) return; 3254 3255 showMsg("ms-addons-msg", "Scheduling cancellationâ¦", ""); 3256 await fnScheduleAddonCancelForProperty({ 3257 addonId: managingAddonId, 3258 propertyId: selectedPropertyId, 3259 }); 3260 3261 try { 3262 await fnReconcileAddonsAndProperties({}); 3263 } catch (_) {} 3264 try { 3265 await fnRefreshAddonsMirror({}); 3266 } catch (_) {} 3267 3268 await refreshAccess(); 3269 await refreshSlotsUI(); 3270 showMsg("ms-addons-msg", "Cancellation scheduled.", "ok"); 3271 3272 managingAddonId = null; 3273 selectedPropertyId = null; 3274 if (pickerWrap) pickerWrap.style.display = "none"; 3275 if (addonsListEl) addonsListEl.style.display = ""; 3276 setPickerChromeForAddons(); 3277 renderAddonsList(); 3278 } catch (e) { 3279 localStorage.removeItem("msCheckoutPending"); 3280 localStorage.removeItem("msCheckoutStartedAt"); 3281 showMsg("ms-addons-msg", "Could not continue: " + extractErr(e), "err"); 3282 } finally { 3283 setBtnLoading(btnPickerConfirm, false); 3284 } 3285 }); 3286 } 3287 3288 // ------------------------- 3289 // Unlock / Checkout 3290 // ------------------------- 3291 if (btnUnlock) { 3292 btnUnlock.addEventListener("click", async () => { 3293 clearMsg("ms-unlock-msg"); 3294 setBtnLoading(btnUnlock, true); 3295 await nextPaint(); 3296 3297 const code = String(el("ms-invite-code")?.value || "") 3298 .trim() 3299 .toUpperCase(); 3300 3301 if (!code) { 3302 setBtnLoading(btnUnlock, false); 3303 showMsg("ms-unlock-msg", "Enter an invite code.", "err"); 3304 return; 3305 } 3306 3307 try { 3308 const res = await fnRedeemSpecialAccessCode({ code }); 3309 const data = res && res.data ? res.data : null; 3310 if (!data || !data.planKey || !data.card) 3311 throw new Error("Invalid unlock response"); 3312 3313 specialUnlocked = { 3314 kind: data.kind, 3315 planKey: data.planKey, 3316 card: data.card, 3317 }; 3318 specialUnlockedCode = code; 3319 3320 selectedPlanKey = specialUnlocked.card.key; 3321 renderAllPlans(); 3322 showMsg("ms-unlock-msg", "Unlocked.", "ok"); 3323 } catch (e) { 3324 specialUnlocked = null; 3325 specialUnlockedCode = ""; 3326 renderAllPlans(); 3327 showMsg("ms-unlock-msg", "Unlock failed: " + extractErr(e), "err"); 3328 } finally { 3329 setBtnLoading(btnUnlock, false); 3330 } 3331 }); 3332 } 3333 3334 if (btnCheckout) { 3335 btnCheckout.addEventListener("click", async (ev) => { 3336 try { 3337 ev && ev.stopPropagation && ev.stopPropagation(); 3338 } catch (_) {} 3339 3340 clearMsg("ms-checkout-msg"); 3341 const isSpecialSelected = 3342 specialUnlocked && selectedPlanKey === specialUnlocked.card.key; 3343 3344 setBtnLoading(btnCheckout, true); 3345 await nextPaint(); 3346 3347 try { 3348 if (isSpecialSelected) { 3349 showMsg("ms-checkout-msg", "Activating special accessâ¦", ""); 3350 3351 const codeToUse = String(specialUnlockedCode || "") 3352 .trim() 3353 .toUpperCase(); 3354 if (!codeToUse) { 3355 throw new Error("Special access code is missing. Please unlock again."); 3356 } 3357 3358 if (specialUnlocked.kind === "influencer") { 3359 await fnStartInfluencerPurchase({ code: codeToUse }); 3360 } else if (specialUnlocked.kind === "owner") { 3361 await fnStartOwnerPurchase({ code: codeToUse }); 3362 } else { 3363 throw new Error("Unknown special kind"); 3364 } 3365 3366 await refreshAccess(); 3367 showMsg("ms-checkout-msg", "Special access activated.", "ok"); 3368 return; 3369 } 3370 3371 const u = auth.currentUser; 3372 3373 if (!u) { 3374 throw new Error("Please sign in again."); 3375 } 3376 3377 let readyData = await loadUserDoc(u.uid); 3378 lastUserData = getSafeAccountData(readyData); 3379 3380 if (!hasStripeCustomer(lastUserData)) { 3381 showMsg( 3382 "ms-checkout-msg", 3383 "Preparing your secure checkout. This can take a few secondsâ¦", 3384 "" 3385 ); 3386 3387 readyData = await waitForStripeCustomer(u.uid, { 3388 maxMs: 18000, 3389 intervalMs: 900, 3390 }); 3391 3392 lastUserData = getSafeAccountData(readyData); 3393 3394 if (!hasStripeCustomer(lastUserData)) { 3395 throw new Error( 3396 "Your account is still being prepared. Please wait a few seconds and try again." 3397 ); 3398 } 3399 } 3400 3401 const reductionGuard = getPlanReductionGuard(selectedPlanKey); 3402 3403 if (reductionGuard) { 3404 openPlanReductionModal(reductionGuard); 3405 setBtnLoading(btnCheckout, false); 3406 return; 3407 } 3408 3409 showMsg("ms-checkout-msg", "Opening Stripe Checkoutâ¦", ""); 3410 localStorage.setItem("msCheckoutPending", "1"); 3411 localStorage.setItem("msCheckoutStartedAt", String(Date.now())); 3412 3413 const useTrialEl = el("ms-use-trial"); 3414 const useTrial = useTrialEl ? useTrialEl.checked !== false : true; 3415 3416 const res = await fnCreateCheckoutSession({ 3417 planKey: selectedPlanKey, 3418 useTrial, 3419 }); 3420 3421 const url = res && res.data && res.data.url; 3422 if (!url) throw new Error("No checkout URL returned"); 3423 window.location.href = url; 3424 } catch (e) { 3425 localStorage.removeItem("msCheckoutPending"); 3426 localStorage.removeItem("msCheckoutStartedAt"); 3427 showMsg("ms-checkout-msg", "Checkout failed: " + extractErr(e), "err"); 3428 } finally { 3429 setBtnLoading(btnCheckout, false); 3430 } 3431 }); 3432 } 3433 3434 async function msOnReturnToAccountTab() {
3435 try { 3436 const pending = localStorage.getItem("msAddonPending") === "1"; 3437 if (!pending) return; 3438 if (!auth.currentUser) return; 3439 await refreshAccess(); 3440 try { 3441 await refreshSlotsUI(); 3442 } catch (_) {} 3443 } catch (_) {} 3444 } 3445 3446 document.addEventListener("visibilitychange", () => { 3447 if (document.visibilityState === "visible") msOnReturnToAccountTab(); 3448 }); 3449 window.addEventListener("focus", () => { 3450 msOnReturnToAccountTab(); 3451 }); 3452 window.addEventListener("pageshow", () => { 3453 msOnReturnToAccountTab(); 3454 }); 3455 3456 // Stripe return handling 3457 let returnHandled = false; 3458 3459 function cleanUrlParams() { 3460 const url = new URL(window.location.href); 3461 url.searchParams.delete("success"); 3462 url.searchParams.delete("canceled"); 3463 url.searchParams.delete("session_id"); 3464 url.searchParams.delete("portal_return"); 3465 window.history.replaceState({}, "", url.toString()); 3466 } 3467 3468 async function handleReturn() { 3469 if (returnHandled) return false; 3470 returnHandled = true; 3471 3472 const returnParams = new URLSearchParams(window.location.search); 3473 const success = returnParams.get("success"); 3474 const sessionId = returnParams.get("session_id"); 3475 const canceled = returnParams.get("canceled"); 3476 const portalReturn = returnParams.get("portal_return"); 3477 3478 if (portalReturn === "1") { 3479 showMsg("ms-checkout-msg", "Refreshing after billing updateâ¦", ""); 3480 3481 try { 3482 try { 3483 await fnReconcileAddonsAndProperties({}); 3484 } catch (_) {} 3485 try { 3486 await fnRefreshAddonsMirror({}); 3487 } catch (_) {} 3488 3489 await refreshAccess(); 3490 await refreshSlotsUI(); 3491 3492 showMsg("ms-checkout-msg", "Billing updated.", "ok"); 3493 return true; 3494 } catch (e) { 3495 showMsg("ms-checkout-msg", "Refresh failed: " + extractErr(e), "err"); 3496 return false; 3497 } finally { 3498 cleanUrlParams(); 3499 } 3500 } 3501 3502 const pending = localStorage.getItem("msCheckoutPending") === "1"; 3503 const startedAt = parseInt( 3504 localStorage.getItem("msCheckoutStartedAt") || "0", 3505 10 3506 ); 3507 const recent = startedAt > 0 && Date.now() - startedAt < 60 * 60 * 1000; 3508 3509 if (canceled === "1") { 3510 if (pending && recent) { 3511 showMsg("ms-checkout-msg", "Checkout canceled.", "err"); 3512 } 3513 3514 try { 3515 await fnClearPendingPlanReductionWeb({}); 3516 } catch (_) {} 3517 3518 localStorage.removeItem("msCheckoutPending"); 3519 localStorage.removeItem("msCheckoutStartedAt"); 3520 3521 cleanUrlParams(); 3522 return false; 3523 } 3524 3525 if (success === "1" && sessionId) { 3526 showMsg("ms-checkout-msg", "Finalizing your purchaseâ¦", ""); 3527 3528 try { 3529 await fnFinalizeCheckoutSession({ sessionId }); 3530 await refreshAccess(); 3531 3532 showMsg( 3533 "ms-checkout-msg", 3534 "Done. If you donât see updates in the app, reopen it and refresh.", 3535 "ok" 3536 ); 3537 return true; 3538 } catch (e) { 3539 showMsg("ms-checkout-msg", "Finalize failed: " + extractErr(e), "err"); 3540 return false; 3541 } finally { 3542 localStorage.removeItem("msCheckoutPending"); 3543 localStorage.removeItem("msCheckoutStartedAt"); 3544 cleanUrlParams(); 3545 } 3546 } 3547 3548 localStorage.removeItem("msCheckoutPending"); 3549 localStorage.removeItem("msCheckoutStartedAt"); 3550 3551 return false; 3552 } 3553 3554 // Auth state 3555 auth.onAuthStateChanged(async (user) => { 3556 if (!user) { 3557 stopAutoRefreshAccess(); 3558 3559 try { 3560 localStorage.removeItem("msAddonPending"); 3561 localStorage.removeItem("msAddonBaseline"); 3562 localStorage.removeItem("msAddonPendingAt"); 3563 } catch (_) {} 3564 3565 specialUnlocked = null; 3566 specialUnlockedCode = ""; 3567 lastUserData = null; 3568 3569 setSignedOutUI(); 3570 return; 3571 } 3572 3573 setSignedInUI(user); 3574 startAddonListeners(user.uid); 3575 3576 /* 3577 Important: 3578 Render a usable account UI immediately. 3579 Do not wait for Stripe sync / lifetime config before showing plans. 3580 */ 3581 try { 3582 const initialData = await loadUserDoc(user.uid); 3583 lastUserData = getSafeAccountData(initialData); 3584 3585 paintAccountFromUserData(lastUserData, { refreshBilling: false }); 3586 revealAccountAfterAccessLoaded(); 3587 } catch (_) { 3588 forceRevealPendingActivationUI("initial-user-doc-failed"); 3589 } 3590 3591 try { 3592 await loadLifetimePromoFromBackend(); 3593 renderAllPlans(); 3594 } catch (_) {} 3595 3596 let returnAlreadyRefreshed = false;
3597 3598 try { 3599 returnAlreadyRefreshed = await handleReturn(); 3600 } catch (e) { 3601 showMsg( 3602 "ms-checkout-msg", 3603 "Could not check Stripe return yet. You can choose a plan while we finish checking.", 3604 "" 3605 ); 3606 } 3607 3608 if (!returnAlreadyRefreshed) { 3609 try { 3610 await refreshAccess(); 3611 } catch (e) { 3612 showMsg( 3613 "ms-checkout-msg", 3614 "Access check is taking longer than usual. You can choose a plan now.", 3615 "" 3616 ); 3617 3618 forceRevealPendingActivationUI("refresh-access-failed"); 3619 } 3620 } 3621 3622 try { 3623 const pending = localStorage.getItem("msAddonPending") === "1"; 3624 if (pending) { 3625 startAutoRefreshAccess({ everyMs: 30000, maxMinutes: 8 }); 3626 } 3627 } catch (_) {} 3628}); 3629 })().catch((e) => { 3630 console.error("[ms-account] fatal:", e); 3631 showMsg("ms-guest-msg", "Fatal error: " + extractErr(e), "err"); 3632 }); 3633})();</script>
3633<script data-optimized="1" id="wp-hooks-js" src="https://mystashhq.com/wp-content/litespeed/js/ccfe8a7a0126bd6262843fa528dcf694.js?ver=fb46e"></script>
3633
3633<script data-optimized="1" id="wp-i18n-js" src="https://mystashhq.com/wp-content/litespeed/js/04dfd186cf8cc88d38cae80205954a55.js?ver=382d1"></script>
3633
3633<script data-optimized="1" id="wp-i18n-js-after">wp.i18n.setLocaleData({'text direction\u0004ltr':['ltr']})</script>
3633
3633<script data-optimized="1" id="underscore-js" src="https://mystashhq.com/wp-content/litespeed/js/6544cd99fb4fd8ec34cc234af65cf1e6.js?ver=ac7e0"></script>
3633
3633<script data-optimized="1" id="wp-util-js-extra">var _wpUtilSettings={"ajax":{"url":"/wp-admin/admin-ajax.php"}}</script>
3633
3633<script data-optimized="1" id="wp-util-js" src="https://mystashhq.com/wp-content/litespeed/js/44603c37535c98ea20d62c49f4b66494.js?ver=8f8c0"></script>
3633
3633<script data-optimized="1" id="dracula-frontend-js-extra">var dracula={"homeUrl":"https://mystashhq.com","adminUrl":"https://mystashhq.com/wp-admin/","ajaxUrl":"https://mystashhq.com/wp-admin/admin-ajax.php","pluginUrl":"https://mystashhq.com/wp-content/plugins/dracula-dark-mode","settings":{"frontendDarkMode":!0,"toggleStyle":2,"showToggle":!0},"isPro":"","nonce":"5c1f43969f","switches":{"1":"\u003Cdiv class=\"toggle-icon-wrap dracula-ignore\"\u003E \u003Cdiv class=\"toggle-icon __dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"toggle-icon __light\"\u003E\u003C/div\u003E \u003C/div\u003E","2":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"dracula-toggle-label\"\u003E \u003Cspan class=\"--light\"\u003ELight\u003C/span\u003E \u003Cspan class=\"--dark\"\u003EDark\u003C/span\u003E \u003C/div\u003E","3":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","4":"\u003Cdiv class=\"prefix-icon\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"suffix-icon\"\u003E\u003C/div\u003E","5":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E","6":"\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E","7":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","8":"\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","9":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","10":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","11":"\u003Cdiv class=\"toggle-prefix\"\u003ELight\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-suffix\"\u003EDark\u003C/div\u003E","12":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","13":"\u003Cspan class=\"toggle-prefix-icon\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-prefix-text\"\u003EDark Mode\u003C/span\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","14":"\u003Cspan class=\"dracula-toggle-icon\"\u003E\u003C/span\u003E \u003Cdiv class=\"toggle-modal dracula-ignore\"\u003E \u003Cdiv class=\"toggle-modal-content\"\u003E \u003Cdiv class=\"toggle-option light\"\u003E \u003Cspan class=\"toggle-option-icon --light\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003ELight Mode\u003C/span\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-option dark\"\u003E \u003Cspan class=\"toggle-option-icon --dark\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003EDark Mode\u003C/span\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-option auto\"\u003E \u003Cspan class=\"toggle-option-icon --auto\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003ESystem Mode\u003C/span\u003E \u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-modal-arrow\"\u003E\u003C/div\u003E \u003C/div\u003E","15":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\u003C/div\u003E","16":"\u003Cspan class=\"toggle-prefix-icon\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-prefix-text dracula-toggle-text\"\u003ELight Mode\u003C/span\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","17":"\u003Cbutton class=\"dracula-toggle-icon --typography\"\u003E\u003C/button\u003E \u003Cbutton class=\"dracula-toggle-icon --light\"\u003E\u003C/button\u003E","18":"\u003Cbutton type=\"button\" class=\"dracula-toggle-icon --light\"\u003E\u003C/button\u003E \u003Cbutton type=\"button\" class=\"dracula-toggle-icon --typography\"\u003E\u003C/button\u003E"},"customSwitches":{"1":"\u003Cdiv class=\"toggle-icon-wrap\"\u003E\n\t\t\t\t\u003Cspan class=\"toggle-icon __dark\"\u003E\u003C/span\u003E\n\t\t\t\t\u003Cspan class=\"toggle-icon __light\"\u003E\u003C/span\u003E\n\t\t\t\u003C/div\u003E","2":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon position-before\"\u003E\u003C/div\u003E\n\t\t\t\u003Cdiv class=\"dracula-toggle-label\"\u003E\n \u003Cspan class=\"--light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"--dark\"\u003E\u003C/span\u003E\n \u003C/div\u003E\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon position-after\"\u003E\u003C/div\u003E\n\t\t","3":"\n\t\t\t\u003Cdiv class=\"toggle-prefix\"\u003E\u003C/div\u003E\n \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n \u003Cdiv class=\"toggle-suffix\"\u003E\u003C/div\u003E\n\t\t","4":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n\n \u003Cdiv class=\"dracula-toggle-label\"\u003E\n \u003Cspan class=\"--light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"--dark\"\u003E\u003C/span\u003E\n \u003C/div\u003E\n\t\t","5":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n\n \u003Cspan class=\"dracula-toggle-label --light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"dracula-toggle-label --dark\"\u003E\u003C/span\u003E\n\t\t"},"presets":[{"key":"default","label":"Default","colors":{"bg":"#181a1b","text":"#e8e6e3","secondary_bg":"#202324","link":"#6ea5d9","link_hover":"#88b9e3","btn_bg":"#3b6f99","btn_text":"#dcdcdc","btn_text_hover":"#f0f0f0","btn_hover_bg":"#325d80","input_text":"#e8e6e3","input_bg":"#1f2223","input_placeholder":"#8c8c8c","border":"#2d2d2d"}},{"key":"dracula","label":"Dracula","colors":{"bg":"#282b36","text":"#e8e6e3","secondary_bg":"#343746","link":"#9a87cc","link_hover":"#b79ce2","btn_bg":"#5a6288","btn_text":"#dedede","btn_text_hover":"#f0f0f0","btn_hover_bg":"#4b5274","input_text":"#e8e6e3","input_bg":"#3a3c4e","input_placeholder":"#8b8b9c","border":"#45475a"}},{"key":"catppuccin","label":"Catppuccin","isPro":!0,"colors":{"bg":"#161320","text":"#d9e0ee","secondary_bg":"#1e1a2e","link":"#b69ad8","link_hover":"#c5b0e1","btn_bg":"#8a74b8","btn_text":"#d9e0ee","btn_text_hover":"#ffffff","btn_hover_bg":"#7a66a3","input_text":"#d9e0ee","input_bg":"#1e1a2e","input_placeholder":"#8e89a3","border":"#2a2438"}},{"key":"gruvbox","label":"Gruvbox","isPro":!0,"colors":{"bg":"#282828","text":"#ebdbb2","secondary_bg":"#32302f","link":"#d4a73c","link_hover":"#e0b252","btn_bg":"#a97e2c","btn_text":"#ebdbb2","btn_text_hover":"#ffffff","btn_hover_bg":"#8f6a25","input_text":"#ebdbb2","input_bg":"#32302f","input_placeholder":"#a89984","border":"#504945"}},{"key":"nord","label":"Nord","isPro":!0,"colors":{"bg":"#2e3440","text":"#eceff4","secondary_bg":"#3b4252","link":"#88c0d0","link_hover":"#a3d1dc","btn_bg":"#5e81ac","btn_text":"#eceff4","btn_text_hover":"#ffffff","btn_hover_bg":"#4c6a92","input_text":"#eceff4","input_bg":"#434c5e","input_placeholder":"#9aa0a6","border":"#4c566a"}},{"key":"rosePine","label":"Rose Pine","isPro":!0,"colors":{"bg":"#191724","text":"#e0def4","secondary_bg":"#1f1d2e","link":"#d2879d","link_hover":"#e2a3b7","btn_bg":"#6d879c","btn_text":"#e0def4","btn_text_hover":"#ffffff","btn_hover_bg":"#5a6f81","input_text":"#e0def4","input_bg":"#26233a","input_placeholder":"#908caa","border":"#524f67"}},{"key":"solarized","label":"Solarized","isPro":!0,"colors":{"bg":"#002b36","text":"#93a1a1","secondary_bg":"#073642","link":"#6aa6a6","link_hover":"#82bcbc","btn_bg":"#2f5f66","btn_text":"#cfe3e3","btn_text_hover":"#e6f0f0","btn_hover_bg":"#2a5359","input_text":"#a7b6b6","input_bg":"#0d3944","input_placeholder":"#6f8383","border":"#0f3a44"}},{"key":"tokyoNight","label":"Tokyo Night","colors":{"bg":"#1a1b26","text":"#a9b1d6","secondary_bg":"#1f2230","link":"#7aa2f7","link_hover":"#8fb5ff","btn_bg":"#3b4a7a","btn_text":"#cfd6f2","btn_text_hover":"#ffffff","btn_hover_bg":"#323f68","input_text":"#b7bfe1","input_bg":"#212335","input_placeholder":"#7c85a9","border":"#2a2e42"}},{"key":"monokai","label":"Monokai","colors":{"bg":"#272822","text":"#f8f8f2","secondary_bg":"#2f302a","link":"#8fc66a","link_hover":"#a1d57a","btn_bg":"#5b6e4a","btn_text":"#e6f1dd","btn_text_hover":"#ffffff","btn_hover_bg":"#4d5e3f","input_text":"#efeede","input_bg":"#303126","input_placeholder":"#9aa08f","border":"#3a3b33"}},{"key":"ayuMirage","label":"Ayu Mirage","colors":{"bg":"#1f2430","text":"#cbccc6","secondary_bg":"#252b39","link":"#9ccfd8","link_hover":"#b7e0e6","btn_bg":"#5f7890","btn_text":"#dfe2e0","btn_text_hover":"#ffffff","btn_hover_bg":"#50677d","input_text":"#d5d6d0","input_bg":"#262d3b","input_placeholder":"#8d94a1","border":"#2c3443"}},{"key":"ayuDark","label":"Ayu Dark","colors":{"bg":"#0a0e14","text":"#b3b1ad","secondary_bg":"#121721","link":"#5aa7c8","link_hover":"#72b8d5","btn_bg":"#3a6075","btn_text":"#cfd6da","btn_text_hover":"#e7eef2","btn_hover_bg":"#314f61","input_text":"#c2c0bc","input_bg":"#121722","input_placeholder":"#808693","border":"#1b2230"}},{"key":"material","label":"Material","colors":{"bg":"#263238","text":"#eceff1","secondary_bg":"#2e3b41","link":"#82b1ff","link_hover":"#9bbfff","btn_bg":"#546e7a","btn_text":"#e6eff3","btn_text_hover":"#ffffff","btn_hover_bg":"#465c65","input_text":"#e4eaee","input_bg":"#2b3940","input_placeholder":"#9aaab1","border":"#31434a"}},{"key":"oneDark","label":"One Dark","colors":{"bg":"#282c34","text":"#abb2bf","secondary_bg":"#2f3440","link":"#6fb4f0","link_hover":"#89c2f4","btn_bg":"#3d5872","btn_text":"#cfd6e2","btn_text_hover":"#eaf1fb","btn_hover_bg":"#334a60","input_text":"#b9c0cd","input_bg":"#2c303a","input_placeholder":"#8a909c","border":"#3a3f4a"}},{"key":"oceanicNext","label":"Oceanic Next","colors":{"bg":"#1B2B34","text":"#CDD3DE","secondary_bg":"#203340","link":"#5fb3b3","link_hover":"#77c4c4","btn_bg":"#3f6d6d","btn_text":"#d8e4e4","btn_text_hover":"#f0f7f7","btn_hover_bg":"#355c5c","input_text":"#d2d8e1","input_bg":"#223746","input_placeholder":"#8ca1ad","border":"#2a4050"}},{"key":"cityLights","label":"City Lights","colors":{"bg":"#1d252c","text":"#b6bfc4","secondary_bg":"#232c34","link":"#76a8d9","link_hover":"#8bb9e3","btn_bg":"#3e5f7a","btn_text":"#d4dde2","btn_text_hover":"#f0f6fb","btn_hover_bg":"#344f66","input_text":"#c2cbd0","input_bg":"#232c34","input_placeholder":"#8b97a0","border":"#2a343e"}},{"key":"nightOwl","label":"Night Owl","colors":{"bg":"#011627","text":"#d6deeb","secondary_bg":"#071d33","link":"#82aaff","link_hover":"#9bb6ff","btn_bg":"#425b8a","btn_text":"#e4ecfa","btn_text_hover":"#ffffff","btn_hover_bg":"#394f78","input_text":"#dbe3f0","input_bg":"#0a1f36","input_placeholder":"#8aa0be","border":"#0f2740"}},{"key":"youtube","label":"YouTube","colors":{"bg":"#181818","text":"#ffffff","secondary_bg":"#202020","link":"#e05a5a","link_hover":"#ff6b6b","btn_bg":"#8a2b2b","btn_text":"#f2f2f2","btn_text_hover":"#ffffff","btn_hover_bg":"#722424","input_text":"#f0f0f0","input_bg":"#222222","input_placeholder":"#9a9a9a","border":"#2a2a2a"}},{"key":"twitter","label":"Twitter","colors":{"bg":"#15202b","text":"#ffffff","secondary_bg":"#1b2733","link":"#69b3ff","link_hover":"#8cc6ff","btn_bg":"#3a6fa1","btn_text":"#e8f3ff","btn_text_hover":"#ffffff","btn_hover_bg":"#325f8a","input_text":"#eef6ff","input_bg":"#1e2a36","input_placeholder":"#8ea5bd","border":"#263544"}},{"key":"reddit","label":"Reddit (Night mode)","colors":{"bg":"#1a1a1b","text":"#d7dadc","secondary_bg":"#202021","link":"#ff9566","link_hover":"#ffb187","btn_bg":"#7a4a2e","btn_text":"#efd9cf","btn_text_hover":"#ffffff","btn_hover_bg":"#693f27","input_text":"#e3e6e8","input_bg":"#222223","input_placeholder":"#9aa0a3","border":"#2a2a2b"}},{"key":"discord","label":"Discord","colors":{"bg":"#36393f","text":"#dcddde","secondary_bg":"#3c4047","link":"#8ea1e1","link_hover":"#a5b3ea","btn_bg":"#4957d6","btn_text":"#e7e9ff","btn_text_hover":"#ffffff","btn_hover_bg":"#3f4bc0","input_text":"#e3e4e6","input_bg":"#40444b","input_placeholder":"#9aa1ae","border":"#454a52"}},{"key":"slack","label":"Slack","colors":{"bg":"#1d1c1d","text":"#e7e7e7","secondary_bg":"#232223","link":"#cf8fb6","link_hover":"#dda6c5","btn_bg":"#6b5a6e","btn_text":"#efe3ef","btn_text_hover":"#ffffff","btn_hover_bg":"#5b4d5d","input_text":"#ededed","input_bg":"#242324","input_placeholder":"#9a969b","border":"#2a292a"}},{"key":"whatsapp","label":"WhatsApp","colors":{"bg":"#121212","text":"#e6e5e4","secondary_bg":"#161616","link":"#67b97a","link_hover":"#7acc8d","btn_bg":"#2f6b3e","btn_text":"#d8f0df","btn_text_hover":"#f2fff6","btn_hover_bg":"#285b35","input_text":"#ecebe9","input_bg":"#1a1a1a","input_placeholder":"#8d8d8d","border":"#222222"}},{"key":"github","label":"GitHub","colors":{"bg":"#0d1117","text":"#c9d1d9","secondary_bg":"#11161e","link":"#6aa6ff","link_hover":"#8abaff","btn_bg":"#2f3a4a","btn_text":"#d8e2ec","btn_text_hover":"#ffffff","btn_hover_bg":"#26303d","input_text":"#d3dbe2","input_bg":"#0f1420","input_placeholder":"#8894a1","border":"#1a2230"}},{"key":"stackoverflow","label":"StackOverflow","colors":{"bg":"#2d2d2d","text":"#f2f2f2","secondary_bg":"#333333","link":"#ffa654","link_hover":"#ffbb7a","btn_bg":"#7a4e1f","btn_text":"#fdeedd","btn_text_hover":"#ffffff","btn_hover_bg":"#683f18","input_text":"#f0f0f0","input_bg":"#353535","input_placeholder":"#9a9a9a","border":"#3c3c3c"}}]};var dracula={"homeUrl":"https://mystashhq.com","adminUrl":"https://mystashhq.com/wp-admin/","ajaxUrl":"https://mystashhq.com/wp-admin/admin-ajax.php","pluginUrl":"https://mystashhq.com/wp-content/plugins/dracula-dark-mode","settings":{"frontendDarkMode":!0,"toggleStyle":2,"showToggle":!0},"isPro":"","nonce":"5c1f43969f","switches":{"1":"\u003Cdiv class=\"toggle-icon-wrap dracula-ignore\"\u003E \u003Cdiv class=\"toggle-icon __dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"toggle-icon __light\"\u003E\u003C/div\u003E \u003C/div\u003E","2":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"dracula-toggle-label\"\u003E \u003Cspan class=\"--light\"\u003ELight\u003C/span\u003E \u003Cspan class=\"--dark\"\u003EDark\u003C/span\u003E \u003C/div\u003E","3":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","4":"\u003Cdiv class=\"prefix-icon\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"suffix-icon\"\u003E\u003C/div\u003E","5":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E","6":"\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E","7":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","8":"\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","9":"\u
3633003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","10":"\u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","11":"\u003Cdiv class=\"toggle-prefix\"\u003ELight\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon \"\u003E\u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-suffix\"\u003EDark\u003C/div\u003E","12":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap \"\u003E\u003C/div\u003E","13":"\u003Cspan class=\"toggle-prefix-icon\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-prefix-text\"\u003EDark Mode\u003C/span\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","14":"\u003Cspan class=\"dracula-toggle-icon\"\u003E\u003C/span\u003E \u003Cdiv class=\"toggle-modal dracula-ignore\"\u003E \u003Cdiv class=\"toggle-modal-content\"\u003E \u003Cdiv class=\"toggle-option light\"\u003E \u003Cspan class=\"toggle-option-icon --light\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003ELight Mode\u003C/span\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-option dark\"\u003E \u003Cspan class=\"toggle-option-icon --dark\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003EDark Mode\u003C/span\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-option auto\"\u003E \u003Cspan class=\"toggle-option-icon --auto\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-option-label\"\u003ESystem Mode\u003C/span\u003E \u003C/div\u003E \u003C/div\u003E \u003Cdiv class=\"toggle-modal-arrow\"\u003E\u003C/div\u003E \u003C/div\u003E","15":"\u003Cdiv class=\"dracula-toggle-icon --light\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon --dark\"\u003E\u003C/div\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\u003C/div\u003E","16":"\u003Cspan class=\"toggle-prefix-icon\"\u003E\u003C/span\u003E \u003Cspan class=\"toggle-prefix-text dracula-toggle-text\"\u003ELight Mode\u003C/span\u003E \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E \u003C/div\u003E","17":"\u003Cbutton class=\"dracula-toggle-icon --typography\"\u003E\u003C/button\u003E \u003Cbutton class=\"dracula-toggle-icon --light\"\u003E\u003C/button\u003E","18":"\u003Cbutton type=\"button\" class=\"dracula-toggle-icon --light\"\u003E\u003C/button\u003E \u003Cbutton type=\"button\" class=\"dracula-toggle-icon --typography\"\u003E\u003C/button\u003E"},"customSwitches":{"1":"\u003Cdiv class=\"toggle-icon-wrap\"\u003E\n\t\t\t\t\u003Cspan class=\"toggle-icon __dark\"\u003E\u003C/span\u003E\n\t\t\t\t\u003Cspan class=\"toggle-icon __light\"\u003E\u003C/span\u003E\n\t\t\t\u003C/div\u003E","2":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon position-before\"\u003E\u003C/div\u003E\n\t\t\t\u003Cdiv class=\"dracula-toggle-label\"\u003E\n \u003Cspan class=\"--light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"--dark\"\u003E\u003C/span\u003E\n \u003C/div\u003E\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon position-after\"\u003E\u003C/div\u003E\n\t\t","3":"\n\t\t\t\u003Cdiv class=\"toggle-prefix\"\u003E\u003C/div\u003E\n \u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n \u003Cdiv class=\"toggle-suffix\"\u003E\u003C/div\u003E\n\t\t","4":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n\n \u003Cdiv class=\"dracula-toggle-label\"\u003E\n \u003Cspan class=\"--light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"--dark\"\u003E\u003C/span\u003E\n \u003C/div\u003E\n\t\t","5":"\n\t\t\t\u003Cdiv class=\"dracula-toggle-icon-wrap\"\u003E\n \u003Cdiv class=\"dracula-toggle-icon\"\u003E\u003C/div\u003E\n \u003C/div\u003E\n\n \u003Cspan class=\"dracula-toggle-label --light\"\u003E\u003C/span\u003E\n \u003Cspan class=\"dracula-toggle-label --dark\"\u003E\u003C/span\u003E\n\t\t"},"presets":[{"key":"default","label":"Default","colors":{"bg":"#181a1b","text":"#e8e6e3","secondary_bg":"#202324","link":"#6ea5d9","link_hover":"#88b9e3","btn_bg":"#3b6f99","btn_text":"#dcdcdc","btn_text_hover":"#f0f0f0","btn_hover_bg":"#325d80","input_text":"#e8e6e3","input_bg":"#1f2223","input_placeholder":"#8c8c8c","border":"#2d2d2d"}},{"key":"dracula","label":"Dracula","colors":{"bg":"#282b36","text":"#e8e6e3","secondary_bg":"#343746","link":"#9a87cc","link_hover":"#b79ce2","btn_bg":"#5a6288","btn_text":"#dedede","btn_text_hover":"#f0f0f0","btn_hover_bg":"#4b5274","input_text":"#e8e6e3","input_bg":"#3a3c4e","input_placeholder":"#8b8b9c","border":"#45475a"}},{"key":"catppuccin","label":"Catppuccin","isPro":!0,"colors":{"bg":"#161320","text":"#d9e0ee","secondary_bg":"#1e1a2e","link":"#b69ad8","link_hover":"#c5b0e1","btn_bg":"#8a74b8","btn_text":"#d9e0ee","btn_text_hover":"#ffffff","btn_hover_bg":"#7a66a3","input_text":"#d9e0ee","input_bg":"#1e1a2e","input_placeholder":"#8e89a3","border":"#2a2438"}},{"key":"gruvbox","label":"Gruvbox","isPro":!0,"colors":{"bg":"#282828","text":"#ebdbb2","secondary_bg":"#32302f","link":"#d4a73c","link_hover":"#e0b252","btn_bg":"#a97e2c","btn_text":"#ebdbb2","btn_text_hover":"#ffffff","btn_hover_bg":"#8f6a25","input_text":"#ebdbb2","input_bg":"#32302f","input_placeholder":"#a89984","border":"#504945"}},{"key":"nord","label":"Nord","isPro":!0,"colors":{"bg":"#2e3440","text":"#eceff4","secondary_bg":"#3b4252","link":"#88c0d0","link_hover":"#a3d1dc","btn_bg":"#5e81ac","btn_text":"#eceff4","btn_text_hover":"#ffffff","btn_hover_bg":"#4c6a92","input_text":"#eceff4","input_bg":"#434c5e","input_placeholder":"#9aa0a6","border":"#4c566a"}},{"key":"rosePine","label":"Rose Pine","isPro":!0,"colors":{"bg":"#191724","text":"#e0def4","secondary_bg":"#1f1d2e","link":"#d2879d","link_hover":"#e2a3b7","btn_bg":"#6d879c","btn_text":"#e0def4","btn_text_hover":"#ffffff","btn_hover_bg":"#5a6f81","input_text":"#e0def4","input_bg":"#26233a","input_placeholder":"#908caa","border":"#524f67"}},{"key":"solarized","label":"Solarized","isPro":!0,"colors":{"bg":"#002b36","text":"#93a1a1","secondary_bg":"#073642","link":"#6aa6a6","link_hover":"#82bcbc","btn_bg":"#2f5f66","btn_text":"#cfe3e3","btn_text_hover":"#e6f0f0","btn_hover_bg":"#2a5359","input_text":"#a7b6b6","input_bg":"#0d3944","input_placeholder":"#6f8383","border":"#0f3a44"}},{"key":"tokyoNight","label":"Tokyo Night","colors":{"bg":"#1a1b26","text":"#a9b1d6","secondary_bg":"#1f2230","link":"#7aa2f7","link_hover":"#8fb5ff","btn_bg":"#3b4a7a","btn_text":"#cfd6f2","btn_text_hover":"#ffffff","btn_hover_bg":"#323f68","input_text":"#b7bfe1","input_bg":"#212335","input_placeholder":"#7c85a9","border":"#2a2e42"}},{"key":"monokai","label":"Monokai","colors":{"bg":"#272822","text":"#f8f8f2","secondary_bg":"#2f302a","link":"#8fc66a","link_hover":"#a1d57a","btn_bg":"#5b6e4a","btn_text":"#e6f1dd","btn_text_hover":"#ffffff","btn_hover_bg":"#4d5e3f","input_text":"#efeede","input_bg":"#303126","input_placeholder":"#9aa08f","border":"#3a3b33"}},{"key":"ayuMirage","label":"Ayu Mirage","colors":{"bg":"#1f2430","text":"#cbccc6","secondary_bg":"#252b39","link":"#9ccfd8","link_hover":"#b7e0e6","btn_bg":"#5f7890","btn_text":"#dfe2e0","btn_text_hover":"#ffffff","btn_hover_bg":"#50677d","input_text":"#d5d6d0","input_bg":"#262d3b","input_placeholder":"#8d94a1","border":"#2c3443"}},{"key":"ayuDark","label":"Ayu Dark","colors":{"bg":"#0a0e14","text":"#b3b1ad","secondary_bg":"#121721","link":"#5aa7c8","link_hover":"#72b8d5","btn_bg":"#3a6075","btn_text":"#cfd6da","btn_text_hover":"#e7eef2","btn_hover_bg":"#314f61","input_text":"#c2c0bc","input_bg":"#121722","input_placeholder":"#808693","border":"#1b2230"}},{"key":"material","label":"Material","colors":{"bg":"#263238","text":"#eceff1","secondary_bg":"#2e3b41","link":"#82b1ff","link_hover":"#9bbfff","btn_bg":"#546e7a","btn_text":"#e6eff3","btn_text_hover":"#ffffff","btn_hover_bg":"#465c65","input_text":"#e4eaee","input_bg":"#2b3940","input_placeholder":"#9aaab1","border":"#31434a"}},{"key":"oneDark","label":"One Dark","colors":{"bg":"#282c34","text":"#abb2bf","secondary_bg":"#2f3440","link":"#6fb4f0","link_hover":"#89c2f4","btn_bg":"#3d5872","btn_text":"#cfd6e2","btn_text_hover":"#eaf1fb","btn_hover_bg":"#334a60","input_text":"#b9c0cd","input_bg":"#2c303a","input_placeholder":"#8a909c","border":"#3a3f4a"}},{"key":"oceanicNext","label":"Oceanic Next","colors":{"bg":"#1B2B34","text":"#CDD3DE","secondary_bg":"#203340","link":"#5fb3b3","link_hover":"#77c4c4","btn_bg":"#3f6d6d","btn_text":"#d8e4e4","btn_text_hover":"#f0f7f7","btn_hover_bg":"#355c5c","input_text":"#d2d8e1","input_bg":"#223746","input_placeholder":"#8ca1ad","border":"#2a4050"}},{"key":"cityLights","label":"City Lights","colors":{"bg":"#1d252c","text":"#b6bfc4","secondary_bg":"#232c34","link":"#76a8d9","link_hover":"#8bb9e3","btn_bg":"#3e5f7a","btn_text":"#d4dde2","btn_text_hover":"#f0f6fb","btn_hover_bg":"#344f66","input_text":"#c2cbd0","input_bg":"#232c34","input_placeholder":"#8b97a0","border":"#2a343e"}},{"key":"nightOwl","label":"Night Owl","colors":{"bg":"#011627","text":"#d6deeb","secondary_bg":"#071d33","link":"#82aaff","link_hover":"#9bb6ff","btn_bg":"#425b8a","btn_text":"#e4ecfa","btn_text_hover":"#ffffff","btn_hover_bg":"#394f78","input_text":"#dbe3f0","input_bg":"#0a1f36","input_placeholder":"#8aa0be","border":"#0f2740"}},{"key":"youtube","label":"YouTube","colors":{"bg":"#181818","text":"#ffffff","secondary_bg":"#202020","link":"#e05a5a","link_hover":"#ff6b6b","btn_bg":"#8a2b2b","btn_text":"#f2f2f2","btn_text_hover":"#ffffff","btn_hover_bg":"#722424","input_text":"#f0f0f0","input_bg":"#222222","input_placeholder":"#9a9a9a","border":"#2a2a2a"}},{"key":"twitter","label":"Twitter","colors":{"bg":"#15202b","text":"#ffffff","secondary_bg":"#1b2733","link":"#69b3ff","link_hover":"#8cc6ff","btn_bg":"#3a6fa1","btn_text":"#e8f3ff","btn_text_hover":"#ffffff","btn_hover_bg":"#325f8a","input_text":"#eef6ff","input_bg":"#1e2a36","input_placeholder":"#8ea5bd","border":"#263544"}},{"key":"reddit","label":"Reddit (Night mode)","colors":{"bg":"#1a1a1b","text":"#d7dadc","secondary_bg":"#202021","link":"#ff9566","link_hover":"#ffb187","btn_bg":"#7a4a2e","btn_text":"#efd9cf","btn_text_hover":"#ffffff","btn_hover_bg":"#693f27","input_text":"#e3e6e8","input_bg":"#222223","input_placeholder":"#9aa0a3","border":"#2a2a2b"}},{"key":"discord","label":"Discord","colors":{"bg":"#36393f","text":"#dcddde","secondary_bg":"#3c4047","link":"#8ea1e1","link_hover":"#a5b3ea","btn_bg":"#4957d6","btn_text":"#e7e9ff","btn_text_hover":"#ffffff","btn_hover_bg":"#3f4bc0","input_text":"#e3e4e6","input_bg":"#40444b","input_placeholder":"#9aa1ae","border":"#454a52"}},{"key":"slack","label":"Slack","colors":{"bg":"#1d1c1d","text":"#e7e7e7","secondary_bg":"#232223","link":"#cf8fb6","link_hover":"#dda6c5","btn_bg":"#6b5a6e","btn_text":"#efe3ef","btn_text_hover":"#ffffff","btn_hover_bg":"#5b4d5d","input_text":"#ededed","input_bg":"#242324","input_placeholder":"#9a969b","border":"#2a292a"}},{"key":"whatsapp","label":"WhatsApp","colors":{"bg":"#121212","text":"#e6e5e4","secondary_bg":"#161616","link":"#67b97a","link_hover":"#7acc8d","btn_bg":"#2f6b3e","btn_text":"#d8f0df","btn_text_hover":"#f2fff6","btn_hover_bg":"#285b35","input_text":"#ecebe9","input_bg":"#1a1a1a","input_placeholder":"#8d8d8d","border":"#222222"}},{"key":"github","label":"GitHub","colors":{"bg":"#0d1117","text":"#c9d1d9","secondary_bg":"#11161e","link":"#6aa6ff","link_hover":"#8abaff","btn_bg":"#2f3a4a","btn_text":"#d8e2ec","btn_text_hover":"#ffffff","btn_hover_bg":"#26303d","input_text":"#d3dbe2","input_bg":"#0f1420","input_placeholder":"#8894a1","border":"#1a2230"}},{"key":"stackoverflow","label":"StackOverflow","colors":{"bg":"#2d2d2d","text":"#f2f2f2","secondary_bg":"#333333","link":"#ffa654","link_hover":"#ffbb7a","btn_bg":"#7a4e1f","btn_text":"#fdeedd","btn_text_hover":"#ffffff","btn_hover_bg":"#683f18","input_text":"#f0f0f0","input_bg":"#353535","input_placeholder":"#9a9a9a","border":"#3c3c3c"}}]}</script>
3633
3633<script data-optimized="1" id="dracula-frontend-js" src="https://mystashhq.com/wp-content/litespeed/js/6a30b63a093885a212506452c0204114.js?ver=b1839"></script>
3633
3633<script data-optimized="1" id="swv-js" src="https://mystashhq.com/wp-content/litespeed/js/5082bd076f41b8532e5756a22972433a.js?ver=ca771"></script>
3633
3633<script data-optimized="1" id="contact-form-7-js-before">var wpcf7={"api":{"root":"https:\/\/mystashhq.com\/wp-json\/","namespace":"contact-form-7\/v1"},"cached":1}</script>
3633
3633<script data-optimized="1" id="contact-form-7-js" src="https://mystashhq.com/wp-content/litespeed/js/ef28ef60474e8226d0dc64f875d11d45.js?ver=33680"></script>
3633
3633<script data-optimized="1" id="generate-menu-js-before">var generatepressMenu={"toggleOpenedSubMenus":!0,"openSubMenuLabel":"Open Sub-Menu","closeSubMenuLabel":"Close Sub-Menu"}</script>
3633
3633<script data-optimized="1" id="generate-menu-js" src="https://mystashhq.com/wp-content/litespeed/js/0f67f5d28ee55b8a46480584e1ad3209.js?ver=2f6ec"></script>
3633
3633<script data-optimized="1" id="elementor-webpack-runtime-js" src="https://mystashhq.com/wp-content/litespeed/js/2589256ae89457728fd3d1321445fee5.js?ver=bc815"></script>
3633
3633<script data-optimized="1" id="elementor-frontend-modules-js" src="https://mystashhq.com/wp-content/litespeed/js/1e8f826087789eb8051b974fe8aa3b9f.js?ver=30a70"></script>
3633
3633<script data-optimized="1" id="jquery-ui-core-js-before">jQuery.uiBackCompat=!0</script>
3633
3633<script data-optimized="1" id="jquery-ui-core-js" src="https://mystashhq.com/wp-content/litespeed/js/da6f6d3fc93193bea6022396e47cc87f.js?ver=afcbc"></script>
3633
3633<script data-optimized="1" id="elementor-frontend-js-before">var elementorFrontendConfig={"environmentMode":{"edit":!1,"wpPreview":!1,"isScriptDebug":!1},"i18n":{"shareOnFacebook":"Share on Facebook","shareOnX":"Share on X","pinIt":"Pin it","download":"Download","downloadImage":"Download image","fullscreen":"Fullscreen","zoom":"Zoom","share":"Share","playVideo":"Play Video","previous":"Previous","next":"Next","close":"Close","a11yCarouselPrevSlideMessage":"Previous slide","a11yCarouselNextSlideMessage":"Next slide","a11yCarouselFirstSlideMessage":"This is the first slide","a11yCarouselLastSlideMessage":"This is the last slide","a11yCarouselPaginationBulletMessage":"Go to slide"},"is_rtl":!1,"breakpoints":{"xs":0,"sm":480,"md":768,"lg":1025,"xl":1440,"xxl":1600},"responsive":{"breakpoints":{"mobile":{"label":"Mobile Portrait","value":767,"default_value":767,"direction":"max","is_enabled":!0},"mobile_extra":{"label":"Mobile Landscape","value":880,"default_value":880,"direction":"max","is_enabled":!1},"tablet":{"label":"Tablet Portrait","value":1024,"default_value":1024,"direction":"max","is_enabled":!0},"tablet_extra":{"label":"Tablet Landscape","value":1200,"default_value":1200,"direction":"max","is_enabled":!1},"laptop":{"label":"Laptop","value":1366,"default_value":1366,"direction":"max","is_enabled":!1},"widescreen":{"label":"Widescreen","value":2400,"default_value":2400,"direction":"min","is_enabled":!1}},"hasCustomBreakpoints":!1},"version":"4.2.4","is_static":!1,"experimentalFeatures":{"e_font_icon_svg":!0,"additional_custom_breakpoints":!0,"container":!0,"e_panel_promotions":!0,"nested-elements":!0,"global_classes_should_enforce_capabilities":!0,"e_variables":!0,"e_opt_in_v4_page":!0,"e_components":!0,"e_interactions":!0,"e_widget_creation":!0,"import-export-customization":!0},"urls":{"assets":"https:\/\/mystashhq.com\/wp-content\/plugins\/elementor\/assets\/","ajaxurl":"https:\/\/mystashhq.com\/wp-admin\/admin-ajax.php","uploadUrl":"https:\/\/mystashhq.com\/wp-content\/uploads"},"nonces":{"floatingButtonsClickTracking":"fd27130bc2","atomicFormsSendForm":"b98bdd2900"},"swiperClass":"swiper","settings":{"page":[],"editorPreferences":[]},"kit":{"active_breakpoints":["viewport_mobile","viewport_tablet"],"global_image_lightbox":"yes","lightbox_enable_counter":"yes","lightbox_enable_fullscreen":"yes","lightbox_enable_zoom":"yes","lightbox_enable_share":"yes","lightbox_title_src":"title","lightbox_description_src":"description"},"post":{"id":1578,"title":"About%20Us%20-%20MyStash%20AI","excerpt":"","featuredImage":!1}}</script>
3633
3633<script data-optimized="1" id="elementor-frontend-js" src="https://mystashhq.com/wp-content/litespeed/js/26faf183695af6191788708204ccc64b.js?ver=cee5c"></script>
3633
3633<script data-optimized="1" id="googlesitekit-events-provider-contact-form-7-js" src="https://mystashhq.com/wp-content/litespeed/js/d0a4148cca58fac0d05247e87f70d306.js?ver=0d306" defer></script>
3633
3633<script data-optimized="1" id="googlesitekit-events-provider-content-events-js-before">window._googlesitekit=window._googlesitekit||{};window._googlesitekit.contentEvents={"postID":1578,"isSinglePost":!1,"hasVimeoEmbed":!1}</script>
3633
3633<script data-optimized="1" id="googlesitekit-events-provider-content-events-js" src="https://mystashhq.com/wp-content/litespeed/js/f1ef12a3ca082a60e27d7e157c203598.js?ver=03598" defer></script>
3633
3633<script data-optimized="1" id="mystash-risk-numeric-fix-js-after">(function(){var selectors=['input[name="yearBuilt"]','input[name="size"]','input[name="marketValue"]'];function isTarget(el){if(!el||!el.matches)return!1;return selectors.some(function(sel){return el.matches(sel)})} 3634function normalizeField(el){if(!el)return;try{el.setAttribute('type','text')}catch(e){} 3635el.setAttribute('inputmode','numeric');el.setAttribute('pattern','[0-9]*');el.setAttribute('maxlength','10');el.removeAttribute('min');el.removeAttribute('max');el.removeAttribute('step');el.value=String(el.value||'').replace(/\D+/g,'').slice(0,10)} 3636function normalizeAll(root){selectors.forEach(function(sel){(root||document).querySelectorAll(sel).forEach(normalizeField)})} 3637document.addEventListener('DOMContentLoaded',function(){normalizeAll(document)});document.addEventListener('focusin',function(e){if(isTarget(e.target))normalizeField(e.target);});document.addEventListener('input',function(e){if(isTarget(e.target)){e.target.value=String(e.target.value||'').replace(/\D+/g,'').slice(0,10)}});document.addEventListener('paste',function(e){if(isTarget(e.target)){setTimeout(function(){e.target.value=String(e.target.value||'').replace(/\D+/g,'').slice(0,10)},0)}})})()</script>
3637
3637<script data-optimized="1" id="smush-lazy-load-js-before">var smushLazyLoadOptions={"autoResizingEnabled":!1,"autoResizeOptions":{"precision":5,"skipAutoWidth":!0,"cdnBaseURL":""}}</script>
3637
3637<script data-optimized="1" id="smush-lazy-load-js" src="https://mystashhq.com/wp-content/litespeed/js/6be138caffd915e2141ab138774eb6f2.js?ver=d657f"></script>
3637
3637<script data-optimized="1" id="mystash-risk-calculator-ajax-js-after">window.MYSTASH_RISK_AJAX_URL="https:\/\/mystashhq.com\/wp-admin\/admin-ajax.php";(function(){if(window.__MYSTASH_RISK_CALCULATOR_AJAX__)return;window.__MYSTASH_RISK_CALCULATOR_AJAX__=!0;var lastEstimate=null;function byId(id){return document.getElementById(id)} 3638function getValue(id){var el=byId(id);return el?String(el.value||"").trim():""} 3639function setText(id,value){var el=byId(id);if(el)el.textContent=value} 3640function setMsg(message,isError){var el=byId("risk-lead-msg");if(!el)return;el.textContent=message||"";el.style.marginTop=message?"8px":"0";el.style.fontSize="13px";el.style.fontWeight="700";el.style.color=isError?"#b91c1c":"#166534"} 3641function currencyForCountry(country){country=String(country||"US").toUpperCase();if(country==="CA")return"CAD";if(country==="MX")return"MXN";return"USD"} 3642function formatMoney(amount,country){var currency=currencyForCountry(country);var n=Number(amount||0);try{return new Intl.NumberFormat("en-US",{style:"currency",currency:currency,maximumFractionDigits:0}).format(n)}catch(e){return"$"+Math.round(n).toLocaleString("en-US")+" "+currency}} 3643function postAjax(data){return fetch(window.MYSTASH_RISK_AJAX_URL,{method:"POST",credentials:"same-origin",headers:{"Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},body:new URLSearchParams(data).toString()}).then(function(res){return res.json()})} 3644function bindEstimateForm(){var form=byId("risk-calculator-form");if(!form)return;form.setAttribute("action","javascript:void(0);");form.setAttribute("novalidate","novalidate");form.addEventListener("submit",function(event){event.preventDefault();event.stopPropagation();var country=getValue("country")||"US";var zip=getValue("zip");var btn=form.querySelector('button[type="submit"]');if(!zip){setMsg("Please enter your ZIP / postal code.",!0);return} 3645if(btn){btn.disabled=!0;btn.textContent="Checking..."} 3646setMsg("",!1);postAjax({action:"mystash_calculator_estimate",country:country,zip:zip,propertyType:getValue("propertyType"),size:getValue("size"),yearBuilt:getValue("yearBuilt"),marketValue:getValue("marketValue")}).then(function(json){if(!json||!json.success||!json.data){throw new Error(json&&json.data&&json.data.message?json.data.message:"Could not calculate your estimate. Please try again.")} 3647var data=json.data;lastEstimate={country:country,zip:zip,propertyType:getValue("propertyType"),size:getValue("size"),yearBuilt:getValue("yearBuilt"),marketValue:getValue("marketValue"),riskScoreLine:data.riskScoreLine||"",replacement:Number(data.replacement||0),avgCoverage:Number(data.avgCoverage||0),gap:Number(data.gap||0)};setText("risk-score-text",lastEstimate.riskScoreLine||"â");setText("replacement-cost-text",formatMoney(lastEstimate.replacement,country));setText("avg-coverage-text",formatMoney(lastEstimate.avgCoverage,country));setText("gap-amount-text",formatMoney(lastEstimate.gap,country));setMsg("Risk estimate generated. Enter your email to receive the full report.",!1)}).catch(function(err){setMsg(err&&err.message?err.message:"Something went wrong. Please try again.",!0)}).finally(function(){if(btn){btn.disabled=!1;btn.textContent="Check my risk"}})})} 3648function bindLeadForm(){var form=byId("calculator-lead-form");if(!form)return;form.addEventListener("submit",function(event){event.preventDefault();event.stopPropagation();var email=getValue("leadEmail");var btn=form.querySelector('button[type="submit"]');if(!email||email.indexOf("@")===-1){setMsg("Please enter a valid email address.",!0);return} 3649if(!lastEstimate){setMsg("Please click âCheck my riskâ first so we can generate your estimate before sending the full report.",!0);return!1} 3650if(btn){btn.disabled=!0;btn.textContent="Sending..."} 3651postAjax({action:"mystash_calculator_lead",email:email,country:lastEstimate.country,zip:lastEstimate.zip,propertyType:lastEstimate.propertyType,size:lastEstimate.size,yearBuilt:lastEstimate.yearBuilt,marketValue:lastEstimate.marketValue,riskScoreLine:lastEstimate.riskScoreLine,replacement:String(lastEstimate.replacement),avgCoverage:String(lastEstimate.avgCoverage),gap:String(lastEstimate.gap)}).then(function(json){if(!json||!json.success){throw new Error(json&&json.data&&json.data.message?json.data.message:"Could not send the report. Please try again.")} 3652setMsg(json.data&&json.data.message?json.data.message:"Done! Check your inbox.",!1)}).catch(function(err){setMsg(err&&err.message?err.message:"Something went wrong. Please try again.",!0)}).finally(function(){if(btn){btn.disabled=!1;btn.textContent="Send me the full report"}})})} 3653document.addEventListener("DOMContentLoaded",function(){bindEstimateForm();bindLeadForm()})})()</script>
3653
3653<script id="wp-emoji-settings" type="application/json">{"baseUrl":"https://s.w.org/images/core/emoji/17.0.2/72x72/","ext":".png","svgUrl":"https://s.w.org/images/core/emoji/17.0.2/svg/","svgExt":".svg","source":{"concatemoji":"https://mystashhq.com/wp-includes/js/wp-emoji-release.min.js?ver=7.1.1"}}</script>
3653
3653<script type="module">/*! This file is auto-generated */ 3654var e="script#wp-emoji-settings",t=document.querySelector(e);if(!(t instanceof HTMLScriptElement))throw new Error("Element missing: "+e);const r=JSON.parse(t.text),s=(window._wpemojiSettings=r,"wpEmojiSettingsSupports"),o=["flag","emoji"];function i(e){try{var t={supportTests:e,timestamp:(new Date).valueOf()};sessionStorage.setItem(s,JSON.stringify(t))}catch(e){}}function c(e,t,n){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);t=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(n,0,0);const r=new Uint32Array(e.getImageData(0,0,e.canvas.width,e.canvas.height).data);return t.every((e,t)=>e===r[t])}function p(e,t){e.clearRect(0,0,e.canvas.width,e.canvas.height),e.fillText(t,0,0);var n=e.getImageData(16,16,1,1);for(let e=0;e<n.data.length;e++)if(0!==n.data[e])return!1;return!0}function u(e,t,n,r){switch(t){case"flag":return n(e,"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f","\ud83c\udff3\ufe0f\u200b\u26a7\ufe0f")?!1:!n(e,"\ud83c\udde8\ud83c\uddf6","\ud83c\udde8\u200b\ud83c\uddf6")&&!n(e,"\ud83c\udff4\udb40\udc67\udb40\udc62\udb40\udc65\udb40\udc6e\udb40\udc67\udb40\udc7f","\ud83c\udff4\u200b\udb40\udc67\u200b\udb40\udc62\u200b\udb40\udc65\u200b\udb40\udc6e\u200b\udb40\udc67\u200b\udb40\udc7f");case"emoji":return!r(e,"\ud83e\u1fac8")}return!1}function f(e,t,n,r){let a;const s=(a="undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?new OffscreenCanvas(300,150):document.createElement("canvas")).getContext("2d",{willReadFrequently:!0}),o=(s.textBaseline="top",s.font="600 32px Arial",{});return e.forEach(e=>{o[e]=t(s,e,n,r)}),o}function a(e){var t=document.createElement("script");t.src=e,t.defer=!0,document.head.appendChild(t)}r.supports={everything:!0,everythingExceptFlag:!0},new Promise(t=>{let n=function(){try{var e=JSON.parse(sessionStorage.getItem(s));if("object"==typeof e&&"number"==typeof e.timestamp&&(new Date).valueOf()<e.timestamp+604800&&"object"==typeof e.supportTests)return e.supportTests}catch(e){}return null}();if(!n){if("undefined"!=typeof Worker&&"undefined"!=typeof OffscreenCanvas&&"undefined"!=typeof URL&&URL.createObjectURL&&"undefined"!=typeof Blob)try{var e="postMessage("+f.toString()+"("+[JSON.stringify(o),u.toString(),c.toString(),p.toString()].join(",")+"));",r=new Blob([e],{type:"text/javascript"});const a=new Worker(URL.createObjectURL(r),{name:"wpTestEmojiSupports"});return void(a.onmessage=e=>{i(n=e.data),a.terminate(),t(n)})}catch(e){}i(n=f(o,u,c,p))}t(n)}).then(e=>{for(const n in e)r.supports[n]=e[n],r.supports.everything=r.supports.everything&&r.supports[n],"flag"!==n&&(r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&r.supports[n]);var t;r.supports.everythingExceptFlag=r.supports.everythingExceptFlag&&!r.supports.flag,r.supports.everything||((t=r.source||{}).concatemoji?a(t.concatemoji):t.wpemoji&&t.twemoji&&(a(t.twemoji),a(t.wpemoji)))}); 3655//# sourceURL=https://mystashhq.com/wp-includes/js/wp-emoji-loader.min.js</script>
3655
3655<script>document.addEventListener("DOMContentLoaded",function(){const header=document.querySelector(".msa-header");const toggle=document.querySelector(".msa-menu-toggle");const mobileMenu=document.querySelector(".msa-mobile-menu");const enButton=document.querySelector(".msa-language-en");const frButton=document.querySelector(".msa-language-fr");function getActiveLanguage(){const path=window.location.pathname.toLowerCase();if(path==="/fr"||path==="/fr/"||path.startsWith("/fr/")){return"fr"} 3656const htmlLang=(document.documentElement.getAttribute("lang")||"").toLowerCase();if(htmlLang.startsWith("fr")){return"fr"} 3657return"en"} 3658function updateLanguageToggle(){const language=getActiveLanguage();if(enButton){const active=language==="en";enButton.classList.toggle("is-current",active);enButton.setAttribute("aria-pressed",active?"true":"false")} 3659if(frButton){const active=language==="fr";frButton.classList.toggle("is-current",active);frButton.setAttribute("aria-pressed",active?"true":"false")}} 3660updateLanguageToggle();document.querySelectorAll(".msa-language-option").forEach(function(button){button.addEventListener("click",function(event){event.preventDefault();event.stopPropagation();const targetUrl=button.getAttribute("data-language-url");const language=button.getAttribute("data-language");if(!targetUrl){console.error("MyStash language URL missing.");return} 3661if(enButton){enButton.classList.toggle("is-current",language==="en");enButton.setAttribute("aria-pressed",language==="en"?"true":"false")} 3662if(frButton){frButton.classList.toggle("is-current",language==="fr");frButton.setAttribute("aria-pressed",language==="fr"?"true":"false")} 3663window.location.assign(targetUrl)})});const languageObserver=new MutationObserver(function(){updateLanguageToggle()});languageObserver.observe(document.documentElement,{attributes:!0,attributeFilter:["lang"]});window.setTimeout(updateLanguageToggle,250);window.setTimeout(updateLanguageToggle,750);window.setTimeout(updateLanguageToggle,1500);if(toggle&&mobileMenu){toggle.addEventListener("click",function(){const isOpen=mobileMenu.classList.toggle("is-open");toggle.setAttribute("aria-expanded",isOpen?"true":"false")});mobileMenu.addEventListener("click",function(event){if(!event.target.closest("a")){return} 3664mobileMenu.classList.remove("is-open");toggle.setAttribute("aria-expanded","false")})} 3665window.addEventListener("scroll",function(){if(!header){return} 3666header.classList.toggle("is-scrolled",window.scrollY>10)});if(header){header.classList.toggle("is-scrolled",window.scrollY>10)}})</script>
3666 <aside data-wg-notranslate="" class="country-selector weglot-dropdown close_outside_click closed weglot-default wg-" tabindex="0" aria-expanded="false" aria-label="Language selected: English"><input id="wg6ab530ac8827f3.767013521790259372799" class="weglot_choice" type="checkbox" name="menu"/><label data-l="en" tabindex="-1" for="wg6ab530ac8827f3.767013521790259372799" class="wgcurrent wg-li weglot-lang weglot-language flag-0 wg-en" data-code-language="wg-en" data-name-language="EN"><span class="wglanguage-name">EN</span></label><ul role="none"><li data-l="fr" class="wg-li weglot-lang weglot-language flag-0 wg-fr" data-code-language="fr" role="option"><a title="Language switcher : French" class="weglot-language-fr" role="option" data-wg-notranslate="" href="https://mystashhq.com/fr/about/">FR</a></li></ul></aside></body></html> 3667<!-- Page optimized by LiteSpeed Cache @2026-09-24 09:16:13 --> 3668 3669<!-- Page cached by LiteSpeed Cache 7.9.1 on 2026-09-24 09:16:12 -->
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.