Skip to content

Toolkit changes

This record describes public toolkit changes and consumer migrations. The package manifest owns the current version. Entries describe source changes, not proof of publication or deployment.

010.4.0

Compatible additions, breaking renames and removals, and changed visual defaults; each breaking change states its migration. Not published by this change.

Components

  • Analytics measures page views and declared events with the shared Umami instance, from the configuration the host serves at /analytics-config.json. Statistics are on by default: its privacy dialog, in the Page language, turns them off and on again, and Do Not Track and Global Privacy Control always turn them off. Every app shares one Umami website: the path starts with the domain, /404 stands for missing pages, and the domain is also the distinct ID, so visitor identifiers stay specific to each site; the first measurement adds the origin of an external referrer. track(name) sends one of the names passed to events. Every workspace app mounts it in its root layout and serves the configuration from its Caddyfile; Bloom's own opt-in measurement is removed. Migration: Bloom drops UMAMI_ENABLED. Workspace Caddyfiles default to the shared distributed·gallery website, formerly Bloom's; UMAMI_ENDPOINT and UMAMI_WEBSITE_ID override it, and an empty website ID turns statistics off.
  • Footer shows the privacy and statistics control after its notice once Analytics has loaded its configuration. The notice and the control wrap as two units in a row; without Analytics, the footer is unchanged.
  • Dialog opens a native modal as a centered panel, a start or end drawer, a full-screen framed sheet or a transparent full-screen media view, with a titled bar, a close button, a blurred backdrop, scroll locking and focus return. open() and close() control it. The media placement hides its title visually, floats the close button in a framed box and closes on a press beside its content; the site's image lightbox uses it. --dialog-width overrides the preferred width of the panel and drawers, and an overflowing body becomes a focusable scrolling region. Bloom's reference reader and drawer use it.
  • Header builds its narrow-screen menu on Dialog. Its appearance, keyboard behavior and focus handling are unchanged; the menu bar title is now the dialog's heading. It accepts an actions snippet for compact controls, placed before the theme switch and kept in the bar beside the menu button below --medium; IconButton adds a search icon for them. The DS opens its search from there.
  • Heading. Accepts num, an optional section number shown before the title in SectionHead's numbering style. The editorial offset above the title is --space-8 instead of --space-7. Migration: pass padding="var(--space-7) var(--layout-padding-inline) var(--layout-padding-block)" to keep the former inset. Workspace apps adopt the new default.
  • Section draws crosses at all four corners by default (crosses="both" instead of "bottom"); Heading and ErrorPage inherit it. At a junction, the new top crosses coincide with the preceding frame's bottom crosses. Migration: pass crosses="bottom" to keep the former corners. Workspace apps adopt the new default. Its inset preset is renamed layout instead of default, so the name states the applied tokens. Migration: replace padding="default" with padding="layout", or omit the prop; workspace apps never pass it. gap accepts the presets layout (default), content, control and none, like padding; custom CSS gap expressions still apply unchanged. Workspace apps, Heading and ErrorPage pass gap="none" instead of gap="0".
  • ChatMessage sets the body role on its message body instead of on every paragraph inside it, and only its plain-text paragraph keeps line breaks. Paragraphs in children no longer lose their margins or collapse their whitespace, so .formatted content applies unchanged. Migration: pass plain text through text, or set white-space: pre-wrap on the element that holds it in children. Bloom renders user messages through text and drops its paragraph overrides.
  • SectionHead accepts padding: none by default, or layout for the shared inset when the head sits in a Section padding="none" with full-width content, so the head stays inside the section it names.
  • Button. The default subtle variant drops its visible border and marks its four corners with accent half-crosses, drawn like the focus marks of text fields; hover replaces them with the inverted fill. Keyboard focus keeps the outer outline, and forced-colors mode shows a system border. solid and accent are unchanged. Migration: restore border-color: var(--border-prominent) and background-image: none on .button in app styles to keep the former look. Workspace apps adopt the new default.
  • Grid. Card cells of a divided Grid take the layout inset (--layout-padding-*) instead of the content inset, so a grid of cards aligns with the shell gutter. Migration: compose divided grids in Section padding="none" gap="none" so their dividers reach the frame; give custom cells the layout inset. Workspace apps are migrated.
  • Cards. minWidth takes a CSS length instead of a pixel number; the default is "17.5rem" (280px at a 16px root). Migration: replace minWidth={240} with minWidth="15rem" or another CSS length. Workspace apps are migrated.
  • Page margins come from the spacing scale: --space-7 (48px instead of 44px) above --narrow and --space-4 (16px, unchanged) below. Its default width is "100rem" instead of "1600px": the same 1600px at a 16px root, but it now follows a larger text size together with the breakpoints. Migration: pass width="1600px" to keep a fixed pixel maximum. A direct aside now becomes a sidebar: Page places it in a start column of 14 to 18rem beside the content, between Header and Footer, and stacks it above the content below --medium. Compositions without an aside are unchanged. The DS catalogue uses it instead of a local grid wrapper.
  • Role alignment. Components use the shared role tokens instead of local values: Card, Heading, ErrorPage and the narrow-screen menu titles take --heading-line-height and --heading-letter-spacing; Card content and ChatMessage take --body-line-height; Quote takes the prose line height and tracking; section numbers take the interface or metadata weight. ChatComposer's hint uses .feedback, the ChatWindow badge the metadata size, and its launcher and suggestions the interface tracking. ChatWindow fullscreen locks scrolling on the root element, like Dialog. IconButton adds previous and next icons, which Cards uses for its scrolling controls. Migration: restore local values in app styles where the former rhythm mattered.

