Beam
Compositions
Layout primitives in beam.css. They own flow, gaps and columns — never colour or type — and every gap reads a density token, so switching density re-flows them all.
Build in CUBE order: composition first (the layout), then utilities for one-off tweaks, then a block only when a component needs its own styles. Variations go through data-* attributes, not new classes. Values in parentheses below are the defaults.
.b-flow / .b-stack
Vertical rhythm between siblings. The gap is a stack-* density token.
data-space- xs · sm · (md) · lg · xl · 2xl
data-split-after- on a .b-stack child: push the rest to the end
<div class="[ b-flow ]" data-space="sm">
<div class="[ b-box ]" data-tone="neutral">Heading</div>
<div class="[ b-box ]" data-tone="neutral">Paragraph</div>
<div class="[ b-box ]" data-tone="neutral">Actions</div>
</div>.b-cluster
Inline items that wrap: tags, toolbars, button rows.
data-gap- xs · sm · (md) · lg
data-justify- end · center · between
data-align- start · stretch
<div class="[ b-cluster ]" data-gap="sm">
<div class="[ b-box ]" data-tone="neutral">Tag 1</div>
<div class="[ b-box ]" data-tone="neutral">Tag 2</div>
<div class="[ b-box ]" data-tone="neutral">Tag 3</div>
<div class="[ b-box ]" data-tone="neutral">Tag 4</div>
<div class="[ b-box ]" data-tone="neutral">Tag 5</div>
<div class="[ b-box ]" data-tone="neutral">Tag 6</div>
</div>.b-repel
Two groups pushed to opposite ends; wraps gracefully when narrow.
--repel-gap- custom property; default inline-md
<div class="[ b-repel ]">
<div class="[ b-box ]">Title</div>
<div class="[ b-cluster ]" data-gap="sm">
<div class="[ b-box ]" data-tone="neutral">Cancel</div>
<div class="[ b-box ]">Save</div>
</div>
</div>.b-sidebar
A fixed-ish aside next to a fluid main; stacks when main would drop below half the width. No media query.
data-side- right
--sidebar-width- default 20rem
--sidebar-content-min- default 50%
<div class="[ b-sidebar ]">
<div class="[ b-box ]" data-tone="neutral">Aside</div>
<div class="[ b-box ]">Main content</div>
</div>.b-switcher
Side by side above the density threshold, stacked below it. Rows never exceed the limit.
data-limit- 2 · 3 · (4)
threshold- --beam-threshold (density)
<div class="[ b-switcher ]" data-limit="3">
<div class="[ b-box ]">One</div>
<div class="[ b-box ]">Two</div>
<div class="[ b-box ]">Three</div>
</div>.b-grid
Intrinsic auto-fit grid for cards and tiles. Columns appear as space allows.
data-min- xs 10rem · sm 13rem · (16rem) · lg 20rem · xl 26rem
data-gap- sm · (md) · lg
<div class="[ b-grid ]" data-min="sm">
<div class="[ b-box ]">Card 1</div>
<div class="[ b-box ]">Card 2</div>
<div class="[ b-box ]">Card 3</div>
<div class="[ b-box ]">Card 4</div>
<div class="[ b-box ]">Card 5</div>
</div>.b-layout-grid
12-column page grid. Mobile-first: full width below sm unless data-span-sm; data-span from md; data-span-lg from lg.
data-span · data-span-sm · data-span-lg- 1–12
data-start- column start
data-cols- 4 · 6 · 8 · (12) · 16
.b-subgrid- child that aligns to the parent tracks
data-gap- sm · (md) · lg
<div class="[ b-layout-grid ]">
<div class="[ b-box ]" data-span="12">12</div>
<div class="[ b-box ]" data-span="8" data-span-lg="9">8 (lg: 9)</div>
<div class="[ b-box ]" data-span="4" data-span-lg="3">4 (lg: 3)</div>
<div class="[ b-box ]" data-span="3" data-span-sm="6">3 (sm: 6)</div>
<div class="[ b-box ]" data-span="3" data-span-sm="6">3 (sm: 6)</div>
<div class="[ b-box ]" data-span="3" data-span-sm="6">3 (sm: 6)</div>
<div class="[ b-box ]" data-span="3" data-span-sm="6">3 (sm: 6)</div>
<div class="[ b-subgrid ]" data-span="12">
<div class="[ b-box ]" data-tone="neutral" data-span="2">sub 2</div>
<div class="[ b-box ]" data-tone="neutral" data-span="10">sub 10</div>
</div>
</div>.b-app-shell
Header / nav / main / aside / footer by named areas. Nav appears at md, aside at lg (with data-aside).
data-area- header · nav · main · aside · footer
data-aside- show the aside column at lg
--nav-width / --aside-width- default 16rem / 20rem
<div class="[ b-app-shell ] [ b-demo-shell ]" data-aside>
<div data-area="header">header</div>
<div data-area="nav">nav</div>
<div data-area="main">main</div>
<div data-area="aside">aside</div>
<div data-area="footer">footer</div>
</div>.b-cover
A full-height block with one vertically centred principal child — hero sections, empty states.
data-cover="center"- the centred child
--cover-height- default 100dvh
--cover-padding- default inset-lg
<div class="[ b-cover ] [ b-box ]" data-tone="neutral" style="--cover-height: var(--beam-width-3xs)">
<div class="[ b-box ]">Top</div>
<div class="[ b-box ]" data-cover="center">Centred</div>
<div class="[ b-box ]">Bottom</div>
</div>.b-center / .b-wrapper / .b-region
.b-wrapper sets page width and side padding; .b-region sets section padding; .b-center caps line length.
.b-wrapper data-max- sm · md · (container) · xl · full
.b-region data-space- xs · sm · (md) · lg · xl
.b-center data-text- center
<section class="[ b-region ] [ b-box ]" data-tone="neutral" data-space="xs">
<div class="[ b-wrapper ]" data-max="sm">
<div class="[ b-center ] [ b-box ]" data-text="center">Wrapper (sm) + centred measure</div>
</div>
</section>.b-reel / .b-frame
.b-reel is a horizontal scroller with snap; .b-frame is an aspect-ratio box for media.
--reel-item- item width, default 18rem
.b-frame data-ratio- square · 4-3 · (16:9) · 21-9
<div class="[ b-reel ]" style="--reel-item: var(--beam-width-3xs)">
<div class="[ b-frame ] [ b-box ]" data-ratio="4-3">1</div>
<div class="[ b-frame ] [ b-box ]" data-ratio="4-3">2</div>
<div class="[ b-frame ] [ b-box ]" data-ratio="4-3">3</div>
<div class="[ b-frame ] [ b-box ]" data-ratio="4-3">4</div>
<div class="[ b-frame ] [ b-box ]" data-ratio="4-3">5</div>
<div class="[ b-frame ] [ b-box ]" data-ratio="4-3">6</div>
</div>