---
name: "Framed page"
description: "The whole page sits in one rounded panel on a tinted ground, with the footer outside the frame."
type: pattern
tags: ["Inset panel", "Rounded frame", "Product", "Calm"]
container: "Tinted ground with a 12px inset, one rounded frame inside"
max_width: "1040px content inside the frame"
columns: "3 equal columns for items, 1 column for hero and quote"
gutter: "32px between items"
rules: "1px solid frame border at 16% ink, 1px hairline under the nav only"
section_padding: "64px top and bottom, 48px below 800px"
breakpoints: "Below 800px the inset shrinks to 6px, radii step down and every grid becomes one column"
sticky: "None. The nav may be sticky inside the frame"
---

# Framed page

The whole page sits in one rounded panel on a tinted ground, with the footer outside the frame.

## AI build instructions

> Read this section before writing any code. It describes page structure only.
> Colors, type, radii and shadows come from the project's DESIGN.md, never from this file.

### 1. Your role

Build the page layout as **Framed page**. Use the HTML and CSS under Reference implementation as the
structural source of truth. Keep the project's own copy, components and styling, and place them into the
regions listed below. If the project has a DESIGN.md, map its tokens onto the base variables
(`--paper`, `--paper-2`, `--ink`, `--ink-2`, `--ink-3`, `--line`, `--accent`) and leave the structure CSS unchanged.

### 2. Structure contract

| Token | Value |
|-------|-------|
| container | Tinted ground with a 12px inset, one rounded frame inside |
| max width | 1040px content inside the frame |
| columns | 3 equal columns for items, 1 column for hero and quote |
| gutter | 32px between items |
| rules | 1px solid frame border at 16% ink, 1px hairline under the nav only |
| section padding | 64px top and bottom, 48px below 800px |
| breakpoints | Below 800px the inset shrinks to 6px, radii step down and every grid becomes one column |
| sticky | None. The nav may be sticky inside the frame |
| accessibility | The frame is a plain div. Landmarks (header, main, footer) are unchanged, and the footer outside the frame stays in reading order |

### 3. Regions

The markup marks each region with `data-region`. These attributes only drive the Blueprint view on
freedesignmd.com and can be removed in production.

1. **Ground.** A tinted page background, a few percent darker than the frame, with a 12px inset on every side. It is visible on all edges and below the page.
2. **Frame.** The whole page lives in one rounded panel with a 1px border and a 16px radius. Nav, sections and panels sit inside it.
3. **Nav bar.** The nav is the frame's top bar. It uses the same wrapper as the sections, so the logo aligns with the headline.
4. **Inset panel.** Wells, stat strips and the closing call to action are nested panels with a 12px radius on a slightly tinted fill. They are the only filled surfaces.
5. **Footer strip.** The footer sits on the ground, outside the frame, so the frame reads as a finished object.

### 4. Rules

- Wrap the entire page in one rounded frame with a 1px border. Never add a second frame.
- Keep the ground inset at 12px and the frame radius at 16px. Nested panels use 12px.
- Tint the ground from the ink color at about 6 percent. Do not use a hue or gradient.
- Separate sections with space only. Fill nested panels, never whole sections.
- Put the footer on the ground, below the frame.

### 5. Hard constraints

Never do any of the following without an explicit instruction from the user:

- Change the structure tokens above, add a column, or add dividers the pattern does not define.
- Replace the structure with cards, shadows or colored backgrounds to separate sections.
- Use gradients, glows or emoji to decorate the layout.
- Put page content inside a region that is meant for another kind of content.

### 6. Before you finish, verify

- [ ] Every region listed above exists and is in the same order as in the reference markup.
- [ ] Container width, columns, gutter, rule weight and section padding match the contract.
- [ ] The layout collapses as described at the stated breakpoints, with no horizontal scroll at 390px.
- [ ] Sticky elements behave as stated and never cover focused content.
- [ ] Colors, type and radii were taken from DESIGN.md, not invented.

---

## Overview

Instead of letting content run to the screen edges, the page is a single rounded panel set into a slightly darker ground. The frame gives the site the feel of a native app window and makes every edge deliberate. Inside, sections are separated by space alone, and the only filled surfaces are nested panels with a smaller radius.

## When to use it

- Product marketing that should feel like a native app window.
- Sites with a calm tone, few rules and generous whitespace.
- Pages that mix a tinted ground with one clean white surface.
- Launch pages and waitlists where the page is short and every edge shows.

