pi-weave 0.3.9 → 0.3.10

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.
@@ -67,8 +67,9 @@ export const THEME_CSS = `
67
67
  --weave-note-gutter:18px;
68
68
  /* The desk-and-page split. The workspace is a desk of instruments — tree,
69
69
  graph, rail, bars — on the --weave-bg ground; the note column is the one
70
- *page* lying on it: crust in both Catppuccin schemes, the ground that
71
- sits furthest from the desk (deep under dark, bright over light). Two
70
+ *page* lying on it: crust under dark, plain white under Latte (the
71
+ refresh's "quiet page": paper reads as paper), the ground that sits
72
+ furthest from the desk. Two
72
73
  voices in total: sans for instruments and prose alike, mono for data — a
73
74
  third face was tried (serif prose) and withdrawn at the user's call; two
74
75
  voices read calmer than three. The CSP allows nothing fetched, and both
@@ -79,7 +80,7 @@ export const THEME_CSS = `
79
80
  two overlays that float above the grid. Tag pills are 999px — a capsule
80
81
  shape, not a scale step. The gate test below refuses any literal px
81
82
  radius so the scale cannot drift back. */
82
- --weave-radius:4px;--weave-radius-pop:7px;
83
+ --weave-radius:6px;--weave-radius-pop:10px;
83
84
  /* The type ramp, role-named because sizes drift and roles stick. Nine
84
85
  steps; every font-size in this sheet is one of these vars — that is a
85
86
  gate, not a convention:
@@ -91,7 +92,7 @@ export const THEME_CSS = `
91
92
  body 13.5 the note column's prose
92
93
  subhead 14 palette input, note-body h2, ribbon icon buttons
93
94
  title 15 note-body h1
94
- display 20 the note's page title
95
+ display 26 the note's page title (20 before the refresh)
95
96
  Two earlier sizes were merged into neighbours: 9px glyphs to prov, and
96
97
  the 10px column overlines to caption (caps plus .09em tracking already
97
98
  read larger than their point size suggests). \`display\` and \`body\` are
@@ -106,7 +107,7 @@ export const THEME_CSS = `
106
107
  rubber stamp. */
107
108
  --weave-px-prov:9.5px;--weave-px-caption:10.5px;--weave-px-ui:11.5px;
108
109
  --weave-px-row:12px;--weave-px-base:13px;--weave-px-body:13.5px;
109
- --weave-px-subhead:14px;--weave-px-title:15px;--weave-px-display:20px;
110
+ --weave-px-subhead:14px;--weave-px-title:15px;--weave-px-display:26px;
110
111
  }
111
112
  @media (prefers-color-scheme: light){
112
113
  :root:not([data-weave-theme]){${paletteTokens("light")}}
@@ -166,7 +167,7 @@ body{font-size:var(--weave-px-base)}
166
167
  so the selected row is always readable. */
167
168
  .weave-row-on .weave-twisty,.weave-row-on .weave-kind,.weave-row-on .weave-prov,
168
169
  .weave-row-on .weave-meta,.weave-row-on .weave-label{color:var(--weave-fg)}
169
- .weave-hit-on .weave-hit-badge,.weave-hit-on .weave-hit-detail{color:var(--weave-fg)}
170
+ .weave-hit-on .weave-hit-icon,.weave-hit-on .weave-hit-detail,.weave-hit-on .weave-hit-meta{color:var(--weave-fg)}
170
171
  /* A newly-arrived node (a file or note added since the last update, ):
171
172
  one short highlight that fades while the label settles from bold back to
172
173
  normal. The class is computed from the frame diff in workspace.ts and
@@ -245,7 +246,7 @@ body{font-size:var(--weave-px-base)}
245
246
  .weave-note-head{position:sticky;top:0;z-index:2;padding:14px var(--weave-note-gutter) 9px;background:var(--weave-page);border-bottom:1px solid var(--weave-line)}
246
247
  /* The page's largest voice, and the point of the review's headline finding:
247
248
  a 15px title sat 1.5px above the body it named. --weave-px-display puts the
248
- title where a page's title belongs, weight 650 for presence at 20px (600
249
+ title where a page's title belongs, weight 650 for presence at 26px (600
249
250
  reads thin at that size, 700 reads as a poster), tracking pulled in by a
250
251
  hair because large sans needs it. */
251
252
  .weave-note-title{margin:0 0 4px;font-size:var(--weave-px-display);font-weight:650;line-height:1.25;letter-spacing:-.005em;color:var(--weave-fg)}
@@ -262,20 +263,67 @@ body{font-size:var(--weave-px-base)}
262
263
  }
263
264
  .weave-note-open:hover{color:var(--weave-fg);background:var(--weave-line)}
264
265
  .weave-note-open-mark{display:inline-flex;line-height:0}
