dsh-plugin-shop 0.9.0-beta.1 → 0.9.0-beta.2
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 +343 -329
- package/lib/index.js +210 -34
- package/lib/typert.host.js +12 -12
- package/lib/typert.remote-client.js +11 -11
- package/lib/types/client/locales.d.ts +2 -0
- package/lib/types/client/present.d.ts +9 -7
- package/lib/types/host/harness.d.ts +26 -2
- package/lib/types/host/index.d.ts +39 -6
- package/lib/types/host/manager-runner.d.ts +24 -0
- package/lib/types/host/plugin-manager.d.ts +5 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -4490,6 +4490,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4490
4490
|
"restartBlocked": union([
|
|
4491
4491
|
literal(null),
|
|
4492
4492
|
literal("desktop"),
|
|
4493
|
+
literal("from-default-profile"),
|
|
4493
4494
|
literal("windows"),
|
|
4494
4495
|
literal("systemd"),
|
|
4495
4496
|
literal("port-zero")
|
|
@@ -4530,7 +4531,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4530
4531
|
},
|
|
4531
4532
|
sourceLocation: {
|
|
4532
4533
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4533
|
-
"line":
|
|
4534
|
+
"line": 1301,
|
|
4534
4535
|
"column": 9
|
|
4535
4536
|
}
|
|
4536
4537
|
},
|
|
@@ -4549,7 +4550,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4549
4550
|
},
|
|
4550
4551
|
sourceLocation: {
|
|
4551
4552
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4552
|
-
"line":
|
|
4553
|
+
"line": 1804,
|
|
4553
4554
|
"column": 9
|
|
4554
4555
|
}
|
|
4555
4556
|
},
|
|
@@ -4568,7 +4569,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4568
4569
|
},
|
|
4569
4570
|
sourceLocation: {
|
|
4570
4571
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4571
|
-
"line":
|
|
4572
|
+
"line": 1795,
|
|
4572
4573
|
"column": 9
|
|
4573
4574
|
}
|
|
4574
4575
|
},
|
|
@@ -4598,7 +4599,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4598
4599
|
},
|
|
4599
4600
|
sourceLocation: {
|
|
4600
4601
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4601
|
-
"line":
|
|
4602
|
+
"line": 1427,
|
|
4602
4603
|
"column": 9
|
|
4603
4604
|
}
|
|
4604
4605
|
},
|
|
@@ -4627,7 +4628,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4627
4628
|
},
|
|
4628
4629
|
sourceLocation: {
|
|
4629
4630
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4630
|
-
"line":
|
|
4631
|
+
"line": 1771,
|
|
4631
4632
|
"column": 3
|
|
4632
4633
|
}
|
|
4633
4634
|
},
|
|
@@ -4646,7 +4647,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4646
4647
|
},
|
|
4647
4648
|
sourceLocation: {
|
|
4648
4649
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4649
|
-
"line":
|
|
4650
|
+
"line": 2055,
|
|
4650
4651
|
"column": 9
|
|
4651
4652
|
}
|
|
4652
4653
|
},
|
|
@@ -4675,7 +4676,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4675
4676
|
},
|
|
4676
4677
|
sourceLocation: {
|
|
4677
4678
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4678
|
-
"line":
|
|
4679
|
+
"line": 953,
|
|
4679
4680
|
"column": 9
|
|
4680
4681
|
}
|
|
4681
4682
|
},
|
|
@@ -4705,7 +4706,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4705
4706
|
},
|
|
4706
4707
|
sourceLocation: {
|
|
4707
4708
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4708
|
-
"line":
|
|
4709
|
+
"line": 1949,
|
|
4709
4710
|
"column": 9
|
|
4710
4711
|
}
|
|
4711
4712
|
},
|
|
@@ -4734,7 +4735,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4734
4735
|
},
|
|
4735
4736
|
sourceLocation: {
|
|
4736
4737
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4737
|
-
"line":
|
|
4738
|
+
"line": 2162,
|
|
4738
4739
|
"column": 9
|
|
4739
4740
|
}
|
|
4740
4741
|
},
|
|
@@ -4753,7 +4754,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4753
4754
|
},
|
|
4754
4755
|
sourceLocation: {
|
|
4755
4756
|
"file": "packages/dsh-plugin-shop/src/host/index.ts",
|
|
4756
|
-
"line":
|
|
4757
|
+
"line": 2119,
|
|
4757
4758
|
"column": 9
|
|
4758
4759
|
}
|
|
4759
4760
|
}
|
|
@@ -4949,6 +4950,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4949
4950
|
notRestartedPidNotice: "dsh 没有重启:页面刷新后,回答的仍是被要求重启的那个进程(pid {pid}),所以更改还没有生效。请手动重启:运行 kill {pid}(进程仍不退出时用 kill -9 {pid}),再运行 dsh web。",
|
|
4950
4951
|
notRestartedLogNotice: "这次重启的经过记录在 {log}。",
|
|
4951
4952
|
restartBlockedDesktopNotice: "此 profile 由 DeepSeek Harness 桌面版管理,商店无法重启它。请重启桌面版,以应用更改。",
|
|
4953
|
+
restartBlockedFromDefaultProfileNotice: "此 dsh 以 --from-default-profile 启动。从 dsh 0.2.1 起,重启会按模板重建 profile,删除其中安装的全部插件,包括商店。请去掉该参数后手动重启 dsh,以应用更改。",
|
|
4952
4954
|
restartBlockedWindowsNotice: "商店暂不支持在 Windows 上重启 dsh。请退出 dsh 后重新启动,以应用更改。",
|
|
4953
4955
|
restartBlockedSystemdNotice: "当前 dsh 由 systemd 服务托管,商店无法安全地重启它。请手动重启服务,或在商店行配置中设置 allowRestart: true。",
|
|
4954
4956
|
restartBlockedPortZeroNotice: "此 dsh 以 --port 0 启动,重启后会绑定到另一个端口,本页面无法跟上。请手动重启 dsh,以应用更改。",
|
|
@@ -5092,6 +5094,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5092
5094
|
notRestartedPidNotice: "dsh did not restart: after the reload, the process that was asked to restart (pid {pid}) is still the one answering, so the change has not taken effect. Restart it by hand: run kill {pid} (kill -9 {pid} if it does not exit), then run dsh web.",
|
|
5093
5095
|
notRestartedLogNotice: "What this restart did is logged in {log}.",
|
|
5094
5096
|
restartBlockedDesktopNotice: "This profile is managed by the DeepSeek Harness desktop app, so the shop cannot restart it. Restart the app to apply the change.",
|
|
5097
|
+
restartBlockedFromDefaultProfileNotice: "This dsh was launched with --from-default-profile. From dsh 0.2.1 a restart would recreate the profile from its template and delete every plugin installed in it, this shop included. Restart dsh manually without that flag to apply the change.",
|
|
5095
5098
|
restartBlockedWindowsNotice: "The shop cannot restart dsh on Windows yet. Quit dsh and start it again to apply the change.",
|
|
5096
5099
|
restartBlockedSystemdNotice: "This dsh process runs as a systemd service, so the shop cannot restart it safely. Restart the service manually, or set allowRestart: true in the shop row config.",
|
|
5097
5100
|
restartBlockedPortZeroNotice: "This dsh was launched with --port 0, so a restart would bind a different port and this page could not follow it. Restart dsh manually to apply the change.",
|
|
@@ -6957,15 +6960,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6957
6960
|
/** Why the shop cannot restart dsh, as a locale key.
|
|
6958
6961
|
*
|
|
6959
6962
|
* A sibling of `activationNoticeKey` and exhaustive for the same reason: the
|
|
6960
|
-
* switch has no default, so a
|
|
6961
|
-
*
|
|
6962
|
-
*
|
|
6963
|
+
* switch has no default, so a reason added to `RestartBlockedReason` is a type
|
|
6964
|
+
* error here rather than a card that silently keeps a neighbour's copy. That
|
|
6965
|
+
* is the whole point of the type — the single boolean this replaced
|
|
6963
6966
|
* had ONE string for three causes, and it named systemd, so a Windows reader
|
|
6964
6967
|
* was told to restart a service they do not run and to set an override that
|
|
6965
6968
|
* could not have helped. */
|
|
6966
6969
|
function restartBlockedNoticeKey(reason) {
|
|
6967
6970
|
switch (reason) {
|
|
6968
6971
|
case "desktop": return "restartBlockedDesktopNotice";
|
|
6972
|
+
case "from-default-profile": return "restartBlockedFromDefaultProfileNotice";
|
|
6969
6973
|
case "windows": return "restartBlockedWindowsNotice";
|
|
6970
6974
|
case "systemd": return "restartBlockedSystemdNotice";
|
|
6971
6975
|
case "port-zero": return "restartBlockedPortZeroNotice";
|
|
@@ -7079,14 +7083,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
7079
7083
|
function refusesInstall(blockers) {
|
|
7080
7084
|
return blockers.some((blocker) => blocker.kind === "name-taken" || blocker.kind === "harness-peers");
|
|
7081
7085
|
}
|
|
7086
|
+
/** The key dsh 0.2.1 lists a package's own `engines.dsh` range under, among
|
|
7087
|
+
* the requirements it refuses (design 2026-10-19-dsh-021-readiness, section
|
|
7088
|
+
* 4). No card receives it yet: the prediction judges the catalog's `dshPeers`
|
|
7089
|
+
* alone, and the catalog carries no `engines` (that section's known gap). A
|
|
7090
|
+
* refusal dsh raises at install time names the key in the install's own detail
|
|
7091
|
+
* (`versionRefusalDetail`), which never passes through here. So look for no
|
|
7092
|
+
* producer in `peerVerdictsOf`; this waits for the catalog to carry `engines`. */
|
|
7093
|
+
const ENGINES_DSH = "engines.dsh";
|
|
7082
7094
|
/**
|
|
7083
|
-
* The refused
|
|
7084
|
-
* the package declared, in the order dsh reported them. A
|
|
7085
|
-
*
|
|
7086
|
-
* it
|
|
7095
|
+
* The refused requirements as the refusal's copy names them: each one and the
|
|
7096
|
+
* range the package declared, in the order dsh reported them. A peer is named
|
|
7097
|
+
* by its package. `engines.dsh` is a manifest path, not a name anyone asked
|
|
7098
|
+
* for, so it reads as `dsh` and its range, the way the sentence says "it
|
|
7099
|
+
* requires dsh >=0.3.0". A blank range — which dsh refuses — is quoted, or the
|
|
7100
|
+
* sentence would name the requirement and nothing it asked for.
|
|
7087
7101
|
*/
|
|
7088
7102
|
function refusedPeersText(refused) {
|
|
7089
|
-
return Object.entries(refused).map(([name, range]) => `${name} ${range.trim() === "" ? JSON.stringify(range) : range}`).join(", ");
|
|
7103
|
+
return Object.entries(refused).map(([name, range]) => `${name === ENGINES_DSH ? "dsh" : name} ${range.trim() === "" ? JSON.stringify(range) : range}`).join(", ");
|
|
7090
7104
|
}
|
|
7091
7105
|
/**
|
|
7092
7106
|
* The plugin already holding this entry's bundle name, if a DIFFERENT one is,
|
|
@@ -8403,136 +8417,136 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8403
8417
|
if (typeof held?.dispose === "function") held.dispose();
|
|
8404
8418
|
}
|
|
8405
8419
|
//#endregion
|
|
8406
|
-
//#region \0dsh-plugin-shop-css:
|
|
8407
|
-
const css = "/* Shop styles — the shop's own page with its market shelf, and the shop's two\n * buttons on dsh's Plugins page. Every variable read here is a dsh theme\n * alias token (`--dsw-alias-*`), one of the shop's own properties declared in\n * this file (`--shop-*`, `--category-hue`, `--switch-hue`, `--track-hue`), or\n * one of two dsh variables outside the alias set, each read where the shop\n * copies dsh: `--dsh-frame-top-clearance`, so the page head clears the\n * desktop frame as dsh's own pages do, and `--dsw-radius-sm`, because the\n * Plugins page buttons copy dsh's Button (0.1.5-rc.3 lacks that token, and\n * has no Plugins page to draw them on). `state-error` and\n * `state-success` do not exist, so the state-*-primary set stands in for\n * them (measured 2026-10-17 on dsh 0.1.5-rc.3, 0.1.7-rc.2 and 0.2.0-rc.2,\n * which do define `bg-layer-3` and `interactive-bg-hover`, once listed here\n * as missing). The signature is the category spine: one HUE per\n * category (seven fixed hues, not the brand token — the brand resolves to\n * near-black in the light theme, so seven brand opacities read as seven\n * shades of gray), with the category name as the cover label in the same hue. Class names are mapped to content-derived names at bundle time\n * (tsdown.sa85938_client.s94d4e5_config.s91da2e_ts) and stubbed in tests; only the keys are relied\n * on.\n *\n * One token rule the theme forces: the background LAYERS do not carry\n * contrast. In the light theme bg-base, bg-layer-1, bg-layer-2 and\n * bg-layer-3 all resolve to the same white; only the dark theme spreads them\n * (950/875/850/800). So a layer-2 fill on a layer-1 ground is invisible for\n * half of all users, and anything whose fill is its ONLY affordance — the\n * loading skeleton, the borderless capability chips — derives its fill from\n * label-primary instead, which inverts with the theme by construction.\n * Elements that also carry a border or text may keep a layer fill.\n * `css-tokens.sa85938_client.sbb5706_spec.s91da2e_ts` pins this. */\n\n.s6a01b8_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n /* The two reds every red text in this tab is painted with. dsh's error red\n * is #ec1313 in the light theme, which measures 4.498:1 as text on white —\n * a miss of two thousandths — and 3.57:1 on the badge's own 14% red fill\n * (4.00:1 in dark). Mixing it toward label-primary fixes both, because\n * label-primary is the theme's foreground pole: it darkens the red on light\n * surfaces and lightens it on dark ones. Measured in the live app: 90% of\n * the red is 5.30:1 on white and 5.29:1 on the dark card, and 80% is\n * 4.98:1 on the badge's tint, 4.92:1 in dark. Computed: 90% is 6.14:1 on\n * the dark page itself (#151517, `bg-base`), where the self-update's\n * failure heading sits (4.69:1 on Settings' #2c2c2e, its ground through\n * 0.8.7), and 80% is 5.23:1 on the uninstall button's 10% hover fill.\n * Declared here, on the tab root, because a custom property inherits: one\n * declaration reaches every red element, and a new one cannot be\n * forgotten. */\n --shop-error: color-mix(in srgb, var(--dsw-alias-state-error-primary) 90%, var(--dsw-alias-label-primary));\n --shop-error-on-tint: color-mix(in srgb, var(--dsw-alias-state-error-primary) 80%, var(--dsw-alias-label-primary));\n /* The amber and the green, mixed the same way for the same reason. dsh's\n * warn #f59e0b and success #22c55e are one value in both themes and pass\n * in the dark one, but as text on white they measure 2.15:1 and 2.28:1.\n * Each derived colour keeps the largest multiple of ten of its hue that\n * clears every surface it paints, as the reds do. Computed from the live\n * tokens over every bg layer in both themes: amber at 60% is 4.95:1 on a\n * plain surface but 4.44:1 on its own 14% tint, so text on an amber tint\n * takes 50% (5.66:1); green at 60% is 5.18:1 plain and 4.60:1 on its 14%\n * tint, so one green serves both. */\n --shop-warn: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 60%, var(--dsw-alias-label-primary));\n --shop-warn-on-tint: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 50%, var(--dsw-alias-label-primary));\n --shop-success: color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary));\n /* The shelf never scrolls sideways: a card too wide for its track wraps\n * its badges rather than widening the panel.\n *\n * Clipped on BOTH axes, with a margin, because `.sa16cbe_searchInput` sits at\n * exactly (0, 0) of this box — it is the first child of `.sbc1497_toolbar`, itself\n * the first child here, and this rule carries no padding — so its focus\n * ring paints ENTIRELY outside the panel.\n *\n * Both axes is the load-bearing part: `overflow-clip-margin` is inert\n * unless the element clips on both. Clipping x alone left the margin doing\n * nothing — measured against the live app on 0.7.1, the ring reached 0 of\n * its 3px on the left at every device pixel ratio (1, 1.25, 1.5, 2), while\n * keeping the full 3px on the right, where the 280px input stops short of\n * the panel and never meets the clip edge. Raising the margin to 6px\n * changed nothing; clipping both axes with the SAME 3px restored the whole\n * ring. A test that reads declarations cannot see that difference, which is\n * why the first attempt at this shipped broken.\n *\n * `clip` is not a scroll container, so this does not bring back the\n * accidental scrolling `hidden` caused by coercing the other axis to\n * `auto`. Nothing is lost vertically: the panel's scrollHeight equals its\n * height and no descendant paints outside the clip rect (measured).\n * `overflow-x: hidden` stays as the fallback for engines without `clip`,\n * where the ring is clipped as it was before, never worse. */\n overflow-x: hidden;\n overflow: clip;\n overflow-clip-margin: 3px;\n}\n\n/* The shop's own page in dsh's main column (design\n * 2026-10-16-shop-sidebar-page §4.2), framed as dsh 0.2.0-rc.2 frames its\n * Plugins page — read from that page's stylesheet: the page is the scroll\n * container, its children one centred column of at most 960px, and the head\n * clears the desktop title bar. One declaration is the shop's own, `color`:\n * dsh's `.s61d354_page` inherits its colour from the shell around it, and the shop's\n * root is not inside dsh's panel stylesheet, so the shop's page states it. */\n.s61d354_page {\n box-sizing: border-box;\n height: 100%;\n overflow: auto;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 32px;\n padding: 0 clamp(24px, 4vw, 48px) 48px;\n color: var(--dsw-alias-label-primary);\n}\n\n.s61d354_page > * {\n width: 100%;\n max-width: 960px;\n}\n\n.s9331e8_pageHead {\n box-sizing: border-box;\n padding-top: calc(28px + var(--dsh-frame-top-clearance, 0px));\n}\n\n.sb4f89f_pageTitle {\n margin: 0;\n font-size: 20px;\n font-weight: 500;\n line-height: 28px;\n}\n\n/* Secondary, as dsh's own intro: 5.80:1 on the light theme's white. */\n.s5b1bea_pageIntro {\n margin: 4px 0 0;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The two buttons on dsh's Plugins page (design 2026-10-16-shop-sidebar-page\n * §7), drawn as that page draws its own small outline buttons beside them —\n * dsh 0.2.0-rc.2's Button, sm + outline: 28px tall, 12px text on an 18px\n * line, 10px of side padding, the small radius, the neutral stroke. That\n * stroke is 0.5px in dsh and 1px here: every border in this stylesheet is,\n * and Chromium paints 0.5px as 1px at every ratio measured. */\n.s591d55_detailAction {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 28px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n cursor: pointer;\n}\n\n.s591d55_detailAction:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.s591d55_detailAction:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s352f7a_stateLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* Visually hidden but screen-reader readable (the loading copy while the\n * skeleton stands in visually). */\n.s60f2f5_srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n overflow: hidden;\n white-space: nowrap;\n}\n\n/* The loading shelf: ghost cards with the same geometry as the real grid, so\n * the swap to content is a same-shape handoff instead of a jump. */\n.s34d5f5_skeletonGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 8px;\n}\n\n.s11e315_skeletonCard {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n}\n\n/* The shimmer sweep: one gradient band travels across each ghost card while\n * the bars breathe, so the loading state reads as \"the shelf is scanning\". */\n.s11e315_skeletonCard::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 100deg,\n transparent 25%,\n color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent) 50%,\n transparent 75%\n );\n transform: translateX(-100%);\n animation: dshShopSkeletonSweep 1.4s ease-in-out infinite;\n pointer-events: none;\n}\n\n@keyframes dshShopSkeletonSweep {\n to { transform: translateX(100%); }\n}\n\n.s227d7c_skeletonName {\n width: 55%;\n height: 14px;\n margin: 10px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.s83025b_skeletonSummary {\n width: 92%;\n height: 12px;\n margin: 10px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sdb7845_skeletonSummaryShort {\n width: 68%;\n height: 12px;\n margin: 6px 12px 10px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n/* The ghost of the action line, right where the real buttons land. */\n.sa61117_skeletonActions {\n display: block;\n width: 84px;\n height: 24px;\n margin: 0 12px 10px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.s11e315_skeletonCard span {\n animation: dshShopSkeletonPulse 1.6s ease-in-out infinite;\n}\n\n@keyframes dshShopSkeletonPulse {\n 0%, 100% { opacity: 0.5; }\n 50% { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s11e315_skeletonCard span { animation: none; opacity: 0.75; }\n .s11e315_skeletonCard::after { content: none; }\n}\n\n.s757132_actionButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s757132_actionButton:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.s757132_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sbc1497_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.s22d15d_toolbarRight {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n/* The shop's own version, right of the search box: `v0.4.4`, plus the\n * update button when the version check found a newer release. */\n.s76d3c9_versionBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.s390e34_versionText {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s79450a_updateSelfButton {\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n color: var(--dsw-alias-brand-primary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.s79450a_updateSelfButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 20%, transparent);\n}\n\n.s79450a_updateSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The on-demand re-check next to the version number: a quiet pill; the\n * border and text carry it in the light theme where bg layers are white. */\n.sb48cbc_checkUpdateButton {\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n.sb48cbc_checkUpdateButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n color: var(--dsw-alias-label-primary);\n}\n\n.sb48cbc_checkUpdateButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.sb48cbc_checkUpdateButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The project's GitHub mark, right of the version row: a quiet icon link.\n * The octocat carries itself — color shift on hover, no text, no border. */\n.s946346_githubLink {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 3px;\n border-radius: 6px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s946346_githubLink:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.s946346_githubLink:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The self-update's expanded states (running log / done + restart /\n * failure detail) sit under the toolbar, above the category bar. */\n.s861599_selfUpdatePanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.sa16cbe_searchInput {\n width: min(280px, 100%);\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n.sa16cbe_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* Subdued line under the search box when a dictionary intent fired (design\n * 2026-10-08-search-query-expansion §4). One fact, no badge. */\n.seb8329_expansionNote {\n margin: 4px 0 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s31a2f0_staleBadge {\n padding: 2px 8px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n color: var(--shop-warn-on-tint);\n font-size: 12px;\n}\n\n.sab4844_categoryBar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n}\n\n.s512425_categoryButton {\n /* The hue this button carries when selected. `All` and `Installed` select by\n * something other than a category and keep the brand token; the six category\n * buttons override it from the shared hue table below, so a pressed Tool tab\n * turns the same blue as a tool card's spine. */\n --category-hue: var(--dsw-alias-brand-primary);\n padding: 3px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n/* Blend text with the theme foreground: darker on light backgrounds, lighter\n * on dark ones. The unblended category hue belongs on the border and fill. */\n.s512425_categoryButton:hover {\n border-color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-border-l2));\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Selected. Written `.s512425_categoryButton.s598384_categoryButtonOn` — TWO classes — so it\n * matches `.s512425_categoryButton:hover`'s specificity and, coming after it, wins.\n * As a bare `.s598384_categoryButtonOn` it lost both `border-color` and `color` to the\n * hover rule for as long as the pointer stayed on the tab that had just been\n * clicked, which is precisely when a reader looks for confirmation.\n *\n * EVERY declaration here is a colour: a pressed tab must occupy exactly the\n * same box as an unpressed one, so the bar does not reflow — and with ~9 pills\n * on a wrapping row, one that grows can push the rest onto another line and\n * move the tab out from under the pointer that just clicked it. That is what\n * `font-weight: 600` did (bold metrics are wider than regular), and it is why\n * nothing may be added here that resolves to a length: no padding, no\n * border-width, no font-size, no letter-spacing. `css-tokens.sa85938_client.sbb5706_spec.s91da2e_ts`\n * fails the build on one.\n *\n * Nor a second line. An inset ring once doubled this border, and every control\n * in the stylesheet now draws exactly one 1px line, which is also the thinnest\n * the host paints (Chromium draws 0.5px as 1px). What separates pressed from\n * unpressed is lightness instead of thickness: the border is the hue mixed 30%\n * toward label-primary, the theme's foreground pole, so it clears 3:1 against\n * the bar in both themes for every hue — the raw hue measured 1.86:1 on white\n * for `ui` — and the fill under it is 22% of the hue. The `other` tab is the\n * case this is for: its hue IS the neutral gray this file uses for \"no\n * category\", so on the light theme the hue alone barely separates the two. */\n.s512425_categoryButton.s598384_categoryButtonOn {\n border-color: color-mix(in srgb, var(--category-hue) 70%, var(--dsw-alias-label-primary));\n background: color-mix(in srgb, var(--category-hue) 22%, transparent);\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Forced colours replace every colour above with the system palette, which\n * would leave the three colour declarations saying nothing and the pressed tab\n * indistinguishable from its neighbours, so this mode alone gets an outline. */\n@media (forced-colors: active) {\n .s512425_categoryButton.s598384_categoryButtonOn {\n outline: 2px solid ButtonText;\n outline-offset: -4px;\n }\n}\n\n.s512425_categoryButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The incompatible filter, at the right edge of the category bar: `margin-left:\n * auto` pushes it past the pills, and the bar wraps, so on a narrow panel it\n * drops to its own line rather than squeezing them. It is a MODIFIER, not a\n * ninth category — the categories select what to show and this one subtracts\n * from whatever they selected — so it takes the error hue it filters on rather\n * than joining the hue table.\n *\n * And it is a SWITCH, which is the difference the shape now carries. It used\n * to wear `.s512425_categoryButton`: same pill, same row, same size as the eight tabs,\n * differing only in being red. That reads as a ninth tab, and it is not one —\n * the tabs are choose-one and this is on-or-off. So it drops the pill chrome\n * entirely (no border, no fill, nothing to compete with the row it sits\n * beside) and puts the state in a track, the same one every installed card\n * carries. Nothing here restates the switch geometry; `--switch-hue` is the\n * whole of what this control says about it, and it reaches the label too, so\n * one declaration keeps the word and the track the same colour. */\n.s7ce437_incompatibleFilter {\n --switch-hue: var(--dsw-alias-state-error-primary);\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n /* Matches the pills' vertical padding so the bar keeps one line box whether\n * this control wraps onto a row of its own or shares theirs. */\n padding: 3px 0;\n border: 0;\n background: none;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n/* Hover lifts the word to full contrast and warms the track's border. Scoped\n * to the OFF track: `.s7ce437_incompatibleFilter:hover .s3a8382_switch` outranks `.s1e392e_switchOn`\n * by two classes, so unscoped it would strip the hue from the border at\n * exactly the moment a reader has the pointer on it to check the state. */\n.s7ce437_incompatibleFilter:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.s7ce437_incompatibleFilter:hover .s3a8382_switch:not(.s1e392e_switchOn) {\n border-color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-border-l2));\n}\n\n/* On. Written with both classes for the reason `.s512425_categoryButton.s598384_categoryButtonOn`\n * is: it has to match `:hover`'s specificity and come after it, or the colour\n * reverts under a pointer that has not moved since the click. */\n.s7ce437_incompatibleFilter.sd9fa8d_incompatibleFilterOn {\n color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Off here means \"nothing is being taken away\" — the resting state — so the\n * knob steps back to the secondary label. The enable switch keeps the full\n * strength dot, where off means \"this plugin is disabled\" and is worth\n * noticing. In this bar it would be the heaviest mark in a row of hairline\n * pills, and on the light theme it is the WHOLE control: bg-layer-2 is the\n * same white as the panel there, so an off track is a hairline outline with a\n * near-black dot sitting in it. */\n.s7ce437_incompatibleFilter .s3a8382_switch:not(.s1e392e_switchOn) .s419ba1_switchKnob {\n background: var(--dsw-alias-label-secondary);\n}\n\n/* The ring has no border to trace, so it takes an offset and the pill radius\n * of the tabs it sits beside rather than hugging the text. */\n.s7ce437_incompatibleFilter:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 999px;\n}\n\n.s320079_updatableHeading {\n margin: 2px 0 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-primary);\n}\n\n.s923c82_catalogStatsRow {\n display: flex;\n align-items: center;\n /* The row holds the catalog line, the refresh button and the shelf order's\n * three pills (design 2026-10-12-shelf-orders §4). Without wrapping, the\n * last of them overflows the tab at a narrow width. */\n flex-wrap: wrap;\n gap: 10px;\n margin: 6px 0 0;\n}\n\n/* The shelf's order control, at the right end of the stats row. `margin-left:\n * auto` is what puts it there while the line and the refresh button stay\n * left — and it is safe on a wrapping row, unlike a width. */\n.s3edd9f_sortGroup {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n margin-left: auto;\n}\n\n.s73feb1_sortLabel {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.sad5aba_catalogStats {\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* Sits beside the 12px stats caption, so it is quieter than `.s757132_actionButton`:\n * this is an affordance, not a call to action — the catalog reloads on its\n * own at mount and the shelf is already usable without it. Named\n * `catalogRefresh*` (not `reload*`) so it cannot collide with the §4 page\n * reload offer below, which reloads the whole tab rather than refetching\n * the catalog data. */\n.s4cca13_catalogRefreshButton {\n padding: 1px 9px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n line-height: 17px;\n cursor: pointer;\n}\n\n.s4cca13_catalogRefreshButton:hover:not(:disabled) {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.s4cca13_catalogRefreshButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.s4cca13_catalogRefreshButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sc24c97_catalogRefreshFailed {\n font-size: 11px;\n color: var(--shop-warn);\n}\n\n.s1aa6bf_emptyLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* The shelf: a responsive grid of cards. */\n/* Single-line rows: one full-width column, one plugin per line. */\n.sa036b0_cards {\n display: grid;\n grid-template-columns: 1fr;\n max-width: 100%;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n animation: dshShopCardsIn 220ms ease;\n}\n\n@keyframes dshShopCardsIn {\n from { opacity: 0; transform: translateY(3px); }\n to { opacity: 1; transform: none; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .sa036b0_cards { animation: none; }\n}\n\n.s88b200_card {\n position: relative;\n display: flex;\n flex-direction: column;\n /* A grid item's min-width is auto by default: its content would widen the\n * 1fr track past the panel and overflow horizontally. */\n min-width: 0;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;\n /* Off-screen cards skip layout and paint; the placeholder keeps scrollbar\n * estimation sane before the browser has measured the real height. */\n content-visibility: auto;\n contain-intrinsic-size: auto 140px;\n}\n\n/* The sentinel that triggers the next shelf batch: zero visual footprint. */\n.s853040_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s239c39_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s88b200_card:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l1));\n transform: translateY(-1px);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s88b200_card { transition: none; }\n .s88b200_card:hover { transform: none; }\n}\n\n/* The signature: a spine and cover in the category's own hue. The hues are\n * fixed mid-bright colors that read on both themes; `other` deliberately\n * stays a neutral gray so the fallback category does not compete. */\n.sc1c25e_cardSpine {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 3px;\n background: var(--category-hue, #8B8E96);\n}\n\n/* The hue table, keyed by `data-category` and read by BOTH surfaces that\n * speak in category colour: a card's spine and badge, and the category bar's\n * own tab. One table, so a tab can never disagree with the cards it filters to\n * — which is the whole point of colouring the tab. `.s512425_categoryButton` sets the\n * brand fallback for `All`/`Installed`; these attribute selectors are one\n * specificity step above it and win wherever the attribute is present. */\n.s88b200_card[data-category='tool'], .s512425_categoryButton[data-category='tool'] { --category-hue: #4C8DFF; }\n.s88b200_card[data-category='provider'], .s512425_categoryButton[data-category='provider'] { --category-hue: #A78BFA; }\n.s88b200_card[data-category='ui'], .s512425_categoryButton[data-category='ui'] { --category-hue: #2DD4BF; }\n.s88b200_card[data-category='workflow'], .s512425_categoryButton[data-category='workflow'] { --category-hue: #F59E0B; }\n.s88b200_card[data-category='integration'], .s512425_categoryButton[data-category='integration'] { --category-hue: #34D399; }\n.s88b200_card[data-category='theme'], .s512425_categoryButton[data-category='theme'] { --category-hue: #F472B6; }\n.s88b200_card[data-category='other'], .s512425_categoryButton[data-category='other'] { --category-hue: #8B8E96; }\n\n/* The category sits in the badge row as a quiet chip in the category's own\n * hue — the border carries it where the light theme's white layers cannot\n * (the same lesson as the check button). */\n.s433c76_categoryBadge {\n padding: 1px 7px;\n border: 1px solid color-mix(in srgb, var(--category-hue, #8B8E96) 45%, transparent);\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--category-hue, #8B8E96);\n white-space: nowrap;\n}\n\n.s6bc968_entryHeader {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 12px;\n min-width: 0;\n padding: 8px 12px 2px;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.s6bc968_entryHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n/* The name fills the row and truncates rather than wraps; the badges stay\n * intact beside it. */\n.s704f0d_name {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n font-weight: 600;\n flex: 1 1 auto;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--dsw-alias-label-primary);\n}\n\n.sba9311_badges {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n/* The action line: buttons side by side; an active install/uninstall flow\n * (gate, log, notices) takes the full width below them. */\n.s9b33f4_cardActions {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n padding: 8px 12px 10px;\n}\n\n.s9b33f4_cardActions > .sc99cff_gate,\n.s9b33f4_cardActions > .sbd0905_installPanel,\n.s9b33f4_cardActions > .sd562d9_installedActions {\n flex-basis: 100%;\n}\n\n/* The entry's version, always visible on the card (the expanded detail\n * repeats it in the version row) — the same quiet mono as the toolbar. */\n.s83e5d6_cardVersion {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n /* A release tag prints as tagged, never cut to seven characters (market\n * borrowings §11), and a tag can run to any length. The cap keeps every\n * tag of up to fourteen characters whole, prerelease suffix included\n * (`v0.1.0-alpha.0`): fourteen glyphs plus the letter-spacing above come to\n * about 14.5ch, so the cap is 15ch, not 14. A longer tag ends in an ellipsis,\n * and the tooltip carries the whole of it. */\n max-width: 15ch;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* The octocat marking a source the reader can read on GitHub, beside the\n * card's version. */\n.s93d06c_sourceBadge {\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s1fe784_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.s1fe784_tierBadge[data-tier='verified'] {\n color: var(--shop-success);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent);\n}\n\n.s1fe784_tierBadge[data-tier='verified-stale'] {\n color: var(--shop-warn-on-tint);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n}\n\n.s1fe784_tierBadge[data-tier='community'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n/* The §C10 shadowed badge: an installed github entry the catalog refuses\n * shadowed-by-npm. Subdued/secondary rather than a warn tint — nothing is\n * wrong with the install itself; the shelf just cannot show it. */\n.s1fe784_tierBadge[data-tier='shadowed'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n/* The §C5 archived badge: a github repository the owner has frozen.\n * Subdued register, same as shadowed — nothing is wrong with the install;\n * the pinned commit still serves, so the mark is informational only. */\n.s1fe784_tierBadge[data-tier='archived'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n.s2f456e_incompatibleBadge {\n flex-shrink: 0;\n padding: 3px 9px;\n border-radius: 999px;\n font-size: 12px;\n white-space: nowrap;\n /* On the tint, not on the plain surface: this text reads on its own 14% red\n * fill, where the 90% red would measure 4.21:1 (light) and 4.43:1 (dark). */\n color: var(--shop-error-on-tint);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);\n}\n\n.sc6c968_starsBadge {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s287fda_chevron, .s20b60f_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s20b60f_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .s287fda_chevron, .s20b60f_chevronOpen { transition: none; }\n}\n\n.s87fcee_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px;\n}\n\n.sf5d0d8_summary {\n margin: 0;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.sa0923f_summaryZh {\n margin: -4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* Expanded cards show the full summary: the clamp is lifted, never raised —\n * a higher number would still truncate the author's text, just later. */\n.s20eea8_summaryExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n.sb53b34_summaryZhExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n/* `white-space: pre-line` so the newline in the copy is the copy's own: the\n dictionary decides where the line breaks, and a translator changes it\n without touching the component. Collapses runs of spaces like `normal`, so\n only the explicit \\n survives. */\n.sc2cc78_incompatibleDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n white-space: pre-line;\n color: var(--shop-error);\n}\n\n/* The way out of dsh's own refusal: the lead-in, then the exemption command\n * on its own line. */\n/* Block layout rather than flex: Firefox 153 will not line-clamp a container\n * that holds a display:flex child (Chromium 151 does), and the fold's\n * measured goal — \"the whole red block, remedy included, as one unit\" —\n * needs the container to clamp in BOTH engines the shop targets. The 4px\n * rhythm between the lead-in and the command is kept by the margins of the\n * children. */\n.sc7602c_remedy {\n display: block;\n}\n\n.sc7602c_remedy > * + * { margin-top: 4px; }\n\n/* The fold under a card's whole red block: two lines by default, a small\n * Refresh-pill-shaped toggle under it. Two containers, one rhythm: the shelf\n * uses `.s895dae_foldBlock` collapsed and `.s6b136d_foldBlockExpanded` open, and they share\n * one `display: block` (Firefox clamps no flex child inside a -webkit-box).\n * The clamp is on the BLOCK rather than any one line, so a 43-line remedy\n * counts as a unit instead of squashing the harness-peers line to a sliver\n * and hiding the command the reader actually came for. Both containers\n * still render the full block to a screen reader — `white-space: normal`\n * instead of pre-line keeps the copy's own `\\n` visible without forcing the\n * browser to lay the block's pieces like a text node. */\n.s895dae_foldBlock {\n display: block;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n display: -webkit-box;\n overflow: hidden;\n}\n\n.s6b136d_foldBlockExpanded { display: block; }\n\n/* The toggle. Geometry and quiet voice are the Refresh pill's\n * (`catalogStatsRow` right beside it on the same screen): one 1px border,\n * 11px text, secondary label, no fill. It is the only one of its kind here,\n * so a class of its own means one function of its own. */\n.s8c3792_foldToggle {\n padding: 1px 9px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n line-height: 17px;\n cursor: pointer;\n}\n\n.s8c3792_foldToggle:hover { border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2)); }\n.s8c3792_foldToggle:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }\n\n.s935bd9_remedyLead {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The exemption command, bound for a terminal unchanged: one click selects\n * all of it, and it wraps anywhere rather than widening the card. A border,\n * not a fill, marks the box: the bg layers are one white in the light theme. */\n.se75f45_allowCommand {\n display: block;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n white-space: pre-wrap;\n word-break: break-all;\n user-select: all;\n color: var(--dsw-alias-label-primary);\n}\n\n/* A refused install on a surface that does not state its blockers — the\n * outdated row — writes them out on their own full-width line under the\n * refused label, the command that clears dsh's refusal included. Block,\n * rather than flex: Firefox will not line-clamp a -webkit-box that holds a\n * display:flex child, and the fold this element can sit inside of carries\n * that clamp. The 6px rhythm between the block's lines is carried by the\n * children's margins. */\n.se69fd7_refusal {\n display: block;\n flex-basis: 100%;\n}\n\n.se69fd7_refusal > * + * { margin-top: 6px; }\n\n.sb2edea_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.sa5c8b2_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sb95e1e_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.sb95e1e_capabilities li {\n padding: 1px 6px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s1f4436_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.sf6f153_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.sbfe178_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.sbfe178_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.sbfe178_detailRow dd {\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n overflow-wrap: anywhere;\n text-align: right;\n color: var(--dsw-alias-label-primary);\n}\n\n.sbfe178_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.sbfe178_detailRow a:hover {\n text-decoration: underline;\n}\n\n.sbfe178_detailRow a:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* What the entry IS rather than what you can do with it — how big it is and\n * who published it — at the right edge of the action row. `margin-left: auto`\n * is what pushes it there, and it lives on this wrapper rather than on either\n * label so the group stays flush right when only one of the two has a value —\n * a packument that named no account has no author, and an entry the registry\n * could not measure honestly has no size. Rarer than it was (every live entry\n * now carries a size, github included), but the wrapper is not what makes it\n * rare: without one, an EMPTY meta group still costs 8px, because\n * `.s9b33f4_cardActions` is a flex row with `gap: 8px` and a zero-width item is still\n * an item. The row is a wrapping flex, so an active install flow (which claims\n * the full width) drops the whole group to the next line rather than squeezing\n * it. */\n.s92d907_cardMeta {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n min-width: 0;\n}\n\n/* The on-disk size, left of the author. Mono and tabular so the digits of one\n * figure line up with the digits of another WHEREVER the two land: `.s92d907_cardMeta`\n * is flush right and the author sits outside the size, so a size's x position\n * moves with the author's width and is different again on the many entries\n * that carry no author at all. There is no column to align to, which is why\n * the reason given here is per-figure legibility rather than the column the\n * first version of this comment claimed. Secondary colour, because it\n * qualifies the entry rather than announcing it.\n *\n * `font-variant-numeric` is safe HERE and would not be on a pill: this element\n * has no state rules, so nothing it does can reflow a wrapping row.\n *\n * `.s6119f4_shelfDate` shares this rule because it is the same kind of fact — a\n * fixed-width figure a reader compares down the shelf (design\n * 2026-10-12-shelf-orders §4) — and two copies of these declarations would\n * drift. */\n.s5889e2_size,\n.s6119f4_shelfDate {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-variant-numeric: tabular-nums;\n font-size: 12px;\n letter-spacing: 0.02em;\n white-space: nowrap;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The publishing account, at the outer end of `.s92d907_cardMeta` on the action row —\n * NOT beside the npm link in the expanded detail, which is where it used to\n * live and what this comment described until the accurate half was deleted\n * with the `margin-left: auto` that moved to `.s92d907_cardMeta`. There is no middot:\n * `.s92d907_cardMeta`'s 8px gap separates it from the size.\n *\n * Secondary label colour carries the distinction — never a background fill,\n * which is invisible in the light theme where every bg-layer token is the\n * same white. */\n.s5efcbe_author {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.sdd3957_reviewedLine {\n margin: 8px 0 0;\n padding: 6px 8px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n font-size: 12px;\n color: var(--shop-warn-on-tint);\n}\n\n/* Install flow. */\n.sbd0905_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n/* ONE geometry for everything that occupies the install button's place: the\n * button itself, the confirm/cancel pair beside the restart gate, the installed\n * label, and the refused label. Stated once because a refused label HAS to look\n * like the button it replaces apart from its colour and its text, and four\n * copies of the same five declarations is how they stop looking alike.\n * `cursor: pointer` is NOT here: only the controls that can be pressed take it,\n * while a label renders with the default cursor. */\n.se20cee_installButton,\n.sdf88f9_confirmButton,\n.s330a03_cancelButton,\n.sad029f_installedLabel,\n.s7b7f2d_refusedLabel {\n align-self: flex-start;\n margin: 0;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n font-size: 13px;\n}\n\n.se20cee_installButton, .sdf88f9_confirmButton, .s330a03_cancelButton {\n cursor: pointer;\n}\n\n.se20cee_installButton {\n border-color: var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n/* Between the click and the host's answer. The flow ignores a repeat start for\n * the same identity, so this is the visible half of the same fact: a control\n * that says \"not now\" rather than one that looks ready to send a second\n * install. Only the button can be in this state — a label is never pressed. */\n.se20cee_installButton:disabled {\n cursor: wait;\n}\n\n.se20cee_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.sdf88f9_confirmButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.sdf88f9_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s330a03_cancelButton {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n}\n\n.s330a03_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.se20cee_installButton:focus-visible, .sdf88f9_confirmButton:focus-visible, .s330a03_cancelButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The shelf card of a plugin that is installed and current carries this\n * non-interactive label instead of an install button. Border + text do the\n * work in the light theme, where every bg-layer token resolves to white. */\n.sad029f_installedLabel {\n align-self: flex-start;\n margin: 0;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n font-size: 13px;\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n/* The refused Install/Update button's replacement: the same box as the button\n * (the geometry rule above), filled solid red, not pressable. The fill is the\n * derived red rather than the raw token because text sits on it — bg-base on\n * `--shop-error` measures 5.31:1 light and 6.14:1 dark — and the raw error red\n * under bg-base text measures 4.498:1, the miss this whole family of fixes\n * exists for. Nothing here changes on hover: it is a statement, not a control,\n * so it keeps the default cursor and its colours. */\n.s7b7f2d_refusedLabel {\n border-color: var(--shop-error);\n background: var(--shop-error);\n color: var(--dsw-alias-bg-base);\n white-space: nowrap;\n}\n\n/* An installed card's controls: the installed label or the update button,\n * plus the uninstall button. The install panel's running/failed states are\n * column layouts and sit as one item of this row. */\n.sd562d9_installedActions {\n display: flex;\n align-items: flex-start;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n/* Uninstall revokes privilege; the quiet outline keeps it from competing\n * with the primary action, and the error tint says \"removes\". */\n.s1ef16e_uninstallButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 55%, transparent);\n border-radius: 6px;\n background: transparent;\n /* The on-tint red: hovering this button paints a 10% red fill under the\n * word, where the plain red measures 4.50:1 (light) — the same two\n * thousandths short of the floor the raw token shipped at. */\n color: var(--shop-error-on-tint);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s1ef16e_uninstallButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.s1ef16e_uninstallButton:focus-visible {\n outline: 2px solid var(--dsw-alias-state-error-primary);\n outline-offset: 1px;\n}\n\n/* The restart dsh button on a done install: quiet outline, same rank as\n * the other secondary actions. */\n.s912ec7_restartSelfButton {\n /* The version row's third state. Geometry matches .sb48cbc_checkUpdateButton and\n * .s79450a_updateSelfButton exactly — the row is one evolving control and a\n * different pill would read as a different kind of thing. It takes the\n * emphasised fill rather than the neutral one because at that moment the\n * restart is the only thing left to do, the same reason Update has it. */\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n color: var(--dsw-alias-brand-primary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.s912ec7_restartSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The two activation offers share one recipe: a border in an alias token,\n * never a `bg-layer` fill alone — all four bg-layer tokens collapse to the\n * same white under `body` in the light theme, and a fill-only button would\n * vanish there. Grouped rather than copied, because a copy is a rule that\n * can be corrected on one button and left wrong on the other, silently. */\n.sa5d8c1_restartButton,\n.se5bd2c_reloadButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.sa5d8c1_restartButton:hover,\n.se5bd2c_reloadButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.sa5d8c1_restartButton:focus-visible,\n.se5bd2c_reloadButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The §4 reload offer: a notice plus its button, one item of\n * `.sd562d9_installedActions` the way the restart gate is — a column of its own\n * rather than inline with the row. */\n.s76690e_reloadPanel {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n}\n\n\n.sc99cff_gate {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n border: 1px solid var(--dsw-alias-state-warn-primary);\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n.s58fe9b_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--shop-warn-on-tint);\n}\n\n.sd510f5_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s943dbd_gateWarning {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n white-space: pre-line;\n color: var(--shop-error);\n}\n\n.sb2e35c_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.s407016_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s56c1a5_log {\n max-height: 160px;\n overflow: auto;\n margin: 0;\n padding: 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n list-style: none;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n}\n\n.s3d7aca_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s3e1ea0_notice {\n margin: 0;\n font-size: 12px;\n color: var(--shop-success);\n}\n\n.s71965d_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--shop-error);\n}\n\n.s41bb43_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s3b880d_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--shop-error);\n}\n\n.s465924_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The Updatable section. The class keeps the Host's field name; only the\n heading the reader sees was renamed. */\n.sfccf6f_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.s403f9e_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.sd9cb61_outdatedRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n.s7b2d89_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s7b2d89_outdatedInfo strong {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n word-break: break-all;\n color: var(--dsw-alias-label-primary);\n}\n\n.sc33878_outdatedVersions {\n /* Two inline labels with nothing between them in the markup ran together as\n * `installed v1.0.0latest v2.0.0`: JSX drops the whitespace-only line, and\n * the per-label class the markup asked for was never defined (singular\n * against this rule's plural). The container owns the gap, the same idiom\n * as .sba9311_badges — the labels need no class of their own. */\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The §C10 shadowed section. Reuses the outdated list's visual language; only\n * the section spacing and the per-row explanation paragraph are its own. */\n.sa88998_shadowedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.s98799e_shadowedDetail {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n}\n\n.saaf7ce_outdatedActions {\n display: flex;\n align-items: center;\n /* The reload offer (§4) mounts inside the switch beside the Update button\n * and is a two-line block, not a control: without wrapping, a row reading\n * [switch][notice + Reload][Update] overflowed the Settings dialog the shop\n * sat in through 0.8.7, and the page's column narrows with the window. */\n flex-wrap: wrap;\n gap: 10px;\n}\n\n/* The shop's one switch. It is worn by two controls that mean different\n * things — the enable/disable toggle on an installed card, and the shelf's\n * incompatible filter — so the geometry lives here once and each caller states\n * only its hue.\n *\n * `--switch-hue` is that knob, and it is read from the ANCESTOR rather than\n * declared per state: `.s7ce437_incompatibleFilter` sets it once and it reaches the\n * track and the label together, which is what keeps a red switch from sitting\n * under a neutral word. A declaration on `.s3a8382_switch` itself would shadow the\n * inherited value (an element's own rule beats what it inherits), so the\n * default rides in the `var()` fallback and is resolved once into\n * `--track-hue` instead of being spelled out at each use.\n *\n * `box-sizing` and `padding` are stated because the two callers are different\n * elements — a `<button>`, which the UA gives padding, and a `<span>`, which\n * it does not. Without them the same class renders two sizes, and the knob\n * sits 2px above centre in the taller one. */\n.s3a8382_switch {\n --track-hue: var(--switch-hue, var(--dsw-alias-state-success-primary));\n box-sizing: border-box;\n display: inline-block;\n position: relative;\n width: 32px;\n height: 18px;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n\n/* The knob's POSITION is the state, which is the reason this control needs no\n * `forced-colors` fallback the way the category pills do: a system palette\n * replaces every colour below and moves nothing. */\n.s1e392e_switchOn {\n border-color: var(--track-hue);\n background: color-mix(in srgb, var(--track-hue) 55%, transparent);\n}\n\n.s419ba1_switchKnob {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: 999px;\n background: var(--dsw-alias-label-primary);\n transition: transform 120ms ease, background 120ms ease;\n}\n\n.s1e392e_switchOn .s419ba1_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.s3a8382_switch:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s3a8382_switch, .s419ba1_switchKnob { transition: none; }\n}\n\n/* The hot enable/disable switch on installed rows: the knob button plus the\n * §8 hot-apply / failure notices rendered beside it. */\n.saa9c93_switchWrap {\n display: inline-flex;\n align-items: center;\n /* Same reason as `.saaf7ce_outdatedActions`: `.s76690e_reloadPanel`'s own comment calls\n * itself \"a column of its own rather than inline with the row\", which held\n * for `.sd562d9_installedActions` and not here until this line. */\n flex-wrap: wrap;\n gap: 8px;\n}\n";
|
|
8408
|
-
if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"
|
|
8420
|
+
//#region \0dsh-plugin-shop-css:a037354d
|
|
8421
|
+
const css = "/* Shop styles — the shop's own page with its market shelf, and the shop's two\n * buttons on dsh's Plugins page. Every variable read here is a dsh theme\n * alias token (`--dsw-alias-*`), one of the shop's own properties declared in\n * this file (`--shop-*`, `--category-hue`, `--switch-hue`, `--track-hue`), or\n * one of two dsh variables outside the alias set, each read where the shop\n * copies dsh: `--dsh-frame-top-clearance`, so the page head clears the\n * desktop frame as dsh's own pages do, and `--dsw-radius-sm`, because the\n * Plugins page buttons copy dsh's Button (0.1.5-rc.3 lacks that token, and\n * has no Plugins page to draw them on). `state-error` and\n * `state-success` do not exist, so the state-*-primary set stands in for\n * them (measured 2026-10-17 on dsh 0.1.5-rc.3, 0.1.7-rc.2 and 0.2.0-rc.2,\n * which do define `bg-layer-3` and `interactive-bg-hover`, once listed here\n * as missing). The signature is the category spine: one HUE per\n * category (seven fixed hues, not the brand token — the brand resolves to\n * near-black in the light theme, so seven brand opacities read as seven\n * shades of gray), with the category name as the cover label in the same hue. Class names are mapped to content-derived names at bundle time\n * (tsdown.sa584e5_client.s18f7ee_config.s39f74c_ts) and stubbed in tests; only the keys are relied\n * on.\n *\n * One token rule the theme forces: the background LAYERS do not carry\n * contrast. In the light theme bg-base, bg-layer-1, bg-layer-2 and\n * bg-layer-3 all resolve to the same white; only the dark theme spreads them\n * (950/875/850/800). So a layer-2 fill on a layer-1 ground is invisible for\n * half of all users, and anything whose fill is its ONLY affordance — the\n * loading skeleton, the borderless capability chips — derives its fill from\n * label-primary instead, which inverts with the theme by construction.\n * Elements that also carry a border or text may keep a layer fill.\n * `css-tokens.sa584e5_client.sf107cf_spec.s39f74c_ts` pins this. */\n\n.s8de901_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n /* The two reds every red text in this tab is painted with. dsh's error red\n * is #ec1313 in the light theme, which measures 4.498:1 as text on white —\n * a miss of two thousandths — and 3.57:1 on the badge's own 14% red fill\n * (4.00:1 in dark). Mixing it toward label-primary fixes both, because\n * label-primary is the theme's foreground pole: it darkens the red on light\n * surfaces and lightens it on dark ones. Measured in the live app: 90% of\n * the red is 5.30:1 on white and 5.29:1 on the dark card, and 80% is\n * 4.98:1 on the badge's tint, 4.92:1 in dark. Computed: 90% is 6.14:1 on\n * the dark page itself (#151517, `bg-base`), where the self-update's\n * failure heading sits (4.69:1 on Settings' #2c2c2e, its ground through\n * 0.8.7), and 80% is 5.23:1 on the uninstall button's 10% hover fill.\n * Declared here, on the tab root, because a custom property inherits: one\n * declaration reaches every red element, and a new one cannot be\n * forgotten. */\n --shop-error: color-mix(in srgb, var(--dsw-alias-state-error-primary) 90%, var(--dsw-alias-label-primary));\n --shop-error-on-tint: color-mix(in srgb, var(--dsw-alias-state-error-primary) 80%, var(--dsw-alias-label-primary));\n /* The amber and the green, mixed the same way for the same reason. dsh's\n * warn #f59e0b and success #22c55e are one value in both themes and pass\n * in the dark one, but as text on white they measure 2.15:1 and 2.28:1.\n * Each derived colour keeps the largest multiple of ten of its hue that\n * clears every surface it paints, as the reds do. Computed from the live\n * tokens over every bg layer in both themes: amber at 60% is 4.95:1 on a\n * plain surface but 4.44:1 on its own 14% tint, so text on an amber tint\n * takes 50% (5.66:1); green at 60% is 5.18:1 plain and 4.60:1 on its 14%\n * tint, so one green serves both. */\n --shop-warn: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 60%, var(--dsw-alias-label-primary));\n --shop-warn-on-tint: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 50%, var(--dsw-alias-label-primary));\n --shop-success: color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary));\n /* The shelf never scrolls sideways: a card too wide for its track wraps\n * its badges rather than widening the panel.\n *\n * Clipped on BOTH axes, with a margin, because `.s3e432c_searchInput` sits at\n * exactly (0, 0) of this box — it is the first child of `.s9a1d55_toolbar`, itself\n * the first child here, and this rule carries no padding — so its focus\n * ring paints ENTIRELY outside the panel.\n *\n * Both axes is the load-bearing part: `overflow-clip-margin` is inert\n * unless the element clips on both. Clipping x alone left the margin doing\n * nothing — measured against the live app on 0.7.1, the ring reached 0 of\n * its 3px on the left at every device pixel ratio (1, 1.25, 1.5, 2), while\n * keeping the full 3px on the right, where the 280px input stops short of\n * the panel and never meets the clip edge. Raising the margin to 6px\n * changed nothing; clipping both axes with the SAME 3px restored the whole\n * ring. A test that reads declarations cannot see that difference, which is\n * why the first attempt at this shipped broken.\n *\n * `clip` is not a scroll container, so this does not bring back the\n * accidental scrolling `hidden` caused by coercing the other axis to\n * `auto`. Nothing is lost vertically: the panel's scrollHeight equals its\n * height and no descendant paints outside the clip rect (measured).\n * `overflow-x: hidden` stays as the fallback for engines without `clip`,\n * where the ring is clipped as it was before, never worse. */\n overflow-x: hidden;\n overflow: clip;\n overflow-clip-margin: 3px;\n}\n\n/* The shop's own page in dsh's main column (design\n * 2026-10-16-shop-sidebar-page §4.2), framed as dsh 0.2.0-rc.2 frames its\n * Plugins page — read from that page's stylesheet: the page is the scroll\n * container, its children one centred column of at most 960px, and the head\n * clears the desktop title bar. One declaration is the shop's own, `color`:\n * dsh's `.sa6404f_page` inherits its colour from the shell around it, and the shop's\n * root is not inside dsh's panel stylesheet, so the shop's page states it. */\n.sa6404f_page {\n box-sizing: border-box;\n height: 100%;\n overflow: auto;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 32px;\n padding: 0 clamp(24px, 4vw, 48px) 48px;\n color: var(--dsw-alias-label-primary);\n}\n\n.sa6404f_page > * {\n width: 100%;\n max-width: 960px;\n}\n\n.scab2f9_pageHead {\n box-sizing: border-box;\n padding-top: calc(28px + var(--dsh-frame-top-clearance, 0px));\n}\n\n.sc4a729_pageTitle {\n margin: 0;\n font-size: 20px;\n font-weight: 500;\n line-height: 28px;\n}\n\n/* Secondary, as dsh's own intro: 5.80:1 on the light theme's white. */\n.s14e198_pageIntro {\n margin: 4px 0 0;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The two buttons on dsh's Plugins page (design 2026-10-16-shop-sidebar-page\n * §7), drawn as that page draws its own small outline buttons beside them —\n * dsh 0.2.0-rc.2's Button, sm + outline: 28px tall, 12px text on an 18px\n * line, 10px of side padding, the small radius, the neutral stroke. That\n * stroke is 0.5px in dsh and 1px here: every border in this stylesheet is,\n * and Chromium paints 0.5px as 1px at every ratio measured. */\n.sd04f34_detailAction {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 28px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n cursor: pointer;\n}\n\n.sd04f34_detailAction:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.sd04f34_detailAction:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sfb4615_stateLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* Visually hidden but screen-reader readable (the loading copy while the\n * skeleton stands in visually). */\n.s43702a_srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n overflow: hidden;\n white-space: nowrap;\n}\n\n/* The loading shelf: ghost cards with the same geometry as the real grid, so\n * the swap to content is a same-shape handoff instead of a jump. */\n.se66364_skeletonGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 8px;\n}\n\n.s41d8a9_skeletonCard {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n}\n\n/* The shimmer sweep: one gradient band travels across each ghost card while\n * the bars breathe, so the loading state reads as \"the shelf is scanning\". */\n.s41d8a9_skeletonCard::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 100deg,\n transparent 25%,\n color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent) 50%,\n transparent 75%\n );\n transform: translateX(-100%);\n animation: dshShopSkeletonSweep 1.4s ease-in-out infinite;\n pointer-events: none;\n}\n\n@keyframes dshShopSkeletonSweep {\n to { transform: translateX(100%); }\n}\n\n.sbad351_skeletonName {\n width: 55%;\n height: 14px;\n margin: 10px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sb2be83_skeletonSummary {\n width: 92%;\n height: 12px;\n margin: 10px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.s67c868_skeletonSummaryShort {\n width: 68%;\n height: 12px;\n margin: 6px 12px 10px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n/* The ghost of the action line, right where the real buttons land. */\n.sbcd6ff_skeletonActions {\n display: block;\n width: 84px;\n height: 24px;\n margin: 0 12px 10px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.s41d8a9_skeletonCard span {\n animation: dshShopSkeletonPulse 1.6s ease-in-out infinite;\n}\n\n@keyframes dshShopSkeletonPulse {\n 0%, 100% { opacity: 0.5; }\n 50% { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s41d8a9_skeletonCard span { animation: none; opacity: 0.75; }\n .s41d8a9_skeletonCard::after { content: none; }\n}\n\n.s602b18_actionButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s602b18_actionButton:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.s602b18_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s9a1d55_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.se2add9_toolbarRight {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n/* The shop's own version, right of the search box: `v0.4.4`, plus the\n * update button when the version check found a newer release. */\n.sf1bc7d_versionBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.seba9a7_versionText {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s8c1ada_updateSelfButton {\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n color: var(--dsw-alias-brand-primary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.s8c1ada_updateSelfButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 20%, transparent);\n}\n\n.s8c1ada_updateSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The on-demand re-check next to the version number: a quiet pill; the\n * border and text carry it in the light theme where bg layers are white. */\n.s82f241_checkUpdateButton {\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n.s82f241_checkUpdateButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n color: var(--dsw-alias-label-primary);\n}\n\n.s82f241_checkUpdateButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.s82f241_checkUpdateButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The project's GitHub mark, right of the version row: a quiet icon link.\n * The octocat carries itself — color shift on hover, no text, no border. */\n.s1e95bf_githubLink {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 3px;\n border-radius: 6px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s1e95bf_githubLink:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.s1e95bf_githubLink:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The self-update's expanded states (running log / done + restart /\n * failure detail) sit under the toolbar, above the category bar. */\n.s91bcc4_selfUpdatePanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.s3e432c_searchInput {\n width: min(280px, 100%);\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n.s3e432c_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* Subdued line under the search box when a dictionary intent fired (design\n * 2026-10-08-search-query-expansion §4). One fact, no badge. */\n.s712943_expansionNote {\n margin: 4px 0 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sf2024f_staleBadge {\n padding: 2px 8px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n color: var(--shop-warn-on-tint);\n font-size: 12px;\n}\n\n.s630e95_categoryBar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n}\n\n.s4575ba_categoryButton {\n /* The hue this button carries when selected. `All` and `Installed` select by\n * something other than a category and keep the brand token; the six category\n * buttons override it from the shared hue table below, so a pressed Tool tab\n * turns the same blue as a tool card's spine. */\n --category-hue: var(--dsw-alias-brand-primary);\n padding: 3px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n/* Blend text with the theme foreground: darker on light backgrounds, lighter\n * on dark ones. The unblended category hue belongs on the border and fill. */\n.s4575ba_categoryButton:hover {\n border-color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-border-l2));\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Selected. Written `.s4575ba_categoryButton.s7c5955_categoryButtonOn` — TWO classes — so it\n * matches `.s4575ba_categoryButton:hover`'s specificity and, coming after it, wins.\n * As a bare `.s7c5955_categoryButtonOn` it lost both `border-color` and `color` to the\n * hover rule for as long as the pointer stayed on the tab that had just been\n * clicked, which is precisely when a reader looks for confirmation.\n *\n * EVERY declaration here is a colour: a pressed tab must occupy exactly the\n * same box as an unpressed one, so the bar does not reflow — and with ~9 pills\n * on a wrapping row, one that grows can push the rest onto another line and\n * move the tab out from under the pointer that just clicked it. That is what\n * `font-weight: 600` did (bold metrics are wider than regular), and it is why\n * nothing may be added here that resolves to a length: no padding, no\n * border-width, no font-size, no letter-spacing. `css-tokens.sa584e5_client.sf107cf_spec.s39f74c_ts`\n * fails the build on one.\n *\n * Nor a second line. An inset ring once doubled this border, and every control\n * in the stylesheet now draws exactly one 1px line, which is also the thinnest\n * the host paints (Chromium draws 0.5px as 1px). What separates pressed from\n * unpressed is lightness instead of thickness: the border is the hue mixed 30%\n * toward label-primary, the theme's foreground pole, so it clears 3:1 against\n * the bar in both themes for every hue — the raw hue measured 1.86:1 on white\n * for `ui` — and the fill under it is 22% of the hue. The `other` tab is the\n * case this is for: its hue IS the neutral gray this file uses for \"no\n * category\", so on the light theme the hue alone barely separates the two. */\n.s4575ba_categoryButton.s7c5955_categoryButtonOn {\n border-color: color-mix(in srgb, var(--category-hue) 70%, var(--dsw-alias-label-primary));\n background: color-mix(in srgb, var(--category-hue) 22%, transparent);\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Forced colours replace every colour above with the system palette, which\n * would leave the three colour declarations saying nothing and the pressed tab\n * indistinguishable from its neighbours, so this mode alone gets an outline. */\n@media (forced-colors: active) {\n .s4575ba_categoryButton.s7c5955_categoryButtonOn {\n outline: 2px solid ButtonText;\n outline-offset: -4px;\n }\n}\n\n.s4575ba_categoryButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The incompatible filter, at the right edge of the category bar: `margin-left:\n * auto` pushes it past the pills, and the bar wraps, so on a narrow panel it\n * drops to its own line rather than squeezing them. It is a MODIFIER, not a\n * ninth category — the categories select what to show and this one subtracts\n * from whatever they selected — so it takes the error hue it filters on rather\n * than joining the hue table.\n *\n * And it is a SWITCH, which is the difference the shape now carries. It used\n * to wear `.s4575ba_categoryButton`: same pill, same row, same size as the eight tabs,\n * differing only in being red. That reads as a ninth tab, and it is not one —\n * the tabs are choose-one and this is on-or-off. So it drops the pill chrome\n * entirely (no border, no fill, nothing to compete with the row it sits\n * beside) and puts the state in a track, the same one every installed card\n * carries. Nothing here restates the switch geometry; `--switch-hue` is the\n * whole of what this control says about it, and it reaches the label too, so\n * one declaration keeps the word and the track the same colour. */\n.sc56af2_incompatibleFilter {\n --switch-hue: var(--dsw-alias-state-error-primary);\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n /* Matches the pills' vertical padding so the bar keeps one line box whether\n * this control wraps onto a row of its own or shares theirs. */\n padding: 3px 0;\n border: 0;\n background: none;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n/* Hover lifts the word to full contrast and warms the track's border. Scoped\n * to the OFF track: `.sc56af2_incompatibleFilter:hover .s247428_switch` outranks `.se62fac_switchOn`\n * by two classes, so unscoped it would strip the hue from the border at\n * exactly the moment a reader has the pointer on it to check the state. */\n.sc56af2_incompatibleFilter:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.sc56af2_incompatibleFilter:hover .s247428_switch:not(.se62fac_switchOn) {\n border-color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-border-l2));\n}\n\n/* On. Written with both classes for the reason `.s4575ba_categoryButton.s7c5955_categoryButtonOn`\n * is: it has to match `:hover`'s specificity and come after it, or the colour\n * reverts under a pointer that has not moved since the click. */\n.sc56af2_incompatibleFilter.s46063b_incompatibleFilterOn {\n color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Off here means \"nothing is being taken away\" — the resting state — so the\n * knob steps back to the secondary label. The enable switch keeps the full\n * strength dot, where off means \"this plugin is disabled\" and is worth\n * noticing. In this bar it would be the heaviest mark in a row of hairline\n * pills, and on the light theme it is the WHOLE control: bg-layer-2 is the\n * same white as the panel there, so an off track is a hairline outline with a\n * near-black dot sitting in it. */\n.sc56af2_incompatibleFilter .s247428_switch:not(.se62fac_switchOn) .se0ac0b_switchKnob {\n background: var(--dsw-alias-label-secondary);\n}\n\n/* The ring has no border to trace, so it takes an offset and the pill radius\n * of the tabs it sits beside rather than hugging the text. */\n.sc56af2_incompatibleFilter:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 999px;\n}\n\n.s622eb2_updatableHeading {\n margin: 2px 0 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-primary);\n}\n\n.s7ef365_catalogStatsRow {\n display: flex;\n align-items: center;\n /* The row holds the catalog line, the refresh button and the shelf order's\n * three pills (design 2026-10-12-shelf-orders §4). Without wrapping, the\n * last of them overflows the tab at a narrow width. */\n flex-wrap: wrap;\n gap: 10px;\n margin: 6px 0 0;\n}\n\n/* The shelf's order control, at the right end of the stats row. `margin-left:\n * auto` is what puts it there while the line and the refresh button stay\n * left — and it is safe on a wrapping row, unlike a width. */\n.sa2f85b_sortGroup {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n margin-left: auto;\n}\n\n.s9d1f07_sortLabel {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.sd5812b_catalogStats {\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* Sits beside the 12px stats caption, so it is quieter than `.s602b18_actionButton`:\n * this is an affordance, not a call to action — the catalog reloads on its\n * own at mount and the shelf is already usable without it. Named\n * `catalogRefresh*` (not `reload*`) so it cannot collide with the §4 page\n * reload offer below, which reloads the whole tab rather than refetching\n * the catalog data. */\n.sc01148_catalogRefreshButton {\n padding: 1px 9px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n line-height: 17px;\n cursor: pointer;\n}\n\n.sc01148_catalogRefreshButton:hover:not(:disabled) {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.sc01148_catalogRefreshButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.sc01148_catalogRefreshButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s7acae8_catalogRefreshFailed {\n font-size: 11px;\n color: var(--shop-warn);\n}\n\n.saec8bc_emptyLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* The shelf: a responsive grid of cards. */\n/* Single-line rows: one full-width column, one plugin per line. */\n.sc932e7_cards {\n display: grid;\n grid-template-columns: 1fr;\n max-width: 100%;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n animation: dshShopCardsIn 220ms ease;\n}\n\n@keyframes dshShopCardsIn {\n from { opacity: 0; transform: translateY(3px); }\n to { opacity: 1; transform: none; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .sc932e7_cards { animation: none; }\n}\n\n.s341f40_card {\n position: relative;\n display: flex;\n flex-direction: column;\n /* A grid item's min-width is auto by default: its content would widen the\n * 1fr track past the panel and overflow horizontally. */\n min-width: 0;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n transition: border-color 120ms ease, transform 120ms ease, box-shadow 120ms ease;\n /* Off-screen cards skip layout and paint; the placeholder keeps scrollbar\n * estimation sane before the browser has measured the real height. */\n content-visibility: auto;\n contain-intrinsic-size: auto 140px;\n}\n\n/* The sentinel that triggers the next shelf batch: zero visual footprint. */\n.sd43e97_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.sb9f4b3_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s341f40_card:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l1));\n transform: translateY(-1px);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s341f40_card { transition: none; }\n .s341f40_card:hover { transform: none; }\n}\n\n/* The signature: a spine and cover in the category's own hue. The hues are\n * fixed mid-bright colors that read on both themes; `other` deliberately\n * stays a neutral gray so the fallback category does not compete. */\n.s3a0d45_cardSpine {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 3px;\n background: var(--category-hue, #8B8E96);\n}\n\n/* The hue table, keyed by `data-category` and read by BOTH surfaces that\n * speak in category colour: a card's spine and badge, and the category bar's\n * own tab. One table, so a tab can never disagree with the cards it filters to\n * — which is the whole point of colouring the tab. `.s4575ba_categoryButton` sets the\n * brand fallback for `All`/`Installed`; these attribute selectors are one\n * specificity step above it and win wherever the attribute is present. */\n.s341f40_card[data-category='tool'], .s4575ba_categoryButton[data-category='tool'] { --category-hue: #4C8DFF; }\n.s341f40_card[data-category='provider'], .s4575ba_categoryButton[data-category='provider'] { --category-hue: #A78BFA; }\n.s341f40_card[data-category='ui'], .s4575ba_categoryButton[data-category='ui'] { --category-hue: #2DD4BF; }\n.s341f40_card[data-category='workflow'], .s4575ba_categoryButton[data-category='workflow'] { --category-hue: #F59E0B; }\n.s341f40_card[data-category='integration'], .s4575ba_categoryButton[data-category='integration'] { --category-hue: #34D399; }\n.s341f40_card[data-category='theme'], .s4575ba_categoryButton[data-category='theme'] { --category-hue: #F472B6; }\n.s341f40_card[data-category='other'], .s4575ba_categoryButton[data-category='other'] { --category-hue: #8B8E96; }\n\n/* The category sits in the badge row as a quiet chip in the category's own\n * hue — the border carries it where the light theme's white layers cannot\n * (the same lesson as the check button). */\n.s5e7fbd_categoryBadge {\n padding: 1px 7px;\n border: 1px solid color-mix(in srgb, var(--category-hue, #8B8E96) 45%, transparent);\n border-radius: 999px;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--category-hue, #8B8E96);\n white-space: nowrap;\n}\n\n.s72c02a_entryHeader {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 12px;\n min-width: 0;\n padding: 8px 12px 2px;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.s72c02a_entryHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n/* The name fills the row and truncates rather than wraps; the badges stay\n * intact beside it. */\n.s54a911_name {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n font-weight: 600;\n flex: 1 1 auto;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: var(--dsw-alias-label-primary);\n}\n\n.sa76f21_badges {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: 6px;\n}\n\n/* The action line: buttons side by side; an active install/uninstall flow\n * (gate, log, notices) takes the full width below them. */\n.sca19d2_cardActions {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n padding: 8px 12px 10px;\n}\n\n.sca19d2_cardActions > .s14145c_gate,\n.sca19d2_cardActions > .s170b01_installPanel,\n.sca19d2_cardActions > .sd9c8c5_installedActions {\n flex-basis: 100%;\n}\n\n/* The entry's version, always visible on the card (the expanded detail\n * repeats it in the version row) — the same quiet mono as the toolbar. */\n.sf0e287_cardVersion {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n /* A release tag prints as tagged, never cut to seven characters (market\n * borrowings §11), and a tag can run to any length. The cap keeps every\n * tag of up to fourteen characters whole, prerelease suffix included\n * (`v0.1.0-alpha.0`): fourteen glyphs plus the letter-spacing above come to\n * about 14.5ch, so the cap is 15ch, not 14. A longer tag ends in an ellipsis,\n * and the tooltip carries the whole of it. */\n max-width: 15ch;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* The octocat marking a source the reader can read on GitHub, beside the\n * card's version. */\n.s75ac5c_sourceBadge {\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s861686_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.s861686_tierBadge[data-tier='verified'] {\n color: var(--shop-success);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent);\n}\n\n.s861686_tierBadge[data-tier='verified-stale'] {\n color: var(--shop-warn-on-tint);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n}\n\n.s861686_tierBadge[data-tier='community'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n/* The §C10 shadowed badge: an installed github entry the catalog refuses\n * shadowed-by-npm. Subdued/secondary rather than a warn tint — nothing is\n * wrong with the install itself; the shelf just cannot show it. */\n.s861686_tierBadge[data-tier='shadowed'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n/* The §C5 archived badge: a github repository the owner has frozen.\n * Subdued register, same as shadowed — nothing is wrong with the install;\n * the pinned commit still serves, so the mark is informational only. */\n.s861686_tierBadge[data-tier='archived'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n.s8474c5_incompatibleBadge {\n flex-shrink: 0;\n padding: 3px 9px;\n border-radius: 999px;\n font-size: 12px;\n white-space: nowrap;\n /* On the tint, not on the plain surface: this text reads on its own 14% red\n * fill, where the 90% red would measure 4.21:1 (light) and 4.43:1 (dark). */\n color: var(--shop-error-on-tint);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);\n}\n\n.s3269e3_starsBadge {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sb3efb0_chevron, .s712bfa_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s712bfa_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .sb3efb0_chevron, .s712bfa_chevronOpen { transition: none; }\n}\n\n.sa23bba_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px;\n}\n\n.s330087_summary {\n margin: 0;\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.sc86a78_summaryZh {\n margin: -4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n display: -webkit-box;\n -webkit-line-clamp: 1;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* Expanded cards show the full summary: the clamp is lifted, never raised —\n * a higher number would still truncate the author's text, just later. */\n.sce8fac_summaryExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n.s644c89_summaryZhExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n/* `white-space: pre-line` so the newline in the copy is the copy's own: the\n dictionary decides where the line breaks, and a translator changes it\n without touching the component. Collapses runs of spaces like `normal`, so\n only the explicit \\n survives. */\n.s9ba4c6_incompatibleDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n white-space: pre-line;\n color: var(--shop-error);\n}\n\n/* The way out of dsh's own refusal: the lead-in, then the exemption command\n * on its own line. */\n/* Block layout rather than flex: Firefox 153 will not line-clamp a container\n * that holds a display:flex child (Chromium 151 does), and the fold's\n * measured goal — \"the whole red block, remedy included, as one unit\" —\n * needs the container to clamp in BOTH engines the shop targets. The 4px\n * rhythm between the lead-in and the command is kept by the margins of the\n * children. */\n.s2149d8_remedy {\n display: block;\n}\n\n.s2149d8_remedy > * + * { margin-top: 4px; }\n\n/* The fold under a card's whole red block: two lines by default, a small\n * Refresh-pill-shaped toggle under it. Two containers, one rhythm: the shelf\n * uses `.sc15f91_foldBlock` collapsed and `.s876a53_foldBlockExpanded` open, and they share\n * one `display: block` (Firefox clamps no flex child inside a -webkit-box).\n * The clamp is on the BLOCK rather than any one line, so a 43-line remedy\n * counts as a unit instead of squashing the harness-peers line to a sliver\n * and hiding the command the reader actually came for. Both containers\n * still render the full block to a screen reader — `white-space: normal`\n * instead of pre-line keeps the copy's own `\\n` visible without forcing the\n * browser to lay the block's pieces like a text node. */\n.sc15f91_foldBlock {\n display: block;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n display: -webkit-box;\n overflow: hidden;\n}\n\n.s876a53_foldBlockExpanded { display: block; }\n\n/* The toggle. Geometry and quiet voice are the Refresh pill's\n * (`catalogStatsRow` right beside it on the same screen): one 1px border,\n * 11px text, secondary label, no fill. It is the only one of its kind here,\n * so a class of its own means one function of its own. */\n.s285921_foldToggle {\n padding: 1px 9px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n line-height: 17px;\n cursor: pointer;\n}\n\n.s285921_foldToggle:hover { border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2)); }\n.s285921_foldToggle:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }\n\n.s7e63ed_remedyLead {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The exemption command, bound for a terminal unchanged: one click selects\n * all of it, and it wraps anywhere rather than widening the card. A border,\n * not a fill, marks the box: the bg layers are one white in the light theme. */\n.sa4cc33_allowCommand {\n display: block;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n white-space: pre-wrap;\n word-break: break-all;\n user-select: all;\n color: var(--dsw-alias-label-primary);\n}\n\n/* A refused install on a surface that does not state its blockers — the\n * outdated row — writes them out on their own full-width line under the\n * refused label, the command that clears dsh's refusal included. Block,\n * rather than flex: Firefox will not line-clamp a -webkit-box that holds a\n * display:flex child, and the fold this element can sit inside of carries\n * that clamp. The 6px rhythm between the block's lines is carried by the\n * children's margins. */\n.s7c5f1b_refusal {\n display: block;\n flex-basis: 100%;\n}\n\n.s7c5f1b_refusal > * + * { margin-top: 6px; }\n\n.s12e4f9_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s9e429f_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sb6cd77_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.sb6cd77_capabilities li {\n padding: 1px 6px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sbc0e0a_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.s67086c_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.sb858f4_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.sb858f4_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.sb858f4_detailRow dd {\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n overflow-wrap: anywhere;\n text-align: right;\n color: var(--dsw-alias-label-primary);\n}\n\n.sb858f4_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.sb858f4_detailRow a:hover {\n text-decoration: underline;\n}\n\n.sb858f4_detailRow a:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* What the entry IS rather than what you can do with it — how big it is and\n * who published it — at the right edge of the action row. `margin-left: auto`\n * is what pushes it there, and it lives on this wrapper rather than on either\n * label so the group stays flush right when only one of the two has a value —\n * a packument that named no account has no author, and an entry the registry\n * could not measure honestly has no size. Rarer than it was (every live entry\n * now carries a size, github included), but the wrapper is not what makes it\n * rare: without one, an EMPTY meta group still costs 8px, because\n * `.sca19d2_cardActions` is a flex row with `gap: 8px` and a zero-width item is still\n * an item. The row is a wrapping flex, so an active install flow (which claims\n * the full width) drops the whole group to the next line rather than squeezing\n * it. */\n.s936159_cardMeta {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n min-width: 0;\n}\n\n/* The on-disk size, left of the author. Mono and tabular so the digits of one\n * figure line up with the digits of another WHEREVER the two land: `.s936159_cardMeta`\n * is flush right and the author sits outside the size, so a size's x position\n * moves with the author's width and is different again on the many entries\n * that carry no author at all. There is no column to align to, which is why\n * the reason given here is per-figure legibility rather than the column the\n * first version of this comment claimed. Secondary colour, because it\n * qualifies the entry rather than announcing it.\n *\n * `font-variant-numeric` is safe HERE and would not be on a pill: this element\n * has no state rules, so nothing it does can reflow a wrapping row.\n *\n * `.sa62ae0_shelfDate` shares this rule because it is the same kind of fact — a\n * fixed-width figure a reader compares down the shelf (design\n * 2026-10-12-shelf-orders §4) — and two copies of these declarations would\n * drift. */\n.s63fc2d_size,\n.sa62ae0_shelfDate {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-variant-numeric: tabular-nums;\n font-size: 12px;\n letter-spacing: 0.02em;\n white-space: nowrap;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The publishing account, at the outer end of `.s936159_cardMeta` on the action row —\n * NOT beside the npm link in the expanded detail, which is where it used to\n * live and what this comment described until the accurate half was deleted\n * with the `margin-left: auto` that moved to `.s936159_cardMeta`. There is no middot:\n * `.s936159_cardMeta`'s 8px gap separates it from the size.\n *\n * Secondary label colour carries the distinction — never a background fill,\n * which is invisible in the light theme where every bg-layer token is the\n * same white. */\n.s5d52b1_author {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.sc2ddce_reviewedLine {\n margin: 8px 0 0;\n padding: 6px 8px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n font-size: 12px;\n color: var(--shop-warn-on-tint);\n}\n\n/* Install flow. */\n.s170b01_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n/* ONE geometry for everything that occupies the install button's place: the\n * button itself, the confirm/cancel pair beside the restart gate, the installed\n * label, and the refused label. Stated once because a refused label HAS to look\n * like the button it replaces apart from its colour and its text, and four\n * copies of the same five declarations is how they stop looking alike.\n * `cursor: pointer` is NOT here: only the controls that can be pressed take it,\n * while a label renders with the default cursor. */\n.s30cc02_installButton,\n.s4732ec_confirmButton,\n.s6dfe5d_cancelButton,\n.s9f738a_installedLabel,\n.se35352_refusedLabel {\n align-self: flex-start;\n margin: 0;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n font-size: 13px;\n}\n\n.s30cc02_installButton, .s4732ec_confirmButton, .s6dfe5d_cancelButton {\n cursor: pointer;\n}\n\n.s30cc02_installButton {\n border-color: var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n/* Between the click and the host's answer. The flow ignores a repeat start for\n * the same identity, so this is the visible half of the same fact: a control\n * that says \"not now\" rather than one that looks ready to send a second\n * install. Only the button can be in this state — a label is never pressed. */\n.s30cc02_installButton:disabled {\n cursor: wait;\n}\n\n.s30cc02_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s4732ec_confirmButton {\n border: 1px solid var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n.s4732ec_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s6dfe5d_cancelButton {\n border: 1px solid var(--dsw-alias-border-l2);\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n}\n\n.s6dfe5d_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s30cc02_installButton:focus-visible, .s4732ec_confirmButton:focus-visible, .s6dfe5d_cancelButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The shelf card of a plugin that is installed and current carries this\n * non-interactive label instead of an install button. Border + text do the\n * work in the light theme, where every bg-layer token resolves to white. */\n.s9f738a_installedLabel {\n align-self: flex-start;\n margin: 0;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n font-size: 13px;\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n/* The refused Install/Update button's replacement: the same box as the button\n * (the geometry rule above), filled solid red, not pressable. The fill is the\n * derived red rather than the raw token because text sits on it — bg-base on\n * `--shop-error` measures 5.31:1 light and 6.14:1 dark — and the raw error red\n * under bg-base text measures 4.498:1, the miss this whole family of fixes\n * exists for. Nothing here changes on hover: it is a statement, not a control,\n * so it keeps the default cursor and its colours. */\n.se35352_refusedLabel {\n border-color: var(--shop-error);\n background: var(--shop-error);\n color: var(--dsw-alias-bg-base);\n white-space: nowrap;\n}\n\n/* An installed card's controls: the installed label or the update button,\n * plus the uninstall button. The install panel's running/failed states are\n * column layouts and sit as one item of this row. */\n.sd9c8c5_installedActions {\n display: flex;\n align-items: flex-start;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n/* Uninstall revokes privilege; the quiet outline keeps it from competing\n * with the primary action, and the error tint says \"removes\". */\n.s1157ec_uninstallButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 55%, transparent);\n border-radius: 6px;\n background: transparent;\n /* The on-tint red: hovering this button paints a 10% red fill under the\n * word, where the plain red measures 4.50:1 (light) — the same two\n * thousandths short of the floor the raw token shipped at. */\n color: var(--shop-error-on-tint);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s1157ec_uninstallButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.s1157ec_uninstallButton:focus-visible {\n outline: 2px solid var(--dsw-alias-state-error-primary);\n outline-offset: 1px;\n}\n\n/* The restart dsh button on a done install: quiet outline, same rank as\n * the other secondary actions. */\n.s748113_restartSelfButton {\n /* The version row's third state. Geometry matches .s82f241_checkUpdateButton and\n * .s8c1ada_updateSelfButton exactly — the row is one evolving control and a\n * different pill would read as a different kind of thing. It takes the\n * emphasised fill rather than the neutral one because at that moment the\n * restart is the only thing left to do, the same reason Update has it. */\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n color: var(--dsw-alias-brand-primary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.s748113_restartSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The two activation offers share one recipe: a border in an alias token,\n * never a `bg-layer` fill alone — all four bg-layer tokens collapse to the\n * same white under `body` in the light theme, and a fill-only button would\n * vanish there. Grouped rather than copied, because a copy is a rule that\n * can be corrected on one button and left wrong on the other, silently. */\n.s1784cd_restartButton,\n.s55f001_reloadButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s1784cd_restartButton:hover,\n.s55f001_reloadButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s1784cd_restartButton:focus-visible,\n.s55f001_reloadButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The §4 reload offer: a notice plus its button, one item of\n * `.sd9c8c5_installedActions` the way the restart gate is — a column of its own\n * rather than inline with the row. */\n.s3e0556_reloadPanel {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n}\n\n\n.s14145c_gate {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n border: 1px solid var(--dsw-alias-state-warn-primary);\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n.s1c22f6_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--shop-warn-on-tint);\n}\n\n.sdd4bac_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s1c4d38_gateWarning {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n white-space: pre-line;\n color: var(--shop-error);\n}\n\n.s7a3c61_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.s9bf897_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s8e495e_log {\n max-height: 160px;\n overflow: auto;\n margin: 0;\n padding: 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n list-style: none;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n}\n\n.sec6c41_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sd27ebf_notice {\n margin: 0;\n font-size: 12px;\n color: var(--shop-success);\n}\n\n.sced88c_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--shop-error);\n}\n\n.s7f8226_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s66949c_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--shop-error);\n}\n\n.sda36fc_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The Updatable section. The class keeps the Host's field name; only the\n heading the reader sees was renamed. */\n.se5be3e_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.sf32898_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s70aac4_outdatedRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n.sc30749_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.sc30749_outdatedInfo strong {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n word-break: break-all;\n color: var(--dsw-alias-label-primary);\n}\n\n.s735987_outdatedVersions {\n /* Two inline labels with nothing between them in the markup ran together as\n * `installed v1.0.0latest v2.0.0`: JSX drops the whitespace-only line, and\n * the per-label class the markup asked for was never defined (singular\n * against this rule's plural). The container owns the gap, the same idiom\n * as .sa76f21_badges — the labels need no class of their own. */\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The §C10 shadowed section. Reuses the outdated list's visual language; only\n * the section spacing and the per-row explanation paragraph are its own. */\n.sbf0d60_shadowedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.s9b143a_shadowedDetail {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s204154_outdatedActions {\n display: flex;\n align-items: center;\n /* The reload offer (§4) mounts inside the switch beside the Update button\n * and is a two-line block, not a control: without wrapping, a row reading\n * [switch][notice + Reload][Update] overflowed the Settings dialog the shop\n * sat in through 0.8.7, and the page's column narrows with the window. */\n flex-wrap: wrap;\n gap: 10px;\n}\n\n/* The shop's one switch. It is worn by two controls that mean different\n * things — the enable/disable toggle on an installed card, and the shelf's\n * incompatible filter — so the geometry lives here once and each caller states\n * only its hue.\n *\n * `--switch-hue` is that knob, and it is read from the ANCESTOR rather than\n * declared per state: `.sc56af2_incompatibleFilter` sets it once and it reaches the\n * track and the label together, which is what keeps a red switch from sitting\n * under a neutral word. A declaration on `.s247428_switch` itself would shadow the\n * inherited value (an element's own rule beats what it inherits), so the\n * default rides in the `var()` fallback and is resolved once into\n * `--track-hue` instead of being spelled out at each use.\n *\n * `box-sizing` and `padding` are stated because the two callers are different\n * elements — a `<button>`, which the UA gives padding, and a `<span>`, which\n * it does not. Without them the same class renders two sizes, and the knob\n * sits 2px above centre in the taller one. */\n.s247428_switch {\n --track-hue: var(--switch-hue, var(--dsw-alias-state-success-primary));\n box-sizing: border-box;\n display: inline-block;\n position: relative;\n width: 32px;\n height: 18px;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n\n/* The knob's POSITION is the state, which is the reason this control needs no\n * `forced-colors` fallback the way the category pills do: a system palette\n * replaces every colour below and moves nothing. */\n.se62fac_switchOn {\n border-color: var(--track-hue);\n background: color-mix(in srgb, var(--track-hue) 55%, transparent);\n}\n\n.se0ac0b_switchKnob {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: 999px;\n background: var(--dsw-alias-label-primary);\n transition: transform 120ms ease, background 120ms ease;\n}\n\n.se62fac_switchOn .se0ac0b_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.s247428_switch:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s247428_switch, .se0ac0b_switchKnob { transition: none; }\n}\n\n/* The hot enable/disable switch on installed rows: the knob button plus the\n * §8 hot-apply / failure notices rendered beside it. */\n.s7dd801_switchWrap {\n display: inline-flex;\n align-items: center;\n /* Same reason as `.s204154_outdatedActions`: `.s3e0556_reloadPanel`'s own comment calls\n * itself \"a column of its own rather than inline with the row\", which held\n * for `.sd9c8c5_installedActions` and not here until this line. */\n flex-wrap: wrap;\n gap: 8px;\n}\n";
|
|
8422
|
+
if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"a037354d\"]")) {
|
|
8409
8423
|
const tag = document.createElement("style");
|
|
8410
|
-
tag.dataset.pluginCss = "
|
|
8424
|
+
tag.dataset.pluginCss = "a037354d";
|
|
8411
8425
|
tag.textContent = css;
|
|
8412
8426
|
document.head.appendChild(tag);
|
|
8413
8427
|
}
|
|
8414
|
-
var
|
|
8415
|
-
"client": "
|
|
8416
|
-
"config": "
|
|
8417
|
-
"ts": "
|
|
8418
|
-
"spec": "
|
|
8419
|
-
"panel": "
|
|
8420
|
-
"searchInput": "
|
|
8421
|
-
"toolbar": "
|
|
8422
|
-
"page": "
|
|
8423
|
-
"pageHead": "
|
|
8424
|
-
"pageTitle": "
|
|
8425
|
-
"pageIntro": "
|
|
8426
|
-
"detailAction": "
|
|
8427
|
-
"stateLine": "
|
|
8428
|
-
"srOnly": "
|
|
8429
|
-
"skeletonGrid": "
|
|
8430
|
-
"skeletonCard": "
|
|
8431
|
-
"skeletonName": "
|
|
8432
|
-
"skeletonSummary": "
|
|
8433
|
-
"skeletonSummaryShort": "
|
|
8434
|
-
"skeletonActions": "
|
|
8435
|
-
"actionButton": "
|
|
8436
|
-
"toolbarRight": "
|
|
8437
|
-
"versionBlock": "
|
|
8438
|
-
"versionText": "
|
|
8439
|
-
"updateSelfButton": "
|
|
8440
|
-
"checkUpdateButton": "
|
|
8441
|
-
"githubLink": "
|
|
8442
|
-
"selfUpdatePanel": "
|
|
8443
|
-
"expansionNote": "
|
|
8444
|
-
"staleBadge": "
|
|
8445
|
-
"categoryBar": "
|
|
8446
|
-
"categoryButton": "
|
|
8447
|
-
"categoryButtonOn": "
|
|
8448
|
-
"incompatibleFilter": "
|
|
8449
|
-
"switch": "
|
|
8450
|
-
"switchOn": "
|
|
8451
|
-
"incompatibleFilterOn": "
|
|
8452
|
-
"switchKnob": "
|
|
8453
|
-
"updatableHeading": "
|
|
8454
|
-
"catalogStatsRow": "
|
|
8455
|
-
"sortGroup": "
|
|
8456
|
-
"sortLabel": "
|
|
8457
|
-
"catalogStats": "
|
|
8458
|
-
"catalogRefreshButton": "
|
|
8459
|
-
"catalogRefreshFailed": "
|
|
8460
|
-
"emptyLine": "
|
|
8461
|
-
"cards": "
|
|
8462
|
-
"card": "
|
|
8463
|
-
"cardsSentry": "
|
|
8464
|
-
"showingLine": "
|
|
8465
|
-
"cardSpine": "
|
|
8466
|
-
"categoryBadge": "
|
|
8467
|
-
"entryHeader": "
|
|
8468
|
-
"name": "
|
|
8469
|
-
"badges": "
|
|
8470
|
-
"cardActions": "
|
|
8471
|
-
"gate": "
|
|
8472
|
-
"installPanel": "
|
|
8473
|
-
"installedActions": "
|
|
8474
|
-
"cardVersion": "
|
|
8475
|
-
"sourceBadge": "
|
|
8476
|
-
"tierBadge": "
|
|
8477
|
-
"incompatibleBadge": "
|
|
8478
|
-
"starsBadge": "
|
|
8479
|
-
"chevron": "
|
|
8480
|
-
"chevronOpen": "
|
|
8481
|
-
"body": "
|
|
8482
|
-
"summary": "
|
|
8483
|
-
"summaryZh": "
|
|
8484
|
-
"summaryExpanded": "
|
|
8485
|
-
"summaryZhExpanded": "
|
|
8486
|
-
"incompatibleDetail": "
|
|
8487
|
-
"remedy": "
|
|
8488
|
-
"foldBlock": "
|
|
8489
|
-
"foldBlockExpanded": "
|
|
8490
|
-
"foldToggle": "
|
|
8491
|
-
"remedyLead": "
|
|
8492
|
-
"allowCommand": "
|
|
8493
|
-
"refusal": "
|
|
8494
|
-
"capabilitiesBlock": "
|
|
8495
|
-
"capabilitiesNote": "
|
|
8496
|
-
"capabilities": "
|
|
8497
|
-
"detail": "
|
|
8498
|
-
"detailRows": "
|
|
8499
|
-
"detailRow": "
|
|
8500
|
-
"cardMeta": "
|
|
8501
|
-
"shelfDate": "
|
|
8502
|
-
"size": "
|
|
8503
|
-
"author": "
|
|
8504
|
-
"reviewedLine": "
|
|
8505
|
-
"installButton": "
|
|
8506
|
-
"confirmButton": "
|
|
8507
|
-
"cancelButton": "
|
|
8508
|
-
"installedLabel": "
|
|
8509
|
-
"refusedLabel": "
|
|
8510
|
-
"uninstallButton": "
|
|
8511
|
-
"restartSelfButton": "
|
|
8512
|
-
"restartButton": "
|
|
8513
|
-
"reloadButton": "
|
|
8514
|
-
"reloadPanel": "
|
|
8515
|
-
"gateTitle": "
|
|
8516
|
-
"gateBody": "
|
|
8517
|
-
"gateWarning": "
|
|
8518
|
-
"gateActions": "
|
|
8519
|
-
"installing": "
|
|
8520
|
-
"log": "
|
|
8521
|
-
"logLine": "
|
|
8522
|
-
"notice": "
|
|
8523
|
-
"failedHeading": "
|
|
8524
|
-
"failedDetail": "
|
|
8525
|
-
"rejectedCode": "
|
|
8526
|
-
"rejectedDetail": "
|
|
8527
|
-
"outdatedSection": "
|
|
8528
|
-
"outdatedList": "
|
|
8529
|
-
"outdatedRow": "
|
|
8530
|
-
"outdatedInfo": "
|
|
8531
|
-
"outdatedVersions": "
|
|
8532
|
-
"shadowedSection": "
|
|
8533
|
-
"shadowedDetail": "
|
|
8534
|
-
"outdatedActions": "
|
|
8535
|
-
"switchWrap": "
|
|
8428
|
+
var _dsh_plugin_shop_css_a037354d_default = {
|
|
8429
|
+
"client": "sa584e5_client",
|
|
8430
|
+
"config": "s18f7ee_config",
|
|
8431
|
+
"ts": "s39f74c_ts",
|
|
8432
|
+
"spec": "sf107cf_spec",
|
|
8433
|
+
"panel": "s8de901_panel",
|
|
8434
|
+
"searchInput": "s3e432c_searchInput",
|
|
8435
|
+
"toolbar": "s9a1d55_toolbar",
|
|
8436
|
+
"page": "sa6404f_page",
|
|
8437
|
+
"pageHead": "scab2f9_pageHead",
|
|
8438
|
+
"pageTitle": "sc4a729_pageTitle",
|
|
8439
|
+
"pageIntro": "s14e198_pageIntro",
|
|
8440
|
+
"detailAction": "sd04f34_detailAction",
|
|
8441
|
+
"stateLine": "sfb4615_stateLine",
|
|
8442
|
+
"srOnly": "s43702a_srOnly",
|
|
8443
|
+
"skeletonGrid": "se66364_skeletonGrid",
|
|
8444
|
+
"skeletonCard": "s41d8a9_skeletonCard",
|
|
8445
|
+
"skeletonName": "sbad351_skeletonName",
|
|
8446
|
+
"skeletonSummary": "sb2be83_skeletonSummary",
|
|
8447
|
+
"skeletonSummaryShort": "s67c868_skeletonSummaryShort",
|
|
8448
|
+
"skeletonActions": "sbcd6ff_skeletonActions",
|
|
8449
|
+
"actionButton": "s602b18_actionButton",
|
|
8450
|
+
"toolbarRight": "se2add9_toolbarRight",
|
|
8451
|
+
"versionBlock": "sf1bc7d_versionBlock",
|
|
8452
|
+
"versionText": "seba9a7_versionText",
|
|
8453
|
+
"updateSelfButton": "s8c1ada_updateSelfButton",
|
|
8454
|
+
"checkUpdateButton": "s82f241_checkUpdateButton",
|
|
8455
|
+
"githubLink": "s1e95bf_githubLink",
|
|
8456
|
+
"selfUpdatePanel": "s91bcc4_selfUpdatePanel",
|
|
8457
|
+
"expansionNote": "s712943_expansionNote",
|
|
8458
|
+
"staleBadge": "sf2024f_staleBadge",
|
|
8459
|
+
"categoryBar": "s630e95_categoryBar",
|
|
8460
|
+
"categoryButton": "s4575ba_categoryButton",
|
|
8461
|
+
"categoryButtonOn": "s7c5955_categoryButtonOn",
|
|
8462
|
+
"incompatibleFilter": "sc56af2_incompatibleFilter",
|
|
8463
|
+
"switch": "s247428_switch",
|
|
8464
|
+
"switchOn": "se62fac_switchOn",
|
|
8465
|
+
"incompatibleFilterOn": "s46063b_incompatibleFilterOn",
|
|
8466
|
+
"switchKnob": "se0ac0b_switchKnob",
|
|
8467
|
+
"updatableHeading": "s622eb2_updatableHeading",
|
|
8468
|
+
"catalogStatsRow": "s7ef365_catalogStatsRow",
|
|
8469
|
+
"sortGroup": "sa2f85b_sortGroup",
|
|
8470
|
+
"sortLabel": "s9d1f07_sortLabel",
|
|
8471
|
+
"catalogStats": "sd5812b_catalogStats",
|
|
8472
|
+
"catalogRefreshButton": "sc01148_catalogRefreshButton",
|
|
8473
|
+
"catalogRefreshFailed": "s7acae8_catalogRefreshFailed",
|
|
8474
|
+
"emptyLine": "saec8bc_emptyLine",
|
|
8475
|
+
"cards": "sc932e7_cards",
|
|
8476
|
+
"card": "s341f40_card",
|
|
8477
|
+
"cardsSentry": "sd43e97_cardsSentry",
|
|
8478
|
+
"showingLine": "sb9f4b3_showingLine",
|
|
8479
|
+
"cardSpine": "s3a0d45_cardSpine",
|
|
8480
|
+
"categoryBadge": "s5e7fbd_categoryBadge",
|
|
8481
|
+
"entryHeader": "s72c02a_entryHeader",
|
|
8482
|
+
"name": "s54a911_name",
|
|
8483
|
+
"badges": "sa76f21_badges",
|
|
8484
|
+
"cardActions": "sca19d2_cardActions",
|
|
8485
|
+
"gate": "s14145c_gate",
|
|
8486
|
+
"installPanel": "s170b01_installPanel",
|
|
8487
|
+
"installedActions": "sd9c8c5_installedActions",
|
|
8488
|
+
"cardVersion": "sf0e287_cardVersion",
|
|
8489
|
+
"sourceBadge": "s75ac5c_sourceBadge",
|
|
8490
|
+
"tierBadge": "s861686_tierBadge",
|
|
8491
|
+
"incompatibleBadge": "s8474c5_incompatibleBadge",
|
|
8492
|
+
"starsBadge": "s3269e3_starsBadge",
|
|
8493
|
+
"chevron": "sb3efb0_chevron",
|
|
8494
|
+
"chevronOpen": "s712bfa_chevronOpen",
|
|
8495
|
+
"body": "sa23bba_body",
|
|
8496
|
+
"summary": "s330087_summary",
|
|
8497
|
+
"summaryZh": "sc86a78_summaryZh",
|
|
8498
|
+
"summaryExpanded": "sce8fac_summaryExpanded",
|
|
8499
|
+
"summaryZhExpanded": "s644c89_summaryZhExpanded",
|
|
8500
|
+
"incompatibleDetail": "s9ba4c6_incompatibleDetail",
|
|
8501
|
+
"remedy": "s2149d8_remedy",
|
|
8502
|
+
"foldBlock": "sc15f91_foldBlock",
|
|
8503
|
+
"foldBlockExpanded": "s876a53_foldBlockExpanded",
|
|
8504
|
+
"foldToggle": "s285921_foldToggle",
|
|
8505
|
+
"remedyLead": "s7e63ed_remedyLead",
|
|
8506
|
+
"allowCommand": "sa4cc33_allowCommand",
|
|
8507
|
+
"refusal": "s7c5f1b_refusal",
|
|
8508
|
+
"capabilitiesBlock": "s12e4f9_capabilitiesBlock",
|
|
8509
|
+
"capabilitiesNote": "s9e429f_capabilitiesNote",
|
|
8510
|
+
"capabilities": "sb6cd77_capabilities",
|
|
8511
|
+
"detail": "sbc0e0a_detail",
|
|
8512
|
+
"detailRows": "s67086c_detailRows",
|
|
8513
|
+
"detailRow": "sb858f4_detailRow",
|
|
8514
|
+
"cardMeta": "s936159_cardMeta",
|
|
8515
|
+
"shelfDate": "sa62ae0_shelfDate",
|
|
8516
|
+
"size": "s63fc2d_size",
|
|
8517
|
+
"author": "s5d52b1_author",
|
|
8518
|
+
"reviewedLine": "sc2ddce_reviewedLine",
|
|
8519
|
+
"installButton": "s30cc02_installButton",
|
|
8520
|
+
"confirmButton": "s4732ec_confirmButton",
|
|
8521
|
+
"cancelButton": "s6dfe5d_cancelButton",
|
|
8522
|
+
"installedLabel": "s9f738a_installedLabel",
|
|
8523
|
+
"refusedLabel": "se35352_refusedLabel",
|
|
8524
|
+
"uninstallButton": "s1157ec_uninstallButton",
|
|
8525
|
+
"restartSelfButton": "s748113_restartSelfButton",
|
|
8526
|
+
"restartButton": "s1784cd_restartButton",
|
|
8527
|
+
"reloadButton": "s55f001_reloadButton",
|
|
8528
|
+
"reloadPanel": "s3e0556_reloadPanel",
|
|
8529
|
+
"gateTitle": "s1c22f6_gateTitle",
|
|
8530
|
+
"gateBody": "sdd4bac_gateBody",
|
|
8531
|
+
"gateWarning": "s1c4d38_gateWarning",
|
|
8532
|
+
"gateActions": "s7a3c61_gateActions",
|
|
8533
|
+
"installing": "s9bf897_installing",
|
|
8534
|
+
"log": "s8e495e_log",
|
|
8535
|
+
"logLine": "sec6c41_logLine",
|
|
8536
|
+
"notice": "sd27ebf_notice",
|
|
8537
|
+
"failedHeading": "sced88c_failedHeading",
|
|
8538
|
+
"failedDetail": "s7f8226_failedDetail",
|
|
8539
|
+
"rejectedCode": "s66949c_rejectedCode",
|
|
8540
|
+
"rejectedDetail": "sda36fc_rejectedDetail",
|
|
8541
|
+
"outdatedSection": "se5be3e_outdatedSection",
|
|
8542
|
+
"outdatedList": "sf32898_outdatedList",
|
|
8543
|
+
"outdatedRow": "s70aac4_outdatedRow",
|
|
8544
|
+
"outdatedInfo": "sc30749_outdatedInfo",
|
|
8545
|
+
"outdatedVersions": "s735987_outdatedVersions",
|
|
8546
|
+
"shadowedSection": "sbf0d60_shadowedSection",
|
|
8547
|
+
"shadowedDetail": "s9b143a_shadowedDetail",
|
|
8548
|
+
"outdatedActions": "s204154_outdatedActions",
|
|
8549
|
+
"switchWrap": "s7dd801_switchWrap"
|
|
8536
8550
|
};
|
|
8537
8551
|
//#endregion
|
|
8538
8552
|
//#region src/client/ShopDetailAction.tsx
|
|
@@ -8592,7 +8606,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8592
8606
|
if (name === null || !canOpen()) return null;
|
|
8593
8607
|
if (own) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8594
8608
|
type: "button",
|
|
8595
|
-
className:
|
|
8609
|
+
className: _dsh_plugin_shop_css_a037354d_default.detailAction,
|
|
8596
8610
|
"data-shop-open-shop": true,
|
|
8597
8611
|
onClick: openShop,
|
|
8598
8612
|
children: t("openShop")
|
|
@@ -8601,7 +8615,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8601
8615
|
const only = listed.keys.length === 1 ? listed.keys[0] ?? null : null;
|
|
8602
8616
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8603
8617
|
type: "button",
|
|
8604
|
-
className:
|
|
8618
|
+
className: _dsh_plugin_shop_css_a037354d_default.detailAction,
|
|
8605
8619
|
"data-shop-view-in-shop": true,
|
|
8606
8620
|
onClick: () => {
|
|
8607
8621
|
page.focus(name, only);
|
|
@@ -9920,13 +9934,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9920
9934
|
const { rootRef, expandable, expanded, toggle } = useFoldableRedBlock();
|
|
9921
9935
|
const kindName = attrName.replace(/^data-shop-/, "");
|
|
9922
9936
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9923
|
-
className: expanded ?
|
|
9937
|
+
className: expanded ? _dsh_plugin_shop_css_a037354d_default.foldBlockExpanded : _dsh_plugin_shop_css_a037354d_default.foldBlock,
|
|
9924
9938
|
[attrName]: true,
|
|
9925
9939
|
ref: rootRef,
|
|
9926
9940
|
children
|
|
9927
9941
|
}), expandable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9928
9942
|
type: "button",
|
|
9929
|
-
className:
|
|
9943
|
+
className: _dsh_plugin_shop_css_a037354d_default.foldToggle,
|
|
9930
9944
|
"data-shop-fold": kindName,
|
|
9931
9945
|
"aria-expanded": expanded,
|
|
9932
9946
|
onClick: toggle,
|
|
@@ -9948,14 +9962,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9948
9962
|
* those nodes, and React's next commit throws on the ones it no longer finds
|
|
9949
9963
|
* (design 2026-09-26-market-borrowings §4). The tab renders no portals, so its
|
|
9950
9964
|
* root is its whole surface. */
|
|
9951
|
-
const PANEL_ROOT = `${
|
|
9965
|
+
const PANEL_ROOT = `${_dsh_plugin_shop_css_a037354d_default.panel} notranslate`;
|
|
9952
9966
|
function ChevronIcon({ open }) {
|
|
9953
9967
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
9954
9968
|
viewBox: "0 0 16 16",
|
|
9955
9969
|
width: "14",
|
|
9956
9970
|
height: "14",
|
|
9957
9971
|
"aria-hidden": "true",
|
|
9958
|
-
className: open ?
|
|
9972
|
+
className: open ? _dsh_plugin_shop_css_a037354d_default.chevronOpen : _dsh_plugin_shop_css_a037354d_default.chevron,
|
|
9959
9973
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
9960
9974
|
fill: "currentColor",
|
|
9961
9975
|
d: "M3.5 6 8 10.5 12.5 6l1 1L8 12.5 2.5 7l1-1Z"
|
|
@@ -9989,17 +10003,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9989
10003
|
subdir: entry.subdir
|
|
9990
10004
|
};
|
|
9991
10005
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
9992
|
-
className:
|
|
10006
|
+
className: _dsh_plugin_shop_css_a037354d_default.card,
|
|
9993
10007
|
"data-shop-entry": entry.name,
|
|
9994
10008
|
"data-category": category,
|
|
9995
10009
|
children: [
|
|
9996
10010
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9997
|
-
className:
|
|
10011
|
+
className: _dsh_plugin_shop_css_a037354d_default.cardSpine,
|
|
9998
10012
|
"aria-hidden": "true"
|
|
9999
10013
|
}),
|
|
10000
10014
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
10001
10015
|
type: "button",
|
|
10002
|
-
className:
|
|
10016
|
+
className: _dsh_plugin_shop_css_a037354d_default.entryHeader,
|
|
10003
10017
|
"aria-expanded": open,
|
|
10004
10018
|
"aria-controls": detailId,
|
|
10005
10019
|
onClick: () => {
|
|
@@ -10007,17 +10021,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10007
10021
|
rerender();
|
|
10008
10022
|
},
|
|
10009
10023
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10010
|
-
className:
|
|
10024
|
+
className: _dsh_plugin_shop_css_a037354d_default.name,
|
|
10011
10025
|
children: entry.name
|
|
10012
10026
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10013
|
-
className:
|
|
10027
|
+
className: _dsh_plugin_shop_css_a037354d_default.badges,
|
|
10014
10028
|
children: [
|
|
10015
10029
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10016
|
-
className:
|
|
10030
|
+
className: _dsh_plugin_shop_css_a037354d_default.categoryBadge,
|
|
10017
10031
|
children: t(categoryKey(entry))
|
|
10018
10032
|
}),
|
|
10019
10033
|
entry.source === "npm" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10020
|
-
className:
|
|
10034
|
+
className: _dsh_plugin_shop_css_a037354d_default.sourceBadge,
|
|
10021
10035
|
"data-shop-source-npm": true,
|
|
10022
10036
|
role: "img",
|
|
10023
10037
|
"aria-label": t("npmSource"),
|
|
@@ -10034,7 +10048,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10034
10048
|
})
|
|
10035
10049
|
}),
|
|
10036
10050
|
hasGithubHome(entry) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10037
|
-
className:
|
|
10051
|
+
className: _dsh_plugin_shop_css_a037354d_default.sourceBadge,
|
|
10038
10052
|
"data-shop-source-github": true,
|
|
10039
10053
|
role: "img",
|
|
10040
10054
|
"aria-label": t("githubSource"),
|
|
@@ -10048,7 +10062,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10048
10062
|
})
|
|
10049
10063
|
}),
|
|
10050
10064
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10051
|
-
className:
|
|
10065
|
+
className: _dsh_plugin_shop_css_a037354d_default.cardVersion,
|
|
10052
10066
|
"data-card-version": true,
|
|
10053
10067
|
role: "img",
|
|
10054
10068
|
"aria-label": versionName,
|
|
@@ -10056,17 +10070,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10056
10070
|
children: version.text
|
|
10057
10071
|
}),
|
|
10058
10072
|
entry.tier !== "community" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10059
|
-
className:
|
|
10073
|
+
className: _dsh_plugin_shop_css_a037354d_default.tierBadge,
|
|
10060
10074
|
"data-tier": entry.tier,
|
|
10061
10075
|
children: t(tierKey(entry.tier))
|
|
10062
10076
|
}),
|
|
10063
10077
|
entry.archived === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10064
|
-
className:
|
|
10078
|
+
className: _dsh_plugin_shop_css_a037354d_default.tierBadge,
|
|
10065
10079
|
"data-tier": "archived",
|
|
10066
10080
|
children: t("archivedBadge")
|
|
10067
10081
|
}),
|
|
10068
10082
|
stars !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10069
|
-
className:
|
|
10083
|
+
className: _dsh_plugin_shop_css_a037354d_default.starsBadge,
|
|
10070
10084
|
role: "img",
|
|
10071
10085
|
"aria-label": t("stars", { count: stars }),
|
|
10072
10086
|
children: ["★ ", formatStars(stars)]
|
|
@@ -10076,14 +10090,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10076
10090
|
})]
|
|
10077
10091
|
}),
|
|
10078
10092
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10079
|
-
className:
|
|
10093
|
+
className: _dsh_plugin_shop_css_a037354d_default.body,
|
|
10080
10094
|
children: [
|
|
10081
10095
|
summary !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10082
|
-
className: open ? `${
|
|
10096
|
+
className: open ? `${_dsh_plugin_shop_css_a037354d_default.summary} ${_dsh_plugin_shop_css_a037354d_default.summaryExpanded}` : _dsh_plugin_shop_css_a037354d_default.summary,
|
|
10083
10097
|
children: summary.en
|
|
10084
10098
|
}),
|
|
10085
10099
|
summary?.zh !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10086
|
-
className: open ? `${
|
|
10100
|
+
className: open ? `${_dsh_plugin_shop_css_a037354d_default.summaryZh} ${_dsh_plugin_shop_css_a037354d_default.summaryZhExpanded}` : _dsh_plugin_shop_css_a037354d_default.summaryZh,
|
|
10087
10101
|
children: summary.zh
|
|
10088
10102
|
}),
|
|
10089
10103
|
blockers.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FoldableRedBlock, {
|
|
@@ -10091,28 +10105,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10091
10105
|
attrName: "data-shop-remedy",
|
|
10092
10106
|
children: blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
10093
10107
|
blocker,
|
|
10094
|
-
className:
|
|
10108
|
+
className: _dsh_plugin_shop_css_a037354d_default.incompatibleDetail,
|
|
10095
10109
|
surface: "detail"
|
|
10096
10110
|
}, blocker.kind))
|
|
10097
10111
|
}),
|
|
10098
10112
|
open && entry.catalog !== void 0 && entry.catalog.capabilities.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10099
|
-
className:
|
|
10113
|
+
className: _dsh_plugin_shop_css_a037354d_default.capabilitiesBlock,
|
|
10100
10114
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10101
|
-
className:
|
|
10115
|
+
className: _dsh_plugin_shop_css_a037354d_default.capabilitiesNote,
|
|
10102
10116
|
children: t("capabilitiesNote")
|
|
10103
10117
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
10104
|
-
className:
|
|
10118
|
+
className: _dsh_plugin_shop_css_a037354d_default.capabilities,
|
|
10105
10119
|
children: entry.catalog.capabilities.map((capability) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: capability }, capability))
|
|
10106
10120
|
})]
|
|
10107
10121
|
}),
|
|
10108
10122
|
open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
10109
10123
|
id: detailId,
|
|
10110
|
-
className:
|
|
10124
|
+
className: _dsh_plugin_shop_css_a037354d_default.detail,
|
|
10111
10125
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
|
|
10112
|
-
className:
|
|
10126
|
+
className: _dsh_plugin_shop_css_a037354d_default.detailRows,
|
|
10113
10127
|
children: [
|
|
10114
10128
|
npmUrl !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10115
|
-
className:
|
|
10129
|
+
className: _dsh_plugin_shop_css_a037354d_default.detailRow,
|
|
10116
10130
|
"data-shop-npm": true,
|
|
10117
10131
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("npmPage") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
10118
10132
|
href: npmUrl,
|
|
@@ -10122,7 +10136,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10122
10136
|
}) })]
|
|
10123
10137
|
}),
|
|
10124
10138
|
entry.repository !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10125
|
-
className:
|
|
10139
|
+
className: _dsh_plugin_shop_css_a037354d_default.detailRow,
|
|
10126
10140
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("repository") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: /^https?:\/\//.test(entry.repository) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
10127
10141
|
href: entry.repository,
|
|
10128
10142
|
target: "_blank",
|
|
@@ -10131,12 +10145,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10131
10145
|
}) : entry.repository })]
|
|
10132
10146
|
}),
|
|
10133
10147
|
entry.license !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10134
|
-
className:
|
|
10148
|
+
className: _dsh_plugin_shop_css_a037354d_default.detailRow,
|
|
10135
10149
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", { children: t("license") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", { children: isCustomLicense(entry.license) ? t("customLicense") : entry.license })]
|
|
10136
10150
|
})
|
|
10137
10151
|
]
|
|
10138
10152
|
}), entry.tier === "verified-stale" && entry.review !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10139
|
-
className:
|
|
10153
|
+
className: _dsh_plugin_shop_css_a037354d_default.reviewedLine,
|
|
10140
10154
|
children: entry.review.reviewedVersion !== void 0 ? t("reviewedVersionLine", {
|
|
10141
10155
|
reviewed: versionLabel("npm", entry.review.reviewedVersion).text,
|
|
10142
10156
|
current: version.text
|
|
@@ -10149,7 +10163,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10149
10163
|
]
|
|
10150
10164
|
}),
|
|
10151
10165
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10152
|
-
className:
|
|
10166
|
+
className: _dsh_plugin_shop_css_a037354d_default.cardActions,
|
|
10153
10167
|
"data-shop-actions": true,
|
|
10154
10168
|
children: [installed === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!inInstalledView && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstallPanel, {
|
|
10155
10169
|
target: installTarget,
|
|
@@ -10181,7 +10195,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10181
10195
|
restartBlocked,
|
|
10182
10196
|
reload
|
|
10183
10197
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10184
|
-
className:
|
|
10198
|
+
className: _dsh_plugin_shop_css_a037354d_default.installedLabel,
|
|
10185
10199
|
"data-shop-installed": true,
|
|
10186
10200
|
children: t("installed")
|
|
10187
10201
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerBadge, {
|
|
@@ -10207,15 +10221,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10207
10221
|
flow: uninstallFlow
|
|
10208
10222
|
})
|
|
10209
10223
|
] }), (size !== void 0 || author !== null || shelfDay !== void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10210
|
-
className:
|
|
10224
|
+
className: _dsh_plugin_shop_css_a037354d_default.cardMeta,
|
|
10211
10225
|
children: [
|
|
10212
10226
|
shelfDay !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10213
|
-
className:
|
|
10227
|
+
className: _dsh_plugin_shop_css_a037354d_default.shelfDate,
|
|
10214
10228
|
"data-shop-shelf-date": true,
|
|
10215
10229
|
children: t(order === "added" ? "listedOn" : "updatedOn", { date: shelfDay })
|
|
10216
10230
|
}),
|
|
10217
10231
|
size !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10218
|
-
className:
|
|
10232
|
+
className: _dsh_plugin_shop_css_a037354d_default.size,
|
|
10219
10233
|
"data-shop-size": true,
|
|
10220
10234
|
role: "img",
|
|
10221
10235
|
"aria-label": t("sizeLabel", { size }),
|
|
@@ -10223,7 +10237,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10223
10237
|
children: size
|
|
10224
10238
|
}),
|
|
10225
10239
|
author !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10226
|
-
className:
|
|
10240
|
+
className: _dsh_plugin_shop_css_a037354d_default.author,
|
|
10227
10241
|
"data-shop-author": true,
|
|
10228
10242
|
children: t("authorLine", { author })
|
|
10229
10243
|
})
|
|
@@ -10273,13 +10287,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10273
10287
|
...attribute,
|
|
10274
10288
|
children: blocker.text
|
|
10275
10289
|
}), blocker.remedy !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10276
|
-
className:
|
|
10290
|
+
className: _dsh_plugin_shop_css_a037354d_default.remedy,
|
|
10277
10291
|
"data-shop-remedy": blocker.kind,
|
|
10278
10292
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10279
|
-
className:
|
|
10293
|
+
className: _dsh_plugin_shop_css_a037354d_default.remedyLead,
|
|
10280
10294
|
children: blocker.remedy.lead
|
|
10281
10295
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
10282
|
-
className:
|
|
10296
|
+
className: _dsh_plugin_shop_css_a037354d_default.allowCommand,
|
|
10283
10297
|
"data-shop-allow-command": true,
|
|
10284
10298
|
children: blocker.remedy.command
|
|
10285
10299
|
})]
|
|
@@ -10317,7 +10331,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10317
10331
|
if (lead === void 0 || word === null) return null;
|
|
10318
10332
|
const detail = blockers.map((blocker) => blocker.text).join("\n");
|
|
10319
10333
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10320
|
-
className:
|
|
10334
|
+
className: _dsh_plugin_shop_css_a037354d_default.incompatibleBadge,
|
|
10321
10335
|
"data-shop-blocker": lead.kind,
|
|
10322
10336
|
role: "img",
|
|
10323
10337
|
"aria-label": detail,
|
|
@@ -10349,37 +10363,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10349
10363
|
const refused = refusesInstall(blockers);
|
|
10350
10364
|
const word = blockerBadgeKey(blockers);
|
|
10351
10365
|
if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10352
|
-
className:
|
|
10366
|
+
className: _dsh_plugin_shop_css_a037354d_default.installPanel,
|
|
10353
10367
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10354
|
-
className:
|
|
10368
|
+
className: _dsh_plugin_shop_css_a037354d_default.installing,
|
|
10355
10369
|
children: t(installPhaseKey(view.phase))
|
|
10356
10370
|
}), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10357
|
-
className:
|
|
10371
|
+
className: _dsh_plugin_shop_css_a037354d_default.log,
|
|
10358
10372
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10359
|
-
className:
|
|
10373
|
+
className: _dsh_plugin_shop_css_a037354d_default.logLine,
|
|
10360
10374
|
"data-shop-log-line": true,
|
|
10361
10375
|
children: line
|
|
10362
10376
|
}, index))
|
|
10363
10377
|
})]
|
|
10364
10378
|
});
|
|
10365
10379
|
if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10366
|
-
className:
|
|
10380
|
+
className: _dsh_plugin_shop_css_a037354d_default.installedActions,
|
|
10367
10381
|
children: [
|
|
10368
10382
|
view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10369
|
-
className:
|
|
10383
|
+
className: _dsh_plugin_shop_css_a037354d_default.log,
|
|
10370
10384
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10371
|
-
className:
|
|
10385
|
+
className: _dsh_plugin_shop_css_a037354d_default.logLine,
|
|
10372
10386
|
"data-shop-log-line": true,
|
|
10373
10387
|
children: line
|
|
10374
10388
|
}, index))
|
|
10375
10389
|
}),
|
|
10376
10390
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10377
|
-
className:
|
|
10391
|
+
className: _dsh_plugin_shop_css_a037354d_default.notice,
|
|
10378
10392
|
"data-shop-restart-notice": true,
|
|
10379
10393
|
children: t(activationNoticeKey(view.activation, view.restartReason))
|
|
10380
10394
|
}),
|
|
10381
10395
|
view.detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10382
|
-
className:
|
|
10396
|
+
className: _dsh_plugin_shop_css_a037354d_default.notice,
|
|
10383
10397
|
"data-shop-done-note": true,
|
|
10384
10398
|
children: view.detail
|
|
10385
10399
|
}),
|
|
@@ -10393,7 +10407,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10393
10407
|
}),
|
|
10394
10408
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10395
10409
|
type: "button",
|
|
10396
|
-
className:
|
|
10410
|
+
className: _dsh_plugin_shop_css_a037354d_default.cancelButton,
|
|
10397
10411
|
"data-shop-install-dismiss": true,
|
|
10398
10412
|
onClick: reset,
|
|
10399
10413
|
children: t("dismiss")
|
|
@@ -10401,33 +10415,33 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10401
10415
|
]
|
|
10402
10416
|
});
|
|
10403
10417
|
if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10404
|
-
className:
|
|
10418
|
+
className: _dsh_plugin_shop_css_a037354d_default.installPanel,
|
|
10405
10419
|
children: [
|
|
10406
10420
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10407
|
-
className:
|
|
10421
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedHeading,
|
|
10408
10422
|
children: t("installFailed")
|
|
10409
10423
|
}),
|
|
10410
10424
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10411
|
-
className:
|
|
10425
|
+
className: _dsh_plugin_shop_css_a037354d_default.log,
|
|
10412
10426
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10413
|
-
className:
|
|
10427
|
+
className: _dsh_plugin_shop_css_a037354d_default.logLine,
|
|
10414
10428
|
"data-shop-log-line": true,
|
|
10415
10429
|
children: line
|
|
10416
10430
|
}, index))
|
|
10417
10431
|
}),
|
|
10418
10432
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10419
|
-
className:
|
|
10433
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedDetail,
|
|
10420
10434
|
children: view.detail === "" ? t("installTransportFailed") : view.detail
|
|
10421
10435
|
}),
|
|
10422
10436
|
refused && word !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10423
10437
|
type: "button",
|
|
10424
|
-
className:
|
|
10438
|
+
className: _dsh_plugin_shop_css_a037354d_default.cancelButton,
|
|
10425
10439
|
"data-shop-install-dismiss": true,
|
|
10426
10440
|
onClick: reset,
|
|
10427
10441
|
children: t("dismiss")
|
|
10428
10442
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10429
10443
|
type: "button",
|
|
10430
|
-
className:
|
|
10444
|
+
className: _dsh_plugin_shop_css_a037354d_default.installButton,
|
|
10431
10445
|
"data-shop-install-retry": true,
|
|
10432
10446
|
disabled: starting,
|
|
10433
10447
|
onClick: () => {
|
|
@@ -10438,19 +10452,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10438
10452
|
]
|
|
10439
10453
|
});
|
|
10440
10454
|
if (view.kind === "rejected") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10441
|
-
className:
|
|
10455
|
+
className: _dsh_plugin_shop_css_a037354d_default.installPanel,
|
|
10442
10456
|
children: [
|
|
10443
10457
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10444
|
-
className:
|
|
10458
|
+
className: _dsh_plugin_shop_css_a037354d_default.rejectedCode,
|
|
10445
10459
|
children: t(rejectionCodeKey(view.code))
|
|
10446
10460
|
}),
|
|
10447
10461
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10448
|
-
className:
|
|
10462
|
+
className: _dsh_plugin_shop_css_a037354d_default.rejectedDetail,
|
|
10449
10463
|
children: view.detail
|
|
10450
10464
|
}),
|
|
10451
10465
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10452
10466
|
type: "button",
|
|
10453
|
-
className:
|
|
10467
|
+
className: _dsh_plugin_shop_css_a037354d_default.cancelButton,
|
|
10454
10468
|
"data-shop-install-dismiss": true,
|
|
10455
10469
|
onClick: reset,
|
|
10456
10470
|
children: t("dismiss")
|
|
@@ -10460,7 +10474,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10460
10474
|
const update = variant === "update";
|
|
10461
10475
|
const detail = blockers.map((blocker) => blocker.text).join("\n");
|
|
10462
10476
|
if (refused && word !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10463
|
-
className:
|
|
10477
|
+
className: _dsh_plugin_shop_css_a037354d_default.refusedLabel,
|
|
10464
10478
|
"data-shop-refused": true,
|
|
10465
10479
|
"data-shop-blocker-kind": blockers[0]?.kind,
|
|
10466
10480
|
role: "img",
|
|
@@ -10472,14 +10486,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10472
10486
|
attrName: "data-shop-refusal",
|
|
10473
10487
|
children: blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
10474
10488
|
blocker,
|
|
10475
|
-
className:
|
|
10489
|
+
className: _dsh_plugin_shop_css_a037354d_default.gateWarning,
|
|
10476
10490
|
surface: "warning"
|
|
10477
10491
|
}, blocker.kind))
|
|
10478
10492
|
})] });
|
|
10479
10493
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
10480
10494
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10481
10495
|
type: "button",
|
|
10482
|
-
className:
|
|
10496
|
+
className: _dsh_plugin_shop_css_a037354d_default.installButton,
|
|
10483
10497
|
disabled: starting,
|
|
10484
10498
|
...update ? { "data-shop-update": true } : { "data-shop-install": true },
|
|
10485
10499
|
onClick: () => {
|
|
@@ -10496,7 +10510,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10496
10510
|
attrName: "data-shop-blocker-lines",
|
|
10497
10511
|
children: blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
10498
10512
|
blocker,
|
|
10499
|
-
className:
|
|
10513
|
+
className: _dsh_plugin_shop_css_a037354d_default.gateWarning,
|
|
10500
10514
|
surface: "warning"
|
|
10501
10515
|
}, blocker.kind))
|
|
10502
10516
|
})
|
|
@@ -10511,32 +10525,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10511
10525
|
function UninstallPanel({ name, t, restart, restartBlocked, reload, flow }) {
|
|
10512
10526
|
const { view, start, reset } = flow;
|
|
10513
10527
|
if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10514
|
-
className:
|
|
10528
|
+
className: _dsh_plugin_shop_css_a037354d_default.installPanel,
|
|
10515
10529
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10516
|
-
className:
|
|
10530
|
+
className: _dsh_plugin_shop_css_a037354d_default.installing,
|
|
10517
10531
|
children: t("uninstalling")
|
|
10518
10532
|
}), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10519
|
-
className:
|
|
10533
|
+
className: _dsh_plugin_shop_css_a037354d_default.log,
|
|
10520
10534
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10521
|
-
className:
|
|
10535
|
+
className: _dsh_plugin_shop_css_a037354d_default.logLine,
|
|
10522
10536
|
"data-shop-log-line": true,
|
|
10523
10537
|
children: line
|
|
10524
10538
|
}, index))
|
|
10525
10539
|
})]
|
|
10526
10540
|
});
|
|
10527
10541
|
if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10528
|
-
className:
|
|
10542
|
+
className: _dsh_plugin_shop_css_a037354d_default.installedActions,
|
|
10529
10543
|
children: [
|
|
10530
10544
|
view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10531
|
-
className:
|
|
10545
|
+
className: _dsh_plugin_shop_css_a037354d_default.log,
|
|
10532
10546
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10533
|
-
className:
|
|
10547
|
+
className: _dsh_plugin_shop_css_a037354d_default.logLine,
|
|
10534
10548
|
"data-shop-log-line": true,
|
|
10535
10549
|
children: line
|
|
10536
10550
|
}, index))
|
|
10537
10551
|
}),
|
|
10538
10552
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10539
|
-
className:
|
|
10553
|
+
className: _dsh_plugin_shop_css_a037354d_default.notice,
|
|
10540
10554
|
"data-shop-uninstall-done": true,
|
|
10541
10555
|
children: t(uninstallActivationNoticeKey(view.activation))
|
|
10542
10556
|
}),
|
|
@@ -10550,7 +10564,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10550
10564
|
}),
|
|
10551
10565
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10552
10566
|
type: "button",
|
|
10553
|
-
className:
|
|
10567
|
+
className: _dsh_plugin_shop_css_a037354d_default.cancelButton,
|
|
10554
10568
|
"data-shop-uninstall-dismiss": true,
|
|
10555
10569
|
onClick: reset,
|
|
10556
10570
|
children: t("dismiss")
|
|
@@ -10558,34 +10572,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10558
10572
|
]
|
|
10559
10573
|
});
|
|
10560
10574
|
if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10561
|
-
className:
|
|
10575
|
+
className: _dsh_plugin_shop_css_a037354d_default.installPanel,
|
|
10562
10576
|
children: [
|
|
10563
10577
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10564
|
-
className:
|
|
10578
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedHeading,
|
|
10565
10579
|
children: t("uninstallFailed")
|
|
10566
10580
|
}),
|
|
10567
10581
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10568
|
-
className:
|
|
10582
|
+
className: _dsh_plugin_shop_css_a037354d_default.log,
|
|
10569
10583
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10570
|
-
className:
|
|
10584
|
+
className: _dsh_plugin_shop_css_a037354d_default.logLine,
|
|
10571
10585
|
"data-shop-log-line": true,
|
|
10572
10586
|
children: line
|
|
10573
10587
|
}, index))
|
|
10574
10588
|
}),
|
|
10575
10589
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10576
|
-
className:
|
|
10590
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedDetail,
|
|
10577
10591
|
children: view.detail === "" ? t("uninstallTransportFailed") : view.detail
|
|
10578
10592
|
}),
|
|
10579
10593
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10580
10594
|
type: "button",
|
|
10581
|
-
className:
|
|
10595
|
+
className: _dsh_plugin_shop_css_a037354d_default.uninstallButton,
|
|
10582
10596
|
"data-shop-uninstall-retry": true,
|
|
10583
10597
|
onClick: () => void start({ name }),
|
|
10584
10598
|
children: t("retry")
|
|
10585
10599
|
}),
|
|
10586
10600
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10587
10601
|
type: "button",
|
|
10588
|
-
className:
|
|
10602
|
+
className: _dsh_plugin_shop_css_a037354d_default.cancelButton,
|
|
10589
10603
|
"data-shop-uninstall-dismiss": true,
|
|
10590
10604
|
onClick: reset,
|
|
10591
10605
|
children: t("dismiss")
|
|
@@ -10595,7 +10609,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10595
10609
|
if (view.kind !== "idle") return null;
|
|
10596
10610
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10597
10611
|
type: "button",
|
|
10598
|
-
className:
|
|
10612
|
+
className: _dsh_plugin_shop_css_a037354d_default.uninstallButton,
|
|
10599
10613
|
"data-shop-uninstall": true,
|
|
10600
10614
|
onClick: () => void start({ name }),
|
|
10601
10615
|
children: t("uninstall")
|
|
@@ -10636,39 +10650,39 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10636
10650
|
else if (outcome.kind === "unreachable") setRefusal(t("restartTransportFailed"));
|
|
10637
10651
|
};
|
|
10638
10652
|
if (monitor?.kind === "requesting" || monitor?.kind === "restarting") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10639
|
-
className:
|
|
10653
|
+
className: _dsh_plugin_shop_css_a037354d_default.notice,
|
|
10640
10654
|
"data-shop-restarting": true,
|
|
10641
10655
|
children: t("restarting")
|
|
10642
10656
|
});
|
|
10643
10657
|
if (monitor?.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10644
|
-
className:
|
|
10658
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedDetail,
|
|
10645
10659
|
"data-shop-restart-error": true,
|
|
10646
10660
|
children: monitor.logFile === void 0 ? t("restartFailedNotice") : t("restartFailedLogNotice", { log: monitor.logFile })
|
|
10647
10661
|
});
|
|
10648
10662
|
if (monitor?.kind === "not-restarted") return null;
|
|
10649
10663
|
if (gateOpen) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10650
|
-
className:
|
|
10664
|
+
className: _dsh_plugin_shop_css_a037354d_default.gate,
|
|
10651
10665
|
"data-shop-restart-gate": true,
|
|
10652
10666
|
children: [
|
|
10653
10667
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10654
|
-
className:
|
|
10668
|
+
className: _dsh_plugin_shop_css_a037354d_default.gateTitle,
|
|
10655
10669
|
children: t("restartTitle")
|
|
10656
10670
|
}),
|
|
10657
10671
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10658
|
-
className:
|
|
10672
|
+
className: _dsh_plugin_shop_css_a037354d_default.gateBody,
|
|
10659
10673
|
children: t("restartBody")
|
|
10660
10674
|
}),
|
|
10661
10675
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10662
|
-
className:
|
|
10676
|
+
className: _dsh_plugin_shop_css_a037354d_default.gateActions,
|
|
10663
10677
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10664
10678
|
type: "button",
|
|
10665
|
-
className:
|
|
10679
|
+
className: _dsh_plugin_shop_css_a037354d_default.confirmButton,
|
|
10666
10680
|
"data-shop-restart-confirm": true,
|
|
10667
10681
|
onClick: () => void onConfirm(),
|
|
10668
10682
|
children: t("restartConfirm")
|
|
10669
10683
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10670
10684
|
type: "button",
|
|
10671
|
-
className:
|
|
10685
|
+
className: _dsh_plugin_shop_css_a037354d_default.cancelButton,
|
|
10672
10686
|
onClick: () => setGateOpen(false),
|
|
10673
10687
|
children: t("cancel")
|
|
10674
10688
|
})]
|
|
@@ -10676,14 +10690,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10676
10690
|
]
|
|
10677
10691
|
});
|
|
10678
10692
|
const refused = refusal === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10679
|
-
className:
|
|
10693
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedDetail,
|
|
10680
10694
|
"data-shop-restart-error": true,
|
|
10681
10695
|
children: refusal
|
|
10682
10696
|
});
|
|
10683
10697
|
if (gate !== void 0) return refused;
|
|
10684
10698
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [refused, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10685
10699
|
type: "button",
|
|
10686
|
-
className:
|
|
10700
|
+
className: _dsh_plugin_shop_css_a037354d_default.restartButton,
|
|
10687
10701
|
"data-shop-restart": true,
|
|
10688
10702
|
onClick: () => setGateOpen(true),
|
|
10689
10703
|
children: t("restart")
|
|
@@ -10701,13 +10715,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10701
10715
|
*/
|
|
10702
10716
|
function NotRestartedNotice({ t, pid, logFile }) {
|
|
10703
10717
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10704
|
-
className:
|
|
10718
|
+
className: _dsh_plugin_shop_css_a037354d_default.selfUpdatePanel,
|
|
10705
10719
|
"data-shop-not-restarted": true,
|
|
10706
10720
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10707
|
-
className:
|
|
10721
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedDetail,
|
|
10708
10722
|
children: pid === void 0 ? t("notRestartedNotice") : t("notRestartedPidNotice", { pid: String(pid) })
|
|
10709
10723
|
}), logFile !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10710
|
-
className:
|
|
10724
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedDetail,
|
|
10711
10725
|
children: t("notRestartedLogNotice", { log: logFile })
|
|
10712
10726
|
})]
|
|
10713
10727
|
});
|
|
@@ -10737,7 +10751,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10737
10751
|
restart,
|
|
10738
10752
|
reload
|
|
10739
10753
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10740
|
-
className:
|
|
10754
|
+
className: _dsh_plugin_shop_css_a037354d_default.notice,
|
|
10741
10755
|
"data-shop-restart-disabled": true,
|
|
10742
10756
|
children: t(restartBlockedNoticeKey(restartBlocked))
|
|
10743
10757
|
});
|
|
@@ -10748,14 +10762,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10748
10762
|
* would help without knowing that now is a good time. */
|
|
10749
10763
|
function ReloadPanel({ t, reload, where }) {
|
|
10750
10764
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10751
|
-
className:
|
|
10765
|
+
className: _dsh_plugin_shop_css_a037354d_default.reloadPanel,
|
|
10752
10766
|
"data-shop-reload": where,
|
|
10753
10767
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10754
|
-
className:
|
|
10768
|
+
className: _dsh_plugin_shop_css_a037354d_default.notice,
|
|
10755
10769
|
children: t("reloadNote")
|
|
10756
10770
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10757
10771
|
type: "button",
|
|
10758
|
-
className:
|
|
10772
|
+
className: _dsh_plugin_shop_css_a037354d_default.reloadButton,
|
|
10759
10773
|
onClick: reload,
|
|
10760
10774
|
children: t("reload")
|
|
10761
10775
|
})]
|
|
@@ -10803,7 +10817,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10803
10817
|
}
|
|
10804
10818
|
};
|
|
10805
10819
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10806
|
-
className:
|
|
10820
|
+
className: _dsh_plugin_shop_css_a037354d_default.switchWrap,
|
|
10807
10821
|
"data-shop-enabled-switch": row.name,
|
|
10808
10822
|
children: [
|
|
10809
10823
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -10812,18 +10826,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10812
10826
|
"aria-checked": enabled,
|
|
10813
10827
|
"aria-label": t("enabledSwitch"),
|
|
10814
10828
|
"data-shop-toggle": true,
|
|
10815
|
-
className: `${
|
|
10829
|
+
className: `${_dsh_plugin_shop_css_a037354d_default.switch} ${enabled ? _dsh_plugin_shop_css_a037354d_default.switchOn : ""}`,
|
|
10816
10830
|
onClick: () => void onToggle(),
|
|
10817
10831
|
disabled: toggle.kind === "saving",
|
|
10818
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
10832
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_a037354d_default.switchKnob })
|
|
10819
10833
|
}),
|
|
10820
10834
|
toggle.kind === "saved" && toggle.live && owed === "nothing" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10821
|
-
className:
|
|
10835
|
+
className: _dsh_plugin_shop_css_a037354d_default.notice,
|
|
10822
10836
|
"data-shop-hot-apply": true,
|
|
10823
10837
|
children: t("hotApplyNote")
|
|
10824
10838
|
}),
|
|
10825
10839
|
owed === "restart" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10826
|
-
className:
|
|
10840
|
+
className: _dsh_plugin_shop_css_a037354d_default.notice,
|
|
10827
10841
|
"data-shop-toggle-restart": true,
|
|
10828
10842
|
children: t("toggleRestartNote")
|
|
10829
10843
|
}),
|
|
@@ -10836,7 +10850,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10836
10850
|
where: "toggle"
|
|
10837
10851
|
}),
|
|
10838
10852
|
toggle.kind === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10839
|
-
className:
|
|
10853
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedDetail,
|
|
10840
10854
|
"data-shop-toggle-error": true,
|
|
10841
10855
|
children: toggle.detail
|
|
10842
10856
|
})
|
|
@@ -10851,19 +10865,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10851
10865
|
* field is narrowed at the parameter. */
|
|
10852
10866
|
function OutdatedRow({ row, tier, missing, harness, t, setEnabled, flowFor, restart, restartBlocked, reload, page }) {
|
|
10853
10867
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10854
|
-
className:
|
|
10868
|
+
className: _dsh_plugin_shop_css_a037354d_default.outdatedRow,
|
|
10855
10869
|
"data-shop-outdated-entry": row.name,
|
|
10856
10870
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10857
|
-
className:
|
|
10871
|
+
className: _dsh_plugin_shop_css_a037354d_default.outdatedInfo,
|
|
10858
10872
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10859
|
-
className:
|
|
10873
|
+
className: _dsh_plugin_shop_css_a037354d_default.name,
|
|
10860
10874
|
children: row.name
|
|
10861
10875
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10862
|
-
className:
|
|
10876
|
+
className: _dsh_plugin_shop_css_a037354d_default.outdatedVersions,
|
|
10863
10877
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("installedVersion", { version: versionLabel(row.source, row.installed).text }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("latestVersion", { version: versionLabel(row.source, row.latest).text }) })]
|
|
10864
10878
|
})]
|
|
10865
10879
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10866
|
-
className:
|
|
10880
|
+
className: _dsh_plugin_shop_css_a037354d_default.outdatedActions,
|
|
10867
10881
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EnabledSwitch, {
|
|
10868
10882
|
row,
|
|
10869
10883
|
surface: "row",
|
|
@@ -10915,22 +10929,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10915
10929
|
function OutdatedSection({ state, entriesByKey, missingByKey, harnessVerdicts, t, setEnabled, flowFor, restart, restartBlocked, reload, page }) {
|
|
10916
10930
|
if (state.kind === "loading") return null;
|
|
10917
10931
|
if (state.kind === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10918
|
-
className:
|
|
10932
|
+
className: _dsh_plugin_shop_css_a037354d_default.stateLine,
|
|
10919
10933
|
"data-shop-outdated-error": true,
|
|
10920
10934
|
children: t("installedError")
|
|
10921
10935
|
});
|
|
10922
10936
|
const outdated = state.entries.filter((entry) => entry.outdated && entry.latest !== null);
|
|
10923
10937
|
if (outdated.length === 0) return null;
|
|
10924
10938
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
10925
|
-
className:
|
|
10939
|
+
className: _dsh_plugin_shop_css_a037354d_default.outdatedSection,
|
|
10926
10940
|
"data-shop-outdated": true,
|
|
10927
10941
|
"aria-labelledby": UPDATABLE_HEADING_ID,
|
|
10928
10942
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
10929
|
-
className:
|
|
10943
|
+
className: _dsh_plugin_shop_css_a037354d_default.updatableHeading,
|
|
10930
10944
|
id: UPDATABLE_HEADING_ID,
|
|
10931
10945
|
children: t("updatableSection")
|
|
10932
10946
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
10933
|
-
className:
|
|
10947
|
+
className: _dsh_plugin_shop_css_a037354d_default.outdatedList,
|
|
10934
10948
|
children: outdated.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutdatedRow, {
|
|
10935
10949
|
row,
|
|
10936
10950
|
tier: entriesByKey.get(identityKey(row))?.tier ?? "community",
|
|
@@ -10958,37 +10972,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10958
10972
|
const shadowed = entries.filter((entry) => entry.shadowed === true);
|
|
10959
10973
|
if (shadowed.length === 0) return null;
|
|
10960
10974
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
10961
|
-
className:
|
|
10975
|
+
className: _dsh_plugin_shop_css_a037354d_default.shadowedSection,
|
|
10962
10976
|
"data-shop-shadowed": true,
|
|
10963
10977
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
10964
|
-
className:
|
|
10978
|
+
className: _dsh_plugin_shop_css_a037354d_default.outdatedList,
|
|
10965
10979
|
children: shadowed.map((row) => {
|
|
10966
10980
|
const key = identityKey(row);
|
|
10967
10981
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10968
|
-
className:
|
|
10982
|
+
className: _dsh_plugin_shop_css_a037354d_default.outdatedRow,
|
|
10969
10983
|
"data-shop-shadowed-entry": row.name,
|
|
10970
10984
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10971
|
-
className:
|
|
10985
|
+
className: _dsh_plugin_shop_css_a037354d_default.outdatedInfo,
|
|
10972
10986
|
children: [
|
|
10973
10987
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10974
|
-
className:
|
|
10988
|
+
className: _dsh_plugin_shop_css_a037354d_default.name,
|
|
10975
10989
|
children: row.name
|
|
10976
10990
|
}),
|
|
10977
10991
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10978
|
-
className:
|
|
10992
|
+
className: _dsh_plugin_shop_css_a037354d_default.badges,
|
|
10979
10993
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10980
|
-
className:
|
|
10994
|
+
className: _dsh_plugin_shop_css_a037354d_default.tierBadge,
|
|
10981
10995
|
"data-tier": "shadowed",
|
|
10982
10996
|
children: t("shadowedBadge")
|
|
10983
10997
|
})
|
|
10984
10998
|
}),
|
|
10985
10999
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10986
|
-
className:
|
|
11000
|
+
className: _dsh_plugin_shop_css_a037354d_default.shadowedDetail,
|
|
10987
11001
|
children: t("shadowedDetail")
|
|
10988
11002
|
})
|
|
10989
11003
|
]
|
|
10990
11004
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10991
|
-
className:
|
|
11005
|
+
className: _dsh_plugin_shop_css_a037354d_default.outdatedActions,
|
|
10992
11006
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UninstallPanel, {
|
|
10993
11007
|
name: row.name,
|
|
10994
11008
|
t,
|
|
@@ -11038,16 +11052,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11038
11052
|
role: "alert",
|
|
11039
11053
|
children: [
|
|
11040
11054
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11041
|
-
className:
|
|
11055
|
+
className: _dsh_plugin_shop_css_a037354d_default.stateLine,
|
|
11042
11056
|
children: say("tabCrashed", en.tabCrashed)
|
|
11043
11057
|
}),
|
|
11044
11058
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11045
|
-
className:
|
|
11059
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedDetail,
|
|
11046
11060
|
children: error.message
|
|
11047
11061
|
}),
|
|
11048
11062
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11049
11063
|
type: "button",
|
|
11050
|
-
className:
|
|
11064
|
+
className: _dsh_plugin_shop_css_a037354d_default.actionButton,
|
|
11051
11065
|
onClick: () => this.setState({ error: null }),
|
|
11052
11066
|
children: say("retry", en.retry)
|
|
11053
11067
|
})
|
|
@@ -11373,19 +11387,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11373
11387
|
"data-shop-tab": true,
|
|
11374
11388
|
"aria-busy": "true",
|
|
11375
11389
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11376
|
-
className:
|
|
11390
|
+
className: _dsh_plugin_shop_css_a037354d_default.srOnly,
|
|
11377
11391
|
children: t("loading")
|
|
11378
11392
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11379
|
-
className:
|
|
11393
|
+
className: _dsh_plugin_shop_css_a037354d_default.skeletonGrid,
|
|
11380
11394
|
"data-shop-skeleton": true,
|
|
11381
11395
|
"aria-hidden": "true",
|
|
11382
11396
|
children: Array.from({ length: 8 }, (_, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11383
|
-
className:
|
|
11397
|
+
className: _dsh_plugin_shop_css_a037354d_default.skeletonCard,
|
|
11384
11398
|
children: [
|
|
11385
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
11386
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
11387
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
11388
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
11399
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_a037354d_default.skeletonName }),
|
|
11400
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_a037354d_default.skeletonSummary }),
|
|
11401
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_a037354d_default.skeletonSummaryShort }),
|
|
11402
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_a037354d_default.skeletonActions })
|
|
11389
11403
|
]
|
|
11390
11404
|
}, i))
|
|
11391
11405
|
})]
|
|
@@ -11395,11 +11409,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11395
11409
|
translate: "no",
|
|
11396
11410
|
"data-shop-tab": true,
|
|
11397
11411
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11398
|
-
className:
|
|
11412
|
+
className: _dsh_plugin_shop_css_a037354d_default.stateLine,
|
|
11399
11413
|
children: t("error")
|
|
11400
11414
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11401
11415
|
type: "button",
|
|
11402
|
-
className:
|
|
11416
|
+
className: _dsh_plugin_shop_css_a037354d_default.actionButton,
|
|
11403
11417
|
onClick: () => {
|
|
11404
11418
|
setRequest({
|
|
11405
11419
|
kind: "retry",
|
|
@@ -11417,11 +11431,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11417
11431
|
"data-shop-tab": true,
|
|
11418
11432
|
children: [
|
|
11419
11433
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11420
|
-
className:
|
|
11434
|
+
className: _dsh_plugin_shop_css_a037354d_default.toolbar,
|
|
11421
11435
|
children: [
|
|
11422
11436
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
11423
11437
|
type: "search",
|
|
11424
|
-
className:
|
|
11438
|
+
className: _dsh_plugin_shop_css_a037354d_default.searchInput,
|
|
11425
11439
|
"aria-label": t("search"),
|
|
11426
11440
|
placeholder: t("search"),
|
|
11427
11441
|
value: query,
|
|
@@ -11434,31 +11448,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11434
11448
|
}),
|
|
11435
11449
|
expansionMemo.intents.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11436
11450
|
"data-shop-expansion-note": true,
|
|
11437
|
-
className:
|
|
11451
|
+
className: _dsh_plugin_shop_css_a037354d_default.expansionNote,
|
|
11438
11452
|
children: t("zhExpansionNote", { terms: expansionMemo.terms.slice(1).map((term) => term.startsWith("#") ? term.slice(1) : term).join(", ") })
|
|
11439
11453
|
}),
|
|
11440
11454
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11441
|
-
className:
|
|
11455
|
+
className: _dsh_plugin_shop_css_a037354d_default.toolbarRight,
|
|
11442
11456
|
children: [
|
|
11443
11457
|
result.stale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11444
|
-
className:
|
|
11458
|
+
className: _dsh_plugin_shop_css_a037354d_default.staleBadge,
|
|
11445
11459
|
children: t("staleLabel", { date: result.builtAt.slice(0, 10) })
|
|
11446
11460
|
}),
|
|
11447
11461
|
selfVersion !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11448
|
-
className:
|
|
11462
|
+
className: _dsh_plugin_shop_css_a037354d_default.versionBlock,
|
|
11449
11463
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
11450
|
-
className:
|
|
11464
|
+
className: _dsh_plugin_shop_css_a037354d_default.versionText,
|
|
11451
11465
|
"data-shop-version": true,
|
|
11452
11466
|
children: ["v", selfVersion.installed]
|
|
11453
11467
|
}), restartMonitor !== null ? null : selfPending && restartBlocked === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11454
11468
|
type: "button",
|
|
11455
|
-
className:
|
|
11469
|
+
className: _dsh_plugin_shop_css_a037354d_default.restartSelfButton,
|
|
11456
11470
|
"data-shop-restart": true,
|
|
11457
11471
|
onClick: () => setSelfRestartGate(true),
|
|
11458
11472
|
children: t("restart")
|
|
11459
11473
|
}) : !selfPending && selfVersion.outdated && selfVersion.latest !== null && selfUpdate.view.kind === "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11460
11474
|
type: "button",
|
|
11461
|
-
className:
|
|
11475
|
+
className: _dsh_plugin_shop_css_a037354d_default.updateSelfButton,
|
|
11462
11476
|
"data-shop-update-self": true,
|
|
11463
11477
|
onClick: () => {
|
|
11464
11478
|
if (selfVersion.latest !== null) selfUpdate.start({ version: selfVersion.latest });
|
|
@@ -11466,7 +11480,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11466
11480
|
children: t("update")
|
|
11467
11481
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11468
11482
|
type: "button",
|
|
11469
|
-
className:
|
|
11483
|
+
className: _dsh_plugin_shop_css_a037354d_default.checkUpdateButton,
|
|
11470
11484
|
"data-shop-check-update": true,
|
|
11471
11485
|
title: t("checkUpdateTitle"),
|
|
11472
11486
|
disabled: checkState !== "idle",
|
|
@@ -11475,7 +11489,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11475
11489
|
})]
|
|
11476
11490
|
}),
|
|
11477
11491
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
11478
|
-
className:
|
|
11492
|
+
className: _dsh_plugin_shop_css_a037354d_default.githubLink,
|
|
11479
11493
|
href: SHOP_REPO_URL,
|
|
11480
11494
|
target: "_blank",
|
|
11481
11495
|
rel: "noopener noreferrer",
|
|
@@ -11500,28 +11514,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11500
11514
|
logFile: restartMonitor.logFile
|
|
11501
11515
|
}),
|
|
11502
11516
|
selfUpdate.view.kind === "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11503
|
-
className:
|
|
11517
|
+
className: _dsh_plugin_shop_css_a037354d_default.selfUpdatePanel,
|
|
11504
11518
|
"data-shop-self-updating": true,
|
|
11505
11519
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11506
|
-
className:
|
|
11520
|
+
className: _dsh_plugin_shop_css_a037354d_default.installing,
|
|
11507
11521
|
children: t(installPhaseKey(selfUpdate.view.phase))
|
|
11508
11522
|
}), selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11509
|
-
className:
|
|
11523
|
+
className: _dsh_plugin_shop_css_a037354d_default.log,
|
|
11510
11524
|
children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11511
|
-
className:
|
|
11525
|
+
className: _dsh_plugin_shop_css_a037354d_default.logLine,
|
|
11512
11526
|
"data-shop-log-line": true,
|
|
11513
11527
|
children: line
|
|
11514
11528
|
}, index))
|
|
11515
11529
|
})]
|
|
11516
11530
|
}),
|
|
11517
11531
|
selfPending && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11518
|
-
className:
|
|
11532
|
+
className: _dsh_plugin_shop_css_a037354d_default.selfUpdatePanel,
|
|
11519
11533
|
"data-shop-self-update-done": true,
|
|
11520
11534
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11521
|
-
className:
|
|
11535
|
+
className: _dsh_plugin_shop_css_a037354d_default.installedActions,
|
|
11522
11536
|
children: [
|
|
11523
11537
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11524
|
-
className:
|
|
11538
|
+
className: _dsh_plugin_shop_css_a037354d_default.notice,
|
|
11525
11539
|
children: t("installedRestartNotice")
|
|
11526
11540
|
}),
|
|
11527
11541
|
restartBlocked === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RestartPanel, {
|
|
@@ -11534,7 +11548,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11534
11548
|
}
|
|
11535
11549
|
}),
|
|
11536
11550
|
restartBlocked !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11537
|
-
className:
|
|
11551
|
+
className: _dsh_plugin_shop_css_a037354d_default.notice,
|
|
11538
11552
|
"data-shop-restart-disabled": true,
|
|
11539
11553
|
children: t(restartBlockedNoticeKey(restartBlocked))
|
|
11540
11554
|
})
|
|
@@ -11542,28 +11556,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11542
11556
|
})
|
|
11543
11557
|
}),
|
|
11544
11558
|
selfUpdate.view.kind === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11545
|
-
className:
|
|
11559
|
+
className: _dsh_plugin_shop_css_a037354d_default.selfUpdatePanel,
|
|
11546
11560
|
"data-shop-self-update-failed": true,
|
|
11547
11561
|
children: [
|
|
11548
11562
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11549
|
-
className:
|
|
11563
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedHeading,
|
|
11550
11564
|
children: t("updateFailed")
|
|
11551
11565
|
}),
|
|
11552
11566
|
selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11553
|
-
className:
|
|
11567
|
+
className: _dsh_plugin_shop_css_a037354d_default.log,
|
|
11554
11568
|
children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11555
|
-
className:
|
|
11569
|
+
className: _dsh_plugin_shop_css_a037354d_default.logLine,
|
|
11556
11570
|
"data-shop-log-line": true,
|
|
11557
11571
|
children: line
|
|
11558
11572
|
}, index))
|
|
11559
11573
|
}),
|
|
11560
11574
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11561
|
-
className:
|
|
11575
|
+
className: _dsh_plugin_shop_css_a037354d_default.failedDetail,
|
|
11562
11576
|
children: selfUpdate.view.detail === "" ? t("updateTransportFailed") : selfUpdate.view.detail
|
|
11563
11577
|
}),
|
|
11564
11578
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11565
11579
|
type: "button",
|
|
11566
|
-
className:
|
|
11580
|
+
className: _dsh_plugin_shop_css_a037354d_default.cancelButton,
|
|
11567
11581
|
"data-shop-update-self-dismiss": true,
|
|
11568
11582
|
onClick: () => {
|
|
11569
11583
|
selfUpdate.resetWhere((current) => current.kind === "failed");
|
|
@@ -11573,13 +11587,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11573
11587
|
]
|
|
11574
11588
|
}),
|
|
11575
11589
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11576
|
-
className:
|
|
11590
|
+
className: _dsh_plugin_shop_css_a037354d_default.categoryBar,
|
|
11577
11591
|
role: "group",
|
|
11578
11592
|
"aria-label": t("catalog"),
|
|
11579
11593
|
children: [
|
|
11580
11594
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
11581
11595
|
type: "button",
|
|
11582
|
-
className: category === null ? `${
|
|
11596
|
+
className: category === null ? `${_dsh_plugin_shop_css_a037354d_default.categoryButton} ${_dsh_plugin_shop_css_a037354d_default.categoryButtonOn}` : _dsh_plugin_shop_css_a037354d_default.categoryButton,
|
|
11583
11597
|
"aria-pressed": category === null,
|
|
11584
11598
|
onClick: () => {
|
|
11585
11599
|
page.setView({
|
|
@@ -11596,7 +11610,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11596
11610
|
}),
|
|
11597
11611
|
CATEGORY_ORDER.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
11598
11612
|
type: "button",
|
|
11599
|
-
className: category === key ? `${
|
|
11613
|
+
className: category === key ? `${_dsh_plugin_shop_css_a037354d_default.categoryButton} ${_dsh_plugin_shop_css_a037354d_default.categoryButtonOn}` : _dsh_plugin_shop_css_a037354d_default.categoryButton,
|
|
11600
11614
|
"aria-pressed": category === key,
|
|
11601
11615
|
"data-category": key,
|
|
11602
11616
|
"data-shop-category-tab": key,
|
|
@@ -11614,7 +11628,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11614
11628
|
}, key)),
|
|
11615
11629
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
11616
11630
|
type: "button",
|
|
11617
|
-
className: category === "installed" ? `${
|
|
11631
|
+
className: category === "installed" ? `${_dsh_plugin_shop_css_a037354d_default.categoryButton} ${_dsh_plugin_shop_css_a037354d_default.categoryButtonOn}` : _dsh_plugin_shop_css_a037354d_default.categoryButton,
|
|
11618
11632
|
"aria-pressed": category === "installed",
|
|
11619
11633
|
"data-shop-category-installed": true,
|
|
11620
11634
|
onClick: () => {
|
|
@@ -11633,7 +11647,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11633
11647
|
type: "button",
|
|
11634
11648
|
role: "switch",
|
|
11635
11649
|
"aria-checked": hideIncompatible,
|
|
11636
|
-
className: hideIncompatible ? `${
|
|
11650
|
+
className: hideIncompatible ? `${_dsh_plugin_shop_css_a037354d_default.incompatibleFilter} ${_dsh_plugin_shop_css_a037354d_default.incompatibleFilterOn}` : _dsh_plugin_shop_css_a037354d_default.incompatibleFilter,
|
|
11637
11651
|
title: t(hideIncompatible ? "showIncompatibleTitle" : "incompatibleFilterTitle"),
|
|
11638
11652
|
"data-shop-hide-incompatible": true,
|
|
11639
11653
|
onClick: () => {
|
|
@@ -11643,18 +11657,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11643
11657
|
}));
|
|
11644
11658
|
},
|
|
11645
11659
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11646
|
-
className: hideIncompatible ? `${
|
|
11660
|
+
className: hideIncompatible ? `${_dsh_plugin_shop_css_a037354d_default.switch} ${_dsh_plugin_shop_css_a037354d_default.switchOn}` : _dsh_plugin_shop_css_a037354d_default.switch,
|
|
11647
11661
|
"aria-hidden": "true",
|
|
11648
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
11662
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_a037354d_default.switchKnob })
|
|
11649
11663
|
}), t("hideIncompatible", { count: incompatibleCount })]
|
|
11650
11664
|
})
|
|
11651
11665
|
]
|
|
11652
11666
|
}),
|
|
11653
11667
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11654
|
-
className:
|
|
11668
|
+
className: _dsh_plugin_shop_css_a037354d_default.catalogStatsRow,
|
|
11655
11669
|
children: [
|
|
11656
11670
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11657
|
-
className:
|
|
11671
|
+
className: _dsh_plugin_shop_css_a037354d_default.catalogStats,
|
|
11658
11672
|
"data-shop-catalog-stats": true,
|
|
11659
11673
|
children: t("catalogStats", {
|
|
11660
11674
|
count: String(browsable.length),
|
|
@@ -11663,7 +11677,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11663
11677
|
}),
|
|
11664
11678
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11665
11679
|
type: "button",
|
|
11666
|
-
className:
|
|
11680
|
+
className: _dsh_plugin_shop_css_a037354d_default.catalogRefreshButton,
|
|
11667
11681
|
"data-shop-catalog-refresh": true,
|
|
11668
11682
|
disabled: reloading,
|
|
11669
11683
|
onClick: () => {
|
|
@@ -11678,22 +11692,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11678
11692
|
children: reloading ? t("refreshing") : t("refresh")
|
|
11679
11693
|
}),
|
|
11680
11694
|
reloadFailed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11681
|
-
className:
|
|
11695
|
+
className: _dsh_plugin_shop_css_a037354d_default.catalogRefreshFailed,
|
|
11682
11696
|
"data-shop-catalog-refresh-failed": true,
|
|
11683
11697
|
children: t("refreshFailed")
|
|
11684
11698
|
}),
|
|
11685
11699
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
11686
|
-
className:
|
|
11700
|
+
className: _dsh_plugin_shop_css_a037354d_default.sortGroup,
|
|
11687
11701
|
role: "group",
|
|
11688
11702
|
"aria-labelledby": sortLabelId,
|
|
11689
11703
|
"data-shop-sort": true,
|
|
11690
11704
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11691
|
-
className:
|
|
11705
|
+
className: _dsh_plugin_shop_css_a037354d_default.sortLabel,
|
|
11692
11706
|
id: sortLabelId,
|
|
11693
11707
|
children: t("sortLabel")
|
|
11694
11708
|
}), SHELF_ORDERS.map((name) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11695
11709
|
type: "button",
|
|
11696
|
-
className: order === name ? `${
|
|
11710
|
+
className: order === name ? `${_dsh_plugin_shop_css_a037354d_default.categoryButton} ${_dsh_plugin_shop_css_a037354d_default.categoryButtonOn}` : _dsh_plugin_shop_css_a037354d_default.categoryButton,
|
|
11697
11711
|
"aria-pressed": order === name,
|
|
11698
11712
|
"data-shop-order": name,
|
|
11699
11713
|
onClick: () => {
|
|
@@ -11708,18 +11722,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11708
11722
|
]
|
|
11709
11723
|
}),
|
|
11710
11724
|
result.plugins.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11711
|
-
className:
|
|
11725
|
+
className: _dsh_plugin_shop_css_a037354d_default.emptyLine,
|
|
11712
11726
|
children: t("empty")
|
|
11713
11727
|
}) : filtered.length === 0 ? category === "installed" && installedState.kind !== "ready" ? installedState.kind === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11714
|
-
className:
|
|
11728
|
+
className: _dsh_plugin_shop_css_a037354d_default.emptyLine,
|
|
11715
11729
|
"data-shop-installed-loading": true,
|
|
11716
11730
|
children: t("installedLoading")
|
|
11717
11731
|
}) : null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11718
|
-
className:
|
|
11732
|
+
className: _dsh_plugin_shop_css_a037354d_default.emptyLine,
|
|
11719
11733
|
"data-shop-empty": true,
|
|
11720
11734
|
children: matched.length > 0 ? t("emptyIncompatibleFiltered") : t("emptySearch")
|
|
11721
11735
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
|
|
11722
|
-
className:
|
|
11736
|
+
className: _dsh_plugin_shop_css_a037354d_default.cards,
|
|
11723
11737
|
children: [visible.map((entry) => {
|
|
11724
11738
|
const key = entryKey(entry);
|
|
11725
11739
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
@@ -11746,12 +11760,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11746
11760
|
}, key);
|
|
11747
11761
|
}), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
11748
11762
|
ref: sentinelRef,
|
|
11749
|
-
className:
|
|
11763
|
+
className: _dsh_plugin_shop_css_a037354d_default.cardsSentry,
|
|
11750
11764
|
"data-shop-sentry": true,
|
|
11751
11765
|
"aria-hidden": "true"
|
|
11752
11766
|
})]
|
|
11753
11767
|
}), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11754
|
-
className:
|
|
11768
|
+
className: _dsh_plugin_shop_css_a037354d_default.showingLine,
|
|
11755
11769
|
"aria-live": "polite",
|
|
11756
11770
|
children: t("showing", {
|
|
11757
11771
|
shown: String(visibleCount),
|
|
@@ -11908,7 +11922,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11908
11922
|
}, [page]);
|
|
11909
11923
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
11910
11924
|
ref: scroller,
|
|
11911
|
-
className: `${
|
|
11925
|
+
className: `${_dsh_plugin_shop_css_a037354d_default.page} notranslate`,
|
|
11912
11926
|
translate: "no",
|
|
11913
11927
|
"data-shop-page": true,
|
|
11914
11928
|
onScroll: (event) => {
|
|
@@ -11918,15 +11932,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11918
11932
|
onTouchStart: cancelRestore,
|
|
11919
11933
|
onKeyDown: cancelRestore,
|
|
11920
11934
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
11921
|
-
className:
|
|
11935
|
+
className: _dsh_plugin_shop_css_a037354d_default.pageHead,
|
|
11922
11936
|
"data-shop-page-head": true,
|
|
11923
11937
|
"data-window-drag": true,
|
|
11924
11938
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
11925
|
-
className:
|
|
11939
|
+
className: _dsh_plugin_shop_css_a037354d_default.pageTitle,
|
|
11926
11940
|
"data-shop-page-title": true,
|
|
11927
11941
|
children: t("title")
|
|
11928
11942
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11929
|
-
className:
|
|
11943
|
+
className: _dsh_plugin_shop_css_a037354d_default.pageIntro,
|
|
11930
11944
|
"data-shop-page-intro": true,
|
|
11931
11945
|
children: t("intro")
|
|
11932
11946
|
})]
|