castle-web-cli 0.4.177 → 0.4.179

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 (40) hide show
  1. package/dist/agent-failures.js +4 -4
  2. package/dist/agent-prompts.d.ts +9 -1
  3. package/dist/agent-prompts.js +15 -2
  4. package/dist/agent.js +125 -40
  5. package/dist/deckLocatorShape.d.ts +16 -0
  6. package/dist/deckLocatorShape.js +28 -0
  7. package/dist/editorConfig.d.ts +1 -0
  8. package/dist/shell/assets/index-C5DS_7UM.js +447 -0
  9. package/dist/shell/assets/index-CoU3ETYM.css +1 -0
  10. package/dist/shell/index.html +2 -2
  11. package/kits/base/CLAUDE.md +3 -0
  12. package/kits/base/castle.json +21 -11
  13. package/kits/physics-2d/CLAUDE.md +41 -8
  14. package/kits/physics-2d/behaviors/AnalogStick.jsx +80 -4
  15. package/kits/physics-2d/behaviors/Slingshot.jsx +14 -2
  16. package/kits/physics-2d/behaviors/Sprite.jsx +17 -8
  17. package/kits/physics-2d/behaviors/Style.jsx +270 -0
  18. package/kits/physics-2d/behaviors/Text.jsx +213 -0
  19. package/kits/physics-2d/behaviors/Video.jsx +8 -4
  20. package/kits/physics-2d/blueprints/text.scene +12 -0
  21. package/kits/physics-2d/castle.json +10 -6
  22. package/kits/physics-2d/editors/SceneEditor.jsx +41 -0
  23. package/kits/physics-2d/editors/deckFont.js +65 -55
  24. package/kits/physics-2d/editors/fontPreview.js +6 -38
  25. package/kits/physics-2d/editors/pixelInspector.jsx +4 -154
  26. package/kits/physics-2d/engine/blueprint.js +28 -0
  27. package/kits/physics-2d/engine/fonts.js +125 -23
  28. package/kits/physics-2d/engine/paletteField.jsx +235 -0
  29. package/kits/physics-2d/engine/physics/controls.js +5 -81
  30. package/kits/physics-2d/engine/popoverDismiss.js +17 -0
  31. package/kits/physics-2d/engine/scene.js +12 -3
  32. package/kits/physics-2d/engine/spriteField.jsx +2 -15
  33. package/kits/physics-2d/engine/tap.js +90 -0
  34. package/kits/physics-2d/engine/text.js +94 -0
  35. package/kits/physics-2d/engine/ui.jsx +20 -0
  36. package/kits/physics-2d/engine/ui.module.css +10 -2
  37. package/kits/physics-3d/castle.json +4 -2
  38. package/package.json +1 -1
  39. package/dist/shell/assets/index-BWOEraUy.js +0 -447
  40. package/dist/shell/assets/index-BkVF1OXc.css +0 -1
