diff --git a/RECOMMENDED_FONTS.md b/RECOMMENDED_FONTS.md
index f07e1e3..2a13e3e 100644
--- a/RECOMMENDED_FONTS.md
+++ b/RECOMMENDED_FONTS.md
@@ -1,47 +1,39 @@
-# Earthen — recommended fonts
+# Earthen — fonts
-This theme ships `fonts.json = []` per the wave-1 fonts policy
-(see `themes/docs/FONTS.md`). The CSS uses
-`var(--font-heading)` / `var(--font-body)` / `var(--font-mono)` with a
-fallback stack so the page reads close to the intended aesthetic before
-the admin assigns fonts.
+Earthen **bundles** its display and body faces as `source=template` rows via
+`fonts.json`, so the theme reads correctly on activation with no admin setup.
+All CSS references fonts through `var(--font-heading)` / `var(--font-body)` /
+`var(--font-mono)` with a fallback stack, so the admin can still override any
+role from the Typography panel.
-Configure these in the admin Typography panel to match the spec's
-intended look.
+## Bundled faces (ship with the theme)
-## Display / heading — assign to `Heading`
+| Role | Family | Weights | File | License |
+|------|--------|---------|------|---------|
+| Heading | **Fraunces** | 400, 600 | `assets/fonts/fraunces-latin-400.woff2`, `fraunces-latin-600.woff2` | SIL Open Font License 1.1 (`assets/fonts/OFL.txt`) |
+| Body | **Work Sans** | 400, 600 | `assets/fonts/worksans-latin-400.woff2`, `worksans-latin-600.woff2` | SIL Open Font License 1.1 (`assets/fonts/OFL.txt`) |
-Primary pick:
+Fraunces gives the organic, slightly wobbly display voice the persona wants;
+Work Sans keeps body copy warm but legible for donation and report pages. Both
+are OFL, subset to the Latin range to stay inside the marketplace size gate.
-- **Fraunces** — Source: `google:Fraunces`.
- Open the Typography panel, switch to the Google Fonts tab, search
- "Fraunces", click Add, then assign to Heading. (OFL, free to host.)
+## Fallback stacks (used before/without admin fonts)
-Spec-preferred display face (commercial):
+- Heading: `var(--font-heading, "Fraunces", "Playfair Display", Georgia, serif)`
+- Body: `var(--font-body, "Work Sans", ui-sans-serif, system-ui, sans-serif)`
+- Mono: `var(--font-mono, "JetBrains Mono", ui-monospace, monospace)`
-- **Recoleta** — Source: `upload:Recoleta`.
- Recoleta is a commercial face from Latinotype. Purchase the desktop +
- webfont licence, upload the woff2 in the Fonts panel, then assign to
- Heading. Until then Fraunces is the fallback used by the theme CSS.
+## Optional admin choices
-## Body — assign to `Body`
-
-- **Spectral** — Source: `google:Spectral`.
- Open the Typography panel, Google Fonts tab, search "Spectral",
- click Add, assign to Body. (OFL, free to host.)
-
-## Mono / data captions — assign to `Mono`
-
-- **JetBrains Mono** — Source: `google:JetBrains Mono`.
- Open the Typography panel, Google Fonts tab, search "JetBrains Mono",
- click Add, assign to Mono. (OFL, free to host.)
+- **Mono** is not bundled. If your content uses monospace (data captions, code),
+ add **JetBrains Mono** (`google:JetBrains Mono`, OFL) from the Typography panel
+ Google Fonts tab and assign it to Mono. Until then the system mono stack applies.
+- **Alegreya** (`google:Alegreya`, OFL) is a good serif alternative for Body if you
+ want a more literary, long-read feel for field journals. Assign it to Body to swap.
## Notes
-- All three Google-Font picks are part of the curated picker list.
- No manual upload required for the OFL families.
-- A future build pass may bundle Recoleta woff2s directly via a
- populated `fonts.json` once the licence is confirmed.
-- The CSS fallback stack inside the theme (`"Fraunces", "Playfair Display",
- Georgia, serif` for headings; `"Spectral", Georgia, serif` for body)
- keeps the moss/clay character visible during the cold-load window.
+- Do not hardcode a `font-family` anywhere. Every family flows through the CSS
+ variables so the admin font picker keeps working.
+- Bundled woff2 files are subset to Latin. Extend the subset only if you serve
+ non-Latin content, and keep the total artifact within the registry size gate.
diff --git a/RECOMMENDED_ICONS.md b/RECOMMENDED_ICONS.md
new file mode 100644
index 0000000..00238f3
--- /dev/null
+++ b/RECOMMENDED_ICONS.md
@@ -0,0 +1,23 @@
+# Earthen — icon packs
+
+Earthen renders icons through the sprite system only
+(``, or the `::pack:name:size::`
+shorthand in templates). It does **not** inline icon SVGs. The theme's botanical
+line-art (fern, seed, root motifs) is decorative illustration, not icons, and is
+drawn inline on purpose.
+
+## Required pack
+
+- **Lucide** — declared in `plugin.mod` `required_icon_packs = ["lucide"]`.
+ Lucide ships bundled with the CMS, so no action is normally needed. If it is
+ missing on your instance, open `/admin/icons`, install **Lucide**, and enable it.
+
+Block schemas that expose an icon picker default to Lucide names, so the theme
+renders correctly out of the box. When the loader begins honoring
+`required_icon_packs`, Lucide will be installed automatically on activation.
+
+## Optional
+
+No other packs are required. If you add icons from another pack in block content,
+install that pack via `/admin/icons` first, then reference it as `":"`
+in the block's icon field.
diff --git a/assets/fonts/OFL.txt b/assets/fonts/OFL.txt
new file mode 100644
index 0000000..0bc9995
--- /dev/null
+++ b/assets/fonts/OFL.txt
@@ -0,0 +1,111 @@
+Bundled fonts — SIL Open Font License 1.1
+=========================================
+
+This directory bundles latin-subset woff2 files for three families, all
+licensed under the SIL Open Font License, Version 1.1 (OFL-1.1).
+
+Copyright notices
+-----------------
+Fraunces: Copyright 2018 The Fraunces Project Authors (https://github.com/undercasetype/Fraunces)
+Work Sans: Copyright 2019 The Work Sans Project Authors (https://github.com/weiweihuanghuang/Work-Sans)
+Caveat: Copyright 2019 The Caveat Project Authors (https://github.com/googlefonts/caveat)
+
+Files
+-----
+fraunces-latin-400.woff2, fraunces-latin-600.woff2 — Fraunces (heading)
+worksans-latin-400.woff2, worksans-latin-600.woff2 — Work Sans (body)
+caveat-latin-400.woff2, caveat-latin-700.woff2 — Caveat (hand-drawn accents)
+
+Full license text (SIL OFL 1.1)
+-------------------------------
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/assets/fonts/README.md b/assets/fonts/README.md
index c8daa74..dd353ce 100644
--- a/assets/fonts/README.md
+++ b/assets/fonts/README.md
@@ -1,5 +1,9 @@
# Earthen fonts
-Reserved for woff2 bundles in a future build pass. The wave-1 build ships
-`fonts.json = []` per the FONTS.md policy; admins assign Fraunces /
-Spectral / JetBrains Mono through the typography picker.
+Bundled woff2 faces, served as `source=template` rows via `../../fonts.json`:
+
+- **Fraunces** 400/600 (`fraunces-latin-400.woff2`, `fraunces-latin-600.woff2`) — heading.
+- **Work Sans** 400/600 (`worksans-latin-400.woff2`, `worksans-latin-600.woff2`) — body.
+
+Both are SIL Open Font License 1.1 (see `OFL.txt`), subset to Latin. See
+`../../RECOMMENDED_FONTS.md` for admin assignment and the mono option.
diff --git a/assets/fonts/fraunces-latin-400.woff2 b/assets/fonts/fraunces-latin-400.woff2
new file mode 100644
index 0000000..83cbd8f
Binary files /dev/null and b/assets/fonts/fraunces-latin-400.woff2 differ
diff --git a/assets/fonts/fraunces-latin-600.woff2 b/assets/fonts/fraunces-latin-600.woff2
new file mode 100644
index 0000000..58cee1f
Binary files /dev/null and b/assets/fonts/fraunces-latin-600.woff2 differ
diff --git a/assets/fonts/worksans-latin-400.woff2 b/assets/fonts/worksans-latin-400.woff2
new file mode 100644
index 0000000..02a6a42
Binary files /dev/null and b/assets/fonts/worksans-latin-400.woff2 differ
diff --git a/assets/fonts/worksans-latin-600.woff2 b/assets/fonts/worksans-latin-600.woff2
new file mode 100644
index 0000000..1ec3048
Binary files /dev/null and b/assets/fonts/worksans-latin-600.woff2 differ
diff --git a/assets/style.css b/assets/style.css
index db57ef7..f6b99f4 100644
--- a/assets/style.css
+++ b/assets/style.css
@@ -102,9 +102,9 @@
color: hsl(var(--muted-foreground));
}
-/* Ensure article main column uses the Spectral body fallback. */
+/* Ensure article main column uses the Work Sans body fallback. */
.earthen-article {
- font-family: var(--font-body, "Spectral", Georgia, serif);
+ font-family: var(--font-body, "Work Sans", ui-sans-serif, system-ui, sans-serif);
color: hsl(var(--foreground));
}
@@ -112,3 +112,69 @@
.earthen-glyph {
color: hsl(var(--primary));
}
+
+/* Organic blob — soft asymmetric corners for cards, media frames and hero art.
+ The signature earthen shape: hand-crafted, never a hard rectangle. */
+.earthen-blob {
+ border-radius: 42% 58% 62% 38% / 42% 44% 56% 58%;
+}
+.earthen-blob-soft {
+ border-radius: 1.75rem 2.25rem 1.75rem 2.25rem;
+}
+
+/* Soft card / panel frame — cream surface with a hairline botanical border. */
+.earthen-panel {
+ background-color: hsl(var(--card));
+ color: hsl(var(--card-foreground));
+ border: 1px solid hsl(var(--border));
+ box-shadow: inset 0 0 0 1px hsl(var(--border) / 0.35);
+}
+
+/* Terracotta seedling button — the primary call to action across the theme. */
+.earthen-cta {
+ background-color: hsl(var(--accent));
+ color: hsl(var(--accent-foreground));
+ border-radius: 0.75rem;
+ transition: box-shadow 200ms ease, transform 120ms ease;
+}
+.earthen-cta:hover,
+.earthen-cta:focus-visible {
+ box-shadow: 0 6px 0 -2px hsl(var(--accent) / 0.35);
+ transform: translateY(-1px);
+}
+.earthen-cta:focus-visible {
+ outline: 2px solid hsl(var(--ring));
+ outline-offset: 2px;
+}
+
+/* Sage link — dotted botanical underline that fills on hover. */
+.earthen-link {
+ color: hsl(var(--primary));
+ text-decoration: none;
+ border-bottom: 1px dotted hsl(var(--primary) / 0.6);
+ transition: color 150ms ease, border-color 150ms ease;
+}
+.earthen-link:hover,
+.earthen-link:focus-visible {
+ color: hsl(var(--accent));
+ border-bottom-color: hsl(var(--accent));
+}
+
+/* Leaf line-draw — a hairline that draws in on scroll where motion is allowed. */
+@media (prefers-reduced-motion: no-preference) {
+ .earthen-draw {
+ stroke-dasharray: 240;
+ stroke-dashoffset: 240;
+ animation: earthen-draw-in 1.4s ease forwards;
+ }
+ @keyframes earthen-draw-in {
+ to { stroke-dashoffset: 0; }
+ }
+ .earthen-blob-morph {
+ animation: earthen-blob-morph 18s ease-in-out infinite;
+ }
+ @keyframes earthen-blob-morph {
+ 0%, 100% { border-radius: 42% 58% 62% 38% / 42% 44% 56% 58%; }
+ 50% { border-radius: 58% 42% 38% 62% / 56% 58% 42% 44%; }
+ }
+}
diff --git a/blocks/blocks.yaml b/blocks/blocks.yaml
index c386792..dd5f0e2 100644
--- a/blocks/blocks.yaml
+++ b/blocks/blocks.yaml
@@ -1,42 +1,26 @@
-# Earthen theme block definitions (codeless .bnp, WO-WZ-021).
-# Keys are fully qualified (earthen:) because the codeless loader registers
-# definitions verbatim — there is no PluginBlockRegistry prefixing in the
-# codeless path (unlike the wasm/templ path). The qualified keys match the
-# hardcoded data-block attributes and the master_pages.json references.
+# Earthen theme block definitions (codeless .bnp, WO-WZ-021 / WO-TF-016).
+# Only TRUE persona furniture remains as theme blocks. Everything that
+# duplicated a builtin (footer, stats/impact-metrics, logo-strip/partner-logos,
+# divider/botanical-divider) is now a template OVERRIDE of the builtin key
+# (templates/overrides/earthen/). Keys are fully qualified (earthen:) — the
+# codeless loader registers definitions verbatim; the qualified keys match the
+# data-block attributes, master_pages.json and seed references.
blocks:
- key: earthen:donation_cta
title: Donation CTA
- description: Donation call-to-action with preset amount tiles and custom amount field.
+ description: Donation appeal with preset amount tiles and a custom amount field.
category: content
schema: donation_cta.schema.json
template: donation_cta.ninjatpl
- - key: earthen:impact_metrics
- title: Impact Metrics
- description: Numerical impact metrics with optional botanical illustration.
- category: content
- schema: impact_metrics.schema.json
- template: impact_metrics.ninjatpl
- - key: earthen:partner_logos
- title: Partner Logos
- description: Grayscale partner logo grid with hover-to-color treatment.
- category: content
- schema: partner_logos.schema.json
- template: partner_logos.ninjatpl
- key: earthen:field_note
title: Field Note
- description: Article-style dispatch from the field with byline and location.
+ description: Dispatch from the field with byline, location and a lede image.
category: content
schema: field_note.schema.json
template: field_note.ninjatpl
- - key: earthen:botanical_divider
- title: Botanical Divider
- description: Hand-illustrated SVG section break in fern, root or seed motif.
- category: layout
- schema: botanical_divider.schema.json
- template: botanical_divider.ninjatpl
- - key: earthen:footer
- title: Site Footer
- description: Cream-on-moss footer with optional newsletter and column links.
- category: navigation
- schema: footer.schema.json
- template: footer.ninjatpl
+ - key: earthen:impact_report
+ title: Impact Report
+ description: Narrative impact report with a summary lede and outcome rows.
+ category: content
+ schema: impact_report.schema.json
+ template: impact_report.ninjatpl
diff --git a/blocks/botanical_divider.ninjatpl b/blocks/botanical_divider.ninjatpl
deleted file mode 100644
index 62e22b1..0000000
--- a/blocks/botanical_divider.ninjatpl
+++ /dev/null
@@ -1,5 +0,0 @@
-