dsh-mobile 0.3.12 → 0.3.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -19,6 +19,12 @@ window.__ModuleLoader__.load({
19
19
  updatingPlugin: "Updating…",
20
20
  pluginUpdatedRestart: "Updated to v{version}. Restart DSH to apply it.",
21
21
  pluginUpdateFailed: "Update failed: {error}",
22
+ updateTo: "Update to v{version}",
23
+ updateNotesHeading: "What’s new",
24
+ updateNotice: "Restart DSH after installing. Existing apps and paired devices need no re-pairing; unsure about the desktop version? Check the README compatibility table.",
25
+ updateNotesEmpty: "No release notes fetched — updating is still fine; full details on the GitHub Release page.",
26
+ updateNow: "Update now",
27
+ updateLater: "Not now",
22
28
  lan: "Local network",
23
29
  remote: "Remote",
24
30
  lanAccess: "Local network access",
@@ -153,12 +159,20 @@ window.__ModuleLoader__.load({
153
159
  resetTailscaleConfirm: "Sign out of Tailscale on this computer and remove all remote paired devices? Local network configuration is unchanged.",
154
160
  requestFailed: "Request failed: {error}",
155
161
  wsPathsTitle: "Third-party WebSocket paths",
156
- wsPathsIntro: "Let installed plugins’ WebSocket endpoints (exact paths such as /sidebar/ws/terminal) work through the gateway. Built-in DSH paths always work; everything else stays blocked.",
162
+ wsPathsIntro: "When an installed plugin cannot connect (say a sidebar terminal or a live panel), it is usually because its connection paths have not been approved yet. Everything that needs your attention is listed below — one click on “Allow” fixes it.",
157
163
  wsPathsPlaceholder: "/sidebar/ws/terminal",
158
164
  wsPathsAdd: "Allow path",
159
165
  wsPathsRemove: "Remove",
160
- wsPathsEmpty: "No extra paths allowed.",
161
- wsPathsInvalid: "Enter an exact path starting with / (no query string)."
166
+ wsPathsEmpty: "Nothing to configure right now. If a plugin cannot connect later, one-click options appear here.",
167
+ wsPathsInvalid: "Enter an exact path starting with / (no query string).",
168
+ wsPathsDetected: "A plugin connection was blocked — press Allow to let it through",
169
+ wsPathsAllow: "Allow",
170
+ wsPathsAllowAll: "Allow all",
171
+ wsPathsGroupMeta: "{n} paths · blocked {m} times",
172
+ wsPathsNewBlocked: "New blocked third-party connections — open diagnostics to review",
173
+ wsPathsAdvancedToggle: "Add paths manually (advanced)",
174
+ wsPathsAnnounce: "{n} plugin connections waiting to be approved",
175
+ wsPathsAdvancedHint: "Manual entries are rarely necessary: use the buttons above. Only fill this in when you know the exact path."
162
176
  },
163
177
  it: {
164
178
  mobileAccess: "Accesso mobile",
@@ -172,6 +186,12 @@ window.__ModuleLoader__.load({
172
186
  updatingPlugin: "Aggiornamento…",
173
187
  pluginUpdatedRestart: "Aggiornato alla v{version}. Riavvia DSH per applicarlo.",
174
188
  pluginUpdateFailed: "Aggiornamento non riuscito: {error}",
189
+ updateTo: "Aggiorna alla v{version}",
190
+ updateNotesHeading: "Novità",
191
+ updateNotice: "Riavvia DSH dopo l’installazione. Le app esistenti e i dispositivi già associati non richiedono ri-associazione; in caso di dubbi sulla versione desktop, consulta la tabella di compatibilità nel README.",
192
+ updateNotesEmpty: "Note di rilascio non recuperate — l’aggiornamento resta possibile; dettagli nella pagina Release su GitHub.",
193
+ updateNow: "Aggiorna ora",
194
+ updateLater: "Non ora",
175
195
  lan: "Rete locale",
176
196
  remote: "Remoto",
177
197
  lanAccess: "Accesso rete locale",
@@ -306,12 +326,20 @@ window.__ModuleLoader__.load({
306
326
  resetTailscaleConfirm: "Uscire da Tailscale su questo computer e rimuovere tutti i dispositivi remoti? La configurazione della rete locale resta invariata.",
307
327
  requestFailed: "Richiesta non riuscita: {error}",
308
328
  wsPathsTitle: "Percorsi WebSocket di terze parti",
309
- wsPathsIntro: "Consenti agli endpoint WebSocket dei plugin installati (percorsi esatti come /sidebar/ws/terminal) di passare dal gateway. I percorsi DSH integrati funzionano sempre; tutto il resto resta bloccato.",
329
+ wsPathsIntro: "Quando un plugin installato non riesce a connettersi (per esempio un terminale laterale o un pannello live), di solito è perché i suoi percorsi di connessione non sono ancora stati approvati. Tutto ciò che richiede attenzione è elencato qui sotto: un clic su “Consenti” risolve.",
310
330
  wsPathsPlaceholder: "/sidebar/ws/terminal",
311
331
  wsPathsAdd: "Consenti percorso",
312
332
  wsPathsRemove: "Rimuovi",
313
- wsPathsEmpty: "Nessun percorso aggiuntivo consentito.",
314
- wsPathsInvalid: "Inserisci un percorso esatto che inizi con / (senza query)."
333
+ wsPathsEmpty: "Non serve configurare nulla per ora. Se in seguito un plugin non riesce a connettersi, qui compariranno opzioni con un clic.",
334
+ wsPathsInvalid: "Inserisci un percorso esatto che inizi con / (senza query).",
335
+ wsPathsDetected: "Una connessione di un plugin è stata bloccata — premi Consenti per lasciarla passare",
336
+ wsPathsAllow: "Consenti",
337
+ wsPathsAllowAll: "Consenti tutti",
338
+ wsPathsGroupMeta: "{n} percorsi · bloccati {m} volte",
339
+ wsPathsNewBlocked: "Nuove connessioni di terze parti bloccate — apri la diagnostica",
340
+ wsPathsAdvancedToggle: "Aggiungi percorsi manualmente (avanzato)",
341
+ wsPathsAnnounce: "{n} connessioni di plugin in attesa di approvazione",
342
+ wsPathsAdvancedHint: "Le voci manuali servono raramente: usa i pulsanti qui sopra. Compila solo se conosci il percorso esatto."
315
343
  },
316
344
  zh: {}
317
345
  };
@@ -327,6 +355,12 @@ window.__ModuleLoader__.load({
327
355
  updatingPlugin: "正在更新…",
328
356
  pluginUpdatedRestart: "插件已更新至 v{version},重启 DSH 后生效。",
329
357
  pluginUpdateFailed: "更新失败:{error}",
358
+ updateTo: "更新到 v{version}",
359
+ updateNotesHeading: "更新内容",
360
+ updateNotice: "安装后需重启 DSH。现有 App 与已配对设备无需重新配对;电脑端版本不确定时,先对照 README 兼容表。",
361
+ updateNotesEmpty: "未取到最新版更新说明,仍可继续更新;详情见 GitHub Release 页。",
362
+ updateNow: "立即更新",
363
+ updateLater: "暂不",
330
364
  lan: "局域网",
331
365
  remote: "远程",
332
366
  lanAccess: "局域网访问",
@@ -461,12 +495,20 @@ window.__ModuleLoader__.load({
461
495
  resetTailscaleConfirm: "退出电脑上的 Tailscale 登录并移除所有远程配对设备?局域网配置不会改变。",
462
496
  requestFailed: "请求失败:{error}",
463
497
  wsPathsTitle: "第三方 WebSocket 路径",
464
- wsPathsIntro: "允许已装插件的 WebSocket 端点(确切路径,如 /sidebar/ws/terminal)经网关通行。DSH 内置路径始终可用,其余一律拦截。",
498
+ wsPathsIntro: "插件(如侧边栏终端、实时面板)连不上时,通常是它的连接路径还没放行。下面列出需要处理的项,点「允许」即可。",
465
499
  wsPathsPlaceholder: "/sidebar/ws/terminal",
466
500
  wsPathsAdd: "允许该路径",
467
501
  wsPathsRemove: "移除",
468
- wsPathsEmpty: "暂无额外允许的路径。",
469
- wsPathsInvalid: "请输入以 / 开头的确切路径(不带 query)。"
502
+ wsPathsEmpty: "目前无需任何设置。以后有插件连不上,会在这里出现可一键放行的选项。",
503
+ wsPathsInvalid: "请输入以 / 开头的确切路径(不带 query)。",
504
+ wsPathsDetected: "有插件连接被拦截——点「允许」放行",
505
+ wsPathsAllow: "允许",
506
+ wsPathsAllowAll: "全部允许",
507
+ wsPathsGroupMeta: "{n} 条路径 · 共拦截 {m} 次",
508
+ wsPathsNewBlocked: "发现被拦截的第三方连接,去诊断页查看",
509
+ wsPathsAdvancedToggle: "手动添加路径(高级)",
510
+ wsPathsAnnounce: "{n} 条插件连接等待放行",
511
+ wsPathsAdvancedHint: "通常不需要手动填写:用上方按钮即可。只有当你确切知道所需路径时才填。"
470
512
  });
471
513
  Object.assign(MOBILE_CONTROL_MESSAGES.en, {
472
514
  selfHostedConnections: "Self-hosted connection",
@@ -489,7 +531,6 @@ window.__ModuleLoader__.load({
489
531
  copyServerTemplate: "Copy server template",
490
532
  templateCopied: "Server template copied. Save frps.toml and the Caddy snippet on the VPS, then add the import line to the Caddyfile.",
491
533
  templateCopyFailed: "Could not copy the template. Check the four fields above.",
492
- vpsDeployTitle: "Deploy the VPS automatically",
493
534
  vpsDeployText: "Use an existing OpenSSH key or agent. The VPS must be Ubuntu/Debian with systemd; existing Caddy site configuration is never overwritten.",
494
535
  vpsDeployChangesTitle: "Automatic deployment will change the following on the VPS (manual template changes nothing by itself):",
495
536
  vpsDeployChangePackages: "Install Caddy from its official APT repository, plus a Python venv and Certbot for public-IPv4 certificates.",
@@ -578,7 +619,6 @@ window.__ModuleLoader__.load({
578
619
  copyServerTemplate: "Copia modello server",
579
620
  templateCopied: "Modello server copiato. Salva frps.toml e lo snippet Caddy sul VPS, poi aggiungi la riga import al Caddyfile.",
580
621
  templateCopyFailed: "Impossibile copiare il modello. Controlla i quattro campi sopra.",
581
- vpsDeployTitle: "Prepara automaticamente il VPS",
582
622
  vpsDeployText: "Usa una chiave OpenSSH o un agent esistente. Il VPS deve essere Ubuntu/Debian con systemd; una configurazione Caddy non vuota non viene sovrascritta.",
583
623
  vpsDeployChangesTitle: "Il deploy automatico modifica quanto segue sul VPS (il modello manuale da solo non cambia nulla):",
584
624
  vpsDeployChangePackages: "Installa Caddy dal repository APT ufficiale, più un venv Python e Certbot per i certificati IPv4 pubblici.",
@@ -667,7 +707,6 @@ window.__ModuleLoader__.load({
667
707
  copyServerTemplate: "复制手动部署模板",
668
708
  templateCopied: "服务器模板已复制,请在 VPS 上保存 frps.toml 和 Caddy 片段,并在 Caddyfile 里加一行 import。",
669
709
  templateCopyFailed: "无法复制模板,请检查上方连接信息。",
670
- vpsDeployTitle: "中转服务器部署",
671
710
  vpsDeployText: "填写 SSH 登录信息。服务器需为带 systemd 的 Ubuntu/Debian;不会覆盖已有的 Caddy 站点配置。",
672
711
  vpsDeployChangesTitle: "自动部署会在 VPS 上做这些改动(只复制手动模板不会改变任何东西):",
673
712
  vpsDeployChangePackages: "从官方 APT 源安装 Caddy,并安装 Python venv 与 Certbot(公网 IP 证书用)。",
@@ -1998,7 +2037,8 @@ window.__ModuleLoader__.load({
1998
2037
  updateAvailable: data.updateAvailable === true && latestVersion !== void 0,
1999
2038
  ...latestVersion === void 0 ? {} : { latestVersion },
2000
2039
  ...androidVersion === void 0 ? {} : { androidVersion },
2001
- androidDownloadUrl
2040
+ androidDownloadUrl,
2041
+ ...typeof data.releaseNotes === "string" && data.releaseNotes !== "" ? { releaseNotes: data.releaseNotes.slice(0, 4e3) } : {}
2002
2042
  };
2003
2043
  }
2004
2044
  async function requestJson(path, init, timeoutMs = CONTROL_REQUEST_TIMEOUT_MS) {
@@ -2073,6 +2113,22 @@ window.__ModuleLoader__.load({
2073
2113
  updatePlugin.type = "button";
2074
2114
  updatePlugin.textContent = t("updatePlugin");
2075
2115
  updatePlugin.hidden = true;
2116
+ const updateCard = element("div", "dsh-mobile-control__update-card");
2117
+ updateCard.hidden = true;
2118
+ const updateCardTitle = element("div", "dsh-mobile-control__update-card-title");
2119
+ const updateCardNotes = element("pre", "dsh-mobile-control__update-notes");
2120
+ updateCardNotes.setAttribute("tabindex", "0");
2121
+ const updateCardNotice = element("p", "dsh-mobile-control__update-notice");
2122
+ updateCardNotice.textContent = t("updateNotice");
2123
+ const updateActions = element("div", "dsh-mobile-control__update-actions");
2124
+ const updateNow = element("button", "dsh-mobile-control__primary");
2125
+ updateNow.type = "button";
2126
+ updateNow.textContent = t("updateNow");
2127
+ const updateLater = element("button", "dsh-mobile-control__secondary");
2128
+ updateLater.type = "button";
2129
+ updateLater.textContent = t("updateLater");
2130
+ updateActions.append(updateLater, updateNow);
2131
+ updateCard.append(updateCardTitle, updateCardNotes, updateCardNotice, updateActions);
2076
2132
  const diagnosticsEntry = element("button", "dsh-mobile-control__diagnostic-entry");
2077
2133
  diagnosticsEntry.type = "button";
2078
2134
  diagnosticsEntry.textContent = t("diagnostics");
@@ -2447,7 +2503,7 @@ window.__ModuleLoader__.load({
2447
2503
  frpConnectionGroup.append(frpConnectionSummary, frpStep1);
2448
2504
  const frpVpsGroup = element("details", "dsh-mobile-control__frp-group");
2449
2505
  const frpVpsSummary = element("summary");
2450
- frpVpsSummary.textContent = t("vpsDeployTitle");
2506
+ frpVpsSummary.textContent = t("frpStep2Title");
2451
2507
  frpVpsGroup.append(frpVpsSummary, frpStep2);
2452
2508
  const frpComponentGroup = element("details", "dsh-mobile-control__frp-group");
2453
2509
  const frpComponentSummary = element("summary");
@@ -2553,21 +2609,34 @@ window.__ModuleLoader__.load({
2553
2609
  wsPathsTitle.textContent = t("wsPathsTitle");
2554
2610
  const wsPathsIntro = element("p", "dsh-mobile-control__intro");
2555
2611
  wsPathsIntro.textContent = t("wsPathsIntro");
2612
+ const wsPathsDetected = element("div", "dsh-mobile-control__ws-paths-detected");
2613
+ wsPathsDetected.hidden = true;
2614
+ const wsPathsDetectedTitle = element("p", "dsh-mobile-control__ws-paths-detected-title");
2615
+ wsPathsDetectedTitle.textContent = t("wsPathsDetected");
2616
+ const wsPathsDetectedList = element("ul", "dsh-mobile-control__ws-paths-list");
2617
+ wsPathsDetected.append(wsPathsDetectedTitle, wsPathsDetectedList);
2556
2618
  const wsPathsList = element("ul", "dsh-mobile-control__ws-paths-list");
2619
+ const wsPathsAdvanced = element("details", "dsh-mobile-control__ws-paths-advanced");
2620
+ const wsPathsAdvancedSummary = element("summary");
2621
+ wsPathsAdvancedSummary.textContent = t("wsPathsAdvancedToggle");
2622
+ const wsPathsAdvancedHint = element("p", "dsh-mobile-control__intro");
2623
+ wsPathsAdvancedHint.textContent = t("wsPathsAdvancedHint");
2557
2624
  const wsPathsRow = element("div", "dsh-mobile-control__ws-paths-row");
2558
2625
  const wsPathsInput = element("input", "dsh-mobile-control__ws-paths-input");
2559
2626
  wsPathsInput.type = "text";
2560
2627
  wsPathsInput.placeholder = t("wsPathsPlaceholder");
2561
2628
  wsPathsInput.setAttribute("aria-label", t("wsPathsTitle"));
2562
- const wsPathsAdd = element("button", "dsh-mobile-control__secondary");
2629
+ const wsPathsAdd = element("button", "dsh-mobile-control__primary");
2563
2630
  wsPathsAdd.type = "button";
2564
2631
  wsPathsAdd.textContent = t("wsPathsAdd");
2565
2632
  const wsPathsStatus = element("p", "dsh-mobile-control__status");
2566
2633
  wsPathsStatus.hidden = true;
2567
2634
  wsPathsStatus.setAttribute("aria-live", "polite");
2568
2635
  wsPathsRow.append(wsPathsInput, wsPathsAdd);
2569
- wsPathsSection.append(wsPathsTitle, wsPathsIntro, wsPathsList, wsPathsRow, wsPathsStatus);
2636
+ wsPathsAdvanced.append(wsPathsAdvancedSummary, wsPathsAdvancedHint, wsPathsRow, wsPathsStatus);
2637
+ wsPathsSection.append(wsPathsTitle, wsPathsIntro, wsPathsDetected, wsPathsList, wsPathsAdvanced);
2570
2638
  let wsPathsCurrent = [];
2639
+ let wsPathsBlocked = [];
2571
2640
  let wsPathsLoaded = false;
2572
2641
  const renderWsPaths = (paths) => {
2573
2642
  wsPathsCurrent = [...paths];
@@ -2592,11 +2661,103 @@ window.__ModuleLoader__.load({
2592
2661
  wsPathsList.append(item);
2593
2662
  }
2594
2663
  };
2664
+ const wsGroupOf = (path) => {
2665
+ const slash = path.lastIndexOf("/");
2666
+ return slash > 0 ? path.slice(0, slash) : "/";
2667
+ };
2668
+ let wsPathsSeenAttempts = 0;
2669
+ let wsDotAnnounced = 0;
2670
+ const wsDotStatus = element("p", "dsh-mobile-control__ws-sr-status");
2671
+ wsDotStatus.setAttribute("role", "status");
2672
+ wsDotStatus.setAttribute("aria-atomic", "true");
2673
+ const wsBlockedTotal = (blocked) => blocked.reduce((sum, entry) => sum + entry.attempts, 0);
2674
+ const renderWsDot = () => {
2675
+ for (const stale of document.querySelectorAll(".dsh-mobile-control__ws-dot")) stale.remove();
2676
+ if (!wsDotStatus.isConnected) root.append(wsDotStatus);
2677
+ const pendingCount = wsPathsBlocked.filter((entry) => !wsPathsCurrent.includes(entry.path)).length;
2678
+ if (pendingCount === 0 || wsBlockedTotal(wsPathsBlocked) <= wsPathsSeenAttempts) {
2679
+ if (pendingCount === 0 && wsDotAnnounced !== 0) {
2680
+ wsDotAnnounced = 0;
2681
+ wsDotStatus.textContent = "";
2682
+ }
2683
+ return;
2684
+ }
2685
+ if (wsDotAnnounced !== pendingCount) {
2686
+ wsDotAnnounced = pendingCount;
2687
+ wsDotStatus.textContent = t("wsPathsAnnounce", { n: String(pendingCount) });
2688
+ }
2689
+ for (const trigger of document.querySelectorAll(".dsh-mobile-control__trigger, .dsh-mobile-control__diagnostic-entry")) {
2690
+ const dot = element("span", "dsh-mobile-control__ws-dot");
2691
+ dot.textContent = String(pendingCount);
2692
+ dot.title = t("wsPathsNewBlocked");
2693
+ dot.setAttribute("aria-hidden", "true");
2694
+ dot.addEventListener("click", (event) => {
2695
+ event.stopPropagation();
2696
+ setOpen(true);
2697
+ selectView("diagnostics");
2698
+ });
2699
+ trigger.append(dot);
2700
+ }
2701
+ };
2702
+ const renderWsBlocked = (blocked) => {
2703
+ wsPathsDetectedList.replaceChildren();
2704
+ const pending = blocked.filter((entry) => !wsPathsCurrent.includes(entry.path));
2705
+ wsPathsDetected.hidden = pending.length === 0;
2706
+ const groups = /* @__PURE__ */ new Map();
2707
+ for (const entry of pending) {
2708
+ const group = wsGroupOf(entry.path);
2709
+ const list = groups.get(group);
2710
+ if (list) list.push(entry);
2711
+ else groups.set(group, [entry]);
2712
+ }
2713
+ for (const [group, entries] of groups) {
2714
+ const groupItem = element("li", "dsh-mobile-control__ws-paths-group");
2715
+ const groupHead = element("div", "dsh-mobile-control__ws-paths-group-head");
2716
+ const groupLabel = element("code");
2717
+ groupLabel.textContent = `${group}/*`;
2718
+ const groupCount = element("span", "dsh-mobile-control__ws-count");
2719
+ groupCount.textContent = t("wsPathsGroupMeta", {
2720
+ n: entries.length,
2721
+ m: entries.reduce((sum, entry) => sum + entry.attempts, 0)
2722
+ });
2723
+ groupHead.append(groupLabel, groupCount);
2724
+ if (entries.length > 1) {
2725
+ const allowAll = element("button", "dsh-mobile-control__primary");
2726
+ allowAll.type = "button";
2727
+ allowAll.textContent = t("wsPathsAllowAll");
2728
+ allowAll.addEventListener("click", () => {
2729
+ saveWsPaths([...wsPathsCurrent, ...entries.map((entry) => entry.path)]);
2730
+ });
2731
+ groupHead.append(allowAll);
2732
+ }
2733
+ groupItem.append(groupHead);
2734
+ for (const entry of entries) {
2735
+ const item = element("div", "dsh-mobile-control__ws-paths-item is-child");
2736
+ const label = element("code");
2737
+ label.textContent = `${entry.path} ×${String(entry.attempts)}`;
2738
+ const allow = element("button", "dsh-mobile-control__primary");
2739
+ allow.type = "button";
2740
+ allow.textContent = t("wsPathsAllow");
2741
+ allow.setAttribute("aria-label", `${t("wsPathsAllow")}: ${entry.path}`);
2742
+ allow.addEventListener("click", () => {
2743
+ saveWsPaths([...wsPathsCurrent, entry.path]);
2744
+ });
2745
+ item.append(label, allow);
2746
+ groupItem.append(item);
2747
+ }
2748
+ wsPathsDetectedList.append(groupItem);
2749
+ }
2750
+ renderWsDot();
2751
+ };
2595
2752
  const loadWsPaths = () => {
2596
2753
  controlRequestJson("/api/mobile-access/remote/websocket-paths").then((data) => {
2597
2754
  wsPathsLoaded = true;
2598
2755
  wsPathsStatus.hidden = true;
2599
2756
  renderWsPaths(Array.isArray(data.paths) ? data.paths.filter((entry) => typeof entry === "string") : []);
2757
+ controlRequestJson("/api/mobile-access/remote/websocket-paths/blocked").then((blocked) => {
2758
+ wsPathsBlocked = (Array.isArray(blocked.blocked) ? blocked.blocked : []).filter((entry) => typeof entry === "object" && entry !== null && typeof entry.path === "string" && typeof entry.attempts === "number");
2759
+ renderWsBlocked(wsPathsBlocked);
2760
+ }, () => {});
2600
2761
  }, (error) => {
2601
2762
  wsPathsStatus.hidden = false;
2602
2763
  wsPathsStatus.textContent = t("requestFailed", { error: String(error) });
@@ -2610,6 +2771,7 @@ window.__ModuleLoader__.load({
2610
2771
  }).then((data) => {
2611
2772
  wsPathsLoaded = true;
2612
2773
  renderWsPaths(Array.isArray(data.paths) ? data.paths.filter((entry) => typeof entry === "string") : []);
2774
+ renderWsBlocked(wsPathsBlocked);
2613
2775
  }, (error) => {
2614
2776
  wsPathsStatus.hidden = false;
2615
2777
  wsPathsStatus.textContent = t("requestFailed", { error: String(error) });
@@ -2626,7 +2788,7 @@ window.__ModuleLoader__.load({
2626
2788
  saveWsPaths([...wsPathsCurrent, value]);
2627
2789
  });
2628
2790
  const remoteWorkspace = element("section", "dsh-mobile-control__remote-workspace");
2629
- remoteWorkspace.append(providerSetupHeader, remoteStatus, remoteAccess, remoteGuide, providerSetupBody, remoteActions, remoteQr, remoteManageRow, remoteDevicePanel, wsPathsSection);
2791
+ remoteWorkspace.append(providerSetupHeader, remoteStatus, remoteAccess, remoteGuide, providerSetupBody, remoteActions, remoteQr, remoteManageRow, remoteDevicePanel);
2630
2792
  const diagnosticsView = element("div", "dsh-mobile-control__view is-diagnostics");
2631
2793
  diagnosticsView.hidden = true;
2632
2794
  const diagnosticsIntro = element("p", "dsh-mobile-control__intro");
@@ -2672,8 +2834,8 @@ window.__ModuleLoader__.load({
2672
2834
  actions.append(toggle, pair, linkPair);
2673
2835
  lanView.append(access, qrBox, status, extensionStatus, actions, manageRow, devicePanel);
2674
2836
  remoteView.append(remoteIntro, providerSection, remoteWorkspace);
2675
- diagnosticsView.append(diagnosticsIntro, diagnosticsSummary, diagnosticsToolbar, diagnosticsFeedback, diagnosticsChecks, diagnosticsDetails);
2676
- panel.append(header, releaseNotice, appDownload, switcher, lanView, remoteView, diagnosticsView);
2837
+ diagnosticsView.append(diagnosticsIntro, diagnosticsSummary, diagnosticsToolbar, diagnosticsFeedback, diagnosticsChecks, wsPathsSection, diagnosticsDetails);
2838
+ panel.append(header, releaseNotice, updateCard, appDownload, switcher, lanView, remoteView, diagnosticsView);
2677
2839
  root.append(panel);
2678
2840
  document.body.append(root);
2679
2841
  let running = false;
@@ -2703,11 +2865,14 @@ window.__ModuleLoader__.load({
2703
2865
  let copiedDiagnosticReport = "";
2704
2866
  let pluginUpdateAvailable = false;
2705
2867
  let pluginLatestVersion = "";
2868
+ let pluginReleaseNotes = "";
2869
+ let updateInFlight = false;
2706
2870
  const renderRelease = (data) => {
2707
2871
  const release = clientReleaseInfo(data);
2708
2872
  pluginUpdateAvailable = release.updateAvailable;
2709
2873
  pluginLatestVersion = release.latestVersion ?? "";
2710
- updatePlugin.hidden = !pluginUpdateAvailable || !diagnosticsView.hidden;
2874
+ pluginReleaseNotes = release.releaseNotes ?? "";
2875
+ updatePlugin.hidden = !pluginUpdateAvailable || !diagnosticsView.hidden || !updateCard.hidden;
2711
2876
  updatePlugin.textContent = t("updatePlugin");
2712
2877
  if (pluginLatestVersion !== "") updatePlugin.setAttribute("aria-label", t("updatePluginAria", { version: pluginLatestVersion }));
2713
2878
  if (release.androidVersion !== void 0) {
@@ -2756,6 +2921,11 @@ window.__ModuleLoader__.load({
2756
2921
  diagnosticsEntry.setAttribute("aria-pressed", String(view === "diagnostics"));
2757
2922
  diagnosticsEntry.textContent = view === "diagnostics" ? t("back") : t("diagnostics");
2758
2923
  diagnosticsEntry.setAttribute("aria-label", view === "diagnostics" ? t("backToMobile") : t("openDiagnostics"));
2924
+ if (view === "diagnostics") {
2925
+ wsPathsSeenAttempts = wsBlockedTotal(wsPathsBlocked);
2926
+ renderWsDot();
2927
+ if (!wsPathsLoaded) loadWsPaths();
2928
+ }
2759
2929
  updatePlugin.hidden = view === "diagnostics" || !pluginUpdateAvailable;
2760
2930
  appDownload.hidden = view === "diagnostics";
2761
2931
  switcher.hidden = view === "diagnostics";
@@ -2767,7 +2937,6 @@ window.__ModuleLoader__.load({
2767
2937
  remoteTab.addEventListener("click", () => {
2768
2938
  selectView("remote");
2769
2939
  loadRemote();
2770
- if (!wsPathsLoaded) loadWsPaths();
2771
2940
  });
2772
2941
  const setOpen = (open) => {
2773
2942
  panel.hidden = !open;
@@ -2984,7 +3153,7 @@ window.__ModuleLoader__.load({
2984
3153
  if (!frpLayoutInitialized) {
2985
3154
  frpConnectionGroup.open = !frpConfigured;
2986
3155
  frpComponentGroup.open = !frpInstalled;
2987
- frpVpsGroup.open = false;
3156
+ frpVpsGroup.open = !frpConfigured;
2988
3157
  frpLayoutInitialized = true;
2989
3158
  }
2990
3159
  selfHostedBadge.textContent = frpConfigured && frpInstalled ? t("ready") : t("advanced");
@@ -3836,10 +4005,16 @@ window.__ModuleLoader__.load({
3836
4005
  loadDiagnostics();
3837
4006
  });
3838
4007
  diagnosticsRun.addEventListener("click", loadDiagnostics);
3839
- updatePlugin.addEventListener("click", () => {
3840
- if (!pluginUpdateAvailable || pluginLatestVersion === "") return;
3841
- updatePlugin.disabled = true;
3842
- updatePlugin.textContent = t("updatingPlugin");
4008
+ const closeUpdateCard = () => {
4009
+ updateCard.hidden = true;
4010
+ if (pluginUpdateAvailable && pluginLatestVersion !== "") updatePlugin.hidden = !diagnosticsView.hidden;
4011
+ };
4012
+ const runPluginUpdate = () => {
4013
+ if (!pluginUpdateAvailable || pluginLatestVersion === "" || updateInFlight) return;
4014
+ updateInFlight = true;
4015
+ updateNow.disabled = true;
4016
+ updateLater.disabled = true;
4017
+ updateCardTitle.textContent = t("updatingPlugin");
3843
4018
  releaseNotice.hidden = true;
3844
4019
  releaseNotice.classList.remove("is-error");
3845
4020
  controlRequestJson("/api/mobile-access/release/update", {
@@ -3848,18 +4023,32 @@ window.__ModuleLoader__.load({
3848
4023
  }, LONG_CONTROL_REQUEST_TIMEOUT_MS).then((data) => {
3849
4024
  const installedVersion = releaseVersion(data.installedVersion) ?? pluginLatestVersion;
3850
4025
  pluginUpdateAvailable = false;
4026
+ updateCard.hidden = true;
3851
4027
  updatePlugin.hidden = true;
3852
4028
  releaseNotice.textContent = t("pluginUpdatedRestart", { version: installedVersion });
3853
4029
  releaseNotice.hidden = false;
3854
4030
  }, (error) => {
3855
- updatePlugin.textContent = t("updatePlugin");
4031
+ updateCard.hidden = true;
4032
+ updatePlugin.hidden = false;
3856
4033
  releaseNotice.textContent = t("pluginUpdateFailed", { error: String(error) });
3857
4034
  releaseNotice.classList.add("is-error");
3858
4035
  releaseNotice.hidden = false;
3859
4036
  }).finally(() => {
3860
- updatePlugin.disabled = false;
4037
+ updateInFlight = false;
4038
+ updateNow.disabled = false;
4039
+ updateLater.disabled = false;
3861
4040
  });
4041
+ };
4042
+ updatePlugin.addEventListener("click", () => {
4043
+ if (!pluginUpdateAvailable || pluginLatestVersion === "" || updateInFlight) return;
4044
+ updatePlugin.hidden = true;
4045
+ updateCardTitle.textContent = t("updateTo", { version: pluginLatestVersion });
4046
+ updateCardNotes.textContent = pluginReleaseNotes === "" ? t("updateNotesEmpty") : pluginReleaseNotes;
4047
+ updateCardNotes.hidden = pluginReleaseNotes === "";
4048
+ updateCard.hidden = false;
3862
4049
  });
4050
+ updateNow.addEventListener("click", runPluginUpdate);
4051
+ updateLater.addEventListener("click", closeUpdateCard);
3863
4052
  diagnosticsCopy.addEventListener("click", () => {
3864
4053
  if (copiedDiagnosticReport === "") return;
3865
4054
  navigator.clipboard.writeText(copiedDiagnosticReport).then(() => {
@@ -3900,10 +4089,19 @@ window.__ModuleLoader__.load({
3900
4089
  const remotePoll = window.setInterval(() => {
3901
4090
  if (!panel.hidden && !remoteView.hidden) loadRemote();
3902
4091
  }, 1500);
4092
+ const pollWsBlocked = () => {
4093
+ controlRequestJson("/api/mobile-access/remote/websocket-paths/blocked").then((blocked) => {
4094
+ wsPathsBlocked = (Array.isArray(blocked.blocked) ? blocked.blocked : []).filter((entry) => typeof entry === "object" && entry !== null && typeof entry.path === "string" && typeof entry.attempts === "number");
4095
+ renderWsDot();
4096
+ if (!diagnosticsView.hidden) renderWsBlocked(wsPathsBlocked);
4097
+ }, () => {});
4098
+ };
4099
+ const wsBlockedPoll = window.setInterval(pollWsBlocked, 2e4);
3903
4100
  return {
3904
4101
  remove: () => {
3905
4102
  lifecycle.abort();
3906
4103
  window.clearInterval(remotePoll);
4104
+ window.clearInterval(wsBlockedPoll);
3907
4105
  window.removeEventListener("focus", retryAfterSetup);
3908
4106
  document.removeEventListener("visibilitychange", retryAfterSetup);
3909
4107
  document.removeEventListener("pointerdown", dismiss);
@@ -5082,12 +5280,12 @@ window.__ModuleLoader__.load({
5082
5280
  .dsh-mobile-control{position:fixed;z-index:1000;left:16px;bottom:112px;font:14px/1.45 system-ui;color:var(--dsw-alias-label-primary,#16181d)}
5083
5281
  .dsh-mobile-control__panel{box-sizing:border-box;width:min(380px,calc(100vw - 32px));max-height:calc(100vh - 140px);overflow-y:auto;padding:16px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:18px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 18px 50px rgb(15 23 42 / 18%)}
5084
5282
  .dsh-mobile-control__header{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}.dsh-mobile-control__panel h2{margin:0;font-size:17px;line-height:24px}.dsh-mobile-control__header-actions{display:flex;align-items:center;gap:2px}.dsh-mobile-control__update-plugin,.dsh-mobile-control__diagnostic-entry,.dsh-mobile-control__close{display:inline-flex;align-items:center;justify-content:center;min-width:44px;height:44px;padding:0;border:0;border-radius:10px;background:transparent;color:inherit;cursor:pointer}.dsh-mobile-control__update-plugin,.dsh-mobile-control__diagnostic-entry{padding:0 8px;color:#2563eb;font:650 12px/1 system-ui;white-space:nowrap}.dsh-mobile-control__update-plugin[hidden]{display:none}.dsh-mobile-control__update-plugin:disabled{cursor:wait;opacity:.55}.dsh-mobile-control__close{font-size:24px;line-height:1}.dsh-mobile-control__update-plugin:hover:not(:disabled),.dsh-mobile-control__diagnostic-entry:hover,.dsh-mobile-control__close:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}
5085
- .dsh-mobile-control__release-notice{margin:-2px 0 10px;padding:8px 10px;border-radius:9px;background:var(--dsw-alias-bg-layer-1,#eff6ff);color:var(--dsw-alias-label-primary,#1d4ed8);font-size:11px;line-height:1.45}.dsh-mobile-control__release-notice.is-error{color:#dc2626}.dsh-mobile-control__release-notice[hidden]{display:none}.dsh-mobile-control__app-download{display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;min-height:38px;margin:0 0 10px;padding:8px 11px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#f7f8fa);color:var(--dsw-alias-label-primary,#16181d);font:600 12px/1.3 system-ui;text-decoration:none}.dsh-mobile-control__app-download[hidden]{display:none}.dsh-mobile-control__app-download::after{color:#2563eb;font-size:14px;content:"↗"}.dsh-mobile-control__app-download:hover{border-color:#9fb9e8;background:var(--dsw-alias-interactive-bg-hover-solid,var(--dsw-alias-bg-layer-2,#f5f8ff));color:var(--dsw-alias-label-primary,#1d4ed8)}
5283
+ .dsh-mobile-control__release-notice{margin:-2px 0 10px;padding:8px 10px;border-radius:9px;background:var(--dsw-alias-bg-layer-1,#eff6ff);color:var(--dsw-alias-label-primary,#1d4ed8);font-size:11px;line-height:1.45}.dsh-mobile-control__release-notice.is-error{color:#dc2626}.dsh-mobile-control__release-notice[hidden]{display:none}.dsh-mobile-control__update-card{margin:0 0 10px;padding:11px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:12px;background:var(--dsw-alias-bg-layer-1,#f8fafc)}.dsh-mobile-control__update-card[hidden]{display:none}.dsh-mobile-control__update-card-title{margin:0 0 7px;color:var(--dsw-alias-label-primary,#16181d);font:650 13px/1.4 system-ui}.dsh-mobile-control__update-notes{display:block;box-sizing:border-box;max-height:150px;overflow-y:auto;margin:0 0 8px;padding:8px 10px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:9px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-secondary,#475569);white-space:pre-wrap;word-break:break-word;font:11px/1.5 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}.dsh-mobile-control__update-notes[hidden]{display:none}.dsh-mobile-control__update-notice{margin:0 0 9px;padding:7px 9px;border-radius:8px;background:#fff4d6;color:#92400e;font-size:11px;line-height:1.5}.dsh-mobile-control__update-actions{display:flex;align-items:center;justify-content:flex-end;gap:8px}.dsh-mobile-control__update-actions .dsh-mobile-control__primary,.dsh-mobile-control__update-actions .dsh-mobile-control__secondary{min-height:34px;padding:0 12px}.dsh-mobile-control__app-download{display:flex;align-items:center;justify-content:space-between;box-sizing:border-box;min-height:38px;margin:0 0 10px;padding:8px 11px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#f7f8fa);color:var(--dsw-alias-label-primary,#16181d);font:600 12px/1.3 system-ui;text-decoration:none}.dsh-mobile-control__app-download[hidden]{display:none}.dsh-mobile-control__app-download::after{color:#2563eb;font-size:14px;content:"↗"}.dsh-mobile-control__app-download:hover{border-color:#9fb9e8;background:var(--dsw-alias-interactive-bg-hover-solid,var(--dsw-alias-bg-layer-2,#f5f8ff));color:var(--dsw-alias-label-primary,#1d4ed8)}
5086
5284
  .dsh-mobile-control__switcher{display:grid;grid-template-columns:repeat(2,1fr);gap:4px;margin:0 0 14px;padding:4px;border-radius:12px;background:var(--dsw-alias-bg-layer-1,#f3f5f8)}.dsh-mobile-control__switcher[hidden]{display:none}.dsh-mobile-control__tab{min-height:36px;border:0;border-radius:9px;background:transparent;color:var(--dsw-alias-label-secondary,#606873);font:600 13px/1 system-ui;cursor:pointer}.dsh-mobile-control__tab.is-active{background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);box-shadow:0 1px 3px rgb(15 23 42 / 10%)}.dsh-mobile-control__view[hidden]{display:none}.dsh-mobile-control__intro{margin:0 0 12px;color:var(--dsw-alias-label-secondary,#606873);font-size:12px;line-height:1.55}.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions{display:grid;grid-template-columns:1fr 1fr;gap:8px}.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions button[hidden]{display:none}
5087
5285
  .dsh-mobile-control__provider-section{position:relative;margin:0 0 14px}.dsh-mobile-control__section-title{margin:0 0 8px;color:var(--dsw-alias-label-primary,#16181d);font:650 13px/1.4 system-ui}.dsh-mobile-control__provider-section>.dsh-mobile-control__section-title{padding-right:42px}.dsh-mobile-control__provider-choices{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}.dsh-mobile-control__provider{display:flex;min-width:0;flex-direction:column;gap:6px;min-height:94px;padding:10px 11px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);text-align:left;cursor:pointer;touch-action:manipulation;transition:border-color 160ms ease,background-color 160ms ease,box-shadow 160ms ease}.dsh-mobile-control__provider:hover{border-color:#6f96db;background:var(--dsw-alias-interactive-bg-hover-solid,var(--dsw-alias-bg-layer-1,#f8fbff))}.dsh-mobile-control__provider.is-selected{border-color:#2563eb;background:var(--dsw-alias-interactive-bg-active,var(--dsw-alias-bg-layer-1,#f5f8ff));box-shadow:0 0 0 1px #2563eb inset}.dsh-mobile-control__provider:disabled{cursor:wait;opacity:.62}.dsh-mobile-control__provider-top{display:flex;min-width:0;align-items:flex-start;justify-content:space-between;gap:5px}.dsh-mobile-control__provider-top strong{min-width:0;font-size:12px;line-height:1.3}.dsh-mobile-control__provider-badge{flex:none;padding:2px 5px;border-radius:999px;background:#e8f0ff;color:#1d4ed8;font:650 9px/1.25 system-ui}.dsh-mobile-control__provider-badge.is-cpolar{background:#eaf8f2;color:#087454}.dsh-mobile-control__provider-description{color:var(--dsw-alias-label-secondary,#606873);font-size:10px;line-height:1.45}.dsh-mobile-control__provider-info{position:absolute;z-index:5;top:-13px;right:-8px}.dsh-mobile-control__provider-info-button{display:flex;align-items:center;justify-content:center;width:44px;height:44px;padding:0;border:0;border-radius:50%;background:transparent;color:var(--dsw-alias-label-secondary,#475569);cursor:pointer;touch-action:manipulation}.dsh-mobile-control__provider-info-button:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f5f9);color:#2563eb}.dsh-mobile-control__provider-info-glyph{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:18px;height:18px;border:1.5px solid currentColor;border-radius:50%;font:700 12px/1 system-ui}.dsh-mobile-control__provider-info-popover{position:absolute;z-index:6;top:38px;right:4px;box-sizing:border-box;width:min(292px,calc(100vw - 72px));padding:10px 12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#fff);box-shadow:0 10px 28px rgb(15 23 42 / 16%)}.dsh-mobile-control__provider-info-popover[hidden]{display:none}.dsh-mobile-control__provider-info-popover strong,.dsh-mobile-control__provider-info-popover span{display:block}.dsh-mobile-control__provider-info-popover strong{margin-bottom:3px;font-size:12px}.dsh-mobile-control__provider-info-popover span{color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.55}
5088
5286
  .dsh-mobile-control__self-hosted{margin:8px 0 0;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:12px;background:var(--dsw-alias-bg-layer-1,#f8fafc)}.dsh-mobile-control__self-hosted-summary{display:flex;box-sizing:border-box;min-height:48px;align-items:center;justify-content:space-between;gap:10px;padding:8px 11px;cursor:pointer;list-style-position:inside}.dsh-mobile-control__self-hosted-summary>span:first-child{display:flex;min-width:0;flex-direction:column;gap:1px}.dsh-mobile-control__self-hosted-summary strong{font-size:11px}.dsh-mobile-control__self-hosted-summary span span{color:var(--dsw-alias-label-secondary,#606873);font-size:9px;line-height:1.35}.dsh-mobile-control__provider-badge.is-frp{background:#eef0f3;color:#475569}.dsh-mobile-control__self-hosted-body{padding:0 8px 8px}.dsh-mobile-control__provider.is-frp{width:100%;min-height:64px;background:var(--dsw-alias-bg-layer-2,#fff)}
5089
5287
  .dsh-mobile-control__cpolar-setup{margin:0 0 12px;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__cpolar-setup[hidden],.dsh-mobile-control__cpolar-account[hidden],.dsh-mobile-control__details[hidden],.dsh-mobile-control__view.is-remote .dsh-mobile-control__actions[hidden],.dsh-mobile-control__danger[hidden]{display:none}.dsh-mobile-control__component-status,.dsh-mobile-control__component-note{margin:0 0 10px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.55}.dsh-mobile-control__cpolar-setup>.dsh-mobile-control__primary{width:100%;min-height:44px;padding:9px 12px;border-radius:10px;font:600 12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__cpolar-account{margin-top:10px}.dsh-mobile-control__link-row{display:flex;flex-wrap:wrap;gap:6px 12px;margin:0 0 10px}.dsh-mobile-control__text-link{color:#2563eb;font-size:11px;text-decoration:none}.dsh-mobile-control__text-link:hover{text-decoration:underline}.dsh-mobile-control__token-label{display:flex;flex-direction:column;gap:5px;margin:0 0 8px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px}.dsh-mobile-control__token{box-sizing:border-box;width:100%;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-bg-layer-2,#fff));color:var(--dsw-alias-label-primary,#16181d);font:16px/1.4 system-ui}.dsh-mobile-control__cpolar-connect{display:flex;align-items:center;justify-content:center;box-sizing:border-box;width:100%;min-height:44px;padding:10px 14px;border-radius:12px;font:650 13px/1.2 system-ui;cursor:pointer;transition:background-color 160ms ease,border-color 160ms ease,opacity 160ms ease}.dsh-mobile-control__cpolar-connect:hover:not(:disabled){border-color:#1d4ed8;background:#1d4ed8}.dsh-mobile-control__cpolar-connect:active:not(:disabled){border-color:#1e40af;background:#1e40af}.dsh-mobile-control__cpolar-connect:disabled{cursor:wait;opacity:.55}.dsh-mobile-control__details{margin:10px 0 0;border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb);padding-top:9px}.dsh-mobile-control__details>summary{min-height:30px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:30px;cursor:pointer}.dsh-mobile-control__details-body{display:flex;flex-wrap:wrap;align-items:center;gap:7px 12px;padding:4px 0}.dsh-mobile-control__details-body p{flex:1 0 100%;margin:0;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__storage{display:block;flex:1 0 100%;max-width:100%;overflow:hidden;padding:7px 8px;border-radius:8px;background:var(--dsw-alias-bg-layer-1,#f3f5f8);color:var(--dsw-alias-label-secondary,#475569);font:10px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__danger{flex:1 0 100%;min-height:38px;margin-top:3px;padding:7px 10px;border:1px solid #dc2626;border-radius:9px;background:transparent;color:#dc2626;font:12px/1.3 system-ui;cursor:pointer}
5090
- .dsh-mobile-control__frp-setup{margin:0;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__frp-setup[hidden]{display:none}.dsh-mobile-control__frp-step{padding:11px 0}.dsh-mobile-control__frp-step + .dsh-mobile-control__frp-step{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__frp-step>strong{display:block;margin-bottom:3px;font-size:12px;line-height:1.4}.dsh-mobile-control__frp-step>p{margin:0 0 9px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__frp-step>.dsh-mobile-control__frp-requirement{padding:8px 9px;border-radius:9px;background:var(--dsw-alias-bg-layer-1,#f3f5f8);color:var(--dsw-alias-label-primary,#384152);font-size:11px}.dsh-mobile-control__frp-fields{display:grid;grid-template-columns:minmax(0,1fr) 96px;gap:8px}.dsh-mobile-control__field{display:flex;min-width:0;flex-direction:column;gap:5px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px}.dsh-mobile-control__field:nth-child(3),.dsh-mobile-control__field:nth-child(4){grid-column:1/-1}.dsh-mobile-control__field input{box-sizing:border-box;width:100%;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:16px/1.4 system-ui}.dsh-mobile-control__frp-action{box-sizing:border-box;width:100%;min-height:44px;padding:9px 12px;border-radius:10px;font:650 12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__frp-action:disabled{cursor:not-allowed;opacity:.5}.dsh-mobile-control__remote-workspace{margin:0;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:15px;background:var(--dsw-alias-bg-layer-1,#f7f8fa)}.dsh-mobile-control__stage-header{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:9px}.dsh-mobile-control__stage-header .dsh-mobile-control__section-title{margin:0}.dsh-mobile-control__stage-meta{display:flex;min-width:0;align-items:center;justify-content:flex-end;gap:5px}.dsh-mobile-control__stage-value{max-width:115px;overflow:hidden;color:var(--dsw-alias-label-primary,#16181d);font:650 10px/1.3 system-ui;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__state-badge{flex:none;padding:3px 7px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-secondary,#606873);font:650 9px/1.25 system-ui}.dsh-mobile-control__state-badge.is-ready{background:#e6f7f0;color:#087454}.dsh-mobile-control__state-badge.is-busy{background:#e8f0ff;color:#1d4ed8}.dsh-mobile-control__state-badge.is-attention{background:#fff4dc;color:#935100}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__status{box-sizing:border-box;margin:0 0 10px;padding:9px 10px;border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);font-size:11px;line-height:1.45}.dsh-mobile-control__provider-setup-body{margin:0 0 10px}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__cpolar-setup{margin:0}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__cpolar-setup>.dsh-mobile-control__section-title,.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__frp-setup>.dsh-mobile-control__section-title{display:none}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__details{margin:0;padding:9px 10px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__actions{margin-top:2px}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__qr{margin:10px 0 0}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__manage-row{margin-top:10px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}
5288
+ .dsh-mobile-control__frp-setup{margin:0;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__frp-setup[hidden]{display:none}.dsh-mobile-control__frp-step{padding:11px 0}.dsh-mobile-control__frp-step + .dsh-mobile-control__frp-step{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__frp-step>strong{display:block;margin-bottom:3px;font-size:12px;line-height:1.4}.dsh-mobile-control__frp-step>p{margin:0 0 9px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__frp-changes{margin:0 0 9px;padding:0;list-style:none;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;line-height:1.5}.dsh-mobile-control__frp-changes li{position:relative;margin:0;padding-left:12px}.dsh-mobile-control__frp-changes li+li{margin-top:5px}.dsh-mobile-control__frp-changes li::before{content:"•";position:absolute;left:2px;color:var(--dsw-alias-label-tertiary,#98a1ad)}.dsh-mobile-control__frp-step>.dsh-mobile-control__frp-requirement{padding:8px 9px;border-radius:9px;background:var(--dsw-alias-bg-layer-1,#f3f5f8);color:var(--dsw-alias-label-primary,#384152);font-size:11px}.dsh-mobile-control__frp-fields{display:grid;grid-template-columns:minmax(0,1fr) 96px;gap:8px}.dsh-mobile-control__field{display:flex;min-width:0;flex-direction:column;gap:5px;color:var(--dsw-alias-label-secondary,#606873);font-size:11px}.dsh-mobile-control__field:nth-child(3),.dsh-mobile-control__field:nth-child(4){grid-column:1/-1}.dsh-mobile-control__field input{box-sizing:border-box;width:100%;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:16px/1.4 system-ui}.dsh-mobile-control__frp-action{box-sizing:border-box;width:100%;min-height:44px;padding:9px 12px;border-radius:10px;font:650 12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__frp-action:disabled{cursor:not-allowed;opacity:.5}.dsh-mobile-control__remote-workspace{margin:0;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:15px;background:var(--dsw-alias-bg-layer-1,#f7f8fa)}.dsh-mobile-control__stage-header{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:9px}.dsh-mobile-control__stage-header .dsh-mobile-control__section-title{margin:0}.dsh-mobile-control__stage-meta{display:flex;min-width:0;align-items:center;justify-content:flex-end;gap:5px}.dsh-mobile-control__stage-value{max-width:115px;overflow:hidden;color:var(--dsw-alias-label-primary,#16181d);font:650 10px/1.3 system-ui;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__state-badge{flex:none;padding:3px 7px;border-radius:999px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-secondary,#606873);font:650 9px/1.25 system-ui}.dsh-mobile-control__state-badge.is-ready{background:#e6f7f0;color:#087454}.dsh-mobile-control__state-badge.is-busy{background:#e8f0ff;color:#1d4ed8}.dsh-mobile-control__state-badge.is-attention{background:#fff4dc;color:#935100}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__status{box-sizing:border-box;margin:0 0 10px;padding:9px 10px;border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);font-size:11px;line-height:1.45}.dsh-mobile-control__provider-setup-body{margin:0 0 10px}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__cpolar-setup{margin:0}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__cpolar-setup>.dsh-mobile-control__section-title,.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__frp-setup>.dsh-mobile-control__section-title{display:none}.dsh-mobile-control__provider-setup-body>.dsh-mobile-control__details{margin:0;padding:9px 10px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__actions{margin-top:2px}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__qr{margin:10px 0 0}.dsh-mobile-control__remote-workspace>.dsh-mobile-control__manage-row{margin-top:10px;padding-top:10px;border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}
5091
5289
  .dsh-mobile-control__frp-overview{display:grid;grid-template-columns:32px minmax(0,1fr);align-items:center;gap:10px;margin:0 0 10px;padding:10px;border:1px solid #a9dfc9;border-radius:11px;background:#edf9f4}.dsh-mobile-control__frp-overview[hidden]{display:none}.dsh-mobile-control__frp-overview-mark{display:grid;width:32px;height:32px;place-items:center;border-radius:50%;background:#087454;color:#fff;font:700 15px/1 system-ui}.dsh-mobile-control__frp-overview-body{display:flex;min-width:0;flex-direction:column;gap:2px}.dsh-mobile-control__frp-overview-body strong{color:#075d46;font-size:12px;line-height:1.35}.dsh-mobile-control__frp-overview-body span{overflow:hidden;color:#357061;font:10px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__frp-group{margin:8px 0 0;overflow:hidden;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#f8fafc)}.dsh-mobile-control__frp-group>summary{box-sizing:border-box;min-height:44px;padding:12px 34px 10px 12px;color:var(--dsw-alias-label-primary,#16181d);font:650 12px/1.4 system-ui;cursor:pointer}.dsh-mobile-control__frp-group[open]>summary{border-bottom:1px solid var(--dsw-alias-border-subtle,#e1e5eb);background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__frp-group>.dsh-mobile-control__frp-step{padding:12px}.dsh-mobile-control__frp-group>.dsh-mobile-control__frp-step>strong:first-child{display:none}.dsh-mobile-control__frp-group .dsh-mobile-control__frp-step{border-top:0}.dsh-mobile-control__frp-setup>.dsh-mobile-control__frp-step{margin-bottom:8px;padding:10px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:11px;background:var(--dsw-alias-bg-layer-1,#f8fafc)}
5092
5290
  .dsh-mobile-control__access{display:flex;align-items:baseline;gap:6px;min-width:0;margin:0 0 12px}.dsh-mobile-control__access[hidden]{display:none}.dsh-mobile-control__access-label{flex:none;color:var(--dsw-alias-label-secondary,#606873);white-space:nowrap}.dsh-mobile-control__access-label::after{content:":"}.dsh-mobile-control__access-link{min-width:0;overflow:hidden;color:#2563eb;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__access-link:hover{text-decoration:underline}.dsh-mobile-control__qr{display:flex;justify-content:center;margin:0 0 12px}.dsh-mobile-control__qr[hidden]{display:none}.dsh-mobile-control__qr img{border-radius:12px;background:#fff;padding:8px}
5093
5291
  .dsh-mobile-control__status{margin:0 0 14px;overflow-wrap:anywhere;color:var(--dsw-alias-label-secondary,#606873)}.dsh-mobile-control__status::before{display:inline-block;width:8px;height:8px;margin-right:7px;border-radius:50%;background:#98a1ad;content:""}.dsh-mobile-control__status.is-running::before{background:#16a36a}.dsh-mobile-control__status.is-key{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;word-break:break-all}
@@ -5102,7 +5300,7 @@ window.__ModuleLoader__.load({
5102
5300
  .dsh-mobile-control__actions{display:flex;flex-wrap:nowrap;gap:6px}.dsh-mobile-control__actions button{flex:1 1 0;min-width:0;min-height:40px;padding:8px 4px;border-radius:10px;font:12px/1.2 system-ui;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dsh-mobile-control__secondary{border:1px solid var(--dsw-alias-border-normal,#cfd5dd);background:transparent;color:inherit}.dsh-mobile-control__primary{border:1px solid #2563eb;background:#2563eb;color:#fff}.dsh-mobile-control__actions button:disabled{cursor:not-allowed;opacity:.45}
5103
5301
  .dsh-mobile-control button:focus-visible,.dsh-mobile-control a:focus-visible,.dsh-mobile-control input:focus-visible,.dsh-mobile-control summary:focus-visible{outline:3px solid rgb(37 99 235 / 28%);outline-offset:2px}
5104
5302
  .dsh-mobile-control__trigger{box-sizing:border-box;flex:none;display:flex;align-items:center;gap:8px;width:calc(100% + 4px);height:42px;margin:4px -2px;padding:0 10px 0 8px;border:0;border-radius:12px;background:transparent;color:var(--dsw-alias-label-primary,#16181d);font-family:inherit;font-size:14px;line-height:22px;cursor:pointer;overflow:hidden}.dsh-mobile-control__trigger:hover{background:var(--dsw-alias-interactive-bg-hover,#f1f3f6)}.dsh-mobile-control__trigger:active,.dsh-mobile-control__trigger[aria-expanded="true"]{background:var(--dsw-alias-interactive-bg-active,#e8ebf0)}.dsh-mobile-control__trigger:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,currentColor);outline-offset:2px}.dsh-mobile-control__trigger.is-rail{width:36px;height:36px;margin:8px 0 10px;padding:0;justify-content:center;gap:0;border-radius:50%}.dsh-mobile-control__trigger-icon{display:block;flex:none}.dsh-mobile-control__trigger-label{min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
5105
- .dsh-mobile-control__manage-row{display:flex;justify-content:space-between;gap:8px;margin-top:10px}.dsh-mobile-control__manage{flex:1 1 0;min-width:0;min-height:34px;padding:6px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:transparent;color:inherit;font:12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__devices{margin-top:10px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:10px;padding:8px;max-height:220px;overflow-y:auto}.dsh-mobile-control__device-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px;margin:0}.dsh-mobile-control__device{display:flex;align-items:center;gap:8px;padding:6px 2px}.dsh-mobile-control__device + .dsh-mobile-control__device{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__device-label{flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.dsh-mobile-control__device-meta{flex:none;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;white-space:nowrap}.dsh-mobile-control__device-revoke{flex:none;min-height:28px;padding:4px 8px;border:1px solid #dc2626;border-radius:8px;background:transparent;color:#dc2626;font:12px/1.2 system-ui;cursor:pointer}.dsh-mobile-control__ws-paths{margin:10px 0 0;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__ws-paths-list{margin:0 0 8px;padding:0;list-style:none}.dsh-mobile-control__ws-paths-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px}.dsh-mobile-control__ws-paths-item{display:flex;align-items:center;gap:8px;padding:6px 0}.dsh-mobile-control__ws-paths-item + .dsh-mobile-control__ws-paths-item{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__ws-paths-item code{flex:1 1 0;min-width:0;overflow:hidden;font:11px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__ws-paths-remove{flex:none;min-height:28px;padding:4px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:8px;background:transparent;color:inherit;font:12px/1.2 system-ui;cursor:pointer}.dsh-mobile-control__ws-paths-row{display:flex;gap:8px}.dsh-mobile-control__ws-paths-row input{flex:1 1 0;min-width:0;box-sizing:border-box;min-height:40px;padding:8px 10px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:14px/1.4 system-ui}.dsh-mobile-control__ws-paths-row button{flex:none}
5303
+ .dsh-mobile-control__manage-row{display:flex;justify-content:space-between;gap:8px;margin-top:10px}.dsh-mobile-control__manage{flex:1 1 0;min-width:0;min-height:34px;padding:6px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:transparent;color:inherit;font:12px/1.3 system-ui;cursor:pointer}.dsh-mobile-control__devices{margin-top:10px;border:1px solid var(--dsw-alias-border-subtle,#e1e5eb);border-radius:10px;padding:8px;max-height:220px;overflow-y:auto}.dsh-mobile-control__device-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px;margin:0}.dsh-mobile-control__device{display:flex;align-items:center;gap:8px;padding:6px 2px}.dsh-mobile-control__device + .dsh-mobile-control__device{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__device-label{flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px}.dsh-mobile-control__device-meta{flex:none;color:var(--dsw-alias-label-secondary,#606873);font-size:11px;white-space:nowrap}.dsh-mobile-control__device-revoke{flex:none;min-height:28px;padding:4px 8px;border:1px solid #dc2626;border-radius:8px;background:transparent;color:#dc2626;font:12px/1.2 system-ui;cursor:pointer}.dsh-mobile-control__ws-paths{margin:10px 0 0;padding:12px;border:1px solid var(--dsw-alias-border-subtle,#dbe1e8);border-radius:13px;background:var(--dsw-alias-bg-layer-2,#fff)}.dsh-mobile-control__ws-paths-list{margin:0 0 8px;padding:0;list-style:none}.dsh-mobile-control__ws-paths-empty{color:var(--dsw-alias-label-secondary,#606873);font-size:12px}.dsh-mobile-control__ws-paths-item{display:flex;align-items:center;gap:8px;padding:6px 0}.dsh-mobile-control__ws-paths-item + .dsh-mobile-control__ws-paths-item{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__ws-paths-item code{flex:1 1 0;min-width:0;overflow:hidden;font:11px/1.4 ui-monospace,SFMono-Regular,Consolas,monospace;text-overflow:ellipsis;white-space:nowrap}.dsh-mobile-control__ws-paths-remove{flex:none;min-height:28px;padding:4px 8px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:8px;background:transparent;color:inherit;font:12px/1.2 system-ui;cursor:pointer}.dsh-mobile-control__trigger,.dsh-mobile-control__diagnostic-entry{position:relative}.dsh-mobile-control__ws-dot{position:absolute;top:2px;right:2px;z-index:1;min-width:16px;height:16px;padding:0 4px;border-radius:999px;background:#dc2626;color:#fff;font:650 10px/16px system-ui;text-align:center;cursor:pointer}.dsh-mobile-control__ws-dot::after{content:'';position:absolute;inset:-5px}.dsh-mobile-control__ws-sr-status{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}.dsh-mobile-control__ws-paths-row{display:flex;gap:8px}.dsh-mobile-control__ws-paths-row .dsh-mobile-control__primary{width:auto;flex:none;padding:9px 14px;border-radius:10px}.dsh-mobile-control__ws-paths-group{padding:6px 0}.dsh-mobile-control__ws-paths-group + .dsh-mobile-control__ws-paths-group{border-top:1px solid var(--dsw-alias-border-subtle,#e1e5eb)}.dsh-mobile-control__ws-paths-group-head{display:flex;align-items:center;gap:8px}.dsh-mobile-control__ws-count{flex:none;padding:1px 7px;border-radius:999px;background:#e8f0ff;color:#1d4ed8;font:650 10px/1.6 system-ui}.dsh-mobile-control__ws-paths-item.is-child{padding-left:12px}.dsh-mobile-control__ws-paths-group-head .dsh-mobile-control__primary,.dsh-mobile-control__ws-paths-item .dsh-mobile-control__primary{width:auto;flex:none;min-height:34px;padding:6px 12px;border-radius:10px}.dsh-mobile-control__ws-paths-row input{flex:1 1 0;min-width:0;box-sizing:border-box;min-height:44px;padding:9px 10px;border:1px solid var(--dsw-alias-border-normal,#cfd5dd);border-radius:10px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#16181d);font:16px/1.4 system-ui}.dsh-mobile-control__ws-paths-row button{flex:none}.dsh-mobile-control__ws-paths-detected-title{margin:0 0 2px;font:600 12px/1.4 system-ui}.dsh-mobile-control__ws-paths-advanced{margin-top:8px}.dsh-mobile-control__ws-paths-advanced summary{cursor:pointer;color:var(--dsw-alias-label-secondary,#606873);font:12px/1.4 system-ui;user-select:none}.dsh-mobile-control__ws-paths-advanced summary:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,currentColor);outline-offset:2px;border-radius:4px}.dsh-mobile-control__ws-paths-advanced[open] summary{margin-bottom:6px}.dsh-mobile-control__ws-paths-advanced .dsh-mobile-control__status{margin:6px 0 0}
5106
5304
  @media (max-width:359px){.dsh-mobile-control__provider-choices{grid-template-columns:1fr}.dsh-mobile-control__provider{min-height:68px}}@media (prefers-reduced-motion:reduce){.dsh-mobile-control__provider,.dsh-mobile-control__cpolar-connect{transition:none}.dsh-mobile-control__diagnostic-summary.is-running .dsh-mobile-control__diagnostic-summary-icon::before,.dsh-mobile-control__diagnostic-checks{animation:none}}
5107
5305
  `;
5108
5306
  /** Mount the desktop control or mobile feature enhancements. */