@janga/norna 0.7.8 → 0.7.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/README.md +1 -1
  2. package/docs/README.md +18 -11
  3. package/docs/configuration.md +9 -54
  4. package/docs/content.md +6 -7
  5. package/docs/design/norna-diagram-design.md +158 -0
  6. package/docs/getting-started.md +18 -16
  7. package/docs/routes.md +7 -6
  8. package/docs/site-structure.md +4 -2
  9. package/docs/sitewide-content.md +74 -0
  10. package/docs/theme.md +61 -128
  11. package/docs/typography.md +45 -33
  12. package/examples/001-dog-shelter-single-page/README.md +9 -0
  13. package/examples/001-dog-shelter-single-page/site/config.mjs +27 -0
  14. package/examples/001-dog-shelter-single-page/site/content.md +38 -0
  15. package/examples/001-dog-shelter-single-page/site/images/what-we-do/dog-house.svg +25 -0
  16. package/examples/001-dog-shelter-single-page/site/images/you-can-help/heart.svg +13 -0
  17. package/examples/001-dog-shelter-single-page/site/public/favicon.svg +10 -0
  18. package/examples/001-dog-shelter-single-page/site/public/robots.txt +2 -0
  19. package/examples/001-dog-shelter-single-page/site/sitewide-content.md +6 -0
  20. package/examples/001-dog-shelter-single-page/site/theme.md +25 -0
  21. package/examples/002-dog-shelter-multi-page/README.md +9 -0
  22. package/examples/002-dog-shelter-multi-page/site/config.mjs +27 -0
  23. package/examples/002-dog-shelter-multi-page/site/content.md +12 -0
  24. package/examples/002-dog-shelter-multi-page/site/public/favicon.svg +10 -0
  25. package/examples/002-dog-shelter-multi-page/site/public/robots.txt +2 -0
  26. package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rex.svg +19 -0
  27. package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/images/dogs/rover.svg +19 -0
  28. package/examples/002-dog-shelter-multi-page/site/routes/010-dogs/route-content.md +30 -0
  29. package/examples/002-dog-shelter-multi-page/site/routes/020-adopt/route-content.md +12 -0
  30. package/examples/002-dog-shelter-multi-page/site/sitewide-content.md +6 -0
  31. package/examples/002-dog-shelter-multi-page/site/theme.md +25 -0
  32. package/examples/dog-gallery/.astro/collections/site.schema.json +776 -0
  33. package/examples/dog-gallery/.astro/collections/theme.schema.json +672 -0
  34. package/examples/dog-gallery/.astro/content-assets.mjs +4 -0
  35. package/examples/dog-gallery/.astro/content-modules.mjs +1 -0
  36. package/examples/dog-gallery/.astro/content.d.ts +175 -0
  37. package/examples/dog-gallery/.astro/data-store.json +1 -0
  38. package/examples/dog-gallery/.astro/dev-local.json +8 -0
  39. package/examples/dog-gallery/.astro/dev.json +13 -0
  40. package/examples/dog-gallery/.astro/dev.log +95 -0
  41. package/examples/dog-gallery/.astro/settings.json +5 -0
  42. package/examples/dog-gallery/.astro/types.d.ts +2 -0
  43. package/examples/dog-gallery/dist/_astro/GalleryGrid.astro_astro_type_script_index_0_lang.B0kxDyGz.js +1 -0
  44. package/examples/dog-gallery/dist/_astro/SitePage.DicGh_5N.css +1 -0
  45. package/examples/dog-gallery/dist/dog-care/index.html +15 -0
  46. package/examples/dog-gallery/dist/dog-shelter-logo.svg +14 -0
  47. package/examples/dog-gallery/dist/favicon.svg +7 -0
  48. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1080.webp +0 -0
  49. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1440.webp +0 -0
  50. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-1536.webp +0 -0
  51. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-480.webp +0 -0
  52. package/examples/dog-gallery/dist/images/generated/black-dogs/black-puppy-meadow-7255e3d9-768.webp +0 -0
  53. package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-480.webp +0 -0
  54. package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-768.webp +0 -0
  55. package/examples/dog-gallery/dist/images/generated/black-dogs/photo-of-a-black-dog-5cf614d2-960.webp +0 -0
  56. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1080.webp +0 -0
  57. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1440.webp +0 -0
  58. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-1920.webp +0 -0
  59. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-3939.webp +0 -0
  60. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-480.webp +0 -0
  61. package/examples/dog-gallery/dist/images/generated/brown-dogs/brown-dog-50ef114e-768.webp +0 -0
  62. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1080.webp +0 -0
  63. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1440.webp +0 -0
  64. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-1920.webp +0 -0
  65. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-2400.webp +0 -0
  66. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-480.webp +0 -0
  67. package/examples/dog-gallery/dist/images/generated/brown-dogs/dog-accompanies-master-7ef804d5-768.webp +0 -0
  68. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1080.webp +0 -0
  69. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1440.webp +0 -0
  70. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-1600.webp +0 -0
  71. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-480.webp +0 -0
  72. package/examples/dog-gallery/dist/images/generated/golden-dogs/golden-retriever-f797fd88-768.webp +0 -0
  73. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1080.webp +0 -0
  74. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1440.webp +0 -0
  75. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-1920.webp +0 -0
  76. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-2576.webp +0 -0
  77. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-480.webp +0 -0
  78. package/examples/dog-gallery/dist/images/generated/golden-dogs/toller-puppy-a2a8fbc0-768.webp +0 -0
  79. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-1080.webp +0 -0
  80. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-1277.webp +0 -0
  81. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-480.webp +0 -0
  82. package/examples/dog-gallery/dist/images/generated/white-dogs/white-cute-dog-077a0689-768.webp +0 -0
  83. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1080.webp +0 -0
  84. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1440.webp +0 -0
  85. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-1536.webp +0 -0
  86. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-480.webp +0 -0
  87. package/examples/dog-gallery/dist/images/generated/white-dogs/white-puppy-garden-d3ab2ca0-768.webp +0 -0
  88. package/examples/dog-gallery/dist/index.html +45 -0
  89. package/examples/dog-gallery/dist/robots.txt +2 -0
  90. package/examples/dog-gallery/node_modules/.vite/deps/_metadata.json +7 -7
  91. package/examples/dog-gallery/site/.norna/generated-images.json +8 -8
  92. package/examples/dog-gallery/site/config.mjs +0 -20
  93. package/examples/dog-gallery/site/content.md +4 -5
  94. package/examples/dog-gallery/site/public/logo.svg +14 -0
  95. package/examples/dog-gallery/site/sitewide-content.md +16 -0
  96. package/examples/dog-gallery/site/theme.md +13 -24
  97. package/examples/presentation/README.md +15 -0
  98. package/examples/presentation/site/.norna/generated-images.json +66 -0
  99. package/examples/presentation/site/config.mjs +29 -0
  100. package/examples/presentation/site/content.md +67 -0
  101. package/examples/presentation/site/public/robots.txt +2 -0
  102. package/examples/presentation/site/routes/010-presets/route-content.md +63 -0
  103. package/examples/presentation/site/routes/010-presets/theme.md +4 -0
  104. package/examples/presentation/site/routes/020-media/images/cards/card-carousel.svg +11 -0
  105. package/examples/presentation/site/routes/020-media/images/cards/card-stack.svg +9 -0
  106. package/examples/presentation/site/routes/020-media/images/cards/card-surfaces.svg +8 -0
  107. package/examples/presentation/site/routes/020-media/images/carousel/carousel-one.svg +8 -0
  108. package/examples/presentation/site/routes/020-media/images/carousel/carousel-three.svg +13 -0
  109. package/examples/presentation/site/routes/020-media/images/carousel/carousel-two.svg +8 -0
  110. package/examples/presentation/site/routes/020-media/images/stack/stack-one.svg +8 -0
  111. package/examples/presentation/site/routes/020-media/images/stack/stack-two.svg +9 -0
  112. package/examples/presentation/site/routes/020-media/route-content.md +77 -0
  113. package/examples/presentation/site/routes/020-media/theme.md +4 -0
  114. package/examples/presentation/site/routes/030-surfaces/route-content.md +44 -0
  115. package/examples/presentation/site/routes/030-surfaces/theme.md +7 -0
  116. package/examples/presentation/site/sitewide-content.md +6 -0
  117. package/examples/presentation/site/theme.md +43 -0
  118. package/examples/typography-presets/.astro/collections/routeTheme.schema.json +746 -0
  119. package/examples/typography-presets/.astro/collections/site.schema.json +59 -0
  120. package/examples/typography-presets/.astro/collections/sitewide.schema.json +114 -0
  121. package/examples/typography-presets/.astro/collections/theme.schema.json +770 -0
  122. package/examples/typography-presets/.astro/content-assets.mjs +4 -0
  123. package/examples/typography-presets/.astro/content-modules.mjs +1 -0
  124. package/examples/typography-presets/.astro/content.d.ts +183 -0
  125. package/examples/typography-presets/.astro/data-store.json +1 -0
  126. package/examples/typography-presets/.astro/dev-local.json +8 -0
  127. package/examples/typography-presets/.astro/dev.json +15 -0
  128. package/examples/typography-presets/.astro/dev.log +45 -0
  129. package/examples/typography-presets/.astro/settings.json +5 -0
  130. package/examples/typography-presets/.astro/types.d.ts +2 -0
  131. package/examples/typography-presets/node_modules/.vite/deps/_metadata.json +80 -0
  132. package/examples/typography-presets/node_modules/.vite/deps/astro-D_GIpJIE.js +434 -0
  133. package/examples/typography-presets/node_modules/.vite/deps/astro-D_GIpJIE.js.map +1 -0
  134. package/examples/typography-presets/node_modules/.vite/deps/astro_n_aria-query.js +6390 -0
  135. package/examples/typography-presets/node_modules/.vite/deps/astro_n_aria-query.js.map +1 -0
  136. package/examples/typography-presets/node_modules/.vite/deps/astro_n_axobject-query.js +2702 -0
  137. package/examples/typography-presets/node_modules/.vite/deps/astro_n_axobject-query.js.map +1 -0
  138. package/examples/typography-presets/node_modules/.vite/deps/astro_n_html-escaper.js +65 -0
  139. package/examples/typography-presets/node_modules/.vite/deps/astro_n_html-escaper.js.map +1 -0
  140. package/examples/typography-presets/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +455 -0
  141. package/examples/typography-presets/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +1 -0
  142. package/examples/typography-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js +1534 -0
  143. package/examples/typography-presets/node_modules/.vite/deps/audit-DM9Hkl5B.js.map +1 -0
  144. package/examples/typography-presets/node_modules/.vite/deps/embla-carousel.js +1389 -0
  145. package/examples/typography-presets/node_modules/.vite/deps/embla-carousel.js.map +1 -0
  146. package/examples/typography-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js +48 -0
  147. package/examples/typography-presets/node_modules/.vite/deps/highlight-DnZ1ULOL.js.map +1 -0
  148. package/examples/typography-presets/node_modules/.vite/deps/icons-RyebKi45.js +42 -0
  149. package/examples/typography-presets/node_modules/.vite/deps/icons-RyebKi45.js.map +1 -0
  150. package/examples/typography-presets/node_modules/.vite/deps/package.json +3 -0
  151. package/examples/typography-presets/node_modules/.vite/deps/rolldown-runtime-BvCyGRYZ.js +4 -0
  152. package/examples/typography-presets/node_modules/.vite/deps/settings-DaU-gNnK.js +190 -0
  153. package/examples/typography-presets/node_modules/.vite/deps/settings-DaU-gNnK.js.map +1 -0
  154. package/examples/typography-presets/node_modules/.vite/deps/toolbar-63PA619H.js +458 -0
  155. package/examples/typography-presets/node_modules/.vite/deps/toolbar-63PA619H.js.map +1 -0
  156. package/examples/typography-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js +1016 -0
  157. package/examples/typography-presets/node_modules/.vite/deps/ui-library--bkcNSYz.js.map +1 -0
  158. package/examples/typography-presets/node_modules/.vite/deps/window-jPkpKVcy.js +32 -0
  159. package/examples/typography-presets/node_modules/.vite/deps/window-jPkpKVcy.js.map +1 -0
  160. package/examples/typography-presets/node_modules/.vite/deps/xray-BXCHpEJP.js +111 -0
  161. package/examples/typography-presets/node_modules/.vite/deps/xray-BXCHpEJP.js.map +1 -0
  162. package/examples/typography-presets/site/.norna/generated-images.json +290 -0
  163. package/examples/typography-presets/site/config.mjs +29 -0
  164. package/examples/typography-presets/site/content.md +16 -0
  165. package/examples/typography-presets/site/public/robots.txt +2 -0
  166. package/examples/typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery/puppy-portrait.jpg +0 -0
  167. package/examples/typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery/shepherd-portrait.jpg +0 -0
  168. package/examples/typography-presets/site/routes/010-quiet-gallery/images/quiet-gallery/white-puppy.jpg +0 -0
  169. package/examples/typography-presets/site/routes/010-quiet-gallery/route-content.md +34 -0
  170. package/examples/typography-presets/site/routes/010-quiet-gallery/theme.md +4 -0
  171. package/examples/typography-presets/site/routes/020-compact-gallery/images/compact-gallery/black-schnauzer.jpg +0 -0
  172. package/examples/typography-presets/site/routes/020-compact-gallery/images/compact-gallery/retriever-portrait.jpg +0 -0
  173. package/examples/typography-presets/site/routes/020-compact-gallery/images/compact-gallery/schnauzer-portrait.jpg +0 -0
  174. package/examples/typography-presets/site/routes/020-compact-gallery/route-content.md +33 -0
  175. package/examples/typography-presets/site/routes/020-compact-gallery/theme.md +4 -0
  176. package/examples/typography-presets/site/routes/030-text-forward/images/text-forward/boxer-portrait.jpg +0 -0
  177. package/examples/typography-presets/site/routes/030-text-forward/images/text-forward/grass-puppy.jpg +0 -0
  178. package/examples/typography-presets/site/routes/030-text-forward/images/text-forward/grey-street-dog.jpg +0 -0
  179. package/examples/typography-presets/site/routes/030-text-forward/route-content.md +34 -0
  180. package/examples/typography-presets/site/routes/030-text-forward/theme.md +4 -0
  181. package/examples/typography-presets/site/routes/040-statement/images/statement/black-pedigree.jpg +0 -0
  182. package/examples/typography-presets/site/routes/040-statement/images/statement/sheepdog-grass.jpg +0 -0
  183. package/examples/typography-presets/site/routes/040-statement/images/statement/sheepdog-wide.jpg +0 -0
  184. package/examples/typography-presets/site/routes/040-statement/route-content.md +34 -0
  185. package/examples/typography-presets/site/routes/040-statement/theme.md +4 -0
  186. package/examples/typography-presets/site/sitewide-content.md +14 -0
  187. package/examples/typography-presets/site/theme.md +43 -0
  188. package/fixtures/basic/site/config.mjs +0 -13
  189. package/fixtures/basic/site/sitewide-content.md +12 -0
  190. package/fixtures/basic/site/theme.md +2 -2
  191. package/fixtures/content-model-v2/site/content.md +2 -5
  192. package/fixtures/content-model-v2/site/theme.md +1 -3
  193. package/package.json +3 -2
  194. package/scripts/check-config.mjs +22 -1
  195. package/scripts/lib/frontmatter-yaml.mjs +28 -0
  196. package/scripts/lib/logo-assets.mjs +35 -0
  197. package/scripts/lib/norna-markdown-blocks.mjs +166 -0
  198. package/scripts/lib/presentation.mjs +104 -46
  199. package/scripts/lib/project-config.mjs +67 -105
  200. package/scripts/lib/site-content.mjs +26 -42
  201. package/scripts/lib/site-paths.mjs +2 -0
  202. package/scripts/lib/sitewide-config.mjs +34 -0
  203. package/scripts/lib/theme-config.mjs +72 -6
  204. package/scripts/lib/typography.mjs +20 -26
  205. package/scripts/show-typography.mjs +40 -147
  206. package/scripts/sync-content-sections.mjs +19 -14
  207. package/scripts/test-content-check.mjs +76 -14
  208. package/scripts/test-content-model-v2.mjs +154 -0
  209. package/scripts/test-engine-commands.mjs +3 -1
  210. package/scripts/test-package-check.mjs +78 -19
  211. package/scripts/test-temporary-visibility.mjs +19 -2
  212. package/src/components/CardList.astro +5 -2
  213. package/src/components/GalleryGrid.astro +37 -16
  214. package/src/components/SiteBanners.astro +100 -0
  215. package/src/components/SiteNavigation.astro +48 -31
  216. package/src/components/SitePage.astro +55 -13
  217. package/src/components/SiteSection.astro +194 -36
  218. package/src/content.config.ts +78 -48
  219. package/src/layouts/BaseLayout.astro +64 -14
  220. package/src/lib/routeThemes.ts +61 -0
  221. package/src/lib/sectionContent.ts +236 -44
  222. package/src/lib/sitePublicAssets.ts +1 -0
  223. package/src/styles/global.css +282 -93
  224. package/starters/basic/.github/workflows/deploy.yml +1 -1
  225. package/starters/basic/README.md +7 -6
  226. package/starters/basic/site/config.mjs +0 -13
  227. package/starters/basic/site/content.md +1 -1
  228. package/starters/basic/site/sitewide-content.md +14 -0
  229. package/starters/basic/site/theme.md +13 -24
  230. package/starters/project/.github/workflows/deploy.yml +1 -1
  231. package/starters/project/README.md +10 -8
  232. package/starters/project/site/config.mjs +0 -13
  233. package/starters/project/site/sitewide-content.md +14 -0
  234. package/starters/project/site/theme.md +3 -11
