castle-web-cli 0.4.71 → 0.4.73

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.
Files changed (57) hide show
  1. package/dist/agent-prompts.js +22 -3
  2. package/dist/agent.js +731 -313
  3. package/dist/init.js +1 -1
  4. package/dist/shell/assets/index-Dfn29Bkt.js +108 -0
  5. package/dist/shell/assets/{index-CVEnWuGV.css → index-WNbOHPBj.css} +1 -1
  6. package/dist/shell/index.html +2 -2
  7. package/dist/vitePlugins.js +3 -2
  8. package/kits/basic-2d/CLAUDE.md +29 -8
  9. package/kits/basic-2d/behaviors/Collider.jsx +6 -4
  10. package/kits/basic-2d/behaviors/Layout.jsx +2 -2
  11. package/kits/basic-2d/behaviors/Sprite.jsx +210 -0
  12. package/kits/basic-2d/behaviors/tint.js +47 -0
  13. package/kits/basic-2d/docs/pxart-format.md +298 -0
  14. package/kits/basic-2d/drawings/pig.pxart +59 -0
  15. package/kits/basic-2d/editors/App.jsx +125 -76
  16. package/kits/basic-2d/editors/CodeEditor.jsx +9 -45
  17. package/kits/basic-2d/editors/FileBrowser.jsx +234 -47
  18. package/kits/basic-2d/editors/PlayOnly.jsx +9 -7
  19. package/kits/basic-2d/editors/PxArtEditor.jsx +662 -0
  20. package/kits/basic-2d/editors/SceneEditor.jsx +587 -221
  21. package/kits/basic-2d/editors/SelectionOverlay.jsx +808 -0
  22. package/kits/basic-2d/editors/SingleEditor.jsx +38 -20
  23. package/kits/basic-2d/editors/codeTheme.js +135 -0
  24. package/kits/basic-2d/editors/editorHistory.js +44 -17
  25. package/kits/basic-2d/editors/inspectorSheet.js +23 -0
  26. package/kits/basic-2d/editors/pixelCanvas.js +11 -0
  27. package/kits/basic-2d/editors/pixelEditorChrome.jsx +55 -0
  28. package/kits/basic-2d/editors/pixelGeometry.js +45 -0
  29. package/kits/basic-2d/editors/pixelInspector.jsx +416 -0
  30. package/kits/basic-2d/editors/pxArtEditorModel.js +718 -0
  31. package/kits/basic-2d/editors/pxArtPlayback.js +92 -0
  32. package/kits/basic-2d/editors/pxArtTimeline.jsx +752 -0
  33. package/kits/basic-2d/editors/pxArtTimeline.module.css +506 -0
  34. package/kits/basic-2d/editors/pxArtTools.js +124 -0
  35. package/kits/basic-2d/editors/useArtboardFit.js +102 -0
  36. package/kits/basic-2d/engine/ScenePlayer.jsx +10 -4
  37. package/kits/basic-2d/engine/SceneUI.jsx +3 -11
  38. package/kits/basic-2d/engine/assets.js +15 -0
  39. package/kits/basic-2d/engine/files.js +57 -2
  40. package/kits/basic-2d/engine/pxart.js +985 -0
  41. package/kits/basic-2d/engine/scene.js +222 -41
  42. package/kits/basic-2d/engine/ui.jsx +155 -26
  43. package/kits/basic-2d/engine/ui.module.css +1280 -344
  44. package/kits/basic-2d/eslint.config.js +21 -0
  45. package/kits/basic-2d/index.html +13 -0
  46. package/kits/basic-2d/package.json +1 -0
  47. package/kits/basic-2d/pnpm-lock.yaml +5 -5
  48. package/kits/basic-2d/scenes/main.scene +19 -26
  49. package/kits/basic-2d/scripts/draw.mjs +121 -0
  50. package/kits/basic-3d/editors/PlayOnly.jsx +9 -1
  51. package/kits/basic-3d/engine/ScenePlayer.jsx +7 -1
  52. package/package.json +1 -1
  53. package/dist/shell/assets/index-BY21Og40.js +0 -106
  54. package/kits/basic-2d/behaviors/Drawing.jsx +0 -142
  55. package/kits/basic-2d/drawings/block.drawing +0 -70
  56. package/kits/basic-2d/drawings/default.drawing +0 -70
  57. package/kits/basic-2d/editors/DrawingEditor.jsx +0 -224
@@ -11,33 +11,47 @@
11
11
  sans-serif;
12
12
  --castle-font-display: var(--castle-font-body);
13
13
  --castle-font-mono: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
14
- --castle-black: #000;
14
+ --castle-black: #111;
15
15
  --castle-tap-highlight: #111;
16
16
  --castle-panel: #080808;
17
17
  --castle-panel-raised: #101010;
18
18
  --castle-panel-sunken: #050505;
19
19
  --castle-border: #444;
20
- --castle-border-soft: #252525;
20
+ --castle-border-soft: #2a2a2a;
21
21
  --castle-text: #fff;
22
- --castle-text-dim: #777;
23
- --castle-text-muted: #aaa;
24
- --castle-inspector-bg: #fff;
25
- --castle-inspector-text: #222;
22
+ --castle-text-dim: #888;
23
+ --castle-text-muted: #888;
24
+ --castle-inspector-bg: #0d0d0d;
25
+ --castle-inspector-text: #e6e6e6;
26
26
  --castle-inspector-muted: #888;
27
- --castle-inspector-border: #000;
28
- --castle-inspector-divider: #ccc;
29
- --castle-inspector-input-bg: #fff;
30
- --castle-inspector-button-bg: #fff;
31
- --castle-workspace-bg: #f0f0f0;
32
- --castle-stage-workspace-bg: #ddd;
33
- --castle-sheet-bg: #fff;
27
+ --castle-inspector-border: #2a2a2a;
28
+ --castle-inspector-divider: #2a2a2a;
29
+ --castle-inspector-input-bg: #161616;
30
+ --castle-inspector-button-bg: #0d0d0d;
31
+ --castle-workspace-bg: #0a0a0a;
32
+ --castle-stage-workspace-bg: #161616;
33
+ --castle-sheet-bg: #0d0d0d;
34
34
  --castle-card: #121213;
35
- --castle-selected: #e3e6ff;
36
- --castle-selected-ink: #242234;
35
+ --castle-selected: #e6e6e6;
36
+ --castle-selected-ink: #111;
37
37
  --castle-danger: #ff5d5d;
38
38
  --castle-ok: #81e69b;
39
39
  --castle-blue: #8db7ff;
40
40
  --castle-radius: 4px;
41
+ /* Tools/hotbar strip height -- aligned to the inspector "+ Add behavior" row
42
+ (top+bottom pad + 1px borders + select padding + text line). The text line
43
+ uses `rem` (root-relative), NOT `em`: the hotbar inherits the 16px body font
44
+ while the inspector sets font-size:14px, so an `em` here resolved to 20px on
45
+ the hotbar but only 17.5px inside the inspector -- leaving the Add-behavior
46
+ row ~2.5px short of the hotbar. `rem` resolves to the same value in both. */
47
+ --castle-hotbar-row-pad-y: 12px;
48
+ --castle-hotbar-row-h: calc(var(--castle-hotbar-row-pad-y) * 2 + 2px + 10px + 1.25rem);
49
+ /* Full row height shared by the scene hotbar (.sceneTools + its grid track)
50
+ and the inspector "+ Add behavior" row, so both bottom borders land on the
51
+ same y. The +2px matches the Add-behavior row's outer box; it also gives the
52
+ 46px hotbar buttons room to sit fully inside the bar (no bottom clipping). */
53
+ --castle-hotbar-row-full: calc(var(--castle-hotbar-row-h) + 2px);
54
+ color-scheme: dark;
41
55
  }
42
56
 
43
57
  :global(*) {
@@ -89,15 +103,42 @@
89
103
  outline: none;
90
104
  }
91
105
 
106
+ /* Editor-root is a vertical stack: full-width header row, then the
107
+ `[file list | workspace]` grid row. */
108
+ .editorRoot {
109
+ width: 100%;
110
+ height: 100%;
111
+ display: flex;
112
+ flex-direction: column;
113
+ background: var(--castle-workspace-bg);
114
+ color: var(--castle-inspector-text);
115
+ }
116
+
117
+ /* Portal target for the active editor's header. `display: contents` lets the
118
+ portaled `.editorHeader` be a direct flex child of `.editorRoot`. */
119
+ .editorHeaderHost {
120
+ display: contents;
121
+ }
122
+
92
123
  .appShell {
93
- width: 100vw;
94
- height: 100vh;
124
+ flex: 1 1 0;
125
+ min-height: 0;
95
126
  display: grid;
96
- grid-template-columns: 236px 1fr;
127
+ grid-template-columns: 200px 1fr;
97
128
  background: var(--castle-workspace-bg);
98
129
  color: var(--castle-inspector-text);
99
130
  }
100
131
 
132
+ /* Desktop: the files toggle collapses the file-list column. (Never set in
133
+ compact mode, where the file list is a bottom sheet instead.) */
134
+ .editorRoot.filesHidden .appShell {
135
+ grid-template-columns: 1fr;
136
+ }
137
+
138
+ .editorRoot.filesHidden .fileBrowser {
139
+ display: none;
140
+ }
141
+
101
142
  .fileBrowser {
102
143
  min-width: 0;
103
144
  border-right: 1px solid var(--castle-inspector-divider);
@@ -106,7 +147,16 @@
106
147
  flex-direction: column;
107
148
  }
