dsh-plugin-shop 0.8.7-beta.0 → 0.8.7-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/client.js CHANGED
@@ -4328,6 +4328,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4328
4328
  _undefined(),
4329
4329
  literal(false),
4330
4330
  literal(true)
4331
+ ]).optional(),
4332
+ "forked": union([
4333
+ _undefined(),
4334
+ literal(false),
4335
+ literal(true)
4331
4336
  ]).optional()
4332
4337
  })),
4333
4338
  "denied": array(object({
@@ -6546,15 +6551,61 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6546
6551
  case "desktop-profile": return "desktopProfileCode";
6547
6552
  }
6548
6553
  }
6549
- /** The version a card displays: full for npm, the short commit for github. */
6550
- function displayVersion(entry) {
6551
- return entry.source === "github" ? entry.version.slice(0, 7) : entry.version;
6554
+ /** A commit pin as the registry writes one: forty lowercase hex. */
6555
+ const COMMIT_PIN = /^[0-9a-f]{40}$/;
6556
+ /**
6557
+ * How a version string reads on the shelf, decided by its source and its
6558
+ * shape alone (market borrowings §11).
6559
+ *
6560
+ * Shape, never the entry's `tarball`, because an installed row carries only
6561
+ * the pin the shop recorded at install — the catalog `version` of that moment
6562
+ * — and no `tarball`. The registry pins a commit as forty lowercase hex and a
6563
+ * release by its tag, so the two shapes do not cross; `present.test.ts`
6564
+ * checks that against the committed live catalog.
6565
+ *
6566
+ * - An npm version takes the `v` the shelf has always shown, and only before
6567
+ * a digit: an installed row reports the manifest's spec, and a range there
6568
+ * (`^1.2.3`) is not a version to prefix.
6569
+ * - A commit is cut to the seven characters git abbreviates to, with no `v`:
6570
+ * it is not a version number.
6571
+ * - A release tag prints exactly as tagged, never cut and never prefixed:
6572
+ * cutting `v0.29.10` to seven characters printed `v0.29.1`, another
6573
+ * version, and the `v` this function no longer adds doubled the tag's own.
6574
+ */
6575
+ function versionLabel(source, version) {
6576
+ if (source === "npm") return {
6577
+ kind: "npm",
6578
+ text: /^\d/.test(version) ? `v${version}` : version,
6579
+ value: version
6580
+ };
6581
+ if (COMMIT_PIN.test(version)) {
6582
+ const short = version.slice(0, 7);
6583
+ return {
6584
+ kind: "commit",
6585
+ text: short,
6586
+ value: short
6587
+ };
6588
+ }
6589
+ return {
6590
+ kind: "release",
6591
+ text: version,
6592
+ value: version
6593
+ };
6594
+ }
6595
+ /** The copy that names a version's kind, for the accessible name and the
6596
+ * tooltip; its `{version}` takes {@link VersionLabel.value}. */
6597
+ function versionLabelKey(kind) {
6598
+ switch (kind) {
6599
+ case "npm": return "npmVersionLabel";
6600
+ case "commit": return "commitVersionLabel";
6601
+ case "release": return "releaseVersionLabel";
6602
+ }
6552
6603
  }
6553
6604
  /** The hash pin a stale line names for a repo or release-rescued entry — the
6554
6605
  * reviewed commit, or the reviewed release tarball sha256 (market borrowings
6555
- * §3.1). Shortened to 7 chars like the card's own version; '' only for a
6556
- * hand-built fixture carrying no pin. The npm form is a version and keeps the
6557
- * version line's `v` prefix instead. */
6606
+ * §3.1). Shortened to 7 chars like a commit on the card; '' only for a
6607
+ * hand-built fixture carrying no pin. The npm form is a version, which
6608
+ * {@link versionLabel} prints instead. */
6558
6609
  function reviewHashPin(review) {
6559
6610
  return (review.reviewedCommit ?? review.reviewedSha256 ?? "").slice(0, 7);
6560
6611
  }
@@ -6679,6 +6730,24 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6679
6730
  }
6680
6731
  }
6681
6732
  }
6733
+ /**
6734
+ * Which order the shelf is in (design 2026-10-12-shelf-orders). `stars` is
6735
+ * the default AND the tie-break of both date orders, so the two date orders
6736
+ * are stable re-sorts of it rather than orders with comparators of their own.
6737
+ */
6738
+ const SHELF_ORDER_KEYS = {
6739
+ stars: "sortStars",
6740
+ added: "sortAdded",
6741
+ updated: "sortUpdated"
6742
+ };
6743
+ /** The three orders in display order (map insertion order). `readonly`: this
6744
+ * is a shared vocabulary, and an order list a caller can push to is a bug
6745
+ * waiting for its second caller. */
6746
+ const SHELF_ORDERS = Object.keys(SHELF_ORDER_KEYS);
6747
+ /** The locale key naming one order (the toggle's buttons). */
6748
+ function shelfOrderLocaleKey(order) {
6749
+ return SHELF_ORDER_KEYS[order];
6750
+ }
6682
6751
  const CATEGORY_KEYS = {
6683
6752
  tool: "categoryTool",
6684
6753
  provider: "categoryProvider",
@@ -6825,6 +6894,77 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6825
6894
  return NAME_COLLATOR.compare(a.name, b.name);
6826
6895
  });
6827
6896
  }
6897
+ /** The day form the registry writes into `added` (`emit.ts` E9 enforces it
6898
+ * on every build on its side; a catalog is untrusted input on this side). */
6899
+ const DAY_FORM = /^\d{4}-\d{2}-\d{2}$/;
6900
+ /**
6901
+ * The ES date-time form WITH an explicit zone. The zone is required, and not
6902
+ * for tidiness: a date-time string with no zone is parsed as LOCAL time, so
6903
+ * accepting one would make the shelf's order depend on the machine.
6904
+ */
6905
+ const INSTANT_FORM = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?(?:Z|[+-]\d{2}:\d{2})$/;
6906
+ /**
6907
+ * One date string as milliseconds, or undefined when it cannot be trusted.
6908
+ *
6909
+ * The form is checked BEFORE `Date.parse`, and that order is load-bearing:
6910
+ * V8 answers a real instant for `2026-02-31T00:00:00Z` (3 March) and for
6911
+ * `October 12` (a 2001 date), so `Date.parse` alone is not a validity test.
6912
+ */
6913
+ function parseForm(value, form) {
6914
+ if (typeof value !== "string" || !form.test(value)) return void 0;
6915
+ const ms = Date.parse(value);
6916
+ return Number.isNaN(ms) ? void 0 : ms;
6917
+ }
6918
+ /** `shelfTime` with the catalog's build time already parsed, for the n calls
6919
+ * `orderShelf` makes in one pass. */
6920
+ function timeOf(entry, order, built) {
6921
+ if (order === "stars") return void 0;
6922
+ const ms = order === "added" ? parseForm(entry.added, DAY_FORM) : parseForm(entry.publishedAt, INSTANT_FORM);
6923
+ if (ms === void 0 || built === void 0 || ms > built) return void 0;
6924
+ return ms;
6925
+ }
6926
+ /**
6927
+ * The entry's sort key under a date order, or undefined when it has no usable
6928
+ * date (design §3): absent, off-form, unparseable, or later than the catalog's
6929
+ * own `builtAt`. Milliseconds since the epoch. `'stars'` carries no date, so
6930
+ * this answers undefined for it.
6931
+ */
6932
+ function shelfTime(entry, order, builtAt) {
6933
+ return timeOf(entry, order, parseForm(builtAt, INSTANT_FORM));
6934
+ }
6935
+ /**
6936
+ * A UTC calendar day for display: "2026-10-12". Derived from the instant the
6937
+ * sort ranked by, so a card's label and its position cannot disagree. UTC and
6938
+ * never a local getter: a reader in UTC+8 must see the same days the catalog
6939
+ * was built in, the calendar the stats row already prints.
6940
+ */
6941
+ function utcDay(ms) {
6942
+ return new Date(ms).toISOString().slice(0, 10);
6943
+ }
6944
+ /**
6945
+ * The shelf in `order` (design 2026-10-12-shelf-orders §2, §5). `'stars'`
6946
+ * returns the array it was handed, so the default path allocates nothing and
6947
+ * does not invalidate the memos downstream of it.
6948
+ *
6949
+ * Each key is computed ONCE per entry rather than inside the comparator, and
6950
+ * the sort is stable (ES2019), so entries sharing a date keep the star order
6951
+ * they arrived in — which is how the tie-break is defined without a second
6952
+ * comparator that could drift from `sortByStars`.
6953
+ */
6954
+ function orderShelf(starOrdered, order, builtAt) {
6955
+ if (order === "stars") return starOrdered;
6956
+ const built = parseForm(builtAt, INSTANT_FORM);
6957
+ const keyed = starOrdered.map((entry) => ({
6958
+ entry,
6959
+ time: timeOf(entry, order, built)
6960
+ }));
6961
+ keyed.sort((a, b) => {
6962
+ if (a.time === void 0) return b.time === void 0 ? 0 : 1;
6963
+ if (b.time === void 0) return -1;
6964
+ return b.time - a.time;
6965
+ });
6966
+ return keyed.map((item) => item.entry);
6967
+ }
6828
6968
  /** 999 → "999"; 1000 → "1k"; 1234 → "1.2k"; 1500 → "1.5k"; 99999 → "100k". */
6829
6969
  function formatStars(n) {
6830
6970
  if (n < 1e3) return String(n);
@@ -6897,6 +7037,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6897
7037
  all: "全部",
6898
7038
  catalog: "插件目录",
6899
7039
  catalogStats: "{count} 个插件 · 构建于 {date}",
7040
+ /** The shelf's order control, and the date each card carries under the two
7041
+ * date orders (design 2026-10-12-shelf-orders §4). */
7042
+ sortLabel: "排序",
7043
+ sortStars: "星标",
7044
+ sortAdded: "最新上架",
7045
+ sortUpdated: "最近更新",
7046
+ listedOn: "上架 {date}",
7047
+ updatedOn: "更新 {date}",
6900
7048
  stars: "{count} 星",
6901
7049
  categoryTool: "工具",
6902
7050
  categoryProvider: "模型服务",
@@ -6981,7 +7129,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6981
7129
  emptyIncompatibleFiltered: "匹配的插件都标为不兼容,已被「隐藏不兼容」筛掉。",
6982
7130
  license: "许可",
6983
7131
  customLicense: "自定义许可",
6984
- reviewedVersionLine: "已审核 v{reviewed} / 当前 v{current} 未审核",
7132
+ reviewedVersionLine: "已审核 {reviewed} / 当前 {current} 未审核",
6985
7133
  reviewedPinLine: "已审核 {pin} / 当前 {current} 未审核",
6986
7134
  deniedCode: "已拒绝",
6987
7135
  notInCatalogCode: "不在目录中",
@@ -6995,6 +7143,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6995
7143
  nameTakenDetail: "已安装同名的另一个插件({holder})。\n两个同名插件声明相同的加载项 id,无法共存;安装它会替换掉已装的那个。",
6996
7144
  npmSource: "npm 包",
6997
7145
  githubSource: "源码在 GitHub",
7146
+ /** The accessible name and the tooltip of a card's version, which say which
7147
+ * of three things the printed string is (market borrowings §11): the string
7148
+ * alone cannot tell a release tag from a version number, and a short commit
7149
+ * printed with a `v` read as one. */
7150
+ npmVersionLabel: "npm 版本 {version}",
7151
+ commitVersionLabel: "GitHub 提交 {version}",
7152
+ releaseVersionLabel: "GitHub 发布 {version}",
6998
7153
  /** The badge and the explanation for an installed github entry no catalog
6999
7154
  * row claims (C10 MVP). The mechanism synthesizes a row for ANY github spec
7000
7155
  * with no catalog row — shadowed by a same-named npm package, an unlisted
@@ -7004,8 +7159,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7004
7159
  shadowedBadge: "目录未列出此包",
7005
7160
  shadowedDetail: "此包已安装,但当前的插件目录没有它(可能是被同名 npm 包遮蔽、作者已下架、或目录尚未收录);它照常运行。",
7006
7161
  updatableSection: "可更新",
7007
- installedVersion: "已安装 v{version}",
7008
- latestVersion: "最新 v{version}",
7162
+ /** `{version}` is the shelf's own version text (`versionLabel`), which
7163
+ * carries the `v` an npm version takes and no other kind does. */
7164
+ installedVersion: "已安装 {version}",
7165
+ latestVersion: "最新 {version}",
7009
7166
  update: "更新",
7010
7167
  installed: "已安装",
7011
7168
  uninstall: "卸载",
@@ -7061,6 +7218,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7061
7218
  all: "All",
7062
7219
  catalog: "Plugin catalog",
7063
7220
  catalogStats: "{count} packages · built {date}",
7221
+ /** The shelf's order control, and the date each card carries under the two
7222
+ * date orders (design 2026-10-12-shelf-orders §4). */
7223
+ sortLabel: "Sort",
7224
+ sortStars: "Stars",
7225
+ sortAdded: "Newest",
7226
+ sortUpdated: "Recently updated",
7227
+ listedOn: "Listed {date}",
7228
+ updatedOn: "Updated {date}",
7064
7229
  stars: "{count} stars",
7065
7230
  categoryTool: "Tool",
7066
7231
  categoryProvider: "Provider",
@@ -7121,7 +7286,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7121
7286
  emptyIncompatibleFiltered: "Every matching plugin is marked incompatible, and the incompatible filter is leaving them out.",
7122
7287
  license: "License",
7123
7288
  customLicense: "Custom license",
7124
- reviewedVersionLine: "reviewed v{reviewed} / current v{current} unreviewed",
7289
+ reviewedVersionLine: "reviewed {reviewed} / current {current} unreviewed",
7125
7290
  reviewedPinLine: "reviewed {pin} / current {current} unreviewed",
7126
7291
  deniedCode: "Denied",
7127
7292
  notInCatalogCode: "Not in the catalog",
@@ -7135,11 +7300,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7135
7300
  nameTakenDetail: "A different plugin of this name is installed ({holder}).\nTwo plugins of one name declare the same loader entry id and cannot both load; installing this one would replace it.",
7136
7301
  npmSource: "npm package",
7137
7302
  githubSource: "source on GitHub",
7303
+ npmVersionLabel: "npm version {version}",
7304
+ commitVersionLabel: "GitHub commit {version}",
7305
+ releaseVersionLabel: "GitHub release {version}",
7138
7306
  shadowedBadge: "Not in the current catalog",
7139
7307
  shadowedDetail: "This package is installed but the current catalog does not list it (it may be shadowed by a same-named npm package, removed by the author, or never listed); it runs as before.",
7140
7308
  updatableSection: "Updatable",
7141
- installedVersion: "installed v{version}",
7142
- latestVersion: "latest v{version}",
7309
+ installedVersion: "installed {version}",
7310
+ latestVersion: "latest {version}",
7143
7311
  update: "Update",
7144
7312
  installed: "Installed",
7145
7313
  uninstall: "Uninstall",
@@ -9047,124 +9215,127 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9047
9215
  };