Typography

  • Strong emphasis. --strong-font-weight (400) is one emphasis weight shared by every strong, b, th and dt, inside or outside .formatted, above every role and keeping the family, size and color of its context. Table headers and definition terms were set apart by color only, at the surrounding weight, and .formatted th cancelled the native bold; a th outside .formatted took the browser's bold (700), and strong and b the browser's relative bolder. A role class on the element itself, such as <th class="ui">, sets that role's weight instead; set the role on an ancestor to keep the emphasis, as thead does with the interface role. Migration: set font-weight: inherit on th and dt in app styles to keep the former weight. www drops its local weight on press sources.
  • Type scale. --font-size-base defaults to 0.95rem instead of 1rem. At a 16px root, body text is 15.2px, interface text 11.4px and metadata 10.45px; headings scale in proportion and spacing is unchanged. Migration: set --font-size-base: 1rem on :root to keep the former sizes.
  • Type scale steps. --font-size-sm, --font-size-md and --font-size-lg are removed: --font-size-base is the only shared length, and each role derives its own factor from it. Migration: replace var(--font-size-sm) with calc(var(--font-size-base) * 0.6875), var(--font-size-md) with calc(var(--font-size-base) * 0.75) and var(--font-size-lg) with var(--font-size-base). Workspace apps never used them.
  • Code role. .code sets code blocks and literal data, such as token names and values, in monospace at --code-font-size (0.85 × the base, 12.92px at a 16px root, between interface and body text) with its own weight, line height and slightly tightened tracking (-0.05em), keeping the source casing even inside .ui or .metadata. --code-font-size, --code-font-weight, --code-line-height and --code-letter-spacing define it, and .formatted code blocks now use it instead of the surrounding text size. Migration: set font-size: inherit on .formatted pre in app styles to keep the former code block size.
  • Inline code. Every code element takes the code role's family, weight (200) and tracking (-0.05em), with the surrounding text size and line-height: 1; code inside pre keeps the block line height. Outside .formatted, code formerly used the browser's generic monospace and the inherited weight; inside, the inherited weight without tracking. Migration: set font-weight: inherit and letter-spacing: normal on code in app styles to keep the former weight and tracking. Workspace apps adopt the new default.
  • Preformatted text and literals. pre takes the complete code role everywhere, as .formatted pre already did, and kbd and samp follow inline code. They formerly used the browser's generic monospace, which reduces the size to about 13/16 of the surrounding text. All four are upright and keep their source casing, so code inside italic text or a .ui or .metadata parent is no longer slanted or uppercased. Every pre scrolls long lines inside the block instead of overflowing its container; .formatted pre keeps only its surface and padding, and the 0.85em reduction of .prose applies to inline code, kbd and samp but not inside pre, and only once: the keys of a nested kbd combination inherit it instead of shrinking again. Migration: set font-family: monospace on pre, kbd or samp in app styles to keep the browser default, or font-style: inherit and text-transform: inherit to let literals follow their context. Workspace apps use pre only inside .formatted or with .code, so their rendering is unchanged.
  • Formatted content. The .prose class is renamed .formatted. .constrained-width works on any element instead of only beside .formatted, filling the available width up to the measure, and --prose-max-width is renamed --reading-max-width. Inline code takes the surrounding text size instead of 0.9em, since Roboto Mono shares Roboto's glyph heights, and sets line-height: 1 so lines containing it keep the body rhythm. Migration: replace the class and token names; set font-size: 0.9em on .formatted code in app styles to keep the former code size. Workspace apps and svx-deck are migrated.
  • Prose role. .prose now sets continuous authored writing in the serif family, with its own --prose-font-size, --prose-font-weight, --prose-line-height and --prose-letter-spacing; inline code inside it is reduced to 0.85em. An element still using the former .prose loses its formatted rhythm and becomes serif; complete the rename above before adopting the role. The site's presentation and artwork texts use it.
  • Serif italics. Teodor italics show the font's drawn slant at 10° in every browser. The face's slant range stops at 10deg instead of 12deg, and body sets font-synthesis-style: none: since the range stays below the browsers' italic threshold, Chromium added a synthetic skew of about 14° on top of the axis (about 25° in all) and WebKit skewed the upright glyphs by about 14°. Only Quote, which turned synthesis off itself, showed the drawn slant; it now relies on the document default. A font without an italic face stays upright instead of being skewed. Migration: set font-synthesis-style: auto on body in app styles to let browsers synthesize italics again. Workspace apps adopt the new default.
  • Local type scale. .typography is renamed .typescale; behavior is unchanged. Migration: replace the class name where a local --font-size-base is set. The DS and svx-deck are migrated.
  • Tables and rules. Tables replace their native rendering with one appearance, inside or outside .formatted. They collapse their borders, fill their container and draw a --border rule between rows, without an outer frame. Cells and captions align to the start instead of centering. Cells take --space-2 and --space-3 padding, except on the table's outer edges so the first and last columns align with the surrounding text; they align their content to the top, use tabular numbers and size columns around whole words instead of the inherited anywhere, and literals inside them do not wrap. thead takes the interface role, th and dt prominent text, and table captions --text-subtle, --space-2 above their table. Figure captions take the same subtle text everywhere; formatted content keeps --space-2 between a figure and its caption. Every hr draws one --border-prominent rule instead of the native inset line. A .scrollable wrapper scrolls wide tables. Migration: remove local table, caption and rule styles that duplicate these, or override them on the app's own selectors, such as border-collapse: separate, min-inline-size: auto or text-align: center, to keep the native rendering, and set overflow-wrap: anywhere on .formatted td to keep the former breaks. Bloom is migrated, and www drops its local term color.
  • Underlined text. .underlined gives any element the underline of .formatted links, a 1px line offset by 0.16em, for a link or a button presented as a text link that color alone would not distinguish. Migration: replace local underline declarations with the class. The site's exhibition links, Bloom's reference button and Footer's privacy control use it; Bloom's buttons move from offsets of 0.2em and 0.3em to the shared one.
  • Scrollable regions. .scrollable scrolls content wider than its column, such as a wide table, horizontally inside the column; the owner adds tabindex="0", role="region" and an accessible name. Migration: replace local horizontal scrolling wrappers with the class. Bloom's Markdown tables and the DS reference tables use it instead of their local .table and .table-scroll rules.
  • Formatted blocks. In a loose list, whose items wrap their content in paragraphs, items and their paragraphs are separated by --content-gap-block, as quotation paragraphs are, instead of --space-2 between items and no gap between paragraphs; a nested list in such an item takes the same gap. An ordered list of ten items or more, or with a start other than 1, indents by --space-6 instead of --space-5, so two-digit numbers no longer touch the column edge; Bloom sets start only when a list does not begin at 1. Unordered items replace the native bullet with a muted cross centered on the first line, and ordered numbers take the same --text-muted. hr takes one and a half times the content gap on both sides, like a subsection heading. Definition lists gain list styling: definitions at the list indent and --space-2 between items, with the prominent terms that every dt now takes. A figure caption placed before its media no longer gets a top margin. Code blocks draw their edge with --border-subtle instead of --border, since their fill identifies them. Migration: in app styles, set border-color: var(--border) on .formatted pre to keep the former edge. Workspace apps adopt the new defaults.

