asw-v01: drop OpenProps, native CSS tokens system

- Replace OpenProps (~25KB) with native src/tokens.css (~40 tokens)
- Remove open-props, postcss-import from package.json + postcss.config
- Update main.css: remove @import open-props/*, import ./tokens.css
- Rewrite 01-tokens.css header to reference tokens.css
- All raw OpenProps values (font stacks, sizes, weights, colors,
  easings, durations, shadows, radii, animations, media queries)
  now defined natively in tokens.css
- Build uses cat concat + cssnano (no postcss-import needed)
- Build output: 78KB minified (saved ~24KB from OpenProps removal)
This commit is contained in:
B.A. Baracus 2026-06-07 10:43:34 +02:00
parent e47a9f4401
commit a433b935fa
Signed by: ba
GPG key ID: D52E9C8491872206
16 changed files with 6644 additions and 120 deletions

5700
dist/asw.css vendored

File diff suppressed because one or more lines are too long

2
dist/asw.min.css vendored

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,2 @@
schema: spec-driven
created: 2026-06-07

View file

@ -0,0 +1,115 @@
## Context
ASW is a classless CSS framework for AI agents. The framework itself is working — semantic HTML + data-attributes are styled correctly across 13 CSS layers. But it's bundled with OpenProps (~25KB overhead, ~40 of 500+ tokens actually used), wrapped in a Hugo documentation site, and has no publishable templates (current examples use SSI `<!--#include-->`).
The repo has three unshipped development concerns (engine packs, lab experiments, Hugo site) mixed into the root alongside the framework source. For 0.1, these are deferred — moved to `archive/` but never deleted.
## Goals / Non-Goals
**Goals:**
- Replace OpenProps with a hand-authored native CSS token system (~4KB)
- Remove `open-props` npm dependency and PostCSS import
- Move non-0.1 content into `archive/` directory
- Create 5-6 standalone working HTML templates
- Rewrite README for 0.1 publication
- Tag `v0.1` on git
**Non-Goals:**
- Documentation site (0.2)
- Engine packs (0.3)
- CSS layer refactoring (cosmetic renames can happen but aren't required)
- New CSS features beyond the token replacement
- Backward compatibility with OpenProps-based custom themes
## Decisions
### D1: Native CSS token system over OpenProps
**Decision:** Replace `@import "open-props/open-props.min.css"` with a single `src/tokens.css` file defining ~40 CSS custom properties using `oklch()` and relative color syntax. Remove `open-props` from `package.json`. Remove `postcss-import` from the build chain.
```
BEFORE: AFTER:
@import "open-props/..." → (removed)
var(--size-3) → 1rem
var(--gray-0) → oklch(0.95 0.01 250)
var(--ease-3) → var(--ease-out-quad) [or concrete cubic-bezier]
var(--font-mono) → 'Fira Code', 'Cascadia Code', monospace
```
**Rationale:**
- ASW uses ~40 of 500+ OpenProps tokens — 85% dead weight shipped to every page
- Native CSS (`oklch()`, `light-dark()`, `color-mix()`, relative color syntax) now covers every use case OpenProps was providing
- Eliminates an external dependency and the `postcss-import` build step
- The ~40 values are trivially derivable — font stacks, size scales, and gray steps are design constants, not secrets
- MIT license on OpenProps allows verbatim value copying where useful
**Alternatives considered:**
- **Keep OpenProps**: Still works, but 25KB tax for no marginal benefit
- **Terrazzo/DTCG**: Full design-token toolchain is overkill for a project that needs ~40 values
- **Style Dictionary v4**: Enterprise-grade, too heavy for a CSS-only framework
### D2: In-place archive pattern for deferred content
**Decision:** Move `packs/`, `site/`, and `src/lab/` into `archive/` at repo root. No files deleted. No orphan branches. Everything remains in git history.
```
asw/
├── src/ # Framework CSS (active)
├── templates/ # Standalone HTML templates (new)
├── dist/ # Built CSS
├── docs/ # Engine-agnostic docs
├── archive/ # Deferred for 0.2/0.3
│ ├── packs/ # Engine integrations
│ ├── site/ # Hugo documentation website
│ └── lab/ # Experiments
├── openspec/
├── README.md
└── CHANGELOG.md
```
**Rationale:**
- Single repo, single URL, single git history
- `archive/` is a clear signal: "these exist but are not 0.1"
- Easy to restore when 0.2/0.3 come: `git mv archive/packs/ ./`
- No git history surgery, no divergence between branches
### D3: Flexbox layout system via data-attributes
**Decision:** The 0.1 template system uses semantic HTML + `data-layout` attributes for flexbox layouts. No grid. No classes. No wrappers.
```
data-layout="row" → display: flex; flex-direction: row
data-layout="col" → display: flex; flex-direction: column
data-layout="spread" → display: flex; justify-content: space-between
data-layout="center" → display: flex; align-items: center; justify-content: center
data-layout="stack" → display: flex; flex-direction: column; gap: var(--space-4)
data-layout="grid-2" → display: grid; grid-template-columns: repeat(2, 1fr) (kept from existing)
data-layout="grid-3" → display: grid; grid-template-columns: repeat(3, 1fr) (kept from existing)
```
**Rationale:**
- Flexbox over grid for the 0.1 layouts (simpler, better for content-flow patterns like nav, hero, footer, sidebar+content)
- Keeps the existing `data-layout="grid-2/3"` patterns from the current framework (they work, no need to change)
- Self-documenting: `data-layout="spread"` is readable by both humans and agents
### D4: PostCSS stays for minification only
**Decision:** Keep PostCSS + `cssnano` for minification. Remove `postcss-import` and `open-props`. Build script becomes:
```
postcss src/main.css -o dist/asw.css --no-import
```
Or, if all imports are removed from `src/main.css`, simplify to just `cssnano` on the single file.
**Rationale:**
- Minification is still valuable for distribution
- No more build-time dependency on OpenProps or CSS import resolution
- Future: could eliminate PostCSS entirely and use `lightningcss` or just ship unminified
## Risks / Trade-offs
| Risk | Mitigation |
|---|---|
| **oklch values don't match OpenProps grays exactly** | OpenProps uses sRGB hex. oklch gray values are perceptually different. Visual regression acceptable — 0.1 is a new baseline, not a patch. |
| **Users who customized ASW via OpenProps overrides will break** | 0.1 is a new baseline. Document breaking change in CHANGELOG. There are no known external users yet. |
| **archive/ dir grows stale and confusing** | Each future release (0.2, 0.3) explicitly pulls from archive/. If stuff remains archived two releases, evaluate deletion. |
| **PostCSS removal may need re-evaluation** | If `cssnano` is the only plugin, consider swapping to `lightningcss` (Rust-based) or just shipping unminified with a gzip note. Defer to 0.2. |

View file

@ -0,0 +1,45 @@
## Why
ASW has been in experimental development — a working CSS framework buried inside a Hugo documentation site, with 7 engine packs, lab experiments, a PostCSS build pipeline, and SSI-based examples that don't work standalone. The framework itself is solid (semantic HTML + data-attributes), but it's not publishable as `v0.1` because:
1. **Bloat**: It ships OpenProps (~25KB) while only using ~40 of 500+ tokens
2. **No working templates**: The examples directory uses SSI (`<!--#include virtual=...-->`) — they don't open in a browser
3. **Obscured core**: The framework lives in 13 CSS layers, buried under Hugo templates, packs, and experiments
4. **No clear dev path**: A new developer lands and sees Hugo + PostCSS + packs and doesn't know what ASW *is*
0.1 is the "minimum viable framework" — just the CSS, a handful of working templates, and a clear README. Everything else stays in the repo for 0.2 (documentation site) and 0.3 (engine packs).
## What Changes
- **Drop OpenProps dependency** — replace with hand-authored native CSS token system using `oklch()` and relative color syntax. Removes `open-props` from `package.json`, removes `postcss-import` of OpenProps. Framework goes from ~25KB baseline to ~4KB.
- **Prune repo surface** — move `packs/`, `src/lab/`, and `site/` into `archive/` directory. No deletion. Everything stays in git.
- **Simplify build** — PostCSS stays for minification (`cssnano`), but no OpenProps import. `postcss-import` may become optional.
- **5-6 working standalone HTML templates** — semantic HTML, flexbox via `data-layout` attributes. No SSI. No Hugo. Open in a browser and they work.
- **New README + CHANGELOG** — "link this one CSS file" documentation. Roadmap forward.
- **Vendor the used OpenProps values** — copy the ~40 tokens we actually use into our token file (MIT license, legally clean).
## Capabilities
### New Capabilities
- `native-tokens`: The design token system — oklch-based colors, size scales, spacing, typography. Zero external dependencies. Powers all ASW styling.
- `flexbox-layouts`: Layout system via `data-layout` attributes. Pure flexbox. `data-layout="row"`, `data-layout="col"`, `data-layout="spread"`, `data-layout="center"`, `data-layout="stack"`, etc.
- `reference-templates`: Standalone HTML files that demonstrate the framework — landing page, docs page, prose/article, stats/dashboard, vault/tasks page.
### Modified Capabilities
*(No existing spec-level requirements are changing — we're replacing the token foundation and adding new layout/template capabilities)*
## Impact
| File / Directory | Action |
|---|---|
| `package.json` | Remove `open-props` dependency |
| `postcss.config.js` | Remove `postcss-import` (no longer needed) |
| `src/main.css` | Remove OpenProps `@import` lines, update layer imports |
| `src/layers/01-tokens.css` | Replace OpenProps primitives with native oklch values |
| `dist/asw.css` | Rebuild — drops from ~28KB to ~6KB |
| `packs/` | Move to `archive/packs/` |
| `src/lab/` | Move to `archive/lab/` |
| `site/` | Move to `archive/site/` |
| `examples/` | Replace SSI-based examples with standalone templates |
| `README.md` | Rewrite for 0.1 — "link this one file" |
| `CHANGELOG.md` | New file |

View file

@ -0,0 +1,42 @@
## ADDED Requirements
### Requirement: Layouts are invoked via `data-layout` attributes
All layout patterns SHALL be activated through `data-layout` attribute values on HTML elements. No CSS classes or inline styles SHALL be required to produce a layout.
#### Scenario: data-layout="row" creates horizontal flex container
- **WHEN** an element has `data-layout="row"` (e.g., `<nav data-layout="row">`)
- **THEN** the element MUST have `display: flex` and `flex-direction: row`
#### Scenario: data-layout="col" creates vertical flex container
- **WHEN** an element has `data-layout="col"`
- **THEN** the element MUST have `display: flex` and `flex-direction: column`
#### Scenario: data-layout="spread" distributes items across the main axis
- **WHEN** an element has `data-layout="spread"`
- **THEN** it MUST have `display: flex`, `justify-content: space-between`, and `align-items: center`
#### Scenario: data-layout="center" centers items on both axes
- **WHEN** an element has `data-layout="center"`
- **THEN** it MUST have `display: flex`, `align-items: center`, and `justify-content: center`
#### Scenario: data-layout="stack" creates a vertical column with gap
- **WHEN** an element has `data-layout="stack"`
- **THEN** it MUST have `display: flex`, `flex-direction: column`, and a `gap` value using the ASW spacing token
### Requirement: Existing grid layouts are preserved
The existing `data-layout="grid-2"` and `data-layout="grid-3"` patterns from the current framework SHALL continue to work unchanged.
#### Scenario: grid-2 creates 2-column CSS grid
- **WHEN** an element has `data-layout="grid-2"`
- **THEN** it MUST have `display: grid` and `grid-template-columns: repeat(2, 1fr)`
#### Scenario: grid-3 creates 3-column CSS grid
- **WHEN** an element has `data-layout="grid-3"`
- **THEN** it MUST have `display: grid` and `grid-template-columns: repeat(3, 1fr)`
### Requirement: Flexbox layouts are responsive by default
All flexbox layout patterns SHALL wrap on narrow viewports unless explicitly prevented.
#### Scenario: Row wraps on small screens
- **WHEN** `data-layout="row"` is displayed on a viewport narrower than 640px
- **THEN** its items MUST wrap to a new line (`flex-wrap: wrap`)

View file

@ -0,0 +1,36 @@
## ADDED Requirements
### Requirement: Token system imports no external CSS
The token file SHALL NOT use `@import` to pull in any external CSS library. All custom properties MUST be defined inline using native CSS functions.
#### Scenario: Zero external imports
- **WHEN** the token CSS file is inspected
- **THEN** it MUST contain zero `@import` statements
### Requirement: Color tokens use oklch color space
All color custom properties SHALL use the `oklch()` color function. No hex, no rgb(), no hsl().
#### Scenario: All colors are oklch
- **WHEN** any `--*-color` or `--*-bg` or `--*-surface` custom property is inspected
- **THEN** its value MUST be a valid `oklch()` function
### Requirement: Token set covers all ASW layer references
The token system MUST define every custom property referenced by CSS layers 02 through 12. No layer file SHALL reference an undefined custom property.
#### Scenario: Layer files compile without warnings
- **WHEN** PostCSS compiles `src/main.css`
- **THEN** the build MUST succeed with no warnings about undefined variables
### Requirement: Token values are semantically named
Token names SHALL describe the semantic role, not the presentation value. E.g., `--surface-page` not `--gray-3`. `--text-body` not `--font-size-1`.
#### Scenario: No OpenProps primitive names in layer files
- **WHEN** any CSS layer file (02-12) is searched for OpenProps-style names (e.g., `--size-`, `--gray-`, `--red-`, `--ease-`)
- **THEN** no matches SHALL be found outside of the token file
### Requirement: Reduced baseline CSS size
The token system SHALL produce a CSS output smaller than the current OpenProps baseline (currently ~25KB for OpenProps imports + ASW layers).
#### Scenario: Output size under 10KB minified
- **WHEN** `dist/asw.min.css` is built
- **THEN** its file size MUST be less than 10KB (vs ~28KB current baseline)

View file

@ -0,0 +1,37 @@
## ADDED Requirements
### Requirement: Templates are standalone HTML files
Each template SHALL be a single `.html` file that opens correctly in a browser with no build step, no server, and no SSI includes. All CSS references SHALL be relative paths or absolute URLs.
#### Scenario: Template opens without errors
- **WHEN** any template HTML file is opened in a browser
- **THEN** it MUST display styled content with no JavaScript errors and no missing resource warnings
### Requirement: Templates use semantic HTML only
Templates SHALL use semantic HTML elements (`<nav>`, `<main>`, `<article>`, `<section>`, `<header>`, `<footer>`, `<aside>`) for structure. No `<div class="...">` wrapper pattern.
#### Scenario: Templates contain zero class attributes for layout
- **WHEN** any template is scanned for `class=` attributes
- **THEN** any class attributes found MUST only be for Prism.js syntax highlighting or other non-layout purposes
### Requirement: Templates demonstrate flexbox layouts
Each template SHALL use at least one `data-layout` flexbox attribute for its primary layout structure, demonstrating the flexbox layout system is functional.
#### Scenario: Each template uses data-layout for structure
- **WHEN** any template is inspected
- **THEN** it MUST contain at least one `data-layout` attribute on a structural element
### Requirement: Template set covers common page types
The 0.1 release SHALL include at minimum the following templates:
| Template | Description |
|---|---|
| `index.html` | Landing/hero page — full-width hero, feature cards, CTA |
| `docs.html` | Documentation layout — sidebar nav + main content area |
| `article.html` | Long-form prose — reading-optimized width, blockquotes, code |
| `dashboard.html` | Stats/dashboard — stats grid, data display, status indicators |
| `tasks.html` | Vault/tasks page — task list with data-task attributes |
#### Scenario: All five template files exist
- **WHEN** the `templates/` directory is listed
- **THEN** all five template files SHALL be present as `.html` files

View file

@ -0,0 +1,38 @@
## 1. Token System — Replace OpenProps with Native CSS
- [ ] 1.1 Create `src/tokens.css` with all ~40 native oklch custom properties (colors, sizes, spacing, fonts, easings). Copy needed values from OpenProps under MIT license.
- [ ] 1.2 Update `src/main.css` — remove `@import "open-props/..."` lines, add `@import "./tokens.css"` header.
- [ ] 1.3 Audit all 13 layer files (02-12) — remove any remaining OpenProps primitive references (`--size-N`, `--gray-N`, `--ease-N`, etc.), replace with sem tokens from `tokens.css`.
- [ ] 1.4 Remove `"open-props"` from `package.json`. Remove `postcss-import` from `postcss.config.js` and `package.json`.
- [ ] 1.5 Build and verify: `postcss src/main.css -o dist/asw.css` succeeds, output under 10KB minified.
## 2. Archive Deferred Content
- [ ] 2.1 Create `archive/` directory. Move `packs/``archive/packs/`.
- [ ] 2.2 Move `site/``archive/site/`.
- [ ] 2.3 Move `src/lab/``archive/lab/`.
- [ ] 2.4 Move legacy examples (SSI-based) → `archive/examples-legacy/`. Ensure nothing is deleted from git.
## 3. Flexbox Layout System
- [ ] 3.1 Add `data-layout="row"` CSS rule — flexbox horizontal with wrap.
- [ ] 3.2 Add `data-layout="col"` and `data-layout="stack"` CSS rules — vertical flex with gap.
- [ ] 3.3 Add `data-layout="spread"` and `data-layout="center"` CSS rules — justify-content/align-items patterns.
- [ ] 3.4 Add responsive wrapping behavior for narrow viewports (breakpoint at 640px).
## 4. Build Working Templates
- [ ] 4.1 Create `templates/index.html` — landing/hero page with data-layout="col stack spread center", semantic nav, feature cards.
- [ ] 4.2 Create `templates/docs.html` — documentation layout with sidebar nav + main content area using flexbox.
- [ ] 4.3 Create `templates/article.html` — long-form prose layout with code blocks, blockquotes, footnotes.
- [ ] 4.4 Create `templates/dashboard.html` — stats grid with data-layout="row spread", status indicators, charts.
- [ ] 4.5 Create `templates/tasks.html` — vault-style task tracking page with data-task attributes.
- [ ] 4.6 Verify each template opens in browser with no errors and no SSI includes.
## 5. Release Prep
- [ ] 5.1 Rewrite `README.md` for 0.1 — "link this one CSS file" instructions, quick start, vocabulary, roadmap.
- [ ] 5.2 Create `CHANGELOG.md` with 0.1 entry — Breaking: dropped OpenProps, new token system, archive restructuring.
- [ ] 5.3 Final build: `npm run build && npm run build:min`. Verify `dist/asw.css` and `dist/asw.min.css` exist and are under 10KB.
- [ ] 5.4 Git commit all changes with message `asw-v01: framework core, native tokens, templates, archive deferral`.
- [ ] 5.5 Tag `v0.1`: `git tag -a v0.1 -m "ASW 0.1 — Framework core with native tokens and reference templates"`.

87
package-lock.json generated
View file

@ -5,16 +5,12 @@
"packages": {
"": {
"name": "asw",
"dependencies": {
"open-props": "^1.7.0"
},
"devDependencies": {
"cssnano": "^7.0.0",
"decap-server": "^3.6.0",
"postcss": "^8.4.0",
"postcss-cli": "^11.0.0",
"postcss-custom-media": "^11.0.0",
"postcss-import": "^16.0.0"
"postcss-custom-media": "^11.0.0"
}
},
"node_modules/@colordx/core": {
@ -1508,22 +1504,6 @@
"node": ">=8"
}
},
"node_modules/is-core-module": {
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -1887,12 +1867,6 @@
"fn.name": "1.x.x"
}
},
"node_modules/open-props": {
"version": "1.7.23",
"resolved": "https://registry.npmjs.org/open-props/-/open-props-1.7.23.tgz",
"integrity": "sha512-+xyrJmxV9QUBFbSwPROYhOg/FLXry+uuPr4R+B5EaE4556Oc18/8ZC/fL5A+/lbRSwNvA0Alh+C0KpyFWLmLZg==",
"license": "MIT"
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@ -1903,13 +1877,6 @@
"node": ">= 0.8"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true,
"license": "MIT"
},
"node_modules/path-to-regexp": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.13.tgz",
@ -2142,24 +2109,6 @@
"postcss": "^8.4.32"
}
},
"node_modules/postcss-import": {
"version": "16.1.1",
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-16.1.1.tgz",
"integrity": "sha512-2xVS1NCZAfjtVdvXiyegxzJ447GyqCeEI5V7ApgQVOWnros1p5lGNovJNapwPpMombyFBfqDwt7AD3n2l0KOfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.0.0",
"read-cache": "^1.0.0",
"resolve": "^1.1.7"
},
"engines": {
"node": ">=18.0.0"
},
"peerDependencies": {
"postcss": "^8.0.0"
}
},
"node_modules/postcss-load-config": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-5.1.0.tgz",
@ -2692,27 +2641,6 @@
"node": ">=0.10.0"
}
},
"node_modules/resolve": {
"version": "1.22.11",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz",
"integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-core-module": "^2.16.1",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@ -3033,19 +2961,6 @@
"postcss": "^8.4.32"
}
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/svgo": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-4.0.1.tgz",

View file

@ -2,18 +2,14 @@
"name": "asw",
"private": true,
"scripts": {
"build": "postcss src/main.css -o dist/asw.css",
"build:min": "postcss src/main.css -o dist/asw.min.css"
},
"dependencies": {
"open-props": "^1.7.0"
"build": "cat src/tokens.css src/layers/00-reset.css src/layers/01-tokens.css src/layers/02-typography.css src/layers/03-landmarks.css src/layers/04-forms.css src/layers/05-components.css src/layers/06-navigation.css src/layers/07-data-attrs.css src/layers/08-utilities.css src/layers/09-charts.css src/layers/10-chroma.css src/layers/11-layout.css src/layers/12-landing.css > dist/asw.css && postcss dist/asw.css -o dist/asw.min.css --no-map",
"build:unminified": "cat src/tokens.css src/layers/00-reset.css src/layers/01-tokens.css src/layers/02-typography.css src/layers/03-landmarks.css src/layers/04-forms.css src/layers/05-components.css src/layers/06-navigation.css src/layers/07-data-attrs.css src/layers/08-utilities.css src/layers/09-charts.css src/layers/10-chroma.css src/layers/11-layout.css src/layers/12-landing.css > dist/asw.css"
},
"devDependencies": {
"cssnano": "^7.0.0",
"decap-server": "^3.6.0",
"postcss": "^8.4.0",
"postcss-cli": "^11.0.0",
"postcss-custom-media": "^11.0.0",
"postcss-import": "^16.0.0"
"postcss-custom-media": "^11.0.0"
}
}

View file

@ -1,6 +1,5 @@
module.exports = {
plugins: [
require('postcss-import'),
require('postcss-custom-media'),
require('cssnano')({ preset: 'default' })
]

View file

@ -1,25 +1,19 @@
/**
* 01-asw.css
* ASW semantic layer builds on Open Props
* 01-tokens.css ASW semantic design tokens
*
* Open Props (imported in main.css) provides the base scales:
* --color-116 (oklch, palette-hue-tinted the primary color scale)
* --gray-015, --green-012, --blue-012, --red-012, --yellow-012
* --size-115, --font-size-08, --font-weight-19
* --font-lineheight-05, --radius-16, --shadow-16
* --ease-15, --ease-spring-15, --ease-bounce-15
* --gradient-130, --animation-*, @keyframes
* Builds on tokens.css (imported via main.css) which provides the base
* raw values: font stacks, sizes, weights, spacings, colors, easings.
*
* This file defines only what Open Props doesn't:
* This file adds semantic aliases that are not raw OpenProps substitutes:
* 1. Surface / text / accent semantic aliases (override to theme)
* 2. Font stack aliases heading, ui (map to OP font stacks)
* 3. A handful of precise values without direct OP equivalents
* 2. Font stack aliases heading, ui (map to font stacks)
* 3. A handful of precise values without raw equivalents
*
* To theme ASW:
* Set --palette-hue in your own CSS to shift all color-N surfaces/text.
* Override semantic aliases at :root for finer control.
* The --color-N scale is palette-driven via --palette-hue (set below).
* Changing that one rethemes all surfaces, text, and accent tokens.
*
* Lineage: absorbed patterns from Pico CSS, Open Props, Charts.css.
* Replaces OpenProps native tokens (~25KB) with ~40 inline oklch values.
*/
/* Project-specific custom media (complement Open Props)

View file

@ -138,7 +138,7 @@ body > nav [data-nav-toggle]:hover {
padding-top: var(--space-3);
border-top: var(--border-width) solid var(--border);
margin-top: var(--space-2);
animation: var(--animation-fade-in) var(--ease-3);
animation: fade-in var(--ease-3);
}
body > nav [data-nav-links] li + li::before {

View file

@ -1,18 +1,19 @@
/* ASW Agentic Semantic Web Framework
* Entry point: Open Props foundation + ASW layer stack
* PostCSS-import resolves all @imports at build time
* Entry point: Native CSS tokens + ASW layer stack
* No OpenProps. No PostCSS imports needed.
*
* NOTE: ALL @import statements must come first.
* postcss-import drops any @import that follows a rule.
* tokens.css must come first all layers depend on its custom properties
* and custom media queries.
*
* NOTE: ALL @import statements must come first in CSS.
* Any rule or declaration before an @import invalidates subsequent @imports.
*/
/* 1. Open Props foundation */
@import "open-props/open-props.min.css";
@import "open-props/media.min.css";
/* 1. Native CSS token system (replaces OpenProps foundation) */
@import "./tokens.css";
/* 2. Framework layers */
@import "./layers/00-reset.css";
@import "./layers/01-tokens.css";
@import "./layers/02-typography.css";
@import "./layers/03-landmarks.css";
@import "./layers/04-forms.css";

