# Bengal 0.5.1

URL: /bengal/releases/0.5.1/
Section: releases
Description: A real CSS engine and a refreshed default theme — a tokenizer-based minifier that can't corrupt your stylesheets, OKLCH palettes with light-dark() dark mode, a dependency-free knowledge graph, and byte-reproducible build output.

---

> For a complete page index, fetch /bengal/llms.txt.

**Key theme:** A real CSS engine, and a default theme that earns its zero-dependency promise. Bengal 0.5.1 replaces the regex-based CSS minifier with a proper CSS Syntax Level 3 engine that tokenizes before it serializes — so it can no longer glue tokens together and silently corrupt a stylesheet — and it re-authors the default theme around modern CSS: OKLCH palettes, `light-dark()` dark mode, structured data, and a knowledge graph that no longer pulls D3 from a CDN. Build output is now byte-reproducible across rebuilds, and a few free-threading correctness fixes round it out.

---

## Highlights

### A real CSS engine

The CSS minifier was a pile of regexes. It is now `bengal.css`: a CSS Syntax Level 3 engine that tokenizes the stylesheet before serializing it. The bug that prompted the rewrite — `@scope (...) to (...)` getting glued into `to(...)`, which made the parser treat `to` as a function and silently drop the scoped rule — is gone, and the new tokenizer makes that whole class of "identifier glued to `(`" corruption structurally impossible (#510).

The engine verifies its own work. After minifying, it re-parses its output and compares an independent meaning signature — selector combinators, declaration values, and (at the aggressive level) the resolved cascade — against the input. On any mismatch it returns the input unchanged, so it can never emit corrupted CSS.

`minify_css` also gained a `level` argument:

- `"safe"` (default) — lossless whitespace and comment removal. The default build path is unchanged.
- `"optimize"` — adds safe value normalizations: named colors when shorter than hex, unquoted `url()` bodies, length-context unitless zeros (`margin:0px` → `margin:0`), and collapsed shorthands (`margin:0 0 0 0` → `margin:0`) (#515).
- `"aggressive"` — adds cascade-invariant structural rewrites: empty-rule removal, exact-duplicate dedup, and adjacent-rule merging.

Two opt-in passes layer on top: `flatten_nesting=True` de-sugars native CSS nesting into flat selectors for legacy browser targets while preserving the cascade (#516), and intra-stylesheet dead-code removal strips unused `@keyframes`, `@font-face`, and custom properties (#512). Native CSS nesting (`&:hover`) is now preserved by default rather than flattened (it's Baseline 2023).

### A refreshed default theme

The default theme was re-authored around modern CSS and a zero-dependency runtime:

- **No third-party CDNs by default.** The theme no longer loads Mermaid, D3, KaTeX, or Google Fonts from third-party CDNs at runtime. Opt in via `[capabilities]` in `bengal.toml` to self-host diagram and math vendors at build time (#533).
- **OKLCH palettes.** Colors are now authored in OKLCH for wide-gamut richness, and the five built-in palettes derive their hover, active, border, surface, and state variants automatically from a handful of anchors via relative-color and `color-mix` — retuning a palette no longer means editing a hand-painted hex matrix. The focus ring is palette-aware instead of falling back to a fixed blue (#534).
- **`light-dark()` dark mode.** Dark colors flow through a single `light-dark()` token set selected by `color-scheme`, replacing the duplicated dark token matrix. Dark mode now renders correctly in every named palette and follows the OS preference with no flash of the wrong theme (#535).
- **Structured data.** Pages emit correct `og:type` per kind, `WebSite`/`CollectionPage` JSON-LD on landing and list surfaces, and `BreadcrumbList` data; the docs right-sidebar graph minimap is consolidated into shared partials (#536).
- **One JavaScript model.** Interactive regions — table of contents, docs nav, learning-track sidebar, and the REST API catalog — are now custom elements (`<bengal-toc>`, `<bengal-docs-nav>`, `<bengal-track-nav>`, `<bengal-api-catalog>`) that initialize themselves when they appear (including content inserted after load) and tear their listeners down when removed. This retires the redundant second script-loading registry. Every page still degrades gracefully with JavaScript disabled (#537).

### A dependency-free knowledge graph

The graph minimap and the full `/graph/` explorer are now rendered by a first-party, dependency-free engine. Node positions are computed at build time and the explorer draws to a canvas, so it stays responsive on large sites. The opt-in `d3` capability is removed — the graph no longer depends on D3, and the runtime CDN request for it is gone.

### Reproducible output

Two builds of unchanged content now produce byte-identical output. The knowledge graph's `graph/graph.json` and the search `index.json` previously used a per-process randomized hash (and absolute paths), with process-dependent edge and tag ordering; ids are now a stable hash of the site-relative path, and edges and tags sort deterministically. Sitemap and `agent.json` aggregates use stable URL/path ordering so results no longer depend on page discovery order (#431).

### Free-threading correctness

Provenance-cache races that could return stale warm-build output under free-threaded Python — when records were loaded or verified concurrently — are fixed (#438), and free-threading detection is consolidated to the canonical `bengal.utils.concurrency` helper so executor selection and render paths no longer drift on GIL-fallback logic (#381).

---

## Added

- Opt-in intra-stylesheet removal of unused `@keyframes`, `@font-face`, and custom properties (#512).
- `minify_css(..., flatten_nesting=True)` de-sugars nested rules into flat selectors for legacy targets while preserving the cascade (#516).

## Changed

- The CSS minifier is now a tokenizing CSS Syntax Level 3 engine (`bengal.css`) with `safe`/`optimize`/`aggressive` levels; `optimize` adds safe color, `url()`, and numeric normalizations (#510, #515).
- Default theme re-authored in OKLCH with anchor-derived palettes and a palette-aware focus ring (#534).
- Default theme dark mode uses a single `light-dark()` token set selected by `color-scheme`, correct in every palette and following OS preference (#535).
- Default theme no longer loads Mermaid, D3, KaTeX, or Google Fonts from third-party CDNs; opt in via `[capabilities]` to self-host at build time (#533).
- Default theme emits `og:type`, `WebSite`/`CollectionPage` JSON-LD, and `BreadcrumbList` structured data; docs sidebar graph minimap consolidated into shared partials (#536).
- Default theme JavaScript uses one custom-element enhancement model (`<bengal-toc>`, `<bengal-docs-nav>`, `<bengal-track-nav>`, `<bengal-api-catalog>`), retiring the redundant script registry (#537).
- The knowledge graph minimap and `/graph/` explorer are rendered by a dependency-free, first-party engine that computes layout at build time.
- Core: per-heading search index records for deep-link search results (#546); renderer-agnostic data-table contract decoupled from Tabulator config (#547); optional git-derived last-modified field for pages (#548); code-fence attributes (title, diff, line ranges) parsed through to the highlighter (#549).
- Free-threading detection consolidated to `bengal.utils.concurrency` so executor selection and render paths don't drift on GIL fallback (#381).

## Fixed

- The CSS minifier no longer corrupts `@scope (...) to (...)` by gluing it into `to(...)` and dropping the rule; the tokenizing engine makes that class of corruption impossible, and it verifies its own output before emitting (#510).
- `graph/graph.json` and the search `index.json` are byte-identical across rebuilds of unchanged content (stable ids, deterministic edge/tag ordering).
- Sitemap and `agent.json` aggregate output uses stable URL/path ordering, independent of discovery order (#431).
- Provenance-cache races that could return stale warm-build output under free-threaded Python are fixed (#438).
- `bengal fix` now receives per-source link metadata, so it can suggest repairs for every broken internal link on a page, not just the first few shown in validator details (#508).

## Removed

- The opt-in `d3` capability and the runtime D3 CDN request from the `/graph/` page; the knowledge graph works by default with no third-party scripts.
- The obsolete `@supports (color: color-mix(...))` feature-query fallbacks in the default theme — `color-mix()` is now Baseline, so the guarded branches apply unconditionally (#534).
- The legacy CSS code paths: the `bengal.assets.css_minifier` shim and the regex-based `bengal/core/asset/css_transforms.py` (`lossless_minify_css`, `remove_duplicate_bare_h1_rules`, `transform_css_nesting`). Import `minify_css` from `bengal.css` (#510).

---

## Upgrading

```bash
uv pip install --upgrade bengal
# or
pip install --upgrade bengal
```

A few things to know:

- **The CSS minifier moved.** If you imported CSS helpers from internals, switch to `from bengal.css import minify_css`. The `bengal.assets.css_minifier` shim and `bengal/core/asset/css_transforms.py` are gone. Native CSS nesting is now preserved by default rather than flattened; pass `flatten_nesting=True` if you target browsers without nesting support.
- **The default theme is CDN-free by default.** If you relied on Mermaid, D3, KaTeX, or Google Fonts loading at runtime, opt in under `[capabilities]` in `bengal.toml` to self-host them at build time. The knowledge graph needs no opt-in — it's dependency-free now, and the `d3` capability is removed.
- **Reproducible builds.** Graph and search output is now byte-identical across rebuilds of unchanged content; if you diff or cache build artifacts, expect previously-noisy `graph.json`/`index.json`/sitemap output to settle.
