<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Vanilla Breeze changelog</title>
  <subtitle>Releases of the Vanilla Breeze HTML component system</subtitle>
  <id>https://vanilla-breeze.com/changelog/</id>
  <link rel="self" type="application/atom+xml" href="https://vanilla-breeze.com/changelog/feed.xml"/>
  <link rel="alternate" type="text/html" href="https://vanilla-breeze.com/changelog/"/>
  <updated>2026-11-02T00:00:00Z</updated>
  <author><name>Thomas A. Powell</name></author>
  <entry>
    <title>v0.5.0</title>
    <id>https://vanilla-breeze.com/changelog/#v0-5-0</id>
    <link rel="alternate" type="text/html" href="https://vanilla-breeze.com/changelog/#v0-5-0"/>
    <updated>2026-11-02T00:00:00Z</updated>
    <published>2026-11-02T00:00:00Z</published>
    <content type="html">&lt;p&gt;0.5.0 is the first element quality release, covering every A, B and C element. Components rebuild cleanly when moved or re-populated, keyboard and screen-reader access is fixed across the C components, and several XSS paths are closed. Themes gain a &lt;code&gt;--btn-border-width&lt;/code&gt; hook, reach 4.5:1 contrast for links and outline buttons, and paint their own dark-mode backgrounds. It includes breaking changes, listed under Changed: C-component API cleanups, &lt;code&gt;&amp;lt;cite data-variant=&amp;quot;quoted&amp;quot;&amp;gt;&lt;/code&gt;, removed legacy link and abbr classes, and the brand demo and stale per-accent theme files are no longer in the package.&lt;/p&gt;