Colors, surfaces and interaction

  • Colors. The accent has one value in both themes: the dark theme no longer redefines --accent, which was a different, out-of-gamut pink, and --accent-subtle and --focus derive from it at the root. --text-subtle sits midway between default and muted text (47% light, 71% dark), and the dark --background takes hue 260 like the other dark neutrals instead of 340, a difference below one sRGB level. Migration: redefine --accent under [data-theme="dark"] to keep a distinct dark accent, with --accent-subtle and --focus beside it.
  • Feedback colors. The four light --feedback-* colors are more saturated; the light error moves from pink toward red, away from the accent, and the light warning toward orange. In the dark theme, error and warning are more saturated, success shifts slightly toward teal and info is unchanged. The light values stay below 4.5:1 on light surfaces, and the browser suite checks feedback contrast in the dark theme only. Migration: redefine the four tokens under :root and [data-theme="dark"] to keep the former values.
  • Dark shadows and overlay. The dark theme redefines --floating-control-shadow and --floating-shadow at 45% and 60% black, and --overlay at 60% black instead of 32%, so floating surfaces and modal backdrops separate from the near-black page; light values are unchanged. Migration: redefine them under [data-theme="dark"] to keep the former, nearly invisible shadows and veil.
  • OKLCH notation. Every color token and component color is written in OKLCH, and every color-mix() interpolates in oklch. --background reads oklch(100% 0 0) instead of #fff, and the shadows and overlay use oklch(0% 0 0 / …) instead of rgb(0 0 0 / …); these values are exact equivalents. Mixes with transparent render identically. Only the ThemeToggle outline changes, as it mixes text and background: it is imperceptibly different in the light theme and slightly darker in the dark theme. Migration: scripts that read a token with getPropertyValue() receive the OKLCH string.
  • Overlay tokens. --overlay (the translucent veil behind modal surfaces) and --overlay-blur (the blur of the page seen through it) hold the Dialog backdrop values; ChatComposer's fade uses the same blur. Workspace modals and translucent bands use them.
  • Half-crosses. .half-crossed marks the four corners of any element with accent half-crosses, drawn as background layers. The default Button variant and the focus of text fields and select share this drawing instead of separate copies; their rendering is unchanged.
  • Focus color. --focus-color is renamed --focus: like --border beside --border-width, the bare name holds the color of the focus group. Its value is unchanged. Migration: replace var(--focus-color) with var(--focus). Workspace apps are migrated.
  • Motion tokens. Durations are named by function: --state-duration (120ms) for interaction state changes and --motion-duration (220ms) for positional transitions, with --motion-easing. --duration-normal (160ms) is merged into --state-duration, so HeaderNav and ThemeToggle color changes and the site's artwork arrow take 120ms. Migration: replace --duration-fast and --duration-normal with --state-duration, --duration-slow with --motion-duration and --ease-standard with --motion-easing. Workspace apps are migrated.
  • Inset focus. --focus-inset-offset (-3px) holds the inner focus clearance that Card, Cards, Grid, HeaderNav, ChatThread and Tabs used as local values; rendering is unchanged.
  • Radius tokens. --radius-small and --radius-medium are removed: each served a single component, and ChatMessage and ChatComposer now keep their 0.75rem and 1rem corners locally. --radius-full remains the shared capsule. Migration: replace var(--radius-small) with 0.75rem and var(--radius-medium) with 1rem in app styles. Workspace apps never used them.

