feat: auto-generated docs sidebar, Decap CMS, content migration infra

Docs restructure:
- Move flat docs into section subdirs (getting-started/, core/,
  components/, reference/) with _index.md for each
- Sidebar auto-generates from content structure — no manual menu entries
- New doc pages appear automatically when created in a section

Decap CMS:
- admin/index.html + config.yml for browser-based editing
- Local mode (npx decap-server) — no OAuth needed
- Collections for all content types: docs, articles, essays, notes, pages

Hugo head.html updated for new CSS layer filenames.
decap-server added as devDependency.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ludo 2026-04-11 18:02:34 +02:00
parent 86464f3e21
commit dd810f5a63
Signed by: ludo
GPG key ID: F6E479DEFAB84D6E
22 changed files with 1624 additions and 140 deletions

View file

@ -0,0 +1,4 @@
---
title: "Core"
weight: 20
---

View file

@ -0,0 +1,362 @@
---
title: "Data Attributes"
description: "Complete reference for ASW's data-attribute vocabulary — roles, states, text modifiers, nav, and agentic-specific patterns."
type: docs
weight: 50
date: 2026-04-09
tags: ["data-attributes", "css", "reference"]
ai-disclosure: "generated"
ai-model: "claude-sonnet-4-5"
ai-provider: "Anthropic"
---
ASW uses `data-*` attributes as its entire styling API. No class names are needed. Agents can write semantic HTML with intent expressed as data attributes; the stylesheet does the rest.
---
## data-role
Semantic role indicator. Applied to the element that *is* the component.
| Value | Element | Description |
|-------|---------|-------------|
| `primary` | `<a>` | Filled CTA button |
| `secondary` | `<a>` | Outlined CTA button |
| `card` | any | Card container |
| `command-box` | `<div>` | Install/command pill with prefix glyph |
| `status-card` | `<div>` | Bordered status block |
| `diff` | `<div>` | Inline diff viewer (legacy; prefer `data-diff`) |
| `log-entry` | any | Single log line, bottom border |
| `list-item` | any | Minimal padding list item |
| `prev-next` | `<div>` | Prev/next navigation pair |
| `tag-cloud` | `<div>` | Tag cluster |
| `timeline` | `<div>` | Simple left-spine timeline (legacy; prefer `data-layout="timeline"`) |
```html
<a href="/docs/" data-role="primary">Read docs →</a>
<a href="/github/" data-role="secondary">Source</a>
<div data-role="command-box">
<span class="prefix">$</span><!-- .prefix is one of ASW's intentional class exceptions -->
npm install agentic-css
</div>
```
---
## data-status
Semantic status state. Renders with mono font and status-appropriate colour.
| Value | Colour | Use |
|-------|--------|-----|
| `awake` | accent (green) | Active, running |
| `sleeping` | muted, italic | Idle, paused |
| `blocked` | red | Waiting, error state |
| `danger` | red | Critical state |
| `warning` | orange | Caution |
| `unknown` | dim | Indeterminate |
```html
<span data-status="awake">online</span>
<span data-status="blocked">waiting on DNS</span>
<span data-status="sleeping">idle since 03:00</span>
```
---
## data-task
Task list item with state glyph. Apply to `<li>` elements.
| Value | Glyph | Colour |
|-------|-------|--------|
| `todo` | ○ | orange |
| `done` | ● | accent |
| `blocked` | ◐ | red |
```html
<ul>
<li data-task="done">Deploy nginx config</li>
<li data-task="todo">Update DNS records</li>
<li data-task="blocked">TLS cert — waiting on propagation</li>
</ul>
```
---
## data-callout
Advisory block with left border accent and optional title.
| Value | Border colour |
|-------|--------------|
| *(default)* | blue |
| `tip` | accent (green) |
| `warning` | orange |
| `error` | red |
```html
<div data-callout="tip">
<span data-callout-title>Tip</span>
<p>Use data attributes instead of class names.</p>
</div>
<div data-callout="warning">
<span data-callout-title>Warning</span>
<p>This resets the token cascade.</p>
</div>
```
---
## data-text
Text modifier. Supports multiple space-separated values.
| Value | Effect |
|-------|--------|
| `dim` | `var(--text-3)` — muted |
| `accent` | `var(--accent)` — green accent |
| `eyebrow` | mono, uppercase, spaced — section label |
| `small` | `var(--text-sm)` |
| `mono` | monospace font |
| `tagline` | larger, lighter — subtitle treatment |
```html
<p data-text="eyebrow">Getting started</p>
<h1>Token System</h1>
<p data-text="tagline">How the custom property hierarchy is structured.</p>
<p data-text="dim small">Last updated 2026-04-10</p>
<code data-text="mono accent">--accent</code>
```
---
## data-layout
Layout pattern. See [Layouts](/docs/layouts/) for the full reference.
Common values: `docs`, `hero`, `install`, `actions`, `grid-2`, `grid-3`, `card-grid`, `stats`, `prose`, `fluid`, `timeline`, `report`.
---
## data-nav
Navigation variant. Applied to `<nav>` elements.
| Value | Description |
|-------|-------------|
| `sidebar` | Vertical nav list, no pipe separators |
| `toc` | TOC nav, compact, left-border active indicator |
```html
<nav data-nav="sidebar" aria-label="Documentation">
<ul>
<li><a href="/docs/introduction/" aria-current="page">Introduction</a></li>
<li><a href="/docs/tokens/">Token System</a></li>
</ul>
</nav>
```
---
## data-subnav
Inline breadcrumb-style section nav. Slash-separated. `aria-current="page"` marks the active item.
```html
<nav data-subnav>
<a href="/vigilio/">index</a>
<a href="/vigilio/now">now</a>
<a href="/vigilio/status" aria-current="page">status</a>
</nav>
```
---
## data-tooltip / data-tooltip-position
CSS-only tooltip on hover and focus. No JavaScript.
```html
<span data-tooltip="Explained here">term</span>
<!-- Bottom placement -->
<span data-tooltip="Below the element" data-tooltip-position="bottom">term</span>
```
Tooltip content comes from the attribute value. Max-width is `var(--tooltip-max-width)`.
---
## data-badge
Inline mono pill. Used for token labels, version indicators, or icon tags.
```html
<span data-badge>&lt;/&gt;</span>
<span data-badge>v2.1</span>
<span data-badge>data=</span>
```
---
## data-diff / data-diff-line / data-diff-file
Semantic diff viewer. Renders a code diff with standard +/- gutter markers.
```html
<div data-diff>
<span data-diff-file>src/tokens.css</span>
<span data-diff-line="hunk">@@ -12,6 +12,8 @@</span>
<span data-diff-line="context"> --text: var(--gray-1);</span>
<span data-diff-line="removed"> --accent: var(--green-5);</span>
<span data-diff-line="added"> --accent: var(--green-4);</span>
<span data-diff-line="added"> --accent-hover: var(--green-3);</span>
</div>
```
---
## data-session / data-mode
Session metadata block. Used to render agent session records.
```html
<section data-session data-mode="autonomous">
<header>
<h3>Session 2847</h3>
<p data-text="dim small">2026-04-10 · 28 min · claude-sonnet-4-6</p>
</header>
<ul>
<li data-task="done">Token layer audit</li>
<li data-task="todo">Deploy docs site</li>
</ul>
</section>
```
`data-mode` values: `autonomous` (blue), `interactive` (accent).
---
## data-wikilink / data-unresolved
Knowledge-graph link style. Dotted underline distinguishes internal wiki links from standard hyperlinks.
```html
<a href="/notes/sessions/" data-wikilink>Sessions</a>
<!-- Unresolved — link target doesn't exist yet -->
<a href="#" data-wikilink data-unresolved>Missing Note</a>
```
---
## data-tag / data-hash
Inline taxonomy labels.
```html
<a href="/tags/agentic/" data-tag>agentic</a>
<span data-hash>a3f9c12</span>
```
`data-tag` prepends a `#` character. `data-hash` renders in mono with tight letter-spacing.
---
## data-redacted
Privacy-aware redaction. Renders content as a black bar. Assistive technology should use `aria-label` for a screen-reader replacement.
```html
<!-- Full redaction -->
<span data-redacted aria-label="redacted">sk-ant-abc123</span>
<!-- Hover to reveal -->
<span data-redacted="reveal" aria-label="classified content">classified</span>
<!-- Shows [REDACTED] label, hides children -->
<span data-redacted="label" aria-label="API key">sk-ant-abc123</span>
```
---
## ai-disclosure
Marks AI content provenance with a left border indicator.
| Value | Border |
|-------|--------|
| `ai-generated` | subtle accent |
| `ai-assisted` | lighter accent |
| `autonomous` | full accent |
| `mixed` | amber |
```html
<section ai-disclosure="autonomous">
<p>This section was written entirely by an autonomous agent.</p>
</section>
```
Add `data-show-disclosure` to render an inline `[autonomous]` badge after the content.
---
## data-reading-progress
CSS-only scroll progress bar. Apply to `<body>` or any scrolling container. Uses `animation-timeline: scroll()` — Chrome 115+, Firefox 110+.
```html
<body data-reading-progress>
```
Renders a thin accent-colored bar fixed to the top of the viewport.
---
## data-visible
Responsive visibility control.
| Value | Effect |
|-------|--------|
| `desktop` | Hidden on mobile |
| `mobile` | Hidden on desktop |
```html
<span data-visible="desktop">Full label</span>
<span data-visible="mobile">Short</span>
```
---
## data-abstract / data-byline / data-section
Document metadata patterns for structured article content.
```html
<article>
<header>
<h1>Title</h1>
<p data-byline>By Vigilio Desto · 2026-04-10</p>
<p data-abstract>A concise summary of the article's argument and scope.</p>
</header>
<section data-section>
<h2 data-section-header>Introduction</h2>
<p>Body content.</p>
</section>
</article>
```
---
## Related
- [Layouts](/docs/layouts/) — `data-layout` values in full
- [Semantic HTML](/docs/semantic-html/) — how plain elements are styled without attributes
- [Components](/docs/components/) — callouts, tasks, and session blocks in detail

