dsh-mobile 0.3.13 → 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/CHANGELOG.md CHANGED
@@ -3,6 +3,11 @@
3
3
  Notable changes to DSH Mobile are recorded here. GitHub Releases remain the source for downloadable packages and complete generated commit notes.
4
4
 
5
5
 
6
+ ## 0.3.14 - 2026-09-08
7
+
8
+ - The panel's “Update plugin” action now shows a preview card first: the latest release notes (fetched from the GitHub releases API, graceful fallback when unavailable) plus fixed upgrade notices (restart DSH after installing; apps and paired devices need no re-pairing; check the README compatibility table when unsure about the desktop version), then explicit Update now / Not now buttons. Notes are served from the release itself, so a user on any older plugin version sees the current guidance before updating.
9
+ - Fixed a regression in 0.3.13: its layout adaptation tracked the harness master branch (which renamed the right details seat to `rightbar`), but the published 0.1.3-alpha.2 host still exposes `details` — so on real hosts the mobile right panel rendered empty. The layout now registers and renders both seat names (`details` with the legacy empty owner share, `rightbar` with resolved column geometry), so the right panel works on 0.1.3-alpha.1, the published 0.1.3-alpha.2, and the master contract alike. The compatibility check still asserts the master (`rightbar`) contract.
10
+
6
11
  ## 0.3.13 - 2026-09-08
7
12
 
8
13
  - Third-party WebSocket approval is interception-driven and generic: whenever a plugin's WebSocket connection is blocked, the diagnostics view groups the rejected paths by directory with attempt counts and offers per-path or allow-all approval, behind the same local-admin trust as pairing, and both the sidebar entry and the in-panel diagnostics button carry a red badge until reviewed. Manual path entry is tucked under an “advanced” disclosure that most users never need to open (thanks @idoall for reporting #47). Badge changes are announced to screen readers and the disclosure has a visible focus ring.
package/README.en.md CHANGED
@@ -19,14 +19,14 @@
19
19
 
20
20
  > DSH Mobile is a DeepSeek Harness community plugin; the native app supports Android only.
21
21
  >
