# Build a landing page with the Strict One theme

You are building one page in an existing project: a marketing landing page for a software product, from header to footer. Follow this brief closely. `DESIGN.md` decides the tokens: colors, type, spacing steps and corners. This brief decides the layout and which token goes where. If this brief names a value that is not in `DESIGN.md`, `DESIGN.md` wins.

## Before you start

1. **Check the theme is installed.** The project should have `DESIGN.md` in its root and the Strict One variables in its global CSS. If not, run `npx shadcn@latest add https://strictthemes.com/r/strict-one.json` and save https://strictthemes.com/themes/strict-one/DESIGN.md as `DESIGN.md` in the project root. In a project without shadcn, use https://strictthemes.com/themes/strict-one/tailwind.css instead. If the global CSS still imports a font the theme does not use (a new shadcn project imports Geist), remove that import, and uninstall its package if nothing else uses it.
2. **Read `DESIGN.md` from start to finish.** It is the source of truth for every visual decision.
3. **Look at the project before writing code.** Use its framework, router and file layout. For controls (buttons, inputs, tabs, menus, dialogs, accordions, data tables) use the components in `components/ui`, and add a missing one with `npx shadcn@latest add <name>` rather than writing your own, unless this brief names a plain element. Layout is plain elements with theme classes: sections, panels, figures and lists need no component.
4. **Teach `cn()` the theme's type classes.** shadcn's class merger does not know `text-display` or `text-h1`. It takes them for colors, so `cn("text-label text-muted-foreground")` silently drops one of the two, and a type class passed to a stock component does not replace its size. Unless `lib/utils.ts` already does this, change it to:

   ```ts
   import { createCn } from "cn/config"

   // The theme's type classes are font sizes, not colors.
   export const cn = createCn({
     extend: {
       classGroups: {
         "font-size": [{ text: ["display", "h1", "h2", "body", "label"] }],
       },
     },
   })
   ```

   Then make every file in `components/ui` use it: where one has `import { cn } from "cn"`, change that line to import `cn` from the project's utils file (`@/lib/utils` in a default setup). Do the same for each component you add later. If the project uses `tailwind-merge` instead of the `cn` package, its components already import from the utils file: pass the same object to `extendTailwindMerge` and keep `clsx`.
5. **Write real content.** If the user gave you details about their product, use them. Otherwise use the sample product in this brief and write the rest of the copy yourself: specific and plain, the way the samples read. Invent the company and people names; do not use real ones. Never use lorem ipsum. A link with no destination yet points to `#`. Set the page's `<title>` and meta description.

## The theme in short

- **Fonts:** Archivo for headings, IBM Plex Sans for body text, IBM Plex Mono for labels and code.
- **Type scale** (size/weight; each class also sets line height and tracking): `text-display` 56px/700, `text-h1` 36px/700, `text-h2` 24px/600, `text-body` 16px/400, `text-label` 12px/500.
- **Font per size:** a type class does not set the font family. Headings (`<h1>` to `<h6>`) get the heading font on their own; on any other element add the font class: `font-heading` with `text-display`, `text-h1`, `text-h2`; `font-mono` with `text-label`.
- **Spacing scale**, with the Tailwind step in brackets: 4px (`1`), 8px (`2`), 16px (`4`), 32px (`8`), 64px (`16`).
- **Corners:** none 0, sm 2px, md 4px.
- **Colors (light mode):** primary #1F3BFF, on-primary #FFFFFF, secondary #111111, on-secondary #FFFFFF, tertiary #FF4F00, on-tertiary #111111, neutral #6B6B6B, background #FFFFFF, surface #F5F5F4, foreground #111111, border #E2E2E0, error #C62828.

### How Strict One pages are laid out

