@glw907/cairn-cms 0.60.1 → 0.62.2

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 (254) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/dist/components/AdminLayout.svelte +22 -0
  3. package/dist/components/CairnAdmin.svelte +3 -0
  4. package/dist/components/CairnTidySettings.svelte +2 -2
  5. package/dist/components/CairnTidySettings.svelte.d.ts +1 -1
  6. package/dist/components/EditPage.svelte +116 -39
  7. package/dist/components/HelpHome.svelte +824 -0
  8. package/dist/components/HelpHome.svelte.d.ts +22 -0
  9. package/dist/components/MarkdownHelpDialog.svelte +4 -15
  10. package/dist/components/client-ingest.d.ts +16 -8
  11. package/dist/components/client-ingest.js +12 -6
  12. package/dist/components/editor-media.js +16 -8
  13. package/dist/components/editor-placeholder.d.ts +4 -2
  14. package/dist/components/editor-tidy.d.ts +24 -12
  15. package/dist/components/editor-tidy.js +8 -4
  16. package/dist/components/index.d.ts +1 -0
  17. package/dist/components/index.js +1 -0
  18. package/dist/components/link-completion.d.ts +12 -6
  19. package/dist/components/link-completion.js +12 -6
  20. package/dist/components/markdown-directives.d.ts +9 -6
  21. package/dist/components/markdown-directives.js +9 -6
  22. package/dist/components/markdown-format.d.ts +7 -2
  23. package/dist/components/markdown-format.js +59 -28
  24. package/dist/components/markdown-reference.d.ts +8 -0
  25. package/dist/components/markdown-reference.js +22 -0
  26. package/dist/components/media-upload-outcome.d.ts +12 -6
  27. package/dist/components/objective-errors.d.ts +8 -4
  28. package/dist/components/objective-errors.js +8 -4
  29. package/dist/components/preview-doc.d.ts +4 -2
  30. package/dist/components/preview-doc.js +4 -2
  31. package/dist/components/spellcheck.d.ts +55 -29
  32. package/dist/components/spellcheck.js +39 -21
  33. package/dist/components/tidy-categorize.d.ts +20 -10
  34. package/dist/components/tidy-categorize.js +16 -8
  35. package/dist/components/tidy-validate.d.ts +12 -6
  36. package/dist/components/tidy-validate.js +20 -10
  37. package/dist/components/topbar-context.d.ts +4 -2
  38. package/dist/content/advisories.d.ts +56 -0
  39. package/dist/content/advisories.js +87 -0
  40. package/dist/content/compose.d.ts +4 -2
  41. package/dist/content/compose.js +1 -0
  42. package/dist/content/excerpt.js +4 -2
  43. package/dist/content/getting-started.d.ts +18 -0
  44. package/dist/content/getting-started.js +12 -0
  45. package/dist/content/links.d.ts +16 -8
  46. package/dist/content/links.js +12 -6
  47. package/dist/content/manifest.d.ts +36 -18
  48. package/dist/content/manifest.js +32 -16
  49. package/dist/content/media-refs.d.ts +4 -2
  50. package/dist/content/media-refs.js +4 -2
  51. package/dist/content/media-rewrite.d.ts +8 -4
  52. package/dist/content/media-rewrite.js +76 -38
  53. package/dist/content/schema.d.ts +20 -10
  54. package/dist/content/site-dictionary.d.ts +4 -2
  55. package/dist/content/site-dictionary.js +8 -4
  56. package/dist/content/types.d.ts +97 -42
  57. package/dist/delivery/content-index.d.ts +16 -8
  58. package/dist/delivery/feeds.js +4 -2
  59. package/dist/delivery/json-ld.d.ts +3 -0
  60. package/dist/delivery/json-ld.js +3 -0
  61. package/dist/delivery/manifest.d.ts +4 -2
  62. package/dist/delivery/manifest.js +4 -2
  63. package/dist/delivery/public-routes.d.ts +12 -6
  64. package/dist/delivery/public-routes.js +4 -2
  65. package/dist/delivery/seo-fields.d.ts +12 -6
  66. package/dist/delivery/seo-fields.js +8 -4
  67. package/dist/delivery/site-indexes.d.ts +4 -2
  68. package/dist/delivery/site-resolver.d.ts +4 -2
  69. package/dist/delivery/site-resolver.js +4 -2
  70. package/dist/doctor/cloudflare-api.d.ts +6 -0
  71. package/dist/doctor/cloudflare-api.js +6 -0
  72. package/dist/doctor/index.d.ts +12 -6
  73. package/dist/doctor/report.d.ts +3 -0
  74. package/dist/doctor/report.js +3 -0
  75. package/dist/doctor/run.d.ts +3 -0
  76. package/dist/doctor/run.js +3 -0
  77. package/dist/doctor/types.d.ts +10 -2
  78. package/dist/doctor/types.js +6 -0
  79. package/dist/doctor/wrangler-config.d.ts +7 -2
  80. package/dist/doctor/wrangler-config.js +3 -0
  81. package/dist/email.d.ts +4 -2
  82. package/dist/env.d.ts +0 -3
  83. package/dist/env.js +0 -3
  84. package/dist/github/branches.d.ts +4 -2
  85. package/dist/github/branches.js +4 -2
  86. package/dist/github/signing.d.ts +1 -1
  87. package/dist/github/signing.js +2 -2
  88. package/dist/log/events.d.ts +1 -1
  89. package/dist/media/bulk-delete-plan.d.ts +8 -4
  90. package/dist/media/config.d.ts +12 -6
  91. package/dist/media/config.js +16 -8
  92. package/dist/media/delivery-bucket.d.ts +4 -2
  93. package/dist/media/library-entry.d.ts +4 -2
  94. package/dist/media/library-entry.js +4 -2
  95. package/dist/media/manifest.d.ts +29 -15
  96. package/dist/media/manifest.js +29 -16
  97. package/dist/media/naming.d.ts +12 -6
  98. package/dist/media/naming.js +24 -12
  99. package/dist/media/orphan-scan.d.ts +4 -2
  100. package/dist/media/reconcile.d.ts +21 -11
  101. package/dist/media/reconcile.js +12 -6
  102. package/dist/media/reference.d.ts +8 -4
  103. package/dist/media/reference.js +12 -6
  104. package/dist/media/rewrite-plan.d.ts +12 -6
  105. package/dist/media/sniff.d.ts +4 -2
  106. package/dist/media/sniff.js +28 -14
  107. package/dist/media/store.d.ts +16 -8
  108. package/dist/media/store.js +4 -2
  109. package/dist/media/transform-url.d.ts +12 -6
  110. package/dist/media/transform-url.js +8 -4
  111. package/dist/media/usage.d.ts +8 -4
  112. package/dist/nav/site-config.d.ts +16 -8
  113. package/dist/render/component-grammar.d.ts +23 -10
  114. package/dist/render/component-grammar.js +19 -8
  115. package/dist/render/component-insert.d.ts +8 -4
  116. package/dist/render/component-insert.js +4 -2
  117. package/dist/render/component-reference.d.ts +4 -2
  118. package/dist/render/component-reference.js +4 -2
  119. package/dist/render/component-validate.d.ts +3 -0
  120. package/dist/render/component-validate.js +3 -0
  121. package/dist/render/glyph.d.ts +4 -2
  122. package/dist/render/glyph.js +4 -2
  123. package/dist/render/pipeline.d.ts +20 -10
  124. package/dist/render/pipeline.js +4 -2
  125. package/dist/render/registry.d.ts +40 -20
  126. package/dist/render/registry.js +16 -8
  127. package/dist/render/rehype-dispatch.d.ts +22 -8
  128. package/dist/render/rehype-dispatch.js +22 -8
  129. package/dist/render/remark-directives.d.ts +3 -0
  130. package/dist/render/remark-directives.js +3 -0
  131. package/dist/render/remark-figure.d.ts +4 -2
  132. package/dist/render/remark-figure.js +4 -2
  133. package/dist/render/resolve-links.d.ts +4 -2
  134. package/dist/render/resolve-links.js +4 -2
  135. package/dist/render/resolve-media.d.ts +16 -8
  136. package/dist/render/resolve-media.js +12 -6
  137. package/dist/sveltekit/admin-dispatch.d.ts +2 -0
  138. package/dist/sveltekit/admin-dispatch.js +9 -3
  139. package/dist/sveltekit/auth-routes.d.ts +3 -0
  140. package/dist/sveltekit/auth-routes.js +3 -0
  141. package/dist/sveltekit/cairn-admin.d.ts +16 -5
  142. package/dist/sveltekit/cairn-admin.js +26 -10
  143. package/dist/sveltekit/content-routes.d.ts +191 -86
  144. package/dist/sveltekit/content-routes.js +297 -107
  145. package/dist/sveltekit/editors-routes.d.ts +3 -0
  146. package/dist/sveltekit/editors-routes.js +3 -0
  147. package/dist/sveltekit/guard.d.ts +4 -2
  148. package/dist/sveltekit/guard.js +4 -2
  149. package/dist/sveltekit/https-required-page.d.ts +1 -1
  150. package/dist/sveltekit/https-required-page.js +1 -1
  151. package/dist/sveltekit/index.d.ts +1 -1
  152. package/dist/sveltekit/media-route.d.ts +1 -2
  153. package/dist/sveltekit/media-route.js +13 -8
  154. package/dist/sveltekit/nav-routes.d.ts +7 -2
  155. package/dist/sveltekit/nav-routes.js +3 -0
  156. package/dist/sveltekit/types.d.ts +4 -2
  157. package/dist/vite/index.d.ts +32 -16
  158. package/dist/vite/index.js +52 -26
  159. package/dist/vite/resolve-root.d.ts +8 -4
  160. package/dist/vite/resolve-root.js +4 -2
  161. package/package.json +7 -1
  162. package/src/lib/components/AdminLayout.svelte +22 -0
  163. package/src/lib/components/CairnAdmin.svelte +3 -0
  164. package/src/lib/components/CairnTidySettings.svelte +2 -2
  165. package/src/lib/components/ComponentForm.svelte +0 -1
  166. package/src/lib/components/EditPage.svelte +133 -41
  167. package/src/lib/components/HelpHome.svelte +850 -0
  168. package/src/lib/components/MarkdownHelpDialog.svelte +4 -15
  169. package/src/lib/components/client-ingest.ts +20 -10
  170. package/src/lib/components/editor-media.ts +20 -10
  171. package/src/lib/components/editor-placeholder.ts +12 -6
  172. package/src/lib/components/editor-tidy.ts +28 -14
  173. package/src/lib/components/index.ts +1 -0
  174. package/src/lib/components/link-completion.ts +12 -6
  175. package/src/lib/components/markdown-directives.ts +13 -8
  176. package/src/lib/components/markdown-format.ts +63 -30
  177. package/src/lib/components/markdown-reference.ts +30 -0
  178. package/src/lib/components/media-upload-outcome.ts +12 -6
  179. package/src/lib/components/objective-errors.ts +16 -8
  180. package/src/lib/components/preview-doc.ts +4 -2
  181. package/src/lib/components/spellcheck.ts +79 -41
  182. package/src/lib/components/tidy-categorize.ts +28 -14
  183. package/src/lib/components/tidy-validate.ts +28 -14
  184. package/src/lib/components/topbar-context.ts +4 -2
  185. package/src/lib/content/advisories.ts +150 -0
  186. package/src/lib/content/compose.ts +5 -2
  187. package/src/lib/content/excerpt.ts +4 -2
  188. package/src/lib/content/getting-started.ts +31 -0
  189. package/src/lib/content/links.ts +16 -8
  190. package/src/lib/content/manifest.ts +36 -18
  191. package/src/lib/content/media-refs.ts +4 -2
  192. package/src/lib/content/media-rewrite.ts +100 -50
  193. package/src/lib/content/schema.ts +20 -10
  194. package/src/lib/content/site-dictionary.ts +8 -4
  195. package/src/lib/content/types.ts +97 -42
  196. package/src/lib/delivery/content-index.ts +16 -8
  197. package/src/lib/delivery/feeds.ts +4 -2
  198. package/src/lib/delivery/json-ld.ts +3 -0
  199. package/src/lib/delivery/manifest.ts +4 -2
  200. package/src/lib/delivery/public-routes.ts +16 -8
  201. package/src/lib/delivery/seo-fields.ts +12 -6
  202. package/src/lib/delivery/site-indexes.ts +4 -2
  203. package/src/lib/delivery/site-resolver.ts +4 -2
  204. package/src/lib/doctor/cloudflare-api.ts +6 -0
  205. package/src/lib/doctor/index.ts +12 -6
  206. package/src/lib/doctor/report.ts +3 -0
  207. package/src/lib/doctor/run.ts +3 -0
  208. package/src/lib/doctor/types.ts +10 -2
  209. package/src/lib/doctor/wrangler-config.ts +7 -2
  210. package/src/lib/email.ts +4 -2
  211. package/src/lib/env.ts +0 -3
  212. package/src/lib/github/branches.ts +4 -2
  213. package/src/lib/github/signing.ts +2 -2
  214. package/src/lib/log/events.ts +1 -0
  215. package/src/lib/media/bulk-delete-plan.ts +8 -4
  216. package/src/lib/media/config.ts +24 -12
  217. package/src/lib/media/delivery-bucket.ts +4 -2
  218. package/src/lib/media/library-entry.ts +4 -2
  219. package/src/lib/media/manifest.ts +33 -18
  220. package/src/lib/media/naming.ts +24 -12
  221. package/src/lib/media/orphan-scan.ts +4 -2
  222. package/src/lib/media/reconcile.ts +21 -11
  223. package/src/lib/media/reference.ts +12 -6
  224. package/src/lib/media/rewrite-plan.ts +12 -6
  225. package/src/lib/media/sniff.ts +28 -14
  226. package/src/lib/media/store.ts +16 -8
  227. package/src/lib/media/transform-url.ts +12 -6
  228. package/src/lib/media/usage.ts +8 -4
  229. package/src/lib/nav/site-config.ts +16 -8
  230. package/src/lib/render/component-grammar.ts +23 -10
  231. package/src/lib/render/component-insert.ts +8 -4
  232. package/src/lib/render/component-reference.ts +4 -2
  233. package/src/lib/render/component-validate.ts +3 -0
  234. package/src/lib/render/glyph.ts +4 -2
  235. package/src/lib/render/pipeline.ts +20 -10
  236. package/src/lib/render/registry.ts +44 -22
  237. package/src/lib/render/rehype-dispatch.ts +22 -8
  238. package/src/lib/render/remark-directives.ts +3 -0
  239. package/src/lib/render/remark-figure.ts +4 -2
  240. package/src/lib/render/resolve-links.ts +4 -2
  241. package/src/lib/render/resolve-media.ts +16 -8
  242. package/src/lib/sveltekit/admin-dispatch.ts +10 -4
  243. package/src/lib/sveltekit/auth-routes.ts +3 -0
  244. package/src/lib/sveltekit/cairn-admin.ts +37 -15
  245. package/src/lib/sveltekit/content-routes.ts +494 -197
  246. package/src/lib/sveltekit/editors-routes.ts +3 -0
  247. package/src/lib/sveltekit/guard.ts +4 -2
  248. package/src/lib/sveltekit/https-required-page.ts +1 -1
  249. package/src/lib/sveltekit/index.ts +3 -0
  250. package/src/lib/sveltekit/media-route.ts +13 -8
  251. package/src/lib/sveltekit/nav-routes.ts +7 -2
  252. package/src/lib/sveltekit/types.ts +4 -2
  253. package/src/lib/vite/index.ts +60 -30
  254. package/src/lib/vite/resolve-root.ts +8 -4