@@ -0,0 +1 @@
1
+ :root{--castle-font-body:baltomobile, Balto, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--castle-font-display:Basteleur, Georgia, "Times New Roman", serif;--castle-font-mono:ui-monospace, SFMono-Regular, Menlo, monospace;--castle-text-size-small:11px;--castle-text-size-base:13px;--castle-text-size-large:15px;--castle-text-style-smallcaps-size:var(--castle-text-size-small);--castle-text-style-smallcaps-letter-spacing:.05em;--castle-text-style-smallcaps-transform:uppercase;--castle-text-primary:#e6e6e6;--castle-text-secondary:#b3b3b3;--castle-text-muted:#888;--castle-text-dim:#525252;--castle-text-dark:#111;--castle-surface-1:#000;--castle-surface-2:#0c0c0c;--castle-surface-3:#181818;--castle-surface-4:#242424;--castle-surface-5:#303030;--castle-surface-6:#3c3c3c;--castle-surface-light:#e6e6e6;--castle-border-1:#2a2a2a;--castle-border-2:#6a6a6a;--castle-border-3:#3a3a3a;--castle-border-4:#e6e6e6;--castle-accent:#793a80;--castle-danger-text:#e86a73;--castle-danger-surface:#73172d;--castle-danger-surface-hover:#b4202a;--castle-warn-text:#e8b25a;--castle-warn-surface:#5a3d0a;--castle-space-small:3px;--castle-space-base:6px;--castle-space-large:12px;--castle-radius-small:4px;--castle-radius-base:8px;--castle-radius-large:16px;--castle-radius-pill:999px;--castle-button-height:24px;--castle-button-icon-size:16px;--castle-button-height-large:36px;--castle-button-icon-size-large:24px;--castle-icon-size-inline:12px;--castle-panel-header-height:36px;--castle-panel-header-height-mobile:48px}.text-style-smallcaps{font-size:var(--castle-text-style-smallcaps-size);letter-spacing:var(--castle-text-style-smallcaps-letter-spacing);text-transform:var(--castle-text-style-smallcaps-transform)}.icon-inline{flex:0 0 var(--castle-icon-size-inline);width:var(--castle-icon-size-inline);height:var(--castle-icon-size-inline);font-size:var(--castle-icon-size-inline)}.icon-slot{flex:0 0 var(--castle-button-icon-size);width:var(--castle-button-icon-size);height:var(--castle-button-icon-size);justify-content:center;align-items:center;display:flex}.icon-cell{flex:0 0 var(--castle-button-height);width:var(--castle-button-height);height:var(--castle-button-height);color:var(--castle-text-dim);pointer-events:none;justify-content:center;align-items:center;display:inline-flex}.icon-slot svg,.icon-slot iconify-icon,.icon-cell svg,.icon-cell iconify-icon{flex:0 0 var(--castle-button-icon-size);width:var(--castle-button-icon-size);height:var(--castle-button-icon-size);font-size:var(--castle-button-icon-size)}.button{justify-content:center;align-items:center;gap:var(--castle-space-base);max-width:100%;height:var(--castle-button-height);padding:0 var(--castle-space-base);border-radius:var(--castle-radius-small);background:var(--castle-surface-4);color:var(--castle-text-primary);font-family:var(--castle-font-body);font-size:var(--castle-text-size-base);white-space:nowrap;cursor:pointer;border:0;line-height:1.3;display:inline-flex}.button:not(.button-icon){min-width:0}.button>span{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.button:hover,.button.is-hover{background:var(--castle-surface-5)}.button:active,.button.is-pressed{background:var(--castle-surface-3)}.button:focus-visible,.button.is-focus{outline:1px solid var(--castle-border-2);outline-offset:2px}.button[aria-pressed=true],.button[aria-pressed=true]:hover,.button[aria-pressed=true]:active{background:var(--castle-surface-light);color:var(--castle-text-dark)}.button:disabled{opacity:.4;cursor:default}.button-icon{width:var(--castle-button-height);padding:0}.button-icon-large{width:var(--castle-button-height-large);height:var(--castle-button-height-large)}.button-danger{background:var(--castle-danger-surface);color:var(--castle-text-primary)}.button-danger:hover,.button-danger.is-hover{background:var(--castle-danger-surface-hover)}.button-danger:active,.button-danger.is-pressed{background:var(--castle-danger-surface)}.button-quiet{color:var(--castle-text-dim);background:0 0}.button-quiet:hover,.button-quiet.is-hover{background:var(--castle-surface-5);color:var(--castle-text-primary)}.button-quiet:active,.button-quiet.is-pressed{background:var(--castle-surface-3)}.button-quiet[aria-pressed=true],.button-quiet[aria-pressed=true]:hover,.button-quiet[aria-pressed=true]:active{background:var(--castle-surface-5);color:var(--castle-text-primary)}.composer-action{border-radius:var(--castle-radius-pill);color:var(--castle-text-muted);box-shadow:inset 0 0 0 1px var(--castle-border-2);background:0 0}.composer-action:disabled{opacity:1;color:var(--castle-text-muted);box-shadow:inset 0 0 0 1px var(--castle-border-1);background:0 0}.composer-action:not(:disabled),.composer-action:not(:disabled):hover,.composer-action:not(:disabled):active,.composer-action:not(:disabled).is-hover,.composer-action:not(:disabled).is-pressed{background:var(--castle-surface-light);color:var(--castle-text-dark);box-shadow:none}.button svg,.button iconify-icon{width:var(--castle-button-icon-size);height:var(--castle-button-icon-size);font-size:var(--castle-button-icon-size)}.button-icon-large svg,.button-icon-large iconify-icon{width:var(--castle-button-icon-size-large);height:var(--castle-button-icon-size-large);font-size:var(--castle-button-icon-size-large)}.button-badge{min-width:16px;height:16px;padding:0 var(--castle-space-small);border-radius:var(--castle-radius-pill);background:var(--castle-surface-5);color:var(--castle-text-secondary);font-size:var(--castle-text-size-small);font-variant-numeric:tabular-nums;text-align:center;text-overflow:clip;flex:none;line-height:16px;overflow:hidden}.button>.button-badge{text-overflow:clip;min-width:16px;overflow:hidden}.text-field{min-width:0;height:var(--castle-button-height);padding:0 var(--castle-space-base);border:1px solid var(--castle-border-3);border-radius:var(--castle-radius-small);background:var(--castle-surface-3);color:var(--castle-text-primary);font-family:var(--castle-font-body);font-size:var(--castle-text-size-base);cursor:text;outline:0}.text-field::placeholder{color:var(--castle-text-muted)}.text-field:hover,.text-field.is-hover{background:var(--castle-surface-4)}.text-field:focus,.text-field:focus-visible,.text-field.is-focus{outline:1px solid var(--castle-border-2);outline-offset:2px}.text-field:disabled{opacity:.4;cursor:default}.select{min-width:0;height:var(--castle-button-height);padding:0 var(--castle-space-base);border:1px solid var(--castle-border-3);border-radius:var(--castle-radius-small);background:var(--castle-surface-3);color:var(--castle-text-primary);font-family:var(--castle-font-body);font-size:var(--castle-text-size-base);cursor:pointer;outline:0}.select:hover,.select.is-hover{background:var(--castle-surface-4)}.select:focus,.select:focus-visible,.select.is-focus{outline:1px solid var(--castle-border-2);outline-offset:2px}.select:disabled{opacity:.4;cursor:default}.dock-control{justify-content:center;align-items:center;gap:var(--castle-space-base);max-width:100%;height:var(--castle-panel-header-height);padding:0 var(--castle-space-large);border:1px solid var(--castle-border-1);border-radius:var(--castle-radius-base);background:var(--castle-surface-3);color:var(--castle-text-primary);font-family:var(--castle-font-body);font-size:var(--castle-text-size-base);white-space:nowrap;cursor:pointer;font-weight:600;line-height:1;display:inline-flex}.dock-control:not(.dock-control-icon){min-width:0}.dock-control>span{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.dock-control-icon{width:var(--castle-panel-header-height);padding:0}.dock-control-quiet{background:0 0;border-color:#0000;justify-content:flex-start;min-width:0}.dock-control-mark{background:var(--castle-surface-1)}.dock-control-group{cursor:default;box-shadow:inset 0 0 0 1px var(--castle-border-1);border:none;justify-content:flex-start;align-items:stretch;gap:0;padding:0;overflow:hidden}button.dock-control:hover,button.dock-control.is-hover{background:var(--castle-surface-4);border-color:var(--castle-border-3)}button.dock-control:active,button.dock-control.is-pressed{background:var(--castle-surface-2)}button.dock-control-quiet:active,button.dock-control-quiet.is-pressed{background:var(--castle-surface-3)}button.dock-control:focus-visible,button.dock-control.is-focus{outline:1px solid var(--castle-border-2);outline-offset:2px}.dock-control:disabled{opacity:.4;cursor:default}button.dock-control:disabled:hover,button.dock-control:disabled.is-hover{background:var(--castle-surface-3);border-color:var(--castle-border-1)}button.dock-control-quiet:disabled:hover,button.dock-control-quiet:disabled.is-hover{background:0 0;border-color:#0000}button.dock-control-mark:disabled:hover,button.dock-control-mark:disabled.is-hover{background:var(--castle-surface-1)}.dock-control svg,.dock-control iconify-icon{width:var(--castle-button-icon-size);height:var(--castle-button-icon-size);font-size:var(--castle-button-icon-size);flex-shrink:0}.dock-control-mark svg,.dock-control-mark img{width:20px;height:20px}.dock-control-mark img{object-fit:contain;display:block}.dock-segment{flex:0 0 var(--castle-panel-header-height);width:var(--castle-panel-header-height);height:var(--castle-panel-header-height);color:var(--castle-text-muted);cursor:pointer;background:0 0;border:none;border-radius:0;justify-content:center;align-items:center;padding:0;display:inline-flex}.dock-segment iconify-icon,.dock-segment svg{width:var(--castle-button-icon-size);height:var(--castle-button-icon-size);font-size:var(--castle-button-icon-size)}@media (hover:hover){.dock-segment:hover:not(.is-active){color:var(--castle-text-primary);background:var(--castle-surface-5)}}.dock-segment.is-hover:not(.is-active){color:var(--castle-text-primary);background:var(--castle-surface-5)}.dock-segment.is-active{color:var(--castle-text-dark);background:var(--castle-surface-light)}.dock-segment.is-drag-origin{opacity:0;pointer-events:none;flex:0 0 0;width:0;min-width:0;max-width:0;padding:0;overflow:hidden}.dock-segment-slot{flex:0 0 var(--castle-panel-header-height);width:var(--castle-panel-header-height);height:var(--castle-panel-header-height);color:var(--castle-text-primary);background:var(--castle-surface-6);pointer-events:none;justify-content:center;align-items:center;display:inline-flex}.dock-segment-slot iconify-icon,.dock-segment-slot svg{width:var(--castle-button-icon-size);height:var(--castle-button-icon-size);font-size:var(--castle-button-icon-size)}.dock-segment-ghost{border-radius:var(--castle-radius-small);pointer-events:none;box-shadow:0 8px 24px #00000073}.dock-segment:has(.dock-badge){position:relative}.dock-segment .dock-badge{top:var(--castle-space-small);right:var(--castle-space-small);z-index:1;background:var(--castle-surface-light);color:var(--castle-text-dark);pointer-events:none;transform-origin:50%;position:absolute}.dock-segment .dock-badge:not(.is-appearing){visibility:hidden;opacity:0;transform:scale(.45)}.dock-segment .dock-badge.is-appearing{visibility:visible;animation:.28s cubic-bezier(.2,.8,.2,1) both dock-badge-appear}@keyframes dock-badge-appear{0%{opacity:0;transform:scale(.45)}70%{opacity:1;transform:scale(1.08)}to{opacity:1;transform:scale(1)}}@media (prefers-reduced-motion:reduce){.dock-segment .dock-badge.is-appearing{animation:none}}.menu{gap:var(--castle-space-small);width:max-content;min-width:144px;padding:var(--castle-space-small);border:1px solid var(--castle-border-3);border-radius:var(--castle-radius-base);background:var(--castle-surface-5);flex-direction:column;display:flex;box-shadow:0 8px 24px #0000008c}.menu-item{align-items:center;gap:var(--castle-space-base);width:100%;height:26px;padding:0 var(--castle-space-base);border-radius:var(--castle-radius-small);color:var(--castle-text-primary);font-family:var(--castle-font-body);font-size:var(--castle-text-size-base);cursor:pointer;background:0 0;border:0;display:flex}.menu-icon{flex:0 0 16px;width:16px;height:16px;font-size:16px}svg.menu-icon,iconify-icon.menu-icon{fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.5px}.menu-icon svg,.menu-icon iconify-icon{width:16px;height:16px;font-size:16px}.menu-item:hover:not(:disabled),.menu-item.is-hover:not(:disabled){background:var(--castle-surface-6)}.menu-item:disabled{opacity:.4;cursor:default}.menu-item-label{text-overflow:ellipsis;white-space:nowrap;text-align:left;flex:auto;min-width:0;overflow:hidden}.menu-check{color:var(--castle-text-primary);flex:none}.menu-keys{margin-left:var(--castle-space-large);color:var(--castle-text-muted);font-size:var(--castle-text-size-small);white-space:nowrap;flex:none}.menu-item:disabled .menu-keys{color:inherit}.menu-item-danger{color:var(--castle-danger-text)}.menu-separator{height:1px;margin:var(--castle-space-small) 0;background:var(--castle-border-3)}.menu-header{padding:var(--castle-space-small) var(--castle-space-base);color:var(--castle-text-muted);font-size:var(--castle-text-size-small);letter-spacing:.04em;text-transform:uppercase}.menu-confirm{gap:var(--castle-space-base);min-width:180px;padding:var(--castle-space-small) var(--castle-space-base);flex-direction:column;display:flex}.menu-confirm-text{color:var(--castle-text-primary);font-size:var(--castle-text-size-base);margin:0}.menu-confirm-actions{justify-content:flex-end;gap:var(--castle-space-base);display:flex}.menu-error{padding:var(--castle-space-small) var(--castle-space-base);color:var(--castle-danger-text);font-size:var(--castle-text-size-small);margin:0}.feedback-quiet{--castle-feedback-text:var(--castle-text-muted);--castle-feedback-surface:var(--castle-surface-3);--castle-feedback-border:var(--castle-border-3)}.feedback-warn{--castle-feedback-text:var(--castle-warn-text);--castle-feedback-surface:var(--castle-warn-surface);--castle-feedback-surface-hover:color-mix(in srgb, var(--castle-warn-text) 35%, var(--castle-warn-surface));--castle-feedback-border:color-mix(in srgb, var(--castle-warn-text), var(--castle-warn-surface))}.feedback-danger{--castle-feedback-text:var(--castle-danger-text);--castle-feedback-surface:var(--castle-danger-surface);--castle-feedback-surface-hover:var(--castle-danger-surface-hover);--castle-feedback-border:color-mix(in srgb, var(--castle-danger-text), var(--castle-danger-surface))}.feedback-note{color:var(--castle-feedback-text);margin:0}.feedback-banner{align-items:center;gap:var(--castle-space-base);min-height:var(--castle-panel-header-height);padding:var(--castle-space-base);border-bottom:1px solid var(--castle-feedback-border);background:var(--castle-feedback-surface);color:var(--castle-feedback-text);font-size:var(--castle-text-size-base);display:flex}.feedback-banner>span:not(.icon-cell){flex:auto;min-width:0}.feedback-banner .icon-cell{color:inherit}.feedback-warn .button,.feedback-danger .button{border:1px solid var(--castle-feedback-border);background:var(--castle-feedback-surface);color:var(--castle-text-primary)}.feedback-warn .button:hover,.feedback-warn .button.is-hover,.feedback-danger .button:hover,.feedback-danger .button.is-hover{background:var(--castle-feedback-surface-hover)}.feedback-warn .button:active,.feedback-warn .button.is-pressed,.feedback-danger .button:active,.feedback-danger .button.is-pressed{background:var(--castle-feedback-surface)}.feedback-takeover{padding:calc(var(--castle-space-large) * 2);border:1px solid var(--castle-feedback-border);border-radius:var(--castle-radius-base);background:var(--castle-feedback-surface);color:var(--castle-feedback-text);font-size:var(--castle-text-size-base);text-align:center;justify-content:center;align-items:center;display:flex}.panel{border:1px solid var(--castle-border-1);border-radius:var(--castle-radius-base);background:var(--castle-surface-2);color:var(--castle-text-primary);font-family:var(--castle-font-body);transition:border-color .12s;position:relative;overflow:hidden}@media (hover:hover){.panel:hover{border-color:var(--castle-border-3)}}.panel.is-hover{border-color:var(--castle-border-3)}.panel.is-active,.panel.is-active:hover,.panel.is-active.is-hover{border-color:var(--castle-border-2)}.panel.is-dragging,.panel.is-dragging:hover,.panel.is-dragging.is-hover,.panel.is-dragging.is-active{border-color:var(--castle-border-4)}.panel-header,.panel-tabs-header{height:var(--castle-panel-header-height);padding:0 var(--castle-space-base);border-bottom:1px solid var(--castle-border-1);background:var(--castle-surface-3);align-items:center;display:flex}@media (hover:hover){.panel-header:hover,.panel-tabs-header:hover{background:var(--castle-surface-4);cursor:grab}}.panel-header.is-hover,.panel-tabs-header.is-hover{background:var(--castle-surface-4);cursor:grab}.panel-header:active,.panel-header.is-pressed,.panel-tabs-header:active,.panel-tabs-header.is-pressed{cursor:grabbing}.panel-tabs-header{align-items:stretch;gap:var(--castle-space-base)}.panel-title{align-items:center;gap:var(--castle-space-base);min-width:0;padding:0 var(--castle-space-base);color:var(--castle-text-primary);font-family:var(--castle-font-display);font-size:var(--castle-text-size-base);margin:0 auto 0 0;font-weight:700;line-height:1.5;display:inline-flex}.panel-title svg,.panel-title iconify-icon{width:var(--castle-button-icon-size);height:var(--castle-button-icon-size);font-size:var(--castle-button-icon-size);flex-shrink:0}.panel-header-actions{align-items:center;gap:var(--castle-space-small);margin-left:auto;display:flex}.panel-type-toggle{align-items:center;gap:var(--castle-space-base);min-width:0;max-width:100%;height:var(--castle-button-height);padding:0 var(--castle-space-base);border-radius:var(--castle-radius-small);color:var(--castle-text-primary);font-family:var(--castle-font-display);font-size:var(--castle-text-size-base);white-space:nowrap;cursor:pointer;background:0 0;border:0;align-self:center;font-weight:700;display:inline-flex}.panel-type-toggle:hover,.panel-type-toggle.is-hover,.panel-type-toggle[aria-pressed=true]{background:var(--castle-surface-5)}.panel-type-toggle svg,.panel-type-toggle iconify-icon{width:var(--castle-button-icon-size);height:var(--castle-button-icon-size);font-size:var(--castle-button-icon-size);flex-shrink:0}.panel-tabs{align-items:center;gap:var(--castle-space-base);flex:auto;min-width:0;display:flex}.panel-tab{max-width:160px;height:var(--castle-button-height);padding:var(--castle-space-small) var(--castle-space-base);border-radius:var(--castle-radius-small);color:var(--castle-text-dim);font-family:var(--castle-font-body);font-size:var(--castle-text-size-base);white-space:nowrap;cursor:pointer;background:0 0;border:0;align-items:center;line-height:18px;display:flex;position:relative;overflow:hidden}.panel-tab>span{text-overflow:ellipsis;min-width:0;overflow:hidden}.panel-tab:hover,.panel-tab.is-hover{background:var(--castle-surface-5);color:var(--castle-text-secondary)}.panel-tab.is-active{background:var(--castle-surface-5);color:var(--castle-text-primary)}.panel-tab:hover>span,.panel-tab.is-hover>span{-webkit-mask-image:linear-gradient(to right, #000 calc(100% - (var(--castle-button-icon-size) + var(--castle-space-large))), transparent 100%);mask-image:linear-gradient(to right, #000 calc(100% - (var(--castle-button-icon-size) + var(--castle-space-large))), transparent 100%)}.panel-tab.is-narrow:not(.is-active):hover>span,.panel-tab.is-narrow:not(.is-active).is-hover>span{-webkit-mask-image:none;mask-image:none}.panel-tab-close{z-index:1;top:var(--castle-space-small);right:var(--castle-space-small);width:calc(var(--castle-button-icon-size) + var(--castle-space-large));height:var(--castle-button-icon-size);border-radius:var(--castle-radius-small);background:linear-gradient(to right, transparent, var(--castle-surface-3) 45%);color:currentColor;cursor:pointer;opacity:0;pointer-events:none;border:0;justify-content:flex-end;align-items:center;padding:0;display:inline-flex;position:absolute}.panel-tab-close svg,.panel-tab-close iconify-icon{width:var(--castle-button-icon-size);height:var(--castle-button-icon-size);font-size:var(--castle-button-icon-size)}.panel-tab:hover .panel-tab-close,.panel-tab.is-hover .panel-tab-close,.panel-tab:focus-within .panel-tab-close{opacity:1;pointer-events:auto;background:linear-gradient(to right, transparent, var(--castle-surface-5) 45%)}.panel-tab.is-active .panel-tab-close{background:linear-gradient(to right, transparent, var(--castle-surface-5) 45%)}.panel-tab-close:hover,.panel-tab-close.is-hover{background:linear-gradient(to right, transparent, var(--castle-surface-5) 45%);color:var(--castle-text-primary)}.panel-tab.is-narrow:not(.is-active):hover .panel-tab-close,.panel-tab.is-narrow:not(.is-active).is-hover .panel-tab-close{opacity:0;pointer-events:none}.panel-tab.is-drag-origin{opacity:0;pointer-events:none;border:0;width:0;min-width:0;max-width:0;padding:0}.panel-tab-insert{width:2px;height:var(--castle-button-height);border-radius:var(--castle-radius-pill);background:var(--castle-border-4);pointer-events:none;flex:0 0 2px}.panel-tab-ghost{padding:var(--castle-space-base) var(--castle-space-large);border:1px solid var(--castle-border-1);border-radius:var(--castle-radius-small);background:var(--castle-surface-3);color:var(--castle-text-primary);font-size:var(--castle-text-size-base);pointer-events:none;box-shadow:0 8px 24px #00000073}.panel-mobile-current{justify-content:center;align-self:center;align-items:center;gap:var(--castle-space-base);min-width:0;max-width:100%;height:var(--castle-button-height-large);padding:0 var(--castle-space-base);border-radius:var(--castle-radius-small);color:var(--castle-text-primary);font-family:var(--castle-font-body);font-size:var(--castle-text-size-base);cursor:pointer;background:0 0;border:0;display:inline-flex}.panel-mobile-current:hover,.panel-mobile-current.is-hover{background:var(--castle-surface-5)}.panel-mobile-current-text{align-items:baseline;gap:var(--castle-space-small);min-width:0;display:flex}.panel-mobile-current-label{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.panel-mobile-current strong,.panel-mobile-current-type{font-family:var(--castle-font-display);flex-shrink:0;font-weight:700}.panel-mobile-current svg,.panel-mobile-current iconify-icon{width:var(--castle-button-icon-size-large);height:var(--castle-button-icon-size-large);font-size:var(--castle-button-icon-size-large);flex:none}.segmented{border-radius:var(--castle-radius-small);flex-wrap:wrap;align-items:stretch;display:flex;overflow:hidden}.segmented>.button{border-radius:0}.feedback-banner.is-inset{border-radius:var(--castle-radius-small);border-bottom:none}.feedback-banner.is-inset .button{flex:none;width:auto}.popover{width:max-content;max-width:calc(100vw - 24px);max-height:calc(100vh - 16px);padding:var(--castle-space-large);border:1px solid var(--castle-border-3);border-radius:var(--castle-radius-base);background:var(--castle-surface-4);color:var(--castle-text-primary);font-family:var(--castle-font-body);font-size:var(--castle-text-size-base);flex-direction:column;display:flex;overflow:auto;box-shadow:0 8px 24px #0000008c}.popover .button:not(.button-quiet){background:var(--castle-surface-5)}.popover .button:not(.button-quiet):hover,.popover .button:not(.button-quiet).is-hover{background:var(--castle-surface-6)}.popover .button:not(.button-quiet):active,.popover .button:not(.button-quiet).is-pressed{background:var(--castle-surface-4)}.popover .button[aria-pressed=true],.popover .button[aria-pressed=true]:hover,.popover .button[aria-pressed=true]:active{background:var(--castle-surface-light);color:var(--castle-text-dark)}.popover .feedback-warn .button:not(.button-quiet),.popover .feedback-danger .button:not(.button-quiet){border:1px solid var(--castle-feedback-border);background:var(--castle-feedback-surface);color:var(--castle-text-primary)}.popover .feedback-warn .button:not(.button-quiet):hover,.popover .feedback-warn .button:not(.button-quiet).is-hover,.popover .feedback-danger .button:not(.button-quiet):hover,.popover .feedback-danger .button:not(.button-quiet).is-hover{background:var(--castle-feedback-surface-hover)}.popover .feedback-warn .button:not(.button-quiet):active,.popover .feedback-warn .button:not(.button-quiet).is-pressed,.popover .feedback-danger .button:not(.button-quiet):active,.popover .feedback-danger .button:not(.button-quiet).is-pressed{background:var(--castle-feedback-surface)}:root{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark;--v2-gutter:#000;--v2-surface:#0d0d0d;--v2-raised:#161616;--v2-hover:#1d1d1d;--v2-fg:#e6e6e6;--v2-head:#e8e8e8;--v2-secondary:#b3b3b3;--v2-muted:#888;--v2-dim:#525252;--v2-placeholder:#666;--v2-ink:#111;--v2-white:#fff;--v2-border:#2a2a2a;--v2-accent:var(--castle-accent);--v2-accent-hover:color-mix(in srgb, var(--castle-accent) 84%, #fff);--v2-error-bg:#5a2b2b;--v2-warn:#e2c08d;--v2-error:#e08c8c;--v2-overlay-scrim:#00000059;--v2-overlay-code:#00000038;--v2-overlay-code-block:#00000047;--v2-overlay-task:#141414eb;--v2-overlay-feed-code:#7878784d;--v2-overlay-white-subtle:#ffffff0f;--v2-overlay-white-hover:#ffffff14;--v2-overlay-white-border:#ffffff24;--v2-overlay-white-quote:#fff6;--v2-overlay-white-dim:#ffffffd9;--v2-shadow-pop:0 10px 24px -10px #000000e6;--v2-selection:#e6e6e62e;--v2-mono:ui-monospace, SFMono-Regular, Menlo, monospace;--panel-gutter:10px;--panel-chrome-radius:8px}*{box-sizing:border-box}html,body,#root{height:100%;margin:0}body{color:var(--v2-fg);background:var(--v2-surface);font-family:baltomobile,Balto,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;overflow:hidden}.panel-error{height:100%;color:var(--v2-muted);flex-direction:column;align-items:flex-start;gap:8px;padding:14px 16px;font-size:13px;display:flex;overflow:auto}.panel-error-title{color:var(--v2-fg)}.panel-error-msg{white-space:pre-wrap;word-break:break-word;max-width:100%;color:var(--v2-muted);margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.panel-error-retry{font:inherit;border:1px solid var(--v2-border);background:var(--v2-raised);color:var(--v2-fg);cursor:pointer;border-radius:4px;padding:3px 10px;font-size:12px}.panel-error-retry:hover{background:var(--v2-hover)}.editor-panel-root{flex-direction:column;width:100%;height:100%;min-height:0;display:flex}.editor-shell{flex:auto;min-height:0;display:flex}.editor-panel-body{flex-direction:column;flex:auto;min-width:0;min-height:0;display:flex}.editor-panel-view{flex:auto;min-width:0;min-height:0;position:relative}.editor-import-banner{background:var(--flow-surface,#181818);border-bottom:1px solid var(--v2-border,#2a2a2a);color:var(--v2-muted,#888);flex:none;align-items:center;gap:8px;padding:8px;font:12px ui-sans-serif,system-ui,sans-serif;display:flex}.editor-import-chip{border:1px solid var(--v2-border,#2a2a2a);background:var(--v2-raised,#161616);color:var(--v2-muted,#888);letter-spacing:.02em;border-radius:999px;flex:none;align-items:center;padding:2px 8px;font-size:12px;line-height:1.4;display:inline-flex}.editor-import-banner-text{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.editor-import-banner-action{border:1px solid var(--v2-border,#2a2a2a);background:var(--v2-raised,#161616);color:var(--v2-text,#ddd);font:inherit;cursor:pointer;border-radius:4px;flex:none;margin-left:auto;padding:2px 10px}.editor-import-banner-action:hover{border-color:var(--v2-muted,#888)}.editor-import-chip.editor-fork-chip{color:var(--v2-text,#ddd)}.editor-fork-modal-scrim{z-index:40;background:#00000080;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.editor-fork-modal{border:1px solid var(--v2-border,#2a2a2a);background:var(--flow-surface,#181818);max-width:420px;color:var(--v2-text,#ddd);border-radius:6px;padding:16px;font:13px ui-sans-serif,system-ui,sans-serif}.editor-fork-modal-title{margin-bottom:8px;font-weight:600}.editor-fork-modal-body{color:var(--v2-muted,#888);line-height:1.5}.editor-fork-modal-actions{justify-content:flex-end;gap:8px;margin-top:16px;display:flex}.editor-fork-modal-actions button{border:1px solid var(--v2-border,#2a2a2a);background:var(--v2-raised,#161616);color:var(--v2-text,#ddd);font:inherit;cursor:pointer;border-radius:4px;padding:4px 12px}.editor-fork-modal-actions button:hover{border-color:var(--v2-muted,#888)}.editor-contextbar{background:var(--v2-gutter,#0d0d0d);border-bottom:1px solid var(--v2-border,#2a2a2a);flex:none;align-items:center;gap:8px;padding:5px 8px;display:flex}.editor-drawer-toggle{width:26px;height:24px;color:var(--v2-muted,#888);cursor:pointer;background:0 0;border:1px solid #0000;border-radius:6px;flex:none;justify-content:center;align-items:center;display:inline-flex}.editor-drawer-toggle:hover{color:var(--v2-fg,#e7e7ef);background:var(--v2-surface,#1b1b2b)}.editor-drawer-toggle.on{color:var(--v2-fg,#e7e7ef);background:var(--v2-surface,#1b1b2b);border-color:var(--v2-border,#3a3a52)}.editor-drawer{background:var(--v2-gutter,#0d0d0d);border-right:1px solid var(--v2-border,#2a2a2a);flex:none;width:190px;padding:6px 4px;overflow-y:auto}.editor-drawer-folder{letter-spacing:.03em;text-transform:uppercase;color:var(--v2-muted,#888);padding:6px 8px 2px;font:10px ui-sans-serif,system-ui,sans-serif}.editor-drawer-item{width:100%;color:var(--v2-secondary,#b3b3b3);cursor:pointer;text-align:left;text-overflow:ellipsis;white-space:nowrap;background:0 0;border:none;border-radius:6px;padding:5px 8px;font:12px ui-sans-serif,system-ui,sans-serif;display:block;overflow:hidden}.editor-drawer-item:hover{background:var(--v2-surface,#1b1b2b);color:var(--v2-fg,#e7e7ef)}.editor-drawer-item.current{color:var(--v2-fg,#e7e7ef);background:#ffffff1a}.editor-drawer-empty{color:var(--v2-muted,#888);padding:10px 8px;font-size:12px}.editor-view-picker{background:var(--v2-surface,#1b1b2b);color:var(--v2-fg,#e7e7ef);border:1px solid var(--v2-border,#3a3a52);cursor:pointer;border-radius:6px;flex:none;padding:3px 6px;font:12px system-ui,sans-serif}.editor-contextbar-path{text-overflow:ellipsis;white-space:nowrap;color:var(--v2-muted,#888);flex:auto;font:11px ui-monospace,SFMono-Regular,Menlo,monospace;overflow:hidden}.editor-contextbar-reload{width:22px;height:22px;color:var(--v2-muted,#888);cursor:pointer;background:0 0;border:none;border-radius:5px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.editor-contextbar-reload:hover{color:var(--v2-white,#fff);background:var(--v2-overlay-white-hover,#ffffff14)}.editor-contextbar-reload svg{width:13px;height:13px}.deck-panel{background:var(--v2-surface);width:100%;height:100%}.deck-frame{border:0;width:100%;height:100%;display:block}.play-panel{background:var(--castle-surface-2);flex-direction:column;width:100%;height:100%;display:flex}.play-scene-picker{padding:0 var(--castle-space-large) var(--castle-space-large);flex:none;justify-content:center;align-items:center;display:flex}.play-stage{min-height:0;padding:var(--castle-space-large);flex:auto;justify-content:center;align-items:center;display:flex;container-type:size}.play-stage:has(+.play-scene-picker){padding-bottom:var(--castle-space-base)}.play-frame-shell{aspect-ratio:5/7;border-radius:4%/2.85714%;width:min(100cqw,71.4286cqh);height:min(100cqh,140cqw);position:relative;overflow:hidden}.play-frame-shell .deck-frame{width:100%;height:100%}.play-logs{border-top:1px solid var(--castle-border-1);background:var(--castle-surface-2);color:var(--castle-text-secondary);flex:none;position:relative}.play-logs.is-open{--play-logs-height:160px;flex:0 0 var(--play-logs-height);height:var(--play-logs-height);flex-direction:column;min-height:0;display:flex;overflow:hidden}.play-logs-resize{z-index:2;cursor:row-resize;touch-action:none;height:12px;display:none;position:absolute;top:-6px;left:0;right:0}.play-logs.is-open>.play-logs-resize{display:block}body.play-logs-resizing,body.play-logs-resizing *{cursor:row-resize!important;-webkit-user-select:none!important;user-select:none!important}.play-logs-header{min-height:calc(var(--castle-button-height) + 2 * var(--castle-space-base));padding:var(--castle-space-base);align-items:center;column-gap:var(--castle-space-base);cursor:pointer;flex:none;grid-template-columns:minmax(0,1fr) minmax(0,max-content) max-content;display:grid;position:relative}.play-logs-header:hover{background:var(--castle-surface-3)}.play-logs-expand{z-index:0;cursor:pointer;background:0 0;border:0;padding:0;position:absolute;inset:0}.play-logs-expand:focus{outline:none}.play-logs-expand:focus-visible{outline:2px solid var(--castle-border-2);outline-offset:-2px}.play-logs-label{align-items:center;gap:var(--castle-space-base);min-width:0;color:var(--castle-text-dim);pointer-events:none;justify-self:start;display:inline-flex}.play-logs-header:hover .play-logs-label{color:var(--castle-text-primary)}.play-logs-label svg{flex:0 0 var(--castle-button-icon-size);width:var(--castle-button-icon-size);height:var(--castle-button-icon-size);font-size:var(--castle-button-icon-size)}.play-logs-pending{min-width:0;color:var(--castle-text-muted);font-size:var(--castle-text-size-small);text-overflow:ellipsis;white-space:nowrap;pointer-events:none;grid-column:2;margin:0;line-height:1.4;overflow:hidden}.play-logs-restart{z-index:1;grid-column:3;justify-self:end;min-width:max-content;position:relative}.play-logs-restart.is-pending,.play-logs-restart.is-pending:hover,.play-logs-restart.is-pending:active{color:var(--castle-warn-text)}.play-logs-restart-icon{line-height:1;display:inline-flex}.play-logs-restart-icon.is-spinning{animation:.6s linear infinite play-logs-spin}@keyframes play-logs-spin{to{transform:rotate(360deg)}}.play-logs-toolbar{align-items:center;gap:var(--castle-space-base);padding:var(--castle-space-base);border-top:1px solid var(--castle-border-1);flex-wrap:wrap;flex:none;display:flex}.play-logs-body{min-height:0;padding:var(--castle-space-base) var(--castle-space-large);border-top:1px solid var(--castle-border-1);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:var(--castle-text-size-small);flex:auto;line-height:1.5;overflow-y:auto}.play-logs-line{white-space:pre-wrap;word-break:break-word}.play-logs-warn{color:var(--castle-warn-text)}.play-logs-error{color:var(--castle-danger-text)}.play-logs-empty{color:var(--castle-text-dim)}.flow-root.is-mobile .play-panel{--castle-text-size-small:14px;--castle-text-size-base:16px;--castle-text-style-smallcaps-size:var(--castle-text-size-small);--castle-button-height:var(--castle-button-height-large)}.flow-root.is-mobile .play-panel .button:not(.button-icon){padding-left:var(--castle-space-large);padding-right:var(--castle-space-large)}.flow-root.is-mobile .play-logs.is-open{--play-logs-height:200px}.flow-root.is-mobile .play-logs-header:hover{background:0 0}.flow-root.is-mobile .play-logs-header:hover .play-logs-label{color:var(--castle-text-dim)}.flow-root.is-mobile .play-stage{padding:var(--castle-space-small)}.term-panel{width:100%;height:100%;position:relative}.term-host{overscroll-behavior:contain;padding:6px;position:absolute;inset:0}.shell-root{--operator-pad:var(--castle-space-large);--operator-col-fit:min(var(--operator-col,400px), 100%);background:var(--v2-gutter);height:100%;position:relative}#chat-host{width:var(--operator-col-fit);background:var(--v2-gutter);color:var(--v2-fg);z-index:10;flex-direction:column;font-family:Balto,system-ui,-apple-system,sans-serif;display:flex;position:absolute;top:0;bottom:0;left:0;overflow:hidden}.settings-popover{z-index:2147483000;width:390px;position:fixed}.settings-popover .settings-row{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:6px 10px;display:flex}.settings-popover .settings-row+.settings-row{margin-top:8px}.settings-popover .settings-label{white-space:nowrap}.settings-popover .settings-row-stack{flex-direction:column;align-items:stretch;gap:4px;display:flex}.settings-popover .settings-row-main{flex-wrap:wrap;justify-content:space-between;align-items:center;gap:6px 10px;display:flex}.settings-popover .settings-text-warn{border-color:var(--v2-warn)}.settings-popover .settings-warning{color:var(--v2-warn);text-align:right;font-size:11px;line-height:1.35}.settings-popover .settings-warning-suggest{appearance:none;font:inherit;color:var(--v2-warn);cursor:pointer;background:0 0;border:none;margin:0;padding:0;text-decoration:underline}.settings-popover .settings-warning-suggest:hover{color:var(--castle-text-primary)}.settings-popover .settings-group+.settings-group{border-top:1px solid var(--castle-border-1);margin-top:12px;padding-top:12px}.settings-popover .settings-credits{margin-top:var(--castle-space-base);color:var(--castle-text-secondary);font-size:var(--castle-text-size-base)}.settings-popover .settings-usage-subtext{margin-top:var(--castle-space-small);color:var(--castle-text-muted);font-size:var(--castle-text-size-small)}.settings-popover .settings-usage-subtext.feedback-note{color:var(--castle-feedback-text)}.settings-popover .settings-split{justify-content:space-between;align-items:center;gap:var(--castle-space-large);margin-top:var(--castle-space-base);display:flex}.settings-popover .settings-group>.settings-split:first-child{margin-top:0}.settings-popover .settings-split-copy,.settings-popover .settings-split>.settings-credits{flex:auto;min-width:0}.settings-popover .settings-split .settings-credits{margin-top:0}.settings-popover .settings-split .button{flex:none;width:auto;margin-left:auto}.settings-popover .settings-group>.feedback-banner.is-inset{margin-top:var(--castle-space-base)}.settings-popover .text-field{flex:auto}.settings-popover .select{flex:0 auto;max-width:60%}.settings-popover .settings-usage-bar{height:4px;margin-top:var(--castle-space-base);background:var(--castle-surface-5);border-radius:2px;overflow:hidden}.settings-popover .settings-usage-fill{background:var(--castle-accent);height:100%}.settings-popover .settings-usage-fill.blocked{background:var(--castle-danger-text)}.castle-key-heading{margin-bottom:4px;font-weight:600}.castle-key-subtitle{color:#9a9a9a;margin-bottom:14px;font-size:12px;line-height:1.5}.castle-key-tabs{border:1px solid #3a3a3a;border-radius:4px;margin-bottom:12px;display:flex;overflow:hidden}.castle-key-tab{color:#9a9a9a;font:inherit;cursor:pointer;background:#2e2e2e;border:0;flex:1;padding:6px 10px;font-size:12px}.castle-key-tab+.castle-key-tab{border-left:1px solid #3a3a3a}.castle-key-tab:hover{color:#e8e8e8}.castle-key-tab.active{color:#e8e8e8;background:#3a3a3a}.castle-key-input{box-sizing:border-box;color:#e8e8e8;width:100%;font:inherit;background:#1b1b1b;border:1px solid #3a3a3a;border-radius:4px;outline:none;padding:7px 9px;font-size:12px;display:block}.castle-key-input:focus{border-color:#4a4a4a}.castle-key-input::placeholder{color:#6a6a6a}.castle-key-stored{color:#8a8a8a;margin-top:8px;font-size:11px}.castle-key-error{color:#e8705a;margin-top:8px;font-size:11px;line-height:1.4}.castle-key-row{color:#c8c8c8;justify-content:space-between;align-items:center;gap:10px;margin-bottom:12px;display:flex}.castle-key-row button{color:#e8e8e8;font:inherit;cursor:pointer;background:#2e2e2e;border:1px solid #3a3a3a;border-radius:4px;padding:5px 12px;font-size:12px}.castle-key-row button:hover{background:#383838}.castle-key-login{margin-bottom:12px}.castle-key-signin{color:#e8e8e8;width:100%;font:inherit;cursor:pointer;background:#2e2e2e;border:1px solid #3a3a3a;border-radius:4px;padding:9px 12px;font-size:13px;display:block}.castle-key-signin:hover{background:#383838}.castle-key-or{color:#7a7a7a;letter-spacing:.08em;text-transform:uppercase;align-items:center;gap:10px;margin:14px 0;font-size:11px;display:flex}.castle-key-or:before,.castle-key-or:after{content:"";background:#3a3a3a;flex:1;height:1px}.castle-key-field-label{color:#c8c8c8;margin-bottom:6px;font-size:12px}.castle-key-url{color:#7aa2f7;word-break:break-all;-webkit-user-select:all;user-select:all;background:#1b1b1b;border:1px solid #3a3a3a;border-radius:4px;padding:8px 9px;font-size:11px;line-height:1.4;display:block}#chat-messages{overflow-anchor:none;min-height:0;font-size:var(--castle-text-size-base);scrollbar-width:none;-ms-overflow-style:none;flex-direction:column;flex:1 1 0;padding:0;line-height:1.5;display:flex;overflow-y:auto}#chat-messages .chat-thread{gap:var(--castle-space-large);padding-bottom:var(--castle-space-large);opacity:0;flex-direction:column;transition:opacity .12s;display:flex}#chat-messages .chat-thread.ready{opacity:1}.shell-root.docked #chat-messages{padding:0}.shell-root.docked #chat-messages>:first-child{margin-top:auto}#chat-messages::-webkit-scrollbar{width:0;height:0}#chat-empty{color:var(--castle-text-muted)}#chat-host .msg{margin:0}#chat-host .msg.user{text-align:right}#chat-host .msg.user span:not(.msg-image){background:var(--castle-surface-light);color:var(--castle-text-dark);padding:var(--castle-space-base) var(--castle-space-large);border-radius:var(--castle-radius-large);text-align:left;white-space:pre-wrap;word-break:break-word;max-width:85%;display:inline-block}#chat-host .msg-image{border:1px solid var(--castle-border-1);border-radius:var(--castle-radius-base);max-width:220px;max-height:150px;margin:0 0 var(--castle-space-base) auto;display:block}#chat-host .assistant-turn{align-items:flex-start;gap:var(--castle-space-base);flex-direction:column;margin:0;display:flex}#chat-host .assistant-turn .feedback-note{max-width:85%}#chat-host .msg.assistant{background:var(--castle-accent);width:fit-content;color:var(--castle-surface-light);padding:var(--castle-space-base) var(--castle-space-large);border-radius:var(--castle-radius-large);word-break:break-word;max-width:85%;margin:0}#chat-host .msg.assistant.errbubble{background:var(--castle-danger-surface);color:var(--castle-danger-text)}#chat-host .msg.assistant.streaming:after{content:"▌";opacity:.6;animation:1s step-end infinite chat-blink}@keyframes chat-blink{50%{opacity:0}}#chat-host .msg.toolline{color:var(--castle-text-muted);font-size:var(--castle-text-size-base);font-family:var(--castle-font-mono);word-break:break-word}#chat-host .msg-error-detail{font-size:var(--castle-text-size-base);color:var(--castle-text-muted)}#chat-host .msg-error-detail summary{cursor:pointer;-webkit-user-select:none;user-select:none}#chat-host .msg-error-detail pre{margin:var(--castle-space-small) 0 0;padding:var(--castle-space-base);background:var(--castle-surface-1);border-radius:var(--castle-radius-small);font-size:var(--castle-text-size-small);white-space:pre-wrap;word-break:break-word;max-height:160px;overflow-y:auto}#chat-host .operator-line,#chat-host .msg-thinking{color:var(--castle-text-muted);font-size:var(--castle-text-size-base)}#chat-host .operator-line{align-items:center;gap:var(--castle-space-base);display:flex}#chat-host .operator-line .icon-inline{flex:0 0 var(--castle-icon-size-inline)}#chat-host .operator-line .icon-inline:not(:first-child){color:var(--castle-text-dim)}#chat-host .operator-line-link{color:inherit;font:inherit;text-underline-offset:2px;cursor:pointer;background:0 0;border:0;padding:0;text-decoration:underline}#chat-host .operator-line-link:hover{color:var(--castle-text-primary)}#chat-host .msg-thinking summary{cursor:pointer;-webkit-user-select:none;user-select:none;list-style:none}#chat-host .msg-thinking summary::-webkit-details-marker{display:none}#chat-host .msg-thinking .thinking-caret{transform-origin:50%;transition:transform .12s}#chat-host .msg-thinking[open] .thinking-caret{transform:rotate(90deg)}#chat-host .msg-thinking.is-active .thinking-label{background-image:linear-gradient(90deg, var(--castle-text-muted) 20%, var(--castle-text-primary) 50%, var(--castle-text-muted) 80%);color:#0000;-webkit-text-fill-color:transparent;background-size:200% 100%;-webkit-background-clip:text;background-clip:text;animation:1.6s linear infinite thinking-shimmer;display:inline-block}@keyframes thinking-shimmer{0%{background-position:100% 0}to{background-position:-100% 0}}@media (prefers-reduced-motion:reduce){#chat-host .msg-thinking.is-active .thinking-label{color:var(--castle-text-muted);-webkit-text-fill-color:currentColor;background:0 0;animation:none}}#chat-host .msg-thinking-body{max-height:160px;padding:0 var(--castle-space-large) 0 calc(var(--castle-icon-size-inline) + var(--castle-space-base));border-radius:var(--castle-radius-small);background:var(--castle-surface-1);color:var(--castle-text-muted);font-size:var(--castle-text-size-base);overflow-y:auto}#chat-host .msg.md>:first-child,#chat-host .task-notes>:first-child{margin-top:0}#chat-host .msg.md>:last-child,#chat-host .task-notes>:last-child{margin-bottom:0}#chat-host .msg.md p:empty{display:none}#chat-host .msg.md p,#chat-host .task-notes p{margin:.4em 0}#chat-host .msg.md ul,#chat-host .msg.md ol,#chat-host .task-notes ul,#chat-host .task-notes ol{margin:.4em 0;padding-left:1.3em}#chat-host .task-notes li,#chat-host .msg.md li{margin:.1em 0}#chat-host .msg.md h1,#chat-host .msg.md h2,#chat-host .msg.md h3{margin:.5em 0 .3em;font-weight:700;line-height:1.25}#chat-host .msg.md h1{font-size:1.2em}#chat-host .msg.md h2{font-size:1.12em}#chat-host .msg.md h3{font-size:1.05em}#chat-host .msg.md a:not(.msg-link),#chat-host .msg-thinking-body a:not(.msg-link),#chat-host .task-notes a:not(.msg-link),#chat-host .task-feed-msg a:not(.msg-link){color:var(--castle-surface-light);text-underline-offset:2px;text-decoration:underline}#chat-host .msg-link{border-radius:var(--castle-radius-small);color:inherit;font-family:var(--castle-font-mono);-webkit-text-decoration-color:color-mix(in srgb, currentColor 40%, transparent);text-decoration-color:color-mix(in srgb, currentColor 40%, transparent);text-underline-offset:2px;margin:0 -.35em;padding:.1em .35em}#chat-host .msg-link:hover{background:var(--castle-surface-4);color:var(--castle-text-primary);text-decoration-color:currentColor}#chat-host .msg.assistant .msg-link:hover{background:color-mix(in srgb, var(--castle-accent) 84%, #fff)}#chat-host .msg.md code{font-family:var(--castle-font-mono);font-size:var(--castle-text-size-small);background:color-mix(in srgb, var(--castle-accent) 78%, #000);border-radius:var(--castle-radius-small);padding:.1em .35em}#chat-host .msg.md pre{margin:var(--castle-space-base) 0;padding:var(--castle-space-base) var(--castle-space-large);background:color-mix(in srgb, var(--castle-accent) 72%, #000);border-radius:var(--castle-radius-small);white-space:pre-wrap;word-break:break-word;font-family:var(--castle-font-mono);font-size:var(--castle-text-size-small);line-height:1.4;overflow-x:auto}#chat-host .msg.md pre code{background:0 0;border-radius:0;padding:0}#chat-host .msg.md blockquote{margin:var(--castle-space-base) 0;padding-left:var(--castle-space-large);border-left:3px solid color-mix(in srgb, var(--castle-accent) 60%, #fff)}.shell-root.docked #chat-host .operator-inset{min-height:0;padding:0 var(--operator-pad);flex-direction:column;flex:1 1 0;display:flex;overflow:hidden}.shell-root.docked #chat-host .chat-divider{margin:0 calc(-1 * var(--operator-pad));background:var(--castle-border-1);flex:0 0 1px}.task-stack{gap:var(--castle-space-small);flex-direction:column;display:flex}#task-board{min-height:0;margin-inline:calc(-1 * var(--castle-space-base));padding-inline:var(--castle-space-base);padding-top:0;padding-bottom:var(--castle-space-base);scrollbar-width:thin;scrollbar-color:transparent transparent;flex-direction:column;flex:0 auto;max-height:40vh;display:flex;overflow:hidden auto}#task-board.scrolling{scrollbar-color:var(--castle-text-dim) transparent}#task-board::-webkit-scrollbar{width:6px}#task-board::-webkit-scrollbar-track{background:0 0}#task-board::-webkit-scrollbar-thumb{background:0 0;border-radius:3px;transition:background .25s}#task-board.scrolling::-webkit-scrollbar-thumb{background:var(--castle-text-dim)}#chat-host .task{margin:0 calc(-1 * var(--castle-space-base));border-radius:var(--castle-radius-small);cursor:pointer;transition:background .12s,box-shadow .12s}#chat-host .task.open{background:var(--castle-surface-2);box-shadow:inset 0 0 0 1px var(--castle-border-1)}#chat-host .task:hover{background:var(--castle-surface-3)}#chat-host .task-row{align-items:center;gap:var(--castle-space-large);padding:var(--castle-space-small) var(--castle-space-base);display:flex;position:relative}#chat-host .task.open .task-row{align-items:flex-start;padding-bottom:0}#chat-host .pie{background:conic-gradient(var(--castle-surface-light) calc(var(--pct,0) * 3.6deg), var(--castle-surface-5) 0deg);border-radius:50%;flex:0 0 32px;width:32px;height:32px;padding:2px;display:flex;position:relative}#chat-host .pie .avatar{background:var(--castle-surface-3);width:100%;height:100%;color:var(--castle-text-dark);border-radius:50%;justify-content:center;align-items:center;display:flex;overflow:hidden}#chat-host .pie .avatar .avatar-icon-wrap{justify-content:center;align-items:center;width:16px;height:16px;font-size:16px;display:flex}#chat-host .pie .avatar .avatar-icon-wrap svg{width:16px;height:16px;display:block}#chat-host .task-meta{flex:1;min-width:0}#chat-host .task-head{align-items:center;gap:var(--castle-space-base);display:flex}#chat-host .task-text{flex:1;min-width:0}#chat-host .task-name{color:var(--castle-text-muted);font-size:var(--castle-text-size-base);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}#chat-host .task-name .tn{color:var(--castle-text-primary);font-weight:600}#chat-host .task-sub{color:var(--castle-text-muted);font-size:var(--castle-text-size-small);text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums;overflow:hidden}#chat-host .task-actions{align-items:center;gap:var(--castle-space-small);visibility:hidden;flex:none;margin-left:auto;display:flex}#chat-host .task:hover .task-actions,#chat-host .task.open .task-actions{visibility:visible}#chat-host .task-board-header{z-index:1;justify-content:space-between;align-items:center;gap:var(--castle-space-base);margin-inline:calc(-1 * var(--castle-space-base));padding:var(--castle-space-large) var(--castle-space-base) var(--castle-space-base);background:var(--castle-surface-1);display:flex;position:sticky;top:0}#chat-host .task-board-actions{align-items:center;gap:var(--castle-space-large);display:flex}#chat-host .task-board-status{font-size:var(--castle-text-size-base);color:var(--castle-text-muted)}#chat-host .task-body{padding:0 0 var(--castle-space-base);font-size:var(--castle-text-size-base);color:var(--castle-text-secondary);display:none}#chat-host .task.open .task-body{display:block}#chat-host .task-notes{margin-top:var(--castle-space-small);font-size:var(--castle-text-size-base);color:var(--castle-text-secondary);word-break:break-word}#chat-host .task-body>.feedback-note{margin-top:var(--castle-space-small)}#chat-host .task-notes code{border-radius:var(--castle-radius-small);font-family:var(--castle-font-mono);padding:1px 4px;font-size:12px}#chat-host .task-playtest-frames{margin-top:var(--castle-space-base)}#chat-host .task-playtest-frames-label{font-size:var(--castle-text-size-small);color:var(--castle-text-muted);margin-bottom:var(--castle-space-small)}#chat-host .task-playtest-frames-row{gap:var(--castle-space-base);flex-wrap:wrap;display:flex}#chat-host .task-playtest-frame{object-fit:cover;border:1px solid var(--castle-border-1);background:var(--castle-text-dark);border-radius:4px;width:64px;height:90px;display:block}#chat-host .task-feed{margin-top:var(--castle-space-base);scrollbar-width:none;-ms-overflow-style:none;max-height:96px;font-size:var(--castle-text-size-base);color:var(--castle-text-secondary);cursor:default;word-break:break-word;line-height:1.5;overflow:hidden auto;-webkit-mask-image:linear-gradient(#0000,#000 8px 100%);mask-image:linear-gradient(#0000,#000 8px 100%)}#chat-host .task-feed::-webkit-scrollbar{width:0;height:0}#chat-host .task-feed-tool{padding-left:var(--castle-space-large);color:var(--castle-text-muted);font-family:var(--castle-font-mono);white-space:pre-wrap;font-size:12px}#chat-host .task-feed-msg{margin:0}#chat-host .task-feed-msg>:first-child{margin-top:0}#chat-host .task-feed-msg>:last-child{margin-bottom:0}#chat-host .task-feed-msg p{margin:0}#chat-host .task-feed-msg code{font-family:var(--castle-font-mono);font-size:var(--castle-text-size-base)}#chat-host .task-page{min-height:0;margin-inline:calc(-1 * var(--operator-pad));flex-direction:column;flex:1 1 0;display:flex}#chat-host .task-page-header{padding:var(--castle-space-large) var(--operator-pad);border-bottom:1px solid var(--castle-border-1);flex:none}#chat-host .task-page-header .task-row{padding:0}#chat-host .task-page-header .tn{color:var(--castle-text-primary)}#chat-host .task-page-body{min-height:0;padding:var(--castle-space-large) var(--operator-pad);flex:1 1 0;overflow:auto}#chat-host .task-page-body .task-feed{max-height:none;margin-top:0;overflow:visible;-webkit-mask-image:none;mask-image:none}#chat-host .task-page-body:not(.task-board-page) .task-notes{margin-top:var(--castle-space-large);padding-top:var(--castle-space-large);border-top:1px solid var(--castle-border-1)}#chat-host .task-page-body:not(.task-board-page) .task-notes:first-child{border-top:0;margin-top:0;padding-top:0}#chat-host .task-report-label{margin:0 0 var(--castle-space-small);color:var(--castle-text-primary);font-weight:700}#chat-host .task-page-empty{color:var(--castle-text-muted);margin:0}#chat-host .task-board-page{min-height:0;margin-inline:calc(-1 * var(--operator-pad));padding:var(--castle-space-large) var(--operator-pad);flex-direction:column;flex:1 1 0;display:flex;overflow:auto}#chat-host .task-archive{margin-top:var(--castle-space-base);padding-top:var(--castle-space-large);border-top:1px solid var(--castle-border-1)}#chat-host .task-archive:first-child{border-top:0;margin-top:0;padding-top:0}#chat-host .task-archive-heading{margin:0 0 var(--castle-space-large);color:var(--castle-text-muted)}#chat-host .operator-composer{flex-direction:column;flex:0 auto;min-height:0;max-height:50%;display:flex;overflow:auto}.chat-input{padding:0 var(--operator-pad) var(--operator-pad);flex:none;position:relative}#chat-host .chat-input .ta{width:100%;min-height:60px;padding:var(--castle-space-base) var(--castle-space-small);border:1px solid var(--castle-border-1);border-radius:var(--castle-radius-base);background:var(--castle-surface-2);cursor:text;flex-direction:column;display:flex;overflow:hidden}#chat-input{width:100%;min-height:21px;max-height:120px;padding:0 var(--castle-space-base);color:var(--castle-text-primary);font:inherit;font-size:var(--castle-text-size-base);resize:none;scrollbar-width:none;-ms-overflow-style:none;background:0 0;border:none;outline:none;line-height:1.5;display:block;overflow-y:auto}#chat-input::-webkit-scrollbar{width:0;height:0}#chat-input::placeholder{color:var(--castle-text-muted)}#chat-host .chat-input .ta-bottom{justify-content:space-between;align-items:center;gap:var(--castle-space-base);min-width:0;display:flex}#chat-host .composer-settings{flex:auto;min-width:0}#chat-host .composer-settings .button{min-width:0;max-width:100%;font-size:var(--castle-text-size-small);justify-content:flex-start}#chat-host .composer-settings .operator-usage-warn,#chat-host .composer-settings .operator-usage-warn:hover,#chat-host .composer-settings .operator-usage-warn[aria-pressed=true]{color:var(--castle-warn-text)}#chat-host .composer-settings .operator-usage-blocked,#chat-host .composer-settings .operator-usage-blocked:hover,#chat-host .composer-settings .operator-usage-blocked[aria-pressed=true]{color:var(--castle-danger-text)}#chat-host .queue-row .button,#chat-host .ta-bottom .button-icon{flex-shrink:0}#chat-host .composer-action{margin-right:var(--castle-space-small)}#chat-pending{gap:var(--castle-space-base);padding:0 var(--operator-pad) var(--castle-space-base);flex:none;display:flex}#chat-pending .operator-thumb{object-fit:cover;border:1px solid var(--castle-border-1);border-radius:var(--castle-radius-small);cursor:pointer;width:64px;height:44px;margin:0;display:block}#chat-host .chat-input .chat-queue{gap:var(--castle-space-small);margin-bottom:var(--castle-space-base);flex-direction:column;display:flex}#chat-host .chat-input .queue-row{align-items:center;gap:var(--castle-space-base);padding:var(--castle-space-base) var(--castle-space-base) var(--castle-space-base) var(--castle-space-large);border:1px dashed var(--castle-border-1);border-radius:var(--castle-radius-base);background:var(--castle-surface-1);color:var(--castle-text-muted);font-size:var(--castle-text-size-base);display:flex}#chat-host .chat-input .queue-snippet{text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}#chat-host .picker{gap:var(--castle-space-large);width:100%;padding:var(--castle-space-large);border:1px solid var(--castle-border-1);border-radius:var(--castle-radius-base);background:var(--castle-surface-3);flex-direction:column;align-self:stretch;margin:0;display:flex}#chat-host .picker-q{border:none;min-width:0;margin:0;padding:0}#chat-host .picker-q-label{margin:0 0 var(--castle-space-base);color:var(--castle-text-primary);font-size:var(--castle-text-size-base);font-weight:inherit;padding:0}#chat-host .picker-options{gap:var(--castle-space-small);flex-direction:column;display:flex}#chat-host .picker-option{align-items:center;gap:var(--castle-space-base);padding:var(--castle-space-small) var(--castle-space-base);border-radius:var(--castle-radius-small);color:var(--castle-text-secondary);cursor:pointer;display:flex}#chat-host .picker-option input{appearance:none;border:1px solid var(--castle-border-2);border-radius:var(--castle-radius-small);background:var(--castle-surface-3);width:12px;height:12px;cursor:inherit;flex:none;place-content:center;margin:0;display:grid}#chat-host .picker-option input[type=radio]{border-radius:var(--castle-radius-pill)}#chat-host .picker-option input:checked{border-color:var(--castle-surface-light);background:var(--castle-surface-light)}#chat-host .picker-option input:before{content:"";display:block}#chat-host .picker-option input[type=radio]:checked:before{border-radius:var(--castle-radius-pill);background:var(--castle-text-dark);width:4px;height:4px}#chat-host .picker-option input[type=checkbox]:checked:before{border-left:1.5px solid var(--castle-text-dark);border-bottom:1.5px solid var(--castle-text-dark);width:6px;height:3px;margin-top:-2px;transform:rotate(-45deg)}#chat-host .picker:not(.picker-locked) .picker-option:hover,#chat-host .picker-option.is-checked{background:var(--castle-surface-5);color:var(--castle-text-primary)}#chat-host .picker-option:has(input:checked){background:var(--castle-surface-5);color:var(--castle-text-primary)}#chat-host .picker-locked{opacity:.72}#chat-host .picker-locked .picker-option{cursor:default}#chat-host .picker-actions{justify-content:flex-end;display:flex}#chat-host .chips{justify-content:flex-end;align-self:flex-end;gap:var(--castle-space-base);max-width:85%;margin:var(--castle-space-small) 0 var(--castle-space-small);flex-wrap:wrap;display:flex}#chat-host .chip{padding:var(--castle-space-base) var(--castle-space-large);border:1px dotted var(--castle-surface-light);border-radius:var(--castle-radius-pill);color:var(--castle-surface-light);font:inherit;font-size:var(--castle-text-size-base);text-align:left;cursor:pointer;background:0 0;line-height:1.3}#chat-host .chips-inert .chip{border-color:var(--castle-text-dim);color:var(--castle-text-muted);cursor:default}#chat-host .chip.is-picked,#chat-host .chips-inert .chip.is-picked{border-style:solid;border-color:var(--castle-surface-light);background:var(--castle-surface-light);color:var(--castle-text-dark)}#chat-host .msg-file{color:inherit;font:inherit;text-underline-offset:2px;text-decoration:underline;-webkit-text-decoration-color:color-mix(in srgb, currentColor 40%, transparent);text-decoration-color:color-mix(in srgb, currentColor 40%, transparent);cursor:pointer;word-break:break-all;background:0 0;border:0;margin:0;padding:0;display:inline}#chat-host .msg-file:hover{text-decoration-color:currentColor}#chat-host .picker-skeleton{pointer-events:none}#chat-host .picker-skeleton-hint{color:var(--castle-text-muted);font-size:var(--castle-text-size-base)}#chat-host .picker-skeleton-line,#chat-host .picker-skeleton-chip{border-radius:var(--castle-radius-small);background:var(--castle-border-1);display:block}#chat-host .picker-skeleton-label{width:60%;height:11px;margin-bottom:var(--castle-space-base)}#chat-host .picker-skeleton-chip{height:24px}.xterm,.xterm-viewport,.xterm-screen,.xterm-helpers{background-color:#0000!important}.xterm{overscroll-behavior:contain}.xterm-viewport{overscroll-behavior:contain;scrollbar-width:none;-ms-overflow-style:none}.xterm-viewport::-webkit-scrollbar{width:0;height:0}.xterm .xterm-scrollable-element>.scrollbar,.xterm .xterm-scrollable-element>.scrollbar.visible,.xterm .xterm-scrollable-element>.visible.scrollbar,.xterm .xterm-scrollable-element>.invisible.scrollbar,.xterm .xterm-scrollable-element>.xterm-scrollbar{opacity:0!important;pointer-events:none!important;width:0!important;min-width:0!important;height:0!important;min-height:0!important;display:none!important}.xterm .xterm-scrollable-element>.scrollbar>.slider,.xterm .xterm-scrollable-element>.scrollbar>.scra,.xterm .xterm-scrollable-element>.xterm-scrollbar>.xterm-slider{width:0!important;height:0!important;display:none!important}.xterm .xterm-scrollable-element>.shadow{display:none!important}.quick-open-backdrop{z-index:2147483100;justify-content:center;align-items:flex-start;padding-top:12vh;display:flex;position:fixed;inset:0}.quick-open{background:#232323;border:1px solid #3a3a3a;border-radius:8px;flex-direction:column;width:min(600px,90vw);max-height:60vh;display:flex;overflow:hidden;box-shadow:0 16px 48px #0009}.quick-open-input{color:#f0f0f0;background:#161616;border:1px solid #4a4a4a;border-radius:5px;outline:none;flex:none;margin:8px;padding:8px 10px;font-size:14px}.quick-open-input:focus{border-color:#5a8bd6}.quick-open-list{flex:auto;padding:4px;overflow-y:auto}.quick-open-item{color:#e6e6e6;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:4px;align-items:baseline;gap:8px;width:100%;padding:5px 8px;font-size:13px;display:flex}.quick-open-item.active{background:#37506f}.quick-open-name{white-space:nowrap;flex:none}.quick-open-dir{text-overflow:ellipsis;white-space:nowrap;color:#8a8a8a;flex:auto;min-width:0;font-size:12px;overflow:hidden}.quick-open-empty{color:#8a8a8a;text-align:center;padding:12px;font-size:13px}.quick-open-keys{color:#b0b0b0;white-space:nowrap;border:1px solid #4a4a4a;border-radius:4px;flex:none;margin-left:8px;padding:1px 6px;font-family:SFMono-Regular,Consolas,monospace;font-size:11px}.mention-picker{z-index:2147483100;background:#232323;border:1px solid #3a3a3a;border-radius:8px;width:min(360px,90vw);max-height:40vh;padding:4px;position:fixed;overflow-y:auto;box-shadow:0 16px 48px #0009}.mention-item{color:#e6e6e6;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:4px;align-items:baseline;gap:8px;width:100%;padding:5px 8px;font-size:13px;display:flex}.mention-item.active{background:#37506f}.mention-name{white-space:nowrap;flex:none}.mention-dir{text-overflow:ellipsis;white-space:nowrap;color:#8a8a8a;flex:auto;min-width:0;font-size:12px;overflow:hidden}.chord-hint{z-index:2147483200;color:#c7c7c7;background:#232323;border:1px solid #3a3a3a;border-radius:8px;align-items:center;gap:8px;padding:6px 12px;font-size:12px;display:flex;position:fixed;bottom:24px;left:50%;transform:translate(-50%);box-shadow:0 8px 24px #0000008c}.chord-hint kbd{color:#f0f0f0;background:#333;border:1px solid #4a4a4a;border-radius:4px;padding:2px 7px;font-family:SFMono-Regular,Consolas,monospace;font-size:12px}@media (pointer:coarse){input,textarea,select,[contenteditable]:not(.cm-content){font-size:16px!important}}.cm-url,.cm-md-link{color:var(--v2-link,#82aaff);text-underline-offset:2px;cursor:pointer;text-decoration:underline;text-decoration-thickness:1px}.cm-url:hover,.cm-md-link:hover{color:var(--v2-white,#fff)}.castle-file-panel,.castle-code-panel,.castle-params-panel,.castle-params-overlay,.flow-class-files{--castle-font-mono:"SFMono-Regular", Consolas, "Liberation Mono", monospace;--castle-black:var(--v2-ink);--castle-panel-raised:var(--v2-raised);--castle-border:#444;--castle-text:var(--v2-white);--castle-text-dim:var(--v2-muted);--castle-inspector-bg:var(--v2-surface);--castle-inspector-text:var(--v2-fg);--castle-inspector-muted:var(--v2-muted);--castle-inspector-border:var(--v2-border);--castle-inspector-divider:var(--v2-border);--castle-inspector-input-bg:var(--v2-raised);--castle-workspace-bg:var(--v2-surface);--castle-sheet-bg:var(--v2-surface);--castle-radius:4px}.castle-file-panel{background:var(--castle-sheet-bg);flex-direction:column;height:100%;display:flex;overflow:hidden;transform:translateZ(0)}.castle-file-panel>.fileBrowserBare{flex:1 1 0;height:auto;min-height:0}.castle-file-toolbar{border-bottom:1px solid var(--castle-inspector-border);flex-wrap:wrap;flex:none;align-items:center;gap:6px;padding:6px 8px;display:flex}.castle-file-toolbar .button-icon{margin-left:auto}.castle-file-toolbar .button-icon+.button-icon{margin-left:0}.castle-file-toolbar.versions-toolbar{padding-left:var(--castle-space-large);justify-content:space-between}.versions-toolbar-label{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--castle-text-muted);line-height:1;overflow:hidden}.castle-versions{flex-direction:column;flex:1 1 0;min-height:0;display:flex}.versions-error{align-items:flex-start}.versions-error>span:not(.icon-cell){white-space:pre-line}.versions-save{align-items:center;gap:var(--castle-space-base);flex-wrap:wrap;padding:0;display:flex}.versions-save .text-field{flex:130px;width:auto;min-width:0}.versions-save .button{white-space:nowrap;flex:none}.versions-note{padding:var(--castle-space-large) var(--castle-space-large) 0;color:var(--castle-text-muted);font-size:var(--castle-text-size-base)}.versions-empty{padding:var(--castle-space-large);color:var(--castle-text-muted);font-size:var(--castle-text-size-base)}.castle-versions-list{flex:1 1 0;min-height:0;overflow-y:auto}.version{align-items:start;column-gap:var(--castle-space-base);padding:var(--castle-space-base) var(--castle-space-base) var(--castle-space-large);border-bottom:1px solid var(--castle-border-1);grid-template-columns:minmax(0,1fr) auto;display:grid}.version-toggle{grid-template-columns:var(--castle-button-height) minmax(0, 1fr);align-items:start;column-gap:var(--castle-space-base);min-width:0;color:inherit;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;grid-area:1/1/auto/-1;margin:0;padding:0;display:grid}.version.is-expanded:not(.version-new) .version-toggle{grid-column:1}.version-toggle:focus-visible{outline:1px solid var(--castle-border-2);outline-offset:2px}.version.later,.version.later .icon-cell,.version.later .version-message,.version.later .version-nomessage,.version.later .version-meta,.version.later .version-summary{color:var(--castle-text-dim)}.version:hover{background:var(--castle-surface-3)}.version-main{gap:var(--castle-space-small);flex-direction:column;min-width:0;display:flex}.version-heading{align-items:center;gap:var(--castle-space-base);min-width:0;min-height:var(--castle-button-height);display:flex}.version-message{text-overflow:ellipsis;white-space:nowrap;min-width:0;color:var(--castle-text-primary);font-size:var(--castle-text-size-base);flex:auto;overflow:hidden}.version-nomessage{color:var(--castle-text-muted);font-style:italic}.version-meta{color:var(--castle-text-muted);font-size:var(--castle-text-size-small);margin:0;display:block}.version-actions{min-height:var(--castle-button-height);flex:none;grid-area:1/2;align-items:center;display:none}.version.is-expanded .version-actions{display:flex}.version-detail{padding-left:calc(var(--castle-button-height) + var(--castle-space-base));grid-column:1/-1;display:none}.version-new{flex:none}.version.is-expanded .version-detail{gap:var(--castle-space-small);flex-direction:column;display:flex}.version-summary{color:var(--castle-text-secondary);font-size:var(--castle-text-size-base);overflow-wrap:anywhere;margin:0}.files-feedback-banner{flex:none}.fileEditInput{border:1px solid var(--castle-border);background:var(--castle-inspector-input-bg);min-width:0;color:var(--castle-inspector-text);font:inherit;border-radius:3px;flex:auto;padding:1px 4px;font-size:13px}.fileEditInput:focus{border-color:#5a8bd6;outline:none}.castle-file-menu{z-index:1000;min-width:168px;position:fixed}.castle-file-menu .menu-keys{font-family:SFMono-Regular,Consolas,monospace}.castle-file-picker{gap:var(--castle-space-small);flex-direction:column;min-width:180px;display:flex}.castle-file-picker .text-field{width:100%}.castle-file-picker-label{color:var(--castle-text-muted);margin:0}.castle-file-picker-list{gap:var(--castle-space-small);flex-direction:column;max-height:min(40vh,180px);display:flex;overflow-y:auto}.castle-file-picker-list[hidden]{display:none}.fileBrowserBare{flex-direction:column;min-width:0;height:100%;display:flex}.fileTree{min-height:0;padding:var(--castle-space-base);flex:1 1 0;overflow-y:auto}.fileBranch{min-width:0}.file-row,.file-row.folder-row{align-items:center;gap:var(--castle-space-base);width:100%;min-width:0;height:var(--castle-button-height);margin:0 0 var(--castle-space-small);padding:0 var(--castle-space-base);padding-left:calc(var(--castle-space-base) + var(--file-depth,0) * (var(--castle-button-icon-size) + var(--castle-space-base)));border-radius:var(--castle-radius-small);color:var(--castle-text-secondary);font-size:var(--castle-text-size-base);text-align:left;cursor:pointer;background:0 0;border:0;line-height:1;display:flex}.file-row.folder-row{color:var(--castle-text-muted)}.file-row>span:not(.icon-slot):not(.icon-inline):not(.icon-cell){text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.file-row:hover{background:var(--castle-surface-3);color:var(--castle-text-primary)}.file-row.imported-row{color:var(--castle-text-muted);font-style:italic}.file-row.forked-row{color:var(--castle-text-secondary);font-style:normal}.file-row.selected-row,.file-row.selected-row:hover{background:var(--castle-surface-4);color:var(--castle-text-primary)}.file-row.hidden-row{color:var(--castle-text-dim)}:is(.file-row:has(.button-icon),.file-row:has(.icon-cell)){padding-right:0}.file-row .button-icon,.file-row .icon-cell{margin-left:auto}.file-row.edit-row{height:auto;min-height:var(--castle-button-height);cursor:default;flex-wrap:wrap}.file-row.edit-row .text-field{flex:auto;width:auto}.file-suffix{color:var(--castle-text-muted);flex:none}.file-row .file-edit-feedback{padding-left:calc(var(--castle-button-icon-size) + var(--castle-space-base));padding-bottom:var(--castle-space-small);font-size:var(--castle-text-size-small);white-space:normal;flex:1 0 100%;line-height:1.45;overflow:visible}.flow-root.is-mobile .castle-file-panel,.flow-mobile-switch{--castle-button-height:var(--castle-button-height-large)}.flow-mobile-switch{--castle-text-size-small:14px;--castle-text-size-base:16px;--castle-text-style-smallcaps-size:var(--castle-text-size-small)}.flow-root.is-mobile .castle-file-panel .button:not(.button-icon){padding-left:var(--castle-space-large);padding-right:var(--castle-space-large)}.flow-root.is-mobile .file-row,.flow-mobile-switch .file-row{margin-bottom:0}.flow-root.is-mobile .file-row>span:not(.icon-slot):not(.icon-inline):not(.icon-cell),.flow-mobile-switch .file-row>span:not(.icon-slot):not(.icon-inline):not(.icon-cell){line-height:var(--castle-button-height)}.flow-root.is-mobile .file-row:hover,.flow-mobile-switch .file-row:hover{color:var(--castle-text-secondary);background:0 0}.flow-root.is-mobile .file-row.folder-row:hover,.flow-root.is-mobile .file-row.imported-row:hover,.flow-mobile-switch .file-row.folder-row:hover,.flow-mobile-switch .file-row.imported-row:hover{color:var(--castle-text-muted)}.flow-root.is-mobile .file-row.hidden-row:hover,.flow-mobile-switch .file-row.hidden-row:hover{color:var(--castle-text-dim)}.flow-root.is-mobile .file-row.selected-row:hover,.flow-mobile-switch .file-row.selected-row:hover{background:var(--castle-surface-4);color:var(--castle-text-primary)}.flow-root.is-mobile .version:hover{background:0 0}.castle-code-panel{flex-direction:column;width:100%;height:100%;display:flex;position:relative}.mainEditor{background:var(--castle-sheet-bg);flex-direction:column;flex:1 1 0;width:100%;min-width:0;height:100%;min-height:0;display:flex}.editorBody{flex:1;min-height:0;display:flex;overflow:hidden;container:editor/inline-size}.codeEditor{background:var(--castle-workspace-bg);flex:1;grid-template-columns:1fr;min-width:0;min-height:0;display:grid}.codeMirrorHost{min-width:0;height:100%;min-height:0}.castle-code-overlay{color:var(--castle-inspector-muted);pointer-events:none;font-size:12px;position:absolute;top:10px;left:12px}.castle-code-overlay.castle-code-error{color:var(--v2-error)}.castle-code-savebar{background:var(--v2-error-bg);color:var(--v2-error);padding:4px 10px;font-size:11px;position:absolute;bottom:0;left:0;right:0}.castle-tab-import{color:var(--v2-muted);font-style:italic}.castle-modal-scrim{z-index:1000;background:#00000080;justify-content:center;align-items:center;display:flex;position:fixed;inset:0}.castle-modal{color:#e8e8e8;background:#232323;border:1px solid #3a3a3a;border-radius:6px;min-width:260px;max-width:380px;padding:16px;font-size:13px;box-shadow:0 8px 24px #0000008c}.castle-modal-text{margin-bottom:14px}.castle-modal-actions{justify-content:flex-end;gap:8px;margin-top:16px;display:flex}.castle-modal-actions button,.castle-import-link-row button{color:#e8e8e8;cursor:pointer;background:#2e2e2e;border:1px solid #3a3a3a;border-radius:4px;padding:5px 12px;font-size:12px}.castle-modal-actions button:hover:not(:disabled),.castle-import-link-row button:hover:not(:disabled){background:#383838}.castle-modal-actions button:disabled,.castle-import-link-row button:disabled{opacity:.6;cursor:default}.castle-upload-modal{flex-direction:column;gap:10px;width:min(460px,100vw - 24px);max-width:none;max-height:calc(100vh - 32px);display:flex;overflow-y:auto}.castle-upload-modal>.castle-modal-text{margin-bottom:0}.castle-upload-modal>.castle-file-picker{width:100%;min-width:0}.castle-upload-input{opacity:0;pointer-events:none;width:1px;height:1px;position:absolute}.castle-upload-drop{justify-content:center;align-items:center;gap:var(--castle-space-small);width:100%;padding:calc(var(--castle-space-large) + var(--castle-space-base)) var(--castle-space-large);border:1px dashed var(--castle-border-3);border-radius:var(--castle-radius-small);background:var(--castle-surface-3);color:var(--castle-text-primary);font:inherit;cursor:pointer;flex-direction:column;display:flex}.castle-upload-drop:hover,.castle-upload-drop.over{border-color:var(--castle-border-2);background:var(--castle-surface-5)}.castle-upload-drop svg{font-size:var(--castle-button-icon-size)}.castle-upload-drop-label{font-size:var(--castle-text-size-base)}.castle-upload-drop-hint{color:var(--castle-text-muted);font-size:var(--castle-text-size-small)}.castle-upload-picked{flex-direction:column;max-height:132px;display:flex;overflow-y:auto}.castle-upload-picked-row{align-items:center;gap:var(--castle-space-base);min-height:var(--castle-button-height);padding:var(--castle-space-small) 0;display:flex}.castle-upload-picked-row+.castle-upload-picked-row{border-top:1px solid var(--castle-border-1)}.castle-upload-picked-name{min-width:0;font-size:var(--castle-text-size-base);flex-direction:column;flex:auto;justify-content:center;display:flex}.castle-upload-picked-label{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.castle-upload-picked-name .text-field{width:100%}.castle-upload-picked-warning{color:var(--castle-warn-text);font-size:var(--castle-text-size-small);white-space:normal;margin-top:2px;display:block}.castle-upload-picked-size{color:var(--castle-text-muted);font-size:var(--castle-text-size-small);font-variant-numeric:tabular-nums;flex:none}.castle-upload-status{text-overflow:ellipsis;white-space:nowrap;opacity:.7;text-align:left;flex:auto;min-width:0;font-size:12px;overflow:hidden}@media (width<=520px){.castle-upload-modal{width:calc(100vw - 16px);min-width:0;padding:12px}.castle-upload-drop{padding:var(--castle-space-large) var(--castle-space-base)}.castle-upload-picked{max-height:104px}.castle-file-picker-list{max-height:132px}}.castle-import-modal{flex-direction:column;width:min(520px,100vw - 32px);max-width:none;height:min(560px,100vh - 64px);max-height:none;display:flex}.castle-import-modal>.castle-modal-text,.castle-import-modal>.castle-key-tabs,.castle-import-modal>.castle-import-select-bar,.castle-import-modal>.castle-import-filter,.castle-import-modal>.castle-import-note,.castle-import-modal>.castle-import-error,.castle-import-modal>.castle-modal-actions{flex:none}.castle-import-select-bar{align-items:center;gap:10px;margin-bottom:8px;display:flex}.castle-import-select-all{padding:4px 8px}.castle-import-update-row{align-items:center}.castle-import-tick{color:#1b1b1b;border:1px solid #5a5a5a;border-radius:3px;flex:none;justify-content:center;align-items:center;width:16px;height:16px;font-size:10px;display:flex}.castle-import-tick.checked{background:#8ab4f8;border-color:#8ab4f8}.castle-import-filter{margin-bottom:8px}.castle-import-empty{color:#9a9a9a;text-align:center;flex:auto;justify-content:center;align-items:center;min-height:0;padding:10px;font-size:11px;display:flex}.castle-import-tabs .castle-key-tab{min-height:34px}.castle-import-list{background:#1b1b1b;border:1px solid #3a3a3a;border-radius:4px;flex:auto;min-height:0;overflow-y:auto}.castle-import-row{color:#e8e8e8;width:100%;font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-bottom:1px solid #2e2e2e;gap:10px;padding:8px;font-size:12px;display:flex}.castle-import-row:last-child{border-bottom:0}.castle-import-row:hover{background:#262626}.castle-import-row.selected{background:#3a3a3a}.castle-import-row.disabled{opacity:.5}.castle-import-thumb{object-fit:cover;background:#2e2e2e;border-radius:3px;flex:none;width:56px;height:79px}.castle-import-row-text{flex-direction:column;gap:3px;min-width:0;display:flex}.castle-import-row-title{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.castle-import-row-meta{color:#9a9a9a;font-size:11px}.castle-import-link{flex-direction:column;flex:auto;gap:8px;min-height:0;display:flex}.castle-import-link-row{gap:8px;display:flex}.castle-import-link-row button{white-space:nowrap}.castle-import-note{color:#9a9a9a;padding:10px 2px;font-size:11px}.castle-import-error{color:#ff8f8f;margin-top:8px;font-size:11px}.castle-code-params-strip{border:0;border-bottom:1px solid var(--castle-inspector-border);background:var(--castle-inspector-input-bg);width:100%;color:var(--castle-inspector-muted);font:inherit;text-align:left;cursor:pointer;align-items:center;gap:8px;padding:6px 12px;font-size:12px;display:flex}.castle-code-params-strip:hover{color:var(--castle-inspector-text)}.castle-code-params-icon{flex:none;display:inline-flex}.castle-code-params-count{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.castle-code-params-action{color:var(--castle-inspector-text);flex:none;margin-left:auto}.castle-code-selection-bar{z-index:2;position:absolute;bottom:12px;right:12px}.castle-params-panel{background:var(--castle-sheet-bg);height:100%;color:var(--castle-inspector-text);-webkit-overflow-scrolling:touch;font-size:14px;overflow:hidden auto}.paramsFields{padding:10px 16px 24px}.paramsGroup+.paramsGroup{margin-top:6px}.paramsGroupTitle{color:var(--castle-inspector-muted);text-transform:uppercase;letter-spacing:.06em;margin:0 0 10px;font-size:12px}.paramsGroup+.paramsGroup>.paramsGroupTitle{border-top:1px solid var(--castle-inspector-divider);margin-top:10px;padding-top:10px}.paramsNotice{color:var(--castle-inspector-muted);padding:16px}.paramsSaveError{border-bottom:1px solid var(--castle-inspector-border);color:var(--castle-inspector-text);background:#be464629;padding:8px 16px;font-size:13px}.paramsScopeBar{z-index:2;border-bottom:1px solid var(--castle-inspector-border);background:var(--castle-sheet-bg);align-items:center;gap:8px;padding:6px 10px;display:flex;position:sticky;top:0}.paramsScopeButton{border:1px solid var(--castle-inspector-border);border-radius:var(--castle-radius);background:var(--castle-inspector-input-bg);min-width:0;color:var(--castle-inspector-text);font:inherit;cursor:pointer;align-items:center;gap:6px;padding:4px 8px;font-size:13px;display:flex}.paramsScopeIcon,.paramsScopeChevron{flex:none;display:inline-flex}.paramsScopeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.paramsScopeSummary{color:var(--castle-inspector-muted);font-size:12px}.paramsScopeMenu{max-width:calc(100% - 16px);max-height:60vh;position:absolute;top:100%;left:8px;overflow-y:auto}.paramsScopeMenu .menu-item-label{text-overflow:ellipsis;white-space:nowrap;text-align:left;direction:rtl;overflow:hidden}.paramsScopeDivider{color:var(--castle-inspector-muted);text-transform:uppercase;letter-spacing:.06em;padding:6px 10px 4px;font-size:11px}.paramsScopeCount,.paramsFileCount{color:var(--castle-inspector-muted);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;padding-left:10px;font-size:12px}.paramsFile+.paramsFile{border-top:1px solid var(--castle-inspector-divider)}.paramsFileHead{align-items:center;padding:0 6px 0 0;display:flex}.paramsFileHead~.paramsFields{padding-bottom:6px}.paramsFileToggle{min-width:0;color:var(--castle-inspector-text);font:inherit;text-align:left;cursor:pointer;background:0 0;border:0;flex:1;align-items:center;gap:6px;padding:8px 4px 8px 10px;font-size:12px;display:flex}.paramsFileChevron{color:var(--castle-inspector-muted);flex:none;display:inline-flex}.paramsFilePath{text-overflow:ellipsis;white-space:nowrap;text-align:left;min-width:0;font-family:var(--castle-font-mono);direction:rtl;overflow:hidden}.paramsFileOpen{border-radius:var(--castle-radius);color:var(--castle-inspector-muted);cursor:pointer;background:0 0;border:0;flex:none;padding:4px 6px;display:inline-flex}.paramsFileOpen:hover{color:var(--castle-inspector-text)}.paramsScopeBar .paramsFileOpen{margin-left:auto}.paramsEmpty{max-width:46em;padding:20px 16px}.paramsEmptyLead{color:var(--castle-inspector-text);margin:0 0 10px;font-size:15px}.paramsEmptyBody{color:var(--castle-inspector-muted);margin:0 0 12px;line-height:1.5}.paramsEmpty code{font-family:var(--castle-font-mono);color:var(--castle-inspector-text);font-size:13px}.paramsEmptyCode{border:1px solid var(--castle-inspector-border);border-radius:var(--castle-radius);background:var(--castle-inspector-input-bg);color:var(--castle-inspector-text);font-family:var(--castle-font-mono);margin:0 0 14px;padding:10px 12px;font-size:13px;line-height:1.45;overflow-x:auto}.castle-params-panel .paramExpr{text-overflow:ellipsis;white-space:nowrap;border:1px dashed var(--castle-inspector-border);border-radius:var(--castle-radius);min-width:0;color:var(--castle-inspector-muted);font-family:var(--castle-font-mono);cursor:default;padding:5px 8px;font-size:13px;overflow:hidden}.castle-params-panel .fieldRow{grid-template-columns:minmax(82px,.5fr) minmax(0,1fr);align-items:center;gap:12px;min-height:28px;padding-bottom:12px;display:grid}.castle-params-panel .fieldRow.paramFieldRevealed{animation:1.4s ease-out paramFieldReveal}@keyframes paramFieldReveal{0%,60%{background:var(--castle-inspector-input-bg);box-shadow:0 0 0 4px var(--castle-inspector-input-bg)}to{background:0 0;box-shadow:0 0 0 4px #0000}}.castle-params-panel .fieldLabel{color:var(--castle-inspector-text);text-overflow:ellipsis;font-size:14px;overflow:hidden}.castle-params-panel .input{border:1px solid var(--castle-inspector-border);border-radius:var(--castle-radius);background:var(--castle-inspector-input-bg);width:100%;color:var(--castle-inspector-text);font:inherit;outline:0;padding:5px 8px}.castle-params-panel .numberField{width:100%;position:relative}.castle-params-panel .numberInput{appearance:textfield}.castle-params-panel .numberInput::-webkit-inner-spin-button{appearance:none;margin:0}.castle-params-panel .numberInput::-webkit-outer-spin-button{appearance:none;margin:0}.castle-params-panel .numberScrub{cursor:ew-resize;-webkit-user-select:none;user-select:none;align-items:center;gap:6px;display:flex;position:relative;overflow:hidden}.castle-params-panel .numberValue{z-index:1;text-align:right;font-variant-numeric:tabular-nums;flex:auto;min-width:0;position:relative}.castle-params-panel .scrubGrip{z-index:1;color:var(--castle-inspector-muted);letter-spacing:-2px;opacity:.4;flex:none;font-size:12px;line-height:1;position:relative}.castle-params-panel .colorInput{border:1px solid var(--castle-inspector-border);border-radius:var(--castle-radius);background:var(--castle-inspector-input-bg);cursor:pointer;outline:0;width:100%;height:28px;padding:2px}.castle-params-panel .checkbox{border:1px solid var(--castle-inspector-border);border-radius:var(--castle-radius);background:var(--castle-inspector-input-bg);cursor:pointer;width:20px;height:20px;box-shadow:none;color:var(--castle-text);flex:none;justify-content:center;justify-self:end;align-items:center;padding:0;display:flex}.castle-params-panel .checkboxOn{background:var(--castle-black)}.castle-params-panel .checkboxMark{width:12px;height:12px;display:none}.castle-params-panel .checkboxOn .checkboxMark{display:block}.castle-params-overlay .scrubBubble{z-index:1001;border:1px solid var(--castle-inspector-border);color:var(--castle-inspector-text);font-variant-numeric:tabular-nums;pointer-events:none;background:#14181ef5;border-radius:8px;padding:3px 10px;font-size:15px;position:fixed;transform:translate(-50%,-100%);box-shadow:0 2px 10px #00000073}.castle-params-overlay .numpadBackdrop{z-index:1000;background:#00000059;flex-direction:column;justify-content:flex-end;display:flex;position:fixed;inset:0}.castle-params-overlay .numpadSheet{background:var(--castle-inspector-bg,#16181d);border-top:1px solid var(--castle-inspector-border);padding:10px 10px calc(10px + env(safe-area-inset-bottom,0px));border-radius:14px 14px 0 0;box-shadow:0 -8px 24px #0006}.castle-params-overlay .numpadValueRow{justify-content:space-between;align-items:baseline;gap:12px;padding:6px 8px 12px;display:flex}.castle-params-overlay .numpadValueLabel{color:var(--castle-inspector-text);text-overflow:ellipsis;white-space:nowrap;min-width:0;font-size:22px;overflow:hidden}.castle-params-overlay .numpadValueNum{color:var(--castle-inspector-text);font-variant-numeric:tabular-nums;flex:none;font-size:22px}.castle-params-overlay .numpadGrid{grid-template-columns:repeat(4,1fr);gap:8px;display:grid}.castle-params-overlay .numpadKey{border:1px solid var(--castle-inspector-border);background:var(--castle-inspector-input-bg);height:52px;color:var(--castle-inspector-text);cursor:pointer;touch-action:manipulation;border-radius:10px;font-size:20px}.castle-params-overlay .numpadKey:active{background:var(--castle-inspector-divider)}.castle-params-overlay .numpadKeyZero{grid-column:span 3}.castle-params-overlay .numpadKeyDone{color:#fff;background:#5a8cd2e6;border-color:#0000;font-size:16px}.xterm{cursor:text;-webkit-user-select:none;user-select:none;position:relative}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{z-index:5;position:absolute;top:0}.xterm .xterm-helper-textarea{opacity:0;z-index:-5;white-space:nowrap;resize:none;border:0;width:0;height:0;margin:0;padding:0;position:absolute;top:0;left:-9999em;overflow:hidden}.xterm .composition-view{color:#fff;white-space:nowrap;z-index:1;background:#000;display:none;position:absolute}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{cursor:default;background-color:#000;position:absolute;inset:0;overflow-y:scroll}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;top:0;left:0}.xterm-char-measure-element{visibility:hidden;line-height:normal;display:inline-block;position:absolute;top:0;left:-9999em}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{z-index:10;color:#0000;pointer-events:none;position:absolute;inset:0}.xterm .xterm-accessibility-tree:not(.debug) ::selection{color:#0000}.xterm .xterm-accessibility-tree{-webkit-user-select:text;user-select:text;white-space:pre;font-family:monospace}.xterm .xterm-accessibility-tree>div{transform-origin:0;width:fit-content}.xterm .live-region{width:1px;height:1px;position:absolute;left:-9999px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{-webkit-text-decoration:underline double;text-decoration:underline double}.xterm-underline-3{-webkit-text-decoration:underline wavy;text-decoration:underline wavy}.xterm-underline-4{-webkit-text-decoration:underline dotted;text-decoration:underline dotted}.xterm-underline-5{-webkit-text-decoration:underline dashed;text-decoration:underline dashed}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:underline overline}.xterm-overline.xterm-underline-2{-webkit-text-decoration:overline double underline;text-decoration:overline double underline}.xterm-overline.xterm-underline-3{-webkit-text-decoration:overline wavy underline;text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{-webkit-text-decoration:overline dotted underline;text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{-webkit-text-decoration:overline dashed underline;text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;pointer-events:none;position:absolute;top:0;right:0}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;z-index:11;background:0 0;transition:opacity .1s linear}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{display:none;position:absolute}.xterm .xterm-scrollable-element>.shadow.top{width:100%;height:3px;box-shadow:var(--vscode-scrollbar-shadow,#000) 0 6px 6px -6px inset;display:block;top:0;left:3px}.xterm .xterm-scrollable-element>.shadow.left{width:3px;height:100%;box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset;display:block;top:3px;left:0}.xterm .xterm-scrollable-element>.shadow.top-left-corner{width:3px;height:3px;display:block;top:0;left:0}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow,#000) 6px 0 6px -6px inset}@font-face{font-family:Basteleur;src:url(/__castle/ide/assets/Basteleur-Bold-DKFKedNb.woff2)format("woff2"),url(/__castle/ide/assets/Basteleur-Bold-CK8LF7Pt.woff)format("woff");font-weight:700;font-style:normal}.flow-root{--flow-gutter:#000;--flow-surface:#181818;--flow-chip:#282828;--flow-font-display:"Basteleur", Georgia, "Times New Roman", serif;--flow-fg:#e6e6e6;--flow-secondary:#b3b3b3;--flow-muted:#888;--flow-dim:#525252;--flow-border:#2a2a2a;--flow-border-active:#5a5a5a;--flow-gap:12px;--flow-dock-h:36px;--flow-tab-h:var(--castle-panel-header-height);--flow-icon-dock:var(--castle-button-icon-size);--flow-btn-sm:var(--castle-button-height);--flow-host-l:0px;--flow-host-r:0px;--flow-max-chips:6;--flow-chip-size:36px;--flow-chips-w:calc(var(--flow-max-chips) * var(--flow-chip-size));--flow-fade:22px;background:var(--flow-gutter);color:var(--flow-fg);flex-direction:column;font:13px ui-sans-serif,system-ui,-apple-system,sans-serif;display:flex;position:fixed;inset:0;overflow:hidden}.flow-root *{box-sizing:border-box}body.flow-reordering,body.flow-reordering *{touch-action:none;-webkit-user-select:none!important;user-select:none!important;cursor:grabbing!important}.flow-topbar{top:var(--flow-gap);left:var(--flow-gap);right:var(--flow-gap);height:var(--flow-dock-h);align-items:center;gap:var(--castle-space-base);z-index:40;pointer-events:none;padding-left:var(--flow-host-l);padding-right:var(--flow-host-r);grid-template-columns:minmax(0,1fr) minmax(0,auto) minmax(0,1fr);display:grid;position:absolute}.flow-topbar-leading{justify-self:start;align-items:center;gap:var(--castle-space-base);pointer-events:none;min-width:0;display:flex}.flow-topbar-leading>*{pointer-events:auto}.flow-castle-wrap{flex-shrink:0;position:relative}.flow-menu-backdrop{z-index:49;position:fixed;inset:0}.flow-castle-menu{top:calc(var(--flow-dock-h) + var(--castle-space-base));z-index:50;position:absolute;left:0}.flow-menu-narrow{display:none}.flow-deck-identity{max-width:260px}.flow-deck-vis{color:var(--flow-secondary);flex-shrink:0;font-size:14px;display:inline-flex}.flow-deck-vis svg{width:14px;height:14px}.flow-deck-name{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.flow-deck-caret{color:var(--flow-muted);flex-shrink:0;display:inline-flex}.flow-draft-status{color:var(--flow-muted);font-size:var(--castle-text-size-small);white-space:nowrap;flex-shrink:0}.flow-draft-status.is-error{color:var(--castle-danger-text)}.flow-tabs-wrap{pointer-events:auto;justify-self:center;align-items:center;gap:var(--castle-space-base);min-width:0;max-width:100%;display:flex}.flow-tabs{min-width:0;max-width:var(--flow-chips-w);flex:0 auto;position:relative}.flow-tabs-scroll{scrollbar-width:none;align-items:stretch;gap:0;height:100%;padding:0;display:flex;overflow:auto hidden}.flow-tabs-scroll::-webkit-scrollbar{display:none}.flow-tabs.more-left{-webkit-mask-image:linear-gradient(to right, transparent, #000 var(--flow-fade));-webkit-mask-image:linear-gradient(to right, transparent, #000 var(--flow-fade));mask-image:linear-gradient(to right, transparent, #000 var(--flow-fade));border-top-left-radius:0;border-bottom-left-radius:0}.flow-tabs.more-right{-webkit-mask-image:linear-gradient(to left, transparent, #000 var(--flow-fade));-webkit-mask-image:linear-gradient(to left, transparent, #000 var(--flow-fade));mask-image:linear-gradient(to left, transparent, #000 var(--flow-fade));border-top-right-radius:0;border-bottom-right-radius:0}.flow-tabs.more-left.more-right{-webkit-mask-image:linear-gradient(to right, transparent, #000 var(--flow-fade), #000 calc(100% - var(--flow-fade)), transparent);-webkit-mask-image:linear-gradient(to right, transparent, #000 var(--flow-fade), #000 calc(100% - var(--flow-fade)), transparent);mask-image:linear-gradient(to right, transparent, #000 var(--flow-fade), #000 calc(100% - var(--flow-fade)), transparent)}.button.flow-tabs-add{width:var(--castle-button-height-large);height:var(--castle-button-height-large);border-radius:var(--castle-radius-base);flex-shrink:0}.flow-chip-icon{font-size:var(--flow-icon-dock);display:inline-flex}.flow-chip-icon svg{width:var(--flow-icon-dock);height:var(--flow-icon-dock)}.flow-topbar-trailing{justify-self:end;align-items:center;gap:var(--castle-space-base);pointer-events:none;min-width:0;display:flex}.flow-preview-btn{pointer-events:auto;flex-shrink:0}.flow-preview-btn-failed{color:var(--castle-danger-text);border-color:var(--castle-danger-text)}.flow-preview-label{justify-items:center;display:grid}.flow-preview-label>*{grid-area:1/1}.flow-preview-label-sizer{visibility:hidden;pointer-events:none}.flow-root.is-mobile{--flow-max-chips:4;--flow-gap:var(--castle-space-base);--castle-text-size-small:14px;--castle-text-size-base:16px;--castle-text-style-smallcaps-size:var(--castle-text-size-small);--flow-tab-h:var(--castle-panel-header-height-mobile);--flow-icon-dock:var(--castle-button-icon-size-large);--flow-btn-sm:var(--castle-button-height-large)}.flow-root.is-mobile .flow-deck-identity,.flow-root.is-mobile .flow-topbar-trailing{display:none}.flow-root.is-mobile .flow-topbar{grid-template-columns:auto minmax(0,1fr)}.flow-root.is-mobile .flow-tabs-wrap{justify-self:start}.flow-root.is-mobile .flow-topbar-leading:not(:has(.flow-castle-wrap)):not(:has(.flow-draft-status)){display:none}.flow-root.is-mobile .menu-item.flow-menu-narrow{display:flex}.flow-root.is-mobile .menu-separator.flow-menu-narrow{display:block}.flow-scroller{flex:auto;min-height:0;overflow:auto}.flow-field{width:max-content;min-width:100%;min-height:100%}.flow-row{align-items:flex-start;gap:var(--flow-gap);width:max-content;min-height:100%;padding:calc(var(--flow-dock-h) + var(--flow-gap) * 2) var(--flow-gap) var(--flow-gap);padding-right:calc(var(--flow-gap) + var(--flow-overscroll,0px));display:flex}.flow-group{flex-direction:column;min-width:200px;display:flex;overflow:clip}.flow-root.is-mobile .panel:hover,.flow-root.is-mobile .panel.is-hover,.flow-root.is-maximized .panel:hover,.flow-root.is-maximized .panel.is-hover{border-color:var(--castle-border-1)}.flow-root.is-mobile .panel-header:hover,.flow-root.is-mobile .panel-tabs-header:hover{background:var(--castle-surface-3);cursor:default}.operator-chrome{align-items:stretch;gap:var(--castle-space-base);flex:auto;min-width:0;display:flex}.flow-tab-icon{font-size:var(--flow-icon-dock);flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}.flow-drop-indicator{background:var(--castle-border-4);z-index:60;pointer-events:none;border-radius:2px;width:3px;position:fixed;transform:translate(-50%)}.flow-group.pinned{left:var(--flow-gap);z-index:5;position:sticky;box-shadow:0 6px 24px #00000073}.flow-panel-body{flex:auto;min-height:0;position:relative;overflow:hidden}.flow-panel-slot{width:100%;height:100%}.flow-resize-e{top:var(--flow-tab-h);cursor:col-resize;touch-action:none;z-index:20;width:16px;position:absolute;bottom:0;right:-8px}.flow-resize-s{cursor:row-resize;touch-action:none;z-index:20;height:16px;position:absolute;bottom:-8px;left:0;right:0}.flow-resize-se{cursor:nwse-resize;touch-action:none;z-index:21;width:22px;height:22px;position:absolute;bottom:-11px;right:-11px}.flow-placeholder{height:100%;color:var(--flow-muted);text-align:center;flex-direction:column;justify-content:center;align-items:center;gap:8px;padding:16px;display:flex}.flow-placeholder-icon :is(svg){width:34px;height:34px}.flow-placeholder-label{color:var(--flow-secondary);font-size:14px}.flow-placeholder-kind{color:var(--flow-muted);font:11px ui-monospace,SFMono-Regular,Menlo,monospace}.flow-placeholder.kind-play{background:repeating-linear-gradient(45deg,#101018,#101018 10px,#0d0d14 10px 20px)}.flow-picker{z-index:50;max-height:min(60vh,420px);position:fixed}.flow-picker-input{margin-bottom:var(--castle-space-base);color:var(--flow-fg);background:var(--flow-surface);border:1px solid var(--flow-border);border-radius:var(--castle-radius-small);outline:none;flex:none;padding:7px 9px;font:13px ui-sans-serif,system-ui,sans-serif}.flow-picker-input:focus{border-color:var(--flow-border-active)}.flow-picker-list{flex:auto;min-height:0;overflow-y:auto}.flow-picker-empty{color:var(--flow-muted);padding:10px 8px;font-size:12px}.flow-operator-host{width:100%;height:100%}.flow-root.is-maximized .flow-scroller{overflow:hidden}.flow-root.is-maximized .flow-field,.flow-root.is-maximized .flow-row{width:100%;height:100%}.flow-root.is-maximized .flow-row{align-items:stretch}.flow-group.maximized{width:100%;height:100%}.flow-group.hidden{display:none}.flow-root.is-mobile .flow-scroller{position:relative;overflow:clip}.flow-root.is-mobile .flow-field{inset:calc(var(--flow-dock-h) + var(--flow-gap) * 2) 0 var(--flow-gap);width:auto;min-width:0;height:auto;min-height:0;position:absolute;overflow:clip}.flow-root.is-mobile .flow-row{width:100%;height:100%;transform:translateX(calc(var(--flow-page,0) * -100% + var(--flow-drag,0px)));will-change:transform;flex-wrap:nowrap;align-items:stretch;gap:0;padding:0;transition:transform .28s cubic-bezier(.22,.61,.36,1);display:flex}.flow-root.is-mobile.flow-dragging .flow-row{transition:none}.flow-root.is-mobile .flow-group{flex:0 0 100%;min-width:0;margin:0}.flow-root.is-mobile .flow-resize-e,.flow-root.is-mobile .flow-resize-s,.flow-root.is-mobile .flow-resize-se{display:none}@media (prefers-reduced-motion:reduce){.flow-root.is-mobile .flow-row{transition:none}}.flow-push-modal-backdrop{z-index:1000;-webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);pointer-events:auto;background:#0000008c;justify-content:center;align-items:center;padding:24px;display:flex;position:fixed;inset:0}.flow-push-modal{border:1px solid var(--flow-border);text-align:center;background:#141414;border-radius:18px;flex-direction:column;align-items:center;gap:10px;width:min(360px,100%);padding:28px 24px;display:flex;box-shadow:0 20px 60px #0009}.flow-push-spinner{border:3px solid #ffffff26;border-top-color:var(--flow-fg);border-radius:50%;width:34px;height:34px;animation:.8s linear infinite flow-push-spin}@keyframes flow-push-spin{to{transform:rotate(360deg)}}.flow-push-check{color:#fff;background:#2e7d32;border-radius:50%;justify-content:center;align-items:center;width:34px;height:34px;font-size:20px;font-weight:700;display:flex}.flow-push-check-failed{background:var(--castle-danger-surface)}.flow-push-title{color:var(--flow-fg);font-size:16px;font-weight:600}.flow-push-sub{color:var(--flow-secondary);font-size:12px}.flow-push-url{overflow-wrap:anywhere;color:#7aa2ff;max-width:100%;font:13px ui-monospace,SFMono-Regular,Menlo,monospace;text-decoration:none}.flow-push-url:hover{text-decoration:underline}.flow-push-done{background:var(--flow-fg);color:var(--flow-gutter);cursor:pointer;border:none;border-radius:999px;margin-top:8px;padding:9px 24px;font-size:14px;font-weight:600}.flow-tabstrip{height:var(--flow-tab-h);-webkit-user-select:none;user-select:none;touch-action:none;flex-shrink:0}.flow-tabs-row{position:relative;overflow:hidden}.flow-tabs-row .panel-tab{flex:0 auto;min-width:0}.flow-tab-icon svg{width:var(--flow-icon-dock);height:var(--flow-icon-dock)}.flow-tabs-row .panel-tab-insert{z-index:3;height:auto;position:absolute;top:0;bottom:0}.panel-tab-ghost,.dock-segment-ghost{z-index:80;position:fixed}.flow-tabstrip .button{flex-shrink:0;align-self:center}.flow-tab-body{position:absolute;inset:0}.flow-tab-body.inactive{display:none}.flow-class-drawer{background:var(--castle-sheet-bg,var(--v2-surface));border-right:1px solid var(--flow-border);flex-direction:column;flex:none;width:220px;min-height:0;padding:2px 4px 6px;display:flex;overflow:hidden}.flow-class-files{flex:auto;min-height:0;overflow-y:auto}.flow-class-files .fileBrowserBare,.flow-class-files .fileTree{flex:none;height:auto;overflow:visible}.flow-class-recent{border-bottom:1px solid var(--castle-inspector-divider,var(--flow-border));margin-bottom:10px;padding-bottom:10px}.flow-class-section{color:var(--v2-muted,var(--flow-muted));padding:5px 9px;font-size:14px}.flow-class-drawer .flow-view-segments{margin:4px 2px 8px}.flow-class-drawer-empty{color:var(--flow-muted);padding:10px 8px;font-size:12px}.flow-empty-editor{flex:auto;height:100%;min-height:0;display:flex}.flow-empty-editor .flow-class-drawer{flex:0 0 220px}.flow-empty-editor-msg{color:var(--flow-muted);background:var(--castle-sheet-bg,var(--v2-surface));flex:auto;justify-content:center;align-items:center;font-size:13px;display:flex}.flow-tabstrip-mobile{cursor:default;grid-template-columns:1fr auto 1fr;align-items:center;display:grid}.flow-mobile-strip-left,.flow-mobile-strip-right{min-width:0}.flow-mobile-strip-right{justify-content:flex-end;align-items:center;display:flex}.flow-tabstrip-mobile .panel-header-actions{margin-left:0}.panel-mobile-current .flow-tab-icon,.panel-mobile-current .flow-tab-icon svg{width:var(--castle-button-icon-size-large);height:var(--castle-button-icon-size-large)}.flow-mobile-chevron{width:var(--castle-button-icon-size-large);height:var(--castle-button-icon-size-large);opacity:.6;flex-shrink:0;justify-content:center;align-items:center;display:inline-flex}.flow-mobile-chevron svg{width:var(--castle-button-icon-size-large);height:var(--castle-button-icon-size-large);display:block}.flow-mobile-switch-backdrop{z-index:900;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);pointer-events:auto;background:#0000008c;align-items:flex-end;display:flex;position:fixed;inset:0}.flow-mobile-switch{border-top:1px solid var(--flow-border);background:#141414;border-radius:16px 16px 0 0;flex-direction:column;width:100%;max-height:70vh;display:flex;overflow:hidden}.flow-mobile-switch-header{border-bottom:1px solid var(--flow-border);justify-content:space-between;align-items:center;padding:14px 16px;font-weight:600;display:flex}.flow-mobile-switch-close{color:var(--flow-secondary);cursor:pointer;background:0 0;border:none;font-size:22px;line-height:1}.flow-view-segments{background:var(--v2-inset,#0e0e0e);border-radius:8px;flex:none;gap:2px;margin:10px 16px 6px;padding:2px;display:flex}.flow-view-segment{color:var(--flow-secondary);font:inherit;cursor:pointer;background:0 0;border:none;border-radius:6px;flex:1 1 0;padding:7px 10px;font-size:13px;font-weight:600}.flow-view-segment.on{color:var(--flow-text,#eee);background:#282828}.flow-mobile-switch-list{background:var(--v2-surface,#141414);flex-direction:column;flex:auto;min-height:0;display:flex;overflow:hidden}.flow-mobile-switch-list .flow-class-files{padding:4px 6px 10px}
@@ -10,8 +10,8 @@
10
10
  <link rel="icon" type="image/png" sizes="32x32" href="/__castle/ide/favicon-32x32.png" />
11
11
  <link rel="icon" type="image/png" sizes="16x16" href="/__castle/ide/favicon-16x16.png" />
12
12
  <link rel="icon" href="/__castle/ide/favicon.ico" sizes="any" />
13
- <script type="module" crossorigin src="/__castle/ide/assets/index-BWOEraUy.js"></script>
14
- <link rel="stylesheet" crossorigin href="/__castle/ide/assets/index-BkVF1OXc.css">
13
+ <script type="module" crossorigin src="/__castle/ide/assets/index-C5DS_7UM.js"></script>
14
+ <link rel="stylesheet" crossorigin href="/__castle/ide/assets/index-CoU3ETYM.css">
15
15
  </head>
16
16
  <body>
17
17
  <div id="root"></div>
@@ -122,6 +122,9 @@ bottleneck.
122
122
  - `unsupported` — a refusal: why this deck must NOT be built on this
123
123
  format, shown when someone tries to upload one. Only for formats you
124
124
  recognize and reject.
125
+ - `width` — preferred card width in px when the shell opens this type's
126
+ editor in a new pane. A layout hint: the shell caps it to the window
127
+ and ignores it on phones. Absent means the shell's default.
125
128
 
126
129
  2. **Write the module** at the declared path. It is handed the file and a way
127
130
  to save it; how it renders is yours.
@@ -12,61 +12,71 @@
12
12
  "ext": ".png",
13
13
  "label": "Image",
14
14
  "icon": "file-image",
15
- "editor": "editors/ImageViewer.js"
15
+ "editor": "editors/ImageViewer.js",
16
+ "width": 480
16
17
  },
