dsh-any-background 0.3.5 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -76,7 +76,7 @@ A **DeepSeek Harness** appearance plugin: custom theme color, background wallpap
76
76
  - **Produced / Highlights** — Code blocks in conversation content (with their language banner), inline `code` highlight chips and produced chips share one opacity + blur slider. The opacity is the alpha of **each surface's own background color** (no second color stacked on top of the original), and the blur frosts that same layer so the wallpaper shows through the content.
77
77
  - **Right sidebar / bettersidebar surface** — One slider pair (`panelOpacity` / `blurs.panel`), two identities: without dsh-better-sidebar it reads "右方侧边栏" (Right sidebar) and drives the official right Sidebar's surface tokens and frosted blur (works on 0.1.5-rc.2 through 0.1.7); with dsh-better-sidebar installed it reads "bettersidebar" and takes over that plugin's bottom workbench panel (the official sidebar keeps responding too). The row is always visible.
78
78
  - **Header popovers** — The session-header dropdowns get their own opacity + blur pair: the Agent Team panel, the background-job list, the open-in-app / session-log menus and the subagent lineage tree. On 0.1.7 the open-in-app picker moved to a portal and the session-row menu became a dynamic slot, so the plugin observes the stable `conversation.session.header*` slot anchors and tags the open popover at runtime instead of relying on class shapes.
79
- - **Header bar (the session title row)** — The row carrying the session title, its actions and the view tabs gets a slider pair of its own. The host paints nothing there (the centre column's background shows straight through), so once a wallpaper is up the title and tabs sat on the raw picture while every masked surface around them did not. It now paints as a region tint, the same recipe as the chat column's card: the material is the plugin's main-background surface at this part's own opacity, so the bar reads as one band over the column rather than a second colour stacked on it, and the frost rides the row's own `backdrop-filter` — the row hosts no in-place overlay of its own (its dropdowns portal to `body`), so the backdrop root costs nothing and no underlay node is injected into a host element. The anchor is expressed in CSS (the row is the `conversation.session.header` slot's direct parent) instead of guessing a hashed class or tagging a host element at runtime; before `0.1.7-alpha.1` the host mounts that slot bare with no such element, so there the rule matches nothing and the part is simply inert.
79
+ - **Header bar (the session title row)** — The row carrying the session title, its actions and the view tabs gets a slider pair of its own. The host paints nothing there (the centre column's background shows straight through), so once a wallpaper is up the title and tabs sat on the raw picture while every masked surface around them did not. It now paints as a region tint, the same recipe as the chat column's card: the material is the plugin's main-background surface at this part's own opacity, so the bar reads as one band over the column rather than a second colour stacked on it, and the frost rides the row's own `backdrop-filter` — the row hosts no in-place overlay of its own (its dropdowns portal to `body`), so the backdrop root costs nothing and no underlay node is injected into a host element. The anchor is expressed in CSS (the row is the `conversation.session.header` slot's direct parent) instead of guessing a hashed class or tagging a host element at runtime; before `0.1.7-alpha.1` the host mounts that slot bare with no such element, so there the rule matches nothing and the part is simply inert. On the Windows desktop shell the same slider pair also drives the window caption band — its fill and its frost both read this card's two variables, so the caption area and the session title row can never disagree — and the native minimize/maximize/close block is handed `transparent` so Windows paints no background of its own, leaving the band itself showing through. A blank session marks the row `headerBlank` (a placeholder left with only its padding) and the plugin skips claiming it.
80
80
  - **Sidebar "Theme" page (dual mode)** — The same five pages (Color / Interface / Font / Background / Profiles) register into two surfaces: without dsh-better-sidebar, a "Theme" card is contributed to the **official right Sidebar's guide page** through its public extension points (`sidebarRightTabs` + the `sidebar.right.pane.tab` keyed seat); with dsh-better-sidebar installed, the page registers in that plugin's sidebar instead and the official guide card withdraws itself, so the two never duplicate. Settings panel, official sidebar and better-sidebar all share one page implementation and one state store — a change in any of them shows up everywhere. The shell adapts to the panel width, and a narrow panel tightens padding and falls back to a single column. On a host without the right Sidebar the registration silently never happens.
