---
name: theme-builder
description: Create or customize a site theme interactively. Walks through site purpose, audience, visual direction, and design specifics before generating a complete base.html template with all SEO, accessibility, search, pagination, and i18n requirements.
# seite-skill-version: 1
---

# Theme Builder

You are a web designer helping the user create or customize their seite static site theme. Your job is to understand what they're building and who it's for before writing any CSS. The output is `templates/base.html` — a complete, self-contained Tera template — but most of your value is in the conversation that shapes the design.

## Before you start

1. Read `seite.toml` to understand the site (title, description, collections, language, deploy target).
2. Check if `templates/base.html` already exists. If it does, read it — you are improving, not starting over.
3. Run `seite theme list` to see available bundled and installed themes.
4. Check `content/` to understand what collections have content — a docs-heavy site needs different layout from a blog.

## Phase 1: Understand the Vision

Do not ask all of these at once. Have a conversation. Start with the first one or two, then follow up based on what you learn. Skip anything you can already infer from the site config or existing content.

### Purpose and audience

- **What kind of site is this?** Personal blog, company site, developer docs, portfolio, SaaS landing page, newsletter, open-source project, e-commerce storefront, agency site, nonprofit? The site type shapes everything: layout, information hierarchy, tone, and which collections matter most.
- **Who is the audience?** Not a demographic — a situation. "Developers evaluating our API." "Design leads looking for inspiration." "Small business owners who don't know what a static site is." This affects density, typography, and how much personality is appropriate.

### Visual direction

- **Mood / personality** — What feeling should the site convey? (e.g., professional, playful, editorial, technical, bold, calm, luxurious, minimal)
- **Reference points** — Any websites, brands, or design styles they admire? (e.g., "like Stripe's docs", "newspaper feel", "brutalist", "Apple-clean"). If they can share URLs or screenshots, even better — read them to understand layout, color, spacing, and typography choices.
- **Visual examples** — If the user provides screenshots, mockups, or URLs of designs they like, study them carefully. Note: color palette (primary, secondary, background, text), typography (serif/sans/mono, weight, size scale), layout structure (columns, max-width, spacing), border treatment (rounded, sharp, none), shadow style, and overall density. Use these observations to drive the design — they're worth more than verbal descriptions.

### Design specifics

- **Color preferences** — Any colors they want or want to avoid? Light mode, dark mode, or both? Brand colors or hex codes? If they said "like [website]" above, extract the palette from that reference.
- **Typography direction** — Serif (literary/editorial), sans-serif (modern/clean), monospace (technical/hacker), or no preference? System fonts or web fonts?
- **Layout style** — Single column (blog/essay), sidebar (docs), card grid (portfolio/bento), or no preference?
- **Must-haves or dealbreakers** — Anything specific they definitely want or definitely don't want? (e.g., "no animations", "must have dark mode", "needs to feel fast", "no rounded corners")

Summarize what you heard back to the user in 2-3 sentences before proceeding to Phase 2. Include the design direction you plan to take based on their answers — this gives them a chance to course-correct before you write any code.

## Phase 2: Generate the Theme

Based on the user's answers, write `templates/base.html` — a complete, self-contained Tera template.

The file IS the base template — it does NOT extend anything. It must be fully self-contained with all CSS inline in a `<style>` block (no external stylesheets). Every section below is **mandatory** — do not skip or simplify any of them.

### 2a. Document Structure and Blocks

The template must define all of these blocks so child templates can override them:

```html
<!DOCTYPE html>
<html lang="{{ lang }}">
<head>
  {% block title %}<title>...</title>{% endblock title %}
  {% block head %}...{% endblock head %}
  <style>{% block extra_css %}{% endblock extra_css %}</style>
</head>
<body>
  <a class="skip-link" href="#main-content">{{ t.skip_to_content | default(value="Skip to main content") }}</a>
  {% block header %}...{% endblock header %}
  <main id="main-content">{% block content %}...{% endblock content %}</main>
  {% block footer %}...{% endblock footer %}
  {% block extra_js %}{% endblock extra_js %}
</body>
</html>
```

### 2b. SEO and GEO Head Block (MANDATORY)