## When to avoid it

- Content-heavy pages, because the inset steals width on small screens.
- Full-bleed imagery or video heroes, which want to reach the edges.
- Sites that already have a strong background pattern, since the ground would compete with it.

---

## Reference implementation

Plain HTML and CSS. The preview on freedesignmd.com renders exactly these three blocks, so what you see
is what you get. The pattern CSS decides structure. The base CSS is the neutral skin shared by every
pattern: replace its variables with your DESIGN.md tokens and keep the names.

### HTML

```html
<!-- data-region and data-dim only drive the Blueprint view. Remove them in production. -->
<div class="ground" data-region="Ground" data-n="1" data-at="ir">
  <div class="frame" data-region="Frame" data-n="2" data-at="in">
    <header class="bar" data-region="Nav bar" data-n="3" data-at="bl">
      <div class="wrap">
        <nav class="nav" aria-label="Primary">
          <a class="brand" href="#"><span class="mark"></span>Meridian</a>
          <ul class="links">
            <li><a href="#">Product</a></li>
            <li><a href="#">Pricing</a></li>
            <li><a href="#">Docs</a></li>
            <li><a href="#">Changelog</a></li>
          </ul>
          <div class="actions">
            <a class="btn btn-ghost" href="#">Sign in</a>
            <a class="btn btn-primary" href="#">Start free</a>
          </div>
        </nav>
      </div>
    </header>
    <main>
      <section class="sec" data-dim="64" data-dim-axis="pad">
        <div class="wrap" data-dim="max 1040">
          <p class="eyebrow">Release 2.4</p>
          <h1>Ship changes your customers actually read</h1>
          <p class="lead">Meridian turns merged pull requests into clear release notes, changelogs and update emails.</p>
          <div class="actions">
            <a class="btn btn-primary" href="#">Start free</a>
            <a class="btn btn-ghost" href="#">Read the docs</a>
          </div>
          <div class="well" data-region="Inset panel" data-n="4" data-at="in" data-dim="radius 12" data-dim-axis="tag" data-dim-at="tr">
            <figure class="mock" aria-label="Release notes preview">
              <div class="mock-bar"><span>Release 2.4</span><span>Mar 12</span></div>
              <ul>
                <li><b class="new">New</b>Draft notes from merged pull requests</li>
                <li><b>Improved</b>Changelog search across all releases</li>
                <li><b>Fixed</b>Email previews on narrow screens</li>
              </ul>
            </figure>
          </div>
        </div>
      </section>
      <section class="sec" id="features">
        <div class="wrap">
          <div class="head">
            <div>
              <p class="eyebrow">01 Features</p>
              <h2>Everything between merge and inbox</h2>
            </div>
            <p class="sub">Drafts group by product area, not by commit.</p>
          </div>
          <div class="cols">
            <article class="feature">
              <span class="n">01</span>
              <h3>Draft from pull requests</h3>
              <p>Group merged work by product area and get a first draft in seconds.</p>
            </article>
            <article class="feature">
              <span class="n">02</span>
              <h3>Edit in one place</h3>
              <p>Rewrite, reorder and approve notes with your team before anything ships.</p>
            </article>
            <article class="feature">
              <span class="n">03</span>
              <h3>Publish everywhere</h3>
              <p>Send the same note to your changelog, email list and in-app feed.</p>
            </article>
          </div>
        </div>
      </section>
      <section class="sec" id="numbers">
        <div class="wrap">
          <div class="head">
            <div>
              <p class="eyebrow">02 Numbers</p>
              <h2>Quiet, fast and always on</h2>
            </div>
            <p class="sub">Rolling twelve month medians across all workspaces.</p>
          </div>
          <div class="strip" data-region="Inset panel">
            <div class="stat"><strong>2.4M</strong><span>Notes published</span></div>
            <div class="stat"><strong>99.98%</strong><span>Uptime, last 12 months</span></div>
            <div class="stat"><strong>140 ms</strong><span>Median render time</span></div>
          </div>
        </div>
      </section>
      <section class="sec" id="customers">
        <div class="wrap">
          <div class="head">
            <div>
              <p class="eyebrow">03 Customers</p>
              <h2>In their words</h2>
            </div>
            <p class="sub">Halden, a 40 person team, publishes every week.</p>
          </div>
          <figure class="quote">
            <blockquote>“Our changelog went from a Friday chore to the page customers open first.”</blockquote>
            <figcaption><b>Sana Okafor</b> Head of Product, Halden</figcaption>
          </figure>
        </div>
      </section>
      <section class="sec" id="pricing">
        <div class="wrap">
          <div class="panel" data-region="Inset panel">
            <div>
              <p class="eyebrow">04 Pricing</p>
              <h2>Free for small teams</h2>
              <p class="sub">Up to five people and one changelog, no card needed.</p>
            </div>
            <div class="actions">
              <a class="btn btn-primary" href="#">Start free</a>
            </div>
          </div>
        </div>
      </section>
    </main>
  </div>
  <footer data-region="Footer strip" data-n="5" data-at="bl">
    <div class="wrap">
      <div class="foot">
        <span>© 2026 Meridian</span>
        <ul>
          <li><a href="#">Privacy</a></li>
          <li><a href="#">Terms</a></li>
          <li><a href="#">Status</a></li>
        </ul>
      </div>
    </div>
  </footer>
</div>
```

