@graview/primitives 0.1.9 → 0.1.12

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 (91) hide show
  1. package/README.md +12 -5
  2. package/dist/declared-lens-doors.d.ts +18 -0
  3. package/dist/declared-lens-doors.d.ts.map +1 -0
  4. package/dist/declared-lens-doors.js +73 -0
  5. package/dist/declared-lens-doors.js.map +1 -0
  6. package/dist/declared-lenses.d.ts +6 -0
  7. package/dist/declared-lenses.d.ts.map +1 -0
  8. package/dist/declared-lenses.js +86 -0
  9. package/dist/declared-lenses.js.map +1 -0
  10. package/dist/declared-views.d.ts +11 -0
  11. package/dist/declared-views.d.ts.map +1 -0
  12. package/dist/declared-views.js +15 -0
  13. package/dist/declared-views.js.map +1 -0
  14. package/dist/default-views.d.ts.map +1 -1
  15. package/dist/default-views.js +5 -1
  16. package/dist/default-views.js.map +1 -1
  17. package/dist/figure.d.ts.map +1 -1
  18. package/dist/figure.js +2 -1
  19. package/dist/figure.js.map +1 -1
  20. package/dist/frame.d.ts +4 -3
  21. package/dist/frame.d.ts.map +1 -1
  22. package/dist/frame.js +5 -3
  23. package/dist/frame.js.map +1 -1
  24. package/dist/home-landing.d.ts +18 -0
  25. package/dist/home-landing.d.ts.map +1 -0
  26. package/dist/home-landing.js +59 -0
  27. package/dist/home-landing.js.map +1 -0
  28. package/dist/home-view.d.ts +4 -0
  29. package/dist/home-view.d.ts.map +1 -0
  30. package/dist/home-view.js +19 -0
  31. package/dist/home-view.js.map +1 -0
  32. package/dist/index.d.ts +7 -2
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +7 -2
  35. package/dist/index.js.map +1 -1
  36. package/dist/lens/columns.d.ts +40 -0
  37. package/dist/lens/columns.d.ts.map +1 -0
  38. package/dist/lens/columns.js +197 -0
  39. package/dist/lens/columns.js.map +1 -0
  40. package/dist/notices.js +1 -1
  41. package/dist/notices.js.map +1 -1
  42. package/dist/pages.d.ts +2 -0
  43. package/dist/pages.d.ts.map +1 -1
  44. package/dist/pages.js +3 -0
  45. package/dist/pages.js.map +1 -1
  46. package/dist/primitives/index.d.ts +2 -31
  47. package/dist/primitives/index.d.ts.map +1 -1
  48. package/dist/primitives/index.js +3 -42
  49. package/dist/primitives/index.js.map +1 -1
  50. package/dist/primitives/measure.d.ts +32 -0
  51. package/dist/primitives/measure.d.ts.map +1 -0
  52. package/dist/primitives/measure.js +51 -0
  53. package/dist/primitives/measure.js.map +1 -0
  54. package/dist/scene-css.d.ts +13 -0
  55. package/dist/scene-css.d.ts.map +1 -0
  56. package/dist/scene-css.js +735 -0
  57. package/dist/scene-css.js.map +1 -0
  58. package/dist/scene.d.ts +22 -0
  59. package/dist/scene.d.ts.map +1 -0
  60. package/dist/scene.js +22 -0
  61. package/dist/scene.js.map +1 -0
  62. package/dist/seeding.d.ts +0 -8
  63. package/dist/seeding.d.ts.map +1 -1
  64. package/dist/seeding.js +50 -16
  65. package/dist/seeding.js.map +1 -1
  66. package/dist/shell.d.ts.map +1 -1
  67. package/dist/shell.js +2 -1
  68. package/dist/shell.js.map +1 -1
  69. package/dist/spec-css.d.ts.map +1 -1
  70. package/dist/spec-css.js +24 -0
  71. package/dist/spec-css.js.map +1 -1
  72. package/dist/spec-views.d.ts +38 -58
  73. package/dist/spec-views.d.ts.map +1 -1
  74. package/dist/spec-views.js +134 -195
  75. package/dist/spec-views.js.map +1 -1
  76. package/dist/theme.d.ts +3 -1
  77. package/dist/theme.d.ts.map +1 -1
  78. package/dist/theme.js +13 -706
  79. package/dist/theme.js.map +1 -1
  80. package/dist/workbench/activity.d.ts.map +1 -1
  81. package/dist/workbench/activity.js +3 -3
  82. package/dist/workbench/activity.js.map +1 -1
  83. package/dist/workbench/back-out.d.ts +2 -16
  84. package/dist/workbench/back-out.d.ts.map +1 -1
  85. package/dist/workbench/back-out.js +3 -22
  86. package/dist/workbench/back-out.js.map +1 -1
  87. package/dist/workbench/descent.d.ts +17 -0
  88. package/dist/workbench/descent.d.ts.map +1 -0
  89. package/dist/workbench/descent.js +24 -0
  90. package/dist/workbench/descent.js.map +1 -0
  91. package/package.json +10 -6
