@graview/primitives 0.1.10 → 0.1.14

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 (107) hide show
  1. package/README.md +27 -5
  2. package/dist/arrange-bar.d.ts.map +1 -1
  3. package/dist/arrange-bar.js +2 -1
  4. package/dist/arrange-bar.js.map +1 -1
  5. package/dist/arrangement.d.ts +1 -1
  6. package/dist/arrangement.d.ts.map +1 -1
  7. package/dist/arrangement.js +1 -1
  8. package/dist/arrangement.js.map +1 -1
  9. package/dist/chat.d.ts.map +1 -1
  10. package/dist/chat.js +5 -2
  11. package/dist/chat.js.map +1 -1
  12. package/dist/declared-lenses.d.ts.map +1 -1
  13. package/dist/declared-lenses.js +3 -0
  14. package/dist/declared-lenses.js.map +1 -1
  15. package/dist/default-views.d.ts +0 -7
  16. package/dist/default-views.d.ts.map +1 -1
  17. package/dist/default-views.js +14 -140
  18. package/dist/default-views.js.map +1 -1
  19. package/dist/editable.d.ts.map +1 -1
  20. package/dist/editable.js +3 -2
  21. package/dist/editable.js.map +1 -1
  22. package/dist/figure.d.ts.map +1 -1
  23. package/dist/figure.js +13 -6
  24. package/dist/figure.js.map +1 -1
  25. package/dist/find.d.ts.map +1 -1
  26. package/dist/find.js +2 -1
  27. package/dist/find.js.map +1 -1
  28. package/dist/frame.d.ts +3 -3
  29. package/dist/frame.d.ts.map +1 -1
  30. package/dist/frame.js +4 -3
  31. package/dist/frame.js.map +1 -1
  32. package/dist/index.d.ts +2 -2
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +2 -2
  35. package/dist/index.js.map +1 -1
  36. package/dist/ladder.d.ts.map +1 -1
  37. package/dist/ladder.js +2 -1
  38. package/dist/ladder.js.map +1 -1
  39. package/dist/lens/arranging.d.ts.map +1 -1
  40. package/dist/lens/arranging.js +3 -2
  41. package/dist/lens/arranging.js.map +1 -1
  42. package/dist/lens/calendar-drawing.d.ts.map +1 -1
  43. package/dist/lens/calendar-drawing.js +3 -2
  44. package/dist/lens/calendar-drawing.js.map +1 -1
  45. package/dist/lens/calendar-view.js +5 -0
  46. package/dist/lens/calendar-view.js.map +1 -1
  47. package/dist/lens/columns.d.ts +41 -0
  48. package/dist/lens/columns.d.ts.map +1 -0
  49. package/dist/lens/columns.js +197 -0
  50. package/dist/lens/columns.js.map +1 -0
  51. package/dist/lens/coverage.d.ts.map +1 -1
  52. package/dist/lens/coverage.js +120 -6
  53. package/dist/lens/coverage.js.map +1 -1
  54. package/dist/notices.js +1 -1
  55. package/dist/notices.js.map +1 -1
  56. package/dist/places.d.ts +13 -8
  57. package/dist/places.d.ts.map +1 -1
  58. package/dist/places.js +90 -182
  59. package/dist/places.js.map +1 -1
  60. package/dist/primitives/index.d.ts +2 -31
  61. package/dist/primitives/index.d.ts.map +1 -1
  62. package/dist/primitives/index.js +12 -45
  63. package/dist/primitives/index.js.map +1 -1
  64. package/dist/primitives/measure.d.ts +32 -0
  65. package/dist/primitives/measure.d.ts.map +1 -0
  66. package/dist/primitives/measure.js +51 -0
  67. package/dist/primitives/measure.js.map +1 -0
  68. package/dist/quick-relations.d.ts.map +1 -1
  69. package/dist/quick-relations.js +4 -3
  70. package/dist/quick-relations.js.map +1 -1
  71. package/dist/relation-key.d.ts.map +1 -1
  72. package/dist/relation-key.js +2 -1
  73. package/dist/relation-key.js.map +1 -1
  74. package/dist/scene-css.d.ts +13 -0
  75. package/dist/scene-css.d.ts.map +1 -0
  76. package/dist/scene-css.js +762 -0
  77. package/dist/scene-css.js.map +1 -0
  78. package/dist/scene.d.ts +1 -0
  79. package/dist/scene.d.ts.map +1 -1
  80. package/dist/scene.js +2 -0
  81. package/dist/scene.js.map +1 -1
  82. package/dist/spec-css.d.ts.map +1 -1
  83. package/dist/spec-css.js +19 -6
  84. package/dist/spec-css.js.map +1 -1
  85. package/dist/spec-views.d.ts +15 -2
  86. package/dist/spec-views.d.ts.map +1 -1
  87. package/dist/spec-views.js +20 -9
  88. package/dist/spec-views.js.map +1 -1
  89. package/dist/theme.d.ts +3 -1
  90. package/dist/theme.d.ts.map +1 -1
  91. package/dist/theme.js +50 -773
  92. package/dist/theme.js.map +1 -1
  93. package/dist/workbench/agent-seat.d.ts.map +1 -1
  94. package/dist/workbench/agent-seat.js +2 -1
  95. package/dist/workbench/agent-seat.js.map +1 -1
  96. package/dist/workbench/answer-args.d.ts.map +1 -1
  97. package/dist/workbench/answer-args.js +1 -1
  98. package/dist/workbench/answer-args.js.map +1 -1
  99. package/dist/workbench/back-out.d.ts +2 -16
  100. package/dist/workbench/back-out.d.ts.map +1 -1
  101. package/dist/workbench/back-out.js +7 -26
  102. package/dist/workbench/back-out.js.map +1 -1
  103. package/dist/workbench/descent.d.ts +17 -0
  104. package/dist/workbench/descent.d.ts.map +1 -0
  105. package/dist/workbench/descent.js +24 -0
  106. package/dist/workbench/descent.js.map +1 -0
  107. package/package.json +6 -6
package/dist/theme.js CHANGED
@@ -26,7 +26,8 @@
26
26
  * without reaching into the UI package.
27
27
  */
28
28
  export { DARK, LIGHT, SCHEMES } from "@graview/core";
29
- import { isoShade, SCHEMES, kitVariables, layer, layerVariables, resolveKit, SCENE_LAYERS, shapeOf, TYPOGRAPHY, typographyOf } from "@graview/core";
29
+ import { SCHEMES, kitVariables, layer, layerVariables, resolveKit, SCENE_LAYERS, shapeOf, TYPOGRAPHY, typographyOf } from "@graview/core";
30
+ import { MARQUEE_GAP, MARQUEE_WIDTH } from "@graview/layout/view";
30
31
  import { SPEC_VIEW_CSS } from "./spec-css.js";
