@ash-qw/dsh-theme-prts 1.2.0 → 1.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ash-qw/dsh-theme-prts",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Unofficial Arknights P.R.T.S.-inspired UI theme for DeepSeek Harness Web and the official desktop client",
@@ -1,4 +1,4 @@
1
- // Hold anywhere on a card to sort; movement before the hold keeps native touch scrolling.
1
+ // Cards own touch gestures: immediate swipes scroll, while a hold locks into sorting.
2
2
  export function mountEmblemReorder({ list, window, status, canStart, onStart, onCommit }) {
3
3
  let gesture = null, holdTimer, frame, previousTime = 0, suppressClick = false
4
4
  const rows = () => [...list.children].filter(row => row.hasAttribute('data-emblem-key'))
@@ -13,6 +13,7 @@ export function mountEmblemReorder({ list, window, status, canStart, onStart, on
13
13
  gesture = null; clear()
14
14
  current.ghost?.remove();current.row.removeAttribute('data-prts-emblem-dragging')
15
15
  list.removeAttribute('data-prts-emblem-sorting')
16
+ scroller?.removeAttribute('data-prts-emblem-sort-active')
16
17
  current.handle.setAttribute('aria-pressed','false')
17
18
  try { if (list.hasPointerCapture?.(current.pointerId)) list.releasePointerCapture(current.pointerId) } catch {}
18
19
  const ordered = rows().map(row=>row.dataset.emblemKey)
@@ -59,6 +60,7 @@ export function mountEmblemReorder({ list, window, status, canStart, onStart, on
59
60
  current.handle.setAttribute('aria-pressed','true')
60
61
  list.setAttribute('data-prts-emblem-sorting','')
61
62
  if (!current.keyboard) {
63
+ scroller?.setAttribute('data-prts-emblem-sort-active','')
62
64
  const box=current.row.getBoundingClientRect()
63
65
  const ghost=current.row.cloneNode(true)
64
66
  ghost.removeAttribute('data-emblem-key');ghost.setAttribute('data-prts-emblem-drag-ghost','')
@@ -82,17 +84,27 @@ export function mountEmblemReorder({ list, window, status, canStart, onStart, on
82
84
  const handle=row?.querySelector('[data-prts-emblem-reorder]')
83
85
  suppressClick=false
84
86
  if (!handle || handle.disabled || event.button!==0 || event.isPrimary===false || !canStart() || rows().length<2) return
85
- gesture={handle,row,pointerId:event.pointerId,startX:event.clientX,startY:event.clientY,x:event.clientX,y:event.clientY,original:rows(),active:false}
87
+ gesture={handle,row,pointerType:event.pointerType,pointerId:event.pointerId,startX:event.clientX,startY:event.clientY,x:event.clientX,y:event.clientY,original:rows(),active:false}
86
88
  holdTimer=window.setTimeout(activate,400)
87
89
  }
88
90
  const move = event => {
89
91
  if (!gesture || gesture.pointerId!==event.pointerId) return
92
+ const previousY=gesture.y
90
93
  gesture.x=event.clientX;gesture.y=event.clientY
91
- if (!gesture.active && Math.hypot(gesture.x-gesture.startX,gesture.y-gesture.startY)>8) {finish();return}
92
- if (gesture.active) event.preventDefault()
94
+ if (!gesture.active && !gesture.scrolling && Math.hypot(gesture.x-gesture.startX,gesture.y-gesture.startY)>8) {
95
+ if (gesture.pointerType !== 'touch') {finish();return}
96
+ window.clearTimeout(holdTimer)
97
+ gesture.scrolling=true;suppressClick=true
98
+ try {list.setPointerCapture(gesture.pointerId)}catch{finish();return}
99
+ // Include the movement accumulated while deciding between a tap and a swipe.
100
+ if(scroller)scroller.scrollTop += gesture.startY-previousY
101
+ }
102
+ if (gesture.scrolling && scroller) scroller.scrollTop += previousY-gesture.y
103
+ if (gesture.active || gesture.scrolling) event.preventDefault()
93
104
  }
94
105
  const up = event => {
95
106
  if (gesture?.pointerId!==event.pointerId) return
107
+ if (gesture.scrolling) {finish();return}
96
108
  const box=list.getBoundingClientRect(), viewport=(scroller || list).getBoundingClientRect()
97
109
  finish(event.clientX>=box.left && event.clientX<=box.right && event.clientY>=viewport.top && event.clientY<=viewport.bottom)
98
110
  }
@@ -21,6 +21,7 @@ const SILHOUETTE_PATHS = Object.freeze({
21
21
  })
22
22
 
23
23
  let silhouetteId = 0
24
+ const renderStates = new WeakMap()
24
25
 
25
26
  export const FACILITY_TEXTURES = Object.freeze(['none', 'grid', 'scanline', 'silhouette', 'pickup'])
26
27
 
@@ -86,6 +87,7 @@ export function ensureFacilityTextureDefs(document) {
86
87
  }
87
88
 
88
89
  function appendSilhouetteScene(document, graphic) {
90
+ renderStates.delete(graphic)
89
91
  const clipId = `prts-facility-silhouette-clip-${++silhouetteId}`
90
92
  const defs = svgNode(document, 'defs')
91
93
  const clip = svgNode(document, 'clipPath', { id: clipId, clipPathUnits: 'userSpaceOnUse' })
@@ -112,6 +114,7 @@ function appendSilhouetteScene(document, graphic) {
112
114
  }
113
115
 
114
116
  function appendSessionPickup(document, graphic) {
117
+ renderStates.delete(graphic)
115
118
  const clipId = `prts-facility-pickup-clip-${++silhouetteId}`
116
119
  const defs = svgNode(document, 'defs')
117
120
  const clip = svgNode(document, 'clipPath', { id: clipId, clipPathUnits: 'userSpaceOnUse' })
@@ -171,6 +174,7 @@ function appendSessionStatusUnderlay(document, graphic) {
171
174
  const surface = graphic.querySelector('[data-prts-facility-layer="surface"]')
172
175
  if (!surface) return
173
176
  if (!graphic.querySelector('[data-prts-session-status-underlay]')) {
177
+ renderStates.delete(graphic)
174
178
  graphic.insertBefore(svgNode(document, 'path', {
175
179
  'data-prts-session-status-underlay': '',
176
180
  'aria-hidden': 'true',
@@ -179,6 +183,7 @@ function appendSessionStatusUnderlay(document, graphic) {
179
183
  }), surface)
180
184
  }
181
185
  if (!graphic.querySelector('[data-prts-session-idle-indicator]')) {
186
+ renderStates.delete(graphic)
182
187
  graphic.insertBefore(svgNode(document, 'rect', {
183
188
  'data-prts-session-idle-indicator': '',
184
189
  'aria-hidden': 'true',
@@ -249,48 +254,60 @@ export function renderFacilityGraphic(owner, { width, height } = {}) {
249
254
  const graphic = owner?.querySelector?.(':scope > svg[data-prts-facility-svg]')
250
255
  const topNotch = graphic?.hasAttribute('data-prts-top-notch')
251
256
  const sessionNotch = graphic?.hasAttribute('data-prts-session-notch')
252
- const path = createFacilityPath({ width, height, topNotch, sessionNotch })
253
- if (!graphic || !path) {
257
+ if (!graphic || !Number.isFinite(width) || !Number.isFinite(height) || width <= 2 || height <= FACILITY_GEOMETRY.sideOpening + 2) {
258
+ if (graphic) renderStates.delete(graphic)
254
259
  owner?.removeAttribute?.('data-prts-facility-size')
255
260
  setReady(owner, false)
256
261
  return false
257
262
  }
258
263
 
259
264
  const size = `${Number(width.toFixed(3))}x${Number(height.toFixed(3))}:${topNotch ? 't' : '-'}${sessionNotch ? 's' : '-'}`
260
- const lifeline = graphic.querySelector('[data-prts-session-lifeline]')
261
- const lifelineGeometry = lifeline ? sessionLifelineGeometry(width, height) : undefined
262
- if (owner.getAttribute('data-prts-facility-size') !== size) {
263
- graphic.setAttribute('viewBox', `0 0 ${Number(width.toFixed(3))} ${Number(height.toFixed(3))}`)
264
- for (const layer of graphic.querySelectorAll('[data-prts-facility-layer], [data-prts-facility-clip]')) layer.setAttribute('d', path)
265
- const statusUnderlay = graphic.querySelector('[data-prts-session-status-underlay]')
266
- statusUnderlay?.setAttribute('d', createFacilityPath({ width, height }))
267
- const idleIndicator = graphic.querySelector('[data-prts-session-idle-indicator]')
268
- idleIndicator?.setAttribute('x', String(Number((width / 2 - 25).toFixed(3))))
269
- const silhouette = graphic.querySelector('[data-prts-facility-silhouette]')
270
- if (silhouette) {
271
- const availableHeight = Math.max(1, height - 2)
272
- silhouette.setAttribute('transform', `translate(0 1) scale(1 ${Number((availableHeight / 38).toFixed(5))})`)
265
+ let state = renderStates.get(graphic)
266
+ if (state?.size === size) {
267
+ setReady(owner, true)
268
+ return true
269
+ }
270
+ if (!state) {
271
+ state = {
272
+ layers: graphic.querySelectorAll('[data-prts-facility-layer], [data-prts-facility-clip]'),
273
+ statusUnderlay: graphic.querySelector('[data-prts-session-status-underlay]'),
274
+ idleIndicator: graphic.querySelector('[data-prts-session-idle-indicator]'),
275
+ silhouette: graphic.querySelector('[data-prts-facility-silhouette]'),
276
+ pickup: graphic.querySelector('[data-prts-session-pickup]'),
277
+ lifeline: graphic.querySelector('[data-prts-session-lifeline]'),
273
278
  }
274
- const pickup = graphic.querySelector('[data-prts-session-pickup]')
275
- if (pickup) {
276
- const center = Number((height / 2).toFixed(3))
277
- for (const baseline of pickup.querySelectorAll('[data-prts-session-pickup-baseline]')) {
278
- baseline.setAttribute('y1', String(center))
279
- baseline.setAttribute('y2', String(center))
280
- }
281
- for (const indicator of pickup.querySelectorAll('[data-prts-session-pickup-indicator]')) {
282
- indicator.setAttribute('cy', String(center))
283
- }
284
- for (const bar of pickup.querySelectorAll('[data-prts-session-pickup-bar]')) {
285
- const barHeight = Number(bar.getAttribute('height')) || 0
286
- bar.setAttribute('y', String(Number((center - barHeight / 2).toFixed(3))))
287
- }
279
+ renderStates.set(graphic, state)
280
+ }
281
+ const { statusUnderlay, idleIndicator, silhouette, pickup, lifeline } = state
282
+ const path = createFacilityPath({ width, height, topNotch, sessionNotch })
283
+ graphic.setAttribute('viewBox', `0 0 ${Number(width.toFixed(3))} ${Number(height.toFixed(3))}`)
284
+ for (const layer of state.layers) layer.setAttribute('d', path)
285
+ statusUnderlay?.setAttribute('d', createFacilityPath({ width, height }))
286
+ idleIndicator?.setAttribute('x', String(Number((width / 2 - 25).toFixed(3))))
287
+ if (silhouette && state.height !== height) {
288
+ const availableHeight = Math.max(1, height - 2)
289
+ silhouette.setAttribute('transform', `translate(0 1) scale(1 ${Number((availableHeight / 38).toFixed(5))})`)
290
+ }
291
+ if (pickup && state.height !== height) {
292
+ const center = Number((height / 2).toFixed(3))
293
+ for (const baseline of pickup.querySelectorAll('[data-prts-session-pickup-baseline]')) {
294
+ baseline.setAttribute('y1', String(center))
295
+ baseline.setAttribute('y2', String(center))
288
296
  }
289
- if (lifeline) {
290
- configureSessionLifeline(lifeline, lifelineGeometry)
297
+ for (const indicator of pickup.querySelectorAll('[data-prts-session-pickup-indicator]')) {
298
+ indicator.setAttribute('cy', String(center))
291
299
  }
292
- owner.setAttribute('data-prts-facility-size', size)
300
+ for (const bar of pickup.querySelectorAll('[data-prts-session-pickup-bar]')) {
301
+ const barHeight = Number(bar.getAttribute('height')) || 0
302
+ bar.setAttribute('y', String(Number((center - barHeight / 2).toFixed(3))))
303
+ }
304
+ }
305
+ if (lifeline) {
306
+ configureSessionLifeline(lifeline, sessionLifelineGeometry(width, height))
293
307
  }
308
+ state.size = size
309
+ state.height = height
310
+ owner.setAttribute('data-prts-facility-size', size)
294
311
  setReady(owner, true)
295
312
  return true
296
313
  }
@@ -193,7 +193,6 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
193
193
  let observer
194
194
  let resizeObserver
195
195
  let resizeFrame
196
- let resizeTimer
197
196
  let scanFrame
198
197
  let stopSessionList = () => {}
199
198
  let stopWorkspaceList = () => {}
@@ -363,6 +362,10 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
363
362
  }
364
363
 
365
364
  function flushVectors() {
365
+ if (resizeFrame !== undefined) {
366
+ if (window?.cancelAnimationFrame) window.cancelAnimationFrame(resizeFrame)
367
+ else window?.clearTimeout?.(resizeFrame)
368
+ }
366
369
  resizeFrame = undefined
367
370
  const measurements = []
368
371
  for (const [owner, observedSize] of dirtyVectors) {
@@ -533,11 +536,9 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
533
536
  const rect = entry.contentRect
534
537
  dirtyVectors.set(entry.target, rect ? { width: rect.width, height: rect.height } : undefined)
535
538
  }
536
- if (resizeTimer !== undefined) window?.clearTimeout?.(resizeTimer)
537
- resizeTimer = window?.setTimeout?.(() => {
538
- resizeTimer = undefined
539
- scheduleVectors()
540
- }, 160)
539
+ // ResizeObserver runs before paint. Update only the SVG geometry here so
540
+ // the previous viewBox is never stretched across the new card width.
541
+ flushVectors()
541
542
  })
542
543
  }
543
544
  scan()
@@ -580,8 +581,6 @@ export function createSidebarControlAdapter({ document, window, sessions, worksp
580
581
  else window?.clearTimeout?.(resizeFrame)
581
582
  }
582
583
  resizeFrame = undefined
583
- if (resizeTimer !== undefined) window?.clearTimeout?.(resizeTimer)
584
- resizeTimer = undefined
585
584
  lifelineAnimator.dispose()
586
585
  clear()
587
586
  },
@@ -3,6 +3,7 @@
3
3
  html[data-dsh-prts][data-prts-cursor="prts"] {
4
4
  --prts-hand-cursor: var(--prts-hand-frame, url("__PRTS_HAND__") 7 6);
5
5
  --prts-text-cursor: var(--prts-text-frame, url("__PRTS_TEXT__") 24 24);
6
+ --prts-sort-cursor: url("__PRTS_GRABBING__") 22 19, grabbing;
6
7
  --prts-link-cursor: url("__PRTS_LINK__") 7 7;
7
8
  cursor: var(--prts-hand-cursor), default;
8
9
  }
@@ -15,13 +16,18 @@
15
16
  html[data-dsh-prts][data-prts-cursor="prts"] :is(textarea, input:not([type]), input[type="text"], input[type="search"], input[type="email"], input[type="url"], input[type="password"], input[type="number"], input[type="tel"], [contenteditable=""], [contenteditable="true"], [contenteditable="plaintext-only"]) {
16
17
  cursor: var(--prts-text-cursor), text;
17
18
  }
19
+ html[data-dsh-prts][data-prts-cursor="prts"] [data-emblem-key],
18
20
  html[data-dsh-prts][data-prts-cursor="prts"] :is(.dsh-partner-pendant-hit, .dsh-partner-pendant-anchor, [data-prts-emblem-reorder]):enabled {
19
21
  cursor: url("__PRTS_GRAB__") 22 19, grab;
20
22
  }
21
23
  html[data-dsh-prts][data-prts-cursor="prts"] :is(.dsh-partner-pendant-hit, .dsh-partner-pendant-anchor, [data-prts-emblem-reorder]):enabled:active {
22
- cursor: url("__PRTS_GRABBING__") 22 19, grabbing;
24
+ cursor: var(--prts-sort-cursor);
23
25
  }
24
26
  html[data-dsh-prts][data-prts-cursor="prts"] :is(:disabled, [aria-disabled="true"]) {
25
27
  cursor: url("__PRTS_NOT_ALLOWED__") 7 7, not-allowed !important;
26
28
  }
27
29
  }
30
+
31
+ html[data-dsh-prts] :is([data-prts-emblem-sort-active],[data-prts-emblem-sort-active] *) {
32
+ cursor: var(--prts-sort-cursor, grabbing) !important;
33
+ }
@@ -20,8 +20,6 @@ html[data-dsh-prts] {
20
20
  --prts-host-top-inset: 0px;
21
21
  --prts-rail-width: 52px;
22
22
  --prts-nav-width: 52px;
23
- --prts-sessions-width: 286px;
24
- --prts-sessions-compact: 54px;
25
23
  --prts-workspace-height: 38px;
26
24
  --prts-session-height: 36px;
27
25
  --prts-facility-gap: 7px;
@@ -843,7 +841,7 @@ html[data-dsh-prts] [data-prts-region="sessions"] :is(
843
841
  [data-rc7-sidebar-root], [data-slot="sidebar"] > :first-child) {
844
842
  box-sizing: border-box;
845
843
  width: 100% !important;
846
- min-width: var(--prts-sessions-width);
844
+ min-width: 0;
847
845
  padding: 14px 10px;
848
846
  overflow: hidden auto;
849
847
  background: transparent !important;
@@ -325,7 +325,7 @@ padding-block: 9px;
325
325
  }
326
326
  html[data-dsh-prts] [data-prts-settings-common] [data-prts-session-flow-color-workbench] {
327
327
  display: grid;
328
- grid-template-columns: minmax(160px, .8fr) minmax(0, 1.2fr);
328
+ grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
329
329
  align-items: center;
330
330
  gap: 10px;
331
331
  }
@@ -745,7 +745,7 @@ color: var(--prts-ink);
745
745
  }
746
746
  html[data-dsh-prts] [data-prts-theme-settings] {
747
747
  & [data-prts-setting-row="sessionFlowPalette"] > div { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
748
- & [data-prts-setting-row="sessionFlowColors"] { grid-template-columns: minmax(0, 1fr); }
748
+ & [data-prts-settings-common] [data-prts-setting-row="sessionFlowColors"] { grid-template-columns: minmax(0, 1fr); }
749
749
  & [data-prts-settings-advanced] { border-top: 1px solid var(--prts-line); }
750
750
  & [data-prts-settings-advanced] > [data-prts-section-heading] { padding: 22px 0; }
751
751
  & [data-prts-settings-section][hidden] { display: none !important; }
@@ -851,7 +851,7 @@ margin-bottom: 20px;
851
851
  & [data-prts-custom-emblem] header { display: grid; gap: 6px; }
852
852
  & [data-prts-custom-emblem] :is(small, p) { font: 400 12px/1.6 var(--prts-body); color: var(--prts-muted); margin: 0; }
853
853
  & [data-prts-custom-emblem] label { display: grid; grid-template-columns: 110px minmax(0, 1fr); align-items: center; gap: 12px; font-size: 13px; }
854
- & [data-prts-emblem-editor]{display:grid;gap:14px;}& [data-prts-custom-emblem] :is(input,select){min-width:0;max-width:100%;}& [data-prts-custom-emblem] select{padding:8px;background:var(--prts-panel-raised);color:var(--prts-ink);border:1px solid var(--prts-line);}& [data-prts-emblem-preview]{touch-action:none;cursor:grab;width:min(100%,280px);height:auto;justify-self:center;border:1px solid var(--prts-line);border-radius:4px;}& [data-prts-emblem-actions]{display:flex;flex-wrap:wrap;gap:10px;}& [data-prts-emblem-actions] button{padding:10px 14px;border:1px solid var(--prts-line);border-radius:4px;color:var(--prts-ink);background:var(--prts-panel-raised);}& [data-prts-emblem-actions] button:disabled{opacity:.45;}& [data-prts-custom-emblem] h4{margin:8px 0 12px;font:600 14px/1.5 var(--prts-body);}& [data-prts-emblem-list]{display:grid;gap:10px;list-style:none;padding:0;margin:14px 0;}& :is([data-prts-emblem-list] > li,[data-prts-emblem-hero-row]){display:flex;align-items:center;flex-wrap:wrap;gap:10px;padding:12px;border:1px solid var(--prts-line);border-radius:4px;}& :is([data-prts-emblem-list],[data-prts-emblem-hero-row]) canvas{width:48px;height:48px;flex:none;border-radius:3px;}& :is([data-prts-emblem-list] > li,[data-prts-emblem-hero-row]) > span{flex:1;min-width:100px;overflow-wrap:anywhere;font-size:13px;}& [data-emblem-action]{padding:7px 10px;border:1px solid var(--prts-line);border-radius:4px;background:var(--prts-panel-raised);color:var(--prts-ink);}& [data-emblem-action]:disabled{opacity:.4;}& [data-prts-emblem-reorder]{padding:0;border:0;background:transparent;cursor:grab;}& [data-emblem-key]{user-select:none;-webkit-touch-callout:none}& [data-prts-emblem-reorder]:focus-visible{outline:2px solid var(--prts-ink);outline-offset:3px;}& [data-prts-emblem-sorting]{user-select:none;}& [data-prts-emblem-dragging]{opacity:.35;border-style:dashed !important;}& [data-prts-emblem-drag-ghost]{background:var(--prts-panel-raised);box-shadow:0 8px 28px #0005;opacity:.95;}& :is([data-prts-emblem-reset-confirm],[data-prts-emblem-workspace],[data-prts-emblem-discard]){position:fixed;inset:0;margin:auto;width:min(460px,calc(100vw - 32px));max-height:80dvh;box-sizing:border-box;overflow:auto;padding:24px;border:1px solid var(--prts-line);border-radius:8px;background:var(--prts-panel-raised);color:var(--prts-ink);box-shadow:0 16px 64px #0008;font:13px/1.7 var(--prts-body);}& :is([data-prts-emblem-reset-confirm],[data-prts-emblem-workspace],[data-prts-emblem-discard])::backdrop{background:#0008;}& [data-prts-emblem-reset-confirm]{& > strong{display:block;font-size:16px;}& > p{margin:12px 0 18px;}& > [data-prts-emblem-actions]{justify-content:flex-end;padding-top:16px;border-top:1px solid var(--prts-line);}& [data-prts-emblem-reset-cancel]{border:0;background:transparent;}& [data-emblem-action]{display:flex;gap:6px;padding:5px 10px;font-size:12px;background:transparent;}& [data-prts-emblem-reset-status]:empty{display:none;}}& [data-prts-emblem-reset-exports]{display:grid;gap:8px;margin:18px 0;}& [data-prts-emblem-reset-asset]{display:grid;grid-template-columns:36px minmax(0,1fr) auto;gap:12px;align-items:center;padding:12px;border:1px solid var(--prts-line);border-radius:4px;}& [data-prts-emblem-reset-asset] > span{overflow-wrap:anywhere;line-height:1.5;}& [data-prts-emblem-reset-asset] canvas{width:36px;height:36px;border-radius:3px;}& [data-prts-emblem-workspace]{width:min(820px,calc(100vw - 24px));padding:0;max-height:90dvh;}
854
+ & [data-prts-emblem-editor]{display:grid;gap:14px;}& [data-prts-custom-emblem] :is(input,select){min-width:0;max-width:100%;}& [data-prts-custom-emblem] select{padding:8px;background:var(--prts-panel-raised);color:var(--prts-ink);border:1px solid var(--prts-line);}& [data-prts-emblem-preview]{touch-action:none;cursor:grab;width:min(100%,280px);height:auto;justify-self:center;border:1px solid var(--prts-line);border-radius:4px;}& [data-prts-emblem-actions]{display:flex;flex-wrap:wrap;gap:10px;}& [data-prts-emblem-actions] button{padding:10px 14px;border:1px solid var(--prts-line);border-radius:4px;color:var(--prts-ink);background:var(--prts-panel-raised);}& [data-prts-emblem-actions] button:disabled{opacity:.45;}& [data-prts-custom-emblem] h4{margin:8px 0 12px;font:600 14px/1.5 var(--prts-body);}& [data-prts-emblem-list]{display:grid;gap:10px;list-style:none;padding:0;margin:14px 0;}& :is([data-prts-emblem-list] > li,[data-prts-emblem-hero-row]){display:flex;align-items:center;flex-wrap:wrap;gap:10px;padding:12px;border:1px solid var(--prts-line);border-radius:4px;}& :is([data-prts-emblem-list],[data-prts-emblem-hero-row]) canvas{width:48px;height:48px;flex:none;border-radius:3px;}& :is([data-prts-emblem-list] > li,[data-prts-emblem-hero-row]) > span{flex:1;min-width:100px;overflow-wrap:anywhere;font-size:13px;}& [data-emblem-action]{padding:7px 10px;border:1px solid var(--prts-line);border-radius:4px;background:var(--prts-panel-raised);color:var(--prts-ink);}& [data-emblem-action]:disabled{opacity:.4;}& [data-prts-emblem-reorder]{padding:0;border:0;background:transparent;cursor:grab;}& [data-emblem-key]{touch-action:none;cursor:grab;user-select:none;-webkit-touch-callout:none}& [data-prts-emblem-reorder]:focus-visible{outline:2px solid var(--prts-ink);outline-offset:3px;}& [data-prts-emblem-sorting]{user-select:none;}& [data-prts-emblem-dragging]{opacity:.35;border-style:dashed !important;}& [data-prts-emblem-drag-ghost]{background:var(--prts-panel-raised);box-shadow:0 8px 28px #0005;opacity:.95;}& :is([data-prts-emblem-reset-confirm],[data-prts-emblem-workspace],[data-prts-emblem-discard]){position:fixed;inset:0;margin:auto;width:min(460px,calc(100vw - 32px));max-height:80dvh;box-sizing:border-box;overflow:auto;padding:24px;border:1px solid var(--prts-line);border-radius:8px;background:var(--prts-panel-raised);color:var(--prts-ink);box-shadow:0 16px 64px #0008;font:13px/1.7 var(--prts-body);}& :is([data-prts-emblem-reset-confirm],[data-prts-emblem-workspace],[data-prts-emblem-discard])::backdrop{background:#0008;}& [data-prts-emblem-reset-confirm]{& > strong{display:block;font-size:16px;}& > p{margin:12px 0 18px;}& > [data-prts-emblem-actions]{justify-content:flex-end;padding-top:16px;border-top:1px solid var(--prts-line);}& [data-prts-emblem-reset-cancel]{border:0;background:transparent;}& [data-emblem-action]{display:flex;gap:6px;padding:5px 10px;font-size:12px;background:transparent;}& [data-prts-emblem-reset-status]:empty{display:none;}}& [data-prts-emblem-reset-exports]{display:grid;gap:8px;margin:18px 0;}& [data-prts-emblem-reset-asset]{display:grid;grid-template-columns:36px minmax(0,1fr) auto;gap:12px;align-items:center;padding:12px;border:1px solid var(--prts-line);border-radius:4px;}& [data-prts-emblem-reset-asset] > span{overflow-wrap:anywhere;line-height:1.5;}& [data-prts-emblem-reset-asset] canvas{width:36px;height:36px;border-radius:3px;}& [data-prts-emblem-workspace]{width:min(820px,calc(100vw - 24px));padding:0;max-height:90dvh;}
855
855
  & [data-prts-emblem-edit-header],& [data-prts-emblem-edit-bar]{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:18px 22px;}
856
856
  & [data-prts-emblem-edit-header]{border-bottom:1px solid var(--prts-line);}
857
857
  & [data-prts-emblem-edit-header] button{border:0;background:none;color:inherit;font-size:22px;}