- **Container:** every section's content sits in a `max-w-[1200px]` container, centered, with `px-4` on small screens and `px-8` from `md` up. This width is the one arbitrary value allowed.
- **Grid:** inside the container, a 12-column grid with `gap-x-8` from `md` up, and a single column below `md`. The grid only sets columns: every vertical distance comes from the rhythm rule, written as `gap-y-*` or `mt-*`, also when the grid is stacked. Align content to the grid's left edge. Do not center text blocks.
- **Sections:** a section ends with `pb-16`. A section that opens with a rule (a section header, or its own top border) has nothing above the rule: the rule is its first line, and the space before it is the previous section's `pb-16`. A section with no rule, such as a hero, also has `pt-16`. A one-line row between sections (a proof row, a single link) has `pb-8` and no top padding. No background bands, no boxes around sections.
- **Vertical rhythm:** `gap-2` between a label and the thing it labels, `gap-4` between a heading and its paragraph and between paragraphs, `gap-8` between blocks, and `mt-8` between a section header and the section's content. In a list of links or features, `gap-2` between items and `gap-4` under the list's label heading. `gap-4` between a button and a link beside it. A header row has `py-4`, with `gap-8` between its items from `md` up and `gap-4` below.
- **Section header:** a section opens with a 1px `border-foreground` top rule and `pt-4`. Under it, columns 1–3 hold a label in the form `01 / FEATURES` in `text-muted-foreground`, and columns 4–12 hold the section heading, an `<h2>` in `text-h1`. Where this brief gives only the label, write the heading yourself. Below `md` the label sits above the heading with `gap-2`.
- **Borders:** every line is 1px and `border-border`, unless this brief says `border-foreground`. The header's bottom line and the footer's top line run the full width of the window; every other line stays inside the container.
- **Labels:** eyebrows, table headers, captions, bylines, nav links, button and badge text, and metadata are labels: `font-mono text-label uppercase`. Write a label as a short fragment, not a sentence; text that needs a full sentence is body text. Email addresses and values in a table or a figure are never uppercased. A "label heading" is a real heading element styled as a label: an `<h2>` in a footer, otherwise `<h2>` or `<h3>`, whichever keeps the heading order.
- **Text color:** body text, headings, label headings and nav links are `text-foreground`. Other labels, captions and metadata are `text-muted-foreground`. A button's text color comes from its variant. Paragraphs are never muted: hierarchy comes from size and weight, not color.
- **Measure:** a paragraph of body text is at most `max-w-lg` wide (512px, 65 to 70 characters a line in this font), however many columns it sits in.
- **Links:** a text link is `text-primary underline underline-offset-4 hover:text-foreground` and inherits its size. A link in a nav or in a footer's link list is `text-foreground` and gets an underline on hover.
- **Buttons:** use the shadcn `Button` with `className="rounded-sm px-4 font-mono text-label uppercase"`, so labels are uppercase mono as `DESIGN.md` asks. A call to action that goes to another page is an `<a>` with the same classes: write `cn(buttonVariants({ variant }), "…")`, because `buttonVariants` alone does not merge classes and the stock size and corners would win. `Button` is for actions, so on a marketing page most "buttons" in this brief are such links. One default button per screenful. Other actions, a "Menu" button included, use `variant="outline"` or a text link. A group of buttons where one is selected (a filter, a period switch) is a `role="group"` with an `aria-label` and `gap-1`; the selected one has `aria-pressed="true"` and `variant="secondary"`, the rest `variant="outline"`.
- **Badges:** the shadcn `Badge` with `className="rounded-none font-mono text-label uppercase"`, in the `secondary` or `outline` variant. At most one badge in a view is the signal badge `DESIGN.md` describes: the `secondary` variant with `bg-tertiary text-tertiary-foreground` added.
- **Inputs:** the shadcn `Input` with `className="rounded-sm text-body md:text-body"`, and an `aria-label` when it has no visible label.
- **Icons:** from the project's icon set, with `size-4` and `strokeWidth={1.5}`.
- **Corners:** controls use `rounded-sm` (2px), panels and code blocks `rounded-md` (4px), badges and figures inside panels `rounded-none`.
- **Figures:** a figure's caption is a label below its panel, outside it, with `mt-2`.
- **Panels:** a panel is a plain element with a 1px border and `rounded-md`. On a content page, panels that hold a figure or code are `bg-card`; on an app screen every panel is `bg-background`. Do not use the shadcn `Card` for a panel: it ships larger corners and a ring.
- **Surfaces:** flat. No shadows, no blur, no gradients. Where a stock component ships a shadow, a blur or a dimmed overlay (`Sheet`, `DropdownMenu`, `Tooltip`), remove it: with `className` where that reaches, otherwise by editing the file in `components/ui`, which is yours to change. Use a 1px border instead of a shadow and `bg-background/80` for an overlay.
- **Tables:** a table's body text is `text-body`; set it on the `Table` or the `<table>`. Header cells are labels in `text-muted-foreground`. Cells have `px-4 py-2`, in a plain `<table>` and in the stock `Table` alike (its `TableHead` and `TableCell` ship `px-2` and `whitespace-nowrap`). Where the table sits in something that already has padding (a section, a padded panel), add `first:pl-0 last:pr-0`; where it touches a panel's border, do not. Cells that hold a sentence get `whitespace-normal`. A table that can be wider than its box scrolls in a box that is reachable with the keyboard: `tabIndex={0}`, `role="region"` and an `aria-label`. For the stock `Table`, edit `components/ui/table.tsx` and add a prop for the label. A table that always fits needs none of this; one that should scroll on a phone rather than squeeze gets `min-w-lg`.
- **Primary color:** only for the one main action and for links. Never for large fills such as chart bars, bands or panels; those are `bg-foreground`, `bg-card` or a border.
- **Menus on small screens:** a "Menu" button with `aria-expanded` and `aria-controls` that shows the links as a list inside the `<header>`, under its row, with a 1px top border; each link is a block with `py-2`. If the row still does not fit at 360px, move its call to action into the menu too. Use the shadcn `Sheet` only for a full sidebar; such a sheet is `bg-sidebar`, 256px wide (`data-[side=left]:w-64`, since a plain `w-64` loses to the stock width) and has a visually hidden `SheetTitle`. It is rendered outside the page's root, so it also needs `text-body`, plus `overflow-y-auto` and `pt-16` to clear its close button. Its trigger takes `render={<Button … />}` in a Base UI project and `asChild` in a Radix one. A page never has two "Menu" buttons.
- **Motion:** in the code you write, the only transition is color: links and buttons get `transition-colors duration-150`. Nothing moves on scroll. Stock components keep the motion they ship with.

