dsh-plugin-shop 0.8.0 → 0.8.1-beta.0

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
@@ -4314,7 +4314,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4314
4314
  "sha256": string()
4315
4315
  })]).optional(),
4316
4316
  "added": union([_undefined(), string()]).optional(),
4317
- "peers": union([_undefined(), array(string())]).optional()
4317
+ "peers": union([_undefined(), array(string())]).optional(),
4318
+ "unpackedSize": union([_undefined(), number()]).optional()
4318
4319
  })),
4319
4320
  "denied": array(object({
4320
4321
  "name": string(),
@@ -6529,6 +6530,42 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6529
6530
  if (n < 1e3) return String(n);
6530
6531
  return `${(n / 1e3).toFixed(1).replace(/\.0$/, "")}k`;
6531
6532
  }
6533
+ /**
6534
+ * One entry's unpacked size as a label: 0 → "0 B", 812 → "812 B",
6535
+ * 25283 → "25.3 kB", 847407 → "847.4 kB", 179562863 → "179.6 MB".
6536
+ *
6537
+ * Decimal kB/MB, not KiB/MiB, because the number itself is npm's
6538
+ * `dist.unpackedSize` and npm's own package page shows it decimal — a reader
6539
+ * comparing the shelf against npmjs.com must not find two different figures
6540
+ * for one package. One fractional digit at every magnitude above a kilobyte,
6541
+ * the same rule `formatStars` follows: a column of sizes is read by comparing
6542
+ * them down the shelf, and switching precision by magnitude makes that column
6543
+ * ragged for no gain.
6544
+ *
6545
+ * Locale-free by construction (`toFixed`, not `toLocaleString`): the shelf's
6546
+ * two languages must not disagree about what a size is, and a decimal comma
6547
+ * in one of them would read as a thousands separator in the other.
6548
+ *
6549
+ * Undefined in, undefined out — a github entry and an old npm publish both
6550
+ * have no figure, and the card renders no label rather than a guess. The
6551
+ * caller need not check first.
6552
+ */
6553
+ function formatSize(bytes) {
6554
+ if (bytes === void 0) return void 0;
6555
+ if (bytes < 1e3) return `${bytes} B`;
6556
+ let value = bytes;
6557
+ let unit = "B";
6558
+ for (const next of [
6559
+ "kB",
6560
+ "MB",
6561
+ "GB"
6562
+ ]) {
6563
+ if (Number(value.toFixed(1)) < 1e3) break;
6564
+ value /= 1e3;
6565
+ unit = next;
6566
+ }
6567
+ return `${value.toFixed(1)} ${unit}`;
6568
+ }
6532
6569
  //#endregion
6533
6570
  //#region src/client/locales.ts
6534
6571
  /** Copy dictionaries for the shop Settings tab. */
@@ -6581,6 +6618,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6581
6618
  repository: "仓库",
6582
6619
  npmPage: "npm 页面",
6583
6620
  authorLine: "作者:{author}",
6621
+ /** The accessible name and tooltip of the size label; the label itself shows
6622
+ * the bare figure. "解包后" is the load-bearing word — the number is npm's
6623
+ * unpacked size, not the download. */
6624
+ sizeLabel: "解包后 {size}",
6625
+ hideIncompatible: "隐藏不兼容 {count}",
6626
+ showIncompatible: "显示不兼容 {count}",
6627
+ incompatibleFilterTitle: "不显示缺少组件的插件",
6628
+ showIncompatibleTitle: "把缺少组件的插件放回列表",
6629
+ emptyIncompatibleFiltered: "匹配的插件都缺少组件,已被「隐藏不兼容」筛掉。",
6584
6630
  license: "许可",
6585
6631
  customLicense: "自定义许可",
6586
6632
  reviewedVersionLine: "已审核 v{reviewed} / 当前 v{current} 未审核",
@@ -6674,6 +6720,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6674
6720
  repository: "Repository",
6675
6721
  npmPage: "npm page",
6676
6722
  authorLine: "Author: {author}",
6723
+ sizeLabel: "{size} unpacked",
6724
+ hideIncompatible: "Hide incompatible {count}",
6725
+ showIncompatible: "Show incompatible {count}",
6726
+ incompatibleFilterTitle: "Leave out plugins whose components are missing",
6727
+ showIncompatibleTitle: "Put plugins whose components are missing back on the shelf",
6728
+ emptyIncompatibleFiltered: "Every matching plugin is missing components, and the incompatible filter is leaving them out.",
6677
6729
  license: "License",
6678
6730
  customLicense: "Custom license",
6679
6731
  reviewedVersionLine: "reviewed v{reviewed} / current v{current} unreviewed",
@@ -6918,111 +6970,114 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6918
6970
  };
6919
6971
  }
6920
6972
  //#endregion