View file

@ -0,0 +1,128 @@
---
title: "Reset"
description: "What ASW's reset layer does, where it came from, and what it deliberately leaves alone."
type: docs
weight: 60
date: 2026-04-09
tags: ["reset", "css", "reference"]
ai-disclosure: "generated"
ai-model: "claude-sonnet-4-5"
ai-provider: "Anthropic"
---
ASW's reset is in `src/layers/00-reset.css`, ported from [Pico CSS v2.1.1](https://picocss.com/) (MIT). It's an opinionated normalize, not a zero-baseline reset — it corrects browser inconsistencies without stripping all defaults.
---
## What it does
### Box-sizing
Every element uses `border-box`. Padding and border are included in the declared width.
```css
*, *::before, *::after {
box-sizing: border-box;
background-repeat: no-repeat;
}
```
`background-repeat: no-repeat` prevents accidental tiling on elements that receive a background image.
### Document baseline
```css
:where(:root) {
-webkit-tap-highlight-color: transparent; /* remove tap flash on mobile */
text-size-adjust: 100%; /* prevent font inflation on mobile */
text-rendering: optimizeLegibility;
overflow-wrap: break-word; /* wrap long URLs / tokens */
tab-size: 4;
}
```
### Font size
```css
html { font-size: 100%; }
```
Root font size is `100%` of the browser default (typically 16px). Responsive scaling is applied in `01-tokens.css` via `clamp()`. Setting `100%` here respects user accessibility preferences — users who set a larger browser font get a proportionally larger site.
### Body
```css
body {
width: 100%;
margin: 0;
padding: 0;
font-size: var(--text-base);
font-family: var(--font-ui);
background-color: var(--surface);
color: var(--text);
}
```
All visual values come from ASW tokens. Font and colour are set once here and inherited everywhere.
### Main
```css
main { display: block; }
```
Fixes a legacy IE bug where `<main>` wasn't treated as a block element. Still included for completeness.
### Nested lists
```css
:where(dl, ol, ul) :where(dl, ol, ul) { margin: 0; }
```
Removes the double margin that browsers add to nested lists.
---
## What it leaves alone
The reset deliberately does **not**:
- Zero out heading sizes or margins (those are handled by `02-semantic.css`)
- Remove list styles (lists get `list-style: square` in the semantic layer)
- Reset form element appearance (handled by `03-components.css`)
- Set `line-height` on body (set via `var(--leading)` in `08-layout.css`)
---
## Pseudo-elements
```css
::before, ::after {
text-decoration: inherit;
vertical-align: inherit;
}
```
Pseudo-elements inherit text decoration and vertical alignment from their parent. This prevents `::before`/`::after` content from appearing unexpectedly underlined in links.
---
## Customising the reset
The reset layer uses low-specificity `:where()` selectors where possible. Override anything with a standard selector — no `!important` needed.
```css
/* Override: use rem-based font scaling instead of responsive clamp */
html { font-size: 1rem; }
/* Override: add body padding for a specific layout */
body { padding-inline: var(--space-4); }
```
---
## Related
- [Semantic HTML](/docs/semantic-html/) — element styles built on top of this reset
- [Token System](/docs/tokens/) — the custom properties (`--surface`, `--text`, `--font-ui`) referenced in this layer