## The page

Where this section and the layout notes above differ, this section wins.

Sample product, if the user gave none: **Plainsheet**, "spreadsheets your whole team can read". It turns messy spreadsheets into clean shared views with comments and history.

Build these sections in order.

### 1. Header

A single row with a 1px bottom border. Left: the product name in `font-heading text-h2`. Middle or right: three text links as labels (Product, Pricing, Docs). Far right: a "Sign in" label link and an `outline` button "Start free". Below `md` the row holds only the product name, "Start free" and a "Menu" button; the three links and "Sign in" move into the menu.

### 2. Hero

- Columns 1–12: an eyebrow label, e.g. `SPREADSHEETS FOR TEAMS`.
- Columns 1–10: the `<h1>` in `text-display` on `md` and up, `text-h1` below. Sample: "The spreadsheet everyone on the team can actually read."
- Columns 1–6: one paragraph in `text-body`, two or three sentences.
- Then a row with the default button ("Start free") and one text link ("See how it works").
- Then, across all 12 columns, a product figure: a `bg-card` panel with `p-8` (`p-4` below `md`), holding a plain `<table>`: a header row of labels and five data rows of plausible sample data, numbers in `font-mono text-body tabular-nums` aligned right, rows divided by 1px borders. Below `md`, hide the less important columns so the table fits; it then needs no scroll box. Give the figure a caption.

### 3. Proof row

One row, padded as the layout notes say for a one-line row: a label "USED BY TEAMS AT" followed by five invented company names as plain text in `font-heading text-h2`. They wrap onto more lines on small screens. No logos.

### 4. Features

Section header: `01 / FEATURES`. Then three features in a 12-column grid, four columns each. Each feature has a 1px top border, `pt-4`, a one-word label naming it (`VIEWS`, `COMMENTS`, `HISTORY`), an `<h3>` in `text-h2`, and a paragraph in `text-body`. No icons, no cards.

### 5. How it works

Section header: `02 / HOW IT WORKS`. Two rows, each with a 1px top border and `pt-8`. In each, columns 1–5 hold a step label (`STEP 01`), an `<h3>` in `text-h2` and a paragraph; columns 7–12 hold a `bg-card` panel with `p-8` (`p-4` below `md`), a figure built from elements (for example a comment thread, or a list of versions), with a caption. Stack the two parts below `md`.

### 6. Quote

One customer quote in a `<blockquote>`, set in `font-heading text-h1` across columns 1–10, with a 1px `border-foreground` top border above it, as wide as the container, and `pt-8`. Under it, with `mt-4`, a label with the person's name, role and company. No avatar, no quotation-mark graphic.

### 7. Closing call to action