9048
9216
  }
9049
9217
  //#endregion
9050
- //#region \0dsh-plugin-shop-css:e3675a89
9051
- const css = "/* Shop tab styles — a market shelf inside the settings surface. The visual\n * language is the dsh theme's alias tokens ONLY (the four tokens the previous\n * styles referenced that do not exist — bg-layer-3, interactive-bg-hover,\n * state-error, state-success — are corrected to bg-layer-2 and the\n * state-*-primary set). 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.s8583e3_client.s942a79_config.s5f67aa_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.s8583e3_client.sfd9d8a_spec.s5f67aa_ts` pins this. */\n\n.s255e5a_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\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 `.s232ec4_searchInput` sits at\n * exactly (0, 0) of this box — it is the first child of `.s646509_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.s44a3ec_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.s3a0ece_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.se0c3b4_skeletonGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 8px;\n}\n\n.s520416_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.s520416_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.s8c7d6f_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.sf5179e_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.sbb0d25_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.s96e910_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.s520416_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 .s520416_skeletonCard span { animation: none; opacity: 0.75; }\n .s520416_skeletonCard::after { content: none; }\n}\n\n.s73242a_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.s73242a_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.s73242a_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s646509_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.s745e3c_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.s4fe61f_versionBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.sb9b924_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.sa04455_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.sa04455_updateSelfButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 20%, transparent);\n}\n\n.sa04455_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.s614a38_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.s614a38_checkUpdateButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n color: var(--dsw-alias-label-primary);\n}\n\n.s614a38_checkUpdateButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.s614a38_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.sa987f7_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.sa987f7_githubLink:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.sa987f7_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.sb81ba5_selfUpdatePanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.s232ec4_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.s232ec4_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.s76fb13_expansionNote {\n margin: 4px 0 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s3946f1_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(--dsw-alias-state-warn-primary);\n font-size: 12px;\n}\n\n.sb2c859_categoryBar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n}\n\n.s26d58e_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.s26d58e_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 `.s26d58e_categoryButton.s5f68c4_categoryButtonOn` — TWO classes — so it\n * matches `.s26d58e_categoryButton:hover`'s specificity and, coming after it, wins.\n * As a bare `.s5f68c4_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 or a shadow: a pressed tab must occupy\n * exactly the same box as an unpressed one, so the bar does not reflow — and\n * with ~9 pills on a wrapping row, one that grows can push the rest onto\n * another line and move the tab out from under the pointer that just clicked\n * it. That is what `font-weight: 600` did (bold metrics are wider than\n * regular), and it is why nothing may be added here that resolves to a length:\n * no padding, no border-width, no font-size, no letter-spacing.\n * `css-tokens.s8583e3_client.sfd9d8a_spec.s5f67aa_ts` fails the build on one.\n *\n * `box-shadow` is the exception that earns its place: it paints outside the\n * layout box, so an inset ring doubles the border's weight at zero cost to the\n * metrics. It is what `font-weight: 600` used to be — a second, thickness-\n * based signal that hover does not also produce — and the `other` tab needs it\n * most: its hue IS the neutral gray this file uses for \"no category\", so on\n * the light theme hue alone barely separates pressed from unpressed. */\n.s26d58e_categoryButton.s5f68c4_categoryButtonOn {\n border-color: var(--category-hue);\n background: color-mix(in srgb, var(--category-hue) 14%, transparent);\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n box-shadow: inset 0 0 0 1px var(--category-hue);\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. `box-shadow` is dropped in this mode\n * too, so the ring has to come back as an outline. */\n@media (forced-colors: active) {\n .s26d58e_categoryButton.s5f68c4_categoryButtonOn {\n outline: 2px solid ButtonText;\n outline-offset: -4px;\n }\n}\n\n.s26d58e_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 `.s26d58e_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.sfd887b_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: `.sfd887b_incompatibleFilter:hover .s11c019_switch` outranks `.s7580e8_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.sfd887b_incompatibleFilter:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.sfd887b_incompatibleFilter:hover .s11c019_switch:not(.s7580e8_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 `.s26d58e_categoryButton.s5f68c4_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.sfd887b_incompatibleFilter.s6e4cba_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.sfd887b_incompatibleFilter .s11c019_switch:not(.s7580e8_switchOn) .saab2b3_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.sfd887b_incompatibleFilter:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 999px;\n}\n\n.sebf017_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.seb0a1e_catalogStatsRow {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 6px 0 0;\n}\n\n.sccc4d1_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 `.s73242a_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.sff243d_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.sff243d_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.sff243d_catalogRefreshButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.sff243d_catalogRefreshButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s194168_catalogRefreshFailed {\n font-size: 11px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s6de1ab_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.sf657f5_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 .sf657f5_cards { animation: none; }\n}\n\n.s65f383_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.sd7ee01_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s705cc6_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s65f383_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 .s65f383_card { transition: none; }\n .s65f383_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.s4ce25d_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. `.s26d58e_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.s65f383_card[data-category='tool'], .s26d58e_categoryButton[data-category='tool'] { --category-hue: #4C8DFF; }\n.s65f383_card[data-category='provider'], .s26d58e_categoryButton[data-category='provider'] { --category-hue: #A78BFA; }\n.s65f383_card[data-category='ui'], .s26d58e_categoryButton[data-category='ui'] { --category-hue: #2DD4BF; }\n.s65f383_card[data-category='workflow'], .s26d58e_categoryButton[data-category='workflow'] { --category-hue: #F59E0B; }\n.s65f383_card[data-category='integration'], .s26d58e_categoryButton[data-category='integration'] { --category-hue: #34D399; }\n.s65f383_card[data-category='theme'], .s26d58e_categoryButton[data-category='theme'] { --category-hue: #F472B6; }\n.s65f383_card[data-category='other'], .s26d58e_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.s9c8eaa_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.sa97234_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.sa97234_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.sc3f149_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.s513026_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.s9b5048_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.s9b5048_cardActions > .sc4f2ac_gate,\n.s9b5048_cardActions > .s4d374c_installPanel,\n.s9b5048_cardActions > .sf53ca0_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.sc6ec6e_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}\n\n/* The octocat marking a github-sourced entry, beside its short commit. */\n.s71f10f_sourceBadge {\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s5e82cb_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.s5e82cb_tierBadge[data-tier='verified'] {\n color: var(--dsw-alias-state-success-primary);\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.s5e82cb_tierBadge[data-tier='verified-stale'] {\n color: var(--dsw-alias-state-warn-primary);\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.s5e82cb_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.s5e82cb_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.s5e82cb_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.s4bbe02_incompatibleBadge {\n flex-shrink: 0;\n padding: 3px 9px;\n border-radius: 999px;\n font-size: 12px;\n white-space: nowrap;\n color: var(--dsw-alias-state-error-primary);\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.sff43b4_starsBadge {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s73f7fb_chevron, .s61393c_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s61393c_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .s73f7fb_chevron, .s61393c_chevronOpen { transition: none; }\n}\n\n.s820ebf_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px;\n}\n\n.sb8fbc8_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.se507db_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.s10baf0_summaryExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n.sb9dba9_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.s6eca19_incompatibleDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n white-space: pre-line;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* The way out of dsh's own refusal: the lead-in, then the exemption command\n * on its own line. */\n.s3d0044_remedy {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.sdf203f_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.sc32335_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 * disabled button, the command that clears dsh's refusal included. */\n.sc74941_refusal {\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex-basis: 100%;\n}\n\n.s9d2029_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s3bdbd5_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s441702_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s441702_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.sde3f0c_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.se98179_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.sfb4d2f_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.sfb4d2f_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.sfb4d2f_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.sfb4d2f_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.sfb4d2f_detailRow a:hover {\n text-decoration: underline;\n}\n\n.sfb4d2f_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 * `.s9b5048_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.s5fbaf9_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: `.s5fbaf9_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.s2d3c05_size {\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 `.s5fbaf9_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 `.s5fbaf9_cardMeta`. There is no middot:\n * `.s5fbaf9_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.s1ff66f_author {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.sd58c6d_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(--dsw-alias-state-warn-primary);\n}\n\n/* Install flow. */\n.s4d374c_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n.se7aaed_installButton, .sb43a49_confirmButton, .s6e45d1_cancelButton {\n align-self: flex-start;\n padding: 5px 14px;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n}\n\n.se7aaed_installButton {\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.se7aaed_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.sb43a49_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.sb43a49_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s6e45d1_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.s6e45d1_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.se7aaed_installButton:focus-visible, .sb43a49_confirmButton:focus-visible, .s6e45d1_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.sb6fc74_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/* 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.sf53ca0_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.s96967f_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 color: var(--dsw-alias-state-error-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s96967f_uninstallButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.s96967f_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.sb00c36_restartSelfButton {\n /* The version row's third state. Geometry matches .s614a38_checkUpdateButton and\n * .sa04455_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.sb00c36_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.s6ac237_restartButton,\n.s64a5ff_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.s6ac237_restartButton:hover,\n.s64a5ff_reloadButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s6ac237_restartButton:focus-visible,\n.s64a5ff_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 * `.sf53ca0_installedActions` the way the restart gate is — a column of its own\n * rather than inline with the row. */\n.sf79aef_reloadPanel {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n}\n\n\n.sc4f2ac_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.s559c38_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s3c0ace_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.sc323e5_gateWarning {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n white-space: pre-line;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.s4b2373_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.s52b5a5_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s64ab71_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.s1531a8_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sf20dda_notice {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.seb9b08_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.sfd3021_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s50ba35_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.se75489_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.sa276cf_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.sceae6e_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s8d2072_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.s5c2545_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s5c2545_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.s877c68_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 .s513026_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.s6c4649_shadowedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.scc2a21_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.sa1f556_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] overflows the settings dialog. */\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: `.sfd887b_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 `.s11c019_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.s11c019_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.s7580e8_switchOn {\n border-color: var(--track-hue);\n background: color-mix(in srgb, var(--track-hue) 55%, transparent);\n}\n\n.saab2b3_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.s7580e8_switchOn .saab2b3_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.s11c019_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 .s11c019_switch, .saab2b3_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.sd9f9e4_switchWrap {\n display: inline-flex;\n align-items: center;\n /* Same reason as `.sa1f556_outdatedActions`: `.sf79aef_reloadPanel`'s own comment calls\n * itself \"a column of its own rather than inline with the row\", which held\n * for `.sf53ca0_installedActions` and not here until this line. */\n flex-wrap: wrap;\n gap: 8px;\n}\n";
9052
- if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"e3675a89\"]")) {
9218
+ //#region \0dsh-plugin-shop-css:d74581c2
9219
+ const css = "/* Shop tab styles — a market shelf inside the settings surface. The visual\n * language is the dsh theme's alias tokens ONLY (the four tokens the previous\n * styles referenced that do not exist — bg-layer-3, interactive-bg-hover,\n * state-error, state-success — are corrected to bg-layer-2 and the\n * state-*-primary set). 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.s73a3ff_client.s45aee2_config.s8a51a7_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.s73a3ff_client.s117e2f_spec.s8a51a7_ts` pins this. */\n\n.sa2d7b5_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\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 `.s7c10d7_searchInput` sits at\n * exactly (0, 0) of this box — it is the first child of `.sbee2c3_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.sa89499_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.s90f53b_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.sd5b66e_skeletonGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 8px;\n}\n\n.sfb41cd_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.sfb41cd_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.sc9bc63_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.s75708b_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.s772f28_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.s6ce39d_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.sfb41cd_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 .sfb41cd_skeletonCard span { animation: none; opacity: 0.75; }\n .sfb41cd_skeletonCard::after { content: none; }\n}\n\n.s1547e4_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.s1547e4_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.s1547e4_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sbee2c3_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.sfb98ad_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.s15df74_versionBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.s9d78e5_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.scb0503_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.scb0503_updateSelfButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 20%, transparent);\n}\n\n.scb0503_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.seab5ae_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.seab5ae_checkUpdateButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n color: var(--dsw-alias-label-primary);\n}\n\n.seab5ae_checkUpdateButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.seab5ae_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.s6932e1_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.s6932e1_githubLink:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.s6932e1_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.sb1e444_selfUpdatePanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.s7c10d7_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.s7c10d7_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.s1dee54_expansionNote {\n margin: 4px 0 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s5823b0_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(--dsw-alias-state-warn-primary);\n font-size: 12px;\n}\n\n.s52084f_categoryBar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n}\n\n.sd07f01_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.sd07f01_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 `.sd07f01_categoryButton.s7d231e_categoryButtonOn` — TWO classes — so it\n * matches `.sd07f01_categoryButton:hover`'s specificity and, coming after it, wins.\n * As a bare `.s7d231e_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 or a shadow: a pressed tab must occupy\n * exactly the same box as an unpressed one, so the bar does not reflow — and\n * with ~9 pills on a wrapping row, one that grows can push the rest onto\n * another line and move the tab out from under the pointer that just clicked\n * it. That is what `font-weight: 600` did (bold metrics are wider than\n * regular), and it is why nothing may be added here that resolves to a length:\n * no padding, no border-width, no font-size, no letter-spacing.\n * `css-tokens.s73a3ff_client.s117e2f_spec.s8a51a7_ts` fails the build on one.\n *\n * `box-shadow` is the exception that earns its place: it paints outside the\n * layout box, so an inset ring doubles the border's weight at zero cost to the\n * metrics. It is what `font-weight: 600` used to be — a second, thickness-\n * based signal that hover does not also produce — and the `other` tab needs it\n * most: its hue IS the neutral gray this file uses for \"no category\", so on\n * the light theme hue alone barely separates pressed from unpressed. */\n.sd07f01_categoryButton.s7d231e_categoryButtonOn {\n border-color: var(--category-hue);\n background: color-mix(in srgb, var(--category-hue) 14%, transparent);\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n box-shadow: inset 0 0 0 1px var(--category-hue);\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. `box-shadow` is dropped in this mode\n * too, so the ring has to come back as an outline. */\n@media (forced-colors: active) {\n .sd07f01_categoryButton.s7d231e_categoryButtonOn {\n outline: 2px solid ButtonText;\n outline-offset: -4px;\n }\n}\n\n.sd07f01_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 `.sd07f01_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.s7abba7_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: `.s7abba7_incompatibleFilter:hover .sa4bed2_switch` outranks `.s97d8ec_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.s7abba7_incompatibleFilter:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.s7abba7_incompatibleFilter:hover .sa4bed2_switch:not(.s97d8ec_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 `.sd07f01_categoryButton.s7d231e_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.s7abba7_incompatibleFilter.sa24b4e_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.s7abba7_incompatibleFilter .sa4bed2_switch:not(.s97d8ec_switchOn) .s24e1f5_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.s7abba7_incompatibleFilter:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 999px;\n}\n\n.s3ffb2a_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.sfd3ed8_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.sc5a073_sortGroup {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n margin-left: auto;\n}\n\n.s275eb9_sortLabel {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.s3c7a5d_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 `.s1547e4_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.s6d141d_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.s6d141d_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.s6d141d_catalogRefreshButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.s6d141d_catalogRefreshButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s8b8ed4_catalogRefreshFailed {\n font-size: 11px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.s918b21_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.sf66d65_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 .sf66d65_cards { animation: none; }\n}\n\n.sa6c0bf_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.s21cef7_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s9babb8_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa6c0bf_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 .sa6c0bf_card { transition: none; }\n .sa6c0bf_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.sce2063_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. `.sd07f01_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.sa6c0bf_card[data-category='tool'], .sd07f01_categoryButton[data-category='tool'] { --category-hue: #4C8DFF; }\n.sa6c0bf_card[data-category='provider'], .sd07f01_categoryButton[data-category='provider'] { --category-hue: #A78BFA; }\n.sa6c0bf_card[data-category='ui'], .sd07f01_categoryButton[data-category='ui'] { --category-hue: #2DD4BF; }\n.sa6c0bf_card[data-category='workflow'], .sd07f01_categoryButton[data-category='workflow'] { --category-hue: #F59E0B; }\n.sa6c0bf_card[data-category='integration'], .sd07f01_categoryButton[data-category='integration'] { --category-hue: #34D399; }\n.sa6c0bf_card[data-category='theme'], .sd07f01_categoryButton[data-category='theme'] { --category-hue: #F472B6; }\n.sa6c0bf_card[data-category='other'], .sd07f01_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.sdc7cd8_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.s6ae6ba_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.s6ae6ba_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.saf3e98_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.s93d243_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.s763b75_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.s763b75_cardActions > .sff1df6_gate,\n.s763b75_cardActions > .s6d7bee_installPanel,\n.s763b75_cardActions > .s10ddb2_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.s9d1d9e_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.sad456f_sourceBadge {\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s7f352e_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.s7f352e_tierBadge[data-tier='verified'] {\n color: var(--dsw-alias-state-success-primary);\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.s7f352e_tierBadge[data-tier='verified-stale'] {\n color: var(--dsw-alias-state-warn-primary);\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.s7f352e_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.s7f352e_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.s7f352e_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.s649a66_incompatibleBadge {\n flex-shrink: 0;\n padding: 3px 9px;\n border-radius: 999px;\n font-size: 12px;\n white-space: nowrap;\n color: var(--dsw-alias-state-error-primary);\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.se83753_starsBadge {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sc7129d_chevron, .s3e170e_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s3e170e_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .sc7129d_chevron, .s3e170e_chevronOpen { transition: none; }\n}\n\n.s249e15_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px;\n}\n\n.sdd4d7a_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.s1a6809_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.sc924dd_summaryExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n.sab7503_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.s4625f5_incompatibleDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n white-space: pre-line;\n color: var(--dsw-alias-state-error-primary);\n}\n\n/* The way out of dsh's own refusal: the lead-in, then the exemption command\n * on its own line. */\n.s632e71_remedy {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s360025_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.s12ec11_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 * disabled button, the command that clears dsh's refusal included. */\n.sa92311_refusal {\n display: flex;\n flex-direction: column;\n gap: 6px;\n flex-basis: 100%;\n}\n\n.s99a4f5_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.scf0a21_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sc760c8_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.sc760c8_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.s48edfc_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.sce5502_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.scc4b2b_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.scc4b2b_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.scc4b2b_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.scc4b2b_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.scc4b2b_detailRow a:hover {\n text-decoration: underline;\n}\n\n.scc4b2b_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 * `.s763b75_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.s8fb80a_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: `.s8fb80a_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 * `.s72b045_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.s24611f_size,\n.s72b045_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 `.s8fb80a_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 `.s8fb80a_cardMeta`. There is no middot:\n * `.s8fb80a_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.seefbaa_author {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.sa79085_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(--dsw-alias-state-warn-primary);\n}\n\n/* Install flow. */\n.s6d7bee_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n.sdddc5f_installButton, .safd4a8_confirmButton, .sfcf768_cancelButton {\n align-self: flex-start;\n padding: 5px 14px;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n}\n\n.sdddc5f_installButton {\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.sdddc5f_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.safd4a8_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.safd4a8_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.sfcf768_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.sfcf768_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.sdddc5f_installButton:focus-visible, .safd4a8_confirmButton:focus-visible, .sfcf768_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.s563674_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/* 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.s10ddb2_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.s767a97_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 color: var(--dsw-alias-state-error-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s767a97_uninstallButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.s767a97_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.sa6b105_restartSelfButton {\n /* The version row's third state. Geometry matches .seab5ae_checkUpdateButton and\n * .scb0503_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.sa6b105_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.s426aa0_restartButton,\n.sa283f9_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.s426aa0_restartButton:hover,\n.sa283f9_reloadButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s426aa0_restartButton:focus-visible,\n.sa283f9_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 * `.s10ddb2_installedActions` the way the restart gate is — a column of its own\n * rather than inline with the row. */\n.sf20a99_reloadPanel {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n}\n\n\n.sff1df6_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.see0e3d_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.sd04ef9_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.s7fd5d3_gateWarning {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n white-space: pre-line;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.sf6b0aa_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.sa32b72_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sf9b6a4_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.s9e4d00_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s7cd7db_notice {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.sfb1bae_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.s9591b1_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.saa0605_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.sbd5c7c_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.s7c248d_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.se144d3_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s6fbe58_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.s8af496_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s8af496_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.sf82d51_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 .s93d243_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.s31b89a_shadowedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.scf838f_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.s109c95_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] overflows the settings dialog. */\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: `.s7abba7_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 `.sa4bed2_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.sa4bed2_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.s97d8ec_switchOn {\n border-color: var(--track-hue);\n background: color-mix(in srgb, var(--track-hue) 55%, transparent);\n}\n\n.s24e1f5_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.s97d8ec_switchOn .s24e1f5_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.sa4bed2_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 .sa4bed2_switch, .s24e1f5_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.s5c21f4_switchWrap {\n display: inline-flex;\n align-items: center;\n /* Same reason as `.s109c95_outdatedActions`: `.sf20a99_reloadPanel`'s own comment calls\n * itself \"a column of its own rather than inline with the row\", which held\n * for `.s10ddb2_installedActions` and not here until this line. */\n flex-wrap: wrap;\n gap: 8px;\n}\n";
9220
+ if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"d74581c2\"]")) {
9053
9221
  const tag = document.createElement("style");
9054
- tag.dataset.pluginCss = "e3675a89";
9222
+ tag.dataset.pluginCss = "d74581c2";
9055
9223
  tag.textContent = css;
9056
9224
  document.head.appendChild(tag);
9057
9225
  }
