@zq-silk/yui 2.15.0 → 2.16.0

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.
Files changed (53) hide show
  1. package/dist/web/assets/client/app/catalog.js +40 -14
  2. package/dist/web/assets/client/app/main.js +33 -9
  3. package/dist/web/assets/client/app/manage.js +18 -0
  4. package/dist/web/assets/client/app/selection.js +4 -1
  5. package/dist/web/assets/client/app/taskView.js +22 -5
  6. package/dist/web/assets/client/i18n/en.js +10 -3
  7. package/dist/web/assets/client/i18n/zh-CN.js +10 -3
  8. package/dist/web/assets/client/index.js +4 -0
  9. package/dist/web/assets/client/layout/manageShell.js +30 -8
  10. package/dist/web/assets/client/layout/shortcuts.js +7 -3
  11. package/dist/web/assets/client/layout/sidebarNav.js +147 -0
  12. package/dist/web/assets/client/layout/sizing.js +5 -2
  13. package/dist/web/assets/client/layout/workspace.js +120 -21
  14. package/dist/web/assets/client/lib/motion.js +59 -0
  15. package/dist/web/assets/client/lib/prefs.js +29 -2
  16. package/dist/web/assets/client/lib/theme.js +11 -4
  17. package/dist/web/assets/client/ui/primitives.js +27 -0
  18. package/dist/web/assets/client/views/overview.js +8 -5
  19. package/dist/web/assets/client/views/task/page.js +10 -10
  20. package/dist/web/assets/shared/brand.js +22 -0
  21. package/dist/web/assets/shared/geometry.js +7 -1
  22. package/dist/web/assets/shared/icons.js +4 -0
  23. package/dist/web/assets/shared/motion.js +74 -0
  24. package/dist/web/assets/shell/appRail.js +14 -0
  25. package/dist/web/assets/shell/dialogs.js +1 -0
  26. package/dist/web/assets/shell/dock.js +19 -6
  27. package/dist/web/assets/shell/index.js +6 -2
  28. package/dist/web/assets/shell/login.js +9 -8
  29. package/dist/web/assets/shell/manage.js +32 -20
  30. package/dist/web/assets/shell/settingsContent.js +1 -1
  31. package/dist/web/assets/shell/sidebar.js +16 -23
  32. package/dist/web/assets/styles/base.js +1 -1
  33. package/dist/web/assets/styles/index.js +2 -0
  34. package/dist/web/assets/styles/layout/responsive.js +63 -19
  35. package/dist/web/assets/styles/layout/workspace.js +53 -16
  36. package/dist/web/assets/styles/motion.js +51 -0
  37. package/dist/web/assets/styles/tokens.js +5 -3
  38. package/dist/web/assets/styles/ui/controls.js +1 -1
  39. package/dist/web/assets/styles/ui/forms.js +1 -1
  40. package/dist/web/assets/styles/ui/surfaces.js +1 -2
  41. package/dist/web/assets/styles/views/conversation.js +1 -1
  42. package/dist/web/assets/styles/views/dock.js +22 -2
  43. package/dist/web/assets/styles/views/login.js +16 -13
  44. package/dist/web/assets/styles/views/manage.js +25 -42
  45. package/dist/web/assets/styles/views/page.js +2 -3
  46. package/dist/web/assets/styles/views/records.js +1 -1
  47. package/dist/web/assets/styles/views/settings.js +1 -1
  48. package/dist/web/assets/styles/views/sidebar.js +25 -20
  49. package/dist/web/assets/styles/views/task.js +9 -15
  50. package/dist/web/assets/styles/views/terminal.js +1 -1
  51. package/docs/release-workflow.md +22 -0
  52. package/docs/release-workflow.zh-CN.md +15 -0
  53. package/package.json +1 -1
@@ -1,38 +1,83 @@
1
- import { BREAKPOINTS, SIDEBAR } from "../../shared/geometry.js";
1
+ import { BREAKPOINTS, DOCK_FOCUS_MAX, SIDEBAR } from "../../shared/geometry.js";
2
2
  /*
3
3
  * RESPONSIVE — breakpoints only, from shared/geometry.ts.
4
4
  * ≤ wide compact sidebar default and a three-column metric strip
5
- * ≤ narrow master–detail: task list OR task page; the dock becomes a
6
- * full-screen sheet over the task page
5
+ * ≤ focus an open dock moves the task list out of the grid so the task
6
+ * column keeps its minimum width; it opens as a drawer instead
7
+ * ≤ narrow the workspace takes the screen; the rail and the list open
8
+ * together as one drawer, and the dock becomes a full-screen sheet
7
9
  * ≤ small phone layout for page content
8
- * Sidebar container queries adapt its footer to the width the user chose.
10
+ *
11
+ * Motion follows the native sheet pattern (Vaul, Radix Sheet, iOS): drawers
12
+ * and sheets stay rendered off screen and move only by transform, so opening
13
+ * and closing both animate on the compositor; the scrim only fades. A drag
14
+ * (layout/sidebarNav) moves the panels directly and the release continues
15
+ * from where the finger left them.
9
16
  */