265
- /* Save / Done, chip-shaped: the same quiet row, and a control in a reading
266
- column should not outweigh the title. */
267
- .weave-note-edit,.weave-note-save{
266
+ /* The note's own actions, at the end of the meta line. History is a quiet
267
+ word with an icon; Edit is the one bordered control, and neither outweighs
268
+ the title. */
269
+ .weave-note-actions{margin-left:auto;display:inline-flex;align-items:center;gap:4px}
270
+ .weave-note-meta .weave-note-action{
271
+ display:inline-flex;align-items:center;gap:5px;
268
272
  font:inherit;font-size:var(--weave-px-caption);line-height:1;white-space:nowrap;cursor:pointer;
269
- color:var(--weave-dim);background:var(--weave-panel);padding:4px 7px;
270
- border:1px solid var(--weave-line-strong);border-radius:var(--weave-radius);
271
- }
272
- .weave-note-edit:hover,.weave-note-save:hover{color:var(--weave-fg);border-color:var(--weave-accent)}
273
- /* Save is the row's only affirmative action, so the only one with the accent. */
274
- .weave-note-save{color:var(--weave-accent);border-color:var(--weave-accent)}
275
- .weave-note-save:disabled{color:var(--weave-faint);border-color:var(--weave-line-strong);cursor:default}
276
- /* History: a slim bar under the header. The step's added text is marked in
277
- the accent tint, the same strength the selected rows use. */
278
- .weave-note-history[aria-pressed="true"]{color:var(--weave-accent);border-color:var(--weave-accent)}
273
+ color:var(--weave-dim);background:none;padding:5px 8px;
274
+ border:1px solid transparent;border-radius:var(--weave-radius);
275
+ }
276
+ .weave-note-meta .weave-note-action .weave-icon{width:13px;height:13px}
277
+ .weave-note-meta .weave-note-action:hover{color:var(--weave-fg);background:var(--weave-new)}
278
+ .weave-note-meta .weave-note-action:disabled{color:var(--weave-faint);background:none;cursor:default}
279
+ .weave-note-meta .weave-note-edit{color:var(--weave-fg);background:var(--weave-page);border-color:var(--weave-line-strong)}
280
+ .weave-note-meta .weave-note-edit:hover{border-color:var(--weave-accent);background:var(--weave-page)}
281
+ .weave-note-meta .weave-note-history[aria-pressed="true"]{color:var(--weave-accent);background:var(--weave-new)}
282
+ /* Where the note lives, above its title: a crumb, not a heading. */
283
+ .weave-note-crumb{margin:0 0 6px;display:flex;align-items:center;gap:5px;font-size:var(--weave-px-caption);color:var(--weave-faint)}
284
+ .weave-note-crumb .weave-icon{width:12px;height:12px}
285
+ /* Who wrote it, in words, with the spine's colour as a dot. */
286
+ .weave-note-meta .weave-prov{display:inline-flex;align-items:center;gap:6px;font-size:var(--weave-px-ui);color:var(--weave-dim)}
287
+ .weave-prov-dot{width:7px;height:7px;border-radius:999px;background:var(--weave-spine,var(--weave-accent))}
288
+ /* The edit bar (E1): one row while editing, pinned over the text it edits.
289
+ Formatting on the left, where the words are; the save state and the two
290
+ ways out on the right. Saving is automatic, so Done is the only
291
+ affirmative control and the only one in the accent. */
292
+ .weave-editbar{
293
+ position:sticky;top:0;z-index:3;display:flex;align-items:center;gap:6px;flex-wrap:wrap;
294
+ min-height:40px;padding:5px 12px;font-size:var(--weave-px-ui);
295
+ background:var(--weave-page);border-bottom:1px solid var(--weave-line);
296
+ }
297
+ .weave-editbar .weave-icon{width:14px;height:14px}
298
+ .weave-editbar-badge{
299
+ display:inline-flex;align-items:center;gap:5px;padding:3px 9px;border-radius:999px;
300
+ font-size:var(--weave-px-caption);font-weight:600;color:var(--weave-accent);background:var(--weave-new);
301
+ }
302
+ .weave-editbar-badge .weave-icon{width:12px;height:12px}
303
+ .weave-editbar-tools{display:inline-flex;align-items:center;gap:1px;margin-left:4px;padding-left:8px;border-left:1px solid var(--weave-line)}
304
+ .weave-editbar .weave-editbar-tool{
305
+ display:inline-grid;place-items:center;width:28px;height:28px;padding:0;cursor:pointer;
306
+ color:var(--weave-dim);background:none;border:0;border-radius:var(--weave-radius);
307
+ }
308
+ .weave-editbar .weave-editbar-tool:hover{color:var(--weave-fg);background:var(--weave-new)}
309
+ .weave-editbar-status{margin-left:auto;display:inline-flex;align-items:center;gap:5px;white-space:nowrap;font-size:var(--weave-px-caption);color:var(--weave-faint)}
310
+ .weave-editbar-pending,.weave-editbar-saving{color:var(--weave-dim)}
311
+ .weave-editbar-saved{color:var(--weave-ok)}
312
+ .weave-editbar-failed{color:var(--weave-bad);font-weight:600}
313
+ .weave-editbar .weave-editbar-retry{font:inherit;color:var(--weave-accent);background:none;border:0;padding:2px 4px;cursor:pointer;text-decoration:underline;text-underline-offset:2px}
314
+ .weave-editbar .weave-editbar-discard,.weave-editbar .weave-editbar-done{font:inherit;font-size:var(--weave-px-caption);line-height:1;white-space:nowrap;cursor:pointer;border-radius:var(--weave-radius)}
315
+ .weave-editbar .weave-editbar-discard{padding:7px 9px;color:var(--weave-dim);background:none;border:1px solid transparent}
316
+ .weave-editbar .weave-editbar-discard:hover{color:var(--weave-fg);background:var(--weave-new)}
317
+ .weave-editbar .weave-editbar-done{padding:7px 14px;font-weight:600;color:var(--weave-page);background:var(--weave-accent);border:1px solid var(--weave-accent)}
318
+ .weave-editbar .weave-editbar-done:hover{filter:brightness(1.08)}
319
+ .weave-editbar .weave-editbar-discard:disabled,.weave-editbar .weave-editbar-done:disabled{opacity:.5;cursor:default;filter:none}
320
+ /* A finalized note's opening TLDR, set apart as the first thing to read.
321
+ The label is the card's own; task boxes keep their row and lose the bullet. */
322
+ .weave-tldr{margin:0 0 18px;padding:12px 16px;background:var(--weave-new);border:1px solid var(--weave-line-strong);border-radius:var(--weave-radius)}
323
+ .weave-tldr>p,.weave-tldr>ul,.weave-tldr>ol{margin:0 0 6px}
324
+ .weave-tldr>*:last-child{margin-bottom:0}
325
+ .weave-tldr ul:has(>li>input[type="checkbox"]){list-style:none;padding-left:2px}
326
+ .weave-tldr-label{display:block;margin-bottom:3px;font-size:var(--weave-px-prov);font-weight:700;letter-spacing:.08em;color:var(--weave-accent)}
279
327
  /* The replay band sits under the header like the header itself: full width,
280
328
  the note's gutter, one line of words, one line of controls. Dots on the
281
329
  track are the versions, coloured by who made them. */