Document defaults

  • Cascade layers. A formatted layer between base and utilities holds the .formatted rules, and cascade layers define the question each layer answers. A class placed on an element inside formatted content, such as .framed on a code block, now overrides the formatted styles instead of losing to their more specific selectors. .feedback and .visually-hidden move from base to utilities, beside the classes they belong with; .feedback shares the rules of .metadata. Unlayered app styles still override every layer, so the rendering of workspace apps is unchanged.
  • Lists. The reset removes the native markers of ul and ol, which hung outside lists left without padding; formatted content draws crosses and restores the numbers. Migration: set list-style on lists outside .formatted that should keep native markers. Workspace interface lists drop their local list-style: none.
  • Hidden attribute. hidden hides its element even when a class, component or app style sets display; an element with hidden and .stack, for instance, formerly stayed visible as a flex container. hidden="until-found" keeps its native behavior. Migration: to show an element that carries hidden, remove the attribute instead of overriding display. The DS contents band drops its local [hidden] rule.
  • Dialog margins. The reset keeps the native auto margins of dialog, so a native modal without component styles is centered in the viewport instead of pinned to the top-left corner. Dialog and ChatWindow set their own margins and are unchanged.
  • Text size adjustment. The root sets text-size-adjust: 100%, so iOS Safari no longer enlarges text when a phone turns to landscape.