17
18
  {
18
19
  "ext": ".jpg",
19
20
  "label": "Image",
20
21
  "icon": "file-image",
21
- "editor": "editors/ImageViewer.js"
22
+ "editor": "editors/ImageViewer.js",
23
+ "width": 480
22
24
  },
23
25
  {
24
26
  "ext": ".jpeg",
25
27
  "label": "Image",
26
28
  "icon": "file-image",
27
- "editor": "editors/ImageViewer.js"
29
+ "editor": "editors/ImageViewer.js",
30
+ "width": 480
28
31
  },
29
32
  {
30
33
  "ext": ".gif",
31
34
  "label": "Image",
32
35
  "icon": "file-image",
33
- "editor": "editors/ImageViewer.js"
36
+ "editor": "editors/ImageViewer.js",
37
+ "width": 480
34
38
  },
35
39
  {
36
40
  "ext": ".webp",
37
41
  "label": "Image",
38
42
  "icon": "file-image",
39
- "editor": "editors/ImageViewer.js"
43
+ "editor": "editors/ImageViewer.js",
44
+ "width": 480
40
45
  },
41
46
  {
42
47
  "ext": ".svg",
43
48
  "label": "Image",
44
49
  "icon": "file-image",
45
- "editor": "editors/ImageViewer.js"
50
+ "editor": "editors/ImageViewer.js",
51
+ "width": 480
46
52
  },
