castle-web-cli 0.4.11 → 0.4.13

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 (49) hide show
  1. package/dist/agent-prompts.d.ts +31 -0
  2. package/dist/agent-prompts.js +104 -0
  3. package/dist/agent.d.ts +17 -0
  4. package/dist/agent.js +952 -0
  5. package/dist/chat-client.d.ts +1 -0
  6. package/dist/chat-client.js +425 -0
  7. package/dist/commonInstructions.d.ts +1 -0
  8. package/dist/commonInstructions.js +8 -0
  9. package/dist/ide-client.js +46 -14
  10. package/dist/ide.d.ts +2 -0
  11. package/dist/ide.js +348 -36
  12. package/dist/init.js +12 -1
  13. package/dist/serve.js +18 -3
  14. package/kits/basic-2d/CLAUDE.md +3 -1
  15. package/kits/basic-3d/.prettierrc +8 -0
  16. package/kits/basic-3d/CLAUDE.md +162 -0
  17. package/kits/basic-3d/behaviors/Camera.jsx +56 -0
  18. package/kits/basic-3d/behaviors/Collider.jsx +78 -0
  19. package/kits/basic-3d/behaviors/Mesh.jsx +82 -0
  20. package/kits/basic-3d/behaviors/Model.jsx +61 -0
  21. package/kits/basic-3d/behaviors/Transform.jsx +35 -0
  22. package/kits/basic-3d/editors/App.jsx +147 -0
  23. package/kits/basic-3d/editors/CodeEditor.jsx +112 -0
  24. package/kits/basic-3d/editors/FileBrowser.jsx +143 -0
  25. package/kits/basic-3d/editors/ModelEditor.jsx +400 -0
  26. package/kits/basic-3d/editors/PlayOnly.jsx +14 -0
  27. package/kits/basic-3d/editors/SceneEditor.jsx +1087 -0
  28. package/kits/basic-3d/editors/behaviorRegistry.js +24 -0
  29. package/kits/basic-3d/editors/editorHistory.js +52 -0
  30. package/kits/basic-3d/editors/viewportRig.js +90 -0
  31. package/kits/basic-3d/engine/ScenePlayer.jsx +55 -0
  32. package/kits/basic-3d/engine/SceneUI.jsx +67 -0
  33. package/kits/basic-3d/engine/SceneViewport.jsx +102 -0
  34. package/kits/basic-3d/engine/TouchControls.jsx +136 -0
  35. package/kits/basic-3d/engine/autoInspector.jsx +51 -0
  36. package/kits/basic-3d/engine/files.js +73 -0
  37. package/kits/basic-3d/engine/scene.js +502 -0
  38. package/kits/basic-3d/engine/threeUtil.js +260 -0
  39. package/kits/basic-3d/engine/ui.jsx +352 -0
  40. package/kits/basic-3d/engine/ui.module.css +944 -0
  41. package/kits/basic-3d/eslint.config.js +51 -0
  42. package/kits/basic-3d/index.html +11 -0
  43. package/kits/basic-3d/main.jsx +10 -0
  44. package/kits/basic-3d/models/block.model +14 -0
  45. package/kits/basic-3d/package-lock.json +2713 -0
  46. package/kits/basic-3d/package.json +41 -0
  47. package/kits/basic-3d/scenes/main.scene +76 -0
  48. package/kits/basic-3d/vite.config.js +1 -0
  49. package/package.json +6 -1
