1<!doctype html> 2 3<html lang="en" dir="ltr"> 4 <head> 5 <meta charset="utf-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0, height=device-height, minimum-scale=1.0, maximum-scale=5.0, viewport-fit=cover"> 7 <meta name="apple-mobile-web-app-capable" content="yes"> 8 <meta name="apple-mobile-web-app-status-bar-style" content="default"> 9 <meta name="theme-color" content="#ffffff"><title> 10 Your Shopping Cart 11 </title><link rel="canonical" href="https://atlasruggallery.com/cart"><link rel="preconnect" href="https://fonts.shopifycdn.com" crossorigin><link rel="preload" href="//atlasruggallery.com/cdn/fonts/quicksand/quicksand_n4.bf8322a9d1da765aa396ad7b6eeb81930a6214de.woff2" as="font" type="font/woff2" crossorigin><link rel="preload" href="//atlasruggallery.com/cdn/fonts/nunito/nunito_n4.fc49103dc396b42cae9460289072d384b6c6eb63.woff2" as="font" type="font/woff2" crossorigin><meta property="og:type" content="website"> 12 <meta property="og:title" content="Your Shopping Cart"><meta property="og:url" content="https://atlasruggallery.com/cart"> 13<meta property="og:site_name" content="AtlasRugGallery"><meta name="twitter:card" content="summary"><meta name="twitter:title" content="Your Shopping Cart"> 14 <meta name="twitter:description" content="Your Shopping Cart">
14<script type="application/ld+json"> 15 { 16 "@context": "https://schema.org", 17 "@type": "BreadcrumbList", 18 "itemListElement": [{ 19 "@type": "ListItem", 20 "position": 1, 21 "name": "Home", 22 "item": "https://atlasruggallery.com" 23 }] 24 } 25</script>
25<style>/* Typography (heading) */ 26 @font-face { 27 font-family: Quicksand; 28 font-weight: 400; 29 font-style: normal; 30 font-display: fallback; 31 src: url("//atlasruggallery.com/cdn/fonts/quicksand/quicksand_n4.bf8322a9d1da765aa396ad7b6eeb81930a6214de.woff2") format("woff2"), 32 url("//atlasruggallery.com/cdn/fonts/quicksand/quicksand_n4.fa4cbd232d3483059e72b11f7239959a64c98426.woff") format("woff"); 33} 34 35/* Typography (body) */ 36 @font-face { 37 font-family: Nunito; 38 font-weight: 400; 39 font-style: normal; 40 font-display: fallback; 41 src: url("//atlasruggallery.com/cdn/fonts/nunito/nunito_n4.fc49103dc396b42cae9460289072d384b6c6eb63.woff2") format("woff2"), 42 url("//atlasruggallery.com/cdn/fonts/nunito/nunito_n4.5d26d13beeac3116db2479e64986cdeea4c8fbdd.woff") format("woff"); 43} 44 45@font-face { 46 font-family: Nunito; 47 font-weight: 400; 48 font-style: italic; 49 font-display: fallback; 50 src: url("//atlasruggallery.com/cdn/fonts/nunito/nunito_i4.fd53bf99043ab6c570187ed42d1b49192135de96.woff2") format("woff2"), 51 url("//atlasruggallery.com/cdn/fonts/nunito/nunito_i4.cb3876a003a73aaae5363bb3e3e99d45ec598cc6.woff") format("woff"); 52} 53 54@font-face { 55 font-family: Nunito; 56 font-weight: 700; 57 font-style: normal; 58 font-display: fallback; 59 src: url("//atlasruggallery.com/cdn/fonts/nunito/nunito_n7.37cf9b8cf43b3322f7e6e13ad2aad62ab5dc9109.woff2") format("woff2"), 60 url("//atlasruggallery.com/cdn/fonts/nunito/nunito_n7.45cfcfadc6630011252d54d5f5a2c7c98f60d5de.woff") format("woff"); 61} 62 63@font-face { 64 font-family: Nunito; 65 font-weight: 700; 66 font-style: italic; 67 font-display: fallback; 68 src: url("//atlasruggallery.com/cdn/fonts/nunito/nunito_i7.3f8ba2027bc9ceb1b1764ecab15bae73f86c4632.woff2") format("woff2"), 69 url("//atlasruggallery.com/cdn/fonts/nunito/nunito_i7.82bfb5f86ec77ada3c9f660da22064c2e46e1469.woff") format("woff"); 70} 71 72:root { 73 /* Container */ 74 --container-max-width: 100%; 75 --container-xxs-max-width: 27.5rem; /* 440px */ 76 --container-xs-max-width: 42.5rem; /* 680px */ 77 --container-sm-max-width: 61.25rem; /* 980px */ 78 --container-md-max-width: 71.875rem; /* 1150px */ 79 --container-lg-max-width: 78.75rem; /* 1260px */ 80 --container-xl-max-width: 85rem; /* 1360px */ 81 --container-gutter: 1.25rem; 82 83 --section-vertical-spacing: 2.5rem; 84 --section-vertical-spacing-tight:2.5rem; 85 86 --section-stack-gap:2.25rem; 87 --section-stack-gap-tight:2.25rem; 88 89 /* Form settings */ 90 --form-gap: 1.25rem; /* Gap between fieldset and submit button */ 91 --fieldset-gap: 1rem; /* Gap between each form input within a fieldset */ 92 --form-control-gap: 0.625rem; /* Gap between input and label (ignored for floating label) */ 93 --checkbox-control-gap: 0.75rem; /* Horizontal gap between checkbox and its associated label */ 94 --input-padding-block: 0.65rem; /* Vertical padding for input, textarea and native select */ 95 --input-padding-inline: 0.8rem; /* Horizontal padding for input, textarea and native select */ 96 --checkbox-size: 0.875rem; /* Size (width and height) for checkbox */ 97 98 /* Other sizes */ 99 --sticky-area-height: calc(var(--announcement-bar-is-sticky, 0) * var(--announcement-bar-height, 0px) + var(--header-is-sticky, 0) * var(--header-is-visible, 1) * var(--header-height, 0px)); 100 101 /* RTL support */ 102 --transform-logical-flip: 1; 103 --transform-origin-start: left; 104 --transform-origin-end: right; 105 106 /** 107 * --------------------------------------------------------------------- 108 * TYPOGRAPHY 109 * --------------------------------------------------------------------- 110 */ 111 112 /* Font properties */ 113 --heading-font-family: Quicksand, sans-serif; 114 --heading-font-weight: 400; 115 --heading-font-style: normal; 116 --heading-text-transform: uppercase; 117 --heading-letter-spacing: 0.18em; 118 --text-font-family: Nunito, sans-serif; 119 --text-font-weight: 400; 120 --text-font-style: normal; 121 --text-letter-spacing: 0.0em; 122 --button-font: var(--text-font-style) var(--text-font-weight) var(--text-sm) / 1.65 var(--text-font-family); 123 --button-text-transform: uppercase; 124 --button-letter-spacing: 0.18em; 125 126 /* Font sizes */--text-heading-size-factor: 1; 127 --text-h1: max(0.6875rem, clamp(1.375rem, 1.146341463414634rem + 0.975609756097561vw, 2rem) * var(--text-heading-size-factor)); 128 --text-h2: max(0.6875rem, clamp(1.25rem, 1.0670731707317074rem + 0.7804878048780488vw, 1.75rem) * var(--text-heading-size-factor)); 129 --text-h3: max(0.6875rem, clamp(1.125rem, 1.0335365853658536rem + 0.3902439024390244vw, 1.375rem) * var(--text-heading-size-factor)); 130 --text-h4: max(0.6875rem, clamp(1rem, 0.9542682926829268rem + 0.1951219512195122vw, 1.125rem) * var(--text-heading-size-factor)); 131 --text-h5: calc(0.875rem * var(--text-heading-size-factor)); 132 --text-h6: calc(0.75rem * var(--text-heading-size-factor)); 133 134 --text-xs: 0.75rem; 135 --text-sm: 0.8125rem; 136 --text-base: 0.875rem; 137 --text-lg: 1.0rem; 138 --text-xl: 1.125rem; 139 140 /* Rounded variables (used for border radius) */ 141 --rounded-full: 9999px; 142 --button-border-radius: 0.0rem; 143 --input-border-radius: 0.0rem; 144 145 /* Box shadow */ 146 --shadow-sm: 0 2px 8px rgb(0 0 0 / 0.05); 147 --shadow: 0 5px 15px rgb(0 0 0 / 0.05); 148 --shadow-md: 0 5px 30px rgb(0 0 0 / 0.05); 149 --shadow-block: px px px rgb(var(--text-primary) / 0.0); 150 151 /* Product card */--product-card-text-transform: uppercase;/** 152 * --------------------------------------------------------------------- 153 * OTHER 154 * --------------------------------------------------------------------- 155 */ 156 157 --checkmark-svg-url: url(//atlasruggallery.com/cdn/shop/t/47/assets/checkmark.svg?v=5588600397216680941787370159); 158 --cursor-zoom-in-svg-url: url(//atlasruggallery.com/cdn/shop/t/47/assets/cursor-zoom-in.svg?v=26022421335126260971787370159); 159 } 160 161 [dir="rtl"]:root { 162 /* RTL support */ 163 --transform-logical-flip: -1; 164 --transform-origin-start: right;
165 --transform-origin-end: left; 166 } 167 168 @media screen and (min-width: 700px) { 169 :root { 170 /* Typography (font size) */ 171 --text-xs: 0.75rem; 172 --text-sm: 0.8125rem; 173 --text-base: 0.875rem; 174 --text-lg: 1.0rem; 175 --text-xl: 1.25rem; 176 177 /* Spacing settings */ 178 --container-gutter: 2rem; 179 } 180 } 181 182 @media screen and (min-width: 1000px) { 183 :root { 184 /* Spacing settings */ 185 --container-gutter: 3rem; 186 187 --section-vertical-spacing: 4rem; 188 --section-vertical-spacing-tight: 4rem; 189 190 --section-stack-gap:3rem; 191 --section-stack-gap-tight:3rem; 192 } 193 }:root {/* Overlay used for modal */ 194 --page-overlay: 0 0 0 / 0.4; 195 196 /* We use the first scheme background as default */ 197 --page-background: ; 198 199 /* Product colors */ 200 --on-sale-text: 227 44 43; 201 --on-sale-badge-background: 227 44 43; 202 --on-sale-badge-text: 255 255 255; 203 --sold-out-badge-background: 239 239 239; 204 --sold-out-badge-text: 0 0 0 / 0.65; 205 --custom-badge-background: 28 28 28; 206 --custom-badge-text: 255 255 255; 207 --star-color: 28 28 28; 208 209 /* Status colors */ 210 --success-background: 212 227 203; 211 --success-text: 48 122 7; 212 --warning-background: 253 241 224; 213 --warning-text: 237 138 0; 214 --error-background: 243 204 204; 215 --error-text: 203 43 43; 216 217 /* Modal scheme */ 218 --modal-scheme-background: 255 255 255; 219 --modal-scheme-background-gradient: ; 220 --modal-scheme-text-color: 28 28 28; 221 }.color-scheme--scheme-1 { 222 /* Color settings */--accent: 28 28 28; 223 --text-color: 28 28 28; 224 --background: 239 239 239 / 1.0; 225 --background-without-opacity: 239 239 239; 226 --background-gradient: ;--border-color: 207 207 207;/* Button colors */ 227 --button-background: 28 28 28; 228 --button-text-color: 255 255 255; 229 230 /* Circled buttons */ 231 --circle-button-background: 255 255 255; 232 --circle-button-text-color: 28 28 28; 233 }.shopify-section:has(.section-spacing.color-scheme--bg-609ecfcfee2f667ac6c12366fc6ece56) + .shopify-section:has(.section-spacing.color-scheme--bg-609ecfcfee2f667ac6c12366fc6ece56:not(.bordered-section)) .section-spacing { 234 padding-block-start: 0; 235 }.color-scheme--scheme-2 { 236 /* Color settings */--accent: 28 28 28; 237 --text-color: 28 28 28; 238 --background: 255 255 255 / 1.0; 239 --background-without-opacity: 255 255 255; 240 --background-gradient: ;--border-color: 221 221 221;/* Button colors */ 241 --button-background: 28 28 28; 242 --button-text-color: 255 255 255; 243 244 /* Circled buttons */ 245 --circle-button-background: 255 255 255; 246 --circle-button-text-color: 28 28 28; 247 }.shopify-section:has(.section-spacing.color-scheme--bg-54922f2e920ba8346f6dc0fba343d673) + .shopify-section:has(.section-spacing.color-scheme--bg-54922f2e920ba8346f6dc0fba343d673:not(.bordered-section)) .section-spacing { 248 padding-block-start: 0; 249 }.color-scheme--scheme-3 { 250 /* Color settings */--accent: 255 255 255; 251 --text-color: 255 255 255; 252 --background: 28 28 28 / 1.0; 253 --background-without-opacity: 28 28 28; 254 --background-gradient: ;--border-color: 62 62 62;/* Button colors */ 255 --button-background: 255 255 255; 256 --button-text-color: 28 28 28; 257 258 /* Circled buttons */ 259 --circle-button-background: 255 255 255; 260 --circle-button-text-color: 28 28 28; 261 }.shopify-section:has(.section-spacing.color-scheme--bg-c1f8cb21047e4797e94d0969dc5d1e44) + .shopify-section:has(.section-spacing.color-scheme--bg-c1f8cb21047e4797e94d0969dc5d1e44:not(.bordered-section)) .section-spacing { 262 padding-block-start: 0; 263 }.color-scheme--scheme-4 { 264 /* Color settings */--accent: 255 255 255; 265 --text-color: 255 255 255; 266 --background: 0 0 0 / 0.0; 267 --background-without-opacity: 0 0 0; 268 --background-gradient: ;--border-color: 255 255 255;/* Button colors */ 269 --button-background: 255 255 255; 270 --button-text-color: 28 28 28; 271 272 /* Circled buttons */ 273 --circle-button-background: 255 255 255; 274 --circle-button-text-color: 28 28 28; 275 }.shopify-section:has(.section-spacing.color-scheme--bg-3671eee015764974ee0aef1536023e0f) + .shopify-section:has(.section-spacing.color-scheme--bg-3671eee015764974ee0aef1536023e0f:not(.bordered-section)) .section-spacing { 276 padding-block-start: 0; 277 }.color-scheme--scheme-39371cc7-ca8e-4abf-b075-d539f965b7ff { 278 /* Color settings */--accent: 28 28 28; 279 --text-color: 28 28 28; 280 --background: 234 187 51 / 1.0; 281 --background-without-opacity: 234 187 51; 282 --background-gradient: ;--border-color: 203 163 48;/* Button colors */ 283 --button-background: 28 28 28; 284 --button-text-color: 255 255 255; 285 286 /* Circled buttons */ 287 --circle-button-background: 255 255 255; 288 --circle-button-text-color: 28 28 28; 289 }.shopify-section:has(.section-spacing.color-scheme--bg-f5f944b70d75d54b3eb50164e3bec0ff) + .shopify-section:has(.section-spacing.color-scheme--bg-f5f944b70d75d54b3eb50164e3bec0ff:not(.bordered-section)) .section-spacing { 290 padding-block-start: 0; 291 }.color-scheme--scheme-552ad9b9-d921-48a6-b84a-14a5fa4be78e { 292 /* Color settings */--accent: 28 28 28; 293 --text-color: 28 28 28; 294 --background: 129 228 235 / 1.0; 295 --background-without-opacity: 129 228 235; 296 --background-gradient: ;--border-color: 114 198 204;/* Button colors */ 297 --button-background: 28 28 28; 298 --button-text-color: 255 255 255; 299 300 /* Circled buttons */ 301 --circle-button-background: 255 255 255; 302 --circle-button-text-color: 28 28 28; 303 }.shopify-section:has(.section-spacing.color-scheme--bg-6668f3e75326e9051334d7c4ab3c98b0) + .shopify-section:has(.section-spacing.color-scheme--bg-6668f3e75326e9051334d7c4ab3c98b0:not(.bordered-section)) .section-spacing { 304 padding-block-start: 0; 305 }.color-scheme--scheme-b22647d4-462f-476d-9bbb-f65a5afb15bf { 306 /* Color settings */--accent: 28 28 28; 307 --text-color: 129 228 235; 308 --background: 217 114 76 / 1.0; 309 --background-without-opacity: 217 114 76; 310 --background-gradient: ;--border-color: 204 131 100;/* Button colors */ 311 --button-background: 28 28 28; 312 --button-text-color: 129 228 235; 313 314 /* Circled buttons */ 315 --circle-button-background: 255 255 255; 316 --circle-button-text-color: 28 28 28; 317 }.shopify-section:has(.section-spacing.color-scheme--bg-086754fce968d592abf29d583705fd26) + .shopify-section:has(.section-spacing.color-scheme--bg-086754fce968d592abf29d583705fd26:not(.bordered-section)) .section-spacing { 318 padding-block-start: 0; 319 }.color-scheme--scheme-32f97f71-e993-4298-abec-25b63fba6844 { 320 /* Color settings */--accent: 28 28 28; 321 --text-color: 217 114 76; 322 --background: 139 225 233 / 1.0; 323 --background-without-opacity: 139 225 233; 324 --background-gradient: ;--border-color: 151 208 209;/* Button colors */ 325 --button-background: 28 28 28; 326 --button-text-color: 255 255 255; 327 328 /* Circled buttons */ 329 --circle-button-background: 255 255 255; 330 --circle-button-text-color: 28 28 28; 331 }.shopify-section:has(.section-spacing.color-scheme--bg-ecba8421923ff0f9d77a26e859f263f7) + .shopify-section:has(.section-spacing.color-scheme--bg-ecba8421923ff0f9d77a26e859f263f7:not(.bordered-section)) .section-spacing { 332 padding-block-start: 0; 333 }.color-scheme--dialog { 334 /* Color settings */--accent: 28 28 28; 335 --text-color: 28 28 28; 336 --background: 255 255 255 / 1.0; 337 --background-without-opacity: 255 255 255; 338 --background-gradient: ;--border-color: 221 221 221;/* Button colors */ 339 --button-background: 28 28 28; 340 --button-text-color: 255 255 255; 341 342 /* Circled buttons */ 343 --circle-button-background: 255 255 255; 344 --circle-button-text-color: 28 28 28; 345 }@view-transition { 346 navigation: auto; 347 }</style>
348<script> 349 // This allows to expose several variables to the global scope, to be used in scripts 350 window.themeVariables = { 351 settings: { 352 showPageTransition: true, 353 pageType: "cart", 354 moneyFormat: "${{amount}}", 355 moneyWithCurrencyFormat: "${{amount}} USD", 356 currencyCodeEnabled: false, 357 cartType: "drawer", 358 staggerMenuApparition: true 359 }, 360 361 strings: { 362 addedToCart: "Added to your cart!", 363 addedToCartWithTitle: "{{ product_title }} added to cart.", 364 closeGallery: "Close gallery", 365 zoomGallery: "Zoom picture", 366 errorGallery: "Image cannot be loaded", 367 shippingEstimatorNoResults: "Sorry, we do not ship to your address.", 368 shippingEstimatorOneResult: "There is one shipping rate for your address:", 369 shippingEstimatorMultipleResults: "There are several shipping rates for your address:", 370 shippingEstimatorError: "One or more error occurred while retrieving shipping rates:", 371 next: "Next", 372 previous: "Previous" 373 }, 374 375 mediaQueries: { 376 'sm': 'screen and (min-width: 700px)', 377 'md': 'screen and (min-width: 1000px)', 378 'lg': 'screen and (min-width: 1150px)', 379 'xl': 'screen and (min-width: 1400px)', 380 '2xl': 'screen and (min-width: 1600px)', 381 'sm-max': 'screen and (max-width: 699px)', 382 'md-max': 'screen and (max-width: 999px)', 383 'lg-max': 'screen and (max-width: 1149px)', 384 'xl-max': 'screen and (max-width: 1399px)', 385 '2xl-max': 'screen and (max-width: 1599px)', 386 'motion-safe': '(prefers-reduced-motion: no-preference)', 387 'motion-reduce': '(prefers-reduced-motion: reduce)', 388 'supports-hover': 'screen and (pointer: fine)', 389 'supports-touch': 'screen and (hover: none)' 390 } 391 };</script>
vendor: 1 bytes, line 391
391
392<script async crossorigin fetchpriority="high" src="/cdn/shopifycloud/importmap-polyfill/es-modules-shim.2.4.0.js"></script>
vendor: 1 bytes, line 392
392
393<script type="importmap">{ 394 "imports": { 395 "vendor": "//atlasruggallery.com/cdn/shop/t/47/assets/vendor.min.js?v=55929477288600450501787370141", 396 "theme": "//atlasruggallery.com/cdn/shop/t/47/assets/theme.js?v=58311755909072418771787370141", 397 "photoswipe": "//atlasruggallery.com/cdn/shop/t/47/assets/photoswipe.min.js?v=13374349288281597431787370141" 398 } 399 } 400 </script>
400 401 402
402<script type="module" src="//atlasruggallery.com/cdn/shop/t/47/assets/vendor.min.js?v=55929477288600450501787370141"></script>
402 403
403<script type="module" src="//atlasruggallery.com/cdn/shop/t/47/assets/theme.js?v=58311755909072418771787370141"></script>
403 404 405
405<script>window.performance && window.performance.mark && window.performance.mark('shopify.content_for_header.start');</script>
405<meta id="shopify-digital-wallet" name="shopify-digital-wallet" content="/71740981292/digital_wallets/dialog"> 406<link rel="ucp" href="/.well-known/ucp" version="2026-08-25">
406<script async="async" src="/checkouts/internal/preloads.js?locale=en-US"></script>
vendor: 1 bytes, line 406
406
407<script id="shopify-features" type="application/json">{"accessToken":"fab99ddd1ee5958444661755f0706135","betas":["rich-media-storefront-analytics"],"domain":"atlasruggallery.com","predictiveSearch":true,"shopId":71740981292,"locale":"en"}</script>
vendor: 1 bytes, line 407
407
408<script>var Shopify = Shopify || {}; 409Shopify.shop = "atlasruggallery.myshopify.com"; 410Shopify.locale = "en"; 411Shopify.currency = {"active":"USD","rate":"1.0"}; 412Shopify.country = "US"; 413Shopify.theme = {"name":"Milestone-09-Aug22","id":150828449836,"schema_name":"Prestige","schema_version":"11.0.0","theme_store_id":null,"role":"main"}; 414Shopify.theme.handle = "null"; 415Shopify.theme.style = {"id":null,"handle":null}; 416Shopify.cdnHost = "atlasruggallery.com/cdn"; 417Shopify.routes = Shopify.routes || {}; 418Shopify.routes.root = "/"; 419Shopify.shopJsCdnBaseUrl = "https://cdn.shopify.com/shopifycloud/shop-js"; 420Shopify.SignInWithShop = Shopify.SignInWithShop || {}; 421Shopify.SignInWithShop.User = Shopify.SignInWithShop.User || {}; 422Shopify.SignInWithShop.User.recognized = false;</script>
vendor: 1 bytes, line 422
422
423<script type="module">!function(o){(o.Shopify=o.Shopify||{}).modules=!0}(window);</script>
vendor: 1 bytes, line 423
423
424<script>!function(o){function n(){var o=[];function n(){o.push(Array.prototype.slice.apply(arguments))}return n.q=o,n}var t=o.Shopify=o.Shopify||{};t.loadFeatures=n(),t.autoloadFeatures=n()}(window);</script>
vendor: 1 bytes, line 424
424
425<script> 426 window.Shopify = window.Shopify || {}; 427 window.Shopify.SignInWithShop = window.Shopify.SignInWithShop || {}; 428 window.Shopify.SignInWithShop.assetMetrics = { sampleRate: 0.25 }; 429 window.Shopify.SignInWithShop.eligible = true; 430</script>
vendor: 1 bytes, line 430
430
431<script id="shop-js-analytics" type="application/json">{"pageType":"cart"}</script>
vendor: 1 bytes, line 431
431
432<script defer="defer" async type="module" src="https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.init-shop-cart-sync.en.esm.js"></script>
vendor: 1 bytes, line 432
432
433<script type="module"> 434 await import("https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.init-shop-cart-sync.en.esm.js"); 435 436 window.Shopify.SignInWithShop?.initShopCartSync?.({"fedCMEnabled":true,"windoidEnabled":true}); 437 438</script>
vendor: 1 bytes, line 438
438
439<script> 440 window.Shopify = window.Shopify || {}; 441 if (!window.Shopify.featureAssets) window.Shopify.featureAssets = {}; 442 window.Shopify.featureAssets['shop-js'] = {"avatar":["modules/v2/loader.avatar.en.esm.js"],"checkout-modal":["modules/v2/loader.checkout-modal.en.esm.js"],"init-customer-accounts-sign-up":["modules/v2/loader.init-customer-accounts-sign-up.en.esm.js"],"init-customer-accounts":["modules/v2/loader.init-customer-accounts.en.esm.js"],"init-fed-cm":["modules/v2/loader.init-fed-cm.en.esm.js"],"init-shop-cart-sync":["modules/v2/loader.init-shop-cart-sync.en.esm.js"],"init-shop-email-lookup-coordinator":["modules/v2/loader.init-shop-email-lookup-coordinator.en.esm.js"],"init-shop-for-new-customer-accounts":["modules/v2/loader.init-shop-for-new-customer-accounts.en.esm.js"],"init-shop-user-recognition":["modules/v2/loader.init-shop-user-recognition.en.esm.js"],"init-windoid":["modules/v2/loader.init-windoid.en.esm.js"],"lead-capture":["modules/v2/loader.lead-capture.en.esm.js"],"listener":["modules/v2/loader.listener.en.esm.js"],"pay-button":["modules/v2/loader.pay-button.en.esm.js"],"payment-terms":["modules/v2/loader.payment-terms.en.esm.js"],"shop-button":["modules/v2/loader.shop-button.en.esm.js"],"shop-cart-sync":["modules/v2/loader.shop-cart-sync.en.esm.js"],"shop-cash-offers":["modules/v2/loader.shop-cash-offers.en.esm.js"],"shop-follow-button":["modules/v2/loader.shop-follow-button.en.esm.js"],"shop-login-button":["modules/v2/loader.shop-login-button.en.esm.js"],"shop-login":["modules/v2/loader.shop-login.en.esm.js"],"shop-toast-manager":["modules/v2/loader.shop-toast-manager.en.esm.js"],"shop-user-recognition":["modules/v2/loader.shop-user-recognition.en.esm.js"]}; 443</script>
vendor: 1 bytes, line 443
443
444<script id="__st">var __st={"a":71740981292,"offset":-14400,"reqid":"5cb7ebb4-e86d-4870-a7ec-bd0c17010393-1791093385","pageurl":"atlasruggallery.com\/cart","u":"1290e4e54933","p":"cart"};</script>
vendor: 1 bytes, line 444
444
445<script>window.ShopifyPaypalV4VisibilityTracking = true;</script>
vendor: 1 bytes, line 445
445
446<script id="captcha-bootstrap">!function(){'use strict';const t='contact',e='account',n='new_comment',o=[[t,t],['blogs',n],['comments',n],[t,'customer']],c=[[e,'customer_login'],[e,'guest_login'],[e,'recover_customer_password'],[e,'create_customer']],r=t=>t.map((([t,e])=>`form[action*='/${t}']:not([data-nocaptcha='true']) input[name='form_type'][value='${e}']`)).join(','),a=t=>()=>t?[...document.querySelectorAll(t)].map((t=>t.form)):[];function s(){const t=[...o],e=r(t);return a(e)}const i='password',u='form_key',d=['recaptcha-v3-token','g-recaptcha-response','h-captcha-response',i],f=()=>{try{return window.sessionStorage}catch{return}},m='__shopify_v',_=t=>t.elements[u];function p(t,e,n=!1){try{const o=window.sessionStorage,c=JSON.parse(o.getItem(e)),{data:r}=function(t){const{data:e,action:n}=t;return t[m]||n?{data:e,action:n}:{data:t,action:n}}(c);for(const[e,n]of Object.entries(r))t.elements[e]&&(t.elements[e].value=n);n&&o.removeItem(e)}catch(o){console.error('form repopulation failed',{error:o})}}const l='form_type',E='cptcha';function T(t){t.dataset[E]=!0}const w=window,h=w.document,L='Shopify',v='ce_forms',y='captcha';let A=!1;((t,e)=>{const n=(g='f06e6c50-85a8-45c8-87d0-21a2b65856fe',I='https://cdn.shopify.com/shopifycloud/storefront-forms-hcaptcha/ce_storefront_forms_captcha_hcaptcha.v1.5.3.iife.js',D={infoText:'Protected by hCaptcha',privacyText:'Privacy',termsText:'Terms'},(t,e,n)=>{const o=w[L][v],c=o.bindForm;if(c)return c(t,g,e,D).then(n);var r;o.q.push([[t,g,e,D],n]),r=I,A||(h.body.append(Object.assign(h.createElement('script'),{id:'captcha-provider',async:!0,src:r})),A=!0)});var g,I,D;w[L]=w[L]||{},w[L][v]=w[L][v]||{},w[L][v].q=[],w[L][y]=w[L][y]||{},w[L][y].protect=function(t,e){n(t,void 0,e),T(t)},Object.freeze(w[L][y]),function(t,e,n,w,h,L){const[v,y,A,g]=function(t,e,n){const i=e?o:[],u=t?c:[],d=[...i,...u],f=r(d),m=r(i),_=r(d.filter((([t,e])=>n.includes(e))));return[a(f),a(m),a(_),s()]}(w,h,L),I=t=>{const e=t.target;return e instanceof HTMLFormElement?e:e&&e.form},D=t=>v().includes(t);t.addEventListener('submit',(t=>{const e=I(t);if(!e)return;const n=D(e)&&!e.dataset.hcaptchaBound&&!e.dataset.recaptchaBound,o=_(e),c=g().includes(e)&&(!o||!o.value);(n||c)&&t.preventDefault(),c&&!n&&(function(t){try{if(!f())return;!function(t){const e=f();if(!e)return;const n=_(t);if(!n)return;const o=n.value;o&&e.removeItem(o)}(t);const e=Array.from(Array(32),(()=>Math.random().toString(36)[2])).join('');!function(t,e){_(t)||t.append(Object.assign(document.createElement('input'),{type:'hidden',name:u})),t.elements[u].value=e}(t,e),function(t,e){const n=f();if(!n)return;const o=[...t.querySelectorAll(`input[type='${i}']`)].map((({name:t})=>t)),c=[...d,...o],r={};for(const[a,s]of new FormData(t).entries())c.includes(a)||(r[a]=s);n.setItem(e,JSON.stringify({[m]:1,action:t.action,data:r}))}(t,e)}catch(e){console.error('failed to persist form',e)}}(e),e.submit())}));const S=(t,e)=>{t&&!t.dataset[E]&&(n(t,e.some((e=>e===t))),T(t))};for(const o of['focusin','change'])t.addEventListener(o,(t=>{const e=I(t);D(e)&&S(e,y())}));const B=e.get('form_key'),M=e.get(l),P=B&&M;t.addEventListener('DOMContentLoaded',(()=>{const t=y();if(P)for(const e of t)e.elements[l].value===M&&p(e,B);[...new Set([...A(),...v().filter((t=>'true'===t.dataset.shopifyCaptcha))])].forEach((e=>S(e,t)))}))}(h,new URLSearchParams(w.location.search),n,t,e,['guest_login'])})(!0,!0)}();</script>
vendor: 1 bytes, line 446
446
447<script integrity="sha256-JjoPp5ZfB1sSAs5SQaol1x1GgvveM+BgmRzyDexInEQ=" data-source-attribution="shopify.loadfeatures" defer="defer" src="//atlasruggallery.com/cdn/shopifycloud/storefront/assets/storefront/load_feature-1bd60354.js" crossorigin="anonymous"></script>
vendor: 1 bytes, line 447
447
448<script>(function () {var userAgent = navigator.userAgent;var platform = navigator.platform;var maxTouchPoints = navigator.maxTouchPoints || 0;var isIOS = /iPad|iPhone|iPod/.test(platform) || (platform === 'MacIntel' && maxTouchPoints > 1);var isMacSafari = platform.indexOf('Mac') === 0 && /Safari/.test(userAgent) && !/Chrome|Chromium|CriOS|FxiOS|Edg|OPR|Android/.test(userAgent);var isAppleSafari = isIOS || isMacSafari;if (isAppleSafari) {fetch('/sf_private_access_tokens' + location.search).catch(function () {});}function browserMajorVersion(pattern) {var match = userAgent.match(pattern);return match ? parseInt(match[1], 10) : null;}function shouldLoadAutosizesPolyfill() {if (!window.PerformanceObserver?.supportedEntryTypes?.includes('paint')) {return false;}var chromeVersion = browserMajorVersion(/Chrome\/(\d+)/);if (chromeVersion !== null) {return chromeVersion < 126;}var firefoxVersion = browserMajorVersion(/Firefox\/(\d+)/);if (firefoxVersion !== null) {return firefoxVersion < 150;}var safariVersion = isAppleSafari ? browserMajorVersion(/Version\/(\d+).*Safari\//) : null;if (safariVersion !== null) {return safariVersion < 27;}return true;}if (shouldLoadAutosizesPolyfill()) {var autosizesScript = document.createElement('script');autosizesScript.async = true;autosizesScript.crossOrigin = 'anonymous';autosizesScript.src = "//atlasruggallery.com/cdn/shopifycloud/storefront/assets/storefront/autosizes-84416378.js";(document.head || document.documentElement).appendChild(autosizesScript);}window.ShopifyAnalytics = window.ShopifyAnalytics || {};window.ShopifyAnalytics.performance = window.ShopifyAnalytics.performance || {};(function () {var LONG_FRAME_THRESHOLD = 50;var longAnimationFrames = [];var activeRafId = null;function collectLongFrames() {var previousTime = null;function rafMonitor(now) {if (activeRafId === null) {return;}var delta = now - previousTime;if (delta > LONG_FRAME_THRESHOLD) {longAnimationFrames.push({startTime: previousTime,endTime: now,});}previousTime = now;activeRafId = requestAnimationFrame(rafMonitor);}previousTime = performance.now();activeRafId = requestAnimationFrame(rafMonitor);}if (!window.PerformanceObserver?.supportedEntryTypes?.includes('long-animation-frame')) {collectLongFrames();var timeoutId = setTimeout(function () {cancelAnimationFrame(activeRafId);}, 10000);window.ShopifyAnalytics.performance.getLongAnimationFrames = function (stopCollection) {if (stopCollection === undefined) {stopCollection = false;}if (stopCollection) {clearTimeout(timeoutId);cancelAnimationFrame(activeRafId);}return longAnimationFrames;};}})();})();</script>
448<script id="shopify-origin-trials" async="async" integrity="sha256-qJbe/jEZBHtr5W/BlA2cKAz3vkXu6vJQyLjgvgCC86g=" src="//cdn.shopify.com/shopifycloud/storefront/assets/storefront/origin_trials-318ab40a.js" crossorigin="anonymous" onload="window.__shopifyOriginTrialsDone = true" onerror="window.__shopifyOriginTrialsDone = true"></script>
vendor: 1 bytes, line 448
448
449<script> 450 window.Shopify = window.Shopify || {}; 451 window.Shopify.MCP = window.Shopify.MCP || {}; 452 window.Shopify.MCP.enabled = true; 453 window.Shopify.MCP.shop = "atlasruggallery.myshopify.com"; 454 window.Shopify.MCP.mcpEndpoint = "https:\/\/atlasruggallery.com\/api\/mcp"; 455 window.Shopify.MCP.tools = [{"name":"search_shop_policies_and_faqs","description":"Used to get facts about the stores policies, products, or services.\nSome examples of questions you can ask are:\n - What is your return policy?\n - What is your shipping policy?\n - What is your phone number?\n - What are your hours of operation?\"\n","inputSchema":{"$schema":"https:\/\/json-schema.org\/draft\/2020-12\/schema","type":"object","properties":{"query":{"type":"string","description":"A natural language query."},"context":{"type":"string","description":"Additional information about the request such as user demographics, mood, location, or other relevant details that could help in tailoring the response appropriately."}},"required":["query"]}}]; 456</script>
vendor: 1 bytes, line 456
456
457<script>(()=>{var d="shopify:webmcp_adapter_loaded",n=Symbol.for("shopify.webmcp_adapter_loading");function s(c,a,{win:r=window,doc:o=document}={}){function p(){try{return r.localStorage.getItem(d)==="true"}catch{return!1}}function l(){try{r.localStorage.setItem(d,"true")}catch{}}function u(){return typeof(o.modelContext||r.navigator?.modelContext)?.registerTool=="function"}function f(){if(r[n]||!u())return;let t=o.head||o.getElementsByTagName("head")[0];if(!t)return;let e=o.createElement("script");e.type="module",e.crossOrigin="anonymous",a&&(e.integrity=a),e.src=c,e.addEventListener("load",l,{once:!0}),e.addEventListener("error",()=>{r[n]=!1},{once:!0}),t.appendChild(e),r[n]=!0}function _(t){let e=o.getElementById("shopify-origin-trials");if(!e||r.__shopifyOriginTrialsDone){t();return}e.addEventListener("load",t,{once:!0}),e.addEventListener("error",t,{once:!0})}function i(){_(()=>r.setTimeout(f,0))}function m(){o.addEventListener("DOMContentLoaded",i,{once:!0})}p()?i():m()}s("\/\/atlasruggallery.com\/cdn\/shopifycloud\/storefront\/assets\/storefront\/webmcp-c6b62ece.js","sha256-ke4DDuBjdvea3vxLWxHc9E9nq8zihuG4IfYEGbb77ys=");})(); 458</script>
vendor: 1 bytes, line 458
458
459<script data-source-attribution="shopify.dynamic_checkout.dynamic.init">var Shopify=Shopify||{};Shopify.PaymentButton=Shopify.PaymentButton||{isStorefrontPortableWallets:!0,init:function(){window.Shopify.PaymentButton.init=function(){};var t=document.createElement("script");t.src="https://atlasruggallery.com/cdn/shopifycloud/portable-wallets/latest/portable-wallets.en.js",t.type="module",document.head.appendChild(t)}}; 460</script>
vendor: 1 bytes, line 460
460
461<script data-source-attribution="shopify.dynamic_checkout.buyer_consent"> 462 function portableWalletsHideBuyerConsent(e){var t=document.getElementById("shopify-buyer-consent"),n=document.getElementById("shopify-subscription-policy-button");t&&n&&(t.classList.add("hidden"),t.setAttribute("aria-hidden","true"),n.removeEventListener("click",e))}function portableWalletsShowBuyerConsent(e){var t=document.getElementById("shopify-buyer-consent"),n=document.getElementById("shopify-subscription-policy-button");t&&n&&(t.classList.remove("hidden"),t.removeAttribute("aria-hidden"),n.addEventListener("click",e))}window.Shopify?.PaymentButton&&(window.Shopify.PaymentButton.hideBuyerConsent=portableWalletsHideBuyerConsent,window.Shopify.PaymentButton.showBuyerConsent=portableWalletsShowBuyerConsent); 463</script>
vendor: 1 bytes, line 463
463
464<script data-source-attribution="shopify.dynamic_checkout.cart.bootstrap">document.addEventListener("DOMContentLoaded",(function(){function t(){return document.querySelector("shopify-accelerated-checkout-cart, shopify-accelerated-checkout")}if(t())Shopify.PaymentButton.init();else{new MutationObserver((function(e,n){t()&&(Shopify.PaymentButton.init(),n.disconnect())})).observe(document.body,{childList:!0,subtree:!0})}})); 465</script>
465 466
467<script id="shopify-cfh-end">window.performance && window.performance.mark && window.performance.mark('shopify.content_for_header.end');</script>
467 468<link href="//atlasruggallery.com/cdn/shop/t/47/assets/theme.css?v=148142637820107618341787370141" rel="stylesheet" type="text/css" media="all" /><link href="//atlasruggallery.com/cdn/shop/t/47/assets/atlas-custom.css?v=46288089855389312111787370141" rel="stylesheet" type="text/css" media="all" /><link rel="preconnect" href="https://api.productadvisorai.com" crossorigin> 469 <!-- == NEW VISUALIZER DEPENDENCIES == --> 470 <link href="//atlasruggallery.com/cdn/shop/t/47/assets/output.css?v=144739979901331796831787370141" rel="stylesheet" type="text/css" media="all" /> 471 <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet"> 472 <link href="//atlasruggallery.com/cdn/shop/t/47/assets/see_in_my_room.css?v=155626319342267045851787370141" rel="stylesheet" type="text/css" media="all" /> 473 <link href="//atlasruggallery.com/cdn/shop/t/47/assets/style-ai-search.css?v=169065352740005500861787370141" rel="stylesheet" type="text/css" media="all" /> 474
474<script> 475 document.documentElement.className = document.documentElement.className.replace('no-js', 'js'); 476 if (typeof Shopify !== 'undefined' && Shopify.designMode) { 477 document.documentElement.classList.add('shopify-design-mode'); 478 } 479 </script>
479 480 <link href="https://monorail-edge.shopifysvc.com" rel="dns-prefetch">
481<script>(function(){if ("sendBeacon" in navigator && "performance" in window) {try {var session_token_from_headers = performance.getEntriesByType('navigation')[0].serverTiming.find(x => x.name == '_s').description;} catch {var session_token_from_headers = undefined;}var session_cookie_matches = document.cookie.match(/_shopify_s=([^;]*)/);var session_token_from_cookie = session_cookie_matches && session_cookie_matches.length === 2 ? session_cookie_matches[1] : "";var session_token = session_token_from_headers || session_token_from_cookie || "";function handle_abandonment_event(e) {var entries = performance.getEntries().filter(function(entry) {return /monorail-edge.shopifysvc.com/.test(entry.name);});if (!window.abandonment_tracked && entries.length === 0) {window.abandonment_tracked = true;var currentMs = Date.now();var navigation_start = performance.timing.navigationStart;var payload = {shop_id: 71740981292,url: window.location.href,navigation_start,duration: currentMs - navigation_start,session_token,page_type: "cart"};window.navigator.sendBeacon("https://monorail-edge.shopifysvc.com/v1/produce", JSON.stringify({schema_id: "online_store_buyer_site_abandonment/1.1",payload: payload,metadata: {event_created_at_ms: currentMs,event_sent_at_ms: currentMs}}));}}window.addEventListener('pagehide', handle_abandonment_event);}}());</script>
vendor: 1 bytes, line 481
481
482<script> 483 window.__TREKKIE_SHIM_QUEUE = window.__TREKKIE_SHIM_QUEUE || []; 484</script>
vendor: 1 bytes, line 484
484
485<script>(function(){var wpmLoader=function(){"use strict";var e=/Googlebot|Storebot-Google|bingbot|Baiduspider|YandexBot|DuckDuckBot|Slurp|facebookexternalhit|Twitterbot|LinkedInBot|Applebot|AdsBot-Google|Mediapartners-Google|APIs-Google|PetalBot|SemrushBot|AhrefsBot|MJ12bot|DotBot|Acunetix|PerplexityBot|Perplexity-User/i,t=/bytedance/i;function i(){try{var e=document.cookie;if(!e||"string"!=typeof e)return;for(var t=0,i=e.split(";");t<i.length;t++){var n=i[t],r=n.indexOf("=");if(-1!==r){var o=n.slice(0,r).trim();if(o){var a=void 0;try{a=decodeURIComponent(o)}catch(e){a=o}if("_shopify_s"===a){var d=n.slice(r+1).trim();try{return decodeURIComponent(d)}catch(e){return d}}}}}return}catch(e){return}}function n(e){try{"undefined"!=typeof console&&"function"==typeof console.warn&&console.warn(e)}catch(e){}}function r(e,t){return"string"==typeof e&&e.length>0&&e.length<=t?e:void 0}function o(e){var t;switch(null==(t=null==e?void 0:e.navigation)?void 0:t.type){case 0:return"navigate";case 1:return"reload";case 2:return"back_forward";default:return}}function a(){var e,t,i;try{var n=null==(i=null==(t=null==(e=self.ShopifyAnalytics)?void 0:e.lib)?void 0:t.trekkie)?void 0:i.state;return"awaiting-consent"===n||"initialized"===n?n:void 0}catch(e){return}}return function(d,s,u,l){var c=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};try{var p=c.trekkieShim;!0!==p&&"true"!==p||null!=window.__TREKKIE_SHIM_QUEUE||(window.__TREKKIE_SHIM_QUEUE=[])}catch(e){}var f,v,h,y,g=(v=(f={modern:/Edge?\/(1{2}[4-9]|1[2-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Firefox\/(1{2}[4-9]|1[2-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Chrom(ium|e)\/(9{2}|\d{3,})\.\d+(\.\d+|)|(Maci|X1{2}).+ Version\/(15\.\d+|(1[6-9]|[2-9]\d|\d{3,})\.\d+)([,.]\d+|)( \(\w+\)|)( Mobile\/\w+|) Safari\/|Chrome.+OPR\/(9{2}|\d{3,})\.\d+\.\d+|(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS|CPU iPad OS)[ +]+(15[._]\d+|(1[6-9]|[2-9]\d|\d{3,})[._]\d+)([._]\d+|)|Android:?[ /-](14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})(\.\d+|)(\.\d+|)|Android.+Firefox\/(15\d|1[6-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Android.+Chrom(ium|e)\/(14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|SamsungBrowser\/([2-9]\d|\d{3,})\.\d+/,legacy:/Edge?\/(1[6-9]|[2-9]\d|\d{3,})\.\d+(\.\d+|)|Firefox\/(5[4-9]|[6-9]\d|\d{3,})\.\d+(\.\d+|)|Chrom(ium|e)\/(5[1-9]|[6-9]\d|\d{3,})\.\d+(\.\d+|)([\d.]+$|.*Safari\/(?![\d.]+ Edge\/[\d.]+$))|(Maci|X1{2}).+ Version\/(10\.\d+|(1[1-9]|[2-9]\d|\d{3,})\.\d+)([,.]\d+|)( \(\w+\)|)( Mobile\/\w+|) Safari\/|Chrome.+OPR\/(3[89]|[4-9]\d|\d{3,})\.\d+\.\d+|(CPU[ +]OS|iPhone[ +]OS|CPU[ +]iPhone|CPU IPhone OS|CPU iPad OS)[ +]+(10[._]\d+|(1[1-9]|[2-9]\d|\d{3,})[._]\d+)([._]\d+|)|Android:?[ /-](14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})(\.\d+|)(\.\d+|)|Mobile Safari.+OPR\/([89]\d|\d{3,})\.\d+\.\d+|Android.+Firefox\/(15\d|1[6-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Android.+Chrom(ium|e)\/(14[89]|1[5-9]\d|[2-9]\d{2}|\d{4,})\.\d+(\.\d+|)|Android.+(UC? ?Browser|UCWEB|U3)[ /]?(15\.([5-9]|\d{2,})|(1[6-9]|[2-9]\d|\d{3,})\.\d+)\.\d+|SamsungBrowser\/(5\.\d+|([6-9]|\d{2,})\.\d+)|Android.+MQ{2}Browser\/(14(\.(9|\d{2,})|)|(1[5-9]|[2-9]\d|\d{3,})(\.\d+|))(\.\d+|)|K[Aa][Ii]OS\/(3\.\d+|([4-9]|\d{2,})\.\d+)(\.\d+|)/}).modern,h=f.legacy,(y=navigator.userAgent).match(e)?"bot":y.match(v)?"modern":y.match(h)?"legacy":y.match(t)?"bot":"unknown"),m=function(e){var t,i,n=r(e,128);try{var a=window.performance,d=null==(t=null==a?void 0:a.getEntriesByType)?void 0:t.call(a,"navigation")[0];if(!d)return{requestId:n,navigationType:o(a)};var s="type"in d?r(d.type,64):void 0,u="serverTiming"in d&&Array.isArray(d.serverTiming)?d.serverTiming:[];return{requestId:null!=n?n:r(null==(i=u.find(function(e){return"requestID"===e.name}))?void 0:i.description,128),navigationType:s}}catch(e){return{requestId:n}}}(c.requestId),w=function(e){var t=e.version,r=e.browserTarget,o=e.surface,a=e.shopId,d=e.monorailEndpoint,s=window.location.href;return{emit:function(e){var u=e.status,l=e.errorMsg,c=e.failureReason,p=e.useKeepaliveFallback,f=void 0!==p&&p,v=e.navigationType,h=e.pagehidePersisted,y=e.requestId,g=e.trekkieState;if(d){var m,w;try{var b=(new Date).getTime();m=JSON.stringify({metadata:{event_sent_at_ms:b},events:[{schema_id:"web_pixels_manager_load/3.3",payload:{version:t,bundle_target:r,page_url:s,status:u,surface:o,error_msg:l,failure_reason:c,navigation_type:v,pagehide_persisted:h,request_id:y,trekkie_state:g,shop_id:a,visit_token:i()},metadata:{event_created_at_ms:b}}]})}catch(e){return}try{if("function"==typeof window.navigator.sendBeacon&&-1===(w=window.navigator.userAgent).indexOf("iPhone; CPU iPhone OS 12_")&&-1===w.indexOf("iPad; CPU OS 12_")&&-1===w.indexOf("iPod touch; CPU iPhone OS 12_")&&window.navigator.sendBeacon.bind(window.navigator)(d,m))return}catch(e){}if(f)try{"function"==typeof window.fetch&&window.fetch(d,{method:"POST",headers:{"Content-Type":"text/plain"},body:m,keepalive:!0}
485).catch(function(){})}catch(e){}else try{var _=new XMLHttpRequest;_.open("POST",d,!0),_.setRequestHeader("Content-Type","text/plain"),_.send(m)}catch(e){n("[Web Pixels Manager] Got an unhandled error while logging to Monorail.")}}else n("[Web Pixels Manager] No Monorail endpoint provided, skipping logging.")}}}({version:u,browserTarget:g,surface:d.surface,shopId:d.shopId,monorailEndpoint:d.monorailEndpoint});if(Boolean(null==(_=null==(b=window.Shopify)?void 0:b.analytics)?void 0:_.replayQueue))w.emit({status:"setup-skipped",errorMsg:"replay queue already initialized."});else{var b,_;w.emit({status:"setup-started"}),window.Shopify=window.Shopify||{};var S=window.Shopify;S.analytics=S.analytics||{};var P=S.analytics;P.replayQueue=[],P.publish=function(e,t,i){return P.replayQueue.push([e,t,i]),!0};try{self.performance.mark("wpm:start")}catch(e){}var k,C="modern"===g?"modern":"legacy",E=(null!=l?l:{modern:"",legacy:""})[C],I=[(k={baseUrl:s,hashVersion:u,buildTarget:C}).baseUrl,"/wpm","/b",k.hashVersion,"modern"===k.buildTarget?"m":"l",".js"].join(""),O=!1,T=!1;try{c.browserTarget=g,function(){O=!0;try{window.addEventListener("pagehide",M)}catch(e){O=!1}}(),R(function(){try{R(x)}catch(e){D(e)}}),w.emit({status:"loading",requestId:m.requestId,navigationType:m.navigationType,trekkieState:a()})}catch(e){D(e)}}function U(){var e;if(q(),!function(){var e,t;return Boolean(null==(t=null==(e=window.Shopify)?void 0:e.analytics)?void 0:t.initialized)}()){var t,i,n;try{if("function"!=typeof(null==(e=window.webPixelsManager)?void 0:e.init))return void A();if(!(null!==(n=i=t=window.webPixelsManager.init(d))&&"function"!=typeof n&&Object(n)===n&&"publish"in i&&"function"==typeof i.publish&&"publishCustomEvent"in i&&"function"==typeof i.publishCustomEvent&&"visitor"in i&&"function"==typeof i.visitor))return void A()}catch(e){return void A(e)}var r=window.Shopify.analytics;r.replayQueue.forEach(function(e){var i=e[0],n=e[1],r=e[2];t.publishCustomEvent(i,n,r)}),r.replayQueue=[],r.publish=t.publishCustomEvent,r.visitor=t.visitor,r.initialized=!0}}function A(e){B("manager_api_unavailable",void 0===e?void 0:Q(e))}function x(){B("script_load_failed","".concat(I," has failed to load"))}function B(e,t){T||(T=!0,q(),w.emit({status:"failed",errorMsg:t,failureReason:e,requestId:m.requestId,navigationType:m.navigationType,trekkieState:a()}))}function M(e){O&&(q(),w.emit({status:"pagehide-while-loading",useKeepaliveFallback:!0,pagehidePersisted:e.persisted,requestId:m.requestId,navigationType:m.navigationType,trekkieState:a()}))}function q(){O=!1;try{window.removeEventListener("pagehide",M)}catch(e){}}function R(e){var t;!function(e){var t=e.src,i=e.async,n=void 0===i||i,r=e.onload,o=e.onerror,a=e.sri,d=e.scriptDataAttributes,s=void 0===d?{}:d,u=document.createElement("script"),l=document.querySelector("head"),c=document.querySelector("body");if(u.async=n,u.src=t,a&&(u.integrity=a,u.crossOrigin="anonymous"),s)for(var p in s)if(Object.prototype.hasOwnProperty.call(s,p))try{u.dataset[p]=String(s[p])}catch(e){}if(r&&u.addEventListener("load",r),o&&u.addEventListener("error",o),l)l.appendChild(u);else{if(!c)throw new Error("Did not find a head or body element to append the script");c.appendChild(u)}}({src:I,async:!0,onload:U,onerror:e,sri:(t=E,"string"==typeof t&&/^sha384-[A-Za-z0-9+/=]+$/.test(t)?E:""),scriptDataAttributes:c})}function D(e){B("script_append_failed",Q(e))}function Q(e){return e instanceof Error?e.message:"Unknown error"}}}();wpmLoader({shopId: 71740981292,storefrontBaseUrl: "https://atlasruggallery.com",extensionsBaseUrl: "https://extensions.shopifycdn.com/cdn/shopifycloud/web-pixels-manager",monorailEndpoint: "https://atlasruggallery.com/.well-known/shopify/monorail/unstable/produce_batch",surface: "storefront-renderer",enabledBetaFlags: ["4c64608a","16072cab","8450a54b","7ee89bf1"],webPixelsConfigList: [{"id":"2064613420","configuration":"{\"config\":\"{\\\"google_tag_ids\\\":[\\\"AW-18430891491\\\"],\\\"target_country\\\":\\\"ZZ\\\",\\\"gtag_events\\\":[{\\\"type\\\":\\\"begin_checkout\\\",\\\"action_label\\\":[\\\"AW-18430891491\\\/N4hmCMOm0e4cEOOrxNRE\\\",\\\"AW-18430891491\\\"]},{\\\"type\\\":\\\"search\\\",\\\"action_label\\\":[\\\"AW-18430891491\\\/yAM7CM-m0e4cEOOrxNRE\\\",\\\"AW-18430891491\\\"]},{\\\"type\\\":\\\"view_item\\\",\\\"action_label\\\":[\\\"AW-18430891491\\\/GxuPCMym0e4cEOOrxNRE\\\",\\\"AW-18430891491\\\"]},{\\\"type\\\":\\\"purchase\\\",\\\"action_label\\\":[\\\"AW-18430891491\\\/05BJCMCm0e4cEOOrxNRE\\\",\\\"AW-18430891491\\\"]},{\\\"type\\\":\\\"page_view\\\",\\\"action_label\\\":[\\\"AW-18430891491\\\/yT42CMmm0e4cEOOrxNRE\\\",\\\"AW-18430891491\\\"]},{\\\"type\\\":\\\"add_payment_info\\\",\\\"action_label\\\":[\\\"AW-18430891491\\\/7GpoCNKm0e4cEOOrxNRE\\\",\\\"AW-18430891491\\\"]},{\\\"type\\\":\\\"add_to_cart\\\",\\\"action_label\\\":[\\\"AW-18430891491\\\/Ln1QCMam0e4cEOOrxNRE\\\",\\\"AW-18430891491\\\"]}],\\\"enable_monitoring_mode\\\":false}\"}","eventPayloadVersion":"v1","runtimeContext":"OPEN","scriptVersion":"a3321ca85cf5aaf6b57585fcd8d67b3a","type":"APP","apiClientId":1780363,"privacyPurposes":[],"dataSharingAdjustments":{"protectedCustomerApprovalScopes":["read_customer_address","read_customer_email","read_customer_name","read_customer_personal_data","read_customer_phone"],"dataSharingControls":["share_all_events"]},"dataSharingState":"optimized","enabledFlags":["9a3ed68a"]},{"id":"shopify-app-pixel","configuration":"{}","eventPayloadVersion":"v1","runtimeContext":"STRICT","scriptVersion":"0530","apiClientId":"shopify-pixel","type":"APP","privacyPurposes":["ANALYTICS","MARKETING"]},{"id":"shopify-custom-pixel","eventPayloadVersion":"v1","runtimeContext":"LAX","scriptVersion":"0530","apiClientId":"shopify-pixel","type":"CUSTOM","privacyPurposes":["ANALYTICS","MARKETING"]}],isMerchantRequest: false,initData: {"shop":{"name":"AtlasRugGallery","paymentSettings":{"currencyCode":"USD"},"myshopifyDomain":"atlasruggallery.myshopify.com","countryCode":"US","storefrontUrl":"https:\/\/atlasruggallery.com"},"customer":null,"cart":null,"checkout":null,"productVariants":[],"products":[],"purchasingCompany":null},},"https://atlasruggallery.com/cdn","5982071ew7ea472e3p69b68784m2150dfea",{"modern":"","legacy":""},{"trekkieShim":true,"agentContext":true,"apiClientId":"580111","facebookCapiEnabled":"false","themeId":"150828449836","themePublished":"true","eventMetadataId":"ef70bad2-da8f-4e96-824a-be1659160011","pageType":"cart","shopId":"71740981292","storefrontBaseUrl":"https:\/\/atlasruggallery.com","extensionBaseUrl":"https:\/\/extensions.shopifycdn.com\/cdn\/shopifycloud\/web-pixels-manager","surface":"storefront-renderer","enabledBetaFlags":"[\"4c64608a\", \"16072cab\", \"8450a54b\", \"7ee89bf1\"]","isMerchantRequest":"false","hashVersion":"5982071ew7ea472e3p69b68784m2150dfea","publish":"custom","events":"[[\"page_viewed\",{}]]"});})();</script>
485<script> 486 window.ShopifyAnalytics = window.ShopifyAnalytics || {}; 487 window.ShopifyAnalytics.meta = window.ShopifyAnalytics.meta || {}; 488 window.ShopifyAnalytics.meta.currency = 'USD'; 489 var meta = {"page":{"pageType":"cart","requestId":"5cb7ebb4-e86d-4870-a7ec-bd0c17010393-1791093385"}}; 490 for (var attr in meta) { 491 window.ShopifyAnalytics.meta[attr] = meta[attr]; 492 } 493</script>
vendor: 1 bytes, line 493
493
494<script class="analytics"> 495 (function () { 496 var customDocumentWrite = function(content) { 497 var jquery = null; 498 499 if (window.jQuery) { 500 jquery = window.jQuery; 501 } else if (window.Checkout && window.Checkout.$) { 502 jquery = window.Checkout.$; 503 } 504 505 if (jquery) { 506 jquery('body').append(content); 507 } 508 }; 509 510 var hasLoggedConversion = function(token) { 511 if (token) { 512 return document.cookie.indexOf('loggedConversion=' + token) !== -1; 513 } 514 return false; 515 } 516 517 var setCookieIfConversion = function(token) { 518 if (token) { 519 var twoMonthsFromNow = new Date(Date.now()); 520 twoMonthsFromNow.setMonth(twoMonthsFromNow.getMonth() + 2); 521 522 document.cookie = 'loggedConversion=' + token + '; expires=' + twoMonthsFromNow; 523 } 524 } 525 526 var trekkie = window.ShopifyAnalytics.lib = window.trekkie = window.trekkie || []; 527 window.ShopifyAnalytics.lib.trekkie = window.trekkie; 528 if (trekkie.integrations) { 529 return; 530 } 531 trekkie.methods = [ 532 'identify', 533 'page', 534 'ready', 535 'track', 536 'trackForm', 537 'trackLink' 538 ]; 539 trekkie.factory = function(method) { 540 return function() { 541 var args = Array.prototype.slice.call(arguments); 542 args.unshift(method); 543 trekkie.push(args); 544 if (method == 'track' || method == 'page') { 545 var pageUrl; 546 try { 547 pageUrl = window.location.href; 548 } catch (e) {} 549 var pageReferrer; 550 try { 551 pageReferrer = document.referrer; 552 } catch (e) {} 553 try { 554 if (window.__TREKKIE_SHIM_QUEUE == null) { 555 window.__TREKKIE_SHIM_QUEUE = []; 556 } 557 window.__TREKKIE_SHIM_QUEUE.push({ 558 from: 'trekkie-stub', 559 method: method, 560 args: args.slice(1), 561 pageContext: { 562 url: pageUrl, 563 referrer: pageReferrer 564 } 565 }); 566 } catch (e) { 567 // no-op 568 } 569 } 570 return trekkie; 571 }; 572 }; 573 for (var i = 0; i < trekkie.methods.length; i++) { 574 var key = trekkie.methods[i]; 575 trekkie[key] = trekkie.factory(key); 576 } 577 trekkie.load = function(config) { 578 trekkie.config = config || {}; 579 trekkie.config.initialDocumentCookie = document.cookie; 580 var first = document.getElementsByTagName('script')[0]; 581var script = document.createElement('script'); 582script.type = 'text/javascript'; 583script.onerror = function(e) { 584 var scriptFallback = document.createElement('script'); 585 scriptFallback.type = 'text/javascript'; 586 scriptFallback.onerror = function(error) { 587 var Monorail = { 588 produce: function produce(monorailDomain, schemaId, payload) { 589 var currentMs = new Date().getTime(); 590 var event = { 591 schema_id: schemaId, 592 payload: payload, 593 metadata: { 594 event_created_at_ms: currentMs, 595 event_sent_at_ms: currentMs 596 } 597 }; 598 return Monorail.sendRequest("https://" + monorailDomain + "/v1/produce", JSON.stringify(event)); 599 }, 600 sendRequest: function sendRequest(endpointUrl, payload) { 601 // Try the sendBeacon API 602 if (window && window.navigator && typeof window.navigator.sendBeacon === 'function' && typeof window.Blob === 'function' && !Monorail.isIos12()) { 603 var blobData = new window.Blob([payload], { 604 type: 'text/plain' 605 }); 606 607 if (window.navigator.sendBeacon(endpointUrl, blobData)) { 608 return true; 609 } // sendBeacon was not successful 610 611 } // XHR beacon 612 613 var xhr = new XMLHttpRequest(); 614 615 try { 616 xhr.open('POST', endpointUrl); 617 xhr.setRequestHeader('Content-Type', 'text/plain'); 618 xhr.send(payload); 619 } catch (e) { 620 console.log(e); 621 } 622 623 return false; 624 }, 625 isIos12: function isIos12() { 626 return window.navigator.userAgent.lastIndexOf('iPhone; CPU iPhone OS 12_') !== -1 || window.navigator.userAgent.lastIndexOf('iPad; CPU OS 12_') !== -1; 627 } 628 }; 629 Monorail.produce('monorail-edge.shopifysvc.com', 630 'trekkie_storefront_load_errors/1.1', 631 {shop_id: 71740981292, 632 theme_id: 150828449836, 633 app_name: "storefront", 634 context_url: window.location.href, 635 source_url: "//atlasruggallery.com/cdn/s/trekkie.storefront.2f6d7d7ede7d24234881a9cd5f47e679642fa1f6.min.js"}); 636 637 }; 638 scriptFallback.async = true; 639 scriptFallback.src = '//atlasruggallery.com/cdn/s/trekkie.storefront.2f6d7d7ede7d24234881a9cd5f47e679642fa1f6.min.js'; 640 first.parentNode.insertBefore(scriptFallback, first); 641}; 642script.async = true; 643script.src = '//atlasruggallery.com/cdn/s/trekkie.storefront.2f6d7d7ede7d24234881a9cd5f47e679642fa1f6.min.js'; 644first.parentNode.insertBefore(script, first); 645 646 }; 647 trekkie.load( 648 {"Trekkie":{"appName":"storefront","development":false,"defaultAttributes":{"shopId":71740981292,"isMerchantRequest":null,"themeId":150828449836,"themeCityHash":"8693036598257751454","contentLanguage":"en","currency":"USD","eventMetadataId":"ef70bad2-da8f-4e96-824a-be1659160011"},"isServerSideCookieWritingEnabled":true,"monorailRegion":"shop_domain","enabledBetaFlags":["764d78cb","8450a54b","7ee89bf1","4c64608a"]},"Session Attribution":{},"S2S":{"facebookCapiEnabled":false,"source":"trekkie-storefront-renderer","apiClientId":580111}} 649 ); 650 651 var loaded = false;
652 trekkie.ready(function() { 653 if (loaded) return; 654 loaded = true; 655 656 window.ShopifyAnalytics.lib = window.trekkie; 657 658 var originalDocumentWrite = document.write; 659 document.write = customDocumentWrite; 660 try { window.ShopifyAnalytics.merchantGoogleAnalytics.call(this); } catch(error) {}; 661 document.write = originalDocumentWrite; 662 663 var match = window.location.pathname.match(/checkouts\/(.+)\/(thank_you|post_purchase)/) 664 var token = match? match[1]: undefined; 665 if (!hasLoggedConversion(token)) { 666 setCookieIfConversion(token); 667 668 } 669 }); 670 671 window.ShopifyAnalytics.lib.page(null,{"pageType":"cart","requestId":"5cb7ebb4-e86d-4870-a7ec-bd0c17010393-1791093385","shopifyEmitted":true}); 672 673 var eventsListenerScript = document.createElement('script'); 674 eventsListenerScript.async = true; 675 eventsListenerScript.src = "//atlasruggallery.com/cdn/shopifycloud/storefront/assets/shop_events_listener-4e26a9ce.js"; 676 document.getElementsByTagName('head')[0].appendChild(eventsListenerScript); 677})();</script>
vendor: 1 bytes, line 677
677
678<script 679 defer 680 src="https://atlasruggallery.com/cdn/shopifycloud/perf-kit/shopify-perf-kit-3.9.4.min.js" 681 data-application="storefront-renderer" 682 data-shop-id="71740981292" 683 data-render-region="gcp-us-central1" 684 data-page-type="cart" 685 data-theme-instance-id="150828449836" 686 data-theme-name="Prestige" 687 data-theme-version="11.0.0" 688 data-monorail-region="shop_domain" 689 data-resource-timing-sampling-rate="10" 690 data-shs="true" 691 data-shs-beacon="true" 692 data-shs-export-with-fetch="true" 693 data-shs-logs-sample-rate="1" 694 data-shs-beacon-endpoint="https://atlasruggallery.com/api/collect" 695></script>
vendor: 1 bytes, line 695
695
696<script src="https://cdn.shopify.com/storefront/web-components/account.js" type="module" crossorigin fetchpriority="low" async></script>
696<script id="shopify-customer-account-data" type="application/json">{"customer":null,"shop":{"id":"71740981292","customerAccountTranslations":[{"key":"account_menu.signed_out_state.sheet_title","value":"Sign in or create account"},{"key":"account_menu.signed_out_state.section_divider","value":"More ways to sign in"},{"key":"account_menu.signed_out_state.alternate_divider","value":"OR"},{"key":"account_menu.signed_out_state.email_field_label","value":"Email"},{"key":"account_menu.signed_out_state.orders_button","value":"Orders"},{"key":"account_menu.signed_out_state.profile_button","value":"Profile"},{"key":"account_menu.signed_out_state.shop_login_button","value":"Sign in with Shop"},{"key":"account_menu.signed_out_state.continue_with_google","value":"Continue with Google"},{"key":"account_menu.signed_out_state.continue_with_facebook","value":"Continue with Facebook"},{"key":"account_menu.signed_out_state.marketing_consent_label","value":"Email me with news and offers"},{"key":"account_menu.signed_in_state.greeting_with_name","value":"Hi, {{first_name}}"},{"key":"account_menu.signed_in_state.greeting_without_name","value":"Account"},{"key":"account_menu.signed_in_state.orders_button","value":"Orders"},{"key":"account_menu.signed_in_state.profile_button","value":"Profile"},{"key":"account_menu.location_picker.sheet_title","value":"Locations"},{"key":"account_menu.location_picker.search_field_placeholder","value":"Search"},{"key":"account_menu.aria_labels.close_menu","value":"Close menu"},{"key":"account_menu.aria_labels.back_to_main_menu","value":"Back to main menu from {{title}}"},{"key":"account_menu.aria_labels.open_submenu","value":"{{title}}, opens submenu"},{"key":"account_menu.aria_labels.loading_menu","value":"Loading menu"},{"key":"account_menu.aria_labels.account","value":"Account"},{"key":"account_menu.aria_labels.sign_in_with_email","value":"Sign in with email"},{"key":"account_menu.aria_labels.sign_in","value":"Sign in"}],"socialLoginProviders":[{"handle":"Shop"}],"legacyCustomerAccounts":false,"signInLinksVisible":true,"b2bEnabled":false,"marketingConsentSigninEnabled":false},"visitor":{"country":"US","language":"en"}}</script>
696 697<meta name="shopify-y" content="d773354e-3c82-406e-949a-e657b5f3ed04" data-expiration="1822650985000"><meta name="shopify-s" content="0139ce4d-9111-421e-917c-3e8f03b2bb9b" data-expiration="1791095185000"><meta name="new-cookie-storage-activated" content="t"> 698</head> 699 700 701 702 <body class="features--button-transition features--zoom-image color-scheme color-scheme--scheme-1"><template id="drawer-default-template"> 703 <div part="base"> 704 <div part="overlay"></div> 705 706 <div part="content"> 707 <header part="header"> 708 <slot name="header"></slot> 709 710 <dialog-close-button style="display: contents"> 711 <button type="button" part="close-button tap-area" aria-label="Close"><svg aria-hidden="true" focusable="false" fill="none" width="14" class="icon icon-close" viewBox="0 0 16 16"> 712 <path d="m1 1 14 14M1 15 15 1" stroke="currentColor" stroke-width="1.5"/> 713 </svg> 714 715 </button> 716 </dialog-close-button> 717 </header> 718 719 <div part="body"> 720 <slot></slot> 721 </div> 722 723 <footer part="footer"> 724 <slot name="footer"></slot> 725 </footer> 726 </div> 727 </div> 728</template><template id="modal-default-template"> 729 <div part="base"> 730 <div part="overlay"></div> 731 732 <div part="content"> 733 <header part="header"> 734 <slot name="header"></slot> 735 736 <dialog-close-button style="display: contents"> 737 <button type="button" part="close-button tap-area" aria-label="Close"><svg aria-hidden="true" focusable="false" fill="none" width="14" class="icon icon-close" viewBox="0 0 16 16"> 738 <path d="m1 1 14 14M1 15 15 1" stroke="currentColor" stroke-width="1.5"/> 739 </svg> 740 741 </button> 742 </dialog-close-button> 743 </header> 744 745 <div part="body"> 746 <slot></slot> 747 </div> 748 </div> 749 </div> 750</template><template id="popover-default-template"> 751 <div part="base"> 752 <div part="overlay"></div> 753 754 <div part="content"> 755 <header part="header"> 756 <slot name="header"></slot> 757 758 <dialog-close-button style="display: contents"> 759 <button type="button" part="close-button tap-area" aria-label="Close"><svg aria-hidden="true" focusable="false" fill="none" width="14" class="icon icon-close" viewBox="0 0 16 16"> 760 <path d="m1 1 14 14M1 15 15 1" stroke="currentColor" stroke-width="1.5"/> 761 </svg> 762 763 </button> 764 </dialog-close-button> 765 </header> 766 767 <div part="body"> 768 <slot></slot> 769 </div> 770 </div> 771 </div> 772</template><template id="header-search-default-template"> 773 <div part="base"> 774 <div part="overlay"></div> 775 776 <div part="content"> 777 <slot></slot> 778 </div> 779 </div> 780</template><template id="video-media-default-template"> 781 <slot></slot> 782 783 <svg part="play-button" fill="none" width="48" height="48" viewBox="0 0 48 48"> 784 <path fill-rule="evenodd" clip-rule="evenodd" d="M48 24c0 13.255-10.745 24-24 24S0 37.255 0 24 10.745 0 24 0s24 10.745 24 24Zm-18 0-9-6.6v13.2l9-6.6Z" fill="var(--play-button-background, #efefef)"/> 785 </svg> 786</template> 787<style> 788 /* ── OVERLAY ── */ 789#room-img-manager { 790 display: none; 791 position: fixed; 792 inset: 0; 793 z-index: 1005; 794 background: rgba(0, 0, 0, 0.55); 795 align-items: center; 796 justify-content: center; 797 padding: 20px; 798} 799 800/* ── CARD ── */ 801.rim-card { 802 width: min(460px, 96vw); 803 max-height: 90vh; 804 background: #ffffff; 805 color: #111; 806 border-radius: 22px; 807 box-shadow: 0 24px 60px rgba(0, 0, 0, 0.25); 808 display: flex; 809 flex-direction: column; 810 overflow: hidden; 811} 812 813/* ── HEADER ── */ 814.rim-head { 815 display: flex; 816 justify-content: space-between; 817 align-items: center; 818 padding: 18px 20px; 819 border-bottom: 1px solid rgba(0, 0, 0, 0.08); 820} 821 822.rim-section-label { 823 font-size: 11px; 824 letter-spacing: 0.1em; 825 text-transform: uppercase; 826 color: #96a6ff; 827 margin: 0; 828} 829 830.rim-close { 831 width: 30px; 832 height: 30px; 833 border-radius: 50%; 834 border: 1px solid rgba(0, 0, 0, 0.12); 835 background: #f5f5f5; 836 cursor: pointer; 837 color: #222; 838} 839 840.rim-close:hover { 841 background: #eaeaea; 842} 843 844/* ── SECTIONS ── */ 845.rim-section { 846 padding: 20px; 847 overflow-y: auto; 848} 849 850.rim-title { 851 margin-bottom: 16px; 852 color: #000000; 853} 854 855/* ── GRID: 3-column square tiles (better UI/UX) ── */ 856.rim-user-grid { 857 display: grid; 858 grid-template-columns: repeat(3, 1fr); /* 3 columns by default */ 859 gap: 12px; 860} 861
862#rim-demo-grid-container { 863 grid-template-columns: repeat(3, 1fr); 864} 865 866#rim-demo-grid-container .rim-thumb-btn, 867.rim-user-grid .rim-thumb-btn { 868 aspect-ratio: 4 / 3; /* square tiles for a consistent visual rhythm */ 869} 870 871/* ── THUMB ── */ 872.rim-thumb-btn { 873 position: relative; 874 border-radius: 12px; 875 overflow: hidden; 876 border: 1.5px solid transparent; 877 background: #f2f2f2; 878 cursor: pointer; 879 transition: transform 200ms ease, box-shadow 160ms ease, border-color 160ms ease; 880} 881 882.rim-thumb-btn img { 883 width: 100%; 884 height: 100%; 885 object-fit: cover; 886 transition: transform 300ms ease; 887} 888 889.rim-thumb-btn:hover { 890 border-color: #378ADD; 891 transform: translateY(-4px); 892 box-shadow: 0 8px 20px rgba(0,0,0,0.08); 893} 894 895.rim-thumb-btn:focus-visible { 896 outline: 3px solid rgba(55,138,221,0.18); 897 outline-offset: 2px; 898} 899 900.rim-thumb-btn:hover img { transform: scale(1.04); } 901 902.rim-empty { color: #6b7280; padding: 12px; text-align: center; font-size: 14px; } 903 904/* Add-tile removed: uploads now via the CTA for clearer UX */ 905 906/* ── CTA ── */ 907.rim-upload-cta { 908 margin: 0 20px 18px; 909 padding: 14px; 910 border-radius: 12px; 911 background: #378ADD; 912 border: none; 913 color: #fff; 914 font-size: 14px; 915 font-weight: 600; 916 cursor: pointer; 917} 918 919.rim-upload-cta:hover { 920 opacity: 0.92; 921} 922 923/* ── DIVIDER ── */ 924.rim-divider { 925 height: 1px; 926 background: rgba(0, 0, 0, 0.08); 927 margin: 4px 0; 928} 929 930/* ── DARK MODE ── */ 931@media (prefers-color-scheme: dark) { 932 .rim-card { background: #1e1e1e; color: #fff; } 933 .rim-head { border-bottom-color: rgba(255,255,255,0.08); } 934 .rim-close { background: #2c2c2c; color: #ccc; } 935 .rim-title {color: #ccc; } 936 .rim-thumb-btn { background: #2a2a2a; } 937} 938 939</style> 940 941<div id="room-img-manager"> 942 <div class="rim-card"> 943 944 <!-- HEADER --> 945 <div class="rim-head"> 946 <p class="rim-section-label">Visualize...</p> 947 <button class="rim-close" onclick="closeRoomManager()">✕</button> 948 </div> 949 950 <!-- USER SECTION --> 951 <div class="rim-section"> 952 <h3 class="rim-title">Upload Your Room</h3> 953 <div class="rim-user-grid" id="rim-grid-container"></div> 954 </div> 955 956 <!-- CTA --> 957 <button class="rim-upload-cta" id="rim-upload-cta-btn"> 958 Upload your room photo <span>— see it transformed</span> 959 </button> 960 961 <input type="file" id="rim-hidden-upload" accept="image/*" capture="environment" hidden /> 962 963 <!-- DIVIDER --> 964 <div class="rim-divider"></div> 965 966 <!-- DEMO SECTION --> 967 <div class="rim-section"> 968 <h3 class="rim-title">Try Our Demo Rooms</h3> 969 <div class="rim-user-grid" id="rim-demo-grid-container"></div> 970 </div> 971 972 </div> 973</div> 974
975<script src="//atlasruggallery.com/cdn/shop/t/47/assets/room1.js?v=110986185886360465611787370141"></script>
vendor: 2 bytes, line 975
975
976<script src="//atlasruggallery.com/cdn/shop/t/47/assets/room2.js?v=142485241580031055181787370141"></script>
vendor: 2 bytes, line 976
976
977<script src="//atlasruggallery.com/cdn/shop/t/47/assets/room3.js?v=85556423527414518071787370141"></script>
977 978
979<script> 980 (function() { 981 const ROOM_DB_NAME = 'RoomVisualizerDB'; 982 const ROOM_STORE = 'rooms'; 983 const ROOM_LIMIT = 3; 984 const DEMO_ROOMS = window.DEMO_ROOMS_DATA || []; 985 console.log('Loaded rooms:', DEMO_ROOMS); 986 const demoRoomBlobs = {}; 987 let activeDemoRugUrl = ''; 988 let activeDemoSizeStr = ''; 989 990 // IDB functions for demo caching (same as pyodide_controller.js) 991 const IDB_STORE = 'cacheStore'; 992 function openDB() { 993 return new Promise((resolve, reject) => { 994 const req = indexedDB.open('DiscoveryAIVisualizer', 1); 995 req.onupgradeneeded = (e) => { 996 if (!e.target.result.objectStoreNames.contains(IDB_STORE)) { 997 e.target.result.createObjectStore(IDB_STORE); 998 } 999 }; 1000 req.onsuccess = () => resolve(req.result); 1001 req.onerror = () => reject(req.error); 1002 }); 1003 } 1004 1005 async function idbGet(key) { 1006 try { 1007 const db = await openDB(); 1008 return new Promise((resolve, reject) => { 1009 const req = db.transaction(IDB_STORE, 'readonly').objectStore(IDB_STORE).get(key); 1010 req.onsuccess = () => resolve(req.result); 1011 req.onerror = () => reject(req.error); 1012 }); 1013 } catch (e) { console.warn("IDB Get Error", e); return null; } 1014 } 1015 1016 async function idbSet(key, value) { 1017 try { 1018 const db = await openDB(); 1019 return new Promise((resolve, reject) => { 1020 const req = db.transaction(IDB_STORE, 'readwrite').objectStore(IDB_STORE).put(value, key); 1021 req.onsuccess = () => { 1022 try { 1023 if (typeof window !== 'undefined' && String(key || '').startsWith('rv:mask:')) { 1024 try { window.dispatchEvent(new CustomEvent('maskCached', { detail: { key } })); } catch (_) {} 1025 } 1026 } catch (_) {} 1027 resolve(); 1028 }; 1029 req.onerror = () => reject(req.error); 1030 }); 1031 } catch (e) { console.warn("IDB Set Error", e); } 1032 } 1033 1034 let roomDbPromise = null; 1035 1036 function openRoomDb() { 1037 if (roomDbPromise) return roomDbPromise; 1038 roomDbPromise = new Promise((resolve, reject) => { 1039 const req = indexedDB.open(ROOM_DB_NAME, 1); 1040 req.onupgradeneeded = (evt) => { 1041 const db = evt.target.result; 1042 if (!db.objectStoreNames.contains(ROOM_STORE)) { 1043 const store = db.createObjectStore(ROOM_STORE, { keyPath: 'id' }); 1044 store.createIndex('createdAt', 'createdAt', { unique: false }); 1045 } 1046 }; 1047 req.onsuccess = (evt) => resolve(evt.target.result); 1048 req.onerror = () => reject(req.error || new Error('IndexedDB init failed')); 1049 }); 1050 return roomDbPromise; 1051 } 1052 1053 async function getRooms() { 1054 const db = await openRoomDb(); 1055 return new Promise((resolve, reject) => { 1056 const tx = db.transaction(ROOM_STORE, 'readonly'); 1057 const store = tx.objectStore(ROOM_STORE); 1058 const req = store.getAll(); 1059 req.onsuccess = () => { 1060 const list = Array.isArray(req.result) ? req.result : []; 1061 list.sort((a, b) => Number(b.createdAt || 0) - Number(a.createdAt || 0)); 1062 resolve(list); 1063 }; 1064 req.onerror = () => reject(req.error || new Error('Failed loading rooms')); 1065 }); 1066 } 1067 1068 async function saveRoom(roomObj) { 1069 const db = await openRoomDb(); 1070 const rooms = await getRooms(); 1071 /* FIFO: evict oldest entries beyond the limit */ 1072 const toDelete = rooms.slice(ROOM_LIMIT - 1); 1073 1074 return new Promise((resolve, reject) => { 1075 const tx = db.transaction(ROOM_STORE, 'readwrite'); 1076 const store = tx.objectStore(ROOM_STORE); 1077 1078 toDelete.forEach((entry) => { 1079 if (entry && entry.id !== roomObj.id) { 1080 try { store.delete(entry.id); } catch (_) {} 1081 } 1082 }); 1083 1084 store.put(roomObj); 1085 tx.oncomplete = () => resolve(roomObj); 1086 tx.onerror = () => reject(tx.error || new Error('Failed saving room')); 1087 }); 1088 } 1089 1090 function normalizeFilepath(filepath) { 1091 if (!filepath) return null; 1092 if (typeof filepath !== 'string') return null; 1093 return filepath; 1094 } 1095 1096 function normalizePoints(points) { 1097 if (!Array.isArray(points)) return []; 1098 return points 1099 .map((p) => { 1100 if (Array.isArray(p) && p.length >= 2) return [Number(p[0]), Number(p[1])]; 1101 if (p && typeof p === 'object' && p.x != null && p.y != null) return [Number(p.x), Number(p.y)]; 1102 return null; 1103 }) 1104 .filter((p) => Array.isArray(p) && Number.isFinite(p[0]) && Number.isFinite(p[1])); 1105 } 1106 1107 // track object URLs for thumbnails so we can revoke them when re-rendering 1108 let rimObjectUrls = []; 1109 1110 function openCacheDB() { 1111 return new Promise((resolve, reject) => { 1112 const req = indexedDB.open('DiscoveryAIVisualizer', 1);
1113 req.onupgradeneeded = (e) => { 1114 if (!e.target.result.objectStoreNames.contains('cacheStore')) { 1115 e.target.result.createObjectStore('cacheStore'); 1116 } 1117 }; 1118 req.onsuccess = () => resolve(req.result); 1119 req.onerror = () => reject(req.error || new Error('Cache DB open failed')); 1120 }); 1121 } 1122 1123 async function cacheSet(key, value) { 1124 try { 1125 const db = await openCacheDB(); 1126 1127 const tryPut = (v) => new Promise((resolve, reject) => { 1128 const tx = db.transaction('cacheStore', 'readwrite'); 1129 const req = tx.objectStore('cacheStore').put(v, key); 1130 req.onsuccess = () => resolve(); 1131 req.onerror = () => reject(req.error || new Error('IDB put failed')); 1132 }); 1133 1134 try { 1135 await tryPut(value); 1136 if (typeof window !== 'undefined' && String(key || '').startsWith('rv:mask:')) { 1137 try { window.dispatchEvent(new CustomEvent('maskCached', { detail: { key } })); } catch (_) {} 1138 } 1139 return; 1140 } catch (err) { 1141 try { 1142 const isBlob = (typeof Blob !== 'undefined' && value instanceof Blob) || (typeof File !== 'undefined' && value instanceof File); 1143 if (isBlob && typeof value.arrayBuffer === 'function') { 1144 const ab = await value.arrayBuffer(); 1145 const clone = new Blob([ab], { type: (value && value.type) || 'application/octet-stream' }); 1146 await tryPut(clone); 1147 if (typeof window !== 'undefined' && String(key || '').startsWith('rv:mask:')) { 1148 try { window.dispatchEvent(new CustomEvent('maskCached', { detail: { key } })); } catch (_) {} 1149 } 1150 return; 1151 } 1152 } catch (e) { 1153 console.warn('cacheSet blob fallback failed', e); 1154 } 1155 throw err; 1156 } 1157 } catch (e) { console.warn('cacheSet error', e); } 1158 } 1159 1160 async function cacheGet(key) { 1161 try { 1162 const db = await openCacheDB(); 1163 return new Promise((resolve, reject) => { 1164 const req = db.transaction('cacheStore', 'readonly').objectStore('cacheStore').get(key); 1165 req.onsuccess = () => resolve(req.result || null); 1166 req.onerror = () => reject(req.error || new Error('IDB get failed')); 1167 }); 1168 } catch (e) { console.warn('cacheGet error', e); return null; } 1169 } 1170 1171 function buildMaskCacheKey(roomUrlForApi, initialPoints) { 1172 function extractUploadPath(url) { 1173 try { 1174 return String(url).match(/\/uploads\/.+/)?.[0] || url; 1175 } catch (_) { 1176 return url; 1177 } 1178 } 1179 1180 const normalized = normalizePoints(initialPoints).map(([x, y]) => ({ x, y })); 1181 const uploadPath = extractUploadPath(roomUrlForApi); 1182 return 'rv:mask:' + btoa(uploadPath + JSON.stringify(normalized)); 1183 } 1184 1185 async function preloadDemoRooms() { 1186 await Promise.all(DEMO_ROOMS.map(async (room) => { 1187 try { 1188 if (!room || !room.roomUrlForApi || !Array.isArray(room.initialPoints) || !room.maskData) return; 1189 1190 const key = buildMaskCacheKey(room.roomUrlForApi, room.initialPoints); 1191 // Check if mask data is already cached in DiscoveryAIVisualizer IDB 1192 const existingMask = await cacheGet(key); 1193 if (!existingMask) { 1194 await cacheSet(key, room.maskData); 1195 console.log(`💾 Cached demo mask: ${room.id}`); 1196 } else { 1197 } 1198 1199 // Check if demo blob is already cached in DiscoveryAI IDB 1200 const blobCacheKey = `demoRoomBlob:${room.id}`; 1201 let cachedBlob = await cacheGet(blobCacheKey); 1202 1203 if (!cachedBlob) { 1204 // Fetch and cache the demo image blob 1205 console.log(`🔄 Fetching demo image: ${room.id}`); 1206 const demoAssetMap = { 1207 'living-room-x1': '//atlasruggallery.com/cdn/shop/t/47/assets/demo-room-1.jpg?v=1457', 1208 'living-room-xx1': '//atlasruggallery.com/cdn/shop/t/47/assets/demo-room-2.jpg?v=1457', 1209 'Open-room-x1': '//atlasruggallery.com/cdn/shop/t/47/assets/demo-room-3.jpg?v=1457' 1210 }; 1211 const fetchUrl = room.roomUrlForApi || demoAssetMap[room.id]; 1212 const res = await fetch(fetchUrl); 1213 if (!res.ok) throw new Error('Demo room image fetch failed: ' + res.status); 1214 cachedBlob = await res.blob(); 1215 // Persist the raw Blob in DiscoveryAI IDB for future use (small objects like images are fine) 1216 try { 1217 await cacheSet(blobCacheKey, cachedBlob); 1218 console.log(`💾 Cached demo blob (raw): ${room.id}`); 1219 } catch (e) { 1220 // Fallback: store a File if Blob store fails in some browsers 1221 try { 1222 const file = new File([cachedBlob], `${room.id}.${(cachedBlob && cachedBlob.type && cachedBlob.type.indexOf('png') !== -1) ? 'png' : 'jpg'}`, { type: cachedBlob.type || 'image/jpeg' }); 1223 await cacheSet(blobCacheKey, file); 1224 console.log(`💾 Cached demo blob (file fallback): ${room.id}`); 1225 // Keep cachedBlob as the original Blob for in-memory use 1226 } catch (err) { 1227 console.warn('Failed to persist demo blob to DiscoveryAI IDB', err); 1228 } 1229 } 1230 } else { 1231 } 1232 1233 // Store in memory for quick access (cachedBlob may be a Blob or a File) 1234 demoRoomBlobs[room.id] = cachedBlob; 1235 1236 } catch (e) { 1237 console.warn(`Demo preload failed: ${room && room.id ? room.id : 'unknown'}`, e); 1238 } 1239 })); 1240 1241 // Cache a temporary hard-coded session token to avoid getSessionToken calls for demo pics 1242 const existingToken = await cacheGet('Temporary-token-per-room-img-upload'); 1243 if (!existingToken) { 1244 await cacheSet('Temporary-token-per-room-img-upload', 'demo-token'); 1245 console.log('💾 Cached demo session token'); 1246 } else { 1247 } 1248 } 1249 1250 async function launchDemoRoom(roomId, rugUrl) { 1251 const room = DEMO_ROOMS.find((r) => r.id === roomId); 1252 if (!room || !rugUrl) return console.warn('Missing room or rugUrl:', roomId); 1253 if (!demoRoomBlobs[roomId]) { 1254 await preloadDemoRooms(); 1255 } 1256 const roomFile = demoRoomBlobs[roomId]; 1257 if (!roomFile) return console.warn('Demo blob not ready:', roomId); 1258 closeRoomManager(); 1259 1260 const fakeApiResponse = { 1261 filepath: room.roomUrlForApi.replace('https://api.productadvisorai.com/', ''), 1262 points: room.initialPoints, 1263 }; 1264 1265 const key = buildMaskCacheKey(room.roomUrlForApi, room.initialPoints); 1266 await cacheSet(key, room.maskData); 1267 1268 // NEW: Sync local storage and IDB so the visualizer doesn't pull the wrong mask on refresh 1269 localStorage.setItem('analysis_filepath', JSON.stringify(fakeApiResponse.filepath)); 1270 localStorage.setItem('analysis_points', JSON.stringify(fakeApiResponse.points)); 1271 await cacheSet('currentRoomImageBlob', roomFile); 1272 1273 // NEW: Re-bind the session to the demo room 1274 if (typeof window.bindPendingSessionToRoom === 'function') { 1275 const uploadPath = room.roomUrlForApi.match(/\/uploads\/.+/)?.[0] || room.roomUrlForApi; 1276 window.bindPendingSessionToRoom(uploadPath).catch(() => {}); 1277 } 1278 1279 (function() { 1280 const _existingPending = window.pendingSeeInRoom || {}; 1281 window.pendingSeeInRoom = Object.assign({}, _existingPending, { 1282 rugUrl, 1283 sizeStr: _existingPending.sizeStr || activeDemoSizeStr || '', 1284 source: _existingPending.source || 'demo' 1285 });
1286 })(); 1287 1288 await window.handleAnalyzerSuccess(fakeApiResponse, roomFile, true); 1289} 1290 1291 function initDemoButtons(rugUrl, sizeStr, options = {}) { 1292 const demoSelectMode = !!(options && options.demoSelectMode); 1293 const onDemoSelect = options && typeof options.onDemoSelect === 'function' 1294 ? options.onDemoSelect 1295 : null; 1296 1297 if (typeof rugUrl === 'string' && rugUrl) { 1298 activeDemoRugUrl = rugUrl; 1299 } 1300 if (typeof sizeStr === 'string' && sizeStr) { 1301 activeDemoSizeStr = sizeStr; 1302 } 1303 1304 function trackVisualizerEvent(payload, legacyEventName) { 1305 if (typeof window.trackEvent === 'function') { 1306 window.trackEvent(payload.event, payload, { legacyEventName: legacyEventName }); 1307 try { 1308 window.dispatchEvent(new CustomEvent('visualizerAnalyticsEvent', { detail: payload })); 1309 } catch (_) {} 1310 return; 1311 } 1312 1313 window.dataLayer = window.dataLayer || []; 1314 window.dataLayer.push(payload); 1315 1316 if (legacyEventName) { 1317 window.dataLayer.push({ 1318 event: legacyEventName, 1319 product_handle: payload.product_handle, 1320 variant_id: payload.variant_id, 1321 page_type: payload.page_type, 1322 visualizer_event: payload.event, 1323 image_source: payload.image_source 1324 }); 1325 } 1326 1327 if (typeof window.gtag === 'function') { 1328 const params = Object.assign({}, payload); 1329 delete params.event; 1330 window.gtag('event', payload.event, params); 1331 if (legacyEventName) { 1332 window.gtag('event', legacyEventName, params); 1333 } 1334 } 1335 1336 try { 1337 window.dispatchEvent(new CustomEvent('visualizerAnalyticsEvent', { detail: payload })); 1338 } catch (_) {} 1339 } 1340 1341 preloadDemoRooms(); 1342 1343 DEMO_ROOMS.forEach((room) => { 1344 const btn = document.getElementById(`demo-btn-${room.id}`); 1345 if (!btn || btn.dataset.demoBound === '1') return; 1346 btn.dataset.demoBound = '1'; 1347 1348 btn.addEventListener('click', async () => { 1349 const variantInput = document.querySelector('input[name="id"]'); 1350 const variantId = variantInput ? variantInput.value : ''; 1351 const pdpBtn = document.getElementById('pdp-see-in-room'); 1352 const productHandle = pdpBtn ? pdpBtn.getAttribute('data-product-handle') : ''; 1353 const payload = { 1354 event: 'visualizer_demo_image_used', 1355 product_handle: productHandle, 1356 variant_id: variantId, 1357 image_source: 'demo', 1358 page_type: 'PDP' 1359 }; 1360 1361 trackVisualizerEvent(payload, 'see_in_room_click'); 1362 console.log('Event: visualizer_demo_image_used', payload); 1363 1364 if (demoSelectMode || !activeDemoRugUrl) { 1365 try { 1366 let demoBlob = demoRoomBlobs[room.id]; 1367 if (!demoBlob) { 1368 await preloadDemoRooms(); 1369 demoBlob = demoRoomBlobs[room.id]; 1370 } 1371 if (!demoBlob) throw new Error('Demo room blob unavailable'); 1372 1373 const demoFile = (typeof File !== 'undefined' && demoBlob instanceof File) 1374 ? demoBlob 1375 : blobToFile(demoBlob, `${room.id}.jpg`); 1376 1377 closeRoomManager(); 1378 if (onDemoSelect) { 1379 await onDemoSelect({ isCached: false, isNewUpload: true, file: demoFile, room }); 1380 } 1381 return; 1382 } catch (e) { 1383 console.warn('Demo room selection failed', e); 1384 return; 1385 } 1386 } 1387 1388 await launchDemoRoom(room.id, activeDemoRugUrl); 1389 }); 1390 }); 1391 } 1392 1393 async function renderDemoGrid() { 1394 const container = document.getElementById('rim-demo-grid-container'); 1395 if (!container) return; 1396 1397 // Ensure demo rooms are preloaded 1398 await preloadDemoRooms(); 1399 1400 // Clean up previous object URLs
1401 try { rimObjectUrls.forEach(u => URL.revokeObjectURL(u)); } catch (_) {} 1402 rimObjectUrls = []; 1403 1404 container.innerHTML = DEMO_ROOMS.map((room) => { 1405 const id = String(room.id || ''); 1406 const label = String(room.label || 'Demo room'); 1407 const blob = demoRoomBlobs[room.id]; 1408 let src = ''; 1409 1410 if (blob) { 1411 // Use cached blob URL for instant loading 1412 src = URL.createObjectURL(blob); 1413 rimObjectUrls.push(src); 1414 } else { 1415 // Blob should always be available after preloadDemoRooms() 1416 // If not, show a placeholder or loading state 1417 src = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwIiBoZWlnaHQ9IjEwMCIgdmlld0JveD0iMCAwIDEwMCAxMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIxMDAiIGhlaWdodD0iMTAwIiBmaWxsPSIjZjNmM2YzIi8+Cjx0ZXh0IHg9IjUwIiB5PSI1MCIgZm9udC1mYW1pbHk9IkFyaWFsLCBzYW5zLXNlcmlmIiBmb250LXNpemU9IjEyIiBmaWxsPSIjYWFhIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBkeT0iMC4zZW0iPkRlbW88L3RleHQ+Cjwvc3ZnPg=='; 1418 } 1419 1420 return `<button type="button" class="rim-thumb-btn" id="demo-btn-${id}" data-demo-room-id="${id}" aria-label="${label}"> 1421 <img src="${src}" alt="${label}" loading="eager" /> 1422 </button>`; 1423 }).join(''); 1424 } 1425 1426 function blobToFile(blob, fileName) { 1427 const type = (blob && blob.type) || 'image/jpeg'; 1428 return new File([blob], fileName || 'cached-room.jpg', { type }); 1429 } 1430 1431 function fileToBase64(file) { 1432 return new Promise((resolve, reject) => { 1433 const rd = new FileReader(); 1434 rd.onload = () => resolve(rd.result); 1435 rd.onerror = reject; 1436 rd.readAsDataURL(file); 1437 }); 1438 } 1439 1440 async function hydrateSelection(room) { 1441 if (!room) return null; 1442 1443 // NEW: Ensure points are formatted as objects to prevent cache-key mismatches 1444 const pointsToSave = (Array.isArray(room.points) ? room.points : []).map(p => { 1445 if (Array.isArray(p)) return { x: p[0], y: p[1] }; 1446 return p; 1447 }); 1448 1449 localStorage.setItem('analysis_filepath', JSON.stringify(room.filepath || null)); 1450 localStorage.setItem('analysis_points', JSON.stringify(pointsToSave)); 1451 1452 if (room.facts) { 1453 localStorage.setItem('last_analyzed_facts', JSON.stringify(room.facts)); 1454 } 1455 1456 let file = null; 1457 if (room.file) { 1458 file = room.file; 1459 } else if (room.blob) { 1460 file = blobToFile(room.blob, room.fileName || 'cached-room.jpg'); 1461 } else if (room.blobKey) { 1462 try { 1463 const maybeBlob = await cacheGet(room.blobKey); 1464 if (maybeBlob) file = blobToFile(maybeBlob, room.fileName || 'cached-room.jpg'); 1465 } catch (e) { 1466 console.warn('Failed to load room blob from cacheStore', e); 1467 } 1468 } else if (room.dataUrl) { 1469 const resp = await fetch(room.dataUrl); 1470 const blob = await resp.blob(); 1471 file = blobToFile(blob, room.fileName || 'cached-room.jpg'); 1472 } 1473 1474 // If we still don't have a File, try fetching from a URL (room.url or derived from filepath) 1475 if (!file) { 1476 let maybeUrl = room.dataUrl || room.url || null; 1477 if (!maybeUrl && room.filepath) { 1478 try { 1479 if (typeof IMAGE_ANALYSIS_API_URL !== 'undefined' && IMAGE_ANALYSIS_API_URL) { 1480 maybeUrl = IMAGE_ANALYSIS_API_URL.split('/api/')[0] + '/uploads/' + String(room.filepath).replace(/^uploads\//, '').replace(/^\//, ''); 1481 } else { 1482 maybeUrl = String(room.filepath || ''); 1483 } 1484 } catch (_) { maybeUrl = String(room.filepath || ''); } 1485 } 1486 1487 if (maybeUrl) { 1488 try { 1489 const resp = await fetch(maybeUrl); 1490 if (resp && (resp.ok || resp.type === 'opaque')) { 1491 const blob = await resp.blob(); 1492 if (blob && blob.size > 0) { 1493 file = blobToFile(blob, room.fileName || 'cached-room.jpg'); 1494 } 1495 } 1496 } catch (e) { 1497 console.warn('Failed to fetch room image from url', maybeUrl, e); 1498 } 1499 } 1500 } 1501 1502 if (file) { 1503 try { await idbSet('currentRoomImageBlob', file); } catch (e) { console.warn('Failed to cache selected room to IDB', e); } 1504 } 1505 1506 return file; 1507 } 1508 1509 function closeRoomManager() { 1510 const root = document.getElementById('room-img-manager'); 1511 if (root) { 1512 root.style.display = 'none'; 1513 root.setAttribute('aria-hidden', 'true'); 1514 } 1515 } 1516 1517 /* ── Render user-upload grid ── */ 1518 async function renderUserGrid() { 1519 const container = document.getElementById('rim-grid-container'); 1520 if (!container) return; 1521 const rooms = await getRooms(); 1522 1523 // Revoke any previously created object URLs to avoid leaks
1524 try { rimObjectUrls.forEach(u => URL.revokeObjectURL(u)); } catch (_) {} 1525 rimObjectUrls = []; 1526 1527 const thumbsArr = []; 1528 for (const room of rooms) { 1529 const id = String(room.id || ''); 1530 let src = room.dataUrl || ''; 1531 1532 if (!src) { 1533 if (room.file) { 1534 try { 1535 const objUrl = URL.createObjectURL(room.file); 1536 rimObjectUrls.push(objUrl); 1537 src = objUrl; 1538 } catch (_) { src = room.url || ''; } 1539 } else if (room.blobKey) { 1540 try { 1541 const maybeBlob = await cacheGet(room.blobKey); 1542 if (maybeBlob) { 1543 const objUrl = URL.createObjectURL(maybeBlob); 1544 rimObjectUrls.push(objUrl); 1545 src = objUrl; 1546 } else { 1547 src = room.url || ''; 1548 } 1549 } catch (e) { 1550 src = room.url || ''; 1551 } 1552 } 1553 } 1554 1555 thumbsArr.push(`<button type="button" class="rim-thumb-btn" data-room-id="${id}"> 1556 <img src="${src}" alt="Saved room" loading="lazy" /> 1557 </button>`); 1558 } 1559 const thumbs = thumbsArr.join(''); 1560 // Render saved thumbnails; if none exist show a subtle empty state. 1561 container.innerHTML = thumbs || '<div class="rim-empty" role="status">No saved rooms yet.</div>'; 1562 } 1563 1564 let currentCallback = null; 1565 1566 async function openRoomManager(callback, options) { 1567 currentCallback = typeof callback === 'function' ? callback : null; 1568 1569 const hideDemos = options && options.hideDemos; 1570 const demoSelectMode = !!(options && options.demoSelectMode); 1571 const demoGrid = document.getElementById('rim-demo-grid-container'); 1572 const demoSection = demoGrid ? demoGrid.closest('.rim-section') : null; 1573 const demoDivider = document.querySelector('#room-img-manager .rim-divider'); 1574 1575 if (hideDemos) { 1576 if (demoSection) demoSection.style.display = 'none'; 1577 if (demoGrid) demoGrid.style.display = 'none'; 1578 if (demoDivider) demoDivider.style.display = 'none'; 1579 } else { 1580 if (demoSection) demoSection.style.display = ''; 1581 if (demoGrid) demoGrid.style.display = ''; 1582 if (demoDivider) demoDivider.style.display = ''; 1583 await renderDemoGrid(); 1584 initDemoButtons(activeDemoRugUrl, activeDemoSizeStr, { 1585 demoSelectMode, 1586 onDemoSelect: currentCallback 1587 }); 1588 } 1589 1590 await renderUserGrid(); 1591 1592 const root = document.getElementById('room-img-manager'); 1593 if (root) { 1594 root.style.display = 'flex'; 1595 root.setAttribute('aria-hidden', 'false'); 1596 } 1597 } 1598 1599 async function prewarmDependencies() { 1600 try { 1601 if (typeof window.initializePyodide === 'function' && !window.isPyodideReady) { 1602 window.initializePyodide().catch(() => {}); 1603 } 1604 } catch (_) {} 1605 } 1606 1607 const hiddenUpload = document.getElementById('rim-hidden-upload'); 1608 1609 /* ── Small helper: create a thumbnail DOM node and wire selection ── */ 1610 function addThumb(container, src, insertBeforeAdd, file) { 1611 const btn = document.createElement('button'); 1612 btn.className = 'rim-thumb-btn'; 1613 btn.type = 'button'; 1614 btn.setAttribute('aria-label', 'Select room'); 1615 1616 const img = document.createElement('img'); 1617 img.loading = 'lazy'; 1618 img.decoding = 'async'; 1619 img.src = src; 1620 img.alt = 'Room preview'; 1621 img.onload = () => btn.classList.add('loaded'); 1622 img.onerror = () => btn.remove(); 1623 btn.appendChild(img); 1624 1625 // keep a reference to the File when available so click can forward it 1626 if (file instanceof File) btn._file = file; 1627 1628 btn.addEventListener('click', async () => { 1629 document.querySelectorAll('.rim-thumb-btn').forEach(t => t.classList.remove('selected')); 1630 btn.classList.add('selected'); 1631 1632 // If this thumb corresponds to a cached room id, use existing hydrate flow 1633 const roomId = btn.getAttribute('data-room-id'); 1634 if (roomId) { 1635 const rooms = await getRooms(); 1636 const selected = rooms.find(r => String(r.id) === String(roomId)); 1637 if (!selected) return; 1638 try { 1639 const fileFromCache = await hydrateSelection(selected); 1640 closeRoomManager(); 1641 if (currentCallback) currentCallback({ isCached: true, file: fileFromCache, room: selected }); 1642 } catch (e) { console.warn('hydrateSelection failed', e); } 1643 return; 1644 } 1645 1646 // Local file thumb: forward the File if we have it 1647 if (btn._file) { 1648 closeRoomManager(); 1649 if (currentCallback) currentCallback({ isCached: false, isNewUpload: true, file: btn._file }); 1650 return; 1651 } 1652 1653 // Fallback: fetch blob from blob: URL and turn into File 1654 try { 1655 if (img.src && img.src.startsWith('blob:')) { 1656 const resp = await fetch(img.src); 1657 const blob = await resp.blob(); 1658 const f = blobToFile(blob, 'room.jpg'); 1659 closeRoomManager(); 1660 if (currentCallback) currentCallback({ isCached: false, isNewUpload: true, file: f }); 1661 return; 1662 } 1663 } catch (e) { console.warn('Failed to fetch blob for thumb click', e); } 1664 1665 // If we get here we only have a URL — forward the URL as a fallback 1666 closeRoomManager(); 1667 if (currentCallback) currentCallback({ isCached: false, file: null, url: img.src }); 1668 }); 1669 1670 // If requested, insert new uploads at the start of the grid for prominence 1671 if (insertBeforeAdd && container.firstChild) container.insertBefore(btn, container.firstChild); 1672 else container.appendChild(btn); 1673 return btn; 1674 } 1675 1676 // Stub for upload/prepare logic. Replace with real upload/analyzer integration. 1677 function onFileReady(file, localUrl) { 1678 return new Promise((res) => setTimeout(() => res(localUrl), 700)); 1679 } 1680 1681 /* ── User grid clicks (cached rooms) ── */ 1682 const userGrid = document.getElementById('rim-grid-container'); 1683 if (userGrid) { 1684 userGrid.addEventListener('click', async (evt) => { 1685 const thumb = evt.target.closest('.rim-thumb-btn[data-room-id]'); 1686 if (!thumb) return; 1687 1688 const id = thumb.getAttribute('data-room-id'); 1689 const rooms = await getRooms(); 1690 const selected = rooms.find((r) => String(r.id) === String(id)); 1691 if (!selected) return; 1692 1693 try { 1694 const file = await hydrateSelection(selected); 1695 closeRoomManager(); 1696 if (currentCallback) currentCallback({ isCached: true, file, room: selected }); 1697 } catch (err) { 1698 console.warn('Failed to hydrate cached room:', err); 1699 } 1700 }); 1701 } 1702 1703 /* ── Upload CTA button ── */ 1704 const ctaBtn = document.getElementById('rim-upload-cta-btn'); 1705 if (ctaBtn) { 1706 ctaBtn.addEventListener('click', () => { 1707 // 🚀 INSTANT WAKE-UP: Fire the session token request the millisecond they click 'Upload' 1708 if (typeof window.getSessionToken === 'function') {
1709 window.getSessionToken(true).catch((error) => console.error('Error getting session token on Upload click:', error)); 1710 } 1711 if (hiddenUpload) hiddenUpload.click(); 1712 }); 1713 } 1714 1715 /* ── File input change: optimistic thumbnail rendering ── */ 1716 if (hiddenUpload) { 1717 hiddenUpload.addEventListener('change', () => { 1718 const file = hiddenUpload.files && hiddenUpload.files[0]; 1719 hiddenUpload.value = ''; 1720 if (!file) return; 1721 1722 const container = document.getElementById('rim-grid-container'); 1723 if (container) { 1724 const objectUrl = URL.createObjectURL(file); 1725 try { rimObjectUrls.push(objectUrl); } catch (_) {} 1726 1727 const thumb = addThumb(container, objectUrl, true, file); 1728 thumb.classList.add('uploading'); 1729 1730 // Replace this with the real upload/analyzer pipeline integration. 1731 onFileReady(file, objectUrl).then((finalUrl) => { 1732 thumb.classList.remove('uploading'); 1733 if (finalUrl && finalUrl !== objectUrl) { 1734 const img = thumb.querySelector('img'); 1735 if (img) img.src = finalUrl; 1736 try { URL.revokeObjectURL(objectUrl); } catch (_) {} 1737 } 1738 1739 // Close manager and forward to callback (preserve previous behavior) 1740 closeRoomManager(); 1741 if (currentCallback) currentCallback({ isCached: false, isNewUpload: true, file }); 1742 }).catch(() => { 1743 thumb.remove(); 1744 try { URL.revokeObjectURL(objectUrl); } catch (_) {} 1745 }); 1746 return; 1747 } 1748 1749 // Fallback to previous behavior 1750 closeRoomManager(); 1751 if (currentCallback) currentCallback({ isCached: false, isNewUpload: true, file }); 1752 }); 1753 } 1754 1755 /* ── Public API (unchanged surface) ── */ 1756 window.closeRoomManager = closeRoomManager; 1757 1758 window.DEMO_ROOMS = DEMO_ROOMS; 1759 window.preloadDemoRooms = preloadDemoRooms; 1760 window.launchDemoRoom = launchDemoRoom; 1761 window.initDemoButtons = initDemoButtons; 1762 1763 // Preload demo rooms on page load for instant loading 1764 if (document.readyState === 'loading') { 1765 document.addEventListener('DOMContentLoaded', () => preloadDemoRooms()); 1766 } else { 1767 preloadDemoRooms(); 1768 } 1769 1770 window.openRoomManager = async function(callback, options) { 1771 await prewarmDependencies(); 1772 return openRoomManager(callback, options); 1773 }; 1774 1775 window.roomImageCache = { 1776 getRooms, 1777 saveRoom, 1778 open: window.openRoomManager, 1779 async saveAnalyzedRoom(payload) { 1780 const file = payload && payload.file; 1781 const filepath = normalizeFilepath(payload && payload.filepath); 1782 const points = normalizePoints(payload && payload.points); 1783 if (!(file instanceof File) || !filepath) return null; 1784 const roomObj = { 1785 id: 'room_' + Date.now() + '_' + Math.random().toString(36).slice(2, 8), 1786 createdAt: Date.now(), 1787 // Do NOT store the raw File in the rooms DB (Safari/IDB can fail cloning nested Files). 1788 // Instead store a blobKey that references the binary in the shared cacheStore. 1789 fileName: file.name || 'room.jpg', 1790 filepath, 1791 points, 1792 facts: payload && payload.facts ? payload.facts : null, 1793 }; 1794 1795 // Ensure the single-source cache is populated for quick access 1796 try { await idbSet('currentRoomImageBlob', file); } catch (e) { console.warn('Failed to populate currentRoomImageBlob', e); } 1797 1798 // Persist the binary into the DiscoveryAI cacheStore under a unique key 1799 const blobKey = `roomBlob:${roomObj.id}`; 1800 try { 1801 await cacheSet(blobKey, file); 1802 roomObj.blobKey = blobKey; 1803 } catch (e) { 1804 console.warn('Failed to persist room blob into cacheStore', e); 1805 } 1806 1807 return saveRoom(roomObj); 1808 } 1809 }; 1810 })(); 1811</script>
1811 1812 1813 1814 1815 1816
1816<script> 1817 window.updateSizeInputs = function() { 1818 const shape = (document.getElementById('spec-shape')?.value || '').toLowerCase(); 1819 const container = document.getElementById('dynamic-size-container'); 1820 if (!container) return; 1821 1822 if (!shape) { 1823 container.innerHTML = ''; 1824 return; 1825 } 1826 1827 if (shape === 'round' || shape === 'square') { 1828 container.innerHTML = ` 1829 <div class="spec-field-group"> 1830 <label class="spec-field-label">${shape === 'round' ? 'Diameter' : 'Side'} Size</label> 1831 <div class="spec-inputs-row"> 1832 <div class="spec-input-wrapper"> 1833 <input type="number" id="spec-dia-ft" placeholder="0" min="0" class="spec-input"> 1834 <span class="spec-input-unit">ft</span> 1835 </div> 1836 <div class="spec-input-wrapper"> 1837 <input type="number" id="spec-dia-in" placeholder="0" min="0" max="11" class="spec-input"> 1838 <span class="spec-input-unit">in</span> 1839 </div> 1840 </div> 1841 </div> 1842 `; 1843 } else { 1844 container.innerHTML = ` 1845 <div class="spec-inputs-grid"> 1846 <div class="spec-field-group"> 1847 <label class="spec-field-label">Width</label> 1848 <div class="spec-inputs-row"> 1849 <div class="spec-input-wrapper"> 1850 <input type="number" id="spec-w-ft" placeholder="0" min="0" class="spec-input"> 1851 <span class="spec-input-unit">ft</span> 1852 </div> 1853 <div class="spec-input-wrapper"> 1854 <input type="number" id="spec-w-in" placeholder="0" min="0" max="11" class="spec-input"> 1855 <span class="spec-input-unit">in</span> 1856 </div> 1857 </div> 1858 </div> 1859 <div class="spec-field-group"> 1860 <label class="spec-field-label">Length</label> 1861 <div class="spec-inputs-row"> 1862 <div class="spec-input-wrapper"> 1863 <input type="number" id="spec-l-ft" placeholder="0" min="0" class="spec-input"> 1864 <span class="spec-input-unit">ft</span> 1865 </div> 1866 <div class="spec-input-wrapper"> 1867 <input type="number" id="spec-l-in" placeholder="0" min="0" max="11" class="spec-input"> 1868 <span class="spec-input-unit">in</span> 1869 </div> 1870 </div> 1871 </div> 1872 </div> 1873 `; 1874 } 1875 }; 1876 1877 window.handleColorChange = function(e) { 1878 const customInput = document.getElementById('spec-custom-color'); 1879 if (!customInput) return; 1880 if (e.target.value === 'Others') { 1881 customInput.style.display = 'block'; 1882 customInput.focus(); 1883 } else { 1884 customInput.style.display = 'none'; 1885 } 1886 }; 1887 1888 function openSpecsSearch() { 1889 const quizModal = document.getElementById('digi-mo-quiz-modal'); 1890 if (!quizModal) { 1891 console.warn('openSpecsSearch: digi-mo-quiz-modal not found in DOM.'); 1892 return; 1893 } 1894 quizModal.style.display = 'flex'; 1895 quizModal.style.pointerEvents = 'auto'; 1896 document.body.style.overflow = 'hidden'; 1897 1898 const colors = [ 1899 { value: "Beige", label: "Beige", swatch: "#d8c7a3" }, 1900 { value: "Black", label: "Black", swatch: "#111827" }, 1901 { value: "Blue", label: "Blue", swatch: "#3b82f6" }, 1902 { value: "Brown", label: "Brown", swatch: "#78350f" }, 1903 { value: "Gray", label: "Gray", swatch: "#9ca3af" }, 1904 { value: "Navy", label: "Navy", swatch: "#1e3a8a" }, 1905 { value: "Red", label: "Red", swatch: "#ef4444" }, 1906 { value: "White", label: "White", swatch: "#ffffff" }, 1907 { value: "Multi", label: "Multi", swatch: "linear-gradient(45deg,#ef4444,#3b82f6,#10b981)" } 1908 ]; 1909 1910 let colorChipsHtml = colors.map(c => ` 1911 <label> 1912 <input type="checkbox" name="spec_color" value="${c.value}" class="color-chip-input">
1913 <span class="color-chip-label"> 1914 <span class="color-dot" style="background:${c.swatch};"></span> 1915 <span>${c.label}</span> 1916 </span> 1917 </label> 1918 `).join(''); 1919 1920 quizModal.innerHTML = ` 1921 <div class="specs-search-container"> 1922 <button onclick="document.getElementById('digi-mo-quiz-modal').style.display='none'; document.body.style.overflow='';" class="close-specs-modal">×</button> 1923 <h2 class="specs-search-title">Find Your Perfect Rug</h2> 1924 1925 <div class="specs-fields-wrapper"> 1926 <div class="spec-field-group"> 1927 <label class="spec-field-label">Rug Shape</label> 1928 <select id="spec-shape" onchange="window.updateSizeInputs()" class="spec-select"> 1929 <option value="">Any Shape</option> 1930 <option value="Rectangle">Rectangle</option> 1931 <option value="Round">Round</option> 1932 <option value="Square">Square</option> 1933 <option value="Oval">Oval</option> 1934 <option value="Runner">Runner</option> 1935 </select> 1936 </div> 1937 1938 <div id="dynamic-size-container"></div> 1939 1940 <div class="spec-field-group"> 1941 <label class="spec-field-label">Color</label> 1942 <div class="color-options-grid"> 1943 ${colorChipsHtml} 1944 </div> 1945 </div> 1946 1947 <div class="spec-field-group"> 1948 <label class="spec-field-label">Style</label> 1949 <select id="spec-style" class="spec-select"> 1950 <option value="">Any Style</option> 1951 <option value="Traditional">Traditional</option> 1952 <option value="Modern">Modern</option> 1953 <option value="Transitional">Transitional</option> 1954 <option value="Bohemian">Bohemian</option> 1955 <option value="Geometric">Geometric</option> 1956 <option value="Persian">Persian</option> 1957 </select> 1958 </div> 1959 1960 <div class="spec-field-group"> 1961 <label class="spec-field-label">Material</label> 1962 <select id="spec-material" class="spec-select"> 1963 <option value="">Any Material</option> 1964 <option value="Wool">Wool</option> 1965 <option value="Cotton">Cotton</option> 1966 <option value="Jute">Jute</option> 1967 <option value="Silk">Silk</option> 1968 <option value="Viscose">Viscose</option> 1969 <option value="Polyester">Polyester</option> 1970 <option value="Polypropylene">Polypropylene</option> 1971 </select> 1972 </div> 1973 1974 <div class="submit-specs-btn-container"> 1975 <button id="submit-specs" class="submit-specs-btn"> 1976 Show Matching Rugs 1977 </button> 1978 </div> 1979 </div> 1980 </div> 1981 `; 1982 1983 window.updateSizeInputs(); 1984 1985 const submitSpecsBtn = document.getElementById('submit-specs'); 1986 if (submitSpecsBtn) { 1987 submitSpecsBtn.onclick = () => { 1988 const shape = document.getElementById('spec-shape')?.value || ""; 1989 let sizeStr = ""; 1990 1991 if (shape.toLowerCase() === 'round' || shape.toLowerCase() === 'square') { 1992 const ft = document.getElementById('spec-dia-ft')?.value || ""; 1993 const inch = document.getElementById('spec-dia-in')?.value || ""; 1994 if (ft || inch) { 1995 let dim = ft ? `${ft}'` : "0'"; 1996 if (inch) dim += `${inch}"`; 1997 sizeStr = shape.toLowerCase() === 'round' ? `${dim} round` : `${dim} square`; 1998 } 1999 } else { 2000 const wFt = document.getElementById('spec-w-ft')?.value || ""; 2001 const wIn = document.getElementById('spec-w-in')?.value || ""; 2002 const lFt = document.getElementById('spec-l-ft')?.value || ""; 2003 const lIn = document.getElementById('spec-l-in')?.value || ""; 2004 2005 let wStr = wFt ? `${wFt}'` : (wIn ? "0'" : ""); 2006 if (wIn) wStr += `${wIn}"`; 2007 let lStr = lFt ? `${lFt}'` : (lIn ? "0'" : ""); 2008 if (lIn) lStr += `${lIn}"`; 2009 2010 if (wStr && lStr) sizeStr = `${wStr} x ${lStr}`; 2011 else if (wStr) sizeStr = wStr; 2012 else if (lStr) sizeStr = lStr; 2013 } 2014 2015 const checkedColorNodes = document.querySelectorAll('input[name="spec_color"]:checked'); 2016 let colorsArr = Array.from(checkedColorNodes).map(n => n.value); 2017 2018 const style = document.getElementById('spec-style')?.value || ""; 2019 const material = document.getElementById('spec-material')?.value || ""; 2020 2021 const facts = { 2022 shape: shape || undefined, 2023 size: sizeStr ? [sizeStr] : undefined, 2024 color: colorsArr.length > 0 ? colorsArr : undefined, 2025 style: style ? [style] : undefined, 2026 material: material ? [material] : undefined, 2027 in_stock_only: true 2028 }; 2029 2030 quizModal.style.display = 'none'; 2031 quizModal.style.pointerEvents = 'none'; 2032 document.body.style.overflow = ''; 2033 executeStyleSearch(facts); 2034 }; 2035 } 2036 } 2037 2038 window.openSpecsSearch = openSpecsSearch; 2039 2040 document.addEventListener('DOMContentLoaded', () => { 2041 // Handle trigger clicks for Style UI (Specs Search) 2042 document.addEventListener('click', (e) => { 2043 const trigger = e.target.closest('.start-specs-search, #start-specs-search'); 2044 if (trigger) { 2045 e.preventDefault(); 2046 openSpecsSearch(); 2047 } 2048 }); 2049 }); 2050 2051 // Analytics Events 2052 document.addEventListener('DOMContentLoaded', function() {
2053 document.querySelector('#room-photo-btn')?.addEventListener('click', () => { 2054 window.dataLayer = window.dataLayer || []; 2055 window.dataLayer.push({ event: 'cta_room_photo' }); 2056 console.log('Event: cta_room_photo'); 2057 }); 2058 2059 document.querySelector('#start-guided-search')?.addEventListener('click', () => { 2060 window.dataLayer = window.dataLayer || []; 2061 window.dataLayer.push({ event: 'cta_rug_quiz' }); 2062 console.log('Event: cta_rug_quiz'); 2063 }); 2064 2065 document.querySelector('#start-specs-search')?.addEventListener('click', () => { 2066 window.dataLayer = window.dataLayer || []; 2067 window.dataLayer.push({ event: 'cta_specs_search' }); 2068 console.log('Event: cta_specs_search'); 2069 2070 if (typeof openSpecsSearch === 'function') { 2071 try { openSpecsSearch(); } catch (e) { console.error('openSpecsSearch threw an error:', e); } 2072 return; 2073 } 2074 2075 let attempts = 0; 2076 const retryId = setInterval(() => { 2077 if (typeof openSpecsSearch === 'function') { 2078 clearInterval(retryId); 2079 try { openSpecsSearch(); } catch (e) { console.error('openSpecsSearch threw an error on retry:', e); } 2080 return; 2081 } 2082 attempts++; 2083 if (attempts >= 20) { 2084 clearInterval(retryId); 2085 console.warn('openSpecsSearch not available after retries.'); 2086 } 2087 }, 100); 2088 }); 2089 2090 let heroCtaClicked = false; 2091 document.querySelector('#start-guided-search')?.addEventListener('click', () => heroCtaClicked = true); 2092 2093 const heroSection = document.getElementById('rug-hero'); 2094 if (heroSection) { 2095 const observer = new IntersectionObserver(entries => { 2096 entries.forEach(entry => { 2097 if (!entry.isIntersecting && !heroCtaClicked) { 2098 window.dataLayer = window.dataLayer || []; 2099 window.dataLayer.push({ event: 'hero_skipped' }); 2100 console.log('Event: hero_skipped'); 2101 } 2102 }); 2103 }, { threshold: 0 }); 2104 observer.observe(heroSection); 2105 } 2106 }); 2107 2108 2109 </script>
2109 2110
2110<script> 2111document.addEventListener('DOMContentLoaded', function () { 2112 const modal = document.getElementById('digi-mo-quiz-modal'); 2113 if (!modal) return; 2114 2115 function fixModalStyles() { 2116 modal.style.setProperty('position', 'fixed', 'important'); 2117 modal.style.setProperty('top', '0', 'important'); 2118 modal.style.setProperty('left', '0', 'important'); 2119 modal.style.setProperty('width', '100vw', 'important'); 2120 modal.style.setProperty('height', '100vh', 'important'); 2121 modal.style.setProperty('background', 'rgba(0,0,0,0.5)', 'important'); 2122 modal.style.setProperty('display', 'flex', 'important'); 2123 modal.style.setProperty('align-items', 'center', 'important'); 2124 modal.style.setProperty('justify-content', 'center', 'important'); 2125 modal.style.setProperty('z-index', '99999', 'important'); 2126 modal.style.setProperty('transform', 'none', 'important'); 2127 } 2128 2129 function closeModal() { 2130 modal.style.display = 'none'; 2131 document.body.style.overflow = ''; 2132 } 2133 2134 // Watch for when Discovery-Ai opens the modal 2135 const observer = new MutationObserver(function(mutations) { 2136 mutations.forEach(function(mutation) { 2137 if (mutation.attributeName === 'style') { 2138 const display = modal.style.display; 2139 if (display && display !== 'none') { 2140 fixModalStyles(); 2141 } 2142 } 2143 }); 2144 }); 2145 2146 observer.observe(modal, { attributes: true, attributeFilter: ['style'] }); 2147 2148 // Close button 2149 document.addEventListener('click', function(e) { 2150 if (e.target.classList.contains('close-specs-modal')) { 2151 e.stopPropagation(); 2152 closeModal(); 2153 } 2154 if (e.target === modal) { 2155 closeModal(); 2156 } 2157 }); 2158}); 2159</script>
2159 2160<style> 2161/* ===== RESULTS GRID ===== */ 2162.rug-cards-container { 2163 display: grid !important; 2164 grid-template-columns: repeat(4, 1fr) !important; 2165 gap: 1.25rem !important; 2166 padding: 1rem !important; 2167 overflow: visible !important; 2168} 2169 2170.rug-cards-scroll-wrapper { 2171 overflow: visible !important; 2172} 2173 2174.rug-cards-arrow { display: none !important; } 2175 2176/* ===== CARD ===== */ 2177.rug-card { 2178 background: #fff !important; 2179 border: 1px solid #e8e4de !important; 2180 display: flex !important; 2181 flex-direction: column !important; 2182 overflow: hidden !important; 2183 transition: box-shadow 0.2s, transform 0.2s !important; 2184 width: auto !important; 2185 min-width: unset !important; 2186 max-width: unset !important; 2187 flex-shrink: unset !important; 2188} 2189 2190.rug-card:hover { 2191 box-shadow: 0 6px 20px rgba(0,0,0,0.1) !important; 2192 transform: translateY(-2px) !important; 2193} 2194 2195/* ===== IMAGE ===== */ 2196.rug-card-img-link { 2197 display: block !important; 2198 position: relative !important; 2199 aspect-ratio: 1 !important; 2200 overflow: hidden !important; 2201 background: #f5f3ef !important; 2202} 2203 2204.rug-card-img-link img { 2205 width: 100% !important; 2206 height: 100% !important; 2207 object-fit: cover !important; 2208 transition: transform 0.3s ease !important; 2209} 2210 2211.rug-card:hover .rug-card-img-link img { 2212 transform: scale(1.04) !important; 2213} 2214 2215/* ===== BADGES ===== */ 2216.fs-ribbon { 2217 position: absolute !important; 2218 top: 10px !important; 2219 left: 0 !important; 2220 background: #1a1a1a !important; 2221 color: #fff !important; 2222 font-size: 0.62rem !important; 2223 font-weight: 700 !important; 2224 letter-spacing: 0.08em !important; 2225 padding: 0.2rem 0.6rem !important; 2226 z-index: 1 !important; 2227 text-transform: uppercase !important; 2228} 2229 2230.rt-sale { 2231 position: absolute !important; 2232 top: 10px !important; 2233 right: 10px !important; 2234 background: #c8922a !important; 2235 color: #fff !important; 2236 font-size: 0.62rem !important; 2237 font-weight: 700 !important; 2238 padding: 0.2rem 0.5rem !important; 2239 z-index: 1 !important; 2240} 2241 2242/* ===== CARD CONTENT ===== */ 2243.rug-card-content { 2244 padding: 0.85rem !important; 2245 display: flex !important; 2246 flex-direction: column !important; 2247 gap: 0.35rem !important; 2248 flex: 1 !important; 2249} 2250 2251.rug-title { 2252 font-size: 0.82rem !important; 2253 font-weight: 600 !important; 2254 color: #1a1a1a !important; 2255 line-height: 1.35 !important; 2256 display: -webkit-box !important; 2257 -webkit-line-clamp: 2 !important; 2258 -webkit-box-orient: vertical !important; 2259 overflow: hidden !important; 2260} 2261 2262.rug-title a { 2263 color: #1a1a1a !important; 2264 text-decoration: none !important; 2265} 2266 2267.rug-title a:hover { color: #c8922a !important; } 2268 2269/* FIX: brand name was white on white */ 2270.rug-info { 2271 font-size: 0.72rem !important; 2272 color: #666 !important; 2273 line-height: 1.4 !important; 2274} 2275 2276.rug-info span[style*="color:#ffffff"], 2277.rug-info span[style*="color: #ffffff"] { 2278 color: #c8922a !important; 2279 font-size: 0.7rem !important; 2280} 2281 2282.rug-info .sep { color: #ccc !important; } 2283 2284.rug-price { 2285 font-size: 0.95rem !important; 2286 font-weight: 700 !important; 2287 color: #1a1a1a !important; 2288 margin-top: 0.15rem !important; 2289} 2290 2291.rug-link { 2292 display: inline-block !important; 2293 font-size: 0.7rem !important; 2294 font-weight: 700 !important; 2295 color: #fff !important; 2296 text-decoration: none !important; 2297 text-transform: uppercase !important; 2298 letter-spacing: 0.06em !important; 2299 margin-top: auto !important; 2300 padding-top: 0.4rem !important; 2301 background:#c8922a !important; 2302 text-align:center; 2303 padding: 10px 20px; 2304} 2305 2306.rug-link:hover { text-decoration: underline !important; } 2307 2308/* ===== SEE IN MY ROOM BTN ===== */ 2309.rug-card .see-in-room-btn { 2310 width: 100% !important; 2311 padding: 0.55rem !important; 2312 margin-top: 0.5rem !important; 2313 background: transparent !important; 2314 border: 1.5px solid #c8922a !important; 2315 color: #c8922a !important; 2316 font-size: 0.68rem !important; 2317 font-weight: 700 !important; 2318 letter-spacing: 0.08em !important; 2319 cursor: pointer !important; 2320 text-transform: uppercase !important; 2321 transition: background 0.2s, color 0.2s !important; 2322 border-radius: 0 !important; 2323} 2324 2325.rug-card .see-in-room-btn:hover { 2326 background: #c8922a !important; 2327 color: #fff !important; 2328} 2329 2330/* ===== PAGINATION ===== */ 2331.pagination-controls { 2332 display: flex !important; 2333 align-items: center !important; 2334 justify-content: center !important; 2335 gap: 1rem !important; 2336 padding: 2rem 0 1rem !important; 2337} 2338 2339.pagination-btn { 2340 padding: 0.6rem 1.5rem !important; 2341 border: 1.5px solid #1a1a1a !important; 2342 background: transparent !important; 2343 color: #1a1a1a !important; 2344 font-size: 0.8rem !important; 2345 font-weight: 600 !important; 2346 cursor: pointer !important; 2347 transition: background 0.2s, color 0.2s !important; 2348} 2349 2350.pagination-btn:hover:not([disabled]) { 2351 background: #1a1a1a !important; 2352 color: #fff !important; 2353} 2354 2355.pagination-btn[disabled] { 2356 opacity: 0.35 !important;
2357 cursor: not-allowed !important; 2358} 2359 2360.pagination-info { 2361 font-size: 0.8rem !important; 2362 color: #888 !important; 2363} 2364 2365/* ===== RESPONSIVE ===== */ 2366@media (max-width: 1024px) { 2367 .rug-cards-container { 2368 grid-template-columns: repeat(3, 1fr) !important; 2369 } 2370} 2371@media (max-width: 768px) { 2372 .rug-cards-container { 2373 grid-template-columns: repeat(2, 1fr) !important; 2374 gap: 0.75rem !important; 2375 padding: 0.5rem !important; 2376 } 2377} 2378</style> 2379 2380 <loading-bar class="loading-bar" aria-hidden="true"></loading-bar> 2381 <a href="#main" allow-hash-change class="skip-to-content sr-only">Skip to content</a><div class="sr-only" role="status" aria-live="polite" aria-atomic="true"> 2382 <span id="status-announcement"></span> 2383 </div> 2384 2385 <div class="sr-only" role="alert" aria-live="assertive" aria-atomic="true"> 2386 <span id="error-announcement"></span> 2387 </div> 2388 2389 <span id="header-scroll-tracker" style="position: absolute; width: 1px; height: 1px; top: var(--header-scroll-tracker-offset, 10px); left: 0;"></span><!-- BEGIN sections: header-group --> 2390<header id="shopify-section-sections--20775072170028__header" class="shopify-section shopify-section-group-header-group shopify-section--header"><style> 2391 :root { 2392 --header-is-sticky: 1; 2393 } 2394 2395 #shopify-section-sections--20775072170028__header { 2396 --header-grid: "primary-nav logo secondary-nav" / minmax(0, 1fr) auto minmax(0, 1fr); 2397 --header-padding-block: 1rem; 2398 --header-transparent-header-text-color: 255 255 255; 2399 --header-separation-border-color: 28 28 28 / 0.15; 2400 2401 position: relative; 2402 z-index: 4; 2403 } 2404 2405 @media screen and (min-width: 700px) { 2406 #shopify-section-sections--20775072170028__header { 2407 --header-padding-block: 1.6rem; 2408 } 2409 } 2410 2411 @media screen and (min-width: 1000px) { 2412 #shopify-section-sections--20775072170028__header {--header-grid: "logo primary-nav secondary-nav" / auto minmax(0, 1fr) auto;} 2413 }#shopify-section-sections--20775072170028__header { 2414 position: sticky; 2415 top: 0; 2416 } 2417 2418 .shopify-section--announcement-bar ~ #shopify-section-sections--20775072170028__header { 2419 top: calc(var(--announcement-bar-is-sticky, 0) * var(--announcement-bar-height, 0px)); 2420 }#shopify-section-sections--20775072170028__header { 2421 --header-logo-width: 80px; 2422 } 2423 2424 @media screen and (min-width: 700px) { 2425 #shopify-section-sections--20775072170028__header { 2426 --header-logo-width: 130px; 2427 } 2428 }</style> 2429 2430<height-observer variable="header"> 2431 <x-header 2432 2433 class="header color-scheme color-scheme--scheme-2" 2434 > 2435 <a href="/" class="header__logo"><span class="sr-only">AtlasRugGallery</span><img src="//atlasruggallery.com/cdn/shop/files/B3C3302A-F421-4867-89D5-AB7E9ACAABCE.png?v=1775163853&width=2229" alt="AtlasRugGallery" srcset="//atlasruggallery.com/cdn/shop/files/B3C3302A-F421-4867-89D5-AB7E9ACAABCE.png?v=1775163853&width=260 260w, //atlasruggallery.com/cdn/shop/files/B3C3302A-F421-4867-89D5-AB7E9ACAABCE.png?v=1775163853&width=390 390w" width="2229" height="1784" sizes="130px" class="header__logo-image"></a> 2436 2437<nav 2438 class="header__primary-nav " 2439 aria-label="Primary navigation" 2440 > 2441 <button 2442 type="button" 2443 aria-controls="sidebar-menu" 2444 2445 class="md:hidden" 2446 2447 > 2448 <span class="sr-only">Navigation menu</span><svg aria-hidden="true" fill="none" focusable="false" width="24" class="header__nav-icon icon icon-hamburger" viewBox="0 0 24 24"> 2449 <path d="M1 19h22M1 12h22M1 5h22" stroke="currentColor" stroke-width="1.5" stroke-linecap="square"/> 2450 </svg></button><ul class="contents unstyled-list md-max:hidden"> 2451 2452 <li class="header__primary-nav-item"><a 2453 href="/" 2454 data-title="Home" 2455 class="block h6" 2456 2457 >Home</a></li> 2458 2459 <li class="header__primary-nav-item"><a 2460 href="/pages/rug-sales" 2461 data-title="Rug Sales" 2462 class="block h6" 2463 2464 >Rug Sales</a></li> 2465 2466 <li class="header__primary-nav-item"><a 2467 href="/pages/rug-cleaning" 2468 data-title="Rug cleaning" 2469 class="block h6" 2470 2471 >Rug cleaning</a></li> 2472 2473 <li class="header__primary-nav-item"><a 2474 href="/pages/persian-rug-cleaning" 2475 data-title="Persian Rug Cleaning" 2476 class="block h6" 2477 2478 >Persian Rug Cleaning</a></li> 2479 2480 <li class="header__primary-nav-item"><a 2481 href="/pages/rug-repair" 2482 data-title="RUG REPAIRS & RESTORATION" 2483 class="block h6" 2484 2485 >RUG REPAIRS & RESTORATION</a></li> 2486 2487 <li class="header__primary-nav-item"><a 2488 href="/pages/rug-pads" 2489 data-title="Rug Pads" 2490 class="block h6" 2491 2492 >Rug Pads</a></li> 2493 2494 <li class="header__primary-nav-item"><a 2495 href="/pages/our-story" 2496 data-title="Our story" 2497 class="block h6" 2498 2499 >Our story</a></li> 2500 2501 <li class="header__primary-nav-item"><a 2502 href="/pages/designers" 2503 data-title="Designers" 2504 class="block h6" 2505 2506 >Designers</a></li> 2507 2508 <li class="header__primary-nav-item"><a 2509 href="/pages/affiliates" 2510 data-title="Affilates" 2511 class="block h6" 2512 2513 >Affilates</a></li> 2514 2515 <li class="header__primary-nav-item"><a 2516 href="/pages/blogs-news" 2517 data-title="Blog" 2518 class="block h6" 2519 2520 >Blog</a></li> 2521 2522 <li class="header__primary-nav-item"><a 2523 href="/pages/contact" 2524 data-title="Contact" 2525 class="block h6" 2526 2527 >Contact</a></li></ul></nav><nav class="header__secondary-nav" aria-label="Secondary navigation"><ul class="contents unstyled-list"><li class="header__book-consultation-item sm-max:hidden"> 2528 <a href="/pages/get-a-quote" class="header__book-consultation-btn">Book Consultation</a> 2529 </li><li class="header__account-link sm-max:hidden"> 2530 <shopify-store store-domain="https://atlasruggallery.com" country="US" language="en"></shopify-store> 2531<shopify-account menu="customer-account-main-menu"> 2532 <div slot="signed-out-avatar"><svg aria-hidden="true" fill="none" focusable="false" width="24" class="header__nav-icon icon icon-account" viewBox="0 0 24 24">
2533 <path d="M16.125 8.75c-.184 2.478-2.063 4.5-4.125 4.5s-3.944-2.021-4.125-4.5c-.187-2.578 1.64-4.5 4.125-4.5 2.484 0 4.313 1.969 4.125 4.5Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> 2534 <path d="M3.017 20.747C3.783 16.5 7.922 14.25 12 14.25s8.217 2.25 8.984 6.497" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10"/> 2535 </svg></div> 2536 </shopify-account> 2537 </li><li class="header__search-link"> 2538 <a href="/search" aria-controls="header-search-sections--20775072170028__header"> 2539 <span class="sr-only">Search</span><svg aria-hidden="true" fill="none" focusable="false" width="24" class="header__nav-icon icon icon-search" viewBox="0 0 24 24"> 2540 <path d="M10.364 3a7.364 7.364 0 1 0 0 14.727 7.364 7.364 0 0 0 0-14.727Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10"/> 2541 <path d="M15.857 15.858 21 21.001" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round"/> 2542 </svg></a> 2543 </li><li class="relative header__cart-link"> 2544 <a 2545 href="/cart" 2546 2547 data-no-instant 2548 > 2549 <span class="sr-only">Cart</span><svg aria-hidden="true" fill="none" focusable="false" width="24" class="header__nav-icon icon icon-cart" viewBox="0 0 24 24"><path d="M4.75 8.25A.75.75 0 0 0 4 9L3 19.125c0 1.418 1.207 2.625 2.625 2.625h12.75c1.418 0 2.625-1.149 2.625-2.566L20 9a.75.75 0 0 0-.75-.75H4.75Zm2.75 0v-1.5a4.5 4.5 0 0 1 4.5-4.5v0a4.5 4.5 0 0 1 4.5 4.5v1.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg><cart-dot class="header__cart-dot "></cart-dot> 2550 </a> 2551 </li> 2552 </ul> 2553 </nav><header-search id="header-search-sections--20775072170028__header" class="header-search"> 2554 <div class="container"> 2555 <form id="predictive-search-form" action="/search" method="GET" aria-owns="header-predictive-search" class="header-search__form" role="search"> 2556 <div class="header-search__form-control"><svg aria-hidden="true" fill="none" focusable="false" width="20" class="icon icon-search" viewBox="0 0 24 24"> 2557 <path d="M10.364 3a7.364 7.364 0 1 0 0 14.727 7.364 7.364 0 0 0 0-14.727Z" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10"/> 2558 <path d="M15.857 15.858 21 21.001" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10" stroke-linecap="round"/> 2559 </svg><input 2560 type="search" 2561 name="q" 2562 spellcheck="false" 2563 class="header-search__input h5 sm:h4" 2564 aria-label="Search" 2565 placeholder="Search for..." 2566 > 2567 2568 <dialog-close-button class="contents"> 2569 <button type="button"> 2570 <span class="sr-only">Close</span><svg aria-hidden="true" focusable="false" fill="none" width="16" class="icon icon-close" viewBox="0 0 16 16"> 2571 <path d="m1 1 14 14M1 15 15 1" stroke="currentColor" stroke-width="1.5"/> 2572 </svg> 2573 2574 </button> 2575 </dialog-close-button> 2576 </div> 2577 </form> 2578 2579 <predictive-search id="header-predictive-search" class="predictive-search"> 2580 <div class="predictive-search__content" slot="results"></div> 2581 </predictive-search> 2582 </div> 2583</header-search> 2584<template id="header-sidebar-template"> 2585 <div part="base"> 2586 <div part="overlay"></div> 2587 2588 <div part="content"> 2589 <header part="header"> 2590 <dialog-close-button class="contents"> 2591 <button type="button" part="close-button tap-area" aria-label="Close"><svg aria-hidden="true" focusable="false" fill="none" width="16" class="icon icon-close" viewBox="0 0 16 16"> 2592 <path d="m1 1 14 14M1 15 15 1" stroke="currentColor" stroke-width="1.5"/> 2593 </svg> 2594 2595 </button> 2596 </dialog-close-button> 2597 </header> 2598 2599 <div part="panel-list"> 2600 <slot name="main-panel"></slot><slot name="collapsible-panel"></slot></div> 2601 </div> 2602 </div> 2603</template> 2604 2605<header-sidebar id="sidebar-menu" class="header-sidebar drawer drawer--sm color-scheme color-scheme--scheme-2" template="header-sidebar-template" open-from="left"><div class="header-sidebar__main-panel" slot="main-panel"> 2606 <div class="header-sidebar__scroller"> 2607 <ul class="header-sidebar__linklist unstyled-list" role="list"><li><a href="/" class="header-sidebar__linklist-button h6">Home</a></li><li><a href="/pages/rug-sales" class="header-sidebar__linklist-button h6">Rug Sales</a></li><li><a href="/pages/rug-cleaning" class="header-sidebar__linklist-button h6">Rug cleaning</a></li><li><a href="/pages/persian-rug-cleaning" class="header-sidebar__linklist-button h6">Persian Rug Cleaning</a></li><li><a href="/pages/rug-repair" class="header-sidebar__linklist-button h6">RUG REPAIRS & RESTORATION</a></li><li><a href="/pages/rug-pads" class="header-sidebar__linklist-button h6">Rug Pads</a></li><li><a href="/pages/our-story" class="header-sidebar__linklist-button h6">Our story</a></li><li><a href="/pages/designers" class="header-sidebar__linklist-button h6">Designers</a></li><li><a href="/pages/affiliates" class="header-sidebar__linklist-button h6">Affilates</a></li><li><a href="/pages/blogs-news" class="header-sidebar__linklist-button h6">Blog</a></li><li><a href="/pages/contact" class="header-sidebar__linklist-button h6">Contact</a></li></ul> 2608 </div><div class="header-sidebar__footer"><shopify-account menu="customer-account-main-menu"> 2609 <div slot="signed-out-avatar"> 2610 <div class="text-with-icon smallcaps sm:hidden"><svg aria-hidden="true" fill="none" focusable="false" width="20" class="icon icon-account" viewBox="0 0 24 24">
2611 <path d="M16.125 8.75c-.184 2.478-2.063 4.5-4.125 4.5s-3.944-2.021-4.125-4.5c-.187-2.578 1.64-4.5 4.125-4.5 2.484 0 4.313 1.969 4.125 4.5Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/> 2612 <path d="M3.017 20.747C3.783 16.5 7.922 14.25 12 14.25s8.217 2.25 8.984 6.497" stroke="currentColor" stroke-width="1.5" stroke-miterlimit="10"/> 2613 </svg>Login</div> 2614 </div> 2615 </shopify-account></div></div><header-sidebar-collapsible-panel class="header-sidebar__collapsible-panel" slot="collapsible-panel"> 2616 <div class="header-sidebar__scroller"></div> 2617 </header-sidebar-collapsible-panel></header-sidebar> 2618</x-header> 2619</height-observer> 2620
2621<script> 2622 document.documentElement.style.setProperty('--header-height', `${document.getElementById('shopify-section-sections--20775072170028__header').clientHeight.toFixed(2)}px`); 2623</script>
2623 2624 2625 2626</header> 2627<!-- END sections: header-group --><!-- BEGIN sections: overlay-group --> 2628<section id="shopify-section-sections--20775072137260__cart-drawer" class="shopify-section shopify-section-group-overlay-group shopify-section--cart-drawer"><cart-drawer 2629 id="cart-drawer" 2630 aria-label="Cart" 2631 class="cart-drawer drawer drawer--center-body color-scheme color-scheme--scheme-1" 2632 initial-focus="false" 2633 handle-editor-events 2634> 2635 <p class="h4" slot="header">Cart</p><p class="h5 text-center">Your cart is empty</p></cart-drawer> 2636 2637 2638</section><div id="shopify-section-sections--20775072137260__newsletter-popup" class="shopify-section shopify-section-group-overlay-group shopify-section--popup"> 2639</div> 2640<!-- END sections: overlay-group --><main id="main" class="anchor"> 2641 <section id="shopify-section-template--20775071744044__main" class="shopify-section shopify-section--main-cart"><div class="section-spacing section-spacing--tight color-scheme color-scheme--scheme-1 color-scheme--bg-609ecfcfee2f667ac6c12366fc6ece56"><div class="container container--xs"> 2642 <div class="empty-state"> 2643 <div class="prose"> 2644 <h1 class="h4">Cart</h1> 2645 <p>Your cart is empty</p> 2646<a class="button" href="/collections/all" >Continue shopping</a></div> 2647 </div> 2648 </div></div> 2649 2650 2651</section> 2652<!-- BEGIN sections: footer-group --> 2653<div id="shopify-section-sections--20775072202796__footer" class="shopify-section shopify-section-group-footer-group"><style> 2654 :root { 2655 --footer-bg: #faf8f4; 2656 --footer-text: #1a1a1a; 2657 --footer-heading: #1a1a1a; 2658 --footer-accent: #c9a042; 2659 --footer-border: #e5e0d5; 2660 } 2661 2662 .custom-footer { 2663 background-color: var(--footer-bg); 2664 color: var(--footer-text); 2665 padding: 56px 0 0; 2666 text-align: left; 2667 font-family: Nunito, sans-serif; 2668 } 2669 2670 .footer-grid { 2671 max-width: 1440px; 2672 margin: 0 auto; 2673 padding: 0 40px; 2674 display: flex; 2675 flex-wrap: wrap; 2676 justify-content: flex-start; 2677 gap: 40px 60px; 2678 } 2679 .footer-brand-name { 2680 font-size: 22px; 2681 letter-spacing: 0.12em; 2682 font-family: Quicksand, sans-serif; 2683 margin: 0 0 16px; 2684 } 2685 2686 .footer-col { 2687 flex: 1 1 160px; 2688 min-width: 160px; 2689 display: flex; 2690 flex-direction: column; 2691 align-items: flex-start; 2692 } 2693 2694 .footer-col.brand-info { 2695 flex: 1.4 1 240px; 2696 min-width: 220px; 2697 } 2698 2699 /* Info Column Styling */ 2700 .footer-logo { 2701 width: auto; 2702 max-width: 210px; 2703 max-height: 130px; 2704 margin-bottom: 24px; 2705 display: block; 2706 } 2707 .brand-info p { 2708 font-size: 13.5px; 2709 line-height: 1.7; 2710 margin: 0 0 18px; 2711 opacity: 0.75; 2712 } 2713 .contact-list { 2714 list-style: none; 2715 padding: 0; 2716 margin: 0 0 24px; 2717 } 2718 .contact-list li { 2719 font-size: 13px; 2720 margin-bottom: 12px; 2721 display: flex; 2722 align-items: flex-start; 2723 gap: 8px; 2724 opacity: 0.8; 2725 } 2726 .contact-list a { 2727 color: var(--footer-text); 2728 text-decoration: none; 2729 } 2730 .contact-list a:hover { 2731 color: var(--footer-accent); 2732 } 2733 2734 /* Social Icons */ 2735 .footer-col .social-media { 2736 display: flex; 2737 justify-content: flex-start; 2738 gap: 15px; 2739 list-style: none; 2740 padding: 0; 2741 margin: 0; 2742 } 2743 .footer-col .social-media__item a { 2744 color: var(--footer-text); 2745 fill: var(--footer-text); 2746 opacity: 0.8; 2747 transition: opacity 0.2s, color 0.2s; 2748 } 2749 .footer-col .social-media__item a:hover { 2750 opacity: 1; 2751 color: var(--footer-accent); 2752 fill: var(--footer-accent); 2753 } 2754 2755 /* Menu Columns Styling */ 2756 .footer-col h2 { 2757 color: var(--footer-heading); 2758 font-size: 12.5px; 2759 font-weight: 700; 2760 margin: 0 0 24px; 2761 text-transform: uppercase; 2762 letter-spacing: 0.1em; 2763 font-family: Quicksand, sans-serif; 2764 } 2765 .footer-menu { 2766 list-style: none; 2767 padding: 0; 2768 margin: 0; 2769 } 2770 .footer-menu li { 2771 margin-bottom: 15px; 2772 } 2773 .footer-menu a { 2774 position: relative; 2775 display: inline-block; 2776 color: var(--footer-text); 2777 text-decoration: none; 2778 font-size: 13px; 2779 opacity: 0.75; 2780 padding-bottom: 2px; 2781 transition: color 0.2s, opacity 0.2s; 2782 } 2783 .footer-menu a::after { 2784 content: ""; 2785 position: absolute; 2786 left: 0; 2787 bottom: 0; 2788 width: 0; 2789 height: 1px; 2790 background: var(--footer-accent); 2791 transition: width 0.25s ease; 2792 } 2793 .footer-menu a:hover { 2794 color: var(--footer-accent); 2795 opacity: 1; 2796 } 2797 .footer-menu a:hover::after { 2798 width: 100%; 2799 } 2800 .footer-hours { 2801 font-size: 13px; 2802 line-height: 1.7; 2803 opacity: 0.8; 2804 margin: 0 0 14px; 2805 } 2806 .footer-hours__label { 2807 display: block; 2808 font-weight: 700; 2809 opacity: 1; 2810 margin-bottom: 4px; 2811 } 2812 .footer-directions { 2813 display: inline-block; 2814 font-size: 13px; 2815 font-weight: 600; 2816 color: var(--footer-accent); 2817 text-decoration: none; 2818 } 2819 .footer-directions:hover { text-decoration: underline; } 2820 2821 /* Newsletter Styling */ 2822 .newsletter-col p { 2823 font-size: 13px; 2824 line-height: 1.5; 2825 margin: 0 0 16px; 2826 opacity: 0.8; 2827 } 2828 .newsletter-form { 2829 display: flex; 2830 flex-direction: column; 2831 gap: 12px; 2832 width: 100%; 2833 } 2834 .newsletter-input { 2835 width: 100%; 2836 padding: 12px 16px; 2837 background: transparent; 2838 border: 1px solid var(--footer-border); 2839 color: var(--footer-text); 2840 font-size: 13px; 2841 outline: none; 2842 } 2843 .newsletter-input::placeholder { 2844 color: var(--footer-text); 2845 opacity: 0.5; 2846 } 2847 .newsletter-btn { 2848 padding: 12px 16px; 2849 background-color: var(--footer-text); 2850 color: var(--footer-bg); 2851 border: none; 2852 font-size: 12px; 2853 font-weight: 700; 2854 letter-spacing: 0.1em; 2855 text-transform: uppercase; 2856 cursor: pointer; 2857 transition: opacity 0.2s; 2858 } 2859 .newsletter-btn:hover { 2860 opacity: 0.8; 2861 } 2862 2863 /* Bottom Bar */ 2864 .bottom-bar { 2865 max-width: 1440px; 2866 margin: 40px auto 0; 2867 padding: 20px 40px; 2868 border-top: 1px solid var(--footer-border); 2869 display: flex; 2870 justify-content: space-between; 2871 align-items: center; 2872 flex-wrap: wrap; 2873 gap: 20px; 2874 } 2875 .bottom-bar-left { 2876 font-size: 12px; 2877 opacity: 0.7; 2878 } 2879 .footer-powered { 2880 display: inline-block; 2881 margin-left: 10px; 2882 padding-left: 10px; 2883 border-left: 1px solid var(--footer-border); 2884 } 2885 .footer-powered a { color: var(--footer-accent); text-decoration: none; font-weight: 600; } 2886 .footer-powered a:hover { text-decoration: underline; } 2887 @media (max-width: 990px) { 2888 .footer-powered { display: block; margin-left: 0; padding-left: 0; border-left: none; margin-top: 6px; } 2889 } 2890 .bottom-bar-center { 2891 display: flex; 2892 gap: 20px; 2893 } 2894 .bottom-bar-center a { 2895 color: var(--footer-text); 2896 text-decoration: none; 2897 font-size: 11.5px; 2898 letter-spacing: 0.04em; 2899 text-transform: uppercase; 2900 opacity: 0.65; 2901 transition: color 0.2s, opacity 0.2s; 2902 } 2903 .bottom-bar-center a:hover { 2904 color: var(--footer-accent); 2905 opacity: 1; 2906 } 2907 .bottom-bar-right { 2908 display: flex; 2909 gap: 8px; 2910 opacity: 0.8; 2911 } 2912 .bottom-bar-right svg { 2913 width: 38px; 2914 height: 24px; 2915 } 2916 2917 /* Responsive */ 2918 @media (max-width: 990px) { 2919 .footer-col, 2920 .footer-col.brand-info { 2921 flex: 1 1 45%; 2922 min-width: 45%; 2923 } 2924 .bottom-bar { 2925 flex-direction: column; 2926 text-align: center; 2927 } 2928 } 2929 @media (max-width: 600px) { 2930 .footer-col, 2931 .footer-col.brand-info { 2932 flex: 1 1 100%; 2933 min-width: 100%; 2934 } 2935 .footer-grid { 2936 padding: 0 20px; 2937 } 2938 .bottom-bar { 2939 padding: 24px 20px; 2940 } 2941 } 2942</style> 2943 2944<footer class="custom-footer"> 2945 <div class="footer-grid"> 2946 2947 <!-- Brand --><div class="footer-col brand-info"> 2948 2949 <img src="//atlasruggallery.com/cdn/shop/files/B3C3302A-F421-4867-89D5-AB7E9ACAABCE.png?v=1775163853&width=400" class="footer-logo" alt="AtlasRugGallery"> 2950 2951 <p>Premium rugs and personalized service for your home.</p> 2952 </div> 2953 2954 <!-- Showroom --> 2955 2956 2957 <!-- Menus --> 2958 2959 2960 <div class="footer-col" > 2961 <h2>Shop</h2> 2962 <ul class="footer-menu"> 2963 2964 2965 2966 2967 <li><a href="/">Home</a></li> 2968 2969 2970 2971 2972 2973 <li><a href="/pages/rug-pads">Rug Pads</a></li> 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 </ul> 2993 </div> 2994 2995 2996 2997 <div class="footer-col" > 2998 <h2>Services</h2> 2999 <ul class="footer-menu"> 3000 3001 3002 3003 3004 <li><a href="/pages/persian-rug-cleaning">Persian Rug Cleaning</a></li> 3005 3006 3007 3008 3009 3010 <li><a href="/pages/rug-cleaning">Rug Cleaning</a></li> 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 </ul> 3030 </div> 3031 3032 3033 3034 <div class="footer-col" > 3035 <h2>Company</h2> 3036 <ul class="footer-menu"> 3037 3038 3039 3040 3041 <li><a href="/pages/about">Our Story</a></li> 3042 3043 3044 3045 3046 3047 <li><a href="/pages/designers">Designers</a></li> 3048 3049 3050 3051 3052 3053 <li><a href="/pages/affiliates">Affiliates</a></li> 3054 3055 3056 3057 3058 3059 <li><a href="/blogs/news">Blog</a></li> 3060 3061 3062 3063 3064 3065 <li><a href="/pages/contact">Contact</a></li> 3066 3067 3068 3069 3070 3071 3072 </ul> 3073 </div> 3074 3075 3076 3077 <!-- Follow Us --></div> 3078 3079 <div class="bottom-bar"> 3080 <div class="bottom-bar-left"> 3081 © 2026, AtlasRugGallery. All Rights Reserved.<span class="footer-powered">Powered by <a href="https://thediscovery.ai" target="_blank" rel="noopener noreferrer">Discovery-Ai LLC</a></span></div> 3082 <div class="bottom-bar-center"> 3083 <a href="/policies/refund-policy">Return Policy</a> 3084 <a href="/policies/privacy-policy">Privacy Policy</a> 3085 <a href="/policies/terms-of-service">Terms of Service</a> 3086 <a href="/sitemap.xml">Sitemap</a> 3087 </div> 3088 <div class="bottom-bar-right"> 3089 3090 </div> 3091 </div> 3092</footer> 3093 3094 3095</div> 3096<!-- END sections: footer-group --></main> 3097
3097<script src="https://cdn.shopify.com/storefront/standard-actions.js" type="module" data-source-attribution="shopify.standard_actions"></script>
3097 3098</body> 3099</html>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.