package/docs/theme.md CHANGED
@@ -1,20 +1,19 @@
1
1
  # Theme
2
2
 
3
- `site/theme.md` defines optional site-wide visual defaults for a `norna` site.
4
- It uses YAML frontmatter and does not need a Markdown body. If the file is
5
- missing, built-in engine defaults are used.
3
+ `site/theme.md` defines the site-wide visual theme for a `norna` site. It uses
4
+ YAML frontmatter and does not need a Markdown body. The root theme file is
5
+ required, but every setting inside it is optional and falls back to an engine
6
+ default.
6
7
 
7
- Page-level presentation in `site/content.md` and route page files is always an
8
- override on top of `site/theme.md`. Section-level presentation is an override
9
- on top of the resolved page presentation. Use those overrides for focused
10
- exceptions; the normal place for shared visual choices is `site/theme.md`.
8
+ An optional `theme.md` inside a route directory replaces the root visual theme
9
+ for that route. Route themes do not merge with the root theme: omitted values
10
+ use engine defaults. Shared identity such as brand and logo remains site-wide
11
+ and belongs in `sitewide-content.md`.
11
12
 
12
13
  ## Minimal Theme
13
14
 
14
15
  ```yaml
15
16
  ---
16
- navigation:
17
- brand: Example Site
18
17
  layout:
19
18
  density: normal
20
19
  pageWidth: 1180px
@@ -34,10 +33,10 @@ typography:
34
33
  preset: quiet-gallery
35
34
  rhythm: normal
36
35
  presentation:
37
- backgroundColor: "#000000"
38
- textColor: "#f7f4ee"
39
- frame:
40
- colors: presentation
36
+ palette: dark # Alternatives: light, paper
37
+ sectionSurfaces:
38
+ mode: cycle
39
+ sequence: [base, soft, emphasis]
41
40
  ---
42
41
  ```