10
17
  export const RESPONSIVE_STYLES = `
11
- @container sidebar (max-width:299px){
12
- .foot-btn kbd{display:none}
13
- }
14
- @container sidebar (max-width:259px){
15
- .foot-btn{gap:0;padding:0 9px}
16
- .foot-btn span{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
17
- }
18
18
  @media(max-width:${BREAKPOINTS.wide}px){
19
19
  :root{--sidebar-w:${SIDEBAR.compact}px}
20
20
  .metric-strip{grid-template-columns:repeat(3,minmax(0,1fr))}
21
21
  }
22
+ @media(min-width:${BREAKPOINTS.narrow + 1}px) and (max-width:${DOCK_FOCUS_MAX}px){
23
+ body.dock-open .app{grid-template-areas:"rail center divider dock";grid-template-columns:var(--rail-w) minmax(0,1fr) var(--divider-w) var(--dock-w)}
24
+ body.dock-open.dock-center .app{grid-template-areas:"rail dock divider center";grid-template-columns:var(--rail-w) var(--dock-w) var(--divider-w) minmax(0,1fr)}
25
+ body.dock-open .sidebar-divider{display:none}
26
+ body.dock-open .side-expand{display:inline-grid}
27
+ /* The list slides out from under the rail. */
28
+ body.dock-open .app-rail{position:relative;z-index:var(--z-rail-over)}
29
+ body.dock-open.sidebar-collapsed .app .sidebar{display:flex}
30
+ body.dock-open .app .sidebar{--drawer-w:min(340px,calc(100vw - var(--rail-w) - 24px));display:flex;position:fixed;top:0;bottom:0;left:var(--rail-w);z-index:var(--z-drawer);width:var(--drawer-w);border-right:1px solid var(--line-2);box-shadow:var(--shadow-2);transform:translate3d(calc(-100% - 32px),0,0);visibility:hidden;transition:transform var(--t-sheet-out) var(--ease-sheet),visibility 0s linear var(--t-sheet-out)}
31
+ }
22
32
  @media(max-width:${BREAKPOINTS.narrow}px){
33
+ :root{--drawer-w:min(320px,calc(100vw - var(--rail-w) - 48px));--drawer-off:calc(-1 * (var(--rail-w) + var(--drawer-w)) - 32px)}
23
34
  .app,body.dock-open .app,body.dock-open.dock-center .app{grid-template-areas:"main";grid-template-columns:minmax(0,1fr)}
24
- .sidebar{grid-area:main;border-right:0}
25
- .center{grid-area:main;display:none}
26
- body.task-open .sidebar{display:none}
27
- body.task-open .center{display:block}
28
- .back-btn{display:inline-grid}
29
- .crumbs .crumb,.crumbs .crumb-sep{display:none}
35
+ .center{grid-area:main}
36
+ /* One drawer: the rail and the list, side by side, moving together. */
37
+ .app .app-rail,.app .sidebar{display:flex;position:fixed;top:0;bottom:0;z-index:var(--z-drawer);padding-top:env(safe-area-inset-top,0px);transform:translate3d(var(--drawer-off),0,0);visibility:hidden;transition:transform var(--t-sheet-out) var(--ease-sheet),visibility 0s linear var(--t-sheet-out);touch-action:pan-y}
38
+ body.sidebar-collapsed .app .sidebar{display:flex}
39
+ .app .app-rail{left:0;width:var(--rail-w);padding-top:calc(10px + env(safe-area-inset-top,0px))}
40
+ .app .sidebar{left:var(--rail-w);width:var(--drawer-w);border-right:1px solid var(--line-2);border-radius:0 var(--r-lg) var(--r-lg) 0;box-shadow:var(--shadow-2)}
41
+ .icon-btn.side-expand{display:inline-grid}
42
+ .side-expand .i-sidebar{display:none}
43
+ .side-expand .i-menu{display:contents}
44
+ /* Top bar: the current place is the title. */
45
+ .top-bar{padding:0 12px 0 8px}
46
+ .crumbs>span.crumb,.crumbs>span.crumb+.crumb-sep{display:none}
47
+ .crumbs span.crumb-current{font-size:var(--fs-lg)}
30
48
  .dock-divider,.sidebar-divider{display:none}
31
- .dock{position:fixed;inset:0;z-index:60;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}
49
+ .dock{position:fixed;inset:0;z-index:var(--z-sheet);padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px);animation:m-sheet-up var(--t-sheet) var(--ease-sheet)}
32
50
  #dock-swap{display:none}
33
51
  .dock-toggle span{display:none}
34
52
  .dock-toggle{width:32px;padding:0}
35
53
  }
54
+ /* Open drawer (sidebarNav sets body.sidebar-drawer only where the list
55
+ cannot sit inline). Opening eases in a little slower than closing. */
56
+ body.sidebar-drawer .app .sidebar,body.sidebar-drawer .app .app-rail{transform:translate3d(0,0,0);visibility:visible;transition:transform var(--t-sheet) var(--ease-sheet),visibility 0s}
57
+ body.sidebar-drawer .app .sidebar-divider{display:none}
58
+ .sidebar-scrim{position:fixed;inset:0;z-index:var(--z-scrim);background:rgb(12 10 8 / .4);opacity:0;visibility:hidden;pointer-events:none;transition:opacity var(--t-sheet-out) var(--ease-sheet),visibility 0s linear var(--t-sheet-out)}
59
+ body.sidebar-drawer .sidebar-scrim{opacity:1;visibility:visible;pointer-events:auto;transition:opacity var(--t-sheet) var(--ease-sheet),visibility 0s}
60
+ /* While a finger drags the drawer, it follows directly. */
61
+ body.drawer-dragging .app .sidebar,body.drawer-dragging .app .app-rail,body.drawer-dragging .sidebar-scrim{transition:none}
62
+ @media(prefers-reduced-motion:reduce){
63
+ .app .sidebar,.app .app-rail,.sidebar-scrim,body.sidebar-drawer .app .sidebar,body.sidebar-drawer .app .app-rail,body.sidebar-drawer .sidebar-scrim{transition:none}
64
+ .dock{animation:none}
65
+ }
66
+ /* Touch screens: controls reach a comfortable tap size without changing the
67
+ desktop density. */
68
+ @media(pointer:coarse){
69
+ .btn,.icon-btn,.dock-toggle{min-height:38px}
70
+ .icon-btn{min-width:38px}
71
+ .dock-toggle{min-width:38px}
72
+ .seg-btn,.seg-sm .seg-btn{height:36px}
73
+ .cv-pill{height:36px}
74
+ .cv-link{min-height:32px}
75
+ .chip-tab{height:34px}
76
+ .btn-link{min-height:32px;padding-top:6px;padding-bottom:6px}
77
+ .cv-activity>summary{min-height:32px}
78
+ .cv-sub>summary{padding:8px 0}
79
+ .task-row{min-height:48px}
80
+ }
36
81
  @media(max-width:${BREAKPOINTS.small}px){
37
82
  .metric-strip{grid-template-columns:repeat(2,minmax(0,1fr))}
38
83
  .page-head{padding-top:24px;flex-wrap:wrap}
@@ -46,7 +91,6 @@ export const RESPONSIVE_STYLES = `
46
91
  .now-card>.card-body{padding:14px 14px 14px 17px}
47
92
  .kv{grid-template-columns:minmax(0,1fr)}
48
93
  .kv dt{margin-top:4px}
49
- .foot-btn kbd{display:none}
50
94
  .lazy-meta{display:none}
51
95
  .lazy-body{padding-left:16px}
52
96
  }
@@ -1,18 +1,58 @@
1
+ import { RAIL_WIDTH } from "../../shared/geometry.js";
1
2
  /*
2
- * WORKSPACE — the three-region application frame.
3
- * sidebar | center (task details) | divider | dock (session)
4
- * body.dock-open shows the dock; body.dock-center swaps the dock into the
5
- * middle so the order becomes sidebar | dock | divider | center. The sidebar's
6
- * own divider overlays its right edge, so it adds no grid column; --sidebar-w
7
- * is the default width and a stored preference overrides it inline. Region
3
+ * WORKSPACE — the application frame.
4
+ * rail | sidebar | center (task details) | divider | dock (session)
5
+ * The rail is the global Workbench / Models / Settings navigation, shared with
6
+ * the management pages. body.dock-open shows the dock; body.dock-center swaps
7
+ * the dock into the middle so the order becomes rail | sidebar | dock |
8
+ * divider | center. body.sidebar-collapsed folds the task list away (the page
9
+ * header then offers .side-expand to bring it back). The sidebar's own
10
+ * divider overlays its right edge, so it adds no grid column; --sidebar-w is
11
+ * the default width and a stored preference overrides it inline. Region
8
12
  * contents are styled by the view stylesheets.
9
13
  */