@@ -0,0 +1,944 @@
1
+ @font-face {
2
+ font-family: 'Basteleur';
3
+ src:
4
+ url('/Basteleur-Bold.woff2') format('woff2'),
5
+ url('/Basteleur-Bold.woff') format('woff');
6
+ }
7
+
8
+ :global(:root) {
9
+ --castle-font-body:
10
+ baltomobile, Balto, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
11
+ sans-serif;
12
+ --castle-font-display: var(--castle-font-body);
13
+ --castle-font-mono: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace;
14
+ --castle-black: #000;
15
+ --castle-tap-highlight: #111;
16
+ --castle-panel: #080808;
17
+ --castle-panel-raised: #101010;
18
+ --castle-panel-sunken: #050505;
19
+ --castle-border: #444;
20
+ --castle-border-soft: #252525;
21
+ --castle-text: #fff;
22
+ --castle-text-dim: #777;
23
+ --castle-text-muted: #aaa;
24
+ --castle-inspector-bg: #fff;
25
+ --castle-inspector-text: #222;
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;
34
+ --castle-card: #121213;
35
+ --castle-selected: #e3e6ff;
36
+ --castle-selected-ink: #242234;
37
+ --castle-danger: #ff5d5d;
38
+ --castle-ok: #81e69b;
39
+ --castle-blue: #8db7ff;
40
+ --castle-radius: 4px;
41
+ }
42
+
43
+ :global(*) {
44
+ box-sizing: border-box;
45
+ }
46
+
47
+ :global(html),
48
+ :global(body),
49
+ :global(#root) {
50
+ width: 100%;
51
+ height: 100%;
52
+ margin: 0;
53
+ }
54
+
55
+ :global(body) {
56
+ overflow: hidden;
57
+ background: var(--castle-workspace-bg);
58
+ color: var(--castle-inspector-text);
59
+ font-family: var(--castle-font-body);
60
+ -webkit-font-smoothing: antialiased;
61
+ }
62
+
63
+ :global(button),
64
+ :global(input),
65
+ :global(select),
66
+ :global(textarea) {
67
+ font: inherit;
68
+ }
69
+
70
+ :global(button),
71
+ :global(input),
72
+ :global(select),
73
+ :global(textarea),
74
+ :global([tabindex]) {
75
+ outline: none;
76
+ }
77
+
78
+ :global(*:focus),
79
+ :global(*:focus-visible) {
80
+ outline: none;
81
+ }
82
+
83
+ .appShell {
84
+ width: 100vw;
85
+ height: 100vh;
86
+ display: grid;
87
+ grid-template-columns: 236px 1fr;
88
+ background: var(--castle-workspace-bg);
89
+ color: var(--castle-inspector-text);
90
+ }
91
+
92
+ .fileBrowser {
93
+ min-width: 0;
94
+ border-right: 1px solid var(--castle-inspector-divider);
95
+ background: var(--castle-workspace-bg);
96
+ display: flex;
97
+ flex-direction: column;
98
+ }
99
+
100
+ .fileBrowserHeader,
101
+ .editorHeader {
102
+ height: 48px;
103
+ flex: 0 0 48px;
104
+ display: flex;
105
+ align-items: center;
106
+ gap: 8px;
107
+ padding: 10px 12px;
108
+ border-bottom: 1px solid var(--castle-inspector-divider);
109
+ background: var(--castle-sheet-bg);
110
+ }
111
+
112
+ .fileBrowserTitle,
113
+ .editorTitle {
114
+ font-family: var(--castle-font-display);
115
+ letter-spacing: 0.01em;
116
+ font-size: 16px;
117
+ line-height: 1;
118
+ }
119
+
120
+ .fileBrowserSubtitle,
121
+ .muted {
122
+ color: var(--castle-inspector-muted);
123
+ font-size: 12px;
124
+ }
125
+
126
+ .fileTree {
127
+ flex: 1 1 0;
128
+ min-height: 0;
129
+ padding: 8px 6px;
130
+ overflow-y: auto;
131
+ }
132
+
133
+ .fileBranch {
134
+ min-width: 0;
135
+ }
136
+
137
+ .fileRow,
138
+ .fileDirRow {
139
+ width: 100%;
140
+ border: 0;
141
+ border-radius: var(--castle-radius);
142
+ background: transparent;
143
+ color: var(--castle-inspector-text);
144
+ display: flex;
145
+ align-items: center;
146
+ justify-content: flex-start;
147
+ gap: 6px;
148
+ padding: 8px 9px 8px calc(9px + var(--file-depth, 0) * 16px);
149
+ text-align: left;
150
+ cursor: pointer;
151
+ }
152
+
153
+ .fileDirRow {
154
+ color: var(--castle-inspector-muted);
155
+ }
156
+
157
+ .fileRow:hover,
158
+ .fileDirRow:hover {
159
+ background: var(--castle-sheet-bg);
160
+ color: var(--castle-inspector-text);
161
+ }
162
+
163
+ .fileRowSelected {
164
+ background: var(--castle-sheet-bg);
165
+ color: var(--castle-inspector-text);
166
+ }
167
+
168
+ .fileRowSelected:hover {
169
+ background: var(--castle-sheet-bg);
170
+ color: var(--castle-inspector-text);
171
+ }
172
+
173
+ .fileDisclosure {
174
+ width: 12px;
175
+ flex: 0 0 12px;
176
+ display: inline-flex;
177
+ align-items: center;
178
+ justify-content: center;
179
+ color: var(--castle-inspector-muted);
180
+ font-size: 10px;
181
+ }
182
+
183
+ .mainEditor {
184
+ min-width: 0;
185
+ min-height: 0;
186
+ display: flex;
187
+ flex-direction: column;
188
+ background: var(--castle-sheet-bg);
189
+ }
190
+
191
+ .editorHeader {
192
+ justify-content: space-between;
193
+ }
194
+
195
+ .editorHeaderLeft,
196
+ .editorHeaderRight,
197
+ .toolbar {
198
+ display: flex;
199
+ align-items: center;
200
+ gap: 8px;
201
+ min-width: 0;
202
+ }
203
+
204
+ .editorBody {
205
+ min-height: 0;
206
+ flex: 1;
207
+ display: flex;
208
+ overflow: hidden;
209
+ }
210
+
211
+ .sceneWorkspace {
212
+ flex: 1;
213
+ min-width: 0;
214
+ min-height: 0;
215
+ display: grid;
216
+ grid-template-columns: minmax(360px, 1fr) 320px;
217
+ grid-template-rows: 48px minmax(0, 1fr);
218
+ }
219
+
220
+ .sceneTools,
221
+ .drawingTools {
222
+ grid-column: 1;
223
+ grid-row: 1;
224
+ display: flex;
225
+ align-items: center;
226
+ justify-content: center;
227
+ gap: 8px;
228
+ padding: 8px 12px;
229
+ border-bottom: 1px solid var(--castle-inspector-divider);
230
+ background: var(--castle-sheet-bg);
231
+ }
232
+
233
+ .sceneTools {
234
+ display: grid;
235
+ grid-template-columns: 1fr auto 1fr;
236
+ gap: 8px;
237
+ }
238
+
239
+ .sceneToolsGroup {
240
+ display: flex;
241
+ align-items: center;
242
+ gap: 8px;
243
+ }
244
+
245
+ .sceneToolsGroup:last-child {
246
+ justify-self: end;
247
+ }
248
+
249
+ .stageWrap {
250
+ grid-column: 1;
251
+ grid-row: 2;
252
+ min-width: 0;
253
+ min-height: 0;
254
+ display: flex;
255
+ align-items: center;
256
+ justify-content: center;
257
+ padding: 20px;
258
+ background: var(--castle-stage-workspace-bg);
259
+ }
260
+
261
+ .stageCard {
262
+ position: relative;
263
+ width: min(52vh, 440px);
264
+ aspect-ratio: 5 / 7;
265
+ max-width: calc(100vw - 620px);
266
+ background: var(--castle-card);
267
+ border: 1px solid var(--castle-inspector-border);
268
+ border-radius: 12px;
269
+ overflow: hidden;
270
+ box-shadow: 0 2px 0 rgba(0, 0, 0, 0.2);
271
+ }
272
+
273
+ .stageCanvas {
274
+ width: 100%;
275
+ height: 100%;
276
+ display: block;
277
+ touch-action: none;
278
+ }
279
+
280
+ /* Full-bleed stage -- edit mode fills the workspace; play mode keeps the
281
+ 5:7 card so the deck previews at its real aspect. */
282
+ .stageWrapFull {
283
+ padding: 0;
284
+ }
285
+
286
+ .stageWrapFull .stageCard {
287
+ width: 100%;
288
+ height: 100%;
289
+ max-width: none;
290
+ aspect-ratio: auto;
291
+ border: 0;
292
+ border-radius: 0;
293
+ box-shadow: none;
294
+ }
295
+
296
+ /* Game-time UI overlay -- sits exactly over the canvas and clips to the card.
297
+ Behavior `ui` output lands in `.sceneUiLayer`, which is sized in card units
298
+ and scaled onto the canvas box. */
299
+ .sceneUiRoot {
300
+ position: absolute;
301
+ inset: 0;
302
+ overflow: hidden;
303
+ pointer-events: none;
304
+ }
305
+
306
+ .sceneUiLayer {
307
+ position: absolute;
308
+ left: 0;
309
+ top: 0;
310
+ transform-origin: 0 0;
311
+ }
312
+
313
+ .inspector {
314
+ grid-column: 2;
315
+ grid-row: 1 / span 2;
316
+ min-width: 0;
317
+ border-left: 1px solid var(--castle-inspector-divider);
318
+ background: var(--castle-inspector-bg);
319
+ color: var(--castle-inspector-text);
320
+ overflow: auto;
321
+ padding: 0;
322
+ }
323
+
324
+ .panel {
325
+ border: 0;
326
+ border-bottom: 1px solid var(--castle-inspector-divider);
327
+ border-radius: 0;
328
+ background: var(--castle-inspector-bg);
329
+ color: var(--castle-inspector-text);
330
+ margin: 0;
331
+ overflow: visible;
332
+ box-shadow: none;
333
+ }
334
+
335
+ .panel:last-child {
336
+ border-bottom: 0;
337
+ }
338
+
339
+ .panelHeader {
340
+ padding: 14px 16px 6px;
341
+ border-bottom: 0;
342
+ color: var(--castle-inspector-text);
343
+ font-size: 16px;
344
+ font-weight: 650;
345
+ }
346
+
347
+ .panelBody {
348
+ padding: 8px 16px 4px;
349
+ }
350
+
351
+ .fieldRow {
352
+ display: grid;
353
+ grid-template-columns: minmax(82px, 0.5fr) minmax(0, 1fr);
354
+ align-items: center;
355
+ gap: 12px;
356
+ padding-bottom: 12px;
357
+ margin-bottom: 0;
358
+ min-height: 28px;
359
+ }
360
+
361
+ .fieldRow:last-child {
362
+ margin-bottom: 0;
363
+ }
364
+
365
+ .fieldLabel {
366
+ color: var(--castle-inspector-text);
367
+ font-size: 16px;
368
+ }
369
+
370
+ .input,
371
+ .select,
372
+ .textarea {
373
+ width: 100%;
374
+ border: 1px solid var(--castle-inspector-border);
375
+ border-radius: var(--castle-radius);
376
+ background: var(--castle-inspector-input-bg);
377
+ color: var(--castle-inspector-text);
378
+ padding: 5px 8px;
379
+ outline: 0;
380
+ }
381
+
382
+ .select {
383
+ appearance: none;
384
+ -webkit-appearance: none;
385
+ padding-right: 26px;
386
+ 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");
387
+ background-repeat: no-repeat;
388
+ background-position: right 8px center;
389
+ text-overflow: ellipsis;
390
+ }
391
+
392
+ .numberField {
393
+ position: relative;
394
+ width: 100%;
395
+ }
396
+
397
+ .numberInput {
398
+ padding-right: 22px;
399
+ appearance: textfield;
400
+ -moz-appearance: textfield;
401
+ }
402
+
403
+ .numberInput::-webkit-inner-spin-button,
404
+ .numberInput::-webkit-outer-spin-button {
405
+ -webkit-appearance: none;
406
+ appearance: none;
407
+ margin: 0;
408
+ }
409
+
410
+ .numberSteppers {
411
+ position: absolute;
412
+ top: 1px;
413
+ right: 1px;
414
+ bottom: 1px;
415
+ width: 18px;
416
+ display: flex;
417
+ flex-direction: column;
418
+ border-left: 1px solid var(--castle-inspector-divider);
419
+ opacity: 0;
420
+ pointer-events: none;
421
+ transition: opacity 0.1s;
422
+ }
423
+
424
+ .numberField:hover .numberSteppers,
425
+ .numberField:focus-within .numberSteppers {
426
+ opacity: 1;
427
+ pointer-events: auto;
428
+ }
429
+
430
+ .numberStepper {
431
+ flex: 1;
432
+ display: flex;
433
+ align-items: center;
434
+ justify-content: center;
435
+ border: 0;
436
+ padding: 0;
437
+ background: transparent;
438
+ color: var(--castle-inspector-muted);
439
+ cursor: pointer;
440
+ font-size: 8px;
441
+ line-height: 1;
442
+ }
443
+
444
+ .numberStepper:first-child {
445
+ border-bottom: 1px solid var(--castle-inspector-divider);
446
+ }
447
+
448
+ .numberStepper:hover {
449
+ background: #eee;
450
+ color: var(--castle-inspector-text);
451
+ }
452
+
453
+ .numberStepper:disabled {
454
+ opacity: 0.3;
455
+ cursor: default;
456
+ background: transparent;
457
+ }
458
+
459
+ .colorInput {
460
+ width: 100%;
461
+ height: 28px;
462
+ border: 1px solid var(--castle-inspector-border);
463
+ border-radius: var(--castle-radius);
464
+ background: var(--castle-inspector-input-bg);
465
+ padding: 2px;
466
+ outline: 0;
467
+ cursor: pointer;
468
+ }
469
+
470
+ .toggle {
471
+ width: 44px;
472
+ height: 24px;
473
+ border: 1px solid var(--castle-inspector-border);
474
+ border-radius: 999px;
475
+ background: #fff;
476
+ padding: 2px;
477
+ cursor: pointer;
478
+ display: flex;
479
+ align-items: center;
480
+ justify-content: flex-start;
481
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
482
+ }
483
+
484
+ .toggleOn {
485
+ background: var(--castle-black);
486
+ justify-content: flex-end;
487
+ }
488
+
489
+ .toggleKnob {
490
+ width: 18px;
491
+ height: 18px;
492
+ border-radius: 999px;
493
+ background: var(--castle-black);
494
+ }
495
+
496
+ .toggleOn .toggleKnob {
497
+ background: var(--castle-text);
498
+ }
499
+
500
+ .textarea {
501
+ min-height: 0;
502
+ resize: none;
503
+ font-family: var(--castle-font-mono);
504
+ font-size: 12px;
505
+ line-height: 1.45;
506
+ }
507
+
508
+ .button {
509
+ border: 1px solid var(--castle-inspector-border);
510
+ border-radius: var(--castle-radius);
511
+ background: var(--castle-inspector-button-bg);
512
+ color: var(--castle-inspector-text);
513
+ padding: 6px 10px;
514
+ cursor: pointer;
515
+ box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
516
+ }
517
+
518
+ .iconButton {
519
+ width: 34px;
520
+ height: 34px;
521
+ padding: 0;
522
+ display: inline-flex;
523
+ align-items: center;
524
+ justify-content: center;
525
+ }
526
+
527
+ .iconButton svg {
528
+ width: 1em;
529
+ height: 1em;
530
+ }
531
+
532
+ .button:hover {
533
+ background: #eee;
534
+ }
535
+
536
+ .buttonPrimary,
537
+ .buttonActive {
538
+ background: var(--castle-black);
539
+ border-color: var(--castle-black);
540
+ color: var(--castle-text);
541
+ }
542
+
543
+ .buttonPrimary:hover,
544
+ .buttonActive:hover {
545
+ background: var(--castle-black);
546
+ border-color: var(--castle-black);
547
+ color: var(--castle-text);
548
+ }
549
+
550
+ .buttonDanger {
551
+ color: var(--castle-danger);
552
+ }
553
+
554
+ .button:disabled {
555
+ opacity: 0.35;
556
+ cursor: default;
557
+ }
558
+
559
+ .actorList {
560
+ display: grid;
561
+ gap: 4px;
562
+ }
563
+
564
+ .actorRow {
565
+ width: 100%;
566
+ border: 1px solid transparent;
567
+ background: transparent;
568
+ color: var(--castle-inspector-text);
569
+ border-radius: var(--castle-radius);
570
+ padding: 7px 8px;
571
+ text-align: left;
572
+ cursor: pointer;
573
+ }
574
+
575
+ .actorRowSelected {
576
+ background: var(--castle-black);
577
+ border-color: var(--castle-black);
578
+ color: var(--castle-text);
579
+ }
580
+
581
+ .drawingEditor,
582
+ .codeEditor {
583
+ flex: 1;
584
+ min-width: 0;
585
+ min-height: 0;
586
+ display: grid;
587
+ grid-template-columns: minmax(320px, 1fr) 280px;
588
+ background: var(--castle-workspace-bg);
589
+ }
590
+
591
+ .drawingEditor {
592
+ grid-template-rows: 48px minmax(0, 1fr);
593
+ }
594
+
595
+ .drawingCanvasWrap {
596
+ grid-column: 1;
597
+ grid-row: 2;
598
+ display: flex;
599
+ align-items: center;
600
+ justify-content: center;
601
+ padding: 24px;
602
+ min-width: 0;
603
+ min-height: 0;
604
+ }
605
+
606
+ .drawingCanvas {
607
+ image-rendering: pixelated;
608
+ background:
609
+ linear-gradient(45deg, #ddd 25%, transparent 25%),
610
+ linear-gradient(-45deg, #ddd 25%, transparent 25%),
611
+ linear-gradient(45deg, transparent 75%, #ddd 75%),
612
+ linear-gradient(-45deg, transparent 75%, #ddd 75%);
613
+ background-size: 16px 16px;
614
+ background-position:
615
+ 0 0,
616
+ 0 8px,
617
+ 8px -8px,
618
+ -8px 0;
619
+ border: 1px solid var(--castle-inspector-border);
620
+ max-width: min(70vh, 520px);
621
+ max-height: min(70vh, 520px);
622
+ }
623
+
624
+ .palette {
625
+ display: grid;
626
+ grid-template-columns: repeat(6, 1fr);
627
+ gap: 6px;
628
+ padding-bottom: 12px;
629
+ }
630
+
631
+ .swatch {
632
+ aspect-ratio: 1;
633
+ border: 1px solid var(--castle-inspector-border);
634
+ border-radius: var(--castle-radius);
635
+ cursor: pointer;
636
+ }
637
+
638
+ .swatchSelected {
639
+ outline: 2px solid var(--castle-black);
640
+ outline-offset: 1px;
641
+ }
642
+
643
+ .codeEditor {
644
+ grid-template-columns: 1fr;
645
+ }
646
+
647
+ .codeMirrorHost {
648
+ min-width: 0;
649
+ min-height: 0;
650
+ height: 100%;
651
+ }
652
+
653
+ .headerFilesButton {
654
+ width: 34px;
655
+ height: 34px;
656
+ border: 1px solid var(--castle-inspector-border);
657
+ border-radius: var(--castle-radius);
658
+ background: var(--castle-inspector-button-bg);
659
+ color: var(--castle-inspector-text);
660
+ cursor: pointer;
661
+ align-items: center;
662
+ justify-content: center;
663
+ flex: 0 0 34px;
664
+ }
665
+
666
+ .headerFilesButton[aria-pressed='true'] {
667
+ background: var(--castle-black);
668
+ border-color: var(--castle-black);
669
+ color: var(--castle-text);
670
+ }
671
+
672
+ /* mobileOnly comes AFTER element-specific rules so `display: none` wins on desktop. */
673
+ .mobileOnly,
674
+ .headerFilesButton,
675
+ .sheetBackdrop,
676
+ .sheetGrab,
677
+ .sheetGrabBar,
678
+ .sheetGrabLabelRow,
679
+ .sheetGrabLabel,
680
+ .sheetGrabHint {
681
+ display: none;
682
+ }
683
+
684
+ @media (max-width: 860px) {
685
+ :root {
686
+ --sheet-high-height: 62vh;
687
+ --sheet-low-height: 18vh;
688
+ }
689
+
690
+ /* `display: contents` makes wrapper spans transparent in layout so their
691
+ children become direct flex items of the parent (gap applies, etc). */
692
+ .mobileOnly {
693
+ display: contents;
694
+ }
695
+
696
+ .headerFilesButton {
697
+ display: inline-flex;
698
+ }
699
+
700
+ /* Backdrop sits below the header so the files toggle stays interactive. */
701
+ .sheetBackdrop {
702
+ display: block;
703
+ position: fixed;
704
+ top: 52px;
705
+ left: 0;
706
+ right: 0;
707
+ bottom: 0;
708
+ z-index: 30;
709
+ background: transparent;
710
+ }
711
+
712
+ .appShell {
713
+ grid-template-columns: 1fr;
714
+ grid-template-rows: 1fr;
715
+ position: relative;
716
+ }
717
+
718
+ .mainEditor {
719
+ grid-column: 1;
720
+ grid-row: 1;
721
+ min-height: 0;
722
+ }
723
+
724
+ /* Header: title (left, compact) + centered icon group (right slot includes files button). */
725
+ .editorHeader {
726
+ height: 52px;
727
+ flex: 0 0 52px;
728
+ padding: 8px 10px;
729
+ gap: 8px;
730
+ justify-content: space-between;
731
+ }
732
+
733
+ .editorHeaderLeft {
734
+ flex: 1;
735
+ min-width: 0;
736
+ }
737
+
738
+ .editorHeaderRight {
739
+ flex: 0 0 auto;
740
+ justify-content: flex-end;
741
+ gap: 14px;
742
+ }
743
+
744
+ .editorTitle {
745
+ font-size: 15px;
746
+ overflow: hidden;
747
+ text-overflow: ellipsis;
748
+ white-space: nowrap;
749
+ }
750
+
751
+ .muted {
752
+ overflow: hidden;
753
+ text-overflow: ellipsis;
754
+ white-space: nowrap;
755
+ }
756
+
757
+ /* Hide the desktop tools row on mobile -- buttons live in the header instead. */
758
+ .sceneTools,
759
+ .drawingTools {
760
+ display: none;
761
+ }
762
+
763
+ .sceneWorkspace {
764
+ grid-template-columns: 1fr;
765
+ grid-template-rows: minmax(0, 1fr);
766
+ }
767
+
768
+ .drawingEditor {
769
+ grid-template-columns: 1fr;
770
+ grid-template-rows: minmax(0, 1fr);
771
+ }
772
+
773
+ .stageWrap {
774
+ grid-column: 1;
775
+ grid-row: 1;
776
+ align-items: flex-start;
777
+ padding: 10px 12px 12px;
778
+ background: var(--castle-stage-workspace-bg);
779
+ }
780
+
781
+ .stageCard {
782
+ max-width: min(92vw, 480px);
783
+ max-height: 100%;
784
+ width: auto;
785
+ }
786
+
787
+ /* Drawing centers higher in the canvas region -- around the 1/3-from-top mark. */
788
+ .drawingCanvasWrap {
789
+ grid-column: 1;
790
+ grid-row: 1;
791
+ align-items: flex-start;
792
+ padding: 6vh 16px 16px;
793
+ }
794
+
795
+ .drawingCanvas {
796
+ max-width: min(82vw, 480px);
797
+ max-height: min(54vh, 480px);
798
+ }
799
+
800
+ /* File-browser + inspector sheets share fixed-bottom positioning, height,
801
+ transform/transition, and chrome. Per-sheet differences (z-index, side
802
+ border, background, padding) follow in dedicated rules below. */
803
+ .fileBrowser,
804
+ .inspector {
805
+ position: fixed;
806
+ left: 0;
807
+ right: 0;
808
+ bottom: 0;
809
+ width: 100%;
810
+ height: var(--sheet-high-height);
811
+ transform: translateY(100%);
812
+ transition:
813
+ transform 0.28s cubic-bezier(0.32, 0.72, 0, 1),
814
+ height 0.28s cubic-bezier(0.32, 0.72, 0, 1);
815
+ border-top: 1px solid var(--castle-inspector-divider);
816
+ box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.18);
817
+ overflow: hidden;
818
+ display: flex;
819
+ flex-direction: column;
820
+ }
821
+
822
+ /* File-browser sheet: hidden off-screen by default; slides up to high snap. */
823
+ .fileBrowser {
824
+ z-index: 50;
825
+ border-right: 0;
826
+ background: var(--castle-sheet-bg);
827
+ }
828
+
829
+ .fileBrowser[data-sheet-snap='high'] {
830
+ transform: translateY(0);
831
+ }
832
+
833
+ /* Hide the desktop fileBrowserHeader on mobile (the grab handle replaces it). */
834
+ .fileBrowserHeader {
835
+ display: none;
836
+ }
837
+
838
+ .fileTree {
839
+ flex: 1 1 0;
840
+ min-height: 0;
841
+ overflow-y: auto;
842
+ padding: 4px 6px 12px;
843
+ }
844
+
845
+ /* Inspector sheet: hidden off-screen by default; slides up to high (full) or low (partial). */
846
+ .inspector {
847
+ z-index: 45;
848
+ border-left: 0;
849
+ background: var(--castle-inspector-bg);
850
+ padding: 0;
851
+ }
852
+
853
+ .inspector[data-sheet-snap='high'] {
854
+ transform: translateY(0);
855
+ height: var(--sheet-high-height);
856
+ }
857
+
858
+ .inspector[data-sheet-snap='low'] {
859
+ transform: translateY(0);
860
+ height: var(--sheet-low-height);
861
+ }
862
+
863
+ /* Auto-height variant -- inspector hugs its content at the high snap (drawing/code). */
864
+ .inspector.inspectorAuto[data-sheet-snap='high'] {
865
+ height: auto;
866
+ max-height: var(--sheet-high-height);
867
+ }
868
+
869
+ /* Shared sheet chrome -- grab bar pill + label row. Always visible when sheet is visible. */
870
+ .sheetGrab {
871
+ display: flex;
872
+ flex-direction: column;
873
+ align-items: stretch;
874
+ justify-content: center;
875
+ flex: 0 0 auto;
876
+ padding: 8px 14px 8px;
877
+ cursor: grab;
878
+ user-select: none;
879
+ touch-action: none;
880
+ background: var(--castle-sheet-bg);
881
+ border-bottom: 1px solid var(--castle-inspector-divider);
882
+ }
883
+
884
+ .inspector .sheetGrab {
885
+ background: var(--castle-inspector-bg);
886
+ }
887
+
888
+ .sheetGrabBar {
889
+ display: block;
890
+ width: 36px;
891
+ height: 4px;
892
+ border-radius: 999px;
893
+ background: var(--castle-inspector-divider);
894
+ margin: 0 auto 8px;
895
+ flex: 0 0 4px;
896
+ }
897
+
898
+ .sheetGrabLabelRow {
899
+ display: flex;
900
+ align-items: baseline;
901
+ gap: 8px;
902
+ min-width: 0;
903
+ }
904
+
905
+ .sheetGrabLabel {
906
+ display: inline;
907
+ font-size: 14px;
908
+ font-weight: 600;
909
+ color: var(--castle-inspector-text);
910
+ overflow: hidden;
911
+ text-overflow: ellipsis;
912
+ white-space: nowrap;
913
+ }
914
+
915
+ .sheetGrabHint {
916
+ display: inline;
917
+ font-size: 12px;
918
+ color: var(--castle-inspector-muted);
919
+ overflow: hidden;
920
+ text-overflow: ellipsis;
921
+ white-space: nowrap;
922
+ flex: 1;
923
+ }
924
+
925
+ .sheetBody {
926
+ flex: 1;
927
+ min-height: 0;
928
+ overflow: auto;
929
+ }
930
+
931
+ .inspectorBody {
932
+ background: var(--castle-inspector-bg);
933
+ }
934
+
935
+ .codeInspectorInfo {
936
+ display: grid;
937
+ grid-template-columns: 80px 1fr;
938
+ gap: 6px 12px;
939
+ padding: 14px 16px;
940
+ font-size: 13px;
941
+ color: var(--castle-inspector-text);
942
+ word-break: break-all;
943
+ }
944
+ }