47
53
  {
48
54
  "ext": ".mp3",
49
55
  "label": "Audio",
50
56
  "icon": "file-audio",
51
- "editor": "editors/MediaPlayer.js"
57
+ "editor": "editors/MediaPlayer.js",
58
+ "width": 360
52
59
  },
53
60
  {
54
61
  "ext": ".wav",
55
62
  "label": "Audio",
56
63
  "icon": "file-audio",
57
- "editor": "editors/MediaPlayer.js"
64
+ "editor": "editors/MediaPlayer.js",
65
+ "width": 360
58
66
  },
59
67
  {
60
68
  "ext": ".m4a",
61
69
  "label": "Audio",
62
70
  "icon": "file-audio",
63
- "editor": "editors/MediaPlayer.js"
71
+ "editor": "editors/MediaPlayer.js",
72
+ "width": 360
64
73
  },
65
74
  {
66
75
  "ext": ".mp4",
67
76
  "label": "Video",
68
77
  "icon": "file-video",
69
- "editor": "editors/MediaPlayer.js"
78
+ "editor": "editors/MediaPlayer.js",
79
+ "width": 560
70
80
  }
71
81
  ]
72
82
  },
@@ -74,7 +84,7 @@
74
84
  "title": "base",
75
85
  "deckId": "yRcmH4_aYllE",
