@qaiddev/thumbs-embed 1.0.17 → 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-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)}", 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 bt(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 gt(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 = gt(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
119
  }
120
- function xt(e) {
121
- const t = bt(e), i = U(e);
122
- return { selector: wt(e), text: t, dataAttr: i };
120
+ function L(e) {
121
+ const t = xt(e), i = Y(e);
122
+ return { selector: St(e), text: t, dataAttr: i };
123
123
  }
124
- const X = {
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
+ };
320
+ }
321
+ function $t() {
322
+ return G(document);
323
+ }
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;
536
+ let o = null, n = null, s = [], a = null, c = null, l = null, r = 0, d = null, p = null, u = !1, m = null;
297
537
  function g() {
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;
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 = (b) => {
324
- b.data.size > 0 && s.push(b.data);
563
+ }), n.ondataavailable = (h) => {
564
+ h.data.size > 0 && s.push(h.data);
325
565
  }, n.onstop = () => {
326
- const b = new Blob(s, { type: m });
327
- d && d(b), c && c(b), 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 b = Math.floor((Date.now() - r) / 1e3);
332
- a && a(b);
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(), g();
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 g = p.getContext("2d");
398
- return g ? (g.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,25 +937,31 @@ 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
966
  }), this.buttonsContainer.insertBefore(this.dismissBtn, this.buttonsContainer.firstChild), this._startDismissed && this.buttonsContainer.classList.add("qaid-dismissed"));
681
967
  }
@@ -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,10 +996,16 @@ class Xt {
710
996
  this.tooltipElement.classList.remove("qaid-tooltip-visible");
711
997
  }
712
998
  handleDismiss() {
713
- this.buttonsContainer.classList.add("qaid-dismissed"), F(this.config.apiKey, !0);
999
+ this.buttonsContainer.classList.add("qaid-dismissed"), W(this.config.apiKey, !0);
714
1000
  }
715
1001
  handleThumbClick(t, i, o) {
716
- this.buttonsContainer?.classList.contains("qaid-incognito") && (this.buttonsContainer.classList.remove("qaid-incognito"), 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
+ }
717
1009
  }
