@hraness/design-kit 0.35.1 → 0.35.3

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/ARTICLE_COPY.md CHANGED
@@ -17,10 +17,16 @@ Limits are maximums. Count characters in the rendered text.
17
17
  | `provenance` | The drafting kind and the review on record. | | Omitting it on an AI-drafted post. |
18
18
  | `toc` | One entry per `h2`, only when the article has four or more. | Eight entries | Entries for `h3` headings. |
19
19
  | Body headings | Sentence case, each naming what the section shows. | 70 characters | Signpost headings such as "Overview", "Conclusion", or "Key takeaways". |
20
- | `ArticleSources` | Primary sources a reader can open, each with the date someone last checked the cited claim. | | Secondary summaries when the primary source is public. |
20
+ | `ArticleSources` | Primary sources a reader can open, retaining the date someone last checked the cited claim in each record. | | Secondary summaries when the primary source is public. |
21
21
  | `ArticleRelatedProducts` | Siblings from the registered relations for this article, each shown with its mark, name, and one-line description. | Three items | Every product in the portfolio. |
22
22
  | `ArticleCallout` | A limit or warning the reader must see before acting. | One short paragraph | Decorative asides and restated body text. |
23
23
 
24
+ ### Date presentation
25
+
26
+ For evergreen explanations, pass `showDates: false` to `MarketingArticle`, `ArticleIndex`, and `ArticleSources`, or their static equivalents `renderArticleHtml`, `renderArticleIndexHtml`, and `renderArticleSourcesHtml`. Each composition controls its own date presentation. Dates remain visible by default for release notes and other chronological writing.
27
+
28
+ This option hides publication, update, or source-check dates from the rendered text. It keeps authors, review credits, source links, and publishers visible, and removes rows that would otherwise be empty. The `published`, `updated`, and `checkedOn` fields retain their existing types and validation. Keep their true values in article records and use them for feeds and structured metadata; hiding a date never changes it.
29
+
24
30
  ## Post shapes
25
31
 
26
32
  ### Introducing a product
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.1",
14
+ "@hraness/design-kit": "github:hraness/design-kit#v0.35.3",
15
15
  "@hraness/ui": "github:hraness/ui#v0.5.17"
16
16
  }
17
17
  }
@@ -23,8 +23,14 @@ 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
+ ### Joined showcase tabs
27
+
28
+ Version 0.35.3 brings the same folder tabs to mode showcases. Surface tabs attach to one panel containing the controls and preview, while mode and option selections persist across surfaces. A grid reserves the tallest preview so switching surfaces keeps the panel height stable; inactive previews remain hidden and inert. Single-surface showcases keep a complete rounded panel.
29
+
26
30
  ### Compact agent setup and consistent copying
27
31
 
32
+ Version 0.35.2 lets evergreen articles, article indexes, and source lists hide visible dates with `showDates: false`. React and static renderers keep authors, review credits, and source publishers, remove empty date rows, and still require valid publication, update, and source-check metadata. Dates remain visible by default.
33
+
28
34
  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
35
 
30
36
  ### Clearer marketing controls and agent setup
@@ -753,7 +759,7 @@ bun run browser:install
753
759
  bun run check
