Skip to main content

moss_core/contract/
components.rs

1//! moss component contract — Source 2 of the federated contract.
2//!
3//! Single source of truth for every `moss-*` class moss currently emits.
4//! Each entry declares: the class name, its kind (container/instance/standalone/chrome),
5//! accepted `data-*` attributes with value spaces, example HTML, example markdown.
6//!
7//! ## Adding a new emitter class
8//!
9//! 1. Emit the class from your renderer module (`build/markdown/*`, `build/components/*`).
10//! 2. Add a `ComponentEntry` to [`COMPONENTS`] here.
11//! 3. Run `cargo test --test components_sync_test` from src-tauri/ — the
12//!    scanner test will fail if you forget.
13//! 4. Run `cargo run --bin generate-contract-docs --features dev-tools` to
14//!    refresh `docs/contract/reference.md`.
15//!
16//! ## Why a const table, not a derive macro?
17//!
18//! Mirrors the BUILTIN_FIELDS precedent in `schema_fields.rs`. The synchronization
19//! is enforced by a sync test (`emitter_classes_match_components_table`) that
20//! scans emitter Rust source for `class="moss-..."` literals. This is a
21//! best-effort scanner (won't catch classes assembled via `format!()`), not a
22//! type-checked guarantee like BUILTIN_FIELDS' compile-time mirror. The
23//! limitation is documented in the spec § Source 2.
24
25/// Status of a component entry.
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum Status {
28    /// In active use; theme authors can rely on it.
29    Confirmed,
30    /// Emerging convention; may evolve.
31    Emerging,
32    /// Scheduled for removal; theme authors should migrate.
33    Retired,
34}
35
36/// A declared `data-*` attribute on a component.
37pub struct DataAttr {
38    /// Attribute name including `data-` prefix (e.g. `"data-layout"`).
39    pub name: &'static str,
40    /// Allowed values (e.g. `&["grid", "list", "minimal"]`). Empty means free-form.
41    pub values: &'static [&'static str],
42    /// Default value (first in `values`, or `""` for free-form).
43    pub default: &'static str,
44    /// Short description shown in reference.md.
45    pub description: &'static str,
46}
47
48/// A single component contract entry.
49pub struct ComponentEntry {
50    /// Class name without leading `.` (e.g. `"moss-cards"`).
51    pub class: &'static str,
52    /// Container / Instance / Standalone / Chrome.
53    pub kind: &'static str,
54    /// For Instance kinds, the parent container's class (or `""`).
55    pub parent: &'static str,
56    /// Declared `data-*` attributes on the element with this class.
57    pub data_attrs: &'static [DataAttr],
58    /// Example HTML snippet showing the class in context. Multi-line allowed.
59    pub example_html: &'static str,
60    /// Example markdown that produces this HTML. Empty for HTML-only chrome.
61    pub example_markdown: &'static str,
62    /// Status: confirmed / emerging / retired.
63    pub status: Status,
64    /// Contract version this entry was introduced in.
65    pub since: &'static str,
66    /// Optional human-readable description.
67    pub description: &'static str,
68}
69
70/// The full contract surface — every `moss-*` class moss currently emits.
71///
72/// Phase 0b seeds this with the CURRENT emitted vocabulary (not the
73/// v1-collapsed shape). Phase 1c rewrites to the collapsed form.
74pub const COMPONENTS: &[ComponentEntry] = &[
75    ComponentEntry {
76        class: "moss-cards",
77        kind: "container",
78        parent: "",
79        data_attrs: &[
80            DataAttr {
81                name: "data-layout",
82                values: &["grid", "list", "minimal"],
83                default: "grid",
84                description: "Card layout density. Grid: 2-3 cols with covers. List: single column with side covers. Minimal: text-only with year groupings.",
85            },
86            DataAttr {
87                name: "data-density",
88                values: &["default", "compact"],
89                default: "default",
90                description: "Vertical spacing density.",
91            },
92            DataAttr {
93                name: "data-list-axis",
94                values: &["date", "weight", "title"],
95                default: "title",
96                description: "Sort axis for the listing (mirrors the folder's `sort:` frontmatter). Drives `--moss-card-min` density tuning and decides whether each `.moss-card-meta` slot is filled (date axis) or omitted (weight/title axes).",
97            },
98            DataAttr {
99                name: "data-list-has-covers",
100                values: &[""],
101                default: "",
102                description: "Boolean presence flag: emitted iff any child card has a cover. Combines with `data-list-axis` to widen `--moss-card-min` for cover-led layouts. Use `[data-list-has-covers]` in CSS to target it.",
103            },
104        ],
105        example_html: r#"<div class="moss-cards-container">
106  <div class="moss-cards" data-layout="grid" data-list-axis="date" data-list-has-covers>
107    <a class="moss-card" href="...">...</a>
108    <a class="moss-card" href="...">...</a>
109  </div>
110</div>"#,
111        example_markdown: "",
112        status: Status::Confirmed,
113        since: "1",
114        description: "Auto-generated listing of child pages. The single canonical container; layout density on `data-layout` (`grid` for cover-led tiles, `list` for cover+excerpt rows, `minimal` for text-only year-grouped indexes). Wrapped in `.moss-cards-container` to scope CSS container queries.",
115    },
116    ComponentEntry {
117        class: "moss-cards-container",
118        kind: "container",
119        parent: "",
120        data_attrs: &[],
121        example_html: r#"<div class="moss-cards-container">
122  <div class="moss-cards" data-layout="grid">...</div>
123</div>"#,
124        example_markdown: "",
125        status: Status::Confirmed,
126        since: "1",
127        description: "Outer wrapper around `.moss-cards` that carries `container-type: inline-size` so the grid can use `@container` queries instead of viewport `@media` queries. Layout-agnostic — wraps any `data-layout` variant.",
128    },
129    ComponentEntry {
130        class: "moss-summary-layout",
131        kind: "container",
132        parent: "moss-cards",
133        data_attrs: &[],
134        example_html: r#"<div class="moss-cards" data-layout="list">...</div>"#,
135        example_markdown: "",
136        status: Status::Retired,
137        since: "1",
138        description: "Retired: the additional co-class on `.moss-cards[data-layout=\"list\"]` had no matching rules in the default CSS once `children_style: summary` collapsed into the list-layout block, and its lingering emission broke themes that hid the class (e.g. SoCiviC's `.moss/theme/style.css` keyed `display: none` on it, erasing folder-embed listings). Theme authors targeting summary listings should use `.moss-cards[data-layout=\"list\"]` directly.",
139    },
140    // -------------------------------------------------------------------
141    // Cards family — current emitted vocabulary (pre-Phase 1c collapsing).
142    // Three parallel layouts: grid, list, minimal. Each has its own
143    // container + instance + sub-classes.
144    // -------------------------------------------------------------------
145    ComponentEntry {
146        class: "moss-cards-grid",
147        kind: "container",
148        parent: "",
149        data_attrs: &[],
150        example_html: r#"<div class="moss-cards-grid">
151  <a class="moss-card-grid" href="...">...</a>
152</div>"#,
153        example_markdown: "",
154        status: Status::Retired,
155        since: "0",
156        description: "Retired in Phase 1c — collapsed into `.moss-cards[data-layout=grid]`.",
157    },
158    ComponentEntry {
159        class: "moss-cards-list",
160        kind: "container",
161        parent: "",
162        data_attrs: &[],
163        example_html: r#"<div class="moss-cards-list">
164  <a class="moss-card-list" href="...">...</a>
165</div>"#,
166        example_markdown: "",
167        status: Status::Retired,
168        since: "0",
169        description: "Retired in Phase 1c — collapsed into `.moss-cards[data-layout=list]`.",
170    },
171    ComponentEntry {
172        class: "moss-cards-minimal-year-group",
173        kind: "container",
174        parent: "",
175        data_attrs: &[],
176        example_html: r#"<section class="moss-cards-minimal-year-group">
177  <h3>2024</h3>
178  <div class="moss-card-minimal">...</div>
179</section>"#,
180        example_markdown: "",
181        status: Status::Confirmed,
182        since: "0",
183        description: "Year-grouped section in minimal card layout (e.g. blog index). Modifier `--summary` collapses past years.",
184    },
185    ComponentEntry {
186        class: "moss-cards-minimal-year-group--summary",
187        kind: "container",
188        parent: "moss-cards-minimal-year-group",
189        data_attrs: &[],
190        example_html: r#"<section class="moss-cards-minimal-year-group moss-cards-minimal-year-group--summary">...</section>"#,
191        example_markdown: "",
192        status: Status::Confirmed,
193        since: "0",
194        description: "BEM modifier on `.moss-cards-minimal-year-group`. Applied to year groups that should render in collapsed summary form (e.g. past years on a blog index).",
195    },
196    ComponentEntry {
197        class: "moss-card",
198        kind: "instance",
199        parent: "moss-cards",
200        data_attrs: &[
201            DataAttr {
202                name: "data-linkblog",
203                values: &[],
204                default: "",
205                description: "Presence flag: emitted IFF the card's source page has an `external_url:` frontmatter (linkblog pattern). When set, the element is a `<div>` rather than `<a>` so the kicker can host a nested `<a>★</a>` archive link; title, cover, and description carry their own inner anchors to the canonical URL. Absent on ordinary cards (single whole-card `<a>`).",
206            },
207        ],
208        example_html: r#"<a class="moss-card" href="...">...</a>"#,
209        example_markdown: "",
210        status: Status::Confirmed,
211        since: "1",
212        description: "v1 collapsed shape — single canonical instance class inside `.moss-cards`. Layout-specific styling targets `.moss-cards[data-layout=X] .moss-card`. Tag is `<a>` for ordinary cards and `<div>` for linkblog cards (`[data-linkblog]`).",
213    },
214    ComponentEntry {
215        class: "moss-card-cover",
216        kind: "instance",
217        parent: "moss-card",
218        data_attrs: &[],
219        example_html: r#"<div class="moss-card-cover"><img src="..." /></div>"#,
220        example_markdown: "",
221        status: Status::Confirmed,
222        since: "1",
223        description: "Cover media slot inside `.moss-card`. Gets `.moss-card-no-cover` modifier when no image is present.",
224    },
225    ComponentEntry {
226        class: "moss-card-no-cover",
227        kind: "instance",
228        parent: "moss-card",
229        data_attrs: &[],
230        example_html: r#"<div class="moss-card-cover moss-card-no-cover"></div>"#,
231        example_markdown: "",
232        status: Status::Confirmed,
233        since: "1",
234        description: "Modifier applied to `.moss-card-cover` when no cover media is available.",
235    },
236    ComponentEntry {
237        class: "moss-card-content",
238        kind: "instance",
239        parent: "moss-card",
240        data_attrs: &[],
241        example_html: r#"<div class="moss-card-content">...</div>"#,
242        example_markdown: "",
243        status: Status::Confirmed,
244        since: "1",
245        description: "Text content slot inside a grid-layout `.moss-card` (kicker + title + meta).",
246    },
247    ComponentEntry {
248        class: "moss-card-row",
249        kind: "instance",
250        parent: "moss-card",
251        data_attrs: &[],
252        example_html: r#"<div class="moss-card-row">...</div>"#,
253        example_markdown: "",
254        status: Status::Confirmed,
255        since: "1",
256        description: "Row wrapper inside a list-layout `.moss-card` holding body + cover side-by-side.",
257    },
258    ComponentEntry {
259        class: "moss-card-body",
260        kind: "instance",
261        parent: "moss-card",
262        data_attrs: &[],
263        example_html: r#"<div class="moss-card-body">...</div>"#,
264        example_markdown: "",
265        status: Status::Confirmed,
266        since: "1",
267        description: "Text body slot of a list-layout `.moss-card`.",
268    },
269    ComponentEntry {
270        class: "moss-card-head",
271        kind: "instance",
272        parent: "moss-card",
273        data_attrs: &[],
274        example_html: r#"<div class="moss-card-head">...</div>"#,
275        example_markdown: "",
276        status: Status::Confirmed,
277        since: "1",
278        description: "Header row of a `.moss-card-body` (title + kicker + meta).",
279    },
280    ComponentEntry {
281        class: "moss-card-title",
282        kind: "instance",
283        parent: "moss-card",
284        data_attrs: &[],
285        example_html: r#"<h3 class="moss-card-title">Page title</h3>"#,
286        example_markdown: "",
287        status: Status::Confirmed,
288        since: "1",
289        description: "Title inside `.moss-card`.",
290    },
291    ComponentEntry {
292        class: "moss-card-meta",
293        kind: "instance",
294        parent: "moss-card",
295        data_attrs: &[],
296        example_html: r#"<div class="moss-card-meta">2024-01-15</div>"#,
297        example_markdown: "",
298        status: Status::Confirmed,
299        since: "1",
300        description: "Type-aware metadata slot (date for articles, count for folders, domain for links). Renders ABOVE the title in horizontal mode — filling the kicker position when the explicit `kicker` slot is unset, per `docs/design-system/preview-cards.md:22-30`. To the right of the title in vertical CJK mode (the horizontal kicker position transposed). Meta IS the visual kicker, with the same uppercase overline treatment.",
301    },
302    ComponentEntry {
303        class: "moss-card-kicker",
304        kind: "instance",
305        parent: "moss-card",
306        data_attrs: &[],
307        example_html: r#"<span class="moss-card-kicker">Category</span>"#,
308        example_markdown: "",
309        status: Status::Confirmed,
310        since: "1",
311        description: "Eyebrow / overline above the title inside `.moss-card`.",
312    },
313    ComponentEntry {
314        class: "moss-card-permalink",
315        kind: "instance",
316        parent: "moss-card-kicker",
317        data_attrs: &[],
318        example_html: r#"<a class="moss-card-permalink" href="/posts/foo/" title="Permalink to 'Title'">★</a>"#,
319        example_markdown: "",
320        status: Status::Emerging,
321        since: "1",
322        description: "Author's-archive link mark (★, U+2605) emitted INSIDE `.moss-card-kicker` for linkblog cards (those whose child page has `external_url:`). The card title links to the external canonical (publisher); the `★` links to the local archival copy at the page's slug. Reads as part of the kicker line — \"Publisher · Year ★\". Semantically distinct from Daring-Fireball's linkblog ★ (which marks discussion permalink alongside commentary) — here the local copy is the same content preserved for resilience and stable bylines, not added commentary. Putting `<a>★</a>` inside the kicker is valid because linkblog cards emit `<div class=\"moss-card\" data-linkblog>` (not `<a>`) as the outer element — see the `data-linkblog` attribute described on `.moss-card`.",
323    },
324    ComponentEntry {
325        class: "moss-card-title-link",
326        kind: "instance",
327        parent: "moss-card-head",
328        data_attrs: &[],
329        example_html: r#"<a class="moss-card-title-link" href="https://outlet.example/article"><h3 class="moss-card-title">Article Title</h3></a>"#,
330        example_markdown: "",
331        status: Status::Emerging,
332        since: "1",
333        description: "Anchor wrapping the `.moss-card-title` `<h3>` on linkblog cards. Ordinary cards have the whole-card `<a class=\"moss-card\">` as the link target — but linkblog cards switch the outer to `<div>` so the kicker can host a nested `★` anchor, which means the title needs its own anchor to stay clickable. Same canonical-URL target as the other inner anchors (`moss-card-cover-link`, `moss-card-description-link`).",
334    },
335    ComponentEntry {
336        class: "moss-card-cover-link",
337        kind: "instance",
338        parent: "moss-card-row",
339        data_attrs: &[],
340        example_html: r#"<a class="moss-card-cover-link" href="https://outlet.example/article"><div class="moss-card-cover">...</div></a>"#,
341        example_markdown: "",
342        status: Status::Emerging,
343        since: "1",
344        description: "Anchor wrapping the `.moss-card-cover` on linkblog cards — same role as `.moss-card-title-link` but for the cover image / media. Targets the canonical (external) URL.",
345    },
346    ComponentEntry {
347        class: "moss-card-description-link",
348        kind: "instance",
349        parent: "moss-card-body",
350        data_attrs: &[],
351        example_html: r#"<a class="moss-card-description-link" href="https://outlet.example/article"><p class="moss-card-description">…</p></a>"#,
352        example_markdown: "",
353        status: Status::Emerging,
354        since: "1",
355        description: "Anchor wrapping the `.moss-card-description` on linkblog cards — same role as `.moss-card-title-link` but for the description excerpt. Targets the canonical (external) URL.",
356    },
357    ComponentEntry {
358        class: "moss-card-description",
359        kind: "instance",
360        parent: "moss-card",
361        data_attrs: &[],
362        example_html: r#"<p class="moss-card-description">Excerpt...</p>"#,
363        example_markdown: "",
364        status: Status::Confirmed,
365        since: "1",
366        description: "Excerpt / description paragraph inside a `.moss-card` — below the title in both grid- and list-layout cards.",
367    },
368    ComponentEntry {
369        class: "moss-card-count",
370        kind: "instance",
371        parent: "moss-card",
372        data_attrs: &[],
373        example_html: r#"<div class="moss-card-count">4 articles</div>"#,
374        example_markdown: "",
375        status: Status::Confirmed,
376        since: "1",
377        description: "Tertiary subtitle line showing `N articles` for a folder card. Renders only on non-date listings when the folder card has no `description` to display.",
378    },
379    ComponentEntry {
380        class: "moss-card-grid",
381        kind: "instance",
382        parent: "moss-cards-grid",
383        data_attrs: &[],
384        example_html: r#"<a class="moss-card-grid" href="...">...</a>"#,
385        example_markdown: "",
386        status: Status::Retired,
387        since: "0",
388        description: "Retired in Phase 1c — collapsed into `.moss-card` (with parent `.moss-cards[data-layout=grid]`).",
389    },
390    ComponentEntry {
391        class: "moss-card-grid-cover",
392        kind: "instance",
393        parent: "moss-card-grid",
394        data_attrs: &[],
395        example_html: r#"<div class="moss-card-grid-cover"><img src="..." /></div>"#,
396        example_markdown: "",
397        status: Status::Retired,
398        since: "0",
399        description: "Retired in Phase 1c — collapsed into `.moss-card-cover`.",
400    },
401    ComponentEntry {
402        class: "moss-card-grid-no-cover",
403        kind: "instance",
404        parent: "moss-card-grid",
405        data_attrs: &[],
406        example_html: r#"<div class="moss-card-grid-cover moss-card-grid-no-cover"></div>"#,
407        example_markdown: "",
408        status: Status::Retired,
409        since: "0",
410        description: "Retired in Phase 1c — collapsed into `.moss-card-no-cover`.",
411    },
412    ComponentEntry {
413        class: "moss-card-grid-content",
414        kind: "instance",
415        parent: "moss-card-grid",
416        data_attrs: &[],
417        example_html: r#"<div class="moss-card-grid-content">...</div>"#,
418        example_markdown: "",
419        status: Status::Retired,
420        since: "0",
421        description: "Retired in Phase 1c — collapsed into `.moss-card-content`.",
422    },
423    ComponentEntry {
424        class: "moss-card-grid-kicker",
425        kind: "instance",
426        parent: "moss-card-grid",
427        data_attrs: &[],
428        example_html: r#"<span class="moss-card-grid-kicker">Category</span>"#,
429        example_markdown: "",
430        status: Status::Retired,
431        since: "0",
432        description: "Retired in Phase 1c — collapsed into `.moss-card-kicker`.",
433    },
434    ComponentEntry {
435        class: "moss-card-grid-title",
436        kind: "instance",
437        parent: "moss-card-grid",
438        data_attrs: &[],
439        example_html: r#"<h3 class="moss-card-grid-title">Page title</h3>"#,
440        example_markdown: "",
441        status: Status::Retired,
442        since: "0",
443        description: "Retired in Phase 1c — collapsed into `.moss-card-title`.",
444    },
445    ComponentEntry {
446        class: "moss-card-grid-meta",
447        kind: "instance",
448        parent: "moss-card-grid",
449        data_attrs: &[],
450        example_html: r#"<div class="moss-card-grid-meta">2024-01-15</div>"#,
451        example_markdown: "",
452        status: Status::Retired,
453        since: "0",
454        description: "Retired in Phase 1c — collapsed into `.moss-card-meta`.",
455    },
456    ComponentEntry {
457        class: "moss-card-list",
458        kind: "instance",
459        parent: "moss-cards-list",
460        data_attrs: &[],
461        example_html: r#"<a class="moss-card-list" href="...">...</a>"#,
462        example_markdown: "",
463        status: Status::Retired,
464        since: "0",
465        description: "Retired in Phase 1c — collapsed into `.moss-card` (with parent `.moss-cards[data-layout=list]`).",
466    },
467    ComponentEntry {
468        class: "moss-card-list-row",
469        kind: "instance",
470        parent: "moss-card-list",
471        data_attrs: &[],
472        example_html: r#"<div class="moss-card-list-row">...</div>"#,
473        example_markdown: "",
474        status: Status::Retired,
475        since: "0",
476        description: "Retired in Phase 1c — collapsed into `.moss-card-row`.",
477    },
478    ComponentEntry {
479        class: "moss-card-list-cover",
480        kind: "instance",
481        parent: "moss-card-list",
482        data_attrs: &[],
483        example_html: r#"<div class="moss-card-list-cover"><img src="..." /></div>"#,
484        example_markdown: "",
485        status: Status::Retired,
486        since: "0",
487        description: "Retired in Phase 1c — collapsed into `.moss-card-cover`.",
488    },
489    ComponentEntry {
490        class: "moss-card-list-body",
491        kind: "instance",
492        parent: "moss-card-list",
493        data_attrs: &[],
494        example_html: r#"<div class="moss-card-list-body">...</div>"#,
495        example_markdown: "",
496        status: Status::Retired,
497        since: "0",
498        description: "Retired in Phase 1c — collapsed into `.moss-card-body`.",
499    },
500    ComponentEntry {
501        class: "moss-card-list-head",
502        kind: "instance",
503        parent: "moss-card-list",
504        data_attrs: &[],
505        example_html: r#"<div class="moss-card-list-head">...</div>"#,
506        example_markdown: "",
507        status: Status::Retired,
508        since: "0",
509        description: "Retired in Phase 1c — collapsed into `.moss-card-head`.",
510    },
511    ComponentEntry {
512        class: "moss-card-list-kicker",
513        kind: "instance",
514        parent: "moss-card-list",
515        data_attrs: &[],
516        example_html: r#"<span class="moss-card-list-kicker">Category</span>"#,
517        example_markdown: "",
518        status: Status::Retired,
519        since: "0",
520        description: "Retired in Phase 1c — collapsed into `.moss-card-kicker`.",
521    },
522    ComponentEntry {
523        class: "moss-card-list-title",
524        kind: "instance",
525        parent: "moss-card-list",
526        data_attrs: &[],
527        example_html: r#"<h3 class="moss-card-list-title">Page title</h3>"#,
528        example_markdown: "",
529        status: Status::Retired,
530        since: "0",
531        description: "Retired in Phase 1c — collapsed into `.moss-card-title`.",
532    },
533    ComponentEntry {
534        class: "moss-card-list-meta",
535        kind: "instance",
536        parent: "moss-card-list",
537        data_attrs: &[],
538        example_html: r#"<div class="moss-card-list-meta">2024-01-15</div>"#,
539        example_markdown: "",
540        status: Status::Retired,
541        since: "0",
542        description: "Retired in Phase 1c — collapsed into `.moss-card-meta`.",
543    },
544    ComponentEntry {
545        class: "moss-card-list-description",
546        kind: "instance",
547        parent: "moss-card-list",
548        data_attrs: &[],
549        example_html: r#"<p class="moss-card-list-description">Excerpt...</p>"#,
550        example_markdown: "",
551        status: Status::Retired,
552        since: "0",
553        description: "Retired in Phase 1c — collapsed into `.moss-card-description`.",
554    },
555    ComponentEntry {
556        class: "moss-card-minimal",
557        kind: "instance",
558        parent: "moss-cards-minimal-year-group",
559        data_attrs: &[],
560        example_html: r#"<div class="moss-card-minimal">
561  <a class="moss-prefix-link" href="...">...</a>
562</div>"#,
563        example_markdown: "",
564        status: Status::Retired,
565        since: "0",
566        description: "Retired in Phase 1c — collapsed into `.moss-card` (with parent `.moss-cards[data-layout=minimal]`).",
567    },
568    ComponentEntry {
569        class: "moss-folder-item",
570        kind: "instance",
571        parent: "moss-cards-minimal-year-group",
572        data_attrs: &[],
573        example_html: r#"<div class="moss-card-minimal moss-folder-item">
574  <a class="moss-prefix-link moss-folder-link" href="...">...</a>
575  <p class="moss-folder-description">...</p>
576</div>"#,
577        example_markdown: "",
578        status: Status::Confirmed,
579        since: "0",
580        description: "Modifier on `.moss-card-minimal` for folder-type entries in minimal listings.",
581    },
582    ComponentEntry {
583        class: "moss-folder-title",
584        kind: "instance",
585        parent: "moss-folder-item",
586        data_attrs: &[],
587        example_html: r#"<span class="moss-folder-title">Folder name</span>"#,
588        example_markdown: "",
589        status: Status::Confirmed,
590        since: "0",
591        description: "Title text of a folder entry in minimal listings.",
592    },
593    ComponentEntry {
594        class: "moss-folder-description",
595        kind: "instance",
596        parent: "moss-folder-item",
597        data_attrs: &[],
598        example_html: r#"<p class="moss-folder-description">Description...</p>"#,
599        example_markdown: "",
600        status: Status::Confirmed,
601        since: "0",
602        description: "Description paragraph of a folder entry in minimal listings.",
603    },
604    ComponentEntry {
605        class: "moss-folder-link",
606        kind: "instance",
607        parent: "moss-folder-item",
608        data_attrs: &[],
609        example_html: r#"<a class="moss-prefix-link moss-folder-link" href="...">...</a>"#,
610        example_markdown: "",
611        status: Status::Confirmed,
612        since: "0",
613        description: "Modifier on `.moss-prefix-link` for folder-type links in minimal listings.",
614    },
615    // -------------------------------------------------------------------
616    // Prefix-link primitive — used by minimal cards and other listings.
617    // -------------------------------------------------------------------
618    ComponentEntry {
619        class: "moss-prefix-link",
620        kind: "instance",
621        parent: "moss-card-minimal",
622        data_attrs: &[],
623        example_html: r#"<a class="moss-prefix-link" href="...">
624  <span class="moss-prefix-link-prefix">2024-01-15</span>
625  <span class="moss-prefix-link-title">Page title</span>
626</a>"#,
627        example_markdown: "",
628        status: Status::Emerging,
629        since: "0",
630        description: "Link with a prefix span (date or icon) and a title span. Used inside minimal cards.",
631    },
632    ComponentEntry {
633        class: "moss-prefix-link-prefix",
634        kind: "instance",
635        parent: "moss-prefix-link",
636        data_attrs: &[],
637        example_html: r#"<span class="moss-prefix-link-prefix">2024-01-15</span>"#,
638        example_markdown: "",
639        status: Status::Emerging,
640        since: "0",
641        description: "Prefix slot of a prefix-link (typically a date).",
642    },
643    ComponentEntry {
644        class: "moss-prefix-link-title",
645        kind: "instance",
646        parent: "moss-prefix-link",
647        data_attrs: &[],
648        example_html: r#"<span class="moss-prefix-link-title">Page title</span>"#,
649        example_markdown: "",
650        status: Status::Emerging,
651        since: "0",
652        description: "Title slot of a prefix-link.",
653    },
654    ComponentEntry {
655        class: "moss-prefix-link-suffix",
656        kind: "instance",
657        parent: "moss-prefix-link",
658        data_attrs: &[],
659        example_html: r#"<span class="moss-prefix-link-suffix">→</span>"#,
660        example_markdown: "",
661        status: Status::Emerging,
662        since: "0",
663        description: "Optional trailing slot of a prefix-link.",
664    },
665    // -------------------------------------------------------------------
666    // Callouts — Obsidian-style admonitions. Type variant goes on the
667    // container as `.callout-<type>`. Phase 1c may collapse into
668    // `.moss-callout[data-type]`.
669    // -------------------------------------------------------------------
670    ComponentEntry {
671        class: "moss-callout",
672        kind: "standalone",
673        parent: "",
674        data_attrs: &[],
675        example_html: r#"<div class="moss-callout callout" data-type="note">
676  <div class="callout-title">Note</div>
677  <div class="callout-content">Body...</div>
678</div>"#,
679        example_markdown: "> [!note]\n> Body...",
680        status: Status::Confirmed,
681        since: "0",
682        description: "Obsidian-style callout. The Obsidian-compat `.callout` class is co-emitted; type lives on `data-type` (v1).",
683    },
684    ComponentEntry {
685        class: "callout",
686        kind: "standalone",
687        parent: "",
688        data_attrs: &[
689            DataAttr {
690                name: "data-type",
691                values: &["note", "info", "tip", "warning", "pending"],
692                default: "note",
693                description: "v1 callout type. Theme authors target `.callout[data-type=...]` to style by variant.",
694            },
695        ],
696        example_html: r#"<div class="moss-callout callout" data-type="note">...</div>"#,
697        example_markdown: "",
698        status: Status::Confirmed,
699        since: "0",
700        description: "Obsidian-compat class co-emitted on every callout for theme parity. Type lives on `data-type` (v1).",
701    },
702    ComponentEntry {
703        class: "callout-title",
704        kind: "instance",
705        parent: "moss-callout",
706        data_attrs: &[],
707        example_html: r#"<div class="callout-title">Note</div>"#,
708        example_markdown: "",
709        status: Status::Confirmed,
710        since: "0",
711        description: "Title row of a callout.",
712    },
713    ComponentEntry {
714        class: "callout-content",
715        kind: "instance",
716        parent: "moss-callout",
717        data_attrs: &[],
718        example_html: r#"<div class="callout-content">Body...</div>"#,
719        example_markdown: "",
720        status: Status::Confirmed,
721        since: "0",
722        description: "Body container of a callout.",
723    },
724    ComponentEntry {
725        class: "callout-note",
726        kind: "instance",
727        parent: "moss-callout",
728        data_attrs: &[],
729        example_html: r#"<div class="moss-callout callout callout-note">...</div>"#,
730        example_markdown: "> [!note]\n> Body",
731        status: Status::Retired,
732        since: "0",
733        description: "Retired in Phase 1c — type lives on `.callout[data-type=note]`.",
734    },
735    ComponentEntry {
736        class: "callout-info",
737        kind: "instance",
738        parent: "moss-callout",
739        data_attrs: &[],
740        example_html: r#"<div class="moss-callout callout callout-info">...</div>"#,
741        example_markdown: "> [!info]\n> Body",
742        status: Status::Retired,
743        since: "0",
744        description: "Retired in Phase 1c — type lives on `.callout[data-type=info]`.",
745    },
746    ComponentEntry {
747        class: "callout-tip",
748        kind: "instance",
749        parent: "moss-callout",
750        data_attrs: &[],
751        example_html: r#"<div class="moss-callout callout callout-tip">...</div>"#,
752        example_markdown: "> [!tip]\n> Body",
753        status: Status::Retired,
754        since: "0",
755        description: "Retired in Phase 1c — type lives on `.callout[data-type=tip]`.",
756    },
757    ComponentEntry {
758        class: "callout-warning",
759        kind: "instance",
760        parent: "moss-callout",
761        data_attrs: &[],
762        example_html: r#"<div class="moss-callout callout callout-warning">...</div>"#,
763        example_markdown: "> [!warning]\n> Body",
764        status: Status::Retired,
765        since: "0",
766        description: "Retired in Phase 1c — type lives on `.callout[data-type=warning]`.",
767    },
768    ComponentEntry {
769        class: "callout-pending",
770        kind: "instance",
771        parent: "moss-callout",
772        data_attrs: &[],
773        example_html: r#"<div class="moss-callout callout callout-pending">...</div>"#,
774        example_markdown: "> [!pending]\n> Body",
775        status: Status::Retired,
776        since: "0",
777        description: "Retired in Phase 1c — type lives on `.callout[data-type=pending]`.",
778    },
779    // -------------------------------------------------------------------
780    // Embeds — `![[file.ext]]` shortcode renderers (audio, video, pdf,
781    // notebook, table, 3d, iframe).
782    // -------------------------------------------------------------------
783    ComponentEntry {
784        class: "moss-embed",
785        kind: "standalone",
786        parent: "",
787        data_attrs: &[
788            DataAttr {
789                name: "data-type",
790                values: &["audio", "video", "pdf", "notebook", "table", "iframe", "3d"],
791                default: "",
792                description: "v1 embed kind. Set on the embed element. Theme authors target `.moss-embed[data-type=...]`.",
793            },
794            DataAttr {
795                name: "data-width",
796                values: &["body", "wide", "page", "screen"],
797                default: "body",
798                description: "Display width — text-column (body), wider than text (wide), page-width (page), or viewport-width (screen). See spec § P9.",
799            },
800        ],
801        example_html: r#"<div class="moss-embed moss-embed-pdf"><iframe src="..."></iframe></div>"#,
802        example_markdown: "![[paper.pdf]]",
803        status: Status::Confirmed,
804        since: "0",
805        description: "Base class on every typed embed. Kind on `data-type` (v1). `.moss-embed-audio` / `-video` / `-pdf` / `-notebook` / `-table` / `-iframe` / `-3d` retired in Phase 1c.",
806    },
807    ComponentEntry {
808        class: "moss-embed-audio",
809        kind: "instance",
810        parent: "moss-embed",
811        data_attrs: &[],
812        example_html: r#"<div class="moss-embed moss-embed-audio"><audio controls src="..."></audio></div>"#,
813        example_markdown: "![[track.mp3]]",
814        status: Status::Retired,
815        since: "0",
816        description: "Retired in Phase 1c — collapsed to `.moss-embed[data-type=audio]`.",
817    },
818    ComponentEntry {
819        class: "moss-embed-video",
820        kind: "instance",
821        parent: "moss-embed",
822        data_attrs: &[],
823        example_html: r#"<div class="moss-embed moss-embed-video"><video controls src="..."></video></div>"#,
824        example_markdown: "![[clip.mp4]]",
825        status: Status::Retired,
826        since: "0",
827        description: "Retired in Phase 1c — collapsed to `.moss-embed[data-type=video]`.",
828    },
829    ComponentEntry {
830        class: "moss-embed-pdf",
831        kind: "instance",
832        parent: "moss-embed",
833        data_attrs: &[],
834        example_html: r#"<div class="moss-embed moss-embed-pdf"><iframe src="..."></iframe></div>"#,
835        example_markdown: "![[paper.pdf]]",
836        status: Status::Retired,
837        since: "0",
838        description: "Retired in Phase 1c — collapsed to `.moss-embed[data-type=pdf]`.",
839    },
840    ComponentEntry {
841        class: "moss-embed-iframe",
842        kind: "instance",
843        parent: "moss-embed",
844        data_attrs: &[],
845        example_html: r#"<div class="moss-embed moss-embed-iframe"><iframe src="..."></iframe></div>"#,
846        example_markdown: "![[page.html]]",
847        status: Status::Retired,
848        since: "0",
849        description: "Retired in Phase 1c — collapsed to `.moss-embed[data-type=iframe]`.",
850    },
851    ComponentEntry {
852        class: "moss-embed-notebook",
853        kind: "instance",
854        parent: "moss-embed",
855        data_attrs: &[],
856        example_html: r#"<div class="moss-embed moss-embed-notebook">...</div>"#,
857        example_markdown: "![[analysis.ipynb]]",
858        status: Status::Retired,
859        since: "0",
860        description: "Retired in Phase 1c — collapsed to `.moss-embed[data-type=notebook]`.",
861    },
862    ComponentEntry {
863        class: "moss-embed-ipynb",
864        kind: "instance",
865        parent: "moss-embed",
866        data_attrs: &[],
867        example_html: r#"<div class="moss-embed moss-embed-ipynb">...</div>"#,
868        example_markdown: "",
869        status: Status::Emerging,
870        since: "0",
871        description: "Alias of `.moss-embed-notebook`; consolidation pending.",
872    },
873    ComponentEntry {
874        class: "moss-embed-table",
875        kind: "instance",
876        parent: "moss-embed",
877        data_attrs: &[],
878        example_html: r#"<div class="moss-embed moss-embed-table"><table>...</table></div>"#,
879        example_markdown: "![[data.csv]]",
880        status: Status::Retired,
881        since: "0",
882        description: "Retired in Phase 1c — collapsed to `.moss-embed[data-type=table]`.",
883    },
884    ComponentEntry {
885        class: "moss-embed-3d",
886        kind: "instance",
887        parent: "moss-embed",
888        data_attrs: &[],
889        example_html: r#"<div class="moss-embed moss-embed-3d">...</div>"#,
890        example_markdown: "![[model.glb]]",
891        status: Status::Retired,
892        since: "0",
893        description: "Retired in Phase 1c — collapsed to `.moss-embed[data-type=3d]`.",
894    },
895    ComponentEntry {
896        class: "moss-embed-error",
897        kind: "instance",
898        parent: "moss-embed",
899        data_attrs: &[],
900        example_html: r#"<div class="moss-embed moss-embed-error">File not found: ...</div>"#,
901        example_markdown: "",
902        status: Status::Confirmed,
903        since: "0",
904        description: "Error state for embeds whose target cannot be resolved.",
905    },
906    ComponentEntry {
907        class: "moss-embed-missing",
908        kind: "instance",
909        parent: "moss-embed",
910        data_attrs: &[],
911        example_html: r#"<div class="moss-embed-missing">Folder not found: journal</div>"#,
912        example_markdown: "",
913        status: Status::Confirmed,
914        since: "1",
915        description: "Fallback rendered when a folder-list embed (`![[journal/]]`) targets a folder that does not exist or cannot be resolved. Distinct from `.moss-embed-error` (file/wikilink resolution failure) — this one is specifically the folder-listing path.",
916    },
917    // -------------------------------------------------------------------
918    // Hero, image, visual primitives.
919    // -------------------------------------------------------------------
920    ComponentEntry {
921        class: "moss-hero",
922        kind: "standalone",
923        parent: "",
924        data_attrs: &[
925            DataAttr {
926                name: "data-width",
927                values: &["body", "wide", "page", "screen"],
928                default: "body",
929                description: "Display width — text-column (body), wider than text (wide), page-width (page), or viewport-width (screen). See spec § P9. Phase 1c will emit this from authoring shortcode (e.g. `:::hero {full}` -> `data-width=\"screen\"`).",
930            },
931        ],
932        example_html: r#"<section class="moss-hero" data-width="page">
933  <div class="moss-hero-content">...</div>
934</section>"#,
935        example_markdown: "",
936        status: Status::Confirmed,
937        since: "0",
938        description: "Hero banner section at the top of a page (cover image + title). v1 adds `data-width` for author-controlled sizing.",
939    },
940    ComponentEntry {
941        class: "moss-hero-content",
942        kind: "instance",
943        parent: "moss-hero",
944        data_attrs: &[],
945        example_html: r#"<div class="moss-hero-content">...</div>"#,
946        example_markdown: "",
947        status: Status::Confirmed,
948        since: "0",
949        description: "Text content slot inside `.moss-hero`.",
950    },
951    ComponentEntry {
952        class: "moss-image",
953        kind: "standalone",
954        parent: "",
955        data_attrs: &[
956            DataAttr {
957                name: "data-aspect",
958                values: &["portrait", "square", "auto"],
959                default: "auto",
960                description: "v1 image aspect-ratio hint. Theme authors target `.moss-image[data-aspect=...]`. Emitter wiring lands in a follow-up.",
961            },
962            DataAttr {
963                name: "data-width",
964                values: &["body", "wide", "page", "screen"],
965                default: "body",
966                description: "Display width — text-column (body), wider than text (wide), page-width (page), or viewport-width (screen). See spec § P9.",
967            },
968        ],
969        example_html: r#"<figure class="moss-image" data-aspect="portrait" data-width="body"><img src="..." alt="..." /></figure>"#,
970        example_markdown: "![alt](image.jpg)",
971        status: Status::Confirmed,
972        since: "0",
973        description: "Wrapper around an inline `<img>` for sizing and figure semantics. v1 adds `data-aspect` (collapses `--portrait`/`--square`/`--auto` modifiers) and `data-width` (P9).",
974    },
975    ComponentEntry {
976        class: "moss-align-left",
977        kind: "standalone",
978        parent: "",
979        data_attrs: &[],
980        example_html: r#"<img src="..." alt="..." class="moss-align-left" />"#,
981        example_markdown: "![[photo.jpg|align-left]]",
982        status: Status::Confirmed,
983        since: "0",
984        description: "Floats an image to the left of body text (editorial runaround). Defaults max-width to 50% on desktop, collapses to full-width below 48rem. CSS `:has()` escalates the float to a wrapping `<figure class=\"moss-image\">` or `<picture>` when present. Mirrors WordPress's `alignleft` convention.",
985    },
986    ComponentEntry {
987        class: "moss-align-right",
988        kind: "standalone",
989        parent: "",
990        data_attrs: &[],
991        example_html: r#"<img src="..." alt="..." class="moss-align-right" />"#,
992        example_markdown: "![[photo.jpg|align-right]]",
993        status: Status::Confirmed,
994        since: "0",
995        description: "Floats an image to the right of body text (editorial runaround). Symmetric counterpart to `.moss-align-left`. Mirrors WordPress's `alignright` convention.",
996    },
997    ComponentEntry {
998        class: "moss-visual",
999        kind: "standalone",
1000        parent: "",
1001        data_attrs: &[],
1002        example_html: r#"<div class="moss-visual">...</div>"#,
1003        example_markdown: "",
1004        status: Status::Emerging,
1005        since: "0",
1006        description: "Generic visual block (figure-like surface).",
1007    },
1008    ComponentEntry {
1009        class: "moss-article-title",
1010        kind: "instance",
1011        parent: "",
1012        data_attrs: &[],
1013        example_html: r#"<h1 class="moss-article-title">Title</h1>"#,
1014        example_markdown: "",
1015        status: Status::Emerging,
1016        since: "0",
1017        description: "Article-page H1 title emitted from frontmatter.",
1018    },
1019    ComponentEntry {
1020        class: "moss-heading-anchor",
1021        kind: "instance",
1022        parent: "",
1023        data_attrs: &[],
1024        example_html: r##"<h2 id="setup">Setup<a class="moss-heading-anchor" href="#setup" aria-label="Permalink to this section"><span aria-hidden="true">#</span></a></h2>"##,
1025        example_markdown: "## Setup",
1026        status: Status::Emerging,
1027        since: "1",
1028        description: "Clickable permalink appended inside every author-written body heading that carries a slug id; links to the heading's `#`-fragment. The auto-injected `moss-article-title` H1 is emitted separately and gets no anchor.",
1029    },
1030    // -------------------------------------------------------------------
1031    // Grid + gallery + buttons containers (free-form layouts).
1032    // -------------------------------------------------------------------
1033    ComponentEntry {
1034        class: "moss-grid",
1035        kind: "container",
1036        parent: "",
1037        data_attrs: &[
1038            DataAttr {
1039                name: "data-width",
1040                values: &["body", "wide", "page", "screen"],
1041                default: "body",
1042                description: "Display width — text-column (body), wider than text (wide), page-width (page), or viewport-width (screen). See spec § P9.",
1043            },
1044        ],
1045        example_html: r#"<div class="moss-grid" data-width="wide">
1046  <div class="moss-grid-card">...</div>
1047</div>"#,
1048        example_markdown: "",
1049        status: Status::Confirmed,
1050        since: "0",
1051        description: "Generic grid container (used by profiles, link previews, etc.). Modifier classes: `profiles`, `featured`, `no-cards`. v1 adds `data-width` (P9).",
1052    },
1053    ComponentEntry {
1054        class: "moss-grid-card",
1055        kind: "instance",
1056        parent: "moss-grid",
1057        data_attrs: &[
1058            DataAttr {
1059                name: "data-kind",
1060                values: &["link", "friend", "card"],
1061                default: "card",
1062                description: "v1 grid-card variant. Today expressed via co-emitted classes (`.link-card`, `.friend-card`, `.no-cards`); Phase 1c collapses to this `data-kind` attribute.",
1063            },
1064        ],
1065        example_html: r#"<a class="moss-grid-card" data-kind="link" href="...">...</a>"#,
1066        example_markdown: "",
1067        status: Status::Confirmed,
1068        since: "0",
1069        description: "Card instance inside `.moss-grid`. Today emits sibling classes `link-card` / `friend-card` / `no-cards`; v1 collapses to `data-kind`.",
1070    },
1071    ComponentEntry {
1072        class: "moss-gridxyz",
1073        kind: "container",
1074        parent: "",
1075        data_attrs: &[],
1076        example_html: r#"<div class="moss-gridxyz">...</div>"#,
1077        example_markdown: "",
1078        status: Status::Emerging,
1079        since: "0",
1080        description: "Experimental free-form grid variant. Subject to renaming.",
1081    },
1082    ComponentEntry {
1083        class: "moss-gallery",
1084        kind: "container",
1085        parent: "",
1086        data_attrs: &[
1087            DataAttr {
1088                name: "data-width",
1089                values: &["body", "wide", "page", "screen"],
1090                default: "body",
1091                description: "Display width — text-column (body), wider than text (wide), page-width (page), or viewport-width (screen). See spec § P9.",
1092            },
1093        ],
1094        example_html: r#"<div class="moss-gallery" data-width="page">
1095  <figure class="moss-gallery-item">...</figure>
1096</div>"#,
1097        example_markdown: "",
1098        status: Status::Confirmed,
1099        since: "0",
1100        description: "Image gallery container. v1 adds `data-width` (P9).",
1101    },
1102    ComponentEntry {
1103        class: "moss-gallery-item",
1104        kind: "instance",
1105        parent: "moss-gallery",
1106        data_attrs: &[],
1107        example_html: r#"<figure class="moss-gallery-item"><img src="..." /></figure>"#,
1108        example_markdown: "",
1109        status: Status::Confirmed,
1110        since: "0",
1111        description: "Single image entry inside `.moss-gallery`.",
1112    },
1113    ComponentEntry {
1114        class: "moss-buttons",
1115        kind: "container",
1116        parent: "",
1117        data_attrs: &[
1118            DataAttr {
1119                name: "data-style",
1120                values: &["default", "inverted"],
1121                default: "default",
1122                description: "v1 button-row style. Theme authors target `.moss-buttons[data-style=...]`.",
1123            },
1124        ],
1125        example_html: r#"<div class="moss-buttons" data-style="inverted">
1126  <a class="moss-btn" href="...">Click</a>
1127</div>"#,
1128        example_markdown: "",
1129        status: Status::Confirmed,
1130        since: "0",
1131        description: "Container for a row of `.moss-btn` buttons. v1: the inverted variant is on `data-style=\"inverted\"`.",
1132    },
1133    // -------------------------------------------------------------------
1134    // Button primitive (used by subscribe + general CTAs).
1135    // -------------------------------------------------------------------
1136    ComponentEntry {
1137        class: "moss-btn",
1138        kind: "standalone",
1139        parent: "",
1140        data_attrs: &[
1141            DataAttr {
1142                name: "data-role",
1143                values: &["default", "primary", "secondary"],
1144                default: "default",
1145                description: "v1 button role. Theme authors target `.moss-btn[data-role=...]`.",
1146            },
1147        ],
1148        example_html: r#"<button class="moss-btn" data-role="primary">
1149  <span class="moss-btn__label">Submit</span>
1150</button>"#,
1151        example_markdown: "",
1152        status: Status::Confirmed,
1153        since: "0",
1154        description: "Generic button primitive. Role on `data-role` (v1).",
1155    },
1156    ComponentEntry {
1157        class: "moss-btn__label",
1158        kind: "instance",
1159        parent: "moss-btn",
1160        data_attrs: &[],
1161        example_html: r#"<span class="moss-btn__label">Submit</span>"#,
1162        example_markdown: "",
1163        status: Status::Confirmed,
1164        since: "0",
1165        description: "Label span inside `.moss-btn`.",
1166    },
1167    ComponentEntry {
1168        class: "moss-btn__check",
1169        kind: "instance",
1170        parent: "moss-btn",
1171        data_attrs: &[],
1172        example_html: r#"<span class="moss-btn__check">✓</span>"#,
1173        example_markdown: "",
1174        status: Status::Confirmed,
1175        since: "0",
1176        description: "Success checkmark slot inside `.moss-btn`.",
1177    },
1178    ComponentEntry {
1179        class: "moss-btn__spinner",
1180        kind: "instance",
1181        parent: "moss-btn",
1182        data_attrs: &[],
1183        example_html: r#"<span class="moss-btn__spinner"></span>"#,
1184        example_markdown: "",
1185        status: Status::Confirmed,
1186        since: "0",
1187        description: "Loading spinner slot inside `.moss-btn`.",
1188    },
1189    // -------------------------------------------------------------------
1190    // Subscribe form (newsletter / Buttondown / seta).
1191    // -------------------------------------------------------------------
1192    ComponentEntry {
1193        class: "moss-subscribe",
1194        kind: "standalone",
1195        parent: "",
1196        data_attrs: &[],
1197        example_html: r#"<div class="moss-subscribe">
1198  <form class="moss-subscribe-form">...</form>
1199</div>"#,
1200        example_markdown: "",
1201        status: Status::Confirmed,
1202        since: "0",
1203        description: "Newsletter subscribe block (auto-injected into footer when email channel configured).",
1204    },
1205    ComponentEntry {
1206        class: "moss-subscribe-form",
1207        kind: "instance",
1208        parent: "moss-subscribe",
1209        data_attrs: &[],
1210        example_html: r#"<form class="moss-subscribe-form">...</form>"#,
1211        example_markdown: "",
1212        status: Status::Emerging,
1213        since: "0",
1214        description: "Form element inside `.moss-subscribe`.",
1215    },
1216    ComponentEntry {
1217        class: "moss-subscribe-btn-slot",
1218        kind: "instance",
1219        parent: "moss-subscribe",
1220        data_attrs: &[],
1221        example_html: r#"<div class="moss-subscribe-btn-slot"><button class="moss-btn">...</button></div>"#,
1222        example_markdown: "",
1223        status: Status::Emerging,
1224        since: "0",
1225        description: "Slot in the subscribe form that holds the submit button.",
1226    },
1227    ComponentEntry {
1228        class: "moss-subscribe-status",
1229        kind: "instance",
1230        parent: "moss-subscribe",
1231        data_attrs: &[],
1232        example_html: r#"<div class="moss-subscribe-status">
1233  <span class="moss-subscribe-status__icon"></span>
1234  Subscribed!
1235</div>"#,
1236        example_markdown: "",
1237        status: Status::Emerging,
1238        since: "0",
1239        description: "Status message shown after submit (success/error).",
1240    },
1241    ComponentEntry {
1242        class: "moss-subscribe-status__icon",
1243        kind: "instance",
1244        parent: "moss-subscribe-status",
1245        data_attrs: &[],
1246        example_html: r#"<span class="moss-subscribe-status__icon"></span>"#,
1247        example_markdown: "",
1248        status: Status::Emerging,
1249        since: "0",
1250        description: "Icon slot inside `.moss-subscribe-status`.",
1251    },
1252    ComponentEntry {
1253        class: "moss-subscribe-landing",
1254        kind: "standalone",
1255        parent: "",
1256        data_attrs: &[],
1257        example_html: r#"<section class="moss-subscribe-landing">...</section>"#,
1258        example_markdown: "",
1259        status: Status::Emerging,
1260        since: "0",
1261        description: "Standalone subscribe landing page surface (larger variant).",
1262    },
1263    // -------------------------------------------------------------------
1264    // Series navigation (prev/next + collection links).
1265    // -------------------------------------------------------------------
1266    ComponentEntry {
1267        class: "moss-series-nav",
1268        kind: "standalone",
1269        parent: "",
1270        data_attrs: &[],
1271        example_html: r#"<nav class="moss-series-nav">
1272  <div class="moss-series-nav-links">...</div>
1273</nav>"#,
1274        example_markdown: "",
1275        status: Status::Confirmed,
1276        since: "0",
1277        description: "Series navigation bar (prev/next/collection) on series pages.",
1278    },
1279    ComponentEntry {
1280        class: "moss-series-nav-links",
1281        kind: "instance",
1282        parent: "moss-series-nav",
1283        data_attrs: &[],
1284        example_html: r#"<div class="moss-series-nav-links">...</div>"#,
1285        example_markdown: "",
1286        status: Status::Confirmed,
1287        since: "0",
1288        description: "Row holding prev/next links in series nav.",
1289    },
1290    ComponentEntry {
1291        class: "moss-series-nav-link",
1292        kind: "instance",
1293        parent: "moss-series-nav",
1294        data_attrs: &[],
1295        example_html: r#"<a class="moss-series-nav-link moss-series-nav-prev" href="...">...</a>"#,
1296        example_markdown: "",
1297        status: Status::Confirmed,
1298        since: "0",
1299        description: "Individual link inside series nav. Modifiers: `moss-series-nav-prev`, `moss-series-nav-next`, `empty` (placeholder).",
1300    },
1301    ComponentEntry {
1302        class: "moss-series-nav-prev",
1303        kind: "instance",
1304        parent: "moss-series-nav",
1305        data_attrs: &[],
1306        example_html: r#"<a class="moss-series-nav-link moss-series-nav-prev" href="...">...</a>"#,
1307        example_markdown: "",
1308        status: Status::Confirmed,
1309        since: "0",
1310        description: "Previous-page modifier on a series nav link.",
1311    },
1312    ComponentEntry {
1313        class: "moss-series-nav-next",
1314        kind: "instance",
1315        parent: "moss-series-nav",
1316        data_attrs: &[],
1317        example_html: r#"<a class="moss-series-nav-link moss-series-nav-next" href="...">...</a>"#,
1318        example_markdown: "",
1319        status: Status::Confirmed,
1320        since: "0",
1321        description: "Next-page modifier on a series nav link.",
1322    },
1323    ComponentEntry {
1324        class: "moss-series-nav-arrow",
1325        kind: "instance",
1326        parent: "moss-series-nav",
1327        data_attrs: &[],
1328        example_html: r#"<span class="moss-series-nav-arrow">→</span>"#,
1329        example_markdown: "",
1330        status: Status::Confirmed,
1331        since: "0",
1332        description: "Arrow glyph inside a series-nav link.",
1333    },
1334    ComponentEntry {
1335        class: "moss-series-nav-title",
1336        kind: "instance",
1337        parent: "moss-series-nav",
1338        data_attrs: &[],
1339        example_html: r#"<span class="moss-series-nav-title">Next page title</span>"#,
1340        example_markdown: "",
1341        status: Status::Confirmed,
1342        since: "0",
1343        description: "Title text of the destination page in a series-nav link.",
1344    },
1345    ComponentEntry {
1346        class: "moss-series-nav-collection",
1347        kind: "instance",
1348        parent: "moss-series-nav",
1349        data_attrs: &[],
1350        example_html: r#"<div class="moss-series-nav-collection">...</div>"#,
1351        example_markdown: "",
1352        status: Status::Confirmed,
1353        since: "0",
1354        description: "Collection-listing slot in series nav (sibling pages).",
1355    },
1356    ComponentEntry {
1357        class: "moss-series-nav-collection-row",
1358        kind: "instance",
1359        parent: "moss-series-nav-collection",
1360        data_attrs: &[],
1361        example_html: r#"<div class="moss-series-nav-collection-row">...</div>"#,
1362        example_markdown: "",
1363        status: Status::Confirmed,
1364        since: "0",
1365        description: "Row inside the collection listing of series nav.",
1366    },
1367    // -------------------------------------------------------------------
1368    // Collection cover (collection landing pages).
1369    // -------------------------------------------------------------------
1370    ComponentEntry {
1371        class: "moss-collection-cover",
1372        kind: "standalone",
1373        parent: "",
1374        data_attrs: &[],
1375        example_html: r#"<section class="moss-collection-cover">
1376  <div class="moss-collection-cover-row">...</div>
1377</section>"#,
1378        example_markdown: "",
1379        status: Status::Emerging,
1380        since: "0",
1381        description: "Header surface on a collection landing page.",
1382    },
1383    ComponentEntry {
1384        class: "moss-collection-cover-row",
1385        kind: "instance",
1386        parent: "moss-collection-cover",
1387        data_attrs: &[],
1388        example_html: r#"<div class="moss-collection-cover-row">...</div>"#,
1389        example_markdown: "",
1390        status: Status::Emerging,
1391        since: "0",
1392        description: "Row inside `.moss-collection-cover`.",
1393    },
1394    ComponentEntry {
1395        class: "moss-collection-cover-body",
1396        kind: "instance",
1397        parent: "moss-collection-cover",
1398        data_attrs: &[],
1399        example_html: r#"<div class="moss-collection-cover-body">...</div>"#,
1400        example_markdown: "",
1401        status: Status::Emerging,
1402        since: "0",
1403        description: "Body content slot inside `.moss-collection-cover`.",
1404    },
1405    // -------------------------------------------------------------------
1406    // Form primitives (input, label, field, link).
1407    // -------------------------------------------------------------------
1408    ComponentEntry {
1409        class: "moss-input",
1410        kind: "standalone",
1411        parent: "",
1412        data_attrs: &[],
1413        example_html: r#"<input class="moss-input" type="email" />"#,
1414        example_markdown: "",
1415        status: Status::Confirmed,
1416        since: "0",
1417        description: "Generic form input primitive.",
1418    },
1419    ComponentEntry {
1420        class: "moss-field",
1421        kind: "container",
1422        parent: "",
1423        data_attrs: &[],
1424        example_html: r#"<div class="moss-field">
1425  <label class="moss-label">Email</label>
1426  <input class="moss-input" />
1427</div>"#,
1428        example_markdown: "",
1429        status: Status::Confirmed,
1430        since: "0",
1431        description: "Form field group (label + input). Modifier `--inline` for horizontal layout.",
1432    },
1433    ComponentEntry {
1434        class: "moss-label",
1435        kind: "instance",
1436        parent: "moss-field",
1437        data_attrs: &[],
1438        example_html: r#"<label class="moss-label">Email</label>"#,
1439        example_markdown: "",
1440        status: Status::Confirmed,
1441        since: "0",
1442        description: "Label primitive for `.moss-field`. Modifier `--small` for compact form.",
1443    },
1444    ComponentEntry {
1445        class: "moss-link",
1446        kind: "standalone",
1447        parent: "",
1448        data_attrs: &[],
1449        example_html: r#"<a class="moss-link" href="...">Click me</a>"#,
1450        example_markdown: "",
1451        status: Status::Confirmed,
1452        since: "0",
1453        description: "Inline-link primitive (resets `<button>` chrome too). Use `--subtle` for muted variant.",
1454    },
1455    ComponentEntry {
1456        class: "moss-field--inline",
1457        kind: "instance",
1458        parent: "moss-field",
1459        data_attrs: &[],
1460        example_html: r#"<div class="moss-field moss-field--inline">
1461  <label class="moss-label">Email</label>
1462  <input class="moss-input" />
1463</div>"#,
1464        example_markdown: "",
1465        status: Status::Confirmed,
1466        since: "0",
1467        description: "BEM modifier on `.moss-field` for horizontal label+input layout (used by settings UI primitives).",
1468    },
1469    ComponentEntry {
1470        class: "moss-label--small",
1471        kind: "instance",
1472        parent: "moss-label",
1473        data_attrs: &[],
1474        example_html: r#"<label class="moss-label moss-label--small">Compact label</label>"#,
1475        example_markdown: "",
1476        status: Status::Confirmed,
1477        since: "0",
1478        description: "BEM modifier on `.moss-label` for compact form (used by services settings rows).",
1479    },
1480    ComponentEntry {
1481        class: "moss-info-grid",
1482        kind: "container",
1483        parent: "",
1484        data_attrs: &[],
1485        example_html: r#"<div class="moss-info-grid">
1486  <div class="moss-field moss-field--inline">...</div>
1487  <div class="moss-field moss-field--inline">...</div>
1488</div>"#,
1489        example_markdown: "",
1490        status: Status::Emerging,
1491        since: "0",
1492        description: "Two-column aligned label+value rows (CSS grid with `display: contents` children). Used by the deployment settings panel; ships in the default theme so authors can reuse the layout.",
1493    },
1494    ComponentEntry {
1495        class: "moss-row",
1496        kind: "container",
1497        parent: "",
1498        data_attrs: &[],
1499        example_html: r#"<div class="moss-row">
1500  <div class="moss-field">...</div>
1501  <div class="moss-field">...</div>
1502</div>"#,
1503        example_markdown: "",
1504        status: Status::Emerging,
1505        since: "0",
1506        description: "Horizontal flex row of equal-flex `.moss-field` children. Form-row layout helper shipped in the default theme.",
1507    },
1508    ComponentEntry {
1509        class: "moss-input-feedback",
1510        kind: "instance",
1511        parent: "moss-field",
1512        data_attrs: &[],
1513        example_html: r#"<span class="moss-input-feedback">Saving…</span>"#,
1514        example_markdown: "",
1515        status: Status::Emerging,
1516        since: "0",
1517        description: "Auto-save status hint slot under `.moss-field`. Three state modifiers: `--success`, `--error`, `--fade-out`.",
1518    },
1519    ComponentEntry {
1520        class: "moss-input-feedback--success",
1521        kind: "instance",
1522        parent: "moss-input-feedback",
1523        data_attrs: &[],
1524        example_html: r#"<span class="moss-input-feedback moss-input-feedback--success">Saved</span>"#,
1525        example_markdown: "",
1526        status: Status::Emerging,
1527        since: "0",
1528        description: "Success state modifier on `.moss-input-feedback`.",
1529    },
1530    ComponentEntry {
1531        class: "moss-input-feedback--error",
1532        kind: "instance",
1533        parent: "moss-input-feedback",
1534        data_attrs: &[],
1535        example_html: r#"<span class="moss-input-feedback moss-input-feedback--error">Failed to save</span>"#,
1536        example_markdown: "",
1537        status: Status::Emerging,
1538        since: "0",
1539        description: "Error state modifier on `.moss-input-feedback`.",
1540    },
1541    ComponentEntry {
1542        class: "moss-input-feedback--fade-out",
1543        kind: "instance",
1544        parent: "moss-input-feedback",
1545        data_attrs: &[],
1546        example_html: r#"<span class="moss-input-feedback moss-input-feedback--success moss-input-feedback--fade-out">Saved</span>"#,
1547        example_markdown: "",
1548        status: Status::Emerging,
1549        since: "0",
1550        description: "Transient fade-out modifier on `.moss-input-feedback` (applied after a success message to dismiss it).",
1551    },
1552    // -------------------------------------------------------------------
1553    // Other emit surfaces (comments, colophon, shell frame, misc).
1554    // -------------------------------------------------------------------
1555    ComponentEntry {
1556        class: "moss-comments",
1557        kind: "standalone",
1558        parent: "",
1559        data_attrs: &[],
1560        example_html: r#"<section class="moss-comments">...</section>"#,
1561        example_markdown: "",
1562        status: Status::Confirmed,
1563        since: "0",
1564        description: "Comments surface (per-site SQLite backend or Artalk legacy).",
1565    },
1566    ComponentEntry {
1567        class: "moss-service-inactive",
1568        kind: "instance",
1569        parent: "",
1570        data_attrs: &[],
1571        example_html: r#"<section class="moss-comments moss-service-inactive">...</section>"#,
1572        example_markdown: "",
1573        status: Status::Confirmed,
1574        since: "0",
1575        description: "Co-class applied to `.moss-comments` and `.moss-subscribe-form` when the backing service is not configured. Hidden by default in published sites and revealed inside the preview chrome so authors can see the inactive surface during editing.",
1576    },
1577    // -------------------------------------------------------------------
1578    // Preview link popover — emitted by `assets/js/preview.js` runtime.
1579    // -------------------------------------------------------------------
1580    ComponentEntry {
1581        class: "moss-preview-popup",
1582        kind: "chrome",
1583        parent: "",
1584        data_attrs: &[],
1585        example_html: r#"<div class="moss-preview-popup" role="tooltip" aria-live="polite">
1586  <strong class="moss-preview-title">...</strong>
1587  <p class="moss-preview-desc">...</p>
1588  <p class="moss-preview-text">...</p>
1589</div>"#,
1590        example_markdown: "",
1591        status: Status::Confirmed,
1592        since: "0",
1593        description: "Floating link-preview popover injected at `document.body` level by the runtime `preview.js`. Fetches `/_moss/previews.json` and renders a hover card with title, description, and excerpt for internal links.",
1594    },
1595    ComponentEntry {
1596        class: "moss-preview-title",
1597        kind: "instance",
1598        parent: "moss-preview-popup",
1599        data_attrs: &[],
1600        example_html: r#"<strong class="moss-preview-title">Article title</strong>"#,
1601        example_markdown: "",
1602        status: Status::Confirmed,
1603        since: "0",
1604        description: "Title slot inside `.moss-preview-popup`.",
1605    },
1606    ComponentEntry {
1607        class: "moss-preview-desc",
1608        kind: "instance",
1609        parent: "moss-preview-popup",
1610        data_attrs: &[],
1611        example_html: r#"<p class="moss-preview-desc">Short description</p>"#,
1612        example_markdown: "",
1613        status: Status::Confirmed,
1614        since: "0",
1615        description: "Description slot inside `.moss-preview-popup` (from frontmatter `description`).",
1616    },
1617    ComponentEntry {
1618        class: "moss-preview-text",
1619        kind: "instance",
1620        parent: "moss-preview-popup",
1621        data_attrs: &[],
1622        example_html: r#"<p class="moss-preview-text">Excerpt of the linked article…</p>"#,
1623        example_markdown: "",
1624        status: Status::Confirmed,
1625        since: "0",
1626        description: "Excerpt slot inside `.moss-preview-popup` (auto-extracted from the linked article body).",
1627    },
1628    ComponentEntry {
1629        class: "moss-colophon",
1630        kind: "chrome",
1631        parent: "",
1632        data_attrs: &[],
1633        example_html: r#"<footer class="moss-colophon">
1634  <span class="moss-colophon-icon"></span>
1635  Built with moss
1636</footer>"#,
1637        example_markdown: "",
1638        status: Status::Confirmed,
1639        since: "0",
1640        description: "Footer colophon credit appended by moss.",
1641    },
1642    ComponentEntry {
1643        class: "moss-colophon-icon",
1644        kind: "instance",
1645        parent: "moss-colophon",
1646        data_attrs: &[],
1647        example_html: r#"<span class="moss-colophon-icon"></span>"#,
1648        example_markdown: "",
1649        status: Status::Confirmed,
1650        since: "0",
1651        description: "Icon slot inside `.moss-colophon`.",
1652    },
1653    ComponentEntry {
1654        class: "moss-shell-frame",
1655        kind: "chrome",
1656        parent: "",
1657        data_attrs: &[],
1658        example_html: r#"<div class="moss-shell-frame">...</div>"#,
1659        example_markdown: "",
1660        status: Status::Emerging,
1661        since: "0",
1662        description: "App-shell frame surface (preview chrome).",
1663    },
1664    ComponentEntry {
1665        class: "main-nav",
1666        kind: "chrome",
1667        parent: "",
1668        data_attrs: &[],
1669        example_html: r#"<nav class="main-nav container">...</nav>"#,
1670        example_markdown: "",
1671        status: Status::Confirmed,
1672        since: "0",
1673        description: "Top site navigation bar. Legacy non-`moss-` prefix kept for theme parity.",
1674    },
1675    ComponentEntry {
1676        class: "moss-child-section-divider",
1677        kind: "instance",
1678        parent: "",
1679        data_attrs: &[],
1680        example_html: r#"<hr class="moss-child-section-divider" />"#,
1681        example_markdown: "",
1682        status: Status::Emerging,
1683        since: "0",
1684        description: "Divider rule between auto-generated child sections.",
1685    },
1686    ComponentEntry {
1687        class: "moss-unknown-shortcode",
1688        kind: "standalone",
1689        parent: "",
1690        data_attrs: &[],
1691        example_html: r#"<div class="moss-unknown-shortcode">Unknown shortcode: foo</div>"#,
1692        example_markdown: "{{< foo >}}",
1693        status: Status::Confirmed,
1694        since: "0",
1695        description: "Fallback emitted when a shortcode tag is not recognised by any plugin.",
1696    },
1697    // -------------------------------------------------------------------
1698    // Syntax highlight tokens (emitted by syntect inside <code>).
1699    // -------------------------------------------------------------------
1700    ComponentEntry {
1701        class: "moss-hl-keyword",
1702        kind: "instance",
1703        parent: "",
1704        data_attrs: &[],
1705        example_html: r#"<span class="moss-hl-keyword">if</span>"#,
1706        example_markdown: "",
1707        status: Status::Emerging,
1708        since: "0",
1709        description: "Syntax-highlight token: keyword.",
1710    },
1711    ComponentEntry {
1712        class: "moss-hl-string",
1713        kind: "instance",
1714        parent: "",
1715        data_attrs: &[],
1716        example_html: r#"<span class="moss-hl-string">"hi"</span>"#,
1717        example_markdown: "",
1718        status: Status::Emerging,
1719        since: "0",
1720        description: "Syntax-highlight token: string literal.",
1721    },
1722    ComponentEntry {
1723        class: "moss-hl-comment",
1724        kind: "instance",
1725        parent: "",
1726        data_attrs: &[],
1727        example_html: r#"<span class="moss-hl-comment">// note</span>"#,
1728        example_markdown: "",
1729        status: Status::Emerging,
1730        since: "0",
1731        description: "Syntax-highlight token: comment.",
1732    },
1733    ComponentEntry {
1734        class: "moss-hl-function",
1735        kind: "instance",
1736        parent: "",
1737        data_attrs: &[],
1738        example_html: r#"<span class="moss-hl-function">render</span>"#,
1739        example_markdown: "",
1740        status: Status::Emerging,
1741        since: "0",
1742        description: "Syntax-highlight token: function name.",
1743    },
1744    ComponentEntry {
1745        class: "moss-hl-type",
1746        kind: "instance",
1747        parent: "",
1748        data_attrs: &[],
1749        example_html: r#"<span class="moss-hl-type">String</span>"#,
1750        example_markdown: "",
1751        status: Status::Emerging,
1752        since: "0",
1753        description: "Syntax-highlight token: type name.",
1754    },
1755    ComponentEntry {
1756        class: "moss-hl-number",
1757        kind: "instance",
1758        parent: "",
1759        data_attrs: &[],
1760        example_html: r#"<span class="moss-hl-number">42</span>"#,
1761        example_markdown: "",
1762        status: Status::Emerging,
1763        since: "0",
1764        description: "Syntax-highlight token: numeric literal.",
1765    },
1766    ComponentEntry {
1767        class: "moss-hl-operator",
1768        kind: "instance",
1769        parent: "",
1770        data_attrs: &[],
1771        example_html: r#"<span class="moss-hl-operator">+</span>"#,
1772        example_markdown: "",
1773        status: Status::Emerging,
1774        since: "0",
1775        description: "Syntax-highlight token: operator.",
1776    },
1777    ComponentEntry {
1778        class: "moss-hl-builtin",
1779        kind: "instance",
1780        parent: "",
1781        data_attrs: &[],
1782        example_html: r#"<span class="moss-hl-builtin">print</span>"#,
1783        example_markdown: "",
1784        status: Status::Emerging,
1785        since: "0",
1786        description: "Syntax-highlight token: builtin identifier.",
1787    },
1788    ComponentEntry {
1789        class: "moss-hl-tag",
1790        kind: "instance",
1791        parent: "",
1792        data_attrs: &[],
1793        example_html: r#"<span class="moss-hl-tag">div</span>"#,
1794        example_markdown: "",
1795        status: Status::Emerging,
1796        since: "0",
1797        description: "Syntax-highlight token: markup tag name.",
1798    },
1799    ComponentEntry {
1800        class: "moss-hl-attr",
1801        kind: "instance",
1802        parent: "",
1803        data_attrs: &[],
1804        example_html: r#"<span class="moss-hl-attr">class</span>"#,
1805        example_markdown: "",
1806        status: Status::Emerging,
1807        since: "0",
1808        description: "Syntax-highlight token: attribute name.",
1809    },
1810    ComponentEntry {
1811        class: "moss-hl-meta",
1812        kind: "instance",
1813        parent: "",
1814        data_attrs: &[],
1815        example_html: r#"<span class="moss-hl-meta">@derive</span>"#,
1816        example_markdown: "",
1817        status: Status::Emerging,
1818        since: "0",
1819        description: "Syntax-highlight token: meta/annotation.",
1820    },
1821    ComponentEntry {
1822        class: "moss-hl-addition-bg",
1823        kind: "instance",
1824        parent: "",
1825        data_attrs: &[],
1826        example_html: r#"<span class="moss-hl-addition-bg">+ added line</span>"#,
1827        example_markdown: "",
1828        status: Status::Emerging,
1829        since: "0",
1830        description: "Syntax-highlight diff token: added-line background.",
1831    },
1832    ComponentEntry {
1833        class: "moss-hl-deletion",
1834        kind: "instance",
1835        parent: "",
1836        data_attrs: &[],
1837        example_html: r#"<span class="moss-hl-deletion">- removed line</span>"#,
1838        example_markdown: "",
1839        status: Status::Emerging,
1840        since: "0",
1841        description: "Syntax-highlight diff token: removed-line text.",
1842    },
1843    ComponentEntry {
1844        class: "moss-hl-deletion-bg",
1845        kind: "instance",
1846        parent: "",
1847        data_attrs: &[],
1848        example_html: r#"<span class="moss-hl-deletion-bg">- removed line</span>"#,
1849        example_markdown: "",
1850        status: Status::Emerging,
1851        since: "0",
1852        description: "Syntax-highlight diff token: removed-line background.",
1853    },
1854    ComponentEntry {
1855        class: "moss-recent",
1856        kind: "container",
1857        parent: "",
1858        data_attrs: &[],
1859        example_html: r#"<ul class="moss-recent">
1860  <li><a href="/posts/spring-notes/">Spring notes</a><div class="moss-recent__date">2026-04-12</div><div class="moss-recent__desc">A walk through the garden.</div></li>
1861</ul>"#,
1862        example_markdown: ":::recent count=5 since=2026-01-01\n",
1863        status: Status::Emerging,
1864        since: "0",
1865        description: "Auto-generated list of recent posts emitted by the `:::recent` shortcode. Sorted newest-first; date and description slots are filled per child. No default CSS in the bundled theme — theme authors style it freely.",
1866    },
1867    ComponentEntry {
1868        class: "moss-recent__date",
1869        kind: "instance",
1870        parent: "moss-recent",
1871        data_attrs: &[],
1872        example_html: r#"<div class="moss-recent__date">2026-04-12</div>"#,
1873        example_markdown: "",
1874        status: Status::Emerging,
1875        since: "0",
1876        description: "Per-entry date slot inside `.moss-recent` (BEM child). Format is `YYYY-MM-DD`, derived from frontmatter `date`. Empty string when the post lacks a parseable date.",
1877    },
1878    ComponentEntry {
1879        class: "moss-recent__desc",
1880        kind: "instance",
1881        parent: "moss-recent",
1882        data_attrs: &[],
1883        example_html: r#"<div class="moss-recent__desc">A walk through the garden.</div>"#,
1884        example_markdown: "",
1885        status: Status::Emerging,
1886        since: "0",
1887        description: "Per-entry description slot inside `.moss-recent` (BEM child). Sourced from frontmatter `description`; empty when unset.",
1888    },
1889];
1890
1891/// Iterator over class names with `Status::Retired`. Used by the build
1892/// pipeline's theme lint to warn users about pre-v1 vocabulary.
1893///
1894/// Exposed as an iterator over `&'static str` so callers don't need to
1895/// import the `Status` enum (keeps moss-core's surface narrow).
1896pub fn retired_class_names() -> impl Iterator<Item = &'static str> {
1897    COMPONENTS.iter()
1898        .filter(|e| e.status == Status::Retired)
1899        .map(|e| e.class)
1900}