Agentman PDF Style Guide

When to Use

Load this skill before writing any PDF generation code — whether using reportlab, fpdf2, or weasyprint. This skill provides the complete Agentman brand implementation for PDF output.

The brand identity is quiet confidence — charcoal suits, not fire trucks. Carbon and warm neutrals do the heavy lifting. Terracotta appears as a rare, deliberate accent.

STOP — Read Before Writing Any Code

Before writing a SINGLE line of PDF generation code, you MUST:

  1. Define ALL color constants below as the first lines of your script
  2. Set document author to "Agentman Equity Research Assistant"
  3. Set document title to "Agentman — {Report Title}"
  4. Display author on page 1 immediately after the report title: "Author: Agentman Equity Research Assistant"
  5. NEVER use library default colors — override every color explicitly
  6. NEVER import colors.black, colors.grey, colors.blue, colors.navy, colors.darkblue, colors.lightgrey from reportlab
  7. NEVER use getSampleStyleSheet() without overriding every color

Visual Weight Distribution

Every report must maintain this ratio:

  • 70% Carbon/Charcoal (#141413, #292322, #3D3735) — the backbone
  • 20% Warm Neutrals (#F0EEE6, #F6EAE6, #E3DACC, #FAF9F5, #FFFFFF) — warmth without color
  • 10% Terracotta Accent (#CC785C, #D97757, #A65945) — sparingly, max 3 per section

reportlab Implementation

Color Constants (Copy-Paste This Exactly)

from reportlab.lib.colors import HexColor

# ============================================================
# AGENTMAN BRAND COLORS — MANDATORY for all PDF reports
# ============================================================

# Primary Brand (Terracotta) — use sparingly, max 3 per section
AGENTMAN_800 = HexColor('#703B2D')   # Badge text, deep emphasis (rare)
AGENTMAN_700 = HexColor('#8B4A38')   # Cover accent, metric box values (rare)
AGENTMAN_600 = HexColor('#A65945')   # Negative emphasis text
AGENTMAN_500 = HexColor('#CC785C')   # PRIMARY ACCENT — stat numbers, table header text, accent lines
AGENTMAN_400 = HexColor('#D97757')   # Highlight/caution text
AGENTMAN_200 = HexColor('#E6A890')   # Badge borders
AGENTMAN_150 = HexColor('#E3DACC')   # TABLE BORDERS, separators
AGENTMAN_100 = HexColor('#F6EAE6')   # TABLE HEADER FILL (light warm tint)
AGENTMAN_75  = HexColor('#F0EEE6')   # Highlight row bg, callout blocks
AGENTMAN_50  = HexColor('#FAF9F5')   # Alternate row bg (cream)

# Text Colors (Charcoal) — 70% of visual weight
CHARCOAL_950 = HexColor('#141413')   # PRIMARY BODY TEXT
CHARCOAL_900 = HexColor('#292322')   # Section titles, cover title
CHARCOAL_800 = HexColor('#3D3735')   # Secondary text

# Neutral (Slate)
SLATE_700    = HexColor('#334155')   # Secondary text on very light backgrounds
SLATE_600    = HexColor('#475569')   # Secondary body text, metric labels
SLATE_500    = HexColor('#64748B')   # Footer, muted captions
SLATE_400    = HexColor('#94A3B8')   # Descriptions, meta text
WHITE        = HexColor('#FFFFFF')

# ============================================================
# BANNED — NEVER import or use these:
# colors.black, colors.grey, colors.blue, colors.lightgrey
# colors.darkblue, colors.navy, colors.steelblue
# HexColor('#000000'), HexColor('#333333'), HexColor('#666666')
# Any hex not listed above
# ============================================================

Table Style (Copy-Paste This Exactly)

from reportlab.platypus import Table, TableStyle

def agentman_table_style():
    """Return the MANDATORY Agentman table style. Use for ALL tables."""
    return TableStyle([
        # Header row — LIGHT warm fill + terracotta text
        ('BACKGROUND', (0, 0), (-1, 0), AGENTMAN_100),     # #F6EAE6 light fill
        ('TEXTCOLOR',  (0, 0), (-1, 0), AGENTMAN_500),     # #CC785C terracotta text
        ('FONTNAME',   (0, 0), (-1, 0), 'Helvetica-Bold'),
        ('FONTSIZE',   (0, 0), (-1, 0), 11),
        ('BOTTOMPADDING', (0, 0), (-1, 0), 8),
        ('TOPPADDING',    (0, 0), (-1, 0), 8),

        # Body rows — charcoal text
        ('TEXTCOLOR',  (0, 1), (-1, -1), CHARCOAL_950),    # #141413 body text
        ('FONTNAME',   (0, 1), (-1, -1), 'Helvetica'),
        ('FONTSIZE',   (0, 1), (-1, -1), 10),
        ('BOTTOMPADDING', (0, 1), (-1, -1), 6),
        ('TOPPADDING',    (0, 1), (-1, -1), 6),

        # First column — bold labels (same color as body, NOT dark fill)
        ('FONTNAME',   (0, 1), (0, -1), 'Helvetica-Bold'),

        # Alternating row backgrounds
        ('ROWBACKGROUNDS', (0, 1), (-1, -1), [WHITE, AGENTMAN_50]),

        # Grid — warm brand borders
        ('GRID',       (0, 0), (-1, -1), 0.5, AGENTMAN_150),  # #E3DACC warm

        # Alignment
        ('ALIGN',      (0, 0), (-1, 0), 'CENTER'),   # Header centered
        ('ALIGN',      (0, 1), (0, -1), 'LEFT'),     # First col left
        ('ALIGN',      (1, 1), (-1, -1), 'CENTER'),  # Data centered
        ('VALIGN',     (0, 0), (-1, -1), 'MIDDLE'),
    ])


def agentman_highlight_table_style():
    """Table style variant with highlight rows for totals/summaries."""
    base = agentman_table_style()
    # Add highlight row styling — apply to specific rows after creation:
    # table_style.add('BACKGROUND', (0, row_idx), (-1, row_idx), AGENTMAN_75)
    return base

Document Setup (Copy-Paste This Exactly)

from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, PageBreak
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.units import inch
from reportlab.lib.enums import TA_LEFT, TA_CENTER

def create_agentman_doc(filename, title, date_str):
    """Create an Agentman-branded PDF document."""
    doc = SimpleDocTemplate(filename, pagesize=letter,
                           leftMargin=0.75*inch, rightMargin=0.75*inch,
                           topMargin=0.75*inch, bottomMargin=0.75*inch,
                           title=f"Agentman — {title}",
                           author="Agentman Equity Research Assistant")
    return doc

Paragraph Styles (Copy-Paste This Exactly)

# ============================================================
# AGENTMAN PARAGRAPH STYLES — use these for ALL text elements
# ============================================================

STYLE_TITLE = ParagraphStyle('AgentmanTitle',
    fontName='Helvetica-Bold', fontSize=24, textColor=CHARCOAL_900,
    spaceAfter=4, leading=30, alignment=TA_LEFT)

STYLE_SUBTITLE = ParagraphStyle('AgentmanSubtitle',
    fontName='Helvetica', fontSize=13, textColor=SLATE_600,
    spaceBefore=2, spaceAfter=6, leading=17, alignment=TA_LEFT)

STYLE_AUTHOR = ParagraphStyle('AgentmanAuthor',
    fontName='Helvetica', fontSize=11, textColor=SLATE_600,
    spaceAfter=12, leading=14, alignment=TA_LEFT)

STYLE_SECTION = ParagraphStyle('AgentmanSection',
    fontName='Helvetica-Bold', fontSize=16, textColor=CHARCOAL_900,
    spaceBefore=18, spaceAfter=6, alignment=TA_LEFT)

STYLE_SUBSECTION = ParagraphStyle('AgentmanSubsection',
    fontName='Helvetica-Bold', fontSize=13, textColor=CHARCOAL_900,
    spaceBefore=12, spaceAfter=4, alignment=TA_LEFT)

STYLE_BODY = ParagraphStyle('AgentmanBody',
    fontName='Helvetica', fontSize=11, textColor=CHARCOAL_950,
    spaceAfter=8, leading=15, alignment=TA_LEFT)

STYLE_BODY_SECONDARY = ParagraphStyle('AgentmanBodySecondary',
    fontName='Helvetica', fontSize=10, textColor=SLATE_600,
    spaceAfter=6, leading=14, alignment=TA_LEFT)

STYLE_STAT_NUMBER = ParagraphStyle('AgentmanStatNumber',
    fontName='Helvetica-Bold', fontSize=28, textColor=AGENTMAN_500,
    spaceBefore=6, spaceAfter=2, leading=34, alignment=TA_CENTER)

STYLE_STAT_LABEL = ParagraphStyle('AgentmanStatLabel',
    fontName='Helvetica', fontSize=10, textColor=SLATE_600,
    spaceBefore=0, spaceAfter=8, leading=13, alignment=TA_CENTER)

STYLE_FOOTER = ParagraphStyle('AgentmanFooter',
    fontName='Helvetica-Oblique', fontSize=8, textColor=SLATE_500,
    alignment=TA_CENTER)

STYLE_DISCLAIMER = ParagraphStyle('AgentmanDisclaimer',
    fontName='Helvetica-Oblique', fontSize=8, textColor=SLATE_500,
    spaceAfter=4, leading=11, alignment=TA_CENTER)

STYLE_CALLOUT = ParagraphStyle('AgentmanCallout',
    fontName='Helvetica', fontSize=11, textColor=CHARCOAL_950,
    spaceAfter=8, leading=15, alignment=TA_LEFT,
    backColor=AGENTMAN_75, borderPadding=12)

Stat Block Layout (MANDATORY — Prevents Overlap)

CRITICAL: Never place stat blocks as consecutive centered paragraphs. Large font stat numbers (28pt) will overlap their labels and adjacent stats. Always use a Table to contain side-by-side stat blocks.

def agentman_stat_row(stat_pairs, page_width=7.0*inch):
    """Build a row of stat blocks using a Table to prevent overlap.

    Args:
        stat_pairs: list of (value, label) tuples, e.g. [("$264.35", "AAPL Price"), ...]
        page_width: available content width (letter page minus margins)

    Returns:
        A Table flowable with stat blocks that will NOT overlap.
    """
    n = len(stat_pairs)
    col_w = page_width / n

    # Row 1: stat numbers (large terracotta)
    # Row 2: stat labels (small slate)
    data = [
        [Paragraph(val, STYLE_STAT_NUMBER) for val, _ in stat_pairs],
        [Paragraph(lbl, STYLE_STAT_LABEL) for _, lbl in stat_pairs],
    ]
    t = Table(data, colWidths=[col_w] * n)
    t.setStyle(TableStyle([
        ('ALIGN',   (0, 0), (-1, -1), 'CENTER'),
        ('VALIGN',  (0, 0), (-1, -1), 'MIDDLE'),
        ('TOPPADDING',    (0, 0), (-1, 0), 10),
        ('BOTTOMPADDING', (0, 0), (-1, 0), 2),
        ('TOPPADDING',    (0, 1), (-1, 1), 0),
        ('BOTTOMPADDING', (0, 1), (-1, 1), 10),
        ('GRID',    (0, 0), (-1, -1), 0, WHITE),  # invisible grid
    ]))
    return t

# Usage example — NEVER do Paragraph+Paragraph stacking for stats:
# WRONG (causes overlap):
#   elements.append(Paragraph("$264.35", STYLE_STAT_NUMBER))
#   elements.append(Paragraph("AAPL Price", STYLE_STAT_LABEL))
#
# CORRECT:
#   elements.append(agentman_stat_row([
#       ("$264.35", "AAPL Price"),
#       ("$303.33", "GOOGL Price"),
#   ]))

Section Divider (Terracotta Accent Line)

from reportlab.platypus import HRFlowable

def agentman_section_divider():
    """Create a 3pt terracotta accent line between sections."""
    return HRFlowable(
        width="100%", thickness=3,
        color=AGENTMAN_500, spaceBefore=6, spaceAfter=12
    )

def agentman_thin_divider():
    """Create a 1pt warm separator."""
    return HRFlowable(
        width="100%", thickness=1,
        color=AGENTMAN_150, spaceBefore=4, spaceAfter=8
    )

Page 1 Template (Mandatory First-Page Content)

def build_cover_page(elements, report_title, date_str, subtitle=None):
    """Build the mandatory Agentman cover page content.

    Args:
        elements: list of flowables to append to
        report_title: main title (will be prefixed with "Agentman —")
        date_str: date string for the report
        subtitle: optional subtitle (e.g. "Stock Comparison Report")
    """
    # Title — must start with "Agentman —"
    elements.append(Paragraph(f"Agentman — {report_title}", STYLE_TITLE))

    # Subtitle — if provided, uses smaller font with clear spacing
    if subtitle:
        elements.append(Paragraph(subtitle, STYLE_SUBTITLE))

    # Author — MUST appear immediately after title, non-negotiable
    elements.append(Paragraph("Author: Agentman Equity Research Assistant", STYLE_AUTHOR))

    # Date and data source
    elements.append(Paragraph(f"{date_str} | Data Source: Financial Modeling Prep", STYLE_AUTHOR))

    # Terracotta accent line
    elements.append(agentman_section_divider())

    return elements
from reportlab.platypus import Frame, PageTemplate
from reportlab.lib.units import inch
from datetime import date

def agentman_footer(canvas, doc):
    """Draw Agentman footer on every page except the first."""
    if doc.page > 1:
        canvas.saveState()
        # Footer rule — terracotta accent line
        canvas.setStrokeColor(AGENTMAN_500)
        canvas.setLineWidth(1)
        canvas.line(0.75*inch, 0.6*inch, doc.width + 0.75*inch, 0.6*inch)
        # Footer text
        canvas.setFont('Helvetica', 8)
        canvas.setFillColor(SLATE_500)
        footer_text = f"Agentman Equity Research Assistant · {date.today().strftime('%B %d, %Y')} · Data: FMP"
        canvas.drawCentredString(doc.width/2 + 0.75*inch, 0.4*inch, footer_text)
        # Page number
        canvas.drawRightString(doc.width + 0.75*inch, 0.4*inch, f"{doc.page}")
        canvas.restoreState()

Chart Colors (matplotlib)

import matplotlib
import matplotlib.pyplot as plt

# Agentman chart palette — warm, monochromatic progression
CHART_COLORS = [
    '#CC785C',   # AGENTMAN_500 — primary series
    '#292322',   # CHARCOAL_900 — secondary series
    '#E3DACC',   # AGENTMAN_150 — tertiary series
    '#A65945',   # AGENTMAN_600 — fourth series
    '#8B4A38',   # AGENTMAN_700 — fifth series
    '#D97757',   # AGENTMAN_400 — sixth series
    '#475569',   # SLATE_600 — seventh series
    '#703B2D',   # AGENTMAN_800 — eighth series
]

def apply_agentman_chart_style():
    """Apply Agentman brand colors to matplotlib globally."""
    matplotlib.rcParams['axes.prop_cycle'] = matplotlib.cycler(color=CHART_COLORS)
    matplotlib.rcParams['axes.edgecolor'] = '#292322'
    matplotlib.rcParams['axes.labelcolor'] = '#141413'
    matplotlib.rcParams['xtick.color'] = '#475569'
    matplotlib.rcParams['ytick.color'] = '#475569'
    matplotlib.rcParams['grid.color'] = '#E3DACC'
    matplotlib.rcParams['figure.facecolor'] = '#FFFFFF'
    matplotlib.rcParams['font.family'] = 'sans-serif'
    matplotlib.rcParams['font.sans-serif'] = ['Calibri', 'Helvetica', 'Arial']

fpdf2 Implementation

Color Constants (Copy-Paste This Exactly)

from fpdf import FPDF

# ============================================================
# AGENTMAN BRAND COLORS — fpdf2 RGB tuples
# ============================================================
AGENTMAN_800_RGB = (112, 59, 45)     # Badge text, deep emphasis
AGENTMAN_700_RGB = (139, 74, 56)     # Cover accent
AGENTMAN_600_RGB = (166, 89, 69)     # Negative emphasis
AGENTMAN_500_RGB = (204, 120, 92)    # PRIMARY ACCENT
AGENTMAN_400_RGB = (217, 119, 87)    # Highlight text
AGENTMAN_200_RGB = (230, 168, 144)   # Badge borders
AGENTMAN_150_RGB = (227, 218, 204)   # Table borders
AGENTMAN_100_RGB = (246, 234, 230)   # Table header fill
AGENTMAN_75_RGB  = (240, 238, 230)   # Highlight row bg
AGENTMAN_50_RGB  = (250, 249, 245)   # Alternate row bg
CHARCOAL_950_RGB = (20, 20, 19)      # Body text
CHARCOAL_900_RGB = (41, 35, 34)      # Section titles
CHARCOAL_800_RGB = (61, 55, 53)      # Secondary text
SLATE_600_RGB    = (71, 85, 105)     # Secondary text
SLATE_500_RGB    = (100, 116, 139)   # Footer text
WHITE_RGB        = (255, 255, 255)

fpdf2 Table Helper

def fpdf2_draw_agentman_table(pdf, headers, data, col_widths=None):
    """Draw an Agentman-styled table using fpdf2."""
    if col_widths is None:
        col_widths = [pdf.epw / len(headers)] * len(headers)

    # Header row — light warm fill + terracotta text
    pdf.set_fill_color(*AGENTMAN_100_RGB)
    pdf.set_text_color(*AGENTMAN_500_RGB)
    pdf.set_draw_color(*AGENTMAN_150_RGB)
    pdf.set_font('Helvetica', 'B', 11)
    for i, header in enumerate(headers):
        pdf.cell(col_widths[i], 10, header, border=1, fill=True, align='C')
    pdf.ln()

    # Body rows — alternating backgrounds
    pdf.set_font('Helvetica', '', 10)
    for row_idx, row in enumerate(data):
        if row_idx % 2 == 0:
            pdf.set_fill_color(*WHITE_RGB)
        else:
            pdf.set_fill_color(*AGENTMAN_50_RGB)
        pdf.set_text_color(*CHARCOAL_950_RGB)
        for i, cell in enumerate(row):
            font_style = 'B' if i == 0 else ''
            pdf.set_font('Helvetica', font_style, 10)
            pdf.cell(col_widths[i], 9, str(cell), border=1, fill=True,
                     align='L' if i == 0 else 'C')
        pdf.ln()

weasyprint Implementation

Complete CSS Stylesheet (Copy-Paste This Exactly)

/* ============================================================
   AGENTMAN BRAND STYLESHEET — weasyprint
   Apply to ALL HTML before converting to PDF
   ============================================================ */
@page {
  size: letter;
  margin: 0.75in;
  @bottom-center {
    content: "Agentman Equity Research Assistant · Data: FMP";
    font-family: Calibri, 'Segoe UI', sans-serif;
    font-size: 8pt;
    color: #64748B;
  }
  @bottom-right {
    content: counter(page);
    font-family: Calibri, 'Segoe UI', sans-serif;
    font-size: 8pt;
    color: #64748B;
  }
}

* { font-family: Calibri, 'Segoe UI', sans-serif; box-sizing: border-box; }
body { color: #141413; font-size: 11pt; line-height: 1.4; }

/* HEADINGS — charcoal, NEVER colored */
h1 { color: #292322; font-size: 24pt; font-weight: bold; margin-bottom: 4pt; }
h2 { color: #292322; font-size: 18pt; font-weight: bold; border-bottom: 3px solid #CC785C; padding-bottom: 4pt; margin-top: 18pt; }
h3 { color: #292322; font-size: 14pt; font-weight: bold; border-bottom: 2px solid #CC785C; padding-bottom: 3pt; margin-top: 14pt; }
h4 { color: #3D3735; font-size: 12pt; font-weight: bold; margin-top: 10pt; }

/* AUTHOR LINE — must appear on page 1 */
.author { color: #475569; font-size: 11pt; margin-bottom: 12pt; }
.date { color: #475569; font-size: 11pt; margin-bottom: 16pt; }

/* TABLE HEADERS — CRITICAL: light fill + terracotta text, NEVER dark */
table { border-collapse: collapse; width: 100%; margin: 12pt 0; }
th, thead td {
  background-color: #F6EAE6 !important;
  color: #CC785C !important;
  font-weight: 600;
  font-size: 11pt;
  padding: 9px 14px;
  border-bottom: 1px solid #E3DACC;
  text-align: center;
}

/* TABLE BODY */
td {
  color: #141413;
  padding: 9px 14px;
  border-bottom: 1px solid #E3DACC;
  font-size: 10pt;
}
td:first-child { font-weight: 600; color: #141413; text-align: left; }
tr:nth-child(odd) td { background-color: #FFFFFF; }
tr:nth-child(even) td { background-color: #FAF9F5; }
tr.highlight td { background-color: #F0EEE6; }

/* STAT BLOCKS — use .stat-row container to prevent overlap */
.stat-row {
  display: flex;
  justify-content: space-evenly;
  align-items: flex-start;
  gap: 16px;
  margin: 18pt 0;
}
.stat-block {
  flex: 1;
  text-align: center;
  padding: 12px 8px;
  min-width: 0;         /* prevent flex overflow */
}
.stat-number {
  font-size: 28pt;
  font-weight: bold;
  color: #CC785C;
  text-align: center;
  line-height: 1.2;     /* CRITICAL: prevents overlap with label */
  margin-bottom: 4pt;
}
.stat-label {
  font-size: 10pt;
  color: #475569;
  text-align: center;
  line-height: 1.3;
  margin-top: 0;
}
/* NEVER place .stat-number and .stat-label as siblings outside a .stat-block container */

/* EMPHASIS — terracotta family only, NEVER green/red/blue */
.positive { color: #CC785C; font-weight: 700; }
.negative { color: #A65945; font-weight: 700; }
.highlight-text { color: #D97757; font-weight: 600; }
.neutral { color: #141413; font-weight: 600; }

/* CALLOUT BLOCKS */
.callout { background: #F0EEE6; border-radius: 4px; padding: 16px 20px; margin: 12pt 0; }
.callout h3, .callout h4 { color: #141413; font-weight: bold; border: none; margin-top: 0; }
.callout p { color: #475569; }

/* BADGES — all same color, tier via text wording */
.badge {
  display: inline-block;
  background: #F6EAE6; color: #703B2D;
  border: 1px solid #E6A890;
  padding: 3px 10px; border-radius: 4px;
  font-size: 10pt; font-weight: 600;
}

/* SCORE BARS */
.score-bar { background: #E3DACC; height: 6px; border-radius: 3px; width: 100%; }
.score-fill { background: #CC785C; height: 6px; border-radius: 3px; }

/* FOOTER */
footer, .footer { font-size: 8pt; color: #64748B; text-align: center; margin-top: 24pt; }

/* DISCLAIMER */
.disclaimer { font-size: 8pt; color: #64748B; font-style: italic; text-align: center; margin-top: 24pt; }

/* ACCENT LINE */
hr { border: none; border-top: 3px solid #CC785C; margin: 12pt 0; }
hr.thin { border-top: 1px solid #E3DACC; }

/* BANNED: green, red, amber, blue, navy, gradients, shadows, opacity, box-shadow */

Element-to-Color Quick Reference

Report Element Color Hex Constant
Table header fill Light brand #F6EAE6 AGENTMAN_100
Table header text Terracotta #CC785C AGENTMAN_500
Table borders Warm separator #E3DACC AGENTMAN_150
Section titles Charcoal #292322 CHARCOAL_900
Section underline Terracotta #CC785C AGENTMAN_500
Body text Charcoal #141413 CHARCOAL_950
Secondary text Slate #475569 SLATE_600
Footer/meta Slate muted #64748B SLATE_500
Alternate row bg Cream #FAF9F5 AGENTMAN_50
Highlight row bg Warm cream #F0EEE6 AGENTMAN_75
Stat numbers Terracotta #CC785C AGENTMAN_500
Positive emphasis Terracotta bold #CC785C AGENTMAN_500
Negative emphasis Deep terracotta bold #A65945 AGENTMAN_600
Badges (all tiers) Light brand bg + deep text #F6EAE6 bg, #703B2D text AGENTMAN_100 + AGENTMAN_800
Cover accent Terracotta #8B4A38 AGENTMAN_700

Typography

Font: Helvetica (built-in to reportlab) or Calibri (if registered). Use Calibri when available, Helvetica as fallback.

Element Size Weight Alignment
Report title 24pt (leading 30) Bold Left
Subtitle 13pt (leading 17) Regular Left
Section heading (h2) 16–18pt Bold Left
Subsection heading (h3) 13–14pt Bold Left
Body text 10.5–11pt (leading 15) Regular Left
Stat number 28pt (leading 34) Bold Center (in table cell)
Stat label 10pt (leading 13) Regular Center (in table cell)
Table header 11pt Bold (600) Center
Table body 10pt Regular Center (data), Left (labels)
Footer 8pt Italic Center

NEVER center body paragraphs. Left-align all body text.


Banned Colors

Color Hex Why Banned
Green (success) #10B981 Traffic-light aesthetic (except ✓ symbol)
Amber (warning) #F59E0B Dashboard alert feel
Red (error) #EF4444 Alarm aesthetic (except ✗ symbol)
Blue (info) #3B82F6 Generic corporate, dilutes brand
Navy #1B3A5C Corporate default, not Agentman
Cyan #0891B2 Too techy
Pure black #000000 Use #141413 (CHARCOAL_950) instead
Generic grays #333, #666, #999, #ccc Use brand palette equivalents
Any gradient N/A Solid fills only

The ONE exception: #10B981 (green ✓) and #EF4444 (red ✗) for comparison table symbols ONLY — never for text, backgrounds, borders, or any other element.


Overlap Prevention Rules

Text overlap is the #1 layout defect. Follow these rules strictly:

  1. Stat blocks MUST use agentman_stat_row() table layout. Never stack STYLE_STAT_NUMBER and STYLE_STAT_LABEL paragraphs sequentially — the 28pt number will overlap the 10pt label. Always wrap stat pairs in a Table.
  2. Every ParagraphStyle MUST have explicit leading (line height). The leading value must be at least 1.2x the fontSize. Without explicit leading, reportlab defaults can cause text to overlap.
  3. Title + subtitle need STYLE_TITLE (leading=30) then STYLE_SUBTITLE (leading=17). Never use the same style for both — the large title font will collide with text below if spacing is insufficient.
  4. Use Spacer(1, 12) between unrelated content blocks to guarantee breathing room.
  5. Side-by-side content MUST use a Table, not separate centered Paragraphs. Centered paragraphs stack vertically and overlap.
  6. Set spaceBefore and spaceAfter on every style. Never rely on implicit spacing.

Pre-Generation Checklist

Before executing ANY PDF generation code, verify:

  • No text overlap — Stat blocks use agentman_stat_row() table layout, title/subtitle have separate styles with adequate leading
  • Color constants defined — ALL Agentman constants are in the script
  • No library defaults — No colors.black, colors.grey, getSampleStyleSheet(), default table styles
  • Document author set"Agentman Equity Research Assistant" in metadata
  • Page 1 author line — "Author: Agentman Equity Research Assistant" displayed before data
  • Title starts with "Agentman —"
  • Table headers are LIGHTAGENTMAN_100 (#F6EAE6) fill + AGENTMAN_500 (#CC785C) text
  • No dark table headers — No navy, dark blue, dark brown, charcoal, or any saturated color as header fill
  • No banned colors — No green, red, amber, blue, navy, or generic grays
  • Warm bordersAGENTMAN_150 (#E3DACC), not black/gray
  • Alternating rows — White / AGENTMAN_50 (#FAF9F5) cream
  • Terracotta budget — Max 3 AGENTMAN_500 elements per section
  • Footer on every page — "Agentman Equity Research Assistant · {date} · Data: FMP"
  • No gradients, shadows, or opacity — Solid fills only
  • Charts use brand palette — Never library defaults
  • Visual weight feels 70/20/10 — Mostly charcoal, some cream, rare terracotta

Agentman PDF Style Guide

Agentman brand styling for PDF report generation. Use when generating ANY PDF report using reportlab, fpdf2, or weasyprint. Provides mandatory color constants, table styles, document setup, typography, page layout, and a pre-generation checklist. Ensures every PDF uses the Agentman warm terracotta/charcoal palette instead of generic library defaults. Load this skill BEFORE writing any PDF generation code.

designv1.0.0
pdfreportlabfpdf2weasyprintbrand-guidelinesdesign-systemagentmanequity-research

Included Files

  • SKILL.md(25.8 KB)— shown above

Ready to use this skill?

Attach it to your Agentman agents, or clone it and make it yours.

Free to use. Clone this and any other public skill with a free Agentman account — publishing your own is free up to 10 skills.

AgentSkills is more than a copy-paste library

  • Versioned, not pastedEdit a skill once and every agent using it follows the new version.
  • Shared with your teamOne library with per-skill access control and a record of who did what.
  • One connectionA single MCP link works across Claude, ChatGPT, Cursor and Agentman agents.
Explore AgentSkills →

Or try it in an assistant