Layout›Section

Section

A generic page section: a short header — eyebrow, headline, blurb — above an arbitrary body. Use it to introduce any content block with a title and intro, especially primitives that have no header of their own like bento, a grid of cards, or a collection.

The header is anchored to the headline, written as a heading at the start of the section. A paragraph directly before it is the eyebrow, and a paragraph directly after it is the blurb. Everything else is the body. A section that does not start with a heading, or with one paragraph and then a heading, has no header: all of its content is body, so prose placed in a section is never re-read as an eyebrow.

Basic usage

{% section %}
	Composability

	## Runes that work together

	Every block is a rune — combine them freely to build a page.

	{% bento %}
	## Marketing
	Hero, CTA, pricing, testimonials.

	## Docs
	API references, changelogs, symbols.

	## Storytelling
	Characters, realms, factions, lore.
	{% /bento %}
{% /section %}
<section data-rune="section" data-rune-fields="{&quot;align&quot;:&quot;start&quot;}">
  <header>
    <p data-name="eyebrow">Composability</p>
    <h2 id="runes-that-work-together" data-name="headline">Runes that work together</h2>
    <p data-name="blurb">Every block is a rune — combine them freely to build a page.</p>
  </header>
  <div data-name="body">
    <section data-rune="bento" data-rune-fields="{&quot;gap&quot;:&quot;1rem&quot;,&quot;columns&quot;:&quot;6&quot;,&quot;row-height&quot;:&quot;&quot;,&quot;content-height&quot;:&quot;&quot;,&quot;media-ratio&quot;:&quot;&quot;,&quot;collapse&quot;:&quot;&quot;}">
      <div data-name="grid">
        <div data-rune="bento-cell" data-rune-fields="{&quot;size&quot;:&quot;large&quot;,&quot;cols&quot;:&quot;4&quot;,&quot;rows&quot;:&quot;2&quot;,&quot;content-height&quot;:&quot;&quot;,&quot;media-ratio&quot;:&quot;&quot;}" data-media-position="start" data-field="cell">
          <h3 id="marketing" data-name="title">Marketing</h3>
          <div data-name="body">
            <p>Hero, CTA, pricing, testimonials.</p>
          </div>
        </div>
        <div data-rune="bento-cell" data-rune-fields="{&quot;size&quot;:&quot;large&quot;,&quot;cols&quot;:&quot;4&quot;,&quot;rows&quot;:&quot;2&quot;,&quot;content-height&quot;:&quot;&quot;,&quot;media-ratio&quot;:&quot;&quot;}" data-media-position="start" data-field="cell">
          <h3 id="docs" data-name="title">Docs</h3>
          <div data-name="body">
            <p>API references, changelogs, symbols.</p>
          </div>
        </div>
        <div data-rune="bento-cell" data-rune-fields="{&quot;size&quot;:&quot;large&quot;,&quot;cols&quot;:&quot;4&quot;,&quot;rows&quot;:&quot;2&quot;,&quot;content-height&quot;:&quot;&quot;,&quot;media-ratio&quot;:&quot;&quot;}" data-media-position="start" data-field="cell">
          <h3 id="storytelling" data-name="title">Storytelling</h3>
          <div data-name="body">
            <p>Characters, realms, factions, lore.</p>
          </div>
        </div>
      </div>
    </section>
  </div>
</section>

Composability

Runes that work together

Every block is a rune — combine them freely to build a page.

Marketing

Hero, CTA, pricing, testimonials.

Docs

API references, changelogs, symbols.

Storytelling

Characters, realms, factions, lore.

