kai-report-creator

June 18, 2026 · View on GitHub

You have data, decisions, and deadlines — but decision makers don't have time to read everything. AI can generate reports, but they often look instantly AI-made: template headings, primary color flooding every element, 3-column KPI grids regardless of count. kai-report-creator gives you polished, async-friendly reports in one command: drop a document or URL, pick a theme, and get a single HTML file that survives first-contact reading. Downstream AI agents can also parse it — the output embeds a 3-layer machine-readable structure.

See the guide as a report → — this document was generated by kai-report-creator itself.

A skill for Claude Code and OpenClaw that turns plain text or structured outlines into polished HTML reports.

English | 简体中文


Live Demo

Click any screenshot to open the live demo:

corporate-blue
corporate-blue

Warm Premium · Business
minimal
minimal

Research · Academic
dark-tech
dark-tech

Engineering · Ops
dark-board
dark-board

Dashboards · Architecture
data-story
data-story

Annual Reports · Growth
newspaper
newspaper

Editorial · Industry Analysis
regular-lumen
regular-lumen

Periodic Reports · Weekly/Daily/Monthly

Preview the theme gallery: /report --themes → opens report-themes-preview.html


Design Philosophy: Skills as Domain Harness Engineering

This section explains the principles behind report-creator — both as a user tool and as a Claude Code skill. These principles are reusable for anyone building skills.

1. Progressive Disclosure

A skill file loads entirely into the AI's context on every invocation. Size directly affects focus.

report-creator solves this with rules in the skill, assets in files:

--plan        → only IR rules + component syntax; no CSS, no HTML shell
--generate    → one theme CSS + one shared CSS; other theme files stay on disk
--themes      → pre-built preview HTML; skill doesn't parse internals

Result: --plan never touches CSS. Single-theme generation only loads the selected theme.

This is progressive disclosure applied to AI context: reveal information at the moment it's needed, not before.

2. Capability Growth Must Reduce Context Load

When adding a new capability, the first question is not "what else can we stuff into context?" It is "can we reduce prompt/context burden on the generation path?"

report-creator should prefer three moves:

  • Thin routing in SKILL.md. Keep the skill file as a router plus contract boundary. Load only the files needed for the selected path. Do not drag long planning conversations directly into the render phase.
  • Structured compression over raw prose. Prefer .report.md, BRIEF.json-style briefs, explicit contracts, and routing metadata over more prompt paragraphs. If information matters repeatedly, give it a field, a schema, or a deterministic transform.
  • Move quality checks off the hot path. If a new quality mechanism increases generation-time cognitive load, it belongs in guard validation, post-render review, or evals instead of the prompt chain.

This is not minimalism for its own sake. It is reliability work. Prompt bloat makes routing fuzzy, hides the real contract, and causes the model to drop constraints exactly when rendering needs precision.

3. Silicon-Carbon Collaboration Design

report-creator is designed for human-AI collaboration at both input and output ends.

Input: IR as Human-AI Contract

The .report.md Intermediate Representation is the contract between human intent and AI rendering:

---                         ← Frontmatter: document identity
title: Q3 Sales Report         What is this? Who made it? How should it look?
theme: corporate-blue          Declares intent, not content.
---

## Section Heading         ← Prose: human narrative
Plain Markdown text...        Written naturally. AI renders to semantic HTML.

:::kpi                     ← Component blocks: structured data
- Revenue: \$2.45M ↑12%       Machine-parseable. AI renders deterministically.
:::

Humans write naturally without knowing HTML. AI renders each layer with different rules — prose gets Markdown, components get templates. IR is inspectable and version-controllable.

Output: Three-Layer AI-Readable Structure

Every generated HTML embeds machine-readable structure:

Layer 1 — <script id="report-summary">    Document-level: title, abstract, all KPIs
Layer 2 — data-section data-summary       Section-level: heading + one-sentence summary
Layer 3 — data-component data-raw         Component-level: raw KPI/chart/table data

An AI agent reads Layer 1 for a 3-second overview, drills to Layer 2 for section-level understanding, reaches Layer 3 only for specific data.

Progressive disclosure for both species: IR reveals structure to humans; HTML reveals data to machines. The same principle applied twice — once for carbon-based readers, once for silicon-based ones.

4. Visual Rhythm as Cognitive Pacing

Reports that work follow a rhythm: prose sets context, components deliver data, prose interprets it.