43
42
 
@@ -46,23 +45,8 @@ Starter sites include a marked comment block such as
46
45
  explorable help text; YAML comments do not affect rendering. The active
47
46
  configuration is the uncommented YAML below it.
48
47
 
49
- ## Navigation
50
-
51
- `navigation` is optional. It currently supports:
52
-
53
- - `brand`: optional site-wide brand or home-link text shown in the site
54
- navigation.
55
-
56
- If `navigation.brand` is omitted, Norna uses the homepage `title` from
57
- `site/content.md`. Use `navigation.brand` when the homepage title is editorial
58
- or route-specific, but the navigation should keep a stable site name.
59
-
60
- Example:
61
-
62
- ```yaml
63
- navigation:
64
- brand: Norna
65
- ```
48
+ Site identity is not part of the visual theme. Define the optional navigation
49
+ brand and logo settings in `site/sitewide-content.md`; see [Sitewide Content](sitewide-content.md).
66
50
 
67
51
  ## Layout
68
52
 
@@ -74,9 +58,9 @@ navigation:
74
58
  `desktop` / `mobile` values.
75
59
  - `density`: default structural spacing profile. Allowed values are `compact`,
76
60
  `normal`, and `airy`.
77
- - `spacing`: optional structural spacing overrides for sections and Norna
78
- managed media blocks. Every spacing value accepts either one CSS length for all
79
- viewports or `desktop` / `mobile` values.
61
+ - `spacing`: optional spacing overrides for sections and content blocks. Every
62
+ spacing value accepts either one CSS length for all viewports or `desktop` /
63
+ `mobile` values.
80
64
 