76
86
  "cardId": "zkFdingmIm3m",
77
- "publishedVersion": "2026-09-10T23:34:50.309Z",
87
+ "publishedVersion": "2026-09-11T20:21:04.335Z",
78
88
  "provides": [
79
89
  "castle-web-sdk"
80
90
  ]
@@ -22,11 +22,12 @@ Do you already know what you want to make, or do you want to figure it out toget
22
22
  - Every actor is an instance of a **blueprint** (`blueprints/*.scene`) — see `## Blueprints` below. Always author the blueprint file yourself and reference it via `"blueprint"`. Don't write inline actors (full `components`, no `blueprint` field): the editor auto-migrates each one into its own new blueprint file on open, one per actor with no dedup, which litters the deck with junk blueprints.
23
23
  - Real game objects and scenery should usually be editable sprites: generate `.sprite` with `npm run draw -- name`, then place it via a `Sprite` component pointing at `drawings/name.sprite`. Dynamic UI/effects stay procedural.
24
24
  - A deck can also hold uploaded media (the Files panel's Upload button): `Sprite` draws image files as well as `.sprite`, and `Video` plays video files. Point their `file` at the deck path (`assets/logo.png`). For audio see `## Sound` below -- sound effects need no component at all.
25
+ - **Text** — place the kit preset `@imports/castle.physics-2d/blueprints/text.scene`, or add a `Text` component (optional `font`; chrome via sibling `Style`). Dynamic text is `actor.components.Text.text = …`. A sibling `onTap(actor, scene)` fires when that actor is tapped — no extra behavior.
25
26
  - The deck's body/UI font is picked in the Theme editor (`theme.style`): canvas text reads `scene.font`. A second display face is imported in the behavior that uses it. See `## Deck font` below.
26
27
  - This kit is plain JavaScript. Use `.jsx` for files with JSX, `.js` otherwise; do not add TypeScript files or a new build step.
27
28
  - Space is reserved by the editor for play/stop; do not bind Space to gameplay.
28
29
  - Two render hooks: `draw(ctx)` is world space and scrolls with `Camera`; `drawUi(ctx)` is screen space (card units, camera-free). On-screen controls, gauges and HUD go in `drawUi`, never `draw`. The React `ui()` hook is deprecated — prefer `drawUi`.
29
- - Do not read `engine/`, `editors/`, or built-in behaviors (`Layout.jsx`, `Sprite.jsx`, `Collider.jsx`, `Camera.jsx`, and the physics ones — `RigidBody.jsx`, `Joints.jsx`, `Draggable.jsx`, `Slingshot.jsx`, `AnalogStick.jsx`) to build a game. Their public API is documented below. Forking is the exception: when you're deliberately copying a kit file into the deck to change it — an editor (see `## Editors`) or a behavior you're shadowing — read the original. `engine/` stays off-limits either way.
30
+ - Do not read `engine/`, `editors/`, or built-in behaviors (`Layout.jsx`, `Sprite.jsx`, `Text.jsx`, `Style.jsx`, `Collider.jsx`, `Camera.jsx`, and the physics ones — `RigidBody.jsx`, `Joints.jsx`, `Draggable.jsx`, `Slingshot.jsx`, `AnalogStick.jsx`) to build a game. Their public API is documented below. Forking is the exception: when you're deliberately copying a kit file into the deck to change it — an editor (see `## Editors`) or a behavior you're shadowing — read the original. `engine/` stays off-limits either way.
30
31
  - An editor is for content FILES the creator keeps coming back to (catalogs, dialogue, level tables) that nothing already opens. Scenes, sprites and themes have editors; per-actor settings belong on behavior props in the inspector — not in a new editor.
31
32
  - Details below: `## Behavior shape`, `## Scene file`, `## Blueprints`, `## Built-in behaviors`, `## Creating pixel art`, `## SceneRuntime API`, and `## Input shortcuts`.
32
33
 
@@ -74,6 +75,9 @@ These are ALL the fields that exist — do not invent others:
74
75
  - `unsupported` — a refusal: why this deck must NOT be built on this
75
76
  format, shown when someone tries to upload one. Only for formats you
76
77
  recognize and reject.
78
+ - `width` — preferred card width in px when the shell opens this type's
79
+ editor in a new pane. A layout hint: the shell caps it to the window
80
+ and ignores it on phones. Absent means the shell's default.
77
81
 
78
82
  2. **Write the module** at the declared path, default-exporting a component:
79
83
 
@@ -291,6 +295,10 @@ export class MyThing {
291
295
  // For letting go of anything held outside your own props.
292
296
  onDisable(actor, scene) {}
293
297
  onEnable(actor, scene) {}
298
+
299
+ // Optional. Fired on pointer release inside this actor (Collider, else
300
+ // Layout box). No extra component — implementing the method is the opt-in.
301
+ onTap(actor, scene) {}
294
302
  }
295
303
  ```
296
304
 
@@ -383,12 +391,16 @@ Template `components` keys are behavior names (the `static behaviorName`); add a
383
391
  - **Never write inline actors** (full `components`, no `blueprint` field). They aren't a lighter-weight alternative: the editor auto-migrates every such actor into its OWN new blueprint file the first time a human opens the scene — mechanically, one blueprint per actor, no dedup. That migration is a compatibility net for pre-blueprint decks, not an authoring workflow; leaning on it turns 10 inline enemies into 10 junk blueprints.
384
392
  - Never invent your own `blueprint` path pointing at a file you didn't also create — a dangling reference resolves to "no template" (the instance's own sparse `components` render alone, missing whatever it expected to inherit).
385
393
 
394
+ The kit also ships a few presets under `blueprints/` (e.g. `text.scene`, `ball.scene`, `cauldron.scene`). Reference one from a deck as `"blueprint": "@imports/castle.physics-2d/blueprints/text.scene"`.
395
+
386
396
  ## Built-in behaviors
387
397
 
388
398
  - **Layout** — `{ x, y, width, height, z?, rotation? }`. Every actor needs one. `z` orders draw (low first). `rotation` is degrees about the center.
389
399
  - **Sprite** — `{ file: "drawings/foo.sprite", tint?: "#rrggbbaa", playing?: true, tag?: "", mode?: 'cover'|'fit'|'stretch'|'tile', tileSize?: 50 }`. Renders the deck's 2D art into the Layout box. `file` is either a `.sprite` pixel-art sprite or an uploaded **image file** (`.png`, `.jpg`, `.jpeg`, `.gif`, `.webp`, `.svg`) — every prop below works the same on both, except that an image is a single still (no frames or tags) and is drawn smoothed rather than nearest-neighbour, which is what you want for a photo and not for pixel art. Draw modes: scaled up preserving the art's aspect ratio to fill the whole box, cropping whatever overflows a mismatched box (`mode: 'cover'`, the default -- CSS object-fit: cover), scaled preserving the art's aspect ratio and centered so the whole sprite stays visible, letterboxing a mismatched box instead of cropping (`mode: 'fit'` -- CSS object-fit: contain), scaled to fill the box exactly and distorting the art when the aspect ratios don't match (`mode: 'stretch'`), or repeated (`mode: 'tile'`). `tint` multiplies; use white (`#ffffffff`) or omit for the original colors. Animated sprites play automatically; set `playing: false` to hold the first frame, or `tag` to play a named animation tag. Tile mode repeats the art at a fixed cell size (`tileSize` card units tall, width scaled by the art's aspect) instead of stretching it across the Layout box.
390
400
  - **Missing sprites fall back to a placeholder.** If `file` names a sprite that doesn't exist yet, it renders the fallback `drawings/cauldron.sprite` — so you can give an actor its REAL intended sprite name (`drawings/paddle.sprite`) right away and it shows the placeholder until that file is created. Reference real names from the start; don't wait for the art.
391
401
  - **Fill the box, don't distort.** The default `mode: 'cover'` fills the Layout box with the art undistorted, cropping whatever overflows when the box aspect doesn't match the art's — so treat the Layout box like an image frame in a design tool: size it to frame what matters and keep the sprite's important content toward the center, since the edges may be cropped. Keeping an actor's Layout aspect ratio close to its sprite's native aspect ratio minimizes how much gets cropped. When the whole sprite must stay visible (nothing is safe to crop), use `mode: 'fit'`, which preserves the art and letterboxes the mismatched box instead. Avoid `mode: 'stretch'` for pixel art — filling a long/tall box by distorting wrecks the pixels (a brick sprite stretched into a wall ruins the bricks). For long surfaces (walls, floors, platforms), use `mode: 'tile'` on one actor to repeat the art at a fixed cell size instead of stretching or cropping a single sprite.
402
+ - **Text** — `{ text, font?: '', size?: 24, color?: '#131313', align?: 'left'|'center'|'right', verticalAlign?: 'top'|'middle'|'bottom', lineHeight?: 1.25, space?: 'world'|'screen', outlineWidth?: 0, outlineColor?: '#ffffff' }`. Draws wrapped text into the Layout box (wrap width = box minus sibling `Style.padding`; lines may overflow vertically — no clipping, no auto-resize). `font: ''` (default) uses the deck font; pick any Castle face from the inspector and it is added to `fonts.generated.js`. `space: 'world'` scrolls with the camera; `space: 'screen'` is HUD via `drawUi`. `color` / `outlineColor` are deck-palette hexes (`''` = none — skip fill or stroke). Fill/border/shadow/opacity/padding live on sibling **Style**. Hide with `"$enabled": false`. Kit preset: `@imports/castle.physics-2d/blueprints/text.scene`. Change the string from deck code with `actor.components.Text.text = '…'`.
403
+ - **Style** — `{ background?: '', border?: '', borderWidth?: 0, borderRadius?: 0, padding?: 0, shadowX?: 0, shadowY?: 0, shadowBlur?: 0, shadowColor?: '', opacity?: 1 }`. Shared chrome for **Text** and **Sprite**: background fill, border, corner radius, drop shadow (`shadowColor` + offsets + blur; empty color = no shadow), content padding, and opacity. Draws behind content. `background` / `border` are palette hexes (`''` = none). Add it beside Text or Sprite from the inspector.
392
404
  - **Collider** — `{ kind: 'solid'|'pickup', mode?: 'auto'|'manual', width, height, offsetX?, offsetY?, debug? }`. Just a rect; `offsetX`/`offsetY` nudge the collider from its default position (so `0,0` is the default). `mode: 'auto'` (the default) fits the rect to the actor's Sprite's opaque pixels, mapped through the Sprite's draw mode (`fit`'s letterboxed dest rect, `stretch`'s full Layout box, `cover`'s filled box clipped to the Layout box; `tile` mode and a missing/unresolved Sprite use the whole Layout box instead). `width`/`height` only apply in `mode: 'manual'` (a rect of that size, centered in the Layout box); they're ignored in `auto`. The framework does NOT auto-resolve collisions for you. Use it as data:
