@hraness/design-kit 0.35.0 → 0.35.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/AGENT_SETUP.md CHANGED
@@ -13,6 +13,7 @@ import { AgentCommandTabs, AgentSetupPrompt } from "@hraness/design-kit/react";
13
13
  label="Set up Relay with your agent"
14
14
  prompt={setupPrompt}
15
15
  targets={agentSetupTargets(setupPrompt)}
16
+ targetsPlacement="below"
16
17
  />
17
18
  <AgentCommandTabs commands={[
18
19
  { id: "terminal", label: "Codex", mark: "codex", command: "relay init" },
@@ -24,6 +25,9 @@ The prompt preview clips long text with a bottom fade. Copy sits at the
24
25
  bottom right and copies the complete source. A native disclosure reveals
25
26
  the complete prompt without JavaScript. Provider actions move beside the
26
27
  preview when the containing block is wide enough; narrower blocks stack.
28
+ Set `targetsPlacement="below"` to keep actions under the prompt in a compact
29
+ grid with up to three columns. Prompt, command-tab, and platform-install copy
30
+ buttons share the same 44-pixel minimum height and visual treatment.
27
31
  The optional `onCopied` callback runs after a successful copy. Its errors
28
32
  cannot change clipboard feedback.
29
33
 
package/ARTICLE_COPY.md CHANGED
@@ -118,13 +118,18 @@ Title: "How <consumer> uses <provider>". It lives on the consumer's host.
118
118
 
119
119
  A provider may keep one page, such as "Built on <provider>", that lists the products using it. Each entry is the registered relation's own sentence and a link to the consumer's "How <consumer> uses <provider>" post when one exists. The hub is an index. It does not restate each post.
120
120
 
121
- ### Technique posts in two halves
121
+ ### Technique posts
122
122
 
123
123
  A technique post teaches one method, such as property tests, model checking, or proofs. It lives on hraness.com, and a product host may carry a product-specific version that shows the technique inside that product.
124
124
 
125
- - **First half, for any reader.** Ground it in problems people already know, such as vibe-coded slop (software a model wrote quickly that looks finished and breaks on the second use) and fragile foundations (a product built on code nobody checked). Use one familiar failure ("It only breaks if you save, lose connection, then reopen"). Then describe the brighter alternative: what it is like when a whole class of that failure cannot happen. No code or notation in this half.
126
- - **Second half, how Hraness does it.** Show the method with durable examples: laws, invariants, and small code excerpts that still read correctly after a refactor. Cite the repository file that holds the real example. Avoid line numbers and file names that change often, and keep internal jargon to the one term the technique needs.
127
- - End on the last supported fact. State what the technique does not prove, once, at its true scope.
125
+ - Answer one useful question. Explain the reasoning with a concrete example the reader can follow, using code or notation where it helps.
126
+ - Use public references when they clarify the method or support a claim. A product example belongs only when it helps answer the question; neither Hraness code nor a product recommendation is required.
127
+ - Keep internal build diaries, verification logs, and implementation chronology out of the article. Teach the method in the order the reader needs it.
128
+ - End on the last supported fact. State a material limitation where it changes the reader’s decision; do not append a generic disclaimer.
129
+
130
+ ### Illustrations
131
+
132
+ Follow the [shared illustration guidance](https://github.com/hraness/.github/blob/main/STYLE.md). Use SlopCamera to create an illustration when it helps explain the article, with a limited brand palette and a reference that establishes the intended visual style. Record the tools, model, references, and actual asset source used; do not substitute a generic provenance claim. Keep captions useful and optional.
128
133
 
129
134
  ## Titles and formulas
130
135
 
@@ -152,10 +157,10 @@ Some products can be pointed at other people's accounts or data: authenticated b
152
157
 
153
158
  ## Drafting and review note
154
159
 
155
- Every article states who drafted it and who reviewed it, visibly, on every host. The owner decided this on 2026-09-23, as relayed to the task that added this guide. It applies to articles only; other pages follow `STYLE.md`.
160
+ Every article states who drafted it and who reviewed it, visibly, on every host. This applies to articles only; other pages follow `STYLE.md`.
156
161
 
157
162
  - Render `ArticleProvenance`, or the `provenance` prop of `MarketingArticle`, from the admission record with `articleProvenanceFromAdmission()`. Do not type the sentence by hand.
158
- - An AI-drafted post from repository sources reads: "Drafted with AI from the source code and reviewed by <reviewer>."
163
+ - The default AI drafting kind is `ai`: "Drafted with AI and reviewed by <reviewer>." Use `ai-from-source` and its "from the source code" wording only when the article was drafted from source code.
159
164
  - Name the reviewer as it is. An AI reviewer has `reviewerType: "ai"` and a name that says it is AI, for example "Claude Opus 5.5 (claude-opus-5-5) editorial review". The sentence says "human" only when `reviewerType` is `human-editor`.
160
165
  - Keep `humanReview` null unless a person reviewed the article. Never describe AI review as human review.
161
166
  - The byline is "Hraness" on every host. Do not credit a person, including the owner, for an AI-drafted post. A person who later adopts a post may switch the byline to their own name; the drafting and review note stays.
@@ -172,6 +177,7 @@ Every article URL has an `ArticleAdmission` record in its host's registry, check
172
177
 
173
178
  ## Freshness
174
179
 
180
+ - Keep review, publication, and update metadata truthful. Educational bodies do not need repeated "as of" dates, build identifiers, or freshness labels; include a date or version in the prose only when the explanation depends on it.
175
181
  - Every record has `reassessOn`, 28 to 56 days after `review.reviewedOn`. `articleAdmissionsDue(registry, today)` lists the records to look at again.
176
182
  - Render versions, release dates, and status labels from release data (`package.json`, a published release file, or the portfolio facts). Never type a version into an article body.
177
183
  - Each record names its refresh triggers: a release tag bump, a change to a relation's `detail`, a rename, or a change to the feature the post describes.
package/README.md CHANGED
@@ -11,7 +11,7 @@ Pin a GitHub release tag:
11
11
  ```json
12
12
  {
13
13
  "dependencies": {
14
- "@hraness/design-kit": "github:hraness/design-kit#v0.35.0",
14
+ "@hraness/design-kit": "github:hraness/design-kit#v0.35.1",
15
15
  "@hraness/ui": "github:hraness/ui#v0.5.17"
16
16
  }
17
17
  }
@@ -23,6 +23,10 @@ Pin a GitHub release tag:
23
23
  installation so the framework-neutral root and syntax highlighter can be used
24
24
  on their own. React 18 or 19 and React DOM 18 or 19 are also peer dependencies.
25
25
 
26
+ ### Compact agent setup and consistent copying
27
+
28
+ Version 0.35.1 adds `AgentSetupPrompt.targetsPlacement="below"` for a compact provider grid beneath the prompt. Prompt, agent-command, and platform-install copy actions share a 44-pixel control. Platform requirements appear in the terminal footer. Clipboard fallbacks, copy-before-open handoffs, keyboard controls, and no-script access remain available. The article guide also centers technique posts on the reader’s question, with accurate drafting notes and focused illustration guidance.
29
+
26
30
  ### Clearer marketing controls and agent setup
27
31
 
28
32
  Version 0.35.0 aligns related tools with the studio's portfolio categories and compact product cards. It adds account sections and matching actions, a compact comparison table, shared SVG diagram conventions, open benefit grids, and an install-first hero slot. Walkthroughs use folder tabs and a stable stage with accessible chevron controls. Install commands use shell syntax colors and a quiet primary border; ordinary links use dotted underlines.
@@ -749,7 +753,7 @@ bun run browser:install
749
753
  bun run check
750
754
  ```
751
755
 
752
- The stable dependency pair for this release is `@hraness/ui` `v0.5.17` with `@hraness/design-kit` `v0.35.0`. Version 0.31.0 keeps the `limits` beat and beats marked `social: false` out of the social kit and adds `socialPost` for social wording that stands without a caveat. Version 0.30.3 refreshes the portfolio snapshot so related-product cards use each product's own spelling, such as GhostGet and TextButler. Version 0.30.2 keeps the narrow and stacked install-tab layout when another package compiles the same atoms into a later cascade layer. Version 0.30.1 keeps every PlatformInstall tab name whole in columns down to 200px by stacking each mark above its name, using a container query on the component. Version 0.30.0 adds `site-shell.css`, which keeps short-page footers at the viewport bottom. Version 0.29.3 preserves readable selected install tabs in forced colors. Version 0.29.2 keeps all three PlatformInstall tabs visible at 320 to 360px and draws each platform mark once per component. Version 0.29.1 keeps marketing action labels readable in forced colors. Version 0.29.0 adds `PlatformInstall`, one install block for every CLI site: a tab per operating system with its mark, the install command with a Copy button that announces the result, optional alternative commands such as npm or Homebrew, and a note for platforms without a native build. After hydration it selects the visitor's operating system; without JavaScript every command shows. It also adds `PlatformIcon` (Apple, Tux, and Windows marks in `currentColor`) and a `PlatformBadges` "Runs on" row, plus `platformLabel`, `platformMark`, `detectPlatform`, and `matchDetectedPlatform` at the package root. See [Install commands for each platform](#install-commands-for-each-platform). No existing export changes. Version 0.28.0 adds the launch kit. `@hraness/design-kit/mockups` draws labelled illustrations of chat, feeds, inboxes, articles, terminals, browsers, desktop windows, menu bars, and phones in server-safe plain React with no StyleX or React Aria, styled by `@hraness/design-kit/mockups.css`; each renders as one image with a text description and no headings. `@hraness/design-kit/mockups/client` adds `ModeShowcase`, `FitToWidth`, and `StepThrough`. `@hraness/design-kit/launch`, with no React, holds the `LaunchBeat`, `LaunchFacts`, and `SocialKit` shapes with `resolveLaunchBeats`, `buildSocialKit`, and `assertLaunchKit`. `@hraness/design-kit/testing` gives product repositories `blogConformance`, `renderMatrix`, `assertNoHeadings`, `assertRoleImgWithLabel`, and `assertFakeHandles`. The React entries add `ArticleFigure`, `ArticleVideo` with `articleVideoJsonLd`, `ArticleTable`, `ArticleBarChart`, `ComparisonTable`, `LaunchBeats`, and `SocialKitPanel`, and `MarketingProofFrame` takes `chrome` (`window`, `browser` with `url`, or `terminal`). [ARTICLE_COPY.md](ARTICLE_COPY.md) now writes "Introducing a product" as beats; the admission rules are unchanged. No existing export changes. Version 0.27.0 adds explicit Rust, TOML, YAML, Lean, and TLA+ code highlighting, including nested comments and multiline strings. The existing highlighter API and stylesheet remain the shared entry points; unsupported languages still render as escaped text. Version 0.26.0 adds `MarketingNotice` and the raw `.hraness-marketing-notice` class: one status or alert line (`info`, `success`, or `error`) that sits on the content edge of the page column instead of spanning the window. Errors are announced as alerts and other tones as status. Signed-in account pages that render inside `MarketingSiteHeader` should compose `MarketingMain`, `MarketingNotice`, `MarketingStatStrip`, and `MarketingSection` so every block shares the header's measure and gutter, rather than hand-rolled full-bleed banners and nested cards. Version 0.25.0 moves bordered foil surfaces off the spectrum: `.hraness-foil` and `[data-emphasis="primary"]` actions keep their flat surface fill under one theme-aware monochrome edge — black on light, white on dark, overridable through the new `--hraness-foil-edge` token — while the metallic spectrum stays on wordmarks and marks. The foil material contract advances to version 3: `surfaceImage` and `surfaceBackgroundClip` are replaced by `surfaceFill`, `edge`, `edgeDark`, and `edgeColor`. Reinstall any vendored marketing snapshot from the 0.25.0 commit. Version 0.24.0 joins a marketing footer directly followed by the shared `@hraness/site-footer` network footer into one band: the product row's bottom space collapses to a compact gap and the network row's content follows the marketing measure and gutter through `--hraness-site-footer-measure`, so product links and the organization row share one column instead of reading as two stacked bars. Mount the network footer directly after `MarketingSiteFooter`; no prop or markup change is needed inside either landmark. Version 0.23.0 moves marketing pages to the Quiet direction described in [DESIGN.md](DESIGN.md). `ProductHero` no longer renders a backdrop, `HeroBackdrop` renders nothing, and `attachHeroLight` is an inert disposer; their names and props stay so existing code compiles and are marked deprecated. The `cells`, `weave`, `contour`, and `mesh` patterns render as `none`, and marketing fields and Lantern walls paint the flat palette background. Both marketing presets use Nebula Sans for display headings (editorial at weight 550); Instrument Serif stays vendored for explicit opt-in only. Hero eyebrows are plain labels, the accent band loses its grid, and cards and header chrome use hairline edges instead of lifted shadows. On phones `MarketingSiteHeader` keeps the brand, primary action, and appearance menu on one row and moves the links to a second row that scrolls sideways, with 44px targets. To migrate, delete `backdrop` artwork, `HeroBackdrop`, `attachHeroLight`, pattern values, and product CSS that recreated textures or serif headings, then reinstall any vendored marketing snapshot from the 0.23.0 commit. Version 0.22.2 restores the canonical roughday mark — the rain-cloud artwork pinned by the portfolio registry — after the mark slot briefly carried a stray illustration. Version 0.22.1 completes the icon library with the roughday inline chip family (65 admitted assets, no pending members). Version 0.22.0 adds the `./icons` surface: 62 vetted single-ink assets across ten sets — a shared illustration family, product illustration families, and the product marks, each admitted through a measured gate (single ink, bounded aspect, coverage, stroke, paths, bytes) and per-set family coherence, distributed as a typed registry module (`hranessIcons`, `hranessIcon`, `hranessIconMarkup`, `hranessIconsForSet`) and as canonical `./icons/<set>/<slug>.svg` files for image consumers. See [ICONS.md](ICONS.md). Version 0.21.1 accepts status-page `routes` straight from a sitemap: long titles are shortened for the "Did you mean" line and unusable entries are dropped instead of failing the render. Version 0.21.0 replaces the 404 and route-error pages with one shared status page: the product's main action, a "Did you mean" link to the closest known page, at most three next links with one-line descriptions, an optional line for AI agents, and a glyph drawn as dots that gather, move away from the pointer, and settle. `RouteNotFoundPage`, `RouteErrorPage`, and `GlobalErrorDocument` render it; `renderStatusPageHtml` and `attachStatusPage` bring the same page to static sites; `status-page.css` ships in `styles.css` and `compiler-foundation.css`. The default copy changes to "We can’t find that page". See [STATUS_PAGES.md](STATUS_PAGES.md). Version 0.20.0 gives `ThemeMenuButton` the Lantern material: under `data-hraness-material="lantern"` its trigger is raised at rest and inset while pressed, and its menu uses the material plane, lift and warm selection, with no new props. Sites can delete their local Lantern CSS for the appearance menu. It also adds `formatRelativeTime` at the package root and a hydration-safe `RelativeTime` component in `@hraness/design-kit/react`. Version 0.19.0 redraws related-product cards as the hraness.com project cards: each shows the product's mark, its name, and its one-line `role` at reading size, and no longer renders the `relationship` sentence (the prop stays accepted and is deprecated). `MarketingRelatedProduct` and the static `ArticleRelatedLink` take a `mark`, and every `@hraness/design-kit/portfolio` product and `relatedFor()` item now carries its portfolio mark as an inert `data:image/svg+xml` URL. Related-tier and proof headings move to the new `--hraness-marketing-h3-size` token, so the editorial display face never renders below 1.75rem. `typography.css` gains per-level heading tokens (`--hraness-type-h1-font` through `--hraness-type-h4-font`, the matching `-weight` tokens, `--hraness-type-subheading-font`, and `--hraness-type-display-min`). h3 and h4 in `.hraness-prose` and publication articles now use the text face, and the h2 floor rises to 1.75rem. Version 0.18.3 adds the Sponge and Wordcell runtime relations to Oh to the `@hraness/design-kit/portfolio` snapshot, so related-product cards on all three sites can link them. Version 0.18.2 refreshes the `@hraness/design-kit/portfolio` snapshot from the registry: the public ghostget.com entry, updated Gobstopper and xcb naming and descriptions, and the current sibling-product relations for related-product cards. Version 0.18.1 adds the Perplexity mark and a dependency-free `@hraness/design-kit/provider-marks` leaf entry (`providerMark`, `providerMarks`, `providerMarkFallback`, `providerMarkGlyphDataUri`, `providerMarkArtDataUri`, `providerMarkOnAccent`, `providerMarkMonogram`) so packages such as `@hraness/ui` can consume the registry without pulling the marketing surface. Version 0.18.0 adds the shared provider-mark registry: `providerMarks`, `providerMark()` alias resolution, `ProviderMark`/`ProviderMarkChip` accent-tinted tile components on both React entry points, vendored agent and vendor artwork from LobeHub icons 1.95.1 plus documented Crush and Aider marks, monogram fallbacks for uncovered names, and data-URI helpers for CSS-mask consumers. See `vendor/provider-marks/UPSTREAM.md` for asset provenance. Version 0.17.2 carries the canonical portfolio messaging record per product (`names`, `category`, `tagline`, `short`, `meta`, `medium`, `long`, and hero copy) in the `/portfolio` snapshot. Version 0.17.1 lets Next.js apps that compile dependencies with Babel build the article layer: its link check no longer uses a Unicode property escape that Babel cannot rewrite, and it rejects the same control characters and whitespace as before. Version 0.17.0 adds the article layer: server-safe `MarketingArticle`, byline, provenance, sources, callout, related-product, and index components, a matching static HTML renderer for sites without React, long-form article styles in `plain-publication.css`, and the `ArticleAdmission` rubric with `assertArticleAdmissions()`. It also adds `@hraness/design-kit/portfolio`, a snapshot of public product names, one-liners, links, and relations for related-product cards and "How X uses Y" posts. See [ARTICLE_COPY.md](ARTICLE_COPY.md). Version 0.16.4 keeps native appearance-menu labels usable inside keyboard-focusable page landmarks, including mouse and touch selection. Version 0.16.3 keeps decorative hero backgrounds hidden in forced colors and reduced transparency when other packages load their styles afterward. Version 0.16.2 preserves palette hues in translucent headers, material surfaces, and decorative highlights. Version 0.16.1 keeps plain reading pages and nested compiled surfaces in their selected palette, including system appearance without JavaScript. Version 0.16.0 adds a shared bounded hero light, product-owned backdrop slots, five Lantern patterns, palette-derived soft surfaces, and responsive typography across marketing and reading layouts. Static sites can use the palette bridge for system appearance before JavaScript. See [HERO_FIELDS.md](HERO_FIELDS.md), [LANTERN_MATERIAL.md](LANTERN_MATERIAL.md), and [MARKETING_PRESET.md](MARKETING_PRESET.md). Version 0.15.0 lets `MarketingRelated` present labeled tiers of sibling products: a `groups` collection renders each tier under its own heading with an accessible card-row label, while the flat `items` shape stays available for a single group. Version 0.14.0 adds `MarketingRelated`, a collection section that presents sibling products as linked cards, each framed by its relationship to the featured product. Version 0.13.0 publishes `--hraness-sticky-offset` from sticky marketing chrome, gives `MarketingMain` and the next sticky sibling a clearance contract, stretches marketing card rows to the tallest item with a reserved two-line meta block, and clips per-card art wells so a logo surface cannot paint through the gutter. Version 0.12.0 replaces pointer-driven gradient rotation with a steady material and a moving light: the spectrum and its 115deg direction stay fixed while `--hraness-foil-x`/`--hraness-foil-y` highlights travel across each lockup, and marketing footers can opt into the same icon-plus-wordmark foil as the site header with `brandMark`. Version 0.11.1 preserves visible metallic marks when another package repeats a generic hidden atom in a later CSS layer. React consumers load `components.css` or `styles.css`; the raw marketing entry supports authored HTML hooks. Version 0.11 adds server-rendered `FoilMark` artwork and metallic text with subtle rainbow reflections, including a shared header mark seam and original-artwork fallbacks. Version 0.10.1 adds conservative server syntax defaults, includes their styles in the narrow marketing entry, and pins the icon dependency to preserve fresh Linux installs. Version 0.10 adds the shared foil contract: `.hraness-foil` surfaces and `.hraness-foil-text` wordmarks render a pointer-following metallic spectrum from the `--hraness-foil-*` custom properties, applied by default to marketing header brands and primary actions. The `attachFoil` browser export drives the bounded `x`/`y`/`angle` inputs with damped easing, reduced-motion and forced-color fallbacks, and no style injection; the same spectrum feeds `@hraness/site-footer` signup controls. Dark appearances use a deeper palette so the sheen stays visible. Version 0.8 removes Jelly's optional API, stylesheet, vendor runtime and theme-provider side effect. Migrate direct Jelly surfaces to native shared primitives before upgrading. Lantern now uses softer directional depth and shaded faces; the marketing preset adds individually shaded static cells, theme-aware terminal colors and window chrome. Code blocks retain source lines and follow the active palette. Paper preferences, semantic palettes, and compiler identity stay stable. Compiler adopters must regenerate their finalized stylesheet with the new package manifest.
756
+ The stable dependency pair for this release is `@hraness/ui` `v0.5.17` with `@hraness/design-kit` `v0.35.1`. Version 0.31.0 keeps the `limits` beat and beats marked `social: false` out of the social kit and adds `socialPost` for social wording that stands without a caveat. Version 0.30.3 refreshes the portfolio snapshot so related-product cards use each product's own spelling, such as GhostGet and TextButler. Version 0.30.2 keeps the narrow and stacked install-tab layout when another package compiles the same atoms into a later cascade layer. Version 0.30.1 keeps every PlatformInstall tab name whole in columns down to 200px by stacking each mark above its name, using a container query on the component. Version 0.30.0 adds `site-shell.css`, which keeps short-page footers at the viewport bottom. Version 0.29.3 preserves readable selected install tabs in forced colors. Version 0.29.2 keeps all three PlatformInstall tabs visible at 320 to 360px and draws each platform mark once per component. Version 0.29.1 keeps marketing action labels readable in forced colors. Version 0.29.0 adds `PlatformInstall`, one install block for every CLI site: a tab per operating system with its mark, the install command with a Copy button that announces the result, optional alternative commands such as npm or Homebrew, and a note for platforms without a native build. After hydration it selects the visitor's operating system; without JavaScript every command shows. It also adds `PlatformIcon` (Apple, Tux, and Windows marks in `currentColor`) and a `PlatformBadges` "Runs on" row, plus `platformLabel`, `platformMark`, `detectPlatform`, and `matchDetectedPlatform` at the package root. See [Install commands for each platform](#install-commands-for-each-platform). No existing export changes. Version 0.28.0 adds the launch kit. `@hraness/design-kit/mockups` draws labelled illustrations of chat, feeds, inboxes, articles, terminals, browsers, desktop windows, menu bars, and phones in server-safe plain React with no StyleX or React Aria, styled by `@hraness/design-kit/mockups.css`; each renders as one image with a text description and no headings. `@hraness/design-kit/mockups/client` adds `ModeShowcase`, `FitToWidth`, and `StepThrough`. `@hraness/design-kit/launch`, with no React, holds the `LaunchBeat`, `LaunchFacts`, and `SocialKit` shapes with `resolveLaunchBeats`, `buildSocialKit`, and `assertLaunchKit`. `@hraness/design-kit/testing` gives product repositories `blogConformance`, `renderMatrix`, `assertNoHeadings`, `assertRoleImgWithLabel`, and `assertFakeHandles`. The React entries add `ArticleFigure`, `ArticleVideo` with `articleVideoJsonLd`, `ArticleTable`, `ArticleBarChart`, `ComparisonTable`, `LaunchBeats`, and `SocialKitPanel`, and `MarketingProofFrame` takes `chrome` (`window`, `browser` with `url`, or `terminal`). [ARTICLE_COPY.md](ARTICLE_COPY.md) now writes "Introducing a product" as beats; the admission rules are unchanged. No existing export changes. Version 0.27.0 adds explicit Rust, TOML, YAML, Lean, and TLA+ code highlighting, including nested comments and multiline strings. The existing highlighter API and stylesheet remain the shared entry points; unsupported languages still render as escaped text. Version 0.26.0 adds `MarketingNotice` and the raw `.hraness-marketing-notice` class: one status or alert line (`info`, `success`, or `error`) that sits on the content edge of the page column instead of spanning the window. Errors are announced as alerts and other tones as status. Signed-in account pages that render inside `MarketingSiteHeader` should compose `MarketingMain`, `MarketingNotice`, `MarketingStatStrip`, and `MarketingSection` so every block shares the header's measure and gutter, rather than hand-rolled full-bleed banners and nested cards. Version 0.25.0 moves bordered foil surfaces off the spectrum: `.hraness-foil` and `[data-emphasis="primary"]` actions keep their flat surface fill under one theme-aware monochrome edge — black on light, white on dark, overridable through the new `--hraness-foil-edge` token — while the metallic spectrum stays on wordmarks and marks. The foil material contract advances to version 3: `surfaceImage` and `surfaceBackgroundClip` are replaced by `surfaceFill`, `edge`, `edgeDark`, and `edgeColor`. Reinstall any vendored marketing snapshot from the 0.25.0 commit. Version 0.24.0 joins a marketing footer directly followed by the shared `@hraness/site-footer` network footer into one band: the product row's bottom space collapses to a compact gap and the network row's content follows the marketing measure and gutter through `--hraness-site-footer-measure`, so product links and the organization row share one column instead of reading as two stacked bars. Mount the network footer directly after `MarketingSiteFooter`; no prop or markup change is needed inside either landmark. Version 0.23.0 moves marketing pages to the Quiet direction described in [DESIGN.md](DESIGN.md). `ProductHero` no longer renders a backdrop, `HeroBackdrop` renders nothing, and `attachHeroLight` is an inert disposer; their names and props stay so existing code compiles and are marked deprecated. The `cells`, `weave`, `contour`, and `mesh` patterns render as `none`, and marketing fields and Lantern walls paint the flat palette background. Both marketing presets use Nebula Sans for display headings (editorial at weight 550); Instrument Serif stays vendored for explicit opt-in only. Hero eyebrows are plain labels, the accent band loses its grid, and cards and header chrome use hairline edges instead of lifted shadows. On phones `MarketingSiteHeader` keeps the brand, primary action, and appearance menu on one row and moves the links to a second row that scrolls sideways, with 44px targets. To migrate, delete `backdrop` artwork, `HeroBackdrop`, `attachHeroLight`, pattern values, and product CSS that recreated textures or serif headings, then reinstall any vendored marketing snapshot from the 0.23.0 commit. Version 0.22.2 restores the canonical roughday mark — the rain-cloud artwork pinned by the portfolio registry — after the mark slot briefly carried a stray illustration. Version 0.22.1 completes the icon library with the roughday inline chip family (65 admitted assets, no pending members). Version 0.22.0 adds the `./icons` surface: 62 vetted single-ink assets across ten sets — a shared illustration family, product illustration families, and the product marks, each admitted through a measured gate (single ink, bounded aspect, coverage, stroke, paths, bytes) and per-set family coherence, distributed as a typed registry module (`hranessIcons`, `hranessIcon`, `hranessIconMarkup`, `hranessIconsForSet`) and as canonical `./icons/<set>/<slug>.svg` files for image consumers. See [ICONS.md](ICONS.md). Version 0.21.1 accepts status-page `routes` straight from a sitemap: long titles are shortened for the "Did you mean" line and unusable entries are dropped instead of failing the render. Version 0.21.0 replaces the 404 and route-error pages with one shared status page: the product's main action, a "Did you mean" link to the closest known page, at most three next links with one-line descriptions, an optional line for AI agents, and a glyph drawn as dots that gather, move away from the pointer, and settle. `RouteNotFoundPage`, `RouteErrorPage`, and `GlobalErrorDocument` render it; `renderStatusPageHtml` and `attachStatusPage` bring the same page to static sites; `status-page.css` ships in `styles.css` and `compiler-foundation.css`. The default copy changes to "We can’t find that page". See [STATUS_PAGES.md](STATUS_PAGES.md). Version 0.20.0 gives `ThemeMenuButton` the Lantern material: under `data-hraness-material="lantern"` its trigger is raised at rest and inset while pressed, and its menu uses the material plane, lift and warm selection, with no new props. Sites can delete their local Lantern CSS for the appearance menu. It also adds `formatRelativeTime` at the package root and a hydration-safe `RelativeTime` component in `@hraness/design-kit/react`. Version 0.19.0 redraws related-product cards as the hraness.com project cards: each shows the product's mark, its name, and its one-line `role` at reading size, and no longer renders the `relationship` sentence (the prop stays accepted and is deprecated). `MarketingRelatedProduct` and the static `ArticleRelatedLink` take a `mark`, and every `@hraness/design-kit/portfolio` product and `relatedFor()` item now carries its portfolio mark as an inert `data:image/svg+xml` URL. Related-tier and proof headings move to the new `--hraness-marketing-h3-size` token, so the editorial display face never renders below 1.75rem. `typography.css` gains per-level heading tokens (`--hraness-type-h1-font` through `--hraness-type-h4-font`, the matching `-weight` tokens, `--hraness-type-subheading-font`, and `--hraness-type-display-min`). h3 and h4 in `.hraness-prose` and publication articles now use the text face, and the h2 floor rises to 1.75rem. Version 0.18.3 adds the Sponge and Wordcell runtime relations to Oh to the `@hraness/design-kit/portfolio` snapshot, so related-product cards on all three sites can link them. Version 0.18.2 refreshes the `@hraness/design-kit/portfolio` snapshot from the registry: the public ghostget.com entry, updated Gobstopper and xcb naming and descriptions, and the current sibling-product relations for related-product cards. Version 0.18.1 adds the Perplexity mark and a dependency-free `@hraness/design-kit/provider-marks` leaf entry (`providerMark`, `providerMarks`, `providerMarkFallback`, `providerMarkGlyphDataUri`, `providerMarkArtDataUri`, `providerMarkOnAccent`, `providerMarkMonogram`) so packages such as `@hraness/ui` can consume the registry without pulling the marketing surface. Version 0.18.0 adds the shared provider-mark registry: `providerMarks`, `providerMark()` alias resolution, `ProviderMark`/`ProviderMarkChip` accent-tinted tile components on both React entry points, vendored agent and vendor artwork from LobeHub icons 1.95.1 plus documented Crush and Aider marks, monogram fallbacks for uncovered names, and data-URI helpers for CSS-mask consumers. See `vendor/provider-marks/UPSTREAM.md` for asset provenance. Version 0.17.2 carries the canonical portfolio messaging record per product (`names`, `category`, `tagline`, `short`, `meta`, `medium`, `long`, and hero copy) in the `/portfolio` snapshot. Version 0.17.1 lets Next.js apps that compile dependencies with Babel build the article layer: its link check no longer uses a Unicode property escape that Babel cannot rewrite, and it rejects the same control characters and whitespace as before. Version 0.17.0 adds the article layer: server-safe `MarketingArticle`, byline, provenance, sources, callout, related-product, and index components, a matching static HTML renderer for sites without React, long-form article styles in `plain-publication.css`, and the `ArticleAdmission` rubric with `assertArticleAdmissions()`. It also adds `@hraness/design-kit/portfolio`, a snapshot of public product names, one-liners, links, and relations for related-product cards and "How X uses Y" posts. See [ARTICLE_COPY.md](ARTICLE_COPY.md). Version 0.16.4 keeps native appearance-menu labels usable inside keyboard-focusable page landmarks, including mouse and touch selection. Version 0.16.3 keeps decorative hero backgrounds hidden in forced colors and reduced transparency when other packages load their styles afterward. Version 0.16.2 preserves palette hues in translucent headers, material surfaces, and decorative highlights. Version 0.16.1 keeps plain reading pages and nested compiled surfaces in their selected palette, including system appearance without JavaScript. Version 0.16.0 adds a shared bounded hero light, product-owned backdrop slots, five Lantern patterns, palette-derived soft surfaces, and responsive typography across marketing and reading layouts. Static sites can use the palette bridge for system appearance before JavaScript. See [HERO_FIELDS.md](HERO_FIELDS.md), [LANTERN_MATERIAL.md](LANTERN_MATERIAL.md), and [MARKETING_PRESET.md](MARKETING_PRESET.md). Version 0.15.0 lets `MarketingRelated` present labeled tiers of sibling products: a `groups` collection renders each tier under its own heading with an accessible card-row label, while the flat `items` shape stays available for a single group. Version 0.14.0 adds `MarketingRelated`, a collection section that presents sibling products as linked cards, each framed by its relationship to the featured product. Version 0.13.0 publishes `--hraness-sticky-offset` from sticky marketing chrome, gives `MarketingMain` and the next sticky sibling a clearance contract, stretches marketing card rows to the tallest item with a reserved two-line meta block, and clips per-card art wells so a logo surface cannot paint through the gutter. Version 0.12.0 replaces pointer-driven gradient rotation with a steady material and a moving light: the spectrum and its 115deg direction stay fixed while `--hraness-foil-x`/`--hraness-foil-y` highlights travel across each lockup, and marketing footers can opt into the same icon-plus-wordmark foil as the site header with `brandMark`. Version 0.11.1 preserves visible metallic marks when another package repeats a generic hidden atom in a later CSS layer. React consumers load `components.css` or `styles.css`; the raw marketing entry supports authored HTML hooks. Version 0.11 adds server-rendered `FoilMark` artwork and metallic text with subtle rainbow reflections, including a shared header mark seam and original-artwork fallbacks. Version 0.10.1 adds conservative server syntax defaults, includes their styles in the narrow marketing entry, and pins the icon dependency to preserve fresh Linux installs. Version 0.10 adds the shared foil contract: `.hraness-foil` surfaces and `.hraness-foil-text` wordmarks render a pointer-following metallic spectrum from the `--hraness-foil-*` custom properties, applied by default to marketing header brands and primary actions. The `attachFoil` browser export drives the bounded `x`/`y`/`angle` inputs with damped easing, reduced-motion and forced-color fallbacks, and no style injection; the same spectrum feeds `@hraness/site-footer` signup controls. Dark appearances use a deeper palette so the sheen stays visible. Version 0.8 removes Jelly's optional API, stylesheet, vendor runtime and theme-provider side effect. Migrate direct Jelly surfaces to native shared primitives before upgrading. Lantern now uses softer directional depth and shaded faces; the marketing preset adds individually shaded static cells, theme-aware terminal colors and window chrome. Code blocks retain source lines and follow the active palette. Paper preferences, semantic palettes, and compiler identity stay stable. Compiler adopters must regenerate their finalized stylesheet with the new package manifest.
753
757
 
754
758
  The complete check runs linting, typechecking, production builds, an installed-package smoke test, deterministic examples, property tests, server rendering, vendor-integrity checks, and headless Chromium regressions. The browser gate verifies responsive shell ownership, extracted AnimatedRailStage, Fader, layout-surface, and playback-transport delivery, reduced-motion stage fallback, Fader keyboard and focus behavior, forced-color behavior, keyboard-operable appearance, browser-chrome synchronization across opposing device and saved preferences, global-error static metadata and runtime lifecycle, accessible title and copy, deterministic procedural layers, viewport containment, and the absence of the excluded canvas effect. Provision the pinned Chromium with `bun run browser:install`. An explicit `CHROMIUM_EXECUTABLE_PATH` must resolve to a provisioned Chrome for Testing; the browser gate rejects installed auto-updating Chrome.
755
759
 
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SyntaxCode,
3
3
  platformInstallClassName
4
- } from "./chunk-fjf81bww.js";
4
+ } from "./chunk-6ts4955n.js";
5
5
  import {
6
6
  diagramMetrics
7
7
  } from "./chunk-gmea6p0d.js";
@@ -214,38 +214,6 @@ var platformInstallStyles = {
214
214
  kmVPX3: "x1717udv",
215
215
  $$css: true
216
216
  },
217
- copy: {
218
- kGNEyG: "x6s0dn4",
219
- kysU6D: "xjyslct",
220
- kWkggS: "xf7cb96 x3oli7v xnwy5bs",
221
- kVAM5u: "x1ls9zlr x1ylmb6m",
222
- kaIpWk: "x116uinm",
223
- ksu8eU: "x1y0btm7",
224
- kMzoRj: "xmkeg23",
225
- kB7OPa: "x9f619",
226
- kMwMTN: "x1p5laik x1ggml12",
227
- kkrTdU: "x1ypdohk",
228
- k1xSpc: "x3nfvp2 x1cfwndu",
229
- kmuXW: "x2lah0s",
230
- kMv6JI: "x1vnz01h",
231
- kGuDYH: "x1dcheo9",
232
- k63SB2: "xk50ysn",
233
- kOIVth: "x73f2yu",
234
- kLWn49: "xo5v014",
235
- kogj98: "x1ghz6dp",
236
- kAzted: "x1in32aq x1rewkhn",
237
- kI3sdo: "x1a2a7pz x11dsm9b",
238
- kInvED: "x1y3gkto",
239
- k8WAf4: "x1267ecw",
240
- kg3NbH: "x1f6otoe",
241
- $$css: true
242
- },
243
- copyIcon: {
244
- kZKoxP: "x1at03k5",
245
- kmuXW: "x2lah0s",
246
- kzqmXN: "x2tfi8i",
247
- $$css: true
248
- },
249
217
  alternatives: {
250
218
  k1xSpc: "xrvj5dj",
251
219
  kOIVth: "x1uma3xh",
@@ -262,6 +230,14 @@ var platformInstallStyles = {
262
230
  kogj98: "x1ghz6dp",
263
231
  $$css: true
264
232
  },
233
+ commandNote: {
234
+ kLZC3w: "x1h3am7x x19dwuzr",
235
+ kPef9Z: "x13fuv20",
236
+ kEafiO: "x178xt8z",
237
+ k8WAf4: "x8fiyw4",
238
+ kg3NbH: "x1fi0nvg",
239
+ $$css: true
240
+ },
265
241
  unavailable: {
266
242
  kVAM5u: "x1ls9zlr x1w1tqly",
267
243
  kaIpWk: "x1yt6v20",
@@ -367,8 +343,6 @@ var hooks = {
367
343
  code: "hraness-platform-install__code",
368
344
  command: "hraness-platform-install__command",
369
345
  commandBar: "hraness-platform-install__command-bar",
370
- copy: "hraness-platform-install__copy",
371
- copyIcon: "hraness-platform-install__copy-icon",
372
346
  icon: "hraness-platform-icon",
373
347
  markSymbols: "hraness-platform-install__marks",
374
348
  note: "hraness-platform-install__note",
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  SyntaxCode,
3
3
  platformInstallClassName
4
- } from "./chunk-fjf81bww.js";
4
+ } from "./chunk-6ts4955n.js";
5
5
  import {
6
6
  detectPlatform,
7
7
  isKnownPlatformId,
@@ -13,7 +13,102 @@ import {
13
13
 
14
14
  // src/react/platform-install.tsx
15
15
  import { useCallback, useEffect, useId, useRef, useState } from "react";
16
+
17
+ // src/react/setup-copy-button.stylex.ts
18
+ import * as stylex from "@stylexjs/stylex";
19
+ var setupCopyButtonStyles = {
20
+ button: {
21
+ kGNEyG: "x6s0dn4",
22
+ kysU6D: "xjyslct",
23
+ kWkggS: "x17tv4j5 x1lf5oka xnwy5bs",
24
+ kVAM5u: "x3ugid2 x1ylmb6m",
25
+ kaIpWk: "x116uinm",
26
+ ksu8eU: "x1y0btm7",
27
+ kMzoRj: "xmkeg23",
28
+ kB7OPa: "x9f619",
29
+ kMwMTN: "xm06a53 x1ggml12",
30
+ kkrTdU: "x1ypdohk",
31
+ k1xSpc: "x3nfvp2 x1cfwndu",
32
+ kmuXW: "x2lah0s",
33
+ kMv6JI: "xtls1wf",
34
+ kGuDYH: "x1dcheo9",
35
+ k63SB2: "xk50ysn",
36
+ kOIVth: "x1neeqzj",
37
+ kjj79g: "xl56j7k",
38
+ kLWn49: "xo5v014",
39
+ kogj98: "x1ghz6dp",
40
+ kAzted: "xgbkey0",
41
+ kI3sdo: "x1a2a7pz xr5lfjo",
42
+ kInvED: "x1hl8ikr",
43
+ kmVPX3: "x1i4hug3",
44
+ $$css: true
45
+ },
46
+ icon: {
47
+ kZKoxP: "x1l36t39",
48
+ kmuXW: "x2lah0s",
49
+ kzqmXN: "xcdlrvm",
50
+ $$css: true
51
+ }
52
+ };
53
+ function setupCopyButtonClassName(part, caller) {
54
+ return [`hraness-setup-copy__${part}`, stylex.props(setupCopyButtonStyles[part]).className, caller].filter(Boolean).join(" ");
55
+ }
56
+
57
+ // src/react/setup-copy-button.tsx
16
58
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
59
+ function SetupCopyButton({
60
+ className,
61
+ iconClassName,
62
+ onCopy,
63
+ state,
64
+ subject,
65
+ failedLabel = "Copy failed"
66
+ }) {
67
+ return /* @__PURE__ */ jsxs("button", {
68
+ "aria-busy": state === "copying" || undefined,
69
+ "aria-label": `${state === "copied" ? "Copied" : "Copy"} ${subject}`,
70
+ className: setupCopyButtonClassName("button", className),
71
+ "data-copy-state": state,
72
+ disabled: state === "copying",
73
+ onClick: onCopy,
74
+ type: "button",
75
+ children: [
76
+ /* @__PURE__ */ jsx("svg", {
77
+ "aria-hidden": "true",
78
+ className: setupCopyButtonClassName("icon", iconClassName),
79
+ fill: "none",
80
+ focusable: "false",
81
+ stroke: "currentColor",
82
+ strokeLinecap: "round",
83
+ strokeLinejoin: "round",
84
+ strokeWidth: 2,
85
+ viewBox: "0 0 24 24",
86
+ children: state === "copied" ? /* @__PURE__ */ jsx("path", {
87
+ d: "M5 12.5l4.5 4.5L19 7.5"
88
+ }) : /* @__PURE__ */ jsxs(Fragment, {
89
+ children: [
90
+ /* @__PURE__ */ jsx("rect", {
91
+ height: "12",
92
+ rx: "2",
93
+ width: "12",
94
+ x: "8",
95
+ y: "8"
96
+ }),
97
+ /* @__PURE__ */ jsx("path", {
98
+ d: "M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2"
99
+ })
100
+ ]
101
+ })
102
+ }),
103
+ /* @__PURE__ */ jsx("span", {
104
+ children: state === "copied" ? "Copied" : state === "copying" ? "Copying" : state === "failed" ? failedLabel : "Copy"
105
+ })
106
+ ]
107
+ });
108
+ }
109
+
110
+ // src/react/platform-install.tsx
111
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
17
112
  var copyResetMilliseconds = 2000;
18
113
  function assertTargets(platforms, defaultPlatform) {
19
114
  if (platforms.length === 0)
@@ -82,17 +177,17 @@ function PlatformMarkSymbols({
82
177
  ids,
83
178
  symbolId
84
179
  }) {
85
- return /* @__PURE__ */ jsx("svg", {
180
+ return /* @__PURE__ */ jsx2("svg", {
86
181
  "aria-hidden": "true",
87
182
  className: platformInstallClassName(["markSymbols"]),
88
183
  focusable: "false",
89
184
  xmlns: "http://www.w3.org/2000/svg",
90
185
  children: ids.map((id) => {
91
186
  const mark = platformMark(id);
92
- return /* @__PURE__ */ jsx("symbol", {
187
+ return /* @__PURE__ */ jsx2("symbol", {
93
188
  id: symbolId(id),
94
189
  viewBox: mark.viewBox,
95
- children: /* @__PURE__ */ jsx("path", {
190
+ children: /* @__PURE__ */ jsx2("path", {
96
191
  d: mark.path
97
192
  })
98
193
  }, id);
@@ -103,7 +198,7 @@ function PlatformMarkUse({
103
198
  platform,
104
199
  symbolId
105
200
  }) {
106
- return /* @__PURE__ */ jsx("svg", {
201
+ return /* @__PURE__ */ jsx2("svg", {
107
202
  "aria-hidden": "true",
108
203
  className: platformInstallClassName(["icon"]),
109
204
  "data-platform": platform,
@@ -111,97 +206,58 @@ function PlatformMarkUse({
111
206
  focusable: "false",
112
207
  viewBox: platformMark(platform).viewBox,
113
208
  xmlns: "http://www.w3.org/2000/svg",
114
- children: /* @__PURE__ */ jsx("use", {
209
+ children: /* @__PURE__ */ jsx2("use", {
115
210
  href: `#${symbolId}`
116
211
  })
117
212
  });
118
213
  }
119
- function CopyGlyph({
120
- copied
121
- }) {
122
- return /* @__PURE__ */ jsx("svg", {
123
- "aria-hidden": "true",
124
- className: platformInstallClassName(["copyIcon"]),
125
- fill: "none",
126
- focusable: "false",
127
- stroke: "currentColor",
128
- strokeLinecap: "round",
129
- strokeLinejoin: "round",
130
- strokeWidth: 2,
131
- viewBox: "0 0 24 24",
132
- children: copied ? /* @__PURE__ */ jsx("path", {
133
- d: "M5 12.5l4.5 4.5L19 7.5"
134
- }) : /* @__PURE__ */ jsxs(Fragment, {
135
- children: [
136
- /* @__PURE__ */ jsx("rect", {
137
- height: "12",
138
- rx: "2",
139
- width: "12",
140
- x: "8",
141
- y: "8"
142
- }),
143
- /* @__PURE__ */ jsx("path", {
144
- d: "M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2"
145
- })
146
- ]
147
- })
148
- });
149
- }
150
214
  function CommandBlock({
151
215
  caption,
152
216
  command,
153
217
  copyKey,
154
218
  onCopy,
219
+ note,
155
220
  status,
156
221
  subject
157
222
  }) {
158
223
  const preRef = useRef(null);
159
224
  const state = status?.key === copyKey ? status.ok ? "copied" : "failed" : "idle";
160
- return /* @__PURE__ */ jsxs("div", {
225
+ return /* @__PURE__ */ jsxs2("div", {
161
226
  className: platformInstallClassName(["command"]),
162
227
  "data-copy-state": state,
163
228
  children: [
164
- /* @__PURE__ */ jsxs("div", {
229
+ /* @__PURE__ */ jsxs2("div", {
165
230
  className: platformInstallClassName(["commandBar", (caption === undefined || caption === "") && "commandBarEmpty"]),
166
231
  children: [
167
- /* @__PURE__ */ jsx("span", {
232
+ /* @__PURE__ */ jsx2("span", {
168
233
  className: platformInstallClassName(["shell"]),
169
234
  children: caption
170
235
  }),
171
- /* @__PURE__ */ jsxs("button", {
172
- className: platformInstallClassName(["copy"]),
173
- "data-copy-state": state,
174
- onClick: () => onCopy(copyKey, command, subject, preRef.current),
175
- type: "button",
176
- children: [
177
- /* @__PURE__ */ jsx(CopyGlyph, {
178
- copied: state === "copied"
179
- }),
180
- /* @__PURE__ */ jsx("span", {
181
- children: state === "copied" ? "Copied" : state === "failed" ? "Select to copy" : "Copy"
182
- }),
183
- /* @__PURE__ */ jsxs("span", {
184
- className: platformInstallClassName(["status"]),
185
- children: [
186
- " ",
187
- subject
188
- ]
189
- })
190
- ]
236
+ /* @__PURE__ */ jsx2(SetupCopyButton, {
237
+ className: "hraness-platform-install__copy",
238
+ iconClassName: "hraness-platform-install__copy-icon",
239
+ failedLabel: "Select to copy",
240
+ onCopy: () => onCopy(copyKey, command, subject, preRef.current),
241
+ state,
242
+ subject
191
243
  })
192
244
  ]
193
245
  }),
194
- /* @__PURE__ */ jsx("pre", {
246
+ /* @__PURE__ */ jsx2("pre", {
195
247
  "aria-label": subject,
196
248
  className: platformInstallClassName(["pre"]),
197
249
  ref: preRef,
198
250
  tabIndex: 0,
199
- children: /* @__PURE__ */ jsx(SyntaxCode, {
251
+ children: /* @__PURE__ */ jsx2(SyntaxCode, {
200
252
  className: platformInstallClassName(["code"]),
201
253
  code: command,
202
254
  language: "shell",
203
255
  styles: "classes"
204
256
  })
257
+ }),
258
+ note === undefined ? null : /* @__PURE__ */ jsx2("div", {
259
+ className: platformInstallClassName(["note", "commandNote"]),
260
+ children: note
205
261
  })
206
262
  ]
207
263
  });
@@ -286,25 +342,25 @@ function PlatformInstall({
286
342
  event.preventDefault();
287
343
  choose(target, true);
288
344
  };
289
- return /* @__PURE__ */ jsxs("div", {
345
+ return /* @__PURE__ */ jsxs2("div", {
290
346
  className: platformInstallClassName(["root"], className),
291
347
  "data-hraness-platform-install": "",
292
348
  "data-selected-platform": current,
293
349
  "data-selection-source": source,
294
350
  id,
295
351
  children: [
296
- /* @__PURE__ */ jsx(PlatformMarkSymbols, {
352
+ /* @__PURE__ */ jsx2(PlatformMarkSymbols, {
297
353
  ids,
298
354
  symbolId
299
355
  }),
300
- /* @__PURE__ */ jsx("div", {
356
+ /* @__PURE__ */ jsx2("div", {
301
357
  "aria-label": label,
302
358
  className: platformInstallClassName(["tablist"]),
303
359
  onKeyDown,
304
360
  role: "tablist",
305
361
  children: platforms.map((target) => {
306
362
  const isSelected = target.id === current;
307
- return /* @__PURE__ */ jsxs("button", {
363
+ return /* @__PURE__ */ jsxs2("button", {
308
364
  "aria-controls": `${baseId}-panel-${target.id}`,
309
365
  "aria-selected": isSelected,
310
366
  className: platformInstallClassName(["tab", isSelected && "tabSelected"]),
@@ -322,11 +378,11 @@ function PlatformInstall({
322
378
  tabIndex: isSelected ? 0 : -1,
323
379
  type: "button",
324
380
  children: [
325
- /* @__PURE__ */ jsx(PlatformMarkUse, {
381
+ /* @__PURE__ */ jsx2(PlatformMarkUse, {
326
382
  platform: target.id,
327
383
  symbolId: symbolId(target.id)
328
384
  }),
329
- /* @__PURE__ */ jsx("span", {
385
+ /* @__PURE__ */ jsx2("span", {
330
386
  className: platformInstallClassName(["tabLabel"]),
331
387
  children: labelOf(target)
332
388
  })
@@ -337,7 +393,7 @@ function PlatformInstall({
337
393
  platforms.map((target) => {
338
394
  const name = labelOf(target);
339
395
  const alternatives = target.alternatives ?? [];
340
- return /* @__PURE__ */ jsx("div", {
396
+ return /* @__PURE__ */ jsx2("div", {
341
397
  "aria-labelledby": `${baseId}-tab-${target.id}`,
342
398
  className: platformInstallClassName(["panel"]),
343
399
  "data-availability": target.unavailable === true ? "unavailable" : "available",
@@ -345,38 +401,39 @@ function PlatformInstall({
345
401
  hidden: target.id !== current,
346
402
  id: `${baseId}-panel-${target.id}`,
347
403
  role: "tabpanel",
348
- children: /* @__PURE__ */ jsxs("div", {
404
+ children: /* @__PURE__ */ jsxs2("div", {
349
405
  className: platformInstallClassName(["panelBody"]),
350
406
  children: [
351
- /* @__PURE__ */ jsxs("p", {
407
+ /* @__PURE__ */ jsxs2("p", {
352
408
  className: platformInstallClassName(["panelLabel"]),
353
409
  children: [
354
- /* @__PURE__ */ jsx(PlatformMarkUse, {
410
+ /* @__PURE__ */ jsx2(PlatformMarkUse, {
355
411
  platform: target.id,
356
412
  symbolId: symbolId(target.id)
357
413
  }),
358
- /* @__PURE__ */ jsx("span", {
414
+ /* @__PURE__ */ jsx2("span", {
359
415
  children: name
360
416
  })
361
417
  ]
362
418
  }),
363
- target.unavailable === true ? /* @__PURE__ */ jsx("div", {
419
+ target.unavailable === true ? /* @__PURE__ */ jsx2("div", {
364
420
  className: platformInstallClassName(["unavailable"]),
365
421
  children: target.unavailableNote
366
422
  }) : null,
367
- target.command === undefined ? null : /* @__PURE__ */ jsx(CommandBlock, {
423
+ target.command === undefined ? null : /* @__PURE__ */ jsx2(CommandBlock, {
368
424
  caption: target.shell,
369
425
  command: target.command,
370
426
  copyKey: `${target.id}:primary`,
371
427
  onCopy: copy,
428
+ note: target.note,
372
429
  status,
373
430
  subject: `${name} install command`
374
431
  }),
375
- alternatives.length === 0 ? null : /* @__PURE__ */ jsx("ul", {
432
+ alternatives.length === 0 ? null : /* @__PURE__ */ jsx2("ul", {
376
433
  "aria-label": `Other ways to install on ${name}`,
377
434
  className: platformInstallClassName(["alternatives"]),
378
- children: alternatives.map((alternative, index) => /* @__PURE__ */ jsx("li", {
379
- children: /* @__PURE__ */ jsx(CommandBlock, {
435
+ children: alternatives.map((alternative, index) => /* @__PURE__ */ jsx2("li", {
436
+ children: /* @__PURE__ */ jsx2(CommandBlock, {
380
437
  caption: [alternative.label, alternative.shell].filter(Boolean).join(" · "),
381
438
  command: alternative.command,
382
439
  copyKey: `${target.id}:${index}`,
@@ -386,7 +443,7 @@ function PlatformInstall({
386
443
  })
387
444
  }, `${alternative.label}-${index}`))
388
445
  }),
389
- target.note === undefined ? null : /* @__PURE__ */ jsx("div", {
446
+ target.command !== undefined || target.note === undefined ? null : /* @__PURE__ */ jsx2("div", {
390
447
  className: platformInstallClassName(["note"]),
391
448
  children: target.note
392
449
  })
@@ -394,7 +451,7 @@ function PlatformInstall({
394
451
  })
395
452
  }, target.id);
396
453
  }),
397
- /* @__PURE__ */ jsx("p", {
454
+ /* @__PURE__ */ jsx2("p", {
398
455
  "aria-live": "polite",
399
456
  className: platformInstallClassName(["status"]),
400
457
  role: "status",
@@ -404,4 +461,4 @@ function PlatformInstall({
404
461
  });
405
462
  }
406
463
 
407
- export { PlatformInstall };
464
+ export { SetupCopyButton, PlatformInstall };