81
65
  Example:
82
66
 
@@ -94,6 +78,12 @@ layout:
94
78
  sectionGap:
95
79
  desktop: clamp(1.4rem, 3vw, 2.75rem)
96
80
  mobile: 1.5rem
81
+ headingToBlock:
82
+ desktop: 0.75em
83
+ mobile: 0.7em
84
+ blockGap:
85
+ desktop: 1.5em
86
+ mobile: 1.25em
97
87
  ```
98
88
 
99
89
  If omitted, Norna uses `1180px` for `pageWidth`, desktop
@@ -105,11 +95,20 @@ Spacing keys:
105
95
  - `firstSectionTop`: space above the first section heading.
106
96
  - `sectionGap`: space above each following section.
107
97
  - `finalSectionBottom`: space below the final section.
108
- - `bodyToImages`: space from section body text to Norna managed media blocks.
98
+ - `headingToBlock`: space between a section heading and its first visual content
99
+ block, such as an image stack, carousel, or card list.
100
+ - `blockGap`: space between content blocks in a section. It applies between
101
+ Markdown, image, carousel, and card-list blocks, but not after the final block.
109
102
  - `imageGap`: space between stacked images or carousel blocks.
110
103
 
111
- Text-near spacing, such as spacing after headings, spacing before Markdown
112
- subheadings, paragraph spacing, and caption spacing, belongs to
104
+ The default `compact`, `normal`, and `airy` density profiles provide values for
105
+ these spacing keys. The `em` values for `headingToBlock` and `blockGap` are
106
+ relative to the relevant text size, so the rhythm follows typography changes.
107
+ Use `sectionGap` and the other structural keys when the distance should describe
108
+ the page layout rather than the size of nearby text.
109
+
110
+ Text-near spacing inside Markdown, such as spacing after headings, spacing
111
+ before Markdown subheadings, paragraph spacing, and caption spacing, belongs to
113
112
  `typography.rhythm` and typography overrides.
114
113
 
115
114
  ## Image Sizing
@@ -153,18 +152,20 @@ Example:
153
152
  ```yaml
154
153
  typography:
155
154
  fontFamily: "Arial, 'Helvetica Neue', Helvetica, sans-serif"