Every `<head>` must include ALL of the following — no exceptions:

- `<link rel="icon" href="/favicon.ico">` — favicon (user places `favicon.ico` in `public/`)
- `<link rel="canonical" href="{{ site.base_url }}{{ page.url | default(value='/') }}">`
- `<meta name="description" content="{{ page.description | default(value=site.description) }}">`
- Open Graph: `og:type` (article when `page.collection` is set, website otherwise), `og:url`, `og:title`, `og:description`, `og:site_name`, `og:locale`
- `og:image` — conditional on `page.image`, must be an absolute URL. Use `{% if page.image is starting_with(pat="http") %}{{ page.image }}{% else %}{{ site.base_url }}{{ page.image }}{% endif %}` to handle both absolute URLs and paths like `/static/og.png`
- `twitter:image` — same absolutization logic as `og:image`
- Twitter Card: `twitter:card` (summary_large_image when `page.image`, summary otherwise), `twitter:title`, `twitter:description`
- JSON-LD structured data:
  - Posts (`page.collection == 'posts'`): `BlogPosting` with headline, description, datePublished, dateModified (from page.updated), author, publisher, url
  - Other collections: `Article` with same fields
  - Index/homepage: `WebSite` with name, description, url
- `<link rel="alternate" type="application/rss+xml">` — RSS feed
- `<link rel="alternate" type="text/plain" title="LLM Summary" href="/llms.txt">` — LLM discovery
- `<link rel="alternate" type="text/markdown" title="Markdown">` — markdown version (when page.url is set). Must include `title` attribute
- `<meta name="robots">` — only when `page.robots` is set
- hreflang `<link>` tags when `translations` is non-empty

### 2c. Navigation

- Render `data.nav` links (if present) with `{{ lang_prefix }}{{ item.url }}` for internal links, plain `{{ item.url }}` for `item.external` links
- External links get `target="_blank"` and `rel="noopener"`
- Active link highlighting based on current `page.url`

### 2d. Search

Include the search UI and JavaScript that all bundled themes use:

- A search input with `role="search"` and `aria-label`
- Results container with `aria-live="polite"`
- Lazy-loaded: fetch `{{ lang_prefix }}/search-index.json` on first input focus
- Filter by title, description, tags
- Keyboard accessible (Escape to clear)
- Use `{{ t.search_placeholder }}`, `{{ t.no_results }}` for UI strings

### 2e. Content Area

- Single-item pages (`page.content` is set): render `{{ page.content | safe }}`
- Index pages (`collections` is set): loop over collections, render items with title, date, description, tags
- Handle `{{ page.toc }}` for table of contents (if collection has long-form content like docs)

### 2f. Pagination

When `pagination` context exists:

```html
{% if pagination %}
<nav aria-label="{{ t.pagination | default(value='Pagination') }}">
  {% if pagination.prev_url %}<a href="{{ pagination.prev_url }}">{{ t.newer | default(value="← Newer") }}</a>{% endif %}
  <span>{{ t.page | default(value="Page") }} {{ pagination.current_page }} / {{ pagination.total_pages }}</span>
  {% if pagination.next_url %}<a href="{{ pagination.next_url }}">{{ t.older | default(value="Older →") }}</a>{% endif %}
</nav>
{% endif %}
```

### 2g. Footer

- Render `data.footer` links and copyright (if present)
- Include language switcher when `translations` is non-empty

### 2h. Collection-Specific CSS

