# Content formatting

Use HTML only in the `content` field of `text` and `fill-text`. Multiple-choice labels, student-field labels, IDs, and distractor words are plain text.

## HTML

The renderer sanitizes HTML before inserting it into the document. Prefer a small semantic subset:

- Headings: `h1`, `h2`, `h3`
- Text: `p`, `strong`, `em`, `br`
- Lists: `ul`, `ol`, `li`
- Scientific notation: `sup`, `sub`

```html
<h1>Earth science</h1>
<p><strong>Instructions:</strong> answer every question.</p>
<ol>
  <li>Read the prompt.</li>
  <li>Show your work.</li>
</ol>
```

Do not use scripts, styles, forms, iframes, embedded objects, event handlers, or external resources. They are outside the print contract and can be removed.

## Fill-in-the-blank markers

Wrap each answer in double braces. The renderer replaces it with a blank sized from the answer.

```html
<p>The capital of Italy is {{Rome}}.</p>
```

Use `data-fill-blank` when the answer needs inline formatting:

```html
<p>Water freezes at <strong data-fill-blank>0°C</strong>.</p>
```

Answer markers belong only in a `fill-text` block. Do not use that block without at least one marker.

## Word banks

Set `wordBank` to `true` to print the unique answers and `distractorWords` in a shuffled word bank.

```json
{
  "id": "q1-fill",
  "type": "fill-text",
  "content": "<p>Ice is {{solid}} water.</p>",
  "wordBank": true,
  "distractorWords": ["liquid", "gas"]
}
```

The shuffle happens when the document renders, so word order is not stable between renders.

## Math

Math blocks accept KaTeX-compatible LaTeX in display mode.

```json
{
  "id": "q2-math",
  "type": "math",
  "content": "\\frac{-b \\pm \\sqrt{b^2 - 4ac}}{2a}",
  "alignment": "center"
}
```

Do not wrap math in `$`, `$$`, Markdown fences, or HTML. Invalid commands are shown as a rendering error instead of executable content.

## User-provided text

Preserve the user's wording. Escape untrusted values before interpolating them into HTML, and never place untrusted text inside an HTML attribute.