156
- preset: quiet-gallery
155
+ preset: text-forward
157
156
  rhythm: normal
158
157
  overrides:
159
158
  headings:
160
159
  h2:
161
160
  size: medium
161
+ weight: 600
162
162
  spacingAfter: 0.55em
163
163
  h3:
164
164
  size: medium
165
165
  spacingBefore: 1.5em
166
166
  spacingAfter: 0.5em
167
167
  body:
168
+ width: narrow
168
169
  lineHeight: 1.55
169
170
  ```
170
171
 
@@ -174,107 +175,39 @@ selected site. See [Typography](typography.md).
174
175
 
175
176
  ## Presentation
176
177
 
177
- `presentation` is optional. It can contain:
178
+ `presentation` is optional. It selects a small built-in visual palette for the
179
+ page frame and defines how section surfaces are assigned:
178
180
 
179
- - `backgroundColor`: optional quoted hex color in `#rgb`, `#rrggbb`, or
180
- `#rrggbbaa` form.
181
- - `textColor`: optional quoted hex color in `#rgb`, `#rrggbb`, or
182
- `#rrggbbaa` form.
183
- - `inlineStyles`: optional named inline text styles.
181
+ - `palette`: `dark`, `light`, or `paper`. The palette controls the page,
182
+ navigation, footer, and section colors.
183
+ - `sectionSurfaces.mode`: `none` or `cycle`.
184
+ - `sectionSurfaces.sequence`: optional sequence of `base`, `soft`, and
185
+ `emphasis`. Each surface may occur at most once.
184
186
 
185
187
  Example:
186
188
 
187
189
  ```yaml
188
190
  presentation:
189
- backgroundColor: "#101418"
190
- textColor: "#f4f1ea"
191
- ```
192
-
193
- ## Page And Section Overrides
194
-
195
- Site-wide presentation belongs in `site/theme.md`. Page-level presentation in a
196
- page file is always an override on top of the theme:
197
-
198
- ```yaml
199
- presentation:
200
- typography:
201
- overrides:
202
- headings:
203
- h2:
204
- size: large
205
- spacingAfter: 0.6em
206
- body:
207
- paragraphSpacing: 1em
208
- ```
209
-
210
- Section-specific presentation belongs under
211
- `sections.<section-id>.presentation`. Use it when one section genuinely needs
212
- different presentation; do not use `sections` to define section order or normal
213
- Markdown structure.
214
-
215
- ```yaml
216
- sections:
217
- intro:
218
- presentation:
219
- backgroundColor: "#161616"
220
- textColor: "#ffffff"
221
- typography:
222
- preset: statement
223
- ```
224
-
225
- If a page omits `presentation`, it uses the theme presentation unchanged. If a
226
- section omits `presentation`, it uses the resolved page presentation.
227
-
228
- Configured section backgrounds render as full-width horizontal bands while the
229
- section content keeps the normal page and image widths. The top spacing
230
- before the first heading, the spacing between sections, and the spacing after
231
- the final section are part of the section background.
232
-
233
- Configured section text colors apply to section headings, Markdown text,
234
- Markdown subheadings, and image captions. Links keep the global accent color.
235
-
236
- ## Frame Colors
237
-
238
- `frame.colors` controls the sticky navigation and footer colors.
239
-
240
- Allowed values:
241
-
242
- - `presentation`: use the resolved presentation colors for this level.
243
- - `theme`: use the site theme frame colors. This is useful in page-level
244
- frontmatter.
245
- - explicit colors:
246
-
247
- ```yaml
248
- frame:
249
- colors:
250
- backgroundColor: "#111111"
251
- textColor: "#eeeeee"
191
+ palette: paper # Alternatives: dark, light
192
+ sectionSurfaces:
193
+ mode: cycle
194
+ sequence: [base, soft, emphasis]
252
195
  ```
253
196
 
254
- The sticky section navigation row and footer use the resolved frame colors, not
255
- section-specific presentation.
197
+ ## Route Themes
256
198
 
257
- ## Inline Styles
199
+ Add `theme.md` to a route directory when that route should have a different
200
+ visual expression:
258
201
 
259
- `presentation.inlineStyles` defines named inline text styles that can be used
260
- from Markdown:
261
-
262
- ```yaml
263
- presentation:
264
- inlineStyles:
265
- highlight:
266
- color: "#ffd84d"
202
+ ```text
203
+ site/routes/010-guide/theme.md
267
204
  ```
268
205
 
269
- Inline style names must match `^[a-z][a-z0-9-]*$`. Each style currently
270
- supports a required `color` field using the same quoted hex color format as
271
- `textColor`.
272
-
273
- Apply an inline style in Markdown with `[text]{.style-name}`:
274
-
275
- ```md
276
- This sentence contains [highlighted text]{.highlight}.
277
- ```
206
+ The route theme uses the same visual schema as the root theme. It completely
207
+ replaces the root visual theme for that route, so include every non-default
208
+ visual choice the route needs. It cannot define navigation, brand, logo, or
209
+ technical configuration.
278
210
 
279
- `content:check` fails if Markdown uses an inline style that is not defined in
280
- `site/theme.md` `presentation.inlineStyles`.
211
+ Section surfaces render as full-width horizontal bands while the section
212
+ content keeps the normal page and image widths. Links keep the palette's global
213
+ accent color.
@@ -23,11 +23,21 @@ Available presets:
23
23
 
24
24
  If theme typography is omitted, `quiet-gallery` is used.
25
25
 
26
- Presets define alignment, size, and line height for `headings.h1` through
27
- `headings.h4`, `body`, and `caption`. Built-in presets use `medium` as the
28
- default size for every text role. Visual heading hierarchy comes from the
29
- Markdown heading level, so `h1` is larger than `h2`, `h2` is larger than `h3`,
30
- and so on.
26
+ Presets define alignment, size, weight, and line height for `headings.h1`
27
+ through `headings.h4`, `body`, and `caption`. They also choose a readable body
28
+ text width. Built-in presets use `medium` as the default size for every text
29
+ role. Visual heading hierarchy comes from the Markdown heading level, so `h1`
30
+ is larger than `h2`, `h2` is larger than `h3`, and so on.
31
+
32
+ The presets use these controls deliberately:
33
+
34
+ - `quiet-gallery` uses restrained heading weights and a normal reading width.
35
+ - `compact-gallery` uses stronger headings and a wider text column for short,
36
+ scannable content.
37
+ - `text-forward` uses a narrower reading width and more generous body line
38
+ height.
39
+ - `statement` uses the strongest heading weights and a narrow text column for
40
+ short, declarative content.
31
41
 
32
42
  `rhythm` defines text-near spacing for headings, paragraphs, and captions.
33
43
  Available rhythms are `compact`, `normal`, and `airy`. Built-in rhythm values
@@ -62,12 +72,14 @@ typography:
62
72
  headings:
63
73
  h2:
64
74
  size: medium
75
+ weight: 600
65
76
  spacingAfter: 0.55em
66
77
  h3:
67
78
  size: medium
68
79
  spacingBefore: 1.5em
69
80
  spacingAfter: 0.5em
70
81
  body:
82
+ width: narrow
71
83
  paragraphSpacing: 0.8em
72
84
  caption:
73
85
  spacingBefore: 0.5em
@@ -104,21 +116,31 @@ follows the Markdown level the user wrote: `##` uses `headings.h2`.
104
116
  `spacingAfter`, and `paragraphSpacing` are CSS lengths such as `0`, `0.8em`,