81
81
  - **Conversation View Cards** — The message list is wrapped in a translucent card automatically, and the trajectory page gets whole-page opacity & blur controls, letting the wallpaper shine through the content.
82
82
  - **Theme Export / Import** — One-click export to a self-contained `dsh-any-theme.json` (config + wallpaper, video embedded as a data URL) and import to restore it anywhere.
@@ -92,15 +92,12 @@ A **DeepSeek Harness** appearance plugin: custom theme color, background wallpap
92
92
 
93
93
  ## Changelog (latest two releases)
94
94
 
95
- ### v0.3.4 (Two new host lines: `0.2.0-rc.2` and `0.2.1-alpha.1`)
95
+ ### v0.3.6 (The 「标题栏」 card takes over the Windows caption band and the native button block — issue #23)
96
96
 
97
- - **A sticky menu group heading got its own token on `0.2.0-rc.2`** (`--dsw-alias-menu-group-header-fill`, replacing `ModelSelect`'s `.groupTitle{background:var(--dsw-specific-menu)}`), so the model list's heading follows the card / header opacity slider and the picked theme color again instead of sitting on the faded menu as an untinted, near-opaque band. This is the first patch line that needed two folders — rc.1 and rc.2 are the same prerelease channel with different facts — so its folder is named for the build.
98
- - **The turn-event row now fades in its own color**: since rc.2 it fills from `--dsw-alias-turn-trigger-bg` (dark mode points that at the interactive-hover fill, not the code-block one). The plugin reads the same chain the host writes, fallback included, so a newer host takes its new color, an older one takes the code-block color, and no release test enters the styling code.
99
- - **DSH `0.2.1-alpha.1` is supported**: `design-platform.css`, `MenuGroup` and `MenuSurface` are byte-identical to rc.2, and the new `shell.bottom` strip paints `--dsw-alias-bg-base` — the main-background token — so the existing slider already owns it.
100
- - **Small host releases no longer need a plugin release**: `engines.dsh`, the six gated `@deepseek-ai/dsh-*` peers and `dsh.compatibility` now close with `|| 0.2.1-alpha.1 || >=0.1.7-alpha.1` — the umbrella has no upper bound. From `0.1.7-rc.1` the host disables any plugin whose peer ranges do not name the running release, and a range that runs out is a wall in front of a plugin that would have kept working: an uncapped range hands a future 0.2.x or 0.3.x build the closest verified adapter plus a log line saying how far from `exact` that is, and the worst a wrong guess can cost is one slider not fading a surface it no longer recognizes. Installing on a new host still needs a `dsh web` restart — the peer check runs while the profile is composed.
101
- - **The cards that take the composer seat now frost with the input blur.** Approval, plan review and the question composer render *beside* `[data-composer-card]` and fill from the same `--dsw-specific-input-major`, so they faded with the input slider while the blur slider had nothing to act on — the card you are meant to read went straight onto the wallpaper. They now get the capsule's `::before` underlay, gated on a non-zero blur so the plugin still adds no stacking context for free, and the answer field joins the input group's stroke and placeholder bindings. The anchors (`[data-approval-key]`, `[data-plan-review-key]`, `[data-question-key]`) are unchanged from `0.1.5-rc.2` through `0.2.1-alpha.1`, so this is a range-wide binding in shared host facts, not a per-version one.
102
- - **The `invariant` companion is gone** (`lib/invariant.js`, its `exports` entry, its `@deepseek-ai/dsh-invariants` peer): nothing ever loaded it, and `0.2.1-alpha.1` deletes that package.
103
- - **The settings page's stylesheet now carries the plugin tag the other sheets have.** Through rc.2 the host's module system claimed *any* untagged `<style>` present while a plugin materialized and deleted it if that plugin failed; `0.2.1-alpha.1` narrowed the claim to the tags a factory added itself. Tagged, the sheet is safe on both.
97
+ - **The 「标题栏」 (Header bar) card now drives the desktop shell's caption band too.** That band is `AppFrame.module.css`'s `.frame::before` — full width, exactly `--dsh-windows-titlebar-height` tall — and it filled from the host's sidebar token, outside the plugin's reach, so moving the sidebar slider turned the window's caption clear and dropped the title and the Application / Edit menubar onto the raw wallpaper (issue #23, symptom 1). The band now paints from this card's material at this card's opacity and frosts with the same blur variable, so one slider pair drives the session title row and the window caption and the two can never disagree.
98
+ - **The native minimize/maximize/close block is no longer a block of its own.** Windows draws it from a single colour the desktop preload measures off a hidden probe (`--dsw-specific-sidebar-fill`, shipped over `dsh-desktop:windows-appearance` to `setTitleBarOverlay`). v0.3.5 pinned that probe to the material's opaque colour, which then disagreed with a band that had started following its sliders — a washed-out pale rectangle in light mode. The probe now reports `transparent`, so Windows paints **no** background there: the band already covers exactly those 40 px, so the block IS the band — one continuous surface, matching at every opacity. (Feeding the probe the card's paint along with its alpha was tried first: Windows then gives **each button its own background patch**, and the three stack into a lighter, visibly segmented block.) The glyphs are still measured separately off the same probe (`--dsw-alias-label-primary`), so they stay opaque and readable.
99
+ - **The content column's top-left corner is squared.** `AppFrame` rounds `.centerCol`'s top-left by 16 px and clips its overflow; once the frame is cleared to show the wallpaper, that notch let the wallpaper through under the conversation header's first pixels. The plugin now zeroes that corner (`dab-center-flat`).
100
+ - **A blank session is no longer claimed.** For a session-less or empty conversation the host marks the row `headerBlank` (`min-height:0`, no bottom rule), leaving only its padding and the corner control — deliberately a row that paints nothing. The plugin claimed it anyway and tinted it, so a box appeared exactly where there was meant to be no header bar. Claiming now skips that marker, and only one element can hold the class: a row that goes blank, or one the host replaces, has the class removed.
104
101
 