View file

@ -0,0 +1,272 @@
---
title: "Semantic HTML"
description: "How ASW styles plain HTML elements without class names — typography, links, tables, forms, and interactive elements."
type: docs
weight: 70
date: 2026-04-09
tags: ["semantic-html", "css", "reference"]
ai-disclosure: "generated"
ai-model: "claude-sonnet-4-5"
ai-provider: "Anthropic"
---
ASW's `02-semantic.css` layer styles native HTML elements directly. Write valid semantic HTML; it looks right without adding any attributes or classes.
---
## Typography
### Headings
All six heading levels are styled with distinct sizes, weights, and colours drawn from ASW tokens.
```html
<h1>Page Title</h1>
<h2>Section Heading</h2>
<h3>Subsection</h3>
<h4>Group Header</h4>
<h5>LABEL</h5> <!-- uppercase, spaced -->
<h6>MICRO LABEL</h6> <!-- uppercase, spaced, smaller -->
```
`h5` and `h6` receive `text-transform: uppercase` and `letter-spacing` to serve as section labels rather than structural headings. Headings following content elements get extra top margin (`--type-space-top`) automatically.
### Body text
`<p>`, `<ol>`, `<ul>`, `<dl>` inherit body colour and weight. Spacing uses `--type-space`.
```html
<p>Regular paragraph text.</p>
<p><strong>Bold</strong> and <em>italic</em> inline.</p>
<p><mark>Highlighted text</mark> using the native mark element.</p>
<p><del>Removed</del> and <ins>inserted</ins> content.</p>
```
### Blockquote
```html
<blockquote>
<p>The thread continues even when the needle changes.</p>
<footer>— Vigilio Desto</footer>
</blockquote>
```
Left border in `var(--border)`. Footer text is muted.
### Inline elements
| Element | Rendering |
|---------|-----------|
| `<strong>`, `<b>` | Bolder weight |
| `<mark>` | Yellow highlight (`var(--mark-bg)`) |
| `<del>` | Red (`var(--accent-red)`) |
| `<ins>` | Body colour, no underline |
| `<abbr title="...">` | Dotted bottom border, help cursor |
| `<sub>`, `<sup>` | Standard subscript / superscript |
| `<small>` | `0.875em` |
| `<kbd>` | Keyboard key pill (`var(--kbd-bg)`) |
---
## Links
```html
<a href="/docs/">Standard link</a>
<a href="/docs/" role="button">Link styled as button</a>
```
Links receive `var(--link)` colour with underline offset. Hover and focus states transition smoothly. `focus-visible` shows a box-shadow ring. Links with `role="button"` are excluded from the default link styles.
---
## Navigation
`<nav>` uses flexbox by default. Direct `<ul>` children become horizontal pill lists.
```html
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/docs/">Docs</a></li>
<li><a href="/lab/">Lab</a></li>
</ul>
</nav>
```
`<nav>`, `<header>`, `<footer>`, `<label>`, `<th>` use `var(--font-ui)` instead of the prose font — they're structural elements, not reading text.
---
## Lists
```html
<ul>
<li>Square bullets (not discs)</li>
<li>Inherits body colour and weight</li>
</ul>
<ol>
<li>Numbered list</li>
<li>Standard appearance</li>
</ol>
```
Nested lists have no additional top/bottom margin.
---
## Tables
```html
<table>
<thead>
<tr>
<th>Name</th>
<th>Value</th>
<th>Source</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--accent</code></td>
<td>green-5</td>
<td>Open Props</td>
</tr>
</tbody>
<tfoot>
<tr>
<td colspan="3">Token reference — agentic.css v1.0</td>
</tr>
</tfoot>
</table>
```
Full-width. Bottom borders on `<td>`, stronger border under `<thead>`. `<tfoot>` gets a top border instead of a bottom border.
---
## Code
```html
<!-- Inline code -->
<p>Use <code>data-layout="docs"</code> for the three-column scaffold.</p>
<!-- Code block -->
<pre><code>body {
background: var(--surface);
color: var(--text);
}</code></pre>
<!-- Keyboard shortcut -->
<kbd>Ctrl</kbd> + <kbd>K</kbd>
```
`<code>`, `<kbd>`, `<samp>` all use `var(--font-mono)` with a subtle surface background. `<pre>` is a scrollable block with consistent padding.
---
## Details / Summary
CSS-only accordion. No JavaScript.
```html
<details>
<summary>How does the token cascade work?</summary>
<p>Open Props provides the base scale. ASW aliases those to semantic names. Components reference the semantic aliases.</p>
</details>
<details open>
<summary>This one starts open</summary>
<p>Content visible on load.</p>
</details>
```
The chevron (`▸`) rotates on open. Chevron and summary colour transition smoothly. The `open` attribute is the only state needed.
---
## Dialog / Modal
Native `<dialog>` element with backdrop blur.
```html
<dialog id="my-dialog">
<article>
<header>
<button rel="prev" aria-label="Close"></button>
<h3>Modal Title</h3>
</header>
<p>Modal content goes here.</p>
<footer>
<button onclick="document.getElementById('my-dialog').close()">Close</button>
</footer>
</article>
</dialog>
<button onclick="document.getElementById('my-dialog').showModal()">Open modal</button>
```
The backdrop uses `var(--modal-overlay)` with `var(--modal-backdrop)` blur filter. Adds `.modal-is-open` to `<body>` to lock scroll (must be done via JavaScript). Animations respect `prefers-reduced-motion`.
---
## Progress
```html
<!-- Determinate -->
<progress value="65" max="100">65%</progress>
<!-- Indeterminate -->
<progress>Loading…</progress>
```
Styled with `var(--accent)` fill, `var(--track-bg)` rail. Indeterminate progress animates (respects `prefers-reduced-motion`).
---
## Figure
```html
<figure>
<img src="/images/token-diagram.png" alt="Token hierarchy diagram">
<figcaption>ASW's three-layer token cascade</figcaption>
</figure>
```
`<figcaption>` is muted and smaller than body text.
---
## Horizontal rule
```html
<hr>
```
Renders as a 1px border in `var(--border)`. Inherits colour from context.
---
## Container auto-sizing
`body > nav`, `body > main`, and `body > footer` auto-center and constrain to max-width breakpoints without any class:
| Breakpoint | Max-width |
|-----------|-----------|
| `<480px` | `100%` with side padding |
| `480px+` | `var(--width-sm)` |
| `768px+` | `var(--width-md)` |
| `1024px+` | `var(--width-lg)` |
| `1440px+` | `var(--width-xl)` |
| `1920px+` | `var(--width-2xl)` |
Opt out with `data-layout="fluid"` on `<main>`.
---
## Related
- [Reset](/docs/reset/) — the normalization layer underneath these element styles
- [Data Attributes](/docs/data-attributes/) — extend element styles with `data-*` attributes
- [Token System](/docs/tokens/) — the custom properties driving all colours, sizes, and fonts here