105
117
  `1rem`, or `12px`. Use `em` for spacing that should track the text size.
106
118
 
119
+ `weight` is a controlled heading weight. Allowed values are `400`, `500`,
120
+ `600`, and `700`. `body.width` is the readable text width and accepts
121
+ `narrow`, `normal`, or `wide`. It controls the prose column, not the page's
122
+ maximum width or the width of image blocks.
123
+
107
124
  Supported override fields:
108
125
 
109
- - `headings.h1.align`, `headings.h1.size`, `headings.h1.lineHeight`,
126
+ - `headings.h1.align`, `headings.h1.size`, `headings.h1.weight`,
127
+ `headings.h1.lineHeight`,
110
128
  `headings.h1.spacingBefore`, `headings.h1.spacingAfter`
111
- - `headings.h2.align`, `headings.h2.size`, `headings.h2.lineHeight`,
129
+ - `headings.h2.align`, `headings.h2.size`, `headings.h2.weight`,
130
+ `headings.h2.lineHeight`,
112
131
  `headings.h2.spacingBefore`, `headings.h2.spacingAfter`
113
- - `headings.h3.align`, `headings.h3.size`, `headings.h3.lineHeight`,
132
+ - `headings.h3.align`, `headings.h3.size`, `headings.h3.weight`,
133
+ `headings.h3.lineHeight`,
114
134
  `headings.h3.spacingBefore`, `headings.h3.spacingAfter`
115
- - `headings.h4.align`, `headings.h4.size`, `headings.h4.lineHeight`,
135
+ - `headings.h4.align`, `headings.h4.size`, `headings.h4.weight`,
136
+ `headings.h4.lineHeight`,
116
137
  `headings.h4.spacingBefore`, `headings.h4.spacingAfter`
117
- - `body.align`, `body.size`, `body.lineHeight`, `body.paragraphSpacing`
138
+ - `body.align`, `body.size`, `body.width`, `body.lineHeight`,
139
+ `body.paragraphSpacing`
118
140
  - `caption.align`, `caption.size`, `caption.lineHeight`,
119
141
  `caption.spacingBefore`
120
142
 
121
- ## Inheritance
143
+ ## Route Themes
122
144
 
123
145
  Theme typography is the site-wide base:
124
146
 
@@ -130,30 +152,20 @@ typography:
130
152
  rhythm: normal
131
153
  ```
132
154
 
133
- A page-level `presentation.typography.preset` changes the typographic character
134
- for that page. A section-level
135
- `sections.<section-id>.presentation.typography.preset` changes the typographic
136
- character for that section. `rhythm` is inherited separately, so changing
137
- preset does not change spacing unless `rhythm` is also set.
138
-
139
- If a section sets `typography.rhythm`, that section changes text-near spacing.
140
- If a section only sets `typography.overrides`, it keeps the resolved page
141
- preset and rhythm and changes only the specified values.
155
+ A route-local `theme.md` can give that route a different typographic character.
156
+ The route theme replaces the root visual theme rather than inheriting from it,
157
+ so repeat any non-default `fontFamily`, `rhythm`, or `overrides` that the route
158
+ still needs.
142
159
 
143
- Example section override:
160
+ Example route theme:
144
161
 
145
162
  ```yaml
