---
name: property-market-report
description: Use when a user asks for an A4 print-ready property market report for a specific area, branded with an estate agent's design tokens and logos, illustrated by up to 10 property listings that hyperlink back to their source URLs. Triggers include "create a market report for <area>", "market data sheet for <postcode>", "Bishop's Stortford / CM23 / Sawbridgeworth report", or any request that names market metrics for an area and a set of property URLs to feature.
---

# Property Market Report

A 4-page A4 PDF: cover (full-bleed hero with light logo), market summary + headline KPIs, activity + property-type distribution + at-a-glance table, then a featured-listings grid where every tile hyperlinks to its source URL.

## Typography is fixed; only colours and logos come from the agent

The report has its own typographic identity — a luxury serif stack pinned in the template:

- **Display** — Cormorant Garamond (italic for headlines, KPI values, prices, addresses)
- **Body** — Lora
- **Sans / labels** — Inter (eyebrows, KPI labels, chips, footer meta)

**Never substitute the agent's body or display fonts**, even if their `DESIGN.md` specifies different families. The market report intentionally reads as an editorial / luxury document across every brand it renders for; the agent's identity comes through the **palette and logo only**. If a brand insists on its own typography, that's a different deliverable — likely a brochure, not a market report.

## Inputs (never invented)

- **`design_tokens_path`** — path to a `DESIGN.md` that tokenises the agent's brand. Resolve it from `brand_source` at runtime: when `brand_source` is a URL, the path is `<brand_dir>/DESIGN.md` for whatever brand directory the orchestrator created (or already had on disk); when `brand_source` is a directory path, the file is at `<brand_source>/DESIGN.md`. Read the canonical hex values directly; never substitute "close" colours. **Only colour tokens are consumed** — the report imports `primary` (e.g. teal-900), `primary_dark`, `accent` (e.g. gold-500), `paper`, `paper_banded`, and `rule`. Any typography, spacing, or radius tokens in the agent's DESIGN.md are *ignored by design*.
- **`logo_light_path`** / **`logo_dark_path`** — PNG/SVG. Light = white-on-dark version (for the teal-toned cover); dark = full-colour version (for body-page headers). When supplied, the renderer emits an `<img>` for the logo; when omitted, it falls back to a Cormorant-Garamond text wordmark using `brand.name` + `brand.tagline`. The text-wordmark fallback is acceptable for brands whose logo is essentially a serif-typeset name; for richer marks, supply the files.
- **`property_urls`** — list of up to 10 source URLs from any UK estate-agent or portal site (Loop-CRM tenants, Rightmove, Zoopla, OnTheMarket, etc.). Each must resolve to a single property listing page. Reject more than 10; the layout breaks at >10 cards.
- **`market_data`** — flat dict of numbers (average asking, average sold, £/sqft, YoY growth, demand rating, days-on-market, property-type distribution, sample size, period). Source from a market intelligence API (PropertyData / Land Registry / ONS) or paste from an existing report. **The period is the *generated* date, not whatever appears in the URL slug** — the Market Trak `oct-2025` slug describes a snapshot from May 2026 (Oct 2025 was the trailing window). Use the report-page's stated `Generated` value.

## How the skill renders

`references/template.html` is the single source of truth for the layout. It carries `<!-- REPLACE: <slot> -->` comments — never edit the structure directly; edit the template once, the slot names stay stable.

`references/render.py` consumes three plain-Python inputs (brand · market · properties), substitutes them into the template, then drives Chrome headless to produce the PDF and zips the HTML+images bundle. Run it with `python3 render.py inputs.json` where `inputs.json` carries:

```json
{ "out_dir": "...", "filename_stem": "...",
  "brand":   { "name", "tagline", "primary", "primary_dark", "accent",
               "paper", "paper_banded", "rule" },
  "market":  { "location_name", "location_code", "period", "cover_title",
               "cover_hero", "page2_photo",
               "summary_headline", "summary_paragraphs",
               "avg_asking", "avg_sold", "psf", "yoy_growth",
               "demand_rating", "demand_gauge_position",
               "price_growth_note", "demand_note",
               "for_sale", "sales_per_month", "turnover_pct", "dom",
               "n_props", "type_dist" },
  "properties": [{ "url", "slug", "address", "price_kind", "price",
                   "beds", "baths", "type" }, ...]   /* ≤ 10 */
}
```

If any `<!-- REPLACE: ... -->` slot is left unfilled after substitution the renderer raises — a contract gap, not a silent default.

## Outcome contract

Every report ships these artefacts in a single output directory:

- `index.html` — single self-contained file, no build step, opens directly. Webfonts loaded from Google Fonts.
- `<area>-<period>.pdf` — 4–5 page A4 PDF rendered via Chrome headless `--print-to-pdf`. 4 pages when there are ≤ 5 listings, 5 pages when 6–10 listings (the listings split across pages 4 and 5). Anything beyond 5 pages means content is overflowing — tighten KPI tile padding or listing card aspect ratio until it fits.
- `<area>-<period>-web.zip` — packaged bundle containing `index.html` + `img/`, ready to drop into a static-site host. Self-contained except for the Google Fonts CSS link, which is fetched at view time.
- `img/<NN>-<slug>.jpg` — one image per property, 0-padded index, slug from the source URL. Produced by the **property-socials** skill in landscape format (1200×628) where possible; each report-page card uses this branded tile, not the raw hero. If a property has no local brochure scaffold, run `real-estate-brochure:property-extract` → `real-estate-brochure:property-brochure` → `property-socials` first; the report consumes the resulting `og-landscape-main.jpg`.

## Visual contract

The design tokens carry the contract. Two rules survive any token re-skin:

1. **Cover** — full-bleed property hero behind a vertical gradient scrim (top ~55% opacity → bottom ~95% opacity in the surface-deep colour). Light logo top-left, area name in display-italic, tagline in accent colour, four-up meta strip across the foot (Report · Location · Period · Status).
2. **Listing tiles** — every property card is a hyperlinked `<a>` wrapping a tile that pairs the property-socials landscape image with: address (display italic, 14–16pt), price (display italic, 14–16pt), spec chips (sans, pill-shaped). The `<a>` opens the source URL in a new tab. Tile borders use the rule colour from the design tokens, not arbitrary greys.

## Pagination contract

A4 portrait, 210×297 mm, 16 mm horizontal padding, 18 mm vertical. Each `<section class="page">` is `height:297mm; overflow:hidden; page-break-after:always`. If Chrome's `mdls -name kMDItemNumberOfPages` returns >4, content is overflowing — diagnose with `pdftoppm -png -f <n> -l <n>` to see which page bleeds, then trim that page only (smaller KPI padding, tighter photo-strip aspect ratio, fewer listing cards per page). Never reach for `min-height` to "let it grow" — the printed deliverable is the deliverable.

## Listings page layout

Up to 10 properties fit on **two body pages** of the report (page 4 and an optional page 5 if >5 listings):

- ≤ 5 listings → one page, cards stacked at 70mm photo column × 5/3 aspect (~42mm tall photo).
- 6–10 listings → two pages, 5 per page, same dimensions.
- Each card: `<a href="<source_url>" target="_blank" rel="noopener">` wraps the whole card. Tile photo on the left, meta on the right (address · locality · price · chip row). Hover state is irrelevant for print but should still feel clickable in the HTML preview (subtle teal-tint background-shift, no underline on the address).

## Source attribution

The disclaimer block on the final page must name:

- All market-data sources (Land Registry, ONS, PropertyData, Rightmove, Zoopla, local agents) by name.
- Image attribution: `Property imagery: <agent>.co.uk via property-socials`.
- A short "Accuracy" line and a short "Investment" line — see the existing `bishops-stortford-*` reports for canonical wording.

## Failure modes seen

- **Logo invisible in preview.** The IDE preview panel can't always resolve relative `img/` paths or large base64 data URIs. The deliverable PDF is the source of truth; viewing the HTML in a real browser (or via `python3 -m http.server`) is the second source of truth. Don't burn iterations chasing preview-panel artefacts.
- **Date drift from URL slug.** A Market Trak URL like `…-oct-2025?…` does not mean the report is October 2025. Always trust the `Generated:` field on the source page.
- **Page 3 / page 4 overflow.** The default Cormorant Garamond + Lora stack is slightly taller-set than a sans default. KPI tile padding and panel padding need to come down (~5 mm not 7 mm) for serif typography to fit alongside the photo strip on page 3 and two listing cards on page 4.
- **Property-socials skipped.** A report that drops the raw listing-CDN image straight into a tile (whether `loop-app.b-cdn.net/propertyimages/...jpg`, `media.rightmove.co.uk/...`, or any other host) breaks the brand contract — the tiles have no overlay, no scrim, no address copy. Always run the OG pipeline; if it can't run, surface the gap, don't substitute.
- **Anchor links dead in PDF.** Chrome `--print-to-pdf` preserves `<a href>` as live PDF annotations. Verify by opening the PDF in Preview and clicking a listing — if the link is dead, the HTML wrapped a `<div>` instead of an `<a>`.

## Out of scope

- The market-data fetch itself (owned by whichever PropertyData / Land Registry adapter the operator uses).
- The property-extract / property-brochure / property-socials pipeline (owned by those skills).
- HTML emails / web embeds of the report. The deliverable is A4 PDF + the self-contained HTML preview.