393
405
 
394
406
  ```jsx
@@ -492,8 +504,10 @@ behavior imported for itself — before the first frame, so `ctx.font` is safe t
492
504
  set from the very first `draw`. Each face costs its own 12–90 KB in the bundle,
493
505
  so two or three in total is the shape to aim for.
494
506
 
495
- There is no Text behavior text is drawn by the deck's own code via `draw`
496
- (world) or `drawUi` (screen HUD).
507
+ Use the **Text** behavior for labels and HUD strings (optional per-actor `font`,
508
+ plus sibling **Style** for fill/border/padding). Hand-drawn canvas text
509
+ (`ctx.fillText` in `draw` / `drawUi`) is for per-glyph effects or text that
510
+ follows a body in a way the Layout box cannot.
497
511
 
498
512
  ## Physics
499
513
 
@@ -525,8 +539,7 @@ make it move.**
525
539
  - `bodyType: 'dynamic' | 'static' | 'kinematic'`. `dynamic` = simulated
526
540
  (gravity, collisions, forces). `static` = never moves (same as a lone
527
541
  Collider). `kinematic` = unpushable, but you move it by writing its Layout.
528
- - `gravityScale` — multiplies world gravity for this body (`0` = floats;
529
- default, so newly added bodies don't fall until you opt in).
542
+ - `gravityScale` — multiplies world gravity for this body (`0` = floats).
530
543
  - `drag` — linear damping (air resistance). `angularDrag` — spin damping.
531
544
  - `freezeRotation` — keep it from rotating (stays upright).
532
545
  - `velocityX` / `velocityY` — initial velocity, applied once when play starts.
@@ -601,6 +614,26 @@ export class StickSlowDownToggle {
601
614
  }
602
615
  ```