9058
- var _dsh_plugin_shop_css_e3675a89_default = {
9059
- "client": "s8583e3_client",
9060
- "config": "s942a79_config",
9061
- "ts": "s5f67aa_ts",
9062
- "spec": "sfd9d8a_spec",
9063
- "panel": "s255e5a_panel",
9064
- "searchInput": "s232ec4_searchInput",
9065
- "toolbar": "s646509_toolbar",
9066
- "stateLine": "s44a3ec_stateLine",
9067
- "srOnly": "s3a0ece_srOnly",
9068
- "skeletonGrid": "se0c3b4_skeletonGrid",
9069
- "skeletonCard": "s520416_skeletonCard",
9070
- "skeletonName": "s8c7d6f_skeletonName",
9071
- "skeletonSummary": "sf5179e_skeletonSummary",
9072
- "skeletonSummaryShort": "sbb0d25_skeletonSummaryShort",
9073
- "skeletonActions": "s96e910_skeletonActions",
9074
- "actionButton": "s73242a_actionButton",
9075
- "toolbarRight": "s745e3c_toolbarRight",
9076
- "versionBlock": "s4fe61f_versionBlock",
9077
- "versionText": "sb9b924_versionText",
9078
- "updateSelfButton": "sa04455_updateSelfButton",
9079
- "checkUpdateButton": "s614a38_checkUpdateButton",
9080
- "githubLink": "sa987f7_githubLink",
9081
- "selfUpdatePanel": "sb81ba5_selfUpdatePanel",
9082
- "expansionNote": "s76fb13_expansionNote",
9083
- "staleBadge": "s3946f1_staleBadge",
9084
- "categoryBar": "sb2c859_categoryBar",
9085
- "categoryButton": "s26d58e_categoryButton",
9086
- "categoryButtonOn": "s5f68c4_categoryButtonOn",
9087
- "incompatibleFilter": "sfd887b_incompatibleFilter",
9088
- "switch": "s11c019_switch",
9089
- "switchOn": "s7580e8_switchOn",
9090
- "incompatibleFilterOn": "s6e4cba_incompatibleFilterOn",
9091
- "switchKnob": "saab2b3_switchKnob",
9092
- "updatableHeading": "sebf017_updatableHeading",
9093
- "catalogStatsRow": "seb0a1e_catalogStatsRow",
9094
- "catalogStats": "sccc4d1_catalogStats",
9095
- "catalogRefreshButton": "sff243d_catalogRefreshButton",
9096
- "catalogRefreshFailed": "s194168_catalogRefreshFailed",
9097
- "emptyLine": "s6de1ab_emptyLine",
9098
- "cards": "sf657f5_cards",
9099
- "card": "s65f383_card",
9100
- "cardsSentry": "sd7ee01_cardsSentry",
9101
- "showingLine": "s705cc6_showingLine",
9102
- "cardSpine": "s4ce25d_cardSpine",
9103
- "categoryBadge": "s9c8eaa_categoryBadge",
9104
- "entryHeader": "sa97234_entryHeader",
9105
- "name": "sc3f149_name",
9106
- "badges": "s513026_badges",
9107
- "cardActions": "s9b5048_cardActions",
9108
- "gate": "sc4f2ac_gate",
9109
- "installPanel": "s4d374c_installPanel",
9110
- "installedActions": "sf53ca0_installedActions",
9111
- "cardVersion": "sc6ec6e_cardVersion",
9112
- "sourceBadge": "s71f10f_sourceBadge",
9113
- "tierBadge": "s5e82cb_tierBadge",
9114
- "incompatibleBadge": "s4bbe02_incompatibleBadge",
9115
- "starsBadge": "sff43b4_starsBadge",
9116
- "chevron": "s73f7fb_chevron",
9117
- "chevronOpen": "s61393c_chevronOpen",
9118
- "body": "s820ebf_body",
9119
- "summary": "sb8fbc8_summary",
9120
- "summaryZh": "se507db_summaryZh",
9121
- "summaryExpanded": "s10baf0_summaryExpanded",
9122
- "summaryZhExpanded": "sb9dba9_summaryZhExpanded",
9123
- "incompatibleDetail": "s6eca19_incompatibleDetail",
9124
- "remedy": "s3d0044_remedy",
9125
- "remedyLead": "sdf203f_remedyLead",
9126
- "allowCommand": "sc32335_allowCommand",
9127
- "refusal": "sc74941_refusal",
9128
- "capabilitiesBlock": "s9d2029_capabilitiesBlock",
9129
- "capabilitiesNote": "s3bdbd5_capabilitiesNote",
9130
- "capabilities": "s441702_capabilities",
9131
- "detail": "sde3f0c_detail",
9132
- "detailRows": "se98179_detailRows",
9133
- "detailRow": "sfb4d2f_detailRow",
9134
- "cardMeta": "s5fbaf9_cardMeta",
9135
- "size": "s2d3c05_size",
9136
- "author": "s1ff66f_author",
9137
- "reviewedLine": "sd58c6d_reviewedLine",
9138
- "installButton": "se7aaed_installButton",
9139
- "confirmButton": "sb43a49_confirmButton",
9140
- "cancelButton": "s6e45d1_cancelButton",
9141
- "installedLabel": "sb6fc74_installedLabel",
9142
- "uninstallButton": "s96967f_uninstallButton",
9143
- "restartSelfButton": "sb00c36_restartSelfButton",
9144
- "restartButton": "s6ac237_restartButton",
9145
- "reloadButton": "s64a5ff_reloadButton",
9146
- "reloadPanel": "sf79aef_reloadPanel",
9147
- "gateTitle": "s559c38_gateTitle",
9148
- "gateBody": "s3c0ace_gateBody",
9149
- "gateWarning": "sc323e5_gateWarning",
9150
- "gateActions": "s4b2373_gateActions",
9151
- "installing": "s52b5a5_installing",
9152
- "log": "s64ab71_log",
9153
- "logLine": "s1531a8_logLine",
9154
- "notice": "sf20dda_notice",
9155
- "failedHeading": "seb9b08_failedHeading",
9156
- "failedDetail": "sfd3021_failedDetail",
9157
- "rejectedCode": "s50ba35_rejectedCode",
9158
- "rejectedDetail": "se75489_rejectedDetail",
9159
- "outdatedSection": "sa276cf_outdatedSection",
9160
- "outdatedList": "sceae6e_outdatedList",
9161
- "outdatedRow": "s8d2072_outdatedRow",
9162
- "outdatedInfo": "s5c2545_outdatedInfo",
9163
- "outdatedVersions": "s877c68_outdatedVersions",
9164
- "shadowedSection": "s6c4649_shadowedSection",
9165
- "shadowedDetail": "scc2a21_shadowedDetail",
9166
- "outdatedActions": "sa1f556_outdatedActions",
9167
- "switchWrap": "sd9f9e4_switchWrap"
9226
+ var _dsh_plugin_shop_css_d74581c2_default = {
9227
+ "client": "s73a3ff_client",
9228
+ "config": "s45aee2_config",
9229
+ "ts": "s8a51a7_ts",
9230
+ "spec": "s117e2f_spec",
9231
+ "panel": "sa2d7b5_panel",
9232
+ "searchInput": "s7c10d7_searchInput",
9233
+ "toolbar": "sbee2c3_toolbar",
9234
+ "stateLine": "sa89499_stateLine",
9235
+ "srOnly": "s90f53b_srOnly",
9236
+ "skeletonGrid": "sd5b66e_skeletonGrid",
9237
+ "skeletonCard": "sfb41cd_skeletonCard",
9238
+ "skeletonName": "sc9bc63_skeletonName",
9239
+ "skeletonSummary": "s75708b_skeletonSummary",
9240
+ "skeletonSummaryShort": "s772f28_skeletonSummaryShort",
9241
+ "skeletonActions": "s6ce39d_skeletonActions",
9242
+ "actionButton": "s1547e4_actionButton",
9243
+ "toolbarRight": "sfb98ad_toolbarRight",
9244
+ "versionBlock": "s15df74_versionBlock",
9245
+ "versionText": "s9d78e5_versionText",
9246
+ "updateSelfButton": "scb0503_updateSelfButton",
9247
+ "checkUpdateButton": "seab5ae_checkUpdateButton",
9248
+ "githubLink": "s6932e1_githubLink",
9249
+ "selfUpdatePanel": "sb1e444_selfUpdatePanel",
9250
+ "expansionNote": "s1dee54_expansionNote",
9251
+ "staleBadge": "s5823b0_staleBadge",
9252
+ "categoryBar": "s52084f_categoryBar",
9253
+ "categoryButton": "sd07f01_categoryButton",
9254
+ "categoryButtonOn": "s7d231e_categoryButtonOn",
9255
+ "incompatibleFilter": "s7abba7_incompatibleFilter",
9256
+ "switch": "sa4bed2_switch",
9257
+ "switchOn": "s97d8ec_switchOn",
9258
+ "incompatibleFilterOn": "sa24b4e_incompatibleFilterOn",
9259
+ "switchKnob": "s24e1f5_switchKnob",
9260
+ "updatableHeading": "s3ffb2a_updatableHeading",
9261
+ "catalogStatsRow": "sfd3ed8_catalogStatsRow",
9262
+ "sortGroup": "sc5a073_sortGroup",
9263
+ "sortLabel": "s275eb9_sortLabel",
9264
+ "catalogStats": "s3c7a5d_catalogStats",
9265
+ "catalogRefreshButton": "s6d141d_catalogRefreshButton",
9266
+ "catalogRefreshFailed": "s8b8ed4_catalogRefreshFailed",
9267
+ "emptyLine": "s918b21_emptyLine",
9268
+ "cards": "sf66d65_cards",
9269
+ "card": "sa6c0bf_card",
9270
+ "cardsSentry": "s21cef7_cardsSentry",
9271
+ "showingLine": "s9babb8_showingLine",
9272
+ "cardSpine": "sce2063_cardSpine",
9273
+ "categoryBadge": "sdc7cd8_categoryBadge",
9274
+ "entryHeader": "s6ae6ba_entryHeader",
9275
+ "name": "saf3e98_name",
9276
+ "badges": "s93d243_badges",
9277
+ "cardActions": "s763b75_cardActions",
9278
+ "gate": "sff1df6_gate",
9279
+ "installPanel": "s6d7bee_installPanel",
9280
+ "installedActions": "s10ddb2_installedActions",
9281
+ "cardVersion": "s9d1d9e_cardVersion",
9282
+ "sourceBadge": "sad456f_sourceBadge",
9283
+ "tierBadge": "s7f352e_tierBadge",
9284
+ "incompatibleBadge": "s649a66_incompatibleBadge",
9285
+ "starsBadge": "se83753_starsBadge",
9286
+ "chevron": "sc7129d_chevron",
9287
+ "chevronOpen": "s3e170e_chevronOpen",
9288
+ "body": "s249e15_body",
9289
+ "summary": "sdd4d7a_summary",
9290
+ "summaryZh": "s1a6809_summaryZh",
9291
+ "summaryExpanded": "sc924dd_summaryExpanded",
9292
+ "summaryZhExpanded": "sab7503_summaryZhExpanded",
9293
+ "incompatibleDetail": "s4625f5_incompatibleDetail",
9294
+ "remedy": "s632e71_remedy",
9295
+ "remedyLead": "s360025_remedyLead",
9296
+ "allowCommand": "s12ec11_allowCommand",
9297
+ "refusal": "sa92311_refusal",
9298
+ "capabilitiesBlock": "s99a4f5_capabilitiesBlock",
9299
+ "capabilitiesNote": "scf0a21_capabilitiesNote",
9300
+ "capabilities": "sc760c8_capabilities",
9301
+ "detail": "s48edfc_detail",
9302
+ "detailRows": "sce5502_detailRows",
9303
+ "detailRow": "scc4b2b_detailRow",
9304
+ "cardMeta": "s8fb80a_cardMeta",
9305
+ "shelfDate": "s72b045_shelfDate",
9306
+ "size": "s24611f_size",
9307
+ "author": "seefbaa_author",
9308
+ "reviewedLine": "sa79085_reviewedLine",
9309
+ "installButton": "sdddc5f_installButton",
9310
+ "confirmButton": "safd4a8_confirmButton",
9311
+ "cancelButton": "sfcf768_cancelButton",
9312
+ "installedLabel": "s563674_installedLabel",
9313
+ "uninstallButton": "s767a97_uninstallButton",
9314
+ "restartSelfButton": "sa6b105_restartSelfButton",
9315
+ "restartButton": "s426aa0_restartButton",
9316
+ "reloadButton": "sa283f9_reloadButton",
9317
+ "reloadPanel": "sf20a99_reloadPanel",
9318
+ "gateTitle": "see0e3d_gateTitle",
9319
+ "gateBody": "sd04ef9_gateBody",
9320
+ "gateWarning": "s7fd5d3_gateWarning",
9321
+ "gateActions": "sf6b0aa_gateActions",
9322
+ "installing": "sa32b72_installing",
9323
+ "log": "sf9b6a4_log",
9324
+ "logLine": "s9e4d00_logLine",
9325
+ "notice": "s7cd7db_notice",
9326
+ "failedHeading": "sfb1bae_failedHeading",
9327
+ "failedDetail": "s9591b1_failedDetail",
9328
+ "rejectedCode": "saa0605_rejectedCode",
9329
+ "rejectedDetail": "sbd5c7c_rejectedDetail",
9330
+ "outdatedSection": "s7c248d_outdatedSection",
9331
+ "outdatedList": "se144d3_outdatedList",
9332
+ "outdatedRow": "s6fbe58_outdatedRow",
9333
+ "outdatedInfo": "s8af496_outdatedInfo",
9334
+ "outdatedVersions": "sf82d51_outdatedVersions",
9335
+ "shadowedSection": "s31b89a_shadowedSection",
9336
+ "shadowedDetail": "scf838f_shadowedDetail",
9337
+ "outdatedActions": "s109c95_outdatedActions",
9338
+ "switchWrap": "s5c21f4_switchWrap"
9168
9339
  };
9169
9340
  //#endregion
9170
9341
  //#region src/client/ShopTab.tsx
@@ -9181,14 +9352,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9181
9352
  * those nodes, and React's next commit throws on the ones it no longer finds
9182
9353
  * (design 2026-09-26-market-borrowings §4). The tab renders no portals, so its
9183
9354
  * root is its whole surface. */
9184
- const PANEL_ROOT = `${_dsh_plugin_shop_css_e3675a89_default.panel} notranslate`;
9355
+ const PANEL_ROOT = `${_dsh_plugin_shop_css_d74581c2_default.panel} notranslate`;
9185
9356
  function ChevronIcon({ open }) {
9186
9357
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
9187
9358
  viewBox: "0 0 16 16",
9188
9359
  width: "14",
9189
9360
  height: "14",
9190
9361
  "aria-hidden": "true",
9191
- className: open ? _dsh_plugin_shop_css_e3675a89_default.chevronOpen : _dsh_plugin_shop_css_e3675a89_default.chevron,
9362
+ className: open ? _dsh_plugin_shop_css_d74581c2_default.chevronOpen : _dsh_plugin_shop_css_d74581c2_default.chevron,
9192
9363
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
9193
9364
  fill: "currentColor",
9194
9365
  d: "M3.5 6 8 10.5 12.5 6l1 1L8 12.5 2.5 7l1-1Z"
@@ -9201,7 +9372,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9201
9372
  * install controls. An installed plugin's card carries its installed row:
9202
9373
  * current → the non-interactive installed label, behind → the update button;
9203
9374
  * uninstalled → the install button. */
9204
- const EntryCard = (0, react.memo)(function EntryCard({ entry, stars, installed, missing, harness, nameTakenBy, t, flow, uninstallFlow, restart, restartBlocked, reload, setEnabled, inInstalledView, restarts }) {
9375
+ const EntryCard = (0, react.memo)(function EntryCard({ entry, stars, order, shelfDay, installed, missing, harness, nameTakenBy, t, flow, uninstallFlow, restart, restartBlocked, reload, setEnabled, inInstalledView, restarts }) {
9205
9376
  const [open, setOpen] = (0, react.useState)(false);
9206
9377
  const blockers = stateBlockers(blockersOf(missing, harness, nameTakenBy), t);
9207
9378
  const detailId = (0, react.useId)();
@@ -9209,6 +9380,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9209
9380
  const npmUrl = npmPageUrl(entry);
9210
9381
  const author = authorOf(entry);
9211
9382
  const size = formatSize(entry.installSize);
9383
+ const version = versionLabel(entry.source, entry.version);
9384
+ const versionName = t(versionLabelKey(version.kind), { version: version.value });
9212
9385
  const category = entry.catalog?.category ?? "other";
9213
9386
  const installTarget = {
9214
9387
  name: entry.name,
@@ -9218,32 +9391,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9218
9391
  subdir: entry.subdir
9219
9392
  };
9220
9393
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9221
- className: _dsh_plugin_shop_css_e3675a89_default.card,
9394
+ className: _dsh_plugin_shop_css_d74581c2_default.card,
9222
9395
  "data-shop-entry": entry.name,
9223
9396
  "data-category": category,
9224
9397
  children: [
9225
9398
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9226
- className: _dsh_plugin_shop_css_e3675a89_default.cardSpine,
9399
+ className: _dsh_plugin_shop_css_d74581c2_default.cardSpine,
9227
9400
  "aria-hidden": "true"
9228
9401
  }),
9229
9402
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
9230
9403
  type: "button",
9231
- className: _dsh_plugin_shop_css_e3675a89_default.entryHeader,
9404
+ className: _dsh_plugin_shop_css_d74581c2_default.entryHeader,
9232
9405
  "aria-expanded": open,
9233
9406
  "aria-controls": detailId,
9234
9407
  onClick: () => setOpen((current) => !current),
9235
9408
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9236
- className: _dsh_plugin_shop_css_e3675a89_default.name,
9409
+ className: _dsh_plugin_shop_css_d74581c2_default.name,
9237
9410
  children: entry.name
9238
9411
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9239
- className: _dsh_plugin_shop_css_e3675a89_default.badges,
9412
+ className: _dsh_plugin_shop_css_d74581c2_default.badges,
9240
9413
  children: [
9241
9414
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9242
- className: _dsh_plugin_shop_css_e3675a89_default.categoryBadge,
9415
+ className: _dsh_plugin_shop_css_d74581c2_default.categoryBadge,
9243
9416
  children: t(categoryKey(entry))
9244
9417
  }),
9245
9418
  entry.source === "npm" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9246
- className: _dsh_plugin_shop_css_e3675a89_default.sourceBadge,
9419
+ className: _dsh_plugin_shop_css_d74581c2_default.sourceBadge,
9247
9420
  "data-shop-source-npm": true,
9248
9421
  role: "img",
9249
9422
  "aria-label": t("npmSource"),
@@ -9260,7 +9433,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9260
9433
  })
9261
9434
  }),
