waybetter 0.6.0 → 0.7.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 (190) hide show
  1. package/README.md +1 -2
  2. package/bin/waybetter.mjs +2 -5
  3. package/cli/buildenv.mjs +1 -1
  4. package/cli/release.mjs +11 -18
  5. package/cli/releasecheck.mjs +15 -0
  6. package/cli/remote.mjs +4 -4
  7. package/cli/store.mjs +80 -28
  8. package/cli/strings.mjs +2 -0
  9. package/dist/runtime/stringPackHook.js +2 -2
  10. package/dist/runtime/stringPackHook.js.map +1 -1
  11. package/dist/runtime/stringPackTranslate.d.ts +3 -1
  12. package/dist/runtime/stringPackTranslate.js +6 -3
  13. package/dist/runtime/stringPackTranslate.js.map +1 -1
  14. package/dist/runtime/stringPacks.d.ts +53 -5
  15. package/dist/runtime/stringPacks.js +161 -25
  16. package/dist/runtime/stringPacks.js.map +1 -1
  17. package/dist/runtime/themeBar.d.ts +28 -0
  18. package/dist/runtime/themeBar.js +82 -0
  19. package/dist/runtime/themeBar.js.map +1 -0
  20. package/dist/runtime/themeComponents.js +16 -3
  21. package/dist/runtime/themeComponents.js.map +1 -1
  22. package/dist/runtime/themeDecor.js +3 -1
  23. package/dist/runtime/themeDecor.js.map +1 -1
  24. package/dist/runtime/themeDerive.d.ts +69 -0
  25. package/dist/runtime/themeDerive.js +117 -0
  26. package/dist/runtime/themeDerive.js.map +1 -0
  27. package/dist/runtime/themeDoctor.d.ts +44 -3
  28. package/dist/runtime/themeDoctor.js +86 -25
  29. package/dist/runtime/themeDoctor.js.map +1 -1
  30. package/dist/runtime/themeGuards.d.ts +60 -0
  31. package/dist/runtime/themeGuards.js +235 -0
  32. package/dist/runtime/themeGuards.js.map +1 -0
  33. package/dist/runtime/themeIcons.d.ts +1 -1
  34. package/dist/runtime/themeIcons.js +13 -5
  35. package/dist/runtime/themeIcons.js.map +1 -1
  36. package/dist/runtime/themeInk.d.ts +37 -0
  37. package/dist/runtime/themeInk.js +111 -0
  38. package/dist/runtime/themeInk.js.map +1 -0
  39. package/dist/runtime/themeInvariants.d.ts +39 -0
  40. package/dist/runtime/themeInvariants.js +273 -0
  41. package/dist/runtime/themeInvariants.js.map +1 -0
  42. package/dist/runtime/themeRuntime.d.ts +15 -1
  43. package/dist/runtime/themeRuntime.js +78 -5
  44. package/dist/runtime/themeRuntime.js.map +1 -1
  45. package/dist/runtime/themeSpec.d.ts +5 -1
  46. package/dist/runtime/themeSpec.js +9 -13
  47. package/dist/runtime/themeSpec.js.map +1 -1
  48. package/dist/shell/InstallDialog.js +14 -8
  49. package/dist/shell/InstallDialog.js.map +1 -1
  50. package/dist/shell/StoreView.d.ts +12 -0
  51. package/dist/shell/StoreView.js +9 -4
  52. package/dist/shell/StoreView.js.map +1 -1
  53. package/dist/shell/frame/AppMenu.d.ts +26 -3
  54. package/dist/shell/frame/AppMenu.js +106 -27
  55. package/dist/shell/frame/AppMenu.js.map +1 -1
  56. package/dist/shell/frame/FindBar.js +1 -1
  57. package/dist/shell/frame/FindBar.js.map +1 -1
  58. package/dist/shell/frame/Shell.d.ts +1 -0
  59. package/dist/shell/frame/Shell.js +10 -2
  60. package/dist/shell/frame/Shell.js.map +1 -1
  61. package/dist/shell/frame/Titlebar.d.ts +2 -1
  62. package/dist/shell/frame/Titlebar.js +5 -3
  63. package/dist/shell/frame/Titlebar.js.map +1 -1
  64. package/dist/shell/frame/WebPanel.js +4 -1
  65. package/dist/shell/frame/WebPanel.js.map +1 -1
  66. package/dist/shell/frame/accountSwitcher.css +10 -10
  67. package/dist/shell/frame/appMenu.css +19 -13
  68. package/dist/shell/frame/boot.js +2 -0
  69. package/dist/shell/frame/boot.js.map +1 -1
  70. package/dist/shell/frame/chromeTheme.d.ts +19 -1
  71. package/dist/shell/frame/chromeTheme.js +51 -14
  72. package/dist/shell/frame/chromeTheme.js.map +1 -1
  73. package/dist/shell/frame/deck.css +30 -30
  74. package/dist/shell/frame/edges.css +159 -0
  75. package/dist/shell/frame/index.d.ts +2 -2
  76. package/dist/shell/frame/index.js +1 -1
  77. package/dist/shell/frame/index.js.map +1 -1
  78. package/dist/shell/frame/mediaModel.d.ts +13 -0
  79. package/dist/shell/frame/mediaModel.js +14 -0
  80. package/dist/shell/frame/mediaModel.js.map +1 -1
  81. package/dist/shell/frame/menuMessages.en.json +43 -1
  82. package/dist/shell/frame/menuModel.d.ts +42 -0
  83. package/dist/shell/frame/menuModel.js +8 -0
  84. package/dist/shell/frame/menuModel.js.map +1 -1
  85. package/dist/shell/frame/nativeMenu.d.ts +5 -0
  86. package/dist/shell/frame/nativeMenu.js +178 -0
  87. package/dist/shell/frame/nativeMenu.js.map +1 -0
  88. package/dist/shell/frame/nativeMenuModel.d.ts +102 -0
  89. package/dist/shell/frame/nativeMenuModel.js +186 -0
  90. package/dist/shell/frame/nativeMenuModel.js.map +1 -0
  91. package/dist/shell/frame/paletteModel.js +3 -1
  92. package/dist/shell/frame/paletteModel.js.map +1 -1
  93. package/dist/shell/frame/paneTheme.css +1 -1
  94. package/dist/shell/frame/reportModel.d.ts +1 -1
  95. package/dist/shell/frame/reportModel.js +1 -1
  96. package/dist/shell/frame/reportModel.js.map +1 -1
  97. package/dist/shell/frame/shell.css +56 -51
  98. package/dist/shell/frame/state.d.ts +2 -0
  99. package/dist/shell/frame/state.js +3 -1
  100. package/dist/shell/frame/state.js.map +1 -1
  101. package/dist/shell/frame/themeStore.js +21 -6
  102. package/dist/shell/frame/themeStore.js.map +1 -1
  103. package/dist/shell/frame/workspaces.css +12 -12
  104. package/dist/shell/installController.d.ts +16 -1
  105. package/dist/shell/installController.js +31 -5
  106. package/dist/shell/installController.js.map +1 -1
  107. package/dist/shell/panel/Appearance.js +12 -3
  108. package/dist/shell/panel/Appearance.js.map +1 -1
  109. package/dist/shell/panel/Settings.d.ts +1 -1
  110. package/dist/shell/panel/Settings.js +4 -3
  111. package/dist/shell/panel/Settings.js.map +1 -1
  112. package/dist/shell/panel/StoreSection.d.ts +2 -1
  113. package/dist/shell/panel/StoreSection.js +31 -1
  114. package/dist/shell/panel/StoreSection.js.map +1 -1
  115. package/dist/shell/panel/StringPacks.d.ts +12 -3
  116. package/dist/shell/panel/StringPacks.js +33 -8
  117. package/dist/shell/panel/StringPacks.js.map +1 -1
  118. package/dist/shell/panel/backup.css +1 -1
  119. package/dist/shell/panel/builder.css +48 -40
  120. package/dist/shell/panel/make.css +8 -7
  121. package/dist/shell/panel/panel.css +401 -401
  122. package/dist/shell/panel/panelMessages.d.ts +41 -1
  123. package/dist/shell/panel/panelMessages.js +13 -1
  124. package/dist/shell/panel/panelMessages.js.map +1 -1
  125. package/dist/shell/panel/plugins.css +5 -5
  126. package/dist/shell/panel/strings.css +1 -1
  127. package/dist/shell/store.css +34 -14
  128. package/dist/shell/storeMessages.d.ts +24 -0
  129. package/dist/shell/storeMessages.js +24 -0
  130. package/dist/shell/storeMessages.js.map +1 -1
  131. package/dist/shell/storeModel.d.ts +31 -7
  132. package/dist/shell/storeModel.js +15 -2
  133. package/dist/shell/storeModel.js.map +1 -1
  134. package/dist/shell/stringPacksModel.js +7 -2
  135. package/dist/shell/stringPacksModel.js.map +1 -1
  136. package/icons.schema.json +9 -0
  137. package/locales/ar.json +109 -2
  138. package/locales/bg.json +109 -2
  139. package/locales/bn.json +109 -2
  140. package/locales/ca.json +109 -2
  141. package/locales/cs.json +109 -2
  142. package/locales/da.json +109 -2
  143. package/locales/de.json +109 -2
  144. package/locales/el.json +109 -2
  145. package/locales/en.json +108 -2
  146. package/locales/es.json +109 -2
  147. package/locales/eu.json +109 -2
  148. package/locales/fa.json +109 -2
  149. package/locales/fi.json +109 -2
  150. package/locales/fil.json +109 -2
  151. package/locales/fr.json +109 -2
  152. package/locales/ga.json +109 -2
  153. package/locales/gl.json +109 -2
  154. package/locales/gu.json +109 -2
  155. package/locales/ha.json +109 -2
  156. package/locales/he.json +109 -2
  157. package/locales/hi.json +109 -2
  158. package/locales/hr.json +109 -2
  159. package/locales/hu.json +110 -2
  160. package/locales/id.json +109 -2
  161. package/locales/ig.json +109 -2
  162. package/locales/it.json +109 -2
  163. package/locales/ja.json +109 -2
  164. package/locales/kn.json +109 -2
  165. package/locales/ko.json +109 -2
  166. package/locales/mr.json +109 -2
  167. package/locales/ms.json +109 -2
  168. package/locales/nb.json +109 -2
  169. package/locales/nl.json +109 -2
  170. package/locales/pl.json +109 -2
  171. package/locales/pt.json +109 -2
  172. package/locales/ro.json +109 -2
  173. package/locales/ru.json +109 -2
  174. package/locales/sk.json +109 -2
  175. package/locales/sr.json +109 -2
  176. package/locales/sv.json +109 -2
  177. package/locales/ta.json +109 -2
  178. package/locales/th.json +109 -2
  179. package/locales/tr.json +109 -2
  180. package/locales/uk.json +109 -2
  181. package/locales/ur.json +109 -2
  182. package/locales/vi.json +109 -2
  183. package/locales/yo.json +109 -2
  184. package/locales/zh-Hans.json +109 -2
  185. package/locales/zh-Hant.json +109 -2
  186. package/package.json +2 -3
  187. package/store-catalog.schema.json +18 -5
  188. package/theme.schema.json +9 -0
  189. package/windows/installer.nsi +22 -2
  190. package/cli/privacy.mjs +0 -768
