@graview/primitives 0.1.4 → 0.1.6

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 (93) hide show
  1. package/dist/arrange-bar.d.ts +1 -3
  2. package/dist/arrange-bar.d.ts.map +1 -1
  3. package/dist/arrange-bar.js +2 -24
  4. package/dist/arrange-bar.js.map +1 -1
  5. package/dist/arrangement.d.ts +5 -0
  6. package/dist/arrangement.d.ts.map +1 -0
  7. package/dist/arrangement.js +25 -0
  8. package/dist/arrangement.js.map +1 -0
  9. package/dist/chat.js +2 -2
  10. package/dist/chat.js.map +1 -1
  11. package/dist/companion.js +1 -1
  12. package/dist/companion.js.map +1 -1
  13. package/dist/connections.js +1 -1
  14. package/dist/connections.js.map +1 -1
  15. package/dist/default-view.d.ts +1 -1
  16. package/dist/default-view.d.ts.map +1 -1
  17. package/dist/default-view.js +1 -1
  18. package/dist/default-view.js.map +1 -1
  19. package/dist/default-views.d.ts +1 -1
  20. package/dist/default-views.d.ts.map +1 -1
  21. package/dist/default-views.js +11 -5
  22. package/dist/default-views.js.map +1 -1
  23. package/dist/editable.js +1 -1
  24. package/dist/editable.js.map +1 -1
  25. package/dist/find.js +2 -2
  26. package/dist/find.js.map +1 -1
  27. package/dist/frame.d.ts +22 -0
  28. package/dist/frame.d.ts.map +1 -0
  29. package/dist/frame.js +21 -0
  30. package/dist/frame.js.map +1 -0
  31. package/dist/framework-views.d.ts +5 -0
  32. package/dist/framework-views.d.ts.map +1 -0
  33. package/dist/framework-views.js +20 -0
  34. package/dist/framework-views.js.map +1 -0
  35. package/dist/index.d.ts +1 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +1 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/installation.js +2 -2
  40. package/dist/installation.js.map +1 -1
  41. package/dist/ladder.js +1 -1
  42. package/dist/ladder.js.map +1 -1
  43. package/dist/pages.d.ts +20 -0
  44. package/dist/pages.d.ts.map +1 -0
  45. package/dist/pages.js +19 -0
  46. package/dist/pages.js.map +1 -0
  47. package/dist/places.js +2 -2
  48. package/dist/places.js.map +1 -1
  49. package/dist/primitives/index.js +1 -1
  50. package/dist/primitives/index.js.map +1 -1
  51. package/dist/profile.js +1 -1
  52. package/dist/profile.js.map +1 -1
  53. package/dist/quick-relations.js +2 -2
  54. package/dist/quick-relations.js.map +1 -1
  55. package/dist/relation-key.js +1 -1
  56. package/dist/relation-key.js.map +1 -1
  57. package/dist/seats.js +1 -1
  58. package/dist/seats.js.map +1 -1
  59. package/dist/seeding.js +1 -1
  60. package/dist/seeding.js.map +1 -1
  61. package/dist/spec-views.d.ts +1 -1
  62. package/dist/spec-views.d.ts.map +1 -1
  63. package/dist/spec-views.js +1 -1
  64. package/dist/spec-views.js.map +1 -1
  65. package/dist/theme.d.ts +6 -0
  66. package/dist/theme.d.ts.map +1 -1
  67. package/dist/theme.js +507 -393
  68. package/dist/theme.js.map +1 -1
  69. package/dist/view-doors.d.ts +10 -0
  70. package/dist/view-doors.d.ts.map +1 -0
  71. package/dist/view-doors.js +47 -0
  72. package/dist/view-doors.js.map +1 -0
  73. package/dist/wordmark.js +1 -1
  74. package/dist/wordmark.js.map +1 -1
  75. package/dist/workbench/activity.js +1 -1
  76. package/dist/workbench/activity.js.map +1 -1
  77. package/dist/workbench/agent-seat.js +2 -2
  78. package/dist/workbench/agent-seat.js.map +1 -1
  79. package/dist/workbench/answer-args.js +2 -2
  80. package/dist/workbench/answer-args.js.map +1 -1
  81. package/dist/workbench/back-out.d.ts +1 -1
  82. package/dist/workbench/back-out.d.ts.map +1 -1
  83. package/dist/workbench/back-out.js +2 -2
  84. package/dist/workbench/back-out.js.map +1 -1
  85. package/dist/workbench/following.js +1 -1
  86. package/dist/workbench/following.js.map +1 -1
  87. package/dist/workbench/inspector.js +1 -1
  88. package/dist/workbench/inspector.js.map +1 -1
  89. package/dist/workbench/standing.js +1 -1
  90. package/dist/workbench/standing.js.map +1 -1
  91. package/dist/workbench/trail.js +2 -2
  92. package/dist/workbench/trail.js.map +1 -1
  93. package/package.json +14 -6
