dsh-any-background 0.3.4 → 0.3.5

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,114 @@ 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
+ function discoverHeaderBar() {
4022
+ if (centerEl === null || !document.body.contains(centerEl)) return null;
4023
+ const bar = centerEl.querySelector(HEADER_BAR_ANCHOR)?.closest("header");
4024
+ return bar instanceof HTMLElement ? bar : null;
4025
+ }
4026
+ /** The bar's paint. The variables are written by `applyHeaderBar`; the class is
4027
+ * only ever added when they are, so a host the plugin is not theming keeps its
4028
+ * own header untouched. */
4029
+ 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)}`;
4030
+ /** Claim the bar and write its material + frost. `surfaces` arrives from the token
4031
+ * funnel, which already has the resolved source list; the settings sliders and the
4032
+ * parts pass call it without one and the sources are re-resolved here. */
4033
+ function applyHeaderBar(surfaces) {
4034
+ const base = (surfaces === void 0 ? paletteTokens() ?? readHostOpacityTokens() : surfaces)?.["--dsw-alias-bg-base"];
4035
+ const root = document.documentElement;
4036
+ discoverParts();
4037
+ const bar = discoverHeaderBar();
4038
+ if (base === void 0) {
4039
+ if (bar !== null) bar.classList.remove(HEADER_BAR_CLASS);
4040
+ root.style.removeProperty("--dsh-any-op-header-bar");
4041
+ root.style.removeProperty("--dsh-any-blur-header-bar");
4042
+ return;
4043
+ }
4044
+ root.style.setProperty("--dsh-any-op-header-bar", toRgba(base, rHeaderBarOpacity()));
4045
+ const px = rBlurs().headerBar;
4046
+ if (px > 0) root.style.setProperty("--dsh-any-blur-header-bar", `blur(${px}px)`);
4047
+ else root.style.removeProperty("--dsh-any-blur-header-bar");
4048
+ if (bar !== null) bar.classList.add(HEADER_BAR_CLASS);
4049
+ }
4050
+ const CAPTION_FRAME_CLASS = "dab-frame-caption";
4051
+ const WCO_PROBE_SEL = "body > span[style*=\"--dsw-specific-sidebar-fill\"]";
4052
+ let wcoStyleEl = null;
4053
+ function ensureWcoStyle() {
4054
+ if (wcoStyleEl?.isConnected) return wcoStyleEl;
4055
+ wcoStyleEl = document.createElement("style");
4056
+ wcoStyleEl.dataset.plugin = "dsh-any-background-wco";
4057
+ document.head.appendChild(wcoStyleEl);
4058
+ return wcoStyleEl;
4059
+ }
4060
+ /** The band's opaque material, or '' when the plugin has no theme to assert. The
4061
+ * sampled sidebar fill is already opaque in both source paths (the plugin's
4062
+ * palette builds `hsl()`, the host's own token is a static colour) — it only
4063
+ * misses on a host that exposes neither, and then the neutral the plugin builds
4064
+ * for the effective scheme stands in so the band still tracks the label ink. */
4065
+ function captionFill(src) {
4066
+ const sampled = src?.["--dsw-specific-sidebar-fill"];
4067
+ if (sampled !== void 0) return sampled;
4068
+ if (paletteTokens() === null && rBgDark() === null) return "";
4069
+ const dark = rScheme() === "dark";
4070
+ return genTokens(220, .04, dark ? .14 : .92, dark ? "dark" : "light").tokens["--dsw-specific-sidebar-fill"] ?? "";
4071
+ }
4072
+ /** Write the caption rule and mark the frame it targets. The frame is the
4073
+ * plugin's own discovery (`discoverParts`), not a guessed hashed class name. The
4074
+ * probe selector is a verified shape: an inline style that mentions the sidebar
4075
+ * token on a body-level span is the desktop preload's caption probe and nothing
4076
+ * else, so no match means no desktop caption and the rule is inert. */
4077
+ function applyNativeCaption(surfaces) {
4078
+ 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}`;
4081
+ const el = ensureWcoStyle();
4082
+ if (el.textContent !== css) el.textContent = css;
4083
+ discoverParts();
4084
+ if (frameEl === null) return;
4085
+ if (css === "") frameEl.classList.remove(CAPTION_FRAME_CLASS);
4086
+ else frameEl.classList.add(CAPTION_FRAME_CLASS);
4087
+ }
3942
4088
  /** Mirror of the bg-part blur on :root. --dsh-any-part-blur is element-scoped
3943
4089
  * to the columns, so surfaces outside their subtree (the mobile header, or
3944
4090
  * third-party styles) can never inherit it. */
