@ash-qw/dsh-theme-prts 0.1.97 → 0.1.99

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.
@@ -24,7 +24,7 @@ const STARTUP_STAGES = Object.freeze({
24
24
 
25
25
  function startupMarkup(prtsEmblem = '', rhodesEmblem = '') {
26
26
  const ticks = Array.from({ length: 21 }, (_, index) => `<i${index % 5 === 0 ? ' data-major' : ''}></i>`).join('')
27
- return `<section data-prts-startup data-stage="boot" popover="manual" role="status" aria-live="assertive" aria-label="P.R.T.S. 启动序列" tabindex="-1">
27
+ return `<section data-prts-startup data-stage="boot" popover="manual" role="status" aria-live="assertive" aria-label="P.R.T.S. 启动序列">
28
28
  <div data-prts-startup-grid aria-hidden="true"></div>
29
29
  <div data-prts-startup-scan aria-hidden="true"></div>
30
30
  <div data-prts-startup-cut="left" aria-hidden="true"></div>
@@ -73,16 +73,60 @@ function easeOutCubic(value) {
73
73
  return 1 - Math.pow(1 - clamp01(value), 3)
74
74
  }
75
75
 
76
+ function approachProgressAt(elapsed, duration) {
77
+ if (!(duration > 0)) return 90
78
+ return 90 * easeOutCubic(elapsed / duration)
79
+ }
80
+
81
+ function approachVelocityAt(elapsed, duration) {
82
+ if (!(duration > 0)) return 0
83
+ const remaining = 1 - clamp01(elapsed / duration)
84
+ return 270 * remaining * remaining / duration
85
+ }
86
+
87
+ function finishProgressAt(startProgress, startVelocity, elapsed, duration) {
88
+ if (!(duration > 0)) return 100
89
+ const progressDelta = Math.max(0, 100 - startProgress)
90
+ if (progressDelta === 0) return 100
91
+ const time = clamp01(elapsed / duration)
92
+ const timeSquared = time * time
93
+ const timeCubed = timeSquared * time
94
+ const startWeight = 2 * timeCubed - 3 * timeSquared + 1
95
+ const velocityWeight = timeCubed - 2 * timeSquared + time
96
+ const endWeight = -2 * timeCubed + 3 * timeSquared
97
+ const startTangent = Math.min(progressDelta * 3, Math.max(0, startVelocity) * duration)
98
+ const progress = startWeight * startProgress
99
+ + velocityWeight * startTangent
100
+ + endWeight * 100
101
+ return Math.max(startProgress, Math.min(100, progress))
102
+ }
103
+
76
104
  export function findNativeHarnessLoader(document) {
77
105
  return document?.querySelector?.('[data-dsh-boot]') ?? null
78
106
  }
79
107
 
108
+ function matchesOpenTopLayer(node) {
109
+ for (const selector of [':modal', ':popover-open']) {
110
+ try {
111
+ if (node?.matches?.(selector)) return true
112
+ } catch {}
113
+ }
114
+ return false
115
+ }
116
+
117
+ function hostHasOpenTopLayer(document, overlay) {
118
+ const candidates = [...(document?.querySelectorAll?.('dialog[open], [popover]') ?? [])]
119
+ return candidates.some(node => node !== overlay && matchesOpenTopLayer(node))
120
+ }
121
+
80
122
  export function createPrtsStartupSequence({
81
123
  document,
82
124
  window,
83
125
  prtsEmblem = '',
84
126
  rhodesEmblem = '',
85
127
  timings = PRTS_STARTUP_TIMINGS,
128
+ onActiveChange = () => {},
129
+ onReady = () => {},
86
130
  } = {}) {
87
131
  const schedule = { ...PRTS_STARTUP_TIMINGS, ...timings }
88
132
  let overlay
@@ -95,6 +139,7 @@ export function createPrtsStartupSequence({
95
139
  let hostReady = false
96
140
  let finishStartedAt
97
141
  let finishStartedProgress = 0
142
+ let finishStartedVelocity = 0
98
143
  let readyStartedAt
99
144
  let exitStartedAt
100
145
  let timeoutStartedAt
@@ -102,7 +147,12 @@ export function createPrtsStartupSequence({
102
147
  let pendingStage
103
148
  let copyTransitionStartedAt
104
149
  let lastProgress = -1
150
+ let lastRoundedProgress = -1
105
151
  let useReducedMotion = false
152
+ let progressFill
153
+ let progressPercent
154
+ let activeReported = false
155
+ let readyReported = false
106
156
 
107
157
  const now = () => window?.performance?.now?.() ?? Date.now()
108
158
  const requestFrame = callback => window?.requestAnimationFrame?.(callback)
@@ -113,6 +163,21 @@ export function createPrtsStartupSequence({
113
163
  else window?.clearTimeout?.(id)
114
164
  }
115
165
 
166
+ function notify(callback, value) {
167
+ try {
168
+ callback(value)
169
+ } catch {
170
+ // Startup remains fail-open when an integration callback fails.
171
+ }
172
+ }
173
+
174
+ function reportActive(active) {
175
+ const next = Boolean(active)
176
+ if (activeReported === next) return
177
+ activeReported = next
178
+ notify(onActiveChange, next)
179
+ }
180
+
116
181
  function restoreInteractivity() {
117
182
  for (const record of inertRecords) {
118
183
  if (!record.node?.isConnected) continue
@@ -135,9 +200,12 @@ export function createPrtsStartupSequence({
135
200
  }
136
201
  overlay?.remove?.()
137
202
  overlay = undefined
203
+ progressFill = undefined
204
+ progressPercent = undefined
138
205
  restoreInteractivity()
139
206
  if (restoreFocus && previousFocus?.isConnected) previousFocus.focus?.()
140
207
  previousFocus = undefined
208
+ reportActive(false)
141
209
  }
142
210
 
143
211
  function updateProgress(progress) {
@@ -145,9 +213,12 @@ export function createPrtsStartupSequence({
145
213
  const safeProgress = Math.max(0, Math.min(100, progress))
146
214
  if (Math.abs(safeProgress - lastProgress) < .01) return
147
215
  lastProgress = safeProgress
148
- overlay.style.setProperty('--prts-startup-progress', (safeProgress / 100).toFixed(4))
149
- const percent = overlay.querySelector('[data-prts-startup-percent]')
150
- if (percent) percent.textContent = `${String(Math.round(safeProgress)).padStart(3, '0')}%`
216
+ if (progressFill) progressFill.style.transform = `scaleX(${(safeProgress / 100).toFixed(4)})`
217
+ const roundedProgress = Math.round(safeProgress)
218
+ if (progressPercent && roundedProgress !== lastRoundedProgress) {
219
+ lastRoundedProgress = roundedProgress
220
+ progressPercent.textContent = `${String(roundedProgress).padStart(3, '0')}%`
221
+ }
151
222
  }
152
223
 
153
224
  function applyStage(name) {
@@ -161,6 +232,10 @@ export function createPrtsStartupSequence({
161
232
  if (label) label.textContent = stage.label
162
233
  if (detail) detail.textContent = stage.detail
163
234
  overlay.setAttribute('aria-label', `P.R.T.S. 启动序列:${stage.detail}`)
235
+ if (name === 'ready' && !readyReported) {
236
+ readyReported = true
237
+ notify(onReady)
238
+ }
164
239
  }
165
240
 
166
241
  function requestStage(name, elapsed) {
@@ -218,7 +293,14 @@ export function createPrtsStartupSequence({
218
293
  }
219
294
 
220
295
  function promoteToTopLayer() {
221
- if (typeof overlay?.showPopover !== 'function') return
296
+ if (!hostHasOpenTopLayer(document, overlay)) {
297
+ overlay?.removeAttribute('popover')
298
+ return
299
+ }
300
+ if (typeof overlay?.showPopover !== 'function') {
301
+ overlay?.removeAttribute('popover')
302
+ return
303
+ }
222
304
  try {
223
305
  overlay.showPopover()
224
306
  } catch {
@@ -266,7 +348,7 @@ export function createPrtsStartupSequence({
266
348
  updateProgress(90)
267
349
  if (elapsed - timeoutStartedAt >= schedule.timeoutHold) beginExit(elapsed, { failOpen: true })
268
350
  } else {
269
- const approachProgress = 90 * easeOutCubic(elapsed / schedule.approach)
351
+ const approachProgress = approachProgressAt(elapsed, schedule.approach)
270
352
  let progress = Math.min(90, approachProgress)
271
353
 
272
354
  if (!hostReady && elapsed >= schedule.timeout) {
@@ -275,9 +357,14 @@ export function createPrtsStartupSequence({
275
357
  if (finishStartedAt === undefined) {
276
358
  finishStartedAt = elapsed
277
359
  finishStartedProgress = progress
360
+ finishStartedVelocity = approachVelocityAt(elapsed, schedule.approach)
278
361
  }
279
- progress = finishStartedProgress
280
- + (100 - finishStartedProgress) * easeOutCubic((elapsed - finishStartedAt) / schedule.finish)
362
+ progress = finishProgressAt(
363
+ finishStartedProgress,
364
+ finishStartedVelocity,
365
+ elapsed - finishStartedAt,
366
+ schedule.finish,
367
+ )
281
368
  if (elapsed - finishStartedAt >= schedule.finish) {
282
369
  progress = 100
283
370
  requestStage('ready', elapsed)
@@ -332,18 +419,24 @@ export function createPrtsStartupSequence({
332
419
  readyStartedAt = undefined
333
420
  exitStartedAt = undefined
334
421
  timeoutStartedAt = undefined
422
+ finishStartedVelocity = 0
335
423
  currentStage = 'boot'
336
424
  pendingStage = undefined
337
425
  copyTransitionStartedAt = undefined
338
426
  lastProgress = -1
427
+ activeReported = false
428
+ readyReported = false
339
429
  useReducedMotion = reducedMotionRequested(reduced)
340
430
 
341
431
  previousFocus = document.activeElement
432
+ lastRoundedProgress = -1
342
433
  document.body.appendChild(overlay)
434
+ progressFill = overlay.querySelector('[data-prts-startup-fill]')
435
+ progressPercent = overlay.querySelector('[data-prts-startup-percent]')
343
436
  promoteToTopLayer()
344
437
  document.documentElement.setAttribute('data-prts-startup-active', '')
345
438
  lockSiblings()
346
- overlay.focus?.({ preventScroll: true })
439
+ reportActive(true)
347
440
  document.addEventListener('visibilitychange', onVisibilityChange)
348
441
 
349
442
  if (useReducedMotion) {
@@ -7,6 +7,7 @@ const ROOT_ATTRIBUTES = [
7
7
  'data-prts-glass',
8
8
  'data-prts-motion',
9
9
  'data-prts-particle-pattern',
10
+ 'data-prts-session-flow',
10
11
  'data-prts-conversation-style',
11
12
  ]
12
13
 
@@ -716,6 +717,7 @@ export function createThemeController({ document, window, cssText, service, onTr
716
717
  root.dataset.prtsGlass = preferences.glass
717
718
  root.dataset.prtsMotion = preferences.motion
718
719
  root.dataset.prtsParticlePattern = 'orthogonal'
720
+ root.dataset.prtsSessionFlow = preferences.sessionFlow ? 'on' : 'off'
719
721
  root.dataset.prtsConversationStyle = preferences.conversationStyle
720
722
  refresh()
721
723
  },
@@ -7,6 +7,7 @@ const ROOT_ATTRIBUTES = [
7
7
  'data-prts-glass',
8
8
  'data-prts-motion',
9
9
  'data-prts-particle-pattern',
10
+ 'data-prts-session-flow',
10
11
  'data-prts-conversation-style',
11
12
  ]
12
13
 
@@ -109,6 +110,7 @@ export function createThemeController({ document, window, cssText, service }) {
109
110
  root.dataset.prtsGlass = preferences.glass
110
111
  root.dataset.prtsMotion = preferences.motion
111
112
  root.dataset.prtsParticlePattern = 'orthogonal'
113
+ root.dataset.prtsSessionFlow = preferences.sessionFlow ? 'on' : 'off'
112
114
  root.dataset.prtsConversationStyle = preferences.conversationStyle
113
115
  refresh()
114
116
  },
@@ -19,6 +19,7 @@ const COMMON_CONTROLS = [
19
19
  ['texture', '环境底纹', [['off', '关闭'], ['restrained', '克制'], ['full', '完整']]],
20
20
  ['glass', '玻璃材质', [['off', '关闭'], ['soft', '柔和'], ['standard', '标准'], ['clear', '清晰']]],
21
21
  ['motion', '动态效果', [['system', '跟随系统'], ['reduced', '减少']]],
22
+ ['sessionFlow', '当前会话流线', [['false', '关闭'], ['true', '开启']]],
22
23
  ['conversationStyle', '会话主题', [['native', '原有'], ['deck-chat', '通讯链路']]],
23
24
  ]
24
25
 
@@ -37,6 +38,8 @@ function settingButtons(key, label, options) {
37
38
  ? '<small data-prts-setting-note>在任意窗口宽度下默认收起 P.R.T.S. 导航,可从左侧按钮临时展开</small>'
38
39
  : key === 'conversationStyle'
39
40
  ? '<small data-prts-setting-note>立即切换会话背景、头像与消息气泡</small>'
41
+ : key === 'sessionFlow'
42
+ ? '<small data-prts-setting-note>仅控制当前会话卡片的三色流线</small>'
40
43
  : ''
41
44
  const sample = value => key === 'texture' || key === 'glass'
42
45
  ? `<i data-prts-option-sample="${key}" data-prts-option-sample-value="${value}" aria-hidden="true"></i>`
@@ -281,7 +284,11 @@ export function createThemeSettingsOverlay({
281
284
  const particleDetail = resolveParticleDetail(currentPreferences)
282
285
  for (const button of panel.querySelectorAll('button[data-prts-setting-key]')) {
283
286
  const key = button.dataset.prtsSettingKey
284
- const actual = key === 'particleDetail' ? particleDetail : currentPreferences[key]
287
+ const actual = key === 'particleDetail'
288
+ ? particleDetail
289
+ : key === 'sessionFlow'
290
+ ? currentPreferences.sessionFlow !== false
291
+ : currentPreferences[key]
285
292
  const selected = String(actual) === button.dataset.prtsSettingValue
286
293
  button.classList.toggle('is-selected', selected)
287
294
  button.setAttribute('aria-pressed', String(selected))
@@ -141,6 +141,71 @@ html[data-dsh-prts] [data-prts-session-pickup] {
141
141
  pointer-events: none;
142
142
  }
143
143
 
144
+ html[data-dsh-prts] [data-prts-session-lifeline] {
145
+ --prts-lifeline-pink: #f7ddeb;
146
+ --prts-lifeline-green: #65ddb0;
147
+ --prts-lifeline-blue: #6eb7f3;
148
+ opacity: 0;
149
+ transition: opacity 160ms ease;
150
+ pointer-events: none;
151
+ }
152
+
153
+ html[data-dsh-prts][data-prts-scheme="light"] [data-prts-session-lifeline] {
154
+ --prts-lifeline-pink: #c36f99;
155
+ --prts-lifeline-green: #218d6b;
156
+ --prts-lifeline-blue: #357ebc;
157
+ }
158
+
159
+ html[data-dsh-prts] [data-prts-session-lifeline-filament] {
160
+ fill: none;
161
+ stroke: currentColor;
162
+ stroke-width: .8;
163
+ stroke-linecap: round;
164
+ stroke-linejoin: round;
165
+ vector-effect: non-scaling-stroke;
166
+ shape-rendering: geometricPrecision;
167
+ }
168
+
169
+ html[data-dsh-prts] [data-prts-session-lifeline-filament="back"] {
170
+ stroke: var(--prts-lifeline-pink);
171
+ opacity: .74;
172
+ stroke-width: .85;
173
+ }
174
+
175
+ html[data-dsh-prts] [data-prts-session-lifeline-filament="core"] {
176
+ stroke: var(--prts-lifeline-green);
177
+ opacity: .68;
178
+ stroke-width: .9;
179
+ }
180
+
181
+ html[data-dsh-prts] [data-prts-session-lifeline-filament="front"] {
182
+ stroke: var(--prts-lifeline-blue);
183
+ opacity: .74;
184
+ stroke-width: .85;
185
+ }
186
+
187
+ html[data-dsh-prts] [data-prts-session-row][aria-selected="true"] [data-prts-session-lifeline] {
188
+ opacity: .62;
189
+ }
190
+
191
+ html[data-dsh-prts] [data-prts-session-row][aria-selected="true"]:hover [data-prts-session-lifeline] {
192
+ opacity: 0;
193
+ }
194
+
195
+ html[data-dsh-prts][data-prts-session-flow="off"] [data-prts-session-row] [data-prts-session-lifeline] {
196
+ opacity: 0;
197
+ }
198
+
199
+ @media (prefers-reduced-motion: reduce) {
200
+ html[data-dsh-prts] [data-prts-session-lifeline] {
201
+ transition-duration: 0s;
202
+ }
203
+ }
204
+
205
+ html[data-dsh-prts][data-prts-motion="reduced"] [data-prts-session-lifeline] {
206
+ transition-duration: 0s;
207
+ }
208
+
144
209
  html[data-dsh-prts] [data-prts-session-row]:hover [data-prts-facility-texture="pickup"] [data-prts-session-pickup] {
145
210
  opacity: .58;
146
211
  transform: translate3d(0, 0, 0);
@@ -809,7 +809,6 @@ html[data-dsh-prts] [data-prts-region="operation"] {
809
809
  html[data-dsh-prts] [data-prts-region="sessions"] {
810
810
  box-sizing: border-box;
811
811
  position: relative;
812
- z-index: 4;
813
812
  overflow: hidden;
814
813
  border-right: 1px solid var(--prts-line);
815
814
  background: var(--prts-panel);
@@ -818,7 +817,6 @@ html[data-dsh-prts] [data-prts-region="sessions"] {
818
817
 
819
818
  html[data-dsh-prts] [data-prts-region="operation"] {
820
819
  position: relative;
821
- z-index: 1;
822
820
  overflow: hidden;
823
821
  background: var(--prts-canvas);
824
822
  color: var(--prts-ink);
@@ -987,6 +985,14 @@ html[data-dsh-prts] [data-prts-session-row] [data-prts-row-title]::before {
987
985
  letter-spacing: .08em;
988
986
  }
989
987
 
988
+ html[data-dsh-prts] [data-prts-session-row][aria-selected="true"] [data-prts-row-title] {
989
+ font-weight: 700;
990
+ }
991
+
992
+ html[data-dsh-prts] [data-prts-session-row][aria-selected="true"] [data-prts-row-title]::before {
993
+ color: var(--prts-yellow);
994
+ }
995
+
990
996
  html[data-dsh-prts] [data-prts-workspace-actions],
991
997
  html[data-dsh-prts] [data-prts-session-actions] {
992
998
  position: absolute;
@@ -1516,7 +1522,7 @@ html[data-dsh-prts] [data-prts-composer-fallback] :is(textarea, [data-composer-i
1516
1522
  caret-color: var(--prts-yellow);
1517
1523
  }
1518
1524
 
1519
- html[data-dsh-prts] [data-composer-card] button:not([data-slot="conversation.input.attachments"] *),
1525
+ html[data-dsh-prts] [data-composer-card] button:not([data-slot="conversation.input.attachments"] *):not([data-prts-glass-menu] *):not([data-prts-floating-glass] *):not([role="menu"] *):not([role="listbox"] *),
1520
1526
  html[data-dsh-prts] [data-prts-conversation-control] {
1521
1527
  border: 1px solid var(--prts-line) !important;
1522
1528
  border-radius: var(--prts-radius-control) !important;
@@ -1526,7 +1532,7 @@ html[data-dsh-prts] [data-prts-conversation-control] {
1526
1532
  }
1527
1533
 
1528
1534
 
1529
- html[data-dsh-prts] [data-composer-card] button:not([data-slot="conversation.input.attachments"] *):is(:hover, :focus-visible),
1535
+ html[data-dsh-prts] [data-composer-card] button:not([data-slot="conversation.input.attachments"] *):not([data-prts-glass-menu] *):not([data-prts-floating-glass] *):not([role="menu"] *):not([role="listbox"] *):is(:hover, :focus-visible),
1530
1536
  html[data-dsh-prts] [data-prts-conversation-control]:is(:hover, :focus-visible) {
1531
1537
  border-color: var(--prts-yellow) !important;
1532
1538
  }
@@ -1537,7 +1543,7 @@ html[data-dsh-prts] [data-composer-card] button[type="submit"] {
1537
1543
  color: var(--prts-yellow-ink) !important;
1538
1544
  }
1539
1545
 
1540
- html[data-dsh-prts] [data-composer-card] button:not([data-slot="conversation.input.attachments"] *):active,
1546
+ html[data-dsh-prts] [data-composer-card] button:not([data-slot="conversation.input.attachments"] *):not([data-prts-glass-menu] *):not([data-prts-floating-glass] *):not([role="menu"] *):not([role="listbox"] *):active,
1541
1547
  html[data-dsh-prts] [data-prts-conversation-control]:active {
1542
1548
  transform: translateY(1px) scale(.98);
1543
1549
  }
@@ -11,7 +11,6 @@ html[data-dsh-prts] [data-prts-region="frame"] {
11
11
 
12
12
  html[data-dsh-prts] [data-prts-region="frame"] > [data-shell-overlay] {
13
13
  position: absolute !important;
14
- z-index: 120;
15
14
  inset: 0;
16
15
  min-width: 0;
17
16
  min-height: 0;
@@ -155,6 +154,10 @@ html[data-dsh-prts] [data-prts-session-row]:hover [data-prts-session-time] {
155
154
  opacity: 0;
156
155
  }
157
156
 
157
+ html[data-dsh-prts] [data-prts-session-row][aria-selected="true"] [data-prts-session-time] {
158
+ opacity: 0;
159
+ }
160
+
158
161
  /* Restore the notched P.R.T.S. composer with one complete layered contour. */
159
162
  html[data-dsh-prts] [data-composer-card],
160
163
  html[data-dsh-prts] [data-prts-composer-fallback] {
@@ -417,7 +420,7 @@ html[data-dsh-prts] [data-prts-hero-active] [data-prts-composer-fallback] textar
417
420
  resize: vertical;
418
421
  }
419
422
 
420
- html[data-dsh-prts] [data-prts-hero-active] [data-composer-card] button:not([data-slot="conversation.input.attachments"] *),
423
+ html[data-dsh-prts] [data-prts-hero-active] [data-composer-card] button:not([data-slot="conversation.input.attachments"] *):not([data-prts-glass-menu] *):not([data-prts-floating-glass] *):not([role="menu"] *):not([role="listbox"] *),
421
424
  html[data-dsh-prts] [data-prts-hero-active] [data-prts-glass-control] {
422
425
  min-height: 36px;
423
426
  }
@@ -49,6 +49,40 @@ html[data-dsh-prts] [data-prts-nav-bottom] > button:is(:hover, :focus-visible) {
49
49
  color: #f3f6f7 !important;
50
50
  }
51
51
 
52
+ html[data-dsh-prts] [data-prts-theme-disable]::after {
53
+ content: "";
54
+ position: absolute;
55
+ inset: 8px auto 8px 0;
56
+ width: 2px;
57
+ background: var(--prts-yellow);
58
+ transform: scaleY(0);
59
+ transition: transform 160ms var(--prts-ease-snap);
60
+ }
61
+
62
+ html[data-dsh-prts] [data-prts-theme-disable]:is(:hover, :focus-visible) {
63
+ color: var(--prts-yellow) !important;
64
+ }
65
+
66
+ html[data-dsh-prts] [data-prts-theme-disable]:is(:hover, :focus-visible)::after {
67
+ transform: scaleY(1);
68
+ }
69
+
70
+ html[data-dsh-prts] [data-prts-theme-disable-icon] {
71
+ width: 18px;
72
+ height: 18px;
73
+ fill: none;
74
+ stroke: currentColor;
75
+ stroke-width: 1.7;
76
+ stroke-linecap: round;
77
+ stroke-linejoin: round;
78
+ transition: transform 120ms var(--prts-ease-snap), opacity 120ms ease;
79
+ }
80
+
81
+ html[data-dsh-prts] [data-prts-theme-disable]:active [data-prts-theme-disable-icon] {
82
+ opacity: .72;
83
+ transform: scale(.9);
84
+ }
85
+
52
86
  html[data-dsh-prts] [data-prts-rail-brand][aria-expanded="true"]::after {
53
87
  content: "";
54
88
  position: absolute;
@@ -103,7 +137,7 @@ html[data-dsh-prts] [data-prts-nav-bottom] b {
103
137
  /* Complete structural outlines; decorative accents are separate edges. */
104
138
  html[data-dsh-prts] [data-composer-card],
105
139
  html[data-dsh-prts] [data-prts-composer-fallback],
106
- html[data-dsh-prts] [data-composer-card] button:not([data-slot="conversation.input.attachments"] *),
140
+ html[data-dsh-prts] [data-composer-card] button:not([data-slot="conversation.input.attachments"] *):not([data-prts-glass-menu] *):not([data-prts-floating-glass] *):not([role="menu"] *):not([role="listbox"] *),
107
141
  html[data-dsh-prts] [data-prts-conversation-control],
108
142
  html[data-dsh-prts] [data-produced-files-row] > button[type="button"],
109
143
  html[data-dsh-prts] [data-prts-to-bottom] {
@@ -1,13 +1,12 @@
1
- /* P.R.T.S. startup overlay. Popover promotes it above host dialogs; z-index is the legacy fallback. */
1
+ /* P.R.T.S. startup overlay. Fixed composition is the fast path; Popover is reserved for an active Host top layer. */
2
2
  html[data-dsh-prts] [data-prts-startup] {
3
3
  --prts-startup-bg: #07090b;
4
4
  --prts-startup-ink: #e8edef;
5
5
  --prts-startup-muted: #7d898f;
6
6
  --prts-startup-line: #394349;
7
7
  --prts-startup-accent: #f0c800;
8
- --prts-startup-progress: 0;
9
8
  position: fixed;
10
- z-index: 2147480000;
9
+ z-index: 2147483647;
11
10
  inset: 0;
12
11
  width: 100vw;
13
12
  max-width: none;
@@ -20,10 +19,10 @@ html[data-dsh-prts] [data-prts-startup] {
20
19
  overflow: hidden;
21
20
  isolation: isolate;
22
21
  box-sizing: border-box;
23
- background: transparent;
22
+ background: var(--prts-startup-bg);
24
23
  color: var(--prts-startup-ink);
25
24
  font-family: var(--prts-body, sans-serif);
26
- opacity: 0;
25
+ opacity: 1;
27
26
  outline: 0;
28
27
  pointer-events: auto;
29
28
  transition: opacity 120ms ease;
@@ -44,7 +43,9 @@ html[data-dsh-prts] [data-prts-startup]::after {
44
43
  html[data-dsh-prts] [data-prts-startup]::before { left: 0; }
45
44
  html[data-dsh-prts] [data-prts-startup]::after { right: 0; }
46
45
 
47
- html[data-dsh-prts] [data-prts-startup][data-visible] { opacity: 1; }
46
+ html[data-dsh-prts] [data-prts-startup][data-exiting]:not([data-reduced-motion]) {
47
+ background: transparent;
48
+ }
48
49
 
49
50
  html[data-dsh-prts] [data-prts-startup][data-exiting]::before {
50
51
  transform: translate3d(-101%, 0, 0);
@@ -347,6 +348,7 @@ html[data-dsh-prts] [data-prts-startup-track] {
347
348
  }
348
349
 
349
350
  html[data-dsh-prts] [data-prts-startup-fill] {
351
+ --prts-startup-progress: 0;
350
352
  position: absolute;
351
353
  top: -2px;
352
354
  right: 0;
@@ -356,6 +358,7 @@ html[data-dsh-prts] [data-prts-startup-fill] {
356
358
  transform: scaleX(var(--prts-startup-progress));
357
359
  transform-origin: left center;
358
360
  will-change: transform;
361
+ transition: transform 80ms linear;
359
362
  }
360
363
 
361
364
  html[data-dsh-prts] [data-prts-startup-ticks] {
@@ -407,6 +410,10 @@ html[data-dsh-prts] [data-prts-startup][data-reduced-motion] [data-prts-startup-
407
410
  transition: none;
408
411
  }
409
412
 
413
+ html[data-dsh-prts] [data-prts-startup][data-reduced-motion] [data-prts-startup-fill] {
414
+ transition: none;
415
+ }
416
+
410
417
  html[data-dsh-prts] [data-prts-startup][data-reduced-motion] [data-prts-startup-frame-outer] { transform: rotate(45deg); }
411
418
  html[data-dsh-prts] [data-prts-startup][data-reduced-motion] [data-prts-startup-frame-inner] { transform: rotate(-45deg); }
412
419