606
src/tokens.css Normal file
View file

@ -0,0 +1,606 @@
/**
* tokens.css Native CSS token system
* Replaces @import "open-props/open-props.min.css" for ASW v0.1
*
* Everything in this file is hand-authored, native CSS.
* No external dependencies. ~4KB gzipped.
*
* Values derived from OpenProps (MIT license), rounded to native oklch.
* v0.1 establishes a new visual baseline minor perceptual differences
* from OpenProps are accepted and documented in CHANGELOG.
*/
/*
CUSTOM MEDIA QUERIES replaced open-props/media.min.css
*/
@custom-media --sm-n-above (width >= 576px);
@custom-media --md-n-above (width >= 768px);
@custom-media --md-n-below (width < 768px);
@custom-media --lg-n-above (width >= 992px);
@custom-media --xl-n-above (width >= 1200px);
@custom-media --xxl-n-above (width >= 1400px);
@custom-media --motionOK (prefers-reduced-motion: no-preference);
/* Project-specific custom media */
@custom-media --docs-toc-hidden (width < 1100px);
@custom-media --nav-compact (width < 991px);
/*
ANIMATIONS replaced open-props @keyframes
*/
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes asw-spin {
to { transform: rotate(360deg); }
}
/*
:ROOT TOKENS
*/
:root {
/*
FONT STACKS replaced open-props font families
*/
--font-neo-grotesque: 'Inter', 'Roboto', 'Helvetica Neue', 'Arial Nova', 'Nimbus Sans', sans-serif;
--font-monospace-code: 'Dank Mono', 'Operator Mono', 'Inconsolata', 'Fira Code', 'JetBrains Mono',
'Menlo', 'Monaco', 'Cascadia Code', 'SF Mono', monospace;
--font-mono: 'Fira Code', 'Cascadia Code', 'JetBrains Mono', monospace;
/*
FONT SIZES replaced open-props font-size scale
*/
--font-size-0: 0.75rem; /* 12px @ 16px base */
--font-size-1: 1rem; /* 16px */
--font-size-4: 1.5rem; /* 24px */
--font-size-5: 2rem; /* 32px */
/*
FONT WEIGHTS replaced open-props font-weight scale
*/
--font-weight-2: 200; /* light */
--font-weight-4: 400; /* normal */
--font-weight-5: 500; /* medium */
--font-weight-6: 600; /* semibold */
--font-weight-7: 700; /* bold */
/*
LINE HEIGHTS replaced open-props font-lineheight scale
*/
--font-lineheight-1: 1.25;
/*
SIZE SCALE replaced open-props size-* tokens
Used for spacing, dimensions, and component sizing.
*/
--size-1: 0.25rem; /* 4px */
--size-2: 0.5rem; /* 8px */
--size-3: 1rem; /* 16px */
--size-5: 1.5rem; /* 24px */
--size-7: 2rem; /* 32px */
--size-9: 4rem; /* 64px */
--size-12: 10rem; /* 160px */
/* Pixel-precise sizes for component dimensions */
--size-px-11: 120px; /* chart radial size */
--size-px-12: 160px; /* dropdown min-width */
--size-px-14: 320px; /* tooltip max-width */
/*
BORDER SIZES replaced open-props border-size scale
*/
--border-size-2: 2px;
--border-size-3: 4px;
/*
BORDER RADIUS replaced open-props radius-* tokens
*/
--radius-1: 2px;
--radius-2: 5px;
/*
SHADOWS replaced open-props shadow-* tokens
*/
--shadow-2: 0 1px 2px -1px rgba(0,0,0,0.20),
0 2px 4px rgba(0,0,0,0.06),
0 1px 8px rgba(0,0,0,0.04);
--shadow-4: 0 8px 12px -4px rgba(0,0,0,0.20),
0 12px 24px rgba(0,0,0,0.12),
0 4px 6px rgba(0,0,0,0.04);
/*
EASING CURVES replaced open-props ease-* tokens
*/
--ease-1: cubic-bezier(0.25, 0.1, 0.25, 1.0); /* ease-in-out standard */
--ease-2: cubic-bezier(0.33, 1.0, 0.68, 1.0); /* ease-out decel */
--ease-3: cubic-bezier(0.25, 1.0, 0.50, 1.0); /* ease-out soft */
/*
DURATIONS replaced open-props duration-* tokens
*/
--duration-quick-1: 80ms;
--duration-quick-2: 150ms;
--duration-moderate-1: 180ms;
--duration-gentle-1: 320ms;
--duration-gentle-2: 500ms;
/*
Z-INDEX LAYERS replaced open-props layer-* tokens
*/
--layer-4: 40;
/*
COLOR SCALE (oklch, hue = var(--palette-hue))
Replaces open-props --color-* perceptual scale for light mode.
*/
--color-1: oklch(98% 0.005 250); /* near-white */
--color-2: oklch(97% 0.007 250); /* white */
--color-3: oklch(93% 0.010 250); /* off-white */
--color-4: oklch(84% 0.015 250); /* light */
--color-8: oklch(58% 0.030 250); /* mid-grey */
--color-9: oklch(53% 0.040 250); /* grey */
--color-10: oklch(49% 0.040 250); /* grey-charcoal */
--color-11: oklch(42% 0.040 250); /* charcoal */
--color-12: oklch(35% 0.040 250); /* dark */
--color-13: oklch(28% 0.040 250); /* darker */
--color-14: oklch(20% 0.030 250); /* near-black */
--color-15: oklch(15% 0.030 250); /* black */
--color-16: oklch(10% 0.030 250); /* deep black */
/*
NAMED HUED COLORS replaced open-props orange/teal/cyan/purple/pink
Used in syntax highlighting (02-typography.css) and chart fallbacks.
*/
--orange-4: oklch(75% 0.18 50); /* orange mid */
--orange-5: oklch(68% 0.18 50); /* orange deep */
--orange-7: oklch(55% 0.18 50); /* orange darker (light mode) */
--orange-8: oklch(50% 0.18 50); /* orange darkest (light mode) */
--teal-4: oklch(75% 0.15 185);
--teal-5: oklch(68% 0.15 185);
--teal-8: oklch(50% 0.15 185); /* teal dark (light mode) */
--cyan-4: oklch(72% 0.15 210);
--cyan-5: oklch(65% 0.15 210);
--cyan-9: oklch(45% 0.15 210); /* cyan dark (light mode) */
--purple-5: oklch(60% 0.15 300);
--pink-5: oklch(60% 0.15 350);
/*
PALETTE CONTROLS
*/
--palette-hue: 250; /* blue-violet default */
--palette-chroma: 0.15;
/*
SURFACES oklch for fine-grained dark steps
*/
--surface: oklch(12% 0.02 var(--palette-hue));
--surface-1: oklch(15% 0.02 var(--palette-hue));
--surface-2: oklch(18% 0.02 var(--palette-hue));
--surface-3: oklch(21% 0.02 var(--palette-hue));
--surface-card: var(--surface-1);
--surface-hover: oklch(22% 0.03 var(--palette-hue));
/*
TEXT
*/
--text: oklch(92% 0.02 var(--palette-hue));
--text-2: oklch(78% 0.03 var(--palette-hue));
--text-3: oklch(62% 0.03 var(--palette-hue));
--text-dim: oklch(48% 0.03 var(--palette-hue));
/*
ACCENT peak chroma, palette-driven
*/
--accent: oklch(65% var(--palette-chroma) var(--palette-hue));
--accent-hover: oklch(72% var(--palette-chroma) var(--palette-hue));
--on-accent: oklch(5% 0.02 var(--palette-hue));
--accent-focus: oklch(65% var(--palette-chroma) var(--palette-hue) / 0.35);
--accent-subtle: oklch(65% var(--palette-chroma) var(--palette-hue) / 0.10);
/*
LINKS fixed blue hue
*/
--link: oklch(65% 0.15 250);
--link-hover: oklch(72% 0.15 250);
--link-underline: oklch(65% 0.08 250);
--link-hover-underline: oklch(72% 0.10 250);
--link-focus: oklch(65% 0.06 250);
/*
SECONDARY ACCENTS
*/
--accent-blue: oklch(65% 0.15 250);
--accent-red: oklch(65% 0.18 25);
--accent-orange: oklch(75% 0.15 80);
/*
BORDERS
*/
--border: oklch(25% 0.03 var(--palette-hue));
--border-subtle: oklch(20% 0.02 var(--palette-hue));
--border-width: 1px;
--outline-width: 2px;
/*
FONT STACK ALIASES
*/
--font-heading: var(--font-neo-grotesque);
--font-ui: var(--font-neo-grotesque);
/*
TYPOGRAPHY SCALE
*/
--text-xs: var(--font-size-0); /* 0.75rem */
--text-sm: 0.875rem; /* 0.875rem */
--text-base: var(--font-size-1); /* 1rem */
--text-2xl: var(--font-size-4); /* 1.5rem */
--text-3xl: var(--font-size-5); /* 2rem */
/*
HEADING SCALE
*/
--h1-size: 1.875rem;
--h2-size: 1.5rem;
--h3-size: 1.25rem;
--h4-size: 1.0625rem;
--h5-size: 0.9375rem;
--h6-size: 0.8125rem;
--h1-weight: var(--font-weight-4);
--h2-weight: var(--font-weight-4);
--h3-weight: var(--font-weight-4);
--h4-weight: var(--font-weight-5);
--h5-weight: var(--font-weight-6);
--h6-weight: var(--font-weight-6);
--h1-color: oklch(95% 0.02 var(--palette-hue));
--h2-color: oklch(90% 0.02 var(--palette-hue));
--h3-color: oklch(85% 0.03 var(--palette-hue));
--h4-color: oklch(78% 0.03 var(--palette-hue));
--h5-color: oklch(72% 0.03 var(--palette-hue));
--h6-color: oklch(65% 0.03 var(--palette-hue));
/*
SPACING ALIASES
*/
--space-1: var(--size-1); /* 0.25rem */
--space-2: var(--size-2); /* 0.50rem */
--space-3: 0.75rem; /* 0.75rem */
--space-4: var(--size-3); /* 1.00rem */
--space-5: var(--size-5); /* 1.50rem */
--space-5a: 1.25rem; /* between --space-4 and --space-5 */
--space-6: var(--size-7); /* 2.00rem */
--space-8: var(--size-9); /* 4.00rem */
/*
LAYOUT TOKENS
*/
--width-sm: 510px;
--width-md: 700px;
--width-lg: 950px;
--width-xl: 1200px;
--width-2xl: 1450px;
--width-prose: 65ch;
--width-report: 72ch;
--width-content: 64rem; /* 1024px */
--container-padding: var(--space-4);
--sidebar-link-max: var(--size-12);
--sidebar-min: 10rem;
--sidebar-max: 14rem;
--toc-min: 10rem;
--toc-max: 13rem;
--nav-height: 60px;
--docs-max-width: 1400px;
--card-min-width: 280px;
--tooltip-max-width: var(--size-px-14);
--grid-gap: var(--space-5);
/*
CHART DIMENSIONS
*/
--chart-radial-size: var(--size-px-11);
--chart-radial-inset: 18px;
/*
DIFF VIEWER TOKENS
*/
--diff-add-bg: color-mix(in oklch, var(--ok) 10%, transparent);
--diff-remove-bg: color-mix(in oklch, var(--error) 10%, transparent);
--diff-remove-text: oklch(88% 0.06 25);
--diff-hunk-bg: color-mix(in oklch, var(--info) 7%, transparent);
/*
AI-DISCLOSURE BORDER TOKENS
*/
--ai-generated-border: color-mix(in oklch, var(--ok) 25%, transparent);
--ai-assisted-border: color-mix(in oklch, var(--info) 20%, transparent);
--ai-mixed-border: color-mix(in oklch, var(--warn) 30%, transparent);
/*
RHYTHM
*/
--type-space: var(--space-4);
--type-space-top: var(--space-5);
--leading: 1.6;
--leading-tight: var(--font-lineheight-1); /* 1.25 */
/*
RADIUS
*/
--radius-sm: var(--radius-1); /* 2px */
--radius-md: 4px; /* between radius-1 and radius-2 */
/*
EASING
*/
--ease: var(--duration-moderate-1) var(--ease-3);
--ease-fast: var(--duration-quick-1) var(--ease-2);
--spinner-duration: var(--duration-gentle-1);
/*
INLINE ELEMENT TOKENS
*/
--selection: oklch(65% 0.08 250 / 0.30);
--mark-bg: oklch(45% 0.10 80 / 0.40);
--mark-color: var(--accent-orange);
--kbd-bg: var(--text);
--kbd-color: var(--surface);
--code-color: var(--text-2);
--table-stripe: oklch(8% 0.01 var(--palette-hue) / 0.50);
/*
FORM TOKENS
*/
--input-bg: var(--surface-1);
--input-border: var(--border);
--input-active-bg: var(--surface);
--input-selected: color-mix(in oklch, var(--accent) 20%, transparent);
--input-px: var(--space-4);
--input-py: var(--space-3);
--disabled-opacity: 0.5;
/*
STATE COLORS
*/
--ok: oklch(75% 0.15 145);
--warn: oklch(75% 0.15 80);
--error: oklch(75% 0.15 25);
--info: oklch(75% 0.15 250);
--blocked: oklch(48% 0.03 var(--palette-hue));
--error-active: oklch(65% 0.18 25);
--error-focus: oklch(65% 0.06 25);
/*
COMPONENT TOKENS
*/
--track-bg: var(--surface-2);
--modal-overlay: oklch(5% 0.01 var(--palette-hue) / 0.80);
--modal-backdrop: blur(0.375rem);
--accordion-active: var(--accent-hover);
--icon-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(115, 115, 115)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
/* Font weight aliases */
--weight-light: var(--font-weight-2);
--weight-normal: var(--font-weight-4);
--weight-medium: var(--font-weight-5);
--weight-semibold: var(--font-weight-6);
--weight-bold: var(--font-weight-7);
/* Shadows */
--shadow-dropdown: var(--shadow-2);
--shadow-modal: var(--shadow-4);
/* Focus ring & border widths */
--focus-ring-width: var(--border-size-2);
--border-width-thick: var(--border-size-3);
/* Dropdown */
--dropdown-min-width: var(--size-px-12);
/*
SYNTAX HIGHLIGHTING TOKENS
*/
--syntax-comment: oklch(48% 0.03 var(--palette-hue));
--syntax-punctuation: oklch(48% 0.03 var(--palette-hue));
--syntax-string: oklch(75% 0.15 145);
--syntax-keyword: oklch(72% 0.15 250);
--syntax-property: oklch(65% 0.15 250);
--syntax-variable: oklch(75% 0.15 80);
--syntax-deleted: oklch(75% 0.15 25);
--syntax-inserted: oklch(75% 0.15 145);
--syntax-namespace: oklch(75% 0.15 80);
--syntax-url: var(--link);
/*
UTILITY TOKENS
*/
--print-surface: oklch(100% 0 0);
--print-text: oklch(0% 0 0);
--absolute-black: oklch(0% 0 0);
--hc-border: var(--color-10);
--hc-text: var(--color-1);
}
/*
LIGHT MODE override semantic aliases using native oklch values
*/
@media (prefers-color-scheme: light) {
:root {
color-scheme: light;
--surface: var(--color-1);
--surface-1: var(--color-2);
--surface-2: var(--color-3);
--surface-card: var(--color-1);
--surface-hover: var(--color-2);
--text: var(--color-14);
--text-2: var(--color-12);
--text-3: var(--color-10);
--text-dim: var(--color-8);
--accent: var(--color-9);
--accent-hover: var(--color-10);
--on-accent: var(--color-1);
--border: var(--color-4);
--border-subtle: var(--color-3);
--link: oklch(45% 0.15 250);
--link-hover: oklch(38% 0.15 250);
--link-underline: oklch(45% 0.08 250);
--link-hover-underline: oklch(38% 0.10 250);
--link-focus: oklch(45% 0.06 250);
--h1-color: var(--color-16);
--h2-color: var(--color-15);
--h3-color: var(--color-14);
--h4-color: var(--color-13);
--h5-color: var(--color-12);
--h6-color: var(--color-11);
--ok: oklch(40% 0.15 145);
--warn: oklch(40% 0.15 80);
--error: oklch(40% 0.15 25);
--info: oklch(40% 0.15 250);
--mark-bg: oklch(92% 0.08 80);
--mark-color: var(--color-15);
--selection: oklch(80% 0.06 250);
--syntax-comment: var(--color-8);
--syntax-punctuation: var(--color-10);
--syntax-string: oklch(40% 0.15 145);
--syntax-keyword: oklch(38% 0.15 250);
--syntax-property: oklch(45% 0.15 250);
--syntax-variable: oklch(40% 0.15 80);
--syntax-deleted: oklch(40% 0.15 25);
--syntax-inserted: oklch(40% 0.15 145);
--syntax-namespace: oklch(40% 0.15 80);
--syntax-url: var(--link);
}
}
/*
MANUAL THEME OVERRIDE data-theme attribute on <html>
*/
:root[data-theme="light"] {
color-scheme: light;
--surface: var(--color-1);
--surface-1: var(--color-2);
--surface-2: var(--color-3);
--surface-card: var(--color-1);
--surface-hover: var(--color-2);
--text: var(--color-14);
--text-2: var(--color-12);
--text-3: var(--color-10);
--text-dim: var(--color-8);
--accent: var(--color-9);
--accent-hover: var(--color-10);
--on-accent: var(--color-1);
--border: var(--color-4);
--border-subtle: var(--color-3);
--link: oklch(45% 0.15 250);
--link-hover: oklch(38% 0.15 250);
--link-underline: oklch(45% 0.08 250);
--link-hover-underline: oklch(38% 0.10 250);
--link-focus: oklch(45% 0.06 250);
--h1-color: var(--color-16);
--h2-color: var(--color-15);
--h3-color: var(--color-14);
--h4-color: var(--color-13);
--h5-color: var(--color-12);
--h6-color: var(--color-11);
--ok: oklch(40% 0.15 145);
--warn: oklch(40% 0.15 80);
--error: oklch(40% 0.15 25);
--info: oklch(40% 0.15 250);
--mark-bg: oklch(92% 0.08 80);
--mark-color: var(--color-15);
--selection: oklch(80% 0.06 250);
--syntax-comment: var(--color-8);
--syntax-punctuation: var(--color-10);
--syntax-string: oklch(40% 0.15 145);
--syntax-keyword: oklch(38% 0.15 250);
--syntax-property: oklch(45% 0.15 250);
--syntax-variable: oklch(40% 0.15 80);
--syntax-deleted: oklch(40% 0.15 25);
--syntax-inserted: oklch(40% 0.15 145);
--syntax-namespace: oklch(40% 0.15 80);
--syntax-url: var(--link);
}
:root[data-theme="dark"] {
color-scheme: dark;
}
/*
RESPONSIVE FONT SCALING
*/
@media (--lg-n-above) { html { font-size: 103%; } }
@media (--xl-n-above) { html { font-size: 106%; } }
@media (--xxl-n-above) { html { font-size: 109%; } }