<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>PolyFish changelog</title>
  <link href="https://polyfish.org/changelog" rel="alternate"/>
  <link href="https://polyfish.org/changelog.xml" rel="self"/>
  <id>https://polyfish.org/changelog</id>
  <updated>2026-10-05T00:00:00Z</updated>
  <entry>
    <title>0.22.0</title>
    <link href="https://polyfish.org/changelog#v0-22-0"/>
    <id>https://polyfish.org/changelog#v0-22-0</id>
    <updated>2026-10-05T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Fixed: The classless module now sits directly after Core in the layer order instead of before it. `:where()` cannot lose to a later layer, so Core&#x27;s reset had been erasing the unclassed button, field and table styles since the module shipped — bare `&lt;button&gt;` rendered transparent.&lt;/li&gt;&lt;li&gt;Added: Classless covers the remaining text-level and structural elements: `abbr[title]`, `ins`, `del`, `dt`/`dd`, `sub`/`sup`, `caption` and `legend`, plus hover, focus and disabled states on unclassed buttons.&lt;/li&gt;&lt;li&gt;Added: `.pf-reveal` gains `--left`, `--right` and `--zoom` direction variants — scroll-driven entrance motion, still guarded by `animation-timeline` support and `prefers-reduced-motion`.&lt;/li&gt;&lt;li&gt;Added: `themes/sudo.css` — the SudoSecurity house palette: true-black ground, hairline borders, teal accent with a violet second and Inter throughout. Eleven themes ship; polyfish.org itself wears this one.&lt;/li&gt;&lt;li&gt;Changed: 690 public classes across twelve modules.&lt;/li&gt;&lt;li&gt;Added: Docs site: the nav checkbox now publishes `aria-controls`/`aria-expanded` through `site.js`, and every `&lt;main&gt;` carries `tabindex=&quot;-1&quot;` so the skip link moves focus, not just scroll position.&lt;/li&gt;&lt;li&gt;Changed: Docs site: `site.css` ships minified as `site.min.css` (70 KB → 42.6 KB), and the module size tables on `/docs/install` are stamped by `release.py` from the files on disk — they had drifted while being hand-maintained.&lt;/li&gt;&lt;li&gt;Added: New post — &#x27;Coming from Tailwind&#x27;: a ten-row map from the common utility reflexes to what PolyFish does instead, and the honest list of what does not translate.&lt;/li&gt;&lt;li&gt;Fixed: Examples: the palettes card&#x27;s thumbnail existed only in the markup; the four immersive demos (dashboard, app-shell, docs-page, sign-in) gained a route back to the gallery, and two pages carried copy-pasted titles and descriptions.&lt;/li&gt;&lt;li&gt;Added: Tooling: `verify.py` now resolves `src`, `poster` and `srcset` on media elements and checks that `for`, `aria-controls`, `aria-labelledby`, `aria-describedby` and `aria-owns` land on real ids; the browser suite pins nav aria state, `?s=` deep links, `pf-segment`, the classless fill and `pf-reveal` under reduced motion.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.21.0</title>
    <link href="https://polyfish.org/changelog#v0-21-0"/>
    <id>https://polyfish.org/changelog#v0-21-0</id>
    <updated>2026-10-05T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: `--pf-brand-fg` and `--pf-brand-line` — role tokens for text and rules in the mark&#x27;s colours. They darken in the light theme and inside `.pf-invert`, so `.pf-fg-brand` and `.pf-brand-rule` hold AA everywhere.&lt;/li&gt;&lt;li&gt;Added: Forms deepen: `:disabled` styling on inputs, `:-webkit-autofill` theming so Chrome&#x27;s autofill matches the palette, and styled `input[type=&quot;color&quot;]` swatches.&lt;/li&gt;&lt;li&gt;Fixed: Forced-colors mode keeps progress and meter fills, the switch knob and the range track/thumb painted in system colours instead of vanishing.&lt;/li&gt;&lt;li&gt;Changed: `.pf-scroller` smooth-snaps to anchors under `prefers-reduced-motion: no-preference`, so plain `#slide` links drive it — a pager with no script.&lt;/li&gt;&lt;li&gt;Added: Docs site: playground presets and `#play=` share links, tokenised multi-word search with per-word highlighting, and a code-block Copy that exports only the lines you can see.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>1.0.0-beta.1</title>
    <link href="https://polyfish.org/changelog#v1-0-0-beta-1"/>
    <id>https://polyfish.org/changelog#v1-0-0-beta-1</id>
    <updated>2026-10-02T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Changed: **Breaking:** `--pf-density` defaults to `1.2` — the whole space scale, both gaps and the section rhythm, opens up 20% for a roomier default. Set `--pf-density: 1` on `:root` to keep the 0.20 spacing.&lt;/li&gt;&lt;li&gt;Changed: `--pf-leading` 1.7 → 1.75 and `--pf-leading-prose` 1.75 → 1.8. `.pf-airy` moves to 1.4 so it still reads as airy against the new default.&lt;/li&gt;&lt;li&gt;Added: `.pf-segment` — a segmented control on radio inputs with no JavaScript: keyboard, focus and disabled states, plus a `--block` full-width variant.&lt;/li&gt;&lt;li&gt;Changed: The documentation is split across six pages — install, layout, theming, typography, guides, migrating — with generated sidebars, phone menus and prev/next paging. Old section URLs keep working through redirects.&lt;/li&gt;&lt;li&gt;Added: Docs site: global search across docs, blog, examples and changelog with `?s=` deep links and recent searches, heading anchors, an offline fallback served by a service worker, `llms-full.txt` and copy-page-as-Markdown.&lt;/li&gt;&lt;li&gt;Changed: `polyfishcss/js` resolves to a real ES module — `import { init, toast }` works in Vite, webpack and Rollup — with `polyfish.d.ts` for TypeScript and every CSS module importable as a subpath.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.20.0</title>
    <link href="https://polyfish.org/changelog#v0-20-0"/>
    <id>https://polyfish.org/changelog#v0-20-0</id>
    <updated>2026-10-02T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Removed: **Breaking:** `PolyFishCSS-Compat.css`. It aliased the names renamed in 0.16 and 0.17; both renames are listed with their replacements in the migration guide, which is where a rename belongs. The `polyfish.compat` layer is gone from the layer order.&lt;/li&gt;&lt;li&gt;Removed: **Breaking:** duplicate width names — `.pf-w-1-2`, `-1-3`, `-2-3`, `-1-4`, `-3-4`, `-1-5`, `-2-5`, `-3-5`, `-4-5`, `.pf-w-half` and `.pf-w-100`. The percentage scale (`.pf-w-50`, `.pf-w-full`) says the same thing once.&lt;/li&gt;&lt;li&gt;Removed: **Breaking:** flex sizing duplicates `.pf-basis-*`, `.pf-flex-auto`, `.pf-flex-initial`, `.pf-flex-none`, `.pf-grow-0/1`, `.pf-shrink-1`; grid leftovers `.pf-span-1..6`, `.pf-row-span-2` and `.pf-place-*`; and the responsive gap mirrors `.pf-md-gap-*` and `.pf-lg-gap-*` with their `-px` steps.&lt;/li&gt;&lt;li&gt;Removed: **Breaking:** the 22 responsive alignment, order, width and text mirrors (`.pf-md-items-center`, `.pf-lg-order-last` and the rest). Responsive visibility and display stay — `.pf-md-hidden`, `.pf-md-block`, `.pf-md-flex`, `.pf-md-grid-d` — because those genuinely change per breakpoint.&lt;/li&gt;&lt;li&gt;Removed: **Breaking:** from Effects, the transform family (`.pf-translate-*`, `.pf-rotate-*`, `.pf-scale-*`, `.pf-flip-x`, `.pf-origin-*`, `.pf-transform`), the filters except `.pf-frost`, the ring section that duplicated `.pf-ring`, the transition and timing extras (`.pf-duration-*`, `.pf-delay-*`, `.pf-ease-*`, `.pf-transition-opacity/shadow/transform`, `.pf-will-change-*`), scroll snap, blend, resize, appearance, caret, list markers, `.pf-fade-*`, `.pf-animate-bounce`, `.pf-animate-slide-in` and `.pf-group-hide`. The motion tokens they wrapped — `--pf-ease-out`, `--pf-duration-2` and the rest — are unchanged. Effects is 26 classes, down from 109.&lt;/li&gt;&lt;li&gt;Changed: **Breaking:** six names fixed to the naming rule, ahead of the 1.0 freeze: `.pf-none` → `.pf-hidden`, `.pf-hide-sm` → `.pf-hide-mobile`, `.pf-hide-lg` → `.pf-hide-desktop`, `.pf-display` → `.pf-font-display`, `.pf-mono` → `.pf-font-mono`, `.pf-bordered-accent` → `.pf-bordered-strong`. The migration guide carries the table.&lt;/li&gt;&lt;li&gt;Changed: **Breaking:** Variants is curated rather than a cross product: 19 classes, down from 99. Kept are hover background, foreground, border, underline, shadow and lift; focus and focus-within ring; active sink and scale-down; group-hover and group-focus foreground and lift. The whole `pf-disabled-*` family is gone, along with combinations like a disabled lift. Variants is 1 KB, down from 11 KB.&lt;/li&gt;&lt;li&gt;Changed: 678 public classes across twelve modules, down from 926 across thirteen, with no component removed.&lt;/li&gt;&lt;li&gt;Changed: `.pf-pagehead` is `clamp(2.5rem, 5vw, 4rem)` tall instead of `clamp(4rem, 8vw, 6.5rem)`, so a second-level page starts with its content rather than a title band. `.pf-pagehead--roomy` keeps the taller treatment where the title is the point.&lt;/li&gt;&lt;li&gt;Changed: `.pf-section--roomy` and `--vast` lose about a third of their padding (`clamp(3.5rem, 8vw, 6rem)` and `clamp(4.5rem, 11vw, 8.5rem)`).&lt;/li&gt;&lt;li&gt;Changed: The documentation is one long page. Installation, modules, layout, typography, tokens, theming, forms, utilities, effects, JavaScript, accessibility, performance, guides and migrating are sections of `/docs`, each with its own contents row; every old URL returns a 301 to its section. Components and the class reference keep pages of their own.&lt;/li&gt;&lt;li&gt;Added: Code samples in the guide can show what they render: a CSS-only toggle under the sample reveals the live result. No frames, no script, no change to the CSP.&lt;/li&gt;&lt;li&gt;Fixed: `tools/release.py` matched only `vX.Y.Z` when restamping headers, so every prerelease build appended its suffix to the last one and shipped files reading `v0.19.0-rc.8-rc.8-…-rc.1`. It now matches the full semver, prerelease included.&lt;/li&gt;&lt;li&gt;Added: `tools/gen-reference.py` generates the class reference from the CSS source. The page said it was generated on every build and was not: it had drifted to 857 classes and 11 modules.&lt;/li&gt;&lt;li&gt;Added: `tools/gen-docs-nav.py` and `tools/gen-palettes.py`: the documentation navigation and the palette comparison page are written from one list and from `themes/*.css`, not hand-copied into every page.&lt;/li&gt;&lt;li&gt;Added: `tools/remove-classes.py`: deletes a class from the source rule by rule, dropping selectors, emptied at-rule blocks and orphaned keyframes. The 0.20 cuts were made with it.&lt;/li&gt;&lt;li&gt;Added: `PolyFishCSS-Variants.css`: state variants without a build step — `pf-hover-*`, `pf-focus-*`, `pf-focus-within-*`, `pf-active-*`, `pf-disabled-*`, `pf-group-hover-*` and `pf-group-focus-*` across fourteen utilities, 99 classes. Hover variants sit inside `@media (hover: hover)` so they never fire on a touch device.&lt;/li&gt;&lt;li&gt;Added: `PolyFishCSS-Classless.css`: styles unclassed semantic elements — headings, links, buttons, fields, tables, code, quotes, `&lt;details&gt;`, `&lt;dialog&gt;`. Every rule is in `:where()`, sits in the lowest layer, and skips any element carrying a class. Optional.&lt;/li&gt;&lt;li&gt;Added: `.pf-popover`, `.pf-popover--menu`, `.pf-popover-anchor` for the native `popover` attribute, with anchor positioning where supported and a fixed fallback elsewhere.&lt;/li&gt;&lt;li&gt;Added: `.pf-dialog` opens from `command=&quot;show-modal&quot;` and closes on backdrop click with `closedby=&quot;any&quot;`. `.pf-dialog__actions`.&lt;/li&gt;&lt;li&gt;Added: Enter and exit transitions for `.pf-dialog` and `.pf-popover` via `@starting-style` and `transition-behavior: allow-discrete`.&lt;/li&gt;&lt;li&gt;Added: `.pf-accordion` animates open through `::details-content` and `interpolate-size`; exclusive groups use the native `name` attribute.&lt;/li&gt;&lt;li&gt;Added: `.pf-textarea--auto` — grows with its content via `field-sizing: content`, bounded to 4–20 lines.&lt;/li&gt;&lt;li&gt;Added: `text-wrap: pretty` on `p`, `li`, `dd`, `figcaption`, `blockquote`.&lt;/li&gt;&lt;li&gt;Added: `--pf-shadow-lg` token. `.pf-shadow-lg` previously read `--pf-lift` directly.&lt;/li&gt;&lt;li&gt;Added: `polyfish.variants` and `polyfish.classless` in the layer order declared by every module. Classless sits directly after Core: it extends the reset for unclassed elements while still losing to every component layer.&lt;/li&gt;&lt;li&gt;Added: Intrinsic layout primitives that respond to their container rather than the viewport: `.pf-switcher`, `.pf-sidebar` (`__side`, `__main`), `.pf-cover` (`__main`), `.pf-center` (`--intrinsic`), `.pf-icon`, `.pf-with-icon`, `.pf-imposter` (`--contain`). Tunable with `--pf-switch`, `--pf-side`, `--pf-main-min`, `--pf-cover-min`.&lt;/li&gt;&lt;li&gt;Added: `--pf-density`: one number that multiplies the space scale, both gaps and the section rhythm. `.pf-compact` (0.8) and `.pf-airy` (1.25) apply it to a region.&lt;/li&gt;&lt;li&gt;Added: Fluid space scale `--pf-space-fluid-1` to `-5`, growing between 320px and 1440px viewports.&lt;/li&gt;&lt;li&gt;Added: Motion tokens: `--pf-ease-out`, `--pf-ease-in`, `--pf-ease-in-out`, `--pf-ease-spring`, `--pf-duration-1` to `-4`.&lt;/li&gt;&lt;li&gt;Added: Derived colour roles `--pf-accent-hover`, `--pf-accent-wash`, `--pf-accent-line` and the `--pf-accent-2-*` equivalents, computed from the accent with `color-mix()`. A theme can now set `--pf-accent` alone. `.pf-retint` re-derives them for one region.&lt;/li&gt;&lt;li&gt;Changed: `--pf-border-strong` and `--pf-focus` derive from `--pf-accent` instead of fixed values.&lt;/li&gt;&lt;li&gt;Fixed: Components read palette tokens directly in about sixty places, so on any theme that did not redeclare them the primary button hovered to the default green and accent cards, badges and washes stayed green. Every component now reads roles only.&lt;/li&gt;&lt;li&gt;Fixed: `--pf-ring` was a fixed green, so focus rings ignored the theme. It now uses `--pf-accent-line`.&lt;/li&gt;&lt;li&gt;Fixed: Link underlines, inline code borders, `.pf-card__icon` borders and the mobile tap highlight used literal copies of the default accent. They now derive from `--pf-accent`.&lt;/li&gt;&lt;li&gt;Added: `.pf-card--numbered` (position-derived counter, so reordering renumbers the set) and `.pf-card--media` with `.pf-card__media` (a fixed 16:9 band, cropped not letterboxed, so a row of cards lines up whatever the image dimensions).&lt;/li&gt;&lt;li&gt;Added: `.pf-alert--inline`: a one-line alert for field-level messages, where the full alert is a billboard for four words.&lt;/li&gt;&lt;li&gt;Added: `.pf-table--numeric`: tabular figures aligned to the end edge, with `th[scope=row]` and `[data-pf-text]` left alone.&lt;/li&gt;&lt;li&gt;Added: `.pf-quote--pull`: a centred pull quote with rules above and below, for long-form pages.&lt;/li&gt;&lt;li&gt;Added: `.pf-badge--dot`: a status badge with a leading dot in its own colour — the word carries the meaning, the dot carries the scan.&lt;/li&gt;&lt;li&gt;Removed: The Grid module. Its 114 classes — twelve spans across three tiers, offsets, order and row gutters — are replaced by layout primitives that carry their own thresholds: `.pf-grid--2/3/4`, `.pf-sidebar`, `.pf-switcher`. Nine core modules now, not ten. The components page carries the full mapping.&lt;/li&gt;&lt;li&gt;Removed: Axis and side spacing utilities: `mx`, `my`, `ms-N`, `me-N`, `m-N`, `px`, `py`, `pt`, `pb`, `ps`, `pe`, the `gap-x` and `gap-y` families, the `-px` steps, and `.pf-cols-*`. 194 classes. `gap` on a layout primitive covers what they did, which is the whole argument for `gap` existing; `.pf-mt-*`, `.pf-mb-*`, `.pf-p-*` and the auto margins stay.&lt;/li&gt;&lt;li&gt;Changed: 1,323 classes down to 1,003 — 42% fewer than two releases ago, with no component removed. The bundle is 19 KB gzipped.&lt;/li&gt;&lt;li&gt;Removed: Responsive margin and padding tiers (`pf-md-mt-*`, `pf-lg-p-*` and the rest, 60 rules). Vertical rhythm belongs to the layout primitive, not to a breakpoint-prefixed margin; responsive `gap` stays.&lt;/li&gt;&lt;li&gt;Removed: Twelve variant utilities that nothing varied: a second accent, an accent wash, a deep background, muted text, a strong border, plain and removed shadows, three opacity steps, an upward scale and a visibility toggle. At seven states each that was 84 classes; Variants is now 99.&lt;/li&gt;&lt;li&gt;Removed: Margin and padding utilities for individual sides and axes — `.pf-mx-*`, `.pf-my-*`, `.pf-ms-*`, `.pf-me-*`, `.pf-px-*`, `.pf-py-*`, `.pf-pt-*`, `.pf-pb-*`, `.pf-ps-*`, `.pf-pe-*`, `.pf-m-*` and the 1px variants. Gap and the layout primitives cover the spacing these existed for; `.pf-mt-*`, `.pf-mb-*`, `.pf-p-*` and the auto margins remain. 194 rules.&lt;/li&gt;&lt;li&gt;Removed: `.pf-gap-x-*` and `.pf-gap-y-*`, and `.pf-cols-*`, which duplicated `.pf-grid--2/3/4`.&lt;/li&gt;&lt;li&gt;Fixed: `tools/release.py` had a hand-written module list that omitted Grid, so that module was never minified into the bundle and a page loading the bundle got its markup unstyled while every check passed. The release script now compares the list against the module files on disk and refuses to run if one is missing.&lt;/li&gt;&lt;li&gt;Changed: 1,740 classes down to 1,001, thirteen modules, and the bundle from 20.6 KB to 18.6 KB gzipped — measured, not estimated.&lt;/li&gt;&lt;li&gt;Removed: Breakpoint tiers `sm` (576px), `xl` (1200px) and `xxl` (1400px) across Grid, Space and Utilities. Two tiers remain, `md` (768px) and `lg` (992px): `sm` mostly duplicated the base layout and the wide two never applied at the 987px measure. Raise `--pf-container` and need a third? A media query in your own stylesheet is three lines.&lt;/li&gt;&lt;li&gt;Removed: `.pf-offset-*` in every tier. A start margin — `.pf-ms-auto` — does the same job without 36 classes, and the whole site used one offset.&lt;/li&gt;&lt;li&gt;Removed: Scheme variants `pf-dark-*` and `pf-light-*`. The role tokens already flip with the scheme, so these only ever did what a one-line rule in your own stylesheet does.&lt;/li&gt;&lt;li&gt;Changed: 1,740 classes down to 1,323 in the first pass of this release.&lt;/li&gt;&lt;li&gt;Changed: The mark and both wordmarks are redrawn as a robotic betta: a turbine-blade tail fan, a swept dorsal stack, ventral blades, plate seams and a sensor visor — on the same five colours. The files also lost their embedded metadata, taking the mark from 9,006 to 2,134 bytes.&lt;/li&gt;&lt;li&gt;Added: `.pf-particles`: a drifting field of accent-coloured specks behind a hero or title band, built from two pseudo-element layers of radial gradients — no canvas, no script, no DOM node. Animates only transform and opacity, paints behind content, takes no pointer events, and stops still under `prefers-reduced-motion`. Tunable with `--pf-particle-size`, `--pf-particle-opacity` and `--pf-particle-speed`.&lt;/li&gt;&lt;li&gt;Added: `.pf-hero--art` and `.pf-hero__art` for hero and header artwork, as a background image or an inline SVG, with a scrim over it so text keeps its contrast. A group marked `data-pf-art-detail` is dropped below 48em, where dense artwork is noise behind a headline. Ships with the eighteen SudoSecurity hub files in `art/`.&lt;/li&gt;&lt;li&gt;Changed: The hero scrim holds flat across the text band rather than thinning at its midpoint: the worst pixel behind hero text measured 5.58:1 there, and now measures 6.2:1. `--pf-hero-scrim` tunes it; `.pf-hero--panel` is the route to a 7:1 floor.&lt;/li&gt;&lt;li&gt;Added: `.pf-particles--mesh` and `.pf-particles--constellation`: SVG tiles for the particle field — the triangle motif, and points with lines between them. The SVG is used as a mask over an accent fill, because a data URI cannot read a custom property and a tile with the colour baked in would ignore every theme.&lt;/li&gt;&lt;li&gt;Added: `.pf-hero--hub`, with `.pf-hero__assure` and `.pf-hero__glance`: the section-landing header pattern — promise, actions, the reassurance under them, and a row of numbers saying the section is alive. The glance row is a description list, so a screen reader reads label and value as a pair rather than six loose numbers.&lt;/li&gt;&lt;li&gt;Added: `.pf-hero--panel` (hero copy on a bordered surface) and `.pf-hero--compact` (half the vertical padding, for a second-level page).&lt;/li&gt;&lt;li&gt;Added: `.pf-footer--center` (brand, columns and legal line stacked down the middle) and `.pf-footer--minimal` (one row, no column grid).&lt;/li&gt;&lt;li&gt;Changed: Default palette: neutral `#181818` ground with a teal primary (`#32b6af`) and a purple second (`#b396e8`), replacing the navy-and-green scheme. Light scheme accents follow (`#0f5d58`, `#55309c`). Every pairing measures at least 7:1.&lt;/li&gt;&lt;li&gt;Added: Three themes: `themes/ocean.css` (blue-green, cyan and indigo), `themes/ember.css` (warm near-black, amber and rose), `themes/orchid.css` (violet ground, lilac and teal). Nine themes ship now, each with a palette example page.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-checks` and `.pf-steps` list items were two-column grids, so any inline element inside them — a `&lt;code&gt;` chip, a link — became a grid item of its own and was dropped into the narrow marker column, where it wrapped one character per line. Both markers are positioned now and inline content stays inline.&lt;/li&gt;&lt;li&gt;Changed: `.pf-grid--2/3/4` treat the column count as a ceiling: a track narrower than `--pf-col-min` (17rem) drops a column instead. Three cards across a 987px measure left 226px tracks breaking body text every three words.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-row` inherited the page gap for its column gutter. With a larger gap, eleven gutters between twelve tracks were wider than a 320px screen and every track collapsed to zero; the row now has its own gutter, overridable with `--pf-gutter-x`.&lt;/li&gt;&lt;li&gt;Changed: `--pf-container` is 987px, down from 1160px, with new `--pf-container-narrow` (720px) and `--pf-container-wide` tokens; `.pf-container--narrow` and `--wide` read those tokens instead of fixed widths. Wide defaults to the same 987px measure — raise the token for a broader band.&lt;/li&gt;&lt;li&gt;Changed: `.pf-hero--split` needs 460px per column before it splits, up from 400px. Below that the display title breaks into short lines and the panel beside it is unreadable, so the hero stacks.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-invert` never repainted a component&#x27;s own background: its paint rule sat in the `polyfish.core` layer while `.pf-card`&#x27;s background sits in `polyfish.content`, a later layer, so an inverted card kept its dark surface and flipped its text to dark — 2.5:1. The flip is now painted from the utilities layer.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-invert` kept the page&#x27;s accent, leaving a dark-scheme accent on a light panel. It now flips `--pf-accent`, `--pf-accent-2`, `--pf-ink`, `--pf-focus` and the derived hover, wash and line colours.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-btn` read `--pf-base-950` for its text instead of `--pf-ink`, so any scope that flipped the ink — `.pf-invert`, `.pf-retint` — got dark text on a dark button.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-footer--accent` painted itself with the accent without flipping `--pf-text` and `--pf-text-muted`, leaving muted text at 1.19:1 on the accent background.&lt;/li&gt;&lt;li&gt;Fixed: The mobile-menu checkbox stayed in the tab order above the 860px breakpoint, where its label is hidden: a focusable unlabelled control on every desktop page.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-table td[data-pf=&quot;no&quot;]` used a faded copy of the muted colour at 3.7:1; it now uses `--pf-text-muted`.&lt;/li&gt;&lt;li&gt;Fixed: The breadcrumb separator and the scroll-fade gradient used literal palette colours instead of roles.&lt;/li&gt;&lt;li&gt;Fixed: `themes/cream.css`: second accent `#8e3509` (7.01:1, previously 3.6:1). `themes/dusk.css`: second accent `#f07e79` (7.02:1, previously 6.95:1).&lt;/li&gt;&lt;li&gt;Changed: `polyfish.js` builds the tablist as an inserted `&lt;span class=&quot;pf-tabs__list&quot;&gt;` that claims the labels with `aria-owns`, and marks the radios `aria-hidden`. Previously `role=&quot;tablist&quot;` went on `.pf-tabs`, making the radios and panels its children — invalid ARIA.&lt;/li&gt;&lt;li&gt;Changed: `--pf-accent-hover` and `--pf-accent-2-hover` mix toward `--pf-text` instead of black, so hovering can only raise the contrast of button text.&lt;/li&gt;&lt;li&gt;Changed: Syntax colours in `.pf-code` (`.pf-tag`, `.pf-attr`, `.pf-str`, `.pf-comment`) derive from the colour roles.&lt;/li&gt;&lt;li&gt;Changed: Light scheme: `--pf-hue-1` `#2e5816`, `--pf-hue-2` `#7c3d00`, `--pf-base-300` `#3b5163`, bringing links, button text and muted text to at least 7:1.&lt;/li&gt;&lt;li&gt;Changed: `themes/cream.css`: accent `#46580e` (7.02:1, previously 3.96:1).&lt;/li&gt;&lt;li&gt;Changed: Inline `code` wraps: `overflow-wrap: anywhere` with `box-decoration-break: clone`, replacing `white-space: nowrap`.&lt;/li&gt;&lt;li&gt;Changed: `h1`, `h2`, `h3` hyphenate below 30em.&lt;/li&gt;&lt;li&gt;Changed: Touch-target and 16px field rules under `(pointer: coarse)` moved from Core into the module that owns each component.&lt;/li&gt;&lt;li&gt;Fixed: The 16px field floor on touch devices had no effect since 0.17: it sat in the `polyfish.core` layer and Content&#x27;s field rule, in a later layer, overrode it, so iOS zoomed on focus.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-pagination__item` was 40px on touch; now 44px.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-alert--success`, `--warn` and `--danger` used `border-left-color`, colouring the wrong side under `dir=&quot;rtl&quot;`.&lt;/li&gt;&lt;li&gt;Fixed: Single-column grids — `.pf-stack` and 25 others — grew to their widest child&#x27;s minimum content and overflowed narrow screens. Their children can now shrink.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-pagehead__inner` and `.pf-section__head` let a long single-word heading widen the column.&lt;/li&gt;&lt;li&gt;Fixed: The short-landscape media query reset section padding and `--pf-gap-lg` without `--pf-density`.&lt;/li&gt;&lt;li&gt;Fixed: `--pf-ink` was declared only in the optional `PolyFishCSS-Compat.css`, so without it `pf-*-bg-accent` variants and classless buttons set no text colour. It is now a Core role.&lt;/li&gt;&lt;li&gt;Fixed: Field placeholder colour was a literal copy of the default muted colour; it now derives from `--pf-text-muted`.&lt;/li&gt;&lt;li&gt;Changed: `data-pf-dialog` in `polyfish.js` is now a fallback: it acts only where the browser did not already open the dialog natively.&lt;/li&gt;&lt;li&gt;Changed: Hover variants are scoped to `@media (hover: hover)`; transitions sit inside `prefers-reduced-motion: no-preference`.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.19.0</title>
    <link href="https://polyfish.org/changelog#v0-19-0"/>
    <id>https://polyfish.org/changelog#v0-19-0</id>
    <updated>2026-09-18T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: `themes/paper.css` — editorial light palette, serif display face, no radius.&lt;/li&gt;&lt;li&gt;Added: `themes/mono.css` — terminal dark palette, monospace display face, square corners.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.18.0</title>
    <link href="https://polyfish.org/changelog#v0-18-0"/>
    <id>https://polyfish.org/changelog#v0-18-0</id>
    <updated>2026-06-26T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: Metric-matched fallback faces in `PolyFishCSS-Fonts.css`: `Inter Fallback`, `Bricolage Fallback`, `Plex Mono Fallback`, with `ascent-override`, `descent-override`, `line-gap-override` and `size-adjust` measured from the shipped woff2. Reduces layout shift on font swap.&lt;/li&gt;&lt;li&gt;Added: `.pf-no-print`, `.pf-print-only`.&lt;/li&gt;&lt;li&gt;Changed: Font stacks name the metric-matched fallback before generic families.&lt;/li&gt;&lt;li&gt;Changed: Print stylesheet rewritten: forces a light palette, hides navigation and chrome, expands tab panels and accordions, prints external link targets, sets page-break rules.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.17.0</title>
    <link href="https://polyfish.org/changelog#v0-17-0"/>
    <id>https://polyfish.org/changelog#v0-17-0</id>
    <updated>2026-06-12T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: Every module wraps its rules in `@layer polyfish.&lt;module&gt;` and declares the full layer order.&lt;/li&gt;&lt;li&gt;Added: Right-to-left support throughout.&lt;/li&gt;&lt;li&gt;Changed: All physical properties replaced with logical equivalents: `margin-inline-*`, `padding-inline-*`, `border-inline-*`, `inset-inline-*`, `text-align: start|end`.&lt;/li&gt;&lt;li&gt;Changed: **Breaking:** `.pf-ml-*`, `.pf-mr-*`, `.pf-pl-*`, `.pf-pr-*` renamed to `.pf-ms-*`, `.pf-me-*`, `.pf-ps-*`, `.pf-pe-*` (including responsive variants). `.pf-text-left`, `.pf-text-right` renamed to `.pf-text-start`, `.pf-text-end`. Aliased in `PolyFishCSS-Compat.css`.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.16.0</title>
    <link href="https://polyfish.org/changelog#v0-16-0"/>
    <id>https://polyfish.org/changelog#v0-16-0</id>
    <updated>2026-05-29T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: `PolyFishCSS-Compat.css` — aliases for renamed tokens and classes. Kept until 1.0.&lt;/li&gt;&lt;li&gt;Changed: **Breaking:** palette tokens renamed by position. `--pf-blue-{900..600}` → `--pf-base-{900..600}`; `--pf-paper` → `--pf-base-50`; `--pf-mist` → `--pf-base-300`; `--pf-ink` → `--pf-base-950`; `--pf-green*` → `--pf-hue-1*`; `--pf-orange*` → `--pf-hue-2*`.&lt;/li&gt;&lt;li&gt;Changed: **Breaking:** colour-named helpers renamed by role: `.pf-fg-green` → `.pf-fg-accent`, `.pf-bg-green-wash` → `.pf-bg-accent-wash`, `.pf-btn--orange` → `.pf-btn--accent-2`, `.pf-pill--green` → `.pf-pill--accent`, `.pf-footer--green` → `.pf-footer--accent`, and seven more. Aliased in Compat.&lt;/li&gt;&lt;li&gt;Added: Font licences (SIL OFL 1.1) for all bundled faces in `fonts/`.&lt;/li&gt;&lt;li&gt;Added: `package.json` with per-module `exports`.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.15.0</title>
    <link href="https://polyfish.org/changelog#v0-15-0"/>
    <id>https://polyfish.org/changelog#v0-15-0</id>
    <updated>2026-05-15T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Fixed: `.pf-steps`: children after the first rendered in the 2.2rem number column. All children now placed in column 2.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.14.0</title>
    <link href="https://polyfish.org/changelog#v0-14-0"/>
    <id>https://polyfish.org/changelog#v0-14-0</id>
    <updated>2026-05-01T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: `.pf-text-2xl`, `.pf-text-3xl`, `.pf-text-4xl`, `.pf-text-5xl`.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.13.0</title>
    <link href="https://polyfish.org/changelog#v0-13-0"/>
    <id>https://polyfish.org/changelog#v0-13-0</id>
    <updated>2026-04-17T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Changed: Background ramp darkened: `--pf-base-900` `#00030f`, `--pf-base-800` `#000823`, `--pf-base-700` `#000f3f`, `--pf-base-600` `#17306e`.&lt;/li&gt;&lt;li&gt;Fixed: Light-mode surface tints, `.pf-hero--photo` gradient and gallery overlay used a hardcoded legacy navy instead of palette tokens.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.12.0</title>
    <link href="https://polyfish.org/changelog#v0-12-0"/>
    <id>https://polyfish.org/changelog#v0-12-0</id>
    <updated>2026-04-03T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Changed: `--pf-accent` `#a9cc9a` → `#8fe06a`; `--pf-hue-1-deep` `#87ab79` → `#6dc44a`.&lt;/li&gt;&lt;li&gt;Changed: `--pf-section-pad`, `--pf-gap`, `--pf-gap-lg`, `--pf-space-7..9` increased. Hero, page-head, card, step and footer padding follow.&lt;/li&gt;&lt;li&gt;Changed: `.pf-stack` gap reads `--pf-gap`.&lt;/li&gt;&lt;li&gt;Added: `.pf-prose` vertical rhythm from the space scale.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.11.0</title>
    <link href="https://polyfish.org/changelog#v0-11-0"/>
    <id>https://polyfish.org/changelog#v0-11-0</id>
    <updated>2026-03-20T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: `--pf-brand`, `--pf-brand-2`, `--pf-brand-deep`; `.pf-brand-well`, `.pf-fg-brand`, `.pf-brand-rule`.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.10.0</title>
    <link href="https://polyfish.org/changelog#v0-10-0"/>
    <id>https://polyfish.org/changelog#v0-10-0</id>
    <updated>2026-03-06T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: Proportional widths: `.pf-w-0` to `.pf-w-100` in steps of 5, plus `.pf-w-1-2`, `-1-3`, `-2-3`, `-1-4`, `-3-4` and fifths.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.9.0</title>
    <link href="https://polyfish.org/changelog#v0-9-0"/>
    <id>https://polyfish.org/changelog#v0-9-0</id>
    <updated>2026-02-20T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: `PolyFishCSS-Effects.css`: composable transforms, filters, `.pf-frost`, gradients, `.pf-gradient-text`, rings, six animations, transition utilities, scroll-snap, `.pf-group` hover, blend and isolation. 92 rules.&lt;/li&gt;&lt;li&gt;Changed: Animations are defined only inside `prefers-reduced-motion: no-preference`.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.8.0</title>
    <link href="https://polyfish.org/changelog#v0-8-0"/>
    <id>https://polyfish.org/changelog#v0-8-0</id>
    <updated>2026-02-06T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Changed: Background ramp darkened; `--pf-paper` `#e9eefa`, `--pf-mist` `#a9bcd8`, `--pf-ink` `#00081f`.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.7.0</title>
    <link href="https://polyfish.org/changelog#v0-7-0"/>
    <id>https://polyfish.org/changelog#v0-7-0</id>
    <updated>2026-01-23T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: `.pf-drawer`, `.pf-bottombar`, `.pf-has-bottombar`, `.pf-toast`.&lt;/li&gt;&lt;li&gt;Added: `.pf-table--stack`, reading cell labels from `data-pf-label`.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.5.0</title>
    <link href="https://polyfish.org/changelog#v0-5-0"/>
    <id>https://polyfish.org/changelog#v0-5-0</id>
    <updated>2025-12-26T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: `PolyFishCSS-Space.css`: padding, margin, gap, grid tracks, spans, placement and flex sizing at four breakpoints.&lt;/li&gt;&lt;li&gt;Added: `.pf-scroller`.&lt;/li&gt;&lt;li&gt;Added: `env(safe-area-inset-*)` on container gutters, mobile menu and footer; `touch-action: manipulation` on interactive elements.&lt;/li&gt;&lt;li&gt;Removed: Spacing, margin and gap utilities from Utilities; now owned by Space.&lt;/li&gt;&lt;li&gt;Fixed: Form fields floored at 16px under `pointer: coarse` to prevent iOS focus zoom.&lt;/li&gt;&lt;li&gt;Fixed: Mobile menu capped at `100dvh` and scrollable.&lt;/li&gt;&lt;li&gt;Fixed: `min-height: 100vh` paired with `100dvh`.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-menu` popover width capped to the viewport.&lt;/li&gt;&lt;li&gt;Fixed: `.pf-tabs` strip scrolls horizontally below 620px.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.4.0</title>
    <link href="https://polyfish.org/changelog#v0-4-0"/>
    <id>https://polyfish.org/changelog#v0-4-0</id>
    <updated>2025-12-12T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: `polyfish.js`: `data-pf-menu`, `data-pf-tabs`, `data-pf-dialog`, `data-pf-copy`, `data-pf-counter`, `data-pf-dismiss`, `data-pf-sort`, `data-pf-spy`, `data-pf-theme-toggle`; `PolyFish.init(root)`.&lt;/li&gt;&lt;li&gt;Added: `.pf-code__copy`, `.pf-th-sort` — styles for elements the script creates.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.3.0</title>
    <link href="https://polyfish.org/changelog#v0-3-0"/>
    <id>https://polyfish.org/changelog#v0-3-0</id>
    <updated>2025-11-28T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: `PolyFishCSS-Forms.css`.&lt;/li&gt;&lt;li&gt;Added: Automatic light mode via `prefers-color-scheme`; `data-pf-theme` to pin.&lt;/li&gt;&lt;li&gt;Added: Container-query helpers: `.pf-container-q`, `.pf-cq-row`, `.pf-cq-2..4`, `.pf-cq-side`.&lt;/li&gt;&lt;li&gt;Added: Icon and link buttons, `aria-busy` loading state, `.pf-stretched-link`, shadow scale, divide utilities, table variants.&lt;/li&gt;&lt;li&gt;Changed: Validation styling keys off `aria-invalid` and `:user-invalid`.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.2.0</title>
    <link href="https://polyfish.org/changelog#v0-2-0"/>
    <id>https://polyfish.org/changelog#v0-2-0</id>
    <updated>2025-11-14T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: `PolyFishCSS-Grid.css`: twelve columns at five breakpoints, offsets, order, gutters.&lt;/li&gt;&lt;li&gt;Added: `PolyFishCSS-Components.css`.&lt;/li&gt;&lt;li&gt;Added: Responsive utility variants using infixes (`.pf-md-hidden`).&lt;/li&gt;&lt;li&gt;Changed: **Breaking:** flex-direction helpers renamed `.pf-flex-col` / `.pf-flex-row`; `.pf-col` now belongs to Grid.&lt;/li&gt;&lt;li&gt;Changed: **Breaking:** removable chip renamed `.pf-tag` → `.pf-chip`.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
  <entry>
    <title>0.1.0</title>
    <link href="https://polyfish.org/changelog#v0-1-0"/>
    <id>https://polyfish.org/changelog#v0-1-0</id>
    <updated>2025-10-31T00:00:00Z</updated>
    <content type="html">&lt;ul&gt;&lt;li&gt;Added: Core, Headers, Content, Footers, Utilities.&lt;/li&gt;&lt;/ul&gt;</content>
  </entry>
</feed>
