站点详情页(跳转前展示目标站点 TDK 信息)
CGTrader - 3D Models And 3D Printing Marketplace
www.cgtrader.com
Explore 2M+ 3D models online for print, game, VR/AR & design projects. Download, customize, or hire 3D experts - all on CGTrader.
关键词:176977842455249" property="fb:app_id" />.btn{padding:.5rem 1.5rem;font-size:1rem;line-height:1.5;border-radius:3px;display:inline-block;text-align:center;text-decoration:none;white-space:nowrap;vertical-align:middle;border:0 solid transparent}.btn-primary{color:#fff;background-color:#41a48f}.btn-sm{padding:.25rem 1rem;font-size:.875rem;line-height:1.5;border-radius:2px}.notice{font-size:.875rem;position:fixed;bottom:42px;left:0;z-index:448;width:100%;background-color:#3f444c;padding:20px 30px;color:#fff;text-align:left}.notice .btn{display:block;width:100px;margin:15px auto 0}.notice .notice-content{position:relative}.notice .close-notice{position:absolute;top:-5px;right:-15px}@media (min-width: 576px){.notice{bottom:0;padding:10px 25px;text-align:center}.notice .btn{display:inline-block;margin:0 0 0 15px}.notice .close-notice{top:0;right:-10px}}.link--darker{color:#19bcc9}.timer-strip{background-color:#159ca9;padding:1.25rem;text-align:center;color:#fff;letter-spacing:.5px}.timer-strip.is-secondary-color{background:linear-gradient(90.05deg, #a91e4c 0, #cc2795 52.4%, #a91e4a 100%)}.timer-strip .timer-row{line-height:2}.timer-strip .timer-strip__item{display:inline-flex;height:24px;vertical-align:middle;line-height:24px;font-size:16px;font-weight:600}.timer-strip .timer-strip__item:first-child{padding-left:0}.timer-strip .timer-strip__item .big-text{font-size:2.5rem;line-height:24px;letter-spacing:1px;font-weight:600}@media (min-width: 968px){.timer-strip .timer-strip__item .big-text{font-weight:800}}.timer-strip .timer-strip__item--info{font-size:16px}@media (min-width: 640px){.timer-strip .timer-strip__item--info{font-size:20px}}.timer-strip--top-bar{width:100%;height:42px;z-index:500;text-decoration:none}.timer-strip--top-bar .timer-strip{font-size:1rem;padding:7px 0}.timer-strip--top-bar .timer-strip .timer-row{display:flex;align-items:center;justify-content:center;gap:32px;line-height:24px}@media (max-width: 340px){.timer-strip--top-bar .timer-strip .timer-row{gap:0;justify-content:space-between;padding-inline:5px}}.timer-strip--top-bar .timer-strip .big-text{font-size:1.0625rem;line-height:24px}.timer-strip--top-bar .timer-strip .timer-strip__item--text{font-weight:600;font-size:16px}.timer-strip--top-bar .timer-strip .timer-strip__item--content{display:none}@media (min-width: 968px){.timer-strip--top-bar .timer-strip .timer-strip__item--content{display:inline-flex}}.timer-strip--top-bar .timer-strip .timer-strip__item--button{height:28px;color:#097b95;background-color:#fff;border:none}.timer-strip--top-bar .timer-strip .timer-strip__item--time{display:none;background:rgba(255,255,255,0.16);border-radius:2px;padding:0 10px}@media (min-width: 640px){.timer-strip--top-bar .timer-strip .timer-strip__item--time{display:inline-flex;border:none}}.timer-strip--top-bar .timer-strip .timer-strip__item--info{font-weight:600}.timer-strip{background-color:#159ca9;padding:1.25rem;text-align:center;color:#fff;letter-spacing:.5px}.timer-strip.is-secondary-color{background:linear-gradient(90.05deg, #a91e4c 0, #cc2795 52.4%, #a91e4a 100%)}.timer-strip .timer-row{line-height:2}.timer-strip .timer-strip__item{display:inline-flex;height:24px;vertical-align:middle;line-height:24px;font-size:16px;font-weight:600}.timer-strip .timer-strip__item:first-child{padding-left:0}.timer-strip .timer-strip__item .big-text{font-size:2.5rem;line-height:24px;letter-spacing:1px;font-weight:600}@media (min-width: 968px){.timer-strip .timer-strip__item .big-text{font-weight:800}}.timer-strip .timer-strip__item--info{font-size:16px}@media (min-width: 640px){.timer-strip .timer-strip__item--info{font-size:20px}}.timer-strip--top-bar{width:100%;height:42px;z-index:500;text-decoration:none}.timer-strip--top-bar .timer-strip{font-size:1rem;padding:7px 0}.timer-strip--top-bar .timer-strip .timer-row{display:flex;align-items:center;justify-content:center;gap:32px;line-height:24px}@media (max-width: 340px){.timer-strip--top-bar .timer-strip .timer-row{gap:0;justify-content:space-between;padding-inline:5px}}.timer-strip--top-bar .timer-strip .big-text{font-size:1.0625rem;line-height:24px}.timer-strip--top-bar .timer-strip .timer-strip__item--text{font-weight:600;font-size:16px}.timer-strip--top-bar .timer-strip .timer-strip__item--content{display:none}@media (min-width: 968px){.timer-strip--top-bar .timer-strip .timer-strip__item--content{display:inline-flex}}.timer-strip--top-bar .timer-strip .timer-strip__item--button{height:28px;color:#097b95;background-color:#fff;border:none}.timer-strip--top-bar .timer-strip .timer-strip__item--time{display:none;background:rgba(255,255,255,0.16);border-radius:2px;padding:0 10px}@media (min-width: 640px){.timer-strip--top-bar .timer-strip .timer-strip__item--time{display:inline-flex;border:none}}.timer-strip--top-bar .timer-strip .timer-strip__item--info{font-weight:600}.chatbot-button{display:flex;justify-content:center;align-items:center;position:fixed;bottom:3rem;right:1rem;width:50px;height:50px;border-radius:25px;background-color:#46a9b4;box-shadow:rgba(0,0,0,0.2) 0 4px 8px 0;z-index:2147483645;left:unset;transform:scale(1)}@media (min-width: 576px){.chatbot-button{bottom:1rem}}html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}h1{margin:.67em 0;font-size:2em}a{background-color:transparent}strong{font-weight:bolder}img{border-style:none}button,input{margin:0;font-family:inherit;font-size:100%;line-height:1.15}button,input{overflow:visible}button{text-transform:none}button{-webkit-appearance:button}button::-moz-focus-inner{border-style:none;padding:0}button:-moz-focusring{outline:1px dotted ButtonText}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}.is-hidden{display:none !important}body{display:flex;position:relative;right:0;background:#f4f6f7;font-size:16px;line-height:22px;flex-direction:column;overflow-x:hidden}body,h1,h2,h3,input{font-family:"Source Sans Pro",Helvetica,sans-serif}h1{font-size:36px}h2{font-size:27px}h3{font-size:24px}h1,h2,h3{margin-bottom:20px;font-weight:300}p{margin:0 0 20px}a{color:#19bcc9}img{max-width:100%}html{box-sizing:border-box}*,::after,::before{box-sizing:inherit}body{margin:0;background-color:rgba(30,39,50,0.02);color:#1e2732;font-family:"Source Sans Pro",Helvetica,Arial,sans-serif;font-size:16px;font-weight:400;line-height:24px}img{max-width:100%}input{font-family:inherit}.container-fixed{width:100%;padding-right:20px;padding-left:20px;margin-right:auto;margin-left:auto}@media (min-width: 640px){.container-fixed{padding-right:40px;padding-left:40px}}@media (min-width: 960px){.container-fixed{max-width:840px}}@media (min-width: 1280px){.container-fixed{max-width:1104px}}@media (min-width: 1600px){.container-fixed{max-width:1392px}}@media (min-width: 1920px){.container-fixed{max-width:1680px}}.cgt-heading-h2{font-size:28px;line-height:36px;margin:0;color:#1e2732;letter-spacing:normal;font-style:normal;font-weight:600}.cgt-heading-h3{font-size:24px;line-height:32px;margin:0;color:#1e2732;letter-spacing:normal;font-style:normal;font-weight:600}.cgt-heading-h4{font-size:20px;line-height:28px;margin:0;color:#1e2732;letter-spacing:normal;font-style:normal;font-weight:600}.cgt-heading-h5{font-size:20px;line-height:28px;margin:0;color:#1e2732;letter-spacing:normal;font-style:normal;font-weight:600;font-weight:600}.cgt-heading-h6{font-size:16px;line-height:24px;margin:0;color:#1e2732;letter-spacing:normal;font-style:normal;font-weight:600}@media (min-width: 964px){.cgt-heading-h2{font-size:40px;line-height:48px}.cgt-heading-h3{font-size:32px;line-height:44px}.cgt-heading-h4{font-size:24px;line-height:32px}}.cgt-text-default{color:#1e2732;font-style:normal;font-weight:400;font-size:16px;line-height:24px}.cgt-avatar--24{color:#1e2732;font-style:normal;font-size:12px;font-weight:600;line-height:16px}.cgt-icon--default{width:40px;height:40px}.cgt-icon--dark .fillable{fill:rgba(30,39,50,0.6)}.cgt-icon__icon{display:flex;margin-right:4px;border-radius:50%;justify-content:center;align-items:center}.cgt-icon--not-spaced{margin-right:0}.cgt-button{display:inline-block;height:40px;margin:0;border:0;border-radius:6px;padding:8px 12px;font-size:16px;font-weight:600;text-align:center;text-decoration:none;text-transform:none;font-family:inherit;align-items:center;line-height:24px}.cgt-button>svg{display:inline-block;font-size:20px;line-height:24px;transform-origin:calc(50% + 4px) 50%;vertical-align:middle}.cgt-button>svg+span{vertical-align:middle}.cgt-button>span{display:inline-block;padding:0 12px}.cgt-button--primary{border:1px solid #19bcc9;background-color:#19bcc9;color:#fff}.cgt-button--secondary{border:1px solid rgba(30,39,50,0.12);background-color:transparent;color:rgba(30,39,50,0.8)}.cgt-button--ghost{border:1px solid transparent;background-color:transparent;color:rgba(30,39,50,0.8)}.cgt-button *>svg,.cgt-button>div{width:auto;margin-right:0}.cgt-button *>.fillable{fill:currentColor !important}.cgt-button--small{height:32px;padding:4px 8px;font-size:14px;line-height:20px}.cgt-button--small>svg{font-size:20px;line-height:20px}.cgt-button--small>span{padding:0 8px}.cgt-button--with-icon{position:relative;line-height:initial}.cgt-button--with-icon{display:flex}.cgt-button--only-icon{position:relative;padding:8px;align-items:baseline;line-height:initial}.cgt-button--only-icon:not(.cgt-button--width-expand){width:40px}.cgt-button--only-icon *>svg,.cgt-button--only-icon>div{height:100%}.cgt-avatar{display:flex;position:relative;overflow:hidden;border-radius:50%;background-repeat:no-repeat;background-size:cover;text-transform:uppercase;align-items:center;justify-content:center;vertical-align:middle;-webkit-font-smoothing:antialiased}.cgt-avatar--24{width:24px;height:24px}.cgt-avatar--color{color:#fff !important;box-shadow:inset 0 0 0 1px rgba(30,39,50,0.12)}.cgt-avatar__image{position:absolute;top:50%;left:0;width:100%;height:100%;object-fit:cover;transform:translateY(-50%)}.cgt-slider-wrapper.with-slider-on-top .cgt-slider__left-input{grid-area:left-input;justify-self:start;width:84px}.cgt-slider-wrapper.with-slider-on-top .cgt-slider--dual{grid-area:slider;margin-bottom:24px;width:calc(100% - 16px)}.cgt-slider-wrapper.with-slider-on-top .cgt-slider__right-input{grid-area:right-input;justify-self:end;width:84px}.cgt-text-input{display:flex;align-items:center;position:relative;border-radius:6px;background-color:#fff;line-height:24px;box-shadow:inset 0 0 0 1px rgba(30,39,50,0.12)}.cgt-text-input>*{font-size:16px}.cgt-text-input input{flex-grow:1;max-width:100%;border:none;outline:0;color:#1e2732;font-family:"Source Sans Pro",Helvetica,Arial,sans-serif;font-style:normal;appearance:none;order:4;background-color:unset}.cgt-text-input .trail-button{order:8}.cgt-text-input--medium{height:40px;padding:8px 8px}.app-nav{margin:0;padding:0;list-style:none}.uppercased-text{text-transform:uppercase}.app-nav{display:none;position:absolute;left:4px;z-index:500;width:calc(100% - 8px);overflow:auto;border-radius:6px;background-color:#fff;box-shadow:0 4px 4px rgba(30,39,50,0.04),0 1px 8px rgba(30,39,50,0.04),0 2px 4px rgba(30,39,50,0.04),0 0 0 4px rgba(30,39,50,0.04),inset 0 0 0 1px rgba(30,39,50,0.12);flex-direction:row;align-items:flex-start;flex-flow:column;gap:0}@media (min-width: 960px){.app-nav{max-width:624px}}@media (min-width: 1280px){.app-nav{height:100%}}.app-nav__item{width:100%}.app-nav__item-name{font-size:16px;line-height:24px;margin:0;color:#1e2732;letter-spacing:normal;font-style:normal;font-weight:600}.app-nav__item-link{padding:8px 6px;min-height:56px;white-space:nowrap;color:#1e2732}.app-nav__item{position:relative;justify-content:center;align-items:center;width:100%}.app-nav__item:last-of-type{border-bottom:0}@media (min-width: 640px){.app-nav{left:8px;width:auto;flex-flow:row;flex-wrap:wrap;gap:0;width:320px;box-shadow:0 4px 16px rgba(30,39,50,0.04), 0 6px 8px rgba(30,39,50,0.04), 0 8px 12px rgba(30,39,50,0.04), 0 0 0 8px rgba(30,39,50,0.04), inset 0 0 0 1px rgba(30,39,50,0.12)}}@media (min-width: 960px){.app-nav__item-link{min-height:auto}}@media (min-width: 960px){.app-nav.new_navbar_ui{display:flex;position:relative;top:auto !important;left:auto;width:auto;max-width:none;overflow:visible;border-radius:none;background:0 0;flex-flow:row;box-shadow:none}.app-nav.new_navbar_ui .app-nav__trigger-mobile{display:none}.app-nav.new_navbar_ui .app-nav__item{display:flex;width:auto;height:100%;border-bottom:none}.app-nav.new_navbar_ui #navigation-community,.app-nav.new_navbar_ui #navigation-jobs{display:none}}@media (min-width: 1280px){.app-nav.new_navbar_ui #navigation-community,.app-nav.new_navbar_ui #navigation-jobs{display:flex}}[class*=" icon-"]:before{font-family:fontello;font-style:normal;font-weight:400;speak:never;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.custom-icon--light{color:rgba(30,39,50,0.6)}.icon-arrow-right:before{content:'\e808'}.custom-font-icon{width:24px;height:24px}.custom-font-icon::before{margin:0;font-size:24px}.popover{display:none;opacity:0;position:fixed;right:4px;bottom:8px;left:4px;background-color:#fff;border-radius:6px;box-shadow:0 0 0 4px rgba(30,39,50,0.04),0 2px 4px 0 rgba(30,39,50,0.04),0 1px 8px 0 rgba(30,39,50,0.04),0 4px 4px 0 rgba(30,39,50,0.04),inset 0 0 0 1px rgba(30,39,50,0.12);z-index:451}@media (min-width: 640px){.popover{left:auto;bottom:auto;width:400px;right:8px}}.popover-content{overflow-y:auto;overflow-x:visible;color:#3f444c}.wayfinder-container{height:80px}.wayfinder-container.with-bar{height:122px}.wayfinder-container.with-bar .wayfinder{display:flex;flex-flow:column;justify-content:flex-end}@media (min-width: 640px){.wayfinder-container{height:96px}.wayfinder-container.with-bar{height:138px}}@media (min-width: 960px){.wayfinder-container{height:48px}.wayfinder-container.with-bar{height:90px}}@media (min-width: 1280px){.wayfinder-container{height:56px}.wayfinder-container.with-bar{height:98px}}.wayfinder{position:fixed;top:0;left:0;z-index:453;width:100%;background-color:#fff;height:80px}.wayfinder .app-nav{top:calc(80px + 8px);max-height:calc(100dvh - 88px)}@media (max-width: 1279.98px){.wayfinder .app-nav{top:calc(80px + 2px);max-height:calc(100dvh - 82px)}}.wayfinder__image-search-wrapper{position:relative}.wayfinder.with-bar{height:122px}.wayfinder.with-bar .app-nav{top:calc(122px + 8px);max-height:calc(100dvh - 130px)}@media (max-width: 1279.98px){.wayfinder.with-bar .app-nav{top:calc(122px + 2px);max-height:calc(100dvh - 124px)}}.wayfinder.with-bar .mobile-curtains{top:122px}.wayfinder.with-bar .wayfinder__container{height:calc(100% - 40px)}.wayfinder__container{display:flex;width:100%;height:100%;flex-wrap:wrap;background-color:#fff}.wayfinder__item,.wayfinder__logo{height:50%;display:flex;justify-content:center;align-items:center}.wayfinder__logo{width:36px}.wayfinder__search{position:relative;order:9;width:100%;height:50%;border:1px solid rgba(30,39,50,0.12);display:flex;justify-content:center;align-items:center}.wayfinder__search .cgt-button{height:calc(100% - 8px);margin-right:4px}.wayfinder__form{width:100%;height:100%;display:flex;display:flex;justify-content:center;align-items:center}.wayfinder__search-input{width:100%;height:100%;padding:8px 12px;border:none;font-size:16px}.wayfinder__search-button{width:52px !important}.wayfinder__search-button svg{width:24px;height:24px}.wayfinder__action-icon-svg .fillable{fill:rgba(30,39,50,0.8)}.wayfinder .hamburger{z-index:1;margin-left:0;margin-top:0;width:48px;min-width:48px;height:50%;display:flex;justify-content:center;align-items:center;border:1px solid rgba(30,39,50,0.12);border-bottom:none}.wayfinder .hamburger .hamburger-box,.wayfinder .hamburger .hamburger-inner{z-index:0}.wayfinder .hamburger .hamburger-box{position:relative;display:inline-block;width:18px;height:12px}.wayfinder .hamburger .hamburger-box .hamburger-inner{top:50%;display:block;margin-top:-2px}.wayfinder .hamburger .hamburger-box .hamburger-inner,.wayfinder .hamburger .hamburger-box .hamburger-inner:after,.wayfinder .hamburger .hamburger-box .hamburger-inner:before{position:absolute;width:18px;height:2px;border-radius:1px;background-color:rgba(30,39,50,0.8)}.wayfinder .hamburger .hamburger-box .hamburger-inner:after,.wayfinder .hamburger .hamburger-box .hamburger-inner:before{display:block;content:''}.wayfinder .hamburger .hamburger-box .hamburger-inner:after{bottom:-5px}.wayfinder .hamburger .hamburger-box .hamburger-inner:before{top:-5px}.wayfinder .cgt-button.cgt-button--rectangular{height:100%;border-radius:0}.wayfinder .mobile-curtains{position:fixed;display:none;opacity:0;top:80px;right:0;left:0;bottom:0;background-color:rgba(0,0,0,0.5);mix-blend-mode:normal;backdrop-filter:blur(2px);width:100%;z-index:450;animation:showCurtains .5s}@keyframes showCurtains{from{opacity:0}to{opacity:100%}}.wayfinder__actions{display:flex;flex-flow:row;height:50%;flex-grow:1;justify-content:flex-end;align-items:center}.wayfinder__actions-list{height:100%;margin:0;padding:0;list-style:none;display:flex;flex-flow:row;justify-content:center;align-items:center}.wayfinder__action{height:100%}.wayfinder__action-link,.wayfinder__image-search{width:100%;height:100%;padding:0 12px;display:flex;justify-content:center;align-items:center}.wayfinder__image-search{border-right:1px solid rgba(30,39,50,0.12);max-width:47px}.wayfinder__action-icon{position:relative;display:block}.wayfinder__action-icon .cgt-icon{width:100%}.wayfinder__user-section{padding:4px;gap:4px;height:100%;height:100%;display:flex;justify-content:center;align-items:center}.wayfinder__user-section .cgt-button{height:100%}.wayfinder__user-section .cgt-button{padding:8px;white-space:nowrap;display:flex}.wayfinder__user-section .cgt-button span{padding:0 8px}.wayfinder__user-section .cgt-button.blue-button{background-color:#0c1015;border-color:#0c1015}.wayfinder .app-nav .app-nav__item .cgt-button:not(.actions-bar__link){border-top:none}@media (min-width: 390px){.wayfinder__logo--signed-out{width:auto;margin-left:6px}}@media (min-width: 640px){.wayfinder{height:96px}.wayfinder .mobile-curtains{top:96px}.wayfinder .app-nav{top:calc(96px + 8px);max-height:calc(100dvh - 104px)}.wayfinder.with-bar{height:138px}.wayfinder.with-bar .mobile-curtains{top:138px}.wayfinder.with-bar .app-nav{top:calc(138px + 8px);max-height:calc(100dvh - 146px)}.wayfinder__logo{margin:0 12px;width:auto;min-width:100px}.wayfinder__action-link,.wayfinder__image-search{padding:0 16px}.wayfinder__user-section .cgt-button{padding:12px;white-space:nowrap;display:flex}.wayfinder__user-section .cgt-button span{padding:0 12px}.wayfinder__search-button{width:72px !important}}@media (min-width: 960px){.wayfinder{height:48px}.wayfinder .wayfinder__container{border-bottom:1px solid rgba(30,39,50,0.12)}.wayfinder .mobile-curtains{top:48px}.wayfinder .app-nav{top:calc(48px + 8px);max-height:calc(100dvh - 56px)}.wayfinder.with-bar{height:90px}.wayfinder.with-bar .mobile-curtains{top:90px}.wayfinder.with-bar .app-nav{top:calc(90px + 8px);max-height:calc(100dvh - 98px)}.wayfinder__logo{width:auto;margin:0 16px}.wayfinder__container{flex-wrap:nowrap}.wayfinder__actions,.wayfinder__item,.wayfinder__logo{height:100%}.wayfinder__search{order:0;height:100%;border-top:none;border-bottom:none}.wayfinder .app-nav .app-nav__item .cgt-button:not(.actions-bar__link){border-top:none;border-bottom:none;border-left:none}}@media (min-width: 1280px){.wayfinder{height:56px}.wayfinder .mobile-curtains{display:none;top:56px}.wayfinder .app-nav{top:calc(56px + 8px);max-height:calc(100dvh - 64px)}.wayfinder.with-bar{height:98px}.wayfinder.with-bar .mobile-curtains{top:98px}.wayfinder.with-bar .app-nav{top:calc(98px + 8px);max-height:calc(100dvh - 106px)}.wayfinder .hamburger{display:none}.wayfinder__logo{margin:0 20px}.wayfinder__action-link,.wayfinder__image-search{padding:0 20px}.wayfinder__image-search{max-width:none}.wayfinder__search-button{width:88px !important}}@media (max-width: 1279.98px){.wayfinder-container.wayfinder-container--without-mobile-search{height:40px}.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder{height:48px}.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder .app-nav{top:calc(40px + 10px);max-height:calc(100dvh - 50px)}.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder .mobile-curtains{top:48px}.wayfinder-container.wayfinder-container--without-mobile-search.with-bar{height:82px}.wayfinder-container.wayfinder-container--without-mobile-search.with-bar .wayfinder{height:90px}.wayfinder-container.wayfinder-container--without-mobile-search.with-bar .wayfinder .wayfinder__container{height:calc(100% - 42px)}.wayfinder-container.wayfinder-container--without-mobile-search.with-bar .wayfinder .app-nav{top:calc(82px + 10px);max-height:calc(100dvh - 92px)}.wayfinder-container.wayfinder-container--without-mobile-search.with-bar .wayfinder .mobile-curtains{top:90px}.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder__search{display:none}.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder .wayfinder__container>.hamburger,.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder .wayfinder__container>.wayfinder__actions,.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder .wayfinder__container>.wayfinder__logo{height:100% !important}}@media (min-width: 960px){.wayfinder-container.wayfinder-container--without-mobile-search{height:48px}.wayfinder-container.wayfinder-container--without-mobile-search.with-bar{height:90px}.wayfinder-container.wayfinder-container--without-mobile-search.with-bar .wayfinder{height:90px}.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder__search{display:flex}.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder__item,.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder__logo{height:50%}.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder__actions{height:50%}}@media (min-width: 1280px){.wayfinder-container.wayfinder-container--without-mobile-search{height:56px}.wayfinder-container.wayfinder-container--without-mobile-search.with-bar{height:98px}.wayfinder-container.wayfinder-container--without-mobile-search.with-bar .wayfinder{height:98px}.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder .wayfinder__container>.hamburger,.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder .wayfinder__container>.wayfinder__actions,.wayfinder-container.wayfinder-container--without-mobile-search .wayfinder .wayfinder__container>.wayfinder__logo{height:100% !important}}.wayfinder__action-link{flex-direction:row;align-items:center;text-decoration:none;gap:8px}.btn{display:inline-block;border:0 solid transparent;border-radius:3px;padding:.5rem 1.5rem;font-size:1rem;line-height:1.5;text-align:center;text-decoration:none;white-space:nowrap;vertical-align:middle}.btn-primary{background-color:#159ca9;color:#fff}.btn-sm{padding:.25rem 1rem;font-size:.875rem;line-height:24px;border-radius:2px;border-radius:4px}.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-exclamation-triangle:before{content:"\f071"}.fa-times:before{content:"\f00d"}.fa-unlock-alt:before{content:"\f13e"}.far{font-family:"Font Awesome 5 Pro";font-weight:400}.fas{font-family:"Font Awesome 5 Pro Solid";font-weight:900}[class*=" icon-"]:before{font-family:fontello;font-style:normal;font-weight:400;speak:never;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.custom-icon--light{color:rgba(30,39,50,0.6)}.icon-arrow-right:before{content:'\e808'}.custom-font-icon{width:24px;height:24px}.custom-font-icon::before{margin:0;font-size:24px}.responsive-footer__logo{width:80px;height:20px;margin-bottom:32px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAAAyCAQAAACzWFxqAAAABGdBTUEAALGPC%2FxhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAAmJLR0QA%2F4ePzL8AAAvdSURBVHja7ZtnlJXFGYBnKSsgIGUpAi5FECliQSygCYaDAUQQggcRkyBEPRqIJRgTMIAGYxCVBNAjNhSMoihwVlSiiXiIgiAEAfeEIgtIZynLwrZ7v3mf%2FNhbZr5yy7KEP3e%2BP3v2m2%2FK%2B8zM2%2BYqlSk%2BhfrObXqu7JQdehaDqZORyLkG8iRmmZiRyDkuzisgkQd4PiORc1z0SxaQmRmJZID8n87m8youC99Ef37ClYUNMkDONY668g9CEUWp2UyrDJBzCyRHjhGfJlyVAXJugTSVQ3EgorkiAyQDJAMkA%2BTMBZdNSzrRhbbUT6F2TRrTilY0pnZSpX7QAtI5rVE1oRtdyQkcRTM60oMedKYVddNot05ZbsVlXEYbalYNCOeTS%2FfQ5XSmZTIZ%2BH7foKIL3Wnh96oZv%2BQd8uWYlEmFFMsuWc6EstxAEd3Jm7JRDsgJOSEHZLN8wHSm6SfiD1OZoqfqqfoJ%2FQTPyOn4REX0vFitKXSNtZrFAGbzDov0q85YspVSivb6FfZJiAoO8i5NrVF05j4WykY5LKXiiCPlclx2sJxHkwOnH6%2FxXzkpYQlzgvV6Cq3TAVJ6Eb%2BWPNkpxRIWR8rlmGzhDYZTL6C%2F63iWt%2FW7ej4PVi52cphJAeUSppAVtLPWr36MH%2FApUqifcu8VaukJFJB2EeOx%2Fv9%2BfL3IAePFFUqFb3KNa2ikZg2Gs0JKAjsrZq4NzyzlF8tSn%2FHtc8YqxQvJgdBY%2F5kjAT1%2FywifL7JYa9QZrBTd2Wx%2Bpp%2BMV27LSrfATMHJ%2B9Qymr5APgiqXZUHZD1ZkbYbyX7iwLpzvZzAquuMrdyfkueF7AH%2BTeWa9winl%2Bz2%2BxZAz9SvJwMSulK%2BDe4bQM8yJRYB8o1h9g%2BkA7vsmekN0aq58h2JBVZe3iHWcG1Zgs9KPyMgm6InOI1kXxSIhBgpu9z7St%2BrlFL6MW%2BffgKWj92CUaqsvexJJEwplYRA6MmBxBIA4K8eIOsM0GNkjXtmsiMS0JDPExwmlVUl1DOm8h7AHv4xNpMvJ9OHYvSyxtgh%2B2LthKK7xfpmnFJK8QY%2Bo%2FU9GIe4BFND8oLm6wXrBUJz2eaSQJHky2Y5aPYN4NwRCES8SwLku0oBP%2BRmK%2FtZpufphbJWQtGBhnpFmm0oO42Bl%2BvJtKYW2bRnuoSNDiSxoFyvZ8SGbQLBV%2Bi3K6UUrxIdbRmr9J%2B4Pdw33Ds8gIlstOcji13B9Vt8cBTIfwIPMTeQedb4ivk9bcmmVnGOM5wt1rvtNAjcIT4z03MqvYO91jBEz6B5TG324i0BJMylkf8NNBvVD1tDnWKgOsRg%2BlrPEDlumr3O3dwQeXpzvj%2BQWO3TvKUnMZfNcriii1JKMTGydJ6mu9uM5BNrjLtNk4QsWeECtoMhNKAGDRnCBpIACV0h5Zjjutnqu7Vr94wKAhKrEZZlerJ%2BjrUco69SyvmVS7FM96RrhvO9rI3a9nqaMZydtoFXnCOHY2%2FFGegSVH2XH9LVV916gIDkc000XkzLyF8X6rf1FC70beNqCRk9lZV3MqyrTlJqrdN95ZeYvetFJASi55JQWowkYHd6gQD7o1KiZkkrspRS5noByfdzqmhUHHPI9GvGVJe4a8YVFehpVfHU3UBAvqd9mq5WPSkw9UHoWuOdawE697jdYv12sA6hQdzIACm2PAeXlSiAFBh73wUEOBpdaIYrKEesLfZY0skuNET%2Bdw%2BQr4y3T585EOB0uE%2Favm%2BWrLfauNFY4ZZJKz9wgY%2FnvTrI7OV6EWMOX%2Fn1Ll%2BYu5NOgTtEOyM9H4evRywhXZM0zjPbqL%2FG7SzJAUNZPVotQB6vSvhHvrba%2BJGByhK2Xug7x7lBQGwLU7%2Fp2%2FcHlsLuE6TU9Wt%2B07%2FDWi9Ho%2Bo8AZD7jS8qwv2s1h62JnJLdQBJvj%2FI4qJwX2eM%2FgPPMJd5zGOeHBF%2FIOfHDzMB9EPpBReZZa3xg7Ia1yOr5ajV94AgINzl1%2FXvsO2NpGE5LqHEWAF7GFTpeFGPezltCPwwzaoFyI8TjuZSprJGihKZ2BaQ5lJotu4MSw%2BIrfKTB4iAQYFAxvhtr%2BUWkO9SiVbyksua3ijvs0S22m6Rfq5q4ffUgdCYWRQnjxJYQC6Sk1br%2FdIDIh%2BSpusbHpAekI1WlZSAnGwiGwj0ciPi3uY9%2FKoXCK352idckWyHtJVTVuv90zyylqeyQ6wAZ7u0gDiLrCo7gwLHlihaycbEIT0p8BN2dQIhWz7zxBdKZJdskvWyXtbL6QAgrcxQJTi3pwlkqTXzH%2BTT4IdPWcrgYE%2FdF4ieYB0%2FRclvglBXVuITVIsVh%2FfK2lc9Y5gikFEuHGv5RXlH6lOTLLLIknX%2BVlZRY%2FZbB%2BsjaeqQN6w3L6VnjKeyQ4ZZE5Nw36RW1iOGUD%2FRz7BNKgBE5CSbmEOfM0vhpgbEpfuWx92vyPsAINSSLckNV%2F1iIJDpVr8fVjuQih4StgY4I6kPvC0eHA9dpRT1KrryI%2FrSk9zEGsgGgnB1VYEcqS%2B7jZZC9PQACwCiFHmWSAvcKJUqy5XtQUCc0dbXu7xfnyEQt13OPj9PhEHMqtQudI8CBCkht6qXHPz8lNSBcKEVpjzizQvK2iAg%2BknXYTfa1XaO6ad7dEhXqTBalmj2stqAKMXrru4X7TjPjp3q6RKGyvVMbzNroN%2BhI9kqK9VkPnus3Ti7ykBamlfu5JR7YfBTigJ3SD%2BXPbjLjJTRgS8TBRepbQdlZEvQtQulyLZ%2FWZIikHA%2FxDWAz%2Bh%2FsgnZ1C1rr%2B9nS0RXD1JKKTrFg8%2BV4TXJl3WySv4pefIeC%2FSLTGVURVd8IFHDZS6f4u7TLWhENx6NJ5FSAlLP5W9Pst7eyckgs1cp6sv3LiRbuY1m1Kcd49mbLPwe16GRr1d7D0zqcS3T2SIrTUc71R1SU%2F7lTdjIfsmX7VJs2FC3RWp%2FltwSlzL%2BzV3xazWxvhZ4TNVC2S%2FlwOdpKvVlVkvlTOMSGhbncAML4tE5PyBK6ck%2B8z0su8ycZ3BOnabuTLiUksdEfsYg51bn5%2Fpx3pVtoitTwWVt0waiFD2t6zm%2Bzl7c46SHHCC11OwSmrhsujuDsoaykRppmb0jfLyQvXIo8rdr7DYQmsZznvY4rKRsYMbQGSGSwqIEpCR%2BEyENIEo549CJLzkgdItbZhwgpbCBfIStjxqa%2BTSr%2FXSB1JZP%2FRdRNOwdDy%2B6gSjlDKQi4Y2R53mORJccJqVyfwCkmDZVAqIUYwm4pBDJ9v4tdiukjn6ZkKR6wWCcW91Kme%2FdkJV%2BCR4Bgjwjcv0v4lCZ%2BBnGEkOkHqjOGEoDZlvOJKX0X4yvn%2FXp%2FT6OJ72ChKwzFyRZ2FmasYltoCtlGRU%2BAha%2BJBYTfa8m8y0762UGMNQZyWhnrH6QObLDo%2FJquPoZzA5vL%2FpBQ%2BnutF71ChxxC16n3DteyaN7pZaJlet8vr6JDT6z%2FbISnp7me33N9OC66vlyIkEUq0DP4WKXlfWFVWNEcsP0Kv1H%2BYStHJJjckS2ywqm0dtUztxtWTcveCOwstiqcTyaA7fU4j0sZpPskf2yU9boec4tJjYu5xE9U8%2FWz%2FM4N3tNA3vEPCWr2CPHpUgOyQbmRI8nujFZz9KzeZpRlRdSvbaQM1oWy1YKpYhC8lngDI26tuTwADOZrZ9lQnCOiHaM1fPla9ktR6VIiqRQCljNAn7LjTT0qX8x45mhZ%2BtZehrDUv65NXVoSkuaeT%2BgruRjZk98fpaG4fuDlJlXCOzLqDSgUSrBzBRG3LCkVWkbmrp3Y2qzPd2CNjS3va90r0vTgja0pnk6nnt1TLyXmVHWC3zrdI77siCnaKsy5awBGW45hUt964y36mzbWzcjt7NWnFstu6IETzbBGcJRy5KYk5Ha2dwhHU2jFXD4iN8wIHRd6Br6M56PRVv74xRdMlI7m0Cy4ldc3B6917cHPT4js7ONpIPs8L827flPyH0vK1POEhLygn8REitr%2FK8PZMrZgXKzXih77B8cxMIF%2B1nEUH9XLFPOJpQL6MVd%2Bi0pkVIpkRKpkFXOOPoUN83Ipurlf1R%2B3oIpwIIsAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE5LTAyLTI2VDEwOjU1OjM5KzAwOjAwNm0mnQAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxOS0wMi0yNlQxMDo1NTozOSswMDowMEcwniEAAAAASUVORK5CYII%3D) no-repeat;background-size:auto auto;background-size:80px 20px}.responsive-footer__logo a{display:block;overflow:hidden;text-indent:-119988px;text-align:left}@media (min-width: 968px){.responsive-footer__logo--mobile{display:none}}.locale-selector .popover-container .popover{top:auto;bottom:20px;left:50%;right:auto;transform:translate(-50%, 0)}.locale-selector--dropdown{padding:6px 10px;background-color:#fff}.locale-selector--dropdown--link{display:block;min-width:10em;margin:3px 0;color:#131518}.locale-selector .flag{margin:0 4px 0 0}.site-admin-control-warning{font-size:.875rem;position:fixed;bottom:0;display:block;width:100%;padding:12px 30px;background-color:#b3475d;color:#fff;line-height:24px;z-index:449}.site-admin-control-warning a{color:#fff;text-decoration:none}.site-admin-control-warning .u-float-left{float:left}.site-admin-control-warning .u-float-right{float:right}.notice .btn{display:inline-block;padding:.25rem 1rem}.new-search{overflow:hidden;border-radius:6px;background-color:#fff;max-width:720px;height:48px}.new-search__wrap{position:relative}.new-search__input{height:48px !important}.new-search__wrap--with-image .wayfinder__image-search-wrapper{position:absolute !important}.new-search__wrap.new-search__wrap--with-image .new-search{padding-left:47px}@media (min-width: 1240px){.new-search__wrap.new-search__wrap--with-image .new-search{padding-left:65px}}.new-search__wrap--with-image .new-search__input{box-shadow:none}@media (max-width: 640px){.new-search__wrap--with-image{position:relative}.new-search__wrap--with-image .wayfinder__image-search-wrapper{width:calc(100% - 8px)}}.home-hero{position:relative;display:flex;flex-direction:column;justify-content:center;align-items:center;width:100%;height:400px;color:#fff;background-color:rgba(0,0,0,0.4)}.home-hero__background{position:absolute;top:0;left:0;width:100%;height:100%;z-index:0}.home-hero__background-image{width:100%;height:100%;object-fit:cover;position:absolute;top:0;left:0}.home-hero__content{position:relative;z-index:3;display:flex;flex-direction:column;align-items:center;justify-content:center;width:100%;max-width:1200px;padding:0 20px;text-align:center}.home-hero__title{margin-bottom:24px;font-size:48px;font-weight:600;line-height:1.2;text-align:center;color:#fff;margin-top:0}@media (max-width: 992px){.home-hero__title{font-size:2.5rem}}@media (max-width: 576px){.home-hero__title{font-size:38px}}.home-hero__search{width:100%;max-width:720px}.home-hero__author-badge{display:flex;align-items:center;gap:6px;background:rgba(0,0,0,0.1);padding:4px 8px;border-radius:999px;backdrop-filter:blur(40px);-webkit-backdrop-filter:blur(40px);position:absolute;right:24px;bottom:10px;z-index:2;text-decoration:none;color:#fff}.home-hero__author-badge:visited{color:#fff}.home-hero__author-text{font-size:12px;font-weight:400;line-height:1.32;letter-spacing:-2%;opacity:.85}.home-hero__author-name{font-size:12px;font-weight:600;line-height:1.32;letter-spacing:-2%;margin-left:2px}.subscription-banner__container{display:flex;flex-direction:column;position:relative;background:linear-gradient(135deg, #ede7f6 0, #e8eaf6 50%, #e3f2fd 100%);border-radius:12px;overflow:hidden;max-width:576px;margin:0 auto}.subscription-banner__content{position:relative;z-index:1;display:flex;flex-direction:column;text-align:center;align-items:center;padding:32px 20px;gap:16px}.subscription-banner__tags{display:flex;flex-wrap:wrap;justify-content:center;gap:4px;padding:0;margin:0;max-width:505px}.subscription-banner__tag{display:inline-flex;align-items:center;padding:4px 12px;background-color:rgba(255,255,255,0.32);border-radius:24px;font-size:18px;font-weight:400;color:#676b6f}@media (min-width: 960px){.subscription-banner__tag{font-size:14px}}.subscription-banner__cta{width:288px}.subscription-banner__subtext{font-size:13px;font-weight:600;color:#666;margin:0}@media (min-width: 960px){.subscription-banner__subtext{font-size:14px}}.subscription-banner__visual{display:none;position:relative;overflow:visible;width:100%;max-width:none;min-height:260px}.subscription-banner__wave{position:absolute;top:0;left:0;width:100%;height:100%;z-index:0}.subscription-banner__wave-image{width:100%;height:100%;object-fit:cover}.subscription-banner__butterfly{position:absolute;left:auto;right:60px;top:-25px;width:252px;transform:scale(1.1);z-index:4}.subscription-banner__bird{display:none}.subscription-banner__value-card{display:none;position:absolute;top:auto;left:80px;bottom:120px;padding:24px 16px;background:rgba(255,255,255,0.56);border-radius:12px;transform:rotate(8.75deg);text-align:center;z-index:3;color:#35424f;box-shadow:0 1px 2px 0 rgba(255,255,255,0.8) inset,0 -1px 1px 0 rgba(48,47,45,0.06) inset;backdrop-filter:blur(8px);-webkit-mask-image:radial-gradient(circle 10px at 50% 0%, transparent 10px, black 10px),radial-gradient(circle 10px at 50% 100%, transparent 10px, black 10px);mask-image:radial-gradient(circle 10px at 50% 0%, transparent 10px, black 10px),radial-gradient(circle 10px at 50% 100%, transparent 10px, black 10px);-webkit-mask-size:100% 51%;mask-size:100% 51%;-webkit-mask-position:top,bottom;mask-position:top,bottom;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;font-size:20px;font-weight:400}.subscription-banner__value-bottom,.subscription-banner__value-top{margin:0;font-size:20px;font-weight:400;color:#35424f;line-height:1.2}.subscription-banner__value-amount{font-size:22px;font-weight:800;background:linear-gradient(135deg, #19bcc9 0, #ad9dfc 100%);-webkit-background-clip:text;background-clip:text;-webkit-text-fill-color:transparent;line-height:1.2;display:inline}.subscription-banner__value-price{font-size:24px;font-weight:700;color:#159ca9;line-height:1.2}.subscription-banner__value-period{font-weight:400;color:#159ca9}.subscription-banner__flower{display:none}.subscription-banner__everyday-pill{display:none;position:absolute;top:auto;left:162px;bottom:86px;transform:rotate(-5deg);padding:6px 14px;border-radius:32px;font-size:16px;font-weight:400;white-space:nowrap;z-index:3;color:#686c70;background-color:#fff;backdrop-filter:blur(12px);box-shadow:0 1px 2px 0 rgba(255,255,255,0.8) inset,0 -1px 1px 0 rgba(48,47,45,0.06) inset,1px 1px 12px 0 rgba(0,0,0,0.1)}@media (min-width: 577px){.subscription-banner__everyday-pill,.subscription-banner__value-card,.subscription-banner__visual{display:block}}@media (min-width: 1280px){.subscription-banner__container{flex-direction:row;align-items:center;max-width:unset;margin:unset}.subscription-banner__content{flex:1 1 60%;text-align:left;align-items:flex-start;padding:40px;gap:20px}.subscription-banner__tags{justify-content:flex-start;max-width:unset}.subscription-banner__visual{display:block;flex:0 0 35%;max-width:35%;width:auto;min-height:368px;overflow:hidden}.subscription-banner__butterfly{left:275px;right:auto;top:130px;width:270px;transform:translate(-50%, -50%) scale(1.1)}.subscription-banner__value-card{display:block;top:160px;left:730px;bottom:auto;padding:24px 12px}.subscription-banner__value-amount{font-size:28px}.subscription-banner__flower{display:block;position:absolute;right:-25px;bottom:-20px;width:163px;z-index:1}.subscription-banner__everyday-pill{display:block;top:270px;left:770px;bottom:auto;padding:8px 20px;font-size:18px}}@media (min-width: 1600px){.subscription-banner__content{padding:48px 56px;gap:24px}.subscription-banner__visual{flex:0 0 40%;max-width:40%;min-height:368px}.subscription-banner__butterfly{left:280px;top:164px;width:369px}.subscription-banner__bird{display:block;position:absolute;right:0;top:0;width:141px;height:141px;filter:blur(3px);z-index:1}.subscription-banner__value-card{top:105px;left:667px;padding:32px 20px;transform:rotate(4.5deg)}.subscription-banner__value-bottom,.subscription-banner__value-top{font-size:26px}.subscription-banner__value-price{font-size:30px}.subscription-banner__flower{position:absolute;right:-25px;bottom:0;width:210px;z-index:1;scale:1}.subscription-banner__everyday-pill{top:250px;left:730px;font-size:22px}}.filter-item__count,.promo-card__badge{background-color:rgba(0,0,0,0.05);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px);font-size:12px;font-weight:600;padding:2px 6px;border-radius:6px;letter-spacing:-2%}.model-filter__layout{display:grid;width:100%;gap:8px;grid-template-columns:1fr;grid-template-rows:auto}@media (min-width: 1025px){.model-filter__layout{grid-template-columns:repeat(3, 1fr);grid-template-rows:repeat(3, 1fr)}}@media (min-width: 1025px){.model-filter__type-section{grid-row:span 3}}@media (min-width: 1025px){.model-filter__format-section{grid-column:span 2;grid-row:span 2}}@media (min-width: 1025px){.model-filter__promo-section{grid-column:2/span 2;grid-row:3/span 1}}.filter-panel{background-color:#f7f7f8;padding:24px;border-radius:8px;height:100%}.filter-items{display:flex;flex-direction:column;gap:0 12px}@media (min-width: 768px){.filter-items--formats,.filter-items--types{display:grid;grid-template-columns:1fr 1fr}}@media (min-width: 768px) and (min-width: 1025px){.filter-items--types{display:flex;flex-direction:column}}.filter-item{display:flex;justify-content:space-between;align-items:center;padding:12px;border-bottom:1px solid rgba(39,44,48,0.12);text-decoration:none;color:inherit}.filter-item__content{display:flex;align-items:center;gap:12px}.filter-item__name{font-weight:600;font-size:16px;color:#333}.filter-item__meta{display:flex;align-items:center;gap:8px;justify-content:flex-end;text-align:right}.filter-item__ext{color:#6c757d;font-size:13px}.type-filter-item{position:relative}.type-filter-item .filter-item__icon-container{display:flex;align-items:center;justify-content:center;width:24px;height:24px;margin-right:4px}.type-filter-item .filter-item__icon-wrapper{display:flex;align-items:center;justify-content:center;opacity:0}.type-filter-item .filter-item__icon-wrapper svg path{transform:translateX(-8px);opacity:0}.type-filter-item .filter-item__icon-wrapper svg circle{opacity:1}.promo-cards{display:flex;flex-direction:column;gap:8px;align-items:center;justify-content:center;width:100%;height:100%;min-height:168px}@media (min-width: 768px){.promo-cards{flex-direction:row}}.promo-card{padding:16px;display:flex;align-items:center;justify-content:center;border-radius:8px;position:relative;width:100%;height:168px}@media (min-width: 768px){.promo-card{flex:1;height:100%}}.promo-card--sale{background-color:#f5eff0}.promo-card--free{background-color:#f4f3ec}.promo-card__content{position:absolute;width:100%;font-size:16px;font-weight:600;display:flex;align-items:center;justify-content:space-between;bottom:0;left:0;height:60px;padding-left:16px;gap:8px;padding:16px}.promo-card__content--title{display:flex;align-items:center;flex-direction:row;gap:8px}.promo-card__arrow-wrapper{display:flex;align-items:center;justify-content:center}.promo-card__arrow-wrapper svg circle{opacity:0}.promo-card__arrow-wrapper svg path{transform:translateX(-8px)}.circled-arrow--responsive{width:16px;height:16px}@media (min-width: 768px){.circled-arrow--responsive{width:24px;height:24px}}.card-button-mobile{display:flex;flex:1}.card-button-mobile a{width:100%;text-align:center}@media (min-width: 576px){.card-button-mobile{display:none}}.modelry-button{background-color:#3c73f6;border:1px solid transparent;justify-content:center}.three-d-jobs-button{background-color:#19bcc9;border:1px solid transparent;justify-content:center}.asset-collection{margin:0 auto}.asset-collection__description{margin-bottom:32px;margin-top:8px}@media (min-width: 420px){.asset-collection__description{margin-bottom:40px}}.asset-collection__trending{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:32px}@media (min-width: 420px){.asset-collection__trending{margin-bottom:40px}}.asset-collection__actions{display:flex;flex-direction:column;align-items:center;gap:16px;margin-top:20px}@media (min-width: 768px){.asset-collection__actions{margin-top:30px}}.category-grid{display:grid;grid-template-columns:repeat(12, 1fr);gap:10px;width:100%}@media (max-width: 991px){.category-grid{grid-template-columns:repeat(6, 1fr);gap:16px}}@media (max-width: 767px){.category-grid{grid-template-columns:repeat(2, 1fr);gap:12px}}.category-grid__item{grid-column:span 3;grid-row:span 1;position:relative;padding-bottom:80.03%}.category-grid__item--wide{grid-column:span 6;padding-bottom:40.015%}.category-grid__item--tall{grid-row:span 2;padding-bottom:140.06%}@media (max-width: 991px){.category-grid__item{grid-column:span 3}.category-grid__item--wide{grid-column:span 6}}@media (max-width: 767px){.category-grid__item{grid-column:span 1}.category-grid__item--wide{grid-column:span 2}.category-grid__item--tall{grid-row:span 2;padding-bottom:140.06%}}.category-grid .category-grid__item>.category-card{position:absolute;top:0;left:0;right:0;bottom:0;padding-top:0;height:100%}.print-ready-models{background-color:#f7f7f8;border-radius:16px;margin:0 10px;padding:56px 16px}@media (min-width: 768px) and (max-width: 991px){.print-ready-models{padding:64px 32px}}@media (min-width: 992px){.print-ready-models{padding:64px 48px}}@media (min-width: 1440px){.print-ready-models{padding:64px 136px}}@media (min-width: 1600px){.print-ready-models{max-width:1600px;margin:0 auto}}.asset-collection__subcategories{margin:0 15px}@media (min-width: 768px){.asset-collection__subcategories{margin:0 45px}}.asset-collection__subcategories--hidden{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border:0}.subcategories-table{margin-top:40px;margin-bottom:40px;border:1px solid rgba(39,44,48,0.12);border-radius:8px;overflow:hidden}.subcategories-table__row{display:grid;grid-template-columns:repeat(4, 1fr)}@media (max-width: 991px){.subcategories-table__row{grid-template-columns:repeat(2, 1fr)}}@media (max-width: 767px){.subcategories-table__row{grid-template-columns:1fr}}.subcategories-table__column{padding:24px;position:relative;border-right:0.5px solid rgba(39,44,48,0.12);border-bottom:0.5px solid rgba(39,44,48,0.12)}.subcategories-table__header{display:flex;justify-content:flex-start;gap:8px;align-items:center;margin-bottom:16px}.subcategories-table__title{font-size:16px;font-weight:600;color:#272c30;margin:0;text-decoration:none}.subcategories-table__count{font-size:12px;color:rgba(39,44,48,0.6);background:rgba(39,44,48,0.06);padding:2px 6px;border-radius:6px}.subcategories-table__list{list-style:none;padding:0;margin:0}.subcategories-table__item{margin-bottom:16px}.subcategories-table__item:last-child{margin-bottom:0}.subcategories-table__link{font-size:14px;color:rgba(39,44,48,0.8);text-decoration:none;display:block}@media (max-width: 992px){.category-grid.print-models-3d .category-grid__item:nth-child(7){order:7}.category-grid.print-models-3d .category-grid__item:nth-child(8){order:8}.category-grid.print-models-3d .category-grid__item:nth-child(9){order:6}}.trending-buttons{display:flex;flex-direction:row;align-items:center;flex-wrap:wrap;gap:8px}.home-hero__trending-buttons-container{display:flex;flex-direction:row;align-items:center;justify-content:center;margin-top:16px}@media (min-width: 768px){.home-hero__trending-buttons-container{width:calc(100% + 50px);margin-left:-25px}}.home-hero .trending-buttons{justify-content:center}.home-hero .trending-buttons .home-hero__trending-button:nth-child(n+8){display:none}@media (min-width: 768px){.home-hero .trending-buttons .home-hero__trending-button:nth-child(n+8){display:flex}}.home-hero__trending-button{color:#fff;background-color:rgba(255,255,255,0.2);border:1px solid rgba(255,255,255,0.12);backdrop-filter:blur(16px);-webkit-backdrop-filter:blur(16px)}.trending-models__header{display:flex;flex-direction:column;gap:16px}@media (min-width: 768px){.trending-models__header{flex-direction:row;align-items:flex-start;justify-content:space-between;gap:24px}}.trending-models__title-group{display:flex;flex-direction:column;gap:8px}.trending-models__description{max-width:600px}.trending-models__list{display:none;gap:12px}@media (min-width: 420px){.trending-models__list{display:flex;flex-wrap:wrap}}.browse-all-desktop{display:none;margin-left:auto}@media (min-width: 768px){.browse-all-desktop{display:inline-flex}}.browse-all-mobile{display:flex;justify-content:center;width:100%}@media (min-width: 768px){.browse-all-mobile{display:none}}.featured-designers-container{display:flex;flex-direction:column;gap:24px;padding:24px 16px;background-color:#f7f7f8;border-radius:16px;margin:16px}@media (min-width: 768px){.featured-designers-container{padding:32px;gap:32px;margin:24px}}@media (min-width: 1024px){.featured-designers-container{padding:48px 64px;gap:40px}}@media (min-width: 1440px){.featured-designers-container{width:100%;max-width:1280px;margin:40px auto}}.u-mr10{margin-right:10px}.text-white{color:#fff}#notifications-container{top:96px;position:fixed;margin:10px 0 0;right:10px;z-index:1001}#notifications-container.with-bar{top:136px}.category-card{position:relative;width:100%;padding-top:70.03%;height:0;z-index:1}.category-card__main{position:absolute;width:100%;height:100%;top:0;left:0;border-radius:8px;background-color:#272c301f;border:1px solid rgba(39,44,48,0.12);box-shadow:0 4px 15px rgba(0,0,0,0.1);z-index:3;overflow:hidden}.category-card__image{position:absolute;border-radius:8px;top:0;left:0;width:100%;height:100%;object-fit:cover;z-index:1}.category-card::before{content:'';position:absolute;width:95%;height:95%;top:-2.5%;left:2.5%;background-color:#eff0f0;border-radius:8px;z-index:2;border:0.5px solid rgba(39,44,48,0.12)}.category-card--no-before::before{content:none}.category-card__overlay{position:absolute;bottom:0;left:0;width:100%;min-height:64px;background:linear-gradient(to top, rgba(0,0,0,0.5), rgba(0,0,0,0));display:flex;justify-content:space-between;align-items:center;padding:0 16px;z-index:4}.category-card__info-wrapper{display:flex;flex-direction:row;align-items:center;gap:8px}.category-card__icon-wrapper{display:flex;align-items:center;justify-content:center;opacity:0;transform:translateX(-10px)}.category-card__badge{min-width:37px;height:20px;display:flex;align-items:center;justify-content:center;background-color:rgba(255,255,255,0.2);color:#fff;font-size:12px;font-weight:600;padding:2px 6px;border-radius:6px;backdrop-filter:blur(16px)}@media (max-width: 1279.98px){.category-card{padding-top:70%}.category-card::before{height:95%}}@media (max-width: 639.98px){.category-card{padding-top:65.9%}.category-card::before{height:95%;border-radius:6px}.category-card__badge{font-size:10px;padding:0 6px;border-radius:6px;opacity:.8}.category-card__overlay{min-height:50px}}.new-home-section{padding:56px 16px}@media (min-width: 768px) and (max-width: 991px){.new-home-section{padding:64px 40px}}@media (min-width: 992px){.new-home-section{padding:64px}}@media (min-width: 1440px){.new-home-section{padding:64px 160px}}@media (min-width: 1600px){.new-home-section{max-width:1600px;margin:0 auto}}.__react_component_tooltip:not(.show){visibility:hidden;opacity:0;display:none}.cgt-tooltip:not(.show){visibility:hidden;opacity:0;display:none}.timer-strip.is-secondary-color{background:linear-gradient(90.05deg, #A91E4C 0%, #CC2795 52.4%, #A91E4A 100%)}.timer-strip.blue-gradient{background:linear-gradient(90.05deg, #3E8AED 0%, #1769D3 52.4%, #3E8AED 100%)}.timer-strip.black-gradient{background:linear-gradient(90deg, #131920 0%, #073F89 48.08%, #131920 100%)}.timer-strip.timer-strip--subscription{background:linear-gradient(90deg, rgba(158,48,165,0.14) -15.62%, rgba(30,155,169,0.14) 43.39%, rgba(25,149,158,0.14) 67.13%, rgba(158,48,165,0.14) 98.8%),#fff;color:#1A1A1A}.timer-strip--subscription .timer-strip__cta{display:inline-flex;align-items:center;gap:4px;color:#1E9BA9;font-weight:600;text-decoration:none}.timer-strip--subscription .timer-strip__cta svg{fill:currentColor}.new-search__wrap--with-image .wayfinder__image-search-wrapper{position:absolute !important}@media (max-width: 640px){.new-search__wrap--with-image .wayfinder__image-search-wrapper .is-active{position:relative;transform:translateY(15px);z-index:1000;width:100%}.new-search__wrap--with-image .wayfinder__image-search-wrapper{width:calc(100% - 8px)}}.wayfinder__action-link,.wayfinder__image-search{width:100%;height:100%;padding:0 12px;display:flex;justify-content:center;align-items:center}.wayfinder__image-search{border-right:1px solid rgba(30,39,50,0.12);max-width:47px}@media (min-width: 1280px){.wayfinder__action-link,.wayfinder__image-search{padding:0 20px}.wayfinder__image-search{max-width:none}}
window.addEventListener("load", function () {
const headElement = document.getElementsByTagName("head")[0];
const stylesLinkElement = document.createElement("link");
stylesLinkElement.rel = "stylesheet";
stylesLinkElement.href = 'https://assets.cgtrader.com/assets/new_homepage/new_homepage-458179ad299786a655ead2edd40f24b7f7abc5df14b1c5356aa99b3a0263ae1a.css';
headElement.appendChild(stylesLinkElement);
});(function() {
window.App = {}
window.numberOfAxiosCallPending = 0;
})();
// jshint ignore: start
'use strict'
window.removeInlineCookieBar = function () {
const barSelector = '.js-inline-cookies'
const currentBar = document.querySelector(barSelector)
if (currentBar) {
document.body.removeChild(currentBar)
}
}
window.handleCookiesAccept = function (cookie) {
if (cookie) {
Cookies.set(cookie, true, { expires: 365, path: '/' });
}
removeInlineCookieBar();
}
window.handleCookiesDismiss = function (cookie) {
if (cookie) {
Cookies.set(cookie, true, { path: '/' });
}
removeInlineCookieBar();
}
window.lazyLoad = function (image, srcAttributeName = 'src') {
const urlToLoad = image.dataset[srcAttributeName]
if (urlToLoad) {
const tempImage = new Image()
tempImage.src = urlToLoad
tempImage.onload = function () {
image.src = tempImage.src
}
}
}
window.checkIfUnderControl = function (isUnderControl, currentUserProfile, currentUserUsername) {
if (!isUnderControl || !currentUserProfile || !currentUserUsername) {
return null
}
const underControlTarget = withId('under-controll-inner')
const profileLink = document.createElement('a')
profileLink.href = currentUserProfile
profileLink.innerText = `Under ${currentUserUsername} support.`
underControlTarget.append(profileLink)
withElementsToggleClass('.js-under-controll-bar', 'is-hidden')
}
function loadScript(source, beforeEl, async = true, defer = true) {
return new Promise((resolve, reject) => {
let script = document.createElement('script')
const prior = beforeEl || document.getElementsByTagName('script')[0]
script.async = async
script.defer = defer
function onloadHander(_, isAbort) {
if (
isAbort ||
!script.readyState ||
/loaded|complete/.test(script.readyState)
) {
script.onload = null
script.onreadystatechange = null
script = undefined
if (isAbort) {
reject()
} else {
resolve()
}
}
}
script.onload = onloadHander
script.onreadystatechange = onloadHander
script.src = source
prior.parentNode.insertBefore(script, prior)
})
}
function decodeHtml(html) {
const textarea = document.createElement('textarea')
textarea.innerHTML = html
return textarea.value
}
function withId(id) {
return document.getElementById(id)
}
function withElements(selector, callback, rootNode = document) {
if (!rootNode) {
console.warn('[withElements] rootNode is null for selector:', selector)
return []
}
let elements
if (typeof selector === 'string') {
elements = rootNode.querySelectorAll(selector)
} else if (!selector.length) {
elements = [selector]
} else {
elements = selector
}
for (let i = 0; i < elements.length; i++) {
callback(elements[i], i)
}
return elements
}
function withClosestElementToggleClass(selector, cssClass, rootNode) {
rootNode.closest(selector).classList.toggle(cssClass)
}
function withElementsSetBackground(selector, img, rootNode) {
withElements(
selector,
function (element) {
element.style.backgroundImage = `url('${img}')`
},
rootNode
)
}
function withElementsSetDisplay(selector, display, rootNode) {
withElements(
selector,
function (element) {
element.style.display = display
},
rootNode
)
}
function withElementsToggleDisplay(selector, display, rootNode) {
return withElements(
selector,
function (element) {
if (element.style.display === display) {
element.style.display = ''
} else {
element.style.display = display
}
},
rootNode
)
}
function withElementsToggleClass(selector, cssClass, rootNode) {
return withElements(
selector,
function (element) {
element.classList.toggle(cssClass)
},
rootNode
)
}
function withElementsRemoveClass(selector, cssClass, rootNode) {
return withElements(
selector,
function (element) {
element.classList.remove(cssClass)
},
rootNode
)
}
function withElementsAddClass(selector, cssClass, rootNode) {
return withElements(
selector,
function (element) {
element.classList.add(cssClass)
},
rootNode
)
}
function withElementsSetInnerText(selector, innerText, rootNode) {
return withElements(
selector,
function (element) {
element.innerText = innerText
},
rootNode
)
}
function withElementsAddEventListener(selector, event, callback, rootNode) {
withElements(
selector,
function (element) {
element.addEventListener(event, callback)
},
rootNode
)
}
function timeAgo(timeStamp) {
const now = new Date()
const secondsPast = (now.getTime() - timeStamp.getTime()) / 1000
if (secondsPast < 60) {
return `${parseInt(secondsPast)} seconds ago`
}
if (secondsPast < 3600) {
return `${parseInt(secondsPast / 60)} minutes ago`
}
if (secondsPast 86400) {
return timeStamp.toISOString().slice(0, 10)
}
}
function closeModal(modalRoot) {
if (!modalRoot) {
modalRoot = document.querySelector('.overlay-modal--background')
}
document.body.classList.remove('has-open-modal')
if (modalRoot.parentNode) {
modalRoot.parentNode.removeChild(modalRoot)
}
}
function showModal(modalContainerElement) {
document.body.classList.add('has-open-modal')
withElements(
'.js-close-modal',
function (closeButton) {
closeButton.addEventListener('click', function (event) {
closeModal(modalContainerElement)
})
},
modalContainerElement
)
}
function createModal(contentHTML, options) {
options = options || {}
const id = `modal-${Math.ceil(Math.random() * 10e4)}`
const root = document.createElement('div')
root.classList.add('overlay-modal--background')
root.id = id
if (options.rootClass) {
options.rootClass.split(' ').forEach(function (name) {
root.classList.add(name)
})
}
if (!options.skipAutoClose) {
root.addEventListener('click', function (e) {
if (!getContainer(e, 'overlay-modal--content')) {
closeModal(root)
}
})
}
const container = document.createElement('div')
container.classList.add(
'overlay-modal-container',
'overlay-modal-container--smaller'
)
root.append(container)
const modal = document.createElement('div')
modal.classList.add('overlay-modal')
container.append(modal)
const close = document.createElement('button')
close.classList.add(
'btn',
'btn-transparent',
'overlay-modal__close',
'js-close-modal'
)
modal.append(close)
const closeIcon = document.createElement('i')
closeIcon.classList.add('far', 'fa-times', 'is-grey')
close.append(closeIcon)
const content = document.createElement('div')
content.classList.add('overlay-modal--content')
modal.append(content)
content.innerHTML = options.parseHTML ? decodeHtml(contentHTML) : contentHTML
document.body.append(root)
return root
}
function getParentWith(selector, node) {
let container = node
let target
while (!target) {
if (!container.parentElement) break
container = container.parentElement
target = container.querySelector(selector)
}
return container
}
function getItemData(item) {
const data = item.dataset
const itemAttributes =
data && data.attributes ? JSON.parse(data.attributes) : {}
return itemAttributes
}
function findAncestor(cls, el) {
while ((el = el.parentElement) && !el.classList.contains(cls));
return el
}
function debounce(func, wait, immediate) {
var timeout
return function () {
var context = this,
args = arguments
var later = function () {
timeout = null
if (!immediate) func.apply(context, args)
}
var callNow = immediate && !timeout
clearTimeout(timeout)
timeout = setTimeout(later, wait)
if (callNow) func.apply(context, args)
}
}
function performXHR(method, url, callback, data) {
window.numberOfAxiosCallPending += 1
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (callback) {
const { responseText, status } = xhr
callback(responseText, status)
}
}
window.numberOfAxiosCallPending -= 1
}
xhr.open(method, url)
// Set Accept header for .js requests to ensure proper content negotiation (MARKETPLACE-JS-418X)
if (url.match(/\.js(\?|$)/)) {
xhr.setRequestHeader('Accept', 'text/javascript, application/javascript')
}
if (data && !(data instanceof FormData)) {
xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8')
}
xhr.setRequestHeader('X-CSRF-Token', '' + getToken())
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
xhr.send(data)
return xhr
}
// this is a legacy function to get the JSON data from the server
// it is was used in the fast pages with vanilla JS bundles
// for pages where webpack bundle is used, please don't use this function!!!
// use something from axios or react-query instead.
async function fetchJSON(url) {
window.numberOfAxiosCallPending += 1
const res = await fetch(url, {
credentials: 'same-origin',
headers: {
'X-CSRF-Token': getToken(),
},
})
window.numberOfAxiosCallPending -= 1
if (!res.ok) {
throw new Error(`HTTP error when fetching json! status: ${res.status}`)
}
try {
return await res.json();
} catch (error) {
console.error('Error parsing JSON:', error);
throw new Error('Invalid JSON response');
}
}
async function postJSON(url, data) {
window.numberOfAxiosCallPending += 1
const res = await fetch(url, {
method: 'POST',
credentials: 'same-origin',
headers: {
'X-CSRF-Token': getToken(),
'Content-Type': 'application/json;charset=UTF-8',
},
body: JSON.stringify(data),
})
window.numberOfAxiosCallPending -= 1
if (!res.ok) {
throw new Error(`HTTP error when posting json! status: ${res.status}`)
}
try {
return await res.json();
} catch (error) {
console.error('Error parsing JSON:', error);
throw new Error('Invalid JSON response');
}
}
async function fetchHTML(url) {
window.numberOfAxiosCallPending += 1
const res = await fetch(url, {
credentials: 'same-origin',
headers: {
'X-CSRF-Token': getToken(),
},
})
window.numberOfAxiosCallPending -= 1
return await res.text()
}
function getContainer(event, className) {
const closest = event.target.closest('.' + className)
return event.target.classList.contains(className) ? event.target : closest
}
function layoutGallery(root) {
const carouselContainer = root.querySelector('.product-carousel')
const listImageArea = carouselContainer.querySelector(
'.product-carousel__thumbs ul'
)
if (listImageArea.scrollWidth === listImageArea.offsetWidth) {
listImageArea.style.justifyContent = 'center'
} else {
listImageArea.style.justifyContent = 'flex-start'
}
}
function getOffsetTop(element) {
let offsetTop = 0
while (element) {
offsetTop += element.offsetTop
element = element.offsetParent
}
return offsetTop
}
function showTooltip(el) {
let closeTimeout
function close() {
closeTimeout = setTimeout(function () {
clearTimeout(timeout)
if (tooltip.parentNode) {
tooltip.parentNode.removeChild(tooltip)
}
}, 100)
}
const tooltip = document.createElement('span')
tooltip.classList.add('tooltip')
if (el.dataset.class) {
tooltip.classList.add(el.dataset.class)
}
const arrow = document.createElement('span')
arrow.classList.add('arrow')
tooltip.append(arrow)
const content = document.createElement('span')
content.classList.add('content')
content.innerHTML = el.dataset.value
tooltip.append(content)
el.parentNode.insertBefore(tooltip, el)
if (el.dataset.side) {
tooltip.style[el.dataset.side] = el.offsetWidth / 2 + 'px'
} else {
tooltip.style.left = el.offsetWidth / 2 + 'px'
}
const timeout = setTimeout(function () {
tooltip.classList.add('active')
}, 100)
content.addEventListener('mouseenter', function () {
clearTimeout(closeTimeout)
content.addEventListener('mouseleave', function () {
close()
})
})
el.addEventListener('mouseleave', function () {
close()
})
}
function getItemAttributes(attributes) {
return {
id: `${attributes.id}`,
name: attributes.title,
price: `${attributes.price}`,
brand: attributes.authorUsername,
category: attributes.category,
variant: attributes.productType,
position: attributes.index,
...attributes.itemCategories
}
}
function prepareItemTracking(attributes, listItemV2 = false, searchQueryPrefixed = false) {
const cart = window.pageConfig.cart
const isCurrentUser = window.pageConfig.isCurrentUser
const productPricing = resolveProductPricing({
cart,
attributes,
id: attributes.id,
isCurrentUser,
})
const items = []
data = [{}, 0, 0]
if (attributes.searchingFree && productPricing.price > 0) {
data = [attributes, 0, attributes.price.toFixed(2)]
} else if (productPricing.ribbon === 'saleOff') {
if (productPricing.discount > 0) {
data = [attributes, (productPricing.originalPrice - productPricing.price).toFixed(2), productPricing.price.toFixed(2)]
} else {
data = [attributes, 0, attributes.price.toFixed(2)]
}
} else if (productPricing.ribbon === 'CLD') {
if (productPricing.discount > 0) {
data = [attributes, (productPricing.originalPrice - productPricing.price).toFixed(2), productPricing.price.toFixed(2)]
} else {
data = [attributes, 0, attributes.price.toFixed(2)]
}
} else {
data = [attributes, 0, attributes.price.toFixed(2)]
}
if (listItemV2) {
items.push(prepareTrackViewItemList(...data, searchQueryPrefixed))
} else {
items.push(prepareTrackViewItem(...data))
}
return items
}
function searchQueryPrefix() {
let prefix = '';
let currentSearchParams = new URLSearchParams(window.location.search);
if (currentSearchParams.has('keywords') && currentSearchParams.has('suggested') && currentSearchParams.get('suggested') === '1') {
prefix = 'suggested_'
} else if (currentSearchParams.has('keywords')) {
prefix = 'search_'
} else {
prefix = 'category_'
}
return prefix
}
function prepareTrackViewItemUA(attributes, discount, price) {
prefix = searchQueryPrefix()
const trackable_attributes = {
id: String(attributes.id),
name: attributes.title,
list_position: attributes.index,
category: attributes.category,
item_list_id: prefix + attributes.searchQuery,
item_list_name: prefix + attributes.searchQuery,
price: parseFloat((price - discount).toFixed(2)),
}
return trackable_attributes
}
function prepareTrackViewItemList(attributes, discount, price, prefixed = false) {
const hasSimilarModelsReference = window.pageConfig.similarSelect
const searchQuery = hasSimilarModelsReference ? 'similar' : attributes.searchQuery || ''
const trackable_attributes = {
item_id: String(attributes.id),
item_name: attributes.title,
affiliation: attributes.affiliation || '',
currency: 'USD',
index: parseInt(attributes.index) || 0,
item_brand: attributes.authorUsername,
item_category: attributes.category,
item_category2: attributes.subcategory,
item_category3: attributes.itemCategory3,
item_category4: attributes.itemCategory4,
item_category5: attributes.itemCategory5,
item_list_id: searchQuery,
item_list_name: searchQuery,
item_variant: attributes.productType,
location_id: attributes.locationId && attributes.locationId.join("_"),
price: parseFloat(price),
quantity: 1,
}
trackable_attributes.discount = discount > 0 ? parseFloat(discount) : 0
return trackable_attributes
}
function prepareTrackViewItem(attributes, discount, price) {
let prefix = '';
let currentSearchParams = new URLSearchParams(window.location.search);
if (currentSearchParams.has('keywords') && currentSearchParams.has('suggested') && currentSearchParams.get('suggested') === '1') {
prefix = 'suggested_'
} else if (currentSearchParams.has('keywords')) {
prefix = 'search_'
} else {
prefix = 'category_'
}
const trackable_attributes = {
item_id: String(attributes.id),
item_name: attributes.title,
currency: 'USD',
index: attributes.index,
item_category: attributes.category,
item_category2: attributes.subcategory,
item_list_id: prefix + attributes.searchQuery,
item_list_name: prefix + attributes.searchQuery,
price: price,
value: parseFloat((price - discount).toFixed(2)),
quantity: 1,
}
if (discount > 0) {
trackable_attributes.discount = parseFloat(discount)
}
return trackable_attributes
}
// Exact copy of /app/javascript/Utils/ResolveProductPricing.js
function resolveProductPricing({ cart, attributes, id, isCurrentUser }) {
const productDiscountAvailable = {
saleOff: cart.isSaleOff && attributes.isSaleOffApplicable,
cld: !cart.isCLDDisabled && attributes.isCLDApplicable
}
if ((productDiscountAvailable.saleOff) && attributes.saleOffDiscount !== 0) {
const discountedPrice = attributes.price * (100 - attributes.saleOffDiscount) / 100.0
return {
price: discountedPrice,
originalPrice: attributes.price,
discount: 1.0 - discountedPrice / attributes.price,
discountAmount: attributes.price - discountedPrice,
ribbon: 'saleOff',
}
} else if (productDiscountAvailable.cld) {
const isCartSizeSufficient =
cart.value + attributes.price >= cart.applicableCldValue
if (isCurrentUser && isCartSizeSufficient) {
let discountedPrice = Math.max(
attributes.price - cart.creditsAvailable,
attributes.price * 0.7
)
return {
price: discountedPrice,
originalPrice: attributes.price,
discount: 1.0 - discountedPrice / attributes.price,
discountAmount: attributes.price - discountedPrice,
ribbon: 'CLD',
}
} else {
return {
price: attributes.price,
originalPrice: attributes.price,
discount: 0,
discountAmount: 0,
ribbon: 'CLD',
}
}
} else {
return {
price: attributes.price,
originalPrice: attributes.price,
discount: 0,
}
}
}
function createElementWithConfig(element, config) {
const el = document.createElement(element);
Object.keys(config).forEach((key) => {
el.setAttribute(key, config[key]);
});
return el;
}
// Utility function to setup user interaction listeners
// Executes callback on first user interaction then removes listeners
window.setupUserInteractionListener = function(callback, options = {}) {
if (typeof callback !== 'function') {
console.warn('[setupUserInteractionListener] callback must be a function');
return;
}
let userHasInteracted = false;
const events = options.events || ['click', 'scroll', 'keydown', 'touchstart', 'mousemove'];
const useCapture = options.useCapture || false;
const handleUserInteraction = function(event) {
if (userHasInteracted) return;
userHasInteracted = true;
removeInteractionListeners();
callback(event);
};
const removeInteractionListeners = function() {
events.forEach(eventType => {
document.removeEventListener(eventType, handleUserInteraction, useCapture);
});
};
// Add listeners for user interactions
events.forEach(eventType => {
document.addEventListener(eventType, handleUserInteraction, useCapture);
});
// Return cleanup function in case manual cleanup is needed
return removeInteractionListeners;
}
;
//
// event bus
//
; (function () {
const events = []
App.events = {
publish: function (event, data) {
events.forEach(function (item) {
if (item.key === event) {
item.callback(data)
}
})
},
subscribe: function (event, callback) {
events.push({
key: event,
callback: callback,
})
},
unsubscribe: function (event, callback) {
const index = events.findIndex(function (item) {
return item.key === event && item.callback === callback
})
if (index > -1) {
events.splice(index, 1)
}
},
}
})();
'use strict'
function getToken() {
const meta = document.querySelector('meta[name="csrf-token"]')
const freshToken = meta ? meta.content : ''
return freshToken
}
function setToken() {
withElements('[name=authenticity_token]', function (element) { element.value = getToken() })
}
setToken()
;
function initSaleOff() {
'use strict'
function init(saleOffConfig) {
const { content, discount, discountPhrase, endsAt, useTimer } = saleOffConfig
let setIntervalId = null
withElements('.js-sale-off-timer', function (timerContainer) {
timerContainer.innerHTML = JSON.parse(timerContainer.getAttribute('data-timer')).content
withElementsSetInnerText('#sale-off-strip-content', content, timerContainer)
withElementsSetInnerText('#sale-off-strip-discount', `${discount}%`, timerContainer)
withElementsSetInnerText('#sale-off-strip-discount-phrase', discountPhrase, timerContainer)
withElementsSetDisplay('#sale-off-strip-time', 'none', timerContainer)
function updateTimer() {
let timeRemaining = endsAt - new Date().getTime()
if (timeRemaining >= 0) {
const days = parseInt(timeRemaining / (60 * 60 * 24 * 1000)).toString().padStart(2, '0')
timeRemaining = (timeRemaining % (60 * 60 * 24 * 1000))
const hours = parseInt(timeRemaining / (60 * 60 * 1000)).toString().padStart(2, '0')
timeRemaining = (timeRemaining % (60 * 60 * 1000))
const minutes = parseInt(timeRemaining / (60 * 1000)).toString().padStart(2, '0')
timeRemaining = (timeRemaining % (60 * 1000))
const seconds = parseInt(timeRemaining / 1000).toString().padStart(2, '0')
withElementsSetInnerText('#sale-off-strip-days', `${days} : `, timerContainer)
withElementsSetInnerText('#sale-off-strip-hours', `${hours} : `, timerContainer)
withElementsSetInnerText('#sale-off-strip-minutes', `${minutes} : `, timerContainer)
withElementsSetInnerText('#sale-off-strip-seconds', seconds, timerContainer)
} else {
withElementsSetDisplay('.js-sale-off-timer', 'none')
clearInterval(setIntervalId)
}
}
if (useTimer) {
setIntervalId = setInterval(updateTimer, 1000)
withElementsSetDisplay('#sale-off-strip-time', '', timerContainer)
}
})
}
if (
window.pageConfig.saleOff &&
window.pageConfig.saleOff.visible &&
window.pageConfig.saleOff.endsAt - new Date().getTime() > 0
) {
init(window.pageConfig.saleOff)
}
}
;
;(function() {
window.dataLayer = window.dataLayer || []
window.itemIdsBuffer = window.itemIdsBuffer || []
window.impressionsCounter = window.impressionsCounter || 0
window.track = function(options) {
window.dataLayer.push({
event: options.event || 'CustomEvent',
eventCategory: options.eventCategory || '',
eventAction: options.eventAction || '',
eventLabel: options.eventLabel || '',
eventValue: options.eventValue || '',
isNonInteractionHit: options.isNonInteractionHit || false,
})
}
window.trackCustomEvent = function(event = null) {
// this function is used to track GA events
// let's use this insted of window.dataLayer.push
if (event) {
window.dataLayer.push(event)
}
}
})();
"use strict";
function showGuestElements() {
withElementsSetDisplay(".js-only-for-user", "none");
withElementsSetDisplay(".js-only-for-admin", "none");
withElementsSetDisplay(".js-only-for-guest", "");
}
function showUserElements(isNotAdmin) {
withElementsSetDisplay(".js-only-for-guest", "none");
withElementsSetDisplay(".js-only-for-user", "");
if (isNotAdmin) {
withElementsSetDisplay(".js-only-for-admin", "none");
}
}
function bindUserInfo(props) {
const { currentUserUsername, currentUserAvatarUrl } = props
if (currentUserAvatarUrl) {
withElementsSetDisplay(".js-current-user-initials", "none");
withElements(".js-current-user-avatar-image", function (element) {
element.src = currentUserAvatarUrl;
});
} else {
withElements(".js-avatar-container", function (element) {
element.classList.add("is-empty");
});
withElementsSetDisplay(".js-current-user-avatar-image", "none");
withElementsSetInnerText(
".js-current-user-initials",
currentUserUsername[0].toUpperCase()
);
}
}
function nodeScriptExec(node) {
withElements('script', function (el) {
eval(el.innerHTML)
}, node)
}
function goBack() {
history.go(-1)
}
window.nodeScriptExec = nodeScriptExec;
window.goBack = goBack;
; (function () {
window.showNotification = function (text, options) {
// Ugly alternative for null coalescing (??) on node 12
const autohide = (options.autohide !== null && options.autohide !== undefined) ? options.autohide : true;
const type = options.type || 'success';
const appendIcon = (options.appendIcon !== null && options.appendIcon !== undefined) ? options.appendIcon : true;
const notification = document.createElement('div')
notification.classList.add(
'notifyjs-custom-base',
'notifyjs-custom-' + type
)
notification.addEventListener('click', function () {
notification.parentNode.removeChild(notification)
})
if (appendIcon) {
const icon = document.createElement('div')
icon.classList.add('notification-icon')
notification.append(icon)
switch (type) {
case 'success':
icon.classList.add('fa', 'fa-check-circle')
break
case 'error':
icon.classList.add('fa', 'fa-times-circle')
break
}
}
const content = document.createElement('div')
content.classList.add('notification-content')
if (options.className) {
content.classList.add(options.className)
}
content.innerHTML = text
notification.append(content)
const close = document.createElement('div')
close.classList.add('notification-close-icon', 'fa', 'fa-times')
if (options.onDismiss) {
close.addEventListener('click', options.onDismiss)
}
notification.append(close)
if (autohide) {
let timeout = autohide === true ? 5000 : parseInt(autohide, 10)
setTimeout(function () {
if (notification.parentNode) {
notification.parentNode.removeChild(notification)
}
}, timeout)
}
withId('notifications-container').append(notification)
if (type !== 'error') {
let eventLabel = text
if (/has successfully been added to the cart/.test(eventLabel)) {
eventLabel = 'Item has successfully been added to the cart'
} else if (/has already been added to the cart/.test(eventLabel)) {
eventLabel = 'Item has already been added to the cart'
}
}
}
})()
;
/*!
* JavaScript Cookie v2.2.0
* https://github.com/js-cookie/js-cookie
*
* Copyright 2006, 2015 Klaus Hartl & Fagner Brack
* Released under the MIT license
*/
;(function (factory) {
var registeredInModuleLoader = false;
if (typeof define === 'function' && define.amd) {
define(factory);
registeredInModuleLoader = true;
}
if (typeof exports === 'object') {
module.exports = factory();
registeredInModuleLoader = true;
}
if (!registeredInModuleLoader) {
var OldCookies = window.Cookies;
var api = window.Cookies = factory();
api.noConflict = function () {
window.Cookies = OldCookies;
return api;
};
}
}(function () {
function extend () {
var i = 0;
var result = {};
for (; i < arguments.length; i++) {
var attributes = arguments[ i ];
for (var key in attributes) {
result[key] = attributes[key];
}
}
return result;
}
function init (converter) {
function api (key, value, attributes) {
var result;
if (typeof document === 'undefined') {
return;
}
// Write
if (arguments.length > 1) {
attributes = extend({
path: '/'
}, api.defaults, attributes);
if (typeof attributes.expires === 'number') {
var expires = new Date();
expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
attributes.expires = expires;
}
// We're using "expires" because "max-age" is not supported by IE
attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
try {
result = JSON.stringify(value);
if (/^[\{\[]/.test(result)) {
value = result;
}
} catch (e) {}
if (!converter.write) {
value = encodeURIComponent(String(value))
.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
} else {
value = converter.write(value, key);
}
key = encodeURIComponent(String(key));
key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
key = key.replace(/[\(\)]/g, escape);
var stringifiedAttributes = '';
for (var attributeName in attributes) {
if (!attributes[attributeName]) {
continue;
}
stringifiedAttributes += '; ' + attributeName;
if (attributes[attributeName] === true) {
continue;
}
stringifiedAttributes += '=' + attributes[attributeName];
}
return (document.cookie = key + '=' + value + stringifiedAttributes);
}
// Read
if (!key) {
result = {};
}
// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all. Also prevents odd result when
// calling "get()"
var cookies = document.cookie ? document.cookie.split('; ') : [];
var rdecode = /(%[0-9A-Z]{2})+/g;
var i = 0;
for (; i < cookies.length; i++) {
var parts = cookies[i].split('=');
var cookie = parts.slice(1).join('=');
if (!this.json && cookie.charAt(0) === '"') {
cookie = cookie.slice(1, -1);
}
try {
var name = parts[0].replace(rdecode, decodeURIComponent);
cookie = converter.read ?
converter.read(cookie, name) : converter(cookie, name) ||
cookie.replace(rdecode, decodeURIComponent);
if (this.json) {
try {
cookie = JSON.parse(cookie);
} catch (e) {}
}
if (key === name) {
result = cookie;
break;
}
if (!key) {
result[name] = cookie;
}
} catch (e) {}
}
return result;
}
api.set = api;
api.get = function (key) {
return api.call(api, key);
};
api.getJSON = function () {
return api.apply({
json: true
}, [].slice.call(arguments));
};
api.defaults = {};
api.remove = function (key, attributes) {
api(key, '', extend(attributes, {
expires: -1
}));
};
api.withConverter = init;
return api;
}
return init(function () {});
}));
// TO-DO: extract this into a fast_pages category. Stop using fast_product_page for everything
//
// abstract dom controller
//
; (function () {
window.createAndShowModal = function (data, options) {
let html
if (data.id) {
html = withId(data.id).innerHTML
} else {
html = data
}
const modal = createModal(html, options)
showModal(modal)
}
window.reload = function () {
document.location.reload()
}
window.reloadAfterLogin = function () {
reload()
}
window.getData = function (target, event) {
if (event) {
event.preventDefault()
}
const dataset = target.dataset
const url = !!dataset.url.match(/^\//)
? dataset.url
: window.location.pathname + '/' + dataset.url
performXHR(dataset.method || 'get', url, function (data) {
switch (dataset.onsuccess) {
case 'createAndShowModal':
createAndShowModal(data, { rootClass: dataset.class })
break
case 'showPopover':
withId(dataset.target).innerHTML = data
showPopover(target, null)
break
case 'reload':
reload()
break
}
})
}
window.parseData = function (data) {
if (data && data.data && data.data.type) {
switch (data.data.type) {
case 'cartItems':
if (data.meta) {
window.pageConfig.cart.size = data.meta.size
window.pageConfig.cart.itemIds = data.meta.itemIds
window.pageConfig.cart.cartItemIds = data.meta.cartItemIds
window.pageConfig.cart.creditsAvailable = data.meta.storeCreditsLeft
if (data.meta.item) {
window.pageConfig.cart.totalPrice = pageConfig.cart.totalPrice + data.meta.item.price
window.pageConfig.cart_items = data.meta.trackingCartItems
}
personalize(window.pageConfig)
}
break
}
}
}
window.isMobileView = function () {
return window.innerWidth 0 && window.searchTracker) {
window.searchTracker({
searchTerm: searchQuery,
type: 'model',
})
}
})
}
window.showErrorsNotifications = function (errors) {
for (let key in errors) {
if (typeof errors[key] === 'string' && key !== 'status') {
showNotification(errors[key], {
type: 'error',
autohide: true,
})
}
}
}
document.addEventListener('submit', function (e) {
const form = e.target
const formClasses = form.classList
const isSearchForm = formClasses.contains('js-search')
const searchButton = form.querySelector('.js-search-button')
const isJSform = formClasses.contains('js-form')
const isAddToCart = formClasses.contains('js-add-to-cart')
if (searchButton) {
const icon = searchButton.querySelector('.js-search-button-icon')
const loader = searchButton.querySelector('.js-search-button-loader')
if (icon && loader) {
icon.classList.add('is-hidden')
loader.classList.remove('is-hidden')
}
}
const disableFormSubmissions = disabled => {
withElements(
'[type=submit]',
function (el) {
el.disabled = disabled
},
form
)
}
const conditionallyAppendInformations = () =>
form.querySelectorAll('input').forEach((input) => {
if (input.name === 'location') {
return (input.value = window.location.pathname)
}
if (input.name === 'utm_statistics[referrer]') {
const referrer = Cookies.get('__gtm_referrer') || ''
return (input.value = referrer)
}
if (input.name === 'utm_statistics[raw_utm_string]') {
const raw_utm_string = Cookies.get('__gtm_campaign_url') || ''
return (input.value = raw_utm_string)
}
})
conditionallyAppendInformations()
if (isSearchForm) {
e.preventDefault()
sendSearchQueryToAnalytics(e)
const formUrl = extractCurrentSearchQuery(form)
if (!formUrl) return form.submit()
const searchUrl = new URL(formUrl)
const searchKeywords = form.querySelector('[name="keywords"]').value
searchUrl.searchParams.append('keywords', searchKeywords)
return window.location.href = searchUrl.href
}
if (formClasses.contains('js-purchase-button-form') && !formClasses.contains('js-add-to-cart')) {
e.preventDefault()
if (window.pageConfig && window.pageConfig && window.pageConfig.product) {
const itemAttributes = window.pageConfig.product
trackAddToCart(itemAttributes);
}
}
if (isJSform) {
e.preventDefault()
try {
const formData = new FormData(form)
if (formClasses.contains('js-purchase-button-form')) {
if (window.pageConfig && window.pageConfig.product && window.pageConfig.product.searchQuery) {
formData.set('search_query', pageConfig.product.searchQuery)
formData.set('index', window.pageConfig.indexTrack)
}
}
if (isAddToCart) {
const sendAddToCartActionToAnalytics = () => {
const parent = findAncestor('js-fast-listing-item', form)
const itemAttributes = getItemData(parent)
if (itemAttributes.searchQuery) {
formData.set('search_query', itemAttributes.searchQuery)
formData.set('index', itemAttributes.index)
}
trackAddToCart(itemAttributes, false);
}
sendAddToCartActionToAnalytics()
}
disableFormSubmissions(true)
const appendTwoFaStep = () => {
const requiredFields = [
'user[login]',
'user[password]',
'user[remember_me]',
]
for (var [inputField, value] of formData.entries()) {
if (requiredFields.includes(inputField)) {
document.getElementById('two-fa-second-state-form')[
inputField
].value = value
}
}
withElementsSetDisplay('.form__log-in', 'none')
withElementsSetDisplay('.form__two-fa-second-state', 'block')
}
const handleLoginSessionExpiration = () => {
// reload page to get valid session token
return window.location.reload()
}
const formSubmissionCallback = (data, status) => {
const isLoginAction = form.action.includes('/2fa-or-login')
disableFormSubmissions(false)
if (status === 422 && isLoginAction) {
return handleLoginSessionExpiration()
}
data = JSON.parse(data)
const isTwoFaForm = data.twoFaEnabled
const twoFaIsValid = isTwoFaForm && status === 200
const sucessfulResponse = data.jsonapi || data.success || twoFaIsValid
if (sucessfulResponse) {
parseData(data)
const message = data.message || form.dataset.successmessage
const formHasOnSuccessFunction =
form.dataset.onsuccess &&
typeof window[form.dataset.onsuccess] === 'function'
const shouldReloadPage = form.dataset.reloadpage === 'true'
if (message) {
showNotification(message, {
type: 'success',
autohide: true,
})
}
if (data.twoFaEnabled) {
return appendTwoFaStep()
}
if (formHasOnSuccessFunction) {
window[form.dataset.onsuccess]()
}
if (shouldReloadPage) {
if (location.href.includes('?rating=')) {
return window.location.href = location.href.split('?')[0];
}
return window.location.reload()
}
if (data.redirectTo) {
disableFormSubmissions(true)
window.location = data.redirectTo
}
} else {
const errorMessage =
typeof data.error === 'string' ? data.error : data.message
const formHasOnErrorFunction =
form.dataset.onerror &&
typeof window[form.dataset.onerror] === 'function'
if (formHasOnErrorFunction) {
window[form.dataset.onerror]()
}
if (errorMessage) {
showNotification(errorMessage, {
type: 'error',
autohide: true,
})
} else if (data.errors && data.errors instanceof Object && data.errors.length) {
showErrorsNotifications(data.errors)
} else if (data.errors && data.errors.custom_errors) {
showErrorsNotifications(data.errors.custom_errors)
} else {
showNotification('Something went wrong, please try again', {
type: 'error',
autohide: true,
})
}
}
}
const currentMethod = form.classList.contains('comment-form') ? form.dataset.method : form.method
performXHR(currentMethod, form.action, formSubmissionCallback, formData)
return false
} catch (error) {
const isLoginAction = form.action.includes('/2fa-or-login')
const isRegistrationAction =
form.action.includes('/users') &&
form
.querySelector('button[type="submit"]')
.textContent.includes('Register')
if (isLoginAction) {
const loginErrorContext = {
msg: 'Login error',
email: form.querySelector('[name="user[login]"]').value,
}
window.sendErrorToSentry(error, { tags: { section: 'Fast pages login' }, extra: loginErrorContext })
}
if (isRegistrationAction) {
const registrationErrorContext = {
msg: 'Registration error',
email: form.querySelector('[name="new_user[email]"]').value,
gdprConsent: form.querySelector('[name="new_user[gdpr_consent]"]')
.value,
}
window.sendErrorToSentry(error, { tags: { section: 'Fast pages registration' }, extra: registrationErrorContext })
}
return showNotification('An unexpected error ocurred', {
type: 'error',
autohide: true,
})
}
}
})
function extractCurrentSearchQuery(form) {
const params = window.location.href.split('?')[1]
const formUrl = new URL(form.action)
const skipParams = ['page', 'suggested_keywords', 'keywords']
if (params === undefined) return
const searchQuery = new URLSearchParams(params)
for (const key of searchQuery.keys()) {
if (skipParams.includes(key)) continue
formUrl.searchParams.append(key, searchQuery.get(key))
}
return formUrl.href
}
function resetCaptcha(id) {
if (document.getElementById(id)) {
mtcaptcha.resetUI(id)
}
}
window.resetLoginCaptcha = function () {
resetCaptcha('login-captcha')
}
window.resetRegistrationCaptcha = function () {
resetCaptcha('registration-captcha')
}
})()
//
// popovers
//
; (function () {
window.hidePopover = function () {
withElements('.popover-container.is-active', function (item) {
item.classList.remove('is-active')
})
}
const showPopoverDelay = 100;
let showPopoverLastExecution = 0;
window.showPopover = function (container, event) {
if ((showPopoverLastExecution + showPopoverDelay) < Date.now()) {
// close other popovers
withElements('.popover-container.is-active', function (item) {
if (item !== container) {
item.classList.remove('is-active')
}
})
if (container) {
// block direct-link clicks
if (event) {
const a =
event.target.tagName === 'A'
? event.target
: event.target.closest('a')
if (a && a.parentNode === container) {
event.preventDefault()
}
}
if (event === null || (window.pageConfig && !window.pageConfig.servicesLoaded)) {
return
}
// dont close on popover content click
if (!event || (event && !event.target.closest('.popover'))) {
if (container.classList.contains('is-active')) {
container.classList.remove('is-active')
App.events.publish(container, 'popover-closed')
} else {
container.classList.add('is-active')
App.events.publish(container, 'popover-opened')
}
showPopoverLastExecution = Date.now()
}
}
}
}
function handlePopoverClick(e) {
const container = getContainer(e, 'popover-container')
if (
container
&& container.id === 'login-popover'
&& window.mountPasswordComponent
) {
window.mountPasswordComponent()
}
showPopover(container, e)
}
document.addEventListener('click', handlePopoverClick)
}())
//
// cart
//
; (function () {
document.addEventListener('click', function (event) {
const targetClasses = event.target.classList
if (targetClasses.contains('js-checkout-click') && pageConfig && pageConfig.cart_items) {
trackProceedToCheckout()
}
return null
});
document.addEventListener('auxclick', function (event) {
const targetClasses = event.target.classList
if (event.button === 1) {
if (targetClasses.contains('js-checkout-click') && pageConfig && pageConfig.cart_items) {
trackProceedToCheckout()
}
}
return null
});
function trackProceedToCheckout() {
let cartItems = [];
for (let cartItemId in pageConfig.cart_items) {
cartItems.push(prepareItemTracking(pageConfig.cart_items[cartItemId], true, true)[0])
}
window.dataLayer && window.dataLayer.push({
event: 'begin_checkout',
ecommerce: {
currency: 'USD',
value: pageConfig.cart.totalPrice,
items: cartItems
}
})
}
function trackRemoveFromCart(item_data) {
const item = prepareItemTracking(item_data, true, true)
window.pageConfig.cart.totalPrice = window.pageConfig.cart.totalPrice - item.price
window.dataLayer && window.dataLayer.push({
event: 'remove_from_cart',
user_id: window.pageConfig.currentUserId || '',
ecommerce: {
currency: 'USD',
value: item[0]['price'],
items: item
},
_clear: true,
})
}
function setCart(html) {
withId('top-menu-cart').innerHTML = html
nodeScriptExec(withId('top-menu-cart'))
}
window.getCartAsync = async function () {
try {
return new Promise((resolve, reject) => {
performXHR('get', '/api/internal/cg/cart_items.html', (response, status) => {
if (status >= 200 && status < 300) {
withId('top-menu-cart').innerHTML = response
nodeScriptExec(withId('top-menu-cart'))
resolve({
data: response,
status,
hasItems: window.pageConfig?.cart?.size > 0
})
} else {
reject(new Error('Failed to load cart'))
}
})
})
} catch (error) {
console.error('Error in getCartAsync:', error)
throw error
}
}
window.removeFromCart = function (context) {
const item_id = context.attributes['data-item'].value;
trackRemoveFromCart(window.pageConfig.cart_items.filter(function (el) { return el.id == item_id; })[0])
window.pageConfig.cart_items = window.pageConfig.cart_items.filter(function (el) { return el.id != item_id; });
performXHR('delete', context.attributes['data-href'].value, (response) => {
setCart(response)
App.events.publish('item-removed-from-cart');
window.dispatchEvent(new Event('item-removed-from-cart'));
})
if (window.pageConfig.cart_items.length === 0) {
hidePopover();
}
}
function trackGA4ViewCart() {
let cartItems = [];
for (let cartItem in pageConfig.cart_items) {
cartItems.push(prepareItemTracking(pageConfig.cart_items[cartItem], true, true)[0])
}
window.dataLayer && window.dataLayer.push({
event: 'view_cart',
ecommerce: {
currency: 'USD',
value: pageConfig.cart.totalPrice,
items: cartItems
}
})
}
})()
//
// tabs
//
; (function () {
window.setNavTab = function (id, e) {
const tabs = getParentWith('#' + id, e.target)
withElements(
'.cgt-tab, .tab-pane',
function (item) {
item.classList.remove('is-active', 'cgt-tab--active')
},
tabs
)
e.target.closest('.cgt-tab').classList.add('cgt-tab--active')
withId(id).classList.add('is-active')
}
window.setTab = function (id, e) {
const tabs = getParentWith('#' + id, e.target)
withElements(
'.tab, .tab-pane',
function (item) {
item.classList.remove('is-active')
},
tabs
)
e.target.closest('.tab').classList.add('is-active')
withId(id).classList.add('is-active')
}
})()
;
Our website uses cookies to collect statistical visitor data and track interaction with direct marketing communication / improve our website and improve your browsing experience. Please see our Cookie Notice for more information about cookies, data they collect, who may access them, and your rights. Learn more AcceptWeekend Sale🚀 UP TO 50%OFF 🚀Sale ends inFind deals