Metadata-Version: 2.5
Name: mark-my-word
Version: 0.10.0
Summary: Convert Markdown file to PDF using themes extracted directly from Word templates
Project-URL: Homepage, https://gitlab.com/tastapod/mark-my-word
Project-URL: Repository, https://gitlab.com/tastapod/mark-my-word.git
Project-URL: Issues, https://gitlab.com/tastapod/mark-my-word/-/issues
Author-email: Daniel Terhorst-North <daniel@dannorth.net>
License-Expression: MIT
Keywords: docx,markdown,pdf,theme,weasyprint,word
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: End Users/Desktop
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Topic :: Text Processing :: Markup
Classifier: Topic :: Utilities
Requires-Python: >=3.11
Requires-Dist: click~=8.3
Requires-Dist: markdown~=3.10
Requires-Dist: pymdown-extensions~=12.3
Requires-Dist: python-docx~=1.2
Requires-Dist: python-frontmatter~=1.1
Requires-Dist: pyyaml~=6.0
Requires-Dist: weasyprint~=70.0
Description-Content-Type: text/markdown

# mark-my-word

You have a Word template — the right fonts, colours, headers, footers. You have a Markdown file you want to print. `mark-my-word` connects the two: it reads your Word template and uses it to render your Markdown as a styled PDF.

## Is this for me?

It's a good fit if:

- You have a `.docx` or `.dotx` Word template with the styling you want
- You want your PDFs to match that template without manual CSS work
- You're happy running a command-line tool

It's probably not for you if you need pixel-perfect fidelity to complex Word layouts (tables with merged cells, tracked changes, etc.) or if you need to render Word documents directly — this tool works with Markdown input.

## Install

```shell
uv tool install mark-my-word
# or
pipx install mark-my-word
```

Requires Python 3.11 to 3.15. WeasyPrint (the PDF engine) needs pango, cairo and gdk-pixbuf as system libraries. On Debian or Ubuntu:

```shell
apt-get install libpango-1.0-0 libpangoft2-1.0-0 libcairo2 libgdk-pixbuf-2.0-0
```