@@ -0,0 +1,735 @@
1
+ import { isoShade, layer, SCENE_LAYERS } from "@graview/core";
2
+ import { baseSheet, GRAVIEW_BRAND, withinTheBox } from "./theme.js";
3
+ /*
4
+ * THE SCENE'S OWN RULES (FR-104).
5
+ *
6
+ * The districts from altitude, their plots, the village and the roads, the
7
+ * billboards and their rails, the bands and what they could not hold, the
8
+ * kind's tag, the zoom: everything here names an element only the scene
9
+ * draws. They were a third of the one theme sheet, and the sheet is drawn
10
+ * by the frame of every face, so a page that opened on the pages face —
11
+ * a phone, a chat's widget, Graview Cloud's hosted page — carried them up
12
+ * front and parsed them into its <style>. They are the scene face's now:
13
+ * it draws them beside the frame's sheet, after it, which is where they
14
+ * stand in `themeCss`. The rules are where theme.ts had them, in its
15
+ * order, and each still carries its note.
16
+ */
17
+ const face = (f) => `${f.saturation}% ${f.lightness}%`;
18
+ const wash = (f) => `${face(f)} / ${f.alpha}`;
19
+ function sceneSheet(scheme) {
20
+ const iso = isoShade(scheme);
21
+ return `
22
+ [data-graview-altitude] .graview-kind-card {
23
+ overflow: visible;
24
+ }
25
+ ${ /* From altitude a district is a village on its plot, not a card: hovering
26
+ it must not raise a white panel over the buildings. The lift stays in
27
+ the stack, where the card is a card. */""}
28
+ [data-graview-altitude] .graview-kind-card:hover,
29
+ [data-graview-altitude] .graview-kind-card:focus-within {
30
+ transform: none;
31
+ box-shadow: none;
32
+ background: transparent;
33
+ }
34
+
35
+ ${ /* THE GROUND UNDER A DISTRICT: its plot, drawn. Four lattice corners in
36
+ the kind's hue, a kerb, a cast shadow toward the light — the arithmetic
37
+ the layout already did, made visible, so a district stands on land
38
+ rather than floating on a hatch. Fades in with the altitude number the
39
+ lattice fades in with; a hand-placed district's kerb is dashed, which is
40
+ the pinned mark on the ground rather than a box over the drawing. */""}
41
+ .graview-plots {
42
+ z-index: ${SCENE_LAYERS.plots};
43
+ opacity: var(--graview-altitude);
44
+ transition: opacity 640ms cubic-bezier(0.33, 0, 0.2, 1);
45
+ }
46
+ .graview-plot-tile {
47
+ fill: hsl(var(--graview-hue, 200) ${wash(iso.plot)});
48
+ stroke: hsl(var(--graview-hue, 200) ${wash(iso.plotEdge)});
49
+ stroke-width: 1;
50
+ stroke-linejoin: round;
51
+ pointer-events: auto;
52
+ cursor: pointer;
53
+ filter: drop-shadow(${scheme === "light" ? "5px 4px 6px rgba(20,30,32,0.14)" : "6px 5px 8px rgba(0,0,0,0.4)"});
54
+ transition: fill 170ms ease;
55
+ }
56
+ .graview-plot-tile:hover {
57
+ fill: hsl(var(--graview-hue, 200) 45% ${scheme === "light" ? "58%" : "48%"} / ${scheme === "light" ? "0.2" : "0.3"});
58
+ }
59
+ .graview-plot[data-graview-pinned] .graview-plot-tile {
60
+ stroke-dasharray: 4 3;
61
+ }
62
+ ${ /* THE VILLAGE on the tile: one small iso building per member in the kind's
63
+ own faces (the same roof and walls the block had), a flagged member's roof
64
+ in the warning colour, a selected member's building lit in the accent.
65
+ Architecture, not controls: the tile under them takes the click. */""}
66
+ .graview-village { pointer-events: none; }
67
+ .graview-building polygon { stroke-width: 0.8; }
68
+ .graview-building[data-graview-flagged] .graview-iso-roof { fill: var(--graview-warn); stroke: var(--graview-warn); }
69
+ .graview-building[data-graview-selected] polygon { stroke: var(--graview-accent); stroke-width: 1.4; }
70
+ .graview-building[data-graview-selected] .graview-iso-roof { fill: color-mix(in oklab, var(--graview-accent) 45%, var(--graview-panel)); }
71
+ .graview-village-rest {
72
+ font-size: 0.75rem;
73
+ letter-spacing: 0.06em;
74
+ fill: var(--graview-ink-muted);
75
+ }
76
+ ${ /* THE ROADS between plots: the lattice's own two legs from kerb to kerb, a
77
+ bed between two edges in the ground's ink. Under the tiles and the
78
+ buildings, over the fields. A road the legend is asking about comes up
79
+ in the accent. */""}
80
+ .graview-road-edge {
81
+ fill: none;
82
+ stroke: var(--graview-ink);
83
+ stroke-opacity: ${scheme === "light" ? "0.28" : "0.4"};
84
+ stroke-width: 7;
85
+ stroke-linejoin: round;
86
+ stroke-linecap: round;
87
+ }
88
+ .graview-road-bed {
89
+ fill: none;
90
+ stroke: var(--graview-ground);
91
+ stroke-width: 5;
92
+ stroke-linejoin: round;
93
+ stroke-linecap: round;
94
+ }
95
+ .graview-road[data-graview-lit] .graview-road-edge {
96
+ stroke: var(--graview-accent);
97
+ stroke-opacity: 0.9;
98
+ }
99
+ ${ /* FIELDS. From altitude the ground darkens a shade toward the near edge and
100
+ fades to the page at the horizon, so the lattice is land with a distance
101
+ rather than paper with a pattern. */""}
102
+ .graview-ground[data-graview-altitude] {
103
+ background:
104
+ linear-gradient(to top, color-mix(in oklab, var(--graview-ground) ${scheme === "light" ? "93%" : "88%"}, var(--graview-ink)) 0%, var(--graview-ground) 78%),
105
+ var(--graview-ground);
106
+ }
107
+
108
+ ${ /* THE OPEN CHEVRON APPEARS WHEN REACHED FOR. Drawn on every plate at
109
+ altitude it was noise times the number of districts; it shows on hover,
110
+ on keyboard focus, and while the district is open — and stays a real
111
+ button in between, so Tab still finds it and Enter still opens. */""}
112
+ [data-graview-altitude] .graview-kind-open {
113
+ opacity: 0.5;
114
+ transition: opacity 150ms ease;
115
+ }
116
+ ${ /* Quiet: the chevron alone until reached for. Never opacity zero — a
117
+ button nobody can see is a button a driven browser cannot press either,
118
+ and Tab must land on something that looks like something. */""}
119
+ [data-graview-altitude] .graview-kind-open-word {
120
+ display: none;
121
+ }
122
+ [data-graview-altitude] .graview-kind-card:hover .graview-kind-open,
123
+ [data-graview-altitude] .graview-kind-card:focus-within .graview-kind-open,
124
+ [data-graview-altitude] .graview-kind-open[aria-expanded="true"] {
125
+ opacity: 1;
126
+ }
127
+ [data-graview-altitude] .graview-kind-card:hover .graview-kind-open-word,
128
+ [data-graview-altitude] .graview-kind-card:focus-within .graview-kind-open-word,
129
+ [data-graview-altitude] .graview-kind-open[aria-expanded="true"] .graview-kind-open-word {
130
+ display: inline;
131
+ }
132
+ [data-graview-altitude] .graview-kind-open {
133
+ display: inline-flex;
134
+ align-items: center;
135
+ justify-content: center;
136
+ flex: 0 0 auto;
137
+ ${ /* A FINGERTIP, AND THE READER'S FINGERTIP IF IT IS BIGGER. 24px is the
138
+ floor audit-ui holds every control to; 1.5rem is the same 24 at the
139
+ default text size and grows with a reader who asked for more, so the
140
+ control never drifts under the words it sits beside. A max() rather than
141
+ either one alone: rem alone drops below the fingertip at a smaller
142
+ setting, px alone ignores the setting altogether. */""}
143
+ min-height: max(1.5rem, 24px);
144
+ padding: 1px 9px;
145
+ margin: -3px 0;
146
+ border-radius: 999px;
147
+ border: 1px solid var(--graview-edge);
148
+ background: var(--graview-panel);
149
+ box-shadow: none;
150
+ color: var(--graview-ink-muted);
151
+ cursor: pointer;
152
+ ${ /* IN REM, LIKE EVERY OTHER SIZE HERE. At 10px this control's words were
153
+ the one piece of text in the framework that ignored the reader's text
154
+ size completely: set to Largest, every name on the screen doubled and
155
+ "open" stayed ten pixels tall. A size a person chose and a control that
156
+ will not take it is the accessibility setting failing on its own
157
+ surface. */""}
158
+ font-size: 0.75rem;
159
+ letter-spacing: 0.08em;
160
+ text-transform: uppercase;
161
+ line-height: 1;
162
+ white-space: nowrap;
163
+ }
164
+ [data-graview-altitude] .graview-kind-open:hover {
165
+ color: var(--graview-accent);
166
+ border-color: var(--graview-accent-dim);
167
+ }
168
+ ${ /* THE BILLBOARD'S FULL-SCREEN CONTROL: the one way down from a picture. */""}
169
+ ${ /* THE RAIL A BILLBOARD IS MOVED BY: a title bar, in the board's own frame
170
+ ink, along its top edge. Positioned like the full-screen control beside
171
+ it — the host wraps its children, so the rail is a grandchild of the
172
+ screen box and a child selector never reaches it. Wide enough to be an
173
+ easy target, short enough that the picture underneath is still what you
174
+ see, and present only at altitude, because only up there is the board
175
+ standing on a plot it could be moved around. */""}
176
+ .graview-screen-grip {
177
+ display: none;
178
+ }
179
+ [data-graview-altitude] [data-graview-screen] .graview-screen-grip {
180
+ display: flex;
181
+ align-items: center;
182
+ gap: 8px;
183
+ position: absolute;
184
+ left: 0;
185
+ right: 0;
186
+ top: 0;
187
+ ${ /* Drawn height, not CSS height: a district's plane is scaled down at
188
+ altitude, and 14 here reached the screen as an eight-pixel strip that
189
+ took three attempts to catch. */""}
190
+ height: 32px;
191
+ padding: 0 6px 0 12px;
192
+ box-sizing: border-box;
193
+ cursor: grab;
194
+ ${ /* A title bar in the panel's own colours, not a grey strip: the board is
195
+ a window onto the picture, and its bar reads as the window's. */""}
196
+ background: var(--graview-panel-muted);
197
+ border-bottom: 1px solid var(--graview-edge);
198
+ z-index: ${SCENE_LAYERS.lines};
199
+ }
200
+ [data-graview-altitude] [data-graview-screen] .graview-screen-title {
201
+ flex: 1 1 auto;
202
+ min-width: 0;
203
+ overflow: hidden;
204
+ text-overflow: ellipsis;
205
+ white-space: nowrap;
206
+ font-size: 0.8125rem;
207
+ font-weight: 600;
208
+ color: var(--graview-ink);
209
+ }
210
+ [data-graview-altitude] [data-graview-screen] .graview-screen-grip:active {
211
+ cursor: grabbing;
212
+ }
213
+ .graview-screen-fullscreen {
214
+ flex: 0 0 auto;
215
+ min-height: max(1.5rem, 24px);
216
+ padding: 1px 10px;
217
+ border-radius: 999px;
218
+ border: 1px solid var(--graview-edge);
219
+ background: var(--graview-panel);
220
+ color: var(--graview-accent);
221
+ font-size: 0.8125rem;
222
+ font-weight: 600;
223
+ white-space: nowrap;
224
+ cursor: pointer;
225
+ box-shadow: none;
226
+ }
227
+ .graview-screen-fullscreen:hover:not(:disabled) {
228
+ border-color: var(--graview-accent);
229
+ }
230
+ [data-graview-altitude] .graview-kind-members > [data-graview-pick] {
231
+ width: 100%;
232
+ box-sizing: border-box;
233
+ justify-content: flex-start;
234
+ max-width: none;
235
+ }
236
+ ${ /* An OPENED district is a PANEL, not a pill with a list stuffed in it:
237
+ name and count share the header line, the roster sits under a hairline,
238
+ and the block behind fades — the plate IS the district while it is
239
+ open, so no roof pokes out above the roster. */""}
240
+ [data-graview-altitude] .graview-kind-face[data-graview-opened] {
241
+ ${ /* A header that WRAPS rather than a grid that squeezes: the name's column
242
+ was minmax(0, 1fr) beside the count's auto, so "VEHICLES" beside
243
+ "291 · +29 past · close" got 25 pixels and the count was drawn over it. */""}
244
+ display: flex !important;
245
+ flex-wrap: wrap;
246
+ justify-content: flex-start !important;
247
+ align-items: baseline !important;
248
+ column-gap: 10px;
249
+ row-gap: 2px;
250
+ border-radius: 12px !important;
251
+ padding: 10px 12px 11px !important;
252
+ width: 236px;
253
+ max-width: 236px;
254
+ box-shadow: var(--graview-lift-high) !important;
255
+ }
256
+ [data-graview-altitude] .graview-kind-face[data-graview-opened] .graview-kind-members {
257
+ flex: 1 0 100%;
258
+ margin-top: 8px;
259
+ padding-top: 8px;
260
+ border-top: 1px solid var(--graview-edge);
261
+ }
262
+ [data-graview-altitude] .graview-kind-block[data-graview-opened] {
263
+ opacity: calc(var(--graview-altitude) * 0.22);
264
+ }
265
+
266
+ ${ /* WHAT KIND OF THING THIS IS, astride the focus panel's top-right edge —
267
+ the kind's dot and its name, the same thread the chips and the legend
268
+ carry. Scene chrome, so no view has to remember to say it. */""}
269
+ .graview-kind-tag {
270
+ position: absolute;
271
+ top: -9px;
272
+ right: 14px;
273
+ z-index: ${SCENE_LAYERS.tag};
274
+ display: var(--graview-kit-tags, inline-flex);
275
+ align-items: center;
276
+ gap: 5px;
277
+ padding: 2px 8px;
278
+ border-radius: 999px;
279
+ ${ /* The kind's own hue on the border and the words, so the tag and the
280
+ district it belongs to read as one thread. */""}
281
+ border: 1px solid hsl(var(--graview-hue, 200) 45% var(--graview-tint-lightness) / 0.55);
282
+ color: hsl(var(--graview-hue, 200) 45% calc(var(--graview-tint-lightness) + ${scheme === "light" ? "-32%" : "28%"}));
283
+ background: var(--graview-float);
284
+ box-shadow: var(--graview-lift-low);
285
+ font-size: 0.6875rem;
286
+ letter-spacing: 0.14em;
287
+ text-transform: uppercase;
288
+ color: var(--graview-ink-faint);
289
+ pointer-events: none;
290
+ }
291
+
292
+ ${ /* A LINE UNDER THE POINTER says it will take the press: the invisible hit
293
+ run ghosts in, so editability is discoverable by hovering the relation
294
+ itself rather than by rumor. */""}
295
+ .graview-edge-hit:hover {
296
+ stroke: var(--graview-accent);
297
+ opacity: 0.3;
298
+ }
299
+
300
+ ${ /* THE DISTRICTS THE ROW COULD NOT HOLD.
301
+ Not a district: no figure, no count, no tint of its own. A card that is
302
+ one control — how many more, and a press — and, open, a panel above the
303
+ row naming every district with what it holds. Solid rather than dashed
304
+ and faded: a dashed, translucent card read as a placeholder, and the only
305
+ way to five districts should not look like something that failed to load. */""}
306
+ ${ /* A RELATION THE BAND COULD NOT HOLD: a group with its count and first names,
307
+ or the door to the rest. A card like the others, never the kind's lens small. */""}
308
+ .graview-band-group {
309
+ display: grid;
310
+ align-content: center;
311
+ gap: 2px;
312
+ height: 100%;
313
+ ${ /* A card you press, held to the floor every pressable piece of chrome keeps. */""}
314
+ min-height: max(1.75rem, 28px);
315
+ box-sizing: border-box;
316
+ padding: 6px 10px;
317
+ border-radius: var(--graview-radius-sm, 8px);
318
+ border: 1px solid var(--graview-edge);
319
+ background: var(--graview-panel);
320
+ color: var(--graview-ink);
321
+ overflow: hidden;
322
+ cursor: pointer;
323
+ }
324
+ .graview-band-group[data-graview-band="picture"] {
325
+ border-style: dashed;
326
+ }
327
+ .graview-band-group[data-graview-emphasis="lit"] {
328
+ border-color: var(--graview-accent);
329
+ }
330
+ .graview-band-group[data-graview-emphasis="dimmed"] {
331
+ opacity: 0.5;
332
+ }
333
+ .graview-band-group-head {
334
+ display: flex;
335
+ align-items: baseline;
336
+ gap: 6px;
337
+ min-width: 0;
338
+ }
339
+ .graview-band-group-name {
340
+ flex: 1;
341
+ min-width: 0;
342
+ font-weight: 600;
343
+ font-size: 0.9375rem;
344
+ line-height: 1.25;
345
+ white-space: nowrap;
346
+ overflow: hidden;
347
+ text-overflow: ellipsis;
348
+ }
349
+ .graview-band-group-open {
350
+ font-size: 0.75rem;
351
+ color: var(--graview-accent);
352
+ }
353
+ .graview-band-group-names {
354
+ font-size: 0.8125rem;
355
+ line-height: 1.3;
356
+ color: var(--graview-ink-muted);
357
+ white-space: nowrap;
358
+ overflow: hidden;
359
+ text-overflow: ellipsis;
360
+ }
361
+ .graview-band-group-count {
362
+ color: var(--graview-ink);
363
+ font-variant-numeric: tabular-nums;
364
+ }
365
+ .graview-beyond {
366
+ position: relative;
367
+ height: 100%;
368
+ box-sizing: border-box;
369
+ border-radius: var(--graview-radius-sm, 8px);
370
+ border: 1px solid var(--graview-edge);
371
+ background: var(--graview-panel);
372
+ }
373
+ .graview-beyond-more {
374
+ display: flex;
375
+ align-items: center;
376
+ gap: 6px;
377
+ width: 100%;
378
+ height: 100%;
379
+ min-height: max(1.75rem, 28px);
380
+ padding: var(--graview-pad-sm, 8px);
381
+ box-sizing: border-box;
382
+ border: none;
383
+ border-radius: inherit;
384
+ background: none;
385
+ color: var(--graview-ink-muted);
386
+ cursor: pointer;
387
+ font: inherit;
388
+ font-size: 0.875rem;
389
+ text-align: left;
390
+ }
391
+ .graview-beyond-more:hover,
392
+ .graview-beyond[data-graview-beyond-open] .graview-beyond-more {
393
+ color: var(--graview-accent);
394
+ background: var(--graview-wash);
395
+ }
396
+ .graview-beyond-count {
397
+ font-family: var(--graview-font-display);
398
+ font-size: 1.1875rem;
399
+ line-height: 1;
400
+ color: inherit;
401
+ }
402
+ .graview-beyond-word {
403
+ font-size: 0.75rem;
404
+ letter-spacing: 0.08em;
405
+ text-transform: uppercase;
406
+ }
407
+ .graview-beyond-chevron {
408
+ margin-left: auto;
409
+ font-size: 0.8125rem;
410
+ }
411
+ ${ /* The panel stands above the card, inside the scene, and never clips: the
412
+ card's box is a district's height, which holds a count and not a list. */""}
413
+ .graview-beyond-list {
414
+ position: absolute;
415
+ left: 0;
416
+ bottom: calc(100% + 6px);
417
+ ${ /* On the ground, over every plane — the focused card on plane zero
418
+ painted over a panel drawn on plane two, and a menu under a card is
419
+ no menu. Above the zoom control too, which is the only other thing
420
+ that stands on the ground. */""}
421
+ z-index: ${layer("popover")};
422
+ margin: 0;
423
+ padding: 6px;
424
+ list-style: none;
425
+ display: flex;
426
+ flex-direction: column;
427
+ gap: 1px;
428
+ ${ /* Its own width, not the ground's: portalled, a percentage here is the
429
+ whole scene. */""}
430
+ min-width: 200px;
431
+ max-width: min(280px, 92%);
432
+ max-height: 60vh;
433
+ overflow: auto;
434
+ border-radius: var(--graview-radius-sm, 8px);
435
+ border: 1px solid var(--graview-edge);
436
+ background: var(--graview-panel);
437
+ box-shadow: 0 18px 44px -18px rgba(0, 0, 0, 0.45);
438
+ }
439
+ .graview-beyond-list button {
440
+ display: flex;
441
+ align-items: center;
442
+ gap: 10px;
443
+ width: 100%;
444
+ ${ /* A FINGERTIP WHERE IT IS ACTUALLY DRAWN, not where it was designed.
445
+ Every other control in this sheet is floored at 24 and the audit divides
446
+ by the plane's scale before judging it, which is right for a control
447
+ that sits ON a large target: the chip's disclosure is small, and the
448
+ card behind it is the size of a card. These names are not that. They are
449
+ the ONLY way to the districts the row could not hold, and plane two is
450
+ drawn at 0.90 — so a designed 24 meets a finger as 21.7. Designed at 28
451
+ it is drawn at 25, which is the number the floor was always about. */""}
452
+ min-height: max(1.75rem, 28px);
453
+ padding: 0 8px;
454
+ border: none;
455
+ border-radius: var(--graview-radius-sm, 6px);
456
+ background: none;
457
+ color: var(--graview-ink);
458
+ cursor: pointer;
459
+ font: inherit;
460
+ font-size: 0.875rem;
461
+ text-align: left;
462
+ overflow-wrap: anywhere;
463
+ white-space: nowrap;
464
+ }
465
+ .graview-beyond-list button:hover {
466
+ color: var(--graview-accent);
467
+ background: var(--graview-wash);
468
+ }
469
+ .graview-beyond-list button[aria-current] {
470
+ color: var(--graview-ink-muted);
471
+ cursor: default;
472
+ }
473
+ .graview-beyond-tally {
474
+ margin-left: auto;
475
+ font-size: 0.75rem;
476
+ font-variant-numeric: tabular-nums;
477
+ color: var(--graview-ink-faint);
478
+ }
479
+ .graview-iso-roof {
480
+ fill: hsl(var(--graview-hue, 200) ${face(iso.roof)});
481
+ stroke: ${iso.roofEdge};
482
+ stroke-width: 1;
483
+ }
484
+ .graview-iso-right {
485
+ fill: hsl(var(--graview-hue, 200) ${face(iso.right)});
486
+ }
487
+ .graview-iso-left {
488
+ fill: hsl(var(--graview-hue, 200) ${face(iso.left)});
489
+ }
490
+ ${ /* A SIGNPOST at the plot's front corner. From altitude the nameplate stood
491
+ at the top of the card — over the back row of the village — and the
492
+ screen had to clear it. It is planted at the front vertex of the tile
493
+ now, on a short post, where a sign stands at the entrance to a place;
494
+ the scene says where that vertex is in --graview-front-y. */""}
495
+ [data-graview-altitude] .graview-kind-face {
496
+ position: absolute !important;
497
+ left: 50% !important;
498
+ top: 2% !important;
499
+ transform: translateX(-50%);
500
+ width: max-content;
501
+ ${ /* Wider than the block when the name is: a label overflows its building
502
+ the way a map label does. "REQUIRE / MENTS" on two lines does not. */""}
503
+ max-width: none;
504
+ white-space: nowrap;
505
+ height: auto !important;
506
+ flex-direction: row !important;
507
+ align-items: baseline !important;
508
+ gap: 7px !important;
509
+ padding: 3px 11px !important;
510
+ border-radius: 999px !important;
511
+ box-shadow: var(--graview-lift-low) !important;
512
+ z-index: ${SCENE_LAYERS.tag};
513
+ }
514
+ [data-graview-altitude] [data-graview-plot] .graview-kind-face {
515
+ top: calc(var(--graview-front-y) - 22px) !important;
516
+ }
517
+ [data-graview-altitude] [data-graview-plot] .graview-kind-face::after {
518
+ content: "";
519
+ position: absolute;
520
+ left: 50%;
521
+ top: 100%;
522
+ width: 1px;
523
+ height: 10px;
524
+ background: var(--graview-ink-faint);
525
+ }
526
+ ${ /* A landmark WITHOUT a plot — a nested card — keeps its plate floating
527
+ above the drawing rather than across its head; one on a plot stands at
528
+ the signpost like every other district (the rule above). */""}
529
+ [data-graview-altitude] [data-graview-landmark]:not([data-graview-plot] *) .graview-kind-face {
530
+ top: 0 !important;
531
+ transform: translate(-50%, calc(-100% - 7px));
532
+ }
533
+ ${ /* The drive-in's board hangs UNDER the signpost, in the ground the layout
534
+ reserved for it below the tile's front corner, not over the village. */""}
535
+ [data-graview-altitude] .graview-drive-in {
536
+ top: calc(var(--graview-front-y, 42px) + 12px);
537
+ }
538
+ ${ /* An OPENED district's listing takes the ground under the signpost; the
539
+ board steps up over the village, which the listing covers anyway. */""}
540
+ [data-graview-altitude] .graview-kind-face[data-graview-opened] ~ .graview-drive-in {
541
+ top: calc(var(--graview-front-y, 42px) - 22px - var(--graview-marquee-room, 0px) + 8px);
542
+ }
543
+ ${ /* THE LANDMARK STANDS IN THE SQUARE: its feet at the plot's centre, among
544
+ the buildings, rather than at the card's bottom edge — which, once the
545
+ card grew for a board, was out in the road in front of the village. */""}
546
+ [data-graview-altitude] [data-graview-plot] .graview-kind-landmark {
547
+ bottom: auto;
548
+ top: calc(var(--graview-centre-y, 50%) + 10px);
549
+ transform: translate(-50%, -100%) scale(calc(0.55 + var(--graview-altitude) * 0.45));
550
+ }
551
+ ${ /* ZOOM, in the ground's corner: the way a map carries its own. Two
552
+ fingertip-sized buttons and the level between them, shown from altitude. */""}
553
+ .graview-zoom {
554
+ position: absolute;
555
+ right: 16px;
556
+ bottom: 16px;
557
+ ${ /* Above the occupants: a robot walking past a control must not cover it. */""}
558
+ z-index: ${SCENE_LAYERS.zoom};
559
+ display: inline-flex;
560
+ align-items: center;
561
+ gap: 2px;
562
+ padding: 2px;
563
+ border-radius: 999px;
564
+ border: 1px solid var(--graview-edge);
565
+ background: var(--graview-panel);
566
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
567
+ }
568
+ .graview-zoom-button {
569
+ min-width: 32px;
570
+ min-height: 32px;
571
+ border: 0;
572
+ border-radius: 999px;
573
+ background: transparent;
574
+ color: var(--graview-ink);
575
+ font: inherit;
576
+ font-size: 1.0625rem;
577
+ line-height: 1;
578
+ cursor: pointer;
579
+ }
580
+ .graview-zoom-button:hover:not(:disabled) {
581
+ background: var(--graview-edge);
582
+ }
583
+ .graview-zoom-button:disabled {
584
+ opacity: 0.35;
585
+ cursor: default;
586
+ }
587
+ .graview-zoom-level {
588
+ min-width: 3.2em;
589
+ text-align: center;
590
+ font-size: 0.8125rem;
591
+ color: var(--graview-ink-faint);
592
+ font-variant-numeric: tabular-nums;
593
+ }
594
+
595
+ ${ /* THE SCREEN IS A BILLBOARD at the back of the village: a frame, and two
596
+ posts into the ground at its foot. */""}
597
+ ${ /* On the NATURAL BOX, which is the picture now: the layout cuts the
598
+ billboard to what the lens drew (measured by the scene), never shorter
599
+ than a screen's worth — so the box is the picture, and an empty lens is a
600
+ header over an empty screen rather than a strip floating over the
601
+ village. The frame used to sit on the drawing itself, from the days the
602
+ box was as tall as the window with the picture in its top third. It
603
+ carries the panel's own ground so the empty part of a screen is a screen
604
+ and not the field showing through a frame. */""}
605
+ [data-graview-altitude] [data-graview-screen] > [data-graview-natural],
606
+ [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag) {
607
+ outline: 2px solid color-mix(in oklab, var(--graview-ink) 60%, var(--graview-panel));
608
+ outline-offset: 0;
609
+ background: var(--graview-panel);
610
+ }
611
+ [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag) {
612
+ position: relative;
613
+ }
614
+ [data-graview-altitude] [data-graview-screen] > [data-graview-natural]::before,
615
+ [data-graview-altitude] [data-graview-screen] > [data-graview-natural]::after,
616
+ [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag)::before,
617
+ [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag)::after {
618
+ content: "";
619
+ position: absolute;
620
+ top: 100%;
621
+ width: 3px;
622
+ height: 16px;
623
+ background: color-mix(in oklab, var(--graview-ink) 60%, var(--graview-panel));
624
+ }
625
+ [data-graview-altitude] [data-graview-screen] > [data-graview-natural]::before,
626
+ [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag)::before { left: 22%; }
627
+ [data-graview-altitude] [data-graview-screen] > [data-graview-natural]::after,
628
+ [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag)::after { right: 22%; }
629
+
630
+ ${ /* A thing inside a view that is itself a thing: an event in a calendar, a
631
+ person in a list. It has to look reachable, and it has to SHOW focus —
632
+ these are the primary way anyone moves through the graph, so a keyboard
633
+ user who cannot see where they are is stuck. */""}
634
+ ${ /* A card someone dragged into place. Marked, not decorated: a dotted tie to
635
+ say this position is held rather than computed. */""}
636
+ ${ /* On the CHILD, not the host: the host is the layout's box, and a view
637
+ that sizes to its content (a zoomed record, a fit panel) fills only part
638
+ of it — a dashed box around the empty remainder read as a drawing
639
+ mistake, not a mark. */""}
640
+ ${ /* And never on the natural box either — a view drawn scaled sits inside a
641
+ box the size of the whole scene, and the mark belongs on the drawing, not
642
+ on the box; nor on the kind tag, which is a label and not the thing. */""}
643
+ [data-graview-pinned] > :not([data-graview-natural]):not(.graview-kind-tag),
644
+ [data-graview-pinned] > [data-graview-natural] > * {
645
+ outline: 1px dashed var(--graview-edge-bright);
646
+ outline-offset: 3px;
647
+ border-radius: 12px;
648
+ }
649
+ ${ /* AND NOT FROM ALTITUDE, where a district is a village on a plot and its
650
+ card is a box with nothing drawn in it: the dashed outline was the only
651
+ visible part, so a hand-placed district read as an empty rounded
652
+ rectangle sitting on the ground — several of them, in a picture that had
653
+ no rectangles in it. The plot's own kerb goes dashed up here, which is
654
+ the same fact said where the district actually is. */""}
655
+ [data-graview-altitude] [data-graview-pinned] > :not([data-graview-natural]):not(.graview-kind-tag),
656
+ [data-graview-altitude] [data-graview-pinned] > [data-graview-natural] > * {
657
+ outline: none;
658
+ }
659
+ [data-graview-stage="dom"] [data-graview-view] > :not([data-graview-natural]),
660
+ [data-graview-stage="dom"] [data-graview-view] > [data-graview-natural] > * {
661
+ pointer-events: auto;
662
+ }
663
+ [data-graview-view][data-graview-selected] {
664
+ filter: drop-shadow(0 0 14px var(--graview-accent-dim));
665
+ }
666
+ [data-graview-touched] > * {
667
+ animation: graview-touched 1100ms cubic-bezier(0.22, 1, 0.36, 1);
668
+ border-radius: 10px;
669
+ }
670
+
671
+ ${ /* ------------------------------------------------------------ watching
672
+ *
673
+ * From outside the plane stack, activity has somewhere to HAPPEN: a kind
674
+ * lights where an edit landed, an edge pulses where a relation was made or
675
+ * broken, and a flag appears where a rule started failing. All of it is
676
+ * derived from the op log — author, intent, reads and writes — and all of it
677
+ * is drawn by these rules rather than by a frame loop, which is why watching
678
+ * costs nothing while nothing is happening.
679
+ *
680
+ * Who moved is carried in HUE, not in a badge. A person is the accent the
681
+ * whole interface already uses for "you did this"; an agent is a colder cast,
682
+ * so a turn it took on its own is distinguishable at a glance from one you
683
+ * directed; both at once takes both.
684
+ */""}
685
+ [data-graview-activity] {
686
+ --graview-activity: var(--graview-accent);
687
+ }
688
+ [data-graview-activity="autonomous"] {
689
+ --graview-activity: hsl(212 72% 62%);
690
+ }
691
+ [data-graview-activity="co-edited"] {
692
+ --graview-activity: hsl(280 60% 66%);
693
+ }
694
+ [data-graview-activity="rule"] {
695
+ --graview-activity: var(--graview-warn);
696
+ }
697
+ [data-graview-view][data-graview-wrote] > * {
698
+ animation: graview-landed 900ms cubic-bezier(0.22, 1, 0.36, 1);
699
+ border-radius: 10px;
700
+ }
701
+ [data-graview-view][data-graview-read] > :not([data-graview-natural]):not(.graview-kind-tag),
702
+ [data-graview-view][data-graview-read] > [data-graview-natural] > * {
703
+ outline: 1px dashed transparent;
704
+ outline-offset: 3px;
705
+ border-radius: 10px;
706
+ animation: graview-considered 1800ms ease-out;
707
+ }
708
+
709
+ ${ /* A rule that has just begun to fail. It outlives the edit that caused it,
710
+ because the problem does. */""}
711
+ [data-graview-view][data-graview-broke] > * {
712
+ box-shadow: 0 0 0 1px var(--graview-warn), 0 0 22px -6px var(--graview-warn);
713
+ border-radius: 10px;
714
+ }
715
+ [data-graview-connector][data-graview-activity] {
716
+ animation: graview-relation 1200ms cubic-bezier(0.22, 1, 0.36, 1);
717
+ }`;
718
+ }
719
+ /** The scene's rules, scoped as the frame's sheet is: what the scene face draws beside `themeBaseCss`. */
720
+ export function sceneCss(scheme = "dark", options = {}) {
721
+ const css = sceneSheet(scheme);
722
+ return options.scope === undefined ? css : withinTheBox(css, options.scope);
723
+ }
724
+ /**
725
+ * The whole theme as one stylesheet — the variables every primitive reads,
726
+ * the rules every face draws on, and the scene's own after them — for a
727
+ * page that draws the Shell. Everything the primitives reference is a
728
+ * custom property, so a host can override a single token without forking a
729
+ * component, and switching scheme is one `replaceSync`, not a re-render.
730
+ */
731
+ export function themeCss(scheme = "dark", brand = GRAVIEW_BRAND, options = {}) {
732
+ const css = `${baseSheet(scheme, brand, options)}\n${sceneSheet(scheme)}`;
733
+ return options.scope === undefined ? css : withinTheBox(css, options.scope);
734
+ }
735
+ //# sourceMappingURL=scene-css.js.map