Native forms

  • Search fields. The clear button of a search field draws a thin cross in --text-subtle, turning --accent on hover, instead of the browser's icon and color. Migration: set appearance: auto and background: none on input[type="search"]::-webkit-search-cancel-button in app styles to restore the browser's button.
  • Native form controls. Select and text fields use the --background-prominent fill without a visible border, and focus draws accent half-crosses at their corners instead of an outer outline, following :focus-within so date and time fields keep them on their internal segments and picker buttons; read-only text fields drop the fill. Checkbox and radio replace their native appearance with a 17px box: --border-prominent boundary, below the 3:1 contrast of a control boundary, accent square or dot when checked, thin ring for keyboard focus. ChatComposer's focus turns its frame to the focus color instead of drawing an outer outline. Date and time inputs share the text field skin, fieldsets drop their native frame, and native widgets follow the active theme through color-scheme. Forced-colors mode keeps system indicators. Migration: in app styles, restore border-color: var(--text-muted) on fields, or appearance: auto with accent-color on choice controls, to keep the former look. Workspace apps adopt the new defaults.
  • Native form messages. .feedback uses metadata typography (mono, uppercase, metadata size and tracking) instead of body text, and untoned feedback takes --text-muted instead of the inherited color. It now also carries field help and validation errors: .field-help and .field-error are removed, since they duplicated untoned and error-toned feedback. Migration: replace class="field-help" with class="feedback" and class="field-error" with class="feedback" data-tone="error", and restore body typography on .feedback in app styles to keep the former look. Workspace apps are migrated.
  • Labels, legends and select. Every label, legend and select takes the complete interface role, uppercase included, wherever it sits: the typography of .ui without the class. Labels beside a checkbox or radio follow it, and select no longer inherits from its context. Text fields keep body typography. .field-label is removed, since the element default replaces it; labels lose its --text-prominent color and its source casing. Migration: remove class="field-label"; a .ui class on a select is now redundant. To keep the former look, set color: var(--text-prominent) and text-transform: none on label and legend, or font: inherit, letter-spacing: inherit and text-transform: none on select, in app styles. Workspace apps are migrated.
  • Input zoom. Text fields and the ChatComposer textarea keep at least 1rem under (pointer: coarse) instead of below --narrow, since touch browsers zoom on focus regardless of viewport width; a narrow desktop window keeps the body size. Select gains the same floor over its interface size, so it shows 16px instead of 11.4px on touch devices. Migration: set font-size: var(--ui-font-size) on select in app styles to keep the interface size.