603
616
 
617
+ ### Tap hook
618
+
619
+ Any behavior may implement `onTap(actor, scene)`. No extra component: if an
620
+ enabled behavior on the actor has the method, a pointer release inside the hit
621
+ zone fires it on every sibling that implements it (Collider when present, else
622
+ the Layout box; screen-space Text uses screen coords). The finger is claimed so
623
+ it does not also drive a stick or a grab-anywhere sling. A targeted control
624
+ (Draggable, a sling pressed on its own body) still wins. An actor with no
625
+ `onTap` does not claim the finger.
626
+
627
+ ```jsx
628
+ export class TapCounter {
629
+ static behaviorName = 'TapCounter';
630
+ onTap(actor, scene) {
631
+ const text = actor.components.Text;
632
+ if (text) text.text = String(Number(text.text || 0) + 1);
633
+ }
634
+ }
635
+ ```
636
+
604
637
  ### Built-in controls (add these behaviors, no code needed)
605
638
 
606
639
  These read input and drive the actor through the physics system, so the actor
@@ -650,7 +683,7 @@ see the SceneRuntime API below.
650
683
  ### Recipe: a launch-and-bounce game
651
684
 
652
685
  - Ball blueprint: `Layout` (square), `Sprite`, `Collider {shape:'circle',
653
- bounciness:0.6}`, `RigidBody {bodyType:'dynamic', gravityScale:1}`, `Slingshot {}`.
686
+ bounciness:0.6}`, `RigidBody {bodyType:'dynamic'}`, `Slingshot {}`.
654
687
  - Walls/floor blueprint: `Layout`, `Collider {bounciness:0.4}` (no RigidBody →
655
688
  static).
656
689
  - Goal blueprint: `Collider {isTrigger:true}` + a `Goal` behavior with
@@ -853,14 +886,14 @@ if (scene.keys.has('KeyX')) /* launch ball */ ;
853
886
 
854
887
  **Space is reserved** — the editor binds it to the play/stop toggle, so don't bind Space to a gameplay action (jump / shoot / launch / ...). Use arrows, WASD, letter keys, or on-screen buttons instead.
855
888
 
856
- For HUD text and shapes use `drawUi` (screen-fixed canvas). Only in-world text or shapes go in `draw`. Both read `scene.font` — see `## Deck font`. The React `ui()` hook is deprecated.
889
+ For HUD text prefer a `Text` actor with `space: 'screen'` (or `drawUi` for custom canvas HUD). Only in-world text or shapes go in `draw`. Both read `scene.font` — see `## Deck font`. A tappable label is `Text` plus a sibling with `onTap`. The React `ui()` hook is deprecated.
857
890
 