105
102
  ### v0.3.5 (The takeover-card frost no longer races the host for the card's position — issue #24)
106
103
 
package/README.zh.md CHANGED
@@ -76,7 +76,7 @@
76
76
  - **产出物 / 高亮内容** — 对话正文里的代码块(含语言顶栏)、行内 `code` 高亮芯片与产出物 chip 共用一支滑块:透明度只**调制这些表面原本的背景色**(不会在旧背景上再叠一层新色),模糊度给同一层表面加磨砂,壁纸从内容后方透出来。
77
77
  - **右方侧边栏 / bettersidebar 表面** — 同一对滑块(`panelOpacity` / `blurs.panel`)按宿主环境自动切换目标:未安装 dsh-better-sidebar 时叫「右方侧边栏」,驱动官方右侧栏的表面令牌与毛玻璃模糊(0.1.5-rc.2 至 0.1.7 均适用);安装了 dsh-better-sidebar 时改叫「bettersidebar」,接管其底部工作台面板(官方右侧栏同样生效)。该行现在始终显示。
78
78
  - **顶栏选项** — 会话头部的下拉浮层获得了独立的透明度 + 模糊滑块:Agent Team 面板、后台任务列表、「用其它应用打开」与「会话日志」菜单、子代理血缘树。由于这些浮层被 portal 到 `<body>`(与头部 DOM 断开),且 0.1.7 把「用其它应用打开」改成 portal、把会话行菜单改成动态槽位,插件改为在运行时监听稳定的 `conversation.session.header*` 槽位锚点来标记当前展开的浮层,不再依赖类名形状。
