@bongos/core 1.19.928 → 1.19.930
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.
- package/.bongos-core.json +80 -50
- package/docs/copy-inventory.md +36 -15
- package/docs/copy-registry.json +239 -28
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +4 -0
- package/modules/hall-ui/public/atlas.html +1 -1
- package/modules/hall-ui/public/blockers.html +1 -1
- package/modules/hall-ui/public/board-room.html +1 -1
- package/modules/hall-ui/public/collab.html +1 -1
- package/modules/hall-ui/public/copy-desk.html +1 -1
- package/modules/hall-ui/public/deploy.html +1 -1
- package/modules/hall-ui/public/diagrams.html +1 -1
- package/modules/hall-ui/public/drachmae.html +1 -1
- package/modules/hall-ui/public/gate.html +1 -1
- package/modules/hall-ui/public/goals.html +1 -1
- package/modules/hall-ui/public/government.html +1 -1
- package/modules/hall-ui/public/idea-objects.js +109 -0
- package/modules/hall-ui/public/idea.html +1 -1
- package/modules/hall-ui/public/ideas.html +1 -1
- package/modules/hall-ui/public/index.html +1 -1
- package/modules/hall-ui/public/modules.html +1 -1
- package/modules/hall-ui/public/people.html +1 -1
- package/modules/hall-ui/public/primer.html +1 -1
- package/modules/hall-ui/public/profile.html +1 -1
- package/modules/hall-ui/public/project-settings.html +1 -1
- package/modules/hall-ui/public/ranks.html +1 -1
- package/modules/hall-ui/public/roadmap.html +1 -1
- package/modules/hall-ui/public/roster.html +1 -1
- package/modules/hall-ui/public/sessions.html +1 -1
- package/modules/hall-ui/public/settings.html +1 -1
- package/modules/hall-ui/public/shell.js +11 -0
- package/modules/hall-ui/public/studio.html +1 -1
- package/modules/hall-ui/public/style.css +10 -0
- package/modules/hall-ui/public/task.html +1 -1
- package/modules/hall-ui/public/thinking.css +277 -0
- package/modules/hall-ui/public/thinking.html +74 -0
- package/modules/hall-ui/public/thinking.js +418 -0
- package/modules/hall-ui/public/thinking.states.json +20 -0
- package/modules/hall-ui/public/watch.html +1 -1
- package/modules/hall-ui/public/work.html +1 -1
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/src/bongos/serve-internal.js +7 -1
- package/src/module-api.js +1 -1
- package/tests/hall_board_world.mjs +32 -0
- package/tests/hall_nav.mjs +1 -1
- package/tests/hall_page_gate_map.mjs +6 -0
- package/tests/hall_thinking_room.mjs +366 -0
- package/tests/helpers.mjs +124 -0
- package/tests/nav_permission_atoms.mjs +1 -1
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
// modules/hall-ui/public/idea-objects.js — THE FIVE OBJECTS, as a reader's
|
|
2
|
+
// words (task 1004098 / BV2.R03 "the room", goal 1000095).
|
|
3
|
+
//
|
|
4
|
+
// The server derives which object a thought IS — once, in
|
|
5
|
+
// modules/ideas/idea-state.js, from the ledger (ADR 0322). This file is the
|
|
6
|
+
// other half of that decision and deliberately does NOT re-derive anything: it
|
|
7
|
+
// maps a state the server already answered onto the word, the sentence and the
|
|
8
|
+
// mark a surface draws for it. `resolveIdeaState` is the authority on WHICH of
|
|
9
|
+
// the five; this is the authority on how one LOOKS.
|
|
10
|
+
//
|
|
11
|
+
// IT IS SHARED BECAUSE TWO SURFACES DRAW THESE AND A THIRD WILL. The room
|
|
12
|
+
// (this task) is the first, the sky (BV2.R26) is the next, and the idea record
|
|
13
|
+
// is the obvious third. A vocabulary copied into each of them is how the sky
|
|
14
|
+
// ends up calling a thought "burned out" while the room beside it says
|
|
15
|
+
// "declined" — the same failure the resolver exists to prevent, one layer up.
|
|
16
|
+
// The descent on /idea/:id is deliberately NOT a consumer: a descent row is a
|
|
17
|
+
// TASK, and marking one with an idea-level object would be exactly the
|
|
18
|
+
// re-derivation this pair of files refuses (see idea.js, "what a row is marked
|
|
19
|
+
// by").
|
|
20
|
+
//
|
|
21
|
+
// THE WORDS ARE THE DESIGN'S, taken from docs/design/ideator-surface-direction.md
|
|
22
|
+
// §"The five objects" rather than invented here, so the surface says what the
|
|
23
|
+
// owner said. Where that table is a fragment ("it burned, then the project
|
|
24
|
+
// removed it"), it is spelled into a sentence and nothing more.
|
|
25
|
+
//
|
|
26
|
+
// NO DOM, no fetch, no state. One frozen table and three lookups, so a page
|
|
27
|
+
// under test can read it without booting a page.
|
|
28
|
+
(function () {
|
|
29
|
+
'use strict';
|
|
30
|
+
|
|
31
|
+
// Canonical order. It is the order the design lists them in and the order a
|
|
32
|
+
// filter row draws them in — brightest and most actionable first, folded and
|
|
33
|
+
// declined last — so two surfaces cannot disagree about where a pill sits.
|
|
34
|
+
var ORDER = ['star', 'protostar', 'satellite', 'remnant', 'cold-body'];
|
|
35
|
+
|
|
36
|
+
var OBJECTS = {
|
|
37
|
+
star: {
|
|
38
|
+
label: 'burning',
|
|
39
|
+
noun: 'star',
|
|
40
|
+
blurb: 'caused work that is still alive. it dims as pieces of that work are removed',
|
|
41
|
+
},
|
|
42
|
+
protostar: {
|
|
43
|
+
label: 'waiting',
|
|
44
|
+
noun: 'protostar',
|
|
45
|
+
blurb: 'filed, not yet ignited',
|
|
46
|
+
},
|
|
47
|
+
satellite: {
|
|
48
|
+
label: 'folded in',
|
|
49
|
+
noun: 'satellite',
|
|
50
|
+
blurb: 'folded into another thought. it orbits that one now, and its value counts there',
|
|
51
|
+
},
|
|
52
|
+
remnant: {
|
|
53
|
+
label: 'burned out',
|
|
54
|
+
noun: 'remnant',
|
|
55
|
+
blurb: 'it burned, then the project removed it. it keeps every bit of its size',
|
|
56
|
+
},
|
|
57
|
+
'cold-body': {
|
|
58
|
+
label: 'declined',
|
|
59
|
+
noun: 'cold body',
|
|
60
|
+
blurb: 'declined at triage. it never ignited, so it has no size at all',
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// An unknown state is passed through rather than swallowed, the way idea.js
|
|
65
|
+
// passes through an unknown descent relation: a sixth object would be a real
|
|
66
|
+
// answer the server gave, and drawing it unstyled beats drawing nothing or,
|
|
67
|
+
// worse, silently drawing it as a protostar.
|
|
68
|
+
function objectFor(state) {
|
|
69
|
+
var key = String(state || '');
|
|
70
|
+
return OBJECTS[key] || { label: key || 'unknown', noun: key || 'unknown', blurb: '' };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// POSITION is the second axis and it is only load-bearing for a protostar —
|
|
74
|
+
// the design is explicit that a star has a position too, and that the
|
|
75
|
+
// distinction only MEANS something for a thought nothing has claimed yet.
|
|
76
|
+
// So this returns a sentence for exactly that case and null otherwise,
|
|
77
|
+
// rather than letting every row carry a word that tells a reader nothing.
|
|
78
|
+
function positionWord(state) {
|
|
79
|
+
if (!state || state.state !== 'protostar') return null;
|
|
80
|
+
if (state.position !== 'well') return 'nothing has claimed it';
|
|
81
|
+
return state.awaitingNod ? 'waiting for a nod' : 'has a home';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Brightness as a reader's phrase. THE THREE ANSWERS ARE THREE, never two:
|
|
85
|
+
// a number → this share of the work it caused is still alive
|
|
86
|
+
// null → the removal facts could not be read at all
|
|
87
|
+
// no work → nothing to be alive or dead yet
|
|
88
|
+
// Collapsing "we could not look" into "none of it survived" is the exact
|
|
89
|
+
// mistake modules/ideas/idea-state.js step 3 was written to prevent, and it
|
|
90
|
+
// would render a healthy instance as a field of hollow rings the moment the
|
|
91
|
+
// lifecycle module failed to mount.
|
|
92
|
+
function brightnessWord(state) {
|
|
93
|
+
if (!state || state.hasWork !== true) return null;
|
|
94
|
+
if (state.attributable !== true || state.brightness === null || state.brightness === undefined) {
|
|
95
|
+
return 'still alive — unknown';
|
|
96
|
+
}
|
|
97
|
+
var pct = Math.round(Number(state.brightness) * 100);
|
|
98
|
+
if (pct >= 100) return 'all of it still alive';
|
|
99
|
+
if (pct <= 0) return 'none of it still alive';
|
|
100
|
+
return pct + '% still alive';
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
window.OTBIdeaObjects = {
|
|
104
|
+
ORDER: ORDER,
|
|
105
|
+
objectFor: objectFor,
|
|
106
|
+
positionWord: positionWord,
|
|
107
|
+
brightnessWord: brightnessWord,
|
|
108
|
+
};
|
|
109
|
+
})();
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
|
|
53
53
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
54
54
|
|
|
55
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
55
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
56
56
|
<script src="/builders/palette.js" defer></script>
|
|
57
57
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib" defer></script>
|
|
58
58
|
<!-- task-detail.js still owns the #/idea/N and #/blocker/N overlay, so a ref
|
|
@@ -192,7 +192,7 @@
|
|
|
192
192
|
|
|
193
193
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
194
194
|
|
|
195
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
195
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
196
196
|
<script src="/builders/palette.js" defer></script>
|
|
197
197
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
198
198
|
<!-- task 1003069 (R08) — the quick-filing form's routed result links a task
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
<script src="/builders/brand-apply.js?v=2026-06-27-r75" defer></script>
|
|
103
103
|
<!-- The app shell (sidebar + top bar + view router). Dependency-free; loaded
|
|
104
104
|
BEFORE builders.js so the chrome ids exist when events are wired. -->
|
|
105
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
105
|
+
<script src="/builders/shell.js?v=2026-09-20-room1" defer></script>
|
|
106
106
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
107
107
|
<script src="/builders/palette.js" defer></script>
|
|
108
108
|
<!-- task 2166: the shared component kit (window.OTBKit) — pager/ledger/rail.
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
|
|
81
81
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
82
82
|
|
|
83
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
83
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
84
84
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
85
85
|
<script src="/builders/palette.js" defer></script>
|
|
86
86
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
|
|
56
56
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
57
57
|
chrome exists before the page script runs. -->
|
|
58
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
58
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
59
59
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
60
60
|
<script src="/builders/palette.js" defer></script>
|
|
61
61
|
<!-- shared frontend toolkit (window.OTB — rank labels, number formats) + the
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
|
|
116
116
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
117
117
|
|
|
118
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
118
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
119
119
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
120
120
|
<script src="/builders/palette.js" defer></script>
|
|
121
121
|
<!-- the shared markdown reader (window.OTBMdReader) — primer.js renders through
|
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
|
|
188
188
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
189
189
|
chrome exists before the page script runs. -->
|
|
190
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
190
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
191
191
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
192
192
|
<script src="/builders/palette.js" defer></script>
|
|
193
193
|
<!-- shared frontend toolkit (window.OTB) — loaded before profile.js, which pulls from it. -->
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
|
|
59
59
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
60
60
|
|
|
61
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
61
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
62
62
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
63
63
|
<script src="/builders/palette.js" defer></script>
|
|
64
64
|
<script src="/builders/dom-utils.js?v=2026-06-16-gate"></script>
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
|
|
69
69
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
70
70
|
chrome exists before the page script runs. -->
|
|
71
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
71
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
72
72
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
73
73
|
<script src="/builders/palette.js" defer></script>
|
|
74
74
|
<!-- shared frontend toolkit (window.OTB) — loaded before ranks.js, which pulls from it. -->
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
|
|
42
42
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
43
43
|
|
|
44
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
44
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
45
45
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
46
46
|
<script src="/builders/palette.js" defer></script>
|
|
47
47
|
<script src="/builders/dom-utils.js?v=2026-06-14-domutils"></script>
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
|
|
51
51
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
52
52
|
chrome exists before the page script runs. -->
|
|
53
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
53
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
54
54
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
55
55
|
<script src="/builders/palette.js" defer></script>
|
|
56
56
|
<!-- shared frontend toolkit (window.OTB — rank labels, number formats) + the
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
|
|
100
100
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
101
101
|
chrome exists before the page script runs. -->
|
|
102
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
102
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
103
103
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
104
104
|
<script src="/builders/palette.js" defer></script>
|
|
105
105
|
<!-- shared frontend toolkit (window.OTB) — loaded BEFORE sessions.js so it can pull from it. -->
|
|
@@ -416,7 +416,7 @@
|
|
|
416
416
|
|
|
417
417
|
<!-- The app shell (sidebar + top bar). Dependency-free; loaded FIRST so the
|
|
418
418
|
chrome exists before the page scripts run. -->
|
|
419
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
419
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
420
420
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
421
421
|
<script src="/builders/palette.js" defer></script>
|
|
422
422
|
<!-- shared frontend toolkit (window.OTB) — loaded before consuming IIFEs. -->
|
|
@@ -216,6 +216,17 @@
|
|
|
216
216
|
// behind the ideator craft would hide the ideator's own surface from
|
|
217
217
|
// everyone else who has a thought, which is most of the value.
|
|
218
218
|
{ id: 'ideas', label: 'Ideas', icon: 'goals', href: '/ideas', gate: 'signed' },
|
|
219
|
+
// task 1004098 (BV2.R03 of goal 1000095): THE ROOM — what you filed and
|
|
220
|
+
// what became of it. Directly under Ideas because the two are the daily
|
|
221
|
+
// loop: you file on one and you find out on the other, and the whole
|
|
222
|
+
// criterion (`ideator-nothing-is-lost`) is that the second half must be
|
|
223
|
+
// reachable without asking anyone. NOT in the 'You' group beside Standing
|
|
224
|
+
// and Profile, even though it is your own view: that group is your
|
|
225
|
+
// numbers, and this page's subject is the project's work, seen from the
|
|
226
|
+
// thought that caused it. gate 'signed' for the same reason Ideas is —
|
|
227
|
+
// there is no permission gate on having a thought, and the route reads the
|
|
228
|
+
// VIEWER's own trail, so there is nothing here a rank could protect.
|
|
229
|
+
{ id: 'thinking', label: 'Your thinking', icon: 'goals', href: '/thinking', gate: 'signed' },
|
|
219
230
|
{ id: 'copy-desk', label: 'Copy desk', icon: 'docs', href: '/copy-desk', gate: 'signed', module: 'copy-desk' },
|
|
220
231
|
// task 1003117 (R06 of goal 1000074): the Studio — artist mode, "a place an
|
|
221
232
|
// artist wants to be, not a form". Beside the copy desk (the artist's other
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
|
|
67
67
|
<div id="toast" class="toast" role="status" aria-live="polite" data-visible="0"></div>
|
|
68
68
|
|
|
69
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
69
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
70
70
|
<script src="/builders/palette.js" defer></script>
|
|
71
71
|
<script src="/builders/dom-utils.js?v=2026-06-23-contrib"></script>
|
|
72
72
|
<!-- The kit, for its ONE renderer: the full-size ship-time visual figure
|
|
@@ -3163,10 +3163,20 @@ main [id] { scroll-margin-top: calc(var(--topbar-h) + 16px); }
|
|
|
3163
3163
|
/* tab strip — the .setup__tab idiom in the .setup__toggle frame, promoted */
|
|
3164
3164
|
/* A tab strip is hairlines, not a segmented box: one rule under the row and a
|
|
3165
3165
|
2px accent underline on the open tab, the lit-step grammar again. */
|
|
3166
|
+
/* Both axes are named on purpose, and the pair is load-bearing — do not
|
|
3167
|
+
"simplify" this back to the single `overflow-x`. Per the overflow spec a
|
|
3168
|
+
non-`visible` value on one axis computes the OTHER axis to `auto` too, so
|
|
3169
|
+
`overflow-x: auto` alone made the strip a scroll container vertically as
|
|
3170
|
+
well; `.setup__tab`'s `margin-bottom: -1px` (the underline sitting on the
|
|
3171
|
+
strip's hairline, below) then overflowed it by exactly 1px and every hall
|
|
3172
|
+
page with tabs grew a vertical scrollbar it could never scroll. `hidden` is
|
|
3173
|
+
the fix and `visible` is not: `visible` beside an `auto` is the value the
|
|
3174
|
+
spec rewrites, which would put the bug straight back (task 1004130). */
|
|
3166
3175
|
.kit-tabs {
|
|
3167
3176
|
display: flex;
|
|
3168
3177
|
max-width: 100%;
|
|
3169
3178
|
overflow-x: auto;
|
|
3179
|
+
overflow-y: hidden;
|
|
3170
3180
|
border: 0;
|
|
3171
3181
|
border-bottom: 1px solid var(--rule);
|
|
3172
3182
|
border-radius: 0;
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
|
|
58
58
|
<!-- The app shell (sidebar + top bar + footer). Dependency-free; runs at parse
|
|
59
59
|
time so the chrome exists before the deferred page scripts execute. -->
|
|
60
|
-
<script src="/builders/shell.js?v=2026-09-20-
|
|
60
|
+
<script src="/builders/shell.js?v=2026-09-20-room1"></script>
|
|
61
61
|
<!-- jump palette (Ctrl/Cmd-K). Optional by design: without it the shell's slot stays hidden. -->
|
|
62
62
|
<script src="/builders/palette.js" defer></script>
|
|
63
63
|
<!-- shared frontend toolkit (window.OTB) — loaded FIRST so task.js can pull from it. -->
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/* thinking.css — what THE ROOM has that no other hall page has
|
|
2
|
+
(task 1004098 / BV2.R03, goal 1000095).
|
|
3
|
+
|
|
4
|
+
The composition is the shell's: `.page-head--board`, `.scroll`, `.ledger` and
|
|
5
|
+
the kit's `.kit-tabs` strip all come from style.css and are not restated here.
|
|
6
|
+
What is left is the three shapes only this page has — the figure run over the
|
|
7
|
+
list, the size bar, and the mark for the five objects — plus the cells the
|
|
8
|
+
ledger has no opinion about.
|
|
9
|
+
|
|
10
|
+
NO COLOUR THAT IS NOT A TOKEN. Every value below is one of the world's
|
|
11
|
+
fifteen or a color-mix of them, so the page inherits dark and light from the
|
|
12
|
+
pack rather than declaring either: there is not one mode-specific rule in this
|
|
13
|
+
sheet, which is why it needs no dark twin. `--line` is a WIDTH; a hairline's
|
|
14
|
+
colour is `--rule` / `--rule-soft`.
|
|
15
|
+
|
|
16
|
+
NO MOTION. Nothing here transitions or animates, so the sheet sits entirely
|
|
17
|
+
inside the Kill Switch rather than needing to be excused by it. The one thing
|
|
18
|
+
that could have moved — a size bar growing as the background pages land —
|
|
19
|
+
deliberately does not: the bar is a measurement, and a measurement that
|
|
20
|
+
animates on every re-render turns a quiet page into a twitching one. */
|
|
21
|
+
|
|
22
|
+
/* ---- the figures over the list -------------------------------------------
|
|
23
|
+
The same object as the descent's `.ig-desc__figs` on /idea/:id, and that is
|
|
24
|
+
on purpose rather than by accident: the two pages state the same kind of fact
|
|
25
|
+
(a count over a body of work) and a reader moving between them should not
|
|
26
|
+
have to learn a second shape for it. It is not SHARED code, because the
|
|
27
|
+
descent's figures live in the idea record's own sheet and hoisting them into
|
|
28
|
+
style.css to serve two pages is an archetype decision, not a page's. If a
|
|
29
|
+
third surface wants them — the sky will — that is the moment. */
|
|
30
|
+
.tr-figs {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-wrap: wrap;
|
|
33
|
+
gap: var(--sp-md) var(--sp-lg);
|
|
34
|
+
margin: 0 0 var(--sp-md);
|
|
35
|
+
}
|
|
36
|
+
.tr-fig { display: grid; gap: 6px; }
|
|
37
|
+
.tr-fig__n {
|
|
38
|
+
font-size: 32px;
|
|
39
|
+
font-weight: 300;
|
|
40
|
+
line-height: 1;
|
|
41
|
+
letter-spacing: -0.03em;
|
|
42
|
+
font-variant-numeric: tabular-nums;
|
|
43
|
+
color: var(--ink);
|
|
44
|
+
}
|
|
45
|
+
/* Only ONE figure is warm, and it is the live one — "still burning" is the
|
|
46
|
+
number the page exists to make visible, and an accent spent on all four would
|
|
47
|
+
say nothing. "burned out" goes faint for the same reason it does in the
|
|
48
|
+
descent: the record of work that happened is not an error to shout. */
|
|
49
|
+
.tr-fig[data-tone="warm"] .tr-fig__n { color: var(--accent-deep); }
|
|
50
|
+
.tr-fig[data-tone="dim"] .tr-fig__n { color: var(--ink-faint); }
|
|
51
|
+
.tr-fig__label {
|
|
52
|
+
font-family: var(--label-face);
|
|
53
|
+
font-size: var(--label-size);
|
|
54
|
+
letter-spacing: var(--label-space);
|
|
55
|
+
text-transform: var(--label-case);
|
|
56
|
+
color: var(--ink-faint);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* ---- the filter strip ---------------------------------------------------- */
|
|
60
|
+
/* The strip itself is `.kit-tabs`; all this adds is the air under it, because
|
|
61
|
+
the kit's own margin assumes a panel directly beneath and here a table
|
|
62
|
+
follows. */
|
|
63
|
+
.tr-filters { margin: 0 0 var(--sp-sm); }
|
|
64
|
+
|
|
65
|
+
/* ---- the rows ------------------------------------------------------------ */
|
|
66
|
+
/* The four short columns are pinned and the two prose ones share what is left,
|
|
67
|
+
so the row's SUBJECT — the thought — gets the width instead of losing it to
|
|
68
|
+
an outcome sentence that happens to be long. `width` on a th is a hint under
|
|
69
|
+
`table-layout: auto`, which is what is wanted here: a pinned column still
|
|
70
|
+
gives way rather than clipping when a cell genuinely needs more. */
|
|
71
|
+
.tr-table { table-layout: auto; }
|
|
72
|
+
.tr-table th:nth-child(1) { width: 34%; }
|
|
73
|
+
.tr-table th:nth-child(2) { width: 100px; }
|
|
74
|
+
.tr-table th:nth-child(3) { width: 30%; }
|
|
75
|
+
.tr-table th:nth-child(4) { width: 104px; }
|
|
76
|
+
.tr-table th:nth-child(5) { width: 142px; }
|
|
77
|
+
/* The thought is the row's subject, so it is the one cell that may take the
|
|
78
|
+
width and the one cell whose link reads at body size. */
|
|
79
|
+
.tr-thought a {
|
|
80
|
+
display: inline-block;
|
|
81
|
+
min-height: 24px;
|
|
82
|
+
padding: 3px 0;
|
|
83
|
+
line-height: 18px;
|
|
84
|
+
color: var(--ink);
|
|
85
|
+
border-bottom: var(--line) solid var(--rule);
|
|
86
|
+
}
|
|
87
|
+
.tr-thought a:hover { border-bottom-color: var(--ink); text-decoration: none; }
|
|
88
|
+
.tr-became { font-size: 13.5px; color: var(--ink-soft); }
|
|
89
|
+
.tr-became a {
|
|
90
|
+
display: inline-block;
|
|
91
|
+
min-height: 24px;
|
|
92
|
+
padding: 3px 0;
|
|
93
|
+
line-height: 18px;
|
|
94
|
+
color: var(--ink-soft);
|
|
95
|
+
border-bottom: var(--line) solid var(--rule-soft);
|
|
96
|
+
}
|
|
97
|
+
.tr-became a:hover { color: var(--ink); border-bottom-color: var(--ink); text-decoration: none; }
|
|
98
|
+
.tr-quiet { color: var(--ink-faint); }
|
|
99
|
+
/* The one actionable phrase on the page — a task sitting at backlog inside a
|
|
100
|
+
goal is one promote from claimable — so it is the only thing in a row that
|
|
101
|
+
takes the accent, and it says the word as well as wearing the colour. */
|
|
102
|
+
.tr-nod { color: var(--accent-ink); }
|
|
103
|
+
|
|
104
|
+
/* ---- size ---------------------------------------------------------------- */
|
|
105
|
+
/* Bar and number together, never the bar alone: size is long-tailed and its
|
|
106
|
+
compressed width is a comparison, not a quantity. The direction is explicit
|
|
107
|
+
that the true figure stays available wherever the drawing is. */
|
|
108
|
+
.tr-sizecell { white-space: nowrap; }
|
|
109
|
+
.tr-size { display: inline-flex; align-items: center; gap: 10px; }
|
|
110
|
+
.tr-size__bar {
|
|
111
|
+
display: block;
|
|
112
|
+
flex: none;
|
|
113
|
+
width: 56px;
|
|
114
|
+
height: 3px;
|
|
115
|
+
border-radius: 999px;
|
|
116
|
+
/* The track is the unfilled remainder; the fill is the accent at the server's
|
|
117
|
+
own compressed width. One element, so a row costs no extra box. */
|
|
118
|
+
background:
|
|
119
|
+
linear-gradient(to right, var(--fill, var(--accent)) 0 var(--w, 0%), transparent var(--w, 0%) 100%),
|
|
120
|
+
var(--rule-soft);
|
|
121
|
+
}
|
|
122
|
+
/* Every bit of its size, none of its colour — the remnant's whole picture. See
|
|
123
|
+
thinking.js sizeHtml() for why this is set from the state and not from the
|
|
124
|
+
number. `--ink-faint` and not `--rule`: at the hairline's weight a full-width
|
|
125
|
+
bar stops clearing the 3:1 non-text floor on the dark ground, and this bar is
|
|
126
|
+
the one that must still read as LARGE. */
|
|
127
|
+
.tr-size[data-lit="out"] { --fill: var(--ink-faint); }
|
|
128
|
+
.tr-size__n {
|
|
129
|
+
font-size: 13px;
|
|
130
|
+
font-variant-numeric: tabular-nums;
|
|
131
|
+
color: var(--ink-soft);
|
|
132
|
+
}
|
|
133
|
+
/* A size computed from a descent rather than from payouts that were made. It is
|
|
134
|
+
a footnote, not a warning — the number is real, it just means something
|
|
135
|
+
slightly different, and the title says which. */
|
|
136
|
+
.tr-hist {
|
|
137
|
+
display: block;
|
|
138
|
+
margin-top: 2px;
|
|
139
|
+
font-size: 11.5px;
|
|
140
|
+
color: var(--ink-faint);
|
|
141
|
+
text-decoration: none;
|
|
142
|
+
border-bottom: var(--line) dotted var(--rule);
|
|
143
|
+
cursor: help;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/* ---- the five objects ---------------------------------------------------- */
|
|
147
|
+
/* THE MARK RESTATES THE WORD IN SHAPE. Every object below differs from the
|
|
148
|
+
others by geometry — filled, haloed, ringed, outlined — and not only by tone,
|
|
149
|
+
because a mark distinguished by colour alone tells a colour-blind reader
|
|
150
|
+
nothing. That is the sheet's existing rule for the grade badge and the
|
|
151
|
+
descent's glyph; this is the same rule applied to a vocabulary of five.
|
|
152
|
+
|
|
153
|
+
`--lit` is the server's brightness, between 0 and 1, set per row by
|
|
154
|
+
thinking.js. It rides the star's opacity — and the star's ALONE, because the
|
|
155
|
+
other four objects have no live share to show and dimming them would invent
|
|
156
|
+
one. A star whose brightness could not be READ arrives with --lit: 1 and says
|
|
157
|
+
so in words (idea-objects.js brightnessWord); a full glyph over "still alive
|
|
158
|
+
— unknown" is the honest pair. The floor of 0.35 is a contrast floor: below
|
|
159
|
+
it the mark stops clearing 3:1 against the ground and a dim star becomes an
|
|
160
|
+
absent one, which is the wrong reading entirely — a star is never nothing. */
|
|
161
|
+
.tr-objcell { white-space: nowrap; }
|
|
162
|
+
.tr-obj { display: inline-flex; align-items: flex-start; gap: 10px; }
|
|
163
|
+
.tr-obj__glyph {
|
|
164
|
+
flex: none;
|
|
165
|
+
width: 9px;
|
|
166
|
+
height: 9px;
|
|
167
|
+
margin-top: 5px;
|
|
168
|
+
border-radius: 50%;
|
|
169
|
+
background: var(--ink-faint);
|
|
170
|
+
}
|
|
171
|
+
.tr-obj__body { display: grid; gap: 2px; min-width: 0; }
|
|
172
|
+
.tr-obj__label { font-size: 13.5px; color: var(--ink); }
|
|
173
|
+
.tr-obj__sub { font-size: 12px; color: var(--ink-faint); }
|
|
174
|
+
|
|
175
|
+
/* star — filled, accent, dimmed by its live share. */
|
|
176
|
+
.tr-obj[data-object="star"] .tr-obj__glyph {
|
|
177
|
+
background: var(--accent);
|
|
178
|
+
opacity: max(0.35, var(--lit, 1));
|
|
179
|
+
}
|
|
180
|
+
/* protostar — small and haloed: matter gathering, not yet burning. The halo is
|
|
181
|
+
a ring of the accent mixed back into the ground, so it reads as glow rather
|
|
182
|
+
than as a second border. */
|
|
183
|
+
.tr-obj[data-object="protostar"] .tr-obj__glyph {
|
|
184
|
+
width: 7px;
|
|
185
|
+
height: 7px;
|
|
186
|
+
margin-top: 6px;
|
|
187
|
+
background: var(--ink-soft);
|
|
188
|
+
box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 18%, transparent);
|
|
189
|
+
}
|
|
190
|
+
/* satellite — a small body with an orbit around it, detached from the mark so
|
|
191
|
+
it reads as something going round rather than as a thick edge. */
|
|
192
|
+
.tr-obj[data-object="satellite"] .tr-obj__glyph {
|
|
193
|
+
width: 6px;
|
|
194
|
+
height: 6px;
|
|
195
|
+
margin-top: 6px;
|
|
196
|
+
background: var(--ink-soft);
|
|
197
|
+
outline: var(--line) solid var(--rule);
|
|
198
|
+
outline-offset: 4px;
|
|
199
|
+
}
|
|
200
|
+
/* remnant — the hollow ring, and the largest mark of the five. A thought that
|
|
201
|
+
caused a great deal of work the project then tore out renders LARGE and DEAD:
|
|
202
|
+
that is the whole reason size and brightness are two channels, so the object
|
|
203
|
+
that carries it must not be the quietest thing in the column. `--ink-faint`
|
|
204
|
+
and not `--rule`: at the hairline's weight this measured under the 3:1
|
|
205
|
+
non-text floor on the dark ground, the same finding the descent's "out" glyph
|
|
206
|
+
recorded. */
|
|
207
|
+
.tr-obj[data-object="remnant"] .tr-obj__glyph {
|
|
208
|
+
width: 12px;
|
|
209
|
+
height: 12px;
|
|
210
|
+
margin-top: 4px;
|
|
211
|
+
background: transparent;
|
|
212
|
+
box-shadow: inset 0 0 0 1.5px var(--ink-faint);
|
|
213
|
+
}
|
|
214
|
+
/* cold body — the smallest mark there is, a dark point with a hairline edge. It
|
|
215
|
+
never ignited, so it has no size at all, and the mark says that by being the
|
|
216
|
+
one object with nothing inside it and nothing around it. */
|
|
217
|
+
.tr-obj[data-object="cold-body"] .tr-obj__glyph {
|
|
218
|
+
width: 6px;
|
|
219
|
+
height: 6px;
|
|
220
|
+
margin-top: 6px;
|
|
221
|
+
background: var(--surface-2);
|
|
222
|
+
box-shadow: inset 0 0 0 var(--line) var(--ink-faint);
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* ---- notes + the empty state --------------------------------------------- */
|
|
226
|
+
.tr-note { font-size: 13.5px; color: var(--ink-faint); margin: 0; }
|
|
227
|
+
.tr-empty {
|
|
228
|
+
margin: 0;
|
|
229
|
+
padding: var(--sp-md) 0;
|
|
230
|
+
font-size: 14px;
|
|
231
|
+
color: var(--ink-soft);
|
|
232
|
+
max-width: var(--measure);
|
|
233
|
+
}
|
|
234
|
+
.tr-foot {
|
|
235
|
+
margin: var(--sp-md) 0 0;
|
|
236
|
+
font-size: 13px;
|
|
237
|
+
color: var(--ink-faint);
|
|
238
|
+
max-width: var(--measure);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/* ---- the phone ----------------------------------------------------------- */
|
|
242
|
+
/* Nothing below widens the document — the page never scrolls sideways, and the
|
|
243
|
+
restacking here is what makes that true without leaning on the shell's strip
|
|
244
|
+
at all. */
|
|
245
|
+
@media (max-width: 640px) {
|
|
246
|
+
.tr-fig__n { font-size: 26px; }
|
|
247
|
+
/* THE TABLE STOPS BEING A TABLE. The shell would give it a horizontal strip
|
|
248
|
+
(`:has(> .ledger)`) and the page would still measure clean — but five
|
|
249
|
+
columns inside a 390px strip is a table nobody can read: the thought column
|
|
250
|
+
collapses to one word per line while the object scrolls off the right, so
|
|
251
|
+
the row's two most important facts end up on opposite sides of a gesture.
|
|
252
|
+
A strip is the right answer for a ledger whose columns are a grid of
|
|
253
|
+
numbers; this one is a sentence plus three facts about it, and those stack.
|
|
254
|
+
The row becomes one flex line-box: the thought takes the width, and filed,
|
|
255
|
+
size and object run under it. */
|
|
256
|
+
.tr-table,
|
|
257
|
+
.tr-table tbody,
|
|
258
|
+
.tr-table td { display: block; width: auto; }
|
|
259
|
+
.tr-table thead { display: none; }
|
|
260
|
+
.tr-table tr {
|
|
261
|
+
display: flex;
|
|
262
|
+
flex-wrap: wrap;
|
|
263
|
+
align-items: baseline;
|
|
264
|
+
gap: 6px 16px;
|
|
265
|
+
padding: 14px 0;
|
|
266
|
+
border-bottom: 1px solid var(--rule-soft);
|
|
267
|
+
}
|
|
268
|
+
.tr-table tr:last-child { border-bottom: 0; }
|
|
269
|
+
.tr-table td { padding: 0; border: 0; }
|
|
270
|
+
.tr-table .tr-thought { flex-basis: 100%; font-size: 15px; }
|
|
271
|
+
/* Dropped on a phone: the outcome prose, the longest cell in the row and the
|
|
272
|
+
only one the idea's own record — one tap away on the title — states in
|
|
273
|
+
full. Size and object stay, because they are the two facts this page exists
|
|
274
|
+
for and the two the record does not put side by side. */
|
|
275
|
+
.tr-table .tr-became { display: none; }
|
|
276
|
+
.tr-obj__sub { white-space: normal; }
|
|
277
|
+
}
|