Layout

  • Breakpoints. --narrow is (width < 48rem) and --wide is renamed --medium, (width < 70rem). Both thresholds follow the root size in rem and exclude their boundary: 768px and 1120px at a 16px root, instead of the inclusive 760px and 1100px. Use not (--medium) for the range above. Migration: replace (--wide) with (--medium) and check layouts at the new boundaries. Workspace apps are migrated.
  • Spacing. --space-8 (16 units, 64px at a 16px root) extends the scale.

Token names

  • Naming rule. Functional tokens name the role first, then the property, as described in Tokens; values are unchanged. Migration: replace --{heading,body,ui,metadata}-weight with --{role}-font-weight, --heading-{1..6}-size with --heading-{1..6}-font-size, --section-number-weight with --section-number-font-weight, --cross with --cross-size, --shadow-control and --shadow-floating with --floating-control-shadow and --floating-shadow, and --layer-floating-control, --layer-floating and --layer-skip-link with --floating-control-layer, --floating-layer and --skip-link-layer, and --text-primary and --text-secondary with --text and --text-subtle, matching the default and subtle levels of the background and border colors. Workspace apps are migrated.

Configuration

  • Configuration factories. createViteConfig, createSvelteConfig and the shared compiler options move from the repository's tooling/ into the package as @dg/ui/config/vite.js, @dg/ui/config/svelte.js and @dg/ui/config/tsconfig.json; behavior is unchanged. The package now declares the PostCSS plugins the Vite factory uses and resolves breakpoints.css itself, so an app's build depends only on its own directory and @dg/ui. Migration: replace ../../tooling/vite.js, ../../tooling/svelte.js and ../../tooling/tsconfig.json with these package paths. Workspace apps are migrated.

  • SvelteKit 3. Workspace apps move to SvelteKit 3, Vite 8, @sveltejs/vite-plugin-svelte 7 and adapter-static 4, which require Node.js 22.17 or later. SvelteKit 3 no longer reads svelte.config.js, so @dg/ui/config/svelte.js is removed and createViteConfig(sveltekit, adapter) passes the adapter and root-relative asset URLs to the SvelteKit plugin. @dg/ui/config/tsconfig.json now only keeps type checks non-strict, which TypeScript 6 no longer does by default; SvelteKit's $app/tsconfig provides the other options. Migration: delete svelte.config.js, import the adapter in vite.config.js and pass it as the second argument; in jsconfig.json, extend ["$app/tsconfig", "@dg/ui/config/tsconfig.json"] with "include": ["src", "*"]; replace $lib/ imports with #lib/ and declare "imports": { "#lib/*": "./src/lib/*" } in the app's package.json. Workspace apps are migrated.

  • Browser test configuration. createPlaywrightConfig({ port, server }) from @dg/ui/config/playwright.js runs a package's tests/*.spec.js with Playwright against one app's dev server on a dedicated port, with the shared viewport, workers and failure traces. Each workspace app and @dg/ui keep their tests in their own tests/ directory; Node tests (*.test.js) run with node --test, and @dg/ui tests its components on the DS pages. The repository's tests/ui suite, tooling/playwright.js and tooling/playwright-toolkit.js are removed. Migration: add a playwright.config.js and a test:ui script as in the boilerplate. Workspace apps are migrated.