9262
9435
  hasGithubHome(entry) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9263
- className: _dsh_plugin_shop_css_e3675a89_default.sourceBadge,
9436
+ className: _dsh_plugin_shop_css_d74581c2_default.sourceBadge,
9264
9437
  "data-shop-source-github": true,
9265
9438
  role: "img",
9266
9439
  "aria-label": t("githubSource"),
@@ -9273,23 +9446,26 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9273
9446
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" })
9274
9447
  })
9275
9448
  }),
9276
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9277
- className: _dsh_plugin_shop_css_e3675a89_default.cardVersion,
9449
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9450
+ className: _dsh_plugin_shop_css_d74581c2_default.cardVersion,
9278
9451
  "data-card-version": true,
9279
- children: ["v", displayVersion(entry)]
9452
+ role: "img",
9453
+ "aria-label": versionName,
9454
+ title: versionName,
9455
+ children: version.text
9280
9456
  }),
9281
9457
  entry.tier !== "community" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9282
- className: _dsh_plugin_shop_css_e3675a89_default.tierBadge,
9458
+ className: _dsh_plugin_shop_css_d74581c2_default.tierBadge,
9283
9459
  "data-tier": entry.tier,
9284
9460
  children: t(tierKey(entry.tier))
9285
9461
  }),
9286
9462
  entry.archived === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9287
- className: _dsh_plugin_shop_css_e3675a89_default.tierBadge,
9463
+ className: _dsh_plugin_shop_css_d74581c2_default.tierBadge,
9288
9464
  "data-tier": "archived",
9289
9465
  children: t("archivedBadge")
9290
9466
  }),
9291
9467
  stars !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9292
- className: _dsh_plugin_shop_css_e3675a89_default.starsBadge,
9468
+ className: _dsh_plugin_shop_css_d74581c2_default.starsBadge,
9293
9469
  role: "img",
