castle-web-cli 0.4.84 → 0.4.85
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/dist/ide.js +35 -13
- package/dist/shell/assets/{index-BOgm5T3W.js → index-BJLaUTJE.js} +21 -21
- package/dist/shell/index.html +1 -1
- package/kits/physics-2d/.prettierrc +8 -0
- package/kits/physics-2d/CLAUDE.md +329 -0
- package/kits/physics-2d/behaviors/Camera.jsx +43 -0
- package/kits/physics-2d/behaviors/Collider.jsx +199 -0
- package/kits/physics-2d/behaviors/Goal.jsx +29 -0
- package/kits/physics-2d/behaviors/Layout.jsx +53 -0
- package/kits/physics-2d/behaviors/Sprite.jsx +352 -0
- package/kits/physics-2d/behaviors/tint.js +47 -0
- package/kits/physics-2d/blueprints/ball.scene +14 -0
- package/kits/physics-2d/blueprints/block.scene +12 -0
- package/kits/physics-2d/blueprints/cauldron.scene +18 -0
- package/kits/physics-2d/blueprints/crate.scene +14 -0
- package/kits/physics-2d/blueprints/goal.scene +12 -0
- package/kits/physics-2d/castle.json +13 -0
- package/kits/physics-2d/docs/pxart-format.md +377 -0
- package/kits/physics-2d/drawings/block.pxart +25 -0
- package/kits/physics-2d/drawings/cauldron.pxart +113 -0
- package/kits/physics-2d/editors/BlueprintLibrary.jsx +247 -0
- package/kits/physics-2d/editors/ErrorBoundary.jsx +59 -0
- package/kits/physics-2d/editors/PlayOnly.jsx +31 -0
- package/kits/physics-2d/editors/PxArtEditor.jsx +954 -0
- package/kits/physics-2d/editors/SceneEditor.jsx +1681 -0
- package/kits/physics-2d/editors/SelectionOverlay.jsx +909 -0
- package/kits/physics-2d/editors/SingleEditor.jsx +122 -0
- package/kits/physics-2d/editors/behaviorRegistry.js +30 -0
- package/kits/physics-2d/editors/editorHistory.js +157 -0
- package/kits/physics-2d/editors/inspectorSheet.js +13 -0
- package/kits/physics-2d/editors/pixelCanvas.js +11 -0
- package/kits/physics-2d/editors/pixelEditorChrome.jsx +74 -0
- package/kits/physics-2d/editors/pixelGeometry.js +140 -0
- package/kits/physics-2d/editors/pixelInspector.jsx +633 -0
- package/kits/physics-2d/editors/pxArtEditorModel.js +732 -0
- package/kits/physics-2d/editors/pxArtPlayback.js +92 -0
- package/kits/physics-2d/editors/pxArtTimeline.jsx +752 -0
- package/kits/physics-2d/editors/pxArtTimeline.module.css +506 -0
- package/kits/physics-2d/editors/pxArtTools.js +232 -0
- package/kits/physics-2d/editors/useArtboardFit.js +102 -0
- package/kits/physics-2d/engine/ScenePlayer.jsx +196 -0
- package/kits/physics-2d/engine/SceneUI.jsx +59 -0
- package/kits/physics-2d/engine/assets.js +15 -0
- package/kits/physics-2d/engine/autoInspector.jsx +70 -0
- package/kits/physics-2d/engine/blueprint.js +521 -0
- package/kits/physics-2d/engine/collider.js +196 -0
- package/kits/physics-2d/engine/files.js +117 -0
- package/kits/physics-2d/engine/liveReload.js +88 -0
- package/kits/physics-2d/engine/pxart.js +1032 -0
- package/kits/physics-2d/engine/pxartSmooth.js +222 -0
- package/kits/physics-2d/engine/scene.js +686 -0
- package/kits/physics-2d/engine/spriteGeometry.js +32 -0
- package/kits/physics-2d/engine/ui.jsx +688 -0
- package/kits/physics-2d/engine/ui.module.css +2287 -0
- package/kits/physics-2d/eslint.config.js +71 -0
- package/kits/physics-2d/index.html +24 -0
- package/kits/physics-2d/main.jsx +24 -0
- package/kits/physics-2d/package-lock.json +2706 -0
- package/kits/physics-2d/package.json +42 -0
- package/kits/physics-2d/physics/PhysicsSystem.js +290 -0
- package/kits/physics-2d/physics/behaviors/AnalogStick.jsx +101 -0
- package/kits/physics-2d/physics/behaviors/Draggable.jsx +79 -0
- package/kits/physics-2d/physics/behaviors/RigidBody.jsx +55 -0
- package/kits/physics-2d/physics/behaviors/Slingshot.jsx +118 -0
- package/kits/physics-2d/physics/controls.js +79 -0
- package/kits/physics-2d/physics/index.js +26 -0
- package/kits/physics-2d/physics/matterBridge.js +126 -0
- package/kits/physics-2d/pnpm-lock.yaml +1761 -0
- package/kits/physics-2d/scenes/main.scene +12 -0
- package/kits/physics-2d/scenes/sandbox.scene +13 -0
- package/kits/physics-2d/scripts/draw.mjs +121 -0
- package/kits/physics-2d/vite.config.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,2287 @@
|
|
|
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: #111;
|
|
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: #2a2a2a;
|
|
21
|
+
--castle-text: #fff;
|
|
22
|
+
--castle-text-dim: #888;
|
|
23
|
+
--castle-text-muted: #888;
|
|
24
|
+
--castle-inspector-bg: #0d0d0d;
|
|
25
|
+
--castle-inspector-text: #e6e6e6;
|
|
26
|
+
--castle-inspector-muted: #888;
|
|
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
|
+
--castle-card: #121213;
|
|
35
|
+
--castle-selected: #e6e6e6;
|
|
36
|
+
--castle-selected-ink: #111;
|
|
37
|
+
--castle-danger: #ff5d5d;
|
|
38
|
+
--castle-ok: #81e69b;
|
|
39
|
+
--castle-blue: #8db7ff;
|
|
40
|
+
/* Instance-override indicator: label/reset text + a dimmer input border. */
|
|
41
|
+
--castle-override: #b388ff;
|
|
42
|
+
--castle-override-border: #5b4a80;
|
|
43
|
+
--castle-radius: 4px;
|
|
44
|
+
/* Tools/hotbar strip height -- aligned to the inspector "+ Add behavior" row
|
|
45
|
+
(top+bottom pad + 1px borders + select padding + text line). The text line
|
|
46
|
+
uses `rem` (root-relative), NOT `em`: the hotbar inherits the 16px body font
|
|
47
|
+
while the inspector sets font-size:14px, so an `em` here resolved to 20px on
|
|
48
|
+
the hotbar but only 17.5px inside the inspector -- leaving the Add-behavior
|
|
49
|
+
row ~2.5px short of the hotbar. `rem` resolves to the same value in both. */
|
|
50
|
+
--castle-hotbar-row-pad-y: 12px;
|
|
51
|
+
--castle-hotbar-row-h: calc(var(--castle-hotbar-row-pad-y) * 2 + 2px + 10px + 1.25rem);
|
|
52
|
+
/* Full row height shared by the scene hotbar (.sceneTools + its grid track)
|
|
53
|
+
and the inspector "+ Add behavior" row, so both bottom borders land on the
|
|
54
|
+
same y. The +2px matches the Add-behavior row's outer box; it also gives the
|
|
55
|
+
46px hotbar buttons room to sit fully inside the bar (no bottom clipping). */
|
|
56
|
+
--castle-hotbar-row-full: calc(var(--castle-hotbar-row-h) + 2px);
|
|
57
|
+
color-scheme: dark;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
:global(*) {
|
|
61
|
+
box-sizing: border-box;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Hide scrollbars across the whole editor while keeping scroll functional. */
|
|
65
|
+
:global(*) {
|
|
66
|
+
scrollbar-width: none;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
:global(*)::-webkit-scrollbar {
|
|
70
|
+
display: none;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
:global(html),
|
|
74
|
+
:global(body),
|
|
75
|
+
:global(#root) {
|
|
76
|
+
width: 100%;
|
|
77
|
+
height: 100%;
|
|
78
|
+
margin: 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
:global(body) {
|
|
82
|
+
overflow: hidden;
|
|
83
|
+
background: var(--castle-workspace-bg);
|
|
84
|
+
color: var(--castle-inspector-text);
|
|
85
|
+
font-family: var(--castle-font-body);
|
|
86
|
+
-webkit-font-smoothing: antialiased;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
:global(button),
|
|
90
|
+
:global(input),
|
|
91
|
+
:global(select),
|
|
92
|
+
:global(textarea) {
|
|
93
|
+
font: inherit;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
:global(button),
|
|
97
|
+
:global(input),
|
|
98
|
+
:global(select),
|
|
99
|
+
:global(textarea),
|
|
100
|
+
:global([tabindex]) {
|
|
101
|
+
outline: none;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
:global(*:focus),
|
|
105
|
+
:global(*:focus-visible) {
|
|
106
|
+
outline: none;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Editor-root is a vertical stack: full-width header row, then the
|
|
110
|
+
`[file list | workspace]` grid row. */
|
|
111
|
+
.editorRoot {
|
|
112
|
+
width: 100%;
|
|
113
|
+
height: 100%;
|
|
114
|
+
display: flex;
|
|
115
|
+
flex-direction: column;
|
|
116
|
+
background: var(--castle-workspace-bg);
|
|
117
|
+
color: var(--castle-inspector-text);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Portal target for the active editor's header. `display: contents` lets the
|
|
121
|
+
portaled `.editorHeader` be a direct flex child of `.editorRoot`. */
|
|
122
|
+
.editorHeaderHost {
|
|
123
|
+
display: contents;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.appShell {
|
|
127
|
+
flex: 1 1 0;
|
|
128
|
+
min-height: 0;
|
|
129
|
+
display: grid;
|
|
130
|
+
grid-template-columns: 200px 1fr;
|
|
131
|
+
background: var(--castle-workspace-bg);
|
|
132
|
+
color: var(--castle-inspector-text);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/* Desktop: the files toggle collapses the file-list column. (Never set in
|
|
136
|
+
compact mode, where the file list is a bottom sheet instead.) */
|
|
137
|
+
.editorRoot.filesHidden .appShell {
|
|
138
|
+
grid-template-columns: 1fr;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.editorRoot.filesHidden .fileBrowser {
|
|
142
|
+
display: none;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.fileBrowser {
|
|
146
|
+
min-width: 0;
|
|
147
|
+
border-right: 1px solid var(--castle-inspector-divider);
|
|
148
|
+
background: var(--castle-workspace-bg);
|
|
149
|
+
display: flex;
|
|
150
|
+
flex-direction: column;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* Bare file browser for the dockview "Files" panel: no sidebar border or
|
|
154
|
+
mobile-sheet chrome, just a full-height column so the tree fills the panel
|
|
155
|
+
and the empty area below the rows still catches the blank-area menu. */
|
|
156
|
+
.fileBrowserBare {
|
|
157
|
+
min-width: 0;
|
|
158
|
+
height: 100%;
|
|
159
|
+
display: flex;
|
|
160
|
+
flex-direction: column;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.editorHeader {
|
|
164
|
+
height: 48px;
|
|
165
|
+
flex: 0 0 48px;
|
|
166
|
+
display: flex;
|
|
167
|
+
align-items: center;
|
|
168
|
+
gap: 8px;
|
|
169
|
+
padding: 10px 12px;
|
|
170
|
+
border-bottom: 1px solid var(--castle-inspector-divider);
|
|
171
|
+
background: var(--castle-workspace-bg);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.editorTitle {
|
|
175
|
+
font-family: var(--castle-font-display);
|
|
176
|
+
letter-spacing: 0.01em;
|
|
177
|
+
font-size: 14px;
|
|
178
|
+
line-height: 1;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.muted {
|
|
182
|
+
color: var(--castle-inspector-muted);
|
|
183
|
+
font-size: 12px;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
.fileTree {
|
|
187
|
+
flex: 1 1 0;
|
|
188
|
+
min-height: 0;
|
|
189
|
+
padding-top: 5px;
|
|
190
|
+
overflow-y: auto;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.fileBranch {
|
|
194
|
+
min-width: 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/* File-list rows ride the workspace "notch" ladder: default sits on the
|
|
198
|
+
workspace bg (#0a0a0a, transparent), hover lifts one notch to the sheet bg
|
|
199
|
+
(#0d0d0d), and the selected row lifts one notch further to panel-raised
|
|
200
|
+
(#101010). Text follows the same idea: unselected rows are the SAME light
|
|
201
|
+
text token as the selected/hover row, just faded (reduced opacity) so they
|
|
202
|
+
stay clearly legible on the dark panel; the selected row is the full
|
|
203
|
+
standard light text. */
|
|
204
|
+
.fileRow,
|
|
205
|
+
.fileDirRow {
|
|
206
|
+
width: 100%;
|
|
207
|
+
border: 0;
|
|
208
|
+
border-radius: var(--castle-radius);
|
|
209
|
+
background: transparent;
|
|
210
|
+
/* Plain opaque gray, NOT color-mix(...transparent): Safari fails to paint a
|
|
211
|
+
semi-transparent color-mix result until a repaint is forced (opening
|
|
212
|
+
devtools makes it appear), leaving rows invisible at rest. This solid value
|
|
213
|
+
approximates the light text token faded over the dark panel. */
|
|
214
|
+
color: #a8a8a8;
|
|
215
|
+
display: flex;
|
|
216
|
+
align-items: center;
|
|
217
|
+
justify-content: flex-start;
|
|
218
|
+
gap: 6px;
|
|
219
|
+
padding: 5px 9px 5px calc(9px + var(--file-depth, 0) * 20px);
|
|
220
|
+
text-align: left;
|
|
221
|
+
cursor: pointer;
|
|
222
|
+
font-size: 14px;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/* Folders read darker than files at rest so the tree's structure (containers
|
|
226
|
+
vs. leaves) is legible at a glance. Hover/selected still lift both to the full
|
|
227
|
+
light text via the higher-specificity rules below. */
|
|
228
|
+
.fileDirRow {
|
|
229
|
+
color: #777;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.fileRow:hover,
|
|
233
|
+
.fileDirRow:hover {
|
|
234
|
+
background: var(--castle-sheet-bg);
|
|
235
|
+
color: var(--castle-inspector-text);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/* Compound `.fileRow.fileRowSelected` so the selected look (full text +
|
|
239
|
+
one-notch-lighter bg) outranks `.fileRow:hover` on specificity, not source
|
|
240
|
+
order -- the selected row stays put even while hovered. */
|
|
241
|
+
.fileRow.fileRowSelected,
|
|
242
|
+
.fileRow.fileRowSelected:hover {
|
|
243
|
+
background: var(--castle-panel-raised);
|
|
244
|
+
color: var(--castle-inspector-text);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/* The disclosure caret only appears on folder rows; keep it a shade darker than
|
|
248
|
+
the folder name (#666 vs #777) at rest, then lift it to the full light text on
|
|
249
|
+
hover alongside the name. Compound `.fileIcon.fileDisclosure` (0,2,0) is
|
|
250
|
+
required to beat the later `.fileIcon` muted-color rule (0,1,0); a bare
|
|
251
|
+
`.fileDisclosure` ties on specificity and loses on source order. */
|
|
252
|
+
.fileIcon.fileDisclosure {
|
|
253
|
+
color: #666;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.fileDirRow:hover .fileIcon.fileDisclosure {
|
|
257
|
+
color: inherit;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.fileDisclosure svg {
|
|
261
|
+
width: 10px;
|
|
262
|
+
height: 10px;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/* Icon + name group: its own gap controls icon<->name spacing, independent of
|
|
266
|
+
the row's disclosure<->label gap. */
|
|
267
|
+
.fileLabel {
|
|
268
|
+
display: inline-flex;
|
|
269
|
+
align-items: center;
|
|
270
|
+
gap: 6px;
|
|
271
|
+
min-width: 0;
|
|
272
|
+
flex: 1 1 auto;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/* Inline rename field. Constrained to the row width (flex:1 + min-width:0 +
|
|
276
|
+
border-box) so a long name never pushes the file browser into horizontal
|
|
277
|
+
overflow. */
|
|
278
|
+
.fileRenameInput {
|
|
279
|
+
flex: 1 1 auto;
|
|
280
|
+
min-width: 0;
|
|
281
|
+
width: 100%;
|
|
282
|
+
max-width: 100%;
|
|
283
|
+
box-sizing: border-box;
|
|
284
|
+
padding: 1px 4px;
|
|
285
|
+
border: 1px solid var(--castle-border);
|
|
286
|
+
border-radius: 5px;
|
|
287
|
+
background: var(--castle-panel-raised);
|
|
288
|
+
color: var(--castle-text);
|
|
289
|
+
font: inherit;
|
|
290
|
+
font-size: 13px;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
.fileRenameInput:focus {
|
|
294
|
+
outline: none;
|
|
295
|
+
border-color: var(--castle-text-dim);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/* Type-based file icon: muted so the file name stays the visual emphasis. */
|
|
299
|
+
.fileIcon {
|
|
300
|
+
width: 14px;
|
|
301
|
+
flex: 0 0 14px;
|
|
302
|
+
display: inline-flex;
|
|
303
|
+
align-items: center;
|
|
304
|
+
justify-content: center;
|
|
305
|
+
color: var(--castle-inspector-muted);
|
|
306
|
+
font-size: 14px;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
.mainEditor {
|
|
310
|
+
min-width: 0;
|
|
311
|
+
min-height: 0;
|
|
312
|
+
width: 100%;
|
|
313
|
+
height: 100%;
|
|
314
|
+
display: flex;
|
|
315
|
+
flex-direction: column;
|
|
316
|
+
background: var(--castle-sheet-bg);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.editorHeader {
|
|
320
|
+
justify-content: space-between;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
.editorHeaderLeft,
|
|
324
|
+
.editorHeaderRight,
|
|
325
|
+
.toolbar {
|
|
326
|
+
display: flex;
|
|
327
|
+
align-items: center;
|
|
328
|
+
gap: 8px;
|
|
329
|
+
min-width: 0;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
.editorBody {
|
|
333
|
+
min-height: 0;
|
|
334
|
+
flex: 1;
|
|
335
|
+
display: flex;
|
|
336
|
+
overflow: hidden;
|
|
337
|
+
container-type: inline-size;
|
|
338
|
+
container-name: editor;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.sceneWorkspace {
|
|
342
|
+
flex: 1;
|
|
343
|
+
min-width: 0;
|
|
344
|
+
min-height: 0;
|
|
345
|
+
display: grid;
|
|
346
|
+
grid-template-columns: minmax(0, 1fr) 280px;
|
|
347
|
+
grid-template-rows: var(--castle-hotbar-row-full) minmax(0, 1fr);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
.sceneTools {
|
|
351
|
+
grid-column: 1;
|
|
352
|
+
grid-row: 1;
|
|
353
|
+
height: var(--castle-hotbar-row-full);
|
|
354
|
+
min-width: 0;
|
|
355
|
+
display: flex;
|
|
356
|
+
align-items: center;
|
|
357
|
+
padding: 0;
|
|
358
|
+
border-bottom: 1px solid var(--castle-inspector-divider);
|
|
359
|
+
background: var(--castle-workspace-bg);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/* Blueprint hotbar -- left-aligned djinn-style stamp palette. Today it holds a
|
|
363
|
+
single "+" Add-actor control; drag-and-drop blueprint slots land here later. */
|
|
364
|
+
.bpHotbar {
|
|
365
|
+
display: flex;
|
|
366
|
+
flex-direction: row;
|
|
367
|
+
align-items: center;
|
|
368
|
+
gap: 6px;
|
|
369
|
+
width: 100%;
|
|
370
|
+
height: 100%;
|
|
371
|
+
padding: 0 6px;
|
|
372
|
+
overflow-x: auto;
|
|
373
|
+
overflow-y: hidden;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.bpSlot,
|
|
377
|
+
.bpActionSlot {
|
|
378
|
+
position: relative;
|
|
379
|
+
width: 46px;
|
|
380
|
+
height: 46px;
|
|
381
|
+
/* Never shrink in the flex hotbar -- keep the square 46x46 and let the
|
|
382
|
+
hotbar scroll (overflow-x: auto) when the panel gets narrow, instead of
|
|
383
|
+
squishing slots (the add button collapsed since its icon is only 14px). */
|
|
384
|
+
flex: 0 0 46px;
|
|
385
|
+
display: inline-flex;
|
|
386
|
+
align-items: center;
|
|
387
|
+
justify-content: center;
|
|
388
|
+
padding: 0;
|
|
389
|
+
border: 1px solid var(--castle-inspector-border);
|
|
390
|
+
border-radius: var(--castle-radius);
|
|
391
|
+
background: var(--castle-inspector-button-bg);
|
|
392
|
+
color: var(--castle-inspector-text);
|
|
393
|
+
cursor: pointer;
|
|
394
|
+
font-size: 14px;
|
|
395
|
+
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.bpSlotBadge {
|
|
399
|
+
position: absolute;
|
|
400
|
+
right: -4px;
|
|
401
|
+
bottom: -4px;
|
|
402
|
+
min-width: 15px;
|
|
403
|
+
height: 15px;
|
|
404
|
+
padding: 0 3px;
|
|
405
|
+
border-radius: 999px;
|
|
406
|
+
background: var(--castle-selected);
|
|
407
|
+
color: var(--castle-selected-ink);
|
|
408
|
+
font-size: 10px;
|
|
409
|
+
font-weight: 700;
|
|
410
|
+
line-height: 15px;
|
|
411
|
+
text-align: center;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
.bpSlot:hover,
|
|
415
|
+
.bpActionSlot:hover {
|
|
416
|
+
background: var(--castle-inspector-input-bg);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.bpSlotSelected,
|
|
420
|
+
.bpSlotSelected:hover {
|
|
421
|
+
border-color: var(--castle-selected);
|
|
422
|
+
box-shadow: 0 0 0 1px var(--castle-selected);
|
|
423
|
+
background: var(--castle-inspector-input-bg);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
/* The blueprint of the currently-selected actor: distinct from a direct
|
|
427
|
+
blueprint selection -- just a white border, no thickening/glow. */
|
|
428
|
+
.bpSlotInstance,
|
|
429
|
+
.bpSlotInstance:hover {
|
|
430
|
+
border-color: #fff;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
.bpSlot:disabled,
|
|
434
|
+
.bpActionSlot:disabled {
|
|
435
|
+
cursor: default;
|
|
436
|
+
opacity: 0.35;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
.bpSlot svg,
|
|
440
|
+
.bpActionSlot svg {
|
|
441
|
+
width: 14px;
|
|
442
|
+
height: 14px;
|
|
443
|
+
flex: 0 0 auto;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
.bpSlotThumb,
|
|
447
|
+
.bpSlotFallback {
|
|
448
|
+
width: 36px;
|
|
449
|
+
height: 36px;
|
|
450
|
+
flex: 0 0 36px;
|
|
451
|
+
border-radius: 3px;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
.bpSlotThumb {
|
|
455
|
+
image-rendering: pixelated;
|
|
456
|
+
background: var(--castle-card);
|
|
457
|
+
object-fit: contain;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.bpSlotFallback {
|
|
461
|
+
display: inline-flex;
|
|
462
|
+
align-items: center;
|
|
463
|
+
justify-content: center;
|
|
464
|
+
color: var(--castle-inspector-muted);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.bpDragPreview {
|
|
468
|
+
position: fixed;
|
|
469
|
+
z-index: 1000;
|
|
470
|
+
pointer-events: none;
|
|
471
|
+
display: flex;
|
|
472
|
+
align-items: center;
|
|
473
|
+
justify-content: center;
|
|
474
|
+
border: 1px dashed var(--castle-text);
|
|
475
|
+
background: rgb(230 230 230 / 0.08);
|
|
476
|
+
opacity: 0.7;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
.bpDragPreviewOverStage {
|
|
480
|
+
opacity: 0.9;
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
.bpPreviewThumb {
|
|
484
|
+
width: 100%;
|
|
485
|
+
height: 100%;
|
|
486
|
+
flex: 1 1 auto;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
.confirmBackdrop {
|
|
490
|
+
position: fixed;
|
|
491
|
+
inset: 0;
|
|
492
|
+
z-index: 2000;
|
|
493
|
+
display: flex;
|
|
494
|
+
align-items: center;
|
|
495
|
+
justify-content: center;
|
|
496
|
+
background: rgba(0, 0, 0, 0.55);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
.confirmDialog {
|
|
500
|
+
width: min(340px, calc(100vw - 32px));
|
|
501
|
+
padding: 18px;
|
|
502
|
+
border: 1px solid var(--castle-border);
|
|
503
|
+
border-radius: 10px;
|
|
504
|
+
background: var(--castle-panel-raised);
|
|
505
|
+
color: var(--castle-text);
|
|
506
|
+
box-shadow: 0 20px 48px rgba(0, 0, 0, 0.5);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.confirmTitle {
|
|
510
|
+
font-size: 15px;
|
|
511
|
+
font-weight: 650;
|
|
512
|
+
margin-bottom: 8px;
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.confirmMessage {
|
|
516
|
+
font-size: 13px;
|
|
517
|
+
color: var(--castle-text-dim);
|
|
518
|
+
line-height: 1.45;
|
|
519
|
+
margin-bottom: 16px;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.confirmActions {
|
|
523
|
+
display: flex;
|
|
524
|
+
justify-content: flex-end;
|
|
525
|
+
gap: 8px;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.blueprintBadge {
|
|
529
|
+
display: inline-flex;
|
|
530
|
+
align-items: center;
|
|
531
|
+
padding: 2px 7px;
|
|
532
|
+
border-radius: 999px;
|
|
533
|
+
border: 1px solid var(--castle-inspector-border);
|
|
534
|
+
background: var(--castle-inspector-input-bg);
|
|
535
|
+
color: var(--castle-inspector-muted);
|
|
536
|
+
font-size: 11px;
|
|
537
|
+
font-weight: 600;
|
|
538
|
+
letter-spacing: 0.02em;
|
|
539
|
+
text-transform: uppercase;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
.editorHeaderTitleRow {
|
|
543
|
+
display: inline-flex;
|
|
544
|
+
align-items: center;
|
|
545
|
+
gap: 8px;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
.instanceHint {
|
|
549
|
+
display: flex;
|
|
550
|
+
align-items: center;
|
|
551
|
+
justify-content: space-between;
|
|
552
|
+
gap: 8px;
|
|
553
|
+
padding: 10px 16px;
|
|
554
|
+
border-bottom: 1px solid var(--castle-inspector-divider);
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
.instanceHintLabel {
|
|
558
|
+
color: var(--castle-inspector-muted);
|
|
559
|
+
font-size: 12px;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.instanceHeader {
|
|
563
|
+
display: flex;
|
|
564
|
+
flex-direction: column;
|
|
565
|
+
align-items: stretch;
|
|
566
|
+
gap: 12px;
|
|
567
|
+
padding: 14px 16px;
|
|
568
|
+
border-bottom: 1px solid var(--castle-inspector-divider);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
.instanceHeaderName {
|
|
572
|
+
display: flex;
|
|
573
|
+
align-items: center;
|
|
574
|
+
gap: 8px;
|
|
575
|
+
min-width: 0;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
.instanceHeaderNameText {
|
|
579
|
+
min-width: 0;
|
|
580
|
+
overflow: hidden;
|
|
581
|
+
text-overflow: ellipsis;
|
|
582
|
+
white-space: nowrap;
|
|
583
|
+
color: var(--castle-inspector-text);
|
|
584
|
+
font-size: 14px;
|
|
585
|
+
font-weight: 400;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
.instanceHeaderNameStrong {
|
|
589
|
+
font-weight: 600;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
.instanceHeaderNameCol {
|
|
593
|
+
display: flex;
|
|
594
|
+
flex-direction: column;
|
|
595
|
+
gap: 2px;
|
|
596
|
+
min-width: 0;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.instanceHeaderId {
|
|
600
|
+
color: var(--castle-inspector-muted);
|
|
601
|
+
font-size: 12px;
|
|
602
|
+
overflow: hidden;
|
|
603
|
+
text-overflow: ellipsis;
|
|
604
|
+
white-space: nowrap;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
.revealOverridesButton {
|
|
608
|
+
display: flex;
|
|
609
|
+
align-items: center;
|
|
610
|
+
justify-content: flex-start;
|
|
611
|
+
gap: 8px;
|
|
612
|
+
width: 100%;
|
|
613
|
+
padding: 14px 16px;
|
|
614
|
+
border: 0;
|
|
615
|
+
border-bottom: 1px solid var(--castle-inspector-divider);
|
|
616
|
+
background: transparent;
|
|
617
|
+
color: var(--castle-inspector-muted);
|
|
618
|
+
font-size: 13px;
|
|
619
|
+
text-align: left;
|
|
620
|
+
cursor: pointer;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
.revealOverridesButton:hover {
|
|
624
|
+
background: var(--castle-inspector-input-bg);
|
|
625
|
+
color: var(--castle-inspector-text);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.instanceForkButton {
|
|
629
|
+
display: inline-flex;
|
|
630
|
+
align-items: center;
|
|
631
|
+
justify-content: center;
|
|
632
|
+
gap: 6px;
|
|
633
|
+
align-self: flex-start;
|
|
634
|
+
border: 1px solid var(--castle-inspector-border);
|
|
635
|
+
border-radius: 6px;
|
|
636
|
+
background: var(--castle-inspector-input-bg);
|
|
637
|
+
color: inherit;
|
|
638
|
+
font-size: 11px;
|
|
639
|
+
padding: 5px 9px;
|
|
640
|
+
cursor: pointer;
|
|
641
|
+
white-space: nowrap;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
.instanceForkButton:hover {
|
|
645
|
+
background: var(--castle-inspector-border);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/* Editable blueprint title: reads as a heading until hovered/focused, where a
|
|
649
|
+
border + input background reveal that it's editable. */
|
|
650
|
+
.blueprintNameInput {
|
|
651
|
+
flex: 1;
|
|
652
|
+
min-width: 0;
|
|
653
|
+
border: 1px solid transparent;
|
|
654
|
+
border-radius: var(--castle-radius);
|
|
655
|
+
background: transparent;
|
|
656
|
+
color: var(--castle-inspector-text);
|
|
657
|
+
font-size: 14px;
|
|
658
|
+
font-weight: 600;
|
|
659
|
+
padding: 4px 6px;
|
|
660
|
+
margin: -4px -6px;
|
|
661
|
+
outline: 0;
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
.blueprintNameInput:hover {
|
|
665
|
+
border-color: var(--castle-inspector-border);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.blueprintNameInput:focus {
|
|
669
|
+
border-color: var(--castle-inspector-border);
|
|
670
|
+
background: var(--castle-inspector-input-bg);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
.stageWrap {
|
|
674
|
+
grid-column: 1;
|
|
675
|
+
grid-row: 2;
|
|
676
|
+
min-width: 0;
|
|
677
|
+
min-height: 0;
|
|
678
|
+
display: flex;
|
|
679
|
+
align-items: center;
|
|
680
|
+
justify-content: center;
|
|
681
|
+
padding: 20px;
|
|
682
|
+
background: var(--castle-stage-workspace-bg);
|
|
683
|
+
overflow: hidden;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
.stageCard {
|
|
687
|
+
position: relative;
|
|
688
|
+
width: min(52vh, 440px);
|
|
689
|
+
aspect-ratio: 5 / 7;
|
|
690
|
+
max-width: 100%;
|
|
691
|
+
overflow: visible;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.stageCardClip {
|
|
695
|
+
position: absolute;
|
|
696
|
+
inset: 0;
|
|
697
|
+
background: var(--castle-card);
|
|
698
|
+
border-radius: 12px;
|
|
699
|
+
overflow: hidden;
|
|
700
|
+
box-shadow: 0 2px 0 rgba(0, 0, 0, 0.2);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.stageCardEditSurface {
|
|
704
|
+
overflow: visible;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.stageCanvas {
|
|
708
|
+
width: 100%;
|
|
709
|
+
height: 100%;
|
|
710
|
+
display: block;
|
|
711
|
+
touch-action: none;
|
|
712
|
+
/* tabIndex=-1 (keyboard-focus capture on pointer-down) would otherwise draw a
|
|
713
|
+
focus ring; focus here is programmatic only, never via keyboard. */
|
|
714
|
+
outline: none;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
.stageCanvasEdit {
|
|
718
|
+
position: absolute;
|
|
719
|
+
left: -100%;
|
|
720
|
+
top: -100%;
|
|
721
|
+
width: 300%;
|
|
722
|
+
height: 300%;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/* Game-time UI overlay -- sits exactly over the canvas and clips to the card.
|
|
726
|
+
Behavior `ui` output lands in `.sceneUiLayer`, which is sized in card units
|
|
727
|
+
and scaled onto the canvas box. */
|
|
728
|
+
.sceneUiRoot {
|
|
729
|
+
position: absolute;
|
|
730
|
+
inset: 0;
|
|
731
|
+
overflow: hidden;
|
|
732
|
+
pointer-events: none;
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
.sceneUiLayer {
|
|
736
|
+
position: absolute;
|
|
737
|
+
left: 0;
|
|
738
|
+
top: 0;
|
|
739
|
+
transform-origin: 0 0;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/* On-canvas selection toolbar ("selection handles"). Two stacked layers cover
|
|
743
|
+
the canvas box (sized by a ResizeObserver, like .sceneUiRoot):
|
|
744
|
+
- .selChromeLayer is the card-unit (500x700) layer, scaled onto the canvas
|
|
745
|
+
and translated by -camera so the dashed box / dots / pivot track the edit
|
|
746
|
+
camera exactly like the canvas draw path. Chrome lives in card units, so it
|
|
747
|
+
scales gently with the responsive card.
|
|
748
|
+
- .selButtonLayer is an un-scaled px layer; the floating buttons are placed
|
|
749
|
+
in projected px (world -> screen) so they stay crisp and fixed-size with
|
|
750
|
+
fixed px gaps regardless of card scale. */
|
|
751
|
+
.selOverlayRoot {
|
|
752
|
+
position: absolute;
|
|
753
|
+
inset: 0;
|
|
754
|
+
overflow: visible;
|
|
755
|
+
pointer-events: none;
|
|
756
|
+
animation: selOverlayIn 150ms ease;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
/* Fade only -- no scale. Scaling the full-card overlay about its center made
|
|
760
|
+
an off-center selection's handles slide inward-from-center on every mount
|
|
761
|
+
(most visible re-selecting a different actor after a deselect, where the
|
|
762
|
+
overlay remounts), reading as "animating in from the old position". */
|
|
763
|
+
@keyframes selOverlayIn {
|
|
764
|
+
from {
|
|
765
|
+
opacity: 0;
|
|
766
|
+
}
|
|
767
|
+
to {
|
|
768
|
+
opacity: 1;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
.selChromeLayer {
|
|
773
|
+
position: absolute;
|
|
774
|
+
left: 0;
|
|
775
|
+
top: 0;
|
|
776
|
+
transform-origin: 0 0;
|
|
777
|
+
pointer-events: none;
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
.selChromeWorld {
|
|
781
|
+
position: absolute;
|
|
782
|
+
left: 0;
|
|
783
|
+
top: 0;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.selColliderBox {
|
|
787
|
+
position: absolute;
|
|
788
|
+
box-sizing: border-box;
|
|
789
|
+
border: 2px dotted rgb(141 183 255 / 0.9);
|
|
790
|
+
background: rgb(141 183 255 / 0.14);
|
|
791
|
+
border-radius: 2px;
|
|
792
|
+
pointer-events: none;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.selColliderPickup {
|
|
796
|
+
border-color: rgb(255 225 122 / 0.9);
|
|
797
|
+
background: rgb(255 225 122 / 0.14);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
.selBox {
|
|
801
|
+
position: absolute;
|
|
802
|
+
box-sizing: border-box;
|
|
803
|
+
border: 2px solid var(--castle-text);
|
|
804
|
+
border-radius: 3px;
|
|
805
|
+
opacity: 0.85;
|
|
806
|
+
pointer-events: none;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
/* Connector stem from the box's right-center edge to the rotate handle. Lives
|
|
810
|
+
in the un-scaled px layer and is rotated about its left-center anchor, so its
|
|
811
|
+
thickness matches the selection box border at any zoom. */
|
|
812
|
+
.selStem {
|
|
813
|
+
position: absolute;
|
|
814
|
+
height: 2px;
|
|
815
|
+
background: var(--castle-text);
|
|
816
|
+
opacity: 0.85;
|
|
817
|
+
transform-origin: left center;
|
|
818
|
+
pointer-events: none;
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
.selScaleHandle {
|
|
822
|
+
position: absolute;
|
|
823
|
+
border: 0;
|
|
824
|
+
padding: 0;
|
|
825
|
+
background: var(--castle-text);
|
|
826
|
+
border: 2px solid var(--castle-selected-ink);
|
|
827
|
+
transform: translate(-50%, -50%);
|
|
828
|
+
pointer-events: auto;
|
|
829
|
+
touch-action: none;
|
|
830
|
+
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
.selScaleCorner {
|
|
834
|
+
width: 11px;
|
|
835
|
+
height: 11px;
|
|
836
|
+
border-radius: 999px;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.selScaleEdge {
|
|
840
|
+
border-radius: 999px;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
.selScaleEdge[data-handle='n'],
|
|
844
|
+
.selScaleEdge[data-handle='s'] {
|
|
845
|
+
width: 28px;
|
|
846
|
+
height: 9px;
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
.selScaleEdge[data-handle='e'],
|
|
850
|
+
.selScaleEdge[data-handle='w'] {
|
|
851
|
+
width: 9px;
|
|
852
|
+
height: 28px;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
.selPivot {
|
|
856
|
+
position: absolute;
|
|
857
|
+
width: 13px;
|
|
858
|
+
height: 13px;
|
|
859
|
+
border-radius: 999px;
|
|
860
|
+
border: 2px solid var(--castle-text);
|
|
861
|
+
background: transparent;
|
|
862
|
+
opacity: 0.85;
|
|
863
|
+
transform: translate(-50%, -50%);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
.selButtonLayer {
|
|
867
|
+
position: absolute;
|
|
868
|
+
inset: 0;
|
|
869
|
+
pointer-events: none;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
.selBtnWrap {
|
|
873
|
+
position: absolute;
|
|
874
|
+
transform: translate(-50%, -50%);
|
|
875
|
+
pointer-events: auto;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
.selBtnGroup {
|
|
879
|
+
display: flex;
|
|
880
|
+
gap: 8px;
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
.selArrangeWrap {
|
|
884
|
+
position: relative;
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
.selArrangeMenu {
|
|
888
|
+
position: absolute;
|
|
889
|
+
left: 50%;
|
|
890
|
+
top: calc(100% + 8px);
|
|
891
|
+
min-width: 150px;
|
|
892
|
+
padding: 5px;
|
|
893
|
+
border: 1px solid var(--castle-border);
|
|
894
|
+
border-radius: 10px;
|
|
895
|
+
background: var(--castle-panel-raised);
|
|
896
|
+
color: var(--castle-text);
|
|
897
|
+
box-shadow: 0 10px 26px rgba(0, 0, 0, 0.45);
|
|
898
|
+
transform: translateX(-50%);
|
|
899
|
+
z-index: 2;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
.selArrangeItem {
|
|
903
|
+
width: 100%;
|
|
904
|
+
border: 0;
|
|
905
|
+
border-radius: 7px;
|
|
906
|
+
padding: 7px 9px;
|
|
907
|
+
background: transparent;
|
|
908
|
+
color: inherit;
|
|
909
|
+
cursor: pointer;
|
|
910
|
+
font: inherit;
|
|
911
|
+
font-size: 12px;
|
|
912
|
+
text-align: left;
|
|
913
|
+
white-space: nowrap;
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
.selArrangeItem:hover {
|
|
917
|
+
background: var(--castle-panel);
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
.selArrangeItemDisabled,
|
|
921
|
+
.selArrangeItemDisabled:hover {
|
|
922
|
+
opacity: 0.4;
|
|
923
|
+
background: transparent;
|
|
924
|
+
cursor: default;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
.selBtn {
|
|
928
|
+
width: 32px;
|
|
929
|
+
height: 32px;
|
|
930
|
+
border-radius: 999px;
|
|
931
|
+
border: 1px solid var(--castle-border);
|
|
932
|
+
background: var(--castle-panel-raised);
|
|
933
|
+
color: var(--castle-text);
|
|
934
|
+
display: inline-flex;
|
|
935
|
+
align-items: center;
|
|
936
|
+
justify-content: center;
|
|
937
|
+
padding: 0;
|
|
938
|
+
font-size: 14px;
|
|
939
|
+
cursor: pointer;
|
|
940
|
+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.45);
|
|
941
|
+
touch-action: none;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
.selBtn:hover {
|
|
945
|
+
background: var(--castle-panel);
|
|
946
|
+
border-color: var(--castle-text-dim);
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
.selBtn svg {
|
|
950
|
+
width: 1em;
|
|
951
|
+
height: 1em;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
.selBtnGrab {
|
|
955
|
+
cursor: grab;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
.selBtnRotate {
|
|
959
|
+
cursor: grab;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
/* Touch targets: larger hit area on coarse pointers / compact layout. */
|
|
963
|
+
@media (pointer: coarse), (max-width: 600px) {
|
|
964
|
+
.selBtn {
|
|
965
|
+
width: 44px;
|
|
966
|
+
height: 44px;
|
|
967
|
+
font-size: 18px;
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
.selBtnGroup {
|
|
971
|
+
gap: 12px;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
.selScaleCorner {
|
|
975
|
+
width: 17px;
|
|
976
|
+
height: 17px;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
.selScaleEdge[data-handle='n'],
|
|
980
|
+
.selScaleEdge[data-handle='s'] {
|
|
981
|
+
width: 38px;
|
|
982
|
+
height: 15px;
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
.selScaleEdge[data-handle='e'],
|
|
986
|
+
.selScaleEdge[data-handle='w'] {
|
|
987
|
+
width: 15px;
|
|
988
|
+
height: 38px;
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
.inspector {
|
|
993
|
+
grid-column: 2;
|
|
994
|
+
grid-row: 1 / span 2;
|
|
995
|
+
min-width: 0;
|
|
996
|
+
border-left: 1px solid var(--castle-inspector-divider);
|
|
997
|
+
background: var(--castle-workspace-bg);
|
|
998
|
+
color: var(--castle-inspector-text);
|
|
999
|
+
font-size: 14px;
|
|
1000
|
+
overflow: auto;
|
|
1001
|
+
padding: 0;
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
.panel {
|
|
1005
|
+
border: 0;
|
|
1006
|
+
border-bottom: 1px solid var(--castle-inspector-divider);
|
|
1007
|
+
border-radius: 0;
|
|
1008
|
+
background: var(--castle-inspector-bg);
|
|
1009
|
+
color: var(--castle-inspector-text);
|
|
1010
|
+
font-size: 14px;
|
|
1011
|
+
margin: 0;
|
|
1012
|
+
overflow: visible;
|
|
1013
|
+
box-shadow: none;
|
|
1014
|
+
}
|
|
1015
|
+
|
|
1016
|
+
.panel:last-child {
|
|
1017
|
+
border-bottom: 0;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
.panelHeader {
|
|
1021
|
+
display: flex;
|
|
1022
|
+
align-items: center;
|
|
1023
|
+
justify-content: space-between;
|
|
1024
|
+
gap: 12px;
|
|
1025
|
+
padding: 14px 16px 6px;
|
|
1026
|
+
border-bottom: 0;
|
|
1027
|
+
color: var(--castle-inspector-text);
|
|
1028
|
+
font-size: 14px;
|
|
1029
|
+
font-weight: 650;
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
.panelTitleOverridden {
|
|
1033
|
+
color: var(--castle-override);
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
.panelBody {
|
|
1037
|
+
padding: 8px 16px 4px;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
.fieldRow {
|
|
1041
|
+
display: grid;
|
|
1042
|
+
grid-template-columns: minmax(82px, 0.5fr) minmax(0, 1fr);
|
|
1043
|
+
align-items: center;
|
|
1044
|
+
gap: 12px;
|
|
1045
|
+
padding-bottom: 12px;
|
|
1046
|
+
margin-bottom: 0;
|
|
1047
|
+
min-height: 28px;
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
.fieldRow:last-child {
|
|
1051
|
+
margin-bottom: 0;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
.fieldLabel {
|
|
1055
|
+
color: var(--castle-inspector-text);
|
|
1056
|
+
font-size: 14px;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
/* Instance override: purple label + input border, plus a "Default: X [Reset]"
|
|
1060
|
+
sub-line rendered below the control (see FieldRow). */
|
|
1061
|
+
.fieldLabelOverridden {
|
|
1062
|
+
color: var(--castle-override);
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
.fieldRowOverridden .input,
|
|
1066
|
+
.fieldRowOverridden .select,
|
|
1067
|
+
.fieldRowOverridden .colorInput {
|
|
1068
|
+
border-color: var(--castle-override-border);
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
.fieldOverride {
|
|
1072
|
+
padding-bottom: 12px;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
.fieldOverride .fieldRow {
|
|
1076
|
+
padding-bottom: 4px;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
.fieldDefault {
|
|
1080
|
+
display: grid;
|
|
1081
|
+
grid-template-columns: minmax(82px, 0.5fr) minmax(0, 1fr);
|
|
1082
|
+
gap: 12px;
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1085
|
+
.fieldDefaultInner {
|
|
1086
|
+
grid-column: 2;
|
|
1087
|
+
display: flex;
|
|
1088
|
+
align-items: center;
|
|
1089
|
+
gap: 8px;
|
|
1090
|
+
min-width: 0;
|
|
1091
|
+
font-size: 12px;
|
|
1092
|
+
color: var(--castle-inspector-muted);
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
.fieldDefaultInner > span {
|
|
1096
|
+
min-width: 0;
|
|
1097
|
+
overflow: hidden;
|
|
1098
|
+
text-overflow: ellipsis;
|
|
1099
|
+
white-space: nowrap;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
.fieldResetBtn {
|
|
1103
|
+
margin-left: auto;
|
|
1104
|
+
border: 0;
|
|
1105
|
+
padding: 0;
|
|
1106
|
+
background: transparent;
|
|
1107
|
+
color: var(--castle-override);
|
|
1108
|
+
font-size: 12px;
|
|
1109
|
+
cursor: pointer;
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
.fieldResetBtn:hover {
|
|
1113
|
+
color: var(--castle-inspector-text);
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
.input,
|
|
1117
|
+
.select,
|
|
1118
|
+
.textarea {
|
|
1119
|
+
width: 100%;
|
|
1120
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1121
|
+
border-radius: var(--castle-radius);
|
|
1122
|
+
background: var(--castle-inspector-input-bg);
|
|
1123
|
+
color: var(--castle-inspector-text);
|
|
1124
|
+
padding: 5px 8px;
|
|
1125
|
+
outline: 0;
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
.select {
|
|
1129
|
+
appearance: none;
|
|
1130
|
+
-webkit-appearance: none;
|
|
1131
|
+
padding-right: 26px;
|
|
1132
|
+
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");
|
|
1133
|
+
background-repeat: no-repeat;
|
|
1134
|
+
background-position: right 8px center;
|
|
1135
|
+
text-overflow: ellipsis;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
.numberField {
|
|
1139
|
+
position: relative;
|
|
1140
|
+
width: 100%;
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
.numberInput {
|
|
1144
|
+
padding-right: 22px;
|
|
1145
|
+
appearance: textfield;
|
|
1146
|
+
-moz-appearance: textfield;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
.numberInput::-webkit-inner-spin-button,
|
|
1150
|
+
.numberInput::-webkit-outer-spin-button {
|
|
1151
|
+
-webkit-appearance: none;
|
|
1152
|
+
appearance: none;
|
|
1153
|
+
margin: 0;
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
.numberSteppers {
|
|
1157
|
+
position: absolute;
|
|
1158
|
+
top: 1px;
|
|
1159
|
+
right: 1px;
|
|
1160
|
+
bottom: 1px;
|
|
1161
|
+
width: 18px;
|
|
1162
|
+
display: flex;
|
|
1163
|
+
flex-direction: column;
|
|
1164
|
+
border-left: 1px solid var(--castle-inspector-divider);
|
|
1165
|
+
opacity: 0;
|
|
1166
|
+
pointer-events: none;
|
|
1167
|
+
transition: opacity 0.1s;
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
.numberField:hover .numberSteppers,
|
|
1171
|
+
.numberField:focus-within .numberSteppers {
|
|
1172
|
+
opacity: 1;
|
|
1173
|
+
pointer-events: auto;
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
.numberStepper {
|
|
1177
|
+
flex: 1;
|
|
1178
|
+
display: flex;
|
|
1179
|
+
align-items: center;
|
|
1180
|
+
justify-content: center;
|
|
1181
|
+
border: 0;
|
|
1182
|
+
padding: 0;
|
|
1183
|
+
background: transparent;
|
|
1184
|
+
color: var(--castle-inspector-muted);
|
|
1185
|
+
cursor: pointer;
|
|
1186
|
+
font-size: 14px;
|
|
1187
|
+
line-height: 1;
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
.numberStepper:first-child {
|
|
1191
|
+
border-bottom: 1px solid var(--castle-inspector-divider);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
.numberStepper:hover {
|
|
1195
|
+
background: var(--castle-inspector-input-bg);
|
|
1196
|
+
color: var(--castle-inspector-text);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
.numberStepper:disabled {
|
|
1200
|
+
opacity: 0.3;
|
|
1201
|
+
cursor: default;
|
|
1202
|
+
background: transparent;
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
.colorInput {
|
|
1206
|
+
width: 100%;
|
|
1207
|
+
height: 28px;
|
|
1208
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1209
|
+
border-radius: var(--castle-radius);
|
|
1210
|
+
background: var(--castle-inspector-input-bg);
|
|
1211
|
+
padding: 2px;
|
|
1212
|
+
outline: 0;
|
|
1213
|
+
cursor: pointer;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
.toggle {
|
|
1217
|
+
width: 44px;
|
|
1218
|
+
height: 24px;
|
|
1219
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1220
|
+
border-radius: 999px;
|
|
1221
|
+
background: var(--castle-inspector-input-bg);
|
|
1222
|
+
padding: 2px;
|
|
1223
|
+
cursor: pointer;
|
|
1224
|
+
display: flex;
|
|
1225
|
+
align-items: center;
|
|
1226
|
+
justify-content: flex-start;
|
|
1227
|
+
box-shadow: none;
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
.toggleOn {
|
|
1231
|
+
background: var(--castle-black);
|
|
1232
|
+
justify-content: flex-end;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
.toggleKnob {
|
|
1236
|
+
width: 18px;
|
|
1237
|
+
height: 18px;
|
|
1238
|
+
border-radius: 999px;
|
|
1239
|
+
background: var(--castle-inspector-muted);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
.toggleOn .toggleKnob {
|
|
1243
|
+
background: var(--castle-text);
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
.textarea {
|
|
1247
|
+
min-height: 0;
|
|
1248
|
+
resize: none;
|
|
1249
|
+
font-family: var(--castle-font-mono);
|
|
1250
|
+
font-size: 14px;
|
|
1251
|
+
line-height: 1.45;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
/* Shared chrome for the inspector "Button" and every square icon button: a 1px
|
|
1255
|
+
border, sunken fill, text-colored glyph, and a subtle drop line. */
|
|
1256
|
+
.button,
|
|
1257
|
+
.iconButton {
|
|
1258
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1259
|
+
border-radius: var(--castle-radius);
|
|
1260
|
+
background: var(--castle-inspector-button-bg);
|
|
1261
|
+
color: var(--castle-inspector-text);
|
|
1262
|
+
cursor: pointer;
|
|
1263
|
+
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
|
|
1264
|
+
}
|
|
1265
|
+
|
|
1266
|
+
.button {
|
|
1267
|
+
padding: 6px 10px;
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1270
|
+
/* The square icon button -- the single source of truth every other square icon
|
|
1271
|
+
button across the editor matches. Default/hover/active follow the pixel
|
|
1272
|
+
editor's eyedropper; the disabled dimming follows the undo button. Fixed
|
|
1273
|
+
28x28, never shrinks in a toolbar row, and centers a 14px glyph. */
|
|
1274
|
+
.iconButton {
|
|
1275
|
+
width: 28px;
|
|
1276
|
+
height: 28px;
|
|
1277
|
+
flex: 0 0 auto;
|
|
1278
|
+
padding: 0;
|
|
1279
|
+
display: inline-flex;
|
|
1280
|
+
align-items: center;
|
|
1281
|
+
justify-content: center;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
.iconButton svg {
|
|
1285
|
+
width: 14px;
|
|
1286
|
+
height: 14px;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
.button:hover,
|
|
1290
|
+
.iconButton:hover {
|
|
1291
|
+
background: var(--castle-inspector-input-bg);
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
.buttonDanger {
|
|
1295
|
+
color: var(--castle-danger);
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
.button:disabled,
|
|
1299
|
+
.iconButton:disabled {
|
|
1300
|
+
opacity: 0.35;
|
|
1301
|
+
cursor: default;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
.actorList {
|
|
1305
|
+
display: grid;
|
|
1306
|
+
gap: 4px;
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
.actorRow {
|
|
1310
|
+
width: 100%;
|
|
1311
|
+
border: 1px solid transparent;
|
|
1312
|
+
background: transparent;
|
|
1313
|
+
color: var(--castle-inspector-text);
|
|
1314
|
+
border-radius: var(--castle-radius);
|
|
1315
|
+
padding: 7px 8px;
|
|
1316
|
+
text-align: left;
|
|
1317
|
+
cursor: pointer;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
.actorRowSelected {
|
|
1321
|
+
background: var(--castle-black);
|
|
1322
|
+
border-color: var(--castle-black);
|
|
1323
|
+
color: var(--castle-text);
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
.drawingEditor,
|
|
1327
|
+
.codeEditor {
|
|
1328
|
+
flex: 1;
|
|
1329
|
+
min-width: 0;
|
|
1330
|
+
min-height: 0;
|
|
1331
|
+
display: grid;
|
|
1332
|
+
grid-template-columns: minmax(320px, 1fr) 280px;
|
|
1333
|
+
background: var(--castle-workspace-bg);
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
.drawingEditor {
|
|
1337
|
+
grid-template-columns: minmax(320px, 1fr) minmax(50px, 250px);
|
|
1338
|
+
grid-template-rows: minmax(0, 1fr);
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
.drawingEditor > .pxArtInspector {
|
|
1342
|
+
grid-column: 2;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
.artboardToolColumn,
|
|
1346
|
+
.paintColumn {
|
|
1347
|
+
flex: 0 0 50px;
|
|
1348
|
+
display: flex;
|
|
1349
|
+
align-items: flex-start;
|
|
1350
|
+
justify-content: center;
|
|
1351
|
+
height: 100%;
|
|
1352
|
+
padding: 8px;
|
|
1353
|
+
box-sizing: border-box;
|
|
1354
|
+
background: var(--castle-workspace-bg);
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
.paintColumn {
|
|
1358
|
+
display: none;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
.drawingToolColumn {
|
|
1362
|
+
display: flex;
|
|
1363
|
+
align-items: flex-start;
|
|
1364
|
+
justify-content: center;
|
|
1365
|
+
width: 50px;
|
|
1366
|
+
min-width: 0;
|
|
1367
|
+
min-height: 0;
|
|
1368
|
+
height: 100%;
|
|
1369
|
+
padding: 8px;
|
|
1370
|
+
box-sizing: border-box;
|
|
1371
|
+
background: var(--castle-workspace-bg);
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
.drawingCanvasWrap {
|
|
1375
|
+
flex: 1 1 0;
|
|
1376
|
+
min-width: 0;
|
|
1377
|
+
min-height: 0;
|
|
1378
|
+
display: flex;
|
|
1379
|
+
align-items: center;
|
|
1380
|
+
justify-content: center;
|
|
1381
|
+
padding: 16px 24px;
|
|
1382
|
+
overflow: hidden;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
.artboardStack {
|
|
1386
|
+
display: flex;
|
|
1387
|
+
flex-direction: column;
|
|
1388
|
+
align-items: center;
|
|
1389
|
+
gap: 10px;
|
|
1390
|
+
min-width: 0;
|
|
1391
|
+
max-width: 100%;
|
|
1392
|
+
max-height: 100%;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
.canvasTopStack {
|
|
1396
|
+
display: flex;
|
|
1397
|
+
flex-direction: column;
|
|
1398
|
+
gap: 6px;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
.canvasTopBar {
|
|
1402
|
+
display: flex;
|
|
1403
|
+
align-items: center;
|
|
1404
|
+
gap: 16px;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
.canvasSizeBar {
|
|
1408
|
+
display: flex;
|
|
1409
|
+
align-items: center;
|
|
1410
|
+
gap: 6px;
|
|
1411
|
+
flex: 0 0 auto;
|
|
1412
|
+
font-size: 12px;
|
|
1413
|
+
color: var(--castle-inspector-muted);
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
.cornerRadiusBar {
|
|
1417
|
+
display: flex;
|
|
1418
|
+
align-items: center;
|
|
1419
|
+
gap: 6px;
|
|
1420
|
+
flex: 0 0 auto;
|
|
1421
|
+
font-size: 12px;
|
|
1422
|
+
color: var(--castle-inspector-muted);
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
/* Corner-radius segmented control (0 / ¼ / ½) — same bordered-row-of-
|
|
1426
|
+
buttons pattern as .drawingShapeModeRow, sized for short text labels
|
|
1427
|
+
instead of square glyph buttons. */
|
|
1428
|
+
.cornerRadiusSegments {
|
|
1429
|
+
display: flex;
|
|
1430
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1431
|
+
border-radius: var(--castle-radius);
|
|
1432
|
+
overflow: hidden;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
.cornerRadiusSegments > * + * {
|
|
1436
|
+
border-left: 1px solid var(--castle-inspector-border);
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
.cornerRadiusSegment {
|
|
1440
|
+
min-width: 28px;
|
|
1441
|
+
padding: 3px 8px;
|
|
1442
|
+
border: 0;
|
|
1443
|
+
background: var(--castle-inspector-button-bg);
|
|
1444
|
+
color: var(--castle-inspector-text);
|
|
1445
|
+
cursor: pointer;
|
|
1446
|
+
font-size: 12px;
|
|
1447
|
+
font-variant-numeric: tabular-nums;
|
|
1448
|
+
line-height: 1.35;
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1451
|
+
.cornerRadiusSegment:hover {
|
|
1452
|
+
background: var(--castle-inspector-input-bg);
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
/* Compound selector (not a bare `.cornerRadiusSegmentOn`) for the same reason
|
|
1456
|
+
documented above `.drawingToolButton.drawingToolSelected`: it must beat
|
|
1457
|
+
`.cornerRadiusSegment:hover` on specificity no matter source order. */
|
|
1458
|
+
.cornerRadiusSegment.cornerRadiusSegmentOn,
|
|
1459
|
+
.cornerRadiusSegment.cornerRadiusSegmentOn:hover {
|
|
1460
|
+
background: var(--castle-selected);
|
|
1461
|
+
color: var(--castle-selected-ink);
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
.canvasSizeSep {
|
|
1465
|
+
color: var(--castle-inspector-muted);
|
|
1466
|
+
user-select: none;
|
|
1467
|
+
}
|
|
1468
|
+
|
|
1469
|
+
.canvasSizeSelect {
|
|
1470
|
+
width: 52px;
|
|
1471
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1472
|
+
border-radius: var(--castle-radius);
|
|
1473
|
+
background: var(--castle-inspector-input-bg);
|
|
1474
|
+
color: var(--castle-inspector-text);
|
|
1475
|
+
padding: 3px 22px 3px 6px;
|
|
1476
|
+
font-size: 12px;
|
|
1477
|
+
text-align: center;
|
|
1478
|
+
appearance: none;
|
|
1479
|
+
-webkit-appearance: none;
|
|
1480
|
+
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");
|
|
1481
|
+
background-repeat: no-repeat;
|
|
1482
|
+
background-position: right 6px center;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
.pxArtInspector {
|
|
1486
|
+
min-width: 0;
|
|
1487
|
+
border-left: 1px solid var(--castle-inspector-divider);
|
|
1488
|
+
background: var(--castle-workspace-bg);
|
|
1489
|
+
color: var(--castle-inspector-text);
|
|
1490
|
+
font-size: 14px;
|
|
1491
|
+
overflow: hidden;
|
|
1492
|
+
display: flex;
|
|
1493
|
+
flex-direction: column;
|
|
1494
|
+
}
|
|
1495
|
+
|
|
1496
|
+
.paintStrip {
|
|
1497
|
+
display: flex;
|
|
1498
|
+
flex-direction: column;
|
|
1499
|
+
width: 34px;
|
|
1500
|
+
flex: 0 0 auto;
|
|
1501
|
+
gap: 8px;
|
|
1502
|
+
}
|
|
1503
|
+
|
|
1504
|
+
/* Each control group (color, size, shape type, mode toggle) is its own boxed
|
|
1505
|
+
section, separated by the strip's gap. Controls stacked inside a section keep
|
|
1506
|
+
1px dividers so a multi-button group still reads as one segmented unit. */
|
|
1507
|
+
.paintStripSection {
|
|
1508
|
+
display: flex;
|
|
1509
|
+
flex-direction: column;
|
|
1510
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1511
|
+
border-radius: var(--castle-radius);
|
|
1512
|
+
overflow: hidden;
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
.paintStripSection > * + * {
|
|
1516
|
+
border-top: 1px solid var(--castle-inspector-border);
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
.paintStripColor {
|
|
1520
|
+
width: 34px;
|
|
1521
|
+
height: 34px;
|
|
1522
|
+
padding: 0;
|
|
1523
|
+
border: 0;
|
|
1524
|
+
border-radius: 0;
|
|
1525
|
+
cursor: pointer;
|
|
1526
|
+
flex: 0 0 auto;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
.paintStripSlider {
|
|
1530
|
+
height: 100px;
|
|
1531
|
+
display: flex;
|
|
1532
|
+
align-items: center;
|
|
1533
|
+
justify-content: center;
|
|
1534
|
+
padding: 8px 0;
|
|
1535
|
+
flex: 0 0 auto;
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
.paintStripModeButton {
|
|
1539
|
+
width: 34px;
|
|
1540
|
+
height: 34px;
|
|
1541
|
+
padding: 0;
|
|
1542
|
+
display: inline-flex;
|
|
1543
|
+
align-items: center;
|
|
1544
|
+
justify-content: center;
|
|
1545
|
+
border: 0;
|
|
1546
|
+
border-radius: 0;
|
|
1547
|
+
background: var(--castle-inspector-button-bg);
|
|
1548
|
+
color: var(--castle-inspector-text);
|
|
1549
|
+
cursor: pointer;
|
|
1550
|
+
font-size: 14px;
|
|
1551
|
+
line-height: 1;
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
.paintStripModeButton svg {
|
|
1555
|
+
width: 1em;
|
|
1556
|
+
height: 1em;
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1559
|
+
.paintStripModeButton:hover {
|
|
1560
|
+
background: var(--castle-inspector-input-bg);
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
.paintStripModeButton:disabled {
|
|
1564
|
+
opacity: 0.35;
|
|
1565
|
+
cursor: default;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
.drawingSizeSliderVertical {
|
|
1569
|
+
width: 88px;
|
|
1570
|
+
height: 14px;
|
|
1571
|
+
margin: 0;
|
|
1572
|
+
cursor: pointer;
|
|
1573
|
+
transform: rotate(-90deg);
|
|
1574
|
+
appearance: none;
|
|
1575
|
+
-webkit-appearance: none;
|
|
1576
|
+
background: transparent;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
.drawingSizeSliderVertical:disabled {
|
|
1580
|
+
cursor: default;
|
|
1581
|
+
opacity: 0.45;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
.drawingSizeSliderVertical::-webkit-slider-runnable-track {
|
|
1585
|
+
height: 4px;
|
|
1586
|
+
border-radius: 999px;
|
|
1587
|
+
background: #4a4a4a;
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
.drawingSizeSliderVertical::-webkit-slider-thumb {
|
|
1591
|
+
appearance: none;
|
|
1592
|
+
-webkit-appearance: none;
|
|
1593
|
+
width: 14px;
|
|
1594
|
+
height: 14px;
|
|
1595
|
+
margin-top: -5px;
|
|
1596
|
+
border-radius: 999px;
|
|
1597
|
+
border: 1px solid #d8d8d8;
|
|
1598
|
+
background: #fff;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
.drawingSizeSliderVertical::-moz-range-track {
|
|
1602
|
+
height: 4px;
|
|
1603
|
+
border-radius: 999px;
|
|
1604
|
+
background: #4a4a4a;
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
.drawingSizeSliderVertical::-moz-range-thumb {
|
|
1608
|
+
width: 14px;
|
|
1609
|
+
height: 14px;
|
|
1610
|
+
border-radius: 999px;
|
|
1611
|
+
border: 1px solid #d8d8d8;
|
|
1612
|
+
background: #fff;
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
.palettePopover {
|
|
1616
|
+
position: fixed;
|
|
1617
|
+
z-index: 200;
|
|
1618
|
+
width: min(280px, calc(100vw - 16px));
|
|
1619
|
+
max-height: min(420px, calc(100vh - 16px));
|
|
1620
|
+
overflow: auto;
|
|
1621
|
+
padding: 12px 14px 14px;
|
|
1622
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1623
|
+
border-radius: var(--castle-radius);
|
|
1624
|
+
background: var(--castle-workspace-bg);
|
|
1625
|
+
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
.palettePopoverHeader {
|
|
1629
|
+
display: flex;
|
|
1630
|
+
align-items: center;
|
|
1631
|
+
justify-content: space-between;
|
|
1632
|
+
gap: 10px;
|
|
1633
|
+
margin-bottom: 10px;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
.palettePopoverTitle {
|
|
1637
|
+
font-size: 14px;
|
|
1638
|
+
font-weight: 650;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
.drawingArtboard {
|
|
1642
|
+
min-width: 0;
|
|
1643
|
+
min-height: 0;
|
|
1644
|
+
display: flex;
|
|
1645
|
+
align-items: center;
|
|
1646
|
+
justify-content: center;
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
/* Stacks the native artboard canvas, the smooth-preview canvas, and the
|
|
1650
|
+
display-resolution overlay so the marching-ants outline renders crisp
|
|
1651
|
+
instead of sub-pixel on the upscaled art. The checkerboard "transparency"
|
|
1652
|
+
background lives on the FRAME (not the main canvas) so it doesn't paint
|
|
1653
|
+
over the smooth-preview canvas underneath in "smooth" render mode. */
|
|
1654
|
+
.drawingArtboardFrame {
|
|
1655
|
+
position: relative;
|
|
1656
|
+
flex: 0 0 auto;
|
|
1657
|
+
/* Own stacking context, so the negative-z .drawingSmooth canvas paints just
|
|
1658
|
+
above THIS element's checkerboard background instead of sinking below it
|
|
1659
|
+
(without isolation, negative z-index children paint before all in-flow
|
|
1660
|
+
descendant backgrounds of the outer stacking context — checkerboard
|
|
1661
|
+
included — hiding the smooth render entirely). */
|
|
1662
|
+
isolation: isolate;
|
|
1663
|
+
background:
|
|
1664
|
+
linear-gradient(45deg, #1a1a1a 25%, transparent 25%),
|
|
1665
|
+
linear-gradient(-45deg, #1a1a1a 25%, transparent 25%),
|
|
1666
|
+
linear-gradient(45deg, transparent 75%, #1a1a1a 75%),
|
|
1667
|
+
linear-gradient(-45deg, transparent 75%, #1a1a1a 75%);
|
|
1668
|
+
background-color: #121212;
|
|
1669
|
+
background-size: 16px 16px;
|
|
1670
|
+
background-position:
|
|
1671
|
+
0 0,
|
|
1672
|
+
0 8px,
|
|
1673
|
+
8px -8px,
|
|
1674
|
+
-8px 0;
|
|
1675
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
.drawingOverlay {
|
|
1679
|
+
position: absolute;
|
|
1680
|
+
inset: 0;
|
|
1681
|
+
width: 100%;
|
|
1682
|
+
height: 100%;
|
|
1683
|
+
pointer-events: none;
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
/* Behind the main canvas (negative z-index paints before static content in
|
|
1687
|
+
the same containing block) — holds the corner-rounded render for "smooth"
|
|
1688
|
+
sprites while the main canvas above it stays transparent except for tool
|
|
1689
|
+
overlays, so editing interactions are unaffected. Empty/0-sized in "pixel"
|
|
1690
|
+
mode. */
|
|
1691
|
+
.drawingSmooth {
|
|
1692
|
+
position: absolute;
|
|
1693
|
+
inset: 0;
|
|
1694
|
+
width: 100%;
|
|
1695
|
+
height: 100%;
|
|
1696
|
+
pointer-events: none;
|
|
1697
|
+
z-index: -1;
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
.drawingCanvas {
|
|
1701
|
+
image-rendering: pixelated;
|
|
1702
|
+
position: absolute;
|
|
1703
|
+
inset: 0;
|
|
1704
|
+
width: 100%;
|
|
1705
|
+
height: 100%;
|
|
1706
|
+
flex: 0 0 auto;
|
|
1707
|
+
/* tabIndex=-1 (for keyboard-focus capture on pointer-down) would otherwise
|
|
1708
|
+
draw a focus ring around the artboard; it's focused programmatically, never
|
|
1709
|
+
via keyboard, so suppressing the outline is safe. */
|
|
1710
|
+
outline: none;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
.palette {
|
|
1714
|
+
display: grid;
|
|
1715
|
+
grid-template-columns: repeat(12, minmax(0, 1fr));
|
|
1716
|
+
gap: 4px;
|
|
1717
|
+
padding-bottom: 12px;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
.swatch {
|
|
1721
|
+
aspect-ratio: 1;
|
|
1722
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1723
|
+
border-radius: var(--castle-radius);
|
|
1724
|
+
cursor: pointer;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
/* Selected paint color. A double ring — light on the inside, dark on the
|
|
1728
|
+
outside — so the selection stays legible over ANY of the 64 swatch colors
|
|
1729
|
+
(a single-color border can vanish against a similar swatch). */
|
|
1730
|
+
.swatchSelected {
|
|
1731
|
+
border-color: transparent;
|
|
1732
|
+
box-shadow:
|
|
1733
|
+
inset 0 0 0 2px #fff,
|
|
1734
|
+
0 0 0 2px var(--castle-black);
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1737
|
+
.drawingToolStrip {
|
|
1738
|
+
display: flex;
|
|
1739
|
+
flex-direction: column;
|
|
1740
|
+
width: 34px;
|
|
1741
|
+
flex: 0 0 auto;
|
|
1742
|
+
max-height: 100%;
|
|
1743
|
+
overflow: auto;
|
|
1744
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1745
|
+
border-radius: var(--castle-radius);
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
.drawingToolStrip > * + * {
|
|
1749
|
+
border-top: 1px solid var(--castle-inspector-border);
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1752
|
+
.drawingToolsPanel {
|
|
1753
|
+
overflow: hidden;
|
|
1754
|
+
display: flex;
|
|
1755
|
+
flex-direction: column;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
.drawingToolsPanelBody {
|
|
1759
|
+
flex: 1 1 0;
|
|
1760
|
+
min-height: 0;
|
|
1761
|
+
display: grid;
|
|
1762
|
+
grid-template-columns: 58px minmax(0, 1fr);
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
.drawingSettingsColumn {
|
|
1766
|
+
min-width: 0;
|
|
1767
|
+
height: 100%;
|
|
1768
|
+
overflow: auto;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
.drawingToolButton,
|
|
1772
|
+
.drawingSizeButton {
|
|
1773
|
+
background: var(--castle-inspector-button-bg);
|
|
1774
|
+
color: var(--castle-inspector-text);
|
|
1775
|
+
cursor: pointer;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
.drawingToolButton {
|
|
1779
|
+
width: 34px;
|
|
1780
|
+
height: 34px;
|
|
1781
|
+
padding: 0;
|
|
1782
|
+
display: inline-flex;
|
|
1783
|
+
align-items: center;
|
|
1784
|
+
justify-content: center;
|
|
1785
|
+
font-size: 14px;
|
|
1786
|
+
line-height: 1;
|
|
1787
|
+
border: 0;
|
|
1788
|
+
border-radius: 0;
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
.drawingToolButton svg {
|
|
1792
|
+
width: 1em;
|
|
1793
|
+
height: 1em;
|
|
1794
|
+
}
|
|
1795
|
+
|
|
1796
|
+
.drawingToolButton:hover {
|
|
1797
|
+
background: var(--castle-inspector-input-bg);
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
.drawingToolButton:disabled {
|
|
1801
|
+
opacity: 0.35;
|
|
1802
|
+
cursor: default;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
/* Active / selected square icon button -- the eyedropper reference: a light
|
|
1806
|
+
fill with a dark glyph. The single selected/engaged look shared by the
|
|
1807
|
+
IconButton component (`active`), the onion-skin toggle, and the pixel
|
|
1808
|
+
editors' tool strip.
|
|
1809
|
+
|
|
1810
|
+
These use COMPOUND selectors (`.button.buttonActive`,
|
|
1811
|
+
`.drawingToolButton.drawingToolSelected`) on purpose: every active button
|
|
1812
|
+
already carries both classes, so the (0,2,0)/(0,3,0) specificity beats the
|
|
1813
|
+
equal-specificity base + size rules (`.button`/`.iconButton`,
|
|
1814
|
+
`.drawingToolButton`) NO MATTER the source order. A bare `.buttonActive`
|
|
1815
|
+
ties those base rules on specificity and only wins if it happens to appear
|
|
1816
|
+
later in the file -- which Vite HMR can reshuffle when this module is edited,
|
|
1817
|
+
silently dropping the active fill. The compound selector removes that
|
|
1818
|
+
fragility. */
|
|
1819
|
+
.button.buttonActive,
|
|
1820
|
+
.drawingToolButton.drawingToolSelected,
|
|
1821
|
+
.paintStripModeButton.drawingToolSelected {
|
|
1822
|
+
background: var(--castle-selected);
|
|
1823
|
+
border-color: var(--castle-selected);
|
|
1824
|
+
color: var(--castle-selected-ink);
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
.button.buttonActive:hover,
|
|
1828
|
+
.drawingToolButton.drawingToolSelected:hover,
|
|
1829
|
+
.paintStripModeButton.drawingToolSelected:hover {
|
|
1830
|
+
background: var(--castle-selected);
|
|
1831
|
+
border-color: var(--castle-selected);
|
|
1832
|
+
color: var(--castle-selected-ink);
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
/* Horizontal segmented row of shape sub-mode buttons in the wide-layout Tool
|
|
1836
|
+
Settings panel. Reuses .drawingToolButton glyph buttons with shared borders. */
|
|
1837
|
+
.drawingShapeModeRow {
|
|
1838
|
+
display: flex;
|
|
1839
|
+
width: max-content;
|
|
1840
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1841
|
+
border-radius: var(--castle-radius);
|
|
1842
|
+
overflow: hidden;
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
.drawingShapeModeRow > * + * {
|
|
1846
|
+
border-left: 1px solid var(--castle-inspector-border);
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
.drawingToolHint {
|
|
1850
|
+
color: var(--castle-inspector-muted);
|
|
1851
|
+
font-size: 14px;
|
|
1852
|
+
line-height: 1.35;
|
|
1853
|
+
padding-bottom: 8px;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
.drawingToolSettings {
|
|
1857
|
+
padding-bottom: 8px;
|
|
1858
|
+
}
|
|
1859
|
+
|
|
1860
|
+
.drawingSizePicker {
|
|
1861
|
+
display: grid;
|
|
1862
|
+
gap: 8px;
|
|
1863
|
+
padding-bottom: 8px;
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
.drawingSizeLabel {
|
|
1867
|
+
display: flex;
|
|
1868
|
+
align-items: baseline;
|
|
1869
|
+
justify-content: space-between;
|
|
1870
|
+
gap: 10px;
|
|
1871
|
+
color: var(--castle-inspector-muted);
|
|
1872
|
+
font-size: 14px;
|
|
1873
|
+
line-height: 1.35;
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
.drawingSizeLabel span:last-child {
|
|
1877
|
+
color: var(--castle-inspector-text);
|
|
1878
|
+
font-variant-numeric: tabular-nums;
|
|
1879
|
+
}
|
|
1880
|
+
|
|
1881
|
+
.drawingSizeControlRow {
|
|
1882
|
+
display: grid;
|
|
1883
|
+
grid-template-columns: minmax(0, 1fr);
|
|
1884
|
+
align-items: center;
|
|
1885
|
+
gap: 10px;
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
.drawingSizeSlider {
|
|
1889
|
+
width: 100%;
|
|
1890
|
+
cursor: pointer;
|
|
1891
|
+
appearance: none;
|
|
1892
|
+
-webkit-appearance: none;
|
|
1893
|
+
background: transparent;
|
|
1894
|
+
}
|
|
1895
|
+
|
|
1896
|
+
.drawingSizeSlider:disabled {
|
|
1897
|
+
cursor: default;
|
|
1898
|
+
opacity: 0.45;
|
|
1899
|
+
}
|
|
1900
|
+
|
|
1901
|
+
.drawingSizeSlider::-webkit-slider-runnable-track {
|
|
1902
|
+
height: 4px;
|
|
1903
|
+
border-radius: 999px;
|
|
1904
|
+
background: #4a4a4a;
|
|
1905
|
+
}
|
|
1906
|
+
|
|
1907
|
+
.drawingSizeSlider::-webkit-slider-thumb {
|
|
1908
|
+
appearance: none;
|
|
1909
|
+
-webkit-appearance: none;
|
|
1910
|
+
width: 14px;
|
|
1911
|
+
height: 14px;
|
|
1912
|
+
margin-top: -5px;
|
|
1913
|
+
border-radius: 999px;
|
|
1914
|
+
border: 1px solid #d8d8d8;
|
|
1915
|
+
background: #fff;
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
.drawingFillToggle {
|
|
1919
|
+
min-height: 28px;
|
|
1920
|
+
padding: 4px 9px;
|
|
1921
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1922
|
+
border-radius: var(--castle-radius);
|
|
1923
|
+
background: var(--castle-inspector-button-bg);
|
|
1924
|
+
color: var(--castle-inspector-text);
|
|
1925
|
+
cursor: pointer;
|
|
1926
|
+
font-size: 14px;
|
|
1927
|
+
}
|
|
1928
|
+
|
|
1929
|
+
.drawingFillToggleOn {
|
|
1930
|
+
background: var(--castle-selected);
|
|
1931
|
+
border-color: var(--castle-selected);
|
|
1932
|
+
color: var(--castle-selected-ink);
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
.drawingModeRow {
|
|
1936
|
+
display: flex;
|
|
1937
|
+
align-items: center;
|
|
1938
|
+
justify-content: space-between;
|
|
1939
|
+
gap: 12px;
|
|
1940
|
+
color: var(--castle-inspector-muted);
|
|
1941
|
+
font-size: 14px;
|
|
1942
|
+
line-height: 1.35;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
.drawingSwitch {
|
|
1946
|
+
position: relative;
|
|
1947
|
+
width: 34px;
|
|
1948
|
+
height: 20px;
|
|
1949
|
+
padding: 0;
|
|
1950
|
+
border: 1px solid var(--castle-inspector-border);
|
|
1951
|
+
border-radius: 999px;
|
|
1952
|
+
background: #343434;
|
|
1953
|
+
cursor: pointer;
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
.drawingSwitchOn {
|
|
1957
|
+
border-color: var(--castle-selected);
|
|
1958
|
+
background: var(--castle-selected);
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
.drawingSwitchKnob {
|
|
1962
|
+
position: absolute;
|
|
1963
|
+
top: 2px;
|
|
1964
|
+
left: 2px;
|
|
1965
|
+
width: 14px;
|
|
1966
|
+
height: 14px;
|
|
1967
|
+
border-radius: 999px;
|
|
1968
|
+
background: #fff;
|
|
1969
|
+
box-shadow: 0 1px 2px rgb(0 0 0 / 0.25);
|
|
1970
|
+
transition: transform 120ms ease;
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
.drawingSwitchOn .drawingSwitchKnob {
|
|
1974
|
+
transform: translateX(14px);
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
.drawingSizeSlider::-moz-range-track {
|
|
1978
|
+
height: 4px;
|
|
1979
|
+
border-radius: 999px;
|
|
1980
|
+
background: #4a4a4a;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
.drawingSizeSlider::-moz-range-thumb {
|
|
1984
|
+
width: 14px;
|
|
1985
|
+
height: 14px;
|
|
1986
|
+
border-radius: 999px;
|
|
1987
|
+
border: 1px solid #d8d8d8;
|
|
1988
|
+
background: #fff;
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
.codeEditor {
|
|
1992
|
+
grid-template-columns: 1fr;
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
.codeMirrorHost {
|
|
1996
|
+
min-width: 0;
|
|
1997
|
+
min-height: 0;
|
|
1998
|
+
height: 100%;
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
/* mobileOnly comes AFTER element-specific rules so `display: none` wins on desktop. */
|
|
2002
|
+
.mobileOnly,
|
|
2003
|
+
.sheetBackdrop,
|
|
2004
|
+
.sheetGrab,
|
|
2005
|
+
.sheetGrabBar {
|
|
2006
|
+
display: none;
|
|
2007
|
+
}
|
|
2008
|
+
|
|
2009
|
+
@media (max-width: 600px) {
|
|
2010
|
+
:root {
|
|
2011
|
+
/* Fallback for the file-browser sheet and the inspector's initial slide-in;
|
|
2012
|
+
the inspector's live height is driven by the hook's --sheet-h (see below). */
|
|
2013
|
+
--sheet-high-height: 62vh;
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
/* `display: contents` makes wrapper spans transparent in layout so their
|
|
2017
|
+
children become direct flex items of the parent (gap applies, etc). */
|
|
2018
|
+
.mobileOnly {
|
|
2019
|
+
display: contents;
|
|
2020
|
+
}
|
|
2021
|
+
|
|
2022
|
+
/* Backdrop sits below the header so the files toggle stays interactive. */
|
|
2023
|
+
.sheetBackdrop {
|
|
2024
|
+
display: block;
|
|
2025
|
+
position: fixed;
|
|
2026
|
+
top: 52px;
|
|
2027
|
+
left: 0;
|
|
2028
|
+
right: 0;
|
|
2029
|
+
bottom: 0;
|
|
2030
|
+
z-index: 30;
|
|
2031
|
+
background: transparent;
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
.appShell {
|
|
2035
|
+
grid-template-columns: 1fr;
|
|
2036
|
+
grid-template-rows: 1fr;
|
|
2037
|
+
position: relative;
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
.mainEditor {
|
|
2041
|
+
grid-column: 1;
|
|
2042
|
+
grid-row: 1;
|
|
2043
|
+
min-height: 0;
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
/* Header: title (left, compact) + centered icon group (right slot includes files button). */
|
|
2047
|
+
.editorHeader {
|
|
2048
|
+
height: 52px;
|
|
2049
|
+
flex: 0 0 52px;
|
|
2050
|
+
padding: 8px 10px;
|
|
2051
|
+
gap: 8px;
|
|
2052
|
+
justify-content: space-between;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
.editorHeaderLeft {
|
|
2056
|
+
flex: 1;
|
|
2057
|
+
min-width: 0;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
.editorHeaderRight {
|
|
2061
|
+
flex: 0 0 auto;
|
|
2062
|
+
justify-content: flex-end;
|
|
2063
|
+
gap: 14px;
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
.editorTitle {
|
|
2067
|
+
font-size: 14px;
|
|
2068
|
+
overflow: hidden;
|
|
2069
|
+
text-overflow: ellipsis;
|
|
2070
|
+
white-space: nowrap;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
.muted {
|
|
2074
|
+
overflow: hidden;
|
|
2075
|
+
text-overflow: ellipsis;
|
|
2076
|
+
white-space: nowrap;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
/* Scene hotbar row stays visible when compact (it holds drag-and-drop
|
|
2080
|
+
blueprints later). Drawing playback lives in the header instead. */
|
|
2081
|
+
.sceneWorkspace {
|
|
2082
|
+
grid-template-columns: 1fr;
|
|
2083
|
+
grid-template-rows: var(--castle-hotbar-row-full) minmax(0, 1fr);
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2086
|
+
.drawingEditor {
|
|
2087
|
+
grid-template-columns: 1fr;
|
|
2088
|
+
grid-template-rows: minmax(0, 1fr);
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
.stageWrap {
|
|
2092
|
+
grid-column: 1;
|
|
2093
|
+
grid-row: 2;
|
|
2094
|
+
align-items: flex-start;
|
|
2095
|
+
padding: 10px 12px 12px;
|
|
2096
|
+
background: var(--castle-stage-workspace-bg);
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
/* One-column layout: the card MUST keep a definite width. Its clip/canvas
|
|
2100
|
+
children are absolutely positioned (no intrinsic size), so a flex item with
|
|
2101
|
+
`width: auto` + `aspect-ratio` collapses to 0x0 -- the stage went blank and
|
|
2102
|
+
only the dark `.stageWrap` showed. Drive width from the viewport (capped by
|
|
2103
|
+
480px and by 62vh so the aspect-derived height always fits without
|
|
2104
|
+
`max-height` clamping and distorting the maze). */
|
|
2105
|
+
.stageCard {
|
|
2106
|
+
width: min(92vw, 480px, 62vh);
|
|
2107
|
+
max-width: 100%;
|
|
2108
|
+
max-height: 100%;
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
/* PxArt artboard: keep flanking tool/paint columns; fit hook drives canvas size. */
|
|
2112
|
+
.drawingCanvasWrap {
|
|
2113
|
+
align-items: center;
|
|
2114
|
+
padding: 10px 8px 12px;
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
.artboardToolColumn,
|
|
2118
|
+
.paintColumn {
|
|
2119
|
+
padding: 8px 4px;
|
|
2120
|
+
}
|
|
2121
|
+
|
|
2122
|
+
/* File-browser + inspector sheets share fixed-bottom positioning, height,
|
|
2123
|
+
transform/transition, and chrome. Per-sheet differences (z-index, side
|
|
2124
|
+
border, background, padding) follow in dedicated rules below. */
|
|
2125
|
+
.fileBrowser,
|
|
2126
|
+
.inspector {
|
|
2127
|
+
position: fixed;
|
|
2128
|
+
left: 0;
|
|
2129
|
+
right: 0;
|
|
2130
|
+
bottom: 0;
|
|
2131
|
+
width: 100%;
|
|
2132
|
+
height: var(--sheet-high-height);
|
|
2133
|
+
transform: translateY(100%);
|
|
2134
|
+
transition:
|
|
2135
|
+
transform 0.28s cubic-bezier(0.32, 0.72, 0, 1),
|
|
2136
|
+
height 0.28s cubic-bezier(0.32, 0.72, 0, 1);
|
|
2137
|
+
border-top: 1px solid var(--castle-inspector-divider);
|
|
2138
|
+
box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.18);
|
|
2139
|
+
overflow: hidden;
|
|
2140
|
+
display: flex;
|
|
2141
|
+
flex-direction: column;
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
/* File-browser sheet: hidden off-screen by default; slides up to high snap. */
|
|
2145
|
+
.fileBrowser {
|
|
2146
|
+
z-index: 50;
|
|
2147
|
+
border-right: 0;
|
|
2148
|
+
background: var(--castle-sheet-bg);
|
|
2149
|
+
}
|
|
2150
|
+
|
|
2151
|
+
.fileBrowser[data-sheet-snap='high'] {
|
|
2152
|
+
transform: translateY(0);
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
.fileTree {
|
|
2156
|
+
flex: 1 1 0;
|
|
2157
|
+
min-height: 0;
|
|
2158
|
+
overflow-y: auto;
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
/* Inspector sheet: hidden off-screen by default; slides up when open. */
|
|
2162
|
+
.inspector {
|
|
2163
|
+
z-index: 45;
|
|
2164
|
+
border-left: 0;
|
|
2165
|
+
background: var(--castle-workspace-bg);
|
|
2166
|
+
padding: 0;
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
/* Open inspector sheet: continuous height driven by the hook's live --sheet-h
|
|
2170
|
+
(falls back to the default expanded height). Drag the grab handle to resize
|
|
2171
|
+
freely; the hook picks the settle point on release. */
|
|
2172
|
+
.inspector[data-sheet-open='true'] {
|
|
2173
|
+
transform: translateY(0);
|
|
2174
|
+
height: var(--sheet-h, var(--sheet-high-height));
|
|
2175
|
+
}
|
|
2176
|
+
|
|
2177
|
+
/* While dragging, drop the transition so the sheet tracks the finger 1:1; the
|
|
2178
|
+
settle animation returns the moment this class is removed on release. */
|
|
2179
|
+
.inspector.sheetDragging {
|
|
2180
|
+
transition: none;
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
/* Shared sheet chrome -- grab bar pill. Always visible when sheet is visible. */
|
|
2184
|
+
.sheetGrab {
|
|
2185
|
+
display: flex;
|
|
2186
|
+
flex-direction: column;
|
|
2187
|
+
align-items: stretch;
|
|
2188
|
+
justify-content: center;
|
|
2189
|
+
flex: 0 0 auto;
|
|
2190
|
+
padding: 8px 14px 8px;
|
|
2191
|
+
cursor: grab;
|
|
2192
|
+
user-select: none;
|
|
2193
|
+
touch-action: none;
|
|
2194
|
+
background: var(--castle-sheet-bg);
|
|
2195
|
+
border-bottom: 1px solid var(--castle-inspector-divider);
|
|
2196
|
+
}
|
|
2197
|
+
|
|
2198
|
+
.inspector .sheetGrab {
|
|
2199
|
+
background: var(--castle-workspace-bg);
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
.sheetGrabBar {
|
|
2203
|
+
display: block;
|
|
2204
|
+
width: 36px;
|
|
2205
|
+
height: 4px;
|
|
2206
|
+
border-radius: 999px;
|
|
2207
|
+
background: var(--castle-inspector-divider);
|
|
2208
|
+
margin: 0 auto;
|
|
2209
|
+
flex: 0 0 4px;
|
|
2210
|
+
}
|
|
2211
|
+
|
|
2212
|
+
.sheetBody {
|
|
2213
|
+
flex: 1;
|
|
2214
|
+
min-height: 0;
|
|
2215
|
+
overflow: auto;
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
.inspectorBody {
|
|
2219
|
+
background: var(--castle-workspace-bg);
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
.codeInspectorInfo {
|
|
2223
|
+
display: grid;
|
|
2224
|
+
grid-template-columns: 80px 1fr;
|
|
2225
|
+
gap: 6px 12px;
|
|
2226
|
+
padding: 14px 16px;
|
|
2227
|
+
font-size: 14px;
|
|
2228
|
+
color: var(--castle-inspector-text);
|
|
2229
|
+
word-break: break-all;
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
/* Bare (panel) editor wrapper: fills the panel iframe; single column.
|
|
2234
|
+
Use 100% not 100vw/100vh — in a dock iframe vw/vh are the TOP-LEVEL
|
|
2235
|
+
viewport, so the editor "thinks" it is full-window-wide and container
|
|
2236
|
+
queries on .editorBody never flip to compact. */
|
|
2237
|
+
.panelBare {
|
|
2238
|
+
display: grid;
|
|
2239
|
+
grid-template-columns: 1fr;
|
|
2240
|
+
width: 100%;
|
|
2241
|
+
height: 100%;
|
|
2242
|
+
min-width: 0;
|
|
2243
|
+
min-height: 0;
|
|
2244
|
+
background: var(--castle-workspace-bg);
|
|
2245
|
+
}
|
|
2246
|
+
/* In a panel the scene editor's tools row must stay visible even below 860px --
|
|
2247
|
+
it normally moves into the mobile header, which bare mode removes. Restore the
|
|
2248
|
+
full-height tools row (--castle-hotbar-row-full, same as the desktop track) and
|
|
2249
|
+
put the stage back in row 2 (the narrow layout moves it up into row 1). The row
|
|
2250
|
+
must use the full height -- a shorter hardcoded track left the centered 46px
|
|
2251
|
+
hotbar buttons overhanging the stage, which clipped their bottoms.
|
|
2252
|
+
|
|
2253
|
+
The PxArt editor (.drawingEditor) is intentionally NOT included here: it has
|
|
2254
|
+
no docked tools row (its controls live in the header), and its left column
|
|
2255
|
+
(.editorLeft) is pinned to grid-row 1, so injecting a 48px first row collapsed
|
|
2256
|
+
the artboard to zero height across the 600-860px band. PxArt compact layout
|
|
2257
|
+
is driven by the @container editor (max-width: 620px) rule on .editorBody. */
|
|
2258
|
+
@media (max-width: 860px) {
|
|
2259
|
+
.panelBare .sceneWorkspace {
|
|
2260
|
+
grid-template-rows: var(--castle-hotbar-row-full) minmax(0, 1fr);
|
|
2261
|
+
}
|
|
2262
|
+
.panelBare .sceneTools {
|
|
2263
|
+
display: grid;
|
|
2264
|
+
}
|
|
2265
|
+
.panelBare .stageWrap {
|
|
2266
|
+
grid-row: 2;
|
|
2267
|
+
}
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
/* PxArt compact layout — MUST stay after .drawingToolsPanel / .paintColumn base
|
|
2271
|
+
rules so these container-query overrides win the cascade (same element carries
|
|
2272
|
+
pxArtInspector + drawingToolsPanel; a later bare .drawingToolsPanel{display:flex}
|
|
2273
|
+
was keeping the sidebar visible beside the paint strip). */
|
|
2274
|
+
@container editor (max-width: 620px) {
|
|
2275
|
+
.drawingEditor {
|
|
2276
|
+
grid-template-columns: 1fr;
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
.drawingEditor > .pxArtInspector.drawingToolsPanel {
|
|
2280
|
+
display: none;
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2283
|
+
.paintColumn {
|
|
2284
|
+
display: flex;
|
|
2285
|
+
}
|
|
2286
|
+
}
|
|
2287
|
+
|