Budget
Structured budgets with categories and line items. Headings become budget categories, and list items with a "Description: $amount" pattern are parsed into line items with automatic subtotals.
Basic usage
Use headings for categories and list items with amounts for line items.
{% budget currency="JPY" duration="5 days" %}
Spring 2026
# Tokyo Trip
A week in Japan — temples, food, and a night in a ryokan.
## Accommodation
- Hotel in Shinjuku: ¥15000
- Ryokan in Hakone: ¥25000
## Transportation
- Japan Rail Pass (7-day): ¥29650
- Airport transfer: ¥3000
- Local metro cards: ¥5000
## Food & Dining
- Daily meals: ¥5000
- Sushi experience: ¥8000
{% /budget %}<section data-field="content-section" data-rune="budget" typeof="ItemList" data-rune-fields="{"currency":"JPY","duration":"5 days","showPerDay":"true","variant":"detailed","total":"90650","perDay":"18130"}">
<p data-name="eyebrow">Spring 2026</p>
<h1 id="tokyo-trip" data-name="headline">Tokyo Trip</h1>
<p data-name="blurb">A week in Japan — temples, food, and a night in a ryokan.</p>
<div data-name="categories">
<div data-field="category" data-rune="budget-category" data-rune-fields="{"label":"Accommodation","estimate":"false","subtotal":"40000"}">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Accommodation</span>
<span class="rf-budget-category__subtotal">¥40,000</span>
</div>
<ul data-name="line-items">
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Hotel in Shinjuku</span>
<span data-field="amount">¥15000</span>
</li>
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Ryokan in Hakone</span>
<span data-field="amount">¥25000</span>
</li>
</ul>
</div>
<div data-field="category" data-rune="budget-category" data-rune-fields="{"label":"Transportation","estimate":"false","subtotal":"37650"}">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Transportation</span>
<span class="rf-budget-category__subtotal">¥37,650</span>
</div>
<ul data-name="line-items">
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Japan Rail Pass (7-day)</span>
<span data-field="amount">¥29650</span>
</li>
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Airport transfer</span>
<span data-field="amount">¥3000</span>
</li>
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Local metro cards</span>
<span data-field="amount">¥5000</span>
</li>
</ul>
</div>
<div data-field="category" data-rune="budget-category" data-rune-fields="{"label":"Food & Dining","estimate":"false","subtotal":"13000"}">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Food & Dining</span>
<span class="rf-budget-category__subtotal">¥13,000</span>
</div>
<ul data-name="line-items">
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Daily meals</span>
<span data-field="amount">¥5000</span>
</li>
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Sushi experience</span>
<span data-field="amount">¥8000</span>
</li>
</ul>
</div>
</div>
<div class="rf-budget__footer">
<div class="rf-budget__total">
<span class="rf-budget__total-label" data-i18n="core.budget.total">Total</span>
<span class="rf-budget__total-amount">¥90,650</span>
</div>
<div class="rf-budget__per-day">
<span class="rf-budget__per-day-label" data-i18n="core.budget.perDay">Per day</span>
<span class="rf-budget__per-day-amount">¥18,130</span>
</div>
</div>
</section>Tokyo Trip
A week in Japan — temples, food, and a night in a ryokan.
Spring 2026
- Hotel in Shinjuku¥15000
- Ryokan in Hakone¥25000
- Japan Rail Pass (7-day)¥29650
- Airport transfer¥3000
- Local metro cards¥5000
- Daily meals¥5000
- Sushi experience¥8000
<section data-field="content-section" typeof="ItemList" class="rf-budget rf-budget--JPY rf-budget--5 days rf-budget--true rf-budget--detailed" data-currency="JPY" data-duration="5 days" data-show-per-day="true" data-variant="detailed" data-elevation="flat" data-rune="budget" data-density="full">
<div data-name="meta" data-zone="meta" data-zone-layout="bar" class="rf-budget__meta">
<span class="rf-badge" data-meta-type="category">5 days</span>
<span class="rf-badge" data-meta-type="category" data-align="end">JPY</span>
</div>
<header data-name="preamble" class="rf-budget__preamble" data-section="preamble">
<h1 id="tokyo-trip" data-name="headline" class="rf-budget__headline" data-section="title">Tokyo Trip</h1>
<p data-name="blurb" class="rf-budget__blurb">A week in Japan — temples, food, and a night in a ryokan.</p>
</header>
<p data-name="eyebrow" class="rf-budget__eyebrow">Spring 2026</p>
<div data-name="categories" class="rf-budget__categories">
<div data-field="category" class="rf-budget-category rf-budget-category--false" data-estimate="false" data-label="Accommodation" data-subtotal="40000" data-rune="budget-category" data-density="full">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Accommodation</span>
<span class="rf-budget-category__subtotal">¥40,000</span>
</div>
<ul data-name="line-items" class="rf-budget-category__line-items">
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Hotel in Shinjuku</span>
<span data-field="amount">¥15000</span>
</li>
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Ryokan in Hakone</span>
<span data-field="amount">¥25000</span>
</li>
</ul>
</div>
<div data-field="category" class="rf-budget-category rf-budget-category--false" data-estimate="false" data-label="Transportation" data-subtotal="37650" data-rune="budget-category" data-density="full">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Transportation</span>
<span class="rf-budget-category__subtotal">¥37,650</span>
</div>
<ul data-name="line-items" class="rf-budget-category__line-items">
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Japan Rail Pass (7-day)</span>
<span data-field="amount">¥29650</span>
</li>
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Airport transfer</span>
<span data-field="amount">¥3000</span>
</li>
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Local metro cards</span>
<span data-field="amount">¥5000</span>
</li>
</ul>
</div>
<div data-field="category" class="rf-budget-category rf-budget-category--false" data-estimate="false" data-label="Food & Dining" data-subtotal="13000" data-rune="budget-category" data-density="full">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Food & Dining</span>
<span class="rf-budget-category__subtotal">¥13,000</span>
</div>
<ul data-name="line-items" class="rf-budget-category__line-items">
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Daily meals</span>
<span data-field="amount">¥5000</span>
</li>
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Sushi experience</span>
<span data-field="amount">¥8000</span>
</li>
</ul>
</div>
</div>
<div class="rf-budget__footer">
<div class="rf-budget__total">
<span class="rf-budget__total-label">Total</span>
<span class="rf-budget__total-amount">¥90,650</span>
</div>
<div class="rf-budget__per-day">
<span class="rf-budget__per-day-label">Per day</span>
<span class="rf-budget__per-day-amount">¥18,130</span>
</div>
</div>
</section>Summary variant
Use variant="summary" to show only category totals without individual line items.
{% budget currency="JPY" duration="5 days" variant="summary" %}
Spring 2026
# Tokyo Trip
A week in Japan — temples, food, and a night in a ryokan.
## Accommodation
- Hotel in Shinjuku: ¥15000
- Ryokan in Hakone: ¥25000
## Transportation
- Japan Rail Pass (7-day): ¥29650
- Airport transfer: ¥3000
- Local metro cards: ¥5000
## Food & Dining
- Daily meals: ¥5000
- Sushi experience: ¥8000
{% /budget %}<section data-field="content-section" data-rune="budget" typeof="ItemList" data-rune-fields="{"currency":"JPY","duration":"5 days","showPerDay":"true","variant":"summary","total":"90650","perDay":"18130"}">
<p data-name="eyebrow">Spring 2026</p>
<h1 id="tokyo-trip" data-name="headline">Tokyo Trip</h1>
<p data-name="blurb">A week in Japan — temples, food, and a night in a ryokan.</p>
<div data-name="categories">
<div data-field="category" data-rune="budget-category" data-rune-fields="{"label":"Accommodation","estimate":"false","subtotal":"40000"}">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Accommodation</span>
<span class="rf-budget-category__subtotal">¥40,000</span>
</div>
<ul data-name="line-items">
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Hotel in Shinjuku</span>
<span data-field="amount">¥15000</span>
</li>
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Ryokan in Hakone</span>
<span data-field="amount">¥25000</span>
</li>
</ul>
</div>
<div data-field="category" data-rune="budget-category" data-rune-fields="{"label":"Transportation","estimate":"false","subtotal":"37650"}">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Transportation</span>
<span class="rf-budget-category__subtotal">¥37,650</span>
</div>
<ul data-name="line-items">
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Japan Rail Pass (7-day)</span>
<span data-field="amount">¥29650</span>
</li>
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Airport transfer</span>
<span data-field="amount">¥3000</span>
</li>
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Local metro cards</span>
<span data-field="amount">¥5000</span>
</li>
</ul>
</div>
<div data-field="category" data-rune="budget-category" data-rune-fields="{"label":"Food & Dining","estimate":"false","subtotal":"13000"}">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Food & Dining</span>
<span class="rf-budget-category__subtotal">¥13,000</span>
</div>
<ul data-name="line-items">
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Daily meals</span>
<span data-field="amount">¥5000</span>
</li>
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Sushi experience</span>
<span data-field="amount">¥8000</span>
</li>
</ul>
</div>
</div>
<div class="rf-budget__footer">
<div class="rf-budget__total">
<span class="rf-budget__total-label" data-i18n="core.budget.total">Total</span>
<span class="rf-budget__total-amount">¥90,650</span>
</div>
<div class="rf-budget__per-day">
<span class="rf-budget__per-day-label" data-i18n="core.budget.perDay">Per day</span>
<span class="rf-budget__per-day-amount">¥18,130</span>
</div>
</div>
</section>Tokyo Trip
A week in Japan — temples, food, and a night in a ryokan.
Spring 2026
- Hotel in Shinjuku¥15000
- Ryokan in Hakone¥25000
- Japan Rail Pass (7-day)¥29650
- Airport transfer¥3000
- Local metro cards¥5000
- Daily meals¥5000
- Sushi experience¥8000
<section data-field="content-section" typeof="ItemList" class="rf-budget rf-budget--JPY rf-budget--5 days rf-budget--true rf-budget--summary" data-currency="JPY" data-duration="5 days" data-show-per-day="true" data-variant="summary" data-elevation="flat" data-rune="budget" data-density="full">
<div data-name="meta" data-zone="meta" data-zone-layout="bar" class="rf-budget__meta">
<span class="rf-badge" data-meta-type="category">5 days</span>
<span class="rf-badge" data-meta-type="category" data-align="end">JPY</span>
</div>
<header data-name="preamble" class="rf-budget__preamble" data-section="preamble">
<h1 id="tokyo-trip" data-name="headline" class="rf-budget__headline" data-section="title">Tokyo Trip</h1>
<p data-name="blurb" class="rf-budget__blurb">A week in Japan — temples, food, and a night in a ryokan.</p>
</header>
<p data-name="eyebrow" class="rf-budget__eyebrow">Spring 2026</p>
<div data-name="categories" class="rf-budget__categories">
<div data-field="category" class="rf-budget-category rf-budget-category--false" data-estimate="false" data-label="Accommodation" data-subtotal="40000" data-rune="budget-category" data-density="full">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Accommodation</span>
<span class="rf-budget-category__subtotal">¥40,000</span>
</div>
<ul data-name="line-items" class="rf-budget-category__line-items">
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Hotel in Shinjuku</span>
<span data-field="amount">¥15000</span>
</li>
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Ryokan in Hakone</span>
<span data-field="amount">¥25000</span>
</li>
</ul>
</div>
<div data-field="category" class="rf-budget-category rf-budget-category--false" data-estimate="false" data-label="Transportation" data-subtotal="37650" data-rune="budget-category" data-density="full">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Transportation</span>
<span class="rf-budget-category__subtotal">¥37,650</span>
</div>
<ul data-name="line-items" class="rf-budget-category__line-items">
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Japan Rail Pass (7-day)</span>
<span data-field="amount">¥29650</span>
</li>
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Airport transfer</span>
<span data-field="amount">¥3000</span>
</li>
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Local metro cards</span>
<span data-field="amount">¥5000</span>
</li>
</ul>
</div>
<div data-field="category" class="rf-budget-category rf-budget-category--false" data-estimate="false" data-label="Food & Dining" data-subtotal="13000" data-rune="budget-category" data-density="full">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Food & Dining</span>
<span class="rf-budget-category__subtotal">¥13,000</span>
</div>
<ul data-name="line-items" class="rf-budget-category__line-items">
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Daily meals</span>
<span data-field="amount">¥5000</span>
</li>
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Sushi experience</span>
<span data-field="amount">¥8000</span>
</li>
</ul>
</div>
</div>
<div class="rf-budget__footer">
<div class="rf-budget__total">
<span class="rf-budget__total-label">Total</span>
<span class="rf-budget__total-amount">¥90,650</span>
</div>
<div class="rf-budget__per-day">
<span class="rf-budget__per-day-label">Per day</span>
<span class="rf-budget__per-day-amount">¥18,130</span>
</div>
</div>
</section>Estimates
Mark categories as estimates by adding (estimate) or (est.) to the heading, or use strikethrough.
{% budget currency="USD" %}
# Weekend Getaway
## Hotel
- Two nights downtown: $250
## Activities (estimate)
- Museum passes: $40
- Boat tour: $60-80
- Dining: $100-150
{% /budget %}<section data-field="content-section" data-rune="budget" typeof="ItemList" data-rune-fields="{"currency":"USD","duration":"","showPerDay":"true","variant":"detailed","total":"485"}">
<h1 id="weekend-getaway" data-name="headline">Weekend Getaway</h1>
<div data-name="categories">
<div data-field="category" data-rune="budget-category" data-rune-fields="{"label":"Hotel","estimate":"false","subtotal":"250"}">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Hotel</span>
<span class="rf-budget-category__subtotal">$250</span>
</div>
<ul data-name="line-items">
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Two nights downtown</span>
<span data-field="amount">$250</span>
</li>
</ul>
</div>
<div data-field="category" data-rune="budget-category" data-rune-fields="{"label":"Activities","estimate":"estimate","subtotal":"235"}">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Activities</span>
<span class="rf-budget-category__subtotal">$235</span>
</div>
<ul data-name="line-items">
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Museum passes</span>
<span data-field="amount">$40</span>
</li>
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Boat tour</span>
<span data-field="amount">$60-80</span>
</li>
<li data-field="line-item" data-rune="budget-line-item">
<span data-field="description">Dining</span>
<span data-field="amount">$100-150</span>
</li>
</ul>
</div>
</div>
<div class="rf-budget__footer">
<div class="rf-budget__total">
<span class="rf-budget__total-label" data-i18n="core.budget.total">Total</span>
<span class="rf-budget__total-amount">$485</span>
</div>
</div>
</section>Weekend Getaway
- Two nights downtown$250
- Museum passes$40
- Boat tour$60-80
- Dining$100-150
<section data-field="content-section" typeof="ItemList" class="rf-budget rf-budget--USD rf-budget--true rf-budget--detailed" data-currency="USD" data-duration="" data-show-per-day="true" data-variant="detailed" data-elevation="flat" data-rune="budget" data-density="full">
<div data-name="meta" data-zone="meta" data-zone-layout="bar" class="rf-budget__meta">
<span class="rf-badge" data-meta-type="category" data-align="end">USD</span>
</div>
<header data-name="preamble" class="rf-budget__preamble" data-section="preamble">
<h1 id="weekend-getaway" data-name="headline" class="rf-budget__headline" data-section="title">Weekend Getaway</h1>
</header>
<div data-name="categories" class="rf-budget__categories">
<div data-field="category" class="rf-budget-category rf-budget-category--false" data-estimate="false" data-label="Hotel" data-subtotal="250" data-rune="budget-category" data-density="full">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Hotel</span>
<span class="rf-budget-category__subtotal">$250</span>
</div>
<ul data-name="line-items" class="rf-budget-category__line-items">
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Two nights downtown</span>
<span data-field="amount">$250</span>
</li>
</ul>
</div>
<div data-field="category" class="rf-budget-category rf-budget-category--estimate" data-estimate="estimate" data-label="Activities" data-subtotal="235" data-rune="budget-category" data-density="full">
<div class="rf-budget-category__header">
<span class="rf-budget-category__label">Activities</span>
<span class="rf-budget-category__subtotal">$235</span>
</div>
<ul data-name="line-items" class="rf-budget-category__line-items">
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Museum passes</span>
<span data-field="amount">$40</span>
</li>
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Boat tour</span>
<span data-field="amount">$60-80</span>
</li>
<li data-field="line-item" class="rf-budget-line-item" data-rune="budget-line-item" data-density="full">
<span data-field="description">Dining</span>
<span data-field="amount">$100-150</span>
</li>
</ul>
</div>
</div>
<div class="rf-budget__footer">
<div class="rf-budget__total">
<span class="rf-budget__total-label">Total</span>
<span class="rf-budget__total-amount">$485</span>
</div>
</div>
</section>Section header
Budget supports an optional eyebrow, headline, and blurb above the categories. Place a short paragraph or heading before the first category heading to use them. See Page sections for the full syntax.
Attributes
budget
| Attribute | Type | Required | Description |
|---|---|---|---|
currency | string | — | Currency symbol or code (e.g. USD, EUR) |
duration | string | — | Budget duration for per-day calculations (e.g. "5 days", "1 month") |
showPerDay | boolean | — | Show per-day cost breakdown |
variant | "detailed" | "summary" | — | Display style: detailed line items or summary |
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) |
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) |
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 |
|---|---|
| dropcap, reading | this rune declares no prose body |
| frame | this rune declares neither a `frameTarget` nor a media section |
budget-category
| Attribute | Type | Required | Description |
|---|---|---|---|
label | string | ✓ | |
estimate | boolean | — |
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) |
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) |
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 |
|---|---|
| dropcap, reading | this rune declares no prose body |
| frame | this rune declares neither a `frameTarget` nor a media section |
| prominence | this rune has no page-section header |
budget-line-item
| Attribute | Type | Required | Description |
|---|---|---|---|
description | string | — | Line item description |
amount | string | — | Line item amount |
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) |
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) |
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 |
|---|---|
| dropcap, reading | this rune declares no prose body |
| frame | this rune declares neither a `frameTarget` nor a media section |
| prominence | this rune has no page-section header |