<section class="rf-section rf-section--start" data-align="start" data-rune="section" data-density="full">
  <header data-name="preamble" class="rf-section__preamble" data-section="preamble">
    <p data-name="eyebrow" class="rf-section__eyebrow" data-section="eyebrow">Composability</p>
    <h2 id="runes-that-work-together" data-name="headline" class="rf-section__headline" data-section="title">Runes that work together</h2>
    <p data-name="blurb" class="rf-section__blurb" data-section="description">Every block is a rune — combine them freely to build a page.</p>
  </header>
  <div data-name="body" class="rf-section__body" data-section="body">
    <section class="rf-bento" data-columns="6" data-gap="1rem" data-row-height="" data-content-height="" data-media-ratio="" data-collapse="" data-elevation="flush" data-rune="bento" data-density="full" style="--bento-columns: 6; --bento-gap: 1rem">
      <div data-name="grid" class="rf-bento__grid">
        <div class="rf-bento-cell" data-media-position="start" data-field="cell" data-size="large" data-cols="4" data-rows="2" data-content-height="" data-media-ratio="" data-rune="bento-cell" data-density="compact" style="--cell-cols: 4; --cell-rows: 2">
          <div data-name="content" class="rf-bento-cell__content">
            <h3 id="marketing" data-name="title" class="rf-bento-cell__title" data-section="title">Marketing</h3>
            <div data-name="body" class="rf-bento-cell__body" data-section="body">
              <p>Hero, CTA, pricing, testimonials.</p>
            </div>
          </div>
        </div>
        <div class="rf-bento-cell" data-media-position="start" data-field="cell" data-size="large" data-cols="4" data-rows="2" data-content-height="" data-media-ratio="" data-rune="bento-cell" data-density="compact" style="--cell-cols: 4; --cell-rows: 2">
          <div data-name="content" class="rf-bento-cell__content">
            <h3 id="docs" data-name="title" class="rf-bento-cell__title" data-section="title">Docs</h3>
            <div data-name="body" class="rf-bento-cell__body" data-section="body">
              <p>API references, changelogs, symbols.</p>
            </div>
          </div>
        </div>
        <div class="rf-bento-cell" data-media-position="start" data-field="cell" data-size="large" data-cols="4" data-rows="2" data-content-height="" data-media-ratio="" data-rune="bento-cell" data-density="compact" style="--cell-cols: 4; --cell-rows: 2">
          <div data-name="content" class="rf-bento-cell__content">
            <h3 id="storytelling" data-name="title" class="rf-bento-cell__title" data-section="title">Storytelling</h3>
            <div data-name="body" class="rf-bento-cell__body" data-section="body">
              <p>Characters, realms, factions, lore.</p>
            </div>
          </div>
        </div>
      </div>
    </section>
  </div>
</section>

Header-only or body-only

Every header slot is optional. With no leading heading the section is just a styled wrapper around its body; with only a header it's a standalone intro.

Choose which header roles to read

header says how much of the start of the section becomes its header:

ValueReads
auto (default)eyebrow, headline and blurb, around a leading heading
headlineonly a leading heading; the paragraph after it stays body
noneno header; all content is body
{% section header="headline" %}
## Release notes

This paragraph is body text, not a blurb.
{% /section %}
<section data-rune="section" data-rune-fields="{&quot;align&quot;:&quot;start&quot;}">
  <header>
    <h2 id="release-notes" data-name="headline">Release notes</h2>
  </header>
  <div data-name="body">
    <p>This paragraph is body text, not a blurb.</p>
  </div>
</section>

Release notes

This paragraph is body text, not a blurb.

<section class="rf-section rf-section--start" data-align="start" data-rune="section" data-density="full">
  <header data-name="preamble" class="rf-section__preamble" data-section="preamble">
    <h2 id="release-notes" data-name="headline" class="rf-section__headline" data-section="title">Release notes</h2>
  </header>
  <div data-name="body" class="rf-section__body" data-section="body">
    <p>This paragraph is body text, not a blurb.</p>
  </div>
</section>

A composed rune that places a section gets the same grammar for its slots. When a slot's content lands in a header role the slot is not named for, the build reports slot-header-role and names both remedies: name the field for the role, or set header on the section.

Media beside or above the content

Give a section media-position and it splits on --- the way card does: a leading media zone, the content, and an optional trailing footer. The header stays in the content column, beside or below the media. Without media-position the section reads no zones, and a --- is an ordinary rule in the body.

{% section media-position="start" media-ratio="1/3" %}
![A harbour at dawn](placeholder:landscape)

---

Field notes

## The harbour at dawn

Salt, rope and the first boats going out.