22
- > **0.3.13 update**: interception-driven, plugin-agnostic WebSocket approval — grouped blocked paths, dual red badges, manual entry under an advanced disclosure (#47) — plus panel polish (FRP step numbering, deploy-notes layout, approval button) and adaptation to DeepSeek Harness 0.1.3-alpha.2 (layout right-bar slot rename). [Details](CHANGELOG.md).
22
+ > **0.3.14 update**: the 0.3.13 layout regression is fixed (right panel renders on both the published and the newer host contract), and the panel's “Update plugin” action now shows the latest release notes and upgrade notices before updating. Everything 0.3.13 brought stays (interception-driven WebSocket approval #47, panel polish, screen-reader announcements). [Details](CHANGELOG.md).
23
23
  >
24
- > **Upgrade reminder**: check your desktop DeepSeek Harness version before updating the plugin — **0.1.3-alpha.2 or later** pairs with plugin **0.3.13**; on an earlier desktop (0.1.2 line or 0.1.3-alpha.1) stay on plugin **0.3.12**. Existing 0.3.3-0.3.12 apps and paired devices remain compatible without re-pairing. [Compatibility notes](#compatibility).
24
+ > **Upgrade reminder**: plugin **0.3.14** is recommended and works on every 0.1.3 desktop release (alpha.1 included). Restart DSH after installing a new plugin. Existing 0.3.3-0.3.13 apps and paired devices remain compatible without re-pairing. [Compatibility notes](#compatibility).
25
25
 
26
26
  <p align="center">
27
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.13/dsh-mobile-android-v0.3.13.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile Android app icon" width="72" height="72"></a><br>
28
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.13/dsh-mobile-android-v0.3.13.apk"><strong>Download Android app 0.3.13</strong></a><br>
29
- <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.13">Release notes and checksums</a></sub>
27
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.14/dsh-mobile-android-v0.3.14.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile Android app icon" width="72" height="72"></a><br>
28
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.14/dsh-mobile-android-v0.3.14.apk"><strong>Download Android app 0.3.14</strong></a><br>
29
+ <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.14">Release notes and checksums</a></sub>
30
30
  </p>
31
31
 
32
32
  DSH Mobile is a DeepSeek Harness plugin that lets a mobile browser or the Android app connect over a protected LAN or an optional Tailscale Funnel, cpolar, or self-hosted FRP remote path. Local and remote access keep the same sessions, Workspaces, messages, and tools while using separate switches and paired-device stores without modifying DeepSeek Harness source.
@@ -201,14 +201,14 @@ The table below lists, for each plugin version, the DeepSeek Harness version it
201
201
 
202
202
  | DSH Mobile plugin | Verified DeepSeek Harness version |
203
203
  | --- | --- |
204
- | `0.3.13` | `0.1.3-alpha.2` |
204
+ | `0.3.14` | `0.1.3-alpha.2` |
205
205
  | `0.3.9`-`0.3.12` | `0.1.3-alpha.1` |
206
206
  | `0.3.6`-`0.3.8` | `0.1.2-rc.1` |
207
207
  | `0.3.4`, `0.3.5` | `0.1.2-alpha.2` |
208
208
  | `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
209
209
  | `0.1.4`, `0.2.x` | `0.1.1-rc.2` |
210
210
 
211
- Existing 0.3.3-0.3.13 apps do not need re-pairing. Earlier apps use a different status-bar strategy, so updating both is recommended. App 0.1.3 or earlier requires reinstalling and pairing again.
211
+ Existing 0.3.3-0.3.14 apps do not need re-pairing. Earlier apps use a different status-bar strategy, so updating both is recommended. App 0.1.3 or earlier requires reinstalling and pairing again.
212
212
 
213
213
  ## Uninstall
214
214
 
package/README.md CHANGED
@@ -26,14 +26,14 @@
26
26
 
27
27
  > DSH Mobile 是 DeepSeek Harness 社区插件,原生 App 仅支持 Android。
28
28
  >
29
- > **0.3.13 更新**:第三方插件 WebSocket 连接拦截即通用一键放行——按目录分组、红点双入口、手动配置收进高级项(#47)+ 面板修整(FRP 步骤编号、部署说明排版、批准按钮)+ 适配 DeepSeek Harness 0.1.3-alpha.2(布局右栏插槽更名)。[详细记录](CHANGELOG.md)。
29
+ > **0.3.14 更新**:0.3.13 布局回归修复(右栏在已发布与开发线宿主均可显示)+ 面板「更新插件」现在先展示最新版更新内容与注意事项、确认后才更新;0.3.13 功能不变(第三方 WebSocket 一键放行 #47、面板修整、读屏播报)。[详细记录](CHANGELOG.md)。
30
30
  >
31
- > **升级提醒**:先看电脑端 DeepSeek Harness 版本再升插件——**0.1.3-alpha.2 及以上**用插件 **0.3.13**;电脑端为更早版本(0.1.2 线或 0.1.3-alpha.1)时请保持插件 **0.3.12**。现有 0.3.3-0.3.12 App 可继续使用,无需重新配对。[兼容说明](#兼容性)。
31
+ > **升级提醒**:推荐升级到插件 **0.3.14**(0.1.3 各版本桌面均适用,含 alpha.1)。安装新插件后需重启 DSH。现有 0.3.3-0.3.13 App 可继续使用,无需重新配对。[兼容说明](#兼容性)。
32
32
 
33
33
  <p align="center">
34
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.13/dsh-mobile-android-v0.3.13.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile 安卓应用图标" width="72" height="72"></a><br>
35
- <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.13/dsh-mobile-android-v0.3.13.apk"><strong>下载 Android App 0.3.13</strong></a><br>
36
- <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.13">版本说明与校验文件</a></sub>
34
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.14/dsh-mobile-android-v0.3.14.apk"><img src="assets/brand/app-icon-rounded.svg" alt="DSH Mobile 安卓应用图标" width="72" height="72"></a><br>
35
+ <a href="https://github.com/saya-ch/dsh-mobile/releases/download/v0.3.14/dsh-mobile-android-v0.3.14.apk"><strong>下载 Android App 0.3.14</strong></a><br>
36
+ <sub><a href="https://github.com/saya-ch/dsh-mobile/releases/tag/v0.3.14">版本说明与校验文件</a></sub>
37
37
  </p>
38
38
 
39
39
  DSH Mobile 是一个 DeepSeek Harness 插件,让手机浏览器或 Android App 通过局域网,或可选的 Tailscale Funnel、cpolar、自建 FRP 远程通道连接电脑,继续使用同一份会话、工作区、消息和工具。局域网与远程访问分别启停、分别管理设备,且都不修改 DeepSeek Harness 源码。
@@ -210,14 +210,14 @@ flowchart LR
210
210
 
211
211
  | DSH Mobile 插件 | 验证支持的 DeepSeek Harness 版本 |
212
212
  | --- | --- |
213
- | `0.3.13` | `0.1.3-alpha.2` |
213
+ | `0.3.14` | `0.1.3-alpha.2` |
214
214
  | `0.3.9`-`0.3.12` | `0.1.3-alpha.1` |
215
215
  | `0.3.6`-`0.3.8` | `0.1.2-rc.1` |
216
216
  | `0.3.4`、`0.3.5` | `0.1.2-alpha.2` |
217
217
  | `0.3.0`-`0.3.3` | `0.1.2-alpha.1` |
218
218
  | `0.1.4`、`0.2.x` | `0.1.1-rc.2` |
219
219
 
220
- 现有 0.3.3-0.3.13 App 无需重新配对;更早的 App 使用不同的状态栏策略,建议同步升级;App 0.1.3 及更早版本需卸载重装并重新配对。
220
+ 现有 0.3.3-0.3.14 App 无需重新配对;更早的 App 使用不同的状态栏策略,建议同步升级;App 0.1.3 及更早版本需卸载重装并重新配对。
221
221
 
222
222
  ## 卸载
223
223
 
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",
@@ -180,6 +186,12 @@ window.__ModuleLoader__.load({
180
186
  updatingPlugin: "Aggiornamento…",
181
187
  pluginUpdatedRestart: "Aggiornato alla v{version}. Riavvia DSH per applicarlo.",
182
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",
183
195
  lan: "Rete locale",
184
196
  remote: "Remoto",
185
197
  lanAccess: "Accesso rete locale",
@@ -343,6 +355,12 @@ window.__ModuleLoader__.load({
343
355
  updatingPlugin: "正在更新…",
344
356
  pluginUpdatedRestart: "插件已更新至 v{version},重启 DSH 后生效。",
345
357
  pluginUpdateFailed: "更新失败:{error}",
358
+ updateTo: "更新到 v{version}",
359
+ updateNotesHeading: "更新内容",
360
+ updateNotice: "安装后需重启 DSH。现有 App 与已配对设备无需重新配对;电脑端版本不确定时,先对照 README 兼容表。",
361
+ updateNotesEmpty: "未取到最新版更新说明,仍可继续更新;详情见 GitHub Release 页。",
362
+ updateNow: "立即更新",
363
+ updateLater: "暂不",
346
364
  lan: "局域网",
347
365
  remote: "远程",
348
366
  lanAccess: "局域网访问",
@@ -2019,7 +2037,8 @@ window.__ModuleLoader__.load({
2019
2037
  updateAvailable: data.updateAvailable === true && latestVersion !== void 0,
2020
2038
  ...latestVersion === void 0 ? {} : { latestVersion },
2021
2039
  ...androidVersion === void 0 ? {} : { androidVersion },
2022
- androidDownloadUrl
2040
+ androidDownloadUrl,
2041
+ ...typeof data.releaseNotes === "string" && data.releaseNotes !== "" ? { releaseNotes: data.releaseNotes.slice(0, 4e3) } : {}
2023
2042
  };
2024
2043
  }
2025
2044
  async function requestJson(path, init, timeoutMs = CONTROL_REQUEST_TIMEOUT_MS) {
@@ -2094,6 +2113,22 @@ window.__ModuleLoader__.load({
2094
2113
  updatePlugin.type = "button";
2095
2114
  updatePlugin.textContent = t("updatePlugin");
2096
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);
2097
2132
  const diagnosticsEntry = element("button", "dsh-mobile-control__diagnostic-entry");
2098
2133
  diagnosticsEntry.type = "button";
2099
2134
  diagnosticsEntry.textContent = t("diagnostics");
@@ -2800,7 +2835,7 @@ window.__ModuleLoader__.load({
2800
2835
  lanView.append(access, qrBox, status, extensionStatus, actions, manageRow, devicePanel);
2801
2836
  remoteView.append(remoteIntro, providerSection, remoteWorkspace);
2802
2837
  diagnosticsView.append(diagnosticsIntro, diagnosticsSummary, diagnosticsToolbar, diagnosticsFeedback, diagnosticsChecks, wsPathsSection, diagnosticsDetails);
2803
- panel.append(header, releaseNotice, appDownload, switcher, lanView, remoteView, diagnosticsView);
2838
+ panel.append(header, releaseNotice, updateCard, appDownload, switcher, lanView, remoteView, diagnosticsView);
2804
2839
  root.append(panel);
2805
2840
  document.body.append(root);
2806
2841
  let running = false;
@@ -2830,11 +2865,14 @@ window.__ModuleLoader__.load({
2830
2865
  let copiedDiagnosticReport = "";
2831
2866
  let pluginUpdateAvailable = false;
2832
2867
  let pluginLatestVersion = "";
2868
+ let pluginReleaseNotes = "";
2869
+ let updateInFlight = false;
2833
2870
  const renderRelease = (data) => {
2834
2871
  const release = clientReleaseInfo(data);
2835
2872
  pluginUpdateAvailable = release.updateAvailable;
2836
2873
  pluginLatestVersion = release.latestVersion ?? "";
2837
- updatePlugin.hidden = !pluginUpdateAvailable || !diagnosticsView.hidden;
2874
+ pluginReleaseNotes = release.releaseNotes ?? "";
2875
+ updatePlugin.hidden = !pluginUpdateAvailable || !diagnosticsView.hidden || !updateCard.hidden;
2838
2876
  updatePlugin.textContent = t("updatePlugin");
2839
2877
  if (pluginLatestVersion !== "") updatePlugin.setAttribute("aria-label", t("updatePluginAria", { version: pluginLatestVersion }));
2840
2878
  if (release.androidVersion !== void 0) {
@@ -3967,10 +4005,16 @@ window.__ModuleLoader__.load({
3967
4005
  loadDiagnostics();
3968
4006
  });
3969
4007
  diagnosticsRun.addEventListener("click", loadDiagnostics);
3970
- updatePlugin.addEventListener("click", () => {
3971
- if (!pluginUpdateAvailable || pluginLatestVersion === "") return;
3972
- updatePlugin.disabled = true;
3973
- 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");
3974
4018
  releaseNotice.hidden = true;
3975
4019
  releaseNotice.classList.remove("is-error");
3976
4020
  controlRequestJson("/api/mobile-access/release/update", {
@@ -3979,18 +4023,32 @@ window.__ModuleLoader__.load({
3979
4023
  }, LONG_CONTROL_REQUEST_TIMEOUT_MS).then((data) => {
3980
4024
  const installedVersion = releaseVersion(data.installedVersion) ?? pluginLatestVersion;
3981
4025
  pluginUpdateAvailable = false;
4026
+ updateCard.hidden = true;
3982
4027
  updatePlugin.hidden = true;
3983
4028
  releaseNotice.textContent = t("pluginUpdatedRestart", { version: installedVersion });
3984
4029
  releaseNotice.hidden = false;
3985
4030
  }, (error) => {
3986
- updatePlugin.textContent = t("updatePlugin");
4031
+ updateCard.hidden = true;
4032
+ updatePlugin.hidden = false;
3987
4033
  releaseNotice.textContent = t("pluginUpdateFailed", { error: String(error) });
3988
4034
  releaseNotice.classList.add("is-error");
3989
4035
  releaseNotice.hidden = false;
3990
4036
  }).finally(() => {
3991
- updatePlugin.disabled = false;
4037
+ updateInFlight = false;
4038
+ updateNow.disabled = false;
4039
+ updateLater.disabled = false;
3992
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;
3993
4049
  });
4050
+ updateNow.addEventListener("click", runPluginUpdate);
4051
+ updateLater.addEventListener("click", closeUpdateCard);
3994
4052
  diagnosticsCopy.addEventListener("click", () => {
3995
4053
  if (copiedDiagnosticReport === "") return;
3996
4054
  navigator.clipboard.writeText(copiedDiagnosticReport).then(() => {
@@ -5222,7 +5280,7 @@ window.__ModuleLoader__.load({
5222
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)}
5223
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%)}
5224
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)}
5225
- .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)}
5226
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}
5227
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}
5228
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)}