Layout primitives
Composable regions for desktop SaaS / web-app surfaces — not opinionated page designs. Low specificity (:where()), token-driven gaps, and each primitive exposes --pl-l-* instance-config tokens with framework defaults. Defaults assume comfortable desktop density;.pl-l-sidebar adapts to its panel width via a container query, not the viewport.
.pl-l-grid — dashboard widgets
Auto-fitting tracks; set --pl-l-grid-min for a wider floor.
.pl-l-cluster — action bar
A wrapping row of filters and actions; --pl-l-cluster-justify: flex-end to right-align.
.pl-l-stack + .pl-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 thewrapping panel (.demo-panel) is the container.
.pl-l-scroll-area — data pane
Independent scroll with a stable gutter (no layout shift when the bar appears) and contained overscroll.
| Account | Plan | Status | MRR |
|---|---|---|---|
| Acme Ops | Enterprise | Active | $2,400 |
| Northwind | Pro | Trialing | $980 |
| Globex | Pro | Past due | $980 |
| Initech | Team | Active | $420 |
| Umbrella | Enterprise | Active | $2,400 |
| Stark Industries | Pro | Active | $980 |
| Acme Ops | Enterprise | Active | $2,400 |
| Northwind | Pro | Trialing | $980 |
| Globex | Pro | Past due | $980 |
| Initech | Team | Active | $420 |
| Umbrella | Enterprise | Active | $2,400 |
| Stark Industries | Pro | Active | $980 |
.pl-l-page — readable column
Centered content within a wide surface; tighten --pl-l-page-max for prose.
Long-form guidance, release notes, or policy text — kept readable even when the surrounding app runs edge-to-edge.
.pl-l-container — centered app wrapper
General-purpose max-width container for dashboards, settings, and lists. Distinct from .pl-l-page (prose-focused, 88rem). Default 80rem; tune via --pl-l-container-max.
This content is centered and capped at 80rem.
.pl-l-columns — multi-column masonry
CSS multi-column layout for card walls, search results, and image grids. Set column count via --pl-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.
.pl-l-inset — constrained content in full-bleed
Centers and constrains content inside a full-width parent (hero, banner). Default 48rem; tune via --pl-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
| Primitive | Purpose | Tunable token |
|---|---|---|
.pl-l-stack | Vertical flow (forms, sections) | --pl-l-stack-gap |
.pl-l-cluster | Horizontal wrapping group (buttons, filters) | --pl-l-cluster-gap |
.pl-l-grid | Auto-fitting card grid | --pl-l-grid-min |
.pl-l-sidebar | Two-column with container-query collapse | --pl-l-sidebar-size |
.pl-l-page | Centered prose column (88rem) | --pl-l-page-max |
.pl-l-scroll-area | Independent scroll region | — |
.pl-l-app-shell | Full SaaS shell (topbar + sidebar + main) | --pl-app-sidebar-size |
.pl-l-container | Centered app wrapper (80rem) | --pl-l-container-max |
.pl-l-columns | Multi-column masonry | --pl-l-columns-count |
.pl-l-inset | Constrained content in full-bleed | --pl-l-inset-max |