# Build a legal briefing article with the Counsel theme

You are building one page in an existing project: a long-read briefing from a commercial law firm, with a summary box, a list of its sections, four headed sections with a pull quote and numbered points, the author and related briefings. Follow this brief closely. `DESIGN.md` decides the tokens: colors, type, spacing steps and corners. This brief decides the layout, its widths included, and which token goes where. If this brief names a color, a type size, a spacing step or a corner that `DESIGN.md` does not have, `DESIGN.md` wins.

## Before you start

1. **Check the theme is installed.** The project should have `DESIGN.md` in its root and the Counsel variables in its global CSS. If not, run `npx shadcn@latest add https://strictthemes.com/r/counsel.json` and save https://strictthemes.com/themes/counsel/DESIGN.md as `DESIGN.md` in the project root. In a project without shadcn, use https://strictthemes.com/themes/counsel/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. Keep every font import the theme's install added, also one for a style no page uses yet.
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. In a new shadcn project, `lib/utils.ts` only passes `cn` on from the `cn` package. Unless the file already holds the lines below, 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:** Marcellus for headings, Jost for body text, Courier Prime for labels and code.
- **Type scale** (size/weight; each class also sets line height and tracking): `text-display` 60px/400, `text-h1` 40px/400, `text-h2` 24px/400, `text-body` 17px/400, `text-label` 13px/400.
- **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`), 56px (`14`), 112px (`28`).
- **Corners:** `rounded-sm` 1px, `rounded-md` 2px, `rounded-xl` 4px (the `lg` corner in `DESIGN.md`). `rounded-lg` is 2px as well: it is shadcn's name for the base corner, the one its stock buttons and inputs use.
- **Colors (light mode):** primary #14213D, on-primary #FFFFFF, secondary #000000, on-secondary #FFFFFF, tertiary #FCA311, on-tertiary #000000, neutral #5B6170, background #FFFFFF, surface #F6F6F6, foreground #000000, border #E5E5E5, error #B3261E.

### How Counsel pages are laid out

- **Container:** one `<div>` wraps the whole page and is the container: `mx-auto max-w-[1200px] px-4 md:px-8`, plus `text-body`. This width is the one arbitrary value allowed. Inside it sit the `<header>`, a `<main>` holding everything between the two, and the `<footer>`.
- **Grid:** a section's content sits in a grid: `grid grid-cols-1 md:grid-cols-12 md:gap-x-8`. The grid sets columns only, never `gap-y-*`: every vertical distance comes from the rhythm rule. Below `md` every grid item takes the full width. Leave the columns this brief does not fill empty; an empty column is part of the design, so center nothing to fill it. From `md` up every grid item gets `md:col-span-*`, because an item without one takes a single column: "columns 1–12" is `md:col-span-12`. It also gets `md:col-start-*` when it starts after column 1, and `md:col-start-1` when it must start a new row under an item that leaves room beside it; or the grid puts it in that room. An item whose columns overlap those of the item before it always starts a new row. Where a brief puts "a section's content in columns 5–12", the `<section>` is the grid and the content is one `<div>` with those column classes. Where a list "is itself the grid", the `<section>` is not a grid: the heading above the list sits directly in it at the full width.
- **Text and note:** running text sits in seven of the twelve columns (`md:col-span-7`, or the columns this brief gives). Beside it, where this brief asks for one, sits one short note in columns 9–12 (`md:col-start-9 md:col-span-4`), with `mt-14 md:mt-0` on a phone, so it comes after the text. Nothing else stands beside the text.
- **Vertical rhythm:** written as a top margin on the lower element (`mt-*`), never as `space-y-*`, `gap-y-*`, a bottom margin or padding, except the padding a section gets around its hairline (see Sections) and the padding of a card or a list entry, which these notes give. Between a label and the one thing it names (a form label and its field, a name and the role under it, a term and its value when they stack): `mt-2`. Between a heading and the text under it, and between paragraphs: `mt-4`. A label line above a heading, and a label heading above its text, its `<address>` or its `<dl>`, count as headings: `mt-4` to what follows. Between blocks inside a section (a paragraph and a button, a heading and a list, a card and the text after it, two parts of a side column): `mt-8`. Between two parts of a section that each have their own `<h2>`: `mt-14`. Where two grid items share a row from `md` up, the second has its phone margin and `md:mt-0`, unless this brief gives a margin from `md` up. Inside a flex row (the header, a label line with a badge, a group of buttons) the space is the row's `gap-*` as this brief states it. Where this brief gives an element its own margin, it replaces the one from this list.
- **Sections:** `<main>` holds a stack of `<section>` elements. The first has `mt-14 md:mt-28` and no border: the header's hairline is above it. Every other section is divided from the one before it by one hairline, with white space on both sides of it: `mt-8 border-t border-border pt-8 md:mt-14 md:pt-14`, which is 112px from section to section on a large screen and 64px on a phone, with the line in the middle. That is the whole gap and the only padding a section has; the section's first element takes no top margin of its own.
- **Header:** the `<header>` is itself the row, with `border-b border-border py-8`: `flex flex-col items-start gap-4 md:flex-row md:items-baseline md:justify-between`. On the left the firm's name, `Harrow & Vane`, a link to `/` in `font-heading text-h2`, styled as a header link and never marked as the current page. It is not a heading element, and it has no weight class. On the right a `<nav>` with the `aria-label` "Main" and no classes, holding a `<ul>` with `flex flex-wrap gap-x-4 gap-y-2 md:gap-x-8` of four links as labels, in this order: "Practice" (`/practice/commercial-disputes`), "People" (`/people/ruth-calloway`), "Insights" (`/insights/notice-clauses`) and "Contact" (`/contact`). Each brief names the current one, if any. Below `md` the links sit under the name and may wrap onto a second line; there is no "Menu" button.
- **Footer:** a `<footer>` with `mt-14 md:mt-28`, a 1px `border-border` top border and `py-8`. Inside it a grid like the one above, with three parts:
  - Columns 1–4 (`md:col-span-4`): the firm's full name as plain text in `font-heading text-h2`, `Harrow & Vane LLP`, then with `mt-2` the office's address: one `<address>` with `not-italic font-mono text-label uppercase text-muted-foreground` holding two `<p>` lines with no margin between them, `4 Chancery Row` and `Wexcombe WX1 2LN`.
  - Columns 5–8 (`md:col-start-5 md:col-span-4`, with `mt-8 md:mt-0`): two `<p>` label lines, the second with `mt-2`: the telephone number `01632 960 214` as a `tel:01632960214` link, and the email address `enquiries@harrowvane.example` as a `mailto:` link in `normal-case`. Both styled as footer links.
  - Columns 9–12 (`md:col-start-9 md:col-span-4`, with `mt-8 md:mt-0`): a `<nav>` with the `aria-label` "Footer" holding a `<ul>` of the header's four links, in the same order, as labels, `mt-2` between items. The current page is marked here too, with `aria-current="page"` and `underline`.
  - Under the grid, with `mt-8`, a label line in `text-muted-foreground`: `© 2026 Harrow & Vane LLP · Registered in England and Wales`.
- **Headings:** the `<h1>` is `text-h1`, and `text-display` from `md` up where this brief says so (`text-h1 md:text-display`). An `<h2>` in the heading font is `text-h2`, and so is an `<h3>`. Nothing in the heading font is smaller than `text-h2`: a smaller heading is a label heading. Headings keep the regular weight their type class gives them: add no weight class, never `font-bold` or `font-semibold`. Sentence case, no full stop.
- **No bold, no italics:** Marcellus has one weight and no italic, and nothing on these pages fakes either. No `<em>`, `<i>`, `<strong>`, `<b>` or `<cite>`, and no `italic` or bold class, in headings or in running text. An `<address>` is italic by default: give every `<address>` `not-italic`.
- **Labels:** nav links, dates, matter numbers, the names of practice areas in a label line, roles under a name, form labels, terms in a `<dl>`, and button and badge text are labels: `font-mono text-label uppercase`. The wide tracking comes with `text-label`; do not add a `tracking-*` class. Write a label as a short fragment, not a sentence. Error lines and helper text use the label's font and size but are sentences, and are not uppercased. Join the parts of a label line with ` · `. A label on its own line is a block element such as a `<p>`. Email addresses and what someone typed are never uppercased: put an email address inside a label in a `<span>` (or give its link) `normal-case`.
- **Label headings:** a heading that is styled as a label (Address, Hours, Contact) is an `<h2>` or `<h3>`, whichever keeps the heading order, with `font-mono text-label uppercase text-foreground`. Keep the `font-mono`: a heading element gets the heading font on its own.
- **Text color:** headings, label headings, body text, nav links, names and form labels are `text-foreground`. A button's or a badge's text color comes from its variant or its classes. Dates, matter numbers, roles under a name, `<dt>` terms, caption lines and helper text are `text-muted-foreground`. Muted text sits only on `bg-background` or `bg-card`. Paragraphs are never muted. No other text colors: gold (`tertiary`) and navy (`primary`) are never text colors.
- **Measure:** a paragraph of body text is at most `max-w-xl` wide (576px, about 70 characters in Jost at this size), however many columns it sits in. A heading may run wider.
- **Figures:** a sum, a count or a year that stands on its own in a label is `font-mono tabular-nums`. A large figure in a row of figures is `font-heading text-h1`, where this brief says so. Sums are written with the pound sign before the number: `£6.2m`, `£48m`, `£1,480`. A date or a year that stands on its own (in a label line, a `<dd>`, a list entry) is a `<time>` with a `dateTime`. A date or a year inside a sentence (running text, a confirmation message, an error line) is plain text, not a `<time>`, unless this brief says otherwise. A date is written `10 November 2026` (`dateTime="2026-11-10"`), a time `08:30`, a year `2026`. The copyright year is plain text.
- **Telephone numbers** are written in groups, `01632 960 214`; a `tel:` link's `href` has the digits with no spaces (`tel:01632960214`).
- **Links:** a link in running text is `text-foreground underline decoration-1 underline-offset-4 hover:text-muted-foreground`, and inherits its size and font. A link in the header or the footer, and a name or a title that is a link, is `text-foreground decoration-1 underline-offset-4 hover:underline`; the link for the current page has `aria-current="page"` and `underline`. Mark one only where this brief names the current page. Links are never colored, and get `transition-colors duration-150`. A link whose destination this brief does not give points to `#`; the firm's name always points to `/`.
- **Onward links:** a link that stands alone at the end of a part ("All partners", "All briefings") is a `<p>` holding the link (also where a brief puts it in a heading's row), as a label (`font-mono text-label uppercase`) styled as a link in running text, in `inline-flex items-center gap-2`, followed by the `ArrowRight` icon.
- **Buttons:** the shadcn `Button` with `className="h-auto px-8 py-2 font-mono text-label font-normal uppercase"`: `font-normal` because the labels are regular. The default variant (navy, gold in dark mode) is for the page's one main action: one on a page, unless this brief gives a second. Any other button is `variant="secondary"` (black, near-white in dark mode). In `components/ui/button.tsx`, replace that variant's stock `hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)]` with `hover:bg-secondary/80`, once, not beside it: the 5% mix cannot be told from the resting color. Make this change even on a page with no secondary button, so every page's `button.tsx` is the same. Do not use the `outline`, `ghost`, `link` or `destructive` variants, or the `xs`, `sm` or icon sizes. A button that sends a form needs `type="submit"`: this `Button` is `type="button"` unless told otherwise. A call to action that goes to another page, or a `mailto:` or `tel:` link styled as a button, is an `<a>` with the same classes: write `cn(buttonVariants({ variant }), "…")`, because `buttonVariants` alone does not merge classes. Button text is at most four words.
- **Inputs:** the shadcn `Input` and `Textarea` (`npx shadcn@latest add input textarea`) with `className="h-auto border-muted-foreground px-4 py-2 text-body md:text-body"`. The stock `border-input` is too faint against the page and the card; `border-muted-foreground` reaches 3:1 in both modes. They keep their stock 2px corner, the fill they ship with (in dark mode too), the stock `focus-visible:border-ring` and the stock `aria-invalid:border-destructive`. Every field has a visible `<label>` above it with `block`, tied to it with `htmlFor` and styled as a label in `text-foreground`; the field has `mt-2`. Fields follow each other with `mt-8`, on the wrapper `<div>` that holds a label, its field and its error. Optional fields say so in the label: `Telephone (optional)`.
- **Selects:** a choice from a short list is a native `<select>` with `h-auto w-full rounded-md border border-muted-foreground bg-transparent px-4 py-2 text-body text-foreground dark:bg-input/30 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 focus-visible:border-ring` and the four `focus-visible:outline-*` classes from the rules: the fill, border and error classes are the ones the stock `Input` ships, so the two look alike in both modes; these two `dark:` classes are the one exception to the rules' "no `dark:` color overrides". It takes the same label, margins and error line as any field, and shows an error with `aria-invalid` and its red border, like an `Input`. Its first option is a prompt with an empty value.
- **Checkboxes:** the shadcn `Checkbox` (`npx shadcn@latest add checkbox`). In `components/ui/checkbox.tsx`, change its `rounded-[4px]` to `rounded-md` and its `border-input` to `border-muted-foreground`, once, so it has the inputs' corner and border (where the file ships another corner or border class, change that one). Its stock size, check icon and checked fill (`bg-primary`) stay. Its row is `flex items-start gap-4`, with `mt-1` on the checkbox so it lines up with the first line of its label, and the `<label>` in `text-body text-foreground`, not uppercased: it is a sentence, not a label. Give the `Checkbox` an `id` and the `<label>` `htmlFor` with it, so a click on the words ticks the box; give the `<label>` an `id` too, and the `Checkbox` `aria-labelledby` naming it, because in a Base UI project the `Checkbox`'s `id` lands on a hidden input and the visible box would otherwise have no name.
- **Errors:** an error is a line under its field with `mt-2`: a `<p>` with an `id`, `flex items-start gap-2 font-mono text-label text-destructive`, not uppercased, holding the `CircleAlert` icon (`shrink-0`, no margin) and a sentence that says what to do. The field gets `aria-invalid` and points to the line with `aria-describedby` (beside any helper line it already names). Fields are checked in code when the form is sent, with `noValidate` on the `<form>`, and focus moves to the first field with an error. Render the error lines first and move focus after that render, in an effect or a `requestAnimationFrame`, so the field's description is there when it is read. An error line and its field's `aria-invalid` are removed when that field changes (on `input` or `change`; for the checkbox, on `onCheckedChange`). Every other error stays until the next send.
- **Forms:** a form sits on the pale grey: the `<form>` is `rounded-xl bg-card p-8`, with no border and no shadow. The send button sits under the last field with `mt-8`.
- **Confirmations:** a message that replaces a form goes into an element with `role="status"` that is on the page from the start, empty. The form and the status element share one wrapper, and the wrapper carries the top margin and the column classes, so the message stands where the form stood. The status element has no classes and no margin, so empty it takes no space; never hide it. Inside it, rendered only once there is a message, a `<div>` with `rounded-xl bg-card p-8`, like the form: an `<h2>` or `<h3>` in `text-h2` (whichever keeps the heading order), then with `mt-4` one or two sentences in `text-body`, then whatever this brief adds. A button that follows the message sits after the status element in the same wrapper, not inside it, with `mt-8`. Give the heading `tabIndex={-1}` and move focus to it, because the button that had focus is gone.
- **Badges:** exactly one badge on a page, where this brief puts it, and it is the page's one use of gold: the shadcn `Badge` (`npx shadcn@latest add badge`) with `className="h-auto rounded-sm border-transparent bg-tertiary px-2 py-1 font-mono text-label font-normal uppercase text-tertiary-foreground"`. One or two words, no icon. Nothing else on the page is `bg-tertiary`. In dark mode the gold moves to the main button and the badge turns pale grey, as `DESIGN.md` says; that needs no code.
- **Cards:** a card is a plain element with `rounded-xl bg-card p-8`: pale grey, no border, no shadow. Not the shadcn `Card`, which ships its own padding and a ring. Inside it, a label comes first, with no top margin. Use one only where this brief asks for it, never a card inside a card, and nothing with a border or a fill inside a card except the fields of a form.
- **Portraits:** there are no image files. A portrait is a rectangle, never a circle: a plain `<div>` with `aspect-3/4 w-full rounded-xl border border-border bg-card`, `role="img"` and an `aria-label` that describes the photograph in a sentence ("Ruth Calloway in a dark suit, at a window of the firm's library"). It is drawn as a monogram plate: the `<div>` also has `flex items-end p-4` (`p-8` for a portrait this brief calls large), and holds one `<span>` with `aria-hidden="true"`, the person's initials in `font-heading text-h1 text-muted-foreground` (`text-display` for a large portrait). Nothing else is drawn in it: no icon, no gradient, no shape. A portrait never sits inside a card.
- **Lists of people and matters:** a list where this brief gives each item a 1px top border (people, matters, briefings, steps) is a `<ul>` or `<ol>` with `list-none`, no padding, and no space between its items; each item has `border-t border-border py-8`, unless this brief gives `py-4`, and the list a `border-b border-border` that closes it. In each item a name or a title is in the heading font (an `<h3>` in `text-h2`, or the element this brief names), and the role, the date or the matter number is a label line in `text-muted-foreground`, `mt-2` under the name or above the title as this brief says. Where this brief lays an entry out in columns, the `<li>` itself carries the grid classes beside these, and its parts are the grid items.
- **Description lists:** a `<dl>` is a list of rows. Each row is a `<div>` with `grid grid-cols-3 items-baseline gap-x-4 border-t border-border py-4`: the `<dt>` is a label in `text-muted-foreground`, the `<dd>` takes the other two columns (`col-span-2`) in `text-body`. The `<dl>` has `border-b border-border`, so the last row is closed too. This holds at 375px as well, unless this brief stacks the rows.
- **Rules:** every line is 1px and `border-border`. Hairlines, not boxes, divide a page. No shadows, no blur, no gradients, no colored backgrounds behind sections.
- **Corners:** `rounded-sm` (1px) for the badge, `rounded-md` (2px) for the select and the checkbox, the stock 2px of the `Button`, `Input` and `Textarea` (their `rounded-lg`, which this theme sets to 2px), and `rounded-xl` (4px, the `lg` corner in `DESIGN.md`) for cards, forms and portraits. Nothing is a pill or a circle: no portrait, no badge, no dot and no switch is round.
- **Icons:** from the project's icon set, `lucide-react`, with `size-4`, `strokeWidth={1.5}` and `aria-hidden="true"`. Use them only where this brief or these notes name one. Never emoji.
- **Surfaces:** flat. A stock component that floats over the page (a menu, a dialog) keeps the one short shadow it ships with; these pages use none.
- **Motion:** in the code you write, the only transition is color, and nothing moves on scroll. Stock components keep the motion they ship with, the `Button`'s included.

## The page

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

Sample firm, if the user gave none: **Harrow & Vane LLP**, an invented commercial law firm in Wexcombe, an invented English city, founded in 1952, with 14 partners and 86 lawyers in one office at 4 Chancery Row, Wexcombe WX1 2LN. This page is a briefing by **Ruth Calloway**, a partner in its Commercial disputes team (made partner on 1 May 2026; `01632 960 237`, r.calloway@harrowvane.example), published on 10 November 2026, an 8 minute read: "Notice clauses after a sale: when a late letter ends a warranty claim". Its subject: a buyer of a company who finds a problem after completion usually has a warranty claim against the sellers, but the sale contract says how, to whom and by when the buyer must give notice of it, and a notice that misses one of those terms can end the claim before its merits are heard. Its example is a claim the firm defended this year for the sellers of Halden Print, an invented printing company: a £3.4m warranty claim, struck out because the buyer's notice arrived one day after the contract's deadline. Write the full text yourself, 1,000 to 1,200 words of running text, in the third person plural ("we"), plain and exact, as a careful letter to a client reads. Name no real case, judge, court ruling, statute or section of one, and no real firm or person: speak of "the contract", "the court" and "the buyer". Every name is invented.

Build these parts in order. An `<article>` inside `<main>` wraps the first two sections, the opening and the briefing; the sections after it are siblings of the `<article>`, and keep the section margins and hairlines of the layout notes.

### 1. Header

The header from the layout notes. "Insights" is the current page, in the header and in the footer.

### 2. Opening

The first section, in the grid:

- A row in columns 1–12 (`md:col-span-12`), a `<div>` with `flex flex-wrap items-center gap-x-4 gap-y-2`: a label line in `text-muted-foreground`, `Briefing · Commercial disputes`, and beside it the page's one badge, "New".
- With `mt-4`, the `<h1>` in `text-h1 md:text-display`, columns 1–10 (`md:col-span-10`): "Notice clauses after a sale: when a late letter ends a warranty claim". It runs over three lines on a large screen, and that is fine.
- With `mt-8`, the standfirst: a `<p>` in `font-heading text-h2` in columns 1–8 (`md:col-start-1 md:col-span-8`, which overlap the `<h1>`'s, so it starts a row under it), two sentences. Sample: "A buyer can have a good claim and still lose it to the calendar. Before anyone argues about the accounts, the contract asks whether the notice was right."
- With `mt-8`, in columns 1–8 (`md:col-start-1 md:col-span-8`), a label line in `text-muted-foreground`: `By Ruth Calloway · 10 November 2026 · 8 min read`. "Ruth Calloway" is a link to `/people/ruth-calloway`, styled as a link in running text and kept in `text-foreground`; the date is a `<time dateTime="2026-11-10">`.

### 3. The briefing

A section in the grid, with two parts. The list of sections comes first in the code, so that on a phone it stands above the text; from `md` up both parts have `md:row-start-1`, so the text takes columns 1–7 and the list sits at the right of its first lines.

**On this page**, in columns 9–12 (`md:col-start-9 md:col-span-4 md:row-start-1`): a `<nav>` with `aria-labelledby` naming its label heading, and no `aria-label`:

- A label heading "On this page", an `<h2>` with an `id`.
- With `mt-4`, an `<ol>` with `list-none`, no padding, `mt-2` between items, holding four links in `text-body`, styled as titles that are links, one for each `<h2>` of the text below, with the same words.

**The text**, in columns 1–7 (`md:col-span-7 md:row-start-1`), with `mt-14 md:mt-0`: one `<div>` in normal block flow, every paragraph at most `max-w-xl`. Inside it, in this order:

- **In brief:** a card from the layout notes, a `<div>` with no top margin. A label heading "In brief", an `<h2>`, then with `mt-4` a `<ul>` with `list-disc pl-4` and `mt-2` between items, three sentences in `text-body`: notice clauses set the form, the recipient and the deadline of a claim; a court reads them strictly, and one day late can be too late; check the clause and serve early, with the facts you have.
- With `mt-8`, two opening paragraphs in `text-body`, the second with `mt-4`.
- **Four `<h2>` sections**, each `<h2>` in `text-h2` with `mt-14`, an `id` and `scroll-mt-8`, and the text under it with `mt-4`. Paragraphs follow each other with `mt-4`. A list, the pull quote, or a paragraph that follows a list or the pull quote has `mt-8`. The headings, in this order:
  1. "What a notice clause asks for" (`id="asks"`): two or three paragraphs on what such a clause usually requires (writing, the right address, reasonable detail of the claim, a last day).
  2. "Three ways a notice fails" (`id="fails"`): one paragraph, then with `mt-8` a numbered list (`list-decimal pl-8`, `mt-2` between items) of three items of one or two sentences each: sent too late; sent to the wrong person or address; too thin to say what the claim is. Then with `mt-8` the pull quote, then one more paragraph.
  3. "A claim lost by a day" (`id="a-day"`): two or three paragraphs on the Halden Print claim: the contract's deadline, the letter sent by courier on the last day and signed for the next morning, and the court's decision to strike the claim out. The sum (£3.4m) and the dates are written in the sentences as plain text.
  4. "What to do before you send" (`id="before"`): one paragraph, then with `mt-8` a numbered list (`list-decimal pl-8`, `mt-2` between items) of four steps of one sentence each, then with `mt-8` a closing paragraph.
- **The pull quote:** a `<blockquote>` with `border-l border-border pl-8`, holding one `<p>` in `font-heading text-h2`: one sentence from this briefing, with no quotation marks, upright. Sample: "Most warranty claims are argued over the accounts. Some are lost in the post room first." No name under it: it is the briefing's own words.
- With `mt-8`, after the closing paragraph, one line of small print: a `<p>` in `font-mono text-label text-muted-foreground`, a sentence, not uppercased: "This briefing is general information and is not advice on any particular matter."

### 4. About the author

A section in the grid, with two parts:

- **The portrait**, in columns 1–2 (`md:col-span-2`): a portrait from the layout notes with the initials `RC`, and the `aria-label` "Ruth Calloway in a dark suit, at a window of the firm's library". On a phone it is a third of the width: write `w-1/3 md:w-full` in place of the notes' `w-full`.
- **The text**, in columns 4–10 (`md:col-start-4 md:col-span-7`), with `mt-8 md:mt-0`, a `<div>` in this order: a label heading "About the author", an `<h2>`; with `mt-4` the name as an `<h3>` in `text-h2` holding a link to `/people/ruth-calloway`, styled as a name that is a link; with `mt-2` a label line in `text-muted-foreground`, `Partner · Commercial disputes`; with `mt-4` two sentences in `text-body`, at most `max-w-xl`, on the disputes she handles; with `mt-8` a `<div>` holding the default button "Discuss this with Ruth", an `<a>` styled with `buttonVariants` and the Buttons classes, to `/contact`. The page's one default button.

### 5. Related briefings

A section that is not a grid:

- An `<h2>` in `text-h2`: "Related briefings".
- With `mt-8`, a `<ul>` as a list of entries, three entries, each with `py-8`. Each `<li>` is also `md:grid md:grid-cols-12 md:items-baseline md:gap-x-8`: in columns 1–3 (`md:col-span-3`) a label line in `text-muted-foreground` with the date as a `<time>` and the reading time, `29 October 2026 · 6 min read`; in columns 4–12 (`md:col-span-9`), with `mt-2 md:mt-0`, the title as an `<h3>` in `text-h2` holding a link to `#`, styled as a title that is a link, then with `mt-2` a label line in `text-muted-foreground` with the author and the practice area, `David Achterberg · Commercial disputes`.

  Entries, newest first: "Freezing orders: the first forty-eight hours" (29 October 2026, 6 min read, David Achterberg, Commercial disputes); "Break clauses in a commercial lease: getting the notice right" (1 October 2026, 5 min read, Thomas Kerridge, Real estate); "Earn-outs that end in dispute" (17 September 2026, 6 min read, Ruth Calloway, Commercial disputes).
- With `mt-8`, an onward link from the layout notes: "All briefings", to `#`.

### 6. Footer

The footer from the layout notes.

### On a phone

Every part is one column. The `<h1>` is `text-h1` and wraps over five or six lines; the standfirst follows it. The list of sections comes before the text, which starts 56px under it with the In brief card. The portrait is a third of the width, with the author's text under it. Each related briefing stacks: label line, title, then author.

### Behavior

- The links in On this page jump to their headings; `scroll-mt-8` keeps each heading clear of the top edge.
- Nothing else has state. Links only.

## 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`, `14`, `28`) plus 0, 1px and 2px. 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 outermost element of the page you write. 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. This theme has no full rounds: do not use `rounded-full`, and give a small mark a corner under half its height or none, because a box whose corner is half its height or more is a full round however it is written.
- **Contrast:** all text meets WCAG AA against its background.
- **Stock components:** a component from `components/ui`, and an `<a>` styled with `buttonVariants`, keeps the hover, pressed and disabled colors and the motion it ships with, unless this brief changes them. They are the theme's colors under other names.
- **Counts:** a number with a noun reads right at one: "1 set", not "1 sets". Where this brief gives the words for only one of the two, write the other the same way.
- **Sizes from data:** a height or a width that comes from data (a chart bar, a meter) is set with an inline `style`. That is the one use for an inline style.
- **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. An element that only gets focus from code (a heading or a message with `tabIndex={-1}`) gets the same outline written with `focus:` in place of `focus-visible:` (`focus:outline-solid focus:outline-2 focus:outline-offset-2 focus:outline-ring`): after a mouse click, a browser does not match `:focus-visible` on an element that code focuses. A link, a button or a field that code focuses keeps the `focus-visible:` classes it has: after a mouse click it shows no outline, which is how a browser treats every control, and is right. A stock component that ships its own focus ring (`Button`, `buttonVariants`, `Input`, `Textarea`, `Checkbox`, `Switch`, `AccordionTrigger`, the close button of a `Sheet`) must lose that ring. Do it once, in the component's file in `components/ui`, which is yours to change: replace its `focus-visible:ring-*` classes with the outline classes, and in a field replace its `aria-invalid:ring-*` classes, the `dark:` ones included, with `aria-invalid:ring-0`, or a field with an error shows a tinted ring. `Button` has two more sets. Its base classes also carry `aria-invalid:ring-*` classes: replace them with `aria-invalid:ring-0`, as in a field. Its `destructive` variant carries `focus-visible:ring-*` classes of its own, the `dark:` one included: delete them and put nothing in their place, because the base classes already give every variant the outline. Wherever this rule says replace, change the classes in the file and do not add `ring-0` beside them: an added class only wins where it comes later and passes through `cn`. The stock `focus-visible:border-ring` can stay. These ring changes go only into the files of components that this page uses and that can take focus on it: a `Badge` that is not a link keeps its ring classes. The `cn` import from the setup steps is another matter and goes into every file. A box that scrolls sideways (a code block, a wide table) gets `tabIndex={0}`, `role="region"`, an `aria-label` and the same outline, also at widths where it happens to fit. Where a focusable box touches the edges of a parent that has `overflow-hidden`, draw its outline inside it: `focus-visible:-outline-offset-2` in place of `focus-visible:outline-offset-2`.
- **Not allowed:** purple or multi-color gradients; emoji used as icons or bullets; glows and colored shadows.
- **Avoid:** a card inside a card.
- **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. A new shadcn project follows the system's mode and switches on the `d` key: leave that as it is, and add no mode switch of your own. If the page has a native `<select>` or a date or time field, tell the browser the mode, or its list and its picker stay light in dark mode: in the global CSS, give `:root` `color-scheme: light` and `.dark` `color-scheme: dark`.

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

- Do use gold once on a page, and let it mean something. The focus outline and a ticked checkbox do not count.
- Do leave wide margins: an empty column is part of the design.
- Do set names and titles in the heading font and the facts about them in labels.
- Don't set Marcellus in bold or italics: it has neither.
- Don't use gradients, glows or photographs with color casts.
- 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 briefing is inside an `<article>` with one `<h1>`; its four `<h2>` sections each have an `id`, and each link in On this page jumps to its heading.
- [ ] The running text sits in columns 1–7 from `md` up, at most `max-w-xl` wide, with the list of sections in columns 9–12 and the columns between empty; on a phone the list of sections comes before the text.
- [ ] The summary box is the only card in the article, with a pale grey fill, 4px corners and no border or shadow, and the pull quote is set in the heading font, upright, with a 1px rule at its left.
- [ ] The page has exactly one badge, New, and nothing else on the page is `bg-tertiary`; there is exactly one default (navy) button, Discuss this with Ruth.
- [ ] No heading or text on the page is bold or italic, the article names no real case, court ruling, statute or firm, and nothing on the page is round.
- [ ] No color is written as a hex, rgb or Tailwind palette value in the page's code.
- [ ] Every padding, margin and gap in the code you wrote 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.