On macOS, `brew install pango cairo gdk-pixbuf`. If the install still fails, the [WeasyPrint docs](https://doc.courtbouillon.org/weasyprint/stable/first_steps.html#installation) cover the rest.

## Basic usage

With no template at all, `mark-my-word` renders on Word's own default template, the plain look a new Word document has:

```shell
mark-my-word render document.md --out document.docx
mark-my-word render document.md --out document.pdf
```

It says `Using Word's default template` before it writes the file.

Pass your own Word template and `mark-my-word` does the rest:

```shell
mark-my-word render document.md --template my-template.dotx
```

Output lands next to the input file by default (`document.pdf`). Use `--out` (or `-o`) to put it somewhere else:

```shell
mark-my-word render document.md --template my-template.dotx --out /tmp/document.pdf
```

If the output file already exists, the command refuses rather than silently overwriting. Use `--force` (or `-f`) to overwrite:

```shell
mark-my-word render document.md --template my-template.dotx --force
```

### Or extract the theme separately

If you render from the same template often, extract it once and reuse the theme directory:

```shell
mark-my-word extract my-template.dotx --out themes/my-theme/
mark-my-word render document.md --theme themes/my-theme/
```

The extracted theme is plain CSS and HTML — easy to inspect or tweak. Add `--save-theme themes/my-theme/` to the one-step command if you want to keep the theme without a separate extract step.

### Or install the theme under a name

A theme you use often can be installed once and named, so `--theme` takes a name instead of a path and works from any directory:

```shell
mark-my-word theme install my-template.dotx house-style
mark-my-word render document.md --theme house-style
```

`theme install` takes either a Word template (extracting it) or an existing theme directory (copying it), and names the theme after the source unless you give a name. The copy is a snapshot: edit the original and the installed theme does not change.

For a theme you are still working on, link it instead — the installed name follows your edits:

```shell
mark-my-word theme link ../themes/goalwards
```

The rest of the commands manage what is installed:

```shell
mark-my-word theme list             # names, and where the links point
mark-my-word theme rename OLD NEW
mark-my-word theme remove NAME      # for a link, removes the link only
```

`theme list` also names the template each theme came from, and flags one an older version built:

```text
base  (base.dotx, 0.9.0)
goalwards  (Goalwards.dotx, built by 0.8.1 — current 0.9.0)
handmade
```

That comes from a `mark-my-word.json` file `extract` writes into the theme, recording the template's **filename**, the extraction date, and the version. It holds no path, so a theme you share says nothing about where your templates live. A theme without the file — hand-written, or extracted before 0.9.0 — works exactly the same; the file is a record, not a requirement.

Installing over an existing name fails unless you pass `--force`. Themes live in `$XDG_DATA_HOME/mark-my-word/themes`, or `~/.local/share/mark-my-word/themes` when that is unset.

When `--theme` gets a bare name it looks in the registry first, and says `Using installed theme: NAME` when it finds one. To use a local directory of the same name, write it as a path — `--theme ./goalwards`.

## Document frontmatter

Headers and footers in your theme can include placeholders like `{{title}}` or `{{author}}`. You can also supply a fallback: `{{title: Untitled}}` is used when `title` is not set. Matching is case-insensitive.

Set values in your Markdown file's YAML frontmatter:

```markdown
---
title: Q1 Report
author: Daniel
---

# Introduction

...
```

Pass extra values on the command line with `--set`:

```shell
mark-my-word render document.md --theme themes/my-theme/ --set version=draft
```

## Skipping preamble

If you write notes in an app like NotePlan, there's often metadata at the top — tags, links, app-specific syntax — that you don't want in the PDF. Put `<!--more-->` on its own line to mark where your real content starts:

```markdown
@project(Quarterly Review)
[[linked-note]]

<!--more-->

# Q1 Report

...
```

Everything before `<!--more-->` is ignored. Everything after renders normally. If `<!--more-->` appears inside a code block in the body, put a second one at the top of the document to act as the separator instead.

## Inline markup

Beyond the usual `**bold**` and `*italic*`:

| Syntax | Renders as |
|---|---|
| `~~struck through~~` | struck through |
| `==highlighted==` | highlighted |
| `^superscript^` | the 1^st^ of May |
| `~subscript~` | H~2~O |

Each needs a matching pair with no spaces inside, so an unpaired `~` or `^` in ordinary prose — "about ~30 people", "the 2^32 limit" — is left alone.

HTML entities work too: `Goalwards&trade;` gives Goalwards™. Typing the character directly works just as well.

## Heading anchors and links

Every heading gets an anchor derived from its text, so you can link between sections. The trouble is that the anchor for "Everything you wanted to know about widgets" is `everything-you-wanted-to-know-about-widgets` — correct, and miserable to type into a link.

So name it yourself. Put `{#your-id}` at the end of the heading line:

```markdown
# Everything you wanted to know about widgets {#widgets}

See [the widget section](#widgets) for the details.
```

The link resolves to the heading, and the id holds steady even when you reword the heading text. One catch: the `{#id}` has to sit at the end of the heading line. On its own line above the heading it does not attach — it renders as literal text instead.

The same braces carry CSS classes too, if your theme has a use for them: `# Heading {#widgets .callout}` adds `class="callout"`.

### Table of contents

Put `[TOC]` on its own line and it becomes a linked table of contents, one entry per heading it covers:

```markdown
[TOC]

# Introduction

# Details
```

Newly extracted themes render it as an indented list, each entry followed by a dotted leader and the page its heading lands on. The look is set by the `.toc` rules in your theme's `style.css`; the quickest knobs are `--toc-leader` (the leader: `'.'` dots, `'-'` dashes, `' '` blank, `''` for none) and `--toc-indent` (per-level indent), which you can set in `:root`.

By default the contents lists heading levels 1 to 3, which is what Word's own table of contents covers. Set `toc.levels` in frontmatter to change that — a single number for "up to that level", or a range:

```yaml
---
toc:
  levels: 2-4    # or 3 for H1–H3, or 1-6 for every level
---
```

A single document can override the leader with `toc.leader` (same values as `--toc-leader`) — a one-off flourish without touching the theme. From the command line these are `--set toc.levels=2-4` and `--set toc.leader=-`.

### Numbered headings

If your Word template numbers its heading styles, the extracted theme carries that through — headings render as `1`, `1.1`, `1.1.1`, the decimal outline Word would have shown.

You can also switch numbering on, off, or onto a different range per document with `heading_numbers` in frontmatter:

```yaml
---
heading_numbers:
  levels: 2-4    # number H2–H4; a single number like 3 means H1–H3
  reset: 1       # optional: an H1 restarts the count under each section
---
```

`levels` picks which heading levels are numbered, and its low end is the root of the outline — `2-4` numbers H2 as `1`, `2`, … and leaves H1 as an unnumbered "big heading". Set it to `none` (or `off`/`false`/`0`) to switch a numbered template off for one document.

By default the count runs continuously, so an H1 between sections does not interrupt it. `reset` makes a higher level a section break that restarts the count — `reset: 1` (or `h1`) gives each H1 its own `1`, `2`, …; the reset level must sit above the numbered range. A document setting always wins over the template's own numbering. From the command line: `--set heading_numbers.levels=2-4 --set heading_numbers.reset=1`.

## Footnotes

A footnote renders at the foot of the page it is referenced on. Reference it with `[^label]` and define it anywhere in the document:

```markdown
The claim rests on shaky ground[^pub].

[^pub]: Source: overheard at the pub.
```

The label is yours to name — `pub`, not a number. You reference and define by the same handle, so inserting or removing a footnote never makes you renumber anything by hand. The rendered marker is a plain number, counted in the order the footnotes appear.

A footnote is defined once and referenced once. Defining the same `[^label]` twice is an error — there is no telling which definition you meant — and referencing it twice is too, since one note shared across two places is not supported. Either way, `render` stops and names the label.

## What gets extracted

From your Word template, `mark-my-word extract` pulls:

- Page margins
- Theme colours → CSS custom properties (`--color-body`, `--color-heading`, etc.)
- Body text formatting: font family, size, line height, and paragraph spacing (from the Normal style)
- Heading styles: font size, weight, colour, and spacing for H1–H6
- Header and footer content, including tab-separated left/right layouts, page numbers, and paragraph borders (top and bottom)
- Watermark images

The result is a plain directory you can inspect and edit. The stylesheet uses CSS custom properties throughout, so tweaking colours or fonts is a one-line change.

## Theme directory layout

```
themes/my-theme/
  style.css           required
  header.html         header on all pages (or cont-header.html / first-header.html)
  footer.html         footer on all pages (or cont-footer.html / first-footer.html)
  watermark.png       optional full-page background image
  mark-my-word.json   what extracted it: template filename, date, version
  MyTemplate.dotx     the Word template it was extracted from
```

`extract` copies the template into the theme under its own name, so a theme carries everything it was built from.

If your Word template has a different header on the first page, `extract` writes `first-header.html` and `cont-header.html` separately. `render` handles both layouts automatically.

## Tips for Word templates

### Left/right footer layouts

For a footer with content on the left and right (e.g. company name on the left, page number on the right), use a **single paragraph with a right-aligned tab stop** rather than a table:

1. In your footer, type the left content
2. Press Tab
3. Type the right content
4. Set a right-aligned tab stop at the right margin (Format → Tabs, or drag the tab marker in the ruler)

`mark-my-word` converts the tab character into a flex-row layout. Tables work too, but they carry implicit cell spacing that doesn't always translate cleanly.

### Horizontal rules

To draw a decorative line above or below footer content, add a paragraph border (Format → Borders and Shading → Borders tab) rather than an actual horizontal rule or a separate table row. Paragraph top and bottom borders are extracted and rendered faithfully.

## Options

```
mark-my-word render --help
mark-my-word extract --help
mark-my-word theme --help
```

## Changelog

### 0.10.0

- A blank line between list items shows as a gap in both formats, after the whole item, nested lists included. The PDF used to put it after the item's own text, before the nested list, and Word showed none at all.

- Task lists render. `- [x] done` and `- [ ] open` draw a ticked or an empty box in place of the bullet, in the PDF as ☑ and ☐ and in Word as the Wingdings checkbox bullets Word's own gallery uses. Nested tasks keep their depth.

- **Fixed: bullets nested under a numbered item sat left of the number in Word.** Word's default template defines its bullet chain with one level, so a nested bullet had no definition and no indent. A template chain short of Word's nine levels now gets the missing ones, each stepping in by the first level's indent with Word's usual glyph for that depth.

- **Breaking:** a numbered list in Word takes the template's own `List Number` chain where it has one, filled to nine levels the same way, and the appended decimal definition only where it has none. Every list in a document then sits on one scale, the template's, so a bullet or a checkbox nested under a number steps in from the number's text as Word's own lists do, and the Word indents match the PDF's.

- Inline code no longer carries 3pt of padding either side, which put a visible gap between `` `code` `` and the full stop after it. Nothing in a Word template asks for it. Re-extract to pick this up.

- **Breaking:** a link takes the template's hyperlink colour, the theme's `hlink` slot, where it used to take the third accent. The circus templates set both to the same teal, so their PDFs are unchanged; Word's default template draws links blue where the accent is green. Re-extract to pick this up.

- A render on `--template`, or on Word's default template, no longer prints the `wrote style.css` lines and the temporary directory of the theme it extracts on the way. Those lines still print for `extract` and for `--save-theme`, where the theme is kept.

- A missing image is named and left out, in both formats. `![photo](shots/photo.jpg)` with no such file used to stop the Word writer with a traceback and leave a silent gap in the PDF; both now print `image not found, left out: shots/photo.jpg` before the `Written:` line, once per file, and carry on.

- **Fixed: an image wider than the page.** Neither output ever sized an image, so a 3000-pixel photograph ran off the right edge of the PDF and came into Word at 42 inches, pushing whatever came before it onto a page of its own. An image wider than nine tenths of the measure now shrinks to that, keeping its ratio, in both formats, and an image on a line of its own sits centred. An image that already fits is left at its size. Re-extract to pick this up.

- A NotePlan width suffix in an image's alt text, the `|100%` in `![image|100%](photo.jpg)`, is dropped from the alt text in both formats.

- `render` works without a theme. Given neither `--theme` nor `--template`, it renders on the blank template python-docx bundles, which carries Word's default styles, to Word or to PDF, and says `Using Word's default template`. `--save-theme` still needs `--template`.

- Runs on Python 3.14 and 3.15, and says so in its metadata. The suite segfaulted on 3.15 under cffi 2.0, which predates that Python; the lockfile now carries cffi 2.1, WeasyPrint 70 and pymdown-extensions 12, and CI runs on every version from 3.11 to 3.15.

- **Fixed: a line break wherever the Markdown source wraps.** Word output broke every paragraph at each newline in the source, so a document hard-wrapped at 80 columns came out ragged, and a PDF footnote did the same. A newline inside a paragraph is a space, as Markdown reads it, and a hard break written as two trailing spaces is the one line break Word output carries.

- A placeholder a theme cannot fill now says so. `{{author}}` in a template, with nothing setting an author, raised a bare `KeyError` and printed a traceback; it now names the placeholder and says how to fill it — frontmatter, `--set`, or a default written as `{{author: ...}}`. Both output formats.

- `render` to Word says what it could not carry. A horizontal rule and a raw HTML block are left out of the document, an `attr_list` class has nowhere to go, and a style the template does not define gets written into the document — each of those prints a line before the `Written:` line, once per kind.

- Word output fills in the `{{title}}`-style placeholders the template carries in its own header and footer. A template asking for `{{title}}` used to put a literal `{{title}}` in front of whoever opened the document; it now gets the frontmatter value, by the same rules the PDF follows. `{{name: default}}` falls back to the default, and a name with neither a value nor a default is an error.

- The source distribution carries the package and nothing else. It used to ship the test suite, the example templates and their extracted themes — about 300KB of Word binaries — which no one installing the package ever runs. Clone the repository to run the tests. The wheel is unchanged, and never held them.

- **Breaking:** the page's bottom margin comes from the template. It used to be synthesised from the footer's height plus an 8pt gap invented here, which discarded whatever the template asked for — a template saying 25.4mm got 21.8mm. Now the template's own bottom margin stands, the footer sits inside it at the template's footer distance the way Word places it, and only a footer too tall to fit pushes the body up. The `--footer-gap` token is gone. Re-extract to pick this up.

- Word output carries lists, footnotes and a table of contents. A bulleted list takes the numbering definition the template's `List Bullet` style uses, or its first bullet definition where that style has none, and a numbered list takes a decimal definition written into the document, each nested to the depth you wrote. A template shipping no numbering part gets one built. A footnote becomes a real Word footnote in the footnotes part rather than text in the body. `[TOC]` becomes a `TOC` field, so Word regenerates the contents itself and the page numbers are Word's — it shows empty until you refresh the field, which is what Word does with a field it has not been asked to update.

- **Fixed: an ordered list written straight after a bulleted list renders as numbers.** Python-Markdown absorbs the second list into the first when only a blank line separates them, so the numbered items came out as bullets. Both output formats get the two lists separately.

- **Breaking:** `[TOC]` lists heading levels 1 to 3 by default, where it used to list every level. Word's own table of contents covers 1 to 3, so one source rendered to both formats gets the same contents. A document that wants the deeper entries back sets `toc.levels: 1-6`.

- **Breaking:** the space around the body and the first-page header comes from the template. The body carried 10pt of padding and the first-page header 8pt above and 18pt below, all three chosen by eye. Word puts its header at the section's header distance and starts the body at the top margin, so that is what the theme does now: the first page's top margin is the header distance, and the flowed header takes its space out of the top margin, with `--space-after-first-header` holding whatever is left of it. A tall first-page header pushes the body down the page rather than overlapping it. The footer's height, which sets the bottom margin, is measured from the `Footer` style's own size instead of an assumed 9pt, so a template with an 8pt footer gets a shallower bottom margin and one with a 12pt footer a deeper one. Re-extract to pick this up.

- **Breaking:** the footnote separator comes from the template. Every theme used to rule off its footnotes with a full-width 0.5pt line; now a template whose footnotes part defines the `separator` footnote gets one, and a template whose footnotes part leaves it out gets none. A template with no footnotes part at all, Word's default among them, gets one, because Word output builds that part with a separator. Word says only that it draws a separator, so its weight is the theme's, as `--footnote-separator-weight`. Word draws its own across about a third of the measure; ours runs the full width, because nothing WeasyPrint paints on a footnote area draws a part-width line. Re-extract to pick this up.

- **Breaking:** lists take their indent and their spacing from the template. The generated stylesheet used to indent every list 20pt, leave 14pt under one and 4pt under each item, whatever the template said. The indent now comes from the template's numbering — the abstract definition the `List Bullet` style numbers with for `ul`, and `List Number`'s for `ol`, or where the template has no such style, the first definition whose level 0 is a bullet, or decimal — and a level whose step differs from the one above it gets a rule of its own. The spacing comes from the `List Paragraph` style: a style carrying `w:contextualSpacing`, as Word's own does, leaves no gap between items and none where a nested list ends, and the space below a whole list is that style's own space after. A template with no numbering part keeps the 20pt indent, as the `--list-indent` token. Re-extract to pick this up.

- A run and a named paragraph style keep the character spacing and kerning Word sets. A `Title` that tightens its letters by half a point and a `Subtitle` that opens them by three quarters both used to render at the font's natural spacing, which left a 14pt subtitle looking cramped beside Word's. `w:spacing` becomes `letter-spacing`. `w:kern` names the size at or above which Word kerns, and CSS has only kerning on or off, so a style whose own size reaches that threshold emits `font-kerning: normal` and one below it `none`. Re-extract to pick this up.
- A named paragraph style's bold is extracted alongside its italic, so a template whose `Header` style is bold renders bold. Re-extract to pick this up.

- **Breaking:** a document's first `# Heading` stays where you wrote it. Until now, a document with no `title:` in its frontmatter had its first H1 taken as the title and deleted from the body — convenient once and surprising thereafter, and it meant the same Markdown produced a title in the PDF's header and a heading in a Word document's body. Set `title:` in frontmatter for a header title; the filename stem is still the fallback when nothing sets one.

- Code takes the font and size of the template's own code style, looked up under the names templates use: `Source Code` and `Verbatim Char` (pandoc's), `HTML Preformatted`, `HTML Code`, `Macro Text` and `Plain Text` (Word's), and `Code`, `Code Block` and `Preformatted Text`. Where a template names none, `--font-size-code` sits a point under the body size, because a monospace face reads larger than a proportional one at the same size. The docx writer looks for the same names, taking a paragraph style for a fenced block and a character style for inline code. Re-extract to pick this up.
- **Breaking:** a table header row takes its styling from the template's default table style, read from that style's `firstRow` conditional format — its font, colour, shading, alignment and bottom border. The generated stylesheet used to colour every `th` in the heading colour, embolden it, align it left and rule it off with a 1pt border, whatever the template said. A template that styles no header row now gets no `th` rule at all, so its header cells look like its body cells. The circus example gained a `Circus Table` style, so the examples exercise the path. Re-extract to pick this up, or keep the old `th` rule in your theme's `style.css` by hand.
- Tables and code take the body font size instead of the 10pt and 11pt the generated stylesheet used to impose. The monospace stack is now the `--font-mono` token, so a theme can change it in one place. Re-extract to pick this up.

- **Breaking:** the template's `Header`, `Footer` and `Quote` styles are extracted, and the generated stylesheet no longer states a size, a colour or an alignment of its own for headers, footers and blockquotes. Running headers and footers used to be forced to 9pt in the footer colour, and a blockquote to italic at three-quarters opacity behind a 3pt bar, whatever the template said. Where a Word style is silent the text inherits, as it does in Word. Re-extract to pick this up.

- **Breaking:** a named paragraph style renders only the properties the Word style sets. `.para-title` and `.para-subtitle` used to carry a size, a heading colour and an alignment the tool chose — a centred title and a left-aligned subtitle — whatever the template said. Alignment now comes from the style's own `w:jc`, and a style that sets nothing at all gets no rule. Centre your `Title` style in Word to keep a centred title. Re-extract to pick this up.

- The generated stylesheet no longer carries `.header-title` and `.header-subtitle`. Nothing has emitted those classes since the first-page header started using the template's own styles. Re-extract to drop them from your theme.

- Header and footer text keeps the font size and typeface its Word runs set. `extract` read only bold, italic and colour from a run, so a 10pt header line and an 8pt footer line both came out at the 9pt the generated stylesheet imposes. A run that switches bold or italic off now renders plain, where before any `w:b` at all made it bold. Re-extract to pick this up.

- `^superscript^` and `~subscript~` render, alongside the existing `~~strikethrough~~`. Both need a matching pair with no spaces inside, so an unpaired `~` or `^` in prose is untouched.

- A template's `Subtitle` style is now extracted and rendered like `Title`, as `.para-subtitle`, including its italic. A first-page header carrying `{{title}}` and `{{subtitle}}` renders both from the template's own styling.
- The first-page header no longer jams its paragraphs together. Its `p` reset was written when that header was a single line; it now keeps a gap between paragraphs and clears the body below. Running headers and footers stay tight, as before. Re-extract to pick this up.

- The first page no longer shows the continuation header in its top margin. Since 0.9.0 the first-page header flows at the top of the body rather than sitting in a margin box, but `@page :first` never stopped the running header filling that box, so a document with a distinct first page printed both. Re-extract to pick this up.

- **Breaking:** the rule under a running header now comes from the template, not from the tool. Extracted themes used to carry a hardcoded `border-bottom` on `.header-cont`, so every PDF got a separator whether or not the Word template had one. A template that draws its own rule — a paragraph border on the header text, or an empty bordered paragraph, both of which `extract` already reads — still gets one; a template with none now renders none. Re-extract to pick this up, or add the `border-bottom` back to your theme's `style.css` by hand.

- `==highlighted text==` renders as highlighted text. Themes style it through a new `--color-highlight` token, which defaults to a soft yellow — Word highlights per run rather than per theme, so there is nothing in a template to extract it from. Re-extract a theme to pick up the token and the `mark` rule.

- **Breaking:** a code block no longer carries a grey bar down its left edge. Nothing in a Word template asks for one, so the `pre` border and the `--color-code-bar` token are gone. Add the border back to your theme's `style.css` by hand if you want it. Re-extract to pick this up.

- **Fixed: a blank line under the first-page title.** The title's container was a flex column, and WeasyPrint gives a child of one a block box twice its line height. The container is an ordinary block, its paragraphs stack in normal flow, and the first-page header of the circus example is a third shorter. Re-extract to pick this up.

### 0.9.1

- Every help screen ends with the version, not just the top-level one — `render --help`, `extract --help`, `theme --help`, and each `theme` subcommand.
- The source distribution no longer carries the repository internals. `[tool.hatchling.build]` was a misspelling of `[tool.hatch.build]`, so the setting was ignored and the sdist packaged the whole working directory — including nearly a thousand files from `.jj/`. The sdist now ships an explicit list: source, tests, docs, examples, and scripts. The wheel is unaffected.

### 0.9.0

- Themes can be installed under a name: `theme install` copies a theme (or extracts a Word template) into `~/.local/share/mark-my-word/themes`, `theme link` points at a directory you are still editing, and `theme list`/`rename`/`remove` manage what is there. `--theme NAME` then works from any directory, and says `Using installed theme: NAME` when it resolves one. A bare name means an installed theme; write `./name` for a directory.
- `extract` now writes a `mark-my-word.json` record into the theme — the template's filename, the date, and the version that built it, with no path in it. `theme list` shows the template and flags a theme an older version built, so you can see which themes want re-extracting.
- **Fixed: extracted themes now take their colours from the Word template.** Theme colour extraction never worked — the parser reached for a `_element` the theme part does not have, and an over-broad `except` swallowed the error, so every theme silently got the built-in default palette. Re-extract your themes to pick up their real colours.
- **Fixed: a heading using Word's "automatic" colour produced invalid CSS.** The generated stylesheet contained `color: #NONE;` for that heading level, so it fell back to the browser default rather than the theme colour. Such a heading now inherits the theme heading colour, as it always should have.

### 0.8.1

- The flowed first-page title (0.8.0) started at the body top margin, leaving a large gap above it. `extract` now sets the first page's top margin to the Word template's header distance, so the title sits where the header used to. Re-extract your theme to pick this up.
- `mark-my-word --help` (and the bare command) now shows the version.

### 0.8.0

- **Breaking:** the first-page title now flows at the top of the body instead of sitting in a fixed-height page margin box. A title that wraps to two lines no longer clips off the top of the page — the header grows and pushes the body down. Re-extract your theme to pick this up; the change is in the generated `style.css` (`.header-first` loses `position: running`, and `@page :first` no longer reserves a header margin box).

### 0.7.0

- **Breaking:** the output flag is `--out` (short `-o`) on both subcommands. `extract`'s `--output` is gone; `render` keeps `--out` but drops the old `--output` alias.

### 0.6.1

- CLI errors are now consistent and actionable. Running with no command, a mistyped path, or a contradictory set of flags fails with a usage line and a message that names the fix — not a stray "no such command" or a stack trace. A `--theme` directory must now exist and contain a `style.css`.

### 0.6.0

- Numbered headings. A Word template with numbered heading styles now carries the numbering through to the PDF (`1`, `1.1`, `1.1.1`). `heading_numbers.levels` in frontmatter opts in, overrides the range, or switches it off per document, and `heading_numbers.reset` restarts the count at a section-break level. See [Numbered headings](#numbered-headings).
- **Breaking:** the table-of-contents settings moved under a `toc` mapping — `toc.levels` and `toc.leader`, where they were `toc_levels` and `toc_leader`. Nested settings reach the command line through dotted keys, e.g. `--set toc.levels=2-4`.

### 0.5.0

- The `[TOC]` table of contents now shows the page each heading lands on, with a dotted leader between title and number. `toc_levels` in frontmatter limits which heading levels it lists (`3` for H1–H3, or a range like `2-4`), and `toc_leader` overrides the leader character per document.

### 0.4.0

- Footnotes: `[^label]` references render at the foot of the page they appear on, with named labels you never renumber by hand and CSS-counted numbers. Reusing a label is an error.

### 0.3.0

- Headings can carry a hand-picked anchor — `# Long heading {#short}` — so you can link to `#short` instead of the auto-generated slug. The same `{...}` syntax also sets CSS classes and other attributes.
- `[TOC]` on its own line expands into a linked table of contents. Newly extracted themes style it as a plain indented list.
- The Markdown engine moved from markdown2 to Python-Markdown — this is what makes the anchor and table-of-contents support possible. Existing documents render unchanged.

### 0.2.3

- More style properties are now extracted from the Word template and applied to the PDF: body text font size, line height, and paragraph spacing (from the Normal style) join heading size, weight, colour, and spacing (H1–H6) as template-driven values rather than hardcoded defaults
- Internal cleanup: removed unused helper functions

### 0.2.2

- README updated with 0.2.1 changes (should have shipped with the release)

### 0.2.1

- Paragraph borders (top and bottom) in Word headers and footers are now extracted and rendered with correct spacing
- Empty paragraphs used as horizontal rules extract at natural line height, matching Word's visual spacing
- Footer height estimation fixed: `<p>` elements inside flex-row cells are no longer counted as separate lines, preventing over-large body margins
- Page break orphan/widow protection relaxed from 3 lines to 2

### 0.2.0

- First-page header/footer fallback: if no distinct first-page fragments exist, the running header/footer is used on all pages
- `<!--more-->` preamble separator support
- `{{variable: default}}` syntax for fragment placeholders
- H1 extracted as document title and removed from body when no `title:` frontmatter is set
- `--force` flag to overwrite existing output files
- Watermark extraction from Word VML `<w:pict>` elements

## Links

- [Repository](https://gitlab.com/tastapod/mark-my-word)
- [Issue tracker](https://gitlab.com/tastapod/mark-my-word/-/issues)
