zeus-css 1.0.11 → 1.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zeus-css",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "description": "⚡ A Premium, Zero-Emission, Fluid-Scaling CSS Framework based on Sass SCSS Engine",
5
5
  "author": "Stavros Lazaris",
6
6
  "license": "MIT",
@@ -15,14 +15,11 @@
15
15
  "main": "./dist/zeus.css",
16
16
  "style": "./dist/zeus.css",
17
17
  "bin": {
18
- "zeus-css": "./bin/init.js"
19
- },
20
- "scripts": {
21
- "postinstall": "node ./bin/postinstall.js"
18
+ "zeus-css": "bin/init.js"
22
19
  },
23
20
  "exports": {
24
21
  ".": {
25
- "sass": "./scss/zeus.scss",
22
+ "sass": "./scss/foundation/foundation.scss",
26
23
  "css": "./dist/zeus.css",
27
24
  "default": "./dist/zeus.css"
28
25
  },
@@ -30,17 +27,25 @@
30
27
  "./zeus": "./scss/zeus.scss",
31
28
  "./config": "./scss/zeus.config.scss",
32
29
  "./customize": "./scss/zeus.customize.scss",
30
+ "./css": "./dist/zeus.css",
31
+ "./min": "./dist/zeus.min.css",
33
32
  "./dist/*": "./dist/*",
34
33
  "./scss/*": "./scss/*",
35
34
  "./bin/*": "./bin/*"
36
35
  },
37
36
  "files": [
38
- "scss",
37
+ "scss/foundation",
38
+ "scss/zeus.scss",
39
+ "scss/zeus.config.scss",
40
+ "scss/zeus.customize.scss",
41
+ "scss/zeus.token.sets.example.scss",
42
+ "scss/zeus.tokens.json",
39
43
  "dist",
40
- "bin"
44
+ "bin",
45
+ "CHANGELOG.md"
41
46
  ],
42
47
  "peerDependencies": {
43
- "sass": "^1.60.0"
48
+ "sass": "^1.79.0"
44
49
  },
45
50
  "keywords": [
46
51
  "zeus",
@@ -52,4 +57,4 @@
52
57
  "design-tokens",
53
58
  "type-safe"
54
59
  ]
55
- }
60
+ }
package/scss/CHANGELOG.md CHANGED
@@ -1,299 +1,112 @@
1
1
  # Changelog
2
2
 
