Overview#
Keystone is a website for a design-build construction firm, built as a WordPress block theme. The
fictional brand is Corbel Design-Build, an architecture studio and general contractor in
Milwaukee, Wisconsin. The theme has a blueprint-style home page with a hero drawing that draws
itself in, count-up figures, services, selected work, a process timeline, accreditations and client
references; a project portfolio with type filters and search; a case study with a facts table, a
before/after slider and a drawing gallery with a lightbox; a services page with sectors, contract
models and an FAQ; a five-step cost estimator that feeds a quote request; an about page with the
story, values, leadership, safety record and open roles; a contact page with live office status, a
map and a contact form; and a 404 page. It is version 1.0.0 (see template.json and style.css),
works with WordPress 7.1 and PHP 7.4 or newer, and is the WordPress version of the HTML template of
the same name. See it live at
freeframe.dev/templates/keystone.
Headings, copy, cards, lists, buttons and images are core WordPress blocks arranged in block
patterns, so you edit them in the block editor without touching code. The interactive parts (the
estimator, the project filter bar, the before/after slider, the gallery lightbox, the forms and the
office status) work as in the HTML version: they are small Custom HTML blocks driven by
assets/js/main.js. Colours and fonts are design tokens in theme.json: change them in
Appearance > Editor > Styles and the whole site follows.
Quick start#
Requirements: WordPress 7.1 or newer and PHP 7.4 or newer. No plugins are needed.
- Download
keystone.zipfrom freeframe.dev/templates/keystone (the WordPress tab). - In your WordPress admin go to Appearance > Themes > Add New Theme > Upload Theme, choose the zip and click Install Now, then Activate. The theme is listed as Freeframe Keystone.
- Go to Appearance > Keystone setup and click Create the demo pages. This creates the Home, Projects, Malt House Lofts (the case study), Services, Project estimator, About and Contact pages from the theme's page patterns, sets Home as the front page (Settings > Reading) and creates the header menu. Pages that already exist with the same slug are left alone, so it is safe to click it again.
- Visit your site. Edit any page in Pages, and the header, footer and templates in Appearance > Editor.
You can also try the theme without installing anything: the Try it in WordPress button on freeframe.dev opens it in WordPress Playground (WordPress running in your browser) with the demo pages already set up.
To work on the theme's files locally you need Node.js 24 and pnpm; WordPress itself runs in WordPress Playground, so there is no PHP, web server or database to install:
pnpm install
pnpm dev # builds the CSS, then starts WordPress with the theme at http://127.0.0.1:9400pnpm dev signs you in as admin (password password) and creates the demo pages. The site is
rebuilt from scratch every time you start it; your edits to theme files are live, edits made in the
WordPress admin are not kept.
Pages#
Each page is a page pattern (in Patterns > Keystone pages) made of section patterns. Every section is also offered on its own in the block inserter under Patterns > Keystone.
| Page | Slug | Page pattern | Sections (pattern files in patterns/) |
|---|---|---|---|
| Home | / |
page-home.php |
home-hero (line drawing and count-up figures), home-services, selected-work, process, accreditations, client-references, cta |
| Projects | /projects/ |
page-projects.php |
projects-hero, project-list (type filter, search and nine project cards), projects-cta |
| Malt House Lofts | /project/ |
page-project.php |
case-study-hero, case-study-brief (drawing, brief and project facts), before-after, gallery (with the lightbox), outcome, related-projects, project-cta |
| Services | /services/ |
page-services.php |
services-hero, service-commercial, service-residential, service-renovation, service-architecture, sectors, contract-models, faq, cta |
| Project estimator | /estimate/ |
page-estimate.php |
estimate-hero, estimator (the five steps, the quote request and the cost summary), estimate-bar (the cost bar on phones) |
| About | /about/ |
page-about.php |
about-hero, story (with the timeline), values, leadership, safety-record (with the chart), careers, cta |
| Contact | /contact/ |
page-contact.php |
contact-hero, contact-form (form and the two office cards), service-area (map), direct-lines |
| 404 | any missing URL | templates/404.html |
404 |
The cta band ("Have a site? Let's put numbers on it.") is one pattern shared by Home, Services
and About: insert it anywhere from Patterns > Keystone. Posts use templates/single.html; the
blog, archives and search results use templates/index.html, templates/archive.html and
templates/search.html.
Project structure#
freeframe-keystone/
style.css theme header (name, version, requirements, license); no styles
theme.json design tokens: palette, fonts, font sizes, spacing, layout widths, button
functions.php loads the files in inc/
inc/setup.php stylesheet and script (with its strings), editor styles, the `js`
class script, theme colour and favicon, pattern categories
inc/icons.php registers assets/icons/*.svg for the Icon block
inc/icon-labels.php the icons' names shown in the editor
inc/block-styles.php button block styles
inc/site-setup.php Appearance > Keystone setup: creates the demo pages and the menu
templates/ page.html (pages), page-with-title.html, single.html, index.html,
archive.html, search.html, 404.html
parts/ header.html and footer.html (they show the header and footer patterns)
patterns/ every section and page (PHP files with block markup)
assets/css/theme.css the compiled stylesheet (do not edit: built from src/)
assets/css/editor.css the same for the block editor (generated by src/editor-css.mjs)
assets/js/main.js estimator, project filter, slider, lightbox, forms, office status...
assets/icons/ SVG icons for the Icon block
assets/img/ project drawings, team portraits, logo, favicon, social image
assets/fonts/ Barlow, Barlow Condensed and IBM Plex Mono, with their licenses
src/theme.css the Tailwind CSS source of assets/css/theme.css
src/icons.css icons drawn before or after text with CSS (generated)
src/editor-css.mjs writes assets/css/editor.css after each build
languages/ freeframe-keystone.pot, the template for translations
blueprint.json WordPress Playground setup used by `pnpm dev`
screenshot.png the picture shown in Appearance > Themes
package.json the CSS build and the local WordPress (Node.js tooling)
readme.txt, README.md, DOCS.md, CHANGELOG.md, LICENSE.txtCustomising#
Brand and colours#
The colours are in theme.json (settings.color.palette) and in Appearance > Editor > Styles >
Colors > Palette:
| Colour | Default | Used for |
|---|---|---|
| Charcoal 950 | #121314 |
blueprint sections, the footer, text on orange |
| Charcoal 900, 800, 700 | #1a1b1d, #242629, #34373b |
outlines, dark buttons, body text |
| Charcoal 600, 500 | #4a4e53, #6b7076 |
secondary text, labels |
| Concrete 50 | #f6f5f2 |
the page background |
| Concrete 100 to 400 | #ecebe6 to #a19e95 |
drawing-paper sections, borders, hairlines |
| Signal 500 | #f15a0f |
the brand orange: buttons, markers, highlights on charcoal |
| Signal 300, 400, 600 | #ffa366, #ff7a2e, #d24c0a |
hover states and icons |
| Signal 700 | #a83b06 |
orange text on light backgrounds (enough contrast) |
| White, Black | for your own blocks |
The theme's stylesheet reads these colours from the palette (bg-signal-500, text-char-600...),
so changing Signal 500 in Styles recolours every button and marker at once. Keep Signal 700 dark
enough for text on Concrete 50 (4.5:1). The SVG drawings (the hero building, the 404 keystone, the
project elevations, the map and the safety chart) carry their own colours in their markup.
The drawing-paper and blueprint backgrounds are the classes grid-paper and grid-blueprint
(gradients in src/theme.css): add either to a Group's Additional CSS class(es).
Typography#
Three fonts are bundled in assets/fonts/ and declared in theme.json
(settings.typography.fontFamilies), so no request goes to Google: Barlow Condensed (500 to
700; preset display) for headings, buttons and big numbers, Barlow (400 to 600 and italic;
preset sans) for text, and IBM Plex Mono (400 and 500; preset mono) for the technical
labels. To use other fonts, install them in Styles > Typography > Fonts (the Font Library) and
select them, or replace the fontFace entries in theme.json. The utility classes read the
presets (--wp--preset--font-family--display, --sans, --mono), so keep those slugs. The SVG
drawings name the fonts directly (font-family="IBM Plex Mono, …").
Font sizes are the presets in theme.json (xs 0.75rem to 9xl 8rem, the Tailwind scale). The
classes h-display (condensed, bold, uppercase), spec (small mono label), eyebrow (mono label
with an orange square) and eyebrow-light (the same on dark) give text the template's styles.
Content#
Edit pages in Pages: click any text to change it, select a button to change its link. Sections are groups; open List View (the stacked lines icon at the top left) to select a section, move it, duplicate it or delete it. To add a section from another page, use the block inserter (+) > Patterns > Keystone.
What the script drives is in Custom HTML blocks: edit those in the block's HTML view, and keep
their ids and data- attributes.
| Pattern | Custom HTML | What it is |
|---|---|---|
home-hero |
the building drawing | an SVG that draws itself in (.draw) |
project-list |
the type chips and search box, the result count, the empty state | see Projects filter and search |
before-after |
the slider | see Before/after slider |
gallery |
the gallery buttons and the lightbox | see Gallery lightbox |
estimator, estimate-bar |
the steps, the quote form, the cost summary, the cost bar on phones | see Project estimator |
safety-record |
the chart and its data table | an SVG bar chart; update the bars and the sr-only table together |
contact-form |
the form, its success message, the office status and the opening hours | see Forms and Office status |
service-area |
the map | an SVG map of southeast Wisconsin |
404 |
the keystone drawing | an SVG that draws itself in |
header, footer |
the menu button, the CORBEL wordmark | driven by the script; decorative |
Some blocks carry classes (Block settings > Advanced > Additional CSS class(es)) that the script
reads. Blocks can't store data- attributes, so the script turns classes starting with ffd- into
them when the page loads: ffd-project ffd-type--renovation on a project card becomes
data-project data-type="renovation".
revealfades a block in as it scrolls into view.link-cardon a group makes the whole group clickable: the first link inside it stretches over the group (the logos).cropdraws orange crop marks on two corners of a card.
Adding a project
On the Projects page, select a project card (a List item group with the class
ffd-project ffd-type--commercial, for example) in List View and duplicate it. Change the drawing,
the badge, the "P-1xx / place" line, the name and its link, the description and the floor area and
year. The type class must be one of the chip filters (ffd-type--commercial, --residential,
--renovation, --architecture); the search matches the name, the place, the badge, the year and
the description, read from the card itself. Then update the counts on the chips (the
chip-count numbers in the filter bar's Custom HTML) and the "Showing 9 projects" text.
Images and artwork#
The project elevations, the case study drawings and the team portraits are SVG files in
assets/img/, used by Image blocks: select one and Replace it with a photo. Keep the aspect
ratios: project cards are 4:3 (800 × 600), the before/after pair 800 × 520 (both images the same
size), team portraits 5:6 (400 × 480). The logo is assets/img/logo.svg in an Image block next to
the CORBEL wordmark in the header and footer patterns. Icons are Icon blocks: select one and pick
another from the Keystone collection or WordPress's own. The social image is
assets/img/og-image.png (1200 × 630, source og-image.svg); the favicon
assets/img/favicon.svg is used until you set a Site Icon in Settings > General.
The hero drawing, the 404 keystone, the safety chart and the map are inline SVG in Custom HTML blocks (inline so their lines can animate and their labels use the theme's fonts). Replace any of them with an Image block if you prefer a photo.
Navigation, header and footer#
The header and footer are template parts (parts/header.html, parts/footer.html) showing the
header and footer patterns. Edit them in Appearance > Editor > Patterns > Header / Footer.
The header pattern starts with the licence and phone bar.
The header has two Navigation blocks showing the same menu: the desktop one and the one in the
mobile menu. Edit the menu once in Appearance > Editor > Navigation (the setup creates "Main
menu": Home, Projects, Services, About, Contact, Get an estimate). Its first link (Home) and
last link (Get an estimate) are hidden in the desktop header, which has the logo and its own
estimate button; keep them first and last, or remove the .site-nav … :first-child and
:last-child rules in src/theme.css. A Navigation block that doesn't point at a menu shows the
most recently created one; to pin a menu, select the Navigation block and choose it in the block
settings, for both blocks.
The footer's Work and Company menus are List blocks: click a link to change it, press Enter to add one. The phone number, email and licence number appear in the header bar, the footer, the contact page and the call-to-action bands; search for them when you change them.
Features#
Project estimator#
The Project estimator page walks through five steps (project type, size, finish, timeline, your
details) and shows a live estimate in the summary panel (aria-live="polite"), with a cost bar at
the bottom of the screen on phones.
-
Where the code is: the "Estimator price model" block at the top of the second part of
assets/js/main.js(data andestimate()), and the "Estimator: 4 steps + request form" block further down (the interface). The markup is theestimatorpattern's Custom HTML. -
The data:
jsvar TYPES = { commercial: { label: __('Commercial build'), desc: __('…'), rate: [215, 340], min: 2000, max: 80000, step: 500, size: 12000, weeks: [26, 1], help: __('…') }, … }; var FINISH = { standard: { …, mult: [1, 1] }, premium: { …, mult: [1.18, 1.28] }, signature: { …, mult: [1.45, 1.65] } }; var TIMELINE = { flexible: { …, mult: [0.96, 0.97], pace: 1.15 }, standard: { … }, fast: { …, mult: [1.08, 1.14], pace: 0.82 } }; var DESIGN = { label: __('Architecture & permits'), mult: [1.07, 1.1], weeks: [12, 20] }; var DEFAULT_ESTIMATE = { type: 'commercial', size: 12000, finish: 'standard', timeline: 'standard', design: true }; -
The calculation (
estimate(s)): floor area × the type'srateper ft², times the finish and timeline multipliers, timesDESIGN.multwhen architecture is included. The low end is rounded down and the high end up to the nearest $5,000. Build time in weeks is(weeks[0] + weeks[1] × size / 1000) × pace, shown as a range of −8% to +10%. -
Changing prices: edit
rateandmult(in a child theme, see Child themes). Also update the price text on the option cards in theestimatorpattern ($215–$340 / ft²,+18–28%) and the default numbers in the summary panel, which show before the script runs. -
Adding a project type: add a key to
TYPESand copy an option card in step 1 with<input type="radio" name="type" value="your-key">. -
Links in:
/estimate/?type=renovationpreselects a type (the services and case study pages use it), and/estimate/#requestopens the details step. -
Accessibility: each step is a
<fieldset>with a<legend>; choices are real radio buttons and a checkbox. The step buttons usearia-current="step", and moving between steps puts focus on the new step's heading. Without JavaScript all steps are shown at once.
Projects filter and search#
On the Projects page the chips filter the cards by type and the search box matches every typed word
against the card's name, place, type, year and description. The count (role="status") announces
"Showing 2 of 9 projects", an empty state with a Clear filters button appears when nothing
matches, and the URL updates to ?type=…&q=…, so filtered views can be shared (the services page
links to /projects/?type=commercial and so on). Chips are buttons with aria-pressed. The code is
the "Projects: type filter + search" block in main.js; the search text is built from each card by
the WordPress adapter at the top of the file.
Before/after slider#
On the case study, the after image sits underneath and the before image is clipped on top with
clip-path driven by the --pos custom property (.before-after-clip in src/theme.css). An
invisible range input covers the images, so dragging, clicking, touch and arrow keys all work, and
screen readers hear "52% before, 48% after". To use other pictures, edit the two <img> paths in
the before-after pattern's Custom HTML and keep both images the same size.
Gallery lightbox#
The gallery buttons open their drawing in a native <dialog> with previous and next buttons, arrow
keys, Esc or a click on the backdrop to close, and focus returned to the button that opened it. The
lightbox reads its pictures, titles and captions from the gallery buttons themselves, in order: to
change a drawing, edit the <img src> and the two text lines of its button in the gallery
pattern's Custom HTML; to add one, copy a button and give it the next data-lightbox-open number.
FAQ accordion#
The FAQ on the Services page is an Accordion block (WordPress's own, with its keyboard support
and ARIA): add a question by duplicating an item in List View. The first answer is open when the
page loads (Open by default in the item's settings). The square plus/minus marker is drawn by
CSS (.wp-block-accordion-heading__toggle::after in src/theme.css).
Office status#
Each office card on the Contact page (ffd-office--milwaukee, ffd-office--madison) shows "Open
now · until 5:30 pm" or "Closed · opens tomorrow 7:00 am", worked out in the office's own time zone:
var OFFICE_HOURS = {
milwaukee: { tz: 'America/Chicago', days: [null, [7, 17.5], [7, 17.5], [7, 17.5], [7, 17.5], [7, 16], null] },
madison: { tz: 'America/Chicago', days: [null, [8, 17], [8, 17], [8, 17], [8, 17], [8, 17], null] }
};Day 0 is Sunday; null means closed; hours are decimals (17.5 is 5:30 pm). Keep these in step
with the opening-hours tables in the contact-form pattern. Without JavaScript the badge reads
"Office hours".
Count-up stats, scroll reveals and line drawings#
Blocks with reveal fade and rise into view, and .draw SVGs draw their lines, when they scroll
into view. Numbers inside <span data-count="620" data-decimals="0">620</span> count up once when
they appear (edit the number and its data-count together in the paragraph's HTML view). All three
are skipped when the visitor prefers reduced motion, and nothing is hidden without JavaScript.
Header, mobile menu and back to top#
The header is sticky and gains a shadow after scrolling. Below 1024 px the menu button opens the
mobile menu, updating aria-expanded and its label; Esc closes it and returns focus to the button.
A back-to-top button appears after about one screen of scrolling and steps aside while the footer's
"Back to top" link is visible; on the estimator it lifts above the cost bar
(data-back-to-top-avoid). To remove it, delete the "Back to top" part at the end of
assets/js/main.js and the .back-to-top styles in src/theme.css, then run pnpm build.
Block styles#
In the block settings' Styles panel:
| Block | Styles |
|---|---|
| Button | Fill (default, the orange button), Dark, Ghost, Ghost (on dark) |
The class is-large on a Button block makes it the larger hero size. Arrow and pencil icons on
buttons are classes too (icon-after-arrow-right, icon-before-ruler, with icon-size-20); see
src/icons.css for the available icons.
Forms#
There are two forms. Both validate in the browser and neither sends anything until you connect it; their success messages say so.
| Form | Where | Validation |
|---|---|---|
Quote request (data-quote-form) |
Project estimator, step 5 | name, email, phone (10+ digits), site, ideal start, project notes (20+ characters), consent box |
Contact (data-contact-form) |
Contact | name, email, optional phone (10+ digits if filled), topic, nearest office, message (10+ characters) |
Validation is in wireForm() and check() in assets/js/main.js. It reads required,
type="email", minlength, required checkboxes and data-validate (phone, phone-optional)
from the forms' Custom HTML; a <fieldset data-group="office"> of radio buttons requires a choice.
Errors appear under each field, linked with aria-describedby, and the first invalid field gets
focus.
To collect messages, use a form plugin (replace the form's Custom HTML block with the plugin's
block; add the classes label, input and btn btn-signal to its labels, fields and button), or
post the form in its callback in assets/js/main.js (in a child theme), for example to Formspree:
wireForm(form, function () {
fetch('https://formspree.io/f/your-form-id', { method: 'POST', body: new FormData(form), headers: { Accept: 'application/json' } })
.then(function (res) {
if (!res.ok) throw new Error('Send failed');
form.reset();
form.classList.add('hidden');
ok.classList.remove('hidden');
ok.focus();
})
.catch(function () { alert('Sorry, your message could not be sent. Please call us.'); });
});For the quote request, do the same inside wireForm(quoteForm, …), and append the estimator's
choices (they are in a separate form): data.append('type', state.type), size_ft2, finish,
timeline, design and compact(r.low) + ' – ' + compact(r.high). Then change the "This is a demo,
so nothing was sent" text in the patterns. The reference number (CDB-26-1234) is random; replace
it with the ID your system returns, or remove it.
Saved data (localStorage)#
| Key | Shape | Written |
|---|---|---|
keystone-estimate-v1 |
{"type": "commercial", "size": 12000, "finish": "standard", "timeline": "standard", "design": true} |
on every estimator change |
This is the HTML version's key. readEstimate() validates it on every read: type, finish and
timeline must be keys of TYPES, FINISH and TIMELINE; size must be within the type's limits
(otherwise the type's default size is used); design must be a boolean. Anything else falls back
to DEFAULT_ESTIMATE, and storage errors are ignored. A ?type= in the URL overrides the saved
type. To reset it, delete the key in your browser's developer tools (Application > Local Storage).
If you change the shape, rename ESTIMATE_KEY so old values are ignored.
SEO and sharing#
Page titles come from WordPress: the page title, an em dash and the site name (for example
"Services — Corbel Design-Build"); the home page shows the site name and tagline (Settings >
General). The theme doesn't output meta descriptions or Open Graph tags; use an SEO plugin such
as Yoast SEO, Rank Math or The SEO Framework, and give it assets/img/og-image.png (or your own
1200 × 630 image) as the default social image. WordPress already generates a sitemap at
/wp-sitemap.xml. A construction firm benefits from LocalBusiness (or GeneralContractor)
structured data with the office addresses and hours; most SEO plugins can add it.
Accessibility#
Built in: a skip link to the main content (added by WordPress, styled by the theme), landmarks
(header, labelled navigation, main, footer), one h1 per page, labelled sections, visible focus
rings in signal orange, the menu button with aria-expanded and a label that changes with its
state, filter chips with aria-pressed and a live result count, a range input behind the
before/after slider with a spoken value, a native dialog for the lightbox, the Accordion block for
the FAQ, estimator steps as fieldsets with aria-current="step", form errors announced through
aria-describedby and aria-invalid, a data table behind the safety chart, labelled drawings and
reduced-motion support for every animation. Orange text on light backgrounds uses Signal 700 for
contrast. The demo passes axe (WCAG 2.1 A and AA).
When you edit: keep one Heading 1 per page, give images alt text (or mark them decorative), keep
link text meaningful, and label any field you add to a form (<label for="...">).
Building and deploying#
You only need this if you change the theme's files. The stylesheet assets/css/theme.css is
compiled with Tailwind CSS from src/theme.css and the classes used in patterns/, parts/,
templates/, inc/ and assets/js/:
pnpm install
pnpm build # compile assets/css/theme.css and assets/css/editor.css
pnpm watch # recompile assets/css/theme.css on every change (run pnpm build before you commit)Run pnpm build after adding a utility class to a pattern, template or the script's markup,
otherwise the class has no style. Classes you type in the editor's Additional CSS class(es)
field are only styled if the stylesheet already contains them.
To deploy, zip the theme folder (named freeframe-keystone, without node_modules/) and upload it
in Appearance > Themes, or copy the folder to wp-content/themes/ on your server.
Translations#
The theme is translation-ready with the text domain freeframe-keystone. All text in patterns,
templates and PHP goes through WordPress's translation functions; the script's strings (estimator
labels and breakdown lines, result counts, office status, form errors and messages) are translated
in PHP (freeframe_keystone_script_strings() in inc/setup.php). Create a translation with Loco
Translate, or with WP-CLI and Poedit:
wp i18n make-pot wp-content/themes/freeframe-keystone wp-content/themes/freeframe-keystone/languages/freeframe-keystone.potSave freeframe-keystone-de_DE.mo (for example) in wp-content/languages/themes/ or in the
theme's languages/ folder. Page content created by Keystone setup is copied into your pages in the
site's language at that moment; translate it in the editor like any other content. Prices are
formatted in US dollars and square feet by the script (money(), compact()).
Child themes#
Use a child theme for changes you want to keep when Keystone is updated (your prices and office
hours in particular). Create wp-content/themes/keystone-child/style.css:
/*
Theme Name: Keystone Child
Template: freeframe-keystone
*/Templates, parts, patterns and theme.json in the child theme override the parent's files of the
same name. To use your own copy of assets/js/main.js, dequeue the parent's script
(freeframe-keystone) and enqueue yours in the child's functions.php, keeping the inline
window.freeframeKeystone strings (or copy them). The parent's stylesheet only contains the classes
the parent uses: if your child theme uses new utility classes, compile a stylesheet for the child
(copy package.json and src/theme.css, point the @source lines at the child's folders) and
enqueue it.
Troubleshooting#
- The pages look unstyled or new classes do nothing. The stylesheet only contains classes it
found when it was built. Run
pnpm buildafter editing patterns, then reload. - "This block contains unexpected or invalid content". A pattern or page was edited by hand with markup that doesn't match the block. Click Attempt recovery, or re-insert the section from Patterns > Keystone.
- A new project card doesn't show up under a filter. Its group needs the classes
ffd-projectandffd-type--<type>with one of the chip types. See Adding a project. - The estimate doesn't change after editing prices. The option cards show text from the
pattern, but the numbers come from
TYPES,FINISH,TIMELINEandDESIGNinassets/js/main.js. Change both. A saved estimate in the browser can also hold an old type: see Saved data. - Home or Get an estimate is missing from the desktop menu. The desktop header hides the menu's first and last links. See Navigation, header and footer.
- Keystone setup says the pages exist, but they are empty. It never overwrites existing pages. Delete (and empty the trash of) the pages with those slugs, or open each page and insert its page pattern from Patterns > Keystone pages.
- The forms don't send anything. They are demo forms; see Forms.
- A page shows the title twice or no title. Pages use a template without a title, because the page patterns start with their own heading. For a plain text page (privacy policy, terms), choose the Page with title template in the page's settings.
License#
MIT, which is compatible with the GPL that WordPress requires (see LICENSE.txt in the theme
folder). Free for personal and commercial use. The project drawings, portraits, map, chart and logo
are included under the same license. Barlow, Barlow Condensed and IBM Plex Mono are licensed under
the SIL Open Font License 1.1 (OFL.txt in each folder of assets/fonts/).