privateboard 0.1.13 → 0.1.16
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/dist/cli.js +2623 -333
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/public/adjourn-overlay.css +6 -6
- package/public/agent-build-bgm.js +292 -0
- package/public/agent-overlay.css +14 -14
- package/public/agent-profile.css +408 -87
- package/public/agent-profile.js +254 -0
- package/public/app.js +2486 -384
- package/public/home.html +26 -26
- package/public/i18n.js +1890 -21
- package/public/icons/logo2.png +0 -0
- package/public/icons/private-board-vi.html +1716 -0
- package/public/index.html +2954 -1018
- package/public/magazine.html +12 -12
- package/public/new-agent.css +29 -29
- package/public/newspaper.html +20 -20
- package/public/onboarding.css +350 -272
- package/public/onboarding.js +614 -323
- package/public/quote-cta.css +4 -4
- package/public/report.html +2008 -1673
- package/public/room-settings.css +192 -24
- package/public/room-settings.js +5 -0
- package/public/share-cover-svg-creator.js +736 -0
- package/public/themes.css +0 -34
- package/public/typing-sfx.js +176 -3
- package/public/user-settings.css +50 -27
- package/public/user-settings.js +43 -14
- package/public/voice-onboarding.css +425 -0
- package/public/voice-onboarding.js +144 -0
- package/public/voice-replay.css +31 -38
- package/public/voice-replay.js +12 -11
package/package.json
CHANGED
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
}
|
|
79
79
|
.adjourn-head .meta {
|
|
80
80
|
font-family: var(--mono);
|
|
81
|
-
font-size:
|
|
81
|
+
font-size: 10px;
|
|
82
82
|
color: var(--text-dim, #5C5A52);
|
|
83
83
|
text-transform: uppercase;
|
|
84
84
|
letter-spacing: 0.12em;
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
}
|
|
160
160
|
.adjourn-summary-key {
|
|
161
161
|
font-family: var(--mono);
|
|
162
|
-
font-size:
|
|
162
|
+
font-size: 10px;
|
|
163
163
|
letter-spacing: 0.14em;
|
|
164
164
|
text-transform: uppercase;
|
|
165
165
|
color: var(--text-faint);
|
|
@@ -199,7 +199,7 @@
|
|
|
199
199
|
background: transparent;
|
|
200
200
|
border: none;
|
|
201
201
|
font-family: var(--mono);
|
|
202
|
-
font-size:
|
|
202
|
+
font-size: 10px;
|
|
203
203
|
letter-spacing: 0.14em;
|
|
204
204
|
text-transform: uppercase;
|
|
205
205
|
color: var(--text-soft);
|
|
@@ -231,7 +231,7 @@
|
|
|
231
231
|
}
|
|
232
232
|
.adjourn-mode-label {
|
|
233
233
|
font-family: var(--mono);
|
|
234
|
-
font-size:
|
|
234
|
+
font-size: 10px;
|
|
235
235
|
letter-spacing: 0.14em;
|
|
236
236
|
color: var(--text-faint);
|
|
237
237
|
margin-bottom: 8px;
|
|
@@ -395,7 +395,7 @@
|
|
|
395
395
|
align-items: center;
|
|
396
396
|
gap: 8px;
|
|
397
397
|
font-family: var(--mono);
|
|
398
|
-
font-size:
|
|
398
|
+
font-size: 10px;
|
|
399
399
|
font-weight: 700;
|
|
400
400
|
letter-spacing: 0.14em;
|
|
401
401
|
text-transform: uppercase;
|
|
@@ -421,7 +421,7 @@
|
|
|
421
421
|
.adjourn-cancel,
|
|
422
422
|
.adjourn-confirm {
|
|
423
423
|
font-family: var(--mono);
|
|
424
|
-
font-size:
|
|
424
|
+
font-size: 10px;
|
|
425
425
|
font-weight: 700;
|
|
426
426
|
letter-spacing: 0.14em;
|
|
427
427
|
text-transform: uppercase;
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/* ────────────────────────────────────────────────────────────────
|
|
2
|
+
agent-build-bgm.js · Sci-fi SCANNING palette played during
|
|
3
|
+
agent-creation flows (Signal-mode `_runAgentSpecGeneration` AND
|
|
4
|
+
Full-persona `personaJob` builds). Reads as "the system is
|
|
5
|
+
scanning the search space" — a slow radar/sonar sweep with deep
|
|
6
|
+
echoey tail. Earlier meditative drone gave users a headache
|
|
7
|
+
(gain LFO chopping + sustained pad layered too dense); this
|
|
8
|
+
version trades the drone for movement, with quieter overall
|
|
9
|
+
level and no rhythmic chopping.
|
|
10
|
+
|
|
11
|
+
Public surface · window.boardroomAgentBuildBgm:
|
|
12
|
+
· start() · idempotent · build audio graph + fade in
|
|
13
|
+
· stop() · idempotent · fade out + tear down
|
|
14
|
+
· isPlaying()· boolean state for diagnostics
|
|
15
|
+
|
|
16
|
+
Sound design (scanning palette):
|
|
17
|
+
· Sweep ping · sine carrier whose frequency rises from 400 Hz
|
|
18
|
+
to ~1200 Hz over each 2.5 s cycle then snaps
|
|
19
|
+
back · driven by a sawtooth LFO. Classic radar
|
|
20
|
+
sweep. The audible motion IS the audio.
|
|
21
|
+
· Sub presence · sine 80 Hz at low volume, constant · gives
|
|
22
|
+
the scanner a "machine is online" foundation
|
|
23
|
+
without adding a drone the ear fixates on.
|
|
24
|
+
· Counter sweep · a second sine that sweeps DOWN (1100 Hz →
|
|
25
|
+
350 Hz) in counter-phase with the main · the
|
|
26
|
+
two crossing pitches read as "two scanners
|
|
27
|
+
triangulating". Half the level of the main.
|
|
28
|
+
· Long delay · 0.55 s with 0.22 feedback, low-pass 2 kHz on
|
|
29
|
+
the feedback chain · the ping decays into
|
|
30
|
+
fainter echoes, creating spaciousness without
|
|
31
|
+
adding new tones.
|
|
32
|
+
· Master gain · peak 0.035 (slightly quieter than the previous
|
|
33
|
+
0.04 drone). The pitch motion is more salient
|
|
34
|
+
than steady drone gain, so the same loudness
|
|
35
|
+
would read as too loud.
|
|
36
|
+
· NO gain-LFO chopping. NO tremolo. NO shimmer layer. Those
|
|
37
|
+
three together produced the "headache" report on v1 ·
|
|
38
|
+
removed entirely here. Movement comes purely from the
|
|
39
|
+
pitch sweep + the delay tail.
|
|
40
|
+
|
|
41
|
+
Gating · the SAME global toggle as `typing-sfx.js`
|
|
42
|
+
(`boardroom.sfx.typing`, surfaced as "Sound effects" in User
|
|
43
|
+
Settings). When that's OFF, this BGM is silent regardless of
|
|
44
|
+
call frequency. The caller (`_syncAgentBuildBgm` in app.js)
|
|
45
|
+
decides WHEN to call start/stop based on composer state +
|
|
46
|
+
build status; this module just plays / doesn't play.
|
|
47
|
+
|
|
48
|
+
Gesture gate · same pattern as typing-sfx.js: AudioContext is
|
|
49
|
+
created lazily on the first `start()` call that follows a user
|
|
50
|
+
gesture. If `start()` is called pre-gesture, the start is
|
|
51
|
+
deferred via the gesture listener.
|
|
52
|
+
──────────────────────────────────────────────────────────────── */
|
|
53
|
+
|
|
54
|
+
(function () {
|
|
55
|
+
"use strict";
|
|
56
|
+
|
|
57
|
+
/* ─── State ─── */
|
|
58
|
+
let _ctx = null;
|
|
59
|
+
let _ctxFailed = false;
|
|
60
|
+
let _hadGesture = false;
|
|
61
|
+
let _pendingStart = false;
|
|
62
|
+
let _running = false;
|
|
63
|
+
/** Audio graph references kept alive while playing · cleared in
|
|
64
|
+
* stop() so the GC can reclaim the nodes. */
|
|
65
|
+
let _nodes = null;
|
|
66
|
+
|
|
67
|
+
function readGlobalSfxEnabled() {
|
|
68
|
+
try {
|
|
69
|
+
if (typeof window.boardroomTypingSfx?.isEnabled === "function") {
|
|
70
|
+
return window.boardroomTypingSfx.isEnabled();
|
|
71
|
+
}
|
|
72
|
+
} catch { /* fall through */ }
|
|
73
|
+
// If the typing-sfx module hasn't loaded yet, default to ON ·
|
|
74
|
+
// the caller already gated on a build being active, so this
|
|
75
|
+
// is a soft permissive default. Once typing-sfx is around the
|
|
76
|
+
// real toggle wins.
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function markGesture() {
|
|
81
|
+
_hadGesture = true;
|
|
82
|
+
if (_ctx && _ctx.state === "suspended") {
|
|
83
|
+
_ctx.resume().catch(() => { /* swallow */ });
|
|
84
|
+
}
|
|
85
|
+
if (_pendingStart && readGlobalSfxEnabled()) {
|
|
86
|
+
_pendingStart = false;
|
|
87
|
+
start();
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
["pointerdown", "keydown", "touchstart"].forEach((ev) => {
|
|
91
|
+
window.addEventListener(ev, markGesture, { passive: true, capture: true });
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
function ensureContext() {
|
|
95
|
+
if (_ctxFailed) return null;
|
|
96
|
+
if (_ctx) {
|
|
97
|
+
if (_ctx.state === "suspended") {
|
|
98
|
+
_ctx.resume().catch(() => { /* */ });
|
|
99
|
+
}
|
|
100
|
+
return _ctx;
|
|
101
|
+
}
|
|
102
|
+
if (!_hadGesture) return null;
|
|
103
|
+
try {
|
|
104
|
+
const Ctx = window.AudioContext || window.webkitAudioContext;
|
|
105
|
+
if (!Ctx) { _ctxFailed = true; return null; }
|
|
106
|
+
_ctx = new Ctx();
|
|
107
|
+
if (_ctx.state === "suspended") {
|
|
108
|
+
_ctx.resume().catch(() => { /* */ });
|
|
109
|
+
}
|
|
110
|
+
return _ctx;
|
|
111
|
+
} catch {
|
|
112
|
+
_ctxFailed = true;
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/* ─── Build the audio graph ─── */
|
|
118
|
+
function buildGraph(ctx) {
|
|
119
|
+
const t0 = ctx.currentTime;
|
|
120
|
+
|
|
121
|
+
/* Master gain · everything routes through here. Starts silent,
|
|
122
|
+
* ramped up by start(). */
|
|
123
|
+
const master = ctx.createGain();
|
|
124
|
+
master.gain.setValueAtTime(0.0001, t0);
|
|
125
|
+
master.connect(ctx.destination);
|
|
126
|
+
|
|
127
|
+
/* Long delay · feeds back its low-pass-filtered tail. The two
|
|
128
|
+
* sweeps below send into this directly so each cycle leaves a
|
|
129
|
+
* fainter echo decaying for a few seconds — classic radar / sonar
|
|
130
|
+
* "ping returning from far away" feel. */
|
|
131
|
+
const delay = ctx.createDelay(2.0);
|
|
132
|
+
delay.delayTime.value = 0.55;
|
|
133
|
+
const delayFb = ctx.createGain();
|
|
134
|
+
delayFb.gain.value = 0.22;
|
|
135
|
+
const delayFbFilter = ctx.createBiquadFilter();
|
|
136
|
+
delayFbFilter.type = "lowpass";
|
|
137
|
+
delayFbFilter.frequency.value = 2000;
|
|
138
|
+
delayFbFilter.Q.value = 0.5;
|
|
139
|
+
delay.connect(delayFbFilter).connect(delayFb).connect(delay);
|
|
140
|
+
delay.connect(master);
|
|
141
|
+
|
|
142
|
+
/* Sub presence · sine 80 Hz, constant low volume. Gives the
|
|
143
|
+
* scanner an "online" hum without becoming a drone the ear
|
|
144
|
+
* latches onto. Routed direct to master (no delay). */
|
|
145
|
+
const subOsc = ctx.createOscillator();
|
|
146
|
+
subOsc.type = "sine";
|
|
147
|
+
subOsc.frequency.value = 80;
|
|
148
|
+
const subGain = ctx.createGain();
|
|
149
|
+
subGain.gain.value = 0.06;
|
|
150
|
+
subOsc.connect(subGain).connect(master);
|
|
151
|
+
|
|
152
|
+
/* Main sweep · sine carrier swept upward by a sawtooth LFO.
|
|
153
|
+
* Base 400 Hz, peak ~1200 Hz, 2.5-second cycle (LFO at 0.4 Hz).
|
|
154
|
+
* Sawtooth gives a rising ramp that snaps back at the end of
|
|
155
|
+
* each cycle — the canonical radar pattern. */
|
|
156
|
+
const mainOsc = ctx.createOscillator();
|
|
157
|
+
mainOsc.type = "sine";
|
|
158
|
+
mainOsc.frequency.value = 400;
|
|
159
|
+
const mainGain = ctx.createGain();
|
|
160
|
+
mainGain.gain.value = 0.34;
|
|
161
|
+
|
|
162
|
+
const mainLfo = ctx.createOscillator();
|
|
163
|
+
mainLfo.type = "sawtooth";
|
|
164
|
+
mainLfo.frequency.value = 0.4;
|
|
165
|
+
const mainLfoGain = ctx.createGain();
|
|
166
|
+
mainLfoGain.gain.value = 400; // ±400 around 400 base
|
|
167
|
+
mainLfo.connect(mainLfoGain);
|
|
168
|
+
mainLfoGain.connect(mainOsc.frequency);
|
|
169
|
+
|
|
170
|
+
/* Counter sweep · second sine that sweeps DOWN in counter-phase.
|
|
171
|
+
* Base 1100 Hz, troughs around 350 Hz, half the level of the
|
|
172
|
+
* main so the two crossing pitches feel like two scanners
|
|
173
|
+
* triangulating rather than a single noisy ramp. Uses an
|
|
174
|
+
* INVERTED sawtooth LFO (negative gain) so it ramps downward
|
|
175
|
+
* while the main ramps upward. */
|
|
176
|
+
const counterOsc = ctx.createOscillator();
|
|
177
|
+
counterOsc.type = "sine";
|
|
178
|
+
counterOsc.frequency.value = 1100;
|
|
179
|
+
const counterGain = ctx.createGain();
|
|
180
|
+
counterGain.gain.value = 0.17;
|
|
181
|
+
|
|
182
|
+
const counterLfo = ctx.createOscillator();
|
|
183
|
+
counterLfo.type = "sawtooth";
|
|
184
|
+
counterLfo.frequency.value = 0.4;
|
|
185
|
+
const counterLfoGain = ctx.createGain();
|
|
186
|
+
counterLfoGain.gain.value = -375; // negative · sweep DOWN
|
|
187
|
+
counterLfo.connect(counterLfoGain);
|
|
188
|
+
counterLfoGain.connect(counterOsc.frequency);
|
|
189
|
+
|
|
190
|
+
/* Both sweeps go direct to master AND into the delay. The
|
|
191
|
+
* direct path keeps the ping crisp; the delay path adds the
|
|
192
|
+
* spacious decay trail without smearing the present audio. */
|
|
193
|
+
mainOsc.connect(mainGain);
|
|
194
|
+
counterOsc.connect(counterGain);
|
|
195
|
+
mainGain.connect(master);
|
|
196
|
+
counterGain.connect(master);
|
|
197
|
+
mainGain.connect(delay);
|
|
198
|
+
counterGain.connect(delay);
|
|
199
|
+
|
|
200
|
+
/* Start everything · they run forever until stop() takes them
|
|
201
|
+
* down. LFOs start out-of-phase by 1 ms so the two oscillators
|
|
202
|
+
* don't lock to perfectly mirrored peaks. */
|
|
203
|
+
subOsc.start(t0);
|
|
204
|
+
mainOsc.start(t0);
|
|
205
|
+
counterOsc.start(t0);
|
|
206
|
+
mainLfo.start(t0);
|
|
207
|
+
counterLfo.start(t0 + 0.001);
|
|
208
|
+
|
|
209
|
+
return {
|
|
210
|
+
master,
|
|
211
|
+
delay, delayFb, delayFbFilter,
|
|
212
|
+
subOsc, subGain,
|
|
213
|
+
mainOsc, mainGain, mainLfo, mainLfoGain,
|
|
214
|
+
counterOsc, counterGain, counterLfo, counterLfoGain,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function teardownGraph(nodes, ctx) {
|
|
219
|
+
if (!nodes) return;
|
|
220
|
+
const oscs = [nodes.subOsc, nodes.mainOsc, nodes.counterOsc, nodes.mainLfo, nodes.counterLfo];
|
|
221
|
+
for (const o of oscs) {
|
|
222
|
+
try { o.stop(); } catch { /* already stopped */ }
|
|
223
|
+
}
|
|
224
|
+
// Disconnect every node we kept a reference to · loose
|
|
225
|
+
// try/catch so a single failure doesn't strand others.
|
|
226
|
+
for (const key of Object.keys(nodes)) {
|
|
227
|
+
try { nodes[key]?.disconnect(); } catch { /* */ }
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/* ─── Public API ─── */
|
|
232
|
+
function start() {
|
|
233
|
+
if (_running) return;
|
|
234
|
+
if (!readGlobalSfxEnabled()) return;
|
|
235
|
+
const ctx = ensureContext();
|
|
236
|
+
if (!ctx) {
|
|
237
|
+
// No gesture yet · queue a deferred start. The gesture
|
|
238
|
+
// listener (above) will retry when a real interaction lands.
|
|
239
|
+
_pendingStart = true;
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
try {
|
|
243
|
+
_nodes = buildGraph(ctx);
|
|
244
|
+
// Ramp master gain in over 1 s. Exponential ramps need a
|
|
245
|
+
// non-zero starting value; setValueAtTime(0.0001) at t0
|
|
246
|
+
// happened in buildGraph already. 0.035 is slightly quieter
|
|
247
|
+
// than the previous drone's 0.04 · pitch motion is more
|
|
248
|
+
// salient than steady drone, so the same loudness reads as
|
|
249
|
+
// too loud in this palette.
|
|
250
|
+
const t = ctx.currentTime;
|
|
251
|
+
const targetGain = 0.035;
|
|
252
|
+
_nodes.master.gain.exponentialRampToValueAtTime(targetGain, t + 1.0);
|
|
253
|
+
_running = true;
|
|
254
|
+
} catch (e) {
|
|
255
|
+
// Audio graph creation rarely fails, but if it does we tear
|
|
256
|
+
// down anything that partially succeeded and stay silent.
|
|
257
|
+
try { teardownGraph(_nodes, ctx); } catch { /* */ }
|
|
258
|
+
_nodes = null;
|
|
259
|
+
_running = false;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function stop() {
|
|
264
|
+
_pendingStart = false;
|
|
265
|
+
if (!_running || !_ctx || !_nodes) {
|
|
266
|
+
// Even if not playing, defensively kill any deferred start so
|
|
267
|
+
// a later gesture doesn't resurrect a build the caller already
|
|
268
|
+
// declared finished.
|
|
269
|
+
_pendingStart = false;
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const ctx = _ctx;
|
|
273
|
+
const stale = _nodes;
|
|
274
|
+
_nodes = null;
|
|
275
|
+
_running = false;
|
|
276
|
+
try {
|
|
277
|
+
const t = ctx.currentTime;
|
|
278
|
+
stale.master.gain.cancelScheduledValues(t);
|
|
279
|
+
stale.master.gain.setValueAtTime(stale.master.gain.value, t);
|
|
280
|
+
stale.master.gain.exponentialRampToValueAtTime(0.0001, t + 0.8);
|
|
281
|
+
} catch { /* ignore · setTimeout still tears down */ }
|
|
282
|
+
setTimeout(() => {
|
|
283
|
+
teardownGraph(stale, ctx);
|
|
284
|
+
}, 1000);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function isPlaying() {
|
|
288
|
+
return _running;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
window.boardroomAgentBuildBgm = { start, stop, isPlaying };
|
|
292
|
+
})();
|
package/public/agent-overlay.css
CHANGED
|
@@ -118,14 +118,14 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
118
118
|
letter-spacing: -0.01em;
|
|
119
119
|
}
|
|
120
120
|
.agent-card-id .role {
|
|
121
|
-
font-size:
|
|
121
|
+
font-size: 10px;
|
|
122
122
|
color: var(--lime, #6FB572);
|
|
123
123
|
text-transform: uppercase;
|
|
124
124
|
letter-spacing: 0.16em;
|
|
125
125
|
font-weight: 700;
|
|
126
126
|
}
|
|
127
127
|
.agent-card-id .handle {
|
|
128
|
-
font-size:
|
|
128
|
+
font-size: 10px;
|
|
129
129
|
color: var(--text-faint, #3A382F);
|
|
130
130
|
margin-top: 5px;
|
|
131
131
|
letter-spacing: 0.04em;
|
|
@@ -151,7 +151,7 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
151
151
|
|
|
152
152
|
.agent-block { margin-bottom: 16px; }
|
|
153
153
|
.agent-block-label {
|
|
154
|
-
font-size:
|
|
154
|
+
font-size: 10px;
|
|
155
155
|
font-weight: 700;
|
|
156
156
|
text-transform: uppercase;
|
|
157
157
|
letter-spacing: 0.16em;
|
|
@@ -170,7 +170,7 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
170
170
|
}
|
|
171
171
|
.agent-block-label .badge {
|
|
172
172
|
margin-left: auto;
|
|
173
|
-
font-size:
|
|
173
|
+
font-size: 8px;
|
|
174
174
|
letter-spacing: 0.12em;
|
|
175
175
|
color: var(--text-faint, #3A382F);
|
|
176
176
|
font-weight: 600;
|
|
@@ -194,7 +194,7 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
194
194
|
flex-wrap: wrap;
|
|
195
195
|
gap: 8px;
|
|
196
196
|
font-family: var(--mono);
|
|
197
|
-
font-size:
|
|
197
|
+
font-size: 12px;
|
|
198
198
|
color: var(--text, #C8C5BE);
|
|
199
199
|
letter-spacing: 0.02em;
|
|
200
200
|
}
|
|
@@ -202,7 +202,7 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
202
202
|
font-weight: 700;
|
|
203
203
|
}
|
|
204
204
|
.agent-model-provider {
|
|
205
|
-
font-size:
|
|
205
|
+
font-size: 10px;
|
|
206
206
|
letter-spacing: 0.16em;
|
|
207
207
|
text-transform: uppercase;
|
|
208
208
|
color: var(--text-soft, #8E8B83);
|
|
@@ -219,7 +219,7 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
219
219
|
.agent-trait {
|
|
220
220
|
border: 0.5px solid var(--line-bright, #2A2A26);
|
|
221
221
|
padding: 3px 8px;
|
|
222
|
-
font-size:
|
|
222
|
+
font-size: 10px;
|
|
223
223
|
font-family: var(--mono);
|
|
224
224
|
text-transform: uppercase;
|
|
225
225
|
letter-spacing: 0.1em;
|
|
@@ -266,14 +266,14 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
266
266
|
.agent-note-entry:last-child { border-bottom: none; }
|
|
267
267
|
.agent-note-time {
|
|
268
268
|
font-family: var(--mono);
|
|
269
|
-
font-size:
|
|
269
|
+
font-size: 10px;
|
|
270
270
|
color: var(--text-faint, #3A382F);
|
|
271
271
|
letter-spacing: 0.04em;
|
|
272
272
|
padding-top: 3px;
|
|
273
273
|
}
|
|
274
274
|
.agent-note-body {
|
|
275
275
|
font-family: var(--sans);
|
|
276
|
-
font-size:
|
|
276
|
+
font-size: 12px;
|
|
277
277
|
line-height: 1.5;
|
|
278
278
|
color: var(--text-soft, #8E8B83);
|
|
279
279
|
letter-spacing: -0.003em;
|
|
@@ -281,7 +281,7 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
281
281
|
.agent-note-tag {
|
|
282
282
|
display: inline-block;
|
|
283
283
|
font-family: var(--mono);
|
|
284
|
-
font-size:
|
|
284
|
+
font-size: 8px;
|
|
285
285
|
font-weight: 700;
|
|
286
286
|
letter-spacing: 0.1em;
|
|
287
287
|
text-transform: uppercase;
|
|
@@ -321,7 +321,7 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
321
321
|
}
|
|
322
322
|
.agent-memory-empty .lock-text {
|
|
323
323
|
font-family: var(--sans);
|
|
324
|
-
font-size:
|
|
324
|
+
font-size: 12px;
|
|
325
325
|
line-height: 1.5;
|
|
326
326
|
color: var(--text-soft, #8E8B83);
|
|
327
327
|
letter-spacing: -0.003em;
|
|
@@ -349,7 +349,7 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
349
349
|
line-height: 1;
|
|
350
350
|
}
|
|
351
351
|
.agent-stat .l {
|
|
352
|
-
font-size:
|
|
352
|
+
font-size: 8px;
|
|
353
353
|
text-transform: uppercase;
|
|
354
354
|
letter-spacing: 0.14em;
|
|
355
355
|
color: var(--text-faint, #3A382F);
|
|
@@ -366,7 +366,7 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
366
366
|
}
|
|
367
367
|
.agent-card-foot .meta {
|
|
368
368
|
font-family: var(--mono);
|
|
369
|
-
font-size:
|
|
369
|
+
font-size: 10px;
|
|
370
370
|
color: var(--text-faint, #3A382F);
|
|
371
371
|
text-transform: uppercase;
|
|
372
372
|
letter-spacing: 0.12em;
|
|
@@ -425,7 +425,7 @@ img[data-agent]:hover { filter: brightness(1.15); }
|
|
|
425
425
|
font-family: var(--mono);
|
|
426
426
|
text-transform: uppercase;
|
|
427
427
|
letter-spacing: 0.08em;
|
|
428
|
-
font-size:
|
|
428
|
+
font-size: 10px;
|
|
429
429
|
margin-right: 4px;
|
|
430
430
|
}
|
|
431
431
|
.agent-locked .lock-link:hover { text-decoration: underline; }
|