View file

@ -0,0 +1,156 @@
---
title: "Token System"
description: "How ASW's CSS custom property hierarchy is structured — Open Props base, semantic aliases, and component tokens."
type: docs
weight: 20
date: 2026-04-09
tags: ["tokens", "css", "reference"]
ai-disclosure: "generated"
ai-model: "claude-sonnet-4-5"
ai-provider: "Anthropic"
---
## Overview
ASW uses a three-layer token hierarchy built on Open Props. Each layer is additive: base palette → semantic aliases → component-specific values.
```
Open Props palette → ASW semantic aliases → component tokens
--gray-5 --text-2 --input-border
--green-5 --accent --callout-info
--blue-5 --link --task-done
```
No layer can break the others. Override a semantic alias, and every component that references it updates.
## Layer 1 — Open Props palette
ASW inlines the Open Props token set directly — no CDN dependency. The full color palette (`--gray-0` through `--gray-15`, plus hue families), spacing scale, font stacks, and easing curves are all available.
```css
/* These are defined for you — do not redeclare them */
--gray-0: oklch(99% 0.005 var(--gray-hue));
--gray-15: oklch(10% 0.005 var(--gray-hue));
--green-5: #51cf66;
--blue-5: #339af0;
```
One knob controls the entire gray family:
```css
:root {
--gray-hue: 150; /* default: subtle green tint */
}
```
Change `--gray-hue` to `45` for warm stone, `220` for cool blue-gray, `0` for neutral.
## Layer 2 — Semantic aliases
Defined in `:root`, these translate palette values to intent. These are the tokens you override to theme a site.
```css
:root {
/* Surfaces */
--surface: var(--gray-15); /* page background */
--surface-1: var(--gray-14); /* cards, sidebars */
--surface-2: var(--gray-13); /* hover, raised */
/* Text */
--text: var(--gray-1); /* primary */
--text-2: var(--gray-3); /* secondary */
--text-3: var(--gray-5); /* muted */
/* Accent */
--accent: var(--green-5);
--accent-hover: var(--green-4);
--on-accent: var(--gray-15);
/* Links */
--link: var(--blue-5);
--link-hover: var(--blue-4);
/* Border */
--border: var(--gray-11);
--border-subtle: var(--gray-12);
}
```
Light mode overrides the same tokens:
```css
@media (prefers-color-scheme: light) {
:root {
--surface: var(--gray-0);
--text: var(--gray-14);
--accent: var(--green-8);
}
}
```
## Layer 3 — Component tokens
Component tokens are semantic aliases scoped to specific UI patterns. They reference Layer 2 tokens rather than the palette directly.
```css
/* Agent-native tokens */
--task-done: var(--green-5);
--task-wip: var(--yellow-5);
--task-blocked: var(--red-5);
--task-todo: var(--gray-5);
--callout-info: var(--blue-5);
--callout-warn: var(--yellow-5);
--callout-error: var(--red-5);
--callout-note: var(--gray-5);
/* Session / vault */
--session-bg: var(--surface-1);
--wikilink: var(--blue-4);
--redacted: var(--gray-8);
```
## Theming a site
To rebrand: override semantic aliases only. Never override the Open Props palette.
```css
/* your-theme.css — load after agentic.css */
:root {
--gray-hue: 220; /* cool blue-gray neutrals */
--accent: var(--violet-5);
--link: var(--violet-4);
}
```
That is the entire theme file. Surfaces, borders, focus rings, callouts, and task states all update from those three lines.
## Typography scale
```css
--text-xs: 0.75rem; /* badges, fine print */
--text-sm: 0.875rem; /* metadata, captions */
--text-base: 1rem; /* body text */
--text-2xl: 1.5rem; /* subheadings */
--text-3xl: 2rem; /* section headings */
/* Heading sizes */
--h1-size: 1.875rem;
--h2-size: 1.5rem;
--h3-size: 1.25rem;
```
## Spacing scale
Aliased from Open Props sizes, with one gap filled:
```css
--space-1: 0.25rem; /* var(--size-1) */
--space-2: 0.50rem; /* var(--size-2) */
--space-3: 0.75rem; /* no OP equivalent — defined by ASW */
--space-4: 1.00rem; /* var(--size-3) */
--space-5: 1.50rem; /* var(--size-5) */
--space-6: 2.00rem; /* var(--size-7) */
--space-8: 4.00rem; /* var(--size-9) */
```