# Roboto Studio report guidelines

Roboto-branded documents: reports, audits, proposals, contracts, and SEO write-ups delivered as a single HTML file and printed to PDF. The globals are in [design.md](https://robotostudio.com/design.md). The system lives at [github.com/robotostudio/report](https://github.com/robotostudio/report) and matches proposals.robotostudio.com.

## The system

One template, one stylesheet, one script. No build step, dependencies, frameworks, or inline styles beyond the documented `--cols` and `data-*` knobs.

- `reports/_template.html` holds every component. Copy it to `reports/<slug>.html`, replace everything between the `===== Content` and `===== End content` markers, delete unused components, and set the `<title>` and the header's `.meta` line (who it's for, the date). Leave the frame alone.
- `report.css` is the whole visual system. `report.js` renders charts, the table of contents, timeline rulers, and the theme toggle from data attributes, so a document is plain HTML.
- `scripts/pdf.sh reports/<slug>.html` prints `reports/<slug>.pdf` beside it with headless Chrome. Read the PDF back before handing it over.
- Anything new goes into the stylesheet, the script, and the template so the next document gets it.

## Tokens

Zinc in oklch: light by default, dark through `prefers-color-scheme` or `data-theme="dark"`, forced light in print.

| Token | Light | Dark |
|---|---|---|
| `--bg` | `#FFFFFF` | `#141414` |
| `--fg` | `oklch(0.141 0.005 285.823)` | `oklch(0.985 0 0)` |
| `--card` | `#FFFFFF` | `oklch(0.21 0.006 285.885)` |
| `--muted` | `oklch(0.967 0.001 286.375)` | `oklch(0.274 0.006 286.033)` |
| `--muted-fg` | `oklch(0.552 0.016 285.938)` | `oklch(0.705 0.015 286.067)` |
| `--border` | `oklch(0.92 0.004 286.32)` | `oklch(1 0 0 / 10%)` |
| `--line` | `#E4E4E7` | `#27272A` |
| `--primary` | `oklch(0.21 0.006 285.885)` | `oklch(0.92 0.004 286.32)` |
| `--good` | `oklch(0.6 0.13 155)` | `oklch(0.72 0.15 155)` |
| `--bad` | `oklch(0.577 0.245 27.325)` | `oklch(0.704 0.191 22.216)` |

- Geist and Geist Mono from Google Fonts (sans 400, 500, 600; mono 400, 500).
- `border-radius: 0 !important` on every element.
- Headings at weight 400; `strong` is 500.
- Body text is the foreground at 90% (`--body`), 16px over a 28px line. Print drops the root size to 12.5px.
- `--good` and `--bad` appear only on deltas and severity badges.
- Mono uppercase 10px labels (`.eyebrow`, `.label`) for metadata.

## Frame

- Hairline rails run the full height on both sides of an 80rem column, with a rule across the top and bottom.
- The header bar is 4rem tall: the wordmark (182 by 18px, in `currentColor`) in a 215px cell on the left, a mono 10px uppercase meta line ("Prepared for Example Ltd · 9 October 2026") and the theme toggle on the right.
- Content is a single `article.prose` column with a 3rem gap to an 18rem sticky table of contents from 1280px. The TOC builds itself from `h2` and `h3`, numbers the `h2`s `01`, `02`, and so on, and tracks the active section on scroll.

## Prose scale

| Element | Size |
|---|---|
| `h1` | 1.875rem, line height 1.111 |
| `p.lead` | 1.25em, muted standfirst under the title |
| `h2` | 1.5em, 2em above, 1em below |
| `h3` | 1.25em |
| `h4` | 1em |
| body | 1rem over 1.75rem |
| `figcaption` | 0.75rem, muted |

Links are foreground at weight 500 with a dotted underline (solid in print). Inline code and `pre` blocks sit in a 1px bordered muted box, `pre` at 0.8125em. Tables are a bordered card with a muted weight-600 header row and cell borders in the border token; `class="num"` right-aligns a cell with tabular figures. Wrap wide tables in `.table-scroll`.

## Components

All of these are in the template. Copy the markup from there.