754
760
  ```
755
761
 
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.
762
+ The stable dependency pair for this release is `@hraness/ui` `v0.5.17` with `@hraness/design-kit` `v0.35.3`. 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.
757
763
 
758
764
  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.
759
765
 
@@ -5318,6 +5318,7 @@ function MarketingArticle({
5318
5318
  id,
5319
5319
  provenance,
5320
5320
  published,
5321
+ showDates = true,
5321
5322
  toc,
5322
5323
  tocLabel = ARTICLE_TOC_LABEL,
5323
5324
  updated
@@ -5356,7 +5357,7 @@ function MarketingArticle({
5356
5357
  className: "plain-publication__article-dek",
5357
5358
  children: dek
5358
5359
  }),
5359
- /* @__PURE__ */ jsxs4("p", {
5360
+ author === undefined && !showDates ? null : /* @__PURE__ */ jsxs4("p", {
5360
5361
  className: "plain-publication__article-meta",
5361
5362
  children: [
5362
5363
  author === undefined ? null : /* @__PURE__ */ jsxs4(Fragment3, {
@@ -5364,14 +5365,14 @@ function MarketingArticle({
5364
5365
  /* @__PURE__ */ jsx4(ArticleByline, {
5365
5366
  author
5366
5367
  }),
5367
- /* @__PURE__ */ jsx4(Separator, {})
5368
+ showDates ? /* @__PURE__ */ jsx4(Separator, {}) : null
5368
5369
  ]
5369
5370
  }),
5370
- /* @__PURE__ */ jsx4(ArticleDate, {
5371
+ showDates ? /* @__PURE__ */ jsx4(ArticleDate, {
5371
5372
  label: "Published",
5372
5373
  value: published
5373
- }),
5374
- updated === undefined ? null : /* @__PURE__ */ jsxs4(Fragment3, {
5374
+ }) : null,
5375
+ !showDates || updated === undefined ? null : /* @__PURE__ */ jsxs4(Fragment3, {
5375
5376
  children: [
5376
5377
  /* @__PURE__ */ jsx4(Separator, {}),
5377
5378
  /* @__PURE__ */ jsx4(ArticleDate, {
@@ -5424,12 +5425,15 @@ function MarketingArticle({
5424
5425
  function ArticleSources({
5425
5426
  heading = ARTICLE_SOURCES_HEADING,
5426
5427
  headingId = "article-sources",
5428
+ showDates = true,
5427
5429
  sources
5428
5430
  }) {
5429
5431
  if (sources.length === 0)
5430
5432
  return null;
5431
- for (const source of sources)
5433
+ for (const source of sources) {
5432
5434
  assertArticleHref(source.href);
5435
+ formatArticleDate(source.checkedOn);
5436
+ }
5433
5437
  return /* @__PURE__ */ jsxs4("section", {
5434
5438
  "aria-labelledby": headingId,
5435
5439
  className: "plain-publication__sources",
@@ -5445,18 +5449,18 @@ function ArticleSources({
5445
5449
  href: source.href,
5446
5450
  children: source.title
5447
5451
  }),
5448
- /* @__PURE__ */ jsxs4("span", {
5452
+ !showDates && (source.publisher === undefined || source.publisher === "") ? null : /* @__PURE__ */ jsxs4("span", {
5449
5453
  children: [
5450
5454
  source.publisher === undefined || source.publisher === "" ? null : /* @__PURE__ */ jsxs4(Fragment3, {
5451
5455
  children: [
5452
5456
  source.publisher,
5453
- /* @__PURE__ */ jsx4(Separator, {})
5457
+ showDates ? /* @__PURE__ */ jsx4(Separator, {}) : null
5454
5458
  ]
5455
5459
  }),
5456
- /* @__PURE__ */ jsx4(ArticleDate, {
5460
+ showDates ? /* @__PURE__ */ jsx4(ArticleDate, {
5457
5461
  label: "Checked",
5458
5462
  value: source.checkedOn
5459
- })
5463
+ }) : null
5460
5464
  ]
5461
5465
  })
5462
5466
  ]
@@ -5525,6 +5529,7 @@ function ArticleIndex({
5525
5529
  headingLevel = 2,
5526
5530
  id,
5527
5531
  items,
5532
+ showDates = true,
5528
5533
  summary
5529
5534
  }) {
5530
5535
  if (![1, 2, 3, 4, 5].includes(headingLevel))
@@ -5582,7 +5587,7 @@ function ArticleIndex({
5582
5587
  className: "plain-publication__entry-dek",
5583
5588
  children: item.dek
5584
5589
  }),
5585
- /* @__PURE__ */ jsxs4("p", {
5590
+ showDates ? /* @__PURE__ */ jsxs4("p", {
5586
5591
  className: "plain-publication__entry-meta",
5587
5592
  children: [
5588
5593
  /* @__PURE__ */ jsx4(ArticleDate, {
@@ -5599,7 +5604,7 @@ function ArticleIndex({
5599
5604
  ]
5600
5605
  })
5601
5606
  ]
5602
- })
5607
+ }) : null
5603
5608
  ]
5604
5609
  }, item.href))
5605
5610
  })
@@ -460,7 +460,8 @@ function renderArticleHtml(input) {
460
460
  const headingId = input.headingId ?? "article-title";
461
461
  const {
462
462
  published,
463
- updated
463
+ updated,
464
+ showDates = true
464
465
  } = input;
465
466
  assertArticleDates(updated === undefined ? {
466
467
  published
@@ -474,21 +475,27 @@ function renderArticleHtml(input) {
474
475
  throw new RangeError("Contents links must point to a heading in this article.");
475
476
  }
476
477
  const tocId = `${headingId}-contents`;
477
- const meta = [input.author === undefined ? "" : renderArticleBylineHtml(input.author) + SEPARATOR, dateHtml("Published", published), updated === undefined ? "" : SEPARATOR + dateHtml("Updated", updated)].join("");
478
- const header = ['<header class="plain-publication__article-header">', present(input.eyebrow) ? `<p class="plain-publication__eyebrow">${escapeArticleHtml(input.eyebrow)}</p>` : "", `<h1 id="${escapeArticleHtml(headingId)}">${escapeArticleHtml(input.heading)}</h1>`, present(input.dek) ? `<p class="plain-publication__article-dek">${escapeArticleHtml(input.dek)}</p>` : "", `<p class="plain-publication__article-meta">${meta}</p>`, input.provenance === null ? "" : renderArticleProvenanceHtml(input.provenance), "</header>"].join("");
478
+ const meta = [input.author === undefined ? "" : renderArticleBylineHtml(input.author), showDates ? dateHtml("Published", published) : "", showDates && updated !== undefined ? dateHtml("Updated", updated) : ""].filter(Boolean).join(SEPARATOR);
479
+ const header = ['<header class="plain-publication__article-header">', present(input.eyebrow) ? `<p class="plain-publication__eyebrow">${escapeArticleHtml(input.eyebrow)}</p>` : "", `<h1 id="${escapeArticleHtml(headingId)}">${escapeArticleHtml(input.heading)}</h1>`, present(input.dek) ? `<p class="plain-publication__article-dek">${escapeArticleHtml(input.dek)}</p>` : "", meta === "" ? "" : `<p class="plain-publication__article-meta">${meta}</p>`, input.provenance === null ? "" : renderArticleProvenanceHtml(input.provenance), "</header>"].join("");
479
480
  const nav = toc.length === 0 ? "" : [`<nav aria-labelledby="${escapeArticleHtml(tocId)}" class="plain-publication__toc">`, `<p id="${escapeArticleHtml(tocId)}">${escapeArticleHtml(input.tocLabel ?? ARTICLE_TOC_LABEL)}</p>`, "<ol>", ...toc.map((item) => `<li><a href="${escapeArticleHtml(item.href)}">${escapeArticleHtml(item.label)}</a></li>`), "</ol></nav>"].join("");
480
481
  return [`<article aria-labelledby="${escapeArticleHtml(headingId)}" class="${escapeArticleHtml(classes2(ROOT_CLASS, "plain-publication__article", input.className))}" data-hraness-article="" data-toc="${toc.length > 0 ? "aside" : "none"}"${input.id === undefined ? "" : ` id="${escapeArticleHtml(input.id)}"`}>`, header, '<div class="plain-publication__article-layout">', nav, `<div class="plain-publication__article-body">${input.bodyHtml}</div>`, "</div>", present(input.afterHtml) ? `<footer class="plain-publication__article-footer">${input.afterHtml}</footer>` : "", "</article>"].join("");
481
482
  }
482
483
  function renderArticleSourcesHtml({
483
484
  heading = ARTICLE_SOURCES_HEADING,
484
485
  headingId = "article-sources",
486
+ showDates = true,
485
487
  sources
486
488
  }) {
487
489
  if (sources.length === 0)
488
490
  return "";
489
- for (const source of sources)
491
+ for (const source of sources) {
490
492
  assertArticleHref(source.href);
491
- return [`<section aria-labelledby="${escapeArticleHtml(headingId)}" class="plain-publication__sources">`, `<h2 id="${escapeArticleHtml(headingId)}">${escapeArticleHtml(heading)}</h2>`, "<ol>", ...sources.map((source) => [`<li><a href="${escapeArticleHtml(source.href)}">${escapeArticleHtml(source.title)}</a>`, "<span>", present(source.publisher) ? escapeArticleHtml(source.publisher) + SEPARATOR : "", dateHtml("Checked", source.checkedOn), "</span></li>"].join("")), "</ol></section>"].join("");
493
+ formatArticleDate(source.checkedOn);
494
+ }
495
+ return [`<section aria-labelledby="${escapeArticleHtml(headingId)}" class="plain-publication__sources">`, `<h2 id="${escapeArticleHtml(headingId)}">${escapeArticleHtml(heading)}</h2>`, "<ol>", ...sources.map((source) => {
496
+ const meta = [present(source.publisher) ? escapeArticleHtml(source.publisher) : "", showDates ? dateHtml("Checked", source.checkedOn) : ""].filter(Boolean).join(SEPARATOR);
497
+ return [`<li><a href="${escapeArticleHtml(source.href)}">${escapeArticleHtml(source.title)}</a>`, meta === "" ? "" : `<span>${meta}</span>`, "</li>"].join("");
498
+ }), "</ol></section>"].join("");
492
499
  }
493
500
  function renderArticleCalloutHtml(input) {
494
501
  const tone = input.tone ?? "note";
@@ -521,6 +528,7 @@ function renderArticleIndexHtml({
521
528
  headingLevel = 2,
522
529
  id,
523
530
  items,
531
+ showDates = true,
524
532
  summary
525
533
  }) {
526
534
  if (![1, 2, 3, 4, 5].includes(headingLevel))
@@ -540,7 +548,7 @@ function renderArticleIndexHtml({
540
548
  }
541
549
  const heading1 = `h${headingLevel}`;
542
550
  const entry = `h${headingLevel + 1}`;
543
- return [`<section aria-labelledby="${escapeArticleHtml(headingId)}" class="${escapeArticleHtml(classes2(ROOT_CLASS, "plain-publication__list", className))}" data-hraness-article-index=""${id === undefined ? "" : ` id="${escapeArticleHtml(id)}"`}>`, `<div class="plain-publication__section-heading"><${heading1} id="${escapeArticleHtml(headingId)}">${escapeArticleHtml(heading)}</${heading1}>`, present(summary) ? `<p>${escapeArticleHtml(summary)}</p>` : "", "</div>", '<div class="plain-publication__article-list">', ...items.map((item) => ['<article class="plain-publication__entry">', present(item.eyebrow) ? `<p class="plain-publication__entry-label">${escapeArticleHtml(item.eyebrow)}</p>` : "", `<${entry} class="plain-publication__entry-title"><a href="${escapeArticleHtml(item.href)}">${escapeArticleHtml(item.title)}</a></${entry}>`, `<p class="plain-publication__entry-dek">${escapeArticleHtml(item.dek)}</p>`, '<p class="plain-publication__entry-meta">', dateHtml("Published", item.published), item.updated === undefined ? "" : SEPARATOR + dateHtml("Updated", item.updated), "</p></article>"].join("")), "</div></section>"].join("");
551
+ return [`<section aria-labelledby="${escapeArticleHtml(headingId)}" class="${escapeArticleHtml(classes2(ROOT_CLASS, "plain-publication__list", className))}" data-hraness-article-index=""${id === undefined ? "" : ` id="${escapeArticleHtml(id)}"`}>`, `<div class="plain-publication__section-heading"><${heading1} id="${escapeArticleHtml(headingId)}">${escapeArticleHtml(heading)}</${heading1}>`, present(summary) ? `<p>${escapeArticleHtml(summary)}</p>` : "", "</div>", '<div class="plain-publication__article-list">', ...items.map((item) => ['<article class="plain-publication__entry">', present(item.eyebrow) ? `<p class="plain-publication__entry-label">${escapeArticleHtml(item.eyebrow)}</p>` : "", `<${entry} class="plain-publication__entry-title"><a href="${escapeArticleHtml(item.href)}">${escapeArticleHtml(item.title)}</a></${entry}>`, `<p class="plain-publication__entry-dek">${escapeArticleHtml(item.dek)}</p>`, showDates ? ['<p class="plain-publication__entry-meta">', dateHtml("Published", item.published), item.updated === undefined ? "" : SEPARATOR + dateHtml("Updated", item.updated), "</p>"].join("") : "", "</article>"].join("")), "</div></section>"].join("");
544
552
  }
545
553
  // src/status-page.ts
546
554
  var STATUS_PAGE_MAX_NEXT = 3;
package/dist/index.js CHANGED
@@ -64,7 +64,7 @@ import {
64
64
  themeFor,
65
65
  typeScale,
66
66
  typography
67
- } from "./chunk-c80g58j1.js";
67
+ } from "./chunk-fmeg5cxf.js";
68
68
  import {
69
69
  diagramMetrics
70
70
  } from "./chunk-gmea6p0d.js";
@@ -169,111 +169,121 @@ function ModeShowcase({
169
169
  const hasStatus = statusNode !== undefined && statusNode !== null && statusNode !== false && statusNode !== "";
170
170
  return /* @__PURE__ */ jsxs("figure", {
171
171
  "aria-label": label?.(surface) ?? `Illustration of ${surface.label.toLowerCase()}`,
172
- className: joinMockupClasses("hkm-showcase", className),
172
+ className: joinMockupClasses("hkm-showcase", "hkm-modes", className),
173
173
  "data-hkm-theme": theme,
174
174
  "data-nosnippet": "",
175
175
  children: [
176
+ surfaces.length > 1 ? /* @__PURE__ */ jsx("div", {
177
+ "aria-label": "Surface",
178
+ className: "hkm-tabs hkm-folder-tabs",
179
+ role: "tablist",
180
+ children: surfaces.map((entry) => /* @__PURE__ */ jsx("button", {
181
+ "aria-controls": `${id}-panel`,
182
+ "aria-selected": entry.id === surface.id,
183
+ className: "hkm-tab",
184
+ id: `${id}-tab-${entry.id}`,
185
+ onClick: () => setSurfaceId(entry.id),
186
+ onKeyDown: onTabKey,
187
+ ref: (element) => {
188
+ if (element === null)
189
+ tabs.current.delete(entry.id);
190
+ else
191
+ tabs.current.set(entry.id, element);
192
+ },
193
+ role: "tab",
194
+ tabIndex: entry.id === surface.id ? 0 : -1,
195
+ type: "button",
196
+ children: entry.label
197
+ }, entry.id))
198
+ }) : null,
176
199
  /* @__PURE__ */ jsxs("div", {
177
- className: "hkm-showcase-controls",
200
+ "aria-labelledby": surfaces.length > 1 ? `${id}-tab-${surface.id}` : undefined,
201
+ className: "hkm-showcase-stage hkm-mode-panel",
202
+ id: `${id}-panel`,
203
+ role: surfaces.length > 1 ? "tabpanel" : undefined,
204
+ style: {
205
+ "--hkm-page-height": `${height}px`
206
+ },
178
207
  children: [
179
- surfaces.length > 1 ? /* @__PURE__ */ jsx("div", {
180
- "aria-label": "Surface",
181
- className: "hkm-tabs",
182
- role: "tablist",
183
- children: surfaces.map((entry) => /* @__PURE__ */ jsx("button", {
184
- "aria-controls": `${id}-panel`,
185
- "aria-selected": entry.id === surface.id,
186
- className: "hkm-tab",
187
- id: `${id}-tab-${entry.id}`,
188
- onClick: () => setSurfaceId(entry.id),
189
- onKeyDown: onTabKey,
190
- ref: (element) => {
191
- if (element === null)
192
- tabs.current.delete(entry.id);
193
- else
194
- tabs.current.set(entry.id, element);
195
- },
196
- role: "tab",
197
- tabIndex: entry.id === surface.id ? 0 : -1,
198
- type: "button",
199
- children: entry.label
200
- }, entry.id))
201
- }) : null,
202
208
  /* @__PURE__ */ jsxs("div", {
203
- className: "hkm-showcase-settings",
209
+ className: "hkm-showcase-controls",
204
210
  children: [
205
211
  /* @__PURE__ */ jsxs("div", {
206
- className: "hkm-showcase-row",
212
+ className: "hkm-showcase-settings",
207
213
  children: [
208
- /* @__PURE__ */ jsx("span", {
209
- className: "hkm-showcase-label",
210
- id: `${id}-mode`,
211
- children: modeLabel
214
+ /* @__PURE__ */ jsxs("div", {
215
+ className: "hkm-showcase-row",
216
+ children: [
217
+ /* @__PURE__ */ jsx("span", {
218
+ className: "hkm-showcase-label",
219
+ id: `${id}-mode`,
220
+ children: modeLabel
221
+ }),
222
+ /* @__PURE__ */ jsx("div", {
223
+ "aria-labelledby": `${id}-mode`,
224
+ className: "hkm-segmented",
225
+ role: "group",
226
+ children: modes.map((entry) => /* @__PURE__ */ jsx("button", {
227
+ "aria-pressed": entry.id === mode,
228
+ onClick: () => chooseMode(entry.id),
229
+ type: "button",
230
+ children: entry.label
231
+ }, entry.id))
232
+ })
233
+ ]
212
234
  }),
213
- /* @__PURE__ */ jsx("div", {
214
- "aria-labelledby": `${id}-mode`,
215
- className: "hkm-segmented",
216
- role: "group",
217
- children: modes.map((entry) => /* @__PURE__ */ jsx("button", {
218
- "aria-pressed": entry.id === mode,
219
- onClick: () => chooseMode(entry.id),
220
- type: "button",
221
- children: entry.label
222
- }, entry.id))
235
+ options === undefined ? null : /* @__PURE__ */ jsxs("div", {
236
+ className: "hkm-showcase-row",
237
+ children: [
238
+ /* @__PURE__ */ jsx("span", {
239
+ className: "hkm-showcase-label",
240
+ id: `${id}-option`,
241
+ children: optionLabel
242
+ }),
243
+ /* @__PURE__ */ jsx("div", {
244
+ "aria-labelledby": `${id}-option`,
245
+ className: "hkm-segmented",
246
+ role: "group",
247
+ children: options.map((entry) => /* @__PURE__ */ jsx("button", {
248
+ "aria-pressed": entry.id === option,
249
+ disabled: optionInactive,
250
+ onClick: () => chooseOption(entry.id),
251
+ type: "button",
252
+ children: entry.label
253
+ }, entry.id))
254
+ })
255
+ ]
223
256
  })
224
257
  ]
225
258
  }),
226
- options === undefined ? null : /* @__PURE__ */ jsxs("div", {
227
- className: "hkm-showcase-row",
228
- children: [
229
- /* @__PURE__ */ jsx("span", {
230
- className: "hkm-showcase-label",
231
- id: `${id}-option`,
232
- children: optionLabel
233
- }),
234
- /* @__PURE__ */ jsx("div", {
235
- "aria-labelledby": `${id}-option`,
236
- className: "hkm-segmented",
237
- role: "group",
238
- children: options.map((entry) => /* @__PURE__ */ jsx("button", {
239
- "aria-pressed": entry.id === option,
240
- disabled: optionInactive,
241
- onClick: () => chooseOption(entry.id),
242
- type: "button",
243
- children: entry.label
244
- }, entry.id))
245
- })
246
- ]
259
+ hint === "" ? null : /* @__PURE__ */ jsx("p", {
260
+ className: "hkm-showcase-hint",
261
+ children: hint
247
262
  })
248
263
  ]
249
264
  }),
250
- hint === "" ? null : /* @__PURE__ */ jsx("p", {
251
- className: "hkm-showcase-hint",
252
- children: hint
265
+ /* @__PURE__ */ jsx("div", {
266
+ className: "hkm-mode-stage",
267
+ children: surfaces.map((entry) => /* @__PURE__ */ jsx("div", {
268
+ "aria-hidden": entry.id !== surface.id,
269
+ className: "hkm-mode-surface",
270
+ "data-hkm-animated": entry.id === surface.id && animated ? "" : undefined,
271
+ "data-hkm-from": entry.id === surface.id && animated ? previousMode : undefined,
272
+ inert: entry.id !== surface.id,
273
+ children: /* @__PURE__ */ jsx(FitToWidth, {
274
+ minWidth,
275
+ children: entry.render({
276
+ animated: entry.id === surface.id && animated,
277
+ mode,
278
+ option,
279
+ previousMode,
280
+ theme
281
+ })
282
+ })
283
+ }, entry.id))
253
284
  })
254
285
  ]
255
286
  }),
256
- /* @__PURE__ */ jsx("div", {
257
- "aria-labelledby": surfaces.length > 1 ? `${id}-tab-${surface.id}` : undefined,
258
- className: "hkm-showcase-stage",
259
- "data-hkm-animated": animated ? "" : undefined,
260
- "data-hkm-from": animated ? previousMode : undefined,
261
- id: `${id}-panel`,
262
- role: surfaces.length > 1 ? "tabpanel" : undefined,
263
- style: {
264
- "--hkm-page-height": `${height}px`
265
- },
266
- children: /* @__PURE__ */ jsx(FitToWidth, {
267
- minWidth,
268
- children: surface.render({
269
- animated,
270
- mode,
271
- option,
272
- previousMode,
273
- theme
274
- })
275
- })
276
- }),
277
287
  !hasStatus && captionText === undefined ? null : /* @__PURE__ */ jsxs("figcaption", {
278
288
  className: "hkm-showcase-caption",
279
289
  children: [
@@ -332,7 +342,7 @@ function StepThrough({
332
342
  className: "hkm-showcase-controls",
333
343
  children: /* @__PURE__ */ jsx("div", {
334
344
  "aria-label": label,
335
- className: "hkm-tabs hkm-step-tabs",
345
+ className: "hkm-tabs hkm-folder-tabs hkm-step-tabs",
336
346
  role: "tablist",
337
347
  children: steps.map((entry, position) => /* @__PURE__ */ jsxs("button", {
338
348
  "aria-controls": `${id}-panel-${entry.id}`,
@@ -89,7 +89,7 @@ import {
89
89
  marketingProofFrameAddress,
90
90
  proceduralBackdropVariants,
91
91
  proceduralRecipeVersion
92
- } from "../chunk-6bfr0g23.js";
92
+ } from "../chunk-4tgt8egt.js";
93
93
  import {
94
94
  SyntaxCode
95
95
  } from "../chunk-6ts4955n.js";
@@ -121,7 +121,7 @@ import {
121
121
  resolveStatusPage,
122
122
  statusPageRoutesAttribute,
123
123
  suggestStatusRoute
124
- } from "../chunk-c80g58j1.js";
124
+ } from "../chunk-fmeg5cxf.js";
125
125
  import"../chunk-gmea6p0d.js";
126
126
  import"../chunk-wzvdn8ey.js";
127
127
  import"../chunk-he8eznb1.js";
@@ -7132,6 +7132,7 @@ Run the job, then show me its log.`,
7132
7132
  /* @__PURE__ */ jsxs15(MarketingArticle, {
7133
7133
  after: /* @__PURE__ */ jsx17(ArticleSources, {
7134
7134
  headingId: "gallery-article-sources",
7135
+ showDates: false,
7135
7136
  sources: [{
7136
7137
  checkedOn: "2026-09-20",
7137
7138
  href: "#articles",
@@ -7155,6 +7156,7 @@ Run the job, then show me its log.`,
7155
7156
  }
7156
7157
  },
7157
7158
  published: "2026-09-10",
7159
+ showDates: false,
7158
7160
  toc: [{
7159
7161
  href: "#gallery-article-problem",
7160
7162
  label: "The problem"
@@ -68,7 +68,7 @@ import {
68
68
  marketingProofFrameAddress,
69
69
  proceduralBackdropVariants,
70
70
  proceduralRecipeVersion
71
- } from "../chunk-6bfr0g23.js";
71
+ } from "../chunk-4tgt8egt.js";
72
72
  import {
73
73
  SyntaxCode
74
74
  } from "../chunk-6ts4955n.js";