10
14
  export const WORKSPACE_STYLES = `
15
+ :root{--rail-w:${RAIL_WIDTH}px}
11
16
  .app{display:grid;height:100vh;height:100dvh;grid-template-rows:minmax(0,1fr);
12
- grid-template-areas:"sidebar center divider dock";
13
- grid-template-columns:var(--sidebar-w) minmax(0,1fr) 0 0}
14
- body.dock-open .app{grid-template-columns:var(--sidebar-w) minmax(0,1fr) var(--divider-w) var(--dock-w)}
15
- body.dock-open.dock-center .app{grid-template-areas:"sidebar dock divider center";grid-template-columns:var(--sidebar-w) var(--dock-w) var(--divider-w) minmax(0,1fr)}
17
+ grid-template-areas:"rail sidebar center divider dock";
18
+ grid-template-columns:var(--rail-w) var(--sidebar-w) minmax(0,1fr) 0 0}
19
+ body.dock-open .app{grid-template-columns:var(--rail-w) var(--sidebar-w) minmax(0,1fr) var(--divider-w) var(--dock-w)}
20
+ body.dock-open.dock-center .app{grid-template-areas:"rail sidebar dock divider center";grid-template-columns:var(--rail-w) var(--sidebar-w) var(--dock-w) var(--divider-w) minmax(0,1fr)}
21
+ body.sidebar-collapsed{--sidebar-w:0px}
22
+ body.sidebar-collapsed:not(.sidebar-drawer) .sidebar,body.sidebar-collapsed .sidebar-divider{display:none}
23
+
24
+ /* Global rail: brand, then the three areas as icon-over-label tiles. */
25
+ .app-rail{grid-area:rail;display:flex;flex-direction:column;align-items:center;gap:6px;min-height:0;padding:10px 0 12px;background:var(--surface);border-right:1px solid var(--line);overflow-y:auto}
26
+ .rail-brand{display:grid;place-items:center;width:40px;height:40px;margin-bottom:6px;border-radius:var(--r-md);text-decoration:none}
27
+ .rail-brand .brand-mark{display:grid;place-items:center}
28
+ .rail-brand:hover .brand-mark{box-shadow:0 0 0 3px var(--accent-soft)}
29
+ .rail-items{display:flex;flex-direction:column;align-items:center;gap:4px}
30
+ .rail-item{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;width:48px;min-height:50px;padding:6px 2px;border-radius:var(--r-md);color:var(--ink-3);font-size:10.5px;font-weight:550;line-height:1.15;text-align:center;text-decoration:none;transition:background var(--t-fast),color var(--t-fast),transform var(--t-fast) var(--ease)}
31
+ .rail-item .icon{width:18px;height:18px;flex:none}
32
+ .rail-item span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
33
+ .rail-item:hover{background:var(--surface-3);color:var(--ink)}
34
+ .rail-item[aria-current="page"]{background:var(--accent-soft);color:var(--accent)}
35
+
36
+ /* Task-list switch in the page header: only while the list is out of view. */
37
+ .icon-btn.side-expand{display:none}
38
+ .side-expand .i-menu{display:none}
39
+ .side-expand>span{display:contents}
40
+ body.sidebar-collapsed .side-expand{display:inline-grid}
41
+ .side-title{flex:1;min-width:0;font-size:var(--fs-md);font-weight:650;letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
42
+ .sidebar-scrim[hidden]{display:none}
43
+
44
+ /* Top bar: the first row of the center column on every page. Its height and
45
+ rule line up with the task-list head and the dock head, so the frame reads
46
+ as one header row: list switch, location, then the page's actions. */
47
+ .top-bar{position:sticky;top:0;z-index:var(--z-sticky);display:flex;align-items:center;gap:6px;height:var(--header-h);padding:0 16px 0 12px;border-bottom:1px solid var(--line);background:var(--canvas)}
48
+ .top-title{min-width:0;overflow:hidden;color:var(--ink);font-size:var(--fs-md);font-weight:600;text-overflow:ellipsis;white-space:nowrap}
49
+ .crumbs{display:flex;align-items:center;gap:4px;min-width:0;font-size:var(--fs-sm);white-space:nowrap}
50
+ .crumb,.crumb-sep{flex:none}
51
+ .crumb{padding:3px 6px;border:0;border-radius:var(--r-xs);background:transparent;color:var(--ink-3);font-size:var(--fs-sm)}
52
+ button.crumb:hover{color:var(--ink);background:var(--surface-3)}
53
+ .crumb-sep{color:var(--ink-4)}
54
+ .crumb-current{min-width:0;overflow:hidden;padding:3px 6px;color:var(--ink);font-weight:600;text-overflow:ellipsis}
55
+ code.crumb-current{font-weight:500;font-size:var(--fs-xs);color:var(--ink-2)}
16
56
 
17
57
  /* Resize dividers: a wide invisible hit area around a 1px rule that lights up
18
58
  on hover, focus and while dragging. */
@@ -25,16 +65,13 @@ body.sidebar-resizing,body.dock-resizing{cursor:col-resize;user-select:none}
25
65
 
26
66
  /* Sidebar */
27
67
  .sidebar{grid-area:sidebar;display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--surface);border-right:1px solid var(--line);container:sidebar/inline-size}
28
- .sidebar-divider{grid-area:sidebar;justify-self:end;z-index:20;width:var(--divider-w);margin-right:-5px}
68
+ .sidebar-divider{grid-area:sidebar;justify-self:end;z-index:var(--z-header);width:var(--divider-w);margin-right:-5px}
29
69
  .sidebar-divider span{left:3px;background:transparent}
30
70
  .side-head{flex:none;display:flex;align-items:center;gap:10px;height:var(--header-h);padding:0 12px 0 16px;border-bottom:1px solid var(--line)}
31
- .brand{display:flex;align-items:center;gap:10px;flex:1;min-width:0}
32
- .attention-bar{flex:none;margin:10px 12px 0}
33
- .status-tabs{flex:none;margin:10px 0 0;padding:0 12px}
71
+ .status-tabs{flex:none;margin:4px 0 0;padding:0 12px}
34
72
  .task-list{flex:1;min-height:0;overflow-y:auto;padding:4px 8px 12px;scrollbar-gutter:stable}
35
73
  .pager{flex:none;display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:6px;padding:8px 12px;border-top:1px solid var(--line)}
36
74
  .pager .pager-clear{grid-column:1/-1}
37
- .side-foot{flex:none;display:flex;align-items:center;gap:4px;padding:10px;border-top:1px solid var(--line)}
38
75
 
39
76
  /* Center */
40
77
  .center{grid-area:center;min-width:0;min-height:0;overflow-y:auto;scrollbar-gutter:stable;background:var(--canvas)}
@@ -42,7 +79,7 @@ body.sidebar-resizing,body.dock-resizing{cursor:col-resize;user-select:none}
42
79
  .detail{min-height:100%}
43
80
 
44
81
  /* Dock */
45
- .dock-divider{grid-area:divider;background:var(--canvas);z-index:5}
82
+ .dock-divider{grid-area:divider;background:var(--canvas);z-index:var(--z-raised)}
46
83
  .dock-divider span{left:4px;background:var(--line-2)}
47
84
  .dock{grid-area:dock;display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--surface)}
48
85
  body.dock-open:not(.dock-center) .dock{border-left:0}
@@ -0,0 +1,51 @@
1
+ import { BREAKPOINTS } from "../shared/geometry.js";
2
+ import { motionKeyframes } from "../shared/motion.js";
3
+ /*
4
+ * MOTION — the shared animation library. Timings, curves and layers are the
5
+ * tokens generated from shared/motion.ts; this sheet holds the keyframes and
6
+ * the component motion that is the same everywhere:
7
+ * dialogs scale + fade in, quicker fade out; the backdrop fades
8
+ * (@starting-style + allow-discrete, as Radix Dialog does)
9
+ * popovers <details> menus pop in from their anchor
10
+ * press buttons settle slightly under the pointer
11
+ * pages cross-document View Transitions between Workbench, Models
12
+ * and Settings; the rail stays put
13
+ * layout same-document View Transitions for column changes (the
14
+ * client wraps sidebar collapse and dock open/close)
15
+ * Everything honours prefers-reduced-motion (base.ts turns it all off).
16
+ */
17
+ export const MOTION_STYLES = `
18
+ ${motionKeyframes()}
19
+ .dialog{opacity:0;transform:scale(.96);transition:opacity var(--t-exit) var(--ease-exit),transform var(--t-exit) var(--ease-exit),overlay var(--t-exit) allow-discrete,display var(--t-exit) allow-discrete}
20
+ .dialog[open]{opacity:1;transform:none;transition-duration:var(--t-base);transition-timing-function:var(--ease-standard)}
21
+ .dialog::backdrop{opacity:0;transition:opacity var(--t-exit) var(--ease-exit),overlay var(--t-exit) allow-discrete,display var(--t-exit) allow-discrete}
22
+ .dialog[open]::backdrop{opacity:1;transition-duration:var(--t-base)}
23
+ @starting-style{.dialog[open]{opacity:0;transform:scale(.96)}.dialog[open]::backdrop{opacity:0}}
24
+ details[open]>.cv-popbody,details[open]>.dock-target-menu{animation:m-pop var(--t-base) var(--ease-standard)}
25
+ .cv-attach>.cv-popbody,.cv-model>.cv-popbody{transform-origin:bottom left}
26
+ .cv-model>.cv-popbody{transform-origin:bottom right}
27
+ .cv-menu>.cv-popbody{transform-origin:top right}
28
+ .dock-target-menu{transform-origin:top left}
29
+ .icon-btn:active:not(:disabled),.rail-item:active{transform:scale(.94)}
30
+ /* Workbench ⇄ Models ⇄ Settings are separate documents: the browser
31
+ cross-fades them (no blank frame) and the rail stays put between them. */
32
+ @view-transition{navigation:auto}
33
+ ::view-transition-old(root),::view-transition-new(root){animation-duration:var(--t-page);animation-timing-function:var(--ease-sheet)}
34
+ @media(prefers-reduced-motion:reduce){::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation:none!important}}
35
+ /* Page content entering after an explicit navigation (client/lib/motion). */
36
+ .m-enter{animation:m-rise var(--t-base) var(--ease-standard)}
37
+ @media(min-width:${BREAKPOINTS.narrow + 1}px){
38
+ .app-rail{view-transition-name:app-rail}
39
+ /* Column changes: client/lib/motion sets .vt-layout for the transition
40
+ only. Each column glides between its old and new box showing its new
41
+ content (no double image); a column that appears or leaves fades. */
42
+ .vt-layout .sidebar{view-transition-name:sidebar}
43
+ .vt-layout .center{view-transition-name:center}
44
+ .vt-layout .dock{view-transition-name:dock}
45
+ ::view-transition-group(sidebar),::view-transition-group(center),::view-transition-group(dock){animation-duration:var(--t-layout);animation-timing-function:var(--ease-sheet);overflow:clip}
46
+ ::view-transition-old(sidebar),::view-transition-new(sidebar),::view-transition-old(center),::view-transition-new(center),::view-transition-old(dock),::view-transition-new(dock){width:100%;height:100%;object-fit:none;object-position:0 0;animation:none}
47
+ ::view-transition-old(sidebar),::view-transition-old(center),::view-transition-old(dock){opacity:0}
48
+ ::view-transition-old(sidebar):only-child,::view-transition-old(dock):only-child{opacity:1;animation:m-fade var(--t-exit) var(--ease-exit) reverse both}
49
+ ::view-transition-new(sidebar):only-child,::view-transition-new(dock):only-child{animation:m-fade var(--t-layout) var(--ease-standard) both}
50
+ }
51
+ `;
@@ -1,4 +1,5 @@
1
1
  import { DIVIDER_WIDTH, DOCK } from "../shared/geometry.js";
2
+ import { motionTokenStyles } from "../shared/motion.js";
2
3
  import { themeTokenStyles } from "../shared/themes.js";
3
4
  /*
4
5
  * DESIGN TOKENS
@@ -6,8 +7,9 @@ import { themeTokenStyles } from "../shared/themes.js";
6
7
  * Geometry, type, radii, motion and the focus ring are theme-independent and
7
8
  * live once on :root. Colour and effect tokens come from the theme registry
8
9
  * (shared/themes.ts), one block per theme, so switching a theme can never move
9
- * or resize anything. Layout widths come from shared/geometry.ts, the same
10
- * source the client layout controller clamps against.
10
+ * or resize anything. Layout widths come from shared/geometry.ts and motion
11
+ * (durations, easings, stacking layers) from shared/motion.ts, the same
12
+ * sources the client scripts read.
11
13
  */
12
14
  export const TOKEN_STYLES = `