@@ -306,25 +354,28 @@ body{font-size:var(--weave-px-base)}
306
354
  .weave-replay-controls button:disabled{color:var(--weave-faint);cursor:default;opacity:.6}
307
355
  .weave-replay-controls .weave-replay-play{color:var(--weave-page);background:var(--weave-accent);border-color:var(--weave-accent)}
308
356
  .weave-replay-controls .weave-replay-play:hover:not(:disabled){filter:brightness(1.08)}
309
- .weave-replay-track{--weave-replay-at:100%;position:relative;flex:1;min-width:80px;height:28px;margin-left:8px}
357
+ /* The change bars (the refresh's H2): one bar per version, as tall as the
358
+ change was big, coloured by who made it; the version on screen is ringed.
359
+ The day labels sit under the band. Heights and label positions arrive as
360
+ custom properties through Preact's CSSOM style path, never an attribute. */
361
+ .weave-replay-track{--weave-replay-at:100%;position:relative;flex:1;min-width:80px;height:46px;margin-left:8px}
310
362
  .weave-replay-track::before{
311
- content:"";position:absolute;left:7px;right:7px;top:13px;height:2px;border-radius:999px;
363
+ content:"";position:absolute;left:7px;right:7px;top:31px;height:2px;border-radius:999px;
312
364
  background:linear-gradient(to right,color-mix(in srgb,var(--weave-accent) 55%,transparent) var(--weave-replay-at),var(--weave-line-strong) var(--weave-replay-at));
313
365
  }
314
- .weave-replay-ticks{position:absolute;left:7px;right:7px;top:0;bottom:0;display:flex;justify-content:space-between;align-items:center;pointer-events:none}
315
- .weave-replay-tick{position:relative;width:0;height:0}
316
- .weave-replay-tick::before{
317
- content:"";position:absolute;left:-6px;top:-6px;width:12px;height:12px;box-sizing:border-box;border-radius:999px;
318
- background:var(--weave-who);border:2px solid var(--weave-panel);
319
- }
320
- .weave-replay-ahead::before{opacity:.4}
366
+ .weave-replay-bars{position:absolute;left:7px;right:7px;top:2px;height:26px;pointer-events:none}
367
+ .weave-replay-bar{position:absolute;bottom:0;left:var(--weave-bar-at,0);width:max(1px,min(8px,calc(100% / var(--weave-bars,1) - 2px)));transform:translateX(-50%);height:var(--weave-bar,14%);border-radius:var(--weave-radius);background:var(--weave-who);opacity:.85}
368
+ .weave-replay-ahead{opacity:.35}
369
+ .weave-replay-current{opacity:1;outline:2px solid var(--weave-accent);outline-offset:1px}
370
+ .weave-replay-days{position:absolute;left:7px;right:7px;top:34px;height:12px;pointer-events:none}
371
+ .weave-replay-day{position:absolute;left:var(--weave-day-at,0);transform:translateX(-2px);font-size:var(--weave-px-prov);line-height:12px;color:var(--weave-faint);white-space:nowrap}
321
372
  .weave-replay-slider{position:absolute;inset:0;width:100%;height:100%;margin:0;background:transparent;-webkit-appearance:none;appearance:none;cursor:pointer}
322
373
  .weave-replay-slider:disabled{cursor:default}
323
374
  .weave-replay-slider:focus{outline:none}
324
- .weave-replay-slider::-webkit-slider-runnable-track{height:28px;background:transparent}
325
- .weave-replay-slider::-moz-range-track{height:28px;background:transparent}
375
+ .weave-replay-slider::-webkit-slider-runnable-track{height:46px;background:transparent}
376
+ .weave-replay-slider::-moz-range-track{height:46px;background:transparent}
326
377
  .weave-replay-slider::-webkit-slider-thumb{
327
- -webkit-appearance:none;appearance:none;width:14px;height:14px;margin-top:7px;border-radius:999px;
378
+ -webkit-appearance:none;appearance:none;width:14px;height:14px;margin-top:25px;border-radius:999px;
328
379
  background:var(--weave-page);border:2px solid var(--weave-accent);box-sizing:border-box;
329
380
  }
330
381
  .weave-replay-slider::-moz-range-thumb{
@@ -342,7 +393,7 @@ body{font-size:var(--weave-px-base)}
342
393
  display:block;width:100%;flex:1 0 auto;min-height:12em;resize:none;
343
394
  padding:12px var(--weave-note-gutter) 28px;box-sizing:border-box;
344
395
  font-family:var(--weave-mono);font-size:var(--weave-px-row);line-height:1.6;
345
- color:var(--weave-fg);background:var(--weave-bg);border:0;outline:0;
396
+ color:var(--weave-fg);background:var(--weave-page);border:0;outline:0;
346
397
  }