3
- All notable changes to Zeus CSS are documented here. This project follows
4
- [Semantic Versioning](https://semver.org/) against the public API surface
5
- documented in [`API.md`](API.md).
3
+ All notable changes to zeus-css are documented in this file.
4
+ Format loosely follows [Keep a Changelog](https://keepachangelog.com/).
6
5
 
7
- ## [Unreleased]
8
-
9
- ## [1.0.11] — 2026-08-05
6
+ ## [1.0.13]
10
7
 
11
8
  ### Fixed
12
- - **The published package's README (generated by `scripts/build-package.ts`,
13
- not copied from this file) documented Step 1 (`zeus-css/dist/zeus.css`) and
14
- Step 2 (`npx zeus-css init` + `zeus.theme.css`) with no statement that
15
- they're mutually exclusive** — a dev following both in sequence ended up
16
- with both imports in the same root layout. Added an explicit warning plus
17
- a two-line flowchart between the two steps in that template, so the
18
- generated README (and every future publish) states the replacement
19
- relationship instead of leaving it implied.
20
-
21
- ## [1.0.10] — 2026-08-05
22
-
23
- Published to npm as `zeus-css`. [`API.md`](API.md) documents the public API
24
- surface this changelog's semver contract is now binding against.
25
9
 
26
- ### Removed (since first written)
27
- - **Dark mode**, entirely `$zeus-dark-mode-strategy` and
28
- `$zeus-enable-auto-dark-mode` (both mentioned as "Added" just below when
29
- this entry was still labeled `1.0.0`) no longer exist. Architecture
30
- decision: the framework ships one fixed, WCAG-passing light palette;
31
- `semantic-colors.scss` emits a single `:root` block, no strategy branching.
32
- - `$zeus-breakpoint-strategy` and its `"desktop-first"` reserved value —
33
- removed rather than implemented; only mobile-first ever existed as a real
34
- strategy, so the config knob offered no real choice. See `API.md`.
35
- - The `.zeus-*` utility class prefix renamed to bare class names
36
- (`.surface`, `.glass`, `.sr-only`, etc.); `.z-*` is now reserved
37
- exclusively for the framework's fixed BEM components (card, modal, form
38
- controls) and does not participate in `$zeus-use-prefix`.
10
+ - **Package tarball no longer ships a stale nested copy of the framework.**
11
+ `scss/dist/*.css` (a 1.0.0-era build with 12 instances of `outline: none`
12
+ instead of the current 7 an accessibility fix that had already shipped
13
+ in the real `dist/`), the nested `scss/package.json`, `.stylelintrc.json`,
14
+ and dev-only build scripts are no longer included in `files`. Unpacked
15
+ package size drops from carrying a full second copy of the framework to
16
+ just the intended source.
17
+ - **`exports["."].sass` now resolves to `./scss/foundation/foundation.scss`**
18
+ instead of `./scss/zeus.scss`. The latter is an intentional zero-emission
19
+ bridge (four `@forward` statements, no CSS) meant for component
20
+ `.module.scss` files via the `zeus-css/zeus` subpath it was never meant
21
+ to be the target of the bare `zeus-css` import. `@use "pkg:zeus-css"` (or
22
+ any bundler's `sass` condition resolution) now returns the actual
23
+ framework instead of silently compiling to nothing.
24
+ - Fixed a compile crash (`Invalid index 2 for a list with 1 elements`) when
25
+ `$zeus-breakpoints` is overridden down to a single entry. The breakpoint
26
+ sort in `root-generator.scss` now guards `$n > 1` before entering the
27
+ loop.
28
+ - `<main>` no longer collapses to near-zero width as a flex item. It was
29
+ included (with `body` and `.container`) in the container-query
30
+ `container-type: inline-size` reset, which removes it from normal
31
+ content-based sizing; unlike `body`/`.container`, `<main>` in a flex
32
+ context has no other width source. Removed from that selector, matching
33
+ the reasoning already applied to `.grid`.
34
+ - `[hidden]` can now be overridden. The reset declared
35
+ `display: none !important` inside `@layer reset` — the first layer in
36
+ cascade order — and layer order reverses for `!important` declarations,
37
+ so nothing later (layered or not) could win. The `!important` is gone,
38
+ and the selector is now `:where([hidden]):not([hidden="until-found"])`
39
+ so `hidden="until-found"` content stays reachable by in-page find, per
40
+ the HTML spec's own recommended selector for this rule.
41
+ - Fluid typography no longer rounds to visible 1.6px steps. The shared
42
+ clamp() engine's `$step` defaults to `0.1` in the *output* unit — fine at
43
+ 0.1px for spacing, but 0.1rem (1.6px) for type. Typography now compiles
44
+ with `$step: 0.01` / `$accuracy: 3`, and declared min/max endpoints are
45
+ now reached in practice instead of stopping ~1.6px short.
46
+ - `overflow-wrap: anywhere` removed from the `body` reset. It was declared
47
+ alongside `word-break: break-word`, which already handles overflow
48
+ safely; `anywhere` additionally breaks inside words that don't need it,
49
+ including in narrow columns where it isn't wanted.
50
+ - Added `border-style: solid` to the universal box-sizing reset. Elements
51
+ reset with `border: 0` (`button`, `input`, `textarea`, `select`) stayed
52
+ invisible even after a consumer later added `border-width`/`border-color`,
53
+ because `border-style` defaulted to `none`. Same fix Tailwind's preflight
54
+ uses.
55
+ - `bin/init.js` now exits non-zero on a failed scaffold instead of
56
+ swallowing the error and exiting 0, and responds to `--help`/`-h` with
57
+ usage instead of running the full init routine against the current
58
+ directory.
59
+ - `peerDependencies.sass` raised from `^1.60.0` to `^1.79.0`, matching the
60
+ actual floor required by the relative `oklch(from ...)` color syntax and
61
+ the `pkg:` importer used in the docs.
62
+ - Removed the `postinstall` script (`bin/postinstall.js`) and its
63
+ `package.json` hook. It only printed a discovery hint for
64
+ `npx zeus-css init`, already covered in the README — not worth pnpm 10
65
+ blocking lifecycle scripts by default, or the supply-chain-scanner flags
66
+ a postinstall script draws for no functional benefit.
67
+ - Corrected the README's `@property` claim — coverage is the base semantic
68
+ color palette (5 tokens), not "key tokens" broadly; derived color
69
+ variants, spacing, and typography remain plain custom properties.
70
+ - Removed `body-md`, `body-md-bold`, `body-md-semibold`, and `body-md-medium`
71
+ from the typography token map — they were byte-for-byte duplicates of
72
+ `body`/`body-bold`/`body-semibold`/`body-medium`. `--text-body` is now
73
+ the single source; regenerated `zeus.tokens.json`, `cheatsheet.md`, and
74
+ `llms.txt` (both the `scss/` copies and the package-root mirrors, which
75
+ had drifted out of sync). The two real consumers of `--text-body-md`
76
+ (`FinalHeader.module.scss`, `CtaBlock.module.scss`, both outside this
77
+ package) were migrated to `--text-body` — same value, no visual change.
78
+ - Fixed an unrelated bug found while migrating `CtaBlock.module.scss`:
79
+ `.installBox` set `font-size: var(--text-body)`, but `--text-body` is a
80
+ `font` *shorthand* (weight/size/line-height/family), not a bare size —
81
+ invalid as a `font-size` value, so it silently fell back to inherited.
82
+ Replaced with `font: var(--text-code);`, matching the token its sibling
83
+ widget (`TheZeusHero.module.scss` `.install`) already uses, per the
84
+ file's own "kept in visual sync" comment.
85
+ - Documented that Zeus intentionally ships one color palette with no
86
+ `prefers-color-scheme` / light-dark switching — not a gap, a design
87
+ decision. `zeus-theme()` is for swapping the whole palette (e.g. a
88
+ different brand), not a light/dark toggle. See README Features.
89
+ - Fixed a silent-drop bug in color token emission: explicitly setting a
90
+ derived color key in `$zeus-colors` (e.g. `primary-light`) made
91
+ `semantic-colors.scss` skip emitting it, on the assumption that
92
+ `root-generator.scss`'s generic pipeline would emit it instead — but that
93
+ pipeline deliberately excludes `$zeus-colors`. The variable vanished from
94
+ the compiled CSS entirely; with `$zeus-enable-property-registration`
95
+ left at its default it was masked by `@property`'s `initial-value`
96
+ incidentally supplying the same value, but disabling that flag exposed
97
+ the break directly. `_emit-static-color-vars` now always emits every
98
+ variant, using the explicit override when present and the derived value
99
+ otherwise.
39
100
 
40
- ### Added
41
- - **Component library, 3 → 14 components.** Phase 1: `.z-badge`, `.z-alert`,
42
- `.z-avatar` (+ `.z-avatar-group`), `.z-table`, `.z-breadcrumb`,
43
- `.z-pagination`. Phase 2: `.z-tabs`, `.z-tooltip`, `.z-dropdown`,
44
- `.z-toast-region`/`.z-toast`, `.z-skeleton` — the floating ones built on the
45
- native `popover` attribute plus CSS anchor positioning (same
46
- "let the platform do it" approach as `.z-modal`'s `<dialog>`), with
47
- `prefers-reduced-motion` guards and graceful degradation when anchor
48
- positioning is unavailable. All are listed in [`API.md`](API.md) §5 and
49
- therefore covered by the semver contract.
50
- - **`derive-on-color()`** (`design/colors/_color-derivation.scss`) — derives a
51
- readable foreground for text sitting on any brand color by switching on that
52
- color's OKLCH lightness, entirely in CSS so it keeps following runtime
53
- overrides. Fixes `.z-badge--solid`, which previously hardcoded white text
54
- and so shipped 2.20:1 on the default secondary, 2.34:1 on warning and
55
- 2.79:1 on success. All six solid variants now clear WCAG AA
56
- (4.55–7.40:1, browser-verified). Documented non-guarantee: a single
57
- lightness threshold cannot clear AA for *every* possible input color.
58
- - **CI hardening** (`scripts/test-compile.mjs`, 4 → 8 checks) — public-API
59
- smoke test that invokes every public mixin/function, config-variable usage
60
- analysis (catches orphaned config surface), CLI-bridge template integrity,
61
- and a WCAG AA contrast regression guard over all 10 shipped color pairings.
62
- - **Form components** (`_form.scss`): `.z-field`, `.z-label`, `.z-input`,
63
- `.z-textarea`, `.z-select`, `.z-checkbox`, `.z-radio`, `.z-field-group`, with
64
- hover/`:focus-visible`/`:disabled`/invalid states, native `accent-color`
65
- theming for checkboxes/radios, and a CSS-only select chevron.
66
- - **Z-index scale** — `$zeus-z-index` config map, `--z-*` custom properties,
67
- and `.layer-{name}` utility classes; `.z-modal`/`.z-modal-backdrop` now use
68
- the scale instead of hardcoded `z-index: 999/1000`.
69
- - New utility class families: sizing (`w-*`, `h-*`, `min-w-*`, `max-w-*`,
70
- fraction widths), position (`static`/`relative`/`absolute`/`fixed`/`sticky`,
71
- `inset-*`, `top-*`/`bottom-*`, logical `inset-inline-start/end-*`), misc
72
- (`opacity-*` in steps of 5, `overflow-*`, `object-*`, `flex-grow/shrink-*`,
73
- `order-*`), and `hover:`/`focus:` state variants for every `bg-*`/`color-*`/
74
- `border-color-*` class.
75
- - **`zeus.tokens.json`** — every design token (colors, spacing, typography,
76
- shadows, radii, borders, icon sizes, z-index, custom vars) in W3C Design
77
- Tokens format, generated straight from compiled CSS by `npm run gen:tokens`
78
- so it cannot drift from what actually ships.
79
- - **`llms.txt` / `cheatsheet.md`** — auto-generated catalog of every public
80
- mixin, function, and utility class family, via `npm run gen:cheatsheet`.
81
- Both regenerate automatically on `npm run prepack`.
82
- - **`scripts/test-compile.mjs`** — a 4-check compile matrix (default build,
83
- module zero-emission, prefix build, config-override contract) using the
84
- Sass JS API, run via `npm run test:compile`.
85
- - **`.stylelintrc.json`** + `npm run lint:scss`, tuned to this codebase's
86
- established conventions rather than generic defaults.
87
- - A GitHub Actions workflow (`zeus-css-ci.yml`) running the compile matrix and
88
- lint on every push/PR touching `zeus-css/**`.
89
- - Shared color-derivation functions (`_color-derivation.scss`:
90
- `derive-light`, `derive-dark`, `derive-surface`, `derive-muted`,
91
- `derive-border`, `derive-border-strong`, `derive-surface-subtle`,
92
- `derive-warning-subtle`) used by both `semantic-colors.scss` and
93
- `theme-builder.scss`, closing the gap where `zeus-theme()` previously
94
- produced incomplete token sets compared to the default palette.
95
- - `API.md` — the documented public API surface required for a `1.0.0` tag.
96
-
97
- ### Changed
98
- - Shadow presets (`primary`, `secondary`, `glow`, `glow-lg`, `outline`) now
99
- derive from `var(--color-primary)` via `oklch(from ... l c h / N)` instead
100
- of a hardcoded blue `rgba()`, so they follow custom brand colors.
101
- - `col-start-*`/`col-end-*` grid utilities generated via `@for` loop instead
102
- of hand-written rules.
103
-
104
- ### Fixed
105
- - **`engine/shadows.scss`'s mixins didn't follow the codebase's own
106
- CSS-Var-First pattern.** `padding()`/`border-radius()`/`text()` all
107
- reference the already-emitted `:root` custom property (`var(--space-md)`,
108
- etc.) instead of recomputing the value — documented as a deliberate
109
- pattern in `layout.scss`/`typographics.scss`, for two reasons: the value
110
- stays runtime-overridable (JS, `[data-theme]`), and the literal value
111
- lives once instead of being repeated at every call site. Every shadow
112
- mixin (`apply-shadow()`, `elevation()`, `hover-shadow()`, `focus-shadow()`,
113
- `interactive-shadow()`, `card-shadow()`, `semantic-shadow()`,
114
- `inner-shadow()`, `layered-shadow()`, `conditional-shadow()`) instead
115
- called a Sass function (`shadow($key)`) that inlined the raw
116
- `box-shadow` value at compile time — e.g. `.z-card` had a literal
117
- `box-shadow: 0px 2px 8px 0px rgba(...), ...;` sitting right next to a
118
- correctly-referenced `border-radius: var(--border-radius-md);`. A
119
- component styled with `card-shadow()` would not pick up a runtime change
120
- to `--shadow-card`, unlike every other token-driven mixin in the
121
- framework. Added a private `_shadow-var($key)` helper
122
- (`var(--shadow-#{$key})`) and switched all 16 call sites to it — same
123
- compiled visual result under default config, now consistent with the
124
- rest of the engine, and the repeated literal value is gone from the
125
- compiled output (each shadow's value now appears once, at `:root`,
126
- instead of once per component using it).
127
- - **Focus indicators could disappear entirely under Windows High Contrast
128
- Mode (`forced-colors`), a WCAG 2.4.7 Focus Visible risk.** Five call sites
129
- removed the native focus outline (`outline: none`) and relied solely on
130
- `box-shadow`/`border-color` to show `:focus-visible` —
131
- `_form.scss`'s `_z-control-base()`, the `focus-shadow()`,
132
- `interactive-shadow()`, and `conditional-shadow()` mixins in
133
- `engine/shadows.scss`, and the `.focus:shadow-outline`/`.focus:shadow-primary`
134
- utility classes. `forced-colors` mode strips `box-shadow` entirely, so
135
- keyboard focus had no visible indicator left in that mode. Changed
136
- `outline: none` to `outline: 2px solid transparent` at each site: fully
137
- invisible in normal rendering (box-shadow remains the visible affordance),
138
- but browsers paint outlines with a system color under `forced-colors`
139
- regardless of the author-specified color, so focus stays visible exactly
140
- when it's needed. `button-base-reset()` and the link reset in
141
- `typography.scss` already used the correct pattern (`outline: revert` /
142
- a real `outline` on `:focus-visible`) and needed no change.
143
- - `btn-size()` emitted physical `padding-left`/`padding-right` for its
144
- horizontal padding while every other spacing mixin in the framework already
145
- uses logical properties — the one RTL leak in an otherwise RTL-clean
146
- codebase. Now `padding-inline` (and, for consistency, `padding-block`
147
- instead of `padding-top`/`padding-bottom`).
148
- - `_tooltip.scss`'s anchor-positioning fallback comment claimed an
149
- `@supports` guard "protects the whole feature" — no such block exists
150
- anywhere in the codebase. The actual mechanism (browsers ignore the
151
- unrecognized `position-anchor`/`position-area` values and fall back to
152
- default top-layer placement) needed no guard; the comment now says so.
153
- - `API.md` referenced `foundation/core/design/_fluid-core.scss` twice (§3,
154
- §7) — the file has always lived in `foundation/core/engine/`.
155
- - `API.md` §7 listed "the CI workflow" among excluded tooling; no CI workflow
156
- exists in this repository. Reworded to reference the compile-matrix test
157
- suite that does.
158
- - `README.md`'s "Learn more" section said a docs site was "planned for a
159
- future release" while one already existed — corrected to stop disclaiming
160
- it.
161
- - **Package name unified to `zeus-css`.** The source manifest and all docs
162
- said `@lazaris/zeus-css` while the published package `scripts/build-package.ts`
163
- actually generates is — and always was — unscoped `zeus-css`, which is also
164
- what the `zeus-css init` bridge imports (`@use "zeus-css/scss/zeus.scss"`).
165
- Following the README's `npm install @lazaris/zeus-css` therefore produced a
166
- bridge file that could not resolve. `package.json`, `README.md`, and
167
- `API.md` §1 now all say `zeus-css`.
168
- - **The four documented entry points now actually resolve.** README/`API.md` §1
169
- document `zeus-css/foundation`, `zeus-css/zeus`, `zeus-css/config`, and
170
- `zeus-css/customize`, but the generated package's `exports` map only carried
171
- `.`, `./config`, and the raw `./scss/*` passthrough — so three of the four
172
- documented specifiers failed to resolve against the published package.
173
- Explicit aliases for all four are now emitted.
174
- - **`zeus-css/css` and `zeus-css/min` were real, shipped exports
175
- (`package.json` → `exports`) with no entry in README or `API.md` §1** — a
176
- dev with no Sass pipeline had no documented way to just import the
177
- precompiled CSS, and the two specifiers carried no semver contract despite
178
- already being public. README now leads with them for the no-build-step
179
- path; `API.md` §1 lists both, with a note that they're static builds of
180
- `foundation.scss` with default tokens baked in and cannot reflect
181
- `zeus.customize.scss` overrides.
182
- - `$zeus-outer-padding` was declared twice in `zeus.config.scss` — an older
183
- `(mobile, desktop)`-shaped default (used internally to auto-derive
184
- `$container-bounds`) and a newer `(floor, ceil)`-shaped default (the public
185
- config that drives `--padding-outer`) reused the same variable name. Because
186
- the first `!default` assignment wins, the second declaration was always
187
- dead: `--padding-outer` compiled with a `128px` → `64px` max instead of the
188
- documented `128px`, and overriding the public var via its documented
189
- `(floor, ceil)` shape crashed the build (`null` arithmetic) in
190
- `core/design/core/basic.scss`. The internal default is now its own
191
- variable, `$zeus-viewport-gutter` (the gutter between the viewport edge and
192
- the container at each reference width), and both it and `$zeus-viewports`
193
- (which was never forwarded at all) are now included in the `zeus-css init`
194
- CLI bridge template.
195
- - **Six silent-failure gaps in the token pipeline, closed after an internal
196
- audit.** All were "malformed override compiles anyway, producing broken CSS
197
- or a confusing low-level error" — none were reachable through the shipped
198
- defaults, only through a bad override:
199
- - `_validate.scss`'s validators (written for exactly this) were never
200
- `@include`d anywhere. Now wired into every token module that assembles a
201
- `(floor, ceil)`/typography/button-size map — `design/dimensions/spaces.scss`,
202
- `design/dimensions/sizes.scss`, `design/borders/border-radius.scss`,
203
- `design/borders/border-line.scss`, `design/layout/grid.scss`
204
- (`$column-gaps`), `design/typography/typography.scss`, and
205
- `design/buttons/sizes.scss` — so a malformed entry now fails loudly, by
206
- name, at the point it's declared.
207
- - `zeus-resolve-type()` (`views/render/root-generator.scss`) duck-typed the
208
- token pipeline's dictionary by checking for `floor`+`ceil` or
209
- `weight`+`lh`; a map with only one of either pair silently fell through to
210
- "nested map" and emitted a wrong CSS variable instead of the intended one.
211
- Now `@error`s on a partial match, for any dictionary entry — not just the
212
- six categories the validators above cover.
213
- - `zeus-transform-value()`'s typography branch resolved a token's `family`
214
- key against `$font-family` with no existence check, so a typo'd family
215
- silently compiled a literal `null` into the emitted `font` shorthand. Now
216
- `@error`s with the available family names.
217
- - `btn-size()`'s missing-nested-key case (a size entry with `font`/`py`/`px`
218
- present but no `floor`/`ceil` inside) is now unreachable — the
219
- `design/buttons/sizes.scss` validator above rejects the malformed
220
- `$zeus-button-sizes` entry before `btn-size()` ever sees it.
221
- - `_c()` (`design/colors/semantic-colors.scss`) intentionally falls back to
222
- a built-in default when a `$zeus-colors` key is absent — but that made a
223
- typo'd key (e.g. `primry`) indistinguishable from "not set", with no
224
- signal at all. `$zeus-colors` is now checked against the exact set of keys
225
- this file reads; an unrecognized key `@warn`s by name instead of vanishing
226
- silently.
227
- - The custom-vars responsive loop (`zeus-root-vars()`) assumed
228
- `$zeus-breakpoints` was already in ascending pixel order and iterated it
229
- as-written; an override that appended a new breakpoint out of numeric
230
- order would cascade it last instead of where its pixel value puts it. The
231
- loop now sorts breakpoint keys by pixel value before iterating.
232
- - Duplicate `.inset-0` rule (one hardcoded, one loop-generated) in the new
233
- position utilities.
234
- - `_form.scss`'s `&:hover:not(:disabled):not(:focus-visible)` rewritten to
235
- the `:not(a, b)` complex-selector notation required by the new lint config.
101
+ ### Known issues (tracked, not in this release)
236
102
 
237
- ## [0.9.0] 2026-07-20
238
-
239
- First public beta. Prior versions were internal-only; this changelog starts
240
- here rather than reconstructing an inaccurate pre-history.
241
-
242
- ### Added
243
- - `LICENSE` (MIT), `package.json` with a proper `exports` map, and this
244
- `CHANGELOG.md` the framework can now be installed via npm.
245
- - `README.md` with install instructions and a 5-minute quickstart.
246
- - Opt-in `.no-overflow-x` utility (replaces the old global `overflow-x: hidden`
247
- on `html`/`body`, which hid real layout overflow instead of surfacing it).
248
- - `@warn` diagnostic when `$zeus-breakpoint-strategy` is set to an
249
- unimplemented value (previously silently ignored).
250
-
251
- ### Changed
252
- - **Single source of truth for color tokens.** Any `*-light`, `*-dark`,
253
- `surface`, `text-inverse`, `text-muted`, `border`, or `border-strong` key
254
- defined in `$zeus-colors` is now respected as-is; automatic OKLCH derivation
255
- only runs for keys the developer did **not** define. Previously, derived
256
- values silently overwrote explicit config values.
257
- - Cascade layer order (`reset, tokens, base, layout, components, utilities`)
258
- is now established before any layer receives rules, and `html`/`body`,
259
- typography defaults, components (`.z-card`, `.z-modal`), and patterns
260
- (`.z-hero`, `.z-sidebar-layout`) are now emitted inside their proper layer —
261
- utility classes can reliably override component styles without `!important`.
262
- - `zeus.scss` (the module-only entry point used via `@use "zeus" as *` in
263
- component files) is now truly zero-emission: animation `@keyframes` and the
264
- scroll-driven `.z-scroll-*` classes moved to the render layer, so importing
265
- it no longer leaks ~150 lines of duplicate CSS into every component.
266
- - Config schema unified to `(floor, ceil)` everywhere. `$zeus-column-gaps` and
267
- `$zeus-outer-padding` previously used `(min, max)` keys that the engine
268
- silently ignored — overrides now apply correctly.
269
- - Grid utilities (`.grid-cols-*`, `.grid-split`, `.grid-thirds`,
270
- `.grid-sidebar`, `.z-sidebar-layout`) use `minmax(0, 1fr)` instead of bare
271
- `1fr`, preventing grid blowout (a page-level horizontal scrollbar) when a
272
- grid child contains wide unbreakable content such as code blocks.
273
- - `$zeus-use-prefix` now applies consistently across every utility generator
274
- (shadows, containers, compounds, aspect-ratio, animations, grid patterns) —
275
- previously only some class families respected it.
276
- - `color()` alpha blending now uses `color.change()` instead of `rgba()`,
277
- which crashed on OKLCH input in modern Dart Sass.
278
-
279
- ### Fixed
280
- - `<dialog class="z-modal">` no longer renders visible when closed (the base
281
- rule set `display` unconditionally; it's now scoped to `&[open]`).
282
- - `:where(li) { list-style: none }` and the accompanying `padding-left: 0`
283
- reset — both applied globally — have been removed; only lists explicitly
284
- marked `[role="list"]` opt out of native bullets, preserving list semantics
285
- for assistive technology.
286
- - `outline: none` on shadow-based focus styles now only applies under
287
- `:focus-visible`, never plain `:focus`, so keyboard users always retain a
288
- visible focus indicator.
289
- - `html { font-size: 16px }` → `font-size: 100%`, respecting the user's
290
- browser font-size preference instead of overriding it.
291
- - `scroll-behavior: smooth` no longer applied unconditionally outside the
292
- `prefers-reduced-motion` guard already present in the reset.
293
- - `--color-surface-subtle` and `--color-warning-subtle` (referenced by
294
- `:where(code)` / `:where(mark)`) are now actually defined.
295
- - An impossible/dead media query combination
296
- (`min-width: 2560px` together with an inner `max-width` below it) that could
297
- never match has been removed from the responsive utility loop.
298
- - Stale `(min, max)` references in comments and validator error messages
299
- corrected to the actual `(floor, ceil)` schema.
103
+ - `round()`/`oklch(from ...)` are used throughout the compiled CSS with no
104
+ `@supports` fallback, so browsers without CSS `round()` support drop the
105
+ affected `clamp()` declarations entirely. Needs a systematic
106
+ progressive-enhancement pass, not a patch-sized fix.
107
+ - Class naming mixes three conventions (`z-*` BEM components, `btn-*` and
108
+ `.container` utilities, both covered by `$zeus-use-prefix`). Decided:
109
+ keep as-is rather than a breaking rename `$zeus-use-prefix` defaults
110
+ to `false`, so `.container`/`btn-*` are unprefixed unless opted in; this
111
+ is now called out explicitly in `API.md` as a collision risk when
112
+ running alongside another framework.
@@ -54,50 +54,43 @@ $_known-color-keys: (
54
54
  // ║ from 5 resolved base colors. ║
55
55
  // ║ Single source of truth shared with engine/theme-builder.scss. ║
56
56
  // ╚══════════════════════════════════════════════════════════════╝
57
+ // Emits $key either from the developer's explicit $zeus-colors override or
58
+ // from $derived. root-generator.scss's generic token pipeline deliberately
59
+ // excludes $zeus-colors (see _design-system.scss), so this is the only
60
+ // place a variant key ever gets emitted — skipping it on _has($key) (as
61
+ // this used to do, on the assumption something else emitted it) silently
62
+ // dropped the variable from the compiled CSS entirely whenever a developer
63
+ // set it explicitly.
64
+ @function _resolved($key, $derived) {
65
+ @if _has($key) {
66
+ @return _c($key, $derived);
67
+ } @else {
68
+ @return $derived;
69
+ }
70
+ }
71
+
57
72
  @mixin _emit-static-color-vars($primary, $secondary, $accent, $text, $bg) {
58
73
  --color-primary: #{$primary};
59
- @if not _has("primary-light") {
60
- --color-primary-light: #{derive.derive-light("var(--color-primary)")};
61
- }
62
- @if not _has("primary-dark") {
63
- --color-primary-dark: #{derive.derive-dark("var(--color-primary)")};
64
- }
74
+ --color-primary-light: #{_resolved("primary-light", derive.derive-light("var(--color-primary)"))};
75
+ --color-primary-dark: #{_resolved("primary-dark", derive.derive-dark("var(--color-primary)"))};
65
76
 
66
77
  --color-secondary: #{$secondary};
67
- @if not _has("secondary-light") {
68
- --color-secondary-light: #{derive.derive-light("var(--color-secondary)")};
69
- }
70
- @if not _has("secondary-dark") {
71
- --color-secondary-dark: #{derive.derive-dark("var(--color-secondary)")};
72
- }
78
+ --color-secondary-light: #{_resolved("secondary-light", derive.derive-light("var(--color-secondary)"))};
79
+ --color-secondary-dark: #{_resolved("secondary-dark", derive.derive-dark("var(--color-secondary)"))};
73
80
 
74
81
  --color-accent: #{$accent};
75
- @if not _has("accent-light") {
76
- --color-accent-light: #{derive.derive-light("var(--color-accent)")};
77
- }
78
- @if not _has("accent-dark") {
79
- --color-accent-dark: #{derive.derive-dark("var(--color-accent)")};
80
- }
82
+ --color-accent-light: #{_resolved("accent-light", derive.derive-light("var(--color-accent)"))};
83
+ --color-accent-dark: #{_resolved("accent-dark", derive.derive-dark("var(--color-accent)"))};
81
84
 
82
85
  --color-background: #{$bg};
83
- @if not _has("surface") {
84
- --color-surface: #{derive.derive-surface("var(--color-background)")};
85
- }
86
+ --color-surface: #{_resolved("surface", derive.derive-surface("var(--color-background)"))};
86
87
 
87
88
  --color-text: #{$text};
88
- @if not _has("text-inverse") {
89
- --color-text-inverse: #{$bg};
90
- }
89
+ --color-text-inverse: #{_resolved("text-inverse", $bg)};
91
90
 
92
- @if not _has("text-muted") {
93
- --color-text-muted: #{derive.derive-muted("var(--color-text)", "var(--color-background)")};
94
- }
95
- @if not _has("border") {
96
- --color-border: #{derive.derive-border("var(--color-text)", "var(--color-background)")};
97
- }
98
- @if not _has("border-strong") {
99
- --color-border-strong: #{derive.derive-border-strong("var(--color-text)", "var(--color-background)")};
100
- }
91
+ --color-text-muted: #{_resolved("text-muted", derive.derive-muted("var(--color-text)", "var(--color-background)"))};
92
+ --color-border: #{_resolved("border", derive.derive-border("var(--color-text)", "var(--color-background)"))};
93
+ --color-border-strong: #{_resolved("border-strong", derive.derive-border-strong("var(--color-text)", "var(--color-background)"))};
101
94
 
102
95
  --color-surface-subtle: #{derive.derive-surface-subtle("var(--color-surface)", "var(--color-text)")};
103
96
  --color-warning-subtle: #{derive.derive-warning-subtle("var(--base-system-warning)", "var(--color-background)")};
@@ -218,15 +218,6 @@ $_typography-defaults: (
218
218
  weight: 400,
219
219
  role: "body",
220
220
  ),
221
- "body-md": (family: "primary",
222
- size: (floor: 16,
223
- ceil: 18,
224
- ),
225
- lh: 1.6,
226
- ls: 0,
227
- weight: 400,
228
- role: "body",
229
- ),
230
221
  "body-bold": (family: "primary",
231
222
  size: (floor: 16,
232
223
  ceil: 18,
@@ -236,15 +227,6 @@ $_typography-defaults: (
236
227
  weight: 700,
237
228
  role: "body",
238
229
  ),
239
- "body-md-bold": (family: "primary",
240
- size: (floor: 16,
241
- ceil: 18,
242
- ),
243
- lh: 1.6,
244
- ls: 0,
245
- weight: 700,
246
- role: "body",
247
- ),
248
230
  "body-semibold": (family: "primary",
249
231
  size: (floor: 16,
250
232
  ceil: 18,
@@ -254,15 +236,6 @@ $_typography-defaults: (
254
236
  weight: 600,
255
237
  role: "body",
256
238
  ),
257
- "body-md-semibold": (family: "primary",
258
- size: (floor: 16,
259
- ceil: 18,
260
- ),
261
- lh: 1.6,
262
- ls: 0,
263
- weight: 600,
264
- role: "body",
265
- ),
266
239
  "body-medium": (family: "primary",
267
240
  size: (floor: 16,
268
241
  ceil: 18,
@@ -272,15 +245,6 @@ $_typography-defaults: (
272
245
  weight: 500,
273
246
  role: "body",
274
247
  ),
275
- "body-md-medium": (family: "primary",
276
- size: (floor: 16,
277
- ceil: 18,
278
- ),
279
- lh: 1.6,
280
- ls: 0,
281
- weight: 500,
282
- role: "body",
283
- ),
284
248
  "body-sm": (family: "primary",
285
249
  size: (floor: 14,
286
250
  ceil: 16,
@@ -67,5 +67,10 @@
67
67
  $c-floor: _px-to-rem(map.get($container-bounds, "floor"), 2);
68
68
  $c-ceil: _px-to-rem(map.get($container-bounds, "ceil"), 2);
69
69
 
70
- @return fc.zeus-cqi-fluid($min-rem, $max-rem, $c-floor, $c-ceil, "rem", 1);
70
+ // $step in rem defaults to 0.1 (fluid-core.scss), i.e. a 1.6px jump at the
71
+ // 16px root — visible banding in type that isn't visible in px-based
72
+ // spacing. A finer step (and matching $accuracy) keeps the rem rounding
73
+ // below the threshold where it reads as a step, and lets endpoints
74
+ // actually reach their declared min/max instead of stopping short.
75
+ @return fc.zeus-cqi-fluid($min-rem, $max-rem, $c-floor, $c-ceil, "rem", 3, 0.01);
71
76
  }
@@ -36,7 +36,7 @@ $_zp: "";
36
36
  // grid inside a narrow column made every token (spacing/borders/icons/
37
37
  // typography) smaller with each level. Use the opt-in .cq class below on
38
38
  // any specific .grid that should size its own contents.
39
- body, main, .#{$_zp}container {
39
+ body, .#{$_zp}container {
40
40
  container-type: inline-size;
41
41
  }
42
42
 
@@ -47,7 +47,6 @@ $_zp: "";
47
47
  body {
48
48
  color: var(--color-text);
49
49
  background-color: var(--color-background);
50
- overflow-wrap: anywhere;
51
50
  word-break: break-word;
52
51
  @include text(body);
53
52
  }