dsh-plugin-shop 0.9.1-beta.0 → 0.9.1-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +605 -567
- package/lib/types/client/locales.d.ts +8 -0
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -4800,6 +4800,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4800
4800
|
/** The shelf's order control, and the date each card carries under the two
|
|
4801
4801
|
* date orders (design 2026-10-12-shelf-orders §4). */
|
|
4802
4802
|
sortLabel: "排序",
|
|
4803
|
+
/** The wide layout's rail headings (design 2026-11-02-shop-widescreen-layout
|
|
4804
|
+
* §4): the category group above, the hide-incompatible modifier below. */
|
|
4805
|
+
categoriesHeading: "分类",
|
|
4806
|
+
filterHeading: "筛选",
|
|
4803
4807
|
sortStars: "星标最多",
|
|
4804
4808
|
sortAdded: "最新上架",
|
|
4805
4809
|
sortUpdated: "最近更新",
|
|
@@ -4989,6 +4993,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4989
4993
|
/** The shelf's order control, and the date each card carries under the two
|
|
4990
4994
|
* date orders (design 2026-10-12-shelf-orders §4). */
|
|
4991
4995
|
sortLabel: "Sort",
|
|
4996
|
+
/** The wide layout's rail headings (design 2026-11-02-shop-widescreen-layout
|
|
4997
|
+
* §4): the category group above, the hide-incompatible modifier below. */
|
|
4998
|
+
categoriesHeading: "Categories",
|
|
4999
|
+
filterHeading: "Filter",
|
|
4992
5000
|
sortStars: "Most stars",
|
|
4993
5001
|
sortAdded: "Newest",
|
|
4994
5002
|
sortUpdated: "Recently updated",
|
|
@@ -8431,142 +8439,147 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8431
8439
|
if (typeof held?.dispose === "function") held.dispose();
|
|
8432
8440
|
}
|
|
8433
8441
|
//#endregion
|
|
8434
|
-
//#region \0dsh-plugin-shop-css:
|
|
8435
|
-
const css = "/* Shop styles — the shop's own page with its market shelf, and the shop's two\n * buttons on dsh's Plugins page. Every variable read here is a dsh theme\n * alias token (`--dsw-alias-*`), one of the shop's own properties declared in\n * this file (`--shop-*`, `--category-hue`, `--switch-hue`, `--track-hue`), or\n * one of two dsh variables outside the alias set, each read where the shop\n * copies dsh: `--dsh-frame-top-clearance`, so the page head clears the\n * desktop frame as dsh's own pages do, and `--dsw-radius-sm`, because the\n * Plugins page buttons copy dsh's Button (0.1.5-rc.3 lacks that token, and\n * has no Plugins page to draw them on). `state-error` and\n * `state-success` do not exist, so the state-*-primary set stands in for\n * them (measured 2026-10-17 on dsh 0.1.5-rc.3, 0.1.7-rc.2 and 0.2.0-rc.2,\n * which do define `bg-layer-3` and `interactive-bg-hover`, once listed here\n * as missing). The signature is the category spine: one HUE per\n * category (seven fixed hues, not the brand token — the brand resolves to\n * near-black in the light theme, so seven brand opacities read as seven\n * shades of gray), with the category name as the cover label in the same hue. Class names are mapped to content-derived names at bundle time\n * (tsdown.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 two reds every red text in this tab is painted with. dsh's error red\n * is #ec1313 in the light theme, which measures 4.498:1 as text on white —\n * a miss of two thousandths — and 3.57:1 on the badge's own 14% red fill\n * (4.00:1 in dark). Mixing it toward label-primary fixes both, because\n * label-primary is the theme's foreground pole: it darkens the red on light\n * surfaces and lightens it on dark ones. Measured in the live app: 90% of\n * the red is 5.30:1 on white and 5.29:1 on the dark card, and 80% is\n * 4.98:1 on the badge's tint, 4.92:1 in dark. Computed: 90% is 6.14:1 on\n * the dark page itself (#151517, `bg-base`), where the self-update's\n * failure heading sits (4.69:1 on Settings' #2c2c2e, its ground through\n * 0.8.7), and 80% is 5.23:1 on the uninstall button's 10% hover fill.\n * Declared here, on the tab root, because a custom property inherits: one\n * declaration reaches every red element, and a new one cannot be\n * forgotten. */\n --shop-error: color-mix(in srgb, var(--dsw-alias-state-error-primary) 90%, var(--dsw-alias-label-primary));\n --shop-error-on-tint: color-mix(in srgb, var(--dsw-alias-state-error-primary) 80%, var(--dsw-alias-label-primary));\n /* The amber and the green, mixed the same way for the same reason. dsh's\n * warn #f59e0b and success #22c55e are one value in both themes and pass\n * in the dark one, but as text on white they measure 2.15:1 and 2.28:1.\n * Each derived colour keeps the largest multiple of ten of its hue that\n * clears every surface it paints, as the reds do. Computed from the live\n * tokens over every bg layer in both themes: amber at 60% is 4.95:1 on a\n * plain surface but 4.44:1 on its own 14% tint, so text on an amber tint\n * takes 50% (5.66:1); green at 60% is 5.18:1 plain and 4.60:1 on its 14%\n * tint, so one green serves both. */\n --shop-warn: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 60%, var(--dsw-alias-label-primary));\n --shop-warn-on-tint: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 50%, var(--dsw-alias-label-primary));\n --shop-success: color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary));\n /* The shelf never scrolls sideways: a card too wide for its track wraps\n * its badges rather than widening the panel.\n *\n * Clipped on BOTH axes, with a margin, because `.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/* The shop's own page in dsh's main column (design\n * 2026-10-16-shop-sidebar-page §4.2), framed as dsh 0.2.0-rc.2 frames its\n * Plugins page — read from that page's stylesheet: the page is the scroll\n * container, its children one centred column of at most 960px, and the head\n * clears the desktop title bar. One declaration is the shop's own, `color`:\n * dsh's `.s3f14d7_page` inherits its colour from the shell around it, and the shop's\n * root is not inside dsh's panel stylesheet, so the shop's page states it. */\n.s3f14d7_page {\n box-sizing: border-box;\n height: 100%;\n overflow: auto;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 32px;\n padding: 0 clamp(24px, 4vw, 48px) 48px;\n color: var(--dsw-alias-label-primary);\n}\n\n.s3f14d7_page > * {\n width: 100%;\n max-width: 960px;\n}\n\n.s9bc9a3_pageHead {\n box-sizing: border-box;\n padding-top: calc(28px + var(--dsh-frame-top-clearance, 0px));\n}\n\n.sd3fc57_pageTitle {\n margin: 0;\n font-size: 20px;\n font-weight: 500;\n line-height: 28px;\n}\n\n/* Secondary, as dsh's own intro: 5.80:1 on the light theme's white. */\n.s11ac5e_pageIntro {\n margin: 4px 0 0;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The two buttons on dsh's Plugins page (design 2026-10-16-shop-sidebar-page\n * §7), drawn as that page draws its own small outline buttons beside them —\n * dsh 0.2.0-rc.2's Button, sm + outline: 28px tall, 12px text on an 18px\n * line, 10px of side padding, the small radius, the neutral stroke. That\n * stroke is 0.5px in dsh and 1px here: every border in this stylesheet is,\n * and Chromium paints 0.5px as 1px at every ratio measured. */\n.sbaabcb_detailAction {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 28px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n cursor: pointer;\n}\n\n.sbaabcb_detailAction:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.sbaabcb_detailAction:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s44a3ec_stateLine {\n margin: 0;\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n/* Visually hidden but screen-reader readable (the loading copy while the\n * skeleton stands in visually). */\n.s3a0ece_srOnly {\n position: absolute;\n width: 1px;\n height: 1px;\n margin: -1px;\n padding: 0;\n border: 0;\n clip: rect(0 0 0 0);\n clip-path: inset(50%);\n overflow: hidden;\n white-space: nowrap;\n}\n\n/* The loading shelf: ghost cards with the same geometry as the real grid, so\n * the swap to content is a same-shape handoff instead of a jump. */\n.se0c3b4_skeletonGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 8px;\n}\n\n.s520416_skeletonCard {\n position: relative;\n display: flex;\n flex-direction: column;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 10px;\n background: var(--dsw-alias-bg-layer-1);\n overflow: hidden;\n}\n\n/* The shimmer sweep: one gradient band travels across each ghost card while\n * the bars breathe, so the loading state reads as \"the shelf is scanning\". */\n.s520416_skeletonCard::after {\n content: '';\n position: absolute;\n inset: 0;\n background: linear-gradient(\n 100deg,\n transparent 25%,\n color-mix(in srgb, var(--dsw-alias-label-primary) 14%, transparent) 50%,\n transparent 75%\n );\n transform: translateX(-100%);\n animation: dshShopSkeletonSweep 1.4s ease-in-out infinite;\n pointer-events: none;\n}\n\n@keyframes dshShopSkeletonSweep {\n to { transform: translateX(100%); }\n}\n\n.s8c7d6f_skeletonName {\n width: 55%;\n height: 14px;\n margin: 10px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sf5179e_skeletonSummary {\n width: 92%;\n height: 12px;\n margin: 10px 12px 0;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.sbb0d25_skeletonSummaryShort {\n width: 68%;\n height: 12px;\n margin: 6px 12px 10px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n/* The ghost of the action line, right where the real buttons land. */\n.s96e910_skeletonActions {\n display: block;\n width: 84px;\n height: 24px;\n margin: 0 12px 10px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 8%, transparent);\n}\n\n.s520416_skeletonCard span {\n animation: dshShopSkeletonPulse 1.6s ease-in-out infinite;\n}\n\n@keyframes dshShopSkeletonPulse {\n 0%, 100% { opacity: 0.5; }\n 50% { opacity: 1; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s520416_skeletonCard span { animation: none; opacity: 0.75; }\n .s520416_skeletonCard::after { content: none; }\n}\n\n.s73242a_actionButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s73242a_actionButton:hover {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.s73242a_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s646509_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.s745e3c_toolbarRight {\n display: flex;\n align-items: center;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n/* The shop's own version, right of the search box: `v0.4.4`, plus the\n * update button when the version check found a newer release. */\n.s4fe61f_versionBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.sb9b924_versionText {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa04455_updateSelfButton {\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n color: var(--dsw-alias-brand-primary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.sa04455_updateSelfButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 20%, transparent);\n}\n\n.sa04455_updateSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The on-demand re-check next to the version number: a quiet pill; the\n * border and text carry it in the light theme where bg layers are white. */\n.s614a38_checkUpdateButton {\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n.s614a38_checkUpdateButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n color: var(--dsw-alias-label-primary);\n}\n\n.s614a38_checkUpdateButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.s614a38_checkUpdateButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The project's GitHub mark, right of the version row: a quiet icon link.\n * The octocat carries itself — color shift on hover, no text, no border. */\n.sa987f7_githubLink {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 3px;\n border-radius: 6px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa987f7_githubLink:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.sa987f7_githubLink:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The self-update's expanded states (running log / done + restart /\n * failure detail) sit under the toolbar, above the category bar. */\n.sb81ba5_selfUpdatePanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.s232ec4_searchInput {\n width: min(280px, 100%);\n padding: 6px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n}\n\n.s232ec4_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* Subdued line under the search box when a dictionary intent fired (design\n * 2026-10-08-search-query-expansion §4). One fact, no badge. */\n.s76fb13_expansionNote {\n margin: 4px 0 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s3946f1_staleBadge {\n padding: 2px 8px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n color: var(--shop-warn-on-tint);\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: a pressed tab must occupy exactly the\n * same box as an unpressed one, so the bar does not reflow — and with ~9 pills\n * on a wrapping row, one that grows can push the rest onto another line and\n * move the tab out from under the pointer that just clicked it. That is what\n * `font-weight: 600` did (bold metrics are wider than regular), and it is why\n * nothing may be added here that resolves to a length: no padding, no\n * border-width, no font-size, no letter-spacing. `css-tokens.s8583e3_client.sfd9d8a_spec.s5f67aa_ts`\n * fails the build on one.\n *\n * Nor a second line. An inset ring once doubled this border, and every control\n * in the stylesheet now draws exactly one 1px line, which is also the thinnest\n * the host paints (Chromium draws 0.5px as 1px). What separates pressed from\n * unpressed is lightness instead of thickness: the border is the hue mixed 30%\n * toward label-primary, the theme's foreground pole, so it clears 3:1 against\n * the bar in both themes for every hue — the raw hue measured 1.86:1 on white\n * for `ui` — and the fill under it is 22% of the hue. The `other` tab is the\n * case this is for: its hue IS the neutral gray this file uses for \"no\n * category\", so on the light theme the hue alone barely separates the two. */\n.s26d58e_categoryButton.s5f68c4_categoryButtonOn {\n border-color: color-mix(in srgb, var(--category-hue) 70%, var(--dsw-alias-label-primary));\n background: color-mix(in srgb, var(--category-hue) 22%, transparent);\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Forced colours replace every colour above with the system palette, which\n * would leave the three colour declarations saying nothing and the pressed tab\n * indistinguishable from its neighbours, so this mode alone gets an outline. */\n@media (forced-colors: active) {\n .s26d58e_categoryButton.s5f68c4_categoryButtonOn {\n outline: 2px solid ButtonText;\n outline-offset: -4px;\n }\n}\n\n.s26d58e_categoryButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The incompatible filter, at the right edge of the category bar: `margin-left:\n * auto` pushes it past the pills, and the bar wraps, so on a narrow panel it\n * drops to its own line rather than squeezing them. It is a MODIFIER, not a\n * ninth category — the categories select what to show and this one subtracts\n * from whatever they selected — so it takes the error hue it filters on rather\n * than joining the hue table.\n *\n * And it is a SWITCH, which is the difference the shape now carries. It used\n * to wear `.s26d58e_categoryButton`: same pill, same row, same size as the eight tabs,\n * differing only in being red. That reads as a ninth tab, and it is not one —\n * the tabs are choose-one and this is on-or-off. So it drops the pill chrome\n * entirely (no border, no fill, nothing to compete with the row it sits\n * beside) and puts the state in a track, the same one every installed card\n * carries. Nothing here restates the switch geometry; `--switch-hue` is the\n * whole of what this control says about it, and it reaches the label too, so\n * one declaration keeps the word and the track the same colour. */\n.sfd887b_incompatibleFilter {\n --switch-hue: var(--dsw-alias-state-error-primary);\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n /* Matches the pills' vertical padding so the bar keeps one line box whether\n * this control wraps onto a row of its own or shares theirs. */\n padding: 3px 0;\n border: 0;\n background: none;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n/* Hover lifts the word to full contrast and warms the track's border. Scoped\n * to the OFF track: `.sfd887b_incompatibleFilter:hover .s11c019_switch` outranks `.s7580e8_switchOn`\n * by two classes, so unscoped it would strip the hue from the border at\n * exactly the moment a reader has the pointer on it to check the state. */\n.sfd887b_incompatibleFilter:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.sfd887b_incompatibleFilter:hover .s11c019_switch:not(.s7580e8_switchOn) {\n border-color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-border-l2));\n}\n\n/* On. Written with both classes for the reason `.s26d58e_categoryButton.s5f68c4_categoryButtonOn`\n * is: it has to match `:hover`'s specificity and come after it, or the colour\n * reverts under a pointer that has not moved since the click. */\n.sfd887b_incompatibleFilter.s6e4cba_incompatibleFilterOn {\n color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Off here means \"nothing is being taken away\" — the resting state — so the\n * knob steps back to the secondary label. The enable switch keeps the full\n * strength dot, where off means \"this plugin is disabled\" and is worth\n * noticing. In this bar it would be the heaviest mark in a row of hairline\n * pills, and on the light theme it is the WHOLE control: bg-layer-2 is the\n * same white as the panel there, so an off track is a hairline outline with a\n * near-black dot sitting in it. */\n.sfd887b_incompatibleFilter .s11c019_switch:not(.s7580e8_switchOn) .saab2b3_switchKnob {\n background: var(--dsw-alias-label-secondary);\n}\n\n/* The ring has no border to trace, so it takes an offset and the pill radius\n * of the tabs it sits beside rather than hugging the text. */\n.sfd887b_incompatibleFilter:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 999px;\n}\n\n.sebf017_updatableHeading {\n margin: 2px 0 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-primary);\n}\n\n.seb0a1e_catalogStatsRow {\n display: flex;\n align-items: center;\n /* The row holds the catalog line, the refresh button and the shelf order's\n * three pills (design 2026-10-12-shelf-orders §4). Without wrapping, the\n * last of them overflows the tab at a narrow width. */\n flex-wrap: wrap;\n gap: 10px;\n margin: 6px 0 0;\n}\n\n/* The shelf's order control, at the right end of the stats row. `margin-left:\n * auto` is what puts it there while the line and the refresh button stay\n * left — and it is safe on a wrapping row, unlike a width. */\n.sa6825e_sortGroup {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n margin-left: auto;\n}\n\n.s268f9e_sortLabel {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.sccc4d1_catalogStats {\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* Sits beside the 12px stats caption, so it is quieter than `.s73242a_actionButton`:\n * this is an affordance, not a call to action — the catalog reloads on its\n * own at mount and the shelf is already usable without it. Named\n * `catalogRefresh*` (not `reload*`) so it cannot collide with the §4 page\n * reload offer below, which reloads the whole tab rather than refetching\n * the catalog data. */\n.sff243d_catalogRefreshButton {\n padding: 1px 9px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n line-height: 17px;\n cursor: pointer;\n}\n\n.sff243d_catalogRefreshButton:hover:not(:disabled) {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.sff243d_catalogRefreshButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.sff243d_catalogRefreshButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s194168_catalogRefreshFailed {\n font-size: 11px;\n color: var(--shop-warn);\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/* The shelf's grid item is the <li> carrying a card's identity (ShopPage\n * reads it), not the card, and a grid item's min-width is auto: the 1fr track\n * could then never be narrower than the widest item's min-content, and every\n * card widens to it. Two things reach that width. Content that cannot wrap,\n * on a narrow window. And a card the browser skips (`content-visibility:\n * auto` below), which keeps the width it last rendered at: browsing a wide\n * window and narrowing it left every card 960px wide in a 662px column, its\n * right side clipped by the panel (measured on dsh 0.2.1-rc.2, 0.2.0-rc.2 and\n * 0.1.7-rc.2, 2026-10-22). Until the page took the main column the panel was\n * as wide as Settings made it, and a window resize did not move it. */\n.sf657f5_cards > li {\n min-width: 0;\n}\n\n.s65f383_card {\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 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/* One entry's icon: a 32px tile holding a 24px image (design\n * 2026-10-23-shop-plugin-icons §8.3). The border and radius are dsh's own\n * (`PackageArtwork`'s .s7ff339_cardIcon), so a card's icon reads the same here as on\n * dsh's Plugins page. No backplate in either theme (§8.4). */\n.sc2425d_entryIcon {\n box-sizing: border-box;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n overflow: hidden;\n}\n\n.scc3f74_entryIconImage {\n width: 24px;\n height: 24px;\n object-fit: contain;\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: 10px 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.s9b5048_cardActions > .sc34531_receipt {\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 /* A release tag prints as tagged, never cut to seven characters (market\n * borrowings §11), and a tag can run to any length. The cap keeps every\n * tag of up to fourteen characters whole, prerelease suffix included\n * (`v0.1.0-alpha.0`): fourteen glyphs plus the letter-spacing above come to\n * about 14.5ch, so the cap is 15ch, not 14. A longer tag ends in an ellipsis,\n * and the tooltip carries the whole of it. */\n max-width: 15ch;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* The octocat marking a source the reader can read on GitHub, beside the\n * card's version. */\n.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(--shop-success);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent);\n}\n\n.s5e82cb_tierBadge[data-tier='verified-stale'] {\n color: var(--shop-warn-on-tint);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n}\n\n.s5e82cb_tierBadge[data-tier='community'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n/* The §C10 shadowed badge: an installed github entry the catalog refuses\n * shadowed-by-npm. Subdued/secondary rather than a warn tint — nothing is\n * wrong with the install itself; the shelf just cannot show it. */\n.s5e82cb_tierBadge[data-tier='shadowed'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n/* The §C5 archived badge: a github repository the owner has frozen.\n * Subdued register, same as shadowed — nothing is wrong with the install;\n * the pinned commit still serves, so the mark is informational only. */\n.s5e82cb_tierBadge[data-tier='archived'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n.s4bbe02_incompatibleBadge {\n flex-shrink: 0;\n padding: 3px 9px;\n border-radius: 999px;\n font-size: 12px;\n white-space: nowrap;\n /* On the tint, not on the plain surface: this text reads on its own 14% red\n * fill, where the 90% red would measure 4.21:1 (light) and 4.43:1 (dark). */\n color: var(--shop-error-on-tint);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);\n}\n\n.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(--shop-error);\n}\n\n/* The way out of dsh's own refusal: the lead-in, then the exemption command\n * on its own line. */\n/* Block layout rather than flex: Firefox 153 will not line-clamp a container\n * that holds a display:flex child (Chromium 151 does), and the fold's\n * measured goal — \"the whole red block, remedy included, as one unit\" —\n * needs the container to clamp in BOTH engines the shop targets. The 4px\n * rhythm between the lead-in and the command is kept by the margins of the\n * children. */\n.s3d0044_remedy {\n display: block;\n}\n\n.s3d0044_remedy > * + * { margin-top: 4px; }\n\n/* The fold under a card's whole red block: two lines by default, a small\n * Refresh-pill-shaped toggle under it. Two containers, one rhythm: the shelf\n * uses `.s67d135_foldBlock` collapsed and `.s626303_foldBlockExpanded` open, and they share\n * one `display: block` (Firefox clamps no flex child inside a -webkit-box).\n * The clamp is on the BLOCK rather than any one line, so a 43-line remedy\n * counts as a unit instead of squashing the harness-peers line to a sliver\n * and hiding the command the reader actually came for. Both containers\n * still render the full block to a screen reader — `white-space: normal`\n * instead of pre-line keeps the copy's own `\\n` visible without forcing the\n * browser to lay the block's pieces like a text node. */\n.s67d135_foldBlock {\n display: block;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n display: -webkit-box;\n overflow: hidden;\n}\n\n.s626303_foldBlockExpanded { display: block; }\n\n/* The toggle. Geometry and quiet voice are the Refresh pill's\n * (`catalogStatsRow` right beside it on the same screen): one 1px border,\n * 11px text, secondary label, no fill. It is the only one of its kind here,\n * so a class of its own means one function of its own. */\n.sfbcf2c_foldToggle {\n /* The pill's own width. Under a card's red block it is an item of the card\n * body, a column, which stretches every child it is not told otherwise:\n * 934px against the Refresh pill's 59px at a 1440 window (2026-10-22). */\n align-self: flex-start;\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.sfbcf2c_foldToggle:hover { border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2)); }\n.sfbcf2c_foldToggle:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }\n\n.sdf203f_remedyLead {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The exemption command, bound for a terminal unchanged: one click selects\n * all of it, and it wraps anywhere rather than widening the card. A border,\n * not a fill, marks the box: the bg layers are one white in the light theme. */\n.sc32335_allowCommand {\n display: block;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n white-space: pre-wrap;\n word-break: break-all;\n user-select: all;\n color: var(--dsw-alias-label-primary);\n}\n\n/* A refused install on a surface that does not state its blockers — the\n * outdated row — writes them out on their own full-width line under the\n * refused label, the command that clears dsh's refusal included. Block,\n * rather than flex: Firefox will not line-clamp a -webkit-box that holds a\n * display:flex child, and the fold this element can sit inside of carries\n * that clamp. The 6px rhythm between the block's lines is carried by the\n * children's margins. */\n.sc74941_refusal {\n display: block;\n flex-basis: 100%;\n}\n\n.sc74941_refusal > * + * { margin-top: 6px; }\n\n.s9d2029_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s3bdbd5_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s441702_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s441702_capabilities li {\n padding: 1px 6px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--dsw-alias-label-primary) 6%, transparent);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sde3f0c_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.se98179_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.sfb4d2f_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.sfb4d2f_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.sfb4d2f_detailRow dd {\n margin: 0;\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n overflow-wrap: anywhere;\n text-align: right;\n color: var(--dsw-alias-label-primary);\n}\n\n.sfb4d2f_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.sfb4d2f_detailRow a:hover {\n text-decoration: underline;\n}\n\n.sfb4d2f_detailRow a:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* What the entry IS rather than what you can do with it — how big it is and\n * who published it — at the right edge of the action row. `margin-left: auto`\n * is what pushes it there, and it lives on this wrapper rather than on either\n * label so the group stays flush right when only one of the two has a value —\n * a packument that named no account has no author, and an entry the registry\n * could not measure honestly has no size. Rarer than it was (every live entry\n * now carries a size, github included), but the wrapper is not what makes it\n * rare: without one, an EMPTY meta group still costs 8px, because\n * `.s9b5048_cardActions` is a flex row with `gap: 8px` and a zero-width item is still\n * an item. The row is a wrapping flex, so an active install flow (which claims\n * the full width) drops the whole group to the next line rather than squeezing\n * it. */\n.s5fbaf9_cardMeta {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n min-width: 0;\n}\n\n/* The on-disk size, left of the author. Mono and tabular so the digits of one\n * figure line up with the digits of another WHEREVER the two land: `.s5fbaf9_cardMeta`\n * is flush right and the author sits outside the size, so a size's x position\n * moves with the author's width and is different again on the many entries\n * that carry no author at all. There is no column to align to, which is why\n * the reason given here is per-figure legibility rather than the column the\n * first version of this comment claimed. Secondary colour, because it\n * qualifies the entry rather than announcing it.\n *\n * `font-variant-numeric` is safe HERE and would not be on a pill: this element\n * has no state rules, so nothing it does can reflow a wrapping row.\n *\n * `.s98d53f_shelfDate` shares this rule because it is the same kind of fact — a\n * fixed-width figure a reader compares down the shelf (design\n * 2026-10-12-shelf-orders §4) — and two copies of these declarations would\n * drift. */\n.s2d3c05_size,\n.s98d53f_shelfDate {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-variant-numeric: tabular-nums;\n font-size: 12px;\n letter-spacing: 0.02em;\n white-space: nowrap;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The publishing account, at the outer end of `.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(--shop-warn-on-tint);\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/* ONE geometry for everything that occupies the install button's place: the\n * button itself, the confirm/cancel pair beside the restart gate, the installed\n * label, and the refused label. Stated once because a refused label HAS to look\n * like the button it replaces apart from its colour and its text, and four\n * copies of the same five declarations is how they stop looking alike.\n * `cursor: pointer` is NOT here: only the controls that can be pressed take it,\n * while a label renders with the default cursor. */\n.se7aaed_installButton,\n.sb43a49_confirmButton,\n.s6e45d1_cancelButton,\n.sb6fc74_installedLabel,\n.s906629_refusedLabel {\n align-self: flex-start;\n margin: 0;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n font-size: 13px;\n}\n\n.se7aaed_installButton, .sb43a49_confirmButton, .s6e45d1_cancelButton {\n cursor: pointer;\n}\n\n.se7aaed_installButton {\n border-color: var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n/* Between the click and the host's answer. The flow ignores a repeat start for\n * the same identity, so this is the visible half of the same fact: a control\n * that says \"not now\" rather than one that looks ready to send a second\n * install. Only the button can be in this state — a label is never pressed. */\n.se7aaed_installButton:disabled {\n cursor: wait;\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/* The refused Install/Update button's replacement: the same box as the button\n * (the geometry rule above), filled solid red, not pressable. The fill is the\n * derived red rather than the raw token because text sits on it — bg-base on\n * `--shop-error` measures 5.31:1 light and 6.14:1 dark — and the raw error red\n * under bg-base text measures 4.498:1, the miss this whole family of fixes\n * exists for. Nothing here changes on hover: it is a statement, not a control,\n * so it keeps the default cursor and its colours. */\n.s906629_refusedLabel {\n border-color: var(--shop-error);\n background: var(--shop-error);\n color: var(--dsw-alias-bg-base);\n white-space: nowrap;\n}\n\n/* An installed card's controls: the installed label or the update button,\n * plus the uninstall button. The install panel's running/failed states are\n * column layouts and sit as one item of this row. */\n.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 /* The on-tint red: hovering this button paints a 10% red fill under the\n * word, where the plain red measures 4.50:1 (light) — the same two\n * thousandths short of the floor the raw token shipped at. */\n color: var(--shop-error-on-tint);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s96967f_uninstallButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.s96967f_uninstallButton:focus-visible {\n outline: 2px solid var(--dsw-alias-state-error-primary);\n outline-offset: 1px;\n}\n\n/* The restart dsh button on a done install: quiet outline, same rank as\n * the other secondary actions. */\n.sb00c36_restartSelfButton {\n /* The version row's third state. Geometry matches .s614a38_checkUpdateButton and\n * .sa04455_updateSelfButton exactly — the row is one evolving control and a\n * different pill would read as a different kind of thing. It takes the\n * emphasised fill rather than the neutral one because at that moment the\n * restart is the only thing left to do, the same reason Update has it. */\n padding: 2px 10px;\n border: 1px solid var(--dsw-alias-brand-primary);\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 12%, transparent);\n color: var(--dsw-alias-brand-primary);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n}\n\n.sb00c36_restartSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The two activation offers share one recipe: a border in an alias token,\n * never a `bg-layer` fill alone — all four bg-layer tokens collapse to the\n * same white under `body` in the light theme, and a fill-only button would\n * vanish there. Grouped rather than copied, because a copy is a rule that\n * can be corrected on one button and left wrong on the other, silently. */\n.s6ac237_restartButton,\n.s64a5ff_reloadButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s6ac237_restartButton:hover,\n.s64a5ff_reloadButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s6ac237_restartButton:focus-visible,\n.s64a5ff_reloadButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* A settled install's or uninstall's receipt: its log, what happened, and\n * what to do next, stacked. A column, so the log box spans the card as the\n * running and failed views' logs do, rather than being as wide as its longest\n * line (852, 409 and 260px on three cards of one page, 2026-10-22), and the\n * sentence never shares a line with a button it would sit misaligned beside. */\n.sc34531_receipt {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* The buttons under a receipt, a failure, or a reload or restart note, in one\n * row: the offer first (Reload, Restart dsh, Retry) and the way out (Dismiss)\n * beside it. They stood a line apart: Dismiss beside the reload note and\n * Reload under it, or Retry above Dismiss. */\n.sbe9357_offerActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n\n/* The §4 reload offer: a notice plus its button, one item of\n * `.sf53ca0_installedActions` the way the restart gate is — a column of its own\n * rather than inline with the row. */\n.sf79aef_reloadPanel {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n}\n\n\n.sc4f2ac_gate {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 10px;\n border: 1px solid var(--dsw-alias-state-warn-primary);\n border-radius: 8px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);\n}\n\n.s559c38_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--shop-warn-on-tint);\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(--shop-error);\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(--shop-success);\n}\n\n.seb9b08_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--shop-error);\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(--shop-error);\n}\n\n.se75489_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The Updatable section. The class keeps the Host's field name; only the\n heading the reader sees was renamed. */\n.sa276cf_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.sceae6e_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s8d2072_outdatedRow {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n padding: 10px 12px;\n border: 1px solid var(--dsw-alias-border-l1);\n border-radius: 8px;\n background: var(--dsw-alias-bg-layer-1);\n}\n\n.s5c2545_outdatedInfo {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 10px;\n min-width: 0;\n}\n\n/* The name and everything under it, beside the icon. */\n.s3ecfe4_outdatedText {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s5c2545_outdatedInfo strong {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 13px;\n word-break: break-all;\n color: var(--dsw-alias-label-primary);\n}\n\n.s877c68_outdatedVersions {\n /* Two inline labels with nothing between them in the markup ran together as\n * `installed v1.0.0latest v2.0.0`: JSX drops the whitespace-only line, and\n * the per-label class the markup asked for was never defined (singular\n * against this rule's plural). The container owns the gap, the same idiom\n * as .s513026_badges — the labels need no class of their own. */\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The §C10 shadowed section. Reuses the outdated list's visual language; only\n * the section spacing and the per-row explanation paragraph are its own. */\n.s6c4649_shadowedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.scc2a21_shadowedDetail {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa1f556_outdatedActions {\n display: flex;\n align-items: center;\n /* The reload offer (§4) mounts inside the switch beside the Update button\n * and is a two-line block, not a control: without wrapping, a row reading\n * [switch][notice + Reload][Update] overflowed the Settings dialog the shop\n * sat in through 0.8.7, and the page's column narrows with the window. */\n flex-wrap: wrap;\n gap: 10px;\n}\n\n/* The shop's one switch. It is worn by two controls that mean different\n * things — the enable/disable toggle on an installed card, and the shelf's\n * incompatible filter — so the geometry lives here once and each caller states\n * only its hue.\n *\n * `--switch-hue` is that knob, and it is read from the ANCESTOR rather than\n * declared per state: `.sfd887b_incompatibleFilter` sets it once and it reaches the\n * track and the label together, which is what keeps a red switch from sitting\n * under a neutral word. A declaration on `.s11c019_switch` itself would shadow the\n * inherited value (an element's own rule beats what it inherits), so the\n * default rides in the `var()` fallback and is resolved once into\n * `--track-hue` instead of being spelled out at each use.\n *\n * `box-sizing` and `padding` are stated because the two callers are different\n * elements — a `<button>`, which the UA gives padding, and a `<span>`, which\n * it does not. Without them the same class renders two sizes, and the knob\n * sits 2px above centre in the taller one. */\n.s11c019_switch {\n --track-hue: var(--switch-hue, var(--dsw-alias-state-success-primary));\n box-sizing: border-box;\n display: inline-block;\n position: relative;\n width: 32px;\n height: 18px;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n\n/* The knob's POSITION is the state, which is the reason this control needs no\n * `forced-colors` fallback the way the category pills do: a system palette\n * replaces every colour below and moves nothing. */\n.s7580e8_switchOn {\n border-color: var(--track-hue);\n background: color-mix(in srgb, var(--track-hue) 55%, transparent);\n}\n\n.saab2b3_switchKnob {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: 999px;\n background: var(--dsw-alias-label-primary);\n transition: transform 120ms ease, background 120ms ease;\n}\n\n.s7580e8_switchOn .saab2b3_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.s11c019_switch:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .s11c019_switch, .saab2b3_switchKnob { transition: none; }\n}\n\n/* The hot enable/disable switch on installed rows: the knob button plus the\n * §8 hot-apply / failure notices rendered beside it. */\n.sd9f9e4_switchWrap {\n display: inline-flex;\n align-items: center;\n /* Same reason as `.sa1f556_outdatedActions`: `.sf79aef_reloadPanel`'s own comment calls\n * itself \"a column of its own rather than inline with the row\", which held\n * for `.sf53ca0_installedActions` and not here until this line. */\n flex-wrap: wrap;\n gap: 8px;\n}\n";
|
|
8436
|
-
if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"
|
|
8442
|
+
//#region \0dsh-plugin-shop-css:bc430a83
|
|
8443
|
+
const css = "/* Shop styles — the shop's own page with its market shelf, and the shop's two\n * buttons on dsh's Plugins page. Every variable read here is a dsh theme\n * alias token (`--dsw-alias-*`), one of the shop's own properties declared in\n * this file (`--shop-*`, `--category-hue`, `--switch-hue`, `--track-hue`), or\n * one of two dsh variables outside the alias set, each read where the shop\n * copies dsh: `--dsh-frame-top-clearance`, so the page head clears the\n * desktop frame as dsh's own pages do, and `--dsw-radius-sm`, because the\n * Plugins page buttons copy dsh's Button (0.1.5-rc.3 lacks that token, and\n * has no Plugins page to draw them on). `state-error` and\n * `state-success` do not exist, so the state-*-primary set stands in for\n * them (measured 2026-10-17 on dsh 0.1.5-rc.3, 0.1.7-rc.2 and 0.2.0-rc.2,\n * which do define `bg-layer-3` and `interactive-bg-hover`, once listed here\n * as missing). The signature is the category spine: one HUE per\n * category (seven fixed hues, not the brand token — the brand resolves to\n * near-black in the light theme, so seven brand opacities read as seven\n * shades of gray), with the category name as the cover label in the same hue. Class names are mapped to content-derived names at bundle time\n * (tsdown.s514620_client.s7e11f7_config.s418ac5_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.s514620_client.s74d5ba_spec.s418ac5_ts` pins this. */\n\n.sc99bd6_panel {\n display: flex;\n flex-direction: column;\n gap: 14px;\n /* The shop's own width decides the shelf's arrangement (design\n * 2026-11-02-shop-widescreen-layout §3). The container is this tab root,\n * not `.sd86001_shelfBody`: a container query cannot style its own container, and\n * the rule that turns the shelf body into the rail's grid is exactly that.\n * Inline size only — the panel's height still follows its content. */\n container-type: inline-size;\n /* The two reds every red text in this tab is painted with. dsh's error red\n * is #ec1313 in the light theme, which measures 4.498:1 as text on white —\n * a miss of two thousandths — and 3.57:1 on the badge's own 14% red fill\n * (4.00:1 in dark). Mixing it toward label-primary fixes both, because\n * label-primary is the theme's foreground pole: it darkens the red on light\n * surfaces and lightens it on dark ones. Measured in the live app: 90% of\n * the red is 5.30:1 on white and 5.29:1 on the dark card, and 80% is\n * 4.98:1 on the badge's tint, 4.92:1 in dark. Computed: 90% is 6.14:1 on\n * the dark page itself (#151517, `bg-base`), where the self-update's\n * failure heading sits (4.69:1 on Settings' #2c2c2e, its ground through\n * 0.8.7), and 80% is 5.23:1 on the uninstall button's 10% hover fill.\n * Declared here, on the tab root, because a custom property inherits: one\n * declaration reaches every red element, and a new one cannot be\n * forgotten. */\n --shop-error: color-mix(in srgb, var(--dsw-alias-state-error-primary) 90%, var(--dsw-alias-label-primary));\n --shop-error-on-tint: color-mix(in srgb, var(--dsw-alias-state-error-primary) 80%, var(--dsw-alias-label-primary));\n /* The amber and the green, mixed the same way for the same reason. dsh's\n * warn #f59e0b and success #22c55e are one value in both themes and pass\n * in the dark one, but as text on white they measure 2.15:1 and 2.28:1.\n * Each derived colour keeps the largest multiple of ten of its hue that\n * clears every surface it paints, as the reds do. Computed from the live\n * tokens over every bg layer in both themes: amber at 60% is 4.95:1 on a\n * plain surface but 4.44:1 on its own 14% tint, so text on an amber tint\n * takes 50% (5.66:1); green at 60% is 5.18:1 plain and 4.60:1 on its 14%\n * tint, so one green serves both. */\n --shop-warn: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 60%, var(--dsw-alias-label-primary));\n --shop-warn-on-tint: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 50%, var(--dsw-alias-label-primary));\n --shop-success: color-mix(in srgb, var(--dsw-alias-state-success-primary) 60%, var(--dsw-alias-label-primary));\n /* The shelf never scrolls sideways: a card too wide for its track wraps\n * its badges rather than widening the panel.\n *\n * Clipped on BOTH axes, with a margin, because `.s76d7f5_searchInput` sits at\n * exactly (0, 0) of this box — it is the first child of `.sa59b0a_toolbar`, itself\n * the first child here, and this rule carries no padding — so its focus\n * ring paints ENTIRELY outside the panel.\n *\n * Both axes is the load-bearing part: `overflow-clip-margin` is inert\n * unless the element clips on both. Clipping x alone left the margin doing\n * nothing — measured against the live app on 0.7.1, the ring reached 0 of\n * its 3px on the left at every device pixel ratio (1, 1.25, 1.5, 2), while\n * keeping the full 3px on the right, where the 280px input stops short of\n * the panel and never meets the clip edge. Raising the margin to 6px\n * changed nothing; clipping both axes with the SAME 3px restored the whole\n * ring. A test that reads declarations cannot see that difference, which is\n * why the first attempt at this shipped broken.\n *\n * `clip` is not a scroll container, so this does not bring back the\n * accidental scrolling `hidden` caused by coercing the other axis to\n * `auto`. Nothing is lost vertically: the panel's scrollHeight equals its\n * height and no descendant paints outside the clip rect (measured).\n * `overflow-x: hidden` stays as the fallback for engines without `clip`,\n * where the ring is clipped as it was before, never worse. */\n overflow-x: hidden;\n overflow: clip;\n overflow-clip-margin: 3px;\n}\n\n/* The shop's own page in dsh's main column (design\n * 2026-10-16-shop-sidebar-page §4.2), framed as dsh 0.2.0-rc.2 frames its\n * Plugins page — read from that page's stylesheet: the page is the scroll\n * container, its children one centred column (960px then; 1280 since the\n * 2026-11-02 wide layout), and the head clears the desktop title bar. One declaration is the shop's own, `color`:\n * dsh's `.s92dc8e_page` inherits its colour from the shell around it, and the shop's\n * root is not inside dsh's panel stylesheet, so the shop's page states it. */\n.s92dc8e_page {\n box-sizing: border-box;\n height: 100%;\n overflow: auto;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 32px;\n padding: 0 clamp(24px, 4vw, 48px) 48px;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The head and the shelf share one column, and on 2026-11-02 that column\n * widened from 960 to 1280 so the wide arrangement has room for a rail\n * beside two cards (design 2026-11-02-shop-widescreen-layout §3). A head at\n * 960 over a body at 1280 would read as misaligned. */\n.s92dc8e_page > * {\n width: 100%;\n max-width: min(1280px, 100%);\n}\n\n.se536cd_pageHead {\n box-sizing: border-box;\n padding-top: calc(28px + var(--dsh-frame-top-clearance, 0px));\n}\n\n.sb9c160_pageTitle {\n margin: 0;\n font-size: 20px;\n font-weight: 500;\n line-height: 28px;\n}\n\n/* Secondary, as dsh's own intro: 5.80:1 on the light theme's white. */\n.sa532f1_pageIntro {\n margin: 4px 0 0;\n font-size: 13px;\n line-height: 20px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The shelf's two arrangements (design 2026-11-02-shop-widescreen-layout\n * §4). Base: today's column — the controls, then the results — with the\n * same 14px the panel used to put between them. The container is `.sc99bd6_panel`,\n * so these rules are queried from above, not from here. */\n.sd86001_shelfBody {\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n/* Narrow: the category chips and the switch are one row, as they are today.\n * `nowrap` is load-bearing — flex line-breaking uses the chips' MAX-content\n * width, so a wrapping row sends the switch to a line of its own the moment\n * the chips do not fit, which is every narrow panel. The bar shrinks and\n * wraps its own chips instead. The bar is a sibling of the switch now, not\n * its parent, so `align-items: flex-end` is what keeps the switch level with\n * the bar's last line rather than floating beside the middle of a two-line\n * block. */\n.s4b680b_controls {\n display: flex;\n flex-wrap: nowrap;\n align-items: flex-end;\n gap: 6px;\n}\n\n/* The rail's headings. Hidden below the threshold, where the controls are one\n * wrapping bar and these words would label nothing; the wide rule reveals\n * them (design 2026-11-02-shop-widescreen-layout §4). */\n.s91375e_railHeading {\n display: none;\n margin: 0;\n font-size: 11px;\n font-weight: 600;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s7e9262_results {\n display: flex;\n flex-direction: column;\n gap: 14px;\n}\n\n\n/* The two buttons on dsh's Plugins page (design 2026-10-16-shop-sidebar-page\n * §7), drawn as that page draws its own small outline buttons beside them —\n * dsh 0.2.0-rc.2's Button, sm + outline: 28px tall, 12px text on an 18px\n * line, 10px of side padding, the small radius, the neutral stroke. That\n * stroke is 0.5px in dsh and 1px here: every border in this stylesheet is,\n * and Chromium paints 0.5px as 1px at every ratio measured. */\n.s3306eb_detailAction {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 28px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-sm);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n font-size: 12px;\n line-height: 18px;\n cursor: pointer;\n}\n\n.s3306eb_detailAction:hover {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n.s3306eb_detailAction:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s14f3b1_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.s3a0a70_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.sf21dd5_skeletonGrid {\n display: grid;\n grid-template-columns: 1fr;\n gap: 8px;\n}\n\n.s393a26_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.s393a26_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.sdbd3bb_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.s78fd91_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.se0c7ad_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.se30d52_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.s393a26_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 .s393a26_skeletonCard span { animation: none; opacity: 0.75; }\n .s393a26_skeletonCard::after { content: none; }\n}\n\n.sc69180_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.sc69180_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.sc69180_actionButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.sa59b0a_toolbar {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n flex-wrap: wrap;\n}\n\n.sd633e3_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.se387e7_versionBlock {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.seccb93_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.s6b83c1_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.s6b83c1_updateSelfButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 20%, transparent);\n}\n\n.s6b83c1_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.s86fc72_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.s86fc72_checkUpdateButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n color: var(--dsw-alias-label-primary);\n}\n\n.s86fc72_checkUpdateButton:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n.s86fc72_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.s3b5e50_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.s3b5e50_githubLink:hover {\n color: var(--dsw-alias-label-primary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n.s3b5e50_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.s9200c1_selfUpdatePanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 8px;\n}\n\n.s76d7f5_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.s76d7f5_searchInput:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* Subdued line under the search box when a dictionary intent fired (design\n * 2026-10-08-search-query-expansion §4). One fact, no badge. */\n.sf4cb4b_expansionNote {\n margin: 4px 0 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sc6f44e_staleBadge {\n padding: 2px 8px;\n border-radius: 999px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n color: var(--shop-warn-on-tint);\n font-size: 12px;\n}\n\n.sce6c31_categoryBar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 6px;\n margin-top: 6px;\n /* A flex item of `.s4b680b_controls` at narrow widths: it may shrink below its\n * content, so the chips wrap instead of pushing the switch off the line.\n * It must NOT grow — a growing bar takes the whole line and pushes the\n * switch to a line of its own, where today the two share one. The wide\n * rail restores its natural height. */\n flex: 0 1 auto;\n min-width: 0;\n}\n\n.safdbbe_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.safdbbe_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 `.safdbbe_categoryButton.sc5d852_categoryButtonOn` — TWO classes — so it\n * matches `.safdbbe_categoryButton:hover`'s specificity and, coming after it, wins.\n * As a bare `.sc5d852_categoryButtonOn` it lost both `border-color` and `color` to the\n * hover rule for as long as the pointer stayed on the tab that had just been\n * clicked, which is precisely when a reader looks for confirmation.\n *\n * EVERY declaration here is a colour: a pressed tab must occupy exactly the\n * same box as an unpressed one, so the bar does not reflow — and with ~9 pills\n * on a wrapping row, one that grows can push the rest onto another line and\n * move the tab out from under the pointer that just clicked it. That is what\n * `font-weight: 600` did (bold metrics are wider than regular), and it is why\n * nothing may be added here that resolves to a length: no padding, no\n * border-width, no font-size, no letter-spacing. `css-tokens.s514620_client.s74d5ba_spec.s418ac5_ts`\n * fails the build on one.\n *\n * Nor a second line. An inset ring once doubled this border, and every control\n * in the stylesheet now draws exactly one 1px line, which is also the thinnest\n * the host paints (Chromium draws 0.5px as 1px). What separates pressed from\n * unpressed is lightness instead of thickness: the border is the hue mixed 30%\n * toward label-primary, the theme's foreground pole, so it clears 3:1 against\n * the bar in both themes for every hue — the raw hue measured 1.86:1 on white\n * for `ui` — and the fill under it is 22% of the hue. The `other` tab is the\n * case this is for: its hue IS the neutral gray this file uses for \"no\n * category\", so on the light theme the hue alone barely separates the two. */\n.safdbbe_categoryButton.sc5d852_categoryButtonOn {\n border-color: color-mix(in srgb, var(--category-hue) 70%, var(--dsw-alias-label-primary));\n background: color-mix(in srgb, var(--category-hue) 22%, transparent);\n color: color-mix(in srgb, var(--category-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Forced colours replace every colour above with the system palette, which\n * would leave the three colour declarations saying nothing and the pressed tab\n * indistinguishable from its neighbours, so this mode alone gets an outline. */\n@media (forced-colors: active) {\n .safdbbe_categoryButton.sc5d852_categoryButtonOn {\n outline: 2px solid ButtonText;\n outline-offset: -4px;\n }\n}\n\n.safdbbe_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 controls row at narrow\n * widths: `margin-left: auto` pushes it past the bar, which shrinks and wraps\n * its own chips (`flex: 0 1 auto`) rather than squeezing the switch. Under\n * the wide layout it is a full-width row under the rail's \"Filter\" heading.\n * It is a MODIFIER, not a ninth category — the categories select what to show\n * and this one subtracts from whatever they selected — so it takes the error\n * hue it filters on rather than joining the hue table.\n *\n * And it is a SWITCH, which is the difference the shape now carries. It used\n * to wear `.safdbbe_categoryButton`: same pill, same row, same size as the eight tabs,\n * differing only in being red. That reads as a ninth tab, and it is not one —\n * the tabs are choose-one and this is on-or-off. So it drops the pill chrome\n * entirely (no border, no fill, nothing to compete with the row it sits\n * beside) and puts the state in a track, the same one every installed card\n * carries. Nothing here restates the switch geometry; `--switch-hue` is the\n * whole of what this control says about it, and it reaches the label too, so\n * one declaration keeps the word and the track the same colour. */\n.sd6d2c7_incompatibleFilter {\n --switch-hue: var(--dsw-alias-state-error-primary);\n margin-left: auto;\n display: inline-flex;\n align-items: center;\n gap: 6px;\n /* Matches the pills' vertical padding so the bar keeps one line box whether\n * this control wraps onto a row of its own or shares theirs. */\n padding: 3px 0;\n border: 0;\n background: none;\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n cursor: pointer;\n}\n\n/* Hover lifts the word to full contrast and warms the track's border. Scoped\n * to the OFF track: `.sd6d2c7_incompatibleFilter:hover .sc8dc92_switch` outranks `.s12653b_switchOn`\n * by two classes, so unscoped it would strip the hue from the border at\n * exactly the moment a reader has the pointer on it to check the state. */\n.sd6d2c7_incompatibleFilter:hover {\n color: var(--dsw-alias-label-primary);\n}\n\n.sd6d2c7_incompatibleFilter:hover .sc8dc92_switch:not(.s12653b_switchOn) {\n border-color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-border-l2));\n}\n\n/* On. Written with both classes for the reason `.safdbbe_categoryButton.sc5d852_categoryButtonOn`\n * is: it has to match `:hover`'s specificity and come after it, or the colour\n * reverts under a pointer that has not moved since the click. */\n.sd6d2c7_incompatibleFilter.s515b4e_incompatibleFilterOn {\n color: color-mix(in srgb, var(--switch-hue) 45%, var(--dsw-alias-label-primary) 55%);\n}\n\n/* Off here means \"nothing is being taken away\" — the resting state — so the\n * knob steps back to the secondary label. The enable switch keeps the full\n * strength dot, where off means \"this plugin is disabled\" and is worth\n * noticing. In this bar it would be the heaviest mark in a row of hairline\n * pills, and on the light theme it is the WHOLE control: bg-layer-2 is the\n * same white as the panel there, so an off track is a hairline outline with a\n * near-black dot sitting in it. */\n.sd6d2c7_incompatibleFilter .sc8dc92_switch:not(.s12653b_switchOn) .sb7170f_switchKnob {\n background: var(--dsw-alias-label-secondary);\n}\n\n/* The ring has no border to trace, so it takes an offset and the pill radius\n * of the tabs it sits beside rather than hugging the text. */\n.sd6d2c7_incompatibleFilter:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 999px;\n}\n\n.s9964fe_updatableHeading {\n margin: 2px 0 0;\n font-size: 16px;\n font-weight: 600;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-primary);\n}\n\n.sc7794b_catalogStatsRow {\n display: flex;\n align-items: center;\n /* The row holds the catalog line, the refresh button and the shelf order's\n * three pills (design 2026-10-12-shelf-orders §4). Without wrapping, the\n * last of them overflows the tab at a narrow width. */\n flex-wrap: wrap;\n gap: 10px;\n margin: 6px 0 0;\n}\n\n/* The shelf's order control, at the right end of the stats row. `margin-left:\n * auto` is what puts it there while the line and the refresh button stay\n * left — and it is safe on a wrapping row, unlike a width. */\n.s28aa3c_sortGroup {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n margin-left: auto;\n}\n\n.s7842d7_sortLabel {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.s28d92b_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 `.sc69180_actionButton`:\n * this is an affordance, not a call to action — the catalog reloads on its\n * own at mount and the shelf is already usable without it. Named\n * `catalogRefresh*` (not `reload*`) so it cannot collide with the §4 page\n * reload offer below, which reloads the whole tab rather than refetching\n * the catalog data. */\n.s695d80_catalogRefreshButton {\n padding: 1px 9px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: transparent;\n color: var(--dsw-alias-label-secondary);\n font-size: 11px;\n line-height: 17px;\n cursor: pointer;\n}\n\n.s695d80_catalogRefreshButton:hover:not(:disabled) {\n border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2));\n color: var(--dsw-alias-brand-primary);\n}\n\n.s695d80_catalogRefreshButton:disabled {\n cursor: default;\n opacity: 0.6;\n}\n\n.s695d80_catalogRefreshButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n.s7a8ca3_catalogRefreshFailed {\n font-size: 11px;\n color: var(--shop-warn);\n}\n\n.s23625a_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. `auto-fill` with a 430px minimum\n * gives the two columns the wide layout buys — two tracks and their 12px gap\n * need 872px of results column — and one column below that (design\n * 2026-11-02-shop-widescreen-layout §5). The vertical gap is today's 8px. */\n.s36d340_cards {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(min(430px, 100%), 1fr));\n max-width: 100%;\n gap: 8px 12px;\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 .s36d340_cards { animation: none; }\n}\n\n/* The shelf's grid item is the <li> carrying a card's identity (ShopPage\n * reads it), not the card, and a grid item's min-width is auto: the 1fr track\n * could then never be narrower than the widest item's min-content, and every\n * card widens to it. Two things reach that width. Content that cannot wrap,\n * on a narrow window. And a card the browser skips (`content-visibility:\n * auto` below), which keeps the width it last rendered at: browsing a wide\n * window and narrowing it left every card 960px wide in a 662px column, its\n * right side clipped by the panel (measured on dsh 0.2.1-rc.2, 0.2.0-rc.2 and\n * 0.1.7-rc.2, 2026-10-22). Until the page took the main column the panel was\n * as wide as Settings made it, and a window resize did not move it. */\n/* The card is this item's child. Without a grid here the item stretches to\n * the row but the card keeps its content height, so the action row's\n * `margin-top: auto` has no free space to absorb and two cards in a row end\n * their buttons on different lines — measured 65px short at a 1280px tab\n * (2026-11-02). A one-row grid stretches the card to the cell. */\n.s36d340_cards > li {\n min-width: 0;\n display: grid;\n}\n\n.sf5fa2b_card {\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 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.s584a60_cardsSentry {\n height: 1px;\n margin: 0;\n padding: 0;\n}\n\n.s9d9bba_showingLine {\n margin: 0;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sf5fa2b_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 .sf5fa2b_card { transition: none; }\n .sf5fa2b_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.s28d979_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. `.safdbbe_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.sf5fa2b_card[data-category='tool'], .safdbbe_categoryButton[data-category='tool'] { --category-hue: #4C8DFF; }\n.sf5fa2b_card[data-category='provider'], .safdbbe_categoryButton[data-category='provider'] { --category-hue: #A78BFA; }\n.sf5fa2b_card[data-category='ui'], .safdbbe_categoryButton[data-category='ui'] { --category-hue: #2DD4BF; }\n.sf5fa2b_card[data-category='workflow'], .safdbbe_categoryButton[data-category='workflow'] { --category-hue: #F59E0B; }\n.sf5fa2b_card[data-category='integration'], .safdbbe_categoryButton[data-category='integration'] { --category-hue: #34D399; }\n.sf5fa2b_card[data-category='theme'], .safdbbe_categoryButton[data-category='theme'] { --category-hue: #F472B6; }\n.sf5fa2b_card[data-category='other'], .safdbbe_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.s91829d_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/* One entry's icon: a 32px tile holding a 24px image (design\n * 2026-10-23-shop-plugin-icons §8.3). The border and radius are dsh's own\n * (`PackageArtwork`'s .s7f7e1e_cardIcon), so a card's icon reads the same here as on\n * dsh's Plugins page. No backplate in either theme (§8.4). */\n.s9d98a4_entryIcon {\n box-sizing: border-box;\n flex: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n border: 0.5px solid var(--dsw-alias-border-l3);\n border-radius: var(--dsw-radius-md);\n overflow: hidden;\n}\n\n.sac0d07_entryIconImage {\n width: 24px;\n height: 24px;\n object-fit: contain;\n}\n\n.s6a017b_entryHeader {\n display: flex;\n flex-direction: row;\n align-items: flex-start;\n gap: 12px;\n min-width: 0;\n padding: 10px 12px 2px;\n border: none;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n\n.s6a017b_entryHeader:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n/* The name and the badge row, one column inside the header button. The\n * badges used to share the name's row, which at a 430px grid track left the\n * name about 120px; under it they get the full width and the name keeps its\n * line (design 2026-11-02-shop-widescreen-layout §5). */\n.sbc36fc_entryHeading {\n display: flex;\n flex-direction: column;\n gap: 3px;\n min-width: 0;\n flex: 1 1 auto;\n}\n\n/* The name fills the row and truncates rather than wraps; the badges stay\n * intact on the row under it. */\n.s4485fd_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.s150e7a_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.sbdfc2c_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 /* Grid rows stretch every card to the tallest one, and the card is a flex\n * column: this takes the leftover height above the buttons, so two cards\n * in one row end their action rows on the same line (design\n * 2026-11-02-shop-widescreen-layout §5). */\n margin-top: auto;\n}\n\n.sbdfc2c_cardActions > .s35ae56_gate,\n.sbdfc2c_cardActions > .s75cfe7_installPanel,\n.sbdfc2c_cardActions > .s130990_installedActions,\n.sbdfc2c_cardActions > .s848d91_receipt {\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.se4fd96_cardVersion {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 12px;\n letter-spacing: 0.02em;\n color: var(--dsw-alias-label-secondary);\n /* A release tag prints as tagged, never cut to seven characters (market\n * borrowings §11), and a tag can run to any length. The cap keeps every\n * tag of up to fourteen characters whole, prerelease suffix included\n * (`v0.1.0-alpha.0`): fourteen glyphs plus the letter-spacing above come to\n * about 14.5ch, so the cap is 15ch, not 14. A longer tag ends in an ellipsis,\n * and the tooltip carries the whole of it. */\n max-width: 15ch;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* The octocat marking a source the reader can read on GitHub, beside the\n * card's version. */\n.s4ebdb5_sourceBadge {\n display: inline-flex;\n align-items: center;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa10256_tierBadge {\n padding: 1px 7px;\n border-radius: 999px;\n font-size: 11px;\n line-height: 1.6;\n}\n\n.sa10256_tierBadge[data-tier='verified'] {\n color: var(--shop-success);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-success-primary) 40%, transparent);\n}\n\n.sa10256_tierBadge[data-tier='verified-stale'] {\n color: var(--shop-warn-on-tint);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 40%, transparent);\n}\n\n.sa10256_tierBadge[data-tier='community'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n/* The §C10 shadowed badge: an installed github entry the catalog refuses\n * shadowed-by-npm. Subdued/secondary rather than a warn tint — nothing is\n * wrong with the install itself; the shelf just cannot show it. */\n.sa10256_tierBadge[data-tier='shadowed'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n/* The §C5 archived badge: a github repository the owner has frozen.\n * Subdued register, same as shadowed — nothing is wrong with the install;\n * the pinned commit still serves, so the mark is informational only. */\n.sa10256_tierBadge[data-tier='archived'] {\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n border: 1px solid var(--dsw-alias-border-l2);\n}\n\n.se63699_incompatibleBadge {\n flex-shrink: 0;\n padding: 3px 9px;\n border-radius: 999px;\n font-size: 12px;\n white-space: nowrap;\n /* On the tint, not on the plain surface: this text reads on its own 14% red\n * fill, where the 90% red would measure 4.21:1 (light) and 4.43:1 (dark). */\n color: var(--shop-error-on-tint);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 40%, transparent);\n}\n\n.scc86dc_starsBadge {\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sd8ede4_chevron, .s879a81_chevronOpen {\n color: var(--dsw-alias-label-secondary);\n transition: transform 120ms ease;\n}\n\n.s879a81_chevronOpen { transform: rotate(180deg); }\n\n@media (prefers-reduced-motion: reduce) {\n .sd8ede4_chevron, .s879a81_chevronOpen { transition: none; }\n}\n\n.s2900a7_body {\n display: flex;\n flex-direction: column;\n gap: 8px;\n padding: 0 12px;\n}\n\n.sa41615_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.s91610a_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.s81bc49_summaryExpanded {\n -webkit-line-clamp: unset;\n display: block;\n}\n\n.sc64654_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.sfcd9cd_incompatibleDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n white-space: pre-line;\n color: var(--shop-error);\n}\n\n/* The way out of dsh's own refusal: the lead-in, then the exemption command\n * on its own line. */\n/* Block layout rather than flex: Firefox 153 will not line-clamp a container\n * that holds a display:flex child (Chromium 151 does), and the fold's\n * measured goal — \"the whole red block, remedy included, as one unit\" —\n * needs the container to clamp in BOTH engines the shop targets. The 4px\n * rhythm between the lead-in and the command is kept by the margins of the\n * children. */\n.sb6142c_remedy {\n display: block;\n}\n\n.sb6142c_remedy > * + * { margin-top: 4px; }\n\n/* The fold under a card's whole red block: two lines by default, a small\n * Refresh-pill-shaped toggle under it. Two containers, one rhythm: the shelf\n * uses `.s445a81_foldBlock` collapsed and `.sb6457b_foldBlockExpanded` open, and they share\n * one `display: block` (Firefox clamps no flex child inside a -webkit-box).\n * The clamp is on the BLOCK rather than any one line, so a 43-line remedy\n * counts as a unit instead of squashing the harness-peers line to a sliver\n * and hiding the command the reader actually came for. Both containers\n * still render the full block to a screen reader — `white-space: normal`\n * instead of pre-line keeps the copy's own `\\n` visible without forcing the\n * browser to lay the block's pieces like a text node. */\n.s445a81_foldBlock {\n display: block;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n display: -webkit-box;\n overflow: hidden;\n}\n\n.sb6457b_foldBlockExpanded { display: block; }\n\n/* The toggle. Geometry and quiet voice are the Refresh pill's\n * (`catalogStatsRow` right beside it on the same screen): one 1px border,\n * 11px text, secondary label, no fill. It is the only one of its kind here,\n * so a class of its own means one function of its own. */\n.sd9b244_foldToggle {\n /* The pill's own width. Under a card's red block it is an item of the card\n * body, a column, which stretches every child it is not told otherwise:\n * 934px against the Refresh pill's 59px at a 1440 window (2026-10-22). */\n align-self: flex-start;\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.sd9b244_foldToggle:hover { border-color: color-mix(in srgb, var(--dsw-alias-brand-primary) 45%, var(--dsw-alias-border-l2)); }\n.sd9b244_foldToggle:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary); outline-offset: 1px; }\n\n.s29ecbc_remedyLead {\n margin: 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The exemption command, bound for a terminal unchanged: one click selects\n * all of it, and it wraps anywhere rather than widening the card. A border,\n * not a fill, marks the box: the bg layers are one white in the light theme. */\n.se34c39_allowCommand {\n display: block;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-bg-base);\n border: 1px solid var(--dsw-alias-border-l1);\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-size: 11px;\n line-height: 1.5;\n white-space: pre-wrap;\n word-break: break-all;\n user-select: all;\n color: var(--dsw-alias-label-primary);\n}\n\n/* A refused install on a surface that does not state its blockers — the\n * outdated row — writes them out on their own full-width line under the\n * refused label, the command that clears dsh's refusal included. Block,\n * rather than flex: Firefox will not line-clamp a -webkit-box that holds a\n * display:flex child, and the fold this element can sit inside of carries\n * that clamp. The 6px rhythm between the block's lines is carried by the\n * children's margins. */\n.sb88eac_refusal {\n display: block;\n flex-basis: 100%;\n}\n\n.sb88eac_refusal > * + * { margin-top: 6px; }\n\n.seda8cf_capabilitiesBlock {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.s85ae81_capabilitiesNote {\n margin: 0;\n font-size: 11px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.se9f845_capabilities {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.se9f845_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.sa099e4_detail {\n border-top: 1px solid var(--dsw-alias-border-l1);\n padding-top: 8px;\n}\n\n.s33e230_detailRows {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 0;\n}\n\n.s3c9f5e_detailRow {\n display: flex;\n justify-content: space-between;\n gap: 12px;\n font-size: 12px;\n}\n\n.s3c9f5e_detailRow dt {\n color: var(--dsw-alias-label-secondary);\n}\n\n.s3c9f5e_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.s3c9f5e_detailRow a {\n color: var(--dsw-alias-brand-primary);\n text-decoration: none;\n}\n\n.s3c9f5e_detailRow a:hover {\n text-decoration: underline;\n}\n\n.s3c9f5e_detailRow a:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* What the entry IS rather than what you can do with it — how big it is and\n * who published it — at the right edge of the action row. `margin-left: auto`\n * is what pushes it there, and it lives on this wrapper rather than on either\n * label so the group stays flush right when only one of the two has a value —\n * a packument that named no account has no author, and an entry the registry\n * could not measure honestly has no size. Rarer than it was (every live entry\n * now carries a size, github included), but the wrapper is not what makes it\n * rare: without one, an EMPTY meta group still costs 8px, because\n * `.sbdfc2c_cardActions` is a flex row with `gap: 8px` and a zero-width item is still\n * an item. The row is a wrapping flex, so an active install flow (which claims\n * the full width) drops the whole group to the next line rather than squeezing\n * it. */\n.sf02a91_cardMeta {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n min-width: 0;\n}\n\n/* The on-disk size, left of the author. Mono and tabular so the digits of one\n * figure line up with the digits of another WHEREVER the two land: `.sf02a91_cardMeta`\n * is flush right and the author sits outside the size, so a size's x position\n * moves with the author's width and is different again on the many entries\n * that carry no author at all. There is no column to align to, which is why\n * the reason given here is per-figure legibility rather than the column the\n * first version of this comment claimed. Secondary colour, because it\n * qualifies the entry rather than announcing it.\n *\n * `font-variant-numeric` is safe HERE and would not be on a pill: this element\n * has no state rules, so nothing it does can reflow a wrapping row.\n *\n * `.s968579_shelfDate` shares this rule because it is the same kind of fact — a\n * fixed-width figure a reader compares down the shelf (design\n * 2026-10-12-shelf-orders §4) — and two copies of these declarations would\n * drift. */\n.s7859cb_size,\n.s968579_shelfDate {\n font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n font-variant-numeric: tabular-nums;\n font-size: 12px;\n letter-spacing: 0.02em;\n white-space: nowrap;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The publishing account, at the outer end of `.sf02a91_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 `.sf02a91_cardMeta`. There is no middot:\n * `.sf02a91_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.s4801d5_author {\n color: var(--dsw-alias-label-secondary);\n font-size: 12px;\n}\n\n.sfa18da_reviewedLine {\n margin: 8px 0 0;\n padding: 6px 8px;\n border-radius: 6px;\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 12%, transparent);\n font-size: 12px;\n color: var(--shop-warn-on-tint);\n}\n\n/* Install flow. */\n.s75cfe7_installPanel {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 2px;\n}\n\n/* ONE geometry for everything that occupies the install button's place: the\n * button itself, the confirm/cancel pair beside the restart gate, the installed\n * label, and the refused label. Stated once because a refused label HAS to look\n * like the button it replaces apart from its colour and its text, and four\n * copies of the same five declarations is how they stop looking alike.\n * `cursor: pointer` is NOT here: only the controls that can be pressed take it,\n * while a label renders with the default cursor. */\n.s17e180_installButton,\n.s4d480e_confirmButton,\n.s9466ff_cancelButton,\n.sb6cbde_installedLabel,\n.s6d82dc_refusedLabel {\n align-self: flex-start;\n margin: 0;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n font-size: 13px;\n}\n\n.s17e180_installButton, .s4d480e_confirmButton, .s9466ff_cancelButton {\n cursor: pointer;\n}\n\n.s17e180_installButton {\n border-color: var(--dsw-alias-brand-primary);\n background: var(--dsw-alias-brand-primary);\n color: var(--dsw-alias-bg-base);\n}\n\n/* Between the click and the host's answer. The flow ignores a repeat start for\n * the same identity, so this is the visible half of the same fact: a control\n * that says \"not now\" rather than one that looks ready to send a second\n * install. Only the button can be in this state — a label is never pressed. */\n.s17e180_installButton:disabled {\n cursor: wait;\n}\n\n.s17e180_installButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s4d480e_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.s4d480e_confirmButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-brand-primary) 88%, var(--dsw-alias-label-primary));\n}\n\n.s9466ff_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.s9466ff_cancelButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s17e180_installButton:focus-visible, .s4d480e_confirmButton:focus-visible, .s9466ff_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.sb6cbde_installedLabel {\n align-self: flex-start;\n margin: 0;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n font-size: 13px;\n color: var(--dsw-alias-label-secondary);\n background: var(--dsw-alias-bg-layer-2);\n}\n\n/* The refused Install/Update button's replacement: the same box as the button\n * (the geometry rule above), filled solid red, not pressable. The fill is the\n * derived red rather than the raw token because text sits on it — bg-base on\n * `--shop-error` measures 5.31:1 light and 6.14:1 dark — and the raw error red\n * under bg-base text measures 4.498:1, the miss this whole family of fixes\n * exists for. Nothing here changes on hover: it is a statement, not a control,\n * so it keeps the default cursor and its colours. */\n.s6d82dc_refusedLabel {\n border-color: var(--shop-error);\n background: var(--shop-error);\n color: var(--dsw-alias-bg-base);\n white-space: nowrap;\n}\n\n/* An installed card's controls: the installed label or the update button,\n * plus the uninstall button. The install panel's running/failed states are\n * column layouts and sit as one item of this row. */\n.s130990_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.safa1f4_uninstallButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 55%, transparent);\n border-radius: 6px;\n background: transparent;\n /* The on-tint red: hovering this button paints a 10% red fill under the\n * word, where the plain red measures 4.50:1 (light) — the same two\n * thousandths short of the floor the raw token shipped at. */\n color: var(--shop-error-on-tint);\n font-size: 13px;\n cursor: pointer;\n}\n\n.safa1f4_uninstallButton:hover {\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n.safa1f4_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.s19d2da_restartSelfButton {\n /* The version row's third state. Geometry matches .s86fc72_checkUpdateButton and\n * .s6b83c1_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.s19d2da_restartSelfButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* The two activation offers share one recipe: a border in an alias token,\n * never a `bg-layer` fill alone — all four bg-layer tokens collapse to the\n * same white under `body` in the light theme, and a fill-only button would\n * vanish there. Grouped rather than copied, because a copy is a rule that\n * can be corrected on one button and left wrong on the other, silently. */\n.s1916c4_restartButton,\n.se4b67d_reloadButton {\n align-self: flex-start;\n padding: 5px 14px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 6px;\n background: var(--dsw-alias-bg-layer-2);\n color: var(--dsw-alias-label-primary);\n font-size: 13px;\n cursor: pointer;\n}\n\n.s1916c4_restartButton:hover,\n.se4b67d_reloadButton:hover {\n border-color: var(--dsw-alias-label-secondary);\n}\n\n.s1916c4_restartButton:focus-visible,\n.se4b67d_reloadButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n/* A settled install's or uninstall's receipt: its log, what happened, and\n * what to do next, stacked. A column, so the log box spans the card as the\n * running and failed views' logs do, rather than being as wide as its longest\n * line (852, 409 and 260px on three cards of one page, 2026-10-22), and the\n * sentence never shares a line with a button it would sit misaligned beside. */\n.s848d91_receipt {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* The buttons under a receipt, a failure, or a reload or restart note, in one\n * row: the offer first (Reload, Restart dsh, Retry) and the way out (Dismiss)\n * beside it. They stood a line apart: Dismiss beside the reload note and\n * Reload under it, or Retry above Dismiss. */\n.s860bef_offerActions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n}\n\n/* The §4 reload offer: a notice plus its button, one item of\n * `.s130990_installedActions` the way the restart gate is — a column of its own\n * rather than inline with the row. */\n.se6345a_reloadPanel {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n gap: 6px;\n}\n\n\n.s35ae56_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.s4b04c5_gateTitle {\n margin: 0;\n font-size: 13px;\n font-weight: 600;\n color: var(--shop-warn-on-tint);\n}\n\n.s3552a4_gateBody {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.sf344ec_gateWarning {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n white-space: pre-line;\n color: var(--shop-error);\n}\n\n.sba54c1_gateActions {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n.s110c4a_installing {\n margin: 0;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n.sa13cb7_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.s326167_logLine {\n white-space: pre-wrap;\n word-break: break-all;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s88fa30_notice {\n margin: 0;\n font-size: 12px;\n color: var(--shop-success);\n}\n\n.s34c383_failedHeading {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--shop-error);\n}\n\n.s7d7ac6_failedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n.scf1455_rejectedCode {\n margin: 0;\n font-size: 12px;\n font-weight: 600;\n color: var(--shop-error);\n}\n\n.s604bbc_rejectedDetail {\n margin: 0;\n font-size: 12px;\n line-height: 1.6;\n color: var(--dsw-alias-label-primary);\n}\n\n/* The Updatable section. The class keeps the Host's field name; only the\n heading the reader sees was renamed. */\n.s81e51c_outdatedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.s6f80ac_outdatedList {\n display: flex;\n flex-direction: column;\n gap: 8px;\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n.s7e8f68_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.s27f8b7_outdatedInfo {\n display: flex;\n flex-direction: row;\n align-items: center;\n gap: 10px;\n min-width: 0;\n}\n\n/* The name and everything under it, beside the icon. */\n.sf16e21_outdatedText {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.s27f8b7_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.sb74cf7_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 .s150e7a_badges — the labels need no class of their own. */\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 12px;\n color: var(--dsw-alias-label-secondary);\n}\n\n/* The §C10 shadowed section. Reuses the outdated list's visual language; only\n * the section spacing and the per-row explanation paragraph are its own. */\n.s4da305_shadowedSection {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 6px;\n}\n\n.sf1d53c_shadowedDetail {\n margin: 4px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-secondary);\n}\n\n.s43bdbf_outdatedActions {\n display: flex;\n align-items: center;\n /* The reload offer (§4) mounts inside the switch beside the Update button\n * and is a two-line block, not a control: without wrapping, a row reading\n * [switch][notice + Reload][Update] overflowed the Settings dialog the shop\n * sat in through 0.8.7, and the page's column narrows with the window. */\n flex-wrap: wrap;\n gap: 10px;\n}\n\n/* The shop's one switch. It is worn by two controls that mean different\n * things — the enable/disable toggle on an installed card, and the shelf's\n * incompatible filter — so the geometry lives here once and each caller states\n * only its hue.\n *\n * `--switch-hue` is that knob, and it is read from the ANCESTOR rather than\n * declared per state: `.sd6d2c7_incompatibleFilter` sets it once and it reaches the\n * track and the label together, which is what keeps a red switch from sitting\n * under a neutral word. A declaration on `.sc8dc92_switch` itself would shadow the\n * inherited value (an element's own rule beats what it inherits), so the\n * default rides in the `var()` fallback and is resolved once into\n * `--track-hue` instead of being spelled out at each use.\n *\n * `box-sizing` and `padding` are stated because the two callers are different\n * elements — a `<button>`, which the UA gives padding, and a `<span>`, which\n * it does not. Without them the same class renders two sizes, and the knob\n * sits 2px above centre in the taller one. */\n.sc8dc92_switch {\n --track-hue: var(--switch-hue, var(--dsw-alias-state-success-primary));\n box-sizing: border-box;\n display: inline-block;\n position: relative;\n width: 32px;\n height: 18px;\n padding: 0;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 999px;\n background: var(--dsw-alias-bg-layer-2);\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n\n/* The knob's POSITION is the state, which is the reason this control needs no\n * `forced-colors` fallback the way the category pills do: a system palette\n * replaces every colour below and moves nothing. */\n.s12653b_switchOn {\n border-color: var(--track-hue);\n background: color-mix(in srgb, var(--track-hue) 55%, transparent);\n}\n\n.sb7170f_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.s12653b_switchOn .sb7170f_switchKnob {\n transform: translateX(14px);\n background: var(--dsw-alias-bg-base);\n}\n\n.sc8dc92_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 .sc8dc92_switch, .sb7170f_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.see584d_switchWrap {\n display: inline-flex;\n align-items: center;\n /* Same reason as `.s43bdbf_outdatedActions`: `.se6345a_reloadPanel`'s own comment calls\n * itself \"a column of its own rather than inline with the row\", which held\n * for `.s130990_installedActions` and not here until this line. */\n flex-wrap: wrap;\n gap: 8px;\n}\n\n/* THE WIDE RULES MUST STAY LAST. Nesting in @container adds no\n * specificity, so between a container rule and a top-level rule of the same\n * selector the source order decides. Placed above `.sce6c31_categoryBar`,\n * `.safdbbe_categoryButton` and the two focus rules, every one of these lost: the\n * rail kept the pills' row, the switch's auto margin and the outside ring,\n * and the geometry-only e2e passed (measured 2026-11-02).\n * `css-tokens.s514620_client.s74d5ba_spec.s418ac5_ts` fails if this block moves back up. */\n/* The rail. Two 430px tracks and their 12px gap need 872; the rail and its\n * 24px gap add 256; 12px of margin makes the threshold 1140. Below 872 the\n * grid's own `auto-fill` leaves one column. */\n@container (min-width: 1140px) {\n .sd86001_shelfBody {\n display: grid;\n grid-template-columns: 232px minmax(0, 1fr);\n column-gap: 24px;\n row-gap: 14px;\n }\n\n /* The rail sticks under dsh's frame top rather than scrolling away with\n * the results. `.sc99bd6_panel`'s `overflow: clip` is not a scroll container, so\n * the page stays the scrollport; the e2e proves it (design\n * 2026-11-02-shop-widescreen-layout §4). */\n .s4b680b_controls {\n flex-direction: column;\n align-items: stretch;\n gap: 8px;\n position: sticky;\n top: calc(16px + var(--dsh-frame-top-clearance, 0px));\n align-self: start;\n /* The cap subtracts the same clearance the offset adds. Without it a\n * rail whose content fits the cap hangs clearance - 16px below the\n * viewport while stuck (measured: 32px at the desktop frame's 48px), and\n * its last control only comes into view at the very bottom of the page.\n * The 32px is the 16px above the rail plus 16px below it. */\n max-height: calc(100vh - 32px - var(--dsh-frame-top-clearance, 0px));\n overflow: auto;\n }\n\n .s91375e_railHeading {\n display: block;\n }\n\n .sce6c31_categoryBar {\n flex: none;\n flex-direction: column;\n align-items: stretch;\n gap: 4px;\n /* The 6px belongs to the wrapping row; in the rail the controls' 8px gap\n * is the whole rhythm above the first button. */\n margin-top: 0;\n }\n\n /* Label left, count right: the two spans the buttons carry. */\n .safdbbe_categoryButton {\n display: flex;\n justify-content: space-between;\n }\n\n /* The rail is a column with `align-items: stretch`, where an auto left\n * margin would shrink the switch to its content and push it right. */\n .sd6d2c7_incompatibleFilter {\n margin-left: 0;\n }\n\n /* The rail is a scroll container (`overflow: auto`) and its controls are\n * flush with its padding box, so a ring drawn OUTSIDE them loses both\n * vertical segments to the clip — measured: red on the top edge and\n * corners, nothing on the sides. The inset ring, the idiom\n * `.s6a017b_entryHeader:focus-visible` already uses, keeps all four sides. */\n .safdbbe_categoryButton:focus-visible {\n outline-offset: -2px;\n }\n\n .sd6d2c7_incompatibleFilter:focus-visible {\n outline-offset: -2px;\n }\n}\n";
|
|
8444
|
+
if (typeof document !== "undefined" && !document.querySelector("style[data-plugin-css=\"bc430a83\"]")) {
|
|
8437
8445
|
const tag = document.createElement("style");
|
|
8438
|
-
tag.dataset.pluginCss = "
|
|
8446
|
+
tag.dataset.pluginCss = "bc430a83";
|
|
8439
8447
|
tag.textContent = css;
|
|
8440
8448
|
document.head.appendChild(tag);
|
|
8441
8449
|
}
|
|
8442
|
-
var
|
|
8443
|
-
"client": "
|
|
8444
|
-
"config": "
|
|
8445
|
-
"ts": "
|
|
8446
|
-
"spec": "
|
|
8447
|
-
"panel": "
|
|
8448
|
-
"
|
|
8449
|
-
"
|
|
8450
|
-
"
|
|
8451
|
-
"
|
|
8452
|
-
"
|
|
8453
|
-
"
|
|
8454
|
-
"
|
|
8455
|
-
"
|
|
8456
|
-
"
|
|
8457
|
-
"
|
|
8458
|
-
"
|
|
8459
|
-
"
|
|
8460
|
-
"
|
|
8461
|
-
"
|
|
8462
|
-
"
|
|
8463
|
-
"
|
|
8464
|
-
"
|
|
8465
|
-
"
|
|
8466
|
-
"
|
|
8467
|
-
"
|
|
8468
|
-
"
|
|
8469
|
-
"
|
|
8470
|
-
"
|
|
8471
|
-
"
|
|
8472
|
-
"
|
|
8473
|
-
"
|
|
8474
|
-
"
|
|
8475
|
-
"
|
|
8476
|
-
"
|
|
8477
|
-
"
|
|
8478
|
-
"
|
|
8479
|
-
"
|
|
8480
|
-
"
|
|
8481
|
-
"
|
|
8482
|
-
"
|
|
8483
|
-
"
|
|
8484
|
-
"
|
|
8485
|
-
"
|
|
8486
|
-
"
|
|
8487
|
-
"
|
|
8488
|
-
"
|
|
8489
|
-
"
|
|
8490
|
-
"
|
|
8491
|
-
"
|
|
8492
|
-
"
|
|
8493
|
-
"
|
|
8494
|
-
"
|
|
8495
|
-
"
|
|
8496
|
-
"
|
|
8497
|
-
"
|
|
8498
|
-
"
|
|
8499
|
-
"
|
|
8500
|
-
"
|
|
8501
|
-
"
|
|
8502
|
-
"
|
|
8503
|
-
"
|
|
8504
|
-
"
|
|
8505
|
-
"
|
|
8506
|
-
"
|
|
8507
|
-
"
|
|
8508
|
-
"
|
|
8509
|
-
"
|
|
8510
|
-
"
|
|
8511
|
-
"
|
|
8512
|
-
"
|
|
8513
|
-
"
|
|
8514
|
-
"
|
|
8515
|
-
"
|
|
8516
|
-
"
|
|
8517
|
-
"
|
|
8518
|
-
"
|
|
8519
|
-
"
|
|
8520
|
-
"
|
|
8521
|
-
"
|
|
8522
|
-
"
|
|
8523
|
-
"
|
|
8524
|
-
"
|
|
8525
|
-
"
|
|
8526
|
-
"
|
|
8527
|
-
"
|
|
8528
|
-
"
|
|
8529
|
-
"
|
|
8530
|
-
"
|
|
8531
|
-
"
|
|
8532
|
-
"
|
|
8533
|
-
"
|
|
8534
|
-
"
|
|
8535
|
-
"
|
|
8536
|
-
"
|
|
8537
|
-
"
|
|
8538
|
-
"
|
|
8539
|
-
"
|
|
8540
|
-
"
|
|
8541
|
-
"
|
|
8542
|
-
"
|
|
8543
|
-
"
|
|
8544
|
-
"
|
|
8545
|
-
"
|
|
8546
|
-
"
|
|
8547
|
-
"
|
|
8548
|
-
"
|
|
8549
|
-
"
|
|
8550
|
-
"
|
|
8551
|
-
"
|
|
8552
|
-
"
|
|
8553
|
-
"
|
|
8554
|
-
"
|
|
8555
|
-
"
|
|
8556
|
-
"
|
|
8557
|
-
"
|
|
8558
|
-
"
|
|
8559
|
-
"
|
|
8560
|
-
"
|
|
8561
|
-
"
|
|
8562
|
-
"
|
|
8563
|
-
"
|
|
8564
|
-
"
|
|
8565
|
-
"
|
|
8566
|
-
"
|
|
8567
|
-
"
|
|
8568
|
-
"
|
|
8569
|
-
"
|
|
8450
|
+
var _dsh_plugin_shop_css_bc430a83_default = {
|
|
8451
|
+
"client": "s514620_client",
|
|
8452
|
+
"config": "s7e11f7_config",
|
|
8453
|
+
"ts": "s418ac5_ts",
|
|
8454
|
+
"spec": "s74d5ba_spec",
|
|
8455
|
+
"panel": "sc99bd6_panel",
|
|
8456
|
+
"shelfBody": "sd86001_shelfBody",
|
|
8457
|
+
"searchInput": "s76d7f5_searchInput",
|
|
8458
|
+
"toolbar": "sa59b0a_toolbar",
|
|
8459
|
+
"page": "s92dc8e_page",
|
|
8460
|
+
"pageHead": "se536cd_pageHead",
|
|
8461
|
+
"pageTitle": "sb9c160_pageTitle",
|
|
8462
|
+
"pageIntro": "sa532f1_pageIntro",
|
|
8463
|
+
"controls": "s4b680b_controls",
|
|
8464
|
+
"railHeading": "s91375e_railHeading",
|
|
8465
|
+
"results": "s7e9262_results",
|
|
8466
|
+
"detailAction": "s3306eb_detailAction",
|
|
8467
|
+
"stateLine": "s14f3b1_stateLine",
|
|
8468
|
+
"srOnly": "s3a0a70_srOnly",
|
|
8469
|
+
"skeletonGrid": "sf21dd5_skeletonGrid",
|
|
8470
|
+
"skeletonCard": "s393a26_skeletonCard",
|
|
8471
|
+
"skeletonName": "sdbd3bb_skeletonName",
|
|
8472
|
+
"skeletonSummary": "s78fd91_skeletonSummary",
|
|
8473
|
+
"skeletonSummaryShort": "se0c7ad_skeletonSummaryShort",
|
|
8474
|
+
"skeletonActions": "se30d52_skeletonActions",
|
|
8475
|
+
"actionButton": "sc69180_actionButton",
|
|
8476
|
+
"toolbarRight": "sd633e3_toolbarRight",
|
|
8477
|
+
"versionBlock": "se387e7_versionBlock",
|
|
8478
|
+
"versionText": "seccb93_versionText",
|
|
8479
|
+
"updateSelfButton": "s6b83c1_updateSelfButton",
|
|
8480
|
+
"checkUpdateButton": "s86fc72_checkUpdateButton",
|
|
8481
|
+
"githubLink": "s3b5e50_githubLink",
|
|
8482
|
+
"selfUpdatePanel": "s9200c1_selfUpdatePanel",
|
|
8483
|
+
"expansionNote": "sf4cb4b_expansionNote",
|
|
8484
|
+
"staleBadge": "sc6f44e_staleBadge",
|
|
8485
|
+
"categoryBar": "sce6c31_categoryBar",
|
|
8486
|
+
"categoryButton": "safdbbe_categoryButton",
|
|
8487
|
+
"categoryButtonOn": "sc5d852_categoryButtonOn",
|
|
8488
|
+
"incompatibleFilter": "sd6d2c7_incompatibleFilter",
|
|
8489
|
+
"switch": "sc8dc92_switch",
|
|
8490
|
+
"switchOn": "s12653b_switchOn",
|
|
8491
|
+
"incompatibleFilterOn": "s515b4e_incompatibleFilterOn",
|
|
8492
|
+
"switchKnob": "sb7170f_switchKnob",
|
|
8493
|
+
"updatableHeading": "s9964fe_updatableHeading",
|
|
8494
|
+
"catalogStatsRow": "sc7794b_catalogStatsRow",
|
|
8495
|
+
"sortGroup": "s28aa3c_sortGroup",
|
|
8496
|
+
"sortLabel": "s7842d7_sortLabel",
|
|
8497
|
+
"catalogStats": "s28d92b_catalogStats",
|
|
8498
|
+
"catalogRefreshButton": "s695d80_catalogRefreshButton",
|
|
8499
|
+
"catalogRefreshFailed": "s7a8ca3_catalogRefreshFailed",
|
|
8500
|
+
"emptyLine": "s23625a_emptyLine",
|
|
8501
|
+
"cards": "s36d340_cards",
|
|
8502
|
+
"card": "sf5fa2b_card",
|
|
8503
|
+
"cardsSentry": "s584a60_cardsSentry",
|
|
8504
|
+
"showingLine": "s9d9bba_showingLine",
|
|
8505
|
+
"cardSpine": "s28d979_cardSpine",
|
|
8506
|
+
"categoryBadge": "s91829d_categoryBadge",
|
|
8507
|
+
"cardIcon": "s7f7e1e_cardIcon",
|
|
8508
|
+
"entryIcon": "s9d98a4_entryIcon",
|
|
8509
|
+
"entryIconImage": "sac0d07_entryIconImage",
|
|
8510
|
+
"entryHeader": "s6a017b_entryHeader",
|
|
8511
|
+
"entryHeading": "sbc36fc_entryHeading",
|
|
8512
|
+
"name": "s4485fd_name",
|
|
8513
|
+
"badges": "s150e7a_badges",
|
|
8514
|
+
"cardActions": "sbdfc2c_cardActions",
|
|
8515
|
+
"gate": "s35ae56_gate",
|
|
8516
|
+
"installPanel": "s75cfe7_installPanel",
|
|
8517
|
+
"installedActions": "s130990_installedActions",
|
|
8518
|
+
"receipt": "s848d91_receipt",
|
|
8519
|
+
"cardVersion": "se4fd96_cardVersion",
|
|
8520
|
+
"sourceBadge": "s4ebdb5_sourceBadge",
|
|
8521
|
+
"tierBadge": "sa10256_tierBadge",
|
|
8522
|
+
"incompatibleBadge": "se63699_incompatibleBadge",
|
|
8523
|
+
"starsBadge": "scc86dc_starsBadge",
|
|
8524
|
+
"chevron": "sd8ede4_chevron",
|
|
8525
|
+
"chevronOpen": "s879a81_chevronOpen",
|
|
8526
|
+
"body": "s2900a7_body",
|
|
8527
|
+
"summary": "sa41615_summary",
|
|
8528
|
+
"summaryZh": "s91610a_summaryZh",
|
|
8529
|
+
"summaryExpanded": "s81bc49_summaryExpanded",
|
|
8530
|
+
"summaryZhExpanded": "sc64654_summaryZhExpanded",
|
|
8531
|
+
"incompatibleDetail": "sfcd9cd_incompatibleDetail",
|
|
8532
|
+
"remedy": "sb6142c_remedy",
|
|
8533
|
+
"foldBlock": "s445a81_foldBlock",
|
|
8534
|
+
"foldBlockExpanded": "sb6457b_foldBlockExpanded",
|
|
8535
|
+
"foldToggle": "sd9b244_foldToggle",
|
|
8536
|
+
"remedyLead": "s29ecbc_remedyLead",
|
|
8537
|
+
"allowCommand": "se34c39_allowCommand",
|
|
8538
|
+
"refusal": "sb88eac_refusal",
|
|
8539
|
+
"capabilitiesBlock": "seda8cf_capabilitiesBlock",
|
|
8540
|
+
"capabilitiesNote": "s85ae81_capabilitiesNote",
|
|
8541
|
+
"capabilities": "se9f845_capabilities",
|
|
8542
|
+
"detail": "sa099e4_detail",
|
|
8543
|
+
"detailRows": "s33e230_detailRows",
|
|
8544
|
+
"detailRow": "s3c9f5e_detailRow",
|
|
8545
|
+
"cardMeta": "sf02a91_cardMeta",
|
|
8546
|
+
"shelfDate": "s968579_shelfDate",
|
|
8547
|
+
"size": "s7859cb_size",
|
|
8548
|
+
"author": "s4801d5_author",
|
|
8549
|
+
"reviewedLine": "sfa18da_reviewedLine",
|
|
8550
|
+
"installButton": "s17e180_installButton",
|
|
8551
|
+
"confirmButton": "s4d480e_confirmButton",
|
|
8552
|
+
"cancelButton": "s9466ff_cancelButton",
|
|
8553
|
+
"installedLabel": "sb6cbde_installedLabel",
|
|
8554
|
+
"refusedLabel": "s6d82dc_refusedLabel",
|
|
8555
|
+
"uninstallButton": "safa1f4_uninstallButton",
|
|
8556
|
+
"restartSelfButton": "s19d2da_restartSelfButton",
|
|
8557
|
+
"restartButton": "s1916c4_restartButton",
|
|
8558
|
+
"reloadButton": "se4b67d_reloadButton",
|
|
8559
|
+
"offerActions": "s860bef_offerActions",
|
|
8560
|
+
"reloadPanel": "se6345a_reloadPanel",
|
|
8561
|
+
"gateTitle": "s4b04c5_gateTitle",
|
|
8562
|
+
"gateBody": "s3552a4_gateBody",
|
|
8563
|
+
"gateWarning": "sf344ec_gateWarning",
|
|
8564
|
+
"gateActions": "sba54c1_gateActions",
|
|
8565
|
+
"installing": "s110c4a_installing",
|
|
8566
|
+
"log": "sa13cb7_log",
|
|
8567
|
+
"logLine": "s326167_logLine",
|
|
8568
|
+
"notice": "s88fa30_notice",
|
|
8569
|
+
"failedHeading": "s34c383_failedHeading",
|
|
8570
|
+
"failedDetail": "s7d7ac6_failedDetail",
|
|
8571
|
+
"rejectedCode": "scf1455_rejectedCode",
|
|
8572
|
+
"rejectedDetail": "s604bbc_rejectedDetail",
|
|
8573
|
+
"outdatedSection": "s81e51c_outdatedSection",
|
|
8574
|
+
"outdatedList": "s6f80ac_outdatedList",
|
|
8575
|
+
"outdatedRow": "s7e8f68_outdatedRow",
|
|
8576
|
+
"outdatedInfo": "s27f8b7_outdatedInfo",
|
|
8577
|
+
"outdatedText": "sf16e21_outdatedText",
|
|
8578
|
+
"outdatedVersions": "sb74cf7_outdatedVersions",
|
|
8579
|
+
"shadowedSection": "s4da305_shadowedSection",
|
|
8580
|
+
"shadowedDetail": "sf1d53c_shadowedDetail",
|
|
8581
|
+
"outdatedActions": "s43bdbf_outdatedActions",
|
|
8582
|
+
"switchWrap": "see584d_switchWrap"
|
|
8570
8583
|
};
|
|
8571
8584
|
//#endregion
|
|
8572
8585
|
//#region src/client/ShopDetailAction.tsx
|
|
@@ -8626,7 +8639,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8626
8639
|
if (name === null || !canOpen()) return null;
|
|
8627
8640
|
if (own) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8628
8641
|
type: "button",
|
|
8629
|
-
className:
|
|
8642
|
+
className: _dsh_plugin_shop_css_bc430a83_default.detailAction,
|
|
8630
8643
|
"data-shop-open-shop": true,
|
|
8631
8644
|
onClick: openShop,
|
|
8632
8645
|
children: t("openShop")
|
|
@@ -8635,7 +8648,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
8635
8648
|
const only = listed.keys.length === 1 ? listed.keys[0] ?? null : null;
|
|
8636
8649
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
8637
8650
|
type: "button",
|
|
8638
|
-
className:
|
|
8651
|
+
className: _dsh_plugin_shop_css_bc430a83_default.detailAction,
|
|
8639
8652
|
"data-shop-view-in-shop": true,
|
|
8640
8653
|
onClick: () => {
|
|
8641
8654
|
page.focus(name, only);
|
|
@@ -9954,13 +9967,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9954
9967
|
const { rootRef, expandable, expanded, toggle } = useFoldableRedBlock();
|
|
9955
9968
|
const kindName = attrName.replace(/^data-shop-/, "");
|
|
9956
9969
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
9957
|
-
className: expanded ?
|
|
9970
|
+
className: expanded ? _dsh_plugin_shop_css_bc430a83_default.foldBlockExpanded : _dsh_plugin_shop_css_bc430a83_default.foldBlock,
|
|
9958
9971
|
[attrName]: true,
|
|
9959
9972
|
ref: rootRef,
|
|
9960
9973
|
children
|
|
9961
9974
|
}), expandable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
9962
9975
|
type: "button",
|
|
9963
|
-
className:
|
|
9976
|
+
className: _dsh_plugin_shop_css_bc430a83_default.foldToggle,
|
|
9964
9977
|
"data-shop-fold": kindName,
|
|
9965
9978
|
"aria-expanded": expanded,
|
|
9966
9979
|
onClick: toggle,
|
|
@@ -9996,10 +10009,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
9996
10009
|
const [failed, setFailed] = (0, react.useState)(void 0);
|
|
9997
10010
|
const src = icon === void 0 || icon === failed ? DEFAULT_ICON_DATA_URL : icon;
|
|
9998
10011
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
9999
|
-
className:
|
|
10012
|
+
className: _dsh_plugin_shop_css_bc430a83_default.entryIcon,
|
|
10000
10013
|
"aria-hidden": "true",
|
|
10001
10014
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
|
|
10002
|
-
className:
|
|
10015
|
+
className: _dsh_plugin_shop_css_bc430a83_default.entryIconImage,
|
|
10003
10016
|
src,
|
|
10004
10017
|
width: 24,
|
|
10005
10018
|
height: 24,
|
|
@@ -10025,14 +10038,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10025
10038
|
* those nodes, and React's next commit throws on the ones it no longer finds
|
|
10026
10039
|
* (design 2026-09-26-market-borrowings §4). The tab renders no portals, so its
|
|
10027
10040
|
* root is its whole surface. */
|
|
10028
|
-
const PANEL_ROOT = `${
|
|
10041
|
+
const PANEL_ROOT = `${_dsh_plugin_shop_css_bc430a83_default.panel} notranslate`;
|
|
10029
10042
|
function ChevronIcon({ open }) {
|
|
10030
10043
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
10031
10044
|
viewBox: "0 0 16 16",
|
|
10032
10045
|
width: "14",
|
|
10033
10046
|
height: "14",
|
|
10034
10047
|
"aria-hidden": "true",
|
|
10035
|
-
className: open ?
|
|
10048
|
+
className: open ? _dsh_plugin_shop_css_bc430a83_default.chevronOpen : _dsh_plugin_shop_css_bc430a83_default.chevron,
|
|
10036
10049
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
10037
10050
|
fill: "currentColor",
|
|
10038
10051
|
d: "M3.5 6 8 10.5 12.5 6l1 1L8 12.5 2.5 7l1-1Z"
|
|
@@ -10068,17 +10081,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10068
10081
|
const uninstalling = uninstallFlow.view.kind === "running";
|
|
10069
10082
|
const removed = uninstallFlow.view.kind === "done";
|
|
10070
10083
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10071
|
-
className:
|
|
10084
|
+
className: _dsh_plugin_shop_css_bc430a83_default.card,
|
|
10072
10085
|
"data-shop-entry": entry.name,
|
|
10073
10086
|
"data-category": category,
|
|
10074
10087
|
children: [
|
|
10075
10088
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10076
|
-
className:
|
|
10089
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cardSpine,
|
|
10077
10090
|
"aria-hidden": "true"
|
|
10078
10091
|
}),
|
|
10079
10092
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
10080
10093
|
type: "button",
|
|
10081
|
-
className:
|
|
10094
|
+
className: _dsh_plugin_shop_css_bc430a83_default.entryHeader,
|
|
10082
10095
|
"aria-expanded": open,
|
|
10083
10096
|
"aria-controls": detailId,
|
|
10084
10097
|
onClick: () => {
|
|
@@ -10087,86 +10100,88 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10087
10100
|
},
|
|
10088
10101
|
children: [
|
|
10089
10102
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryIcon, { icon }),
|
|
10090
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10091
|
-
className: _dsh_plugin_shop_css_e3675a89_default.name,
|
|
10092
|
-
children: entry.name
|
|
10093
|
-
}),
|
|
10094
10103
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10095
|
-
className:
|
|
10096
|
-
children: [
|
|
10097
|
-
|
|
10098
|
-
|
|
10099
|
-
|
|
10100
|
-
|
|
10101
|
-
|
|
10102
|
-
|
|
10103
|
-
|
|
10104
|
-
|
|
10105
|
-
|
|
10106
|
-
|
|
10107
|
-
|
|
10108
|
-
|
|
10109
|
-
|
|
10110
|
-
"aria-
|
|
10111
|
-
|
|
10112
|
-
|
|
10113
|
-
|
|
10114
|
-
|
|
10104
|
+
className: _dsh_plugin_shop_css_bc430a83_default.entryHeading,
|
|
10105
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10106
|
+
className: _dsh_plugin_shop_css_bc430a83_default.name,
|
|
10107
|
+
children: entry.name
|
|
10108
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10109
|
+
className: _dsh_plugin_shop_css_bc430a83_default.badges,
|
|
10110
|
+
children: [
|
|
10111
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10112
|
+
className: _dsh_plugin_shop_css_bc430a83_default.categoryBadge,
|
|
10113
|
+
children: t(categoryKey(entry))
|
|
10114
|
+
}),
|
|
10115
|
+
entry.source === "npm" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10116
|
+
className: _dsh_plugin_shop_css_bc430a83_default.sourceBadge,
|
|
10117
|
+
"data-shop-source-npm": true,
|
|
10118
|
+
role: "img",
|
|
10119
|
+
"aria-label": t("npmSource"),
|
|
10120
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
10121
|
+
viewBox: "0 0 16 16",
|
|
10122
|
+
width: "12",
|
|
10123
|
+
height: "12",
|
|
10124
|
+
"aria-hidden": "true",
|
|
10125
|
+
fill: "currentColor",
|
|
10126
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
10127
|
+
fillRule: "evenodd",
|
|
10128
|
+
d: "M0 0v16h16V0H0zm13 13h-2V6H8v7H3V3h10v10z"
|
|
10129
|
+
})
|
|
10115
10130
|
})
|
|
10131
|
+
}),
|
|
10132
|
+
hasGithubHome(entry) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10133
|
+
className: _dsh_plugin_shop_css_bc430a83_default.sourceBadge,
|
|
10134
|
+
"data-shop-source-github": true,
|
|
10135
|
+
role: "img",
|
|
10136
|
+
"aria-label": t("githubSource"),
|
|
10137
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
10138
|
+
viewBox: "0 0 16 16",
|
|
10139
|
+
width: "12",
|
|
10140
|
+
height: "12",
|
|
10141
|
+
"aria-hidden": "true",
|
|
10142
|
+
fill: "currentColor",
|
|
10143
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" })
|
|
10144
|
+
})
|
|
10145
|
+
}),
|
|
10146
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10147
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cardVersion,
|
|
10148
|
+
"data-card-version": true,
|
|
10149
|
+
role: "img",
|
|
10150
|
+
"aria-label": versionName,
|
|
10151
|
+
title: versionName,
|
|
10152
|
+
children: version.text
|
|
10153
|
+
}),
|
|
10154
|
+
entry.tier !== "community" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10155
|
+
className: _dsh_plugin_shop_css_bc430a83_default.tierBadge,
|
|
10156
|
+
"data-tier": entry.tier,
|
|
10157
|
+
children: t(tierKey(entry.tier))
|
|
10158
|
+
}),
|
|
10159
|
+
entry.archived === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10160
|
+
className: _dsh_plugin_shop_css_bc430a83_default.tierBadge,
|
|
10161
|
+
"data-tier": "archived",
|
|
10162
|
+
children: t("archivedBadge")
|
|
10163
|
+
}),
|
|
10164
|
+
stars !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10165
|
+
className: _dsh_plugin_shop_css_bc430a83_default.starsBadge,
|
|
10166
|
+
role: "img",
|
|
10167
|
+
"aria-label": t("stars", { count: stars }),
|
|
10168
|
+
children: ["★ ", formatStars(stars)]
|
|
10116
10169
|
})
|
|
10117
|
-
|
|
10118
|
-
|
|
10119
|
-
|
|
10120
|
-
|
|
10121
|
-
role: "img",
|
|
10122
|
-
"aria-label": t("githubSource"),
|
|
10123
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
10124
|
-
viewBox: "0 0 16 16",
|
|
10125
|
-
width: "12",
|
|
10126
|
-
height: "12",
|
|
10127
|
-
"aria-hidden": "true",
|
|
10128
|
-
fill: "currentColor",
|
|
10129
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8Z" })
|
|
10130
|
-
})
|
|
10131
|
-
}),
|
|
10132
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10133
|
-
className: _dsh_plugin_shop_css_e3675a89_default.cardVersion,
|
|
10134
|
-
"data-card-version": true,
|
|
10135
|
-
role: "img",
|
|
10136
|
-
"aria-label": versionName,
|
|
10137
|
-
title: versionName,
|
|
10138
|
-
children: version.text
|
|
10139
|
-
}),
|
|
10140
|
-
entry.tier !== "community" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10141
|
-
className: _dsh_plugin_shop_css_e3675a89_default.tierBadge,
|
|
10142
|
-
"data-tier": entry.tier,
|
|
10143
|
-
children: t(tierKey(entry.tier))
|
|
10144
|
-
}),
|
|
10145
|
-
entry.archived === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10146
|
-
className: _dsh_plugin_shop_css_e3675a89_default.tierBadge,
|
|
10147
|
-
"data-tier": "archived",
|
|
10148
|
-
children: t("archivedBadge")
|
|
10149
|
-
}),
|
|
10150
|
-
stars !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10151
|
-
className: _dsh_plugin_shop_css_e3675a89_default.starsBadge,
|
|
10152
|
-
role: "img",
|
|
10153
|
-
"aria-label": t("stars", { count: stars }),
|
|
10154
|
-
children: ["★ ", formatStars(stars)]
|
|
10155
|
-
}),
|
|
10156
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronIcon, { open })
|
|
10157
|
-
]
|
|
10158
|
-
})
|
|
10170
|
+
]
|
|
10171
|
+
})]
|
|
10172
|
+
}),
|
|
10173
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronIcon, { open })
|
|
10159
10174
|
]
|
|
10160
10175
|
}),
|
|
10161
10176
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10162
|
-
className:
|
|
10177
|
+
className: _dsh_plugin_shop_css_bc430a83_default.body,
|
|
10163
10178
|
children: [
|
|
10164
10179
|
summary !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10165
|
-
className: open ? `${
|
|
10180
|
+
className: open ? `${_dsh_plugin_shop_css_bc430a83_default.summary} ${_dsh_plugin_shop_css_bc430a83_default.summaryExpanded}` : _dsh_plugin_shop_css_bc430a83_default.summary,
|
|
10166
10181
|
children: summary.en
|
|
10167
10182
|
}),
|
|
10168
10183
|
summary?.zh !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10169
|
-
className: open ? `${
|
|
10184
|
+
className: open ? `${_dsh_plugin_shop_css_bc430a83_default.summaryZh} ${_dsh_plugin_shop_css_bc430a83_default.summaryZhExpanded}` : _dsh_plugin_shop_css_bc430a83_default.summaryZh,
|
|
10170
10185
|
children: summary.zh
|
|
10171
10186
|
}),
|
|
10172
10187
|
blockers.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FoldableRedBlock, {
|
|
@@ -10174,28 +10189,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10174
10189
|
attrName: "data-shop-remedy",
|
|
10175
10190
|
children: blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
10176
10191
|
blocker,
|
|
10177
|
-
className:
|
|
10192
|
+
className: _dsh_plugin_shop_css_bc430a83_default.incompatibleDetail,
|
|
10178
10193
|
surface: "detail"
|
|
10179
10194
|
}, blocker.kind))
|
|
10180
10195
|
}),
|
|
10181
10196
|
open && entry.catalog !== void 0 && entry.catalog.capabilities.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10182
|
-
className:
|
|
10197
|
+
className: _dsh_plugin_shop_css_bc430a83_default.capabilitiesBlock,
|
|
10183
10198
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10184
|
-
className:
|
|
10199
|
+
className: _dsh_plugin_shop_css_bc430a83_default.capabilitiesNote,
|
|
10185
10200
|
children: t("capabilitiesNote")
|
|
10186
10201
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
10187
|
-
className:
|
|
10202
|
+
className: _dsh_plugin_shop_css_bc430a83_default.capabilities,
|
|
10188
10203
|
children: entry.catalog.capabilities.map((capability) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: capability }, capability))
|
|
10189
10204
|
})]
|
|
10190
10205
|
}),
|
|
10191
10206
|
open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
10192
10207
|
id: detailId,
|
|
10193
|
-
className:
|
|
10208
|
+
className: _dsh_plugin_shop_css_bc430a83_default.detail,
|
|
10194
10209
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
|
|
10195
|
-
className:
|
|
10210
|
+
className: _dsh_plugin_shop_css_bc430a83_default.detailRows,
|
|
10196
10211
|
children: [
|
|
10197
10212
|
npmUrl !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10198
|
-
className:
|
|
10213
|
+
className: _dsh_plugin_shop_css_bc430a83_default.detailRow,
|
|
10199
10214
|
"data-shop-npm": true,
|
|
10200
10215
|
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", {
|
|
10201
10216
|
href: npmUrl,
|
|
@@ -10205,7 +10220,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10205
10220
|
}) })]
|
|
10206
10221
|
}),
|
|
10207
10222
|
entry.repository !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10208
|
-
className:
|
|
10223
|
+
className: _dsh_plugin_shop_css_bc430a83_default.detailRow,
|
|
10209
10224
|
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", {
|
|
10210
10225
|
href: entry.repository,
|
|
10211
10226
|
target: "_blank",
|
|
@@ -10214,12 +10229,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10214
10229
|
}) : entry.repository })]
|
|
10215
10230
|
}),
|
|
10216
10231
|
entry.license !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10217
|
-
className:
|
|
10232
|
+
className: _dsh_plugin_shop_css_bc430a83_default.detailRow,
|
|
10218
10233
|
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 })]
|
|
10219
10234
|
})
|
|
10220
10235
|
]
|
|
10221
10236
|
}), entry.tier === "verified-stale" && entry.review !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10222
|
-
className:
|
|
10237
|
+
className: _dsh_plugin_shop_css_bc430a83_default.reviewedLine,
|
|
10223
10238
|
children: entry.review.reviewedVersion !== void 0 ? t("reviewedVersionLine", {
|
|
10224
10239
|
reviewed: versionLabel("npm", entry.review.reviewedVersion).text,
|
|
10225
10240
|
current: version.text
|
|
@@ -10232,7 +10247,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10232
10247
|
]
|
|
10233
10248
|
}),
|
|
10234
10249
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10235
|
-
className:
|
|
10250
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cardActions,
|
|
10236
10251
|
"data-shop-actions": true,
|
|
10237
10252
|
children: [installed === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [uninstallFlow.view.kind !== "idle" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UninstallPanel, {
|
|
10238
10253
|
name: entry.name,
|
|
@@ -10265,7 +10280,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10265
10280
|
restartBlocked,
|
|
10266
10281
|
reload
|
|
10267
10282
|
}, "install") : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10268
|
-
className:
|
|
10283
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installedLabel,
|
|
10269
10284
|
"data-shop-installed": true,
|
|
10270
10285
|
children: t("installed")
|
|
10271
10286
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerBadge, {
|
|
@@ -10292,15 +10307,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10292
10307
|
flow: uninstallFlow
|
|
10293
10308
|
}, "uninstall")
|
|
10294
10309
|
] }), (size !== void 0 || author !== null || shelfDay !== void 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10295
|
-
className:
|
|
10310
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cardMeta,
|
|
10296
10311
|
children: [
|
|
10297
10312
|
shelfDay !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10298
|
-
className:
|
|
10313
|
+
className: _dsh_plugin_shop_css_bc430a83_default.shelfDate,
|
|
10299
10314
|
"data-shop-shelf-date": true,
|
|
10300
10315
|
children: t(order === "added" ? "listedOn" : "updatedOn", { date: shelfDay })
|
|
10301
10316
|
}),
|
|
10302
10317
|
size !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10303
|
-
className:
|
|
10318
|
+
className: _dsh_plugin_shop_css_bc430a83_default.size,
|
|
10304
10319
|
"data-shop-size": true,
|
|
10305
10320
|
role: "img",
|
|
10306
10321
|
"aria-label": t("sizeLabel", { size }),
|
|
@@ -10308,7 +10323,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10308
10323
|
children: size
|
|
10309
10324
|
}),
|
|
10310
10325
|
author !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10311
|
-
className:
|
|
10326
|
+
className: _dsh_plugin_shop_css_bc430a83_default.author,
|
|
10312
10327
|
"data-shop-author": true,
|
|
10313
10328
|
children: t("authorLine", { author })
|
|
10314
10329
|
})
|
|
@@ -10358,13 +10373,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10358
10373
|
...attribute,
|
|
10359
10374
|
children: blocker.text
|
|
10360
10375
|
}), blocker.remedy !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10361
|
-
className:
|
|
10376
|
+
className: _dsh_plugin_shop_css_bc430a83_default.remedy,
|
|
10362
10377
|
"data-shop-remedy": blocker.kind,
|
|
10363
10378
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10364
|
-
className:
|
|
10379
|
+
className: _dsh_plugin_shop_css_bc430a83_default.remedyLead,
|
|
10365
10380
|
children: blocker.remedy.lead
|
|
10366
10381
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("code", {
|
|
10367
|
-
className:
|
|
10382
|
+
className: _dsh_plugin_shop_css_bc430a83_default.allowCommand,
|
|
10368
10383
|
"data-shop-allow-command": true,
|
|
10369
10384
|
children: blocker.remedy.command
|
|
10370
10385
|
})]
|
|
@@ -10402,7 +10417,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10402
10417
|
if (lead === void 0 || word === null) return null;
|
|
10403
10418
|
const detail = blockers.map((blocker) => blocker.text).join("\n");
|
|
10404
10419
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10405
|
-
className:
|
|
10420
|
+
className: _dsh_plugin_shop_css_bc430a83_default.incompatibleBadge,
|
|
10406
10421
|
"data-shop-blocker": lead.kind,
|
|
10407
10422
|
role: "img",
|
|
10408
10423
|
"aria-label": detail,
|
|
@@ -10435,39 +10450,39 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10435
10450
|
const refused = refusesInstall(blockers);
|
|
10436
10451
|
const word = blockerBadgeKey(blockers);
|
|
10437
10452
|
if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10438
|
-
className:
|
|
10453
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installPanel,
|
|
10439
10454
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10440
|
-
className:
|
|
10455
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installing,
|
|
10441
10456
|
children: t(installPhaseKey(view.phase))
|
|
10442
10457
|
}), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10443
|
-
className:
|
|
10458
|
+
className: _dsh_plugin_shop_css_bc430a83_default.log,
|
|
10444
10459
|
"data-shop-log": true,
|
|
10445
10460
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10446
|
-
className:
|
|
10461
|
+
className: _dsh_plugin_shop_css_bc430a83_default.logLine,
|
|
10447
10462
|
"data-shop-log-line": true,
|
|
10448
10463
|
children: line
|
|
10449
10464
|
}, index))
|
|
10450
10465
|
})]
|
|
10451
10466
|
});
|
|
10452
10467
|
if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10453
|
-
className:
|
|
10468
|
+
className: _dsh_plugin_shop_css_bc430a83_default.receipt,
|
|
10454
10469
|
children: [
|
|
10455
10470
|
view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10456
|
-
className:
|
|
10471
|
+
className: _dsh_plugin_shop_css_bc430a83_default.log,
|
|
10457
10472
|
"data-shop-log": true,
|
|
10458
10473
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10459
|
-
className:
|
|
10474
|
+
className: _dsh_plugin_shop_css_bc430a83_default.logLine,
|
|
10460
10475
|
"data-shop-log-line": true,
|
|
10461
10476
|
children: line
|
|
10462
10477
|
}, index))
|
|
10463
10478
|
}),
|
|
10464
10479
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10465
|
-
className:
|
|
10480
|
+
className: _dsh_plugin_shop_css_bc430a83_default.notice,
|
|
10466
10481
|
"data-shop-restart-notice": true,
|
|
10467
10482
|
children: t(activationNoticeKey(view.activation, view.restartReason))
|
|
10468
10483
|
}),
|
|
10469
10484
|
view.detail !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10470
|
-
className:
|
|
10485
|
+
className: _dsh_plugin_shop_css_bc430a83_default.notice,
|
|
10471
10486
|
"data-shop-done-note": true,
|
|
10472
10487
|
children: view.detail
|
|
10473
10488
|
}),
|
|
@@ -10480,7 +10495,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10480
10495
|
where: "install",
|
|
10481
10496
|
trailing: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10482
10497
|
type: "button",
|
|
10483
|
-
className:
|
|
10498
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cancelButton,
|
|
10484
10499
|
"data-shop-install-dismiss": true,
|
|
10485
10500
|
onClick: reset,
|
|
10486
10501
|
children: t("dismiss")
|
|
@@ -10489,37 +10504,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10489
10504
|
]
|
|
10490
10505
|
});
|
|
10491
10506
|
if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10492
|
-
className:
|
|
10507
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installPanel,
|
|
10493
10508
|
children: [
|
|
10494
10509
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10495
|
-
className:
|
|
10510
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedHeading,
|
|
10496
10511
|
children: t("installFailed")
|
|
10497
10512
|
}),
|
|
10498
10513
|
view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10499
|
-
className:
|
|
10514
|
+
className: _dsh_plugin_shop_css_bc430a83_default.log,
|
|
10500
10515
|
"data-shop-log": true,
|
|
10501
10516
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10502
|
-
className:
|
|
10517
|
+
className: _dsh_plugin_shop_css_bc430a83_default.logLine,
|
|
10503
10518
|
"data-shop-log-line": true,
|
|
10504
10519
|
children: line
|
|
10505
10520
|
}, index))
|
|
10506
10521
|
}),
|
|
10507
10522
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10508
|
-
className:
|
|
10523
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedDetail,
|
|
10509
10524
|
children: view.detail === "" ? t("installTransportFailed") : view.detail
|
|
10510
10525
|
}),
|
|
10511
10526
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10512
|
-
className:
|
|
10527
|
+
className: _dsh_plugin_shop_css_bc430a83_default.offerActions,
|
|
10513
10528
|
"data-shop-offer": true,
|
|
10514
10529
|
children: refused && word !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10515
10530
|
type: "button",
|
|
10516
|
-
className:
|
|
10531
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cancelButton,
|
|
10517
10532
|
"data-shop-install-dismiss": true,
|
|
10518
10533
|
onClick: reset,
|
|
10519
10534
|
children: t("dismiss")
|
|
10520
10535
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10521
10536
|
type: "button",
|
|
10522
|
-
className:
|
|
10537
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installButton,
|
|
10523
10538
|
"data-shop-install-retry": true,
|
|
10524
10539
|
disabled: starting,
|
|
10525
10540
|
onClick: () => {
|
|
@@ -10531,19 +10546,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10531
10546
|
]
|
|
10532
10547
|
});
|
|
10533
10548
|
if (view.kind === "rejected") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10534
|
-
className:
|
|
10549
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installPanel,
|
|
10535
10550
|
children: [
|
|
10536
10551
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10537
|
-
className:
|
|
10552
|
+
className: _dsh_plugin_shop_css_bc430a83_default.rejectedCode,
|
|
10538
10553
|
children: t(rejectionCodeKey(view.code))
|
|
10539
10554
|
}),
|
|
10540
10555
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10541
|
-
className:
|
|
10556
|
+
className: _dsh_plugin_shop_css_bc430a83_default.rejectedDetail,
|
|
10542
10557
|
children: view.detail
|
|
10543
10558
|
}),
|
|
10544
10559
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10545
10560
|
type: "button",
|
|
10546
|
-
className:
|
|
10561
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cancelButton,
|
|
10547
10562
|
"data-shop-install-dismiss": true,
|
|
10548
10563
|
onClick: reset,
|
|
10549
10564
|
children: t("dismiss")
|
|
@@ -10553,7 +10568,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10553
10568
|
const update = variant === "update";
|
|
10554
10569
|
const detail = blockers.map((blocker) => blocker.text).join("\n");
|
|
10555
10570
|
if (refused && word !== null) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10556
|
-
className:
|
|
10571
|
+
className: _dsh_plugin_shop_css_bc430a83_default.refusedLabel,
|
|
10557
10572
|
"data-shop-refused": true,
|
|
10558
10573
|
"data-shop-blocker-kind": blockers[0]?.kind,
|
|
10559
10574
|
role: "img",
|
|
@@ -10565,14 +10580,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10565
10580
|
attrName: "data-shop-refusal",
|
|
10566
10581
|
children: blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
10567
10582
|
blocker,
|
|
10568
|
-
className:
|
|
10583
|
+
className: _dsh_plugin_shop_css_bc430a83_default.gateWarning,
|
|
10569
10584
|
surface: "warning"
|
|
10570
10585
|
}, blocker.kind))
|
|
10571
10586
|
})] });
|
|
10572
10587
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
10573
10588
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10574
10589
|
type: "button",
|
|
10575
|
-
className:
|
|
10590
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installButton,
|
|
10576
10591
|
disabled: starting || locked,
|
|
10577
10592
|
...update ? { "data-shop-update": true } : { "data-shop-install": true },
|
|
10578
10593
|
onClick: () => {
|
|
@@ -10589,7 +10604,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10589
10604
|
attrName: "data-shop-blocker-lines",
|
|
10590
10605
|
children: blockers.map((blocker) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BlockerLine, {
|
|
10591
10606
|
blocker,
|
|
10592
|
-
className:
|
|
10607
|
+
className: _dsh_plugin_shop_css_bc430a83_default.gateWarning,
|
|
10593
10608
|
surface: "warning"
|
|
10594
10609
|
}, blocker.kind))
|
|
10595
10610
|
})
|
|
@@ -10604,34 +10619,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10604
10619
|
function UninstallPanel({ name, t, restart, restartBlocked, reload, flow }) {
|
|
10605
10620
|
const { view, start, reset } = flow;
|
|
10606
10621
|
if (view.kind === "running") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10607
|
-
className:
|
|
10622
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installPanel,
|
|
10608
10623
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10609
|
-
className:
|
|
10624
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installing,
|
|
10610
10625
|
children: t("uninstalling")
|
|
10611
10626
|
}), view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10612
|
-
className:
|
|
10627
|
+
className: _dsh_plugin_shop_css_bc430a83_default.log,
|
|
10613
10628
|
"data-shop-log": true,
|
|
10614
10629
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10615
|
-
className:
|
|
10630
|
+
className: _dsh_plugin_shop_css_bc430a83_default.logLine,
|
|
10616
10631
|
"data-shop-log-line": true,
|
|
10617
10632
|
children: line
|
|
10618
10633
|
}, index))
|
|
10619
10634
|
})]
|
|
10620
10635
|
});
|
|
10621
10636
|
if (view.kind === "done") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10622
|
-
className:
|
|
10637
|
+
className: _dsh_plugin_shop_css_bc430a83_default.receipt,
|
|
10623
10638
|
children: [
|
|
10624
10639
|
view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10625
|
-
className:
|
|
10640
|
+
className: _dsh_plugin_shop_css_bc430a83_default.log,
|
|
10626
10641
|
"data-shop-log": true,
|
|
10627
10642
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10628
|
-
className:
|
|
10643
|
+
className: _dsh_plugin_shop_css_bc430a83_default.logLine,
|
|
10629
10644
|
"data-shop-log-line": true,
|
|
10630
10645
|
children: line
|
|
10631
10646
|
}, index))
|
|
10632
10647
|
}),
|
|
10633
10648
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10634
|
-
className:
|
|
10649
|
+
className: _dsh_plugin_shop_css_bc430a83_default.notice,
|
|
10635
10650
|
"data-shop-uninstall-done": true,
|
|
10636
10651
|
children: t(uninstallActivationNoticeKey(view.activation))
|
|
10637
10652
|
}),
|
|
@@ -10644,7 +10659,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10644
10659
|
where: "uninstall",
|
|
10645
10660
|
trailing: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10646
10661
|
type: "button",
|
|
10647
|
-
className:
|
|
10662
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cancelButton,
|
|
10648
10663
|
"data-shop-uninstall-dismiss": true,
|
|
10649
10664
|
onClick: reset,
|
|
10650
10665
|
children: t("dismiss")
|
|
@@ -10653,37 +10668,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10653
10668
|
]
|
|
10654
10669
|
});
|
|
10655
10670
|
if (view.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10656
|
-
className:
|
|
10671
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installPanel,
|
|
10657
10672
|
children: [
|
|
10658
10673
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10659
|
-
className:
|
|
10674
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedHeading,
|
|
10660
10675
|
children: t("uninstallFailed")
|
|
10661
10676
|
}),
|
|
10662
10677
|
view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10663
|
-
className:
|
|
10678
|
+
className: _dsh_plugin_shop_css_bc430a83_default.log,
|
|
10664
10679
|
"data-shop-log": true,
|
|
10665
10680
|
children: view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10666
|
-
className:
|
|
10681
|
+
className: _dsh_plugin_shop_css_bc430a83_default.logLine,
|
|
10667
10682
|
"data-shop-log-line": true,
|
|
10668
10683
|
children: line
|
|
10669
10684
|
}, index))
|
|
10670
10685
|
}),
|
|
10671
10686
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10672
|
-
className:
|
|
10687
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedDetail,
|
|
10673
10688
|
children: view.detail === "" ? t("uninstallTransportFailed") : view.detail
|
|
10674
10689
|
}),
|
|
10675
10690
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10676
|
-
className:
|
|
10691
|
+
className: _dsh_plugin_shop_css_bc430a83_default.offerActions,
|
|
10677
10692
|
"data-shop-offer": true,
|
|
10678
10693
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10679
10694
|
type: "button",
|
|
10680
|
-
className:
|
|
10695
|
+
className: _dsh_plugin_shop_css_bc430a83_default.uninstallButton,
|
|
10681
10696
|
"data-shop-uninstall-retry": true,
|
|
10682
10697
|
onClick: () => void start({ name }),
|
|
10683
10698
|
children: t("retry")
|
|
10684
10699
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10685
10700
|
type: "button",
|
|
10686
|
-
className:
|
|
10701
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cancelButton,
|
|
10687
10702
|
"data-shop-uninstall-dismiss": true,
|
|
10688
10703
|
onClick: reset,
|
|
10689
10704
|
children: t("dismiss")
|
|
@@ -10694,7 +10709,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10694
10709
|
if (view.kind !== "idle") return null;
|
|
10695
10710
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10696
10711
|
type: "button",
|
|
10697
|
-
className:
|
|
10712
|
+
className: _dsh_plugin_shop_css_bc430a83_default.uninstallButton,
|
|
10698
10713
|
"data-shop-uninstall": true,
|
|
10699
10714
|
onClick: () => void start({ name }),
|
|
10700
10715
|
children: t("uninstall")
|
|
@@ -10735,44 +10750,44 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10735
10750
|
else if (outcome.kind === "unreachable") setRefusal(t("restartTransportFailed"));
|
|
10736
10751
|
};
|
|
10737
10752
|
const tail = trailing === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10738
|
-
className:
|
|
10753
|
+
className: _dsh_plugin_shop_css_bc430a83_default.offerActions,
|
|
10739
10754
|
"data-shop-offer": true,
|
|
10740
10755
|
children: trailing
|
|
10741
10756
|
});
|
|
10742
10757
|
if (monitor?.kind === "requesting" || monitor?.kind === "restarting") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10743
|
-
className:
|
|
10758
|
+
className: _dsh_plugin_shop_css_bc430a83_default.notice,
|
|
10744
10759
|
"data-shop-restarting": true,
|
|
10745
10760
|
children: t("restarting")
|
|
10746
10761
|
}), tail] });
|
|
10747
10762
|
if (monitor?.kind === "failed") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10748
|
-
className:
|
|
10763
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedDetail,
|
|
10749
10764
|
"data-shop-restart-error": true,
|
|
10750
10765
|
children: monitor.logFile === void 0 ? t("restartFailedNotice") : t("restartFailedLogNotice", { log: monitor.logFile })
|
|
10751
10766
|
}), tail] });
|
|
10752
10767
|
if (monitor?.kind === "not-restarted") return tail;
|
|
10753
10768
|
if (gateOpen) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10754
|
-
className:
|
|
10769
|
+
className: _dsh_plugin_shop_css_bc430a83_default.gate,
|
|
10755
10770
|
"data-shop-restart-gate": true,
|
|
10756
10771
|
children: [
|
|
10757
10772
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10758
|
-
className:
|
|
10773
|
+
className: _dsh_plugin_shop_css_bc430a83_default.gateTitle,
|
|
10759
10774
|
children: t("restartTitle")
|
|
10760
10775
|
}),
|
|
10761
10776
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10762
|
-
className:
|
|
10777
|
+
className: _dsh_plugin_shop_css_bc430a83_default.gateBody,
|
|
10763
10778
|
children: t("restartBody")
|
|
10764
10779
|
}),
|
|
10765
10780
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10766
|
-
className:
|
|
10781
|
+
className: _dsh_plugin_shop_css_bc430a83_default.gateActions,
|
|
10767
10782
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10768
10783
|
type: "button",
|
|
10769
|
-
className:
|
|
10784
|
+
className: _dsh_plugin_shop_css_bc430a83_default.confirmButton,
|
|
10770
10785
|
"data-shop-restart-confirm": true,
|
|
10771
10786
|
onClick: () => void onConfirm(),
|
|
10772
10787
|
children: t("restartConfirm")
|
|
10773
10788
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10774
10789
|
type: "button",
|
|
10775
|
-
className:
|
|
10790
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cancelButton,
|
|
10776
10791
|
onClick: () => setGateOpen(false),
|
|
10777
10792
|
children: t("cancel")
|
|
10778
10793
|
})]
|
|
@@ -10780,17 +10795,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10780
10795
|
]
|
|
10781
10796
|
}), tail] });
|
|
10782
10797
|
const refused = refusal === null ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10783
|
-
className:
|
|
10798
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedDetail,
|
|
10784
10799
|
"data-shop-restart-error": true,
|
|
10785
10800
|
children: refusal
|
|
10786
10801
|
});
|
|
10787
10802
|
if (gate !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [refused, tail] });
|
|
10788
10803
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [refused, /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10789
|
-
className:
|
|
10804
|
+
className: _dsh_plugin_shop_css_bc430a83_default.offerActions,
|
|
10790
10805
|
"data-shop-offer": true,
|
|
10791
10806
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10792
10807
|
type: "button",
|
|
10793
|
-
className:
|
|
10808
|
+
className: _dsh_plugin_shop_css_bc430a83_default.restartButton,
|
|
10794
10809
|
"data-shop-restart": true,
|
|
10795
10810
|
onClick: () => setGateOpen(true),
|
|
10796
10811
|
children: t("restart")
|
|
@@ -10809,13 +10824,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10809
10824
|
*/
|
|
10810
10825
|
function NotRestartedNotice({ t, pid, logFile }) {
|
|
10811
10826
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10812
|
-
className:
|
|
10827
|
+
className: _dsh_plugin_shop_css_bc430a83_default.selfUpdatePanel,
|
|
10813
10828
|
"data-shop-not-restarted": true,
|
|
10814
10829
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10815
|
-
className:
|
|
10830
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedDetail,
|
|
10816
10831
|
children: pid === void 0 ? t("notRestartedNotice") : t("notRestartedPidNotice", { pid: String(pid) })
|
|
10817
10832
|
}), logFile !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10818
|
-
className:
|
|
10833
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedDetail,
|
|
10819
10834
|
children: t("notRestartedLogNotice", { log: logFile })
|
|
10820
10835
|
})]
|
|
10821
10836
|
});
|
|
@@ -10841,7 +10856,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10841
10856
|
trailing
|
|
10842
10857
|
});
|
|
10843
10858
|
const tail = trailing === void 0 ? null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
10844
|
-
className:
|
|
10859
|
+
className: _dsh_plugin_shop_css_bc430a83_default.offerActions,
|
|
10845
10860
|
"data-shop-offer": true,
|
|
10846
10861
|
children: trailing
|
|
10847
10862
|
});
|
|
@@ -10853,7 +10868,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10853
10868
|
trailing
|
|
10854
10869
|
});
|
|
10855
10870
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10856
|
-
className:
|
|
10871
|
+
className: _dsh_plugin_shop_css_bc430a83_default.notice,
|
|
10857
10872
|
"data-shop-restart-disabled": true,
|
|
10858
10873
|
children: t(restartBlockedNoticeKey(restartBlocked))
|
|
10859
10874
|
}), tail] });
|
|
@@ -10864,17 +10879,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10864
10879
|
* would help without knowing that now is a good time. */
|
|
10865
10880
|
function ReloadPanel({ t, reload, where, trailing }) {
|
|
10866
10881
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10867
|
-
className:
|
|
10882
|
+
className: _dsh_plugin_shop_css_bc430a83_default.reloadPanel,
|
|
10868
10883
|
"data-shop-reload": where,
|
|
10869
10884
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10870
|
-
className:
|
|
10885
|
+
className: _dsh_plugin_shop_css_bc430a83_default.notice,
|
|
10871
10886
|
children: t("reloadNote")
|
|
10872
10887
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10873
|
-
className:
|
|
10888
|
+
className: _dsh_plugin_shop_css_bc430a83_default.offerActions,
|
|
10874
10889
|
"data-shop-offer": true,
|
|
10875
10890
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
10876
10891
|
type: "button",
|
|
10877
|
-
className:
|
|
10892
|
+
className: _dsh_plugin_shop_css_bc430a83_default.reloadButton,
|
|
10878
10893
|
onClick: reload,
|
|
10879
10894
|
children: t("reload")
|
|
10880
10895
|
}), trailing]
|
|
@@ -10923,7 +10938,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10923
10938
|
}
|
|
10924
10939
|
};
|
|
10925
10940
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10926
|
-
className:
|
|
10941
|
+
className: _dsh_plugin_shop_css_bc430a83_default.switchWrap,
|
|
10927
10942
|
"data-shop-enabled-switch": row.name,
|
|
10928
10943
|
children: [
|
|
10929
10944
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
@@ -10932,18 +10947,18 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10932
10947
|
"aria-checked": enabled,
|
|
10933
10948
|
"aria-label": t("enabledSwitch"),
|
|
10934
10949
|
"data-shop-toggle": true,
|
|
10935
|
-
className: `${
|
|
10950
|
+
className: `${_dsh_plugin_shop_css_bc430a83_default.switch} ${enabled ? _dsh_plugin_shop_css_bc430a83_default.switchOn : ""}`,
|
|
10936
10951
|
onClick: () => void onToggle(),
|
|
10937
10952
|
disabled: toggle.kind === "saving" || locked,
|
|
10938
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
10953
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_bc430a83_default.switchKnob })
|
|
10939
10954
|
}),
|
|
10940
10955
|
toggle.kind === "saved" && toggle.live && owed === "nothing" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10941
|
-
className:
|
|
10956
|
+
className: _dsh_plugin_shop_css_bc430a83_default.notice,
|
|
10942
10957
|
"data-shop-hot-apply": true,
|
|
10943
10958
|
children: t("hotApplyNote")
|
|
10944
10959
|
}),
|
|
10945
10960
|
owed === "restart" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10946
|
-
className:
|
|
10961
|
+
className: _dsh_plugin_shop_css_bc430a83_default.notice,
|
|
10947
10962
|
"data-shop-toggle-restart": true,
|
|
10948
10963
|
children: t("toggleRestartNote")
|
|
10949
10964
|
}),
|
|
@@ -10956,7 +10971,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10956
10971
|
where: "toggle"
|
|
10957
10972
|
}),
|
|
10958
10973
|
toggle.kind === "error" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
10959
|
-
className:
|
|
10974
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedDetail,
|
|
10960
10975
|
"data-shop-toggle-error": true,
|
|
10961
10976
|
children: toggle.detail
|
|
10962
10977
|
})
|
|
@@ -10971,22 +10986,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
10971
10986
|
* field is narrowed at the parameter. */
|
|
10972
10987
|
function OutdatedRow({ row, icon, tier, missing, harness, t, setEnabled, flowFor, locked, restart, restartBlocked, reload, page }) {
|
|
10973
10988
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10974
|
-
className:
|
|
10989
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedRow,
|
|
10975
10990
|
"data-shop-outdated-entry": row.name,
|
|
10976
10991
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10977
|
-
className:
|
|
10992
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedInfo,
|
|
10978
10993
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryIcon, { icon }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10979
|
-
className:
|
|
10994
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedText,
|
|
10980
10995
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
10981
|
-
className:
|
|
10996
|
+
className: _dsh_plugin_shop_css_bc430a83_default.name,
|
|
10982
10997
|
children: row.name
|
|
10983
10998
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
10984
|
-
className:
|
|
10999
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedVersions,
|
|
10985
11000
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("installedVersion", { version: versionLabel(row.source, row.installed).text }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("latestVersion", { version: versionLabel(row.source, row.latest).text }) })]
|
|
10986
11001
|
})]
|
|
10987
11002
|
})]
|
|
10988
11003
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
10989
|
-
className:
|
|
11004
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedActions,
|
|
10990
11005
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EnabledSwitch, {
|
|
10991
11006
|
row,
|
|
10992
11007
|
surface: "row",
|
|
@@ -11040,22 +11055,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11040
11055
|
function OutdatedSection({ state, entriesByKey, icons, missingByKey, harnessVerdicts, t, setEnabled, flowFor, uninstallFor, restart, restartBlocked, reload, page }) {
|
|
11041
11056
|
if (state.kind === "loading") return null;
|
|
11042
11057
|
if (state.kind === "error") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11043
|
-
className:
|
|
11058
|
+
className: _dsh_plugin_shop_css_bc430a83_default.stateLine,
|
|
11044
11059
|
"data-shop-outdated-error": true,
|
|
11045
11060
|
children: t("installedError")
|
|
11046
11061
|
});
|
|
11047
11062
|
const outdated = state.entries.filter((entry) => entry.outdated && entry.latest !== null);
|
|
11048
11063
|
if (outdated.length === 0) return null;
|
|
11049
11064
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
11050
|
-
className:
|
|
11065
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedSection,
|
|
11051
11066
|
"data-shop-outdated": true,
|
|
11052
11067
|
"aria-labelledby": UPDATABLE_HEADING_ID,
|
|
11053
11068
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
11054
|
-
className:
|
|
11069
|
+
className: _dsh_plugin_shop_css_bc430a83_default.updatableHeading,
|
|
11055
11070
|
id: UPDATABLE_HEADING_ID,
|
|
11056
11071
|
children: t("updatableSection")
|
|
11057
11072
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
11058
|
-
className:
|
|
11073
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedList,
|
|
11059
11074
|
children: outdated.map((row) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutdatedRow, {
|
|
11060
11075
|
row,
|
|
11061
11076
|
icon: iconOf(entriesByKey.get(identityKey(row)), icons),
|
|
@@ -11085,40 +11100,40 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11085
11100
|
const shadowed = entries.filter((entry) => entry.shadowed === true);
|
|
11086
11101
|
if (shadowed.length === 0) return null;
|
|
11087
11102
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
11088
|
-
className:
|
|
11103
|
+
className: _dsh_plugin_shop_css_bc430a83_default.shadowedSection,
|
|
11089
11104
|
"data-shop-shadowed": true,
|
|
11090
11105
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
11091
|
-
className:
|
|
11106
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedList,
|
|
11092
11107
|
children: shadowed.map((row) => {
|
|
11093
11108
|
const key = identityKey(row);
|
|
11094
11109
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11095
|
-
className:
|
|
11110
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedRow,
|
|
11096
11111
|
"data-shop-shadowed-entry": row.name,
|
|
11097
11112
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11098
|
-
className:
|
|
11113
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedInfo,
|
|
11099
11114
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryIcon, { icon: iconOf(entriesByKey.get(identityKey(row)), icons) }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
11100
|
-
className:
|
|
11115
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedText,
|
|
11101
11116
|
children: [
|
|
11102
11117
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11103
|
-
className:
|
|
11118
|
+
className: _dsh_plugin_shop_css_bc430a83_default.name,
|
|
11104
11119
|
children: row.name
|
|
11105
11120
|
}),
|
|
11106
11121
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11107
|
-
className:
|
|
11122
|
+
className: _dsh_plugin_shop_css_bc430a83_default.badges,
|
|
11108
11123
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11109
|
-
className:
|
|
11124
|
+
className: _dsh_plugin_shop_css_bc430a83_default.tierBadge,
|
|
11110
11125
|
"data-tier": "shadowed",
|
|
11111
11126
|
children: t("shadowedBadge")
|
|
11112
11127
|
})
|
|
11113
11128
|
}),
|
|
11114
11129
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11115
|
-
className:
|
|
11130
|
+
className: _dsh_plugin_shop_css_bc430a83_default.shadowedDetail,
|
|
11116
11131
|
children: t("shadowedDetail")
|
|
11117
11132
|
})
|
|
11118
11133
|
]
|
|
11119
11134
|
})]
|
|
11120
11135
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11121
|
-
className:
|
|
11136
|
+
className: _dsh_plugin_shop_css_bc430a83_default.outdatedActions,
|
|
11122
11137
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UninstallPanel, {
|
|
11123
11138
|
name: row.name,
|
|
11124
11139
|
t,
|
|
@@ -11168,16 +11183,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11168
11183
|
role: "alert",
|
|
11169
11184
|
children: [
|
|
11170
11185
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11171
|
-
className:
|
|
11186
|
+
className: _dsh_plugin_shop_css_bc430a83_default.stateLine,
|
|
11172
11187
|
children: say("tabCrashed", en.tabCrashed)
|
|
11173
11188
|
}),
|
|
11174
11189
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11175
|
-
className:
|
|
11190
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedDetail,
|
|
11176
11191
|
children: error.message
|
|
11177
11192
|
}),
|
|
11178
11193
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11179
11194
|
type: "button",
|
|
11180
|
-
className:
|
|
11195
|
+
className: _dsh_plugin_shop_css_bc430a83_default.actionButton,
|
|
11181
11196
|
onClick: () => this.setState({ error: null }),
|
|
11182
11197
|
children: say("retry", en.retry)
|
|
11183
11198
|
})
|
|
@@ -11504,19 +11519,19 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11504
11519
|
"data-shop-tab": true,
|
|
11505
11520
|
"aria-busy": "true",
|
|
11506
11521
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11507
|
-
className:
|
|
11522
|
+
className: _dsh_plugin_shop_css_bc430a83_default.srOnly,
|
|
11508
11523
|
children: t("loading")
|
|
11509
11524
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11510
|
-
className:
|
|
11525
|
+
className: _dsh_plugin_shop_css_bc430a83_default.skeletonGrid,
|
|
11511
11526
|
"data-shop-skeleton": true,
|
|
11512
11527
|
"aria-hidden": "true",
|
|
11513
11528
|
children: Array.from({ length: 8 }, (_, i) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11514
|
-
className:
|
|
11529
|
+
className: _dsh_plugin_shop_css_bc430a83_default.skeletonCard,
|
|
11515
11530
|
children: [
|
|
11516
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
11517
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
11518
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
11519
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className:
|
|
11531
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_bc430a83_default.skeletonName }),
|
|
11532
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_bc430a83_default.skeletonSummary }),
|
|
11533
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_bc430a83_default.skeletonSummaryShort }),
|
|
11534
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_bc430a83_default.skeletonActions })
|
|
11520
11535
|
]
|
|
11521
11536
|
}, i))
|
|
11522
11537
|
})]
|
|
@@ -11526,11 +11541,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11526
11541
|
translate: "no",
|
|
11527
11542
|
"data-shop-tab": true,
|
|
11528
11543
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11529
|
-
className:
|
|
11544
|
+
className: _dsh_plugin_shop_css_bc430a83_default.stateLine,
|
|
11530
11545
|
children: t("error")
|
|
11531
11546
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11532
11547
|
type: "button",
|
|
11533
|
-
className:
|
|
11548
|
+
className: _dsh_plugin_shop_css_bc430a83_default.actionButton,
|
|
11534
11549
|
onClick: () => {
|
|
11535
11550
|
setRequest({
|
|
11536
11551
|
kind: "retry",
|
|
@@ -11548,11 +11563,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11548
11563
|
"data-shop-tab": true,
|
|
11549
11564
|
children: [
|
|
11550
11565
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11551
|
-
className:
|
|
11566
|
+
className: _dsh_plugin_shop_css_bc430a83_default.toolbar,
|
|
11552
11567
|
children: [
|
|
11553
11568
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
11554
11569
|
type: "search",
|
|
11555
|
-
className:
|
|
11570
|
+
className: _dsh_plugin_shop_css_bc430a83_default.searchInput,
|
|
11556
11571
|
"aria-label": t("search"),
|
|
11557
11572
|
placeholder: t("search"),
|
|
11558
11573
|
value: query,
|
|
@@ -11565,31 +11580,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11565
11580
|
}),
|
|
11566
11581
|
expansionMemo.intents.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11567
11582
|
"data-shop-expansion-note": true,
|
|
11568
|
-
className:
|
|
11583
|
+
className: _dsh_plugin_shop_css_bc430a83_default.expansionNote,
|
|
11569
11584
|
children: t("zhExpansionNote", { terms: expansionMemo.terms.slice(1).map((term) => term.startsWith("#") ? term.slice(1) : term).join(", ") })
|
|
11570
11585
|
}),
|
|
11571
11586
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11572
|
-
className:
|
|
11587
|
+
className: _dsh_plugin_shop_css_bc430a83_default.toolbarRight,
|
|
11573
11588
|
children: [
|
|
11574
11589
|
result.stale && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11575
|
-
className:
|
|
11590
|
+
className: _dsh_plugin_shop_css_bc430a83_default.staleBadge,
|
|
11576
11591
|
children: t("staleLabel", { date: result.builtAt.slice(0, 10) })
|
|
11577
11592
|
}),
|
|
11578
11593
|
selfVersion !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11579
|
-
className:
|
|
11594
|
+
className: _dsh_plugin_shop_css_bc430a83_default.versionBlock,
|
|
11580
11595
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
11581
|
-
className:
|
|
11596
|
+
className: _dsh_plugin_shop_css_bc430a83_default.versionText,
|
|
11582
11597
|
"data-shop-version": true,
|
|
11583
11598
|
children: ["v", selfVersion.installed]
|
|
11584
11599
|
}), restartMonitor !== null ? null : selfPending && restartBlocked === null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11585
11600
|
type: "button",
|
|
11586
|
-
className:
|
|
11601
|
+
className: _dsh_plugin_shop_css_bc430a83_default.restartSelfButton,
|
|
11587
11602
|
"data-shop-restart": true,
|
|
11588
11603
|
onClick: () => setSelfRestartGate(true),
|
|
11589
11604
|
children: t("restart")
|
|
11590
11605
|
}) : !selfPending && selfVersion.outdated && selfVersion.latest !== null && selfUpdate.view.kind === "idle" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11591
11606
|
type: "button",
|
|
11592
|
-
className:
|
|
11607
|
+
className: _dsh_plugin_shop_css_bc430a83_default.updateSelfButton,
|
|
11593
11608
|
"data-shop-update-self": true,
|
|
11594
11609
|
onClick: () => {
|
|
11595
11610
|
if (selfVersion.latest !== null) selfUpdate.start({ version: selfVersion.latest });
|
|
@@ -11597,7 +11612,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11597
11612
|
children: t("update")
|
|
11598
11613
|
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11599
11614
|
type: "button",
|
|
11600
|
-
className:
|
|
11615
|
+
className: _dsh_plugin_shop_css_bc430a83_default.checkUpdateButton,
|
|
11601
11616
|
"data-shop-check-update": true,
|
|
11602
11617
|
title: t("checkUpdateTitle"),
|
|
11603
11618
|
disabled: checkState !== "idle",
|
|
@@ -11606,7 +11621,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11606
11621
|
})]
|
|
11607
11622
|
}),
|
|
11608
11623
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("a", {
|
|
11609
|
-
className:
|
|
11624
|
+
className: _dsh_plugin_shop_css_bc430a83_default.githubLink,
|
|
11610
11625
|
href: SHOP_REPO_URL,
|
|
11611
11626
|
target: "_blank",
|
|
11612
11627
|
rel: "noopener noreferrer",
|
|
@@ -11631,29 +11646,29 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11631
11646
|
logFile: restartMonitor.logFile
|
|
11632
11647
|
}),
|
|
11633
11648
|
selfUpdate.view.kind === "running" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11634
|
-
className:
|
|
11649
|
+
className: _dsh_plugin_shop_css_bc430a83_default.selfUpdatePanel,
|
|
11635
11650
|
"data-shop-self-updating": true,
|
|
11636
11651
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11637
|
-
className:
|
|
11652
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installing,
|
|
11638
11653
|
children: t(installPhaseKey(selfUpdate.view.phase))
|
|
11639
11654
|
}), selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11640
|
-
className:
|
|
11655
|
+
className: _dsh_plugin_shop_css_bc430a83_default.log,
|
|
11641
11656
|
"data-shop-log": true,
|
|
11642
11657
|
children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11643
|
-
className:
|
|
11658
|
+
className: _dsh_plugin_shop_css_bc430a83_default.logLine,
|
|
11644
11659
|
"data-shop-log-line": true,
|
|
11645
11660
|
children: line
|
|
11646
11661
|
}, index))
|
|
11647
11662
|
})]
|
|
11648
11663
|
}),
|
|
11649
11664
|
selfPending && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11650
|
-
className:
|
|
11665
|
+
className: _dsh_plugin_shop_css_bc430a83_default.selfUpdatePanel,
|
|
11651
11666
|
"data-shop-self-update-done": true,
|
|
11652
11667
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11653
|
-
className:
|
|
11668
|
+
className: _dsh_plugin_shop_css_bc430a83_default.installedActions,
|
|
11654
11669
|
children: [
|
|
11655
11670
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11656
|
-
className:
|
|
11671
|
+
className: _dsh_plugin_shop_css_bc430a83_default.notice,
|
|
11657
11672
|
children: t("installedRestartNotice")
|
|
11658
11673
|
}),
|
|
11659
11674
|
restartBlocked === null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RestartPanel, {
|
|
@@ -11666,7 +11681,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11666
11681
|
}
|
|
11667
11682
|
}),
|
|
11668
11683
|
restartBlocked !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11669
|
-
className:
|
|
11684
|
+
className: _dsh_plugin_shop_css_bc430a83_default.notice,
|
|
11670
11685
|
"data-shop-restart-disabled": true,
|
|
11671
11686
|
children: t(restartBlockedNoticeKey(restartBlocked))
|
|
11672
11687
|
})
|
|
@@ -11674,29 +11689,29 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11674
11689
|
})
|
|
11675
11690
|
}),
|
|
11676
11691
|
selfUpdate.view.kind === "failed" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11677
|
-
className:
|
|
11692
|
+
className: _dsh_plugin_shop_css_bc430a83_default.selfUpdatePanel,
|
|
11678
11693
|
"data-shop-self-update-failed": true,
|
|
11679
11694
|
children: [
|
|
11680
11695
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11681
|
-
className:
|
|
11696
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedHeading,
|
|
11682
11697
|
children: t("updateFailed")
|
|
11683
11698
|
}),
|
|
11684
11699
|
selfUpdate.view.log.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11685
|
-
className:
|
|
11700
|
+
className: _dsh_plugin_shop_css_bc430a83_default.log,
|
|
11686
11701
|
"data-shop-log": true,
|
|
11687
11702
|
children: selfUpdate.view.log.map((line, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
11688
|
-
className:
|
|
11703
|
+
className: _dsh_plugin_shop_css_bc430a83_default.logLine,
|
|
11689
11704
|
"data-shop-log-line": true,
|
|
11690
11705
|
children: line
|
|
11691
11706
|
}, index))
|
|
11692
11707
|
}),
|
|
11693
11708
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11694
|
-
className:
|
|
11709
|
+
className: _dsh_plugin_shop_css_bc430a83_default.failedDetail,
|
|
11695
11710
|
children: selfUpdate.view.detail === "" ? t("updateTransportFailed") : selfUpdate.view.detail
|
|
11696
11711
|
}),
|
|
11697
11712
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11698
11713
|
type: "button",
|
|
11699
|
-
className:
|
|
11714
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cancelButton,
|
|
11700
11715
|
"data-shop-update-self-dismiss": true,
|
|
11701
11716
|
onClick: () => {
|
|
11702
11717
|
selfUpdate.resetWhere((current) => current.kind === "failed");
|
|
@@ -11706,216 +11721,238 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11706
11721
|
]
|
|
11707
11722
|
}),
|
|
11708
11723
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11709
|
-
className:
|
|
11710
|
-
|
|
11711
|
-
|
|
11712
|
-
|
|
11713
|
-
|
|
11714
|
-
|
|
11715
|
-
|
|
11716
|
-
|
|
11717
|
-
|
|
11718
|
-
|
|
11719
|
-
|
|
11720
|
-
|
|
11721
|
-
|
|
11722
|
-
|
|
11723
|
-
|
|
11724
|
-
|
|
11725
|
-
|
|
11726
|
-
|
|
11727
|
-
|
|
11728
|
-
|
|
11729
|
-
|
|
11730
|
-
|
|
11731
|
-
|
|
11732
|
-
|
|
11733
|
-
|
|
11734
|
-
|
|
11735
|
-
|
|
11736
|
-
|
|
11737
|
-
|
|
11738
|
-
|
|
11739
|
-
|
|
11740
|
-
|
|
11741
|
-
|
|
11742
|
-
|
|
11743
|
-
|
|
11744
|
-
|
|
11745
|
-
|
|
11746
|
-
|
|
11747
|
-
|
|
11748
|
-
|
|
11749
|
-
|
|
11750
|
-
|
|
11751
|
-
|
|
11752
|
-
|
|
11753
|
-
|
|
11754
|
-
|
|
11755
|
-
|
|
11756
|
-
|
|
11757
|
-
|
|
11758
|
-
|
|
11759
|
-
|
|
11760
|
-
|
|
11761
|
-
|
|
11762
|
-
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
|
|
11766
|
-
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
|
|
11770
|
-
|
|
11771
|
-
|
|
11772
|
-
|
|
11773
|
-
|
|
11774
|
-
|
|
11775
|
-
|
|
11776
|
-
|
|
11777
|
-
},
|
|
11778
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("
|
|
11779
|
-
className:
|
|
11780
|
-
|
|
11781
|
-
|
|
11782
|
-
}), t("hideIncompatible", { count: incompatibleCount })]
|
|
11783
|
-
})
|
|
11784
|
-
]
|
|
11785
|
-
}),
|
|
11786
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11787
|
-
className: _dsh_plugin_shop_css_e3675a89_default.catalogStatsRow,
|
|
11788
|
-
children: [
|
|
11789
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11790
|
-
className: _dsh_plugin_shop_css_e3675a89_default.catalogStats,
|
|
11791
|
-
"data-shop-catalog-stats": true,
|
|
11792
|
-
children: t("catalogStats", {
|
|
11793
|
-
count: String(browsable.length),
|
|
11794
|
-
date: result.builtAt.slice(0, 10)
|
|
11795
|
-
})
|
|
11796
|
-
}),
|
|
11797
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11798
|
-
type: "button",
|
|
11799
|
-
className: _dsh_plugin_shop_css_e3675a89_default.catalogRefreshButton,
|
|
11800
|
-
"data-shop-catalog-refresh": true,
|
|
11801
|
-
disabled: reloading,
|
|
11802
|
-
onClick: () => {
|
|
11803
|
-
setReloading(true);
|
|
11804
|
-
setReloadFailed(false);
|
|
11805
|
-
setRequest({
|
|
11806
|
-
kind: "refresh",
|
|
11807
|
-
reverdicts: pendingReverdict()
|
|
11808
|
-
});
|
|
11809
|
-
setVersionReload((current) => current + 1);
|
|
11810
|
-
},
|
|
11811
|
-
children: reloading ? t("refreshing") : t("refresh")
|
|
11812
|
-
}),
|
|
11813
|
-
reloadFailed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11814
|
-
className: _dsh_plugin_shop_css_e3675a89_default.catalogRefreshFailed,
|
|
11815
|
-
"data-shop-catalog-refresh-failed": true,
|
|
11816
|
-
children: t("refreshFailed")
|
|
11817
|
-
}),
|
|
11818
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
11819
|
-
className: _dsh_plugin_shop_css_e3675a89_default.sortGroup,
|
|
11820
|
-
role: "group",
|
|
11821
|
-
"aria-labelledby": sortLabelId,
|
|
11822
|
-
"data-shop-sort": true,
|
|
11823
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11824
|
-
className: _dsh_plugin_shop_css_e3675a89_default.sortLabel,
|
|
11825
|
-
id: sortLabelId,
|
|
11826
|
-
children: t("sortLabel")
|
|
11827
|
-
}), SHELF_ORDERS.map((name) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11724
|
+
className: _dsh_plugin_shop_css_bc430a83_default.shelfBody,
|
|
11725
|
+
"data-shop-shelf": true,
|
|
11726
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11727
|
+
className: _dsh_plugin_shop_css_bc430a83_default.controls,
|
|
11728
|
+
"data-shop-controls": true,
|
|
11729
|
+
children: [
|
|
11730
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
11731
|
+
className: _dsh_plugin_shop_css_bc430a83_default.railHeading,
|
|
11732
|
+
children: t("categoriesHeading")
|
|
11733
|
+
}),
|
|
11734
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11735
|
+
className: _dsh_plugin_shop_css_bc430a83_default.categoryBar,
|
|
11736
|
+
role: "group",
|
|
11737
|
+
"aria-label": t("catalog"),
|
|
11738
|
+
children: [
|
|
11739
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
11740
|
+
type: "button",
|
|
11741
|
+
className: category === null ? `${_dsh_plugin_shop_css_bc430a83_default.categoryButton} ${_dsh_plugin_shop_css_bc430a83_default.categoryButtonOn}` : _dsh_plugin_shop_css_bc430a83_default.categoryButton,
|
|
11742
|
+
"aria-pressed": category === null,
|
|
11743
|
+
onClick: () => {
|
|
11744
|
+
page.setView({
|
|
11745
|
+
category: null,
|
|
11746
|
+
visibleCount: 48
|
|
11747
|
+
});
|
|
11748
|
+
},
|
|
11749
|
+
"data-shop-category-all": true,
|
|
11750
|
+
children: [
|
|
11751
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("all") }),
|
|
11752
|
+
" ",
|
|
11753
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: browsable.length })
|
|
11754
|
+
]
|
|
11755
|
+
}),
|
|
11756
|
+
CATEGORY_ORDER.map((key) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
11757
|
+
type: "button",
|
|
11758
|
+
className: category === key ? `${_dsh_plugin_shop_css_bc430a83_default.categoryButton} ${_dsh_plugin_shop_css_bc430a83_default.categoryButtonOn}` : _dsh_plugin_shop_css_bc430a83_default.categoryButton,
|
|
11759
|
+
"aria-pressed": category === key,
|
|
11760
|
+
"data-category": key,
|
|
11761
|
+
"data-shop-category-tab": key,
|
|
11762
|
+
onClick: () => {
|
|
11763
|
+
page.setView({
|
|
11764
|
+
category: key,
|
|
11765
|
+
visibleCount: 48
|
|
11766
|
+
});
|
|
11767
|
+
},
|
|
11768
|
+
children: [
|
|
11769
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t(categoryLocaleKey(key)) }),
|
|
11770
|
+
" ",
|
|
11771
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: categoryCounts.get(key) ?? 0 })
|
|
11772
|
+
]
|
|
11773
|
+
}, key)),
|
|
11774
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
11775
|
+
type: "button",
|
|
11776
|
+
className: category === "installed" ? `${_dsh_plugin_shop_css_bc430a83_default.categoryButton} ${_dsh_plugin_shop_css_bc430a83_default.categoryButtonOn}` : _dsh_plugin_shop_css_bc430a83_default.categoryButton,
|
|
11777
|
+
"aria-pressed": category === "installed",
|
|
11778
|
+
"data-shop-category-installed": true,
|
|
11779
|
+
onClick: () => {
|
|
11780
|
+
page.setView({
|
|
11781
|
+
category: "installed",
|
|
11782
|
+
visibleCount: 48
|
|
11783
|
+
});
|
|
11784
|
+
},
|
|
11785
|
+
children: [
|
|
11786
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: t("installed") }),
|
|
11787
|
+
" ",
|
|
11788
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: installedCount })
|
|
11789
|
+
]
|
|
11790
|
+
})
|
|
11791
|
+
]
|
|
11792
|
+
}),
|
|
11793
|
+
category !== "installed" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
11794
|
+
className: _dsh_plugin_shop_css_bc430a83_default.railHeading,
|
|
11795
|
+
children: t("filterHeading")
|
|
11796
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
11828
11797
|
type: "button",
|
|
11829
|
-
|
|
11830
|
-
"aria-
|
|
11831
|
-
|
|
11798
|
+
role: "switch",
|
|
11799
|
+
"aria-checked": hideIncompatible,
|
|
11800
|
+
className: hideIncompatible ? `${_dsh_plugin_shop_css_bc430a83_default.incompatibleFilter} ${_dsh_plugin_shop_css_bc430a83_default.incompatibleFilterOn}` : _dsh_plugin_shop_css_bc430a83_default.incompatibleFilter,
|
|
11801
|
+
title: t(hideIncompatible ? "showIncompatibleTitle" : "incompatibleFilterTitle"),
|
|
11802
|
+
"data-shop-hide-incompatible": true,
|
|
11832
11803
|
onClick: () => {
|
|
11833
|
-
page.
|
|
11834
|
-
|
|
11804
|
+
page.updateView((view) => ({
|
|
11805
|
+
hideIncompatible: !view.hideIncompatible,
|
|
11835
11806
|
visibleCount: 48
|
|
11836
|
-
});
|
|
11807
|
+
}));
|
|
11837
11808
|
},
|
|
11838
|
-
children:
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
|
|
11847
|
-
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
|
|
11852
|
-
|
|
11853
|
-
|
|
11854
|
-
|
|
11855
|
-
|
|
11856
|
-
|
|
11857
|
-
|
|
11858
|
-
|
|
11859
|
-
|
|
11860
|
-
|
|
11861
|
-
|
|
11862
|
-
|
|
11863
|
-
|
|
11864
|
-
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
11868
|
-
|
|
11869
|
-
|
|
11809
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11810
|
+
className: hideIncompatible ? `${_dsh_plugin_shop_css_bc430a83_default.switch} ${_dsh_plugin_shop_css_bc430a83_default.switchOn}` : _dsh_plugin_shop_css_bc430a83_default.switch,
|
|
11811
|
+
"aria-hidden": "true",
|
|
11812
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: _dsh_plugin_shop_css_bc430a83_default.switchKnob })
|
|
11813
|
+
}), t("hideIncompatible", { count: incompatibleCount })]
|
|
11814
|
+
})] })
|
|
11815
|
+
]
|
|
11816
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11817
|
+
className: _dsh_plugin_shop_css_bc430a83_default.results,
|
|
11818
|
+
"data-shop-results": true,
|
|
11819
|
+
children: [
|
|
11820
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
11821
|
+
className: _dsh_plugin_shop_css_bc430a83_default.catalogStatsRow,
|
|
11822
|
+
children: [
|
|
11823
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11824
|
+
className: _dsh_plugin_shop_css_bc430a83_default.catalogStats,
|
|
11825
|
+
"data-shop-catalog-stats": true,
|
|
11826
|
+
children: t("catalogStats", {
|
|
11827
|
+
count: String(browsable.length),
|
|
11828
|
+
date: result.builtAt.slice(0, 10)
|
|
11829
|
+
})
|
|
11830
|
+
}),
|
|
11831
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11832
|
+
type: "button",
|
|
11833
|
+
className: _dsh_plugin_shop_css_bc430a83_default.catalogRefreshButton,
|
|
11834
|
+
"data-shop-catalog-refresh": true,
|
|
11835
|
+
disabled: reloading,
|
|
11836
|
+
onClick: () => {
|
|
11837
|
+
setReloading(true);
|
|
11838
|
+
setReloadFailed(false);
|
|
11839
|
+
setRequest({
|
|
11840
|
+
kind: "refresh",
|
|
11841
|
+
reverdicts: pendingReverdict()
|
|
11842
|
+
});
|
|
11843
|
+
setVersionReload((current) => current + 1);
|
|
11844
|
+
},
|
|
11845
|
+
children: reloading ? t("refreshing") : t("refresh")
|
|
11846
|
+
}),
|
|
11847
|
+
reloadFailed && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11848
|
+
className: _dsh_plugin_shop_css_bc430a83_default.catalogRefreshFailed,
|
|
11849
|
+
"data-shop-catalog-refresh-failed": true,
|
|
11850
|
+
children: t("refreshFailed")
|
|
11851
|
+
}),
|
|
11852
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
11853
|
+
className: _dsh_plugin_shop_css_bc430a83_default.sortGroup,
|
|
11854
|
+
role: "group",
|
|
11855
|
+
"aria-labelledby": sortLabelId,
|
|
11856
|
+
"data-shop-sort": true,
|
|
11857
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
11858
|
+
className: _dsh_plugin_shop_css_bc430a83_default.sortLabel,
|
|
11859
|
+
id: sortLabelId,
|
|
11860
|
+
children: t("sortLabel")
|
|
11861
|
+
}), SHELF_ORDERS.map((name) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
11862
|
+
type: "button",
|
|
11863
|
+
className: order === name ? `${_dsh_plugin_shop_css_bc430a83_default.categoryButton} ${_dsh_plugin_shop_css_bc430a83_default.categoryButtonOn}` : _dsh_plugin_shop_css_bc430a83_default.categoryButton,
|
|
11864
|
+
"aria-pressed": order === name,
|
|
11865
|
+
"data-shop-order": name,
|
|
11866
|
+
onClick: () => {
|
|
11867
|
+
page.setView({
|
|
11868
|
+
order: name,
|
|
11869
|
+
visibleCount: 48
|
|
11870
|
+
});
|
|
11871
|
+
},
|
|
11872
|
+
children: t(shelfOrderLocaleKey(name))
|
|
11873
|
+
}, name))]
|
|
11874
|
+
})
|
|
11875
|
+
]
|
|
11876
|
+
}),
|
|
11877
|
+
result.plugins.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11878
|
+
className: _dsh_plugin_shop_css_bc430a83_default.emptyLine,
|
|
11879
|
+
children: t("empty")
|
|
11880
|
+
}) : filtered.length === 0 ? category === "installed" && installedState.kind !== "ready" ? installedState.kind === "loading" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11881
|
+
className: _dsh_plugin_shop_css_bc430a83_default.emptyLine,
|
|
11882
|
+
"data-shop-installed-loading": true,
|
|
11883
|
+
children: t("installedLoading")
|
|
11884
|
+
}) : null : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11885
|
+
className: _dsh_plugin_shop_css_bc430a83_default.emptyLine,
|
|
11886
|
+
"data-shop-empty": true,
|
|
11887
|
+
children: matched.length > 0 ? t("emptyIncompatibleFiltered") : t("emptySearch")
|
|
11888
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
|
|
11889
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cards,
|
|
11890
|
+
children: [visible.map((entry) => {
|
|
11891
|
+
const key = entryKey(entry);
|
|
11892
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
11893
|
+
"data-shop-identity": key,
|
|
11894
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EntryCard, {
|
|
11895
|
+
entry,
|
|
11896
|
+
icon: iconOf(entry, icons),
|
|
11897
|
+
stars: starsOf(entry, stars),
|
|
11898
|
+
order,
|
|
11899
|
+
shelfDay: shelfDayOf(entry),
|
|
11900
|
+
installed: installedByKey.get(key),
|
|
11901
|
+
missing: missingByKey.get(key) ?? [],
|
|
11902
|
+
harness: harnessVerdictOf(harnessVerdicts, key),
|
|
11903
|
+
nameTakenBy: nameTakenByKey.get(key),
|
|
11904
|
+
t,
|
|
11905
|
+
flow: flows.flowFor(key),
|
|
11906
|
+
uninstallFlow: uninstallFlows.flowFor(key),
|
|
11907
|
+
restart,
|
|
11908
|
+
restartBlocked,
|
|
11909
|
+
reload,
|
|
11910
|
+
setEnabled,
|
|
11911
|
+
inInstalledView: category === "installed",
|
|
11912
|
+
page
|
|
11913
|
+
})
|
|
11914
|
+
}, key);
|
|
11915
|
+
}), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
11916
|
+
ref: sentinelRef,
|
|
11917
|
+
className: _dsh_plugin_shop_css_bc430a83_default.cardsSentry,
|
|
11918
|
+
"data-shop-sentry": true,
|
|
11919
|
+
"aria-hidden": "true"
|
|
11920
|
+
})]
|
|
11921
|
+
}), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11922
|
+
className: _dsh_plugin_shop_css_bc430a83_default.showingLine,
|
|
11923
|
+
"aria-live": "polite",
|
|
11924
|
+
children: t("showing", {
|
|
11925
|
+
shown: String(visibleCount),
|
|
11926
|
+
total: String(filtered.length)
|
|
11927
|
+
})
|
|
11928
|
+
})] }),
|
|
11929
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutdatedSection, {
|
|
11930
|
+
state: installedState,
|
|
11931
|
+
entriesByKey,
|
|
11932
|
+
icons,
|
|
11933
|
+
missingByKey,
|
|
11934
|
+
harnessVerdicts,
|
|
11870
11935
|
t,
|
|
11871
|
-
|
|
11872
|
-
|
|
11936
|
+
setEnabled,
|
|
11937
|
+
flowFor: flows.flowFor,
|
|
11938
|
+
uninstallFor: uninstallFlows.flowFor,
|
|
11873
11939
|
restart,
|
|
11874
11940
|
restartBlocked,
|
|
11875
11941
|
reload,
|
|
11876
|
-
setEnabled,
|
|
11877
|
-
inInstalledView: category === "installed",
|
|
11878
11942
|
page
|
|
11943
|
+
}),
|
|
11944
|
+
category === "installed" && installedState.kind === "ready" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShadowedSection, {
|
|
11945
|
+
entries: installedState.entries,
|
|
11946
|
+
icons,
|
|
11947
|
+
entriesByKey,
|
|
11948
|
+
t,
|
|
11949
|
+
uninstallFlows,
|
|
11950
|
+
restart,
|
|
11951
|
+
restartBlocked,
|
|
11952
|
+
reload
|
|
11879
11953
|
})
|
|
11880
|
-
|
|
11881
|
-
}), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
11882
|
-
ref: sentinelRef,
|
|
11883
|
-
className: _dsh_plugin_shop_css_e3675a89_default.cardsSentry,
|
|
11884
|
-
"data-shop-sentry": true,
|
|
11885
|
-
"aria-hidden": "true"
|
|
11954
|
+
]
|
|
11886
11955
|
})]
|
|
11887
|
-
}), incremental && visibleCount < filtered.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
11888
|
-
className: _dsh_plugin_shop_css_e3675a89_default.showingLine,
|
|
11889
|
-
"aria-live": "polite",
|
|
11890
|
-
children: t("showing", {
|
|
11891
|
-
shown: String(visibleCount),
|
|
11892
|
-
total: String(filtered.length)
|
|
11893
|
-
})
|
|
11894
|
-
})] }),
|
|
11895
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(OutdatedSection, {
|
|
11896
|
-
state: installedState,
|
|
11897
|
-
entriesByKey,
|
|
11898
|
-
icons,
|
|
11899
|
-
missingByKey,
|
|
11900
|
-
harnessVerdicts,
|
|
11901
|
-
t,
|
|
11902
|
-
setEnabled,
|
|
11903
|
-
flowFor: flows.flowFor,
|
|
11904
|
-
uninstallFor: uninstallFlows.flowFor,
|
|
11905
|
-
restart,
|
|
11906
|
-
restartBlocked,
|
|
11907
|
-
reload,
|
|
11908
|
-
page
|
|
11909
|
-
}),
|
|
11910
|
-
category === "installed" && installedState.kind === "ready" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ShadowedSection, {
|
|
11911
|
-
entries: installedState.entries,
|
|
11912
|
-
icons,
|
|
11913
|
-
entriesByKey,
|
|
11914
|
-
t,
|
|
11915
|
-
uninstallFlows,
|
|
11916
|
-
restart,
|
|
11917
|
-
restartBlocked,
|
|
11918
|
-
reload
|
|
11919
11956
|
})
|
|
11920
11957
|
]
|
|
11921
11958
|
});
|
|
@@ -11957,10 +11994,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
11957
11994
|
}
|
|
11958
11995
|
/**
|
|
11959
11996
|
* Where the reader is on the shelf: the first card whose bottom lies below
|
|
11960
|
-
* the page's top edge, and its top relative to that edge. The cards
|
|
11961
|
-
*
|
|
11962
|
-
*
|
|
11963
|
-
* one per
|
|
11997
|
+
* the page's top edge, and its top relative to that edge. The cards are laid
|
|
11998
|
+
* out row-major in document order — one per row before 2026-11-02, two per
|
|
11999
|
+
* row since — so their bottoms never fall with their index, and a binary
|
|
12000
|
+
* search reads a handful of their rects on each scroll event, never one per
|
|
12001
|
+
* card.
|
|
11964
12002
|
*
|
|
11965
12003
|
* A card whose top lies below the edge counts only while it lies no further
|
|
11966
12004
|
* below than the shelf's gap between cards, as when the edge falls in that
|
|
@@ -12046,7 +12084,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
12046
12084
|
}, [page]);
|
|
12047
12085
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
12048
12086
|
ref: scroller,
|
|
12049
|
-
className: `${
|
|
12087
|
+
className: `${_dsh_plugin_shop_css_bc430a83_default.page} notranslate`,
|
|
12050
12088
|
translate: "no",
|
|
12051
12089
|
"data-shop-page": true,
|
|
12052
12090
|
onScroll: (event) => {
|
|
@@ -12056,15 +12094,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
12056
12094
|
onTouchStart: cancelRestore,
|
|
12057
12095
|
onKeyDown: cancelRestore,
|
|
12058
12096
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
12059
|
-
className:
|
|
12097
|
+
className: _dsh_plugin_shop_css_bc430a83_default.pageHead,
|
|
12060
12098
|
"data-shop-page-head": true,
|
|
12061
12099
|
"data-window-drag": true,
|
|
12062
12100
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h1", {
|
|
12063
|
-
className:
|
|
12101
|
+
className: _dsh_plugin_shop_css_bc430a83_default.pageTitle,
|
|
12064
12102
|
"data-shop-page-title": true,
|
|
12065
12103
|
children: t("title")
|
|
12066
12104
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
12067
|
-
className:
|
|
12105
|
+
className: _dsh_plugin_shop_css_bc430a83_default.pageIntro,
|
|
12068
12106
|
"data-shop-page-intro": true,
|
|
12069
12107
|
children: t("intro")
|
|
12070
12108
|
})]
|