### CSS (pattern)

```css
:root {
  --max: 1040px;     /* content width inside the frame */
  --inset: 12px;     /* ground visible around the frame */
  --radius: 16px;    /* frame radius */
  --radius-in: 12px; /* nested panels: frame radius minus the 4px optical step */
  --pad: 64px;       /* section padding, top and bottom */
  --ground: color-mix(in srgb, var(--ink) 6%, var(--paper));
}

body { background: var(--ground); }
.ground { min-height: 100svh; padding: var(--inset); }

/* One rounded panel carries the whole page. */
.frame { background: var(--paper); border: 1px solid var(--line-strong); border-radius: var(--radius); }
.wrap { width: min(100% - 64px, var(--max)); margin-inline: auto; }
.bar { border-bottom: 1px solid var(--line); }

/* Sections are separated by space only. Fills are reserved for inset panels. */
.sec { padding-block: var(--pad); }
.sec h1 { margin-top: 16px; }
.sec h1 + .lead { margin-top: 20px; }
.sec .lead + .actions { margin-top: 28px; }

.well { margin-top: 48px; padding: 32px; border-radius: var(--radius-in); background: var(--paper-2); }
.well .mock { max-width: 560px; margin-inline: auto; }

.head { display: flex; align-items: flex-end; justify-content: space-between; gap: 32px; margin-bottom: 40px; }
.head > div > * + * { margin-top: 8px; }
.head .sub { text-align: right; }
.cols { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 32px; }
.strip { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 32px; padding: 32px; border-radius: var(--radius-in); background: var(--paper-2); }
.panel { display: flex; align-items: flex-end; justify-content: space-between; gap: 32px; padding: 40px; border-radius: var(--radius-in); background: var(--paper-2); }
.panel > div > * + * { margin-top: 8px; }

.ground > footer { padding-inline: 0; }

@media (max-width: 800px) {
  :root { --inset: 6px; --radius: 12px; --radius-in: 8px; --pad: 48px; }
  .wrap { width: min(100% - 40px, var(--max)); }
  .head, .panel { flex-direction: column; align-items: flex-start; gap: 12px; }
  .head .sub { text-align: left; }
  .cols, .strip { grid-template-columns: 1fr; gap: 24px; }
  .well, .strip, .panel { padding: 20px; }
}
```

### CSS (base, shared by every pattern)