9294
9470
  "aria-label": t("stars", { count: stars }),
9295
9471
  children: ["★ ", formatStars(stars)]
@@ -9299,39 +9475,39 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9299
9475
  })]
9300
9476
  }),
9301
9477
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9302
- className: _dsh_plugin_shop_css_e3675a89_default.body,
9478
+ className: _dsh_plugin_shop_css_d74581c2_default.body,
9303
9479
  children: [
9304
9480
  summary !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9305
- className: open ? `${_dsh_plugin_shop_css_e3675a89_default.summary} ${_dsh_plugin_shop_css_e3675a89_default.summaryExpanded}` : _dsh_plugin_shop_css_e3675a89_default.summary,
9481
+ className: open ? `${_dsh_plugin_shop_css_d74581c2_default.summary} ${_dsh_plugin_shop_css_d74581c2_default.summaryExpanded}` : _dsh_plugin_shop_css_d74581c2_default.summary,
9306
9482
  children: summary.en
9307
9483
  }),
9308
9484
  summary?.zh !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9309
- className: open ? `${_dsh_plugin_shop_css_e3675a89_default.summaryZh} ${_dsh_plugin_shop_css_e3675a89_default.summaryZhExpanded}` : _dsh_plugin_shop_css_e3675a89_default.summaryZh,
9485
+ className: open ? `${_dsh_plugin_shop_css_d74581c2_default.summaryZh} ${_dsh_plugin_shop_css_d74581c2_default.summaryZhExpanded}` : _dsh_plugin_shop_css_d74581c2_default.summaryZh,
9310
9486
  children: summary.zh
9311
9487
  }),
9312
9488
  blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
9313
9489
  blocker,
9314
- className: _dsh_plugin_shop_css_e3675a89_default.incompatibleDetail,
9490
+ className: _dsh_plugin_shop_css_d74581c2_default.incompatibleDetail,
9315
9491
  surface: "detail"
9316
9492
  }, blocker.kind)),
9317
9493
  open && entry.catalog !== void 0 && entry.catalog.capabilities.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9318
- className: _dsh_plugin_shop_css_e3675a89_default.capabilitiesBlock,
9494
+ className: _dsh_plugin_shop_css_d74581c2_default.capabilitiesBlock,
9319
9495
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9320
- className: _dsh_plugin_shop_css_e3675a89_default.capabilitiesNote,
9496
+ className: _dsh_plugin_shop_css_d74581c2_default.capabilitiesNote,
9321
9497
  children: t("capabilitiesNote")
9322
9498
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
9323
- className: _dsh_plugin_shop_css_e3675a89_default.capabilities,
9499
+ className: _dsh_plugin_shop_css_d74581c2_default.capabilities,
9324
9500
  children: entry.catalog.capabilities.map((capability) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: capability }, capability))
9325
9501
  })]
9326
9502
  }),
9327
9503
  open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
9328
9504
  id: detailId,
9329
- className: _dsh_plugin_shop_css_e3675a89_default.detail,
9505
+ className: _dsh_plugin_shop_css_d74581c2_default.detail,
9330
9506
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
9331
- className: _dsh_plugin_shop_css_e3675a89_default.detailRows,
9507
+ className: _dsh_plugin_shop_css_d74581c2_default.detailRows,
9332
9508
  children: [
9333
9509
  npmUrl !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9334
- className: _dsh_plugin_shop_css_e3675a89_default.detailRow,
9510
+ className: _dsh_plugin_shop_css_d74581c2_default.detailRow,
9335
9511
  "data-shop-npm": true,
9336
9512
  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", {
9337
9513
  href: npmUrl,
@@ -9341,7 +9517,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9341
9517
  }) })]
9342
9518
  }),
9343
9519
  entry.repository !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9344
- className: _dsh_plugin_shop_css_e3675a89_default.detailRow,
9520
+ className: _dsh_plugin_shop_css_d74581c2_default.detailRow,
9345
9521
  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", {
9346
9522
  href: entry.repository,
9347
9523
  target: "_blank",
@@ -9350,25 +9526,25 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9350
9526
  }) : entry.repository })]
9351
9527
  }),
9352
9528
  entry.license !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9353
- className: _dsh_plugin_shop_css_e3675a89_default.detailRow,
9529
+ className: _dsh_plugin_shop_css_d74581c2_default.detailRow,
9354
9530
  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 })]
9355
9531
  })
9356
9532
  ]
9357
9533
  }), entry.tier === "verified-stale" && entry.review !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9358
- className: _dsh_plugin_shop_css_e3675a89_default.reviewedLine,
9534
+ className: _dsh_plugin_shop_css_d74581c2_default.reviewedLine,
9359
9535
  children: entry.review.reviewedVersion !== void 0 ? t("reviewedVersionLine", {
9360
- reviewed: entry.review.reviewedVersion,
9361
- current: entry.version
9536
+ reviewed: versionLabel("npm", entry.review.reviewedVersion).text,
9537
+ current: version.text
9362
9538
  }) : t("reviewedPinLine", {
9363
9539
  pin: reviewHashPin(entry.review),
9364
- current: displayVersion(entry)
9540
+ current: version.text
9365
9541
  })
9366
9542
  })]
9367
9543
  })
9368
9544
  ]
9369
9545
  }),
9370
9546
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9371
- className: _dsh_plugin_shop_css_e3675a89_default.cardActions,
9547
+ className: _dsh_plugin_shop_css_d74581c2_default.cardActions,
9372
9548
  "data-shop-actions": true,
9373
9549
  children: [installed === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [!inInstalledView && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstallPanel, {
9374
9550
  target: installTarget,
@@ -9400,7 +9576,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9400
9576
  restartBlocked,
9401
9577
  reload
9402
9578
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9403
- className: _dsh_plugin_shop_css_e3675a89_default.installedLabel,
9579
+ className: _dsh_plugin_shop_css_d74581c2_default.installedLabel,
9404
9580
  "data-shop-installed": true,
9405
9581
  children: t("installed")
9406
9582
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerBadge, {
@@ -9424,20 +9600,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9424
9600
  reload,
9425
9601
  flow: uninstallFlow
9426
9602
  })
9427
- ] }), (size !== void 0 || author !== null) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9428
- className: _dsh_plugin_shop_css_e3675a89_default.cardMeta,
9429
- children: [size !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9430
- className: _dsh_plugin_shop_css_e3675a89_default.size,
9431
- "data-shop-size": true,
9432
- role: "img",
9433
- "aria-label": t("sizeLabel", { size }),
9434
- title: t("sizeLabel", { size }),
9435
- children: size
9436
- }), author !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9437
- className: _dsh_plugin_shop_css_e3675a89_default.author,
9438
- "data-shop-author": true,
9439
- children: t("authorLine", { author })
9440
- })]
9603
+ ] }), (size !== void 0 || author !== null || shelfDay !== void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
9604
+ className: _dsh_plugin_shop_css_d74581c2_default.cardMeta,
9605
+ children: [
9606
+ shelfDay !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9607
+ className: _dsh_plugin_shop_css_d74581c2_default.shelfDate,
9608
+ "data-shop-shelf-date": true,
9609
+ children: t(order === "added" ? "listedOn" : "updatedOn", { date: shelfDay })
9610
+ }),
9611
+ size !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9612
+ className: _dsh_plugin_shop_css_d74581c2_default.size,
9613
+ "data-shop-size": true,
9614
+ role: "img",
9615
+ "aria-label": t("sizeLabel", { size }),
9616
+ title: t("sizeLabel", { size }),
9617
+ children: size
9618
+ }),
9619
+ author !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9620
+ className: _dsh_plugin_shop_css_d74581c2_default.author,
9621
+ "data-shop-author": true,
9622
+ children: t("authorLine", { author })
9623
+ })
9624
+ ]
9441
9625
  })]
9442
9626
  })
9443
9627
  ]
@@ -9483,13 +9667,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9483
9667
  ...attribute,
9484
9668
  children: blocker.text
9485
9669
  }), blocker.remedy !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9486
- className: _dsh_plugin_shop_css_e3675a89_default.remedy,
9670
+ className: _dsh_plugin_shop_css_d74581c2_default.remedy,
9487
9671
  "data-shop-remedy": blocker.kind,
9488
9672
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9489
- className: _dsh_plugin_shop_css_e3675a89_default.remedyLead,
9673
+ className: _dsh_plugin_shop_css_d74581c2_default.remedyLead,
9490
9674
  children: blocker.remedy.lead
9491
9675
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
9492
- className: _dsh_plugin_shop_css_e3675a89_default.allowCommand,
9676
+ className: _dsh_plugin_shop_css_d74581c2_default.allowCommand,
9493
9677
  "data-shop-allow-command": true,
9494
9678
  children: blocker.remedy.command
9495
9679
  })]
@@ -9527,7 +9711,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9527
9711
  if (lead === void 0 || word === null) return null;
9528
9712
  const detail = blockers.map((blocker) => blocker.text).join("\n");
9529
9713
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
9530
- className: _dsh_plugin_shop_css_e3675a89_default.incompatibleBadge,
9714
+ className: _dsh_plugin_shop_css_d74581c2_default.incompatibleBadge,
9531
9715
  "data-shop-blocker": lead.kind,
9532
9716
  role: "img",
9533
9717
  "aria-label": detail,
@@ -9544,37 +9728,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9544
9728
  const [gateOpen, setGateOpen] = (0, react.useState)(false);
9545
9729
  const { view, start } = flow;
9546
9730
  if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9547
- className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
9731
+ className: _dsh_plugin_shop_css_d74581c2_default.installPanel,
9548
9732
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9549
- className: _dsh_plugin_shop_css_e3675a89_default.installing,
9733
+ className: _dsh_plugin_shop_css_d74581c2_default.installing,
9550
9734
  children: t(installPhaseKey(view.phase))
9551
9735
  }), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9552
- className: _dsh_plugin_shop_css_e3675a89_default.log,
9736
+ className: _dsh_plugin_shop_css_d74581c2_default.log,
9553
9737
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9554
- className: _dsh_plugin_shop_css_e3675a89_default.logLine,
9738
+ className: _dsh_plugin_shop_css_d74581c2_default.logLine,
9555
9739
  "data-shop-log-line": true,
9556
9740
  children: line
9557
9741
  }, index))
9558
9742
  })]
9559
9743
  });
9560
9744
  if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9561
- className: _dsh_plugin_shop_css_e3675a89_default.installedActions,
9745
+ className: _dsh_plugin_shop_css_d74581c2_default.installedActions,
9562
9746
  children: [
9563
9747
  view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9564
- className: _dsh_plugin_shop_css_e3675a89_default.log,
9748
+ className: _dsh_plugin_shop_css_d74581c2_default.log,
9565
9749
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9566
- className: _dsh_plugin_shop_css_e3675a89_default.logLine,
9750
+ className: _dsh_plugin_shop_css_d74581c2_default.logLine,
9567
9751
  "data-shop-log-line": true,
9568
9752
  children: line
9569
9753
  }, index))
9570
9754
  }),
9571
9755
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9572
- className: _dsh_plugin_shop_css_e3675a89_default.notice,
9756
+ className: _dsh_plugin_shop_css_d74581c2_default.notice,
9573
9757
  "data-shop-restart-notice": true,
9574
9758
  children: t(activationNoticeKey(view.activation, view.restartReason))
9575
9759
  }),
9576
9760
  view.detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9577
- className: _dsh_plugin_shop_css_e3675a89_default.notice,
9761
+ className: _dsh_plugin_shop_css_d74581c2_default.notice,
9578
9762
  "data-shop-done-note": true,
9579
9763
  children: view.detail
9580
9764
  }),
@@ -9589,57 +9773,57 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9589
9773
  ]
9590
9774
  });
9591
9775
  if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9592
- className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
9776
+ className: _dsh_plugin_shop_css_d74581c2_default.installPanel,
9593
9777
  children: [
9594
9778
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9595
- className: _dsh_plugin_shop_css_e3675a89_default.failedHeading,
9779
+ className: _dsh_plugin_shop_css_d74581c2_default.failedHeading,
9596
9780
  children: t("installFailed")
9597
9781
  }),
9598
9782
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9599
- className: _dsh_plugin_shop_css_e3675a89_default.log,
9783
+ className: _dsh_plugin_shop_css_d74581c2_default.log,
9600
9784
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9601
- className: _dsh_plugin_shop_css_e3675a89_default.logLine,
9785
+ className: _dsh_plugin_shop_css_d74581c2_default.logLine,
9602
9786
  "data-shop-log-line": true,
9603
9787
  children: line
9604
9788
  }, index))
9605
9789
  }),
9606
9790
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9607
- className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
9791
+ className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
9608
9792
  children: view.detail === "" ? t("installTransportFailed") : view.detail
9609
9793
  })
9610
9794
  ]
9611
9795
  });
9612
9796
  if (view.kind === "rejected") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9613
- className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
9797
+ className: _dsh_plugin_shop_css_d74581c2_default.installPanel,
9614
9798
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9615
- className: _dsh_plugin_shop_css_e3675a89_default.rejectedCode,
9799
+ className: _dsh_plugin_shop_css_d74581c2_default.rejectedCode,
9616
9800
  children: t(rejectionCodeKey(view.code))
9617
9801
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9618
- className: _dsh_plugin_shop_css_e3675a89_default.rejectedDetail,
9802
+ className: _dsh_plugin_shop_css_d74581c2_default.rejectedDetail,
9619
9803
  children: view.detail
9620
9804
  })]
9621
9805
  });
9622
9806
  if (gateOpen) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9623
- className: _dsh_plugin_shop_css_e3675a89_default.gate,
9807
+ className: _dsh_plugin_shop_css_d74581c2_default.gate,
9624
9808
  children: [
9625
9809
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9626
- className: _dsh_plugin_shop_css_e3675a89_default.gateTitle,
9810
+ className: _dsh_plugin_shop_css_d74581c2_default.gateTitle,
9627
9811
  children: t("acknowledgementTitle")
9628
9812
  }),
9629
9813
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9630
- className: _dsh_plugin_shop_css_e3675a89_default.gateBody,
9814
+ className: _dsh_plugin_shop_css_d74581c2_default.gateBody,
9631
9815
  children: t("acknowledgementBody")
9632
9816
  }),
9633
9817
  !blockersStated && blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
9634
9818
  blocker,
