# Page — companion property landing page (`index.html`)

The web bundle includes a **single-page property landing site** at `output/web/index.html`. The brochure is a folio for download; the landing page is the "for sale" web page a property micro-site or a portal page links to. They share the same web-tier images in `images/` but present the property differently — the brochure as an editorial document; the landing page as a continuous, scrollable web page.

The landing page is **mandatory in the web bundle**. A property-brochure run that ships the brochure web bundle without `index.html` is incomplete.

## Canonical reference — `references/index.html` is the only starting point

`references/index.html` ships with this skill alongside `references/template.html`. It is the **only** acceptable starting point for the landing page, exactly as `template.html` is the only acceptable starting point for the brochure. Every property-brochure run that produces a web bundle MUST start by copying `references/index.html` to `<property_dir>/output/web/index.html` and substituting the markers — never re-build the file from scratch from the prose in this reference.

The subsections below describe **why** the canonical is the way it is. They are **not** instructions to rebuild it. If the canonical file already encodes a rule (e.g. drop cap on the first paragraph of every body-block, the 3-slide Ken-Burns rotator with reduced-motion fallback, the hamburger drawer with full nav set on mobile), copying the canonical IS following the rule. The reference file's leading comment block lists the editorial decisions baked in — read it once before any substitution.

### Forbidden starting points

Per the same logic as the brochure's *Forbidden template sources*, do **not** start the landing page from any of:

- A sibling property's rendered `output/web/index.html` (will inherit that property's hand-tuned text + image refs)
- A previous version of `references/index.html` cached anywhere outside the live skill folder
- The prose alone, hand-copying CSS/markup blocks from the section descriptions below
- A "modern landing page generator" or any tool that produces a layout from scratch

A run that reconstructs index.html from prose, even if the result *looks* close to the canonical, drifts every brochure cycle. The dropcap, the rotator timing, the `BRAND-SLUG-logo-dark.png` filename pattern, the sub-nav scroll behaviour, the drawer markup — all of it lives literally in `references/index.html`. Copy it.

## How to populate

Two steps:

1. **Bulk-substitute literal placeholders** (one find/replace pass each):
   - `PROPERTY-SLUG` → property slug (e.g. `warblers-lodge`). Rewrites every image src (`PROPERTY-SLUG-NN.webp`, `PROPERTY-SLUG-floorplan.png`, `PROPERTY-SLUG-hero-N-<role>.webp`) and the in-bundle PDF link (`PROPERTY-SLUG-brochure.pdf`).
   - `BRAND-SLUG` → brand slug (e.g. `rossmargetts`). Rewrites the brand logo path (`BRAND-SLUG-logo-dark.png` — the dark-art variant on the warm-paper top nav). The index.html canonical only uses the dark variant; the light variant is brochure-only.

2. **Substitute each `<!-- REPLACE: ... -->` block** with property-specific copy drawn from the seller brief and `property.json`. Walk the file top-to-bottom: `<title>`, meta description, top-nav utility links, drawer nav + foot, sticky sub-nav left/right, hero info-card (tag, title, address, price, meta, four spec cells, three link slots, CTA mailto subject), three hero slides + alt text, six body-block sections (Story, The Home, Bedrooms, The Garden, The Area — eyebrow + h2 + paragraphs), six photo grids (four cells each, 4:3 cover), floor-plan section meta, key-facts grid (~15 rows), CTA strip, footer.

The Sparrows Farm exemplar copy that ships in the canonical stays in place until you replace it — it is intentionally a working example, not lorem ipsum, so the agent can see what good looks like at every stage.

## Reference register

The landing page follows the editorial-property-portal pattern set by **The Modern House** (themodernhouse.com/sales-list/). Key conventions copied from that pattern:

- A single full-width hero image with a floating info-card overlaid bottom-left.
- Sticky sub-nav appearing after the hero scrolls past — title + price on the left, key links + "Request viewing" on the right.
- Body copy in a narrow centred column (~720px max-width) interleaved with full-width photo grids.
- Photo grids are **2-column 4:3 cells** with no captions — the image speaks for itself.
- Black "Interested? Let's talk." CTA strip near the bottom.
- Minimal footer: agent contact, legal disclaimer, colophon.

