# Header & footer bundle — authoring prompt

The **Design → Menu → Header & footer bundle** card takes a zip that replicates your
main site's header and footer, so the blog reads as part of that site rather than a
separate property.

The fastest way to build one is to hand the prompt below to a coding assistant
(Claude Code / Cursor / Copilot) **inside your website's own repository**. It needs to
read your real header and footer components — their markup, classes, colours, fonts
and logo assets — not guess from a screenshot.

If your site is not in a repo you can point an assistant at, the same prompt works
against saved page source, but expect to fix more by hand.

---

```
Build an Inkhost chrome bundle (zip) that replicates this site's header and footer
so my Inkhost blog looks like part of this site.

Source of truth: the actual header/footer components in this repo (and their
classes, CSS variables, fonts and logo assets). Read them first. Replicate the
rendered look — do not invent a new design.

Output a folder `inkhost-bundle/` in the repo root containing:
  inkhost.json
  header.html
  footer.html
  styles.css
  any font/image assets referenced, at bundle-relative paths

inkhost.json exactly this shape (a raw JSON object, never a quoted string):
{
  "header": { "html": "header.html", "css": ["styles.css"] },
  "footer": { "html": "footer.html", "css": ["styles.css"] }
}

Hard constraints — the uploader sanitizes, and violations are silently stripped:
- Each HTML file is a FRAGMENT (start at <header> / <footer>). No <html>, <head>,
  <body>, <style>, <link>, <script>, <meta>, <iframe>, <form>, <input>.
- ZERO JavaScript. No hydration, no toggles, no dropdown that needs JS. If the real
  header has a JS mobile menu, replace it with a CSS-only layout that wraps or
  stacks at small widths. No checkbox hack (inputs are stripped).
- Allowed tags only: header footer nav main section article aside div span a img
  picture source figure figcaption hgroup address time ul ol li dl dt dd button p
  strong em b i u s small mark abbr sub sup blockquote cite q code pre hr br h1-h6
  label, and inline SVG (svg path g use defs symbol rect circle ellipse polygon
  polyline line text tspan linearGradient radialGradient stop clipPath mask).
- Rendered inside a Shadow DOM, so NOTHING inherits from the page. styles.css must
  be fully self-contained: ship your own reset for the elements you use (box-sizing,
  margin/padding zeroing, font-family, line-height, list-style, a{color,
  text-decoration}, button reset). Do not rely on a framework preflight or on
  utility classes existing.
- No utility-framework classes (Tailwind etc.) in the HTML unless styles.css defines
  every one of them literally. Prefer hand-written, prefixed classes.
- Resolve every CSS variable to a literal value, or redeclare the variables inside
  styles.css on :host / the root element of each fragment.
- No @import (stripped) and no remote font or image URLs. Every <img src> and every
  CSS url() must point at a file inside the bundle — an unresolved src is blanked
  and an unresolved url() becomes about:blank. Copy the needed woff2/png/svg files
  into inkhost-bundle/ and declare @font-face in styles.css with bundle-relative
  url()s, or fall back to a system font stack that matches closely.
- `position: fixed` is stripped. Use static or sticky.
- Prefer inline SVG for the logo over an image file.
- Link hrefs: absolute URLs to the main site (https://example.com/...). Keep one
  link pointing at the blog's public address. External hrefs are fine.
- Support light/dark via prefers-color-scheme only if the site does; no toggle.
- Limits: <=200 files, 5MB per file, 20MB total, header/footer HTML <=200KB each,
  combined CSS <=1MB.

Then zip the CONTENTS of the folder (inkhost.json must sit at the zip root, not
inside a nested directory):
  cd inkhost-bundle && zip -r ../inkhost-bundle.zip . -x '.DS_Store' '__MACOSX/*'

Finally, write a throwaway local HTML file that mounts header.html + styles.css and
footer.html + styles.css into two real shadow roots, open it, and screenshot it at
1280px and 390px wide. Compare against the live site's header and footer and fix the
gaps before handing over the zip.
```

---

## Uploading

1. **Design → Menu → Header & footer bundle** → choose the zip. It uploads as a new
   **draft** version; nothing on the live blog changes yet.
2. Hit **Preview** next to that version. It opens your header and footer framing a
   placeholder page body.
3. **Activate** when it looks right. Previous versions stay listed, so activating an
   older one is the rollback.

## Manifest variations

Both entries are optional — declare a header, a footer, or both. A shared top-level
`styles` covers any entry without its own `css`, and a bare filename is shorthand for
`{ "html": ... }`:

```json
{ "header": "header.html", "footer": "footer.html", "styles": "styles.css" }
```

Unknown top-level keys (`name`, `version`, `brand`, …) are ignored, so a richer
manifest still parses.

## Why the constraints

The bundle renders inside a **Shadow DOM** on every blog page. That isolates it in
both directions: your CSS cannot leak into the blog's own styles, and the blog's
theme cannot leak into your header. The cost is that your fragment inherits nothing —
a bundle that quietly depends on the host page's reset or utility classes will look
correct in your editor and unstyled on the blog.

Everything is sanitized on upload: scripts, event handlers, forms, embeds and unsafe
URLs never reach a reader's browser. `@font-face` blocks are hoisted out of the
Shadow DOM into the document head (where they work reliably), and fonts and images
are re-served from the Inkhost origin with CORS headers, so they still load when the
blog is proxied under your own domain.