The tide turns an hour after sunrise, and the market opens with it.
{% /section %}
<section data-rune="section" data-rune-fields="{&quot;align&quot;:&quot;start&quot;,&quot;media-position&quot;:&quot;start&quot;,&quot;media-ratio&quot;:&quot;1/3&quot;}">
  <div data-name="media">
    <svg class="rf-placeholder" data-shape="cover" viewBox="0 0 1600 900" preserveAspectRatio="xMidYMid slice" width="100%" fill="none" role="img" aria-label="A harbour at dawn">
      <rect x="0" y="0" width="1600" height="900" fill="var(--rf-color-surface)"></rect>
      <circle cx="1216" cy="270" r="90" fill="var(--rf-color-border)"></circle>
      <path d="M0 648 Q 448 495 800 630 T 1600 576 L 1600 900 L 0 900 Z" fill="var(--rf-color-muted)"></path>
      <rect x="4" y="4" width="1593" height="893" fill="none" stroke="var(--rf-color-border)" stroke-width="7"></rect>
    </svg>
  </div>
  <div data-name="content">
    <header>
      <p data-name="eyebrow">Field notes</p>
      <h2 id="the-harbour-at-dawn" data-name="headline">The harbour at dawn</h2>
      <p data-name="blurb">Salt, rope and the first boats going out.</p>
    </header>
    <div data-name="body">
      <p>The tide turns an hour after sunrise, and the market opens with it.</p>
    </div>
  </div>
</section>

Field notes

The harbour at dawn

Salt, rope and the first boats going out.

The tide turns an hour after sunrise, and the market opens with it.

<section class="rf-section rf-section--start" data-align="start" data-media-position="start" data-media-ratio="1/3" data-rune="section" data-density="full">
  <div data-name="media" class="rf-section__media" data-section="media" data-guest-fit="clip">
    <svg class="rf-placeholder" data-shape="cover" viewBox="0 0 1600 900" preserveAspectRatio="xMidYMid slice" width="100%" fill="none" role="img" aria-label="A harbour at dawn">
      <rect x="0" y="0" width="1600" height="900" fill="var(--rf-color-surface)"></rect>
      <circle cx="1216" cy="270" r="90" fill="var(--rf-color-border)"></circle>
      <path d="M0 648 Q 448 495 800 630 T 1600 576 L 1600 900 L 0 900 Z" fill="var(--rf-color-muted)"></path>
      <rect x="4" y="4" width="1593" height="893" fill="none" stroke="var(--rf-color-border)" stroke-width="7"></rect>
    </svg>
  </div>
  <div data-name="content" class="rf-section__content">
    <header data-name="preamble" class="rf-section__preamble" data-section="preamble">
      <p data-name="eyebrow" class="rf-section__eyebrow" data-section="eyebrow">Field notes</p>
      <h2 id="the-harbour-at-dawn" data-name="headline" class="rf-section__headline" data-section="title">The harbour at dawn</h2>
      <p data-name="blurb" class="rf-section__blurb" data-section="description">Salt, rope and the first boats going out.</p>
    </header>
    <div data-name="body" class="rf-section__body" data-section="body">
      <p>The tide turns an hour after sunrise, and the market opens with it.</p>
    </div>
  </div>
</section>
AttributeValuesWhat it does
media-positiontop, bottom, start, end, coverWhere the media zone sits. Turns zoning on.
media-ratio1/3 … 2/3The media's share of the row, beside the content
valigntop, center, bottom, stretchCross-axis alignment, beside the content
collapsesm, md, lg, neverWhen a side-by-side split stacks
mediaportrait, cover, thumbnail, hero, iconWhat the media zone holds, so the media dimension styles it. portrait is cropped round.

The zones count as card's do: one zone is the content, two are media and content, and three or more add the last as the footer. An empty leading zone means no media, and the media element is left out.

Cover

media-position="cover" lays the content over the media, as on card. content-place anchors the content ("end start", or auto), and height (sm to xl) or aspect gives a section with little content its shape.

Align the header

align positions the header (the body always spans the section). Use center for marquee sections, end to right-align.

