---
name: structural-grid
description: Structural Grid (Exposed Grid / Rail Layout) design system for modern SaaS landing pages. Use when building dark-themed marketing sites, landing pages, or SaaS product pages inspired by Linear, Vercel, Resend, and Planetscale. Provides CSS foundations, section patterns, component recipes, and responsive border logic for the visible-grid aesthetic.
metadata:
author: nabinkhair42
version: "1.0.0"
tags:
- design-system
- css
- tailwind
- nextjs
- landing-page
- saas
---
# Structural Grid Design System
You are implementing a **Structural Grid** (also called "Exposed Grid" or "Rail Layout") design pattern. This is the modern SaaS design pattern used by Linear, Vercel, Resend, Profound, and Planetscale — where the underlying page grid is promoted to a first-class visual element.
## Core Principles
1. **Visible structure** — Vertical rail lines and horizontal dividers are decorative elements, not hidden scaffolding
2. **Content lives inside the grid** — Components blend into the rail structure rather than floating over it
3. **Dashed internal, solid external** — Rail lines and section dividers are solid; internal grid cell dividers are dashed
4. **Alternating visual rhythm** — Sections alternate between default and dot-pattern backgrounds for depth
5. **Minimal containers** — No rounded-xl bordered cards floating inside sections. Content sits directly within the grid
6. **Consistent letter-spacing** — Use `tracking-wide` on all section labels and inline labels. Never mix `tracking-widest` and `tracking-wider`
7. **Every card hovers** — All grid cells get `transition-colors hover:bg-white/[0.02]` for interactive feedback
---
## CSS Foundation
Add these to your global CSS. All measurements derive from a single `--rail-offset` variable.
```css
/* Vertical rail lines */
.page-rails {
--rail-offset: max(1rem, calc(50% - 36rem)); /* = max-w-6xl centered */
position: relative;
overflow-x: clip; /* clip, NOT hidden — hidden breaks position:sticky */
}
.page-rails::before,
.page-rails::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
width: 1px;
background: var(--border);
pointer-events: none;
z-index: 1;
}
.page-rails::before { left: var(--rail-offset); }
.page-rails::after { right: var(--rail-offset); }
/* Content bounded to rail edges */
.rail-bounded {
margin-left: var(--rail-offset);
margin-right: var(--rail-offset);
}
/* Horizontal section divider between rails */
.section-divider {
position: relative;
height: 1px;
z-index: 2;
}
.section-divider::before {
content: '';
position: absolute;
left: var(--rail-offset, max(1rem, calc(50% - 36rem)));
right: var(--rail-offset, max(1rem, calc(50% - 36rem)));
height: 1px;
background: var(--border);
}
/* Subtle dot pattern for section backgrounds */
.dot-pattern {
background-image: radial-gradient(rgba(255, 255, 255, 0.04) 1px, transparent 1px);
background-size: 24px 24px;
}
/* Custom scrollbar — matches dark themes */
* {
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
}
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.1); border-radius: 3px; }
::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.2); }
```
### Critical: overflow-x
**Always use `overflow-x: clip` on `.page-rails`, NEVER `overflow-x: hidden`.**
`hidden` creates a new scroll container which breaks `position: sticky` on any descendant.
`clip` clips overflow visually without affecting scroll/sticky behavior.
### Smooth scroll with sticky navbar offset
When using a sticky navbar with anchor links, add to `html`:
```css
html {
scroll-behavior: smooth;
scroll-padding-top: 5rem; /* clears the sticky navbar height */
}
```
### Adjusting rail width
Change `36rem` to match your desired max content width:
- `32rem` = 1024px = Tailwind `max-w-5xl`
- `36rem` = 1152px = Tailwind `max-w-6xl` (recommended default)
- `40rem` = 1280px = Tailwind `max-w-7xl`
---
## Page Structure
```tsx
```
Every section is separated by a `section-divider`. The rails run the full height of `.page-rails`. Navbar and Footer sit **outside** `.page-rails`.
### Section IDs
Always add `id` attributes to sections that need anchor links or nav tracking:
```tsx
```
---
## Section Patterns
### 1. Text Header (reusable across sections)
```tsx
Section Label
Section Title
Section description text here.
```
### 2. Grid with Dashed Internal Dividers
Use `rail-bounded` to align the grid edges with the rails. Apply `border-t border-border` to connect the grid's top edge with the section divider above. Use dashed borders between cells.
**Responsive border logic for a 3-column grid (1 col mobile, 2 col sm, 3 col lg):**
```tsx
```
**Border logic rules:**
- `border-l` (left) = applied to every cell that is NOT the first in its row at that breakpoint
- `border-t` (top) = applied to every cell that is NOT in the first row at that breakpoint
- Use `sm:max-lg:` prefix for tablet-only borders that differ from desktop
- Use `max-sm:` prefix for mobile-only borders
- All internal borders are `border-dashed border-border`
- All grid cells include `group transition-colors hover:bg-white/[0.02]` for hover feedback
### 3. Side-by-Side Layout with Full-Height Dashed Divider
For layouts like text + interactive content, use `items-stretch` so the dashed divider spans the full section height.
```tsx
Label
Title
Description.
{/* tall content */}
```
**Sticky text requirements:**
- Parent `.page-rails` must use `overflow-x: clip` (not `hidden`)
- `items-stretch` on the grid makes both columns match the taller column's height
- Apply padding to children, not the grid itself
### 4. Hero Section
```tsx