Plugin Directory

Changeset 3340495


Ignore:
Timestamp:
08/06/2025 03:59:08 PM (8 months ago)
Author:
petredobrescu
Message:

Version 3.11.0

🌩️ The S3 & Speed Boost Update

Release Date: August 6, 2025

✨ New Features

  • Amazon S3 Integration: Images stored on Amazon S3 can now be seamlessly served through the ShortPixel CDN — faster delivery, no matter where your files live.
  • Lazy-Load Exclusions by URL: You can now exclude specific images from lazy-loading by their URL for greater control over your image loading strategy.

⚙️ Improvements

  • Smarter LQIP Handling: Optimized the way Low-Quality Image Placeholders (LQIPs) are processed to boost performance on sites with lots of images.

🛠️ Fixes

  • Settings Export Restored: Exporting your plugin settings now works reliably in all scenarios.
  • LQIP Fixes: Addressed several minor issues to ensure LQIPs behave correctly across different setups.
  • Security Enhancements: Added extra security checks to strengthen protection and prevent potential vulnerabilities.

Update now to enjoy smarter performance, better control, and enhanced flexibility with your image delivery! 🚀

Location:
shortpixel-adaptive-images
Files:
40 edited
1 copied

Legend:

Unmodified
Added
Removed
  • shortpixel-adaptive-images/tags/3.11.0/assets/css/admin.css

    r3209129 r3340495  
    381381}
    382382
    383 .blue_link {
     383.blue_link,
     384.survey-rating-btn, #survey-feedback-submit {
    384385    cursor             : pointer;
    385386    color              : #ffffff !important;
     
    402403}
    403404
    404 .dark_blue_link:hover, .blue_link:hover {
     405.dark_blue_link:hover,.blue_link:hover,
     406.survey-rating-btn:hover, #survey-feedback-submit {
    405407    color   : #ffffff !important;
    406408    border  : none !important;
    407     opacity : 0.9 !important;
     409    opacity : 0.7 !important;
    408410}
    409411
  • shortpixel-adaptive-images/tags/3.11.0/assets/css/admin.min.css

    r3209129 r3340495  
    1 .shortpixel-settings-wrap input,.shortpixel-settings-wrap textarea,.shortpixel-settings-wrap button{outline:unset!important}.plugins tr[data-slug=shortpixel-adaptive-images] td div p span{display:block;margin:5px 0;padding-left:25px}.shortpixel-on-boarding-wrap{background:#fff}.shortpixel-on-boarding-wrap .socials-block{width:100%;max-width:1e3px;margin-top:10px}.socials-block,.socials-block *{-webkit-box-sizing:border-box;box-sizing:border-box}.socials-block{position:relative;padding:20px;border-radius:15px;font-weight:600;margin-bottom:10px;background:#dfffff}.socials-block>.message-wrap{width:100%;color:#05869f;padding-right:200px}.socials-block:before{content:'';position:absolute;display:block;width:20px;height:20px;top:-8px;left:20px;background:url(../img/socials/share.svg)50%/contain no-repeat}.socials-block>.buttons-wrap{position:absolute;display:block;top:calc(50% - 20px);right:20px}.socials-block [data-social]:before{content:'';position:absolute;width:16px;height:16px;top:calc(50% - 8px);left:7px}.socials-block [data-social]:last-child{margin-right:0}.socials-block [data-social]{position:relative;display:block;float:left;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;line-height:20px;margin-right:5px;border-radius:10px;padding:10px 10px 10px 30px;text-decoration:unset;outline:none;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.socials-block [data-social=twitter]{background:#d9e9f9;color:#2c76ec}.socials-block [data-social=twitter]:hover{-webkit-box-shadow:inset 1px 2px 2px rgba(44,118,236,.2);box-shadow:inset 1px 2px 2px rgba(44,118,236,.2)}.socials-block [data-social=twitter]:before{background:url(../img/socials/twitter.svg)50%/contain no-repeat}.socials-block [data-social=facebook]{background:#d9e6ff;color:#2152b3}.socials-block [data-social=facebook]:hover{-webkit-box-shadow:inset 1px 2px 2px rgba(33,82,179,.2);box-shadow:inset 1px 2px 2px rgba(33,82,179,.2)}.socials-block [data-social=facebook]:before{background:url(../img/socials/facebook.svg)50%/contain no-repeat}.sp-obw__title-wrap img{height:64px;width:64px;float:left;margin:10px 20px 10px 10px}.sp-obw__title-wrap{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.sp-obw__title-wrap:after{position:absolute;bottom:0;left:0;clear:both;width:100%;height:1px;background:#ccc;content:'';display:block}.sp-obw__content-wrap{padding:20px}.sp-obw__content-wrap p{font-size:14px}.sp-obw__content-wrap span.sp-obw-step{line-height:36px}.sp-obw__content-wrap span.sp-obw-alert{font-weight:600;color:crimson}.sp-obw__content-wrap .step-message-wrap label{vertical-align:top;margin-right:10px}.sp-obw__content-wrap .step-message-wrap p button{margin:0 10px 0 0}.sp-obw__content-wrap .step-message-wrap p button:last-child{margin:0}.sp-obw__content-wrap .step-message-wrap button:disabled{color:#a0a5aa!important;border-color:#ddd!important;background:#f7f7f7!important;-webkit-box-shadow:0 1px 1px rgba(171,170,170,.3)!important;box-shadow:0 1px 1px rgba(171,170,170,.3)!important}.bordered_link{cursor:pointer;color:#1fbec9;font-size:14px;line-height:18px;padding:5px 10px;display:inline-block;background:#f5f5f5!important;border:1px solid #1fbec9!important;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:0 1px 1px rgba(171,170,170,.3);box-shadow:0 1px 1px rgba(171,170,170,.3);border-radius:3px;text-decoration:none;margin-bottom:15px;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear}.bordered_link:hover{color:#0f6b7e!important;background:0 0!important}.shortpixel-steps{max-width:670px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding-bottom:24px;margin:30px 0;position:relative}.shortpixel-steps:before{position:absolute;content:'';height:2px;background:#ccc;width:100%;left:0;top:18px;z-index:1}.shortpixel-steps:after{position:absolute;content:'';height:2px;background:#ec2c25;width:100%;left:0;top:18px;z-index:2;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear}.shortpixel-steps[data-step="0"]:after{width:39px}.shortpixel-steps[data-step="1"]:after{width:calc(((100% - 58px)/3) + 39px)}.shortpixel-steps[data-step="2"]:after{width:calc(((100% - 58px) * 2/3) + 39px)}.shortpixel-steps[data-step="3"]:after{width:100%}.shortpixel-steps .step:nth-child(1){padding-left:20px}.shortpixel-steps .step .number{position:relative;font-weight:700;font-size:20px;color:#ccc;line-height:32px;height:34px;width:34px;text-align:center;border:2px solid #ccc;border-radius:50%;background:#fff;z-index:3}.shortpixel-steps .step.active .number,.shortpixel-steps .step.passed .number{color:#1fbec9;border:2px solid #ec2c25}.shortpixel-steps .step .title{position:absolute;color:#555d66;width:80px;text-align:center;opacity:.4;text-transform:uppercase;left:-24px;font-size:14px;bottom:-30px}.shortpixel-steps .step.active .number .title{opacity:1}.sp-obw__content-wrap .step-message-wrap .action-wrap [data-action]{margin-left:5px}div.spai-modal-shade{display:none;position:fixed;z-index:10;left:0;top:0;width:100%;height:100%;overflow:auto;background:#000;opacity:.4}div.spai-modal{background-color:#fefefe;padding:20px;border:1px solid #888;width:30%;min-width:300px;z-index:100001;position:fixed;top:10%;left:50%;max-height:90%;overflow-y:auto}div.spai-modal-title{font-size:22px}div.spai-modal-body{margin-top:10px}div.spai-modal button.spai-close-upgrade-button{float:right;margin-top:0;background:0 0!important;border:none;font-size:22px;line-height:10px;cursor:pointer}.dark_blue_link{cursor:pointer;color:#fff;height:30px;line-height:30px;padding:0 20px;background:#116c7d!important;display:inline-block;-webkit-box-shadow:0 1px 1px #09343d!important;box-shadow:0 1px 1px #09343d!important;border:none!important;border-radius:3px;text-decoration:none;margin-right:10px;position:relative;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;margin-bottom:15px;border:0;outline:none}.blue_link{cursor:pointer;color:#fff!important;height:30px;line-height:30px;padding:0 20px;background:#1fbec9!important;display:inline-block;-webkit-box-shadow:0 1px 1px #16858c;box-shadow:0 1px 1px #16858c;border-radius:3px;text-decoration:none;margin-right:10px;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;margin-bottom:15px;border:0!important;outline:none}.dark_blue_link:hover,.blue_link:hover{color:#fff!important;border:none!important;opacity:.9!important}.dark_blue_link:focus,.blue_link:focus,.dark_blue_link:active,.blue_link:active{color:#fff}.blue_link:disabled,.blue_link:disabled:hover,.dark_blue_link:disabled,.dark_blue_link:disabled:hover{cursor:not-allowed!important;opacity:1!important;color:#737373!important;background:#e2e2e2!important;-webkit-box-shadow:0 1px 1px #8a8a8a!important;box-shadow:0 1px 1px #8a8a8a!important}.bordered_link:disabled,.bordered_link:disabled:hover{cursor:not-allowed!important;opacity:1!important;color:#969696!important;background:#efefef!important;border-color:#ccc!important}.next_icon{padding-right:35px;position:relative}.next_icon:after{content:'';width:9px;height:11px;position:absolute;right:15px;top:10px;background:url(../img/next.svg)50%/cover no-repeat;-webkit-transition:all .2s linear;-o-transition:all .2s linear;transition:all .2s linear}.fast-forward_link{padding-right:40px;position:relative}.fast-forward_link:after{content:'';width:14px;height:13px;position:absolute;right:15px;top:9px;background:url(../img/fast-forward.svg)50%/contain no-repeat;-webkit-transition:all .2s linear;-o-transition:all .2s linear;transition:all .2s linear}.next_icon:hover:after,.fast-forward_link:hover:after{right:10px}@media(max-width:400px){.shortpixel-steps .step .title{text-transform:none}}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{background-position:50%;background-size:contain;background-repeat:no-repeat;background-image:url(../img/robo-happy.png)!important}.notice[data-plugin=short-pixel-ai]{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px}.notice[data-plugin=short-pixel-ai] .body-wrap{position:relative;padding-left:75px}.notice[data-plugin=short-pixel-ai] .body-wrap .message-wrap span{font-weight:600;color:crimson}.notice[data-plugin=short-pixel-ai][data-icon=none] .body-wrap{padding-left:0}.notice[data-plugin=short-pixel-ai][data-icon] .body-wrap:before{content:'';position:absolute;left:0;width:64px;height:100%;background-position:50%;background-size:contain;background-repeat:no-repeat}.notice[data-plugin=short-pixel-ai][data-icon=none] .body-wrap:before{content:none;position:unset;left:0;width:0;height:0;background:0 0}.notice[data-plugin=short-pixel-ai][data-icon=scared] .body-wrap:before{background-image:url(../img/robo-scared.png)}.notice[data-plugin=short-pixel-ai][data-icon=happy] .body-wrap:before{background-image:url(../img/robo-happy.png)}.notice[data-plugin=short-pixel-ai][data-icon=wink] .body-wrap:before{background-image:url(../img/robo-wink.png)}.notice[data-plugin=short-pixel-ai][data-icon=cool] .body-wrap:before{background-image:url(../img/robo-cool.png)}.notice[data-plugin=short-pixel-ai][data-icon=magnifier] .body-wrap:before{background-image:url(../img/robo-magnifier.png)}.notice[data-plugin=short-pixel-ai][data-icon=notes] .body-wrap:before{background-image:url(../img/robo-notes.png)}.notice[data-plugin=short-pixel-ai] .buttons-wrap{margin:10px 0}.notice[data-plugin=short-pixel-ai] .buttons-wrap .button{margin-right:5px}.dismissed-notice[data-plugin=short-pixel-ai] .buttons-wrap .button{margin:0 5px 5px 0}.notice[data-plugin=short-pixel-ai] .buttons-wrap .button:last-child{margin-right:0}div.spai-inline-help{float:right}div.spai-inline-help span{font-size:1.8em;color:#0bb5c1;cursor:pointer}div.spai-modal{background-color:#fefefe;padding:20px 16px 16px;border:1px solid #888;width:30%;max-width:610px;margin-left:-305px;min-width:300px;z-index:100;position:fixed;top:10%;left:50%;max-height:90%;overflow-y:auto}div.spai-modal-spinner{background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50%}.spai-loading{width:100%;min-height:200px;background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50% 0}@media(max-width:610px){div.spai-modal{width:100%;margin-left:-50%;padding:20px 0 16px}}div.spai-modal .spai-close-help-button{position:absolute;top:5px;right:0;margin-top:0;background:0 0;border:none;font-size:22px;line-height:10px;cursor:pointer}div.spai-modal-title{font-size:22px}.spai-hide{display:none}.spai_settings_tab{display:none;background:#fff;border-right:1px solid #e5e5e5;border-left:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;padding:30px 20px}.spai_settings_tab.active{display:block}.shortpixel-settings-tabs{width:calc(100% - 370px);float:left}.shortpixel-settings-tabs .nav-tab-wrapper{position:relative}.shortpixel-settings-tabs .nav-tab:focus{-webkit-box-shadow:none;box-shadow:none;outline:none}.shortpixel-settings-tabs .nav-tab-active{background:#fff;border-bottom:1px solid #fff}.shortpixel-settings-tabs .form-table td label{display:inline-block}.children-wrap{display:block;visibility:visible;opacity:1;max-height:1e4px;margin:5px 0 5px 40px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.children-wrap.hidden{visibility:hidden;opacity:0;max-height:0}.children-wrap.hidden label{display:none}.children-wrap .shortpixel_radio_btns{margin-bottom:0}.children-wrap .bordered_link{margin-bottom:0}.spai_top_actions{cursor:pointer;float:right;border:1px solid #1fbec9;border-bottom:none;margin-left:.5em;padding:5px 10px;font-size:14px;line-height:1.71428571;font-weight:600;background:#1fbec9;color:#fff;text-decoration:none;white-space:nowrap;outline:none}.spai_top_actions:hover{background:#0fa9b4}.clearcss-icon{background:url(../img/clearcss-white.svg)no-repeat;background-size:auto;display:inline-block;height:20px;width:24px;margin-top:4px}#clear_css_cache{margin-bottom:0;padding:2px 5px;height:35px}.shortpixel_radio_btns input{display:none}.shortpixel_radio_btns{-webkit-box-shadow:0 1px 1px #b6b2b2;box-shadow:0 1px 1px #b6b2b2;border-radius:3px;height:32px;display:inline-block;overflow:hidden;font-size:0;vertical-align:middle;margin-right:0;margin-bottom:20px}.shortpixel_radio_btns label{background:#ccc;text-transform:uppercase;display:inline-block;color:#fff;line-height:32px;padding:0 29px;border-left:1px solid #b4b4b4;border-right:1px solid #b4b4b4;font-size:14px;font-weight:700;margin:0 -1px;-webkit-transition:all .2s ease-in;-o-transition:all .2s ease-in;transition:all .2s ease-in}.shortpixel_radio_btns input:checked+label{background:#1fbec9;-webkit-box-shadow:0 0 3px #2a6c78;box-shadow:0 0 3px #2a6c78;border-left:1px solid #1fbec9;border-right:1px solid #1fbec9;position:relative}.shortpixel_radio_btns label:hover{background:#bbb}.shortpixel_radio_btns input:checked+label:hover{background:#0fa9b4}.shortpixel-settings-tabs input[type=text],.shortpixel-settings-tabs textarea{border:1px solid #ddd;border-radius:2px;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs input.error[type=text],.shortpixel-settings-tabs textarea.error,.shortpixel-settings-tabs input.error[type=text]:focus,.shortpixel-settings-tabs textarea.error:focus{border:1px solid crimson;-webkit-box-shadow:0 0 2px 1px rgba(220,20,60,.15),inset 0 0 2px 1px rgba(220,20,60,.15);box-shadow:0 0 2px 1px rgba(220,20,60,.15),inset 0 0 2px 1px rgba(220,20,60,.15)}.shortpixel-settings-tabs textarea{width:100%;max-width:100%;min-width:100%;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs input[type=checkbox]:focus,.shortpixel-settings-tabs input[type=color]:focus,.shortpixel-settings-tabs input[type=date]:focus,.shortpixel-settings-tabs input[type=datetime-local]:focus,.shortpixel-settings-tabs input[type=datetime]:focus,.shortpixel-settings-tabs input[type=email]:focus,.shortpixel-settings-tabs input[type=month]:focus,.shortpixel-settings-tabs input[type=number]:focus,.shortpixel-settings-tabs input[type=password]:focus,.shortpixel-settings-tabs input[type=radio]:focus,.shortpixel-settings-tabs input[type=search]:focus,.shortpixel-settings-tabs input[type=tel]:focus,.shortpixel-settings-tabs input[type=text]:focus,.shortpixel-settings-tabs input[type=time]:focus,.shortpixel-settings-tabs input[type=url]:focus,.shortpixel-settings-tabs input[type=week]:focus,.shortpixel-settings-tabs select:focus,.shortpixel-settings-tabs textarea:focus{border-color:#1fbec9;-webkit-box-shadow:0 0 2px 1px rgba(31,190,201,.15),inset 0 0 2px 1px rgba(31,190,201,.15);box-shadow:0 0 2px 1px rgba(31,190,201,.15),inset 0 0 2px 1px rgba(31,190,201,.15);outline:none;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs .exclusion-wrap{width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.shortpixel-settings-tabs .exclusion-wrap input{margin-right:10px}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content{position:relative;width:100%;padding:5px;margin-bottom:10px;min-height:100px;border:1px solid #ddd;border-radius:2px;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in;-webkit-box-sizing:border-box;box-sizing:border-box}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content *:not(.plus){z-index:1}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover{border:1px solid #aaa}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover .plus:before,.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover .plus:after{visibility:visible;opacity:1}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:before,.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:after{content:'';position:absolute;visibility:hidden;opacity:0;top:calc(50% - 1px);left:calc(50% - 10px);width:20px;height:2px;background:#ddd;-webkit-transition:opacity .15s ease-in;-o-transition:opacity .15s ease-in;transition:opacity .15s ease-in;z-index:0}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:after{top:calc(50% - 10px);left:calc(50% - 1px);width:2px;height:20px}.exclusion-wrap .exclusions-content>div[data-index]{position:relative;float:left;margin:2px;padding:5px 30px 5px 10px;background:#116c7d;color:#fff;border-radius:10px}.exclusion-wrap .exclusions-content span[data-action=delete]{cursor:pointer;position:absolute;top:calc(50% - 10px);right:5px;height:20px;width:20px;border-radius:50%;-moz-border-radius:50%;-webkit-border-radius:50%;background:#1fbec9}.exclusion-wrap .exclusions-content span[data-action=delete]:before,.exclusion-wrap .exclusions-content span[data-action=delete]:after{content:'';position:absolute;display:block;width:60%;height:2px;top:calc(50% - 1px);right:20%;background:#fff;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.exclusion-wrap .exclusions-content span[data-action=delete]:before{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:after{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:hover:before{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:hover:after{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.shortpixel-settings-tabs .exclusion-wrap textarea{display:none}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap select{min-width:90px;vertical-align:unset}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap button{min-width:100px;margin-right:0}.shortpixel-settings-tabs .exclusion-wrap[data-type=urls] .buttons-wrap input{width:calc(100% - 214px)}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap input{width:calc(100% - 111px)}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap .error-message{margin-bottom:10px}.support-and-preferences{display:block;margin:10px 0;font-size:16px}.support-and-preferences a{font-weight:400;margin-right:4px;font-size:18px;color:#176d84}.support-and-preferences a:last-child{margin-right:0}.spai_statusbox_wrap{border:1px solid #e5e5e5;width:350px;float:right;margin-left:20px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:43px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px}.spai_statusbox_wrap .title_wrap{background:#fff;position:relative;border-bottom:1px solid #e1e1e1;font-size:16px;padding:20px 60px 20px 20px}.spai_statusbox_wrap .title_wrap .usage_msg{padding:10px 10px 0 0;font-size:13px}.spai_statusbox_wrap .success{color:#1fbec9;font-weight:600}.spai_statusbox_wrap .error{color:#e53935;font-weight:600}.spai_statusbox_wrap .title_wrap:before{content:'';position:absolute;right:10px;top:calc(50% - 21px);width:42px;height:42px;background-size:contain;background-position:50%;background-repeat:no-repeat}.spai_statusbox_wrap .chart-wrap{position:relative;width:100%}.spai_statusbox_wrap .chart-wrap .toggle{content:'';cursor:pointer;position:absolute;top:0;right:0;width:20px;height:20px;background:url(../img/full-screen.svg)50%/80% no-repeat}.spai_statusbox_wrap .chart-wrap.expanded .toggle{top:20px;right:20px;background:url(../img/minimize.svg)50%/80% no-repeat}.spai_statusbox_wrap .chart-wrap.expanded{display:block;position:fixed;background:#fff;width:80%;max-width:1e3px;padding:20px;top:calc(50% - 250px);left:calc(10% - 20px);z-index:10000;border-radius:10px;-webkit-box-shadow:0 0 10px 3px rgba(0,0,0,.2);box-shadow:0 0 10px 3px rgba(0,0,0,.2)}.spai_statusbox_wrap .chart-wrap.expanded canvas#chart{max-height:500px}.spai_statusbox_wrap .box_content canvas#chart{display:block;height:1px;max-height:350px}.spai_statusbox_wrap .title_wrap[data-status=enough]:before{background-image:url(../img/robo-rtl-cool.png)}.spai_statusbox_wrap .title_wrap[data-status=few]:before{background-image:url(../img/robo-rtl-notes.png)}.spai_statusbox_wrap .title_wrap[data-status=insufficiently]:before{background-image:url(../img/robo-rtl-scared.png)}.spai_statusbox_wrap .box_content{padding:20px;background:#fff}.spai_statusbox_wrap .box_content .buttons-wrap{text-align:center}.spai_statusbox_wrap .login_btn{float:right;margin-top:-5px;margin-bottom:0}.btn_topup{color:#ed3833;float:right;margin-right:-40px;font-weight:700}.spai_statusbox_wrap img{max-width:100%}.spai_statusbox_wrap .full_width{width:calc(100% - 40px);text-align:center;margin:20px 0 0}.spai_statusbox_wrap .progress_wrap{margin-bottom:30px}.spai_statusbox_wrap .progress{height:5px;background:#1fbec9;position:relative;width:100%;clear:both}.spai_statusbox_wrap .progress_wrap .available{color:#1fbec9;float:right}.spai_statusbox_wrap .used{color:#ccc}.spai_statusbox_wrap .progress .used{height:5px;top:0;left:0;background:#ccc;position:absolute}.spai_statusbox_wrap .box_content .box_dropdown.first{margin:30px -20px -20px}.spai_statusbox_wrap .dismissed-notice-wrap{position:relative;border:1px dotted #116c7d;padding:10px;margin-bottom:10px}.spai_statusbox_wrap .dismissed-notice-wrap h4{padding-right:0;margin:5px 0;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in}.spai_statusbox_wrap .dismissed-notice-wrap:hover h4{padding-right:100px}.spai_statusbox_wrap .dismissed-notice-wrap:hover:before{visibility:visible;opacity:1;top:0}.spai_statusbox_wrap .dismissed-notice-wrap:before{content:attr(data-key);position:absolute;visibility:hidden;opacity:0;top:-10px;right:0;padding:5px;max-width:100px;color:#909090;background:#eee;text-align:center;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in}.spai_statusbox_wrap .dismissed-notice-wrap span{font-weight:600;color:crimson}.spai_statusbox_wrap .dismissed-notice-wrap .spai-modal span{color:#000}.shortpixel-offer-wso{width:100%;background-color:#dcfdff;display:flex;align-items:center;border:1px solid #ccc;margin-top:35px;margin-bottom:45px;position:relative}.shortpixel-offer-wso .red{color:red}.shortpixel-offer-wso span{text-align:center}.shortpixel-offer-wso .image{flex:1}.shortpixel-offer-wso .image img{width:45px;height:45px}.shortpixel-offer-wso .line{flex:3;padding:0 20px}.shortpixel-offer-wso .line h3{color:#00d0e5}.shortpixel-offer-wso .button-wrap{flex:2}.shortpixel-offer-wso .button-wrap .banner-button{background:red;padding:8px;font-weight:700;font-size:20px;margin:8px;color:#fff;text-transform:uppercase;height:auto;display:inline-block;text-decoration:none;white-space:nowrap;box-sizing:border-box;line-height:2.15384615;min-height:30px}.shortpixel-offer-wso .button-wrapper a{background-color:red;color:#fff;display:inline-block;padding:8px;text-decoration:none;font-weight:700;font-size:20px}.spai_statusbox_wrap .img-wrapper img{max-width:140px;max-height:140px}.box_dropdown{border-top:1px solid #e5e5e5;margin:20px -20px -20px}.box_dropdown .title{font-weight:600;font-size:16px;position:relative;padding:20px;cursor:pointer}.box_dropdown .title:before{content:"\f140";display:inline-block;font:20px/1 dashicons;position:absolute;right:15px}.box_dropdown.opened .title:before{content:"\f142"}.box_dropdown .dropdown_content{display:none;padding:10px 20px}.box_dropdown.opened .dropdown_content{display:block}.box_dropdown.spai_news .dropdown_content.loading{background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50% 0;min-height:200px}.shortpixel-settings-tabs input[type=submit]{padding:0 40px}.notification_popup{position:relative;background:rgba(0,0,0,2%);padding:15px 20px 20px;margin:20px 0 0;border:1px solid #1fbec9;border-radius:3px;-webkit-box-shadow:1px 1px 1px 0 rgba(31,190,201,.2);box-shadow:1px 1px 1px rgba(31,190,201,.2)}.notification_popup:before{background:#fafafa;border-left:1px solid #1fbec9;border-bottom:1px solid #1fbec9;width:14px;height:14px;display:block;position:absolute;top:-8px;left:22px;-webkit-transform:rotate(135deg);-ms-transform:rotate(135deg);transform:rotate(135deg);content:''}.notification_popup .text{margin:0 0 10px}.spai-modal .spai-modal-body{height:auto;min-height:400px;padding:0}.spai-modal.local{background-image:none}.spai-modal.local .spai-modal-body{min-height:auto}.deactivation-popup[data-type=wrapper],.deactivation-popup[data-type=wrapper] *{-webkit-box-sizing:border-box!important;box-sizing:border-box!important;-webkit-transition:all .2s ease-in-out!important;-o-transition:all .2s ease-in-out!important;transition:all .2s ease-in-out!important}.deactivation-popup[data-type=wrapper]{position:fixed;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;opacity:1;visibility:visible;width:100%;height:100%;top:0;left:0;background:rgba(0,0,0,.8);z-index:100000}.deactivation-popup[data-type=wrapper].hidden{opacity:0;visibility:hidden}.deactivation-popup[data-type=wrapper] .overlay{position:relative;padding:20px;background:#fff;overflow:auto;max-height:90%;max-width:90%;border-radius:10px;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.deactivation-popup[data-type=wrapper] .overlay::-webkit-scrollbar{width:6px}.deactivation-popup[data-type=wrapper] .overlay::-webkit-scrollbar-thumb{border-radius:3px;background:#00c0ce}.deactivation-popup[data-type=wrapper] .body{position:relative;display:block;max-width:360px;background:#fff;border-radius:10px}.deactivation-popup[data-type=wrapper].hidden .overlay{-webkit-transform:translateY(-20px);-ms-transform:translateY(-20px);transform:translateY(-20px)}.deactivation-popup[data-type=wrapper] .overlay .close{cursor:pointer;position:absolute;top:6px;right:6px;width:30px;height:30px;background:rgba(0,192,206,.3);border-radius:10px;z-index:1}.deactivation-popup[data-type=wrapper] .overlay .close:hover{-webkit-box-shadow:inset 1px 2px 3px rgba(14,77,88,.3);box-shadow:inset 1px 2px 3px rgba(14,77,88,.3)}.deactivation-popup[data-type=wrapper] .overlay .close:before{content:'';display:block;width:100%;height:100%;background:url(../img/close.svg)50%/40% no-repeat}.deactivation-popup[data-type=wrapper] .body .title-wrap{position:relative;display:block;font-size:18px;font-weight:600;text-align:center;padding:23px 20px 23px 70px}.deactivation-popup[data-type=wrapper] .body .title-wrap:before{content:'';position:absolute;top:0;left:0;display:block;width:64px;height:64px;background:url(../img/robo-happy.png)50%/contain no-repeat}.deactivation-popup[data-type=wrapper] .body button{float:right;margin:0}.deactivation-popup[data-type=wrapper] .body section{margin-bottom:15px}.deactivation-popup[data-type=wrapper] .body section:last-child{margin-bottom:0}.deactivation-popup[data-type=wrapper] .messages-wrap p{margin:5px 0}.deactivation-popup[data-type=wrapper] .body .options-wrap{padding:10px;border-radius:10px;background:#f3f3f3}.deactivation-popup[data-type=wrapper] .body .options-wrap *:not([type=radio]):not([type=checkbox]){width:100%}.deactivation-popup[data-type=wrapper] .body .options-wrap textarea{max-height:150px;min-height:50px}.deactivation-popup[data-type=wrapper] .options-wrap label{display:block;margin-bottom:5px}.deactivation-popup[data-type=wrapper] .options-wrap label:last-child{margin-bottom:0}.deactivation-popup[data-type=wrapper] .scroll-down{cursor:pointer;display:block;position:absolute;bottom:30px;left:calc(50% - 20px);width:40px;height:50px;background:rgba(178,236,240,.8);z-index:1;border-radius:10px;opacity:1;visibility:visible;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);-webkit-transition:all .4s ease-in-out!important;-o-transition:all .4s ease-in-out!important;transition:all .4s ease-in-out!important;-webkit-animation:1.3s knock-bottom-small 3s ease-in-out;animation:1.3s knock-bottom-small 3s ease-in-out}.deactivation-popup[data-type=wrapper] .scroll-down.hidden{opacity:0;visibility:hidden;-webkit-transform:translateY(-20px);-ms-transform:translateY(-20px);transform:translateY(-20px);-webkit-animation:unset;animation:unset}.deactivation-popup[data-type=wrapper] .scroll-down .mouse{position:absolute;width:26px;height:40px;top:calc(50% - 20px);left:calc(50% - 13px);border-radius:12px;border:2px solid #007cba}.deactivation-popup[data-type=wrapper] .scroll-down .wheel{position:absolute;top:5px;left:calc(50% - 5px);height:10px;width:10px;background:url(../img/down-arrow.svg)50%/contain no-repeat;border-radius:3px;-webkit-animation:wheel-scroll 2.2s infinite;animation:wheel-scroll 2.2s infinite}@-webkit-keyframes wheel-scroll{0%{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}20%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}40%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(18px);transform:translateY(18px)}}@keyframes wheel-scroll{0%{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}20%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}40%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(18px);transform:translateY(18px)}}div.shortpixel-settings-wrap .tgl{display:none}.tgl::-moz-selection,.tgl:after::-moz-selection,.tgl:before::-moz-selection,.tgl *::-moz-selection,.tgl *:after::-moz-selection,.tgl *:before::-moz-selection,.tgl+.tgl-btn::-moz-selection{background:0 0}.tgl::selection,.tgl:after::selection,.tgl:before::selection,.tgl *::selection,.tgl *:after::selection,.tgl *:before::selection,.tgl+.tgl-btn::selection{background:0 0}.tgl+.tgl-btn{line-height:28px}.tgl+.tgl-btn span{outline:0;display:block;width:35px;height:6px;position:relative;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin:10px 10px 0 0}.tgl+.tgl-btn span:after,.tgl+.tgl-btn span:before{position:relative;display:block;content:"";width:18px;height:18px}.tgl+.tgl-btn span:after{left:-3px}.tgl+.tgl-btn span:before{display:none}.tgl:checked+.tgl-btn span:after{left:calc(100% - 15px)}.tgl+.tgl-btn span{background:#e2e2e2;border-radius:14px;padding:2px;-webkit-transition:all .4s ease;-o-transition:all .4s ease;transition:all .4s ease;float:left;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.25);box-shadow:inset 0 1px 1px rgba(0,0,0,.25)}.tgl+.tgl-btn span:after{border-radius:14px;background:#ccc;-webkit-transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;-o-transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.31);box-shadow:0 1px 2px rgba(0,0,0,.31);top:-6px}.tgl:hover+.tgl-btn span:after{background:#bbb}.tgl+.tgl-btn span:hover:after{will-change:padding}.tgl+.tgl-btn span:active{-webkit-box-shadow:inset 0 0 0 2em #e8eae9;box-shadow:inset 0 0 0 2em #e8eae9}.tgl+.tgl-btn span:active:after{padding-right:.8em}.tgl:checked+.tgl-btn span{background:#92d4e2;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.25);box-shadow:inset 0 1px 1px rgba(0,0,0,.25)}.tgl:checked+.tgl-btn span:after{background:#1fbec9}.tgl:checked:hover+.tgl-btn span:after{background:#0fa9b4}.spai_top_actions .tgl:checked+.tgl-btn span:after{background:#72edf5}.tgl:checked+.tgl-btn span:active{-webkit-box-shadow:none;box-shadow:none}.tgl:checked+.tgl-btn span:active:after{margin-left:-.8em}.tgl:disabled+.tgl-btn span{background:#aaa}.tgl:disabled+.tgl-btn span:after{background:#909090}.tgl:checked:disabled+.tgl-btn span{background:#80bbc7}.tgl:checked:disabled+.tgl-btn span:after{background:#1a9ca5}.clearfix:after{content:''!important;display:block!important;clear:both!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu>.ab-item:before{content:' ';width:25px;height:25px;background-size:contain;background-repeat:no-repeat;background-position:0;background-image:url(../img/robo.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .ab-item{display:inline-block}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .ab-item:before{content:' ';width:25px;height:25px;background-size:contain;background-repeat:no-repeat;background-position:0;background-image:url(../img/robo.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache .ab-item:before{background-image:url(../img/clearcss.svg)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache .ab-item:before{background-image:url(../img/update.svg)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache .ab-item:before{background-image:url(../img/robo-blurry.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_processing .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_processing .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_processing .ab-item:before{background-image:url(../img/spinner2.gif)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_success .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_success .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_success .ab-item:before{background-image:none!important;content:'\2713';display:inline-block;color:green;width:25px;font-size:20px;padding:0 -6px 0 6px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_error .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_error .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_error .ab-item:before{background-image:none!important;content:'\203C';display:inline-block;color:red;padding:0 -6px 0 6px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .shortpixel-ai-sniper .ab-item:before{background-image:url(../img/robo-sniper.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai-settings .ab-item:before{background-image:none!important;font-family:dashicons;content:"\f108";color:#93d7e5;width:25px;font-size:25px}@media(max-width:1400px){.spai_statusbox_wrap{}.shortpixel-settings-tabs{width:calc(100% - 370px)}}@media(min-width:1200px){.spai_statusbox_wrap .chart-wrap.expanded{left:calc(50% - 520px)}}@media(max-width:1200px){.spai_settings_tab th,.spai_settings_tab td{display:block}.spai_settings_tab th{padding:20px 0 10px}.spai_settings_tab td{padding:5px 0}}@media(max-width:850px){.spai_statusbox_wrap{width:100%;margin-left:0}.spai_statusbox_wrap .chart-wrap .toggle{display:none}.shortpixel-settings-tabs{width:100%}.spai_statusbox_wrap .title_wrap:after{content:'';display:block;position:absolute;opacity:1;visibility:visible;width:12px;height:12px;bottom:6px;left:calc(50% - 6px);background:url(../img/expand-button.svg)50%/contain no-repeat;-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.spai_statusbox_wrap.expanded .title_wrap:after{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.spai_statusbox_wrap .box_content{display:none}.spai_statusbox_wrap .box_content.opened{position:relative;max-height:1e3px}}@media screen and (min-width:783px){#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{left:0;padding:0;width:24px;height:100%}}@media screen and (max-width:782px){#wpadminbar li#wp-admin-bar-shortpixel-ai-on-boarding{display:block;position:static}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{background-size:70%}#export_settings,#import_settings_form{display:none}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap select{margin-bottom:10px}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap input{width:100%;display:inline-block;margin-right:0;margin-bottom:10px}.shortpixel-settings-tabs .exclusion-wrap[data-type=urls] .buttons-wrap input{width:calc(100% - 10px)}.deactivation-popup[data-type=wrapper] .options-wrap label{margin-bottom:10px}}@media(min-width:851px) and (max-width:1268px){.spai_top_actions{margin:10px 10px 0 0}.spai_settings_tab{border-top:1px solid #e5e5e5}.nav-tab{border-bottom:1px solid #c3c4c7}.shortpixel-settings-tabs .nav-tab-active{border-bottom:1px solid #ccc}.shortpixel-settings-tabs .nav-tab-wrapper{padding-bottom:10px!important}}@media(max-width:600px){.spai_top_actions{margin:10px 10px 0 0}.spai_settings_tab{border-top:1px solid #e5e5e5}.shortpixel-settings-tabs .nav-tab-active{border-bottom:1px solid #ccc}.shortpixel-settings-tabs .nav-tab-wrapper{padding-bottom:10px!important}.socials-block .message-wrap{padding:0;margin-bottom:10px;text-align:center}.socials-block .buttons-wrap{position:unset;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;margin:0 auto}}@media(max-width:450px){.sp-obw__content-wrap .step-message-wrap .dark_blue_link,.sp-obw__content-wrap .step-message-wrap .blue_link,.sp-obw__content-wrap .step-message-wrap .bordered_link,.sp-obw__content-wrap .step-message-wrap .action-wrap input,.sp-obw__content-wrap .step-message-wrap .action-wrap [data-action]{width:100%;display:block;text-align:center;margin:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:inherit;font-size:inherit;font-weight:inherit}.shortpixel-on-boarding-wrap .socials-block{margin-top:30px}}@media(max-width:400px){.shortpixel_radio_btns{width:100%;display:table}.shortpixel_radio_btns label{display:table-cell;text-align:center;padding:0 5px}}@media(-webkit-min-device-pixel-ratio:2),(-o-min-device-pixel-ratio:2/1),(min-resolution:192dpi){#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item:before{background-image:url(../img/robo-happy@2x.png)!important}.spai_statusbox_wrap .title_wrap[data-status=enough]:before{background-image:url(../img/robo-rtl-cool@2x.png)}.spai_statusbox_wrap .title_wrap[data-status=few]:before{background-image:url(../img/robo-rtl-notes@2x.png)}.spai_statusbox_wrap .title_wrap[data-status=insufficiently]:before{background-image:url(../img/robo-rtl-scared@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=scared] .body-wrap:before{background-image:url(../img/robo-scared@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=happy] .body-wrap:before{background-image:url(../img/robo-happy@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=wink] .body-wrap:before{background-image:url(../img/robo-wink@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=cool] .body-wrap:before{background-image:url(../img/robo-cool@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=magnifier] .body-wrap:before{background-image:url(../img/robo-magnifier@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=notes] .body-wrap:before{background-image:url(../img/robo-notes@2x.png)}.deactivation-popup[data-type=wrapper] .body .title-wrap:before{background-image:url(../img/robo-happy@2x.png)}.shortpixel-ai-beacon:before{background-image:url(../img/notes@2x.png)}}@-webkit-keyframes knock-right-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateX(5px);transform:translateX(5px)}50%{-webkit-transform:translateX(3px);transform:translateX(3px)}65%{-webkit-transform:translateX(5px);transform:translateX(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes knock-right-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateX(5px);transform:translateX(5px)}50%{-webkit-transform:translateX(3px);transform:translateX(3px)}65%{-webkit-transform:translateX(5px);transform:translateX(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes knock-bottom-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateY(5px);transform:translateY(5px)}50%{-webkit-transform:translateY(3px);transform:translateY(3px)}65%{-webkit-transform:translateY(5px);transform:translateY(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes knock-bottom-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateY(5px);transform:translateY(5px)}50%{-webkit-transform:translateY(3px);transform:translateY(3px)}65%{-webkit-transform:translateY(5px);transform:translateY(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}
     1.shortpixel-settings-wrap input,.shortpixel-settings-wrap textarea,.shortpixel-settings-wrap button{outline:unset!important}.plugins tr[data-slug=shortpixel-adaptive-images] td div p span{display:block;margin:5px 0;padding-left:25px}.shortpixel-on-boarding-wrap{background:#fff}.shortpixel-on-boarding-wrap .socials-block{width:100%;max-width:1e3px;margin-top:10px}.socials-block,.socials-block *{-webkit-box-sizing:border-box;box-sizing:border-box}.socials-block{position:relative;padding:20px;border-radius:15px;font-weight:600;margin-bottom:10px;background:#dfffff}.socials-block>.message-wrap{width:100%;color:#05869f;padding-right:200px}.socials-block:before{content:'';position:absolute;display:block;width:20px;height:20px;top:-8px;left:20px;background:url(../img/socials/share.svg)50%/contain no-repeat}.socials-block>.buttons-wrap{position:absolute;display:block;top:calc(50% - 20px);right:20px}.socials-block [data-social]:before{content:'';position:absolute;width:16px;height:16px;top:calc(50% - 8px);left:7px}.socials-block [data-social]:last-child{margin-right:0}.socials-block [data-social]{position:relative;display:block;float:left;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;line-height:20px;margin-right:5px;border-radius:10px;padding:10px 10px 10px 30px;text-decoration:unset;outline:none;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.socials-block [data-social=twitter]{background:#d9e9f9;color:#2c76ec}.socials-block [data-social=twitter]:hover{-webkit-box-shadow:inset 1px 2px 2px rgba(44,118,236,.2);box-shadow:inset 1px 2px 2px rgba(44,118,236,.2)}.socials-block [data-social=twitter]:before{background:url(../img/socials/twitter.svg)50%/contain no-repeat}.socials-block [data-social=facebook]{background:#d9e6ff;color:#2152b3}.socials-block [data-social=facebook]:hover{-webkit-box-shadow:inset 1px 2px 2px rgba(33,82,179,.2);box-shadow:inset 1px 2px 2px rgba(33,82,179,.2)}.socials-block [data-social=facebook]:before{background:url(../img/socials/facebook.svg)50%/contain no-repeat}.sp-obw__title-wrap img{height:64px;width:64px;float:left;margin:10px 20px 10px 10px}.sp-obw__title-wrap{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.sp-obw__title-wrap:after{position:absolute;bottom:0;left:0;clear:both;width:100%;height:1px;background:#ccc;content:'';display:block}.sp-obw__content-wrap{padding:20px}.sp-obw__content-wrap p{font-size:14px}.sp-obw__content-wrap span.sp-obw-step{line-height:36px}.sp-obw__content-wrap span.sp-obw-alert{font-weight:600;color:crimson}.sp-obw__content-wrap .step-message-wrap label{vertical-align:top;margin-right:10px}.sp-obw__content-wrap .step-message-wrap p button{margin:0 10px 0 0}.sp-obw__content-wrap .step-message-wrap p button:last-child{margin:0}.sp-obw__content-wrap .step-message-wrap button:disabled{color:#a0a5aa!important;border-color:#ddd!important;background:#f7f7f7!important;-webkit-box-shadow:0 1px 1px rgba(171,170,170,.3)!important;box-shadow:0 1px 1px rgba(171,170,170,.3)!important}.bordered_link{cursor:pointer;color:#1fbec9;font-size:14px;line-height:18px;padding:5px 10px;display:inline-block;background:#f5f5f5!important;border:1px solid #1fbec9!important;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:0 1px 1px rgba(171,170,170,.3);box-shadow:0 1px 1px rgba(171,170,170,.3);border-radius:3px;text-decoration:none;margin-bottom:15px;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear}.bordered_link:hover{color:#0f6b7e!important;background:0 0!important}.shortpixel-steps{max-width:670px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding-bottom:24px;margin:30px 0;position:relative}.shortpixel-steps:before{position:absolute;content:'';height:2px;background:#ccc;width:100%;left:0;top:18px;z-index:1}.shortpixel-steps:after{position:absolute;content:'';height:2px;background:#ec2c25;width:100%;left:0;top:18px;z-index:2;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear}.shortpixel-steps[data-step="0"]:after{width:39px}.shortpixel-steps[data-step="1"]:after{width:calc(((100% - 58px)/3) + 39px)}.shortpixel-steps[data-step="2"]:after{width:calc(((100% - 58px) * 2/3) + 39px)}.shortpixel-steps[data-step="3"]:after{width:100%}.shortpixel-steps .step:nth-child(1){padding-left:20px}.shortpixel-steps .step .number{position:relative;font-weight:700;font-size:20px;color:#ccc;line-height:32px;height:34px;width:34px;text-align:center;border:2px solid #ccc;border-radius:50%;background:#fff;z-index:3}.shortpixel-steps .step.active .number,.shortpixel-steps .step.passed .number{color:#1fbec9;border:2px solid #ec2c25}.shortpixel-steps .step .title{position:absolute;color:#555d66;width:80px;text-align:center;opacity:.4;text-transform:uppercase;left:-24px;font-size:14px;bottom:-30px}.shortpixel-steps .step.active .number .title{opacity:1}.sp-obw__content-wrap .step-message-wrap .action-wrap [data-action]{margin-left:5px}div.spai-modal-shade{display:none;position:fixed;z-index:10;left:0;top:0;width:100%;height:100%;overflow:auto;background:#000;opacity:.4}div.spai-modal{background-color:#fefefe;padding:20px;border:1px solid #888;width:30%;min-width:300px;z-index:100001;position:fixed;top:10%;left:50%;max-height:90%;overflow-y:auto}div.spai-modal-title{font-size:22px}div.spai-modal-body{margin-top:10px}div.spai-modal button.spai-close-upgrade-button{float:right;margin-top:0;background:0 0!important;border:none;font-size:22px;line-height:10px;cursor:pointer}.dark_blue_link{cursor:pointer;color:#fff;height:30px;line-height:30px;padding:0 20px;background:#116c7d!important;display:inline-block;-webkit-box-shadow:0 1px 1px #09343d!important;box-shadow:0 1px 1px #09343d!important;border:none!important;border-radius:3px;text-decoration:none;margin-right:10px;position:relative;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;margin-bottom:15px;border:0;outline:none}.blue_link,.survey-rating-btn,#survey-feedback-submit{cursor:pointer;color:#fff!important;height:30px;line-height:30px;padding:0 20px;background:#1fbec9!important;display:inline-block;-webkit-box-shadow:0 1px 1px #16858c;box-shadow:0 1px 1px #16858c;border-radius:3px;text-decoration:none;margin-right:10px;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;margin-bottom:15px;border:0!important;outline:none}.dark_blue_link:hover,.blue_link:hover,.survey-rating-btn:hover,#survey-feedback-submit{color:#fff!important;border:none!important;opacity:.7!important}.dark_blue_link:focus,.blue_link:focus,.dark_blue_link:active,.blue_link:active{color:#fff}.blue_link:disabled,.blue_link:disabled:hover,.dark_blue_link:disabled,.dark_blue_link:disabled:hover{cursor:not-allowed!important;opacity:1!important;color:#737373!important;background:#e2e2e2!important;-webkit-box-shadow:0 1px 1px #8a8a8a!important;box-shadow:0 1px 1px #8a8a8a!important}.bordered_link:disabled,.bordered_link:disabled:hover{cursor:not-allowed!important;opacity:1!important;color:#969696!important;background:#efefef!important;border-color:#ccc!important}.next_icon{padding-right:35px;position:relative}.next_icon:after{content:'';width:9px;height:11px;position:absolute;right:15px;top:10px;background:url(../img/next.svg)50%/cover no-repeat;-webkit-transition:all .2s linear;-o-transition:all .2s linear;transition:all .2s linear}.fast-forward_link{padding-right:40px;position:relative}.fast-forward_link:after{content:'';width:14px;height:13px;position:absolute;right:15px;top:9px;background:url(../img/fast-forward.svg)50%/contain no-repeat;-webkit-transition:all .2s linear;-o-transition:all .2s linear;transition:all .2s linear}.next_icon:hover:after,.fast-forward_link:hover:after{right:10px}@media(max-width:400px){.shortpixel-steps .step .title{text-transform:none}}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{background-position:50%;background-size:contain;background-repeat:no-repeat;background-image:url(../img/robo-happy.png)!important}.notice[data-plugin=short-pixel-ai]{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px}.notice[data-plugin=short-pixel-ai] .body-wrap{position:relative;padding-left:75px}.notice[data-plugin=short-pixel-ai] .body-wrap .message-wrap span{font-weight:600;color:crimson}.notice[data-plugin=short-pixel-ai][data-icon=none] .body-wrap{padding-left:0}.notice[data-plugin=short-pixel-ai][data-icon] .body-wrap:before{content:'';position:absolute;left:0;width:64px;height:100%;background-position:50%;background-size:contain;background-repeat:no-repeat}.notice[data-plugin=short-pixel-ai][data-icon=none] .body-wrap:before{content:none;position:unset;left:0;width:0;height:0;background:0 0}.notice[data-plugin=short-pixel-ai][data-icon=scared] .body-wrap:before{background-image:url(../img/robo-scared.png)}.notice[data-plugin=short-pixel-ai][data-icon=happy] .body-wrap:before{background-image:url(../img/robo-happy.png)}.notice[data-plugin=short-pixel-ai][data-icon=wink] .body-wrap:before{background-image:url(../img/robo-wink.png)}.notice[data-plugin=short-pixel-ai][data-icon=cool] .body-wrap:before{background-image:url(../img/robo-cool.png)}.notice[data-plugin=short-pixel-ai][data-icon=magnifier] .body-wrap:before{background-image:url(../img/robo-magnifier.png)}.notice[data-plugin=short-pixel-ai][data-icon=notes] .body-wrap:before{background-image:url(../img/robo-notes.png)}.notice[data-plugin=short-pixel-ai] .buttons-wrap{margin:10px 0}.notice[data-plugin=short-pixel-ai] .buttons-wrap .button{margin-right:5px}.dismissed-notice[data-plugin=short-pixel-ai] .buttons-wrap .button{margin:0 5px 5px 0}.notice[data-plugin=short-pixel-ai] .buttons-wrap .button:last-child{margin-right:0}div.spai-inline-help{float:right}div.spai-inline-help span{font-size:1.8em;color:#0bb5c1;cursor:pointer}div.spai-modal{background-color:#fefefe;padding:20px 16px 16px;border:1px solid #888;width:30%;max-width:610px;margin-left:-305px;min-width:300px;z-index:100;position:fixed;top:10%;left:50%;max-height:90%;overflow-y:auto}div.spai-modal-spinner{background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50%}.spai-loading{width:100%;min-height:200px;background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50% 0}@media(max-width:610px){div.spai-modal{width:100%;margin-left:-50%;padding:20px 0 16px}}div.spai-modal .spai-close-help-button{position:absolute;top:5px;right:0;margin-top:0;background:0 0;border:none;font-size:22px;line-height:10px;cursor:pointer}div.spai-modal-title{font-size:22px}.spai-hide{display:none}.spai_settings_tab{display:none;background:#fff;border-right:1px solid #e5e5e5;border-left:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;padding:30px 20px}.spai_settings_tab.active{display:block}.shortpixel-settings-tabs{width:calc(100% - 370px);float:left}.shortpixel-settings-tabs .nav-tab-wrapper{position:relative}.shortpixel-settings-tabs .nav-tab:focus{-webkit-box-shadow:none;box-shadow:none;outline:none}.shortpixel-settings-tabs .nav-tab-active{background:#fff;border-bottom:1px solid #fff}.shortpixel-settings-tabs .form-table td label{display:inline-block}.children-wrap{display:block;visibility:visible;opacity:1;max-height:1e4px;margin:5px 0 5px 40px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.children-wrap.hidden{visibility:hidden;opacity:0;max-height:0}.children-wrap.hidden label{display:none}.children-wrap .shortpixel_radio_btns{margin-bottom:0}.children-wrap .bordered_link{margin-bottom:0}.spai_top_actions{cursor:pointer;float:right;border:1px solid #1fbec9;border-bottom:none;margin-left:.5em;padding:5px 10px;font-size:14px;line-height:1.71428571;font-weight:600;background:#1fbec9;color:#fff;text-decoration:none;white-space:nowrap;outline:none}.spai_top_actions:hover{background:#0fa9b4}.clearcss-icon{background:url(../img/clearcss-white.svg)no-repeat;background-size:auto;display:inline-block;height:20px;width:24px;margin-top:4px}#clear_css_cache{margin-bottom:0;padding:2px 5px;height:35px}.shortpixel_radio_btns input{display:none}.shortpixel_radio_btns{-webkit-box-shadow:0 1px 1px #b6b2b2;box-shadow:0 1px 1px #b6b2b2;border-radius:3px;height:32px;display:inline-block;overflow:hidden;font-size:0;vertical-align:middle;margin-right:0;margin-bottom:20px}.shortpixel_radio_btns label{background:#ccc;text-transform:uppercase;display:inline-block;color:#fff;line-height:32px;padding:0 29px;border-left:1px solid #b4b4b4;border-right:1px solid #b4b4b4;font-size:14px;font-weight:700;margin:0 -1px;-webkit-transition:all .2s ease-in;-o-transition:all .2s ease-in;transition:all .2s ease-in}.shortpixel_radio_btns input:checked+label{background:#1fbec9;-webkit-box-shadow:0 0 3px #2a6c78;box-shadow:0 0 3px #2a6c78;border-left:1px solid #1fbec9;border-right:1px solid #1fbec9;position:relative}.shortpixel_radio_btns label:hover{background:#bbb}.shortpixel_radio_btns input:checked+label:hover{background:#0fa9b4}.shortpixel-settings-tabs input[type=text],.shortpixel-settings-tabs textarea{border:1px solid #ddd;border-radius:2px;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs input.error[type=text],.shortpixel-settings-tabs textarea.error,.shortpixel-settings-tabs input.error[type=text]:focus,.shortpixel-settings-tabs textarea.error:focus{border:1px solid crimson;-webkit-box-shadow:0 0 2px 1px rgba(220,20,60,.15),inset 0 0 2px 1px rgba(220,20,60,.15);box-shadow:0 0 2px 1px rgba(220,20,60,.15),inset 0 0 2px 1px rgba(220,20,60,.15)}.shortpixel-settings-tabs textarea{width:100%;max-width:100%;min-width:100%;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs input[type=checkbox]:focus,.shortpixel-settings-tabs input[type=color]:focus,.shortpixel-settings-tabs input[type=date]:focus,.shortpixel-settings-tabs input[type=datetime-local]:focus,.shortpixel-settings-tabs input[type=datetime]:focus,.shortpixel-settings-tabs input[type=email]:focus,.shortpixel-settings-tabs input[type=month]:focus,.shortpixel-settings-tabs input[type=number]:focus,.shortpixel-settings-tabs input[type=password]:focus,.shortpixel-settings-tabs input[type=radio]:focus,.shortpixel-settings-tabs input[type=search]:focus,.shortpixel-settings-tabs input[type=tel]:focus,.shortpixel-settings-tabs input[type=text]:focus,.shortpixel-settings-tabs input[type=time]:focus,.shortpixel-settings-tabs input[type=url]:focus,.shortpixel-settings-tabs input[type=week]:focus,.shortpixel-settings-tabs select:focus,.shortpixel-settings-tabs textarea:focus{border-color:#1fbec9;-webkit-box-shadow:0 0 2px 1px rgba(31,190,201,.15),inset 0 0 2px 1px rgba(31,190,201,.15);box-shadow:0 0 2px 1px rgba(31,190,201,.15),inset 0 0 2px 1px rgba(31,190,201,.15);outline:none;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs .exclusion-wrap{width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.shortpixel-settings-tabs .exclusion-wrap input{margin-right:10px}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content{position:relative;width:100%;padding:5px;margin-bottom:10px;min-height:100px;border:1px solid #ddd;border-radius:2px;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in;-webkit-box-sizing:border-box;box-sizing:border-box}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content *:not(.plus){z-index:1}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover{border:1px solid #aaa}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover .plus:before,.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover .plus:after{visibility:visible;opacity:1}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:before,.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:after{content:'';position:absolute;visibility:hidden;opacity:0;top:calc(50% - 1px);left:calc(50% - 10px);width:20px;height:2px;background:#ddd;-webkit-transition:opacity .15s ease-in;-o-transition:opacity .15s ease-in;transition:opacity .15s ease-in;z-index:0}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:after{top:calc(50% - 10px);left:calc(50% - 1px);width:2px;height:20px}.exclusion-wrap .exclusions-content>div[data-index]{position:relative;float:left;margin:2px;padding:5px 30px 5px 10px;background:#116c7d;color:#fff;border-radius:10px}.exclusion-wrap .exclusions-content span[data-action=delete]{cursor:pointer;position:absolute;top:calc(50% - 10px);right:5px;height:20px;width:20px;border-radius:50%;-moz-border-radius:50%;-webkit-border-radius:50%;background:#1fbec9}.exclusion-wrap .exclusions-content span[data-action=delete]:before,.exclusion-wrap .exclusions-content span[data-action=delete]:after{content:'';position:absolute;display:block;width:60%;height:2px;top:calc(50% - 1px);right:20%;background:#fff;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.exclusion-wrap .exclusions-content span[data-action=delete]:before{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:after{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:hover:before{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:hover:after{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.shortpixel-settings-tabs .exclusion-wrap textarea{display:none}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap select{min-width:90px;vertical-align:unset}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap button{min-width:100px;margin-right:0}.shortpixel-settings-tabs .exclusion-wrap[data-type=urls] .buttons-wrap input{width:calc(100% - 214px)}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap input{width:calc(100% - 111px)}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap .error-message{margin-bottom:10px}.support-and-preferences{display:block;margin:10px 0;font-size:16px}.support-and-preferences a{font-weight:400;margin-right:4px;font-size:18px;color:#176d84}.support-and-preferences a:last-child{margin-right:0}.spai_statusbox_wrap{border:1px solid #e5e5e5;width:350px;float:right;margin-left:20px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:43px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px}.spai_statusbox_wrap .title_wrap{background:#fff;position:relative;border-bottom:1px solid #e1e1e1;font-size:16px;padding:20px 60px 20px 20px}.spai_statusbox_wrap .title_wrap .usage_msg{padding:10px 10px 0 0;font-size:13px}.spai_statusbox_wrap .success{color:#1fbec9;font-weight:600}.spai_statusbox_wrap .error{color:#e53935;font-weight:600}.spai_statusbox_wrap .title_wrap:before{content:'';position:absolute;right:10px;top:calc(50% - 21px);width:42px;height:42px;background-size:contain;background-position:50%;background-repeat:no-repeat}.spai_statusbox_wrap .chart-wrap{position:relative;width:100%}.spai_statusbox_wrap .chart-wrap .toggle{content:'';cursor:pointer;position:absolute;top:0;right:0;width:20px;height:20px;background:url(../img/full-screen.svg)50%/80% no-repeat}.spai_statusbox_wrap .chart-wrap.expanded .toggle{top:20px;right:20px;background:url(../img/minimize.svg)50%/80% no-repeat}.spai_statusbox_wrap .chart-wrap.expanded{display:block;position:fixed;background:#fff;width:80%;max-width:1e3px;padding:20px;top:calc(50% - 250px);left:calc(10% - 20px);z-index:10000;border-radius:10px;-webkit-box-shadow:0 0 10px 3px rgba(0,0,0,.2);box-shadow:0 0 10px 3px rgba(0,0,0,.2)}.spai_statusbox_wrap .chart-wrap.expanded canvas#chart{max-height:500px}.spai_statusbox_wrap .box_content canvas#chart{display:block;height:1px;max-height:350px}.spai_statusbox_wrap .title_wrap[data-status=enough]:before{background-image:url(../img/robo-rtl-cool.png)}.spai_statusbox_wrap .title_wrap[data-status=few]:before{background-image:url(../img/robo-rtl-notes.png)}.spai_statusbox_wrap .title_wrap[data-status=insufficiently]:before{background-image:url(../img/robo-rtl-scared.png)}.spai_statusbox_wrap .box_content{padding:20px;background:#fff}.spai_statusbox_wrap .box_content .buttons-wrap{text-align:center}.spai_statusbox_wrap .login_btn{float:right;margin-top:-5px;margin-bottom:0}.btn_topup{color:#ed3833;float:right;margin-right:-40px;font-weight:700}.spai_statusbox_wrap img{max-width:100%}.spai_statusbox_wrap .full_width{width:calc(100% - 40px);text-align:center;margin:20px 0 0}.spai_statusbox_wrap .progress_wrap{margin-bottom:30px}.spai_statusbox_wrap .progress{height:5px;background:#1fbec9;position:relative;width:100%;clear:both}.spai_statusbox_wrap .progress_wrap .available{color:#1fbec9;float:right}.spai_statusbox_wrap .used{color:#ccc}.spai_statusbox_wrap .progress .used{height:5px;top:0;left:0;background:#ccc;position:absolute}.spai_statusbox_wrap .box_content .box_dropdown.first{margin:30px -20px -20px}.spai_statusbox_wrap .dismissed-notice-wrap{position:relative;border:1px dotted #116c7d;padding:10px;margin-bottom:10px}.spai_statusbox_wrap .dismissed-notice-wrap h4{padding-right:0;margin:5px 0;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in}.spai_statusbox_wrap .dismissed-notice-wrap:hover h4{padding-right:100px}.spai_statusbox_wrap .dismissed-notice-wrap:hover:before{visibility:visible;opacity:1;top:0}.spai_statusbox_wrap .dismissed-notice-wrap:before{content:attr(data-key);position:absolute;visibility:hidden;opacity:0;top:-10px;right:0;padding:5px;max-width:100px;color:#909090;background:#eee;text-align:center;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in}.spai_statusbox_wrap .dismissed-notice-wrap span{font-weight:600;color:crimson}.spai_statusbox_wrap .dismissed-notice-wrap .spai-modal span{color:#000}.shortpixel-offer-wso{width:100%;background-color:#dcfdff;display:flex;align-items:center;border:1px solid #ccc;margin-top:35px;margin-bottom:45px;position:relative}.shortpixel-offer-wso .red{color:red}.shortpixel-offer-wso span{text-align:center}.shortpixel-offer-wso .image{flex:1}.shortpixel-offer-wso .image img{width:45px;height:45px}.shortpixel-offer-wso .line{flex:3;padding:0 20px}.shortpixel-offer-wso .line h3{color:#00d0e5}.shortpixel-offer-wso .button-wrap{flex:2}.shortpixel-offer-wso .button-wrap .banner-button{background:red;padding:8px;font-weight:700;font-size:20px;margin:8px;color:#fff;text-transform:uppercase;height:auto;display:inline-block;text-decoration:none;white-space:nowrap;box-sizing:border-box;line-height:2.15384615;min-height:30px}.shortpixel-offer-wso .button-wrapper a{background-color:red;color:#fff;display:inline-block;padding:8px;text-decoration:none;font-weight:700;font-size:20px}.spai_statusbox_wrap .img-wrapper img{max-width:140px;max-height:140px}.box_dropdown{border-top:1px solid #e5e5e5;margin:20px -20px -20px}.box_dropdown .title{font-weight:600;font-size:16px;position:relative;padding:20px;cursor:pointer}.box_dropdown .title:before{content:"\f140";display:inline-block;font:20px/1 dashicons;position:absolute;right:15px}.box_dropdown.opened .title:before{content:"\f142"}.box_dropdown .dropdown_content{display:none;padding:10px 20px}.box_dropdown.opened .dropdown_content{display:block}.box_dropdown.spai_news .dropdown_content.loading{background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50% 0;min-height:200px}.shortpixel-settings-tabs input[type=submit]{padding:0 40px}.notification_popup{position:relative;background:rgba(0,0,0,2%);padding:15px 20px 20px;margin:20px 0 0;border:1px solid #1fbec9;border-radius:3px;-webkit-box-shadow:1px 1px 1px 0 rgba(31,190,201,.2);box-shadow:1px 1px 1px rgba(31,190,201,.2)}.notification_popup:before{background:#fafafa;border-left:1px solid #1fbec9;border-bottom:1px solid #1fbec9;width:14px;height:14px;display:block;position:absolute;top:-8px;left:22px;-webkit-transform:rotate(135deg);-ms-transform:rotate(135deg);transform:rotate(135deg);content:''}.notification_popup .text{margin:0 0 10px}.spai-modal .spai-modal-body{height:auto;min-height:400px;padding:0}.spai-modal.local{background-image:none}.spai-modal.local .spai-modal-body{min-height:auto}.deactivation-popup[data-type=wrapper],.deactivation-popup[data-type=wrapper] *{-webkit-box-sizing:border-box!important;box-sizing:border-box!important;-webkit-transition:all .2s ease-in-out!important;-o-transition:all .2s ease-in-out!important;transition:all .2s ease-in-out!important}.deactivation-popup[data-type=wrapper]{position:fixed;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;opacity:1;visibility:visible;width:100%;height:100%;top:0;left:0;background:rgba(0,0,0,.8);z-index:100000}.deactivation-popup[data-type=wrapper].hidden{opacity:0;visibility:hidden}.deactivation-popup[data-type=wrapper] .overlay{position:relative;padding:20px;background:#fff;overflow:auto;max-height:90%;max-width:90%;border-radius:10px;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.deactivation-popup[data-type=wrapper] .overlay::-webkit-scrollbar{width:6px}.deactivation-popup[data-type=wrapper] .overlay::-webkit-scrollbar-thumb{border-radius:3px;background:#00c0ce}.deactivation-popup[data-type=wrapper] .body{position:relative;display:block;max-width:360px;background:#fff;border-radius:10px}.deactivation-popup[data-type=wrapper].hidden .overlay{-webkit-transform:translateY(-20px);-ms-transform:translateY(-20px);transform:translateY(-20px)}.deactivation-popup[data-type=wrapper] .overlay .close{cursor:pointer;position:absolute;top:6px;right:6px;width:30px;height:30px;background:rgba(0,192,206,.3);border-radius:10px;z-index:1}.deactivation-popup[data-type=wrapper] .overlay .close:hover{-webkit-box-shadow:inset 1px 2px 3px rgba(14,77,88,.3);box-shadow:inset 1px 2px 3px rgba(14,77,88,.3)}.deactivation-popup[data-type=wrapper] .overlay .close:before{content:'';display:block;width:100%;height:100%;background:url(../img/close.svg)50%/40% no-repeat}.deactivation-popup[data-type=wrapper] .body .title-wrap{position:relative;display:block;font-size:18px;font-weight:600;text-align:center;padding:23px 20px 23px 70px}.deactivation-popup[data-type=wrapper] .body .title-wrap:before{content:'';position:absolute;top:0;left:0;display:block;width:64px;height:64px;background:url(../img/robo-happy.png)50%/contain no-repeat}.deactivation-popup[data-type=wrapper] .body button{float:right;margin:0}.deactivation-popup[data-type=wrapper] .body section{margin-bottom:15px}.deactivation-popup[data-type=wrapper] .body section:last-child{margin-bottom:0}.deactivation-popup[data-type=wrapper] .messages-wrap p{margin:5px 0}.deactivation-popup[data-type=wrapper] .body .options-wrap{padding:10px;border-radius:10px;background:#f3f3f3}.deactivation-popup[data-type=wrapper] .body .options-wrap *:not([type=radio]):not([type=checkbox]){width:100%}.deactivation-popup[data-type=wrapper] .body .options-wrap textarea{max-height:150px;min-height:50px}.deactivation-popup[data-type=wrapper] .options-wrap label{display:block;margin-bottom:5px}.deactivation-popup[data-type=wrapper] .options-wrap label:last-child{margin-bottom:0}.deactivation-popup[data-type=wrapper] .scroll-down{cursor:pointer;display:block;position:absolute;bottom:30px;left:calc(50% - 20px);width:40px;height:50px;background:rgba(178,236,240,.8);z-index:1;border-radius:10px;opacity:1;visibility:visible;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);-webkit-transition:all .4s ease-in-out!important;-o-transition:all .4s ease-in-out!important;transition:all .4s ease-in-out!important;-webkit-animation:1.3s knock-bottom-small 3s ease-in-out;animation:1.3s knock-bottom-small 3s ease-in-out}.deactivation-popup[data-type=wrapper] .scroll-down.hidden{opacity:0;visibility:hidden;-webkit-transform:translateY(-20px);-ms-transform:translateY(-20px);transform:translateY(-20px);-webkit-animation:unset;animation:unset}.deactivation-popup[data-type=wrapper] .scroll-down .mouse{position:absolute;width:26px;height:40px;top:calc(50% - 20px);left:calc(50% - 13px);border-radius:12px;border:2px solid #007cba}.deactivation-popup[data-type=wrapper] .scroll-down .wheel{position:absolute;top:5px;left:calc(50% - 5px);height:10px;width:10px;background:url(../img/down-arrow.svg)50%/contain no-repeat;border-radius:3px;-webkit-animation:wheel-scroll 2.2s infinite;animation:wheel-scroll 2.2s infinite}@-webkit-keyframes wheel-scroll{0%{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}20%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}40%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(18px);transform:translateY(18px)}}@keyframes wheel-scroll{0%{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}20%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}40%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(18px);transform:translateY(18px)}}div.shortpixel-settings-wrap .tgl{display:none}.tgl::-moz-selection,.tgl:after::-moz-selection,.tgl:before::-moz-selection,.tgl *::-moz-selection,.tgl *:after::-moz-selection,.tgl *:before::-moz-selection,.tgl+.tgl-btn::-moz-selection{background:0 0}.tgl::selection,.tgl:after::selection,.tgl:before::selection,.tgl *::selection,.tgl *:after::selection,.tgl *:before::selection,.tgl+.tgl-btn::selection{background:0 0}.tgl+.tgl-btn{line-height:28px}.tgl+.tgl-btn span{outline:0;display:block;width:35px;height:6px;position:relative;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin:10px 10px 0 0}.tgl+.tgl-btn span:after,.tgl+.tgl-btn span:before{position:relative;display:block;content:"";width:18px;height:18px}.tgl+.tgl-btn span:after{left:-3px}.tgl+.tgl-btn span:before{display:none}.tgl:checked+.tgl-btn span:after{left:calc(100% - 15px)}.tgl+.tgl-btn span{background:#e2e2e2;border-radius:14px;padding:2px;-webkit-transition:all .4s ease;-o-transition:all .4s ease;transition:all .4s ease;float:left;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.25);box-shadow:inset 0 1px 1px rgba(0,0,0,.25)}.tgl+.tgl-btn span:after{border-radius:14px;background:#ccc;-webkit-transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;-o-transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.31);box-shadow:0 1px 2px rgba(0,0,0,.31);top:-6px}.tgl:hover+.tgl-btn span:after{background:#bbb}.tgl+.tgl-btn span:hover:after{will-change:padding}.tgl+.tgl-btn span:active{-webkit-box-shadow:inset 0 0 0 2em #e8eae9;box-shadow:inset 0 0 0 2em #e8eae9}.tgl+.tgl-btn span:active:after{padding-right:.8em}.tgl:checked+.tgl-btn span{background:#92d4e2;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.25);box-shadow:inset 0 1px 1px rgba(0,0,0,.25)}.tgl:checked+.tgl-btn span:after{background:#1fbec9}.tgl:checked:hover+.tgl-btn span:after{background:#0fa9b4}.spai_top_actions .tgl:checked+.tgl-btn span:after{background:#72edf5}.tgl:checked+.tgl-btn span:active{-webkit-box-shadow:none;box-shadow:none}.tgl:checked+.tgl-btn span:active:after{margin-left:-.8em}.tgl:disabled+.tgl-btn span{background:#aaa}.tgl:disabled+.tgl-btn span:after{background:#909090}.tgl:checked:disabled+.tgl-btn span{background:#80bbc7}.tgl:checked:disabled+.tgl-btn span:after{background:#1a9ca5}.clearfix:after{content:''!important;display:block!important;clear:both!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu>.ab-item:before{content:' ';width:25px;height:25px;background-size:contain;background-repeat:no-repeat;background-position:0;background-image:url(../img/robo.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .ab-item{display:inline-block}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .ab-item:before{content:' ';width:25px;height:25px;background-size:contain;background-repeat:no-repeat;background-position:0;background-image:url(../img/robo.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache .ab-item:before{background-image:url(../img/clearcss.svg)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache .ab-item:before{background-image:url(../img/update.svg)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache .ab-item:before{background-image:url(../img/robo-blurry.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_processing .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_processing .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_processing .ab-item:before{background-image:url(../img/spinner2.gif)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_success .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_success .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_success .ab-item:before{background-image:none!important;content:'\2713';display:inline-block;color:green;width:25px;font-size:20px;padding:0 -6px 0 6px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_error .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_error .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_error .ab-item:before{background-image:none!important;content:'\203C';display:inline-block;color:red;padding:0 -6px 0 6px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .shortpixel-ai-sniper .ab-item:before{background-image:url(../img/robo-sniper.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai-settings .ab-item:before{background-image:none!important;font-family:dashicons;content:"\f108";color:#93d7e5;width:25px;font-size:25px}@media(max-width:1400px){.spai_statusbox_wrap{}.shortpixel-settings-tabs{width:calc(100% - 370px)}}@media(min-width:1200px){.spai_statusbox_wrap .chart-wrap.expanded{left:calc(50% - 520px)}}@media(max-width:1200px){.spai_settings_tab th,.spai_settings_tab td{display:block}.spai_settings_tab th{padding:20px 0 10px}.spai_settings_tab td{padding:5px 0}}@media(max-width:850px){.spai_statusbox_wrap{width:100%;margin-left:0}.spai_statusbox_wrap .chart-wrap .toggle{display:none}.shortpixel-settings-tabs{width:100%}.spai_statusbox_wrap .title_wrap:after{content:'';display:block;position:absolute;opacity:1;visibility:visible;width:12px;height:12px;bottom:6px;left:calc(50% - 6px);background:url(../img/expand-button.svg)50%/contain no-repeat;-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.spai_statusbox_wrap.expanded .title_wrap:after{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.spai_statusbox_wrap .box_content{display:none}.spai_statusbox_wrap .box_content.opened{position:relative;max-height:1e3px}}@media screen and (min-width:783px){#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{left:0;padding:0;width:24px;height:100%}}@media screen and (max-width:782px){#wpadminbar li#wp-admin-bar-shortpixel-ai-on-boarding{display:block;position:static}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{background-size:70%}#export_settings,#import_settings_form{display:none}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap select{margin-bottom:10px}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap input{width:100%;display:inline-block;margin-right:0;margin-bottom:10px}.shortpixel-settings-tabs .exclusion-wrap[data-type=urls] .buttons-wrap input{width:calc(100% - 10px)}.deactivation-popup[data-type=wrapper] .options-wrap label{margin-bottom:10px}}@media(min-width:851px) and (max-width:1268px){.spai_top_actions{margin:10px 10px 0 0}.spai_settings_tab{border-top:1px solid #e5e5e5}.nav-tab{border-bottom:1px solid #c3c4c7}.shortpixel-settings-tabs .nav-tab-active{border-bottom:1px solid #ccc}.shortpixel-settings-tabs .nav-tab-wrapper{padding-bottom:10px!important}}@media(max-width:600px){.spai_top_actions{margin:10px 10px 0 0}.spai_settings_tab{border-top:1px solid #e5e5e5}.shortpixel-settings-tabs .nav-tab-active{border-bottom:1px solid #ccc}.shortpixel-settings-tabs .nav-tab-wrapper{padding-bottom:10px!important}.socials-block .message-wrap{padding:0;margin-bottom:10px;text-align:center}.socials-block .buttons-wrap{position:unset;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;margin:0 auto}}@media(max-width:450px){.sp-obw__content-wrap .step-message-wrap .dark_blue_link,.sp-obw__content-wrap .step-message-wrap .blue_link,.sp-obw__content-wrap .step-message-wrap .bordered_link,.sp-obw__content-wrap .step-message-wrap .action-wrap input,.sp-obw__content-wrap .step-message-wrap .action-wrap [data-action]{width:100%;display:block;text-align:center;margin:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:inherit;font-size:inherit;font-weight:inherit}.shortpixel-on-boarding-wrap .socials-block{margin-top:30px}}@media(max-width:400px){.shortpixel_radio_btns{width:100%;display:table}.shortpixel_radio_btns label{display:table-cell;text-align:center;padding:0 5px}}@media(-webkit-min-device-pixel-ratio:2),(-o-min-device-pixel-ratio:2/1),(min-resolution:192dpi){#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item:before{background-image:url(../img/robo-happy@2x.png)!important}.spai_statusbox_wrap .title_wrap[data-status=enough]:before{background-image:url(../img/robo-rtl-cool@2x.png)}.spai_statusbox_wrap .title_wrap[data-status=few]:before{background-image:url(../img/robo-rtl-notes@2x.png)}.spai_statusbox_wrap .title_wrap[data-status=insufficiently]:before{background-image:url(../img/robo-rtl-scared@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=scared] .body-wrap:before{background-image:url(../img/robo-scared@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=happy] .body-wrap:before{background-image:url(../img/robo-happy@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=wink] .body-wrap:before{background-image:url(../img/robo-wink@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=cool] .body-wrap:before{background-image:url(../img/robo-cool@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=magnifier] .body-wrap:before{background-image:url(../img/robo-magnifier@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=notes] .body-wrap:before{background-image:url(../img/robo-notes@2x.png)}.deactivation-popup[data-type=wrapper] .body .title-wrap:before{background-image:url(../img/robo-happy@2x.png)}.shortpixel-ai-beacon:before{background-image:url(../img/notes@2x.png)}}@-webkit-keyframes knock-right-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateX(5px);transform:translateX(5px)}50%{-webkit-transform:translateX(3px);transform:translateX(3px)}65%{-webkit-transform:translateX(5px);transform:translateX(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes knock-right-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateX(5px);transform:translateX(5px)}50%{-webkit-transform:translateX(3px);transform:translateX(3px)}65%{-webkit-transform:translateX(5px);transform:translateX(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes knock-bottom-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateY(5px);transform:translateY(5px)}50%{-webkit-transform:translateY(3px);transform:translateY(3px)}65%{-webkit-transform:translateY(5px);transform:translateY(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes knock-bottom-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateY(5px);transform:translateY(5px)}50%{-webkit-transform:translateY(3px);transform:translateY(3px)}65%{-webkit-transform:translateY(5px);transform:translateY(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}
  • shortpixel-adaptive-images/tags/3.11.0/assets/js/notice.js

    r2900611 r3340495  
    9494            }
    9595        } );
     96        // feedback survey handler
     97        $document.on( 'click', '.notice[data-causer="recommend_survey"] .survey-rating-btn', function(e){
     98            e.preventDefault();
     99            var $btn    = $( this ),
     100                rating  = $btn.data('rating'),
     101                $notice = $btn.closest('.notice[data-causer="recommend_survey"]');
     102
     103            $notice.find('.survey-rating-btn').removeClass('selected');
     104            $btn.addClass('selected');
     105            // send (only) rating first
     106            $.post( ajaxurl, {
     107                action: 'shortpixel_ai_send_rating',
     108                data:   { rating: rating }
     109            });
     110            // for 9–10: show inline thank-you + review prompt for WP pagre
     111            if ( rating >= 9 ) {
     112                $notice.find('h3, .message-wrap > p').slideUp();
     113
     114                var promptHtml =
     115                    '<p>Thank you for your high rating! ' +
     116                    'If you have a moment, the ShortPixel team would be very happy ' +
     117                    'if you could leave a short review for our plugin.</p>';
     118
     119                var reviewLinkHtml =
     120                    '<p>' +
     121                    '<button id="survey-feedback-submit" class="button button-primary" '+
     122                    'onclick="window.open(\'https://wordpress.org/support/plugin/shortpixel-adaptive-images/reviews/?filter=5\', \'_blank\')">' +
     123                    'Leave a review' +
     124                    '</button>' +
     125                    '</p>';
     126
     127                $notice
     128                    .find('#survey-feedback-area')
     129                    .html( promptHtml + reviewLinkHtml )
     130                    .slideDown();
     131
     132                return;
     133            }
     134            // 1–8: close title + buttons & open feedback area
     135            $notice.find('h3').slideUp();
     136            $notice.find('.survey-rating-btn').closest('p').slideUp();
     137            var prompt = rating <= 4
     138                ? 'Thank you for your feedback! If you have encountered any issues with our plugin, we are more than eager to help solving them! Please give us more details:'
     139                : 'Thank you for your feedback! Please let us know what we can improve:';
     140
     141            $notice.find('#survey-feedback-prompt').text( prompt );
     142            $notice.find('#survey-feedback-area').slideDown();
     143        });
     144
     145        // now, when click on submit button send 2nd ajax with feedback
     146        $document.on( 'click', '.notice[data-causer="recommend_survey"] #survey-feedback-submit', function(e){
     147            e.preventDefault();
     148            var $notice      = $( this ).closest( '.notice[data-causer="recommend_survey"]'),
     149                rating       = $notice.find('.survey-rating-btn.selected').data('rating'),
     150                feedbackText = $notice.find('#survey-feedback').val() || '';
     151
     152            $.post( ajaxurl, {
     153                action: 'shortpixel_ai_send_feedback',
     154                data:   {
     155                    rating:   rating,
     156                    feedback: feedbackText
     157                }
     158            })
     159                .done(function( resp ){
     160                        var $msgWrap = $notice.find('.message-wrap');
     161                        if ( resp.success ) {
     162                            $msgWrap.html('<p>Thank you for your feedback!</p>');
     163                            $notice.find('#survey-feedback-area, .buttons-wrap').slideUp();
     164                        }
     165                        else {
     166                            var error = resp.data || 'Something went wrong sending feedback!';
     167                            $msgWrap.html('<p>' + error + '</p>');
     168                    }
     169                });
     170        });
     171
    96172    } );
    97173} )( jQuery, document, window );
  • shortpixel-adaptive-images/tags/3.11.0/assets/js/notice.min.js

    r2900611 r3340495  
    1 (function(t,i,e){t((function(){var a=t(this);var n=false;a.on("click",'.notice[data-plugin="short-pixel-ai"] .buttons-wrap [data-action], .notice[data-plugin="short-pixel-ai"] button.notice-dismiss, .dismissed-notice[data-plugin="short-pixel-ai"] .buttons-wrap [data-action], .dismissed-notice[data-plugin="short-pixel-ai"] .buttons-wrap button.notice-dismiss',(function(){var o=t(this),d=o.parents('.notice[data-plugin="short-pixel-ai"], .dismissed-notice[data-plugin="short-pixel-ai"]');o.prop("disabled",true);var r=d.attr("data-causer"),s=o.attr("data-type"),c=o.attr("data-action"),u=o.attr("data-additional");r=typeof r==="string"&&r!==""?r:undefined;c=typeof c==="string"&&c!==""?c:r!==undefined&&o.hasClass("notice-dismiss")?"dismiss":undefined;try{u=JSON.parse(u)}catch(t){u=undefined}if(r!==undefined){if(s==="js"){if(typeof jQuery[c]==="function"){jQuery[c](u)}}else if(!n){t.ajax({method:"post",url:typeof ajaxurl==="string"&&ajaxurl!==""?ajaxurl:"/wp-admin/admin-ajax.php",data:{action:"shortpixel_ai_handle_notice_action",causer:d.attr("data-causer"),data:{action:c,additional:u}},beforeSend:function(){n=true},success:function(n){d.slideUp("fast",(function(){if(typeof n.notice==="string"&&n.notice!==""){var i=t(n.notice).hide();d.after(i);a.trigger("wp-updates-notice-added");i.slideDown("fast",(function(){i.removeAttr("style")}))}d.remove()}));if(typeof n.redirect!=="undefined"&&!!n.redirect.allowed){if(typeof n.redirect.url==="string"&&n.redirect.url!==""){if(!!n.redirect.blank){e.open(n.redirect.url)}else{i.location.href=n.redirect.url}}}if(typeof n.reload!=="undefined"&&!!n.reload.allowed){i.location.reload()}},complete:function(){n=false}})}}}))}))})(jQuery,document,window);
     1(function(e,t,a){e((function(){var i=e(this);var n=false;i.on("click",'.notice[data-plugin="short-pixel-ai"] .buttons-wrap [data-action], .notice[data-plugin="short-pixel-ai"] button.notice-dismiss, .dismissed-notice[data-plugin="short-pixel-ai"] .buttons-wrap [data-action], .dismissed-notice[data-plugin="short-pixel-ai"] .buttons-wrap button.notice-dismiss',(function(){var r=e(this),o=r.parents('.notice[data-plugin="short-pixel-ai"], .dismissed-notice[data-plugin="short-pixel-ai"]');r.prop("disabled",true);var s=o.attr("data-causer"),d=r.attr("data-type"),u=r.attr("data-action"),c=r.attr("data-additional");s=typeof s==="string"&&s!==""?s:undefined;u=typeof u==="string"&&u!==""?u:s!==undefined&&r.hasClass("notice-dismiss")?"dismiss":undefined;try{c=JSON.parse(c)}catch(e){c=undefined}if(s!==undefined){if(d==="js"){if(typeof jQuery[u]==="function"){jQuery[u](c)}}else if(!n){e.ajax({method:"post",url:typeof ajaxurl==="string"&&ajaxurl!==""?ajaxurl:"/wp-admin/admin-ajax.php",data:{action:"shortpixel_ai_handle_notice_action",causer:o.attr("data-causer"),data:{action:u,additional:c}},beforeSend:function(){n=true},success:function(n){o.slideUp("fast",(function(){if(typeof n.notice==="string"&&n.notice!==""){var t=e(n.notice).hide();o.after(t);i.trigger("wp-updates-notice-added");t.slideDown("fast",(function(){t.removeAttr("style")}))}o.remove()}));if(typeof n.redirect!=="undefined"&&!!n.redirect.allowed){if(typeof n.redirect.url==="string"&&n.redirect.url!==""){if(!!n.redirect.blank){a.open(n.redirect.url)}else{t.location.href=n.redirect.url}}}if(typeof n.reload!=="undefined"&&!!n.reload.allowed){t.location.reload()}},complete:function(){n=false}})}}}));i.on("click",'.notice[data-causer="recommend_survey"] .survey-rating-btn',(function(t){t.preventDefault();var a=e(this),i=a.data("rating"),n=a.closest('.notice[data-causer="recommend_survey"]');n.find(".survey-rating-btn").removeClass("selected");a.addClass("selected");e.post(ajaxurl,{action:"shortpixel_ai_send_rating",data:{rating:i}});if(i>=9){n.find("h3, .message-wrap > p").slideUp();var r="<p>Thank you for your high rating! "+"If you have a moment, the ShortPixel team would be very happy "+"if you could leave a short review for our plugin.</p>";var o="<p>"+'<button id="survey-feedback-submit" class="button button-primary" '+"onclick=\"window.open('https://wordpress.org/support/plugin/shortpixel-adaptive-images/reviews/?filter=5', '_blank')\">"+"Leave a review"+"</button>"+"</p>";n.find("#survey-feedback-area").html(r+o).slideDown();return}n.find("h3").slideUp();n.find(".survey-rating-btn").closest("p").slideUp();var s=i<=4?"Thank you for your feedback! If you have encountered any issues with our plugin, we are more than eager to help solving them! Please give us more details:":"Thank you for your feedback! Please let us know what we can improve:";n.find("#survey-feedback-prompt").text(s);n.find("#survey-feedback-area").slideDown()}));i.on("click",'.notice[data-causer="recommend_survey"] #survey-feedback-submit',(function(t){t.preventDefault();var a=e(this).closest('.notice[data-causer="recommend_survey"]'),i=a.find(".survey-rating-btn.selected").data("rating"),n=a.find("#survey-feedback").val()||"";e.post(ajaxurl,{action:"shortpixel_ai_send_feedback",data:{rating:i,feedback:n}}).done((function(e){var t=a.find(".message-wrap");if(e.success){t.html("<p>Thank you for your feedback!</p>");a.find("#survey-feedback-area, .buttons-wrap").slideUp()}else{var i=e.data||"Something went wrong sending feedback!";t.html("<p>"+i+"</p>")}}))}))}))})(jQuery,document,window);
  • shortpixel-adaptive-images/tags/3.11.0/changelog.txt

    r2614181 r3340495  
     1= 2.3.3 =
     2Release date: June 30th, 2021
     3* Fix: issue with validating API key
     4* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     5
     6= 2.3.2 =
     7Release date: June 29th, 2021
     8* Temporarily deactivate AVIF pending codec bug fix (https://github.com/xiph/rav1e/issues/2757);
     9* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     10
     11= 2.3.1 =
     12Release date: June 28th, 2021
     13* New: Version the javascript in the file name in order to get around more stubborn caches;
     14* Fix: do not parse AJAX responses to uploads;
     15* Fix: nested element that has a different background - was taking the background of the parent element;
     16* Fix: notice in logs sometimes when domain info from server;
     17* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     18
     19= 2.3.0 =
     20Release date: June 17th, 2021
     21* New: images (including the ones from CSS files) are now served automatically in the new AVIF format to supporting browsers;
     22* New: moved the JS detection mechanism for WebP/AVIF support directly to the CDN level, so no JS is required anymore for this;
     23* Language: 0 new strings added, 6 updated, 0 fuzzed, and 0 obsoleted.
     24
     25= 2.2.4 =
     26Release date: June 14th, 2021
     27* Compat: added a constant - `SPAI_ELEMENTOR_WORKAROUND` - to deactivate the parsing of Elementor modules that are resulting in critical errors;
     28* Compat: workaround for WP Rocket that calls in certain circumstances the filter `rocket_css_content` with only one parameter;
     29* Fix: some warnings when lqip queue is not array were showing up in some cases;
     30* Fix: wrong array key when the no background calculation can't determine crop size and returns just width and height;
     31* Fix: iPhone issues with parsing stylesheets while also improving page responsiveness while parsing them (async);
     32* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     33
     34= 2.2.3 =
     35Release date: May 18th, 2021
     36* New: also parse inside `<script type="text/template">` blocks;
     37* Fix: the background crop resize wasn't working in several cases, which is now fixed;
     38* Fix: update the notification text about the next generation images served by SPIO;
     39* Fix: cases when a mutation has backgrounds from an existing CSS block are now properly handled;
     40* Fix: the special crop feature now handles correctly the situations when the width parameter isn't the first one;
     41* Fix: the inline background selector will handle situations with no space before the CSS class definition;
     42* Fix: remove the default values for JS parameters in order to support IE11;
     43* Fix: the images from `li` elements added with `data-thumb` are now replaced;
     44* Fix: the URL exclusions are checked when replacing inside JS blocks too;
     45* Language: 0 new strings added, 2 updated, 0 fuzzed, and 0 obsoleted.
     46
     47= 2.2.2 =
     48Release date: April 29th, 2021
     49* Fix: the minified version of the plugin CSS files was bigger than the not minified one;
     50* Fix: find local file when URL contains a path element before wp-content, that is not present on disk;
     51* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     52
     53= 2.2.1 =
     54Release date: April 26th, 2021
     55* Compat: added integration with Real3D Flipbook;
     56* Fix: there was a "Class not found" error in some cases when purging LiteSpeed cache from our plugin;
     57* Fix: in some cases, the size of background images wasn't properly set;
     58* Fix: protection added for very large number of product variations; the plugin will now work properly in these cases;
     59* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     60
     61= 2.2.0 =
     62Release date: April 20th, 2021
     63* New: added filter `shortpixel/ai/customRules` for custom replacement rules;
     64* New: added proper lazy loading for background images;
     65* New: take into account the `background-*` CSS styles: size, position, etc.;
     66* New: lazy load the images in the CSS blocks;
     67* New: handle correctly multiple URLs in the same `background-image:` declaration;
     68* New: when running out of credits you can now have an option to top-up directly from the plugin settings;
     69* Compat: added an integration with the Uncode theme and its iLightBox component;
     70* Compat: added integration with WPC Variations Table;
     71* Compat: added integration with Soliloquy Slider Plugin;
     72* Compat: also integrate properly with Divi child themes;
     73* Compat: improved the integration with Elementor, all images should now be properly replaced;
     74* Fix: WooCommerce product variations were broken if srcset was present, but false;
     75* Fix: in certain cases, background images with important CSS priority weren't properly handled;
     76* Fix: also remove the sizes attribute if we remove the srcset;
     77* Fix: replacement error when html attribute contains "<style>.." data;
     78* Fix: various small fixes to settings, fonts, debug messages, ShortPixel account login and lazy loading;
     79* Language: 7 new strings added, 2 updated, 0 fuzzed, and 3 obsoleted.
     80
    181= 2.1.6 =
    282Release date: March 19th, 2021
  • shortpixel-adaptive-images/tags/3.11.0/includes/actions/notice.actions.class.php

    r3209129 r3340495  
    5050            die;
    5151        }
     52
     53        private static function handleRecommendSurvey( $data ) {
     54            if ( ( $data['action'] ?? '' ) === 'dismiss' ) {
     55                return [
     56                    'success' => Notice::dismiss( 'recommend_survey' ),
     57                ];
     58            }
     59            return null;
     60        }
    5261
    5362        private static function handleRemoteInfoNotice ($data){
  • shortpixel-adaptive-images/tags/3.11.0/includes/actions/page.actions.class.php

    r3337681 r3340495  
    6060                }
    6161
     62                if (isset($options->behaviour->storage_url)) {
     63                    $options->behaviour->storage_url = sanitize_text_field(trim($options->behaviour->storage_url));
     64                }
     65
     66                if (isset($options->behaviour->host_removal)) {
     67                    $options->behaviour->host_removal = sanitize_text_field(trim($options->behaviour->host_removal));
     68                }
     69
     70
    6271
    6372                //translate simple meta options
    6473                $options = ShortPixelAI::translateSimpleOptions( $options );
    65 
    6674                $current_options = Options::_()->settings;
     75
     76                // if user just disabled the LQIP option, delete the LQIP state from DB
     77                if (($options->behaviour->lqip ?? null) === false && ($current_options->behaviour->lqip ?? null) === true) {
     78                    delete_option('shortpixel_ai_lqip_state');
     79                }
    6780
    6881                $success = true;
     
    176189                    $cdnMessage = '';
    177190                    $cdnErrorMessage =  '';
    178                     $messageData = $api_response['message']['Message'] ?? [];
     191                    $messageData = $api_response['message']['Details'] ?? [];
    179192                    //getting the array of messages
    180193                    if (!empty($messageData['0']['Message']) || !empty($messageData['CDN']['Message']) || !empty($messageData['CDN']['Error']) ) {
     
    252265            else if ( $action === 'clear lqip cache' ) {
    253266                $success = LQIP::clearCache();
    254                 //var_dump('HERE:', $success, $response);exit('this is only for admin button');
    255267                $response[ 'success' ] = $success;
    256268                $response[ 'notice' ]  = Notice::get( null, [
  • shortpixel-adaptive-images/tags/3.11.0/includes/controllers/feedback.class.php

    r2627986 r3340495  
    1515         */
    1616        protected $controller;
     17
     18        private $logger;
    1719
    1820        /**
     
    301303                self::$instance = $this;
    302304            }
    303 
     305            $this->logger = \ShortPixelAILogger::instance();
    304306            $this->controller = $controller;
    305307
    306308            add_action( 'admin_footer-plugins.php', [ $this, 'generatePopUp' ] );
    307309            add_action( 'wp_ajax_shortpixel_ai_handle_feedback_action', [ 'ShortPixel\AI\Feedback\Actions', 'handle' ] );
    308         }
    309     }
     310
     311            add_action( 'wp_ajax_shortpixel_ai_send_rating', [ $this, 'handleSurveyAjax' ] );
     312            add_action( 'wp_ajax_shortpixel_ai_send_feedback', [ $this, 'handleSurveyAjax' ] );
     313        }
     314
     315        public function handleSurveyAjax() {
     316
     317
     318            $rating   = isset($_POST['data']['rating']) ? intval($_POST['data']['rating']) : 0;
     319            $feedback = isset($_POST['data']['feedback']) ? sanitize_text_field($_POST['data']['feedback']) : '';
     320
     321            if ( ! $rating || $rating < 1 || $rating > 10 ) {
     322                wp_send_json_error(__('Invalid rating', 'shortpixel-adaptive-images'));
     323            }
     324            $response = self::sendSurvey( $rating, $feedback );
     325
     326            if ( is_wp_error($response) ) {
     327                wp_send_json_error(__('Feedback could not be sent.', 'shortpixel-adaptive-images'));
     328            }
     329
     330            Notice::dismiss( 'recommend_survey' );
     331            wp_send_json_success();
     332
     333        }
     334
     335
     336        public  function sendSurvey( $rating, $feedback, $anonymous = false ) {
     337
     338            if ( ! is_int( $rating ) || $rating < 1 || $rating > 10 ) {
     339                return false;
     340            }
     341            $wordpress = self::collectWordpressData( ShortPixelAI::is_beta() );
     342            $wordpress['deactivated_plugin']['uninstall_reason']  = 'rating';
     343            $wordpress['deactivated_plugin']['uninstall_details'] = 'Rating: ' . $rating
     344                . ( $feedback ? ' – Feedback: ' . $feedback : '' );
     345
     346            $body = [
     347                'user'      => self::collectUserData( $anonymous ),
     348                'wordpress' => $wordpress,
     349            ];
     350            $spai_key = Options::_()->settings_general_apiKey;
     351            if ( $spai_key && ! $anonymous ) {
     352                $body['key'] = $spai_key;
     353            }
     354
     355            return Request::post( 'https://api.shortpixel.com/v2/feedback.php', true, [ 'body' => $body ] );
     356        }
     357    }
  • shortpixel-adaptive-images/tags/3.11.0/includes/controllers/lqip.class.php

    r3209129 r3340495  
    120120        private $ctrl;
    121121
     122        private function normalizeLqipItem(array $item): array {
     123            if (!isset($item['source']) || !isset($item['url'])) {
     124                return $item;
     125            }
     126
     127            if ($item['source'] === $item['url']) {
     128                $item['lqipUrl'] = $item['url'];
     129                unset($item['source'], $item['url']);
     130            } else {// log to catch them and see if it's really useful to keep both sourcce & url
     131                $this->log('LQIP normalize: source ≠ url', [
     132                    'source' => $item['source'],
     133                    'url'    => $item['url'],
     134                    'referer' => $item['referer'] ?? null
     135                ]);
     136
     137                $item['source'] = null;
     138                $item['lqipUrl'] = $item['url'];
     139                unset($item['url']);
     140            }
     141            return $item;
     142        }
     143
     144
     145        private function provideTimestamp(array $collection): array {
     146            $now = time();
     147            foreach ($collection as &$item) {
     148                if (!isset($item['timestamp'])) {
     149                    $item['timestamp'] = $now;
     150                }
     151            }
     152            unset($item);
     153            return $collection;
     154        }
     155
     156        private function removeOldItemsFromCollection(array $collection, int $maxAgeSeconds = 86400): array {
     157            $threshold = time() - $maxAgeSeconds;
     158            return array_filter($collection, function($item) use ($threshold) {
     159                return !isset($item['timestamp']) || $item['timestamp'] >= $threshold;
     160            });
     161        }
     162
     163        private function getLqipState() {
     164            $state = get_option('shortpixel_ai_lqip_state', null);
     165
     166            if ($state === null) {
     167                // get previous data from old options
     168                $state = [
     169                    'collection' => Options::_()->get('collection', self::OPTIONS_CATEGORY, []),
     170                    'processed'  => Options::_()->get('processed', self::OPTIONS_CATEGORY, []),
     171                ];
     172                $state['collection'] = $this->provideTimestamp($state['collection']);
     173
     174                update_option('shortpixel_ai_lqip_state', $state);
     175                Options::_()->delete('collection', self::OPTIONS_CATEGORY);
     176                Options::_()->delete('processed', self::OPTIONS_CATEGORY);
     177            }
     178
     179            if (!is_array($state)) {
     180                $state = [ 'collection' => [], 'processed' => [] ];
     181            }
     182
     183            if (!isset($state['collection']) || !is_array($state['collection'])) $state['collection'] = [];
     184            if (!isset($state['processed']) || !is_array($state['processed'])) $state['processed'] = [];
     185
     186            return $state;
     187        }
     188
     189        private function saveLqipState($state) {
     190            update_option('shortpixel_ai_lqip_state', $state);
     191        }
     192
     193
     194
    122195        /**
    123196         * Single ton implementation
     
    179252                    $valid = !$this->exists( $name ) || $this->expired( $name );
    180253                    if(!$valid) {
    181                         $this->log("Dropping URL: " . $item . ' name: ' . $name);
     254                        $this->log("Dropping URL: " . json_encode($item) . ' name: ' . $name);
    182255                    }
    183256
     
    251324         */
    252325        public function eventHandler() {
    253             $collection = Options::_()->get( 'collection', self::OPTIONS_CATEGORY, [] );
    254             if(!is_array($collection)) $collection = [];
    255             $this->log('LQIP EVT HANLER: COLLECTION: ', $collection);
    256 
    257             if ( empty( $collection ) ) {
    258                 return;
    259             }
    260 
    261             $processed = Options::_()->get( 'processed', self::OPTIONS_CATEGORY, [] );
    262             $this->log('LQIP EVT HANLER: PROCESSED REQUESTS: ', $processed);
     326            $state = $this->getLqipState();
     327            $collection = $state['collection'];
     328            $processed = $state['processed'];
     329
     330            $this->log('LQIP EVT HANDLER: PROCESSED REQUESTS: ', $processed);
    263331
    264332
    265333            $collection = $this->filterWithProcessed( $collection, $processed );
    266 
    267334            $bundle = array_splice( $collection, 0, self::BUNDLE_CAPACITY );
    268335
    269             $this->log('LQIP EVT HANLER: SETTING COLLECTION: ', $collection);
    270             Options::_()->set( $collection, 'collection', self::OPTIONS_CATEGORY );
    271 
    272             $this->log('LQIP EVT HANLER: GENERATE BUNDLE: ', $bundle);
     336            $this->log('LQIP EVT HANDLER: GENERATE BUNDLE: ', $bundle);
     337            $state['collection'] = $collection;
     338            $this->saveLqipState($state);
    273339            $this->generate( $bundle );
    274340
     
    291357        private function schedule( $collection ) {
    292358            if ( !empty( $collection ) && is_array( $collection ) ) {
    293                 $scheduled_collection = Options::_()->get( 'collection', self::OPTIONS_CATEGORY, [] );
    294                 if(!is_array($scheduled_collection)) $scheduled_collection = [];
    295 
     359                $state = $this->getLqipState();
     360                $scheduled_collection = $state['collection'];
    296361                $collection = array_merge( $scheduled_collection, $collection );
     362                $collection = $this->provideTimestamp($collection);
     363                $collection = $this->removeOldItemsFromCollection($collection);
    297364                $collection = $this->replaceWithParent( $collection );
    298365                $collection = $this->filterCollection( $collection );
    299366
     367                $collection = array_map(function($item) {
     368                    return $this->normalizeLqipItem($item);
     369                }, $collection);
     370
    300371                $collection = array_filter( $collection, function( $item ) {
    301                     $name = $this->getFileName( $item[ 'source' ] );
     372                    $name = $this->getFileName( $item[ 'source' ] ?? $item['lqipUrl'] ?? '' );
    302373
    303374                    return !$this->exists( $name ) || $this->expired( $name );
    304375                } );
    305376
    306                 $this->log('SETTING LQIP COLLECTION: ', $collection);
    307 
    308                 $option_set = Options::_()->set( $collection, 'collection', self::OPTIONS_CATEGORY );
     377
     378                $state['collection'] = $collection;
     379                $this->saveLqipState($state);
    309380
    310381                if ( empty( $collection ) ) {
     
    316387                    $this->reschedule( 'quick' );
    317388
    318                     return ['processed' => !!$option_set, 'message' => (!!$option_set ? '' : 'Could not set lqip option.')];
     389                    return ['processed' => true];
    319390                }
    320391            }
     
    337408            if ( !empty( $collection ) && is_array( $collection ) ) {
    338409
    339                 $processed = Options::_()->get( 'processed', self::OPTIONS_CATEGORY, [] );
     410                $state = $this->getLqipState();
     411                $processed = $state['processed'];
    340412                $this->log( 'LQIP REQUESTS START. ALREADY PROCESSED: ', $processed );
    341413
     
    411483            $return = $this->countAttempts( $return, $processed );
    412484            $processed    = $this->filterCollection( array_merge( $processed, $return ) );
    413             Options::_()->set( $processed, 'processed', self::OPTIONS_CATEGORY );
     485            $state['processed'] = $processed;
     486            $this->saveLqipState($state);
    414487
    415488            return $return;
     
    435508         */
    436509        private function isPlaceholder( $content ) {
    437             return empty( $content ) ? false : $this->isSvg( $content ) && strpos( $content, 'feGaussianBlur' ) !== false;
     510            return empty( $content ) ? false : $this->isSvg( $content ) && (strpos( $content, 'feGaussianBlur' ) !== false ||
     511                strpos( $content, 'filter="blur' ) !== false);
    438512        }
    439513
     
    9591033            if ( !!$this->ctrl->options->settings_behaviour_lqip && $this->ctrl->options->settings_behaviour_processWay === LQIP::USE_INSTANT)
    9601034            {
     1035
    9611036                wp_register_script( 'spai-lqip', $this->ctrl->plugin_url . $file, $this->ctrl->options->settings_behaviour_nojquery <= 0 ? [ 'spai-scripts' ] : [], $version, true );
    9621037                wp_localize_script( 'spai-lqip', 'lqipConstants', [
  • shortpixel-adaptive-images/tags/3.11.0/includes/controllers/notice.class.php

    r3258698 r3340495  
    373373            }
    374374
     375            if ( is_admin() && isset( $_GET['page'] ) && $_GET['page'] === 'shortpixel-ai-settings') {
     376                $installed = get_option( 'shortpixel_ai_installed_time' );
     377                if ( ! $installed ) {
     378                    update_option( 'shortpixel_ai_installed_time', time() );
     379                }
     380                elseif ( time() - $installed >= 30 * DAY_IN_SECONDS ) {
     381                    $dismissed = self::getDismissed();
     382                    if ( !isset( $dismissed->recommend_survey ) ) {
     383                        Notice::render('recommend_survey', [
     384                            'notice' => [
     385                                'type' => 'info',
     386                                'icon' => 'notes',
     387                                'dismissible' => true,
     388                            ],
     389                            'message' => [
     390                                'title' => __('How likely are you to recommend ShortPixel AI to a friend or colleague?', 'shortpixel-adaptive-images'),
     391                                'body' => [
     392                                    '<p><span style="margin-right:1em;">' . __('Not likely', 'shortpixel-adaptive-images') . '</span>'
     393                                    . implode('', array_map(function ($i) {
     394                                        return '<button class="button survey-rating-btn" '
     395                                            . 'data-rating="'. $i .'" '
     396                                            . 'style="margin:0 3px; min-width:2.5em; text-align:center; line-height:1.6;">'
     397                                            . $i
     398                                            . '</button>';
     399                                    }, range(1, 10)))
     400                                    . '<span style="margin-left:1em;">' . __('Very likely', 'shortpixel-adaptive-images') . '</span></p>',
     401                                    '<div id="survey-feedback-area" style="display:none;margin-top:10px;">'
     402                                    . '<p><strong id="survey-feedback-prompt">' . __('Give us your feedback:', 'shortpixel-adaptive-images') . '</strong></p>'
     403                                    . '<textarea id="survey-feedback" rows="3" style="width:100%;"></textarea><br><br>'
     404                                    . '<button id="survey-feedback-submit" class="button button-primary">'
     405                                    . __('Submit', 'shortpixel-adaptive-images')
     406                                    . '</button>'
     407                                    . '</div>',
     408                                ],
     409                            ],
     410                        ]);
     411                    }
     412                }
     413            }
     414
    375415            if ( !isset( $dismissed->wp_rocket_defer_js ) && $integrations->has( 'wp-rocket', 'defer-all-js' ) ) {
    376416                self::render( 'wp rocket defer js', [
  • shortpixel-adaptive-images/tags/3.11.0/includes/controllers/page.class.php

    r3074757 r3340495  
    244244                    header('Content-Type: application/json');
    245245                    header('Content-Disposition: attachment; filename=SPAI-settings.json');
    246                     echo(json_encode($this->ctrl->options->get()->settings, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
     246                    echo(json_encode($this->ctrl->options->get()->settings->exportRecursive(), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    247247                    die();
    248248                } );
  • shortpixel-adaptive-images/tags/3.11.0/includes/controllers/regex-parser.class.php

    r3209129 r3340495  
    2626    private $forceEager = false;
    2727    private $isTemplate = false;
     28    private $content;
    2829
    2930
     
    4243    ];
    4344
     45
     46    protected function markTotalExclude(string $tagHtml, string $origUrl): string
     47    {
     48        $attrs  = ' data-spai-target="src"';
     49        $attrs .= ' data-spai-orig="' . esc_attr($origUrl) . '"';
     50        $attrs .= ' data-spai-exclude="nocdn"';
     51        return preg_replace(
     52            '/<img\b([^>]*)>/i',
     53            '<img$1' . $attrs . '>',
     54            $tagHtml,
     55            1
     56        );
     57    }
    4458
    4559    public function __construct(ShortPixelAI $ctrl)
     
    160174        //In some cases the regex fails with this limit reached (default is 1000000) so make it larger (HS#75940)
    161175        ini_set('pcre.backtrack_limit', 2000000);
     176
     177        $this->content = $content;
    162178
    163179        foreach (\ShortPixel\AI\TagRules::_()->items() as $tagRule) {
     
    670686        if(   !ShortPixelUrlTools::isValid($url)
    671687           && (!$this->isTemplate || strpos($url, '{{:') === false)) {$this->logger->log('NOT VALID');return $text;}
    672         if($this->ctrl->urlIsExcluded($url)) {$this->logger->log('EXCLUDED');return $text;}
     688        if ($this->ctrl->urlIsExcluded($url)) {
     689            $this->logger->log('EXCLUDED TOTALLY: ' . $url);
     690            return $this->markTotalExclude($text, $url);
     691        }
    673692
    674693        //custom exclusion for SliderRevolution TODO unhack
     
    699718        }
    700719
    701         $eager = $this->isEager || $this->ctrl->tagIs('eager', $text);
     720        $eager = $this->isEager || $this->ctrl->tagIs('eager', $text) || $this->ctrl->urlIsEager($url);;
    702721
    703722        SHORTPIXEL_AI_DEBUG && $this->logger->log("Including: " . $url . ($eager ? ' EAGER' : ' LAZY'));
     
    776795
    777796        if($eager) {
    778             //we set any CSS or JS to ret_wait because of the many CORS issues we've seen with these.
    779             $wait = $ext == 'css' || $ext == 'js';
     797            //we set any CSS or JS or FONTS to ret_wait because of the many CORS issues we've seen with these.
     798            $wait = in_array($ext, ShortPixelUrlTools::$EAGER_WAIT);
    780799            $cacheVer = $wait ? $this->ctrl->cssCacheVer : false;
    781800            if($this->isTemplate && strpos($url, '{{:') === 0) {
     
    783802                    . '/' . $url;
    784803            } else {
    785                 $inlinePlaceholder = $this->ctrl->get_api_url( $absoluteUrl, false, false, $this->ctrl->get_extension( $url ), $this->tagRule->getCustomCompression(), $wait, $cacheVer);
     804                $separator = strpos($this->content, $absoluteUrl) > 0 && $this->tagRule->attrValFilter == "preload" ? "," : ShortPixelAI::SEP;
     805                $inlinePlaceholder = $this->ctrl->get_api_url($absoluteUrl, false, false, $this->ctrl->get_extension($url),  $this->tagRule->getCustomCompression(), $wait, $cacheVer, $separator);
    786806            }
    787807            $spaiMarker = ' data-spai-egr=' . $qm . '1' . $qm;
     
    10301050        $aiSrcsetItems = array();
    10311051        $aiUrl = $this->ctrl->get_api_url(false, false);
    1032         $aiUrlBase = $this->ctrl->settings->behaviour->api_url;
     1052        $aiUrlBase = $this->ctrl->settings->behaviour->api_url; //ex: https://cdn.shortpixel.ai/spai
     1053        $aiUrlBaseAmazon = $this->ctrl->settings->behaviour->storage_url; //ex: https://cdn.shortpixel.ai/x9
    10331054        $srcsetItems = explode(',', $srcset);
    10341055        foreach($srcsetItems as $srcsetItem) {
     
    10401061                return $srcset;
    10411062            }
    1042             if(strpos($srcsetItem, $aiUrlBase) !== false || strpos($srcsetItem, 'data:image/') === 0) {
     1063            if(strpos($srcsetItem, $aiUrlBase) !== false || strpos($srcsetItem, $aiUrlBaseAmazon) !== false || strpos($srcsetItem, 'data:image/') === 0) {
    10431064                SHORTPIXEL_AI_DEBUG && $this->logger->log("REPLACE SRCSET abort - AI url: " . $srcsetItem);
    10441065                return $srcset; //already parsed by the hook.
  • shortpixel-adaptive-images/tags/3.11.0/includes/controllers/short-pixel-ai.class.php

    r3310531 r3340495  
    470470        if ( is_null( $this->options->get( 'api_url', [ 'settings', 'behaviour' ], null ) ) ) {
    471471            $this->options->settings_behaviour_apiUrl        = ShortPixelAI::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH;
     472            $this->options->settings_behaviour_amazonS3        = false;
    472473            $this->options->settings_behaviour_replaceMethod = 'src';
    473474            $this->options->settings_behaviour_fadein        = true;
     
    11331134                $result['message'] = __('Invalid selector has been provided.', 'shortpixel-adaptive-images' );
    11341135            }
    1135             else if(empty($which) || !is_string($which) || !in_array($which, array('noresize_selectors', 'excluded_selectors', 'excluded_paths', 'eager_selectors'))) {
     1136            else if(empty($which) || !is_string($which) || !in_array($which, array('noresize_selectors', 'excluded_selectors', 'excluded_paths', 'eager_paths', 'eager_selectors'))) {
    11361137                $result['message'] = __('Invalid list has been provided.', 'shortpixel-adaptive-images' );
    11371138            }
     
    11411142                $selectors_now = $this->options->$wp_option_name;
    11421143                $result['status'] = 'ok';
    1143                 if($which === 'excluded_paths') {
     1144                if($which === 'excluded_paths' || $which === 'eager_paths' ) {
    11441145                    $name = 'URL';
    11451146                    $delimiter = "\n";
     
    12141215                $result['message'] = __('Invalid list has been provided.', 'shortpixel-adaptive-images' );
    12151216            }
    1216             else if(empty($which) || !is_string($which) || !in_array($which, array('noresize_selectors', 'excluded_selectors', 'excluded_paths', 'eager_selectors'))) {
     1217            else if(empty($which) || !is_string($which) || !in_array($which, array('noresize_selectors', 'excluded_selectors', 'excluded_paths', 'eager_selectors', 'eager_paths'))) {
    12171218                $result['message'] = __('Invalid list has been provided.', 'shortpixel-adaptive-images' );
    12181219            }
     
    13031304                $options->settings_behaviour_replaceMethod = $replace_method == 1 ? 'src' : ( $replace_method == 3 ? 'both' : 'srcset' );
    13041305                $options->settings_behaviour_apiUrl        = get_option( 'spai_settings_api_url' );
    1305                 $options->settings_behaviour_hoverHandling = !!get_option( 'spai_settings_hover_handling' );
     1306                $options->settings_behaviour_hoverHandling = !!get_option( 'spai_settings_hover_handling' );
    13061307                $options->settings_behaviour_nativeLazy    = !!get_option( 'spai_settings_native_lazy' );
    13071308
     
    15031504        if (function_exists('is_plugin_active') && is_plugin_active('sg-cachepress/sg-cachepress.php')) {
    15041505            $speedoptimizer = get_option('siteground_optimizer_combine_javascript', false);
    1505             //var_dump($speedoptimizer);
    15061506            if ($speedoptimizer === '1') {
    15071507                $this->conflict = 'speedoptimizer';
     
    15511551    }
    15521552
    1553     public function get_api_url( $url = false, $width = '%WIDTH%', $height = '%HEIGHT%', $type = false, $compression = false, $retAuto = false, $cacheVer = false) {
     1553
     1554    /**
     1555     * This function checks whether the CDN returned by get_cdn_url() is different
     1556     * from the default "https://cdn.shortpixel.ai/spai".
     1557     *
     1558     * If it is different, we consider it a "custom CDN".
     1559     */
     1560    private function is_custom_cdn()
     1561    {
     1562        $cdn = $this->get_cdn_url();
     1563        if (!$cdn) {
     1564            $cdn = self::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH;
     1565        }
     1566        $cdn = rtrim($cdn, '/');
     1567        $defaultCdn = rtrim(self::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH, '/');
     1568        $isBasicCustom = ($cdn !== $defaultCdn);
     1569
     1570        return $isBasicCustom;
     1571    }
     1572
     1573    private function is_amazon_cdn(){
     1574        $amazonGet = $this->settings->behaviour->amazon_s3;
     1575        $amazonEnabled   = !empty($amazonGet);
     1576        $amazonStorageGet   = $this->settings->behaviour->storage_url; // tha's the user input
     1577        $amazonStorage = !empty($amazonStorageGet);
     1578        // only if user has a storage_url (and amazon_s3 is enabled), we  consider that is 'custom as well.
     1579        $isAmazonCustom = ($amazonEnabled && $amazonStorage);
     1580
     1581        return $isAmazonCustom;
     1582    }
     1583
     1584    /**
     1585     * chooses the appropriate API base URL based on CDN settings.
     1586     *
     1587     * @param string|false $url The original URL.
     1588     * @return string The selected base URL.
     1589     */
     1590    public function choose_api_base()
     1591    {
     1592        $isAmazonCdn = $this->is_amazon_cdn();
     1593
     1594        if ($isAmazonCdn) {
     1595            return rtrim($this->settings->behaviour->storage_url, '/');
     1596        } else {
     1597            $cdnUrl = rtrim($this->get_cdn_url(), '/');
     1598            if (!$cdnUrl) {
     1599                $cdnUrl = rtrim(self::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH, '/');
     1600            }
     1601            return $cdnUrl;
     1602        }
     1603    }
     1604
     1605    private function do_host_removal(){
     1606        $hostRemovalGet = $this->settings->behaviour->host_removal;
     1607        $isHostRemoval   = !empty($hostRemovalGet);
     1608        return$isHostRemoval;
     1609    }
     1610
     1611    /**
     1612     * Applies host removal to the API URL if conditions are met.
     1613     *
     1614     * @param string $api_url The constructed API URL.
     1615     * @param string|false $url The original URL.
     1616     * @return string The final URL after host removal (if applied).
     1617     */
     1618    private function host_removal_logic($api_url, $url)
     1619    {
     1620        if (!$url) {
     1621            return $api_url;
     1622        }
     1623
     1624        $doHostRemoval = $this->do_host_removal();
     1625        $hostRemoval = $this->settings->behaviour->host_removal;
     1626
     1627        if ($doHostRemoval && $url){
     1628            $parsedUrl = parse_url($url);
     1629            $host = $parsedUrl['host'] ?? '';
     1630
     1631            if (strpos($host, $hostRemoval) !== false) {
     1632                $path = isset($parsedUrl['path']) ? $parsedUrl['path'] : '';
     1633                $query = isset($parsedUrl['query']) ? '?' . $parsedUrl['query'] : '';
     1634                $frag = isset($parsedUrl['fragment']) ? '#' . $parsedUrl['fragment'] : '';
     1635                $final = rtrim($api_url, '/') . $path . $query . $frag;
     1636                return $final;
     1637            }
     1638        }
     1639
     1640        return $api_url;
     1641    }
     1642
     1643
     1644
     1645
     1646    /**
     1647     * This helper method builds the final URL by appending ShortPixel parameters
     1648     * (w_, q_, ex_, to_, etc.) to the base URL using self::SEP.
     1649     *
     1650     * @param string $baseUrl  e.g. "https://cdn.shortpixel.ai/spai"
     1651     * @param array  $args     e.g. [ ['w' => 300], ['q' => 'lossy'], ['ex' => '1'] ]
     1652     * @return string          e.g. "https://cdn.shortpixel.ai/spai/w_300+q_lossy+ex_1"
     1653     */
     1654    private function build_spai_url($baseUrl, array $args, $separator = self::SEP){
     1655        $api_url = trailingslashit($baseUrl);
     1656        foreach ($args as $arg) {
     1657            foreach ($arg as $k => $v) {
     1658                $api_url .= $k . '_' . $v . $separator;
     1659            }
     1660        }
     1661        return  rtrim($api_url, $separator);
     1662
     1663    }
     1664    public function get_api_url( $url = false, $width = '%WIDTH%', $height = '%HEIGHT%', $type = false, $compression = false, $retAuto = false, $cacheVer = false, $separator = self::SEP) {
     1665
     1666        if ($url && $this->urlIsExcluded($url)) {
     1667            $this->logger->log("DEBUG get_api_url: URL completly excluded. Returning original URL: " . $url);
     1668            return $url;
     1669        }
    15541670        $args = array();
    15551671        $http = $url === false ? !is_ssl() : !self::is_ssl($url);
    15561672
    1557         if($compression == 'orig' && defined('SHORTPIXEL_AI_ORIG_NO_CDN')) {
     1673        if ($compression == 'orig' && defined('SHORTPIXEL_AI_ORIG_NO_CDN')) {
    15581674            return '';
    15591675        }
     
    15901706        }
    15911707
    1592         $api_url = $this->get_cdn_url();
    1593 
    1594         if ( !$api_url ) {
    1595             $api_url = self::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH;
    1596         }
    1597 
    1598         $api_url = trailingslashit($api_url);
    1599 
    1600         /*
    1601         Make args to be in desired format
    1602          */
    1603         foreach ($args as $arg) {
    1604             foreach ($arg as $k => $v) {
    1605                 $api_url .= $k . '_' . $v . self::SEP;
    1606             }
    1607         }
    1608         $api_url = rtrim($api_url, self::SEP);
    1609         //$api_url = trailingslashit( $api_url );
    1610         return $api_url . ($url ?  '/' . self::rem_proto($url) : '');
    1611     }
     1708
     1709        $isAmazonCdn = $this->is_amazon_cdn(); //verify if it is amazon CDN
     1710
     1711//        detect bucket name presence in host
     1712        $hostFound = false;
     1713        if ($isAmazonCdn) {
     1714            $hostRemovalGet = $this->settings->behaviour->host_removal ?? null;
     1715
     1716            if ($hostRemovalGet && $url) {
     1717                $parsed = parse_url($url);
     1718                $host = $parsed['host'] ?? '';
     1719                if (strpos($host, $hostRemovalGet) !== false) {
     1720                    $hostFound = true;
     1721                }
     1722            }
     1723        }
     1724            if ($hostFound){
     1725                // case 1: amazon CDN active and URL contains host_removal, will apply amazon cdn + host removal
     1726                $amazonStorageGet = $this->settings->behaviour->storage_url;
     1727                $base = rtrim($amazonStorageGet, '/'); // Amazon base
     1728                $api_url = $this->build_spai_url($base, $args, $separator);
     1729                $this->logger->log("BUILT Amazon api_url => ", $api_url);
     1730
     1731                $final_url = $this->host_removal_logic($api_url, $url);
     1732                if ($final_url !== $api_url) {
     1733                    return $final_url;
     1734                }
     1735                if (!$url) {
     1736                    return $api_url;
     1737                }
     1738
     1739                $ret = $api_url . '/' . self::rem_proto($url);
     1740                return $ret;
     1741            } else {
     1742                // case 2: Amazon CDN active but URL does't match host_removal will not put amazon cdn and not remove host
     1743                // case 3: Amazon CDN disabled ... get as usual with normal cdn
     1744                $base = rtrim($this->get_cdn_url(), '/');
     1745                if (!$base) {
     1746                    $base = rtrim(self::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH, '/');
     1747                }
     1748                $api_url = $this->build_spai_url($base, $args, $separator);
     1749
     1750                if (!$url) {
     1751                    return $api_url;
     1752                }
     1753
     1754                $final = $api_url . '/' . self::rem_proto($url);
     1755                return $final;
     1756            }
     1757        }
    16121758
    16131759    public function maybe_replace_images_src($content)
     
    17531899            'noresize_selectors' => $this->splitSelectors( @$ex->noresize_selectors, ',' ),
    17541900            'excluded_paths'     => $this->splitSelectors( @$ex->excluded_paths, "\n" ),
     1901            'eager_paths'        => $this->splitSelectors( @$ex->eager_paths, "\n" ),
    17551902            'excluded_pages'     => $this->splitSelectors( @$ex->excluded_pages, "\n" ),
    17561903        ];
     
    18111958    }
    18121959
    1813     public function urlIsExcluded($url) {
    1814 
    1815         //exclude generated images like JetPack's admin bar hours stats
    1816         if(strpos($url, '?page=')) {
    1817             $admin = parse_url(admin_url());
    1818             if(isset($admin['path']) && strpos($url, $admin['path'])) {
    1819                 return true;
    1820             }
    1821         }
    1822 
    1823         if( strlen($this->settings->exclusions->excluded_paths)) {
    1824             return $this->isExcluded($url, $this->settings->exclusions->excluded_paths);
    1825         } else {
    1826             return false;
    1827         }
    1828 
    1829     }
    1830 
     1960
     1961    /**
     1962     *
     1963     * This function parses the given URL and removes any resolution suffix (e.g., "-1024x576")
     1964     * that is automatically appended by some WordPress themes for images.      *
     1965     *
     1966     * useful when comparing image URLs against exclusion rules, insuring that any
     1967     * appended resolution suffix does not prevent a match with the base URL.
     1968     *
     1969     * @param string $url - original image URL.
     1970     * @return string -  normalized image URL without the resolution suffix, or the original URL if parsing fails.
     1971     */
     1972    public function normalizeUrlForExcluded($url) {
     1973        $parsed = parse_url($url);
     1974        $this->logger->log("DEBUG: parsed " . json_encode($parsed, JSON_PRETTY_PRINT)); //var_export($parsed) //print_r($parsed)
     1975        if (!isset($parsed['path'])) {
     1976            return $url;
     1977        }
     1978        $normalizedPath = preg_replace(
     1979            '/-\d+x\d+(?=\.\w+$)/',
     1980            '',
     1981            $parsed['path']
     1982        );
     1983        $scheme   = isset($parsed['scheme']) ? $parsed['scheme'] : (is_ssl() ? 'https' : 'http');
     1984        $siteUrl  = home_url();
     1985        $siteHost = parse_url($siteUrl, PHP_URL_HOST);
     1986        return $scheme . '://' . $siteHost . $normalizedPath;
     1987    }
     1988
     1989    /**
     1990     * Core URL-matching method to test either total or eager exclusion.
     1991     *
     1992     * @param  string $mode  Either 'excluded' (full exclusion) or 'eager' (skip lazy only)
     1993     * @param  string $url   The image URL (may include CDN, Amazon, any host or size suffix)
     1994     * @return bool          True for matching either one mode’s rules
     1995     */
     1996    public function urlIs($mode, $url)
     1997    {
     1998        //revert CDN url to original
     1999        if ($this->urlIsApi($url)) {
     2000            $stripped = self::rem_proto($url);
     2001            $scheme = self::is_ssl($url) ? 'https://' : 'http://';
     2002            $url = $scheme . $stripped;
     2003            $this->logger->log("DEBUG urlIs: Reverted CDN URL to original: $url");
     2004        }
     2005        //exclude generated images like JetPack's admin bar hours stats
     2006        if (strpos($url, '?page=')) {
     2007            $admin = parse_url(admin_url());
     2008            if (strpos($url, $admin['path'])) {
     2009                return true;
     2010            }
     2011        }
     2012        //normalize any resolution suffix...
     2013        $normalizedUrl = $this->normalizeUrlForExcluded($url);
     2014        $this->logger->log("DEBUG urlIsExcluded: Normalized URL: " . $normalizedUrl);
     2015        //2 posibilities URL -> total exclusion('excluded') or eager exclusion('eager')
     2016        $list = ($mode === 'excluded')
     2017            ? $this->settings->exclusions->excluded_paths
     2018            : $this->settings->exclusions->eager_paths;
     2019        if (strlen($list)) {
     2020            if ($this->isExcluded($url, $list) || $this->isExcluded($normalizedUrl, $list)) {
     2021                return true;
     2022            }
     2023        }
     2024
     2025        return false;
     2026
     2027    }
     2028
     2029    /**
     2030     * FULL-EXCLUSION wrapper:
     2031     * Returns true if this URL must skip CDN entirely (no lazy, no CDN).
     2032     *
     2033     * @param  string $url
     2034     * @return bool
     2035     */
     2036    public function urlIsExcluded(string $url): bool
     2037    {
     2038        return $this->urlIs('excluded', $url);
     2039    }
     2040
     2041    /**
     2042     * EAGER-ONLY wrapper:
     2043     * Returns true if this URL should load eagerly (CDN OK but no lazy loading).
     2044     *
     2045     * @param  string $url
     2046     * @return bool
     2047     */
     2048    public function urlIsEager(string $url): bool
     2049    {
     2050        return $this->urlIs('eager', $url);
     2051    }
    18312052
    18322053    /**
     
    18762097                    case 'http': //being so kind to accept urls as they are. :)
    18772098                    case 'https':
    1878                         if(!isset($urlParsed['host'])) {
    1879                             $valueParsed = parse_url($value);
    1880                             if(isset($valueParsed['host'])) {
    1881                                 $url = ShortPixelUrlTools::absoluteUrl($url);
    1882                             }
    1883                         }
    18842099                        if(strpos($url, $value) !== false) {
    18852100                            $this->logger->log("EXCLUDED by $type $value RULE:", $rule);
    18862101                            return true;
    18872102                        }
     2103
     2104                        if (isset($urlParsed['path'])) {
     2105                            $ruleParsed = parse_url($value);
     2106                            if (!empty($ruleParsed['path'])) {
     2107                                $rulePathNorm = preg_replace('/-\d+x\d+(?=\.\w+$)/', '', $ruleParsed['path']);
     2108                                $urlPathNorm  = preg_replace('/-\d+x\d+(?=\.\w+$)/', '', $urlParsed['path']);
     2109                                if ($rulePathNorm === $urlPathNorm) {
     2110                                    $this->logger->log("EXCLUDED by HOST-INSENSITIVE PATH MATCH: $rulePathNorm");
     2111                                    return true;
     2112                                }
     2113                            }
     2114                        }
    18882115                        if(isset($urlParsed['path'])) {
    18892116                            preg_match(self::THUMBNAIL_REGEX, $urlParsed['path'], $matches);
     
    20592286            'exclusions' => [
    20602287                'excluded_paths' => self::GRAVATAR_REGEX,
    2061                 'eager_selectors' => '',
     2288                'eager_paths' => '',
     2289                'eager_selectors' => '',
    20622290                'noresize_selectors' => '',
    20632291                'excluded_selectors' => '',
  • shortpixel-adaptive-images/tags/3.11.0/includes/front/jquery-js-loader.class.php

    r3209129 r3340495  
    7070            //the excluded_paths can contain URLs so we base64 encode them in order to pass our own JS parser :)
    7171            'excluded_paths'        => array_map( 'base64_encode', $this->ctrl->splitSelectors( $this->settings->exclusions->excluded_paths, PHP_EOL ) ),
     72            'eager_paths'        => array_map( 'base64_encode', $this->ctrl->splitSelectors( $this->settings->exclusions->eager_paths, PHP_EOL ) ),
    7273        ] );
    7374
  • shortpixel-adaptive-images/tags/3.11.0/includes/front/vanilla-js-loader.class.php

    r3337681 r3340495  
    1717        add_action( 'wp_head', function() {
    1818            $apiUrlParts = explode('/', rtrim($this->ctrl->get_cdn_url(), '/'));
     19            $customApiUrlParts = explode('/', rtrim($this->ctrl->choose_api_base(), '/'));
     20            $customKeys = [];
     21            if ($this->settings->behaviour->amazon_s3) {
     22                $hostRemoval = $this->settings->behaviour->host_removal;
     23                $customKey   = end($customApiUrlParts);
     24                if ($hostRemoval && $customKey) {
     25                    $customKeys[$hostRemoval] = $customKey;
     26                }
     27            }
     28
    1929            $convert = 'none';
    2030            if(!!$this->settings->compression->webp || !!$this->settings->compression->avif) {
     
    4757                        version: "<?= esc_js(SHORTPIXEL_AI_VERSION) ?>",
    4858                        key: "<?= esc_js(end($apiUrlParts)) ?>",
     59                        customKeys: <?= wp_json_encode($customKeys) ?>,
    4960                        quality: "<?= esc_js($this->settings->compression->level) ?>",
    5061                        convert: "<?= esc_js($convert) ?>",
     
    91102                'noresize_selectors'    => $this->ctrl->splitSelectors( $this->settings->exclusions->noresize_selectors, ',' ),
    92103                'excluded_paths'        => array_map( 'base64_encode', $this->ctrl->splitSelectors( $this->settings->exclusions->excluded_paths, PHP_EOL ) ),
     104                'eager_paths'           => array_map( 'base64_encode', $this->ctrl->splitSelectors( $this->settings->exclusions->eager_paths, PHP_EOL ) ),
    93105            ]);
    94106            wp_enqueue_script( 'spai-snip-action'  );
     
    273285                ['lazy' => 0, 'cdn' => 0, 'resize' => 0, 'crop' => -1]);
    274286        }
     287
     288        foreach($this->ctrl->splitSelectors( $this->settings->exclusions->eager_paths, PHP_EOL) as $eagerPath) {
     289            $this->alterExclusion($exclusions, 'urls', $eagerPath, ['lazy' => 0]);
     290        }
     291
    275292        foreach($this->ctrl->splitSelectors( $this->settings->exclusions->excluded_selectors, ',') as $excludedSel) {
    276293            $this->alterExclusion($exclusions, 'selectors', $excludedSel,
  • shortpixel-adaptive-images/tags/3.11.0/includes/helpers/url-tools.class.php

    r3160580 r3340495  
    1717        'eot', 'woff', 'woff2', 'ttf', 'otf' ];
    1818    public static $ONLY_STORE = [ 'svg', 'js', 'eot', 'webp', 'avif', 'woff', 'woff2', 'ttf', 'otf' ];
     19    public static $EAGER_WAIT = [ 'css', 'js', 'woff2', 'woff', 'otf', 'ttf', 'eot' ];
    1920    private static $SIZE_CACHE = [];
    2021
  • shortpixel-adaptive-images/tags/3.11.0/includes/models/options.category.class.php

    r3125365 r3340495  
    1515        public function getData() {
    1616            return $this->__dyna;
     17        }
     18
     19        /**
     20         *  exports the internal data structure of the Category object
     21         *  - traverses  internal proteected __dyna object, and for each property,
     22         *  it checks if the value is another Category, Option, stdClass.
     23         * @return array  fully expanded data structure.
     24         */
     25        public function exportRecursive() {
     26            $result = [];
     27
     28            foreach ((array) $this->getData() as $key => $value) {
     29                if ($value instanceof \ShortPixel\AI\Options\Category) {
     30                    $result[$key] = $value->getData();
     31                } elseif ($value instanceof \ShortPixel\AI\Options\Option) {
     32                    $result[$key] = $value->getData();
     33                } elseif ($value instanceof \stdClass) {
     34                    $result[$key] = json_decode(json_encode($value), true);
     35                } else {
     36                    $result[$key] = $value;
     37                }
     38            }
     39            return $result;
    1740        }
    1841
  • shortpixel-adaptive-images/tags/3.11.0/includes/views/settings.tpl.php

    r3209129 r3340495  
    706706                                    </td>
    707707                                </tr>
     708
     709
     710                                <tr>
     711                                    <th scope="row">
     712                                        <?= __( 'Amazon S3', 'shortpixel-adaptive-images' ); ?>
     713                                    </th>
     714                                    <td>
     715                                        <div class="spai-inline-help">
     716                <span class="dashicons dashicons-editor-help"
     717                      title="Inline help"
     718                      data-link="https://shortpixel.com/knowledge-base/article/using-shortpixel-adaptive-images-with-images-on-amazon-s3/"></span>
     719                                        </div>
     720                                        <input
     721                                                id="amazon_s3"
     722                                                type="checkbox"
     723                                                name="amazon_s3"
     724                                                class="tgl"
     725                                                data-type="bool"
     726                                                value="1"
     727                                        <?php checked( 1, $options->settings_behaviour_amazonS3, true ); ?>
     728                                        />
     729
     730                                        <label for="amazon_s3" class="tgl-btn">
     731                                            <span></span>
     732                                            <?= __( 'Deliver the images stored on Amazon S3 using ShortPixel CDN', 'shortpixel-adaptive-images' ); ?>
     733                                        </label>
     734                                        <p class="description">
     735                                            <?= __( 'Enable this option if you are offloading the images to an Amazon S3 bucket and you want to deliver them via our CDN to reduce costs. Read the configuration guide in <a href="https://shortpixel.com/knowledge-base/article/using-shortpixel-adaptive-images-with-images-on-amazon-s3/" target="_blank">our knowledge base</a>', 'shortpixel-adaptive-images' ); ?>
     736                                        </p>
     737                                        <div class="amazon-s3-fields-wrapper">
     738                                            <p>
     739                                                <label for="storage_url" style="display: inline-block; width: 140px;">
     740                                                    <strong><?= __( 'Base URL', 'shortpixel-adaptive-images' ); ?></strong>
     741                                                </label>
     742                                                <input
     743                                                        id="storage_url"
     744                                                        type="text"
     745                                                        data-type="string"
     746                                                        name="storage_url"
     747                                                        size="40"
     748                                                        placeholder="<?= __( 'Paste Base URL from ShortPixel Dashboard', 'shortpixel-adaptive-images' ); ?>"
     749                                                        value="<?= esc_attr( $options->settings_behaviour_storageUrl ); ?>"
     750                                                    <?php disabled(!$options->settings_behaviour_amazonS3, true); ?>
     751                                                />
     752
     753
     754                                            </p>
     755                                            <p>
     756                                                <label for="host_removal" style="display: inline-block; width: 140px;">
     757                                                    <strong><?= __( 'S3 Bucket URL', 'shortpixel-adaptive-images' ); ?></strong>
     758                                                </label>
     759                                                <input
     760                                                        id="host_removal"
     761                                                        type="text"
     762                                                        data-type="string"
     763                                                        name="host_removal"
     764                                                        size="40"
     765                                                        placeholder="<?= __( 'Get it from your Amazon S3 bucket details', 'shortpixel-adaptive-images' ); ?>"
     766                                                        value="<?= esc_attr( $options->settings_behaviour_hostRemoval ); ?>"
     767                                                    <?php disabled(!$options->settings_behaviour_amazonS3, true); ?>
     768                                                />
     769                                            </p>
     770                                        </div>
     771                                        <script>
     772                                            jQuery(document).ready(function($){
     773                                                $('#amazon_s3').on('change', function() {
     774                                                    var isChecked = $(this).is(':checked');
     775                                                    $('#storage_url, #host_removal').prop('disabled', !isChecked);
     776                                                }).trigger('change');
     777                                            });
     778                                        </script>
     779                                    </td>
     780                                </tr>
     781
     782
    708783                                <tr>
    709784                                    <th scope="row">
     
    13661441                                $no_resize_selectors = $options->settings_exclusions_noresizeSelectors;
    13671442                                $excluded_selectors  = $options->settings_exclusions_excludedSelectors;
     1443                                $eager_paths         = $options->settings_exclusions_eagerPaths;
    13681444                                $excluded_paths      = $options->settings_exclusions_excludedPaths;
    13691445                                $excluded_pages      = $options->settings_exclusions_excludedPages;
     
    13731449                                    'no_resize_selectors' => $controller->splitSelectors( $no_resize_selectors, ',' ),
    13741450                                    'excluded_selectors'  => $controller->splitSelectors( $excluded_selectors, ',' ),
     1451                                    'eager_paths'         => $controller->splitSelectors( $eager_paths, PHP_EOL ),
    13751452                                    'excluded_paths'      => $controller->splitSelectors( $excluded_paths, PHP_EOL ),
    13761453                                ];
     
    13821459
    13831460                                $excluded_selectors_qty = count( $split_selectors[ 'eager_selectors' ] ) + count( $split_selectors[ 'no_resize_selectors' ] ) + count( $split_selectors[ 'excluded_selectors' ] );
    1384                                 $excluded_paths_qty     = count( $split_selectors[ 'excluded_paths' ] );
     1461                                $excluded_paths_qty     = count( $split_selectors[ 'excluded_paths' ] ) + count( $split_selectors[ 'eager_paths' ] );
    13851462                            ?>
    13861463                            <table class="form-table">
     
    14481525                                            <?= str_replace( '{{QTY}}', $excluded_paths_qty, __( 'You already have <span>{{QTY}}</span> URL exclusions active. Please keep the number of exclusion selectors low for best performance.', 'shortpixel-adaptive-images' ) ); ?>
    14491526                                        </p>
    1450                                         <div>
     1527
     1528                                        <div><label for="eager_paths"><?= __( 'Don\'t lazy-load Url\'s:', 'shortpixel-adaptive-images' ); ?></label><br>
     1529                                            <textarea
     1530                                                    id="eager_paths"
     1531                                                    name="eager_paths"
     1532                                                    rows="5"
     1533                                                    data-type="string"
     1534                                                    data-exclusion-type="urls"
     1535                                                    data-setting="exclusion"
     1536                                                    data-separator="<?= PHP_EOL; ?>"
     1537                                            ><?= $eager_paths; ?></textarea>
     1538                                        </div>
     1539                                        <div><label for="excluded_paths"><?= __( 'Leave out completely Url\'s:', 'shortpixel-adaptive-images' ); ?></label><br>
    14511540                                            <textarea
    14521541                                                id="excluded_paths"
  • shortpixel-adaptive-images/tags/3.11.0/readme.txt

    r3337681 r3340495  
    55Tested up to: 6.8
    66Requires PHP: 5.6.40
    7 Stable tag: 3.10.5
     7Stable tag: 3.11.0
    88License: GPLv2 or later
    99License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    249249
    250250== Changelog ==
     251
     252= 3.11.0 =
     253
     254🌩️ The S3 & Speed Boost Update
     255
     256Release Date: August 6, 2025
     257
     258✨ New Features
     259
     260* Amazon S3 Integration: Images stored on Amazon S3 can now be seamlessly served through the ShortPixel CDN — faster delivery, no matter where your files live.
     261* Lazy-Load Exclusions by URL: You can now exclude specific images from lazy-loading by their URL for greater control over your image loading strategy.
     262
     263⚙️ Improvements
     264
     265* Smarter LQIP Handling: Optimized the way Low-Quality Image Placeholders (LQIPs) are processed to boost performance on sites with lots of images.
     266
     267🛠️ Fixes
     268
     269* Settings Export Restored: Exporting your plugin settings now works reliably in all scenarios.
     270* LQIP Fixes: Addressed several minor issues to ensure LQIPs behave correctly across different setups.
     271* Security Enhancements: Added extra security checks to strengthen protection and prevent potential vulnerabilities.
     272
     273Update now to enjoy smarter performance, better control, and enhanced flexibility with your image delivery! 🚀
    251274
    252275= 3.10.5 =
     
    691714* Language: 18 new strings added, 51 updated, 0 fuzzed, and 12 obsoleted.
    692715
    693 = 2.3.3 =
    694 Release date: June 30th, 2021
    695 * Fix: issue with validating API key
    696 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    697 
    698 = 2.3.2 =
    699 Release date: June 29th, 2021
    700 * Temporarily deactivate AVIF pending codec bug fix (https://github.com/xiph/rav1e/issues/2757);
    701 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    702 
    703 = 2.3.1 =
    704 Release date: June 28th, 2021
    705 * New: Version the javascript in the file name in order to get around more stubborn caches;
    706 * Fix: do not parse AJAX responses to uploads;
    707 * Fix: nested element that has a different background - was taking the background of the parent element;
    708 * Fix: notice in logs sometimes when domain info from server;
    709 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    710 
    711 = 2.3.0 =
    712 Release date: June 17th, 2021
    713 * New: images (including the ones from CSS files) are now served automatically in the new AVIF format to supporting browsers;
    714 * New: moved the JS detection mechanism for WebP/AVIF support directly to the CDN level, so no JS is required anymore for this;
    715 * Language: 0 new strings added, 6 updated, 0 fuzzed, and 0 obsoleted.
    716 
    717 = 2.2.4 =
    718 Release date: June 14th, 2021
    719 * Compat: added a constant - `SPAI_ELEMENTOR_WORKAROUND` - to deactivate the parsing of Elementor modules that are resulting in critical errors;
    720 * Compat: workaround for WP Rocket that calls in certain circumstances the filter `rocket_css_content` with only one parameter;
    721 * Fix: some warnings when lqip queue is not array were showing up in some cases;
    722 * Fix: wrong array key when the no background calculation can't determine crop size and returns just width and height;
    723 * Fix: iPhone issues with parsing stylesheets while also improving page responsiveness while parsing them (async);
    724 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    725 
    726 = 2.2.3 =
    727 Release date: May 18th, 2021
    728 * New: also parse inside `<script type="text/template">` blocks;
    729 * Fix: the background crop resize wasn't working in several cases, which is now fixed;
    730 * Fix: update the notification text about the next generation images served by SPIO;
    731 * Fix: cases when a mutation has backgrounds from an existing CSS block are now properly handled;
    732 * Fix: the special crop feature now handles correctly the situations when the width parameter isn't the first one;
    733 * Fix: the inline background selector will handle situations with no space before the CSS class definition;
    734 * Fix: remove the default values for JS parameters in order to support IE11;
    735 * Fix: the images from `li` elements added with `data-thumb` are now replaced;
    736 * Fix: the URL exclusions are checked when replacing inside JS blocks too;
    737 * Language: 0 new strings added, 2 updated, 0 fuzzed, and 0 obsoleted.
    738 
    739 = 2.2.2 =
    740 Release date: April 29th, 2021
    741 * Fix: the minified version of the plugin CSS files was bigger than the not minified one;
    742 * Fix: find local file when URL contains a path element before wp-content, that is not present on disk;
    743 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    744 
    745 = 2.2.1 =
    746 Release date: April 26th, 2021
    747 * Compat: added integration with Real3D Flipbook;
    748 * Fix: there was a "Class not found" error in some cases when purging LiteSpeed cache from our plugin;
    749 * Fix: in some cases, the size of background images wasn't properly set;
    750 * Fix: protection added for very large number of product variations; the plugin will now work properly in these cases;
    751 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    752 
    753 = 2.2.0 =
    754 Release date: April 20th, 2021
    755 * New: added filter `shortpixel/ai/customRules` for custom replacement rules;
    756 * New: added proper lazy loading for background images;
    757 * New: take into account the `background-*` CSS styles: size, position, etc.;
    758 * New: lazy load the images in the CSS blocks;
    759 * New: handle correctly multiple URLs in the same `background-image:` declaration;
    760 * New: when running out of credits you can now have an option to top-up directly from the plugin settings;
    761 * Compat: added an integration with the Uncode theme and its iLightBox component;
    762 * Compat: added integration with WPC Variations Table;
    763 * Compat: added integration with Soliloquy Slider Plugin;
    764 * Compat: also integrate properly with Divi child themes;
    765 * Compat: improved the integration with Elementor, all images should now be properly replaced;
    766 * Fix: WooCommerce product variations were broken if srcset was present, but false;
    767 * Fix: in certain cases, background images with important CSS priority weren't properly handled;
    768 * Fix: also remove the sizes attribute if we remove the srcset;
    769 * Fix: replacement error when html attribute contains "<style>.." data;
    770 * Fix: various small fixes to settings, fonts, debug messages, ShortPixel account login and lazy loading;
    771 * Language: 7 new strings added, 2 updated, 0 fuzzed, and 3 obsoleted.
    772716
    773717= EARLIER VERSIONS =
  • shortpixel-adaptive-images/tags/3.11.0/short-pixel-ai.php

    r3337681 r3340495  
    44     * Plugin URI: https://shortpixel.com/
    55     * Description: Display properly sized, smart cropped and optimized images on your website. Images are processed on the fly and served from our CDN.
    6      * Version: 3.10.5
     6     * Version: 3.11.0
    77     * Author: ShortPixel
    88     * GitHub Plugin URI: https://github.com/short-pixel-optimizer/shortpixel-adaptive-images
     
    1616
    1717    if ( !class_exists( 'ShortPixelAI' ) ) {
    18         define( 'SHORTPIXEL_AI_VERSION', '3.10.5' );
     18        define( 'SHORTPIXEL_AI_VERSION', '3.11.0' );
    1919        define( 'SPAI_SNIP_VERSION', '3.1.0' );
    2020        define( 'SHORTPIXEL_AI_VANILLAJS_VER', '1.1' );
     
    103103            $old_error_handler = set_error_handler( [ 'ShortPixelAILogger', 'errorHandler' ] );
    104104        }
     105        function activatedTimeCollect(){
     106            update_option('shortpixel_ai_installed_time', time());
     107        }
    105108
    106109        register_activation_hook( __FILE__, [ 'ShortPixelAI', 'activate' ] );
     
    112115            ShortPixelAI::_();
    113116        } );
    114     }
     117
     118    }
  • shortpixel-adaptive-images/trunk/assets/css/admin.css

    r3209129 r3340495  
    381381}
    382382
    383 .blue_link {
     383.blue_link,
     384.survey-rating-btn, #survey-feedback-submit {
    384385    cursor             : pointer;
    385386    color              : #ffffff !important;
     
    402403}
    403404
    404 .dark_blue_link:hover, .blue_link:hover {
     405.dark_blue_link:hover,.blue_link:hover,
     406.survey-rating-btn:hover, #survey-feedback-submit {
    405407    color   : #ffffff !important;
    406408    border  : none !important;
    407     opacity : 0.9 !important;
     409    opacity : 0.7 !important;
    408410}
    409411
  • shortpixel-adaptive-images/trunk/assets/css/admin.min.css

    r3209129 r3340495  
    1 .shortpixel-settings-wrap input,.shortpixel-settings-wrap textarea,.shortpixel-settings-wrap button{outline:unset!important}.plugins tr[data-slug=shortpixel-adaptive-images] td div p span{display:block;margin:5px 0;padding-left:25px}.shortpixel-on-boarding-wrap{background:#fff}.shortpixel-on-boarding-wrap .socials-block{width:100%;max-width:1e3px;margin-top:10px}.socials-block,.socials-block *{-webkit-box-sizing:border-box;box-sizing:border-box}.socials-block{position:relative;padding:20px;border-radius:15px;font-weight:600;margin-bottom:10px;background:#dfffff}.socials-block>.message-wrap{width:100%;color:#05869f;padding-right:200px}.socials-block:before{content:'';position:absolute;display:block;width:20px;height:20px;top:-8px;left:20px;background:url(../img/socials/share.svg)50%/contain no-repeat}.socials-block>.buttons-wrap{position:absolute;display:block;top:calc(50% - 20px);right:20px}.socials-block [data-social]:before{content:'';position:absolute;width:16px;height:16px;top:calc(50% - 8px);left:7px}.socials-block [data-social]:last-child{margin-right:0}.socials-block [data-social]{position:relative;display:block;float:left;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;line-height:20px;margin-right:5px;border-radius:10px;padding:10px 10px 10px 30px;text-decoration:unset;outline:none;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.socials-block [data-social=twitter]{background:#d9e9f9;color:#2c76ec}.socials-block [data-social=twitter]:hover{-webkit-box-shadow:inset 1px 2px 2px rgba(44,118,236,.2);box-shadow:inset 1px 2px 2px rgba(44,118,236,.2)}.socials-block [data-social=twitter]:before{background:url(../img/socials/twitter.svg)50%/contain no-repeat}.socials-block [data-social=facebook]{background:#d9e6ff;color:#2152b3}.socials-block [data-social=facebook]:hover{-webkit-box-shadow:inset 1px 2px 2px rgba(33,82,179,.2);box-shadow:inset 1px 2px 2px rgba(33,82,179,.2)}.socials-block [data-social=facebook]:before{background:url(../img/socials/facebook.svg)50%/contain no-repeat}.sp-obw__title-wrap img{height:64px;width:64px;float:left;margin:10px 20px 10px 10px}.sp-obw__title-wrap{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.sp-obw__title-wrap:after{position:absolute;bottom:0;left:0;clear:both;width:100%;height:1px;background:#ccc;content:'';display:block}.sp-obw__content-wrap{padding:20px}.sp-obw__content-wrap p{font-size:14px}.sp-obw__content-wrap span.sp-obw-step{line-height:36px}.sp-obw__content-wrap span.sp-obw-alert{font-weight:600;color:crimson}.sp-obw__content-wrap .step-message-wrap label{vertical-align:top;margin-right:10px}.sp-obw__content-wrap .step-message-wrap p button{margin:0 10px 0 0}.sp-obw__content-wrap .step-message-wrap p button:last-child{margin:0}.sp-obw__content-wrap .step-message-wrap button:disabled{color:#a0a5aa!important;border-color:#ddd!important;background:#f7f7f7!important;-webkit-box-shadow:0 1px 1px rgba(171,170,170,.3)!important;box-shadow:0 1px 1px rgba(171,170,170,.3)!important}.bordered_link{cursor:pointer;color:#1fbec9;font-size:14px;line-height:18px;padding:5px 10px;display:inline-block;background:#f5f5f5!important;border:1px solid #1fbec9!important;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:0 1px 1px rgba(171,170,170,.3);box-shadow:0 1px 1px rgba(171,170,170,.3);border-radius:3px;text-decoration:none;margin-bottom:15px;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear}.bordered_link:hover{color:#0f6b7e!important;background:0 0!important}.shortpixel-steps{max-width:670px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding-bottom:24px;margin:30px 0;position:relative}.shortpixel-steps:before{position:absolute;content:'';height:2px;background:#ccc;width:100%;left:0;top:18px;z-index:1}.shortpixel-steps:after{position:absolute;content:'';height:2px;background:#ec2c25;width:100%;left:0;top:18px;z-index:2;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear}.shortpixel-steps[data-step="0"]:after{width:39px}.shortpixel-steps[data-step="1"]:after{width:calc(((100% - 58px)/3) + 39px)}.shortpixel-steps[data-step="2"]:after{width:calc(((100% - 58px) * 2/3) + 39px)}.shortpixel-steps[data-step="3"]:after{width:100%}.shortpixel-steps .step:nth-child(1){padding-left:20px}.shortpixel-steps .step .number{position:relative;font-weight:700;font-size:20px;color:#ccc;line-height:32px;height:34px;width:34px;text-align:center;border:2px solid #ccc;border-radius:50%;background:#fff;z-index:3}.shortpixel-steps .step.active .number,.shortpixel-steps .step.passed .number{color:#1fbec9;border:2px solid #ec2c25}.shortpixel-steps .step .title{position:absolute;color:#555d66;width:80px;text-align:center;opacity:.4;text-transform:uppercase;left:-24px;font-size:14px;bottom:-30px}.shortpixel-steps .step.active .number .title{opacity:1}.sp-obw__content-wrap .step-message-wrap .action-wrap [data-action]{margin-left:5px}div.spai-modal-shade{display:none;position:fixed;z-index:10;left:0;top:0;width:100%;height:100%;overflow:auto;background:#000;opacity:.4}div.spai-modal{background-color:#fefefe;padding:20px;border:1px solid #888;width:30%;min-width:300px;z-index:100001;position:fixed;top:10%;left:50%;max-height:90%;overflow-y:auto}div.spai-modal-title{font-size:22px}div.spai-modal-body{margin-top:10px}div.spai-modal button.spai-close-upgrade-button{float:right;margin-top:0;background:0 0!important;border:none;font-size:22px;line-height:10px;cursor:pointer}.dark_blue_link{cursor:pointer;color:#fff;height:30px;line-height:30px;padding:0 20px;background:#116c7d!important;display:inline-block;-webkit-box-shadow:0 1px 1px #09343d!important;box-shadow:0 1px 1px #09343d!important;border:none!important;border-radius:3px;text-decoration:none;margin-right:10px;position:relative;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;margin-bottom:15px;border:0;outline:none}.blue_link{cursor:pointer;color:#fff!important;height:30px;line-height:30px;padding:0 20px;background:#1fbec9!important;display:inline-block;-webkit-box-shadow:0 1px 1px #16858c;box-shadow:0 1px 1px #16858c;border-radius:3px;text-decoration:none;margin-right:10px;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;margin-bottom:15px;border:0!important;outline:none}.dark_blue_link:hover,.blue_link:hover{color:#fff!important;border:none!important;opacity:.9!important}.dark_blue_link:focus,.blue_link:focus,.dark_blue_link:active,.blue_link:active{color:#fff}.blue_link:disabled,.blue_link:disabled:hover,.dark_blue_link:disabled,.dark_blue_link:disabled:hover{cursor:not-allowed!important;opacity:1!important;color:#737373!important;background:#e2e2e2!important;-webkit-box-shadow:0 1px 1px #8a8a8a!important;box-shadow:0 1px 1px #8a8a8a!important}.bordered_link:disabled,.bordered_link:disabled:hover{cursor:not-allowed!important;opacity:1!important;color:#969696!important;background:#efefef!important;border-color:#ccc!important}.next_icon{padding-right:35px;position:relative}.next_icon:after{content:'';width:9px;height:11px;position:absolute;right:15px;top:10px;background:url(../img/next.svg)50%/cover no-repeat;-webkit-transition:all .2s linear;-o-transition:all .2s linear;transition:all .2s linear}.fast-forward_link{padding-right:40px;position:relative}.fast-forward_link:after{content:'';width:14px;height:13px;position:absolute;right:15px;top:9px;background:url(../img/fast-forward.svg)50%/contain no-repeat;-webkit-transition:all .2s linear;-o-transition:all .2s linear;transition:all .2s linear}.next_icon:hover:after,.fast-forward_link:hover:after{right:10px}@media(max-width:400px){.shortpixel-steps .step .title{text-transform:none}}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{background-position:50%;background-size:contain;background-repeat:no-repeat;background-image:url(../img/robo-happy.png)!important}.notice[data-plugin=short-pixel-ai]{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px}.notice[data-plugin=short-pixel-ai] .body-wrap{position:relative;padding-left:75px}.notice[data-plugin=short-pixel-ai] .body-wrap .message-wrap span{font-weight:600;color:crimson}.notice[data-plugin=short-pixel-ai][data-icon=none] .body-wrap{padding-left:0}.notice[data-plugin=short-pixel-ai][data-icon] .body-wrap:before{content:'';position:absolute;left:0;width:64px;height:100%;background-position:50%;background-size:contain;background-repeat:no-repeat}.notice[data-plugin=short-pixel-ai][data-icon=none] .body-wrap:before{content:none;position:unset;left:0;width:0;height:0;background:0 0}.notice[data-plugin=short-pixel-ai][data-icon=scared] .body-wrap:before{background-image:url(../img/robo-scared.png)}.notice[data-plugin=short-pixel-ai][data-icon=happy] .body-wrap:before{background-image:url(../img/robo-happy.png)}.notice[data-plugin=short-pixel-ai][data-icon=wink] .body-wrap:before{background-image:url(../img/robo-wink.png)}.notice[data-plugin=short-pixel-ai][data-icon=cool] .body-wrap:before{background-image:url(../img/robo-cool.png)}.notice[data-plugin=short-pixel-ai][data-icon=magnifier] .body-wrap:before{background-image:url(../img/robo-magnifier.png)}.notice[data-plugin=short-pixel-ai][data-icon=notes] .body-wrap:before{background-image:url(../img/robo-notes.png)}.notice[data-plugin=short-pixel-ai] .buttons-wrap{margin:10px 0}.notice[data-plugin=short-pixel-ai] .buttons-wrap .button{margin-right:5px}.dismissed-notice[data-plugin=short-pixel-ai] .buttons-wrap .button{margin:0 5px 5px 0}.notice[data-plugin=short-pixel-ai] .buttons-wrap .button:last-child{margin-right:0}div.spai-inline-help{float:right}div.spai-inline-help span{font-size:1.8em;color:#0bb5c1;cursor:pointer}div.spai-modal{background-color:#fefefe;padding:20px 16px 16px;border:1px solid #888;width:30%;max-width:610px;margin-left:-305px;min-width:300px;z-index:100;position:fixed;top:10%;left:50%;max-height:90%;overflow-y:auto}div.spai-modal-spinner{background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50%}.spai-loading{width:100%;min-height:200px;background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50% 0}@media(max-width:610px){div.spai-modal{width:100%;margin-left:-50%;padding:20px 0 16px}}div.spai-modal .spai-close-help-button{position:absolute;top:5px;right:0;margin-top:0;background:0 0;border:none;font-size:22px;line-height:10px;cursor:pointer}div.spai-modal-title{font-size:22px}.spai-hide{display:none}.spai_settings_tab{display:none;background:#fff;border-right:1px solid #e5e5e5;border-left:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;padding:30px 20px}.spai_settings_tab.active{display:block}.shortpixel-settings-tabs{width:calc(100% - 370px);float:left}.shortpixel-settings-tabs .nav-tab-wrapper{position:relative}.shortpixel-settings-tabs .nav-tab:focus{-webkit-box-shadow:none;box-shadow:none;outline:none}.shortpixel-settings-tabs .nav-tab-active{background:#fff;border-bottom:1px solid #fff}.shortpixel-settings-tabs .form-table td label{display:inline-block}.children-wrap{display:block;visibility:visible;opacity:1;max-height:1e4px;margin:5px 0 5px 40px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.children-wrap.hidden{visibility:hidden;opacity:0;max-height:0}.children-wrap.hidden label{display:none}.children-wrap .shortpixel_radio_btns{margin-bottom:0}.children-wrap .bordered_link{margin-bottom:0}.spai_top_actions{cursor:pointer;float:right;border:1px solid #1fbec9;border-bottom:none;margin-left:.5em;padding:5px 10px;font-size:14px;line-height:1.71428571;font-weight:600;background:#1fbec9;color:#fff;text-decoration:none;white-space:nowrap;outline:none}.spai_top_actions:hover{background:#0fa9b4}.clearcss-icon{background:url(../img/clearcss-white.svg)no-repeat;background-size:auto;display:inline-block;height:20px;width:24px;margin-top:4px}#clear_css_cache{margin-bottom:0;padding:2px 5px;height:35px}.shortpixel_radio_btns input{display:none}.shortpixel_radio_btns{-webkit-box-shadow:0 1px 1px #b6b2b2;box-shadow:0 1px 1px #b6b2b2;border-radius:3px;height:32px;display:inline-block;overflow:hidden;font-size:0;vertical-align:middle;margin-right:0;margin-bottom:20px}.shortpixel_radio_btns label{background:#ccc;text-transform:uppercase;display:inline-block;color:#fff;line-height:32px;padding:0 29px;border-left:1px solid #b4b4b4;border-right:1px solid #b4b4b4;font-size:14px;font-weight:700;margin:0 -1px;-webkit-transition:all .2s ease-in;-o-transition:all .2s ease-in;transition:all .2s ease-in}.shortpixel_radio_btns input:checked+label{background:#1fbec9;-webkit-box-shadow:0 0 3px #2a6c78;box-shadow:0 0 3px #2a6c78;border-left:1px solid #1fbec9;border-right:1px solid #1fbec9;position:relative}.shortpixel_radio_btns label:hover{background:#bbb}.shortpixel_radio_btns input:checked+label:hover{background:#0fa9b4}.shortpixel-settings-tabs input[type=text],.shortpixel-settings-tabs textarea{border:1px solid #ddd;border-radius:2px;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs input.error[type=text],.shortpixel-settings-tabs textarea.error,.shortpixel-settings-tabs input.error[type=text]:focus,.shortpixel-settings-tabs textarea.error:focus{border:1px solid crimson;-webkit-box-shadow:0 0 2px 1px rgba(220,20,60,.15),inset 0 0 2px 1px rgba(220,20,60,.15);box-shadow:0 0 2px 1px rgba(220,20,60,.15),inset 0 0 2px 1px rgba(220,20,60,.15)}.shortpixel-settings-tabs textarea{width:100%;max-width:100%;min-width:100%;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs input[type=checkbox]:focus,.shortpixel-settings-tabs input[type=color]:focus,.shortpixel-settings-tabs input[type=date]:focus,.shortpixel-settings-tabs input[type=datetime-local]:focus,.shortpixel-settings-tabs input[type=datetime]:focus,.shortpixel-settings-tabs input[type=email]:focus,.shortpixel-settings-tabs input[type=month]:focus,.shortpixel-settings-tabs input[type=number]:focus,.shortpixel-settings-tabs input[type=password]:focus,.shortpixel-settings-tabs input[type=radio]:focus,.shortpixel-settings-tabs input[type=search]:focus,.shortpixel-settings-tabs input[type=tel]:focus,.shortpixel-settings-tabs input[type=text]:focus,.shortpixel-settings-tabs input[type=time]:focus,.shortpixel-settings-tabs input[type=url]:focus,.shortpixel-settings-tabs input[type=week]:focus,.shortpixel-settings-tabs select:focus,.shortpixel-settings-tabs textarea:focus{border-color:#1fbec9;-webkit-box-shadow:0 0 2px 1px rgba(31,190,201,.15),inset 0 0 2px 1px rgba(31,190,201,.15);box-shadow:0 0 2px 1px rgba(31,190,201,.15),inset 0 0 2px 1px rgba(31,190,201,.15);outline:none;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs .exclusion-wrap{width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.shortpixel-settings-tabs .exclusion-wrap input{margin-right:10px}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content{position:relative;width:100%;padding:5px;margin-bottom:10px;min-height:100px;border:1px solid #ddd;border-radius:2px;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in;-webkit-box-sizing:border-box;box-sizing:border-box}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content *:not(.plus){z-index:1}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover{border:1px solid #aaa}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover .plus:before,.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover .plus:after{visibility:visible;opacity:1}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:before,.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:after{content:'';position:absolute;visibility:hidden;opacity:0;top:calc(50% - 1px);left:calc(50% - 10px);width:20px;height:2px;background:#ddd;-webkit-transition:opacity .15s ease-in;-o-transition:opacity .15s ease-in;transition:opacity .15s ease-in;z-index:0}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:after{top:calc(50% - 10px);left:calc(50% - 1px);width:2px;height:20px}.exclusion-wrap .exclusions-content>div[data-index]{position:relative;float:left;margin:2px;padding:5px 30px 5px 10px;background:#116c7d;color:#fff;border-radius:10px}.exclusion-wrap .exclusions-content span[data-action=delete]{cursor:pointer;position:absolute;top:calc(50% - 10px);right:5px;height:20px;width:20px;border-radius:50%;-moz-border-radius:50%;-webkit-border-radius:50%;background:#1fbec9}.exclusion-wrap .exclusions-content span[data-action=delete]:before,.exclusion-wrap .exclusions-content span[data-action=delete]:after{content:'';position:absolute;display:block;width:60%;height:2px;top:calc(50% - 1px);right:20%;background:#fff;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.exclusion-wrap .exclusions-content span[data-action=delete]:before{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:after{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:hover:before{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:hover:after{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.shortpixel-settings-tabs .exclusion-wrap textarea{display:none}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap select{min-width:90px;vertical-align:unset}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap button{min-width:100px;margin-right:0}.shortpixel-settings-tabs .exclusion-wrap[data-type=urls] .buttons-wrap input{width:calc(100% - 214px)}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap input{width:calc(100% - 111px)}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap .error-message{margin-bottom:10px}.support-and-preferences{display:block;margin:10px 0;font-size:16px}.support-and-preferences a{font-weight:400;margin-right:4px;font-size:18px;color:#176d84}.support-and-preferences a:last-child{margin-right:0}.spai_statusbox_wrap{border:1px solid #e5e5e5;width:350px;float:right;margin-left:20px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:43px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px}.spai_statusbox_wrap .title_wrap{background:#fff;position:relative;border-bottom:1px solid #e1e1e1;font-size:16px;padding:20px 60px 20px 20px}.spai_statusbox_wrap .title_wrap .usage_msg{padding:10px 10px 0 0;font-size:13px}.spai_statusbox_wrap .success{color:#1fbec9;font-weight:600}.spai_statusbox_wrap .error{color:#e53935;font-weight:600}.spai_statusbox_wrap .title_wrap:before{content:'';position:absolute;right:10px;top:calc(50% - 21px);width:42px;height:42px;background-size:contain;background-position:50%;background-repeat:no-repeat}.spai_statusbox_wrap .chart-wrap{position:relative;width:100%}.spai_statusbox_wrap .chart-wrap .toggle{content:'';cursor:pointer;position:absolute;top:0;right:0;width:20px;height:20px;background:url(../img/full-screen.svg)50%/80% no-repeat}.spai_statusbox_wrap .chart-wrap.expanded .toggle{top:20px;right:20px;background:url(../img/minimize.svg)50%/80% no-repeat}.spai_statusbox_wrap .chart-wrap.expanded{display:block;position:fixed;background:#fff;width:80%;max-width:1e3px;padding:20px;top:calc(50% - 250px);left:calc(10% - 20px);z-index:10000;border-radius:10px;-webkit-box-shadow:0 0 10px 3px rgba(0,0,0,.2);box-shadow:0 0 10px 3px rgba(0,0,0,.2)}.spai_statusbox_wrap .chart-wrap.expanded canvas#chart{max-height:500px}.spai_statusbox_wrap .box_content canvas#chart{display:block;height:1px;max-height:350px}.spai_statusbox_wrap .title_wrap[data-status=enough]:before{background-image:url(../img/robo-rtl-cool.png)}.spai_statusbox_wrap .title_wrap[data-status=few]:before{background-image:url(../img/robo-rtl-notes.png)}.spai_statusbox_wrap .title_wrap[data-status=insufficiently]:before{background-image:url(../img/robo-rtl-scared.png)}.spai_statusbox_wrap .box_content{padding:20px;background:#fff}.spai_statusbox_wrap .box_content .buttons-wrap{text-align:center}.spai_statusbox_wrap .login_btn{float:right;margin-top:-5px;margin-bottom:0}.btn_topup{color:#ed3833;float:right;margin-right:-40px;font-weight:700}.spai_statusbox_wrap img{max-width:100%}.spai_statusbox_wrap .full_width{width:calc(100% - 40px);text-align:center;margin:20px 0 0}.spai_statusbox_wrap .progress_wrap{margin-bottom:30px}.spai_statusbox_wrap .progress{height:5px;background:#1fbec9;position:relative;width:100%;clear:both}.spai_statusbox_wrap .progress_wrap .available{color:#1fbec9;float:right}.spai_statusbox_wrap .used{color:#ccc}.spai_statusbox_wrap .progress .used{height:5px;top:0;left:0;background:#ccc;position:absolute}.spai_statusbox_wrap .box_content .box_dropdown.first{margin:30px -20px -20px}.spai_statusbox_wrap .dismissed-notice-wrap{position:relative;border:1px dotted #116c7d;padding:10px;margin-bottom:10px}.spai_statusbox_wrap .dismissed-notice-wrap h4{padding-right:0;margin:5px 0;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in}.spai_statusbox_wrap .dismissed-notice-wrap:hover h4{padding-right:100px}.spai_statusbox_wrap .dismissed-notice-wrap:hover:before{visibility:visible;opacity:1;top:0}.spai_statusbox_wrap .dismissed-notice-wrap:before{content:attr(data-key);position:absolute;visibility:hidden;opacity:0;top:-10px;right:0;padding:5px;max-width:100px;color:#909090;background:#eee;text-align:center;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in}.spai_statusbox_wrap .dismissed-notice-wrap span{font-weight:600;color:crimson}.spai_statusbox_wrap .dismissed-notice-wrap .spai-modal span{color:#000}.shortpixel-offer-wso{width:100%;background-color:#dcfdff;display:flex;align-items:center;border:1px solid #ccc;margin-top:35px;margin-bottom:45px;position:relative}.shortpixel-offer-wso .red{color:red}.shortpixel-offer-wso span{text-align:center}.shortpixel-offer-wso .image{flex:1}.shortpixel-offer-wso .image img{width:45px;height:45px}.shortpixel-offer-wso .line{flex:3;padding:0 20px}.shortpixel-offer-wso .line h3{color:#00d0e5}.shortpixel-offer-wso .button-wrap{flex:2}.shortpixel-offer-wso .button-wrap .banner-button{background:red;padding:8px;font-weight:700;font-size:20px;margin:8px;color:#fff;text-transform:uppercase;height:auto;display:inline-block;text-decoration:none;white-space:nowrap;box-sizing:border-box;line-height:2.15384615;min-height:30px}.shortpixel-offer-wso .button-wrapper a{background-color:red;color:#fff;display:inline-block;padding:8px;text-decoration:none;font-weight:700;font-size:20px}.spai_statusbox_wrap .img-wrapper img{max-width:140px;max-height:140px}.box_dropdown{border-top:1px solid #e5e5e5;margin:20px -20px -20px}.box_dropdown .title{font-weight:600;font-size:16px;position:relative;padding:20px;cursor:pointer}.box_dropdown .title:before{content:"\f140";display:inline-block;font:20px/1 dashicons;position:absolute;right:15px}.box_dropdown.opened .title:before{content:"\f142"}.box_dropdown .dropdown_content{display:none;padding:10px 20px}.box_dropdown.opened .dropdown_content{display:block}.box_dropdown.spai_news .dropdown_content.loading{background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50% 0;min-height:200px}.shortpixel-settings-tabs input[type=submit]{padding:0 40px}.notification_popup{position:relative;background:rgba(0,0,0,2%);padding:15px 20px 20px;margin:20px 0 0;border:1px solid #1fbec9;border-radius:3px;-webkit-box-shadow:1px 1px 1px 0 rgba(31,190,201,.2);box-shadow:1px 1px 1px rgba(31,190,201,.2)}.notification_popup:before{background:#fafafa;border-left:1px solid #1fbec9;border-bottom:1px solid #1fbec9;width:14px;height:14px;display:block;position:absolute;top:-8px;left:22px;-webkit-transform:rotate(135deg);-ms-transform:rotate(135deg);transform:rotate(135deg);content:''}.notification_popup .text{margin:0 0 10px}.spai-modal .spai-modal-body{height:auto;min-height:400px;padding:0}.spai-modal.local{background-image:none}.spai-modal.local .spai-modal-body{min-height:auto}.deactivation-popup[data-type=wrapper],.deactivation-popup[data-type=wrapper] *{-webkit-box-sizing:border-box!important;box-sizing:border-box!important;-webkit-transition:all .2s ease-in-out!important;-o-transition:all .2s ease-in-out!important;transition:all .2s ease-in-out!important}.deactivation-popup[data-type=wrapper]{position:fixed;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;opacity:1;visibility:visible;width:100%;height:100%;top:0;left:0;background:rgba(0,0,0,.8);z-index:100000}.deactivation-popup[data-type=wrapper].hidden{opacity:0;visibility:hidden}.deactivation-popup[data-type=wrapper] .overlay{position:relative;padding:20px;background:#fff;overflow:auto;max-height:90%;max-width:90%;border-radius:10px;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.deactivation-popup[data-type=wrapper] .overlay::-webkit-scrollbar{width:6px}.deactivation-popup[data-type=wrapper] .overlay::-webkit-scrollbar-thumb{border-radius:3px;background:#00c0ce}.deactivation-popup[data-type=wrapper] .body{position:relative;display:block;max-width:360px;background:#fff;border-radius:10px}.deactivation-popup[data-type=wrapper].hidden .overlay{-webkit-transform:translateY(-20px);-ms-transform:translateY(-20px);transform:translateY(-20px)}.deactivation-popup[data-type=wrapper] .overlay .close{cursor:pointer;position:absolute;top:6px;right:6px;width:30px;height:30px;background:rgba(0,192,206,.3);border-radius:10px;z-index:1}.deactivation-popup[data-type=wrapper] .overlay .close:hover{-webkit-box-shadow:inset 1px 2px 3px rgba(14,77,88,.3);box-shadow:inset 1px 2px 3px rgba(14,77,88,.3)}.deactivation-popup[data-type=wrapper] .overlay .close:before{content:'';display:block;width:100%;height:100%;background:url(../img/close.svg)50%/40% no-repeat}.deactivation-popup[data-type=wrapper] .body .title-wrap{position:relative;display:block;font-size:18px;font-weight:600;text-align:center;padding:23px 20px 23px 70px}.deactivation-popup[data-type=wrapper] .body .title-wrap:before{content:'';position:absolute;top:0;left:0;display:block;width:64px;height:64px;background:url(../img/robo-happy.png)50%/contain no-repeat}.deactivation-popup[data-type=wrapper] .body button{float:right;margin:0}.deactivation-popup[data-type=wrapper] .body section{margin-bottom:15px}.deactivation-popup[data-type=wrapper] .body section:last-child{margin-bottom:0}.deactivation-popup[data-type=wrapper] .messages-wrap p{margin:5px 0}.deactivation-popup[data-type=wrapper] .body .options-wrap{padding:10px;border-radius:10px;background:#f3f3f3}.deactivation-popup[data-type=wrapper] .body .options-wrap *:not([type=radio]):not([type=checkbox]){width:100%}.deactivation-popup[data-type=wrapper] .body .options-wrap textarea{max-height:150px;min-height:50px}.deactivation-popup[data-type=wrapper] .options-wrap label{display:block;margin-bottom:5px}.deactivation-popup[data-type=wrapper] .options-wrap label:last-child{margin-bottom:0}.deactivation-popup[data-type=wrapper] .scroll-down{cursor:pointer;display:block;position:absolute;bottom:30px;left:calc(50% - 20px);width:40px;height:50px;background:rgba(178,236,240,.8);z-index:1;border-radius:10px;opacity:1;visibility:visible;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);-webkit-transition:all .4s ease-in-out!important;-o-transition:all .4s ease-in-out!important;transition:all .4s ease-in-out!important;-webkit-animation:1.3s knock-bottom-small 3s ease-in-out;animation:1.3s knock-bottom-small 3s ease-in-out}.deactivation-popup[data-type=wrapper] .scroll-down.hidden{opacity:0;visibility:hidden;-webkit-transform:translateY(-20px);-ms-transform:translateY(-20px);transform:translateY(-20px);-webkit-animation:unset;animation:unset}.deactivation-popup[data-type=wrapper] .scroll-down .mouse{position:absolute;width:26px;height:40px;top:calc(50% - 20px);left:calc(50% - 13px);border-radius:12px;border:2px solid #007cba}.deactivation-popup[data-type=wrapper] .scroll-down .wheel{position:absolute;top:5px;left:calc(50% - 5px);height:10px;width:10px;background:url(../img/down-arrow.svg)50%/contain no-repeat;border-radius:3px;-webkit-animation:wheel-scroll 2.2s infinite;animation:wheel-scroll 2.2s infinite}@-webkit-keyframes wheel-scroll{0%{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}20%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}40%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(18px);transform:translateY(18px)}}@keyframes wheel-scroll{0%{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}20%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}40%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(18px);transform:translateY(18px)}}div.shortpixel-settings-wrap .tgl{display:none}.tgl::-moz-selection,.tgl:after::-moz-selection,.tgl:before::-moz-selection,.tgl *::-moz-selection,.tgl *:after::-moz-selection,.tgl *:before::-moz-selection,.tgl+.tgl-btn::-moz-selection{background:0 0}.tgl::selection,.tgl:after::selection,.tgl:before::selection,.tgl *::selection,.tgl *:after::selection,.tgl *:before::selection,.tgl+.tgl-btn::selection{background:0 0}.tgl+.tgl-btn{line-height:28px}.tgl+.tgl-btn span{outline:0;display:block;width:35px;height:6px;position:relative;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin:10px 10px 0 0}.tgl+.tgl-btn span:after,.tgl+.tgl-btn span:before{position:relative;display:block;content:"";width:18px;height:18px}.tgl+.tgl-btn span:after{left:-3px}.tgl+.tgl-btn span:before{display:none}.tgl:checked+.tgl-btn span:after{left:calc(100% - 15px)}.tgl+.tgl-btn span{background:#e2e2e2;border-radius:14px;padding:2px;-webkit-transition:all .4s ease;-o-transition:all .4s ease;transition:all .4s ease;float:left;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.25);box-shadow:inset 0 1px 1px rgba(0,0,0,.25)}.tgl+.tgl-btn span:after{border-radius:14px;background:#ccc;-webkit-transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;-o-transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.31);box-shadow:0 1px 2px rgba(0,0,0,.31);top:-6px}.tgl:hover+.tgl-btn span:after{background:#bbb}.tgl+.tgl-btn span:hover:after{will-change:padding}.tgl+.tgl-btn span:active{-webkit-box-shadow:inset 0 0 0 2em #e8eae9;box-shadow:inset 0 0 0 2em #e8eae9}.tgl+.tgl-btn span:active:after{padding-right:.8em}.tgl:checked+.tgl-btn span{background:#92d4e2;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.25);box-shadow:inset 0 1px 1px rgba(0,0,0,.25)}.tgl:checked+.tgl-btn span:after{background:#1fbec9}.tgl:checked:hover+.tgl-btn span:after{background:#0fa9b4}.spai_top_actions .tgl:checked+.tgl-btn span:after{background:#72edf5}.tgl:checked+.tgl-btn span:active{-webkit-box-shadow:none;box-shadow:none}.tgl:checked+.tgl-btn span:active:after{margin-left:-.8em}.tgl:disabled+.tgl-btn span{background:#aaa}.tgl:disabled+.tgl-btn span:after{background:#909090}.tgl:checked:disabled+.tgl-btn span{background:#80bbc7}.tgl:checked:disabled+.tgl-btn span:after{background:#1a9ca5}.clearfix:after{content:''!important;display:block!important;clear:both!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu>.ab-item:before{content:' ';width:25px;height:25px;background-size:contain;background-repeat:no-repeat;background-position:0;background-image:url(../img/robo.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .ab-item{display:inline-block}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .ab-item:before{content:' ';width:25px;height:25px;background-size:contain;background-repeat:no-repeat;background-position:0;background-image:url(../img/robo.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache .ab-item:before{background-image:url(../img/clearcss.svg)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache .ab-item:before{background-image:url(../img/update.svg)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache .ab-item:before{background-image:url(../img/robo-blurry.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_processing .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_processing .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_processing .ab-item:before{background-image:url(../img/spinner2.gif)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_success .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_success .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_success .ab-item:before{background-image:none!important;content:'\2713';display:inline-block;color:green;width:25px;font-size:20px;padding:0 -6px 0 6px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_error .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_error .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_error .ab-item:before{background-image:none!important;content:'\203C';display:inline-block;color:red;padding:0 -6px 0 6px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .shortpixel-ai-sniper .ab-item:before{background-image:url(../img/robo-sniper.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai-settings .ab-item:before{background-image:none!important;font-family:dashicons;content:"\f108";color:#93d7e5;width:25px;font-size:25px}@media(max-width:1400px){.spai_statusbox_wrap{}.shortpixel-settings-tabs{width:calc(100% - 370px)}}@media(min-width:1200px){.spai_statusbox_wrap .chart-wrap.expanded{left:calc(50% - 520px)}}@media(max-width:1200px){.spai_settings_tab th,.spai_settings_tab td{display:block}.spai_settings_tab th{padding:20px 0 10px}.spai_settings_tab td{padding:5px 0}}@media(max-width:850px){.spai_statusbox_wrap{width:100%;margin-left:0}.spai_statusbox_wrap .chart-wrap .toggle{display:none}.shortpixel-settings-tabs{width:100%}.spai_statusbox_wrap .title_wrap:after{content:'';display:block;position:absolute;opacity:1;visibility:visible;width:12px;height:12px;bottom:6px;left:calc(50% - 6px);background:url(../img/expand-button.svg)50%/contain no-repeat;-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.spai_statusbox_wrap.expanded .title_wrap:after{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.spai_statusbox_wrap .box_content{display:none}.spai_statusbox_wrap .box_content.opened{position:relative;max-height:1e3px}}@media screen and (min-width:783px){#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{left:0;padding:0;width:24px;height:100%}}@media screen and (max-width:782px){#wpadminbar li#wp-admin-bar-shortpixel-ai-on-boarding{display:block;position:static}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{background-size:70%}#export_settings,#import_settings_form{display:none}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap select{margin-bottom:10px}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap input{width:100%;display:inline-block;margin-right:0;margin-bottom:10px}.shortpixel-settings-tabs .exclusion-wrap[data-type=urls] .buttons-wrap input{width:calc(100% - 10px)}.deactivation-popup[data-type=wrapper] .options-wrap label{margin-bottom:10px}}@media(min-width:851px) and (max-width:1268px){.spai_top_actions{margin:10px 10px 0 0}.spai_settings_tab{border-top:1px solid #e5e5e5}.nav-tab{border-bottom:1px solid #c3c4c7}.shortpixel-settings-tabs .nav-tab-active{border-bottom:1px solid #ccc}.shortpixel-settings-tabs .nav-tab-wrapper{padding-bottom:10px!important}}@media(max-width:600px){.spai_top_actions{margin:10px 10px 0 0}.spai_settings_tab{border-top:1px solid #e5e5e5}.shortpixel-settings-tabs .nav-tab-active{border-bottom:1px solid #ccc}.shortpixel-settings-tabs .nav-tab-wrapper{padding-bottom:10px!important}.socials-block .message-wrap{padding:0;margin-bottom:10px;text-align:center}.socials-block .buttons-wrap{position:unset;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;margin:0 auto}}@media(max-width:450px){.sp-obw__content-wrap .step-message-wrap .dark_blue_link,.sp-obw__content-wrap .step-message-wrap .blue_link,.sp-obw__content-wrap .step-message-wrap .bordered_link,.sp-obw__content-wrap .step-message-wrap .action-wrap input,.sp-obw__content-wrap .step-message-wrap .action-wrap [data-action]{width:100%;display:block;text-align:center;margin:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:inherit;font-size:inherit;font-weight:inherit}.shortpixel-on-boarding-wrap .socials-block{margin-top:30px}}@media(max-width:400px){.shortpixel_radio_btns{width:100%;display:table}.shortpixel_radio_btns label{display:table-cell;text-align:center;padding:0 5px}}@media(-webkit-min-device-pixel-ratio:2),(-o-min-device-pixel-ratio:2/1),(min-resolution:192dpi){#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item:before{background-image:url(../img/robo-happy@2x.png)!important}.spai_statusbox_wrap .title_wrap[data-status=enough]:before{background-image:url(../img/robo-rtl-cool@2x.png)}.spai_statusbox_wrap .title_wrap[data-status=few]:before{background-image:url(../img/robo-rtl-notes@2x.png)}.spai_statusbox_wrap .title_wrap[data-status=insufficiently]:before{background-image:url(../img/robo-rtl-scared@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=scared] .body-wrap:before{background-image:url(../img/robo-scared@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=happy] .body-wrap:before{background-image:url(../img/robo-happy@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=wink] .body-wrap:before{background-image:url(../img/robo-wink@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=cool] .body-wrap:before{background-image:url(../img/robo-cool@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=magnifier] .body-wrap:before{background-image:url(../img/robo-magnifier@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=notes] .body-wrap:before{background-image:url(../img/robo-notes@2x.png)}.deactivation-popup[data-type=wrapper] .body .title-wrap:before{background-image:url(../img/robo-happy@2x.png)}.shortpixel-ai-beacon:before{background-image:url(../img/notes@2x.png)}}@-webkit-keyframes knock-right-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateX(5px);transform:translateX(5px)}50%{-webkit-transform:translateX(3px);transform:translateX(3px)}65%{-webkit-transform:translateX(5px);transform:translateX(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes knock-right-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateX(5px);transform:translateX(5px)}50%{-webkit-transform:translateX(3px);transform:translateX(3px)}65%{-webkit-transform:translateX(5px);transform:translateX(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes knock-bottom-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateY(5px);transform:translateY(5px)}50%{-webkit-transform:translateY(3px);transform:translateY(3px)}65%{-webkit-transform:translateY(5px);transform:translateY(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes knock-bottom-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateY(5px);transform:translateY(5px)}50%{-webkit-transform:translateY(3px);transform:translateY(3px)}65%{-webkit-transform:translateY(5px);transform:translateY(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}
     1.shortpixel-settings-wrap input,.shortpixel-settings-wrap textarea,.shortpixel-settings-wrap button{outline:unset!important}.plugins tr[data-slug=shortpixel-adaptive-images] td div p span{display:block;margin:5px 0;padding-left:25px}.shortpixel-on-boarding-wrap{background:#fff}.shortpixel-on-boarding-wrap .socials-block{width:100%;max-width:1e3px;margin-top:10px}.socials-block,.socials-block *{-webkit-box-sizing:border-box;box-sizing:border-box}.socials-block{position:relative;padding:20px;border-radius:15px;font-weight:600;margin-bottom:10px;background:#dfffff}.socials-block>.message-wrap{width:100%;color:#05869f;padding-right:200px}.socials-block:before{content:'';position:absolute;display:block;width:20px;height:20px;top:-8px;left:20px;background:url(../img/socials/share.svg)50%/contain no-repeat}.socials-block>.buttons-wrap{position:absolute;display:block;top:calc(50% - 20px);right:20px}.socials-block [data-social]:before{content:'';position:absolute;width:16px;height:16px;top:calc(50% - 8px);left:7px}.socials-block [data-social]:last-child{margin-right:0}.socials-block [data-social]{position:relative;display:block;float:left;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;line-height:20px;margin-right:5px;border-radius:10px;padding:10px 10px 10px 30px;text-decoration:unset;outline:none;-webkit-box-shadow:none;box-shadow:none;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.socials-block [data-social=twitter]{background:#d9e9f9;color:#2c76ec}.socials-block [data-social=twitter]:hover{-webkit-box-shadow:inset 1px 2px 2px rgba(44,118,236,.2);box-shadow:inset 1px 2px 2px rgba(44,118,236,.2)}.socials-block [data-social=twitter]:before{background:url(../img/socials/twitter.svg)50%/contain no-repeat}.socials-block [data-social=facebook]{background:#d9e6ff;color:#2152b3}.socials-block [data-social=facebook]:hover{-webkit-box-shadow:inset 1px 2px 2px rgba(33,82,179,.2);box-shadow:inset 1px 2px 2px rgba(33,82,179,.2)}.socials-block [data-social=facebook]:before{background:url(../img/socials/facebook.svg)50%/contain no-repeat}.sp-obw__title-wrap img{height:64px;width:64px;float:left;margin:10px 20px 10px 10px}.sp-obw__title-wrap{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.sp-obw__title-wrap:after{position:absolute;bottom:0;left:0;clear:both;width:100%;height:1px;background:#ccc;content:'';display:block}.sp-obw__content-wrap{padding:20px}.sp-obw__content-wrap p{font-size:14px}.sp-obw__content-wrap span.sp-obw-step{line-height:36px}.sp-obw__content-wrap span.sp-obw-alert{font-weight:600;color:crimson}.sp-obw__content-wrap .step-message-wrap label{vertical-align:top;margin-right:10px}.sp-obw__content-wrap .step-message-wrap p button{margin:0 10px 0 0}.sp-obw__content-wrap .step-message-wrap p button:last-child{margin:0}.sp-obw__content-wrap .step-message-wrap button:disabled{color:#a0a5aa!important;border-color:#ddd!important;background:#f7f7f7!important;-webkit-box-shadow:0 1px 1px rgba(171,170,170,.3)!important;box-shadow:0 1px 1px rgba(171,170,170,.3)!important}.bordered_link{cursor:pointer;color:#1fbec9;font-size:14px;line-height:18px;padding:5px 10px;display:inline-block;background:#f5f5f5!important;border:1px solid #1fbec9!important;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-shadow:0 1px 1px rgba(171,170,170,.3);box-shadow:0 1px 1px rgba(171,170,170,.3);border-radius:3px;text-decoration:none;margin-bottom:15px;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear}.bordered_link:hover{color:#0f6b7e!important;background:0 0!important}.shortpixel-steps{max-width:670px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding-bottom:24px;margin:30px 0;position:relative}.shortpixel-steps:before{position:absolute;content:'';height:2px;background:#ccc;width:100%;left:0;top:18px;z-index:1}.shortpixel-steps:after{position:absolute;content:'';height:2px;background:#ec2c25;width:100%;left:0;top:18px;z-index:2;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear}.shortpixel-steps[data-step="0"]:after{width:39px}.shortpixel-steps[data-step="1"]:after{width:calc(((100% - 58px)/3) + 39px)}.shortpixel-steps[data-step="2"]:after{width:calc(((100% - 58px) * 2/3) + 39px)}.shortpixel-steps[data-step="3"]:after{width:100%}.shortpixel-steps .step:nth-child(1){padding-left:20px}.shortpixel-steps .step .number{position:relative;font-weight:700;font-size:20px;color:#ccc;line-height:32px;height:34px;width:34px;text-align:center;border:2px solid #ccc;border-radius:50%;background:#fff;z-index:3}.shortpixel-steps .step.active .number,.shortpixel-steps .step.passed .number{color:#1fbec9;border:2px solid #ec2c25}.shortpixel-steps .step .title{position:absolute;color:#555d66;width:80px;text-align:center;opacity:.4;text-transform:uppercase;left:-24px;font-size:14px;bottom:-30px}.shortpixel-steps .step.active .number .title{opacity:1}.sp-obw__content-wrap .step-message-wrap .action-wrap [data-action]{margin-left:5px}div.spai-modal-shade{display:none;position:fixed;z-index:10;left:0;top:0;width:100%;height:100%;overflow:auto;background:#000;opacity:.4}div.spai-modal{background-color:#fefefe;padding:20px;border:1px solid #888;width:30%;min-width:300px;z-index:100001;position:fixed;top:10%;left:50%;max-height:90%;overflow-y:auto}div.spai-modal-title{font-size:22px}div.spai-modal-body{margin-top:10px}div.spai-modal button.spai-close-upgrade-button{float:right;margin-top:0;background:0 0!important;border:none;font-size:22px;line-height:10px;cursor:pointer}.dark_blue_link{cursor:pointer;color:#fff;height:30px;line-height:30px;padding:0 20px;background:#116c7d!important;display:inline-block;-webkit-box-shadow:0 1px 1px #09343d!important;box-shadow:0 1px 1px #09343d!important;border:none!important;border-radius:3px;text-decoration:none;margin-right:10px;position:relative;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;margin-bottom:15px;border:0;outline:none}.blue_link,.survey-rating-btn,#survey-feedback-submit{cursor:pointer;color:#fff!important;height:30px;line-height:30px;padding:0 20px;background:#1fbec9!important;display:inline-block;-webkit-box-shadow:0 1px 1px #16858c;box-shadow:0 1px 1px #16858c;border-radius:3px;text-decoration:none;margin-right:10px;-webkit-transition:all .3s linear;-o-transition:all .3s linear;transition:all .3s linear;margin-bottom:15px;border:0!important;outline:none}.dark_blue_link:hover,.blue_link:hover,.survey-rating-btn:hover,#survey-feedback-submit{color:#fff!important;border:none!important;opacity:.7!important}.dark_blue_link:focus,.blue_link:focus,.dark_blue_link:active,.blue_link:active{color:#fff}.blue_link:disabled,.blue_link:disabled:hover,.dark_blue_link:disabled,.dark_blue_link:disabled:hover{cursor:not-allowed!important;opacity:1!important;color:#737373!important;background:#e2e2e2!important;-webkit-box-shadow:0 1px 1px #8a8a8a!important;box-shadow:0 1px 1px #8a8a8a!important}.bordered_link:disabled,.bordered_link:disabled:hover{cursor:not-allowed!important;opacity:1!important;color:#969696!important;background:#efefef!important;border-color:#ccc!important}.next_icon{padding-right:35px;position:relative}.next_icon:after{content:'';width:9px;height:11px;position:absolute;right:15px;top:10px;background:url(../img/next.svg)50%/cover no-repeat;-webkit-transition:all .2s linear;-o-transition:all .2s linear;transition:all .2s linear}.fast-forward_link{padding-right:40px;position:relative}.fast-forward_link:after{content:'';width:14px;height:13px;position:absolute;right:15px;top:9px;background:url(../img/fast-forward.svg)50%/contain no-repeat;-webkit-transition:all .2s linear;-o-transition:all .2s linear;transition:all .2s linear}.next_icon:hover:after,.fast-forward_link:hover:after{right:10px}@media(max-width:400px){.shortpixel-steps .step .title{text-transform:none}}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{background-position:50%;background-size:contain;background-repeat:no-repeat;background-image:url(../img/robo-happy.png)!important}.notice[data-plugin=short-pixel-ai]{border-radius:6px;-webkit-border-radius:6px;-moz-border-radius:6px}.notice[data-plugin=short-pixel-ai] .body-wrap{position:relative;padding-left:75px}.notice[data-plugin=short-pixel-ai] .body-wrap .message-wrap span{font-weight:600;color:crimson}.notice[data-plugin=short-pixel-ai][data-icon=none] .body-wrap{padding-left:0}.notice[data-plugin=short-pixel-ai][data-icon] .body-wrap:before{content:'';position:absolute;left:0;width:64px;height:100%;background-position:50%;background-size:contain;background-repeat:no-repeat}.notice[data-plugin=short-pixel-ai][data-icon=none] .body-wrap:before{content:none;position:unset;left:0;width:0;height:0;background:0 0}.notice[data-plugin=short-pixel-ai][data-icon=scared] .body-wrap:before{background-image:url(../img/robo-scared.png)}.notice[data-plugin=short-pixel-ai][data-icon=happy] .body-wrap:before{background-image:url(../img/robo-happy.png)}.notice[data-plugin=short-pixel-ai][data-icon=wink] .body-wrap:before{background-image:url(../img/robo-wink.png)}.notice[data-plugin=short-pixel-ai][data-icon=cool] .body-wrap:before{background-image:url(../img/robo-cool.png)}.notice[data-plugin=short-pixel-ai][data-icon=magnifier] .body-wrap:before{background-image:url(../img/robo-magnifier.png)}.notice[data-plugin=short-pixel-ai][data-icon=notes] .body-wrap:before{background-image:url(../img/robo-notes.png)}.notice[data-plugin=short-pixel-ai] .buttons-wrap{margin:10px 0}.notice[data-plugin=short-pixel-ai] .buttons-wrap .button{margin-right:5px}.dismissed-notice[data-plugin=short-pixel-ai] .buttons-wrap .button{margin:0 5px 5px 0}.notice[data-plugin=short-pixel-ai] .buttons-wrap .button:last-child{margin-right:0}div.spai-inline-help{float:right}div.spai-inline-help span{font-size:1.8em;color:#0bb5c1;cursor:pointer}div.spai-modal{background-color:#fefefe;padding:20px 16px 16px;border:1px solid #888;width:30%;max-width:610px;margin-left:-305px;min-width:300px;z-index:100;position:fixed;top:10%;left:50%;max-height:90%;overflow-y:auto}div.spai-modal-spinner{background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50%}.spai-loading{width:100%;min-height:200px;background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50% 0}@media(max-width:610px){div.spai-modal{width:100%;margin-left:-50%;padding:20px 0 16px}}div.spai-modal .spai-close-help-button{position:absolute;top:5px;right:0;margin-top:0;background:0 0;border:none;font-size:22px;line-height:10px;cursor:pointer}div.spai-modal-title{font-size:22px}.spai-hide{display:none}.spai_settings_tab{display:none;background:#fff;border-right:1px solid #e5e5e5;border-left:1px solid #e5e5e5;border-bottom:1px solid #e5e5e5;padding:30px 20px}.spai_settings_tab.active{display:block}.shortpixel-settings-tabs{width:calc(100% - 370px);float:left}.shortpixel-settings-tabs .nav-tab-wrapper{position:relative}.shortpixel-settings-tabs .nav-tab:focus{-webkit-box-shadow:none;box-shadow:none;outline:none}.shortpixel-settings-tabs .nav-tab-active{background:#fff;border-bottom:1px solid #fff}.shortpixel-settings-tabs .form-table td label{display:inline-block}.children-wrap{display:block;visibility:visible;opacity:1;max-height:1e4px;margin:5px 0 5px 40px;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.children-wrap.hidden{visibility:hidden;opacity:0;max-height:0}.children-wrap.hidden label{display:none}.children-wrap .shortpixel_radio_btns{margin-bottom:0}.children-wrap .bordered_link{margin-bottom:0}.spai_top_actions{cursor:pointer;float:right;border:1px solid #1fbec9;border-bottom:none;margin-left:.5em;padding:5px 10px;font-size:14px;line-height:1.71428571;font-weight:600;background:#1fbec9;color:#fff;text-decoration:none;white-space:nowrap;outline:none}.spai_top_actions:hover{background:#0fa9b4}.clearcss-icon{background:url(../img/clearcss-white.svg)no-repeat;background-size:auto;display:inline-block;height:20px;width:24px;margin-top:4px}#clear_css_cache{margin-bottom:0;padding:2px 5px;height:35px}.shortpixel_radio_btns input{display:none}.shortpixel_radio_btns{-webkit-box-shadow:0 1px 1px #b6b2b2;box-shadow:0 1px 1px #b6b2b2;border-radius:3px;height:32px;display:inline-block;overflow:hidden;font-size:0;vertical-align:middle;margin-right:0;margin-bottom:20px}.shortpixel_radio_btns label{background:#ccc;text-transform:uppercase;display:inline-block;color:#fff;line-height:32px;padding:0 29px;border-left:1px solid #b4b4b4;border-right:1px solid #b4b4b4;font-size:14px;font-weight:700;margin:0 -1px;-webkit-transition:all .2s ease-in;-o-transition:all .2s ease-in;transition:all .2s ease-in}.shortpixel_radio_btns input:checked+label{background:#1fbec9;-webkit-box-shadow:0 0 3px #2a6c78;box-shadow:0 0 3px #2a6c78;border-left:1px solid #1fbec9;border-right:1px solid #1fbec9;position:relative}.shortpixel_radio_btns label:hover{background:#bbb}.shortpixel_radio_btns input:checked+label:hover{background:#0fa9b4}.shortpixel-settings-tabs input[type=text],.shortpixel-settings-tabs textarea{border:1px solid #ddd;border-radius:2px;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs input.error[type=text],.shortpixel-settings-tabs textarea.error,.shortpixel-settings-tabs input.error[type=text]:focus,.shortpixel-settings-tabs textarea.error:focus{border:1px solid crimson;-webkit-box-shadow:0 0 2px 1px rgba(220,20,60,.15),inset 0 0 2px 1px rgba(220,20,60,.15);box-shadow:0 0 2px 1px rgba(220,20,60,.15),inset 0 0 2px 1px rgba(220,20,60,.15)}.shortpixel-settings-tabs textarea{width:100%;max-width:100%;min-width:100%;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs input[type=checkbox]:focus,.shortpixel-settings-tabs input[type=color]:focus,.shortpixel-settings-tabs input[type=date]:focus,.shortpixel-settings-tabs input[type=datetime-local]:focus,.shortpixel-settings-tabs input[type=datetime]:focus,.shortpixel-settings-tabs input[type=email]:focus,.shortpixel-settings-tabs input[type=month]:focus,.shortpixel-settings-tabs input[type=number]:focus,.shortpixel-settings-tabs input[type=password]:focus,.shortpixel-settings-tabs input[type=radio]:focus,.shortpixel-settings-tabs input[type=search]:focus,.shortpixel-settings-tabs input[type=tel]:focus,.shortpixel-settings-tabs input[type=text]:focus,.shortpixel-settings-tabs input[type=time]:focus,.shortpixel-settings-tabs input[type=url]:focus,.shortpixel-settings-tabs input[type=week]:focus,.shortpixel-settings-tabs select:focus,.shortpixel-settings-tabs textarea:focus{border-color:#1fbec9;-webkit-box-shadow:0 0 2px 1px rgba(31,190,201,.15),inset 0 0 2px 1px rgba(31,190,201,.15);box-shadow:0 0 2px 1px rgba(31,190,201,.15),inset 0 0 2px 1px rgba(31,190,201,.15);outline:none;-webkit-transition:all .15s ease-in-out;-o-transition:all .15s ease-in-out;transition:all .15s ease-in-out}.shortpixel-settings-tabs .exclusion-wrap{width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.shortpixel-settings-tabs .exclusion-wrap input{margin-right:10px}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content{position:relative;width:100%;padding:5px;margin-bottom:10px;min-height:100px;border:1px solid #ddd;border-radius:2px;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in;-webkit-box-sizing:border-box;box-sizing:border-box}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content *:not(.plus){z-index:1}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover{border:1px solid #aaa}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover .plus:before,.shortpixel-settings-tabs .exclusion-wrap .exclusions-content:hover .plus:after{visibility:visible;opacity:1}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:before,.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:after{content:'';position:absolute;visibility:hidden;opacity:0;top:calc(50% - 1px);left:calc(50% - 10px);width:20px;height:2px;background:#ddd;-webkit-transition:opacity .15s ease-in;-o-transition:opacity .15s ease-in;transition:opacity .15s ease-in;z-index:0}.shortpixel-settings-tabs .exclusion-wrap .exclusions-content .plus:after{top:calc(50% - 10px);left:calc(50% - 1px);width:2px;height:20px}.exclusion-wrap .exclusions-content>div[data-index]{position:relative;float:left;margin:2px;padding:5px 30px 5px 10px;background:#116c7d;color:#fff;border-radius:10px}.exclusion-wrap .exclusions-content span[data-action=delete]{cursor:pointer;position:absolute;top:calc(50% - 10px);right:5px;height:20px;width:20px;border-radius:50%;-moz-border-radius:50%;-webkit-border-radius:50%;background:#1fbec9}.exclusion-wrap .exclusions-content span[data-action=delete]:before,.exclusion-wrap .exclusions-content span[data-action=delete]:after{content:'';position:absolute;display:block;width:60%;height:2px;top:calc(50% - 1px);right:20%;background:#fff;-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.exclusion-wrap .exclusions-content span[data-action=delete]:before{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:after{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:hover:before{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.exclusion-wrap .exclusions-content span[data-action=delete]:hover:after{-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.shortpixel-settings-tabs .exclusion-wrap textarea{display:none}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap select{min-width:90px;vertical-align:unset}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap button{min-width:100px;margin-right:0}.shortpixel-settings-tabs .exclusion-wrap[data-type=urls] .buttons-wrap input{width:calc(100% - 214px)}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap input{width:calc(100% - 111px)}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap .error-message{margin-bottom:10px}.support-and-preferences{display:block;margin:10px 0;font-size:16px}.support-and-preferences a{font-weight:400;margin-right:4px;font-size:18px;color:#176d84}.support-and-preferences a:last-child{margin-right:0}.spai_statusbox_wrap{border:1px solid #e5e5e5;width:350px;float:right;margin-left:20px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:43px;border-radius:3px;-webkit-border-radius:3px;-moz-border-radius:3px}.spai_statusbox_wrap .title_wrap{background:#fff;position:relative;border-bottom:1px solid #e1e1e1;font-size:16px;padding:20px 60px 20px 20px}.spai_statusbox_wrap .title_wrap .usage_msg{padding:10px 10px 0 0;font-size:13px}.spai_statusbox_wrap .success{color:#1fbec9;font-weight:600}.spai_statusbox_wrap .error{color:#e53935;font-weight:600}.spai_statusbox_wrap .title_wrap:before{content:'';position:absolute;right:10px;top:calc(50% - 21px);width:42px;height:42px;background-size:contain;background-position:50%;background-repeat:no-repeat}.spai_statusbox_wrap .chart-wrap{position:relative;width:100%}.spai_statusbox_wrap .chart-wrap .toggle{content:'';cursor:pointer;position:absolute;top:0;right:0;width:20px;height:20px;background:url(../img/full-screen.svg)50%/80% no-repeat}.spai_statusbox_wrap .chart-wrap.expanded .toggle{top:20px;right:20px;background:url(../img/minimize.svg)50%/80% no-repeat}.spai_statusbox_wrap .chart-wrap.expanded{display:block;position:fixed;background:#fff;width:80%;max-width:1e3px;padding:20px;top:calc(50% - 250px);left:calc(10% - 20px);z-index:10000;border-radius:10px;-webkit-box-shadow:0 0 10px 3px rgba(0,0,0,.2);box-shadow:0 0 10px 3px rgba(0,0,0,.2)}.spai_statusbox_wrap .chart-wrap.expanded canvas#chart{max-height:500px}.spai_statusbox_wrap .box_content canvas#chart{display:block;height:1px;max-height:350px}.spai_statusbox_wrap .title_wrap[data-status=enough]:before{background-image:url(../img/robo-rtl-cool.png)}.spai_statusbox_wrap .title_wrap[data-status=few]:before{background-image:url(../img/robo-rtl-notes.png)}.spai_statusbox_wrap .title_wrap[data-status=insufficiently]:before{background-image:url(../img/robo-rtl-scared.png)}.spai_statusbox_wrap .box_content{padding:20px;background:#fff}.spai_statusbox_wrap .box_content .buttons-wrap{text-align:center}.spai_statusbox_wrap .login_btn{float:right;margin-top:-5px;margin-bottom:0}.btn_topup{color:#ed3833;float:right;margin-right:-40px;font-weight:700}.spai_statusbox_wrap img{max-width:100%}.spai_statusbox_wrap .full_width{width:calc(100% - 40px);text-align:center;margin:20px 0 0}.spai_statusbox_wrap .progress_wrap{margin-bottom:30px}.spai_statusbox_wrap .progress{height:5px;background:#1fbec9;position:relative;width:100%;clear:both}.spai_statusbox_wrap .progress_wrap .available{color:#1fbec9;float:right}.spai_statusbox_wrap .used{color:#ccc}.spai_statusbox_wrap .progress .used{height:5px;top:0;left:0;background:#ccc;position:absolute}.spai_statusbox_wrap .box_content .box_dropdown.first{margin:30px -20px -20px}.spai_statusbox_wrap .dismissed-notice-wrap{position:relative;border:1px dotted #116c7d;padding:10px;margin-bottom:10px}.spai_statusbox_wrap .dismissed-notice-wrap h4{padding-right:0;margin:5px 0;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in}.spai_statusbox_wrap .dismissed-notice-wrap:hover h4{padding-right:100px}.spai_statusbox_wrap .dismissed-notice-wrap:hover:before{visibility:visible;opacity:1;top:0}.spai_statusbox_wrap .dismissed-notice-wrap:before{content:attr(data-key);position:absolute;visibility:hidden;opacity:0;top:-10px;right:0;padding:5px;max-width:100px;color:#909090;background:#eee;text-align:center;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;-webkit-transition:all .15s ease-in;-o-transition:all .15s ease-in;transition:all .15s ease-in}.spai_statusbox_wrap .dismissed-notice-wrap span{font-weight:600;color:crimson}.spai_statusbox_wrap .dismissed-notice-wrap .spai-modal span{color:#000}.shortpixel-offer-wso{width:100%;background-color:#dcfdff;display:flex;align-items:center;border:1px solid #ccc;margin-top:35px;margin-bottom:45px;position:relative}.shortpixel-offer-wso .red{color:red}.shortpixel-offer-wso span{text-align:center}.shortpixel-offer-wso .image{flex:1}.shortpixel-offer-wso .image img{width:45px;height:45px}.shortpixel-offer-wso .line{flex:3;padding:0 20px}.shortpixel-offer-wso .line h3{color:#00d0e5}.shortpixel-offer-wso .button-wrap{flex:2}.shortpixel-offer-wso .button-wrap .banner-button{background:red;padding:8px;font-weight:700;font-size:20px;margin:8px;color:#fff;text-transform:uppercase;height:auto;display:inline-block;text-decoration:none;white-space:nowrap;box-sizing:border-box;line-height:2.15384615;min-height:30px}.shortpixel-offer-wso .button-wrapper a{background-color:red;color:#fff;display:inline-block;padding:8px;text-decoration:none;font-weight:700;font-size:20px}.spai_statusbox_wrap .img-wrapper img{max-width:140px;max-height:140px}.box_dropdown{border-top:1px solid #e5e5e5;margin:20px -20px -20px}.box_dropdown .title{font-weight:600;font-size:16px;position:relative;padding:20px;cursor:pointer}.box_dropdown .title:before{content:"\f140";display:inline-block;font:20px/1 dashicons;position:absolute;right:15px}.box_dropdown.opened .title:before{content:"\f142"}.box_dropdown .dropdown_content{display:none;padding:10px 20px}.box_dropdown.opened .dropdown_content{display:block}.box_dropdown.spai_news .dropdown_content.loading{background-image:url(../img/spinner2.gif);background-repeat:no-repeat;background-position:50% 0;min-height:200px}.shortpixel-settings-tabs input[type=submit]{padding:0 40px}.notification_popup{position:relative;background:rgba(0,0,0,2%);padding:15px 20px 20px;margin:20px 0 0;border:1px solid #1fbec9;border-radius:3px;-webkit-box-shadow:1px 1px 1px 0 rgba(31,190,201,.2);box-shadow:1px 1px 1px rgba(31,190,201,.2)}.notification_popup:before{background:#fafafa;border-left:1px solid #1fbec9;border-bottom:1px solid #1fbec9;width:14px;height:14px;display:block;position:absolute;top:-8px;left:22px;-webkit-transform:rotate(135deg);-ms-transform:rotate(135deg);transform:rotate(135deg);content:''}.notification_popup .text{margin:0 0 10px}.spai-modal .spai-modal-body{height:auto;min-height:400px;padding:0}.spai-modal.local{background-image:none}.spai-modal.local .spai-modal-body{min-height:auto}.deactivation-popup[data-type=wrapper],.deactivation-popup[data-type=wrapper] *{-webkit-box-sizing:border-box!important;box-sizing:border-box!important;-webkit-transition:all .2s ease-in-out!important;-o-transition:all .2s ease-in-out!important;transition:all .2s ease-in-out!important}.deactivation-popup[data-type=wrapper]{position:fixed;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;opacity:1;visibility:visible;width:100%;height:100%;top:0;left:0;background:rgba(0,0,0,.8);z-index:100000}.deactivation-popup[data-type=wrapper].hidden{opacity:0;visibility:hidden}.deactivation-popup[data-type=wrapper] .overlay{position:relative;padding:20px;background:#fff;overflow:auto;max-height:90%;max-width:90%;border-radius:10px;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}.deactivation-popup[data-type=wrapper] .overlay::-webkit-scrollbar{width:6px}.deactivation-popup[data-type=wrapper] .overlay::-webkit-scrollbar-thumb{border-radius:3px;background:#00c0ce}.deactivation-popup[data-type=wrapper] .body{position:relative;display:block;max-width:360px;background:#fff;border-radius:10px}.deactivation-popup[data-type=wrapper].hidden .overlay{-webkit-transform:translateY(-20px);-ms-transform:translateY(-20px);transform:translateY(-20px)}.deactivation-popup[data-type=wrapper] .overlay .close{cursor:pointer;position:absolute;top:6px;right:6px;width:30px;height:30px;background:rgba(0,192,206,.3);border-radius:10px;z-index:1}.deactivation-popup[data-type=wrapper] .overlay .close:hover{-webkit-box-shadow:inset 1px 2px 3px rgba(14,77,88,.3);box-shadow:inset 1px 2px 3px rgba(14,77,88,.3)}.deactivation-popup[data-type=wrapper] .overlay .close:before{content:'';display:block;width:100%;height:100%;background:url(../img/close.svg)50%/40% no-repeat}.deactivation-popup[data-type=wrapper] .body .title-wrap{position:relative;display:block;font-size:18px;font-weight:600;text-align:center;padding:23px 20px 23px 70px}.deactivation-popup[data-type=wrapper] .body .title-wrap:before{content:'';position:absolute;top:0;left:0;display:block;width:64px;height:64px;background:url(../img/robo-happy.png)50%/contain no-repeat}.deactivation-popup[data-type=wrapper] .body button{float:right;margin:0}.deactivation-popup[data-type=wrapper] .body section{margin-bottom:15px}.deactivation-popup[data-type=wrapper] .body section:last-child{margin-bottom:0}.deactivation-popup[data-type=wrapper] .messages-wrap p{margin:5px 0}.deactivation-popup[data-type=wrapper] .body .options-wrap{padding:10px;border-radius:10px;background:#f3f3f3}.deactivation-popup[data-type=wrapper] .body .options-wrap *:not([type=radio]):not([type=checkbox]){width:100%}.deactivation-popup[data-type=wrapper] .body .options-wrap textarea{max-height:150px;min-height:50px}.deactivation-popup[data-type=wrapper] .options-wrap label{display:block;margin-bottom:5px}.deactivation-popup[data-type=wrapper] .options-wrap label:last-child{margin-bottom:0}.deactivation-popup[data-type=wrapper] .scroll-down{cursor:pointer;display:block;position:absolute;bottom:30px;left:calc(50% - 20px);width:40px;height:50px;background:rgba(178,236,240,.8);z-index:1;border-radius:10px;opacity:1;visibility:visible;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0);-webkit-transition:all .4s ease-in-out!important;-o-transition:all .4s ease-in-out!important;transition:all .4s ease-in-out!important;-webkit-animation:1.3s knock-bottom-small 3s ease-in-out;animation:1.3s knock-bottom-small 3s ease-in-out}.deactivation-popup[data-type=wrapper] .scroll-down.hidden{opacity:0;visibility:hidden;-webkit-transform:translateY(-20px);-ms-transform:translateY(-20px);transform:translateY(-20px);-webkit-animation:unset;animation:unset}.deactivation-popup[data-type=wrapper] .scroll-down .mouse{position:absolute;width:26px;height:40px;top:calc(50% - 20px);left:calc(50% - 13px);border-radius:12px;border:2px solid #007cba}.deactivation-popup[data-type=wrapper] .scroll-down .wheel{position:absolute;top:5px;left:calc(50% - 5px);height:10px;width:10px;background:url(../img/down-arrow.svg)50%/contain no-repeat;border-radius:3px;-webkit-animation:wheel-scroll 2.2s infinite;animation:wheel-scroll 2.2s infinite}@-webkit-keyframes wheel-scroll{0%{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}20%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}40%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(18px);transform:translateY(18px)}}@keyframes wheel-scroll{0%{opacity:0;-webkit-transform:translateY(0);transform:translateY(0)}20%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}40%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}100%{opacity:0;-webkit-transform:translateY(18px);transform:translateY(18px)}}div.shortpixel-settings-wrap .tgl{display:none}.tgl::-moz-selection,.tgl:after::-moz-selection,.tgl:before::-moz-selection,.tgl *::-moz-selection,.tgl *:after::-moz-selection,.tgl *:before::-moz-selection,.tgl+.tgl-btn::-moz-selection{background:0 0}.tgl::selection,.tgl:after::selection,.tgl:before::selection,.tgl *::selection,.tgl *:after::selection,.tgl *:before::selection,.tgl+.tgl-btn::selection{background:0 0}.tgl+.tgl-btn{line-height:28px}.tgl+.tgl-btn span{outline:0;display:block;width:35px;height:6px;position:relative;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;margin:10px 10px 0 0}.tgl+.tgl-btn span:after,.tgl+.tgl-btn span:before{position:relative;display:block;content:"";width:18px;height:18px}.tgl+.tgl-btn span:after{left:-3px}.tgl+.tgl-btn span:before{display:none}.tgl:checked+.tgl-btn span:after{left:calc(100% - 15px)}.tgl+.tgl-btn span{background:#e2e2e2;border-radius:14px;padding:2px;-webkit-transition:all .4s ease;-o-transition:all .4s ease;transition:all .4s ease;float:left;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.25);box-shadow:inset 0 1px 1px rgba(0,0,0,.25)}.tgl+.tgl-btn span:after{border-radius:14px;background:#ccc;-webkit-transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;-o-transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;transition:left .3s cubic-bezier(.175,.885,.32,1.275),padding .3s ease,margin .3s ease;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.31);box-shadow:0 1px 2px rgba(0,0,0,.31);top:-6px}.tgl:hover+.tgl-btn span:after{background:#bbb}.tgl+.tgl-btn span:hover:after{will-change:padding}.tgl+.tgl-btn span:active{-webkit-box-shadow:inset 0 0 0 2em #e8eae9;box-shadow:inset 0 0 0 2em #e8eae9}.tgl+.tgl-btn span:active:after{padding-right:.8em}.tgl:checked+.tgl-btn span{background:#92d4e2;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.25);box-shadow:inset 0 1px 1px rgba(0,0,0,.25)}.tgl:checked+.tgl-btn span:after{background:#1fbec9}.tgl:checked:hover+.tgl-btn span:after{background:#0fa9b4}.spai_top_actions .tgl:checked+.tgl-btn span:after{background:#72edf5}.tgl:checked+.tgl-btn span:active{-webkit-box-shadow:none;box-shadow:none}.tgl:checked+.tgl-btn span:active:after{margin-left:-.8em}.tgl:disabled+.tgl-btn span{background:#aaa}.tgl:disabled+.tgl-btn span:after{background:#909090}.tgl:checked:disabled+.tgl-btn span{background:#80bbc7}.tgl:checked:disabled+.tgl-btn span:after{background:#1a9ca5}.clearfix:after{content:''!important;display:block!important;clear:both!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu>.ab-item:before{content:' ';width:25px;height:25px;background-size:contain;background-repeat:no-repeat;background-position:0;background-image:url(../img/robo.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .ab-item{display:inline-block}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .ab-item:before{content:' ';width:25px;height:25px;background-size:contain;background-repeat:no-repeat;background-position:0;background-image:url(../img/robo.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache .ab-item:before{background-image:url(../img/clearcss.svg)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache .ab-item:before{background-image:url(../img/update.svg)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache .ab-item:before{background-image:url(../img/robo-blurry.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_processing .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_processing .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_processing .ab-item:before{background-image:url(../img/spinner2.gif)!important;height:20px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_success .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_success .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_success .ab-item:before{background-image:none!important;content:'\2713';display:inline-block;color:green;width:25px;font-size:20px;padding:0 -6px 0 6px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_css_cache.shortpixel_ai_error .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_purge_cdn_cache.shortpixel_ai_error .ab-item:before,#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai_clear_lqip_cache.shortpixel_ai_error .ab-item:before{background-image:none!important;content:'\203C';display:inline-block;color:red;padding:0 -6px 0 6px}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .shortpixel-ai-sniper .ab-item:before{background-image:url(../img/robo-sniper.png)!important}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel_ai_topmenu .ab-submenu .spai-settings .ab-item:before{background-image:none!important;font-family:dashicons;content:"\f108";color:#93d7e5;width:25px;font-size:25px}@media(max-width:1400px){.spai_statusbox_wrap{}.shortpixel-settings-tabs{width:calc(100% - 370px)}}@media(min-width:1200px){.spai_statusbox_wrap .chart-wrap.expanded{left:calc(50% - 520px)}}@media(max-width:1200px){.spai_settings_tab th,.spai_settings_tab td{display:block}.spai_settings_tab th{padding:20px 0 10px}.spai_settings_tab td{padding:5px 0}}@media(max-width:850px){.spai_statusbox_wrap{width:100%;margin-left:0}.spai_statusbox_wrap .chart-wrap .toggle{display:none}.shortpixel-settings-tabs{width:100%}.spai_statusbox_wrap .title_wrap:after{content:'';display:block;position:absolute;opacity:1;visibility:visible;width:12px;height:12px;bottom:6px;left:calc(50% - 6px);background:url(../img/expand-button.svg)50%/contain no-repeat;-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0);-webkit-transition:all .2s ease-in-out;-o-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.spai_statusbox_wrap.expanded .title_wrap:after{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.spai_statusbox_wrap .box_content{display:none}.spai_statusbox_wrap .box_content.opened{position:relative;max-height:1e3px}}@media screen and (min-width:783px){#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{left:0;padding:0;width:24px;height:100%}}@media screen and (max-width:782px){#wpadminbar li#wp-admin-bar-shortpixel-ai-on-boarding{display:block;position:static}#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item .ab-icon{background-size:70%}#export_settings,#import_settings_form{display:none}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap select{margin-bottom:10px}.shortpixel-settings-tabs .exclusion-wrap .buttons-wrap input{width:100%;display:inline-block;margin-right:0;margin-bottom:10px}.shortpixel-settings-tabs .exclusion-wrap[data-type=urls] .buttons-wrap input{width:calc(100% - 10px)}.deactivation-popup[data-type=wrapper] .options-wrap label{margin-bottom:10px}}@media(min-width:851px) and (max-width:1268px){.spai_top_actions{margin:10px 10px 0 0}.spai_settings_tab{border-top:1px solid #e5e5e5}.nav-tab{border-bottom:1px solid #c3c4c7}.shortpixel-settings-tabs .nav-tab-active{border-bottom:1px solid #ccc}.shortpixel-settings-tabs .nav-tab-wrapper{padding-bottom:10px!important}}@media(max-width:600px){.spai_top_actions{margin:10px 10px 0 0}.spai_settings_tab{border-top:1px solid #e5e5e5}.shortpixel-settings-tabs .nav-tab-active{border-bottom:1px solid #ccc}.shortpixel-settings-tabs .nav-tab-wrapper{padding-bottom:10px!important}.socials-block .message-wrap{padding:0;margin-bottom:10px;text-align:center}.socials-block .buttons-wrap{position:unset;width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;margin:0 auto}}@media(max-width:450px){.sp-obw__content-wrap .step-message-wrap .dark_blue_link,.sp-obw__content-wrap .step-message-wrap .blue_link,.sp-obw__content-wrap .step-message-wrap .bordered_link,.sp-obw__content-wrap .step-message-wrap .action-wrap input,.sp-obw__content-wrap .step-message-wrap .action-wrap [data-action]{width:100%;display:block;text-align:center;margin:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box;font-family:inherit;font-size:inherit;font-weight:inherit}.shortpixel-on-boarding-wrap .socials-block{margin-top:30px}}@media(max-width:400px){.shortpixel_radio_btns{width:100%;display:table}.shortpixel_radio_btns label{display:table-cell;text-align:center;padding:0 5px}}@media(-webkit-min-device-pixel-ratio:2),(-o-min-device-pixel-ratio:2/1),(min-resolution:192dpi){#wpadminbar #wp-toolbar li#wp-admin-bar-shortpixel-ai-on-boarding .ab-item:before{background-image:url(../img/robo-happy@2x.png)!important}.spai_statusbox_wrap .title_wrap[data-status=enough]:before{background-image:url(../img/robo-rtl-cool@2x.png)}.spai_statusbox_wrap .title_wrap[data-status=few]:before{background-image:url(../img/robo-rtl-notes@2x.png)}.spai_statusbox_wrap .title_wrap[data-status=insufficiently]:before{background-image:url(../img/robo-rtl-scared@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=scared] .body-wrap:before{background-image:url(../img/robo-scared@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=happy] .body-wrap:before{background-image:url(../img/robo-happy@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=wink] .body-wrap:before{background-image:url(../img/robo-wink@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=cool] .body-wrap:before{background-image:url(../img/robo-cool@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=magnifier] .body-wrap:before{background-image:url(../img/robo-magnifier@2x.png)}.notice[data-plugin=short-pixel-ai][data-icon=notes] .body-wrap:before{background-image:url(../img/robo-notes@2x.png)}.deactivation-popup[data-type=wrapper] .body .title-wrap:before{background-image:url(../img/robo-happy@2x.png)}.shortpixel-ai-beacon:before{background-image:url(../img/notes@2x.png)}}@-webkit-keyframes knock-right-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateX(5px);transform:translateX(5px)}50%{-webkit-transform:translateX(3px);transform:translateX(3px)}65%{-webkit-transform:translateX(5px);transform:translateX(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes knock-right-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateX(5px);transform:translateX(5px)}50%{-webkit-transform:translateX(3px);transform:translateX(3px)}65%{-webkit-transform:translateX(5px);transform:translateX(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes knock-bottom-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateY(5px);transform:translateY(5px)}50%{-webkit-transform:translateY(3px);transform:translateY(3px)}65%{-webkit-transform:translateY(5px);transform:translateY(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes knock-bottom-small{0%{-webkit-transform:translateX(0);transform:translateX(0)}35%{-webkit-transform:translateY(5px);transform:translateY(5px)}50%{-webkit-transform:translateY(3px);transform:translateY(3px)}65%{-webkit-transform:translateY(5px);transform:translateY(5px)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}
  • shortpixel-adaptive-images/trunk/assets/js/notice.js

    r2900611 r3340495  
    9494            }
    9595        } );
     96        // feedback survey handler
     97        $document.on( 'click', '.notice[data-causer="recommend_survey"] .survey-rating-btn', function(e){
     98            e.preventDefault();
     99            var $btn    = $( this ),
     100                rating  = $btn.data('rating'),
     101                $notice = $btn.closest('.notice[data-causer="recommend_survey"]');
     102
     103            $notice.find('.survey-rating-btn').removeClass('selected');
     104            $btn.addClass('selected');
     105            // send (only) rating first
     106            $.post( ajaxurl, {
     107                action: 'shortpixel_ai_send_rating',
     108                data:   { rating: rating }
     109            });
     110            // for 9–10: show inline thank-you + review prompt for WP pagre
     111            if ( rating >= 9 ) {
     112                $notice.find('h3, .message-wrap > p').slideUp();
     113
     114                var promptHtml =
     115                    '<p>Thank you for your high rating! ' +
     116                    'If you have a moment, the ShortPixel team would be very happy ' +
     117                    'if you could leave a short review for our plugin.</p>';
     118
     119                var reviewLinkHtml =
     120                    '<p>' +
     121                    '<button id="survey-feedback-submit" class="button button-primary" '+
     122                    'onclick="window.open(\'https://wordpress.org/support/plugin/shortpixel-adaptive-images/reviews/?filter=5\', \'_blank\')">' +
     123                    'Leave a review' +
     124                    '</button>' +
     125                    '</p>';
     126
     127                $notice
     128                    .find('#survey-feedback-area')
     129                    .html( promptHtml + reviewLinkHtml )
     130                    .slideDown();
     131
     132                return;
     133            }
     134            // 1–8: close title + buttons & open feedback area
     135            $notice.find('h3').slideUp();
     136            $notice.find('.survey-rating-btn').closest('p').slideUp();
     137            var prompt = rating <= 4
     138                ? 'Thank you for your feedback! If you have encountered any issues with our plugin, we are more than eager to help solving them! Please give us more details:'
     139                : 'Thank you for your feedback! Please let us know what we can improve:';
     140
     141            $notice.find('#survey-feedback-prompt').text( prompt );
     142            $notice.find('#survey-feedback-area').slideDown();
     143        });
     144
     145        // now, when click on submit button send 2nd ajax with feedback
     146        $document.on( 'click', '.notice[data-causer="recommend_survey"] #survey-feedback-submit', function(e){
     147            e.preventDefault();
     148            var $notice      = $( this ).closest( '.notice[data-causer="recommend_survey"]'),
     149                rating       = $notice.find('.survey-rating-btn.selected').data('rating'),
     150                feedbackText = $notice.find('#survey-feedback').val() || '';
     151
     152            $.post( ajaxurl, {
     153                action: 'shortpixel_ai_send_feedback',
     154                data:   {
     155                    rating:   rating,
     156                    feedback: feedbackText
     157                }
     158            })
     159                .done(function( resp ){
     160                        var $msgWrap = $notice.find('.message-wrap');
     161                        if ( resp.success ) {
     162                            $msgWrap.html('<p>Thank you for your feedback!</p>');
     163                            $notice.find('#survey-feedback-area, .buttons-wrap').slideUp();
     164                        }
     165                        else {
     166                            var error = resp.data || 'Something went wrong sending feedback!';
     167                            $msgWrap.html('<p>' + error + '</p>');
     168                    }
     169                });
     170        });
     171
    96172    } );
    97173} )( jQuery, document, window );
  • shortpixel-adaptive-images/trunk/assets/js/notice.min.js

    r2900611 r3340495  
    1 (function(t,i,e){t((function(){var a=t(this);var n=false;a.on("click",'.notice[data-plugin="short-pixel-ai"] .buttons-wrap [data-action], .notice[data-plugin="short-pixel-ai"] button.notice-dismiss, .dismissed-notice[data-plugin="short-pixel-ai"] .buttons-wrap [data-action], .dismissed-notice[data-plugin="short-pixel-ai"] .buttons-wrap button.notice-dismiss',(function(){var o=t(this),d=o.parents('.notice[data-plugin="short-pixel-ai"], .dismissed-notice[data-plugin="short-pixel-ai"]');o.prop("disabled",true);var r=d.attr("data-causer"),s=o.attr("data-type"),c=o.attr("data-action"),u=o.attr("data-additional");r=typeof r==="string"&&r!==""?r:undefined;c=typeof c==="string"&&c!==""?c:r!==undefined&&o.hasClass("notice-dismiss")?"dismiss":undefined;try{u=JSON.parse(u)}catch(t){u=undefined}if(r!==undefined){if(s==="js"){if(typeof jQuery[c]==="function"){jQuery[c](u)}}else if(!n){t.ajax({method:"post",url:typeof ajaxurl==="string"&&ajaxurl!==""?ajaxurl:"/wp-admin/admin-ajax.php",data:{action:"shortpixel_ai_handle_notice_action",causer:d.attr("data-causer"),data:{action:c,additional:u}},beforeSend:function(){n=true},success:function(n){d.slideUp("fast",(function(){if(typeof n.notice==="string"&&n.notice!==""){var i=t(n.notice).hide();d.after(i);a.trigger("wp-updates-notice-added");i.slideDown("fast",(function(){i.removeAttr("style")}))}d.remove()}));if(typeof n.redirect!=="undefined"&&!!n.redirect.allowed){if(typeof n.redirect.url==="string"&&n.redirect.url!==""){if(!!n.redirect.blank){e.open(n.redirect.url)}else{i.location.href=n.redirect.url}}}if(typeof n.reload!=="undefined"&&!!n.reload.allowed){i.location.reload()}},complete:function(){n=false}})}}}))}))})(jQuery,document,window);
     1(function(e,t,a){e((function(){var i=e(this);var n=false;i.on("click",'.notice[data-plugin="short-pixel-ai"] .buttons-wrap [data-action], .notice[data-plugin="short-pixel-ai"] button.notice-dismiss, .dismissed-notice[data-plugin="short-pixel-ai"] .buttons-wrap [data-action], .dismissed-notice[data-plugin="short-pixel-ai"] .buttons-wrap button.notice-dismiss',(function(){var r=e(this),o=r.parents('.notice[data-plugin="short-pixel-ai"], .dismissed-notice[data-plugin="short-pixel-ai"]');r.prop("disabled",true);var s=o.attr("data-causer"),d=r.attr("data-type"),u=r.attr("data-action"),c=r.attr("data-additional");s=typeof s==="string"&&s!==""?s:undefined;u=typeof u==="string"&&u!==""?u:s!==undefined&&r.hasClass("notice-dismiss")?"dismiss":undefined;try{c=JSON.parse(c)}catch(e){c=undefined}if(s!==undefined){if(d==="js"){if(typeof jQuery[u]==="function"){jQuery[u](c)}}else if(!n){e.ajax({method:"post",url:typeof ajaxurl==="string"&&ajaxurl!==""?ajaxurl:"/wp-admin/admin-ajax.php",data:{action:"shortpixel_ai_handle_notice_action",causer:o.attr("data-causer"),data:{action:u,additional:c}},beforeSend:function(){n=true},success:function(n){o.slideUp("fast",(function(){if(typeof n.notice==="string"&&n.notice!==""){var t=e(n.notice).hide();o.after(t);i.trigger("wp-updates-notice-added");t.slideDown("fast",(function(){t.removeAttr("style")}))}o.remove()}));if(typeof n.redirect!=="undefined"&&!!n.redirect.allowed){if(typeof n.redirect.url==="string"&&n.redirect.url!==""){if(!!n.redirect.blank){a.open(n.redirect.url)}else{t.location.href=n.redirect.url}}}if(typeof n.reload!=="undefined"&&!!n.reload.allowed){t.location.reload()}},complete:function(){n=false}})}}}));i.on("click",'.notice[data-causer="recommend_survey"] .survey-rating-btn',(function(t){t.preventDefault();var a=e(this),i=a.data("rating"),n=a.closest('.notice[data-causer="recommend_survey"]');n.find(".survey-rating-btn").removeClass("selected");a.addClass("selected");e.post(ajaxurl,{action:"shortpixel_ai_send_rating",data:{rating:i}});if(i>=9){n.find("h3, .message-wrap > p").slideUp();var r="<p>Thank you for your high rating! "+"If you have a moment, the ShortPixel team would be very happy "+"if you could leave a short review for our plugin.</p>";var o="<p>"+'<button id="survey-feedback-submit" class="button button-primary" '+"onclick=\"window.open('https://wordpress.org/support/plugin/shortpixel-adaptive-images/reviews/?filter=5', '_blank')\">"+"Leave a review"+"</button>"+"</p>";n.find("#survey-feedback-area").html(r+o).slideDown();return}n.find("h3").slideUp();n.find(".survey-rating-btn").closest("p").slideUp();var s=i<=4?"Thank you for your feedback! If you have encountered any issues with our plugin, we are more than eager to help solving them! Please give us more details:":"Thank you for your feedback! Please let us know what we can improve:";n.find("#survey-feedback-prompt").text(s);n.find("#survey-feedback-area").slideDown()}));i.on("click",'.notice[data-causer="recommend_survey"] #survey-feedback-submit',(function(t){t.preventDefault();var a=e(this).closest('.notice[data-causer="recommend_survey"]'),i=a.find(".survey-rating-btn.selected").data("rating"),n=a.find("#survey-feedback").val()||"";e.post(ajaxurl,{action:"shortpixel_ai_send_feedback",data:{rating:i,feedback:n}}).done((function(e){var t=a.find(".message-wrap");if(e.success){t.html("<p>Thank you for your feedback!</p>");a.find("#survey-feedback-area, .buttons-wrap").slideUp()}else{var i=e.data||"Something went wrong sending feedback!";t.html("<p>"+i+"</p>")}}))}))}))})(jQuery,document,window);
  • shortpixel-adaptive-images/trunk/changelog.txt

    r2614181 r3340495  
     1= 2.3.3 =
     2Release date: June 30th, 2021
     3* Fix: issue with validating API key
     4* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     5
     6= 2.3.2 =
     7Release date: June 29th, 2021
     8* Temporarily deactivate AVIF pending codec bug fix (https://github.com/xiph/rav1e/issues/2757);
     9* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     10
     11= 2.3.1 =
     12Release date: June 28th, 2021
     13* New: Version the javascript in the file name in order to get around more stubborn caches;
     14* Fix: do not parse AJAX responses to uploads;
     15* Fix: nested element that has a different background - was taking the background of the parent element;
     16* Fix: notice in logs sometimes when domain info from server;
     17* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     18
     19= 2.3.0 =
     20Release date: June 17th, 2021
     21* New: images (including the ones from CSS files) are now served automatically in the new AVIF format to supporting browsers;
     22* New: moved the JS detection mechanism for WebP/AVIF support directly to the CDN level, so no JS is required anymore for this;
     23* Language: 0 new strings added, 6 updated, 0 fuzzed, and 0 obsoleted.
     24
     25= 2.2.4 =
     26Release date: June 14th, 2021
     27* Compat: added a constant - `SPAI_ELEMENTOR_WORKAROUND` - to deactivate the parsing of Elementor modules that are resulting in critical errors;
     28* Compat: workaround for WP Rocket that calls in certain circumstances the filter `rocket_css_content` with only one parameter;
     29* Fix: some warnings when lqip queue is not array were showing up in some cases;
     30* Fix: wrong array key when the no background calculation can't determine crop size and returns just width and height;
     31* Fix: iPhone issues with parsing stylesheets while also improving page responsiveness while parsing them (async);
     32* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     33
     34= 2.2.3 =
     35Release date: May 18th, 2021
     36* New: also parse inside `<script type="text/template">` blocks;
     37* Fix: the background crop resize wasn't working in several cases, which is now fixed;
     38* Fix: update the notification text about the next generation images served by SPIO;
     39* Fix: cases when a mutation has backgrounds from an existing CSS block are now properly handled;
     40* Fix: the special crop feature now handles correctly the situations when the width parameter isn't the first one;
     41* Fix: the inline background selector will handle situations with no space before the CSS class definition;
     42* Fix: remove the default values for JS parameters in order to support IE11;
     43* Fix: the images from `li` elements added with `data-thumb` are now replaced;
     44* Fix: the URL exclusions are checked when replacing inside JS blocks too;
     45* Language: 0 new strings added, 2 updated, 0 fuzzed, and 0 obsoleted.
     46
     47= 2.2.2 =
     48Release date: April 29th, 2021
     49* Fix: the minified version of the plugin CSS files was bigger than the not minified one;
     50* Fix: find local file when URL contains a path element before wp-content, that is not present on disk;
     51* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     52
     53= 2.2.1 =
     54Release date: April 26th, 2021
     55* Compat: added integration with Real3D Flipbook;
     56* Fix: there was a "Class not found" error in some cases when purging LiteSpeed cache from our plugin;
     57* Fix: in some cases, the size of background images wasn't properly set;
     58* Fix: protection added for very large number of product variations; the plugin will now work properly in these cases;
     59* Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
     60
     61= 2.2.0 =
     62Release date: April 20th, 2021
     63* New: added filter `shortpixel/ai/customRules` for custom replacement rules;
     64* New: added proper lazy loading for background images;
     65* New: take into account the `background-*` CSS styles: size, position, etc.;
     66* New: lazy load the images in the CSS blocks;
     67* New: handle correctly multiple URLs in the same `background-image:` declaration;
     68* New: when running out of credits you can now have an option to top-up directly from the plugin settings;
     69* Compat: added an integration with the Uncode theme and its iLightBox component;
     70* Compat: added integration with WPC Variations Table;
     71* Compat: added integration with Soliloquy Slider Plugin;
     72* Compat: also integrate properly with Divi child themes;
     73* Compat: improved the integration with Elementor, all images should now be properly replaced;
     74* Fix: WooCommerce product variations were broken if srcset was present, but false;
     75* Fix: in certain cases, background images with important CSS priority weren't properly handled;
     76* Fix: also remove the sizes attribute if we remove the srcset;
     77* Fix: replacement error when html attribute contains "<style>.." data;
     78* Fix: various small fixes to settings, fonts, debug messages, ShortPixel account login and lazy loading;
     79* Language: 7 new strings added, 2 updated, 0 fuzzed, and 3 obsoleted.
     80
    181= 2.1.6 =
    282Release date: March 19th, 2021
  • shortpixel-adaptive-images/trunk/includes/actions/notice.actions.class.php

    r3209129 r3340495  
    5050            die;
    5151        }
     52
     53        private static function handleRecommendSurvey( $data ) {
     54            if ( ( $data['action'] ?? '' ) === 'dismiss' ) {
     55                return [
     56                    'success' => Notice::dismiss( 'recommend_survey' ),
     57                ];
     58            }
     59            return null;
     60        }
    5261
    5362        private static function handleRemoteInfoNotice ($data){
  • shortpixel-adaptive-images/trunk/includes/actions/page.actions.class.php

    r3337681 r3340495  
    6060                }
    6161
     62                if (isset($options->behaviour->storage_url)) {
     63                    $options->behaviour->storage_url = sanitize_text_field(trim($options->behaviour->storage_url));
     64                }
     65
     66                if (isset($options->behaviour->host_removal)) {
     67                    $options->behaviour->host_removal = sanitize_text_field(trim($options->behaviour->host_removal));
     68                }
     69
     70
    6271
    6372                //translate simple meta options
    6473                $options = ShortPixelAI::translateSimpleOptions( $options );
    65 
    6674                $current_options = Options::_()->settings;
     75
     76                // if user just disabled the LQIP option, delete the LQIP state from DB
     77                if (($options->behaviour->lqip ?? null) === false && ($current_options->behaviour->lqip ?? null) === true) {
     78                    delete_option('shortpixel_ai_lqip_state');
     79                }
    6780
    6881                $success = true;
     
    176189                    $cdnMessage = '';
    177190                    $cdnErrorMessage =  '';
    178                     $messageData = $api_response['message']['Message'] ?? [];
     191                    $messageData = $api_response['message']['Details'] ?? [];
    179192                    //getting the array of messages
    180193                    if (!empty($messageData['0']['Message']) || !empty($messageData['CDN']['Message']) || !empty($messageData['CDN']['Error']) ) {
     
    252265            else if ( $action === 'clear lqip cache' ) {
    253266                $success = LQIP::clearCache();
    254                 //var_dump('HERE:', $success, $response);exit('this is only for admin button');
    255267                $response[ 'success' ] = $success;
    256268                $response[ 'notice' ]  = Notice::get( null, [
  • shortpixel-adaptive-images/trunk/includes/controllers/feedback.class.php

    r2627986 r3340495  
    1515         */
    1616        protected $controller;
     17
     18        private $logger;
    1719
    1820        /**
     
    301303                self::$instance = $this;
    302304            }
    303 
     305            $this->logger = \ShortPixelAILogger::instance();
    304306            $this->controller = $controller;
    305307
    306308            add_action( 'admin_footer-plugins.php', [ $this, 'generatePopUp' ] );
    307309            add_action( 'wp_ajax_shortpixel_ai_handle_feedback_action', [ 'ShortPixel\AI\Feedback\Actions', 'handle' ] );
    308         }
    309     }
     310
     311            add_action( 'wp_ajax_shortpixel_ai_send_rating', [ $this, 'handleSurveyAjax' ] );
     312            add_action( 'wp_ajax_shortpixel_ai_send_feedback', [ $this, 'handleSurveyAjax' ] );
     313        }
     314
     315        public function handleSurveyAjax() {
     316
     317
     318            $rating   = isset($_POST['data']['rating']) ? intval($_POST['data']['rating']) : 0;
     319            $feedback = isset($_POST['data']['feedback']) ? sanitize_text_field($_POST['data']['feedback']) : '';
     320
     321            if ( ! $rating || $rating < 1 || $rating > 10 ) {
     322                wp_send_json_error(__('Invalid rating', 'shortpixel-adaptive-images'));
     323            }
     324            $response = self::sendSurvey( $rating, $feedback );
     325
     326            if ( is_wp_error($response) ) {
     327                wp_send_json_error(__('Feedback could not be sent.', 'shortpixel-adaptive-images'));
     328            }
     329
     330            Notice::dismiss( 'recommend_survey' );
     331            wp_send_json_success();
     332
     333        }
     334
     335
     336        public  function sendSurvey( $rating, $feedback, $anonymous = false ) {
     337
     338            if ( ! is_int( $rating ) || $rating < 1 || $rating > 10 ) {
     339                return false;
     340            }
     341            $wordpress = self::collectWordpressData( ShortPixelAI::is_beta() );
     342            $wordpress['deactivated_plugin']['uninstall_reason']  = 'rating';
     343            $wordpress['deactivated_plugin']['uninstall_details'] = 'Rating: ' . $rating
     344                . ( $feedback ? ' – Feedback: ' . $feedback : '' );
     345
     346            $body = [
     347                'user'      => self::collectUserData( $anonymous ),
     348                'wordpress' => $wordpress,
     349            ];
     350            $spai_key = Options::_()->settings_general_apiKey;
     351            if ( $spai_key && ! $anonymous ) {
     352                $body['key'] = $spai_key;
     353            }
     354
     355            return Request::post( 'https://api.shortpixel.com/v2/feedback.php', true, [ 'body' => $body ] );
     356        }
     357    }
  • shortpixel-adaptive-images/trunk/includes/controllers/lqip.class.php

    r3209129 r3340495  
    120120        private $ctrl;
    121121
     122        private function normalizeLqipItem(array $item): array {
     123            if (!isset($item['source']) || !isset($item['url'])) {
     124                return $item;
     125            }
     126
     127            if ($item['source'] === $item['url']) {
     128                $item['lqipUrl'] = $item['url'];
     129                unset($item['source'], $item['url']);
     130            } else {// log to catch them and see if it's really useful to keep both sourcce & url
     131                $this->log('LQIP normalize: source ≠ url', [
     132                    'source' => $item['source'],
     133                    'url'    => $item['url'],
     134                    'referer' => $item['referer'] ?? null
     135                ]);
     136
     137                $item['source'] = null;
     138                $item['lqipUrl'] = $item['url'];
     139                unset($item['url']);
     140            }
     141            return $item;
     142        }
     143
     144
     145        private function provideTimestamp(array $collection): array {
     146            $now = time();
     147            foreach ($collection as &$item) {
     148                if (!isset($item['timestamp'])) {
     149                    $item['timestamp'] = $now;
     150                }
     151            }
     152            unset($item);
     153            return $collection;
     154        }
     155
     156        private function removeOldItemsFromCollection(array $collection, int $maxAgeSeconds = 86400): array {
     157            $threshold = time() - $maxAgeSeconds;
     158            return array_filter($collection, function($item) use ($threshold) {
     159                return !isset($item['timestamp']) || $item['timestamp'] >= $threshold;
     160            });
     161        }
     162
     163        private function getLqipState() {
     164            $state = get_option('shortpixel_ai_lqip_state', null);
     165
     166            if ($state === null) {
     167                // get previous data from old options
     168                $state = [
     169                    'collection' => Options::_()->get('collection', self::OPTIONS_CATEGORY, []),
     170                    'processed'  => Options::_()->get('processed', self::OPTIONS_CATEGORY, []),
     171                ];
     172                $state['collection'] = $this->provideTimestamp($state['collection']);
     173
     174                update_option('shortpixel_ai_lqip_state', $state);
     175                Options::_()->delete('collection', self::OPTIONS_CATEGORY);
     176                Options::_()->delete('processed', self::OPTIONS_CATEGORY);
     177            }
     178
     179            if (!is_array($state)) {
     180                $state = [ 'collection' => [], 'processed' => [] ];
     181            }
     182
     183            if (!isset($state['collection']) || !is_array($state['collection'])) $state['collection'] = [];
     184            if (!isset($state['processed']) || !is_array($state['processed'])) $state['processed'] = [];
     185
     186            return $state;
     187        }
     188
     189        private function saveLqipState($state) {
     190            update_option('shortpixel_ai_lqip_state', $state);
     191        }
     192
     193
     194
    122195        /**
    123196         * Single ton implementation
     
    179252                    $valid = !$this->exists( $name ) || $this->expired( $name );
    180253                    if(!$valid) {
    181                         $this->log("Dropping URL: " . $item . ' name: ' . $name);
     254                        $this->log("Dropping URL: " . json_encode($item) . ' name: ' . $name);
    182255                    }
    183256
     
    251324         */
    252325        public function eventHandler() {
    253             $collection = Options::_()->get( 'collection', self::OPTIONS_CATEGORY, [] );
    254             if(!is_array($collection)) $collection = [];
    255             $this->log('LQIP EVT HANLER: COLLECTION: ', $collection);
    256 
    257             if ( empty( $collection ) ) {
    258                 return;
    259             }
    260 
    261             $processed = Options::_()->get( 'processed', self::OPTIONS_CATEGORY, [] );
    262             $this->log('LQIP EVT HANLER: PROCESSED REQUESTS: ', $processed);
     326            $state = $this->getLqipState();
     327            $collection = $state['collection'];
     328            $processed = $state['processed'];
     329
     330            $this->log('LQIP EVT HANDLER: PROCESSED REQUESTS: ', $processed);
    263331
    264332
    265333            $collection = $this->filterWithProcessed( $collection, $processed );
    266 
    267334            $bundle = array_splice( $collection, 0, self::BUNDLE_CAPACITY );
    268335
    269             $this->log('LQIP EVT HANLER: SETTING COLLECTION: ', $collection);
    270             Options::_()->set( $collection, 'collection', self::OPTIONS_CATEGORY );
    271 
    272             $this->log('LQIP EVT HANLER: GENERATE BUNDLE: ', $bundle);
     336            $this->log('LQIP EVT HANDLER: GENERATE BUNDLE: ', $bundle);
     337            $state['collection'] = $collection;
     338            $this->saveLqipState($state);
    273339            $this->generate( $bundle );
    274340
     
    291357        private function schedule( $collection ) {
    292358            if ( !empty( $collection ) && is_array( $collection ) ) {
    293                 $scheduled_collection = Options::_()->get( 'collection', self::OPTIONS_CATEGORY, [] );
    294                 if(!is_array($scheduled_collection)) $scheduled_collection = [];
    295 
     359                $state = $this->getLqipState();
     360                $scheduled_collection = $state['collection'];
    296361                $collection = array_merge( $scheduled_collection, $collection );
     362                $collection = $this->provideTimestamp($collection);
     363                $collection = $this->removeOldItemsFromCollection($collection);
    297364                $collection = $this->replaceWithParent( $collection );
    298365                $collection = $this->filterCollection( $collection );
    299366
     367                $collection = array_map(function($item) {
     368                    return $this->normalizeLqipItem($item);
     369                }, $collection);
     370
    300371                $collection = array_filter( $collection, function( $item ) {
    301                     $name = $this->getFileName( $item[ 'source' ] );
     372                    $name = $this->getFileName( $item[ 'source' ] ?? $item['lqipUrl'] ?? '' );
    302373
    303374                    return !$this->exists( $name ) || $this->expired( $name );
    304375                } );
    305376
    306                 $this->log('SETTING LQIP COLLECTION: ', $collection);
    307 
    308                 $option_set = Options::_()->set( $collection, 'collection', self::OPTIONS_CATEGORY );
     377
     378                $state['collection'] = $collection;
     379                $this->saveLqipState($state);
    309380
    310381                if ( empty( $collection ) ) {
     
    316387                    $this->reschedule( 'quick' );
    317388
    318                     return ['processed' => !!$option_set, 'message' => (!!$option_set ? '' : 'Could not set lqip option.')];
     389                    return ['processed' => true];
    319390                }
    320391            }
     
    337408            if ( !empty( $collection ) && is_array( $collection ) ) {
    338409
    339                 $processed = Options::_()->get( 'processed', self::OPTIONS_CATEGORY, [] );
     410                $state = $this->getLqipState();
     411                $processed = $state['processed'];
    340412                $this->log( 'LQIP REQUESTS START. ALREADY PROCESSED: ', $processed );
    341413
     
    411483            $return = $this->countAttempts( $return, $processed );
    412484            $processed    = $this->filterCollection( array_merge( $processed, $return ) );
    413             Options::_()->set( $processed, 'processed', self::OPTIONS_CATEGORY );
     485            $state['processed'] = $processed;
     486            $this->saveLqipState($state);
    414487
    415488            return $return;
     
    435508         */
    436509        private function isPlaceholder( $content ) {
    437             return empty( $content ) ? false : $this->isSvg( $content ) && strpos( $content, 'feGaussianBlur' ) !== false;
     510            return empty( $content ) ? false : $this->isSvg( $content ) && (strpos( $content, 'feGaussianBlur' ) !== false ||
     511                strpos( $content, 'filter="blur' ) !== false);
    438512        }
    439513
     
    9591033            if ( !!$this->ctrl->options->settings_behaviour_lqip && $this->ctrl->options->settings_behaviour_processWay === LQIP::USE_INSTANT)
    9601034            {
     1035
    9611036                wp_register_script( 'spai-lqip', $this->ctrl->plugin_url . $file, $this->ctrl->options->settings_behaviour_nojquery <= 0 ? [ 'spai-scripts' ] : [], $version, true );
    9621037                wp_localize_script( 'spai-lqip', 'lqipConstants', [
  • shortpixel-adaptive-images/trunk/includes/controllers/notice.class.php

    r3258698 r3340495  
    373373            }
    374374
     375            if ( is_admin() && isset( $_GET['page'] ) && $_GET['page'] === 'shortpixel-ai-settings') {
     376                $installed = get_option( 'shortpixel_ai_installed_time' );
     377                if ( ! $installed ) {
     378                    update_option( 'shortpixel_ai_installed_time', time() );
     379                }
     380                elseif ( time() - $installed >= 30 * DAY_IN_SECONDS ) {
     381                    $dismissed = self::getDismissed();
     382                    if ( !isset( $dismissed->recommend_survey ) ) {
     383                        Notice::render('recommend_survey', [
     384                            'notice' => [
     385                                'type' => 'info',
     386                                'icon' => 'notes',
     387                                'dismissible' => true,
     388                            ],
     389                            'message' => [
     390                                'title' => __('How likely are you to recommend ShortPixel AI to a friend or colleague?', 'shortpixel-adaptive-images'),
     391                                'body' => [
     392                                    '<p><span style="margin-right:1em;">' . __('Not likely', 'shortpixel-adaptive-images') . '</span>'
     393                                    . implode('', array_map(function ($i) {
     394                                        return '<button class="button survey-rating-btn" '
     395                                            . 'data-rating="'. $i .'" '
     396                                            . 'style="margin:0 3px; min-width:2.5em; text-align:center; line-height:1.6;">'
     397                                            . $i
     398                                            . '</button>';
     399                                    }, range(1, 10)))
     400                                    . '<span style="margin-left:1em;">' . __('Very likely', 'shortpixel-adaptive-images') . '</span></p>',
     401                                    '<div id="survey-feedback-area" style="display:none;margin-top:10px;">'
     402                                    . '<p><strong id="survey-feedback-prompt">' . __('Give us your feedback:', 'shortpixel-adaptive-images') . '</strong></p>'
     403                                    . '<textarea id="survey-feedback" rows="3" style="width:100%;"></textarea><br><br>'
     404                                    . '<button id="survey-feedback-submit" class="button button-primary">'
     405                                    . __('Submit', 'shortpixel-adaptive-images')
     406                                    . '</button>'
     407                                    . '</div>',
     408                                ],
     409                            ],
     410                        ]);
     411                    }
     412                }
     413            }
     414
    375415            if ( !isset( $dismissed->wp_rocket_defer_js ) && $integrations->has( 'wp-rocket', 'defer-all-js' ) ) {
    376416                self::render( 'wp rocket defer js', [
  • shortpixel-adaptive-images/trunk/includes/controllers/page.class.php

    r3074757 r3340495  
    244244                    header('Content-Type: application/json');
    245245                    header('Content-Disposition: attachment; filename=SPAI-settings.json');
    246                     echo(json_encode($this->ctrl->options->get()->settings, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
     246                    echo(json_encode($this->ctrl->options->get()->settings->exportRecursive(), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
    247247                    die();
    248248                } );
  • shortpixel-adaptive-images/trunk/includes/controllers/regex-parser.class.php

    r3209129 r3340495  
    2626    private $forceEager = false;
    2727    private $isTemplate = false;
     28    private $content;
    2829
    2930
     
    4243    ];
    4344
     45
     46    protected function markTotalExclude(string $tagHtml, string $origUrl): string
     47    {
     48        $attrs  = ' data-spai-target="src"';
     49        $attrs .= ' data-spai-orig="' . esc_attr($origUrl) . '"';
     50        $attrs .= ' data-spai-exclude="nocdn"';
     51        return preg_replace(
     52            '/<img\b([^>]*)>/i',
     53            '<img$1' . $attrs . '>',
     54            $tagHtml,
     55            1
     56        );
     57    }
    4458
    4559    public function __construct(ShortPixelAI $ctrl)
     
    160174        //In some cases the regex fails with this limit reached (default is 1000000) so make it larger (HS#75940)
    161175        ini_set('pcre.backtrack_limit', 2000000);
     176
     177        $this->content = $content;
    162178
    163179        foreach (\ShortPixel\AI\TagRules::_()->items() as $tagRule) {
     
    670686        if(   !ShortPixelUrlTools::isValid($url)
    671687           && (!$this->isTemplate || strpos($url, '{{:') === false)) {$this->logger->log('NOT VALID');return $text;}
    672         if($this->ctrl->urlIsExcluded($url)) {$this->logger->log('EXCLUDED');return $text;}
     688        if ($this->ctrl->urlIsExcluded($url)) {
     689            $this->logger->log('EXCLUDED TOTALLY: ' . $url);
     690            return $this->markTotalExclude($text, $url);
     691        }
    673692
    674693        //custom exclusion for SliderRevolution TODO unhack
     
    699718        }
    700719
    701         $eager = $this->isEager || $this->ctrl->tagIs('eager', $text);
     720        $eager = $this->isEager || $this->ctrl->tagIs('eager', $text) || $this->ctrl->urlIsEager($url);;
    702721
    703722        SHORTPIXEL_AI_DEBUG && $this->logger->log("Including: " . $url . ($eager ? ' EAGER' : ' LAZY'));
     
    776795
    777796        if($eager) {
    778             //we set any CSS or JS to ret_wait because of the many CORS issues we've seen with these.
    779             $wait = $ext == 'css' || $ext == 'js';
     797            //we set any CSS or JS or FONTS to ret_wait because of the many CORS issues we've seen with these.
     798            $wait = in_array($ext, ShortPixelUrlTools::$EAGER_WAIT);
    780799            $cacheVer = $wait ? $this->ctrl->cssCacheVer : false;
    781800            if($this->isTemplate && strpos($url, '{{:') === 0) {
     
    783802                    . '/' . $url;
    784803            } else {
    785                 $inlinePlaceholder = $this->ctrl->get_api_url( $absoluteUrl, false, false, $this->ctrl->get_extension( $url ), $this->tagRule->getCustomCompression(), $wait, $cacheVer);
     804                $separator = strpos($this->content, $absoluteUrl) > 0 && $this->tagRule->attrValFilter == "preload" ? "," : ShortPixelAI::SEP;
     805                $inlinePlaceholder = $this->ctrl->get_api_url($absoluteUrl, false, false, $this->ctrl->get_extension($url),  $this->tagRule->getCustomCompression(), $wait, $cacheVer, $separator);
    786806            }
    787807            $spaiMarker = ' data-spai-egr=' . $qm . '1' . $qm;
     
    10301050        $aiSrcsetItems = array();
    10311051        $aiUrl = $this->ctrl->get_api_url(false, false);
    1032         $aiUrlBase = $this->ctrl->settings->behaviour->api_url;
     1052        $aiUrlBase = $this->ctrl->settings->behaviour->api_url; //ex: https://cdn.shortpixel.ai/spai
     1053        $aiUrlBaseAmazon = $this->ctrl->settings->behaviour->storage_url; //ex: https://cdn.shortpixel.ai/x9
    10331054        $srcsetItems = explode(',', $srcset);
    10341055        foreach($srcsetItems as $srcsetItem) {
     
    10401061                return $srcset;
    10411062            }
    1042             if(strpos($srcsetItem, $aiUrlBase) !== false || strpos($srcsetItem, 'data:image/') === 0) {
     1063            if(strpos($srcsetItem, $aiUrlBase) !== false || strpos($srcsetItem, $aiUrlBaseAmazon) !== false || strpos($srcsetItem, 'data:image/') === 0) {
    10431064                SHORTPIXEL_AI_DEBUG && $this->logger->log("REPLACE SRCSET abort - AI url: " . $srcsetItem);
    10441065                return $srcset; //already parsed by the hook.
  • shortpixel-adaptive-images/trunk/includes/controllers/short-pixel-ai.class.php

    r3310531 r3340495  
    470470        if ( is_null( $this->options->get( 'api_url', [ 'settings', 'behaviour' ], null ) ) ) {
    471471            $this->options->settings_behaviour_apiUrl        = ShortPixelAI::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH;
     472            $this->options->settings_behaviour_amazonS3        = false;
    472473            $this->options->settings_behaviour_replaceMethod = 'src';
    473474            $this->options->settings_behaviour_fadein        = true;
     
    11331134                $result['message'] = __('Invalid selector has been provided.', 'shortpixel-adaptive-images' );
    11341135            }
    1135             else if(empty($which) || !is_string($which) || !in_array($which, array('noresize_selectors', 'excluded_selectors', 'excluded_paths', 'eager_selectors'))) {
     1136            else if(empty($which) || !is_string($which) || !in_array($which, array('noresize_selectors', 'excluded_selectors', 'excluded_paths', 'eager_paths', 'eager_selectors'))) {
    11361137                $result['message'] = __('Invalid list has been provided.', 'shortpixel-adaptive-images' );
    11371138            }
     
    11411142                $selectors_now = $this->options->$wp_option_name;
    11421143                $result['status'] = 'ok';
    1143                 if($which === 'excluded_paths') {
     1144                if($which === 'excluded_paths' || $which === 'eager_paths' ) {
    11441145                    $name = 'URL';
    11451146                    $delimiter = "\n";
     
    12141215                $result['message'] = __('Invalid list has been provided.', 'shortpixel-adaptive-images' );
    12151216            }
    1216             else if(empty($which) || !is_string($which) || !in_array($which, array('noresize_selectors', 'excluded_selectors', 'excluded_paths', 'eager_selectors'))) {
     1217            else if(empty($which) || !is_string($which) || !in_array($which, array('noresize_selectors', 'excluded_selectors', 'excluded_paths', 'eager_selectors', 'eager_paths'))) {
    12171218                $result['message'] = __('Invalid list has been provided.', 'shortpixel-adaptive-images' );
    12181219            }
     
    13031304                $options->settings_behaviour_replaceMethod = $replace_method == 1 ? 'src' : ( $replace_method == 3 ? 'both' : 'srcset' );
    13041305                $options->settings_behaviour_apiUrl        = get_option( 'spai_settings_api_url' );
    1305                 $options->settings_behaviour_hoverHandling = !!get_option( 'spai_settings_hover_handling' );
     1306                $options->settings_behaviour_hoverHandling = !!get_option( 'spai_settings_hover_handling' );
    13061307                $options->settings_behaviour_nativeLazy    = !!get_option( 'spai_settings_native_lazy' );
    13071308
     
    15031504        if (function_exists('is_plugin_active') && is_plugin_active('sg-cachepress/sg-cachepress.php')) {
    15041505            $speedoptimizer = get_option('siteground_optimizer_combine_javascript', false);
    1505             //var_dump($speedoptimizer);
    15061506            if ($speedoptimizer === '1') {
    15071507                $this->conflict = 'speedoptimizer';
     
    15511551    }
    15521552
    1553     public function get_api_url( $url = false, $width = '%WIDTH%', $height = '%HEIGHT%', $type = false, $compression = false, $retAuto = false, $cacheVer = false) {
     1553
     1554    /**
     1555     * This function checks whether the CDN returned by get_cdn_url() is different
     1556     * from the default "https://cdn.shortpixel.ai/spai".
     1557     *
     1558     * If it is different, we consider it a "custom CDN".
     1559     */
     1560    private function is_custom_cdn()
     1561    {
     1562        $cdn = $this->get_cdn_url();
     1563        if (!$cdn) {
     1564            $cdn = self::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH;
     1565        }
     1566        $cdn = rtrim($cdn, '/');
     1567        $defaultCdn = rtrim(self::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH, '/');
     1568        $isBasicCustom = ($cdn !== $defaultCdn);
     1569
     1570        return $isBasicCustom;
     1571    }
     1572
     1573    private function is_amazon_cdn(){
     1574        $amazonGet = $this->settings->behaviour->amazon_s3;
     1575        $amazonEnabled   = !empty($amazonGet);
     1576        $amazonStorageGet   = $this->settings->behaviour->storage_url; // tha's the user input
     1577        $amazonStorage = !empty($amazonStorageGet);
     1578        // only if user has a storage_url (and amazon_s3 is enabled), we  consider that is 'custom as well.
     1579        $isAmazonCustom = ($amazonEnabled && $amazonStorage);
     1580
     1581        return $isAmazonCustom;
     1582    }
     1583
     1584    /**
     1585     * chooses the appropriate API base URL based on CDN settings.
     1586     *
     1587     * @param string|false $url The original URL.
     1588     * @return string The selected base URL.
     1589     */
     1590    public function choose_api_base()
     1591    {
     1592        $isAmazonCdn = $this->is_amazon_cdn();
     1593
     1594        if ($isAmazonCdn) {
     1595            return rtrim($this->settings->behaviour->storage_url, '/');
     1596        } else {
     1597            $cdnUrl = rtrim($this->get_cdn_url(), '/');
     1598            if (!$cdnUrl) {
     1599                $cdnUrl = rtrim(self::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH, '/');
     1600            }
     1601            return $cdnUrl;
     1602        }
     1603    }
     1604
     1605    private function do_host_removal(){
     1606        $hostRemovalGet = $this->settings->behaviour->host_removal;
     1607        $isHostRemoval   = !empty($hostRemovalGet);
     1608        return$isHostRemoval;
     1609    }
     1610
     1611    /**
     1612     * Applies host removal to the API URL if conditions are met.
     1613     *
     1614     * @param string $api_url The constructed API URL.
     1615     * @param string|false $url The original URL.
     1616     * @return string The final URL after host removal (if applied).
     1617     */
     1618    private function host_removal_logic($api_url, $url)
     1619    {
     1620        if (!$url) {
     1621            return $api_url;
     1622        }
     1623
     1624        $doHostRemoval = $this->do_host_removal();
     1625        $hostRemoval = $this->settings->behaviour->host_removal;
     1626
     1627        if ($doHostRemoval && $url){
     1628            $parsedUrl = parse_url($url);
     1629            $host = $parsedUrl['host'] ?? '';
     1630
     1631            if (strpos($host, $hostRemoval) !== false) {
     1632                $path = isset($parsedUrl['path']) ? $parsedUrl['path'] : '';
     1633                $query = isset($parsedUrl['query']) ? '?' . $parsedUrl['query'] : '';
     1634                $frag = isset($parsedUrl['fragment']) ? '#' . $parsedUrl['fragment'] : '';
     1635                $final = rtrim($api_url, '/') . $path . $query . $frag;
     1636                return $final;
     1637            }
     1638        }
     1639
     1640        return $api_url;
     1641    }
     1642
     1643
     1644
     1645
     1646    /**
     1647     * This helper method builds the final URL by appending ShortPixel parameters
     1648     * (w_, q_, ex_, to_, etc.) to the base URL using self::SEP.
     1649     *
     1650     * @param string $baseUrl  e.g. "https://cdn.shortpixel.ai/spai"
     1651     * @param array  $args     e.g. [ ['w' => 300], ['q' => 'lossy'], ['ex' => '1'] ]
     1652     * @return string          e.g. "https://cdn.shortpixel.ai/spai/w_300+q_lossy+ex_1"
     1653     */
     1654    private function build_spai_url($baseUrl, array $args, $separator = self::SEP){
     1655        $api_url = trailingslashit($baseUrl);
     1656        foreach ($args as $arg) {
     1657            foreach ($arg as $k => $v) {
     1658                $api_url .= $k . '_' . $v . $separator;
     1659            }
     1660        }
     1661        return  rtrim($api_url, $separator);
     1662
     1663    }
     1664    public function get_api_url( $url = false, $width = '%WIDTH%', $height = '%HEIGHT%', $type = false, $compression = false, $retAuto = false, $cacheVer = false, $separator = self::SEP) {
     1665
     1666        if ($url && $this->urlIsExcluded($url)) {
     1667            $this->logger->log("DEBUG get_api_url: URL completly excluded. Returning original URL: " . $url);
     1668            return $url;
     1669        }
    15541670        $args = array();
    15551671        $http = $url === false ? !is_ssl() : !self::is_ssl($url);
    15561672
    1557         if($compression == 'orig' && defined('SHORTPIXEL_AI_ORIG_NO_CDN')) {
     1673        if ($compression == 'orig' && defined('SHORTPIXEL_AI_ORIG_NO_CDN')) {
    15581674            return '';
    15591675        }
     
    15901706        }
    15911707
    1592         $api_url = $this->get_cdn_url();
    1593 
    1594         if ( !$api_url ) {
    1595             $api_url = self::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH;
    1596         }
    1597 
    1598         $api_url = trailingslashit($api_url);
    1599 
    1600         /*
    1601         Make args to be in desired format
    1602          */
    1603         foreach ($args as $arg) {
    1604             foreach ($arg as $k => $v) {
    1605                 $api_url .= $k . '_' . $v . self::SEP;
    1606             }
    1607         }
    1608         $api_url = rtrim($api_url, self::SEP);
    1609         //$api_url = trailingslashit( $api_url );
    1610         return $api_url . ($url ?  '/' . self::rem_proto($url) : '');
    1611     }
     1708
     1709        $isAmazonCdn = $this->is_amazon_cdn(); //verify if it is amazon CDN
     1710
     1711//        detect bucket name presence in host
     1712        $hostFound = false;
     1713        if ($isAmazonCdn) {
     1714            $hostRemovalGet = $this->settings->behaviour->host_removal ?? null;
     1715
     1716            if ($hostRemovalGet && $url) {
     1717                $parsed = parse_url($url);
     1718                $host = $parsed['host'] ?? '';
     1719                if (strpos($host, $hostRemovalGet) !== false) {
     1720                    $hostFound = true;
     1721                }
     1722            }
     1723        }
     1724            if ($hostFound){
     1725                // case 1: amazon CDN active and URL contains host_removal, will apply amazon cdn + host removal
     1726                $amazonStorageGet = $this->settings->behaviour->storage_url;
     1727                $base = rtrim($amazonStorageGet, '/'); // Amazon base
     1728                $api_url = $this->build_spai_url($base, $args, $separator);
     1729                $this->logger->log("BUILT Amazon api_url => ", $api_url);
     1730
     1731                $final_url = $this->host_removal_logic($api_url, $url);
     1732                if ($final_url !== $api_url) {
     1733                    return $final_url;
     1734                }
     1735                if (!$url) {
     1736                    return $api_url;
     1737                }
     1738
     1739                $ret = $api_url . '/' . self::rem_proto($url);
     1740                return $ret;
     1741            } else {
     1742                // case 2: Amazon CDN active but URL does't match host_removal will not put amazon cdn and not remove host
     1743                // case 3: Amazon CDN disabled ... get as usual with normal cdn
     1744                $base = rtrim($this->get_cdn_url(), '/');
     1745                if (!$base) {
     1746                    $base = rtrim(self::DEFAULT_API_AI . self::DEFAULT_API_AI_PATH, '/');
     1747                }
     1748                $api_url = $this->build_spai_url($base, $args, $separator);
     1749
     1750                if (!$url) {
     1751                    return $api_url;
     1752                }
     1753
     1754                $final = $api_url . '/' . self::rem_proto($url);
     1755                return $final;
     1756            }
     1757        }
    16121758
    16131759    public function maybe_replace_images_src($content)
     
    17531899            'noresize_selectors' => $this->splitSelectors( @$ex->noresize_selectors, ',' ),
    17541900            'excluded_paths'     => $this->splitSelectors( @$ex->excluded_paths, "\n" ),
     1901            'eager_paths'        => $this->splitSelectors( @$ex->eager_paths, "\n" ),
    17551902            'excluded_pages'     => $this->splitSelectors( @$ex->excluded_pages, "\n" ),
    17561903        ];
     
    18111958    }
    18121959
    1813     public function urlIsExcluded($url) {
    1814 
    1815         //exclude generated images like JetPack's admin bar hours stats
    1816         if(strpos($url, '?page=')) {
    1817             $admin = parse_url(admin_url());
    1818             if(isset($admin['path']) && strpos($url, $admin['path'])) {
    1819                 return true;
    1820             }
    1821         }
    1822 
    1823         if( strlen($this->settings->exclusions->excluded_paths)) {
    1824             return $this->isExcluded($url, $this->settings->exclusions->excluded_paths);
    1825         } else {
    1826             return false;
    1827         }
    1828 
    1829     }
    1830 
     1960
     1961    /**
     1962     *
     1963     * This function parses the given URL and removes any resolution suffix (e.g., "-1024x576")
     1964     * that is automatically appended by some WordPress themes for images.      *
     1965     *
     1966     * useful when comparing image URLs against exclusion rules, insuring that any
     1967     * appended resolution suffix does not prevent a match with the base URL.
     1968     *
     1969     * @param string $url - original image URL.
     1970     * @return string -  normalized image URL without the resolution suffix, or the original URL if parsing fails.
     1971     */
     1972    public function normalizeUrlForExcluded($url) {
     1973        $parsed = parse_url($url);
     1974        $this->logger->log("DEBUG: parsed " . json_encode($parsed, JSON_PRETTY_PRINT)); //var_export($parsed) //print_r($parsed)
     1975        if (!isset($parsed['path'])) {
     1976            return $url;
     1977        }
     1978        $normalizedPath = preg_replace(
     1979            '/-\d+x\d+(?=\.\w+$)/',
     1980            '',
     1981            $parsed['path']
     1982        );
     1983        $scheme   = isset($parsed['scheme']) ? $parsed['scheme'] : (is_ssl() ? 'https' : 'http');
     1984        $siteUrl  = home_url();
     1985        $siteHost = parse_url($siteUrl, PHP_URL_HOST);
     1986        return $scheme . '://' . $siteHost . $normalizedPath;
     1987    }
     1988
     1989    /**
     1990     * Core URL-matching method to test either total or eager exclusion.
     1991     *
     1992     * @param  string $mode  Either 'excluded' (full exclusion) or 'eager' (skip lazy only)
     1993     * @param  string $url   The image URL (may include CDN, Amazon, any host or size suffix)
     1994     * @return bool          True for matching either one mode’s rules
     1995     */
     1996    public function urlIs($mode, $url)
     1997    {
     1998        //revert CDN url to original
     1999        if ($this->urlIsApi($url)) {
     2000            $stripped = self::rem_proto($url);
     2001            $scheme = self::is_ssl($url) ? 'https://' : 'http://';
     2002            $url = $scheme . $stripped;
     2003            $this->logger->log("DEBUG urlIs: Reverted CDN URL to original: $url");
     2004        }
     2005        //exclude generated images like JetPack's admin bar hours stats
     2006        if (strpos($url, '?page=')) {
     2007            $admin = parse_url(admin_url());
     2008            if (strpos($url, $admin['path'])) {
     2009                return true;
     2010            }
     2011        }
     2012        //normalize any resolution suffix...
     2013        $normalizedUrl = $this->normalizeUrlForExcluded($url);
     2014        $this->logger->log("DEBUG urlIsExcluded: Normalized URL: " . $normalizedUrl);
     2015        //2 posibilities URL -> total exclusion('excluded') or eager exclusion('eager')
     2016        $list = ($mode === 'excluded')
     2017            ? $this->settings->exclusions->excluded_paths
     2018            : $this->settings->exclusions->eager_paths;
     2019        if (strlen($list)) {
     2020            if ($this->isExcluded($url, $list) || $this->isExcluded($normalizedUrl, $list)) {
     2021                return true;
     2022            }
     2023        }
     2024
     2025        return false;
     2026
     2027    }
     2028
     2029    /**
     2030     * FULL-EXCLUSION wrapper:
     2031     * Returns true if this URL must skip CDN entirely (no lazy, no CDN).
     2032     *
     2033     * @param  string $url
     2034     * @return bool
     2035     */
     2036    public function urlIsExcluded(string $url): bool
     2037    {
     2038        return $this->urlIs('excluded', $url);
     2039    }
     2040
     2041    /**
     2042     * EAGER-ONLY wrapper:
     2043     * Returns true if this URL should load eagerly (CDN OK but no lazy loading).
     2044     *
     2045     * @param  string $url
     2046     * @return bool
     2047     */
     2048    public function urlIsEager(string $url): bool
     2049    {
     2050        return $this->urlIs('eager', $url);
     2051    }
    18312052
    18322053    /**
     
    18762097                    case 'http': //being so kind to accept urls as they are. :)
    18772098                    case 'https':
    1878                         if(!isset($urlParsed['host'])) {
    1879                             $valueParsed = parse_url($value);
    1880                             if(isset($valueParsed['host'])) {
    1881                                 $url = ShortPixelUrlTools::absoluteUrl($url);
    1882                             }
    1883                         }
    18842099                        if(strpos($url, $value) !== false) {
    18852100                            $this->logger->log("EXCLUDED by $type $value RULE:", $rule);
    18862101                            return true;
    18872102                        }
     2103
     2104                        if (isset($urlParsed['path'])) {
     2105                            $ruleParsed = parse_url($value);
     2106                            if (!empty($ruleParsed['path'])) {
     2107                                $rulePathNorm = preg_replace('/-\d+x\d+(?=\.\w+$)/', '', $ruleParsed['path']);
     2108                                $urlPathNorm  = preg_replace('/-\d+x\d+(?=\.\w+$)/', '', $urlParsed['path']);
     2109                                if ($rulePathNorm === $urlPathNorm) {
     2110                                    $this->logger->log("EXCLUDED by HOST-INSENSITIVE PATH MATCH: $rulePathNorm");
     2111                                    return true;
     2112                                }
     2113                            }
     2114                        }
    18882115                        if(isset($urlParsed['path'])) {
    18892116                            preg_match(self::THUMBNAIL_REGEX, $urlParsed['path'], $matches);
     
    20592286            'exclusions' => [
    20602287                'excluded_paths' => self::GRAVATAR_REGEX,
    2061                 'eager_selectors' => '',
     2288                'eager_paths' => '',
     2289                'eager_selectors' => '',
    20622290                'noresize_selectors' => '',
    20632291                'excluded_selectors' => '',
  • shortpixel-adaptive-images/trunk/includes/front/jquery-js-loader.class.php

    r3209129 r3340495  
    7070            //the excluded_paths can contain URLs so we base64 encode them in order to pass our own JS parser :)
    7171            'excluded_paths'        => array_map( 'base64_encode', $this->ctrl->splitSelectors( $this->settings->exclusions->excluded_paths, PHP_EOL ) ),
     72            'eager_paths'        => array_map( 'base64_encode', $this->ctrl->splitSelectors( $this->settings->exclusions->eager_paths, PHP_EOL ) ),
    7273        ] );
    7374
  • shortpixel-adaptive-images/trunk/includes/front/vanilla-js-loader.class.php

    r3337681 r3340495  
    1717        add_action( 'wp_head', function() {
    1818            $apiUrlParts = explode('/', rtrim($this->ctrl->get_cdn_url(), '/'));
     19            $customApiUrlParts = explode('/', rtrim($this->ctrl->choose_api_base(), '/'));
     20            $customKeys = [];
     21            if ($this->settings->behaviour->amazon_s3) {
     22                $hostRemoval = $this->settings->behaviour->host_removal;
     23                $customKey   = end($customApiUrlParts);
     24                if ($hostRemoval && $customKey) {
     25                    $customKeys[$hostRemoval] = $customKey;
     26                }
     27            }
     28
    1929            $convert = 'none';
    2030            if(!!$this->settings->compression->webp || !!$this->settings->compression->avif) {
     
    4757                        version: "<?= esc_js(SHORTPIXEL_AI_VERSION) ?>",
    4858                        key: "<?= esc_js(end($apiUrlParts)) ?>",
     59                        customKeys: <?= wp_json_encode($customKeys) ?>,
    4960                        quality: "<?= esc_js($this->settings->compression->level) ?>",
    5061                        convert: "<?= esc_js($convert) ?>",
     
    91102                'noresize_selectors'    => $this->ctrl->splitSelectors( $this->settings->exclusions->noresize_selectors, ',' ),
    92103                'excluded_paths'        => array_map( 'base64_encode', $this->ctrl->splitSelectors( $this->settings->exclusions->excluded_paths, PHP_EOL ) ),
     104                'eager_paths'           => array_map( 'base64_encode', $this->ctrl->splitSelectors( $this->settings->exclusions->eager_paths, PHP_EOL ) ),
    93105            ]);
    94106            wp_enqueue_script( 'spai-snip-action'  );
     
    273285                ['lazy' => 0, 'cdn' => 0, 'resize' => 0, 'crop' => -1]);
    274286        }
     287
     288        foreach($this->ctrl->splitSelectors( $this->settings->exclusions->eager_paths, PHP_EOL) as $eagerPath) {
     289            $this->alterExclusion($exclusions, 'urls', $eagerPath, ['lazy' => 0]);
     290        }
     291
    275292        foreach($this->ctrl->splitSelectors( $this->settings->exclusions->excluded_selectors, ',') as $excludedSel) {
    276293            $this->alterExclusion($exclusions, 'selectors', $excludedSel,
  • shortpixel-adaptive-images/trunk/includes/helpers/url-tools.class.php

    r3160580 r3340495  
    1717        'eot', 'woff', 'woff2', 'ttf', 'otf' ];
    1818    public static $ONLY_STORE = [ 'svg', 'js', 'eot', 'webp', 'avif', 'woff', 'woff2', 'ttf', 'otf' ];
     19    public static $EAGER_WAIT = [ 'css', 'js', 'woff2', 'woff', 'otf', 'ttf', 'eot' ];
    1920    private static $SIZE_CACHE = [];
    2021
  • shortpixel-adaptive-images/trunk/includes/models/options.category.class.php

    r3125365 r3340495  
    1515        public function getData() {
    1616            return $this->__dyna;
     17        }
     18
     19        /**
     20         *  exports the internal data structure of the Category object
     21         *  - traverses  internal proteected __dyna object, and for each property,
     22         *  it checks if the value is another Category, Option, stdClass.
     23         * @return array  fully expanded data structure.
     24         */
     25        public function exportRecursive() {
     26            $result = [];
     27
     28            foreach ((array) $this->getData() as $key => $value) {
     29                if ($value instanceof \ShortPixel\AI\Options\Category) {
     30                    $result[$key] = $value->getData();
     31                } elseif ($value instanceof \ShortPixel\AI\Options\Option) {
     32                    $result[$key] = $value->getData();
     33                } elseif ($value instanceof \stdClass) {
     34                    $result[$key] = json_decode(json_encode($value), true);
     35                } else {
     36                    $result[$key] = $value;
     37                }
     38            }
     39            return $result;
    1740        }
    1841
  • shortpixel-adaptive-images/trunk/includes/views/settings.tpl.php

    r3209129 r3340495  
    706706                                    </td>
    707707                                </tr>
     708
     709
     710                                <tr>
     711                                    <th scope="row">
     712                                        <?= __( 'Amazon S3', 'shortpixel-adaptive-images' ); ?>
     713                                    </th>
     714                                    <td>
     715                                        <div class="spai-inline-help">
     716                <span class="dashicons dashicons-editor-help"
     717                      title="Inline help"
     718                      data-link="https://shortpixel.com/knowledge-base/article/using-shortpixel-adaptive-images-with-images-on-amazon-s3/"></span>
     719                                        </div>
     720                                        <input
     721                                                id="amazon_s3"
     722                                                type="checkbox"
     723                                                name="amazon_s3"
     724                                                class="tgl"
     725                                                data-type="bool"
     726                                                value="1"
     727                                        <?php checked( 1, $options->settings_behaviour_amazonS3, true ); ?>
     728                                        />
     729
     730                                        <label for="amazon_s3" class="tgl-btn">
     731                                            <span></span>
     732                                            <?= __( 'Deliver the images stored on Amazon S3 using ShortPixel CDN', 'shortpixel-adaptive-images' ); ?>
     733                                        </label>
     734                                        <p class="description">
     735                                            <?= __( 'Enable this option if you are offloading the images to an Amazon S3 bucket and you want to deliver them via our CDN to reduce costs. Read the configuration guide in <a href="https://shortpixel.com/knowledge-base/article/using-shortpixel-adaptive-images-with-images-on-amazon-s3/" target="_blank">our knowledge base</a>', 'shortpixel-adaptive-images' ); ?>
     736                                        </p>
     737                                        <div class="amazon-s3-fields-wrapper">
     738                                            <p>
     739                                                <label for="storage_url" style="display: inline-block; width: 140px;">
     740                                                    <strong><?= __( 'Base URL', 'shortpixel-adaptive-images' ); ?></strong>
     741                                                </label>
     742                                                <input
     743                                                        id="storage_url"
     744                                                        type="text"
     745                                                        data-type="string"
     746                                                        name="storage_url"
     747                                                        size="40"
     748                                                        placeholder="<?= __( 'Paste Base URL from ShortPixel Dashboard', 'shortpixel-adaptive-images' ); ?>"
     749                                                        value="<?= esc_attr( $options->settings_behaviour_storageUrl ); ?>"
     750                                                    <?php disabled(!$options->settings_behaviour_amazonS3, true); ?>
     751                                                />
     752
     753
     754                                            </p>
     755                                            <p>
     756                                                <label for="host_removal" style="display: inline-block; width: 140px;">
     757                                                    <strong><?= __( 'S3 Bucket URL', 'shortpixel-adaptive-images' ); ?></strong>
     758                                                </label>
     759                                                <input
     760                                                        id="host_removal"
     761                                                        type="text"
     762                                                        data-type="string"
     763                                                        name="host_removal"
     764                                                        size="40"
     765                                                        placeholder="<?= __( 'Get it from your Amazon S3 bucket details', 'shortpixel-adaptive-images' ); ?>"
     766                                                        value="<?= esc_attr( $options->settings_behaviour_hostRemoval ); ?>"
     767                                                    <?php disabled(!$options->settings_behaviour_amazonS3, true); ?>
     768                                                />
     769                                            </p>
     770                                        </div>
     771                                        <script>
     772                                            jQuery(document).ready(function($){
     773                                                $('#amazon_s3').on('change', function() {
     774                                                    var isChecked = $(this).is(':checked');
     775                                                    $('#storage_url, #host_removal').prop('disabled', !isChecked);
     776                                                }).trigger('change');
     777                                            });
     778                                        </script>
     779                                    </td>
     780                                </tr>
     781
     782
    708783                                <tr>
    709784                                    <th scope="row">
     
    13661441                                $no_resize_selectors = $options->settings_exclusions_noresizeSelectors;
    13671442                                $excluded_selectors  = $options->settings_exclusions_excludedSelectors;
     1443                                $eager_paths         = $options->settings_exclusions_eagerPaths;
    13681444                                $excluded_paths      = $options->settings_exclusions_excludedPaths;
    13691445                                $excluded_pages      = $options->settings_exclusions_excludedPages;
     
    13731449                                    'no_resize_selectors' => $controller->splitSelectors( $no_resize_selectors, ',' ),
    13741450                                    'excluded_selectors'  => $controller->splitSelectors( $excluded_selectors, ',' ),
     1451                                    'eager_paths'         => $controller->splitSelectors( $eager_paths, PHP_EOL ),
    13751452                                    'excluded_paths'      => $controller->splitSelectors( $excluded_paths, PHP_EOL ),
    13761453                                ];
     
    13821459
    13831460                                $excluded_selectors_qty = count( $split_selectors[ 'eager_selectors' ] ) + count( $split_selectors[ 'no_resize_selectors' ] ) + count( $split_selectors[ 'excluded_selectors' ] );
    1384                                 $excluded_paths_qty     = count( $split_selectors[ 'excluded_paths' ] );
     1461                                $excluded_paths_qty     = count( $split_selectors[ 'excluded_paths' ] ) + count( $split_selectors[ 'eager_paths' ] );
    13851462                            ?>
    13861463                            <table class="form-table">
     
    14481525                                            <?= str_replace( '{{QTY}}', $excluded_paths_qty, __( 'You already have <span>{{QTY}}</span> URL exclusions active. Please keep the number of exclusion selectors low for best performance.', 'shortpixel-adaptive-images' ) ); ?>
    14491526                                        </p>
    1450                                         <div>
     1527
     1528                                        <div><label for="eager_paths"><?= __( 'Don\'t lazy-load Url\'s:', 'shortpixel-adaptive-images' ); ?></label><br>
     1529                                            <textarea
     1530                                                    id="eager_paths"
     1531                                                    name="eager_paths"
     1532                                                    rows="5"
     1533                                                    data-type="string"
     1534                                                    data-exclusion-type="urls"
     1535                                                    data-setting="exclusion"
     1536                                                    data-separator="<?= PHP_EOL; ?>"
     1537                                            ><?= $eager_paths; ?></textarea>
     1538                                        </div>
     1539                                        <div><label for="excluded_paths"><?= __( 'Leave out completely Url\'s:', 'shortpixel-adaptive-images' ); ?></label><br>
    14511540                                            <textarea
    14521541                                                id="excluded_paths"
  • shortpixel-adaptive-images/trunk/readme.txt

    r3337681 r3340495  
    55Tested up to: 6.8
    66Requires PHP: 5.6.40
    7 Stable tag: 3.10.5
     7Stable tag: 3.11.0
    88License: GPLv2 or later
    99License URI: http://www.gnu.org/licenses/gpl-2.0.html
     
    249249
    250250== Changelog ==
     251
     252= 3.11.0 =
     253
     254🌩️ The S3 & Speed Boost Update
     255
     256Release Date: August 6, 2025
     257
     258✨ New Features
     259
     260* Amazon S3 Integration: Images stored on Amazon S3 can now be seamlessly served through the ShortPixel CDN — faster delivery, no matter where your files live.
     261* Lazy-Load Exclusions by URL: You can now exclude specific images from lazy-loading by their URL for greater control over your image loading strategy.
     262
     263⚙️ Improvements
     264
     265* Smarter LQIP Handling: Optimized the way Low-Quality Image Placeholders (LQIPs) are processed to boost performance on sites with lots of images.
     266
     267🛠️ Fixes
     268
     269* Settings Export Restored: Exporting your plugin settings now works reliably in all scenarios.
     270* LQIP Fixes: Addressed several minor issues to ensure LQIPs behave correctly across different setups.
     271* Security Enhancements: Added extra security checks to strengthen protection and prevent potential vulnerabilities.
     272
     273Update now to enjoy smarter performance, better control, and enhanced flexibility with your image delivery! 🚀
    251274
    252275= 3.10.5 =
     
    691714* Language: 18 new strings added, 51 updated, 0 fuzzed, and 12 obsoleted.
    692715
    693 = 2.3.3 =
    694 Release date: June 30th, 2021
    695 * Fix: issue with validating API key
    696 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    697 
    698 = 2.3.2 =
    699 Release date: June 29th, 2021
    700 * Temporarily deactivate AVIF pending codec bug fix (https://github.com/xiph/rav1e/issues/2757);
    701 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    702 
    703 = 2.3.1 =
    704 Release date: June 28th, 2021
    705 * New: Version the javascript in the file name in order to get around more stubborn caches;
    706 * Fix: do not parse AJAX responses to uploads;
    707 * Fix: nested element that has a different background - was taking the background of the parent element;
    708 * Fix: notice in logs sometimes when domain info from server;
    709 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    710 
    711 = 2.3.0 =
    712 Release date: June 17th, 2021
    713 * New: images (including the ones from CSS files) are now served automatically in the new AVIF format to supporting browsers;
    714 * New: moved the JS detection mechanism for WebP/AVIF support directly to the CDN level, so no JS is required anymore for this;
    715 * Language: 0 new strings added, 6 updated, 0 fuzzed, and 0 obsoleted.
    716 
    717 = 2.2.4 =
    718 Release date: June 14th, 2021
    719 * Compat: added a constant - `SPAI_ELEMENTOR_WORKAROUND` - to deactivate the parsing of Elementor modules that are resulting in critical errors;
    720 * Compat: workaround for WP Rocket that calls in certain circumstances the filter `rocket_css_content` with only one parameter;
    721 * Fix: some warnings when lqip queue is not array were showing up in some cases;
    722 * Fix: wrong array key when the no background calculation can't determine crop size and returns just width and height;
    723 * Fix: iPhone issues with parsing stylesheets while also improving page responsiveness while parsing them (async);
    724 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    725 
    726 = 2.2.3 =
    727 Release date: May 18th, 2021
    728 * New: also parse inside `<script type="text/template">` blocks;
    729 * Fix: the background crop resize wasn't working in several cases, which is now fixed;
    730 * Fix: update the notification text about the next generation images served by SPIO;
    731 * Fix: cases when a mutation has backgrounds from an existing CSS block are now properly handled;
    732 * Fix: the special crop feature now handles correctly the situations when the width parameter isn't the first one;
    733 * Fix: the inline background selector will handle situations with no space before the CSS class definition;
    734 * Fix: remove the default values for JS parameters in order to support IE11;
    735 * Fix: the images from `li` elements added with `data-thumb` are now replaced;
    736 * Fix: the URL exclusions are checked when replacing inside JS blocks too;
    737 * Language: 0 new strings added, 2 updated, 0 fuzzed, and 0 obsoleted.
    738 
    739 = 2.2.2 =
    740 Release date: April 29th, 2021
    741 * Fix: the minified version of the plugin CSS files was bigger than the not minified one;
    742 * Fix: find local file when URL contains a path element before wp-content, that is not present on disk;
    743 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    744 
    745 = 2.2.1 =
    746 Release date: April 26th, 2021
    747 * Compat: added integration with Real3D Flipbook;
    748 * Fix: there was a "Class not found" error in some cases when purging LiteSpeed cache from our plugin;
    749 * Fix: in some cases, the size of background images wasn't properly set;
    750 * Fix: protection added for very large number of product variations; the plugin will now work properly in these cases;
    751 * Language: 0 new strings added, 0 updated, 0 fuzzed, and 0 obsoleted.
    752 
    753 = 2.2.0 =
    754 Release date: April 20th, 2021
    755 * New: added filter `shortpixel/ai/customRules` for custom replacement rules;
    756 * New: added proper lazy loading for background images;
    757 * New: take into account the `background-*` CSS styles: size, position, etc.;
    758 * New: lazy load the images in the CSS blocks;
    759 * New: handle correctly multiple URLs in the same `background-image:` declaration;
    760 * New: when running out of credits you can now have an option to top-up directly from the plugin settings;
    761 * Compat: added an integration with the Uncode theme and its iLightBox component;
    762 * Compat: added integration with WPC Variations Table;
    763 * Compat: added integration with Soliloquy Slider Plugin;
    764 * Compat: also integrate properly with Divi child themes;
    765 * Compat: improved the integration with Elementor, all images should now be properly replaced;
    766 * Fix: WooCommerce product variations were broken if srcset was present, but false;
    767 * Fix: in certain cases, background images with important CSS priority weren't properly handled;
    768 * Fix: also remove the sizes attribute if we remove the srcset;
    769 * Fix: replacement error when html attribute contains "<style>.." data;
    770 * Fix: various small fixes to settings, fonts, debug messages, ShortPixel account login and lazy loading;
    771 * Language: 7 new strings added, 2 updated, 0 fuzzed, and 3 obsoleted.
    772716
    773717= EARLIER VERSIONS =
  • shortpixel-adaptive-images/trunk/short-pixel-ai.php

    r3337681 r3340495  
    44     * Plugin URI: https://shortpixel.com/
    55     * Description: Display properly sized, smart cropped and optimized images on your website. Images are processed on the fly and served from our CDN.
    6      * Version: 3.10.5
     6     * Version: 3.11.0
    77     * Author: ShortPixel
    88     * GitHub Plugin URI: https://github.com/short-pixel-optimizer/shortpixel-adaptive-images
     
    1616
    1717    if ( !class_exists( 'ShortPixelAI' ) ) {
    18         define( 'SHORTPIXEL_AI_VERSION', '3.10.5' );
     18        define( 'SHORTPIXEL_AI_VERSION', '3.11.0' );
    1919        define( 'SPAI_SNIP_VERSION', '3.1.0' );
    2020        define( 'SHORTPIXEL_AI_VANILLAJS_VER', '1.1' );
     
    103103            $old_error_handler = set_error_handler( [ 'ShortPixelAILogger', 'errorHandler' ] );
    104104        }
     105        function activatedTimeCollect(){
     106            update_option('shortpixel_ai_installed_time', time());
     107        }
    105108
    106109        register_activation_hook( __FILE__, [ 'ShortPixelAI', 'activate' ] );
     
    112115            ShortPixelAI::_();
    113116        } );
    114     }
     117
     118    }
Note: See TracChangeset for help on using the changeset viewer.