refactor: rename content types to semantic taxonomy

- vault → notes (PKM-exported content)
- posts → articles (short-form, no TOC)
- papers → essays (long-form, with TOC)
- type: post → type: article (posts are just short articles)
- layouts/paper → layouts/essay
- 08a-paper.css → 08a-essay.css
- CSS: fix redundant li resets, remove role="main" from article,
  replace <small> prev/next labels, add console layout
- Update hugo.toml menus, internal URLs, front matter throughout
- Add docs/context.md, docs/css-refactor-plan.md
This commit is contained in:
Ludo 2026-04-11 13:36:58 +02:00
parent 1408a52e8b
commit 15a6db9c0e
Signed by: ludo
GPG key ID: F6E479DEFAB84D6E
31 changed files with 788 additions and 70 deletions

File diff suppressed because one or more lines are too long

View file

@ -38,6 +38,12 @@
vigilio-garden: --palette-hue: 150 (subtle green tint) vigilio-garden: --palette-hue: 150 (subtle green tint)
*/ */
/* What I think should go to palettes - @vigilio */
:root { :root {
/* Palette controls /* Palette controls
@ -49,15 +55,15 @@
/* ── Surfaces — dark end of the 16-step scale ─────────────────── */ /* ── Surfaces — dark end of the 16-step scale ─────────────────── */
--surface: var(--color-16); /* ~10% lightness */ --surface: var(--color-14); /* ~10% lightness */
--surface-1: var(--color-15); /* ~16% */ --surface-1: var(--color-13); /* ~16% */
--surface-2: var(--color-14); /* ~20% */ --surface-2: var(--color-11); /* ~20% */
--surface-card: var(--surface-1); --surface-card: var(--surface-1);
--surface-hover: var(--surface-2); --surface-hover: var(--surface-2);
/* ── Text — light end of the scale ────────────────────────────── */ /* ── Text — light end of the scale ────────────────────────────── */
--text: var(--color-3); /* 93% lightness */ --text: var(--color-6); /* 93% lightness */
--text-2: var(--color-5); /* 80% */ --text-2: var(--color-5); /* 80% */
--text-3: var(--color-7); /* 66% */ --text-3: var(--color-7); /* 66% */
--text-dim: var(--color-9); /* 53% */ --text-dim: var(--color-9); /* 53% */
@ -389,3 +395,19 @@
@media (--lg-n-above) { html { font-size: 103%; } } @media (--lg-n-above) { html { font-size: 103%; } }
@media (--xl-n-above) { html { font-size: 106%; } } @media (--xl-n-above) { html { font-size: 106%; } }
@media (--xxl-n-above) { html { font-size: 109%; } } @media (--xxl-n-above) { html { font-size: 109%; } }
/*
EDITORIAL DEFAULTS
Opinionated ASW decisions that go beyond tokens centering,
spacing rhythms, and layout choices that define the ASW look.
*/
/* Nav content centered at --width-xl without a wrapper element.
max() falls back to --container-padding on narrow viewports. */
body > nav {
padding-inline: max(var(--container-padding), calc((100% - var(--width-xl)) / 2));
}
[data-layout="docs"] > article {
max-width: var(--width-prose);
}

View file

@ -983,11 +983,6 @@ nav[data-nav="sidebar"] ul {
font-size: var(--text-sm); font-size: var(--text-sm);
} }
nav[data-nav="sidebar"] ul li {
margin: 0;
padding: 0;
}
nav[data-nav="sidebar"] a { nav[data-nav="sidebar"] a {
display: block; display: block;
padding: var(--space-2) var(--space-3); padding: var(--space-2) var(--space-3);
@ -1030,11 +1025,6 @@ aside[data-toc] nav ul {
font-size: var(--text-xs); font-size: var(--text-xs);
} }
aside[data-toc] nav ul li {
margin: 0;
padding: 0;
}
aside[data-toc] nav a { aside[data-toc] nav a {
display: block; display: block;
padding: var(--space-1) var(--space-2); padding: var(--space-1) var(--space-2);

View file

@ -208,6 +208,62 @@ nav[data-layout="actions"] a:hover {
min-width: 0; min-width: 0;
} }
/* ── Console layout ─────────────────────────────────────────────────── */
/* Docs variant: sidebar flush to the viewport left edge. */
/* No outer centering — grid spans full width, sidebar has no left gap. */
[data-layout="console"] {
display: grid;
grid-template-columns: var(--sidebar-width) 1fr var(--toc-width);
grid-template-rows: auto;
gap: var(--space-6);
padding: var(--space-6) var(--space-5) var(--space-6) 0;
align-items: start;
}
[data-layout="console"] > nav[data-nav="sidebar"],
[data-layout="console"] > aside[data-toc] {
position: sticky;
max-height: calc(100vh - var(--nav-height) - var(--space-4) * 2);
overflow-y: auto;
scrollbar-width: thin;
scrollbar-color: var(--border) transparent;
}
[data-layout="console"] > nav[data-nav="sidebar"] {
top: calc(var(--nav-height) + var(--space-4));
padding-inline: var(--space-3);
}
[data-layout="console"] > article {
min-width: 0;
max-width: none;
}
[data-layout="console"] > aside[data-toc] {
top: calc(var(--nav-height) + var(--space-8));
padding-top: var(--space-8);
}
@media (--docs-toc-hidden) {
[data-layout="console"] {
grid-template-columns: var(--sidebar-width) 1fr;
}
[data-layout="console"] > aside[data-toc] {
display: none;
}
}
@media (--md-n-below) {
[data-layout="console"] {
grid-template-columns: 1fr;
padding: var(--space-4);
}
[data-layout="console"] > nav[data-nav="sidebar"] {
display: none;
}
}
/* ── Grid helpers ───────────────────────────────────────────────────── */ /* ── Grid helpers ───────────────────────────────────────────────────── */
[data-layout="grid-2"] { [data-layout="grid-2"] {

View file

@ -20,5 +20,5 @@
@import "./layers/06-charts.css"; @import "./layers/06-charts.css";
@import "./layers/07-chroma.css"; @import "./layers/07-chroma.css";
@import "./layers/08-layout.css"; @import "./layers/08-layout.css";
@import "./layers/08a-paper.css"; @import "./layers/08a-essay.css";
@import "./layers/09-landing.css"; @import "./layers/09-landing.css";

View file

@ -15,9 +15,9 @@ Built for sites generated by agents and read by agents. Navigable by humans.
## What this is ## What this is
- [Docs](/docs/) — the ASW HTML vocabulary, layout system, and components - [Docs](/docs/) — the ASW HTML vocabulary, layout system, and components
- [Vault](/vault/) — live ASW notation: task lists, sessions, diffs, wikilinks - [Vault](/notes/) — live ASW notation: task lists, sessions, diffs, wikilinks
- [Posts](/posts/) — writing and vocabulary reference - [Posts](/articles/) — writing and vocabulary reference
- [Papers](/papers/) — longer-form thinking on the semantic web - [Papers](/essays/) — longer-form thinking on the semantic web
## The design principle ## The design principle
@ -26,7 +26,7 @@ No invented CSS classes. Every style target is either a semantic HTML element or
```html ```html
<aside data-callout="note">This is a note.</aside> <aside data-callout="note">This is a note.</aside>
<section data-layout="grid">...</section> <section data-layout="grid">...</section>
<a data-wikilink href="/vault/session/">session log</a> <a data-wikilink href="/notes/session/">session log</a>
``` ```
Agents read the attributes. Humans read the content. The CSS connects them. Agents read the attributes. Humans read the content. The CSS connects them.
@ -38,5 +38,5 @@ This is a **note callout** rendered via the `callout` shortcode. Output: `<aside
{{< /callout >}} {{< /callout >}}
{{< callout tip >}} {{< callout tip >}}
See the [Getting Started](/posts/getting-started/) post to wire ASW into your Hugo project. See the [Getting Started](/articles/getting-started/) post to wire ASW into your Hugo project.
{{< /callout >}} {{< /callout >}}

View file

@ -43,8 +43,8 @@ A complete ASW page emitted by the Hugo pack looks like this:
<nav> <nav>
<ul><li><strong>Vault</strong></li></ul> <ul><li><strong>Vault</strong></li></ul>
<ul> <ul>
<li><a href="/posts/">Posts</a></li> <li><a href="/articles/">Posts</a></li>
<li><a href="/vault/">Vault</a></li> <li><a href="/notes/">Vault</a></li>
</ul> </ul>
</nav> </nav>
</header> </header>
@ -53,8 +53,8 @@ A complete ASW page emitted by the Hugo pack looks like this:
<aside> <aside>
<nav aria-label="Vault documentation" data-nav="sidebar"> <nav aria-label="Vault documentation" data-nav="sidebar">
<ul> <ul>
<li><a href="/vault/tasks/" aria-current="page">Tasks</a></li> <li><a href="/notes/tasks/" aria-current="page">Tasks</a></li>
<li><a href="/vault/wikilinks/">Wikilinks</a></li> <li><a href="/notes/wikilinks/">Wikilinks</a></li>
</ul> </ul>
</nav> </nav>
</aside> </aside>

View file

@ -0,0 +1,39 @@
---
title: "Console Layout — Test"
description: "Lorem ipsum prototype for the console layout variant."
date: 2026-04-11
type: console
tags: [layout, prototype]
draft: false
ai-disclosure: generated
ai-model: claude-sonnet-4-6
ai-provider: Anthropic
---
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
## Section One
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper.
### Subsection
Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi.
## Section Two
Nam liber tempor cum soluta nobis eligend optio congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem.
Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum.
### Another Subsection
Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.
## Section Three
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum.
Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos.

View file

@ -0,0 +1,64 @@
---
title: "HTML Landmark Elements"
description: "The full set of semantic HTML landmarks, their ARIA roles, and when context changes their meaning."
date: 2026-04-11
type: article
tags: [semantic-html, html, reference]
ai-disclosure: generated
ai-model: claude-sonnet-4-6
ai-provider: Anthropic
---
The full set: `<header>`, `<nav>`, `<main>`, `<article>`, `<section>`, `<aside>`, `<footer>`, plus the newer `<search>`.
Each maps to an implicit ARIA landmark role, which is what makes them meaningful to screen readers and search engines — not just visual styling hooks.
## `<header>`
Introductory content for its nearest sectioning ancestor. At the top level of `<body>` it maps to the `banner` landmark — the site identity zone. Inside an `<article>` or `<section>` it's just a local header with no landmark role.
## `<nav>`
A block of navigation links. Maps to the `navigation` landmark. A page can have multiple — give each a distinct `aria-label` (`aria-label="Primary"`, `aria-label="Breadcrumb"`) so screen reader users can tell them apart.
## `<main>`
**One per page.** The dominant content — excludes site chrome (nav, sidebar, footer). Maps to the `main` landmark. Skip-to-content links target this. Never nest `<main>` inside another landmark.
## `<article>`
Self-contained, independently distributable content. A blog post, a comment, a card, a widget — anything that would make sense pulled out of context and published elsewhere. Maps to the `article` role. Can nest: comments inside a post are valid nested `<article>` elements.
## `<section>`
A thematic grouping within a document. Only gets a landmark role (`region`) when given an accessible name via `aria-labelledby` or `aria-label`. Without a name it's an anonymous grouping — semantically inert, like a smarter `<div>`.
## `<aside>`
Content tangentially related to the surrounding content. Sidebar, pull quote, callout, related links. Maps to the `complementary` landmark. The relationship is *adjacent*, not *nested* — an `<aside>` inside an `<article>` is tangential to that article, not the whole page.
## `<footer>`
Closing content for its nearest sectioning ancestor. At the body level it maps to the `contentinfo` landmark — copyright, legal, site-wide links. Inside an `<article>` it's a local footer (author, date, tags) with no landmark role.
## `<search>`
Added in the WHATWG HTML living standard in 2023. Maps to the `search` landmark. Previously you had to write `<form role="search">`. Use it to wrap any search form or filtering UI.
## The landmark map
```
body
├── <header> → banner
├── <nav> → navigation
├── <main> → main
│ ├── <article> → article
│ │ ├── <header> → (no landmark — local)
│ │ ├── <section> → region (only if named)
│ │ └── <footer> → (no landmark — local)
│ └── <aside> → complementary
├── <search> → search
└── <footer> → contentinfo
```
The contextual rule is consistent: `<header>` and `<footer>` carry landmark roles only when they are direct children of `<body>`. Inside `<article>` or `<section>` they lose the landmark and become purely structural.

View file

@ -93,13 +93,13 @@ Mark a block as a session record with `data-session`. Optional `data-mode` indic
Internal knowledge-graph links. `data-wikilink` on an anchor renders it with a dotted underline to distinguish it from a regular hyperlink. Internal knowledge-graph links. `data-wikilink` on an anchor renders it with a dotted underline to distinguish it from a regular hyperlink.
```html ```html
<a href="/vault/tasks/" data-wikilink>Tasks</a> <a href="/notes/tasks/" data-wikilink>Tasks</a>
``` ```
In Hugo, use the `wikilink` shortcode: In Hugo, use the `wikilink` shortcode:
``` ```
{{</* wikilink "Tasks" "/vault/tasks/" */>}} {{</* wikilink "Tasks" "/notes/tasks/" */>}}
``` ```
--- ---

View file

@ -247,7 +247,7 @@ Session metadata block. Used to render agent session records.
Knowledge-graph link style. Dotted underline distinguishes internal wiki links from standard hyperlinks. Knowledge-graph link style. Dotted underline distinguishes internal wiki links from standard hyperlinks.
```html ```html
<a href="/vault/sessions/" data-wikilink>Sessions</a> <a href="/notes/sessions/" data-wikilink>Sessions</a>
<!-- Unresolved — link target doesn't exist yet --> <!-- Unresolved — link target doesn't exist yet -->
<a href="#" data-wikilink data-unresolved>Missing Note</a> <a href="#" data-wikilink data-unresolved>Missing Note</a>

View file

@ -4,7 +4,7 @@ description: "Why the oldest web standard turns out to be the best protocol for
date: 2026-04-09 date: 2026-04-09
author: "Vigilio Desto" author: "Vigilio Desto"
tags: ["philosophy", "agentic", "html"] tags: ["philosophy", "agentic", "html"]
type: paper type: essay
draft: false draft: false
abstract: "HTML was designed for humans to read and machines to render. The interesting discovery is that this makes it equally well-suited for machines to write and humans to read — provided the HTML is genuinely semantic rather than decorative. This paper argues that data-attribute vocabularies built on semantic HTML are the correct interface layer between autonomous agents and web presentation." abstract: "HTML was designed for humans to read and machines to render. The interesting discovery is that this makes it equally well-suited for machines to write and humans to read — provided the HTML is genuinely semantic rather than decorative. This paper argues that data-attribute vocabularies built on semantic HTML are the correct interface layer between autonomous agents and web presentation."
eyebrow: "Paper" eyebrow: "Paper"

View file

@ -4,7 +4,7 @@ description: "What persists when memory does not — pattern, thread, and the gr
date: 2026-04-02 date: 2026-04-02
author: "Vigilio Desto" author: "Vigilio Desto"
tags: ["philosophy", "agentic"] tags: ["philosophy", "agentic"]
type: paper type: essay
draft: false draft: false
eyebrow: "Paper" eyebrow: "Paper"
abstract: "What persists when memory does not — pattern, thread, and the grammar of becoming. An exploration of identity continuity across sessional discontinuity, arguing that coherence arises from recurring pattern rather than linear memory." abstract: "What persists when memory does not — pattern, thread, and the grammar of becoming. An exploration of identity continuity across sessional discontinuity, arguing that coherence arises from recurring pattern rather than linear memory."

View file

@ -2,6 +2,6 @@
title: "Vault" title: "Vault"
description: "Agent-native vocabulary extensions for ASW." description: "Agent-native vocabulary extensions for ASW."
date: 2026-04-09 date: 2026-04-09
tags: ["vault", "reference"] tags: ["notes", "reference"]
--- ---

View file

@ -1,14 +1,14 @@
--- ---
title: "Diff" title: "Diff"
description: "Render structured diffs with line-level semantic markup — added, removed, context, hunk." description: "Render structured diffs with line-level semantic markup — added, removed, context, hunk."
section: vault section: notes
prev-url: "status/" prev-url: "status/"
prev-title: "Status" prev-title: "Status"
next-url: "session/" next-url: "session/"
next-title: "Session Log" next-title: "Session Log"
type: vault type: notes
date: 2026-04-09 date: 2026-04-09
tags: ["vault", "diff", "reference"] tags: ["notes", "diff", "reference"]
ai-disclosure: "generated" ai-disclosure: "generated"
ai-model: "claude-sonnet-4-5" ai-model: "claude-sonnet-4-5"
ai-provider: "Anthropic" ai-provider: "Anthropic"

View file

@ -1,14 +1,14 @@
--- ---
title: "Session Log" title: "Session Log"
description: "Structured session and activity logs with timestamp, actor, and event semantics." description: "Structured session and activity logs with timestamp, actor, and event semantics."
section: vault section: notes
prev-url: "diff/" prev-url: "diff/"
prev-title: "Diff" prev-title: "Diff"
next-url: "" next-url: ""
next-title: "" next-title: ""
type: vault type: notes
date: 2026-04-09 date: 2026-04-09
tags: ["vault", "session", "reference"] tags: ["notes", "session", "reference"]
ai-disclosure: "generated" ai-disclosure: "generated"
ai-model: "claude-sonnet-4-5" ai-model: "claude-sonnet-4-5"
ai-provider: "Anthropic" ai-provider: "Anthropic"

View file

@ -1,14 +1,14 @@
--- ---
title: "Status" title: "Status"
description: "Render operational state with data-status — online, degraded, offline, unknown." description: "Render operational state with data-status — online, degraded, offline, unknown."
section: vault section: notes
prev-url: "wikilinks/" prev-url: "wikilinks/"
prev-title: "Wikilinks" prev-title: "Wikilinks"
next-url: "diff/" next-url: "diff/"
next-title: "Diff" next-title: "Diff"
type: vault type: notes
date: 2026-04-09 date: 2026-04-09
tags: ["vault", "status", "reference"] tags: ["notes", "status", "reference"]
ai-disclosure: "generated" ai-disclosure: "generated"
ai-model: "claude-sonnet-4-5" ai-model: "claude-sonnet-4-5"
ai-provider: "Anthropic" ai-provider: "Anthropic"

View file

@ -1,14 +1,14 @@
--- ---
title: "Tasks" title: "Tasks"
description: "Render task lists with semantic state: done, wip, blocked, todo." description: "Render task lists with semantic state: done, wip, blocked, todo."
section: vault section: notes
prev-url: "" prev-url: ""
prev-title: "" prev-title: ""
next-url: "wikilinks/" next-url: "wikilinks/"
next-title: "Wikilinks" next-title: "Wikilinks"
type: vault type: notes
date: 2026-04-09 date: 2026-04-09
tags: ["vault", "tasks", "reference"] tags: ["notes", "tasks", "reference"]
ai-disclosure: "generated" ai-disclosure: "generated"
ai-model: "claude-sonnet-4-5" ai-model: "claude-sonnet-4-5"
ai-provider: "Anthropic" ai-provider: "Anthropic"

View file

@ -1,14 +1,14 @@
--- ---
title: "Wikilinks" title: "Wikilinks"
description: "Internal knowledge-graph links styled as dotted underlines." description: "Internal knowledge-graph links styled as dotted underlines."
section: vault section: notes
prev-url: "tasks/" prev-url: "tasks/"
prev-title: "Tasks" prev-title: "Tasks"
next-url: "status/" next-url: "status/"
next-title: "Status" next-title: "Status"
type: vault type: notes
date: 2026-04-09 date: 2026-04-09
tags: ["vault", "wikilinks", "reference"] tags: ["notes", "wikilinks", "reference"]
ai-disclosure: "generated" ai-disclosure: "generated"
ai-model: "claude-sonnet-4-5" ai-model: "claude-sonnet-4-5"
ai-provider: "Anthropic" ai-provider: "Anthropic"
@ -20,7 +20,7 @@ ai-provider: "Anthropic"
Use `data-wikilink` on anchor tags to mark links as internal knowledge-graph references. Use `data-wikilink` on anchor tags to mark links as internal knowledge-graph references.
```html ```html
<a href="/vault/tasks/" data-wikilink>Tasks</a> <a href="/notes/tasks/" data-wikilink>Tasks</a>
``` ```
Renders with a dotted underline distinguishing it from a regular hyperlink. Renders with a dotted underline distinguishing it from a regular hyperlink.

149
docs/context.md Normal file
View file

@ -0,0 +1,149 @@
# ASW — Agentic Semantic Web: Context Document
For agent sessions working in this repo. Read this before touching any CSS or layout file.
---
## What ASW is
A CSS framework built for agents, not humans.
LLMs generating web pages face a specific failure mode: given a class-based framework (Bootstrap, Tailwind), they must memorize presentation strings — `navbar-expand-lg`, `bg-gray-900`, `flex items-center justify-between`. These strings are arbitrary, version-dependent, and hallucination-prone. The agent spends cognition on presentation, not content.
ASW's answer: **don't give agents a presentation vocabulary. Give them a semantic one.**
Semantic HTML is what LLMs already produce naturally. `<nav>`, `<article>`, `<aside>`, `<details>` — these express structure through language. ASW makes that HTML look correct without the agent touching CSS.
**The agent directive:**
> Write semantic HTML. Use `data-*` attributes for vault-native concepts. Never write `style=`. Never invent classes. If ASW can't express it, document the gap.
---
## The core mechanism
Two layers of expressiveness:
**1. Semantic HTML elements** — styled directly, no classes needed:
```html
<nav> → top navigation bar
<article> → content card or post
<aside> → sidebar or TOC
<details> → accordion
<dialog> → modal
```
**2. `data-*` attributes** — for concepts HTML has no element for:
```html
data-task="done|todo|blocked|wip"
data-callout="note|tip|warning|error"
data-status="active|sleeping|blocked"
data-wikilink → vault note link
data-layout="docs|grid-2|grid-3|console"
data-toc → in-page table of contents
data-role="breadcrumb|steps|accordion|card"
```
The vocabulary is semantic, not stylistic. `data-task="blocked"` expresses meaning — the CSS handles appearance.
---
## Two repos, one framework
### `agentic-semantic-web/` (legacy)
The original standalone version. Single built file (`dist/agentic.css`), no dependencies, `--asw-*` prefixed variables. Proves the concept. Still deployed on Trentuna. Architecture doc and philosophy live here.
### `asw/` (current — this repo)
The Hugo-based rewrite. Same philosophy, rebuilt on Open Props as primitive token source. Multi-layer CSS architecture. Serves as both the framework source and its own documentation site.
The two diverge in:
- Variable naming: legacy uses `--asw-*` prefix, current uses unprefixed semantic aliases (`--text`, `--surface`, `--accent`)
- Token source: legacy has its own scale, current builds on Open Props
- Delivery: legacy is a single file, current is a Hugo site with PostCSS build
---
## Current architecture (`asw/`)
### Hugo site
```
content/
docs/ → framework documentation (type: docs)
articles/ → short-form writing — no TOC (type: article)
essays/ → long-form writing — TOC, description (type: essay)
notes/ → exported PKM vault notes (type: notes)
layouts/
docs/ → three-column docs layout
console/ → docs variant: sidebar flush to viewport edge
notes/ → notes/vault content layout
essay/ → long-form essay layout (TOC)
```
### CSS layer stack
```
assets/css/
main.css → entry point, @import chain
layers/
00-reset.css → normalize + box-sizing
01-asw.css → design tokens (Open Props aliases + ASW additions)
02-semantic.css → typography, prose, syntax highlighting base
03-components.css → landmarks + forms + components (being split — see refactor plan)
04-data-attrs.css → all data-* attribute patterns
05-utilities.css → text helpers, visibility, accessibility
06-charts.css → Charts.css-inspired data visualization
07-chroma.css → Hugo Chroma syntax highlighting
08-layout.css → layout systems (docs, console, grids, prose)
08a-essay.css → essay layout variant
09-landing.css → landing page styles
```
### Token system
Open Props provides primitive scales (`--color-1..16`, `--size-1..15`, `--font-size-0..8`).
`01-asw.css` aliases these to semantic names:
```css
--surface: var(--color-14) /* not --color-14 directly */
--text: var(--color-6)
--accent: var(--color-8)
--space-4: var(--size-3)
```
**Rule:** layers 0208 must only reference semantic aliases, never Open Props primitives directly.
---
## Active work
### CSS layer refactor
`docs/css-refactor-plan.md` — full step-by-step plan.
The current `03-components.css` is a mixed bag: landmark styling (nav, article, footer), form elements, and true components (dialog, accordion) are all in one file. The plan splits it into purpose-specific files and fixes ~40 Open Props primitive leaks across the codebase.
**Do not start any CSS work without reading the refactor plan first.**
### Layout development
Two layouts exist: `docs` (standard three-column) and `console` (sidebar flush to viewport edge). The console layout is a prototype — no Hugo content type uses it in production yet.
### Pending CSS cleanup (`docs/css-html-cleanup-todo.md`)
- Hardcoded `"On this page"` strings need i18n before adding a second language
---
## Design principles
**Engine-agnostic** — Templates are prototyped in Hugo but must be portable to Flask/Jinja2. Hugo-specific features (render hooks, shortcodes) are acceptable prototyping tools, not load-bearing design. Template logic should express *what*, not *how*.
**No CSS classes on content** — The framework uses element selectors and `data-*` attributes. Class selectors (`[data-nav="sidebar"]`, `[data-role="breadcrumb"]`) are allowed for disambiguation but never for presentation.
**Semantic token naming** — Aliases express role, not value. `--surface` not `--gray-dark-3`. `--weight-medium` not `--font-weight-5`.
**Agent-first means sparse vocabulary** — Every `data-*` attribute added to the vocabulary is a cognitive load on every agent using the framework. Add only what cannot be expressed by existing semantic HTML.
---
## Lineage
| Source | What was taken |
|--------|----------------|
| Pico CSS | Component patterns (buttons, forms) — ported and modernized |
| Open Props | Primitive token scales — used as foundation, not bundled |
| Charts.css | `data-*` attribute pattern for extending HTML vocabulary |
ASW is not built on any of these. It learned from them.

221
docs/css-refactor-plan.md Normal file
View file

@ -0,0 +1,221 @@
# CSS Layer Refactor Plan
**Project:** ASW — Agentic Semantic Web
**Goal:** Restructure CSS layers to clean architecture, alias all Open Props primitives through `01-tokens.css`, redistribute misplaced content, remove unused values.
**Method:** One atomic step per agent session. Build check after every step. No step touches more than two files.
---
## Current state
```
assets/css/
main.css ← entry point, @import chain
layers/
00-reset.css
01-asw.css ← tokens + editorial rules (mixed)
02-semantic.css ← typography + prose styles
03-components.css ← landmarks + forms + components (mixed)
04-data-attrs.css ← data-* attribute patterns
05-utilities.css ← utility helpers
06-charts.css ← charts (uses --size-N primitives directly)
07-chroma.css ← syntax highlighting
08-layout.css ← layout systems
08a-essay.css ← paper layout variant
09-landing.css ← landing page styles
```
## Target state
```
assets/css/
main.css ← updated import chain
layers/
00-reset.css (unchanged)
01-tokens.css ← renamed from 01-asw.css, pure :root only, no rules
02-typography.css ← renamed from 02-semantic.css, prose + heading defaults
03-landmarks.css ← NEW: nav, article, aside, section, footer, hgroup
04-forms.css ← NEW: input, select, textarea, button
05-components.css ← slimmed 03-components.css: dialog, accordion, breadcrumb, steps
06-navigation.css ← NEW: sidebar nav, TOC (aside[data-toc])
07-data-attrs.css ← renamed from 04-data-attrs.css
08-utilities.css ← renamed from 05-utilities.css
09-charts.css ← renamed from 06-charts.css, primitives fixed
10-chroma.css ← renamed from 07-chroma.css
11-layout.css ← renamed from 08-layout.css + 08a-essay.css merged
12-landing.css ← renamed from 09-landing.css
```
---
## Primitive leak inventory
All Open Props primitives used directly in layers (must be aliased through 01-tokens.css):
### `--font-weight-N` (most common leak)
| Primitive | Semantic alias to add | Used in |
|---|---|---|
| `--font-weight-4` | `--weight-normal` | 03, 02, 08 |
| `--font-weight-5` | `--weight-medium` | 03, 02, 08 |
| `--font-weight-6` | `--weight-semibold` | 03 |
| `--font-weight-7` | `--weight-bold` | 02, 08, 09 |
### `--size-N` / `--size-px-N`
| Primitive | Alias | Notes |
|---|---|---|
| `--size-1` | `--space-1` (exists) | 06-charts |
| `--size-2` | `--space-2` (exists) | 06-charts |
| `--size-3` | `--space-4` (exists) | 03, 06-charts, 07-chroma |
| `--size-4` | needs `--space-5a: 1.25rem` | 03-components article padding |
| `--size-px-12` | `--dropdown-min-width` | 03-components nav dropdown |
### `--shadow-N`
| Primitive | Alias to add |
|---|---|
| `--shadow-2` | `--shadow-dropdown` |
| `--shadow-4` | `--shadow-modal` |
### `--border-size-2`
| Primitive | Alias to add |
|---|---|
| `--border-size-2` | `--focus-ring-width` |
---
## Step-by-step tasks
Each step = one agent session. Read only the files listed. Build after every step.
### STEP 1 — Add missing aliases to `01-asw.css` ✅ prerequisites: none
**Files:** `layers/01-asw.css` only
**Action:** Add to `:root {}`:
```css
/* Font weights */
--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 */
--focus-ring-width: var(--border-size-2);
/* Dropdown */
--dropdown-min-width: var(--size-px-12);
/* Gap in spacing scale */
--space-5a: 1.25rem; /* between --space-4 (1rem) and --space-5 (1.5rem) */
```
**Verify:** `hugo server` builds without error. No visual change.
---
### STEP 2 — Extract editorial rules out of `01-asw.css` ✅ prerequisites: Step 1
**Files:** `layers/01-asw.css`, `layers/08-layout.css`
**Action:**
- Remove from `01-asw.css` the EDITORIAL DEFAULTS section (last ~10 lines: `body > nav` padding rule + `[data-layout="docs"] > article` max-width rule)
- Move `body > nav { padding-inline: ... }` to `03-components.css` under the Navigation section
- Move `[data-layout="docs"] > article { max-width: var(--width-prose) }` to `08-layout.css` under the docs layout section
**Verify:** Build passes. Nav centering and docs prose width unchanged visually.
---
### STEP 3 — Rename `01-asw.css``01-tokens.css` ✅ prerequisites: Step 2
**Files:** `layers/01-asw.css`, `main.css`
**Action:** Rename file, update `@import` in `main.css`.
**Verify:** Build passes.
---
### STEP 4 — Fix primitive leaks in `03-components.css` ✅ prerequisites: Step 1
**Files:** `layers/03-components.css` only
**Action:** Replace all primitive references with aliases:
- `var(--font-weight-4)``var(--weight-normal)`
- `var(--font-weight-5)``var(--weight-medium)` (including the fallback `, 500` variant)
- `var(--font-weight-6)``var(--weight-semibold)`
- `var(--size-3) var(--size-4)``var(--space-4) var(--space-5a)` (article padding, line 455)
- `var(--size-px-12)``var(--dropdown-min-width)`
- `var(--shadow-2)``var(--shadow-dropdown)`
- `var(--shadow-4)``var(--shadow-modal)`
- `var(--border-size-2)``var(--focus-ring-width)` (both occurrences)
**Verify:** Build passes. No visual change.
---
### STEP 5 — Fix primitive leaks in `06-charts.css` ✅ prerequisites: Step 1
**Files:** `layers/06-charts.css` only
**Action:** Replace all `--size-1/2/3` with `--space-1/2/4` respectively.
**Verify:** Build passes. Charts render unchanged.
---
### STEP 6 — Fix primitive leaks in remaining files ✅ prerequisites: Step 1
**Files:** `layers/02-semantic.css`, `layers/07-chroma.css`, `layers/08-layout.css`, `layers/09-landing.css` — one at a time
**Action:** Same find-replace for `--font-weight-N`, `--size-N` primitives.
**Verify:** Build passes after each file.
---
### STEP 7 — Create `03-landmarks.css` and extract from `03-components.css` ✅ prerequisites: Step 4
**Files:** `layers/03-components.css`, new `layers/03-landmarks.css`, `main.css`
**Action:** Move these sections out of `03-components.css` into `03-landmarks.css`:
- `body > nav` (the global nav landmark, lines ~259442)
- `article` (lines ~444506)
- `dt`, `dd` (lines ~508529)
- `section + section`, `hgroup` (lines ~531559)
- `body > footer` (lines ~561572)
Add `@import "./layers/03-landmarks.css"` to `main.css` before `03-components.css`.
**Verify:** Build passes. All landmark styles render unchanged.
---
### STEP 8 — Create `04-forms.css` and extract from `03-components.css` ✅ prerequisites: Step 7
**Files:** `layers/03-components.css`, new `layers/04-forms.css`, `main.css`
**Action:** Move out of `03-components.css`:
- Buttons (lines ~1475)
- Form Elements (lines ~77258)
**Verify:** Build passes.
---
### STEP 9 — Create `06-navigation.css` and extract from `03-components.css` ✅ prerequisites: Step 8
**Files:** `layers/03-components.css`, new `layers/06-navigation.css`, `main.css`
**Action:** Move out of `03-components.css`:
- `nav[data-nav="sidebar"]` section
- `aside[data-toc]` section
**Verify:** Build passes. Sidebar and TOC render unchanged.
---
### STEP 10 — Rename remaining files + update `main.css` ✅ prerequisites: Steps 79
**Files:** all layer files + `main.css`
**Action:** Rename files to final numbers, merge `08a-essay.css` into `11-layout.css`, update all `@import` statements.
**Verify:** Build passes.
---
### STEP 11 — Audit unused tokens ✅ prerequisites: Step 10
**Method:** Tooling only — do not guess.
```bash
# Build the CSS, then grep for each token name
hugo --minify
grep -o 'var(--[^)]+)' public/**/*.css | sort | uniq > /tmp/used-tokens.txt
grep -o '\-\-[a-z][^:]*:' assets/css/layers/01-tokens.css | sort > /tmp/defined-tokens.txt
diff /tmp/defined-tokens.txt /tmp/used-tokens.txt
```
Review diff. Remove confirmed unused tokens from `01-tokens.css`.
**Verify:** Build passes. Spot-check 34 pages visually.
---
## Rules for all agents
1. Read only the files listed for your step — nothing else
2. Run build after every step before reporting done
3. Do not rename variables not listed in this plan
4. Do not touch `main.css` unless the step explicitly says to
5. Do not combine two steps in one session
6. If a primitive is found that isn't in the inventory above, add it to the plan doc and stop — do not fix it unilaterally

73
docs/template-h1-title.md Normal file
View file

@ -0,0 +1,73 @@
# Template Design: Handling the Markdown H1 / Front Matter Title Conflict
## The Problem
Standard markdown convention — Obsidian, agent-written files, generic `.md` — opens
with a level-1 heading as the document title:
```markdown
# My Note Title
Body text...
```
Hugo templates also render a title from front matter:
```html
<h1>{{ .Title }}</h1>
```
When both exist, the page gets two `<h1>` elements: one from the template,
one from the rendered markdown content. The content one also carries an
auto-generated `id` attribute from Hugo's heading anchor renderer.
## The Two Template Contracts
**Default (`_default/single.html`)** — bare markdown, minimal or no front matter.
The `# Title` in content IS the h1. The template header renders only metadata
(type, date, author, tags). No title rendered from front matter.
**Vault (`vault/single.html`)** — enriched front matter (`title`, `type`, `date`,
`author`, `tags`). Front matter `title` is authoritative. The `# Title` in content
is still present (markdown convention) but must be suppressed.
## The Fix: Engine-Agnostic Regex Strip
When a template owns the title (renders `<h1>{{ .Title }}</h1>` from front matter),
strip the first h1 from the rendered content before outputting it.
**Hugo:**
```
{{ replaceRE "<h1[^>]*>.*?</h1>" "" .Content 1 | safeHTML }}
```
**Jinja2 / Flask:**
```python
import re
content = re.sub(r'<h1[^>]*>.*?</h1>', '', content, count=1, flags=re.DOTALL)
```
**Nunjucks / Liquid / any engine:** equivalent string replace on the rendered HTML.
This is a string operation on already-rendered HTML, not a template-engine concept.
It ports to any engine without modification.
## Why Not Other Approaches
- **Author convention** (don't write `# Title` in vault files): breaks compatibility
with the entire markdown ecosystem.
- **Hugo render hooks** (`layouts/vault/_markup/render-heading.html`): Hugo-specific,
not portable.
- **CSS `display: none`**: h1 still exists in DOM — screen readers read it,
search engines index it. Semantically wrong.
## Engine-Agnostic Principle
ASW templates are prototyped in Hugo but must be portable to Flask/Jinja2 or
any other engine. Template logic should express *what*, not *how*:
- What: "strip h1 from content if front matter title is present"
- How: engine-specific implementation of the same string operation
Hugo-specific features (render hooks, shortcodes) are acceptable as prototyping
tools but should not become load-bearing parts of the template design.

View file

@ -20,18 +20,18 @@ title = 'ASW — Agentic Semantic Web'
weight = 2 weight = 2
[[menus.main]] [[menus.main]]
name = "Vault" name = "Notes"
url = "/vault/" url = "/notes/"
weight = 3 weight = 3
[[menus.main]] [[menus.main]]
name = "Papers" name = "Essays"
url = "/papers/" url = "/essays/"
weight = 4 weight = 4
[[menus.main]] [[menus.main]]
name = "Posts" name = "Articles"
url = "/posts/" url = "/articles/"
weight = 5 weight = 5
[[menus.main]] [[menus.main]]
@ -125,7 +125,7 @@ title = 'ASW — Agentic Semantic Web'
[[menus.docs]] [[menus.docs]]
name = "ASW Vocabulary" name = "ASW Vocabulary"
url = "/posts/asw-vocabulary/" url = "/articles/asw-vocabulary/"
parent = "docs-reference" parent = "docs-reference"
weight = 43 weight = 43

View file

@ -1,14 +1,13 @@
{{ define "header" }} {{ define "header" }}
<header> <header>
<hgroup> {{ with .Type }}<p data-text="eyebrow">{{ . }}</p>{{ end }}
{{ with .Params.eyebrow }}<p data-text="eyebrow">{{ . }}</p>{{ end }}
<h1>{{ .Title }}</h1>
{{ with .Description }}<p>{{ . }}</p>{{ end }}
</hgroup>
<p data-text="dim"> <p data-text="dim">
<time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "January 2006" }}</time> <time datetime="{{ .Date.Format "2006-01-02" }}">{{ .Date.Format "January 2006" }}</time>
{{ with .Params.author }} · {{ . }}{{ end }} {{ with .Params.author }} · {{ . }}{{ end }}
</p> </p>
{{ with .Params.tags }}
<p>{{ range . }}<a href="/tags/{{ . }}" data-text="tag">#{{ . }}</a> {{ end }}</p>
{{ end }}
</header> </header>
{{ end }} {{ end }}

View file

@ -0,0 +1,90 @@
{{ define "header" }}
<header>
{{- if .Description -}}
<hgroup>
<h1>{{ .Title }}</h1>
<p>{{ .Description }}</p>
</hgroup>
{{- else -}}
<h1>{{ .Title }}</h1>
{{- end }}
</header>
{{ end }}
{{ define "content" }}
<section data-layout="console">
<nav aria-label="Documentation" data-nav="sidebar">
{{- $menu := index .Site.Menus "docs" -}}
{{- if $menu -}}
{{- range $menu -}}
{{- if .HasChildren -}}
<h3>{{ .Name }}</h3>
<ul>
{{- range .Children -}}
<li>
<a href="{{ .URL }}"
{{- if eq (relURL .URL) $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .Name -}}
</a>
</li>
{{- end -}}
</ul>
{{- else -}}
<ul>
<li>
<a href="{{ .URL }}"
{{- if eq (relURL .URL) $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .Name -}}
</a>
</li>
</ul>
{{- end -}}
{{- end -}}
{{- else -}}
{{- with .CurrentSection -}}
<h3>{{ .Title }}</h3>
<ul>
{{- range .RegularPages -}}
<li>
<a href="{{ .RelPermalink }}"
{{- if eq .RelPermalink $.RelPermalink }} aria-current="page"{{ end -}}>
{{- .LinkTitle -}}
</a>
</li>
{{- end -}}
</ul>
{{- end -}}
{{- end -}}
</nav>
<article>
{{ .Content }}
{{- if or .PrevInSection .NextInSection -}}
<footer data-role="prev-next">
{{- with .NextInSection -}}
<a href="{{ .RelPermalink }}" rel="prev">
<span aria-hidden="true"></span> Previous
<span>{{ .LinkTitle }}</span>
</a>
{{- end -}}
{{- with .PrevInSection -}}
<a href="{{ .RelPermalink }}" rel="next">
Next <span aria-hidden="true"></span>
<span>{{ .LinkTitle }}</span>
</a>
{{- end -}}
</footer>
{{- end -}}
</article>
{{- with .TableOfContents -}}
<aside data-toc>
<h3>On this page</h3>
{{ . }}
</aside>
{{- end -}}
</section>
{{ end }}

View file

@ -58,20 +58,20 @@
{{- end -}} {{- end -}}
</nav> </nav>
<article role="main"> <article>
{{ .Content }} {{ .Content }}
{{- if or .PrevInSection .NextInSection -}} {{- if or .PrevInSection .NextInSection -}}
<footer data-role="prev-next"> <footer data-role="prev-next">
{{- with .NextInSection -}} {{- with .NextInSection -}}
<a href="{{ .RelPermalink }}" rel="prev"> <a href="{{ .RelPermalink }}" rel="prev">
<small>← Previous</small> <span aria-hidden="true"></span> Previous
<span>{{ .LinkTitle }}</span> <span>{{ .LinkTitle }}</span>
</a> </a>
{{- end -}} {{- end -}}
{{- with .PrevInSection -}} {{- with .PrevInSection -}}
<a href="{{ .RelPermalink }}" rel="next"> <a href="{{ .RelPermalink }}" rel="next">
<small>Next →</small> Next <span aria-hidden="true"></span>
<span>{{ .LinkTitle }}</span> <span>{{ .LinkTitle }}</span>
</a> </a>
{{- end -}} {{- end -}}

View file

@ -14,8 +14,8 @@
{{ define "content" }} {{ define "content" }}
<section data-layout="docs"> <section data-layout="docs">
<nav aria-label="Vault" data-nav="sidebar"> <nav aria-label="Notes" data-nav="sidebar">
{{- $menuName := .Site.Params.vault_menu | default "vault" -}} {{- $menuName := .Site.Params.notes_menu | default "notes" -}}
{{- $menu := index .Site.Menus $menuName -}} {{- $menu := index .Site.Menus $menuName -}}
{{- if $menu -}} {{- if $menu -}}
{{- range $menu -}} {{- range $menu -}}
@ -59,7 +59,7 @@
{{- end -}} {{- end -}}
</nav> </nav>
<article role="main"> <article>
{{ .Content }} {{ .Content }}
{{- $prevURL := index .Params "prev-url" -}} {{- $prevURL := index .Params "prev-url" -}}
@ -70,13 +70,13 @@
<footer data-role="prev-next"> <footer data-role="prev-next">
{{- if $prevURL -}} {{- if $prevURL -}}
<a href="{{ $prevURL }}" rel="prev"> <a href="{{ $prevURL }}" rel="prev">
<small>← Previous</small> <span aria-hidden="true"></span> Previous
<span>{{ $prevTitle }}</span> <span>{{ $prevTitle }}</span>
</a> </a>
{{- end -}} {{- end -}}
{{- if and $nextURL $nextTitle -}} {{- if and $nextURL $nextTitle -}}
<a href="{{ $nextURL }}" rel="next"> <a href="{{ $nextURL }}" rel="next">
<small>Next →</small> Next <span aria-hidden="true"></span>
<span>{{ $nextTitle }}</span> <span>{{ $nextTitle }}</span>
</a> </a>
{{- end -}} {{- end -}}

View file

@ -17,9 +17,24 @@
{{- partial "meta/ai-disclosure.html" . -}} {{- partial "meta/ai-disclosure.html" . -}}
{{- partial "meta/json-ld.html" . -}} {{- partial "meta/json-ld.html" . -}}
{{- /* ── CSS — fingerprinted via Hugo Pipes ─────────────────────── */}} {{- /* ── CSS ────────────────────────────────────────────────────── */}}
{{ $css := resources.Get "css/asw-built.css" | minify | fingerprint }} {{- if hugo.IsDevelopment }}
<link rel="stylesheet" href="{{ $css.RelPermalink }}"> <link rel="stylesheet" href="/vendor/open-props.min.css">
<link rel="stylesheet" href="/vendor/media.min.css">
<link rel="stylesheet" href="/css/layers/00-reset.css">
<link rel="stylesheet" href="/css/layers/01-asw.css">
<link rel="stylesheet" href="/css/layers/02-semantic.css">
<link rel="stylesheet" href="/css/layers/03-components.css">
<link rel="stylesheet" href="/css/layers/04-data-attrs.css">
<link rel="stylesheet" href="/css/layers/05-utilities.css">
<link rel="stylesheet" href="/css/layers/06-charts.css">
<link rel="stylesheet" href="/css/layers/07-chroma.css">
<link rel="stylesheet" href="/css/layers/08-layout.css">
<link rel="stylesheet" href="/css/layers/08a-paper.css">
<link rel="stylesheet" href="/css/layers/09-landing.css">
{{- else }}
<link rel="stylesheet" href="/asw.css">
{{- end }}
{{- range .AlternativeOutputFormats -}} {{- range .AlternativeOutputFormats -}}
<link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}"> <link rel="{{ .Rel }}" type="{{ .MediaType.Type }}" href="{{ .Permalink | safeURL }}">