13
15
  :root{
@@ -17,7 +19,7 @@ export const TOKEN_STYLES = `
17
19
  --r-xs:5px;--r-sm:7px;--r-md:10px;--r-lg:14px;--r-pill:999px;
18
20
  --sidebar-w:clamp(260px,21vw,312px);--dock-w:${DOCK.initial}px;--divider-w:${DIVIDER_WIDTH}px;
19
21
  --center-max:880px;--header-h:56px;--gutter:clamp(16px,3vw,40px);
20
- --t-fast:120ms;--t-med:220ms;--ease:cubic-bezier(.2,.8,.2,1);
22
+ ${motionTokenStyles()}
21
23
  --focus:0 0 0 2px var(--canvas),0 0 0 4px var(--accent-line);
22
24
  }
23
25
  ${themeTokenStyles()}
@@ -27,7 +27,7 @@ export const CONTROL_STYLES = `
27
27
  .btn-link:hover:not(:disabled){background:transparent;text-decoration:underline;text-underline-offset:3px}
28
28
  .link-btn{justify-self:start;padding:0;border:0;background:none;color:var(--accent);font-size:var(--fs-xs);font-weight:500}
29
29
  .link-btn:hover{text-decoration:underline;text-underline-offset:3px}
30
- .icon-btn{display:inline-grid;place-items:center;width:32px;height:32px;flex:none;padding:0;border:0;border-radius:var(--r-sm);background:transparent;color:var(--ink-3);transition:background var(--t-fast),color var(--t-fast)}
30
+ .icon-btn{display:inline-grid;place-items:center;width:32px;height:32px;flex:none;padding:0;border:0;border-radius:var(--r-sm);background:transparent;color:var(--ink-3);transition:background var(--t-fast),color var(--t-fast),transform var(--t-fast) var(--ease)}
31
31
  .icon-btn:hover:not(:disabled){background:var(--surface-3);color:var(--ink)}
32
32
  .icon-btn[aria-pressed="true"]{background:var(--accent-soft);color:var(--accent)}
33
33
  .icon-btn:disabled{opacity:.4}
@@ -41,6 +41,6 @@ export const FORM_STYLES = `
41
41
  .shortcut-list dd{margin:0}
42
42
 
43
43
  /* Toast */
44
- .toast{position:fixed;left:50%;bottom:24px;z-index:90;max-width:min(520px,calc(100vw - 32px));padding:10px 16px;border:1px solid var(--line-2);border-radius:var(--r-md);background:var(--surface-2);color:var(--ink);box-shadow:var(--shadow-2);font-size:var(--fs-sm);opacity:0;transform:translate(-50%,8px);pointer-events:none;transition:opacity var(--t-med),transform var(--t-med) var(--ease)}
44
+ .toast{position:fixed;left:50%;bottom:24px;z-index:var(--z-toast);max-width:min(520px,calc(100vw - 32px));padding:10px 16px;border:1px solid var(--line-2);border-radius:var(--r-md);background:var(--surface-2);color:var(--ink);box-shadow:var(--shadow-2);font-size:var(--fs-sm);opacity:0;transform:translate(-50%,8px);pointer-events:none;transition:opacity var(--t-base) var(--ease),transform var(--t-base) var(--ease)}
45
45
  .toast.show{opacity:1;transform:translate(-50%,0)}
46
46
  `;
@@ -108,8 +108,7 @@ details[open]>summary .disclosure-chevron{transform:rotate(90deg)}
108
108
  .show-more:hover,.pager-clear:hover{color:var(--accent);border-color:var(--accent-line)}
109
109
  .show-more{justify-self:start;display:inline-flex;align-items:center;height:30px;padding:0 12px;font-weight:500}
110
110
  .loading-block{display:flex;align-items:center;gap:10px;padding:32px 8px;color:var(--ink-3)}
111
- .spinner{width:14px;height:14px;border-radius:50%;border:2px solid var(--line-3);border-top-color:var(--accent);animation:spin .8s linear infinite}
112
- @keyframes spin{to{transform:rotate(360deg)}}
111
+ .spinner{width:14px;height:14px;border-radius:50%;border:2px solid var(--line-3);border-top-color:var(--accent);animation:m-spin .8s linear infinite}
113
112
 
114
113
  /* Metrics */
115
114
  .metric{display:grid;gap:4px;align-content:start;min-width:0;padding:12px 14px;border:1px solid var(--line);border-radius:var(--r-md);background:var(--surface)}
@@ -98,7 +98,7 @@ export const CONVERSATION_STYLES = `
98
98
  .cv-pop{position:relative;flex:none}
99
99
  .cv-pop>summary{list-style:none}
100
100
  .cv-pop>summary::-webkit-details-marker{display:none}
101
- .cv-popbody{position:absolute;z-index:20;display:grid;gap:8px;width:min(300px,calc(100vw - 32px));max-height:min(420px,60vh);overflow:auto;padding:10px;border:1px solid var(--line-2);border-radius:var(--r-lg);background:var(--surface-2);box-shadow:var(--shadow-2);box-sizing:border-box}
101
+ .cv-popbody{position:absolute;z-index:var(--z-popover);display:grid;gap:8px;width:min(300px,calc(100vw - 32px));max-height:min(420px,60vh);overflow:auto;padding:10px;border:1px solid var(--line-2);border-radius:var(--r-lg);background:var(--surface-2);box-shadow:var(--shadow-2);box-sizing:border-box}
102
102
  .cv-attach>.cv-popbody{left:0;bottom:calc(100% + 8px)}
103
103
  .cv-model>.cv-popbody{right:0;bottom:calc(100% + 8px)}
104
104
  .cv-menu>.cv-popbody{right:0;top:calc(100% + 6px)}
@@ -4,9 +4,29 @@
4
4
  * The Live session pane is views/terminal; the dock frame is layout/workspace.
5
5
  */
6
6
  export const DOCK_STYLES = `
7
- .dock-head{height:auto;min-height:var(--header-h);padding-top:6px;padding-bottom:6px}
8
- .dock-head .seg{min-width:0;flex-wrap:wrap}
7
+ .dock-head{height:auto;min-height:var(--header-h);padding-top:6px;padding-bottom:6px;border-bottom:0}
9
8
  .dock-actions{flex-shrink:0}
9
+ /* Who the panel talks to: a title-like menu button with its target list */
10
+ .dock-target{position:relative;min-width:0}
11
+ .dock-target-btn{display:flex;align-items:center;gap:8px;min-width:0;height:34px;padding:0 10px 0 6px;border-radius:var(--r-md);color:var(--ink);font-size:var(--fs-md);font-weight:600;cursor:pointer;list-style:none;transition:background var(--t-fast)}
12
+ .dock-target-btn::-webkit-details-marker{display:none}
13
+ .dock-target-btn:hover,.dock-target[open] .dock-target-btn{background:var(--surface-3)}
14
+ .dock-target-btn>.icon{width:14px;height:14px;flex:none;color:var(--ink-4)}
15
+ .dock-target-icon{display:inline-grid;place-items:center;width:24px;height:24px;flex:none;border-radius:var(--r-sm);background:var(--accent-soft);color:var(--accent)}
16
+ .dock-target-icon .icon{width:14px;height:14px}
17
+ .dock-target-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
18
+ .dock-target-menu{position:absolute;left:0;top:calc(100% + 4px);z-index:var(--z-popover);display:grid;gap:2px;min-width:220px;max-width:min(320px,80vw);padding:6px;border:1px solid var(--line-2);border-radius:var(--r-md);background:var(--surface-2);box-shadow:var(--shadow-2)}
19
+ .dock-target-menu hr{margin:4px 2px;border:0;border-top:1px solid var(--line)}
20
+ .dock-target-options{display:grid;gap:2px}
21
+ .dock-target-item{display:flex;align-items:center;gap:8px;width:100%;min-width:0;height:32px;padding:0 8px;border:0;border-radius:var(--r-sm);background:transparent;color:var(--ink-2);font-size:var(--fs-sm);text-align:left}
22
+ .dock-target-item span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
23
+ .dock-target-item .icon{width:15px;height:15px;flex:none;color:var(--ink-4)}
24
+ .dock-target-item:hover{background:var(--surface-3);color:var(--ink)}
25
+ .dock-target-item[aria-pressed="true"]{color:var(--ink);font-weight:550}
26
+ .dock-target-item .dock-target-check{color:var(--accent)}
27
+ .dock-tabs{flex:none;padding:0 12px 10px;border-bottom:1px solid var(--line)}
28
+ .dock-tabs .seg{display:flex;flex-wrap:wrap;width:100%;min-width:0}
29
+ .dock-tabs .seg-btn{flex:1 1 auto;justify-content:center}
10
30
  .dock-preview{display:flex;flex-direction:column;min-height:0;overflow:auto}
11
31
  .dock-preview>.feed-note{text-align:left;padding:0 12px;color:var(--ink-3)}
12
32
  .preview-services{flex:none;max-height:40%;overflow:auto}
@@ -1,17 +1,21 @@
1
1
  /*
2
- * LOGIN VIEW — the standalone sign-in document: one centred card on the
3
- * canvas with the workbench brand, a password field (with reveal toggle),
4
- * inline error/notice states and the plain-HTTP reminder. Colour comes only
5
- * from theme tokens; the card collapses to the full width on narrow screens.
2
+ * LOGIN VIEW — the standalone sign-in document: one card centred on the
3
+ * canvas at every size, headed by the brand and the language control, with a
4
+ * password field (with reveal toggle), inline error/notice states and the
5
+ * plain-HTTP reminder. Colour comes only from theme tokens; on phones the
6
+ * card drops its frame and uses the full width.
6
7
  */
7
8
  export const LOGIN_STYLES = `
8
9
  .login-body{height:auto;min-height:100vh;min-height:100dvh;overflow:auto}
9
- .login-shell{position:relative;display:grid;place-items:center;min-height:100vh;min-height:100dvh;padding:72px 16px 48px;background:radial-gradient(120% 70% at 50% -10%,var(--accent-soft),transparent 60%),var(--canvas)}
10
- .login-top{position:absolute;top:16px;right:16px}
11
- .login-locale select{height:30px;width:auto;max-width:132px;padding:0 26px 0 9px;line-height:28px;font-size:var(--fs-xs);background-color:var(--surface)}
12
- .login-card{display:grid;gap:20px;width:min(400px,100%);padding:32px 28px 28px;border:1px solid var(--line-2);border-radius:var(--r-lg);background:var(--surface);box-shadow:var(--shadow-2)}
10
+ .login-shell{display:grid;place-items:center;min-height:100vh;min-height:100dvh;padding:max(24px,env(safe-area-inset-top,0px)) 16px max(24px,env(safe-area-inset-bottom,0px));background:radial-gradient(120% 70% at 50% -10%,var(--accent-soft),transparent 60%),var(--canvas)}
11
+ .login-top{display:flex;align-items:center;justify-content:space-between;gap:12px;min-width:0}
12
+ .login-locale{flex:none}
13
+ .login-locale select{height:30px;width:auto;max-width:132px;padding:0 26px 0 9px;line-height:28px;font-size:var(--fs-xs)}
14
+ .login-card{display:grid;gap:20px;width:min(400px,100%);margin-bottom:6vh;padding:28px;border:1px solid var(--line-2);border-radius:var(--r-lg);background:var(--surface);box-shadow:var(--shadow-2)}
13
15
  .login-brand{display:flex;align-items:center;gap:10px}
14
- .login-brand .brand-mark{display:grid;place-items:center;width:32px;height:32px;flex:none;border-radius:9px;background:var(--accent);color:var(--accent-ink);font-size:17px;font-weight:700;line-height:1}
16
+ .login-brand .brand-mark{display:block;width:32px;height:32px;flex:none;border-radius:8px;background:var(--ink);color:var(--canvas);overflow:hidden}
17
+ .brand-glyph{display:block;width:100%;height:100%}
18
+ .brand-dot{fill:var(--accent)}
15
19
  .login-brand .brand-name{font-size:var(--fs-lg);font-weight:650;letter-spacing:-.02em}
16
20
  .login-heading{display:grid;gap:6px}
17
21
  .login-heading h1{font-size:var(--fs-2xl)}
@@ -29,14 +33,13 @@ export const LOGIN_STYLES = `
29
33
  .login-reveal[aria-pressed="true"] .icon-hide{display:block}
30
34
  .login-error{margin:0;color:var(--bad);font-size:var(--fs-sm);overflow-wrap:anywhere}
31
35
  .login-submit{width:100%;height:40px;font-size:var(--fs-md)}
32
- .login-spinner{display:none;width:14px;height:14px;flex:none;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:login-spin .8s linear infinite}
36
+ .login-spinner{display:none;width:14px;height:14px;flex:none;border:2px solid currentColor;border-right-color:transparent;border-radius:50%;animation:m-spin .8s linear infinite}
33
37
  .login-form[aria-busy="true"] .login-spinner{display:inline-block}
34
- @keyframes login-spin{to{transform:rotate(360deg)}}
35
38
  .login-transport{display:flex;align-items:flex-start;gap:8px;margin:0;padding-top:16px;border-top:1px solid var(--line);color:var(--ink-3);font-size:var(--fs-xs)}
36
39
  .login-transport .icon{width:14px;height:14px;margin-top:2px;color:var(--warn)}
37
40
  @media(max-width:480px){
38
- .login-shell{place-items:start center;padding:64px 12px 32px}
39
- .login-card{padding:24px 20px;border-radius:var(--r-md)}
41
+ .login-shell{padding-left:0;padding-right:0;background:var(--surface)}
42
+ .login-card{width:100%;margin-bottom:0;padding:24px 20px;border:0;border-radius:0;box-shadow:none}
40
43
  .login-heading h1{font-size:var(--fs-xl)}
41
44
  }
42
45
  `;
@@ -1,40 +1,33 @@
1
1
  import { BREAKPOINTS } from "../../shared/geometry.js";
2
2
  /*
3
- * MANAGE VIEW — the frame shared by the management pages (/models and
4
- * /settings): a rail in the dashboard sidebar's language (brand, the fixed
5
- * Workbench / Models / Settings navigation with every section listed under
6
- * its area, the language control) beside one reading column whose sections
7
- * share a heading (area kicker, title, explanation). Page sheets add only
8
- * their own content. Below the narrow breakpoint the rail becomes a top bar:
9
- * brand and language, the three main destinations, then the current area's
10
- * sections, wrapping so every entry stays visible.
3
+ * MANAGE VIEW — what the management pages (/models and /settings) add to the
4
+ * workbench frame (layout/workspace): the section list in the sidebar slot,
5
+ * the language control in the top bar, and one reading column whose sections
6
+ * share a heading (title, explanation). The rail, the collapsible list, the
7
+ * top bar and the narrow-screen drawer are the workbench's own. Page sheets
8
+ * add only their own content.
11
9
  */
12
10
  export const MANAGE_STYLES = `
13
- .manage-body{display:block;height:auto;min-height:100vh;min-height:100dvh;overflow:auto}
14
- .manage-app{display:grid;grid-template-columns:240px minmax(0,1fr);min-height:100vh;min-height:100dvh}
15
11
  .manage-app[hidden],#models-root[hidden],#settings-root[hidden]{display:none}
12
+ .manage-body{--sidebar-w:240px}
13
+ body.manage-body.sidebar-collapsed{--sidebar-w:0px}
16
14
 
17
- /* Rail */
18
- .manage-rail{position:sticky;top:0;display:flex;flex-direction:column;height:100vh;height:100dvh;min-width:0;overflow-y:auto;background:var(--surface);border-right:1px solid var(--line)}
19
- .manage-rail-head{flex:none;display:flex;align-items:center;gap:10px;height:var(--header-h);padding:0 12px 0 16px;border-bottom:1px solid var(--line)}
20
- .manage-rail-head .brand{flex:1;color:var(--ink);text-decoration:none}
21
- .manage-locale{flex:none;min-width:0}
22
- .manage-locale select{height:30px;width:auto;max-width:124px;padding:0 26px 0 9px;line-height:28px;font-size:var(--fs-xs)}
23
- .manage-nav{display:flex;flex-direction:column;gap:6px;padding:12px 8px 20px;min-width:0}
24
- .manage-area{display:grid;gap:2px;min-width:0}
25
- .manage-primary,.manage-link{position:relative;display:flex;align-items:center;min-width:0;border-radius:var(--r-md);text-decoration:none;white-space:nowrap;transition:background var(--t-fast),color var(--t-fast)}
26
- .manage-primary span,.manage-link span{overflow:hidden;text-overflow:ellipsis}
27
- .manage-primary{gap:9px;height:34px;padding:0 10px;color:var(--ink-2);font-size:var(--fs-md);font-weight:550}
28
- .manage-primary .icon{width:16px;height:16px;flex:none;color:var(--ink-4)}
29
- .manage-primary:hover,.manage-link:hover{background:var(--surface-3);color:var(--ink)}
30
- .manage-primary[aria-current]{color:var(--ink)}
31
- .manage-primary[aria-current] .icon{color:var(--accent)}
32
- .manage-sections{display:grid;gap:1px;margin:0 0 4px 18px;padding-left:8px;border-left:1px solid var(--line);min-width:0}
33
- .manage-link{gap:8px;height:30px;padding:0 10px;color:var(--ink-3);font-size:var(--fs-sm);font-weight:500}
15
+ /* Section list: only the current area's sections (the rail switches areas). */
16
+ .manage-nav{flex:1;min-height:0;overflow-y:auto;padding:10px 8px 20px}
17
+ .manage-area:not([data-active="true"]){display:none}
18
+ .manage-sections{display:grid;gap:2px;min-width:0}
19
+ .manage-link{position:relative;display:flex;align-items:center;gap:8px;min-width:0;height:34px;padding:0 10px;border-radius:var(--r-md);color:var(--ink-3);font-size:var(--fs-sm);font-weight:500;text-decoration:none;white-space:nowrap;transition:background var(--t-fast),color var(--t-fast)}
20
+ .manage-link span{overflow:hidden;text-overflow:ellipsis}
21
+ .manage-link:hover{background:var(--surface-3);color:var(--ink)}
34
22
  .manage-link[aria-current="page"]{background:var(--surface-3);color:var(--ink);box-shadow:inset 0 0 0 1px var(--line-2)}
35
- .manage-link[aria-current="page"]::before{content:"";position:absolute;left:-9px;top:6px;bottom:6px;width:2px;border-radius:2px;background:var(--accent)}
23
+ .manage-link[aria-current="page"]::before{content:"";position:absolute;left:0;top:9px;bottom:9px;width:3px;border-radius:0 3px 3px 0;background:var(--accent)}
36
24
  .manage-dirty{display:none;width:7px;height:7px;margin-left:auto;flex:none;border-radius:50%;background:var(--warn);box-shadow:0 0 0 3px var(--warn-soft)}
37
25
  .manage-link[data-dirty="true"] .manage-dirty{display:inline-block}
26
+ @media(pointer:coarse){.manage-link{height:42px}}
27
+
28
+ /* Language control at the end of the top bar */
29
+ .top-locale{flex:none;min-width:0}
30
+ .top-locale select{height:30px;width:auto;max-width:124px;padding:0 26px 0 9px;line-height:28px;font-size:var(--fs-xs)}
38
31
 
39
32
  /* Reading column and the shared section heading */
40
33
  .manage-main{min-width:0;padding:28px var(--gutter) 72px}
@@ -50,20 +43,10 @@ export const MANAGE_STYLES = `
50
43
  .manage-body input[type=checkbox]{width:16px;height:16px;padding:0;accent-color:var(--accent)}
51
44
 
52
45
  @media(max-width:${BREAKPOINTS.narrow}px){
53
- .manage-app{grid-template-columns:minmax(0,1fr)}
54
- .manage-rail{position:static;height:auto;overflow:visible;border-right:0;border-bottom:1px solid var(--line)}
55
- .manage-rail-head{height:52px}
56
- .manage-nav{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:4px;padding:8px 10px}
57
- .manage-area{display:contents}
58
- .manage-primary{justify-content:center;gap:7px;height:36px;padding:0 6px;font-size:var(--fs-sm);background:var(--surface-2);box-shadow:inset 0 0 0 1px var(--line)}
59
- .manage-primary[aria-current]{background:var(--surface-3);box-shadow:inset 0 0 0 1px var(--line-2),inset 0 -2px 0 var(--accent)}
60
- /* Only the current area's sections, as a wrapping strip under the tabs. */
61
- .manage-sections{display:none;grid-column:1/-1;grid-row:2;margin:4px 0 0;padding:0;border:0}
62
- .manage-area[data-active="true"] .manage-sections{display:flex;flex-wrap:wrap;gap:4px}
63
- .manage-link{flex:0 1 auto;max-width:100%;height:32px;padding:0 10px;border:1px solid var(--line)}
64
- .manage-link[aria-current="page"]{border-color:var(--line-2)}
65
- .manage-link[aria-current="page"]::before{left:10px;right:10px;top:auto;bottom:2px;width:auto;height:2px}
66
- .manage-main{padding:18px 14px 56px}
46
+ .manage-main{padding:20px 14px 56px}
47
+ .manage-body .top-locale{display:none}
48
+ /* The top bar already names the section; the page keeps only its explanation. */
49
+ .manage-heading h1{display:none}
67
50
  }
68
51
  @media(max-width:${BREAKPOINTS.small}px){
69
52
  .manage-heading h1{font-size:var(--fs-xl)}
@@ -8,9 +8,8 @@ export const PAGE_STYLES = `
8
8
  .page{max-width:var(--center-max);margin:0 auto;padding:0 var(--gutter) 64px}
9
9
 
10
10
  /* Page scaffolding */
11
- .page-head{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;padding:36px 0 24px}
12
- .kicker{color:var(--accent);font-size:var(--fs-2xs);font-weight:600;text-transform:uppercase;letter-spacing:.1em}
13
- .page-title{margin-top:6px;font-size:var(--fs-2xl);font-weight:650;letter-spacing:-.025em}
11
+ .page-head{display:flex;align-items:flex-end;justify-content:space-between;gap:16px;padding:28px 0 20px}
12
+ .page-title{font-size:var(--fs-2xl);font-weight:650;letter-spacing:-.025em}
14
13
  .page-sub{margin-top:4px;color:var(--ink-3)}
15
14
  .page-foot{margin-top:20px;color:var(--ink-4);font-size:var(--fs-xs);text-align:center}
16
15
  .sub-head{display:flex;align-items:center;gap:8px;margin-top:6px;font-size:var(--fs-sm);font-weight:600}
@@ -50,7 +50,7 @@ summary.work-head:focus-visible{box-shadow:inset 0 0 0 2px var(--accent-line)}
50
50
  .timeline{list-style:none;margin:0;padding:0;position:relative;display:grid;gap:0}
51
51
  .timeline::before{content:"";position:absolute;left:13px;top:6px;bottom:6px;width:1px;background:var(--line-2)}
52
52
  .timeline-item{position:relative;display:grid;grid-template-columns:28px minmax(0,1fr);gap:12px;padding:0 0 18px}
53
- .timeline-mark{position:relative;z-index:1;display:grid;place-items:center;width:28px;height:28px;border-radius:50%;background:var(--surface-2);border:1px solid var(--line-2);color:var(--ink-3)}
53
+ .timeline-mark{position:relative;z-index:var(--z-raised);display:grid;place-items:center;width:28px;height:28px;border-radius:50%;background:var(--surface-2);border:1px solid var(--line-2);color:var(--ink-3)}
54
54
  .kind-decision .timeline-mark{color:var(--ok);border-color:var(--ok-soft);background:var(--ok-soft)}
55
55
  .kind-milestone .timeline-mark{color:var(--accent);border-color:var(--accent-soft);background:var(--accent-soft)}
56
56
  .kind-run .timeline-mark{color:var(--info);border-color:var(--info-soft);background:var(--info-soft)}
@@ -29,7 +29,7 @@ export const SETTINGS_STYLES = `
29
29
  .settings-receipt{white-space:pre-wrap;overflow-wrap:anywhere}
30
30
  .settings-error{color:var(--bad)!important}
31
31
  .settings-observation{max-height:260px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;font-size:var(--fs-xs)}
32
- .settings-search{position:sticky;top:0;z-index:1;padding:10px 0;background:var(--canvas)}
32
+ .settings-search{position:sticky;top:var(--header-h);z-index:var(--z-raised);padding:10px 0;background:var(--canvas)}
33
33
  .settings-search input{width:100%;max-width:520px}
34
34
  #settings-status:empty,#browser-receipt:empty{display:none}
35
35
  .mono-line{overflow-wrap:anywhere}
@@ -1,26 +1,38 @@
1
1
  /*
2
- * SIDEBAR VIEW — the task index: brand and sync state, search, attention
3
- * pills, status filter tabs, grouped task rows, the catalog pager and the
4
- * footer buttons. Region sizing lives in layout/workspace.
2
+ * SIDEBAR VIEW — the task index: title and sync state, search, attention
3
+ * pills, status filter tabs, grouped task rows and the catalog pager. The
4
+ * brand mark is shared with the global rail. Region sizing lives in
5
+ * layout/workspace.
5
6
  */
6
7
  export const SIDEBAR_STYLES = `
7
- /* Brand and sync state */
8
- .brand-mark{width:28px;height:28px;border-radius:8px;background:var(--accent);color:var(--accent-ink);font-size:15px;font-weight:700;line-height:1}
8
+ /* Brand mark (global rail, management top bar) and sync state */
9
+ .brand-mark{width:28px;height:28px;border-radius:7px;background:var(--ink);color:var(--canvas);overflow:hidden}
10
+ .brand-glyph{display:block;width:100%;height:100%}
11
+ .brand-dot{fill:var(--accent)}
9
12
  .brand-name{font-size:var(--fs-lg);font-weight:650;letter-spacing:-.02em}
10
13
  .sync{display:inline-flex;align-items:center;gap:6px;height:24px;padding:0 8px;border-radius:var(--r-pill);background:var(--surface-3);color:var(--ink-3);font-size:var(--fs-2xs);font-variant-numeric:tabular-nums}
11
14
  .sync i{width:6px;height:6px;border-radius:50%;background:var(--ink-4)}
12
15
  .sync[data-state="ok"] i{background:var(--ok);box-shadow:0 0 0 3px var(--ok-soft)}
13
- .sync[data-state="syncing"] i{background:var(--info);animation:blink 1s ease-in-out infinite}
16
+ .sync[data-state="syncing"] i{background:var(--info);animation:m-blink 1s ease-in-out infinite}
14
17
  .sync[data-state="error"] i{background:var(--bad);box-shadow:0 0 0 3px var(--bad-soft)}
15
18
  .sync[data-state="error"]{color:var(--bad)}
16
- @keyframes blink{50%{opacity:.35}}
17
19
 
18
- /* Search and attention filters */
19
- .search-field{position:relative;display:flex;align-items:center;flex:none;margin:12px 12px 0}
20
- .search-field>.icon{position:absolute;left:10px;color:var(--ink-4);pointer-events:none}
21
- .search-field input{height:34px;padding:0 34px 0 32px;border-radius:var(--r-md);background:var(--surface-2)}
20
+ /* Tools block: create, search, category and attention, on one 8px rhythm */
21
+ .side-tools{flex:none;display:grid;gap:8px;padding:12px 12px 4px}
22
+ .side-create{width:100%;height:34px;border-radius:var(--r-md);box-shadow:var(--shadow-1)}
23
+ .side-create .icon{width:16px;height:16px;stroke-width:2.2}
24
+ .side-search{display:flex;align-items:center;gap:6px;min-width:0}
25
+ .search-field{position:relative;display:flex;align-items:center;flex:1;min-width:0}
26
+ .search-field>.icon{position:absolute;left:10px;width:15px;height:15px;color:var(--ink-4);pointer-events:none}
27
+ .search-field input{height:34px;padding:0 32px 0 32px;border-radius:var(--r-md);background:var(--surface-2)}
22
28
  .search-field input::-webkit-search-cancel-button{display:none}
23
- .search-field kbd{position:absolute;right:8px}
29
+ .search-field kbd{position:absolute;right:8px;pointer-events:none}
30
+ .search-field:focus-within kbd{opacity:0}
31
+ .side-search-body{width:34px;height:34px;border:1px solid var(--line-2);border-radius:var(--r-md);background:var(--surface-2)}
32
+ .side-search-body:hover:not(:disabled){border-color:var(--line-3)}
33
+ .source-seg{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));width:100%}
34
+ .source-seg .seg-btn{justify-content:center;min-width:0;overflow:hidden;text-overflow:ellipsis}
35
+ .attention-bar:empty{display:none}
24
36
  .attention-list{display:flex;flex-wrap:wrap;gap:6px}