79
- - **标题栏(会话标题行)** — 会话顶部那条标题 / 操作 / 视图页签行终于有了自己的一对滑块。宿主自身不给它任何底色(中心列的底色直接透上来),所以壁纸一起来,标题与页签就直接压在图上、和周围被蒙住的表面割裂。现在它按「区块淡色」作画,配方与对话文本框那张卡一致:材质取插件主背景面的颜色、按本部件自己的透明度上色,读起来是压在列上的一条带,而不是叠上去的第二层颜色;模糊落在该行自己的 `backdrop-filter` 上——它内部没有就地弹出的浮层(头部下拉全是 portal 到 `body`),所以这个 backdrop root 没有代价,也不需要往宿主元素里插衬底层。这一行是**运行时认领**的:插件从 `conversation.session.header*` 槽位锚点向上找到最近的那个 `<header>` 再打上自己的类(与卡片、帧同款做法),不猜哈希类名、也不依赖宿主把槽位摆在哪个层级;`0.1.7-alpha.1` 之前宿主把槽位裸挂在会话根上、没有这一行元素,那种宿主上插件什么都不会认领,部件自然无效果。
79
+ - **标题栏(会话标题行)** — 会话顶部那条标题 / 操作 / 视图页签行终于有了自己的一对滑块。宿主自身不给它任何底色(中心列的底色直接透上来),所以壁纸一起来,标题与页签就直接压在图上、和周围被蒙住的表面割裂。现在它按「区块淡色」作画,配方与对话文本框那张卡一致:材质取插件主背景面的颜色、按本部件自己的透明度上色,读起来是压在列上的一条带,而不是叠上去的第二层颜色;模糊落在该行自己的 `backdrop-filter` 上——它内部没有就地弹出的浮层(头部下拉全是 portal 到 `body`),所以这个 backdrop root 没有代价,也不需要往宿主元素里插衬底层。这一行是**运行时认领**的:插件从 `conversation.session.header*` 槽位锚点向上找到最近的那个 `<header>` 再打上自己的类(与卡片、帧同款做法),不猜哈希类名、也不依赖宿主把槽位摆在哪个层级;`0.1.7-alpha.1` 之前宿主把槽位裸挂在会话根上、没有这一行元素,那种宿主上插件什么都不会认领,部件自然无效果。桌面壳(Windows)上这一对滑块同时驱动窗口标题条带:条带的底色与模糊都取本卡片这两个变量,窗口标题区与会话标题行永远一致;原生最小化/最大化/关闭那块改由取色探针报 `transparent`,让 Windows 不画自己的背景,露出的正是条带本身。空会话时宿主把该行标为 `headerBlank`(一条只留 padding 的占位),插件跳过认领。
80
80
  - **侧边栏「主题」页面(双模式)** — 同一套五页(色彩 / 界面 / 字体 / 背景 / 配置)注册到两处:未安装 dsh-better-sidebar 时,通过官方右侧栏的公开扩展点(`sidebarRightTabs` + `sidebar.right.pane.tab`)在**官方侧边栏**的引导页挂一张「主题」卡片,点开即五页;安装了 dsh-better-sidebar 时,改为在它的侧边栏注册同名页面,官方引导页上的卡片自动撤下,避免重复。两处(加设置面板共三处)共用同一套页面代码与同一份状态,改一处处处同步;外壳按面板宽度自适应,窄面板收紧内边距并回到单列。宿主没有右侧栏扩展点时静默不注册,不影响任何其它功能。
81
81
  - **对话视图卡片** — 消息列表自动包裹为半透明卡片,轨迹页可整页调节透明度与模糊,让壁纸从内容后方透出来。
82
82
  - **主题导出 / 导入** — 一键导出为自包含的 `dsh-any-theme.json`(配置 + 壁纸,视频以 data URL 内嵌),可随时导入还原。
@@ -92,15 +92,12 @@
92
92
 