718
1010
  submitDirectFeedback(t, i) {
719
1011
  this.feedbackData.feedbackType = t, this.feedbackData.elementSelector = null, this.feedbackData.elementText = null;
@@ -731,6 +1023,36 @@ class Xt {
731
1023
  startTargeting(t, i) {
732
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);
733
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
+ }
734
1056
  createTargetingOverlay() {
735
1057
  const t = this.ensureOverlayHost();
736
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";
@@ -746,12 +1068,12 @@ class Xt {
746
1068
  }
747
1069
  handleMouseMove(t) {
748
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) {
749
- const i = [this.shadowHost, this.overlayShadowHost].filter(Boolean), o = A(
1071
+ const i = [this.shadowHost, this.overlayShadowHost].filter(Boolean), o = F(
750
1072
  t.clientX,
751
1073
  t.clientY,
752
1074
  i
753
1075
  );
754
- if (o && !$(o)) {
1076
+ if (o && !I(o)) {
755
1077
  if (this.highlightBox) {
756
1078
  const n = o.getBoundingClientRect();
757
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";
@@ -762,25 +1084,25 @@ class Xt {
762
1084
  }
763
1085
  handleClick(t) {
764
1086
  t.preventDefault(), t.stopPropagation();
765
- const i = [this.shadowHost, this.overlayShadowHost].filter(Boolean), o = A(
1087
+ const i = [this.shadowHost, this.overlayShadowHost].filter(Boolean), o = F(
766
1088
  t.clientX,
767
1089
  t.clientY,
768
1090
  i
769
1091
  );
770
- if (!o || $(o))
1092
+ if (!o || I(o))
771
1093
  return;
772
- const n = Ot(o, 8);
1094
+ const n = _(o, 8);
773
1095
  this.selectedBounds = {
774
1096
  ...n,
775
1097
  clickX: t.clientX,
776
1098
  clickY: t.clientY,
777
1099
  visible: !0
778
1100
  };
779
- const { selector: s, text: a } = xt(o);
780
- 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();
781
1103
  }
782
1104
  cancelTargeting() {
783
- 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;
784
1106
  }
785
1107
  removeTargetingOverlay() {
786
1108
  this.overlayContainer && (this.overlayContainer.remove(), this.overlayContainer = null), this.captureLayer = null, this.crosshairH = null, this.crosshairV = null, this.scope = null;
@@ -794,7 +1116,7 @@ class Xt {
794
1116
  }
795
1117
  async submitFeedback() {
796
1118
  let t = null;
797
- 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"));
798
1120
  const i = this.feedbackData.elementSelector ? {
799
1121
  x: this.selectedBounds.x,
800
1122
  y: this.selectedBounds.y,
@@ -827,10 +1149,10 @@ class Xt {
827
1149
  });
828
1150
  if (n.ok) {
829
1151
  const s = await n.json();
830
- this.feedbackId = s.id;
1152
+ this.feedbackId = s.id, this.announceMsg("Feedback sent");
831
1153
  }
832
1154
  } catch (n) {
833
- console.error("Failed to submit feedback:", n);
1155
+ console.error("Failed to submit feedback:", n), this.announceMsg("Failed to send feedback", !0);
834
1156
  }
835
1157
  this.state = "MODAL_OPEN", this.showModal(), this.overlayShadowHost && (this.overlayShadowHost.style.pointerEvents = "auto");
836
1158
  }
@@ -848,7 +1170,7 @@ class Xt {
848
1170
  `, this.applyVars(i), t.appendChild(i), this.modalContainer = i, this.setupModalInteractions();
849
1171
  }
850
1172
  showPositionedModal() {
851
- const t = this.ensureOverlayHost(), { modal: i, arrow: o } = Tt(
1173
+ const t = this.ensureOverlayHost(), { modal: i, arrow: o } = Yt(
852
1174
  this.selectedBounds,
853
1175
  window.innerWidth,
854
1176
  window.innerHeight,
@@ -870,21 +1192,25 @@ class Xt {
870
1192
  const t = this.feedbackData.feedbackType === "up", i = this.config.positiveIcon || E, o = this.config.negativeIcon || T;
871
1193
  return `
872
1194
  <div class="qaid-modal-header">
873
- <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"}">
874
1196
  ${t ? i : o}
875
1197
  </button>
876
1198
  <div class="qaid-modal-header-text">
877
- <h3 class="qaid-modal-title">${this.config.text.modalTitle}</h3>
878
- <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>
879
1201
  </div>
880
1202
  </div>
881
- <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>
882
1204
  <div class="qaid-btn-row">
883
1205
  <button type="button" class="qaid-btn-submit">${this.config.text.skipButton}</button>
884
1206
  </div>
885
1207
  `;
886
1208
  }
887
1209
  setupModalInteractions() {
1210
+ this.openDialogA11y(this.modalContainer, {
1211
+ labelledbyId: `qaid-modal-title-${this.uid}`,
1212
+ describedbyId: `qaid-modal-subtitle-${this.uid}`
1213
+ });
888
1214
  const t = this.modalContainer.querySelector(".qaid-textarea"), i = this.modalContainer.querySelector(".qaid-btn-submit");
889
1215
  t && (setTimeout(() => t.focus(), 100), t.addEventListener("input", () => {
890
1216
  i && (i.textContent = t.value.trim() ? this.config.text.submitButton : this.config.text.skipButton);
@@ -897,11 +1223,13 @@ class Xt {
897
1223
  const n = this.feedbackData.feedbackType === "up" ? "down" : "up";
898
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"));
899
1225
  const s = this.config.positiveIcon || E, a = this.config.negativeIcon || T;
900
- 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}`, {
901
1229
  method: "PATCH",
902
1230
  headers: { "Content-Type": "application/json" },
903
1231
  body: JSON.stringify({ feedbackType: n })
904
- }).catch((c) => console.error("Failed to update feedback type:", c));
1232
+ }).catch((l) => console.error("Failed to update feedback type:", l));
905
1233
  });
906
1234
  }
907
1235
  async submitMessage(t) {
@@ -924,19 +1252,19 @@ class Xt {
924
1252
  method: "PATCH",
925
1253
  headers: { "Content-Type": "application/json" },
926
1254
  body: JSON.stringify({ message: null })
927
- }).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;
928
1256
  }
929
1257
  // ==================== Video Recording ====================
930
1258
  async startRecording() {
931
1259
  if (!(this.isRecording || this.state !== "IDLE"))
932
1260
  try {
933
- this.networkCapture = Mt(), this.videoRecorder = zt({
1261
+ this.networkCapture = te(), this.videoRecorder = oe({
934
1262
  maxDuration: this.config.videoOptions.maxDuration
935
1263
  }), this.videoRecorder.onTick((t) => {
936
1264
  this.updateRecordingTimer(t);
937
1265
  }), this.videoRecorder.onStop((t) => {
938
- 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());
939
- }), 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);
940
1268
  } catch {
941
1269
  this.cleanupRecording();
942
1270
  }
@@ -947,7 +1275,7 @@ class Xt {
947
1275
  } catch {
948
1276
  this.recordedBlob = null;
949
1277
  }
950
- 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();
951
1279
  }
952
1280
  showRecordingIndicator() {
953
1281
  const t = this.ensureOverlayHost();
@@ -964,7 +1292,7 @@ class Xt {
964
1292
  const i = this.recordingIndicator.querySelector(".qaid-recording-time");
965
1293
  if (i) {
966
1294
  const o = Math.max(0, this.config.videoOptions.maxDuration - t);
967
- i.textContent = this.formatTime(o);
1295
+ i.textContent = this.formatTime(o), o > 0 && o <= 5 && this.announceMsg(`${o} second${o === 1 ? "" : "s"} remaining`);
968
1296
  }
969
1297
  }
970
1298
  formatTime(t) {
@@ -980,11 +1308,11 @@ class Xt {
980
1308
  const o = document.createElement("div");
981
1309
  o.className = "qaid-video-preview-box";
982
1310
  const n = document.createElement("h3");
983
- n.textContent = "Review your recording";
1311
+ n.textContent = "Review your recording", n.id = `qaid-video-title-${this.uid}`;
984
1312
  const s = document.createElement("video");
985
1313
  s.src = i, s.controls = !0, s.autoplay = !0, s.muted = !0;
986
1314
  const a = document.createElement("textarea");
987
- 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");
988
1316
  const c = document.createElement("div");
989
1317
  c.className = "qaid-video-preview-actions";
990
1318
  const l = document.createElement("button");
@@ -995,15 +1323,15 @@ class Xt {
995
1323
  });
996
1324
  const d = document.createElement("button");
997
1325
  d.type = "button", d.className = "qaid-video-btn qaid-video-btn-send", d.textContent = "Send", d.addEventListener("click", () => {
998
- const h = a.value.trim() || null;
999
- this.submitVideoFeedback(h, d);
1000
- }), 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);
1001
1329
  }
1002
1330
  cancelRecordingPreview() {
1003
1331
  this.removeVideoPreview(), this.cleanupRecording();
1004
1332
  }
1005
1333
  removeVideoPreview() {
1006
- if (this.videoPreview) {
1334
+ if (this.closeDialogA11y(), this.videoPreview) {
1007
1335
  const t = this.videoPreview.querySelector("video");
1008
1336
  t?.src && URL.revokeObjectURL(t.src), this.videoPreview.remove(), this.videoPreview = null;
1009
1337
  }
@@ -1019,9 +1347,9 @@ class Xt {
1019
1347
  method: "POST",
1020
1348
  body: o
1021
1349
  });
1022
- 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));
1023
1351
  } catch (n) {
1024
- console.error("Failed to submit video feedback:", n);
1352
+ console.error("Failed to submit video feedback:", n), this.announceMsg("Failed to send recording", !0);
1025
1353
  }
