@heroiclands/package-build 22.26.0 → 22.28.0

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 (70) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +3 -1
  3. package/assets/styles/content-base.css +46 -3
  4. package/bin/content-commands.mjs +53 -5
  5. package/ci/publish-npm.mjs +49 -0
  6. package/docs/api.md +44 -24
  7. package/docs/authoring/first-note.md +1 -1
  8. package/docs/authoring/frontmatter.md +2 -2
  9. package/docs/authoring/links-and-markup.md +96 -149
  10. package/docs/content-format.md +7 -3
  11. package/docs/guides/government-migration.md +52 -0
  12. package/docs/guides/site.md +5 -5
  13. package/docs/reference/format-details.md +131 -230
  14. package/docs/reference/note-types.md +27 -29
  15. package/docs/reference/theme-pages.md +31 -29
  16. package/engine/anchors.mjs +85 -13
  17. package/engine/art-fields.mjs +1 -1
  18. package/engine/base-compiler.mjs +9 -1
  19. package/engine/bundles.mjs +1 -1
  20. package/engine/code-fences.mjs +6 -2
  21. package/engine/content-alerts.mjs +195 -0
  22. package/engine/content-blocks.mjs +119 -241
  23. package/engine/content-embeds.mjs +1 -1
  24. package/engine/content-figures.mjs +166 -230
  25. package/engine/content-format-check.mjs +3 -2
  26. package/engine/content-format.yaml +0 -5
  27. package/engine/content-images.mjs +3 -3
  28. package/engine/content-poetry.mjs +141 -0
  29. package/engine/content-spans.mjs +177 -0
  30. package/engine/folder-notes.mjs +2 -3
  31. package/engine/foundry-entries.mjs +2 -0
  32. package/engine/frontmatter-lint.mjs +2 -1
  33. package/engine/heading-attributes.mjs +1 -1
  34. package/engine/helpers.mjs +8 -3
  35. package/engine/holdings.mjs +165 -273
  36. package/engine/index.mjs +2 -2
  37. package/engine/infobox.mjs +1 -1
  38. package/engine/journals.mjs +8 -6
  39. package/engine/markdown-expressions.mjs +9 -3
  40. package/engine/metadata-index.mjs +2 -3
  41. package/engine/note-vocabulary.mjs +19 -15
  42. package/engine/pdf-build.mjs +1 -1
  43. package/engine/pdf-render.mjs +90 -31
  44. package/engine/populations.mjs +17 -83
  45. package/engine/site-build.mjs +44 -16
  46. package/engine/site-preview.mjs +22 -6
  47. package/engine/stub-lint.mjs +20 -64
  48. package/engine/wikilinks.mjs +18 -4
  49. package/githooks/pre-push +1 -1
  50. package/hugo-theme/layouts/partials/holdings/entry.html +2 -2
  51. package/hugo-theme/layouts/partials/holdings.html +14 -14
  52. package/hugo-theme/static/css/style.css +40 -2
  53. package/package.json +3 -1
  54. package/sohl/item-fields.mjs +0 -16
  55. package/types/engine/anchors.d.mts +13 -4
  56. package/types/engine/art-fields.d.mts +1 -1
  57. package/types/engine/code-fences.d.mts +3 -1
  58. package/types/engine/content-alerts.d.mts +62 -0
  59. package/types/engine/content-blocks.d.mts +3 -10
  60. package/types/engine/content-embeds.d.mts +1 -1
  61. package/types/engine/content-figures.d.mts +13 -20
  62. package/types/engine/content-images.d.mts +1 -1
  63. package/types/engine/content-poetry.d.mts +32 -0
  64. package/types/engine/content-spans.d.mts +18 -0
  65. package/types/engine/holdings.d.mts +59 -105
  66. package/types/engine/markdown-expressions.d.mts +1 -1
  67. package/types/engine/note-vocabulary.d.mts +12 -4
  68. package/types/engine/populations.d.mts +4 -13
  69. package/types/engine/site-build.d.mts +3 -3
  70. package/types/engine/wikilinks.d.mts +5 -1
@@ -567,9 +567,9 @@ an author writes — and each type that has any names them under its table.
567
567
 
568
568
  **An `Address` becomes a `Shortcode` where the target field expects one.** SoHL
569
569
  resolves a stored cross-reference among the items one actor holds, and packages do
570
- not exist there, so the field holds a `Shortcode`. Four `affiliation` fields are
570
+ not exist there, so the field holds a `Shortcode`. Three `affiliation` fields are
571
571
  authored as Addresses and stored that way: `data.seat` becomes `system.seat`,
572
- `data.parents` becomes `system.parents`, `data.domains` becomes `system.domain`,
572
+ `data.parents` becomes `system.parents`,
573
573
  and each authored key of `data.relations` becomes a key of `system.relations`. The
574
574
  reduction happens at build time, and two things are errors naming the note: an
575
575
  Address whose type the field does not accept, and two Addresses that reduce to one
@@ -1352,7 +1352,7 @@ Wikilinks contain complete Addresses. For example, `data.parents: [north]` in
1352
1352
 