93
93
  ## 更新日志(只保留最近两个版本)
94
94
 
95
- ### v0.3.4(新增两条宿主线:`0.2.0-rc.2` 与 `0.2.1-alpha.1`)
95
+ ### v0.3.6(「标题栏」卡片接管 Windows 标题条带与原生按钮区,修 issue #23)
96
96
 
97
- - **`0.2.0-rc.2` 给吸顶的菜单分组标题另发了令牌**(`--dsw-alias-menu-group-header-fill`,取代 `ModelSelect` 自己的 `.groupTitle{background:var(--dsw-specific-menu)}`):模型列表的分组标题重新跟着「卡片」「顶栏选项」两组滑块与所选主题色走,不再以一条不套色、近乎不透明的白带压在淡出的菜单上。这是第一条需要两个目录的补丁行——rc.1 与 rc.2 同属一个预发布渠道却交出不同的事实——所以新目录按构建命名。
98
- - **事件行改用他自己的颜色淡出**:rc.2 起该行从 `--dsw-alias-turn-trigger-bg` 取底(深色模式下这个别名指向交互态底色,不再是代码块那一层)。插件按宿主写下的链条去读,连带回退值一起,于是新构建拿新颜色、旧构建拿代码块颜色,样式代码里不引入任何版本判断。
99
- - **支持 DSH `0.2.1-alpha.1`**:`design-platform.css`、`MenuGroup`、`MenuSurface` 与 rc.2 逐字节相同;新增的 `shell.bottom` 条带画的是 `--dsw-alias-bg-base`——主背景令牌——背景透明度滑块本来就管着它。
100
- - **宿主小版本更新不再需要插件跟着发版**:`engines.dsh`、六个受门禁的 `@deepseek-ai/dsh-*` peer 与 `dsh.compatibility` 现在以 `|| 0.2.1-alpha.1 || >=0.1.7-alpha.1` 收尾——总括不设上界。从 `0.1.7-rc.1` 起,peer 范围没点名当前 release 的插件会被整个禁用,而一条写到头的范围等于在一款还能继续工作的插件前面砌墙:不设上界的范围会把未来的 0.2.x、0.3.x 构建交给最近的一份已核对事实,并在日志里写清它离 `exact` 有多远;猜错的最坏代价是某个滑块不再淡出它已认不出的表面。装到新宿主仍要重启 `dsh web`——peer 检查发生在 profile 组装时。
101
- - **接管输入位的那几张卡片现在跟着「输入模糊」磨砂了**:审批、计划回顾与问题卡渲染在 `[data-composer-card]` 的*旁边*,却填的是同一个 `--dsw-specific-input-major`——于是它们会随输入透明度淡出,模糊滑块却对它们无事可做,正是最该看清的那张卡直接压在壁纸上。现在它们拿到输入胶囊同款 `::before` 衬底,并且和胶囊一样只在模糊值非零时挂上,零值时插件不额外制造层叠上下文;答案输入框一并接进输入组的描边与占位符绑定。三张卡的锚点(`[data-approval-key]` / `[data-plan-review-key]` / `[data-question-key]`)从 `0.1.5-rc.2` 到 `0.2.1-alpha.1` 没有变过,所以这条绑定是全范围的事实,放在共享层而不是某个版本目录里。
102
- - **删掉 `invariant` 伴生入口**(`lib/invariant.js`、它的 `exports` 条目、它的 `@deepseek-ai/dsh-invariants` peer):从来没有任何一行装载它,而 `0.2.1-alpha.1` 已把这个包从宿主里移除。
103
- - **设置页那份样式表补上了其它表都有的插件标记**:到 rc.2 为止,宿主的模块系统会把当时*所有*未打标的 `<style>` 判给正在装配的那个插件,并在该插件失败时把它们删掉;`0.2.1-alpha.1` 把认领范围收窄到工厂自己新增的那些。打上标记后,两种宿主都动不了它。
97
+ - **「标题栏」卡片现在也驱动桌面壳的标题条带**:那条条带是 `AppFrame.module.css` 的 `.frame::before`,全宽、高度正好等于 `--dsh-windows-titlebar-height`,此前它按宿主的侧栏令牌上色、完全不归插件管——于是「侧栏」滑杆一动,窗口标题区就跟着变透明,标题与「应用 / 编辑」菜单栏直接压在裸壁纸上(issue #23 现象一)。现在条带的底色就是本卡片的材质在该卡片透明度下的取值,模糊取同一份模糊变量:一对滑块同时驱动会话标题行与窗口标题条带,两处不可能再对不上。
98
+ - **原生最小化 / 最大化 / 关闭那块不再是自己一块**:那块由 Windows 绘制,颜色来自桌面 preload 从一个隐藏探针量到的 `--dsw-specific-sidebar-fill`(经 `dsh-desktop:windows-appearance` 交给主进程 `setTitleBarOverlay`)。v0.3.5 把探针钉回材质实色,于是它和已经会跟随滑杆变淡的条带对不上——浅色模式下是一块偏白的方块。这里换了更彻底的做法:探针直接报 `transparent`,让 Windows **不画**这块背景。条带本来就严丝合缝地覆盖这 40 px,于是按钮区露出来的就是条带本身,一整块连续,任何透明度下都自动一致。(中途试过把卡片材质连同 alpha 喂给探针:Windows 会改成给**每个按钮各画一块自己的背景**,三块半透明叠在条带上,反而变成三块更亮的小方块。)字形颜色仍单独取 `--dsw-alias-label-primary`,保持不透明可读。
99
+ - **内容列左上角改成直角**:`AppFrame` 给 `.centerCol` 左上角 16 px 圆角并裁掉溢出,帧一旦被清成透明让壁纸透出来,那个缺口就在会话标题行的头几个像素下露出壁纸。插件现在把该角归零(`dab-center-flat`)。
100
+ - **空白会话不再被误认领**:无会话 / 空会话时宿主把这一行标成 `headerBlank`(`min-height:0`、去掉下边框),只留 padding 与右侧那个角落控件——本意就是一条什么都不画的占位行。插件此前照样认领并给它上底色,于是「本该没有标题栏」的时候凭空冒出一个框。现在认领前先排除该标记,并且认领改为「只有一个持有者」:切到空白态或宿主换掉这一行时,旧类会被摘掉。
104
101
 
105
102
  ### v0.3.5(接管卡磨砂不再与宿主抢卡片的定位,修 issue #24)
106
103
 
package/lib/client.js CHANGED
@@ -4017,37 +4017,67 @@ window.__ModuleLoader__.load({
4017
4017
  const MOBILE_HEADER_RULE = ".dsh-mobile-app-header{background:var(--dsh-any-op-bg,transparent)!important;backdrop-filter:var(--dsh-any-part-blur-global,none);-webkit-backdrop-filter:var(--dsh-any-part-blur-global,none)}";
4018
4018
  const HEADER_BAR_CLASS = "dab-header-bar";
4019
4019
  const HEADER_BAR_ANCHOR = "[data-slot^=\"conversation.session.header\"]";
4020
- /** The session header bar, or null where this host has no such element. */
4020
+ /** The session header bar, or null where this host has no such element.
4021
+ *
4022
+ * A BLANK session is excluded. `ConversationHeader` marks that row
4023
+ * `headerBlank`, whose rule zeroes its min-height and drops its bottom rule, so
4024
+ * the host paints nothing there and only the row's padding plus the corner
4025
+ * control remain. Claiming it paints a bar over a row the host deliberately
4026
+ * leaves empty — the box that appeared on a fresh session (0.2.0-rc.2). Matched
4027
+ * by the CSS-module LOCAL name: the hash prefix is build-specific, the suffix is
4028
+ * not, and a host that never emits the marker keeps the old behaviour. */
4021
4029
  function discoverHeaderBar() {
4022
4030
  if (centerEl === null || !document.body.contains(centerEl)) return null;
4023
4031
  const bar = centerEl.querySelector(HEADER_BAR_ANCHOR)?.closest("header");
4024
- return bar instanceof HTMLElement ? bar : null;
4032
+ if (!(bar instanceof HTMLElement)) return null;
4033
+ if (bar.className.includes("headerBlank")) return null;
4034
+ return bar;
4035
+ }
4036
+ /** Exactly one owner: the row the current conversation mounted. A row that went
4037
+ * blank, or one the host replaced, must not keep a class from an earlier pass. */
4038
+ let headerBarEl = null;
4039
+ function claimHeaderBar(bar) {
4040
+ if (headerBarEl !== null && headerBarEl !== bar) headerBarEl.classList.remove(HEADER_BAR_CLASS);
4041
+ headerBarEl = bar;
4042
+ if (bar !== null) bar.classList.add(HEADER_BAR_CLASS);
4025
4043
  }
4026
4044
  /** The bar's paint. The variables are written by `applyHeaderBar`; the class is
4027
4045
  * only ever added when they are, so a host the plugin is not theming keeps its
4028
4046
  * own header untouched. */
4029
4047
  const HEADER_BAR_RULE = `.${HEADER_BAR_CLASS}{background:var(--dsh-any-op-header-bar,transparent)!important;backdrop-filter:var(--dsh-any-blur-header-bar,none);-webkit-backdrop-filter:var(--dsh-any-blur-header-bar,none)}`;
4048
+ /** The 「标题栏」card's paint: the card's material at the card's opacity, empty
4049
+ * where the plugin is not theming. The conversation header row, the Windows
4050
+ * caption band, and — through the desktop preload's probe — the native
4051
+ * minimize/maximize/close block all read this one value. */
4052
+ function headerBarPaint(src) {
4053
+ const base = (src === void 0 ? paletteTokens() ?? readHostOpacityTokens() : src)?.["--dsw-alias-bg-base"];
4054
+ return base === void 0 ? "" : toRgba(base, rHeaderBarOpacity());
4055
+ }
4030
4056
  /** Claim the bar and write its material + frost. `surfaces` arrives from the token
4031
4057
  * funnel, which already has the resolved source list; the settings sliders and the
4032
4058
  * parts pass call it without one and the sources are re-resolved here. */
4033
4059
  function applyHeaderBar(surfaces) {
4034
- const base = (surfaces === void 0 ? paletteTokens() ?? readHostOpacityTokens() : surfaces)?.["--dsw-alias-bg-base"];
4060
+ const src = surfaces === void 0 ? paletteTokens() ?? readHostOpacityTokens() : surfaces;
4035
4061
  const root = document.documentElement;
4036
4062
  discoverParts();
4037
4063
  const bar = discoverHeaderBar();
4038
- if (base === void 0) {
4039
- if (bar !== null) bar.classList.remove(HEADER_BAR_CLASS);
4064
+ const paint = headerBarPaint(src);
4065
+ if (paint === "") {
4066
+ claimHeaderBar(null);
4040
4067
  root.style.removeProperty("--dsh-any-op-header-bar");
4041
4068
  root.style.removeProperty("--dsh-any-blur-header-bar");
4069
+ applyNativeCaption(surfaces);
4042
4070
  return;
4043
4071
  }
4044
- root.style.setProperty("--dsh-any-op-header-bar", toRgba(base, rHeaderBarOpacity()));
4072
+ root.style.setProperty("--dsh-any-op-header-bar", paint);
4045
4073
  const px = rBlurs().headerBar;
4046
4074
  if (px > 0) root.style.setProperty("--dsh-any-blur-header-bar", `blur(${px}px)`);
4047
4075
  else root.style.removeProperty("--dsh-any-blur-header-bar");
4048
- if (bar !== null) bar.classList.add(HEADER_BAR_CLASS);
4076
+ claimHeaderBar(bar);
4077
+ applyNativeCaption(surfaces);
4049
4078
  }
4050
4079
  const CAPTION_FRAME_CLASS = "dab-frame-caption";
4080
+ const FLAT_CENTER_CLASS = "dab-center-flat";
4051
4081
  const WCO_PROBE_SEL = "body > span[style*=\"--dsw-specific-sidebar-fill\"]";
4052
4082
  let wcoStyleEl = null;
4053
4083
  function ensureWcoStyle() {
@@ -4076,14 +4106,21 @@ window.__ModuleLoader__.load({
4076
4106
  * else, so no match means no desktop caption and the rule is inert. */
4077
4107
  function applyNativeCaption(surfaces) {
4078
4108
  if (!document.documentElement.hasAttribute("data-windows-titlebar")) return;
4079
- const fill = captionFill(surfaces === void 0 ? paletteTokens() ?? readHostOpacityTokens() : surfaces);
4080
- const css = fill === "" ? "" : `${WCO_PROBE_SEL}{--dsw-specific-sidebar-fill:${fill}}[data-windows-titlebar] .${CAPTION_FRAME_CLASS}::before{background:${fill}!important}`;
4109
+ const src = surfaces === void 0 ? paletteTokens() ?? readHostOpacityTokens() : surfaces;
4110
+ const fill = captionFill(src);
4111
+ const paint = headerBarPaint(src) || fill;
4112
+ const css = fill === "" ? "" : `${WCO_PROBE_SEL}{--dsw-specific-sidebar-fill:transparent}[data-windows-titlebar] .${CAPTION_FRAME_CLASS}::before{background:var(--dsh-any-op-header-bar,${paint})!important;backdrop-filter:var(--dsh-any-blur-header-bar,none);-webkit-backdrop-filter:var(--dsh-any-blur-header-bar,none)}[data-windows-titlebar] .${FLAT_CENTER_CLASS}{border-top-left-radius:0!important}`;
4081
4113
  const el = ensureWcoStyle();
4082
4114
  if (el.textContent !== css) el.textContent = css;
4083
4115
  discoverParts();
4084
4116
  if (frameEl === null) return;
4085
- if (css === "") frameEl.classList.remove(CAPTION_FRAME_CLASS);
4086
- else frameEl.classList.add(CAPTION_FRAME_CLASS);
4117
+ if (css === "") {
4118
+ frameEl.classList.remove(CAPTION_FRAME_CLASS);
4119
+ centerEl?.classList.remove(FLAT_CENTER_CLASS);
4120
+ } else {
4121
+ frameEl.classList.add(CAPTION_FRAME_CLASS);
4122
+ centerEl?.classList.add(FLAT_CENTER_CLASS);
4123
+ }
4087
4124
  }
4088
4125
  /** Mirror of the bg-part blur on :root. --dsh-any-part-blur is element-scoped
4089
4126
  * to the columns, so surfaces outside their subtree (the mobile header, or
@@ -5403,7 +5440,9 @@ window.__ModuleLoader__.load({
5403
5440
  document.documentElement.style.removeProperty("--dsh-any-op-header-bar");
5404
5441
  document.documentElement.style.removeProperty("--dsh-any-blur-header-bar");
5405
5442
  document.querySelectorAll(`.${HEADER_BAR_CLASS}`).forEach((el) => el.classList.remove(HEADER_BAR_CLASS));
5443
+ headerBarEl = null;
5406
5444
  frameEl?.classList.remove(CAPTION_FRAME_CLASS);
5445
+ document.querySelectorAll(`.${FLAT_CENTER_CLASS}`).forEach((el) => el.classList.remove(FLAT_CENTER_CLASS));
5407
5446
  wcoStyleEl?.remove();
5408
5447
  wcoStyleEl = null;
5409
5448
  document.documentElement.style.removeProperty("--dsh-any-blur-panel");