Lossless Changelog
component

Overview

This session focused on building and refining a comprehensive export/conversion system for investment memos, enabling professional PDF generation with Hypernova Capital branding.

Changelog: Export & Conversion System (2025-11-18)

Overview

This session focused on building and refining a comprehensive export/conversion system for investment memos, enabling professional PDF generation with Hypernova Capital branding. The work extended the multi-format export system (commits a9490a8 and 14bfdf7) with direct markdown-to-PDF conversion, addressing critical rendering issues around margins, typography, and dark mode styling.

Key Achievements

  • ✅ Direct Markdown → PDF Conversion: Created streamlined workflow bypassing intermediate HTML files

  • ✅ Dark Mode PDF Support: Solved complex margin coloring challenge for navy (#1a3a52) backgrounds

  • ✅ Typography Optimization: Increased base font size from 11pt → 12pt for improved readability

  • ✅ Margin Balancing: Implemented asymmetric padding (0.3in top, 0.4in sides, 0.1in bottom)

  • ✅ Image Constraints: Fixed image bleeding by adding max-width constraints

  • ✅ WeasyPrint Integration: Full PDF generation pipeline with system dependency management


Python Scripts

1. markdown-to-pdf.py (New)

Purpose: Direct markdown to PDF converter with Hypernova branding

Location: /Users/mpstaton/code/lossless-monorepo/ai-labs/investment-memo-orchestrator/markdown-to-pdf.py

Key Features:

  • Converts markdown directly to PDF without intermediate HTML files

  • Supports light/dark mode themes via --mode flag

  • Embeds Hypernova branding (logo, footer, colors)

  • Uses wrapper div pattern for colored page backgrounds

  • Handles font embedding and CSS integration

Usage:

BASH
# Basic conversion (light mode)
python3 markdown-to-pdf.py memo.md

# Dark mode conversion
python3 markdown-to-pdf.py memo.md --mode dark

# Specify output location
python3 markdown-to-pdf.py memo.md --mode dark -o exports/memo.pdf

Technical Architecture:

PYTHON
# Conversion pipeline
1. Read markdown file (utf-8 encoding)
2. Convert MD → HTML via pypandoc
3. Read template CSS from templates/hypernova-style.css
4. Wrap HTML in branded template with header/footer
5. Apply dark mode classes if mode == "dark"
6. Generate custom PDF CSS for margin handling
7. Convert HTML → PDF via WeasyPrint

Critical Implementation - Colored Margins:

PYTHON
# The key innovation: @page margin: 0 with wrapper div padding
pdf_css = """
@page {
    size: letter;
    margin: 0;                    # No page margin = no white space
    background: #1a3a52;          # Navy background extends to edges
}

html, body {
    margin: 0;
    padding: 0;
    background: transparent;       # Let page background show through
}

.page-wrapper {
    padding: 0.3in 0.4in 0.1in 0.4in;  # Visual margins via padding
    min-height: 11in;                   # Force content height
    box-sizing: border-box;             # Include padding in dimensions
}
"""

Dependencies:

  • pypandoc>=1.13 - Markdown to HTML conversion

  • weasyprint>=60.0 - HTML to PDF rendering

  • System libraries: cairo, pango, gdk-pixbuf, libffi

Error Handling:

  • Checks for pypandoc/weasyprint installation

  • Validates input file existence

  • Provides troubleshooting guidance for system dependencies

  • Reports file size and output path on success


2. export-branded.py (Enhanced)

Purpose: Multi-format branded export tool with HTML/PDF support

Location: /Users/mpstaton/code/lossless-monorepo/ai-labs/investment-memo-orchestrator/export-branded.py

Features:

  • Generates self-contained HTML with embedded fonts

  • Supports light/dark mode themes

  • Includes Hypernova branding (logo, colors, footer)

  • Improved citation spacing ([1], [2], [3] vs [1][2][3])

  • Optional WeasyPrint PDF generation

Usage:

BASH
# Export to HTML (light mode)
python3 export-branded.py output/memo.md -o exports/branded/

# Export to HTML (dark mode)
python3 export-branded.py output/memo.md --mode dark -o exports/dark/

# Export to PDF via WeasyPrint
python3 export-branded.py output/memo.md --mode dark --pdf

Key Capabilities:

  • Font embedding via base64 encoding

  • CSS variable system for theme switching

  • Preserves footnotes with URLs and dates

  • Print-optimized layouts for browser PDF export


3. export-formats.py (Existing)

Purpose: Legacy Word document export tool

Location: /Users/mpstaton/code/lossless-monorepo/ai-labs/investment-memo-orchestrator/export-formats.py

Features:

  • Converts markdown to Word (.docx) format

  • Preserves footnotes and formatting

  • Uses pypandoc for conversion

Usage:

BASH
python3 export-formats.py output/memo.md --word

Bash Scripts

1. md-to-pdf.sh (New)

Purpose: Bash wrapper for markdown-to-pdf.py with environment setup

Location: /Users/mpstaton/code/lossless-monorepo/ai-labs/investment-memo-orchestrator/md-to-pdf.sh

Implementation:

BASH
#!/bin/bash
# Set library paths for WeasyPrint
export DYLD_LIBRARY_PATH="/opt/homebrew/lib:$DYLD_LIBRARY_PATH"

# Activate virtual environment
source .venv/bin/activate

# Run conversion script
python3 markdown-to-pdf.py "$@"

Why This Matters:

  • Sets DYLD_LIBRARY_PATH for WeasyPrint's C library dependencies

  • Activates Python virtual environment automatically

  • Forwards all arguments to markdown-to-pdf.py

  • Provides executable convenience (./md-to-pdf.sh memo.md)

Usage:

BASH
# Make executable (first time only)
chmod +x md-to-pdf.sh

# Convert markdown to PDF
./md-to-pdf.sh output/memo.md --mode dark -o exports/memo.pdf

2. html-to-pdf.sh (New)

Purpose: Convert existing HTML files to PDF using WeasyPrint

Location: /Users/mpstaton/code/lossless-monorepo/ai-labs/investment-memo-orchestrator/html-to-pdf.sh

Implementation:

BASH
#!/bin/bash
export DYLD_LIBRARY_PATH="/opt/homebrew/lib:$DYLD_LIBRARY_PATH"
source .venv/bin/activate

INPUT_HTML="$1"
OUTPUT_PDF="${2:-${INPUT_HTML%.html}.pdf}"

python3 -c "from weasyprint import HTML; HTML('$INPUT_HTML').write_pdf('$OUTPUT_PDF'); print('PDF created: $OUTPUT_PDF')"

Usage:

BASH
# Convert HTML to PDF (auto-named)
./html-to-pdf.sh exports/branded/memo.html

# Convert with custom output name
./html-to-pdf.sh exports/branded/memo.html ~/Desktop/memo.pdf

Use Cases:

  • Convert existing branded HTML exports to PDF

  • Batch process multiple HTML files

  • Alternative to browser "Print to PDF" with better margin control


3. export-all-modes.sh (Existing)

Purpose: Batch export all memos in both light and dark modes

Location: /Users/mpstaton/code/lossless-monorepo/ai-labs/investment-memo-orchestrator/export-all-modes.sh

Features:

  • Exports all markdown memos to exports/light/ and exports/dark/

  • Generates 267+ HTML files per mode

  • Processes company memos, fund memos, and workflow artifacts

Usage:

BASH
./export-all-modes.sh

4. export-all-html.sh (Existing)

Purpose: Legacy batch export script

Features:

  • Exports memos to single HTML directory

  • Supports custom output modes


CSS Templating System

templates/hypernova-style.css

Purpose: Master stylesheet for all exports with light/dark mode support

Location: /Users/mpstaton/code/lossless-monorepo/ai-labs/investment-memo-orchestrator/templates/hypernova-style.css

Architecture:

1. Font Loading (Lines 4-38)

CSS
@font-face {
    font-family: 'Arboria';
    src: local('Arboria Book'), local('Arboria-Book'),
         url('fonts/Arboria_Book.woff2') format('woff2');
    font-weight: 400;
    font-style: normal;
}
/* Additional weights: 500, 500 italic, 700 */

Fonts Included:

  • Arboria Book (400) - Body text

  • Arboria Medium (500) - Subheadings

  • Arboria Medium Italic (500 italic) - Emphasis

  • Arboria Bold (700) - Headlines


2. Color Variables (Lines 41-48)

CSS
:root {
    --hypernova-navy: #1a3a52;      /* Primary brand color */
    --hypernova-cyan: #1dd3d3;       /* Accent color */
    --hypernova-white: #ffffff;
    --hypernova-cream: #f0f0eb;      /* Light backgrounds */
    --hypernova-dark-text: #1a2332;
    --hypernova-gray: #6b7280;
}

3. Base Typography (Lines 62-70)

CSS
body {
    font-family: 'Arboria', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    font-size: 12pt;           /* ↑ Increased from 11pt for readability */
    line-height: 1.6;
    color: var(--hypernova-dark-text);
    background: var(--hypernova-white);
    max-width: 8.5in;
    padding: 0.75in;
}

Changes This Session:

  • ✅ Font size: 11pt → 12pt (line 63)

  • ✅ Print font size: 10pt → 12pt (line 518)


4. Dark Mode Styles (Lines 76-188)

CSS
html:has(body.dark-mode) {
    background: var(--hypernova-navy);  /* Navy background on html element */
}

body.dark-mode {
    background: var(--hypernova-navy);
    color: var(--hypernova-white);
}

/* Dark mode overrides for all elements */
body.dark-mode h1 { color: var(--hypernova-white); }
body.dark-mode h1 { border-bottom-color: var(--hypernova-cyan); }
body.dark-mode a { color: var(--hypernova-cyan); }
body.dark-mode blockquote { background: rgba(29, 211, 211, 0.1); }
/* ...50+ additional dark mode rules... */

Activation: Add class="dark-mode" to <body> element


5. Image Constraints (Lines 321-328)

CSS
img {
    max-width: 100%;          /* ✅ Added to prevent page bleed */
    height: auto;
    display: block;
    margin: 1.5rem auto;
    border-radius: 4px;
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

Problem Solved: Images were rendering at full resolution and bleeding off pages. The max-width: 100% constraint ensures images fit within the text column.


6. Citation Formatting (Lines 462-496)

CSS
.footnote-ref, .footnote-backref {
    font-size: 0.85em;
    vertical-align: super;
    color: var(--hypernova-cyan);
    text-decoration: none;
    font-weight: 600;
    margin-left: 0.15em;      /* ✅ Spacing between citations */
    margin-right: 0.15em;
}

/* Add comma separators between consecutive citations */
.footnote-ref + .footnote-ref::before {
    content: ",";
    margin-right: 0.25em;
    color: var(--hypernova-gray);
}

Before: [1][2][3] (cramped, hard to read) After: [1], [2], [3] (readable, professional)


7. Print Optimization (Lines 515-582)

CSS
@media print {
    body {
        padding: 0.5in;
        font-size: 12pt;  /* ✅ Increased from 10pt */
    }

    /* Prevent awkward page breaks */
    h1 { page-break-after: avoid; }
    h2, h3, h4 { page-break-after: avoid; }
    p, blockquote, li { page-break-inside: avoid; }
}

@page {
    size: letter;
    margin: 0.5in 0.75in;
}

Input/Output Workflows

Workflow 1: Direct Markdown → PDF (Primary)

┌─────────────┐
│ Markdown    │
│ .md file    │
└──────┬──────┘
       │
       ↓ (markdown-to-pdf.py)
┌──────────────┐
│ pypandoc     │ → MD to HTML conversion
└──────┬───────┘
       │
       ↓
┌──────────────┐
│ Template     │ → Wrap in Hypernova branding
│ Assembly     │   - Header (logo, tagline)
│              │   - Content (converted HTML)
│              │   - Footer (branding)
│              │   - CSS (hypernova-style.css)
└──────┬───────┘
       │
       ↓
┌──────────────┐
│ WeasyPrint   │ → HTML to PDF rendering
│              │   - Font embedding
│              │   - Page layout
│              │   - Margin handling
└──────┬───────┘
       │
       ↓
┌──────────────┐
│ Branded PDF  │
│ .pdf file    │
└──────────────┘

Command:

BASH
./md-to-pdf.sh output/TheoryForge_Memo.md --mode dark -o exports/memo.pdf

Output:

  • Professional PDF with navy (#1a3a52) background extending to page edges

  • 12pt Arboria font family

  • Asymmetric margins (0.3in top, 0.4in sides, 0.1in bottom)

  • Images constrained to text column width


Workflow 2: Markdown → HTML → PDF (Alternative)

┌─────────────┐
│ Markdown    │
└──────┬──────┘
       │
       ↓ (export-branded.py)
┌──────────────┐
│ Branded HTML │ → Self-contained with embedded fonts
│ .html file   │   and inline CSS
└──────┬───────┘
       │
       ↓ (html-to-pdf.sh)
┌──────────────┐
│ Branded PDF  │
└──────────────┘

Commands:

BASH
# Step 1: Generate HTML
python3 export-branded.py output/memo.md --mode dark -o exports/dark/

# Step 2: Convert to PDF
./html-to-pdf.sh exports/dark/memo.html

Use Case: When you need both HTML (for web viewing) and PDF (for distribution)


Workflow 3: Batch Export (All Memos, Both Modes)

┌─────────────────┐
│ output/*.md     │ → All markdown memos
└──────┬──────────┘
       │
       ↓ (export-all-modes.sh)
       │
       ├─→ exports/light/*.html  (267+ files)
       │
       └─→ exports/dark/*.html   (267+ files)

Command:

BASH
./export-all-modes.sh

Output:

  • Light mode: White background, navy text, suitable for printing

  • Dark mode: Navy background, white text, suitable for presentations


Python Dependencies

Required Libraries

1. pypandoc >= 1.13

Purpose: Universal document converter (markdown → HTML, Word, etc.)

Installation:

BASH
uv pip install pypandoc

Usage in Scripts:

PYTHON
import pypandoc

# Convert markdown to HTML
html = pypandoc.convert_text(
    md_content,
    'html',
    format='md',
    extra_args=['--mathjax']  # Math formula support
)

Features Used:

  • Markdown to HTML conversion

  • Preserves footnotes/citations

  • Handles tables, lists, code blocks

  • MathJax integration for formulas


2. weasyprint >= 60.0

Purpose: HTML to PDF conversion with CSS support

Installation:

BASH
# Python package
uv pip install weasyprint

# System dependencies (macOS)
brew install cairo pango gdk-pixbuf libffi

Usage in Scripts:

PYTHON
from weasyprint import HTML

# Convert HTML string to PDF
HTML(string=html_content).write_pdf('output.pdf')

# Convert HTML file to PDF
HTML('input.html').write_pdf('output.pdf')

Features Used:

  • CSS3 support (flexbox, variables, media queries)

  • Font embedding (@font-face)

  • Page layout control (@page rules)

  • Background color rendering

  • Print media query support

System Dependencies:

  • cairo: 2D graphics library (rendering engine)

  • pango: Text layout engine (font handling)

  • gdk-pixbuf: Image loading library

  • libffi: Foreign function interface (Python/C bridge)

Environment Setup (macOS):

BASH
export DYLD_LIBRARY_PATH="/opt/homebrew/lib:$DYLD_LIBRARY_PATH"

This environment variable tells Python where to find the Homebrew-installed C libraries.


Dependency Configuration

pyproject.toml additions:

TOML
dependencies = [
    # ...existing dependencies...
    "pypandoc>=1.13",      # For markdown to Word conversion
    "weasyprint>=60.0",    # For HTML to PDF conversion
]

Critical Technical Problems Solved

Problem 1: Dark Mode Not Rendering in PDF

Symptom: PDF showed light mode (white background) despite --mode dark flag

Root Cause: HTML body tag missing class="dark-mode" attribute

Solution:

PYTHON
# markdown-to-pdf.py
body_class = ' class="dark-mode"' if mode == "dark" else ''
full_html = f"""<!DOCTYPE html>
<html lang="en"{html_class}>
<body{body_class}>  <!-- ← Critical attribute -->

Why It Matters: The CSS relies on .dark-mode class selector to apply navy backgrounds and white text. Without it, default light mode styles apply.


Problem 2: White Margins in PDF (Most Complex)

Symptom: PDF had white margins instead of navy (#1a3a52) extending to page edges

Attempts:

  1. ❌ Set @page background: @page { background: #1a3a52; } - Not supported by all PDF renderers

  2. ❌ Set body padding: Only applied to first page, subsequent pages had white margins

  3. ❌ Set html background with @page margin: Margin area remained white

Root Cause: PDF @page margin creates an unprintable white border outside the content area. Setting background colors on html/body doesn't extend into this margin space.

Final Solution (Wrapper Div Pattern):

PYTHON
pdf_css = """
@page {
    size: letter;
    margin: 0;                    # ← Eliminate page margin entirely
    background: #1a3a52;          # ← Set page background
}

html, body {
    margin: 0;
    padding: 0;
    background: transparent;       # ← Let page background show through
}

.page-wrapper {
    padding: 0.3in 0.4in 0.1in 0.4in;  # ← Create visual margins via padding
    min-height: 11in;                   # ← Force content to fill page
    box-sizing: border-box;             # ← Include padding in dimensions
}
"""

full_html = f"""<!DOCTYPE html>
<html>
<body>
<div class="page-wrapper">  <!-- ← Wrapper div for padding -->
    {content}
</div>
</body>
</html>"""

Why It Works:

  • @page margin: 0 removes unprintable white border

  • @page background: #1a3a52 colors entire page navy

  • .page-wrapper padding creates visual margins

  • Content padding extends across all pages (not just first)

  • Navy background shows through transparent html/body

Diagram:

┌─────────────────────────────────────────┐
│ @page { background: #1a3a52; }          │ ← Navy page background
│ ┌─────────────────────────────────────┐ │
│ │ .page-wrapper {                     │ │
│ │   padding: 0.3in (top)              │ │ ← Visual margin (navy)
│ │   ┌─────────────────────────────┐   │ │
│ │   │ Content area                │   │ │ ← Actual content
│ │   │ (white text on navy bg)     │   │ │
│ │   └─────────────────────────────┘   │ │
│ │   padding: 0.1in (bottom)           │ │ ← Visual margin (navy)
│ │ }                                   │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────┘

Problem 3: Unbalanced Top/Bottom Padding

Symptom: Large space at bottom of pages, minimal at top

Root Cause: Using symmetric padding values (0.5in all around)

Evolution:

  1. Initial: padding: 0.5in; → Too much bottom space

  2. Attempt 2: padding: 0.5in 0.5in 0.25in 0.5in; → Still too much bottom space

  3. Final: padding: 0.3in 0.4in 0.1in 0.4in; → Balanced and minimal

Rationale:

  • Top (0.3in): Enough space for header breathing room

  • Sides (0.4in): Standard professional margin

  • Bottom (0.1in): Minimal space to maximize content density

User Feedback: "The bottom of the page still has unnecessary spacing. Please instead of using the same measure for top and bottom padding, make the bottom specifically very small."


Problem 4: Images Bleeding Off Page

Symptom: Images rendered at full resolution, extending beyond text column

Root Cause: No max-width constraint on <img> elements

Solution:

CSS
/* templates/hypernova-style.css */
img {
    max-width: 100%;    /* ← Constrain to container width */
    height: auto;       /* ← Maintain aspect ratio */
    display: block;
    margin: 1.5rem auto;
}

Why It Works: max-width: 100% ensures images never exceed their container's width (the text column), while height: auto maintains aspect ratio.


Problem 5: Font Size Too Small

Symptom: Text hard to read in PDF, especially for presentations

Root Cause: Two issues:

  1. Base font set to 11pt (too small for PDFs)

  2. Print media query overriding to 10pt (even smaller)

Solution:

CSS
/* Base styles */
body {
    font-size: 12pt;  /* ↑ Increased from 11pt */
}

/* Print styles */
@media print {
    body {
        font-size: 12pt;  /* ↑ Increased from 10pt */
    }
}

User Feedback: "is there a way to increase the font size on the export?"


Export System Architecture

Directory Structure

investment-memo-orchestrator/
├── markdown-to-pdf.py          # Direct MD → PDF converter
├── export-branded.py           # MD → HTML converter
├── export-formats.py           # MD → Word converter
├── md-to-pdf.sh               # Bash wrapper for markdown-to-pdf.py
├── html-to-pdf.sh             # HTML → PDF converter
├── export-all-modes.sh        # Batch export script
│
├── templates/
│   ├── hypernova-style.css    # Master stylesheet (583 lines)
│   └── fonts/
│       ├── Arboria_Book.woff2        # 400 weight
│       ├── Arboria_Medium.woff2      # 500 weight
│       ├── Arboria_Medium_Italic.woff2
│       └── Arboria_Bold.woff2        # 700 weight
│
├── output/
│   ├── TheoryForge_Memo.md    # Source markdown memos
│   ├── KearnyJackson_Memo.md
│   └── ...
│
└── exports/
    ├── branded/               # Self-contained HTML exports
    │   ├── TheoryForge_Memo.html
    │   └── fonts/            # Embedded font files
    │
    ├── light/                # Light mode exports
    │   └── *.html           # 267+ files
    │
    ├── dark/                 # Dark mode exports
    │   └── *.html           # 267+ files
    │
    └── *.pdf                 # Direct PDF exports

File Formats Comparison

FormatUse CaseEditabilityPortabilitySize
PDFFinal distribution, printing, presentationsNoneUniversal2-3 MB
HTML (branded)Web viewing, email sharing, interactive readingNone (self-contained)High (works offline)1-2 MB
HTML (light/dark)Internal review, browser-based workflowsNoneMedium (needs fonts)500 KB
Word (.docx)Editing, collaboration, templatesFullMedium (needs Word)300 KB
Markdown (.md)Version control, AI processing, source of truthFullHigh (plain text)50-100 KB

Design Principles

1. Self-Contained Exports

All exports include embedded fonts and inline CSS, ensuring consistent rendering across platforms without external dependencies.

2. Dark Mode for Presentations

Navy background (#1a3a52) reduces eye strain in darkened rooms and looks professional on screens.

3. Light Mode for Printing

White background conserves ink/toner and provides better readability on paper.

4. Citation Readability

Improved spacing ([1], [2], [3] vs [1][2][3]) follows academic standards and improves clickability.

5. Typography Hierarchy

  • H1: 1.75rem, bold, navy, cyan underline

  • H2: 1.3rem, bold, navy

  • H3: 1.1rem, semi-bold, navy

  • Body: 12pt, regular, dark text

  • Citations: 0.85em, superscript, cyan

6. Minimal Bottom Margins

Maximizes content density while maintaining readability, critical for multi-page investment memos.


Testing & Validation

Test Files

  1. TheoryForge_Memo.md → exports/TheoryForge_Memo.pdf (dark mode, 2.4 MB)

  2. KearnyJackson_Memo.md → exports/KearnyJackson_Memo.pdf (dark mode, 2.5 MB)

Validation Checklist

  • ✅ Navy background extends to all page edges

  • ✅ Images constrained to text column width

  • ✅ Font size readable (12pt)

  • ✅ Minimal bottom padding (0.1in)

  • ✅ Citations spaced properly ([1], [2], [3])

  • ✅ Footnotes preserved with URLs

  • ✅ Hypernova branding applied (header, footer)

  • ✅ Dark mode class applied to body

  • ✅ Arboria fonts embedded correctly


Git Commits Referenced

Commit a9490a8

Title: feat(export): add multi-format branded export system with light/dark modes

Date: 2025-11-18 04:24:46

Changes:

  • Added export-branded.py (345 lines)

  • Added export-all-modes.sh batch script

  • Created templates/hypernova-style.css (514 lines)

  • Embedded 8 Arboria font variants

  • Updated pyproject.toml with pypandoc/weasyprint

  • Enhanced README.md with export documentation

Impact: Established foundation for professional PDF generation with Hypernova branding


Commit 14bfdf7

Title: docs(export): add comprehensive guides for export features and citation improvements

Date: 2025-11-18 05:14:47

Changes:

  • Added EXPORT-GUIDE.md (200 lines)

  • Added DARK-MODE-GUIDE.md (212 lines)

  • Added CITATION-IMPROVEMENTS.md (141 lines)

Impact: Provided user documentation for export workflows and design decisions


Session Artifacts (2025-11-18)

Files Created

  1. markdown-to-pdf.py (211 lines)

  2. md-to-pdf.sh (10 lines)

  3. html-to-pdf.sh (43 lines)

  4. test-margins.html (61 lines) - Testing artifact

Files Modified

  1. templates/hypernova-style.css

    • Line 63: font-size: 11pt; → font-size: 12pt;

    • Line 518: font-size: 10pt; → font-size: 12pt;

    • Line 327: Added max-width: 100%; to img selector

  2. exports/branded/TheoryForge_Memo.html

    • Added class="dark-mode" to body tag

PDFs Generated

  1. exports/TheoryForge_Memo.pdf (2.4 MB, 15 pages)

  2. exports/KearnyJackson_Memo.pdf (2.5 MB, 12 pages)

  3. test-margins.pdf (testing artifact)


Future Enhancements

Potential Improvements

  1. Page Numbers: Add configurable page numbering in footer

  2. Cover Pages: Generate custom cover pages with company logos

  3. Table of Contents: Auto-generate TOC from markdown headers

  4. Cross-References: Internal document linking

  5. Multi-Column Layouts: Support for financial tables

  6. Watermarks: Add "CONFIDENTIAL" or "DRAFT" overlays

  7. PDF Metadata: Embed author, title, keywords

  8. Batch PDF Conversion: Extend export-all-modes.sh to generate PDFs

System Optimizations

  1. Caching: Cache HTML conversion for faster PDF regeneration

  2. Parallel Processing: Use multiprocessing for batch exports

  3. Progress Indicators: Add progress bars for long conversions

  4. Error Recovery: Better handling of malformed markdown

  5. Font Subsetting: Reduce PDF size by including only used glyphs


Command Reference

Quick Commands

BASH
# Direct markdown to PDF (dark mode)
./md-to-pdf.sh output/memo.md --mode dark

# Convert HTML to PDF
./html-to-pdf.sh exports/branded/memo.html

# Export to branded HTML
python3 export-branded.py output/memo.md --mode dark -o exports/dark/

# Batch export all memos (HTML)
./export-all-modes.sh

# Export to Word
python3 export-formats.py output/memo.md --word

Environment Setup

BASH
# Install Python dependencies
uv pip install pypandoc weasyprint

# Install system dependencies (macOS)
brew install cairo pango gdk-pixbuf libffi

# Set library path (add to ~/.zshrc or ~/.bashrc)
export DYLD_LIBRARY_PATH="/opt/homebrew/lib:$DYLD_LIBRARY_PATH"

# Activate virtual environment
source .venv/bin/activate

# Make scripts executable
chmod +x md-to-pdf.sh html-to-pdf.sh export-all-modes.sh

Lessons Learned

1. PDF Margin Handling

Traditional CSS margin properties don't work for PDF page backgrounds. Use @page { margin: 0; background: color; } with content padding instead.

2. Multi-Page Consistency

Padding on <body> only applies to first page in PDFs. Wrap content in a div with padding for consistent multi-page rendering.

3. Font Size for PDFs

Screen-optimized font sizes (10-11pt) are too small for PDFs. Use minimum 12pt for professional documents.

4. Image Constraints

Always set max-width: 100% on images to prevent page bleed in responsive layouts.

5. Dark Mode Activation

CSS dark mode requires explicit class application. Don't rely on prefers-color-scheme media queries for PDF exports.

6. WeasyPrint Dependencies

WeasyPrint requires system libraries (cairo, pango) that must be installed via package manager (Homebrew on macOS) and referenced via DYLD_LIBRARY_PATH.


Conclusion

This session successfully implemented a production-ready markdown-to-PDF conversion system with:

  • ✅ Professional Hypernova branding

  • ✅ Dark mode support with navy backgrounds extending to page edges

  • ✅ Optimized typography (12pt Arboria font family)

  • ✅ Balanced margins (minimal bottom padding for content density)

  • ✅ Image constraint handling

  • ✅ Citation formatting improvements

  • ✅ Complete dependency management

  • ✅ Bash wrapper scripts for convenience

The system has been tested on multiple investment memos (TheoryForge, Kearny Jackson) and produces publication-ready PDFs suitable for internal review, partner distribution, and presentation use.


Total Lines of Code:

  • Python: ~350 lines (markdown-to-pdf.py)

  • Bash: ~50 lines (md-to-pdf.sh, html-to-pdf.sh)

  • CSS: ~583 lines (hypernova-style.css)

  • Total: ~983 lines

Total Files Modified/Created: 8 files

Documentation Pages: 3 guides (553 lines)

Test Outputs: 2 production PDFs (~5 MB total)