1353
1353
  SQL queries compare Address-valued fields to complete Addresses. A note's
1354
1354
  `shortcode` is a distinct identity component, so it is not equal to an Address
1355
- stored in `data.parents`, `data.domains` or a governance rank's `lore`. Use the
1355
+ stored in `data.parents`, `data.government` or a governance rank's `lore`. Use the
1356
1356
  target's complete identity for that comparison. A stub has no published page
1357
1357
  address; its note identity still contains the package, system, type and shortcode.
1358
1358
 
@@ -1777,7 +1777,7 @@ a warning, flags an asset whose pixel width falls short of what its role's
1777
1777
  largest print slot needs. Both exempt a vector asset, which carries no pixel
1778
1778
  dimensions and no aspect that survives being drawn at a nominal size.
1779
1779
 
1780
- `role: map` also selects a `:::figure` fence's counter — see
1780
+ `role: map` also selects a captioned image's counter — see
1781
1781
  [figures and numbered references](../authoring/links-and-markup.md#figures-and-numbered-references).
1782
1782
  A fence whose picture draws an address with that role counts as `Map` rather
1783
1783
  than `Figure`, on every surface that numbers it, because the role is the one
@@ -2006,8 +2006,18 @@ convention rather than declared in a field — see
2006
2006
 
2007
2007
  ### Three states of a note
2008
2008
 
2009
- A note has three states, and two of them are nothing but conventions the format
2010
- already carried.
2009
+ Every typed note requires a nonempty body after its closing frontmatter fence.
2010
+ An empty or whitespace-only body is an error, regardless of description or
2011
+ `tags: [draft]`. This includes `folder` and `homepage` notes. Untyped vault
2012
+ scaffolding is excluded. A nonempty body with fewer than 25 prose words warns
2013
+ unless tagged `draft`; the tag never exempts an empty body.
2014
+
2015
+ The `lint`, `content-index`, `package compile`, `site` and `pdf` commands enforce
2016
+ body errors. Write a short beginning and tag it `draft` when work is unfinished.
2017
+
2018
+ The internal classification below describes records, including incomplete notes
2019
+ that inspection APIs can still read. A **stub** is invalid authored content and
2020
+ must receive a body before these commands can publish it.
2011
2021
 
2012
2022
  | State | Body | Marker | Page | Document | Link target |
2013
2023
  | --------- | ------- | --------------- | ------------ | --------------------------------- | ----------- |
@@ -2039,13 +2049,13 @@ same.
2039
2049
 
2040
2050
  | After the fence | Empty? | What happens |
2041
2051
  | ----------------------- | ------ | --------------------------------------------------------------- |
2042
- | Nothing, or blank lines | yes | A stub |
2052
+ | Nothing, or blank lines | yes | An error, with or without `draft` |
2043
2053
  | An HTML comment | no | A note with a body that renders to nothing. The lint reports it |
2044
2054
  | A horizontal rule | no | The same |
2045
2055
  | A lone heading | no | The same |
2046
2056
  | `_To be written._` | no | The same |
2047
2057
 
2048
- An HTML comment is deliberately not empty. An invisible marker does not make a valid stub; use an empty body when the note has no prose.
2058
+ An HTML comment is deliberately not empty, but an invisible marker does not supply prose. Replace placeholder-only content with written text.
2049
2059
 
2050
2060
  #### What a stub emits
2051
2061
 
@@ -2090,12 +2100,12 @@ What is suppressed with the page is the web address and the link target: a
2090
2100
  wikilink into a stub is refused, and a table cell listing one prints its name as
2091
2101
  plain text rather than as a link.
2092
2102
 
2093
- #### Two types are structural and exempt
2103
+ #### Structural classification does not exempt validation
2094
2104
 
2095
- `folder` and `homepage` have no body by design — a folder note's page is a
2096
- generated section index, and the homepage's is the site's front door. An empty
2097
- body on either keeps its address and resolves as **full**, because such a note is
2098
- complete.
2105
+ A `folder` note's page is a generated section index, and the homepage is the
2106
+ site's front door. The classification helpers retain their addresses and report
2107
+ **full** even when their bodies are empty. Validation still rejects an empty
2108
+ body for both types.
2099
2109
 
2100
2110
  Every type in the vocabulary declares whether an empty body suppresses its page,
2101
2111
  so adding a type means answering the question rather than inheriting a default.
@@ -2105,8 +2115,8 @@ so adding a type means answering the question rather than inheriting a default.
2105
2115
  `borders.to` and `routes.to` name a place by `Address`, and those are **index
2106
2116
  relations rather than page links**: a border with a stub on the far side is a
2107
2117
  valid statement about the world and resolves. So does `parents` for the
2108
- containment tree and `domains` for tenure — a stub appears in its region's
2109
- `contains` and on its holder's `holdings`, rendered as plain text. What a stub
2118
+ containment tree and `government` for governance — a stub appears in its region's
2119
+ `contains` and its governing body's `governed_places`, rendered as plain text. What a stub
2110
2120
  cannot be is the target of a wikilink, because a wikilink points at a page.
2111
2121
 
2112
2122
  ### What a note produces
@@ -2242,7 +2252,7 @@ See the [authoring examples](../authoring/links-and-markup.md#footnotes-and-defi
2242
2252
  ```
2243
2253
 
2244
2254
  Any header can end with a braced attribute block, in the same grammar a
2245
- `:::figure` fence and a named block take. Inside the braces:
2255
+ caption, fenced div, span and named block take. Inside the braces:
2246
2256
 
2247
2257
  - `#id` names the anchor a link resolves to (only one allowed)
2248
2258
  - `.class1` names a CSS class (any number of classes allowed)
@@ -2327,8 +2337,7 @@ applied to a word in the middle of a sentence.
2327
2337
  **Alt text renders as a caption on no surface.** On the website and in a
2328
2338
  Foundry journal it stays on the `img` element's `alt` attribute alone, and the
2329
2339
  book prints nothing beneath a picture that carries none. A visible label and
2330
- caption are drawn only for a picture wrapped in [a `:::figure`
2331
- fence](#the-figure-fence), and the text drawn is always the fence's own
2340
+ caption are drawn only for a picture preceded by [a caption](#captions-and-numbered-references), and the text drawn is always the fence's own
2332
2341
  caption. A title — `![alt](src "title")` — is refused rather than dropped in
2333
2342
  silence: there is one place for those words, the alt text, and a title is not
2334
2343
  it.
@@ -2621,179 +2630,122 @@ the tag and, where the directive restricts one, the type. An empty list under
2621
2630
  an authored heading is how a misspelled tag survives a build, so the
2622
2631
  directive's silence is what is refused rather than its output.
2623
2632
 
2624
- ##### The figure fence
2633
+ ##### Captions and numbered references
2625
2634
 
2626
- `:::figure {#anchor .border}` declares what it numbers and, optionally,
2627
- captions: the fence is the unit the counter counts, not the caption text it
2628
- may or may not carry.
2635
+ Write a caption on its own line **before** the item it describes, with a blank line before and after the caption. `:` produces an unnumbered caption; `:@` produces a numbered caption. One or more spaces separate the marker from its text. An optional attribute block at the end accepts an identifier, classes and named attributes:
2629
2636
 
2630
- ````markdown
2631
- :::figure {#trade}
2637
+ ```markdown
2638
+ :@ Regional trade routes {#trade .border type=table}
2632
2639
 
2633
- ```sql
2634
- SELECT name.full AS "Market" FROM notes WHERE type = 'place'
2640
+ | Route | Days |
2641
+ | ----- | ---- |
2642
+ | North | 4 |
2643
+
2644
+ Refer to {{ref "#trade"}} for the market routes.
2635
2645
  ```
2636
2646
 
2637
- ///
2638
- Regional trade routes
2639
- :::
2647
+ This displays **Table 1: Regional trade routes**; the reference links to **Table 1**. An unnumbered `: Regional trade routes {#trade}` displays only its text, has an anchor, and does not consume a number. An item with no caption remains unnumbered.
2640
2648
 
2641
- Refer to {{ref "#trade"}} for the market routes.
2642
- ````
2649
+ The caption attaches to exactly the next supported block:
2650
+
2651
+ | Next item | Inferred type | Numbered label |
2652
+ | ------------------------------------ | ------------- | -------------- |
2653
+ | Markdown table | `table` | Table |
2654
+ | Image, Markdown or wikilink | `figure` | Figure |
2655
+ | SQL fence, including backtick SQL | `table` | Table |
2656
+ | Poetry fence | `poetry` | Poem |
2657
+ | Any other code fence | `code` | Code |
2658
+ | Paragraph, quote block or fenced div | `prose` | Prose |
2643
2659
 
2644
- The fence displays **Table 1: Regional trade routes** and `{{ref "#trade"}}`
2645
- displays **Table 1** as a link.
2646
-
2647
- **The grammar.** `:::figure` opens the fence, on a line of its own and
2648
- optionally followed by a braced attribute block in the grammar a heading and
2649
- a named block take too. A line of `:::` alone closes it. Between the
2650
- two, the first `///` written alone on a line, read at the top level — outside
2651
- any nested code or poetry fence — divides what the fence holds from its caption; a `///`
2652
- written inside a nested fence is content, not a divider. A second top-level
2653
- `///` is an error, naming the line: a figure holds one caption, so it carries
2654
- one `///` line.
2655
-
2656
- An opening line that is not `:::figure`, optionally followed by one braced
2657
- attribute block and nothing else, is reported at its own line as
2658
- `a figure's attributes are written as {#id .border}`.
2659
-
2660
- **Every part but the fence itself is optional.**
2661
-
2662
- - **No `{#id}`.** The fence is still numbered and drawn; it carries no anchor,
2663
- so nothing can address it. An id, when written, must be a name unique within
2664
- the note — a repeat is `duplicate figure id "<id>"` at the fence's opening
2665
- line, and an id that collides with a heading anchor in the same note is
2666
- `heading and figure declare the same anchor "<id>"` at the heading's line.
2667
- - **No `///`.** The fence draws its label alone, with no caption beneath it. A
2668
- `///` with nothing after it before the closing `:::` is an error at the
2669
- `///` line: a figure's `///` section carries no caption — write no `///` to
2670
- leave the figure uncaptioned.
2671
- - **No `.border`.** The fence draws without one. `.border` is the only class
2672
- the construct declares; any other class is reported at the opening line,
2673
- naming it: a figure takes no such class, and the classes a figure takes
2674
- are `.border`. A `key="value"` attribute is reported the same way, naming
2675
- the key: a figure takes an id and classes, nothing else.
2676
-
2677
- **What is never optional.** A fence with nothing between its opening line and
2678
- its `///` or its closing `:::` is `a figure has no contents`, at the opening
2679
- line. An opening `:::figure` with no matching `:::` runs to the end of the
2680
- note and is `a figure needs a closing :::`, also at the opening line, and
2681
- nothing after it is scanned as a second fence.
2682
-
2683
- **The counter is derived, never authored.** The fence's contents decide which
2684
- of six counters it draws from — `Code`, `Table`, `Figure`, `Map`, `Poem`, `Prose` — read from
2685
- the first top-level block inside the fence: a table is `Table`; a fenced `sql`
2686
- block is `Table`, because its rendered output is one; any other fenced or
2687
- indented code block is `Code`; one or more pictures and nothing else is
2688
- `Figure`; a `:::poetry` fence as the first nonblank content is `Poem`; everything else is `Prose`. A poem, table or picture written outside any
2689
- `:::figure` fence draws no label and is counted nowhere. The website and a
2690
- Foundry journal number each counter within the note; the book numbers each
2691
- counter across the book in reading order.
2692
-
2693
- **A heading that would start its own journal page cannot be written inside a
2694
- fence.** An H1, or a heading at any level carrying an `{#anchor}`, is reported
2695
- at its own line inside one: `a heading that starts a page cannot be written
2696
- inside a figure — keep an H1 or an anchored heading at the top level, or drop
2697
- the anchor and the level to stay inside it`.
2698
-
2699
- **The `ref` expression renders a link to a figure's anchor.**
2700
- `{{ref "#thorn"}}` renders "Figure 13"; `{{ref "#thorn" form="full"}}` renders
2701
- the number and the caption; `{{ref "#thorn" form="title"}}` renders the
2702
- caption alone. `form="number"` is the default and may be written explicitly;
2703
- a `form` outside this closed set is reported naming the three. A link written
2704
- inside the figure's own caption contributes only its label text to a `full`
2705
- or `title` reference, because the reference is itself a link, and emphasis
2706
- inside the caption is kept. `form="full"` or `form="title"` aimed at a figure
2707
- with no caption is reported naming the anchor: that form needs a caption, and
2708
- the figure has none. An address naming no figure in the note is reported
2709
- naming the anchor; an address naming another note's figure —
2710
- `{{ref "other-note#anchor"}}` — is reported as addressing a figure this build
2711
- does not resolve outside the note carrying the reference. Only a same-note
2712
- anchor resolves, on the website and in the book.
2713
-
2714
- Foundry gives a `:::figure` fence its own JournalEntryPage. A fence holding
2715
- exactly one picture, captioned in plain text with nothing else — or carrying
2716
- no caption at all — becomes a page of type `image`: the picture is its `src`,
2717
- a caption, when there is one, is `image.caption`, and the page is named for
2718
- the figure's own number. Every other fence becomes a page of type `text`
2719
- instead: a fence grouping more than one picture; an embedded sound, there
2720
- being no audio page type; a fence whose caption carries inline markup —
2721
- emphasis, a link, an embedded icon or image — because `image.caption` is a
2722
- `StringField` with nowhere to render it; and a fence that shares its split
2723
- with prose that follows it, because an `image` page has nowhere to carry that
2724
- prose either. On a `text` page the render is the fence's own content, scanned
2725
- and labelled as the first of its kind on that page alone and then corrected to
2726
- the number the note-wide scan already assigned, so a second figure with no id
2727
- is still named for its true, note-wide number rather than recounted from one.
2728
-
2729
- ##### Named blocks
2730
-
2731
- `:::secret`, `:::info` and `:::warn` set a passage apart from the prose around
2732
- it. The opener and the closing `:::` each take a whole line, the content is
2733
- Markdown and renders normally, and the fences stay outside code blocks. An
2734
- empty, nested or unclosed block is an error at its opening line, as is a name
2735
- that is not one of the three.
2736
-
2737
- A braced attribute block may follow the name. It takes an id as `#id`, classes
2738
- as `.class`, and any other attribute as `key="value"`. `title` is reserved and
2739
- supplies the heading; without it a block heads itself **Secret**, **Info** or
2740
- **Warn**. A title carries its own emphasis and nothing else — a tag written
2741
- there is escaped. `id=` and `class=` are refused in favour of `#id` and
2742
- `.class`, and an attribute beginning `on` is refused as an event handler.
2660
+ The optional `type` attribute overrides inference and accepts `figure`, `table`, `poetry`, `code`, `prose`, and `example`. `type=example` uses **Example 1**, **Example 2**, and so on. It does not allow an unsupported target. A heading, list, thematic break, another caption or end of document after a caption is an error. Caption markers without separating spaces or caption text are errors too.
2661
+
2662
+ Identifiers are optional and must be unique within the note. Classes are unrestricted; `.border` uses the shared border style, while other classes can be styled by the medium. Named attributes use `key=value`, with quoted values for text containing spaces. Use `#id` and `.class` rather than `id=` and `class=`; event-handler attributes are refused.
2663
+
2664
+ Each numbered type has its own counter. Websites and Foundry number within a note; books number across their reading order. Unnumbered captions neither display nor consume a number. A map image can retain its asset-derived **Map** classification when no type is specified.
2665
+
2666
+ `{{ref "#trade"}}` displays the numbered label as a link. `form="full"` includes caption text and `form="title"` displays the caption alone. Use title form for an unnumbered caption. Cross-note references can name the note address before the anchor, such as `{{ref "place-harbor#trade"}}`; the displayed number belongs to the target on the surface rendering it. Links inside caption text contribute their visible text to references, so the reference does not contain a nested link.
2667
+
2668
+ Foundry gives a captioned item its own JournalEntryPage. A solitary image with a plain caption can use an image page; captions with inline markup and other items use text pages. On the website and in the book the item stays in the flow of the surrounding page.
2669
+
2670
+ **Migration:** `:::figure` is no longer supported. Move the former `///` caption before the item as `:@ Caption {#id}` and remove the figure wrapper. To caption a group or passage, put it inside a generic fenced div and caption that div with an explicit type if needed. `///` is no longer a caption delimiter.
2671
+
2672
+ ##### Fenced divs
2673
+
2674
+ A bare `:::` opens a div section. An optional attribute block applies to the whole fenced area. A bare `:::` closes the section:
2743
2675
 
2744
2676
  ```markdown
2745
- :::info
2677
+ ::: {#harbor-note .border lang=en}
2746
2678
  The harbor remains open through winter.
2747
- :::
2748
2679
 
2749
- :::warn {#flood-warning title="Seasonal closure"}
2750
- Spring floods close the eastern road.
2680
+ A second paragraph belongs to the same div.
2751
2681
  :::
2682
+ ```
2752
2683
 
2753
- :::secret {#harbor .wide}
2754
- The harbor master is working for the smugglers.
2755
- :::
2684
+ An attribute-bearing opener allows a nested div to be distinguished from the bare closer. Divs carry no automatic title or number; style their classes for the medium. Use a leading caption to caption the entire div. The same attribute grammar is available on named blocks; identifiers, classes and named attributes belong to the entire section. Headings that would start a Foundry journal page cannot split a fenced section.
2685
+
2686
+ ##### Inline spans
2687
+
2688
+ `[inline content]` represents a span. Follow it immediately with an optional attribute block to apply an identifier, classes and named attributes:
2689
+
2690
+ ```markdown
2691
+ The watch wears [a _blue_ sash]{#watch-sash .uniform lang=en}.
2756
2692
  ```
2757
2693
 
2758
- The block's name is the first class on the emitted element and the author's
2759
- classes follow it. **No block carries an inline `style`**, so the appearance is
2760
- a stylesheet's. The base stylesheet styles `section.info` and `section.warn`;
2761
- `section.secret` is left to Foundry, which styles it and owns the reveal control
2762
- on it.
2694
+ Inline Markdown remains active inside the span. Bracket spans have lower priority than URL links, image links, reference links, footnotes and wikilinks. A bracketed form immediately preceded by `!`, followed by `(` or another `[`, or beginning with `[[` is not a span, even when the link is unresolved. Ordinary links retain their existing syntax. Escape a bracket when it should be literal, or put examples inside a code span or fence. A span identifier addresses that point in the note; it does not start a journal page.
2695
+
2696
+ ##### Alerts
2763
2697
 
2764
- In FoundryVTT a block is a section whose first line is its heading, and a
2765
- `secret` is the section Foundry shows to the GM and to owners of the journal:
2698
+ Alerts replace the former `:::info` and `:::warn` fences. Start with a special blockquote marker, optionally followed by an attribute block, then write the alert body as a standard blockquote:
2766
2699
 
2767
- ```html
2768
- <section class="secret wide" id="harbor">
2769
- <strong>Secret</strong><br />
2770
- <p>The harbor master is working for the smugglers.</p>
2771
- </section>
2700
+ ```markdown
2701
+ > [!NOTE]
2702
+ > Useful information that users should know, even when skimming content.
2703
+
2704
+ > [!TIP]
2705
+ > Helpful advice for doing things better or more easily.
2706
+
2707
+ > [!IMPORTANT]
2708
+ > Key information users need to know to achieve their goal.
2709
+
2710
+ > [!WARNING]
2711
+ > Urgent info that needs immediate user attention to avoid problems.
2772
2712
  ```
2773
2713
 
2774
- A `secret` that states no id of its own is given one derived from its body, so
2775
- that Foundry can remember the section once a reader reveals it.
2714
+ | Marker | Label | Appearance |
2715
+ | -------------- | --------- | ------------------------------------------------- |
2716
+ | `[!NOTE]` | Note | Blue rule and `fa-regular fa-message` |
2717
+ | `[!TIP]` | Tip | Green rule and `fa-regular fa-lightbulb` |
2718
+ | `[!IMPORTANT]` | Important | Purple rule and `fa-solid fa-circle-info` |
2719
+ | `[!WARNING]` | Warning | Amber rule and `fa-solid fa-triangle-exclamation` |
2776
2720
 
2777
- On webpages a block is a disclosure any reader can open, titled in its summary:
2721
+ The label and icon sit above the body. Alerts are visible callouts, not expandable sections. Inline Markdown, links, multiple paragraphs, lists and code examples remain available inside the quote. Prefix blank lines within the body with `>` to keep paragraphs in the same alert.
2778
2722
 
2779
- ```html
2780
- <details class="secret wide" id="harbor">
2781
- <summary class="secret">Secret</summary>
2782
- <p>The harbor master is working for the smugglers.</p>
2783
- </details>
2723
+ Attributes follow the marker and apply to the alert:
2724
+
2725
+ ```markdown
2726
+ > [!WARNING] {#flood-warning .seasonal lang=en title="Seasonal closure"}
2727
+ > The eastern road closes during spring floods.
2728
+ >
2729
+ > Use the ridge path instead.
2784
2730
  ```
2785
2731
 
2786
- In a book each block is a coloured box headed by its title. A printed page has
2787
- no reader permissions and no interactive disclosure control, so a `secret` is
2788
- visible there.
2732
+ Use `#id`, `.class` and named attributes in the shared braced grammar. The marker determines the default label, icon and color. An authored `title` replaces the default **Note**, **Tip**, **Important** or **Warning** heading while preserving the alert type’s icon and color. Event-handler attributes, malformed attributes, unknown alert types and empty alert bodies are errors. Ordinary blockquotes and alert examples inside literal code remain unchanged. A leading caption can describe an alert as a quote block, normally with the `prose` type or an explicit `example` type.
2733
+
2734
+ Migrate former info blocks to `[!NOTE]` alerts and warn blocks to `[!WARNING]` alerts. The old named fences are errors. `:::secret` remains supported.
2789
2735
 
2790
- **A secret is a presentation distinction and not access control.** It is in the
2791
- same authored note as the prose around it, and a reader who inspects source or
2792
- generated output may see it.
2736
+ ##### Secret blocks
2793
2737
 
2794
- **A malformed block does not silence the blocks around it.** It is reported at
2795
- its own line and left as the author wrote it, and every well-formed block in the
2796
- note still renders.
2738
+ `:::secret` sets GM material apart. Its optional attributes accept an identifier, classes and named attributes. `title` supplies its heading; without a title the heading is **Secret**:
2739
+
2740
+ ```markdown
2741
+ :::secret {#harbor-secret title="For the GM"}
2742
+ The harbor master is working for the smugglers.
2743
+ :::
2744
+ ```
2745
+
2746
+ A secret block can contain alerts and general divs. It cannot contain another secret block. A heading that starts its own journal page cannot split a secret block or general div; use a lower heading without an anchor within the section.
2747
+
2748
+ Foundry renders a secret section; the website renders an expandable spoiler, and the book renders a labeled box. An untitled secret takes its normal default title, and a Foundry secret without an id receives an id derived from its body. The presentation does not make published HTML private: deliberately inspecting generated source can reveal its content. Use YAML comments for information that must never be published.
2797
2749
 
2798
2750
  #### Actors
2799
2751
 
@@ -3383,7 +3335,6 @@ rank names the standing, and the standing says.
3383
3335
  | `governance.ranks` | `Rank[]` | The ranks available to members of the affiliation |
3384
3336
  | `governance.offices` | `Map<name, description \| {description, holders}>` | Official offices and their dated holders |
3385
3337
  | `seat` | `Address` | Where the affiliation's authority sits |
3386
- | `domains` | `Address[]` | Places over which this affiliation holds sway |
3387
3338
  | `population` | `number` | Number of people in the affiliation (precision 2 significant digits). |
3388
3339
  | `economy` | `Address[]` | Economic life: `affiliation` or `lore` Addresses, with an explicit type and no default |
3389
3340
  | `lore` | `Address[]` | Lore concerning it — the peoples it draws on, the god a faith venerates, its law, its calendar |
@@ -3443,37 +3394,7 @@ data:
3443
3394
  - { being: being-mara, start: "datefrom vrcal 2 Lusenar 725 VR" }
3444
3395
  ```
3445
3396
 
3446
- **`domains` is territorial, and only territorial.** Seventy-seven divine
3447
- affiliations currently spell `domain:` the other way, holding a deity's sphere of
3448
- influence as prose — _Love, Beauty, and Prosperity_; _Fertility, Agriculture,
3449
- Peace, and Healing_. That sense **folds into `description`**, which those notes
3450
- leave empty in all but one case, and it does not become a field of its own.
3451
-
3452
- A sphere is a characterisation, not a reference. Nothing compiles against it, no
3453
- other note points at it, and rendering it as a list would imply a vocabulary that
3454
- does not exist — whereas `description` is exactly the field for a one-line
3455
- statement of what a thing is. The fuller treatment already has a home: `lore` of
3456
- subType `deity` covers a god's nature, domains, epithets and aspects in prose.
3457
-
3458
- That frees the name for the territorial sense, which earns it: every affiliation
3459
- subType holds sway somewhere, while the divine sense applies to one.
3460
-
3461
- **`domains` names what the affiliation holds directly**, and nothing beneath
3462
- it. A polity whose `domains` names a region holds the region; the settlements
3463
- within it are the region's, reached through its `contains`, and are not
3464
- repeated here. A house holds its manors and names each; the crown holds the
3465
- realm and names the realm. What lies below a holder is answered by the two
3466
- hierarchies together — `place.parents` for where a place sits, and
3467
- `affiliation.parents` for whom a holder answers to — so a subinfeudated manor
3468
- sits in one region by the first and under a lord of another polity by the
3469
- second, and both pages say so.
3470
-
3471
- The website reads `domains` across the package and every fetched index and
3472
- writes the affiliation's page a `holdings` list — every place its `domains`
3473
- names, each entry `{ title, url, type, subType }`, sorted by `subType` then
3474
- `title`, and absent when `domains` names nothing. Every place it names carries
3475
- the affiliation back in `held_by`. Both are derived; a note that writes one has
3476
- it replaced.
3397
+ **Governed places are derived from place notes.** Each place names one governing affiliation in `data.government`. The website writes the body's `governed_places` list by resolving those explicit references across local notes and fetched indexes. Each entry is `{ title, url, type, subType }`, sorted by `subType` then `title`; an empty list is omitted. No affiliation-side list supplies government, and neither geographic containment nor organizational parents expands it.
3477
3398
 
3478
3399
  If `sohl` is present, this becomes an `affiliation` item.
3479
3400
 
@@ -3481,7 +3402,6 @@ If `sohl` is present, this becomes an `affiliation` item.
3481
3402
  | ---------------- | ------------------ | ----- |
3482
3403
  | `subType` | `system.subType` | NA |
3483
3404
  | `data.seat` | `system.seat` | NA |
3484
- | `data.domains` | `system.domain` | NA |
3485
3405
  | `data.parents` | `system.parents` | NA |
3486
3406
  | `data.relations` | `system.relations` | NA |
3487
3407
 
@@ -4263,7 +4183,7 @@ map's prose.
4263
4183
  | `lore` | `Address[]` | Lore concerning this place — its peoples, its law, its calendar, its history |
4264
4184
  | `parents` | `Address[]` | Enclosing places within which this place is located |
4265
4185
  | `population` | `number` | Approximate population (precision 2 significant digits) |
4266
- | `government` | affiliation Address or `null` | Governing affiliation; explicit null means complete anarchy. Omission warns only for positive population. |
4186
+ | `government` | `Address` or `null` (default type: `affiliation`) | Governing affiliation; explicit null means complete anarchy. Omission warns only for positive population. |
4267
4187
  | `market` | `number` | Market class, 1 to 6 — what trade a settlement supports |
4268
4188
  | `borders` | `{ to, bearing }[]` | Places sharing a frontier with this one, and where each lies from here |
4269
4189
  | `routes` | `{ to, bearing, mode, days, terrain?, leagues? }[]` | Journeys from this place's centre to another place |
@@ -4484,27 +4404,13 @@ than the package that wrote it.
4484
4404
  | `river` | boat |
4485
4405
  | `lake` | boat |
4486
4406
 
4487
- #### What lies within a place, and who holds it
4488
-
4489
- `parents` states what a place is within; an affiliation's `domains` states
4490
- what it holds. The website reads both across the package and every fetched
4491
- index and writes each place's page two lists, each entry
4492
- `{ title, url, type, subType }` and each absent when empty:
4493
-
4494
- - `contains` — every place whose `parents` names this one, sorted by
4495
- `subType` then `title`. A region lists its settlements, sites, structures
4496
- and features; a settlement lists the structures within it.
4497
- - `held_by` — every affiliation whose `domains` names this one, sorted by
4498
- `title`.
4407
+ #### What lies within a place
4499
4408
 
4500
- Both are derived; a note that writes one has it replaced. **`domains` is
4501
- never expanded**: a region held by a polity lists the polity in `held_by`, and
4502
- a settlement within that region lists only the house or order whose `domains`
4503
- names it — its lord's lord is reached through `affiliation.parents`.
4409
+ `parents` states what a place is within. The website reads this across the package and every fetched index and writes `contains`: every place whose `parents` names this one, sorted by `subType` then `title`. Each entry is `{ title, url, type, subType }`; the list is omitted when empty. A region lists its settlements, sites, structures and features; a settlement lists its structures. Government never changes this geographical containment.
4504
4410
 
4505
4411
  #### Who governs a place
4506
4412
 
4507
- A place may state its governing affiliation in `data.government`. Use an affiliation Address, either a local shortcode or a fully qualified Address from this package or a fetched dependency:
4413
+ A place may state its governing affiliation in `data.government`. The field type is `Address`, with `affiliation` as the default target type when the type is omitted. Use either a local shortcode or a fully qualified affiliation Address from this package or a fetched dependency:
4508
4414
 
4509
4415
  ```yaml
4510
4416
  data:
@@ -4521,20 +4427,15 @@ Write `government: null` for **complete anarchy**. Omitting the key leaves gover
4521
4427
  | Any | Explicit `null` | None; complete anarchy |
4522
4428
  | Any | Affiliation Address | None; the reference must resolve |
4523
4429
 
4524
- These rules apply to every place subtype, including settlements, sites, structures, features, regions and worlds. Empty strings, numbers, lists, maps, references to another note type and unresolved references are errors. They do not declare anarchy. `domains`, `parents`, containment and capitals do not supply a government. Holdings remain tenure facts; the former unconditional “unheld land” warning is retired.
4430
+ These rules apply to every place subtype, including settlements, sites, structures, features, regions and worlds. Empty strings, numbers, lists, maps, references to another note type and unresolved references are errors. They do not declare anarchy. `domains`, `parents`, containment and capitals do not supply a government. Legacy affiliation `data.domains` is accepted temporarily but ignored. Preserve ownership and influence facts in prose; see [government migration](../guides/government-migration.md).
4525
4431
 
4526
4432
  #### Population figures
4527
4433
 
4528
4434
  `population` is an approximate count, written to two significant digits. A
4529
4435
  place states one, and so does an affiliation — how many people it counts,
4530
4436
  wherever they are. `package-build lint` reads those figures against each other
4531
- and reports four warnings, each named by the phrase its message begins with.
4437
+ and reports three warnings, each named by the phrase its message begins with.
4532
4438
 
4533
- - **`over-held land`** — the polities whose `domains` name a place count more
4534
- people than the place states. A polity subordinate to another polity holding
4535
- the same place is already inside that polity's figure and is not counted
4536
- twice. A **settlement is exempt**: the polity of a city-state holds the city
4537
- and counts the hinterland around it, so its figure is properly the larger.
4538
4439
  - **`over-full region`** — the regions whose `parents` name a place count more
4539
4440
  people than the place states. A region naming both its parent and its
4540
4441
  grandparent counts under the nearer of the two, so a place written into two
@@ -4546,7 +4447,7 @@ and reports four warnings, each named by the phrase its message begins with.
4546
4447
  located at the number the page wrote, and a figure written twice is located
4547
4448
  twice.
4548
4449
 
4549
- The first three are reported on the note's own `data.population`; the fourth
4450
+ The first two are reported on the note's own `data.population`; the third
4550
4451
  on the citation.
4551
4452
 
4552
4453
  **A figure is read as a population only where it carries `~`.** That marker is
@@ -4561,7 +4462,7 @@ cent below what it contains is not a finding.
4561
4462
  **An unstated figure is silent.** A place or affiliation with no `population`
4562
4463
  contributes nothing to a sum and is never the subject of a finding, so a
4563
4464
  half-written region is quiet rather than noisy. A fetched index carries
4564
- `population` alongside `parents` and `domains` when its author stated a
4465
+ `population` alongside `parents` and `government` when its author stated a
4565
4466
  figure. An older fetched index with no figure remains silent.
4566
4467
 
4567
4468
  **There is deliberately no urban-share rule.** The share of a region's people
@@ -4570,8 +4471,8 @@ settlement layer names the notable places and is complete nowhere, so the ratio
4570
4471
  reports how much of a region has been written rather than how much of it is
4571
4472
  urban.
4572
4473
 
4573
- **A place declares what is true of its ground.** Its governing affiliations
4574
- carry their own `domains`; maps name the place they depict through `data.place`.
4474
+ **A place declares what is true of its ground.** It names its governing affiliation
4475
+ in `data.government`; maps name the place they depict through `data.place`.
4575
4476
  The place's `lore` links cover its peoples, calendar, law and history. Political
4576
4477
  languages belong to a polity's `sohl.system.commonSkills`, while the note's
4577
4478
  `description` provides its page summary.
@@ -4844,8 +4745,8 @@ the map for the pack it is writing and falls back to `default` when there is no
4844
4745
  such key, so a mistyped `journal:` files the folder wherever the default puts it
4845
4746
  — exactly the hierarchy the key was written to override, and silently.
4846
4747
 
4847
- **A folder note carries no prose.** It is structure, not content, so it produces
4848
- no documentation journal and takes no part in `docEntryTypes`.
4748
+ **A folder note requires a body**, like every typed note. Its body does not
4749
+ produce a documentation journal or take part in `docEntryTypes`.
4849
4750
  In a compiled Foundry journal, a wikilink to a folder prints its label as text:
4850
4751
  the folder can materialise in several packs and has no single compendium UUID.
4851
4752