# Copyright (c) 2025 Patrick Motsch # All rights reserved. """Default style definitions and style resolution for document rendering.""" from typing import Any, Dict DEFAULT_STYLE: Dict[str, Any] = { "fonts": { "primary": "Calibri", "monospace": "Consolas", }, "colors": { "primary": "#24292e", "secondary": "#586069", "accent": "#0366d6", "background": "#FFFFFF", }, "documentTitle": { "sizePt": 28, "weight": "bold", "color": "#24292e", "spaceBeforePt": 0, "spaceAfterPt": 18, "align": "center", }, "headings": { "h1": {"sizePt": 22, "weight": "bold", "color": "#24292e", "spaceBeforePt": 24, "spaceAfterPt": 8}, "h2": {"sizePt": 18, "weight": "bold", "color": "#24292e", "spaceBeforePt": 20, "spaceAfterPt": 6}, "h3": {"sizePt": 14, "weight": "bold", "color": "#586069", "spaceBeforePt": 16, "spaceAfterPt": 4}, "h4": {"sizePt": 12, "weight": "bold", "color": "#586069", "spaceBeforePt": 12, "spaceAfterPt": 3}, }, "paragraph": {"sizePt": 11, "lineSpacing": 1.5, "color": "#24292e", "align": "left"}, "table": { "headerBg": "#f6f8fa", "headerFg": "#24292e", "headerSizePt": 10, "bodySizePt": 10, "rowBandingEven": "#f6f8fa", "rowBandingOdd": "#FFFFFF", "borderColor": "#e1e4e8", "borderWidthPt": 0.5, "borderStyle": "grid", "bandingEnabled": True, "cellPaddingPt": 4, }, "list": {"bulletChar": "\u2022", "indentPt": 18, "sizePt": 11}, "image": {"defaultWidthPt": 480, "maxWidthPt": 800, "alignment": "center"}, "codeBlock": {"fontSizePt": 9, "background": "#f6f8fa", "borderColor": "#e1e4e8"}, "coverPage": { "titleSizePt": 28, "subtitleSizePt": 16, "authorSizePt": 12, "dateSizePt": 12, "titleColor": "#24292e", "subtitleColor": "#586069", }, "caption": { "sizePt": 10, "color": "#586069", "italic": True, "align": "center", }, "page": { "format": "A4", "marginsPt": {"top": 60, "bottom": 60, "left": 60, "right": 60}, "showPageNumbers": True, "headerHeight": 30, "footerHeight": 30, "headerLogo": None, "headerText": "", "footerText": "", }, } def deepMerge(base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]: """Recursively merge override into base. Both dicts left unchanged; returns new dict.""" result = {} for key in base: if key in override: baseVal = base[key] overVal = override[key] if isinstance(baseVal, dict) and isinstance(overVal, dict): result[key] = deepMerge(baseVal, overVal) else: result[key] = overVal else: result[key] = base[key] for key in override: if key not in base: result[key] = override[key] return result def resolveStyle(agentStyle: dict | None = None) -> Dict[str, Any]: """Resolve the effective style: ``DEFAULT_STYLE <- agentStyle``. Precedence (lowest to highest): platform defaults, then any explicit per-call ``agentStyle`` override. With no override this returns plain :data:`DEFAULT_STYLE`. Context-aware styling is handled by the AI enhancement step in ``mainServiceGeneration.renderReport``. """ resolved = dict(DEFAULT_STYLE) if agentStyle: resolved = deepMerge(resolved, agentStyle) return resolved