@@ -12,22 +12,27 @@
12
12
  :root, .wb-pane-theme {
13
13
  --bt-ground: var(--wb-c-ground, #07080c); --bt-chrome: var(--wb-c-chrome, #0d1017); --bt-field: var(--wb-c-field, #11141c); --bt-raised: var(--wb-c-raised, #141823); --bt-raised-2: var(--wb-c-raised-2, #191e2b);
14
14
  --bt-line: var(--wb-c-line, #1e2333); --bt-line-soft: var(--wb-c-line-soft, #161a26); --bt-line-strong: var(--wb-c-line-strong, #2a3044);
15
- --bt-text: var(--wb-c-text, #eef0f7); --bt-text-2: var(--wb-c-text-2, #c3c7d4); --bt-muted: var(--wb-c-muted, #8a90a6); --bt-faint: var(--wb-c-faint, #5d6379);
15
+ --bt-text: var(--wb-c-text, #eef0f7); --bt-text-2: var(--wb-c-text-2, #c3c7d4); --bt-muted: var(--wb-c-muted, #8a90a6); --bt-faint: var(--wb-c-faint, #8a90a6);
16
16
  /* Space-separated channels for translucent tints: rgb(var(--bt-text-rgb) / .06). */
17
17
  --bt-text-rgb: var(--wb-c-text-rgb, 238 240 247); --bt-accent-rgb: var(--wb-c-accent-rgb, 29 155 240);
18
+ --bt-warn: var(--wb-c-warn, #f0b14a); --bt-danger-ink: var(--wb-c-danger-ink, #ff8a80);
18
19
  --bt-accent: var(--wb-c-accent, #1d9bf0); --bt-accent-ink: var(--wb-c-accent-ink, #cfe6ff); --bt-accent-soft: rgb(var(--bt-accent-rgb) / .14);
19
20
  --bt-hover: rgb(var(--bt-text-rgb) / .055); --bt-press: rgb(var(--bt-text-rgb) / .09);
20
21
  --bt-ring: 0 0 0 1px rgb(var(--bt-accent-rgb) / .55), 0 0 0 4px rgb(var(--bt-accent-rgb) / .16);
21
22
  --bt-shadow-pop: var(--wb-c-shadow-pop, 0 18px 44px -14px rgba(0, 0, 0, .75), 0 3px 10px rgba(0, 0, 0, .35), inset 0 1px 0 rgba(255, 255, 255, .035));
22
23
  --bt-ui: var(--wb-f-chrome, 'Geist Variable', system-ui, sans-serif); --bt-mono: var(--wb-f-mono, 'Geist Mono Variable', ui-monospace, monospace);
24
+ /* Radii scale with the theme's corners (chromeVars: --wb-c-rs, the theme radius / 12): every px
25
+ radius in the chrome is calc(<px> * var(--bt-rs, 1)), so a square theme gets a square window. */
26
+ --bt-rs: var(--wb-c-rs, 1);
27
+ /* The active tab's mark and the palette's edge: wayBetter's brush, or the theme's own accent. */
28
+ --bt-brush: var(--wb-c-brush, linear-gradient(90deg, #4f6bff, #22d3ee 55%, #a855f7));
29
+ --bt-r1: calc(6px * var(--bt-rs)); --bt-r2: calc(8px * var(--bt-rs)); --bt-r3: calc(10px * var(--bt-rs)); --bt-r4: calc(12px * var(--bt-rs)); --bt-r5: calc(14px * var(--bt-rs));
23
30
  color-scheme: var(--wb-c-scheme, dark);
24
31
  }
25
32
  .wb-pane-theme { --bt-bg: var(--bt-ground); --bt-surface: var(--bt-chrome); --bt-surface-2: var(--bt-field); }
26
33
  :root {
27
34
  --bt-danger: #e5484d;
28
- --bt-brush: linear-gradient(90deg, #4f6bff, #22d3ee 55%, #a855f7);
29
35
  --bt-s1: 4px; --bt-s2: 8px; --bt-s3: 12px; --bt-s4: 16px; --bt-s5: 24px; --bt-s6: 32px;
30
- --bt-r1: 6px; --bt-r2: 8px; --bt-r3: 10px; --bt-r4: 12px; --bt-r5: 14px;
31
36
  --bt-ease: cubic-bezier(.2, .7, .2, 1); --bt-ease-out: cubic-bezier(.16, 1, .3, 1);
32
37
  --bt-t1: 120ms; --bt-t2: 180ms; --bt-t3: 320ms;
33
38
  --bt-titlebar-h: 44px; --bt-toolbar-h: 48px; --bt-resize-border: 5px;
@@ -57,13 +62,13 @@ html, body, #root { height: 100%; margin: 0; overflow: hidden; background: var(-
57
62
  :where(.bt-shell, .bt-menu, .bt-palette, .bt-media) :focus-visible { outline: 2px solid rgb(var(--bt-accent-rgb) / .8); outline-offset: 1px; }
58
63
  :where(.bt-palette-list, .bt-profile-menu, .bt-start, .bt-media-body, .dv-tabs-overflow-container) { scrollbar-width: thin; scrollbar-color: var(--bt-line-strong) transparent; }
59
64
 
60
- .bt-kbd { display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px; box-sizing: border-box; border-radius: 5px; background: rgb(var(--bt-text-rgb) / .06); box-shadow: inset 0 0 0 1px rgb(var(--bt-text-rgb) / .07), inset 0 -1px 0 rgb(var(--bt-text-rgb) / .05); color: var(--bt-text-2); font: 500 10.5px/1 var(--bt-mono); }
65
+ .bt-kbd { display: inline-grid; place-items: center; min-width: 18px; height: 18px; padding: 0 5px; box-sizing: border-box; border-radius: calc(5px * var(--bt-rs, 1)); background: rgb(var(--bt-text-rgb) / .06); box-shadow: inset 0 0 0 1px rgb(var(--bt-text-rgb) / .07), inset 0 -1px 0 rgb(var(--bt-text-rgb) / .05); color: var(--bt-text-2); font: 500 10.5px/1 var(--bt-mono); }
61
66
  .bt-kbd + .bt-kbd { margin-inline-start: 3px; }
62
67
 
63
68
  .bt-avatar--image { overflow: hidden; position: relative; }
64
69
  .bt-avatar--image img { width: 100%; height: 100%; object-fit: cover; display: block; border-radius: 50%; }
65
70
  .bt-avatar--image::after { content: ""; position: absolute; inset: 0; border-radius: 50%; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .14); }
66
- .bt-profile-signin { margin-inline-start: auto; font: 600 12px/1 var(--bt-ui); color: var(--bt-accent); background: rgb(var(--bt-accent-rgb) / .12); border: 0; border-radius: 999px; padding: 6px 10px; cursor: pointer; }
71
+ .bt-profile-signin { margin-inline-start: auto; font: 600 12px/1 var(--bt-ui); color: var(--bt-accent); background: rgb(var(--bt-accent-rgb) / .12); border: 0; border-radius: calc(999px * var(--bt-rs, 1)); padding: 6px 10px; cursor: pointer; }
67
72
  .bt-profile-signin:hover { background: rgb(var(--bt-accent-rgb) / .2); }
68
73
  .bt-avatar { display: inline-grid; place-items: center; flex: none; border-radius: 50%; font-family: var(--bt-ui); font-weight: 650; line-height: 1; letter-spacing: 0; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .16), inset 0 -6px 10px -6px rgba(0, 0, 0, .25); user-select: none; }
69
74
 
@@ -91,7 +96,7 @@ html, body, #root { height: 100%; margin: 0; overflow: hidden; background: var(-
91
96
  pointer events only on its own controls; everything else falls through to the tabs and their
92
97
  drag region. With no tabs the titlebar itself is the drag region again. */
93
98
  .bt-titlebar { z-index: 2; pointer-events: none; }
94
- .bt-titlebar > :not(.bt-titlebar-drag):not(.bt-titlebar-spacer) { pointer-events: auto; }
99
+ .bt-titlebar > :not(.bt-titlebar-drag):not(.bt-titlebar-spacer):not(img.bt-titlebar-logo) { pointer-events: auto; }
95
100
  .bt-shell--empty .bt-titlebar > * { pointer-events: auto; }
96
101
  /* Above the dock, so it must not paint: the tab strips hosted in the titlebar row show through it. */
97
102
  .bt-shell:not(.bt-shell--empty) .bt-titlebar { background: transparent; }
@@ -111,7 +116,7 @@ html[data-update] { --bt-tb-right: calc(138px + 48px + 184px + 184px + var(--bt-
111
116
  html[data-os=macos][data-update] { --bt-tb-right: calc(48px + 184px + 184px + var(--bt-tb-menu) + var(--bt-tb-extra, 0px)); }
112
117
  .bt-update-chip {
113
118
  align-self: center; display: inline-flex; align-items: center; gap: 8px; height: 28px; margin-right: 8px; padding: 0 12px 0 10px; /* rtl-ok: titlebar */
114
- border: 1px solid transparent; border-radius: 14px; color: var(--bt-text); font: 500 12px/1 var(--bt-ui); white-space: nowrap; cursor: pointer;
119
+ border: 1px solid transparent; border-radius: calc(14px * var(--bt-rs, 1)); color: var(--bt-text); font: 500 12px/1 var(--bt-ui); white-space: nowrap; cursor: pointer;
115
120
  background: linear-gradient(var(--bt-field), var(--bt-field)) padding-box, var(--bt-brush) border-box;
116
121
  transition: background var(--bt-t1) var(--bt-ease);
117
122
  }
@@ -127,7 +132,7 @@ html[data-os=macos][data-update] { --bt-tb-right: calc(48px + 184px + 184px + va
127
132
  /* Account switcher (titlebar). Width is reserved in --bt-tb-right. */
128
133
  .bt-profile-switcher {
129
134
  align-self: center; display: inline-flex; align-items: center; gap: 8px; max-width: 176px; height: 30px; margin-right: 8px; padding: 0 9px 0 4px; box-sizing: border-box; /* rtl-ok: titlebar */
130
- border: 1px solid var(--bt-line-soft); border-radius: 15px; background: rgb(var(--bt-text-rgb) / .035); color: var(--bt-text); font: 500 12.5px/1 var(--bt-ui); cursor: pointer;
135
+ border: 1px solid var(--bt-line-soft); border-radius: calc(15px * var(--bt-rs, 1)); background: rgb(var(--bt-text-rgb) / .035); color: var(--bt-text); font: 500 12.5px/1 var(--bt-ui); cursor: pointer;
131
136
  transition: background-color var(--bt-t1) var(--bt-ease), border-color var(--bt-t1) var(--bt-ease);
132
137
  }
133
138
  .bt-profile-switcher:hover { background: var(--bt-hover); border-color: var(--bt-line-strong); }
@@ -191,7 +196,7 @@ html[data-os=macos][data-update] { --bt-tb-right: calc(48px + 184px + 184px + va
191
196
  * Tabs: floating pills. They shrink to 52px (favicon only), then the strip scrolls and dockview adds its "N more" list. */
192
197
  .bt-shell .dv-tabs-container .dv-tab {
193
198
  --bt-tab-bg: var(--bt-ground); --bt-tab-fg: var(--bt-muted);
194
- height: 30px; margin: 5px 2px 0 0; padding: 0; border-radius: 9px; box-sizing: border-box;
199
+ height: 30px; margin: 5px 2px 0 0; padding: 0; border-radius: calc(9px * var(--bt-rs, 1)); box-sizing: border-box;
195
200
  width: 224px; min-width: 52px; flex: 0 1 auto;
196
201
  /* Dockview colors tabs with higher-specificity rules; the pill states below only set these two variables. */
197
202
  color: var(--bt-tab-fg) !important; background-color: var(--bt-tab-bg) !important; box-shadow: none;
@@ -205,7 +210,7 @@ html[data-os=macos][data-update] { --bt-tb-right: calc(48px + 184px + 184px + va
205
210
  }
206
211
  /* The brush marks the focused pane's tab; other panes keep a plain raised pill. */
207
212
  .bt-shell .dv-tabs-container .dv-tab.dv-active-tab::after {
208
- content: ''; position: absolute; left: 12px; right: 12px; bottom: 0; height: 2px; border-radius: 2px 2px 0 0;
213
+ content: ''; position: absolute; left: 12px; right: 12px; bottom: 0; height: 2px; border-radius: calc(2px * var(--bt-rs, 1)) calc(2px * var(--bt-rs, 1)) 0 0;
209
214
  background: var(--bt-brush); opacity: .95; pointer-events: none;
210
215
  }
211
216
  .bt-shell .dv-groupview.dv-inactive-group .dv-tabs-container .dv-tab.dv-active-tab { --bt-tab-bg: var(--bt-field); --bt-tab-fg: var(--bt-text-2); }
@@ -223,13 +228,13 @@ html[data-os=macos][data-update] { --bt-tb-right: calc(48px + 184px + 184px + va
223
228
  .bt-tab { container-type: inline-size; height: 100%; width: 100%; box-sizing: border-box; display: flex; align-items: center; gap: 8px; padding-block: 0; padding-inline: 10px 5px; min-width: 0; user-select: none; font: 500 12.5px/1 var(--bt-ui); letter-spacing: .005em; }
224
229
  .bt-tab--pinned { justify-content: center; padding: 0; }
225
230
  .bt-tab-icon { position: relative; display: grid; place-items: center; width: 16px; height: 16px; flex: 0 0 16px; }
226
- .bt-favicon { width: 16px !important; height: 16px !important; flex: 0 0 16px; border-radius: 4px; color: var(--bt-muted); }
231
+ .bt-favicon { width: 16px !important; height: 16px !important; flex: 0 0 16px; border-radius: calc(4px * var(--bt-rs, 1)); color: var(--bt-muted); }
227
232
  .bt-favicon--img { animation: bt-fade-in var(--bt-t2) var(--bt-ease); }
228
233
  .bt-shell .bt-favicon--glyph { width: 15px !important; height: 15px !important; }
229
234
  .bt-tab-account { position: absolute; inset-inline-end: -3px; bottom: -3px; width: 7px; height: 7px; border-radius: 50%; box-shadow: 0 0 0 2px var(--bt-tab-bg, var(--bt-raised)); transition: box-shadow var(--bt-t1) var(--bt-ease); }
230
235
  .bt-tab-title { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; line-height: 16px; -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 18px), transparent); mask-image: linear-gradient(90deg, #000 calc(100% - 18px), transparent); }
231
236
  .bt-tab--loading .bt-tab-title { color: var(--bt-text-2); }
232
- .bt-tab-close { flex: 0 0 20px; width: 20px; height: 20px; display: grid; place-items: center; padding: 0; border: 0; border-radius: 6px; background: transparent; color: var(--bt-muted); cursor: pointer; opacity: 0; transition: opacity var(--bt-t1) var(--bt-ease), background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
237
+ .bt-tab-close { flex: 0 0 20px; width: 20px; height: 20px; display: grid; place-items: center; padding: 0; border: 0; border-radius: calc(6px * var(--bt-rs, 1)); background: transparent; color: var(--bt-muted); cursor: pointer; opacity: 0; transition: opacity var(--bt-t1) var(--bt-ease), background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
233
238
  .bt-shell .bt-tab-close svg { width: 13px; height: 13px; stroke-width: 2; }
234
239
  .dv-tab:hover .bt-tab-close, .dv-active-tab .bt-tab-close, .bt-tab-close:focus-visible { opacity: 1; }
235
240
  .dv-inactive-tab .bt-tab-close { color: var(--bt-faint); }
@@ -253,7 +258,7 @@ html[data-os=macos][data-update] { --bt-tb-right: calc(48px + 184px + 184px + va
253
258
 
254
259
  .bt-group-actions { height: 100%; display: flex; align-items: center; padding: 0 4px 0 2px; }
255
260
  .bt-group--in-titlebar .bt-group-actions { padding-top: 0; }
256
- .bt-group-actions .bt-icon { width: 28px; height: 28px; flex-basis: 28px; border-radius: 8px; }
261
+ .bt-group-actions .bt-icon { width: 28px; height: 28px; flex-basis: 28px; border-radius: calc(8px * var(--bt-rs, 1)); }
257
262
  .bt-group--in-titlebar .bt-group-actions .bt-icon { margin-top: 0; }
258
263
  .bt-shell .bt-newtab svg { width: 15px; height: 15px; }
259
264
 
@@ -263,7 +268,7 @@ html[data-os=macos][data-update] { --bt-tb-right: calc(48px + 184px + 184px + va
263
268
  }
264
269
  .bt-shell .dv-tabs-overflow-dropdown-root { display: flex; align-items: center; height: 100%; }
265
270
  .bt-shell .dv-tabs-overflow-dropdown-default {
266
- height: 26px; margin: 0 2px 0 4px; padding: 0 8px 0 6px; gap: 2px; box-sizing: border-box; border-radius: 8px;
271
+ height: 26px; margin: 0 2px 0 4px; padding: 0 8px 0 6px; gap: 2px; box-sizing: border-box; border-radius: calc(8px * var(--bt-rs, 1));
267
272
  background: rgb(var(--bt-text-rgb) / .04); box-shadow: inset 0 0 0 1px var(--bt-line); color: var(--bt-text-2);
268
273
  font: 500 11.5px/1 var(--bt-mono); font-variant-numeric: tabular-nums; transition: background-color var(--bt-t1) var(--bt-ease);
269
274
  }
@@ -306,14 +311,14 @@ html[data-os=macos][data-update] { --bt-tb-right: calc(48px + 184px + 184px + va
306
311
  .bt-omni--edit { padding-inline-start: 10px; gap: 8px; }
307
312
  .bt-shell .bt-omni-lead { width: 15px; height: 15px; color: var(--bt-muted); }
308
313
  .bt-chip-site {
309
- display: inline-flex; align-items: center; gap: 6px; height: 24px; padding-block: 0; padding-inline: 6px 8px; margin-inline-end: 2px; flex: 0 0 auto; border: 0; border-radius: 7px;
314
+ display: inline-flex; align-items: center; gap: 6px; height: 24px; padding-block: 0; padding-inline: 6px 8px; margin-inline-end: 2px; flex: 0 0 auto; border: 0; border-radius: calc(7px * var(--bt-rs, 1));
310
315
  background: var(--bt-accent-soft); color: var(--bt-accent-ink); font: 600 12.5px/1 var(--bt-ui); letter-spacing: .005em; cursor: pointer;
311
316
  transition: background-color var(--bt-t1) var(--bt-ease);
312
317
  }
313
318
  .bt-chip-site:hover { background: rgb(var(--bt-accent-rgb) / .22); }
314
- .bt-chip-site img { width: 14px; height: 14px; border-radius: 3px; }
315
- .bt-chip-insecure { display: inline-flex; align-items: center; flex: 0 0 auto; height: 22px; margin-inline-end: 2px; padding: 0 8px; border-radius: 6px; background: rgba(245, 158, 11, .12); color: #fbbf24; font: 600 11.5px/1 var(--bt-ui); }
316
- .bt-seg { display: inline-flex; align-items: center; height: 24px; padding: 0 6px; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; border-radius: 6px; border: 0; background: transparent; color: var(--bt-text-2); font: 500 13px/1 var(--bt-ui); white-space: nowrap; cursor: pointer; transition: background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
319
+ .bt-chip-site img { width: 14px; height: 14px; border-radius: calc(3px * var(--bt-rs, 1)); }
320
+ .bt-chip-insecure { display: inline-flex; align-items: center; flex: 0 0 auto; height: 22px; margin-inline-end: 2px; padding: 0 8px; border-radius: calc(6px * var(--bt-rs, 1)); background: rgba(245, 158, 11, .12); color: #fbbf24; font: 600 11.5px/1 var(--bt-ui); }
321
+ .bt-seg { display: inline-flex; align-items: center; height: 24px; padding: 0 6px; flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; border-radius: calc(6px * var(--bt-rs, 1)); border: 0; background: transparent; color: var(--bt-text-2); font: 500 13px/1 var(--bt-ui); white-space: nowrap; cursor: pointer; transition: background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
317
322
  .bt-seg:hover { background: var(--bt-hover); color: var(--bt-text); }
318
323
  .bt-seg[aria-current] { cursor: text; background: none; color: var(--bt-text); font-weight: 600; }
319
324
  .bt-seg--mono { font: 500 12.5px/1 var(--bt-mono); color: var(--bt-text-2); }
@@ -321,7 +326,7 @@ html[data-os=macos][data-update] { --bt-tb-right: calc(48px + 184px + 184px + va
321
326
  .bt-sep { flex: 0 0 auto; color: var(--bt-faint); font: 400 14px/1 var(--bt-ui); padding: 0 1px; opacity: .8; }
322
327
  .bt-omni-raw { flex: 1; min-width: 0; padding-inline-start: 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 400 12.5px var(--bt-mono); color: var(--bt-muted); }
323
328
  .bt-omni-fill { flex: 1; min-width: 8px; align-self: stretch; }
324
- .bt-omni-action { width: 26px; height: 26px; flex: 0 0 26px; display: grid; place-items: center; padding: 0; border: 0; border-radius: 7px; background: transparent; color: var(--bt-faint); cursor: pointer; transition: background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
329
+ .bt-omni-action { width: 26px; height: 26px; flex: 0 0 26px; display: grid; place-items: center; padding: 0; border: 0; border-radius: calc(7px * var(--bt-rs, 1)); background: transparent; color: var(--bt-faint); cursor: pointer; transition: background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
325
330
  .bt-omni:hover .bt-omni-action { color: var(--bt-muted); }
326
331
  .bt-omni-action:hover { background: var(--bt-hover); color: var(--bt-text) !important; }
327
332
  .bt-shell .bt-omni-action svg { width: 14px; height: 14px; }
@@ -329,22 +334,22 @@ html[data-os=macos][data-update] { --bt-tb-right: calc(48px + 184px + 184px + va
329
334
  .bt-omni input:focus-visible { outline: 0; }
330
335
  .bt-omni input::selection { background: rgb(var(--bt-accent-rgb) / .35); }
331
336
  .bt-omni-ops { display: flex; gap: 4px; flex: 0 1 auto; min-width: 0; overflow: hidden; }
332
- .bt-omni-op { flex: 0 0 auto; height: 22px; padding: 0 8px; border: 1px solid var(--bt-line); border-radius: 6px; background: var(--bt-chrome); color: var(--bt-muted); font: 500 11.5px var(--bt-mono); cursor: pointer; }
337
+ .bt-omni-op { flex: 0 0 auto; height: 22px; padding: 0 8px; border: 1px solid var(--bt-line); border-radius: calc(6px * var(--bt-rs, 1)); background: var(--bt-chrome); color: var(--bt-muted); font: 500 11.5px var(--bt-mono); cursor: pointer; }
333
338
  .bt-omni-op[aria-selected=true] { color: var(--bt-accent-ink); border-color: rgb(var(--bt-accent-rgb) / .5); background: var(--bt-accent-soft); }
334
339
  .bt-omni-op:hover { color: var(--bt-text); border-color: var(--bt-accent); }
335
- .bt-omni-progress { position: absolute; left: 8px; right: 8px; bottom: 0; height: 2px; border-radius: 2px; background: var(--bt-brush); transform-origin: left; animation: bt-load 1.2s ease-in-out infinite; pointer-events: none; }
340
+ .bt-omni-progress { position: absolute; left: 8px; right: 8px; bottom: 0; height: 2px; border-radius: calc(2px * var(--bt-rs, 1)); background: var(--bt-brush); transform-origin: left; animation: bt-load 1.2s ease-in-out infinite; pointer-events: none; }
336
341
  @keyframes bt-load { 0% { transform: scaleX(.05); } 60% { transform: scaleX(.7); } 100% { transform: scaleX(.95); opacity: .3; } }
337
342
  @media (prefers-reduced-motion: reduce) { .bt-omni-progress { animation: none; transform: scaleX(.6); } }
338
343
 
339
344
  /* split + wayBetter buttons */
340
345
  .bt-split { position: relative; display: flex; align-items: center; }
341
- .bt-split .bt-split-main { border-start-start-radius: 8px; border-start-end-radius: 0; border-end-end-radius: 0; border-end-start-radius: 8px; }
342
- .bt-split .bt-split-more { width: 18px; flex-basis: 18px; border-start-start-radius: 0; border-start-end-radius: 8px; border-end-end-radius: 8px; border-end-start-radius: 0; }
346
+ .bt-split .bt-split-main { border-start-start-radius: calc(8px * var(--bt-rs, 1)); border-start-end-radius: 0; border-end-end-radius: 0; border-end-start-radius: calc(8px * var(--bt-rs, 1)); }
347
+ .bt-split .bt-split-more { width: 18px; flex-basis: 18px; border-start-start-radius: 0; border-start-end-radius: calc(8px * var(--bt-rs, 1)); border-end-end-radius: calc(8px * var(--bt-rs, 1)); border-end-start-radius: 0; }
343
348
  .bt-shell .bt-split-more svg { width: 12px; height: 12px; }
344
349
  .bt-menu.bt-split-menu { position: absolute; top: 40px; inset-inline-end: 0; z-index: 20; min-width: 200px; }
345
350
  .bt-brand-button {
346
351
  display: inline-flex; align-items: center; gap: 7px; height: 32px; margin-inline-start: 6px; padding-block: 0; padding-inline: 9px 12px; flex: 0 0 auto;
347
- border: 1px solid var(--bt-line); border-radius: 9px; background: rgb(var(--bt-text-rgb) / .02); color: var(--bt-text); font: 600 12.5px/1 var(--bt-ui); cursor: pointer;
352
+ border: 1px solid var(--bt-line); border-radius: calc(9px * var(--bt-rs, 1)); background: rgb(var(--bt-text-rgb) / .02); color: var(--bt-text); font: 600 12.5px/1 var(--bt-ui); cursor: pointer;
348
353
  transition: background-color var(--bt-t1) var(--bt-ease), border-color var(--bt-t1) var(--bt-ease);
349
354
  }
350
355
  .bt-brand-button:hover { background: var(--bt-hover); border-color: var(--bt-line-strong); }
@@ -357,7 +362,7 @@ html[data-os=macos][data-update] { --bt-tb-right: calc(48px + 184px + 184px + va
357
362
  @container pane (max-width: 640px) {
358
363
  .bt-brand-button { padding: 0; width: 36px; min-width: 36px; }
359
364
  .bt-split .bt-split-more { display: none; }
360
- .bt-split .bt-split-main { border-radius: 8px; }
365
+ .bt-split .bt-split-main { border-radius: calc(8px * var(--bt-rs, 1)); }
361
366
  }
362
367
  @container pane (max-width: 420px) {
363
368
  .bt-addressbar > .bt-icon[aria-label=Forward], .bt-split { display: none; }
@@ -405,7 +410,7 @@ html.bt-raised .bt-deck :is(.bt-col-head, .bt-compose-head) { background-color:
405
410
  border-radius: var(--bt-r4); background: var(--bt-raised); border: 1px solid var(--bt-line-strong); box-shadow: var(--bt-shadow-pop);
406
411
  color: var(--bt-text); font: 500 13px/1.3 var(--bt-ui); user-select: none;
407
412
  }
408
- .bt-menu button { display: flex; align-items: center; gap: 10px; height: 32px; padding: 0 10px; border: 0; border-radius: 7px; background: transparent; color: var(--bt-text); font: inherit; text-align: start; cursor: pointer; transition: background-color 80ms var(--bt-ease); }
413
+ .bt-menu button { display: flex; align-items: center; gap: 10px; height: 32px; padding: 0 10px; border: 0; border-radius: calc(7px * var(--bt-rs, 1)); background: transparent; color: var(--bt-text); font: inherit; text-align: start; cursor: pointer; transition: background-color 80ms var(--bt-ease); }
409
414
  .bt-menu button:hover:not(:disabled), .bt-menu button:focus-visible { background: var(--bt-hover); outline: 0; }
410
415
  .bt-menu button:active:not(:disabled) { background: var(--bt-press); }
411
416
  .bt-menu button:disabled { color: var(--bt-faint); cursor: default; }
@@ -421,9 +426,9 @@ html.bt-raised .bt-deck :is(.bt-col-head, .bt-compose-head) { background-color:
421
426
  .bt-profile-menu-head { display: flex; flex-direction: column; gap: 3px; padding: 8px 10px 10px; }
422
427
  .bt-profile-menu-head strong { font: 600 13px/1.2 var(--bt-ui); color: var(--bt-text); }
423
428
  .bt-profile-menu-head span { font: 400 12px/1.3 var(--bt-ui); color: var(--bt-muted); }
424
- .bt-profile-row { position: relative; display: flex; align-items: center; border-radius: 9px; }
429
+ .bt-profile-row { position: relative; display: flex; align-items: center; border-radius: calc(9px * var(--bt-rs, 1)); }
425
430
  .bt-profile-row.is-active { background: rgb(var(--bt-text-rgb) / .035); }
426
- .bt-menu .bt-profile-pick { flex: 1; min-width: 0; height: auto; gap: 11px; padding: 7px 8px; border-radius: 9px; }
431
+ .bt-menu .bt-profile-pick { flex: 1; min-width: 0; height: auto; gap: 11px; padding: 7px 8px; border-radius: calc(9px * var(--bt-rs, 1)); }
427
432
  .bt-profile-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
428
433
  .bt-profile-name { font: 600 13.5px/1.15 var(--bt-ui); color: var(--bt-text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
429
434
  .bt-profile-meta { font: 400 12px/1.2 var(--bt-ui); color: var(--bt-muted); font-variant-numeric: tabular-nums; }
@@ -437,9 +442,9 @@ html.bt-raised .bt-deck :is(.bt-col-head, .bt-compose-head) { background-color:
437
442
  .bt-menu .bt-profile-action { width: 28px; height: 28px; padding: 0; justify-content: center; color: var(--bt-muted); }
438
443
  .bt-menu .bt-profile-action:hover:not(:disabled) { color: var(--bt-text); background: var(--bt-press); }
439
444
  .bt-profile-action .bt-glyph { width: 15px; height: 15px; }
440
- .bt-profile-edit { display: flex; flex-direction: column; gap: 10px; padding: 7px 8px 9px; border-radius: 9px; background: rgb(var(--bt-text-rgb) / .035); }
445
+ .bt-profile-edit { display: flex; flex-direction: column; gap: 10px; padding: 7px 8px 9px; border-radius: calc(9px * var(--bt-rs, 1)); background: rgb(var(--bt-text-rgb) / .035); }
441
446
  .bt-profile-edit-row { display: flex; align-items: center; gap: 11px; }
442
- .bt-profile-name-input { flex: 1; min-width: 0; height: 32px; padding: 0 10px; box-sizing: border-box; border: 0; border-radius: 8px; background: var(--bt-field); box-shadow: var(--bt-ring); color: var(--bt-text); font: 500 13.5px/1 var(--bt-ui); outline: none; user-select: text; }
447
+ .bt-profile-name-input { flex: 1; min-width: 0; height: 32px; padding: 0 10px; box-sizing: border-box; border: 0; border-radius: calc(8px * var(--bt-rs, 1)); background: var(--bt-field); box-shadow: var(--bt-ring); color: var(--bt-text); font: 500 13.5px/1 var(--bt-ui); outline: none; user-select: text; }
443
448
  .bt-profile-swatches { display: flex; flex-wrap: wrap; gap: 8px; padding-inline-start: 41px; }
444
449
  .bt-menu .bt-profile-swatch { width: 18px; height: 18px; padding: 0; border-radius: 50%; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .18); transition: transform var(--bt-t1) var(--bt-ease); }
445
450
  .bt-menu .bt-profile-swatch:hover { transform: scale(1.12); background-color: revert; }
@@ -449,14 +454,14 @@ html.bt-raised .bt-deck :is(.bt-col-head, .bt-compose-head) { background-color:
449
454
  .bt-profile-add-icon .bt-glyph { width: 14px; height: 14px; }
450
455
  .bt-menu .bt-profile-add:hover .bt-profile-add-icon { box-shadow: inset 0 0 0 1px rgb(var(--bt-accent-rgb) / .6); color: var(--bt-accent-ink); }
451
456
  .bt-profile-foot { margin: 2px 10px 6px; color: var(--bt-faint); font: 400 11.5px/1.4 var(--bt-ui); }
452
- .bt-profile-confirm { display: flex; flex-direction: column; gap: 10px; margin: 1px 0; padding: 10px 12px; border-radius: 9px; background: rgba(229, 72, 77, .08); box-shadow: inset 0 0 0 1px rgba(229, 72, 77, .25); color: var(--bt-text-2); font: 400 12.5px/1.45 var(--bt-ui); }
457
+ .bt-profile-confirm { display: flex; flex-direction: column; gap: 10px; margin: 1px 0; padding: 10px 12px; border-radius: calc(9px * var(--bt-rs, 1)); background: rgba(229, 72, 77, .08); box-shadow: inset 0 0 0 1px rgba(229, 72, 77, .25); color: var(--bt-text-2); font: 400 12.5px/1.45 var(--bt-ui); }
453
458
  .bt-profile-confirm strong { color: var(--bt-text); font-weight: 600; }
454
459
  .bt-profile-confirm div { display: flex; gap: 6px; }
455
460
  .bt-menu .bt-profile-confirm button { height: 28px; padding: 0 12px; font-weight: 600; font-size: 12.5px; }
456
461
  .bt-menu .bt-profile-danger { background: var(--bt-danger); color: #fff; }
457
462
  .bt-menu .bt-profile-danger:hover:not(:disabled) { background: #d93d42; }
458
463
  .bt-menu .bt-profile-cancel { background: var(--bt-hover); }
459
- .bt-profile-error { padding: 6px 10px; color: #ff8a80; font: 12px/1.4 var(--bt-ui); }
464
+ .bt-profile-error { padding: 6px 10px; color: var(--bt-danger-ink); font: 12px/1.4 var(--bt-ui); }
460
465
 
461
466
  /* ------------------------------------------------------------------------------------------------
462
467
  * Command palette (Ctrl+K) and the composer drafts picker, which reuses it. */
@@ -475,15 +480,15 @@ html.bt-raised .bt-deck :is(.bt-col-head, .bt-compose-head) { background-color:
475
480
  .bt-palette-list { flex: 1; overflow-y: auto; padding: 6px; }
476
481
  .bt-palette-group { padding: 12px 10px 6px; color: var(--bt-faint); font: 600 10.5px/1 var(--bt-ui); letter-spacing: .08em; text-transform: uppercase; }
477
482
  .bt-palette-group:first-child { padding-top: 6px; }
478
- .bt-palette-item { display: flex; align-items: center; gap: 11px; min-height: 38px; padding: 0 10px; box-sizing: border-box; border-radius: 9px; cursor: pointer; color: var(--bt-text-2); }
483
+ .bt-palette-item { display: flex; align-items: center; gap: 11px; min-height: 38px; padding: 0 10px; box-sizing: border-box; border-radius: calc(9px * var(--bt-rs, 1)); cursor: pointer; color: var(--bt-text-2); }
479
484
  .bt-palette-item[aria-selected=true] { background: rgb(var(--bt-text-rgb) / .055); color: var(--bt-text); }
480
- .bt-palette-icon { display: grid; place-items: center; width: 26px; height: 26px; flex: none; border-radius: 7px; background: rgb(var(--bt-text-rgb) / .04); box-shadow: inset 0 0 0 1px rgb(var(--bt-text-rgb) / .05); color: var(--bt-muted); transition: background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
481
- .bt-palette-icon img { width: 16px; height: 16px; border-radius: 4px; }
485
+ .bt-palette-icon { display: grid; place-items: center; width: 26px; height: 26px; flex: none; border-radius: calc(7px * var(--bt-rs, 1)); background: rgb(var(--bt-text-rgb) / .04); box-shadow: inset 0 0 0 1px rgb(var(--bt-text-rgb) / .05); color: var(--bt-muted); transition: background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
486
+ .bt-palette-icon img { width: 16px; height: 16px; border-radius: calc(4px * var(--bt-rs, 1)); }
482
487
  .bt-palette-icon .bt-glyph { width: 15px; height: 15px; }
483
488
  .bt-palette-item[aria-selected=true] .bt-palette-icon { background: var(--bt-accent-soft); box-shadow: inset 0 0 0 1px rgb(var(--bt-accent-rgb) / .3); color: var(--bt-accent-ink); }
484
489
  .bt-palette-label { font-weight: 500; font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
485
490
  .bt-palette-hint { margin-inline-start: auto; color: var(--bt-faint); font: 400 11.5px/1.2 var(--bt-mono); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 42%; flex-shrink: 0; }
486
- .bt-palette-hint--tag { padding: 3px 7px; border-radius: 6px; background: rgb(var(--bt-text-rgb) / .06); color: var(--bt-muted); font: 500 11px/1.2 var(--bt-ui); }
491
+ .bt-palette-hint--tag { padding: 3px 7px; border-radius: calc(6px * var(--bt-rs, 1)); background: rgb(var(--bt-text-rgb) / .06); color: var(--bt-muted); font: 500 11px/1.2 var(--bt-ui); }
487
492
  .bt-palette-hint--tag.is-match { background: var(--bt-accent-soft); color: var(--bt-accent-ink); }
488
493
  .bt-palette-enter { width: 14px; flex: none; color: var(--bt-muted); font: 500 12px/1 var(--bt-mono); opacity: 0; }
489
494
  .bt-palette-item[aria-selected=true] .bt-palette-enter { opacity: .8; }
@@ -503,11 +508,11 @@ html.bt-raised .bt-deck :is(.bt-col-head, .bt-compose-head) { background-color:
503
508
  var(--bt-ground);
504
509
  }
505
510
  .bt-start-inner { max-width: 660px; margin: 0 auto; padding: clamp(40px, 13vh, 132px) 20px 40px; display: flex; flex-direction: column; align-items: center; gap: 24px; }
506
- .bt-start-mark { display: grid; place-items: center; width: 60px; height: 60px; border-radius: 18px; background: linear-gradient(180deg, var(--bt-raised-2), var(--bt-chrome)); box-shadow: inset 0 0 0 1px rgb(var(--bt-text-rgb) / .07), inset 0 1px 0 rgb(var(--bt-text-rgb) / .06), 0 24px 60px -24px rgba(79, 107, 255, .65); }
507
- .bt-start-mark img { border-radius: 9px; -webkit-user-drag: none; }
511
+ .bt-start-mark { display: grid; place-items: center; width: 60px; height: 60px; border-radius: calc(18px * var(--bt-rs, 1)); background: linear-gradient(180deg, var(--bt-raised-2), var(--bt-chrome)); box-shadow: inset 0 0 0 1px rgb(var(--bt-text-rgb) / .07), inset 0 1px 0 rgb(var(--bt-text-rgb) / .06), 0 24px 60px -24px rgba(79, 107, 255, .65); }
512
+ .bt-start-mark img { border-radius: calc(9px * var(--bt-rs, 1)); -webkit-user-drag: none; }
508
513
  .bt-start-search {
509
514
  width: 100%; height: 52px; display: flex; align-items: center; gap: 12px; padding-block: 0; padding-inline: 17px 12px; box-sizing: border-box;
510
- border-radius: 14px; background: var(--bt-chrome); border: 1px solid var(--bt-line); box-shadow: 0 10px 30px -18px rgba(0, 0, 0, .9);
515
+ border-radius: calc(14px * var(--bt-rs, 1)); background: var(--bt-chrome); border: 1px solid var(--bt-line); box-shadow: 0 10px 30px -18px rgba(0, 0, 0, .9);
511
516
  transition: border-color var(--bt-t1) var(--bt-ease), box-shadow var(--bt-t2) var(--bt-ease);
512
517
  }
513
518
  .bt-start-search:hover { border-color: var(--bt-line-strong); }
@@ -523,7 +528,7 @@ html.bt-raised .bt-deck :is(.bt-col-head, .bt-compose-head) { background-color:
523
528
  .bt-start-accounts .bt-start-label { margin-inline-end: 6px; }
524
529
  .bt-start-account {
525
530
  display: inline-flex; align-items: center; gap: 7px; height: 30px; padding-block: 0; padding-inline: 5px 12px; box-sizing: border-box;
526
- border: 1px solid var(--bt-line-soft); border-radius: 15px; background: transparent; color: var(--bt-muted); font: 500 12.5px/1 var(--bt-ui); cursor: pointer;
531
+ border: 1px solid var(--bt-line-soft); border-radius: calc(15px * var(--bt-rs, 1)); background: transparent; color: var(--bt-muted); font: 500 12.5px/1 var(--bt-ui); cursor: pointer;
527
532
  transition: background-color var(--bt-t1) var(--bt-ease), border-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease);
528
533
  }
529
534
  .bt-start-account:hover { background: var(--bt-hover); color: var(--bt-text-2); }
@@ -537,16 +542,16 @@ html.bt-raised .bt-deck :is(.bt-col-head, .bt-compose-head) { background-color:
537
542
  border: 1px solid var(--bt-line-soft); border-radius: var(--bt-r4); background: rgb(var(--bt-text-rgb) / .02); color: var(--bt-text-2); font: 500 12.5px/1 var(--bt-ui); cursor: pointer;
538
543
  transition: background-color var(--bt-t1) var(--bt-ease), border-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease), transform var(--bt-t2) var(--bt-ease-out);
539
544
  }
540
- .bt-start-link-icon { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 11px; background: var(--bt-field); box-shadow: inset 0 0 0 1px rgb(var(--bt-text-rgb) / .05); color: var(--bt-muted); transition: background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
545
+ .bt-start-link-icon { display: grid; place-items: center; width: 36px; height: 36px; border-radius: calc(11px * var(--bt-rs, 1)); background: var(--bt-field); box-shadow: inset 0 0 0 1px rgb(var(--bt-text-rgb) / .05); color: var(--bt-muted); transition: background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
541
546
  .bt-start-link-icon .bt-glyph { width: 18px; height: 18px; }
542
547
  .bt-start-link-label { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
543
548
  .bt-start-link:hover { background: rgb(var(--bt-text-rgb) / .045); border-color: var(--bt-line); color: var(--bt-text); transform: translateY(-1px); }
544
549
  .bt-start-link:hover .bt-start-link-icon { background: var(--bt-accent-soft); color: var(--bt-accent-ink); }
545
550
  .bt-start-link:active { transform: translateY(0) scale(.985); }
546
551
  .bt-start-recent { list-style: none; margin: 0; padding: 4px; border: 1px solid var(--bt-line-soft); border-radius: var(--bt-r4); background: rgb(var(--bt-text-rgb) / .015); }
547
- .bt-start-row { display: flex; align-items: center; gap: 11px; width: 100%; height: 38px; padding: 0 10px; box-sizing: border-box; border: 0; border-radius: 8px; background: transparent; color: var(--bt-text-2); font: 500 13px/1 var(--bt-ui); text-align: start; cursor: pointer; transition: background-color 80ms var(--bt-ease), color 80ms var(--bt-ease); }
552
+ .bt-start-row { display: flex; align-items: center; gap: 11px; width: 100%; height: 38px; padding: 0 10px; box-sizing: border-box; border: 0; border-radius: calc(8px * var(--bt-rs, 1)); background: transparent; color: var(--bt-text-2); font: 500 13px/1 var(--bt-ui); text-align: start; cursor: pointer; transition: background-color 80ms var(--bt-ease), color 80ms var(--bt-ease); }
548
553
  .bt-start-row:hover { background: var(--bt-hover); color: var(--bt-text); }
549
- .bt-start-row-icon { display: grid; place-items: center; width: 16px; height: 16px; flex: none; border-radius: 4px; color: var(--bt-muted); }
554
+ .bt-start-row-icon { display: grid; place-items: center; width: 16px; height: 16px; flex: none; border-radius: calc(4px * var(--bt-rs, 1)); color: var(--bt-muted); }
550
555
  .bt-start-row-icon .bt-glyph { width: 15px; height: 15px; }
551
556
  .bt-start-row-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
552
557
  .bt-start-row-host { flex: none; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--bt-faint); font: 400 11.5px/1 var(--bt-mono); }
@@ -561,8 +566,8 @@ html.bt-raised .bt-deck :is(.bt-col-head, .bt-compose-head) { background-color:
561
566
  .bt-media { width: min(380px, 100%); height: 100%; display: flex; flex-direction: column; background: var(--bt-raised); border-inline-start: 1px solid var(--bt-line); box-shadow: -24px 0 60px rgba(0, 0, 0, .45); font: 14px/1.3 var(--bt-ui); color: var(--bt-text); animation: bt-slide-in var(--bt-t2) var(--bt-ease-out); }
562
567
  [dir="rtl"] .bt-media { box-shadow: 24px 0 60px rgba(0, 0, 0, .45); animation-name: bt-slide-in-rtl; }
563
568
  .bt-media-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; height: 52px; padding-block: 0; padding-inline: 12px 10px; box-sizing: border-box; border-bottom: 1px solid var(--bt-line); }
564
- .bt-media-tabs { display: flex; gap: 2px; padding: 3px; border-radius: 10px; background: rgb(var(--bt-text-rgb) / .045); }
565
- .bt-media-tabs button { height: 28px; padding: 0 12px; border: 0; border-radius: 7px; background: transparent; color: var(--bt-muted); font: 500 12.5px/1 var(--bt-ui); cursor: pointer; transition: background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
569
+ .bt-media-tabs { display: flex; gap: 2px; padding: 3px; border-radius: calc(10px * var(--bt-rs, 1)); background: rgb(var(--bt-text-rgb) / .045); }
570
+ .bt-media-tabs button { height: 28px; padding: 0 12px; border: 0; border-radius: calc(7px * var(--bt-rs, 1)); background: transparent; color: var(--bt-muted); font: 500 12.5px/1 var(--bt-ui); cursor: pointer; transition: background-color var(--bt-t1) var(--bt-ease), color var(--bt-t1) var(--bt-ease); }
566
571
  .bt-media-tabs button:hover { color: var(--bt-text-2); }
567
572
  .bt-media-tabs button.active { color: var(--bt-text); background: var(--bt-raised-2); box-shadow: inset 0 0 0 1px rgb(var(--bt-text-rgb) / .07), 0 1px 2px rgba(0, 0, 0, .4); }
568
573
  .bt-media .bt-icon svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; }
@@ -571,33 +576,33 @@ html.bt-raised .bt-deck :is(.bt-col-head, .bt-compose-head) { background-color:
571
576
  .bt-media-empty { color: var(--bt-muted); display: flex; flex-direction: column; gap: 10px; align-items: flex-start; padding: 12px 2px; }
572
577
  .bt-media-empty p { margin: 0; }
573
578
  .bt-media-folders { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 12px; }
574
- .bt-media-link { border: 0; background: transparent; color: var(--bt-muted); cursor: pointer; font: 600 12px/1 var(--bt-ui); padding: 4px 6px; border-radius: 6px; }
579
+ .bt-media-link { border: 0; background: transparent; color: var(--bt-muted); cursor: pointer; font: 600 12px/1 var(--bt-ui); padding: 4px 6px; border-radius: calc(6px * var(--bt-rs, 1)); }
575
580
  .bt-media-link:hover { color: var(--bt-text); background: var(--bt-hover); }
576
581
  .bt-media-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 6px; }
577
582
  .bt-media-tile { position: relative; aspect-ratio: 1; padding: 0; border: 1px solid var(--bt-line-soft); border-radius: var(--bt-r2); overflow: hidden; background: rgb(var(--bt-text-rgb) / .03); cursor: pointer; transition: border-color var(--bt-t1) var(--bt-ease), transform var(--bt-t2) var(--bt-ease-out); }
578
583
  .bt-media-tile:hover, .bt-media-tile:focus-visible { border-color: rgb(var(--bt-text-rgb) / .5); outline: none; transform: scale(1.02); }
579
584
  .bt-media-tile img, .bt-media-clip-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
580
585
  .bt-media-thumb-empty { display: block; width: 100%; height: 100%; }
581
- .bt-media-caption { position: absolute; inset-inline-end: 4px; bottom: 4px; padding: 2px 5px; border-radius: 5px; background: rgba(0, 0, 0, .62); color: #fff; font: 500 10.5px/1.3 var(--bt-mono); }
586
+ .bt-media-caption { position: absolute; inset-inline-end: 4px; bottom: 4px; padding: 2px 5px; border-radius: calc(5px * var(--bt-rs, 1)); background: rgba(0, 0, 0, .62); color: #fff; font: 500 10.5px/1.3 var(--bt-mono); }
582
587
  .bt-media-clips { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
583
588
  .bt-media-clip { display: flex; align-items: center; gap: 4px; }
584
589
  .bt-media-clip-main { flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; padding: 8px; border: 0; border-radius: var(--bt-r2); background: transparent; color: var(--bt-text); text-align: start; cursor: pointer; font: inherit; font-size: 13px; }
585
590
  .bt-media-clip-main:hover, .bt-media-clip-main:focus-visible { background: var(--bt-hover); outline: none; }
586
591
  .bt-media-clip-main small { margin-inline-start: auto; color: var(--bt-faint); font: 500 11px/1 var(--bt-mono); }
587
592
  .bt-media-clip-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
588
- .bt-media-clip-thumb { width: 48px; height: 48px; flex: none; border-radius: 7px; overflow: hidden; }
593
+ .bt-media-clip-thumb { width: 48px; height: 48px; flex: none; border-radius: calc(7px * var(--bt-rs, 1)); overflow: hidden; }
589
594
 
590
595
  /* ------------------------------------------------------------------------------------------------
591
596
  * Link drag (a link dragged out of a tab, or in from another app): drop zones with labels. */
592
597
  .bt-shell--link-drag .dv-drop-target > .dv-drop-target-dropzone > .dv-drop-target-selection,
593
598
  .bt-shell--link-drag .dv-drop-target-container .dv-drop-target-anchor {
594
599
  display: grid; place-items: center; overflow: hidden; box-sizing: border-box;
595
- background: rgb(var(--bt-accent-rgb) / .1); border: 1.5px solid rgb(var(--bt-accent-rgb) / .85); border-radius: 12px;
600
+ background: rgb(var(--bt-accent-rgb) / .1); border: 1.5px solid rgb(var(--bt-accent-rgb) / .85); border-radius: calc(12px * var(--bt-rs, 1));
596
601
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .04), inset 0 0 60px rgb(var(--bt-accent-rgb) / .12);
597
602
  }
598
603
  .bt-shell--link-drag .dv-drop-target-selection::after,
599
604
  .bt-shell--link-drag .dv-drop-target-anchor::after {
600
- content: 'Open as tab'; padding: 8px 13px; border-radius: 999px; background: var(--bt-raised); color: var(--bt-text);
605
+ content: 'Open as tab'; padding: 8px 13px; border-radius: calc(999px * var(--bt-rs, 1)); background: var(--bt-raised); color: var(--bt-text);
601
606
  font: 600 12px/1 var(--bt-ui); letter-spacing: .01em; white-space: nowrap;
602
607
  box-shadow: inset 0 0 0 1px var(--bt-line-strong), 0 10px 30px -10px rgba(0, 0, 0, .8);
603
608
  animation: bt-pop-in var(--bt-t2) var(--bt-ease-out);
@@ -607,7 +612,7 @@ html.bt-raised .bt-deck :is(.bt-col-head, .bt-compose-head) { background-color:
607
612
  .bt-shell--link-drag .dv-drop-target-selection.dv-drop-target-top::after, .bt-shell--link-drag .dv-drop-target-anchor.dv-drop-target-top::after { content: '\2191 Split up'; }
608
613
  .bt-shell--link-drag .dv-drop-target-selection.dv-drop-target-bottom::after, .bt-shell--link-drag .dv-drop-target-anchor.dv-drop-target-bottom::after { content: '\2193 Split down'; }
609
614
  /* Tab strip and the empty titlebar part of it: a new tab in that group. */
610
- .bt-shell--link-drag .dv-tabs-and-actions-container .dv-drop-target-selection { border-radius: 8px; }
615
+ .bt-shell--link-drag .dv-tabs-and-actions-container .dv-drop-target-selection { border-radius: calc(8px * var(--bt-rs, 1)); }
611
616
  .bt-shell--link-drag .dv-tabs-and-actions-container .dv-drop-target-selection::after { content: '+ New tab'; padding: 4px 9px; font-size: 11px; }
612
617
  .bt-shell--link-drag .dv-drop-target-small-vertical::after,
613
618
  .bt-shell--link-drag .dv-drop-target-small-horizontal::after { content: none; }
@@ -51,6 +51,8 @@ export declare const shell: {
51
51
  }>;
52
52
  profiles: ProfileSettings;
53
53
  restoring: boolean;
54
+ /** False until the saved layout was read back: an earlier save would overwrite it with an empty dock. */
55
+ layoutReady: boolean;
54
56
  /** Toolbar actions implemented by Shell.tsx (split view, the app's panel). */
55
57
  split: (_id: string, _direction: "right" | "below") => void;
56
58
  openPanel: (_from?: string) => void;
@@ -22,6 +22,8 @@ export const shell = {
22
22
  closed: [],
23
23
  profiles: defaultProfiles(),
24
24
  restoring: false,
25
+ /** False until the saved layout was read back: an earlier save would overwrite it with an empty dock. */
26
+ layoutReady: false,
25
27
  /** Toolbar actions implemented by Shell.tsx (split view, the app's panel). */
26
28
  split: (_id, _direction) => { },
27
29
  openPanel: (_from) => { },
@@ -264,7 +266,7 @@ let saveTimer;
264
266
  export function saveLayoutSoon() {
265
267
  clearTimeout(saveTimer);
266
268
  saveTimer = setTimeout(() => {
267
- if (!shell.api || shell.restoring)
269
+ if (!shell.api || shell.restoring || !shell.layoutReady)
268
270
  return;
269
271
  try {
270
272
  localStorage.setItem(LAYOUT_KEY, JSON.stringify(shell.api.toJSON()));
@@ -1 +1 @@
1
- {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../../../../shell/src/frame/state.ts"],"names":[],"mappings":"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","sourcesContent":["// Shared, non-React shell state: the dock, pane placeholders and the native webview reconciliation\n// (`tabs_sync`, one layout in flight at a time), shell overlays (the shell webview is raised above\n// the tab webviews while a menu, dialog or drag is open), profiles and session layout persistence.\n\nimport type { DockviewApi, IDockviewPanel } from 'dockview';\nimport { cssRgb, paneVisibility, raiseSupported, withNavRedundant } from '../paneModel.ts';\nimport { defaultProfiles, normalizeProfiles, tabProfile, type ProfileSettings } from '../profileModel.ts';\nimport type { PaneInfo } from './accountModel.ts';\nimport { currentWindow, invoke } from './bridge.ts';\nimport { columnSourceUrl, composeTabId, deckById, decks } from './deckStore.ts';\nimport type { PaletteAction } from './paletteModel.ts';\nimport { diag } from './diag.ts';\nimport { site } from './site.ts';\nimport { latestOnly } from './syncGate.ts';\n\n/** `profile`: the account profile (WebView data directory) the tab runs in; missing = default. */\n/** `besideOf`: the group whose \"beside\" link opened this tab; its group is that group's side pane. */\nexport type WebParams = { kind: 'web'; url: string; profile?: string; title?: string; favicon?: string; loading?: boolean; pinned?: boolean; besideOf?: string };\n/** The app's own tab (its settings panel, `site.panel`). */\nexport type PanelParams = { kind: 'panel'; section?: string; nonce?: number; pinned?: boolean };\n/** The new-tab page: drawn by the shell itself (no webview); `profile` is the account it opens links in. */\nexport type StartParams = { kind: 'start'; profile?: string; pinned?: boolean };\n/** A deck of site columns (DeckView.tsx); its columns are tab webviews of their own. */\nexport type DeckParams = { kind: 'deck'; deckId: string; pinned?: boolean };\nexport type TabParams = WebParams | PanelParams | StartParams | DeckParams;\n\nconst LAYOUT_KEY = 'bt.shell.layout.v1';\n\n/** Shared, non-React shell state: pane placeholders and the native webview reconciliation. */\nexport const shell = {\n api: null as DockviewApi | null,\n placeholders: new Map<string, HTMLElement>(),\n /**\n * Open shell overlays (menus, dialogs, palette, drag zones). While > 0 the shell webview is raised\n * above the tab webviews (panes stay visible under it), or, where it cannot be, they are hidden.\n */\n overlay: 0,\n /** Recently closed web tabs, newest last (Ctrl+Shift+T, new-tab page). */\n closed: [] as Array<{ url: string; profile?: string; title?: string }>,\n profiles: defaultProfiles() as ProfileSettings,\n restoring: false,\n /** Toolbar actions implemented by Shell.tsx (split view, the app's panel). */\n split: (_id: string, _direction: 'right' | 'below') => {},\n openPanel: (_from?: string) => {},\n /** Opens the new-tab page in the given profile. */\n newTab: (_profile: string) => {},\n /** The `homeUrl` setting (new-tab page \"Home\" link, first tab); `site.homeUrl` until read. */\n homeUrl: '',\n /** Opens `url` from the new-tab page: replaces that page (`startId`) or, without one, adds a tab. */\n openFromStart: (_url: string, _profile: string, _startId?: string) => {},\n /** Account switcher click: focus a visible pane of that account or open its feed beside (Shell.tsx). */\n openAccount: (_profile: string, _options?: { force?: boolean; url?: string }) => {},\n /** Opens `url` as a web tab in `profile` (a deck column's \"Open as tab\"). */\n openUrl: (_url: string, _profile: string) => {},\n /** Opens the app's panel at a section (e.g. the deck's settings button). */\n openPanelSection: (_section: string) => {},\n /** Runs a shell shortcut by name as if its keys were pressed (`new-tab`, `split-right`, `command-palette`, ...). */\n shortcut: (_name: string) => {},\n /** Runs a palette action (navigation only: open a deck, add a column, restore a workspace, ...). */\n run: (_action: PaletteAction) => {},\n};\n\n/** The app's panel tab id (`site.panel.id`, kept in saved layouts). */\nexport const panelId = () => site().panel.id;\n\n/** Replaces the profile list (after a native save) and tells mounted switchers and tabs. */\nexport function setProfiles(value: unknown) {\n shell.profiles = normalizeProfiles(value, site().accounts);\n window.dispatchEvent(new CustomEvent('bt-profiles'));\n scheduleSync();\n}\n\nexport const newTabId = () => `t${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n\nexport const isWeb = (panel: IDockviewPanel) => (panel.params as TabParams | undefined)?.kind === 'web';\n\n/** Every tab as the account switcher sees it. */\nexport function paneInfos(): PaneInfo[] {\n return (shell.api?.panels ?? []).map(panel => {\n const params = panel.params as TabParams | undefined;\n return {\n id: panel.id,\n kind: !params || params.kind === 'deck' ? 'panel' : params.kind,\n profile: params && params.kind !== 'panel' && params.kind !== 'deck' ? params.profile : undefined,\n url: params?.kind === 'web' ? params.url : undefined,\n visible: panel.api.isVisible,\n };\n });\n}\n\n/** Merge params without ever passing `undefined` (dockview deletes keys set to undefined). */\nexport function patchParams(panel: IDockviewPanel, patch: Partial<WebParams>) {\n const clean = Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== undefined));\n if (Object.keys(clean).length) panel.api.updateParameters(clean);\n}\n\nlet frame = 0;\nlet lastPayload = '';\n/** Last `navRedundant` per tab; a hidden tab keeps its value so it shows up without a flicker. */\nconst navRedundant = new Map<string, boolean>();\nexport function scheduleSync() {\n if (frame) return;\n frame = requestAnimationFrame(() => { frame = 0; void syncTabs(); });\n}\n\n/** Sends the layout again even though nothing moved: native code asked to build every tab webview anew (`tabs-rebuild`). */\nexport function resync() {\n lastPayload = '';\n scheduleSync();\n}\n\n/** Sends the tab rectangles now (e.g. so native code knows closed tabs are gone before a profile removal). */\nexport function flushSync(): Promise<void> {\n if (frame) { cancelAnimationFrame(frame); frame = 0; }\n return syncTabs();\n}\n\nfunction syncTabs(): Promise<void> {\n const api = shell.api;\n if (!api) return Promise.resolve();\n const boxes = api.panels.filter(isWeb).map(panel => {\n const params = panel.params as WebParams;\n const el = shell.placeholders.get(panel.id);\n const rect = el?.isConnected ? el.getBoundingClientRect() : null;\n const shown = !!rect && rect.width > 1 && rect.height > 1 && panel.api.isVisible;\n const { visible, parked } = paneVisibility({ shown, overlay: shell.overlay, raiseSupported: layer.supported });\n return {\n id: panel.id,\n url: params.url,\n profile: tabProfile(shell.profiles, params.profile).id,\n x: Math.round(rect?.left ?? 0),\n y: Math.round(rect?.top ?? 0),\n width: Math.round(rect?.width ?? 1),\n height: Math.round(rect?.height ?? 1),\n visible,\n // Not shown for a reason other than a shell overlay: only these drop to low memory.\n parked,\n };\n });\n // Only visible panes are judged (a shell overlay hides them all and so changes nothing).\n const items = withNavRedundant([...boxes, ...columnBoxes()], site().isSiteUrl, navRedundant);\n const payload = JSON.stringify(items);\n if (payload === lastPayload) return Promise.resolve();\n lastPayload = payload;\n saveLayoutSoon();\n // `viewport`: the window size this layout is for; native code re-bases it if the window was\n // resized while it was in flight (it also follows resizes itself, before the shell re-lays out).\n return sendLayout({ items, viewport: [window.innerWidth, window.innerHeight] });\n}\n\n/** One tabs_sync in flight at a time; during a drag only the newest layout waits (syncGate.ts). */\nconst sendLayout = latestOnly<{ items: unknown[]; viewport: [number, number] }>(args =>\n invoke('tabs_sync', args).then(() => {}, error => console.error('[shell] tabs_sync', error)));\n\n/**\n * Deck columns (and each deck's compose dock) of every open deck tab. A column on another page of\n * its deck has no placeholder: hidden, and parked (low memory) when the setting says so; a deck\n * tab in the background parks all of its columns.\n */\nfunction columnBoxes() {\n const api = shell.api;\n const composeUrl = site().deck?.compose?.url;\n if (!api) return [];\n const boxes = [];\n for (const panel of api.panels) {\n const params = panel.params as TabParams | undefined;\n if (params?.kind !== 'deck') continue;\n const deck = deckById(params.deckId);\n if (!deck) continue;\n const deckShown = panel.api.isVisible;\n const entries = deck.columns.map(column => ({ id: column.tabId, profile: column.profile, url: columnSourceUrl(column.source) }));\n const compose = decks.compose.get(deck.id);\n if (compose && composeUrl) entries.push({ id: composeTabId(deck.id), profile: compose.profile, url: composeUrl });\n for (const entry of entries) {\n if (!entry.url || !decks.ready.has(entry.id)) continue;\n const el = shell.placeholders.get(entry.id);\n const rect = el?.isConnected ? el.getBoundingClientRect() : null;\n const shown = !!rect && rect.width > 1 && rect.height > 1 && deckShown;\n boxes.push({\n id: entry.id,\n url: entry.url,\n profile: tabProfile(shell.profiles, entry.profile).id,\n x: Math.round(rect?.left ?? 0),\n y: Math.round(rect?.top ?? 0),\n width: Math.round(rect?.width ?? 1),\n height: Math.round(rect?.height ?? 1),\n visible: paneVisibility({ shown, overlay: shell.overlay, raiseSupported: layer.supported }).visible,\n parked: !shown && (decks.settings.parkOffPage || !deckShown),\n role: 'column' as const,\n });\n }\n }\n return boxes;\n}\n\nexport function setOverlay(delta: number) {\n const before = shell.overlay;\n shell.overlay = Math.max(0, before + delta);\n diag(`overlay ${before} -> ${shell.overlay}`);\n if ((before === 0) !== (shell.overlay === 0)) {\n window.dispatchEvent(new Event('bt-overlay-changed'));\n syncLayer();\n }\n scheduleSync();\n}\n\n/**\n * The shell webview's place relative to the tab webviews. `supported`: `shell_raise` works here\n * (Windows, Linux, macOS; probed once at startup, which also lowers a shell left raised by a reload). While raised,\n * `html.bt-raised` makes the page see-through where panes are (shell.css).\n */\nconst layer = { supported: false, raised: false, queue: Promise.resolve(), probed: false };\nlet layerProbe: Promise<void> = Promise.resolve();\nconst frames = () => new Promise<void>(resolve => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));\n\n/** The startup probe (createShell): whether this platform can raise the shell above its tabs. */\nexport function probeLayer() {\n if (layer.probed) return;\n layer.probed = true;\n // `localStorage['bt.dev.noRaise'] = '1'` (then reload): overlays hide the tabs as where raising\n // is not supported, for before/after comparisons.\n const off = (() => { try { return localStorage.getItem('bt.dev.noRaise') === '1'; } catch { return false; } })();\n layerProbe = invoke<boolean>('shell_raise', { on: false }).then(ok => { layer.supported = raiseSupported(ok, off); syncLayer(); scheduleSync(); }, () => {});\n}\n\n/** Wait until the startup cover has either raised the shell or hidden the native tabs. */\nexport async function flushLayer(): Promise<void> {\n await layerProbe;\n await layer.queue;\n}\n\n/**\n * While the shell is see-through, the few px of gutter between panes show the window's own\n * background: paint it the theme's ground (read before `bt-raised` clears the page's).\n */\nlet windowGround = '';\nfunction paintWindowGround() {\n const ground = cssRgb(getComputedStyle(document.documentElement).backgroundColor);\n if (!ground || ground.join() === windowGround) return;\n windowGround = ground.join();\n currentWindow().setBackgroundColor([...ground, 255]).catch(() => { windowGround = ''; });\n}\n\nfunction syncLayer() {\n if (!layer.supported) return;\n layer.queue = layer.queue.then(async () => {\n const want = shell.overlay > 0;\n if (want === layer.raised) return;\n const root = document.documentElement;\n if (want) {\n // See-through first (still under the tabs, so nothing changes on screen), then on top.\n paintWindowGround();\n root.classList.add('bt-raised');\n await frames();\n layer.raised = true;\n diag('raise: on');\n await invoke('shell_raise', { on: true });\n diag(`raised (hasFocus=${document.hasFocus()})`);\n } else {\n // Under the tabs first, then opaque again: the panes never blink.\n const refocus = document.hasFocus() && (!document.activeElement || document.activeElement === document.body);\n layer.raised = false;\n diag('raise: off');\n await invoke('shell_raise', { on: false });\n diag(`lowered (hasFocus=${document.hasFocus()})`);\n await frames();\n if (shell.overlay === 0) root.classList.remove('bt-raised');\n // Closed from the keyboard or a click in the shell (not by the window losing focus) with\n // nothing in the shell focused: typing goes back to the active pane.\n const active = shell.api?.activePanel;\n if (refocus && shell.overlay === 0 && active && isWeb(active)) void tabAction(active.id, 'focus');\n }\n }).catch(error => console.error('[shell] shell_raise', error));\n}\n\nlet saveTimer: ReturnType<typeof setTimeout> | undefined;\nexport function saveLayoutSoon() {\n clearTimeout(saveTimer);\n saveTimer = setTimeout(() => {\n if (!shell.api || shell.restoring) return;\n try { localStorage.setItem(LAYOUT_KEY, JSON.stringify(shell.api.toJSON())); } catch { /* Session restore is best effort. */ }\n }, 400);\n}\n\nexport function loadLayout(): unknown {\n try { return JSON.parse(localStorage.getItem(LAYOUT_KEY) || 'null'); } catch { return null; }\n}\n\nexport const tabAction = (id: string, action: 'back' | 'forward' | 'reload' | 'stop' | 'focus') =>\n invoke('tab_action', { id, action }).catch(() => {});\n"]}
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../../../../shell/src/frame/state.ts"],"names":[],"mappings":"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","sourcesContent":["// Shared, non-React shell state: the dock, pane placeholders and the native webview reconciliation\n// (`tabs_sync`, one layout in flight at a time), shell overlays (the shell webview is raised above\n// the tab webviews while a menu, dialog or drag is open), profiles and session layout persistence.\n\nimport type { DockviewApi, IDockviewPanel } from 'dockview';\nimport { cssRgb, paneVisibility, raiseSupported, withNavRedundant } from '../paneModel.ts';\nimport { defaultProfiles, normalizeProfiles, tabProfile, type ProfileSettings } from '../profileModel.ts';\nimport type { PaneInfo } from './accountModel.ts';\nimport { currentWindow, invoke } from './bridge.ts';\nimport { columnSourceUrl, composeTabId, deckById, decks } from './deckStore.ts';\nimport type { PaletteAction } from './paletteModel.ts';\nimport { diag } from './diag.ts';\nimport { site } from './site.ts';\nimport { latestOnly } from './syncGate.ts';\n\n/** `profile`: the account profile (WebView data directory) the tab runs in; missing = default. */\n/** `besideOf`: the group whose \"beside\" link opened this tab; its group is that group's side pane. */\nexport type WebParams = { kind: 'web'; url: string; profile?: string; title?: string; favicon?: string; loading?: boolean; pinned?: boolean; besideOf?: string };\n/** The app's own tab (its settings panel, `site.panel`). */\nexport type PanelParams = { kind: 'panel'; section?: string; nonce?: number; pinned?: boolean };\n/** The new-tab page: drawn by the shell itself (no webview); `profile` is the account it opens links in. */\nexport type StartParams = { kind: 'start'; profile?: string; pinned?: boolean };\n/** A deck of site columns (DeckView.tsx); its columns are tab webviews of their own. */\nexport type DeckParams = { kind: 'deck'; deckId: string; pinned?: boolean };\nexport type TabParams = WebParams | PanelParams | StartParams | DeckParams;\n\nconst LAYOUT_KEY = 'bt.shell.layout.v1';\n\n/** Shared, non-React shell state: pane placeholders and the native webview reconciliation. */\nexport const shell = {\n api: null as DockviewApi | null,\n placeholders: new Map<string, HTMLElement>(),\n /**\n * Open shell overlays (menus, dialogs, palette, drag zones). While > 0 the shell webview is raised\n * above the tab webviews (panes stay visible under it), or, where it cannot be, they are hidden.\n */\n overlay: 0,\n /** Recently closed web tabs, newest last (Ctrl+Shift+T, new-tab page). */\n closed: [] as Array<{ url: string; profile?: string; title?: string }>,\n profiles: defaultProfiles() as ProfileSettings,\n restoring: false,\n /** False until the saved layout was read back: an earlier save would overwrite it with an empty dock. */\n layoutReady: false,\n /** Toolbar actions implemented by Shell.tsx (split view, the app's panel). */\n split: (_id: string, _direction: 'right' | 'below') => {},\n openPanel: (_from?: string) => {},\n /** Opens the new-tab page in the given profile. */\n newTab: (_profile: string) => {},\n /** The `homeUrl` setting (new-tab page \"Home\" link, first tab); `site.homeUrl` until read. */\n homeUrl: '',\n /** Opens `url` from the new-tab page: replaces that page (`startId`) or, without one, adds a tab. */\n openFromStart: (_url: string, _profile: string, _startId?: string) => {},\n /** Account switcher click: focus a visible pane of that account or open its feed beside (Shell.tsx). */\n openAccount: (_profile: string, _options?: { force?: boolean; url?: string }) => {},\n /** Opens `url` as a web tab in `profile` (a deck column's \"Open as tab\"). */\n openUrl: (_url: string, _profile: string) => {},\n /** Opens the app's panel at a section (e.g. the deck's settings button). */\n openPanelSection: (_section: string) => {},\n /** Runs a shell shortcut by name as if its keys were pressed (`new-tab`, `split-right`, `command-palette`, ...). */\n shortcut: (_name: string) => {},\n /** Runs a palette action (navigation only: open a deck, add a column, restore a workspace, ...). */\n run: (_action: PaletteAction) => {},\n};\n\n/** The app's panel tab id (`site.panel.id`, kept in saved layouts). */\nexport const panelId = () => site().panel.id;\n\n/** Replaces the profile list (after a native save) and tells mounted switchers and tabs. */\nexport function setProfiles(value: unknown) {\n shell.profiles = normalizeProfiles(value, site().accounts);\n window.dispatchEvent(new CustomEvent('bt-profiles'));\n scheduleSync();\n}\n\nexport const newTabId = () => `t${Date.now().toString(36)}${Math.random().toString(36).slice(2, 8)}`;\n\nexport const isWeb = (panel: IDockviewPanel) => (panel.params as TabParams | undefined)?.kind === 'web';\n\n/** Every tab as the account switcher sees it. */\nexport function paneInfos(): PaneInfo[] {\n return (shell.api?.panels ?? []).map(panel => {\n const params = panel.params as TabParams | undefined;\n return {\n id: panel.id,\n kind: !params || params.kind === 'deck' ? 'panel' : params.kind,\n profile: params && params.kind !== 'panel' && params.kind !== 'deck' ? params.profile : undefined,\n url: params?.kind === 'web' ? params.url : undefined,\n visible: panel.api.isVisible,\n };\n });\n}\n\n/** Merge params without ever passing `undefined` (dockview deletes keys set to undefined). */\nexport function patchParams(panel: IDockviewPanel, patch: Partial<WebParams>) {\n const clean = Object.fromEntries(Object.entries(patch).filter(([, value]) => value !== undefined));\n if (Object.keys(clean).length) panel.api.updateParameters(clean);\n}\n\nlet frame = 0;\nlet lastPayload = '';\n/** Last `navRedundant` per tab; a hidden tab keeps its value so it shows up without a flicker. */\nconst navRedundant = new Map<string, boolean>();\nexport function scheduleSync() {\n if (frame) return;\n frame = requestAnimationFrame(() => { frame = 0; void syncTabs(); });\n}\n\n/** Sends the layout again even though nothing moved: native code asked to build every tab webview anew (`tabs-rebuild`). */\nexport function resync() {\n lastPayload = '';\n scheduleSync();\n}\n\n/** Sends the tab rectangles now (e.g. so native code knows closed tabs are gone before a profile removal). */\nexport function flushSync(): Promise<void> {\n if (frame) { cancelAnimationFrame(frame); frame = 0; }\n return syncTabs();\n}\n\nfunction syncTabs(): Promise<void> {\n const api = shell.api;\n if (!api) return Promise.resolve();\n const boxes = api.panels.filter(isWeb).map(panel => {\n const params = panel.params as WebParams;\n const el = shell.placeholders.get(panel.id);\n const rect = el?.isConnected ? el.getBoundingClientRect() : null;\n const shown = !!rect && rect.width > 1 && rect.height > 1 && panel.api.isVisible;\n const { visible, parked } = paneVisibility({ shown, overlay: shell.overlay, raiseSupported: layer.supported });\n return {\n id: panel.id,\n url: params.url,\n profile: tabProfile(shell.profiles, params.profile).id,\n x: Math.round(rect?.left ?? 0),\n y: Math.round(rect?.top ?? 0),\n width: Math.round(rect?.width ?? 1),\n height: Math.round(rect?.height ?? 1),\n visible,\n // Not shown for a reason other than a shell overlay: only these drop to low memory.\n parked,\n };\n });\n // Only visible panes are judged (a shell overlay hides them all and so changes nothing).\n const items = withNavRedundant([...boxes, ...columnBoxes()], site().isSiteUrl, navRedundant);\n const payload = JSON.stringify(items);\n if (payload === lastPayload) return Promise.resolve();\n lastPayload = payload;\n saveLayoutSoon();\n // `viewport`: the window size this layout is for; native code re-bases it if the window was\n // resized while it was in flight (it also follows resizes itself, before the shell re-lays out).\n return sendLayout({ items, viewport: [window.innerWidth, window.innerHeight] });\n}\n\n/** One tabs_sync in flight at a time; during a drag only the newest layout waits (syncGate.ts). */\nconst sendLayout = latestOnly<{ items: unknown[]; viewport: [number, number] }>(args =>\n invoke('tabs_sync', args).then(() => {}, error => console.error('[shell] tabs_sync', error)));\n\n/**\n * Deck columns (and each deck's compose dock) of every open deck tab. A column on another page of\n * its deck has no placeholder: hidden, and parked (low memory) when the setting says so; a deck\n * tab in the background parks all of its columns.\n */\nfunction columnBoxes() {\n const api = shell.api;\n const composeUrl = site().deck?.compose?.url;\n if (!api) return [];\n const boxes = [];\n for (const panel of api.panels) {\n const params = panel.params as TabParams | undefined;\n if (params?.kind !== 'deck') continue;\n const deck = deckById(params.deckId);\n if (!deck) continue;\n const deckShown = panel.api.isVisible;\n const entries = deck.columns.map(column => ({ id: column.tabId, profile: column.profile, url: columnSourceUrl(column.source) }));\n const compose = decks.compose.get(deck.id);\n if (compose && composeUrl) entries.push({ id: composeTabId(deck.id), profile: compose.profile, url: composeUrl });\n for (const entry of entries) {\n if (!entry.url || !decks.ready.has(entry.id)) continue;\n const el = shell.placeholders.get(entry.id);\n const rect = el?.isConnected ? el.getBoundingClientRect() : null;\n const shown = !!rect && rect.width > 1 && rect.height > 1 && deckShown;\n boxes.push({\n id: entry.id,\n url: entry.url,\n profile: tabProfile(shell.profiles, entry.profile).id,\n x: Math.round(rect?.left ?? 0),\n y: Math.round(rect?.top ?? 0),\n width: Math.round(rect?.width ?? 1),\n height: Math.round(rect?.height ?? 1),\n visible: paneVisibility({ shown, overlay: shell.overlay, raiseSupported: layer.supported }).visible,\n parked: !shown && (decks.settings.parkOffPage || !deckShown),\n role: 'column' as const,\n });\n }\n }\n return boxes;\n}\n\nexport function setOverlay(delta: number) {\n const before = shell.overlay;\n shell.overlay = Math.max(0, before + delta);\n diag(`overlay ${before} -> ${shell.overlay}`);\n if ((before === 0) !== (shell.overlay === 0)) {\n window.dispatchEvent(new Event('bt-overlay-changed'));\n syncLayer();\n }\n scheduleSync();\n}\n\n/**\n * The shell webview's place relative to the tab webviews. `supported`: `shell_raise` works here\n * (Windows, Linux, macOS; probed once at startup, which also lowers a shell left raised by a reload). While raised,\n * `html.bt-raised` makes the page see-through where panes are (shell.css).\n */\nconst layer = { supported: false, raised: false, queue: Promise.resolve(), probed: false };\nlet layerProbe: Promise<void> = Promise.resolve();\nconst frames = () => new Promise<void>(resolve => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));\n\n/** The startup probe (createShell): whether this platform can raise the shell above its tabs. */\nexport function probeLayer() {\n if (layer.probed) return;\n layer.probed = true;\n // `localStorage['bt.dev.noRaise'] = '1'` (then reload): overlays hide the tabs as where raising\n // is not supported, for before/after comparisons.\n const off = (() => { try { return localStorage.getItem('bt.dev.noRaise') === '1'; } catch { return false; } })();\n layerProbe = invoke<boolean>('shell_raise', { on: false }).then(ok => { layer.supported = raiseSupported(ok, off); syncLayer(); scheduleSync(); }, () => {});\n}\n\n/** Wait until the startup cover has either raised the shell or hidden the native tabs. */\nexport async function flushLayer(): Promise<void> {\n await layerProbe;\n await layer.queue;\n}\n\n/**\n * While the shell is see-through, the few px of gutter between panes show the window's own\n * background: paint it the theme's ground (read before `bt-raised` clears the page's).\n */\nlet windowGround = '';\nfunction paintWindowGround() {\n const ground = cssRgb(getComputedStyle(document.documentElement).backgroundColor);\n if (!ground || ground.join() === windowGround) return;\n windowGround = ground.join();\n currentWindow().setBackgroundColor([...ground, 255]).catch(() => { windowGround = ''; });\n}\n\nfunction syncLayer() {\n if (!layer.supported) return;\n layer.queue = layer.queue.then(async () => {\n const want = shell.overlay > 0;\n if (want === layer.raised) return;\n const root = document.documentElement;\n if (want) {\n // See-through first (still under the tabs, so nothing changes on screen), then on top.\n paintWindowGround();\n root.classList.add('bt-raised');\n await frames();\n layer.raised = true;\n diag('raise: on');\n await invoke('shell_raise', { on: true });\n diag(`raised (hasFocus=${document.hasFocus()})`);\n } else {\n // Under the tabs first, then opaque again: the panes never blink.\n const refocus = document.hasFocus() && (!document.activeElement || document.activeElement === document.body);\n layer.raised = false;\n diag('raise: off');\n await invoke('shell_raise', { on: false });\n diag(`lowered (hasFocus=${document.hasFocus()})`);\n await frames();\n if (shell.overlay === 0) root.classList.remove('bt-raised');\n // Closed from the keyboard or a click in the shell (not by the window losing focus) with\n // nothing in the shell focused: typing goes back to the active pane.\n const active = shell.api?.activePanel;\n if (refocus && shell.overlay === 0 && active && isWeb(active)) void tabAction(active.id, 'focus');\n }\n }).catch(error => console.error('[shell] shell_raise', error));\n}\n\nlet saveTimer: ReturnType<typeof setTimeout> | undefined;\nexport function saveLayoutSoon() {\n clearTimeout(saveTimer);\n saveTimer = setTimeout(() => {\n if (!shell.api || shell.restoring || !shell.layoutReady) return;\n try { localStorage.setItem(LAYOUT_KEY, JSON.stringify(shell.api.toJSON())); } catch { /* Session restore is best effort. */ }\n }, 400);\n}\n\nexport function loadLayout(): unknown {\n try { return JSON.parse(localStorage.getItem(LAYOUT_KEY) || 'null'); } catch { return null; }\n}\n\nexport const tabAction = (id: string, action: 'back' | 'forward' | 'reload' | 'stop' | 'focus') =>\n invoke('tab_action', { id, action }).catch(() => {});\n"]}
@@ -7,7 +7,7 @@
7
7
  import { setChromeIconPack } from "./iconPack.js";
8
8
  import { BOOT_CACHE_KEY } from "./boot.js";
9
9
  import { invoke } from "./bridge.js";
10
- import { CHROME_VAR_NAMES, chromeVars } from "./chromeTheme.js";
10
+ import { CHROME_VAR_NAMES, chromeEdges, chromeVars } from "./chromeTheme.js";
11
11
  import { SCOPES_DEFAULT, normalizeScopes, prunePanes, themeIdFor } from "./themeScopes.js";
12
12
  import { safe } from "./safeStore.js";
13
13
  import { shell } from "./state.js";
@@ -157,6 +157,13 @@ export function createThemeStore(adapter) {
157
157
  for (const [name, value] of Object.entries(vars))
158
158
  element.style.setProperty(name, value);
159
159
  }
160
+ /** The window's edge style (frame/edges.css). Global only: a pane theme brings its colors, fonts and radii, not its edges. */
161
+ function setEdges(edges) {
162
+ if (edges)
163
+ document.documentElement.dataset.wbEdges = edges;
164
+ else
165
+ delete document.documentElement.dataset.wbEdges;
166
+ }
160
167
  function chromeFontsFor(theme) {
161
168
  for (const family of adapter.googleFonts(theme, ['chrome', 'mono']))
162
169
  if (isInstalled(family))
@@ -170,6 +177,7 @@ export function createThemeStore(adapter) {
170
177
  // first-frame cache is left alone, so the next normal start paints the owner's theme again.
171
178
  if (safe.active) {
172
179
  setVars(document.documentElement, {});
180
+ setEdges(null);
173
181
  syncGroups();
174
182
  return;
175
183
  }
@@ -180,6 +188,7 @@ export function createThemeStore(adapter) {
180
188
  chromeFontsFor(global);
181
189
  const vars = chromeVars(adapter.chrome(global), own);
182
190
  setVars(document.documentElement, vars);
191
+ setEdges(chromeEdges(vars));
183
192
  try {
184
193
  setChromeIconPack(own ? null : adapter.iconPack?.(global, state.choice) ?? null);
185
194
  }
@@ -210,13 +219,19 @@ export function createThemeStore(adapter) {
210
219
  if (scoped && scoped.source !== 'global') {
211
220
  chromeFontsFor(scoped.theme);
212
221
  element.classList.add('wb-pane-theme');
213
- setVars(element, chromeVars(adapter.chrome(scoped.theme)));
222
+ const vars = chromeVars(adapter.chrome(scoped.theme));
223
+ setVars(element, vars);
214
224
  element.dataset.wbTheme = scoped.id;
225
+ // A pane's edges are its own theme's (edges.css: `.dv-groupview.wb-bevel`).
226
+ element.classList.toggle('wb-bevel', chromeEdges(vars) === 'bevel');
215
227
  }
216
- else if (element.classList.contains('wb-pane-theme')) {
217
- element.classList.remove('wb-pane-theme');
218
- setVars(element, {});
219
- delete element.dataset.wbTheme;
228
+ else {
229
+ if (element.classList.contains('wb-pane-theme')) {
230
+ element.classList.remove('wb-pane-theme');
231
+ setVars(element, {});
232
+ delete element.dataset.wbTheme;
233
+ }
234
+ element.classList.toggle('wb-bevel', !own && !safe.active && document.documentElement.dataset.wbEdges === 'bevel');
220
235
  }
221
236
  }
222
237
  }