A section with a 1px top border and `pt-16`. It has no bottom border: the footer's line closes it. Columns 1–8: an `<h2>` in `text-h1` and one sentence. Then the default button. This is the second primary button on the page, which is fine because it is never on screen with the hero's.

### 8. Footer

A footer with `py-16`. Four columns from `md` up: the product name in `font-heading text-h2` with a one-line description, then three link groups (Product, Company, Legal), each with a label heading and four links in `text-body`. Under them, with `mt-8`, a 1px top border, `pt-4` and a label line with the copyright.

### Behavior

- The mobile menu opens and closes with the keyboard, closes on Escape and sets `aria-expanded`.

## Rules

- **Colors:** only the theme's colors, through the semantic classes (`bg-background`, `text-foreground`, `bg-card`, `bg-primary`, `text-primary-foreground`, `text-muted-foreground`, `border-border` and so on). No hex, rgb or named colors in components, and no Tailwind palette classes such as `bg-blue-500` or `text-gray-600`.
- **Spacing:** padding, margin and gap use only the scale's steps (`1`, `2`, `4`, `8`, `16`) plus 0 and 1px. No arbitrary values such as `p-[18px]`, and no other steps such as `p-3` or `gap-6`. `auto` margins are fine. Widths and heights such as `w-64` or `size-4` are sizes, not spacing. This applies to the code you write: a stock component keeps the spacing inside it, unless this brief changes it.
- **Type:** every piece of text you write gets its size from one of `text-display`, `text-h1`, `text-h2`, `text-body`, `text-label`, set on the element or on a parent it inherits from. Put `text-body` on the page's root element. No other sizes. A stock shadcn component keeps the size it ships with, unless `DESIGN.md` or this brief gives that component its own style. A type class does not replace a weight class: where a stock component ships `font-medium` and the text should be regular, add `font-normal`.
- **Fonts:** only the theme's fonts, through `font-sans`, `font-heading` and `font-mono`. Do not add a font.
- **Corners:** only the `rounded-*` classes, which the theme already sets. No arbitrary radius, and `rounded-full` only for avatars and status dots.
- **Contrast:** all text meets WCAG AA against its background.
- **Focus:** every link and control shows a 2px outline on keyboard focus: `focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring`. Keep `focus-visible:outline-solid` in it: in Tailwind 4 an `outline-none` on the same element, which stock components carry, otherwise hides the outline. A stock component that ships its own focus ring (`Button`, `buttonVariants`, `Input`, `AccordionTrigger`, the close button of a `Sheet`) also gets `focus-visible:ring-0`, by editing its file in `components/ui` where `className` does not reach. A box that scrolls sideways (a code block, a wide table) gets `tabIndex={0}`, `role="region"`, an `aria-label` and the same outline.
- **Not allowed:** purple or multi-color gradients; emoji used as icons or bullets.
- **Avoid:** a card inside a card; glows and colored shadows.
- **Dark mode:** the page must work with the `dark` class on `<html>`. Because every color comes from a semantic class, this needs no extra code; do not write `dark:` color overrides.

From the theme's own do's and don'ts:

- Do keep one accent color per screen.
- Do let whitespace separate content.
- Don't use gradients, glows, glassmorphism or drop shadows.
- Don't use emoji as icons or bullets.
- Don't introduce a color, size or radius that is not a token above.

## Check before you finish

Go through this list against the code you wrote, and fix anything that fails.

- [ ] The hero heading is the page's only `text-display` text and its only `<h1>`.
- [ ] No screenful shows more than one default (primary) button.
- [ ] The page uses no image files; figures are built from elements.
- [ ] Feature and step blocks are separated by borders and whitespace, not wrapped in cards.
- [ ] No color is written as a hex, rgb or Tailwind palette value in the page's code.
- [ ] Every padding, margin and gap is a step of the spacing scale.
- [ ] Every text element you wrote gets its size from a type-scale class, its own or an inherited one. Visually hidden text is exempt.
- [ ] No file in `components/ui` imports `cn` from `"cn"` directly.
- [ ] Text contrast meets WCAG AA in light and dark mode.
- [ ] The page has one `<h1>`, headings are in order, and every image has alt text.
- [ ] Every interactive element can be reached with the keyboard and shows the focus outline from the rules.
- [ ] At 375px wide the page does not scroll sideways. Wide tables and code blocks scroll inside their own box.
- [ ] The project builds without errors or warnings.

Then tell the user which checks pass, which you could not verify, and anything in this brief you did not do and why.