347
398
  /* The \`## Raw\` box under the editor: folded by default so a long
348
399
  dictation never outgrows the note, a dashed edge to say "captured, not
@@ -516,6 +567,113 @@ body{font-size:var(--weave-px-base)}
516
567
  border-top:1px solid var(--weave-line);
517
568
  }
518
569
 
570
+ /* graph spotlight (G1) ---------------------------------------------------
571
+ The field floating top-left over the canvas, and the side sheet top-right.
572
+ Both are overlays on the stage, so they sit on the panel ground with a
573
+ hairline and the pop radius — no elevation shadow, per the sheet's rule.
574
+ The spotlight's voice is --weave-warn: the highlighter colour the WebGL
575
+ side paints lit edges in (graph.model.ts SPOTLIGHT_EDGE_SLOT), so the chip,
576
+ the legend, the marked words and the lit dots all say "lit" in one hue.
577
+ The sheet stops short of the control strip and count line under the
578
+ canvas (about 54px together) and scrolls inside itself. Button rules are
579
+ qualified by their overlay (.weave-sheet .weave-sheet-open) because the
580
+ workspace sheet's \`.weave-workbench button{font:inherit;color:inherit}\`
581
+ reset is installed later and would outrank a single class. */
582
+ .weave-spotlight{
583
+ position:absolute;z-index:3;top:10px;left:10px;width:min(330px,calc(100% - 20px));box-sizing:border-box;
584
+ display:flex;align-items:center;gap:6px;padding:3px 5px 3px 9px;
585
+ color:var(--weave-faint);background:var(--weave-panel);
586
+ border:1px solid var(--weave-line-strong);border-radius:var(--weave-radius-pop);
587
+ }
588
+ /* The pill is the focus ring: the input inside it drops the global outline
589
+ and the frame takes a 2px accent edge (border plus an inset hairline). */
590
+ .weave-spotlight:focus-within{border-color:var(--weave-accent);box-shadow:inset 0 0 0 1px var(--weave-accent)}
591
+ .weave-spotlight-input:focus-visible{outline:none}
592
+ .weave-spotlight-on{color:var(--weave-warn)}
593
+ .weave-spotlight-icon{flex:none;display:block}
594
+ .weave-spotlight-input{
595
+ flex:1;min-width:0;height:24px;padding:0;font:inherit;font-size:var(--weave-px-row);
596
+ color:var(--weave-fg);background:transparent;border:0;outline:0;
597
+ }
598
+ .weave-spotlight-input::placeholder{color:var(--weave-faint)}
599
+ .weave-spotlight-input::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none}
600
+ .weave-spotlight-count{
601
+ flex:none;padding:1px 7px;font-size:var(--weave-px-caption);font-weight:650;white-space:nowrap;
602
+ color:var(--weave-warn);background:color-mix(in srgb,var(--weave-warn) 16%,transparent);border-radius:999px;
603
+ }
604
+ .weave-spotlight-none{color:var(--weave-dim);background:var(--weave-line)}
605
+ .weave-spotlight .weave-spotlight-clear{
606
+ flex:none;padding:1px 5px;cursor:pointer;font-family:var(--weave-mono);font-size:var(--weave-px-prov);
607
+ color:var(--weave-faint);background:transparent;border:1px solid var(--weave-line-strong);border-radius:var(--weave-radius);
608
+ }
609
+ .weave-spotlight .weave-spotlight-clear:hover{color:var(--weave-fg);border-color:var(--weave-accent)}
610
+ .weave-legend-lit{color:var(--weave-warn)}
611
+ .weave-sheet{
612
+ position:absolute;z-index:3;top:10px;right:10px;width:min(300px,calc(100% - 20px));max-height:calc(100% - 74px);
613
+ box-sizing:border-box;overflow:auto;padding:12px 14px 14px;
614
+ font-size:var(--weave-px-base);color:var(--weave-fg);background:var(--weave-panel);
615
+ border:1px solid var(--weave-line-strong);border-radius:var(--weave-radius-pop);
616
+ }
617
+ .weave-sheet .weave-sheet-close{
618
+ position:absolute;top:6px;right:6px;width:24px;height:24px;padding:0;cursor:pointer;
619
+ font-size:var(--weave-px-display);line-height:1;color:var(--weave-dim);
620
+ background:transparent;border:0;border-radius:var(--weave-radius);
621
+ }
622
+ .weave-sheet .weave-sheet-close:hover{color:var(--weave-fg);background:var(--weave-line)}
623
+ .weave-sheet-crumb{
624
+ margin:0 28px 2px 0;display:flex;align-items:center;gap:5px;min-width:0;
625
+ font-size:var(--weave-px-caption);color:var(--weave-faint);
626
+ }
627
+ .weave-sheet-crumb span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
628
+ .weave-sheet-title{
629
+ margin:0 20px 4px 0;font-size:var(--weave-px-title);font-weight:650;line-height:1.3;overflow-wrap:anywhere;
630
+ }
631
+ .weave-sheet-meta{margin:0;display:flex;align-items:center;gap:5px;font-size:var(--weave-px-ui);color:var(--weave-dim);text-transform:capitalize}
632
+ .weave-sheet-when{color:var(--weave-faint);text-transform:none}
633
+ .weave-sheet-text{
634
+ margin:10px 0 0;padding:8px 10px;line-height:1.55;overflow-wrap:anywhere;
635
+ background:var(--weave-new);border:1px solid color-mix(in srgb,var(--weave-accent) 30%,transparent);
636
+ border-radius:var(--weave-radius-pop);
637
+ }
638
+ .weave-sheet-text-head{
639
+ display:block;margin:0 0 2px;font-size:var(--weave-px-prov);font-weight:700;letter-spacing:.09em;
640
+ text-transform:uppercase;color:var(--weave-accent);
641
+ }
642
+ .weave-sheet-mark{border-radius:var(--weave-radius)}
643
+ .weave-sheet-why{margin:8px 0 0;display:flex;gap:5px;font-size:var(--weave-px-caption);color:var(--weave-dim)}
644
+ .weave-sheet-why span{color:var(--weave-warn)}
645
+ .weave-sheet-section{margin:12px 0 0}
646
+ .weave-sheet-heading{
647
+ margin:0 0 3px;display:flex;align-items:center;font-size:var(--weave-px-caption);font-weight:600;
648
+ letter-spacing:.09em;text-transform:uppercase;color:var(--weave-faint);
649
+ }
650
+ .weave-sheet-count{margin-left:auto;font-family:var(--weave-mono);letter-spacing:0}
651
+ .weave-sheet-rows{margin:0;padding:0;list-style:none}
652
+ .weave-sheet .weave-sheet-row{
653
+ display:flex;align-items:center;gap:7px;width:100%;padding:3px 0;cursor:pointer;text-align:left;
654
+ font:inherit;font-size:var(--weave-px-row);color:var(--weave-fg);background:none;border:0;
655
+ }
656
+ .weave-sheet .weave-sheet-row:hover{color:var(--weave-accent)}
657
+ .weave-sheet-row-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
658
+ .weave-sheet-dot{flex:none;width:6px;height:6px;border-radius:999px;background:var(--weave-faint)}
659
+ .weave-sheet-dot-lit{background:var(--weave-warn)}
660
+ .weave-sheet-more{margin:2px 0 0;font-size:var(--weave-px-caption);color:var(--weave-faint)}
661
+ .weave-sheet-actions{margin:14px 0 0;display:flex;gap:6px;flex-wrap:wrap}
662
+ .weave-sheet .weave-sheet-open,.weave-sheet .weave-sheet-split{
663
+ padding:5px 11px;cursor:pointer;font:inherit;font-size:var(--weave-px-ui);font-weight:600;
664
+ border:1px solid var(--weave-line-strong);border-radius:var(--weave-radius);
665
+ }
666
+ .weave-sheet .weave-sheet-open{color:var(--weave-page);background:var(--weave-accent);border-color:var(--weave-accent)}
667
+ .weave-sheet .weave-sheet-open:hover{filter:brightness(1.08)}
668
+ .weave-sheet .weave-sheet-split{color:var(--weave-fg);background:var(--weave-page)}
669
+ .weave-sheet .weave-sheet-split:hover{border-color:var(--weave-accent)}
670
+ /* Side by side the field (330) and the sheet (300) need about 660px of
671
+ stage; a narrower graph — a split pane, a small window — drops the sheet
672
+ under the field instead of letting the two overlap. */
673
+ .weave-graph{container-type:inline-size}
674
+ @container (max-width:680px){.weave-sheet{top:50px;max-height:calc(100% - 114px)}}
675
+ /* end graph spotlight ---------------------------------------------------- */
676
+
519
677
  /* context rail ---------------------------------------------------------- */
