ai-progress-controls 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +823 -0
  3. package/dist/ai-progress-controls.es.js +7191 -0
  4. package/dist/ai-progress-controls.es.js.map +1 -0
  5. package/dist/ai-progress-controls.umd.js +2 -0
  6. package/dist/ai-progress-controls.umd.js.map +1 -0
  7. package/dist/index.d.ts +2212 -0
  8. package/package.json +105 -0
  9. package/src/__tests__/setup.ts +93 -0
  10. package/src/core/base/AIControl.ts +230 -0
  11. package/src/core/base/index.ts +3 -0
  12. package/src/core/base/types.ts +77 -0
  13. package/src/core/base/utils.ts +168 -0
  14. package/src/core/batch-progress/BatchProgress.test.ts +458 -0
  15. package/src/core/batch-progress/BatchProgress.ts +760 -0
  16. package/src/core/batch-progress/index.ts +14 -0
  17. package/src/core/batch-progress/styles.ts +480 -0
  18. package/src/core/batch-progress/types.ts +169 -0
  19. package/src/core/model-loader/ModelLoader.test.ts +311 -0
  20. package/src/core/model-loader/ModelLoader.ts +673 -0
  21. package/src/core/model-loader/index.ts +2 -0
  22. package/src/core/model-loader/styles.ts +496 -0
  23. package/src/core/model-loader/types.ts +127 -0
  24. package/src/core/parameter-panel/ParameterPanel.test.ts +856 -0
  25. package/src/core/parameter-panel/ParameterPanel.ts +877 -0
  26. package/src/core/parameter-panel/index.ts +14 -0
  27. package/src/core/parameter-panel/styles.ts +323 -0
  28. package/src/core/parameter-panel/types.ts +278 -0
  29. package/src/core/parameter-slider/ParameterSlider.test.ts +299 -0
  30. package/src/core/parameter-slider/ParameterSlider.ts +653 -0
  31. package/src/core/parameter-slider/index.ts +8 -0
  32. package/src/core/parameter-slider/styles.ts +493 -0
  33. package/src/core/parameter-slider/types.ts +107 -0
  34. package/src/core/queue-progress/QueueProgress.test.ts +344 -0
  35. package/src/core/queue-progress/QueueProgress.ts +563 -0
  36. package/src/core/queue-progress/index.ts +5 -0
  37. package/src/core/queue-progress/styles.ts +469 -0
  38. package/src/core/queue-progress/types.ts +130 -0
  39. package/src/core/retry-progress/RetryProgress.test.ts +397 -0
  40. package/src/core/retry-progress/RetryProgress.ts +957 -0
  41. package/src/core/retry-progress/index.ts +6 -0
  42. package/src/core/retry-progress/styles.ts +530 -0
  43. package/src/core/retry-progress/types.ts +176 -0
  44. package/src/core/stream-progress/StreamProgress.test.ts +531 -0
  45. package/src/core/stream-progress/StreamProgress.ts +517 -0
  46. package/src/core/stream-progress/index.ts +2 -0
  47. package/src/core/stream-progress/styles.ts +349 -0
  48. package/src/core/stream-progress/types.ts +82 -0
  49. package/src/index.ts +19 -0
