dsh-any-background 0.3.4 → 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/lib/client.js CHANGED
@@ -56,6 +56,7 @@ window.__ModuleLoader__.load({
56
56
  guideDesc: "管理主题色、壁纸与界面透明度",
57
57
  uiProduced: "产出物/高亮内容",
58
58
  uiHeader: "顶栏选项",
59
+ uiHeaderBar: "标题栏",
59
60
  fontPageTitle: "字体与描边",
60
61
  fontTitle: "自定义字体",
61
62
  fontHint: "支持 ttf/otf/woff/woff2 字体文件(上限 100MB),将应用到整个界面的文字;代码块的等宽字体保持不变。中文字体通常有几十 MB,首次上传与刷新加载需要片刻",
@@ -247,6 +248,7 @@ window.__ModuleLoader__.load({
247
248
  guideDesc: "Theme color, wallpaper and interface opacity in the right sidebar",
248
249
  uiProduced: "Produced / highlights",
249
250
  uiHeader: "Header popovers",
251
+ uiHeaderBar: "Header bar",
250
252
  fontPageTitle: "Font & outline",
251
253
  fontTitle: "Custom font",
252
254
  fontHint: "Accepts ttf/otf/woff/woff2 files (up to 100MB) and applies them to the whole interface; code blocks keep their monospace stack. CJK fonts routinely span tens of MB, so the first upload and each reload take a moment",
@@ -426,7 +428,8 @@ window.__ModuleLoader__.load({
426
428
  input: 30,
427
429
  panel: 30,
428
430
  produced: 30,
429
- header: 30
431
+ header: 30,
432
+ headerBar: 30
430
433
  },
431
434
  strokes: {
432
435
  bg: {
@@ -478,6 +481,11 @@ window.__ModuleLoader__.load({
478
481
  width: 0,
479
482
  color: "auto",
480
483
  customColor: "#808080"
484
+ },
485
+ headerBar: {
486
+ width: 0,
487
+ color: "auto",
488
+ customColor: "#808080"
481
489
  }
482
490
  },
483
491
  settingsOpacity: .5,
@@ -509,6 +517,7 @@ window.__ModuleLoader__.load({
509
517
  panelOpacity: .5,
510
518
  producedOpacity: .5,
511
519
  headerOpacity: .5,
520
+ headerBarOpacity: .5,
512
521
  profiles: [],
513
522
  rotation: {
514
523
  enabled: false,
@@ -649,7 +658,8 @@ window.__ModuleLoader__.load({
649
658
  "input",
650
659
  "panel",
651
660
  "produced",
652
- "header"
661
+ "header",
662
+ "headerBar"
653
663
  ]) {
654
664
  const v = b[k];
655
665
  out[k] = typeof v === "number" ? Math.min(60, Math.max(0, v)) : DEFAULT_CONFIG.blurs[k];
@@ -666,7 +676,8 @@ window.__ModuleLoader__.load({
666
676
  "input",
667
677
  "panel",
668
678
  "produced",
669
- "header"
679
+ "header",
680
+ "headerBar"
670
681
  ];
671
682
  const STROKE_COLOR_KEYS = [
672
683
  "auto",
@@ -718,6 +729,9 @@ window.__ModuleLoader__.load({
718
729
  function rHeaderOpacity() {
719
730
  return clamp01(cfg.headerOpacity, DEFAULT_CONFIG.headerOpacity);
720
731
  }
732
+ function rHeaderBarOpacity() {
733
+ return clamp01(cfg.headerBarOpacity, DEFAULT_CONFIG.headerBarOpacity);
734
+ }
721
735
  function rBgState() {
722
736
  return cfg.bgState;
723
737
  }
@@ -782,7 +796,8 @@ window.__ModuleLoader__.load({
782
796
  trajectoryOpacity: rTrajectoryOpacity(),
783
797
  panelOpacity: rPanelOpacity(),
784
798
  producedOpacity: rProducedOpacity(),
785
- headerOpacity: rHeaderOpacity()
799
+ headerOpacity: rHeaderOpacity(),
800
+ headerBarOpacity: rHeaderBarOpacity()
786
801
  };
787
802
  }
788
803
  /** Apply an appearance snapshot onto cfg (meta fields untouched). */
@@ -805,6 +820,7 @@ window.__ModuleLoader__.load({
805
820
  cfg.panelOpacity = clamp01(ap.panelOpacity, DEFAULT_CONFIG.panelOpacity);
806
821
  cfg.producedOpacity = clamp01(ap.producedOpacity, DEFAULT_CONFIG.producedOpacity);
807
822
  cfg.headerOpacity = clamp01(ap.headerOpacity, DEFAULT_CONFIG.headerOpacity);
823
+ cfg.headerBarOpacity = clamp01(ap.headerBarOpacity, DEFAULT_CONFIG.headerBarOpacity);
808
824
  }
809
825
  const num = (n, def) => typeof n === "number" ? n : def;
810
826
  const cl = (n, lo, hi, def) => typeof n === "number" ? Math.min(hi, Math.max(lo, n)) : def;
@@ -839,7 +855,8 @@ window.__ModuleLoader__.load({
839
855
  trajectoryOpacity: clamp01(ac.trajectoryOpacity, DEFAULT_CONFIG.trajectoryOpacity),
840
856
  panelOpacity: clamp01(ac.panelOpacity, DEFAULT_CONFIG.panelOpacity),
841
857
  producedOpacity: clamp01(ac.producedOpacity, DEFAULT_CONFIG.producedOpacity),
842
- headerOpacity: clamp01(ac.headerOpacity, DEFAULT_CONFIG.headerOpacity)
858
+ headerOpacity: clamp01(ac.headerOpacity, DEFAULT_CONFIG.headerOpacity),
859
+ headerBarOpacity: clamp01(ac.headerBarOpacity, DEFAULT_CONFIG.headerBarOpacity)
843
860
  }
844
861
  });
845
862
  }
@@ -905,7 +922,8 @@ window.__ModuleLoader__.load({
905
922
  "input",
906
923
  "panel",
907
924
  "produced",
908
- "header"
925
+ "header",
926
+ "headerBar"
909
927
  ]) blurs[k] = num(bl[k], DEFAULT_CONFIG.blurs[k]);
910
928
  const bgType = [
911
929
  "video",
@@ -949,6 +967,7 @@ window.__ModuleLoader__.load({
949
967
  panelOpacity: clamp01(c.panelOpacity, DEFAULT_CONFIG.panelOpacity),
950
968
  producedOpacity: clamp01(c.producedOpacity, DEFAULT_CONFIG.producedOpacity),
951
969
  headerOpacity: clamp01(c.headerOpacity, DEFAULT_CONFIG.headerOpacity),
970
+ headerBarOpacity: clamp01(c.headerBarOpacity, DEFAULT_CONFIG.headerBarOpacity),
952
971
  profiles: adoptProfiles(c.profiles),
953
972
  rotation: adoptRotation(c.rotation),
954
973
  schedule: adoptSchedule(c.schedule),
@@ -1168,7 +1187,24 @@ window.__ModuleLoader__.load({
1168
1187
  *
1169
1188
  * The marker sits on the wrapper, the fill on its child card:
1170
1189
  * `[data-approval-key] > div`, `[data-plan-review-key] > section`,
1171
- * `[data-question-key] > section`. */
1190
+ * `[data-question-key] > section`.
1191
+ *
1192
+ * One more fact these three share, and it is the reason the input-frost
1193
+ * treatment for them lives in a runtime pass instead of a stylesheet rule:
1194
+ * NO release in range declares `position` on any of the three cards (checked
1195
+ * per tag — 0 hits for `position:` in `ApprovalPanel.module.css`,
1196
+ * `PlanReviewPanel.module.css` and `QuestionComposer.module.css`), so unlike
1197
+ * the fallback capsule — whose `.card` is `position:relative` on every tag —
1198
+ * the host does not hand the plugin a containing block to mount a
1199
+ * `z-index:-1` underlay on. Writing that `position` from the plugin's own
1200
+ * stylesheet turns the card's box into a cascade race with anything else that
1201
+ * positions it: a host build that caps the card with a percentage
1202
+ * `max-height` loses its absolute containing block the moment a plugin rule
1203
+ * wins that race, and the whole chain collapses — content outside the card,
1204
+ * buttons off the viewport (dsh-any-background issue #24). The consumer that
1205
+ * needs the containing block (`applyTakeoverFrost`) therefore probes each card
1206
+ * at runtime and only anchors a box whose computed position is `static`; see
1207
+ * `inputBlurRule`. */
1172
1208
  const COMPOSER_TAKEOVER_CARD = "[data-approval-key]>div,[data-plan-review-key]>section,[data-question-key]>section";
1173
1209
  /** The takeover cards' free-text answer field — only the question composer has
1174
1210
  * one (approval and plan review are button rows). Form controls do not inherit
@@ -3882,6 +3918,8 @@ window.__ModuleLoader__.load({
3882
3918
  for (const name of appliedTokenNames) document.body.style.removeProperty(name);
3883
3919
  appliedTokenNames = Object.keys(tokens);
3884
3920
  }
3921
+ applyHeaderBar(surfaces);
3922
+ applyNativeCaption(surfaces);
3885
3923
  if (surfaces === null) {
3886
3924
  if (!hasColor && override === "auto" && verdict === null) clearThemeTokens();
3887
3925
  return;
@@ -3928,8 +3966,10 @@ window.__ModuleLoader__.load({
3928
3966
  return `${POPOVER_MENU_SEL}{${menuFrost(CARD_BLUR_VAR)}}${POPOVER_OTHER_SEL}{${elementFrostDecl(`var(${CARD_BLUR_VAR},none)`)}}`;
3929
3967
  }
3930
3968
  const INPUT_FROST_CLASS = "dab-input-frost";
3969
+ const TAKEOVER_FROST_CLASS = "dab-takeover-frost";
3970
+ const TAKEOVER_POS_ATTR = "data-dab-pos-patched";
3931
3971
  function inputBlurRule() {
3932
- return `.${INPUT_FROST_CLASS} [data-composer-card]{position:relative;isolation:isolate}.${INPUT_FROST_CLASS} [data-composer-card]::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;border-radius:inherit;-webkit-backdrop-filter:var(--dsh-any-input-blur,none);backdrop-filter:var(--dsh-any-input-blur,none)}.${INPUT_FROST_CLASS} ${COMPOSER_TAKEOVER_CARD}{position:relative;isolation:isolate}.${INPUT_FROST_CLASS} ${COMPOSER_TAKEOVER_CARD}::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;border-radius:inherit;-webkit-backdrop-filter:var(--dsh-any-input-blur,none);backdrop-filter:var(--dsh-any-input-blur,none)}[data-cordis-panel]{-webkit-backdrop-filter:var(--dsh-any-input-blur,none);backdrop-filter:var(--dsh-any-input-blur,none)}[data-cordis-panel]{${menuFillDecls("var(--dsh-any-op-menu-cordis)!important")}}`;
3972
+ return `.${INPUT_FROST_CLASS} [data-composer-card]{position:relative;isolation:isolate}.${INPUT_FROST_CLASS} [data-composer-card]::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;border-radius:inherit;-webkit-backdrop-filter:var(--dsh-any-input-blur,none);backdrop-filter:var(--dsh-any-input-blur,none)}.${TAKEOVER_FROST_CLASS}{isolation:isolate}.${TAKEOVER_FROST_CLASS}::before{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;border-radius:inherit;-webkit-backdrop-filter:var(--dsh-any-input-blur,none);backdrop-filter:var(--dsh-any-input-blur,none)}.${TAKEOVER_FROST_CLASS}:has([role="dialog"]){isolation:auto}[data-cordis-panel]{-webkit-backdrop-filter:var(--dsh-any-input-blur,none);backdrop-filter:var(--dsh-any-input-blur,none)}[data-cordis-panel]{${menuFillDecls("var(--dsh-any-op-menu-cordis)!important")}}`;
3933
3973
  }
3934
3974
  function applyInputBlur(px) {
3935
3975
  const root = document.documentElement;
@@ -3937,8 +3977,151 @@ window.__ModuleLoader__.load({
3937
3977
  else root.classList.remove(INPUT_FROST_CLASS);
3938
3978
  if (px > 0) root.style.setProperty("--dsh-any-input-blur", `blur(${px}px)`);
3939
3979
  else root.style.removeProperty("--dsh-any-input-blur");
3980
+ applyTakeoverFrost(px);
3981
+ }
3982
+ /** Carry the input frost on the seat's takeover cards (approval / plan review /
3983
+ * question), the capsule's siblings — see `inputBlurRule` for the recipe and
3984
+ * why it is attached here rather than by a stylesheet selector.
3985
+ *
3986
+ * The anchor probe is the `setBlur` guard: `position:relative` is written
3987
+ * inline ONLY where the host left the card `static`, and remembered with
3988
+ * `TAKEOVER_POS_ATTR` so clearing it is this function's job. A card a host or a
3989
+ * desktop shell positions itself is left exactly as it is — its own position
3990
+ * supplies the underlay's containing block — so no host box ever has its
3991
+ * position decided by this plugin's cascade (issue #24).
3992
+ *
3993
+ * Idempotent and cheap in the steady state: cards already carrying the class
3994
+ * (or already clear of it) are skipped without a style read. */
3995
+ function applyTakeoverFrost(px) {
3996
+ const cards = document.querySelectorAll(COMPOSER_TAKEOVER_CARD);
3997
+ if (px > 0) {
3998
+ for (const card of cards) {
3999
+ if (card.classList.contains(TAKEOVER_FROST_CLASS)) continue;
4000
+ if (getComputedStyle(card).position === "static") {
4001
+ card.style.position = "relative";
4002
+ card.setAttribute(TAKEOVER_POS_ATTR, "1");
4003
+ }
4004
+ card.classList.add(TAKEOVER_FROST_CLASS);
4005
+ }
4006
+ return;
4007
+ }
4008
+ for (const card of cards) {
4009
+ if (!card.classList.contains(TAKEOVER_FROST_CLASS)) continue;
4010
+ card.classList.remove(TAKEOVER_FROST_CLASS);
4011
+ if (card.getAttribute(TAKEOVER_POS_ATTR) === "1") {
4012
+ card.style.removeProperty("position");
4013
+ card.removeAttribute(TAKEOVER_POS_ATTR);
4014
+ }
4015
+ }
3940
4016
  }
3941
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
+ const HEADER_BAR_CLASS = "dab-header-bar";
4019
+ const HEADER_BAR_ANCHOR = "[data-slot^=\"conversation.session.header\"]";
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. */
4029
+ function discoverHeaderBar() {
4030
+ if (centerEl === null || !document.body.contains(centerEl)) return null;
4031
+ const bar = centerEl.querySelector(HEADER_BAR_ANCHOR)?.closest("header");
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);
4043
+ }
4044
+ /** The bar's paint. The variables are written by `applyHeaderBar`; the class is
4045
+ * only ever added when they are, so a host the plugin is not theming keeps its
4046
+ * own header untouched. */
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
+ }
4056
+ /** Claim the bar and write its material + frost. `surfaces` arrives from the token
4057
+ * funnel, which already has the resolved source list; the settings sliders and the
4058
+ * parts pass call it without one and the sources are re-resolved here. */
4059
+ function applyHeaderBar(surfaces) {
4060
+ const src = surfaces === void 0 ? paletteTokens() ?? readHostOpacityTokens() : surfaces;
4061
+ const root = document.documentElement;
4062
+ discoverParts();
4063
+ const bar = discoverHeaderBar();
4064
+ const paint = headerBarPaint(src);
4065
+ if (paint === "") {
4066
+ claimHeaderBar(null);
4067
+ root.style.removeProperty("--dsh-any-op-header-bar");
4068
+ root.style.removeProperty("--dsh-any-blur-header-bar");
4069
+ applyNativeCaption(surfaces);
4070
+ return;
4071
+ }
4072
+ root.style.setProperty("--dsh-any-op-header-bar", paint);
4073
+ const px = rBlurs().headerBar;
4074
+ if (px > 0) root.style.setProperty("--dsh-any-blur-header-bar", `blur(${px}px)`);
4075
+ else root.style.removeProperty("--dsh-any-blur-header-bar");
4076
+ claimHeaderBar(bar);
4077
+ applyNativeCaption(surfaces);
4078
+ }
4079
+ const CAPTION_FRAME_CLASS = "dab-frame-caption";
4080
+ const FLAT_CENTER_CLASS = "dab-center-flat";
4081
+ const WCO_PROBE_SEL = "body > span[style*=\"--dsw-specific-sidebar-fill\"]";
4082
+ let wcoStyleEl = null;
4083
+ function ensureWcoStyle() {
4084
+ if (wcoStyleEl?.isConnected) return wcoStyleEl;
4085
+ wcoStyleEl = document.createElement("style");
4086
+ wcoStyleEl.dataset.plugin = "dsh-any-background-wco";
4087
+ document.head.appendChild(wcoStyleEl);
4088
+ return wcoStyleEl;
4089
+ }
4090
+ /** The band's opaque material, or '' when the plugin has no theme to assert. The
4091
+ * sampled sidebar fill is already opaque in both source paths (the plugin's
4092
+ * palette builds `hsl()`, the host's own token is a static colour) — it only
4093
+ * misses on a host that exposes neither, and then the neutral the plugin builds
4094
+ * for the effective scheme stands in so the band still tracks the label ink. */
4095
+ function captionFill(src) {
4096
+ const sampled = src?.["--dsw-specific-sidebar-fill"];
4097
+ if (sampled !== void 0) return sampled;
4098
+ if (paletteTokens() === null && rBgDark() === null) return "";
4099
+ const dark = rScheme() === "dark";
4100
+ return genTokens(220, .04, dark ? .14 : .92, dark ? "dark" : "light").tokens["--dsw-specific-sidebar-fill"] ?? "";
4101
+ }
4102
+ /** Write the caption rule and mark the frame it targets. The frame is the
4103
+ * plugin's own discovery (`discoverParts`), not a guessed hashed class name. The
4104
+ * probe selector is a verified shape: an inline style that mentions the sidebar
4105
+ * token on a body-level span is the desktop preload's caption probe and nothing
4106
+ * else, so no match means no desktop caption and the rule is inert. */
4107
+ function applyNativeCaption(surfaces) {
4108
+ if (!document.documentElement.hasAttribute("data-windows-titlebar")) return;
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}`;
4113
+ const el = ensureWcoStyle();
4114
+ if (el.textContent !== css) el.textContent = css;
4115
+ discoverParts();
4116
+ if (frameEl === null) return;
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
+ }
4124
+ }
3942
4125
  /** Mirror of the bg-part blur on :root. --dsh-any-part-blur is element-scoped
3943
4126
  * to the columns, so surfaces outside their subtree (the mobile header, or
3944
4127
  * third-party styles) can never inherit it. */
@@ -4062,6 +4245,7 @@ window.__ModuleLoader__.load({
4062
4245
  `${SETTINGS_PANEL_SEL}{-webkit-text-stroke:var(--dsh-any-stroke-settings-w,0px) var(--dsh-any-stroke-settings-c,transparent);paint-order:stroke fill}`,
4063
4246
  "[role=\"menu\"]:not([data-dockkit-tab-menu]),[role=\"listbox\"],body>[role=\"tree\"],body>[role=\"dialog\"]:not([aria-modal=\"true\"]){-webkit-text-stroke:var(--dsh-any-stroke-card-w,0px) var(--dsh-any-stroke-card-c,transparent);paint-order:stroke fill}",
4064
4247
  `[data-composer-card],[data-cordis-panel],[data-composer-card] textarea,[data-composer-card] input,[data-composer-card] [contenteditable],[data-cordis-panel] input,[data-cordis-panel] textarea,${COMPOSER_TAKEOVER_CARD},${COMPOSER_TAKEOVER_EDITOR}{-webkit-text-stroke:var(--dsh-any-stroke-input-w,0px) var(--dsh-any-stroke-input-c,transparent);paint-order:stroke fill}`,
4248
+ `.${HEADER_BAR_CLASS}{-webkit-text-stroke:var(--dsh-any-stroke-headerBar-w,0px) var(--dsh-any-stroke-headerBar-c,transparent);paint-order:stroke fill}`,
4065
4249
  `[data-chat-flow]{-webkit-text-stroke:var(--dsh-any-stroke-chat-w,0px) var(--dsh-any-stroke-chat-c,transparent);paint-order:stroke fill}`,
4066
4250
  `[data-conversation-composer-overlay]{-webkit-text-stroke:var(--dsh-any-stroke-trajectory-w,0px) var(--dsh-any-stroke-trajectory-c,transparent);paint-order:stroke fill}`,
4067
4251
  `[data-code-block-content] pre,[data-code-block-content],[data-code-block-banner],[data-composer-chip],:not(pre)>code,[data-changed-files],[data-terminal],[data-read],[data-diff],[data-inspect],[data-turn-trigger],[data-context-injection-body],[data-search],[data-web],[class*="_ioCard"],[style*="--dsh-hover-preview-fade"],${BETTER_SIDEBAR_PANEL}{-webkit-text-stroke:var(--dsh-any-stroke-produced-w,0px) var(--dsh-any-stroke-produced-c,transparent);paint-order:stroke fill}`,
@@ -4082,7 +4266,8 @@ window.__ModuleLoader__.load({
4082
4266
  "input",
4083
4267
  "panel",
4084
4268
  "produced",
4085
- "header"
4269
+ "header",
4270
+ "headerBar"
4086
4271
  ];
4087
4272
  /** Resolve one group's stroke color key into a concrete CSS color.
4088
4273
  * 'auto' contrasts the FONT direction (white fonts → black stroke and vice
@@ -4539,6 +4724,8 @@ window.__ModuleLoader__.load({
4539
4724
  applyPanelBlur(blurs.panel);
4540
4725
  applyProduced();
4541
4726
  applyHeaderPopovers();
4727
+ applyHeaderBar();
4728
+ applyNativeCaption();
4542
4729
  applyViewCards();
4543
4730
  }
4544
4731
  /** Produced/artifact surfaces (conversation code blocks + their banner +
@@ -4589,6 +4776,10 @@ window.__ModuleLoader__.load({
4589
4776
  applyHeaderPopovers();
4590
4777
  return;
4591
4778
  }
4779
+ if (part === "headerBar") {
4780
+ applyHeaderBar();
4781
+ return;
4782
+ }
4592
4783
  if (part === "chat" || part === "trajectory") {
4593
4784
  applyViewCards();
4594
4785
  return;
@@ -4840,6 +5031,17 @@ window.__ModuleLoader__.load({
4840
5031
  function columnsPresent() {
4841
5032
  return frameEl !== null && sidebarEl !== null && centerEl !== null && rightEl !== null && document.body.contains(frameEl) && document.body.contains(centerEl);
4842
5033
  }
5034
+ /** The composer seat's elected takeover card (approval / plan review / question)
5035
+ * when one is mounted. It is not a view, but it shares the view cards' problem:
5036
+ * the host mounts a fresh element when a takeover is elected, and the pass
5037
+ * signature alone would skip that pass — `applyTakeoverFrost` rides
5038
+ * `applyInputBlur` — leaving the new card bare until a slider moves. Scoped to
5039
+ * the center column exactly like the view markers, because this query runs on
5040
+ * every coalesced mutation burst, including token streaming. */
5041
+ function probeTakeoverCard() {
5042
+ if (centerEl === null || !document.body.contains(centerEl)) return null;
5043
+ return centerEl.querySelector(COMPOSER_TAKEOVER_CARD);
5044
+ }
4843
5045
  /** Snapshot of every surface the pass would style, for the identity check. */
4844
5046
  function targetsNow() {
4845
5047
  return [
@@ -4847,7 +5049,8 @@ window.__ModuleLoader__.load({
4847
5049
  sidebarEl,
4848
5050
  centerEl,
4849
5051
  rightEl,
4850
- ...viewTargets
5052
+ ...viewTargets,
5053
+ probeTakeoverCard()
4851
5054
  ];
4852
5055
  }
4853
5056
  /** Watch for the AppFrame mounting so persisted blurs land even when the shell
@@ -5233,6 +5436,15 @@ window.__ModuleLoader__.load({
5233
5436
  if (name) document.documentElement.style.removeProperty(name);
5234
5437
  }
5235
5438
  document.documentElement.classList.remove(INPUT_FROST_CLASS);
5439
+ applyTakeoverFrost(0);
5440
+ document.documentElement.style.removeProperty("--dsh-any-op-header-bar");
5441
+ document.documentElement.style.removeProperty("--dsh-any-blur-header-bar");
5442
+ document.querySelectorAll(`.${HEADER_BAR_CLASS}`).forEach((el) => el.classList.remove(HEADER_BAR_CLASS));
5443
+ headerBarEl = null;
5444
+ frameEl?.classList.remove(CAPTION_FRAME_CLASS);
5445
+ document.querySelectorAll(`.${FLAT_CENTER_CLASS}`).forEach((el) => el.classList.remove(FLAT_CENTER_CLASS));
5446
+ wcoStyleEl?.remove();
5447
+ wcoStyleEl = null;
5236
5448
  document.documentElement.style.removeProperty("--dsh-any-blur-panel");
5237
5449
  document.documentElement.style.removeProperty("--dsh-any-blur-prod");
5238
5450
  document.documentElement.style.removeProperty("--dsh-any-prod-pct");
@@ -5325,7 +5537,7 @@ window.__ModuleLoader__.load({
5325
5537
  function buildStaticStyles() {
5326
5538
  const adapter = rHostAdapter();
5327
5539
  const panel = adapter.panelFragments();
5328
- return DARK_GRADIENT + FRAME_CLEAR_RULE + SETTINGS_STYLE_RULE + popoverBlurRule() + TRAJECTORY_STYLE_RULE + inputBlurRule() + MOBILE_HEADER_RULE + PANEL_TOKEN_RULE + panel.promotion + panel.blur + adapter.pluginPageRule + PRODUCED_RULE + STROKE_RULE + headerPopoverRule() + exemptDefaultRule() + PLACEHOLDER_RULE;
5540
+ return DARK_GRADIENT + FRAME_CLEAR_RULE + SETTINGS_STYLE_RULE + popoverBlurRule() + TRAJECTORY_STYLE_RULE + inputBlurRule() + MOBILE_HEADER_RULE + HEADER_BAR_RULE + PANEL_TOKEN_RULE + panel.promotion + panel.blur + adapter.pluginPageRule + PRODUCED_RULE + STROKE_RULE + headerPopoverRule() + exemptDefaultRule() + PLACEHOLDER_RULE;
5329
5541
  }
5330
5542
  /** Append the plugin's stylesheet and keep it matched to the host.
5331
5543
  * Returns a teardown for the plugin's effect scope. */
@@ -6066,6 +6278,18 @@ window.__ModuleLoader__.load({
6066
6278
  rx: "2"
6067
6279
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 6.6v2M7 8h2" })]
6068
6280
  });
6281
+ /** Session header bar: a window with its title band above the content. */
6282
+ const HeaderBarIcon = ({ size, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Glyph, {
6283
+ size,
6284
+ className,
6285
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
6286
+ x: "2.2",
6287
+ y: "2.2",
6288
+ width: "11.6",
6289
+ height: "11.6",
6290
+ rx: "2"
6291
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.2 5.6h11.6" })]
6292
+ });
6069
6293
  const PlusIcon = ({ size, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Glyph, {
6070
6294
  size,
6071
6295
  className,
@@ -7092,6 +7316,11 @@ window.__ModuleLoader__.load({
7092
7316
  labelKey: "uiHeader",
7093
7317
  Icon: PanelIcon
7094
7318
  },
7319
+ {
7320
+ isHeaderBar: true,
7321
+ labelKey: "uiHeaderBar",
7322
+ Icon: HeaderBarIcon
7323
+ },
7095
7324
  {
7096
7325
  isPanel: true,
7097
7326
  labelKey: "uiPanelNative",
@@ -7121,11 +7350,11 @@ window.__ModuleLoader__.load({
7121
7350
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7122
7351
  className: "dab-grid-parts",
7123
7352
  children: PARTS$1.map((part, i) => {
7124
- const { labelKey, Icon, isSettings, isChat, isTrajectory, isPanel, isProduced, isHeader } = part;
7353
+ const { labelKey, Icon, isSettings, isChat, isTrajectory, isPanel, isProduced, isHeader, isHeaderBar } = part;
7125
7354
  const opKey = part.opKey;
7126
7355
  const label = t(labelKey);
7127
- const blurKey = isChat ? "chat" : isTrajectory ? "trajectory" : isSettings ? "settings" : isPanel ? "panel" : isProduced ? "produced" : isHeader ? "header" : opKey;
7128
- const opacity = isChat ? rChatTextOpacity() : isTrajectory ? rTrajectoryOpacity() : isSettings ? rSop() : isPanel ? rPanelOpacity() : isProduced ? rProducedOpacity() : isHeader ? rHeaderOpacity() : rOps()[opKey];
7356
+ const blurKey = isChat ? "chat" : isTrajectory ? "trajectory" : isSettings ? "settings" : isPanel ? "panel" : isProduced ? "produced" : isHeader ? "header" : isHeaderBar ? "headerBar" : opKey;
7357
+ const opacity = isChat ? rChatTextOpacity() : isTrajectory ? rTrajectoryOpacity() : isSettings ? rSop() : isPanel ? rPanelOpacity() : isProduced ? rProducedOpacity() : isHeader ? rHeaderOpacity() : isHeaderBar ? rHeaderBarOpacity() : rOps()[opKey];
7129
7358
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
7130
7359
  className: "dab-card dab-card-hover dab-rise",
7131
7360
  style: { "--d": i + 1 },
@@ -7174,6 +7403,9 @@ window.__ModuleLoader__.load({
7174
7403
  } else if (isHeader) {
7175
7404
  cfg.headerOpacity = op;
7176
7405
  applyHeaderPopovers();
7406
+ } else if (isHeaderBar) {
7407
+ cfg.headerBarOpacity = op;
7408
+ applyHeaderBar();
7177
7409
  } else {
7178
7410
  const ops = { ...rOps() };
7179
7411
  ops[opKey] = op;
@@ -7202,6 +7434,10 @@ window.__ModuleLoader__.load({
7202
7434
  cfg.headerOpacity = op;
7203
7435
  applyHeaderPopovers();
7204
7436
  saveConfig();
7437
+ } else if (isHeaderBar) {
7438
+ cfg.headerBarOpacity = op;
7439
+ applyHeaderBar();
7440
+ saveConfig();
7205
7441
  } else {
7206
7442
  const ops = { ...rOps() };
7207
7443
  ops[opKey] = op;
@@ -7282,6 +7518,11 @@ window.__ModuleLoader__.load({
7282
7518
  labelKey: "uiHeader",
7283
7519
  Icon: PanelIcon
7284
7520
  },
7521
+ {
7522
+ key: "headerBar",
7523
+ labelKey: "uiHeaderBar",
7524
+ Icon: HeaderBarIcon
7525
+ },
7285
7526
  {
7286
7527
  key: "panel",
7287
7528
  labelKey: "uiPanelNative",
@@ -8653,7 +8894,8 @@ window.__ModuleLoader__.load({
8653
8894
  input: 0,
8654
8895
  panel: 0,
8655
8896
  produced: 0,
8656
- header: 0
8897
+ header: 0,
8898
+ headerBar: 0
8657
8899
  };
8658
8900
  /** Presets ship with strokes off — text outlines are an opt-in look. Fresh
8659
8901
  * objects per call so a profile restore can never alias another preset's
@@ -8674,7 +8916,8 @@ window.__ModuleLoader__.load({
8674
8916
  input: off(),
8675
8917
  panel: off(),
8676
8918
  produced: off(),
8677
- header: off()
8919
+ header: off(),
8920
+ headerBar: off()
8678
8921
  };
8679
8922
  };
8680
8923
  const BUILTIN_PRESETS = [
@@ -8697,7 +8940,8 @@ window.__ModuleLoader__.load({
8697
8940
  trajectoryOpacity: 1,
8698
8941
  panelOpacity: 1,
8699
8942
  producedOpacity: 1,
8700
- headerOpacity: 1
8943
+ headerOpacity: 1,
8944
+ headerBarOpacity: .85
8701
8945
  }
8702
8946
  },
8703
8947
  {
@@ -8732,7 +8976,8 @@ window.__ModuleLoader__.load({
8732
8976
  trajectoryOpacity: .85,
8733
8977
  panelOpacity: .85,
8734
8978
  producedOpacity: 1,
8735
- headerOpacity: 1
8979
+ headerOpacity: 1,
8980
+ headerBarOpacity: .62
8736
8981
  }
8737
8982
  },
8738
8983
  {
@@ -8754,7 +8999,8 @@ window.__ModuleLoader__.load({
8754
8999
  trajectoryOpacity: 1,
8755
9000
  panelOpacity: 1,
8756
9001
  producedOpacity: 1,
8757
- headerOpacity: 1
9002
+ headerOpacity: 1,
9003
+ headerBarOpacity: .97
8758
9004
  }
8759
9005
  },
8760
9006
  {
@@ -8789,7 +9035,8 @@ window.__ModuleLoader__.load({
8789
9035
  trajectoryOpacity: .8,
8790
9036
  panelOpacity: .8,
8791
9037
  producedOpacity: 1,
8792
- headerOpacity: 1
9038
+ headerOpacity: 1,
9039
+ headerBarOpacity: .5
8793
9040
  }
8794
9041
  },
8795
9042
  {
@@ -8824,7 +9071,8 @@ window.__ModuleLoader__.load({
8824
9071
  trajectoryOpacity: .78,
8825
9072
  panelOpacity: .75,
8826
9073
  producedOpacity: 1,
8827
- headerOpacity: 1
9074
+ headerOpacity: 1,
9075
+ headerBarOpacity: .42
8828
9076
  }
8829
9077
  },
8830
9078
  {
@@ -8850,7 +9098,8 @@ window.__ModuleLoader__.load({
8850
9098
  trajectoryOpacity: 1,
8851
9099
  panelOpacity: 1,
8852
9100
  producedOpacity: 1,
8853
- headerOpacity: 1
9101
+ headerOpacity: 1,
9102
+ headerBarOpacity: .92
8854
9103
  }
8855
9104
  }
8856
9105
  ];