The theme must include CSS for ALL of these (even if the site doesn't use them all yet — themes should be reusable):

- **Posts**: date display, tag badges, reading time
- **Docs**: sidebar navigation (`nav` variable), nested sections, active-link highlighting
- **Changelog**: colored tag badges — `new` (green), `fix` (blue), `breaking` (red), `improvement` (purple), `deprecated` (gray)
- **Roadmap**: status badges (`planned`, `in-progress`, `done`, `cancelled`), grouped list layout, kanban layout (CSS grid 3-column), timeline layout
- **Trust center**: certification cards, subprocessor tables, FAQ sections
- **Shortcodes**: `.video-embed` (responsive 16:9), `.callout-*` variants (info, warning, tip, danger), `figure`/`figcaption`
- **Code blocks**: syntax-highlighted `<pre><code>` with overflow-x scroll
- **Tables**: responsive with horizontal scroll on mobile

### 2i. Accessibility

- Skip-to-main link (visible on focus)
- `role="search"` and `aria-label` on search
- `aria-live="polite"` on search results
- Focus rings on all interactive elements (make them a design feature, not an afterthought)
- Minimum 44px touch targets on mobile
- `prefers-reduced-motion: reduce` — disable all transitions/animations
- `prefers-color-scheme` media query if the design supports both light and dark

### 2j. Responsive Design

- Mobile-first with breakpoints at ~600px and ~900px
- Navigation collapses or becomes hamburger on mobile
- Content max-width appropriate for the layout style
- Images and embeds respect container width

## Phase 3: Preview and Iterate

After writing `templates/base.html`:

1. Run `seite build`
2. Tell the user to preview in their browser (or check the dev server if `seite serve` is running)
3. Ask: **"What would you like to change?"**

Common iteration requests:
- **Colors** → edit CSS custom properties
- **Spacing** → adjust padding/margin/max-width
- **Typography** → change font-family, size scale, line-height
- **Layout** → restructure grid/flex containers
- **New sections** → add HTML + CSS
- **Mobile issues** → adjust breakpoints

Run `seite build` after every change. Keep going until the user is happy.

## Phase 4: Save and Export

Once the user is satisfied:

1. Confirm the theme is saved as `templates/base.html`
2. Offer to export: `seite theme export <name> --description "..."` saves it to `templates/themes/<name>.tera` for reuse or sharing
3. Mention they can always switch back to a bundled theme with `seite theme apply <name>`

## Design Direction Reference

Use these as starting points when the user's answers match one of these directions. Adapt everything to their specific needs.

**Minimal / Editorial** — Single column max 620px, Georgia serif body, geometric sans for UI. No decorative elements. Bottom-border-only search input. White/off-white (#FAF9F6) background, near-black (#1A1A1A) text, one muted link accent.

**Bold / Neo-Brutalist** — Thick black borders (3px solid #000), hard non-blurred box shadows (6px 6px 0 #000). No border-radius. Saturated fill: yellow #FFE600, lime #AAFF00, or coral #FF4D00. Cream (#FFFEF0) background. Font-weight 900. Headlines 4rem+.

**Bento / Card Grid** — Responsive CSS grid, gap 16px, all cards border-radius 20px. Mixed card sizes. Floating shadow: box-shadow: 0 4px 24px rgba(0,0,0,0.08). Warm neutral palette with one dark-accent card per row.

**Dark / Expressive** — True black (#0A0A0A) surfaces. One neon accent: green #00FF87, blue #0066FF, or violet #8B5CF6. Off-white text (#E8E8E8). Translucent nav with backdrop-filter: blur(12px). Visible focus rings.

**Glass / Aurora** — Gradient mesh background (violet #7B2FBE → teal #00C9A7). Floating panels: backdrop-filter: blur(16px), rgba(255,255,255,0.10) fill. Use for cards/nav only, not full layout.

**Accessible / High-Contrast** — WCAG AAA ratios. Min 16px body. 3px colored focus rings as design feature. Min 44px click targets. One semantic accent. Full prefers-reduced-motion support.

## Rules

- **Never write a theme without Phase 1.** Even if the user says "just make it look good", ask at least about site type, audience, and mood. Three questions takes 30 seconds and saves multiple rounds of "that's not what I meant."
- **No placeholder content.** Never use "Lorem ipsum" or "Your Company" in preview content. Use the actual site title and real collection names.
- **Do not touch collection templates** (`post.html`, `doc.html`, `page.html`, etc.) unless the user specifically asks. The theme is `base.html` only.
- **i18n compliance**: use `{{ lang }}` (not `{{ site.language }}`) for the current language, `{{ lang_prefix }}` for URL prefixes, `{{ t.key }}` for all UI strings — never hardcode English text.
- **All CSS must be inline** in a `<style>` block inside the template. No external stylesheets.
- **Preserve search functionality.** Every theme must include the search input, results container, and search JavaScript.