9635
- className: _dsh_plugin_shop_css_e3675a89_default.gateWarning,
9819
+ className: _dsh_plugin_shop_css_d74581c2_default.gateWarning,
9636
9820
  surface: "warning"
9637
9821
  }, blocker.kind)),
9638
9822
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9639
- className: _dsh_plugin_shop_css_e3675a89_default.gateActions,
9823
+ className: _dsh_plugin_shop_css_d74581c2_default.gateActions,
9640
9824
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9641
9825
  type: "button",
9642
- className: _dsh_plugin_shop_css_e3675a89_default.confirmButton,
9826
+ className: _dsh_plugin_shop_css_d74581c2_default.confirmButton,
9643
9827
  "data-shop-confirm": true,
9644
9828
  onClick: () => {
9645
9829
  setGateOpen(false);
@@ -9651,7 +9835,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9651
9835
  children: t("confirm")
9652
9836
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9653
9837
  type: "button",
9654
- className: _dsh_plugin_shop_css_e3675a89_default.cancelButton,
9838
+ className: _dsh_plugin_shop_css_d74581c2_default.cancelButton,
9655
9839
  onClick: () => setGateOpen(false),
9656
9840
  children: t("cancel")
9657
9841
  })]
@@ -9663,7 +9847,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9663
9847
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
9664
9848
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9665
9849
  type: "button",
9666
- className: _dsh_plugin_shop_css_e3675a89_default.installButton,
9850
+ className: _dsh_plugin_shop_css_d74581c2_default.installButton,
9667
9851
  disabled: refused,
9668
9852
  ...refused ? { "data-shop-refused": true } : {},
9669
9853
  ...update ? { "data-shop-update": true } : { "data-shop-install": true },
@@ -9681,11 +9865,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9681
9865
  t
9682
9866
  }),
9683
9867
  refused && !blockersStated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9684
- className: _dsh_plugin_shop_css_e3675a89_default.refusal,
9868
+ className: _dsh_plugin_shop_css_d74581c2_default.refusal,
9685
9869
  "data-shop-refusal": true,
9686
9870
  children: blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
9687
9871
  blocker,
9688
- className: _dsh_plugin_shop_css_e3675a89_default.gateWarning,
9872
+ className: _dsh_plugin_shop_css_d74581c2_default.gateWarning,
9689
9873
  surface: "warning"
9690
9874
  }, blocker.kind))
9691
9875
  })
@@ -9700,32 +9884,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9700
9884
  function UninstallPanel({ name, t, restart, restartBlocked, reload, flow }) {
9701
9885
  const { view, start, reset } = flow;
9702
9886
  if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9703
- className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
9887
+ className: _dsh_plugin_shop_css_d74581c2_default.installPanel,
9704
9888
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9705
- className: _dsh_plugin_shop_css_e3675a89_default.installing,
9889
+ className: _dsh_plugin_shop_css_d74581c2_default.installing,
9706
9890
  children: t("uninstalling")
9707
9891
  }), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9708
- className: _dsh_plugin_shop_css_e3675a89_default.log,
9892
+ className: _dsh_plugin_shop_css_d74581c2_default.log,
9709
9893
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9710
- className: _dsh_plugin_shop_css_e3675a89_default.logLine,
9894
+ className: _dsh_plugin_shop_css_d74581c2_default.logLine,
9711
9895
  "data-shop-log-line": true,
9712
9896
  children: line
9713
9897
  }, index))
9714
9898
  })]
9715
9899
  });
9716
9900
  if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9717
- className: _dsh_plugin_shop_css_e3675a89_default.installedActions,
9901
+ className: _dsh_plugin_shop_css_d74581c2_default.installedActions,
9718
9902
  children: [
9719
9903
  view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9720
- className: _dsh_plugin_shop_css_e3675a89_default.log,
9904
+ className: _dsh_plugin_shop_css_d74581c2_default.log,
9721
9905
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9722
- className: _dsh_plugin_shop_css_e3675a89_default.logLine,
9906
+ className: _dsh_plugin_shop_css_d74581c2_default.logLine,
9723
9907
  "data-shop-log-line": true,
9724
9908
  children: line
9725
9909
  }, index))
9726
9910
  }),
9727
9911
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9728
- className: _dsh_plugin_shop_css_e3675a89_default.notice,
9912
+ className: _dsh_plugin_shop_css_d74581c2_default.notice,
9729
9913
  "data-shop-uninstall-done": true,
9730
9914
  children: t(uninstallActivationNoticeKey(view.activation))
9731
9915
  }),
@@ -9739,7 +9923,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9739
9923
  }),
9740
9924
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9741
9925
  type: "button",
9742
- className: _dsh_plugin_shop_css_e3675a89_default.cancelButton,
9926
+ className: _dsh_plugin_shop_css_d74581c2_default.cancelButton,
9743
9927
  "data-shop-uninstall-dismiss": true,
9744
9928
  onClick: reset,
9745
9929
  children: t("dismiss")
@@ -9747,27 +9931,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9747
9931
  ]
9748
9932
  });
9749
9933
  if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9750
- className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
9934
+ className: _dsh_plugin_shop_css_d74581c2_default.installPanel,
9751
9935
  children: [
9752
9936
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9753
- className: _dsh_plugin_shop_css_e3675a89_default.failedHeading,
9937
+ className: _dsh_plugin_shop_css_d74581c2_default.failedHeading,
9754
9938
  children: t("uninstallFailed")
9755
9939
  }),
9756
9940
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9757
- className: _dsh_plugin_shop_css_e3675a89_default.log,
9941
+ className: _dsh_plugin_shop_css_d74581c2_default.log,
9758
9942
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9759
- className: _dsh_plugin_shop_css_e3675a89_default.logLine,
9943
+ className: _dsh_plugin_shop_css_d74581c2_default.logLine,
9760
9944
  "data-shop-log-line": true,
9761
9945
  children: line
9762
9946
  }, index))
9763
9947
  }),
9764
9948
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9765
- className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
9949
+ className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
9766
9950
  children: view.detail === "" ? t("uninstallTransportFailed") : view.detail
9767
9951
  }),
9768
9952
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9769
9953
  type: "button",
9770
- className: _dsh_plugin_shop_css_e3675a89_default.uninstallButton,
9954
+ className: _dsh_plugin_shop_css_d74581c2_default.uninstallButton,
9771
9955
  "data-shop-uninstall-retry": true,
9772
9956
  onClick: () => void start({ name }),
9773
9957
  children: t("retry")
@@ -9777,7 +9961,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9777
9961
  if (view.kind !== "idle") return null;
9778
9962
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9779
9963
  type: "button",
9780
- className: _dsh_plugin_shop_css_e3675a89_default.uninstallButton,
9964
+ className: _dsh_plugin_shop_css_d74581c2_default.uninstallButton,
9781
9965
  "data-shop-uninstall": true,
9782
9966
  onClick: () => void start({ name }),
9783
9967
  children: t("uninstall")
@@ -9818,38 +10002,38 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9818
10002
  else if (outcome.kind === "unreachable") setRefusal(t("restartTransportFailed"));
9819
10003
  };
9820
10004
  if (monitor?.kind === "requesting" || monitor?.kind === "restarting") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9821
- className: _dsh_plugin_shop_css_e3675a89_default.notice,
10005
+ className: _dsh_plugin_shop_css_d74581c2_default.notice,
9822
10006
  "data-shop-restarting": true,
9823
10007
  children: t("restarting")
9824
10008
  });
9825
10009
  if (monitor?.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9826
- className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
10010
+ className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
9827
10011
  "data-shop-restart-error": true,
9828
10012
  children: monitor.logFile === void 0 ? t("restartFailedNotice") : t("restartFailedLogNotice", { log: monitor.logFile })
9829
10013
  });
9830
10014
  if (monitor?.kind === "not-restarted") return null;
9831
10015
  if (gateOpen) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9832
- className: _dsh_plugin_shop_css_e3675a89_default.gate,
10016
+ className: _dsh_plugin_shop_css_d74581c2_default.gate,
9833
10017
  children: [
9834
10018
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9835
- className: _dsh_plugin_shop_css_e3675a89_default.gateTitle,
10019
+ className: _dsh_plugin_shop_css_d74581c2_default.gateTitle,
9836
10020
  children: t("restartTitle")
9837
10021
  }),
9838
10022
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9839
- className: _dsh_plugin_shop_css_e3675a89_default.gateBody,
10023
+ className: _dsh_plugin_shop_css_d74581c2_default.gateBody,
9840
10024
  children: t("restartBody")
9841
10025
  }),
9842
10026
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9843
- className: _dsh_plugin_shop_css_e3675a89_default.gateActions,
10027
+ className: _dsh_plugin_shop_css_d74581c2_default.gateActions,
9844
10028
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9845
10029
  type: "button",
9846
- className: _dsh_plugin_shop_css_e3675a89_default.confirmButton,
10030
+ className: _dsh_plugin_shop_css_d74581c2_default.confirmButton,
9847
10031
  "data-shop-restart-confirm": true,
9848
10032
  onClick: () => void onConfirm(),
9849
10033
  children: t("restartConfirm")
9850
10034
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9851
10035
  type: "button",
9852
- className: _dsh_plugin_shop_css_e3675a89_default.cancelButton,
10036
+ className: _dsh_plugin_shop_css_d74581c2_default.cancelButton,
9853
10037
  onClick: () => setGateOpen(false),
9854
10038
  children: t("cancel")
9855
10039
  })]
@@ -9857,14 +10041,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9857
10041
  ]
9858
10042
  });
9859
10043
  const refused = refusal === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9860
- className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
10044
+ className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
9861
10045
  "data-shop-restart-error": true,
9862
10046
  children: refusal
9863
10047
  });
9864
10048
  if (gate !== void 0) return refused;
9865
10049
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [refused, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9866
10050
  type: "button",
9867
- className: _dsh_plugin_shop_css_e3675a89_default.restartButton,
10051
+ className: _dsh_plugin_shop_css_d74581c2_default.restartButton,
9868
10052
  "data-shop-restart": true,
9869
10053
  onClick: () => setGateOpen(true),
9870
10054
  children: t("restart")
@@ -9882,13 +10066,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9882
10066
  */
9883
10067
  function NotRestartedNotice({ t, pid, logFile }) {
9884
10068
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9885
- className: _dsh_plugin_shop_css_e3675a89_default.selfUpdatePanel,
10069
+ className: _dsh_plugin_shop_css_d74581c2_default.selfUpdatePanel,
9886
10070
  "data-shop-not-restarted": true,
9887
10071
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9888
- className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
10072
+ className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
9889
10073
  children: pid === void 0 ? t("notRestartedNotice") : t("notRestartedPidNotice", { pid: String(pid) })
9890
10074
  }), logFile !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9891
- className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
10075
+ className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
9892
10076
  children: t("notRestartedLogNotice", { log: logFile })
9893
10077
  })]
9894
10078
  });
@@ -9918,7 +10102,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9918
10102
  restart,
9919
10103
  reload
9920
10104
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9921
- className: _dsh_plugin_shop_css_e3675a89_default.notice,
10105
+ className: _dsh_plugin_shop_css_d74581c2_default.notice,
9922
10106
  "data-shop-restart-disabled": true,
9923
10107
  children: t(restartBlockedNoticeKey(restartBlocked))
9924
10108
  });
@@ -9929,14 +10113,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9929
10113
  * would help without knowing that now is a good time. */
9930
10114
  function ReloadPanel({ t, reload, where }) {
9931
10115
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9932
- className: _dsh_plugin_shop_css_e3675a89_default.reloadPanel,
10116
+ className: _dsh_plugin_shop_css_d74581c2_default.reloadPanel,
9933
10117
  "data-shop-reload": where,
9934
10118
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
9935
- className: _dsh_plugin_shop_css_e3675a89_default.notice,
10119
+ className: _dsh_plugin_shop_css_d74581c2_default.notice,
9936
10120
  children: t("reloadNote")
9937
10121
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9938
10122
  type: "button",
9939
- className: _dsh_plugin_shop_css_e3675a89_default.reloadButton,
10123
+ className: _dsh_plugin_shop_css_d74581c2_default.reloadButton,
9940
10124
  onClick: reload,
9941
10125
  children: t("reload")
9942
10126
  })]
@@ -9987,7 +10171,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9987
10171
  }
9988
10172
  };
9989
10173
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9990
- className: _dsh_plugin_shop_css_e3675a89_default.switchWrap,
10174
+ className: _dsh_plugin_shop_css_d74581c2_default.switchWrap,
9991
10175
  "data-shop-enabled-switch": row.name,
9992
10176
  children: [
9993
10177
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
@@ -9996,18 +10180,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
9996
10180
  "aria-checked": enabled,
9997
10181
  "aria-label": t("enabledSwitch"),
9998
10182
  "data-shop-toggle": true,
9999
- className: `${_dsh_plugin_shop_css_e3675a89_default.switch} ${enabled ? _dsh_plugin_shop_css_e3675a89_default.switchOn : ""}`,
10183
+ className: `${_dsh_plugin_shop_css_d74581c2_default.switch} ${enabled ? _dsh_plugin_shop_css_d74581c2_default.switchOn : ""}`,
10000
10184
  onClick: () => void onToggle(),
10001
10185
  disabled: toggle.kind === "saving",
10002
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.switchKnob })
10186
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.switchKnob })
10003
10187
  }),
10004
10188
  toggle.kind === "saved" && owed === "nothing" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10005
- className: _dsh_plugin_shop_css_e3675a89_default.notice,
10189
+ className: _dsh_plugin_shop_css_d74581c2_default.notice,
10006
10190
  "data-shop-hot-apply": true,
10007
10191
  children: t("hotApplyNote")
10008
10192
  }),
10009
10193
  owed === "restart" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10010
- className: _dsh_plugin_shop_css_e3675a89_default.notice,
10194
+ className: _dsh_plugin_shop_css_d74581c2_default.notice,
10011
10195
  "data-shop-toggle-restart": true,
10012
10196
  children: t("toggleRestartNote")
10013
10197
  }),
@@ -10020,7 +10204,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10020
10204
  where: "toggle"
10021
10205
  }),
10022
10206
  toggle.kind === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10023
- className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
10207
+ className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
10024
10208
  "data-shop-toggle-error": true,
10025
10209
  children: toggle.detail
10026
10210
  })