Removals

  • GridFlicker is removed, with its --grid-mask override; it was an experiment, and the site's home hero no longer shows its dot field. Migration: remove GridFlicker imports and usages.
  • .grid-bg is removed: no workspace app used the decorative background grid after GridFlicker. Migration: copy its two linear-gradient layers and background-size into the app's own styles.
  • Instrument Serif is removed from @dg/ui/fonts/* and from the --font-serif stack, which now falls back from Teodor to the system serif. Migration: an app that names "Instrument Serif" must host the font itself. Workspace apps never used it.

Documentation

  • Foundation references. Each foundation subject is one page in docs/foundations/, holding its token roles, classes and usage: colors, typography, spacing, stack and row, frames and surfaces, native forms, interaction and responsive. tokens.md keeps loading and override guidance; foundations/frames.md becomes foundations/surfaces.md, and native form guidance moves from foundations/css.md to foundations/native-forms.md. Component pages order their sections as they are read: Usage, Notes, Parameters, Overrides, Methods, Accessibility. CSS and the public API are unchanged. Migration: update links to former tokens.md anchors and foundations/frames.md; the DS no longer redirects former gallery, token and frame URLs.
  • Sections. Each documentation folder is a section whose README.md lists its pages in reading order: getting-started/, foundations/, components/, guides/ and maintain/. quick-reference.md moves to getting-started/quick-reference.md, guides/new-app.md to getting-started/new-app.md, guides/composition.md to getting-started/composition.md, foundations/css.md to getting-started/css.md, tokens.md to foundations/README.md and changes.md to maintain/changes.md; the root README.md links to the sections. DS URLs drop the /docs prefix and mirror these paths, such as /components/button and /foundations. CSS and the public API are unchanged. Migration: update links to the moved files; former /docs/... URLs are not redirected.
  • One owner per subject. getting-started/css.md becomes foundations/document.md, covering cascade layers, native element defaults and focus; its export table moves to getting-started/new-app.md, and font loading to foundations/typography.md. foundations/layout.md becomes foundations/stack-and-row.md. The maintenance process moves from maintain/format.md to maintain/evolution.md#maintenance-process, and DS rendering conventions to the DS README. new-app.md explains the boilerplate's files instead of reproducing them, and composition.md drops its component table in favor of the quick reference. Section indexes describe each section without repeating its pages, and guides group into patterns and process. CSS and the public API are unchanged. Migration: update links to the moved files and anchors; former URLs are not redirected.
  • Editorial recipe. guides/recipe-editorial.md and its DS page are removed: components/heading.md and foundations/typography.md#editorial-content already document the composition, including .formatted.prose.constrained-width. CSS and the public API are unchanged. Migration: link to those references instead; /guides/recipe-editorial is not redirected.

020.3.0

Breaking simplification of the public contract; not published by this change. All workspace apps are migrated.

  • Fonts. Reading text uses Roboto and interface text Roboto Mono, both self-hosted variable fonts under the SIL Open Font License; Ioskeley Mono and the bundled license files are removed.
  • Serif. Headings use Teodor (variable) at weight 100 with --heading-letter-spacing: -0.07em.
  • Readability. Body text is 16px at weight 200, interface text 12px and metadata 11px. Interface tracking is --ui-letter-spacing: 0.1em, applied by components instead of local values. --font-size-xs is removed; the scale is --font-size-sm, --font-size-md and --font-size-lg.
  • Type scale. --font-size-base defaults to 1rem and is no longer a registered property. Migration: set local bases in rem or px; a consumer with a container-relative base registers the property itself (see type scale).
  • Contrast. Select, text fields and ChatComposer outline with --text-muted (at least 3:1). --accent-subtle derives from --accent; feedback colors use oklch with unchanged values.
  • Frames. Direct frames of Page and Main drop their bottom rule; the next frame's top rule is the shared line. A cross erases the lines around it, so neighboring crosses coincide without coordination. Migration: replace style="border-bottom: none" on a preceding frame with border-top: none on the following one; remove styles that targeted the former ::before frame drawing.
  • Ticker is removed.
  • Exports. CloseButton, FullscreenButton, ControlIcon, HeaderNav, InfoBlock, ChatContext, ChatControls, ChatHeader, ChatLauncher, ChatNotice, ChatSendButton and ChatWelcome are no longer exported. Migration: use IconButton icon="close" for CloseButton; write an empty state, context row or notice as app markup inside ChatPanel; ChatWindow keeps its own launcher, header and controls.
  • Tabs is now a WAI-ARIA tabs widget that switches panels within the page: items take { value, label, panel } and value is bindable. Migration: page navigation styled as tabs uses native links instead.
  • Language. Page takes lang (en or fr); every built-in label follows it. SkipLink is placed first inside Page. Removed props: Header menuLabel, closeLabel, themeLabel, themeLabels; ThemeToggle label, lightLabel, darkLabel; Cards scrollLabel, previousLabel, nextLabel; Ticker pauseLabel, resumeLabel; ChatComposer sendLabel, stopLabel; ErrorPage lang. Content-naming props such as label and placeholder remain as overrides.
  • Theme. The outermost Page restores the saved theme before first paint. Migration: delete the theme script from app.html.
  • Fields. Text inputs and textareas share the native field skin by default; the .field class is removed. Section's horizontal, vertical and no-top padding presets are removed.
  • Responsive. Breakpoints are --narrow (760px) and --wide (1100px); --compact and --medium are removed. Grid switches to one column from its own width (40rem) through a container query.
  • Component behavior. Button keeps its natural width inside stacks. Grid equalizes row heights only with several columns, and its divided lines replace a Card cell's border. ChatComposer keeps the draft focused and read-only while pending, and returns focus to it after a stop.
  • Cascade. base.css uses the reset, base and utilities cascade layers; unlayered component and app styles always override them.
  • Every component forwards native attributes, DOM callbacks, class and style to its root element, except the names it owns. SectionHead no longer shows a default number.

030.2.1

Contract hardening; not published by this change.

  • Forwarded attributes use native Svelte HTML types rather than accepting every property name. Consumer tests cover all eleven forwarding components, supported HTML attributes, invalid values and ignored content. Tabs' JSDoc annotation is corrected.
  • Class names remain strings. Header, Footer and Tabs do not accept unrendered children; Heading keeps ownership of children and gap while forwarding Section's padding and crosses. Replace invented attributes with documented props or appropriate data attributes; remove content these components never rendered.
  • Generated agent context resolves prose links directly to Markdown or repository sources. Code examples and raw Markdown endpoints stay unchanged.
  • pnpm check:toolkit runs contract checks without dev servers or browser engines. The canonical Markdown index alone owns current component grouping; legacy gallery URLs remain compatible.
  • The repository's Node engine declaration matches its documented prerequisites. An independent editorial, collection and conversation evaluation protocol describes how to measure agent autonomy without treating automated checks as accessibility certification.

Existing documented runtime behavior and visual defaults are unchanged. Types now report previously unchecked unsupported usage; read each reference's Notes before forwarding attributes.

040.2.0

Development baseline; not published by this change.

  • Spacing derives from one base unit while retaining the previous default scale. Shared radius, focus, disabled, short-motion, elevation and feedback roles are documented.
  • Native text fields, field labels, help, errors and feedback have an opt-in CSS contract. Existing square frames and circular drawing geometry remain intact.
  • ThemeToggle adds label, lightLabel and darkLabel. Header and HeaderNav forward themeLabels; Cards adds scrollLabel, previousLabel and nextLabel. English defaults and existing call sites remain compatible.
  • The registered root typography base resolves from 1em, preserving its default size while allowing WebKit to follow root text enlargement. Scoped bases still resolve once before inheritance.
  • Public documentation includes composition recipes, native checkbox/radio guidance, evolution rules and an agent workflow. The DS generates agent-readable context from the canonical references and CSS rather than a separate editable catalogue.
  • Toolkit checks cover documentation, APIs, consumers and critical behavior on Chromium, Firefox and WebKit. Manual screen-reader and real browser zoom review remain required where relevant.

No consumer migration is required for these optional additions. Translate labels in an application when its audience needs it. Recheck unusual local CSS overrides against the documented spacing and focus contracts before adoption.

distributed·gallery