whipdesk 0.1.2 → 0.1.3

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.
@@ -18,8 +18,8 @@
18
18
  <meta name="apple-mobile-web-app-title" content="WhipDesk" />
19
19
  <meta name="mobile-web-app-capable" content="yes" />
20
20
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
21
- <script type="module" crossorigin src="./assets/index-_PAhuG6R.js"></script>
22
- <link rel="stylesheet" crossorigin href="./assets/index-C_O8Rc7r.css">
21
+ <script type="module" crossorigin src="./assets/index-D-eJUnpy.js"></script>
22
+ <link rel="stylesheet" crossorigin href="./assets/index-CaqF5am7.css">
23
23
  </head>
24
24
  <body>
25
25
  <div id="app"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "whipdesk",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "WhipDesk desktop host: screen capture, input injection, notification hub, and the HTTP/WebSocket server that serves the mobile client.",
6
6
  "license": "AGPL-3.0",
@@ -1 +0,0 @@
1
- :root{--bg:#f4f6f9;--panel:#fff;--panel-2:#eef1f5;--border:#d6dce4;--text:#1a2330;--muted:#5f6b7a;--accent:#2f6fed;--accent-2:#1aa66b;--warn:#c77700;--error:#d83b3b;--shadow:#141e3229;--screen-bg:#1b2027}@media (prefers-color-scheme:dark){:root{--bg:#0b0e14;--panel:#151a23;--panel-2:#1d2430;--border:#2a3342;--text:#e6edf3;--muted:#8b98a9;--accent:#4ea1ff;--accent-2:#36d399;--warn:#f5a623;--error:#ff5c5c;--shadow:#00000080;--screen-bg:#000}}*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}html,body{background:var(--bg);height:100%;color:var(--text);overscroll-behavior:none;margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,system-ui,sans-serif;overflow:hidden}#app{-webkit-user-select:none;user-select:none;position:fixed;inset:0}input,textarea{-webkit-user-select:text;user-select:text}.wd-screen{background:var(--screen-bg);touch-action:none;width:100%;height:100%;display:block;position:absolute;inset:0}.wd-statusbar{top:calc(env(safe-area-inset-top,0px) + 8px);background:var(--panel);border:1px solid var(--border);max-width:calc(100% - 64px);min-height:38px;box-shadow:0 2px 10px var(--shadow);z-index:5;cursor:pointer;border-radius:10px;align-items:center;gap:8px;padding:6px 10px;font-size:12px;transition:max-width .25s,padding .25s;display:flex;position:absolute;left:8px}.wd-statusbar.collapsed{max-width:124px;padding:6px 8px;overflow:hidden}.wd-statusbar.collapsed .wd-status-text,.wd-statusbar.collapsed .wd-watchers{display:none}.wd-dot{background:var(--muted);border-radius:50%;flex:none;width:9px;height:9px}.wd-dot[data-status=connected]{background:var(--accent-2)}.wd-dot[data-status=connecting]{background:var(--warn)}.wd-dot[data-status=disconnected]{background:var(--error)}.wd-status-text{color:var(--text);white-space:nowrap;text-overflow:ellipsis;flex:auto;min-width:0;font-weight:600;overflow:hidden}.wd-watchers{color:var(--warn);white-space:nowrap;flex:none;font-weight:700}.wd-transport{letter-spacing:.4px;color:#fff;background:var(--accent-2);text-transform:uppercase;border-radius:6px;flex:none;padding:2px 6px;font-size:11px;font-weight:800}.wd-transport.hidden{display:none}.wd-transport[data-kind=turn]{color:#111;background:#e0a800}.wd-transport[data-kind=stun],.wd-transport[data-kind=direct]{background:var(--accent-2)}.wd-transport[data-kind=lan]{background:#3b82f6}.wd-bell{top:calc(env(safe-area-inset-top,0px) + 8px);z-index:6;border:1px solid var(--border);background:var(--panel);min-width:38px;min-height:38px;color:var(--text);box-shadow:0 2px 10px var(--shadow);cursor:pointer;border-radius:10px;place-items:center;padding:6px;display:grid;position:absolute;right:8px}.wd-badge{background:var(--accent);color:#fff;text-align:center;min-width:18px;height:18px;box-shadow:0 1px 4px var(--shadow);border-radius:9px;padding:0 5px;font-size:11px;font-weight:700;line-height:18px;position:absolute;top:-6px;right:-6px}.wd-ribbon{z-index:6;padding-bottom:env(safe-area-inset-bottom,0px);background:var(--panel);border-top:1px solid var(--border);box-shadow:0 -4px 16px var(--shadow);position:absolute;bottom:0;left:0;right:0}.wd-panel{flex-direction:column;display:flex}.wd-options{border-bottom:1px solid var(--border);padding:6px}.wd-pane{flex-wrap:wrap;justify-content:center;align-items:center;gap:5px;display:flex}.wd-pane-col{flex-direction:column;align-items:stretch;gap:8px}.wd-pane-single-row{scrollbar-width:none;flex-wrap:nowrap;justify-content:center;align-items:stretch;gap:4px;overflow-x:auto}.wd-pane-single-row::-webkit-scrollbar{display:none}.wd-pane-single-row .wd-group{flex:0 auto;gap:2px;min-width:0;padding:3px 4px}.wd-pane-single-row .wd-group-items{flex-wrap:nowrap;gap:3px}.wd-pane-single-row .wd-btn{min-width:0}.wd-pane-single-row .wd-btn.wd-icon-only{min-width:30px;padding:4px}.wd-pane-single-row .wd-btn.wd-icon-only svg{width:18px;height:18px}.wd-pane-single-row .wd-btn.wd-go{gap:4px;padding:6px 9px;font-size:12px}@media (min-width:390px){.wd-pane-single-row{gap:5px}.wd-pane-single-row .wd-group{padding:3px 6px}.wd-pane-single-row .wd-btn.wd-icon-only{min-width:36px;padding:5px}.wd-pane-single-row .wd-btn.wd-icon-only svg{width:20px;height:20px}.wd-pane-single-row .wd-btn.wd-go{padding:7px 12px;font-size:13px}}@media (min-width:560px){.wd-pane-single-row .wd-btn.wd-icon-only{min-width:42px;padding:6px}.wd-pane-single-row .wd-btn.wd-go{padding:8px 16px}}@media (min-width:820px){.wd-ribbon{border:1px solid var(--border);width:min(880px,94vw);box-shadow:0 10px 34px var(--shadow);border-radius:16px;padding-bottom:0;bottom:16px;left:50%;right:auto;transform:translate(-50%)}.wd-options{padding:5px 6px}.wd-btn{min-height:32px;font-size:12px}.wd-pane-single-row .wd-btn.wd-icon-only{min-width:32px;padding:4px}.wd-pane-single-row .wd-btn.wd-icon-only svg{width:17px;height:17px}.wd-pane-single-row .wd-btn.wd-go{padding:6px 12px;font-size:12px}.wd-group{padding:3px 6px}.wd-bell{min-width:32px;min-height:32px}.wd-statusbar{min-height:32px}}.wd-group{border:1px solid var(--border);background:var(--panel-2);border-radius:12px;flex-direction:column;align-items:stretch;gap:3px;padding:4px 6px;display:inline-flex}.wd-group-label{letter-spacing:.03em;text-transform:uppercase;color:var(--muted);white-space:nowrap;text-align:center;font-size:9px;font-weight:700}.wd-group-head{justify-content:space-between;align-items:center;gap:4px;display:flex}.wd-mode-toggle{border:1px solid var(--border);background:var(--panel);border-radius:999px;display:inline-flex;overflow:hidden}.wd-mode-btn{color:var(--muted);cursor:pointer;background:0 0;border:0;padding:4px 7px;font-size:10px;font-weight:700;line-height:1}.wd-mode-btn.on{background:var(--accent);color:#fff}.wd-group-items{flex-wrap:wrap;justify-content:center;align-items:center;gap:3px;display:flex}.wd-wrap{flex-wrap:wrap;justify-content:center;gap:6px;display:flex}.wd-btn-label{line-height:1}.wd-row{flex-wrap:wrap;justify-content:center;align-items:center;gap:6px;display:flex}.wd-tabs{align-items:center;gap:4px;padding:5px 6px;display:flex}.wd-tab{min-height:48px;color:var(--muted);cursor:pointer;touch-action:manipulation;background:0 0;border:1px solid #0000;border-radius:10px;flex-direction:column;flex:1;align-items:center;gap:2px;padding:6px 4px;font-size:11px;font-weight:600;display:flex}.wd-tab .wd-tab-label{line-height:1}.wd-tab.on{background:var(--panel-2);color:var(--accent);border-color:var(--border)}.wd-collapse{border:1px solid var(--border);background:var(--panel);min-width:44px;min-height:48px;color:var(--text);cursor:pointer;border-radius:10px;flex:none;place-items:center;display:grid}.wd-btn{border:1px solid var(--border);background:var(--panel);min-width:40px;min-height:40px;color:var(--text);cursor:pointer;-webkit-user-select:none;user-select:none;touch-action:manipulation;white-space:nowrap;border-radius:10px;justify-content:center;align-items:center;gap:7px;padding:6px 10px;font-size:13px;font-weight:600;line-height:1;display:inline-flex}.wd-btn svg{flex:none}.wd-btn.wd-icon-only{min-width:40px;padding:6px}.wd-btn:active{background:var(--panel-2);transform:translateY(1px)}.wd-btn.on{border-color:var(--accent);color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}.wd-btn.wd-primary{background:var(--accent);border-color:var(--accent);color:#fff}.wd-btn.wd-go{background:var(--accent-2);border-color:var(--accent-2);color:#fff;padding:8px 14px}.wd-btn.wd-go:active{filter:brightness(.92);transform:translateY(1px)}.wd-seg{border:1px solid var(--border);border-radius:10px;display:inline-flex;overflow:hidden}.wd-seg-btn{background:var(--panel);min-height:44px;color:var(--muted);cursor:pointer;touch-action:manipulation;border:none;align-items:center;gap:6px;padding:8px 18px;font-size:15px;font-weight:600;display:inline-flex}.wd-seg-btn.on{background:var(--accent);color:#fff}.wd-zoom{text-align:center;font-variant-numeric:tabular-nums;min-width:52px;color:var(--text);font-weight:600}.wd-hint{text-align:center;color:var(--muted);flex-basis:100%;font-size:12px}.wd-type-input{resize:vertical;border:1px solid var(--border);background:var(--panel-2);width:100%;min-height:46px;color:var(--text);border-radius:10px;padding:10px;font-family:inherit;font-size:16px}.wd-keys-row{flex-wrap:wrap;justify-content:center;gap:6px;display:flex}.wd-type-actions{gap:6px;display:flex}.wd-type-actions .wd-btn{flex:1}.wd-monitor-list{flex-wrap:wrap;justify-content:center;gap:6px;display:flex}.wd-toasts{top:calc(env(safe-area-inset-top,0px) + 36px);z-index:9;pointer-events:none;flex-direction:column;gap:8px;display:flex;position:absolute;left:8px;right:8px}.wd-toast{background:var(--panel);border:1px solid var(--border);border-left-width:4px;border-radius:10px;flex-direction:column;gap:2px;padding:10px 12px;transition:opacity .3s,transform .3s;display:flex;box-shadow:0 6px 20px #0006}.wd-toast strong{font-size:14px}.wd-toast span{color:var(--muted);font-size:13px}.wd-toast.wd-success{border-left-color:var(--accent-2)}.wd-toast.wd-warning{border-left-color:var(--warn)}.wd-toast.wd-error{border-left-color:var(--error)}.wd-toast.wd-info{border-left-color:var(--accent)}.wd-toast.wd-hide{opacity:0;transform:translateY(-8px)}.hidden{display:none!important}.wd-sharpen{pointer-events:none;z-index:15;border:2.5px solid #ebf0f840;border-top-color:#ebf0f8e6;border-radius:50%;width:22px;height:22px;margin:-11px 0 0 -11px;animation:.9s linear infinite wd-sharpen-spin;position:fixed;top:50%;left:50%;box-shadow:0 0 0 4px #06090e59}@keyframes wd-sharpen-spin{to{transform:rotate(360deg)}}.wd-pin-overlay{z-index:20;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#06090eeb;place-items:center;padding:20px;display:grid;position:absolute;inset:0}.wd-pin-card{background:var(--panel);border:1px solid var(--border);text-align:center;border-radius:14px;width:100%;max-width:320px;padding:24px}.wd-pin-whip{object-fit:contain;width:64px;height:64px;margin:0 auto 12px;display:block}.wd-pin-card h2{margin:0 0 8px;font-size:20px}.wd-pin-msg{color:var(--muted);margin:0 0 16px;font-size:14px}.wd-pin-msg.err{color:var(--error)}.wd-pin-input{border:1px solid var(--border);background:var(--panel-2);width:100%;color:var(--text);text-align:center;letter-spacing:6px;border-radius:10px;margin-bottom:14px;padding:14px;font-size:22px}.wd-pin-submit{background:var(--accent);color:#fff;cursor:pointer;touch-action:manipulation;border:none;border-radius:12px;width:100%;min-height:50px;font-size:17px;font-weight:700}.wd-pin-submit:active{filter:brightness(.92);transform:translateY(1px)}.wd-pin-back{color:var(--muted);cursor:pointer;background:0 0;border:none;margin:14px auto 0;padding:6px 10px;font-size:13px;font-weight:600;display:block}.wd-pin-back:active{color:var(--text)}.wd-connecting{z-index:18;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);background:#000000f5;place-items:center;padding:20px;display:grid;position:absolute;inset:0}.wd-connecting-card{text-align:center;width:100%;max-width:320px}.wd-connecting-anim{background:#000;border-radius:10px;width:180px;height:auto;margin:0 auto 16px;display:block}.wd-connecting-msg{color:#eef2f7;text-shadow:0 1px 2px #00000080;margin:0;font-size:15px;font-weight:600}.wd-dialog-overlay{z-index:18;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);background:#06090e99;place-items:center;padding:16px;display:grid;position:absolute;inset:0}.wd-dialog{background:var(--panel);border:1px solid var(--border);border-radius:14px;width:100%;max-width:380px;padding:16px}.wd-dialog-head{justify-content:space-between;align-items:center;display:flex}.wd-dialog-head h2{margin:0;font-size:18px}.wd-dialog-x{border:1px solid var(--border);background:var(--panel-2);width:36px;height:36px;color:var(--text);cursor:pointer;border-radius:8px;place-items:center;display:grid}.wd-dialog-help{color:var(--muted);margin:8px 0 12px;font-size:13px}.wd-help-intro{margin:0 0 6px}.wd-help-list{flex-direction:column;gap:5px;margin:0 0 8px;padding-left:18px;display:flex}.wd-help-list strong{color:var(--text)}.wd-help-note{margin:0;font-style:italic}.wd-watch-list{flex-direction:column;gap:8px;margin-bottom:12px;display:flex}.wd-watch-row{border:1px solid var(--border);background:var(--panel-2);border-radius:10px;align-items:center;gap:8px;padding:8px 10px;display:flex}.wd-watch-name{text-align:left;color:var(--text);cursor:pointer;background:0 0;border:none;flex:1;padding:4px 0;font-family:inherit;font-size:14px;font-weight:600}.wd-watch-name:active{color:var(--accent)}.wd-timer-info{flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.wd-timer-name{color:var(--text);align-items:center;gap:6px;font-size:14px;font-weight:600;display:flex}.wd-timer-name svg{color:var(--accent);flex:none}.wd-timer-remain{color:var(--muted);font-variant-numeric:tabular-nums;font-size:12px}.wd-timer-tag{letter-spacing:.5px;text-transform:uppercase;color:#fff;background:var(--accent);border-radius:6px;flex:none;padding:2px 6px;font-size:10px;font-weight:800}.wd-dialog-actions{gap:8px;margin-top:4px;display:flex}.wd-dialog-actions .wd-btn{flex:1;justify-content:center}.wd-dialog-actions.wd-actions-stack{flex-direction:column}.wd-actions-stack .wd-btn{width:100%}.wd-mon-state{letter-spacing:.4px;text-transform:uppercase;color:#fff;background:var(--muted);border-radius:6px;flex:none;padding:2px 6px;font-size:10px;font-weight:800}.wd-mon-state[data-state=working]{background:var(--accent-2)}.wd-mon-state[data-state=blocked]{background:var(--warn)}.wd-mon-state[data-state=finished]{background:var(--accent)}.wd-mon-state[data-state=crashed]{background:var(--error)}.wd-mon-pick-head{justify-content:space-between;align-items:center;gap:8px;margin-bottom:6px;display:flex}.wd-mon-pick{flex-direction:column;gap:6px;max-height:40vh;margin-bottom:12px;display:flex;overflow-y:auto}.wd-mon-item{border:1px solid var(--border);background:var(--panel);width:100%;color:var(--text);cursor:pointer;text-align:left;border-radius:10px;justify-content:space-between;align-items:center;gap:10px;padding:9px 11px;display:flex}.wd-mon-item.on{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}.wd-mon-item-main{align-items:center;gap:8px;min-width:0;display:flex}.wd-mon-item-main svg{color:var(--accent);flex:none}.wd-mon-item-title{white-space:nowrap;text-overflow:ellipsis;font-size:13px;font-weight:600;overflow:hidden}.wd-mon-always{flex-direction:column;gap:8px;display:flex}.wd-check{color:var(--text);cursor:pointer;align-items:flex-start;gap:8px;font-size:13px;display:flex}.wd-check input{width:16px;height:16px;accent-color:var(--accent);flex:none;margin-top:1px}.wd-check-text{flex-direction:column;gap:2px;display:flex}.wd-check-sub{color:var(--muted);font-size:11px}.wd-form-row{flex-direction:column;gap:5px;margin-bottom:12px;display:flex}.wd-form-label{color:var(--muted);font-size:12px;font-weight:700}.wd-input{border:1px solid var(--border);background:var(--panel-2);width:100%;color:var(--text);border-radius:10px;padding:10px 12px;font-family:inherit;font-size:15px}.wd-input-area{resize:vertical;min-height:64px}.wd-form-duration{flex-wrap:wrap;align-items:center;gap:12px;display:flex}.wd-input-num{text-align:center;width:56px}.wd-form-unit{color:var(--muted);font-size:14px;font-weight:600}.wd-preset-row{flex-wrap:wrap;gap:6px;margin-bottom:10px;display:flex}.wd-preset{border:1px solid var(--border);background:var(--panel-2);min-width:48px;color:var(--text);cursor:pointer;border-radius:999px;flex:auto;padding:9px 10px;font-family:inherit;font-size:13px;font-weight:700}.wd-preset:active{background:var(--accent);color:#fff;border-color:#0000}.wd-stepper{align-items:center;gap:4px;display:flex}.wd-step-btn{border:1px solid var(--border);background:var(--panel-2);width:38px;height:38px;color:var(--text);cursor:pointer;touch-action:manipulation;border-radius:10px;flex:none;font-family:inherit;font-size:22px;font-weight:700;line-height:1}.wd-step-btn:active{background:var(--accent);color:#fff;border-color:#0000}.wd-form-target{flex-wrap:wrap;align-items:center;gap:10px;display:flex}.wd-form-target-status{color:var(--muted);font-size:13px}.wd-form-target-status.set{color:var(--accent-2);font-weight:700}.wd-pick-banner{top:calc(env(safe-area-inset-top,0px) + 56px);z-index:30;background:var(--accent);color:#fff;box-shadow:0 6px 20px var(--shadow);pointer-events:none;text-align:center;border-radius:999px;max-width:90%;padding:10px 16px;font-size:13px;font-weight:700;position:absolute;left:50%;transform:translate(-50%)}.wd-conn-row{border-bottom:1px solid var(--border);align-items:flex-start;gap:10px;padding:10px 0;display:flex}.wd-conn-label{width:92px;color:var(--muted);flex:none;padding-top:2px;font-size:13px;font-weight:700}.wd-conn-value{color:var(--text);word-break:break-word;flex:1;font-size:15px;font-weight:600}.wd-conn-route{flex-direction:column;flex:1;gap:4px;display:flex}.wd-conn-route .wd-transport{align-self:flex-start;position:static}.wd-conn-desc{color:var(--muted);font-size:12.5px}.wd-conn-status{flex:1;align-items:center;gap:8px;display:flex}.wd-conn-error{border:1px solid var(--error);color:var(--error);word-break:break-word;background:#dc35451f;border-radius:10px;margin-top:12px;padding:9px 11px;font-size:12.5px;font-weight:600}.wd-disconnect{background:var(--error);color:#fff;border-color:#0000;justify-content:center;width:100%;min-height:46px;margin-top:14px;font-size:15px;font-weight:700}.wd-support-link{border:1px solid var(--border);color:var(--muted);cursor:pointer;background:0 0;border-radius:999px;align-self:flex-start;align-items:center;gap:6px;margin-top:8px;padding:5px 12px;font-size:12.5px;font-weight:600;transition:color .15s,border-color .15s;display:inline-flex}.wd-support-link:hover,.wd-support-link:active{color:var(--accent);border-color:var(--accent)}.wd-support-link svg{flex:none;width:14px;height:14px}.wd-conn-feedback{border-top:1px solid var(--border);text-align:center;margin-top:14px;padding-top:12px}.wd-conn-feedback-text{color:var(--muted);margin:0;font-size:12.5px}.wd-conn-feedback-links{justify-content:center;gap:10px;margin-top:9px;display:flex}.wd-conn-feedback-link{border:1px solid var(--border);color:var(--text);background:0 0;border-radius:999px;align-items:center;gap:7px;padding:7px 16px;font-size:13px;font-weight:600;text-decoration:none;transition:color .15s,border-color .15s;display:inline-flex}.wd-conn-feedback-link:hover,.wd-conn-feedback-link:active{color:var(--accent);border-color:var(--accent)}.wd-conn-feedback-link svg{flex:none;width:16px;height:16px}.wd-pin-support{margin-top:16px}.wd-placing .wd-ribbon,.wd-placing .wd-statusbar,.wd-placing .wd-bell{display:none}.wd-place-layer{z-index:40;touch-action:none;background:0 0;position:absolute;inset:0}.wd-place-marker{z-index:41;pointer-events:none;border:2px solid #4ea1ff;border-radius:50%;width:46px;height:46px;position:absolute;transform:translate(-50%,-50%);box-shadow:0 0 0 2px #00000080,0 0 14px #4ea1ffb3}.wd-place-marker:before,.wd-place-marker:after{content:"";background:#4ea1ff;position:absolute}.wd-place-marker:before{width:2px;top:-8px;bottom:-8px;left:50%;transform:translate(-50%)}.wd-place-marker:after{height:2px;top:50%;left:-8px;right:-8px;transform:translateY(-50%)}.wd-place-bar{z-index:42;padding:12px 14px calc(env(safe-area-inset-bottom,0px) + 12px);-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);border-top:1px solid var(--border);background:#0a0e14f0;flex-direction:column;gap:10px;display:flex;position:absolute;bottom:0;left:0;right:0}.wd-place-hint{color:#eef2f7;text-align:center;margin:0;font-size:13px;font-weight:600}.wd-place-text{width:100%}.wd-place-buttons{gap:8px;display:flex}.wd-place-buttons .wd-btn{flex:1;justify-content:center}.wd-perm-row{border:1px solid var(--border);background:var(--panel-2);border-radius:10px;align-items:center;gap:8px;margin-bottom:12px;padding:8px 10px;display:flex}.wd-perm-dot{background:var(--muted);border-radius:50%;flex:none;width:9px;height:9px}.wd-perm-dot[data-state=on]{background:var(--accent-2)}.wd-perm-dot[data-state=warn]{background:var(--warn)}.wd-perm-dot[data-state=off]{background:var(--error)}.wd-perm-text{color:var(--muted);flex:1;font-size:12px}.wd-perm-enable{flex:none;min-width:auto;min-height:32px;padding:4px 12px;font-size:12px}.wd-dialog .wd-go{justify-content:center;width:100%}.wd-selector{z-index:19;border:2px solid var(--accent);touch-action:none;background:#2f6fed24;border-radius:6px;position:absolute;box-shadow:0 0 0 9999px #06090e59}.wd-selector-move{background:var(--accent);color:#fff;cursor:move;touch-action:none;border-radius:8px 0;place-items:center;width:38px;height:38px;display:grid;position:absolute;top:-1px;left:-1px}.wd-selector-handle{background:var(--accent);border:3px solid var(--panel);cursor:nwse-resize;touch-action:none;border-radius:50%;width:28px;height:28px;position:absolute;bottom:-12px;right:-12px}.wd-selector-bar{white-space:nowrap;gap:8px;display:flex;position:absolute;bottom:-56px;left:50%;transform:translate(-50%)}.wd-selector-info{top:calc(env(safe-area-inset-top,0px) + 52px);z-index:20;background:var(--panel);border:1px solid var(--border);border-left:4px solid var(--accent);max-width:430px;box-shadow:0 6px 20px var(--shadow);color:var(--text);text-align:center;pointer-events:none;border-radius:10px;margin:0 auto;padding:8px 12px;font-size:12.5px;line-height:1.35;position:absolute;left:12px;right:12px}
@@ -1,2 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./index.esm-mXKu2C3o.js","./index.esm-B3ZTr43m.js","./index.esm-CmSagqpw.js","./index.esm-wogdVWd2.js","./index.esm-BgjPHsdM.js","./index.esm-Di8jSGaG.js"])))=>i.map(i=>d[i]);
2
- (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();function e(e){return typeof e==`object`&&!!e&&typeof e.type==`string`}var t=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]);function n(e){return new TextEncoder().encode(e)}function r(e){let n=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),r=e.length*8,i=new Uint8Array((e.length+8>>6)+1<<6);i.set(e),i[e.length]=128;let a=new DataView(i.buffer);a.setUint32(i.length-4,r>>>0,!1),a.setUint32(i.length-8,Math.floor(r/4294967296),!1);let o=new Uint32Array(64);for(let e=0;e<i.length;e+=64){for(let t=0;t<16;t++)o[t]=a.getUint32(e+t*4,!1);for(let e=16;e<64;e++){let t=o[e-15],n=o[e-2],r=(t>>>7|t<<25)^(t>>>18|t<<14)^t>>>3,i=(n>>>17|n<<15)^(n>>>19|n<<13)^n>>>10;o[e]=o[e-16]+r+o[e-7]+i>>>0}let[r,i,s,c,l,u,d,f]=n;for(let e=0;e<64;e++){let n=(l>>>6|l<<26)^(l>>>11|l<<21)^(l>>>25|l<<7),a=l&u^~l&d,p=f+n+a+t[e]+o[e]>>>0,m=((r>>>2|r<<30)^(r>>>13|r<<19)^(r>>>22|r<<10))+(r&i^r&s^i&s)>>>0;f=d,d=u,u=l,l=c+p>>>0,c=s,s=i,i=r,r=p+m>>>0}n[0]=n[0]+r>>>0,n[1]=n[1]+i>>>0,n[2]=n[2]+s>>>0,n[3]=n[3]+c>>>0,n[4]=n[4]+l>>>0,n[5]=n[5]+u>>>0,n[6]=n[6]+d>>>0,n[7]=n[7]+f>>>0}let s=new Uint8Array(32);new DataView(s.buffer).setUint32(0,n[0],!1);for(let e=0;e<8;e++)new DataView(s.buffer).setUint32(e*4,n[e],!1);return s}var i=`0123456789abcdef`;function a(e){let t=``;for(let n of e)t+=i[n>>4]+i[n&15];return t}function o(e){return a(r(n(e)))}function s(e,t,n){let r=o(`${t}:${e}`);for(let e=1;e<n;e++)r=o(r);return r}function c(e,t){return o(`${e}:${t}`)}var l=class{token;handlers={status:new Set,welcome:new Set,screenMeta:new Set,screenRegion:new Set,videoTrack:new Set,overviewTrack:new Set,transport:new Set,notification:new Set,presence:new Set,pinRequired:new Set,watchers:new Set,timers:new Set,monitors:new Set,monitorAlways:new Set,monitorSessions:new Set,netStats:new Set,versionMismatch:new Set,error:new Set};sender=()=>{};challenge=null;wrongPin=!1;rememberedPin=null;constructor(e){this.token=e}on(e,t){this.handlers[e].add(t)}emit(e,t){for(let n of this.handlers[e])n(t)}setSender(e){this.sender=e}send(e){try{this.sender(JSON.stringify(e))}catch{}}sendHello(){this.send({type:`hello`,protocol:1,token:this.token,role:`controller`,client:{userAgent:navigator.userAgent}})}submitPin(e){if(this.rememberedPin=e,!this.challenge)return;let{salt:t,iterations:n,nonce:r}=this.challenge,i=s(e,t,n);this.send({type:`auth`,response:c(i,r)})}setVisible(e){this.send({type:`visibility`,visible:e})}handleText(t){let n;try{n=JSON.parse(t)}catch{return}if(!e(n))return;let r=n;switch(r.type){case`welcome`:this.challenge=null,r.protocol!==1&&this.emit(`versionMismatch`,{agentProtocol:r.protocol,clientProtocol:1,agentVersion:r.agent?.version}),this.emit(`welcome`,r),this.emit(`timers`,r.timers??[]),this.emit(`monitors`,r.monitors??[]),this.emit(`monitorAlways`,r.alwaysAgents??[]);break;case`auth-required`:this.challenge={salt:r.salt,iterations:r.iterations,nonce:r.nonce},this.rememberedPin&&!this.wrongPin?this.submitPin(this.rememberedPin):this.emit(`pinRequired`,{attemptsLeft:r.attemptsLeft,retry:this.wrongPin}),this.wrongPin=!1;break;case`screen-meta`:this.emit(`screenMeta`,{screen:r.screen,activeDisplay:r.activeDisplay});break;case`screen-region`:this.emit(`screenRegion`,{x:r.x,y:r.y,w:r.w,h:r.h,active:r.active});break;case`notification`:this.emit(`notification`,r);break;case`presence`:this.emit(`presence`,r.watchers);break;case`watchers`:this.emit(`watchers`,r.regions);break;case`timers`:this.emit(`timers`,r.timers);break;case`monitors`:this.emit(`monitors`,r.monitors);break;case`monitor-always-agents`:this.emit(`monitorAlways`,r.agents);break;case`monitor-sessions`:this.emit(`monitorSessions`,r.sessions);break;case`error`:r.code===`pin`?(this.wrongPin=!0,this.rememberedPin=null):this.emit(`error`,r.message);break;case`pong`:break}}},u=class{url;core;ws=null;pc=null;dc=null;mainXcv=null;overviewXcv=null;reconnectTimer=0;statsTimer=0;closedByUser=!1;constructor(e,t){this.url=e,this.core=new l(t),this.core.setSender(e=>{if(this.dc&&this.dc.readyState===`open`)try{this.dc.send(e)}catch{}})}on(e,t){this.core.on(e,t)}send(e){this.core.send(e)}submitPin(e){this.core.submitPin(e)}setVisible(e){this.core.setVisible(e)}connect(){this.closedByUser=!1,this.open()}close(){this.closedByUser=!0,window.clearTimeout(this.reconnectTimer),this.teardown()}isHealthy(){return!this.closedByUser&&this.dc?.readyState===`open`&&this.pc?.connectionState===`connected`}wake(){this.closedByUser||this.isHealthy()||(window.clearTimeout(this.reconnectTimer),this.reconnectTimer=0,this.open())}teardown(){if(window.clearInterval(this.statsTimer),this.statsTimer=0,this.core.emit(`videoTrack`,null),this.core.emit(`overviewTrack`,null),this.dc){this.dc.onopen=this.dc.onclose=this.dc.onmessage=null;try{this.dc.close()}catch{}this.dc=null}if(this.pc){this.pc.onconnectionstatechange=null,this.pc.ontrack=null,this.pc.onicecandidate=null;try{this.pc.close()}catch{}this.pc=null}if(this.ws){this.ws.onopen=this.ws.onclose=this.ws.onmessage=this.ws.onerror=null;try{this.ws.close()}catch{}this.ws=null}this.mainXcv=null,this.overviewXcv=null}scheduleReconnect(){this.closedByUser||(window.clearTimeout(this.reconnectTimer),this.reconnectTimer=window.setTimeout(()=>this.open(),1500))}open(){this.core.emit(`status`,`connecting`),this.teardown();let e=new WebSocket(this.url);this.ws=e;let t=t=>{if(e.readyState===WebSocket.OPEN)try{e.send(JSON.stringify(t))}catch{}},n=new RTCPeerConnection({iceServers:[]});this.pc=n;let r=n.createDataChannel(`whipdesk`);r.binaryType=`arraybuffer`,this.dc=r,r.onopen=()=>{this.core.sendHello(),this.core.emit(`status`,`connected`),this.core.emit(`transport`,`LAN`),this.startStatsPoll(n)},r.onclose=()=>this.core.emit(`status`,`disconnected`),r.onmessage=e=>{typeof e.data==`string`&&this.core.handleText(e.data)};try{this.mainXcv=n.addTransceiver(`video`,{direction:`recvonly`}),this.overviewXcv=n.addTransceiver(`video`,{direction:`recvonly`})}catch{}n.ontrack=e=>{let t=e.streams[0]??new MediaStream([e.track]);this.overviewXcv&&e.transceiver===this.overviewXcv?this.core.emit(`overviewTrack`,t):this.core.emit(`videoTrack`,t)},n.onicecandidate=e=>{e.candidate&&t({kind:`candidate`,candidate:e.candidate.toJSON()})},n.onconnectionstatechange=()=>{let e=n.connectionState;(e===`failed`||e===`disconnected`||e===`closed`)&&(this.core.emit(`status`,`disconnected`),this.scheduleReconnect())};let i=!1;e.onopen=async()=>{try{let e=await n.createOffer();await n.setLocalDescription(e),t({kind:`offer`,sdp:n.localDescription?.sdp??``})}catch{}},e.onmessage=e=>{let t;try{t=JSON.parse(typeof e.data==`string`?e.data:``)}catch{return}if(t.kind===`answer`&&t.sdp&&!i)i=!0,n.setRemoteDescription({type:`answer`,sdp:t.sdp});else if(t.kind===`candidate`&&t.candidate)try{n.addIceCandidate(t.candidate)}catch{}else t.kind===`error`&&this.core.emit(`error`,String(t.message??`host error`))},e.onclose=()=>{this.core.emit(`status`,`disconnected`),this.scheduleReconnect()},e.onerror=()=>{}}startStatsPoll(e){window.clearInterval(this.statsTimer),this.statsTimer=window.setInterval(async()=>{let t=null,n=0;try{(await e.getStats()).forEach(e=>{e.type===`inbound-rtp`&&e.kind===`video`?n=Math.max(n,Number(e.framesPerSecond??0)):e.type===`candidate-pair`&&e.nominated&&typeof e.currentRoundTripTime==`number`&&(t=e.currentRoundTripTime)})}catch{return}this.core.emit(`netStats`,{fps:Math.round(n),rtt:t==null?null:Math.round(t*1e3)})},1e3)}},d=``+new URL(`loading-whip-anim-DmlnYIJ-.gif`,import.meta.url).href,f=[`Rounding up your AI agents…`,`Connecting to your agent farm…`,`Uncoiling the whip…`,`Negotiating the fastest route…`,`Tightening the leash…`,`Almost in the saddle…`],p=class{overlay;msg;rotateTimer=0;msgIndex=0;constructor(e){this.overlay=document.createElement(`div`),this.overlay.className=`wd-connecting hidden`;let t=document.createElement(`div`);t.className=`wd-connecting-card`;let n=document.createElement(`img`);n.className=`wd-connecting-anim`,n.src=d,n.alt=`WhipDesk`,n.decoding=`async`,this.msg=document.createElement(`p`),this.msg.className=`wd-connecting-msg`,this.msg.textContent=f[0],t.append(n,this.msg),this.overlay.appendChild(t),e.appendChild(this.overlay)}show(e){this.msg.textContent=e??f[this.msgIndex],this.overlay.classList.contains(`hidden`)&&(this.overlay.classList.remove(`hidden`),!e&&(this.rotateTimer=window.setInterval(()=>{this.msgIndex=(this.msgIndex+1)%f.length,this.msg.textContent=f[this.msgIndex]},2200)))}hide(){this.overlay.classList.add(`hidden`),window.clearInterval(this.rotateTimer),this.rotateTimer=0}},m={eye:`<path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z"/><circle cx="12" cy="12" r="3"/>`,mouse:`<rect x="6" y="3" width="12" height="18" rx="6"/><path d="M12 7v4"/>`,keyboard:`<rect x="2" y="6" width="20" height="12" rx="2"/><path d="M6 10h.01M10 10h.01M14 10h.01M18 10h.01M7 14h10"/>`,monitor:`<rect x="3" y="4" width="18" height="12" rx="2"/><path d="M8 20h8M12 16v4"/>`,hand:`<path d="M7 11V6a1.5 1.5 0 0 1 3 0v4m0-1V4.5a1.5 1.5 0 0 1 3 0V10m0-1.5a1.5 1.5 0 0 1 3 0V12c0 4-2.5 8-6.5 8S6 17 5 15l-1.5-3a1.4 1.4 0 0 1 2.3-1.5L7 12"/>`,bell:`<path d="M6 9a6 6 0 0 1 12 0c0 5 2 6 2 6H4s2-1 2-6Z"/><path d="M10 19a2 2 0 0 0 4 0"/>`,plus:`<path d="M12 5v14M5 12h14"/>`,minus:`<path d="M5 12h14"/>`,"chevron-down":`<path d="m6 9 6 6 6-6"/>`,"chevron-up":`<path d="m6 15 6-6 6 6"/>`,pointer:`<path d="m4 4 6 16 2.5-6.5L19 11Z"/>`,"scroll-up":`<path d="m6 14 6-6 6 6"/><path d="M12 8v11"/>`,"scroll-down":`<path d="m6 10 6 6 6-6"/><path d="M12 16V5"/>`,"mouse-left":`<rect x="6" y="3" width="12" height="18" rx="6"/><path d="M12 3v8H6V8"/>`,"mouse-right":`<rect x="6" y="3" width="12" height="18" rx="6"/><path d="M12 3v8h6V8"/>`,"double-click":`<path d="m4 4 6 16 2.5-6.5L19 11Z"/><path d="M18 4v3M21 6h-3"/>`,drag:`<path d="M12 2v20M2 12h20" /><path d="m8 6 4-4 4 4M8 18l4 4 4-4M6 8l-4 4 4 4M18 8l4 4-4 4"/>`,send:`<path d="M22 2 11 13M22 2l-7 20-4-9-9-4Z"/>`,insert:`<path d="M12 5v14M5 12h7"/><rect x="16" y="4" width="4" height="16" rx="1"/>`,lock:`<rect x="5" y="11" width="14" height="10" rx="2"/><path d="M8 11V7a4 4 0 0 1 8 0v4"/>`,clock:`<circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/>`,power:`<path d="M12 3v9"/><path d="M6.4 7.4a8 8 0 1 0 11.2 0"/>`,activity:`<path d="M3 12h4l2-7 4 14 2-7h6"/>`,x:`<path d="M6 6 18 18M18 6 6 18"/>`,heart:`<path d="M12 20s-7-4.4-9.3-8.5a4.5 4.5 0 0 1 8.1-3.9l1.2 1.6 1.2-1.6a4.5 4.5 0 0 1 8.1 3.9C19 15.6 12 20 12 20Z"/>`,trash:`<path d="M3 6h18"/><path d="M8 6V4h8v2"/><path d="M19 6l-1 14H6L5 6"/><path d="M10 11v6M14 11v6"/>`,github:`<path fill="currentColor" stroke="none" d="M12 .5C5.37.5 0 5.87 0 12.5c0 5.3 3.44 9.8 8.21 11.39.6.11.82-.26.82-.58v-2.03c-3.34.73-4.04-1.61-4.04-1.61-.55-1.39-1.34-1.76-1.34-1.76-1.09-.74.08-.73.08-.73 1.2.09 1.84 1.24 1.84 1.24 1.07 1.83 2.81 1.3 3.5.99.11-.78.42-1.3.76-1.6-2.67-.3-5.47-1.33-5.47-5.93 0-1.31.47-2.38 1.24-3.22-.13-.3-.54-1.52.12-3.18 0 0 1.01-.32 3.3 1.23a11.5 11.5 0 0 1 6 0c2.29-1.55 3.3-1.23 3.3-1.23.66 1.66.25 2.88.12 3.18.77.84 1.23 1.91 1.23 3.22 0 4.61-2.81 5.62-5.49 5.92.43.37.81 1.1.81 2.22v3.29c0 .32.22.7.83.58A12 12 0 0 0 24 12.5C24 5.87 18.63.5 12 .5Z"/>`,reddit:`<path fill="currentColor" stroke="none" d="M24 11.78a2.6 2.6 0 0 0-4.4-1.86 12.74 12.74 0 0 0-6.86-2.16l1.17-3.68 3.16.74a1.83 1.83 0 1 0 .2-1.18l-3.6-.85a.6.6 0 0 0-.72.43l-1.3 4.08a12.8 12.8 0 0 0-7 2.18 2.6 2.6 0 1 0-2.86 4.28 5.1 5.1 0 0 0-.06.79c0 4 4.66 7.24 10.42 7.24S20.42 17.83 20.42 12.95c0-.26-.02-.52-.06-.78A2.6 2.6 0 0 0 24 11.78ZM6.13 13.5a1.83 1.83 0 1 1 3.66 0 1.83 1.83 0 0 1-3.66 0Zm10.2 4.83c-1.25 1.25-3.64 1.34-4.33 1.34-.7 0-3.09-.09-4.33-1.34a.47.47 0 0 1 .67-.67c.79.79 2.47.99 3.66.99 1.2 0 2.88-.2 3.67-.99a.47.47 0 1 1 .66.67h.03Zm-.27-3a1.83 1.83 0 1 1 0-3.66 1.83 1.83 0 0 1 0 3.66Z"/>`},h=`http://www.w3.org/2000/svg`;function g(e,t=20){let n=document.createElementNS(h,`svg`);return n.setAttribute(`viewBox`,`0 0 24 24`),n.setAttribute(`width`,String(t)),n.setAttribute(`height`,String(t)),n.setAttribute(`fill`,`none`),n.setAttribute(`stroke`,`currentColor`),n.setAttribute(`stroke-width`,`2`),n.setAttribute(`stroke-linecap`,`round`),n.setAttribute(`stroke-linejoin`,`round`),n.setAttribute(`aria-hidden`,`true`),n.innerHTML=m[e],n}var _=[`en`],v=`en`;function y(){try{let e=localStorage.getItem(`wd-locale`);if(e&&_.includes(e))return e}catch{}let e=navigator.languages?.length?navigator.languages:[navigator.language];for(let t of e){let e=(t||``).toLowerCase().split(`-`)[0]??``;if(_.includes(e))return e}return v}function b(){return location.hostname.endsWith(`whipdesk.com`)?``:`https://whipdesk.com`}function x(){return`${b()}/${y()}/dashboard/`}function S(e){let t=e?`?next=${encodeURIComponent(e)}`:``;return`${b()}/${y()}/sign-in/${t}`}var C=`https://donate.stripe.com/6oU5kE19N5v35652n88so01`,w=`https://github.com/BinaryBananaLLC/WhipDesk/`,T=`https://www.reddit.com/r/WhipDesk/`,E=[[`Esc`,`Escape`],[`Tab`,`Tab`],[`⌫`,`Backspace`],[`⏎`,`Enter`],[`←`,`ArrowLeft`],[`↑`,`ArrowUp`],[`↓`,`ArrowDown`],[`→`,`ArrowRight`]];function D(e,t,n){let r=document.createElement(e);return t&&(r.className=t),n!==void 0&&(r.textContent=n),r}function O(e,...t){let n=D(`div`,`wd-group`);n.appendChild(D(`span`,`wd-group-label`,e));let r=D(`div`,`wd-group-items`);return r.append(...t),n.appendChild(r),n}function k(e,t){let n=0,r=0,i=()=>{window.clearTimeout(n),window.clearInterval(r)};e.addEventListener(`pointerdown`,e=>{e.preventDefault(),t(),n=window.setTimeout(()=>{r=window.setInterval(t,80)},350)});for(let t of[`pointerup`,`pointercancel`,`pointerleave`])e.addEventListener(t,i);return e}function A(e,t=`wd-btn`){return D(`button`,t,e)}function j(e,t=``,n=`wd-btn`){let r=D(`button`,n);if(r.appendChild(g(e)),t){let e=D(`span`,`wd-btn-label`,t);r.appendChild(e)}else r.classList.add(`wd-icon-only`),r.setAttribute(`aria-label`,e);return r}function ee(e,t,n){let r=D(`a`,`wd-conn-feedback-link`);return r.href=n,r.target=`_blank`,r.rel=`noopener noreferrer`,r.append(g(e,16),D(`span`,void 0,t)),r}function te(e){switch(e.toUpperCase()){case`LAN`:return`Direct on your local network — fastest, no relay.`;case`STUN`:return`Direct peer-to-peer across networks.`;case`TURN`:return`Your network blocked a direct P2P connection, so we're bouncing your stream through our encrypted relay. Yes, this costs us actual money to run. Consider supporting us.`;default:return``}}function M(e){return e.toUpperCase()===`TURN`?`$ ${e}`:e}var ne=class{root;deps;statusDot=D(`span`,`wd-dot`);statusText=D(`span`,`wd-status-text`,`Connecting…`);transportBadge=D(`span`,`wd-transport hidden`);watchersText=D(`span`,`wd-watchers`,``);alertBadge=D(`span`,`wd-badge hidden`);statusbar;statusCollapseTimer=0;connectionOverlay;connName;connRoute;connPresence;connSpeed;connStatusDot;connStatusText;connError;lastError=``;netFps=0;netRtt=null;panel;optionsArea;tabButtons=new Map;tabPanes=new Map;collapseBtn;interactHost;monitorList;promptInput;activeTab=null;interactMode=`mouse`;collapsed=!1;deviceName=``;transport=``;presenceCount=1;status=`connecting`;displays=[];activeDisplay=0;constructor(e,t){this.root=e,this.deps=t,this.build()}setStatus(e){this.status=e,this.statusDot.dataset.status=e,e===`connected`&&(this.lastError=``),this.renderStatusText(),this.updateStatusCollapse(),this.connectionOverlay&&!this.connectionOverlay.classList.contains(`hidden`)&&this.renderConnection()}setAlertCount(e){this.alertBadge.textContent=e>0?String(e):``,this.alertBadge.classList.toggle(`hidden`,e<=0)}setTransport(e){this.transport=e,this.transportBadge.textContent=M(e),this.transportBadge.dataset.kind=e.toLowerCase(),this.transportBadge.classList.toggle(`hidden`,!e),this.connectionOverlay&&!this.connectionOverlay.classList.contains(`hidden`)&&this.renderConnection(),this.peekStatus()}updateStatusCollapse(){window.clearTimeout(this.statusCollapseTimer),this.status===`connected`?this.scheduleStatusCollapse():this.statusbar?.classList.remove(`collapsed`)}scheduleStatusCollapse(){window.clearTimeout(this.statusCollapseTimer),this.statusCollapseTimer=window.setTimeout(()=>{this.status===`connected`&&this.statusbar?.classList.add(`collapsed`)},4e3)}peekStatus(){this.statusbar?.classList.remove(`collapsed`),this.scheduleStatusCollapse()}renderStatusText(){this.statusText.textContent=this.status===`connected`?this.deviceName?`Connected to ${this.deviceName}`:`Connected`:this.status===`connecting`?`Connecting…`:`Disconnected`}setWelcome(e){this.deviceName=e.agent.hostname,this.renderStatusText(),this.displays=e.displays??[],this.activeDisplay=e.activeDisplay??0,this.renderMonitors(),e.capabilities.mouse||this.deps.notifications.show({type:`notification`,id:`cap-${Date.now()}`,title:`View-only`,body:`Host mouse/keyboard unavailable — grant Accessibility on the host.`,level:`warning`,source:`client`,t:Date.now()})}setActiveDisplay(e){this.activeDisplay=e,this.renderMonitors()}setPresence(e){this.presenceCount=e,this.watchersText.textContent=e>1?`● ${e} watching`:``,this.connectionOverlay&&!this.connectionOverlay.classList.contains(`hidden`)&&this.renderConnection()}buildConnectionDialog(){let e=D(`div`,`wd-dialog-overlay hidden`);e.addEventListener(`pointerdown`,t=>{t.target===e&&e.classList.add(`hidden`)});let t=D(`div`,`wd-dialog`),n=D(`div`,`wd-dialog-head`);n.append(D(`h2`,``,`Connection`));let r=D(`button`,`wd-dialog-x`);r.appendChild(g(`x`)),r.onclick=()=>e.classList.add(`hidden`),n.appendChild(r);let i=D(`div`,`wd-conn-row`);i.append(D(`span`,`wd-conn-label`,`Status`));let a=D(`div`,`wd-conn-status`);this.connStatusDot=D(`span`,`wd-dot`),this.connStatusText=D(`span`,`wd-conn-value`,`—`),a.append(this.connStatusDot,this.connStatusText),i.appendChild(a);let o=D(`div`,`wd-conn-row`);o.append(D(`span`,`wd-conn-label`,`Machine`)),this.connName=D(`span`,`wd-conn-value`,`—`),o.appendChild(this.connName);let s=D(`div`,`wd-conn-row`);s.append(D(`span`,`wd-conn-label`,`Connection`)),this.connRoute=D(`div`,`wd-conn-route`),s.appendChild(this.connRoute);let c=D(`div`,`wd-conn-row`);c.append(D(`span`,`wd-conn-label`,`Viewers`)),this.connPresence=D(`span`,`wd-conn-value`,`1`),c.appendChild(this.connPresence);let l=D(`div`,`wd-conn-row`);l.append(D(`span`,`wd-conn-label`,`Speed (FPS/latency)`)),this.connSpeed=D(`span`,`wd-conn-value`,`—`),l.appendChild(this.connSpeed),this.connError=D(`div`,`wd-conn-error hidden`);let u=D(`button`,`wd-btn wd-disconnect`);u.append(g(`power`),D(`span`,`wd-btn-label`,`Disconnect`)),u.onclick=()=>this.disconnect();let d=D(`div`,`wd-conn-feedback`);d.append(D(`p`,`wd-conn-feedback-text`,`Noticed an issue or have an idea? Reach out:`));let f=D(`div`,`wd-conn-feedback-links`);f.append(ee(`reddit`,`Reddit`,T),ee(`github`,`GitHub`,w)),d.appendChild(f),t.append(n,i,s,l,o,c,this.connError,u,d),e.appendChild(t),this.root.appendChild(e),this.connectionOverlay=e}renderConnection(){if(this.connStatusDot.dataset.status=this.status,this.connStatusText.textContent=this.status===`connected`?`Connected`:this.status===`connecting`?`Connecting…`:`Disconnected`,this.lastError?(this.connError.textContent=this.lastError,this.connError.classList.remove(`hidden`)):this.connError.classList.add(`hidden`),this.connName.textContent=this.deviceName||`Connected device`,this.connPresence.textContent=String(Math.max(1,this.presenceCount)),this.connRoute.replaceChildren(),this.transport){let e=D(`span`,`wd-transport`);if(e.textContent=M(this.transport),e.dataset.kind=this.transport.toLowerCase(),this.connRoute.append(e,D(`span`,`wd-conn-desc`,te(this.transport))),this.transport.toLowerCase()===`turn`){let e=D(`button`,`wd-support-link`);e.append(g(`heart`,14),D(`span`,void 0,`Support WhipDesk`)),e.onclick=()=>window.open(C,`_blank`,`noopener`),this.connRoute.append(e)}}else this.connRoute.append(D(`span`,`wd-conn-desc`,this.status===`connected`?`Detecting route…`:`Connecting…`));this.renderSpeed()}renderSpeed(){let e=`${this.netFps} FPS`;this.connSpeed.textContent=this.netRtt==null?e:`${e} / ${this.netRtt} ms`}setNetStats(e,t){this.netFps=e,this.netRtt=t,this.connectionOverlay&&!this.connectionOverlay.classList.contains(`hidden`)&&this.renderSpeed()}openConnection(){this.renderConnection(),this.connectionOverlay.classList.remove(`hidden`)}disconnect(){this.deps.conn.close(),window.location.href=x()}flashError(e){this.lastError=e,this.connectionOverlay&&!this.connectionOverlay.classList.contains(`hidden`)&&this.renderConnection(),this.deps.notifications.show({type:`notification`,id:`err-${Date.now()}`,title:`WhipDesk`,body:e,level:`warning`,source:`client`,t:Date.now()})}build(){let e=D(`div`,`wd-statusbar`);e.append(this.statusDot,this.statusText,this.transportBadge,this.watchersText),e.onclick=()=>this.openConnection(),this.statusbar=e,this.buildConnectionDialog();let t=j(`bell`,``,`wd-bell`);t.setAttribute(`aria-label`,`Auto-Whips`),t.title=`Auto-Whips`,t.appendChild(this.alertBadge),t.onclick=()=>this.deps.watchers.open(),this.root.append(e,t);let n=D(`div`,`wd-ribbon`);this.panel=D(`div`,`wd-panel`),this.optionsArea=D(`div`,`wd-options`),this.tabPanes.set(`viewer`,this.buildViewerPane()),this.tabPanes.set(`interact`,this.buildInteractPane()),this.tabPanes.set(`type`,this.buildTypePane()),this.tabPanes.set(`monitor`,this.buildMonitorPane());for(let e of this.tabPanes.values())this.optionsArea.appendChild(e);let r=D(`div`,`wd-tabs`),i=(e,t,n)=>{let i=D(`button`,`wd-tab`);i.appendChild(g(t,18)),i.appendChild(D(`span`,`wd-tab-label`,n)),i.onclick=()=>this.selectTab(e),this.tabButtons.set(e,i),r.appendChild(i)};i(`viewer`,`eye`,`Viewer`),i(`interact`,`mouse`,`Interact`),i(`type`,`keyboard`,`Type`),i(`monitor`,`monitor`,`Monitor`),this.collapseBtn=j(`chevron-down`,``,`wd-collapse`),this.collapseBtn.onclick=()=>this.setCollapsed(!this.collapsed),r.appendChild(this.collapseBtn),this.panel.append(this.optionsArea,r),n.appendChild(this.panel),this.root.appendChild(n),this.selectTab(`viewer`)}buildViewerPane(){let{view:e,input:t}=this.deps,n=D(`div`,`wd-pane wd-pane-single-row`),r=k(j(`minus`,``,`wd-btn wd-icon-only`),()=>e.zoomBy(.9)),i=k(j(`plus`,``,`wd-btn wd-icon-only`),()=>e.zoomBy(1.11)),a=k(j(`scroll-up`,``,`wd-btn wd-icon-only`),()=>t.scrollStep(-6)),o=k(j(`scroll-down`,``,`wd-btn wd-icon-only`),()=>t.scrollStep(6)),s=j(`hand`,``,`wd-btn wd-icon-only`);s.setAttribute(`aria-label`,`Drag to scroll`),s.title=`Drag to scroll`;let c=j(`drag`,``,`wd-btn wd-icon-only`);c.setAttribute(`aria-label`,`Pan the zoomed screen with one finger`),c.title=`Pan the zoomed screen with one finger`,s.onclick=()=>{let e=!t.getDragScroll();t.setDragScroll(e),s.classList.toggle(`on`,e),c.classList.toggle(`on`,t.getPan())},c.onclick=()=>{let e=!t.getPan();t.setPan(e),c.classList.toggle(`on`,e),s.classList.toggle(`on`,t.getDragScroll())};let l=j(`pointer`,`Click`,`wd-btn wd-go`);return l.onclick=()=>t.click(`left`),n.append(O(`Zoom`,r,i),O(`Pan`,c),O(`Scroll`,a,o,s),O(`Pointer`,l)),n}buildInteractPane(){let e=D(`div`,`wd-pane`);return this.interactHost=D(`div`,`wd-pane`),e.appendChild(this.interactHost),this.renderInteract(),e}renderInteract(){let{input:e}=this.deps;this.interactHost.replaceChildren();let t=D(`div`,`wd-group`),n=D(`div`,`wd-group-head`),r=D(`span`,`wd-group-label`,`Mode`),i=D(`div`,`wd-mode-toggle`),a=D(`button`,`wd-mode-btn`,`Mouse`),o=D(`button`,`wd-mode-btn`,`Touch`);a.classList.toggle(`on`,this.interactMode===`mouse`),o.classList.toggle(`on`,this.interactMode===`touch`),a.onclick=()=>{this.interactMode=`mouse`,this.activeTab===`interact`&&this.deps.input.setInteraction(`mouse`),this.renderInteract()},o.onclick=()=>{this.interactMode=`touch`,this.activeTab===`interact`&&this.deps.input.setInteraction(`touch`),this.renderInteract()},i.append(a,o),n.append(r,i);let s=D(`div`,`wd-group-items`);if(this.interactMode===`mouse`){let t=j(`mouse-left`,`Left`);t.onclick=()=>e.click(`left`);let n=j(`mouse-right`,`Right`);n.onclick=()=>e.click(`right`);let r=j(`double-click`,`Double`);r.onclick=()=>e.multiClick(2);let i=j(`drag`,`Drag`);i.onclick=()=>{let t=!e.getDragLock();e.setDragLock(t),i.classList.toggle(`on`,t)},s.append(t,n,r,i)}else{let t=j(`pointer`,`Tap`);t.onclick=()=>e.click(`left`);let n=j(`hand`,`Hold`);n.onclick=()=>e.longPress();let r=k(j(`scroll-up`,`Up`,`wd-btn`),()=>e.swipe(0,-.25)),i=k(j(`scroll-down`,`Down`,`wd-btn`),()=>e.swipe(0,.25)),a=A(`←`);a.onclick=()=>e.swipe(-.25,0);let o=A(`→`);o.onclick=()=>e.swipe(.25,0);let c=A(`2 fingers`);c.onclick=()=>e.click(`right`),s.append(t,n,r,i,a,o,c)}t.append(n,s),this.interactHost.append(t)}buildTypePane(){let{conn:e,input:t}=this.deps,n=D(`div`,`wd-pane wd-pane-col`);this.promptInput=D(`textarea`,`wd-type-input`),this.promptInput.placeholder=`Type to send to the focused app (URL, command, message…)`,this.promptInput.rows=2;let r=D(`div`,`wd-wrap`);for(let[t,n]of E){let i=A(t);i.onclick=()=>e.send({type:`key`,key:n}),r.appendChild(i)}let i=j(`pointer`,`1x click`);i.onclick=()=>t.click(`left`);let a=j(`double-click`,`2x click`);a.onclick=()=>t.multiClick(2);let o=j(`double-click`,`3x click`);o.onclick=()=>t.multiClick(3);let s=j(`insert`,`Insert`);s.onclick=()=>this.sendText(!1);let c=j(`send`,`Send`,`wd-btn wd-go`);return c.onclick=()=>this.sendText(!0),r.append(i,a,o,s,c),n.append(this.promptInput,r),n}buildMonitorPane(){let e=D(`div`,`wd-pane`);return this.monitorList=D(`div`,`wd-monitor-list`),e.appendChild(this.monitorList),this.renderMonitors(),e}renderMonitors(){if(this.monitorList){if(this.monitorList.replaceChildren(),this.displays.length===0){this.monitorList.appendChild(D(`span`,`wd-hint`,`Single display`));return}this.displays.forEach((e,t)=>{let n=A(`${t+1}. ${e.name}${e.primary?` ★`:``}`);n.classList.toggle(`on`,e.id===this.activeDisplay),n.onclick=()=>{this.deps.conn.send({type:`select-display`,id:e.id}),this.activeDisplay=e.id,this.renderMonitors()},this.monitorList.appendChild(n)})}}selectTab(e){if(this.activeTab!==null&&e===this.activeTab){this.setCollapsed(!this.collapsed);return}this.activeTab=e,this.collapsed&&this.setCollapsed(!1);for(let[t,n]of this.tabButtons)n.classList.toggle(`on`,t===e);for(let[t,n]of this.tabPanes)n.classList.toggle(`hidden`,t!==e);this.deps.input.setInteraction(e===`interact`?this.interactMode:`viewer`),e===`type`&&window.setTimeout(()=>this.promptInput.focus(),50)}setCollapsed(e){this.collapsed=e,this.optionsArea.classList.toggle(`hidden`,e),this.collapseBtn.replaceChildren(g(e?`chevron-up`:`chevron-down`))}sendText(e){let t=this.promptInput.value;t&&(this.deps.conn.send({type:`type`,text:t,submit:e}),this.promptInput.value=``)}};function N(e){return e<0?0:e>1?1:e}var P=2.5,F=250,re=500,ie=8,ae=class{canvas;view;conn;cb;interaction=`viewer`;dragLock=!1;dragScroll=!1;pan=!1;holdingLeft=!1;cursor={nx:.5,ny:.5};pointers=new Map;longPressTimer=0;twoFinger=null;suppressTap=!1;constructor(e,t,n,r={}){this.canvas=e,this.view=t,this.conn=n,this.cb=r,e.style.touchAction=`none`,e.addEventListener(`pointerdown`,e=>this.onDown(e)),e.addEventListener(`pointermove`,e=>this.onMove(e)),e.addEventListener(`pointerup`,e=>this.onUp(e)),e.addEventListener(`pointercancel`,e=>this.onUp(e)),e.addEventListener(`contextmenu`,e=>e.preventDefault()),this.view.setCursor(this.cursor.nx,this.cursor.ny)}setInteraction(e){this.interaction=e,e===`viewer`&&(this.dragLock=!1)}getInteraction(){return this.interaction}setCallbacks(e){this.cb=e}setDragLock(e){this.dragLock=e}getDragLock(){return this.dragLock}setDragScroll(e){this.dragScroll=e,e&&(this.pan=!1)}getDragScroll(){return this.dragScroll}setPan(e){this.pan=e,e&&(this.dragScroll=!1)}getPan(){return this.pan}isPanning(){return this.pan&&this.interaction===`viewer`}click(e,t=!1){this.send({type:`pointer`,action:`click`,button:e,double:t,x:this.cursor.nx,y:this.cursor.ny}),navigator.vibrate?.(15)}multiClick(e){for(let t=0;t<e;t++)this.send({type:`pointer`,action:`click`,button:`left`,x:this.cursor.nx,y:this.cursor.ny});navigator.vibrate?.(15)}longPress(e=650){this.send({type:`pointer`,action:`down`,button:`left`,x:this.cursor.nx,y:this.cursor.ny}),navigator.vibrate?.(25),window.setTimeout(()=>this.send({type:`pointer`,action:`up`,button:`left`}),e)}swipe(e,t){let n=N(this.cursor.nx),r=N(this.cursor.ny),i=N(this.cursor.nx+e),a=N(this.cursor.ny+t);this.send({type:`pointer`,action:`down`,button:`left`,x:n,y:r});for(let e=1;e<=6;e++){let t=e/6;window.setTimeout(()=>{this.send({type:`pointer`,action:`move`,x:n+(i-n)*t,y:r+(a-r)*t}),e===6&&(this.moveCursor(i,a),this.send({type:`pointer`,action:`up`,button:`left`}))},e*16)}navigator.vibrate?.(15)}scrollStep(e){this.send({type:`scroll`,dx:0,dy:e})}send(e){this.conn.send(e)}positionOf(e){let t=this.canvas.getBoundingClientRect();return{x:e.clientX-t.left,y:e.clientY-t.top}}moveCursor(e,t){this.cursor.nx=N(e),this.cursor.ny=N(t),this.view.setCursor(this.cursor.nx,this.cursor.ny),this.cb.onCursor?.(this.cursor.nx,this.cursor.ny)}onDown(e){this.canvas.setPointerCapture?.(e.pointerId);let t=this.positionOf(e);if(this.pointers.set(e.pointerId,{x:t.x,y:t.y,startX:t.x,startY:t.y,startT:performance.now(),moved:!1,consumed:!1}),this.pointers.size===2){window.clearTimeout(this.longPressTimer),this.beginTwoFinger();return}if(this.pointers.size===1&&(this.view.beginViewGesture(),window.clearTimeout(this.longPressTimer),this.interaction===`mouse`&&!this.dragScroll&&(this.longPressTimer=window.setTimeout(()=>this.onLongPress(),re)),!this.dragScroll&&!this.isPanning()&&(this.interaction===`mouse`||this.interaction===`viewer`))){let e=this.view.canvasToNorm(t.x,t.y);this.moveCursor(e.nx,e.ny)}}onLongPress(){let e=[...this.pointers.values()][0];!e||e.moved||e.consumed||(e.consumed=!0,this.send({type:`pointer`,action:`click`,button:`right`,x:this.cursor.nx,y:this.cursor.ny}),navigator.vibrate?.(20))}beginTwoFinger(){let e=[...this.pointers.values()];if(e.length<2)return;let t=e[0],n=e[1];this.twoFinger={dist:Math.hypot(t.x-n.x,t.y-n.y),mx:(t.x+n.x)/2,my:(t.y+n.y)/2,start:performance.now(),moved:!1}}onMove(e){let t=this.pointers.get(e.pointerId);if(!t)return;let n=this.positionOf(e),r=t.x,i=t.y;if(t.x=n.x,t.y=n.y,Math.hypot(n.x-t.startX,n.y-t.startY)>ie&&(t.moved=!0),this.pointers.size>=2&&this.twoFinger){this.onTwoFingerMove();return}if(this.pointers.size!==1||t.consumed||!t.moved)return;window.clearTimeout(this.longPressTimer);let a=n.x-r,o=n.y-i;if(this.isPanning()){this.view.panByCanvasPixels(a,o);return}if(this.interaction===`touch`||this.dragScroll){this.send({type:`scroll`,dx:Math.round(-a/P),dy:Math.round(-o/P)});return}let s=this.view.canvasToNorm(n.x,n.y);this.moveCursor(s.nx,s.ny),this.interaction===`mouse`&&this.dragLock&&!this.holdingLeft&&(this.holdingLeft=!0,this.send({type:`pointer`,action:`down`,button:`left`,x:this.cursor.nx,y:this.cursor.ny})),this.send({type:`pointer`,action:`move`,x:this.cursor.nx,y:this.cursor.ny})}onTwoFingerMove(){let e=[...this.pointers.values()];if(e.length<2||!this.twoFinger)return;let t=e[0],n=e[1],r=Math.hypot(t.x-n.x,t.y-n.y),i=(t.x+n.x)/2,a=(t.y+n.y)/2,o=r-this.twoFinger.dist,s=i-this.twoFinger.mx,c=a-this.twoFinger.my;if(Math.abs(o)>6){this.twoFinger.moved=!0,this.view.zoomAround(1+o/200,i,a),this.twoFinger.dist=r;return}(Math.abs(c)>2||Math.abs(s)>2)&&(this.twoFinger.moved=!0,this.view.getZoom()>1?this.view.panByCanvasPixels(s,c):this.send({type:`scroll`,dx:Math.round(-s/P),dy:Math.round(-c/P)}),this.twoFinger.mx=i,this.twoFinger.my=a)}onUp(e){let t=this.pointers.size,n=this.pointers.get(e.pointerId);if(this.pointers.delete(e.pointerId),window.clearTimeout(this.longPressTimer),this.pointers.size===0&&this.view.endViewGesture(),t===2){let e=this.twoFinger;e&&!e.moved&&this.interaction===`mouse`&&performance.now()-e.start<F&&(this.send({type:`pointer`,action:`click`,button:`right`,x:this.cursor.nx,y:this.cursor.ny}),navigator.vibrate?.(20)),this.twoFinger=null,this.suppressTap=!0;for(let e of this.pointers.values())e.consumed=!0;return}if(this.holdingLeft&&this.pointers.size===0&&(this.holdingLeft=!1,this.send({type:`pointer`,action:`up`,button:`left`})),this.pointers.size<2&&(this.twoFinger=null),!n||n.consumed)return;if(this.suppressTap){this.pointers.size===0&&(this.suppressTap=!1);return}let r=performance.now()-n.startT;if(!(!(!n.moved&&r<F&&this.pointers.size===0)||this.dragScroll)&&(this.interaction===`mouse`||this.interaction===`touch`)){let e=this.view.canvasToNorm(n.startX,n.startY);this.moveCursor(e.nx,e.ny),this.send({type:`pointer`,action:`click`,button:`left`,x:e.nx,y:e.ny}),navigator.vibrate?.(12)}}},oe=class{container;constructor(e){this.container=e}async requestPermission(){try{`Notification`in window&&Notification.permission==="default"&&await Notification.requestPermission()}catch{}}get permission(){return`Notification`in window?Notification.permission:`unsupported`}flash(e,t,n=`info`){this.toast({type:`notification`,id:`flash-${Date.now()}`,title:e,body:t,level:n,source:`client`,t:Date.now()})}show(e){this.toast(e);try{`Notification`in window&&Notification.permission===`granted`&&new Notification(e.title,{body:e.body,tag:e.id})}catch{}navigator.vibrate?.(e.level===`error`?[60,40,60]:40)}toast(e){let t=document.createElement(`div`);t.className=`wd-toast wd-${e.level}`;let n=document.createElement(`strong`);if(n.textContent=e.title,t.appendChild(n),e.body){let n=document.createElement(`span`);n.textContent=e.body,t.appendChild(n)}this.container.appendChild(t),window.setTimeout(()=>{t.classList.add(`wd-hide`),window.setTimeout(()=>t.remove(),300)},5e3)}},se=``+new URL(`whip-CTqIatiK.png`,import.meta.url).href,ce=class{overlay;input;message;onSubmit=null;constructor(e){this.overlay=document.createElement(`div`),this.overlay.className=`wd-pin-overlay hidden`;let t=document.createElement(`div`);t.className=`wd-pin-card`;let n=document.createElement(`img`);n.className=`wd-pin-whip`,n.src=se,n.alt=`WhipDesk`,n.decoding=`async`;let r=document.createElement(`h2`);r.textContent=`Enter device PIN`,this.message=document.createElement(`p`),this.message.className=`wd-pin-msg`,this.message.textContent=`You're connected. Enter the PIN to unlock this device and start whipping.`,this.input=document.createElement(`input`),this.input.className=`wd-pin-input`,this.input.type=`password`,this.input.inputMode=`numeric`,this.input.autocomplete=`one-time-code`,this.input.name=`wd-device-pin`,this.input.setAttribute(`data-1p-ignore`,`true`),this.input.setAttribute(`data-lpignore`,`true`),this.input.setAttribute(`aria-label`,`Device PIN`),this.input.addEventListener(`keydown`,e=>{e.key===`Enter`&&this.submit()});let i=document.createElement(`button`);i.className=`wd-pin-submit`,i.textContent=`Unlock`,i.onclick=()=>this.submit();let a=document.createElement(`button`);a.type=`button`,a.className=`wd-support-link wd-pin-support`,a.append(g(`heart`,14));let o=document.createElement(`span`);o.textContent=`Support WhipDesk`,a.append(o),a.onclick=()=>window.open(C,`_blank`,`noopener`);let s=document.createElement(`button`);s.className=`wd-pin-back`,s.textContent=`← Back to dashboard`,s.onclick=()=>{window.location.href=x()},t.append(n,r,this.message,this.input,i,a,s),this.overlay.appendChild(t),e.appendChild(this.overlay)}show(e,t){this.onSubmit=t,this.input.value=``,e.retry?(this.message.textContent=e.attemptsLeft>0?`Wrong PIN — ${e.attemptsLeft} attempt(s) left.`:`Wrong PIN. Try again.`,this.message.classList.add(`err`),navigator.vibrate?.([40,40,40])):(this.message.textContent=`You're connected. Enter the PIN to unlock this device and start whipping.`,this.message.classList.remove(`err`)),this.overlay.classList.remove(`hidden`),window.setTimeout(()=>this.input.focus(),50)}hide(){this.overlay.classList.add(`hidden`)}submit(){let e=this.input.value.trim();if(e.length<4){this.message.textContent=`PIN is at least 4 characters.`,this.message.classList.add(`err`);return}this.onSubmit?.(e),this.message.textContent=`Checking…`,this.message.classList.remove(`err`)}},le=`modulepreload`,ue=function(e,t){return new URL(e,t).href},de={},I=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e=document.getElementsByTagName(`link`),i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function o(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function s(e){return import.meta.resolve?import.meta.resolve(e):new URL(e,new URL(`../../../src/node/plugins/importAnalysisBuild.ts`,import.meta.url)).href}r=o(t.map(t=>{if(t=ue(t,n),t=s(t),t in de)return;de[t]=!0;let r=t.endsWith(`.css`);for(let n=e.length-1;n>=0;n--){let i=e[n];if(i.href===t&&(!r||i.rel===`stylesheet`))return}let i=document.createElement(`link`);if(i.rel=r?`stylesheet`:le,r||(i.as=`script`),i.crossOrigin=``,i.href=t,a&&i.setAttribute(`nonce`,a),document.head.appendChild(i),r)return new Promise((e,n)=>{i.addEventListener(`load`,e),i.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${t}`)))})}))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})};async function fe(e,t){if(e.vapidKey&&!(!(`serviceWorker`in navigator)||!(`Notification`in window)))try{let{initializeApp:n,getApps:r}=await I(async()=>{let{initializeApp:e,getApps:t}=await import(`./index.esm-mXKu2C3o.js`);return{initializeApp:e,getApps:t}},__vite__mapDeps([0,1]),import.meta.url),{getAuth:i}=await I(async()=>{let{getAuth:e}=await import(`./index.esm-CmSagqpw.js`);return{getAuth:e}},__vite__mapDeps([2,1]),import.meta.url),{getFirestore:a,doc:o,setDoc:s,serverTimestamp:c}=await I(async()=>{let{getFirestore:e,doc:t,setDoc:n,serverTimestamp:r}=await import(`./index.esm-wogdVWd2.js`);return{getFirestore:e,doc:t,setDoc:n,serverTimestamp:r}},__vite__mapDeps([3,1]),import.meta.url),{getMessaging:l,getToken:u,onMessage:d,isSupported:f}=await I(async()=>{let{getMessaging:e,getToken:t,onMessage:n,isSupported:r}=await import(`./index.esm-BgjPHsdM.js`);return{getMessaging:e,getToken:t,onMessage:n,isSupported:r}},__vite__mapDeps([4,1]),import.meta.url);if(!await f().catch(()=>!1))return;let p=r()[0]??n(e),m=i(p).currentUser;if(!m||Notification.permission==="default"&&await Notification.requestPermission()!==`granted`||Notification.permission!==`granted`)return;let h=await navigator.serviceWorker.register(`./firebase-messaging-sw.js`),g=l(p),_=await u(g,{vapidKey:e.vapidKey,serviceWorkerRegistration:h});if(!_)return;await s(o(a(p),`users`,m.uid,`fcmTokens`,_),{token:_,ua:navigator.userAgent,updatedAt:c()},{merge:!0}),d(g,e=>{let n=e.notification;t.show({type:`notification`,id:`push-${Date.now()}`,title:n?.title??`WhipDesk`,body:n?.body,level:`info`,source:`push`,t:Date.now()})})}catch{}}var pe=[{urls:`stun:turn-us1.whipdesk.com:3478`}];async function me(e){try{let t=await e.getStats(),n=``,r=``;t.forEach(e=>{e.type===`transport`&&e.selectedCandidatePairId&&(n=e.selectedCandidatePairId)}),t.forEach(e=>{e.type===`candidate-pair`&&!r&&(e.id===n||e.nominated&&e.state===`succeeded`)&&(r=e.localCandidateId)});let i=``;if(t.forEach(e=>{e.id===r&&e.type===`local-candidate`&&(i=e.candidateType)}),i===`relay`)return`TURN`;if(i===`srflx`||i===`prflx`)return`STUN`;if(i===`host`)return`LAN`}catch{}return null}var he=class{deviceId;config;core;pc=null;dc=null;mainXcv=null;overviewXcv=null;cleanupSignal=null;deleteSessionDoc=null;pushCandidate=null;appliedAnswer=!1;appliedCandidates=new Set;closed=!1;reconnectTimer=0;statsTimer=0;constructor(e,t,n){this.deviceId=e,this.config=n,this.core=new l(t),this.core.setSender(e=>{if(this.dc&&this.dc.readyState===`open`)try{this.dc.send(e)}catch{}})}on(e,t){this.core.on(e,t)}send(e){this.core.send(e)}submitPin(e){this.core.submitPin(e)}setVisible(e){this.core.setVisible(e)}connect(){this.closed=!1,this.start()}close(){this.closed=!0,window.clearTimeout(this.reconnectTimer),this.reconnectTimer=0,this.teardown()}isHealthy(){return!this.closed&&this.pc?.connectionState===`connected`&&this.dc?.readyState===`open`}wake(){this.closed||this.isHealthy()||(window.clearTimeout(this.reconnectTimer),this.reconnectTimer=0,this.teardown(),this.start())}start(){this.open().catch(e=>{this.core.emit(`error`,`Remote connect failed: ${e.message}`),this.core.emit(`status`,`disconnected`),this.scheduleReconnect()})}teardown(){if(window.clearInterval(this.statsTimer),this.statsTimer=0,this.cleanupSignal?.(),this.cleanupSignal=null,this.deleteSessionDoc?.(),this.deleteSessionDoc=null,this.pushCandidate=null,this.appliedAnswer=!1,this.appliedCandidates.clear(),this.core.emit(`videoTrack`,null),this.core.emit(`overviewTrack`,null),this.dc){this.dc.onopen=this.dc.onclose=this.dc.onmessage=null;try{this.dc.close()}catch{}this.dc=null}if(this.pc){this.pc.onconnectionstatechange=null,this.pc.ontrack=null;try{this.pc.close()}catch{}this.pc=null}this.mainXcv=null,this.overviewXcv=null}scheduleReconnect(){this.closed||this.reconnectTimer||(this.reconnectTimer=window.setTimeout(()=>{this.reconnectTimer=0,!this.closed&&(this.teardown(),this.start())},2e3))}async open(){this.core.emit(`status`,`connecting`);let{initializeApp:e,getApps:t}=await I(async()=>{let{initializeApp:e,getApps:t}=await import(`./index.esm-mXKu2C3o.js`);return{initializeApp:e,getApps:t}},__vite__mapDeps([0,1]),import.meta.url),{getAuth:n}=await I(async()=>{let{getAuth:e}=await import(`./index.esm-CmSagqpw.js`);return{getAuth:e}},__vite__mapDeps([2,1]),import.meta.url),{getDatabase:r,ref:i,child:a,push:o,set:s,onValue:c,remove:l,onDisconnect:u}=await I(async()=>{let{getDatabase:e,ref:t,child:n,push:r,set:i,onValue:a,remove:o,onDisconnect:s}=await import(`./index.esm-Di8jSGaG.js`);return{getDatabase:e,ref:t,child:n,push:r,set:i,onValue:a,remove:o,onDisconnect:s}},__vite__mapDeps([5,1]),import.meta.url),d=t()[0]??e(this.config),f=n(d);if(await new Promise(e=>{if(f.currentUser)return e();let t=f.onAuthStateChanged(()=>{t(),e()})}),!f.currentUser){window.location.assign(S(`/app/${window.location.hash}`));return}let p=f.currentUser.uid,m=r(d),h=await this.fetchIceServers(f.currentUser),g=new RTCPeerConnection({iceServers:h,iceTransportPolicy:`all`});this.pc=g;let _=g.createDataChannel(`whipdesk`);_.binaryType=`arraybuffer`,this.dc=_,this.wireDataChannel(_);try{this.mainXcv=g.addTransceiver(`video`,{direction:`recvonly`}),this.overviewXcv=g.addTransceiver(`video`,{direction:`recvonly`})}catch{}g.ontrack=e=>{let t=e.streams[0]??new MediaStream([e.track]);this.overviewXcv&&e.transceiver===this.overviewXcv?this.core.emit(`overviewTrack`,t):this.core.emit(`videoTrack`,t)};let v=!1,y=async()=>{if(v)return;let e=await me(g);if(!e)return;v=!0,this.core.emit(`transport`,e);let t=e===`TURN`?`turn`:e===`STUN`?`stun`:`lan`;try{let{getFirestore:e,doc:n,setDoc:r,increment:i}=await I(async()=>{let{getFirestore:e,doc:t,setDoc:n,increment:r}=await import(`./index.esm-wogdVWd2.js`);return{getFirestore:e,doc:t,setDoc:n,increment:r}},__vite__mapDeps([3,1]),import.meta.url);r(n(e(d),`users`,p),{stats:{[t]:i(1)}},{merge:!0}).catch(()=>{})}catch{}};g.onconnectionstatechange=()=>{let e=g.connectionState;e===`connected`?(this.core.emit(`status`,`connected`),y(),this.startStatsPoll(g)):(e===`failed`||e===`disconnected`||e===`closed`)&&(this.core.emit(`status`,`disconnected`),this.scheduleReconnect())};let b=o(i(m,`signaling/${p}/${this.deviceId}`));this.pushCandidate=e=>{try{s(o(a(b,`offerCandidates`)),e)}catch{}},g.onicecandidate=e=>{e.candidate&&this.pushCandidate?.(e.candidate.toJSON())};let x=await g.createOffer();await g.setLocalDescription(x),await s(b,{offer:{sdp:g.localDescription?.sdp??``},controllerUid:p,createdAtMs:Date.now()}),u(b).remove(),this.deleteSessionDoc=()=>void l(b).catch(()=>{}),this.cleanupSignal=c(b,e=>{let t=e.val();if(!(!t||this.closed)&&(t.answer?.sdp&&!this.appliedAnswer&&(this.appliedAnswer=!0,g.setRemoteDescription({type:`answer`,sdp:t.answer.sdp})),t.answerCandidates&&this.appliedAnswer)){for(let[e,n]of Object.entries(t.answerCandidates))if(!this.appliedCandidates.has(e)){this.appliedCandidates.add(e);try{g.addIceCandidate(n)}catch{}}}})}startStatsPoll(e){window.clearInterval(this.statsTimer),this.lossBase=null,this.statsPolls=0,this.statsTimer=window.setInterval(()=>void this.pollStats(e),1e3)}lossBase=null;statsPolls=0;async pollStats(e){let t=null,n=0,r=0,i=0;try{(await e.getStats()).forEach(e=>{e.type===`inbound-rtp`&&e.kind===`video`?(n=Math.max(n,Number(e.framesPerSecond??0)),r+=Number(e.packetsLost??0),i+=Number(e.packetsReceived??0)):e.type===`candidate-pair`&&e.nominated&&typeof e.currentRoundTripTime==`number`&&(t=e.currentRoundTripTime)})}catch{return}if(this.core.emit(`netStats`,{fps:Math.round(n),rtt:t==null?null:Math.round(t*1e3)}),this.statsPolls+=1,!this.lossBase)this.lossBase={lost:r,received:i};else if(this.statsPolls%5==0){let e=Math.max(0,r-this.lossBase.lost),n=Math.max(0,i-this.lossBase.received);this.lossBase={lost:r,received:i};let a=e+n;if(a>0){let n=e/a*100;this.core.send({type:`video-stats`,lossPct:n,rttMs:t==null?void 0:Math.round(t*1e3)})}}}wireDataChannel(e){e.onopen=()=>this.core.sendHello(),e.onclose=()=>{this.core.emit(`status`,`disconnected`),this.scheduleReconnect()},e.onmessage=e=>{typeof e.data==`string`&&this.core.handleText(e.data)}}async fetchIceServers(e){let t=[...pe];try{let e=sessionStorage.getItem(`wd-ice`);if(e){let{servers:t,exp:n}=JSON.parse(e);if(Array.isArray(t)&&t.length&&n>Date.now())return t}}catch{}try{let t=this.config.iceUrl||`https://us-central1-${this.config.projectId}.cloudfunctions.net/iceServers`,n=await e.getIdToken(),r=await fetch(t,{headers:{authorization:`Bearer ${n}`}});if(r.ok){let e=await r.json();if(Array.isArray(e.iceServers)&&e.iceServers.length){try{sessionStorage.setItem(`wd-ice`,JSON.stringify({servers:e.iceServers,exp:Date.now()+8*6e4}))}catch{}return e.iceServers}}}catch{}return t}};function L(e,t,n){return e<t?t:e>n?n:e}var ge=480,_e=600,R=-.6,z=1.6,ve=1500,ye=120,be=3e3;function B(e){return!e||e.x<=.001&&e.y<=.001&&e.w>=.999&&e.h>=.999}function V(e,t){if(B(e)&&B(t))return!0;if(!e||!t)return!1;let n=.005;return Math.abs(e.x-t.x)<n&&Math.abs(e.y-t.y)<n&&Math.abs(e.w-t.w)<n&&Math.abs(e.h-t.h)<n}var xe=class{canvas;ctx;mainEl=null;region=null;shownRegion=null;regionBridge=0;regionActiveHold=0;hasActiveEcho=!1;screen={width:0,height:0};viewMode=`fit`;zoom=1;center={nx:.5,ny:.5};cursor=null;onZoomCb;onViewCb;onGestureCb;gestureActive=!1;viewDirty=!1;videoActive=!1;videoRaf=0;cssW=1;cssH=1;dpr=1;layout={S:1,tx:0,ty:0};rafPending=!1;overlayBox=null;overlayView=null;overlayCanvas=null;overlayCtx=null;lastOverlayKey=``;overlayCanvasKey=``;minimapActiveAt=0;minimapShown=!0;overview=null;overviewCtx=null;overviewReady=!1;overviewDirty=!1;lastSnapAt=0;overviewEl=null;constructor(e){this.canvas=e;let t=e.getContext(`2d`);if(!t)throw Error(`2D canvas context unavailable`);this.ctx=t,this.createOverlay(),this.startOverlayLoop(),this.resize(),new ResizeObserver(()=>this.resize()).observe(e),window.addEventListener(`orientationchange`,()=>window.setTimeout(()=>this.resize(),200))}createOverlay(){let e=document.createElement(`div`);e.style.cssText=`position:fixed;top:calc(env(safe-area-inset-top, 0px) + 56px);right:10px;box-sizing:border-box;border:1.5px solid rgba(255,255,255,0.8);border-radius:6px;background:rgba(0,0,0,0.55);z-index:2147483600;pointer-events:none;display:none;box-shadow:0 1px 8px rgba(0,0,0,0.6);`;let t=document.createElement(`canvas`);t.style.cssText=`position:absolute;inset:0;width:100%;height:100%;border-radius:5px;display:block;`;let n=document.createElement(`div`);n.style.cssText=`position:absolute;box-sizing:border-box;border:2px solid #4ea1ff;background:rgba(78,161,255,0.18);border-radius:2px;`,e.appendChild(t),e.appendChild(n),document.body.appendChild(e),this.overlayBox=e,this.overlayView=n,this.overlayCanvas=t,this.overlayCtx=t.getContext(`2d`)}startOverlayLoop(){let e=()=>{this.renderOverlay(),requestAnimationFrame(e)};requestAnimationFrame(e)}renderOverlay(){let e=this.overlayBox,t=this.overlayView;if(!e||!t)return;let n=this.getVisibleRegion(),r=this.region,i=this.dispW(),a=this.dispH();if(!(r||n.w<.985||n.h<.985)){e.style.display!==`none`&&(e.style.display=`none`),this.lastOverlayKey=``,this.overlayCanvasKey=``;return}e.style.display===`none`&&(e.style.display=`block`,this.minimapActiveAt=performance.now(),this.minimapShown=!1);let o=Math.round(Math.min(132,Math.max(76,this.cssW*.32))),s=Math.round(o*(a/i||.625)),c=`${o}x${s}`;(c!==this.overlayCanvasKey||this.overviewDirty)&&(this.overlayCanvasKey=c,this.overviewDirty=!1,e.style.width=`${o}px`,e.style.height=`${s}px`,this.paintMinimap(o,s));let l=n,u=performance.now(),d=`${l.x.toFixed(3)},${l.y.toFixed(3)},${l.w.toFixed(3)},${l.h.toFixed(3)}`;d!==this.lastOverlayKey&&(this.lastOverlayKey=d,this.minimapActiveAt=u,t.style.left=`${(L(l.x,0,1)*100).toFixed(2)}%`,t.style.top=`${(L(l.y,0,1)*100).toFixed(2)}%`,t.style.width=`${(L(Math.max(.04,l.w),0,1)*100).toFixed(2)}%`,t.style.height=`${(L(Math.max(.04,l.h),0,1)*100).toFixed(2)}%`);let f=u-this.minimapActiveAt<be;f!==this.minimapShown&&(this.minimapShown=f,e.style.transition=`opacity ${f?.18:.5}s ease`,e.style.opacity=f?`1`:`0`)}paintMinimap(e,t){let n=this.overlayCanvas,r=this.overlayCtx;if(!n||!r)return;let i=Math.max(1,Math.round(e*this.dpr)),a=Math.max(1,Math.round(t*this.dpr));n.width!==i&&(n.width=i),n.height!==a&&(n.height=a),r.clearRect(0,0,i,a);let o=this.overviewImg();o&&(r.imageSmoothingEnabled=!0,r.imageSmoothingQuality=`low`,r.drawImage(o,0,0,i,a))}overviewImg(){return this.overviewReady?this.overview:null}maybeSnapshot(e,t,n){let r=performance.now();if(r-this.lastSnapAt<_e)return;this.lastSnapAt=r,this.overview||(this.overview=document.createElement(`canvas`),this.overviewCtx=this.overview.getContext(`2d`));let i=this.overview,a=this.overviewCtx;if(!i||!a)return;let o=ge,s=Math.max(1,Math.round(o*n/t));i.width!==o&&(i.width=o),i.height!==s&&(i.height=s),a.imageSmoothingEnabled=!0,a.imageSmoothingQuality=`medium`,a.drawImage(e,0,0,t,n,0,0,o,s),this.overviewReady=!0,this.overviewDirty=!0}getCanvas(){return this.canvas}resize(){let e=this.canvas.getBoundingClientRect();this.cssW=Math.max(1,e.width),this.cssH=Math.max(1,e.height),this.dpr=Math.min(window.devicePixelRatio||1,2),this.canvas.width=Math.round(this.cssW*this.dpr),this.canvas.height=Math.round(this.cssH*this.dpr),this.requestDraw(),this.emitView()}setScreen(e){let t=e.width!==this.screen.width||e.height!==this.screen.height;this.screen=e,t&&(this.overviewReady=!1,this.lastSnapAt=0,this.overviewDirty=!0),this.requestDraw()}getScreen(){return this.screen}dispW(){return this.screen.width||this.mainEl?.videoWidth||1}dispH(){return this.screen.height||this.mainEl?.videoHeight||1}setFrameRegion(e){let t=B(e)?null:e;this.region=t,window.clearTimeout(this.regionActiveHold),window.clearTimeout(this.regionBridge),this.hasActiveEcho||(this.regionBridge=window.setTimeout(()=>{this.shownRegion=t,this.videoActive||this.requestDraw()},ve)),this.videoActive||this.requestDraw()}setFrameRegionActive(e){this.hasActiveEcho=!0;let t=B(e)?null:e;if(!V(t,this.region)||V(t,this.shownRegion))return;window.clearTimeout(this.regionActiveHold);let n=()=>{V(t,this.region)&&(this.shownRegion=t,window.clearTimeout(this.regionBridge),this.videoActive||this.requestDraw())};this.regionActiveHold=window.setTimeout(()=>{if(!V(t,this.region))return;let e=this.mainEl;e&&typeof e.requestVideoFrameCallback==`function`?e.requestVideoFrameCallback(n):n()},ye)}setVideoSource(e){this.mainEl=e,this.videoActive=!!e,e?this.startVideoLoop():this.stopVideoLoop()}isVideoActive(){return this.videoActive}setOverviewSource(e){this.overviewEl=e}startVideoLoop(){if(this.videoRaf)return;let e=()=>{if(!this.videoActive){this.videoRaf=0;return}this.draw(),this.videoRaf=requestAnimationFrame(e)};this.videoRaf=requestAnimationFrame(e)}stopVideoLoop(){this.videoRaf&&cancelAnimationFrame(this.videoRaf),this.videoRaf=0,this.requestDraw()}setViewMode(e){this.viewMode=e,e===`fit`?(this.zoom=1,this.center={nx:.5,ny:.5}):this.zoom===1&&(this.zoom=2),this.emitView(),this.requestDraw()}getViewMode(){return this.viewMode}toggleViewMode(){return this.setViewMode(this.viewMode===`fit`?`magnify`:`fit`),this.viewMode}setZoom(e){this.zoom=L(e,1,8),this.viewMode=this.zoom===1?`fit`:`magnify`,this.zoom===1&&(this.center={nx:.5,ny:.5}),this.onZoomCb?.(this.zoom),this.emitView(),this.requestDraw()}zoomBy(e){this.setZoom(this.zoom*e)}getZoom(){return this.zoom}setOnZoom(e){this.onZoomCb=e}setOnView(e){this.onViewCb=e}setOnGesture(e){this.onGestureCb=e}beginViewGesture(){this.gestureActive=!0,this.onGestureCb?.(!0)}endViewGesture(){this.gestureActive&&(this.gestureActive=!1,this.viewDirty&&(this.viewDirty=!1,this.onViewCb?.(this.getVisibleRegion())),this.onGestureCb?.(!1))}emitView(){if(this.gestureActive){this.viewDirty=!0;return}this.onViewCb?.(this.getVisibleRegion())}zoomAround(e,t,n){let r=this.canvasToNorm(t,n),i=L(this.zoom*e,1,8);if(i===1){this.setZoom(1);return}this.zoom=i,this.viewMode=`magnify`;let a=this.dispW(),o=this.dispH(),s=Math.min(this.cssW/a,this.cssH/o)*this.zoom;this.center.nx=L(r.nx-(t-this.cssW/2)/(a*s||1),R,z),this.center.ny=L(r.ny-(n-this.cssH/2)/(o*s||1),R,z),this.onZoomCb?.(this.zoom),this.emitView(),this.requestDraw()}panByNorm(e,t){this.center.nx=L(this.center.nx+e,R,z),this.center.ny=L(this.center.ny+t,R,z),this.emitView(),this.requestDraw()}panByCanvasPixels(e,t){let{S:n}=this.computeLayout(),r=this.dispW(),i=this.dispH();!r||!i||!n||(this.center.nx=L(this.center.nx-e/(r*n),R,z),this.center.ny=L(this.center.ny-t/(i*n),R,z),this.emitView(),this.requestDraw())}setCursor(e,t=0){this.cursor=e===null?null:{nx:e,ny:t},this.videoActive||this.requestDraw()}computeLayout(){let{cssW:e,cssH:t}=this,n=this.dispW(),r=this.dispH();if(!n||!r)return this.layout={S:1,tx:0,ty:0},this.layout;let i=Math.min(e/n,t/r)*this.zoom,a,o;return this.viewMode===`fit`||this.zoom===1?(a=(e-n*i)/2,o=(t-r*i)/2):(a=e/2-this.center.nx*n*i,o=t/2-this.center.ny*r*i),this.layout={S:i,tx:a,ty:o},this.layout}canvasToNorm(e,t){let{S:n,tx:r,ty:i}=this.computeLayout();return{nx:L((e-r)/(this.dispW()*n||1),0,1),ny:L((t-i)/(this.dispH()*n||1),0,1)}}normToCanvas(e,t){let{S:n,tx:r,ty:i}=this.computeLayout();return{cx:r+e*this.dispW()*n,cy:i+t*this.dispH()*n}}getVisibleRegion(){let{S:e,tx:t,ty:n}=this.computeLayout(),r=this.dispW()*e,i=this.dispH()*e;if(!r||!i)return{x:0,y:0,w:1,h:1};let a=L(-t/r,0,1),o=L(-n/i,0,1),s=L((this.cssW-t)/r,0,1),c=L((this.cssH-n)/i,0,1);return{x:a,y:o,w:Math.max(.05,s-a),h:Math.max(.05,c-o)}}requestDraw(){this.videoActive||this.rafPending||(this.rafPending=!0,requestAnimationFrame(()=>{this.rafPending=!1,this.draw()}))}draw(){let e=this.ctx;e.setTransform(this.dpr,0,0,this.dpr,0,0),e.clearRect(0,0,this.cssW,this.cssH);let t=this.mainEl&&this.mainEl.videoWidth>0?this.mainEl:null;if(!t)return;let{S:n,tx:r,ty:i}=this.computeLayout(),a=this.dispW(),o=this.dispH(),s=a*n,c=o*n,l=t.videoWidth,u=t.videoHeight,d=l/u,f=e=>e?e.w*a/(e.h*o):a/o;if(this.region!==this.shownRegion){let e=Math.abs(d/f(this.region)-1)<.06,t=Math.abs(d/f(this.shownRegion)-1)<.06;e&&!t&&(this.shownRegion=this.region,window.clearTimeout(this.regionBridge))}let p=this.shownRegion,m=!!p&&Math.abs(d/f(p)-1)<.08,h=m?r+p.x*s:r,g=m?i+p.y*c:i,_=m?p.w*s:s,v=m?p.h*c:c,y=this.overviewImg();y&&(this.region||this.shownRegion)&&(e.imageSmoothingEnabled=!0,e.imageSmoothingQuality=`low`,e.drawImage(y,r,i,s,c));let b=Math.min(_/l,v/u),x=l*b,S=u*b;if(e.imageSmoothingEnabled=!0,e.imageSmoothingQuality=`high`,e.drawImage(t,0,0,l,u,h+(_-x)/2,g+(v-S)/2,x,S),this.cursor){let{cx:e,cy:t}=this.normToCanvas(this.cursor.nx,this.cursor.ny);this.drawCursor(e,t)}let C=this.overviewEl;if(this.region&&C&&C.videoWidth>0)this.maybeSnapshot(C,C.videoWidth,C.videoHeight);else if(!this.region&&!this.shownRegion&&o>0){let e=a/o;e>0&&Math.abs(d/e-1)<.06&&this.maybeSnapshot(t,l,u)}}drawCursor(e,t){let n=this.ctx;n.save(),n.beginPath(),n.arc(e,t,9,0,Math.PI*2),n.strokeStyle=`rgba(78,161,255,0.95)`,n.lineWidth=2,n.stroke(),n.beginPath(),n.arc(e,t,2.5,0,Math.PI*2),n.fillStyle=`rgba(78,161,255,0.95)`,n.fill(),n.restore()}};function Se(e,t,n,r){let i=document.createElement(`div`);i.className=`wd-place-layer`;let a=document.createElement(`div`);a.className=`wd-place-marker`;let o=document.createElement(`div`);o.className=`wd-place-bar`;let s=document.createElement(`p`);s.className=`wd-place-hint`,s.textContent=n.hint,o.appendChild(s);let c=null;n.withText&&(c=document.createElement(`textarea`),c.className=`wd-input wd-input-area wd-place-text`,c.placeholder=`Type the prompt to send…`,o.appendChild(c));let l=document.createElement(`div`);l.className=`wd-place-buttons`;let u=document.createElement(`button`);u.className=`wd-btn`,u.textContent=`Cancel`;let d=document.createElement(`button`);d.className=`wd-btn wd-go`,d.textContent=n.confirmLabel,l.append(u,d),o.appendChild(l),t.append(i,a,o),t.classList.add(`wd-placing`);let f={nx:.5,ny:.5},p=0,m=()=>{let{cx:t,cy:n}=e.normToCanvas(f.nx,f.ny);a.style.left=`${t}px`,a.style.top=`${n}px`,p=requestAnimationFrame(m)};p=requestAnimationFrame(m);let h=new Map,g=`idle`,_=null,v={x:0,y:0},y=!1,b=e=>{let t=i.getBoundingClientRect();return{x:e.clientX-t.left,y:e.clientY-t.top}},x=t=>{let{cx:n,cy:r}=e.normToCanvas(f.nx,f.ny);return Math.hypot(t.x-n,t.y-r)<38};i.addEventListener(`pointerdown`,t=>{i.setPointerCapture?.(t.pointerId);let n=b(t);if(h.set(t.pointerId,n),h.size===2){let e=[...h.values()],t=e[0],n=e[1];_={dist:Math.hypot(t.x-n.x,t.y-n.y),mx:(t.x+n.x)/2,my:(t.y+n.y)/2},g=`idle`}else h.size===1&&(v=n,y=!1,g=x(n)?`marker`:`pan`,g===`marker`&&(f=e.canvasToNorm(n.x,n.y)))}),i.addEventListener(`pointermove`,t=>{let n=h.get(t.pointerId);if(!n)return;let r=b(t);if(h.set(t.pointerId,r),h.size>=2&&_){let t=[...h.values()],n=t[0],r=t[1],i=Math.hypot(n.x-r.x,n.y-r.y),a=(n.x+r.x)/2,o=(n.y+r.y)/2;Math.abs(i-_.dist)>4&&(e.zoomAround(1+(i-_.dist)/200,a,o),_.dist=i),e.panByCanvasPixels(a-_.mx,o-_.my),_.mx=a,_.my=o;return}Math.hypot(r.x-v.x,r.y-v.y)>6&&(y=!0);let i=r.x-n.x,a=r.y-n.y;g===`marker`?f=e.canvasToNorm(r.x,r.y):g===`pan`&&e.panByCanvasPixels(i,a)});let S=t=>{let n=h.get(t.pointerId);h.delete(t.pointerId),n&&g===`pan`&&!y&&(f=e.canvasToNorm(n.x,n.y)),h.size<2&&(_=null),h.size===0&&(g=`idle`)};i.addEventListener(`pointerup`,S),i.addEventListener(`pointercancel`,S);let C=e=>{cancelAnimationFrame(p),t.classList.remove(`wd-placing`),i.remove(),a.remove(),o.remove(),r(e)};u.onclick=()=>C(null),d.onclick=()=>{let e=c?.value.trim()??``;if(n.withText&&!e){c?.focus();return}C({nx:f.nx,ny:f.ny,text:n.withText?e:void 0})}}var Ce=0;function H(){return`w${Date.now().toString(36)}${(Ce++).toString(36)}`}function we(){return new Date().toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}function Te(e){let t=Math.max(0,Math.round((e-Date.now())/1e3)),n=Math.floor(t/3600),r=Math.floor(t%3600/60),i=t%60;return n>0?`${n}h ${r}m`:r>0?`${r}m ${String(i).padStart(2,`0`)}s`:`${i}s`}function U(e,t,n){let r=document.createElement(e);return t&&(r.className=t),n!==void 0&&(r.textContent=n),r}var Ee={claude:`Claude Code`,codex:`Codex CLI`,gemini:`Gemini CLI`,aider:`Aider`,copilot:`Copilot CLI`,opencode:`opencode`,cursor:`Cursor Agent`,amp:`Amp`,unknown:`AI agent`};function W(e){return Ee[e]??`AI agent`}function De(e){switch(e){case`working`:return`working`;case`blocked`:return`needs you`;case`idle`:return`idle`;case`finished`:return`finished`;case`crashed`:return`crashed`;default:return`…`}}var Oe=class{root;conn;view;notifications;requestNotifications;regions=[];timers=[];monitors=[];monitorSessions=[];alwaysAgents=new Set;renderPicker=null;renderAlways=null;countdownTimer=0;overlay;list;permissionRow;selector=null;constructor(e,t,n,r,i=()=>{}){this.root=e,this.conn=t,this.view=n,this.notifications=r,this.requestNotifications=i,this.overlay=U(`div`,`wd-dialog-overlay hidden`),this.overlay.addEventListener(`pointerdown`,e=>{e.target===this.overlay&&this.close()});let a=U(`div`,`wd-dialog`),o=U(`div`,`wd-dialog-head`);o.append(U(`h2`,``,`Auto-Whips`));let s=U(`button`,`wd-dialog-x`);s.appendChild(g(`x`)),s.onclick=()=>this.close(),o.appendChild(s);let c=U(`div`,`wd-dialog-help`),l=U(`p`,`wd-help-intro`,`Auto-Whips are a set of features that can whip and monitor agents for you automatically:`),u=U(`ul`,`wd-help-list`),d=U(`li`);d.append(U(`strong`,void 0,`Alerts`),document.createTextNode(` — watch part of the screen and ping you when it changes (e.g. your agent finishes).`));let f=U(`li`);f.append(U(`strong`,void 0,`Timers`),document.createTextNode(` — ping you after a set time, and can auto-click or send a prompt when they fire.`));let p=U(`li`);p.append(U(`strong`,void 0,`Session Monitoring`),document.createTextNode(` — pick a running AI session and get pinged the moment the agent stops working (it's waiting on you or has gone idle).`)),u.append(d,f,p);let m=U(`p`,`wd-help-note`,`Enable browser notifications to be reminded even when the browser is closed.`);c.append(l,u,m),this.permissionRow=U(`div`,`wd-perm-row`),this.list=U(`div`,`wd-watch-list`);let h=U(`button`,`wd-btn wd-go`);h.append(g(`plus`),U(`span`,`wd-btn-label`,`Add alert`)),h.onclick=()=>this.beginSelection();let _=U(`button`,`wd-btn wd-go`);_.append(g(`clock`),U(`span`,`wd-btn-label`,`Add timer`)),_.onclick=()=>this.beginTimer();let v=U(`button`,`wd-btn wd-go`);v.append(g(`activity`),U(`span`,`wd-btn-label`,`Add Session Monitoring`)),v.onclick=()=>this.beginMonitor();let y=U(`div`,`wd-dialog-actions wd-actions-stack`);y.append(h,_,v),a.append(o,c,this.permissionRow,this.list,y),this.overlay.appendChild(a),this.root.appendChild(this.overlay),this.renderPermission(),this.conn.on(`monitorSessions`,e=>{this.monitorSessions=e,this.renderPicker?.()})}setRegions(e){this.regions=e,this.renderList()}setTimers(e){this.timers=e,this.renderList()}setMonitors(e){this.monitors=e,this.renderList()}setAlwaysAgents(e){this.alwaysAgents=new Set(e),this.renderAlways?.()}open(){this.renderPermission(),this.renderList(),this.overlay.classList.remove(`hidden`),window.clearInterval(this.countdownTimer),this.countdownTimer=window.setInterval(()=>{this.timers.length&&this.renderList()},1e3)}close(){this.overlay.classList.add(`hidden`),window.clearInterval(this.countdownTimer),this.countdownTimer=0}renderPermission(){this.permissionRow.replaceChildren();let e=U(`span`,`wd-perm-dot`),t=U(`span`,`wd-perm-text`),n=this.notifications.permission;if(n===`granted`)e.dataset.state=`on`,t.textContent=`Browser notifications are on.`,this.permissionRow.append(e,t);else if(n===`denied`)e.dataset.state=`off`,t.textContent=`Notifications are blocked — enable them in your browser settings.`,this.permissionRow.append(e,t);else if(n===`unsupported`)e.dataset.state=`off`,t.textContent=`This browser can't show notifications. Keep this page open for in-app alerts.`,this.permissionRow.append(e,t);else{e.dataset.state=`warn`,t.textContent=`Allow notifications to be alerted while this page is in the background.`;let n=U(`button`,`wd-btn wd-perm-enable`);n.append(U(`span`,`wd-btn-label`,`Enable`)),n.onclick=async()=>{await this.requestNotifications(),this.renderPermission()},this.permissionRow.append(e,t,n)}}renderList(){if(this.list.replaceChildren(),this.regions.length===0&&this.timers.length===0&&this.monitors.length===0){this.list.appendChild(U(`p`,`wd-dialog-help`,`No alerts, timers, or session monitors yet.`));return}for(let e of this.regions){let t=U(`div`,`wd-watch-row`),n=U(`button`,`wd-watch-name`,e.label);n.title=`Edit this alert`,n.onclick=()=>this.beginSelection(e),t.appendChild(n);let r=U(`button`,`wd-btn wd-icon-only`);r.appendChild(g(`trash`)),r.setAttribute(`aria-label`,`Remove ${e.label}`),r.onclick=()=>{this.conn.send({type:`watch-remove`,id:e.id}),this.regions=this.regions.filter(t=>t.id!==e.id),this.renderList()},t.appendChild(r),this.list.appendChild(t)}for(let e of this.timers){let t=U(`div`,`wd-watch-row`),n=U(`div`,`wd-timer-info`),r=U(`span`,`wd-timer-name`);r.append(g(`clock`,15),document.createTextNode(e.label));let i=U(`span`,`wd-timer-remain`,Te(e.fireAtMs));n.append(r,i),t.appendChild(n),e.hasAction&&t.appendChild(U(`span`,`wd-timer-tag`,`auto`));let a=U(`button`,`wd-btn wd-icon-only`);a.appendChild(g(`trash`)),a.setAttribute(`aria-label`,`Cancel ${e.label}`),a.onclick=()=>{this.conn.send({type:`timer-remove`,id:e.id}),this.timers=this.timers.filter(t=>t.id!==e.id),this.renderList()},t.appendChild(a),this.list.appendChild(t)}for(let e of this.monitors){let t=U(`div`,`wd-watch-row`),n=U(`div`,`wd-timer-info`),r=U(`span`,`wd-timer-name`);r.append(g(`activity`,15),document.createTextNode(`${W(e.agent)} · ${e.label}`));let i=U(`span`,`wd-mon-state`);i.dataset.state=e.live?e.state:`finished`,i.textContent=e.live?De(e.state):`ended`,n.append(r,i),t.appendChild(n);let a=U(`button`,`wd-btn wd-icon-only`);a.appendChild(g(`trash`)),a.setAttribute(`aria-label`,`Stop monitoring ${e.label}`),a.onclick=()=>{this.conn.send({type:`monitor-remove`,id:e.id}),this.monitors=this.monitors.filter(t=>t.id!==e.id),this.renderList()},t.appendChild(a),this.list.appendChild(t)}}beginSelection(e){this.close(),this.selector&&this.selector.remove();let t=this.root.getBoundingClientRect(),n=e?this.boxFromRegion(e,t):{x:t.width*.3,y:t.height*.3,w:t.width*.4,h:t.height*.25},r=U(`div`,`wd-selector-info`,e?`Move or resize the area to watch, then Save — you'll be alerted when its pixels change.`:`You'll get a browser notification when the pixels inside this box change. The agent watches this part of the screen.`),i=U(`div`,`wd-selector`),a=U(`div`,`wd-selector-move`);a.appendChild(g(`drag`));let o=U(`div`,`wd-selector-handle`),s=U(`div`,`wd-selector-bar`),c=U(`button`,`wd-btn wd-go`);c.append(U(`span`,`wd-btn-label`,e?`Save`:`Create`));let l=U(`button`,`wd-btn`);l.append(U(`span`,`wd-btn-label`,`Cancel`)),s.append(l,c),i.append(a,o,s),this.root.append(r,i),this.selector=i;let u=()=>{i.remove(),r.remove(),this.selector=null,this.open()},d=()=>{i.style.left=`${n.x}px`,i.style.top=`${n.y}px`,i.style.width=`${n.w}px`,i.style.height=`${n.h}px`};d();let f=(e,t)=>{e.addEventListener(`pointerdown`,n=>{n.preventDefault(),n.stopPropagation(),e.setPointerCapture(n.pointerId);let r=n.clientX,i=n.clientY,a=e=>{t(e.clientX-r,e.clientY-i),r=e.clientX,i=e.clientY,d()},o=()=>{e.removeEventListener(`pointermove`,a),e.removeEventListener(`pointerup`,o)};e.addEventListener(`pointermove`,a),e.addEventListener(`pointerup`,o)})};f(a,(e,r)=>{n.x=Math.max(0,Math.min(t.width-n.w,n.x+e)),n.y=Math.max(0,Math.min(t.height-n.h,n.y+r))}),f(o,(e,r)=>{n.w=Math.max(40,Math.min(t.width-n.x,n.w+e)),n.h=Math.max(40,Math.min(t.height-n.y,n.h+r))}),l.onclick=u,c.onclick=()=>{let t=this.toScreenRegion(n,e);t&&(this.conn.send({type:`watch-add`,region:t}),this.regions=e?this.regions.map(e=>e.id===t.id?t:e):[...this.regions,t],this.notifications.permission==="default"&&this.requestNotifications(),this.notifications.flash(e?`Alert updated`:`Alert created`,e?`"${t.label}" updated.`:`Monitoring "${t.label}". We'll notify you when it changes.`,`success`)),u()}}boxFromRegion(e,t){let n=this.view.normToCanvas(e.x,e.y),r=this.view.normToCanvas(e.x+e.w,e.y+e.h),i=Math.max(40,r.cx-n.cx),a=Math.max(40,r.cy-n.cy);return{x:Math.max(0,Math.min(t.width-i,n.cx)),y:Math.max(0,Math.min(t.height-a,n.cy)),w:i,h:a}}toScreenRegion(e,t){let n=this.view.canvasToNorm(e.x,e.y),r=this.view.canvasToNorm(e.x+e.w,e.y+e.h),i=Math.min(n.nx,r.nx),a=Math.min(n.ny,r.ny),o=Math.abs(r.nx-n.nx),s=Math.abs(r.ny-n.ny);return o<.005||s<.005?null:{id:t?.id??H(),label:t?.label??we(),x:i,y:a,w:o,h:s}}beginTimer(){this.close();let e=U(`div`,`wd-dialog-overlay`),t=()=>{e.remove(),this.open()};e.addEventListener(`pointerdown`,n=>{n.target===e&&t()});let n=U(`div`,`wd-dialog`),r=U(`div`,`wd-dialog-head`);r.append(U(`h2`,``,`Set timer`));let i=U(`button`,`wd-dialog-x`);i.appendChild(g(`x`)),i.onclick=t,r.appendChild(i);let a=U(`p`,`wd-dialog-help`,`Waiting for a session limit to reset? Get notified when the time's up. You can also schedule an action for the moment it hits zero — click Retry, or enter a new prompt.`),o=U(`div`,`wd-form-row`);o.appendChild(U(`label`,`wd-form-label`,`Remind me in`));let s=U(`input`,`wd-input wd-input-num`);s.type=`number`,s.min=`0`,s.max=`168`,s.value=`0`,s.inputMode=`numeric`;let c=U(`input`,`wd-input wd-input-num`);c.type=`number`,c.min=`0`,c.max=`59`,c.value=`30`,c.inputMode=`numeric`;let l=U(`div`,`wd-preset-row`);for(let[e,t,n]of[[`15m`,0,15],[`30m`,0,30],[`1h`,1,0],[`2h`,2,0],[`5h`,5,0]]){let r=U(`button`,`wd-preset`,e);r.type=`button`,r.onclick=()=>{s.value=String(t),c.value=String(n)},l.appendChild(r)}let u=(e,t,n,r)=>{let i=U(`div`,`wd-stepper`),a=U(`button`,`wd-step-btn`,`−`);a.type=`button`;let o=U(`button`,`wd-step-btn`,`+`);o.type=`button`;let s=e=>Math.max(0,Math.min(n,e));return a.onclick=()=>e.value=String(s((Number(e.value)||0)-t)),o.onclick=()=>e.value=String(s((Number(e.value)||0)+t)),i.append(a,e,U(`span`,`wd-form-unit`,r),o),i},d=U(`div`,`wd-form-duration`);d.append(u(s,1,168,`h`),u(c,5,59,`m`)),o.append(l,d);let f=U(`div`,`wd-form-row`);f.appendChild(U(`label`,`wd-form-label`,`Label`));let p=U(`input`,`wd-input`);p.placeholder=`e.g. Claude is back`,f.appendChild(p);let m=U(`div`,`wd-form-row`);m.appendChild(U(`label`,`wd-form-label`,`When it fires`));let h=U(`select`,`wd-input`);for(let[e,t]of[[`none`,`Just remind me`],[`click`,`Click a button`],[`key`,`Click & press Enter`],[`text`,`Click, type & send a prompt`]]){let n=document.createElement(`option`);n.value=e,n.textContent=t,h.appendChild(n)}m.appendChild(h);let _=U(`div`,`wd-dialog-actions`),v=U(`button`,`wd-btn`);v.append(U(`span`,`wd-btn-label`,`Cancel`)),v.onclick=t;let y=U(`button`,`wd-btn wd-go`),b=U(`span`,`wd-btn-label`,`Start timer`);y.append(g(`clock`),b);let x=()=>{b.textContent=h.value===`none`?`Start timer`:`Next: place target`};h.onchange=x,x();let S=()=>{let e=Math.max(0,Math.min(168,Math.round(Number(s.value)||0))),t=Math.max(0,Math.min(59,Math.round(Number(c.value)||0))),n=(e*60+t)*6e4;return n>=6e4?n:null},C=()=>{let e=Math.max(0,Math.round(Number(s.value)||0)),t=Math.max(0,Math.round(Number(c.value)||0));return`${e?`${e}h `:``}${t}m`},w=e=>{let n=H(),r=S(),i=p.value.trim()||`Timer (${C()})`;this.conn.send({type:`timer-add`,id:n,fireInMs:r,label:i,action:e}),this.timers=[...this.timers,{id:n,label:i,fireAtMs:Date.now()+r,hasAction:!!e}],this.notifications.permission==="default"&&this.requestNotifications(),this.notifications.flash(`Timer started`,`"${i}" — I'll ping you in ${C()}.`,`success`),t()};y.onclick=()=>{if(S()==null){this.notifications.flash(`Set a time`,`Choose at least 1 minute.`,`warning`);return}let t=h.value;if(t===`none`){w(void 0);return}e.style.display=`none`;let n=t===`text`?`Drag the crosshair onto the target input and type your prompt. The timer will click it to focus, insert the text and press Enter when time is up.`:t===`key`?`Drag the crosshair onto the field. The timer will click it to focus and press Enter when time is up.`:`Drag the crosshair onto the button or UI. The timer will click it when time is up.`;Se(this.view,this.root,{withText:t===`text`,hint:n,confirmLabel:`Confirm target`},n=>{if(!n){e.style.display=``;return}let r;r=t===`click`?{kind:`click`,x:n.nx,y:n.ny,button:`left`}:t===`key`?{kind:`key`,key:`Enter`,x:n.nx,y:n.ny}:{kind:`text`,text:n.text??``,x:n.nx,y:n.ny},w(r)})},_.append(v,y),n.append(r,a,o,f,m,_),e.appendChild(n),this.root.appendChild(e)}beginMonitor(){this.close();let e=U(`div`,`wd-dialog-overlay`),t=()=>{this.renderPicker=null,this.renderAlways=null,e.remove(),this.open()};e.addEventListener(`pointerdown`,n=>{n.target===e&&t()});let n=U(`div`,`wd-dialog`),r=U(`div`,`wd-dialog-head`);r.append(U(`h2`,``,`Monitor a session`));let i=U(`button`,`wd-dialog-x`);i.appendChild(g(`x`)),i.onclick=t,r.appendChild(i);let a=U(`p`,`wd-dialog-help`,`Pick a running AI session to watch. WhipDesk finds them automatically — no setup, no wrappers. You'll get one ping the moment the agent stops working (it's waiting on you or has gone idle).`),o=U(`div`,`wd-mon-pick-head`),s=U(`button`,`wd-btn`);s.append(U(`span`,`wd-btn-label`,`Rescan`)),s.onclick=()=>this.conn.send({type:`monitor-scan`}),o.append(U(`span`,`wd-form-label`,`Running sessions`),s);let c=U(`div`,`wd-mon-pick`),l=``,u=()=>{if(c.replaceChildren(),this.monitorSessions.length===0){l=``,v(),p(),c.appendChild(U(`p`,`wd-dialog-help`,`No AI sessions detected yet. Start Claude Code, Codex, Gemini, or Aider, then Rescan.`));return}(!l||!this.monitorSessions.some(e=>e.key===l))&&(l=this.monitorSessions[0].key);for(let e of this.monitorSessions){let t=U(`button`,`wd-mon-item`);t.type=`button`,e.key===l&&t.classList.add(`on`);let n=U(`div`,`wd-mon-item-main`);n.append(g(`activity`,15),U(`span`,`wd-mon-item-title`,`${W(e.agent)} · ${e.title}`));let r=U(`span`,`wd-mon-state`);r.dataset.state=e.state,r.textContent=De(e.state),t.append(n,r),t.onclick=()=>{l=e.key,u()},c.appendChild(t)}v(),p()};this.renderPicker=u;let d=U(`div`,`wd-form-row`);d.appendChild(U(`label`,`wd-form-label`,`Always alert me`));let f=U(`div`,`wd-mon-always`);d.appendChild(f);let p=()=>{f.replaceChildren();let e=this.monitorSessions.find(e=>e.key===l);if(!e){f.appendChild(U(`p`,`wd-dialog-help`,`Pick a session above to always alert for its agent.`));return}let t=e.agent,n=U(`label`,`wd-check`),r=U(`input`);r.type=`checkbox`,r.checked=this.alwaysAgents.has(t),r.onchange=()=>{r.checked?this.alwaysAgents.add(t):this.alwaysAgents.delete(t),this.conn.send({type:`monitor-always`,agent:t,enabled:r.checked}),r.checked&&this.notifications.permission==="default"&&this.requestNotifications(),p()};let i=U(`span`,`wd-check-text`);i.append(document.createTextNode(`Always monitor every ${W(t)} session`),U(`span`,`wd-check-sub`,`Keeps alerting across agent and WhipDesk restarts — no need to re-add it.`)),n.append(r,i),f.appendChild(n)};this.renderAlways=p;let m=U(`div`,`wd-dialog-actions`),h=U(`button`,`wd-btn`);h.append(U(`span`,`wd-btn-label`,`Cancel`)),h.onclick=t;let _=U(`button`,`wd-btn wd-go`);_.append(g(`activity`),U(`span`,`wd-btn-label`,`Add monitor`));let v=()=>_.disabled=!l;v(),_.onclick=()=>{let e=this.monitorSessions.find(e=>e.key===l);if(!e)return;let n=H(),r=e.title;this.conn.send({type:`monitor-add`,id:n,key:e.key,agent:e.agent,label:r}),this.monitors=[...this.monitors,{id:n,key:e.key,agent:e.agent,label:r,state:e.state,live:!0}],this.notifications.permission==="default"&&this.requestNotifications(),this.notifications.flash(`Monitoring started`,`Watching ${W(e.agent)} · ${r}.`,`success`),t()},m.append(h,_),n.append(r,a,o,c,d,m),e.appendChild(n),this.root.appendChild(e),u(),this.conn.send({type:`monitor-scan`})}};function ke(){let e=new URLSearchParams(location.hash.replace(/^#/,``));return{token:e.get(`t`)??e.get(`token`)??``,remote:e.get(`remote`)===`1`||e.has(`device`),device:e.get(`device`)??e.get(`d`)??``}}function Ae(){return`${location.protocol===`https:`?`wss`:`ws`}://${location.host}/ws`}async function je(){let e=window.__WHIPDESK_FB__;if(e?.apiKey)return e;try{let e=await fetch(`firebase.json`,{cache:`no-store`});if(e.ok)return await e.json()}catch{}return null}var G=document.getElementById(`app`);if(!G)throw Error(`#app not found`);var K=$(`canvas`,`wd-screen`);K.id=`wd-screen`;var Me=$(`div`,`wd-toasts`);G.append(K,Me);var{token:q,remote:J,device:Y}=ke(),X=new xe(K),Z=new oe(Me),Ne=new ce(G),Q=new p(G);async function Pe(e){if(J&&Y){if(e)return new he(Y,q,e);Z.show({type:`notification`,id:`no-fb`,title:`Remote unavailable`,body:`Firebase config not found for remote mode.`,level:`error`,source:`client`,t:Date.now()})}return new u(Ae(),q)}async function Fe(){let e=J&&Y?await je():null,t=await Pe(e),n=new ae(K,X,t),r=new Oe(G,t,X,Z,()=>e?fe(e,Z):Z.requestPermission()),i=new ne(G,{conn:t,view:X,input:n,notifications:Z,watchers:r}),a=document.createElement(`video`);a.muted=!0,a.autoplay=!0,a.playsInline=!0,a.setAttribute(`playsinline`,``),a.style.display=`none`,G.append(a);let o=document.createElement(`video`);o.muted=!0,o.autoplay=!0,o.playsInline=!0,o.setAttribute(`playsinline`,``),o.style.display=`none`,G.append(o);let s=!1,c=!1,l=null,u=0,d=e=>e.w>=.999&&e.h>=.999,f=null,p=0,m=0,h=!1,g=0,_=document.createElement(`div`);_.className=`wd-sharpen hidden`,_.setAttribute(`aria-label`,`updating view`),G.append(_);let v=()=>{h=!1,_.classList.add(`hidden`)},y=e=>{let n=e.w>=.92&&e.h>=.92?{x:0,y:0,w:1,h:1}:e,r=d(n);if(l){if(r&&d(l))return;if(!r){let e=.08;if(Math.abs(n.x-l.x)<n.w*e&&Math.abs(n.y-l.y)<n.h*e&&Math.abs(n.w-l.w)<n.w*e&&Math.abs(n.h-l.h)<n.h*e)return}}l=n,p=Date.now(),m=0,h=!f||!b(n,f),h&&(g=Date.now()),t.send({type:`set-viewport`,x:n.x,y:n.y,w:n.w,h:n.h})},b=(e,t)=>Math.abs(e.x-t.x)<.005&&Math.abs(e.y-t.y)<.005&&Math.abs(e.w-t.w)<.005&&Math.abs(e.h-t.h)<.005;window.setInterval(()=>{let e=Date.now()-g;if(_.classList.toggle(`hidden`,!(h&&e>1200&&e<3e4)),!(!l||!f)){if(b(f,l)){m=0;return}Date.now()-p<1200||m>=3||(m+=1,p=Date.now(),t.send({type:`set-viewport`,x:l.x,y:l.y,w:l.w,h:l.h}))}},1e3);let x=!1,S=!1,C=()=>{let e=X.getZoom()>1.01;window.clearTimeout(u),u=window.setTimeout(()=>{u=0,y(X.getZoom()>1.01?X.getVisibleRegion():{x:0,y:0,w:1,h:1})},e?400:0)};X.setOnView(()=>{x=!0,C()}),X.setOnGesture(e=>{e?(S=u!==0,S&&(window.clearTimeout(u),u=0),x=!1):!x&&S&&(S=!1,C())}),t.on(`status`,e=>{i.setStatus(e),e===`connected`?(c=!1,Q.hide()):(!s||c)&&Q.show(s?`Reconnecting…`:void 0),e===`disconnected`&&(l=null,f=null,v())}),t.on(`transport`,e=>i.setTransport(e)),t.on(`welcome`,e=>{let t=!s;s=!0,Q.hide(),Ne.hide(),X.setScreen(e.screen),i.setWelcome(e),t?(X.setZoom(1),l=null,y({x:0,y:0,w:1,h:1})):(l=null,window.clearTimeout(u),u=0,y(X.getZoom()>1.01?X.getVisibleRegion():{x:0,y:0,w:1,h:1}))}),t.on(`versionMismatch`,e=>Ie(e.agentVersion)),t.on(`pinRequired`,e=>{Q.hide(),Ne.show(e,e=>t.submitPin(e))}),t.on(`presence`,e=>i.setPresence(e));let w=0,T=0,E=0,D=()=>i.setAlertCount(w+T+E);if(t.on(`watchers`,e=>{w=e.length,r.setRegions(e),D()}),t.on(`timers`,e=>{T=e.length,r.setTimers(e),D()}),t.on(`monitors`,e=>{E=e.length,r.setMonitors(e),D()}),t.on(`monitorAlways`,e=>{r.setAlwaysAgents(e)}),t.on(`screenRegion`,e=>{f={x:e.x,y:e.y,w:e.w,h:e.h},e.active&&v();let t=d(e)?null:e;e.active?X.setFrameRegionActive(t):X.setFrameRegion(t)}),t.on(`videoTrack`,e=>{if(!e){a.srcObject=null,X.setVideoSource(null);return}a.srcObject=e,a.play().catch(()=>{}),X.setVideoSource(a)}),t.on(`overviewTrack`,e=>{if(!e){o.srcObject=null,X.setOverviewSource(null);return}o.srcObject=e,o.play().catch(()=>{}),X.setOverviewSource(o)}),t.on(`netStats`,({fps:e,rtt:t})=>i.setNetStats(e,t)),t.on(`screenMeta`,({screen:e,activeDisplay:t})=>{X.setScreen(e),t!==void 0&&i.setActiveDisplay(t)}),t.on(`notification`,e=>Z.show(e)),t.on(`error`,e=>i.flashError(e)),e){let n=!1;t.on(`welcome`,()=>{n||Z.permission!==`granted`||(n=!0,fe(e,Z))})}let O=()=>{document.hidden||t.isHealthy()||(c=!0,Q.show(`Reconnecting…`),t.wake())};document.addEventListener(`visibilitychange`,()=>{t.setVisible(!document.hidden),document.hidden||O()}),window.addEventListener(`pageshow`,O),window.addEventListener(`pagehide`,e=>{e.persisted||t.close()}),q||i.flashError(`No pairing token in the URL (#t=…). Re-open the link/QR from the agent.`),t.connect()}Fe();function $(e,t){let n=document.createElement(e);return n.className=t,n}function Ie(e){let t=`wd-outdated-banner`;if(document.getElementById(t))return;let n=document.createElement(`div`);n.id=t,n.style.cssText=`position:fixed;top:0;left:0;right:0;z-index:9999;background:#7a2e00;color:#fff;font:14px/1.4 system-ui,sans-serif;padding:10px 40px 10px 14px;text-align:center;box-shadow:0 2px 8px rgba(0,0,0,.35)`,n.innerHTML=`⚠️ This WhipDesk agent${e?` (agent ${e})`:``} is out of date. Update from <a style="color:#ffd9a6" href="https://github.com/BinaryBananaLLC/WhipDesk/releases/latest" target="_blank" rel="noreferrer noopener">the latest release</a> or run <code>npm i -g whipdesk@latest</code>.`;let r=document.createElement(`button`);r.textContent=`✕`,r.setAttribute(`aria-label`,`Dismiss`),r.style.cssText=`position:absolute;right:8px;top:6px;background:none;border:none;color:#fff;font-size:16px;cursor:pointer`,r.onclick=()=>n.remove(),n.appendChild(r),document.body.appendChild(n)}