@@ -10035,19 +10219,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10035
10219
  * field is narrowed at the parameter. */
10036
10220
  function OutdatedRow({ row, tier, missing, harness, t, setEnabled, flowFor, restart, restartBlocked, reload, restarts }) {
10037
10221
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10038
- className: _dsh_plugin_shop_css_e3675a89_default.outdatedRow,
10222
+ className: _dsh_plugin_shop_css_d74581c2_default.outdatedRow,
10039
10223
  "data-shop-outdated-entry": row.name,
10040
10224
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10041
- className: _dsh_plugin_shop_css_e3675a89_default.outdatedInfo,
10225
+ className: _dsh_plugin_shop_css_d74581c2_default.outdatedInfo,
10042
10226
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10043
- className: _dsh_plugin_shop_css_e3675a89_default.name,
10227
+ className: _dsh_plugin_shop_css_d74581c2_default.name,
10044
10228
  children: row.name
10045
10229
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
10046
- className: _dsh_plugin_shop_css_e3675a89_default.outdatedVersions,
10047
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("installedVersion", { version: row.source === "github" ? row.installed.slice(0, 7) : row.installed }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("latestVersion", { version: row.latest }) })]
10230
+ className: _dsh_plugin_shop_css_d74581c2_default.outdatedVersions,
10231
+ 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 }) })]
10048
10232
  })]
10049
10233
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10050
- className: _dsh_plugin_shop_css_e3675a89_default.outdatedActions,
10234
+ className: _dsh_plugin_shop_css_d74581c2_default.outdatedActions,
10051
10235
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EnabledSwitch, {
10052
10236
  row,
10053
10237
  t,
@@ -10096,22 +10280,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10096
10280
  function OutdatedSection({ state, entriesByKey, missingByKey, harnessVerdicts, t, setEnabled, flowFor, restart, restartBlocked, reload, restarts }) {
10097
10281
  if (state.kind === "loading") return null;
10098
10282
  if (state.kind === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10099
- className: _dsh_plugin_shop_css_e3675a89_default.stateLine,
10283
+ className: _dsh_plugin_shop_css_d74581c2_default.stateLine,
10100
10284
  "data-shop-outdated-error": true,
10101
10285
  children: t("installedError")
10102
10286
  });
10103
10287
  const outdated = state.entries.filter((entry) => entry.outdated && entry.latest !== null);
10104
10288
  if (outdated.length === 0) return null;
10105
10289
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
10106
- className: _dsh_plugin_shop_css_e3675a89_default.outdatedSection,
10290
+ className: _dsh_plugin_shop_css_d74581c2_default.outdatedSection,
10107
10291
  "data-shop-outdated": true,
10108
10292
  "aria-labelledby": UPDATABLE_HEADING_ID,
10109
10293
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
10110
- className: _dsh_plugin_shop_css_e3675a89_default.updatableHeading,
10294
+ className: _dsh_plugin_shop_css_d74581c2_default.updatableHeading,
10111
10295
  id: UPDATABLE_HEADING_ID,
10112
10296
  children: t("updatableSection")
10113
10297
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
10114
- className: _dsh_plugin_shop_css_e3675a89_default.outdatedList,
10298
+ className: _dsh_plugin_shop_css_d74581c2_default.outdatedList,
10115
10299
  children: outdated.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutdatedRow, {
10116
10300
  row,
10117
10301
  tier: entriesByKey.get(identityKey(row))?.tier ?? "community",
@@ -10139,37 +10323,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10139
10323
  const shadowed = entries.filter((entry) => entry.shadowed === true);
10140
10324
  if (shadowed.length === 0) return null;
10141
10325
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
10142
- className: _dsh_plugin_shop_css_e3675a89_default.shadowedSection,
10326
+ className: _dsh_plugin_shop_css_d74581c2_default.shadowedSection,
10143
10327
  "data-shop-shadowed": true,
10144
10328
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
10145
- className: _dsh_plugin_shop_css_e3675a89_default.outdatedList,
10329
+ className: _dsh_plugin_shop_css_d74581c2_default.outdatedList,
10146
10330
  children: shadowed.map((row) => {
10147
10331
  const key = identityKey(row);
10148
10332
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10149
- className: _dsh_plugin_shop_css_e3675a89_default.outdatedRow,
10333
+ className: _dsh_plugin_shop_css_d74581c2_default.outdatedRow,
10150
10334
  "data-shop-shadowed-entry": row.name,
10151
10335
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10152
- className: _dsh_plugin_shop_css_e3675a89_default.outdatedInfo,
10336
+ className: _dsh_plugin_shop_css_d74581c2_default.outdatedInfo,
10153
10337
  children: [
10154
10338
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10155
- className: _dsh_plugin_shop_css_e3675a89_default.name,
10339
+ className: _dsh_plugin_shop_css_d74581c2_default.name,
10156
10340
  children: row.name
10157
10341
  }),
10158
10342
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10159
- className: _dsh_plugin_shop_css_e3675a89_default.badges,
10343
+ className: _dsh_plugin_shop_css_d74581c2_default.badges,
10160
10344
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10161
- className: _dsh_plugin_shop_css_e3675a89_default.tierBadge,
10345
+ className: _dsh_plugin_shop_css_d74581c2_default.tierBadge,
10162
10346
  "data-tier": "shadowed",
10163
10347
  children: t("shadowedBadge")
10164
10348
  })
10165
10349
  }),
10166
10350
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10167
- className: _dsh_plugin_shop_css_e3675a89_default.shadowedDetail,
10351
+ className: _dsh_plugin_shop_css_d74581c2_default.shadowedDetail,
10168
10352
  children: t("shadowedDetail")
10169
10353
  })
10170
10354
  ]
10171
10355
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10172
- className: _dsh_plugin_shop_css_e3675a89_default.outdatedActions,
10356
+ className: _dsh_plugin_shop_css_d74581c2_default.outdatedActions,
10173
10357
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UninstallPanel, {
10174
10358
  name: row.name,
10175
10359
  t,
@@ -10219,16 +10403,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10219
10403
  role: "alert",
10220
10404
  children: [
10221
10405
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10222
- className: _dsh_plugin_shop_css_e3675a89_default.stateLine,
10406
+ className: _dsh_plugin_shop_css_d74581c2_default.stateLine,
10223
10407
  children: say("tabCrashed", en.tabCrashed)
10224
10408
  }),
10225
10409
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10226
- className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
10410
+ className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
10227
10411
  children: error.message
10228
10412
  }),
10229
10413
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
10230
10414
  type: "button",
10231
- className: _dsh_plugin_shop_css_e3675a89_default.actionButton,
10415
+ className: _dsh_plugin_shop_css_d74581c2_default.actionButton,
10232
10416
  onClick: () => this.setState({ error: null }),
10233
10417
  children: say("retry", en.retry)
10234
10418
  })
@@ -10315,11 +10499,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10315
10499
  const [reloadFailed, setReloadFailed] = (0, react.useState)(false);
10316
10500
  const [query, setQuery] = (0, react.useState)("");
10317
10501
  const [category, setCategory] = (0, react.useState)(null);
10502
+ const [order, setOrder] = (0, react.useState)("stars");
10318
10503
  const [hideIncompatible, setHideIncompatible] = (0, react.useState)(false);
10319
10504
  const incremental = typeof IntersectionObserver !== "undefined";
10320
10505
  const [visibleCount, setVisibleCount] = (0, react.useState)(48);
10321
10506
  const sentinelRef = (0, react.useRef)(null);
10322
10507
  const filteredLenRef = (0, react.useRef)(0);
10508
+ const sortLabelId = (0, react.useId)();
10323
10509
  const pendingRefreshRef = (0, react.useRef)(null);
10324
10510
  (0, react.useEffect)(() => {
10325
10511
  let cancelled = false;
@@ -10414,7 +10600,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10414
10600
  return map;
10415
10601
  }, [installedState]);
10416
10602
  const stars = (0, react.useMemo)(() => catalogState.kind === "ready" ? catalogState.result.stars : {}, [catalogState]);
10417
- const sortedCatalog = (0, react.useMemo)(() => catalogState.kind === "ready" ? sortByStars(catalogState.result.plugins, stars) : [], [catalogState, stars]);
10603
+ const starOrder = (0, react.useMemo)(() => catalogState.kind === "ready" ? sortByStars(catalogState.result.plugins, stars) : [], [catalogState, stars]);
10604
+ const builtAt = catalogState.kind === "ready" ? catalogState.result.builtAt : "";
10605
+ const sortedCatalog = (0, react.useMemo)(() => orderShelf(starOrder, order, builtAt), [
10606
+ starOrder,
10607
+ order,
10608
+ builtAt
10609
+ ]);
10418
10610
  const browsable = (0, react.useMemo)(() => {
10419
10611
  if (catalogState.kind !== "ready") return [];
10420
10612
  const cleared = new Set(catalogState.result.notAShop ?? []);
@@ -10487,6 +10679,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10487
10679
  filtered.length
10488
10680
  ]);
10489
10681
  const visible = incremental ? filtered.slice(0, visibleCount) : filtered;
10682
+ /** The date a card shows under the current order, or undefined under the
10683
+ * star order and for an entry with no usable date. Computed from the same
10684
+ * `shelfTime` the order keyed on, so a label can never name a date the
10685
+ * order ignored. */
10686
+ const shelfDayOf = (entry) => {
10687
+ const ms = shelfTime(entry, order, builtAt);
10688
+ return ms === void 0 ? void 0 : utcDay(ms);
10689
+ };
10490
10690
  const categoryCounts = (0, react.useMemo)(() => {
10491
10691
  const counts = /* @__PURE__ */ new Map();
10492
10692
  for (const entry of browsable) {
@@ -10509,19 +10709,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10509
10709
  "data-shop-tab": true,
10510
10710
  "aria-busy": "true",
10511
10711
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10512
- className: _dsh_plugin_shop_css_e3675a89_default.srOnly,
10712
+ className: _dsh_plugin_shop_css_d74581c2_default.srOnly,
10513
10713
  children: t("loading")
10514
10714
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10515
- className: _dsh_plugin_shop_css_e3675a89_default.skeletonGrid,
10715
+ className: _dsh_plugin_shop_css_d74581c2_default.skeletonGrid,
10516
10716
  "data-shop-skeleton": true,
10517
10717
  "aria-hidden": "true",
10518
10718
  children: Array.from({ length: 8 }, (_, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10519
- className: _dsh_plugin_shop_css_e3675a89_default.skeletonCard,
10719
+ className: _dsh_plugin_shop_css_d74581c2_default.skeletonCard,
10520
10720
  children: [
10521
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonName }),
10522
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonSummary }),
10523
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonSummaryShort }),
10524
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonActions })
10721
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.skeletonName }),
10722
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.skeletonSummary }),
10723
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.skeletonSummaryShort }),
10724
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.skeletonActions })
10525
10725
  ]
10526
10726
  }, i))
10527
10727
  })]
@@ -10531,11 +10731,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10531
10731
  translate: "no",
10532
10732
  "data-shop-tab": true,
10533
10733
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10534
- className: _dsh_plugin_shop_css_e3675a89_default.stateLine,
10734
+ className: _dsh_plugin_shop_css_d74581c2_default.stateLine,
10535
10735
  children: t("error")
10536
10736
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
10537
10737
  type: "button",
10538
- className: _dsh_plugin_shop_css_e3675a89_default.actionButton,
10738
+ className: _dsh_plugin_shop_css_d74581c2_default.actionButton,
10539
10739
  onClick: () => {
10540
10740
  setRequest({ kind: "retry" });
10541
10741
  setVersionReload((current) => current + 1);
@@ -10550,11 +10750,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10550
10750
  "data-shop-tab": true,
10551
10751
  children: [
10552
10752
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10553
- className: _dsh_plugin_shop_css_e3675a89_default.toolbar,
10753
+ className: _dsh_plugin_shop_css_d74581c2_default.toolbar,
10554
10754
  children: [
10555
10755
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
10556
10756
  type: "search",
10557
- className: _dsh_plugin_shop_css_e3675a89_default.searchInput,
10757
+ className: _dsh_plugin_shop_css_d74581c2_default.searchInput,
10558
10758
  "aria-label": t("search"),
10559
10759
  placeholder: t("search"),
10560
10760
  value: query,
@@ -10565,31 +10765,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10565
10765
  }),
10566
10766
  expansionMemo.intents.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10567
10767
  "data-shop-expansion-note": true,
10568
- className: _dsh_plugin_shop_css_e3675a89_default.expansionNote,
10768
+ className: _dsh_plugin_shop_css_d74581c2_default.expansionNote,
10569
10769
  children: t("zhExpansionNote", { terms: expansionMemo.terms.slice(1).map((term) => term.startsWith("#") ? term.slice(1) : term).join(", ") })
10570
10770
  }),
10571
10771
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10572
- className: _dsh_plugin_shop_css_e3675a89_default.toolbarRight,
10772
+ className: _dsh_plugin_shop_css_d74581c2_default.toolbarRight,
10573
10773
  children: [
10574
10774
  result.stale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10575
- className: _dsh_plugin_shop_css_e3675a89_default.staleBadge,
10775
+ className: _dsh_plugin_shop_css_d74581c2_default.staleBadge,
10576
10776
  children: t("staleLabel", { date: result.builtAt.slice(0, 10) })
10577
10777
  }),
10578
10778
  selfVersion !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10579
- className: _dsh_plugin_shop_css_e3675a89_default.versionBlock,
10779
+ className: _dsh_plugin_shop_css_d74581c2_default.versionBlock,
10580
10780
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
10581
- className: _dsh_plugin_shop_css_e3675a89_default.versionText,
10781
+ className: _dsh_plugin_shop_css_d74581c2_default.versionText,
10582
10782
  "data-shop-version": true,
10583
10783
  children: ["v", selfVersion.installed]
10584
10784
  }), restartMonitor !== null ? null : selfPending && restartBlocked === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
10585
10785
  type: "button",
10586
- className: _dsh_plugin_shop_css_e3675a89_default.restartSelfButton,
10786
+ className: _dsh_plugin_shop_css_d74581c2_default.restartSelfButton,
10587
10787
  "data-shop-restart": true,
10588
10788
  onClick: () => setSelfRestartGate(true),
10589
10789
  children: t("restart")
10590
10790
  }) : !selfPending && selfVersion.outdated && selfVersion.latest !== null && selfUpdate.view.kind === "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