| Need | Markup |
| --- | --- |
| Title + standfirst | `<h1>` then `<p class="lead">` |
| Sections | `<h2>` / `<h3>`. The TOC builds itself from these and numbers the h2s. |
| KPI tiles | `<div class="stats not-prose" style="--cols: 4">` of `.stat` (`.label`, `.value`, `.delta` + `.up`/`.down`) |
| Area chart | `<figure data-chart="area" data-points='[["Jan",120],...]'>` |
| Multi-series line | `<figure data-chart="line" data-points='{"labels":[...],"series":[{"name":"A","values":[...]}]}'>` |
| Ranked bars | `<figure data-chart="bar" data-points='[["/page",9800],...]'>` |
| Chart options | `data-title`, `data-caption`, `data-highlight="Label,Label"`, `data-prefix="$"`, `data-suffix="%"`, `data-max`, `data-x-labels` |
| Table | plain `<table>` in `<div class="table-scroll">`; `class="num"` on numeric cells right-aligns them |
| Callout | `<div class="callout">` (`.warn`, `.danger`) with optional `<span class="title">` |
| Cards | `<div class="cards not-prose" style="--cols: 3">` of `.card` (`.eyebrow`, `.title`, `<p>`, `.foot`) |
| Timeline | `<ol class="timeline not-prose">` of `<li data-weeks="2">` each holding a `.card`; `.checkpoint` for client actions or payments |
| Badge | `<span class="badge">` (`.secondary`, `.outline`, `.good`, `.bad`) |
| Two columns | `<div class="split">` |
| Signatures | `.signatures` block (contracts only) |
| PDF control | `.page-break` starts a new page, `.avoid-break` keeps a block together, `.no-print` hides from PDF |

How they look:

- KPI tiles are a hairline grid with 1px `--line` gaps, each tile on the page background with a mono 10px uppercase label, a 1.875rem tabular value, and a 0.75rem delta. Two columns on narrow screens; `--cols` (2, 3, or 4) from 768px and in print.
- Callouts are 0.875rem bordered boxes with a 2px foreground left edge. `.warn` is a dashed amber border on an amber wash; `.danger` turns the left edge red.
- Cards are 1px bordered boxes with a mono eyebrow, a 1rem weight-500 title, muted body text, and a `.foot` pinned to the bottom under a rule.
- Timelines give each `<li>` 296px per week. The script draws a week ruler above every milestone card, a "wk N" label with seven ticks per week. A `.checkpoint` line (6px square bullet) marks client actions or payments.
- Badges fill with `--primary`; `.secondary` is muted, `.outline` bordered, `.good` and `.bad` outlined in their own color.

## Charts

Monochrome on purpose. Everything draws in `currentColor`, so one chart survives the theme toggle and print. The site's series palette in [charts.md](https://robotostudio.com/design/charts.md) is not for documents.

- Series are told apart by dash pattern, in order: solid, `6 4`, `2 3`, `10 3 2 3`. Series after the first draw at 70% opacity. `data-highlight` dots and labels the named points (area and line) or dims every other bar to 35%.
- Area and line charts render in a 760 by 300 viewBox with 20, 14, 30, and 46px padding (top, right, bottom, left), four gridlines at 18% opacity (baseline plus three), a Y maximum rounded up to a clean step, and about six X labels (`data-x-labels` changes the count). The area fill is 8%.
- Bars are horizontal: a label column up to 14rem, a muted track, a foreground fill, and a mono right-aligned value. Use them for ranked lists (pages, keywords, competitors).
- Values compact to `1.2k` and `3.4m`; `data-prefix` and `data-suffix` wrap them. A legend appears only with two or more series, as 20px line samples in each series' dash.

## Print

- A4, zero page margin. The frame (rails and rules) repeats on every page, inset 8mm from the paper edge; article text sits a further 8mm in.
- The root size drops to 12.5px; the sidebar, buttons, and `.no-print` elements vanish; the theme is forced light with exact color printing.
- Headings never end a page. Tables, stats, cards, charts, callouts, figures, and signature blocks never split. A timeline of six weeks or fewer fits on one row; longer ones stack.
- A contract's signature page starts with `.page-break`.

## Writing rules

British dry, understated, half the words you think you need.

- Sentence case everywhere. No title case.
- No em dashes. Use commas, parentheses, semicolons, colons, or `-`.
- No negative parallelism ("X isn't Y. It's Z."). Lead with the concrete claim.
- Lead each section and bullet with the claim or number; context after, only if it earns its place.
- Cut filler: "robust", "seamless", "comprehensive", "elevate", "unlock", "empower", "in today's digital landscape".
- Don't summarise what you just said.
- Every number states its source and date range somewhere in the report.
