@bongos/core 1.19.484 → 1.19.486
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 +102 -52
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +6 -0
- package/clients/bongos-client/index.cjs +6 -0
- package/clients/bongos-client/index.d.ts +7 -0
- package/clients/bongos-client/index.mjs +6 -0
- package/docs/adr/0232-rot-is-derived-not-swept-and-water-is-the-only-new-verb.md +155 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +147 -3
- package/docs/api-reference.md +7 -4
- package/docs/copy-inventory.md +169 -178
- package/docs/copy-registry.json +295 -405
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +4 -0
- package/migrations/core_231_project_settings_and_attention_water.sql +163 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +6 -0
- package/modules/hall-ui/public/goal-inbox.js +119 -1
- package/modules/hall-ui/public/not-ready.html +14 -10
- package/modules/hall-ui/public/not-ready.states.json +14 -0
- package/modules/hall-ui/public/pair.css +17 -67
- package/modules/hall-ui/public/pair.html +8 -1
- package/modules/hall-ui/public/pair.states.json +14 -0
- package/modules/hall-ui/public/panel.css +333 -0
- package/modules/hall-ui/public/profile.css +85 -0
- package/modules/hall-ui/public/profile.html +12 -5
- package/modules/hall-ui/public/profile.states.json +15 -0
- package/modules/hall-ui/public/settings.css +119 -336
- package/modules/hall-ui/public/settings.html +28 -19
- package/modules/hall-ui/public/settings.js +44 -35
- package/modules/hall-ui/public/settings.states.json +16 -0
- package/modules/hall-ui/public/style.css +5 -2
- package/modules/lifecycle/module.json +2 -1
- package/modules/lifecycle/rot.js +210 -0
- package/modules/lifecycle/routes/rot.js +160 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/fitness-checks-vocabulary.js +0 -1
- package/scripts/gds/fitness.js +9 -0
- package/src/bongos/project-settings.js +193 -0
- package/src/module-api.js +29 -1
- package/tests/hall_settings_world.mjs +274 -0
- package/tests/join_application_note.mjs +7 -15
- package/tests/module-scope-map.mjs +1 -1
- package/tests/module_api.mjs +1 -0
- package/tests/rot_inbox.mjs +532 -0
- package/modules/hall-ui/public/my-projects.css +0 -62
- package/modules/hall-ui/public/my-projects.html +0 -73
- package/modules/hall-ui/public/my-projects.js +0 -153
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
/* panel.css — the PANEL archetype: a titled panel that holds a form, read top
|
|
2
|
+
to bottom (task 1003308, goal 1000081). Shared by settings, profile, pair,
|
|
3
|
+
and not-ready — the pages where the builder reads a label, a
|
|
4
|
+
sentence of consequence, and then acts on ONE control.
|
|
5
|
+
|
|
6
|
+
THE ARCHETYPE is v3 "the glass hall", the owner's pick from the composition
|
|
7
|
+
round — docs/design/hall-direction-v2.md §6, mock
|
|
8
|
+
docs/design/mocks/hall/settings/v3.html. Reading order inside a panel: the
|
|
9
|
+
panel's name, one lede of purpose, then ROWS — each a label, a description in
|
|
10
|
+
the soft ink, and the control on the right — or a FIELD, its label above it
|
|
11
|
+
in the label voice, the input and its button on one line, the status line
|
|
12
|
+
under it, and a note in the faint ink at the foot saying when the change
|
|
13
|
+
applies. The panel is the shell's `.scroll`; v3 has exactly three card levels
|
|
14
|
+
and a fourth would be a design decision, not a local override.
|
|
15
|
+
|
|
16
|
+
WHAT IS SHARED and what is not: the row, the switch, the field, the chip
|
|
17
|
+
control, the status/hint/note voices and the sign-in gate are the family's.
|
|
18
|
+
The section rail and the token ladder are settings' (settings.css); the
|
|
19
|
+
identity band and the shelf are the profile's (profile.css); the device card
|
|
20
|
+
is pair's (pair.css).
|
|
21
|
+
|
|
22
|
+
THE NAMES the page scripts already write (`.sound-row`, `.sessions-row`,
|
|
23
|
+
`.settings-btn`, `.craft-chip` …) are aliased onto the family's rules here
|
|
24
|
+
rather than renamed in three JS files: a class name is not what was wrong
|
|
25
|
+
with these pages — the six divergent hand-rolled rows were.
|
|
26
|
+
|
|
27
|
+
Everything below spends the world's real token names. No compat alias
|
|
28
|
+
(--surface / --surface-2 / --border / --border-strong / --accent-weak /
|
|
29
|
+
--accent-text) appears here — they exist for pages nobody has re-skinned, so
|
|
30
|
+
spending one is legal CSS that quietly opts this sheet back out of the world.
|
|
31
|
+
`--line` is a WIDTH; the hairline's colour is --rule / --rule-soft. */
|
|
32
|
+
|
|
33
|
+
/* ---- the page head ------------------------------------------------------ */
|
|
34
|
+
/* The family takes the reading room's VOICE — the page's own name, lowercase in
|
|
35
|
+
the display face — because on a settings page the document IS the page: the
|
|
36
|
+
builder came to read their own record and change one line of it. The room's
|
|
37
|
+
top air is a reading room's; a form page starts at the content edge. */
|
|
38
|
+
.page-head--room.page-head--panel { padding-top: 0; }
|
|
39
|
+
.page-head--room.page-head--panel .page-head__sub { margin-top: var(--sp-sm); }
|
|
40
|
+
|
|
41
|
+
/* ---- the panel's voices ------------------------------------------------- */
|
|
42
|
+
.panel-lede,
|
|
43
|
+
.scroll > .panel-lede { margin: 0 0 var(--sp-sm); max-width: var(--measure); font-size: 14.5px; color: var(--ink-soft); }
|
|
44
|
+
.panel-note,
|
|
45
|
+
.section-note { margin: var(--sp-sm) 0 0; max-width: var(--measure); font-size: 13px; color: var(--ink-faint); }
|
|
46
|
+
.panel-note:empty, .section-note:empty { display: none; }
|
|
47
|
+
.panel-hint,
|
|
48
|
+
.settings-card__hint { font-size: 13px; color: var(--ink-faint); }
|
|
49
|
+
.panel-status,
|
|
50
|
+
.settings-status,
|
|
51
|
+
.pair-status { margin: var(--sp-xs) 0 0; min-height: 1.2em; font-size: 13.5px; color: var(--ink-soft); }
|
|
52
|
+
.panel-status--ok, .settings-card__ok, .pair-status--ok { color: var(--ok); }
|
|
53
|
+
.panel-status--danger, .pair-status--err { color: var(--danger); }
|
|
54
|
+
.panel-status:empty, .settings-status:empty { margin-top: 0; min-height: 0; }
|
|
55
|
+
/* a prose link in any of the four voices is a control and owes the 24px floor */
|
|
56
|
+
.panel-lede a, .panel-note a, .panel-hint a, .panel-status a, .settings-card__hint a, .section-note a {
|
|
57
|
+
display: inline-block;
|
|
58
|
+
min-width: 24px;
|
|
59
|
+
min-height: 24px;
|
|
60
|
+
padding: 3px 4px;
|
|
61
|
+
margin: 0 -4px;
|
|
62
|
+
color: var(--accent-ink);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* ---- the row: label, description, control ------------------------------ */
|
|
66
|
+
.prows,
|
|
67
|
+
.sound-rows, .event-sound-rows, .sessions-list, #cross-project-rows, #privacy-rows { display: flex; flex-direction: column; margin-top: var(--sp-sm); }
|
|
68
|
+
.prow,
|
|
69
|
+
.sound-row, .event-sound-row, .sessions-row {
|
|
70
|
+
display: flex;
|
|
71
|
+
align-items: center;
|
|
72
|
+
gap: var(--sp-sm);
|
|
73
|
+
padding: var(--sp-sm) 0;
|
|
74
|
+
border-top: var(--line) solid var(--rule-soft);
|
|
75
|
+
}
|
|
76
|
+
.prow__main,
|
|
77
|
+
.sound-row__text, .event-sound-row__text, .sessions-row__main { flex: 1 1 auto; min-width: 0; }
|
|
78
|
+
.prow__label,
|
|
79
|
+
.sound-row__label, .event-sound-row__label, .sessions-row__main > strong { display: block; margin: 0; font-size: 14.5px; font-weight: 500; color: var(--ink); }
|
|
80
|
+
.prow__desc,
|
|
81
|
+
.sound-row__desc, .event-sound-row__desc, .sessions-row__agent, .sessions-row__when { display: block; margin: 2px 0 0; font-size: 13.5px; color: var(--ink-soft); }
|
|
82
|
+
.prow__ctl,
|
|
83
|
+
.event-sound-row__controls { display: flex; align-items: center; justify-content: flex-end; flex: none; flex-wrap: wrap; gap: var(--sp-hair); }
|
|
84
|
+
/* the default note on a row label — "· default for your rank" — is a fact, so it
|
|
85
|
+
takes the label voice beside the label rather than the label's own weight */
|
|
86
|
+
.prow__tag,
|
|
87
|
+
.voices__default { margin-left: 8px; font-family: var(--label-face); font-size: 10.5px; font-weight: 400; letter-spacing: var(--label-space); text-transform: var(--label-case); color: var(--ink-faint); }
|
|
88
|
+
/* a pick row: the whole row is the radio's label */
|
|
89
|
+
.prow--pick { cursor: pointer; }
|
|
90
|
+
.prow--pick .prow__main { display: block; }
|
|
91
|
+
.prow--pick .prow__label, .prow--pick .prow__desc { display: block; }
|
|
92
|
+
.prow--pick[aria-disabled="true"] { cursor: default; }
|
|
93
|
+
.prow--pick[aria-disabled="true"] .prow__label { color: var(--ink-soft); }
|
|
94
|
+
|
|
95
|
+
/* the action row at a panel's foot: buttons and their status on one line */
|
|
96
|
+
.row-end,
|
|
97
|
+
.settings-card, .craft-actions, .artkey-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-xs); margin-top: var(--sp-sm); }
|
|
98
|
+
.row-end .panel-status, .row-end .settings-status,
|
|
99
|
+
.craft-actions .settings-status { margin: 0; }
|
|
100
|
+
|
|
101
|
+
/* ---- the controls: every one clears 24px on both axes ------------------- */
|
|
102
|
+
/* the family button: a glass pill, 38px, quiet by default. `--save` is the
|
|
103
|
+
accent door — the panel's one primary act — and takes --accent-on, the dark
|
|
104
|
+
ink for the salmon; white on it fails AA and DESIGN.md bans it. */
|
|
105
|
+
.pbtn,
|
|
106
|
+
.settings-btn, .sessions-row__end, .event-sound-preview, .pair-approve {
|
|
107
|
+
display: inline-flex;
|
|
108
|
+
align-items: center;
|
|
109
|
+
justify-content: center;
|
|
110
|
+
gap: 8px;
|
|
111
|
+
min-height: 38px;
|
|
112
|
+
min-width: 38px;
|
|
113
|
+
padding: 0 15px;
|
|
114
|
+
border: var(--line) solid var(--glass-edge);
|
|
115
|
+
border-radius: var(--radius-pill);
|
|
116
|
+
background: var(--glass);
|
|
117
|
+
color: var(--ink);
|
|
118
|
+
font: inherit;
|
|
119
|
+
font-size: 14px;
|
|
120
|
+
line-height: 1.2;
|
|
121
|
+
white-space: nowrap;
|
|
122
|
+
text-decoration: none;
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
transition: background 200ms cubic-bezier(.2,.7,.3,1), border-color 200ms cubic-bezier(.2,.7,.3,1), color 200ms cubic-bezier(.2,.7,.3,1);
|
|
125
|
+
}
|
|
126
|
+
.pbtn:hover:not(:disabled), .settings-btn:hover:not(:disabled), .sessions-row__end:hover:not(:disabled),
|
|
127
|
+
.event-sound-preview:hover:not(:disabled), .pair-approve:hover:not(:disabled) { background: var(--glass-strong); color: var(--ink); text-decoration: none; }
|
|
128
|
+
.pbtn:disabled, .settings-btn:disabled, .sessions-row__end:disabled, .pair-approve:disabled,
|
|
129
|
+
.pbtn[aria-disabled="true"], .settings-btn[aria-disabled="true"] { color: var(--ink-faint); background: var(--glass); cursor: default; }
|
|
130
|
+
.pbtn--quiet, .settings-btn--quiet, .sessions-row__end, .event-sound-preview { background: transparent; }
|
|
131
|
+
.pbtn--save,
|
|
132
|
+
.craft-save, .pair-approve { background: var(--accent); border-color: var(--accent); color: var(--accent-on); font-weight: 500; }
|
|
133
|
+
.pbtn--save:hover:not(:disabled), .craft-save:hover:not(:disabled), .pair-approve:hover:not(:disabled) { background: var(--accent-lift); border-color: var(--accent-lift); color: var(--accent-on); }
|
|
134
|
+
.craft-save:disabled, .pbtn--save:disabled, .pair-approve:disabled { background: var(--glass); border-color: var(--glass-edge); color: var(--ink-faint); }
|
|
135
|
+
/* the shell's `.craft-save` was a bordered box; it is the family's save button
|
|
136
|
+
now, so it carries the pill's own box model too */
|
|
137
|
+
button.craft-save { display: inline-flex; align-items: center; justify-content: center; min-height: 38px; min-width: 38px; padding: 0 15px; border-radius: var(--radius-pill); font: inherit; font-size: 14px; cursor: pointer; }
|
|
138
|
+
|
|
139
|
+
/* the field: label above, input and its button on one line */
|
|
140
|
+
.field-label,
|
|
141
|
+
.join-note-label {
|
|
142
|
+
display: block;
|
|
143
|
+
margin: var(--sp-sm) 0 var(--sp-hair);
|
|
144
|
+
font-family: var(--label-face);
|
|
145
|
+
font-size: var(--label-size);
|
|
146
|
+
letter-spacing: var(--label-space);
|
|
147
|
+
text-transform: var(--label-case);
|
|
148
|
+
color: var(--ink-faint);
|
|
149
|
+
}
|
|
150
|
+
.field,
|
|
151
|
+
.display-name-row, .artkey-entry-row, .join { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-xs); margin-top: 0; }
|
|
152
|
+
.field .field-label { flex: 1 1 100%; margin-top: 0; }
|
|
153
|
+
.pinput,
|
|
154
|
+
.display-name-input, .artkey-input, .join input, .join-note {
|
|
155
|
+
flex: 1 1 260px;
|
|
156
|
+
max-width: 420px;
|
|
157
|
+
min-height: 38px;
|
|
158
|
+
padding: 0 16px;
|
|
159
|
+
font: inherit;
|
|
160
|
+
font-size: 15px;
|
|
161
|
+
color: var(--ink);
|
|
162
|
+
background: var(--glass);
|
|
163
|
+
border: var(--line) solid var(--glass-edge);
|
|
164
|
+
border-radius: var(--radius-pill);
|
|
165
|
+
transition: border-color 200ms cubic-bezier(.2,.7,.3,1);
|
|
166
|
+
}
|
|
167
|
+
.pinput::placeholder, .display-name-input::placeholder, .artkey-input::placeholder, .join input::placeholder, .join-note::placeholder { color: var(--ink-faint); }
|
|
168
|
+
.pinput:hover, .display-name-input:hover, .artkey-input:hover, .join input:hover, .join-note:hover { border-color: var(--rule); }
|
|
169
|
+
.pinput[aria-invalid="true"], .display-name-input[aria-invalid="true"] { border-color: var(--danger); }
|
|
170
|
+
/* a secret is typed in the mono face so a pasted key reads as what it is */
|
|
171
|
+
.artkey-input { font-family: var(--font-mono); font-size: 13.5px; }
|
|
172
|
+
.psel,
|
|
173
|
+
.event-sound-select, .voices__select { min-height: 38px; padding: 0 var(--sp-xs); font: inherit; font-size: 14px; color: var(--ink); background: var(--glass); border: var(--line) solid var(--glass-edge); border-radius: var(--radius-pill); cursor: pointer; }
|
|
174
|
+
.psel:hover, .event-sound-select:hover, .voices__select:hover { border-color: var(--rule); }
|
|
175
|
+
.prange,
|
|
176
|
+
.sound-volume input[type="range"] { flex: 1 1 200px; max-width: 260px; height: 38px; margin: 0; accent-color: var(--accent); cursor: pointer; }
|
|
177
|
+
.pradio { width: 24px; height: 24px; flex: none; margin: 0; accent-color: var(--accent); cursor: pointer; }
|
|
178
|
+
.pradio:disabled { cursor: default; opacity: .55; }
|
|
179
|
+
|
|
180
|
+
/* the switch: a 46x38 button whose drawn track is 44x24 — the target clears
|
|
181
|
+
the floor, the drawing stays the world's small shape. State is aria-checked;
|
|
182
|
+
the page scripts still read data-on, which they wrote. */
|
|
183
|
+
.sw,
|
|
184
|
+
.sound-toggle {
|
|
185
|
+
position: relative;
|
|
186
|
+
display: inline-flex;
|
|
187
|
+
align-items: center;
|
|
188
|
+
width: 46px;
|
|
189
|
+
min-width: 46px;
|
|
190
|
+
height: 38px;
|
|
191
|
+
flex: none;
|
|
192
|
+
padding: 0;
|
|
193
|
+
margin: 0;
|
|
194
|
+
border: 0;
|
|
195
|
+
background: none;
|
|
196
|
+
font-size: 0;
|
|
197
|
+
color: transparent;
|
|
198
|
+
cursor: pointer;
|
|
199
|
+
}
|
|
200
|
+
.sw__track {
|
|
201
|
+
width: 44px;
|
|
202
|
+
height: 24px;
|
|
203
|
+
border-radius: var(--radius-pill);
|
|
204
|
+
background: var(--glass-strong);
|
|
205
|
+
border: 1px solid var(--rule);
|
|
206
|
+
transition: background 240ms cubic-bezier(.2,.7,.3,1), border-color 240ms cubic-bezier(.2,.7,.3,1);
|
|
207
|
+
}
|
|
208
|
+
.sw__knob {
|
|
209
|
+
position: absolute;
|
|
210
|
+
left: 5px;
|
|
211
|
+
width: 16px;
|
|
212
|
+
height: 16px;
|
|
213
|
+
border-radius: var(--radius-pill);
|
|
214
|
+
background: var(--ink-faint);
|
|
215
|
+
transition: transform 260ms cubic-bezier(.2,.7,.3,1), background 240ms cubic-bezier(.2,.7,.3,1);
|
|
216
|
+
}
|
|
217
|
+
.sw[aria-checked="true"] .sw__track, .sound-toggle[aria-checked="true"] .sw__track { background: var(--accent-tint); border-color: var(--accent); }
|
|
218
|
+
.sw[aria-checked="true"] .sw__knob, .sound-toggle[aria-checked="true"] .sw__knob { transform: translateX(20px); background: var(--accent); }
|
|
219
|
+
.sw:disabled, .sound-toggle:disabled { cursor: default; opacity: .55; }
|
|
220
|
+
@media (prefers-reduced-motion: reduce) {
|
|
221
|
+
.sw__track, .sw__knob, .pbtn, .settings-btn, .pinput { transition: none; }
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/* the chip control: a checkbox in a pill. The box is a 24px target drawing a
|
|
225
|
+
14px square — the 13x13 native box was the smallest control in the hall. */
|
|
226
|
+
.chips,
|
|
227
|
+
.craft-chips { display: flex; flex-wrap: wrap; gap: var(--sp-hair); margin-top: var(--sp-sm); }
|
|
228
|
+
.chip-ctl,
|
|
229
|
+
.craft-chip {
|
|
230
|
+
display: inline-flex;
|
|
231
|
+
align-items: center;
|
|
232
|
+
gap: 6px;
|
|
233
|
+
min-height: 38px;
|
|
234
|
+
padding: 0 14px 0 8px;
|
|
235
|
+
border: var(--line) solid var(--glass-edge);
|
|
236
|
+
border-radius: var(--radius-pill);
|
|
237
|
+
background: var(--glass);
|
|
238
|
+
color: var(--ink-soft);
|
|
239
|
+
font-size: 14px;
|
|
240
|
+
text-transform: lowercase;
|
|
241
|
+
cursor: pointer;
|
|
242
|
+
user-select: none;
|
|
243
|
+
}
|
|
244
|
+
.chip-ctl:has(input:checked), .craft-chip[data-on="1"] { color: var(--ink); border-color: var(--rule); }
|
|
245
|
+
.chip-ctl input, .craft-pref {
|
|
246
|
+
appearance: none;
|
|
247
|
+
-webkit-appearance: none;
|
|
248
|
+
position: relative;
|
|
249
|
+
width: 24px;
|
|
250
|
+
height: 24px;
|
|
251
|
+
margin: 0;
|
|
252
|
+
flex: none;
|
|
253
|
+
cursor: pointer;
|
|
254
|
+
}
|
|
255
|
+
.chip-ctl input::before, .craft-pref::before {
|
|
256
|
+
content: "";
|
|
257
|
+
position: absolute;
|
|
258
|
+
inset: 5px;
|
|
259
|
+
width: 14px;
|
|
260
|
+
height: 14px;
|
|
261
|
+
border: var(--line) solid var(--ink-faint);
|
|
262
|
+
border-radius: 4px;
|
|
263
|
+
background: transparent;
|
|
264
|
+
}
|
|
265
|
+
.chip-ctl input:checked::before, .craft-pref:checked::before { background: var(--accent); border-color: var(--accent); }
|
|
266
|
+
.chip-ctl input:checked::after, .craft-pref:checked::after {
|
|
267
|
+
content: "";
|
|
268
|
+
position: absolute;
|
|
269
|
+
left: 9px;
|
|
270
|
+
top: 6px;
|
|
271
|
+
width: 4px;
|
|
272
|
+
height: 8px;
|
|
273
|
+
border: solid var(--accent-on);
|
|
274
|
+
border-width: 0 2px 2px 0;
|
|
275
|
+
transform: rotate(45deg);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/* ---- the status pill on a row --------------------------------------------- */
|
|
279
|
+
/* the fixed status vocabulary in the label voice — the shell's .fact-pill; the
|
|
280
|
+
sessions badge is the same pill under the name settings-sessions.js writes */
|
|
281
|
+
.sessions-row__badge {
|
|
282
|
+
display: inline-flex;
|
|
283
|
+
align-items: center;
|
|
284
|
+
min-height: 24px;
|
|
285
|
+
padding: 0 11px;
|
|
286
|
+
margin-left: 8px;
|
|
287
|
+
border: var(--line) solid currentColor;
|
|
288
|
+
border-radius: var(--radius-pill);
|
|
289
|
+
font-family: var(--label-face);
|
|
290
|
+
font-size: 10.5px;
|
|
291
|
+
font-weight: 400;
|
|
292
|
+
letter-spacing: var(--label-space);
|
|
293
|
+
text-transform: var(--label-case);
|
|
294
|
+
color: var(--info);
|
|
295
|
+
white-space: nowrap;
|
|
296
|
+
vertical-align: middle;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/* ---- the banner: one line of consequence, warn or ok ---------------------- */
|
|
300
|
+
.pbanner {
|
|
301
|
+
margin: 0 0 var(--sp-sm);
|
|
302
|
+
padding: var(--sp-xs) var(--sp-sm);
|
|
303
|
+
font-size: 14px;
|
|
304
|
+
line-height: 1.45;
|
|
305
|
+
color: var(--ink);
|
|
306
|
+
background: var(--warn-weak);
|
|
307
|
+
border-left: 2px solid var(--warn);
|
|
308
|
+
border-radius: var(--radius-sm);
|
|
309
|
+
}
|
|
310
|
+
.pbanner--ok { background: var(--ok-weak); border-left-color: var(--ok); }
|
|
311
|
+
.pbanner strong { font-weight: 500; }
|
|
312
|
+
|
|
313
|
+
/* ---- the sign-in gate ----------------------------------------------------- */
|
|
314
|
+
/* Shown INSTEAD of the page when there is nobody to show it to. It is a panel
|
|
315
|
+
with the display voice, the honest sentence, and the one door. */
|
|
316
|
+
.gate { border-top: var(--line) solid var(--glass-edge); }
|
|
317
|
+
.gate__h { margin: 0; font-family: var(--font-display); font-weight: 300; font-size: clamp(22px, 2.1vw, 29px); line-height: 1.15; letter-spacing: -.03em; color: var(--ink); }
|
|
318
|
+
.gate__lede { margin: var(--sp-xs) 0 var(--sp-sm); max-width: var(--measure); font-size: 15px; color: var(--ink-soft); }
|
|
319
|
+
.gate .row-end { margin-top: 0; }
|
|
320
|
+
|
|
321
|
+
/* ---- the skeleton --------------------------------------------------------- */
|
|
322
|
+
/* --skeleton, never --bg-deep: that one collapses to pure black in dark */
|
|
323
|
+
.pskel { display: block; background: var(--skeleton); border-radius: var(--radius-sm); }
|
|
324
|
+
.pskel--row { height: 52px; margin-top: var(--sp-hair); }
|
|
325
|
+
.pskel--h { height: 26px; width: min(240px, 60%); }
|
|
326
|
+
|
|
327
|
+
/* ---- responsive ----------------------------------------------------------- */
|
|
328
|
+
@media (max-width: 520px) {
|
|
329
|
+
.prow, .sound-row, .event-sound-row, .sessions-row { flex-direction: column; align-items: flex-start; gap: var(--sp-xs); }
|
|
330
|
+
.prow__ctl, .event-sound-row__controls { justify-content: flex-start; }
|
|
331
|
+
.prow--pick { flex-direction: row; align-items: flex-start; }
|
|
332
|
+
.pinput, .display-name-input, .artkey-input, .join input, .join-note { max-width: none; }
|
|
333
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/* profile.css — what the builder's profile page has and the rest of the panel
|
|
2
|
+
family does not (task 1003308, goal 1000081; the archetype is panel.css). The
|
|
3
|
+
page everyone else reads: the identity band, the figures, the shelf, the
|
|
4
|
+
ledgers. The figures are the shell's glass band (.stat-row) and the ledgers
|
|
5
|
+
the shell's .ledger; this sheet owns the identity band and the shelf, both
|
|
6
|
+
drawn from docs/design/mocks/hall/settings/v3.html (the profile half).
|
|
7
|
+
|
|
8
|
+
The shell's .profile grid is shared with Home's Standing card, so the band
|
|
9
|
+
here is a MODIFIER (.profile--ident) rather than a second rule for the base
|
|
10
|
+
name; the shelf's .ach is scoped by this sheet loading on this page only. */
|
|
11
|
+
|
|
12
|
+
/* ---- the identity band ---------------------------------------------------- */
|
|
13
|
+
.profile--ident {
|
|
14
|
+
grid-template-columns: 56px minmax(0, 1fr) auto;
|
|
15
|
+
gap: var(--sp-sm);
|
|
16
|
+
align-items: center;
|
|
17
|
+
}
|
|
18
|
+
.profile--ident .profile__avatar {
|
|
19
|
+
width: 56px;
|
|
20
|
+
height: 56px;
|
|
21
|
+
border-radius: var(--radius-pill);
|
|
22
|
+
background: var(--skeleton);
|
|
23
|
+
border: 1px solid var(--rule);
|
|
24
|
+
}
|
|
25
|
+
.profile--ident .profile__name {
|
|
26
|
+
font-family: var(--font-display);
|
|
27
|
+
font-weight: 300;
|
|
28
|
+
font-size: clamp(22px, 2vw, 28px);
|
|
29
|
+
letter-spacing: -.03em;
|
|
30
|
+
line-height: 1.1;
|
|
31
|
+
}
|
|
32
|
+
.profile--ident .profile__handle { margin: 4px 0 0; font-family: var(--font-mono); font-size: 12.5px; color: var(--ink-faint); }
|
|
33
|
+
.profile--ident .profile__stats { margin-top: 4px; font-size: 13px; }
|
|
34
|
+
.profile--ident .profile__disciplines { margin-top: 4px; font-size: 13px; }
|
|
35
|
+
.profile--ident .profile__credits-num { font-family: var(--font-display); font-weight: 300; font-size: clamp(26px, 2.4vw, 32px); letter-spacing: -.035em; line-height: 1; color: var(--ink); }
|
|
36
|
+
.profile--ident .profile__credits-label,
|
|
37
|
+
.profile--ident .profile__karma-label { font-family: var(--label-face); font-size: var(--label-size); font-weight: 400; letter-spacing: var(--label-space); text-transform: var(--label-case); color: var(--ink-faint); }
|
|
38
|
+
.profile--ident .profile__karma-num { font-weight: 500; }
|
|
39
|
+
.profile--ident .profile__placeholder { grid-column: 1 / -1; }
|
|
40
|
+
|
|
41
|
+
/* ---- the shelf -------------------------------------------------------------
|
|
42
|
+
An achievement is a --bg-card tile on the ground (the section is bare, so a
|
|
43
|
+
tile is the panel and not a card in a card), a hairline on top, the mark as
|
|
44
|
+
its figure, the name at the row's weight and the day it was won in the soft
|
|
45
|
+
ink at the foot. */
|
|
46
|
+
.ach-grid { grid-template-columns: repeat(auto-fill, minmax(215px, 1fr)); gap: var(--sp-sm); }
|
|
47
|
+
.ach {
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
gap: 5px;
|
|
50
|
+
padding: 18px;
|
|
51
|
+
background: var(--bg-card);
|
|
52
|
+
border: var(--line) solid var(--glass-edge);
|
|
53
|
+
border-top-color: var(--rule);
|
|
54
|
+
border-radius: var(--radius);
|
|
55
|
+
}
|
|
56
|
+
.ach__icon { font-size: 22px; line-height: 1; margin-bottom: 4px; }
|
|
57
|
+
.ach__name { font-size: 14.5px; font-weight: 500; margin: 0; }
|
|
58
|
+
.ach__desc { font-size: 13px; line-height: 1.4; color: var(--ink-soft); }
|
|
59
|
+
.ach__bonus { margin: auto 0 0; padding-top: var(--sp-hair); font-size: 12.5px; font-weight: 400; color: var(--ink-soft); }
|
|
60
|
+
.ach--locked { border-top-color: var(--rule-soft); }
|
|
61
|
+
.ach--locked .ach__name, .ach--locked .ach__desc { color: var(--ink-faint); }
|
|
62
|
+
|
|
63
|
+
/* ---- the ledgers ---------------------------------------------------------- */
|
|
64
|
+
/* A title in a ledger cell is a door and owes the 24px floor on both axes; it
|
|
65
|
+
measured 18px tall on every populated render (thirteen links a page). The
|
|
66
|
+
prose-link recipe: inline-block buys the height, the padding buys the width,
|
|
67
|
+
the negative margin hands both back so the cell does not re-space. */
|
|
68
|
+
#works-scroll .ledger td a,
|
|
69
|
+
#activity-scroll .ledger td a,
|
|
70
|
+
#xp-scroll a {
|
|
71
|
+
display: inline-block;
|
|
72
|
+
min-width: 24px;
|
|
73
|
+
min-height: 24px;
|
|
74
|
+
padding: 3px 4px;
|
|
75
|
+
margin: -3px -4px;
|
|
76
|
+
color: var(--accent-ink);
|
|
77
|
+
}
|
|
78
|
+
.profile-act__h { margin: var(--sp-md) 0 var(--sp-xs); font-size: 15px; font-weight: 500; color: var(--ink); }
|
|
79
|
+
#activity-body > [id$="-panel"] + [id$="-panel"] { margin-top: var(--sp-md); }
|
|
80
|
+
|
|
81
|
+
@media (max-width: 640px) {
|
|
82
|
+
.profile--ident { grid-template-columns: 48px minmax(0, 1fr); }
|
|
83
|
+
.profile--ident .profile__avatar { width: 48px; height: 48px; }
|
|
84
|
+
.profile--ident .profile__credits { grid-column: 2; align-items: flex-start; text-align: left; }
|
|
85
|
+
}
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
15
15
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
16
16
|
<link rel="stylesheet" href="/builders/style.css?v=2026-07-02-shell1">
|
|
17
|
+
<!-- The PANEL archetype (task 1003308) before the page's own sheet. -->
|
|
18
|
+
<link rel="stylesheet" href="/builders/panel.css">
|
|
19
|
+
<link rel="stylesheet" href="/builders/profile.css">
|
|
17
20
|
</head>
|
|
18
21
|
<body data-page="profile" data-page-title="Profile">
|
|
19
22
|
|
|
@@ -23,7 +26,11 @@
|
|
|
23
26
|
<div class="app-body">
|
|
24
27
|
<header class="app-topbar" id="app-topbar"></header>
|
|
25
28
|
<div class="app-content">
|
|
26
|
-
|
|
29
|
+
<!-- The page's ONE h1 (one-header-main-h1), in the family's voice; the
|
|
30
|
+
sub-line is profile.js's — "<name> — <rank> · N works shipped". -->
|
|
31
|
+
<div class="page-head page-head--room page-head--panel">
|
|
32
|
+
<p class="page-head__eyebrow">the page everyone else reads</p>
|
|
33
|
+
<h1 id="profile-h1" class="page-head__h">profile</h1>
|
|
27
34
|
<p class="page-head__sub" id="profile-sub">Loading profile…</p>
|
|
28
35
|
</div>
|
|
29
36
|
|
|
@@ -31,7 +38,7 @@
|
|
|
31
38
|
<!-- Standing — avatar, name, rank badge, member-since. Filled by profile.js. -->
|
|
32
39
|
<section class="scroll" id="standing-scroll" aria-labelledby="standing-h">
|
|
33
40
|
<h2 id="standing-h" class="sr-only">Standing</h2>
|
|
34
|
-
<div class="profile" id="profile-head">
|
|
41
|
+
<div class="profile profile--ident" id="profile-head">
|
|
35
42
|
<div class="profile__placeholder">…</div>
|
|
36
43
|
</div>
|
|
37
44
|
</section>
|
|
@@ -92,19 +99,19 @@
|
|
|
92
99
|
<div class="profile__placeholder" id="activity-placeholder">…</div>
|
|
93
100
|
|
|
94
101
|
<div id="activity-tasks-panel" hidden>
|
|
95
|
-
<h3 class="
|
|
102
|
+
<h3 class="profile-act__h">Works completed</h3>
|
|
96
103
|
<div id="activity-tasks"></div>
|
|
97
104
|
</div>
|
|
98
105
|
|
|
99
106
|
<div id="activity-goals-panel" hidden>
|
|
100
|
-
<h3 class="
|
|
107
|
+
<h3 class="profile-act__h">Goals created</h3>
|
|
101
108
|
<div id="activity-goals"></div>
|
|
102
109
|
</div>
|
|
103
110
|
|
|
104
111
|
<!-- The idea trail. Revealed only in the craft views where filing an
|
|
105
112
|
idea is the work being shown (all + ideator) — see profile.js. -->
|
|
106
113
|
<div id="activity-ideas-panel" hidden>
|
|
107
|
-
<h3 class="
|
|
114
|
+
<h3 class="profile-act__h">Ideas filed, and what became of them</h3>
|
|
108
115
|
<p class="scroll__lede">Every idea this builder captured — promoted, discarded, merged, or still open.</p>
|
|
109
116
|
<div id="activity-ideas"></div>
|
|
110
117
|
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_": "The hall's PROFILE page through modules/ui-design/kit/render.js (task 1003308). The identity band, the shelf and the three activity ledgers only exist once a profile has LOADED, so the floors run against the hall-preview harness (see settings.states.json for the two commands; pass --base-in/--base-out at it). `out` is a real state here rather than a redirect: a signed-out visitor with no ?id= gets the empty state, not a bounce — under the harness's --fixture-me the /me read still answers, so `out` renders the own profile there and the empty state only under the kit's own stub.",
|
|
3
|
+
"page": "/profile",
|
|
4
|
+
"surface": "hall-ui",
|
|
5
|
+
"stub": { "prefix": "/builders/" },
|
|
6
|
+
"modeQuery": false,
|
|
7
|
+
"ignoreRequests": ["/api/(gds|bongos)/"],
|
|
8
|
+
"ignoreConsole": ["/api/(gds|bongos)/", "\b401\b", "\b404\b", "Unauthorized", "Not Found", "load failed"],
|
|
9
|
+
"states": {
|
|
10
|
+
"own": { "auth": true, "actions": [["wait", 900]], "expect": { "visible": ["#profile-h1", "#profile-head", "#numbers-body", "#works-table", "#activity-tabs"] } },
|
|
11
|
+
"other": { "auth": true, "url": "/profile?id=1000025", "actions": [["wait", 900]], "expect": { "visible": ["#profile-head", "#ach-grid"] } },
|
|
12
|
+
"out": { "auth": false, "actions": [["wait", 600]], "expect": { "visible": ["#profile-h1", "#profile-head"] } }
|
|
13
|
+
},
|
|
14
|
+
"reducedMotion": { "auth": true, "actions": [["wait", 900]] }
|
|
15
|
+
}
|