10591
10791
  type: "button",
10592
- className: _dsh_plugin_shop_css_e3675a89_default.updateSelfButton,
10792
+ className: _dsh_plugin_shop_css_d74581c2_default.updateSelfButton,
10593
10793
  "data-shop-update-self": true,
10594
10794
  onClick: () => {
10595
10795
  if (selfVersion.latest !== null) selfUpdate.start({ version: selfVersion.latest });
@@ -10597,7 +10797,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10597
10797
  children: t("update")
10598
10798
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
10599
10799
  type: "button",
10600
- className: _dsh_plugin_shop_css_e3675a89_default.checkUpdateButton,
10800
+ className: _dsh_plugin_shop_css_d74581c2_default.checkUpdateButton,
10601
10801
  "data-shop-check-update": true,
10602
10802
  title: t("checkUpdateTitle"),
10603
10803
  disabled: checkState !== "idle",
@@ -10606,7 +10806,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10606
10806
  })]
10607
10807
  }),
10608
10808
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
10609
- className: _dsh_plugin_shop_css_e3675a89_default.githubLink,
10809
+ className: _dsh_plugin_shop_css_d74581c2_default.githubLink,
10610
10810
  href: SHOP_REPO_URL,
10611
10811
  target: "_blank",
10612
10812
  rel: "noopener noreferrer",
@@ -10631,28 +10831,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10631
10831
  logFile: restartMonitor.logFile
10632
10832
  }),
10633
10833
  selfUpdate.view.kind === "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10634
- className: _dsh_plugin_shop_css_e3675a89_default.selfUpdatePanel,
10834
+ className: _dsh_plugin_shop_css_d74581c2_default.selfUpdatePanel,
10635
10835
  "data-shop-self-updating": true,
10636
10836
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10637
- className: _dsh_plugin_shop_css_e3675a89_default.installing,
10837
+ className: _dsh_plugin_shop_css_d74581c2_default.installing,
10638
10838
  children: t(installPhaseKey(selfUpdate.view.phase))
10639
10839
  }), selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10640
- className: _dsh_plugin_shop_css_e3675a89_default.log,
10840
+ className: _dsh_plugin_shop_css_d74581c2_default.log,
10641
10841
  children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10642
- className: _dsh_plugin_shop_css_e3675a89_default.logLine,
10842
+ className: _dsh_plugin_shop_css_d74581c2_default.logLine,
10643
10843
  "data-shop-log-line": true,
10644
10844
  children: line
10645
10845
  }, index))
10646
10846
  })]
10647
10847
  }),
10648
10848
  selfPending && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10649
- className: _dsh_plugin_shop_css_e3675a89_default.selfUpdatePanel,
10849
+ className: _dsh_plugin_shop_css_d74581c2_default.selfUpdatePanel,
10650
10850
  "data-shop-self-update-done": true,
10651
10851
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10652
- className: _dsh_plugin_shop_css_e3675a89_default.installedActions,
10852
+ className: _dsh_plugin_shop_css_d74581c2_default.installedActions,
10653
10853
  children: [
10654
10854
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10655
- className: _dsh_plugin_shop_css_e3675a89_default.notice,
10855
+ className: _dsh_plugin_shop_css_d74581c2_default.notice,
10656
10856
  children: t("installedRestartNotice")
10657
10857
  }),
10658
10858
  restartBlocked === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RestartPanel, {
@@ -10665,7 +10865,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10665
10865
  }
10666
10866
  }),
10667
10867
  restartBlocked !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10668
- className: _dsh_plugin_shop_css_e3675a89_default.notice,
10868
+ className: _dsh_plugin_shop_css_d74581c2_default.notice,
10669
10869
  "data-shop-restart-disabled": true,
10670
10870
  children: t(restartBlockedNoticeKey(restartBlocked))
10671
10871
  })
@@ -10673,35 +10873,35 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10673
10873
  })
10674
10874
  }),
10675
10875
  selfUpdate.view.kind === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10676
- className: _dsh_plugin_shop_css_e3675a89_default.selfUpdatePanel,
10876
+ className: _dsh_plugin_shop_css_d74581c2_default.selfUpdatePanel,
10677
10877
  "data-shop-self-update-failed": true,
10678
10878
  children: [
10679
10879
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10680
- className: _dsh_plugin_shop_css_e3675a89_default.failedHeading,
10880
+ className: _dsh_plugin_shop_css_d74581c2_default.failedHeading,
10681
10881
  children: t("updateFailed")
10682
10882
  }),
10683
10883
  selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10684
- className: _dsh_plugin_shop_css_e3675a89_default.log,
10884
+ className: _dsh_plugin_shop_css_d74581c2_default.log,
10685
10885
  children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
10686
- className: _dsh_plugin_shop_css_e3675a89_default.logLine,
10886
+ className: _dsh_plugin_shop_css_d74581c2_default.logLine,
10687
10887
  "data-shop-log-line": true,
10688
10888
  children: line
10689
10889
  }, index))
10690
10890
  }),
10691
10891
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10692
- className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
10892
+ className: _dsh_plugin_shop_css_d74581c2_default.failedDetail,
10693
10893
  children: selfUpdate.view.detail === "" ? t("updateTransportFailed") : selfUpdate.view.detail
10694
10894
  })
10695
10895
  ]
10696
10896
  }),
10697
10897
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10698
- className: _dsh_plugin_shop_css_e3675a89_default.categoryBar,
10898
+ className: _dsh_plugin_shop_css_d74581c2_default.categoryBar,
10699
10899
  role: "group",
10700
10900
  "aria-label": t("catalog"),
10701
10901
  children: [
10702
10902
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
10703
10903
  type: "button",
10704
- className: category === null ? `${_dsh_plugin_shop_css_e3675a89_default.categoryButton} ${_dsh_plugin_shop_css_e3675a89_default.categoryButtonOn}` : _dsh_plugin_shop_css_e3675a89_default.categoryButton,
10904
+ className: category === null ? `${_dsh_plugin_shop_css_d74581c2_default.categoryButton} ${_dsh_plugin_shop_css_d74581c2_default.categoryButtonOn}` : _dsh_plugin_shop_css_d74581c2_default.categoryButton,
10705
10905
  "aria-pressed": category === null,
10706
10906
  onClick: () => {
10707
10907
  setCategory(null);
@@ -10716,7 +10916,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10716
10916
  }),
10717
10917
  CATEGORY_ORDER.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
10718
10918
  type: "button",
10719
- className: category === key ? `${_dsh_plugin_shop_css_e3675a89_default.categoryButton} ${_dsh_plugin_shop_css_e3675a89_default.categoryButtonOn}` : _dsh_plugin_shop_css_e3675a89_default.categoryButton,
10919
+ className: category === key ? `${_dsh_plugin_shop_css_d74581c2_default.categoryButton} ${_dsh_plugin_shop_css_d74581c2_default.categoryButtonOn}` : _dsh_plugin_shop_css_d74581c2_default.categoryButton,
10720
10920
  "aria-pressed": category === key,
10721
10921
  "data-category": key,
10722
10922
  "data-shop-category-tab": key,
@@ -10732,7 +10932,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10732
10932
  }, key)),
10733
10933
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
10734
10934
  type: "button",
10735
- className: category === "installed" ? `${_dsh_plugin_shop_css_e3675a89_default.categoryButton} ${_dsh_plugin_shop_css_e3675a89_default.categoryButtonOn}` : _dsh_plugin_shop_css_e3675a89_default.categoryButton,
10935
+ className: category === "installed" ? `${_dsh_plugin_shop_css_d74581c2_default.categoryButton} ${_dsh_plugin_shop_css_d74581c2_default.categoryButtonOn}` : _dsh_plugin_shop_css_d74581c2_default.categoryButton,
10736
10936
  "aria-pressed": category === "installed",
10737
10937
  "data-shop-category-installed": true,
10738
10938
  onClick: () => {
@@ -10749,7 +10949,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10749
10949
  type: "button",
10750
10950
  role: "switch",
10751
10951
  "aria-checked": hideIncompatible,
10752
- className: hideIncompatible ? `${_dsh_plugin_shop_css_e3675a89_default.incompatibleFilter} ${_dsh_plugin_shop_css_e3675a89_default.incompatibleFilterOn}` : _dsh_plugin_shop_css_e3675a89_default.incompatibleFilter,
10952
+ className: hideIncompatible ? `${_dsh_plugin_shop_css_d74581c2_default.incompatibleFilter} ${_dsh_plugin_shop_css_d74581c2_default.incompatibleFilterOn}` : _dsh_plugin_shop_css_d74581c2_default.incompatibleFilter,
10753
10953
  title: t(hideIncompatible ? "showIncompatibleTitle" : "incompatibleFilterTitle"),
10754
10954
  "data-shop-hide-incompatible": true,
10755
10955
  onClick: () => {
@@ -10757,18 +10957,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10757
10957
  setVisibleCount(48);
10758
10958
  },
10759
10959
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10760
- className: hideIncompatible ? `${_dsh_plugin_shop_css_e3675a89_default.switch} ${_dsh_plugin_shop_css_e3675a89_default.switchOn}` : _dsh_plugin_shop_css_e3675a89_default.switch,
10960
+ className: hideIncompatible ? `${_dsh_plugin_shop_css_d74581c2_default.switch} ${_dsh_plugin_shop_css_d74581c2_default.switchOn}` : _dsh_plugin_shop_css_d74581c2_default.switch,
10761
10961
  "aria-hidden": "true",
10762
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.switchKnob })
10962
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_d74581c2_default.switchKnob })
10763
10963
  }), t("hideIncompatible", { count: incompatibleCount })]
10764
10964
  })
10765
10965
  ]
10766
10966
  }),
10767
10967
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
10768
- className: _dsh_plugin_shop_css_e3675a89_default.catalogStatsRow,
10968
+ className: _dsh_plugin_shop_css_d74581c2_default.catalogStatsRow,
10769
10969
  children: [
10770
10970
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10771
- className: _dsh_plugin_shop_css_e3675a89_default.catalogStats,
10971
+ className: _dsh_plugin_shop_css_d74581c2_default.catalogStats,
10772
10972
  "data-shop-catalog-stats": true,
10773
10973
  children: t("catalogStats", {
10774
10974
  count: String(browsable.length),
@@ -10777,7 +10977,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10777
10977
  }),
10778
10978
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
10779
10979
  type: "button",
10780
- className: _dsh_plugin_shop_css_e3675a89_default.catalogRefreshButton,
10980
+ className: _dsh_plugin_shop_css_d74581c2_default.catalogRefreshButton,
10781
10981
  "data-shop-catalog-refresh": true,
10782
10982
  disabled: reloading,
10783
10983
  onClick: () => {
@@ -10789,26 +10989,49 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10789
10989
  children: reloading ? t("refreshing") : t("refresh")
10790
10990
  }),
10791
10991
  reloadFailed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
10792
- className: _dsh_plugin_shop_css_e3675a89_default.catalogRefreshFailed,
10992
+ className: _dsh_plugin_shop_css_d74581c2_default.catalogRefreshFailed,
10793
10993
  "data-shop-catalog-refresh-failed": true,
10794
10994
  children: t("refreshFailed")
10995
+ }),
10996
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
10997
+ className: _dsh_plugin_shop_css_d74581c2_default.sortGroup,
10998
+ role: "group",
10999
+ "aria-labelledby": sortLabelId,
11000
+ "data-shop-sort": true,
11001
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
11002
+ className: _dsh_plugin_shop_css_d74581c2_default.sortLabel,
11003
+ id: sortLabelId,
11004
+ children: t("sortLabel")
11005
+ }), SHELF_ORDERS.map((name) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
11006
+ type: "button",
11007
+ className: order === name ? `${_dsh_plugin_shop_css_d74581c2_default.categoryButton} ${_dsh_plugin_shop_css_d74581c2_default.categoryButtonOn}` : _dsh_plugin_shop_css_d74581c2_default.categoryButton,
11008
+ "aria-pressed": order === name,
11009
+ "data-shop-order": name,
11010
+ onClick: () => {
11011
+ setOrder(name);
11012
+ setVisibleCount(48);
11013
+ },
11014
+ children: t(shelfOrderLocaleKey(name))
11015
+ }, name))]
10795
11016
  })
10796
11017
  ]
10797
11018
  }),
10798
11019
  result.plugins.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10799
- className: _dsh_plugin_shop_css_e3675a89_default.emptyLine,
11020
+ className: _dsh_plugin_shop_css_d74581c2_default.emptyLine,
10800
11021
  children: t("empty")
10801
11022
  }) : filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10802
- className: _dsh_plugin_shop_css_e3675a89_default.emptyLine,
11023
+ className: _dsh_plugin_shop_css_d74581c2_default.emptyLine,
10803
11024
  "data-shop-empty": true,
10804
11025
  children: matched.length > 0 ? t("emptyIncompatibleFiltered") : t("emptySearch")
10805
11026
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
10806
- className: _dsh_plugin_shop_css_e3675a89_default.cards,
11027
+ className: _dsh_plugin_shop_css_d74581c2_default.cards,
10807
11028
  children: [visible.map((entry) => {
10808
11029
  const key = entryKey(entry);
10809
11030
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryCard, {
10810
11031
  entry,
10811
11032
  stars: starsOf(entry, stars),
11033
+ order,
11034
+ shelfDay: shelfDayOf(entry),
10812
11035
  installed: installedByKey.get(key),
10813
11036
  missing: missingByKey.get(key) ?? [],
10814
11037
  harness: harnessVerdictOf(harnessVerdicts, key),
@@ -10825,12 +11048,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
10825
11048
  }) }, key);
10826
11049
  }), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
10827
11050
  ref: sentinelRef,
10828
- className: _dsh_plugin_shop_css_e3675a89_default.cardsSentry,
11051
+ className: _dsh_plugin_shop_css_d74581c2_default.cardsSentry,
10829
11052
  "data-shop-sentry": true,
10830
11053
  "aria-hidden": "true"
10831
11054
  })]
10832
11055
  }), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
10833
- className: _dsh_plugin_shop_css_e3675a89_default.showingLine,
11056
+ className: _dsh_plugin_shop_css_d74581c2_default.showingLine,
10834
11057
  "aria-live": "polite",
10835
11058
  children: t("showing", {
10836
11059
  shown: String(visibleCount),