diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 82bdedf..a532b27 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,6 +13,8 @@ permissions:
contents: write
pull-requests: write
security-events: write
+ pages: write
+ id-token: write
jobs:
build:
@@ -289,3 +291,49 @@ jobs:
--notes "Pre-release from \`${{ github.head_ref }}\` branch." \
--prerelease \
./artifacts/*.nupkg
+
+ docs:
+ needs: release
+ runs-on: ubuntu-latest
+ if: github.ref == 'refs/heads/master' && github.event_name == 'push'
+
+ steps:
+ - uses: actions/checkout@v4
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: |
+ 8.0.x
+ 9.0.x
+ 10.0.x
+
+ - name: Install DocFX
+ run: dotnet tool install -g docfx
+
+ - name: Restore
+ run: dotnet restore
+
+ - name: Build site
+ run: docfx docs/docfx.json
+
+ - name: Upload Pages artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: docs/_site
+
+ docs-deploy:
+ needs: docs
+ runs-on: ubuntu-latest
+ if: github.ref == 'refs/heads/master' && github.event_name == 'push'
+ concurrency:
+ group: pages
+ cancel-in-progress: false
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+
+ steps:
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.gitignore b/.gitignore
index 0372e5e..114a306 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,7 @@ obj
/_NCrunch*/*.cache
/*.ncrunchsolution.user
/.claude/settings.local.json
+
+# DocFX generated output
+/docs/_site/
+/docs/api/
diff --git a/README.md b/README.md
index 6f95b9e..16b6509 100644
--- a/README.md
+++ b/README.md
@@ -4,3 +4,9 @@
[](https://www.nuget.org/packages/Tharga.Reporter)

[](LICENSE)
+
+**Docs:** [reporter.tharga.net](https://reporter.tharga.net) — guides and API reference.
+
+A .NET library for building and rendering PDF documents from declarative templates. Define a `Template` of `Section`s with text, images, barcodes, lines, rectangles, and tables, feed it data, and render to a PDF byte array.
+
+Supports .NET 8, .NET 9, and .NET 10. Windows-only at runtime.
diff --git a/Tharga.Reporter/Tharga.Reporter.csproj b/Tharga.Reporter/Tharga.Reporter.csproj
index f1a14d4..d67b2f1 100644
--- a/Tharga.Reporter/Tharga.Reporter.csproj
+++ b/Tharga.Reporter/Tharga.Reporter.csproj
@@ -7,7 +7,7 @@
Thargelion ABTharga ReporterTharga Reporter generates PDF and prints pdf-documents and send then m diretly to the printer.
- http://thargelion.se/wp-content/uploads/2019/11/Thargelion-White-Icon-150.png
+ https://thargelion.net/assets/component-reporter.pngTruehttps://github.com/Tharga/ReporterREADME.md
diff --git a/docs/CNAME b/docs/CNAME
new file mode 100644
index 0000000..78f1b41
--- /dev/null
+++ b/docs/CNAME
@@ -0,0 +1 @@
+reporter.tharga.net
diff --git a/docs/articles/data-and-rendering.md b/docs/articles/data-and-rendering.md
new file mode 100644
index 0000000..f443f8c
--- /dev/null
+++ b/docs/articles/data-and-rendering.md
@@ -0,0 +1,176 @@
+# Data and rendering
+
+A template is just the layout. The actual values — invoice number, customer name, line items — come from a `DocumentData` instance passed to the `Renderer`. This page covers the data model, the `Renderer`, and the available page formats.
+
+## DocumentData
+
+Build a `DocumentData` and add key/value pairs:
+
+```csharp
+var data = new DocumentData();
+data.Add("InvoiceNumber", "INV-00042");
+data.Add("CustomerName", "Bob Lablow");
+```
+
+Any text element whose `Value` contains `{Key}` tokens will have those tokens replaced at render time:
+
+```csharp
+section.Pane.ElementList.Add(new Text { Value = "Invoice {InvoiceNumber}" });
+// renders as: "Invoice INV-00042"
+```
+
+Pass the data to the `Renderer`:
+
+```csharp
+var pdf = new Renderer(template, data).GetPdfBinary(PageSize.A4);
+```
+
+If a placeholder references an unknown key, it renders empty. Use `Text.HideValue` to suppress an entire element when a particular key is empty.
+
+## Built-in placeholders
+
+The renderer fills these automatically — you don't need to add them to `DocumentData`:
+
+| Token | Resolves to |
+|---|---|
+| `{Page}` | Current page number |
+| `{TotalPages}` | Total pages in the document |
+| `{Section}` | Current section name |
+
+So `"Page {Page} of {TotalPages}"` produces `"Page 1 of 3"`.
+
+## Table data
+
+For `Table` elements, add a `DocumentDataTable` with the same name as the table's `DataTableName`:
+
+```csharp
+var lines = new DocumentDataTable("InvoiceLines");
+lines.Rows.Add(new DocumentDataTableData(new Dictionary
+{
+ { "Item", "Widget" }, { "Qty", "2" }, { "Price", "10.00" }
+}));
+lines.Rows.Add(new DocumentDataTableData(new Dictionary
+{
+ { "Item", "Gadget" }, { "Qty", "1" }, { "Price", "25.00" }
+}));
+
+var data = new DocumentData();
+data.Add(lines);
+```
+
+Each `DocumentDataTableData` becomes a row; the dictionary keys must match the `ColumnName` on each `TableColumn` you defined.
+
+For visual grouping, use `DocumentDataTableGroup` between data rows — it renders as a styled separator with its `Content` as the label.
+
+## Renderer
+
+The `Renderer` takes a `Template` plus the optional knobs:
+
+```csharp
+var renderer = new Renderer(
+ template,
+ documentData: data,
+ includeBackgroundObjects: true,
+ documentProperties: properties,
+ debug: false
+);
+
+byte[] pdf = renderer.GetPdfBinary(PageSize.A4);
+```
+
+- **`documentData`** — placeholder + table data. `null` for templates with no placeholders.
+- **`includeBackgroundObjects`** — set `false` to omit elements marked `IsBackground = true`. Useful when the foreground is rendered onto pre-printed paper.
+- **`documentProperties`** — fills the PDF metadata: `Author`, `Title`, `Subject`, `Creator`.
+- **`debug`** — draws guides for element bounds, reference points, and the page grid. Off for production.
+
+## DocumentProperties
+
+PDF metadata seen by the reader:
+
+```csharp
+var props = new DocumentProperties
+{
+ Title = "Invoice INV-00042",
+ Author = "Acme Corp",
+ Subject = "Customer invoice",
+ Creator = "MyApp 1.2.0"
+};
+```
+
+## PageFormat
+
+`PageFormat` accepts the PdfSharp `PageSize` enum directly (implicit conversion):
+
+```csharp
+renderer.GetPdfBinary(PageSize.A4);
+renderer.GetPdfBinary(PageSize.Letter);
+renderer.GetPdfBinary(PageSize.A5);
+```
+
+For a custom size, pass millimetres:
+
+```csharp
+renderer.GetPdfBinary(new PageFormat(customWidth: 100, customHeight: 150));
+```
+
+There's also a built-in `PlasticCard` (85x54mm):
+
+```csharp
+renderer.GetPdfBinary(PageFormat.PlasticCard);
+```
+
+## End-to-end example
+
+A two-page invoice with a header, body table, footer page numbers, and metadata:
+
+```csharp
+using PdfSharp;
+using Tharga.Reporter;
+using Tharga.Reporter.Entity;
+using Tharga.Reporter.Entity.Element;
+
+var section = new Section
+{
+ Margin = new UnitRectangle { Left = "1cm", Top = "2cm", Right = "1cm", Bottom = "2cm" }
+};
+
+section.Header.Height = "2cm";
+section.Header.ElementList.Add(new Text { Value = "Invoice {InvoiceNumber}", FontSize = "18pt" });
+
+var table = new Table
+{
+ Width = "100%",
+ DataTableName = "Lines",
+ Columns =
+ {
+ new TableColumn { Title = "Item", ColumnName = "Item", Width = "60%" },
+ new TableColumn { Title = "Qty", ColumnName = "Qty", Width = "20%" },
+ new TableColumn { Title = "Price", ColumnName = "Price", Width = "20%" },
+ }
+};
+section.Pane.ElementList.Add(table);
+
+section.Footer.Height = "1cm";
+section.Footer.ElementList.Add(new Text { Value = "Page {Page} of {TotalPages}" });
+
+var data = new DocumentData();
+data.Add("InvoiceNumber", "INV-00042");
+
+var lines = new DocumentDataTable("Lines");
+lines.Rows.Add(new DocumentDataTableData(new Dictionary
+{
+ { "Item", "Widget" }, { "Qty", "2" }, { "Price", "10.00" }
+}));
+data.Add(lines);
+
+var props = new DocumentProperties
+{
+ Title = "Invoice INV-00042",
+ Author = "Acme Corp"
+};
+
+var pdf = new Renderer(new Template(section), data, documentProperties: props)
+ .GetPdfBinary(PageSize.A4);
+
+File.WriteAllBytes("invoice.pdf", pdf);
+```
diff --git a/docs/articles/elements.md b/docs/articles/elements.md
new file mode 100644
index 0000000..8ef6749
--- /dev/null
+++ b/docs/articles/elements.md
@@ -0,0 +1,149 @@
+# Elements
+
+All visual content lives in one of the section's `ElementList`s — `Header.ElementList`, `Pane.ElementList`, or `Footer.ElementList`. Every element supports the standard positioning properties (`Left`, `Top`, `Right`, `Bottom`, `Width`, `Height`) as `UnitValue` strings, plus `IsBackground` to control draw order.
+
+## Text
+
+Single-line text. Doesn't wrap — anything that exceeds the bounds is clipped.
+
+```csharp
+section.Pane.ElementList.Add(new Text
+{
+ Value = "Invoice {InvoiceNumber}",
+ FontSize = "14pt",
+ TextAlignment = TextBase.Alignment.Right
+});
+```
+
+`Value` supports the `{Key}` placeholder syntax — see [Data and rendering](data-and-rendering.md). The `HideValue` property suppresses output when a referenced data key is empty — useful for optional headers.
+
+## TextBox
+
+Multi-line text that wraps and can span multiple pages.
+
+```csharp
+section.Pane.ElementList.Add(new TextBox
+{
+ Value = "Long descriptive copy that needs to wrap across many lines.",
+ Width = "100%",
+ Top = "5cm"
+});
+```
+
+Use a `TextBox` whenever the content length is unbounded. Combine with `ReferencePoint` (below) to stack content that grows.
+
+## Image
+
+Embed an image from a URL, file path, or stream.
+
+```csharp
+section.Header.ElementList.Add(new Image
+{
+ Source = "https://example.com/logo.png",
+ Left = "0", Top = "0",
+ Width = "5cm"
+});
+```
+
+`Source` accepts an HTTP URL, a local file path, or anything `System.Drawing.Image.FromStream`/`FromFile` understands.
+
+## BarCode
+
+A Code 39 barcode rendered via Aspose.BarCode.
+
+```csharp
+section.Pane.ElementList.Add(new BarCode
+{
+ Code = "1234567890",
+ Left = "8mm",
+ Right = "8mm",
+ Top = "18mm",
+ Bottom = "18mm"
+});
+```
+
+The barcode fills the box you give it; size the box to the print area the scanner expects.
+
+## Line
+
+Straight line. Without explicit position, draws across the full width.
+
+```csharp
+section.Pane.ElementList.Add(new Line
+{
+ Thickness = "1mm",
+ Color = Color.MidnightBlue
+});
+
+section.Pane.ElementList.Add(new Line
+{
+ Top = "10cm",
+ Thickness = "0.5mm",
+ Color = Color.Black
+});
+```
+
+## Rectangle
+
+Outlined or filled rectangle.
+
+```csharp
+section.Pane.ElementList.Add(new Rectangle
+{
+ Left = "25%", Top = "25%",
+ Width = "50%", Height = "50%",
+ BorderColor = Color.Green,
+ BackgroundColor = Color.LightYellow
+});
+```
+
+Set only `BorderColor` for outline, only `BackgroundColor` for solid fill, or both.
+
+## Table
+
+Renders tabular data from a `DocumentDataTable`. Tables grow across pages and support grouping rows.
+
+```csharp
+var table = new Table
+{
+ Width = "100%",
+ DataTableName = "InvoiceLines",
+ Columns =
+ {
+ new TableColumn { Title = "Item", ColumnName = "Item", Width = "60%" },
+ new TableColumn { Title = "Qty", ColumnName = "Qty", Width = "20%", HeaderAlignment = Table.Alignment.Right, ContentAlignment = Table.Alignment.Right },
+ new TableColumn { Title = "Price", ColumnName = "Price", Width = "20%", HeaderAlignment = Table.Alignment.Right, ContentAlignment = Table.Alignment.Right },
+ }
+};
+
+section.Pane.ElementList.Add(table);
+```
+
+The matching table data goes onto the `DocumentData` — see [Data and rendering](data-and-rendering.md).
+
+## ReferencePoint
+
+A logical container that holds child elements, with optional vertical stacking. Use it when you want a group of elements to flow as one block and grow downward.
+
+```csharp
+var rp = new ReferencePoint
+{
+ Stack = ReferencePoint.StackMethod.Vertical,
+ Top = "3cm"
+};
+rp.ElementList.Add(new Text { Value = "First line" });
+rp.ElementList.Add(new TextBox { Value = "Body paragraph that wraps." });
+rp.ElementList.Add(new Text { Value = "Final line" });
+
+section.Pane.ElementList.Add(rp);
+```
+
+With `Stack = Vertical`, each child is anchored directly below the previous one, so a growing `TextBox` shifts the elements after it instead of overlapping them.
+
+## Z-order and `IsBackground`
+
+Elements draw in the order they're added to the `ElementList`. To put something behind the rest, set `IsBackground = true` on the element — backgrounds render in a pre-pass so foreground content overlays them.
+
+## Next
+
+- [Data and rendering](data-and-rendering.md) — `DocumentData`, table data, the full `Renderer` surface, and choosing a `PageFormat`.
diff --git a/docs/articles/getting-started.md b/docs/articles/getting-started.md
new file mode 100644
index 0000000..c4f227c
--- /dev/null
+++ b/docs/articles/getting-started.md
@@ -0,0 +1,81 @@
+# Getting started
+
+## Install
+
+For a typical .NET 8 / 9 / 10 application:
+
+```
+dotnet add package Tharga.Reporter
+```
+
+Tharga.Reporter targets `net8.0`, `net9.0`, and `net10.0`. At runtime it uses `System.Drawing.Common`, `Aspose.BarCode`, and `PdfSharp.MigraDoc`, so it expects a Windows host.
+
+## Namespaces
+
+The core types span three namespaces — import them all at the top of the file that builds your document:
+
+```csharp
+using Tharga.Reporter; // Renderer, PageFormat
+using Tharga.Reporter.Entity; // Template, Section, DocumentData, DocumentProperties
+using Tharga.Reporter.Entity.Element; // Text, TextBox, Image, BarCode, Line, Rectangle, Table
+```
+
+- `Tharga.Reporter` — `Renderer` and `PageFormat`, the rendering entry points.
+- `Tharga.Reporter.Entity` — the document model: `Template`, `Section`, units, document data, font.
+- `Tharga.Reporter.Entity.Element` — the visual elements you stack inside a section's pane, header, or footer.
+
+## Minimal example
+
+The shortest useful program is: build a `Section`, add an element, wrap it in a `Template`, hand it to `Renderer.GetPdfBinary`:
+
+```csharp
+using PdfSharp;
+using Tharga.Reporter;
+using Tharga.Reporter.Entity;
+using Tharga.Reporter.Entity.Element;
+
+var section = new Section();
+section.Pane.ElementList.Add(new Text { Value = "Hello, world!" });
+
+var template = new Template(section);
+var renderer = new Renderer(template);
+var pdfBytes = renderer.GetPdfBinary(PageSize.A4);
+
+File.WriteAllBytes("hello.pdf", pdfBytes);
+```
+
+`GetPdfBinary` returns the PDF as a `byte[]`, so you can stream it to a HTTP response, save it to disk, or hand it to a print pipeline.
+
+## Adding margins, a header, and a footer
+
+`Section` exposes a `Margin`, a `Header`, a `Pane`, and a `Footer`. Each of the three areas has an `ElementList`:
+
+```csharp
+using System.Drawing;
+using PdfSharp;
+using Tharga.Reporter;
+using Tharga.Reporter.Entity;
+using Tharga.Reporter.Entity.Element;
+
+var section = new Section
+{
+ Margin = new UnitRectangle { Left = "1cm", Top = "2cm", Right = "1cm", Bottom = "2cm" }
+};
+section.Header.Height = "2cm";
+section.Header.ElementList.Add(new Text { Value = "Invoice", FontSize = "18pt" });
+
+section.Pane.ElementList.Add(new Text { Value = "Body content here." });
+
+section.Footer.Height = "1cm";
+section.Footer.ElementList.Add(new Text { Value = "Page {Page} of {TotalPages}" });
+
+var pdf = new Renderer(new Template(section)).GetPdfBinary(PageSize.A4);
+```
+
+Units accept `cm`, `mm`, `pt`, `in`, and `%` (relative to the parent area). The `{Page}` and `{TotalPages}` tokens are built-in placeholders filled by the renderer.
+
+## Next steps
+
+- [Templates](templates.md) — how `Template`, `Section`, `Header`, `Pane`, and `Footer` fit together; multi-section documents.
+- [Elements](elements.md) — the catalog of element types and their key properties.
+- [Data and rendering](data-and-rendering.md) — `DocumentData` for placeholder substitution and table data, plus the full `Renderer` and `PageFormat` surface.
diff --git a/docs/articles/index.md b/docs/articles/index.md
new file mode 100644
index 0000000..75346ba
--- /dev/null
+++ b/docs/articles/index.md
@@ -0,0 +1,8 @@
+# Articles
+
+Guides for building with Tharga.Reporter.
+
+- **[Getting started](getting-started.md)** — install, namespaces, and a minimal `Template` → `Renderer` → PDF example.
+- **[Templates](templates.md)** — `Template`, `Section`, the `Header` / `Pane` / `Footer` areas, multi-section documents, and margins.
+- **[Elements](elements.md)** — `Text`, `TextBox`, `Image`, `BarCode`, `Line`, `Rectangle`, `Table`, and `ReferencePoint` for stacking.
+- **[Data and rendering](data-and-rendering.md)** — `DocumentData` placeholder substitution, table data, `Renderer`, `PageFormat`, and `DocumentProperties`.
diff --git a/docs/articles/templates.md b/docs/articles/templates.md
new file mode 100644
index 0000000..4fb4f0d
--- /dev/null
+++ b/docs/articles/templates.md
@@ -0,0 +1,123 @@
+# Templates
+
+A document is a `Template` containing one or more `Section`s. Each `Section` has three areas — `Header`, `Pane`, `Footer` — plus a `Margin`, optional `DefaultFont`, and an optional `Name`.
+
+## Template
+
+```csharp
+var section = new Section();
+section.Pane.ElementList.Add(new Text { Value = "Hello" });
+
+var template = new Template(section);
+```
+
+For multi-section documents, build the `Template` with the first section and add more via `SectionList`:
+
+```csharp
+var first = new Section();
+var second = new Section();
+
+var template = new Template(first);
+template.SectionList.Add(second);
+```
+
+Each section in the list renders as one logical block — usually one page, but elements like `TextBox` and `Table` can grow across pages.
+
+## Section areas
+
+A `Section` is laid out top-to-bottom:
+
+```
++--------------------------------+
+| Header | Height controlled by section.Header.Height
++--------------------------------+
+| |
+| Pane | Fills the remaining space
+| |
++--------------------------------+
+| Footer | Height controlled by section.Footer.Height
++--------------------------------+
+```
+
+Each area is an `ElementList` you push visual elements onto:
+
+```csharp
+section.Header.Height = "2cm";
+section.Header.ElementList.Add(new Text { Value = "Statement of Account" });
+
+section.Pane.ElementList.Add(new TextBox
+{
+ Value = "Body text that wraps across lines and pages.",
+ Width = "100%"
+});
+
+section.Footer.Height = "1cm";
+section.Footer.ElementList.Add(new Text { Value = "Page {Page} of {TotalPages}" });
+```
+
+## Margins
+
+`Section.Margin` is a `UnitRectangle`. The default is zero on all sides:
+
+```csharp
+section.Margin = new UnitRectangle
+{
+ Left = "1cm",
+ Top = "2cm",
+ Right = "1cm",
+ Bottom = "2cm",
+};
+```
+
+Element coordinates (`Left`, `Top`, `Right`, `Bottom`, `Width`, `Height`) are measured **inside** the section's margins.
+
+## Units
+
+Positions and sizes are strings parsed by `UnitValue`:
+
+| Suffix | Meaning |
+|---|---|
+| `cm` | centimetres |
+| `mm` | millimetres |
+| `pt` | points (1/72 inch) |
+| `in` | inches |
+| `%` | percentage of the parent area's width or height |
+
+So `Left = "50%"` means halfway across the parent area, and `Width = "100%"` fills it.
+
+## Default font
+
+Set `Section.DefaultFont` to provide a fallback for all text elements in that section:
+
+```csharp
+section.DefaultFont = new Font
+{
+ Name = "Arial",
+ Size = "12pt",
+ Color = Color.Black
+};
+```
+
+Individual elements can override by setting their own `Font` property.
+
+## Naming sections
+
+Set `Section.Name` if you want to reference a specific section in `DocumentData` table mappings or downstream tooling. The name is preserved in the XML serialization (`Template.ToXml()` / `Template.Load(xml)`).
+
+## XML round-trip
+
+Templates can be persisted as XML:
+
+```csharp
+XmlDocument xml = template.ToXml();
+// ... persist xml ...
+
+Template loaded = Template.Load(xml);
+```
+
+This is useful when the template is authored by a designer separately from the C# call site, or when templates ship as resources alongside the data that fills them.
+
+## Next
+
+- [Elements](elements.md) — the visual primitives you place inside `Header.ElementList`, `Pane.ElementList`, and `Footer.ElementList`.
+- [Data and rendering](data-and-rendering.md) — feeding `DocumentData` into the renderer.
diff --git a/docs/articles/toc.yml b/docs/articles/toc.yml
new file mode 100644
index 0000000..533cb41
--- /dev/null
+++ b/docs/articles/toc.yml
@@ -0,0 +1,10 @@
+- name: Overview
+ href: index.md
+- name: Getting started
+ href: getting-started.md
+- name: Templates
+ href: templates.md
+- name: Elements
+ href: elements.md
+- name: Data and rendering
+ href: data-and-rendering.md
diff --git a/docs/docfx.json b/docs/docfx.json
new file mode 100644
index 0000000..683f2c9
--- /dev/null
+++ b/docs/docfx.json
@@ -0,0 +1,53 @@
+{
+ "metadata": [
+ {
+ "src": [
+ {
+ "src": "..",
+ "files": [
+ "Tharga.Reporter/Tharga.Reporter.csproj"
+ ]
+ }
+ ],
+ "dest": "api",
+ "includePrivateMembers": false,
+ "disableGitFeatures": false,
+ "disableDefaultFilter": false,
+ "noRestore": false,
+ "namespaceLayout": "flattened",
+ "memberLayout": "samePage",
+ "EnumSortOrder": "alphabetic",
+ "allowCompilationErrors": false
+ }
+ ],
+ "build": {
+ "content": [
+ {
+ "files": ["**/*.{md,yml}"],
+ "exclude": ["_site/**", "obj/**"]
+ }
+ ],
+ "resource": [
+ {
+ "files": ["CNAME"]
+ }
+ ],
+ "output": "_site",
+ "globalMetadata": {
+ "_appName": "Tharga.Reporter",
+ "_appTitle": "Tharga.Reporter",
+ "_appLogoPath": "https://thargelion.net/assets/component-reporter.png",
+ "_appFaviconPath": "https://thargelion.net/assets/component-reporter.png",
+ "_enableSearch": true,
+ "_disableContribution": false,
+ "_gitContribute": {
+ "repo": "https://github.com/Tharga/Reporter",
+ "branch": "master"
+ }
+ },
+ "template": ["default", "modern", "templates/thg"],
+ "postProcessors": ["ExtractSearchIndex"],
+ "keepFileLink": false,
+ "disableGitFeatures": false
+ }
+}
diff --git a/docs/index.md b/docs/index.md
new file mode 100644
index 0000000..5816fea
--- /dev/null
+++ b/docs/index.md
@@ -0,0 +1,53 @@
+---
+_layout: landing
+---
+
+# Tharga.Reporter
+
+A .NET library for **building and rendering PDF documents** from declarative templates. Define a `Template` of `Section`s with text, images, barcodes, lines, rectangles, and tables, feed it data, and render to a PDF byte array.
+
+Useful when you want to generate receipts, invoices, member cards, labels, reports, or any other structured PDF without hand-writing PdfSharp/MigraDoc code.
+
+## Package
+
+| Package | Target | What it does |
+|---|---|---|
+| [Tharga.Reporter](https://www.nuget.org/packages/Tharga.Reporter) | net8.0 / net9.0 / net10.0 | Template model (`Section`, `Pane`, `Header`, `Footer`), elements (`Text`, `TextBox`, `Image`, `BarCode`, `Line`, `Rectangle`, `Table`), and a `Renderer` that produces a PDF. |
+
+> Tharga.Reporter is Windows-only at runtime — it uses `System.Drawing.Common` and `Aspose.BarCode` under the hood.
+
+## Quick start
+
+```
+dotnet add package Tharga.Reporter
+```
+
+```csharp
+using Tharga.Reporter;
+using Tharga.Reporter.Entity;
+using Tharga.Reporter.Entity.Element;
+using PdfSharp;
+
+var section = new Section();
+section.Pane.ElementList.Add(new Text { Value = "Hello, world!" });
+
+var template = new Template(section);
+var renderer = new Renderer(template);
+var pdfBytes = renderer.GetPdfBinary(PageSize.A4);
+
+File.WriteAllBytes("hello.pdf", pdfBytes);
+```
+
+See [Getting started](articles/getting-started.md) for the full setup.
+
+## What's in the box
+
+- **Template model** — `Template` wraps one or more `Section`s; each `Section` has a `Header`, `Pane`, `Footer`, and `Margin`. See [Templates](articles/templates.md).
+- **Elements** — `Text`, `TextBox`, `Image`, `BarCode`, `Line`, `Rectangle`, `Table`, and `ReferencePoint` for stacking. See [Elements](articles/elements.md).
+- **Unit system** — positions and sizes use a string-based unit grammar (`"1cm"`, `"10mm"`, `"50%"`) via `UnitValue` and `UnitRectangle`. Percentages are relative to the parent area.
+- **Data substitution** — `DocumentData` lets templates contain `{Placeholder}` tokens that get filled at render time. Tables work the same way for repeating rows. See [Data and rendering](articles/data-and-rendering.md).
+- **Page formats** — `PageFormat` wraps PdfSharp's `PageSize` and adds custom millimetre sizes plus a built-in `PlasticCard` (85x54mm).
+
+## Repo
+
+[github.com/Tharga/Reporter](https://github.com/Tharga/Reporter) — source, issues, releases.
diff --git a/docs/templates/thg/layout/_master.tmpl b/docs/templates/thg/layout/_master.tmpl
new file mode 100644
index 0000000..acac4c1
--- /dev/null
+++ b/docs/templates/thg/layout/_master.tmpl
@@ -0,0 +1,160 @@
+{{!Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license.}}
+{{! Copy of templates/modern/layout/_master.tmpl from DocFX 2.78.5 with two targeted fixes for absolute-URL handling on the favicon and navbar logo. The original prepends _rel (e.g. "../") to _appFaviconPath and _appLogoPath unconditionally, which turns an absolute URL into "../https://..." on sub-pages. The fix moves _rel into the fallback path only, so absolute URLs are rendered as-is. Keep _appFaviconPath / _appLogoPath absolute (or unset to use the fallback). }}
+{{!include(/^public/.*/)}}
+{{!include(favicon.ico)}}
+{{!include(logo.svg)}}
+
+
+
+
+ {{#redirect_url}}
+
+ {{/redirect_url}}
+ {{^redirect_url}}
+ {{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}}
+
+
+ {{#_description}}{{/_description}}
+ {{#description}}{{/description}}
+
+
+
+
+
+ {{#_noindex}}{{/_noindex}}
+ {{#_enableSearch}}{{/_enableSearch}}
+ {{#_disableNewTab}}{{/_disableNewTab}}
+ {{#_disableTocFilter}}{{/_disableTocFilter}}
+ {{#docurl}}{{/docurl}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{#_googleAnalyticsTagId}}
+
+
+ {{/_googleAnalyticsTagId}}
+ {{/redirect_url}}
+
+
+ {{^redirect_url}}
+
+
+ {{^_disableNavbar}}
+
+ {{/_disableNavbar}}
+
+
+
+ {{^_disableToc}}
+