@nervur-org/dock 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (285) hide show
  1. package/GETTING_STARTED.md +128 -0
  2. package/LICENSE +202 -0
  3. package/NOTICE +6 -0
  4. package/README.md +37 -0
  5. package/api/quo-api.md +196 -0
  6. package/api/route.ts +227 -0
  7. package/beings/GLOSSARY.md +118 -0
  8. package/beings/WORLDS.md +567 -0
  9. package/beings/avatar.ts +101 -0
  10. package/beings/carry.ts +159 -0
  11. package/beings/clock.ts +552 -0
  12. package/beings/courier.ts +107 -0
  13. package/beings/desk.ts +128 -0
  14. package/beings/doorbell.ts +129 -0
  15. package/beings/envoy.ts +218 -0
  16. package/beings/index.ts +16 -0
  17. package/beings/join.ts +51 -0
  18. package/beings/link.ts +104 -0
  19. package/beings/look.ts +139 -0
  20. package/beings/porter.ts +43 -0
  21. package/beings/presence.ts +39 -0
  22. package/beings/quo-app-bells.md +280 -0
  23. package/beings/quo-dock.md +1942 -0
  24. package/beings/setup.ts +45 -0
  25. package/beings/side.ts +60 -0
  26. package/beings/user.ts +459 -0
  27. package/beings/way.ts +65 -0
  28. package/cli/bundles.ts +20 -0
  29. package/cli/client.ts +73 -0
  30. package/cli/daemon.ts +581 -0
  31. package/cli/estate/Caddyfile +33 -0
  32. package/cli/estate/quo.service +35 -0
  33. package/cli/estate/systems.quo.plist +44 -0
  34. package/cli/estate.ts +48 -0
  35. package/cli/folder.ts +27 -0
  36. package/cli/oauth.ts +32 -0
  37. package/cli/pilot.ts +38 -0
  38. package/cli/quo-dock.md +1942 -0
  39. package/cli/quo.ts +203 -0
  40. package/cli/stand.ts +160 -0
  41. package/dist/api/route.d.ts +21 -0
  42. package/dist/api/route.js +193 -0
  43. package/dist/beings/avatar.d.ts +32 -0
  44. package/dist/beings/avatar.js +100 -0
  45. package/dist/beings/carry.d.ts +12 -0
  46. package/dist/beings/carry.js +174 -0
  47. package/dist/beings/clock.d.ts +161 -0
  48. package/dist/beings/clock.js +528 -0
  49. package/dist/beings/courier.d.ts +50 -0
  50. package/dist/beings/courier.js +96 -0
  51. package/dist/beings/desk.d.ts +53 -0
  52. package/dist/beings/desk.js +135 -0
  53. package/dist/beings/doorbell.d.ts +78 -0
  54. package/dist/beings/doorbell.js +133 -0
  55. package/dist/beings/envoy.d.ts +54 -0
  56. package/dist/beings/envoy.js +211 -0
  57. package/dist/beings/index.d.ts +14 -0
  58. package/dist/beings/index.js +16 -0
  59. package/dist/beings/join.d.ts +15 -0
  60. package/dist/beings/join.js +42 -0
  61. package/dist/beings/link.d.ts +14 -0
  62. package/dist/beings/link.js +91 -0
  63. package/dist/beings/look.d.ts +30 -0
  64. package/dist/beings/look.js +104 -0
  65. package/dist/beings/porter.d.ts +14 -0
  66. package/dist/beings/porter.js +41 -0
  67. package/dist/beings/presence.d.ts +8 -0
  68. package/dist/beings/presence.js +21 -0
  69. package/dist/beings/setup.d.ts +3 -0
  70. package/dist/beings/setup.js +39 -0
  71. package/dist/beings/side.d.ts +32 -0
  72. package/dist/beings/side.js +37 -0
  73. package/dist/beings/user.d.ts +315 -0
  74. package/dist/beings/user.js +462 -0
  75. package/dist/beings/way.d.ts +19 -0
  76. package/dist/beings/way.js +28 -0
  77. package/dist/cli/bundles.d.ts +5 -0
  78. package/dist/cli/bundles.js +17 -0
  79. package/dist/cli/client.d.ts +15 -0
  80. package/dist/cli/client.js +58 -0
  81. package/dist/cli/daemon.d.ts +50 -0
  82. package/dist/cli/daemon.js +584 -0
  83. package/dist/cli/estate/Caddyfile +33 -0
  84. package/dist/cli/estate/quo.service +35 -0
  85. package/dist/cli/estate/systems.quo.plist +44 -0
  86. package/dist/cli/estate.d.ts +5 -0
  87. package/dist/cli/estate.js +50 -0
  88. package/dist/cli/folder.d.ts +2 -0
  89. package/dist/cli/folder.js +25 -0
  90. package/dist/cli/oauth.d.ts +2 -0
  91. package/dist/cli/oauth.js +32 -0
  92. package/dist/cli/pilot.d.ts +5 -0
  93. package/dist/cli/pilot.js +22 -0
  94. package/dist/cli/quo.d.ts +2 -0
  95. package/dist/cli/quo.js +201 -0
  96. package/dist/cli/stand.d.ts +37 -0
  97. package/dist/cli/stand.js +110 -0
  98. package/dist/dock/agents.d.ts +102 -0
  99. package/dist/dock/agents.js +105 -0
  100. package/dist/dock/apns.d.ts +27 -0
  101. package/dist/dock/apns.js +98 -0
  102. package/dist/dock/console.d.ts +6 -0
  103. package/dist/dock/console.js +20 -0
  104. package/dist/dock/dialers.d.ts +56 -0
  105. package/dist/dock/dialers.js +75 -0
  106. package/dist/dock/faculty.d.ts +24 -0
  107. package/dist/dock/faculty.js +142 -0
  108. package/dist/dock/fcm.d.ts +13 -0
  109. package/dist/dock/fcm.js +77 -0
  110. package/dist/dock/grants.d.ts +41 -0
  111. package/dist/dock/grants.js +99 -0
  112. package/dist/dock/http2.d.ts +4 -0
  113. package/dist/dock/http2.js +68 -0
  114. package/dist/dock/index.d.ts +41 -0
  115. package/dist/dock/index.js +113 -0
  116. package/dist/dock/local.d.ts +13 -0
  117. package/dist/dock/local.js +44 -0
  118. package/dist/dock/location.d.ts +19 -0
  119. package/dist/dock/location.js +11 -0
  120. package/dist/dock/notifications.d.ts +38 -0
  121. package/dist/dock/notifications.js +60 -0
  122. package/dist/dock/push.d.ts +79 -0
  123. package/dist/dock/push.js +132 -0
  124. package/dist/dock/service.d.ts +4 -0
  125. package/dist/dock/service.js +107 -0
  126. package/dist/dock/timer.d.ts +52 -0
  127. package/dist/dock/timer.js +149 -0
  128. package/dist/dock/webpush.d.ts +12 -0
  129. package/dist/dock/webpush.js +144 -0
  130. package/dist/harbor/browser.d.ts +15 -0
  131. package/dist/harbor/browser.js +82 -0
  132. package/dist/harbor/capacitor.d.ts +28 -0
  133. package/dist/harbor/capacitor.js +218 -0
  134. package/dist/harbor/disk.d.ts +27 -0
  135. package/dist/harbor/disk.js +249 -0
  136. package/dist/harbor/edge/alarm.d.ts +10 -0
  137. package/dist/harbor/edge/alarm.js +38 -0
  138. package/dist/harbor/edge/edge.d.ts +54 -0
  139. package/dist/harbor/edge/edge.js +370 -0
  140. package/dist/harbor/edge/exercise.d.ts +7 -0
  141. package/dist/harbor/edge/exercise.js +232 -0
  142. package/dist/harbor/edge/given.d.ts +26 -0
  143. package/dist/harbor/edge/given.js +42 -0
  144. package/dist/harbor/edge/platform.d.ts +39 -0
  145. package/dist/harbor/edge/storage.d.ts +30 -0
  146. package/dist/harbor/edge/storage.js +180 -0
  147. package/dist/harbor/edge/worker.d.ts +17 -0
  148. package/dist/harbor/edge/worker.js +67 -0
  149. package/dist/harbor/files.d.ts +15 -0
  150. package/dist/harbor/files.js +220 -0
  151. package/dist/harbor/http.d.ts +19 -0
  152. package/dist/harbor/http.js +177 -0
  153. package/dist/harbor/idb.d.ts +15 -0
  154. package/dist/harbor/idb.js +0 -0
  155. package/dist/harbor/quo.d.ts +10 -0
  156. package/dist/harbor/quo.js +42 -0
  157. package/dist/harbor/resolve.d.ts +16 -0
  158. package/dist/harbor/resolve.js +17 -0
  159. package/dist/harbor/seal.d.ts +3 -0
  160. package/dist/harbor/seal.js +25 -0
  161. package/dist/harbor/sealed.d.ts +35 -0
  162. package/dist/harbor/sealed.js +162 -0
  163. package/dist/harbor/tauri.d.ts +16 -0
  164. package/dist/harbor/tauri.js +59 -0
  165. package/dist/harbor/ward.d.ts +9 -0
  166. package/dist/harbor/ward.js +15 -0
  167. package/dist/human/app.d.ts +32 -0
  168. package/dist/human/app.js +527 -0
  169. package/dist/human/apps.d.ts +10 -0
  170. package/dist/human/apps.js +29 -0
  171. package/dist/human/dom.d.ts +2 -0
  172. package/dist/human/dom.js +15 -0
  173. package/dist/human/door.d.ts +19 -0
  174. package/dist/human/door.js +92 -0
  175. package/dist/human/guest.d.ts +3 -0
  176. package/dist/human/guest.js +33 -0
  177. package/dist/human/html.d.ts +55 -0
  178. package/dist/human/html.js +451 -0
  179. package/dist/human/local.d.ts +7 -0
  180. package/dist/human/local.js +10 -0
  181. package/dist/human/mark.d.ts +8 -0
  182. package/dist/human/mark.js +47 -0
  183. package/dist/human/move.d.ts +17 -0
  184. package/dist/human/move.js +90 -0
  185. package/dist/human/screen.d.ts +19 -0
  186. package/dist/human/screen.js +119 -0
  187. package/dist/human/style.d.ts +2 -0
  188. package/dist/human/style.js +60 -0
  189. package/dist/human/tab.bundle.txt +4775 -0
  190. package/dist/human/tab.d.ts +15 -0
  191. package/dist/human/tab.js +409 -0
  192. package/dist/human/tree.d.ts +50 -0
  193. package/dist/human/tree.js +157 -0
  194. package/dist/human/wake.d.ts +34 -0
  195. package/dist/human/wake.js +179 -0
  196. package/dist/human/web.d.ts +33 -0
  197. package/dist/human/web.js +184 -0
  198. package/dist/human/worker.bundle.txt +3868 -0
  199. package/dist/human/worker.d.ts +1 -0
  200. package/dist/human/worker.js +81 -0
  201. package/dist/human/worlds.d.ts +24 -0
  202. package/dist/human/worlds.js +99 -0
  203. package/dist/mcp/agent.d.ts +10 -0
  204. package/dist/mcp/agent.js +78 -0
  205. package/dist/mcp/allow.d.ts +20 -0
  206. package/dist/mcp/allow.js +88 -0
  207. package/dist/mcp/http.d.ts +27 -0
  208. package/dist/mcp/http.js +92 -0
  209. package/dist/mcp/oauth.d.ts +91 -0
  210. package/dist/mcp/oauth.js +241 -0
  211. package/dist/mcp/route.d.ts +15 -0
  212. package/dist/mcp/route.js +42 -0
  213. package/dist/mcp/runner.d.ts +45 -0
  214. package/dist/mcp/runner.js +99 -0
  215. package/dist/mcp/server.d.ts +11 -0
  216. package/dist/mcp/server.js +102 -0
  217. package/dock/agents.ts +121 -0
  218. package/dock/apns.ts +138 -0
  219. package/dock/console.ts +23 -0
  220. package/dock/dialers.ts +85 -0
  221. package/dock/faculty.ts +148 -0
  222. package/dock/fcm.ts +103 -0
  223. package/dock/grants.ts +111 -0
  224. package/dock/http2.ts +70 -0
  225. package/dock/index.ts +133 -0
  226. package/dock/local.ts +48 -0
  227. package/dock/location.ts +22 -0
  228. package/dock/notifications.ts +67 -0
  229. package/dock/push.ts +161 -0
  230. package/dock/quo-app-bells.md +280 -0
  231. package/dock/quo-dock.md +1942 -0
  232. package/dock/service.ts +100 -0
  233. package/dock/timer.ts +174 -0
  234. package/dock/webpush.ts +182 -0
  235. package/harbor/browser.ts +97 -0
  236. package/harbor/capacitor.ts +223 -0
  237. package/harbor/disk.ts +237 -0
  238. package/harbor/edge/alarm.ts +48 -0
  239. package/harbor/edge/edge.ts +407 -0
  240. package/harbor/edge/exercise.ts +241 -0
  241. package/harbor/edge/given.ts +106 -0
  242. package/harbor/edge/platform.d.ts +39 -0
  243. package/harbor/edge/storage.ts +179 -0
  244. package/harbor/edge/text.d.ts +15 -0
  245. package/harbor/edge/worker.ts +70 -0
  246. package/harbor/edge/wrangler.toml +30 -0
  247. package/harbor/files.ts +221 -0
  248. package/harbor/http.ts +188 -0
  249. package/harbor/idb.ts +0 -0
  250. package/harbor/quo-harbor.md +850 -0
  251. package/harbor/quo.ts +44 -0
  252. package/harbor/resolve.ts +31 -0
  253. package/harbor/seal.ts +26 -0
  254. package/harbor/sealed.ts +183 -0
  255. package/harbor/tauri.ts +79 -0
  256. package/harbor/ward.ts +28 -0
  257. package/human/app.ts +580 -0
  258. package/human/apps.ts +47 -0
  259. package/human/dom.ts +21 -0
  260. package/human/door.ts +113 -0
  261. package/human/guest.ts +34 -0
  262. package/human/html.ts +490 -0
  263. package/human/local.ts +30 -0
  264. package/human/mark.ts +53 -0
  265. package/human/move.ts +122 -0
  266. package/human/quo-human.md +1042 -0
  267. package/human/screen.ts +136 -0
  268. package/human/style.ts +63 -0
  269. package/human/tab.bundle.txt +4775 -0
  270. package/human/tab.ts +446 -0
  271. package/human/tree.ts +217 -0
  272. package/human/wake.ts +191 -0
  273. package/human/web.ts +259 -0
  274. package/human/worker.bundle.txt +3868 -0
  275. package/human/worker.ts +124 -0
  276. package/human/worlds.ts +127 -0
  277. package/mcp/agent.ts +94 -0
  278. package/mcp/allow.ts +131 -0
  279. package/mcp/http.ts +92 -0
  280. package/mcp/oauth.ts +270 -0
  281. package/mcp/quo-mcp.md +343 -0
  282. package/mcp/route.ts +45 -0
  283. package/mcp/runner.ts +136 -0
  284. package/mcp/server.ts +101 -0
  285. package/package.json +121 -0