The skill enforces this: never 3+ consecutive prose-only sections. Every 4–5 sections must include a visual anchor chosen for the content type — callout, timeline, diagram, KPI grid, or chart. Dense prose fatigues; data without context loses. Alternation creates flow.

This is why IR's component syntax (:::tag ... :::) is visually obvious: authors scan IR files and see data-heavy sections immediately.

5. Reports Are Asynchronous Decision Support

Slides have a presenter. Reports don't. A report must survive first contact with a busy reader who skims the opening, scans headings, glances at data, and decides in under a minute whether to continue.

This constraint drives product design:

  • --review is one-pass automatic refinement, not interactive editing
  • --generate runs the same checklist as a silent final pass
  • Checklist split into L0 visual quality and L1 content quality
  • Only rules AI can judge and repair reliably are included

Rule of thumb: A generated report should reduce reader effort. If a stakeholder can understand the point, evidence, and next action from a fast skim, the report works.

6. Design Quality Baseline: Against AI Slop

The enemy: instantly recognizable AI output — uniform borders, primary color flooding everything, 3-column KPI grids regardless of count, template-sounding headings.

references/design-quality.md encodes four disciplines:

90/8/2 Color Law. 90% neutral surface, 8% structural accent, 2% bullet-point hits. When --primary floods headings, KPIs, charts, callouts, TOC, and badges — it becomes noise.

10:1 Typography Tension. Largest element ≥10× smallest. Report titles should feel like anchors (2.8–4rem), not labels. Pages without hierarchy look like spreadsheet exports.

KPI Grid Rules. Default isn't always 3 columns. 4 KPIs → 2×2. Hero metric → 2fr 1fr 1fr. 7+ KPIs need dividers. Rigid 3-column grids signal AI wasn't paying attention.

Content-Tone Color Calibration. Different emotional registers deserve different palettes:

Toneprimary_colorFeel
Contemplative / Research#7C6853 warm brownGrounded, editorial
Technical / Engineering#3D5A80 navyPrecise, authoritative
Business / Data#0F7B6C deep tealConfident, forward
Narrative / Annual#B45309 amberWarm, momentum

Pre-output check: "If you told someone 'an AI wrote this', would they believe it? If yes — find the most generic-looking part and redesign it."

7. Contract Enforcement Before Render

v1.20.0's guard validation pipeline introduces a new principle: intercept invalid IR before rendering, not repair after.

IR → Guard (validate + downgrade) → Renderer → HTML

              Block invalid input

Three sub-principles:

PrincipleImplementationMeaning
Zero-Drift ResolutionGuard and renderer share the same resolve_report_class logicValidation and rendering never diverge
Graceful DegradationInvalid components auto-downgrade (kpi→callout, chart→table, timeline→list)Don't fail outright; fall back to safe substitute
Traceability<meta name="ir-hash"> embeds IR hash in HTMLOutput is traceable to source IR

Why it matters:

  • Earlier --review was post-hoc repair; guard is pre-hoc interception
  • Prevents invalid IR from entering the render pipeline and producing unpredictable output
  • Zero-drift ensures guard's judgment and renderer's behavior stay aligned

v1.23.0 extends this boundary to final HTML with scripts/html_quality_gate.py: rendered files must keep the standard shell controls, the declared theme's CSS fingerprint, typography/layout markers, and only real quantitative KPI values. This catches failures where IR is legal but the HTML hand-rolls a theme, drops summary/export controls, or smuggles placeholder/status text into KPI cards.

8. Eval as Quality Boundary, Not Quality Score

v1.15.0's eval workflow embodies this principle: evals define boundaries, not scores.

compression → ir_contract → async_readability → render_integrity
     ↓             ↓              ↓                  ↓
   Source→IR     IR Spec        Reading UX          HTML Integrity
LayerWhat it checksWhere to fix
compressionreport_class, audience, decision_goal declaredSKILL.md
ir_contracttimeline is real time, kpi is short value, chart schema legalrendering-rules.md + contract_checks.py
async_readabilityBLUF, heading stack, takeaway after datareview-checklist.md
render_integrityshell IDs, report-summary JSON, no ::: leak, theme fidelityhtml-shell-template.md + html_quality_gate.py

Failure Map rule: Every real production failure → one new eval case. Not post-hoc discussion about "feels wrong", but direct pointer to the layer that needs fixing.

