@qaiddev/thumbs-embed 1.0.16 → 1.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.
package/dist/qaid.js CHANGED
@@ -2,24 +2,24 @@ const E = `<svg xmlns="http://www.w3.org/2000/svg" class="qaid-icon" fill="none"
2
2
  <path stroke-linecap="round" stroke-linejoin="round" d="M14 10h4.764a2 2 0 011.789 2.894l-3.5 7A2 2 0 0115.263 21h-4.017c-.163 0-.326-.02-.485-.06L7 20m7-10V5a2 2 0 00-2-2h-.095c-.5 0-.905.405-.905.905 0 .714-.211 1.412-.608 2.006L7 11v9m7-10h-2M7 20H5a2 2 0 01-2-2v-6a2 2 0 012-2h2.5"/>
3
3
  </svg>`, T = `<svg xmlns="http://www.w3.org/2000/svg" class="qaid-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
4
4
  <path stroke-linecap="round" stroke-linejoin="round" d="M10 14H5.236a2 2 0 01-1.789-2.894l3.5-7A2 2 0 018.737 3h4.018a2 2 0 01.485.06l3.76.94m-7 10v5a2 2 0 002 2h.095c.5 0 .905-.405.905-.905 0-.714.211-1.412.608-2.006L17 13V4m-7 10h2m5-10h2a2 2 0 012 2v6a2 2 0 01-2 2h-2.5"/>
5
- </svg>`, it = `<svg xmlns="http://www.w3.org/2000/svg" class="qaid-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
5
+ </svg>`, dt = `<svg xmlns="http://www.w3.org/2000/svg" class="qaid-icon" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
6
6
  <path stroke-linecap="round" stroke-linejoin="round" d="M15.75 10.5l4.72-4.72a.75.75 0 011.28.53v11.38a.75.75 0 01-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25h-9A2.25 2.25 0 002.25 7.5v9a2.25 2.25 0 002.25 2.25z"/>
7
- </svg>`, ot = "button{cursor:pointer}.qaid-buttons{display:flex;gap:.5rem}.qaid-buttons.qaid-vertical{flex-direction:column}.qaid-buttons.qaid-auto-container{position:fixed;z-index:50}.qaid-buttons.qaid-auto-container.qaid-bottom-right{bottom:1rem;right:1rem}.qaid-buttons.qaid-auto-container.qaid-bottom-left{bottom:1rem;left:1rem}.qaid-buttons.qaid-auto-container.qaid-top-right{top:1rem;right:1rem}.qaid-buttons.qaid-auto-container.qaid-top-left{top:1rem;left:1rem}.qaid-buttons.qaid-incognito{opacity:0;transition:opacity .2s ease-in-out}.qaid-buttons.qaid-incognito:hover{opacity:1}.qaid-buttons.qaid-incognito.qaid-force-hidden{opacity:0}.qaid-dismiss-btn{width:20px;height:20px;padding:0;border:none;border-radius:50%;background:#0006;color:#fff;display:flex;align-items:center;justify-content:center;align-self:center;opacity:0;transition:opacity .15s,background .15s;cursor:pointer;pointer-events:auto;-webkit-appearance:none;appearance:none}.qaid-dismiss-btn:hover{background:#0009}.qaid-buttons:hover .qaid-dismiss-btn{opacity:1}button.qaid-btn-structural{display:inline-flex;align-items:center;justify-content:center;cursor:pointer;-webkit-appearance:none;appearance:none}.qaid-icon{width:24px;height:24px}.qaid-btn-structural:not(:has(svg)),.qaid-btn:not(:has(svg)){font-size:var(--qaid-icon-size, 24px);line-height:1}.qaid-emoji-icon{font-size:var(--qaid-icon-size, 24px);line-height:1}.qaid-buttons,.qaid-buttons *,.qaid-modal-container,.qaid-modal-container *{cursor:pointer!important}.qaid-tooltip-wrapper{position:relative}.qaid-tooltip-text{position:fixed;padding:.5rem .75rem;background:#1f2937;color:#fff;font-size:1rem;font-weight:600;border-radius:.5rem;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .15s;z-index:99999}.qaid-tooltip-text.qaid-tooltip-visible{opacity:1}.qaid-targeting-overlay{position:fixed;inset:0;z-index:40;pointer-events:none}.qaid-capture-layer{position:fixed;inset:0;pointer-events:none;z-index:9999}@keyframes qaid-slideDown{0%{transform:translateY(-100%)}to{transform:translateY(0)}}.qaid-vignette{position:fixed;inset:0;pointer-events:none;background:radial-gradient(ellipse at center,transparent 30%,rgba(0,0,0,.3) 70%,rgba(0,0,0,.6) 100%);z-index:41}.qaid-crosshair-h,.qaid-crosshair-v{position:fixed;pointer-events:none;z-index:42}.qaid-crosshair-h{left:0;right:0;height:1px;background:color-mix(in srgb,var(--qaid-negative) 60%,transparent)}.qaid-crosshair-v{top:0;bottom:0;width:1px;background:color-mix(in srgb,var(--qaid-negative) 60%,transparent)}.qaid-type-up .qaid-crosshair-h,.qaid-type-up .qaid-crosshair-v{background:color-mix(in srgb,var(--qaid-positive) 60%,transparent)}.qaid-highlight-box{position:fixed;top:0;left:0;pointer-events:none;z-index:41;display:none;border:3px solid color-mix(in srgb,var(--qaid-negative) 80%,transparent);border-radius:2px;background:color-mix(in srgb,var(--qaid-negative) 8%,transparent);will-change:transform,width,height}.qaid-type-up .qaid-highlight-box{border-color:color-mix(in srgb,var(--qaid-positive) 80%,transparent);background:color-mix(in srgb,var(--qaid-positive) 8%,transparent)}.qaid-scope{position:fixed;width:80px;height:80px;pointer-events:none;z-index:43;transform:translate(-50%,-50%)}.qaid-scope-ring{position:absolute;inset:10px;border:2px solid color-mix(in srgb,var(--qaid-negative) 80%,transparent);border-radius:50%}.qaid-type-up .qaid-scope-ring{border-color:color-mix(in srgb,var(--qaid-positive) 80%,transparent)}.qaid-scope-ring-inner{position:absolute;inset:20px;border:1px solid color-mix(in srgb,var(--qaid-negative) 50%,transparent);border-radius:50%}.qaid-type-up .qaid-scope-ring-inner{border-color:color-mix(in srgb,var(--qaid-positive) 50%,transparent)}.qaid-scope-dot{position:absolute;top:50%;left:50%;width:4px;height:4px;background:var(--qaid-negative);border-radius:50%;transform:translate(-50%,-50%)}.qaid-type-up .qaid-scope-dot{background:var(--qaid-positive)}.qaid-selected-marker{position:fixed;border:3px solid var(--qaid-marker, #6366f1);border-radius:50%;pointer-events:none;z-index:44;animation:qaid-markerPulse 1.5s ease-in-out infinite}@keyframes qaid-markerPulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.7;transform:scale(1.05)}}.qaid-backdrop{position:fixed;inset:0;z-index:45;background:#0000004d}.qaid-modal-container{position:fixed;z-index:50;display:flex;flex-direction:column;align-items:flex-start;max-height:calc(100vh - 32px);font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px)}.qaid-modal-container.qaid-above{flex-direction:column-reverse}.qaid-modal-arrow{width:0;height:0;border-left:12px solid transparent;border-right:12px solid transparent;position:relative;align-self:flex-start}.qaid-modal-container.qaid-below .qaid-modal-arrow{border-bottom:12px solid light-dark(#ffffff,#1f2937)}.qaid-modal-container.qaid-above .qaid-modal-arrow{border-top:12px solid light-dark(#ffffff,#1f2937)}.qaid-modal-box{color-scheme:inherit;background:light-dark(#ffffff,#1f2937);border-radius:1rem;padding:1.5rem;box-shadow:0 25px 50px -12px light-dark(rgba(0,0,0,.25),rgba(0,0,0,.5));width:var(--qaid-modal-width, 400px);max-width:calc(100vw - 32px);max-height:calc(100vh - 60px);overflow-y:auto}.qaid-modal-header{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:1rem}button.qaid-type-toggle{border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s;flex-shrink:0;-webkit-appearance:none;appearance:none}button.qaid-type-toggle:hover{transform:scale(1.1)}button.qaid-type-toggle:not(.qaid-type-toggle-custom){width:2.5rem;height:2.5rem;border-radius:50%}button.qaid-type-toggle:not(.qaid-type-toggle-custom) svg{width:1.25rem;height:1.25rem}button.qaid-type-toggle.qaid-type-up{background:var(--qaid-positive);color:#fff}button.qaid-type-toggle.qaid-type-down{background:var(--qaid-negative);color:#fff}.qaid-modal-header-text{flex:1;min-width:0}.qaid-modal-title{font-size:1.125rem;font-weight:700;margin:0 0 .25rem;color:light-dark(#1f2937,#f9fafb)}.qaid-modal-subtitle{color:light-dark(#6b7280,#9ca3af);margin:0;font-size:.875rem}.qaid-textarea{width:100%;height:6rem;padding:.75rem;border:1px solid light-dark(#d1d5db,#374151);border-radius:.5rem;font-family:inherit;font-size:1rem;resize:vertical;margin-bottom:1rem;box-sizing:border-box;background:light-dark(#ffffff,#111827);color:light-dark(#1f2937,#f9fafb)}.qaid-textarea:focus{outline:none;border-color:var(--qaid-marker);box-shadow:0 0 0 3px color-mix(in srgb,var(--qaid-marker) 20%,transparent)}.qaid-btn-row{display:flex;gap:.5rem;justify-content:flex-end}button.qaid-btn-submit{padding:.5rem 1rem;background:var(--qaid-marker);color:var(--qaid-marker-text, white);border:none;border-radius:.5rem;font-size:.875rem;font-weight:500;cursor:pointer;transition:background-color .2s,filter .2s;-webkit-appearance:none;appearance:none}button.qaid-btn-submit:hover{filter:brightness(.85)}button.qaid-btn-submit:focus{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--qaid-marker) 30%,transparent)}.qaid-bottom-sheet{position:fixed;bottom:0;left:0;right:0;z-index:50;animation:qaid-slideUpSheet .3s ease-out;font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px)}.qaid-bottom-sheet-content{background:light-dark(#ffffff,#1f2937);border-radius:1rem 1rem 0 0;padding:1.5rem;padding-bottom:max(1.5rem,env(safe-area-inset-bottom))}.qaid-bottom-sheet-handle{width:36px;height:4px;background:light-dark(rgba(0,0,0,.2),rgba(255,255,255,.2));border-radius:2px;margin:0 auto 1rem}@keyframes qaid-slideUpSheet{0%{transform:translateY(100%)}to{transform:translateY(0)}}button.qaid-btn-record:hover{background:#dc2626;color:#fff}.qaid-recording-indicator{position:fixed;top:12px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:.5rem;padding:.5rem 1rem;background:light-dark(#1f2937,#374151);color:#fff;border-radius:9999px;font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:.875rem;font-weight:500;box-shadow:0 4px 12px #0000004d;z-index:99999;animation:qaid-slideDown .2s ease-out}.qaid-recording-dot{width:10px;height:10px;background:#dc2626;border-radius:50%;animation:qaid-dotPulse 1.5s ease-in-out infinite}@keyframes qaid-dotPulse{0%,to{opacity:1}50%{opacity:.3}}.qaid-recording-time{font-variant-numeric:tabular-nums;min-width:2.5rem;text-align:center}button.qaid-recording-stop{padding:.25rem .75rem;background:#dc2626;color:#fff;border:none;border-radius:9999px;font-size:.75rem;font-weight:600;cursor:pointer;transition:background-color .2s;-webkit-appearance:none;appearance:none}button.qaid-recording-stop:hover{background:#b91c1c}.qaid-video-preview{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:#0009;z-index:99998;animation:qaid-fadeIn .2s ease-out}@keyframes qaid-fadeIn{0%{opacity:0}to{opacity:1}}.qaid-video-preview-box{color-scheme:inherit;background:light-dark(#ffffff,#1f2937);border-radius:1rem;padding:1.5rem;box-shadow:0 25px 50px -12px #00000080;width:560px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);overflow-y:auto;font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px)}.qaid-video-preview-box h3{font-size:1.125rem;font-weight:700;margin:0 0 1rem;color:light-dark(#1f2937,#f9fafb)}.qaid-video-preview-box video{width:100%;border-radius:.5rem;background:#000;margin-bottom:1rem}.qaid-video-preview-box textarea{width:100%;height:4rem;padding:.75rem;border:1px solid light-dark(#d1d5db,#374151);border-radius:.5rem;font-family:inherit;font-size:.875rem;resize:vertical;margin-bottom:1rem;box-sizing:border-box;background:light-dark(#ffffff,#111827);color:light-dark(#1f2937,#f9fafb)}.qaid-video-preview-box textarea:focus{outline:none;border-color:var(--qaid-marker);box-shadow:0 0 0 3px color-mix(in srgb,var(--qaid-marker) 20%,transparent)}.qaid-video-preview-actions{display:flex;gap:.5rem;justify-content:flex-end}button.qaid-video-btn{padding:.5rem 1rem;border:none;border-radius:.5rem;font-size:.875rem;font-weight:500;cursor:pointer;transition:background-color .2s,filter .2s;-webkit-appearance:none;appearance:none}button.qaid-video-btn-cancel{background:light-dark(#f3f4f6,#374151);color:light-dark(#374151,#d1d5db)}button.qaid-video-btn-cancel:hover{background:light-dark(#e5e7eb,#4b5563)}button.qaid-video-btn-rerecord{background:light-dark(#fef3c7,#78350f);color:light-dark(#92400e,#fde68a)}button.qaid-video-btn-rerecord:hover{filter:brightness(.9)}button.qaid-video-btn-send{background:var(--qaid-marker);color:var(--qaid-marker-text, white)}button.qaid-video-btn-send:hover{filter:brightness(.85)}button.qaid-video-btn-send:disabled{opacity:.5;cursor:not-allowed}.qaid-video-sending{display:flex;align-items:center;gap:.5rem;font-size:.875rem;color:light-dark(#6b7280,#9ca3af)}", nt = "body.qaid-targeting,body.qaid-targeting *{cursor:none!important}";
8
- let w = 0;
9
- const st = "button.qaid-btn{width:var(--qaid-btn-size);height:var(--qaid-btn-size);border-radius:50%;border:none;background:#f3f4f6;color:#374151;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);transition:background-color .2s,color .2s,transform .2s;-webkit-appearance:none;appearance:none;--qaid-hover-up-bg:var(--qaid-positive);--qaid-hover-up-color:#fff;--qaid-hover-down-bg:var(--qaid-negative);--qaid-hover-down-color:#fff}button.qaid-btn:hover{transform:scale(1.05)}button.qaid-btn-up:hover{background:var(--qaid-hover-up-bg);color:var(--qaid-hover-up-color)}button.qaid-btn-down:hover{background:var(--qaid-hover-down-bg);color:var(--qaid-hover-down-color)}button.qaid-btn svg{width:var(--qaid-icon-size);height:var(--qaid-icon-size)}", at = {
7
+ </svg>`, ct = "button{cursor:pointer}.qaid-buttons{display:flex;gap:.5rem}.qaid-buttons.qaid-vertical{flex-direction:column}.qaid-buttons.qaid-auto-container{position:fixed;z-index:50}.qaid-buttons.qaid-auto-container.qaid-bottom-right{bottom:1rem;right:1rem}.qaid-buttons.qaid-auto-container.qaid-bottom-left{bottom:1rem;left:1rem}.qaid-buttons.qaid-auto-container.qaid-top-right{top:1rem;right:1rem}.qaid-buttons.qaid-auto-container.qaid-top-left{top:1rem;left:1rem}.qaid-buttons.qaid-incognito{opacity:0;transition:opacity .2s ease-in-out}.qaid-buttons.qaid-incognito:hover{opacity:1}.qaid-buttons.qaid-dismissed{display:none!important}.qaid-dismiss-btn{width:20px;height:20px;padding:0;border:none;border-radius:50%;background:#0006;color:#fff;display:flex;align-items:center;justify-content:center;align-self:center;opacity:0;transition:opacity .15s,background .15s;cursor:pointer;pointer-events:auto;-webkit-appearance:none;appearance:none}.qaid-dismiss-btn:hover{background:#0009}.qaid-buttons:hover .qaid-dismiss-btn{opacity:1}button.qaid-btn-structural{display:inline-flex;align-items:center;justify-content:center;cursor:pointer;-webkit-appearance:none;appearance:none}.qaid-icon{width:24px;height:24px}.qaid-btn-structural:not(:has(svg)),.qaid-btn:not(:has(svg)){font-size:var(--qaid-icon-size, 24px);line-height:1}.qaid-emoji-icon{font-size:var(--qaid-icon-size, 24px);line-height:1}.qaid-buttons,.qaid-buttons *,.qaid-modal-container,.qaid-modal-container *{cursor:pointer!important}.qaid-tooltip-wrapper{position:relative}.qaid-tooltip-text{position:fixed;padding:.5rem .75rem;background:#1f2937;color:#fff;font-size:1rem;font-weight:600;border-radius:.5rem;white-space:nowrap;opacity:0;pointer-events:none;transition:opacity .15s;z-index:99999}.qaid-tooltip-text.qaid-tooltip-visible{opacity:1}.qaid-targeting-overlay{position:fixed;inset:0;z-index:40;pointer-events:none}.qaid-capture-layer{position:fixed;inset:0;pointer-events:none;z-index:9999}@keyframes qaid-slideDown{0%{transform:translateY(-100%)}to{transform:translateY(0)}}.qaid-vignette{position:fixed;inset:0;pointer-events:none;background:radial-gradient(ellipse at center,transparent 30%,rgba(0,0,0,.3) 70%,rgba(0,0,0,.6) 100%);z-index:41}.qaid-crosshair-h,.qaid-crosshair-v{position:fixed;pointer-events:none;z-index:42}.qaid-crosshair-h{left:0;right:0;height:1px;background:color-mix(in srgb,var(--qaid-negative) 60%,transparent)}.qaid-crosshair-v{top:0;bottom:0;width:1px;background:color-mix(in srgb,var(--qaid-negative) 60%,transparent)}.qaid-type-up .qaid-crosshair-h,.qaid-type-up .qaid-crosshair-v{background:color-mix(in srgb,var(--qaid-positive) 60%,transparent)}.qaid-highlight-box{position:fixed;top:0;left:0;pointer-events:none;z-index:41;display:none;border:3px solid color-mix(in srgb,var(--qaid-negative) 80%,transparent);border-radius:2px;background:color-mix(in srgb,var(--qaid-negative) 8%,transparent);will-change:transform,width,height}.qaid-type-up .qaid-highlight-box{border-color:color-mix(in srgb,var(--qaid-positive) 80%,transparent);background:color-mix(in srgb,var(--qaid-positive) 8%,transparent)}.qaid-scope{position:fixed;width:80px;height:80px;pointer-events:none;z-index:43;transform:translate(-50%,-50%)}.qaid-scope-ring{position:absolute;inset:10px;border:2px solid color-mix(in srgb,var(--qaid-negative) 80%,transparent);border-radius:50%}.qaid-type-up .qaid-scope-ring{border-color:color-mix(in srgb,var(--qaid-positive) 80%,transparent)}.qaid-scope-ring-inner{position:absolute;inset:20px;border:1px solid color-mix(in srgb,var(--qaid-negative) 50%,transparent);border-radius:50%}.qaid-type-up .qaid-scope-ring-inner{border-color:color-mix(in srgb,var(--qaid-positive) 50%,transparent)}.qaid-scope-dot{position:absolute;top:50%;left:50%;width:4px;height:4px;background:var(--qaid-negative);border-radius:50%;transform:translate(-50%,-50%)}.qaid-type-up .qaid-scope-dot{background:var(--qaid-positive)}.qaid-selected-marker{position:fixed;border:3px solid var(--qaid-marker, #6366f1);border-radius:50%;pointer-events:none;z-index:44;animation:qaid-markerPulse 1.5s ease-in-out infinite}@keyframes qaid-markerPulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.7;transform:scale(1.05)}}.qaid-backdrop{position:fixed;inset:0;z-index:45;background:#0000004d}.qaid-modal-container{position:fixed;z-index:50;display:flex;flex-direction:column;align-items:flex-start;max-height:calc(100vh - 32px);font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px)}.qaid-modal-container.qaid-above{flex-direction:column-reverse}.qaid-modal-arrow{width:0;height:0;border-left:12px solid transparent;border-right:12px solid transparent;position:relative;align-self:flex-start}.qaid-modal-container.qaid-below .qaid-modal-arrow{border-bottom:12px solid light-dark(#ffffff,#1f2937)}.qaid-modal-container.qaid-above .qaid-modal-arrow{border-top:12px solid light-dark(#ffffff,#1f2937)}.qaid-modal-box{color-scheme:inherit;background:light-dark(#ffffff,#1f2937);border-radius:1rem;padding:1.5rem;box-shadow:0 25px 50px -12px light-dark(rgba(0,0,0,.25),rgba(0,0,0,.5));width:var(--qaid-modal-width, 400px);max-width:calc(100vw - 32px);max-height:calc(100vh - 60px);overflow-y:auto}.qaid-modal-header{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:1rem}button.qaid-type-toggle{border:none;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:all .2s;flex-shrink:0;-webkit-appearance:none;appearance:none}button.qaid-type-toggle:hover{transform:scale(1.1)}button.qaid-type-toggle:not(.qaid-type-toggle-custom){width:2.5rem;height:2.5rem;border-radius:50%}button.qaid-type-toggle:not(.qaid-type-toggle-custom) svg{width:1.25rem;height:1.25rem}button.qaid-type-toggle.qaid-type-up{background:var(--qaid-positive);color:#fff}button.qaid-type-toggle.qaid-type-down{background:var(--qaid-negative);color:#fff}.qaid-modal-header-text{flex:1;min-width:0}.qaid-modal-title{font-size:1.125rem;font-weight:700;margin:0 0 .25rem;color:light-dark(#1f2937,#f9fafb)}.qaid-modal-subtitle{color:light-dark(#6b7280,#9ca3af);margin:0;font-size:.875rem}.qaid-textarea{width:100%;height:6rem;padding:.75rem;border:1px solid light-dark(#d1d5db,#374151);border-radius:.5rem;font-family:inherit;font-size:1rem;resize:vertical;margin-bottom:1rem;box-sizing:border-box;background:light-dark(#ffffff,#111827);color:light-dark(#1f2937,#f9fafb)}.qaid-textarea:focus{outline:none;border-color:var(--qaid-marker);box-shadow:0 0 0 3px color-mix(in srgb,var(--qaid-marker) 20%,transparent)}.qaid-btn-row{display:flex;gap:.5rem;justify-content:flex-end}button.qaid-btn-submit{padding:.5rem 1rem;background:var(--qaid-marker);color:var(--qaid-marker-text, white);border:none;border-radius:.5rem;font-size:.875rem;font-weight:500;cursor:pointer;transition:background-color .2s,filter .2s;-webkit-appearance:none;appearance:none}button.qaid-btn-submit:hover{filter:brightness(.85)}button.qaid-btn-submit:focus{outline:none;box-shadow:0 0 0 3px color-mix(in srgb,var(--qaid-marker) 30%,transparent)}.qaid-bottom-sheet{position:fixed;bottom:0;left:0;right:0;z-index:50;animation:qaid-slideUpSheet .3s ease-out;font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px)}.qaid-bottom-sheet-content{background:light-dark(#ffffff,#1f2937);border-radius:1rem 1rem 0 0;padding:1.5rem;padding-bottom:max(1.5rem,env(safe-area-inset-bottom))}.qaid-bottom-sheet-handle{width:36px;height:4px;background:light-dark(rgba(0,0,0,.2),rgba(255,255,255,.2));border-radius:2px;margin:0 auto 1rem}@keyframes qaid-slideUpSheet{0%{transform:translateY(100%)}to{transform:translateY(0)}}button.qaid-btn-record:hover{background:#dc2626;color:#fff}.qaid-recording-indicator{position:fixed;top:12px;left:50%;transform:translate(-50%);display:flex;align-items:center;gap:.5rem;padding:.5rem 1rem;background:light-dark(#1f2937,#374151);color:#fff;border-radius:9999px;font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:.875rem;font-weight:500;box-shadow:0 4px 12px #0000004d;z-index:99999;animation:qaid-slideDown .2s ease-out}.qaid-recording-dot{width:10px;height:10px;background:#dc2626;border-radius:50%;animation:qaid-dotPulse 1.5s ease-in-out infinite}@keyframes qaid-dotPulse{0%,to{opacity:1}50%{opacity:.3}}.qaid-recording-time{font-variant-numeric:tabular-nums;min-width:2.5rem;text-align:center}button.qaid-recording-stop{padding:.25rem .75rem;background:#dc2626;color:#fff;border:none;border-radius:9999px;font-size:.75rem;font-weight:600;cursor:pointer;transition:background-color .2s;-webkit-appearance:none;appearance:none}button.qaid-recording-stop:hover{background:#b91c1c}.qaid-video-preview{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:#0009;z-index:99998;animation:qaid-fadeIn .2s ease-out}@keyframes qaid-fadeIn{0%{opacity:0}to{opacity:1}}.qaid-video-preview-box{color-scheme:inherit;background:light-dark(#ffffff,#1f2937);border-radius:1rem;padding:1.5rem;box-shadow:0 25px 50px -12px #00000080;width:560px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);overflow-y:auto;font-family:var(--qaid-font-family, system-ui, -apple-system, sans-serif);font-size:var(--qaid-font-size, 16px)}.qaid-video-preview-box h3{font-size:1.125rem;font-weight:700;margin:0 0 1rem;color:light-dark(#1f2937,#f9fafb)}.qaid-video-preview-box video{width:100%;border-radius:.5rem;background:#000;margin-bottom:1rem}.qaid-video-preview-box textarea{width:100%;height:4rem;padding:.75rem;border:1px solid light-dark(#d1d5db,#374151);border-radius:.5rem;font-family:inherit;font-size:.875rem;resize:vertical;margin-bottom:1rem;box-sizing:border-box;background:light-dark(#ffffff,#111827);color:light-dark(#1f2937,#f9fafb)}.qaid-video-preview-box textarea:focus{outline:none;border-color:var(--qaid-marker);box-shadow:0 0 0 3px color-mix(in srgb,var(--qaid-marker) 20%,transparent)}.qaid-video-preview-actions{display:flex;gap:.5rem;justify-content:flex-end}button.qaid-video-btn{padding:.5rem 1rem;border:none;border-radius:.5rem;font-size:.875rem;font-weight:500;cursor:pointer;transition:background-color .2s,filter .2s;-webkit-appearance:none;appearance:none}button.qaid-video-btn-cancel{background:light-dark(#f3f4f6,#374151);color:light-dark(#374151,#d1d5db)}button.qaid-video-btn-cancel:hover{background:light-dark(#e5e7eb,#4b5563)}button.qaid-video-btn-rerecord{background:light-dark(#fef3c7,#78350f);color:light-dark(#92400e,#fde68a)}button.qaid-video-btn-rerecord:hover{filter:brightness(.9)}button.qaid-video-btn-send{background:var(--qaid-marker);color:var(--qaid-marker-text, white)}button.qaid-video-btn-send:hover{filter:brightness(.85)}button.qaid-video-btn-send:disabled{opacity:.5;cursor:not-allowed}.qaid-video-sending{display:flex;align-items:center;gap:.5rem;font-size:.875rem;color:light-dark(#6b7280,#9ca3af)}button:focus-visible,textarea:focus-visible,a:focus-visible,[tabindex]:focus-visible,[role=button]:focus-visible{outline:2px solid var(--qaid-marker, #6366f1);outline-offset:2px}.qaid-textarea:focus-visible,button.qaid-btn-submit:focus-visible,.qaid-video-preview-box textarea:focus-visible{outline:2px solid var(--qaid-marker, #6366f1);outline-offset:2px}.qaid-buttons.qaid-incognito:focus-within{opacity:1}.qaid-buttons:focus-within .qaid-dismiss-btn,.qaid-dismiss-btn:focus-visible{opacity:1}.qaid-dismiss-btn{min-width:24px;min-height:24px}button.qaid-recording-stop{min-height:24px}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation:none!important;transition:none!important;scroll-behavior:auto!important}}@media(forced-colors:active){button:focus-visible,textarea:focus-visible,a:focus-visible,[tabindex]:focus-visible,[role=button]:focus-visible,.qaid-textarea:focus,button.qaid-btn-submit:focus,.qaid-video-preview-box textarea:focus{outline:2px solid CanvasText;outline-offset:2px}.qaid-selected-marker,.qaid-highlight-box{border-color:Highlight}}", lt = "body.qaid-targeting,body.qaid-targeting *{cursor:none!important}";
8
+ let x = 0;
9
+ const ht = "button.qaid-btn{width:var(--qaid-btn-size);height:var(--qaid-btn-size);border-radius:50%;border:none;background:#f3f4f6;color:#374151;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -1px rgba(0,0,0,.06);transition:background-color .2s,color .2s,transform .2s;-webkit-appearance:none;appearance:none;--qaid-hover-up-bg:var(--qaid-positive);--qaid-hover-up-color:#fff;--qaid-hover-down-bg:var(--qaid-negative);--qaid-hover-down-color:#fff}button.qaid-btn:hover{transform:scale(1.05)}button.qaid-btn-up:hover{background:var(--qaid-hover-up-bg);color:var(--qaid-hover-up-color)}button.qaid-btn-down:hover{background:var(--qaid-hover-down-bg);color:var(--qaid-hover-down-color)}button.qaid-btn svg{width:var(--qaid-icon-size);height:var(--qaid-icon-size)}", ut = {
10
10
  small: 36,
11
11
  medium: 48,
12
12
  large: 64
13
- }, rt = {
13
+ }, pt = {
14
14
  small: 18,
15
15
  medium: 24,
16
16
  large: 32
17
17
  };
18
- function dt(e, t, i) {
18
+ function mt(e, t, i) {
19
19
  const [o, n, s] = [e, t, i].map((a) => (a = a / 255, a <= 0.03928 ? a / 12.92 : Math.pow((a + 0.055) / 1.055, 2.4)));
20
20
  return 0.2126 * o + 0.7152 * n + 0.0722 * s;
21
21
  }
22
- function ct(e) {
22
+ function ft(e) {
23
23
  if (e.startsWith("#")) {
24
24
  const i = e.slice(1), o = i.length === 3 ? i.split("").map((s) => s + s).join("") : i, n = parseInt(o, 16);
25
25
  return {
@@ -35,11 +35,11 @@ function ct(e) {
35
35
  b: parseInt(t[3])
36
36
  } : null;
37
37
  }
38
- function lt(e) {
39
- const t = ct(e);
40
- return t && dt(t.r, t.g, t.b) > 0.4 ? "black" : "white";
38
+ function bt(e) {
39
+ const t = ft(e);
40
+ return t && mt(t.r, t.g, t.b) > 0.4 ? "black" : "white";
41
41
  }
42
- function ht(e = {}) {
42
+ function gt(e = {}) {
43
43
  const {
44
44
  positiveColor: t = "rgb(0, 200, 83)",
45
45
  negativeColor: i = "rgb(255, 0, 0)",
@@ -49,12 +49,12 @@ function ht(e = {}) {
49
49
  backdropOpacity: a = 0.3,
50
50
  fontFamily: c = "system-ui, -apple-system, sans-serif",
51
51
  fontSize: l = 16
52
- } = e, r = at[n], d = rt[n], h = lt(o);
52
+ } = e, r = ut[n], d = pt[n], p = bt(o);
53
53
  return {
54
54
  "--qaid-positive": t,
55
55
  "--qaid-negative": i,
56
56
  "--qaid-marker": o,
57
- "--qaid-marker-text": h,
57
+ "--qaid-marker-text": p,
58
58
  "--qaid-btn-size": `${r}px`,
59
59
  "--qaid-icon-size": `${d}px`,
60
60
  "--qaid-modal-width": `${s}px`,
@@ -63,26 +63,26 @@ function ht(e = {}) {
63
63
  "--qaid-font-size": `${l}px`
64
64
  };
65
65
  }
66
- function ut(e, t) {
66
+ function vt(e, t) {
67
67
  for (const [i, o] of Object.entries(t))
68
68
  e.style.setProperty(i, o);
69
69
  }
70
- function z() {
71
- return ot + st;
70
+ function P() {
71
+ return ct + ht;
72
72
  }
73
- function pt() {
74
- if (w++, w > 1) return;
73
+ function yt() {
74
+ if (x++, x > 1) return;
75
75
  const e = document.createElement("style");
76
- e.id = "qaid-styles", e.textContent = nt, document.head.appendChild(e);
76
+ e.id = "qaid-styles", e.textContent = lt, document.head.appendChild(e);
77
77
  }
78
- function mt() {
79
- w <= 0 || (w--, w === 0 && document.getElementById("qaid-styles").remove());
78
+ function wt() {
79
+ x <= 0 || (x--, x === 0 && document.getElementById("qaid-styles").remove());
80
80
  }
81
- const ft = ["data-comp", "data-qa", "data-testid", "data-id"];
82
- function U(e, t = document.body) {
81
+ const j = ["data-comp", "data-qa", "data-testid", "data-id"];
82
+ function Y(e, t = document.body) {
83
83
  let i = e;
84
84
  for (; i && i !== t; ) {
85
- for (const o of ft) {
85
+ for (const o of j) {
86
86
  const n = i.getAttribute(o);
87
87
  if (n)
88
88
  return `${o}="${n}"`;
@@ -91,44 +91,284 @@ function U(e, t = document.body) {
91
91
  }
92
92
  return null;
93
93
  }
94
- function gt(e, t = 100) {
94
+ function xt(e, t = 100) {
95
95
  const i = e.textContent?.trim().slice(0, t) || "";
96
96
  return i.length === t ? i + "..." : i;
97
97
  }
98
- function bt(e) {
98
+ function qt(e) {
99
99
  let t = 1, i = e.previousElementSibling;
100
100
  for (; i; )
101
101
  t++, i = i.previousElementSibling;
102
102
  return t;
103
103
  }
104
- function vt(e) {
104
+ function kt(e) {
105
105
  const t = [];
106
106
  let i = e;
107
107
  for (; i && i !== document.body && i !== document.documentElement; ) {
108
- const o = i.tagName.toLowerCase(), n = bt(i);
108
+ const o = i.tagName.toLowerCase(), n = qt(i);
109
109
  t.unshift(`${o}:nth-child(${n})`), i = i.parentElement;
110
110
  }
111
111
  return t.length > 0 ? `body > ${t.join(" > ")}` : "body";
112
112
  }
113
- function yt(e) {
113
+ function Ct(e) {
114
114
  return e.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1");
115
115
  }
116
- function wt(e) {
117
- const t = U(e);
118
- return t ? `[${t}]` : e.id ? `#${yt(e.id)}` : vt(e);
116
+ function St(e) {
117
+ const t = Y(e);
118
+ return t ? `[${t}]` : e.id ? `#${Ct(e.id)}` : kt(e);
119
+ }
120
+ function L(e) {
121
+ const t = xt(e), i = Y(e);
122
+ return { selector: St(e), text: t, dataAttr: i };
123
+ }
124
+ const Et = [
125
+ "a[href]",
126
+ "button",
127
+ "input:not([type=hidden])",
128
+ "select",
129
+ "textarea",
130
+ "summary",
131
+ "[tabindex]",
132
+ "[role]",
133
+ "img",
134
+ "h1",
135
+ "h2",
136
+ "h3",
137
+ "h4",
138
+ "h5",
139
+ "h6",
140
+ "p",
141
+ "li",
142
+ "label",
143
+ ...j.map((e) => `[${e}]`)
144
+ ].join(","), Tt = /^(?:A|BUTTON|INPUT|SELECT|TEXTAREA|SUMMARY)$/;
145
+ function Lt(e) {
146
+ if (e.hasAttribute("hidden") || e.getAttribute("aria-hidden") === "true") return !1;
147
+ const t = e.ownerDocument?.defaultView;
148
+ if (t && typeof t.getComputedStyle == "function") {
149
+ const i = t.getComputedStyle(e);
150
+ if (i.display === "none" || i.visibility === "hidden") return !1;
151
+ }
152
+ return !0;
153
+ }
154
+ function It(e = {}) {
155
+ const t = e.root ?? document.body, i = e.selector ?? Et, o = e.isExcluded ?? (() => !1), n = e.isVisible ?? Lt;
156
+ return Array.from(t.querySelectorAll(i)).filter(
157
+ (s) => !o(s) && n(s)
158
+ );
159
+ }
160
+ function Dt(e) {
161
+ const t = e.candidates ?? It({
162
+ root: e.root,
163
+ selector: e.selector,
164
+ isExcluded: e.isExcluded,
165
+ isVisible: e.isVisible
166
+ }), i = e.moveFocus ?? !0, o = e.eventTarget ?? document, n = /* @__PURE__ */ new Set();
167
+ let s = -1, a = !1;
168
+ const c = e.initial !== void 0 ? e.initial : typeof document < "u" ? document.activeElement : null;
169
+ if (c) {
170
+ const h = t.indexOf(c);
171
+ h >= 0 && (s = h);
172
+ }
173
+ s < 0 && t.length > 0 && (s = 0);
174
+ function l(h) {
175
+ if (!i) return;
176
+ const y = h;
177
+ if (typeof y.focus == "function") {
178
+ h.getAttribute("tabindex") === null && !Tt.test(h.tagName) && (h.setAttribute("tabindex", "-1"), n.add(h));
179
+ try {
180
+ y.focus();
181
+ } catch {
182
+ }
183
+ }
184
+ }
185
+ function r() {
186
+ const h = t[s];
187
+ h && (l(h), e.onHighlight?.(h, s));
188
+ }
189
+ function d(h) {
190
+ if (a || t.length === 0) return;
191
+ const y = t.length;
192
+ s = (h % y + y) % y, r();
193
+ }
194
+ function p() {
195
+ d(s + 1);
196
+ }
197
+ function u() {
198
+ d(s - 1);
199
+ }
200
+ function m() {
201
+ return t[s] ?? null;
202
+ }
203
+ function g() {
204
+ a || (a = !0, o.removeEventListener("keydown", v, !0), n.forEach((h) => h.removeAttribute("tabindex")), n.clear());
205
+ }
206
+ function b() {
207
+ if (a) return;
208
+ const h = m();
209
+ g(), h && e.onSelect(h);
210
+ }
211
+ function f() {
212
+ a || (g(), e.onCancel?.());
213
+ }
214
+ function v(h) {
215
+ if (!a)
216
+ switch (h.key) {
217
+ case "Tab":
218
+ h.preventDefault(), h.stopPropagation(), h.shiftKey ? u() : p();
219
+ break;
220
+ case "ArrowDown":
221
+ case "ArrowRight":
222
+ h.preventDefault(), h.stopPropagation(), p();
223
+ break;
224
+ case "ArrowUp":
225
+ case "ArrowLeft":
226
+ h.preventDefault(), h.stopPropagation(), u();
227
+ break;
228
+ case "Enter":
229
+ case " ":
230
+ case "Spacebar":
231
+ h.preventDefault(), h.stopPropagation(), b();
232
+ break;
233
+ case "Escape":
234
+ case "Esc":
235
+ h.preventDefault(), h.stopPropagation(), f();
236
+ break;
237
+ }
238
+ }
239
+ return o.addEventListener("keydown", v, !0), s >= 0 && r(), {
240
+ candidates: t,
241
+ getIndex: () => s,
242
+ getCurrent: m,
243
+ next: p,
244
+ prev: u,
245
+ moveTo: d,
246
+ select: b,
247
+ cancel: f,
248
+ handleKey: v,
249
+ stop: g
250
+ };
251
+ }
252
+ const O = "data-qaid-a11y-live", At = "position:absolute;width:1px;height:1px;margin:-1px;padding:0;border:0;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;", Mt = [
253
+ "a[href]",
254
+ "button",
255
+ "input",
256
+ "textarea",
257
+ "select",
258
+ "[tabindex]"
259
+ ].join(",");
260
+ function Rt(e) {
261
+ return e.ownerDocument || document;
262
+ }
263
+ function Ht(e, t) {
264
+ const i = t ? "assertive" : "polite", o = e.querySelector(
265
+ `[${O}="${i}"]`
266
+ );
267
+ if (o) return o;
268
+ const s = Rt(e).createElement("div");
269
+ return s.setAttribute(O, i), s.setAttribute("role", t ? "alert" : "status"), s.setAttribute("aria-live", t ? "assertive" : "polite"), s.setAttribute("aria-atomic", "true"), s.style.cssText = At, e.appendChild(s), s;
270
+ }
271
+ function Bt(e, t, i = {}) {
272
+ const o = Ht(e, !!i.assertive);
273
+ o.textContent = "", o.textContent = t;
274
+ }
275
+ function zt(e) {
276
+ return e.hasAttribute("disabled") ? !0 : e.disabled === !0;
277
+ }
278
+ function Pt(e) {
279
+ let t = e;
280
+ for (; t; ) {
281
+ if (t.hasAttribute("hidden")) return !0;
282
+ const i = t.style;
283
+ if (i && (i.display === "none" || i.visibility === "hidden" || i.visibility === "collapse"))
284
+ return !0;
285
+ t = t.parentElement;
286
+ }
287
+ return !1;
288
+ }
289
+ function $(e) {
290
+ return Array.from(
291
+ e.querySelectorAll(Mt)
292
+ ).filter((i) => !(i.getAttribute("tabindex") === "-1" || i instanceof HTMLInputElement && i.type === "hidden" || i instanceof HTMLAnchorElement && !i.getAttribute("href") || zt(i) || Pt(i)));
293
+ }
294
+ function G(e) {
295
+ let t = e.activeElement;
296
+ for (; t && t.shadowRoot && t.shadowRoot.activeElement; )
297
+ t = t.shadowRoot.activeElement;
298
+ return t instanceof HTMLElement ? t : null;
299
+ }
300
+ function Ot(e) {
301
+ const t = e.ownerDocument || document;
302
+ let i = !1;
303
+ const o = (s) => {
304
+ if (s.key !== "Tab") return;
305
+ const a = $(e);
306
+ if (a.length === 0) {
307
+ s.preventDefault(), e.focus();
308
+ return;
309
+ }
310
+ const c = a[0], l = a[a.length - 1], r = G(t), d = r ? a.indexOf(r) !== -1 : !1;
311
+ s.shiftKey ? (!d || r === c) && (s.preventDefault(), l.focus()) : (!d || r === l) && (s.preventDefault(), c.focus());
312
+ };
313
+ e.addEventListener("keydown", o);
314
+ const n = $(e);
315
+ return n.length > 0 ? n[0].focus() : (e.hasAttribute("tabindex") || (e.setAttribute("tabindex", "-1"), i = !0), e.focus()), {
316
+ release() {
317
+ e.removeEventListener("keydown", o), i && (e.removeAttribute("tabindex"), i = !1);
318
+ }
319
+ };
119
320
  }
120
- function xt(e) {
121
- const t = gt(e), i = U(e);
122
- return { selector: wt(e), text: t, dataAttr: i };
321
+ function $t() {
322
+ return G(document);
123
323
  }
124
- const X = {
324
+ function Nt(e) {
325
+ if (!(!e || typeof e.focus != "function"))
326
+ try {
327
+ e.focus();
328
+ } catch {
329
+ }
330
+ }
331
+ function Vt(e, t = {}) {
332
+ e.setAttribute("role", "dialog"), e.setAttribute("aria-modal", "true"), t.labelledbyId && e.setAttribute("aria-labelledby", t.labelledbyId), t.describedbyId && e.setAttribute("aria-describedby", t.describedbyId), t.label && e.setAttribute("aria-label", t.label);
333
+ }
334
+ function Ft(e, t) {
335
+ let i = e;
336
+ for (; i && i !== t; ) {
337
+ const o = i.parentNode;
338
+ if (o === t) return i;
339
+ if (o && o.host) {
340
+ i = o.host;
341
+ continue;
342
+ }
343
+ if (!o) return null;
344
+ i = o;
345
+ }
346
+ return null;
347
+ }
348
+ function _t(e) {
349
+ const i = (e.ownerDocument || document).body;
350
+ if (!i) return () => {
351
+ };
352
+ const o = Ft(e, i), n = [];
353
+ return Array.from(i.children).forEach((s) => {
354
+ if (!(s instanceof HTMLElement) || o && s === o) return;
355
+ const a = s.inert === !0, c = s.getAttribute("aria-hidden");
356
+ a && c === "true" || (s.inert = !0, s.setAttribute("aria-hidden", "true"), n.push({ el: s, prevInert: a, prevAriaHidden: c }));
357
+ }), function() {
358
+ for (; n.length; ) {
359
+ const a = n.pop();
360
+ a && (a.el.inert = a.prevInert, a.prevAriaHidden === null ? a.el.removeAttribute("aria-hidden") : a.el.setAttribute("aria-hidden", a.prevAriaHidden));
361
+ }
362
+ };
363
+ }
364
+ const J = {
125
365
  width: 400,
126
366
  height: 280,
127
367
  arrowHeight: 12,
128
368
  gap: 8,
129
369
  viewportPadding: 16
130
370
  };
131
- function qt(e, t, i, o, n) {
371
+ function Ut(e, t, i, o, n) {
132
372
  const s = e.y, a = t - (e.y + e.height);
133
373
  if (a >= i + o)
134
374
  return {
@@ -147,22 +387,22 @@ function qt(e, t, i, o, n) {
147
387
  t - i - n
148
388
  ) : l = Math.max(n, e.y - i - o), { top: l, position: c };
149
389
  }
150
- function kt(e, t, i, o) {
390
+ function Kt(e, t, i, o) {
151
391
  let s = e.x + e.width / 2 - i / 2;
152
392
  return s = Math.max(o, Math.min(s, t - i - o)), s;
153
393
  }
154
- function Ct(e, t, i, o = 24, n = 24) {
394
+ function Xt(e, t, i, o = 24, n = 24) {
155
395
  const a = e.clickX - t - n / 2;
156
396
  return Math.max(o, Math.min(a, i - o - n / 2));
157
397
  }
158
- function St(e, t, i, o = X) {
159
- const n = o.height + o.arrowHeight, s = qt(
398
+ function Wt(e, t, i, o = J) {
399
+ const n = o.height + o.arrowHeight, s = Ut(
160
400
  e,
161
401
  i,
162
402
  n,
163
403
  o.gap,
164
404
  o.viewportPadding
165
- ), a = kt(
405
+ ), a = Kt(
166
406
  e,
167
407
  t,
168
408
  o.width,
@@ -174,15 +414,15 @@ function St(e, t, i, o = X) {
174
414
  position: s.position
175
415
  };
176
416
  }
177
- function Et(e, t, i, o = {}) {
417
+ function jt(e, t, i, o = {}) {
178
418
  const n = o.gap ?? 8;
179
419
  let s = e.bottom + n;
180
420
  s + t.height > i.height - n && (s = e.top - t.height - n);
181
421
  let a = e.left;
182
422
  return a < n ? a = n : a + t.width > i.width - n && (a = i.width - t.width - n), s < n ? s = n : s + t.height > i.height - n && (s = i.height - t.height - n), { top: s, left: a };
183
423
  }
184
- function Tt(e, t, i, o = X) {
185
- const n = St(e, t, i, o), s = Ct(
424
+ function Yt(e, t, i, o = J) {
425
+ const n = Wt(e, t, i, o), s = Xt(
186
426
  e,
187
427
  n.left,
188
428
  o.width
@@ -192,15 +432,15 @@ function Tt(e, t, i, o = X) {
192
432
  arrow: { left: s }
193
433
  };
194
434
  }
195
- const It = 20;
196
- function Lt(e) {
435
+ const Gt = 20;
436
+ function Jt(e) {
197
437
  const t = [], i = console.error, o = console.warn, n = console.log, s = (a, c) => {
198
438
  const l = {
199
439
  message: c.map((r) => String(r)).join(" "),
200
440
  timestamp: Date.now(),
201
441
  level: a
202
442
  };
203
- t.length >= It && t.shift(), t.push(l), e && e(l);
443
+ t.length >= Gt && t.shift(), t.push(l), e && e(l);
204
444
  };
205
445
  return console.error = function(...a) {
206
446
  s("error", a), i.apply(console, a);
@@ -215,15 +455,15 @@ function Lt(e) {
215
455
  }
216
456
  };
217
457
  }
218
- const Dt = 20, P = 4096;
458
+ const Zt = 20, N = 4096;
219
459
  function q(e) {
220
460
  const t = typeof e == "string" ? e : JSON.stringify(e);
221
- return t.length > P ? t.slice(0, P) + "…[truncated]" : t;
461
+ return t.length > N ? t.slice(0, N) + "…[truncated]" : t;
222
462
  }
223
- function O(e, t) {
224
- e.length >= Dt && e.shift(), e.push(t);
463
+ function V(e, t) {
464
+ e.length >= Zt && e.shift(), e.push(t);
225
465
  }
226
- async function Ht(e) {
466
+ async function Qt(e) {
227
467
  try {
228
468
  const t = await e.clone().text();
229
469
  return q(t);
@@ -231,7 +471,7 @@ async function Ht(e) {
231
471
  return;
232
472
  }
233
473
  }
234
- function Mt() {
474
+ function te() {
235
475
  const e = [], t = window.fetch;
236
476
  window.fetch = async function(n, s) {
237
477
  const a = typeof n == "string" ? n : n instanceof URL ? n.toString() : n.url, c = s?.method ?? (typeof n == "object" && "method" in n ? n.method : "GET");
@@ -239,8 +479,8 @@ function Mt() {
239
479
  s?.body && (l = q(s.body));
240
480
  const r = await t.apply(window, [n, s]);
241
481
  if (r.status >= 400) {
242
- const d = await Ht(r);
243
- O(e, {
482
+ const d = await Qt(r);
483
+ V(e, {
244
484
  url: a,
245
485
  method: c.toUpperCase(),
246
486
  status: r.status,
@@ -258,7 +498,7 @@ function Mt() {
258
498
  }, XMLHttpRequest.prototype.send = function(n) {
259
499
  const s = this, a = n ? q(n) : void 0;
260
500
  return s.addEventListener("load", function() {
261
- s.status >= 400 && O(e, {
501
+ s.status >= 400 && V(e, {
262
502
  url: s._qaid_url,
263
503
  method: s._qaid_method.toUpperCase(),
264
504
  status: s.status,
@@ -275,10 +515,10 @@ function Mt() {
275
515
  }
276
516
  };
277
517
  }
278
- function Bt() {
518
+ function ee() {
279
519
  return typeof navigator < "u" && !!navigator.mediaDevices && typeof navigator.mediaDevices.getDisplayMedia == "function" && typeof MediaRecorder < "u";
280
520
  }
281
- function Rt() {
521
+ function ie() {
282
522
  if (typeof MediaRecorder > "u") return "";
283
523
  const e = [
284
524
  "video/webm;codecs=vp9",
@@ -291,20 +531,20 @@ function Rt() {
291
531
  return t;
292
532
  return "";
293
533
  }
294
- function zt(e = {}) {
534
+ function oe(e = {}) {
295
535
  const t = e.maxDuration ?? 15, i = e.videoBitsPerSecond ?? 8e5;
296
- let o = null, n = null, s = [], a = null, c = null, l = null, r = 0, d = null, h = null, u = !1, p = null;
297
- function b() {
298
- l !== null && (clearInterval(l), l = null), p !== null && (clearTimeout(p), p = null), o && (o.getTracks().forEach((m) => m.stop()), o = null), n = null, s = [], a = null, c = null, d = null, h = null;
536
+ let o = null, n = null, s = [], a = null, c = null, l = null, r = 0, d = null, p = null, u = !1, m = null;
537
+ function g() {
538
+ l !== null && (clearInterval(l), l = null), m !== null && (clearTimeout(m), m = null), o && (o.getTracks().forEach((f) => f.stop()), o = null), n = null, s = [], a = null, c = null, d = null, p = null;
299
539
  }
300
- function f() {
540
+ function b() {
301
541
  u || (u = !0, n && n.state !== "inactive" && n.stop());
302
542
  }
303
543
  return {
304
544
  async start() {
305
545
  u = !1, s = [];
306
- const m = Rt();
307
- if (!m)
546
+ const f = ie();
547
+ if (!f)
308
548
  throw new Error("No supported video MIME type found");
309
549
  o = await navigator.mediaDevices.getDisplayMedia({
310
550
  video: {
@@ -316,53 +556,53 @@ function zt(e = {}) {
316
556
  });
317
557
  const v = o.getVideoTracks()[0];
318
558
  v && v.addEventListener("ended", () => {
319
- f();
559
+ b();
320
560
  }), n = new MediaRecorder(o, {
321
- mimeType: m,
561
+ mimeType: f,
322
562
  videoBitsPerSecond: i
323
- }), n.ondataavailable = (g) => {
324
- g.data.size > 0 && s.push(g.data);
563
+ }), n.ondataavailable = (h) => {
564
+ h.data.size > 0 && s.push(h.data);
325
565
  }, n.onstop = () => {
326
- const g = new Blob(s, { type: m });
327
- d && d(g), c && c(g), o && o.getTracks().forEach((x) => x.stop());
566
+ const h = new Blob(s, { type: f });
567
+ d && d(h), c && c(h), o && o.getTracks().forEach((y) => y.stop());
328
568
  }, n.onerror = () => {
329
- h && h(new Error("MediaRecorder error"));
569
+ p && p(new Error("MediaRecorder error"));
330
570
  }, n.start(1e3), r = Date.now(), l = setInterval(() => {
331
- const g = Math.floor((Date.now() - r) / 1e3);
332
- a && a(g);
333
- }, 1e3), p = setTimeout(() => {
334
- f();
571
+ const h = Math.floor((Date.now() - r) / 1e3);
572
+ a && a(h);
573
+ }, 1e3), m = setTimeout(() => {
574
+ b();
335
575
  }, t * 1e3);
336
576
  },
337
577
  stop() {
338
- return new Promise((m, v) => {
339
- d = m, h = v, f();
578
+ return new Promise((f, v) => {
579
+ d = f, p = v, b();
340
580
  });
341
581
  },
342
- onTick(m) {
343
- a = m;
582
+ onTick(f) {
583
+ a = f;
344
584
  },
345
- onStop(m) {
346
- c = m;
585
+ onStop(f) {
586
+ c = f;
347
587
  },
348
588
  destroy() {
349
- f(), b();
589
+ b(), g();
350
590
  }
351
591
  };
352
592
  }
353
- function Pt(e = 640) {
593
+ function ne(e = 640) {
354
594
  return typeof window < "u" && window.innerWidth < e;
355
595
  }
356
- function A(e, t, i) {
596
+ function F(e, t, i) {
357
597
  const o = i.map((s) => s.style.visibility);
358
598
  i.forEach((s) => s.style.visibility = "hidden");
359
599
  const n = document.elementFromPoint(e, t);
360
600
  return i.forEach((s, a) => s.style.visibility = o[a]), n;
361
601
  }
362
- function $(e) {
602
+ function I(e) {
363
603
  return e ? e.hasAttribute("data-qaid-embed") || e.hasAttribute("data-qaid-embed-overlay") ? !0 : !!e.closest("[data-qaid-embed], [data-qaid-embed-overlay]") : !1;
364
604
  }
365
- function Ot(e, t = 0) {
605
+ function _(e, t = 0) {
366
606
  const i = e.getBoundingClientRect();
367
607
  return {
368
608
  x: i.left - t,
@@ -371,7 +611,7 @@ function Ot(e, t = 0) {
371
611
  height: i.height + t * 2
372
612
  };
373
613
  }
374
- async function At(e = {}) {
614
+ async function se(e = {}) {
375
615
  const { quality: t = 1, maxWidth: i = 1280, maxHeight: o = 800 } = e;
376
616
  try {
377
617
  if (!navigator.mediaDevices?.getDisplayMedia)
@@ -382,58 +622,58 @@ async function At(e = {}) {
382
622
  displaySurface: "browser"
383
623
  }
384
624
  }), s = n.getVideoTracks()[0], a = s.getSettings(), c = document.createElement("video");
385
- c.srcObject = n, c.muted = !0, await new Promise((f) => {
625
+ c.srcObject = n, c.muted = !0, await new Promise((b) => {
386
626
  c.onloadedmetadata = () => {
387
- c.play(), f();
627
+ c.play(), b();
388
628
  };
389
- }), await new Promise((f) => {
390
- const m = () => {
391
- c.readyState >= 2 ? f() : requestAnimationFrame(m);
629
+ }), await new Promise((b) => {
630
+ const f = () => {
631
+ c.readyState >= 2 ? b() : requestAnimationFrame(f);
392
632
  };
393
- m();
394
- }), await new Promise((f) => setTimeout(f, 100));
395
- const l = a.width || c.videoWidth, r = a.height || c.videoHeight, d = Math.min(i / l, o / r, 1), h = Math.round(l * d), u = Math.round(r * d), p = document.createElement("canvas");
396
- p.width = h, p.height = u;
397
- const b = p.getContext("2d");
398
- return b ? (b.drawImage(c, 0, 0, h, u), s.stop(), p.toDataURL("image/webp", t)) : (s.stop(), null);
633
+ f();
634
+ }), await new Promise((b) => setTimeout(b, 100));
635
+ const l = a.width || c.videoWidth, r = a.height || c.videoHeight, d = Math.min(i / l, o / r, 1), p = Math.round(l * d), u = Math.round(r * d), m = document.createElement("canvas");
636
+ m.width = p, m.height = u;
637
+ const g = m.getContext("2d");
638
+ return g ? (g.drawImage(c, 0, 0, p, u), s.stop(), m.toDataURL("image/webp", t)) : (s.stop(), null);
399
639
  } catch (n) {
400
640
  return console.warn("Screenshot capture failed:", n), null;
401
641
  }
402
642
  }
403
- const N = "https://qaid.dev/lib/html2canvas.min.js", $t = 1e4, Nt = 50;
404
- let y = null;
405
- function Kt() {
643
+ const U = "https://qaid.dev/lib/html2canvas.min.js", ae = 1e4, re = 50;
644
+ let w = null;
645
+ function fe() {
406
646
  if (typeof document > "u" || typeof window > "u")
407
647
  return !1;
408
648
  const e = document.createElement("canvas");
409
649
  return typeof e.getContext == "function" && !!e.getContext("2d");
410
650
  }
411
- function Vt() {
412
- return window.html2canvas ? Promise.resolve(!0) : y || (y = new Promise((e) => {
651
+ function de() {
652
+ return window.html2canvas ? Promise.resolve(!0) : w || (w = new Promise((e) => {
413
653
  if (!document.querySelector(
414
- `script[src="${N}"]`
654
+ `script[src="${U}"]`
415
655
  )) {
416
656
  const n = document.createElement("script");
417
- n.src = N, n.async = !0, document.head.appendChild(n);
657
+ n.src = U, n.async = !0, document.head.appendChild(n);
418
658
  }
419
659
  const i = Date.now(), o = () => {
420
660
  if (window.html2canvas) {
421
661
  e(!0);
422
662
  return;
423
663
  }
424
- if (Date.now() - i > $t) {
425
- y = null, e(!1);
664
+ if (Date.now() - i > ae) {
665
+ w = null, e(!1);
426
666
  return;
427
667
  }
428
- setTimeout(o, Nt);
668
+ setTimeout(o, re);
429
669
  };
430
670
  o();
431
- }), y);
671
+ }), w);
432
672
  }
433
- async function _t(e = {}) {
673
+ async function ce(e = {}) {
434
674
  const { quality: t = 0.8, maxWidth: i = 1280, maxHeight: o = 800 } = e;
435
675
  try {
436
- if (!await Vt() || !window.html2canvas)
676
+ if (!await de() || !window.html2canvas)
437
677
  return console.warn("html2canvas failed to load"), null;
438
678
  const s = await window.html2canvas(document.body, {
439
679
  useCORS: !0,
@@ -448,42 +688,42 @@ async function _t(e = {}) {
448
688
  ignoreElements: (r) => r instanceof HTMLElement ? r.classList.contains("qaid-buttons") || r.classList.contains("qaid-targeting-overlay") || r.classList.contains("qaid-modal-container") || r.classList.contains("qaid-bottom-sheet") || r.classList.contains("qaid-backdrop") || r.classList.contains("qaid-selected-marker") || r.classList.contains("qaid-tooltip-text") || r.classList.contains("qaid-recording-indicator") || r.classList.contains("qaid-video-preview") || r.className?.toString().startsWith?.("qaid-") : !1
449
689
  }), a = s.width, c = s.height, l = Math.min(i / a, o / c, 1);
450
690
  if (l < 1) {
451
- const r = Math.round(a * l), d = Math.round(c * l), h = document.createElement("canvas");
452
- h.width = r, h.height = d;
453
- const u = h.getContext("2d");
454
- return u ? (u.drawImage(s, 0, 0, r, d), h.toDataURL("image/webp", t)) : null;
691
+ const r = Math.round(a * l), d = Math.round(c * l), p = document.createElement("canvas");
692
+ p.width = r, p.height = d;
693
+ const u = p.getContext("2d");
694
+ return u ? (u.drawImage(s, 0, 0, r, d), p.toDataURL("image/webp", t)) : null;
455
695
  }
456
696
  return s.toDataURL("image/webp", t);
457
697
  } catch (n) {
458
698
  return console.warn("DOM screenshot capture failed:", n), null;
459
699
  }
460
700
  }
461
- const V = "qaid_visitor_id", _ = "qaid_hide_feedback";
462
- function I(e) {
463
- return e ? `${_}_${e}` : _;
701
+ const K = "qaid_visitor_id", X = "qaid_hide_feedback";
702
+ function D(e) {
703
+ return e ? `${X}_${e}` : X;
464
704
  }
465
- function Ft(e) {
705
+ function le(e) {
466
706
  try {
467
- return localStorage.getItem(I(e)) === "1";
707
+ return localStorage.getItem(D(e)) === "1";
468
708
  } catch {
469
709
  return !1;
470
710
  }
471
711
  }
472
- function F(e, t = !0) {
712
+ function W(e, t = !0) {
473
713
  try {
474
- t ? localStorage.setItem(I(e), "1") : localStorage.removeItem(I(e));
714
+ t ? localStorage.setItem(D(e), "1") : localStorage.removeItem(D(e));
475
715
  } catch {
476
716
  }
477
717
  }
478
- function Ut() {
718
+ function he() {
479
719
  try {
480
- let e = localStorage.getItem(V);
481
- return e || (e = crypto.randomUUID(), localStorage.setItem(V, e)), e;
720
+ let e = localStorage.getItem(K);
721
+ return e || (e = crypto.randomUUID(), localStorage.setItem(K, e)), e;
482
722
  } catch {
483
723
  return crypto.randomUUID();
484
724
  }
485
725
  }
486
- class Xt {
726
+ class ue {
487
727
  config;
488
728
  state = "IDLE";
489
729
  feedbackData = {
@@ -536,6 +776,18 @@ class Xt {
536
776
  dismissBtn = null;
537
777
  // Per-instance CSS variables
538
778
  cssVars = {};
779
+ // Keyboard element-targeting
780
+ keyboardController = null;
781
+ activeThumbBtn = null;
782
+ // Tracks whether the pending activation came from the keyboard (Enter/Space)
783
+ // rather than a pointer, so targeting can avoid elementFromPoint(0,0).
784
+ keyboardActivation = !1;
785
+ // Accessibility: dialog focus management
786
+ dialogTrigger = null;
787
+ dialogTrap = null;
788
+ dialogRestoreInert = null;
789
+ // Unique id suffix for aria-labelledby/describedby references
790
+ uid = Math.random().toString(36).slice(2, 9);
539
791
  // Bound event handlers
540
792
  boundKeyDown;
541
793
  boundMouseMove;
@@ -573,7 +825,11 @@ class Xt {
573
825
  modalSubtitle: t.text?.modalSubtitle ?? "Would you like to add a message to help us understand your feedback better?",
574
826
  placeholder: t.text?.placeholder ?? "Optional: Tell us more about your experience...",
575
827
  submitButton: t.text?.submitButton ?? "Submit",
576
- skipButton: t.text?.skipButton ?? "Skip"
828
+ skipButton: t.text?.skipButton ?? "Skip",
829
+ positiveLabel: t.text?.positiveLabel ?? "Send positive feedback",
830
+ negativeLabel: t.text?.negativeLabel ?? "Send negative feedback",
831
+ recordLabel: t.text?.recordLabel ?? "Record a screen recording",
832
+ dismissLabel: t.text?.dismissLabel ?? "Hide feedback buttons"
577
833
  },
578
834
  modalWidth: t.modalWidth ?? 400,
579
835
  backdropOpacity: t.backdropOpacity ?? 0.3,
@@ -597,13 +853,37 @@ class Xt {
597
853
  maxDuration: t.videoOptions?.maxDuration ?? 15
598
854
  },
599
855
  recordIcon: t.recordIcon ?? ""
600
- }, this.boundKeyDown = this.handleKeyDown.bind(this), this.boundMouseMove = this.handleMouseMove.bind(this), this.boundClick = this.handleClick.bind(this), this.boundResize = this.handleResize.bind(this), this.visitorId = Ut(), this.init();
856
+ }, this.boundKeyDown = this.handleKeyDown.bind(this), this.boundMouseMove = this.handleMouseMove.bind(this), this.boundClick = this.handleClick.bind(this), this.boundResize = this.handleResize.bind(this), this.visitorId = he(), this.init();
601
857
  }
602
858
  applyVars(t) {
603
- ut(t, this.cssVars);
859
+ vt(t, this.cssVars);
860
+ }
861
+ /**
862
+ * Announce a message via the shared visually-hidden live regions.
863
+ * Prefer the overlay shadow root (which hosts every transient surface and
864
+ * is never inerted by its own dialogs) so announcements are not suppressed
865
+ * while a dialog aria-hides the main button host.
866
+ */
867
+ announceMsg(t, i = !1) {
868
+ const o = this.overlayShadowRoot ?? this.shadowRoot;
869
+ o && Bt(o, t, { assertive: i });
870
+ }
871
+ /**
872
+ * Turn a transient surface into an accessible modal dialog: save the
873
+ * invoking control, apply dialog semantics, trap focus, and inert the
874
+ * background. Paired with closeDialogA11y() on every close path.
875
+ */
876
+ openDialogA11y(t, i) {
877
+ this.dialogTrigger = $t(), Vt(t, i), this.dialogTrap = Ot(t), this.dialogRestoreInert = _t(t);
878
+ }
879
+ closeDialogA11y() {
880
+ this.dialogTrap?.release(), this.dialogTrap = null, this.dialogRestoreInert && (this.dialogRestoreInert(), this.dialogRestoreInert = null), Nt(this.dialogTrigger), this.dialogTrigger = null;
881
+ }
882
+ clearActiveThumb() {
883
+ this.activeThumbBtn && (this.activeThumbBtn.setAttribute("aria-pressed", "false"), this.activeThumbBtn = null);
604
884
  }
605
885
  init() {
606
- pt(), this.cssVars = ht({
886
+ yt(), this.cssVars = gt({
607
887
  positiveColor: this.config.colors.positive,
608
888
  negativeColor: this.config.colors.negative,
609
889
  markerColor: this.config.colors.marker,
@@ -612,7 +892,7 @@ class Xt {
612
892
  backdropOpacity: this.config.backdropOpacity,
613
893
  fontFamily: this.config.fontFamily,
614
894
  fontSize: this.config.fontSize
615
- }), !this.config.hideDismiss && Ft(this.config.apiKey) && (this._startDismissed = !0), this.checkMobile(), window.addEventListener("resize", this.boundResize), this.createEmbed(), this.consoleCapture = Lt((t) => {
895
+ }), !this.config.hideDismiss && le(this.config.apiKey) && (this._startDismissed = !0), this.checkMobile(), window.addEventListener("resize", this.boundResize), this.createEmbed(), this.consoleCapture = Jt((t) => {
616
896
  this.feedbackData.consoleErrors = this.consoleCapture?.errors ?? [];
617
897
  }), this.feedbackData.consoleErrors = this.consoleCapture.errors, this.observeDom();
618
898
  }
@@ -635,7 +915,7 @@ class Xt {
635
915
  }), this.domObserver.observe(document.body, { childList: !0 });
636
916
  }
637
917
  checkMobile() {
638
- this.isMobile = Pt();
918
+ this.isMobile = ne();
639
919
  }
640
920
  handleResize() {
641
921
  this.checkMobile();
@@ -645,7 +925,7 @@ class Xt {
645
925
  let t = null;
646
926
  this.config.container && (t = document.querySelector(this.config.container)), t ? (t.appendChild(this.shadowHost), this.isUserProvidedContainer = !0, this.config.hideDismiss = !0) : (this.shadowHost.style.position = "fixed", this.shadowHost.style.display = "block", this.shadowHost.style.inset = "0", this.shadowHost.style.pointerEvents = "none", this.shadowHost.style.zIndex = String(this.config.zIndex), document.body.appendChild(this.shadowHost)), this.shadowRoot = this.shadowHost.attachShadow({ mode: "open" });
647
927
  const i = document.createElement("style");
648
- if (i.textContent = z(), this.shadowRoot.appendChild(i), this.config.css) {
928
+ if (i.textContent = P(), this.shadowRoot.appendChild(i), this.config.css) {
649
929
  const r = document.createElement("style");
650
930
  r.textContent = this.config.css, this.shadowRoot.appendChild(r);
651
931
  }
@@ -657,27 +937,33 @@ class Xt {
657
937
  const { x: r, y: d } = this.config.offset;
658
938
  this.config.position.includes("right") ? this.buttonsContainer.style.right = `${r}px` : this.buttonsContainer.style.left = `${r}px`, this.config.position.includes("bottom") ? this.buttonsContainer.style.bottom = `${d}px` : this.buttonsContainer.style.top = `${d}px`;
659
939
  }
660
- this.applyVars(this.buttonsContainer), this.shadowRoot.appendChild(this.buttonsContainer);
940
+ this.applyVars(this.buttonsContainer), this.shadowRoot.appendChild(this.buttonsContainer), this.buttonsContainer.addEventListener("keydown", (r) => {
941
+ (r.key === "Enter" || r.key === " " || r.key === "Spacebar") && (this.keyboardActivation = !0);
942
+ }), this.buttonsContainer.addEventListener("mousedown", () => {
943
+ this.keyboardActivation = !1;
944
+ }), this.buttonsContainer.addEventListener("pointerdown", () => {
945
+ this.keyboardActivation = !1;
946
+ });
661
947
  const n = !!this.config.buttonClass, s = n ? `qaid-btn-structural ${this.config.buttonClass}` : "qaid-btn", c = this.config.text.tooltip || "Feedback for us?", l = document.createElement("div");
662
948
  if (l.className = "qaid-tooltip-text", l.textContent = c, this.applyVars(l), this.shadowRoot.appendChild(l), this.tooltipElement = l, !this.config.hideThumbs) {
663
949
  const r = document.createElement("div");
664
950
  r.className = "qaid-tooltip-wrapper";
665
951
  const d = document.createElement("button");
666
- d.type = "button", d.className = n ? `${s} qaid-btn-up` : "qaid-btn qaid-btn-up", d.innerHTML = this.config.positiveIcon || E, d.addEventListener("click", (p) => this.handleThumbClick("up", p.currentTarget, p)), d.addEventListener("mouseenter", () => this.showTooltip(d)), d.addEventListener("mouseleave", () => this.hideTooltip()), r.appendChild(d);
667
- const h = document.createElement("div");
668
- h.className = "qaid-tooltip-wrapper";
952
+ d.type = "button", d.className = n ? `${s} qaid-btn-up` : "qaid-btn qaid-btn-up", d.setAttribute("aria-label", this.config.text.positiveLabel), d.innerHTML = this.config.positiveIcon || E, d.addEventListener("click", (m) => this.handleThumbClick("up", m.currentTarget, m)), d.addEventListener("mouseenter", () => this.showTooltip(d)), d.addEventListener("mouseleave", () => this.hideTooltip()), r.appendChild(d);
953
+ const p = document.createElement("div");
954
+ p.className = "qaid-tooltip-wrapper";
669
955
  const u = document.createElement("button");
670
- u.type = "button", u.className = n ? `${s} qaid-btn-down` : "qaid-btn qaid-btn-down", u.innerHTML = this.config.negativeIcon || T, u.addEventListener("click", (p) => this.handleThumbClick("down", p.currentTarget, p)), u.addEventListener("mouseenter", () => this.showTooltip(u)), u.addEventListener("mouseleave", () => this.hideTooltip()), h.appendChild(u), this.buttonsContainer.appendChild(r), this.buttonsContainer.appendChild(h);
956
+ u.type = "button", u.className = n ? `${s} qaid-btn-down` : "qaid-btn qaid-btn-down", u.setAttribute("aria-label", this.config.text.negativeLabel), u.innerHTML = this.config.negativeIcon || T, u.addEventListener("click", (m) => this.handleThumbClick("down", m.currentTarget, m)), u.addEventListener("mouseenter", () => this.showTooltip(u)), u.addEventListener("mouseleave", () => this.hideTooltip()), p.appendChild(u), this.buttonsContainer.appendChild(r), this.buttonsContainer.appendChild(p);
671
957
  }
672
- if (this.config.captureVideo && Bt()) {
958
+ if (this.config.captureVideo && ee()) {
673
959
  const r = document.createElement("div");
674
960
  r.className = "qaid-tooltip-wrapper";
675
961
  const d = document.createElement("button");
676
- d.type = "button", d.className = n ? `${s} qaid-btn-record` : "qaid-btn qaid-btn-record", d.innerHTML = this.config.recordIcon || it, d.addEventListener("click", () => this.startRecording()), d.addEventListener("mouseenter", () => this.showTooltip(d)), d.addEventListener("mouseleave", () => this.hideTooltip()), r.appendChild(d), this.buttonsContainer.appendChild(r);
962
+ d.type = "button", d.className = n ? `${s} qaid-btn-record` : "qaid-btn qaid-btn-record", d.setAttribute("aria-label", this.config.text.recordLabel), d.innerHTML = this.config.recordIcon || dt, d.addEventListener("click", () => this.startRecording()), d.addEventListener("mouseenter", () => this.showTooltip(d)), d.addEventListener("mouseleave", () => this.hideTooltip()), r.appendChild(d), this.buttonsContainer.appendChild(r);
677
963
  }
678
- this.config.hideDismiss || (this.dismissBtn = document.createElement("button"), this.dismissBtn.type = "button", this.dismissBtn.className = "qaid-dismiss-btn", this.dismissBtn.setAttribute("aria-label", "Hide Feedback"), this.dismissBtn.title = "Hide Feedback", this.dismissBtn.innerHTML = '<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 2l8 8M10 2l-8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>', this.dismissBtn.addEventListener("click", (r) => {
964
+ this.config.hideDismiss || (this.dismissBtn = document.createElement("button"), this.dismissBtn.type = "button", this.dismissBtn.className = "qaid-dismiss-btn", this.dismissBtn.setAttribute("aria-label", this.config.text.dismissLabel), this.dismissBtn.title = this.config.text.dismissLabel, this.dismissBtn.innerHTML = '<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M2 2l8 8M10 2l-8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>', this.dismissBtn.addEventListener("click", (r) => {
679
965
  r.stopPropagation(), this.handleDismiss();
680
- }), this.buttonsContainer.insertBefore(this.dismissBtn, this.buttonsContainer.firstChild), this._startDismissed && this.buttonsContainer.classList.add("qaid-incognito"));
966
+ }), this.buttonsContainer.insertBefore(this.dismissBtn, this.buttonsContainer.firstChild), this._startDismissed && this.buttonsContainer.classList.add("qaid-dismissed"));
681
967
  }
682
968
  /**
683
969
  * Lazily create a separate overlay shadow host on document.body.
@@ -689,7 +975,7 @@ class Xt {
689
975
  if (this.overlayShadowRoot) return this.overlayShadowRoot;
690
976
  this.overlayShadowHost = document.createElement("div"), this.overlayShadowHost.setAttribute("data-qaid-embed-overlay", ""), this.overlayShadowHost.style.position = "fixed", this.overlayShadowHost.style.inset = "0", this.overlayShadowHost.style.pointerEvents = "none", this.overlayShadowHost.style.zIndex = String(this.config.zIndex), document.body.appendChild(this.overlayShadowHost), this.overlayShadowRoot = this.overlayShadowHost.attachShadow({ mode: "open" });
691
977
  const t = document.createElement("style");
692
- if (t.textContent = z(), this.overlayShadowRoot.appendChild(t), this.config.css) {
978
+ if (t.textContent = P(), this.overlayShadowRoot.appendChild(t), this.config.css) {
693
979
  const i = document.createElement("style");
694
980
  i.textContent = this.config.css, this.overlayShadowRoot.appendChild(i);
695
981
  }
@@ -699,7 +985,7 @@ class Xt {
699
985
  showTooltip(t) {
700
986
  const i = this.tooltipElement;
701
987
  i.style.visibility = "hidden", i.classList.add("qaid-tooltip-visible");
702
- const o = t.getBoundingClientRect(), n = i.getBoundingClientRect(), { top: s, left: a } = Et(
988
+ const o = t.getBoundingClientRect(), n = i.getBoundingClientRect(), { top: s, left: a } = jt(
703
989
  o,
704
990
  n,
705
991
  { width: window.innerWidth, height: window.innerHeight }
@@ -710,13 +996,16 @@ class Xt {
710
996
  this.tooltipElement.classList.remove("qaid-tooltip-visible");
711
997
  }
712
998
  handleDismiss() {
713
- const t = this.buttonsContainer;
714
- t.classList.add("qaid-incognito"), t.classList.add("qaid-force-hidden"), t.addEventListener("mouseleave", () => {
715
- t.classList.remove("qaid-force-hidden");
716
- }, { once: !0 }), F(this.config.apiKey, !0);
999
+ this.buttonsContainer.classList.add("qaid-dismissed"), W(this.config.apiKey, !0);
717
1000
  }
718
1001
  handleThumbClick(t, i, o) {
719
- this.buttonsContainer?.classList.contains("qaid-incognito") && (this.buttonsContainer.classList.remove("qaid-incognito"), this.buttonsContainer.classList.remove("qaid-force-hidden"), F(this.config.apiKey, !1)), this.config.skipTargeting ? this.submitDirectFeedback(t, i) : this.startTargeting(t, o);
1002
+ if (this.buttonsContainer?.classList.contains("qaid-incognito") && (this.buttonsContainer.classList.remove("qaid-incognito"), W(this.config.apiKey, !1)), this.config.skipTargeting)
1003
+ this.submitDirectFeedback(t, i);
1004
+ else {
1005
+ this.activeThumbBtn = i, i.setAttribute("aria-pressed", "true");
1006
+ const n = this.keyboardActivation;
1007
+ this.keyboardActivation = !1, n ? this.startKeyboardTargetingFlow(t) : this.startTargeting(t, o);
1008
+ }
720
1009
  }
721
1010
  submitDirectFeedback(t, i) {
722
1011
  this.feedbackData.feedbackType = t, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null;
@@ -734,6 +1023,36 @@ class Xt {
734
1023
  startTargeting(t, i) {
735
1024
  this.state = "TARGETING", this.feedbackData.feedbackType = t, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1, this.mousePos.x = i.clientX, this.mousePos.y = i.clientY, document.body.classList.add("qaid-targeting"), t === "up" ? document.body.classList.add("qaid-type-up") : document.body.classList.remove("qaid-type-up"), document.body.style.setProperty("--qaid-positive", this.cssVars["--qaid-positive"]), document.body.style.setProperty("--qaid-negative", this.cssVars["--qaid-negative"]), this.createTargetingOverlay(), document.addEventListener("keydown", this.boundKeyDown), document.addEventListener("mousemove", this.boundMouseMove), document.addEventListener("click", this.boundClick, !0);
736
1025
  }
1026
+ /**
1027
+ * Keyboard-driven targeting. Mirrors startTargeting minus the mouse
1028
+ * plumbing: no `qaid-targeting` body class (keeps the cursor visible for
1029
+ * keyboard users), no mouse reticle, and no document mouse/click listeners.
1030
+ * The KeyboardTargetingController owns Tab/Arrow/Enter/Space/Escape.
1031
+ */
1032
+ startKeyboardTargetingFlow(t) {
1033
+ this.state = "TARGETING", this.feedbackData.feedbackType = t, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1, document.body.style.setProperty("--qaid-positive", this.cssVars["--qaid-positive"]), document.body.style.setProperty("--qaid-negative", this.cssVars["--qaid-negative"]), this.createTargetingOverlay(), this.crosshairH && (this.crosshairH.style.display = "none"), this.crosshairV && (this.crosshairV.style.display = "none"), this.scope && (this.scope.style.display = "none"), this.keyboardController = Dt({
1034
+ isExcluded: (i) => I(i),
1035
+ onHighlight: (i) => {
1036
+ const o = i.getBoundingClientRect(), n = this.highlightBox;
1037
+ n && (n.style.transform = `translate(${o.left}px, ${o.top}px)`, n.style.width = `${o.width}px`, n.style.height = `${o.height}px`, n.style.display = "block");
1038
+ const { text: s } = L(i);
1039
+ this.announceMsg(`Targeting ${s || i.tagName.toLowerCase()}`);
1040
+ },
1041
+ onSelect: (i) => this.selectKeyboardTarget(i),
1042
+ onCancel: () => this.cancelTargeting()
1043
+ });
1044
+ }
1045
+ selectKeyboardTarget(t) {
1046
+ const i = _(t, 8);
1047
+ this.selectedBounds = {
1048
+ ...i,
1049
+ clickX: i.x + i.width / 2,
1050
+ clickY: i.y + i.height / 2,
1051
+ visible: !0
1052
+ };
1053
+ const { selector: o, text: n } = L(t);
1054
+ this.feedbackData.elementSelector = o, this.feedbackData.elementText = n, this.removeTargetingOverlay(), document.body.classList.remove("qaid-targeting", "qaid-type-up"), document.body.style.removeProperty("--qaid-positive"), document.body.style.removeProperty("--qaid-negative"), this.keyboardController = null, this.clearActiveThumb(), this.state = "SELECTED", this.showSelectedMarker(), this.submitFeedback();
1055
+ }
737
1056
  createTargetingOverlay() {
738
1057
  const t = this.ensureOverlayHost();
739
1058
  this.overlayContainer = document.createElement("div"), this.overlayContainer.className = `qaid-targeting-overlay qaid-type-${this.feedbackData.feedbackType}`, this.captureLayer = document.createElement("div"), this.captureLayer.className = "qaid-capture-layer";
@@ -749,12 +1068,12 @@ class Xt {
749
1068
  }
750
1069
  handleMouseMove(t) {
751
1070
  if (this.mousePos.x = t.clientX, this.mousePos.y = t.clientY, this.crosshairH && (this.crosshairH.style.top = `${t.clientY}px`), this.crosshairV && (this.crosshairV.style.left = `${t.clientX}px`), this.scope && (this.scope.style.left = `${t.clientX}px`, this.scope.style.top = `${t.clientY}px`), this.captureLayer && this.shadowHost) {
752
- const i = [this.shadowHost, this.overlayShadowHost].filter(Boolean), o = A(
1071
+ const i = [this.shadowHost, this.overlayShadowHost].filter(Boolean), o = F(
753
1072
  t.clientX,
754
1073
  t.clientY,
755
1074
  i
756
1075
  );
757
- if (o && !$(o)) {
1076
+ if (o && !I(o)) {
758
1077
  if (this.highlightBox) {
759
1078
  const n = o.getBoundingClientRect();
760
1079
  this.highlightBox.style.transform = `translate(${n.left}px, ${n.top}px)`, this.highlightBox.style.width = `${n.width}px`, this.highlightBox.style.height = `${n.height}px`, this.highlightBox.style.display = "block";
@@ -765,25 +1084,25 @@ class Xt {
765
1084
  }
766
1085
  handleClick(t) {
767
1086
  t.preventDefault(), t.stopPropagation();
768
- const i = [this.shadowHost, this.overlayShadowHost].filter(Boolean), o = A(
1087
+ const i = [this.shadowHost, this.overlayShadowHost].filter(Boolean), o = F(
769
1088
  t.clientX,
770
1089
  t.clientY,
771
1090
  i
772
1091
  );
773
- if (!o || $(o))
1092
+ if (!o || I(o))
774
1093
  return;
775
- const n = Ot(o, 8);
1094
+ const n = _(o, 8);
776
1095
  this.selectedBounds = {
777
1096
  ...n,
778
1097
  clickX: t.clientX,
779
1098
  clickY: t.clientY,
780
1099
  visible: !0
781
1100
  };
782
- const { selector: s, text: a } = xt(o);
783
- this.feedbackData.elementSelector = s, this.feedbackData.elementText = a, this.removeTargetingOverlay(), document.removeEventListener("mousemove", this.boundMouseMove), document.removeEventListener("click", this.boundClick, !0), document.removeEventListener("keydown", this.boundKeyDown), document.body.classList.remove("qaid-targeting", "qaid-type-up"), document.body.style.removeProperty("--qaid-positive"), document.body.style.removeProperty("--qaid-negative"), this.state = "SELECTED", this.showSelectedMarker(), this.submitFeedback();
1101
+ const { selector: s, text: a } = L(o);
1102
+ this.feedbackData.elementSelector = s, this.feedbackData.elementText = a, this.removeTargetingOverlay(), document.removeEventListener("mousemove", this.boundMouseMove), document.removeEventListener("click", this.boundClick, !0), document.removeEventListener("keydown", this.boundKeyDown), document.body.classList.remove("qaid-targeting", "qaid-type-up"), document.body.style.removeProperty("--qaid-positive"), document.body.style.removeProperty("--qaid-negative"), this.state = "SELECTED", this.clearActiveThumb(), this.showSelectedMarker(), this.submitFeedback();
784
1103
  }
785
1104
  cancelTargeting() {
786
- this.removeTargetingOverlay(), document.removeEventListener("mousemove", this.boundMouseMove), document.removeEventListener("click", this.boundClick, !0), document.removeEventListener("keydown", this.boundKeyDown), document.body.classList.remove("qaid-targeting", "qaid-type-up"), document.body.style.removeProperty("--qaid-positive"), document.body.style.removeProperty("--qaid-negative"), this.state = "IDLE", this.feedbackData.feedbackType = null, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1;
1105
+ this.keyboardController?.stop(), this.keyboardController = null, this.removeTargetingOverlay(), document.removeEventListener("mousemove", this.boundMouseMove), document.removeEventListener("click", this.boundClick, !0), document.removeEventListener("keydown", this.boundKeyDown), document.body.classList.remove("qaid-targeting", "qaid-type-up"), document.body.style.removeProperty("--qaid-positive"), document.body.style.removeProperty("--qaid-negative"), this.clearActiveThumb(), this.state = "IDLE", this.feedbackData.feedbackType = null, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1;
787
1106
  }
788
1107
  removeTargetingOverlay() {
789
1108
  this.overlayContainer && (this.overlayContainer.remove(), this.overlayContainer = null), this.captureLayer = null, this.crosshairH = null, this.crosshairV = null, this.scope = null;
@@ -797,7 +1116,7 @@ class Xt {
797
1116
  }
798
1117
  async submitFeedback() {
799
1118
  let t = null;
800
- this.config.captureScreenshot && (this.config.screenshotMethod === "dom" ? t = await _t(this.config.screenshotOptions) : t = await At(this.config.screenshotOptions));
1119
+ this.config.captureScreenshot && (this.config.screenshotMethod === "dom" ? t = await ce(this.config.screenshotOptions) : t = await se(this.config.screenshotOptions), t && this.announceMsg("Screenshot captured"));
801
1120
  const i = this.feedbackData.elementSelector ? {
802
1121
  x: this.selectedBounds.x,
803
1122
  y: this.selectedBounds.y,
@@ -830,10 +1149,10 @@ class Xt {
830
1149
  });
831
1150
  if (n.ok) {
832
1151
  const s = await n.json();
833
- this.feedbackId = s.id;
1152
+ this.feedbackId = s.id, this.announceMsg("Feedback sent");
834
1153
  }
835
1154
  } catch (n) {
836
- console.error("Failed to submit feedback:", n);
1155
+ console.error("Failed to submit feedback:", n), this.announceMsg("Failed to send feedback", !0);
837
1156
  }
838
1157
  this.state = "MODAL_OPEN", this.showModal(), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "auto");
839
1158
  }
@@ -851,7 +1170,7 @@ class Xt {
851
1170
  `, this.applyVars(i), t.appendChild(i), this.modalContainer = i, this.setupModalInteractions();
852
1171
  }
853
1172
  showPositionedModal() {
854
- const t = this.ensureOverlayHost(), { modal: i, arrow: o } = Tt(
1173
+ const t = this.ensureOverlayHost(), { modal: i, arrow: o } = Yt(
855
1174
  this.selectedBounds,
856
1175
  window.innerWidth,
857
1176
  window.innerHeight,
@@ -873,21 +1192,25 @@ class Xt {
873
1192
  const t = this.feedbackData.feedbackType === "up", i = this.config.positiveIcon || E, o = this.config.negativeIcon || T;
874
1193
  return `
875
1194
  <div class="qaid-modal-header">
876
- <button type="button" class="${this.config.buttonClass ? `qaid-type-toggle qaid-type-toggle-custom ${this.config.buttonClass} ${t ? "qaid-btn-up" : "qaid-btn-down"}` : `qaid-type-toggle ${t ? "qaid-type-up" : "qaid-type-down"}`}" title="Click to switch">
1195
+ <button type="button" class="${this.config.buttonClass ? `qaid-type-toggle qaid-type-toggle-custom ${this.config.buttonClass} ${t ? "qaid-btn-up" : "qaid-btn-down"}` : `qaid-type-toggle ${t ? "qaid-type-up" : "qaid-type-down"}`}" title="Click to switch" aria-pressed="${t}" aria-label="${t ? "Feedback type: positive" : "Feedback type: negative"}">
877
1196
  ${t ? i : o}
878
1197
  </button>
879
1198
  <div class="qaid-modal-header-text">
880
- <h3 class="qaid-modal-title">${this.config.text.modalTitle}</h3>
881
- <p class="qaid-modal-subtitle">${this.config.text.modalSubtitle}</p>
1199
+ <h3 class="qaid-modal-title" id="qaid-modal-title-${this.uid}">${this.config.text.modalTitle}</h3>
1200
+ <p class="qaid-modal-subtitle" id="qaid-modal-subtitle-${this.uid}">${this.config.text.modalSubtitle}</p>
882
1201
  </div>
883
1202
  </div>
884
- <textarea class="qaid-textarea" placeholder="${this.config.text.placeholder}"></textarea>
1203
+ <textarea class="qaid-textarea" aria-label="${this.config.text.modalSubtitle}" placeholder="${this.config.text.placeholder}"></textarea>
885
1204
  <div class="qaid-btn-row">
886
1205
  <button type="button" class="qaid-btn-submit">${this.config.text.skipButton}</button>
887
1206
  </div>
888
1207
  `;
889
1208
  }
890
1209
  setupModalInteractions() {
1210
+ this.openDialogA11y(this.modalContainer, {
1211
+ labelledbyId: `qaid-modal-title-${this.uid}`,
1212
+ describedbyId: `qaid-modal-subtitle-${this.uid}`
1213
+ });
891
1214
  const t = this.modalContainer.querySelector(".qaid-textarea"), i = this.modalContainer.querySelector(".qaid-btn-submit");
892
1215
  t && (setTimeout(() => t.focus(), 100), t.addEventListener("input", () => {
893
1216
  i && (i.textContent = t.value.trim() ? this.config.text.submitButton : this.config.text.skipButton);
@@ -900,11 +1223,13 @@ class Xt {
900
1223
  const n = this.feedbackData.feedbackType === "up" ? "down" : "up";
901
1224
  this.feedbackData.feedbackType = n, this.config.buttonClass ? (o.classList.toggle("qaid-btn-up", n === "up"), o.classList.toggle("qaid-btn-down", n === "down")) : (o.classList.toggle("qaid-type-up", n === "up"), o.classList.toggle("qaid-type-down", n === "down"));
902
1225
  const s = this.config.positiveIcon || E, a = this.config.negativeIcon || T;
903
- o.innerHTML = n === "up" ? s : a, this.feedbackId && fetch(`${this.config.endpoint}/${this.feedbackId}`, {
1226
+ o.innerHTML = n === "up" ? s : a;
1227
+ const c = n === "up" ? "Feedback type: positive" : "Feedback type: negative";
1228
+ o.setAttribute("aria-pressed", String(n === "up")), o.setAttribute("aria-label", c), this.announceMsg(c), this.feedbackId && fetch(`${this.config.endpoint}/${this.feedbackId}`, {
904
1229
  method: "PATCH",
905
1230
  headers: { "Content-Type": "application/json" },
906
1231
  body: JSON.stringify({ feedbackType: n })
907
- }).catch((c) => console.error("Failed to update feedback type:", c));
1232
+ }).catch((l) => console.error("Failed to update feedback type:", l));
908
1233
  });
909
1234
  }
910
1235
  async submitMessage(t) {
@@ -927,19 +1252,19 @@ class Xt {
927
1252
  method: "PATCH",
928
1253
  headers: { "Content-Type": "application/json" },
929
1254
  body: JSON.stringify({ message: null })
930
- }).catch((t) => console.error("Failed to finalize feedback:", t)), this.modalContainer && (this.modalContainer.remove(), this.modalContainer = null), this.backdrop && (this.backdrop.remove(), this.backdrop = null), document.removeEventListener("keydown", this.boundKeyDown), this.hideSelectedMarker(), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "none"), this.state = "IDLE", this.feedbackId = null, this.feedbackData.feedbackType = null, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1;
1255
+ }).catch((t) => console.error("Failed to finalize feedback:", t)), this.closeDialogA11y(), this.modalContainer && (this.modalContainer.remove(), this.modalContainer = null), this.backdrop && (this.backdrop.remove(), this.backdrop = null), document.removeEventListener("keydown", this.boundKeyDown), this.hideSelectedMarker(), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "none"), this.state = "IDLE", this.feedbackId = null, this.feedbackData.feedbackType = null, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null, this.selectedBounds.visible = !1;
931
1256
  }
932
1257
  // ==================== Video Recording ====================
933
1258
  async startRecording() {
934
1259
  if (!(this.isRecording || this.state !== "IDLE"))
935
1260
  try {
936
- this.networkCapture = Mt(), this.videoRecorder = zt({
1261
+ this.networkCapture = te(), this.videoRecorder = oe({
937
1262
  maxDuration: this.config.videoOptions.maxDuration
938
1263
  }), this.videoRecorder.onTick((t) => {
939
1264
  this.updateRecordingTimer(t);
940
1265
  }), this.videoRecorder.onStop((t) => {
941
- this.isRecording && (this.recordedBlob = t, this.isRecording = !1, this.removeRecordingIndicator(), document.removeEventListener("keydown", this.boundKeyDown), this.setButtonsDisabled(!1), t && t.size > 0 ? this.showRecordingPreview() : this.cleanupRecording());
942
- }), await this.videoRecorder.start(), this.isRecording = !0, this.setButtonsDisabled(!0), this.showRecordingIndicator(), document.addEventListener("keydown", this.boundKeyDown);
1266
+ this.isRecording && (this.recordedBlob = t, this.isRecording = !1, this.announceMsg("Recording stopped"), this.removeRecordingIndicator(), document.removeEventListener("keydown", this.boundKeyDown), this.setButtonsDisabled(!1), t && t.size > 0 ? this.showRecordingPreview() : this.cleanupRecording());
1267
+ }), await this.videoRecorder.start(), this.isRecording = !0, this.announceMsg("Recording started"), this.setButtonsDisabled(!0), this.showRecordingIndicator(), document.addEventListener("keydown", this.boundKeyDown);
943
1268
  } catch {
944
1269
  this.cleanupRecording();
945
1270
  }
@@ -950,7 +1275,7 @@ class Xt {
950
1275
  } catch {
951
1276
  this.recordedBlob = null;
952
1277
  }
953
- this.isRecording = !1, this.removeRecordingIndicator(), document.removeEventListener("keydown", this.boundKeyDown), this.recordedBlob && this.recordedBlob.size > 0 ? this.showRecordingPreview() : this.cleanupRecording();
1278
+ this.isRecording = !1, this.announceMsg("Recording stopped"), this.removeRecordingIndicator(), document.removeEventListener("keydown", this.boundKeyDown), this.recordedBlob && this.recordedBlob.size > 0 ? this.showRecordingPreview() : this.cleanupRecording();
954
1279
  }
955
1280
  showRecordingIndicator() {
956
1281
  const t = this.ensureOverlayHost();
@@ -967,7 +1292,7 @@ class Xt {
967
1292
  const i = this.recordingIndicator.querySelector(".qaid-recording-time");
968
1293
  if (i) {
969
1294
  const o = Math.max(0, this.config.videoOptions.maxDuration - t);
970
- i.textContent = this.formatTime(o);
1295
+ i.textContent = this.formatTime(o), o > 0 && o <= 5 && this.announceMsg(`${o} second${o === 1 ? "" : "s"} remaining`);
971
1296
  }
972
1297
  }
973
1298
  formatTime(t) {
@@ -983,11 +1308,11 @@ class Xt {
983
1308
  const o = document.createElement("div");
984
1309
  o.className = "qaid-video-preview-box";
985
1310
  const n = document.createElement("h3");
986
- n.textContent = "Review your recording";
1311
+ n.textContent = "Review your recording", n.id = `qaid-video-title-${this.uid}`;
987
1312
  const s = document.createElement("video");
988
1313
  s.src = i, s.controls = !0, s.autoplay = !0, s.muted = !0;
989
1314
  const a = document.createElement("textarea");
990
- a.placeholder = "Optional: Describe the issue you recorded...";
1315
+ a.placeholder = "Optional: Describe the issue you recorded...", a.setAttribute("aria-label", "Describe the issue you recorded");
991
1316
  const c = document.createElement("div");
992
1317
  c.className = "qaid-video-preview-actions";
993
1318
  const l = document.createElement("button");
@@ -998,15 +1323,15 @@ class Xt {
998
1323
  });
999
1324
  const d = document.createElement("button");
1000
1325
  d.type = "button", d.className = "qaid-video-btn qaid-video-btn-send", d.textContent = "Send", d.addEventListener("click", () => {
1001
- const h = a.value.trim() || null;
1002
- this.submitVideoFeedback(h, d);
1003
- }), c.appendChild(l), c.appendChild(r), c.appendChild(d), o.appendChild(n), o.appendChild(s), o.appendChild(a), o.appendChild(c), this.videoPreview.appendChild(o), this.applyVars(this.videoPreview), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "auto"), t.appendChild(this.videoPreview), document.addEventListener("keydown", this.boundKeyDown);
1326
+ const p = a.value.trim() || null;
1327
+ this.submitVideoFeedback(p, d);
1328
+ }), c.appendChild(l), c.appendChild(r), c.appendChild(d), o.appendChild(n), o.appendChild(s), o.appendChild(a), o.appendChild(c), this.videoPreview.appendChild(o), this.applyVars(this.videoPreview), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "auto"), t.appendChild(this.videoPreview), this.openDialogA11y(o, { labelledbyId: n.id }), document.addEventListener("keydown", this.boundKeyDown);
1004
1329
  }
1005
1330
  cancelRecordingPreview() {
1006
1331
  this.removeVideoPreview(), this.cleanupRecording();
1007
1332
  }
1008
1333
  removeVideoPreview() {
1009
- if (this.videoPreview) {
1334
+ if (this.closeDialogA11y(), this.videoPreview) {
1010
1335
  const t = this.videoPreview.querySelector("video");
1011
1336
  t?.src && URL.revokeObjectURL(t.src), this.videoPreview.remove(), this.videoPreview = null;
1012
1337
  }
@@ -1022,9 +1347,9 @@ class Xt {
1022
1347
  method: "POST",
1023
1348
  body: o
1024
1349
  });
1025
- n.ok || console.error("Failed to submit video feedback:", await n.text());
1350
+ n.ok ? this.announceMsg("Recording sent") : (console.error("Failed to submit video feedback:", await n.text()), this.announceMsg("Failed to send recording", !0));
1026
1351
  } catch (n) {
1027
- console.error("Failed to submit video feedback:", n);
1352
+ console.error("Failed to submit video feedback:", n), this.announceMsg("Failed to send recording", !0);
1028
1353
  }
1029
1354
  this.isSendingVideo = !1, this.removeVideoPreview(), this.cleanupRecording();
1030
1355
  }
@@ -1041,13 +1366,13 @@ class Xt {
1041
1366
  * Destroy the embed and clean up all resources
1042
1367
  */
1043
1368
  destroy() {
1044
- this.destroyed = !0, this.domObserver && (this.domObserver.disconnect(), this.domObserver = null), this.boundBeforeSwap && (document.removeEventListener("astro:before-swap", this.boundBeforeSwap), this.boundBeforeSwap = null), this.cleanupRecording(), this.removeVideoPreview(), this.consoleCapture && (this.consoleCapture.restore(), this.consoleCapture = null), window.removeEventListener("resize", this.boundResize), document.removeEventListener("keydown", this.boundKeyDown), document.removeEventListener("mousemove", this.boundMouseMove), document.removeEventListener("click", this.boundClick, !0), document.body.classList.remove("qaid-targeting", "qaid-type-up"), document.body.style.removeProperty("--qaid-positive"), document.body.style.removeProperty("--qaid-negative"), this.shadowHost && (this.shadowHost.remove(), this.shadowHost = null, this.shadowRoot = null), this.overlayShadowHost && (this.overlayShadowHost.remove(), this.overlayShadowHost = null, this.overlayShadowRoot = null), this.buttonsContainer = null, this.overlayContainer = null, this.captureLayer = null, this.crosshairH = null, this.crosshairV = null, this.scope = null, this.marker = null, this.modalContainer = null, this.backdrop = null, this.dismissBtn = null, this.tooltipElement = null, mt();
1369
+ this.destroyed = !0, this.domObserver && (this.domObserver.disconnect(), this.domObserver = null), this.boundBeforeSwap && (document.removeEventListener("astro:before-swap", this.boundBeforeSwap), this.boundBeforeSwap = null), this.keyboardController?.stop(), this.keyboardController = null, this.clearActiveThumb(), this.closeDialogA11y(), this.cleanupRecording(), this.removeVideoPreview(), this.consoleCapture && (this.consoleCapture.restore(), this.consoleCapture = null), window.removeEventListener("resize", this.boundResize), document.removeEventListener("keydown", this.boundKeyDown), document.removeEventListener("mousemove", this.boundMouseMove), document.removeEventListener("click", this.boundClick, !0), document.body.classList.remove("qaid-targeting", "qaid-type-up"), document.body.style.removeProperty("--qaid-positive"), document.body.style.removeProperty("--qaid-negative"), this.shadowHost && (this.shadowHost.remove(), this.shadowHost = null, this.shadowRoot = null), this.overlayShadowHost && (this.overlayShadowHost.remove(), this.overlayShadowHost = null, this.overlayShadowRoot = null), this.buttonsContainer = null, this.overlayContainer = null, this.captureLayer = null, this.crosshairH = null, this.crosshairV = null, this.scope = null, this.marker = null, this.modalContainer = null, this.backdrop = null, this.dismissBtn = null, this.tooltipElement = null, wt();
1045
1370
  }
1046
1371
  }
1047
- function W(e) {
1372
+ function Z(e) {
1048
1373
  return document.querySelector(e)?.textContent?.trim() ?? "";
1049
1374
  }
1050
- function Wt() {
1375
+ function pe() {
1051
1376
  const e = document.querySelector(
1052
1377
  'script[type="application/json"][data-feedback-config]'
1053
1378
  );
@@ -1056,20 +1381,20 @@ function Wt() {
1056
1381
  if (!t) return null;
1057
1382
  try {
1058
1383
  const i = JSON.parse(t);
1059
- return i.cssSelector && !i.css && (i.css = W(i.cssSelector), delete i.cssSelector), i;
1384
+ return i.cssSelector && !i.css && (i.css = Z(i.cssSelector), delete i.cssSelector), i;
1060
1385
  } catch {
1061
1386
  return null;
1062
1387
  }
1063
1388
  }
1064
- function jt(e) {
1389
+ function me(e) {
1065
1390
  const t = e.getAttribute("data-endpoint");
1066
1391
  if (!t) return null;
1067
- const i = e.getAttribute("data-position"), o = e.getAttribute("data-zindex"), n = e.getAttribute("data-positive-color"), s = e.getAttribute("data-negative-color"), a = e.getAttribute("data-marker-color"), c = e.getAttribute("data-container"), l = e.getAttribute("data-button-class"), r = e.getAttribute("data-skip-targeting"), d = e.getAttribute("data-incognito"), h = e.getAttribute("data-button-size"), u = e.getAttribute("data-offset-x"), p = e.getAttribute("data-offset-y"), b = e.getAttribute("data-modal-width"), f = e.getAttribute("data-backdrop-opacity"), m = e.getAttribute("data-font-family"), v = e.getAttribute("data-font-size"), g = e.getAttribute("data-tooltip"), x = e.getAttribute("data-modal-title"), L = e.getAttribute("data-modal-subtitle"), D = e.getAttribute("data-placeholder"), H = e.getAttribute("data-submit-button"), M = e.getAttribute("data-skip-button"), j = e.getAttribute("data-positive-icon"), K = e.getAttribute("data-negative-icon"), Y = e.getAttribute("data-api-key"), J = e.getAttribute("data-capture-screenshot"), k = e.getAttribute("data-screenshot-quality"), C = e.getAttribute("data-screenshot-max-width"), S = e.getAttribute("data-screenshot-max-height"), G = e.getAttribute("data-capture-video"), Z = e.getAttribute("data-hide-thumbs"), Q = e.getAttribute("data-hide-dismiss"), B = e.getAttribute("data-video-max-duration"), tt = e.getAttribute("data-screenshot-method"), et = e.getAttribute("data-direction"), R = e.getAttribute("data-css-selector");
1392
+ const i = e.getAttribute("data-position"), o = e.getAttribute("data-zindex"), n = e.getAttribute("data-positive-color"), s = e.getAttribute("data-negative-color"), a = e.getAttribute("data-marker-color"), c = e.getAttribute("data-container"), l = e.getAttribute("data-button-class"), r = e.getAttribute("data-skip-targeting"), d = e.getAttribute("data-incognito"), p = e.getAttribute("data-button-size"), u = e.getAttribute("data-offset-x"), m = e.getAttribute("data-offset-y"), g = e.getAttribute("data-modal-width"), b = e.getAttribute("data-backdrop-opacity"), f = e.getAttribute("data-font-family"), v = e.getAttribute("data-font-size"), h = e.getAttribute("data-tooltip"), y = e.getAttribute("data-modal-title"), A = e.getAttribute("data-modal-subtitle"), M = e.getAttribute("data-placeholder"), R = e.getAttribute("data-submit-button"), H = e.getAttribute("data-skip-button"), Q = e.getAttribute("data-positive-icon"), tt = e.getAttribute("data-negative-icon"), et = e.getAttribute("data-api-key"), it = e.getAttribute("data-capture-screenshot"), k = e.getAttribute("data-screenshot-quality"), C = e.getAttribute("data-screenshot-max-width"), S = e.getAttribute("data-screenshot-max-height"), ot = e.getAttribute("data-capture-video"), nt = e.getAttribute("data-hide-thumbs"), st = e.getAttribute("data-hide-dismiss"), B = e.getAttribute("data-video-max-duration"), at = e.getAttribute("data-screenshot-method"), rt = e.getAttribute("data-direction"), z = e.getAttribute("data-css-selector");
1068
1393
  return {
1069
1394
  endpoint: t,
1070
- css: R ? W(R) : void 0,
1071
- apiKey: Y ?? void 0,
1072
- captureScreenshot: J === "true" ? !0 : void 0,
1395
+ css: z ? Z(z) : void 0,
1396
+ apiKey: et ?? void 0,
1397
+ captureScreenshot: it === "true" ? !0 : void 0,
1073
1398
  screenshotOptions: k || C || S ? {
1074
1399
  quality: k ? parseFloat(k) : void 0,
1075
1400
  maxWidth: C ? parseInt(C, 10) : void 0,
@@ -1077,39 +1402,39 @@ function jt(e) {
1077
1402
  } : void 0,
1078
1403
  container: c ?? void 0,
1079
1404
  buttonClass: l ?? void 0,
1080
- direction: et ?? void 0,
1405
+ direction: rt ?? void 0,
1081
1406
  position: i ?? void 0,
1082
1407
  zIndex: o ? parseInt(o, 10) : void 0,
1083
1408
  skipTargeting: r === "true" ? !0 : void 0,
1084
1409
  incognito: d === "true" ? !0 : void 0,
1085
- buttonSize: h ?? void 0,
1086
- offset: u || p ? {
1410
+ buttonSize: p ?? void 0,
1411
+ offset: u || m ? {
1087
1412
  x: u ? parseInt(u, 10) : void 0,
1088
- y: p ? parseInt(p, 10) : void 0
1413
+ y: m ? parseInt(m, 10) : void 0
1089
1414
  } : void 0,
1090
- modalWidth: b ? parseInt(b, 10) : void 0,
1091
- backdropOpacity: f ? parseFloat(f) : void 0,
1092
- fontFamily: m ?? void 0,
1415
+ modalWidth: g ? parseInt(g, 10) : void 0,
1416
+ backdropOpacity: b ? parseFloat(b) : void 0,
1417
+ fontFamily: f ?? void 0,
1093
1418
  fontSize: v ? parseInt(v, 10) : void 0,
1094
1419
  colors: {
1095
1420
  positive: n ?? void 0,
1096
1421
  negative: s ?? void 0,
1097
1422
  marker: a ?? void 0
1098
1423
  },
1099
- text: g || x || L || D || H || M ? {
1100
- tooltip: g ?? void 0,
1101
- modalTitle: x ?? void 0,
1102
- modalSubtitle: L ?? void 0,
1103
- placeholder: D ?? void 0,
1104
- submitButton: H ?? void 0,
1105
- skipButton: M ?? void 0
1424
+ text: h || y || A || M || R || H ? {
1425
+ tooltip: h ?? void 0,
1426
+ modalTitle: y ?? void 0,
1427
+ modalSubtitle: A ?? void 0,
1428
+ placeholder: M ?? void 0,
1429
+ submitButton: R ?? void 0,
1430
+ skipButton: H ?? void 0
1106
1431
  } : void 0,
1107
- positiveIcon: j ?? void 0,
1108
- negativeIcon: K ?? void 0,
1109
- screenshotMethod: tt ?? void 0,
1110
- captureVideo: G === "true" ? !0 : void 0,
1111
- hideThumbs: Z === "true" ? !0 : void 0,
1112
- hideDismiss: Q === "true" ? !0 : void 0,
1432
+ positiveIcon: Q ?? void 0,
1433
+ negativeIcon: tt ?? void 0,
1434
+ screenshotMethod: at ?? void 0,
1435
+ captureVideo: ot === "true" ? !0 : void 0,
1436
+ hideThumbs: nt === "true" ? !0 : void 0,
1437
+ hideDismiss: st === "true" ? !0 : void 0,
1113
1438
  videoOptions: B ? {
1114
1439
  maxDuration: parseInt(B, 10)
1115
1440
  } : void 0
@@ -1117,18 +1442,18 @@ function jt(e) {
1117
1442
  }
1118
1443
  if (typeof document < "u") {
1119
1444
  const e = () => {
1120
- const t = document.currentScript, i = Wt(), o = t ? jt(t) : null, n = i ?? o;
1121
- n?.endpoint && new Xt(n);
1445
+ const t = document.currentScript, i = pe(), o = t ? me(t) : null, n = i ?? o;
1446
+ n?.endpoint && new ue(n);
1122
1447
  };
1123
1448
  document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", e) : e();
1124
1449
  }
1125
1450
  export {
1126
- Xt as QaidFeedback,
1127
- _t as captureDomScreenshot,
1128
- Mt as captureNetworkErrors,
1129
- zt as createVideoRecorder,
1130
- Rt as getSupportedMimeType,
1131
- Kt as isDomScreenshotSupported,
1132
- Bt as isVideoRecordingSupported
1451
+ ue as QaidFeedback,
1452
+ ce as captureDomScreenshot,
1453
+ te as captureNetworkErrors,
1454
+ oe as createVideoRecorder,
1455
+ ie as getSupportedMimeType,
1456
+ fe as isDomScreenshotSupported,
1457
+ ee as isVideoRecordingSupported
1133
1458
  };
1134
1459
  //# sourceMappingURL=qaid.js.map