privateboard 0.1.5 → 0.1.7
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 +12 -2
- package/dist/cli.js.map +1 -1
- package/package.json +4 -2
- package/public/agent-profile.js +14 -0
- package/public/app.js +465 -704
- package/public/home.html +3 -3
- package/public/index.html +193 -151
- package/public/report.html +356 -59
- package/public/typing-sfx.js +158 -0
- package/public/user-settings.css +90 -0
- package/public/user-settings.js +71 -0
package/public/home.html
CHANGED
|
@@ -1304,12 +1304,12 @@
|
|
|
1304
1304
|
<span class="ok">▸</span> requires <span class="hl">node 18+</span> · opens at <span class="hl">http://localhost:3030</span>
|
|
1305
1305
|
</div>
|
|
1306
1306
|
<div class="install-line ghost">
|
|
1307
|
-
<span class="dim"># or
|
|
1307
|
+
<span class="dim"># or install globally</span>
|
|
1308
1308
|
</div>
|
|
1309
1309
|
<div class="install-line">
|
|
1310
1310
|
<span class="prompt">$</span>
|
|
1311
|
-
<span class="cmd"><span class="bin">
|
|
1312
|
-
<button type="button" class="copy-btn" data-copy="
|
|
1311
|
+
<span class="cmd"><span class="bin">npm</span> install -g privateboard</span>
|
|
1312
|
+
<button type="button" class="copy-btn" data-copy="npm install -g privateboard" aria-label="Copy command">copy</button>
|
|
1313
1313
|
</div>
|
|
1314
1314
|
</div>
|
|
1315
1315
|
</div>
|
package/public/index.html
CHANGED
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
|
|
56
56
|
/* Logo stays on Inter so the brandmark reads consistently
|
|
57
57
|
across pages, regardless of the chat-page font swap. */
|
|
58
|
-
.brand-name,
|
|
58
|
+
.sidebar-brand-name,
|
|
59
59
|
.brand-mark {
|
|
60
60
|
font-family: "Inter", -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
|
|
61
61
|
}
|
|
@@ -131,78 +131,33 @@
|
|
|
131
131
|
}
|
|
132
132
|
.sys-notice-close:hover { color: var(--lime, #6FB572); }
|
|
133
133
|
|
|
134
|
-
/* ─────────── ROOT ───────────
|
|
134
|
+
/* ─────────── ROOT ───────────
|
|
135
|
+
Single-row grid · the previous decorative top "classification
|
|
136
|
+
banner" (PRIVATEBOARD wordmark + SYNC / UID / ROOM placeholder
|
|
137
|
+
metadata) was retired. The brand mark moved into the sidebar's
|
|
138
|
+
header, and the placeholder fields were never real data. Sidebar
|
|
139
|
+
and room now get the full viewport height. */
|
|
135
140
|
.control {
|
|
136
141
|
display: grid;
|
|
137
|
-
grid-template-rows:
|
|
142
|
+
grid-template-rows: 1fr;
|
|
138
143
|
flex: 1 1 auto;
|
|
139
144
|
min-height: 0;
|
|
140
|
-
gap: 8px;
|
|
141
145
|
padding: 8px;
|
|
142
146
|
}
|
|
143
147
|
|
|
144
|
-
/*
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
padding: 8px 14px;
|
|
151
|
-
display: flex;
|
|
152
|
-
justify-content: space-between;
|
|
153
|
-
align-items: center;
|
|
154
|
-
gap: 20px;
|
|
155
|
-
position: relative;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
.brand-block {
|
|
159
|
-
display: flex;
|
|
160
|
-
align-items: center;
|
|
161
|
-
gap: 10px;
|
|
162
|
-
}
|
|
148
|
+
/* ─── Brand mark · 16-pixel "PrivateBoard" logo ───
|
|
149
|
+
The single remaining piece of the retired topbar — kept because
|
|
150
|
+
the sidebar's header re-uses it as the lock-up logo (replacing
|
|
151
|
+
the prior "// CONTROL" text title). The fill swap (lime bg / bg
|
|
152
|
+
fg) produces the inverse-tile look when rendered against the
|
|
153
|
+
sidebar's panel-2 surface. */
|
|
163
154
|
.brand-mark {
|
|
164
|
-
width:
|
|
155
|
+
width: 16px; height: 16px;
|
|
165
156
|
display: block;
|
|
166
157
|
flex-shrink: 0;
|
|
167
158
|
}
|
|
168
159
|
.brand-mark .bg { fill: var(--lime); }
|
|
169
160
|
.brand-mark .fg { fill: var(--bg); }
|
|
170
|
-
.brand-name {
|
|
171
|
-
font-size: 11px;
|
|
172
|
-
font-weight: 700;
|
|
173
|
-
color: var(--text);
|
|
174
|
-
letter-spacing: 0.1em;
|
|
175
|
-
}
|
|
176
|
-
.brand-sep {
|
|
177
|
-
color: var(--text-dim);
|
|
178
|
-
margin: 0 4px;
|
|
179
|
-
}
|
|
180
|
-
.classification {
|
|
181
|
-
color: var(--lime);
|
|
182
|
-
background: var(--panel-3);
|
|
183
|
-
border: 0.5px solid var(--lime-dim);
|
|
184
|
-
padding: 1px 7px;
|
|
185
|
-
font-size: 9px;
|
|
186
|
-
letter-spacing: 0.14em;
|
|
187
|
-
margin-left: 6px;
|
|
188
|
-
font-weight: 700;
|
|
189
|
-
}
|
|
190
|
-
.classification::before { content: "["; margin-right: 3px; }
|
|
191
|
-
.classification::after { content: "]"; margin-left: 3px; }
|
|
192
|
-
|
|
193
|
-
.topbar-right {
|
|
194
|
-
display: flex;
|
|
195
|
-
gap: 18px;
|
|
196
|
-
align-items: center;
|
|
197
|
-
color: var(--text-dim);
|
|
198
|
-
font-size: 9.5px;
|
|
199
|
-
letter-spacing: 0.06em;
|
|
200
|
-
text-transform: uppercase;
|
|
201
|
-
}
|
|
202
|
-
/* Topbar key label · bumped from text-faint (~2:1) to text-soft
|
|
203
|
-
(~6:1) so the key reads cleanly against the topbar bg. */
|
|
204
|
-
.topbar-right .key { color: var(--text-soft); margin-right: 4px; }
|
|
205
|
-
.topbar-right .val { color: var(--text-soft); }
|
|
206
161
|
@keyframes pulse { 0%, 60% { opacity: 1; } 80% { opacity: 0.4; } }
|
|
207
162
|
|
|
208
163
|
/* ═══════════════════════════════════════════
|
|
@@ -214,10 +169,10 @@
|
|
|
214
169
|
gap: 0;
|
|
215
170
|
overflow: hidden;
|
|
216
171
|
min-height: 0;
|
|
217
|
-
/* `position: relative` so the floating sidebar-expand-btn
|
|
218
|
-
positioned) anchors to the body-grid's top-left
|
|
219
|
-
|
|
220
|
-
|
|
172
|
+
/* `position: relative` so the floating sidebar-expand-btn
|
|
173
|
+
(absolute-positioned) anchors to the body-grid's top-left
|
|
174
|
+
edge — which, after the topbar's retirement, is the viewport's
|
|
175
|
+
top-left under the 8px page padding. */
|
|
221
176
|
position: relative;
|
|
222
177
|
}
|
|
223
178
|
|
|
@@ -280,27 +235,37 @@
|
|
|
280
235
|
}
|
|
281
236
|
|
|
282
237
|
.sidebar-head {
|
|
283
|
-
padding:
|
|
238
|
+
padding: 8px 12px;
|
|
284
239
|
border-bottom: 0.5px solid var(--line-bright);
|
|
285
240
|
display: flex;
|
|
286
241
|
justify-content: space-between;
|
|
287
242
|
align-items: center;
|
|
243
|
+
gap: 10px;
|
|
288
244
|
background: var(--panel-2);
|
|
289
245
|
}
|
|
290
|
-
|
|
291
|
-
|
|
246
|
+
/* Lock-up · brand mark + wordmark in the slot the prior
|
|
247
|
+
"// CONTROL" title held. Anchored as a link so a click on the
|
|
248
|
+
logo returns to the boardroom root (`/`) — same affordance the
|
|
249
|
+
pre-retired topbar offered. */
|
|
250
|
+
.sidebar-brand {
|
|
251
|
+
display: inline-flex;
|
|
252
|
+
align-items: center;
|
|
253
|
+
gap: 8px;
|
|
254
|
+
text-decoration: none;
|
|
255
|
+
color: inherit;
|
|
256
|
+
min-width: 0;
|
|
257
|
+
}
|
|
258
|
+
.sidebar-brand-name {
|
|
259
|
+
font-size: 11px;
|
|
292
260
|
color: var(--text);
|
|
293
|
-
letter-spacing: 0.
|
|
261
|
+
letter-spacing: 0.12em;
|
|
294
262
|
text-transform: uppercase;
|
|
295
263
|
font-weight: 700;
|
|
264
|
+
white-space: nowrap;
|
|
265
|
+
overflow: hidden;
|
|
266
|
+
text-overflow: ellipsis;
|
|
296
267
|
}
|
|
297
|
-
.sidebar-
|
|
298
|
-
font-size: 9px;
|
|
299
|
-
color: var(--text-dim);
|
|
300
|
-
letter-spacing: 0.06em;
|
|
301
|
-
}
|
|
302
|
-
.sidebar-head-meta .lime { color: var(--lime); }
|
|
303
|
-
|
|
268
|
+
.sidebar-brand:hover .sidebar-brand-name { color: var(--lime); }
|
|
304
269
|
/* ─── Sidebar collapse toggle ───
|
|
305
270
|
Sits at the right edge of sidebar-head. Pure CSS glyph (no svg)
|
|
306
271
|
so we can flip the direction via class without re-rendering DOM.
|
|
@@ -1178,7 +1143,13 @@
|
|
|
1178
1143
|
|
|
1179
1144
|
.sidebar-foot {
|
|
1180
1145
|
border-top: 0.5px solid var(--line-bright);
|
|
1181
|
-
padding:
|
|
1146
|
+
padding: 0 10px;
|
|
1147
|
+
/* Pinned to the same min-height as the room's `.adjourned-bar`
|
|
1148
|
+
(the "Convene Follow-up" rail at the bottom of an adjourned
|
|
1149
|
+
room) so the two footers sit on a single visual baseline
|
|
1150
|
+
regardless of which view is showing. */
|
|
1151
|
+
min-height: 44px;
|
|
1152
|
+
box-sizing: border-box;
|
|
1182
1153
|
display: flex;
|
|
1183
1154
|
align-items: center;
|
|
1184
1155
|
gap: 8px;
|
|
@@ -1447,7 +1418,14 @@
|
|
|
1447
1418
|
.notes-filter-chip.on .notes-filter-count { color: var(--text-dim); }
|
|
1448
1419
|
|
|
1449
1420
|
/* ─── Reading list ─────────────────────────────────────────────── */
|
|
1450
|
-
|
|
1421
|
+
/* Divider hair under the filter chips · group headers were dropped
|
|
1422
|
+
in favour of a single rule + flat list (chips already disclose
|
|
1423
|
+
recency, no need for repeated section headers). */
|
|
1424
|
+
.reports-list-wrap {
|
|
1425
|
+
margin-top: 14px;
|
|
1426
|
+
padding-top: 14px;
|
|
1427
|
+
border-top: 1px solid var(--border);
|
|
1428
|
+
}
|
|
1451
1429
|
|
|
1452
1430
|
/* Load-more sentinel · sits at the bottom of the list when more
|
|
1453
1431
|
items are available beyond the current page (default 20). The
|
|
@@ -1485,21 +1463,6 @@
|
|
|
1485
1463
|
line-height: 1;
|
|
1486
1464
|
}
|
|
1487
1465
|
|
|
1488
|
-
/* Date-bucket label · sits flush left, hairline rule fills the
|
|
1489
|
-
remaining width. Reads as a quiet section break. */
|
|
1490
|
-
.reports-group + .reports-group { margin-top: 32px; }
|
|
1491
|
-
.reports-group-label {
|
|
1492
|
-
font-family: var(--mono);
|
|
1493
|
-
font-size: 10px;
|
|
1494
|
-
font-weight: 700;
|
|
1495
|
-
letter-spacing: 0.22em;
|
|
1496
|
-
text-transform: uppercase;
|
|
1497
|
-
color: var(--text-faint);
|
|
1498
|
-
padding-bottom: 8px;
|
|
1499
|
-
border-bottom: 0.5px solid var(--line);
|
|
1500
|
-
margin-bottom: 4px;
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
1466
|
.reports-list {
|
|
1504
1467
|
list-style: none;
|
|
1505
1468
|
margin: 0;
|
|
@@ -1783,36 +1746,53 @@
|
|
|
1783
1746
|
color: var(--text-dim);
|
|
1784
1747
|
}
|
|
1785
1748
|
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
.notes-
|
|
1791
|
-
|
|
1792
|
-
align-items: baseline;
|
|
1793
|
-
justify-content: space-between;
|
|
1794
|
-
padding-bottom: 8px;
|
|
1749
|
+
.notes-list { list-style: none; margin: 0; padding: 0; }
|
|
1750
|
+
/* `position: relative` so the absolutely-positioned delete button
|
|
1751
|
+
(top-right of each note row) anchors to its own item. Hover-only
|
|
1752
|
+
reveal — the row stays clean during normal scanning. */
|
|
1753
|
+
.notes-item {
|
|
1754
|
+
position: relative;
|
|
1795
1755
|
border-bottom: 0.5px solid var(--line);
|
|
1796
|
-
margin-bottom: 4px;
|
|
1797
1756
|
}
|
|
1798
|
-
.notes-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1757
|
+
.notes-item:last-child { border-bottom: none; }
|
|
1758
|
+
.notes-item-delete {
|
|
1759
|
+
position: absolute;
|
|
1760
|
+
top: 16px;
|
|
1761
|
+
right: 6px;
|
|
1762
|
+
width: 22px;
|
|
1763
|
+
height: 22px;
|
|
1764
|
+
background: var(--panel-2);
|
|
1765
|
+
border: 0.5px solid var(--line-bright);
|
|
1804
1766
|
color: var(--text-faint);
|
|
1805
|
-
}
|
|
1806
|
-
.notes-group-count {
|
|
1807
1767
|
font-family: var(--mono);
|
|
1808
|
-
font-size:
|
|
1809
|
-
|
|
1810
|
-
|
|
1768
|
+
font-size: 11px;
|
|
1769
|
+
line-height: 1;
|
|
1770
|
+
cursor: pointer;
|
|
1771
|
+
display: none;
|
|
1772
|
+
align-items: center;
|
|
1773
|
+
justify-content: center;
|
|
1774
|
+
padding: 0;
|
|
1775
|
+
transition: color 0.12s, border-color 0.12s, background 0.12s;
|
|
1776
|
+
z-index: 2;
|
|
1811
1777
|
}
|
|
1812
|
-
|
|
1813
|
-
.notes-
|
|
1814
|
-
|
|
1815
|
-
|
|
1778
|
+
.notes-item:hover .notes-item-delete { display: flex; }
|
|
1779
|
+
.notes-item-delete:hover {
|
|
1780
|
+
color: var(--red);
|
|
1781
|
+
border-color: var(--red);
|
|
1782
|
+
background: var(--bg);
|
|
1783
|
+
}
|
|
1784
|
+
/* Reserve the right-edge gutter ALWAYS (not only on hover) so the
|
|
1785
|
+
passage text doesn't reflow when the delete button appears. An
|
|
1786
|
+
earlier version applied `padding-right: 30px` only on hover —
|
|
1787
|
+
the text visibly jumped each time the user mousemoved across
|
|
1788
|
+
rows. Cost: a fixed 30px of empty space at the right edge of
|
|
1789
|
+
every passage; cheap compared to the jitter. */
|
|
1790
|
+
.notes-item-passage { padding-right: 30px; }
|
|
1791
|
+
/* On hover · hide the trailing time tag so the delete button
|
|
1792
|
+
occupies the right-edge slot cleanly. visibility:hidden keeps
|
|
1793
|
+
the layout box (the meta row doesn't reflow either). Same
|
|
1794
|
+
pattern as `.session-row-shell:hover .row-time` in rooms. */
|
|
1795
|
+
.notes-item:hover .notes-item-time { visibility: hidden; }
|
|
1816
1796
|
.notes-item-link {
|
|
1817
1797
|
display: block;
|
|
1818
1798
|
padding: 18px 4px;
|
|
@@ -2018,6 +1998,63 @@
|
|
|
2018
1998
|
color: var(--text);
|
|
2019
1999
|
background: var(--panel-3);
|
|
2020
2000
|
}
|
|
2001
|
+
/* Cold empty state · 3-step capture workflow rendered as an
|
|
2002
|
+
ordered list. Each step has a circled number on the left + a
|
|
2003
|
+
bilingual instruction on the right (zh + en together because
|
|
2004
|
+
a note may be saved from either language room). The steps are
|
|
2005
|
+
the load-bearing pedagogy of this view — without them, new
|
|
2006
|
+
users hit "All Notes" and have no idea how to get the first
|
|
2007
|
+
note in. */
|
|
2008
|
+
.notes-empty-steps {
|
|
2009
|
+
list-style: none;
|
|
2010
|
+
margin: 6px 0 4px;
|
|
2011
|
+
padding: 0;
|
|
2012
|
+
display: flex;
|
|
2013
|
+
flex-direction: column;
|
|
2014
|
+
gap: 12px;
|
|
2015
|
+
max-width: 560px;
|
|
2016
|
+
}
|
|
2017
|
+
.notes-empty-steps li {
|
|
2018
|
+
display: grid;
|
|
2019
|
+
grid-template-columns: 22px 1fr;
|
|
2020
|
+
gap: 12px;
|
|
2021
|
+
align-items: start;
|
|
2022
|
+
}
|
|
2023
|
+
.notes-empty-step-num {
|
|
2024
|
+
width: 22px;
|
|
2025
|
+
height: 22px;
|
|
2026
|
+
border-radius: 50%;
|
|
2027
|
+
border: 0.5px solid var(--line-bright);
|
|
2028
|
+
background: var(--panel-3);
|
|
2029
|
+
color: var(--lime);
|
|
2030
|
+
font-family: var(--mono);
|
|
2031
|
+
font-size: 10.5px;
|
|
2032
|
+
font-weight: 700;
|
|
2033
|
+
display: inline-flex;
|
|
2034
|
+
align-items: center;
|
|
2035
|
+
justify-content: center;
|
|
2036
|
+
line-height: 1;
|
|
2037
|
+
}
|
|
2038
|
+
.notes-empty-step-text {
|
|
2039
|
+
font-family: var(--font-human);
|
|
2040
|
+
font-size: 12.5px;
|
|
2041
|
+
line-height: 1.55;
|
|
2042
|
+
color: var(--text-dim);
|
|
2043
|
+
}
|
|
2044
|
+
.notes-empty-step-text strong {
|
|
2045
|
+
color: var(--text);
|
|
2046
|
+
font-weight: 600;
|
|
2047
|
+
}
|
|
2048
|
+
.notes-empty-foot {
|
|
2049
|
+
margin-top: 8px;
|
|
2050
|
+
padding-top: 10px;
|
|
2051
|
+
border-top: 0.5px dashed var(--line-bright);
|
|
2052
|
+
font-family: var(--mono);
|
|
2053
|
+
font-size: 10.5px;
|
|
2054
|
+
line-height: 1.6;
|
|
2055
|
+
color: var(--text-faint);
|
|
2056
|
+
max-width: 560px;
|
|
2057
|
+
}
|
|
2021
2058
|
/* Window-empty CTA · "← Show all notes" button shown when a
|
|
2022
2059
|
non-All filter has zero matches. Same visual register as
|
|
2023
2060
|
`.reports-list-empty-cta`. */
|
|
@@ -2049,9 +2086,14 @@
|
|
|
2049
2086
|
font-size: 11px;
|
|
2050
2087
|
line-height: 1;
|
|
2051
2088
|
}
|
|
2052
|
-
/* Wrap around the
|
|
2053
|
-
|
|
2054
|
-
|
|
2089
|
+
/* Wrap around the flat list · matches the reports list wrap so
|
|
2090
|
+
the chip strip → divider → list rhythm reads identically. Group
|
|
2091
|
+
headers were dropped in favour of a single hair under the chips. */
|
|
2092
|
+
.notes-list-wrap {
|
|
2093
|
+
margin-top: 14px;
|
|
2094
|
+
padding-top: 14px;
|
|
2095
|
+
border-top: 1px solid var(--border);
|
|
2096
|
+
}
|
|
2055
2097
|
|
|
2056
2098
|
/* Loading skeleton · matches `.reports-skeleton` rhythm and
|
|
2057
2099
|
reuses its pulse keyframe. */
|
|
@@ -2463,10 +2505,15 @@
|
|
|
2463
2505
|
50% { opacity: 1; }
|
|
2464
2506
|
}
|
|
2465
2507
|
|
|
2466
|
-
/* Paused footer bar (sits where input-bar would be)
|
|
2508
|
+
/* Paused footer bar (sits where input-bar would be) — shares the
|
|
2509
|
+
`.adjourned-bar` height so the bottom edge of the room view stays
|
|
2510
|
+
on the same baseline as the sidebar's user footer regardless of
|
|
2511
|
+
which state (paused vs adjourned) is showing. */
|
|
2467
2512
|
.paused-bar {
|
|
2468
2513
|
border-top: 0.5px solid var(--line-bright);
|
|
2469
|
-
padding:
|
|
2514
|
+
padding: 0 14px;
|
|
2515
|
+
min-height: 44px;
|
|
2516
|
+
box-sizing: border-box;
|
|
2470
2517
|
background: var(--panel-2);
|
|
2471
2518
|
display: flex;
|
|
2472
2519
|
align-items: center;
|
|
@@ -2594,7 +2641,11 @@
|
|
|
2594
2641
|
|
|
2595
2642
|
.adjourned-bar {
|
|
2596
2643
|
border-top: 0.5px solid var(--line-bright);
|
|
2597
|
-
padding:
|
|
2644
|
+
padding: 0 14px;
|
|
2645
|
+
/* Same min-height as `.sidebar-foot` so the bottom edges of the
|
|
2646
|
+
sidebar footer and this room footer sit on a single baseline. */
|
|
2647
|
+
min-height: 44px;
|
|
2648
|
+
box-sizing: border-box;
|
|
2598
2649
|
background: var(--panel-2);
|
|
2599
2650
|
display: flex;
|
|
2600
2651
|
align-items: center;
|
|
@@ -9082,6 +9133,7 @@
|
|
|
9082
9133
|
<script src="onboarding.js" defer></script>
|
|
9083
9134
|
<link rel="stylesheet" href="quote-cta.css">
|
|
9084
9135
|
<script src="quote-cta.js" defer></script>
|
|
9136
|
+
<script src="typing-sfx.js" defer></script>
|
|
9085
9137
|
<script src="app.js" defer></script>
|
|
9086
9138
|
<script>
|
|
9087
9139
|
/* FOUC-prevention: apply saved theme synchronously before paint */
|
|
@@ -9113,41 +9165,31 @@
|
|
|
9113
9165
|
|
|
9114
9166
|
<div class="control">
|
|
9115
9167
|
|
|
9116
|
-
<!-- ═══════════════ TOP BAR (classification banner) ═══════════════ -->
|
|
9117
|
-
<header class="topbar">
|
|
9118
|
-
<div class="brand-block">
|
|
9119
|
-
<svg class="brand-mark" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" shape-rendering="crispEdges" role="img" aria-label="PrivateBoard">
|
|
9120
|
-
<rect class="bg" width="16" height="16"/>
|
|
9121
|
-
<rect class="fg" x="3" y="2" width="2" height="2"/>
|
|
9122
|
-
<rect class="fg" x="7" y="2" width="2" height="2"/>
|
|
9123
|
-
<rect class="fg" x="11" y="2" width="2" height="2"/>
|
|
9124
|
-
<rect class="fg" x="2" y="4" width="12" height="2"/>
|
|
9125
|
-
<rect class="fg" x="1" y="7" width="14" height="2"/>
|
|
9126
|
-
<rect class="fg" x="2" y="10" width="1" height="4"/>
|
|
9127
|
-
<rect class="fg" x="13" y="10" width="1" height="4"/>
|
|
9128
|
-
</svg>
|
|
9129
|
-
<span class="brand-name">PRIVATEBOARD</span>
|
|
9130
|
-
<span class="brand-sep">//</span>
|
|
9131
|
-
<span class="brand-name">CONTROL</span>
|
|
9132
|
-
<span class="classification">PRIVATE ACCESS</span>
|
|
9133
|
-
</div>
|
|
9134
|
-
|
|
9135
|
-
<div class="topbar-right">
|
|
9136
|
-
<div><span class="key">SYNC:</span><span class="val">2026·04·28 · 14:42</span></div>
|
|
9137
|
-
<div><span class="key">UID:</span><span class="val">0x4A1F</span></div>
|
|
9138
|
-
<div><span class="key">ROOM:</span><span class="val">047 · ROUND 03</span></div>
|
|
9139
|
-
</div>
|
|
9140
|
-
</header>
|
|
9141
|
-
|
|
9142
9168
|
<!-- ═══════════════ MAIN GRID ═══════════════ -->
|
|
9169
|
+
<!-- The previous `<header class="topbar">` (decorative classification
|
|
9170
|
+
banner with brand mark + SYNC / UID / ROOM placeholder fields)
|
|
9171
|
+
has been retired. The brand mark moved into `.sidebar-head` as
|
|
9172
|
+
the lock-up logo; the placeholder fields were never load-bearing
|
|
9173
|
+
data. Sidebar + room now reach the top of the viewport. -->
|
|
9143
9174
|
<div class="body-grid">
|
|
9144
9175
|
|
|
9145
9176
|
<!-- ═══════════════ SIDEBAR ═══════════════ -->
|
|
9146
9177
|
<aside class="sidebar">
|
|
9147
9178
|
|
|
9148
9179
|
<div class="sidebar-head">
|
|
9149
|
-
<
|
|
9150
|
-
|
|
9180
|
+
<a href="/" class="sidebar-brand" aria-label="PrivateBoard">
|
|
9181
|
+
<svg class="brand-mark" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" shape-rendering="crispEdges" role="img" aria-label="PrivateBoard">
|
|
9182
|
+
<rect class="bg" width="16" height="16"/>
|
|
9183
|
+
<rect class="fg" x="3" y="2" width="2" height="2"/>
|
|
9184
|
+
<rect class="fg" x="7" y="2" width="2" height="2"/>
|
|
9185
|
+
<rect class="fg" x="11" y="2" width="2" height="2"/>
|
|
9186
|
+
<rect class="fg" x="2" y="4" width="12" height="2"/>
|
|
9187
|
+
<rect class="fg" x="1" y="7" width="14" height="2"/>
|
|
9188
|
+
<rect class="fg" x="2" y="10" width="1" height="4"/>
|
|
9189
|
+
<rect class="fg" x="13" y="10" width="1" height="4"/>
|
|
9190
|
+
</svg>
|
|
9191
|
+
<span class="sidebar-brand-name">PRIVATEBOARD</span>
|
|
9192
|
+
</a>
|
|
9151
9193
|
<button type="button" class="sidebar-collapse-btn" data-sidebar-collapse aria-label="Collapse sidebar" title="Collapse sidebar"></button>
|
|
9152
9194
|
</div>
|
|
9153
9195
|
|