@@ -0,0 +1,824 @@
1
+ <!--
2
+ @component
3
+ The Help home admin screen, the standing place an author comes to get their bearings and look up
4
+ how things work. It renders inside `AdminLayout` (the office shell), so it carries no `data-theme`
5
+ wrapper and imports no CSS: the layout owns the theme and `cairn-admin.css`, and this component
6
+ consumes the Warm Stone tokens through its scoped `<style>` block.
7
+
8
+ The content is one calm column: a masthead, then three co-equal eyebrow-plus-display sections.
9
+
10
+ - Getting started reads `data.gettingStarted`, the count derived from the committed manifest and
11
+ the open edit branches (never a stored count). At 3 of 3 the whole section is omitted, never
12
+ shown as a done checklist. A per-device localStorage flag hides it on request.
13
+ - Formatting renders `data.reference` (the everyday text and links rows) as a real semantic table.
14
+ - Get help reads the optional `data.supportContact`. Unset is the canonical self-serve default,
15
+ with no control; set renders the hand-off shaped by the contact (email, URL, or a note).
16
+ -->
17
+ <script lang="ts">let { data } = $props();
18
+ const textRows = $derived(data.reference.filter((r) => r.group === "text"));
19
+ const linkRows = $derived(data.reference.filter((r) => r.group === "links"));
20
+ const steps = $derived([
21
+ {
22
+ title: "Write your first post",
23
+ done: data.gettingStarted.wrotePost,
24
+ doneDesc: "You have a post started. Open it any time to keep going.",
25
+ todoDesc: "A post is for news and updates. Start your first one whenever you are ready.",
26
+ actionLabel: "Write a post",
27
+ href: "/admin/posts"
28
+ },
29
+ {
30
+ title: "Publish it",
31
+ done: data.gettingStarted.publishedPost,
32
+ doneDesc: "Your post is on the live site. Edit it and publish again any time.",
33
+ todoDesc: "Publishing puts your post on the live site. You can change it and publish again any time.",
34
+ actionLabel: "Publish a post",
35
+ href: "/admin/posts"
36
+ },
37
+ {
38
+ title: "Create a page",
39
+ done: data.gettingStarted.createdPage,
40
+ doneDesc: "You have a page. Open it any time to keep going.",
41
+ todoDesc: "A page is for the parts that stay put, like About or Contact.",
42
+ actionLabel: "Add a page",
43
+ href: "/admin/pages"
44
+ }
45
+ ]);
46
+ const doneCount = $derived(data.gettingStarted.doneCount);
47
+ const barWidth = $derived(doneCount === 0 ? "3%" : `${doneCount / 3 * 100}%`);
48
+ function supportLink(contact2) {
49
+ const c = contact2.trim();
50
+ if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(c)) return { kind: "email", href: `mailto:${c}` };
51
+ if (/^https?:\/\/\S+$/.test(c)) return { kind: "url", href: c };
52
+ return { kind: "text" };
53
+ }
54
+ const contact = $derived(data.supportContact?.trim() ?? "");
55
+ const support = $derived(contact ? supportLink(contact) : null);
56
+ const HIDDEN_KEY = "cairn-help-getting-started-hidden";
57
+ let hidden = $state(false);
58
+ $effect(() => {
59
+ hidden = localStorage.getItem(HIDDEN_KEY) === "1";
60
+ });
61
+ function hideSteps() {
62
+ hidden = true;
63
+ localStorage.setItem(HIDDEN_KEY, "1");
64
+ }
65
+ function showSteps() {
66
+ hidden = false;
67
+ localStorage.removeItem(HIDDEN_KEY);
68
+ }
69
+ </script>
70
+
71
+ <div class="cairn-help-content">
72
+ <div class="help-col">
73
+ <!-- masthead: a real-sentence h1, the page's single display beat -->
74
+ <div class="page-head">
75
+ <span class="eyebrow">Help</span>
76
+ <h1 class="page-h1">Find your way around</h1>
77
+ <p class="page-lede">The place to get your bearings and look up how things work.</p>
78
+ </div>
79
+
80
+ <!-- SECTION 1: getting started (omitted at 3 of 3) -->
81
+ {#if doneCount < 3}
82
+ {#if hidden}
83
+ <div class="start-restore">
84
+ <button type="button" onclick={showSteps}>Show getting started</button>
85
+ </div>
86
+ {:else}
87
+ <section class="section" aria-labelledby="cairn-help-start-eye">
88
+ <div class="section-head">
89
+ <div class="section-titles">
90
+ <span class="eyebrow" id="cairn-help-start-eye">Getting started</span>
91
+ <h2 class="section-h">Your first steps</h2>
92
+ </div>
93
+ </div>
94
+
95
+ <div class="card start" class:start-empty={doneCount === 0}>
96
+ <div class="start-top">
97
+ {#if doneCount === 0}
98
+ <span class="start-mark" aria-hidden="true">
99
+ <svg viewBox="0 0 24 24" fill="currentColor"
100
+ ><ellipse cx="12" cy="18.2" rx="7" ry="2.5" /><ellipse
101
+ cx="12"
102
+ cy="13"
103
+ rx="5.2"
104
+ ry="2.1"
105
+ /><ellipse cx="12" cy="8.6" rx="3.7" ry="1.7" /><ellipse
106
+ cx="12"
107
+ cy="5"
108
+ rx="2"
109
+ ry="1.2"
110
+ /></svg
111
+ >
112
+ </span>
113
+ {/if}
114
+ <div class="start-lead">
115
+ <p class="start-lead-sub">Three small steps to get going.</p>
116
+ </div>
117
+ <!-- the count is the source of truth; the bar is decorative only -->
118
+ <div class="prog">
119
+ <div class="prog-count"><b>{doneCount}</b> of 3 done</div>
120
+ <div class="prog-bar" class:is-seed={doneCount === 0} role="presentation">
121
+ <i style="width:{barWidth}"></i>
122
+ </div>
123
+ </div>
124
+ </div>
125
+
126
+ <ol class="steps">
127
+ {#each steps as step (step.title)}
128
+ <li class="step" class:is-done={step.done}>
129
+ <span class="step-box" aria-hidden="true">
130
+ {#if step.done}
131
+ <svg
132
+ fill="none"
133
+ viewBox="0 0 24 24"
134
+ stroke="currentColor"
135
+ stroke-width="3"
136
+ stroke-linecap="round"
137
+ stroke-linejoin="round"><path d="M20 6 9 17l-5-5" /></svg
138
+ >
139
+ {/if}
140
+ </span>
141
+ <span class="step-body">
142
+ <span class="step-title">{step.title}</span>
143
+ <span class="step-desc">{step.done ? step.doneDesc : step.todoDesc}</span>
144
+ </span>
145
+ {#if step.done}
146
+ <span class="step-done-tag">
147
+ <svg
148
+ fill="none"
149
+ viewBox="0 0 24 24"
150
+ stroke="currentColor"
151
+ stroke-width="2.5"
152
+ stroke-linecap="round"
153
+ stroke-linejoin="round"
154
+ aria-hidden="true"><path d="M20 6 9 17l-5-5" /></svg
155
+ >
156
+ Done
157
+ </span>
158
+ <a class="step-open" href={step.href}>Open it</a>
159
+ {:else}
160
+ <span class="sr-only">not done</span>
161
+ <a class="step-act" href={step.href}>
162
+ {step.actionLabel}
163
+ <svg
164
+ fill="none"
165
+ viewBox="0 0 24 24"
166
+ stroke="currentColor"
167
+ stroke-width="2.5"
168
+ stroke-linecap="round"
169
+ stroke-linejoin="round"
170
+ aria-hidden="true"><path d="m9 18 6-6-6-6" /></svg
171
+ >
172
+ </a>
173
+ {/if}
174
+ </li>
175
+ {/each}
176
+ </ol>
177
+
178
+ <div class="start-foot">
179
+ <span>These steps follow what is really on your site.</span>
180
+ <button type="button" onclick={hideSteps}>Hide these steps</button>
181
+ </div>
182
+ </div>
183
+ </section>
184
+ {/if}
185
+ {/if}
186
+
187
+ <!-- SECTION 2: formatting reference -->
188
+ <section class="section" aria-labelledby="cairn-help-ref-eye">
189
+ <div class="section-head">
190
+ <div class="section-titles">
191
+ <span class="eyebrow" id="cairn-help-ref-eye">Formatting</span>
192
+ <h2 class="section-h">How to format text</h2>
193
+ </div>
194
+ <span class="section-meta">Type the characters on the left</span>
195
+ </div>
196
+
197
+ {#snippet refTable(caption: string, rows: MarkdownReferenceRow[])}
198
+ <table class="ref-table">
199
+ <caption>{caption}</caption>
200
+ <thead>
201
+ <tr><th scope="col">Type this</th><th scope="col">What it makes</th></tr>
202
+ </thead>
203
+ <tbody>
204
+ {#each rows as row (row.syntax)}
205
+ <tr>
206
+ <th scope="row">{row.syntax}</th>
207
+ <td>{row.makes}</td>
208
+ </tr>
209
+ {/each}
210
+ </tbody>
211
+ </table>
212
+ {/snippet}
213
+
214
+ <div class="card ref-card">
215
+ <div class="ref-cols">
216
+ {@render refTable('Text', textRows)}
217
+ {@render refTable('Links and lists', linkRows)}
218
+ </div>
219
+
220
+ <p class="ref-foot">
221
+ <svg
222
+ fill="none"
223
+ viewBox="0 0 24 24"
224
+ stroke="currentColor"
225
+ stroke-width="2"
226
+ stroke-linecap="round"
227
+ stroke-linejoin="round"
228
+ aria-hidden="true"
229
+ ><circle cx="12" cy="12" r="10" /><path d="M12 16v-4" /><path d="M12 8h.01" /></svg
230
+ >
231
+ <span
232
+ >This same sheet opens beside the editor while you write. Press <span class="kbd"
233
+ >Ctrl</span
234
+ >
235
+ <span class="kbd">/</span>.</span
236
+ >
237
+ </p>
238
+ </div>
239
+ </section>
240
+
241
+ <!-- SECTION 3: get help -->
242
+ <section class="section" aria-labelledby="cairn-help-eye">
243
+ <div class="section-head">
244
+ <div class="section-titles">
245
+ <span class="eyebrow" id="cairn-help-eye">Get help</span>
246
+ <h2 class="section-h">
247
+ {support ? 'Ask the person who set up your site' : 'Stuck on something?'}
248
+ </h2>
249
+ </div>
250
+ </div>
251
+
252
+ <div class="card help-card">
253
+ {#if !support}
254
+ <div class="help-card-body">
255
+ <p class="help-card-sub">
256
+ Check the formatting guide above, or ask whoever set up your site.
257
+ </p>
258
+ </div>
259
+ {:else if support.kind === 'text'}
260
+ <div class="help-card-body">
261
+ <p class="help-card-sub">Whoever set up your site left this note: {contact}</p>
262
+ </div>
263
+ {:else}
264
+ <div class="help-card-body">
265
+ <p class="help-card-sub">
266
+ Whoever set up your site can change things you cannot change here, like the menu and
267
+ who can sign in.
268
+ {#if support.kind === 'email'}Reach them at <b>{contact}</b>.{:else}Find help at
269
+ <b>{contact}</b>.{/if}
270
+ </p>
271
+ </div>
272
+ {#if support.kind === 'email'}
273
+ <a class="btn-quiet" href={support.href}>
274
+ <svg
275
+ fill="none"
276
+ viewBox="0 0 24 24"
277
+ stroke="currentColor"
278
+ stroke-width="2"
279
+ stroke-linecap="round"
280
+ stroke-linejoin="round"
281
+ aria-hidden="true"
282
+ ><rect x="2" y="4" width="20" height="16" rx="2" /><path
283
+ d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"
284
+ /></svg
285
+ >
286
+ Email support
287
+ </a>
288
+ {:else}
289
+ <a class="btn-quiet" href={support.href} target="_blank" rel="noopener">
290
+ <svg
291
+ fill="none"
292
+ viewBox="0 0 24 24"
293
+ stroke="currentColor"
294
+ stroke-width="2"
295
+ stroke-linecap="round"
296
+ stroke-linejoin="round"
297
+ aria-hidden="true"
298
+ ><path d="M15 3h6v6" /><path d="M10 14 21 3" /><path
299
+ d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"
300
+ /></svg
301
+ >
302
+ Get help
303
+ </a>
304
+ {/if}
305
+ {/if}
306
+ </div>
307
+ </section>
308
+ </div>
309
+ </div>
310
+
311
+ <style>
312
+ /* The Help home content column. The styles consume the Warm Stone tokens the AdminLayout theme
313
+ root owns; this block never redefines :root or [data-theme]. Ported from the rev.2 polished
314
+ mockup (docs/internal/design/2026-06-23-help-shell-mockup-rev2-polished.html), adapted to the
315
+ three co-equal eyebrow-plus-display sections and the derived getting-started state. */
316
+
317
+ .sr-only {
318
+ position: absolute;
319
+ width: 1px;
320
+ height: 1px;
321
+ padding: 0;
322
+ margin: -1px;
323
+ overflow: hidden;
324
+ clip: rect(0 0 0 0);
325
+ white-space: nowrap;
326
+ border: 0;
327
+ }
328
+
329
+ .cairn-help-content {
330
+ flex: 1 1 auto;
331
+ padding: 2.75rem 2.5rem 3.5rem;
332
+ overflow: auto;
333
+ }
334
+ .help-col {
335
+ max-width: 58rem;
336
+ margin: 0 auto;
337
+ width: 100%;
338
+ }
339
+
340
+ .eyebrow {
341
+ font-size: 0.6875rem;
342
+ font-weight: 600;
343
+ letter-spacing: 0.08em;
344
+ text-transform: uppercase;
345
+ color: var(--color-muted);
346
+ }
347
+
348
+ /* the masthead: a plain eyebrow over a real-sentence h1, the page's single display beat */
349
+ .page-head {
350
+ margin-bottom: 30px;
351
+ }
352
+ .page-h1 {
353
+ font-family: var(--font-display);
354
+ font-size: 1.875rem;
355
+ font-weight: 700;
356
+ letter-spacing: -0.025em;
357
+ margin: 5px 0 0;
358
+ }
359
+ .page-lede {
360
+ font-size: 0.9375rem;
361
+ color: var(--color-muted);
362
+ margin: 8px 0 0;
363
+ max-width: 54ch;
364
+ line-height: 1.55;
365
+ }
366
+
367
+ /* the shared section-head rhythm: an eyebrow over a display title, with an optional trailing meta */
368
+ .section {
369
+ margin-top: 36px;
370
+ }
371
+ .section-head {
372
+ display: flex;
373
+ align-items: baseline;
374
+ gap: 14px;
375
+ margin-bottom: 16px;
376
+ }
377
+ .section-titles {
378
+ display: flex;
379
+ flex-direction: column;
380
+ gap: 2px;
381
+ }
382
+ .section-h {
383
+ font-family: var(--font-display);
384
+ font-size: 1.25rem;
385
+ font-weight: 700;
386
+ letter-spacing: -0.02em;
387
+ line-height: 1.12;
388
+ margin: 0;
389
+ }
390
+ .section-meta {
391
+ margin-left: auto;
392
+ align-self: center;
393
+ font-size: 0.75rem;
394
+ color: var(--color-muted);
395
+ }
396
+
397
+ /* the floating-card recipe: rounded-box, hairline plus soft shadow, on base-100 */
398
+ .card {
399
+ border: 1px solid var(--cairn-card-border);
400
+ border-radius: var(--radius-box);
401
+ background: var(--color-base-100);
402
+ box-shadow: var(--cairn-shadow);
403
+ overflow: hidden;
404
+ }
405
+
406
+ /* SECTION 1: getting started */
407
+ .start {
408
+ padding: 22px 24px 18px;
409
+ }
410
+ /* the 0-of-3 empty state composition: the cairn mark presides above a warmer frame */
411
+ .start-empty {
412
+ background: color-mix(in oklab, var(--color-primary) 2.5%, var(--color-base-100));
413
+ }
414
+ .start-mark {
415
+ flex: none;
416
+ height: 40px;
417
+ width: 40px;
418
+ border-radius: 0.75rem;
419
+ background: color-mix(in oklab, var(--color-primary) 12%, transparent);
420
+ color: var(--color-primary);
421
+ display: inline-flex;
422
+ align-items: center;
423
+ justify-content: center;
424
+ }
425
+ .start-mark svg {
426
+ width: 22px;
427
+ height: 22px;
428
+ }
429
+ .start-top {
430
+ display: flex;
431
+ align-items: flex-start;
432
+ gap: 18px;
433
+ flex-wrap: wrap;
434
+ }
435
+ .start-lead {
436
+ flex: 1 1 20rem;
437
+ min-width: 0;
438
+ }
439
+ .start-lead-sub {
440
+ font-size: 0.8125rem;
441
+ color: var(--color-muted);
442
+ margin: 0;
443
+ max-width: 46ch;
444
+ line-height: 1.5;
445
+ }
446
+
447
+ /* the progress readout: the count is the source of truth, the bar is decorative only */
448
+ .prog {
449
+ flex: 0 0 auto;
450
+ min-width: 11rem;
451
+ text-align: right;
452
+ }
453
+ .prog-count {
454
+ font-size: 0.8125rem;
455
+ font-weight: 600;
456
+ color: var(--color-base-content);
457
+ }
458
+ .prog-count b {
459
+ color: var(--color-positive-ink);
460
+ font-weight: 700;
461
+ }
462
+ .prog-bar {
463
+ height: 6px;
464
+ border-radius: 999px;
465
+ margin-top: 8px;
466
+ background: color-mix(in oklab, var(--color-base-content) 8%, transparent);
467
+ overflow: hidden;
468
+ }
469
+ .prog-bar > i {
470
+ display: block;
471
+ height: 100%;
472
+ min-width: 6px;
473
+ border-radius: 999px;
474
+ background: var(--color-primary);
475
+ }
476
+ /* the 0-of-3 seed: a faint desaturated fill, so the rail reads as a track, never as progress */
477
+ .prog-bar.is-seed > i {
478
+ background: color-mix(in oklab, var(--color-base-content) 22%, transparent);
479
+ }
480
+
481
+ /* the steps: quiet rows inside the single card, never nested cards */
482
+ .steps {
483
+ list-style: none;
484
+ margin: 18px 0 0;
485
+ padding: 0;
486
+ display: grid;
487
+ gap: 8px;
488
+ }
489
+ .step {
490
+ display: flex;
491
+ align-items: center;
492
+ gap: 13px;
493
+ padding: 12px 14px;
494
+ border: 1px solid var(--cairn-card-border);
495
+ border-radius: 0.75rem;
496
+ background: var(--color-base-100);
497
+ }
498
+ /* the unchecked ring is content-55% (about 3:1 on base-100), a control state perceivable on its
499
+ own (WCAG 1.4.11), and kept a thin ring rather than a filled box so it never reads as checked */
500
+ .step-box {
501
+ flex: none;
502
+ height: 24px;
503
+ width: 24px;
504
+ border-radius: 7px;
505
+ border: 2px solid color-mix(in oklab, var(--color-base-content) 55%, transparent);
506
+ background: var(--color-base-100);
507
+ display: inline-flex;
508
+ align-items: center;
509
+ justify-content: center;
510
+ color: transparent;
511
+ }
512
+ .step-box svg {
513
+ width: 13px;
514
+ height: 13px;
515
+ }
516
+ .step-body {
517
+ flex: 1 1 auto;
518
+ min-width: 0;
519
+ display: flex;
520
+ flex-direction: column;
521
+ }
522
+ .step-title {
523
+ font-size: 0.9375rem;
524
+ font-weight: 600;
525
+ color: var(--color-base-content);
526
+ }
527
+ .step-desc {
528
+ font-size: 0.8125rem;
529
+ color: var(--color-muted);
530
+ margin-top: 2px;
531
+ line-height: 1.45;
532
+ }
533
+
534
+ /* a not-done step routes to where it completes through its own short action link */
535
+ .step-act {
536
+ flex: none;
537
+ margin-left: auto;
538
+ display: inline-flex;
539
+ align-items: center;
540
+ gap: 5px;
541
+ height: 30px;
542
+ padding: 0 12px;
543
+ border: 1px solid var(--cairn-card-border);
544
+ border-radius: var(--radius-field);
545
+ background: var(--color-base-100);
546
+ color: var(--color-primary);
547
+ font: 600 0.78125rem/1 var(--font-body);
548
+ cursor: pointer;
549
+ text-decoration: none;
550
+ transition: border-color 120ms ease, background-color 120ms ease;
551
+ }
552
+ .step-act:hover {
553
+ border-color: color-mix(in oklab, var(--color-primary) 40%, var(--cairn-card-border));
554
+ background: color-mix(in oklab, var(--color-primary) 6%, transparent);
555
+ }
556
+ .step-act svg {
557
+ width: 13px;
558
+ height: 13px;
559
+ }
560
+
561
+ /* the done state. The cue reaches three ways and never by color alone (WCAG 1.4.1): the filled
562
+ glyph box, a visible "Done" tag, and the open step's sr-only "not done". A done step keeps a
563
+ quiet "Open it" so every row carries an affordance. */
564
+ .step.is-done {
565
+ background: color-mix(in oklab, var(--color-positive-ink) 4%, var(--color-base-100));
566
+ }
567
+ .step.is-done .step-box {
568
+ background: var(--color-positive-ink);
569
+ border-color: var(--color-positive-ink);
570
+ color: var(--color-primary-content);
571
+ }
572
+ .step.is-done .step-title {
573
+ color: var(--color-muted);
574
+ }
575
+ .step-done-tag {
576
+ flex: none;
577
+ margin-left: auto;
578
+ display: inline-flex;
579
+ align-items: center;
580
+ gap: 5px;
581
+ font-size: 0.75rem;
582
+ font-weight: 600;
583
+ color: var(--color-positive-ink);
584
+ }
585
+ .step-done-tag svg {
586
+ width: 13px;
587
+ height: 13px;
588
+ }
589
+ .step-open {
590
+ flex: none;
591
+ display: inline-flex;
592
+ align-items: center;
593
+ gap: 5px;
594
+ font: 600 0.78125rem/1 var(--font-body);
595
+ color: var(--color-muted);
596
+ padding: 4px 6px;
597
+ text-decoration: underline;
598
+ text-underline-offset: 2px;
599
+ }
600
+ .step-open:hover {
601
+ color: var(--color-base-content);
602
+ }
603
+
604
+ .start-foot {
605
+ margin-top: 16px;
606
+ display: flex;
607
+ align-items: center;
608
+ gap: 10px;
609
+ flex-wrap: wrap;
610
+ font-size: 0.75rem;
611
+ color: var(--color-muted);
612
+ }
613
+ .start-foot button {
614
+ color: var(--color-muted);
615
+ background: none;
616
+ border: 0;
617
+ padding: 0;
618
+ cursor: pointer;
619
+ font: inherit;
620
+ text-decoration: underline;
621
+ text-underline-offset: 2px;
622
+ }
623
+ .start-foot button:hover {
624
+ color: var(--color-base-content);
625
+ }
626
+
627
+ /* the restore affordance shown once the section is hidden */
628
+ .start-restore {
629
+ margin-top: 36px;
630
+ }
631
+ .start-restore button {
632
+ color: var(--color-muted);
633
+ background: none;
634
+ border: 0;
635
+ padding: 0;
636
+ cursor: pointer;
637
+ font: 500 0.8125rem/1 var(--font-body);
638
+ text-decoration: underline;
639
+ text-underline-offset: 2px;
640
+ }
641
+ .start-restore button:hover {
642
+ color: var(--color-base-content);
643
+ }
644
+
645
+ /* SECTION 2: formatting reference */
646
+ .ref-cols {
647
+ display: grid;
648
+ grid-template-columns: 1fr 1fr;
649
+ }
650
+ .ref-cols > table:first-child {
651
+ border-right: 1px solid var(--cairn-card-border);
652
+ }
653
+ .ref-table {
654
+ width: 100%;
655
+ border-collapse: collapse;
656
+ table-layout: fixed;
657
+ }
658
+ .ref-table caption {
659
+ text-align: left;
660
+ font-size: 0.625rem;
661
+ font-weight: 600;
662
+ letter-spacing: 0.09em;
663
+ text-transform: uppercase;
664
+ color: var(--color-muted);
665
+ padding: 16px 22px 6px;
666
+ }
667
+ .ref-table thead th {
668
+ text-align: left;
669
+ width: 50%;
670
+ font-size: 0.625rem;
671
+ font-weight: 600;
672
+ letter-spacing: 0.07em;
673
+ text-transform: uppercase;
674
+ color: var(--color-muted);
675
+ font-family: var(--font-body);
676
+ padding: 6px 22px 10px;
677
+ border-bottom: 1px solid color-mix(in oklab, var(--cairn-card-border) 70%, transparent);
678
+ }
679
+ .ref-table tbody tr + tr td,
680
+ .ref-table tbody tr + tr th {
681
+ border-top: 1px solid color-mix(in oklab, var(--cairn-card-border) 65%, transparent);
682
+ }
683
+ /* the "type this" cell renders the literal syntax in the iA Writer Mono editor face */
684
+ .ref-table th[scope='row'] {
685
+ font-weight: 400;
686
+ text-align: left;
687
+ padding: 10px 22px;
688
+ font-family: var(--font-editor);
689
+ font-size: 0.8125rem;
690
+ line-height: 1.5;
691
+ color: var(--color-base-content);
692
+ white-space: nowrap;
693
+ }
694
+ /* the "what it makes" cell: the plain gloss in the body face */
695
+ .ref-table td {
696
+ padding: 10px 22px;
697
+ font-size: 0.875rem;
698
+ line-height: 1.5;
699
+ color: var(--color-base-content);
700
+ }
701
+
702
+ /* the reference foot points at the present, working help beside the editor */
703
+ .ref-foot {
704
+ display: flex;
705
+ align-items: center;
706
+ gap: 8px;
707
+ margin: 0;
708
+ padding: 12px 22px;
709
+ border-top: 1px solid var(--cairn-card-border);
710
+ background: color-mix(in oklab, var(--color-base-content) 1.5%, transparent);
711
+ font-size: 0.8125rem;
712
+ color: var(--color-muted);
713
+ }
714
+ .ref-foot svg {
715
+ width: 15px;
716
+ height: 15px;
717
+ flex: none;
718
+ color: var(--color-muted);
719
+ }
720
+ .kbd {
721
+ font-family: var(--font-editor);
722
+ font-size: 0.6875rem;
723
+ border: 1px solid var(--cairn-card-border);
724
+ border-radius: 0.25rem;
725
+ padding: 1px 5px;
726
+ background: var(--color-base-100);
727
+ color: var(--color-base-content);
728
+ }
729
+
730
+ /* SECTION 3: get help. A calm text-plus-action row, no decorative icon tile. */
731
+ .help-card {
732
+ display: flex;
733
+ align-items: center;
734
+ gap: 16px;
735
+ padding: 18px 20px;
736
+ }
737
+ .help-card-body {
738
+ flex: 1 1 auto;
739
+ min-width: 0;
740
+ }
741
+ .help-card-sub {
742
+ font-size: 0.8125rem;
743
+ color: var(--color-muted);
744
+ margin: 0;
745
+ line-height: 1.45;
746
+ max-width: 48ch;
747
+ }
748
+ .help-card-sub b {
749
+ color: var(--color-base-content);
750
+ font-weight: 600;
751
+ }
752
+
753
+ /* a quiet bordered control (the get-help hand-off) */
754
+ .btn-quiet {
755
+ display: inline-flex;
756
+ align-items: center;
757
+ justify-content: center;
758
+ gap: 6px;
759
+ height: 36px;
760
+ padding: 0 14px;
761
+ border: 1px solid var(--cairn-card-border);
762
+ border-radius: var(--radius-field);
763
+ background: var(--color-base-100);
764
+ color: var(--color-base-content);
765
+ font: 600 0.8125rem/1 var(--font-body);
766
+ cursor: pointer;
767
+ text-decoration: none;
768
+ white-space: nowrap;
769
+ transition: border-color 120ms ease, color 120ms ease;
770
+ }
771
+ .btn-quiet:hover {
772
+ border-color: color-mix(in oklab, var(--color-primary) 38%, var(--cairn-card-border));
773
+ color: var(--color-primary);
774
+ }
775
+ .btn-quiet svg {
776
+ width: 15px;
777
+ height: 15px;
778
+ }
779
+
780
+ @media (max-width: 900px) {
781
+ .ref-cols {
782
+ grid-template-columns: 1fr;
783
+ }
784
+ .ref-cols > table:first-child {
785
+ border-right: 0;
786
+ border-bottom: 1px solid var(--cairn-card-border);
787
+ }
788
+ }
789
+ @media (max-width: 760px) {
790
+ .cairn-help-content {
791
+ padding: 1.75rem 1.25rem 2.5rem;
792
+ }
793
+ .start-top {
794
+ flex-direction: column;
795
+ }
796
+ .prog {
797
+ text-align: left;
798
+ min-width: 0;
799
+ width: 100%;
800
+ }
801
+ .step {
802
+ flex-wrap: wrap;
803
+ }
804
+ .step-act,
805
+ .step-done-tag,
806
+ .step-open {
807
+ margin-left: 37px;
808
+ }
809
+ .ref-table th[scope='row'] {
810
+ white-space: normal;
811
+ }
812
+ .help-card {
813
+ flex-direction: column;
814
+ align-items: flex-start;
815
+ }
816
+ }
817
+
818
+ @media (prefers-reduced-motion: reduce) {
819
+ .btn-quiet,
820
+ .step-act {
821
+ transition: none;
822
+ }
823
+ }
824
+ </style>