This rune is part of @refrakt-md/plan. Install with npm install @refrakt-md/plan and add "@refrakt-md/plan" to the plugins array in your refrakt.config.json.
Work
A discrete piece of implementation work with acceptance criteria, priority, complexity, and status tracking. Not a user story — a clear description of what needs to change. H2 headings create named sections for structured content like acceptance criteria, approach, and references.
Also available as {% task %}.
Ready work item
A work item ready for implementation with acceptance criteria and approach.
{% work id="RF-142" status="ready" priority="high" complexity="moderate" milestone="v0.5.0" tags="tint,theming" %}
# Implement tint rune dark mode support
The tint rune currently handles single-scheme colour tokens. It needs to support dual light/dark definitions.
## Acceptance Criteria
- [ ] Tint rune accepts light and dark content sections
- [ ] Identity transform emits data-tint-dark when dark values present
- [ ] Theme CSS swaps tokens in prefers-color-scheme: dark
- [ ] Inline tints without dark values fall back to page tokens
- [ ] Inspector audits contrast ratios for both variants
## Approach
The identity transform parses light/dark headings within the tint child rune body. Dark values are emitted as `--tint-dark-*` CSS custom properties alongside the light values.
{% /work %}<article data-rune="work" data-rune-fields="{"id":"RF-142","status":"ready","priority":"high","complexity":"moderate","assignee":"","milestone":"v0.5.0","source":"","supersedes":"","pr":"","tags":"tint,theming","created":"2026-09-13","modified":"2026-09-13"}">
<header data-name="title">
<h1 id="implement-tint-rune-dark-mode-support">Implement tint rune dark mode support</h1>
</header>
<div data-name="blurb">
<p>The tint rune currently handles single-scheme colour tokens. It needs to support dual light/dark definitions.</p>
</div>
<div data-name="body">
<section data-name="acceptance-criteria">
<h2 id="acceptance-criteria">Acceptance Criteria</h2>
<ul>
<li>[ ] Tint rune accepts light and dark content sections</li>
<li>[ ] Identity transform emits data-tint-dark when dark values present</li>
<li>[ ] Theme CSS swaps tokens in prefers-color-scheme: dark</li>
<li>[ ] Inline tints without dark values fall back to page tokens</li>
<li>[ ] Inspector audits contrast ratios for both variants</li>
</ul>
</section>
<section data-name="approach">
<h2 id="approach">Approach</h2>
<p>
The identity transform parses light/dark headings within the tint child rune body. Dark values are emitted as
<code>--tint-dark-*</code>
CSS custom properties alongside the light values.
</p>
</section>
</div>
</article>Implement tint rune dark mode support
The tint rune currently handles single-scheme colour tokens. It needs to support dual light/dark definitions.
Acceptance Criteria
- Tint rune accepts light and dark content sections
- Identity transform emits data-tint-dark when dark values present
- Theme CSS swaps tokens in prefers-color-scheme: dark
- Inline tints without dark values fall back to page tokens
- Inspector audits contrast ratios for both variants
Approach
The identity transform parses light/dark headings within the tint child rune body. Dark values are emitted as --tint-dark-* CSS custom properties alongside the light values.
<article class="rf-work rf-work--RF-142 rf-work--ready rf-work--high rf-work--moderate" data-id="RF-142" data-status="ready" data-priority="high" data-complexity="moderate" data-assignee="" data-milestone="v0.5.0" data-source="" data-supersedes="" data-pr="" data-tags="tint,theming" data-created="2026-09-13" data-modified="2026-09-13" data-rune="work" data-density="full">
<div data-name="eyebrow" data-zone="eyebrow" data-zone-layout="bar" class="rf-work__eyebrow">
<span data-meta-type="id">RF-142</span>
<span class="rf-badge" data-meta-type="status" data-meta-sentiment="neutral" data-align="end">ready</span>
</div>
<header data-name="title" class="rf-work__title" data-section="title">
<h1 id="implement-tint-rune-dark-mode-support">Implement tint rune dark mode support</h1>
</header>
<div data-name="blurb" class="rf-work__blurb" data-section="description">
<p>The tint rune currently handles single-scheme colour tokens. It needs to support dual light/dark definitions.</p>
</div>
<dl data-name="metadata" data-zone="metadata" data-zone-layout="definition-list" class="rf-work__metadata">
<div data-name="row" data-field="priority" class="rf-work__row">
<dt data-meta-label="">Priority</dt>
<dd>
<span class="rf-badge" data-meta-type="category" data-meta-sentiment="caution">high</span>
</dd>
</div>
<div data-name="row" data-field="complexity" class="rf-work__row">
<dt data-meta-label="">Complexity</dt>
<dd data-meta-type="quantity">moderate</dd>
</div>
<div data-name="row" data-field="milestone" class="rf-work__row">
<dt data-meta-label="">Milestone</dt>
<dd>
<span class="rf-badge" data-meta-type="tag">v0.5.0</span>
</dd>
</div>
<div data-name="row" data-field="created" class="rf-work__row">
<dt data-meta-label="">Created</dt>
<dd data-meta-type="temporal">
<time datetime="2026-09-13">2026-09-13</time>
</dd>
</div>
<div data-name="row" data-field="modified" class="rf-work__row">
<dt data-meta-label="">Modified</dt>
<dd data-meta-type="temporal">
<time datetime="2026-09-13">2026-09-13</time>
</dd>
</div>
</dl>
<div data-name="tags" data-zone="tags" data-zone-layout="bar" class="rf-work__tags">
<span class="rf-badge" data-meta-type="tag">tint</span>
<span class="rf-badge" data-meta-type="tag">theming</span>
</div>
<div data-name="body" class="rf-work__body" data-section="body">
<section data-name="acceptance-criteria" class="rf-work__acceptance-criteria">
<h2 id="acceptance-criteria">Acceptance Criteria</h2>
<ul>
<li data-checked="unchecked">Tint rune accepts light and dark content sections</li>
<li data-checked="unchecked">Identity transform emits data-tint-dark when dark values present</li>
<li data-checked="unchecked">Theme CSS swaps tokens in prefers-color-scheme: dark</li>
<li data-checked="unchecked">Inline tints without dark values fall back to page tokens</li>
<li data-checked="unchecked">Inspector audits contrast ratios for both variants</li>
</ul>
</section>
<section data-name="approach" class="rf-work__approach">
<h2 id="approach">Approach</h2>
<p>
The identity transform parses light/dark headings within the tint child rune body. Dark values are emitted as
<code>--tint-dark-*</code>
CSS custom properties alongside the light values.
</p>
</section>
</div>
</article>Blocked work item
A work item blocked by a dependency.
{% work id="RF-215" status="blocked" priority="medium" complexity="complex" assignee="alice" %}
# Alignment system migration
Migrate all runes from manual alignment classes to the new alignment system.
## Acceptance Criteria
- [ ] All runes use alignment utilities instead of manual classes
- [ ] No visual regressions in existing content
- [ ] Migration guide published
{% /work %}<article data-rune="work" data-rune-fields="{"id":"RF-215","status":"blocked","priority":"medium","complexity":"complex","assignee":"alice","milestone":"","source":"","supersedes":"","pr":"","tags":"","created":"2026-09-13","modified":"2026-09-13"}">
<header data-name="title">
<h1 id="alignment-system-migration">Alignment system migration</h1>
</header>
<div data-name="blurb">
<p>Migrate all runes from manual alignment classes to the new alignment system.</p>
</div>
<div data-name="body">
<section data-name="acceptance-criteria">
<h2 id="acceptance-criteria">Acceptance Criteria</h2>
<ul>
<li>[ ] All runes use alignment utilities instead of manual classes</li>
<li>[ ] No visual regressions in existing content</li>
<li>[ ] Migration guide published</li>
</ul>
</section>
</div>
</article>Alignment system migration
Migrate all runes from manual alignment classes to the new alignment system.
Acceptance Criteria
- All runes use alignment utilities instead of manual classes
- No visual regressions in existing content
- Migration guide published
<article class="rf-work rf-work--RF-215 rf-work--blocked rf-work--medium rf-work--complex" data-id="RF-215" data-status="blocked" data-priority="medium" data-complexity="complex" data-assignee="alice" data-milestone="" data-source="" data-supersedes="" data-pr="" data-tags="" data-created="2026-09-13" data-modified="2026-09-13" data-rune="work" data-density="full">
<div data-name="eyebrow" data-zone="eyebrow" data-zone-layout="bar" class="rf-work__eyebrow">
<span data-meta-type="id">RF-215</span>
<span class="rf-badge" data-meta-type="status" data-meta-sentiment="negative" data-align="end">blocked</span>
</div>
<header data-name="title" class="rf-work__title" data-section="title">
<h1 id="alignment-system-migration">Alignment system migration</h1>
</header>
<div data-name="blurb" class="rf-work__blurb" data-section="description">
<p>Migrate all runes from manual alignment classes to the new alignment system.</p>
</div>
<dl data-name="metadata" data-zone="metadata" data-zone-layout="definition-list" class="rf-work__metadata">
<div data-name="row" data-field="priority" class="rf-work__row">
<dt data-meta-label="">Priority</dt>
<dd>
<span class="rf-badge" data-meta-type="category" data-meta-sentiment="neutral">medium</span>
</dd>
</div>
<div data-name="row" data-field="complexity" class="rf-work__row">
<dt data-meta-label="">Complexity</dt>
<dd data-meta-type="quantity">complex</dd>
</div>
<div data-name="row" data-field="assignee" class="rf-work__row">
<dt data-meta-label="">Assignee</dt>
<dd>
<span class="rf-badge" data-meta-type="tag">alice</span>
</dd>
</div>
<div data-name="row" data-field="created" class="rf-work__row">
<dt data-meta-label="">Created</dt>
<dd data-meta-type="temporal">
<time datetime="2026-09-13">2026-09-13</time>
</dd>
</div>
<div data-name="row" data-field="modified" class="rf-work__row">
<dt data-meta-label="">Modified</dt>
<dd data-meta-type="temporal">
<time datetime="2026-09-13">2026-09-13</time>
</dd>
</div>
</dl>
<div data-name="body" class="rf-work__body" data-section="body">
<section data-name="acceptance-criteria" class="rf-work__acceptance-criteria">
<h2 id="acceptance-criteria">Acceptance Criteria</h2>
<ul>
<li data-checked="unchecked">All runes use alignment utilities instead of manual classes</li>
<li data-checked="unchecked">No visual regressions in existing content</li>
<li data-checked="unchecked">Migration guide published</li>
</ul>
</section>
</div>
</article>Attributes
| Attribute | Type | Required | Description |
|---|---|---|---|
id | string | ✓ | Unique identifier (e.g., "RF-142"). |
status | "draft" | "ready" | "in-progress" | "review" | "done" | "blocked" | "pending" | "cancelled" | "superseded" | — | Current status: draft, ready, in-progress, review, done, blocked, pending, cancelled, or superseded. |
priority | "critical" | "high" | "medium" | "low" | — | Priority level: critical, high, medium, or low. |
complexity | "trivial" | "simple" | "moderate" | "complex" | "unknown" | — | Complexity signal: trivial, simple, moderate, complex, or unknown. |
assignee | string | — | Person or agent working on this. |
milestone | string | — | Milestone this belongs to. |
source | string | — | Comma-separated IDs of specs or decisions this item implements. |
supersedes | string | — | ID of the work item this replaces (set when status="superseded"). |
pr | string | — | Comma-separated PR references that implemented this item (e.g. "refrakt-md/refrakt#142"). |
tags | string | — | Comma-separated labels. |
created | string | — | Creation date (ISO 8601). Defaults to file creation date from git. |
modified | string | — | Last modified date (ISO 8601). Defaults to file modification date from git. |
Universal attributes
bg
The background layer (SPEC-088): image, video, gradient, flat overlay wash and legibility scrim, in a single injected layer behind the rune's content.
| Attribute | Type | Required | Description |
|---|---|---|---|
bg | string | — | Background preset applied to this block |
bg-from | string | — | Gradient start colour — a semantic token name (→ var(--rf-color-*)) |
bg-gradient | "to-t" | "to-b" | "to-l" | "to-r" | "to-tr" | "to-br" | "to-bl" | "to-tl" | — | Gradient direction (bounded named set) |
bg-gradient-type | "linear" | "radial" | "conic" | — | Gradient type |
bg-to | string | — | Gradient end colour — a semantic token name |
bg-via | string | — | Optional middle gradient stop — a semantic token name |
scrim | "top" | "bottom" | "left" | "right" | "none" | — | Scrim direction (heaviest edge); presence turns the scrim on, "none" opts out of the default cover scrim |
scrim-blur | "none" | "sm" | "md" | "lg" | — | Frost scrim blur amount |
scrim-strength | "sm" | "md" | "lg" | — | Gradient scrim strength |
scrim-tone | "dark" | "light" | — | Whether the scrim darkens (for light text) or lightens (for dark text) |
scrim-type | "gradient" | "frost" | — | Scrim treatment: gradient (default) or frost (backdrop blur) |
dropcap
Per-instance drop-cap opt-in (SPEC-108).
| Attribute | Type | Required | Description |
|---|---|---|---|
dropcap | boolean | — | Style the opening letter of a prose body as a drop cap (SPEC-108). Honoured only when the body reads as prose; ignored otherwise. |
elevation
The chrome/depth ladder (SPEC-107). The skin maps each rung to a chrome bundle by attribute, so there is no BEM class.
| Attribute | Type | Required | Description |
|---|---|---|---|
elevation | "sunken" | "flush" | "flat" | "raised" | "floating" | "overlay" | "none" | "sm" | "md" | "lg" | — | Surface depth on the SPEC-107 ladder (sunken→overlay); none/sm/md/lg are deprecated aliases |
inset
Internal padding override.
| Attribute | Type | Required | Description |
|---|---|---|---|
inset | "flush" | "tight" | "default" | "loose" | "breathe" | — | Inner padding of this block |
motion
Scroll-reveal entrance (SPEC-105). The author declares the character, the theme owns the choreography, a behaviour owns the timing.
| Attribute | Type | Required | Description |
|---|---|---|---|
reveal | "none" | "fade" | "slide" | "scale" | "blur" | — | Scroll-reveal entrance character (none|fade|slide|scale|blur); the theme owns the choreography |
stagger | boolean | — | Cascade this block's items in as it reveals (no-op on single-child runes) |
prominence
Header emphasis (SPEC-107). Scales a rune's page-section header; the skin maps it to a type register by attribute, so there is no BEM class.
| Attribute | Type | Required | Description |
|---|---|---|---|
prominence | "quiet" | "normal" | "prominent" | "display" | — | Section-header emphasis (only on page-section-header family runes) |
reading
Editorial register for body text (SPEC-108). The author picks the register; the theme owns the magnitude.
| Attribute | Type | Required | Description |
|---|---|---|---|
reading | "fine" | "ui" | "prose" | — | Reading register for this block’s body (SPEC-108): fine | ui | prose. The theme owns the editorial treatment. |
spacing
Block-level rhythm override.
| Attribute | Type | Required | Description |
|---|---|---|---|
spacing | "flush" | "tight" | "default" | "loose" | "breathe" | — | Vertical spacing above and below this block |
substrate
Generated pattern fills (SPEC-087). Markers only — the engine sets the attributes and cell/opacity custom properties, CSS draws the pattern.
| Attribute | Type | Required | Description |
|---|---|---|---|
substrate | "dots" | "grid" | "lines" | "cross" | "checker" | "none" | — | Generated surface pattern |
substrate-fill | "inherit" | "inset" | — | Surface fill the pattern sits on (full colour stays with tint) |
substrate-opacity | "sm" | "md" | "lg" | — | Pattern ink strength |
substrate-size | "sm" | "md" | "lg" | — | Pattern cell size |
substrate-target | "self" | "media" | — | Which surface the pattern fills (overrides the rune/theme default) |
tint
Per-rune colour override (SPEC-053): a named tint from the theme registry, with inline per-token overrides layered on top.
| Attribute | Type | Required | Description |
|---|---|---|---|
tint | string | — | Color tint preset applied to this block |
tint-mode | "auto" | "dark" | "light" | — | Whether the tint adapts to auto, dark, or light mode |
width
The track a block rune occupies.
| Attribute | Type | Required | Description |
|---|---|---|---|
width | "compact" | "narrow" | "content" | "wide" | "full" | — | Maximum width constraint for this block |
| Not available | Why |
|---|---|
| frame | this rune declares neither a `frameTarget` nor a media section |
Retiring a work item
Not every work item ships. Rather than deleting the file (which loses the reasoning trail) or marking it done (which lies to progress rollups), use one of the two terminal-but-non-achieving states:
cancelled— the work is deliberately dropped and no longer wanted. Record the reason in the body or a## Resolution.superseded— the work is replaced by a different item. Pair it withsupersedes="WORK-xxx"pointing at the replacement.
Both statuses end the item's lifecycle without counting as completion — they are excluded from plan next, from milestone progress, and from plan-progress achieved counts. A ## Resolution explaining the retirement is allowed on either. | created | string | $file.created | Creation date (ISO 8601). Auto-populated from git history | | modified | string | $file.modified | Last modified date (ISO 8601). Auto-populated from git history |