{% section align="center" %}
	Pick a plan

	## Simple, transparent pricing

	No hidden fees. Cancel anytime.

	{% bento %}
	## Free
	For trying things out.

	## Pro
	For growing teams.
	{% /bento %}
{% /section %}
<section data-rune="section" data-rune-fields="{&quot;align&quot;:&quot;center&quot;}">
  <header>
    <p data-name="eyebrow">Pick a plan</p>
    <h2 id="simple-transparent-pricing" data-name="headline">Simple, transparent pricing</h2>
    <p data-name="blurb">No hidden fees. Cancel anytime.</p>
  </header>
  <div data-name="body">
    <section data-rune="bento" data-rune-fields="{&quot;gap&quot;:&quot;1rem&quot;,&quot;columns&quot;:&quot;6&quot;,&quot;row-height&quot;:&quot;&quot;,&quot;content-height&quot;:&quot;&quot;,&quot;media-ratio&quot;:&quot;&quot;,&quot;collapse&quot;:&quot;&quot;}">
      <div data-name="grid">
        <div data-rune="bento-cell" data-rune-fields="{&quot;size&quot;:&quot;large&quot;,&quot;cols&quot;:&quot;4&quot;,&quot;rows&quot;:&quot;2&quot;,&quot;content-height&quot;:&quot;&quot;,&quot;media-ratio&quot;:&quot;&quot;}" data-media-position="start" data-field="cell">
          <h3 id="free" data-name="title">Free</h3>
          <div data-name="body">
            <p>For trying things out.</p>
          </div>
        </div>
        <div data-rune="bento-cell" data-rune-fields="{&quot;size&quot;:&quot;large&quot;,&quot;cols&quot;:&quot;4&quot;,&quot;rows&quot;:&quot;2&quot;,&quot;content-height&quot;:&quot;&quot;,&quot;media-ratio&quot;:&quot;&quot;}" data-media-position="start" data-field="cell">
          <h3 id="pro" data-name="title">Pro</h3>
          <div data-name="body">
            <p>For growing teams.</p>
          </div>
        </div>
      </div>
    </section>
  </div>
</section>

Pick a plan

Simple, transparent pricing

No hidden fees. Cancel anytime.

Free

For trying things out.

Pro

For growing teams.

<section class="rf-section rf-section--center" data-align="center" data-rune="section" data-density="full">
  <header data-name="preamble" class="rf-section__preamble" data-section="preamble">
    <p data-name="eyebrow" class="rf-section__eyebrow" data-section="eyebrow">Pick a plan</p>
    <h2 id="simple-transparent-pricing" data-name="headline" class="rf-section__headline" data-section="title">Simple, transparent pricing</h2>
    <p data-name="blurb" class="rf-section__blurb" data-section="description">No hidden fees. Cancel anytime.</p>
  </header>
  <div data-name="body" class="rf-section__body" data-section="body">
    <section class="rf-bento" data-columns="6" data-gap="1rem" data-row-height="" data-content-height="" data-media-ratio="" data-collapse="" data-elevation="flush" data-rune="bento" data-density="full" style="--bento-columns: 6; --bento-gap: 1rem">
      <div data-name="grid" class="rf-bento__grid">
        <div class="rf-bento-cell" data-media-position="start" data-field="cell" data-size="large" data-cols="4" data-rows="2" data-content-height="" data-media-ratio="" data-rune="bento-cell" data-density="compact" style="--cell-cols: 4; --cell-rows: 2">
          <div data-name="content" class="rf-bento-cell__content">
            <h3 id="free" data-name="title" class="rf-bento-cell__title" data-section="title">Free</h3>
            <div data-name="body" class="rf-bento-cell__body" data-section="body">
              <p>For trying things out.</p>
            </div>
          </div>
        </div>
        <div class="rf-bento-cell" data-media-position="start" data-field="cell" data-size="large" data-cols="4" data-rows="2" data-content-height="" data-media-ratio="" data-rune="bento-cell" data-density="compact" style="--cell-cols: 4; --cell-rows: 2">
          <div data-name="content" class="rf-bento-cell__content">
            <h3 id="pro" data-name="title" class="rf-bento-cell__title" data-section="title">Pro</h3>
            <div data-name="body" class="rf-bento-cell__body" data-section="body">
              <p>For growing teams.</p>
            </div>
          </div>
        </div>
      </div>
    </section>
  </div>
</section>

Attributes