@@ -0,0 +1,136 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // The human side: one avatar, one surface. The surface is the least a
3
+ // screen can be: it shows a page and hands back a submitted form, and that
4
+ // is all this side asks of a terrain. A DOM is one surface; a test is
5
+ // another. The side keeps the model, speaks it as a page after every change
6
+ // through `html.ts`, calls the avatar when a form comes back, and re-asks
7
+ // her describe after each call, so a digest that moved is a page that
8
+ // moved. A push is appended and shown the moment it lands.
9
+ import { digest } from '@nervur-org/nervur';
10
+ import type { Blueprint, JsonObject } from '@nervur-org/nervur';
11
+ import { word, type Serving, type Subject } from '../beings/side.ts';
12
+ import { isInvitation } from '@nervur-org/nervur';
13
+ import type { Invitation } from '@nervur-org/nervur';
14
+ import { page, values, hintFor, mine, asks, standing, stands, type Model, type Raw } from './html.ts';
15
+ import { sanitiseTree, answersIn } from './tree.ts';
16
+ import { groups, sanitise } from '../beings/look.ts';
17
+ import { isSilence, isWord } from '@nervur-org/nervur';
18
+
19
+ export type Surface = {
20
+ show(html: string): void;
21
+ // The surface calls this when a form is submitted: the ask's name and
22
+ // the fields as strings. Set once by the side.
23
+ onSubmit: ((ask: string, raw: Raw) => void) | undefined;
24
+ };
25
+
26
+ // `after` runs after every ask the side makes, a submitted form, her
27
+ // describe, her look and the read-only asks run on open alike, as it does
28
+ // for the model side: every ask rotates her keys, and a harbor that must
29
+ // write what the ward changed hooks it. A side that saved only after a form
30
+ // would bring her back from a reload with a stale count, and the far door
31
+ // would refuse her. `admit` is what to do
32
+ // with an answer that is an invitation: a guest at a world's door is let in
33
+ // by it, and a side with no `admit` shows it as any answer. `focus` is one
34
+ // standing she carries shown as the whole page, the page at
35
+ // `web./<ward>/<being>`, and `at` the world's page address the sections and a
36
+ // focused page link to.
37
+ // `ended` is called when her describe says the relation is over, so a shell
38
+ // can offer the one act left, leaving. It is told and never obeyed: the
39
+ // shell decides what to put in front of the human, and nothing here drops a
40
+ // ward.
41
+ export type Options = { after?: () => Promise<void>; notice?: string; admit?: (invitation: Invitation) => Promise<void>; focus?: string; at?: string; ended?: () => Promise<void> };
42
+ export async function screenSide(avatar: Subject, surface: Surface, options: Options = {}): Promise<Serving & { model: Model; refresh(): Promise<void> }> {
43
+ const after = options.after ?? (async () => {});
44
+ const notice = options.notice ?? '';
45
+ const model: Model = { blueprint: null, look: {}, tree: null, pages: {}, notice, standing: 'in', answers: {}, pushes: [], ...(options.focus !== undefined ? { focus: options.focus } : {}), ...(options.at !== undefined ? { at: options.at } : {}) };
46
+ let seen: string | null = null;
47
+ const show = () => surface.show(page(model));
48
+
49
+ // Her describe, again: the page follows the digest.
50
+ const refresh = async () => {
51
+ const bp = await avatar.tools();
52
+ if ('error' in bp && !('asks' in bp)) {
53
+ // the last page she gave stays, with the answers under it, and the
54
+ // notice says where the human stands now: her relation ended, the
55
+ // world away for the moment, or her own error, told apart because
56
+ // only one of the three is over
57
+ model.standing = standing(bp.error);
58
+ model.notice = stands(bp.error);
59
+ if (model.standing === 'ended') await options.ended?.();
60
+ } else {
61
+ model.standing = 'in';
62
+ const d = await digest(bp as Blueprint);
63
+ const moved = d !== seen;
64
+ if (moved) {
65
+ seen = d;
66
+ model.blueprint = bp as Blueprint;
67
+ for (const k of Object.keys(model.answers)) if (!(bp as Blueprint).asks.some((a) => a.name === k)) delete model.answers[k];
68
+ // her look, once per digest: how she wants her page painted, and what each ask is
69
+ if ((bp as Blueprint).asks.some((a) => a.name === 'look')) {
70
+ const l = await avatar.call('look');
71
+ model.look = isSilence(l) || isWord(l) ? {} : sanitise(l);
72
+ } else model.look = {};
73
+ }
74
+ // her page, after every ask: a tree of values from what she holds now, or nothing and her asks
75
+ // are forms. A cell moved is a page moved, and her describe need not have; so the answers the
76
+ // page shows are run again with it, and the page never stands more than one ask behind her
77
+ const trees = () => [model.tree ? answersIn(model.tree) : [], ...Object.entries(model.pages).map(([id, t]) => (t ? answersIn(t).map((n) => `${id}-${n}`) : []))].flat();
78
+ const shows = new Set(trees());
79
+ const tree = async (name: string) => {
80
+ const t = await avatar.call(name);
81
+ return isSilence(t) || isWord(t) ? null : sanitiseTree(t);
82
+ };
83
+ model.tree = (bp as Blueprint).asks.some((a) => a.name === 'page') ? await tree('page') : null;
84
+ // and the page of every standing she carries, the same way, painted in that standing's section;
85
+ // a name a carried page uses is one of that standing's asks, carried, and nothing else
86
+ model.pages = {};
87
+ for (const [id, g] of Object.entries(groups(bp as Blueprint))) if (typeof g.page === 'string' && (bp as Blueprint).asks.some((a) => a.name === g.page)) model.pages[id] = await tree(g.page);
88
+ const wanted = new Set(trees());
89
+ for (const n of shows) if (wanted.has(n)) delete model.answers[n];
90
+ // a read-only ask that needs nothing typed is run on her behalf once per digest, and one her page
91
+ // shows the answer of after every ask, so the page opens and stays with what it shows
92
+ for (const a of (bp as Blueprint).asks) {
93
+ // What the side fills for itself is not something a human has to
94
+ // type, so an ask whose only required argument is the moment has
95
+ // nothing left to ask and runs like one with no arguments at all.
96
+ const needs = asks(a).length > 0;
97
+ const run = wanted.has(a.name) || (moved && hintFor(bp as Blueprint, model.look, a.name).readOnly);
98
+ if (run && !needs && !(a.name in model.answers)) model.answers[a.name] = word(await avatar.call(a.name, mine(a)));
99
+ }
100
+ }
101
+ await after();
102
+ show();
103
+ };
104
+
105
+ surface.onSubmit = (name, raw) => void submit(name, raw);
106
+ const submit = async (name: string, raw: Raw) => {
107
+ const ask = model.blueprint?.asks.find((a) => a.name === name);
108
+ if (!ask) return;
109
+ const v = values(ask, raw);
110
+ if ('error' in v) {
111
+ model.answers[name] = { word: 'error', value: { error: v.error } };
112
+ return show();
113
+ }
114
+ const out = await avatar.call(name, v.args);
115
+ await after();
116
+ if (options.admit && isInvitation(out)) return options.admit(out);
117
+ model.answers[name] = word(out);
118
+ await refresh();
119
+ };
120
+
121
+ const ear = (object: JsonObject) => {
122
+ model.pushes.push(object);
123
+ show();
124
+ };
125
+ avatar.ears.add(ear);
126
+
127
+ await refresh();
128
+ return {
129
+ model,
130
+ refresh,
131
+ close: async () => {
132
+ avatar.ears.delete(ear);
133
+ surface.onSubmit = undefined;
134
+ },
135
+ };
136
+ }
package/human/style.ts ADDED
@@ -0,0 +1,63 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // The stylesheet: the kit, and then what the screen alone has.
3
+ //
4
+ // One stylesheet for every screen there is, whatever carries it: the web
5
+ // route serves it beside the tab's bundle, and the desk app's window
6
+ // carries it in its own. A screen that looked like another product on
7
+ // another terrain would be two designs to keep and one of them always
8
+ // behind. It is one string and not four files because a screen builds its
9
+ // own page and has nowhere to put a link.
10
+ //
11
+ // The kit brings the tokens, its own light and dark face, the reset, the
12
+ // baseline, the bare controls and every piece a page is made of. The
13
+ // painter emits those pieces and nothing else, so what follows is small:
14
+ // the page's one column, and the few things the shells alone have, the
15
+ // door, a local being's section, moving a world, the daemon's state line.
16
+ // Nothing below mints a colour or a size; every one is a slot or a scale,
17
+ // so a face swapped for another swaps the screen with it. A far being's
18
+ // look sets the kit's slots on her own section, and the kit does the rest.
19
+ import { CSS as KIT, TOKENS, BASE, COMPONENTS } from '@nervur-org/ui/css';
20
+
21
+ const SCREEN = [
22
+ // One column that is a phone first and a desk after: the same page, more
23
+ // air. The insets are the phone's: an app fills the screen, corners and
24
+ // camera and all, so the first line of the page would otherwise sit under
25
+ // the clock. `env()` is zero everywhere else, so a tab and a window are
26
+ // laid out by the gutter alone.
27
+ 'body{max-width:var(--nv-page-w-md);margin-inline:auto;padding-inline:calc(var(--nv-page-gutter) + env(safe-area-inset-left)) calc(var(--nv-page-gutter) + env(safe-area-inset-right));padding-block:env(safe-area-inset-top) calc(var(--nv-space-8) + env(safe-area-inset-bottom))}',
28
+ 'main{display:flex;flex-direction:column;gap:var(--nv-space-4)}',
29
+ // a subsection holding a form and the answer under it, and the sections
30
+ // of one being's page after another
31
+ 'main>.nv-stack>section+section,main>.nv-stack>section+.nv-standing,main>.nv-stack>.nv-standing+section{margin-block-start:var(--nv-space-3)}',
32
+ // a far being's logo beside her name, and the way to her own page
33
+ 'img.logo{height:var(--nv-icon-lg)}a.open,a.back{text-decoration:none;font-weight:var(--nv-weight-medium)}a.back::before{content:"\\2190 "}',
34
+ // A place the side vouches for reads as a place to go. One it will not
35
+ // vouch for reads as what it is, an address the human may copy and weigh,
36
+ // and it is deliberately not underlined and not the accent: it must never
37
+ // look like something the page is willing to stand behind. A link that
38
+ // leaves the world wears the origin it goes to, out of the anchor's own
39
+ // data, so a human reads where she is going on the page rather than in a
40
+ // status bar she may never look at.
41
+ 'a.link.out::after{content:" \\2197 " attr(data-origin);font-size:var(--nv-text-sm);color:var(--nv-color-fg-muted)}span.link.away{border:1px dashed var(--nv-color-border-strong)}',
42
+ // a being of the world running in the tab: her own section under the far page
43
+ 'section.local{border-block-start:1px solid var(--nv-color-border);margin-block:var(--nv-space-5) 0;padding-block-start:var(--nv-space-3)}',
44
+ // moving a world to another device, and leaving one: quiet, at the foot
45
+ // of the page, and the offer wrapping rather than running off the side,
46
+ // since it is one long word
47
+ '.move,section.held{display:flex;flex-direction:column;gap:var(--nv-space-2);align-items:flex-start;border-block-start:1px solid var(--nv-color-border);margin-block:var(--nv-space-7) 0;padding-block-start:var(--nv-space-3);font-size:var(--nv-text-sm);color:var(--nv-color-fg-muted)}.move .invitation,section.held .invitation{font-family:var(--nv-font-mono);font-size:var(--nv-text-xs);overflow-wrap:anywhere}',
48
+ 'section.held .worlds{display:flex;flex-wrap:wrap;gap:var(--nv-space-2)}',
49
+ // a foot the shell hid stays hidden: a class that lays it out would otherwise beat the attribute
50
+ '.move[hidden],section.held[hidden]{display:none}',
51
+ // the door page: one thing on air, vertically centred in the window
52
+ 'main[data-door]{min-height:70vh;justify-content:center}main[data-door] .nv-picture{width:var(--nv-space-7);height:var(--nv-space-7);color:var(--nv-color-accent)}',
53
+ // the desk window: the state of the daemon behind the page, a line, and nothing when all is well
54
+ 'p.state:empty{display:none}',
55
+ ].join('');
56
+
57
+ export const CSS = `${KIT}\n${SCREEN}`;
58
+
59
+ // The same screen for a world that wears a design of its own: the kit
60
+ // without its own face, since the kit's contract says a surface loads the
61
+ // default face or a design's and never both, and the design's stylesheet
62
+ // is linked after it by the route that serves it.
63
+ export const BARE = `${TOKENS}\n${BASE}\n${COMPONENTS}\n${SCREEN}`;