858
891
  ## Common breakout-shaped recipe (sketch)
859
892
 
860
893
  - `Paddle` behavior: read keys, clamp x to `[0, 500 - layout.width]`.
861
894
  - `Ball` behavior: store `vx, vy` on `actor.runtime`; integrate; bounce off wall edges (`x<0`, `x+w>500`, `y<0`); on `scene.overlaps(actor, paddle)`, flip `vy`; for each `brick` in `scene.actorsWith('Brick')` check `scene.overlaps(actor, brick)` → flip `vy` and `scene.despawnActor(brick.id)`; if `y > 700` lose a life.
862
895
  - `Brick` behavior: typically just a marker — `kind: 'solid'` collider is enough. State (hit count) goes on `actor.runtime` or the brick's own props.
863
- - `GameController` (no Layout needed if you don't draw it): tracks score / lives / status; expose HUD via `drawUi()`.
896
+ - `GameController` (no Layout needed if you don't draw it): tracks score / lives / status; expose HUD via `Text` with `space: 'screen'` or `drawUi()`.
864
897
 
865
898
  ## Don't
866
899
 
@@ -4,11 +4,8 @@ import { AutoFields, overrideProps } from '../engine/autoInspector';
4
4
  import {
5
5
  GREEDY_CLAIM,
6
6
  acquirePress,
7
+ clampLength,
7
8
  length,
8
- screenPoint,
9
- stickBrake,
10
- stickDrive,
11
- stickVector,
12
9
  } from '../engine/physics/controls';
13
10
 
14
11
  // AnalogStick: on-screen virtual joystick (press anywhere) that drives the
@@ -26,6 +23,85 @@ import {
26
23
  //
27
24
  // Sibling hooks (fired on this actor only): onAnalogStickBegin / onAnalogStickEnd
28
25
  // (actor, scene) — begin on first nonzero deflection, end on release or disable.
26
+ //
27
+ // Force-mode math lives here (only consumer): stickDrive / stickBrake return
28
+ // velocity deltas via applyImpulse — mass-independent, composable, and
29
+ // restricted to driven axes so gravity on an undriven axis is never clamped.
30
+
31
+ // Stick displacement from origin, clamped to maxRadius.
32
+ function stickVector(pointer, origin, maxRadius = 60) {
33
+ return clampLength({ x: pointer.x - origin.x, y: pointer.y - origin.y }, maxRadius);
34
+ }
35
+
36
+ // Card coords before the camera — for screen-fixed controls reading a pointer.
37
+ function screenPoint(pointer) {
38
+ return { x: pointer.screenX, y: pointer.screenY };
39
+ }
40
+
41
+ // Keep only the axes the stick is allowed to drive. An undriven axis (gravity
42
+ // in a platformer) must never be clamped or braked by the stick.
43
+ function drivenAxes(v, axes) {
44
+ return {
45
+ x: axes === 'vertical' ? 0 : v.x,
46
+ y: axes === 'horizontal' ? 0 : v.y,
47
+ };
48
+ }
49
+
50
+ // Smallest signed angle from `from` to `to`, wrapped into [−π, π].
51
+ function angleDelta(from, to) {
52
+ let d = Math.atan2(to.y, to.x) - Math.atan2(from.y, from.x);
53
+ if (d > Math.PI) d -= 2 * Math.PI;
54
+ if (d < -Math.PI) d += 2 * Math.PI;
55
+ return d;
56
+ }
57
+
58
+ // Velocity delta while held: accelerate toward deflection × speed with turn
59
+ // boost on reversals, then clamp driven axes to `speed`. Impulse only.
60
+ function stickDrive(velocity, deflection, props = {}, dt) {
61
+ const speed = props.speed ?? 6;
62
+ const rampTime = props.rampTime ?? 0.2;
63
+ const turnBoost = props.turnBoost ?? 3;
64
+ const axes = props.axes ?? 'both';
65
+ const vDriven = drivenAxes(velocity, axes);
66
+
67
+ let boost = 1;
68
+ if (turnBoost > 0 && length(velocity) > 0 && length(deflection) > 0) {
69
+ boost = 1 + turnBoost * (Math.abs(angleDelta(velocity, deflection)) / Math.PI);
70
+ }
71
+
72
+ let delta;
73
+ if (rampTime <= 0) {
74
+ const target = drivenAxes(
75
+ { x: deflection.x * speed, y: deflection.y * speed },
76
+ axes,
77
+ );
78
+ delta = { x: target.x - vDriven.x, y: target.y - vDriven.y };
79
+ } else {
80
+ const accel = speed / rampTime;
81
+ delta = drivenAxes(
82
+ { x: deflection.x * accel * boost * dt, y: deflection.y * accel * boost * dt },
83
+ axes,
84
+ );
85
+ const capped = clampLength({ x: vDriven.x + delta.x, y: vDriven.y + delta.y }, speed);
86
+ delta = { x: capped.x - vDriven.x, y: capped.y - vDriven.y };
87
+ }
88
+ return delta;
89
+ }
90
+
91
+ // Velocity delta while idle: Coulomb brake on driven axes only.
92
+ // `slowDown` is speed units lost per second (px/step per second). 0 = coast.
93
+ function stickBrake(velocity, props = {}, dt) {
94
+ const slowDown = props.slowDown ?? 20;
95
+ if (slowDown <= 0) return { x: 0, y: 0 };
96
+ const axes = props.axes ?? 'both';
97
+ const vDriven = drivenAxes(velocity, axes);
98
+ const len = length(vDriven);
99
+ if (len === 0) return { x: 0, y: 0 };
100
+ const reduce = Math.min(len, slowDown * dt);
101
+ const s = -reduce / len;
102
+ return { x: vDriven.x * s, y: vDriven.y * s };
103
+ }
104
+
29
105
  function fireStickHook(actor, scene, hook) {
30
106
  scene.forEachBehavior(actor, (inst) => inst[hook]?.(actor, scene));
31
107
  }
@@ -62,6 +62,14 @@ export class Slingshot {
62
62
  // Anchor at the press point (like castle-client): the aim/launch depends
63
63
  // on the drag gesture, not where the press landed relative to the actor.
64
64
  rt._slingAnchor = { x: press.x, y: press.y };
65
+ // A same-frame tap (down already false) is not an aim — cancel before we
66
+ // can launch with a zero pull. A TARGETED control that updates later this
67
+ // frame may still steal a greedy claim; we must not freeze velocity yet.
68
+ if (!press.down) {
69
+ rt._slinging = false;
70
+ rt._slingPointerId = null;
71
+ return;
72
+ }
65
73
  }
66
74
  }
67
75
  if (!rt._slinging) return;
@@ -77,8 +85,12 @@ export class Slingshot {
77
85
  }
78
86
 
79
87
  if (p.down) {
80
- // Hold still while aiming, and remember the aim point for draw().
81
- scene.physics.setVelocity(actor, { x: 0, y: 0 });
88
+ // Hold still while aiming but not on the press frame. A greedy claim can
89
+ // still lose to a higher claim that hasn't updated yet (e.g. a Draggable
90
+ // on the pressed body); freezing here would hitch a mid-air body for one frame
91
+ // and then drop the shot with no launch. Matches claimPointer's contract
92
+ // that the press frame costs a greedy control nothing visible.
93
+ if (!p.justPressed) scene.physics.setVelocity(actor, { x: 0, y: 0 });
82
94
  rt._slingAim = { x: p.x, y: p.y };
83
95
  } else {
84
96
  scene.physics.setVelocity(actor, slingLaunch(rt._slingAnchor, p, this.props));