25
37
  .attention-pill{display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 9px;border:1px solid transparent;border-radius:var(--r-pill);background:var(--tone-soft);color:var(--tone);font-size:var(--fs-xs);font-weight:500}
26
38
  .attention-pill b{font-weight:700;font-variant-numeric:tabular-nums}
@@ -59,17 +71,10 @@ export const SIDEBAR_STYLES = `
59
71
  .list-empty{display:grid;justify-items:center;gap:8px;padding:36px 16px;color:var(--ink-4);font-size:var(--fs-sm);text-align:center}
60
72
  .list-empty.is-error{color:var(--bad)}
61
73
 
62
- /* Catalog pager and footer */
74
+ /* Catalog pager */
63
75
  .pager-btn{height:28px;padding:0 10px;border:1px solid var(--line-2);border-radius:var(--r-sm);background:transparent;color:var(--ink-2);font-size:var(--fs-xs)}
64
76
  .pager-btn:hover:not(:disabled){border-color:var(--line-3);color:var(--ink)}
65
77
  .pager-btn:disabled{opacity:.4}
66
78
  .pager-count{grid-column:2;text-align:center;color:var(--ink-4);font-size:var(--fs-2xs);font-variant-numeric:tabular-nums}
67
79
  .pager-clear{height:28px}
68
- .foot-btn{display:inline-flex;align-items:center;gap:6px;height:32px;padding:0 8px;border:1px solid var(--line-2);border-radius:var(--r-sm);background:transparent;color:var(--ink-2);font-size:var(--fs-xs);font-weight:500;min-width:0}
69
- .foot-btn span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
70
- .foot-btn:hover{color:var(--ink);border-color:var(--line-3);background:var(--surface-3)}
71
- .foot-btn[aria-pressed="true"]{color:var(--accent);border-color:var(--accent-line);background:var(--accent-soft)}
72
- .foot-btn kbd{margin-left:2px}
73
- .side-foot .icon-btn{margin-left:auto}
74
- .side-foot .icon-btn+.icon-btn{margin-left:0}
75
80
  `;