@@ -4062,6 +4208,7 @@ window.__ModuleLoader__.load({
4062
4208
  `${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
4209
  "[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
4210
  `[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}`,
4211
+ `.${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
4212
  `[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
4213
  `[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
4214
  `[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 +4229,8 @@ window.__ModuleLoader__.load({
4082
4229
  "input",
4083
4230
  "panel",
4084
4231
  "produced",
4085
- "header"
4232
+ "header",
4233
+ "headerBar"
4086
4234
  ];
4087
4235
  /** Resolve one group's stroke color key into a concrete CSS color.
4088
4236
  * 'auto' contrasts the FONT direction (white fonts → black stroke and vice
@@ -4539,6 +4687,8 @@ window.__ModuleLoader__.load({
4539
4687
  applyPanelBlur(blurs.panel);
4540
4688
  applyProduced();
4541
4689
  applyHeaderPopovers();
4690
+ applyHeaderBar();
4691
+ applyNativeCaption();
4542
4692
  applyViewCards();
4543
4693
  }
4544
4694
  /** Produced/artifact surfaces (conversation code blocks + their banner +
@@ -4589,6 +4739,10 @@ window.__ModuleLoader__.load({
4589
4739
  applyHeaderPopovers();
4590
4740
  return;
4591
4741
  }
4742
+ if (part === "headerBar") {
4743
+ applyHeaderBar();
4744
+ return;
4745
+ }
4592
4746
  if (part === "chat" || part === "trajectory") {
4593
4747
  applyViewCards();
4594
4748
  return;
@@ -4840,6 +4994,17 @@ window.__ModuleLoader__.load({
4840
4994
  function columnsPresent() {
4841
4995
  return frameEl !== null && sidebarEl !== null && centerEl !== null && rightEl !== null && document.body.contains(frameEl) && document.body.contains(centerEl);
4842
4996
  }
4997
+ /** The composer seat's elected takeover card (approval / plan review / question)
4998
+ * when one is mounted. It is not a view, but it shares the view cards' problem:
4999
+ * the host mounts a fresh element when a takeover is elected, and the pass
5000
+ * signature alone would skip that pass — `applyTakeoverFrost` rides
5001
+ * `applyInputBlur` — leaving the new card bare until a slider moves. Scoped to
5002
+ * the center column exactly like the view markers, because this query runs on
5003
+ * every coalesced mutation burst, including token streaming. */
5004
+ function probeTakeoverCard() {
5005
+ if (centerEl === null || !document.body.contains(centerEl)) return null;
5006
+ return centerEl.querySelector(COMPOSER_TAKEOVER_CARD);
5007
+ }
4843
5008
  /** Snapshot of every surface the pass would style, for the identity check. */
4844
5009
  function targetsNow() {
4845
5010
  return [
@@ -4847,7 +5012,8 @@ window.__ModuleLoader__.load({
4847
5012
  sidebarEl,
4848
5013
  centerEl,
4849
5014
  rightEl,
4850
- ...viewTargets
5015
+ ...viewTargets,
5016
+ probeTakeoverCard()
4851
5017
  ];
4852
5018
  }
4853
5019
  /** Watch for the AppFrame mounting so persisted blurs land even when the shell
@@ -5233,6 +5399,13 @@ window.__ModuleLoader__.load({
5233
5399
  if (name) document.documentElement.style.removeProperty(name);
5234
5400
  }
5235
5401
  document.documentElement.classList.remove(INPUT_FROST_CLASS);
5402
+ applyTakeoverFrost(0);
5403
+ document.documentElement.style.removeProperty("--dsh-any-op-header-bar");
5404
+ document.documentElement.style.removeProperty("--dsh-any-blur-header-bar");
5405
+ document.querySelectorAll(`.${HEADER_BAR_CLASS}`).forEach((el) => el.classList.remove(HEADER_BAR_CLASS));
5406
+ frameEl?.classList.remove(CAPTION_FRAME_CLASS);
5407
+ wcoStyleEl?.remove();
5408
+ wcoStyleEl = null;
5236
5409
  document.documentElement.style.removeProperty("--dsh-any-blur-panel");
5237
5410
  document.documentElement.style.removeProperty("--dsh-any-blur-prod");
5238
5411
  document.documentElement.style.removeProperty("--dsh-any-prod-pct");
@@ -5325,7 +5498,7 @@ window.__ModuleLoader__.load({
5325
5498
  function buildStaticStyles() {
5326
5499
  const adapter = rHostAdapter();
5327
5500
  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;
5501
+ 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
5502
  }
5330
5503
  /** Append the plugin's stylesheet and keep it matched to the host.
5331
5504
  * Returns a teardown for the plugin's effect scope. */
@@ -6066,6 +6239,18 @@ window.__ModuleLoader__.load({
6066
6239
  rx: "2"
6067
6240
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 6.6v2M7 8h2" })]
6068
6241
  });
6242
+ /** Session header bar: a window with its title band above the content. */
6243
+ const HeaderBarIcon = ({ size, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Glyph, {
6244
+ size,
6245
+ className,
6246
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
6247
+ x: "2.2",
6248
+ y: "2.2",
6249
+ width: "11.6",
6250
+ height: "11.6",
6251
+ rx: "2"
6252
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2.2 5.6h11.6" })]
6253
+ });
6069
6254
  const PlusIcon = ({ size, className }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Glyph, {
6070
6255
  size,
6071
6256
  className,
@@ -7092,6 +7277,11 @@ window.__ModuleLoader__.load({
7092
7277
  labelKey: "uiHeader",
7093
7278
  Icon: PanelIcon
7094
7279
  },
7280
+ {
7281
+ isHeaderBar: true,
7282
+ labelKey: "uiHeaderBar",
7283
+ Icon: HeaderBarIcon
7284
+ },
7095
7285
  {
7096
7286
  isPanel: true,
7097
7287
  labelKey: "uiPanelNative",
@@ -7121,11 +7311,11 @@ window.__ModuleLoader__.load({
7121
7311
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7122
7312
  className: "dab-grid-parts",
7123
7313
  children: PARTS$1.map((part, i) => {
7124
- const { labelKey, Icon, isSettings, isChat, isTrajectory, isPanel, isProduced, isHeader } = part;
7314
+ const { labelKey, Icon, isSettings, isChat, isTrajectory, isPanel, isProduced, isHeader, isHeaderBar } = part;
7125
7315
  const opKey = part.opKey;
7126
7316
  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];
7317
+ const blurKey = isChat ? "chat" : isTrajectory ? "trajectory" : isSettings ? "settings" : isPanel ? "panel" : isProduced ? "produced" : isHeader ? "header" : isHeaderBar ? "headerBar" : opKey;
7318
+ const opacity = isChat ? rChatTextOpacity() : isTrajectory ? rTrajectoryOpacity() : isSettings ? rSop() : isPanel ? rPanelOpacity() : isProduced ? rProducedOpacity() : isHeader ? rHeaderOpacity() : isHeaderBar ? rHeaderBarOpacity() : rOps()[opKey];
7129
7319
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
7130
7320
  className: "dab-card dab-card-hover dab-rise",
7131
7321
  style: { "--d": i + 1 },
@@ -7174,6 +7364,9 @@ window.__ModuleLoader__.load({
7174
7364
  } else if (isHeader) {
7175
7365
  cfg.headerOpacity = op;
7176
7366
  applyHeaderPopovers();
7367
+ } else if (isHeaderBar) {
7368
+ cfg.headerBarOpacity = op;
7369
+ applyHeaderBar();
7177
7370
  } else {
7178
7371
  const ops = { ...rOps() };
7179
7372
  ops[opKey] = op;
@@ -7202,6 +7395,10 @@ window.__ModuleLoader__.load({
7202
7395
  cfg.headerOpacity = op;
7203
7396
  applyHeaderPopovers();
7204
7397
  saveConfig();
7398
+ } else if (isHeaderBar) {
7399
+ cfg.headerBarOpacity = op;
7400
+ applyHeaderBar();
7401
+ saveConfig();
7205
7402
  } else {
7206
7403
  const ops = { ...rOps() };
7207
7404
  ops[opKey] = op;
@@ -7282,6 +7479,11 @@ window.__ModuleLoader__.load({
7282
7479
  labelKey: "uiHeader",
7283
7480
  Icon: PanelIcon
7284
7481
  },
7482
+ {
7483
+ key: "headerBar",
7484
+ labelKey: "uiHeaderBar",
7485
+ Icon: HeaderBarIcon
7486
+ },
7285
7487
  {
7286
7488
  key: "panel",
7287
7489
  labelKey: "uiPanelNative",
@@ -8653,7 +8855,8 @@ window.__ModuleLoader__.load({
8653
8855
  input: 0,
8654
8856
  panel: 0,
8655
8857
  produced: 0,
8656
- header: 0
8858
+ header: 0,
8859
+ headerBar: 0
8657
8860
  };
8658
8861
  /** Presets ship with strokes off — text outlines are an opt-in look. Fresh
8659
8862
  * objects per call so a profile restore can never alias another preset's
@@ -8674,7 +8877,8 @@ window.__ModuleLoader__.load({
8674
8877
  input: off(),
8675
8878
  panel: off(),
8676
8879
  produced: off(),
8677
- header: off()
8880
+ header: off(),
8881
+ headerBar: off()
8678
8882
  };
8679
8883
  };
8680
8884
  const BUILTIN_PRESETS = [
@@ -8697,7 +8901,8 @@ window.__ModuleLoader__.load({
8697
8901
  trajectoryOpacity: 1,
8698
8902
  panelOpacity: 1,
8699
8903
  producedOpacity: 1,
8700
- headerOpacity: 1
8904
+ headerOpacity: 1,
8905
+ headerBarOpacity: .85
8701
8906
  }
8702
8907
  },
8703
8908
  {
@@ -8732,7 +8937,8 @@ window.__ModuleLoader__.load({
8732
8937
  trajectoryOpacity: .85,
8733
8938
  panelOpacity: .85,
8734
8939
  producedOpacity: 1,
8735
- headerOpacity: 1
8940
+ headerOpacity: 1,
8941
+ headerBarOpacity: .62
8736
8942
  }
8737
8943
  },
8738
8944
  {
@@ -8754,7 +8960,8 @@ window.__ModuleLoader__.load({
8754
8960
  trajectoryOpacity: 1,
8755
8961
  panelOpacity: 1,
8756
8962
  producedOpacity: 1,
8757
- headerOpacity: 1
8963
+ headerOpacity: 1,
8964
+ headerBarOpacity: .97
8758
8965
  }
8759
8966
  },
8760
8967
  {
@@ -8789,7 +8996,8 @@ window.__ModuleLoader__.load({
8789
8996
  trajectoryOpacity: .8,
8790
8997
  panelOpacity: .8,
8791
8998
  producedOpacity: 1,
8792
- headerOpacity: 1
8999
+ headerOpacity: 1,
9000
+ headerBarOpacity: .5
8793
9001
  }
8794
9002
  },
8795
9003
  {
@@ -8824,7 +9032,8 @@ window.__ModuleLoader__.load({
8824
9032
  trajectoryOpacity: .78,
8825
9033
  panelOpacity: .75,
8826
9034
  producedOpacity: 1,
8827
- headerOpacity: 1
9035
+ headerOpacity: 1,
9036
+ headerBarOpacity: .42
8828
9037
  }
8829
9038
  },
8830
9039
  {
@@ -8850,7 +9059,8 @@ window.__ModuleLoader__.load({
8850
9059
  trajectoryOpacity: 1,
8851
9060
  panelOpacity: 1,
8852
9061
  producedOpacity: 1,
8853
- headerOpacity: 1
9062
+ headerOpacity: 1,
9063
+ headerBarOpacity: .92
8854
9064
  }
8855
9065
  }
8856
9066
  ];