108
149
 
109
- .fileBrowserHeader,
150
+ /* Bare file browser for the dockview "Files" panel: no sidebar border or
151
+ mobile-sheet chrome, just a full-height column so the tree fills the panel
152
+ and the empty area below the rows still catches the blank-area menu. */
153
+ .fileBrowserBare {
154
+ min-width: 0;
155
+ height: 100%;
156
+ display: flex;
157
+ flex-direction: column;
158
+ }
159
+
110
160
  .editorHeader {
111
161
  height: 48px;
112
162
  flex: 0 0 48px;
@@ -115,18 +165,16 @@
115
165
  gap: 8px;
116
166
  padding: 10px 12px;
117
167
  border-bottom: 1px solid var(--castle-inspector-divider);
118
- background: var(--castle-sheet-bg);
168
+ background: var(--castle-workspace-bg);
119
169
  }
120
170
 
121
- .fileBrowserTitle,
122
171
  .editorTitle {
123
172
  font-family: var(--castle-font-display);
124
173
  letter-spacing: 0.01em;
125
- font-size: 16px;
174
+ font-size: 14px;
126
175
  line-height: 1;
127
176
  }
128
177
 
129
- .fileBrowserSubtitle,
130
178
  .muted {
131
179
  color: var(--castle-inspector-muted);
132
180
  font-size: 12px;
@@ -135,7 +183,7 @@
135
183
  .fileTree {
136
184
  flex: 1 1 0;
137
185
  min-height: 0;
138
- padding: 8px 6px;
186
+ padding-top: 5px;
139
187
  overflow-y: auto;
140
188
  }
141
189
 
@@ -143,24 +191,39 @@
143
191
  min-width: 0;
144
192
  }
145
193
 
194
+ /* File-list rows ride the workspace "notch" ladder: default sits on the
195
+ workspace bg (#0a0a0a, transparent), hover lifts one notch to the sheet bg
196
+ (#0d0d0d), and the selected row lifts one notch further to panel-raised
197
+ (#101010). Text follows the same idea: unselected rows are the SAME light
198
+ text token as the selected/hover row, just faded (reduced opacity) so they
199
+ stay clearly legible on the dark panel; the selected row is the full
200
+ standard light text. */
146
201
  .fileRow,
147
202
  .fileDirRow {
148
203
  width: 100%;
149
204
  border: 0;
150
205
  border-radius: var(--castle-radius);
151
206
  background: transparent;
152
- color: var(--castle-inspector-text);
207
+ /* Plain opaque gray, NOT color-mix(...transparent): Safari fails to paint a
208
+ semi-transparent color-mix result until a repaint is forced (opening
209
+ devtools makes it appear), leaving rows invisible at rest. This solid value
210
+ approximates the light text token faded over the dark panel. */
211
+ color: #a8a8a8;
153
212
  display: flex;
154
213
  align-items: center;
155
214
  justify-content: flex-start;
156
215
  gap: 6px;
157
- padding: 8px 9px 8px calc(9px + var(--file-depth, 0) * 16px);
216
+ padding: 5px 9px 5px calc(9px + var(--file-depth, 0) * 20px);
158
217
  text-align: left;
159
218
  cursor: pointer;
219
+ font-size: 14px;
160
220
  }
161
221
 
222
+ /* Folders read darker than files at rest so the tree's structure (containers
223
+ vs. leaves) is legible at a glance. Hover/selected still lift both to the full
224
+ light text via the higher-specificity rules below. */
162
225
  .fileDirRow {
163
- color: var(--castle-inspector-muted);
226
+ color: #777;
164
227
  }
165
228
 
166
229
  .fileRow:hover,
@@ -169,29 +232,82 @@
169
232
  color: var(--castle-inspector-text);
170
233
  }
171
234
 