package/dist/theme.js CHANGED
@@ -99,7 +99,121 @@ function stillness(asking, within) {
99
99
  ${at} [data-graview-view][data-graview-read] > * { box-shadow: 0 0 0 1px var(--graview-activity); }
100
100
  ${at} [data-graview-connector][data-graview-activity] { animation: none; stroke-opacity: 1; }`;
101
101
  }
102
+ /*
103
+ * WHY THE STYLESHEET'S NOTES ARE WRITTEN `${/* … *\/ ""}`. They were CSS
104
+ * comments inside the template, and every page carried them — 25 KB of the
105
+ * 60 this function was, shipped to each reader and parsed into each embed's
106
+ * <style> (FR-57). As a JS comment in an empty interpolation the words stay
107
+ * where they explain the rule, and a minifier folds them away.
108
+ */
102
109
  export function themeCss(scheme = "dark", brand = GRAVIEW_BRAND, options = {}) {
110
+ const css = sheet(scheme, brand, options);
111
+ return options.scope === undefined ? css : withinTheBox(css, options.scope);
112
+ }
113
+ /*
114
+ * A SCOPED STYLESHEET KEEPS TO ITS BOX (FR-64).
115
+ *
116
+ * The tokens, the ground and the type were written on the scope, but every
117
+ * other rule was written for a whole page — `button`, `h1, h2, h3, h4`,
118
+ * `code` — and an embed's <style> is a whole page's stylesheet: on Cloud's
119
+ * builder the host's own buttons, below the studio, took the framework's
120
+ * ink on a transparent ground and failed contrast in dark. Rather than
121
+ * remember to scope each rule as it is written, the finished sheet is
122
+ * rewritten: every selector that does not already start at the box is put
123
+ * under `:where(<scope>)`. `:where` weighs nothing, so each rule wins and
124
+ * loses exactly the contests it did on a whole page, and only where it
125
+ * applies changes. What is not a style rule (a registered property, the
126
+ * keyframes) names no element and is left as it is; @media and @supports
127
+ * are walked into.
128
+ */
129
+ function withinTheBox(css, scope) {
130
+ const under = `:where(${scope}) `;
131
+ const at = (selector) => selector === scope ||
132
+ selector.startsWith(`${scope} `) ||
133
+ selector.startsWith(`${scope}:`) ||
134
+ selector.startsWith(`${scope}[`) ||
135
+ // The reader's motion answer: asked of the document, applied inside the box.
136
+ (selector.startsWith(":root") && selector.includes(` ${scope} `));
137
+ const rewrite = (prelude) => {
138
+ const lead = prelude.match(/^\s*/)[0];
139
+ const list = splitSelectors(prelude.trim()).map((selector) => (at(selector) ? selector : `${under}${selector}`));
140
+ return `${lead}${list.join(", ")} `;
141
+ };
142
+ const walk = (text) => {
143
+ let out = "";
144
+ let i = 0;
145
+ while (i < text.length) {
146
+ const open = text.indexOf("{", i);
147
+ if (open === -1)
148
+ return out + text.slice(i);
149
+ const close = blockEnd(text, open);
150
+ const prelude = text.slice(i, open);
151
+ const body = text.slice(open + 1, close);
152
+ const name = prelude.trim().startsWith("@") ? prelude.trim().split(/[\s(]/)[0] : null;
153
+ if (name === null)
154
+ out += `${rewrite(prelude)}{${body}}`;
155
+ else if (name === "@media" || name === "@supports" || name === "@container" || name === "@layer")
156
+ out += `${prelude}{${walk(body)}}`;
157
+ else
158
+ out += `${prelude}{${body}}`;
159
+ i = close + 1;
160
+ }
161
+ return out;
162
+ };
163
+ return walk(css);
164
+ }
165
+ /** The index of the brace that closes the block opened at `open`, past strings and comments. */
166
+ function blockEnd(text, open) {
167
+ let depth = 0;
168
+ let quote = null;
169
+ for (let j = open; j < text.length; j++) {
170
+ const ch = text[j];
171
+ if (quote) {
172
+ if (ch === "\\")
173
+ j++;
174
+ else if (ch === quote)
175
+ quote = null;
176
+ }
177
+ else if (ch === '"' || ch === "'")
178
+ quote = ch;
179
+ else if (ch === "/" && text[j + 1] === "*")
180
+ j = text.indexOf("*/", j + 2) + 1 || text.length;
181
+ else if (ch === "{")
182
+ depth++;
183
+ else if (ch === "}" && --depth === 0)
184
+ return j;
185
+ }
186
+ return text.length;
187
+ }
188
+ /** A selector list split on its own commas — not those inside `:is(…)`, `[…]` or a string. */
189
+ function splitSelectors(list) {
190
+ const out = [];
191
+ let depth = 0;
192
+ let quote = null;
193
+ let current = "";
194
+ for (const ch of list) {
195
+ if (quote) {
196
+ if (ch === quote)
197
+ quote = null;
198
+ }
199
+ else if (ch === '"' || ch === "'")
200
+ quote = ch;
201
+ else if (ch === "(" || ch === "[")
202
+ depth++;
203
+ else if (ch === ")" || ch === "]")
204
+ depth--;
205
+ else if (ch === "," && depth === 0) {
206
+ out.push(current.trim());
207
+ current = "";
208
+ continue;
209
+ }
210
+ current += ch;
211
+ }
212
+ if (current.trim())
213
+ out.push(current.trim());
214
+ return out;
215
+ }
216
+ function sheet(scheme, brand, options) {
103
217
  const tokens = brand.schemes[scheme];
104
218
  const root = options.scope ?? ":root";
105
219
  const surface = options.scope ?? "html, body";
@@ -138,7 +252,7 @@ ${kitVariables(kit)}
138
252
  --graview-font-body: ${body};
139
253
  --graview-font-display: ${brand.typography?.display ?? body};
140
254
  --graview-font-mono: ${brand.typography?.mono ?? 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace'};
141
- /* Shape, as tokens, so a component never has to know whose product it is. */
255
+ ${ /* Shape, as tokens, so a component never has to know whose product it is. */""}
142
256
  --graview-radius: ${radius}px;
143
257
  --graview-radius-sm: ${Math.max(2, Math.round(radius * 0.72))}px;
144
258
  --graview-pad: ${Math.round(15 * density)}px;
@@ -153,36 +267,36 @@ ${surface} {
153
267
  color: var(--graview-ink);
154
268
  }
155
269
 
156
- /*
157
- * THE READER'S OWN TEXT SIZE.
158
- *
159
- * Every size in the framework was once an absolute pixel count, so somebody
160
- * who sets a larger default font in their browser — the setting WCAG 1.4.4
161
- * is about — got a Graview that ignored them completely. 0.875rem is 14px
162
- * at the default 16px root, so nothing moves for anyone who has not asked
163
- * for anything, and everything moves together for anyone who has.
164
- */
270
+ ${ /*
271
+ * THE READER'S OWN TEXT SIZE.
272
+ *
273
+ * Every size in the framework was once an absolute pixel count, so somebody
274
+ * who sets a larger default font in their browser — the setting WCAG 1.4.4
275
+ * is about — got a Graview that ignored them completely. 0.875rem is 14px
276
+ * at the default 16px root, so nothing moves for anyone who has not asked
277
+ * for anything, and everything moves together for anyone who has.
278
+ */""}
165
279
  ${text} {
166
280
  font: 0.875rem/1.55 var(--graview-font-body);
167
281
  font-variant-numeric: tabular-nums;
168
282
  -webkit-font-smoothing: antialiased;
169
283
  }
170
284
 
171
- /* Headings and the wordmark take the display face when a brand supplies one,
172
- and the body face when it does not — so a brand with one font is not asked
173
- to name it twice. */
285
+ ${ /* Headings and the wordmark take the display face when a brand supplies one,
286
+ and the body face when it does not — so a brand with one font is not asked
287
+ to name it twice. */""}
174
288
  h1, h2, h3, h4, .graview-wordmark { font-family: var(--graview-font-display); }
175
289
  code, kbd, samp { font-family: var(--graview-font-mono); }
176
290
 
177
- /*
178
- * A KIND'S FIGURE fills the box it is given.
179
- *
180
- * The art declares its own viewBox and knows nothing about where it is
181
- * drawn — a chip at twelve pixels, a district's heading at eighteen, a kind
182
- * card's landmark at forty — so the SIZE is the container's and the drawing
183
- * scales into it. currentColor on the strokes means the kind's own hue
184
- * arrives through the cascade without the art being redrawn.
185
- */
291
+ ${ /*
292
+ * A KIND'S FIGURE fills the box it is given.
293
+ *
294
+ * The art declares its own viewBox and knows nothing about where it is
295
+ * drawn — a chip at twelve pixels, a district's heading at eighteen, a kind
296
+ * card's landmark at forty — so the SIZE is the container's and the drawing
297
+ * scales into it. currentColor on the strokes means the kind's own hue
298
+ * arrives through the cascade without the art being redrawn.
299
+ */""}
186
300
  [data-graview-figure] > svg {
187
301
  width: 100%;
188
302
  height: 100%;
@@ -190,17 +304,17 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
190
304
  overflow: visible;
191
305
  }
192
306
 
193
- /* How far above the stack the camera is, 0..1 — REGISTERED so it can
194
- transition. Rising to the Graview morphs the scene instead of cutting:
195
- the square grid dissolves into the iso lattice and the districts grow up
196
- out of their cards, all riding this one number. */
307
+ ${ /* How far above the stack the camera is, 0..1 — REGISTERED so it can
308
+ transition. Rising to the Graview morphs the scene instead of cutting:
309
+ the square grid dissolves into the iso lattice and the districts grow up
310
+ out of their cards, all riding this one number. */""}
197
311
  @property --graview-altitude {
198
312
  syntax: "<number>";
199
313
  inherits: true;
200
314
  initial-value: 0;
201
315
  }
202
316
 
203
- /* The ground: a slow wash, so depth has something to recede into. */
317
+ ${ /* The ground: a slow wash, so depth has something to recede into. */""}
204
318
  .graview-ground {
205
319
  position: relative;
206
320
  background: var(--graview-wash), var(--graview-ground);
@@ -208,13 +322,13 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
208
322
  transition: --graview-altitude 640ms cubic-bezier(0.33, 0, 0.2, 1);
209
323
  }
210
324
 
211
- /*
212
- * The altitude control rides the SAME number the scene rides — its own copy,
213
- * because it sits beside the ground rather than inside it — on the same
214
- * curve. So the mark morphs exactly as long as the scene does, and where an
215
- * engine cannot register the property, both cut together: one mechanism,
216
- * and no way for the control and the picture to disagree about the change.
217
- */
325
+ ${ /*
326
+ * The altitude control rides the SAME number the scene rides — its own copy,
327
+ * because it sits beside the ground rather than inside it — on the same
328
+ * curve. So the mark morphs exactly as long as the scene does, and where an
329
+ * engine cannot register the property, both cut together: one mechanism,
330
+ * and no way for the control and the picture to disagree about the change.
331
+ */""}
218
332
  .graview-altitude-control {
219
333
  --graview-altitude: 0;
220
334
  transition:
@@ -226,7 +340,7 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
226
340
  transform-box: fill-box;
227
341
  transform-origin: center;
228
342
  }
229
- /* The ring of three kinds tightens to one ring around one node. */
343
+ ${ /* The ring of three kinds tightens to one ring around one node. */""}
230
344
  .graview-altitude-mark-ring {
231
345
  transform: scaleX(calc(1 - 0.48 * var(--graview-altitude)));
232
346
  opacity: calc(0.55 + 0.4 * var(--graview-altitude));
@@ -234,7 +348,7 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
234
348
  .graview-altitude-mark-apex {
235
349
  transform: translateY(calc(2.6px * var(--graview-altitude)));
236
350
  }
237
- /* The two wings gather into the centre and give their ink to the apex. */
351
+ ${ /* The two wings gather into the centre and give their ink to the apex. */""}
238
352
  .graview-altitude-mark-wing {
239
353
  opacity: calc(0.75 * (1 - var(--graview-altitude)));
240
354
  }
@@ -245,9 +359,9 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
245
359
  transform: translate(calc(-4.4px * var(--graview-altitude)), calc(-0.8px * var(--graview-altitude)));
246
360
  }
247
361
 
248
- /* A fine measure under the scene. Faint enough to feel like calibration
249
- rather than graph paper, and it fades out at the edges so the scene has no
250
- hard boundary. */
362
+ ${ /* A fine measure under the scene. Faint enough to feel like calibration
363
+ rather than graph paper, and it fades out at the edges so the scene has no
364
+ hard boundary. */""}
251
365
  .graview-ground::before {
252
366
  content: "";
253
367
  position: absolute;
@@ -261,15 +375,15 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
261
375
  mask-image: radial-gradient(120% 90% at 50% 40%, #000 30%, transparent 78%);
262
376
  }
263
377
 
264
- /* Content that scrolls inside a panel, and SAYS SO.
265
- *
266
- * A pure-CSS scroll shadow: two cover gradients painted in the panel's own
267
- * ground scroll with the content, two shadows stay put, and so a shadow
268
- * only shows at an edge there is more content past. No
269
- * JavaScript, no measurement, and nothing to go stale — which matters
270
- * because the failure it prevents is silent. macOS hides overlay scrollbars
271
- * until you scroll, so without this a clipped list looks like a finished
272
- * one. */
378
+ ${ /* Content that scrolls inside a panel, and SAYS SO.
379
+ *
380
+ * A pure-CSS scroll shadow: two cover gradients painted in the panel's own
381
+ * ground scroll with the content, two shadows stay put, and so a shadow
382
+ * only shows at an edge there is more content past. No
383
+ * JavaScript, no measurement, and nothing to go stale — which matters
384
+ * because the failure it prevents is silent. macOS hides overlay scrollbars
385
+ * until you scroll, so without this a clipped list looks like a finished
386
+ * one. */""}
273
387
  .graview-scroll {
274
388
  overflow: auto;
275
389
  min-height: 0;
@@ -282,8 +396,8 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
282
396
  background-size: 100% 24px, 100% 24px, 100% 10px, 100% 10px;
283
397
  background-attachment: local, local, scroll, scroll;
284
398
  }
285
- /* "There is more of this", said by the ground: a few pixels of the panel's
286
- * own colour over the last row, stuck to the bottom of what scrolls. */
399
+ ${ /* "There is more of this", said by the ground: a few pixels of the panel's
400
+ * own colour over the last row, stuck to the bottom of what scrolls. */""}
287
401
  .graview-scroll[data-graview-overflowing]::after {
288
402
  content: "";
289
403
  position: sticky;
@@ -294,23 +408,23 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
294
408
  pointer-events: none;
295
409
  }
296
410
 
297
- /* A card on the kinds plane.
298
- *
299
- * Title and count only at rest — a strip of ten cards each showing three
300
- * truncated member names is ten unreadable things, and the members are not
301
- * what you are asking the strip. Hovering lifts one and reveals the kind's
302
- * own description, which the declaration has always carried and nothing has
303
- * ever shown. */
411
+ ${ /* A card on the kinds plane.
412
+ *
413
+ * Title and count only at rest — a strip of ten cards each showing three
414
+ * truncated member names is ten unreadable things, and the members are not
415
+ * what you are asking the strip. Hovering lifts one and reveals the kind's
416
+ * own description, which the declaration has always carried and nothing has
417
+ * ever shown. */""}
304
418
  .graview-kind-card {
305
419
  height: 100%;
306
420
  transition: transform 170ms cubic-bezier(0.22, 1, 0.36, 1), height 170ms ease,
307
421
  box-shadow 170ms ease;
308
- /* IN THE STACK NOTHING HANGS BELOW A CARD. The iso block rests eighteen
309
- pixels low there, invisible, ready to rise — and an invisible box that
310
- pokes under the bottom row still made the stage scroll by nine pixels
311
- with nowhere to scroll. Clipped (not hidden: no scroll container, no
312
- scrollable overflow), and let out again from altitude, where the plate
313
- floats above the card and the block stands up out of it. */
422
+ ${ /* IN THE STACK NOTHING HANGS BELOW A CARD. The iso block rests eighteen
423
+ pixels low there, invisible, ready to rise — and an invisible box that
424
+ pokes under the bottom row still made the stage scroll by nine pixels
425
+ with nowhere to scroll. Clipped (not hidden: no scroll container, no
426
+ scrollable overflow), and let out again from altitude, where the plate
427
+ floats above the card and the block stands up out of it. */""}
314
428
  overflow: clip;
315
429
  }
316
430
  [data-graview-altitude] .graview-kind-card {
@@ -324,9 +438,9 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
324
438
  position: relative;
325
439
  z-index: 3;
326
440
  }
327
- /* From altitude a district is a village on its plot, not a card: hovering
328
- it must not raise a white panel over the buildings. The lift stays in
329
- the stack, where the card is a card. */
441
+ ${ /* From altitude a district is a village on its plot, not a card: hovering
442
+ it must not raise a white panel over the buildings. The lift stays in
443
+ the stack, where the card is a card. */""}
330
444
  [data-graview-altitude] .graview-kind-card:hover,
331
445
  [data-graview-altitude] .graview-kind-card:focus-within {
332
446
  transform: none;
@@ -334,19 +448,19 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
334
448
  background: transparent;
335
449
  }
336
450
 
337
- /* FROM ALTITUDE the ground is an ISOMETRIC LATTICE — diamond cells at the
338
- classic 2:1 pitch, a finer far weave above, dissolving toward the
339
- horizon. Always present, faded by the altitude number, so rising
340
- CROSSFADES the square grid into the lattice instead of cutting. */
341
- /* DRAWN AS TILES, one cell each. A repeating gradient at the lattice's
342
- angle was phased from the middle of the box and seamed at the box's own
343
- edge when repeated with an offset, so the lines never sat where the
344
- city's cells were: a plot stood beside the grid, not on it. Each tile is
345
- one cell wide and half a cell tall — the diamond's bounding box — with
346
- the tile's two diagonals drawn across it, which is the whole lattice:
347
- corners and centres of the tiles are its vertices, and a tile corner is
348
- pinned where the city's cell (0,0) meets the canvas. The far weave is the
349
- same tile at half size. */
451
+ ${ /* FROM ALTITUDE the ground is an ISOMETRIC LATTICE — diamond cells at the
452
+ classic 2:1 pitch, a finer far weave above, dissolving toward the
453
+ horizon. Always present, faded by the altitude number, so rising
454
+ CROSSFADES the square grid into the lattice instead of cutting. */""}
455
+ ${ /* DRAWN AS TILES, one cell each. A repeating gradient at the lattice's
456
+ angle was phased from the middle of the box and seamed at the box's own
457
+ edge when repeated with an offset, so the lines never sat where the
458
+ city's cells were: a plot stood beside the grid, not on it. Each tile is
459
+ one cell wide and half a cell tall — the diamond's bounding box — with
460
+ the tile's two diagonals drawn across it, which is the whole lattice:
461
+ corners and centres of the tiles are its vertices, and a tile corner is
462
+ pinned where the city's cell (0,0) meets the canvas. The far weave is the
463
+ same tile at half size. */""}
350
464
  .graview-ground::after {
351
465
  content: "";
352
466
  position: absolute;
@@ -364,21 +478,21 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
364
478
  var(--graview-lattice-tile) calc(var(--graview-lattice-tile) / 2),
365
479
  calc(var(--graview-lattice-tile) / 2) calc(var(--graview-lattice-tile) / 4),
366
480
  calc(var(--graview-lattice-tile) / 2) calc(var(--graview-lattice-tile) / 4);
367
- /* Anchored where the city's cell (0,0) meets the canvas, so a plot placed
368
- by the map sits ON the grid a person can see, and pans with it. */
481
+ ${ /* Anchored where the city's cell (0,0) meets the canvas, so a plot placed
482
+ by the map sits ON the grid a person can see, and pans with it. */""}
369
483
  background-position: var(--graview-lattice-x, 0px) var(--graview-lattice-y, 0px);
370
- /* Twice the square grid's weight: fields are meant to be seen, the grid is meant to be felt. */
484
+ ${ /* Twice the square grid's weight: fields are meant to be seen, the grid is meant to be felt. */""}
371
485
  opacity: calc(var(--graview-kit-lattice, 1) * var(--graview-grid-alpha) * 2 * var(--graview-altitude));
372
486
  mask-image: linear-gradient(to top, #000 42%, rgba(0,0,0,0.35) 70%, transparent 92%);
373
487
  -webkit-mask-image: linear-gradient(to top, #000 42%, rgba(0,0,0,0.35) 70%, transparent 92%);
374
488
  }
375
489
 
376
- /* THE GROUND UNDER A DISTRICT: its plot, drawn. Four lattice corners in
377
- the kind's hue, a kerb, a cast shadow toward the light — the arithmetic
378
- the layout already did, made visible, so a district stands on land
379
- rather than floating on a hatch. Fades in with the altitude number the
380
- lattice fades in with; a hand-placed district's kerb is dashed, which is
381
- the pinned mark on the ground rather than a box over the drawing. */
490
+ ${ /* THE GROUND UNDER A DISTRICT: its plot, drawn. Four lattice corners in
491
+ the kind's hue, a kerb, a cast shadow toward the light — the arithmetic
492
+ the layout already did, made visible, so a district stands on land
493
+ rather than floating on a hatch. Fades in with the altitude number the
494
+ lattice fades in with; a hand-placed district's kerb is dashed, which is
495
+ the pinned mark on the ground rather than a box over the drawing. */""}
382
496
  .graview-plots {
383
497
  z-index: 0;
384
498
  opacity: var(--graview-altitude);
@@ -400,10 +514,10 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
400
514
  .graview-plot[data-graview-pinned] .graview-plot-tile {
401
515
  stroke-dasharray: 4 3;
402
516
  }
403
- /* THE VILLAGE on the tile: one small iso building per member in the kind's
404
- own faces (the same roof and walls the block had), a flagged member's roof
405
- in the warning colour, a selected member's building lit in the accent.
406
- Architecture, not controls: the tile under them takes the click. */
517
+ ${ /* THE VILLAGE on the tile: one small iso building per member in the kind's
518
+ own faces (the same roof and walls the block had), a flagged member's roof
519
+ in the warning colour, a selected member's building lit in the accent.
520
+ Architecture, not controls: the tile under them takes the click. */""}
407
521
  .graview-village { pointer-events: none; }
408
522
  .graview-building polygon { stroke-width: 0.8; }
409
523
  .graview-building[data-graview-flagged] .graview-iso-roof { fill: var(--graview-warn); stroke: var(--graview-warn); }
@@ -414,10 +528,10 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
414
528
  letter-spacing: 0.06em;
415
529
  fill: var(--graview-ink-muted);
416
530
  }
417
- /* THE ROADS between plots: the lattice's own two legs from kerb to kerb, a
418
- bed between two edges in the ground's ink. Under the tiles and the
419
- buildings, over the fields. A road the legend is asking about comes up
420
- in the accent. */
531
+ ${ /* THE ROADS between plots: the lattice's own two legs from kerb to kerb, a
532
+ bed between two edges in the ground's ink. Under the tiles and the
533
+ buildings, over the fields. A road the legend is asking about comes up
534
+ in the accent. */""}
421
535
  .graview-road-edge {
422
536
  fill: none;
423
537
  stroke: var(--graview-ink);
@@ -437,34 +551,34 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
437
551
  stroke: var(--graview-accent);
438
552
  stroke-opacity: 0.9;
439
553
  }
440
- /* FIELDS. From altitude the ground darkens a shade toward the near edge and
441
- fades to the page at the horizon, so the lattice is land with a distance
442
- rather than paper with a pattern. */
554
+ ${ /* FIELDS. From altitude the ground darkens a shade toward the near edge and
555
+ fades to the page at the horizon, so the lattice is land with a distance
556
+ rather than paper with a pattern. */""}
443
557
  .graview-ground[data-graview-altitude] {
444
558
  background:
445
559
  linear-gradient(to top, color-mix(in oklab, var(--graview-ground) ${scheme === "light" ? "93%" : "88%"}, var(--graview-ink)) 0%, var(--graview-ground) 78%),
446
560
  var(--graview-ground);
447
561
  }
448
562
 
449
- /* THE KEEPER'S BLOCK IN THE PROFILE, which hides itself when it is empty.
450
- Both controls inside it draw nothing for a seat that may not administer,
451
- and a heading with nothing under it is worse than no heading — so the
452
- block is drawn only when it actually holds a control. */
563
+ ${ /* THE KEEPER'S BLOCK IN THE PROFILE, which hides itself when it is empty.
564
+ Both controls inside it draw nothing for a seat that may not administer,
565
+ and a heading with nothing under it is worse than no heading — so the
566
+ block is drawn only when it actually holds a control. */""}
453
567
  .graview-profile-keeping { display: grid; gap: 6px; }
454
568
  .graview-profile-keeping:not(:has(button, a)) { display: none; }
455
569
  .graview-profile-keeping > * { justify-self: start; }
456
570
 
457
- /* THE OPEN CHEVRON APPEARS WHEN REACHED FOR. Drawn on every plate at
458
- altitude it was noise times the number of districts; it shows on hover,
459
- on keyboard focus, and while the district is open — and stays a real
460
- button in between, so Tab still finds it and Enter still opens. */
571
+ ${ /* THE OPEN CHEVRON APPEARS WHEN REACHED FOR. Drawn on every plate at
572
+ altitude it was noise times the number of districts; it shows on hover,
573
+ on keyboard focus, and while the district is open — and stays a real
574
+ button in between, so Tab still finds it and Enter still opens. */""}
461
575
  [data-graview-altitude] .graview-kind-open {
462
576
  opacity: 0.5;
463
577
  transition: opacity 150ms ease;
464
578
  }
465
- /* Quiet: the chevron alone until reached for. Never opacity zero — a
466
- button nobody can see is a button a driven browser cannot press either,
467
- and Tab must land on something that looks like something. */
579
+ ${ /* Quiet: the chevron alone until reached for. Never opacity zero — a
580
+ button nobody can see is a button a driven browser cannot press either,
581
+ and Tab must land on something that looks like something. */""}
468
582
  [data-graview-altitude] .graview-kind-open-word {
469
583
  display: none;
470
584
  }
@@ -478,22 +592,22 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
478
592
  [data-graview-altitude] .graview-kind-open[aria-expanded="true"] .graview-kind-open-word {
479
593
  display: inline;
480
594
  }
481
- /* The district-open control and its roster: altitude-only chrome. Inside
482
- the stack expanding dissolves a card, so the control does not exist
483
- there. A full fingertip even though the glyph is small — the audit holds
484
- every control to 24px. */
595
+ ${ /* The district-open control and its roster: altitude-only chrome. Inside
596
+ the stack expanding dissolves a card, so the control does not exist
597
+ there. A full fingertip even though the glyph is small — the audit holds
598
+ every control to 24px. */""}
485
599
  .graview-kind-open { display: none; }
486
600
  [data-graview-altitude] .graview-kind-open {
487
601
  display: inline-flex;
488
602
  align-items: center;
489
603
  justify-content: center;
490
604
  flex: 0 0 auto;
491
- /* A FINGERTIP, AND THE READER'S FINGERTIP IF IT IS BIGGER. 24px is the
492
- floor audit-ui holds every control to; 1.5rem is the same 24 at the
493
- default text size and grows with a reader who asked for more, so the
494
- control never drifts under the words it sits beside. A max() rather than
495
- either one alone: rem alone drops below the fingertip at a smaller
496
- setting, px alone ignores the setting altogether. */
605
+ ${ /* A FINGERTIP, AND THE READER'S FINGERTIP IF IT IS BIGGER. 24px is the
606
+ floor audit-ui holds every control to; 1.5rem is the same 24 at the
607
+ default text size and grows with a reader who asked for more, so the
608
+ control never drifts under the words it sits beside. A max() rather than
609
+ either one alone: rem alone drops below the fingertip at a smaller
610
+ setting, px alone ignores the setting altogether. */""}
497
611
  min-height: max(1.5rem, 24px);
498
612
  padding: 1px 9px;
499
613
  margin: -3px 0;
@@ -503,12 +617,12 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
503
617
  box-shadow: none;
504
618
  color: var(--graview-ink-muted);
505
619
  cursor: pointer;
506
- /* IN REM, LIKE EVERY OTHER SIZE HERE. At 10px this control's words were
507
- the one piece of text in the framework that ignored the reader's text
508
- size completely: set to Largest, every name on the screen doubled and
509
- "open" stayed ten pixels tall. A size a person chose and a control that
510
- will not take it is the accessibility setting failing on its own
511
- surface. */
620
+ ${ /* IN REM, LIKE EVERY OTHER SIZE HERE. At 10px this control's words were
621
+ the one piece of text in the framework that ignored the reader's text
622
+ size completely: set to Largest, every name on the screen doubled and
623
+ "open" stayed ten pixels tall. A size a person chose and a control that
624
+ will not take it is the accessibility setting failing on its own
625
+ surface. */""}
512
626
  font-size: 0.75rem;
513
627
  letter-spacing: 0.08em;
514
628
  text-transform: uppercase;
@@ -519,19 +633,19 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
519
633
  color: var(--graview-accent);
520
634
  border-color: var(--graview-accent-dim);
521
635
  }
522
- /* The roster reads as a LIST, one member a row — chips wrapping at their
523
- own widths read as spilled tiles, and a district's population is a roll
524
- call, not a mosaic. */
525
- /* A DRIVE-IN: a dark screen standing on the plot, and the showings under
526
- it as a marquee of real buttons. Only from altitude; the same list the
527
- Places pills carry, drawn where the pictures live. */
636
+ ${ /* The roster reads as a LIST, one member a row — chips wrapping at their
637
+ own widths read as spilled tiles, and a district's population is a roll
638
+ call, not a mosaic. */""}
639
+ ${ /* A DRIVE-IN: a dark screen standing on the plot, and the showings under
640
+ it as a marquee of real buttons. Only from altitude; the same list the
641
+ Places pills carry, drawn where the pictures live. */""}
528
642
  .graview-drive-in {
529
- /* Its own block under the nameplate, never a row inside the pill: the
530
- pill is one line of name and count, and a marquee flattened into it
531
- read as "12 • shown above The month The week". On a box the pill sits
532
- on the roof at the top of the card, so the marquee hangs under it; on
533
- a landmark the pill floats above the card, so the marquee takes the
534
- card's own top edge. */
643
+ ${ /* Its own block under the nameplate, never a row inside the pill: the
644
+ pill is one line of name and count, and a marquee flattened into it
645
+ read as "12 • shown above The month The week". On a box the pill sits
646
+ on the roof at the top of the card, so the marquee hangs under it; on
647
+ a landmark the pill floats above the card, so the marquee takes the
648
+ card's own top edge. */""}
535
649
  position: absolute;
536
650
  left: 50%;
537
651
  top: 42px;
@@ -554,9 +668,9 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
554
668
  .graview-drive-in-marquee[data-graview-thumbs="one"] {
555
669
  grid-template-columns: 120px;
556
670
  }
557
- /* THE LENSES AS PICTURES: each showing is its lens drawn small — the real
558
- component at a fraction of its size, cut to a thumbnail — with its name
559
- under it. The picture takes no pointer; the button around it does. */
671
+ ${ /* THE LENSES AS PICTURES: each showing is its lens drawn small — the real
672
+ component at a fraction of its size, cut to a thumbnail — with its name
673
+ under it. The picture takes no pointer; the button around it does. */""}
560
674
  .graview-drive-in-thumb {
561
675
  position: relative;
562
676
  display: grid;
@@ -574,12 +688,12 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
574
688
  border-color: var(--graview-accent);
575
689
  color: var(--graview-accent);
576
690
  }
577
- /* The press: the whole frame, laid over the picture and the title rather than
578
- around them, so the lens drawn small never sits inside a button. */
691
+ ${ /* The press: the whole frame, laid over the picture and the title rather than
692
+ around them, so the lens drawn small never sits inside a button. */""}
579
693
  .graview-drive-in-thumb-press {
580
694
  position: absolute;
581
695
  inset: -1px;
582
- /* It fills its frame, and says the frame's floor itself: a target is sized where it is declared. */
696
+ ${ /* It fills its frame, and says the frame's floor itself: a target is sized where it is declared. */""}
583
697
  min-height: max(1.75rem, 28px);
584
698
  margin: 0;
585
699
  padding: 0;
@@ -588,7 +702,7 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
588
702
  background: transparent;
589
703
  box-shadow: none;
590
704
  cursor: pointer;
591
- /* The card's own floor, stated: it covers the card, and the card is at least this tall. */
705
+ ${ /* The card's own floor, stated: it covers the card, and the card is at least this tall. */""}
592
706
  min-height: max(1.75rem, 28px);
593
707
  }
594
708
  .graview-drive-in-thumb-press:focus-visible {
@@ -624,20 +738,20 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
624
738
  font-size: 0.75rem;
625
739
  line-height: 1.2;
626
740
  white-space: nowrap;
627
- /* Its own frame's width: two pictures share the marquee, and two names
628
- each allowed the width of one picture ran into each other. */
741
+ ${ /* Its own frame's width: two pictures share the marquee, and two names
742
+ each allowed the width of one picture ran into each other. */""}
629
743
  max-width: 100%;
630
744
  overflow: hidden;
631
745
  text-overflow: ellipsis;
632
746
  }
633
- /* THE BILLBOARD'S FULL-SCREEN CONTROL: the one way down from a picture. */
634
- /* THE RAIL A BILLBOARD IS MOVED BY: a title bar, in the board's own frame
635
- ink, along its top edge. Positioned like the full-screen control beside
636
- it — the host wraps its children, so the rail is a grandchild of the
637
- screen box and a child selector never reaches it. Wide enough to be an
638
- easy target, short enough that the picture underneath is still what you
639
- see, and present only at altitude, because only up there is the board
640
- standing on a plot it could be moved around. */
747
+ ${ /* THE BILLBOARD'S FULL-SCREEN CONTROL: the one way down from a picture. */""}
748
+ ${ /* THE RAIL A BILLBOARD IS MOVED BY: a title bar, in the board's own frame
749
+ ink, along its top edge. Positioned like the full-screen control beside
750
+ it — the host wraps its children, so the rail is a grandchild of the
751
+ screen box and a child selector never reaches it. Wide enough to be an
752
+ easy target, short enough that the picture underneath is still what you
753
+ see, and present only at altitude, because only up there is the board
754
+ standing on a plot it could be moved around. */""}
641
755
  .graview-screen-grip {
642
756
  display: none;
643
757
  }
@@ -649,15 +763,15 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
649
763
  left: 0;
650
764
  right: 0;
651
765
  top: 0;
652
- /* Drawn height, not CSS height: a district's plane is scaled down at
653
- altitude, and 14 here reached the screen as an eight-pixel strip that
654
- took three attempts to catch. */
766
+ ${ /* Drawn height, not CSS height: a district's plane is scaled down at
767
+ altitude, and 14 here reached the screen as an eight-pixel strip that
768
+ took three attempts to catch. */""}
655
769
  height: 32px;
656
770
  padding: 0 6px 0 12px;
657
771
  box-sizing: border-box;
658
772
  cursor: grab;
659
- /* A title bar in the panel's own colours, not a grey strip: the board is
660
- a window onto the picture, and its bar reads as the window's. */
773
+ ${ /* A title bar in the panel's own colours, not a grey strip: the board is
774
+ a window onto the picture, and its bar reads as the window's. */""}
661
775
  background: var(--graview-panel-muted);
662
776
  border-bottom: 1px solid var(--graview-edge);
663
777
  z-index: 3;
@@ -703,11 +817,11 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
703
817
  color: var(--graview-accent);
704
818
  }
705
819
 
706
- /* THE OTHERS: people and their agents in the city, each a small figure in
707
- the scene's own line vocabulary with a name under it. They move by a
708
- transition on transform — one number, the layout tween's curve — so a
709
- quiet city runs nothing. This tab's own seat is not drawn here: the
710
- companion on the frame is where it speaks. */
820
+ ${ /* THE OTHERS: people and their agents in the city, each a small figure in
821
+ the scene's own line vocabulary with a name under it. They move by a
822
+ transition on transform — one number, the layout tween's curve — so a
823
+ quiet city runs nothing. This tab's own seat is not drawn here: the
824
+ companion on the frame is where it speaks. */""}
711
825
  .graview-occupants {
712
826
  position: absolute;
713
827
  inset: 0;
@@ -767,9 +881,9 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
767
881
  color: var(--graview-ink-muted);
768
882
  pointer-events: none;
769
883
  }
770
- /* ANOTHER PERSON, on your map: a head and shoulders in their own hue, at
771
- the plot their stop names or in the audience row of the showing they are
772
- watching. Press to follow them; their name is under them like a robot's. */
884
+ ${ /* ANOTHER PERSON, on your map: a head and shoulders in their own hue, at
885
+ the plot their stop names or in the audience row of the showing they are
886
+ watching. Press to follow them; their name is under them like a robot's. */""}
773
887
  .graview-figure[data-graview-person] .graview-figure-body {
774
888
  left: -11px;
775
889
  top: -24px;
@@ -784,11 +898,11 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
784
898
  .graview-figure[data-graview-person][data-graview-followed] .graview-figure-body {
785
899
  color: var(--graview-accent);
786
900
  }
787
- /* Their robot, beside them, captioned as theirs. */
901
+ ${ /* Their robot, beside them, captioned as theirs. */""}
788
902
  .graview-figure[data-graview-theirs] .graview-figure-body {
789
903
  opacity: 0.85;
790
904
  }
791
- /* More than a row can hold, and the anonymous: a number where they stand. */
905
+ ${ /* More than a row can hold, and the anonymous: a number where they stand. */""}
792
906
  .graview-figure-count {
793
907
  position: absolute;
794
908
  transform: translate(-50%, -100%);
@@ -801,7 +915,7 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
801
915
  white-space: nowrap;
802
916
  pointer-events: auto;
803
917
  }
804
- /* What somebody else is pointing at, outlined in their colour. */
918
+ ${ /* What somebody else is pointing at, outlined in their colour. */""}
805
919
  .graview-presence-over {
806
920
  position: absolute;
807
921
  border: 2px solid hsl(var(--graview-hue, 200) 55% 52%);
@@ -810,7 +924,7 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
810
924
  opacity: 0.75;
811
925
  transition: left 200ms ease, top 200ms ease, width 200ms ease, height 200ms ease;
812
926
  }
813
- /* Off the visible ground: an indicator at the border, pointing at it. */
927
+ ${ /* Off the visible ground: an indicator at the border, pointing at it. */""}
814
928
  .graview-figure-edge {
815
929
  position: absolute;
816
930
  min-height: max(1.5rem, 24px);
@@ -839,14 +953,14 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
839
953
  justify-content: flex-start;
840
954
  max-width: none;
841
955
  }
842
- /* An OPENED district is a PANEL, not a pill with a list stuffed in it:
843
- name and count share the header line, the roster sits under a hairline,
844
- and the block behind fades — the plate IS the district while it is
845
- open, so no roof pokes out above the roster. */
956
+ ${ /* An OPENED district is a PANEL, not a pill with a list stuffed in it:
957
+ name and count share the header line, the roster sits under a hairline,
958
+ and the block behind fades — the plate IS the district while it is
959
+ open, so no roof pokes out above the roster. */""}
846
960
  [data-graview-altitude] .graview-kind-face[data-graview-opened] {
847
- /* A header that WRAPS rather than a grid that squeezes: the name's column
848
- was minmax(0, 1fr) beside the count's auto, so "VEHICLES" beside
849
- "291 · +29 past · close" got 25 pixels and the count was drawn over it. */
961
+ ${ /* A header that WRAPS rather than a grid that squeezes: the name's column
962
+ was minmax(0, 1fr) beside the count's auto, so "VEHICLES" beside
963
+ "291 · +29 past · close" got 25 pixels and the count was drawn over it. */""}
850
964
  display: flex !important;
851
965
  flex-wrap: wrap;
852
966
  justify-content: flex-start !important;
@@ -869,9 +983,9 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
869
983
  opacity: calc(var(--graview-altitude) * 0.22);
870
984
  }
871
985
 
872
- /* WHAT KIND OF THING THIS IS, astride the focus panel's top-right edge —
873
- the kind's dot and its name, the same thread the chips and the legend
874
- carry. Scene chrome, so no view has to remember to say it. */
986
+ ${ /* WHAT KIND OF THING THIS IS, astride the focus panel's top-right edge —
987
+ the kind's dot and its name, the same thread the chips and the legend
988
+ carry. Scene chrome, so no view has to remember to say it. */""}
875
989
  .graview-kind-tag {
876
990
  position: absolute;
877
991
  top: -9px;
@@ -882,8 +996,8 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
882
996
  gap: 5px;
883
997
  padding: 2px 8px;
884
998
  border-radius: 999px;
885
- /* The kind's own hue on the border and the words, so the tag and the
886
- district it belongs to read as one thread. */
999
+ ${ /* The kind's own hue on the border and the words, so the tag and the
1000
+ district it belongs to read as one thread. */""}
887
1001
  border: 1px solid hsl(var(--graview-hue, 200) 45% var(--graview-tint-lightness) / 0.55);
888
1002
  color: hsl(var(--graview-hue, 200) 45% calc(var(--graview-tint-lightness) + ${scheme === "light" ? "-32%" : "28%"}));
889
1003
  background: var(--graview-float);
@@ -895,28 +1009,28 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
895
1009
  pointer-events: none;
896
1010
  }
897
1011
 
898
- /* A LINE UNDER THE POINTER says it will take the press: the invisible hit
899
- run ghosts in, so editability is discoverable by hovering the relation
900
- itself rather than by rumor. */
1012
+ ${ /* A LINE UNDER THE POINTER says it will take the press: the invisible hit
1013
+ run ghosts in, so editability is discoverable by hovering the relation
1014
+ itself rather than by rumor. */""}
901
1015
  .graview-edge-hit:hover {
902
1016
  stroke: var(--graview-accent);
903
1017
  opacity: 0.3;
904
1018
  }
905
1019
 
906
- /* THE DISTRICTS THE ROW COULD NOT HOLD.
907
- Not a district: no figure, no count, no tint of its own. A card that is
908
- one control — how many more, and a press — and, open, a panel above the
909
- row naming every district with what it holds. Solid rather than dashed
910
- and faded: a dashed, translucent card read as a placeholder, and the only
911
- way to five districts should not look like something that failed to load. */
912
- /* A RELATION THE BAND COULD NOT HOLD: a group with its count and first names,
913
- or the door to the rest. A card like the others, never the kind's lens small. */
1020
+ ${ /* THE DISTRICTS THE ROW COULD NOT HOLD.
1021
+ Not a district: no figure, no count, no tint of its own. A card that is
1022
+ one control — how many more, and a press — and, open, a panel above the
1023
+ row naming every district with what it holds. Solid rather than dashed
1024
+ and faded: a dashed, translucent card read as a placeholder, and the only
1025
+ way to five districts should not look like something that failed to load. */""}
1026
+ ${ /* A RELATION THE BAND COULD NOT HOLD: a group with its count and first names,
1027
+ or the door to the rest. A card like the others, never the kind's lens small. */""}
914
1028
  .graview-band-group {
915
1029
  display: grid;
916
1030
  align-content: center;
917
1031
  gap: 2px;
918
1032
  height: 100%;
919
- /* A card you press, held to the floor every pressable piece of chrome keeps. */
1033
+ ${ /* A card you press, held to the floor every pressable piece of chrome keeps. */""}
920
1034
  min-height: max(1.75rem, 28px);
921
1035
  box-sizing: border-box;
922
1036
  padding: 6px 10px;
@@ -1014,16 +1128,16 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1014
1128
  margin-left: auto;
1015
1129
  font-size: 0.8125rem;
1016
1130
  }
1017
- /* The panel stands above the card, inside the scene, and never clips: the
1018
- card's box is a district's height, which holds a count and not a list. */
1131
+ ${ /* The panel stands above the card, inside the scene, and never clips: the
1132
+ card's box is a district's height, which holds a count and not a list. */""}
1019
1133
  .graview-beyond-list {
1020
1134
  position: absolute;
1021
1135
  left: 0;
1022
1136
  bottom: calc(100% + 6px);
1023
- /* On the ground, over every plane — the focused card on plane zero
1024
- painted over a panel drawn on plane two, and a menu under a card is
1025
- no menu. Above the zoom control too, which is the only other thing
1026
- that stands on the ground. */
1137
+ ${ /* On the ground, over every plane — the focused card on plane zero
1138
+ painted over a panel drawn on plane two, and a menu under a card is
1139
+ no menu. Above the zoom control too, which is the only other thing
1140
+ that stands on the ground. */""}
1027
1141
  z-index: 60;
1028
1142
  margin: 0;
1029
1143
  padding: 6px;
@@ -1031,8 +1145,8 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1031
1145
  display: flex;
1032
1146
  flex-direction: column;
1033
1147
  gap: 1px;
1034
- /* Its own width, not the ground's: portalled, a percentage here is the
1035
- whole scene. */
1148
+ ${ /* Its own width, not the ground's: portalled, a percentage here is the
1149
+ whole scene. */""}
1036
1150
  min-width: 200px;
1037
1151
  max-width: min(280px, 92%);
1038
1152
  max-height: 60vh;
@@ -1047,14 +1161,14 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1047
1161
  align-items: center;
1048
1162
  gap: 10px;
1049
1163
  width: 100%;
1050
- /* A FINGERTIP WHERE IT IS ACTUALLY DRAWN, not where it was designed.
1051
- Every other control in this sheet is floored at 24 and the audit divides
1052
- by the plane's scale before judging it, which is right for a control
1053
- that sits ON a large target: the chip's disclosure is small, and the
1054
- card behind it is the size of a card. These names are not that. They are
1055
- the ONLY way to the districts the row could not hold, and plane two is
1056
- drawn at 0.90 — so a designed 24 meets a finger as 21.7. Designed at 28
1057
- it is drawn at 25, which is the number the floor was always about. */
1164
+ ${ /* A FINGERTIP WHERE IT IS ACTUALLY DRAWN, not where it was designed.
1165
+ Every other control in this sheet is floored at 24 and the audit divides
1166
+ by the plane's scale before judging it, which is right for a control
1167
+ that sits ON a large target: the chip's disclosure is small, and the
1168
+ card behind it is the size of a card. These names are not that. They are
1169
+ the ONLY way to the districts the row could not hold, and plane two is
1170
+ drawn at 0.90 — so a designed 24 meets a finger as 21.7. Designed at 28
1171
+ it is drawn at 25, which is the number the floor was always about. */""}
1058
1172
  min-height: max(1.75rem, 28px);
1059
1173
  padding: 0 8px;
1060
1174
  border: none;
@@ -1083,13 +1197,13 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1083
1197
  color: var(--graview-ink-faint);
1084
1198
  }
1085
1199
 
1086
- /* The way into the archive, on the card that fed it: quiet, but a real
1087
- control at a real size. */
1200
+ ${ /* The way into the archive, on the card that fed it: quiet, but a real
1201
+ control at a real size. */""}
1088
1202
  .graview-kind-past {
1089
1203
  display: inline-flex;
1090
1204
  align-items: center;
1091
1205
  flex: 0 0 auto;
1092
- /* The same floor as the disclosure beside it — see .graview-kind-open. */
1206
+ ${ /* The same floor as the disclosure beside it — see .graview-kind-open. */""}
1093
1207
  min-height: max(1.5rem, 24px);
1094
1208
  padding: 1px 8px;
1095
1209
  margin: -3px 0;
@@ -1107,10 +1221,10 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1107
1221
  border-color: var(--graview-accent-dim);
1108
1222
  }
1109
1223
 
1110
- /* A SEARCH OVER THE CITY. The districts the words found are lit and say how
1111
- many; the rest recede — the same dimming a selection's reach has always
1112
- used, so a search reads as "where the thing is", not as a new mode. The
1113
- count is the way in: a real control, the words carried down. */
1224
+ ${ /* A SEARCH OVER THE CITY. The districts the words found are lit and say how
1225
+ many; the rest recede — the same dimming a selection's reach has always
1226
+ used, so a search reads as "where the thing is", not as a new mode. The
1227
+ count is the way in: a real control, the words carried down. */""}
1114
1228
  .graview-kind-card[data-graview-emphasis="dimmed"] {
1115
1229
  opacity: 0.42;
1116
1230
  transition: opacity 160ms ease;
@@ -1143,27 +1257,27 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1143
1257
  .graview-kind-card[data-graview-emphasis="dimmed"] { transition: none; }
1144
1258
  }
1145
1259
 
1146
- /* Chrome that arrives with a state settles in rather than popping. */
1260
+ ${ /* Chrome that arrives with a state settles in rather than popping. */""}
1147
1261
  @keyframes graview-settle {
1148
1262
  from { opacity: 0; transform: translateY(7px); }
1149
1263
  }
1150
1264
 
1151
- /* A district STANDS: an isometric block — roof, two shaded walls — whose
1152
- height is its population. Always in the tree, faded and settled by the
1153
- altitude number: rising, each block grows up out of its card while the
1154
- card flies to its ring stop — a morph, not a cut. At altitude zero it is
1155
- fully transparent and costs nothing. */
1265
+ ${ /* A district STANDS: an isometric block — roof, two shaded walls — whose
1266
+ height is its population. Always in the tree, faded and settled by the
1267
+ altitude number: rising, each block grows up out of its card while the
1268
+ card flies to its ring stop — a morph, not a cut. At altitude zero it is
1269
+ fully transparent and costs nothing. */""}
1156
1270
  .graview-kind-block {
1157
1271
  display: block;
1158
- /* Architecture, not a control: clicks fall through to the card, and an
1159
- invisible in-stack block must never sit over a neighbour's tuck. */
1272
+ ${ /* Architecture, not a control: clicks fall through to the card, and an
1273
+ invisible in-stack block must never sit over a neighbour's tuck. */""}
1160
1274
  pointer-events: none;
1161
1275
  position: absolute;
1162
1276
  left: 8%;
1163
1277
  bottom: 2px;
1164
1278
  width: 84%;
1165
1279
  height: auto;
1166
- /* Under a marquee the block keeps out of its band: the drawing scales down inside the box. */
1280
+ ${ /* Under a marquee the block keeps out of its band: the drawing scales down inside the box. */""}
1167
1281
  max-height: calc(100% - var(--graview-marquee-room, 0px));
1168
1282
  opacity: var(--graview-altitude);
1169
1283
  transform: translateY(calc((1 - var(--graview-altitude)) * 18px));
@@ -1181,64 +1295,64 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1181
1295
  fill: hsl(var(--graview-hue, 200) ${scheme === "light" ? "34% 55%" : "38% 13%"});
1182
1296
  }
1183
1297
 
1184
- /* WHERE THE KIND HAS ITS OWN DRAWING, the drawing is the building.
1185
- Same footprint as the block, same ground line, same cast shadow — the
1186
- difference is that the district is now a person, a plot or a vehicle
1187
- rather than one more box. Size carries the population the box's height
1188
- used to: the rise the card computed, in a channel a drawing can use.
1189
-
1190
- Stroke weight is set HERE rather than in the art, because the art is
1191
- drawn to read at twenty pixels and a 1.4-unit stroke on a 24-unit box
1192
- becomes a six-pixel marker line at a hundred. Thinned to a drafting
1193
- line, which is what a blueprint of a thing looks like. */
1298
+ ${ /* WHERE THE KIND HAS ITS OWN DRAWING, the drawing is the building.
1299
+ Same footprint as the block, same ground line, same cast shadow — the
1300
+ difference is that the district is now a person, a plot or a vehicle
1301
+ rather than one more box. Size carries the population the box's height
1302
+ used to: the rise the card computed, in a channel a drawing can use.
1303
+
1304
+ Stroke weight is set HERE rather than in the art, because the art is
1305
+ drawn to read at twenty pixels and a 1.4-unit stroke on a 24-unit box
1306
+ becomes a six-pixel marker line at a hundred. Thinned to a drafting
1307
+ line, which is what a blueprint of a thing looks like. */""}
1194
1308
  .graview-kind-landmark {
1195
1309
  display: block;
1196
1310
  left: 50%;
1197
- /* The block's own two pixels of ground clearance, kept: at altitude zero
1198
- every block is pushed eighteen pixels down as part of the morph, and
1199
- without them the drawing hangs two pixels past the bottom of the scene
1200
- and gives the whole page a scrollbar's worth of overflow. */
1311
+ ${ /* The block's own two pixels of ground clearance, kept: at altitude zero
1312
+ every block is pushed eighteen pixels down as part of the morph, and
1313
+ without them the drawing hangs two pixels past the bottom of the scene
1314
+ and gives the whole page a scrollbar's worth of overflow. */""}
1201
1315
  bottom: 2px;
1202
1316
  aspect-ratio: 1;
1203
- /* Sized by the card's HEIGHT, not its width: a district card is wider
1204
- than it is tall, and a square drawing at 96% of the width stood a third
1205
- of itself above the card and back through the nameplate. Population is
1206
- in the drawing's size either way — the same rise the box's height
1207
- carried, 10 for a district of one and 46 for the largest. */
1317
+ ${ /* Sized by the card's HEIGHT, not its width: a district card is wider
1318
+ than it is tall, and a square drawing at 96% of the width stood a third
1319
+ of itself above the card and back through the nameplate. Population is
1320
+ in the drawing's size either way — the same rise the box's height
1321
+ carried, 10 for a district of one and 46 for the largest. */""}
1208
1322
  height: calc((100% - var(--graview-marquee-room, 0px)) * (0.72 + var(--graview-rise, 24) * 0.008));
1209
1323
  width: auto;
1210
- /* AND IT KEEPS UP WITH THE WORDS. The card is laid out in pixels off the
1211
- stage and the nameplate is sized in rem, so a reader on Largest doubled
1212
- every name in the city while every drawing under one stayed exactly the
1213
- size it was — a postage stamp under a headline. A floor in em ties the
1214
- drawing to the same number the names follow; at the browser's own size
1215
- it is below what the card already gives and nothing moves.
1216
-
1217
- Capped at the card, because a floor alone overflowed it: the drawings
1218
- grew past the box they stand in and were sliced off at the bottom
1219
- edge — a plot that reads as a V rather than a bed. The card's own
1220
- height is what the picture can actually show, and the CARD is the thing
1221
- that still does not follow the reader's size (see below).
1222
-
1223
- (No back ticks in here: this whole stylesheet is a template literal,
1224
- and one of them ends it.) */
1324
+ ${ /* AND IT KEEPS UP WITH THE WORDS. The card is laid out in pixels off the
1325
+ stage and the nameplate is sized in rem, so a reader on Largest doubled
1326
+ every name in the city while every drawing under one stayed exactly the
1327
+ size it was — a postage stamp under a headline. A floor in em ties the
1328
+ drawing to the same number the names follow; at the browser's own size
1329
+ it is below what the card already gives and nothing moves.
1330
+
1331
+ Capped at the card, because a floor alone overflowed it: the drawings
1332
+ grew past the box they stand in and were sliced off at the bottom
1333
+ edge — a plot that reads as a V rather than a bed. The card's own
1334
+ height is what the picture can actually show, and the CARD is the thing
1335
+ that still does not follow the reader's size (see below).
1336
+
1337
+ (No back ticks in here: this whole stylesheet is a template literal,
1338
+ and one of them ends it.) */""}
1225
1339
  min-height: min(5em, calc(96% - var(--graview-marquee-room, 0px)));
1226
- /* The morph is a GROWTH from the ground line, not a drop: a block slides
1227
- eighteen pixels down at altitude zero and grows up out of the card, and
1228
- a drawing given the same treatment hangs below the card it belongs to —
1229
- two pixels past the bottom of the scene on the lowest row, which is a
1230
- scrollbar on every ground-level screen in the app. Scaling from the
1231
- drawing's own feet is the same reading and costs nothing below. */
1340
+ ${ /* The morph is a GROWTH from the ground line, not a drop: a block slides
1341
+ eighteen pixels down at altitude zero and grows up out of the card, and
1342
+ a drawing given the same treatment hangs below the card it belongs to —
1343
+ two pixels past the bottom of the scene on the lowest row, which is a
1344
+ scrollbar on every ground-level screen in the app. Scaling from the
1345
+ drawing's own feet is the same reading and costs nothing below. */""}
1232
1346
  transform-origin: bottom center;
1233
1347
  transform: translateX(-50%) scale(calc(0.55 + var(--graview-altitude) * 0.45));
1234
- /* A cast shadow belongs to a solid; on a line drawing it is a blurred
1235
- second copy of every stroke. The drawing keeps a hint of one so it
1236
- still stands on the lattice rather than floating over it. */
1348
+ ${ /* A cast shadow belongs to a solid; on a line drawing it is a blurred
1349
+ second copy of every stroke. The drawing keeps a hint of one so it
1350
+ still stands on the lattice rather than floating over it. */""}
1237
1351
  filter: drop-shadow(${scheme === "light" ? "6px 5px 7px rgba(20,30,32,0.16)" : "7px 6px 9px rgba(0,0,0,0.45)"});
1238
1352
  }
1239
- /* The nameplate floats ABOVE a drawing rather than standing on it. On a box
1240
- the pill sits on the roof, which is what a label does over a building; on
1241
- a figure the same 2% put it across the head. */
1353
+ ${ /* The nameplate floats ABOVE a drawing rather than standing on it. On a box
1354
+ the pill sits on the roof, which is what a label does over a building; on
1355
+ a figure the same 2% put it across the head. */""}
1242
1356
 
1243
1357
  .graview-kind-landmark [data-graview-figure] {
1244
1358
  width: 100% !important;
@@ -1251,29 +1365,29 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1251
1365
  stroke-width: 0.85;
1252
1366
  }
1253
1367
 
1254
- /* From altitude the card's face becomes the district's NAMEPLATE: an
1255
- upright pill standing on the roof, the way a label floats over a building
1256
- in any city view — the block carries the architecture, the pill carries
1257
- the words. Inline styles drew the in-stack card, so the pill overrides
1258
- must outrank them. */
1368
+ ${ /* From altitude the card's face becomes the district's NAMEPLATE: an
1369
+ upright pill standing on the roof, the way a label floats over a building
1370
+ in any city view — the block carries the architecture, the pill carries
1371
+ the words. Inline styles drew the in-stack card, so the pill overrides
1372
+ must outrank them. */""}
1259
1373
  .graview-kind-face {
1260
1374
  transition: border-radius 640ms cubic-bezier(0.33, 0, 0.2, 1),
1261
1375
  padding 640ms cubic-bezier(0.33, 0, 0.2, 1),
1262
1376
  box-shadow 640ms ease;
1263
1377
  }
1264
- /* A SIGNPOST at the plot's front corner. From altitude the nameplate stood
1265
- at the top of the card — over the back row of the village — and the
1266
- screen had to clear it. It is planted at the front vertex of the tile
1267
- now, on a short post, where a sign stands at the entrance to a place;
1268
- the scene says where that vertex is in --graview-front-y. */
1378
+ ${ /* A SIGNPOST at the plot's front corner. From altitude the nameplate stood
1379
+ at the top of the card — over the back row of the village — and the
1380
+ screen had to clear it. It is planted at the front vertex of the tile
1381
+ now, on a short post, where a sign stands at the entrance to a place;
1382
+ the scene says where that vertex is in --graview-front-y. */""}
1269
1383
  [data-graview-altitude] .graview-kind-face {
1270
1384
  position: absolute !important;
1271
1385
  left: 50% !important;
1272
1386
  top: 2% !important;
1273
1387
  transform: translateX(-50%);
1274
1388
  width: max-content;
1275
- /* Wider than the block when the name is: a label overflows its building
1276
- the way a map label does. "REQUIRE / MENTS" on two lines does not. */
1389
+ ${ /* Wider than the block when the name is: a label overflows its building
1390
+ the way a map label does. "REQUIRE / MENTS" on two lines does not. */""}
1277
1391
  max-width: none;
1278
1392
  white-space: nowrap;
1279
1393
  height: auto !important;
@@ -1297,38 +1411,38 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1297
1411
  height: 10px;
1298
1412
  background: var(--graview-ink-faint);
1299
1413
  }
1300
- /* A landmark WITHOUT a plot — a nested card — keeps its plate floating
1301
- above the drawing rather than across its head; one on a plot stands at
1302
- the signpost like every other district (the rule above). */
1414
+ ${ /* A landmark WITHOUT a plot — a nested card — keeps its plate floating
1415
+ above the drawing rather than across its head; one on a plot stands at
1416
+ the signpost like every other district (the rule above). */""}
1303
1417
  [data-graview-altitude] [data-graview-landmark]:not([data-graview-plot] *) .graview-kind-face {
1304
1418
  top: 0 !important;
1305
1419
  transform: translate(-50%, calc(-100% - 7px));
1306
1420
  }
1307
- /* The drive-in's board hangs UNDER the signpost, in the ground the layout
1308
- reserved for it below the tile's front corner, not over the village. */
1421
+ ${ /* The drive-in's board hangs UNDER the signpost, in the ground the layout
1422
+ reserved for it below the tile's front corner, not over the village. */""}
1309
1423
  [data-graview-altitude] .graview-drive-in {
1310
1424
  top: calc(var(--graview-front-y, 42px) + 12px);
1311
1425
  }
1312
- /* An OPENED district's listing takes the ground under the signpost; the
1313
- board steps up over the village, which the listing covers anyway. */
1426
+ ${ /* An OPENED district's listing takes the ground under the signpost; the
1427
+ board steps up over the village, which the listing covers anyway. */""}
1314
1428
  [data-graview-altitude] .graview-kind-face[data-graview-opened] ~ .graview-drive-in {
1315
1429
  top: calc(var(--graview-front-y, 42px) - 22px - var(--graview-marquee-room, 0px) + 8px);
1316
1430
  }
1317
- /* THE LANDMARK STANDS IN THE SQUARE: its feet at the plot's centre, among
1318
- the buildings, rather than at the card's bottom edge — which, once the
1319
- card grew for a board, was out in the road in front of the village. */
1431
+ ${ /* THE LANDMARK STANDS IN THE SQUARE: its feet at the plot's centre, among
1432
+ the buildings, rather than at the card's bottom edge — which, once the
1433
+ card grew for a board, was out in the road in front of the village. */""}
1320
1434
  [data-graview-altitude] [data-graview-plot] .graview-kind-landmark {
1321
1435
  bottom: auto;
1322
1436
  top: calc(var(--graview-centre-y, 50%) + 10px);
1323
1437
  transform: translate(-50%, -100%) scale(calc(0.55 + var(--graview-altitude) * 0.45));
1324
1438
  }
1325
- /* ZOOM, in the ground's corner: the way a map carries its own. Two
1326
- fingertip-sized buttons and the level between them, shown from altitude. */
1439
+ ${ /* ZOOM, in the ground's corner: the way a map carries its own. Two
1440
+ fingertip-sized buttons and the level between them, shown from altitude. */""}
1327
1441
  .graview-zoom {
1328
1442
  position: absolute;
1329
1443
  right: 16px;
1330
1444
  bottom: 16px;
1331
- /* Above the occupants: a robot walking past a control must not cover it. */
1445
+ ${ /* Above the occupants: a robot walking past a control must not cover it. */""}
1332
1446
  z-index: 8;
1333
1447
  display: inline-flex;
1334
1448
  align-items: center;
@@ -1366,16 +1480,16 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1366
1480
  font-variant-numeric: tabular-nums;
1367
1481
  }
1368
1482
 
1369
- /* THE SCREEN IS A BILLBOARD at the back of the village: a frame, and two
1370
- posts into the ground at its foot. */
1371
- /* On the NATURAL BOX, which is the picture now: the layout cuts the
1372
- billboard to what the lens drew (measured by the scene), never shorter
1373
- than a screen's worth — so the box is the picture, and an empty lens is a
1374
- header over an empty screen rather than a strip floating over the
1375
- village. The frame used to sit on the drawing itself, from the days the
1376
- box was as tall as the window with the picture in its top third. It
1377
- carries the panel's own ground so the empty part of a screen is a screen
1378
- and not the field showing through a frame. */
1483
+ ${ /* THE SCREEN IS A BILLBOARD at the back of the village: a frame, and two
1484
+ posts into the ground at its foot. */""}
1485
+ ${ /* On the NATURAL BOX, which is the picture now: the layout cuts the
1486
+ billboard to what the lens drew (measured by the scene), never shorter
1487
+ than a screen's worth — so the box is the picture, and an empty lens is a
1488
+ header over an empty screen rather than a strip floating over the
1489
+ village. The frame used to sit on the drawing itself, from the days the
1490
+ box was as tall as the window with the picture in its top third. It
1491
+ carries the panel's own ground so the empty part of a screen is a screen
1492
+ and not the field showing through a frame. */""}
1379
1493
  [data-graview-altitude] [data-graview-screen] > [data-graview-natural],
1380
1494
  [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag) {
1381
1495
  outline: 2px solid color-mix(in oklab, var(--graview-ink) 60%, var(--graview-panel));
@@ -1401,31 +1515,31 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1401
1515
  [data-graview-altitude] [data-graview-screen] > [data-graview-natural]::after,
1402
1516
  [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag)::after { right: 22%; }
1403
1517
 
1404
- /* A thing inside a view that is itself a thing: an event in a calendar, a
1405
- person in a list. It has to look reachable, and it has to SHOW focus —
1406
- these are the primary way anyone moves through the graph, so a keyboard
1407
- user who cannot see where they are is stuck. */
1408
- /* A card someone dragged into place. Marked, not decorated: a dotted tie to
1409
- say this position is held rather than computed. */
1410
- /* On the CHILD, not the host: the host is the layout's box, and a view
1411
- that sizes to its content (a zoomed record, a fit panel) fills only part
1412
- of it — a dashed box around the empty remainder read as a drawing
1413
- mistake, not a mark. */
1414
- /* And never on the natural box either — a view drawn scaled sits inside a
1415
- box the size of the whole scene, and the mark belongs on the drawing, not
1416
- on the box; nor on the kind tag, which is a label and not the thing. */
1518
+ ${ /* A thing inside a view that is itself a thing: an event in a calendar, a
1519
+ person in a list. It has to look reachable, and it has to SHOW focus —
1520
+ these are the primary way anyone moves through the graph, so a keyboard
1521
+ user who cannot see where they are is stuck. */""}
1522
+ ${ /* A card someone dragged into place. Marked, not decorated: a dotted tie to
1523
+ say this position is held rather than computed. */""}
1524
+ ${ /* On the CHILD, not the host: the host is the layout's box, and a view
1525
+ that sizes to its content (a zoomed record, a fit panel) fills only part
1526
+ of it — a dashed box around the empty remainder read as a drawing
1527
+ mistake, not a mark. */""}
1528
+ ${ /* And never on the natural box either — a view drawn scaled sits inside a
1529
+ box the size of the whole scene, and the mark belongs on the drawing, not
1530
+ on the box; nor on the kind tag, which is a label and not the thing. */""}
1417
1531
  [data-graview-pinned] > :not([data-graview-natural]):not(.graview-kind-tag),
1418
1532
  [data-graview-pinned] > [data-graview-natural] > * {
1419
1533
  outline: 1px dashed var(--graview-edge-bright);
1420
1534
  outline-offset: 3px;
1421
1535
  border-radius: 12px;
1422
1536
  }
1423
- /* AND NOT FROM ALTITUDE, where a district is a village on a plot and its
1424
- card is a box with nothing drawn in it: the dashed outline was the only
1425
- visible part, so a hand-placed district read as an empty rounded
1426
- rectangle sitting on the ground — several of them, in a picture that had
1427
- no rectangles in it. The plot's own kerb goes dashed up here, which is
1428
- the same fact said where the district actually is. */
1537
+ ${ /* AND NOT FROM ALTITUDE, where a district is a village on a plot and its
1538
+ card is a box with nothing drawn in it: the dashed outline was the only
1539
+ visible part, so a hand-placed district read as an empty rounded
1540
+ rectangle sitting on the ground — several of them, in a picture that had
1541
+ no rectangles in it. The plot's own kerb goes dashed up here, which is
1542
+ the same fact said where the district actually is. */""}
1429
1543
  [data-graview-altitude] [data-graview-pinned] > :not([data-graview-natural]):not(.graview-kind-tag),
1430
1544
  [data-graview-altitude] [data-graview-pinned] > [data-graview-natural] > * {
1431
1545
  outline: none;
@@ -1443,10 +1557,10 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1443
1557
  outline-offset: 2px;
1444
1558
  border-radius: 7px;
1445
1559
  }
1446
- /* On a board the keyboard ring hugs the DISC, not the disc-plus-label
1447
- group: a rectangle drawn around a circle read as a mystery box on the
1448
- pitch ("why does Left Midfield have this box?"), when all it ever said
1449
- was "the keyboard is here". */
1560
+ ${ /* On a board the keyboard ring hugs the DISC, not the disc-plus-label
1561
+ group: a rectangle drawn around a circle read as a mystery box on the
1562
+ pitch ("why does Left Midfield have this box?"), when all it ever said
1563
+ was "the keyboard is here". */""}
1450
1564
  [data-graview-slot]:focus-visible {
1451
1565
  outline: none;
1452
1566
  }
@@ -1454,7 +1568,7 @@ code, kbd, samp { font-family: var(--graview-font-mono); }
1454
1568
  box-shadow: 0 0 0 2px var(--graview-ground), 0 0 0 4px var(--graview-accent);
1455
1569
  }
1456
1570
 
1457
- /* A view is a thing you can act on. It should look like one. */
1571
+ ${ /* A view is a thing you can act on. It should look like one. */""}
1458
1572
  [data-graview-view] { cursor: pointer; }
1459
1573
  [data-graview-view]:hover { filter: brightness(${scheme === "light" ? 0.985 : 1.12}); }
1460
1574
  [data-graview-view]:focus-visible {
@@ -1488,25 +1602,25 @@ button:disabled { opacity: 0.45; cursor: default; }
1488
1602
 
1489
1603
  code { color: var(--graview-ink-muted); font-size: 0.8125rem; letter-spacing: 0.02em; }
1490
1604
 
1491
- /* A view host, once the scene has placed it. The transition is on filter
1492
- only — never on layout properties, which would make every navigation
1493
- reflow the page. */
1605
+ ${ /* A view host, once the scene has placed it. The transition is on filter
1606
+ only — never on layout properties, which would make every navigation
1607
+ reflow the page. */""}
1494
1608
  [data-graview-view] {
1495
1609
  transition: filter 260ms cubic-bezier(0.22, 1, 0.36, 1);
1496
1610
  }
1497
1611
 
1498
- /* WHAT YOU CAN PRESS IS WHAT YOU CAN SEE.
1499
-
1500
- A host is the box the LAYOUT gave a view — a band on the ground, the whole
1501
- scene scaled small from altitude — and a view that sizes to its content
1502
- fills only part of it. The rest is invisible, and an invisible box must
1503
- not be a target: a record read from altitude and pinned beside a district
1504
- covered that district's open button with nothing at all, and the button
1505
- stopped answering. So the host itself is out of hit-testing on the DOM
1506
- path and only the drawn content is in; every handler still hears the
1507
- content's events on the way up. The GPU path keeps its own rule: there
1508
- the whole subtree stays out, because the platform's hit-test descending
1509
- into a captured view brings the renderer down. */
1612
+ ${ /* WHAT YOU CAN PRESS IS WHAT YOU CAN SEE.
1613
+
1614
+ A host is the box the LAYOUT gave a view — a band on the ground, the whole
1615
+ scene scaled small from altitude — and a view that sizes to its content
1616
+ fills only part of it. The rest is invisible, and an invisible box must
1617
+ not be a target: a record read from altitude and pinned beside a district
1618
+ covered that district's open button with nothing at all, and the button
1619
+ stopped answering. So the host itself is out of hit-testing on the DOM
1620
+ path and only the drawn content is in; every handler still hears the
1621
+ content's events on the way up. The GPU path keeps its own rule: there
1622
+ the whole subtree stays out, because the platform's hit-test descending
1623
+ into a captured view brings the renderer down. */""}
1510
1624
  [data-graview-stage="dom"] [data-graview-view],
1511
1625
  [data-graview-stage="dom"] [data-graview-view] > [data-graview-natural] {
1512
1626
  pointer-events: none;
@@ -1519,11 +1633,11 @@ code { color: var(--graview-ink-muted); font-size: 0.8125rem; letter-spacing: 0.
1519
1633
  filter: drop-shadow(0 0 14px var(--graview-accent-dim));
1520
1634
  }
1521
1635
 
1522
- /* A node implicated by the last change, whoever made it. The pulse is the
1523
- same for a human edit and an agent edit, because the diff is. */
1524
- /* THE SEAT'S MARK on what it just wrote: its own glyph, in its own hue, at
1525
- the thing's top-right corner. It arrives with the change and fades with
1526
- it; the companion's log is what remembers. */
1636
+ ${ /* A node implicated by the last change, whoever made it. The pulse is the
1637
+ same for a human edit and an agent edit, because the diff is. */""}
1638
+ ${ /* THE SEAT'S MARK on what it just wrote: its own glyph, in its own hue, at
1639
+ the thing's top-right corner. It arrives with the change and fades with
1640
+ it; the companion's log is what remembers. */""}
1527
1641
  .graview-seat-marks {
1528
1642
  position: absolute;
1529
1643
  inset: 0;
@@ -1546,9 +1660,9 @@ code { color: var(--graview-ink-muted); font-size: 0.8125rem; letter-spacing: 0.
1546
1660
  box-shadow: var(--graview-lift-low);
1547
1661
  animation: graview-seat-mark 4000ms ease-out forwards;
1548
1662
  }
1549
- /* A QUESTION THE SEAT ASKED, standing at the node it is about: it says
1550
- itself and waits, because a dot nobody can read is a question nobody
1551
- answers. It does not fade — an unanswered question is still open. */
1663
+ ${ /* A QUESTION THE SEAT ASKED, standing at the node it is about: it says
1664
+ itself and waits, because a dot nobody can read is a question nobody
1665
+ answers. It does not fade — an unanswered question is still open. */""}
1552
1666
  .graview-seat-asking {
1553
1667
  position: absolute;
1554
1668
  transform: translate(-50%, -100%);
@@ -1599,20 +1713,20 @@ code { color: var(--graview-ink-muted); font-size: 0.8125rem; letter-spacing: 0.
1599
1713
  border-radius: 10px;
1600
1714
  }
1601
1715
 
1602
- /* ------------------------------------------------------------ watching
1603
- *
1604
- * From outside the plane stack, activity has somewhere to HAPPEN: a kind
1605
- * lights where an edit landed, an edge pulses where a relation was made or
1606
- * broken, and a flag appears where a rule started failing. All of it is
1607
- * derived from the op log — author, intent, reads and writes — and all of it
1608
- * is drawn by these rules rather than by a frame loop, which is why watching
1609
- * costs nothing while nothing is happening.
1610
- *
1611
- * Who moved is carried in HUE, not in a badge. A person is the accent the
1612
- * whole interface already uses for "you did this"; an agent is a colder cast,
1613
- * so a turn it took on its own is distinguishable at a glance from one you
1614
- * directed; both at once takes both.
1615
- */
1716
+ ${ /* ------------------------------------------------------------ watching
1717
+ *
1718
+ * From outside the plane stack, activity has somewhere to HAPPEN: a kind
1719
+ * lights where an edit landed, an edge pulses where a relation was made or
1720
+ * broken, and a flag appears where a rule started failing. All of it is
1721
+ * derived from the op log — author, intent, reads and writes — and all of it
1722
+ * is drawn by these rules rather than by a frame loop, which is why watching
1723
+ * costs nothing while nothing is happening.
1724
+ *
1725
+ * Who moved is carried in HUE, not in a badge. A person is the accent the
1726
+ * whole interface already uses for "you did this"; an agent is a colder cast,
1727
+ * so a turn it took on its own is distinguishable at a glance from one you
1728
+ * directed; both at once takes both.
1729
+ */""}
1616
1730
  [data-graview-activity] {
1617
1731
  --graview-activity: var(--graview-accent);
1618
1732
  }
@@ -1636,9 +1750,9 @@ code { color: var(--graview-ink-muted); font-size: 0.8125rem; letter-spacing: 0.
1636
1750
  border-radius: 10px;
1637
1751
  }
1638
1752
 
1639
- /* What an agent READ is the half a diff cannot show, and the half that says
1640
- whether to trust what it then did. Quieter than a write on purpose: it is
1641
- evidence of attention, not of a change. */
1753
+ ${ /* What an agent READ is the half a diff cannot show, and the half that says
1754
+ whether to trust what it then did. Quieter than a write on purpose: it is
1755
+ evidence of attention, not of a change. */""}
1642
1756
  @keyframes graview-considered {
1643
1757
  0% { outline-color: transparent; }
1644
1758
  25% { outline-color: var(--graview-activity); }
@@ -1652,15 +1766,15 @@ code { color: var(--graview-ink-muted); font-size: 0.8125rem; letter-spacing: 0.
1652
1766
  animation: graview-considered 1800ms ease-out;
1653
1767
  }
1654
1768
 
1655
- /* A rule that has just begun to fail. It outlives the edit that caused it,
1656
- because the problem does. */
1769
+ ${ /* A rule that has just begun to fail. It outlives the edit that caused it,
1770
+ because the problem does. */""}
1657
1771
  [data-graview-view][data-graview-broke] > * {
1658
1772
  box-shadow: 0 0 0 1px var(--graview-warn), 0 0 22px -6px var(--graview-warn);
1659
1773
  border-radius: 10px;
1660
1774
  }
1661
1775
 
1662
- /* A relation made or broken: both ends were written, so the line between
1663
- them is the thing that changed. */
1776
+ ${ /* A relation made or broken: both ends were written, so the line between
1777
+ them is the thing that changed. */""}
1664
1778
  @keyframes graview-relation {
1665
1779
  0% { stroke-opacity: 0.28; stroke-width: 1.4; }
1666
1780
  30% { stroke-opacity: 1; stroke-width: 3; }
@@ -1670,28 +1784,28 @@ code { color: var(--graview-ink-muted); font-size: 0.8125rem; letter-spacing: 0.
1670
1784
  animation: graview-relation 1200ms cubic-bezier(0.22, 1, 0.36, 1);
1671
1785
  }
1672
1786
 
1673
- /*
1674
- * MOTION, ASKED OF THE SYSTEM AND OVERRIDABLE BY THE PERSON.
1675
- *
1676
- * The system's own preference is the default and always was. The "motion"
1677
- * setting (see readerSettings) stamps data-graview-motion on the root
1678
- * element when — and only when — a reader overrides it: "reduce" turns the same
1679
- * rules on for somebody whose system says otherwise, and "full" turns them
1680
- * off for somebody whose system says reduce and who wants the movement
1681
- * here anyway. Choosing "as your system has it" removes the attribute, so
1682
- * the media query is what answers again.
1683
- *
1684
- * Written as one rule list under two selectors rather than duplicated,
1685
- * because a stylesheet where the two copies can drift is a stylesheet where
1686
- * they will.
1687
- */
1787
+ ${ /*
1788
+ * MOTION, ASKED OF THE SYSTEM AND OVERRIDABLE BY THE PERSON.
1789
+ *
1790
+ * The system's own preference is the default and always was. The "motion"
1791
+ * setting (see readerSettings) stamps data-graview-motion on the root
1792
+ * element when — and only when — a reader overrides it: "reduce" turns the same
1793
+ * rules on for somebody whose system says otherwise, and "full" turns them
1794
+ * off for somebody whose system says reduce and who wants the movement
1795
+ * here anyway. Choosing "as your system has it" removes the attribute, so
1796
+ * the media query is what answers again.
1797
+ *
1798
+ * Written as one rule list under two selectors rather than duplicated,
1799
+ * because a stylesheet where the two copies can drift is a stylesheet where
1800
+ * they will.
1801
+ */""}
1688
1802
  @media (prefers-reduced-motion: reduce) {
1689
1803
  .graview-figure { transition: none; }
1690
1804
  ${stillness(`${motionRoot}:not([data-graview-motion='full'])`, text)}
1691
1805
  }
1692
1806
  ${stillness(`${motionRoot}[data-graview-motion='reduce']`, text)}
1693
1807
 
1694
- /* VIEWS AS DATA (FR-03): the blocks a view spec is drawn with, over the tokens above. */
1808
+ ${ /* VIEWS AS DATA (FR-03): the blocks a view spec is drawn with, over the tokens above. */""}
1695
1809
  ${SPEC_VIEW_CSS}`;
1696
1810
  }
1697
1811
  //# sourceMappingURL=theme.js.map