31
32
  /**
32
33
  * The framework's own brand, expressed as an ordinary declared one.
@@ -104,8 +105,16 @@ function stillness(asking, within) {
104
105
  * <style> (FR-57). As a JS comment in an empty interpolation the words stay
105
106
  * where they explain the rule, and a minifier folds them away.
106
107
  */
107
- export function themeCss(scheme = "dark", brand = GRAVIEW_BRAND, options = {}) {
108
- const css = sheet(scheme, brand, options);
108
+ /*
109
+ * THE SHEET WITHOUT THE SCENE (FR-104). What every face draws on: the
110
+ * tokens, the type, the panels, the views as data, motion. The scene's own
111
+ * rules — the districts from altitude, the plots, the village, the roads,
112
+ * the billboards, the bands — are `sceneCss` (scene-css.ts), which the
113
+ * scene face draws beside it, so a page that opens on the pages face
114
+ * carries none of them. `themeCss` is the two together, in that order.
115
+ */
116
+ export function themeBaseCss(scheme = "dark", brand = GRAVIEW_BRAND, options = {}) {
117
+ const css = baseSheet(scheme, brand, options);
109
118
  return options.scope === undefined ? css : withinTheBox(css, options.scope);
110
119
  }
111
120
  /*
@@ -124,7 +133,7 @@ export function themeCss(scheme = "dark", brand = GRAVIEW_BRAND, options = {}) {
124
133
  * keyframes) names no element and is left as it is; @media and @supports
125
134
  * are walked into.
126
135
  */
127
- function withinTheBox(css, scope) {
136
+ export function withinTheBox(css, scope) {
128
137
  const under = `:where(${scope}) `;
129
138
  const at = (selector) => selector === scope ||
130
139
  selector.startsWith(`${scope} `) ||
@@ -211,11 +220,7 @@ function splitSelectors(list) {
211
220
  out.push(current.trim());
212
221
  return out;
213
222
  }
214
- /** A face of the iso lighting as the saturation and lightness of an `hsl()` whose hue is the kind's. */
215
- const face = (f) => `${f.saturation}% ${f.lightness}%`;
216
- /** A translucent one, with its alpha. */
217
- const wash = (f) => `${face(f)} / ${f.alpha}`;
218
- function sheet(scheme, brand, options) {
223
+ export function baseSheet(scheme, brand, options) {
219
224
  const tokens = brand.schemes[scheme];
220
225
  const root = options.scope ?? ":root";
221
226
  const surface = options.scope ?? "html, body";
@@ -251,7 +256,6 @@ function sheet(scheme, brand, options) {
251
256
  */
252
257
  const shape = shapeOf(brand);
253
258
  const type = typographyOf(brand);
254
- const iso = isoShade(scheme);
255
259
  const kit = resolveKit(brand.kit);
256
260
  return `${root} {
257
261
  ${themeVariables(tokens)}
@@ -441,9 +445,6 @@ ${ /* A card on the kinds plane.
441
445
  floats above the card and the block stands up out of it. */""}
442
446
  overflow: clip;
443
447
  }
444
- [data-graview-altitude] .graview-kind-card {
445
- overflow: visible;
446
- }
447
448
  .graview-kind-card:hover,
448
449
  .graview-kind-card:focus-within {
449
450
  height: auto;
@@ -452,15 +453,6 @@ ${ /* A card on the kinds plane.
452
453
  position: relative;
453
454
  z-index: ${SCENE_LAYERS.lines};
454
455
  }
455
- ${ /* From altitude a district is a village on its plot, not a card: hovering
456
- it must not raise a white panel over the buildings. The lift stays in
457
- the stack, where the card is a card. */""}
458
- [data-graview-altitude] .graview-kind-card:hover,
459
- [data-graview-altitude] .graview-kind-card:focus-within {
460
- transform: none;
461
- box-shadow: none;
462
- background: transparent;
463
- }
464
456
 
465
457
  ${ /* FROM ALTITUDE the ground is an ISOMETRIC LATTICE — diamond cells at the
466
458
  classic 2:1 pitch, a finer far weave above, dissolving toward the
@@ -501,79 +493,6 @@ ${ /* DRAWN AS TILES, one cell each. A repeating gradient at the lattice's
501
493
  -webkit-mask-image: linear-gradient(to top, #000 42%, rgba(0,0,0,0.35) 70%, transparent 92%);
502
494
  }
503
495
 
504
- ${ /* THE GROUND UNDER A DISTRICT: its plot, drawn. Four lattice corners in
505
- the kind's hue, a kerb, a cast shadow toward the light — the arithmetic
506
- the layout already did, made visible, so a district stands on land
507
- rather than floating on a hatch. Fades in with the altitude number the
508
- lattice fades in with; a hand-placed district's kerb is dashed, which is
509
- the pinned mark on the ground rather than a box over the drawing. */""}
510
- .graview-plots {
511
- z-index: ${SCENE_LAYERS.plots};
512
- opacity: var(--graview-altitude);
513
- transition: opacity 640ms cubic-bezier(0.33, 0, 0.2, 1);
514
- }
515
- .graview-plot-tile {
516
- fill: hsl(var(--graview-hue, 200) ${wash(iso.plot)});
517
- stroke: hsl(var(--graview-hue, 200) ${wash(iso.plotEdge)});
518
- stroke-width: 1;
519
- stroke-linejoin: round;
520
- pointer-events: auto;
521
- cursor: pointer;
522
- filter: drop-shadow(${scheme === "light" ? "5px 4px 6px rgba(20,30,32,0.14)" : "6px 5px 8px rgba(0,0,0,0.4)"});
523
- transition: fill 170ms ease;
524
- }
525
- .graview-plot-tile:hover {
526
- fill: hsl(var(--graview-hue, 200) 45% ${scheme === "light" ? "58%" : "48%"} / ${scheme === "light" ? "0.2" : "0.3"});
527
- }
528
- .graview-plot[data-graview-pinned] .graview-plot-tile {
529
- stroke-dasharray: 4 3;
530
- }
531
- ${ /* THE VILLAGE on the tile: one small iso building per member in the kind's
532
- own faces (the same roof and walls the block had), a flagged member's roof
533
- in the warning colour, a selected member's building lit in the accent.
534
- Architecture, not controls: the tile under them takes the click. */""}
535
- .graview-village { pointer-events: none; }
536
- .graview-building polygon { stroke-width: 0.8; }
537
- .graview-building[data-graview-flagged] .graview-iso-roof { fill: var(--graview-warn); stroke: var(--graview-warn); }
538
- .graview-building[data-graview-selected] polygon { stroke: var(--graview-accent); stroke-width: 1.4; }
539
- .graview-building[data-graview-selected] .graview-iso-roof { fill: color-mix(in oklab, var(--graview-accent) 45%, var(--graview-panel)); }
540
- .graview-village-rest {
541
- font-size: 0.75rem;
542
- letter-spacing: 0.06em;
543
- fill: var(--graview-ink-muted);
544
- }
545
- ${ /* THE ROADS between plots: the lattice's own two legs from kerb to kerb, a
546
- bed between two edges in the ground's ink. Under the tiles and the
547
- buildings, over the fields. A road the legend is asking about comes up
548
- in the accent. */""}
549
- .graview-road-edge {
550
- fill: none;
551
- stroke: var(--graview-ink);
552
- stroke-opacity: ${scheme === "light" ? "0.28" : "0.4"};
553
- stroke-width: 7;
554
- stroke-linejoin: round;
555
- stroke-linecap: round;
556
- }
557
- .graview-road-bed {
558
- fill: none;
559
- stroke: var(--graview-ground);
560
- stroke-width: 5;
561
- stroke-linejoin: round;
562
- stroke-linecap: round;
563
- }
564
- .graview-road[data-graview-lit] .graview-road-edge {
565
- stroke: var(--graview-accent);
566
- stroke-opacity: 0.9;
567
- }
568
- ${ /* FIELDS. From altitude the ground darkens a shade toward the near edge and
569
- fades to the page at the horizon, so the lattice is land with a distance
570
- rather than paper with a pattern. */""}
571
- .graview-ground[data-graview-altitude] {
572
- background:
573
- linear-gradient(to top, color-mix(in oklab, var(--graview-ground) ${scheme === "light" ? "93%" : "88%"}, var(--graview-ink)) 0%, var(--graview-ground) 78%),
574
- var(--graview-ground);
575
- }
576
-
577
496
  ${ /* THE KEEPER'S BLOCK IN THE PROFILE, which hides itself when it is empty.
578
497
  Both controls inside it draw nothing for a seat that may not administer,
579
498
  and a heading with nothing under it is worse than no heading — so the
@@ -587,78 +506,24 @@ ${ /* A host's own action in the profile (FR-72): a row of the pane, lit where t
587
506
  background: var(--graview-wash);
588
507
  color: var(--graview-accent);
589
508
  }
590
-
591
- ${ /* THE OPEN CHEVRON APPEARS WHEN REACHED FOR. Drawn on every plate at
592
- altitude it was noise times the number of districts; it shows on hover,
593
- on keyboard focus, and while the district is open — and stays a real
594
- button in between, so Tab still finds it and Enter still opens. */""}
595
- [data-graview-altitude] .graview-kind-open {
596
- opacity: 0.5;
597
- transition: opacity 150ms ease;
598
- }
599
- ${ /* Quiet: the chevron alone until reached for. Never opacity zero — a
600
- button nobody can see is a button a driven browser cannot press either,
601
- and Tab must land on something that looks like something. */""}
602
- [data-graview-altitude] .graview-kind-open-word {
603
- display: none;
604
- }
605
- [data-graview-altitude] .graview-kind-card:hover .graview-kind-open,
606
- [data-graview-altitude] .graview-kind-card:focus-within .graview-kind-open,
607
- [data-graview-altitude] .graview-kind-open[aria-expanded="true"] {
608
- opacity: 1;
609
- }
610
- [data-graview-altitude] .graview-kind-card:hover .graview-kind-open-word,
611
- [data-graview-altitude] .graview-kind-card:focus-within .graview-kind-open-word,
612
- [data-graview-altitude] .graview-kind-open[aria-expanded="true"] .graview-kind-open-word {
613
- display: inline;
614
- }
615
509
  ${ /* The district-open control and its roster: altitude-only chrome. Inside
616
510
  the stack expanding dissolves a card, so the control does not exist
617
511
  there. A full fingertip even though the glyph is small — the audit holds
618
512
  every control to 24px. */""}
619
513
  .graview-kind-open { display: none; }
620
- [data-graview-altitude] .graview-kind-open {
621
- display: inline-flex;
622
- align-items: center;
623
- justify-content: center;
624
- flex: 0 0 auto;
625
- ${ /* A FINGERTIP, AND THE READER'S FINGERTIP IF IT IS BIGGER. 24px is the
626
- floor audit-ui holds every control to; 1.5rem is the same 24 at the
627
- default text size and grows with a reader who asked for more, so the
628
- control never drifts under the words it sits beside. A max() rather than
629
- either one alone: rem alone drops below the fingertip at a smaller
630
- setting, px alone ignores the setting altogether. */""}
631
- min-height: max(1.5rem, 24px);
632
- padding: 1px 9px;
633
- margin: -3px 0;
634
- border-radius: 999px;
635
- border: 1px solid var(--graview-edge);
636
- background: var(--graview-panel);
637
- box-shadow: none;
638
- color: var(--graview-ink-muted);
639
- cursor: pointer;
640
- ${ /* IN REM, LIKE EVERY OTHER SIZE HERE. At 10px this control's words were
641
- the one piece of text in the framework that ignored the reader's text
642
- size completely: set to Largest, every name on the screen doubled and
643
- "open" stayed ten pixels tall. A size a person chose and a control that
644
- will not take it is the accessibility setting failing on its own
645
- surface. */""}
646
- font-size: 0.75rem;
647
- letter-spacing: 0.08em;
648
- text-transform: uppercase;
649
- line-height: 1;
650
- white-space: nowrap;
651
- }
652
- [data-graview-altitude] .graview-kind-open:hover {
653
- color: var(--graview-accent);
654
- border-color: var(--graview-accent-dim);
655
- }
656
514
  ${ /* The roster reads as a LIST, one member a row — chips wrapping at their
657
515
  own widths read as spilled tiles, and a district's population is a roll
658
516
  call, not a mosaic. */""}
517
+ ${ /* THE PLACES, as text tabs (FR-117): the place you are on underlined, the
518
+ others the ink's quieter shade until reached for; a row longer than its
519
+ room scrolls, with no bar drawn under it. */""}
520
+ .graview-places::-webkit-scrollbar { display: none; }
521
+ .graview-place-tab:hover { color: var(--graview-ink) !important; border-bottom-color: var(--graview-edge-bright, var(--graview-edge)) !important; }
522
+ .graview-place-tab[aria-pressed="true"]:hover { border-bottom-color: var(--graview-accent) !important; }
523
+ .graview-place-tab:focus-visible { outline: 2px solid var(--graview-accent); outline-offset: -2px; }
659
524
  ${ /* A DRIVE-IN: a dark screen standing on the plot, and the showings under
660
525
  it as a marquee of real buttons. Only from altitude; the same list the
661
- Places pills carry, drawn where the pictures live. */""}
526
+ places tabs carry, drawn where the pictures live. */""}
662
527
  .graview-drive-in {
663
528
  ${ /* Its own block under the nameplate, never a row inside the pill: the
664
529
  pill is one line of name and count, and a marquee flattened into it
@@ -679,162 +544,62 @@ ${ /* A DRIVE-IN: a dark screen standing on the plot, and the showings under
679
544
  [data-graview-landmark] .graview-drive-in {
680
545
  top: 4px;
681
546
  }
547
+ ${ /* THE SHOWINGS, BY NAME (FR-118): a column of names hanging off the
548
+ signpost's post, each whole and wrapped rather than cut, the one showing
549
+ now marked by the post's rule in the accent. Words on the ground, haloed
550
+ in the ground's colour like the district's own name — no capsules, no
551
+ pictures drawn too small to read. */""}
682
552
  .graview-drive-in-marquee {
683
553
  display: grid;
684
- gap: 4px;
685
- grid-template-columns: repeat(2, 58px);
686
- justify-content: center;
554
+ gap: ${MARQUEE_GAP}px;
555
+ width: ${MARQUEE_WIDTH}px;
556
+ justify-items: stretch;
687
557
  }
688
- .graview-drive-in-marquee[data-graview-thumbs="one"] {
689
- grid-template-columns: 120px;
690
- }
691
- ${ /* THE LENSES AS PICTURES: each showing is its lens drawn small — the real
692
- component at a fraction of its size, cut to a thumbnail — with its name
693
- under it. The picture takes no pointer; the button around it does. */""}
694
558
  .graview-drive-in-thumb {
695
559
  position: relative;
696
- display: grid;
697
- gap: 2px;
698
- justify-items: center;
699
- padding: 2px;
700
- min-height: max(1.75rem, 28px);
701
- border-radius: 6px;
702
- border: 1px solid var(--graview-edge);
703
- background: var(--graview-panel);
560
+ display: block;
561
+ box-sizing: border-box;
562
+ min-height: max(1.5rem, 24px);
563
+ padding: 3px 6px 3px 10px;
564
+ border-left: 2px solid var(--graview-edge-bright, var(--graview-edge));
704
565
  color: var(--graview-ink);
705
566
  font: inherit;
567
+ text-align: left;
706
568
  }
707
569
  .graview-drive-in-thumb[data-graview-pressed] {
708
- border-color: var(--graview-accent);
570
+ border-left-color: var(--graview-accent);
709
571
  color: var(--graview-accent);
710
572
  }
711
- ${ /* The press: the whole frame, laid over the picture and the title rather than
712
- around them, so the lens drawn small never sits inside a button. */""}
573
+ ${ /* The press: the whole name, laid over it. */""}
713
574
  .graview-drive-in-thumb-press {
714
575
  position: absolute;
715
- inset: -1px;
716
- ${ /* It fills its frame, and says the frame's floor itself: a target is sized where it is declared. */""}
717
- min-height: max(1.75rem, 28px);
576
+ inset: 0;
577
+ min-height: max(1.5rem, 24px);
718
578
  margin: 0;
719
579
  padding: 0;
720
580
  border: none;
721
- border-radius: 6px;
581
+ border-radius: 0 4px 4px 0;
722
582
  background: transparent;
723
583
  box-shadow: none;
724
584
  cursor: pointer;
725
- ${ /* The card's own floor, stated: it covers the card, and the card is at least this tall. */""}
726
- min-height: max(1.75rem, 28px);
585
+ }
586
+ .graview-drive-in-thumb-press:hover {
587
+ background: color-mix(in srgb, var(--graview-accent) 8%, transparent);
727
588
  }
728
589
  .graview-drive-in-thumb-press:focus-visible {
729
590
  outline: 2px solid var(--graview-accent);
730
591
  outline-offset: 1px;
731
592
  }
732
- .graview-drive-in-thumb-picture {
733
- display: block;
734
- position: relative;
735
- width: 54px;
736
- height: 34px;
737
- overflow: hidden;
738
- border-radius: 3px;
739
- background: var(--graview-panel);
740
- pointer-events: none;
741
- }
742
- [data-graview-thumbs="one"] .graview-drive-in-thumb-picture {
743
- width: 116px;
744
- height: 70px;
745
- }
746
- .graview-drive-in-thumb-natural {
747
- position: absolute;
748
- left: 0;
749
- top: 0;
750
- width: 960px;
751
- transform: scale(0.05625);
752
- transform-origin: 0 0;
753
- }
754
- [data-graview-thumbs="one"] .graview-drive-in-thumb-natural {
755
- transform: scale(0.1208);
756
- }
757
593
  .graview-drive-in-thumb-title {
758
- font-size: 0.75rem;
759
- line-height: 1.2;
760
- white-space: nowrap;
761
- ${ /* Its own frame's width: two pictures share the marquee, and two names
762
- each allowed the width of one picture ran into each other. */""}
763
- max-width: 100%;
764
- overflow: hidden;
765
- text-overflow: ellipsis;
766
- }
767
- ${ /* THE BILLBOARD'S FULL-SCREEN CONTROL: the one way down from a picture. */""}
768
- ${ /* THE RAIL A BILLBOARD IS MOVED BY: a title bar, in the board's own frame
769
- ink, along its top edge. Positioned like the full-screen control beside
770
- it — the host wraps its children, so the rail is a grandchild of the
771
- screen box and a child selector never reaches it. Wide enough to be an
772
- easy target, short enough that the picture underneath is still what you
773
- see, and present only at altitude, because only up there is the board
774
- standing on a plot it could be moved around. */""}
775
- .graview-screen-grip {
776
- display: none;
777
- }
778
- [data-graview-altitude] [data-graview-screen] .graview-screen-grip {
779
- display: flex;
780
- align-items: center;
781
- gap: 8px;
782
- position: absolute;
783
- left: 0;
784
- right: 0;
785
- top: 0;
786
- ${ /* Drawn height, not CSS height: a district's plane is scaled down at
787
- altitude, and 14 here reached the screen as an eight-pixel strip that
788
- took three attempts to catch. */""}
789
- height: 32px;
790
- padding: 0 6px 0 12px;
791
- box-sizing: border-box;
792
- cursor: grab;
793
- ${ /* A title bar in the panel's own colours, not a grey strip: the board is
794
- a window onto the picture, and its bar reads as the window's. */""}
795
- background: var(--graview-panel-muted);
796
- border-bottom: 1px solid var(--graview-edge);
797
- z-index: ${SCENE_LAYERS.lines};
798
- }
799
- [data-graview-altitude] [data-graview-screen] .graview-screen-title {
800
- flex: 1 1 auto;
801
- min-width: 0;
802
- overflow: hidden;
803
- text-overflow: ellipsis;
804
- white-space: nowrap;
594
+ display: block;
805
595
  font-size: 0.8125rem;
806
- font-weight: 600;
807
- color: var(--graview-ink);
808
- }
809
- [data-graview-altitude] [data-graview-screen] .graview-screen-grip:active {
810
- cursor: grabbing;
596
+ font-weight: 500;
597
+ line-height: 1.25;
598
+ overflow-wrap: anywhere;
599
+ text-shadow: 0 0 3px var(--graview-ground), 0 0 6px var(--graview-ground);
811
600
  }
812
- .graview-screen-fullscreen {
813
- flex: 0 0 auto;
814
- min-height: max(1.5rem, 24px);
815
- padding: 1px 10px;
816
- border-radius: 999px;
817
- border: 1px solid var(--graview-edge);
818
- background: var(--graview-panel);
819
- color: var(--graview-accent);
820
- font-size: 0.8125rem;
601
+ .graview-drive-in-thumb[data-graview-pressed] .graview-drive-in-thumb-title {
821
602
  font-weight: 600;
822
- white-space: nowrap;
823
- cursor: pointer;
824
- box-shadow: none;
825
- }
826
- .graview-screen-fullscreen:hover:not(:disabled) {
827
- border-color: var(--graview-accent);
828
- }
829
- .graview-drive-in-marquee > button.graview-drive-in-thumb {
830
- font-size: 0.75rem;
831
- line-height: 1.2;
832
- min-height: max(1.75rem, 28px);
833
- cursor: pointer;
834
- }
835
- .graview-drive-in-marquee > button[aria-pressed="true"] {
836
- border-color: var(--graview-accent);
837
- color: var(--graview-accent);
838
603
  }
839
604
 
840
605
  ${ /* THE OTHERS: people and their agents in the city, each a small figure in
@@ -967,255 +732,6 @@ ${ /* Off the visible ground: an indicator at the border, pointing at it. */""}
967
732
  margin-top: 7px;
968
733
  animation: graview-settle 240ms ease backwards;
969
734
  }
970
- [data-graview-altitude] .graview-kind-members > [data-graview-pick] {
971
- width: 100%;
972
- box-sizing: border-box;
973
- justify-content: flex-start;
974
- max-width: none;
975
- }
976
- ${ /* An OPENED district is a PANEL, not a pill with a list stuffed in it:
977
- name and count share the header line, the roster sits under a hairline,
978
- and the block behind fades — the plate IS the district while it is
979
- open, so no roof pokes out above the roster. */""}
980
- [data-graview-altitude] .graview-kind-face[data-graview-opened] {
981
- ${ /* A header that WRAPS rather than a grid that squeezes: the name's column
982
- was minmax(0, 1fr) beside the count's auto, so "VEHICLES" beside
983
- "291 · +29 past · close" got 25 pixels and the count was drawn over it. */""}
984
- display: flex !important;
985
- flex-wrap: wrap;
986
- justify-content: flex-start !important;
987
- align-items: baseline !important;
988
- column-gap: 10px;
989
- row-gap: 2px;
990
- border-radius: 12px !important;
991
- padding: 10px 12px 11px !important;
992
- width: 236px;
993
- max-width: 236px;
994
- box-shadow: var(--graview-lift-high) !important;
995
- }
996
- [data-graview-altitude] .graview-kind-face[data-graview-opened] .graview-kind-members {
997
- flex: 1 0 100%;
998
- margin-top: 8px;
999
- padding-top: 8px;
1000
- border-top: 1px solid var(--graview-edge);
1001
- }
1002
- [data-graview-altitude] .graview-kind-block[data-graview-opened] {
1003
- opacity: calc(var(--graview-altitude) * 0.22);
1004
- }
1005
-
1006
- ${ /* WHAT KIND OF THING THIS IS, astride the focus panel's top-right edge —
1007
- the kind's dot and its name, the same thread the chips and the legend
1008
- carry. Scene chrome, so no view has to remember to say it. */""}
1009
- .graview-kind-tag {
1010
- position: absolute;
1011
- top: -9px;
1012
- right: 14px;
1013
- z-index: ${SCENE_LAYERS.tag};
1014
- display: var(--graview-kit-tags, inline-flex);
1015
- align-items: center;
1016
- gap: 5px;
1017
- padding: 2px 8px;
1018
- border-radius: 999px;
1019
- ${ /* The kind's own hue on the border and the words, so the tag and the
1020
- district it belongs to read as one thread. */""}
1021
- border: 1px solid hsl(var(--graview-hue, 200) 45% var(--graview-tint-lightness) / 0.55);
1022
- color: hsl(var(--graview-hue, 200) 45% calc(var(--graview-tint-lightness) + ${scheme === "light" ? "-32%" : "28%"}));
1023
- background: var(--graview-float);
1024
- box-shadow: var(--graview-lift-low);
1025
- font-size: 0.6875rem;
1026
- letter-spacing: 0.14em;
1027
- text-transform: uppercase;
1028
- color: var(--graview-ink-faint);
1029
- pointer-events: none;
1030
- }
1031
-
1032
- ${ /* A LINE UNDER THE POINTER says it will take the press: the invisible hit
1033
- run ghosts in, so editability is discoverable by hovering the relation
1034
- itself rather than by rumor. */""}
1035
- .graview-edge-hit:hover {
1036
- stroke: var(--graview-accent);
1037
- opacity: 0.3;
1038
- }
1039
-
1040
- ${ /* THE DISTRICTS THE ROW COULD NOT HOLD.
1041
- Not a district: no figure, no count, no tint of its own. A card that is
1042
- one control — how many more, and a press — and, open, a panel above the
1043
- row naming every district with what it holds. Solid rather than dashed
1044
- and faded: a dashed, translucent card read as a placeholder, and the only
1045
- way to five districts should not look like something that failed to load. */""}
1046
- ${ /* A RELATION THE BAND COULD NOT HOLD: a group with its count and first names,
1047
- or the door to the rest. A card like the others, never the kind's lens small. */""}
1048
- .graview-band-group {
1049
- display: grid;
1050
- align-content: center;
1051
- gap: 2px;
1052
- height: 100%;
1053
- ${ /* A card you press, held to the floor every pressable piece of chrome keeps. */""}
1054
- min-height: max(1.75rem, 28px);
1055
- box-sizing: border-box;
1056
- padding: 6px 10px;
1057
- border-radius: var(--graview-radius-sm, 8px);
1058
- border: 1px solid var(--graview-edge);
1059
- background: var(--graview-panel);
1060
- color: var(--graview-ink);
1061
- overflow: hidden;
1062
- cursor: pointer;
1063
- }
1064
- .graview-band-group[data-graview-band="picture"] {
1065
- border-style: dashed;
1066
- }
1067
- .graview-band-group[data-graview-emphasis="lit"] {
1068
- border-color: var(--graview-accent);
1069
- }
1070
- .graview-band-group[data-graview-emphasis="dimmed"] {
1071
- opacity: 0.5;
1072
- }
1073
- .graview-band-group-head {
1074
- display: flex;
1075
- align-items: baseline;
1076
- gap: 6px;
1077
- min-width: 0;
1078
- }
1079
- .graview-band-group-name {
1080
- flex: 1;
1081
- min-width: 0;
1082
- font-weight: 600;
1083
- font-size: 0.9375rem;
1084
- line-height: 1.25;
1085
- white-space: nowrap;
1086
- overflow: hidden;
1087
- text-overflow: ellipsis;
1088
- }
1089
- .graview-band-group-open {
1090
- font-size: 0.75rem;
1091
- color: var(--graview-accent);
1092
- }
1093
- .graview-band-group-names {
1094
- font-size: 0.8125rem;
1095
- line-height: 1.3;
1096
- color: var(--graview-ink-muted);
1097
- white-space: nowrap;
1098
- overflow: hidden;
1099
- text-overflow: ellipsis;
1100
- }
1101
- .graview-band-group-count {
1102
- color: var(--graview-ink);
1103
- font-variant-numeric: tabular-nums;
1104
- }
1105
- .graview-beyond {
1106
- position: relative;
1107
- height: 100%;
1108
- box-sizing: border-box;
1109
- border-radius: var(--graview-radius-sm, 8px);
1110
- border: 1px solid var(--graview-edge);
1111
- background: var(--graview-panel);
1112
- }
1113
- .graview-beyond-more {
1114
- display: flex;
1115
- align-items: center;
1116
- gap: 6px;
1117
- width: 100%;
1118
- height: 100%;
1119
- min-height: max(1.75rem, 28px);
1120
- padding: var(--graview-pad-sm, 8px);
1121
- box-sizing: border-box;
1122
- border: none;
1123
- border-radius: inherit;
1124
- background: none;
1125
- color: var(--graview-ink-muted);
1126
- cursor: pointer;
1127
- font: inherit;
1128
- font-size: 0.875rem;
1129
- text-align: left;
1130
- }
1131
- .graview-beyond-more:hover,
1132
- .graview-beyond[data-graview-beyond-open] .graview-beyond-more {
1133
- color: var(--graview-accent);
1134
- background: var(--graview-wash);
1135
- }
1136
- .graview-beyond-count {
1137
- font-family: var(--graview-font-display);
1138
- font-size: 1.1875rem;
1139
- line-height: 1;
1140
- color: inherit;
1141
- }
1142
- .graview-beyond-word {
1143
- font-size: 0.75rem;
1144
- letter-spacing: 0.08em;
1145
- text-transform: uppercase;
1146
- }
1147
- .graview-beyond-chevron {
1148
- margin-left: auto;
1149
- font-size: 0.8125rem;
1150
- }
1151
- ${ /* The panel stands above the card, inside the scene, and never clips: the
1152
- card's box is a district's height, which holds a count and not a list. */""}
1153
- .graview-beyond-list {
1154
- position: absolute;
1155
- left: 0;
1156
- bottom: calc(100% + 6px);
1157
- ${ /* On the ground, over every plane — the focused card on plane zero
1158
- painted over a panel drawn on plane two, and a menu under a card is
1159
- no menu. Above the zoom control too, which is the only other thing
1160
- that stands on the ground. */""}
1161
- z-index: ${layer("popover")};
1162
- margin: 0;
1163
- padding: 6px;
1164
- list-style: none;
1165
- display: flex;
1166
- flex-direction: column;
1167
- gap: 1px;
1168
- ${ /* Its own width, not the ground's: portalled, a percentage here is the
1169
- whole scene. */""}
1170
- min-width: 200px;
1171
- max-width: min(280px, 92%);
1172
- max-height: 60vh;
1173
- overflow: auto;
1174
- border-radius: var(--graview-radius-sm, 8px);
1175
- border: 1px solid var(--graview-edge);
1176
- background: var(--graview-panel);
1177
- box-shadow: 0 18px 44px -18px rgba(0, 0, 0, 0.45);
1178
- }
1179
- .graview-beyond-list button {
1180
- display: flex;
1181
- align-items: center;
1182
- gap: 10px;
1183
- width: 100%;
1184
- ${ /* A FINGERTIP WHERE IT IS ACTUALLY DRAWN, not where it was designed.
1185
- Every other control in this sheet is floored at 24 and the audit divides
1186
- by the plane's scale before judging it, which is right for a control
1187
- that sits ON a large target: the chip's disclosure is small, and the
1188
- card behind it is the size of a card. These names are not that. They are
1189
- the ONLY way to the districts the row could not hold, and plane two is
1190
- drawn at 0.90 — so a designed 24 meets a finger as 21.7. Designed at 28
1191
- it is drawn at 25, which is the number the floor was always about. */""}
1192
- min-height: max(1.75rem, 28px);
1193
- padding: 0 8px;
1194
- border: none;
1195
- border-radius: var(--graview-radius-sm, 6px);
1196
- background: none;
1197
- color: var(--graview-ink);
1198
- cursor: pointer;
1199
- font: inherit;
1200
- font-size: 0.875rem;
1201
- text-align: left;
1202
- overflow-wrap: anywhere;
1203
- white-space: nowrap;
1204
- }
1205
- .graview-beyond-list button:hover {
1206
- color: var(--graview-accent);
1207
- background: var(--graview-wash);
1208
- }
1209
- .graview-beyond-list button[aria-current] {
1210
- color: var(--graview-ink-muted);
1211
- cursor: default;
1212
- }
1213
- .graview-beyond-tally {
1214
- margin-left: auto;
1215
- font-size: 0.75rem;
1216
- font-variant-numeric: tabular-nums;
1217
- color: var(--graview-ink-faint);
1218
- }
1219
735
 
1220
736
  ${ /* The way into the archive, on the card that fed it: quiet, but a real
1221
737
  control at a real size. */""}
@@ -1303,17 +819,6 @@ ${ /* A district STANDS: an isometric block — roof, two shaded walls — whose
1303
819
  transform: translateY(calc((1 - var(--graview-altitude)) * 18px));
1304
820
  filter: drop-shadow(${scheme === "light" ? "10px 7px 14px rgba(20,30,32,0.28)" : "12px 8px 18px rgba(0,0,0,0.6)"});
1305
821
  }
1306
- .graview-iso-roof {
1307
- fill: hsl(var(--graview-hue, 200) ${face(iso.roof)});
1308
- stroke: ${iso.roofEdge};
1309
- stroke-width: 1;
1310
- }
1311
- .graview-iso-right {
1312
- fill: hsl(var(--graview-hue, 200) ${face(iso.right)});
1313
- }
1314
- .graview-iso-left {
1315
- fill: hsl(var(--graview-hue, 200) ${face(iso.left)});
1316
- }
1317
822
 
1318
823
  ${ /* WHERE THE KIND HAS ITS OWN DRAWING, the drawing is the building.
1319
824
  Same footprint as the block, same ground line, same cast shadow — the
@@ -1395,175 +900,6 @@ ${ /* From altitude the card's face becomes the district's NAMEPLATE: an
1395
900
  padding 640ms cubic-bezier(0.33, 0, 0.2, 1),
1396
901
  box-shadow 640ms ease;
1397
902
  }
1398
- ${ /* A SIGNPOST at the plot's front corner. From altitude the nameplate stood
1399
- at the top of the card — over the back row of the village — and the
1400
- screen had to clear it. It is planted at the front vertex of the tile
1401
- now, on a short post, where a sign stands at the entrance to a place;
1402
- the scene says where that vertex is in --graview-front-y. */""}
1403
- [data-graview-altitude] .graview-kind-face {
1404
- position: absolute !important;
1405
- left: 50% !important;
1406
- top: 2% !important;
1407
- transform: translateX(-50%);
1408
- width: max-content;
1409
- ${ /* Wider than the block when the name is: a label overflows its building
1410
- the way a map label does. "REQUIRE / MENTS" on two lines does not. */""}
1411
- max-width: none;
1412
- white-space: nowrap;
1413
- height: auto !important;
1414
- flex-direction: row !important;
1415
- align-items: baseline !important;
1416
- gap: 7px !important;
1417
- padding: 3px 11px !important;
1418
- border-radius: 999px !important;
1419
- box-shadow: var(--graview-lift-low) !important;
1420
- z-index: ${SCENE_LAYERS.tag};
1421
- }
1422
- [data-graview-altitude] [data-graview-plot] .graview-kind-face {
1423
- top: calc(var(--graview-front-y) - 22px) !important;
1424
- }
1425
- [data-graview-altitude] [data-graview-plot] .graview-kind-face::after {
1426
- content: "";
1427
- position: absolute;
1428
- left: 50%;
1429
- top: 100%;
1430
- width: 1px;
1431
- height: 10px;
1432
- background: var(--graview-ink-faint);
1433
- }
1434
- ${ /* A landmark WITHOUT a plot — a nested card — keeps its plate floating
1435
- above the drawing rather than across its head; one on a plot stands at
1436
- the signpost like every other district (the rule above). */""}
1437
- [data-graview-altitude] [data-graview-landmark]:not([data-graview-plot] *) .graview-kind-face {
1438
- top: 0 !important;
1439
- transform: translate(-50%, calc(-100% - 7px));
1440
- }
1441
- ${ /* The drive-in's board hangs UNDER the signpost, in the ground the layout
1442
- reserved for it below the tile's front corner, not over the village. */""}
1443
- [data-graview-altitude] .graview-drive-in {
1444
- top: calc(var(--graview-front-y, 42px) + 12px);
1445
- }
1446
- ${ /* An OPENED district's listing takes the ground under the signpost; the
1447
- board steps up over the village, which the listing covers anyway. */""}
1448
- [data-graview-altitude] .graview-kind-face[data-graview-opened] ~ .graview-drive-in {
1449
- top: calc(var(--graview-front-y, 42px) - 22px - var(--graview-marquee-room, 0px) + 8px);
1450
- }
1451
- ${ /* THE LANDMARK STANDS IN THE SQUARE: its feet at the plot's centre, among
1452
- the buildings, rather than at the card's bottom edge — which, once the
1453
- card grew for a board, was out in the road in front of the village. */""}
1454
- [data-graview-altitude] [data-graview-plot] .graview-kind-landmark {
1455
- bottom: auto;
1456
- top: calc(var(--graview-centre-y, 50%) + 10px);
1457
- transform: translate(-50%, -100%) scale(calc(0.55 + var(--graview-altitude) * 0.45));
1458
- }
1459
- ${ /* ZOOM, in the ground's corner: the way a map carries its own. Two
1460
- fingertip-sized buttons and the level between them, shown from altitude. */""}
1461
- .graview-zoom {
1462
- position: absolute;
1463
- right: 16px;
1464
- bottom: 16px;
1465
- ${ /* Above the occupants: a robot walking past a control must not cover it. */""}
1466
- z-index: ${SCENE_LAYERS.zoom};
1467
- display: inline-flex;
1468
- align-items: center;
1469
- gap: 2px;
1470
- padding: 2px;
1471
- border-radius: 999px;
1472
- border: 1px solid var(--graview-edge);
1473
- background: var(--graview-panel);
1474
- box-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);
1475
- }
1476
- .graview-zoom-button {
1477
- min-width: 32px;
1478
- min-height: 32px;
1479
- border: 0;
1480
- border-radius: 999px;
1481
- background: transparent;
1482
- color: var(--graview-ink);
1483
- font: inherit;
1484
- font-size: 1.0625rem;
1485
- line-height: 1;
1486
- cursor: pointer;
1487
- }
1488
- .graview-zoom-button:hover:not(:disabled) {
1489
- background: var(--graview-edge);
1490
- }
1491
- .graview-zoom-button:disabled {
1492
- opacity: 0.35;
1493
- cursor: default;
1494
- }
1495
- .graview-zoom-level {
1496
- min-width: 3.2em;
1497
- text-align: center;
1498
- font-size: 0.8125rem;
1499
- color: var(--graview-ink-faint);
1500
- font-variant-numeric: tabular-nums;
1501
- }
1502
-
1503
- ${ /* THE SCREEN IS A BILLBOARD at the back of the village: a frame, and two
1504
- posts into the ground at its foot. */""}
1505
- ${ /* On the NATURAL BOX, which is the picture now: the layout cuts the
1506
- billboard to what the lens drew (measured by the scene), never shorter
1507
- than a screen's worth — so the box is the picture, and an empty lens is a
1508
- header over an empty screen rather than a strip floating over the
1509
- village. The frame used to sit on the drawing itself, from the days the
1510
- box was as tall as the window with the picture in its top third. It
1511
- carries the panel's own ground so the empty part of a screen is a screen
1512
- and not the field showing through a frame. */""}
1513
- [data-graview-altitude] [data-graview-screen] > [data-graview-natural],
1514
- [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag) {
1515
- outline: 2px solid color-mix(in oklab, var(--graview-ink) 60%, var(--graview-panel));
1516
- outline-offset: 0;
1517
- background: var(--graview-panel);
1518
- }
1519
- [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag) {
1520
- position: relative;
1521
- }
1522
- [data-graview-altitude] [data-graview-screen] > [data-graview-natural]::before,
1523
- [data-graview-altitude] [data-graview-screen] > [data-graview-natural]::after,
1524
- [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag)::before,
1525
- [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag)::after {
1526
- content: "";
1527
- position: absolute;
1528
- top: 100%;
1529
- width: 3px;
1530
- height: 16px;
1531
- background: color-mix(in oklab, var(--graview-ink) 60%, var(--graview-panel));
1532
- }
1533
- [data-graview-altitude] [data-graview-screen] > [data-graview-natural]::before,
1534
- [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag)::before { left: 22%; }
1535
- [data-graview-altitude] [data-graview-screen] > [data-graview-natural]::after,
1536
- [data-graview-altitude] [data-graview-screen] > :not([data-graview-natural]):not(.graview-kind-tag)::after { right: 22%; }
1537
-
1538
- ${ /* A thing inside a view that is itself a thing: an event in a calendar, a
1539
- person in a list. It has to look reachable, and it has to SHOW focus —
1540
- these are the primary way anyone moves through the graph, so a keyboard
1541
- user who cannot see where they are is stuck. */""}
1542
- ${ /* A card someone dragged into place. Marked, not decorated: a dotted tie to
1543
- say this position is held rather than computed. */""}
1544
- ${ /* On the CHILD, not the host: the host is the layout's box, and a view
1545
- that sizes to its content (a zoomed record, a fit panel) fills only part
1546
- of it — a dashed box around the empty remainder read as a drawing
1547
- mistake, not a mark. */""}
1548
- ${ /* And never on the natural box either — a view drawn scaled sits inside a
1549
- box the size of the whole scene, and the mark belongs on the drawing, not
1550
- on the box; nor on the kind tag, which is a label and not the thing. */""}
1551
- [data-graview-pinned] > :not([data-graview-natural]):not(.graview-kind-tag),
1552
- [data-graview-pinned] > [data-graview-natural] > * {
1553
- outline: 1px dashed var(--graview-edge-bright);
1554
- outline-offset: 3px;
1555
- border-radius: 12px;
1556
- }
1557
- ${ /* AND NOT FROM ALTITUDE, where a district is a village on a plot and its
1558
- card is a box with nothing drawn in it: the dashed outline was the only
1559
- visible part, so a hand-placed district read as an empty rounded
1560
- rectangle sitting on the ground — several of them, in a picture that had
1561
- no rectangles in it. The plot's own kerb goes dashed up here, which is
1562
- the same fact said where the district actually is. */""}
1563
- [data-graview-altitude] [data-graview-pinned] > :not([data-graview-natural]):not(.graview-kind-tag),
1564
- [data-graview-altitude] [data-graview-pinned] > [data-graview-natural] > * {
1565
- outline: none;
1566
- }
1567
903
 
1568
904
  [data-graview-pick] {
1569
905
  cursor: pointer;
@@ -1645,13 +981,6 @@ ${ /* WHAT YOU CAN PRESS IS WHAT YOU CAN SEE.
1645
981
  [data-graview-stage="dom"] [data-graview-view] > [data-graview-natural] {
1646
982
  pointer-events: none;
1647
983
  }
1648
- [data-graview-stage="dom"] [data-graview-view] > :not([data-graview-natural]),
1649
- [data-graview-stage="dom"] [data-graview-view] > [data-graview-natural] > * {
1650
- pointer-events: auto;
1651
- }
1652
- [data-graview-view][data-graview-selected] {
1653
- filter: drop-shadow(0 0 14px var(--graview-accent-dim));
1654
- }
1655
984
 
1656
985
  ${ /* A node implicated by the last change, whoever made it. The pulse is the
1657
986
  same for a human edit and an agent edit, because the diff is. */""}
@@ -1728,47 +1057,12 @@ ${ /* A QUESTION THE SEAT ASKED, standing at the node it is about: it says
1728
1057
  35% { box-shadow: 0 0 26px 3px var(--graview-accent-dim); }
1729
1058
  100% { box-shadow: 0 0 0 0 transparent; }
1730
1059
  }
1731
- [data-graview-touched] > * {
1732
- animation: graview-touched 1100ms cubic-bezier(0.22, 1, 0.36, 1);
1733
- border-radius: 10px;
1734
- }
1735
-
1736
- ${ /* ------------------------------------------------------------ watching
1737
- *
1738
- * From outside the plane stack, activity has somewhere to HAPPEN: a kind
1739
- * lights where an edit landed, an edge pulses where a relation was made or
1740
- * broken, and a flag appears where a rule started failing. All of it is
1741
- * derived from the op log — author, intent, reads and writes — and all of it
1742
- * is drawn by these rules rather than by a frame loop, which is why watching
1743
- * costs nothing while nothing is happening.
1744
- *
1745
- * Who moved is carried in HUE, not in a badge. A person is the accent the
1746
- * whole interface already uses for "you did this"; an agent is a colder cast,
1747
- * so a turn it took on its own is distinguishable at a glance from one you
1748
- * directed; both at once takes both.
1749
- */""}
1750
- [data-graview-activity] {
1751
- --graview-activity: var(--graview-accent);
1752
- }
1753
- [data-graview-activity="autonomous"] {
1754
- --graview-activity: hsl(212 72% 62%);
1755
- }
1756
- [data-graview-activity="co-edited"] {
1757
- --graview-activity: hsl(280 60% 66%);
1758
- }
1759
- [data-graview-activity="rule"] {
1760
- --graview-activity: var(--graview-warn);
1761
- }
1762
1060
 
1763
1061
  @keyframes graview-landed {
1764
1062
  0% { box-shadow: 0 0 0 0 var(--graview-activity); opacity: 0.55; }
1765
1063
  30% { box-shadow: 0 0 30px 4px var(--graview-activity); opacity: 1; }
1766
1064
  100% { box-shadow: 0 0 0 0 transparent; opacity: 1; }
1767
1065
  }
1768
- [data-graview-view][data-graview-wrote] > * {
1769
- animation: graview-landed 900ms cubic-bezier(0.22, 1, 0.36, 1);
1770
- border-radius: 10px;
1771
- }
1772
1066
 
1773
1067
  ${ /* What an agent READ is the half a diff cannot show, and the half that says
1774
1068
  whether to trust what it then did. Quieter than a write on purpose: it is
@@ -1778,20 +1072,6 @@ ${ /* What an agent READ is the half a diff cannot show, and the half that says
1778
1072
  25% { outline-color: var(--graview-activity); }
1779
1073
  100% { outline-color: transparent; }
1780
1074
  }
1781
- [data-graview-view][data-graview-read] > :not([data-graview-natural]):not(.graview-kind-tag),
1782
- [data-graview-view][data-graview-read] > [data-graview-natural] > * {
1783
- outline: 1px dashed transparent;
1784
- outline-offset: 3px;
1785
- border-radius: 10px;
1786
- animation: graview-considered 1800ms ease-out;
1787
- }
1788
-
1789
- ${ /* A rule that has just begun to fail. It outlives the edit that caused it,
1790
- because the problem does. */""}
1791
- [data-graview-view][data-graview-broke] > * {
1792
- box-shadow: 0 0 0 1px var(--graview-warn), 0 0 22px -6px var(--graview-warn);
1793
- border-radius: 10px;
1794
- }
1795
1075
 
1796
1076
  ${ /* A relation made or broken: both ends were written, so the line between
1797
1077
  them is the thing that changed. */""}
@@ -1800,9 +1080,6 @@ ${ /* A relation made or broken: both ends were written, so the line between
1800
1080
  30% { stroke-opacity: 1; stroke-width: 3; }
1801
1081
  100% { stroke-opacity: 0.28; stroke-width: 1.4; }
1802
1082
  }
1803
- [data-graview-connector][data-graview-activity] {
1804
- animation: graview-relation 1200ms cubic-bezier(0.22, 1, 0.36, 1);
1805
- }
1806
1083
 
1807
1084
  ${ /*
1808
1085
  * MOTION, ASKED OF THE SYSTEM AND OVERRIDABLE BY THE PERSON.