privateboard 0.1.6 → 0.1.8

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/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: auto 1fr;
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
- TOP BAR (classification banner)
146
- ═══════════════════════════════════════════ */
147
- .topbar {
148
- background: var(--panel);
149
- border: 0.5px solid var(--line);
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: 20px; height: 20px;
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 (absolute-
218
- positioned) anchors to the body-grid's top-left edge instead of
219
- the viewport that puts the button below the topbar / brand
220
- logo where the user expects it, not on top of it. */
172
+ /* `position: relative` so the floating sidebar-expand-btn
173
+ (absolute-positioned) anchors to the body-grid's top-left
174
+ edgewhich, 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: 6px 12px;
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
- .sidebar-head-title {
291
- font-size: 10px;
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.14em;
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-head-meta {
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: 8px 10px;
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;
@@ -1404,7 +1375,7 @@
1404
1375
  .notes-filters {
1405
1376
  display: flex;
1406
1377
  gap: 2px;
1407
- margin: 22px 0 6px;
1378
+ margin: 22px 0 2px;
1408
1379
  flex-wrap: wrap;
1409
1380
  }
1410
1381
  .reports-filter-chip,
@@ -1447,7 +1418,14 @@
1447
1418
  .notes-filter-chip.on .notes-filter-count { color: var(--text-dim); }
1448
1419
 
1449
1420
  /* ─── Reading list ─────────────────────────────────────────────── */
1450
- .reports-list-wrap { margin-top: 18px; }
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: 8px;
1426
+ padding-top: 8px;
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
- /* Date-bucket sections · each opens with its own hairline-divided
1787
- label row, matching the reports `.reports-group` rhythm. */
1788
- .notes-group + .notes-group { margin-top: 32px; }
1789
- .notes-group:first-of-type { margin-top: 22px; }
1790
- .notes-group-head {
1791
- display: flex;
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-group-label {
1799
- font-family: var(--mono);
1800
- font-size: 10px;
1801
- font-weight: 700;
1802
- letter-spacing: 0.22em;
1803
- text-transform: uppercase;
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: 10px;
1809
- color: var(--text-dim);
1810
- letter-spacing: 0.04em;
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-list { list-style: none; margin: 0; padding: 0; }
1814
- .notes-item { border-bottom: 0.5px solid var(--line); }
1815
- .notes-item:last-child { border-bottom: none; }
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 date-grouped list · matches the reports list
2053
- wrap so the chip strip → list spacing reads identically. */
2054
- .notes-list-wrap { margin-top: 18px; }
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: 8px;
2094
+ padding-top: 8px;
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: 8px 14px;
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: 8px 14px;
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;
@@ -2709,6 +2760,23 @@
2709
2760
  text-transform: uppercase;
2710
2761
  color: var(--lime);
2711
2762
  }
2763
+ /* Mode chip · "Report" / "Bento" / "Magazine" / "Newspaper".
2764
+ Sits between the // report kicker and the FILED stamp, styled as
2765
+ a hairline mono pill so the user sees the report type at a glance
2766
+ without it competing with the kicker for primary emphasis.
2767
+ `margin-right: auto` pushes the stamp to the right edge while the
2768
+ chip stays anchored next to the kicker. */
2769
+ .brief-banner-type {
2770
+ font-size: 9px;
2771
+ font-weight: 600;
2772
+ letter-spacing: 0.12em;
2773
+ text-transform: uppercase;
2774
+ color: var(--text-soft);
2775
+ border: 0.5px solid var(--line-bright, var(--line));
2776
+ padding: 2px 8px;
2777
+ margin-right: auto;
2778
+ white-space: nowrap;
2779
+ }
2712
2780
  .brief-banner-stamp {
2713
2781
  font-size: 9px;
2714
2782
  letter-spacing: 0.12em;
@@ -9082,6 +9150,7 @@
9082
9150
  <script src="onboarding.js" defer></script>
9083
9151
  <link rel="stylesheet" href="quote-cta.css">
9084
9152
  <script src="quote-cta.js" defer></script>
9153
+ <script src="typing-sfx.js" defer></script>
9085
9154
  <script src="app.js" defer></script>
9086
9155
  <script>
9087
9156
  /* FOUC-prevention: apply saved theme synchronously before paint */
@@ -9113,41 +9182,31 @@
9113
9182
 
9114
9183
  <div class="control">
9115
9184
 
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
9185
  <!-- ═══════════════ MAIN GRID ═══════════════ -->
9186
+ <!-- The previous `<header class="topbar">` (decorative classification
9187
+ banner with brand mark + SYNC / UID / ROOM placeholder fields)
9188
+ has been retired. The brand mark moved into `.sidebar-head` as
9189
+ the lock-up logo; the placeholder fields were never load-bearing
9190
+ data. Sidebar + room now reach the top of the viewport. -->
9143
9191
  <div class="body-grid">
9144
9192
 
9145
9193
  <!-- ═══════════════ SIDEBAR ═══════════════ -->
9146
9194
  <aside class="sidebar">
9147
9195
 
9148
9196
  <div class="sidebar-head">
9149
- <div class="sidebar-head-title">// CONTROL</div>
9150
- <div class="sidebar-head-meta"><span class="lime">●</span> <span data-sidebar-summary>0 LIVE / 0 AGENTS</span></div>
9197
+ <a href="/" class="sidebar-brand" aria-label="PrivateBoard">
9198
+ <svg class="brand-mark" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" shape-rendering="crispEdges" role="img" aria-label="PrivateBoard">
9199
+ <rect class="bg" width="16" height="16"/>
9200
+ <rect class="fg" x="3" y="2" width="2" height="2"/>
9201
+ <rect class="fg" x="7" y="2" width="2" height="2"/>
9202
+ <rect class="fg" x="11" y="2" width="2" height="2"/>
9203
+ <rect class="fg" x="2" y="4" width="12" height="2"/>
9204
+ <rect class="fg" x="1" y="7" width="14" height="2"/>
9205
+ <rect class="fg" x="2" y="10" width="1" height="4"/>
9206
+ <rect class="fg" x="13" y="10" width="1" height="4"/>
9207
+ </svg>
9208
+ <span class="sidebar-brand-name">PRIVATEBOARD</span>
9209
+ </a>
9151
9210
  <button type="button" class="sidebar-collapse-btn" data-sidebar-collapse aria-label="Collapse sidebar" title="Collapse sidebar"></button>
9152
9211
  </div>
9153
9212