AttributeTypeRequiredDescription
align"start" | "center" | "end"—Header alignment: start (default), center, or end
header"auto" | "headline" | "none"—Which header roles to read: auto (eyebrow, headline and blurb around a leading heading; the default), headline (only the heading), or none (all content is body)
media"portrait" | "cover" | "thumbnail" | "hero" | "icon"—What the media zone holds, stamped as `data-media` so the media dimension styles it (portrait is cropped round)
content-placestring—Cover overlay anchor: "<block> <inline>" (e.g. "end start") or "auto"
height"sm" | "md" | "lg" | "xl"—Intrinsic section height (named scale) for cover sections
aspectstring—Intrinsic section aspect ratio (e.g. "16/9") for cover sections

Inherited from the split layout preset

AttributeTypeRequiredDescription
media-position"top" | "bottom" | "start" | "end" | "cover"—Where the media zone sits relative to the content: above (top), below (bottom), or beside (start/end)
media-ratio"1/3" | "2/5" | "1/2" | "3/5" | "2/3"—Media zone’s share of the row width when media is beside content (start/end)
valign"top" | "center" | "bottom" | "stretch"—Cross-axis alignment when media is beside content (start/end); applies to the shorter zone
collapse"sm" | "md" | "lg" | "never"—Breakpoint at which side-by-side layouts collapse to a single stacked column

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.

AttributeTypeRequiredDescription
bgstring—Background preset applied to this block
bg-fromstring—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-tostring—Gradient end colour — a semantic token name
bg-viastring—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).

AttributeTypeRequiredDescription
dropcapboolean—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.

AttributeTypeRequiredDescription
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
frame

Surface chrome (SPEC-086): a named preset from the theme registry with inline `frame-*` overrides layered on top.

AttributeTypeRequiredDescription
framestring—Named frame preset presenting this block's media surface
frame-anchorstring—Crop focal point when the guest is cut (object-position)
frame-aspectstring—Aspect ratio of the framed media, e.g. "16/9"
frame-displace"top" | "bottom" | "end" | "bottom-end" | "top-end" | "both"—Edge/corner the framed guest moves toward
frame-displace-mode"peek" | "bleed"—How displacement renders: `peek` (default) translates the guest visually inside its frame target; `bleed` uses negative margin on the media zone so following layout pulls up — extends past a section like a hero without leaving a gap above
frame-offset"none" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl"—Displacement distance (non-linear named scale: sm…xl ride the block-spacing tokens, 2xl/3xl/4xl step up to section-spacing for bleed-mode displacements that clear a section edge)
frame-overflow"clip" | "bleed"—How the frame handles a guest whose content is wider than it: `clip` (default) keeps it inside the rounded frame; `bleed` runs an overflowing guest out to the layout edge on a narrow viewport so it reads as cropped by the screen (a bleed host only — hero/feature)
frame-oversizestring—How far the guest exceeds its slot (scale factor)
frame-placestring—Guest-box alignment in the slot (e.g. "left top")
frame-shadow"none" | "sm" | "md" | "lg"—Silhouette drop-shadow strength for the framed media
inset

Internal padding override.

AttributeTypeRequiredDescription
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.

AttributeTypeRequiredDescription
reveal"none" | "fade" | "slide" | "scale" | "blur"—Scroll-reveal entrance character (none|fade|slide|scale|blur); the theme owns the choreography
staggerboolean—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.

AttributeTypeRequiredDescription
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.

AttributeTypeRequiredDescription
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.

AttributeTypeRequiredDescription
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.

AttributeTypeRequiredDescription
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.

AttributeTypeRequiredDescription
tintstring—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.

AttributeTypeRequiredDescription
width"compact" | "narrow" | "content" | "wide" | "full"—Maximum width constraint for this block

Anatomy

SlotFromClass
Eyebrowa paragraph directly before the headline.rf-section__eyebrow
Headlinea heading at the start, or after the eyebrow.rf-section__headline
Blurba paragraph directly after the headline.rf-section__blurb
Bodyeverything else.rf-section__body
Mediathe leading zone, with media-position.rf-section__media
Contentthe header, body and footer, with media-position.rf-section__content
Footera trailing zone after a second ---, with media-position.rf-section__footer

The header slots are wrapped in .rf-section__preamble; the whole block is .rf-section.