1026
1354
  this.isSendingVideo = !1, this.removeVideoPreview(), this.cleanupRecording();
1027
1355
  }
@@ -1038,13 +1366,13 @@ class Xt {
1038
1366
  * Destroy the embed and clean up all resources
1039
1367
  */
1040
1368
  destroy() {
1041
- 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();
1042
1370
  }
1043
1371
  }
1044
- function W(e) {
1372
+ function Z(e) {
1045
1373
  return document.querySelector(e)?.textContent?.trim() ?? "";
1046
1374
  }
1047
- function Wt() {
1375
+ function pe() {
1048
1376
  const e = document.querySelector(
1049
1377
  'script[type="application/json"][data-feedback-config]'
1050
1378
  );
@@ -1053,20 +1381,20 @@ function Wt() {
1053
1381
  if (!t) return null;
1054
1382
  try {
1055
1383
  const i = JSON.parse(t);
1056
- 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;
1057
1385
  } catch {
1058
1386
  return null;
1059
1387
  }
1060
1388
  }
1061
- function jt(e) {
1389
+ function me(e) {
1062
1390
  const t = e.getAttribute("data-endpoint");
1063
1391
  if (!t) return null;
1064
- 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"), g = e.getAttribute("data-modal-width"), f = e.getAttribute("data-backdrop-opacity"), m = e.getAttribute("data-font-family"), v = e.getAttribute("data-font-size"), b = 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");
1065
1393
  return {
1066
1394
  endpoint: t,
1067
- css: R ? W(R) : void 0,
1068
- apiKey: Y ?? void 0,
1069
- 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,
1070
1398
  screenshotOptions: k || C || S ? {
1071
1399
  quality: k ? parseFloat(k) : void 0,
1072
1400
  maxWidth: C ? parseInt(C, 10) : void 0,
@@ -1074,39 +1402,39 @@ function jt(e) {
1074
1402
  } : void 0,
1075
1403
  container: c ?? void 0,
1076
1404
  buttonClass: l ?? void 0,
1077
- direction: et ?? void 0,
1405
+ direction: rt ?? void 0,
1078
1406
  position: i ?? void 0,
1079
1407
  zIndex: o ? parseInt(o, 10) : void 0,
1080
1408
  skipTargeting: r === "true" ? !0 : void 0,
1081
1409
  incognito: d === "true" ? !0 : void 0,
1082
- buttonSize: h ?? void 0,
1083
- offset: u || p ? {
1410
+ buttonSize: p ?? void 0,
1411
+ offset: u || m ? {
1084
1412
  x: u ? parseInt(u, 10) : void 0,
1085
- y: p ? parseInt(p, 10) : void 0
1413
+ y: m ? parseInt(m, 10) : void 0
1086
1414
  } : void 0,
1087
1415
  modalWidth: g ? parseInt(g, 10) : void 0,
1088
- backdropOpacity: f ? parseFloat(f) : void 0,
1089
- fontFamily: m ?? void 0,
1416
+ backdropOpacity: b ? parseFloat(b) : void 0,
1417
+ fontFamily: f ?? void 0,
1090
1418
  fontSize: v ? parseInt(v, 10) : void 0,
1091
1419
  colors: {
1092
1420
  positive: n ?? void 0,
1093
1421
  negative: s ?? void 0,
1094
1422
  marker: a ?? void 0
1095
1423
  },
1096
- text: b || x || L || D || H || M ? {
1097
- tooltip: b ?? void 0,
1098
- modalTitle: x ?? void 0,
1099
- modalSubtitle: L ?? void 0,
1100
- placeholder: D ?? void 0,
1101
- submitButton: H ?? void 0,
1102
- 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
1103
1431
  } : void 0,
1104
- positiveIcon: j ?? void 0,
1105
- negativeIcon: K ?? void 0,
1106
- screenshotMethod: tt ?? void 0,
1107
- captureVideo: G === "true" ? !0 : void 0,
1108
- hideThumbs: Z === "true" ? !0 : void 0,
1109
- 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,
1110
1438
  videoOptions: B ? {
1111
1439
  maxDuration: parseInt(B, 10)
1112
1440
  } : void 0
@@ -1114,18 +1442,18 @@ function jt(e) {
1114
1442
  }
1115
1443
  if (typeof document < "u") {
1116
1444
  const e = () => {
1117
- const t = document.currentScript, i = Wt(), o = t ? jt(t) : null, n = i ?? o;
1118
- 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);
1119
1447
  };
1120
1448
  document.readyState === "loading" ? document.addEventListener("DOMContentLoaded", e) : e();
1121
1449
  }
1122
1450
  export {
1123
- Xt as QaidFeedback,
1124
- _t as captureDomScreenshot,
1125
- Mt as captureNetworkErrors,
1126
- zt as createVideoRecorder,
1127
- Rt as getSupportedMimeType,
1128
- Kt as isDomScreenshotSupported,
1129
- 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
1130
1458
  };
1131
1459
  //# sourceMappingURL=qaid.js.map