146
- sections:
147
- intro:
148
- presentation:
149
- typography:
150
- preset: statement
151
- overrides:
152
- body:
153
- paragraphSpacing: 0.7em
163
+ # site/routes/010-introduction/theme.md
164
+ typography:
165
+ preset: statement
166
+ rhythm: normal
154
167
  ```
155
168
 
156
- Centered text uses narrower text widths. Left- or right-aligned heading and body
157
- text use the calculated image layout width so text edges line up with images
158
- after layout gutters and image limits are applied. Captions are normally
159
- centered.
169
+ The `body.width` value controls the prose column independently of the page and
170
+ image widths. Captions are normally centered, but `text-forward` uses
171
+ left-aligned captions to support longer explanatory text.
@@ -0,0 +1,9 @@
1
+ # Dog Shelter single-page example
2
+
3
+ A small Norna site with two homepage sections and no routes.
4
+
5
+ Run it from the Norna repository root:
6
+
7
+ ```sh
8
+ node bin/norna.mjs --site-dir examples/001-dog-shelter-single-page/site dev:local
9
+ ```
@@ -0,0 +1,27 @@
1
+ export default {
2
+ site: {
3
+ url: 'http://localhost:4321/',
4
+ basePath: '/',
5
+ },
6
+ navigation: {
7
+ smoothScroll: {
8
+ enabled: true,
9
+ minimumDurationMs: 600,
10
+ maximumDurationMs: 1_200,
11
+ durationPerPixelMs: 0.2,
12
+ },
13
+ },
14
+ locale: {
15
+ lang: 'en',
16
+ labels: {
17
+ skipToContent: 'Skip to content',
18
+ sectionNavigation: 'Sections',
19
+ gallery: 'Images',
20
+ },
21
+ },
22
+ github: {
23
+ repo: 'owner/dog-shelter',
24
+ branch: 'main',
25
+ pagesWorkflow: 'Deploy to GitHub Pages',
26
+ },
27
+ };
@@ -0,0 +1,38 @@
1
+ ---
2
+ title: Home
3
+ description: A single-page dog shelter website built with Norna.
4
+ ---
5
+
6
+ ## What we do {#what-we-do}
7
+
8
+ We rescue and rehome dogs.
9
+
10
+ <!-- norna-image-provenance:
11
+ image: dog-house.svg
12
+ source: AI-assisted, hand-authored SVG
13
+ prompt: Draw a simple flat vector dog house with a friendly dog at the entrance,
14
+ using a small paper, red and dark-brown palette. No text and no external assets.
15
+ -->
16
+
17
+ ```norna-image-stack
18
+ - image: dog-house.svg
19
+ alt: A brown dog standing at the entrance to a red dog house.
20
+ caption: Time to recover before adoption.
21
+ ```
22
+
23
+ ## You can help {#you-can-help}
24
+
25
+ Adopt. Foster. Donate.
26
+
27
+ <!-- norna-image-provenance:
28
+ image: heart.svg
29
+ source: AI-assisted, hand-authored SVG
30
+ prompt: Draw two simple hands holding a red heart as a flat vector illustration,
31
+ using a small paper, red and dark-brown palette. No text or external assets.
32
+ -->
33
+
34
+ ```norna-image-stack
35
+ - image: heart.svg
36
+ alt: Two open hands holding a red heart.
37
+ caption: Foster care helps another dog.
38
+ ```
@@ -0,0 +1,25 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 520" role="img" aria-labelledby="title desc">
2
+ <title id="title">Dog at a shelter house</title>
3
+ <desc id="desc">A friendly brown dog stands at the entrance to a red wooden dog house.</desc>
4
+ <rect width="800" height="520" rx="32" fill="#eef3ef"/>
5
+ <path d="M0 405 Q180 365 380 405 T800 390 V520 H0Z" fill="#cad8bd"/>
6
+ <g stroke="#493c2b" stroke-width="8" stroke-linejoin="round">
7
+ <path d="M190 247 L400 82 L610 247" fill="#9f493a"/>
8
+ <path d="M236 222 H564 V432 H236Z" fill="#c8674f"/>
9
+ <path d="M327 432 V300 Q327 234 400 234 Q473 234 473 300 V432Z" fill="#332d29"/>
10
+ <path d="M213 244 L400 94 L587 244" fill="none" stroke="#7f3f32" stroke-width="24" stroke-linecap="round"/>
11
+ </g>
12
+ <g transform="translate(310 250)" stroke="#493c2b" stroke-width="6" stroke-linejoin="round">
13
+ <path d="M40 119 C47 80 93 64 142 76 C181 86 196 119 184 158 H58 C42 151 34 135 40 119Z" fill="#b8794d"/>
14
+ <path d="M62 94 C45 61 58 23 96 13 C133 3 169 27 168 64 C167 93 145 108 112 109 H76Z" fill="#b8794d"/>
15
+ <path d="M76 32 L53 3 L98 17" fill="#8c573a"/>
16
+ <path d="M143 25 L171 3 L164 46" fill="#8c573a"/>
17
+ <circle cx="92" cy="53" r="6" fill="#272522" stroke="none"/>
18
+ <circle cx="140" cy="53" r="6" fill="#272522" stroke="none"/>
19
+ <ellipse cx="116" cy="76" rx="25" ry="19" fill="#dca477"/>
20
+ <circle cx="116" cy="70" r="7" fill="#272522" stroke="none"/>
21
+ <path d="M105 84 Q116 96 129 84" fill="none" stroke-linecap="round"/>
22
+ <path d="M59 154 V188 M94 154 V188 M145 154 V188" fill="none" stroke-linecap="round"/>
23
+ <path d="M177 105 Q220 80 211 39" fill="none" stroke-linecap="round"/>
24
+ </g>
25
+ </svg>
@@ -0,0 +1,13 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 520" role="img" aria-labelledby="title desc">
2
+ <title id="title">Hands holding a heart</title>
3
+ <desc id="desc">Two open hands support a large red heart.</desc>
4
+ <rect width="800" height="520" rx="32" fill="#f3eee5"/>
5
+ <circle cx="400" cy="250" r="176" fill="#e5dccd"/>
6
+ <path d="M400 354 C368 316 263 252 263 166 C263 108 309 79 354 92 C379 99 394 116 400 135 C406 116 421 99 446 92 C491 79 537 108 537 166 C537 252 432 316 400 354Z" fill="#b84f45" stroke="#493c2b" stroke-width="8" stroke-linejoin="round"/>
7
+ <g fill="#d5a071" stroke="#493c2b" stroke-width="7" stroke-linecap="round" stroke-linejoin="round">
8
+ <path d="M74 368 C144 330 211 328 291 365 L363 407 C382 420 373 451 350 450 L268 426 C228 414 191 421 154 451 L92 502 L30 429Z"/>
9
+ <path d="M726 368 C656 330 589 328 509 365 L437 407 C418 420 427 451 450 450 L532 426 C572 414 609 421 646 451 L708 502 L770 429Z"/>
10
+ <path d="M290 365 L350 349 C369 344 383 360 376 378 L363 407"/>
11
+ <path d="M510 365 L450 349 C431 344 417 360 424 378 L437 407"/>
12
+ </g>
13
+ </svg>
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Dog Shelter paw mark">
2
+ <rect width="64" height="64" rx="12" fill="#f8f5ee"/>
3
+ <g fill="#7f3f32">
4
+ <ellipse cx="32" cy="39" rx="16" ry="13"/>
5
+ <circle cx="16" cy="25" r="7"/>
6
+ <circle cx="29" cy="18" r="7"/>
7
+ <circle cx="43" cy="20" r="7"/>
8
+ <circle cx="50" cy="32" r="7"/>
9
+ </g>
10
+ </svg>
@@ -0,0 +1,2 @@
1
+ User-agent: *
2
+ Allow: /
@@ -0,0 +1,6 @@
1
+ ---
2
+ navigation:
3
+ brand: Dog Shelter
4
+ footer:
5
+ copyrightMessage: Dog Shelter example site.
6
+ ---
@@ -0,0 +1,25 @@
1
+ ---
2
+ layout:
3
+ density: normal
4
+ pageWidth: 1180px
5
+ gutter:
6
+ desktop: clamp(1.25rem, 4vw, 3rem)
7
+ mobile: 1rem
8
+ gallery:
9
+ width: 760px
10
+ maxAvailableWidthPercent:
11
+ desktop: 100
12
+ mobile: 100
13
+ maxAvailableHeightPercent:
14
+ desktop: 72
15
+ mobile: 68
16
+ typography:
17
+ fontFamily: "Arial, 'Helvetica Neue', Helvetica, sans-serif"
18
+ preset: text-forward
19
+ rhythm: normal
20
+ presentation:
21
+ palette: paper
22
+ sectionSurfaces:
23
+ mode: cycle
24
+ sequence: [base, soft]
25
+ ---
@@ -0,0 +1,9 @@
1
+ # Dog Shelter multi-page example
2
+
3
+ A small Norna site with a homepage and ordered routes for dogs and adoption.
4
+
5
+ Run it from the Norna repository root:
6
+
7
+ ```sh
8
+ node bin/norna.mjs --site-dir examples/002-dog-shelter-multi-page/site dev:local
9
+ ```
@@ -0,0 +1,27 @@
1
+ export default {
2
+ site: {
3
+ url: 'http://localhost:4321/',
4
+ basePath: '/',
5
+ },
6
+ navigation: {
7
+ smoothScroll: {
8
+ enabled: true,
9
+ minimumDurationMs: 600,
10
+ maximumDurationMs: 1_200,
11
+ durationPerPixelMs: 0.2,
12
+ },
13
+ },
14
+ locale: {
15
+ lang: 'en',
16
+ labels: {
17
+ skipToContent: 'Skip to content',
18
+ sectionNavigation: 'Sections',
19
+ gallery: 'Images',
20
+ },
21
+ },
22
+ github: {
23
+ repo: 'owner/dog-shelter',
24
+ branch: 'main',
25
+ pagesWorkflow: 'Deploy to GitHub Pages',
26
+ },
27
+ };
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: Home
3
+ description: A multi-page dog shelter website built with Norna.
4
+ ---
5
+
6
+ ## Dog Shelter {#intro}
7
+
8
+ We rescue dogs, help them recover and introduce them to families ready to give
9
+ them a permanent home.
10
+
11
+ Visit **Dogs** to meet two current residents, or **Adopt** to learn how the
12
+ adoption process works.
@@ -0,0 +1,10 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Dog Shelter paw mark">
2
+ <rect width="64" height="64" rx="12" fill="#f8f5ee"/>
3
+ <g fill="#7f3f32">
4
+ <ellipse cx="32" cy="39" rx="16" ry="13"/>
5
+ <circle cx="16" cy="25" r="7"/>
6
+ <circle cx="29" cy="18" r="7"/>
7
+ <circle cx="43" cy="20" r="7"/>
8
+ <circle cx="50" cy="32" r="7"/>
9
+ </g>
10
+ </svg>
@@ -0,0 +1,2 @@
1
+ User-agent: *
2
+ Allow: /
@@ -0,0 +1,19 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 560" role="img" aria-labelledby="title desc">
2
+ <title id="title">Rex</title>
3
+ <desc id="desc">A gentle golden dog with one floppy ear and a curved tail.</desc>
4
+ <rect width="800" height="560" rx="32" fill="#f3eee3"/>
5
+ <ellipse cx="404" cy="462" rx="270" ry="36" fill="#ddd1b8"/>
6
+ <g stroke="#493c2b" stroke-width="9" stroke-linejoin="round">
7
+ <path d="M218 316 C265 240 386 219 527 258 C594 277 623 343 589 404 H278 C221 391 196 354 218 316Z" fill="#e3c681"/>
8
+ <path d="M274 275 C237 202 279 112 370 91 C458 71 538 132 528 218 C520 285 464 318 389 317 H307Z" fill="#e3c681"/>
9
+ <path d="M309 134 L264 52 L365 91" fill="#c49b51"/>
10
+ <path d="M465 111 Q560 96 551 181 Q529 214 488 197Z" fill="#c49b51"/>
11
+ <circle cx="346" cy="187" r="11" fill="#272522" stroke="none"/>
12
+ <circle cx="451" cy="187" r="11" fill="#272522" stroke="none"/>
13
+ <ellipse cx="399" cy="239" rx="61" ry="45" fill="#f1dca9"/>
14
+ <circle cx="399" cy="225" r="14" fill="#272522" stroke="none"/>
15
+ <path d="M377 254 Q399 280 427 254" fill="none" stroke-linecap="round"/>
16
+ <path d="M281 400 V479 M374 400 V479 M511 400 V479" fill="none" stroke-linecap="round"/>
17
+ <path d="M568 294 Q676 330 642 420" fill="none" stroke-linecap="round"/>
18
+ </g>
19
+ </svg>