520
678
  /* The \`.weave-empty\` block that used to sit above went with \`EmptyState.tsx\`
521
679
  in P3: every column now has its own empty state (\`treeEmptyMessage\`,
@@ -596,6 +754,7 @@ body{font-size:var(--weave-px-base)}
596
754
  .weave-status-cwd,.weave-status-sel{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
597
755
  .weave-status-cwd{max-width:38%;color:var(--weave-faint)}
598
756
  .weave-status-sel{color:var(--weave-fg)}
757
+ .weave-status-hint{margin-left:auto;padding-left:8px;white-space:nowrap;color:var(--weave-faint)}
599
758
 
600
759
  /* overlays: the ⌘K palette and the ? help sheet (P4) --------------------- */
601
760
  /* The scrim is a click target that closes, and the reason both overlays sit
@@ -611,31 +770,77 @@ body{font-size:var(--weave-px-base)}
611
770
  overflow:hidden;background:var(--weave-panel);color:var(--weave-fg);
612
771
  border:1px solid var(--weave-line-strong);border-radius:var(--weave-radius-pop);
613
772
  }
773
+ /* The ⌘K palette, grouped and compact: an input row (glyph, query, Esc), a
774
+ scope row of pills that Tab cycles, one line per result under small
775
+ capitals group heads, and a footer of key hints. Wider than the help sheet
776
+ because a row carries a title, a snippet and a meta column side by side. */
777
+ .weave-palette{max-width:640px}
778
+ .weave-palette-bar{
779
+ flex:none;display:flex;align-items:center;gap:8px;padding:0 11px;
780
+ border-bottom:1px solid var(--weave-line);
781
+ }
782
+ .weave-palette-glyph{color:var(--weave-faint)}
614
783
  .weave-palette-input{
615
- flex:none;height:34px;padding:0 11px;font:inherit;font-size:var(--weave-px-subhead);
616
- color:var(--weave-fg);background:transparent;border:0;
617
- border-bottom:1px solid var(--weave-line);border-radius:0;
784
+ flex:1;min-width:0;height:36px;padding:0;font:inherit;font-size:var(--weave-px-subhead);
785
+ color:var(--weave-fg);background:transparent;border:0;border-radius:0;
786
+ }
787
+ .weave-palette-input:focus-visible{outline:0}
788
+ .weave-palette-input::-webkit-search-cancel-button{display:none}
789
+ .weave-palette-bar:focus-within{box-shadow:inset 0 -1px 0 var(--weave-accent)}
790
+ .weave-palette-kbd{
791
+ flex:none;padding:0 4px;font-family:inherit;font-size:var(--weave-px-prov);line-height:14px;
792
+ color:var(--weave-faint);border:1px solid var(--weave-line-strong);border-radius:var(--weave-radius);
793
+ }
794
+ .weave-palette-scopes{
795
+ flex:none;display:flex;flex-wrap:wrap;gap:3px;padding:5px 8px;
796
+ border-bottom:1px solid var(--weave-line);
618
797
  }
619
- .weave-palette-input:focus-visible{outline-offset:-2px}
620
- .weave-hits{flex:1;min-height:0;overflow:auto;margin:0;padding:3px 0;list-style:none}
798
+ .weave-palette-scope{
799
+ font:inherit;font-size:var(--weave-px-caption);line-height:1;padding:3px 9px;cursor:pointer;
800
+ color:var(--weave-dim);background:none;border:0;border-radius:999px;
801
+ }
802
+ .weave-palette-scope:hover{color:var(--weave-fg);background:var(--weave-line)}
803
+ .weave-palette-scope[aria-pressed="true"]{color:var(--weave-panel);background:var(--weave-fg);font-weight:600}
804
+ .weave-palette-scope-count{font-variant-numeric:tabular-nums}
805
+ .weave-hits{flex:1;min-height:0;overflow:auto;margin:0;padding:0 0 4px;list-style:none}
806
+ .weave-hit-section{list-style:none}
807
+ .weave-hit-group{
808
+ padding:7px 11px 2px;font-size:var(--weave-px-prov);font-weight:700;letter-spacing:.08em;
809
+ text-transform:uppercase;color:var(--weave-faint);
810
+ }
811
+ .weave-hit-rows{margin:0;padding:0;list-style:none}
621
812
  .weave-hit{
622
- display:flex;align-items:baseline;gap:7px;padding:3px 11px;cursor:pointer;
623
- min-width:0;white-space:nowrap;
813
+ display:flex;align-items:center;gap:8px;padding:3px 11px;cursor:pointer;
814
+ min-width:0;white-space:nowrap;font-size:var(--weave-px-row);
624
815
  }
