Layout primitives

Composable regions for desktop SaaS / web-app surfaces — not opinionated page designs. Low specificity (:where()), token-driven gaps, and each primitive exposes --l-* instance-config tokens with framework defaults. Defaults assume comfortable desktop density; .l-sidebar adapts to its panel width via a container query, not the viewport.

.l-grid — dashboard widgets

Auto-fitting tracks; set --l-grid-min for a wider floor.

Active seats 1,284 +4.2%
MRR $48.2k +1.1%
Churn 1.4% -0.3%
Open tickets 23

.l-cluster — action bar

A wrapping row of filters and actions; --l-cluster-justify: flex-end to right-align.

.l-stack + .l-sidebar — settings panel

Resize the demo panel's handle (or narrow the window) to cross 48rem: the sidebar collapses to a single column because the wrapping panel (.demo-panel) is the container.

.l-scroll-area — data pane

Independent scroll with a stable gutter (no layout shift when the bar appears) and contained overscroll.

AccountPlanStatusMRR
Acme OpsEnterpriseActive$2,400
NorthwindProTrialing$980
GlobexProPast due$980
InitechTeamActive$420
UmbrellaEnterpriseActive$2,400
Stark IndustriesProActive$980
Acme OpsEnterpriseActive$2,400
NorthwindProTrialing$980
GlobexProPast due$980
InitechTeamActive$420
UmbrellaEnterpriseActive$2,400
Stark IndustriesProActive$980

.l-page — readable column

Centered content within a wide surface; tighten --l-page-max for prose.

Long-form guidance, release notes, or policy text — kept readable even when the surrounding app runs edge-to-edge.

.l-container — centered app wrapper

General-purpose max-width container for dashboards, settings, and lists. Distinct from .l-page (prose-focused, 88rem). Default 80rem; tune via --l-container-max.

This content is centered and capped at 80rem.

.l-columns — multi-column masonry

CSS multi-column layout for card walls, search results, and image grids. Set column count via --l-columns-count or let it auto-fit. Items use break-inside: avoid so cards don't split.

Card 1

Each card flows into the next column without splitting. Resize to see reflow.

Card 2

Each card flows into the next column without splitting. Resize to see reflow.

Card 3

Each card flows into the next column without splitting. Resize to see reflow.

Card 4

Each card flows into the next column without splitting. Resize to see reflow.

Card 5

Each card flows into the next column without splitting. Resize to see reflow.

Card 6

Each card flows into the next column without splitting. Resize to see reflow.

.l-inset — constrained content in full-bleed

Centers and constrains content inside a full-width parent (hero, banner). Default 48rem; tune via --l-inset-max.

This inset is centered inside a full-bleed surface.

Use for captions, CTAs, or forms within a wide hero section.

Full layout index

PrimitivePurposeTunable token
.l-stackVertical flow (forms, sections)--l-stack-gap
.l-clusterHorizontal wrapping group (buttons, filters)--l-cluster-gap
.l-gridAuto-fitting card grid--l-grid-min
.l-sidebarTwo-column with container-query collapse--l-sidebar-size
.l-pageCentered prose column (88rem)--l-page-max
.l-scroll-areaIndependent scroll region
.l-app-shellFull SaaS shell (topbar + sidebar + main)--app-sidebar-size
.l-containerCentered app wrapper (80rem)--l-container-max
.l-columnsMulti-column masonry--l-columns-count
.l-insetConstrained content in full-bleed--l-inset-max