6921
- //#region \0dsh-plugin-shop-css:26093961
6922
- 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.sfae5fa_client.se9da7d_config.se722f1_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.sfae5fa_client.s2f7a8b_spec.se722f1_ts` pins this. */\n\n.s99b207_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 `.se23a0e_searchInput` sits at\n * exactly (0, 0) of this box — it is the first child of `.s27ad76_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.s2abe0f_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.sfb85e5_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.s728a01_skeletonGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 8px;\n}\n\n.s33d002_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.s33d002_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.s46e666_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.s2a467d_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.s232601_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.sde9b0c_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.s33d002_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 .s33d002_skeletonCard span { animation: none; opacity: 0.75; }\n .s33d002_skeletonCard::after { content: none; }\n}\n\n.sb632c0_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.sb632c0_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.sb632c0_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s27ad76_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.saba3c3_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.s6736c0_versionBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.s2dff04_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.s40b16e_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.s40b16e_updateSelfButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 20%, transparent);\n}\n\n.s40b16e_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.secd6a2_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.secd6a2_checkUpdateButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n color: var(--dsw-alias-label-primary);\n}\n\n.secd6a2_checkUpdateButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.secd6a2_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.s5e1ce3_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.s5e1ce3_githubLink:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.s5e1ce3_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.s798348_selfUpdatePanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.se23a0e_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.se23a0e_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.see2588_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.se67e0b_categoryBar {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n margin-top: 6px;\n}\n\n.s8c06a0_categoryButton {\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.s8c06a0_categoryButton: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.s65a55a_categoryButtonOn {\n border-color: var(--dsw-alias-brand-primary);\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n color: var(--dsw-alias-brand-primary);\n font-weight: 600;\n}\n\n.s8c06a0_categoryButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sb6cdd6_catalogHeading {\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.sf2305c_catalogStatsRow {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 6px 0 0;\n}\n\n.s38a33e_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 `.sb632c0_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. */\n.s71d105_reloadButton {\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.s71d105_reloadButton: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.s71d105_reloadButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.s71d105_reloadButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sa079ea_reloadFailed {\n font-size: 11px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.se3ba96_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.sb41fe1_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 .sb41fe1_cards { animation: none; }\n}\n\n.sfcd584_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.sf2d932_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s947694_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sfcd584_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 .sfcd584_card { transition: none; }\n .sfcd584_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.sfc4028_cardSpine {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 3px;\n background: var(--spine-hue, #8B8E96);\n}\n\n.sfcd584_card[data-category='tool'] { --spine-hue: #4C8DFF; }\n.sfcd584_card[data-category='provider'] { --spine-hue: #A78BFA; }\n.sfcd584_card[data-category='ui'] { --spine-hue: #2DD4BF; }\n.sfcd584_card[data-category='workflow'] { --spine-hue: #F59E0B; }\n.sfcd584_card[data-category='integration'] { --spine-hue: #34D399; }\n.sfcd584_card[data-category='theme'] { --spine-hue: #F472B6; }\n.sfcd584_card[data-category='other'] { --spine-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.sb94610_categoryBadge {\n padding: 1px 7px;\n border: 1px solid color-mix(in srgb, var(--spine-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(--spine-hue, #8B8E96);\n white-space: nowrap;\n}\n\n.s50a94e_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.s50a94e_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.sfdbf47_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.s28e55e_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.s9359c0_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.s9359c0_cardActions > .s549462_gate,\n.s9359c0_cardActions > .s20fbe0_installPanel,\n.s9359c0_cardActions > .s94517f_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.sc54e24_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.s623bee_sourceBadge {\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sf9a12c_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.sf9a12c_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.sf9a12c_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.sf9a12c_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.s671f97_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.s963e5c_starsBadge {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sbb5739_chevron, .s4e56e8_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s4e56e8_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .sbb5739_chevron, .s4e56e8_chevronOpen { transition: none; }\n}\n\n.sf9a60a_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px;\n}\n\n.sfd2791_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.s69ed84_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.s83c8c8_summaryExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n.s20b5b9_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.s45793c_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.s551fd2_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.sb1f0de_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s9a5379_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s9a5379_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.s9e0e76_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.s41121d_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.s852a05_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.s852a05_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.s852a05_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.s852a05_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.s852a05_detailRow a:hover {\n text-decoration: underline;\n}\n\n.s852a05_detailRow a:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The publishing account, beside the npm link. Secondary label colour and a\n * middot separator carry the distinction — never a background fill, which is\n * invisible in the light theme where every bg-layer token is the same white. */\n/* Who published the entry, at the right edge of the action row. `margin-left:\n * auto` is what pushes it there; the row is a wrapping flex, so an active\n * install flow (which claims the full width) drops this to the next line\n * rather than squeezing it. */\n.s367f3b_author {\n margin-left: auto;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.s2f9e91_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.s20fbe0_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n.s89d599_installButton, .s7b4348_confirmButton, .s20b00b_cancelButton {\n align-self: flex-start;\n padding: 5px 14px;\n border-radius: 6px;\n font-size: 13px;\n cursor: pointer;\n}\n\n.s89d599_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.s89d599_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s7b4348_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.s7b4348_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s20b00b_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.s20b00b_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s89d599_installButton:focus-visible, .s7b4348_confirmButton:focus-visible, .s20b00b_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.s1e55fb_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.s94517f_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.s432016_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.s432016_uninstallButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.s432016_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.sdc8ac4_restartSelfButton {\n /* The version row's third state. Geometry matches .secd6a2_checkUpdateButton and\n * .s40b16e_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.sdc8ac4_restartSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s5c0f5a_restartButton {\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.s5c0f5a_restartButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s5c0f5a_restartButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s549462_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.sed2c7d_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n.sdce129_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.sfae869_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.sae8426_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.s260a62_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sba0b9c_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.s5c7c9d_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sebdc74_notice {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-state-success-primary);\n}\n\n.s2672db_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.s3a9748_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.sc1144d_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--dsw-alias-state-error-primary);\n}\n\n.s2209a3_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* Installed section. */\n.sb4abbb_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.sbca39c_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s1abd04_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.s10dca9_outdatedInfo {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s10dca9_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.sb04966_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 .s28e55e_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.see54bf_outdatedActions {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n/* The enable/disable switch. */\n.sa65b66_switch {\n position: relative;\n width: 32px;\n height: 18px;\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.s50b82f_switchOn {\n border-color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 55%, transparent);\n}\n\n.sbbb39a_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.s50b82f_switchOn .sbbb39a_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.sa65b66_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 .sa65b66_switch, .sbbb39a_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.s24b48c_switchWrap {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n}\n";
6923
- if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"26093961\"]")) {
6973
+ //#region \0dsh-plugin-shop-css:e3675a89
6974
+ 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.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 * It IS a pill, so it wears `.s26d58e_categoryButton` and states only its two\n * differences. The geometry rule the pills follow then covers it by\n * construction rather than by a second copy that has to be kept in step: this\n * rule was a verbatim clone of the four `.s26d58e_categoryButton` rules, and every\n * padding or border change to the bar had to be made twice or the two silently\n * drifted. `--category-hue` is the knob that makes the clone unnecessary —\n * declared here at the same specificity as `.s26d58e_categoryButton`'s fallback and\n * after it, so it wins; the button carries no `data-category`, so the hue\n * table below cannot reach it. */\n.sfd887b_incompatibleFilter {\n --category-hue: var(--dsw-alias-state-error-primary);\n margin-left: auto;\n}\n\n.s668774_catalogHeading {\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. */\n.s64a5ff_reloadButton {\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.s64a5ff_reloadButton: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.s64a5ff_reloadButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.s64a5ff_reloadButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s4453f3_reloadFailed {\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.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.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 github entry has no npm size, and a packument that named no account has no\n * author. 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 unpacked 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.s6ac237_restartButton {\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 border-color: var(--dsw-alias-label-secondary);\n}\n\n.s6ac237_restartButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\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/* Installed section. */\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.sa1f556_outdatedActions {\n display: flex;\n align-items: center;\n gap: 10px;\n}\n\n/* The enable/disable switch. */\n.s11c019_switch {\n position: relative;\n width: 32px;\n height: 18px;\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.s7580e8_switchOn {\n border-color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 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 gap: 8px;\n}\n";
6975
+ if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"e3675a89\"]")) {
6924
6976
  const tag = document.createElement("style");
6925
- tag.dataset.pluginCss = "26093961";
6977
+ tag.dataset.pluginCss = "e3675a89";
6926
6978
  tag.textContent = css;
6927
6979
  document.head.appendChild(tag);
6928
6980
  }
6929
- var _dsh_plugin_shop_css_26093961_default = {
6930
- "client": "sfae5fa_client",
6931
- "config": "se9da7d_config",
6932
- "ts": "se722f1_ts",
6933
- "spec": "s2f7a8b_spec",
6934
- "panel": "s99b207_panel",
6935
- "searchInput": "se23a0e_searchInput",
6936
- "toolbar": "s27ad76_toolbar",
6937
- "stateLine": "s2abe0f_stateLine",
6938
- "srOnly": "sfb85e5_srOnly",
6939
- "skeletonGrid": "s728a01_skeletonGrid",
6940
- "skeletonCard": "s33d002_skeletonCard",
6941
- "skeletonName": "s46e666_skeletonName",
6942
- "skeletonSummary": "s2a467d_skeletonSummary",
6943
- "skeletonSummaryShort": "s232601_skeletonSummaryShort",
6944
- "skeletonActions": "sde9b0c_skeletonActions",
6945
- "actionButton": "sb632c0_actionButton",
6946
- "toolbarRight": "saba3c3_toolbarRight",
6947
- "versionBlock": "s6736c0_versionBlock",
6948
- "versionText": "s2dff04_versionText",
6949
- "updateSelfButton": "s40b16e_updateSelfButton",
6950
- "checkUpdateButton": "secd6a2_checkUpdateButton",
6951
- "githubLink": "s5e1ce3_githubLink",
6952
- "selfUpdatePanel": "s798348_selfUpdatePanel",
6953
- "staleBadge": "see2588_staleBadge",
6954
- "categoryBar": "se67e0b_categoryBar",
6955
- "categoryButton": "s8c06a0_categoryButton",
6956
- "categoryButtonOn": "s65a55a_categoryButtonOn",
6957
- "catalogHeading": "sb6cdd6_catalogHeading",
6958
- "catalogStatsRow": "sf2305c_catalogStatsRow",
6959
- "catalogStats": "s38a33e_catalogStats",
6960
- "reloadButton": "s71d105_reloadButton",
6961
- "reloadFailed": "sa079ea_reloadFailed",
6962
- "emptyLine": "se3ba96_emptyLine",
6963
- "cards": "sb41fe1_cards",
6964
- "card": "sfcd584_card",
6965
- "cardsSentry": "sf2d932_cardsSentry",
6966
- "showingLine": "s947694_showingLine",
6967
- "cardSpine": "sfc4028_cardSpine",
6968
- "categoryBadge": "sb94610_categoryBadge",
6969
- "entryHeader": "s50a94e_entryHeader",
6970
- "name": "sfdbf47_name",
6971
- "badges": "s28e55e_badges",
6972
- "cardActions": "s9359c0_cardActions",
6973
- "gate": "s549462_gate",
6974
- "installPanel": "s20fbe0_installPanel",
6975
- "installedActions": "s94517f_installedActions",
6976
- "cardVersion": "sc54e24_cardVersion",
6977
- "sourceBadge": "s623bee_sourceBadge",
6978
- "tierBadge": "sf9a12c_tierBadge",
6979
- "incompatibleBadge": "s671f97_incompatibleBadge",
6980
- "starsBadge": "s963e5c_starsBadge",
6981
- "chevron": "sbb5739_chevron",
6982
- "chevronOpen": "s4e56e8_chevronOpen",
6983
- "body": "sf9a60a_body",
6984
- "summary": "sfd2791_summary",
6985
- "summaryZh": "s69ed84_summaryZh",
6986
- "summaryExpanded": "s83c8c8_summaryExpanded",
6987
- "summaryZhExpanded": "s20b5b9_summaryZhExpanded",
6988
- "incompatibleDetail": "s45793c_incompatibleDetail",
6989
- "capabilitiesBlock": "s551fd2_capabilitiesBlock",
6990
- "capabilitiesNote": "sb1f0de_capabilitiesNote",
6991
- "capabilities": "s9a5379_capabilities",
6992
- "detail": "s9e0e76_detail",
6993
- "detailRows": "s41121d_detailRows",
6994
- "detailRow": "s852a05_detailRow",
6995
- "author": "s367f3b_author",
6996
- "reviewedLine": "s2f9e91_reviewedLine",
6997
- "installButton": "s89d599_installButton",
6998
- "confirmButton": "s7b4348_confirmButton",
6999
- "cancelButton": "s20b00b_cancelButton",
7000
- "installedLabel": "s1e55fb_installedLabel",
7001
- "uninstallButton": "s432016_uninstallButton",
7002
- "restartSelfButton": "sdc8ac4_restartSelfButton",
7003
- "restartButton": "s5c0f5a_restartButton",
7004
- "gateTitle": "sed2c7d_gateTitle",
7005
- "gateBody": "sdce129_gateBody",
7006
- "gateWarning": "sfae869_gateWarning",
7007
- "gateActions": "sae8426_gateActions",
7008
- "installing": "s260a62_installing",
7009
- "log": "sba0b9c_log",
7010
- "logLine": "s5c7c9d_logLine",
7011
- "notice": "sebdc74_notice",
7012
- "failedHeading": "s2672db_failedHeading",
7013
- "failedDetail": "s3a9748_failedDetail",
7014
- "rejectedCode": "sc1144d_rejectedCode",
7015
- "rejectedDetail": "s2209a3_rejectedDetail",
7016
- "outdatedSection": "sb4abbb_outdatedSection",
7017
- "outdatedList": "sbca39c_outdatedList",
7018
- "outdatedRow": "s1abd04_outdatedRow",
7019
- "outdatedInfo": "s10dca9_outdatedInfo",
7020
- "outdatedVersions": "sb04966_outdatedVersions",
7021
- "outdatedActions": "see54bf_outdatedActions",
7022
- "switch": "sa65b66_switch",
7023
- "switchOn": "s50b82f_switchOn",
7024
- "switchKnob": "sbbb39a_switchKnob",
7025
- "switchWrap": "s24b48c_switchWrap"
6981
+ var _dsh_plugin_shop_css_e3675a89_default = {
6982
+ "client": "s8583e3_client",
6983
+ "config": "s942a79_config",
6984
+ "ts": "s5f67aa_ts",
6985
+ "spec": "sfd9d8a_spec",
6986
+ "panel": "s255e5a_panel",
6987
+ "searchInput": "s232ec4_searchInput",
6988
+ "toolbar": "s646509_toolbar",
6989
+ "stateLine": "s44a3ec_stateLine",
6990
+ "srOnly": "s3a0ece_srOnly",
6991
+ "skeletonGrid": "se0c3b4_skeletonGrid",
6992
+ "skeletonCard": "s520416_skeletonCard",
6993
+ "skeletonName": "s8c7d6f_skeletonName",
6994
+ "skeletonSummary": "sf5179e_skeletonSummary",
6995
+ "skeletonSummaryShort": "sbb0d25_skeletonSummaryShort",
6996
+ "skeletonActions": "s96e910_skeletonActions",
6997
+ "actionButton": "s73242a_actionButton",
6998
+ "toolbarRight": "s745e3c_toolbarRight",
6999
+ "versionBlock": "s4fe61f_versionBlock",
7000
+ "versionText": "sb9b924_versionText",
7001
+ "updateSelfButton": "sa04455_updateSelfButton",
7002
+ "checkUpdateButton": "s614a38_checkUpdateButton",
7003
+ "githubLink": "sa987f7_githubLink",
7004
+ "selfUpdatePanel": "sb81ba5_selfUpdatePanel",
7005
+ "staleBadge": "s3946f1_staleBadge",
7006
+ "categoryBar": "sb2c859_categoryBar",
7007
+ "categoryButton": "s26d58e_categoryButton",
7008
+ "categoryButtonOn": "s5f68c4_categoryButtonOn",
7009
+ "incompatibleFilter": "sfd887b_incompatibleFilter",
7010
+ "catalogHeading": "s668774_catalogHeading",
7011
+ "catalogStatsRow": "seb0a1e_catalogStatsRow",
7012
+ "catalogStats": "sccc4d1_catalogStats",
7013
+ "reloadButton": "s64a5ff_reloadButton",
7014
+ "reloadFailed": "s4453f3_reloadFailed",
7015
+ "emptyLine": "s6de1ab_emptyLine",
7016
+ "cards": "sf657f5_cards",
7017
+ "card": "s65f383_card",
7018
+ "cardsSentry": "sd7ee01_cardsSentry",
7019
+ "showingLine": "s705cc6_showingLine",
7020
+ "cardSpine": "s4ce25d_cardSpine",
7021
+ "categoryBadge": "s9c8eaa_categoryBadge",
7022
+ "entryHeader": "sa97234_entryHeader",
7023
+ "name": "sc3f149_name",
7024
+ "badges": "s513026_badges",
7025
+ "cardActions": "s9b5048_cardActions",
7026
+ "gate": "sc4f2ac_gate",
7027
+ "installPanel": "s4d374c_installPanel",
7028
+ "installedActions": "sf53ca0_installedActions",
7029
+ "cardVersion": "sc6ec6e_cardVersion",
7030
+ "sourceBadge": "s71f10f_sourceBadge",
7031
+ "tierBadge": "s5e82cb_tierBadge",
7032
+ "incompatibleBadge": "s4bbe02_incompatibleBadge",
7033
+ "starsBadge": "sff43b4_starsBadge",
7034
+ "chevron": "s73f7fb_chevron",
7035
+ "chevronOpen": "s61393c_chevronOpen",
7036
+ "body": "s820ebf_body",
7037
+ "summary": "sb8fbc8_summary",
7038
+ "summaryZh": "se507db_summaryZh",
7039
+ "summaryExpanded": "s10baf0_summaryExpanded",
7040
+ "summaryZhExpanded": "sb9dba9_summaryZhExpanded",
7041
+ "incompatibleDetail": "s6eca19_incompatibleDetail",
7042
+ "capabilitiesBlock": "s9d2029_capabilitiesBlock",
7043
+ "capabilitiesNote": "s3bdbd5_capabilitiesNote",
7044
+ "capabilities": "s441702_capabilities",
7045
+ "detail": "sde3f0c_detail",
7046
+ "detailRows": "se98179_detailRows",
7047
+ "detailRow": "sfb4d2f_detailRow",
7048
+ "cardMeta": "s5fbaf9_cardMeta",
7049
+ "size": "s2d3c05_size",
7050
+ "author": "s1ff66f_author",
7051
+ "reviewedLine": "sd58c6d_reviewedLine",
7052
+ "installButton": "se7aaed_installButton",
7053
+ "confirmButton": "sb43a49_confirmButton",
7054
+ "cancelButton": "s6e45d1_cancelButton",
7055
+ "installedLabel": "sb6fc74_installedLabel",
7056
+ "uninstallButton": "s96967f_uninstallButton",
7057
+ "restartSelfButton": "sb00c36_restartSelfButton",
7058
+ "restartButton": "s6ac237_restartButton",
7059
+ "gateTitle": "s559c38_gateTitle",
7060
+ "gateBody": "s3c0ace_gateBody",
7061
+ "gateWarning": "sc323e5_gateWarning",
7062
+ "gateActions": "s4b2373_gateActions",
7063
+ "installing": "s52b5a5_installing",
7064
+ "log": "s64ab71_log",
7065
+ "logLine": "s1531a8_logLine",
7066
+ "notice": "sf20dda_notice",
7067
+ "failedHeading": "seb9b08_failedHeading",
7068
+ "failedDetail": "sfd3021_failedDetail",
7069
+ "rejectedCode": "s50ba35_rejectedCode",
7070
+ "rejectedDetail": "se75489_rejectedDetail",
7071
+ "outdatedSection": "sa276cf_outdatedSection",
7072
+ "outdatedList": "sceae6e_outdatedList",
7073
+ "outdatedRow": "s8d2072_outdatedRow",
7074
+ "outdatedInfo": "s5c2545_outdatedInfo",
7075
+ "outdatedVersions": "s877c68_outdatedVersions",
7076
+ "outdatedActions": "sa1f556_outdatedActions",
7077
+ "switch": "s11c019_switch",
7078
+ "switchOn": "s7580e8_switchOn",
7079
+ "switchKnob": "saab2b3_switchKnob",
7080
+ "switchWrap": "sd9f9e4_switchWrap"
7026
7081
  };
7027
7082
  //#endregion
7028
7083
  //#region src/client/ShopTab.tsx
@@ -7039,7 +7094,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7039
7094
  width: "14",
7040
7095
  height: "14",
7041
7096
  "aria-hidden": "true",
7042
- className: open ? _dsh_plugin_shop_css_26093961_default.chevronOpen : _dsh_plugin_shop_css_26093961_default.chevron,
7097
+ className: open ? _dsh_plugin_shop_css_e3675a89_default.chevronOpen : _dsh_plugin_shop_css_e3675a89_default.chevron,
7043
7098
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
7044
7099
  fill: "currentColor",
7045
7100
  d: "M3.5 6 8 10.5 12.5 6l1 1L8 12.5 2.5 7l1-1Z"
@@ -7059,6 +7114,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7059
7114
  const summary = entry.catalog?.summary;
7060
7115
  const npmUrl = npmPageUrl(entry);
7061
7116
  const author = authorOf(entry);
7117
+ const size = formatSize(entry.unpackedSize);
7062
7118
  const category = entry.catalog?.category ?? "other";
7063
7119
  const installTarget = {
7064
7120
  name: entry.name,
@@ -7073,32 +7129,32 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7073
7129
  onSettled();
7074
7130
  }, [flow, onSettled]);
7075
7131
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7076
- className: _dsh_plugin_shop_css_26093961_default.card,
7132
+ className: _dsh_plugin_shop_css_e3675a89_default.card,
7077
7133
  "data-shop-entry": entry.name,
7078
7134
  "data-category": category,
7079
7135
  children: [
7080
7136
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7081
- className: _dsh_plugin_shop_css_26093961_default.cardSpine,
7137
+ className: _dsh_plugin_shop_css_e3675a89_default.cardSpine,
7082
7138
  "aria-hidden": "true"
7083
7139
  }),
7084
7140
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
7085
7141
  type: "button",
7086
- className: _dsh_plugin_shop_css_26093961_default.entryHeader,
7142
+ className: _dsh_plugin_shop_css_e3675a89_default.entryHeader,
7087
7143
  "aria-expanded": open,
7088
7144
  "aria-controls": detailId,
7089
7145
  onClick: () => setOpen((current) => !current),
7090
7146
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7091
- className: _dsh_plugin_shop_css_26093961_default.name,
7147
+ className: _dsh_plugin_shop_css_e3675a89_default.name,
7092
7148
  children: entry.name
7093
7149
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7094
- className: _dsh_plugin_shop_css_26093961_default.badges,
7150
+ className: _dsh_plugin_shop_css_e3675a89_default.badges,
7095
7151
  children: [
7096
7152
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7097
- className: _dsh_plugin_shop_css_26093961_default.categoryBadge,
7153
+ className: _dsh_plugin_shop_css_e3675a89_default.categoryBadge,
7098
7154
  children: t(categoryKey(entry))
7099
7155
  }),
7100
7156
  entry.source === "npm" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7101
- className: _dsh_plugin_shop_css_26093961_default.sourceBadge,
7157
+ className: _dsh_plugin_shop_css_e3675a89_default.sourceBadge,
7102
7158
  "data-shop-source-npm": true,
7103
7159
  role: "img",
7104
7160
  "aria-label": t("npmSource"),
@@ -7115,7 +7171,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7115
7171
  })
7116
7172
  }),
7117
7173
  hasGithubHome(entry) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7118
- className: _dsh_plugin_shop_css_26093961_default.sourceBadge,
7174
+ className: _dsh_plugin_shop_css_e3675a89_default.sourceBadge,
7119
7175
  "data-shop-source-github": true,
7120
7176
  role: "img",
7121
7177
  "aria-label": t("githubSource"),
@@ -7129,17 +7185,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7129
7185
  })
7130
7186
  }),
7131
7187
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7132
- className: _dsh_plugin_shop_css_26093961_default.cardVersion,
7188
+ className: _dsh_plugin_shop_css_e3675a89_default.cardVersion,
7133
7189
  "data-card-version": true,
7134
7190
  children: ["v", displayVersion(entry)]
7135
7191
  }),
7136
7192
  entry.tier !== "community" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7137
- className: _dsh_plugin_shop_css_26093961_default.tierBadge,
7193
+ className: _dsh_plugin_shop_css_e3675a89_default.tierBadge,
7138
7194
  "data-tier": entry.tier,
7139
7195
  children: t(tierKey(entry.tier))
7140
7196
  }),
7141
7197
  stars !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7142
- className: _dsh_plugin_shop_css_26093961_default.starsBadge,
7198
+ className: _dsh_plugin_shop_css_e3675a89_default.starsBadge,
7143
7199
  role: "img",
7144
7200
  "aria-label": t("stars", { count: stars }),
7145
7201
  children: ["★ ", formatStars(stars)]
@@ -7149,39 +7205,39 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7149
7205
  })]
7150
7206
  }),
7151
7207
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7152
- className: _dsh_plugin_shop_css_26093961_default.body,
7208
+ className: _dsh_plugin_shop_css_e3675a89_default.body,
7153
7209
  children: [
7154
7210
  summary !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7155
- className: open ? `${_dsh_plugin_shop_css_26093961_default.summary} ${_dsh_plugin_shop_css_26093961_default.summaryExpanded}` : _dsh_plugin_shop_css_26093961_default.summary,
7211
+ className: open ? `${_dsh_plugin_shop_css_e3675a89_default.summary} ${_dsh_plugin_shop_css_e3675a89_default.summaryExpanded}` : _dsh_plugin_shop_css_e3675a89_default.summary,
7156
7212
  children: summary.en
7157
7213
  }),
7158
7214
  summary?.zh !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7159
- className: open ? `${_dsh_plugin_shop_css_26093961_default.summaryZh} ${_dsh_plugin_shop_css_26093961_default.summaryZhExpanded}` : _dsh_plugin_shop_css_26093961_default.summaryZh,
7215
+ className: open ? `${_dsh_plugin_shop_css_e3675a89_default.summaryZh} ${_dsh_plugin_shop_css_e3675a89_default.summaryZhExpanded}` : _dsh_plugin_shop_css_e3675a89_default.summaryZh,
7160
7216
  children: summary.zh
7161
7217
  }),
7162
7218
  blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7163
- className: _dsh_plugin_shop_css_26093961_default.incompatibleDetail,
7219
+ className: _dsh_plugin_shop_css_e3675a89_default.incompatibleDetail,
7164
7220
  "data-shop-incompatible-detail": true,
7165
7221
  children: blocker.text
7166
7222
  }, blocker.kind)),
7167
7223
  open && entry.catalog !== void 0 && entry.catalog.capabilities.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7168
- className: _dsh_plugin_shop_css_26093961_default.capabilitiesBlock,
7224
+ className: _dsh_plugin_shop_css_e3675a89_default.capabilitiesBlock,
7169
7225
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7170
- className: _dsh_plugin_shop_css_26093961_default.capabilitiesNote,
7226
+ className: _dsh_plugin_shop_css_e3675a89_default.capabilitiesNote,
7171
7227
  children: t("capabilitiesNote")
7172
7228
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
7173
- className: _dsh_plugin_shop_css_26093961_default.capabilities,
7229
+ className: _dsh_plugin_shop_css_e3675a89_default.capabilities,
7174
7230
  children: entry.catalog.capabilities.map((capability) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: capability }, capability))
7175
7231
  })]
7176
7232
  }),
7177
7233
  open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
7178
7234
  id: detailId,
7179
- className: _dsh_plugin_shop_css_26093961_default.detail,
7235
+ className: _dsh_plugin_shop_css_e3675a89_default.detail,
7180
7236
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
7181
- className: _dsh_plugin_shop_css_26093961_default.detailRows,
7237
+ className: _dsh_plugin_shop_css_e3675a89_default.detailRows,
7182
7238
  children: [
7183
7239
  npmUrl !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7184
- className: _dsh_plugin_shop_css_26093961_default.detailRow,
7240
+ className: _dsh_plugin_shop_css_e3675a89_default.detailRow,
7185
7241
  "data-shop-npm": true,
7186
7242
  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", {
7187
7243
  href: npmUrl,
@@ -7191,7 +7247,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7191
7247
  }) })]
7192
7248
  }),
7193
7249
  entry.repository !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7194
- className: _dsh_plugin_shop_css_26093961_default.detailRow,
7250
+ className: _dsh_plugin_shop_css_e3675a89_default.detailRow,
7195
7251
  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", {
7196
7252
  href: entry.repository,
7197
7253
  target: "_blank",
@@ -7200,12 +7256,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7200
7256
  }) : entry.repository })]
7201
7257
  }),
7202
7258
  entry.license !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7203
- className: _dsh_plugin_shop_css_26093961_default.detailRow,
7259
+ className: _dsh_plugin_shop_css_e3675a89_default.detailRow,
7204
7260
  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 })]
7205
7261
  })
7206
7262
  ]
7207
7263
  }), entry.tier === "verified-stale" && entry.review !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7208
- className: _dsh_plugin_shop_css_26093961_default.reviewedLine,
7264
+ className: _dsh_plugin_shop_css_e3675a89_default.reviewedLine,
7209
7265
  children: entry.review.reviewedVersion !== void 0 ? t("reviewedVersionLine", {
7210
7266
  reviewed: entry.review.reviewedVersion,
7211
7267
  current: entry.version
@@ -7218,7 +7274,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7218
7274
  ]
7219
7275
  }),
7220
7276
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7221
- className: _dsh_plugin_shop_css_26093961_default.cardActions,
7277
+ className: _dsh_plugin_shop_css_e3675a89_default.cardActions,
7222
7278
  "data-shop-actions": true,
7223
7279
  children: [installed === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InstallPanel, {
7224
7280
  target: installTarget,
@@ -7243,7 +7299,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7243
7299
  restart,
7244
7300
  restartSupported
7245
7301
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7246
- className: _dsh_plugin_shop_css_26093961_default.installedLabel,
7302
+ className: _dsh_plugin_shop_css_e3675a89_default.installedLabel,
7247
7303
  "data-shop-installed": true,
7248
7304
  children: t("installed")
7249
7305
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerBadge, {
@@ -7264,10 +7320,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7264
7320
  restartSupported,
7265
7321
  onSettled: uninstallSettled
7266
7322
  })
7267
- ] }), author !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7268
- className: _dsh_plugin_shop_css_26093961_default.author,
7269
- "data-shop-author": true,
7270
- children: t("authorLine", { author })
7323
+ ] }), (size !== void 0 || author !== null) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7324
+ className: _dsh_plugin_shop_css_e3675a89_default.cardMeta,
7325
+ children: [size !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7326
+ className: _dsh_plugin_shop_css_e3675a89_default.size,
7327
+ "data-shop-size": true,
7328
+ role: "img",
7329
+ "aria-label": t("sizeLabel", { size }),
7330
+ title: t("sizeLabel", { size }),
7331
+ children: size
7332
+ }), author !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7333
+ className: _dsh_plugin_shop_css_e3675a89_default.author,
7334
+ "data-shop-author": true,
7335
+ children: t("authorLine", { author })
7336
+ })]
7271
7337
  })]
7272
7338
  })
7273
7339
  ]
@@ -7303,7 +7369,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7303
7369
  const detail = blockers.map((blocker) => blocker.text).join("\n");
7304
7370
  const taken = blockers.some((blocker) => blocker.kind === "name-taken");
7305
7371
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7306
- className: _dsh_plugin_shop_css_26093961_default.incompatibleBadge,
7372
+ className: _dsh_plugin_shop_css_e3675a89_default.incompatibleBadge,
7307
7373
  "data-shop-blocker": taken ? "name-taken" : "missing-peers",
7308
7374
  role: "img",
7309
7375
  "aria-label": detail,
@@ -7320,30 +7386,30 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7320
7386
  const [gateOpen, setGateOpen] = (0, react.useState)(false);
7321
7387
  const { view, start } = flow;
7322
7388
  if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7323
- className: _dsh_plugin_shop_css_26093961_default.installPanel,
7389
+ className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
7324
7390
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7325
- className: _dsh_plugin_shop_css_26093961_default.installing,
7391
+ className: _dsh_plugin_shop_css_e3675a89_default.installing,
7326
7392
  children: t("installing")
7327
7393
  }), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7328
- className: _dsh_plugin_shop_css_26093961_default.log,
7394
+ className: _dsh_plugin_shop_css_e3675a89_default.log,
7329
7395
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7330
- className: _dsh_plugin_shop_css_26093961_default.logLine,
7396
+ className: _dsh_plugin_shop_css_e3675a89_default.logLine,
7331
7397
  children: line
7332
7398
  }, index))
7333
7399
  })]
7334
7400
  });
7335
7401
  if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7336
- className: _dsh_plugin_shop_css_26093961_default.installedActions,
7402
+ className: _dsh_plugin_shop_css_e3675a89_default.installedActions,
7337
7403
  children: [
7338
7404
  view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7339
- className: _dsh_plugin_shop_css_26093961_default.log,
7405
+ className: _dsh_plugin_shop_css_e3675a89_default.log,
7340
7406
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7341
- className: _dsh_plugin_shop_css_26093961_default.logLine,
7407
+ className: _dsh_plugin_shop_css_e3675a89_default.logLine,
7342
7408
  children: line
7343
7409
  }, index))
7344
7410
  }),
7345
7411
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7346
- className: _dsh_plugin_shop_css_26093961_default.notice,
7412
+ className: _dsh_plugin_shop_css_e3675a89_default.notice,
7347
7413
  "data-shop-restart-notice": true,
7348
7414
  children: view.needsRestart ? t(restartReasonKey(view.restartReason)) : t("installedNoRestartNotice")
7349
7415
  }),
@@ -7352,63 +7418,63 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7352
7418
  restart
7353
7419
  }),
7354
7420
  view.needsRestart && !restartSupported && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7355
- className: _dsh_plugin_shop_css_26093961_default.notice,
7421
+ className: _dsh_plugin_shop_css_e3675a89_default.notice,
7356
7422
  "data-shop-restart-disabled": true,
7357
7423
  children: t("restartDisabledNotice")
7358
7424
  })
7359
7425
  ]
7360
7426
  });
7361
7427
  if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7362
- className: _dsh_plugin_shop_css_26093961_default.installPanel,
7428
+ className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
7363
7429
  children: [
7364
7430
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7365
- className: _dsh_plugin_shop_css_26093961_default.failedHeading,
7431
+ className: _dsh_plugin_shop_css_e3675a89_default.failedHeading,
7366
7432
  children: t("installFailed")
7367
7433
  }),
7368
7434
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7369
- className: _dsh_plugin_shop_css_26093961_default.log,
7435
+ className: _dsh_plugin_shop_css_e3675a89_default.log,
7370
7436
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7371
- className: _dsh_plugin_shop_css_26093961_default.logLine,
7437
+ className: _dsh_plugin_shop_css_e3675a89_default.logLine,
7372
7438
  children: line
7373
7439
  }, index))
7374
7440
  }),
7375
7441
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7376
- className: _dsh_plugin_shop_css_26093961_default.failedDetail,
7442
+ className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
7377
7443
  children: view.detail === "" ? t("installTransportFailed") : view.detail
7378
7444
  })
7379
7445
  ]
7380
7446
  });
7381
7447
  if (view.kind === "rejected") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7382
- className: _dsh_plugin_shop_css_26093961_default.installPanel,
7448
+ className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
7383
7449
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7384
- className: _dsh_plugin_shop_css_26093961_default.rejectedCode,
7450
+ className: _dsh_plugin_shop_css_e3675a89_default.rejectedCode,
7385
7451
  children: t(rejectionCodeKey(view.code))
7386
7452
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7387
- className: _dsh_plugin_shop_css_26093961_default.rejectedDetail,
7453
+ className: _dsh_plugin_shop_css_e3675a89_default.rejectedDetail,
7388
7454
  children: view.detail
7389
7455
  })]
7390
7456
  });
7391
7457
  if (gateOpen) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7392
- className: _dsh_plugin_shop_css_26093961_default.gate,
7458
+ className: _dsh_plugin_shop_css_e3675a89_default.gate,
7393
7459
  children: [
7394
7460
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7395
- className: _dsh_plugin_shop_css_26093961_default.gateTitle,
7461
+ className: _dsh_plugin_shop_css_e3675a89_default.gateTitle,
7396
7462
  children: t("acknowledgementTitle")
7397
7463
  }),
7398
7464
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7399
- className: _dsh_plugin_shop_css_26093961_default.gateBody,
7465
+ className: _dsh_plugin_shop_css_e3675a89_default.gateBody,
7400
7466
  children: t("acknowledgementBody")
7401
7467
  }),
7402
7468
  !missingStated && blockersOf(missing, void 0, t).map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7403
- className: _dsh_plugin_shop_css_26093961_default.gateWarning,
7469
+ className: _dsh_plugin_shop_css_e3675a89_default.gateWarning,
7404
7470
  "data-shop-incompatible-warning": true,
7405
7471
  children: blocker.text
7406
7472
  }, blocker.kind)),
7407
7473
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7408
- className: _dsh_plugin_shop_css_26093961_default.gateActions,
7474
+ className: _dsh_plugin_shop_css_e3675a89_default.gateActions,
7409
7475
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7410
7476
  type: "button",
7411
- className: _dsh_plugin_shop_css_26093961_default.confirmButton,
7477
+ className: _dsh_plugin_shop_css_e3675a89_default.confirmButton,
7412
7478
  "data-shop-confirm": true,
7413
7479
  onClick: () => {
7414
7480
  setGateOpen(false);
@@ -7420,7 +7486,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7420
7486
  children: t("confirm")
7421
7487
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7422
7488
  type: "button",
7423
- className: _dsh_plugin_shop_css_26093961_default.cancelButton,
7489
+ className: _dsh_plugin_shop_css_e3675a89_default.cancelButton,
7424
7490
  onClick: () => setGateOpen(false),
7425
7491
  children: t("cancel")
7426
7492
  })]
@@ -7431,7 +7497,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7431
7497
  const refused = blockers.some((blocker) => blocker.kind === "name-taken");
7432
7498
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7433
7499
  type: "button",
7434
- className: _dsh_plugin_shop_css_26093961_default.installButton,
7500
+ className: _dsh_plugin_shop_css_e3675a89_default.installButton,
7435
7501
  disabled: refused,
7436
7502
  ...refused ? { "data-shop-refused": true } : {},
7437
7503
  ...update ? { "data-shop-update": true } : { "data-shop-install": true },
@@ -7462,23 +7528,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7462
7528
  if (view.kind === "done") settled.current();
7463
7529
  }, [view.kind]);
7464
7530
  if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7465
- className: _dsh_plugin_shop_css_26093961_default.installPanel,
7531
+ className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
7466
7532
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7467
- className: _dsh_plugin_shop_css_26093961_default.installing,
7533
+ className: _dsh_plugin_shop_css_e3675a89_default.installing,
7468
7534
  children: t("uninstalling")
7469
7535
  }), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7470
- className: _dsh_plugin_shop_css_26093961_default.log,
7536
+ className: _dsh_plugin_shop_css_e3675a89_default.log,
7471
7537
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7472
- className: _dsh_plugin_shop_css_26093961_default.logLine,
7538
+ className: _dsh_plugin_shop_css_e3675a89_default.logLine,
7473
7539
  children: line
7474
7540
  }, index))
7475
7541
  })]
7476
7542
  });
7477
7543
  if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7478
- className: _dsh_plugin_shop_css_26093961_default.installedActions,
7544
+ className: _dsh_plugin_shop_css_e3675a89_default.installedActions,
7479
7545
  children: [
7480
7546
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7481
- className: _dsh_plugin_shop_css_26093961_default.notice,
7547
+ className: _dsh_plugin_shop_css_e3675a89_default.notice,
7482
7548
  "data-shop-uninstall-done": true,
7483
7549
  children: view.needsRestart ? t("uninstalledRestartNotice") : t("uninstalledLiveNotice")
7484
7550
  }),
@@ -7487,28 +7553,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7487
7553
  restart
7488
7554
  }),
7489
7555
  view.needsRestart && !restartSupported && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7490
- className: _dsh_plugin_shop_css_26093961_default.notice,
7556
+ className: _dsh_plugin_shop_css_e3675a89_default.notice,
7491
7557
  "data-shop-restart-disabled": true,
7492
7558
  children: t("restartDisabledNotice")
7493
7559
  })
7494
7560
  ]
7495
7561
  });
7496
7562
  if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7497
- className: _dsh_plugin_shop_css_26093961_default.installPanel,
7563
+ className: _dsh_plugin_shop_css_e3675a89_default.installPanel,
7498
7564
  children: [
7499
7565
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7500
- className: _dsh_plugin_shop_css_26093961_default.failedHeading,
7566
+ className: _dsh_plugin_shop_css_e3675a89_default.failedHeading,
7501
7567
  children: t("uninstallFailed")
7502
7568
  }),
7503
7569
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7504
- className: _dsh_plugin_shop_css_26093961_default.log,
7570
+ className: _dsh_plugin_shop_css_e3675a89_default.log,
7505
7571
  children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7506
- className: _dsh_plugin_shop_css_26093961_default.logLine,
7572
+ className: _dsh_plugin_shop_css_e3675a89_default.logLine,
7507
7573
  children: line
7508
7574
  }, index))
7509
7575
  }),
7510
7576
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7511
- className: _dsh_plugin_shop_css_26093961_default.failedDetail,
7577
+ className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
7512
7578
  children: view.detail === "" ? t("uninstallTransportFailed") : view.detail
7513
7579
  })
7514
7580
  ]
@@ -7516,7 +7582,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7516
7582
  if (view.kind !== "idle") return null;
7517
7583
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7518
7584
  type: "button",
7519
- className: _dsh_plugin_shop_css_26093961_default.uninstallButton,
7585
+ className: _dsh_plugin_shop_css_e3675a89_default.uninstallButton,
7520
7586
  "data-shop-uninstall": true,
7521
7587
  onClick: () => void start({ name }),
7522
7588
  children: t("uninstall")
@@ -7578,37 +7644,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7578
7644
  return () => clearInterval(timer);
7579
7645
  }, [state, t]);
7580
7646
  if (state.kind === "restarting") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7581
- className: _dsh_plugin_shop_css_26093961_default.notice,
7647
+ className: _dsh_plugin_shop_css_e3675a89_default.notice,
7582
7648
  "data-shop-restarting": true,
7583
7649
  children: t("restarting")
7584
7650
  });
7585
7651
  if (state.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7586
- className: _dsh_plugin_shop_css_26093961_default.failedDetail,
7652
+ className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
7587
7653
  "data-shop-restart-error": true,
7588
7654
  children: state.detail
7589
7655
  });
7590
7656
  if (gateOpen) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7591
- className: _dsh_plugin_shop_css_26093961_default.gate,
7657
+ className: _dsh_plugin_shop_css_e3675a89_default.gate,
7592
7658
  children: [
7593
7659
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7594
- className: _dsh_plugin_shop_css_26093961_default.gateTitle,
7660
+ className: _dsh_plugin_shop_css_e3675a89_default.gateTitle,
7595
7661
  children: t("restartTitle")
7596
7662
  }),
7597
7663
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7598
- className: _dsh_plugin_shop_css_26093961_default.gateBody,
7664
+ className: _dsh_plugin_shop_css_e3675a89_default.gateBody,
7599
7665
  children: t("restartBody")
7600
7666
  }),
7601
7667
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7602
- className: _dsh_plugin_shop_css_26093961_default.gateActions,
7668
+ className: _dsh_plugin_shop_css_e3675a89_default.gateActions,
7603
7669
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7604
7670
  type: "button",
7605
- className: _dsh_plugin_shop_css_26093961_default.confirmButton,
7671
+ className: _dsh_plugin_shop_css_e3675a89_default.confirmButton,
7606
7672
  "data-shop-restart-confirm": true,
7607
7673
  onClick: () => void onConfirm(),
7608
7674
  children: t("restartConfirm")
7609
7675
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7610
7676
  type: "button",
7611
- className: _dsh_plugin_shop_css_26093961_default.cancelButton,
7677
+ className: _dsh_plugin_shop_css_e3675a89_default.cancelButton,
7612
7678
  onClick: () => setGateOpen(false),
7613
7679
  children: t("cancel")
7614
7680
  })]
@@ -7618,7 +7684,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7618
7684
  if (gate !== void 0) return null;
7619
7685
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7620
7686
  type: "button",
7621
- className: _dsh_plugin_shop_css_26093961_default.restartButton,
7687
+ className: _dsh_plugin_shop_css_e3675a89_default.restartButton,
7622
7688
  "data-shop-restart": true,
7623
7689
  onClick: () => setGateOpen(true),
7624
7690
  children: t("restart")
@@ -7658,7 +7724,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7658
7724
  }
7659
7725
  };
7660
7726
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7661
- className: _dsh_plugin_shop_css_26093961_default.switchWrap,
7727
+ className: _dsh_plugin_shop_css_e3675a89_default.switchWrap,
7662
7728
  "data-shop-enabled-switch": row.name,
7663
7729
  children: [
7664
7730
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
@@ -7667,18 +7733,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7667
7733
  "aria-checked": enabled,
7668
7734
  "aria-label": t("enabledSwitch"),
7669
7735
  "data-shop-toggle": true,
7670
- className: `${_dsh_plugin_shop_css_26093961_default.switch} ${enabled ? _dsh_plugin_shop_css_26093961_default.switchOn : ""}`,
7736
+ className: `${_dsh_plugin_shop_css_e3675a89_default.switch} ${enabled ? _dsh_plugin_shop_css_e3675a89_default.switchOn : ""}`,
7671
7737
  onClick: () => void onToggle(),
7672
7738
  disabled: toggle.kind === "saving",
7673
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_26093961_default.switchKnob })
7739
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.switchKnob })
7674
7740
  }),
7675
7741
  toggle.kind === "saved" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7676
- className: _dsh_plugin_shop_css_26093961_default.notice,
7742
+ className: _dsh_plugin_shop_css_e3675a89_default.notice,
7677
7743
  "data-shop-hot-apply": true,
7678
7744
  children: t("hotApplyNote")
7679
7745
  }),
7680
7746
  toggle.kind === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7681
- className: _dsh_plugin_shop_css_26093961_default.failedDetail,
7747
+ className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
7682
7748
  "data-shop-toggle-error": true,
7683
7749
  children: toggle.detail
7684
7750
  })
@@ -7690,19 +7756,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7690
7756
  * install flow for `name@latest`, reusing `InstallPanel`). */
7691
7757
  function OutdatedRow({ row, tier, missing, t, setEnabled, flowFor, restart, restartSupported }) {
7692
7758
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7693
- className: _dsh_plugin_shop_css_26093961_default.outdatedRow,
7759
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedRow,
7694
7760
  "data-shop-outdated-entry": row.name,
7695
7761
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7696
- className: _dsh_plugin_shop_css_26093961_default.outdatedInfo,
7762
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedInfo,
7697
7763
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
7698
- className: _dsh_plugin_shop_css_26093961_default.name,
7764
+ className: _dsh_plugin_shop_css_e3675a89_default.name,
7699
7765
  children: row.name
7700
7766
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
7701
- className: _dsh_plugin_shop_css_26093961_default.outdatedVersions,
7767
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedVersions,
7702
7768
  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 }) })]
7703
7769
  })]
7704
7770
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7705
- className: _dsh_plugin_shop_css_26093961_default.outdatedActions,
7771
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedActions,
7706
7772
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EnabledSwitch, {
7707
7773
  row,
7708
7774
  t,
@@ -7737,20 +7803,20 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7737
7803
  function OutdatedSection({ state, entriesByKey, missingByKey, t, setEnabled, flowFor, restart, restartSupported }) {
7738
7804
  if (state.kind === "loading") return null;
7739
7805
  if (state.kind === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7740
- className: _dsh_plugin_shop_css_26093961_default.stateLine,
7806
+ className: _dsh_plugin_shop_css_e3675a89_default.stateLine,
7741
7807
  "data-shop-outdated-error": true,
7742
7808
  children: t("error")
7743
7809
  });
7744
7810
  const outdated = state.entries.filter((entry) => entry.outdated);
7745
7811
  if (outdated.length === 0) return null;
7746
7812
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
7747
- className: _dsh_plugin_shop_css_26093961_default.outdatedSection,
7813
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedSection,
7748
7814
  "data-shop-outdated": true,
7749
7815
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
7750
- className: _dsh_plugin_shop_css_26093961_default.catalogHeading,
7816
+ className: _dsh_plugin_shop_css_e3675a89_default.catalogHeading,
7751
7817
  children: t("installedSection")
7752
7818
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
7753
- className: _dsh_plugin_shop_css_26093961_default.outdatedList,
7819
+ className: _dsh_plugin_shop_css_e3675a89_default.outdatedList,
7754
7820
  children: outdated.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutdatedRow, {
7755
7821
  row,
7756
7822
  tier: entriesByKey.get(identityKey(row))?.tier ?? "community",
@@ -7789,6 +7855,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7789
7855
  const [reloadFailed, setReloadFailed] = (0, react.useState)(false);
7790
7856
  const [query, setQuery] = (0, react.useState)("");
7791
7857
  const [category, setCategory] = (0, react.useState)(null);
7858
+ const [hideIncompatible, setHideIncompatible] = (0, react.useState)(false);
7792
7859
  const incremental = typeof IntersectionObserver !== "undefined";
7793
7860
  const [visibleCount, setVisibleCount] = (0, react.useState)(48);
7794
7861
  const sentinelRef = (0, react.useRef)(null);
@@ -7887,7 +7954,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7887
7954
  }, [catalogState]);
7888
7955
  const stars = (0, react.useMemo)(() => catalogState.kind === "ready" ? catalogState.result.stars : {}, [catalogState]);
7889
7956
  const sortedBrowsable = (0, react.useMemo)(() => sortByStars(browsable, stars), [browsable, stars]);
7890
- const filtered = (0, react.useMemo)(() => {
7957
+ const missingByKey = (0, react.useMemo)(() => {
7958
+ const map = /* @__PURE__ */ new Map();
7959
+ if (catalogState.kind === "ready") for (const entry of catalogState.result.plugins) map.set(entryKey(entry), missingPeersOf(catalogState.result.incompatible, entryKey(entry)));
7960
+ return map;
7961
+ }, [catalogState]);
7962
+ const nameTakenByKey = (0, react.useMemo)(() => {
7963
+ const map = /* @__PURE__ */ new Map();
7964
+ if (catalogState.kind !== "ready") return map;
7965
+ for (const entry of catalogState.result.plugins) {
7966
+ const holder = heldBy(entry, specs);
7967
+ if (holder !== void 0) map.set(entryKey(entry), holder);
7968
+ }
7969
+ return map;
7970
+ }, [catalogState, specs]);
7971
+ const badgedIncompatible = (0, react.useCallback)((key) => (missingByKey.get(key) ?? []).length > 0 && !nameTakenByKey.has(key), [missingByKey, nameTakenByKey]);
7972
+ const matched = (0, react.useMemo)(() => {
7891
7973
  const q = query.trim().toLowerCase();
7892
7974
  return sortedBrowsable.filter((entry) => {
7893
7975
  if (category === "installed") {
@@ -7904,6 +7986,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7904
7986
  category,
7905
7987
  installedByKey
7906
7988
  ]);
7989
+ const filtered = (0, react.useMemo)(() => hideIncompatible && category !== "installed" ? matched.filter((entry) => !badgedIncompatible(entryKey(entry))) : matched, [
7990
+ matched,
7991
+ hideIncompatible,
7992
+ category,
7993
+ badgedIncompatible
7994
+ ]);
7907
7995
  filteredLenRef.current = filtered.length;
7908
7996
  (0, react.useEffect)(() => {
7909
7997
  if (!incremental) return;
@@ -7933,70 +8021,57 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7933
8021
  if (installedState.kind !== "ready") return 0;
7934
8022
  return installedState.entries.filter((entry) => !isShopLike(entry.name)).length;
7935
8023
  }, [installedState]);
8024
+ const incompatibleCount = (0, react.useMemo)(() => browsable.filter((entry) => badgedIncompatible(entryKey(entry))).length, [browsable, badgedIncompatible]);
7936
8025
  const entriesByKey = (0, react.useMemo)(() => {
7937
8026
  const map = /* @__PURE__ */ new Map();
7938
8027
  if (catalogState.kind === "ready") for (const entry of catalogState.result.plugins) map.set(entryKey(entry), entry);
7939
8028
  return map;
7940
8029
  }, [catalogState]);
7941
- const missingByKey = (0, react.useMemo)(() => {
7942
- const map = /* @__PURE__ */ new Map();
7943
- if (catalogState.kind === "ready") for (const entry of catalogState.result.plugins) map.set(entryKey(entry), missingPeersOf(catalogState.result.incompatible, entryKey(entry)));
7944
- return map;
7945
- }, [catalogState]);
7946
- const nameTakenByKey = (0, react.useMemo)(() => {
7947
- const map = /* @__PURE__ */ new Map();
7948
- if (catalogState.kind !== "ready") return map;
7949
- for (const entry of catalogState.result.plugins) {
7950
- const holder = heldBy(entry, specs);
7951
- if (holder !== void 0) map.set(entryKey(entry), holder);
7952
- }
7953
- return map;
7954
- }, [catalogState, specs]);
7955
8030
  if (catalogState.kind === "loading") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7956
- className: _dsh_plugin_shop_css_26093961_default.panel,
8031
+ className: _dsh_plugin_shop_css_e3675a89_default.panel,
7957
8032
  "data-shop-tab": true,
7958
8033
  "aria-busy": "true",
7959
8034
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7960
- className: _dsh_plugin_shop_css_26093961_default.srOnly,
8035
+ className: _dsh_plugin_shop_css_e3675a89_default.srOnly,
7961
8036
  children: t("loading")
7962
8037
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7963
- className: _dsh_plugin_shop_css_26093961_default.skeletonGrid,
8038
+ className: _dsh_plugin_shop_css_e3675a89_default.skeletonGrid,
7964
8039
  "data-shop-skeleton": true,
7965
8040
  "aria-hidden": "true",
7966
8041
  children: Array.from({ length: 8 }, (_, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7967
- className: _dsh_plugin_shop_css_26093961_default.skeletonCard,
8042
+ className: _dsh_plugin_shop_css_e3675a89_default.skeletonCard,
7968
8043
  children: [
7969
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_26093961_default.skeletonName }),
7970
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_26093961_default.skeletonSummary }),
7971
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_26093961_default.skeletonSummaryShort }),
7972
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_26093961_default.skeletonActions })
8044
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonName }),
8045
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonSummary }),
8046
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonSummaryShort }),
8047
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_e3675a89_default.skeletonActions })
7973
8048
  ]
7974
8049
  }, i))
7975
8050
  })]
7976
8051
  });
7977
8052
  if (catalogState.kind === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7978
- className: _dsh_plugin_shop_css_26093961_default.panel,
8053
+ className: _dsh_plugin_shop_css_e3675a89_default.panel,
7979
8054
  "data-shop-tab": true,
7980
8055
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
7981
- className: _dsh_plugin_shop_css_26093961_default.stateLine,
8056
+ className: _dsh_plugin_shop_css_e3675a89_default.stateLine,
7982
8057
  children: t("error")
7983
8058
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
7984
8059
  type: "button",
7985
- className: _dsh_plugin_shop_css_26093961_default.actionButton,
8060
+ className: _dsh_plugin_shop_css_e3675a89_default.actionButton,
7986
8061
  onClick: () => setRequest({ kind: "retry" }),
7987
8062
  children: t("retry")
7988
8063
  })]
7989
8064
  });
7990
8065
  const { result } = catalogState;
7991
8066
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7992
- className: _dsh_plugin_shop_css_26093961_default.panel,
8067
+ className: _dsh_plugin_shop_css_e3675a89_default.panel,
7993
8068
  "data-shop-tab": true,
7994
8069
  children: [
7995
8070
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7996
- className: _dsh_plugin_shop_css_26093961_default.toolbar,
8071
+ className: _dsh_plugin_shop_css_e3675a89_default.toolbar,
7997
8072
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
7998
8073
  type: "search",
7999
- className: _dsh_plugin_shop_css_26093961_default.searchInput,
8074
+ className: _dsh_plugin_shop_css_e3675a89_default.searchInput,
8000
8075
  "aria-label": t("search"),
8001
8076
  placeholder: t("search"),
8002
8077
  value: query,
@@ -8005,27 +8080,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8005
8080
  setVisibleCount(48);
8006
8081
  }
8007
8082
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8008
- className: _dsh_plugin_shop_css_26093961_default.toolbarRight,
8083
+ className: _dsh_plugin_shop_css_e3675a89_default.toolbarRight,
8009
8084
  children: [
8010
8085
  result.stale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8011
- className: _dsh_plugin_shop_css_26093961_default.staleBadge,
8086
+ className: _dsh_plugin_shop_css_e3675a89_default.staleBadge,
8012
8087
  children: t("staleLabel", { date: result.builtAt.slice(0, 10) })
8013
8088
  }),
8014
8089
  selfVersion !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8015
- className: _dsh_plugin_shop_css_26093961_default.versionBlock,
8090
+ className: _dsh_plugin_shop_css_e3675a89_default.versionBlock,
8016
8091
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
8017
- className: _dsh_plugin_shop_css_26093961_default.versionText,
8092
+ className: _dsh_plugin_shop_css_e3675a89_default.versionText,
8018
8093
  "data-shop-version": true,
8019
8094
  children: ["v", selfVersion.installed]
8020
8095
  }), selfUpdate.view.kind === "done" && restartSupported ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8021
8096
  type: "button",
8022
- className: _dsh_plugin_shop_css_26093961_default.restartSelfButton,
8097
+ className: _dsh_plugin_shop_css_e3675a89_default.restartSelfButton,
8023
8098
  "data-shop-restart": true,
8024
8099
  onClick: () => setSelfRestartGate(true),
8025
8100
  children: t("restart")
8026
8101
  }) : selfVersion.outdated && selfVersion.latest !== null && selfUpdate.view.kind === "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8027
8102
  type: "button",
8028
- className: _dsh_plugin_shop_css_26093961_default.updateSelfButton,
8103
+ className: _dsh_plugin_shop_css_e3675a89_default.updateSelfButton,
8029
8104
  "data-shop-update-self": true,
8030
8105
  onClick: () => {
8031
8106
  if (selfVersion.latest !== null) selfUpdate.start({ version: selfVersion.latest });
@@ -8033,7 +8108,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8033
8108
  children: t("update")
8034
8109
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8035
8110
  type: "button",
8036
- className: _dsh_plugin_shop_css_26093961_default.checkUpdateButton,
8111
+ className: _dsh_plugin_shop_css_e3675a89_default.checkUpdateButton,
8037
8112
  "data-shop-check-update": true,
8038
8113
  title: t("checkUpdateTitle"),
8039
8114
  disabled: checkState !== "idle",
@@ -8042,7 +8117,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8042
8117
  })]
8043
8118
  }),
8044
8119
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
8045
- className: _dsh_plugin_shop_css_26093961_default.githubLink,
8120
+ className: _dsh_plugin_shop_css_e3675a89_default.githubLink,
8046
8121
  href: SHOP_REPO_URL,
8047
8122
  target: "_blank",
8048
8123
  rel: "noopener noreferrer",
@@ -8061,27 +8136,27 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8061
8136
  })]
8062
8137
  }),
8063
8138
  selfUpdate.view.kind === "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8064
- className: _dsh_plugin_shop_css_26093961_default.selfUpdatePanel,
8139
+ className: _dsh_plugin_shop_css_e3675a89_default.selfUpdatePanel,
8065
8140
  "data-shop-self-updating": true,
8066
8141
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8067
- className: _dsh_plugin_shop_css_26093961_default.installing,
8142
+ className: _dsh_plugin_shop_css_e3675a89_default.installing,
8068
8143
  children: t("installing")
8069
8144
  }), selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8070
- className: _dsh_plugin_shop_css_26093961_default.log,
8145
+ className: _dsh_plugin_shop_css_e3675a89_default.log,
8071
8146
  children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8072
- className: _dsh_plugin_shop_css_26093961_default.logLine,
8147
+ className: _dsh_plugin_shop_css_e3675a89_default.logLine,
8073
8148
  children: line
8074
8149
  }, index))
8075
8150
  })]
8076
8151
  }),
8077
8152
  selfUpdate.view.kind === "done" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8078
- className: _dsh_plugin_shop_css_26093961_default.selfUpdatePanel,
8153
+ className: _dsh_plugin_shop_css_e3675a89_default.selfUpdatePanel,
8079
8154
  "data-shop-self-update-done": true,
8080
8155
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8081
- className: _dsh_plugin_shop_css_26093961_default.installedActions,
8156
+ className: _dsh_plugin_shop_css_e3675a89_default.installedActions,
8082
8157
  children: [
8083
8158
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8084
- className: _dsh_plugin_shop_css_26093961_default.notice,
8159
+ className: _dsh_plugin_shop_css_e3675a89_default.notice,
8085
8160
  children: t("installedRestartNotice")
8086
8161
  }),
8087
8162
  restartSupported && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RestartPanel, {
@@ -8093,7 +8168,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8093
8168
  }
8094
8169
  }),
8095
8170
  !restartSupported && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8096
- className: _dsh_plugin_shop_css_26093961_default.notice,
8171
+ className: _dsh_plugin_shop_css_e3675a89_default.notice,
8097
8172
  "data-shop-restart-disabled": true,
8098
8173
  children: t("restartDisabledNotice")
8099
8174
  })
@@ -8101,34 +8176,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8101
8176
  })
8102
8177
  }),
8103
8178
  selfUpdate.view.kind === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8104
- className: _dsh_plugin_shop_css_26093961_default.selfUpdatePanel,
8179
+ className: _dsh_plugin_shop_css_e3675a89_default.selfUpdatePanel,
8105
8180
  "data-shop-self-update-failed": true,
8106
8181
  children: [
8107
8182
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8108
- className: _dsh_plugin_shop_css_26093961_default.failedHeading,
8183
+ className: _dsh_plugin_shop_css_e3675a89_default.failedHeading,
8109
8184
  children: t("updateFailed")
8110
8185
  }),
8111
8186
  selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8112
- className: _dsh_plugin_shop_css_26093961_default.log,
8187
+ className: _dsh_plugin_shop_css_e3675a89_default.log,
8113
8188
  children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8114
- className: _dsh_plugin_shop_css_26093961_default.logLine,
8189
+ className: _dsh_plugin_shop_css_e3675a89_default.logLine,
8115
8190
  children: line
8116
8191
  }, index))
8117
8192
  }),
8118
8193
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8119
- className: _dsh_plugin_shop_css_26093961_default.failedDetail,
8194
+ className: _dsh_plugin_shop_css_e3675a89_default.failedDetail,
8120
8195
  children: selfUpdate.view.detail === "" ? t("updateTransportFailed") : selfUpdate.view.detail
8121
8196
  })
8122
8197
  ]
8123
8198
  }),
8124
8199
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8125
- className: _dsh_plugin_shop_css_26093961_default.categoryBar,
8200
+ className: _dsh_plugin_shop_css_e3675a89_default.categoryBar,
8126
8201
  role: "group",
8127
8202
  "aria-label": t("catalog"),
8128
8203
  children: [
8129
8204
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8130
8205
  type: "button",
8131
- className: category === null ? `${_dsh_plugin_shop_css_26093961_default.categoryButton} ${_dsh_plugin_shop_css_26093961_default.categoryButtonOn}` : _dsh_plugin_shop_css_26093961_default.categoryButton,
8206
+ className: category === null ? `${_dsh_plugin_shop_css_e3675a89_default.categoryButton} ${_dsh_plugin_shop_css_e3675a89_default.categoryButtonOn}` : _dsh_plugin_shop_css_e3675a89_default.categoryButton,
8132
8207
  "aria-pressed": category === null,
8133
8208
  onClick: () => {
8134
8209
  setCategory(null);
@@ -8143,8 +8218,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8143
8218
  }),
8144
8219
  CATEGORY_ORDER.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8145
8220
  type: "button",
8146
- className: category === key ? `${_dsh_plugin_shop_css_26093961_default.categoryButton} ${_dsh_plugin_shop_css_26093961_default.categoryButtonOn}` : _dsh_plugin_shop_css_26093961_default.categoryButton,
8221
+ className: category === key ? `${_dsh_plugin_shop_css_e3675a89_default.categoryButton} ${_dsh_plugin_shop_css_e3675a89_default.categoryButtonOn}` : _dsh_plugin_shop_css_e3675a89_default.categoryButton,
8147
8222
  "aria-pressed": category === key,
8223
+ "data-category": key,
8224
+ "data-shop-category-tab": key,
8148
8225
  onClick: () => {
8149
8226
  setCategory(key);
8150
8227
  setVisibleCount(48);
@@ -8157,8 +8234,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8157
8234
  }, key)),
8158
8235
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
8159
8236
  type: "button",
8160
- className: category === "installed" ? `${_dsh_plugin_shop_css_26093961_default.categoryButton} ${_dsh_plugin_shop_css_26093961_default.categoryButtonOn}` : _dsh_plugin_shop_css_26093961_default.categoryButton,
8237
+ className: category === "installed" ? `${_dsh_plugin_shop_css_e3675a89_default.categoryButton} ${_dsh_plugin_shop_css_e3675a89_default.categoryButtonOn}` : _dsh_plugin_shop_css_e3675a89_default.categoryButton,
8161
8238
  "aria-pressed": category === "installed",
8239
+ "data-shop-category-installed": true,
8162
8240
  onClick: () => {
8163
8241
  setCategory("installed");
8164
8242
  setVisibleCount(48);
@@ -8168,14 +8246,25 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8168
8246
  " ",
8169
8247
  installedCount
8170
8248
  ]
8249
+ }),
8250
+ category !== "installed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8251
+ type: "button",
8252
+ className: hideIncompatible ? `${_dsh_plugin_shop_css_e3675a89_default.categoryButton} ${_dsh_plugin_shop_css_e3675a89_default.incompatibleFilter} ${_dsh_plugin_shop_css_e3675a89_default.categoryButtonOn}` : `${_dsh_plugin_shop_css_e3675a89_default.categoryButton} ${_dsh_plugin_shop_css_e3675a89_default.incompatibleFilter}`,
8253
+ title: t(hideIncompatible ? "showIncompatibleTitle" : "incompatibleFilterTitle"),
8254
+ "data-shop-hide-incompatible": true,
8255
+ onClick: () => {
8256
+ setHideIncompatible((current) => !current);
8257
+ setVisibleCount(48);
8258
+ },
8259
+ children: t(hideIncompatible ? "showIncompatible" : "hideIncompatible", { count: incompatibleCount })
8171
8260
  })
8172
8261
  ]
8173
8262
  }),
8174
8263
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8175
- className: _dsh_plugin_shop_css_26093961_default.catalogStatsRow,
8264
+ className: _dsh_plugin_shop_css_e3675a89_default.catalogStatsRow,
8176
8265
  children: [
8177
8266
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8178
- className: _dsh_plugin_shop_css_26093961_default.catalogStats,
8267
+ className: _dsh_plugin_shop_css_e3675a89_default.catalogStats,
8179
8268
  "data-shop-catalog-stats": true,
8180
8269
  children: t("catalogStats", {
8181
8270
  count: String(browsable.length),
@@ -8184,7 +8273,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8184
8273
  }),
8185
8274
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8186
8275
  type: "button",
8187
- className: _dsh_plugin_shop_css_26093961_default.reloadButton,
8276
+ className: _dsh_plugin_shop_css_e3675a89_default.reloadButton,
8188
8277
  "data-shop-reload": true,
8189
8278
  disabled: reloading,
8190
8279
  onClick: () => {
@@ -8195,20 +8284,21 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8195
8284
  children: reloading ? t("refreshing") : t("refresh")
8196
8285
  }),
8197
8286
  reloadFailed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8198
- className: _dsh_plugin_shop_css_26093961_default.reloadFailed,
8287
+ className: _dsh_plugin_shop_css_e3675a89_default.reloadFailed,
8199
8288
  "data-shop-reload-failed": true,
8200
8289
  children: t("refreshFailed")
8201
8290
  })
8202
8291
  ]
8203
8292
  }),
8204
8293
  result.plugins.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8205
- className: _dsh_plugin_shop_css_26093961_default.emptyLine,
8294
+ className: _dsh_plugin_shop_css_e3675a89_default.emptyLine,
8206
8295
  children: t("empty")
8207
8296
  }) : filtered.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8208
- className: _dsh_plugin_shop_css_26093961_default.emptyLine,
8209
- children: t("emptySearch")
8297
+ className: _dsh_plugin_shop_css_e3675a89_default.emptyLine,
8298
+ "data-shop-empty": true,
8299
+ children: matched.length > 0 ? t("emptyIncompatibleFiltered") : t("emptySearch")
8210
8300
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
8211
- className: _dsh_plugin_shop_css_26093961_default.cards,
8301
+ className: _dsh_plugin_shop_css_e3675a89_default.cards,
8212
8302
  children: [visible.map((entry) => {
8213
8303
  const key = entryKey(entry);
8214
8304
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryCard, {
@@ -8228,12 +8318,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8228
8318
  }) }, key);
8229
8319
  }), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
8230
8320
  ref: sentinelRef,
8231
- className: _dsh_plugin_shop_css_26093961_default.cardsSentry,
8321
+ className: _dsh_plugin_shop_css_e3675a89_default.cardsSentry,
8232
8322
  "data-shop-sentry": true,
8233
8323
  "aria-hidden": "true"
8234
8324
  })]
8235
8325
  }), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
8236
- className: _dsh_plugin_shop_css_26093961_default.showingLine,
8326
+ className: _dsh_plugin_shop_css_e3675a89_default.showingLine,
8237
8327
  "aria-live": "polite",
8238
8328
  children: t("showing", {
8239
8329
  shown: String(visibleCount),