@@ -0,0 +1,2 @@
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t="undefined"!=typeof globalThis?globalThis:t||self).AIProgressControls={})}(this,function(t){"use strict";var e=Object.defineProperty,n=(t,n,s)=>((t,n,s)=>n in t?e(t,n,{enumerable:!0,configurable:!0,writable:!0,value:s}):t[n]=s)(t,"symbol"!=typeof n?n+"":n,s);class s extends HTMLElement{constructor(t={}){super(),n(this,"config"),n(this,"_disabled",!1),n(this,"startTime",0),this.config={debug:!1,disabled:!1,...t},this._disabled=this.config.disabled??!1}connectedCallback(){this.log("Component connected to DOM"),this.applyTheme(),this.setupAccessibility(),this.render()}disconnectedCallback(){this.log("Component disconnected from DOM"),this.cleanup()}attributeChangedCallback(t,e,n){this.log(`Attribute ${t} changed from ${e} to ${n}`),this.handleAttributeChange(t,e,n)}applyTheme(t){var e;if(!t)return;const n=null==(e=this.shadowRoot)?void 0:e.host;n&&Object.entries(t).forEach(([t,e])=>{const s=`--ai-${t.replaceAll(/([A-Z])/g,"-$1").toLowerCase()}`;n.style.setProperty(s,e)})}setupAccessibility(){this.getAttribute("role")||this.setAttribute("role",this.getDefaultRole()),this.config.ariaLabel&&this.setAttribute("aria-label",this.config.ariaLabel),this._disabled&&this.setAttribute("aria-disabled","true")}emit(t,e){const n=new CustomEvent(t,{detail:e,bubbles:!0,composed:!0});this.dispatchEvent(n),this.log(`Event emitted: ${t}`,e)}log(t,...e){this.config.debug&&console.log(`[${this.constructor.name}] ${t}`,...e)}logError(t,e){console.error(`[${this.constructor.name}] ERROR: ${t}`,e)}startTimer(){this.startTime=Date.now()}getElapsedTime(){return Date.now()-this.startTime}formatNumber(t){return t>=1e6?`${(t/1e6).toFixed(1)}M`:t>=1e3?`${(t/1e3).toFixed(1)}K`:t.toString()}formatDuration(t){const e=Math.floor(t/1e3),n=Math.floor(e/60),s=Math.floor(n/60);return s>0?`${s}h ${n%60}m`:n>0?`${n}m ${e%60}s`:`${e}s`}calculatePercentage(t,e){return 0===e?0:Math.min(100,Math.max(0,t/e*100))}get disabled(){return this._disabled}set disabled(t){this._disabled=t,t?(this.setAttribute("aria-disabled","true"),this.setAttribute("disabled","")):(this.setAttribute("aria-disabled","false"),this.removeAttribute("disabled")),this.render()}getDefaultRole(){return"region"}handleAttributeChange(t,e,n){}cleanup(){}}function a(t,e){let n;return function(...s){n||(t.apply(this,s),n=!0,setTimeout(()=>n=!1,e))}}function i(t,e,n){return Math.min(Math.max(t,e),n)}function r(t,e=2){if(0===t)return"0 Bytes";const n=Math.max(0,e),s=Math.floor(Math.log(t)/Math.log(1024));return`${Number.parseFloat((t/Math.pow(1024,s)).toFixed(n))} ${["Bytes","KB","MB","GB","TB"][s]}`}function o(t,e=4){return`$${t.toFixed(e)}`}function l(t){if(t<60)return`${Math.round(t)}s`;const e=Math.floor(t/60),n=Math.round(t%60);if(e<60)return n>0?`${e}m ${n}s`:`${e}m`;const s=Math.floor(e/60),a=e%60;return a>0?`${s}h ${a}m`:`${s}h`}class d extends s{constructor(t={}){super({debug:t.debug??!1,className:t.className,ariaLabel:t.ariaLabel??"AI Stream Progress"}),n(this,"config"),n(this,"state"),n(this,"updateThrottled"),n(this,"animationFrame",0),n(this,"displayTokens",0),this.config={maxTokens:t.maxTokens??4e3,costPerToken:t.costPerToken??2e-5,currency:t.currency??"$",showRate:t.showRate??!0,showCost:t.showCost??!0,showProgressBar:t.showProgressBar??!0,showCancelButton:t.showCancelButton??!0,smoothProgress:t.smoothProgress??!0,updateThrottle:t.updateThrottle??100,cancelLabel:t.cancelLabel??"Cancel",debug:t.debug??!1,className:t.className??"",ariaLabel:t.ariaLabel??"AI Stream Progress",cursorFeedback:t.cursorFeedback??!0,size:t.size??"default",variant:t.variant??"default",animation:t.animation??"none"},this.state={tokensGenerated:0,tokensPerSecond:0,totalCost:0,isStreaming:!1,isPaused:!1,isCancelled:!1,startTime:0,lastUpdateTime:0},this.updateThrottled=a(this._updateInternal.bind(this),this.config.updateThrottle),this.attachShadow({mode:"open"})}static get observedAttributes(){return["max-tokens","cost-per-token","disabled","size","variant","animation"]}connectedCallback(){super.connectedCallback(),this.log("StreamProgress mounted")}disconnectedCallback(){this.cleanup(),super.disconnectedCallback()}cleanup(){this.animationFrame&&cancelAnimationFrame(this.animationFrame)}updateCursor(){this.config.cursorFeedback&&(this.state.isStreaming&&!this.state.isPaused?this.style.cursor="progress":this.state.isCancelled?this.style.cursor="not-allowed":this.style.cursor="default")}getDefaultRole(){return"progressbar"}handleAttributeChange(t,e,n){switch(t){case"max-tokens":this.config.maxTokens=Number.parseInt(n,10)||4e3,this.render();break;case"cost-per-token":this.config.costPerToken=Number.parseFloat(n)||2e-5,this.render();break;case"disabled":this._disabled=null!==n,this.render();break;case"size":this.config.size=n,this.render();break;case"variant":this.config.variant=n,this.render();break;case"animation":this.config.animation=n,this.render()}}start(t){this.state.isStreaming?this.log("Already streaming"):(this.state={...this.state,isStreaming:!0,isPaused:!1,isCancelled:!1,tokensGenerated:0,tokensPerSecond:0,totalCost:0,startTime:Date.now(),lastUpdateTime:Date.now(),message:t},this.displayTokens=0,this.startTimer(),this.render(),this.updateCursor(),this.emit("streamstart",{startTime:this.state.startTime,message:t}),this.log("Stream started",this.state))}update(t){this.state.isStreaming&&!this.state.isCancelled&&this.updateThrottled(t)}_updateInternal(t){const e=Date.now(),n=t.tokensGenerated;let s=t.tokensPerSecond??0;if(!s&&this.state.lastUpdateTime){const t=(e-this.state.lastUpdateTime)/1e3,a=n-this.state.tokensGenerated;s=t>0?a/t:0}const a=n*this.config.costPerToken;this.state={...this.state,tokensGenerated:n,tokensPerSecond:s,totalCost:a,lastUpdateTime:e,message:t.message??this.state.message},this.config.smoothProgress?this.animateProgress():(this.displayTokens=n,this.render()),this.setAttribute("aria-valuenow",n.toString()),this.setAttribute("aria-valuemax",this.config.maxTokens.toString()),this.emit("streamupdate",this.state),this.log("Progress updated",this.state)}animateProgress(){const t=()=>{const e=this.state.tokensGenerated-this.displayTokens;if(Math.abs(e)<.1)return this.displayTokens=this.state.tokensGenerated,void this.render();this.displayTokens+=.2*e,this.render(),this.animationFrame=requestAnimationFrame(t)};this.animationFrame&&cancelAnimationFrame(this.animationFrame),this.animationFrame=requestAnimationFrame(t)}complete(){if(!this.state.isStreaming)return;const t=this.getElapsedTime(),e=this.state.tokensGenerated/(t/1e3),n={tokensGenerated:this.state.tokensGenerated,duration:t,totalCost:this.state.totalCost,averageRate:e};this.state={...this.state,isStreaming:!1},this.render(),this.updateCursor(),this.emit("streamcomplete",n),this.log("Stream completed",n)}cancel(t="user"){if(!this.state.isStreaming||this.state.isCancelled)return;const e=this.getElapsedTime(),n={tokensGenerated:this.state.tokensGenerated,duration:e,reason:t};this.state={...this.state,isStreaming:!1,isCancelled:!0},this.render(),this.updateCursor(),this.emit("streamcancel",n),this.log("Stream cancelled",n)}reset(){this.state={tokensGenerated:0,tokensPerSecond:0,totalCost:0,isStreaming:!1,isPaused:!1,isCancelled:!1,startTime:0,lastUpdateTime:0},this.displayTokens=0,this.animationFrame&&cancelAnimationFrame(this.animationFrame),this.render(),this.updateCursor(),this.log("Component reset")}_syncAttributes(){this.config.size&&this.getAttribute("size")!==this.config.size&&this.setAttribute("size",this.config.size),this.config.variant&&this.getAttribute("variant")!==this.config.variant&&this.setAttribute("variant",this.config.variant),this.config.animation&&this.getAttribute("animation")!==this.config.animation&&this.setAttribute("animation",this.config.animation)}_getProgressBarHtml(t){return this.config.showProgressBar?`\n <div class="progress-bar">\n <div class="progress-fill" style="width: ${t}%"></div>\n </div>\n `:""}_getStatsHtml(t,e,n){const s=this.config.showRate?`\n <div class="stat-item">\n <span class="stat-label">Rate:</span>\n <span class="stat-value">${e} tokens/s</span>\n </div>\n `:"",a=this.config.showCost?`\n <div class="stat-item">\n <span class="stat-label">Cost:</span>\n <span class="stat-value">${n}</span>\n </div>\n `:"";return`\n <div class="stats">\n <div class="stat-item">\n <span class="stat-label">Tokens:</span>\n <span class="stat-value">${t} / ${this.config.maxTokens}</span>\n </div>\n ${s}\n ${a}\n </div>\n `}_getCancelButtonHtml(){return this.config.showCancelButton&&this.state.isStreaming?`\n <button class="cancel-button" aria-label="Cancel streaming">\n ${this.config.cancelLabel}\n </button>\n `:""}_getStatusClass(){return this.state.isCancelled?"cancelled":this.state.isStreaming?"streaming":"idle"}_attachEventListeners(){var t;if(!this.config.showCancelButton)return;const e=null==(t=this.shadowRoot)?void 0:t.querySelector(".cancel-button");e&&e.addEventListener("click",()=>this.cancel("user"))}render(){if(!this.shadowRoot)return;this._syncAttributes();const t=this.calculatePercentage(this.displayTokens,this.config.maxTokens),e=Math.round(this.displayTokens),n=Math.round(this.state.tokensPerSecond),s=o(this.state.totalCost),a=this._getProgressBarHtml(t),i=this._getStatsHtml(e,n,s),r=this.state.message?`<div class="message">${this.state.message}</div>`:"",l=this._getCancelButtonHtml(),d=this._getStatusClass();this.shadowRoot.innerHTML=`\n \n<style>\n:host {\n /* CSS variables inherit from document root with fallback defaults */\n \n display: block;\n font-family: var(--ai-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);\n font-size: var(--ai-font-size, 14px);\n}\n\n:host([style*="cursor: progress"]) .stream-progress {\n cursor: progress;\n}\n\n:host([style*="cursor: not-allowed"]) .stream-progress {\n cursor: not-allowed;\n}\n\n:host([style*="cursor: default"]) .stream-progress {\n cursor: default;\n}\n\n.stream-progress {\n background: var(--ai-background-color, #ffffff);\n border: 1px solid var(--ai-border-color, #e5e7eb);\n border-radius: var(--ai-border-radius, 8px);\n padding: var(--ai-spacing, 12px);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n.stream-progress.streaming {\n border-color: var(--ai-primary-color, #3b82f6);\n}\n\n.stream-progress.cancelled {\n border-color: #ef4444;\n opacity: 0.7;\n}\n\n.message {\n color: var(--ai-text-color, #1f2937);\n font-weight: 500;\n margin-bottom: calc(var(--ai-spacing, 12px) * 0.75);\n font-size: 13px;\n}\n\n.progress-bar {\n width: 100%;\n height: 8px;\n background: #f3f4f6;\n border-radius: 4px;\n overflow: hidden;\n margin-bottom: var(--ai-spacing, 12px);\n}\n\n.progress-fill {\n height: 100%;\n background: linear-gradient(90deg, var(--ai-primary-color, #3b82f6), var(--ai-secondary-color, #10b981));\n transition: width 0.3s ease;\n border-radius: 4px;\n}\n\n.streaming .progress-fill {\n /* Default pulse animation - will be overridden by animation attribute */\n}\n\n@keyframes pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.8;\n }\n}\n\n.stats {\n display: flex;\n justify-content: space-between;\n align-items: center;\n flex-wrap: wrap;\n gap: calc(var(--ai-spacing, 12px) * 0.75);\n margin-bottom: var(--ai-spacing, 12px);\n}\n\n.stat-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.stat-label {\n font-size: 11px;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n font-weight: 600;\n}\n\n.stat-value {\n font-size: 16px;\n color: var(--ai-text-color, #1f2937);\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n}\n\n.cancel-button {\n width: 100%;\n padding: 8px 16px;\n background: #ef4444;\n color: white;\n border: none;\n border-radius: calc(var(--ai-border-radius, 8px) * 0.75);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.2s ease;\n font-family: inherit;\n}\n\n.cancel-button:hover {\n background: #dc2626;\n}\n\n.cancel-button:active {\n transform: translateY(1px);\n}\n\n.cancel-button:focus-visible {\n outline: 2px solid var(--ai-primary-color, #3b82f6);\n outline-offset: 2px;\n}\n\n/* Size variants */\n:host([size="compact"]) .stream-progress {\n padding: 8px;\n font-size: 12px;\n}\n\n:host([size="compact"]) .progress-bar {\n height: 6px;\n}\n\n:host([size="compact"]) .message {\n font-size: 11px;\n margin-bottom: 6px;\n}\n\n:host([size="compact"]) .stat-label {\n font-size: 10px;\n}\n\n:host([size="compact"]) .stat-value {\n font-size: 14px;\n}\n\n:host([size="compact"]) .cancel-button {\n padding: 6px 12px;\n font-size: 11px;\n}\n\n:host([size="large"]) .stream-progress {\n padding: 16px;\n font-size: 16px;\n}\n\n:host([size="large"]) .progress-bar {\n height: 10px;\n}\n\n:host([size="large"]) .message {\n font-size: 15px;\n margin-bottom: 12px;\n}\n\n:host([size="large"]) .stat-label {\n font-size: 12px;\n}\n\n:host([size="large"]) .stat-value {\n font-size: 18px;\n}\n\n:host([size="large"]) .cancel-button {\n padding: 10px 20px;\n font-size: 15px;\n}\n\n/* Visual Variants */\n\n/* Minimal variant - clean, no shadows */\n:host([variant="minimal"]) .stream-progress {\n box-shadow: none;\n border: 1px solid var(--ai-border-color, #e5e7eb);\n}\n\n:host([variant="minimal"]) .progress-bar {\n background: transparent;\n border: 1px solid var(--ai-border-color, #e5e7eb);\n}\n\n/* Gradient variant - colorful gradients */\n:host([variant="gradient"]) .progress-fill {\n background: linear-gradient(\n 90deg,\n var(--ai-primary-color, #3b82f6),\n var(--ai-secondary-color, #10b981),\n var(--ai-primary-color, #3b82f6)\n );\n background-size: 200% 100%;\n animation: gradient-shift 3s ease-in-out infinite;\n}\n\n@keyframes gradient-shift {\n 0%, 100% { background-position: 0% 50%; }\n 50% { background-position: 100% 50%; }\n}\n\n/* Override gradient animation when custom animation is set */\n:host([animation]:not([animation="none"])[variant="gradient"]) .progress-fill {\n animation: none !important;\n}\n\n/* Glassmorphic variant - frosted glass effect */\n:host([variant="glassmorphic"]) .stream-progress {\n background: rgba(255, 255, 255, 0.1);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.2);\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);\n}\n\n:host([variant="glassmorphic"]) .progress-bar {\n background: rgba(0, 0, 0, 0.1);\n}\n\n:host([variant="glassmorphic"]) .progress-fill {\n background: linear-gradient(\n 90deg,\n rgba(59, 130, 246, 0.8),\n rgba(16, 185, 129, 0.8)\n );\n}\n\n/* Animation Effects */\n\n/* Striped animation - layer stripes on top of existing background */\n:host([animation="striped"]) .streaming .progress-fill,\n:host([animation="striped"]) .progress-fill {\n background-image: \n linear-gradient(\n 45deg,\n rgba(255, 255, 255, 0.2) 25%,\n transparent 25%,\n transparent 50%,\n rgba(255, 255, 255, 0.2) 50%,\n rgba(255, 255, 255, 0.2) 75%,\n transparent 75%,\n transparent\n ),\n linear-gradient(to right, var(--ai-primary-color, #3b82f6), var(--ai-primary-color, #3b82f6)) !important;\n background-size: 2rem 2rem, 100% 100% !important;\n animation: progress-stripes 3s linear infinite !important;\n}\n\n@keyframes progress-stripes {\n 0% { background-position: 0 0, 0 0; }\n 100% { background-position: 2rem 0, 0 0; }\n}\n\n/* Pulse animation */\n:host([animation="pulse"]) .streaming .progress-fill,\n:host([animation="pulse"]) .progress-fill {\n animation: progress-pulse 4s ease-in-out infinite !important;\n}\n\n@keyframes progress-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n}\n\n/* Glow animation */\n:host([animation="glow"]) .streaming .progress-fill,\n:host([animation="glow"]) .progress-fill {\n animation: progress-glow 4s ease-in-out infinite !important;\n}\n\n@keyframes progress-glow {\n 0%, 100% { \n box-shadow: 0 0 5px var(--ai-primary-color, #3b82f6),\n 0 0 10px var(--ai-primary-color, #3b82f6);\n }\n 50% { \n box-shadow: 0 0 20px var(--ai-primary-color, #3b82f6), \n 0 0 35px var(--ai-primary-color, #3b82f6),\n 0 0 50px var(--ai-primary-color, #3b82f6);\n }\n}\n\n/* Dark mode support */\n@media (prefers-color-scheme: dark) {\n :host {\n --ai-background-color: #1f2937;\n --ai-text-color: #f9fafb;\n --ai-border-color: #374151;\n }\n \n .progress-bar {\n background: #374151;\n }\n \n .stat-label {\n color: #9ca3af;\n }\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .progress-fill {\n transition: none;\n }\n \n .streaming .progress-fill {\n animation: none;\n }\n \n .cancel-button {\n transition: none;\n }\n}\n\n/* Responsive design */\n@media (max-width: 640px) {\n .stats {\n flex-direction: column;\n align-items: flex-start;\n }\n \n .stat-item {\n width: 100%;\n }\n}\n\n/* Disabled state */\n:host([disabled]) .stream-progress {\n opacity: 0.5;\n pointer-events: none;\n}\n</style>\n\n <div class="stream-progress ${d} ${this.config.className}">\n ${r}\n ${a}\n ${i}\n ${l}\n </div>\n `,this._attachEventListeners()}getState(){return{...this.state}}getConfig(){return{...this.config}}}customElements.get("stream-progress")||customElements.define("stream-progress",d);class c extends s{constructor(t={}){super({debug:t.debug??!1,className:t.className,ariaLabel:t.ariaLabel??"Model Loading Progress",cursorFeedback:t.cursorFeedback??!0}),n(this,"config"),n(this,"state"),n(this,"updateThrottled"),this.config={stages:t.stages??["download","load","initialize","ready"],modelName:t.modelName??"AI Model",showBytes:t.showBytes??!0,showMemoryUsage:t.showMemoryUsage??!0,showETA:t.showETA??!0,showRetryButton:t.showRetryButton??!0,smoothProgress:t.smoothProgress??!0,updateThrottle:t.updateThrottle??100,retryLabel:t.retryLabel??"Retry",cursorFeedback:t.cursorFeedback??!0,debug:t.debug??!1,className:t.className??"",ariaLabel:t.ariaLabel??"Model Loading Progress",size:t.size??"default",variant:t.variant??"default",animation:t.animation??"none"};this.state={currentStage:this.config.stages[0],stages:{download:{status:"pending",progress:0},load:{status:"pending",progress:0},initialize:{status:"pending",progress:0},ready:{status:"pending",progress:0}},isLoading:!1,hasError:!1,startTime:0},this.updateThrottled=a(this._updateStageInternal.bind(this),this.config.updateThrottle),this.attachShadow({mode:"open"})}static get observedAttributes(){return["model-name","disabled","size","variant","animation"]}connectedCallback(){super.connectedCallback(),this.log("ModelLoader mounted")}getDefaultRole(){return"progressbar"}updateCursor(){this.config.cursorFeedback&&(this.state.isLoading?this.style.cursor="progress":this.state.hasError?this.style.cursor="not-allowed":this.style.cursor="default")}handleAttributeChange(t,e,n){switch(t){case"model-name":this.config.modelName=n||"AI Model",this.render();break;case"disabled":this._disabled=null!==n,this.render();break;case"size":this.config.size=n,this.render();break;case"variant":this.config.variant=n,this.render();break;case"animation":this.config.animation=n,this.render()}}start(t){if(this.state.isLoading)return void this.log("Already loading");const e={download:{status:"pending",progress:0},load:{status:"pending",progress:0},initialize:{status:"pending",progress:0},ready:{status:"pending",progress:0}},n=this.config.stages[0];e[n]={status:"in-progress",progress:0,message:t,startTime:Date.now()},this.state={currentStage:n,stages:e,isLoading:!0,hasError:!1,startTime:Date.now()},this.startTimer(),this.render(),this.updateCursor(),this.emit("loadstart",{stage:n,timestamp:Date.now()}),this.log("Loading started",this.state)}updateStage(t,e){this.state.isLoading&&!this.state.hasError&&this.updateThrottled({stage:t,...e})}_updateStageInternal(t){const{stage:e,progress:n,bytesLoaded:s,totalBytes:a,message:i,memoryUsage:r}=t;if(!this.state.stages[e])return void this.logError(`Invalid stage: ${e}`);let o=n;void 0===o&&void 0!==s&&void 0!==a&&(o=this.calculatePercentage(s,a));const l=this.state.stages[e],d={...l,progress:o??l.progress,message:i,bytesLoaded:s,totalBytes:a};this.state={...this.state,stages:{...this.state.stages,[e]:d},memoryUsage:r??this.state.memoryUsage},this.render(),this.emit("stageupdate",{stage:e,...d}),this.log("Stage updated",e,d)}setStage(t,e={}){if(!this.state.isLoading||this.state.hasError)return;if(!this.config.stages.includes(t))return void this.logError(`Stage ${t} not in configured stages`);const n=this.state.currentStage,s=this.state.stages[n];this.state.stages[n]={...s,status:"completed",progress:100,endTime:Date.now()};const a=this.state.stages[t];this.state.stages[t]={...a,status:"in-progress",progress:e.progress??0,message:e.message,startTime:Date.now()},this.state={...this.state,currentStage:t},this.render();const i={previousStage:n,currentStage:t,timestamp:Date.now()};this.emit("stagechange",i),this.log("Stage changed",i)}completeStage(t){const e=this.config.stages.indexOf(this.state.currentStage),n=this.config.stages[e+1];n?this.setStage(n,{message:t}):this.complete()}complete(){if(!this.state.isLoading)return;const t=this.getElapsedTime(),e={...this.state.stages};this.config.stages.forEach(t=>{const n=e[t];e[t]={...n,status:"completed",progress:100,endTime:n.endTime??Date.now()}}),this.state={...this.state,stages:e,isLoading:!1,currentStage:"ready"};const n={duration:t,memoryUsage:this.state.memoryUsage,stages:this.state.stages};this.render(),this.updateCursor(),this.emit("loadcomplete",n),this.log("Loading completed",n)}error(t,e){const n=e??this.state.currentStage,s=this.state.stages[n];this.state={...this.state,hasError:!0,errorMessage:t,isLoading:!1,stages:{...this.state.stages,[n]:{...s,status:"error"}}};const a={stage:n,message:t,timestamp:Date.now()};this.render(),this.updateCursor(),this.emit("loaderror",a),this.logError("Loading error",new Error(t))}retry(){this.start(),this.emit("loadretry",{timestamp:Date.now()}),this.log("Retrying load")}reset(){this.state={currentStage:this.config.stages[0],stages:{download:{status:"pending",progress:0},load:{status:"pending",progress:0},initialize:{status:"pending",progress:0},ready:{status:"pending",progress:0}},isLoading:!1,hasError:!1,startTime:0},this.render(),this.log("Component reset")}getStageIcon(t){switch(t){case"pending":default:return"β—‹";case"in-progress":return"◐";case"completed":return"βœ“";case"error":return"βœ•"}}calculateETA(){var t;if(!this.state.isLoading||this.state.hasError)return"--";const e=this.getElapsedTime(),n=this.config.stages.indexOf(this.state.currentStage),s=this.config.stages.length,a=n,i=(null==(t=this.state.stages[this.state.currentStage])?void 0:t.progress)??0;if(0===a&&0===i)return"--";const r=(a+i/100)/s;if(0===r)return"--";const o=e/r-e;return this.formatDuration(Math.max(0,o))}getOverallStatus(){var t;return this.state.hasError?"error":this.state.isLoading?"loading":this.state.isLoading||"completed"!==(null==(t=this.state.stages.ready)?void 0:t.status)?"idle":"completed"}getStatusBadgeText(t){return this.state.hasError?"Error":this.state.isLoading?"Loading":"completed"===t?"Ready":"Idle"}generateStagesHtml(){return this.config.stages.map(t=>{const e=this.state.stages[t];if(!e)return"";const n=this.getStageIcon(e.status),s=`${Math.round(e.progress)}%`,a=e.message?`<div class="stage-message">${e.message}</div>`:"";return`\n <div class="stage ${e.status}">\n <div class="stage-header">\n <div class="stage-info">\n <div class="stage-icon ${e.status}">${n}</div>\n <span class="stage-name">${t}</span>\n </div>\n <span class="stage-progress-text">${s}</span>\n </div>\n ${a}\n <div class="progress-bar">\n <div class="progress-fill ${"error"===e.status?"error":""}" style="width: ${e.progress}%"></div>\n </div>\n </div>\n `}).join("")}generateStatsHtml(){const t=[];if(this.config.showBytes&&this.state.stages.download){const{bytesLoaded:e,totalBytes:n}=this.state.stages.download;void 0!==e&&void 0!==n&&t.push(`\n <div class="stat-item">\n <span class="stat-label">Downloaded</span>\n <span class="stat-value">${r(e)} / ${r(n)}</span>\n </div>\n `)}return this.config.showMemoryUsage&&void 0!==this.state.memoryUsage&&t.push(`\n <div class="stat-item">\n <span class="stat-label">Memory</span>\n <span class="stat-value">${this.state.memoryUsage.toFixed(0)} MB</span>\n </div>\n `),this.config.showETA&&this.state.isLoading&&t.push(`\n <div class="stat-item">\n <span class="stat-label">ETA</span>\n <span class="stat-value">${this.calculateETA()}</span>\n </div>\n `),t.length>0?`<div class="stats">${t.join("")}</div>`:""}render(){if(!this.shadowRoot)return;this.config.size&&this.getAttribute("size")!==this.config.size&&this.setAttribute("size",this.config.size),this.config.variant&&this.getAttribute("variant")!==this.config.variant&&this.setAttribute("variant",this.config.variant),this.config.animation&&this.getAttribute("animation")!==this.config.animation&&this.setAttribute("animation",this.config.animation);const t=this.getOverallStatus(),e=this.getStatusBadgeText(t),n=this.generateStagesHtml(),s=this.generateStatsHtml(),a=this.state.hasError?`\n <div class="error-message">\n <div class="error-icon">⚠</div>\n <div class="error-text">${this.state.errorMessage}</div>\n </div>\n `:"",i=this.config.showRetryButton&&this.state.hasError?`\n <button class="retry-button" aria-label="Retry loading">\n ${this.config.retryLabel}\n </button>\n `:"";if(this.shadowRoot.innerHTML=`\n \n<style>\n:host {\n /* CSS variables inherit from document root with fallback defaults */\n display: block;\n font-family: var(--ai-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);\n font-size: var(--ai-font-size, 14px);\n}\n\n:host([style*="cursor: progress"]) .model-loader {\n cursor: progress;\n}\n\n:host([style*="cursor: not-allowed"]) .model-loader {\n cursor: not-allowed;\n}\n\n:host([style*="cursor: default"]) .model-loader {\n cursor: default;\n}\n\n.model-loader {\n background: var(--ai-background-color, #ffffff);\n border: 1px solid var(--ai-border-color, #e5e7eb);\n border-radius: var(--ai-border-radius, 8px);\n padding: var(--ai-spacing, 12px);\n box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n\n.model-loader.loading {\n border-color: var(--ai-primary-color, #3b82f6);\n}\n\n.model-loader.error {\n border-color: #ef4444;\n}\n\n.model-loader.completed {\n border-color: var(--ai-secondary-color, #10b981);\n}\n\n.header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: var(--ai-spacing, 12px);\n}\n\n.model-name {\n font-size: 15px;\n font-weight: 600;\n color: var(--ai-text-color, #1f2937);\n}\n\n.status-badge {\n padding: 4px 10px;\n border-radius: 12px;\n font-size: 11px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.status-badge.loading {\n background: #dbeafe;\n color: #1e40af;\n}\n\n.status-badge.completed {\n background: #d1fae5;\n color: #065f46;\n}\n\n.status-badge.error {\n background: #fee2e2;\n color: #991b1b;\n}\n\n.stages {\n display: flex;\n flex-direction: column;\n gap: var(--ai-spacing, 12px);\n margin-bottom: var(--ai-spacing, 12px);\n}\n\n.stage {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n.stage-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n}\n\n.stage-info {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.stage-icon {\n width: 24px;\n height: 24px;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: bold;\n flex-shrink: 0;\n}\n\n.stage-icon.pending {\n background: #f3f4f6;\n color: #9ca3af;\n}\n\n.stage-icon.in-progress {\n background: #dbeafe;\n color: #1e40af;\n animation: pulse 2s ease-in-out infinite;\n}\n\n.stage-icon.completed {\n background: #d1fae5;\n color: #065f46;\n}\n\n.stage-icon.error {\n background: #fee2e2;\n color: #991b1b;\n}\n\n@keyframes pulse {\n 0%, 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.7;\n }\n}\n\n.stage-name {\n font-size: 13px;\n font-weight: 600;\n color: var(--ai-text-color, #1f2937);\n text-transform: capitalize;\n}\n\n.stage-progress-text {\n font-size: 12px;\n color: #6b7280;\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n}\n\n.stage-message {\n font-size: 12px;\n color: #6b7280;\n padding-left: 32px;\n}\n\n.progress-bar {\n width: 100%;\n height: 6px;\n background: #f3f4f6;\n border-radius: 3px;\n overflow: hidden;\n margin-left: 32px;\n width: calc(100% - 32px);\n}\n\n.progress-fill {\n height: 100%;\n background: linear-gradient(90deg, var(--ai-primary-color, #3b82f6), var(--ai-secondary-color, #10b981));\n transition: width 0.3s ease;\n border-radius: 3px;\n}\n\n.progress-fill.error {\n background: #ef4444;\n}\n\n.stage.in-progress .progress-fill {\n animation: shimmer 2s ease-in-out infinite;\n}\n\n@keyframes shimmer {\n 0% {\n opacity: 1;\n }\n 50% {\n opacity: 0.7;\n }\n 100% {\n opacity: 1;\n }\n}\n\n/* Override default animation when animation attribute is set */\n:host([animation]) .stage.in-progress .progress-fill {\n animation: none !important;\n}\n\n.stats {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n gap: var(--ai-spacing, 12px);\n padding-top: var(--ai-spacing, 12px);\n border-top: 1px solid var(--ai-border-color, #e5e7eb);\n margin-top: var(--ai-spacing, 12px);\n}\n\n.stat-item {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.stat-label {\n font-size: 11px;\n color: #6b7280;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n font-weight: 600;\n}\n\n.stat-value {\n font-size: 15px;\n color: var(--ai-text-color, #1f2937);\n font-weight: 600;\n font-variant-numeric: tabular-nums;\n}\n\n.error-message {\n background: #fef2f2;\n border: 1px solid #fecaca;\n border-radius: 6px;\n padding: 12px;\n margin-top: var(--ai-spacing, 12px);\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n.error-icon {\n color: #dc2626;\n font-size: 18px;\n flex-shrink: 0;\n margin-top: 2px;\n}\n\n.error-text {\n color: #991b1b;\n font-size: 13px;\n line-height: 1.5;\n}\n\n.retry-button {\n width: 100%;\n padding: 10px 16px;\n background: var(--ai-primary-color, #3b82f6);\n color: white;\n border: none;\n border-radius: calc(var(--ai-border-radius, 8px) * 0.75);\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.2s ease;\n font-family: inherit;\n margin-top: var(--ai-spacing, 12px);\n}\n\n.retry-button:hover {\n background: #2563eb;\n}\n\n.retry-button:active {\n transform: translateY(1px);\n}\n\n.retry-button:focus-visible {\n outline: 2px solid var(--ai-primary-color, #3b82f6);\n outline-offset: 2px;\n}\n\n/* Visual Variants */\n\n/* Minimal variant - clean, no shadows */\n:host([variant="minimal"]) .model-loader {\n box-shadow: none;\n border: 1px solid var(--ai-border-color, #e5e7eb);\n}\n\n:host([variant="minimal"]) .progress-bar {\n background: transparent;\n border: 1px solid var(--ai-border-color, #e5e7eb);\n}\n\n/* Gradient variant - colorful gradients */\n:host([variant="gradient"]) .progress-fill {\n background: linear-gradient(\n 90deg,\n var(--ai-primary-color, #3b82f6),\n var(--ai-secondary-color, #10b981),\n var(--ai-primary-color, #3b82f6)\n );\n background-size: 200% 100%;\n animation: gradient-shift 3s ease-in-out infinite;\n}\n\n@keyframes gradient-shift {\n 0%, 100% { background-position: 0% 50%; }\n 50% { background-position: 100% 50%; }\n}\n\n/* Override default animation when animation attribute is set */\n:host([animation][variant="gradient"]) .progress-fill {\n animation: none !important;\n}\n\n/* Glassmorphic variant - frosted glass effect */\n:host([variant="glassmorphic"]) .model-loader {\n background: rgba(255, 255, 255, 0.1);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.2);\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);\n}\n\n:host([variant="glassmorphic"]) .progress-bar {\n background: rgba(0, 0, 0, 0.1);\n}\n\n:host([variant="glassmorphic"]) .progress-fill {\n background: linear-gradient(\n 90deg,\n rgba(59, 130, 246, 0.8),\n rgba(16, 185, 129, 0.8)\n );\n}\n\n/* Animation Effects */\n\n/* Striped animation */\n:host([animation="striped"]) .progress-fill {\n background-image: \n linear-gradient(\n 45deg,\n rgba(255, 255, 255, 0.2) 25%,\n transparent 25%,\n transparent 50%,\n rgba(255, 255, 255, 0.2) 50%,\n rgba(255, 255, 255, 0.2) 75%,\n transparent 75%,\n transparent\n ),\n linear-gradient(to right, var(--ai-primary-color, #3b82f6), var(--ai-primary-color, #3b82f6)) !important;\n background-size: 2rem 2rem, 100% 100% !important;\n animation: progress-stripes 3s linear infinite !important;\n}\n\n@keyframes progress-stripes {\n 0% { background-position: 0 0, 0 0; }\n 100% { background-position: 2rem 0, 0 0; }\n}\n\n/* Pulse animation */\n:host([animation="pulse"]) .progress-fill {\n animation: progress-pulse 4s ease-in-out infinite !important;\n}\n\n@keyframes progress-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n}\n\n/* Glow animation */\n:host([animation="glow"]) .progress-fill {\n animation: progress-glow 4s ease-in-out infinite !important;\n}\n\n@keyframes progress-glow {\n 0%, 100% { \n box-shadow: 0 0 5px var(--ai-primary-color, #3b82f6),\n 0 0 10px var(--ai-primary-color, #3b82f6);\n }\n 50% { \n box-shadow: 0 0 20px var(--ai-primary-color, #3b82f6), \n 0 0 35px var(--ai-primary-color, #3b82f6),\n 0 0 50px var(--ai-primary-color, #3b82f6);\n }\n}\n\n/* Dark mode support - variables can be overridden at document level */\n@media (prefers-color-scheme: dark) {\n .progress-bar {\n background: #374151;\n }\n \n .stat-label,\n .stage-message,\n .stage-progress-text {\n color: #9ca3af;\n }\n \n .error-message {\n background: #450a0a;\n border-color: #7f1d1d;\n }\n}\n\n/* Reduced motion support */\n@media (prefers-reduced-motion: reduce) {\n .progress-fill,\n .stage-icon.in-progress,\n .stage.in-progress .progress-fill {\n animation: none;\n transition: none;\n }\n \n .retry-button {\n transition: none;\n }\n}\n\n/* Size variants */\n:host([size="compact"]) .model-loader {\n padding: 8px;\n font-size: 12px;\n}\n\n:host([size="compact"]) .progress-bar {\n height: 6px;\n}\n\n:host([size="compact"]) .model-name {\n font-size: 13px;\n}\n\n:host([size="compact"]) .status-badge {\n padding: 3px 8px;\n font-size: 10px;\n}\n\n:host([size="compact"]) .stage-name {\n font-size: 11px;\n}\n\n:host([size="compact"]) .stat-value {\n font-size: 14px;\n}\n\n:host([size="large"]) .model-loader {\n padding: 16px;\n font-size: 16px;\n}\n\n:host([size="large"]) .progress-bar {\n height: 10px;\n}\n\n:host([size="large"]) .model-name {\n font-size: 17px;\n}\n\n:host([size="large"]) .status-badge {\n padding: 5px 12px;\n font-size: 12px;\n}\n\n:host([size="large"]) .stage-name {\n font-size: 15px;\n}\n\n:host([size="large"]) .stat-value {\n font-size: 18px;\n}\n\n/* Responsive design */\n@media (max-width: 640px) {\n .stats {\n grid-template-columns: 1fr;\n }\n}\n\n/* Disabled state */\n:host([disabled]) .model-loader {\n opacity: 0.5;\n pointer-events: none;\n}\n</style>\n\n <div class="model-loader ${t} ${this.config.className}">\n <div class="header">\n <div class="model-name">${this.config.modelName}</div>\n <div class="status-badge ${t}">${e}</div>\n </div>\n <div class="stages">\n ${n}\n </div>\n ${s}\n ${a}\n ${i}\n </div>\n `,this.config.showRetryButton&&this.state.hasError){const t=this.shadowRoot.querySelector(".retry-button");t&&t.addEventListener("click",()=>this.retry())}}getState(){return{...this.state}}getConfig(){return{...this.config}}}customElements.get("model-loader")||customElements.define("model-loader",c);class p extends s{constructor(t={}){super({debug:t.debug??!1,className:t.className,ariaLabel:t.ariaLabel??`${t.label??"Parameter"} Slider`}),n(this,"config"),n(this,"state"),n(this,"sliderTrack",null),n(this,"sliderThumb",null),n(this,"handleThumbMouseMove",t=>{if(!this.state.isDragging||!this.sliderTrack)return;const e=this.sliderTrack.getBoundingClientRect(),n=i((t.clientX-e.left)/e.width,0,1),s=this.config.min+n*(this.config.max-this.config.min);this.setValue(s,"slider")}),n(this,"handleThumbMouseUp",()=>{var t;this.state.isDragging=!1,null==(t=this.sliderThumb)||t.classList.remove("dragging"),document.removeEventListener("mousemove",this.handleThumbMouseMove),document.removeEventListener("mouseup",this.handleThumbMouseUp)}),n(this,"handleThumbTouchMove",t=>{if(!this.state.isDragging||!this.sliderTrack)return;t.preventDefault();const e=t.touches[0];if(!e)return;const n=this.sliderTrack.getBoundingClientRect(),s=i((e.clientX-n.left)/n.width,0,1),a=this.config.min+s*(this.config.max-this.config.min);this.setValue(a,"slider")}),n(this,"handleThumbTouchEnd",()=>{var t;this.state.isDragging=!1,null==(t=this.sliderThumb)||t.classList.remove("dragging"),document.removeEventListener("touchmove",this.handleThumbTouchMove),document.removeEventListener("touchend",this.handleThumbTouchEnd)}),this.config={label:t.label??"Parameter",min:t.min??0,max:t.max??1,value:t.value??.5,defaultValue:t.defaultValue??t.value??.5,step:t.step??.01,decimals:t.decimals??2,description:t.description??"",showPresets:t.showPresets??!0,presets:t.presets??[],showInput:t.showInput??!0,showReset:t.showReset??!0,showRangeLabels:t.showRangeLabels??!0,unit:t.unit??"",cursorFeedback:t.cursorFeedback??!0,disabled:t.disabled??!1,debug:t.debug??!1,className:t.className??"",ariaLabel:t.ariaLabel??`${t.label??"Parameter"} Slider`,size:t.size??"default",variant:t.variant??"default",animation:t.animation??"none"},this.state={currentValue:i(this.config.value,this.config.min,this.config.max),isDragging:!1,isFocused:!1},this.attachShadow({mode:"open"})}static get observedAttributes(){return["label","min","max","value","disabled","size","variant","animation"]}connectedCallback(){super.connectedCallback(),this.render(),this.attachEventListeners(),this.log("ParameterSlider mounted")}disconnectedCallback(){this.removeEventListeners(),super.disconnectedCallback()}getDefaultRole(){return"slider"}handleAttributeChange(t,e,n){switch(t){case"label":this.config.label=n||"Parameter",this.render();break;case"min":this.config.min=Number.parseFloat(n)||0,this.render();break;case"max":this.config.max=Number.parseFloat(n)||1,this.render();break;case"value":this.setValue(Number.parseFloat(n)||.5);break;case"disabled":this._disabled=null!==n,this.render();break;case"size":this.config.size=n,this.render();break;case"variant":this.config.variant=n,this.render();break;case"animation":this.config.animation=n,this.render()}}getValue(){return this.state.currentValue}setValue(t,e="slider"){const n=this.state.currentValue,s=i(t,this.config.min,this.config.max),a=Math.round(s/this.config.step)*this.config.step,r=Number.parseFloat(a.toFixed(this.config.decimals));if(r===this.state.currentValue)return;this.state.currentValue=r,this.updateSliderPosition();const o={value:r,previousValue:n,source:e,timestamp:Date.now()};this.emit("valuechange",o),this.log("Value changed",o)}reset(){this.setValue(this.config.defaultValue,"reset")}selectPreset(t){const e=this.state.currentValue;this.setValue(t.value,"preset");const n={preset:t,previousValue:e,timestamp:Date.now()};this.emit("presetselect",n),this.log("Preset selected",n)}attachEventListeners(){if(!this.shadowRoot)return;this.sliderTrack=this.shadowRoot.querySelector(".slider-track"),this.sliderThumb=this.shadowRoot.querySelector(".slider-thumb"),this.sliderTrack&&this.sliderTrack.addEventListener("click",this.handleTrackClick.bind(this)),this.sliderThumb&&(this.sliderThumb.addEventListener("mousedown",this.handleThumbMouseDown.bind(this)),this.sliderThumb.addEventListener("touchstart",this.handleThumbTouchStart.bind(this),{passive:!1}),this.sliderThumb.addEventListener("keydown",this.handleThumbKeyDown.bind(this)));const t=this.shadowRoot.querySelector(".value-input");t&&(t.addEventListener("change",this.handleInputChange.bind(this)),t.addEventListener("blur",this.handleInputBlur.bind(this)));const e=this.shadowRoot.querySelector(".reset-button");e&&e.addEventListener("click",()=>this.reset());this.shadowRoot.querySelectorAll(".preset-button").forEach((t,e)=>{t.addEventListener("click",()=>{const t=this.config.presets[e];t&&this.selectPreset(t)})})}removeEventListeners(){document.removeEventListener("mousemove",this.handleThumbMouseMove),document.removeEventListener("mouseup",this.handleThumbMouseUp),document.removeEventListener("touchmove",this.handleThumbTouchMove),document.removeEventListener("touchend",this.handleThumbTouchEnd)}handleTrackClick(t){if(!this.sliderTrack||this.config.disabled)return;const e=this.sliderTrack.getBoundingClientRect(),n=(t.clientX-e.left)/e.width,s=this.config.min+n*(this.config.max-this.config.min);this.setValue(s,"slider")}handleThumbMouseDown(t){var e;this.config.disabled||(t.preventDefault(),this.state.isDragging=!0,null==(e=this.sliderThumb)||e.classList.add("dragging"),document.addEventListener("mousemove",this.handleThumbMouseMove),document.addEventListener("mouseup",this.handleThumbMouseUp))}handleThumbTouchStart(t){var e;this.config.disabled||(t.preventDefault(),this.state.isDragging=!0,null==(e=this.sliderThumb)||e.classList.add("dragging"),document.addEventListener("touchmove",this.handleThumbTouchMove,{passive:!1}),document.addEventListener("touchend",this.handleThumbTouchEnd))}handleThumbKeyDown(t){if(this.config.disabled)return;let e=0;const n=10*this.config.step;switch(t.key){case"ArrowRight":case"ArrowUp":e=this.config.step;break;case"ArrowLeft":case"ArrowDown":e=-this.config.step;break;case"PageUp":e=n;break;case"PageDown":e=-n;break;case"Home":return this.setValue(this.config.min,"slider"),void t.preventDefault();case"End":return this.setValue(this.config.max,"slider"),void t.preventDefault();default:return}t.preventDefault(),this.setValue(this.state.currentValue+e,"slider")}handleInputChange(t){const e=t.target,n=Number.parseFloat(e.value);Number.isNaN(n)||this.setValue(n,"input")}handleInputBlur(t){t.target.value=this.state.currentValue.toFixed(this.config.decimals)}updateSliderPosition(){if(!this.sliderThumb||!this.shadowRoot)return;const t=(this.state.currentValue-this.config.min)/(this.config.max-this.config.min)*100;this.sliderThumb.style.left=`${t}%`;const e=this.shadowRoot.querySelector(".slider-fill");e&&(e.style.width=`${t}%`);const n=this.shadowRoot.querySelector(".current-value");n&&(n.textContent=this.state.currentValue.toFixed(this.config.decimals));const s=this.shadowRoot.querySelector(".value-input");s&&document.activeElement!==s&&(s.value=this.state.currentValue.toFixed(this.config.decimals)),this.updateActivePreset(),this.updateCursor()}updateCursor(){this.config.cursorFeedback&&this.sliderThumb&&(this.config.disabled?this.sliderThumb.style.cursor="not-allowed":this.state.isDragging?this.sliderThumb.style.cursor="grabbing":this.sliderThumb.style.cursor="grab")}updateActivePreset(){if(!this.shadowRoot)return;this.shadowRoot.querySelectorAll(".preset-button").forEach((t,e)=>{const n=this.config.presets[e];n&&Math.abs(n.value-this.state.currentValue)<this.config.step/2?t.classList.add("active"):t.classList.remove("active")})}renderInputControls(){if(!this.config.showInput&&!this.config.showReset)return"";const t=this.config.disabled?"disabled":"";let e="";return this.config.showInput&&(e+=`\n <span class="input-label">Value:</span>\n <input \n type="number" \n class="value-input"\n value="${this.state.currentValue.toFixed(this.config.decimals)}"\n min="${this.config.min}"\n max="${this.config.max}"\n step="${this.config.step}"\n ${t}\n />\n `),this.config.showReset&&(e+=`\n <button class="reset-button" type="button" ${t}>\n Reset\n </button>\n `),`\n <div class="input-container">\n ${e}\n </div>\n `}render(){if(!this.shadowRoot)return;this.config.size&&this.getAttribute("size")!==this.config.size&&this.setAttribute("size",this.config.size),this.config.variant&&this.getAttribute("variant")!==this.config.variant&&this.setAttribute("variant",this.config.variant),this.config.animation&&this.getAttribute("animation")!==this.config.animation&&this.setAttribute("animation",this.config.animation);const t=this.config.disabled?"disabled":"",e=`\n <div class="header">\n <div class="label-section">\n <label class="label">${this.config.label}</label>\n ${this.config.description?`<div class="description">${this.config.description}</div>`:""}\n </div>\n <div class="value-display">\n <span class="current-value">${this.state.currentValue.toFixed(this.config.decimals)}</span>\n ${this.config.unit?`<span class="unit">${this.config.unit}</span>`:""}\n </div>\n </div>\n `,n=(this.state.currentValue-this.config.min)/(this.config.max-this.config.min)*100,s=`\n <div class="slider-container">\n <div class="slider-track" role="presentation">\n <div class="slider-fill" style="width: ${n}%"></div>\n <div \n class="slider-thumb" \n style="left: ${n}%"\n role="slider"\n tabindex="${this.config.disabled?-1:0}"\n aria-valuemin="${this.config.min}"\n aria-valuemax="${this.config.max}"\n aria-valuenow="${this.state.currentValue}"\n aria-label="${this.config.ariaLabel}"\n ></div>\n </div>\n ${this.config.showRangeLabels?`\n <div class="range-labels">\n <span class="range-label">${this.config.min.toFixed(this.config.decimals)}</span>\n <span class="range-label">${this.config.max.toFixed(this.config.decimals)}</span>\n </div>\n `:""}\n </div>\n `,a=this.config.showPresets&&this.config.presets.length>0?`\n <div class="presets">\n ${this.config.presets.map(t=>`\n <button class="preset-button" type="button">\n <span class="preset-value">${t.value}</span>\n <span class="preset-label">${t.label}</span>\n </button>\n `).join("")}\n </div>\n `:"",i=this.renderInputControls();this.shadowRoot.innerHTML=`\n \n <style>\n :host {\n /* CSS variables inherit from document root with fallback defaults */\n display: block;\n width: 100%;\n font-family: var(--ai-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);\n font-size: var(--ai-font-size, 14px);\n }\n\n :host([style*="cursor: grab"]) .slider-thumb {\n cursor: grab;\n }\n\n :host([style*="cursor: grabbing"]) .slider-thumb {\n cursor: grabbing;\n }\n\n .parameter-slider {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 16px;\n background: var(--ai-slider-bg, #1f2937);\n border-radius: 12px;\n color: var(--ai-slider-text, #f9fafb);\n position: relative;\n }\n\n .parameter-slider.disabled {\n opacity: 0.5;\n pointer-events: none;\n }\n\n /* Header */\n .header {\n display: flex;\n justify-content: space-between;\n align-items: flex-start;\n gap: 12px;\n }\n\n .label-section {\n flex: 1;\n }\n\n .label {\n font-size: 14px;\n font-weight: 600;\n color: var(--ai-slider-label, #f9fafb);\n margin-bottom: 4px;\n display: block;\n }\n\n .description {\n font-size: 12px;\n color: var(--ai-slider-description, #9ca3af);\n line-height: 1.4;\n }\n\n .value-display {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-shrink: 0;\n }\n\n .current-value {\n font-size: 18px;\n font-weight: 700;\n color: var(--ai-slider-value, #60a5fa);\n font-variant-numeric: tabular-nums;\n min-width: 60px;\n text-align: right;\n }\n\n .unit {\n font-size: 12px;\n color: var(--ai-slider-description, #9ca3af);\n font-weight: 500;\n }\n\n /* Slider Container */\n .slider-container {\n position: relative;\n padding: 8px 0;\n }\n\n .slider-track {\n position: relative;\n height: 6px;\n background: var(--ai-slider-track-bg, #374151);\n border-radius: 3px;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .slider-track:hover {\n background: var(--ai-slider-track-hover, #4b5563);\n }\n\n .slider-fill {\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n background: linear-gradient(90deg, \n var(--ai-slider-fill-start, #3b82f6) 0%, \n var(--ai-slider-fill-end, #60a5fa) 100%\n );\n border-radius: 3px;\n transition: width 0.2s ease;\n }\n\n .slider-thumb {\n position: absolute;\n top: 50%;\n transform: translate(-50%, -50%);\n width: 20px;\n height: 20px;\n background: var(--ai-slider-thumb, #ffffff);\n border: 3px solid var(--ai-slider-thumb-border, #3b82f6);\n border-radius: 50%;\n cursor: grab;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n transition: transform 0.2s, box-shadow 0.2s;\n }\n\n .slider-thumb:hover {\n transform: translate(-50%, -50%) scale(1.1);\n box-shadow: 0 4px 12px rgba(59, 130, 246, 0.4);\n }\n\n .slider-thumb:active,\n .slider-thumb.dragging {\n cursor: grabbing;\n transform: translate(-50%, -50%) scale(1.15);\n box-shadow: 0 4px 16px rgba(59, 130, 246, 0.5);\n }\n\n .slider-thumb:focus-visible {\n outline: 2px solid var(--ai-slider-focus, #60a5fa);\n outline-offset: 2px;\n }\n\n /* Range Labels */\n .range-labels {\n display: flex;\n justify-content: space-between;\n margin-top: 4px;\n }\n\n .range-label {\n font-size: 11px;\n color: var(--ai-slider-description, #9ca3af);\n font-variant-numeric: tabular-nums;\n }\n\n /* Presets */\n .presets {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n }\n\n .preset-button {\n flex: 1;\n min-width: 80px;\n padding: 8px 12px;\n background: var(--ai-slider-preset-bg, #374151);\n color: var(--ai-slider-preset-text, #d1d5db);\n border: 1px solid var(--ai-slider-preset-border, #4b5563);\n border-radius: 8px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 2px;\n }\n\n .preset-button:hover {\n background: var(--ai-slider-preset-hover, #4b5563);\n border-color: var(--ai-slider-preset-hover-border, #60a5fa);\n transform: translateY(-1px);\n }\n\n .preset-button.active {\n background: linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%);\n color: #ffffff;\n border-color: #3b82f6;\n }\n\n .preset-value {\n font-size: 14px;\n font-weight: 700;\n }\n\n .preset-label {\n font-size: 10px;\n opacity: 0.8;\n }\n\n /* Input Field */\n .input-container {\n display: flex;\n gap: 8px;\n align-items: center;\n }\n\n .input-label {\n font-size: 12px;\n color: var(--ai-slider-description, #9ca3af);\n flex-shrink: 0;\n }\n\n .value-input {\n flex: 1;\n padding: 8px 12px;\n background: var(--ai-slider-input-bg, #374151);\n border: 1px solid var(--ai-slider-input-border, #4b5563);\n border-radius: 6px;\n color: var(--ai-slider-text, #f9fafb);\n font-size: 14px;\n font-family: inherit;\n font-variant-numeric: tabular-nums;\n transition: border-color 0.2s;\n }\n\n .value-input:hover {\n border-color: var(--ai-slider-input-hover, #6b7280);\n }\n\n .value-input:focus {\n outline: none;\n border-color: var(--ai-slider-focus, #60a5fa);\n box-shadow: 0 0 0 2px rgba(96, 165, 250, 0.2);\n }\n\n .reset-button {\n padding: 8px 16px;\n background: var(--ai-slider-reset-bg, #374151);\n color: var(--ai-slider-reset-text, #d1d5db);\n border: 1px solid var(--ai-slider-reset-border, #4b5563);\n border-radius: 6px;\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s;\n flex-shrink: 0;\n }\n\n .reset-button:hover {\n background: var(--ai-slider-reset-hover, #4b5563);\n border-color: var(--ai-slider-reset-hover-border, #6b7280);\n }\n\n .reset-button:active {\n transform: scale(0.95);\n }\n\n /* Visual Variants */\n\n /* Minimal variant - clean, no shadows */\n :host([variant="minimal"]) .parameter-slider {\n box-shadow: none;\n border: 1px solid var(--ai-slider-border, #374151);\n }\n\n :host([variant="minimal"]) .slider-track {\n background: transparent;\n border: 1px solid var(--ai-slider-track-bg, #374151);\n }\n\n /* Gradient variant - colorful gradients */\n :host([variant="gradient"]) .slider-fill {\n background: linear-gradient(\n 90deg,\n var(--ai-slider-fill-start, #3b82f6),\n var(--ai-slider-fill-end, #60a5fa),\n var(--ai-slider-fill-start, #3b82f6)\n );\n background-size: 200% 100%;\n animation: gradient-shift 3s ease-in-out infinite;\n }\n\n @keyframes gradient-shift {\n 0%, 100% { background-position: 0% 50%; }\n 50% { background-position: 100% 50%; }\n }\n\n /* Override default animation when animation attribute is set */\n :host([animation][variant="gradient"]) .slider-fill {\n animation: none !important;\n }\n\n /* Glassmorphic variant - frosted glass effect */\n :host([variant="glassmorphic"]) .parameter-slider {\n background: rgba(31, 41, 55, 0.6);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n }\n\n :host([variant="glassmorphic"]) .slider-track {\n background: rgba(0, 0, 0, 0.2);\n }\n\n :host([variant="glassmorphic"]) .slider-fill {\n background: linear-gradient(\n 90deg,\n rgba(59, 130, 246, 0.8),\n rgba(96, 165, 250, 0.8)\n );\n }\n\n /* Animation Effects */\n\n /* Striped animation */\n :host([animation="striped"]) .slider-fill {\n background-image: \n linear-gradient(\n 45deg,\n rgba(255, 255, 255, 0.2) 25%,\n transparent 25%,\n transparent 50%,\n rgba(255, 255, 255, 0.2) 50%,\n rgba(255, 255, 255, 0.2) 75%,\n transparent 75%,\n transparent\n ),\n linear-gradient(to right, var(--ai-slider-fill-start, #3b82f6), var(--ai-slider-fill-end, #3b82f6)) !important;\n background-size: 2rem 2rem, 100% 100% !important;\n animation: slider-stripes 3s linear infinite !important;\n }\n\n @keyframes slider-stripes {\n 0% { background-position: 0 0, 0 0; }\n 100% { background-position: 2rem 0, 0 0; }\n }\n\n /* Pulse animation */\n :host([animation="pulse"]) .slider-fill {\n animation: slider-pulse 4s ease-in-out infinite !important;\n }\n\n @keyframes slider-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n }\n\n /* Glow animation */\n :host([animation="glow"]) .slider-fill {\n animation: slider-glow 4s ease-in-out infinite !important;\n }\n\n @keyframes slider-glow {\n 0%, 100% { \n box-shadow: 0 0 5px var(--ai-slider-fill-start, #3b82f6),\n 0 0 10px var(--ai-slider-fill-start, #3b82f6);\n }\n 50% { \n box-shadow: 0 0 20px var(--ai-slider-fill-start, #3b82f6), \n 0 0 35px var(--ai-slider-fill-start, #3b82f6),\n 0 0 50px var(--ai-slider-fill-start, #3b82f6);\n }\n }\n\n /* Responsive */\n @media (max-width: 480px) {\n .parameter-slider {\n padding: 12px;\n }\n\n .header {\n flex-direction: column;\n }\n\n .value-display {\n align-self: flex-end;\n }\n\n .presets {\n flex-direction: column;\n }\n\n .preset-button {\n min-width: unset;\n }\n }\n\n /* Size variants */\n :host([size="compact"]) .parameter-slider {\n padding: 8px;\n font-size: 12px;\n gap: 8px;\n }\n\n :host([size="compact"]) .slider-track {\n height: 4px;\n }\n\n :host([size="compact"]) .slider-thumb {\n width: 16px;\n height: 16px;\n }\n\n :host([size="compact"]) .label {\n font-size: 12px;\n }\n\n :host([size="compact"]) .current-value {\n font-size: 16px;\n }\n\n :host([size="compact"]) .description {\n font-size: 10px;\n }\n\n :host([size="large"]) .parameter-slider {\n padding: 16px;\n font-size: 16px;\n gap: 16px;\n }\n\n :host([size="large"]) .slider-track {\n height: 8px;\n }\n\n :host([size="large"]) .slider-thumb {\n width: 24px;\n height: 24px;\n }\n\n :host([size="large"]) .label {\n font-size: 16px;\n }\n\n :host([size="large"]) .current-value {\n font-size: 20px;\n }\n\n :host([size="large"]) .description {\n font-size: 14px;\n }\n\n /* Dark mode overrides (already default, but can be customized) */\n @media (prefers-color-scheme: light) {\n .parameter-slider {\n background: #ffffff;\n color: #1f2937;\n }\n\n .label {\n color: #1f2937;\n }\n\n .description,\n .range-label,\n .input-label {\n color: #6b7280;\n }\n\n .slider-track {\n background: #e5e7eb;\n }\n\n .slider-track:hover {\n background: #d1d5db;\n }\n\n .preset-button {\n background: #f3f4f6;\n color: #374151;\n border-color: #d1d5db;\n }\n\n .preset-button:hover {\n background: #e5e7eb;\n }\n\n .value-input,\n .reset-button {\n background: #f9fafb;\n color: #1f2937;\n border-color: #d1d5db;\n }\n }\n </style>\n\n <div class="parameter-slider ${t} ${this.config.className}">\n ${e}\n ${s}\n ${a}\n ${i}\n </div>\n `,this.sliderTrack=this.shadowRoot.querySelector(".slider-track"),this.sliderThumb=this.shadowRoot.querySelector(".slider-thumb"),this.attachEventListeners()}getState(){return{...this.state}}getConfig(){return{...this.config}}}customElements.get("parameter-slider")||customElements.define("parameter-slider",p);class h extends s{constructor(t){if(super({debug:t.debug,disabled:t.disabled}),n(this,"state"),n(this,"parameters",new Map),n(this,"parameterDefinitions",new Map),n(this,"presets"),n(this,"panelConfig"),this.panelConfig=t,!t.parameters||0===t.parameters.length)throw new Error("ParameterPanel requires at least one parameter");t.parameters.forEach(t=>{this.parameterDefinitions.set(t.id,t)}),this.presets=new Map,t.presets&&Object.entries(t.presets).forEach(([t,e])=>{this.presets.set(t,{...e,isBuiltIn:e.isBuiltIn??!1})});const e={};t.parameters.forEach(t=>{e[t.id]=t.value}),this.state={values:e,activePreset:null,isCollapsed:Boolean(this.panelConfig.collapsible&&this.panelConfig.startCollapsed),errors:{},isDirty:!1},this.attachShadow({mode:"open"}),this.panelConfig.persistValues&&this.loadFromStorage(),this.panelConfig.persistPresets&&this.loadPresetsFromStorage()}getAllValues(){return{...this.state.values}}getValue(t){return this.state.values[t]}setValue(t,e,n="slider"){const s=this.parameterDefinitions.get(t);if(!s)return void this.log(`Parameter ${t} not found`,"warn");if(e=Math.max(s.min,Math.min(s.max,e)),this.panelConfig.validateOnChange&&s.validate&&"reset"!==n&&"import"!==n){const n=s.validate(e,this.state.values);if(!0!==n)return this.state.errors[t]="string"==typeof n?n:"Validation failed",this.dispatchValidationError(t,this.state.errors[t]),void this.render()}delete this.state.errors[t];const a=this.state.values[t];this.state.values[t]=e,"reset"!==n&&"import"!==n&&"preset"!==n&&(this.state.isDirty=!0,this.state.activePreset=null);const i=this.parameters.get(t);if(i&&a!==e){const t="import"===n?"reset":n;i.setValue(e,t)}this.panelConfig.persistValues&&this.saveToStorage(),this.panelConfig.emitChangeEvents&&a!==e&&this.dispatchPanelChange(t,e,a??s.min,n),this.render()}loadPreset(t){const e=this.presets.get(t);if(!e)return void this.log(`Preset ${t} not found`,"warn");const n={...this.state.values};Object.entries(e.values).forEach(([t,e])=>{this.parameterDefinitions.has(t)&&this.setValue(t,e,"preset")}),this.state.activePreset=t,this.state.isDirty=!1,this.dispatchPresetLoad(t,e,n),this.render()}resetAll(){this.parameterDefinitions.forEach((t,e)=>{const n=t.value;this.setValue(e,n,"reset")}),this.state.activePreset=null,this.state.isDirty=!1,this.state.errors={},this.dispatchPanelReset(),this.render()}exportConfig(){const t={};this.parameterDefinitions.forEach((e,n)=>{t[n]=this.state.values[n]??0});const e={version:"1.0",parameters:t};return this.state.activePreset&&(e.preset=this.state.activePreset),e.metadata={created:(new Date).toISOString(),name:this.config.title||"Parameters"},this.dispatchConfigExport(e),e}importConfig(t){t.parameters?(Object.entries(t.parameters).forEach(([t,e])=>{this.parameterDefinitions.has(t)&&this.setValue(t,e,"import")}),t.preset&&this.presets.has(t.preset)?this.state.activePreset=t.preset:this.state.activePreset=null,this.state.isDirty=!1,this.dispatchConfigImport(t),this.render()):this.log("Invalid config: missing parameters","warn")}toggleCollapse(){this.panelConfig.collapsible&&(this.state.isCollapsed=!this.state.isCollapsed,this.render())}validateAll(){let t=!0;return this.state.errors={},this.parameterDefinitions.forEach((e,n)=>{if(e.validate){const s=this.state.values[n]??e.min,a=e.validate(s,this.state.values);!0!==a&&(t=!1,this.state.errors[n]="string"==typeof a?a:"Validation failed",this.dispatchValidationError(n,this.state.errors[n]))}}),t||this.render(),t}addPreset(t,e,n,s){this.presets.set(t,{name:e,description:s,values:n,isBuiltIn:!1}),this.panelConfig.persistPresets&&this.savePresetsToStorage(),this.render()}removePreset(t){const e=this.presets.get(t);e&&!e.isBuiltIn&&(this.presets.delete(t),this.state.activePreset===t&&(this.state.activePreset=null),this.panelConfig.persistPresets&&this.savePresetsToStorage(),this.render())}dispatchPanelChange(t,e,n,s){const a=new CustomEvent("panelchange",{detail:{parameterId:t,value:e,previousValue:n,allValues:this.getAllValues(),source:s,timestamp:Date.now()},bubbles:!0,composed:!0});this.dispatchEvent(a)}dispatchPresetLoad(t,e,n){const s=new CustomEvent("presetload",{detail:{presetId:t,preset:{name:e.name,description:e.description,values:e.values},previousValues:n,timestamp:Date.now()},bubbles:!0,composed:!0});this.dispatchEvent(s)}dispatchConfigExport(t){const e=new CustomEvent("configexport",{detail:{config:t,format:"json",timestamp:Date.now()},bubbles:!0,composed:!0});this.dispatchEvent(e)}dispatchConfigImport(t){const e={...this.state.values},n=new CustomEvent("configimport",{detail:{config:t,previousValues:e,timestamp:Date.now()},bubbles:!0,composed:!0});this.dispatchEvent(n)}dispatchPanelReset(){const t={...this.state.values},e={};this.parameterDefinitions.forEach((t,n)=>{e[n]=t.value});const n=new CustomEvent("panelreset",{detail:{previousValues:t,newValues:e,timestamp:Date.now()},bubbles:!0,composed:!0});this.dispatchEvent(n)}dispatchValidationError(t,e){const n=new CustomEvent("validationerror",{detail:{parameterId:t,error:e,value:this.state.values[t]||0,timestamp:Date.now()},bubbles:!0,composed:!0});this.dispatchEvent(n)}saveToStorage(){try{const t={values:this.state.values,activePreset:this.state.activePreset};localStorage.setItem(this.panelConfig.storageKey,JSON.stringify(t))}catch(t){this.log("Failed to save to storage","error",t)}}loadFromStorage(){try{const t=localStorage.getItem(this.panelConfig.storageKey);if(t){const e=JSON.parse(t);e.values&&Object.entries(e.values).forEach(([t,e])=>{this.parameterDefinitions.has(t)&&(this.state.values[t]=e)}),e.activePreset&&this.presets.has(e.activePreset)&&(this.state.activePreset=e.activePreset)}}catch(t){this.log("Failed to load from storage","error",t)}}savePresetsToStorage(){try{const t=Array.from(this.presets.entries()).filter(([t,e])=>!e.isBuiltIn).reduce((t,[e,n])=>(t[e]={name:n.name,description:n.description,values:n.values},t),{});localStorage.setItem(`${this.panelConfig.storageKey}-presets`,JSON.stringify(t))}catch(t){this.log("Failed to save presets","error",t)}}loadPresetsFromStorage(){try{const t=localStorage.getItem(`${this.panelConfig.storageKey}-presets`);if(t){const e=JSON.parse(t);Object.entries(e).forEach(([t,e])=>{this.presets.set(t,{...e,isBuiltIn:!1})})}}catch(t){this.log("Failed to load presets","error",t)}}render(){if(!this.shadowRoot)return;const t=Object.keys(this.state.errors).length>0;this.shadowRoot.innerHTML=`\n <style>\n :host {\n display: block;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;\n --panel-bg: #ffffff;\n --panel-border: #e5e7eb;\n --panel-text: #1f2937;\n --panel-text-secondary: #6b7280;\n --panel-header-bg: #f9fafb;\n --panel-primary: #2563eb;\n --panel-primary-hover: #1d4ed8;\n --panel-danger: #dc2626;\n --panel-danger-hover: #b91c1c;\n --panel-success: #16a34a;\n --panel-radius: 12px;\n --panel-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n }\n\n .container {\n background: var(--panel-bg);\n border: 1px solid var(--panel-border);\n border-radius: var(--panel-radius);\n box-shadow: var(--panel-shadow);\n overflow: hidden;\n }\n\n .header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 16px 20px;\n background: var(--panel-header-bg);\n border-bottom: 1px solid var(--panel-border);\n }\n\n .header.collapsible {\n cursor: pointer;\n user-select: none;\n }\n\n .header.collapsible:hover {\n background: #f3f4f6;\n }\n\n .title-section {\n display: flex;\n align-items: center;\n gap: 12px;\n flex: 1;\n }\n\n .title {\n font-size: 18px;\n font-weight: 600;\n color: var(--panel-text);\n margin: 0;\n }\n\n .dirty-indicator {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 8px;\n height: 8px;\n background: var(--panel-primary);\n border-radius: 50%;\n opacity: 0;\n transition: opacity 0.2s;\n }\n\n .dirty-indicator.show {\n opacity: 1;\n }\n\n .collapse-icon {\n font-size: 20px;\n color: var(--panel-text-secondary);\n transition: transform 0.2s;\n }\n\n .collapse-icon.collapsed {\n transform: rotate(-90deg);\n }\n\n .content {\n max-height: 2000px;\n overflow: hidden;\n transition: max-height 0.3s ease-out, padding 0.3s ease-out;\n }\n\n .content.collapsed {\n max-height: 0;\n padding: 0 !important;\n }\n\n .presets-section {\n padding: 16px 20px;\n border-bottom: 1px solid var(--panel-border);\n background: var(--panel-header-bg);\n }\n\n .presets-label {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.05em;\n color: var(--panel-text-secondary);\n margin-bottom: 10px;\n }\n\n .presets-buttons {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n }\n\n .preset-btn {\n padding: 8px 16px;\n background: white;\n border: 1px solid var(--panel-border);\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n color: var(--panel-text);\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .preset-btn:hover {\n border-color: var(--panel-primary);\n background: #eff6ff;\n }\n\n .preset-btn.active {\n background: var(--panel-primary);\n color: white;\n border-color: var(--panel-primary);\n }\n\n .preset-btn .icon {\n font-size: 16px;\n }\n\n .preset-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .parameters-section {\n padding: 20px;\n }\n\n .parameters-grid {\n display: grid;\n gap: 20px;\n }\n\n .parameters-grid.layout-grid {\n grid-template-columns: repeat(var(--grid-columns, 2), 1fr);\n }\n\n .parameters-grid.layout-vertical {\n grid-template-columns: 1fr;\n }\n\n @media (max-width: 768px) {\n .parameters-grid.layout-grid {\n grid-template-columns: 1fr;\n }\n }\n\n .parameter-wrapper {\n display: block;\n }\n\n .actions-section {\n padding: 16px 20px;\n border-top: 1px solid var(--panel-border);\n background: var(--panel-header-bg);\n display: flex;\n align-items: center;\n justify-content: space-between;\n flex-wrap: wrap;\n gap: 12px;\n }\n\n .actions-left,\n .actions-right {\n display: flex;\n gap: 8px;\n flex-wrap: wrap;\n }\n\n .action-btn {\n padding: 8px 16px;\n background: white;\n border: 1px solid var(--panel-border);\n border-radius: 6px;\n font-size: 14px;\n font-weight: 500;\n color: var(--panel-text);\n cursor: pointer;\n transition: all 0.2s;\n display: flex;\n align-items: center;\n gap: 6px;\n }\n\n .action-btn:hover {\n background: #f9fafb;\n border-color: var(--panel-primary);\n }\n\n .action-btn.primary {\n background: var(--panel-primary);\n color: white;\n border-color: var(--panel-primary);\n }\n\n .action-btn.primary:hover {\n background: var(--panel-primary-hover);\n }\n\n .action-btn.danger {\n color: var(--panel-danger);\n }\n\n .action-btn.danger:hover {\n background: #fef2f2;\n border-color: var(--panel-danger);\n }\n\n .action-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .validation-errors {\n padding: 12px 20px;\n background: #fef2f2;\n border-bottom: 1px solid #fecaca;\n display: none;\n }\n\n .validation-errors.show {\n display: block;\n }\n\n .error-item {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--panel-danger);\n font-size: 13px;\n margin: 4px 0;\n }\n\n .error-icon {\n font-size: 16px;\n }\n\n .empty-state {\n padding: 40px 20px;\n text-align: center;\n color: var(--panel-text-secondary);\n }\n\n .empty-state-icon {\n font-size: 48px;\n margin-bottom: 12px;\n opacity: 0.5;\n }\n\n .empty-state-text {\n font-size: 14px;\n }\n\n /* Dark mode support */\n :host([theme="dark"]) {\n --panel-bg: #1f2937;\n --panel-border: #374151;\n --panel-text: #f9fafb;\n --panel-text-secondary: #9ca3af;\n --panel-header-bg: #111827;\n --panel-primary: #3b82f6;\n --panel-primary-hover: #2563eb;\n --panel-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);\n }\n\n /* Loading state */\n .loading {\n position: relative;\n pointer-events: none;\n opacity: 0.6;\n }\n\n .loading::after {\n content: '';\n position: absolute;\n top: 50%;\n left: 50%;\n width: 24px;\n height: 24px;\n margin: -12px 0 0 -12px;\n border: 3px solid var(--panel-border);\n border-top-color: var(--panel-primary);\n border-radius: 50%;\n animation: spin 0.6s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n /* Disabled state */\n :host([disabled]) .container {\n opacity: 0.6;\n pointer-events: none;\n }\n</style>\n <div class="container" style="--grid-columns: ${this.panelConfig.columns}">\n ${this.renderHeader()}\n <div class="content ${this.state.isCollapsed?"collapsed":""}">\n ${t?this.renderErrors():""}\n ${this.panelConfig.showPresets&&this.presets.size>0?this.renderPresets():""}\n ${this.renderParameters()}\n ${this.panelConfig.showResetAll||this.panelConfig.showExportImport?this.renderActions():""}\n </div>\n </div>\n `,this.attachEventListeners(),this.createParameterSliders()}renderHeader(){const t=this.state.isCollapsed?"collapsed":"",e=void 0!==this.panelConfig.title&&null!==this.panelConfig.title;return`\n <div class="header ${this.panelConfig.collapsible?"collapsible":""}" id="header">\n ${e?`\n <div class="title-section">\n <h3 class="title">${this.panelConfig.title}</h3>\n <span class="dirty-indicator ${this.state.isDirty?"show":""}"></span>\n </div>\n `:`\n <div class="title-section">\n <span class="dirty-indicator ${this.state.isDirty?"show":""}"></span>\n </div>\n `}\n ${this.panelConfig.collapsible?`\n <span class="collapse-icon ${t}">β–Ό</span>\n `:""}\n </div>\n `}renderErrors(){const t=Object.entries(this.state.errors);return 0===t.length?"":`\n <div class="validation-errors show">\n ${t.map(([t,e])=>{var n;return`\n <div class="error-item">\n <span class="error-icon">⚠</span>\n <span>${(null==(n=this.parameterDefinitions.get(t))?void 0:n.label)||t}: ${e}</span>\n </div>\n `}).join("")}\n </div>\n `}renderPresets(){return`\n <div class="presets-section">\n <div class="presets-label">Presets</div>\n <div class="presets-buttons">\n ${Array.from(this.presets.entries()).map(([t,e])=>`\n <button \n class="preset-btn ${this.state.activePreset===t?"active":""}" \n data-preset-id="${t}"\n title="${e.description||e.name}"\n >\n ${e.name}\n </button>\n `).join("")}\n </div>\n </div>\n `}renderParameters(){return`\n <div class="parameters-section">\n <div class="parameters-grid layout-${this.panelConfig.layout}">\n ${Array.from(this.parameterDefinitions.keys()).map(t=>`\n <div class="parameter-wrapper" data-parameter-id="${t}"></div>\n `).join("")}\n </div>\n </div>\n `}renderActions(){return`\n <div class="actions-section">\n <div class="actions-left">\n ${this.panelConfig.showResetAll?'\n <button class="action-btn danger" id="reset-btn">\n <span>↻</span>\n <span>Reset All</span>\n </button>\n ':""}\n </div>\n <div class="actions-right">\n ${this.panelConfig.showExportImport?'\n <button class="action-btn" id="import-btn">\n <span>πŸ“₯</span>\n <span>Import</span>\n </button>\n <button class="action-btn primary" id="export-btn">\n <span>πŸ“€</span>\n <span>Export</span>\n </button>\n ':""}\n </div>\n </div>\n `}attachEventListeners(){if(!this.shadowRoot)return;if(this.panelConfig.collapsible){const t=this.shadowRoot.getElementById("header");null==t||t.addEventListener("click",()=>this.toggleCollapse())}this.shadowRoot.querySelectorAll(".preset-btn").forEach(t=>{t.addEventListener("click",()=>{const e=t.dataset.presetId;e&&this.loadPreset(e)})});const t=this.shadowRoot.getElementById("reset-btn");null==t||t.addEventListener("click",()=>this.resetAll());const e=this.shadowRoot.getElementById("export-btn");null==e||e.addEventListener("click",()=>this.handleExport());const n=this.shadowRoot.getElementById("import-btn");null==n||n.addEventListener("click",()=>this.handleImport())}createParameterSliders(){this.shadowRoot&&(this.parameters.clear(),this.parameterDefinitions.forEach((t,e)=>{const n=this.shadowRoot.querySelector(`[data-parameter-id="${e}"]`);if(!n)return;const s=new p({label:t.label,min:t.min,max:t.max,value:this.state.values[e],step:t.step,unit:t.unit,description:t.description,presets:t.presets,showInput:t.showInput,disabled:t.disabled||this._disabled});s.addEventListener("valuechange",t=>{t.stopPropagation();const n=this.parameterDefinitions.get(e);if(!n)return;const s=t.detail.value,a=t.detail.source,i=Math.max(n.min,Math.min(n.max,s));if(this.panelConfig.validateOnChange&&n.validate){const t=n.validate(i,this.state.values);if(!0!==t)return this.state.errors[e]="string"==typeof t?t:"Validation failed",this.dispatchValidationError(e,this.state.errors[e]),void this.render()}delete this.state.errors[e];const r=this.state.values[e];this.state.values[e]=i,"reset"!==a&&"import"!==a&&"preset"!==a&&(this.state.isDirty=!0,this.state.activePreset=null),this.panelConfig.persistValues&&this.saveToStorage(),this.panelConfig.emitChangeEvents&&r!==i&&this.dispatchPanelChange(e,i,r??n.min,a),this.render()}),n.appendChild(s),this.parameters.set(e,s)}))}handleExport(){const t=this.exportConfig(),e=JSON.stringify(t,null,2),n=new Blob([e],{type:"application/json"}),s=URL.createObjectURL(n),a=document.createElement("a");a.href=s,a.download=`${this.panelConfig.title}-config.json`,a.click(),URL.revokeObjectURL(s)}handleImport(){const t=document.createElement("input");t.type="file",t.accept=".json",t.onchange=t=>{var e;const n=null==(e=t.target.files)?void 0:e[0];n&&n.text().then(t=>{try{const e=JSON.parse(t);this.importConfig(e)}catch(e){this.log("Failed to parse config file","error",e)}}).catch(t=>{this.log("Failed to read config file","error",t)})},t.click()}disconnectedCallback(){this.parameters.clear()}}customElements.get("ai-parameter-panel")||customElements.define("ai-parameter-panel",h);class u extends s{constructor(t={}){super({debug:t.debug??!1,className:t.className,ariaLabel:t.ariaLabel??"Queue Progress"}),n(this,"config"),n(this,"state"),n(this,"updateThrottled"),n(this,"timerInterval"),n(this,"initialPosition",0),this.config={position:t.position??0,queueSize:t.queueSize??0,estimatedWait:t.estimatedWait??0,processingRate:t.processingRate??1,showPosition:t.showPosition??!0,showWaitTime:t.showWaitTime??!0,showRate:t.showRate??!0,showQueueSize:t.showQueueSize??!0,showProgressBar:t.showProgressBar??!0,message:t.message??"You are in the queue",animate:t.animate??!0,updateThrottle:t.updateThrottle??100,cursorFeedback:t.cursorFeedback??!0,debug:t.debug??!1,className:t.className??"",ariaLabel:t.ariaLabel??"Queue Progress",size:t.size??"default",variant:t.variant??"default",animation:t.animation??"none"},this.state={status:"waiting",position:this.config.position,queueSize:this.config.queueSize,estimatedWait:this.config.estimatedWait,processingRate:this.config.processingRate,startTime:0,message:this.config.message,elapsedTime:0},this.initialPosition=this.config.position,this.updateThrottled=a(this._updateInternal.bind(this),this.config.updateThrottle),this.attachShadow({mode:"open"})}static get observedAttributes(){return["position","queue-size","disabled","size","variant","animation"]}connectedCallback(){super.connectedCallback(),this.log("QueueProgress mounted")}disconnectedCallback(){this.stopTimer(),super.disconnectedCallback()}getDefaultRole(){return"status"}handleAttributeChange(t,e,n){switch(t){case"position":this.update({position:Number.parseInt(n,10)||0});break;case"queue-size":this.update({queueSize:Number.parseInt(n,10)||0});break;case"disabled":this._disabled=null!==n,this.render();break;case"size":this.config.size=n,this.render();break;case"variant":this.config.variant=n,this.render();break;case"animation":this.config.animation=n,this.render()}}start(t){this.state={...this.state,status:"waiting",startTime:Date.now(),elapsedTime:0,message:t||this.config.message},this.initialPosition=this.state.position,this.startTimer(),this.render(),this.updateCursor(),this.emit("queuestart",{position:this.state.position,queueSize:this.state.queueSize,estimatedWait:this.state.estimatedWait,timestamp:Date.now()}),this.log("Queue tracking started",this.state)}update(t){"completed"!==this.state.status&&"error"!==this.state.status&&this.updateThrottled(t)}_updateInternal(t){var e;const n=this.state.position;if(this.state={...this.state,position:t.position??this.state.position,queueSize:t.queueSize??this.state.queueSize,estimatedWait:t.estimatedWait??this.state.estimatedWait,processingRate:t.processingRate??this.state.processingRate,message:t.message??this.state.message},void 0!==t.position&&t.position!==n){const t=null==(e=this.shadowRoot)?void 0:e.querySelector(".position-number");t&&this.config.animate&&(t.classList.add("changing"),setTimeout(()=>t.classList.remove("changing"),500)),this.emit("positionchange",{previousPosition:n,currentPosition:this.state.position,queueSize:this.state.queueSize,estimatedWait:this.state.estimatedWait,timestamp:Date.now()})}this.render(),this.log("Position updated",this.state)}complete(){this.state={...this.state,status:"completed",position:0},this.stopTimer(),this.render(),this.updateCursor();const t=this.state.startTime>0?Date.now()-this.state.startTime:0;this.emit("queuecomplete",{totalWaitTime:t,startPosition:this.initialPosition,timestamp:Date.now()}),this.log("Queue completed",{totalWaitTime:t})}cancel(t="Cancelled by user"){this.state={...this.state,status:"cancelled",message:t},this.stopTimer(),this.render(),this.updateCursor(),this.log("Queue cancelled",t)}error(t){this.state={...this.state,status:"error",message:t},this.stopTimer(),this.render(),this.updateCursor(),this.emit("queueerror",{message:t,position:this.state.position,timestamp:Date.now()}),this.logError("Queue error",new Error(t))}reset(){this.stopTimer(),this.state={status:"waiting",position:this.config.position,queueSize:this.config.queueSize,estimatedWait:this.config.estimatedWait,processingRate:this.config.processingRate,startTime:0,message:this.config.message,elapsedTime:0},this.initialPosition=this.config.position,this.render(),this.log("Queue reset")}getPosition(){return this.state.position}getStatus(){return this.state.status}startTimer(){this.stopTimer(),this.timerInterval=globalThis.setInterval(()=>{this.state.startTime>0&&(this.state.elapsedTime=Date.now()-this.state.startTime,this.render())},1e3)}stopTimer(){this.timerInterval&&(clearInterval(this.timerInterval),this.timerInterval=void 0)}getProgressPercentage(){if(0===this.state.queueSize||0===this.initialPosition)return 0;const t=this.initialPosition-this.state.position;return Math.min(100,Math.max(0,t/this.initialPosition*100))}updateCursor(){this.config.cursorFeedback&&("waiting"===this.state.status?this.style.cursor="wait":"error"===this.state.status||"cancelled"===this.state.status?this.style.cursor="not-allowed":this.style.cursor="default")}renderMetrics(){if("waiting"!==this.state.status)return"";let t="";return this.config.showQueueSize&&(t+=`\n <div class="metric">\n <div class="metric-value">${this.state.queueSize}</div>\n <div class="metric-label">Queue Size</div>\n </div>\n `),this.config.showWaitTime&&(t+=`\n <div class="metric">\n <div class="metric-value">${l(Math.round(this.state.estimatedWait))}</div>\n <div class="metric-label">Est. Wait</div>\n </div>\n `),this.config.showRate&&(t+=`\n <div class="metric">\n <div class="metric-value">${this.state.processingRate.toFixed(1)}/s</div>\n <div class="metric-label">Processing Rate</div>\n </div>\n `),t?`\n <div class="queue-metrics">\n ${t}\n </div>\n `:""}render(){if(!this.shadowRoot)return;this.config.size&&this.getAttribute("size")!==this.config.size&&this.setAttribute("size",this.config.size),this.config.variant&&this.getAttribute("variant")!==this.config.variant&&this.setAttribute("variant",this.config.variant),this.config.animation&&this.getAttribute("animation")!==this.config.animation&&this.setAttribute("animation",this.config.animation);const t=this.getProgressPercentage(),e=this.state.status,n=this.getStatusText();this.shadowRoot.innerHTML=`\n <style>\n :host {\n /* CSS variables inherit from document root with fallback defaults */\n display: block;\n font-family: var(--queue-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif);\n font-size: var(--queue-font-size, 14px);\n color: var(--queue-text, #e4e4e7);\n }\n\n :host([style*="cursor: wait"]) .queue-container {\n cursor: wait;\n }\n\n :host([style*="cursor: not-allowed"]) .queue-container {\n cursor: not-allowed;\n }\n\n :host([style*="cursor: default"]) .queue-container {\n cursor: default;\n }\n\n .queue-container {\n background: var(--queue-background, #1a1a2e);\n border: 1px solid var(--queue-border, #27273a);\n border-radius: var(--queue-border-radius, 12px);\n padding: var(--queue-padding, 24px);\n box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);\n }\n\n .queue-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 20px;\n }\n\n .queue-icon {\n font-size: 32px;\n line-height: 1;\n animation: pulse 2s ease-in-out infinite;\n }\n\n @keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.6; }\n }\n\n .queue-title {\n flex: 1;\n }\n\n .queue-status {\n font-size: 16px;\n font-weight: 600;\n color: var(--queue-text, #e4e4e7);\n margin: 0 0 4px 0;\n }\n\n .queue-message {\n font-size: 13px;\n color: var(--queue-text-secondary, #a1a1aa);\n margin: 0;\n }\n\n .queue-badge {\n padding: 4px 12px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .queue-badge.waiting {\n background: rgba(251, 191, 36, 0.1);\n color: #fbbf24;\n }\n\n .queue-badge.processing {\n background: rgba(102, 126, 234, 0.1);\n color: #667eea;\n }\n\n .queue-badge.completed {\n background: rgba(16, 185, 129, 0.1);\n color: #10b981;\n }\n\n .queue-badge.error {\n background: rgba(239, 68, 68, 0.1);\n color: #ef4444;\n }\n\n .queue-position {\n text-align: center;\n margin: 24px 0;\n }\n\n .position-number {\n font-size: 64px;\n font-weight: 700;\n color: var(--queue-primary, #667eea);\n line-height: 1;\n margin: 0 0 8px 0;\n font-variant-numeric: tabular-nums;\n transition: all var(--transition-speed) ease;\n }\n\n .position-label {\n font-size: 14px;\n color: var(--queue-text-secondary, #a1a1aa);\n text-transform: uppercase;\n letter-spacing: 1px;\n font-weight: 500;\n }\n\n .queue-metrics {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));\n gap: 16px;\n margin: 20px 0;\n }\n\n .metric {\n background: var(--queue-metric-bg, #16162a);\n border: 1px solid var(--queue-border, #27273a);\n border-radius: 8px;\n padding: 12px 16px;\n }\n\n .metric-value {\n font-size: 24px;\n font-weight: 700;\n color: var(--queue-text, #e4e4e7);\n margin: 0 0 4px 0;\n font-variant-numeric: tabular-nums;\n }\n\n .metric-label {\n font-size: 12px;\n color: var(--queue-text-secondary, #a1a1aa);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n margin: 0;\n }\n\n .progress-container {\n margin: 20px 0;\n }\n\n .progress-bar {\n width: 100%;\n height: 8px;\n background: var(--queue-progress-bg, #27273a);\n border-radius: 4px;\n overflow: hidden;\n position: relative;\n }\n\n .progress-fill {\n height: 100%;\n background: linear-gradient(90deg, #667eea 0%, #764ba2 100%);\n border-radius: 4px;\n transition: width var(--transition-speed) ease;\n position: relative;\n overflow: hidden;\n }\n\n .progress-fill::after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: linear-gradient(\n 90deg,\n transparent,\n rgba(255, 255, 255, 0.3),\n transparent\n );\n animation: shimmer 2s infinite;\n }\n\n @keyframes shimmer {\n 0% { transform: translateX(-100%); }\n 100% { transform: translateX(100%); }\n }\n\n/* Override default animation when animation attribute is set */\n:host([animation]) .progress-fill::after {\n animation: none !important;\n}\n\n .info-icon {\n font-size: 18px;\n }\n\n .info-text {\n font-size: 13px;\n color: var(--queue-text, #e4e4e7);\n margin: 0;\n }\n\n .queue-actions {\n display: flex;\n gap: 12px;\n margin-top: 20px;\n }\n\n .queue-button {\n flex: 1;\n padding: 10px 16px;\n background: var(--queue-button-bg, #667eea);\n color: var(--queue-button-text, #ffffff);\n border: none;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all var(--transition-speed) ease;\n }\n\n .queue-button:hover:not(:disabled) {\n background: var(--queue-button-hover, #5568d3);\n transform: translateY(-1px);\n box-shadow: 0 4px 8px rgba(102, 126, 234, 0.3);\n }\n\n .queue-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .queue-button.secondary {\n background: var(--queue-button-secondary, #27273a);\n color: var(--queue-text, #e4e4e7);\n }\n\n .queue-button.secondary:hover:not(:disabled) {\n background: var(--queue-button-secondary-hover, #333348);\n }\n\n .error-message {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 12px;\n background: rgba(239, 68, 68, 0.1);\n border: 1px solid #ef4444;\n border-radius: 8px;\n color: #ef4444;\n margin-top: 16px;\n }\n\n .error-icon {\n font-size: 20px;\n }\n\n .error-text {\n font-size: 13px;\n margin: 0;\n }\n\n /* Animation for position change */\n @keyframes positionChange {\n 0% { transform: scale(1); }\n 50% { transform: scale(1.1); color: var(--queue-success, #10b981); }\n 100% { transform: scale(1); }\n }\n\n .position-number.changing {\n animation: positionChange 0.5s ease;\n }\n\n /* Visual Variants */\n\n /* Minimal variant - clean, no shadows */\n :host([variant="minimal"]) .queue-container {\n box-shadow: none;\n border: 1px solid var(--queue-border, #27273a);\n }\n\n :host([variant="minimal"]) .progress-bar {\n background: transparent;\n border: 1px solid var(--queue-border, #27273a);\n }\n\n /* Gradient variant - colorful gradients */\n :host([variant="gradient"]) .progress-fill {\n background: linear-gradient(\n 90deg,\n #667eea,\n #764ba2,\n #667eea\n );\n background-size: 200% 100%;\n animation: gradient-shift 3s ease-in-out infinite;\n }\n\n @keyframes gradient-shift {\n 0%, 100% { background-position: 0% 50%; }\n 50% { background-position: 100% 50%; }\n }\n\n /* Override default animation when animation attribute is set */\n :host([animation][variant="gradient"]) .progress-fill {\n animation: none !important;\n }\n\n /* Glassmorphic variant - frosted glass effect */\n :host([variant="glassmorphic"]) .queue-container {\n background: rgba(26, 26, 46, 0.6);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n }\n\n :host([variant="glassmorphic"]) .progress-bar {\n background: rgba(0, 0, 0, 0.2);\n }\n\n :host([variant="glassmorphic"]) .progress-fill {\n background: linear-gradient(\n 90deg,\n rgba(102, 126, 234, 0.8),\n rgba(118, 75, 162, 0.8)\n );\n }\n\n /* Animation Effects */\n\n /* Striped animation */\n :host([animation="striped"]) .progress-fill {\n background-image: \n linear-gradient(\n 45deg,\n rgba(255, 255, 255, 0.2) 25%,\n transparent 25%,\n transparent 50%,\n rgba(255, 255, 255, 0.2) 50%,\n rgba(255, 255, 255, 0.2) 75%,\n transparent 75%,\n transparent\n ),\n linear-gradient(to right, #667eea, #667eea) !important;\n background-size: 2rem 2rem, 100% 100% !important;\n animation: progress-stripes 3s linear infinite !important;\n }\n\n @keyframes progress-stripes {\n 0% { background-position: 0 0, 0 0; }\n 100% { background-position: 2rem 0, 0 0; }\n }\n\n /* Pulse animation */\n :host([animation="pulse"]) .progress-fill {\n animation: progress-pulse 4s ease-in-out infinite !important;\n }\n\n @keyframes progress-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n }\n\n /* Glow animation */\n :host([animation="glow"]) .progress-fill {\n animation: progress-glow 4s ease-in-out infinite !important;\n }\n\n @keyframes progress-glow {\n 0%, 100% { \n box-shadow: 0 0 5px #667eea,\n 0 0 10px #667eea;\n }\n 50% { \n box-shadow: 0 0 20px #667eea, \n 0 0 35px #667eea,\n 0 0 50px #667eea;\n }\n }\n\n /* Size variants */\n :host([size="compact"]) .queue-container {\n padding: 8px;\n font-size: 12px;\n }\n\n :host([size="compact"]) .progress-bar {\n height: 6px;\n }\n\n :host([size="compact"]) .queue-status {\n font-size: 14px;\n }\n\n :host([size="compact"]) .queue-message {\n font-size: 11px;\n }\n\n :host([size="compact"]) .position-number {\n font-size: 48px;\n }\n\n :host([size="compact"]) .metric-value {\n font-size: 22px;\n }\n\n :host([size="large"]) .queue-container {\n padding: 16px;\n font-size: 16px;\n }\n\n :host([size="large"]) .progress-bar {\n height: 10px;\n }\n\n :host([size="large"]) .queue-status {\n font-size: 18px;\n }\n\n :host([size="large"]) .queue-message {\n font-size: 15px;\n }\n\n :host([size="large"]) .position-number {\n font-size: 72px;\n }\n\n :host([size="large"]) .metric-value {\n font-size: 32px;\n }\n\n /* Responsive design */\n @media (max-width: 480px) {\n .queue-container {\n padding: 16px;\n }\n\n .position-number {\n font-size: 48px;\n }\n\n .queue-metrics {\n grid-template-columns: 1fr;\n }\n }\n\n /* Dark mode adjustments (default) */\n :host {\n color-scheme: dark;\n }\n\n /* Accessibility */\n .queue-button:focus-visible {\n outline: 2px solid var(--queue-primary, #667eea);\n outline-offset: 2px;\n }\n\n /* Reduced motion */\n @media (prefers-reduced-motion: reduce) {\n * {\n animation-duration: 0.01ms !important;\n animation-iteration-count: 1 !important;\n transition-duration: 0.01ms !important;\n }\n }\n</style>\n <div class="queue-container">\n <div class="queue-header">\n <div class="queue-icon">${this.getStatusIcon()}</div>\n <div class="queue-title">\n <h3 class="queue-status">${n}</h3>\n <p class="queue-message">${this.state.message||""}</p>\n </div>\n <span class="queue-badge ${e}">${this.state.status}</span>\n </div>\n\n ${this.config.showPosition&&"waiting"===this.state.status?`\n <div class="queue-position">\n <div class="position-number">${this.state.position}</div>\n <div class="position-label">Position in Queue</div>\n </div>\n `:""}\n\n ${this.renderMetrics()}\n\n ${this.config.showProgressBar&&"waiting"===this.state.status&&this.initialPosition>0?`\n <div class="progress-container">\n <div class="progress-bar">\n <div class="progress-fill" style="width: ${t}%"></div>\n </div>\n <div class="progress-label">\n <span>${Math.round(t)}% through queue</span>\n <span>${l(Math.round(this.state.elapsedTime/1e3))} elapsed</span>\n </div>\n </div>\n `:""}\n\n ${"waiting"===this.state.status&&this.state.position<=5?'\n <div class="queue-info">\n <span class="info-icon">🎯</span>\n <p class="info-text">You\'re almost there! Processing will begin shortly.</p>\n </div>\n ':""}\n\n ${"completed"===this.state.status?'\n <div class="queue-info">\n <span class="info-icon">βœ…</span>\n <p class="info-text">Your request is now being processed!</p>\n </div>\n ':""}\n\n ${"error"===this.state.status?`\n <div class="error-message">\n <span class="error-icon">⚠️</span>\n <p class="error-text">${this.state.message}</p>\n </div>\n `:""}\n </div>\n `,this.setAttribute("aria-valuenow",this.state.position.toString()),this.setAttribute("aria-valuetext",`Position ${this.state.position} in queue`)}getStatusIcon(){switch(this.state.status){case"waiting":default:return"⏳";case"processing":return"βš™οΈ";case"completed":return"βœ…";case"cancelled":return"🚫";case"error":return"❌"}}getStatusText(){switch(this.state.status){case"waiting":return"Waiting in Queue";case"processing":return"Processing Your Request";case"completed":return"Processing Started";case"cancelled":return"Queue Cancelled";case"error":return"Queue Error";default:return"Queue Status"}}}customElements.get("queue-progress")||customElements.define("queue-progress",u);class g extends s{constructor(t={}){super(t),n(this,"config"),n(this,"state"),n(this,"waitTimer"),n(this,"elapsedTimer"),n(this,"progressTimer"),this.config={attempt:t.attempt??1,maxAttempts:t.maxAttempts??3,initialDelay:t.initialDelay??1e3,maxDelay:t.maxDelay??3e4,backoffMultiplier:t.backoffMultiplier??2,strategy:t.strategy??"exponential",message:t.message??"Retrying operation...",showAttemptCount:t.showAttemptCount??!0,showNextRetry:t.showNextRetry??!0,showProgressBar:t.showProgressBar??!0,showElapsedTime:t.showElapsedTime??!0,allowManualRetry:t.allowManualRetry??!1,allowCancel:t.allowCancel??!0,animate:t.animate??!0,className:t.className??"",ariaLabel:t.ariaLabel??"Retry Progress",cursorFeedback:t.cursorFeedback??!0,debug:t.debug??!1,disabled:t.disabled??!1,size:t.size??"default",variant:t.variant??"default",animation:t.animation??"none"},this.state={status:"idle",attempt:this.config.attempt,maxAttempts:this.config.maxAttempts,currentDelay:this.config.initialDelay,nextRetryTime:0,startTime:0,elapsedTime:0,message:this.config.message},this.attachShadow({mode:"open"})}_readMaxAttemptsAttribute(){if(!this.hasAttribute("max-attempts"))return;const t=Number.parseInt(this.getAttribute("max-attempts")||"",10);Number.isNaN(t)||(this.config.maxAttempts=t,this.state.maxAttempts=t)}_readInitialDelayAttribute(){if(!this.hasAttribute("initial-delay"))return;const t=Number.parseInt(this.getAttribute("initial-delay")||"",10);Number.isNaN(t)||(this.config.initialDelay=t)}_readMaxDelayAttribute(){if(!this.hasAttribute("max-delay"))return;const t=Number.parseInt(this.getAttribute("max-delay")||"",10);Number.isNaN(t)||(this.config.maxDelay=t)}_readBackoffMultiplierAttribute(){if(!this.hasAttribute("backoff-multiplier"))return;const t=Number.parseFloat(this.getAttribute("backoff-multiplier")||"");Number.isNaN(t)||(this.config.backoffMultiplier=t)}_readStrategyAttribute(){if(!this.hasAttribute("strategy"))return;const t=this.getAttribute("strategy");["exponential","linear","fixed","fibonacci"].includes(t)&&(this.config.strategy=t)}_readBooleanAttributes(){this.hasAttribute("allow-manual-retry")&&(this.config.allowManualRetry="true"===this.getAttribute("allow-manual-retry")),this.hasAttribute("allow-cancel")&&(this.config.allowCancel="true"===this.getAttribute("allow-cancel")),this.hasAttribute("show-attempt-count")&&(this.config.showAttemptCount="true"===this.getAttribute("show-attempt-count")),this.hasAttribute("show-progress-bar")&&(this.config.showProgressBar="true"===this.getAttribute("show-progress-bar"))}connectedCallback(){super.connectedCallback(),this._readMaxAttemptsAttribute(),this._readInitialDelayAttribute(),this._readMaxDelayAttribute(),this._readBackoffMultiplierAttribute(),this._readStrategyAttribute(),this._readBooleanAttributes(),this.render()}calculateDelay(t){const{strategy:e,initialDelay:n,backoffMultiplier:s,maxDelay:a}=this.config;let i;switch(e){case"exponential":i=n*Math.pow(s,t-1);break;case"linear":i=n*t;break;case"fibonacci":i=n*this.fibonacci(t);break;default:i=n}return Math.min(i,a)}fibonacci(t){if(t<=1)return 1;let e=1,n=1;for(let s=2;s<t;s++)[e,n]=[n,e+n];return n}attempt(t){this.stopTimers();const e=t||`Attempt ${this.state.attempt} of ${this.state.maxAttempts}`;this.setState({status:"attempting",message:e,startTime:this.state.startTime||Date.now()}),this.startElapsedTimer(),this.dispatchEvent(new CustomEvent("retryattempt",{detail:{attempt:this.state.attempt,maxAttempts:this.state.maxAttempts,message:e,timestamp:Date.now()}})),this.log(`Retry attempt ${this.state.attempt}/${this.state.maxAttempts}: ${e}`)}waitForRetry(t={}){var e;const n=t.attempt??this.state.attempt+1;if(n>this.state.maxAttempts)return void this.failure(t.error);const s=t.delay??this.calculateDelay(n),a=Date.now()+s;this.setState({status:"waiting",attempt:n,currentDelay:s,nextRetryTime:a,message:t.message||`Retrying in ${l(Math.ceil(s/1e3))}...`,errorMessage:null==(e=t.error)?void 0:e.message,lastError:t.error}),this.startWaitTimer(s),this.startProgressTimer(s),this.dispatchEvent(new CustomEvent("retrywaiting",{detail:{attempt:n,delay:s,nextRetryTime:a,strategy:this.config.strategy,timestamp:Date.now()}})),this.log(`Waiting ${s}ms before retry ${n}/${this.state.maxAttempts}`)}success(t){this.stopTimers();const e=t||"Operation successful!";this.setState({status:"success",message:e}),this.dispatchEvent(new CustomEvent("retrysuccess",{detail:{attempt:this.state.attempt,totalAttempts:this.state.attempt,elapsedTime:this.state.elapsedTime,message:e,timestamp:Date.now()}})),this.log(`Success after ${this.state.attempt} attempts (${this.state.elapsedTime}ms)`)}failure(t){this.stopTimers(),this.setState({status:"failed",message:"Maximum retry attempts reached",errorMessage:(null==t?void 0:t.message)||"Operation failed",lastError:t}),this.dispatchEvent(new CustomEvent("retryfailure",{detail:{totalAttempts:this.state.attempt,lastError:t,elapsedTime:this.state.elapsedTime,timestamp:Date.now()}})),this.logError("Retry failed",t||new Error("Maximum attempts reached"))}cancel(t){this.stopTimers(),this.setState({status:"cancelled",message:t||"Operation cancelled"}),this.dispatchEvent(new CustomEvent("retrycancel",{detail:{attempt:this.state.attempt,reason:t,timestamp:Date.now()}})),this.log(`Retry cancelled: ${t||"User cancelled"}`)}reset(){this.stopTimers(),this.state={status:"idle",attempt:this.config.attempt,maxAttempts:this.config.maxAttempts,currentDelay:this.config.initialDelay,nextRetryTime:0,startTime:0,elapsedTime:0,message:this.config.message},this.render(),this.log("Reset to initial state")}getAttempt(){return this.state.attempt}getStatus(){return this.state.status}getTimeUntilRetry(){return"waiting"!==this.state.status?0:Math.max(0,this.state.nextRetryTime-Date.now())}startElapsedTimer(){this.elapsedTimer=globalThis.setInterval(()=>{this.state.startTime>0&&(this.state.elapsedTime=Date.now()-this.state.startTime,this.render())},1e3)}startWaitTimer(t){this.waitTimer=globalThis.setTimeout(()=>{"waiting"===this.state.status&&this.attempt()},t)}startProgressTimer(t){this.progressTimer=globalThis.setInterval(()=>{if("waiting"===this.state.status){const t=Math.max(0,this.state.nextRetryTime-Date.now());this.state.message=`Retrying in ${l(Math.ceil(t/1e3))}...`,this.render()}},100)}stopTimers(){this.waitTimer&&(globalThis.clearTimeout(this.waitTimer),this.waitTimer=void 0),this.elapsedTimer&&(globalThis.clearInterval(this.elapsedTimer),this.elapsedTimer=void 0),this.progressTimer&&(globalThis.clearInterval(this.progressTimer),this.progressTimer=void 0)}handleManualRetry(){"waiting"!==this.state.status&&"failed"!==this.state.status||(this.dispatchEvent(new CustomEvent("manualretry",{detail:{attempt:this.state.attempt,timestamp:Date.now()}})),this.attempt())}handleCancel(){this.cancel("User cancelled operation")}setState(t){Object.assign(this.state,t),this.render(),this.updateCursor();const e=(this.state.attempt/this.state.maxAttempts*100).toFixed(0);this.setAttribute("aria-valuenow",this.state.attempt.toString()),this.setAttribute("aria-valuemax",this.state.maxAttempts.toString()),this.setAttribute("aria-valuetext",`Attempt ${this.state.attempt} of ${this.state.maxAttempts}, ${e}% complete`)}updateCursor(){this.config.cursorFeedback&&("attempting"===this.state.status?this.style.cursor="progress":"waiting"===this.state.status?this.style.cursor="wait":"failed"===this.state.status||"cancelled"===this.state.status?this.style.cursor="not-allowed":this.style.cursor="default")}getStatusIcon(){switch(this.state.status){case"attempting":return"πŸ”„";case"waiting":return"⏳";case"success":return"βœ…";case"failed":return"❌";case"cancelled":return"🚫";default:return"⏸️"}}getStatusText(){switch(this.state.status){case"attempting":return"Attempting";case"waiting":return"Waiting";case"success":return"Success";case"failed":return"Failed";case"cancelled":return"Cancelled";default:return"Idle"}}getProgressPercentage(){if("waiting"!==this.state.status)return 0;const t=Date.now()-(this.state.nextRetryTime-this.state.currentDelay);return Math.min(100,t/this.state.currentDelay*100)}renderSuccessMessage(t,e){if("success"!==t)return"";return`\n <div class="success-message">\n <div class="success-icon">πŸŽ‰</div>\n <div class="success-text">Success!</div>\n <div class="success-details">Completed in ${e} attempt${e>1?"s":""}</div>\n </div>\n `}renderActions(t,e,n,s){if("success"===t||!e&&!n)return"";const a=e&&("waiting"===t||"failed"===t),i=n&&"cancelled"!==t&&"failed"!==t;if(!a&&!i)return"";const r=s?"disabled":"";let o="";return a&&(o+=`\n <button class="retry-button" id="manual-retry" ${r}>\n ${"failed"===t?"Try Again":"Retry Now"}\n </button>\n `),i&&(o+=`\n <button class="cancel-button" id="cancel-btn" ${r}>\n Cancel\n </button>\n `),`\n <div class="actions">\n ${o}\n </div>\n `}_syncAttributes(){this.config.size&&this.getAttribute("size")!==this.config.size&&this.setAttribute("size",this.config.size),this.config.variant&&this.getAttribute("variant")!==this.config.variant&&this.setAttribute("variant",this.config.variant),this.config.animation&&this.getAttribute("animation")!==this.config.animation&&this.setAttribute("animation",this.config.animation)}_getAttemptCounterHtml(t,e,n,s){return t?`\n <div class="attempt-counter">\n <div class="attempt-number ${s}">${e}</div>\n <div class="attempt-label">of ${n} attempts</div>\n </div>\n `:""}_getMetricsGridHtml(t,e,n,s,a,i){return`\n <div class="metrics-grid">\n ${t&&"waiting"===n?`\n <div class="metric">\n <div class="metric-value">${l(Math.ceil(s/1e3))}</div>\n <div class="metric-label">Next Retry</div>\n </div>\n `:""}\n ${e&&a>0?`\n <div class="metric">\n <div class="metric-value">${l(Math.ceil(a/1e3))}</div>\n <div class="metric-label">Elapsed</div>\n </div>\n `:""}\n <div class="metric">\n <div class="metric-value">${i}</div>\n <div class="metric-label">Strategy</div>\n </div>\n </div>\n `}_getProgressBarHtml(t,e,n){return t&&"waiting"===e?`\n <div class="progress-bar-container">\n <div class="progress-label">Time until next attempt</div>\n <div class="progress-bar">\n <div class="progress-fill" style="width: ${n}%"></div>\n </div>\n </div>\n `:""}_getErrorDisplayHtml(t,e){return!t||"waiting"!==e&&"failed"!==e?"":`\n <div class="error-display">\n <div class="error-title">Last Error</div>\n <div class="error-message">${t}</div>\n </div>\n `}_attachEventListeners(t,e){var n,s;if(t){const t=null==(n=this.shadowRoot)?void 0:n.getElementById("manual-retry");null==t||t.addEventListener("click",()=>this.handleManualRetry())}if(e){const t=null==(s=this.shadowRoot)?void 0:s.getElementById("cancel-btn");null==t||t.addEventListener("click",()=>this.handleCancel())}}render(){if(!this.shadowRoot)return;this._syncAttributes();const{status:t,attempt:e,maxAttempts:n,message:s,errorMessage:a,elapsedTime:i}=this.state,{showAttemptCount:r,showNextRetry:o,showProgressBar:l,showElapsedTime:d,allowManualRetry:c,allowCancel:p,disabled:h}=this.config,u=this.getTimeUntilRetry(),g=this.getProgressPercentage(),m=this._getAttemptCounterHtml(r,e,n,t),b=this._getMetricsGridHtml(o,d,t,u,i,this.config.strategy),f=this._getProgressBarHtml(l,t,g),v=this._getErrorDisplayHtml(a,t),x=this.renderSuccessMessage(t,e),y=this.renderActions(t,c,p,h);this.shadowRoot.innerHTML=`\n <style>\n :host {\n /* CSS variables inherit from document root with fallback defaults */\n display: block;\n font-family: var(--ai-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);\n font-size: var(--ai-font-size, 14px);\n }\n\n :host([style*="cursor: progress"]) .retry-container {\n cursor: progress;\n }\n\n :host([style*="cursor: wait"]) .retry-container {\n cursor: wait;\n }\n\n :host([style*="cursor: not-allowed"]) .retry-container {\n cursor: not-allowed;\n }\n\n :host([style*="cursor: default"]) .retry-container {\n cursor: default;\n }\n\n .retry-container {\n background: var(--retry-background);\n border-radius: 12px;\n padding: 20px;\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);\n border: 1px solid var(--retry-border);\n }\n\n .retry-container.disabled {\n opacity: 0.6;\n pointer-events: none;\n }\n\n /* Header */\n .retry-header {\n display: flex;\n align-items: center;\n gap: 12px;\n margin-bottom: 16px;\n }\n\n .retry-icon {\n font-size: 32px;\n animation: rotate 2s linear infinite;\n }\n\n .retry-icon.success {\n animation: none;\n }\n\n .retry-icon.failed {\n animation: shake 0.5s ease;\n }\n\n @keyframes rotate {\n from { transform: rotate(0deg); }\n to { transform: rotate(360deg); }\n }\n\n @keyframes shake {\n 0%, 100% { transform: translateX(0); }\n 25% { transform: translateX(-5px); }\n 75% { transform: translateX(5px); }\n }\n\n .retry-info {\n flex: 1;\n }\n\n .retry-title {\n font-size: 16px;\n font-weight: 600;\n color: var(--retry-text);\n margin: 0 0 4px 0;\n }\n\n .retry-message {\n font-size: 14px;\n color: var(--retry-text-secondary);\n margin: 0;\n }\n\n /* Status Badge */\n .status-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 4px 12px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .status-badge.idle {\n background: #4b5563;\n color: #d1d5db;\n }\n\n .status-badge.attempting {\n background: #3b82f6;\n color: white;\n animation: pulse 2s infinite;\n }\n\n .status-badge.waiting {\n background: var(--retry-primary);\n color: white;\n }\n\n .status-badge.success {\n background: var(--retry-success);\n color: white;\n }\n\n .status-badge.failed {\n background: var(--retry-error);\n color: white;\n }\n\n .status-badge.cancelled {\n background: #6b7280;\n color: white;\n }\n\n @keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.7; }\n }\n\n /* Attempt Counter */\n .attempt-counter {\n text-align: center;\n margin: 16px 0;\n }\n\n .attempt-number {\n font-size: 48px;\n font-weight: 700;\n color: var(--retry-primary);\n line-height: 1;\n margin-bottom: 8px;\n }\n\n .attempt-number.success {\n color: var(--retry-success);\n }\n\n .attempt-number.failed {\n color: var(--retry-error);\n }\n\n .attempt-label {\n font-size: 14px;\n color: var(--retry-text-secondary);\n text-transform: uppercase;\n letter-spacing: 1px;\n }\n\n /* Metrics Grid */\n .metrics-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));\n gap: 12px;\n margin: 16px 0;\n }\n\n .metric {\n background: rgba(0, 0, 0, 0.3);\n border-radius: 8px;\n padding: 12px;\n text-align: center;\n border: 1px solid rgba(255, 255, 255, 0.1);\n }\n\n .metric-value {\n font-size: 20px;\n font-weight: 600;\n color: var(--retry-text);\n margin-bottom: 4px;\n }\n\n .metric-label {\n font-size: 11px;\n color: var(--retry-text-secondary);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n /* Progress Bar */\n .progress-bar-container {\n margin: 16px 0;\n }\n\n .progress-label {\n font-size: 12px;\n color: var(--retry-text-secondary);\n margin-bottom: 8px;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n }\n\n .progress-bar {\n height: 8px;\n background: rgba(0, 0, 0, 0.3);\n border-radius: 4px;\n overflow: hidden;\n position: relative;\n }\n\n .progress-fill {\n height: 100%;\n background: linear-gradient(90deg, var(--retry-primary), #fbbf24);\n border-radius: 4px;\n transition: width 0.3s ease;\n position: relative;\n }\n\n .progress-fill::after {\n content: '';\n position: absolute;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: linear-gradient(\n 90deg,\n transparent,\n rgba(255, 255, 255, 0.3),\n transparent\n );\n animation: shimmer 2s infinite;\n }\n\n @keyframes shimmer {\n 0% { transform: translateX(-100%); }\n 100% { transform: translateX(100%); }\n }\n\n/* Override default animation when animation attribute is set */\n:host([animation]) .progress-fill::after {\n animation: none !important;\n}\n font-size: 13px;\n color: #fca5a5;\n font-family: 'Monaco', 'Courier New', monospace;\n word-break: break-word;\n }\n\n /* Action Buttons */\n .actions {\n display: flex;\n gap: 8px;\n margin-top: 16px;\n }\n\n .retry-button,\n .cancel-button {\n flex: 1;\n padding: 10px 16px;\n border: none;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s;\n }\n\n .retry-button {\n background: linear-gradient(135deg, var(--retry-primary), #fbbf24);\n color: white;\n }\n\n .retry-button:hover:not(:disabled) {\n transform: translateY(-2px);\n box-shadow: 0 4px 12px rgba(245, 158, 11, 0.4);\n }\n\n .retry-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .cancel-button {\n background: #4b5563;\n color: white;\n }\n\n .cancel-button:hover:not(:disabled) {\n background: #6b7280;\n }\n\n .cancel-button:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n /* Success State */\n .success-message {\n background: rgba(16, 185, 129, 0.1);\n border: 1px solid var(--retry-success);\n border-radius: 8px;\n padding: 16px;\n margin: 16px 0;\n text-align: center;\n }\n\n .success-icon {\n font-size: 48px;\n margin-bottom: 8px;\n }\n\n .success-text {\n font-size: 16px;\n font-weight: 600;\n color: var(--retry-success);\n margin-bottom: 4px;\n }\n\n .success-details {\n font-size: 13px;\n color: var(--retry-text-secondary);\n }\n\n /* Visual Variants */\n\n /* Minimal variant - clean, no shadows */\n :host([variant="minimal"]) .retry-container {\n box-shadow: none;\n border: 1px solid var(--retry-border);\n }\n\n :host([variant="minimal"]) .progress-bar {\n background: transparent;\n border: 1px solid rgba(255, 255, 255, 0.1);\n }\n\n /* Gradient variant - colorful gradients */\n :host([variant="gradient"]) .progress-fill {\n background: linear-gradient(\n 90deg,\n var(--retry-primary),\n #fbbf24,\n var(--retry-primary)\n );\n background-size: 200% 100%;\n animation: gradient-shift 3s ease-in-out infinite;\n }\n\n @keyframes gradient-shift {\n 0%, 100% { background-position: 0% 50%; }\n 50% { background-position: 100% 50%; }\n }\n\n /* Override gradient animation when custom animation is set */\n :host([animation]:not([animation="none"])[variant="gradient"]) .progress-fill {\n animation: none !important;\n }\n\n /* Override default animation when animation attribute is set */\n :host([animation][variant="gradient"]) .progress-fill {\n animation: none !important;\n }\n\n /* Glassmorphic variant - frosted glass effect */\n :host([variant="glassmorphic"]) .retry-container {\n background: rgba(var(--retry-background-rgb, 26, 26, 46), 0.6);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.1);\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);\n }\n\n :host([variant="glassmorphic"]) .progress-bar {\n background: rgba(0, 0, 0, 0.2);\n }\n\n :host([variant="glassmorphic"]) .progress-fill {\n background: linear-gradient(\n 90deg,\n rgba(245, 158, 11, 0.8),\n rgba(251, 191, 36, 0.8)\n );\n }\n\n /* Animation Effects */\n\n /* Striped animation */\n :host([animation="striped"]) .progress-fill {\n background-image: \n linear-gradient(\n 45deg,\n rgba(255, 255, 255, 0.2) 25%,\n transparent 25%,\n transparent 50%,\n rgba(255, 255, 255, 0.2) 50%,\n rgba(255, 255, 255, 0.2) 75%,\n transparent 75%,\n transparent\n ),\n linear-gradient(to right, var(--retry-primary), var(--retry-primary)) !important;\n background-size: 2rem 2rem, 100% 100% !important;\n animation: progress-stripes 3s linear infinite !important;\n }\n\n @keyframes progress-stripes {\n 0% { background-position: 0 0, 0 0; }\n 100% { background-position: 2rem 0, 0 0; }\n }\n\n /* Pulse animation */\n :host([animation="pulse"]) .progress-fill {\n animation: progress-pulse 4s ease-in-out infinite !important;\n }\n\n @keyframes progress-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n }\n\n /* Glow animation */\n :host([animation="glow"]) .progress-fill {\n animation: progress-glow 4s ease-in-out infinite !important;\n }\n\n @keyframes progress-glow {\n 0%, 100% { \n box-shadow: 0 0 5px var(--retry-primary),\n 0 0 10px var(--retry-primary);\n }\n 50% { \n box-shadow: 0 0 20px var(--retry-primary), \n 0 0 35px var(--retry-primary),\n 0 0 50px var(--retry-primary);\n }\n }\n\n /* Size variants */\n :host([size="compact"]) .retry-container {\n padding: 8px;\n font-size: 12px;\n }\n\n :host([size="compact"]) .progress-bar {\n height: 6px;\n }\n\n :host([size="compact"]) .retry-title {\n font-size: 14px;\n }\n\n :host([size="compact"]) .retry-message {\n font-size: 12px;\n }\n\n :host([size="compact"]) .attempt-number {\n font-size: 40px;\n }\n\n :host([size="compact"]) .metric-value {\n font-size: 20px;\n }\n\n :host([size="large"]) .retry-container {\n padding: 16px;\n font-size: 16px;\n }\n\n :host([size="large"]) .progress-bar {\n height: 10px;\n }\n\n :host([size="large"]) .retry-title {\n font-size: 18px;\n }\n\n :host([size="large"]) .retry-message {\n font-size: 16px;\n }\n\n :host([size="large"]) .attempt-number {\n font-size: 56px;\n }\n\n :host([size="large"]) .metric-value {\n font-size: 28px;\n }\n\n /* Responsive */\n @media (max-width: 480px) {\n .retry-container {\n padding: 16px;\n }\n\n .attempt-number {\n font-size: 36px;\n }\n\n .metrics-grid {\n grid-template-columns: repeat(2, 1fr);\n }\n\n .actions {\n flex-direction: column;\n }\n }\n\n /* Accessibility */\n .retry-button:focus-visible,\n .cancel-button:focus-visible {\n outline: 2px solid var(--retry-primary);\n outline-offset: 2px;\n }\n\n @media (prefers-reduced-motion: reduce) {\n .retry-icon,\n .progress-fill::after {\n animation: none;\n }\n }\n</style>\n <div class="retry-container ${h?"disabled":""}" role="status">\n <div class="retry-header">\n <div class="retry-icon ${t}">${this.getStatusIcon()}</div>\n <div class="retry-info">\n <h3 class="retry-title">${this.getStatusText()}</h3>\n <p class="retry-message">${s}</p>\n </div>\n <span class="status-badge ${t}">${this.getStatusText()}</span>\n </div>\n\n ${m}\n ${b}\n ${f}\n ${v}\n ${x}\n ${y}\n </div>\n `,this._attachEventListeners(c,p)}disconnectedCallback(){super.disconnectedCallback(),this.stopTimers()}static get observedAttributes(){return["attempt","max-attempts","initial-delay","max-delay","backoff-multiplier","strategy","allow-manual-retry","allow-cancel","show-attempt-count","show-progress-bar","disabled","size","variant","animation"]}handleAttributeChange(t,e,n){switch(t){case"attempt":this.state.attempt=Number.parseInt(n,10)||1;break;case"max-attempts":{const t=Number.parseInt(n,10)||3;this.state.maxAttempts=t,this.config.maxAttempts=t;break}case"initial-delay":{const t=Number.parseInt(n,10);!1===Number.isNaN(t)&&(this.config.initialDelay=t);break}case"max-delay":{const t=Number.parseInt(n,10);!1===Number.isNaN(t)&&(this.config.maxDelay=t);break}case"backoff-multiplier":{const t=Number.parseFloat(n);!1===Number.isNaN(t)&&(this.config.backoffMultiplier=t);break}case"strategy":["exponential","linear","fixed","fibonacci"].includes(n)&&(this.config.strategy=n);break;case"allow-manual-retry":this.config.allowManualRetry="true"===n;break;case"allow-cancel":this.config.allowCancel="true"===n;break;case"show-attempt-count":this.config.showAttemptCount="true"===n;break;case"show-progress-bar":this.config.showProgressBar="true"===n;break;case"variant":this.config.variant=n,this.render();break;case"animation":this.config.animation=n,this.render();break;case"disabled":this._disabled=null!==n;break;case"size":this.config.size=n}this.render()}}customElements.get("retry-progress")||customElements.define("retry-progress",g);class m extends s{constructor(t={}){super({debug:t.debug??!1,className:t.className,ariaLabel:t.ariaLabel??"Batch Progress"}),n(this,"config"),n(this,"state"),n(this,"updateThrottleTimer",null),this.config={totalItems:t.totalItems??0,concurrency:t.concurrency??5,showItems:t.showItems??!0,maxDisplayItems:t.maxDisplayItems??100,showProgressBar:t.showProgressBar??!0,showStats:t.showStats??!0,showTime:t.showTime??!0,showRate:t.showRate??!0,allowCancel:t.allowCancel??!0,cancelLabel:t.cancelLabel??"Cancel Batch",collapseCompleted:t.collapseCompleted??!1,message:t.message??"Processing batch...",disabled:t.disabled??!1,debug:t.debug??!1,className:t.className??"",ariaLabel:t.ariaLabel??"Batch Progress",cursorFeedback:t.cursorFeedback??!0,size:t.size??"default",variant:t.variant??"default",animation:t.animation??"none"},this.state={status:"idle",items:new Map,totalItems:this.config.totalItems,completedCount:0,failedCount:0,successCount:0,currentConcurrency:0,startTime:null,endTime:null,message:this.config.message},this.attachShadow({mode:"open"})}static get observedAttributes(){return["total-items","disabled","size","variant","animation"]}connectedCallback(){super.connectedCallback(),this.render()}attributeChangedCallback(t,e,n){if(e!==n)switch(t){case"total-items":this.state.totalItems=Number.parseInt(n||"0",10),this.render();break;case"disabled":this._disabled=null!==n,this.render();break;case"size":this.config.size=n,this.render();break;case"variant":this.config.variant=n,this.render();break;case"animation":this.config.animation=n,this.render()}}updateCursor(){this.config.cursorFeedback&&("processing"===this.state.status?this.style.cursor="progress":"cancelled"===this.state.status?this.style.cursor="not-allowed":this.style.cursor="default")}start(t){if(this.config.disabled)return;this.state.status="processing",this.state.startTime=Date.now(),this.state.message=t||this.config.message,this.state.completedCount=0,this.state.failedCount=0,this.state.successCount=0,this.render(),this.updateCursor();const e={totalItems:this.state.totalItems,startTime:this.state.startTime};this.dispatchEvent(new CustomEvent("batchstart",{detail:e,bubbles:!0,composed:!0})),this.log("Batch started",e)}addItem(t,e){const n={id:t,label:e||t,status:"pending",progress:0};this.state.items.set(t,n),this.state.totalItems=this.state.items.size,this.render(),this.log("Item added",n)}updateItem(t){const e=this.state.items.get(t.itemId);if(!e)return void this.log(`Item not found: ${t.itemId}`);t.status&&(e.status=t.status),void 0!==t.progress&&(e.progress=t.progress),t.error&&(e.error=t.error),void 0!==t.result&&(e.result=t.result),t.label&&(e.label=t.label),"completed"===t.status?(e.endTime=Date.now(),this.state.completedCount++,e.error||this.state.successCount++):"failed"===t.status&&(e.endTime=Date.now(),this.state.completedCount++,this.state.failedCount++),this.throttledRender();const n=this.getOverallProgress(),s={...e,totalCompleted:this.state.completedCount,totalFailed:this.state.failedCount,overallProgress:n};this.dispatchEvent(new CustomEvent("itemupdate",{detail:s,bubbles:!0,composed:!0})),this.state.completedCount===this.state.totalItems&&"processing"===this.state.status&&this.complete()}completeItem(t,e){this.updateItem({itemId:t,status:"completed",progress:100,result:e});const n=this.state.items.get(t);if(!n)return;const s={item:n,totalCompleted:this.state.completedCount,remainingItems:this.state.totalItems-this.state.completedCount};this.dispatchEvent(new CustomEvent("itemcomplete",{detail:s,bubbles:!0,composed:!0}))}failItem(t,e){this.updateItem({itemId:t,status:"failed",error:e});const n=this.state.items.get(t);if(!n)return;const s={item:n,error:e,totalFailed:this.state.failedCount};this.dispatchEvent(new CustomEvent("itemfailed",{detail:s,bubbles:!0,composed:!0}))}complete(){this.state.status="completed",this.state.endTime=Date.now(),this.render(),this.updateCursor();const t=this.state.endTime-(this.state.startTime||0),e=this.state.totalItems/(t/1e3),n={totalItems:this.state.totalItems,successCount:this.state.successCount,failedCount:this.state.failedCount,duration:t,averageRate:e,startTime:this.state.startTime,endTime:this.state.endTime};this.dispatchEvent(new CustomEvent("batchcomplete",{detail:n,bubbles:!0,composed:!0})),this.log("Batch completed",n)}cancel(t){this.state.status="cancelled",this.state.endTime=Date.now();let e=0;this.state.items.forEach(t=>{"pending"!==t.status&&"processing"!==t.status||(t.status="cancelled",e++)}),this.render(),this.updateCursor();const n={completedCount:this.state.completedCount,failedCount:this.state.failedCount,cancelledCount:e,reason:t};this.dispatchEvent(new CustomEvent("batchcancel",{detail:n,bubbles:!0,composed:!0})),this.log("Batch cancelled",n)}reset(){this.state.status="idle",this.state.items.clear(),this.state.totalItems=this.config.totalItems,this.state.completedCount=0,this.state.failedCount=0,this.state.successCount=0,this.state.currentConcurrency=0,this.state.startTime=null,this.state.endTime=null,this.state.message=this.config.message,this.render(),this.log("Batch reset")}getOverallProgress(){return 0===this.state.totalItems?0:this.state.completedCount/this.state.totalItems*100}getRate(){if(!this.state.startTime||0===this.state.completedCount)return 0;const t=(Date.now()-this.state.startTime)/1e3;return this.state.completedCount/t}getStats(){return{total:this.state.totalItems,completed:this.state.completedCount,success:this.state.successCount,failed:this.state.failedCount,pending:this.state.totalItems-this.state.completedCount,progress:this.getOverallProgress(),rate:this.getRate(),duration:this._calculateDuration()}}throttledRender(){this.updateThrottleTimer||(this.updateThrottleTimer=globalThis.setTimeout(()=>{this.render(),this.updateThrottleTimer=null},100))}_calculateDuration(){return this.state.endTime?this.state.endTime-(this.state.startTime||0):this.state.startTime?Date.now()-this.state.startTime:0}_getRateDisplay(t){return this.config.showRate?`\n <div class="stat-item">\n <span class="stat-label">Rate</span>\n <span class="stat-value rate">${t.toFixed(1)}/s</span>\n </div>\n `:""}_syncAttributes(){this.config.size&&this.getAttribute("size")!==this.config.size&&this.setAttribute("size",this.config.size),this.config.variant&&this.getAttribute("variant")!==this.config.variant&&this.setAttribute("variant",this.config.variant),this.config.animation&&this.getAttribute("animation")!==this.config.animation&&this.setAttribute("animation",this.config.animation)}_getStatusBadgeClass(t){switch(t){case"processing":return"processing";case"completed":return"completed";case"cancelled":return"cancelled";default:return""}}_getStatusText(t){switch(t){case"idle":return"Ready";case"processing":return"Processing";case"completed":return"Completed";case"cancelled":return"Cancelled";default:return""}}_getStatsHtml(t,e){return this.config.showStats?`\n <div class="stats">\n <div class="stat-item">\n <span class="stat-label">Total</span>\n <span class="stat-value">${t.total}</span>\n </div>\n <div class="stat-item">\n <span class="stat-label">Success</span>\n <span class="stat-value success">${t.success}</span>\n </div>\n <div class="stat-item">\n <span class="stat-label">Failed</span>\n <span class="stat-value error">${t.failed}</span>\n </div>\n ${this._getRateDisplay(e)}\n </div>\n `:""}_getProgressBarHtml(t,e){return this.config.showProgressBar?`\n <div class="overall-progress">\n <div class="progress-header">\n <span>Overall Progress</span>\n <span>${e.completed} / ${e.total} (${t.toFixed(0)}%)</span>\n </div>\n <div class="progress-bar">\n <div class="progress-fill" style="width: ${t}%"></div>\n </div>\n </div>\n `:""}_getControlsHtml(){if(!this.config.allowCancel||"processing"!==this.state.status)return"";return`\n <div class="controls">\n <button class="cancel-btn" id="cancel-btn" ${this.config.disabled?"disabled":""}>\n ${this.config.cancelLabel}\n </button>\n </div>\n `}_attachEventListeners(){var t;if(!this.config.allowCancel)return;const e=null==(t=this.shadowRoot)?void 0:t.getElementById("cancel-btn");e&&e.addEventListener("click",()=>this.cancel("User cancelled"))}render(){if(!this.shadowRoot)return;this._syncAttributes();const t=this.getOverallProgress(),e=this.getRate(),n=this.getStats(),s=this._getStatusBadgeClass(this.state.status),a=this._getStatusText(this.state.status),i=this._getStatsHtml(n,e),r=this._getProgressBarHtml(t,n),o=this.config.showItems?this.renderItems():"",l=this._getControlsHtml();this.shadowRoot.innerHTML=`\n <style>\n :host {\n /* CSS variables inherit from document root with fallback defaults */\n display: block;\n font-family: var(--ai-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif);\n font-size: var(--ai-font-size, 14px);\n color: var(--ai-text-color, #1f2937);\n }\n\n :host([style*="cursor: progress"]) .container {\n cursor: progress;\n }\n\n :host([style*="cursor: not-allowed"]) .container {\n cursor: not-allowed;\n }\n\n :host([style*="cursor: default"]) .container {\n cursor: default;\n }\n\n .container {\n background: var(--ai-background-color, #ffffff);\n border: 1px solid var(--ai-border-color, #e5e7eb);\n border-radius: var(--ai-border-radius, 8px);\n padding: var(--ai-spacing, 12px);\n }\n\n .header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: var(--ai-spacing, 12px);\n }\n\n .status-message {\n font-weight: 600;\n color: var(--ai-text-color, #1f2937);\n font-size: 14px;\n }\n\n .status-badge {\n padding: 4px 10px;\n border-radius: 12px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n }\n\n .status-badge.processing {\n background: #dbeafe;\n color: #1e40af;\n }\n\n .status-badge.completed {\n background: #d1fae5;\n color: #065f46;\n }\n\n .status-badge.cancelled {\n background: #fee2e2;\n color: #991b1b;\n }\n\n .stats {\n display: flex;\n gap: 16px;\n margin-bottom: var(--ai-spacing, 12px);\n padding: 8px;\n background: #f9fafb;\n border-radius: 6px;\n }\n\n .stat-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .stat-label {\n font-size: 11px;\n color: #6b7280;\n text-transform: uppercase;\n font-weight: 600;\n letter-spacing: 0.5px;\n }\n\n .stat-value {\n font-size: 18px;\n font-weight: 700;\n color: var(--ai-text-color, #1f2937);\n }\n\n .stat-value.success {\n color: var(--ai-secondary-color, #10b981);\n }\n\n .stat-value.error {\n color: #ef4444;\n }\n\n .stat-value.rate {\n color: var(--ai-primary-color, #3b82f6);\n }\n\n .overall-progress {\n margin-bottom: var(--ai-spacing, 12px);\n }\n\n .progress-header {\n display: flex;\n justify-content: space-between;\n margin-bottom: 6px;\n font-size: 12px;\n color: #6b7280;\n }\n\n .progress-bar {\n width: 100%;\n height: 8px;\n background: #f3f4f6;\n border-radius: 4px;\n overflow: hidden;\n position: relative;\n }\n\n .progress-fill {\n height: 100%;\n background: linear-gradient(90deg, var(--ai-primary-color, #3b82f6), var(--ai-secondary-color, #10b981));\n transition: width 0.3s ease;\n border-radius: 4px;\n }\n\n .items-container {\n max-height: 400px;\n overflow-y: auto;\n border: 1px solid var(--ai-border-color, #e5e7eb);\n border-radius: 6px;\n background: white;\n }\n\n .batch-item {\n padding: 10px 12px;\n border-bottom: 1px solid var(--ai-border-color, #e5e7eb);\n transition: background 0.2s;\n }\n\n .batch-item:last-child {\n border-bottom: none;\n }\n\n .batch-item.processing {\n background: #eff6ff;\n }\n\n .batch-item.completed {\n background: #f0fdf4;\n }\n\n .batch-item.failed {\n background: #fef2f2;\n }\n\n .batch-item.collapsed {\n opacity: 0.6;\n max-height: 0;\n padding: 0 12px;\n overflow: hidden;\n transition: max-height 0.3s, padding 0.3s, opacity 0.3s;\n }\n\n .item-header {\n display: flex;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 4px;\n }\n\n .item-label {\n font-size: 13px;\n font-weight: 500;\n color: var(--ai-text-color, #1f2937);\n flex: 1;\n }\n\n .item-status {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 11px;\n font-weight: 600;\n }\n\n .item-status.pending {\n color: #6b7280;\n }\n\n .item-status.processing {\n color: var(--ai-primary-color, #3b82f6);\n }\n\n .item-status.completed {\n color: var(--ai-secondary-color, #10b981);\n }\n\n .item-status.failed {\n color: #ef4444;\n }\n\n .item-status-icon {\n font-size: 14px;\n }\n\n .item-progress-bar {\n height: 4px;\n background: #e5e7eb;\n border-radius: 2px;\n overflow: hidden;\n margin-top: 4px;\n }\n\n .item-progress-fill {\n height: 100%;\n background: var(--ai-primary-color, #3b82f6);\n transition: width 0.3s ease;\n border-radius: 2px;\n }\n\n .item-error {\n margin-top: 4px;\n padding: 6px 8px;\n background: #fee2e2;\n border-left: 3px solid #ef4444;\n border-radius: 4px;\n font-size: 12px;\n color: #991b1b;\n }\n\n .controls {\n margin-top: var(--ai-spacing, 12px);\n display: flex;\n justify-content: flex-end;\n }\n\n .cancel-btn {\n padding: 8px 16px;\n background: #fee2e2;\n color: #991b1b;\n border: 1px solid #fecaca;\n border-radius: 6px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n transition: background 0.2s;\n }\n\n .cancel-btn:hover:not(:disabled) {\n background: #fecaca;\n }\n\n .cancel-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n .spinner {\n display: inline-block;\n width: 12px;\n height: 12px;\n border: 2px solid currentColor;\n border-radius: 50%;\n border-top-color: transparent;\n animation: spin 0.6s linear infinite;\n }\n\n @keyframes spin {\n to { transform: rotate(360deg); }\n }\n\n .empty-state {\n text-align: center;\n padding: 40px 20px;\n color: #9ca3af;\n }\n\n .empty-state-icon {\n font-size: 48px;\n margin-bottom: 12px;\n }\n\n /* Visual Variants */\n\n /* Minimal variant - clean, no shadows */\n :host([variant="minimal"]) .container {\n box-shadow: none;\n border: 1px solid var(--ai-border-color, #e5e7eb);\n }\n\n :host([variant="minimal"]) .progress-bar {\n background: transparent;\n border: 1px solid var(--ai-border-color, #e5e7eb);\n }\n\n /* Gradient variant - colorful gradients */\n :host([variant="gradient"]) .progress-fill {\n background: linear-gradient(\n 90deg,\n var(--ai-primary-color, #3b82f6),\n var(--ai-secondary-color, #10b981),\n var(--ai-primary-color, #3b82f6)\n );\n background-size: 200% 100%;\n animation: gradient-shift 3s ease-in-out infinite;\n }\n\n @keyframes gradient-shift {\n 0%, 100% { background-position: 0% 50%; }\n 50% { background-position: 100% 50%; }\n }\n\n /* Override default animation when animation attribute is set */\n :host([animation][variant="gradient"]) .progress-fill {\n animation: none !important;\n }\n\n /* Glassmorphic variant - frosted glass effect */\n :host([variant="glassmorphic"]) .container {\n background: rgba(255, 255, 255, 0.1);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n border: 1px solid rgba(255, 255, 255, 0.2);\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);\n }\n\n :host([variant="glassmorphic"]) .progress-bar {\n background: rgba(0, 0, 0, 0.1);\n }\n\n :host([variant="glassmorphic"]) .progress-fill {\n background: linear-gradient(\n 90deg,\n rgba(59, 130, 246, 0.8),\n rgba(16, 185, 129, 0.8)\n );\n }\n\n /* Animation Effects */\n\n /* Striped animation */\n :host([animation="striped"]) .progress-fill {\n background-image: \n linear-gradient(\n 45deg,\n rgba(255, 255, 255, 0.2) 25%,\n transparent 25%,\n transparent 50%,\n rgba(255, 255, 255, 0.2) 50%,\n rgba(255, 255, 255, 0.2) 75%,\n transparent 75%,\n transparent\n ),\n linear-gradient(to right, var(--ai-primary-color, #3b82f6), var(--ai-primary-color, #3b82f6)) !important;\n background-size: 2rem 2rem, 100% 100% !important;\n animation: progress-stripes 3s linear infinite !important;\n}\n\n@keyframes progress-stripes {\n 0% { background-position: 0 0, 0 0; }\n 100% { background-position: 2rem 0, 0 0; }\n}\n\n/* Pulse animation */\n:host([animation="pulse"]) .progress-fill {\n animation: progress-pulse 4s ease-in-out infinite !important;\n}\n\n@keyframes progress-pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n}\n\n/* Glow animation */\n:host([animation="glow"]) .progress-fill {\n animation: progress-glow 4s ease-in-out infinite !important;\n}\n\n@keyframes progress-glow {\n 0%, 100% { \n box-shadow: 0 0 5px var(--ai-primary-color, #3b82f6),\n 0 0 10px var(--ai-primary-color, #3b82f6);\n }\n 50% { \n box-shadow: 0 0 20px var(--ai-primary-color, #3b82f6), \n 0 0 35px var(--ai-primary-color, #3b82f6),\n 0 0 50px var(--ai-primary-color, #3b82f6);\n }\n}\n\n /* Size variants */\n :host([size="compact"]) .container {\n padding: 8px;\n font-size: 12px;\n }\n\n :host([size="compact"]) .progress-bar {\n height: 6px;\n }\n\n :host([size="compact"]) .status-message {\n font-size: 12px;\n }\n\n :host([size="compact"]) .status-badge {\n padding: 3px 8px;\n font-size: 10px;\n }\n\n :host([size="compact"]) .stat-value {\n font-size: 16px;\n }\n\n :host([size="compact"]) .stat-label {\n font-size: 10px;\n }\n\n :host([size="large"]) .container {\n padding: 16px;\n font-size: 16px;\n }\n\n :host([size="large"]) .progress-bar {\n height: 10px;\n }\n\n :host([size="large"]) .status-message {\n font-size: 16px;\n }\n\n :host([size="large"]) .status-badge {\n padding: 5px 12px;\n font-size: 13px;\n }\n\n :host([size="large"]) .stat-value {\n font-size: 20px;\n }\n\n :host([size="large"]) .stat-label {\n font-size: 12px;\n }\n\n /* Accessibility */\n @media (prefers-reduced-motion: reduce) {\n .progress-fill,\n .item-progress-fill,\n .spinner {\n animation: none;\n transition: none;\n }\n }\n\n /* Scrollbar styling */\n .items-container::-webkit-scrollbar {\n width: 8px;\n }\n\n .items-container::-webkit-scrollbar-track {\n background: #f3f4f6;\n border-radius: 4px;\n }\n\n .items-container::-webkit-scrollbar-thumb {\n background: #d1d5db;\n border-radius: 4px;\n }\n\n .items-container::-webkit-scrollbar-thumb:hover {\n background: #9ca3af;\n }\n</style>\n <div class="container">\n <div class="header">\n <div class="status-message">${this.state.message}</div>\n ${s?`<span class="status-badge ${s}">${a}</span>`:""}\n </div>\n ${i}\n ${r}\n ${o}\n ${l}\n </div>\n `,this._attachEventListeners()}renderItems(){if(0===this.state.items.size)return'\n <div class="empty-state">\n <div class="empty-state-icon">πŸ“¦</div>\n <div>No items in batch</div>\n </div>\n ';return`\n <div class="items-container">\n ${Array.from(this.state.items.values()).slice(0,this.config.maxDisplayItems).map(t=>{const e=this.getStatusIcon(t.status),n=this.config.collapseCompleted&&"completed"===t.status?"collapsed":"",s="processing"===t.status&&void 0!==t.progress?`\n <div class="item-progress-bar">\n <div class="item-progress-fill" style="width: ${t.progress}%"></div>\n </div>\n `:"",a=t.error?`\n <div class="item-error">\n ${t.error}\n </div>\n `:"";return`\n <div class="batch-item ${t.status} ${n}">\n <div class="item-header">\n <span class="item-label">${t.label||t.id}</span>\n <span class="item-status ${t.status}">\n <span class="item-status-icon">${e}</span>\n ${t.status}\n </span>\n </div>\n ${s}\n ${a}\n </div>\n `}).join("")}\n </div>\n `}getStatusIcon(t){switch(t){case"pending":return"⏳";case"processing":return'<span class="spinner"></span>';case"completed":return"βœ…";case"failed":return"❌";case"cancelled":return"β›”";default:return""}}get disabled(){return this.config.disabled}set disabled(t){this.config.disabled=t,t?this.setAttribute("disabled",""):this.removeAttribute("disabled"),this.render()}}customElements.get("batch-progress")||customElements.define("batch-progress",m),t.AIControl=s,t.BatchProgress=m,t.ModelLoader=c,t.ParameterPanel=h,t.ParameterSlider=p,t.QueueProgress=u,t.RetryProgress=g,t.StreamProgress=d,t.calculateETA=function(t,e,n){return 0===t?0:(e-t)/(t/(Date.now()-n))},t.clamp=i,t.createStyle=function(t){const e=document.createElement("style");return e.textContent=t,e},t.debounce=function(t,e){let n=null;return function(...s){n&&clearTimeout(n),n=setTimeout(()=>t.apply(this,s),e)}},t.easeOutCubic=function(t){return 1-Math.pow(1-t,3)},t.formatBytes=r,t.formatCurrency=o,t.formatTime=l,t.generateId=function(t="ai-control"){return`${t}-${Math.random().toString(36).slice(2,11)}`},t.isInViewport=function(t){const e=t.getBoundingClientRect();return e.top>=0&&e.left>=0&&e.bottom<=(globalThis.innerHeight||document.documentElement.clientHeight)&&e.right<=(globalThis.innerWidth||document.documentElement.clientWidth)},t.lerp=function(t,e,n){return t+(e-t)*n},t.parseColor=function(t){const e=document.createElement("div");e.style.color=t,document.body.appendChild(e);const n=getComputedStyle(e).color;e.remove();const s=/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/.exec(n);return(null==s?void 0:s[1])&&(null==s?void 0:s[2])&&(null==s?void 0:s[3])?{r:Number.parseInt(s[1],10),g:Number.parseInt(s[2],10),b:Number.parseInt(s[3],10)}:null},t.prefersReducedMotion=function(){return globalThis.matchMedia("(prefers-reduced-motion: reduce)").matches},t.throttle=a,Object.defineProperty(t,Symbol.toStringTag,{value:"Module"})});
2
+ //# sourceMappingURL=ai-progress-controls.umd.js.map