The landing page **does not** have a "More Photos" gallery hidden behind a button. Every photograph used in the brochure appears in the body, distributed across photo grids in narrative order. The user wants every image visible without an extra click.

## Info-card sizing — specs and links MUST sit on a single row each

The hero info-card is a fixed-width block (~380 px wide on desktop). Two rows inside it have a recurring failure mode:

1. **The specs row** — `BEDS · BATHS · SQ FT · ACRES` — is four uppercase labels separated by gold-soft "·" dots. At wide letter-spacing (>0.16em) and font-size 10px, four labels routinely overflow a 320 px card. Default to `font-size: 9.5px; letter-spacing: 0.10em; gap: 0; justify-content: space-between` so the four cells distribute across the full width with `·` separators inserted as `::before` pseudo-elements (margin 0 8px on either side).
2. **The links row** — `FLOOR PLAN · BROCHURE · VIDEO TOUR` — is three uppercase labels with gold-underlines. At letter-spacing 0.22em the labels wrap onto two lines each (`FLOOR / PLAN`, `VIDEO / TOUR`). Default to `font-size: 9.5px; letter-spacing: 0.14em; gap: 16px; flex-wrap: nowrap` and apply `white-space: nowrap` to each `<a>`.

The card width is the lever of last resort — widen from 320 → 380 px before reducing typography below 9 px. Below 9 px the labels lose their tracked-caps editorial register.

Verification: at 1440 px viewport, the rendered specs row reads as one line with the four cells visually balanced; the links row reads as one line with no `<br>` introduced by the browser. If either row wraps, either widen the card by 20 px increments or tighten letter-spacing by 0.02em increments — never reduce font-size below 9 px or drop a `·` separator.

## Hero — rotating Ken-Burns stage

The hero is **not a single static image**. It rotates between **three exemplar shots** with a slow camera-style pan/zoom on each — the editorial property-portal pattern (Modern House, Inigo) where the hero suggests "this property has more than one moment". Three is the right number: enough to give the viewer three distinct facets (front exterior, principal interior, garden complex), few enough that the viewer sees the full cycle within ~18 seconds without feeling rushed.

### The three exemplar slides

The three slides are chosen by their *register*, not their slot index. Pick one from each of these categories:

| Slide | Role | Typical brochure slot |
|---|---|---|
| 1 (main) | The strongest hero — usually the cover image (golden-hour exterior or the property's most "you-arrive-here" moment) | Slot 01 |
| 2 (interior) | The principal interior moment — usually the open-plan kitchen-dining hero or the principal sitting room | Slot 04 or 05 |
| 3 (outdoor / garden) | The garden complex, summerhouse, pool, or a secondary exterior at a different time of day | Slot 12, 24, or 26 |

If the property has no kitchen/garden distinction (e.g. an apartment), substitute "best second interior" and "best third interior". The pattern is **three different rooms or moments**, not three angles of the same shot.

### Dedicated `*-hero-N-<role>.webp` tier

The hero shows each image **fullscreen at viewport scale**, with a 1.05–1.20× Ken-Burns transform on top. That means a body-tier 1300 px @ q82 webp will visibly soften at typical desktop and Retina viewports. The hero needs its own encode tier:

| Setting | Body tier (rest of `index.html`) | **Hero tier** |
|---|---|---|
| Long edge | 1300 px (hero) / 1100 px (story) / 800 px (thumb) | **source resolution** (no `-resize`) — typically 1536–1600 px |
| Quality | q82 / q80 / q76 | **q88** |
| Filename | `<slug>-NN.webp` | `<slug>-hero-1-main.webp`, `<slug>-hero-2-<role>.webp`, `<slug>-hero-3-<role>.webp` |
| Typical size | 25–300 KB each | 200–600 KB each |

Encoder invocation (no `-resize` so source pixels are preserved):

```bash
cwebp -q 88 -m 6 -mt "<source>" -o "<slug>-hero-N-<role>.webp"
```

### Markup

Three slides stacked in a `.hero-stage` container; each `.hero-slide` is the same dimensions as the hero, layered with `position: absolute; inset: 0`. Each contains exactly one `<img>`.

```html
<section class="hero">
  <div class="hero-stage" aria-label="<Property> — three views" role="img">
    <div class="hero-slide s1"><img src="images/<slug>-hero-1-main.webp" alt="…golden-hour exterior…"></div>
    <div class="hero-slide s2"><img src="images/<slug>-hero-2-<role>.webp" alt="…interior…"></div>
    <div class="hero-slide s3"><img src="images/<slug>-hero-3-<role>.webp" alt="…garden…"></div>
  </div>
  <div class="info-card">…</div>
</section>
```

The accessible label sits on `.hero-stage` (not on each slide) because to a screen reader the stage is a single visual element. Each `<img>` keeps its own `alt` for image-grouping crawlers.

### CSS — pure-CSS rotator + Ken-Burns

The rotator is **CSS-only**, no JS. Three slides on an 18-second master cycle, each visible for ~5.4s with a 0.5s crossfade between. The rotator works the same way on a static-site host as in a Playwright preview — there's no `setInterval`, no library, no failure mode.

```css
.hero-stage { position: absolute; inset: 0; overflow: hidden; }
.hero-slide { position: absolute; inset: 0; opacity: 0; will-change: opacity; }
.hero-slide img { width: 100%; height: 100%; object-fit: cover;
  transform-origin: 50% 50%; will-change: transform; }

/* Stagger: each slide's animation starts 6s apart */
.hero-slide.s1 { animation: heroFade 18s 0s  infinite; }
.hero-slide.s2 { animation: heroFade 18s 6s  infinite; }
.hero-slide.s3 { animation: heroFade 18s 12s infinite; }
.hero-slide.s1 img { animation: heroKb1 18s 0s  infinite ease-out; }
.hero-slide.s2 img { animation: heroKb2 18s 6s  infinite ease-out; }
.hero-slide.s3 img { animation: heroKb3 18s 12s infinite ease-out; }

@keyframes heroFade {
  0%   { opacity: 0; }  3%   { opacity: 1; }
  33%  { opacity: 1; }  36%  { opacity: 0; }
  100% { opacity: 0; }
}

/* Each slide gets a different camera motion so the rotator doesn't
   feel mechanical. Push-in, pan-and-zoom-left, tilt-up are good defaults. */
@keyframes heroKb1 {
  0%   { transform: scale(1.04) translate(0%, 0%); }
  36%  { transform: scale(1.16) translate(-1.2%, 0.4%); }
  100% { transform: scale(1.16) translate(-1.2%, 0.4%); }
}
@keyframes heroKb2 {
  0%   { transform: scale(1.06) translate(1.5%, 0%); }
  36%  { transform: scale(1.18) translate(-1%, -0.8%); }
  100% { transform: scale(1.18) translate(-1%, -0.8%); }
}
@keyframes heroKb3 {
  0%   { transform: scale(1.05) translate(0%, 1%); }
  36%  { transform: scale(1.18) translate(0.8%, -1.4%); }
  100% { transform: scale(1.18) translate(0.8%, -1.4%); }
}

/* Reduced-motion users see a static slide-1 */
@media (prefers-reduced-motion: reduce) {
  .hero-slide.s1 { opacity: 1; animation: none; }
  .hero-slide.s2, .hero-slide.s3 { opacity: 0; animation: none; }
  .hero-slide img { animation: none; transform: none; }
}
```

### Timing rationale

The 18-second master cycle is chosen because:

- 3 slides × 6 seconds each = each slide on screen long enough to be noticed but short enough that the loop doesn't feel slow.
- The 540ms crossfade (3% of 18s) is long enough to feel deliberate, short enough not to feel sluggish.
- The Ken-Burns scale ramp 1.04 → 1.18 over 6.5 seconds (the full visible window) translates to ~2.2% per second — slow enough to read as "drifting" rather than "moving", which is the editorial register.

Avoid going under 4.5s per slide (feels twitchy) or over 8s (loses energy). 6s is the sweet spot.

### Reduced-motion contract

Some viewers find subtle continuous motion uncomfortable. The `@media (prefers-reduced-motion: reduce)` rule turns off both the crossfade and the Ken-Burns transforms, holding slide 1 statically. This is required, not optional — accessibility regulations in several jurisdictions treat persistent motion as a barrier.

## Page sections (top to bottom)

| Section | Content | Notes |
|---|---|---|
| Top nav | Brand wordmark/logo centred; deep links left (Story · Home · Garden · Area); utility links right (Brochure · Listing · Enquire) | Use the brand's *dark* logo variant — the nav background is paper |
| Hero | **Rotating Ken-Burns stage** (3 slides — main, interior, garden — crossfading every 6s with a slow camera pan/zoom on each); floating info-card bottom-left with FOR SALE tag, italic property name, address, price, freehold, beds/baths/sqft/acres specs row, three text links (Floor plan · Brochure · Video tour), and a dark REQUEST VIEWING CTA | See **Hero — rotating Ken-Burns stage** above. The info-card is on a translucent paper background with a 1px gold top-edge |
| Sticky sub-nav | Property name + price on the left; Floor plan · Brochure · Video tour · Request viewing on the right | Hidden until the hero scrolls past; reveals via JS scroll-listener |
| Intro body | "Of place & pedigree" eyebrow; italic editorial headline; 1–2 paragraph introduction | First chapter of the brochure, condensed |
| Photo grid 1 | 4 establishing shots — drone aerial, front elevation, golden-hour exterior, etc. | All web-tier `<slug>-NN.webp` |
| Body section "The Home" | 2–3 paragraph description of the layout | Reflects the brochure's Chapter II/III content |
| Photo grids 2–3 | 8 interior shots in two grids | Kitchens, dining, hearth, sitting rooms |
| Body section "Bedrooms & baths" | Paragraph about the sleeping floor | Reflects Chapter IV |
| Photo grid 4 | 4 bedroom/bathroom shots | Principal + others |
| Body section "Pool, outdoor kitchen & summerhouse" | Paragraph distinguishing the three garden features | Reflects Chapter V |
| Photo grid 5 | 4 garden-complex shots | Pool, summerhouse, outdoor kitchen |
| Body section "The Area" | Paragraph about the local area, transport, schools | Reflects Chapter VI; sourced partly from the **seller brief Q11–14** |
| Photo grid 6 | Final 3–4 shots — wider grounds, atmospheric closing | Use a hero re-run as the final cell if needed to fill |
| Floor plan section | Two-column: floor plan image left, areas table right | "Floor 1 · 2,573 sq ft" style table |
| Key facts section | 3-column grid of Material Information rows | Tenure, council tax, broadband, mobile, flood risk, construction, etc. |
| CTA strip | Black band, italic "Interested? Let's talk.", three contact CTAs (phone, email, request-viewing) | Mirrors the back-page tagline |
| Footer | Agent contact card, legal disclaimer (CGI/AI line included), colophon | Minimal |

## Image references — body grid uses `<slug>-NN.webp`; hero rotator uses `<slug>-hero-N-<role>.webp`

The page has two image tiers:

1. **Hero rotator** — three dedicated `<slug>-hero-1-main.webp`, `<slug>-hero-2-<role>.webp`, `<slug>-hero-3-<role>.webp` files at source resolution and q88. See **Hero — rotating Ken-Burns stage** above. These are *additional* files; they don't replace the body-tier images even when sourced from the same originals — the body-tier `<slug>-03.webp` is still used in the photo grids.
2. **Body photo grids** — `<slug>-NN.webp` at the body-tier (1300/1100/800 px @ q82/80/76) — the same images the brochure HTML references. Both `brochure.html` and `index.html` resolve them to the same file under `output/web/images/`.

Distribute every brochure image across the photo grids — typically 24–28 unique images across 6 grids of 4. If the count doesn't divide cleanly (e.g. 23 images for 6 grids of 4 = 24 cells), reuse the cover hero in the final cell as a closing visual.

## Typography and palette

The landing page uses the same three-font system as the brochure:
- **Cormorant Garamond** for italic display headlines (info-card title, body section h2, "Interested? Let's talk." CTA, floor plan title).
- **Lora** for body paragraphs (and address line, info-card meta).
- **Inter** for tracked-caps utility (nav links, eyebrows, key-facts labels, button text).

Palette is paper / ink / bronze / antique gold — matching the brochure's tokens. The landing page introduces no new tokens; it re-skins them in a continuous-scroll layout.

## Mobile responsive — hero must stack vertically below ~760px

On narrow viewports the hero **stops being a floating-card-over-photo overlay** and stacks: photo on top, info card below. A floating overlay at mobile widths inevitably covers part of the rotator, defeating the point of having three exemplar slides. The reference register (Modern House mobile) handles this exactly the same way.

The rules:

1. **The hero loses its fixed height** at `≤ 760px`. `.hero { height: auto; min-height: 0; display: flex; flex-direction: column; }`.
2. **The hero stage gets a bounded aspect ratio** so the absolute-positioned slides have a positioning context. `4/3` works at 760px tablets, `5/4` at very narrow phones (≤ 440px). The aspect ratio is the key — without it the absolute children collapse to 0 height.
3. **The info card switches from absolute to static**. Drop the floating shadow and gold top-edge; let it flow as a normal block under the photo, with the page's paper background.

```css
@media (max-width: 760px) {
  .hero {
    height: auto; min-height: 0;
    display: flex; flex-direction: column;
    background: var(--paper);
  }
  .hero-stage {
    position: relative;
    width: 100%;
    aspect-ratio: 4/3;
    flex: 0 0 auto;
    background: var(--ink);     /* shows through any letterboxing */
  }
  .info-card {
    position: static;
    left: auto; right: auto; bottom: auto;
    width: auto;
    margin: 0;
    padding: 24px 24px 28px;
    box-shadow: none;
    border-top: 1px solid var(--rule);
    background: var(--paper);
  }
  .info-card .title { font-size: 30px; }
  .info-card .specs { font-size: 10px; }
  .info-card .links { font-size: 10px; }

  /* Footer colophon — stack the property line and copyright on
     separate rows on mobile. The desktop layout uses
     justify-content: space-between to put them on one row, which
     overflows on narrow viewports. */
  footer .colophon {
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
  }
}

@media (max-width: 440px) {
  .hero-stage { aspect-ratio: 5/4; }   /* taller frame at narrow phones */
}
```

### General mobile-stack principle

Every multi-column block in the page becomes single-column or vertically-stacked at the mobile breakpoint. The pattern is consistent:

| Block | Desktop | Mobile (≤ 760px) |
|---|---|---|
| Hero | Photo with floating overlay info-card | Photo above, info-card stacks below |
| Photo grids | 2-column | 1-column |
| Floor plan section | Plan left, areas table right | Plan above, table below |
| Key-facts grid | 3-column | 2-column at 760, 1-column at 440 |
| Footer colophon | Property line left, copyright right (single row) | Property line above, copyright below (stacked rows) |
| Top-nav | Deep links + centred wordmark + utility group | Burger + wordmark, all else in drawer |

When adding a new multi-column section to the page, add a matching mobile rule that flattens it to single-column or stacked. Without an explicit rule, the desktop layout will overflow narrow viewports.

### Top-nav collapse — hamburger drawer at ≤ 960px

Desktop layout has four section-deep links on the left (Story · Home · Garden · Area), the wordmark logo in the centre, and three utility links on the right (Brochure · Listing · Enquire). The full bar needs roughly **1100 px** of horizontal room to breathe. Below ~960 px the deep-section labels overlap the centred logo, and a "just hide the deep links" approach leaves a lopsided bar with the centred logo crammed against the surviving right-side group. The right answer is a **hamburger-revealed drawer**.

The breakpoint cascade:

1. **At ≤ 960 px**: collapse the *entire* desktop nav (left + right) into a hamburger button on the left and a centred logo. The hamburger reveals a right-side drawer with **every** nav link plus the CTA — no items lost.
2. **At ≤ 760 px**: the hero stops being an overlay (see *Mobile responsive — hero must stack vertically* above). Nav already collapsed.
3. **At ≤ 440 px**: tighten the hero stage's aspect ratio (5/4 instead of 4/3) so the photo doesn't dominate a tiny phone viewport.

The 960 px threshold is the right cut-off because at ≤ 960 the full nav is *visually* broken even if it doesn't quite overflow the box; at > 960 the desktop nav reads cleanly. Don't tune it lower (you'll see overlapping links at intermediate widths) and don't tune it higher (you'll lose the desktop nav at standard laptop widths).

### Drawer markup

The drawer is a fixed-position panel that slides in from the right. The markup sits as a sibling of `.topnav` (not inside it — the drawer overlays the page chrome).

```html
<nav class="topnav">
  <button class="burger" aria-label="Open menu" aria-expanded="false" aria-controls="drawer">
    <span></span><span></span><span></span>
  </button>
  <div class="left">…</div>      <!-- hidden ≤ 960px -->
  <div class="center">…</div>    <!-- always visible -->
  <div class="right">…</div>     <!-- hidden ≤ 960px -->
</nav>

<div class="drawer" id="drawer" aria-hidden="true">
  <button class="drawer-close" aria-label="Close menu">&times;</button>
  <nav class="drawer-nav">
    <a href="#story">Story</a>
    <a href="#home">The Home</a>
    <a href="#garden">The Garden</a>
    <a href="#area">The Area</a>
    <a href="#floorplan">Floor plan</a>
    <a href="#facts">Key facts</a>
    <a href="<slug>-brochure.pdf" download>Download brochure</a>
    <a href="<video-url>" target="_blank">Watch video tour</a>
    <a href="<listing-url>" target="_blank">View on <agent></a>
    <a href="mailto:<agent-email>" class="drawer-cta">Enquire</a>
  </nav>
  <div class="drawer-foot">
    <agent name> · <agency> · <office><br>
    <a href="tel:+…"><phone></a>
  </div>
</div>
```

The drawer is **fuller** than the desktop nav — it includes deep-section links (Story / Home / Garden / Area), every utility link (brochure / video / listing), the **Enquire CTA**, and an agent-contact footer. Mobile users get *more* navigation options than desktop users, on the assumption that scrolling to a section is harder on a small screen. This matches the Inigo / Modern House mobile pattern.

### Drawer interaction

- The hamburger button toggles `aria-expanded` and the `.open` class on `.drawer`.
- A backdrop element is created lazily by the script (no markup pollution), darkening the page behind the drawer when open.
- Clicking the backdrop, the close button, **or any link inside the drawer** closes it (so a section-link click both navigates and closes).
- `Escape` closes.
- `body.drawer-open { overflow: hidden }` prevents scroll-leak under the drawer.
- The hamburger animates to an X via two `transform`s on the outer spans + `opacity: 0` on the middle span — the standard CSS-only hamburger.

The whole drawer system is roughly **40 lines of JS** + ~50 lines of CSS. No library, no framework, no router. It works the same on a static-site host as in a Playwright preview.

### Verification

When testing at multiple viewports, screenshot the topnav at:

- **1280 × 900** — full desktop. Burger hidden; left + centre + right all visible.
- **960 × 800** — collapse trigger. Burger appears; left + right hidden; logo centred (now via flex `margin: 0 auto` since `.center` switched from absolute to static).
- **390 × 844** — phone. Same as 960 plus the hero stacking from the previous section.

Open the drawer at 390 × 844; verify all 9 links + CTA visible; verify backdrop dims the page; click a section link and verify both navigation *and* drawer-close happen.

### Mobile hero verification

When testing at mobile widths, screenshot at three viewports: **390 × 844** (iPhone 14 Pro), **414 × 896** (iPhone 11), and **320 × 568** (iPhone SE). Confirm at each:

- The hero photo is fully visible (not covered by the info card).
- The info card flows beneath the photo with paper background.
- The top-nav has clean horizontal spacing (logo doesn't touch the right links).
- The rotator still cycles all three slides (the Ken-Burns transforms are scale-relative, not viewport-relative, so they work at any width).

## Bundling and smoke-test

`index.html` is included in `<slug>-web.zip` automatically (the zip command zips everything in `output/web/`). After zipping, the smoke-test must include both `brochure.html` AND `index.html`:

```bash
for f in brochure.html index.html cover-print.jpg images/<slug>-01.webp images/<brand>-logo-dark.png <slug>-brochure.pdf; do
  echo "$(curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8765/$f) $f"
done
```

Both pages must return 200 and render correctly. The landing page should not exhibit overflow on a 1440px-wide viewport at desktop sizes; on narrow mobile (<760px) it should reflow to single-column photo grids.

## When to regenerate

`index.html` is regenerated whenever the brochure's image set changes (new photos, swapped slot assignments) or whenever the brochure's chapter copy materially changes (the landing page mirrors the brochure's narrative). Cosmetic CSS-only changes to the brochure don't require a landing-page regenerate. The landing page is *not* part of the canonical print archive — it lives only in `output/web/` and the zip.