172
- .fileRowSelected {
173
- background: var(--castle-sheet-bg);
235
+ /* Compound `.fileRow.fileRowSelected` so the selected look (full text +
236
+ one-notch-lighter bg) outranks `.fileRow:hover` on specificity, not source
237
+ order -- the selected row stays put even while hovered. */
238
+ .fileRow.fileRowSelected,
239
+ .fileRow.fileRowSelected:hover {
240
+ background: var(--castle-panel-raised);
174
241
  color: var(--castle-inspector-text);
175
242
  }
176
243
 
177
- .fileRowSelected:hover {
178
- background: var(--castle-sheet-bg);
179
- color: var(--castle-inspector-text);
244
+ /* The disclosure caret only appears on folder rows; keep it a shade darker than
245
+ the folder name (#666 vs #777) at rest, then lift it to the full light text on
246
+ hover alongside the name. Compound `.fileIcon.fileDisclosure` (0,2,0) is
247
+ required to beat the later `.fileIcon` muted-color rule (0,1,0); a bare
248
+ `.fileDisclosure` ties on specificity and loses on source order. */
249
+ .fileIcon.fileDisclosure {
250
+ color: #666;
251
+ }
252
+
253
+ .fileDirRow:hover .fileIcon.fileDisclosure {
254
+ color: inherit;
255
+ }
256
+
257
+ .fileDisclosure svg {
258
+ width: 10px;
259
+ height: 10px;
260
+ }
261
+
262
+ /* Icon + name group: its own gap controls icon<->name spacing, independent of
263
+ the row's disclosure<->label gap. */
264
+ .fileLabel {
265
+ display: inline-flex;
266
+ align-items: center;
267
+ gap: 6px;
268
+ min-width: 0;
269
+ flex: 1 1 auto;
270
+ }
271
+
272
+ /* Inline rename field. Constrained to the row width (flex:1 + min-width:0 +
273
+ border-box) so a long name never pushes the file browser into horizontal
274
+ overflow. */
275
+ .fileRenameInput {
276
+ flex: 1 1 auto;
277
+ min-width: 0;
278
+ width: 100%;
279
+ max-width: 100%;
280
+ box-sizing: border-box;
281
+ padding: 1px 4px;
282
+ border: 1px solid var(--castle-border);
283
+ border-radius: 5px;
284
+ background: var(--castle-panel-raised);
285
+ color: var(--castle-text);
286
+ font: inherit;
287
+ font-size: 13px;
180
288
  }
181
289
 
182
- .fileDisclosure {
183
- width: 12px;
184
- flex: 0 0 12px;
290
+ .fileRenameInput:focus {
291
+ outline: none;
292
+ border-color: var(--castle-text-dim);
293
+ }
294
+
295
+ /* Type-based file icon: muted so the file name stays the visual emphasis. */
296
+ .fileIcon {
297
+ width: 14px;
298
+ flex: 0 0 14px;
185
299
  display: inline-flex;
186
300
  align-items: center;
187
301
  justify-content: center;
188
302
  color: var(--castle-inspector-muted);
189
- font-size: 10px;
303
+ font-size: 14px;
190
304
  }
191
305
 
192
306
  .mainEditor {
193
307
  min-width: 0;
194
308
  min-height: 0;
309
+ width: 100%;
310
+ height: 100%;
195
311
  display: flex;
196
312
  flex-direction: column;
197
313
  background: var(--castle-sheet-bg);
@@ -215,6 +331,8 @@
215
331
  flex: 1;
216
332
  display: flex;
217
333
  overflow: hidden;
334
+ container-type: inline-size;
335
+ container-name: editor;
218
336
  }
219
337
 
220
338
  .sceneWorkspace {
@@ -222,37 +340,112 @@
222
340
  min-width: 0;
223
341
  min-height: 0;
224
342
  display: grid;
225
- grid-template-columns: minmax(360px, 1fr) 320px;
226
- grid-template-rows: 48px minmax(0, 1fr);
343
+ grid-template-columns: minmax(0, 1fr) 280px;
344
+ grid-template-rows: var(--castle-hotbar-row-full) minmax(0, 1fr);
227
345
  }
228
346
 
229
- .sceneTools,
230
- .drawingTools {
347
+ .sceneTools {
231
348
  grid-column: 1;
232
349
  grid-row: 1;
350
+ height: var(--castle-hotbar-row-full);
351
+ min-width: 0;
233
352
  display: flex;
234
353
  align-items: center;
235
- justify-content: center;
236
- gap: 8px;
237
- padding: 8px 12px;
354
+ padding: 0;
238
355
  border-bottom: 1px solid var(--castle-inspector-divider);
239
- background: var(--castle-sheet-bg);
356
+ background: var(--castle-workspace-bg);
240
357
  }
241
358
 
242
- .sceneTools {
243
- display: grid;
244
- grid-template-columns: 1fr auto 1fr;
245
- gap: 8px;
359
+ /* Blueprint hotbar -- left-aligned djinn-style stamp palette. Today it holds a
360
+ single "+" Add-actor control; drag-and-drop blueprint slots land here later. */
361
+ .bpHotbar {
362
+ display: flex;
363
+ flex-direction: row;
364
+ align-items: center;
365
+ gap: 6px;
366
+ width: 100%;
367
+ height: 100%;
368
+ padding: 0 6px;
369
+ overflow-x: auto;
370
+ overflow-y: hidden;
371
+ }
372
+
373
+ .bpSlot,
374
+ .bpActionSlot {
375
+ width: 46px;
376
+ height: 46px;
377
+ display: inline-flex;
378
+ align-items: center;
379
+ justify-content: center;
380
+ padding: 0;
381
+ border: 1px solid var(--castle-inspector-border);
382
+ border-radius: var(--castle-radius);
383
+ background: var(--castle-inspector-button-bg);
384
+ color: var(--castle-inspector-text);
385
+ cursor: pointer;
386
+ font-size: 14px;
387
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
388
+ }
389
+
390
+ .bpSlot:hover,
391
+ .bpActionSlot:hover {
392
+ background: var(--castle-inspector-input-bg);
393
+ }
394
+
395
+ .bpSlot:disabled,
396
+ .bpActionSlot:disabled {
397
+ cursor: default;
398
+ opacity: 0.35;
399
+ }
400
+
401
+ .bpSlot svg,
402
+ .bpActionSlot svg {
403
+ width: 14px;
404
+ height: 14px;
405
+ flex: 0 0 auto;
406
+ }
407
+
408
+ .bpSlotThumb,
409
+ .bpSlotFallback {
410
+ width: 36px;
411
+ height: 36px;
412
+ flex: 0 0 36px;
413
+ border-radius: 3px;
414
+ }
415
+
416
+ .bpSlotThumb {
417
+ image-rendering: pixelated;
418
+ background: var(--castle-card);
419
+ object-fit: contain;
420
+ }
421
+
422
+ .bpSlotFallback {
423
+ display: inline-flex;
424
+ align-items: center;
425
+ justify-content: center;
426
+ color: var(--castle-inspector-muted);
246
427
  }
247
428
 
248
- .sceneToolsGroup {
429
+ .bpDragPreview {
430
+ position: fixed;
431
+ z-index: 1000;
432
+ pointer-events: none;
249
433
  display: flex;
250
434
  align-items: center;
251
- gap: 8px;
435
+ justify-content: center;
436
+ border: 1px dashed var(--castle-text);
437
+ background: rgb(230 230 230 / 0.08);
438
+ opacity: 0.7;
252
439
  }
253
440
 
254
- .sceneToolsGroup:last-child {
255
- justify-self: end;
441
+ .bpDragPreviewOverStage {
442
+ opacity: 0.9;
443
+ }
444
+
445
+ .bpPreviewThumb {
446
+ width: 100%;
447
+ height: 100%;
448
+ flex: 1 1 auto;
256
449
  }
257
450
 
258
451
  .stageWrap {
@@ -265,20 +458,30 @@
265
458
  justify-content: center;
266
459
  padding: 20px;
267
460
  background: var(--castle-stage-workspace-bg);
461
+ overflow: hidden;
268
462
  }
269
463
 
270
464
  .stageCard {
271
465
  position: relative;
272
466
  width: min(52vh, 440px);
273
467
  aspect-ratio: 5 / 7;
274
- max-width: calc(100vw - 620px);
468
+ max-width: 100%;
469
+ overflow: visible;
470
+ }
471
+
472
+ .stageCardClip {
473
+ position: absolute;
474
+ inset: 0;
275
475
  background: var(--castle-card);
276
- border: 1px solid var(--castle-inspector-border);
277
476
  border-radius: 12px;
278
477
  overflow: hidden;
279
478
  box-shadow: 0 2px 0 rgba(0, 0, 0, 0.2);
280
479
  }
281
480
 
481
+ .stageCardEditSurface {
482
+ overflow: visible;
483
+ }
484
+
282
485
  .stageCanvas {
283
486
  width: 100%;
284
487
  height: 100%;
@@ -286,6 +489,14 @@
286
489
  touch-action: none;
287
490
  }
288
491
 
492
+ .stageCanvasEdit {
493
+ position: absolute;
494
+ left: -100%;
495
+ top: -100%;
496
+ width: 300%;
497
+ height: 300%;
498
+ }
499
+
289
500
  /* Game-time UI overlay -- sits exactly over the canvas and clips to the card.
290
501
  Behavior `ui` output lands in `.sceneUiLayer`, which is sized in card units
291
502
  and scaled onto the canvas box. */
@@ -303,334 +514,1064 @@
303
514
  transform-origin: 0 0;
304
515
  }
305
516
 
306
- .inspector {
307
- grid-column: 2;
308
- grid-row: 1 / span 2;
309
- min-width: 0;
310
- border-left: 1px solid var(--castle-inspector-divider);
311
- background: var(--castle-inspector-bg);
312
- color: var(--castle-inspector-text);
313
- overflow: auto;
314
- padding: 0;
517
+ /* On-canvas selection toolbar ("selection handles"). Two stacked layers cover
518
+ the canvas box (sized by a ResizeObserver, like .sceneUiRoot):
519
+ - .selChromeLayer is the card-unit (500x700) layer, scaled onto the canvas
520
+ and translated by -camera so the dashed box / dots / pivot track the edit
521
+ camera exactly like the canvas draw path. Chrome lives in card units, so it
522
+ scales gently with the responsive card.
523
+ - .selButtonLayer is an un-scaled px layer; the floating buttons are placed
524
+ in projected px (world -> screen) so they stay crisp and fixed-size with
525
+ fixed px gaps regardless of card scale. */
526
+ .selOverlayRoot {
527
+ position: absolute;
528
+ inset: 0;
529
+ overflow: visible;
530
+ pointer-events: none;
531
+ animation: selOverlayIn 150ms ease;
315
532
  }
316
533
 
317
- .panel {
318
- border: 0;
319
- border-bottom: 1px solid var(--castle-inspector-divider);
320
- border-radius: 0;
321
- background: var(--castle-inspector-bg);
322
- color: var(--castle-inspector-text);
323
- margin: 0;
324
- overflow: visible;
325
- box-shadow: none;
534
+ @keyframes selOverlayIn {
535
+ from {
536
+ opacity: 0;
537
+ transform: scale(0.92);
538
+ }
539
+ to {
540
+ opacity: 1;
541
+ transform: scale(1);
542
+ }
326
543
  }
327
544
 
328
- .panel:last-child {
329
- border-bottom: 0;
545
+ .selChromeLayer {
546
+ position: absolute;
547
+ left: 0;
548
+ top: 0;
549
+ transform-origin: 0 0;
550
+ pointer-events: none;
330
551
  }
331
552
 
332
- .panelHeader {
333
- padding: 14px 16px 6px;
334
- border-bottom: 0;
335
- color: var(--castle-inspector-text);
336
- font-size: 16px;
337
- font-weight: 650;
553
+ .selChromeWorld {
554
+ position: absolute;
555
+ left: 0;
556
+ top: 0;
338
557
  }
339
558
 
340
- .panelBody {
341
- padding: 8px 16px 4px;
559
+ .selChromeRotate {
560
+ position: absolute;
561
+ left: 0;
562
+ top: 0;
342
563
  }
343
564
 
344
- .fieldRow {
345
- display: grid;
346
- grid-template-columns: minmax(82px, 0.5fr) minmax(0, 1fr);
347
- align-items: center;
348
- gap: 12px;
349
- padding-bottom: 12px;
350
- margin-bottom: 0;
351
- min-height: 28px;
565
+ .selColliderBox {
566
+ position: absolute;
567
+ box-sizing: border-box;
568
+ border: 2px solid rgb(141 183 255 / 0.9);
569
+ background: rgb(141 183 255 / 0.14);
570
+ border-radius: 2px;
571
+ pointer-events: none;
352
572
  }
353
573
 
354
- .fieldRow:last-child {
355
- margin-bottom: 0;
574
+ .selColliderPickup {
575
+ border-color: rgb(255 225 122 / 0.9);
576
+ background: rgb(255 225 122 / 0.14);
356
577
  }
357
578
 
358
- .fieldLabel {
359
- color: var(--castle-inspector-text);
360
- font-size: 16px;
579
+ .selBox {
580
+ position: absolute;
581
+ border: 2px dashed var(--castle-text);
582
+ border-radius: 3px;
583
+ opacity: 0.85;
361
584
  }
362
585
 
363
- .input,
364
- .select,
365
- .textarea {
366
- width: 100%;
367
- border: 1px solid var(--castle-inspector-border);
368
- border-radius: var(--castle-radius);
369
- background: var(--castle-inspector-input-bg);
370
- color: var(--castle-inspector-text);
371
- padding: 5px 8px;
372
- outline: 0;
586
+ /* Connector stem from the box's right-center edge to the rotate handle. */
587
+ .selStem {
588
+ position: absolute;
589
+ height: 2px;
590
+ background: var(--castle-text);
591
+ opacity: 0.7;
592
+ transform: translateY(-50%);
373
593
  }
374
594
 
375
- .select {
376
- appearance: none;
377
- -webkit-appearance: none;
378
- padding-right: 26px;
379
- background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' fill='none' stroke='%23222' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
380
- background-repeat: no-repeat;
381
- background-position: right 8px center;
382
- text-overflow: ellipsis;
595
+ .selScaleHandle {
596
+ position: absolute;
597
+ border: 0;
598
+ padding: 0;
599
+ background: var(--castle-text);
600
+ border: 2px solid var(--castle-selected-ink);
601
+ transform: translate(-50%, -50%);
602
+ pointer-events: auto;
603
+ touch-action: none;
604
+ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
383
605
  }
384
606
 
385
- .numberField {
386
- position: relative;
387
- width: 100%;
607
+ .selScaleCorner {
608
+ width: 11px;
609
+ height: 11px;
610
+ border-radius: 999px;
388
611
  }
389
612
 
390
- .numberInput {
391
- padding-right: 22px;
392
- appearance: textfield;
393
- -moz-appearance: textfield;
613
+ .selScaleEdge {
614
+ border-radius: 999px;
394
615
  }
395
616
 
396
- .numberInput::-webkit-inner-spin-button,
397
- .numberInput::-webkit-outer-spin-button {
398
- -webkit-appearance: none;
399
- appearance: none;
400
- margin: 0;
617
+ .selScaleEdge[data-handle='n'],
618
+ .selScaleEdge[data-handle='s'] {
619
+ width: 28px;
620
+ height: 9px;
401
621
  }
402
622
 
403
- .numberSteppers {
623
+ .selScaleEdge[data-handle='e'],
624
+ .selScaleEdge[data-handle='w'] {
625
+ width: 9px;
626
+ height: 28px;
627
+ }
628
+
629
+ .selPivot {
404
630
  position: absolute;
405
- top: 1px;
406
- right: 1px;
407
- bottom: 1px;
408
- width: 18px;
409
- display: flex;
410
- flex-direction: column;
411
- border-left: 1px solid var(--castle-inspector-divider);
412
- opacity: 0;
631
+ width: 13px;
632
+ height: 13px;
633
+ border-radius: 999px;
634
+ border: 2px solid var(--castle-text);
635
+ background: transparent;
636
+ opacity: 0.85;
637
+ transform: translate(-50%, -50%);
638
+ }
639
+
640
+ .selButtonLayer {
641
+ position: absolute;
642
+ inset: 0;
413
643
  pointer-events: none;
414
- transition: opacity 0.1s;
415
644
  }
416
645
 
417
- .numberField:hover .numberSteppers,
418
- .numberField:focus-within .numberSteppers {
419
- opacity: 1;
646
+ .selBtnWrap {
647
+ position: absolute;
648
+ transform: translate(-50%, -50%);
420
649
  pointer-events: auto;
421
650
  }
422
651
 
423
- .numberStepper {
424
- flex: 1;
652
+ .selBtnGroup {
653
+ display: flex;
654
+ gap: 8px;
655
+ }
656
+
657
+ .selArrangeWrap {
658
+ position: relative;
659
+ }
660
+
661
+ .selArrangeMenu {
662
+ position: absolute;
663
+ left: 50%;
664
+ top: calc(100% + 8px);
665
+ min-width: 150px;
666
+ padding: 5px;
667
+ border: 1px solid var(--castle-border);
668
+ border-radius: 10px;
669
+ background: var(--castle-panel-raised);
670
+ color: var(--castle-text);
671
+ box-shadow: 0 10px 26px rgba(0, 0, 0, 0.45);
672
+ transform: translateX(-50%);
673
+ z-index: 2;
674
+ }
675
+
676
+ .selArrangeItem {
677
+ width: 100%;
678
+ border: 0;
679
+ border-radius: 7px;
680
+ padding: 7px 9px;
681
+ background: transparent;
682
+ color: inherit;
683
+ cursor: pointer;
684
+ font: inherit;
685
+ font-size: 12px;
686
+ text-align: left;
687
+ white-space: nowrap;
688
+ }
689
+
690
+ .selArrangeItem:hover {
691
+ background: var(--castle-panel);
692
+ }
693
+
694
+ .selArrangeItemDisabled,
695
+ .selArrangeItemDisabled:hover {
696
+ opacity: 0.4;
697
+ background: transparent;
698
+ cursor: default;
699
+ }
700
+
701
+ .selBtn {
702
+ width: 32px;
703
+ height: 32px;
704
+ border-radius: 999px;
705
+ border: 1px solid var(--castle-border);
706
+ background: var(--castle-panel-raised);
707
+ color: var(--castle-text);
708
+ display: inline-flex;
709
+ align-items: center;
710
+ justify-content: center;
711
+ padding: 0;
712
+ font-size: 14px;
713
+ cursor: pointer;
714
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.45);
715
+ touch-action: none;
716
+ }
717
+
718
+ .selBtn:hover {
719
+ background: var(--castle-panel);
720
+ border-color: var(--castle-text-dim);
721
+ }
722
+
723
+ .selBtn svg {
724
+ width: 1em;
725
+ height: 1em;
726
+ }
727
+
728
+ .selBtnGrab {
729
+ cursor: grab;
730
+ }
731
+
732
+ .selBtnRotate {
733
+ cursor: grab;
734
+ }
735
+
736
+ /* Touch targets: larger hit area on coarse pointers / compact layout. */
737
+ @media (pointer: coarse), (max-width: 600px) {
738
+ .selBtn {
739
+ width: 44px;
740
+ height: 44px;
741
+ font-size: 18px;
742
+ }
743
+
744
+ .selBtnGroup {
745
+ gap: 12px;
746
+ }
747
+
748
+ .selScaleCorner {
749
+ width: 17px;
750
+ height: 17px;
751
+ }
752
+
753
+ .selScaleEdge[data-handle='n'],
754
+ .selScaleEdge[data-handle='s'] {
755
+ width: 38px;
756
+ height: 15px;
757
+ }
758
+
759
+ .selScaleEdge[data-handle='e'],
760
+ .selScaleEdge[data-handle='w'] {
761
+ width: 15px;
762
+ height: 38px;
763
+ }
764
+ }
765
+
766
+ .inspector {
767
+ grid-column: 2;
768
+ grid-row: 1 / span 2;
769
+ min-width: 0;
770
+ border-left: 1px solid var(--castle-inspector-divider);
771
+ background: var(--castle-workspace-bg);
772
+ color: var(--castle-inspector-text);
773
+ font-size: 14px;
774
+ overflow: auto;
775
+ padding: 0;
776
+ }
777
+
778
+ .panel {
779
+ border: 0;
780
+ border-bottom: 1px solid var(--castle-inspector-divider);
781
+ border-radius: 0;
782
+ background: var(--castle-inspector-bg);
783
+ color: var(--castle-inspector-text);
784
+ font-size: 14px;
785
+ margin: 0;
786
+ overflow: visible;
787
+ box-shadow: none;
788
+ }
789
+
790
+ .panel:last-child {
791
+ border-bottom: 0;
792
+ }
793
+
794
+ .panelHeader {
795
+ display: flex;
796
+ align-items: center;
797
+ justify-content: space-between;
798
+ gap: 12px;
799
+ padding: 14px 16px 6px;
800
+ border-bottom: 0;
801
+ color: var(--castle-inspector-text);
802
+ font-size: 14px;
803
+ font-weight: 650;
804
+ }
805
+
806
+ .panelBody {
807
+ padding: 8px 16px 4px;
808
+ }
809
+
810
+ .fieldRow {
811
+ display: grid;
812
+ grid-template-columns: minmax(82px, 0.5fr) minmax(0, 1fr);
813
+ align-items: center;
814
+ gap: 12px;
815
+ padding-bottom: 12px;
816
+ margin-bottom: 0;
817
+ min-height: 28px;
818
+ }
819
+
820
+ .fieldRow:last-child {
821
+ margin-bottom: 0;
822
+ }
823
+
824
+ .fieldLabel {
825
+ color: var(--castle-inspector-text);
826
+ font-size: 14px;
827
+ }
828
+
829
+ .input,
830
+ .select,
831
+ .textarea {
832
+ width: 100%;
833
+ border: 1px solid var(--castle-inspector-border);
834
+ border-radius: var(--castle-radius);
835
+ background: var(--castle-inspector-input-bg);
836
+ color: var(--castle-inspector-text);
837
+ padding: 5px 8px;
838
+ outline: 0;
839
+ }
840
+
841
+ .select {
842
+ appearance: none;
843
+ -webkit-appearance: none;
844
+ padding-right: 26px;
845
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' fill='none' stroke='%23888888' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
846
+ background-repeat: no-repeat;
847
+ background-position: right 8px center;
848
+ text-overflow: ellipsis;
849
+ }
850
+
851
+ .numberField {
852
+ position: relative;
853
+ width: 100%;
854
+ }
855
+
856
+ .numberInput {
857
+ padding-right: 22px;
858
+ appearance: textfield;
859
+ -moz-appearance: textfield;
860
+ }
861
+
862
+ .numberInput::-webkit-inner-spin-button,
863
+ .numberInput::-webkit-outer-spin-button {
864
+ -webkit-appearance: none;
865
+ appearance: none;
866
+ margin: 0;
867
+ }
868
+
869
+ .numberSteppers {
870
+ position: absolute;
871
+ top: 1px;
872
+ right: 1px;
873
+ bottom: 1px;
874
+ width: 18px;
875
+ display: flex;
876
+ flex-direction: column;
877
+ border-left: 1px solid var(--castle-inspector-divider);
878
+ opacity: 0;
879
+ pointer-events: none;
880
+ transition: opacity 0.1s;
881
+ }
882
+
883
+ .numberField:hover .numberSteppers,
884
+ .numberField:focus-within .numberSteppers {
885
+ opacity: 1;
886
+ pointer-events: auto;
887
+ }
888
+
889
+ .numberStepper {
890
+ flex: 1;
891
+ display: flex;
892
+ align-items: center;
893
+ justify-content: center;
894
+ border: 0;
895
+ padding: 0;
896
+ background: transparent;
897
+ color: var(--castle-inspector-muted);
898
+ cursor: pointer;
899
+ font-size: 14px;
900
+ line-height: 1;
901
+ }
902
+
903
+ .numberStepper:first-child {
904
+ border-bottom: 1px solid var(--castle-inspector-divider);
905
+ }
906
+
907
+ .numberStepper:hover {
908
+ background: var(--castle-inspector-input-bg);
909
+ color: var(--castle-inspector-text);
910
+ }
911
+
912
+ .numberStepper:disabled {
913
+ opacity: 0.3;
914
+ cursor: default;
915
+ background: transparent;
916
+ }
917
+
918
+ .colorInput {
919
+ width: 100%;
920
+ height: 28px;
921
+ border: 1px solid var(--castle-inspector-border);
922
+ border-radius: var(--castle-radius);
923
+ background: var(--castle-inspector-input-bg);
924
+ padding: 2px;
925
+ outline: 0;
926
+ cursor: pointer;
927
+ }
928
+
929
+ .toggle {
930
+ width: 44px;
931
+ height: 24px;
932
+ border: 1px solid var(--castle-inspector-border);
933
+ border-radius: 999px;
934
+ background: var(--castle-inspector-input-bg);
935
+ padding: 2px;
936
+ cursor: pointer;
937
+ display: flex;
938
+ align-items: center;
939
+ justify-content: flex-start;
940
+ box-shadow: none;
941
+ }
942
+
943
+ .toggleOn {
944
+ background: var(--castle-black);
945
+ justify-content: flex-end;
946
+ }
947
+
948
+ .toggleKnob {
949
+ width: 18px;
950
+ height: 18px;
951
+ border-radius: 999px;
952
+ background: var(--castle-inspector-muted);
953
+ }
954
+
955
+ .toggleOn .toggleKnob {
956
+ background: var(--castle-text);
957
+ }
958
+
959
+ .textarea {
960
+ min-height: 0;
961
+ resize: none;
962
+ font-family: var(--castle-font-mono);
963
+ font-size: 14px;
964
+ line-height: 1.45;
965
+ }
966
+
967
+ /* Shared chrome for the inspector "Button" and every square icon button: a 1px
968
+ border, sunken fill, text-colored glyph, and a subtle drop line. */
969
+ .button,
970
+ .iconButton {
971
+ border: 1px solid var(--castle-inspector-border);
972
+ border-radius: var(--castle-radius);
973
+ background: var(--castle-inspector-button-bg);
974
+ color: var(--castle-inspector-text);
975
+ cursor: pointer;
976
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
977
+ }
978
+
979
+ .button {
980
+ padding: 6px 10px;
981
+ }
982
+
983
+ /* The square icon button -- the single source of truth every other square icon
984
+ button across the editor matches. Default/hover/active follow the pixel
985
+ editor's eyedropper; the disabled dimming follows the undo button. Fixed
986
+ 28x28, never shrinks in a toolbar row, and centers a 14px glyph. */
987
+ .iconButton {
988
+ width: 28px;
989
+ height: 28px;
990
+ flex: 0 0 auto;
991
+ padding: 0;
992
+ display: inline-flex;
993
+ align-items: center;
994
+ justify-content: center;
995
+ }
996
+
997
+ .iconButton svg {
998
+ width: 14px;
999
+ height: 14px;
1000
+ }
1001
+
1002
+ .dashedSquareIcon {
1003
+ width: 14px;
1004
+ height: 14px;
1005
+ border: 2px dashed currentColor;
1006
+ border-radius: 2px;
1007
+ }
1008
+
1009
+ .button:hover,
1010
+ .iconButton:hover {
1011
+ background: var(--castle-inspector-input-bg);
1012
+ }
1013
+
1014
+ .buttonDanger {
1015
+ color: var(--castle-danger);
1016
+ }
1017
+
1018
+ .button:disabled,
1019
+ .iconButton:disabled {
1020
+ opacity: 0.35;
1021
+ cursor: default;
1022
+ }
1023
+
1024
+ .actorList {
1025
+ display: grid;
1026
+ gap: 4px;
1027
+ }
1028
+
1029
+ .actorRow {
1030
+ width: 100%;
1031
+ border: 1px solid transparent;
1032
+ background: transparent;
1033
+ color: var(--castle-inspector-text);
1034
+ border-radius: var(--castle-radius);
1035
+ padding: 7px 8px;
1036
+ text-align: left;
1037
+ cursor: pointer;
1038
+ }
1039
+
1040
+ .actorRowSelected {
1041
+ background: var(--castle-black);
1042
+ border-color: var(--castle-black);
1043
+ color: var(--castle-text);
1044
+ }
1045
+
1046
+ .drawingEditor,
1047
+ .codeEditor {
1048
+ flex: 1;
1049
+ min-width: 0;
1050
+ min-height: 0;
1051
+ display: grid;
1052
+ grid-template-columns: minmax(320px, 1fr) 280px;
1053
+ background: var(--castle-workspace-bg);
1054
+ }
1055
+
1056
+ .drawingEditor {
1057
+ grid-template-columns: minmax(320px, 1fr) minmax(50px, 250px);
1058
+ grid-template-rows: minmax(0, 1fr);
1059
+ }
1060
+
1061
+ .drawingEditor > .pxArtInspector {
1062
+ grid-column: 2;
1063
+ }
1064
+
1065
+ .artboardToolColumn,
1066
+ .paintColumn {
1067
+ flex: 0 0 50px;
1068
+ display: flex;
1069
+ align-items: flex-start;
1070
+ justify-content: center;
1071
+ height: 100%;
1072
+ padding: 8px;
1073
+ box-sizing: border-box;
1074
+ background: var(--castle-workspace-bg);
1075
+ }
1076
+
1077
+ .paintColumn {
1078
+ display: none;
1079
+ }
1080
+
1081
+ .drawingToolColumn {
1082
+ display: flex;
1083
+ align-items: flex-start;
1084
+ justify-content: center;
1085
+ width: 50px;
1086
+ min-width: 0;
1087
+ min-height: 0;
1088
+ height: 100%;
1089
+ padding: 8px;
1090
+ box-sizing: border-box;
1091
+ background: var(--castle-workspace-bg);
1092
+ }
1093
+
1094
+ .drawingCanvasWrap {
1095
+ flex: 1 1 0;
1096
+ min-width: 0;
1097
+ min-height: 0;
1098
+ display: flex;
1099
+ align-items: center;
1100
+ justify-content: center;
1101
+ padding: 16px 24px;
1102
+ overflow: hidden;
1103
+ }
1104
+
1105
+ .artboardStack {
1106
+ display: flex;
1107
+ flex-direction: column;
1108
+ align-items: center;
1109
+ gap: 10px;
1110
+ min-width: 0;
1111
+ max-width: 100%;
1112
+ max-height: 100%;
1113
+ }
1114
+
1115
+ .canvasSizeBar {
1116
+ display: flex;
1117
+ align-items: center;
1118
+ gap: 6px;
1119
+ flex: 0 0 auto;
1120
+ font-size: 12px;
1121
+ color: var(--castle-inspector-muted);
1122
+ }
1123
+
1124
+ .canvasSizeSep {
1125
+ color: var(--castle-inspector-muted);
1126
+ user-select: none;
1127
+ }
1128
+
1129
+ .canvasSizeSelect {
1130
+ width: 52px;
1131
+ border: 1px solid var(--castle-inspector-border);
1132
+ border-radius: var(--castle-radius);
1133
+ background: var(--castle-inspector-input-bg);
1134
+ color: var(--castle-inspector-text);
1135
+ padding: 3px 22px 3px 6px;
1136
+ font-size: 12px;
1137
+ text-align: center;
1138
+ appearance: none;
1139
+ -webkit-appearance: none;
1140
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' fill='none' stroke='%23888888' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
1141
+ background-repeat: no-repeat;
1142
+ background-position: right 6px center;
1143
+ }
1144
+
1145
+ .pxArtInspector {
1146
+ min-width: 0;
1147
+ border-left: 1px solid var(--castle-inspector-divider);
1148
+ background: var(--castle-workspace-bg);
1149
+ color: var(--castle-inspector-text);
1150
+ font-size: 14px;
1151
+ overflow: hidden;
1152
+ display: flex;
1153
+ flex-direction: column;
1154
+ }
1155
+
1156
+ .paintStrip {
1157
+ display: flex;
1158
+ flex-direction: column;
1159
+ width: 34px;
1160
+ flex: 0 0 auto;
1161
+ border: 1px solid var(--castle-inspector-border);
1162
+ border-radius: var(--castle-radius);
1163
+ overflow: hidden;
1164
+ }
1165
+
1166
+ .paintStrip > * + * {
1167
+ border-top: 1px solid var(--castle-inspector-border);
1168
+ }
1169
+
1170
+ .paintStripColor {
1171
+ width: 34px;
1172
+ height: 34px;
1173
+ padding: 0;
1174
+ border: 0;
1175
+ border-radius: 0;
1176
+ cursor: pointer;
1177
+ flex: 0 0 auto;
1178
+ }
1179
+
1180
+ .paintStripSlider {
1181
+ height: 100px;
1182
+ display: flex;
1183
+ align-items: center;
1184
+ justify-content: center;
1185
+ padding: 8px 0;
1186
+ flex: 0 0 auto;
1187
+ }
1188
+
1189
+ .paintStripModeButton {
1190
+ width: 34px;
1191
+ height: 34px;
1192
+ padding: 0;
1193
+ display: inline-flex;
1194
+ align-items: center;
1195
+ justify-content: center;
1196
+ border: 0;
1197
+ border-radius: 0;
1198
+ background: var(--castle-inspector-button-bg);
1199
+ color: var(--castle-inspector-text);
1200
+ cursor: pointer;
1201
+ font-size: 14px;
1202
+ line-height: 1;
1203
+ }
1204
+
1205
+ .paintStripModeButton svg {
1206
+ width: 1em;
1207
+ height: 1em;
1208
+ }
1209
+
1210
+ .paintStripModeButton:hover {
1211
+ background: var(--castle-inspector-input-bg);
1212
+ }
1213
+
1214
+ .drawingSizeSliderVertical {
1215
+ width: 88px;
1216
+ height: 14px;
1217
+ margin: 0;
1218
+ cursor: pointer;
1219
+ transform: rotate(-90deg);
1220
+ appearance: none;
1221
+ -webkit-appearance: none;
1222
+ background: transparent;
1223
+ }
1224
+
1225
+ .drawingSizeSliderVertical:disabled {
1226
+ cursor: default;
1227
+ opacity: 0.45;
1228
+ }
1229
+
1230
+ .drawingSizeSliderVertical::-webkit-slider-runnable-track {
1231
+ height: 4px;
1232
+ border-radius: 999px;
1233
+ background: #4a4a4a;
1234
+ }
1235
+
1236
+ .drawingSizeSliderVertical::-webkit-slider-thumb {
1237
+ appearance: none;
1238
+ -webkit-appearance: none;
1239
+ width: 14px;
1240
+ height: 14px;
1241
+ margin-top: -5px;
1242
+ border-radius: 999px;
1243
+ border: 1px solid #d8d8d8;
1244
+ background: #fff;
1245
+ }
1246
+
1247
+ .drawingSizeSliderVertical::-moz-range-track {
1248
+ height: 4px;
1249
+ border-radius: 999px;
1250
+ background: #4a4a4a;
1251
+ }
1252
+
1253
+ .drawingSizeSliderVertical::-moz-range-thumb {
1254
+ width: 14px;
1255
+ height: 14px;
1256
+ border-radius: 999px;
1257
+ border: 1px solid #d8d8d8;
1258
+ background: #fff;
1259
+ }
1260
+
1261
+ .palettePopover {
1262
+ position: fixed;
1263
+ z-index: 200;
1264
+ width: min(280px, calc(100vw - 16px));
1265
+ max-height: min(420px, calc(100vh - 16px));
1266
+ overflow: auto;
1267
+ padding: 12px 14px 14px;
1268
+ border: 1px solid var(--castle-inspector-border);
1269
+ border-radius: var(--castle-radius);
1270
+ background: var(--castle-workspace-bg);
1271
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
1272
+ }
1273
+
1274
+ .palettePopoverHeader {
1275
+ display: flex;
1276
+ align-items: center;
1277
+ justify-content: space-between;
1278
+ gap: 10px;
1279
+ margin-bottom: 10px;
1280
+ }
1281
+
1282
+ .palettePopoverTitle {
1283
+ font-size: 14px;
1284
+ font-weight: 650;
1285
+ }
1286
+
1287
+ .drawingArtboard {
1288
+ min-width: 0;
1289
+ min-height: 0;
425
1290
  display: flex;
426
1291
  align-items: center;
427
1292
  justify-content: center;
428
- border: 0;
429
- padding: 0;
430
- background: transparent;
431
- color: var(--castle-inspector-muted);
432
- cursor: pointer;
433
- font-size: 8px;
434
- line-height: 1;
435
- }
436
-
437
- .numberStepper:first-child {
438
- border-bottom: 1px solid var(--castle-inspector-divider);
439
1293
  }
440
1294
 
441
- .numberStepper:hover {
442
- background: #eee;
443
- color: var(--castle-inspector-text);
1295
+ .drawingCanvas {
1296
+ image-rendering: pixelated;
1297
+ background:
1298
+ linear-gradient(45deg, #1a1a1a 25%, transparent 25%),
1299
+ linear-gradient(-45deg, #1a1a1a 25%, transparent 25%),
1300
+ linear-gradient(45deg, transparent 75%, #1a1a1a 75%),
1301
+ linear-gradient(-45deg, transparent 75%, #1a1a1a 75%);
1302
+ background-color: #121212;
1303
+ background-size: 16px 16px;
1304
+ background-position:
1305
+ 0 0,
1306
+ 0 8px,
1307
+ 8px -8px,
1308
+ -8px 0;
1309
+ border: 1px solid var(--castle-inspector-border);
1310
+ flex: 0 0 auto;
444
1311
  }
445
1312
 
446
- .numberStepper:disabled {
447
- opacity: 0.3;
448
- cursor: default;
449
- background: transparent;
1313
+ .palette {
1314
+ display: grid;
1315
+ grid-template-columns: repeat(12, minmax(0, 1fr));
1316
+ gap: 4px;
1317
+ padding-bottom: 12px;
450
1318
  }
451
1319
 
452
- .colorInput {
453
- width: 100%;
454
- height: 28px;
1320
+ .swatch {
1321
+ aspect-ratio: 1;
455
1322
  border: 1px solid var(--castle-inspector-border);
456
1323
  border-radius: var(--castle-radius);
457
- background: var(--castle-inspector-input-bg);
458
- padding: 2px;
459
- outline: 0;
460
1324
  cursor: pointer;
461
1325
  }
462
1326
 
463
- .toggle {
464
- width: 44px;
465
- height: 24px;
466
- border: 1px solid var(--castle-inspector-border);
467
- border-radius: 999px;
468
- background: #fff;
469
- padding: 2px;
470
- cursor: pointer;
471
- display: flex;
472
- align-items: center;
473
- justify-content: flex-start;
474
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
1327
+ /* Selected paint color. A double ring — light on the inside, dark on the
1328
+ outside — so the selection stays legible over ANY of the 64 swatch colors
1329
+ (a single-color border can vanish against a similar swatch). */
1330
+ .swatchSelected {
1331
+ border-color: transparent;
1332
+ box-shadow:
1333
+ inset 0 0 0 2px #fff,
1334
+ 0 0 0 2px var(--castle-black);
475
1335
  }
476
1336
 
477
- .toggleOn {
478
- background: var(--castle-black);
479
- justify-content: flex-end;
1337
+ .drawingToolStrip {
1338
+ display: flex;
1339
+ flex-direction: column;
1340
+ width: 34px;
1341
+ flex: 0 0 auto;
1342
+ max-height: 100%;
1343
+ overflow: auto;
1344
+ border: 1px solid var(--castle-inspector-border);
1345
+ border-radius: var(--castle-radius);
480
1346
  }
481
1347
 
482
- .toggleKnob {
483
- width: 18px;
484
- height: 18px;
485
- border-radius: 999px;
486
- background: var(--castle-black);
1348
+ .drawingToolStrip > * + * {
1349
+ border-top: 1px solid var(--castle-inspector-border);
487
1350
  }
488
1351
 
489
- .toggleOn .toggleKnob {
490
- background: var(--castle-text);
1352
+ .drawingToolsPanel {
1353
+ overflow: hidden;
1354
+ display: flex;
1355
+ flex-direction: column;
491
1356
  }
492
1357
 
493
- .textarea {
1358
+ .drawingToolsPanelBody {
1359
+ flex: 1 1 0;
494
1360
  min-height: 0;
495
- resize: none;
496
- font-family: var(--castle-font-mono);
497
- font-size: 12px;
498
- line-height: 1.45;
1361
+ display: grid;
1362
+ grid-template-columns: 58px minmax(0, 1fr);
499
1363
  }
500
1364
 
501
- .button {
502
- border: 1px solid var(--castle-inspector-border);
503
- border-radius: var(--castle-radius);
1365
+ .drawingSettingsColumn {
1366
+ min-width: 0;
1367
+ height: 100%;
1368
+ overflow: auto;
1369
+ }
1370
+
1371
+ .drawingToolButton,
1372
+ .drawingSizeButton {
504
1373
  background: var(--castle-inspector-button-bg);
505
1374
  color: var(--castle-inspector-text);
506
- padding: 6px 10px;
507
1375
  cursor: pointer;
508
- box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
509
1376
  }
510
1377
 
511
- .iconButton {
1378
+ .drawingToolButton {
512
1379
  width: 34px;
513
1380
  height: 34px;
514
1381
  padding: 0;
515
1382
  display: inline-flex;
516
1383
  align-items: center;
517
1384
  justify-content: center;
1385
+ font-size: 14px;
1386
+ line-height: 1;
1387
+ border: 0;
1388
+ border-radius: 0;
518
1389
  }
519
1390
 
520
- .iconButton svg {
1391
+ .drawingToolButton svg {
521
1392
  width: 1em;
522
1393
  height: 1em;
523
1394
  }
524
1395
 
525
- .button:hover {
526
- background: #eee;
1396
+ .drawingToolButton:hover {
1397
+ background: var(--castle-inspector-input-bg);
527
1398
  }
528
1399
 
529
- .buttonPrimary,
530
- .buttonActive {
531
- background: var(--castle-black);
532
- border-color: var(--castle-black);
533
- color: var(--castle-text);
1400
+ .drawingToolButton:disabled {
1401
+ opacity: 0.35;
1402
+ cursor: default;
534
1403
  }
535
1404
 
536
- .buttonPrimary:hover,
537
- .buttonActive:hover {
538
- background: var(--castle-black);
539
- border-color: var(--castle-black);
540
- color: var(--castle-text);
1405
+ /* Active / selected square icon button -- the eyedropper reference: a light
1406
+ fill with a dark glyph. The single selected/engaged look shared by the
1407
+ IconButton component (`active`), the onion-skin toggle, and the pixel
1408
+ editors' tool strip.
1409
+
1410
+ These use COMPOUND selectors (`.button.buttonActive`,
1411
+ `.drawingToolButton.drawingToolSelected`) on purpose: every active button
1412
+ already carries both classes, so the (0,2,0)/(0,3,0) specificity beats the
1413
+ equal-specificity base + size rules (`.button`/`.iconButton`,
1414
+ `.drawingToolButton`) NO MATTER the source order. A bare `.buttonActive`
1415
+ ties those base rules on specificity and only wins if it happens to appear
1416
+ later in the file -- which Vite HMR can reshuffle when this module is edited,
1417
+ silently dropping the active fill. The compound selector removes that
1418
+ fragility. */
1419
+ .button.buttonActive,
1420
+ .drawingToolButton.drawingToolSelected,
1421
+ .paintStripModeButton.drawingToolSelected {
1422
+ background: var(--castle-selected);
1423
+ border-color: var(--castle-selected);
1424
+ color: var(--castle-selected-ink);
1425
+ }
1426
+
1427
+ .button.buttonActive:hover,
1428
+ .drawingToolButton.drawingToolSelected:hover,
1429
+ .paintStripModeButton.drawingToolSelected:hover {
1430
+ background: var(--castle-selected);
1431
+ border-color: var(--castle-selected);
1432
+ color: var(--castle-selected-ink);
1433
+ }
1434
+
1435
+ .drawingToolHint {
1436
+ color: var(--castle-inspector-muted);
1437
+ font-size: 14px;
1438
+ line-height: 1.35;
1439
+ padding-bottom: 8px;
541
1440
  }
542
1441
 
543
- .buttonDanger {
544
- color: var(--castle-danger);
1442
+ .drawingToolSettings {
1443
+ padding-bottom: 8px;
545
1444
  }
546
1445
 
547
- .button:disabled {
548
- opacity: 0.35;
549
- cursor: default;
1446
+ .drawingSizePicker {
1447
+ display: grid;
1448
+ gap: 8px;
1449
+ padding-bottom: 8px;
550
1450
  }
551
1451
 
552
- .actorList {
1452
+ .drawingSizeLabel {
1453
+ display: flex;
1454
+ align-items: baseline;
1455
+ justify-content: space-between;
1456
+ gap: 10px;
1457
+ color: var(--castle-inspector-muted);
1458
+ font-size: 14px;
1459
+ line-height: 1.35;
1460
+ }
1461
+
1462
+ .drawingSizeLabel span:last-child {
1463
+ color: var(--castle-inspector-text);
1464
+ font-variant-numeric: tabular-nums;
1465
+ }
1466
+
1467
+ .drawingSizeControlRow {
553
1468
  display: grid;
554
- gap: 4px;
1469
+ grid-template-columns: minmax(0, 1fr);
1470
+ align-items: center;
1471
+ gap: 10px;
555
1472
  }
556
1473
 
557
- .actorRow {
1474
+ .drawingSizeSlider {
558
1475
  width: 100%;
559
- border: 1px solid transparent;
560
- background: transparent;
561
- color: var(--castle-inspector-text);
562
- border-radius: var(--castle-radius);
563
- padding: 7px 8px;
564
- text-align: left;
565
1476
  cursor: pointer;
1477
+ appearance: none;
1478
+ -webkit-appearance: none;
1479
+ background: transparent;
566
1480
  }
567
1481
 
568
- .actorRowSelected {
569
- background: var(--castle-black);
570
- border-color: var(--castle-black);
571
- color: var(--castle-text);
1482
+ .drawingSizeSlider:disabled {
1483
+ cursor: default;
1484
+ opacity: 0.45;
572
1485
  }
573
1486
 
574
- .drawingEditor,
575
- .codeEditor {
576
- flex: 1;
577
- min-width: 0;
578
- min-height: 0;
579
- display: grid;
580
- grid-template-columns: minmax(320px, 1fr) 280px;
581
- background: var(--castle-workspace-bg);
1487
+ .drawingSizeSlider::-webkit-slider-runnable-track {
1488
+ height: 4px;
1489
+ border-radius: 999px;
1490
+ background: #4a4a4a;
582
1491
  }
583
1492
 
584
- .drawingEditor {
585
- grid-template-rows: 48px minmax(0, 1fr);
1493
+ .drawingSizeSlider::-webkit-slider-thumb {
1494
+ appearance: none;
1495
+ -webkit-appearance: none;
1496
+ width: 14px;
1497
+ height: 14px;
1498
+ margin-top: -5px;
1499
+ border-radius: 999px;
1500
+ border: 1px solid #d8d8d8;
1501
+ background: #fff;
586
1502
  }
587
1503
 
588
- .drawingCanvasWrap {
589
- grid-column: 1;
590
- grid-row: 2;
1504
+ .drawingFillToggle {
1505
+ min-height: 28px;
1506
+ padding: 4px 9px;
1507
+ border: 1px solid var(--castle-inspector-border);
1508
+ border-radius: var(--castle-radius);
1509
+ background: var(--castle-inspector-button-bg);
1510
+ color: var(--castle-inspector-text);
1511
+ cursor: pointer;
1512
+ font-size: 14px;
1513
+ }
1514
+
1515
+ .drawingFillToggleOn {
1516
+ background: var(--castle-selected);
1517
+ border-color: var(--castle-selected);
1518
+ color: var(--castle-selected-ink);
1519
+ }
1520
+
1521
+ .drawingModeRow {
591
1522
  display: flex;
592
1523
  align-items: center;
593
- justify-content: center;
594
- padding: 24px;
595
- min-width: 0;
596
- min-height: 0;
1524
+ justify-content: space-between;
1525
+ gap: 12px;
1526
+ color: var(--castle-inspector-muted);
1527
+ font-size: 14px;
1528
+ line-height: 1.35;
597
1529
  }
598
1530
 
599
- .drawingCanvas {
600
- image-rendering: pixelated;
601
- background:
602
- linear-gradient(45deg, #ddd 25%, transparent 25%),
603
- linear-gradient(-45deg, #ddd 25%, transparent 25%),
604
- linear-gradient(45deg, transparent 75%, #ddd 75%),
605
- linear-gradient(-45deg, transparent 75%, #ddd 75%);
606
- background-size: 16px 16px;
607
- background-position:
608
- 0 0,
609
- 0 8px,
610
- 8px -8px,
611
- -8px 0;
1531
+ .drawingSwitch {
1532
+ position: relative;
1533
+ width: 34px;
1534
+ height: 20px;
1535
+ padding: 0;
612
1536
  border: 1px solid var(--castle-inspector-border);
613
- max-width: min(70vh, 520px);
614
- max-height: min(70vh, 520px);
1537
+ border-radius: 999px;
1538
+ background: #343434;
1539
+ cursor: pointer;
615
1540
  }
616
1541
 
617
- .palette {
618
- display: grid;
619
- grid-template-columns: repeat(6, 1fr);
620
- gap: 6px;
621
- padding-bottom: 12px;
1542
+ .drawingSwitchOn {
1543
+ border-color: var(--castle-selected);
1544
+ background: var(--castle-selected);
622
1545
  }
623
1546
 
624
- .swatch {
625
- aspect-ratio: 1;
626
- border: 1px solid var(--castle-inspector-border);
627
- border-radius: var(--castle-radius);
628
- cursor: pointer;
1547
+ .drawingSwitchKnob {
1548
+ position: absolute;
1549
+ top: 2px;
1550
+ left: 2px;
1551
+ width: 14px;
1552
+ height: 14px;
1553
+ border-radius: 999px;
1554
+ background: #fff;
1555
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.25);
1556
+ transition: transform 120ms ease;
629
1557
  }
630
1558
 
631
- .swatchSelected {
632
- outline: 2px solid var(--castle-black);
633
- outline-offset: 1px;
1559
+ .drawingSwitchOn .drawingSwitchKnob {
1560
+ transform: translateX(14px);
1561
+ }
1562
+
1563
+ .drawingSizeSlider::-moz-range-track {
1564
+ height: 4px;
1565
+ border-radius: 999px;
1566
+ background: #4a4a4a;
1567
+ }
1568
+
1569
+ .drawingSizeSlider::-moz-range-thumb {
1570
+ width: 14px;
1571
+ height: 14px;
1572
+ border-radius: 999px;
1573
+ border: 1px solid #d8d8d8;
1574
+ background: #fff;
634
1575
  }
635
1576
 
636
1577
  .codeEditor {
@@ -643,28 +1584,8 @@
643
1584
  height: 100%;
644
1585
  }
645
1586
 
646
- .headerFilesButton {
647
- width: 34px;
648
- height: 34px;
649
- border: 1px solid var(--castle-inspector-border);
650
- border-radius: var(--castle-radius);
651
- background: var(--castle-inspector-button-bg);
652
- color: var(--castle-inspector-text);
653
- cursor: pointer;
654
- align-items: center;
655
- justify-content: center;
656
- flex: 0 0 34px;
657
- }
658
-
659
- .headerFilesButton[aria-pressed='true'] {
660
- background: var(--castle-black);
661
- border-color: var(--castle-black);
662
- color: var(--castle-text);
663
- }
664
-
665
1587
  /* mobileOnly comes AFTER element-specific rules so `display: none` wins on desktop. */
666
1588
  .mobileOnly,
667
- .headerFilesButton,
668
1589
  .sheetBackdrop,
669
1590
  .sheetGrab,
670
1591
  .sheetGrabBar,
@@ -674,7 +1595,7 @@
674
1595
  display: none;
675
1596
  }
676
1597
 
677
- @media (max-width: 860px) {
1598
+ @media (max-width: 600px) {
678
1599
  :root {
679
1600
  --sheet-high-height: 62vh;
680
1601
  --sheet-low-height: 18vh;
@@ -686,10 +1607,6 @@
686
1607
  display: contents;
687
1608
  }
688
1609
 
689
- .headerFilesButton {
690
- display: inline-flex;
691
- }
692
-
693
1610
  /* Backdrop sits below the header so the files toggle stays interactive. */
694
1611
  .sheetBackdrop {
695
1612
  display: block;
@@ -735,7 +1652,7 @@
735
1652
  }
736
1653
 
737
1654
  .editorTitle {
738
- font-size: 15px;
1655
+ font-size: 14px;
739
1656
  overflow: hidden;
740
1657
  text-overflow: ellipsis;
741
1658
  white-space: nowrap;
@@ -747,15 +1664,11 @@
747
1664
  white-space: nowrap;
748
1665
  }
749
1666
 
750
- /* Hide the desktop tools row on mobile -- buttons live in the header instead. */
751
- .sceneTools,
752
- .drawingTools {
753
- display: none;
754
- }
755
-
1667
+ /* Scene hotbar row stays visible when compact (it holds drag-and-drop
1668
+ blueprints later). Drawing playback lives in the header instead. */
756
1669
  .sceneWorkspace {
757
1670
  grid-template-columns: 1fr;
758
- grid-template-rows: minmax(0, 1fr);
1671
+ grid-template-rows: var(--castle-hotbar-row-full) minmax(0, 1fr);
759
1672
  }
760
1673
 
761
1674
  .drawingEditor {
@@ -765,29 +1678,33 @@
765
1678
 
766
1679
  .stageWrap {
767
1680
  grid-column: 1;
768
- grid-row: 1;
1681
+ grid-row: 2;
769
1682
  align-items: flex-start;
770
1683
  padding: 10px 12px 12px;
771
1684
  background: var(--castle-stage-workspace-bg);
772
1685
  }
773
1686
 
1687
+ /* One-column layout: the card MUST keep a definite width. Its clip/canvas
1688
+ children are absolutely positioned (no intrinsic size), so a flex item with
1689
+ `width: auto` + `aspect-ratio` collapses to 0x0 -- the stage went blank and
1690
+ only the dark `.stageWrap` showed. Drive width from the viewport (capped by
1691
+ 480px and by 62vh so the aspect-derived height always fits without
1692
+ `max-height` clamping and distorting the maze). */
774
1693
  .stageCard {
775
- max-width: min(92vw, 480px);
1694
+ width: min(92vw, 480px, 62vh);
1695
+ max-width: 100%;
776
1696
  max-height: 100%;
777
- width: auto;
778
1697
  }
779
1698
 
780
- /* Drawing centers higher in the canvas region -- around the 1/3-from-top mark. */
1699
+ /* PxArt artboard: keep flanking tool/paint columns; fit hook drives canvas size. */
781
1700
  .drawingCanvasWrap {
782
- grid-column: 1;
783
- grid-row: 1;
784
- align-items: flex-start;
785
- padding: 6vh 16px 16px;
1701
+ align-items: center;
1702
+ padding: 10px 8px 12px;
786
1703
  }
787
1704
 
788
- .drawingCanvas {
789
- max-width: min(82vw, 480px);
790
- max-height: min(54vh, 480px);
1705
+ .artboardToolColumn,
1706
+ .paintColumn {
1707
+ padding: 8px 4px;
791
1708
  }
792
1709
 
793
1710
  /* File-browser + inspector sheets share fixed-bottom positioning, height,
@@ -823,23 +1740,17 @@
823
1740
  transform: translateY(0);
824
1741
  }
825
1742
 
826
- /* Hide the desktop fileBrowserHeader on mobile (the grab handle replaces it). */
827
- .fileBrowserHeader {
828
- display: none;
829
- }
830
-
831
1743
  .fileTree {
832
1744
  flex: 1 1 0;
833
1745
  min-height: 0;
834
1746
  overflow-y: auto;
835
- padding: 4px 6px 12px;
836
1747
  }
837
1748
 
838
1749
  /* Inspector sheet: hidden off-screen by default; slides up to high (full) or low (partial). */
839
1750
  .inspector {
840
1751
  z-index: 45;
841
1752
  border-left: 0;
842
- background: var(--castle-inspector-bg);
1753
+ background: var(--castle-workspace-bg);
843
1754
  padding: 0;
844
1755
  }
845
1756
 
@@ -875,7 +1786,7 @@
875
1786
  }
876
1787
 
877
1788
  .inspector .sheetGrab {
878
- background: var(--castle-inspector-bg);
1789
+ background: var(--castle-workspace-bg);
879
1790
  }
880
1791
 
881
1792
  .sheetGrabBar {
@@ -907,7 +1818,7 @@
907
1818
 
908
1819
  .sheetGrabHint {
909
1820
  display: inline;
910
- font-size: 12px;
1821
+ font-size: 14px;
911
1822
  color: var(--castle-inspector-muted);
912
1823
  overflow: hidden;
913
1824
  text-overflow: ellipsis;
@@ -922,7 +1833,7 @@
922
1833
  }
923
1834
 
924
1835
  .inspectorBody {
925
- background: var(--castle-inspector-bg);
1836
+ background: var(--castle-workspace-bg);
926
1837
  }
927
1838
 
928
1839
  .codeInspectorInfo {
@@ -930,38 +1841,63 @@
930
1841
  grid-template-columns: 80px 1fr;
931
1842
  gap: 6px 12px;
932
1843
  padding: 14px 16px;
933
- font-size: 13px;
1844
+ font-size: 14px;
934
1845
  color: var(--castle-inspector-text);
935
1846
  word-break: break-all;
936
1847
  }
937
1848
  }
938
1849
 
939
- /* Bare (panel) editor wrapper: fills the panel iframe; single column. */
1850
+ /* Bare (panel) editor wrapper: fills the panel iframe; single column.
1851
+ Use 100% not 100vw/100vh — in a dock iframe vw/vh are the TOP-LEVEL
1852
+ viewport, so the editor "thinks" it is full-window-wide and container
1853
+ queries on .editorBody never flip to compact. */
940
1854
  .panelBare {
941
1855
  display: grid;
942
1856
  grid-template-columns: 1fr;
943
- width: 100vw;
944
- height: 100vh;
1857
+ width: 100%;
1858
+ height: 100%;
1859
+ min-width: 0;
1860
+ min-height: 0;
945
1861
  background: var(--castle-workspace-bg);
946
1862
  }
947
- /* In a panel the editor toolbar (play / undo / add) must stay visible even
948
- below 860px -- it normally moves into the mobile header, which bare mode
949
- removes. Keep it; the inspector still drops below at narrow widths. */
1863
+ /* In a panel the scene editor's tools row must stay visible even below 860px --
1864
+ it normally moves into the mobile header, which bare mode removes. Restore the
1865
+ full-height tools row (--castle-hotbar-row-full, same as the desktop track) and
1866
+ put the stage back in row 2 (the narrow layout moves it up into row 1). The row
1867
+ must use the full height -- a shorter hardcoded track left the centered 46px
1868
+ hotbar buttons overhanging the stage, which clipped their bottoms.
1869
+
1870
+ The PxArt editor (.drawingEditor) is intentionally NOT included here: it has
1871
+ no docked tools row (its controls live in the header), and its left column
1872
+ (.editorLeft) is pinned to grid-row 1, so injecting a 48px first row collapsed
1873
+ the artboard to zero height across the 600-860px band. PxArt compact layout
1874
+ is driven by the @container editor (max-width: 620px) rule on .editorBody. */
950
1875
  @media (max-width: 860px) {
951
- /* restore the 48px tools row the narrow layout drops, show the toolbar, and
952
- put the stage back in row 2 (the narrow layout moves it up into row 1). */
953
- .panelBare .sceneWorkspace,
954
- .panelBare .drawingEditor {
955
- grid-template-rows: 48px minmax(0, 1fr);
1876
+ .panelBare .sceneWorkspace {
1877
+ grid-template-rows: var(--castle-hotbar-row-full) minmax(0, 1fr);
956
1878
  }
957
1879
  .panelBare .sceneTools {
958
1880
  display: grid;
959
1881
  }
960
- .panelBare .drawingTools {
961
- display: flex;
962
- }
963
- .panelBare .stageWrap,
964
- .panelBare .drawingCanvasWrap {
1882
+ .panelBare .stageWrap {
965
1883
  grid-row: 2;
966
1884
  }
967
1885
  }
1886
+
1887
+ /* PxArt compact layout — MUST stay after .drawingToolsPanel / .paintColumn base
1888
+ rules so these container-query overrides win the cascade (same element carries
1889
+ pxArtInspector + drawingToolsPanel; a later bare .drawingToolsPanel{display:flex}
1890
+ was keeping the sidebar visible beside the paint strip). */
1891
+ @container editor (max-width: 620px) {
1892
+ .drawingEditor {
1893
+ grid-template-columns: 1fr;
1894
+ }
1895
+
1896
+ .drawingEditor > .pxArtInspector.drawingToolsPanel {
1897
+ display: none;
1898
+ }
1899
+
1900
+ .paintColumn {
1901
+ display: flex;
1902
+ }
1903
+ }