```css
/* Base: tokens and content blocks shared by every pattern. Structure lives in the pattern CSS. */
:root {
  color-scheme: light;
  --paper: #ffffff;
  --paper-2: #f5f5f6;
  --ink: #0e0e10;
  --ink-2: #55555c;
  --ink-3: #767680;
  --line: rgba(14, 14, 16, 0.09);
  --line-strong: rgba(14, 14, 16, 0.16);
  --accent: #c8421a;
  --inv-paper: #0b0b0d;
  --inv-ink: #f3f3f5;
  --inv-ink-2: #a4a4ab;
  --inv-line: rgba(255, 255, 255, 0.12);
  --font: "Inter Variable", Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "JetBrains Mono Variable", "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
}
:root[data-theme="dark"] {
  color-scheme: dark;
  --paper: #0b0b0d;
  --paper-2: #131316;
  --ink: #f3f3f5;
  --ink-2: #a4a4ab;
  --ink-3: #74747c;
  --line: rgba(255, 255, 255, 0.09);
  --line-strong: rgba(255, 255, 255, 0.16);
  --accent: #ff8a5c;
  --inv-paper: #f6f6f7;
  --inv-ink: #0e0e10;
  --inv-ink-2: #55555c;
  --inv-line: rgba(14, 14, 16, 0.1);
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 15px/1.55 var(--font);
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, p, ul, ol, figure, blockquote, dl, dd { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }

/* Type scale: 12 / 13 / 15 / 17 / 22 / 28 / 44 */
h1, .t-h1 { font-size: 44px; line-height: 1.05; letter-spacing: -0.03em; font-weight: 500; text-wrap: balance; }
h2, .t-h2 { font-size: 28px; line-height: 1.15; letter-spacing: -0.02em; font-weight: 500; text-wrap: balance; }
h3 { font-size: 15px; line-height: 1.4; font-weight: 500; }
.lead { font-size: 17px; line-height: 1.55; color: var(--ink-2); max-width: 46ch; text-wrap: pretty; }
.sub { font-size: 14px; line-height: 1.55; color: var(--ink-2); max-width: 40ch; text-wrap: pretty; }
.eyebrow { font: 400 12px/16px var(--mono); color: var(--ink-3); letter-spacing: 0.02em; }

/* Buttons: one primary per view */
.actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.btn {
  display: inline-flex; align-items: center; height: 36px; padding: 0 14px;
  border: 1px solid transparent; border-radius: 8px;
  font: 500 14px/1 var(--font); white-space: nowrap;
}
.btn-primary { background: var(--ink); color: var(--paper); }
.btn-ghost { border-color: var(--line-strong); color: var(--ink); }

/* Nav */
.nav { display: flex; align-items: center; gap: 32px; height: 56px; }
.brand { display: inline-flex; align-items: center; gap: 8px; font-weight: 500; letter-spacing: -0.01em; }
.mark { width: 16px; height: 16px; border: 4px solid var(--ink); border-radius: 50%; }
.links { display: flex; gap: 24px; font-size: 14px; color: var(--ink-2); }
.nav .actions { margin-left: auto; }

/* Feature */
.feature { display: flex; flex-direction: column; gap: 8px; }
.feature .n { font: 400 12px/16px var(--mono); color: var(--accent); }
.feature p { font-size: 14px; line-height: 1.55; color: var(--ink-2); }

/* Stat */
.stat strong {
  display: block; font: 500 36px/1.1 var(--font); letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.stat span { display: block; margin-top: 4px; font-size: 13px; color: var(--ink-2); }

/* Quote */
.quote blockquote { font-size: 22px; line-height: 1.35; letter-spacing: -0.015em; text-wrap: balance; }
.quote figcaption { margin-top: 16px; font-size: 13px; color: var(--ink-2); }
.quote figcaption b { color: var(--ink); font-weight: 500; }

/* Release card: the one visual used when a pattern has a media slot */
.mock { border: 1px solid var(--line-strong); border-radius: 12px; background: var(--paper); overflow: hidden; }
.mock-bar { display: flex; justify-content: space-between; padding: 12px 16px; border-bottom: 1px solid var(--line); font: 400 12px/16px var(--mono); color: var(--ink-3); }
.mock li { display: flex; gap: 12px; align-items: baseline; padding: 12px 16px; border-bottom: 1px solid var(--line); font-size: 14px; }
.mock li:last-child { border-bottom: 0; }
.mock li b { flex: none; width: 64px; font: 400 12px/16px var(--mono); color: var(--ink-3); }
.mock li b.new { color: var(--accent); }

/* Footer strip */
.foot { display: flex; align-items: center; justify-content: space-between; gap: 16px; height: 56px; font-size: 13px; color: var(--ink-3); }
.foot ul { display: flex; gap: 20px; }

/* Inverted band: swaps the tokens, so every block inside adapts */
.inv {
  --paper: var(--inv-paper); --ink: var(--inv-ink); --ink-2: var(--inv-ink-2);
  --ink-3: var(--inv-ink-2); --line: var(--inv-line); --line-strong: var(--inv-line);
  background: var(--paper); color: var(--ink);
}

@media (max-width: 640px) {
  h1, .t-h1 { font-size: 34px; }
  h2, .t-h2 { font-size: 24px; }
  .links, .nav .btn-ghost { display: none; }
  .nav { gap: 16px; }
  .foot ul { gap: 14px; }
}

```