&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;--btn-border-width&lt;/code&gt; button hook.&lt;/strong&gt; Themes set the border width through it
(plus &lt;code&gt;border-color&lt;/code&gt;/&lt;code&gt;border-style&lt;/code&gt;) instead of a &lt;code&gt;border&lt;/code&gt; shorthand. The
padding gives the width back, so primary, secondary and ghost buttons are the
same height in every theme. All bordered themes and packs use it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stop buttons and history for the AI components.&lt;/strong&gt; &lt;code&gt;&amp;lt;ai-chat&amp;gt;&lt;/code&gt; and
&lt;code&gt;&amp;lt;ai-summary&amp;gt;&lt;/code&gt; show a Stop button while a reply streams (plus a public
&lt;code&gt;stop()&lt;/code&gt;); endpoint mode sends prior turns as &lt;code&gt;messages[]&lt;/code&gt;
(ai-page-tools v1.1 — servers that ignore it still work); the
&lt;code&gt;{content}&lt;/code&gt; fallback-URL token is filled (capped at 1,500 characters;
&lt;code&gt;&amp;lt;ai-chat&amp;gt;&lt;/code&gt; uses only its &lt;code&gt;context&lt;/code&gt; region); &lt;code&gt;format=&amp;quot;plain-text&amp;quot;&lt;/code&gt;
renders as text; &lt;code&gt;&amp;lt;ai-summary&amp;gt;&lt;/code&gt; warns when input exceeds the on-device
quota.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;heading&lt;/code&gt; and &lt;code&gt;heading-level&lt;/code&gt; on &lt;code&gt;&amp;lt;analytics-panel&amp;gt;&lt;/code&gt; and
&lt;code&gt;&amp;lt;author-index&amp;gt;&lt;/code&gt;.&lt;/strong&gt; &lt;code&gt;&amp;lt;analytics-panel title&amp;gt;&lt;/code&gt; is renamed &lt;code&gt;heading&lt;/code&gt; (the
global &lt;code&gt;title&lt;/code&gt; put a tooltip on the whole panel).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;activity-feed&amp;gt;&lt;/code&gt; load-more contract.&lt;/strong&gt; &lt;code&gt;load-more&lt;/code&gt; carries
&lt;code&gt;detail.done()&lt;/code&gt;, the feed is &lt;code&gt;aria-busy&lt;/code&gt; while loading, and removing
&lt;code&gt;data-infinite&lt;/code&gt; ends it. Authored &lt;code&gt;&amp;lt;time datetime&amp;gt;&lt;/code&gt; works as the
timestamp without JavaScript.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;Analytics.getStatus()&lt;/code&gt;&lt;/strong&gt; — a read-only snapshot of the analytics
runtime: whether it is running, why it is off (user, GPC, DNT, consent),
the fields an event carries, and per-page send counts. A
&lt;code&gt;vb:analytics-status&lt;/code&gt; event fires when it changes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;markdown-viewer sanitize&amp;gt;&lt;/code&gt;&lt;/strong&gt; — parsed markdown now goes through the
shared sanitizer by default; &lt;code&gt;sanitize=&amp;quot;off&amp;quot;&lt;/code&gt; opts out for trusted
content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;data-accent&lt;/code&gt; for colour accents.&lt;/strong&gt; Accent presets (ocean, forest,
sunset, …) were inline seeds ThemeManager wrote on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt;, and the
themes page&amp;#39;s &lt;code&gt;data-theme=&amp;quot;forest&amp;quot;&lt;/code&gt; examples did nothing. &lt;code&gt;data-accent&lt;/code&gt;
now applies them on &lt;code&gt;&amp;lt;html&amp;gt;&lt;/code&gt; or any element, as a separate axis from
&lt;code&gt;data-theme&lt;/code&gt;: accents tint the default and personality themes (modern,
minimal, classic); fixed-palette themes keep their colours.
&lt;code&gt;ThemeManager.setAccent()&lt;/code&gt; sets the attribute. The CSS is generated from
&lt;code&gt;src/lib/theme-data.js&lt;/code&gt; (&lt;code&gt;scripts/generate-accent-css.mjs&lt;/code&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;VB.store&lt;/code&gt; and &lt;code&gt;VB.service&lt;/code&gt; are public.&lt;/strong&gt; The storage and fetch layers
VB&amp;#39;s components already used are now on &lt;code&gt;window.VB&lt;/code&gt; and exported by name
from the main, core and autoload bundles (&lt;code&gt;import { VBStore, VBService, VBServiceError } from &amp;#39;vanilla-breeze/js&amp;#39;&lt;/code&gt;). &lt;code&gt;VB.service.configure({ baseUrl })&lt;/code&gt; points every &lt;code&gt;/go/&lt;/code&gt; role (notify, email, newsletter) at your
own backend; &lt;code&gt;VB.store.clearAll()&lt;/code&gt; clears every &lt;code&gt;vb:*&lt;/code&gt; key. Their state
is shared across bundles, so configuration reaches autoloaded components
too. Documented at &lt;code&gt;/docs/concepts/vb-service/&lt;/code&gt; and
&lt;code&gt;/docs/concepts/vb-store/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Changed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Brand demo themes are no longer in the package.&lt;/strong&gt; &lt;code&gt;themes/anthropic.css&lt;/code&gt;,
&lt;code&gt;themes/ibm.css&lt;/code&gt;, &lt;code&gt;themes/mcdonalds.css&lt;/code&gt; and &lt;code&gt;themes/starbucks.css&lt;/code&gt; were
demonstrations of building a theme from a brand, not library themes. They
now live with the alpenglow demo (&lt;code&gt;/docs/alpenglow/themes/&lt;/code&gt;) and are no
longer in &lt;code&gt;dist/cdn/themes/&lt;/code&gt; or the theme manifest.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stale per-accent theme files removed from the package.&lt;/strong&gt;
&lt;code&gt;themes/{ocean,sunset,forest,rose,lavender,coral,amber,indigo,slate,emerald}.css&lt;/code&gt;
were leftovers from before accents were bundled. Use &lt;code&gt;data-accent=&amp;quot;ocean&amp;quot;&lt;/code&gt;
(and so on) with the main bundle instead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Breaking API changes from the C-element review.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;comment-thread&amp;gt;&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;addComment()&lt;/code&gt;/&lt;code&gt;updateComment()&lt;/code&gt; take &lt;code&gt;bodyText&lt;/code&gt; (set as text) or &lt;code&gt;bodyHtml&lt;/code&gt; (sanitized) instead of &lt;code&gt;body&lt;/code&gt;. Author links are kept only for http(s) and relative URLs.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;comment-box&amp;gt;&lt;/code&gt; submit:&lt;/strong&gt; the event detail offers &lt;code&gt;waitUntil(promise)&lt;/code&gt;. The box stays busy, clears when the promise resolves and keeps the text when it rejects. &lt;code&gt;comment-thread:reply&lt;/code&gt; follows the same pattern and is now cancelable.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;chat-input&amp;gt;&lt;/code&gt;:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Inside a form it now submits the form (Enter or the send button) instead of firing &lt;code&gt;chat-input:send&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The send detail is &lt;code&gt;{ message }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--chat-input-radius&lt;/code&gt; is removed.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;chat-window&amp;gt;&lt;/code&gt;:&lt;/strong&gt; user messages are always shown as plain text. &lt;code&gt;resolveTyping()&lt;/code&gt; fills a typing placeholder.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;card-list&amp;gt;&lt;/code&gt;:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;setItems()&lt;/code&gt;/&lt;code&gt;getItems()&lt;/code&gt; are removed; use &lt;code&gt;.items&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;URL attributes bound from data must be safe URLs, and &lt;code&gt;on*&lt;/code&gt;/&lt;code&gt;style&lt;/code&gt; are never written.&lt;/li&gt;
&lt;li&gt;It follows the global &lt;code&gt;data-layout&lt;/code&gt; system.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;popularity-index&amp;gt;&lt;/code&gt;:&lt;/strong&gt; the analytics endpoint moves to &lt;code&gt;analytics-src&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Change events:&lt;/strong&gt; &lt;code&gt;&amp;lt;compare-surface&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;content-lens&amp;gt;&lt;/code&gt; no longer fire them during setup or when changed from script.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;content-swap&amp;gt;&lt;/code&gt;:&lt;/strong&gt; without explicit triggers, it adds a real toggle button instead of turning the container into a button.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;color-picker&amp;gt;&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;required&lt;/code&gt; is removed. &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;disabled&lt;/code&gt; on the inner input move to the host.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;context-menu&amp;gt;&lt;/code&gt;:&lt;/strong&gt; &lt;code&gt;select&lt;/code&gt; detail is &lt;code&gt;{ item, value }&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;change-set&amp;gt;&lt;/code&gt;:&lt;/strong&gt; gains &lt;code&gt;controls=&amp;quot;none&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;calendar-wc&amp;gt;&lt;/code&gt;:&lt;/strong&gt; month titles are plain text unless &lt;code&gt;data-heading-level&lt;/code&gt; is set.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;calendar-event&amp;gt;&lt;/code&gt;:&lt;/strong&gt; is a block (titles ellipsize). It shows a pointer only when it contains a link or button.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Overlapping clusters:&lt;/strong&gt; &lt;code&gt;data-layout-overlap&lt;/code&gt; keeps source order (the &amp;quot;+N&amp;quot; chip comes last).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;cite&amp;gt;&lt;/code&gt;:&lt;/strong&gt; the quoted variant is &lt;code&gt;data-variant=&amp;quot;quoted&amp;quot;&lt;/code&gt; (was &lt;code&gt;class=&amp;quot;quoted&amp;quot;&lt;/code&gt;), matching &lt;code&gt;a&lt;/code&gt; and &lt;code&gt;abbr&lt;/code&gt;. Its quotation marks follow the language, as &lt;code&gt;&amp;lt;q&amp;gt;&lt;/code&gt; does: «…» in French, „…&amp;quot; in German.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;brand-mark&amp;gt;&lt;/code&gt; never modifies its content.&lt;/strong&gt; Authored children (an
&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt;, an &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt;, text, a tagline) are left exactly as written. &lt;code&gt;src&lt;/code&gt;
adds one owned &lt;code&gt;&amp;lt;picture&amp;gt;&lt;/code&gt;; image-only vs wordmark is CSS, with the
authored text kept as the accessible name. &lt;code&gt;alt&lt;/code&gt; and &lt;code&gt;height&lt;/code&gt; now work,
&lt;code&gt;src-compact&lt;/code&gt; is implemented (plus &lt;code&gt;compact-media&lt;/code&gt;), and the host no
longer gets an &lt;code&gt;aria-label&lt;/code&gt;. New &lt;code&gt;api.json&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Blockquote attribution belongs outside the quote.&lt;/strong&gt; &lt;code&gt;figure.quote&lt;/code&gt; +
&lt;code&gt;figcaption&lt;/code&gt; is the documented pattern; &lt;code&gt;blockquote &amp;gt; footer&lt;/code&gt; /
&lt;code&gt;&amp;gt; cite&lt;/code&gt; still style as a legacy attribution line, and only as direct
children.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;analytics-panel&amp;gt;&lt;/code&gt; rebuilt on the runtime&amp;#39;s real state.&lt;/strong&gt; It used to
read storage keys nothing writes, so it always said &amp;quot;No data stored&amp;quot;
while page views were being sent, and it reported &amp;quot;active&amp;quot; to visitors
whose Global Privacy Control or Do Not Track kept analytics off. It now
shows what is actually sent and why analytics is off, Pause/Resume go
through &lt;code&gt;setConsent()&lt;/code&gt;, &amp;quot;Clear my data&amp;quot; is gone (there was nothing local
to clear), it renders once and keeps focus, and it uses VB tokens, so it
is readable in dark mode. The unused &lt;code&gt;--font-size-0&lt;/code&gt;/&lt;code&gt;--font-size-1&lt;/code&gt;
Open Props aliases are removed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Legacy link and abbr classes removed.&lt;/strong&gt; &lt;code&gt;a.muted&lt;/code&gt;, &lt;code&gt;a.plain&lt;/code&gt; and
&lt;code&gt;a.external&lt;/code&gt; are gone (use &lt;code&gt;data-variant=&amp;quot;muted&amp;quot;&lt;/code&gt; / &lt;code&gt;&amp;quot;plain&amp;quot;&lt;/code&gt; and
&lt;code&gt;rel=&amp;quot;external&amp;quot;&lt;/code&gt;), and &lt;code&gt;abbr.plain&lt;/code&gt; is now &lt;code&gt;abbr[data-variant=&amp;quot;plain&amp;quot;]&lt;/code&gt;,
matching the link API.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;vanilla-breeze-autoload.js&lt;/code&gt; ships in the npm package.&lt;/strong&gt; The
autoloader was documented as a loading strategy but excluded from the
package. It finds its &lt;code&gt;components/&lt;/code&gt; chunks next to its own script, so it
works from unpkg.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Buttons follow the theme&amp;#39;s hover and active colours.&lt;/strong&gt; Themes set
&lt;code&gt;--color-primary-hover&lt;/code&gt; / &lt;code&gt;--color-primary-active&lt;/code&gt;, but &lt;code&gt;button&lt;/code&gt;
computed its own states, so those overrides never showed. A button with
no custom colour now uses &lt;code&gt;--color-interactive-hover&lt;/code&gt; and the new
&lt;code&gt;--color-interactive-active&lt;/code&gt; (both follow primary); a button with
&lt;code&gt;--btn-color&lt;/code&gt; still derives its own states.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;nav.pills&lt;/code&gt; and &lt;code&gt;nav.pagination&lt;/code&gt; pick readable text for the current
item&lt;/strong&gt; with &lt;code&gt;contrast-color()&lt;/code&gt; instead of a fixed white, which failed in
dark themes that lighten their primary colour. The current-page tokens
(&lt;code&gt;--color-active-text&lt;/code&gt;, &lt;code&gt;--color-active-bg&lt;/code&gt;) are now documented on the
nav page.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Themes.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Links, outline buttons and primary-button labels reach 4.5:1 contrast in every theme and accent, in both modes (art-deco, claymorphism, cyber, journal, nord, solarized, super2026, tokyo-night, dusk, bauhaus, high-noon, dawn, cottagecore; forest, sunset, coral and amber accents). Brand primaries keep their brand value; only &lt;code&gt;--color-interactive&lt;/code&gt; changed.&lt;/li&gt;
&lt;li&gt;Dark mode paints each theme&amp;#39;s own &lt;code&gt;--color-background&lt;/code&gt; as the page background. A fixed VB blue-black used to cover it in most themes (solarized dark showed blue-black, not #002b36). The light-only a11y-dyslexia palette declares &lt;code&gt;color-scheme: light&lt;/code&gt;, so in dark mode it is a readable cream page instead of dark text on a dark page.&lt;/li&gt;
&lt;li&gt;Theme blockquote glyphs are silent to screen readers and sit on the inline-start side in right-to-left text, with logical padding.&lt;/li&gt;
&lt;li&gt;A breadcrumb&amp;#39;s linked current crumb is plain current text, not the nav current-page pill (starbucks pill, neumorphism inset, wrong colour elsewhere).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Range sliders.&lt;/strong&gt; The value bubble and datalist labels are positioned in CSS, so they track the thumb after late layout changes and resizes. The chat &lt;code&gt;[data-bubble]&lt;/code&gt; shape no longer narrows range inputs to 75%.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security and data loss.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;card-list&amp;gt;&lt;/code&gt; no longer writes &lt;code&gt;javascript:&lt;/code&gt; URLs from data.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;comment-thread&amp;gt;&lt;/code&gt; no longer injects unsanitized HTML or &lt;code&gt;javascript:&lt;/code&gt; author links.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;chat-window&amp;gt;&lt;/code&gt; no longer parses typed text as HTML.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ConsentBanner.getConsent()&lt;/code&gt; honours expiry and the docs await it. Before, the sample never started analytics.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Components that broke when moved or re-populated.&lt;/strong&gt; These now rebuild cleanly on reconnect and on data setters: &lt;code&gt;&amp;lt;calendar-wc&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;color-picker&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;command-palette&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;context-menu&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;comment-thread&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;comment-box&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;carousel-wc&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;card-list&amp;gt;&lt;/code&gt;. Before, they duplicated their UI, doubled their listeners, or left actions dead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Keyboard and screen-reader access in the C components.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;content-swap&amp;gt;&lt;/code&gt;:&lt;/strong&gt; explicit triggers work.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;chat-input&amp;gt;&lt;/code&gt;:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Confirming input-method composition with Enter no longer sends.&lt;/li&gt;
&lt;li&gt;It has a focus ring.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;disabled&lt;/code&gt; and &lt;code&gt;maxlength&lt;/code&gt; are enforced.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;context-menu&amp;gt;&lt;/code&gt;:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Opens with Shift+F10 or the Menu key.&lt;/li&gt;
&lt;li&gt;Reports the chosen item.&lt;/li&gt;
&lt;li&gt;Uses correct menu roles.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;command-palette&amp;gt;&lt;/code&gt;:&lt;/strong&gt; announces the active option.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;color-picker&amp;gt;&lt;/code&gt;:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Its button is named by the field&amp;#39;s label.&lt;/li&gt;
&lt;li&gt;Escape closes it.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;calendar-wc&amp;gt;&lt;/code&gt;:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Arrow keys move from the focused day.&lt;/li&gt;
&lt;li&gt;The day detail opens from the keyboard.&lt;/li&gt;
&lt;li&gt;Multi-day events no longer lose a day across daylight-saving changes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data-year-range&lt;/code&gt; sets how many years the year select lists either side of the current year (default 10).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;carousel-wc&amp;gt;&lt;/code&gt;:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Autoplay has a pause/play button.&lt;/li&gt;
&lt;li&gt;It stops announcing every slide while rotating.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;chart-wc&amp;gt;&lt;/code&gt;:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;The fallback table stays available to screen readers.&lt;/li&gt;
&lt;li&gt;Charts print as a table.&lt;/li&gt;
&lt;li&gt;Charts built from data get a generated table.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CSS for the C elements.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Invalid rule removed:&lt;/strong&gt; the &lt;code&gt;translate: no&lt;/code&gt; rule did nothing; use the HTML &lt;code&gt;translate=&amp;quot;no&amp;quot;&lt;/code&gt; attribute.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt;:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;Bare &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; no longer wraps ASCII art.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;pre&amp;gt;&amp;lt;samp&amp;gt;&lt;/code&gt; gets the code-block treatment.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inline &lt;code&gt;&amp;lt;code&amp;gt;&lt;/code&gt;:&lt;/strong&gt; wraps long identifiers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Editorial theme:&lt;/strong&gt; no longer turns inline citations into block lines.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cover hero:&lt;/strong&gt; headers span the full width.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;compare-surface&amp;gt;&lt;/code&gt;:&lt;/strong&gt; works in right-to-left layouts and reacts to &lt;code&gt;position&lt;/code&gt; changes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;content-lens&amp;gt;&lt;/code&gt;:&lt;/strong&gt; chips show keyboard focus.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;C element doc pages.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Removed false screen-reader claims (cite, code, colgroup, caption, chat-thread, comment-thread).&lt;/li&gt;
&lt;li&gt;Layout pages show the &lt;code&gt;data-layout&lt;/code&gt; attribute form.&lt;/li&gt;
&lt;li&gt;Canvas demos follow the theme.&lt;/li&gt;
&lt;li&gt;The carousel transitions demo meets 4.5:1 text contrast on every slide.&lt;/li&gt;
&lt;li&gt;colgroup documents &lt;code&gt;scope=&amp;quot;colgroup&amp;quot;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Every C component&amp;#39;s &lt;code&gt;api.json&lt;/code&gt; now matches its runtime.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;bdo dir=&amp;quot;rtl&amp;quot;&amp;gt;&lt;/code&gt; reverses text again.&lt;/strong&gt; VB&amp;#39;s own &lt;code&gt;unicode-bidi&lt;/code&gt;
rules outranked the element and weakened the browser&amp;#39;s isolation on
every &lt;code&gt;[dir]&lt;/code&gt; element; they are removed and the UA defaults apply.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;data-loading&lt;/code&gt; buttons keep the submitter.&lt;/strong&gt; The button was disabled
inside the submit event, dropping its &lt;code&gt;name&lt;/code&gt;/&lt;code&gt;value&lt;/code&gt; from the form data;
it now uses &lt;code&gt;aria-disabled&lt;/code&gt; and swallows repeat activations, only the
button that submitted shows the spinner, and spinner-only keeps its
label as hidden text.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Buttons.&lt;/strong&gt; &lt;code&gt;a.button&lt;/code&gt; follows &lt;code&gt;--btn-color&lt;/code&gt; (a gold link button was
white on gold); &lt;code&gt;input[type=submit|button|reset]&lt;/code&gt; match &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;; all
variants share a transparent border (equal heights, visible in forced
colours); disabled buttons ignore hover, hover is skipped on touch;
&lt;code&gt;aria-disabled&lt;/code&gt; and &lt;code&gt;aria-pressed&lt;/code&gt; are styled; icon-only buttons are
square; the focus ring follows the &lt;code&gt;--focus-ring-*&lt;/code&gt; tokens.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;bread-crumb&amp;gt;&lt;/code&gt; and &lt;code&gt;nav.breadcrumb&lt;/code&gt;.&lt;/strong&gt; Separators are silent to
screen readers, &lt;code&gt;data-truncated&lt;/code&gt; shows an ellipsis, collapsed trails get
a real &amp;quot;Show full path&amp;quot; button, &lt;code&gt;&amp;lt;nav aria-label=&amp;quot;Breadcrumb&amp;quot;&amp;gt;&lt;/code&gt; is the
canonical markup (no duplicate landmark), JSON-LD resolves relative
hrefs, and path segments are decoded.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;B-element doc pages.&lt;/strong&gt; &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; are written (they were
placeholders); &lt;code&gt;&amp;lt;bdi&amp;gt;&lt;/code&gt;/&lt;code&gt;&amp;lt;bdo&amp;gt;&lt;/code&gt; guidance and demos corrected; &lt;code&gt;&amp;lt;b&amp;gt;&lt;/code&gt; and
&lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt; no longer claim screen readers announce them; &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt; and
button pages updated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A-element review, batch 5.&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;audio-player&amp;gt;&lt;/code&gt;: the seek slider announces &amp;quot;0:13 of 0:30&amp;quot;, mute
reports &lt;code&gt;aria-pressed&lt;/code&gt;, load errors show a message, shuffle plays each
track once per cycle, scrubbing no longer jumps, and the player and the
&lt;code&gt;.audio-standalone&lt;/code&gt; utility share one track helper (both auto-advance).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;audio-visualizer&amp;gt;&lt;/code&gt;: caches its canvas and colours instead of doing
the work every frame, draws a baseline instead of a blank box (and a
single frame under reduced motion), and follows &lt;code&gt;for&lt;/code&gt;/&lt;code&gt;data-mode&lt;/code&gt;
changes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;activity-feed&amp;gt;&lt;/code&gt;: follows the APG feed pattern (Page keys move one
article; feed children are all articles; &lt;code&gt;aria-setsize&lt;/code&gt; is -1 while
infinite), and avatars render (they never did).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;author-index&amp;gt;&lt;/code&gt;: a failed fetch keeps the filter on authored markup,
ids are unique for any script, unsafe hrefs are dropped, result counts
are announced, and moving it doesn&amp;#39;t refetch.&lt;/li&gt;
&lt;li&gt;Article highlights: every article paints its own palette (only the
first did), two articles sharing a colour no longer overwrite each
other, and custom colours work in the &lt;code&gt;&amp;lt;mark&amp;gt;&lt;/code&gt; fallback.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;comment-thread&amp;gt;&lt;/code&gt; avatars render.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;area&amp;gt;&lt;/code&gt; focus uses the theme&amp;#39;s interactive colour.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;ai-summary&amp;gt;&lt;/code&gt; XSS.&lt;/strong&gt; Model or endpoint output rendered through
&lt;code&gt;&amp;lt;markdown-viewer&amp;gt;&lt;/code&gt; was inserted as raw HTML; it is now sanitized.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;activity-feed&amp;gt;&lt;/code&gt; froze grouped feeds.&lt;/strong&gt; Any child change on a
&lt;code&gt;data-group&lt;/code&gt; feed started an endless regroup loop. Moving the feed no
longer stacks infinite-scroll sentinels, and keyboard navigation now
works (a single Tab stop with a roving tabindex; keys work from links
inside an entry).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;audio-player&amp;gt;&lt;/code&gt; keyboard.&lt;/strong&gt; Shortcuts were bound on the host and
could not see past the shadow boundary, so arrow keys on the volume
slider seeked the track and Space on the playlist started playback.
Focused controls now keep their own keys. &lt;code&gt;loop&lt;/code&gt; now loops a single
track.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;audio-visualizer&amp;gt;&lt;/code&gt;&lt;/strong&gt; restarts after a DOM move, no longer silences
cross-origin audio (it skips hooking and sets &lt;code&gt;data-state&lt;/code&gt;), no longer
doubles the volume when two visualizers share an &lt;code&gt;&amp;lt;audio&amp;gt;&lt;/code&gt;, and clamps
bad &lt;code&gt;data-fft-size&lt;/code&gt; values instead of throwing.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;ai-chat&amp;gt;&lt;/code&gt; / &lt;code&gt;&amp;lt;ai-summary&amp;gt;&lt;/code&gt;&lt;/strong&gt; no longer duplicate their UI when
moved; &lt;code&gt;&amp;lt;ai-chat&amp;gt;&lt;/code&gt; ignores a send while a reply is streaming (Escape to
stop keeps working), and streaming output is &lt;code&gt;aria-busy&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;&amp;lt;accordion-wc&amp;gt;&lt;/code&gt; &lt;code&gt;panels&lt;/code&gt; setter&lt;/strong&gt; bound listeners twice when assigned
before connection (with &lt;code&gt;transition&lt;/code&gt;, a click never opened the panel)
and dropped &lt;code&gt;data-upgraded&lt;/code&gt; when assigned later. A lone &lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;
answer is now wrapped instead of being turned into &lt;code&gt;role=&amp;quot;region&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Link auto-icons.&lt;/strong&gt; A &lt;code&gt;download&lt;/code&gt; link to a PDF shows the download
arrow instead of the PDF badge; links in &lt;code&gt;nav&lt;/code&gt;, &lt;code&gt;header&lt;/code&gt; and &lt;code&gt;footer&lt;/code&gt; and
button-styled links suppress every auto-icon (some slipped through
before); an authored &lt;code&gt;&amp;lt;icon-wc&amp;gt;&lt;/code&gt; replaces the auto glyph instead of
doubling it; the glyphs carry empty alternative text, so screen readers
read only the link text. &lt;code&gt;&amp;lt;abbr&amp;gt;&lt;/code&gt; gets the dotted underline and help
cursor only when it has a &lt;code&gt;title&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A-element doc pages corrected&lt;/strong&gt; after a quality review: &lt;code&gt;article&lt;/code&gt;
highlights (the toolbar is &lt;code&gt;&amp;lt;selection-menu&amp;gt;&lt;/code&gt;; no &lt;code&gt;initHighlights&lt;/code&gt;
export; real colour defaults and events), &lt;code&gt;article.compact&lt;/code&gt; no longer
collapses its text column, &lt;code&gt;data-drop-cap&lt;/code&gt; no longer applies twice,
&lt;code&gt;address.inline&lt;/code&gt; sample is valid HTML and &lt;code&gt;.compact&lt;/code&gt; separators are
CSS-generated and silent, &lt;code&gt;aside.float&lt;/code&gt; un-floats below 40rem, wrong
landmark/screen-reader claims fixed on &lt;code&gt;article&lt;/code&gt;, &lt;code&gt;aside&lt;/code&gt; and &lt;code&gt;address&lt;/code&gt;,
&lt;code&gt;area&lt;/code&gt; (&lt;code&gt;shape&lt;/code&gt; is optional; coordinates; document order), &lt;code&gt;audio&lt;/code&gt;
captions, the accordion custom-indicator escapes and &lt;code&gt;flush&lt;/code&gt; wording,
the author-index JSON sample, and stray parsed placeholders on the AI
component pages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Theme text contrast on real pages.&lt;/strong&gt; A new themed site-pages suite
(5 doc pages × 10 aggressive themes × light/dark, with an AA check on
every text node) found 37 failures; all are fixed. Kawaii dark inline
code was 1.6:1 (the kawaii pack hardcoded the light-mode colour);
brutalist light code inside &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; sat on the inline-code chip (2.4:1)
and its links deepen a step; vaporwave light links and code use a
deeper &lt;code&gt;--color-interactive&lt;/code&gt;; win9x dark links, muted text and the
active nav link are lighter on the dark window.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;win9x puts page content in a window.&lt;/strong&gt; Text sat directly on the teal
desktop (body ~3:1, links and muted text under 2:1); &lt;code&gt;main&lt;/code&gt; now has the
window surface, framed by the teal desktop.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Themes no longer frame every form and blockquote.&lt;/strong&gt; Under the ~28
themes that set a border style (swiss, genai, kawaii, organic, …),
&lt;code&gt;data-border-style&lt;/code&gt; auto-applied a full border to bare &lt;code&gt;form&lt;/code&gt; and
&lt;code&gt;blockquote&lt;/code&gt; with no padding, so controls and quote text touched the
frame. Those rules were inert until 0.4.0 moved them out of the tokens
layer. Auto-apply now targets padded containers only (&lt;code&gt;.card&lt;/code&gt;, the
preview panels).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;tab-set&lt;/code&gt; panels span the full width.&lt;/strong&gt; The open panel sat in the
first tab&amp;#39;s column, which stretched that tab across the component and
pushed the others to the far edge (off-screen on phones). Chromium and
Safari wrap &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt; content in a &lt;code&gt;::details-content&lt;/code&gt; box that became
the grid item; tab-set now flattens it and gives the grid one explicit
column per tab.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;data-page-layout=&amp;quot;sidebar-right&amp;quot;&lt;/code&gt; stacks on phones.&lt;/strong&gt; The mobile stack
template had no &lt;code&gt;body-aside&lt;/code&gt; area, so the aside got an implicit column
beside the stack and overflowed the viewport.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Print styles and two themes match the current effect syntax.&lt;/strong&gt; They
still targeted &lt;code&gt;[data-gradient-text]&lt;/code&gt;, &lt;code&gt;[data-shimmer]&lt;/code&gt; and friends,
which became &lt;code&gt;data-effect&lt;/code&gt; tokens.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Component transitions animate again.&lt;/strong&gt; &lt;code&gt;tab-set&lt;/code&gt;, &lt;code&gt;accordion-wc&lt;/code&gt; and
&lt;code&gt;carousel-wc&lt;/code&gt; animate their &lt;code&gt;transition&lt;/code&gt; modes with &lt;code&gt;vt-*&lt;/code&gt;
keyframes that only existed in the opt-in &lt;code&gt;utils/view-transitions.css&lt;/code&gt;,
which neither bundle imports, so the transitions silently did nothing.
The keyframes now ship in &lt;code&gt;vanilla-breeze.css&lt;/code&gt; and
&lt;code&gt;vanilla-breeze-core.css&lt;/code&gt;; cross-document &lt;code&gt;@view-transition&lt;/code&gt; stays
opt-in.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;data-transition&lt;/code&gt; presets animate.&lt;/strong&gt; &lt;code&gt;slide&lt;/code&gt;, &lt;code&gt;fade&lt;/code&gt;, &lt;code&gt;scale&lt;/code&gt; and
&lt;code&gt;none&lt;/code&gt; played the browser&amp;#39;s plain crossfade, for two reasons: the
runtime processed elements before the presets registered, so they never
got their &lt;code&gt;view-transition-class&lt;/code&gt;, and the rules for those classes lived
only in the opt-in &lt;code&gt;utils/view-transitions.css&lt;/code&gt;. Late registrations now
re-wire waiting elements, like effects and triggers. The class rules,
the &lt;code&gt;--view-transition-duration&lt;/code&gt; tokens and the reduced-motion rule now
ship in every bundle, so content-swap, image-gallery and
version-switcher transitions also respect reduced motion.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;combo-box&lt;/code&gt; exposes one combobox, the W3C way.&lt;/strong&gt; The &lt;code&gt;combobox&lt;/code&gt; role
went through &lt;code&gt;ElementInternals&lt;/code&gt;, which put it on the host in Chromium
while &lt;code&gt;aria-expanded&lt;/code&gt;, &lt;code&gt;aria-controls&lt;/code&gt; and &lt;code&gt;aria-activedescendant&lt;/code&gt; sat on
the inner input (Firefox put everything on the input). The role is now a
plain &lt;code&gt;role=&amp;quot;combobox&amp;quot;&lt;/code&gt; on the input in every browser, as the docs
already described.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;data-effect=&amp;quot;stamp&amp;quot;&lt;/code&gt; is visible on dark surfaces.&lt;/strong&gt; It blended with
&lt;code&gt;multiply&lt;/code&gt; and dark ink, which nearly vanished on dark backgrounds. On
dark surfaces (nearest &lt;code&gt;data-mode=&amp;quot;dark&amp;quot;&lt;/code&gt;, or the system preference) it
now uses &lt;code&gt;screen&lt;/code&gt; with lighter ink; &lt;code&gt;--vb-stamp-blend&lt;/code&gt; overrides it for
custom stages.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v0.4.1</title>
    <id>https://vanilla-breeze.com/changelog/#v0-4-1</id>
    <link rel="alternate" type="text/html" href="https://vanilla-breeze.com/changelog/#v0-4-1"/>
    <updated>2026-10-31T00:00:00Z</updated>
    <published>2026-10-31T00:00:00Z</published>
    <content type="html">&lt;p&gt;Patch release: the package no longer drags in a runtime dependency, and the
npm listing gains an author and keywords.&lt;/p&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;No runtime dependencies.&lt;/strong&gt; &lt;code&gt;codex-claude-bridge&lt;/code&gt; (the Codex review
tooling) had sat in &lt;code&gt;dependencies&lt;/code&gt; since 0.1.3, so every install of
vanilla-breeze pulled 138 packages it never used. It is a devDependency
now and a unit gate keeps &lt;code&gt;dependencies&lt;/code&gt; empty.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v0.4.0</title>
    <id>https://vanilla-breeze.com/changelog/#v0-4-0</id>
    <link rel="alternate" type="text/html" href="https://vanilla-breeze.com/changelog/#v0-4-0"/>
    <updated>2026-10-31T00:00:00Z</updated>
    <published>2026-10-31T00:00:00Z</published>
    <content type="html">&lt;p&gt;First release since 0.3.1 and breaking in aggregate: themes self-declare the
&lt;code&gt;bundle-theme&lt;/code&gt; cascade layer and the charts add-on is layered, every layout
lives once as &lt;code&gt;:is(layout-x, [data-layout=&amp;quot;x&amp;quot;])&lt;/code&gt;, the size scale is spelled
&lt;code&gt;s/m/l&lt;/code&gt; everywhere with no aliases, 76 dead tokens are gone, and the tokens
layer holds custom properties only. Also in this release: generated and gated
api.json manifests for all 14 layouts, a vendored &lt;code&gt;marked&lt;/code&gt;, local placeholder
images, a page-pinned &lt;code&gt;data-theme&lt;/code&gt; that survives saved preferences, and the
effects runtime fix for scroll-triggered effects. Details below.&lt;/p&gt;
&lt;h3&gt;Changed (breaking)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The charts add-on is layered.&lt;/strong&gt; &lt;code&gt;vanilla-breeze-charts.css&lt;/code&gt; now lands in
&lt;code&gt;@layer web-components&lt;/code&gt; like any bundled component, below utils, themes
and your own CSS; it used to be unlayered and outranked everything. The
file carries the layer-order prefix so it is order-safe in &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;.
chart-wc&amp;#39;s hidden-table overrides lock the properties the
&lt;code&gt;.visually-hidden&lt;/code&gt; utility sets. Visible effect: an author rule such as
&lt;code&gt;.tall-spark { block-size: 120px }&lt;/code&gt; on a sparkline now applies.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;One scale spelling: &lt;code&gt;s&lt;/code&gt; / &lt;code&gt;m&lt;/code&gt; / &lt;code&gt;l&lt;/code&gt; everywhere&lt;/strong&gt; (j1hi). &lt;code&gt;--font-size-sm/md/lg&lt;/code&gt;
are now &lt;code&gt;--font-size-s/m/l&lt;/code&gt;, &lt;code&gt;--shadow-sm/md/lg&lt;/code&gt; are &lt;code&gt;--shadow-s/m/l&lt;/code&gt;, and
the breakpoint references &lt;code&gt;--bp-sm/md/lg&lt;/code&gt; are &lt;code&gt;--bp-s/m/l&lt;/code&gt;, matching
&lt;code&gt;--size-*&lt;/code&gt; and &lt;code&gt;--radius-*&lt;/code&gt;. No aliases: the two-letter names are gone.
Every usage in the framework, themes, packs, demos and docs was renamed
by codemod; downstream consumers rename the same three families.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;72 dead core tokens removed&lt;/strong&gt; (p0wn): the Open Props numeric aliases
(&lt;code&gt;--size-1..10&lt;/code&gt;, &lt;code&gt;--gray-0..9&lt;/code&gt;, &lt;code&gt;--radius-1..6&lt;/code&gt;, &lt;code&gt;--shadow-1/3..6&lt;/code&gt;,
&lt;code&gt;--font-size-00/2..8&lt;/code&gt;, &lt;code&gt;--ease-1/2/4/5&lt;/code&gt;), the unused easings
(&lt;code&gt;--ease-in-*&lt;/code&gt;, &lt;code&gt;--ease-out-*&lt;/code&gt;, &lt;code&gt;--ease-squish-*&lt;/code&gt;), the colour harmonics
(&lt;code&gt;--color-complement&lt;/code&gt;, &lt;code&gt;--color-triad-*&lt;/code&gt;, &lt;code&gt;--color-analog-*&lt;/code&gt;), the
surface gradient/texture tokens nothing rendered, &lt;code&gt;--cursor-grab/grabbing&lt;/code&gt;,
&lt;code&gt;--font-weight-light/range&lt;/code&gt;, &lt;code&gt;--filter-rough-heavy&lt;/code&gt;, &lt;code&gt;--opacity-60&lt;/code&gt;,
&lt;code&gt;--prose-font-size&lt;/code&gt;, &lt;code&gt;--page-bg-overlay&lt;/code&gt;, the animated-border duration
tokens, and &lt;code&gt;--color-secondary-active&lt;/code&gt; / &lt;code&gt;--color-accent-active&lt;/code&gt;. Nothing
in the framework, demos, docs, themes or packs read any of them. A gate
(&lt;code&gt;tests/unit/token-usage.test.js&lt;/code&gt;) rejects new unread tokens; 28 tokens
that themes set or the docs list but nothing reads are tracked there for
a wire-or-prune decision.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Layout attribute API made consistent&lt;/strong&gt; (vqw8):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One gap scale everywhere: &lt;code&gt;none&lt;/code&gt;, &lt;code&gt;3xs&lt;/code&gt; … &lt;code&gt;3xl&lt;/code&gt; on every gap-bearing
layout (cluster, grid, cover, sidebar, switcher, reel, split, media,
page-layout, body regions). Previously each layout accepted a random
subset.&lt;/li&gt;
&lt;li&gt;One sidebar width: &lt;code&gt;--sidebar-width&lt;/code&gt; defaults to &lt;code&gt;16rem&lt;/code&gt; and
&lt;code&gt;data-layout-sidebar-width&lt;/code&gt; is &lt;code&gt;12 / 16 / 20rem&lt;/code&gt; in every context
(layout-sidebar and page-layout &lt;code&gt;normal&lt;/code&gt; were 15rem, grid identity 280px,
the page templates 250px).&lt;/li&gt;
&lt;li&gt;One max-width keyword set: &lt;code&gt;narrow | normal | wide | prose&lt;/code&gt; on
layout-center, layout-card and canvas, mapped to &lt;code&gt;--content-*&lt;/code&gt; tokens.
&lt;code&gt;content&lt;/code&gt; is gone (card&amp;#39;s read a token that never existed; card &lt;code&gt;wide&lt;/code&gt;
was 90rem, now the shared 80rem).&lt;/li&gt;
&lt;li&gt;Prefix rule: flow primitives use &lt;code&gt;data-layout-*&lt;/code&gt;; surfaces use bare
&lt;code&gt;data-*&lt;/code&gt;. Canvas moves from &lt;code&gt;data-layout-max&lt;/code&gt; / &lt;code&gt;data-layout-padding&lt;/code&gt; to
&lt;code&gt;data-max&lt;/code&gt; / &lt;code&gt;data-padding&lt;/code&gt; to match card and badge.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;data-layout-min&lt;/code&gt; stays on both grid (column minimum) and cover (block
minimum), as the vocabulary spec already defines: the minimum on that
layout&amp;#39;s principal axis.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Layout element and attribute forms now share one rule set.&lt;/strong&gt; Eight
layouts existed twice, as &lt;code&gt;layout-x/styles.css&lt;/code&gt; and as a &lt;code&gt;[data-layout=&amp;quot;x&amp;quot;]&lt;/code&gt;
block in &lt;code&gt;layout-attributes.css&lt;/code&gt;, and the copies had drifted. Each now lives
once, selected via &lt;code&gt;:is(layout-x, [data-layout=&amp;quot;x&amp;quot;])&lt;/code&gt;. Where the forks
disagreed, the better behaviour wins on both sides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;layout-cover&lt;/code&gt; defaults to &lt;code&gt;100dvh&lt;/code&gt; (was &lt;code&gt;100vh&lt;/code&gt;) and auto-centers a sole
child; &lt;code&gt;layout-center&lt;/code&gt; honours the documented &lt;code&gt;data-layout-max=&amp;quot;prose&amp;quot;&lt;/code&gt;
(65ch; the element form silently fell back to &lt;code&gt;normal&lt;/code&gt;) and its
&lt;code&gt;[data-layout-gap]&lt;/code&gt; flex-collapse guard now fills the parent exactly
(the attribute form&amp;#39;s &lt;code&gt;inline-size: 100%&lt;/code&gt; overflowed by the padding);
&lt;code&gt;layout-cluster&lt;/code&gt; accepts &lt;code&gt;data-layout-gap=&amp;quot;none&amp;quot;&lt;/code&gt;
and &lt;code&gt;&amp;quot;2xl&amp;quot;&lt;/code&gt;; &lt;code&gt;layout-sidebar&lt;/code&gt; is now semantic-aware like the attribute
form (&lt;code&gt;nav&lt;/code&gt;/&lt;code&gt;aside&lt;/code&gt; are the sidebar, &lt;code&gt;data-layout-side=&amp;quot;end&amp;quot;&lt;/code&gt; keeps DOM
order via &lt;code&gt;order&lt;/code&gt;; position-based fallback when no &lt;code&gt;nav&lt;/code&gt;/&lt;code&gt;aside&lt;/code&gt; child);
the attribute forms lose their blanket container-query fallbacks
(&lt;code&gt;grid&lt;/code&gt; to one column under 400px, &lt;code&gt;switcher&lt;/code&gt; stacking under 30rem):
auto-fit and the threshold formula already do that job, and the
fallbacks overrode &lt;code&gt;data-layout-min=&amp;quot;xs|s&amp;quot;&lt;/code&gt; and
&lt;code&gt;data-layout-threshold=&amp;quot;s&amp;quot;&lt;/code&gt; inside any section on a phone.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Typographic containers share one core&lt;/strong&gt; (&lt;code&gt;layout-text/styles.css&lt;/code&gt;):
&lt;code&gt;layout-text&lt;/code&gt;, &lt;code&gt;layout-columns&lt;/code&gt;, &lt;code&gt;[data-layout=&amp;quot;columns&amp;quot;]&lt;/code&gt; and
&lt;code&gt;[data-layout=&amp;quot;prose&amp;quot;]&lt;/code&gt; all get the same measure variants
(&lt;code&gt;data-layout-measure&lt;/code&gt; or &lt;code&gt;data-layout-max&lt;/code&gt;: narrow/normal/wide, mapped
to &lt;code&gt;--measure-*&lt;/code&gt;), vertical rhythm, &lt;code&gt;data-layout-centered&lt;/code&gt;, the
&lt;code&gt;[data-bleed]&lt;/code&gt; breakout and the narrow-container width release. Notable
shifts: &lt;code&gt;data-layout=&amp;quot;prose&amp;quot;&lt;/code&gt; gains rhythm; &lt;code&gt;layout-columns&lt;/code&gt; line-height
moves from &lt;code&gt;--line-height-relaxed&lt;/code&gt; (1.625) to &lt;code&gt;--prose-line-height&lt;/code&gt;
(1.6); &lt;code&gt;article[data-measure=&amp;quot;narrow&amp;quot;]&lt;/code&gt; is &lt;code&gt;--measure-narrow&lt;/code&gt; (45ch),
was 55ch.&lt;/li&gt;
&lt;li&gt;Selector specificity for the element forms rises from (0,0,1) to
(0,1,0), matching the attribute forms. Author rules that relied on
out-specifying &lt;code&gt;layout-x {}&lt;/code&gt; with a bare element selector will need the
attribute form&amp;#39;s specificity; layered author CSS is unaffected.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Themes now live in the &lt;code&gt;bundle-theme&lt;/code&gt; cascade layer.&lt;/strong&gt; Every file in
&lt;code&gt;src/tokens/themes/&lt;/code&gt; wraps its rules in &lt;code&gt;@layer bundle-theme { }&lt;/code&gt;, and the
entries import the bundled themes directly instead of through the tokens
barrel. Before, the bundled themes sat in the lowest layer (&lt;code&gt;tokens&lt;/code&gt;) and
the standalone CDN theme files were unlayered, so a linked theme beat every
framework layer, packs included, and beat your own unlayered CSS.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;What changes for you:&lt;/strong&gt; unlayered author CSS now overrides theme rules,
as it already did for every other part of the framework. Packs
(&lt;code&gt;bundle-effects&lt;/code&gt;, &lt;code&gt;bundle-components&lt;/code&gt;) now sit above themes as
documented. A theme&amp;#39;s element rules now beat &lt;code&gt;native-elements&lt;/code&gt; without
&lt;code&gt;!important&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;The CDN build prefixes each standalone theme file with the layer-order
statement from &lt;code&gt;main.css&lt;/code&gt;, so a theme &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; placed before the bundle
still slots in correctly.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_access-dyslexia&lt;/code&gt; dropped its three &lt;code&gt;!important&lt;/code&gt; declarations; the layer
now does that job.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;api.json manifests for all 14 layout elements&lt;/strong&gt;, generated from and
gated against the CSS (&lt;code&gt;tests/unit/layout-manifests.test.js&lt;/code&gt;). The
html-validate registry previously carried layout manifests with attribute
names the CSS never read (&lt;code&gt;data-gap&lt;/code&gt; for &lt;code&gt;data-layout-gap&lt;/code&gt;), so it now
validates the real layout API — which immediately caught &lt;code&gt;layout-imposter&lt;/code&gt;
demos using &lt;code&gt;data-position&lt;/code&gt; / &lt;code&gt;data-margin&lt;/code&gt; (the CSS reads
&lt;code&gt;data-layout-position&lt;/code&gt; / &lt;code&gt;data-layout-margin&lt;/code&gt;; 42 sites migrated) and two
badges using &lt;code&gt;data-variant&lt;/code&gt; for a color. Every layout element&amp;#39;s doc page
attribute table is regenerated from its manifest.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Two dead &lt;code&gt;exports&lt;/code&gt; entries removed.&lt;/strong&gt; &lt;code&gt;vanilla-breeze/ux-planning-css&lt;/code&gt;
and &lt;code&gt;vanilla-breeze/ux-planning-js&lt;/code&gt; pointed at pack files the Workstream D
removal deleted before 0.3.1 shipped, so importing them failed to resolve.
A unit gate now checks that every &lt;code&gt;exports&lt;/code&gt; target exists in &lt;code&gt;dist/&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;markdown-viewer and markdown-editor are in the full barrel; &lt;code&gt;marked&lt;/code&gt; is
vendored&lt;/strong&gt; (kdkb). Both imported &lt;code&gt;marked&lt;/code&gt; by bare specifier, which esbuild
resolves but a browser cannot, so they were kept out of
&lt;code&gt;src/web-components/index.js&lt;/code&gt; (one unresolvable import kills the whole raw
&lt;code&gt;/src/main.js&lt;/code&gt; graph in dev). &lt;code&gt;marked&lt;/code&gt; now lives in &lt;code&gt;src/vendor/marked/&lt;/code&gt;
as a verbatim copy of the installed package, imported by relative path;
&lt;code&gt;npm run vendor:marked&lt;/code&gt; refreshes it and a unit gate fails on drift. The
eleven demos that carried an esm.sh import map for &lt;code&gt;marked&lt;/code&gt; no longer hit
the network, and the barrel parity test has no exemptions left.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scroll-triggered effects and self-wrapping effects work again on every
page&lt;/strong&gt; (t5r2). Since the effects runtime began booting its own observer
(6xxy), it processed elements while &lt;code&gt;vb.js&lt;/code&gt; evaluated — before
&lt;code&gt;vb-triggers.js&lt;/code&gt; and the effect modules had registered. Every
&lt;code&gt;data-trigger=&amp;quot;scroll&amp;quot;&lt;/code&gt; element sat at opacity 0 forever (the slide-in
demo, the effects kitchen-sink hero), and &lt;code&gt;animate-image&lt;/code&gt; lost its
play/pause control because the observer treated the effect wrapping its
own image as a removal and unwrapped it. &lt;code&gt;VB.trigger()&lt;/code&gt; now wires
already-processed elements, &lt;code&gt;VB.effect()&lt;/code&gt; activates an element that
activated before the effect existed, and a node that is still connected
after a mutation batch is a move, not a removal.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A page-pinned &lt;code&gt;&amp;lt;html data-theme&amp;gt;&lt;/code&gt; is now that page&amp;#39;s default&lt;/strong&gt; (psme).
ThemeManager used to replace it on load in two cases: any saved
preference, even a light/dark toggle or a &lt;code&gt;default&lt;/code&gt; picked on another
page of the same origin, resolved the brand to &lt;code&gt;default&lt;/code&gt;; and a brand VB
has no CSS file for (a site&amp;#39;s own theme) failed to load and was reset to
&lt;code&gt;default&lt;/code&gt; on every first visit. Now only a saved preference naming a
different, explicit brand replaces the pin, a pinned brand that fails to
load is kept (the page supplies its CSS), cross-document sync applies the
same precedence, and &lt;code&gt;reset()&lt;/code&gt; returns to the pin.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Demos and docs no longer hot-link picsum.photos&lt;/strong&gt; (uz4f). 145 image
references across 27 demos, 5 docs pages and image-gallery&amp;#39;s static
example pointed at picsum, so every page load fetched random third-party
photos and screenshots were never reproducible. They now use deterministic
local SVG placeholders under &lt;code&gt;src/assets/placeholders/&lt;/code&gt;, generated from a
manifest by &lt;code&gt;scripts/generate-placeholders.mjs&lt;/code&gt; and served at the same
&lt;code&gt;/src/assets/…&lt;/code&gt; path in dev and on the built site. The visual suite&amp;#39;s
picsum interception shim is gone. &lt;code&gt;data-mock=&amp;quot;photo&amp;quot;&lt;/code&gt; and
&lt;code&gt;mock.imageUrl()&lt;/code&gt; still name picsum as their documented opt-in service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;30 media containers in demos and docs used &lt;code&gt;data-layout-ratio&lt;/code&gt; on
&lt;code&gt;[data-media]&lt;/code&gt;, which reads &lt;code&gt;data-ratio&lt;/code&gt;; the aspect ratio never applied.
Found by the per-layout conformance check below.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The tokens layer holds custom properties only&lt;/strong&gt; (dtw6). Backdrop&amp;#39;s
application rules (body padding, region elevation, chrome modes, the
mobile flush breakpoint), the &lt;code&gt;[data-scrollbar]&lt;/code&gt;, &lt;code&gt;[data-border-style]&lt;/code&gt;
and &lt;code&gt;[data-spotlight]&lt;/code&gt; rules, the OpenType utility classes and the
external-component token bridge all lived in &lt;code&gt;@layer tokens&lt;/code&gt; — the lowest
layer — where any component rule beat them. They now live in
&lt;code&gt;src/utils/&lt;/code&gt; in &lt;code&gt;@layer utils&lt;/code&gt;; their custom properties stay in
&lt;code&gt;src/tokens/&lt;/code&gt;. Visible effect: with &lt;code&gt;data-backdrop&lt;/code&gt;, regions are centered
to the canvas width and separated by the canvas gap as documented. A gate
in bundle-parity keeps selector rules out of the tokens graph
(&lt;code&gt;color-scheme&lt;/code&gt;, &lt;code&gt;interpolate-size&lt;/code&gt; and the root token transition are the
documented exceptions).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Theme cursors now apply to every control&lt;/strong&gt; (vjpn). The reset wires
&lt;code&gt;cursor: var(--cursor-custom-pointer)&lt;/code&gt; so a theme can ship its own
pointer, but 169 component rules hardcoded &lt;code&gt;cursor: pointer&lt;/code&gt; in higher
layers, so the theme cursor only ever reached bare links. Every one now
reads &lt;code&gt;var(--cursor-custom-pointer, pointer)&lt;/code&gt;; a gate keeps it that way.
Also: backdrop&amp;#39;s mobile breakpoint moves from 640px to the contract&amp;#39;s
&lt;code&gt;--bp-sm&lt;/code&gt; (37.5rem / 600px), and heading weights use the
&lt;code&gt;--font-weight-*&lt;/code&gt; tokens.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Effects activate on elements added after load on core-only pages&lt;/strong&gt;
(6xxy). &lt;code&gt;VB.observe()&lt;/code&gt; was only called from the full and autoload entries;
the production docs load the core entry, so a &lt;code&gt;data-effect&lt;/code&gt; element
inserted later never activated. The runtime now boots its own observer
once the DOM is ready, and is one instance per document, so a page that
loads both extras and the effects pack (five shared effect modules) no
longer gets two registries and two observers.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Removed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;data-layout=&amp;quot;body-*&amp;quot;&lt;/code&gt; page templates&lt;/strong&gt; (tfcw). They were a
line-for-line legacy copy of &lt;code&gt;data-page-layout&lt;/code&gt; and used by one demo;
use &lt;code&gt;data-page-layout=&amp;quot;stack | sidebar-left | sidebar-right | holy-grail | app-shell | dashboard | article | landing&amp;quot;&lt;/code&gt;. The page regions keep their
named containers (&lt;code&gt;region-main&lt;/code&gt; / &lt;code&gt;region-nav&lt;/code&gt; / &lt;code&gt;region-aside&lt;/code&gt;) under
&lt;code&gt;data-page-layout&lt;/code&gt;. The dormant &lt;code&gt;main[data-layout] &amp;gt; *&lt;/code&gt; and
&lt;code&gt;article[data-layout] &amp;gt; *&lt;/code&gt; grid-area rules, which fired for every
layout value and named areas no template defined, are scoped to the
&lt;code&gt;main[data-layout=&amp;quot;sidebar-*&amp;quot;]&lt;/code&gt; templates that use them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;layout-cover&lt;/code&gt;&amp;#39;s &lt;code&gt;data-hero-overlay&lt;/code&gt; and &lt;code&gt;data-layout-nospace&lt;/code&gt; (zero
usages; &lt;code&gt;data-layout-padding=&amp;quot;none&amp;quot;&lt;/code&gt; is the latter). &lt;code&gt;src/charts/index.css&lt;/code&gt;
and &lt;code&gt;markdown-viewer/vb-extensions.js&lt;/code&gt;, both imported by nothing (822u).&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Internal&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The demos visual suite pins the clock to 2026-07-06 so calendars and
anything rendering &amp;quot;today&amp;quot; stop drifting from their baselines monthly.
17 stale desktop baselines triaged: 3 were the regressions above (they
match their July baselines again), 1 was the clock, 13 are intended drift
(16rem sidebar, the s/m/l rename making demo-CSS token references
resolve, the border-style system reaching &lt;code&gt;form&lt;/code&gt;, the 120px sparkline,
the sidebar merge, semantic-HTML rewrites) and were refreshed. The mobile
project, not run since July, had 12 stale baselines of the same kinds
(mostly horizontal overflow that no longer happens); refreshed. Two demos
join the skip list: &lt;code&gt;effects-kitchen-sink&lt;/code&gt; (live scramble effect, never
stable) and &lt;code&gt;markdown-viewer-mermaid&lt;/code&gt; (loads Mermaid and D3 from esm.sh
at runtime).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Per-theme visual regression is back&lt;/strong&gt; (iwuq): &lt;code&gt;tests/visual/theme-surfaces.spec.js&lt;/code&gt;
screenshots a purpose-built surfaces page (&lt;code&gt;demos/examples/demos/theme-surfaces.html&lt;/code&gt;:
typography, actions, forms, cards, table, details) under all 48 CDN
themes plus the bundled seven, in light and dark, and the form-validation
demo per theme — replacing the theme-lab coverage lost in the pack
decomposition. Desktop only.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The CI quality gate now runs &lt;code&gt;validate:api&lt;/code&gt; and &lt;code&gt;check:api-drift&lt;/code&gt;; the
registry that lint:html validates against is generated from the manifests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Width media queries in &lt;code&gt;src/&lt;/code&gt; use the breakpoint contract (&lt;code&gt;--bp-s/l&lt;/code&gt;)
and a gate rejects px widths (s3hy). Four documented-but-wired-to-nothing
extension tokens removed: &lt;code&gt;--motion-hover-glow&lt;/code&gt;, &lt;code&gt;--border-roughness&lt;/code&gt;,
&lt;code&gt;--gradient-subtle&lt;/code&gt;, &lt;code&gt;--page-bg-type&lt;/code&gt; (z1im); the remaining unread tokens
are categorised in the token gate, and the seed-derived state colours
themes override but components never read are tracked as o4tj.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The native-elements layer contract now admits element-scoped semantic
modifier classes (&lt;code&gt;p.lead&lt;/code&gt;, &lt;code&gt;section.hero&lt;/code&gt;, &lt;code&gt;article.card&lt;/code&gt;) and classes
the framework&amp;#39;s own init modules write, instead of claiming &amp;quot;no classes&amp;quot;
while defining 147 of them (hl9c). Seven classes nothing used were
removed (&lt;code&gt;.hn-action-remove&lt;/code&gt;, &lt;code&gt;.hn-swatch&lt;/code&gt;, &lt;code&gt;fieldset.code-inputs&lt;/code&gt;,
&lt;code&gt;img.ratio-landscape&lt;/code&gt;, &lt;code&gt;.changelog-year/-month&lt;/code&gt;, &lt;code&gt;video.ultrawide&lt;/code&gt;); the
hex fallbacks inside &lt;code&gt;var()&lt;/code&gt; and the Tailwind-palette highlight colours
are gone (tokens are always loaded; the highlight colours are oklch); a
gate (&lt;code&gt;tests/unit/native-element-classes.test.js&lt;/code&gt;) rejects dead classes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;youtube-player and social-embed no longer wrap themselves in
&lt;code&gt;@layer web-components&lt;/code&gt; (the entry owns the layer; they nested as
&lt;code&gt;web-components.web-components&lt;/code&gt;) (7371).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Per-component autoload chunks stay self-contained: code splitting was
measured (1.3 MB → 775 KB raw across all chunks) and rejected because a
single component file is a documented cherry-pick contract (6xxy).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The web-components CSS barrels are pure import manifests&lt;/strong&gt; (jhku).
&lt;code&gt;index.css&lt;/code&gt; and &lt;code&gt;core.css&lt;/code&gt; carried 1477 and 650 lines of inline rules,
hand-copied between them; 96 of core&amp;#39;s 103 rules were verbatim copies and
the rest had drifted (core&amp;#39;s &lt;code&gt;data-copy&lt;/code&gt; selector still named components
moved to packs in 0.3.0; its gradient-text and shimmer rules predated the
composable animation slots). The rules live once under
&lt;code&gt;src/web-components/_shared/&lt;/code&gt; (data utilities, form enhancements, effects,
math) and geo-map&amp;#39;s no-JS fallback in &lt;code&gt;geo-map/styles.css&lt;/code&gt;; core imports
the core subset. Core therefore adopts the slot design for gradient-text
and shimmer, and both bundles now clear those effects&amp;#39; decoration slot
under reduced motion (only core did before). A gate rejects inline rules
in either barrel.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stale headers corrected: the core and extras JS barrels state their real
counts (29 + 27 and 29 + 9 modules); &lt;code&gt;pointer.css&lt;/code&gt; no longer re-sets
&lt;code&gt;--size-touch-min&lt;/code&gt; under &lt;code&gt;(pointer: coarse)&lt;/code&gt; to the value sizing.css
already sets; the CDN build comment no longer claims the slim bundle has
no themes (822u).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;layout-attributes.css&lt;/code&gt; is layout again (tfcw, 1294 → 760 lines):
density modes moved to &lt;code&gt;src/utils/density.css&lt;/code&gt;, the scroll-driven header
shrink / &lt;code&gt;data-animate&lt;/code&gt; reveals / &lt;code&gt;data-parallax&lt;/code&gt; to
&lt;code&gt;src/utils/scroll-driven.css&lt;/code&gt;, and the canvas surface into
&lt;code&gt;layout-canvas/styles.css&lt;/code&gt;. &lt;code&gt;&amp;lt;layout-badge&amp;gt;&lt;/code&gt; keeps its tag; it is
documented as a surface element rather than a layout primitive.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;vb/layout-attr-value&lt;/code&gt; now validates each &lt;code&gt;data-layout-*&lt;/code&gt; value against
the vocabulary of the element&amp;#39;s own layout (resolved from &lt;code&gt;&amp;lt;layout-x&amp;gt;&lt;/code&gt;,
&lt;code&gt;data-layout=&amp;quot;x&amp;quot;&lt;/code&gt; or &lt;code&gt;data-page-layout&lt;/code&gt;), instead of the union across all
layouts — &lt;code&gt;data-layout-min=&amp;quot;auto&amp;quot;&lt;/code&gt; on a grid is now caught. Child
attributes and elements naming no layout fall back to the merged check.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conformance guards that tested a whole line now judge the tag they
examine: a styled element sharing a line with a &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;, a state class
beside an &lt;code&gt;&amp;lt;output&amp;gt;&lt;/code&gt;, or a second &lt;code&gt;&amp;lt;svg&amp;gt;&lt;/code&gt; on a line are no longer exempt.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;check:api-drift&lt;/code&gt; no longer claims tab-set manages &lt;code&gt;aria-selected&lt;/code&gt;; it
manages &lt;code&gt;aria-expanded&lt;/code&gt; on its summaries by design.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;context-menu&lt;/code&gt; and &lt;code&gt;drop-down&lt;/code&gt; reset themed button styling on their items
through their own stylesheets (&lt;code&gt;!important&lt;/code&gt; in the component layer) instead
of inline styles written by JavaScript. The nav active-item &lt;code&gt;!important&lt;/code&gt;
rules stay, with their rationale corrected: themes sit above
&lt;code&gt;native-elements&lt;/code&gt; by contract and most of them color bare links.
&lt;code&gt;_extreme-neumorphism&lt;/code&gt; dropped an unneeded &lt;code&gt;!important&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v0.3.1</title>
    <id>https://vanilla-breeze.com/changelog/#v0-3-1</id>
    <link rel="alternate" type="text/html" href="https://vanilla-breeze.com/changelog/#v0-3-1"/>
    <updated>2026-07-07T00:00:00Z</updated>
    <published>2026-07-07T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Removed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Purged stale build artifacts left over from the 0.3.0 decomposition: the
&lt;code&gt;design-system&lt;/code&gt; + &lt;code&gt;ux-planning&lt;/code&gt; pack bundles (&lt;code&gt;dist/cdn/packs/*&lt;/code&gt;) and the
individual component bundles for the 36 removed components
(&lt;code&gt;dist/cdn/components/*&lt;/code&gt;). No &lt;code&gt;package.json&lt;/code&gt; export referenced them — this
just trims dead weight from the published tarball.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v0.3.0</title>
    <id>https://vanilla-breeze.com/changelog/#v0-3-0</id>
    <link rel="alternate" type="text/html" href="https://vanilla-breeze.com/changelog/#v0-3-0"/>
    <updated>2026-07-06T00:00:00Z</updated>
    <published>2026-07-06T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Changed (breaking)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Decomposed the design-system and project-planning packs out of core.&lt;/strong&gt; These 36 components now ship as standalone, token-driven packages and were removed from &lt;code&gt;vanilla-breeze&lt;/code&gt;:&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Design system → &lt;a href=&quot;https://www.npmjs.com/package/@profpowell/vb-design-system&quot;&gt;&lt;code&gt;@profpowell/vb-design-system&lt;/code&gt;&lt;/a&gt;:&lt;/strong&gt; accessibility-, breakpoint-, layout-, motion-, spacing-, token-, and type-specimen; color-palette, component-sampler, font-pairer, gradient-builder, palette-generator, semantic-palette; theme-catalog, theme-export, theme-import. (The pack also adds new components with no core equivalent: brand-specimen, icon-set, icon-specimen.)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Project planning → &lt;a href=&quot;https://www.npmjs.com/package/@profpowell/vb-project-planning&quot;&gt;&lt;code&gt;@profpowell/vb-project-planning&lt;/code&gt;&lt;/a&gt;:&lt;/strong&gt; adr-wc, burndown-chart, capacity-plan, empathy-map, gantt-chart, impact-effort, iron-triangle, kanban-board, product-roadmap, quadrant-grid, quality-target, requirement-card, review-surface, risk-register, story-map, traceability-matrix, user-journey, user-persona, user-story, work-item.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Migration:&lt;/strong&gt; &lt;code&gt;npm i @profpowell/vb-design-system&lt;/code&gt; and/or &lt;code&gt;@profpowell/vb-project-planning&lt;/code&gt;. Both read VB design tokens and adopt the active theme automatically — load them on any page that also loads &lt;code&gt;vanilla-breeze&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Core primitives the packs build on — &lt;code&gt;icon-wc&lt;/code&gt;, &lt;code&gt;brand-mark&lt;/code&gt;, &lt;code&gt;color-picker&lt;/code&gt;, &lt;code&gt;drag-surface&lt;/code&gt;, &lt;code&gt;chart-wc&lt;/code&gt; — &lt;strong&gt;remain in core.&lt;/strong&gt; The new terse &lt;code&gt;[data-icon]&lt;/code&gt; primitive (0.2.0) also stays.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Internal&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Relocated the DTCG serialize/deserialize/parse modules to &lt;code&gt;src/lib/dtcg/&lt;/code&gt; and the public token-set catalog to &lt;code&gt;src/data/theme-catalog/&lt;/code&gt; (they back the core theme/CDN build and were previously co-located with the now-removed theme components).&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v0.2.0</title>
    <id>https://vanilla-breeze.com/changelog/#v0-2-0</id>
    <link rel="alternate" type="text/html" href="https://vanilla-breeze.com/changelog/#v0-2-0"/>
    <updated>2026-07-02T00:00:00Z</updated>
    <published>2026-07-02T00:00:00Z</published>
    <content type="html">&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;[data-icon]&lt;/code&gt; icon primitive&lt;/strong&gt; — a terse, native way to place a single monochrome icon (&lt;code&gt;&amp;lt;i data-icon=&amp;quot;star&amp;quot;&amp;gt;&lt;/code&gt;, or on any element) via a CSS &lt;code&gt;mask&lt;/code&gt; &lt;code&gt;::before&lt;/code&gt; plus a tiny core-loaded enhancer, alongside &lt;code&gt;&amp;lt;icon-wc&amp;gt;&lt;/code&gt;. Ships build-generated per-set no-JS stylesheets and name manifests at &lt;code&gt;/cdn/icons/&amp;lt;set&amp;gt;.css&lt;/code&gt; and &lt;code&gt;/cdn/icons/&amp;lt;set&amp;gt;.json&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Fixed&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Site header layout shift&lt;/strong&gt; — the site header now reserves its height (&lt;code&gt;header.site&lt;/code&gt;), so it no longer grows and pushes the page down as chrome components upgrade on first (uncached) load.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;List flow-spacing in flex/grid layouts&lt;/strong&gt; — &lt;code&gt;li&lt;/code&gt; spacing no longer misfires as a cross-axis offset in flex-row or grid lists. The base &lt;code&gt;li + li&lt;/code&gt; rule is now an overridable &lt;code&gt;:where()&lt;/code&gt; default, and every &lt;code&gt;[data-layout]&lt;/code&gt; list (which spaces with &lt;code&gt;gap&lt;/code&gt;) resets it.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  <entry>
    <title>v0.1.0</title>
    <id>https://vanilla-breeze.com/changelog/#v0-1-0</id>
    <link rel="alternate" type="text/html" href="https://vanilla-breeze.com/changelog/#v0-1-0"/>
    <updated>2025-01-01T00:00:00Z</updated>
    <published>2025-01-01T00:00:00Z</published>
    <content type="html">&lt;p&gt;Initial public release.&lt;/p&gt;
&lt;h3&gt;Added&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Tokens&lt;/strong&gt; — design tokens for spacing, typography, colors, sizing, borders, shadows, motion, and fluid scaling&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Native element styles&lt;/strong&gt; — layered CSS for &lt;code&gt;&amp;lt;nav&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;aside&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;main&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;dialog&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;details&amp;gt;&lt;/code&gt;, and more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Layout system&lt;/strong&gt; — &lt;code&gt;data-layout&lt;/code&gt; attributes (stack, cluster, sidebar, grid) plus &lt;code&gt;data-page-layout&lt;/code&gt; presets&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;30+ web components&lt;/strong&gt; — accordion, carousel, tabs, toast, tooltip, data-table, command-palette, combo-box, drag-surface, emoji-picker, geo-map, and more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Theme engine&lt;/strong&gt; — 10 brand themes, 18 extreme themes, 4 accessibility themes, dark/light mode&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Accessibility&lt;/strong&gt; — ARIA mapping, reduced-motion support, high-contrast themes, dyslexia-friendly mode&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Utilities&lt;/strong&gt; — copy-to-clipboard, hotkeys, format-number, format-date, spoiler, typewriter, and more&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;i18n&lt;/strong&gt; — CSS layer and JS locale utilities&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Doc site&lt;/strong&gt; — Eleventy-powered documentation with interactive demos and examples&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
</feed>