625
816
  .weave-hit-on{background:var(--weave-new);box-shadow:inset 2px 0 0 var(--weave-accent)}
626
- .weave-hit-badge{
627
- flex:none;font-size:var(--weave-px-prov);letter-spacing:.06em;text-transform:uppercase;color:var(--weave-faint);
628
- min-width:56px;
629
- }
630
- .weave-hit-note .weave-hit-badge{color:var(--weave-accent)}
631
- .weave-hit-label{flex:none;max-width:46%;overflow:hidden;text-overflow:ellipsis}
817
+ .weave-hit-icon{color:var(--weave-faint)}
818
+ .weave-hit-notes .weave-hit-icon{color:var(--weave-accent)}
819
+ .weave-hit-label{flex:none;max-width:46%;overflow:hidden;text-overflow:ellipsis;font-weight:600;color:var(--weave-fg)}
820
+ .weave-hit-mono{font-family:var(--weave-mono);font-size:var(--weave-px-ui);font-weight:500}
632
821
  .weave-hit-detail{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;font-size:var(--weave-px-ui);color:var(--weave-dim)}
822
+ /* The match marks (search rows, the graph sheet) are a find-in-page amber.
823
+ Dark themes tint their own light --weave-warn, and the marked words go
824
+ white: the theme's text on that tint measured 3.3–3.6:1 in the Catppuccin
825
+ darks, white is 5.5:1 or better in every dark theme. A light theme's
826
+ --weave-warn is a deep brown that tints to mud, so light schemes take a
827
+ fixed amber under their own text instead. */
828
+ .weave-hit-mark,.weave-sheet-mark{color:#fff;background:color-mix(in srgb,var(--weave-warn) 28%,transparent)}
829
+ .weave-hit-mark{border-radius:var(--weave-radius);padding:0 1px}
830
+ :root[data-weave-scheme="light"] .weave-hit-mark,:root[data-weave-scheme="light"] .weave-sheet-mark{color:var(--weave-fg);background:color-mix(in srgb,#f2a93b 34%,transparent)}
831
+ .weave-hit-meta{flex:none;margin-left:auto;font-size:var(--weave-px-caption);color:var(--weave-faint);font-variant-numeric:tabular-nums}
633
832
  .weave-palette-status{margin:0;padding:14px 11px;color:var(--weave-dim);line-height:1.5}
634
833
  .weave-palette-foot,.weave-help-foot{
635
834
  display:flex;gap:12px;margin:0;padding:4px 11px;font-size:var(--weave-px-caption);color:var(--weave-faint);
636
835
  border-top:1px solid var(--weave-line);
637
836
  }
638
- .weave-palette-hint,.weave-help-hint{margin-left:auto}
837
+ .weave-palette-foot{align-items:center;flex-wrap:wrap;row-gap:2px;min-height:26px;box-sizing:border-box;background:var(--weave-bg)}
838
+ .weave-palette-light{
839
+ margin-left:auto;display:flex;align-items:center;gap:6px;padding:0;cursor:pointer;white-space:nowrap;
840
+ font:inherit;font-weight:600;color:var(--weave-accent);background:none;border:0;
841
+ }
842
+ .weave-palette-light .weave-palette-kbd{color:inherit;border-color:currentColor}
843
+ .weave-help-hint{margin-left:auto}
639
844
  .weave-help-title{margin:0;padding:9px 11px;font-size:var(--weave-px-base);font-weight:600;border-bottom:1px solid var(--weave-line)}
640
845
  .weave-keys{flex:1;min-height:0;overflow:auto;margin:0;padding:5px 11px}
641
846
  .weave-key-group{margin:0 0 3px;font-size:var(--weave-px-prov);letter-spacing:.09em;text-transform:uppercase;color:var(--weave-faint)}
@@ -5,7 +5,7 @@ export const WORKSPACE_CSS = `
5
5
  .weave-workbench button:focus-visible,.weave-workbench summary:focus-visible{outline:2px solid var(--weave-accent);outline-offset:-2px}
6
6
  .weave-workbench button:disabled{opacity:.35;cursor:default}
7
7
  .weave-ribbon{width:44px;flex:none;display:flex;align-items:center;flex-direction:column;gap:8px;padding:12px 0;background:var(--weave-panel);border-right:1px solid var(--weave-line)}
8
- .weave-ribbon button{width:32px;height:32px;border:0;border-radius:var(--weave-radius);background:transparent;font-size:var(--weave-px-display);color:var(--weave-dim)}
8
+ .weave-ribbon button{width:32px;height:32px;display:grid;place-items:center;border:0;border-radius:var(--weave-radius);background:transparent;font-size:var(--weave-px-display);color:var(--weave-dim)}
9
9
  .weave-ribbon button:hover,.weave-ribbon button[aria-pressed=true]{color:var(--weave-accent);background:var(--weave-new)}
10
10
  .weave-ribbon-space{flex:1}
11
11
  .weave-sidebar{flex:none;min-width:0;display:flex;flex-direction:column;background:var(--weave-panel);overflow:hidden}
@@ -65,20 +65,24 @@ export const WORKSPACE_CSS = `
65
65
  .weave-pane-menu button{text-align:left;border:0;background:none;padding:9px 10px;font-size:var(--weave-px-row)}
66
66
  .weave-pane-menu button:hover{background:var(--weave-new)}
67
67
  .weave-pane-content{min-width:0;min-height:0;display:flex;overflow:hidden;position:relative}
68
- .weave-document{display:flex;min-width:0;min-height:0;flex:1}
68
+ /* The reading column's gutters. Centred at the reading width; where the
69
+ floating Context card covers the right margin, the right gutter grows to
70
+ clear it and the column slides left before it narrows. */
71
+ .weave-document{display:flex;min-width:0;min-height:0;flex:1;
72
+ --weave-gutter-c:max(24px,calc((100% - var(--weave-reading-width,760px))/2));
73
+ --weave-gutter-r:max(var(--weave-gutter-c),var(--weave-card-space,0px));
74
+ --weave-gutter-l:max(24px,min(var(--weave-gutter-c),calc(100% - var(--weave-reading-width,760px) - var(--weave-gutter-r))))}
69
75
  .weave-document .weave-note{width:100%;border-left:0}
70
- .weave-document .weave-note-head{position:static;padding:28px max(24px,calc((100% - var(--weave-reading-width,760px))/2)) 18px;border:0}
71
- .weave-document .weave-note-title{font-size:var(--weave-px-display);letter-spacing:-.03em;margin-bottom:12px}
72
- .weave-document .weave-note-body{padding:10px max(24px,calc((100% - var(--weave-reading-width,760px))/2)) 64px;font-size:var(--weave-note-size,var(--weave-px-subhead));line-height:1.8}
76
+ .weave-document .weave-note-head{position:static;padding:28px var(--weave-gutter-r) 18px var(--weave-gutter-l);border:0}
77
+ .weave-document .weave-note-title{font-size:var(--weave-px-display);letter-spacing:-.03em;margin-bottom:10px}
78
+ .weave-document .weave-note-body{padding:10px var(--weave-gutter-r) 64px var(--weave-gutter-l);font-size:var(--weave-note-size,var(--weave-px-subhead));line-height:1.8}
73
79
  .weave-document .weave-note-body h1{font-size:var(--weave-px-display);line-height:1.4;margin-bottom:18px}
74
80
  .weave-document .weave-note-body h2{font-size:var(--weave-px-title);margin-top:28px}
75
- .weave-document .weave-note-editor{padding:14px max(24px,calc((100% - var(--weave-reading-width,760px))/2));min-height:220px;flex:1;font-size:var(--weave-note-size,var(--weave-px-subhead))}
81
+ .weave-document .weave-note-editor{padding:14px var(--weave-gutter-r) 14px var(--weave-gutter-l);min-height:220px;flex:1;font-size:var(--weave-note-size,var(--weave-px-subhead))}
76
82
  .weave-document .weave-note-tags{margin-top:12px}
77
- .weave-document .weave-replay{padding:12px max(24px,calc((100% - var(--weave-reading-width,760px))/2)) 14px}
78
- .weave-document .weave-raw{margin:0 max(24px,calc((100% - var(--weave-reading-width,760px))/2)) 28px}
79
- .weave-document .weave-note-edit,.weave-document .weave-note-save{padding:5px 10px;border-radius:var(--weave-radius);font-size:var(--weave-px-caption)}
80
- .weave-document .weave-note-edit{color:var(--weave-dim);background:transparent;border-color:transparent}
81
- .weave-document .weave-note-edit:hover{color:var(--weave-accent);background:var(--weave-new);border-color:transparent}
83
+ .weave-document .weave-replay{padding:12px var(--weave-gutter-r) 14px var(--weave-gutter-l)}
84
+ .weave-document .weave-raw{margin:0 var(--weave-gutter-r) 28px var(--weave-gutter-l)}
85
+ .weave-document .weave-editbar{padding-right:calc(12px + var(--weave-card-space,0px))}
82
86
  .weave-welcome{align-self:center;margin:auto;padding:35px;max-width:560px;color:var(--weave-dim);line-height:1.7}
83
87
  .weave-welcome-mark{font-size:var(--weave-px-display);color:var(--weave-accent)}
84
88
  .weave-welcome h1{font-size:var(--weave-px-display);line-height:1.4;letter-spacing:-.025em;color:var(--weave-fg);font-weight:550}
@@ -117,6 +121,29 @@ export const WORKSPACE_CSS = `
117
121
  .weave-footer>.weave-status{flex:1;min-width:0;border:0}
118
122
  .weave-footer>span{padding:4px 10px;white-space:nowrap}
119
123
  .weave-footer>button{font:inherit;color:var(--weave-fg);background:none;border:0;padding:7px 12px;cursor:pointer}
124
+ /* Context as a floating card (C1): over the page's right margin, below the
125
+ pane toolbar, folding to a pill in the toolbar strip. Pinned, it is the
126
+ column it always was. The shadow is the card's only elevation, and lives
127
+ here rather than in THEME_CSS, whose surfaces are flat by rule. */
128
+ .weave-context-dock.weave-context-float{position:absolute;top:90px;right:14px;bottom:auto;z-index:10;width:var(--weave-card-width);max-height:calc(100% - 104px);border:1px solid var(--weave-line-strong);border-radius:var(--weave-radius-pop);background:var(--weave-panel);box-shadow:0 12px 32px #0000001f,0 2px 6px #00000014;transition:opacity 160ms ease,visibility 0s}
129
+ .weave-context-dock.weave-context-float[data-open=false]{width:var(--weave-card-width);opacity:0;visibility:hidden;transition:opacity 160ms ease,visibility 0s 160ms}
130
+ .weave-context-float>.weave-workspace-divider{display:none}
131
+ .weave-context-float>.weave-sidebar,.weave-context-float[data-open=false]>.weave-sidebar{width:100%;max-height:100%;border:0;background:none;transform:none}
132
+ .weave-context-float .weave-sidebar-heading{height:38px;padding:0 6px 0 12px;border-bottom:1px solid var(--weave-line)}
133
+ .weave-context-float .weave-rail{padding:4px 12px 10px}
134
+ .weave-context-float .weave-context-graph-slot{max-height:calc(100dvh - 260px)}
135
+ .weave-context-float .weave-context-tags{height:auto!important;max-height:220px}
136
+ .weave-context-float .weave-ctx-group>.weave-workspace-divider{display:none}
137
+ .weave-context-heading strong{color:var(--weave-fg)}
138
+ .weave-context-count{min-width:18px;padding:1px 6px;border-radius:999px;background:var(--weave-raise);color:var(--weave-dim);font-size:var(--weave-px-caption);line-height:1.4;text-align:center}
139
+ .weave-sidebar-heading .weave-context-pin{margin-left:auto}
140
+ .weave-context-heading button:last-child{margin-left:0}
141
+ .weave-context-heading .weave-context-pin[aria-pressed=true]{color:var(--weave-accent)}
142
+ .weave-context-heading button{display:grid;place-items:center;width:28px;height:28px;padding:0}
143
+ .weave-context-pill{position:absolute;top:47px;right:54px;z-index:10;display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 6px 0 9px;border:1px solid var(--weave-line-strong);border-radius:999px;background:var(--weave-panel);color:var(--weave-dim)!important;font-size:var(--weave-px-caption)!important;box-shadow:0 2px 8px #00000014}
144
+ .weave-context-pill:hover{color:var(--weave-fg)!important;border-color:var(--weave-accent)}
145
+ .weave-context-pill .weave-icon{width:13px;height:13px}
146
+ .weave-pane-under-card{--weave-card-space:calc(var(--weave-card-width) + 28px)}
120
147
  @media(max-width:1049px){
121
148
  .weave-context-dock{position:absolute;right:0;top:0;bottom:0;z-index:10;width:var(--weave-sidebar-width)}
122
149
  .weave-sidebar-context{border-left:1px solid var(--weave-line-strong)}
@@ -3,7 +3,7 @@
3
3
  * `light` and `dark` keep existing saved choices compatible.
4
4
  */
5
5
  const latte = {
6
- bg: "#eff1f5", panel: "#e6e9ef", page: "#dce0e8", raise: "#ccd0da",
6
+ bg: "#eff1f5", panel: "#e6e9ef", page: "#ffffff", raise: "#ccd0da",
7
7
  fg: "#4c4f69", dim: "#56586a", faint: "#606274", line: "#ccd0da", "line-strong": "#bcc0cc",
8
8
  accent: "#7113ec", ok: "#28641b", warn: "#7c4f10", bad: "#b20d30",
9
9
  };
@@ -27,6 +27,11 @@ export interface WorkspaceLayout {
27
27
  readonly ratio: number;
28
28
  readonly treeVisible: boolean;
29
29
  readonly contextVisible: boolean;
30
+ /**
31
+ * Context as a docked column (true) or a card floating over the page's
32
+ * right margin (false, the default since the refresh).
33
+ */
34
+ readonly contextPinned: boolean;
30
35
  readonly treeWidth: number;
31
36
  readonly contextWidth: number;
32
37
  readonly contextGraphHeight: number;
@@ -50,6 +55,7 @@ export function initialLayout(): WorkspaceLayout {
50
55
  ratio: 0.5,
51
56
  treeVisible: true,
52
57
  contextVisible: true,
58
+ contextPinned: false,
53
59
  treeWidth: 240,
54
60
  contextWidth: 240,
55
61
  contextGraphHeight: 260,
@@ -246,11 +252,13 @@ function boundedId(value: unknown, prefix?: "pane" | "tab"): value is string {
246
252
  }
247
253
 
248
254
  export function parseWorkspaceLayout(value: unknown): WorkspaceLayout | null {
249
- if (!record(value) || !exactKeys(value, ["version", "panes", "activePane", "split", "ratio", "treeVisible", "contextVisible", "treeWidth", "contextWidth", "theme", ...["preferences", "contextGraphHeight", "contextTagsHeight"].filter(key => Object.hasOwn(value, key))])) return null;
255
+ if (!record(value) || !exactKeys(value, ["version", "panes", "activePane", "split", "ratio", "treeVisible", "contextVisible", "treeWidth", "contextWidth", "theme", ...["preferences", "contextGraphHeight", "contextTagsHeight", "contextPinned"].filter(key => Object.hasOwn(value, key))])) return null;
250
256
  if (value["version"] !== 1 || !Array.isArray(value["panes"]) || value["panes"].length < 1 || value["panes"].length > 2 || !boundedId(value["activePane"], "pane")) return null;
251
257
  if (value["split"] !== "right" && value["split"] !== "down") return null;
252
258
  if (typeof value["ratio"] !== "number" || !Number.isFinite(value["ratio"]) || value["ratio"] < 0.1 || value["ratio"] > 0.9) return null;
253
259
  if (typeof value["treeVisible"] !== "boolean" || typeof value["contextVisible"] !== "boolean") return null;
260
+ const contextPinned = Object.hasOwn(value, "contextPinned") ? value["contextPinned"] : false;
261
+ if (typeof contextPinned !== "boolean") return null;
254
262
  if (typeof value["treeWidth"] !== "number" || !Number.isFinite(value["treeWidth"]) || value["treeWidth"] < 120 || value["treeWidth"] > 800) return null;
255
263
  if (typeof value["contextWidth"] !== "number" || !Number.isFinite(value["contextWidth"]) || value["contextWidth"] < 120 || value["contextWidth"] > 800) return null;
256
264
  const contextGraphHeight = Object.hasOwn(value, "contextGraphHeight") ? value["contextGraphHeight"] : 260;
@@ -292,7 +300,7 @@ export function parseWorkspaceLayout(value: unknown): WorkspaceLayout | null {
292
300
  panes.push({ id: rawPane["id"], tabs, activeTab: rawPane["activeTab"], ...(typeof lastDocumentTab === "string" ? { lastDocumentTab } : {}) });
293
301
  }
294
302
  if (count > MAX_TABS || graphs > 1 || !panes.some((pane) => pane.id === value["activePane"])) return null;
295
- return { version: 1, panes, activePane: value["activePane"], split: value["split"], ratio: value["ratio"], treeVisible: value["treeVisible"], contextVisible: value["contextVisible"], treeWidth: value["treeWidth"], contextWidth: value["contextWidth"], contextGraphHeight, contextTagsHeight, theme: value["theme"], preferences };
303
+ return { version: 1, panes, activePane: value["activePane"], split: value["split"], ratio: value["ratio"], treeVisible: value["treeVisible"], contextVisible: value["contextVisible"], contextPinned, treeWidth: value["treeWidth"], contextWidth: value["contextWidth"], contextGraphHeight, contextTagsHeight, theme: value["theme"], preferences };
296
304
  }
297
305
 
298
306
  /** Startup choice resets navigation only; appearance and sidebar preferences survive. */