1(()=>{"use strict";const e={isDebug:function(){return new URLSearchParams(location.search).has("spc_debug")||null!==localStorage.getItem("spc_debug")},log:function(e,...t){this.isDebug()&&console[e]("[SPC]",...t)},info:function(...e){this.log("info",...e)},warn:function(...e){this.log("warn",...e)},error:function(...e){this.log("error",...e)},table:function(e){this.isDebug()&&(console.log("[SPC] Table:"),console.table(e))}},t={getKey:function(e,t){return`spc_pp_${e}_${t}`},isProcessed:function(t,s){try{const e=this.getKey(t,s),r=sessionStorage.getItem(e);return!!r&&(parseInt(r,10),Date.now(),!0)}catch(t){return e.error("Error checking sessionStorage:",t),!1}},markProcessed:function(t,s){try{const e=this.getKey(t,s);sessionStorage.setItem(e,Date.now().toString())}catch(t){e.error("Error setting sessionStorage:",t)}}},s={DEVICE_TYPES:{MOBILE:1,DESKTOP:2},MOBILE_BREAKPOINT:600,getDeviceType:function(){const t=document.documentElement.clientWidth||window.innerWidth;return t<=this.MOBILE_BREAKPOINT?(e.info("Device detected as mobile based on width:",t),this.DEVICE_TYPES.MOBILE):(e.info("Device detected as desktop based on width:",t),this.DEVICE_TYPES.DESKTOP)},isMobile:function(){return this.getDeviceType()===this.DEVICE_TYPES.MOBILE},isDesktop:function(){return this.getDeviceType()===this.DEVICE_TYPES.DESKTOP}},r={sendToRestApi:function(s){const{restUrl:r}=window.spcDataOptimizer||{};if(!r)return void e.error("REST API URL not available");const n=r+"/optimizations",i=new Blob([JSON.stringify(s)],{type:"application/json"});navigator.sendBeacon(n,i)?(e.info("Data sent successfully using sendBeacon"),t.markProcessed(s.u,s.d)):(e.error("Failed to send data using sendBeacon"),this._sendWithFetch(n,s))},_sendWithFetch:function(s,r){fetch(s,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)}).then((e=>{if(!e.ok)throw new Error("Network response was not ok");return e.json()})).then((s=>{e.info("Data sent successfully using fetch fallback:",s),t.markProcessed(r.u,r.d)})).catch((t=>{e.error("Error sending data using fetch fallback:",t)}))}},n={debounce:function(e,t){let s;return function(){clearTimeout(s),s=setTimeout((()=>e.apply(this,arguments)),t)}},getUniqueSelector:function(e){if(!e||e===document.body)return"body";if(e.id)return`#${e.id}`;const t=e.tagName.toLowerCase();let s="";e.className&&"string"==typeof e.className&&(s=e.className.includes("spc-bg-lazyloaded")?"."+e.className.trim().split(/\s+/).filter((e=>"spc-bg-lazyloaded"!==e)).join("."):"."+e.className.trim().replace(/\s+/g,"."));const r=e.parentElement;if(!r||r===document.body)return`body > ${t}${s}`;let n="";const i=r.children;let o=0,c=0;for(let t=0;t<i.length;t++)i[t].tagName===e.tagName&&(o++,i[t]===e&&(c=o));return o>1&&(n=`:nth-of-type(${c})`),`${r.id?`#${r.id}`:this.getUniqueSelector(r)} > ${t}${s}${n}`},hasBackgroundImage:function(e,t=!1){const s=window.getComputedStyle(e).backgroundImage;return!(!s||"none"===s||!s.includes("url("))&&(!t||s)},extractUrlsFromBgImage:function(e){if(!e)return null;const t=[],s=/url\(['"]?(.*?)['"]?\)/g;let r;for(;null!==(r=s.exec(e));)r[1]&&t.push(r[1]);return t.length>0?t:null},checkPageConditions:function(){return{hasValidViewport:window.innerWidth>0&&window.innerHeight>0,isVisible:"hidden"!==document.visibilityState||document.prerendering,isComplete:"complete"===document.readyState}},waitForPageLoad:function(){return"complete"===document.readyState?Promise.resolve():new Promise((e=>{window.addEventListener("load",e,{once:!0})}))},waitForIdleTime:function(){return new Promise((e=>{"function"==typeof requestIdleCallback?requestIdleCallback(e):setTimeout(e,200)}))}},i={detectLcpElement:async function(){const t={element:null,imageId:null,bgSelector:null,bgUrls:null};if(!PerformanceObserver.supportedEntryTypes.includes("largest-contentful-paint"))return e.info("LCP detection not supported in this browser"),t;const s=performance.getEntriesByType("largest-contentful-paint");if(s&&s.length>0){const r=s[s.length-1];r&&r.element&&(t.element=r.element,e.info("LCP element found from existing entries:",t.element),this._processLcpElement(r.element,t))}else e.info("Setting up LCP observer"),await new Promise((s=>{const r=new PerformanceObserver((n=>{const i=n.getEntries();if(0===i.length)return;const o=i[i.length-1];o&&o.element&&(t.element=o.element,e.info("LCP element detected:",t.element),this._processLcpElement(o.element,t)),r.disconnect(),s()}));r.observe({type:"largest-contentful-paint",buffered:!0}),setTimeout((()=>{r.disconnect(),s()}),1500)}));return t},_processLcpElement:function(t,s){if(t)if("IMG"===t.tagName){const r=t.getAttribute("data-spc-id");r&&(s.imageId=parseInt(r,10),e.info("LCP element is an SPC image with ID:",s.imageId))}
1else{const r=n.hasBackgroundImage(t,!0);!1!==r&&(s.bgSelector=n.getUniqueSelector(t),s.bgUrls=n.extractUrlsFromBgImage(r),e.info("LCP element has background image:",s.bgSelector,s.bgUrls))}}};class o{constructor(){this.results={selectors:new Map,sheets:[]},this.deviceType=s.getDeviceType(),this.cssStructure=new Map,this.usedCSSVariables=new Set,this.ruleIndex=0}async analyze(){e.info("Starting CSS analysis...");try{await this.collectStylesheets(),await this.checkSelectorUsage(),await this.checkPropertyUsage();const t=this.generateReport();return e.info("CSS analysis completed:",{totalRules:t.summary.totalRules,usedRules:t.summary.usedRules,unusedRules:t.summary.unusedRules,usagePercentage:t.summary.usagePercentage,deviceType:1===this.deviceType?"mobile":"desktop"}),t}catch(t){return e.error("CSS analysis failed:",t),null}}async collectStylesheets(){const t=document.styleSheets,s=t.length;for(let r=0;r<s;r++){const s=t[r];try{const e={index:r,href:s.href||"inline",rules:[],accessible:!0},t=s.cssRules||s.rules;if(t){const s=t.length;for(let r=0;r<s;r++)this.processRule(t[r],e)}this.results.sheets.push(e)}catch(t){this.results.sheets.push({index:r,href:s.href||"inline",rules:[],accessible:!1,error:"CORS or other access restriction"}),e.warn("Could not access stylesheet:",s.href||"inline",t.message)}}}processRule(e,t){switch(e.type){case CSSRule.STYLE_RULE:const s={selector:e.selectorText,cssText:e.cssText,style:e.style,used:!1,type:"style",mediaQuery:"default"};t.rules.push(s);break;case CSSRule.MEDIA_RULE:this.processMediaRule(e,t);break;case CSSRule.IMPORT_RULE:t.rules.push({selector:"@import",cssText:e.cssText,used:!0,type:"import",mediaQuery:"default"});break;case CSSRule.FONT_FACE_RULE:t.rules.push({selector:"@font-face",cssText:e.cssText,used:!0,type:"font-face",mediaQuery:"default"});break;default:t.rules.push({selector:e.constructor.name||"unknown",cssText:e.cssText,used:!0,type:"other",mediaQuery:"default"})}}processMediaRule(e,t){const s=e.media.mediaText,r={selector:`@media ${s}`,cssText:"",used:!1,type:"media",mediaText:s,nestedRules:[]},n=e.cssRules;if(n){const e=n.length;for(let i=0;i<e;i++){const e=n[i];if(e.type===CSSRule.STYLE_RULE){const n={selector:e.selectorText,cssText:e.cssText,style:e.style,used:!1,mediaQuery:s};r.nestedRules.push(n),t.rules.push(n)}}}t.rules.push(r)}stripPseudoElements(e){const t=e.split(",").map((e=>{let t=e.trim().replace(/::(before|after|first-line|first-letter|marker|selection|placeholder|backdrop|cue|grammar-error|spelling-error)/gi,"").replace(/:(before|after|first-line|first-letter)/gi,"").trim();return""===t||":"===t?"*":t}));return[...new Set(t.filter((e=>e&&""!==e)))].join(", ")}extractCSSVariables(e){const t=[];if(!e)return t;const s=/var\(\s*(--[a-zA-Z0-9-_]+)/g;let r;for(;null!==(r=s.exec(e));)t.push(r[1]);return t}async scanAllRulesForCSSVariables(){const t=/var\(\s*(--[a-zA-Z0-9-_]+)/g;for(const e of this.results.sheets){if(!e.accessible)continue;const s=e.rules.length;for(let r=0;r<s;r++){const s=e.rules[r],n=s.cssText||s.style?.cssText;if(n){let e;for(;null!==(e=t.exec(n));)this.usedCSSVariables.add(e[1]);t.lastIndex=0}if("media"===s.type&&s.nestedRules){const e=s.nestedRules.length;for(let r=0;r<e;r++){const e=s.nestedRules[r].cssText||s.nestedRules[r].style?.cssText;if(e){let s;for(;null!==(s=t.exec(e));)this.usedCSSVariables.add(s[1]);t.lastIndex=0}}}}}const s=document.querySelectorAll("[style]"),r=s.length;for(let e=0;e<r;e++){const r=s[e].getAttribute("style");if(r){let e;for(;null!==(e=t.exec(r));)this.usedCSSVariables.add(e[1]);t.lastIndex=0}}this.usedCSSVariables.size>0&&e.info("CSS variables detected:",{count:this.usedCSSVariables.size})}async checkSelectorUsage(){const e=new Map;for(const t of this.results.sheets){if(!t.accessible)continue;const s=t.rules.length;for(let r=0;r<s;r++){const s=t.rules[r];if("style"!==s.type&&s.type)"media"===s.type?this.checkMediaRuleUsage(s,t.href,e):(s.used=!0,this.addToStructure(s),this.results.selectors.set(s.selector,{used:s.used,sheet:t.href,mediaQuery:s.mediaQuery||"default"}));else try{const r=this.stripPseudoElements(s.selector);let n;e.has(r)?n=e.get(r):(n=document.querySelectorAll(r).length,e.set(r,n)),s.used=n>0,s.matchCount=n,s.used&&this.addToStructure(s),this.results.selectors.set(s.selector,{used:s.used,matchCount:n,sheet:t.href,mediaQuery:s.mediaQuery||"default"})}catch(e){s.used=!1,s.error="Invalid selector",this.results.selectors.set(s.selector,{used:!1,error:"Invalid selector",sheet:t.href,mediaQuery:s.mediaQuery||"default"})}}}e.clear(),await this.scanAllRulesForCSSVariables(),await this.includeCSSVariableDefinitions()}
1addToStructure(t){const s=t.mediaQuery||"default";this.cssStructure.has(s)||this.cssStructure.set(s,new Map);const r=this.cssStructure.get(s);r.has(t.selector)||r.set(t.selector,{});const n=r.get(t.selector);if(void 0===n._order&&(n._order=this.ruleIndex++),"import"===t.type||"font-face"===t.type||"keyframes"===t.type||"other"===t.type)return n._cssText?n._cssText=n._cssText+"\n"+t.cssText:n._cssText=t.cssText,void(n._type=t.type);t.style&&t.style.cssText?(n._cssText?n._cssText=n._cssText+" "+t.style.cssText:n._cssText=t.style.cssText,n._type="declarations"):(n._cssText?n._cssText=n._cssText+" "+t.cssText:n._cssText=t.cssText,n._type="fallback",e.info("Fallback: storing entire CSS rule for:",{selector:t.selector,cssText:t.cssText}))}async includeCSSVariableDefinitions(){if(0===this.usedCSSVariables.size)return;let t=0;for(const e of this.results.sheets)if(e.accessible)for(const s of e.rules)if("style"===s.type||!s.type){const r=s.cssText||s.style?.cssText||"";if(this.definesUsedCSSVariable(r))if(t++,s.used){const e=s.mediaQuery||"default";this.cssStructure.has(e)&&this.cssStructure.get(e).has(s.selector)||this.addToStructure(s)}else s.used=!0,s.matchCount=0,this.addToStructure(s),this.results.selectors.set(s.selector,{used:!0,matchCount:0,cssText:s.cssText,sheet:e.href,mediaQuery:s.mediaQuery||"default",reason:"css-variables"})}t>0&&e.info("CSS variable definitions included:",{count:t})}definesAnyCSSVariable(e){return!!e&&/(--[a-zA-Z0-9-_]+)\s*:/.test(e)}definesUsedCSSVariable(e){if(!e)return!1;const t=/(--[a-zA-Z0-9-_]+)\s*:/g;let s;for(;null!==(s=t.exec(e));)if(this.usedCSSVariables.has(s[1]))return!0;return!1}checkMediaRuleUsage(e,t,s){const r=[];for(const t of e.nestedRules)t.used&&(this.extractCSSVariables(t.cssText).forEach((e=>this.usedCSSVariables.add(e))),r.push(t));if(r.length>0){e.used=!0;const t=r.map((e=>e.cssText)).join("\n ");e.cssText=`@media ${e.mediaText} {\n ${t}\n}`}else e.used=!1,e.cssText="";this.results.selectors.set(e.selector,{used:e.used,cssText:e.cssText,sheet:t,type:"media"})}async checkPropertyUsage(){}generateReport(){const e=Array.from(this.results.selectors.values()).filter((e=>e.used)),t=this.results.selectors.size,s=t>0?(e.length/t*100).toFixed(2):0,r=this.buildStructuredCSS();return{summary:{totalStylesheets:this.results.sheets.length,accessibleStylesheets:this.results.sheets.filter((e=>e.accessible)).length,totalRules:t,usedRules:e.length,unusedRules:t-e.length,usagePercentage:`${s}%`,deviceType:1===this.deviceType?"mobile":"desktop",structuredCSSSize:JSON.stringify(r).length,cssVariables:this.usedCSSVariables.size},css:{structured:r}}}buildStructuredCSS(){const t={};return this.cssStructure.forEach(((e,s)=>{t[s]={},e.forEach(((e,r)=>{t[s][r]={...e}}))})),e.info("Structured CSS built:",{mediaQueries:Object.keys(t).length,totalSelectors:Object.values(t).reduce(((e,t)=>e+Object.keys(t).length),0),deviceType:1===this.deviceType?"mobile":"desktop"}),t}getStructuredCSS(){return this.buildStructuredCSS()}async prepareStructuredCSS(t){if(!t)return null;const s=JSON.stringify(t);return e.info("Structured CSS prepared for transmission:",{size:s.length,mediaQueries:Object.keys(t).length}),{data:t,originalSize:s.length}}}const c={runProfiling:async function(){if(0===window.innerWidth||0===window.innerHeight)return e.info("Window must have non-zero dimensions for image detection."),null;if("hidden"===document.visibilityState&&!document.prerendering)return e.info("Page opened in background tab so image detection is not performed."),null;const{pageProfileId:c,missingDevices:a,bgSelectors:l,pageUrl:u}=window.spcDataOptimizer||{},d=s.getDeviceType(),f=c,h=a?a.split(","):[];if(e.info("Device Type:",d),e.info("Missing Devices:",h),e.info("Profile ID:",c),e.info("Backgroun
1d Selectors:",l||"None provided"),!h.includes(d.toString()))return e.info("Skipping device type, data already exists:",d),null;if(t.isProcessed(f,d))return e.info("Skipping detection, already processed this device/URL combination"),null;"complete"!==document.readyState&&(e.info("Waiting for page to fully load..."),await n.waitForPageLoad(),e.info("Page fully loaded, proceeding with detection")),await n.waitForIdleTime();let g=null;if("1"===window.spcDataOptimizer?.unusedCss||1===window.spcDataOptimizer?.unusedCss){e.info("Unused CSS removal is enabled, starting CSS analysis");try{const t=new o,s=await t.analyze();if(s&&s.css.structured){const r=await t.prepareStructuredCSS(s.css.structured);r&&(g={css:r.data},e.info("Structured CSS analysis data prepared for API:",{dataSize:r.originalSize,deviceType:s.summary.deviceType}))}}catch(t){e.error("CSS analysis failed:",t)}}else e.info("Unused CSS removal is disabled, skipping CSS analysis");const m=await i.detectLcpElement();let p="hidden"!==document.visibilityState,S=!1;const y=n.debounce((()=>{S=!0,e.info("Window resized during detection, results may be affected")}),100),b=()=>{p="hidden"!==document.visibilityState,e.info("Page visibility changed:",p?"visible":"hidden")};window.addEventListener("resize",y,{passive:!0}),document.addEventListener("visibilitychange",b);const T=[],w=new Map,C=new IntersectionObserver((t=>{t.forEach((t=>{if(t.isIntersecting){const s=t.target;if("IMG"===s.tagName){const e=parseInt(s.getAttribute("data-spc-id"),10);isNaN(e)||T.includes(e)||T.push(e)}else if(s.hasAttribute("data-spc-bg-selector")){const t=s.getAttribute("data-spc-bg-selector"),r=s.getAttribute("data-spc-specific-selector");if(t&&r&&v.has(t)){const s=v.get(t);s.includes(r)||(s.push(r),e.info(`Element with selector "${r}" is above the fold`))}}}}))}),{threshold:.1});document.querySelectorAll("img[data-spc-id]").forEach((t=>{const s=parseInt(t.getAttribute("data-spc-id"),10);isNaN(s)?e.warn("Invalid data-spc-id:",t.getAttribute("data-spc-id")):(w.set(t,s),
1C.observe(t))}));const v=new Map,x=new Map;if(l&&Array.isArray(l)&&l.length>0){e.info("Processing background selectors:",l);let t=0;l.forEach((s=>{try{const r=document.querySelectorAll(s);if(0===r.length)return void e.warn("No elements found for background selector:",s);v.set(s,[]),t+=function(t,s,r,i){const o=new MutationObserver((t=>{for(const s of t)if("attributes"===s.type&&"class"===s.attributeName){const t=s.target;if(t.classList.contains("spc-bg-lazyloaded")&&n.hasBackgroundImage(t)){i.observe(t),o.disconnect(t);const s=t.getAttribute("data-spc-specific-selector");e.info(`Background element "${s}" is now observable`)}}})),c=[];return t.forEach((e=>{const t=n.getUniqueSelector(e);e.setAttribute("data-spc-bg-selector",s),e.setAttribute("data-spc-specific-selector",t),e.classList.contains("spc-bg-lazyloaded")&&n.hasBackgroundImage(e)?i.observe(e):c.push(e)})),c.length>0&&(c.forEach((e=>{o.observe(e,{attributes:!0,attributeFilter:["class"]})})),setTimeout((()=>{o.disconnect(),e.info(`Stopped waiting for lazyload on ${s} elements`)}),5e3)),c.length}(Array.from(r),s,0,C),e.info(`Processed ${r.length} elements for background selector: ${s}`)}catch(t){e.error("Error processing background selector:",s,t)}})),function(t,s){t.forEach((t=>{const r=new Map;s.set(t,r),document.querySelectorAll(t).forEach((t=>{if(t.classList.contains("spc-bg-lazyloaded")){const s=n.hasBackgroundImage(t,!0);if(!1===s)return;const i=n.getUniqueSelector(t);if(!i)return;const o=[],c=/url\(['"]?(.*?)['"]?\)/g;let a;for(;null!==(a=c.exec(s));)a[1]&&o.push(a[1]);o.length>0&&(r.set(i,o),e.info(`Found background image URL(s) for "${i}":`,o))}}))}))}(l,x);const s=t>0?600:300;e.info(`Waiting ${s}ms for ${t} pending background elements`),await new Promise((e=>setTimeout(e,s)))}else await new Promise((e=>setTimeout(e,300)));if(C.disconnect(),window.removeEventListener("resize",y),document.removeEventListener("visibilitychange",b),document.querySelectorAll("[data-spc-bg-selector]").forEach((e=>{e.removeAttribute("data-spc-bg-selector"),e.removeAttribute("data-spc-specific-selector")})),S&&e.warn("Window was resized during detection, results may not be accurate"),p||e.warn("Page became hidden during detection, results may not be accurate"),e.info("Above the fold images with data-spc-id:",T),e.info("Backgroun
1d selectors:",v),T.length>0||v.size>0||m.imageId||m.bgSelector||g){const t={};v.forEach(((e,s)=>{t[s]={},e.forEach((e=>{t[s][e]=null,x.has(s)&&x.get(s).has(e)&&(t[s][e]=x.get(s).get(e))}))}));const s={d,a:T,b:t,u:f,p:u,t:window.spcDataOptimizer._t,h:window.spcDataOptimizer.hmac,l:{i:m.imageId,s:m.bgSelector,u:m.bgUrls},c:g};return e.info("Sending data with LCP and CSS information:",{lcpImageId:m.imageId,lcpBgSelector:m.bgSelector,lcpBgUrls:m.bgUrls,hasStructuredCSS:!!g}),e.info("Sending background selectors:",t),r.sendToRestApi(s),s}return e.info("No above-the-fold images, background elements, LCP elements, or structured CSS analysis data found"),null}};window.spcLogger=e,function(){function e(){c&&c.runProfiling?c.runProfiling():console.error("[SPC] Main module not available")}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",e):e()}()})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.