Rubric design: Output structured JSON (verdict + scores + findings), not fuzzy scores. Downstream agents can parse and auto-repair.

9. Contract Checks as Programmable Guardrails

contract_checks.py makes IR spec executable:

# Timeline must be real dates
DATE_PATTERNS = [YYYY-MM-DD, YYYY-MM, Q1-4 YYYY, Day N, Week N]

# KPI value must be a short real quantitative value; placeholders/status-only words fail
def is_short_kpi_value(value): ...

# Placeholder pattern recognition
PLACEHOLDER_RE = r"\[(INSERT VALUE|数据待填写)\]"

Design principles:

  • Spec declared in SKILL.md, validated in contract_checks.py
  • Guard calls contract_checks, zero drift
  • Every component has auto_downgrade_target: safe fallback path when invalid

Final HTML has a separate gate:

python scripts/html_quality_gate.py report.html

Install

Claude Code

Tell Claude: "Install https://github.com/kaisersong/kai-report-creator"

Or manually:

git clone https://github.com/kaisersong/kai-report-creator ~/.claude/skills/kai-report-creator

Restart Claude Code. Use as /report.

OpenClaw

# Via ClawHub (recommended)
clawhub install kai-report-creator

# Or manually
git clone https://github.com/kaisersong/kai-report-creator ~/.openclaw/skills/kai-report-creator

Release Downloads

The current release is v1.24.0. Download source bundles from GitHub Releases:


Usage

Commands

CommandDescription
/report --from file.mdGenerate from an existing document
/report --from URLGenerate from a web page
/report --plan "topic"Create a .report.md outline first
/report --generate file.report.mdRender an outline to HTML
/report --review file.htmlRefine an existing report
/report --themesPreview the bundled theme gallery
/report --bundle --from file.mdOffline HTML with inlined CDN assets
/report --theme <name> --from file.mdUse a built-in or custom theme
/report [content]One-step: generate from description

Typical Workflows

One-step generation:

/report --from meeting-notes.md
/report --from https://example.com/data-page --output market-analysis.html

Two-stage workflow (complex content):

/report --plan "Q3 Sales Summary" --from q3-data.csv
# edit q3-sales-summary.report.md if needed
/report --generate q3-sales-summary.report.md

Review and refine:

/report --review market-analysis.html

Review Mode

Run --review to improve existing reports with 13 checkpoints:

/report --review market-analysis.html

Behavior:

  1. Load references/review-checklist.md
  2. Apply hard rules automatically
  3. Apply AI-advised rules when confidence is high
  4. Save refined HTML back to file

If you want a structured change summary after review, use references/review-report-template.md.

One-pass automatic refinement — not interactive approval.

--generate also runs this checklist as a silent final review before writing HTML.

This review flow is the built-in 13-checkpoint review system.

13 Checkpoints:

  • KPI value length
  • Badge coverage
  • Summary card poster hierarchy
  • Timeline content validity
  • Export menu completeness
  • BLUF opening (Bottom Line Up Front)
  • Heading stack logic
  • Anti-template section headings
  • Prose-wall cleanup
  • Takeaway-after-data
  • Insight-over-data
  • Scan-anchor coverage
  • Conditional reader guidance

Eval Workflow

This repo now includes a small, repo-contained eval harness focused on async reading quality, not slide-style presenter flow.

Run it with:

python scripts/run-report-evals.py --root . --packet-dir .tmp/eval-packets

What it does:

  • Runs deterministic checks for compression, ir_contract, render_integrity, and jsonld
  • Emits rubric-ready JSON packets for async_readability instead of hiding quality behind vibes
  • Uses repo-contained cases from evals/report-cases.csv

Key files:

  • evals/report-cases.csv — living case set
  • evals/rubric.schema.json — structured grader output contract
  • evals/failure-map.md — where to fix each layer when a case fails
  • evals/cases/* — source + IR artifacts for each case

Captured-Run Skill Evals

scripts/run-report-evals.py checks repo-contained source/IR/HTML artifacts. It is a deterministic regression gate, not a full agent-run skill eval.

For OpenAI-style skill evals, run the captured-run harness against checked-in fixtures or recorded traces:

python scripts/run-skill-evals.py --runner fixture --format json --json-out .tmp/skill-evals/results.json

The harness reads evals/report-skill-prompts.csv, replays deterministic fixture metrics by default, and scores each case across four categories:

  • Outcome: report task completion and valid artifacts.
  • Process: skill flow, reference loading, guard validation, and HTML quality gate evidence from normalized runner metrics.
  • Style: template/theme/content conventions plus structured rubric grading for positive captured-run cases.
  • Efficiency: shell command count, repeated failures, token budgets, and wall-clock budget.

Release verification also uses fixture mode by default, so it does not require Codex, Claude, Qoder, network access, model auth, or any live agent environment:

python scripts/verify-release.py --include-skill-evals

Positive fixture cases use checked-in tests/fixtures/skill-evals/*-style-rubric.json. If a positive case has no rubric, the harness marks it eval_complete: false and fails the case instead of hiding the coverage gap behind a green score.

Saved baselines live under evals/baselines/. Compare a fresh run against the checked-in baseline before changing skill behavior:

python scripts/run-skill-evals.py --runner fixture \
  --artifact-dir .tmp/check-skill-evals-fixture-artifacts \
  --format json \
  --json-out .tmp/check-skill-evals-fixture.json

python scripts/compare-skill-eval-baseline.py \
  --old evals/baselines/2026-05-17-skill-evals-fixture.json \
  --new .tmp/check-skill-evals-fixture.json \
  --format text

evals/baselines/2026-05-17-baseline-summary.md records the saved scores: the deterministic fixture baseline passes 6/6 with incomplete: 0, average_score: 100.0, and Style 25.0, while the hardened Codex live baseline is archival evidence of one manual runner sample. It is not part of default release verification. The comparator checks pass/fail state, eval_complete, total score, and each category score.

Manual live sampling is still possible, but it must be explicit because it depends on the local runner environment:

python scripts/run-skill-evals.py --runner codex --run-live --format json --json-out .tmp/skill-evals/codex-live.json

For complex reports, keep these IR frontmatter fields so evals can measure compression quality directly: report_class, audience, decision_goal, must_include, must_avoid.

Maintainers can run the full release verification chain from one entry point:

python scripts/verify-release.py --root .

For a single generated report, run the final HTML gate directly:

python scripts/html_quality_gate.py report.html

Features

Core

  • Zero dependencies — single .html file, works offline with --bundle
  • 8 built-in themes — corporate-blue, minimal, dark-tech, dark-board, data-story, newspaper, regular-lumen, fangsong
  • 9 component types — KPIs, charts (ECharts), tables, timelines, diagrams, code blocks, callouts, images, lists
  • Report Review System — 13-checkpoint automatic refinement
  • AI-readable output — 3-layer machine-readable structure for downstream agents

Interaction

  • Summary card overlay⊞ Summary button opens a poster-style title card with abstract, KPIs, and section summaries
  • Built-in export — Print/PDF, PNG (Desktop), PNG (Mobile) via ↓ Export button
  • Mobile responsive — adapts to any screen size
  • Bilingual — full zh/en support with auto-detection

Output

  • Custom themesthemes/<name>/theme.css + --theme <name>
  • Custom templatestemplate: ./my-brand-template.html with placeholders
  • Theme overridestheme_overrides.primary_color in frontmatter
  • Offline bundles--bundle inlines all CDN assets

Themes

ThemeVibeBest For
corporate-blueWarm premiumBusiness reports, executive summaries
minimalClean, academicResearch papers, analysis
dark-techEngineering feelOps reports, technical docs
dark-boardDashboard styleArchitecture, metrics dashboards
data-storyNarrative-drivenAnnual reports, growth stories
newspaperEditorialIndustry analysis, newsletters
regular-lumenPoster-style, warm-tonedPeriodic work reports (日报/周报/月报 · 本周期复盘 + 下周期规划) · Kami-style reading experience
fangsongTraditional Chinese, warm brownFormal reports with FangSong typography (标题衬线仿宋 + 正文非衬线仿宋)

corporate-blue

Warm business theme with subtle gradients. Default for executive-facing reports. Uses restrained primary color on key elements only — KPI values, section links, and one accent block per report.

Why it works: Primary color appears on ≤3 element types, creating clear visual hierarchy without the "AI flooded everything with blue" look.


Creating Custom Themes

  1. Create themes/your-theme/ directory
  2. Write theme.css with CSS custom properties:
:root {
  --primary: #B45309;
  --bg: #FAFAF9;
  --text: #1C1917;
  --font-heading: "Merriweather", serif;
}
  1. Run: /report --theme your-theme --from file.md

Example theme bundled: themes/warm-editorial/


Report Format (IR)

For complex reports, use --plan to generate a .report.md intermediate file.

Frontmatter:

---
title: Q3 Sales Report
theme: corporate-blue
author: Sales Team
date: 2024-10-08
lang: en
toc: true
abstract: "Q3 revenue grew 12% YoY with record new customer acquisition."
---

Component blocks:

:::kpi
items:
  - label: Revenue
    value: \$2.45M
    delta: ↑12%
  - label: New Clients
    value: 183
    delta: ↑8%
:::

:::chart type=line title="Monthly Revenue"
labels: [Jul, Aug, Sep]
datasets:
  - label: Actual
    data: [780000, 820000, 850000]
:::

:::timeline
- 2024-10-15: Q4 targets released
- 2024-10-31: Product launch
:::

:::callout type=tip
Key insight goes here.
:::

Badges remain optional HTML chips for scanability; they are not standalone IR tags. Timelines are strict chronological components and should use explicit time tokens such as 2024-10-15 or Q4 2024.


For AI Agents

Other agents can call report-creator programmatically:

# From document
/report --from ./analysis.md --output summary.html

# From URL
/report --from https://example.com/report-page --theme data-story

# Two-step with review
/report --plan "Market Analysis" --from ./raw-data.md
/report --generate market-analysis.report.md
/report --review report.html

Extracting structured data:

from bs4 import BeautifulSoup
import json

soup = BeautifulSoup(open("report.html"), "html.parser")
summary = json.loads(soup.find("script", {"id": "report-summary"}).string)
print(summary["title"], summary["kpis"])

Export

Every report has a built-in ↓ Export button (bottom-right):

OptionHow it works
Print / PDFOpens browser print dialog → Save as PDF
PNG (Desktop)Full page at 2× resolution
PNG (Mobile)Report body at 1170px wide (≈3× iPhone)

Tip: Uncheck "Headers and footers" in print dialog for clean PDFs.


Use Case: Daily Work Report → Telegram

Generate a report of today's work in dark-board style, export as IM image, send via Telegram.

OpenClaw will:

  1. Summarize tasks, decisions, next steps
  2. Render to dark-board HTML with KPIs and timeline
  3. Screenshot as 800px JPEG (animations auto-disabled for headless capture)
  4. Send directly to your Telegram channel

Examples

FileDescription
examples/en/business-report.htmlQ3 Sales Report (EN)
examples/en/business-report-reviewed-demo.htmlReviewed demo with stronger BLUF (EN)
examples/zh/business-report.htmlQ3 销售业绩报告(中文)
examples/review-reports/Structured review report examples

Requirements

No dependencies. Works in any modern browser.

For offline bundles with --bundle: internet connection needed once to inline CDN assets.


Compatibility

PlatformVersionInstall path
Claude Codeany~/.claude/skills/kai-report-creator/
OpenClaw≥ 0.9~/.openclaw/skills/kai-report-creator/

Version History

v1.24.0 — JSON-LD structured metadata release: every rendered HTML now embeds <script type="application/ld+json"> with schema.org Report metadata (name, inLanguage, creator, theme, metadataVersion, irHash); add references/output-metadata.md field contract; add quality gate JSON-LD validation (position, escaping, required fields, hash parity, propertyID allow-list); add jsonld eval dimension; update canonical templates with JSON-LD; 34 new JSON-LD unit tests; normalize IR hash computation for cross-repo parity.

v1.23.3 — No-agent eval gate release: make release verification use fixture skill evals by default, document that skill evals do not require Codex/Claude/Qoder/model auth/network access, and reject non-fixture runners unless a recorded trace or explicit live flag is provided.

v1.23.2 — Complete fixture rubric release: add checked-in positive-case style rubrics, require eval_complete for green captured-run results, compare completeness regressions, and refresh the deterministic fixture baseline to 6/6 passing at 100.0 average with Style 25.0.

v1.23.1 — Captured-run skill eval release: add OpenAI-style skill eval prompts, fixture and Codex trace runners, normalized timeout handling, baseline comparison, saved fixture/live baselines, release-verification integration, and README guidance for comparing future skill changes against the saved scores.

v1.23.0 — Final HTML quality gate release: add scripts/html_quality_gate.py to validate rendered shell IDs, theme CSS fidelity, regular-lumen/fangsong typography and layout markers, and KPI values; require every KPI card to use a real quantitative value; remove forced placeholder KPIs from periodic reports; fix dark-board status KPI examples; and add regression coverage for the failure modes.

v1.22.0 — Reference split and validator profile release: split oversized shell and rendering contracts into route-specific child references, add a reference index and validator-facing usage boundary artifacts, add a generated-cache cleanup gate to release verification, and document golden eval cases for external validators.

v1.21.2 — Packaging cleanup: remove the tracked docs/ directory from GitHub and ClawHub packages, ignore the local docs symlink, and keep project documentation in /Users/song/projects/mydocs/report-creator.

v1.21.1 — Skill prompt budget release: compress SKILL.md into a thin routing contract under 320 lines, move shell metadata and duplicate-date details into references, add a size-budget regression test, and include that test in the fast verification path.

v1.21.0 — Late-context isolation and release hardening: require --generate to extract exactly one IR block from context, add context isolation helpers plus late-context eval runner, expand release verification and fast-test coverage, normalize footer/watermark shell metadata, and tighten bilingual doc-sync guardrails.

v1.20.1 — Design philosophy expansion: added §6 (Contract Enforcement Before Render), §7 (Eval as Quality Boundary), §8 (Contract Checks as Programmable Guardrails) documenting the guard pipeline and eval workflow principles.

v1.20.0 — Guard validation pipeline: Python guard (scripts/guard_validate.py) runs before HTML rendering with zero-drift report_class resolution, auto-downgrade invalid blocks (kpi→callout, chart→table, timeline→list, diagram→callout), IR hash embedding in <meta name="ir-hash"> for traceability, and guard integration tests.

v1.18.0 — Theme routing fixed for work reports: priority-ordered keyword matching now correctly routes weekly/daily/monthly reports to regular-lumen (first priority) and generic work progress reports to corporate-blue (fallback), instead of misrouting to dark-tech/dark-board due to overlapping keywords like "项目/进展/状态".

v1.17.1 — Resolve ClawHub version conflict (merge ClawHub v1.16.1 updates).

v1.17.0 — Merge ClawHub v1.16.1 updates + add watermark feature.

v1.16.0 — Minimal Kami borrowing, fully landed: add hard anti-patterns.md and diagram-decision-rules.md, introduce silent spec-loading-matrix.md plus optional archetype routing hints, add maintainer-side scripts/verify-release.py, and raise the Windows release suite to 134 passing tests.

v1.15.0 — IR contract hardening and eval foundation: split failures into invalid_syntax / invalid_semantics / contract_conflict, formalize kpi / chart / timeline / diagram schemas, demote badge to optional enhancement, add repo-contained eval cases plus run-report-evals.py, fix install paths to kai-report-creator, and bring the Windows release suite to 125 passing tests.

v1.14.2 — Export menu completeness enforced in the standard generate flow: require print/desktop/mobile/IM export entries plus JS bindings during pre-write shell validation and silent final review; add shell contract coverage so reports no longer regress to partial export menus.

v1.14.1 — Print/PDF export fix: preserve report background and force animated KPI/data blocks visible during print export; add print export regression coverage.

v1.14.0 — ECharts standard: unified all charts on ECharts (was Chart.js), added bar/line/radar/pie ECharts templates, grid bottom rule for rotated labels, line data integrity rule, 14 new chart rendering contract tests.

v1.13.0 — L2 HTML shell structure validation: 10 mandatory elements check in SKILL.md pre-write, design-quality.md §8, 30 new HTML shell contract tests (BUG-001 fix).

v1.9.0 — Report Review System: --review with 13 checkpoints; silent final review in --generate; L0/L1 quality layering.

v1.8.3 — KPI overflow fix: .kpi-suffix for long units; rendering rules updated.

v1.8.2 — Restrained color system: shared badges default to neutral; data-report-mode="comparison" for entity colors.

v1.8.1 — Export background fix: resolve --bg before fallback.

v1.8.0 — Custom themes: --theme <name> loads themes/<name>/.

v1.6.0 — Sankey chart: :::chart type=sankey for flow diagrams.

v1.5.0 — Design Quality Baseline: 90/8/2 color law, KPI grid rules, content-tone calibration.

v1.4.0 — Summary card overlay with poster entry card behavior and KPI/section summaries.

v1.3.0 — Zero-dependency animations: staggered KPI bounce, timeline slide-in.

v1.0.0 — Initial release with 6 themes and 9 component types.