@volter/editor-core 0.5.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BUNDLED_NOTICES +1527 -0
- package/LICENSE +686 -0
- package/LICENSE-APACHE +202 -0
- package/NOTICE +18 -0
- package/README.md +24 -0
- package/dist/build/chunk-JS4D4XZ3.js +175 -0
- package/dist/build/chunk-JS4D4XZ3.js.map +7 -0
- package/dist/build/vite-plugin-product-contributions.js +100 -0
- package/dist/build/vite-plugin-product-contributions.js.map +7 -0
- package/dist/build/vite-plugin-shared-react.js +25 -0
- package/dist/build/vite-plugin-shared-react.js.map +7 -0
- package/dist/build/vite-plugin-shared-three.js +86 -0
- package/dist/build/vite-plugin-shared-three.js.map +7 -0
- package/dist/server/chunk-KMJC7AGO.js +98 -0
- package/dist/server/chunk-KMJC7AGO.js.map +7 -0
- package/dist/server/chunk-PSILUMGS.js +46 -0
- package/dist/server/chunk-PSILUMGS.js.map +7 -0
- package/dist/server/frame-proxy.js +255 -0
- package/dist/server/frame-proxy.js.map +7 -0
- package/dist/server/open-browser.js +53 -0
- package/dist/server/open-browser.js.map +7 -0
- package/dist/server/process-shutdown.js +127 -0
- package/dist/server/process-shutdown.js.map +7 -0
- package/dist/server/session-registry.js +141 -0
- package/dist/server/session-registry.js.map +7 -0
- package/dist/server/spawn-opener.js +11 -0
- package/dist/server/spawn-opener.js.map +7 -0
- package/dist/server/worktree-identity.js +11 -0
- package/dist/server/worktree-identity.js.map +7 -0
- package/dist-server/packaged.mjs +88816 -0
- package/package.json +118 -0
- package/scripts/build-plugins.mjs +14 -0
- package/scripts/build-server.mjs +26 -0
- package/scripts/build-session.mjs +9 -0
- package/server/account-credentials.ts +60 -0
- package/server/account-service.ts +1434 -0
- package/server/adapter-region-includes.ts +47 -0
- package/server/asset-catalog-v2.ts +175 -0
- package/server/asset-history-snapshots.ts +196 -0
- package/server/asset-ledger-store.ts +195 -0
- package/server/asset-library-routes.ts +1595 -0
- package/server/blender-wasm-artifact.ts +430 -0
- package/server/boot-timings.ts +106 -0
- package/server/canonical-path.ts +50 -0
- package/server/checkout-workspace-preflight.ts +349 -0
- package/server/cloud-asset-catalog.ts +158 -0
- package/server/coding-inference-launch.ts +237 -0
- package/server/collaboration-account-client.ts +202 -0
- package/server/collaboration-attribution.ts +122 -0
- package/server/collaboration-session.ts +934 -0
- package/server/comfyui-bridge.ts +248 -0
- package/server/console-ledger.ts +499 -0
- package/server/creation-site-transform.ts +304 -0
- package/server/creation-site-write.ts +648 -0
- package/server/data-file-serialize.ts +158 -0
- package/server/editor-brand-html.ts +72 -0
- package/server/editor-control-socket.ts +366 -0
- package/server/editor-server-options.ts +190 -0
- package/server/editor-server.ts +1483 -0
- package/server/editor-sse.ts +352 -0
- package/server/engine-provenance.ts +169 -0
- package/server/engine-source-restart.ts +117 -0
- package/server/frame-bridge.ts +115 -0
- package/server/frame-proxy.ts +490 -0
- package/server/frame-workbench.ts +259 -0
- package/server/frontend-handoff.ts +229 -0
- package/server/game-globals-shadow.ts +113 -0
- package/server/gameplay-session-retention.ts +149 -0
- package/server/gameplay-sessions.ts +123 -0
- package/server/generation-jobs.ts +201 -0
- package/server/generation-reconciler.ts +137 -0
- package/server/generative-execution-context.ts +59 -0
- package/server/git-workflow.ts +612 -0
- package/server/harness-chat-caller.ts +36 -0
- package/server/harness-chat-service.ts +1681 -0
- package/server/idle-shutdown.ts +170 -0
- package/server/js-profiling-policy.ts +52 -0
- package/server/launcher-settings.ts +84 -0
- package/server/local-asset-catalog.ts +410 -0
- package/server/managed-account-defaults.ts +22 -0
- package/server/mock-control-plane.ts +540 -0
- package/server/model-import-conversion.ts +345 -0
- package/server/native-credential-store.ts +162 -0
- package/server/open-browser.ts +118 -0
- package/server/packaged.ts +1192 -0
- package/server/play-stall.ts +126 -0
- package/server/process-shutdown.ts +218 -0
- package/server/product-presets.ts +55 -0
- package/server/project-build-artifact.ts +95 -0
- package/server/project-components.ts +100 -0
- package/server/project-dependency-invalidation.ts +114 -0
- package/server/project-file-scan.ts +235 -0
- package/server/project-hmr-files.ts +215 -0
- package/server/project-install-roots.ts +210 -0
- package/server/project-kinds.ts +71 -0
- package/server/project-mcp-servers.ts +82 -0
- package/server/project-module-freshness.ts +109 -0
- package/server/project-module-instance.ts +375 -0
- package/server/project-optimize-deps-entries.ts +827 -0
- package/server/project-output-writer.ts +679 -0
- package/server/project-package-origin.ts +63 -0
- package/server/project-root-surface.ts +831 -0
- package/server/project-scratch-path.ts +47 -0
- package/server/project-script-hmr.ts +619 -0
- package/server/project-serving-plugins.ts +236 -0
- package/server/project-tools.ts +653 -0
- package/server/project-validation.ts +250 -0
- package/server/project-verbs.ts +127 -0
- package/server/project-view.ts +52 -0
- package/server/project-watch.ts +1134 -0
- package/server/project-work-coordinator.ts +288 -0
- package/server/provider-credentials.ts +331 -0
- package/server/recent-projects-store.ts +98 -0
- package/server/redact-secrets.ts +71 -0
- package/server/repository-presence.ts +267 -0
- package/server/routes/account.ts +357 -0
- package/server/routes/agents.ts +60 -0
- package/server/routes/assets.ts +154 -0
- package/server/routes/build.ts +13 -0
- package/server/routes/collaboration.ts +595 -0
- package/server/routes/configurations.ts +419 -0
- package/server/routes/context.ts +264 -0
- package/server/routes/control-plane.ts +1811 -0
- package/server/routes/logs.ts +272 -0
- package/server/routes/project-identity.ts +302 -0
- package/server/routes/project-open.ts +429 -0
- package/server/routes/project-source.ts +686 -0
- package/server/routes/project-state.ts +383 -0
- package/server/routes/relay.ts +1029 -0
- package/server/routes/route-helpers.ts +29 -0
- package/server/routes/served-modules.ts +138 -0
- package/server/routes/session-tabs.ts +196 -0
- package/server/routes/settings.ts +121 -0
- package/server/routes/share-control.ts +486 -0
- package/server/routes/themes.ts +116 -0
- package/server/routes/tools.ts +230 -0
- package/server/routes/worktrees.ts +595 -0
- package/server/scoped-game-css.ts +461 -0
- package/server/server-utils.ts +1194 -0
- package/server/session-product.ts +112 -0
- package/server/session-registry.ts +230 -0
- package/server/share-claims.ts +138 -0
- package/server/share-host.ts +526 -0
- package/server/share-session-gateway.ts +1362 -0
- package/server/share-tunnel.ts +123 -0
- package/server/spawn-opener.ts +74 -0
- package/server/support/play/log-format.ts +76 -0
- package/server/support/play/session-record.ts +199 -0
- package/server/support/project/build-discipline.ts +718 -0
- package/server/support/project/inspection-node.ts +119 -0
- package/server/support/project/log-naming.ts +54 -0
- package/server/support/project/provenance.ts +290 -0
- package/server/support/project/run-name.ts +18 -0
- package/server/support/project/session-journal.ts +830 -0
- package/server/support/project/shared.ts +327 -0
- package/server/tab-bootstrap.ts +62 -0
- package/server/tab-heartbeat.ts +477 -0
- package/server/tab-lifecycle.ts +550 -0
- package/server/tab-presence.ts +1508 -0
- package/server/team-agent-mirror.ts +95 -0
- package/server/twin-auth.ts +138 -0
- package/server/vendored-lock-recorder.ts +968 -0
- package/server/worktree-identity.ts +121 -0
- package/server/worktree-management.ts +398 -0
- package/server/worktree-retention.d.mts +13 -0
- package/server/worktree-retention.mjs +205 -0
- package/src/EditorContext.tsx +169 -0
- package/src/account.ts +333 -0
- package/src/action-registry.ts +532 -0
- package/src/active-product.ts +74 -0
- package/src/active-project.ts +155 -0
- package/src/adapter-editor-config.ts +25 -0
- package/src/adapter-observation.ts +49 -0
- package/src/animation/stage-transport.ts +379 -0
- package/src/animation/three-clips-subject.ts +172 -0
- package/src/api/asset-library-wire.ts +45 -0
- package/src/api/assets.ts +365 -0
- package/src/api/base.ts +10 -0
- package/src/api/build.ts +99 -0
- package/src/api/git-wire.ts +56 -0
- package/src/api/logs.ts +92 -0
- package/src/api/project-identity.ts +74 -0
- package/src/api/project-open.ts +355 -0
- package/src/api/project-source.ts +162 -0
- package/src/api/project-state.ts +107 -0
- package/src/api/relay.ts +268 -0
- package/src/api/settings.ts +36 -0
- package/src/api/themes.ts +45 -0
- package/src/api/worktrees.ts +257 -0
- package/src/asset-compare-core.ts +171 -0
- package/src/asset-compare.ts +294 -0
- package/src/asset-editor-context.tsx +100 -0
- package/src/asset-events.ts +97 -0
- package/src/asset-inspector-actions.ts +87 -0
- package/src/asset-preview-framing.ts +357 -0
- package/src/asset-preview.ts +2802 -0
- package/src/asset-selection-viewer-registry.ts +113 -0
- package/src/asset-selection.ts +133 -0
- package/src/asset-workflow/asset-capabilities.ts +344 -0
- package/src/asset-workflow/asset-import-jobs.ts +106 -0
- package/src/asset-workflow/asset-ledger-backend.ts +126 -0
- package/src/asset-workflow/asset-ledger.ts +156 -0
- package/src/asset-workflow/asset-materialization-report.ts +140 -0
- package/src/asset-workflow/asset-pack-manifest.ts +320 -0
- package/src/asset-workflow/asset-types.ts +142 -0
- package/src/asset-workflow/asset-workflow-quality.ts +61 -0
- package/src/asset-workflow/audio-preview-player.ts +193 -0
- package/src/asset-workflow/audio-waveform.ts +22 -0
- package/src/asset-workflow/cloud-asset-client.ts +263 -0
- package/src/asset-workflow/folder-preview.ts +345 -0
- package/src/asset-workflow/hosted-asset-materialization.ts +236 -0
- package/src/asset-workflow/image-view-scale.ts +32 -0
- package/src/asset-workflow/import-contract.ts +124 -0
- package/src/asset-workflow/ledger-write-lock.ts +244 -0
- package/src/asset-workflow/model-inspection.ts +818 -0
- package/src/asset-workflow/pixi-spritesheet.ts +197 -0
- package/src/asset-workflow/preview-resource-lifetime.ts +44 -0
- package/src/asset-workflow/project-asset-commands.ts +23 -0
- package/src/asset-workflow/project-asset-health.ts +139 -0
- package/src/asset-workflow/project-asset-operations.ts +154 -0
- package/src/asset-workflow/project-asset-roots.ts +68 -0
- package/src/asset-workflow/project-content.ts +288 -0
- package/src/asset-workflow/project-source-index.ts +550 -0
- package/src/asset-workflow/thumbnail-system.ts +256 -0
- package/src/authoring/active-adapter.ts +199 -0
- package/src/authoring/active-systems.ts +422 -0
- package/src/authoring/adapter-key.ts +18 -0
- package/src/authoring/authoring-asset-url.ts +27 -0
- package/src/authoring/bootstrap-state.ts +49 -0
- package/src/authoring/boundary-authoring-adapter.ts +184 -0
- package/src/authoring/breakpoint-state.ts +43 -0
- package/src/authoring/canvas-scene-guides.ts +76 -0
- package/src/authoring/component-instance-root.ts +171 -0
- package/src/authoring/composite-authoring-adapter.ts +2110 -0
- package/src/authoring/consumer-actions.ts +520 -0
- package/src/authoring/css-numeric-style.ts +97 -0
- package/src/authoring/design-time-layers.ts +849 -0
- package/src/authoring/design-time-mount-registry.ts +235 -0
- package/src/authoring/design-time-settle.ts +343 -0
- package/src/authoring/edit-mode-authoring.ts +619 -0
- package/src/authoring/eyedropper-session.ts +60 -0
- package/src/authoring/instance-source-menu-register.ts +13 -0
- package/src/authoring/instance-source-menu.ts +135 -0
- package/src/authoring/layered-pick.ts +183 -0
- package/src/authoring/live-gesture-lock.ts +50 -0
- package/src/authoring/live-object-transform.ts +62 -0
- package/src/authoring/mount-failure-report.ts +154 -0
- package/src/authoring/mounted-root-subjects.ts +144 -0
- package/src/authoring/no-authoring-adapter.ts +55 -0
- package/src/authoring/null-inspection-subjects.tsx +75 -0
- package/src/authoring/object3d-document-persistence.ts +106 -0
- package/src/authoring/object3d-document-session-registry.ts +120 -0
- package/src/authoring/object3d-document-session.ts +1326 -0
- package/src/authoring/object3d-gesture-controller.ts +113 -0
- package/src/authoring/panel-authoring.ts +121 -0
- package/src/authoring/prefab-instance-inspector-section.tsx +237 -0
- package/src/authoring/prefab-instance-section-model.ts +55 -0
- package/src/authoring/project-authoring-session.ts +105 -0
- package/src/authoring/provenance.ts +99 -0
- package/src/authoring/quarks-particle-systems.ts +19 -0
- package/src/authoring/react-canvas-navigation.ts +255 -0
- package/src/authoring/react-design-canvas-style.ts +20 -0
- package/src/authoring/react-story-board.ts +937 -0
- package/src/authoring/selection-scope.ts +195 -0
- package/src/authoring/shell-document-ops.ts +169 -0
- package/src/authoring/shell-object3d-document-write-policy.ts +108 -0
- package/src/authoring/shell-viewport-policy.ts +48 -0
- package/src/authoring/source-object3d-authoring-adapter.ts +526 -0
- package/src/authoring/stories-scope.ts +35 -0
- package/src/authoring/story-board-chrome-fit.ts +107 -0
- package/src/authoring/story-board-presentation.ts +111 -0
- package/src/authoring/three-projection-core.ts +226 -0
- package/src/authoring/viewport-pick-context.ts +40 -0
- package/src/authoring/viewport-raycast.ts +240 -0
- package/src/authoring/viewport-tool-context.ts +73 -0
- package/src/authoring/world-canvas-viewport-state.ts +35 -0
- package/src/authoring/world-hidden-viewport.ts +152 -0
- package/src/authoring/world-pan-state.ts +198 -0
- package/src/authoring/world-session-state.ts +101 -0
- package/src/authoring/write-pipe.ts +173 -0
- package/src/availability-tick.ts +66 -0
- package/src/bitmap-label.ts +120 -0
- package/src/blender-tab-metrics.ts +161 -0
- package/src/board-open-actions.ts +20 -0
- package/src/boot-routing.ts +391 -0
- package/src/build-identity.ts +15 -0
- package/src/bytes-codec.ts +62 -0
- package/src/camera-authoring.ts +175 -0
- package/src/cancellation-reason.ts +58 -0
- package/src/canvas-preview-frames.ts +482 -0
- package/src/capture-camera-pose.ts +77 -0
- package/src/chrome-registry.ts +159 -0
- package/src/chrome-slot-registry.ts +91 -0
- package/src/collaboration-client.ts +264 -0
- package/src/collaboration-presence.ts +41 -0
- package/src/command-dispatch.ts +19 -0
- package/src/command-listener.ts +2743 -0
- package/src/command-registry.ts +70 -0
- package/src/component-board-registry.ts +205 -0
- package/src/component-states-registry.ts +200 -0
- package/src/components/AgentPresentationNotice.tsx +75 -0
- package/src/components/AlignToolbar.tsx +204 -0
- package/src/components/AppRoot.tsx +394 -0
- package/src/components/ApplicationMenus.tsx +415 -0
- package/src/components/AssetBrowser.tsx +2843 -0
- package/src/components/AssetEditorShell.tsx +216 -0
- package/src/components/AssetInspectorToolSection.tsx +124 -0
- package/src/components/BoardRulers.tsx +354 -0
- package/src/components/CameraInfo.tsx +81 -0
- package/src/components/CanvasSceneViewport.tsx +556 -0
- package/src/components/CapabilityCoverageSection.tsx +185 -0
- package/src/components/CenterDocuments.tsx +22 -0
- package/src/components/ChromeSlot.tsx +20 -0
- package/src/components/CodeView.tsx +470 -0
- package/src/components/CollaborationHeaderControl.css +74 -0
- package/src/components/CompactInspectorCard.tsx +190 -0
- package/src/components/CompactInspectorShell.tsx +39 -0
- package/src/components/ConsolePanel.css +55 -0
- package/src/components/ConsolePanel.tsx +270 -0
- package/src/components/DefaultEditorLayout.tsx +106 -0
- package/src/components/DocumentHeaderStrip.tsx +96 -0
- package/src/components/DocumentShelfRail.tsx +45 -0
- package/src/components/DocumentThumbnail.tsx +345 -0
- package/src/components/EditorLeaseGuard.tsx +372 -0
- package/src/components/ErrorBanner.tsx +123 -0
- package/src/components/FolderPreviewTile.tsx +159 -0
- package/src/components/GameHierarchy.tsx +3842 -0
- package/src/components/GameplaySessionTimeline.tsx +295 -0
- package/src/components/InspectionProjection.tsx +968 -0
- package/src/components/Inspector.tsx +233 -0
- package/src/components/InspectorCanvasPreview.tsx +35 -0
- package/src/components/InspectorFieldsSection.tsx +290 -0
- package/src/components/InspectorObjectPreview.tsx +57 -0
- package/src/components/InspectorStoriesSection.tsx +92 -0
- package/src/components/InspectorToolSection.tsx +96 -0
- package/src/components/InspectorTransformSection.tsx +245 -0
- package/src/components/LightExplorerPanel.tsx +433 -0
- package/src/components/MediaProperties.tsx +145 -0
- package/src/components/NonThreeAuthoringBootstrap.tsx +19 -0
- package/src/components/Object3DDocumentToolbar.css +100 -0
- package/src/components/Object3DDocumentToolbar.tsx +454 -0
- package/src/components/Object3DDocumentViewport.tsx +58 -0
- package/src/components/ProjectHeader.css +617 -0
- package/src/components/ProjectHeader.tsx +328 -0
- package/src/components/ProjectLayout.tsx +249 -0
- package/src/components/ReactCanvasControls.tsx +284 -0
- package/src/components/RootSelectionOverlay.tsx +3162 -0
- package/src/components/RootTextEditor.tsx +79 -0
- package/src/components/SaveStatus.tsx +70 -0
- package/src/components/StageHost.tsx +1954 -0
- package/src/components/StageOverlays.tsx +21 -0
- package/src/components/StartupErrorScreen.tsx +76 -0
- package/src/components/StartupLoadingScreen.tsx +65 -0
- package/src/components/StatsOverlay.tsx +78 -0
- package/src/components/SurfaceStateOverlay.tsx +24 -0
- package/src/components/ToolContributionSurfaces.tsx +65 -0
- package/src/components/ToolHost.tsx +370 -0
- package/src/components/ToolObject3DPreview.tsx +39 -0
- package/src/components/Toolbar.tsx +595 -0
- package/src/components/TransientHint.tsx +44 -0
- package/src/components/TransportStrip.tsx +174 -0
- package/src/components/VersionControlSection.tsx +470 -0
- package/src/components/VgaiLogo.css +83 -0
- package/src/components/VgaiLogo.tsx +35 -0
- package/src/components/ViewportControlsHint.tsx +60 -0
- package/src/components/ViewportFurniture.tsx +401 -0
- package/src/components/ViewportOverlay.tsx +145 -0
- package/src/components/ViewportOverlaysMenu.tsx +153 -0
- package/src/components/ViewportShadingMenu.tsx +300 -0
- package/src/components/ViewportViewMenu.tsx +101 -0
- package/src/components/WorkspaceDocumentSurface.tsx +204 -0
- package/src/components/WorkspaceUtilitySurface.tsx +22 -0
- package/src/components/WorktreeSwitcher.css +239 -0
- package/src/components/WorktreeSwitcher.tsx +890 -0
- package/src/components/account-documents.tsx +1162 -0
- package/src/components/asset-documents.tsx +812 -0
- package/src/components/asset-editor-persistence.ts +216 -0
- package/src/components/asset-selection-section.tsx +535 -0
- package/src/components/asset-thumbnails.tsx +312 -0
- package/src/components/asset-viewers/AudioViewer.tsx +201 -0
- package/src/components/asset-viewers/EntityModelDocument.tsx +122 -0
- package/src/components/asset-viewers/EnvironmentAssetDocument.tsx +440 -0
- package/src/components/asset-viewers/GenericJsonViewer.tsx +102 -0
- package/src/components/asset-viewers/ImageViewer.tsx +300 -0
- package/src/components/asset-viewers/JsonAssetDocument.tsx +93 -0
- package/src/components/asset-viewers/LiveModuleDocument.tsx +417 -0
- package/src/components/asset-viewers/LutAssetDocument.tsx +444 -0
- package/src/components/asset-viewers/ModelAssetDocument.tsx +105 -0
- package/src/components/asset-viewers/Object3DPreview.tsx +359 -0
- package/src/components/asset-viewers/OnlineAssetDetail.tsx +421 -0
- package/src/components/asset-viewers/PasteboardModuleDocument.tsx +67 -0
- package/src/components/asset-viewers/QuarksAssetDocument.tsx +526 -0
- package/src/components/asset-viewers/ShaderAssetDocument.tsx +743 -0
- package/src/components/asset-viewers/SourceAssetViewer.tsx +281 -0
- package/src/components/asset-viewers/SpritesheetSpriteView.tsx +102 -0
- package/src/components/asset-viewers/VideoViewer.tsx +101 -0
- package/src/components/asset-viewers/shader-source.ts +144 -0
- package/src/components/asset-workflow.css +731 -0
- package/src/components/board-guides.ts +150 -0
- package/src/components/compact-inspector.css +539 -0
- package/src/components/core-utilities.tsx +90 -0
- package/src/components/editor-notifications.css +40 -0
- package/src/components/engine-workspace.css +274 -0
- package/src/components/inspector-preview-section.tsx +238 -0
- package/src/components/inspector-property-grouping.ts +64 -0
- package/src/components/inspector-revert-label.ts +20 -0
- package/src/components/inspector-selection.ts +42 -0
- package/src/components/inspector-stories-gating.ts +171 -0
- package/src/components/inspector-transform-subject.ts +11 -0
- package/src/components/inspector-transform.ts +75 -0
- package/src/components/kind-documents.tsx +500 -0
- package/src/components/palette-action-publisher.tsx +140 -0
- package/src/components/primitives/DraftColorInput.tsx +74 -0
- package/src/components/product-shell.css +1829 -0
- package/src/components/project-tool-documents.tsx +410 -0
- package/src/components/scene-documents.tsx +223 -0
- package/src/components/stage-keyboard.tsx +37 -0
- package/src/components/stage-overlay-set.tsx +107 -0
- package/src/components/stage-presence-markers.ts +478 -0
- package/src/components/standard-viewport-dressing.ts +417 -0
- package/src/components/status-contributions.tsx +403 -0
- package/src/components/tool-documents.tsx +309 -0
- package/src/components/tool-schema-form.tsx +262 -0
- package/src/components/use-after-paint.ts +41 -0
- package/src/components/use-project-image-assets.ts +86 -0
- package/src/components/viewport-header-controls.css +90 -0
- package/src/components/viewport-surface-status.tsx +55 -0
- package/src/components/workspace-history.ts +32 -0
- package/src/components/workspace-static-panel-registry.tsx +152 -0
- package/src/components/workspace-surfaces.css +621 -0
- package/src/components/world-documents.tsx +586 -0
- package/src/components/world-overlay-gestures.ts +1694 -0
- package/src/composite-screenshot.ts +1641 -0
- package/src/console-sync.ts +131 -0
- package/src/constraint-helper.ts +338 -0
- package/src/content-entry-source-registry.ts +184 -0
- package/src/coverage/authoring-seam-evidence.ts +300 -0
- package/src/coverage/canvas-reveal.ts +192 -0
- package/src/coverage/design-time-surfaces.ts +101 -0
- package/src/coverage/live-seam-evidence.ts +11 -0
- package/src/coverage/ontology-invariants.ts +466 -0
- package/src/coverage/session-vitals.ts +501 -0
- package/src/coverage/system-seam-evidence.ts +72 -0
- package/src/crash-null-boundary.ts +36 -0
- package/src/creation-site-edit.ts +1479 -0
- package/src/creation-site-registry.ts +160 -0
- package/src/delegate-harness-registry.ts +143 -0
- package/src/document-context-registry.ts +177 -0
- package/src/document-open-registry.ts +200 -0
- package/src/document-preview-source.ts +20 -0
- package/src/document-renderer-session.ts +138 -0
- package/src/editor-api.ts +46 -0
- package/src/editor-chrome-capture.ts +139 -0
- package/src/editor-commands.ts +164 -0
- package/src/editor-console.ts +563 -0
- package/src/editor-current-view.ts +82 -0
- package/src/editor-document-probe.ts +881 -0
- package/src/editor-git-client.ts +115 -0
- package/src/editor-host-door.ts +462 -0
- package/src/editor-hotkeys.ts +842 -0
- package/src/editor-lease-view.ts +39 -0
- package/src/editor-lease.ts +415 -0
- package/src/editor-mode.ts +19 -0
- package/src/editor-notifications.ts +140 -0
- package/src/editor-presence.ts +563 -0
- package/src/editor-presentation-activity.ts +50 -0
- package/src/editor-presentation-notice.ts +42 -0
- package/src/editor-runtime.tsx +145 -0
- package/src/editor-server-response.ts +86 -0
- package/src/editor-session-attribution.ts +75 -0
- package/src/editor-session-mode.ts +54 -0
- package/src/editor-shell-store.ts +1304 -0
- package/src/editor-state-facets.ts +74 -0
- package/src/editor-styles.css +33 -0
- package/src/editor-view-presentation.ts +810 -0
- package/src/editor-viewport.ts +5302 -0
- package/src/entity-lod.ts +31 -0
- package/src/entity-object.ts +91 -0
- package/src/files/file-provider.ts +62 -0
- package/src/files/project-files.ts +264 -0
- package/src/finders/index.ts +136 -0
- package/src/finders/scenes-from-entrypoint-selection.ts +387 -0
- package/src/frame/bridge.tsx +1408 -0
- package/src/frame/product.ts +77 -0
- package/src/gameplay-dom-recording.ts +319 -0
- package/src/gameplay-export-state.ts +14 -0
- package/src/gameplay-replay.ts +417 -0
- package/src/gameplay-session-time.ts +9 -0
- package/src/gameplay-sessions.ts +204 -0
- package/src/harness-chat-types.ts +253 -0
- package/src/hierarchy-component-marks.ts +298 -0
- package/src/hierarchy-drop.ts +91 -0
- package/src/hierarchy-expansion-state.ts +80 -0
- package/src/hierarchy-header-slot.ts +52 -0
- package/src/hierarchy-internals.ts +197 -0
- package/src/hierarchy-kind-icon.ts +217 -0
- package/src/hierarchy-mark-reader.ts +73 -0
- package/src/hierarchy-menu-registry.ts +67 -0
- package/src/hierarchy-node-rows.ts +307 -0
- package/src/hierarchy-panel-view.ts +280 -0
- package/src/hierarchy-projection.ts +76 -0
- package/src/hierarchy-row-cache.ts +243 -0
- package/src/hierarchy-row-model.ts +308 -0
- package/src/hierarchy-rows.ts +11 -0
- package/src/hierarchy-walk.ts +86 -0
- package/src/history/editor-session.ts +25 -0
- package/src/history/history-commands.ts +147 -0
- package/src/history/history-delegate.ts +163 -0
- package/src/history/history-limit-notices.ts +43 -0
- package/src/history/history-service.ts +1173 -0
- package/src/history/persistence-coordinator.ts +35 -0
- package/src/history/project-file-history.ts +386 -0
- package/src/history/project-root-history-backends.ts +139 -0
- package/src/history/resource-registry.ts +209 -0
- package/src/history/snapshot-store.ts +103 -0
- package/src/history/source-history-backend.ts +546 -0
- package/src/history/types.ts +124 -0
- package/src/hmr-registration-group.ts +67 -0
- package/src/hmr-stable-react-context.ts +23 -0
- package/src/hotkeys.ts +188 -0
- package/src/inference-diagnostics.ts +69 -0
- package/src/initial-project.ts +80 -0
- package/src/inspection/active-subject.ts +578 -0
- package/src/inspection/active-surface.ts +142 -0
- package/src/inspection/compose.ts +1064 -0
- package/src/inspection/display.ts +170 -0
- package/src/inspection/document-subject.ts +109 -0
- package/src/inspection/game-subject.ts +85 -0
- package/src/inspection/model.ts +542 -0
- package/src/inspection/null-subject.ts +115 -0
- package/src/inspection/serialize.ts +357 -0
- package/src/inspection/use-active-inspection.ts +180 -0
- package/src/inspector-presentation.ts +201 -0
- package/src/inspector-section-registry.ts +221 -0
- package/src/instance-source-actions.ts +163 -0
- package/src/instanced-presentation.ts +164 -0
- package/src/js-heap.ts +71 -0
- package/src/key-actions.ts +91 -0
- package/src/keymap-presets.ts +401 -0
- package/src/layout-policy.ts +31 -0
- package/src/learn-links.ts +73 -0
- package/src/light-explorer-model.ts +134 -0
- package/src/live-canvas-frame.ts +55 -0
- package/src/live-document.ts +279 -0
- package/src/live-module-source.ts +230 -0
- package/src/live-session-registry.ts +220 -0
- package/src/live-transition.ts +633 -0
- package/src/manifest-project.ts +107 -0
- package/src/model-thumbnail.ts +523 -0
- package/src/native-selection-style.ts +202 -0
- package/src/object3d-document-write-policy.ts +137 -0
- package/src/packaged-runtime.ts +108 -0
- package/src/palettes/maya.palette.json +57 -0
- package/src/palettes/substance.palette.json +57 -0
- package/src/pasteboard-module.ts +81 -0
- package/src/performance-profiler.ts +367 -0
- package/src/performance-sources.ts +69 -0
- package/src/play-boot-phase.ts +145 -0
- package/src/presentation-surface.ts +248 -0
- package/src/project-adapter.ts +1143 -0
- package/src/project-asset-refresh.ts +26 -0
- package/src/project-declaration-refresh.ts +31 -0
- package/src/project-local-state.ts +118 -0
- package/src/project-manager.ts +243 -0
- package/src/project-module-changes.ts +163 -0
- package/src/project-module-split.ts +266 -0
- package/src/project-provenance.ts +115 -0
- package/src/project-ready.ts +42 -0
- package/src/project-session-reset.ts +67 -0
- package/src/project-shape.ts +68 -0
- package/src/project-tool-discovery.ts +66 -0
- package/src/project-tools.ts +107 -0
- package/src/project-work-types.ts +149 -0
- package/src/projection/three.ts +898 -0
- package/src/projection/types.ts +44 -0
- package/src/readiness.ts +113 -0
- package/src/reflection-probe-helper.ts +142 -0
- package/src/reported-play-state.ts +90 -0
- package/src/resolve-relative-specifier.ts +33 -0
- package/src/scene-document-plan.ts +315 -0
- package/src/scene-framing.ts +315 -0
- package/src/scene-live-open.ts +210 -0
- package/src/scene-view-fog.ts +89 -0
- package/src/scoped-game-css.ts +152 -0
- package/src/session-orphan-record.ts +193 -0
- package/src/session-tombstone.ts +126 -0
- package/src/settings/settings-provider.ts +82 -0
- package/src/settings-store.ts +345 -0
- package/src/shared-view-restore.ts +42 -0
- package/src/shell-store-door.ts +45 -0
- package/src/source-conflict.ts +122 -0
- package/src/spatial-handle-visuals.ts +332 -0
- package/src/stage-context.ts +341 -0
- package/src/stage-store-registry.ts +63 -0
- package/src/stale-chunk-recovery.ts +34 -0
- package/src/state-report-deferral.ts +73 -0
- package/src/storage/host-files-storage.ts +97 -0
- package/src/storage/http-storage.ts +174 -0
- package/src/storage/index.ts +75 -0
- package/src/storage/mem-storage.ts +149 -0
- package/src/storage/path-lock.ts +44 -0
- package/src/storage/paths.ts +26 -0
- package/src/storage/types.ts +116 -0
- package/src/stories/StoryComponentThumbnail.tsx +184 -0
- package/src/stories/StoryPreviewMount.tsx +306 -0
- package/src/stories/component-content-source.tsx +106 -0
- package/src/stories/component-states-source.ts +78 -0
- package/src/stories/compose-project-stories.ts +255 -0
- package/src/stories/pixi-story-model.ts +30 -0
- package/src/stories/prefabs-finder.ts +54 -0
- package/src/stories/prefabs-from-stories.ts +182 -0
- package/src/stories/project-story-discovery.ts +78 -0
- package/src/stories/project-story-regions.ts +24 -0
- package/src/stories/story-actions.ts +54 -0
- package/src/stories/story-capture-command.ts +124 -0
- package/src/stories/story-capture.ts +584 -0
- package/src/stories/story-declared-medium.ts +126 -0
- package/src/stories/story-discovery.ts +176 -0
- package/src/stories/story-document-openers.ts +36 -0
- package/src/stories/story-dom-runtime.ts +78 -0
- package/src/stories/story-grouping.ts +111 -0
- package/src/stories/story-lane.ts +88 -0
- package/src/stories/story-mount-turn.ts +27 -0
- package/src/stories/story-opener.ts +260 -0
- package/src/stories/story-pixi-preview.ts +408 -0
- package/src/stories/story-presentation.ts +215 -0
- package/src/stories/story-registry.ts +517 -0
- package/src/stories/story-three-preview.ts +807 -0
- package/src/stories/three-story-model.ts +96 -0
- package/src/story-three-preview-runtime.ts +56 -0
- package/src/surface-keyboard.ts +112 -0
- package/src/surface-state.ts +124 -0
- package/src/tab-bootstrap.js +628 -0
- package/src/tab-census.ts +198 -0
- package/src/tab-lifecycle-client.ts +196 -0
- package/src/theme-library.ts +844 -0
- package/src/theme-preference.ts +378 -0
- package/src/theme.css +3437 -0
- package/src/three-viewport/bone-selection-highlight.ts +119 -0
- package/src/three-viewport/camera-fit.ts +41 -0
- package/src/three-viewport/interactive-renderer.ts +132 -0
- package/src/three-viewport/selection-brackets.ts +310 -0
- package/src/three-viewport/selection-outline.ts +183 -0
- package/src/three-viewport/skeleton-helper.ts +61 -0
- package/src/three-viewport/source-color.ts +167 -0
- package/src/three-viewport/studio-environment.ts +96 -0
- package/src/three-viewport-presentation.ts +23 -0
- package/src/tool-contribution-play.ts +74 -0
- package/src/tool-loader.ts +1798 -0
- package/src/transform-mode-request.ts +57 -0
- package/src/transient-hint.ts +78 -0
- package/src/trigger-volume-helper.ts +116 -0
- package/src/ui-source/adapter-region-includes.ts +241 -0
- package/src/ui-source/ensure-import.ts +132 -0
- package/src/ui-source/file-region-resolver.ts +302 -0
- package/src/ui-source/inspect.ts +775 -0
- package/src/ui-source/oid-transform.ts +1845 -0
- package/src/ui-source/plan-csf-story.ts +196 -0
- package/src/ui-source/plan-extract-component.ts +421 -0
- package/src/ui-source/plan-fork-component.ts +621 -0
- package/src/ui-source/plan-named-style.ts +95 -0
- package/src/ui-source/plan-source-edit.ts +353 -0
- package/src/ui-source/r3f-contract-resolver.ts +327 -0
- package/src/ui-source/r3f-diagnostic-index.ts +165 -0
- package/src/ui-source/r3f-environment-binding.ts +133 -0
- package/src/ui-source/r3f-joint-binding.ts +251 -0
- package/src/ui-source/r3f-lod-binding.ts +91 -0
- package/src/ui-source/r3f-particle-binding.ts +235 -0
- package/src/ui-source/r3f-physics-binding.ts +483 -0
- package/src/ui-source/r3f-project-contracts.ts +444 -0
- package/src/ui-source/relative-import-specifier.ts +34 -0
- package/src/ui-source/reparent-guard.ts +544 -0
- package/src/ui-source/source-edit-request.ts +97 -0
- package/src/ui-source/source-write-backend.ts +618 -0
- package/src/ui-source/syntactic-prop-specs.ts +296 -0
- package/src/ui-source/tier-source-write-backend.ts +279 -0
- package/src/ui-source/ts-ast.ts +171 -0
- package/src/ui-source/utility-class-support.ts +169 -0
- package/src/ui-source/write-component-default.ts +133 -0
- package/src/ui-source/writer.ts +1989 -0
- package/src/viewport-activation-timings.ts +840 -0
- package/src/viewport-authoring-policy.ts +186 -0
- package/src/viewport-controls-hint.ts +57 -0
- package/src/viewport-door.ts +237 -0
- package/src/viewport-shading-boundary.ts +12 -0
- package/src/vite-error-surface.ts +141 -0
- package/src/wait-until.ts +37 -0
- package/src/workspace-areas.ts +156 -0
- package/src/workspace-aux-commands.ts +11 -0
- package/src/workspace-available-documents.ts +127 -0
- package/src/workspace-core-utilities.ts +31 -0
- package/src/workspace-document-ids.ts +59 -0
- package/src/workspace-document-registry.ts +612 -0
- package/src/workspace-document-restore.ts +145 -0
- package/src/workspace-host-commands.ts +141 -0
- package/src/workspace-persistence-gate.ts +40 -0
- package/src/workspace-play-utilities.ts +44 -0
- package/src/workspace-presets.ts +425 -0
- package/src/workspace-regions.ts +294 -0
- package/src/workspace-state-persistence.ts +536 -0
- package/src/workspace-static-panels.ts +73 -0
- package/src/workspace-status-registry.ts +121 -0
- package/src/workspace-style.ts +239 -0
- package/src/workspace-utility-commands.ts +74 -0
- package/src/workspace-utility-registry.ts +263 -0
- package/src/workspace-viewport-rect.ts +97 -0
- package/src/world-adoption.ts +115 -0
- package/src/world-document-routing.ts +104 -0
- package/vite-plugin-creation-site-write.ts +184 -0
- package/vite-plugin-creation-site.ts +80 -0
- package/vite-plugin-game-static.ts +303 -0
- package/vite-plugin-module-doorways.ts +336 -0
- package/vite-plugin-product-contributions.ts +197 -0
- package/vite-plugin-project-game-static.ts +125 -0
- package/vite-plugin-project-jsx-js.ts +65 -0
- package/vite-plugin-project-root-absolute-assets.ts +359 -0
- package/vite-plugin-shared-react.ts +420 -0
- package/vite-plugin-shared-three.ts +203 -0
- package/vite-plugin-ui-oid.ts +2106 -0
package/src/theme.css
ADDED
|
@@ -0,0 +1,3437 @@
|
|
|
1
|
+
.vgai-editor-theme {
|
|
2
|
+
/* Legacy aliases. New code consumes the semantic variables above. */
|
|
3
|
+
--vgai-bg-0: var(--vgai-surface-shell);
|
|
4
|
+
--vgai-bg-1: var(--vgai-surface-panel);
|
|
5
|
+
--vgai-bg-2: var(--vgai-surface-chrome);
|
|
6
|
+
--vgai-bg-3: var(--vgai-surface-raised);
|
|
7
|
+
--vgai-bg-inset: var(--vgai-surface-inset);
|
|
8
|
+
|
|
9
|
+
/* Borders */
|
|
10
|
+
--vgai-border-1: var(--vgai-boundary-default);
|
|
11
|
+
--vgai-border-2: var(--vgai-boundary-strong);
|
|
12
|
+
|
|
13
|
+
/* Text */
|
|
14
|
+
--vgai-text-1: var(--vgai-content-primary);
|
|
15
|
+
--vgai-text-2: var(--vgai-content-muted);
|
|
16
|
+
--vgai-text-3: var(--vgai-content-dim);
|
|
17
|
+
|
|
18
|
+
/* Interior STICKY surfaces (--vgai-surface-sticky/-panel and their
|
|
19
|
+
* -backdrop-filter): emitted per-theme by editorThemeVariables() in
|
|
20
|
+
* theme.ts since §2.31 P2 — treatment themes use the translucent token +
|
|
21
|
+
* a sticky blur (soft occlusion), treatment-less themes the opaque
|
|
22
|
+
* token-over-shell stack. See stickySurfaceValue() there. */
|
|
23
|
+
|
|
24
|
+
/* Concrete spacing, dimension, type, and stacking variables are installed
|
|
25
|
+
* by editorThemeVariables() from theme.ts. Keeping their numbers out of CSS
|
|
26
|
+
* preserves one typed source of truth for class and inline-style consumers. */
|
|
27
|
+
|
|
28
|
+
/* Asset-kind category palette (asset-thumbnails.tsx, folder previews).
|
|
29
|
+
* These are stable per-kind data colors — category identity, not chrome
|
|
30
|
+
* paint (same doctrine as the color guard's visualization allowlist), so
|
|
31
|
+
* they stay literal instead of remapping through accent/semantic slots;
|
|
32
|
+
* both shipped editor themes are dark, and these mid-tone values read on
|
|
33
|
+
* each. Named --vgai-* so the migration guard's dangling-variable check
|
|
34
|
+
* owns them: the previous --asset-* spelling was silently deleted in a
|
|
35
|
+
* refactor and every glyph went invisible. */
|
|
36
|
+
--vgai-asset-icon-folder: #e8a740;
|
|
37
|
+
--vgai-asset-icon-model: #6bc5f7;
|
|
38
|
+
--vgai-asset-icon-prefab: #3b82f6;
|
|
39
|
+
--vgai-asset-icon-component: #9ca3af;
|
|
40
|
+
--vgai-asset-icon-audio: #34d399;
|
|
41
|
+
--vgai-asset-icon-image: #f472b6;
|
|
42
|
+
--vgai-asset-icon-video: #c084fc;
|
|
43
|
+
--vgai-asset-icon-json: #fbbf24;
|
|
44
|
+
--vgai-asset-icon-unknown: #6b7280;
|
|
45
|
+
--vgai-asset-icon-source: #fb923c;
|
|
46
|
+
|
|
47
|
+
/* Content-legibility text shadow (liquid glass, report §2.32): themes with
|
|
48
|
+
* a `textShadowOpacity` treatment axis emit a real shadow via this var;
|
|
49
|
+
* every other theme emits 'none', so this inherited declaration is inert
|
|
50
|
+
* for them. Near-white text + a concentrated local shadow keeps chrome legible
|
|
51
|
+
* when the surface itself is only a ≤15% white whisper over live scene
|
|
52
|
+
* content. */
|
|
53
|
+
text-shadow: var(--vgai-content-text-shadow, none);
|
|
54
|
+
|
|
55
|
+
/* THE BASELINE. Every descendant inherits the product's type from here and
|
|
56
|
+
* declares only what differs. Before this, the root minted the tokens but
|
|
57
|
+
* applied none of them, so each surface had to opt in per property, and the
|
|
58
|
+
* ones that forgot fell to the browser's serif at 16px (the agent notice,
|
|
59
|
+
* the command palette). Declared here rather than inherited from <body>: a
|
|
60
|
+
* game's own `body { font }` rule shares this document, and a declared
|
|
61
|
+
* value on the root is what keeps it out of editor chrome. */
|
|
62
|
+
font-family: var(--vgai-font-sans);
|
|
63
|
+
font-size: var(--vgai-font-base);
|
|
64
|
+
line-height: var(--vgai-leading-normal);
|
|
65
|
+
color: var(--vgai-content-primary);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Content-zone frost (§2.31 P2 owner amendment): text-dense interior zones
|
|
69
|
+
* get a LOCAL frosted-blur layer so text stays legible over open glass,
|
|
70
|
+
* while gutters/bezels stay clear and refractive. Both vars are emitted by
|
|
71
|
+
* editorThemeVariables() from the `contentFrostBlurPx` treatment axis —
|
|
72
|
+
* `transparent`/`none` for every theme without it (byte-identical paint,
|
|
73
|
+
* including the reduced-transparency degrade, which strips `treatment`).
|
|
74
|
+
* The parent card's refraction url() filter makes the card a backdrop root,
|
|
75
|
+
* so this blur samples the already-refracted backdrop — frost over the
|
|
76
|
+
* lensed scene, the intended composite. */
|
|
77
|
+
.vgai-content-frost {
|
|
78
|
+
background: var(--vgai-content-frost-bg, transparent);
|
|
79
|
+
backdrop-filter: var(--vgai-content-frost-filter, none);
|
|
80
|
+
-webkit-backdrop-filter: var(--vgai-content-frost-filter, none);
|
|
81
|
+
border-radius: var(--vgai-radius-md);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/* Adaptive foreground ink follows measured backdrop luminance. Compact
|
|
85
|
+
* navigation islands expose this as a local appearance flip. Larger Regular
|
|
86
|
+
* surfaces use the same foreground threshold, while retaining a shallow
|
|
87
|
+
* material correction independent of that ink decision. */
|
|
88
|
+
.vgai-editor-theme [data-vgai-adaptive-ink="bright"] {
|
|
89
|
+
--vgai-backdrop-dim: none;
|
|
90
|
+
--vgai-content-primary: var(--vgai-content-primary-on-bright);
|
|
91
|
+
--vgai-content-muted: var(--vgai-content-muted-on-bright);
|
|
92
|
+
--vgai-content-dim: var(--vgai-content-dim-on-bright);
|
|
93
|
+
--vgai-content-text-shadow: var(--vgai-content-text-shadow-on-bright);
|
|
94
|
+
--vgai-content-frost-bg: var(--vgai-content-frost-bg-on-bright);
|
|
95
|
+
--vgai-island-border-color: color-mix(
|
|
96
|
+
in srgb,
|
|
97
|
+
var(--vgai-content-primary-on-bright) 30%,
|
|
98
|
+
transparent
|
|
99
|
+
);
|
|
100
|
+
--vgai-text-1: var(--vgai-content-primary);
|
|
101
|
+
--vgai-text-2: var(--vgai-content-muted);
|
|
102
|
+
--vgai-text-3: var(--vgai-content-dim);
|
|
103
|
+
--dv-activegroup-visiblepanel-tab-color: var(--vgai-content-primary);
|
|
104
|
+
--dv-activegroup-hiddenpanel-tab-color: var(--vgai-content-muted);
|
|
105
|
+
--dv-inactivegroup-visiblepanel-tab-color: var(--vgai-content-muted);
|
|
106
|
+
--dv-inactivegroup-hiddenpanel-tab-color: var(--vgai-content-dim);
|
|
107
|
+
text-shadow: var(--vgai-content-text-shadow, none);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Complex authored UI is a deliberately non-adaptive backdrop. Regular
|
|
111
|
+
* panels over it use stable light ink and a strong dark frost rather than
|
|
112
|
+
* chasing local component colors as the interface changes beneath them. */
|
|
113
|
+
.vgai-editor-theme [data-vgai-panel-backdrop-policy="dark-frost"] {
|
|
114
|
+
--vgai-content-primary: #f4f8ff;
|
|
115
|
+
--vgai-content-muted: #c3cedd;
|
|
116
|
+
--vgai-content-dim: #94a2b5;
|
|
117
|
+
--vgai-content-text-shadow: 0 1px 3px rgb(0 0 0 / 72%);
|
|
118
|
+
--vgai-text-1: var(--vgai-content-primary);
|
|
119
|
+
--vgai-text-2: var(--vgai-content-muted);
|
|
120
|
+
--vgai-text-3: var(--vgai-content-dim);
|
|
121
|
+
--dv-activegroup-visiblepanel-tab-color: var(--vgai-content-primary);
|
|
122
|
+
--dv-activegroup-hiddenpanel-tab-color: var(--vgai-content-muted);
|
|
123
|
+
--dv-inactivegroup-visiblepanel-tab-color: var(--vgai-content-muted);
|
|
124
|
+
--dv-inactivegroup-hiddenpanel-tab-color: var(--vgai-content-dim);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Native controls otherwise fall back to the browser's unrelated UI font.
|
|
128
|
+
* Keep the reset scoped to the editor shell; component classes and inline
|
|
129
|
+
* styles can still opt into a different size or the monospace stack. */
|
|
130
|
+
.vgai-editor-shell button,
|
|
131
|
+
.vgai-editor-shell input,
|
|
132
|
+
.vgai-editor-shell select,
|
|
133
|
+
.vgai-editor-shell textarea {
|
|
134
|
+
font-family: inherit;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.vgai-editor-shell button {
|
|
138
|
+
font-size: inherit;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/* Visually hidden content remains available to assistive technology. */
|
|
142
|
+
.vgai-sr-only {
|
|
143
|
+
position: absolute;
|
|
144
|
+
width: 1px;
|
|
145
|
+
height: 1px;
|
|
146
|
+
padding: 0;
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
clip: rect(0, 0, 0, 0);
|
|
149
|
+
white-space: nowrap;
|
|
150
|
+
border: 0;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.vgai-tooltip-anchor {
|
|
154
|
+
position: relative;
|
|
155
|
+
display: inline-flex;
|
|
156
|
+
}
|
|
157
|
+
.vgai-tooltip {
|
|
158
|
+
position: fixed;
|
|
159
|
+
z-index: var(--vgai-z-dropdown);
|
|
160
|
+
display: flex;
|
|
161
|
+
align-items: center;
|
|
162
|
+
gap: var(--vgai-space-4);
|
|
163
|
+
padding: var(--vgai-space-2) var(--vgai-space-4);
|
|
164
|
+
color: var(--vgai-content-primary);
|
|
165
|
+
background: var(--vgai-surface-inset);
|
|
166
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-strong);
|
|
167
|
+
border-radius: var(--vgai-radius-md);
|
|
168
|
+
box-shadow: var(--vgai-shadow-sm);
|
|
169
|
+
font-size: var(--vgai-font-base);
|
|
170
|
+
white-space: nowrap;
|
|
171
|
+
pointer-events: none;
|
|
172
|
+
}
|
|
173
|
+
.vgai-tooltip kbd {
|
|
174
|
+
padding: 1px var(--vgai-space-3);
|
|
175
|
+
color: var(--vgai-content-primary);
|
|
176
|
+
background: var(--vgai-surface-raised);
|
|
177
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
178
|
+
border-radius: var(--vgai-radius-sm);
|
|
179
|
+
font-family: var(--vgai-font-mono);
|
|
180
|
+
font-size: var(--vgai-font-sm);
|
|
181
|
+
}
|
|
182
|
+
/* U6a (P6 glass-native chrome, inventory row "tooltip"): under islands
|
|
183
|
+
* chrome the tooltip is transient overlay chrome like `.vgai-menu` — the
|
|
184
|
+
* self-sufficient Regular material (`--vgai-glass-regular-bg` + its
|
|
185
|
+
* strong frost) statically paired with the `-on-bright` ink ramp, legible
|
|
186
|
+
* over ANY backdrop. Same re-declaration rationale as the `.vgai-menu`
|
|
187
|
+
* block below: descendants inherit the theme root's COMPUTED shadow, so the
|
|
188
|
+
* flipped var needs a fresh `text-shadow` declaration here. Bars chrome
|
|
189
|
+
* (graphite/classic, reduced-transparency/lite) never matches — the dark
|
|
190
|
+
* inset slab above stays byte-identical. The kbd chip re-tints from
|
|
191
|
+
* `currentColor` so it reads on either ink side. */
|
|
192
|
+
[data-vgai-chrome="islands"] .vgai-tooltip {
|
|
193
|
+
--vgai-content-primary: var(--vgai-content-primary-on-bright);
|
|
194
|
+
--vgai-content-muted: var(--vgai-content-muted-on-bright);
|
|
195
|
+
--vgai-content-dim: var(--vgai-content-dim-on-bright);
|
|
196
|
+
--vgai-content-text-shadow: var(--vgai-content-text-shadow-on-bright);
|
|
197
|
+
--vgai-text-1: var(--vgai-content-primary);
|
|
198
|
+
--vgai-text-2: var(--vgai-content-muted);
|
|
199
|
+
--vgai-text-3: var(--vgai-content-dim);
|
|
200
|
+
text-shadow: var(--vgai-content-text-shadow, none);
|
|
201
|
+
background: var(--vgai-glass-regular-bg, var(--vgai-surface-chrome));
|
|
202
|
+
border-color: var(--vgai-border-1);
|
|
203
|
+
backdrop-filter: var(--vgai-glass-regular-backdrop-filter, none);
|
|
204
|
+
-webkit-backdrop-filter: var(--vgai-glass-regular-backdrop-filter, none);
|
|
205
|
+
}
|
|
206
|
+
[data-vgai-chrome="islands"] .vgai-tooltip kbd {
|
|
207
|
+
color: inherit;
|
|
208
|
+
background: color-mix(in srgb, currentColor 10%, transparent);
|
|
209
|
+
border-color: color-mix(in srgb, currentColor 28%, transparent);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/* ---------------------------------------------------------------------- */
|
|
213
|
+
/* Canonical editor button family. All product button paint and states live */
|
|
214
|
+
/* here. */
|
|
215
|
+
/* ---------------------------------------------------------------------- */
|
|
216
|
+
|
|
217
|
+
.vgai-btn {
|
|
218
|
+
display: inline-flex;
|
|
219
|
+
/* Inline controls should keep their intrinsic size even when authored as
|
|
220
|
+
* direct children of a CSS grid. Grid's default align-items: stretch
|
|
221
|
+
* otherwise turns a compact action into a full-width slab. A caller that
|
|
222
|
+
* deliberately wants a wide button can still set width: 100%. */
|
|
223
|
+
width: max-content;
|
|
224
|
+
max-width: 100%;
|
|
225
|
+
align-items: center;
|
|
226
|
+
justify-content: center;
|
|
227
|
+
gap: var(--vgai-space-2);
|
|
228
|
+
font-family: var(--vgai-font-sans);
|
|
229
|
+
font-size: var(--vgai-font-md);
|
|
230
|
+
line-height: var(--vgai-leading-tight);
|
|
231
|
+
border-radius: var(--vgai-radius-sm);
|
|
232
|
+
cursor: pointer;
|
|
233
|
+
border: 1px solid transparent;
|
|
234
|
+
box-sizing: border-box;
|
|
235
|
+
transition:
|
|
236
|
+
background-color 0.12s var(--vgai-ease-standard),
|
|
237
|
+
border-color 0.12s var(--vgai-ease-standard),
|
|
238
|
+
color 0.12s var(--vgai-ease-standard),
|
|
239
|
+
filter 0.12s var(--vgai-ease-standard);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.vgai-btn[data-size="compact"] {
|
|
243
|
+
height: var(--vgai-control-compact-height);
|
|
244
|
+
padding-top: 0;
|
|
245
|
+
padding-bottom: 0;
|
|
246
|
+
font-size: var(--vgai-font-base);
|
|
247
|
+
}
|
|
248
|
+
.vgai-btn:not([data-size]),
|
|
249
|
+
.vgai-btn[data-size="default"] {
|
|
250
|
+
height: var(--vgai-control-default-height);
|
|
251
|
+
padding-top: 0;
|
|
252
|
+
padding-bottom: 0;
|
|
253
|
+
font-size: var(--vgai-font-base);
|
|
254
|
+
}
|
|
255
|
+
.vgai-btn[data-size="comfortable"] {
|
|
256
|
+
height: var(--vgai-control-comfortable-height);
|
|
257
|
+
padding-top: 0;
|
|
258
|
+
padding-bottom: 0;
|
|
259
|
+
font-size: var(--vgai-font-md);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.vgai-btn[data-variant="primary"] {
|
|
263
|
+
background: var(--vgai-accent);
|
|
264
|
+
color: var(--vgai-content-on-accent);
|
|
265
|
+
border-color: var(--vgai-accent);
|
|
266
|
+
padding: var(--vgai-space-3) var(--vgai-space-6);
|
|
267
|
+
font-weight: 600;
|
|
268
|
+
}
|
|
269
|
+
.vgai-btn[data-variant="primary"]:hover:not(:disabled) {
|
|
270
|
+
filter: brightness(1.08);
|
|
271
|
+
}
|
|
272
|
+
.vgai-btn[data-variant="primary"]:active:not(:disabled) {
|
|
273
|
+
filter: brightness(0.92);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* A PUSHBUTTON — Blender's `wcol_regular` widget class. `--vgai-widget-regular`
|
|
277
|
+
resolves to `surface.raised` for any palette that does not name the class,
|
|
278
|
+
which is every palette but Blender's. */
|
|
279
|
+
.vgai-btn:not([data-variant]),
|
|
280
|
+
.vgai-btn[data-variant="secondary"] {
|
|
281
|
+
background: var(--vgai-widget-regular);
|
|
282
|
+
color: var(--vgai-content-primary);
|
|
283
|
+
border-color: var(--vgai-boundary-strong);
|
|
284
|
+
padding-inline: var(--vgai-space-4);
|
|
285
|
+
/* THE EMBOSS — Blender lays a 1 px translucent-black line under EVERY
|
|
286
|
+
widget, below its own outline. One rule, verified on five widget kinds
|
|
287
|
+
(pushbutton, text field, dropdown well, checkbox, list box) in
|
|
288
|
+
`properties-modifier.png` / `properties-object.png` /
|
|
289
|
+
`properties-data-edit.png`; the measurements and the alpha solve live on
|
|
290
|
+
`EditorTheme.color.widget.emboss`. It is a shadow, so it costs no layout
|
|
291
|
+
and a palette that names no emboss resolves the token to `none`. */
|
|
292
|
+
box-shadow: var(--vgai-widget-emboss-shadow);
|
|
293
|
+
}
|
|
294
|
+
.vgai-btn:not([data-variant]):hover:not(:disabled),
|
|
295
|
+
.vgai-btn[data-variant="secondary"]:hover:not(:disabled) {
|
|
296
|
+
/* Hover LIFTS the widget (Blender lifts a widget by a step); the bar colour it
|
|
297
|
+
used to take sank it below its own resting fill under an opaque skin. */
|
|
298
|
+
background: var(--vgai-widget-regular-hover);
|
|
299
|
+
border-color: var(--vgai-boundary-strong);
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* A MENU BUTTON — Blender's `wcol_menu`, a dark well, not a pushbutton: a
|
|
303
|
+
dropdown TRIGGER is a different widget class from a button that does a
|
|
304
|
+
thing, and painting both from one surface is what made `Object Mode v`
|
|
305
|
+
read pushbutton-grey under the Blender skin (measured #272727 against our
|
|
306
|
+
#545454). The discriminator is the trigger's own ARIA — a button that opens
|
|
307
|
+
a menu or a listbox IS a menu button — so no call site grows a marker
|
|
308
|
+
attribute. Scoped to the two button-shaped variants only: `ghost` menu
|
|
309
|
+
words (the viewport header's View/Select/Add, the app menus' own
|
|
310
|
+
`.vgai-menu-trigger`) carry no chrome in Blender either, and must not
|
|
311
|
+
acquire a well here.
|
|
312
|
+
|
|
313
|
+
`.vgai-field-trigger` is deliberately NOT in this list: it is a LAYOUT
|
|
314
|
+
class (full width, mono, left-aligned) and two of its three users are
|
|
315
|
+
genuine select-like triggers while the third
|
|
316
|
+
(`@vgai/dom/react-inspector-section.tsx`'s "No gradient — click to add")
|
|
317
|
+
is a plain action that opens nothing. Paint follows what the control DOES,
|
|
318
|
+
which the ARIA already states.
|
|
319
|
+
|
|
320
|
+
`dialog` is in the list because a value-labelled trigger that opens an
|
|
321
|
+
anchored SETTINGS popover (`Studio v`, the Asset Lab preview environment)
|
|
322
|
+
is the same widget as one that opens a menu — Blender draws both as one
|
|
323
|
+
well — and its popup is a form, so `aria-haspopup="dialog"` is the honest
|
|
324
|
+
ARIA and must not be bent to win paint. The one other `dialog` trigger in
|
|
325
|
+
the estate (the conversation tray) is `ghost`, which this rule does not
|
|
326
|
+
reach. */
|
|
327
|
+
.vgai-btn:is(:not([data-variant]), [data-variant="secondary"]):is(
|
|
328
|
+
[aria-haspopup="menu"],
|
|
329
|
+
[aria-haspopup="listbox"],
|
|
330
|
+
[aria-haspopup="dialog"]
|
|
331
|
+
) {
|
|
332
|
+
background: var(--vgai-widget-menu);
|
|
333
|
+
}
|
|
334
|
+
.vgai-btn:is(:not([data-variant]), [data-variant="secondary"]):is(
|
|
335
|
+
[aria-haspopup="menu"],
|
|
336
|
+
[aria-haspopup="listbox"],
|
|
337
|
+
[aria-haspopup="dialog"]
|
|
338
|
+
):hover:not(:disabled) {
|
|
339
|
+
background: var(--vgai-widget-menu-hover);
|
|
340
|
+
}
|
|
341
|
+
.vgai-btn:not([data-variant]):active:not(:disabled),
|
|
342
|
+
.vgai-btn[data-variant="secondary"]:active:not(:disabled) {
|
|
343
|
+
background: var(--vgai-surface-inset);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.vgai-btn[data-variant="outline"] {
|
|
347
|
+
background: transparent;
|
|
348
|
+
color: var(--vgai-content-primary);
|
|
349
|
+
border-color: var(--vgai-boundary-default);
|
|
350
|
+
padding-inline: var(--vgai-space-4);
|
|
351
|
+
}
|
|
352
|
+
.vgai-btn[data-variant="outline"]:hover:not(:disabled) {
|
|
353
|
+
background: var(--vgai-neutral-hover);
|
|
354
|
+
border-color: var(--vgai-boundary-strong);
|
|
355
|
+
}
|
|
356
|
+
.vgai-btn[data-variant="outline"]:active:not(:disabled) {
|
|
357
|
+
background: var(--vgai-neutral-active);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.vgai-btn[data-variant="ghost"] {
|
|
361
|
+
background: transparent;
|
|
362
|
+
color: var(--vgai-content-muted);
|
|
363
|
+
border-color: transparent;
|
|
364
|
+
padding-inline: var(--vgai-space-3);
|
|
365
|
+
}
|
|
366
|
+
.vgai-btn[data-variant="ghost"]:hover:not(:disabled) {
|
|
367
|
+
color: var(--vgai-content-primary);
|
|
368
|
+
background: var(--vgai-neutral-hover);
|
|
369
|
+
}
|
|
370
|
+
.vgai-btn[data-variant="ghost"]:active:not(:disabled) {
|
|
371
|
+
background: var(--vgai-neutral-active);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.vgai-btn[data-variant="danger"] {
|
|
375
|
+
color: var(--vgai-content-primary);
|
|
376
|
+
background: var(--vgai-danger-muted);
|
|
377
|
+
border-color: var(--vgai-danger);
|
|
378
|
+
padding-inline: var(--vgai-space-4);
|
|
379
|
+
font-weight: 600;
|
|
380
|
+
}
|
|
381
|
+
.vgai-btn[data-variant="danger"]:hover:not(:disabled) {
|
|
382
|
+
filter: brightness(1.12);
|
|
383
|
+
}
|
|
384
|
+
.vgai-btn[data-variant="danger"]:active:not(:disabled) {
|
|
385
|
+
filter: brightness(0.9);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
.vgai-btn[data-variant="success"] {
|
|
389
|
+
color: var(--vgai-content-on-accent);
|
|
390
|
+
background: var(--vgai-success);
|
|
391
|
+
border-color: var(--vgai-success);
|
|
392
|
+
padding-inline: var(--vgai-space-4);
|
|
393
|
+
font-weight: 600;
|
|
394
|
+
}
|
|
395
|
+
.vgai-btn[data-variant="success"]:hover:not(:disabled) {
|
|
396
|
+
filter: brightness(1.1);
|
|
397
|
+
}
|
|
398
|
+
.vgai-btn[data-variant="success"]:active:not(:disabled) {
|
|
399
|
+
filter: brightness(0.92);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.vgai-btn[aria-pressed="true"] {
|
|
403
|
+
/* The ink PAIRS WITH THE FILL, and the fill differs per skin: white on
|
|
404
|
+
Blender's solid widget blue, the ordinary ink on the translucent accent
|
|
405
|
+
wash every other skin uses. `theme.ts`'s `selectionInkValue` derives it —
|
|
406
|
+
hardcoding on-accent here painted near-black on a dark wash and made a
|
|
407
|
+
pressed toggle unreadable in every skin but Blender. */
|
|
408
|
+
color: var(--vgai-content-on-selection, var(--vgai-content-primary));
|
|
409
|
+
background: var(--vgai-selection-bg);
|
|
410
|
+
border-color: var(--vgai-selection-border);
|
|
411
|
+
}
|
|
412
|
+
.vgai-btn[aria-busy="true"] {
|
|
413
|
+
cursor: progress;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
.vgai-btn.vgai-sprite-frame-option {
|
|
417
|
+
width: 100%;
|
|
418
|
+
min-width: 0;
|
|
419
|
+
height: 72px;
|
|
420
|
+
flex-direction: column;
|
|
421
|
+
gap: var(--vgai-space-1);
|
|
422
|
+
padding: var(--vgai-space-1);
|
|
423
|
+
background: var(--vgai-surface-inset);
|
|
424
|
+
border-color: var(--vgai-boundary-default);
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
.vgai-btn.vgai-sprite-frame-option[aria-pressed="true"] {
|
|
428
|
+
background: var(--vgai-selection-bg);
|
|
429
|
+
border-color: var(--vgai-selection-border);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
.vgai-btn[data-icon="true"] {
|
|
433
|
+
width: var(--vgai-control-default-height);
|
|
434
|
+
padding: 0;
|
|
435
|
+
}
|
|
436
|
+
.vgai-btn[data-icon="true"][data-size="compact"] {
|
|
437
|
+
width: var(--vgai-control-compact-height);
|
|
438
|
+
}
|
|
439
|
+
.vgai-btn[data-icon="true"][data-size="comfortable"] {
|
|
440
|
+
width: var(--vgai-control-comfortable-height);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/* A labelled icon button is the same canonical toolbar control with a
|
|
444
|
+
vertical content arrangement. Toolbars choose whether its pressed state is
|
|
445
|
+
independent or part of one exclusive selection; product surfaces don't
|
|
446
|
+
author their own icon/label metrics. */
|
|
447
|
+
.vgai-btn[data-icon="true"][data-label-placement="below"] {
|
|
448
|
+
width: 68px;
|
|
449
|
+
min-width: 68px;
|
|
450
|
+
height: 42px;
|
|
451
|
+
flex-direction: column;
|
|
452
|
+
gap: 3px;
|
|
453
|
+
padding: 4px 8px 3px;
|
|
454
|
+
}
|
|
455
|
+
.vgai-icon-button-label {
|
|
456
|
+
max-width: 100%;
|
|
457
|
+
min-width: 0;
|
|
458
|
+
overflow: hidden;
|
|
459
|
+
font-size: var(--vgai-font-xs);
|
|
460
|
+
line-height: var(--vgai-leading-tight);
|
|
461
|
+
text-overflow: ellipsis;
|
|
462
|
+
white-space: nowrap;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
.vgai-btn:disabled,
|
|
466
|
+
.vgai-btn[aria-disabled="true"] {
|
|
467
|
+
opacity: 0.4;
|
|
468
|
+
cursor: not-allowed;
|
|
469
|
+
filter: none;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.vgai-btn:focus-visible {
|
|
473
|
+
outline: var(--vgai-focus-ring);
|
|
474
|
+
outline-offset: 1px;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.vgai-machine-list-entry {
|
|
478
|
+
display: block;
|
|
479
|
+
width: 100%;
|
|
480
|
+
height: auto;
|
|
481
|
+
justify-content: flex-start;
|
|
482
|
+
border-left: var(--vgai-stroke-active) solid transparent;
|
|
483
|
+
padding: var(--vgai-space-3) var(--vgai-space-4);
|
|
484
|
+
text-align: left;
|
|
485
|
+
}
|
|
486
|
+
/* Selected rows are a thin state overlay on the panel's one content floor,
|
|
487
|
+
never another blur-bearing layer. */
|
|
488
|
+
.vgai-machine-list-entry[data-selected="true"] {
|
|
489
|
+
border-left-color: var(--vgai-selection-indicator);
|
|
490
|
+
background: var(--vgai-selection-bg);
|
|
491
|
+
}
|
|
492
|
+
.vgai-performance-overlay {
|
|
493
|
+
pointer-events: auto;
|
|
494
|
+
display: grid;
|
|
495
|
+
grid-template-columns: repeat(5, auto);
|
|
496
|
+
width: auto;
|
|
497
|
+
height: auto;
|
|
498
|
+
gap: var(--vgai-space-5);
|
|
499
|
+
border-color: var(--vgai-boundary-strong);
|
|
500
|
+
background: var(--vgai-surface-overlay);
|
|
501
|
+
color: var(--vgai-content-primary);
|
|
502
|
+
padding: var(--vgai-space-3) var(--vgai-space-4);
|
|
503
|
+
font-family: var(--vgai-font-mono);
|
|
504
|
+
font-size: var(--vgai-font-sm);
|
|
505
|
+
}
|
|
506
|
+
.vgai-performance-overlay[data-enabled="true"] {
|
|
507
|
+
border-color: var(--vgai-accent);
|
|
508
|
+
}
|
|
509
|
+
/* Viewport HUD overlays (P6-U6, owner taste decision 3 — "HUD overlays →
|
|
510
|
+
real islands"): the shared base paint for the stats / network /
|
|
511
|
+
tile-palette HUD whispers, byte-identical to their former inline recipes
|
|
512
|
+
(overlay surface, radius-md, per-site border/shadow variants). Under
|
|
513
|
+
islands chrome each of these elements also carries `vgai-chrome-island`
|
|
514
|
+
(+ `vgai-glass-island` for the refraction upgrade), whose higher-
|
|
515
|
+
specificity material rules override this base — that is the promotion. */
|
|
516
|
+
.vgai-hud-overlay {
|
|
517
|
+
background: var(--vgai-surface-overlay);
|
|
518
|
+
border-radius: var(--vgai-radius-md);
|
|
519
|
+
}
|
|
520
|
+
.vgai-hud-overlay[data-hud-border="strong"] {
|
|
521
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-strong);
|
|
522
|
+
}
|
|
523
|
+
.vgai-hud-overlay[data-hud-border="default"] {
|
|
524
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
525
|
+
}
|
|
526
|
+
.vgai-hud-overlay[data-hud-shadow="true"] {
|
|
527
|
+
box-shadow: var(--vgai-shadow-sm);
|
|
528
|
+
}
|
|
529
|
+
.vgai-field-trigger {
|
|
530
|
+
width: 100%;
|
|
531
|
+
justify-content: space-between;
|
|
532
|
+
overflow: hidden;
|
|
533
|
+
font-family: var(--vgai-font-mono);
|
|
534
|
+
text-align: left;
|
|
535
|
+
}
|
|
536
|
+
.vgai-inspector-group-trigger {
|
|
537
|
+
width: 100%;
|
|
538
|
+
height: auto;
|
|
539
|
+
justify-content: flex-start;
|
|
540
|
+
padding: var(--vgai-space-4);
|
|
541
|
+
font-weight: 600;
|
|
542
|
+
text-align: left;
|
|
543
|
+
text-transform: uppercase;
|
|
544
|
+
letter-spacing: 0.4px;
|
|
545
|
+
}
|
|
546
|
+
.vgai-hierarchy-more {
|
|
547
|
+
width: 100%;
|
|
548
|
+
height: var(--vgai-tree-row-height);
|
|
549
|
+
justify-content: flex-start;
|
|
550
|
+
font-style: italic;
|
|
551
|
+
text-align: left;
|
|
552
|
+
}
|
|
553
|
+
/* The tree's disclosure cell. Sized on the ICON axis, not the type axis: the
|
|
554
|
+
caret is a pictogram, and the icon rungs default to the type scale's values
|
|
555
|
+
so no skin that declares none moves. Blender's chevron measures 4.5x9 CSS
|
|
556
|
+
collapsed and 8.5x5 expanded on the native 2x `outliner.png`. */
|
|
557
|
+
.vgai-btn.vgai-tree-caret {
|
|
558
|
+
/* ONE INDENT CELL, and no inline padding — a button's `padding-inline` is
|
|
559
|
+
what made the expander's cell 19 px against the leaf spacer's 14, so a
|
|
560
|
+
child row's type glyph sat 15 px right of its parent's where the tree's
|
|
561
|
+
own step is 20. Blender's chevron and type glyph each own exactly one
|
|
562
|
+
indent cell (`outliner.png`: chevron centres 30.25/50.25, glyph centres
|
|
563
|
+
one cell right of each), which is what this width says. */
|
|
564
|
+
width: var(--vgai-tree-indent);
|
|
565
|
+
height: 18px;
|
|
566
|
+
flex: 0 0 var(--vgai-tree-indent);
|
|
567
|
+
padding-inline: 0;
|
|
568
|
+
font-size: var(--vgai-icon-xs);
|
|
569
|
+
}
|
|
570
|
+
.vgai-chat-icon {
|
|
571
|
+
width: var(--vgai-control-default-height);
|
|
572
|
+
padding-inline: 0;
|
|
573
|
+
}
|
|
574
|
+
.vgai-chat-session-row {
|
|
575
|
+
width: 100%;
|
|
576
|
+
height: auto;
|
|
577
|
+
justify-content: flex-start;
|
|
578
|
+
padding: var(--vgai-space-4);
|
|
579
|
+
text-align: left;
|
|
580
|
+
}
|
|
581
|
+
.vgai-chat-session-row[data-selected="true"] {
|
|
582
|
+
background: var(--vgai-surface-raised);
|
|
583
|
+
}
|
|
584
|
+
.vgai-chat-harness-trigger {
|
|
585
|
+
max-width: 190px;
|
|
586
|
+
overflow: hidden;
|
|
587
|
+
white-space: nowrap;
|
|
588
|
+
}
|
|
589
|
+
.vgai-chat-header-trigger {
|
|
590
|
+
min-width: 0;
|
|
591
|
+
flex: 1;
|
|
592
|
+
justify-content: flex-start;
|
|
593
|
+
overflow: hidden;
|
|
594
|
+
text-align: left;
|
|
595
|
+
}
|
|
596
|
+
/* ---------------------------------------------------------------------- */
|
|
597
|
+
/* .vgai-input / .vgai-select / .vgai-checkbox — shared form-control */
|
|
598
|
+
/* classes. */
|
|
599
|
+
/* ---------------------------------------------------------------------- */
|
|
600
|
+
|
|
601
|
+
.vgai-input {
|
|
602
|
+
background: var(--vgai-input-surface, var(--vgai-bg-inset));
|
|
603
|
+
color: var(--vgai-text-1);
|
|
604
|
+
border: 1px solid var(--vgai-input-border, var(--vgai-border-1));
|
|
605
|
+
border-radius: var(--vgai-radius-sm);
|
|
606
|
+
box-shadow: var(--vgai-input-shadow, none);
|
|
607
|
+
padding: var(--vgai-space-1) var(--vgai-space-3);
|
|
608
|
+
font-size: var(--vgai-font-base);
|
|
609
|
+
font-family: var(--vgai-font-sans);
|
|
610
|
+
outline: none;
|
|
611
|
+
min-width: 0;
|
|
612
|
+
min-height: var(--vgai-control-default-height);
|
|
613
|
+
box-sizing: border-box;
|
|
614
|
+
}
|
|
615
|
+
/* A PLACEHOLDER IS A PALETTE INK, and until this rule existed it was a
|
|
616
|
+
BROWSER's. No `::placeholder` declaration existed anywhere in the editor's
|
|
617
|
+
CSS, so Chrome's UA default decided one of our inks — measured live at a
|
|
618
|
+
fixed rgb(117,117,117), identical for fields inked 229, 100, red and black,
|
|
619
|
+
which is what says it is a constant of the browser's and not a composite of
|
|
620
|
+
ours. Blender's own is #5e5e5e (94), measured on the Outliner's `Search` in
|
|
621
|
+
`modeling-object-none.png` (x 3100..3260, y 60..96, ceiling 94) — below its
|
|
622
|
+
dim, which is where a placeholder belongs. `content.placeholder` falls back
|
|
623
|
+
to `content.dim` in the emitter; see theme.ts for why the fallback is the
|
|
624
|
+
palette's ink rather than a transcription of the browser's. */
|
|
625
|
+
.vgai-input::placeholder {
|
|
626
|
+
color: var(--vgai-content-placeholder);
|
|
627
|
+
/* Chrome's UA rule carries no opacity, but Firefox's does (0.54) and would
|
|
628
|
+
halve the declared ink. Stated so the token means the same on both. */
|
|
629
|
+
opacity: 1;
|
|
630
|
+
}
|
|
631
|
+
/* A single-line field is exactly control height, like `.vgai-btn`; padding
|
|
632
|
+
used to add to it, so a 20 px density still drew a 22 px field. */
|
|
633
|
+
input.vgai-input,
|
|
634
|
+
select.vgai-input {
|
|
635
|
+
height: var(--vgai-control-default-height);
|
|
636
|
+
padding-block: 0;
|
|
637
|
+
}
|
|
638
|
+
.vgai-input:hover:not(:disabled) {
|
|
639
|
+
border-color: var(--vgai-border-2);
|
|
640
|
+
}
|
|
641
|
+
.vgai-input:focus-visible {
|
|
642
|
+
border-color: var(--vgai-accent);
|
|
643
|
+
outline: var(--vgai-focus-ring);
|
|
644
|
+
outline-offset: -1px;
|
|
645
|
+
}
|
|
646
|
+
.vgai-input[aria-invalid="true"] {
|
|
647
|
+
border-color: var(--vgai-danger);
|
|
648
|
+
}
|
|
649
|
+
.vgai-input[data-tone="danger"] {
|
|
650
|
+
color: var(--vgai-danger);
|
|
651
|
+
}
|
|
652
|
+
.vgai-input[data-state="editing"] {
|
|
653
|
+
border-color: var(--vgai-accent);
|
|
654
|
+
}
|
|
655
|
+
.vgai-input[data-emphasis="strong"] {
|
|
656
|
+
font-size: var(--vgai-font-md);
|
|
657
|
+
font-weight: 600;
|
|
658
|
+
}
|
|
659
|
+
.vgai-input[data-emphasis="semibold"] {
|
|
660
|
+
font-weight: 600;
|
|
661
|
+
}
|
|
662
|
+
.vgai-input[data-monospace="true"] {
|
|
663
|
+
font-family: var(--vgai-font-mono);
|
|
664
|
+
}
|
|
665
|
+
.vgai-input[data-density="compact"],
|
|
666
|
+
.vgai-select[data-density="compact"] {
|
|
667
|
+
min-height: var(--vgai-control-compact-height);
|
|
668
|
+
font-size: var(--vgai-font-sm);
|
|
669
|
+
}
|
|
670
|
+
.vgai-input[data-density="comfortable"],
|
|
671
|
+
.vgai-select[data-density="comfortable"] {
|
|
672
|
+
min-height: var(--vgai-control-comfortable-height);
|
|
673
|
+
font-size: var(--vgai-font-md);
|
|
674
|
+
}
|
|
675
|
+
.vgai-input[data-density="compact-tall"],
|
|
676
|
+
.vgai-select[data-density="compact-tall"] {
|
|
677
|
+
min-height: var(--vgai-control-comfortable-height);
|
|
678
|
+
font-size: var(--vgai-font-sm);
|
|
679
|
+
}
|
|
680
|
+
.vgai-input[data-leading-icon="true"] {
|
|
681
|
+
padding-left: calc(var(--vgai-space-12) + 1px);
|
|
682
|
+
}
|
|
683
|
+
.vgai-input[data-variant="entity-name"] {
|
|
684
|
+
min-height: var(--vgai-control-comfortable-height);
|
|
685
|
+
padding: var(--vgai-space-2) var(--vgai-space-3);
|
|
686
|
+
font-size: var(--vgai-font-lg);
|
|
687
|
+
font-weight: 600;
|
|
688
|
+
}
|
|
689
|
+
.vgai-input[data-variant="tree-edit"] {
|
|
690
|
+
min-height: var(--vgai-control-compact-height);
|
|
691
|
+
padding: 0 var(--vgai-space-2);
|
|
692
|
+
border-color: var(--vgai-accent);
|
|
693
|
+
font-size: var(--vgai-font-lg);
|
|
694
|
+
outline: none;
|
|
695
|
+
}
|
|
696
|
+
.vgai-input[data-variant="prominent"] {
|
|
697
|
+
min-height: var(--vgai-command-bar-height);
|
|
698
|
+
padding: var(--vgai-space-5) calc(var(--vgai-space-6) + var(--vgai-space-1));
|
|
699
|
+
border: 0;
|
|
700
|
+
border-bottom: var(--vgai-stroke-resting) solid var(--vgai-boundary-strong);
|
|
701
|
+
border-radius: 0;
|
|
702
|
+
font-size: var(--vgai-font-xl);
|
|
703
|
+
}
|
|
704
|
+
.vgai-input[data-variant="prominent"]:focus-visible {
|
|
705
|
+
outline-offset: -2px;
|
|
706
|
+
}
|
|
707
|
+
.vgai-input[data-variant="seamless"] {
|
|
708
|
+
padding: var(--vgai-space-4);
|
|
709
|
+
color: var(--vgai-content-primary);
|
|
710
|
+
background: transparent;
|
|
711
|
+
border: 0;
|
|
712
|
+
border-radius: 0;
|
|
713
|
+
}
|
|
714
|
+
.vgai-input[data-dynamic="true"],
|
|
715
|
+
.vgai-select[data-dynamic="true"] {
|
|
716
|
+
color: var(--vgai-dynamic);
|
|
717
|
+
background-color: var(--vgai-dynamic-muted);
|
|
718
|
+
border-color: var(--vgai-dynamic);
|
|
719
|
+
}
|
|
720
|
+
.vgai-input[data-mixed="true"],
|
|
721
|
+
.vgai-select[data-mixed="true"] {
|
|
722
|
+
color: var(--vgai-content-dim);
|
|
723
|
+
font-style: italic;
|
|
724
|
+
}
|
|
725
|
+
.vgai-input:disabled {
|
|
726
|
+
opacity: 0.5;
|
|
727
|
+
cursor: not-allowed;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.vgai-select {
|
|
731
|
+
appearance: none;
|
|
732
|
+
-webkit-appearance: none;
|
|
733
|
+
background-color: var(--vgai-input-surface, var(--vgai-bg-inset));
|
|
734
|
+
background-image: var(--vgai-select-chevron);
|
|
735
|
+
background-repeat: no-repeat;
|
|
736
|
+
background-position: right 6px center;
|
|
737
|
+
background-size: 8px 5px;
|
|
738
|
+
color: var(--vgai-text-1);
|
|
739
|
+
border: 1px solid var(--vgai-input-border, var(--vgai-border-1));
|
|
740
|
+
border-radius: var(--vgai-radius-sm);
|
|
741
|
+
box-shadow: var(--vgai-input-shadow, none);
|
|
742
|
+
padding: var(--vgai-space-1) var(--vgai-space-6) var(--vgai-space-1) var(--vgai-space-3);
|
|
743
|
+
font-size: var(--vgai-font-base);
|
|
744
|
+
font-family: var(--vgai-font-sans);
|
|
745
|
+
outline: none;
|
|
746
|
+
min-height: var(--vgai-control-default-height);
|
|
747
|
+
box-sizing: border-box;
|
|
748
|
+
cursor: pointer;
|
|
749
|
+
}
|
|
750
|
+
.vgai-select:hover:not(:disabled) {
|
|
751
|
+
border-color: var(--vgai-border-2);
|
|
752
|
+
}
|
|
753
|
+
.vgai-select:focus-visible {
|
|
754
|
+
border-color: var(--vgai-accent);
|
|
755
|
+
outline: var(--vgai-focus-ring);
|
|
756
|
+
outline-offset: -1px;
|
|
757
|
+
}
|
|
758
|
+
.vgai-select:disabled {
|
|
759
|
+
opacity: 0.5;
|
|
760
|
+
cursor: not-allowed;
|
|
761
|
+
}
|
|
762
|
+
.vgai-select option {
|
|
763
|
+
background: var(--vgai-bg-2);
|
|
764
|
+
color: var(--vgai-text-1);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.vgai-textarea {
|
|
768
|
+
display: block;
|
|
769
|
+
width: 100%;
|
|
770
|
+
min-height: calc(var(--vgai-control-default-height) * 2);
|
|
771
|
+
resize: vertical;
|
|
772
|
+
line-height: var(--vgai-leading-normal);
|
|
773
|
+
}
|
|
774
|
+
.vgai-textarea[data-variant="code"] {
|
|
775
|
+
padding: var(--vgai-space-5);
|
|
776
|
+
font-family: var(--vgai-font-mono);
|
|
777
|
+
font-size: var(--vgai-font-base);
|
|
778
|
+
line-height: var(--vgai-leading-relaxed);
|
|
779
|
+
}
|
|
780
|
+
.vgai-textarea[data-variant="inline-editor"] {
|
|
781
|
+
padding: var(--vgai-space-1);
|
|
782
|
+
color: var(--vgai-content-primary);
|
|
783
|
+
background: var(--vgai-input-surface, var(--vgai-surface-inset));
|
|
784
|
+
border: var(--vgai-stroke-active) solid var(--vgai-accent);
|
|
785
|
+
font: inherit;
|
|
786
|
+
font-size: var(--vgai-font-lg);
|
|
787
|
+
line-height: 1.3;
|
|
788
|
+
outline: none;
|
|
789
|
+
}
|
|
790
|
+
/* ---------------------------------------------------------------------- */
|
|
791
|
+
/* Public contribution recipes. These are deliberately ordinary semantic */
|
|
792
|
+
/* HTML classes, not an extension UI framework: package contributions keep */
|
|
793
|
+
/* familiar React/HTML while the host owns spacing, paint, and responsive */
|
|
794
|
+
/* behavior. */
|
|
795
|
+
/* ---------------------------------------------------------------------- */
|
|
796
|
+
|
|
797
|
+
.vgai-tool-page {
|
|
798
|
+
width: 100%;
|
|
799
|
+
max-width: 960px;
|
|
800
|
+
min-height: 100%;
|
|
801
|
+
margin: 0 auto;
|
|
802
|
+
padding: var(--vgai-space-6);
|
|
803
|
+
color: var(--vgai-content-primary);
|
|
804
|
+
box-sizing: border-box;
|
|
805
|
+
}
|
|
806
|
+
.vgai-tool-header {
|
|
807
|
+
max-width: 720px;
|
|
808
|
+
margin-bottom: var(--vgai-space-5);
|
|
809
|
+
}
|
|
810
|
+
.vgai-tool-eyebrow {
|
|
811
|
+
margin-bottom: var(--vgai-space-2);
|
|
812
|
+
color: var(--vgai-content-dim);
|
|
813
|
+
font-size: var(--vgai-font-sm);
|
|
814
|
+
font-weight: 600;
|
|
815
|
+
letter-spacing: 0.06em;
|
|
816
|
+
text-transform: uppercase;
|
|
817
|
+
}
|
|
818
|
+
.vgai-tool-title {
|
|
819
|
+
margin: 0 0 var(--vgai-space-2);
|
|
820
|
+
font-size: var(--vgai-font-xl);
|
|
821
|
+
}
|
|
822
|
+
.vgai-tool-description {
|
|
823
|
+
margin: 0;
|
|
824
|
+
color: var(--vgai-content-muted);
|
|
825
|
+
line-height: var(--vgai-leading-relaxed);
|
|
826
|
+
}
|
|
827
|
+
.vgai-tool-card {
|
|
828
|
+
padding: var(--vgai-space-5);
|
|
829
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
830
|
+
border-radius: var(--vgai-radius-md);
|
|
831
|
+
background: var(--vgai-surface-panel);
|
|
832
|
+
}
|
|
833
|
+
.vgai-tool-form {
|
|
834
|
+
display: grid;
|
|
835
|
+
max-width: 720px;
|
|
836
|
+
gap: var(--vgai-space-4);
|
|
837
|
+
}
|
|
838
|
+
.vgai-tool-field {
|
|
839
|
+
display: grid;
|
|
840
|
+
min-width: 0;
|
|
841
|
+
gap: var(--vgai-space-2);
|
|
842
|
+
}
|
|
843
|
+
.vgai-tool-field > .vgai-input,
|
|
844
|
+
.vgai-tool-field > .vgai-select {
|
|
845
|
+
width: 100%;
|
|
846
|
+
}
|
|
847
|
+
.vgai-tool-field-label {
|
|
848
|
+
color: var(--vgai-content-primary);
|
|
849
|
+
font-weight: 500;
|
|
850
|
+
}
|
|
851
|
+
.vgai-tool-help {
|
|
852
|
+
color: var(--vgai-content-dim);
|
|
853
|
+
font-size: var(--vgai-font-sm);
|
|
854
|
+
line-height: var(--vgai-leading-normal);
|
|
855
|
+
}
|
|
856
|
+
.vgai-tool-advanced {
|
|
857
|
+
padding: var(--vgai-space-3);
|
|
858
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
859
|
+
border-radius: var(--vgai-radius-sm);
|
|
860
|
+
background: var(--vgai-surface-inset);
|
|
861
|
+
}
|
|
862
|
+
.vgai-tool-advanced > summary {
|
|
863
|
+
color: var(--vgai-content-muted);
|
|
864
|
+
cursor: pointer;
|
|
865
|
+
font-weight: 500;
|
|
866
|
+
}
|
|
867
|
+
.vgai-tool-advanced[open] > summary {
|
|
868
|
+
margin-bottom: var(--vgai-space-3);
|
|
869
|
+
color: var(--vgai-content-primary);
|
|
870
|
+
}
|
|
871
|
+
.vgai-tool-actions {
|
|
872
|
+
display: flex;
|
|
873
|
+
flex-wrap: wrap;
|
|
874
|
+
align-items: center;
|
|
875
|
+
gap: var(--vgai-space-3);
|
|
876
|
+
padding-top: var(--vgai-space-1);
|
|
877
|
+
}
|
|
878
|
+
.vgai-cost-disclosure {
|
|
879
|
+
display: grid;
|
|
880
|
+
gap: var(--vgai-space-1);
|
|
881
|
+
padding: var(--vgai-space-3) var(--vgai-space-4);
|
|
882
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
883
|
+
border-left: var(--vgai-stroke-active) solid var(--vgai-accent);
|
|
884
|
+
border-radius: var(--vgai-radius-sm);
|
|
885
|
+
background: var(--vgai-surface-inset);
|
|
886
|
+
}
|
|
887
|
+
.vgai-cost-disclosure[data-route="mock"] {
|
|
888
|
+
border-left-color: var(--vgai-success);
|
|
889
|
+
}
|
|
890
|
+
.vgai-cost-disclosure[data-route="managed"] {
|
|
891
|
+
border-left-color: var(--vgai-accent);
|
|
892
|
+
}
|
|
893
|
+
.vgai-cost-disclosure[data-route="direct"] {
|
|
894
|
+
border-left-color: var(--vgai-warn);
|
|
895
|
+
}
|
|
896
|
+
.vgai-cost-disclosure-title {
|
|
897
|
+
font-weight: 600;
|
|
898
|
+
}
|
|
899
|
+
.vgai-cost-disclosure-detail {
|
|
900
|
+
color: var(--vgai-content-muted);
|
|
901
|
+
font-size: var(--vgai-font-sm);
|
|
902
|
+
}
|
|
903
|
+
.vgai-tool-confirmation {
|
|
904
|
+
display: grid;
|
|
905
|
+
gap: var(--vgai-space-3);
|
|
906
|
+
padding: var(--vgai-space-4);
|
|
907
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-warn);
|
|
908
|
+
border-radius: var(--vgai-radius-sm);
|
|
909
|
+
background: var(--vgai-warn-muted);
|
|
910
|
+
}
|
|
911
|
+
.vgai-tool-status {
|
|
912
|
+
max-width: 720px;
|
|
913
|
+
margin-top: var(--vgai-space-4);
|
|
914
|
+
padding: var(--vgai-space-3) var(--vgai-space-4);
|
|
915
|
+
border-radius: var(--vgai-radius-sm);
|
|
916
|
+
color: var(--vgai-content-primary);
|
|
917
|
+
background: var(--vgai-surface-raised);
|
|
918
|
+
}
|
|
919
|
+
.vgai-tool-status[data-tone="error"] {
|
|
920
|
+
color: var(--vgai-danger);
|
|
921
|
+
background: var(--vgai-danger-faint);
|
|
922
|
+
}
|
|
923
|
+
.vgai-tool-status[data-tone="success"] {
|
|
924
|
+
color: var(--vgai-success);
|
|
925
|
+
background: var(--vgai-success-muted);
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
.vgai-generation-job-meta {
|
|
929
|
+
color: var(--vgai-content-muted);
|
|
930
|
+
font-size: var(--vgai-font-sm);
|
|
931
|
+
}
|
|
932
|
+
.vgai-generation-document {
|
|
933
|
+
display: grid;
|
|
934
|
+
width: 100%;
|
|
935
|
+
max-width: 1120px;
|
|
936
|
+
min-height: 100%;
|
|
937
|
+
margin: 0 auto;
|
|
938
|
+
padding: var(--vgai-space-6);
|
|
939
|
+
gap: var(--vgai-space-4);
|
|
940
|
+
color: var(--vgai-content-primary);
|
|
941
|
+
box-sizing: border-box;
|
|
942
|
+
}
|
|
943
|
+
.vgai-generation-document-header {
|
|
944
|
+
display: flex;
|
|
945
|
+
align-items: flex-start;
|
|
946
|
+
justify-content: space-between;
|
|
947
|
+
gap: var(--vgai-space-4);
|
|
948
|
+
}
|
|
949
|
+
.vgai-generation-result {
|
|
950
|
+
min-height: 280px;
|
|
951
|
+
padding: var(--vgai-space-4);
|
|
952
|
+
overflow: auto;
|
|
953
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
954
|
+
border-radius: var(--vgai-radius-md);
|
|
955
|
+
background: var(--vgai-surface-inset);
|
|
956
|
+
}
|
|
957
|
+
.vgai-generation-document-empty,
|
|
958
|
+
.vgai-generation-result-empty {
|
|
959
|
+
padding: var(--vgai-space-5);
|
|
960
|
+
color: var(--vgai-content-muted);
|
|
961
|
+
}
|
|
962
|
+
.vgai-generation-native-result {
|
|
963
|
+
margin: 0;
|
|
964
|
+
overflow: auto;
|
|
965
|
+
color: var(--vgai-content-muted);
|
|
966
|
+
font-size: var(--vgai-font-sm);
|
|
967
|
+
white-space: pre-wrap;
|
|
968
|
+
overflow-wrap: anywhere;
|
|
969
|
+
}
|
|
970
|
+
.vgai-generation-image-grid {
|
|
971
|
+
display: grid;
|
|
972
|
+
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
973
|
+
gap: var(--vgai-space-3);
|
|
974
|
+
}
|
|
975
|
+
.vgai-generation-image-grid img,
|
|
976
|
+
.vgai-generation-panorama,
|
|
977
|
+
.vgai-generation-world-result img {
|
|
978
|
+
display: block;
|
|
979
|
+
width: 100%;
|
|
980
|
+
max-height: 620px;
|
|
981
|
+
border-radius: var(--vgai-radius-sm);
|
|
982
|
+
object-fit: contain;
|
|
983
|
+
}
|
|
984
|
+
.vgai-generation-media {
|
|
985
|
+
display: block;
|
|
986
|
+
width: min(100%, 860px);
|
|
987
|
+
margin: auto;
|
|
988
|
+
}
|
|
989
|
+
.vgai-generation-result-links,
|
|
990
|
+
.vgai-generation-world-result,
|
|
991
|
+
.vgai-generation-output-paths {
|
|
992
|
+
display: grid;
|
|
993
|
+
align-content: start;
|
|
994
|
+
justify-items: start;
|
|
995
|
+
gap: var(--vgai-space-3);
|
|
996
|
+
}
|
|
997
|
+
.vgai-generation-output-paths code {
|
|
998
|
+
color: var(--vgai-content-muted);
|
|
999
|
+
overflow-wrap: anywhere;
|
|
1000
|
+
}
|
|
1001
|
+
.vgai-generation-document-footer {
|
|
1002
|
+
display: flex;
|
|
1003
|
+
justify-content: flex-end;
|
|
1004
|
+
}
|
|
1005
|
+
.vgai-generation-create-grid {
|
|
1006
|
+
display: grid;
|
|
1007
|
+
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
|
1008
|
+
gap: var(--vgai-space-2);
|
|
1009
|
+
}
|
|
1010
|
+
.vgai-generation-create-card {
|
|
1011
|
+
display: grid;
|
|
1012
|
+
gap: var(--vgai-space-1);
|
|
1013
|
+
padding: var(--vgai-space-3);
|
|
1014
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
1015
|
+
border-radius: var(--vgai-radius-sm);
|
|
1016
|
+
color: var(--vgai-content-primary);
|
|
1017
|
+
text-align: left;
|
|
1018
|
+
background: var(--vgai-surface-raised);
|
|
1019
|
+
cursor: pointer;
|
|
1020
|
+
}
|
|
1021
|
+
.vgai-generation-create-card:hover {
|
|
1022
|
+
border-color: var(--vgai-boundary-strong);
|
|
1023
|
+
background: var(--vgai-neutral-hover);
|
|
1024
|
+
}
|
|
1025
|
+
.vgai-generation-create-card:focus-visible {
|
|
1026
|
+
outline: var(--vgai-focus-ring);
|
|
1027
|
+
outline-offset: 1px;
|
|
1028
|
+
}
|
|
1029
|
+
.vgai-generation-create-card span {
|
|
1030
|
+
color: var(--vgai-content-muted);
|
|
1031
|
+
font-size: var(--vgai-font-sm);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
/* Live account markup class (account-documents.tsx); its visual treatment
|
|
1035
|
+
* lives in product-shell.css — this only provides the card's internal flow.
|
|
1036
|
+
* The rest of the legacy account vocabulary (.vgai-account-summary-grid,
|
|
1037
|
+
* .vgai-provider-connection singular, …) was dead and has been pruned. */
|
|
1038
|
+
.vgai-provider-connections {
|
|
1039
|
+
display: grid;
|
|
1040
|
+
gap: var(--vgai-space-4);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
@media (max-width: 720px) {
|
|
1044
|
+
.vgai-tool-page {
|
|
1045
|
+
padding: var(--vgai-space-4);
|
|
1046
|
+
}
|
|
1047
|
+
.vgai-generation-document {
|
|
1048
|
+
padding: var(--vgai-space-4);
|
|
1049
|
+
}
|
|
1050
|
+
.vgai-generation-document-header {
|
|
1051
|
+
display: grid;
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
.vgai-checkbox {
|
|
1056
|
+
accent-color: var(--vgai-accent);
|
|
1057
|
+
width: 13px;
|
|
1058
|
+
height: 13px;
|
|
1059
|
+
cursor: pointer;
|
|
1060
|
+
margin: 0;
|
|
1061
|
+
}
|
|
1062
|
+
.vgai-checkbox:focus-visible {
|
|
1063
|
+
outline: var(--vgai-focus-ring);
|
|
1064
|
+
outline-offset: 2px;
|
|
1065
|
+
}
|
|
1066
|
+
.vgai-checkbox:indeterminate {
|
|
1067
|
+
accent-color: var(--vgai-warn);
|
|
1068
|
+
}
|
|
1069
|
+
.vgai-checkbox:disabled {
|
|
1070
|
+
opacity: 0.5;
|
|
1071
|
+
cursor: not-allowed;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
.vgai-color-swatch {
|
|
1075
|
+
width: var(--vgai-control-compact-height);
|
|
1076
|
+
height: var(--vgai-control-compact-height);
|
|
1077
|
+
flex: 0 0 auto;
|
|
1078
|
+
padding: 0;
|
|
1079
|
+
overflow: hidden;
|
|
1080
|
+
background: transparent;
|
|
1081
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
1082
|
+
border-radius: var(--vgai-radius-sm);
|
|
1083
|
+
cursor: pointer;
|
|
1084
|
+
}
|
|
1085
|
+
.vgai-color-swatch:hover:not(:disabled) {
|
|
1086
|
+
border-color: var(--vgai-boundary-strong);
|
|
1087
|
+
}
|
|
1088
|
+
.vgai-color-swatch:focus-visible,
|
|
1089
|
+
.vgai-file-input:focus-visible,
|
|
1090
|
+
.vgai-range:focus-visible {
|
|
1091
|
+
outline: var(--vgai-focus-ring);
|
|
1092
|
+
outline-offset: 2px;
|
|
1093
|
+
}
|
|
1094
|
+
.vgai-color-swatch:disabled,
|
|
1095
|
+
.vgai-file-input:disabled,
|
|
1096
|
+
.vgai-range:disabled {
|
|
1097
|
+
opacity: 0.5;
|
|
1098
|
+
cursor: not-allowed;
|
|
1099
|
+
}
|
|
1100
|
+
.vgai-file-input {
|
|
1101
|
+
color: var(--vgai-content-muted);
|
|
1102
|
+
font: inherit;
|
|
1103
|
+
}
|
|
1104
|
+
.vgai-range {
|
|
1105
|
+
min-width: 0;
|
|
1106
|
+
accent-color: var(--vgai-accent);
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
.vgai-number-input,
|
|
1110
|
+
.vgai-color-input {
|
|
1111
|
+
display: flex;
|
|
1112
|
+
min-width: 0;
|
|
1113
|
+
align-items: center;
|
|
1114
|
+
gap: var(--vgai-space-2);
|
|
1115
|
+
}
|
|
1116
|
+
.vgai-number-input-label {
|
|
1117
|
+
width: 12px;
|
|
1118
|
+
flex: 0 0 auto;
|
|
1119
|
+
color: var(--vgai-content-muted);
|
|
1120
|
+
font-size: var(--vgai-font-sm);
|
|
1121
|
+
font-weight: 600;
|
|
1122
|
+
text-align: center;
|
|
1123
|
+
user-select: none;
|
|
1124
|
+
}
|
|
1125
|
+
.vgai-number-input-editor,
|
|
1126
|
+
.vgai-number-input-scrub,
|
|
1127
|
+
.vgai-color-input > .vgai-input {
|
|
1128
|
+
width: 100%;
|
|
1129
|
+
min-width: 0;
|
|
1130
|
+
}
|
|
1131
|
+
.vgai-number-input-scrub {
|
|
1132
|
+
box-sizing: border-box;
|
|
1133
|
+
overflow: hidden;
|
|
1134
|
+
padding: var(--vgai-space-1) var(--vgai-space-3);
|
|
1135
|
+
color: var(--vgai-content-primary);
|
|
1136
|
+
background: var(--vgai-input-surface, var(--vgai-surface-inset));
|
|
1137
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-input-border, var(--vgai-boundary-default));
|
|
1138
|
+
border-radius: var(--vgai-radius-sm);
|
|
1139
|
+
box-shadow: var(--vgai-input-shadow, none);
|
|
1140
|
+
font-size: var(--vgai-font-base);
|
|
1141
|
+
text-overflow: ellipsis;
|
|
1142
|
+
white-space: nowrap;
|
|
1143
|
+
cursor: ew-resize;
|
|
1144
|
+
user-select: none;
|
|
1145
|
+
}
|
|
1146
|
+
.vgai-number-input-scrub:hover {
|
|
1147
|
+
border-color: var(--vgai-boundary-strong);
|
|
1148
|
+
}
|
|
1149
|
+
.vgai-scrub-label {
|
|
1150
|
+
transition:
|
|
1151
|
+
color 0.12s var(--vgai-ease-standard),
|
|
1152
|
+
filter 0.12s var(--vgai-ease-standard);
|
|
1153
|
+
}
|
|
1154
|
+
.vgai-scrub-label {
|
|
1155
|
+
color: var(--vgai-content-muted);
|
|
1156
|
+
}
|
|
1157
|
+
.vgai-scrub-label:hover:not([data-disabled="true"]) {
|
|
1158
|
+
color: var(--vgai-content-primary);
|
|
1159
|
+
}
|
|
1160
|
+
.vgai-number-input-scrub[data-disabled] {
|
|
1161
|
+
opacity: 0.5;
|
|
1162
|
+
cursor: not-allowed;
|
|
1163
|
+
}
|
|
1164
|
+
.vgai-number-input-scrub[data-mixed="true"],
|
|
1165
|
+
.vgai-color-input > .vgai-input[data-mixed="true"] {
|
|
1166
|
+
color: var(--vgai-content-dim);
|
|
1167
|
+
font-style: italic;
|
|
1168
|
+
}
|
|
1169
|
+
.vgai-color-input-mixed {
|
|
1170
|
+
width: var(--vgai-control-compact-height);
|
|
1171
|
+
height: var(--vgai-control-compact-height);
|
|
1172
|
+
flex: 0 0 auto;
|
|
1173
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
1174
|
+
border-radius: var(--vgai-radius-sm);
|
|
1175
|
+
background-color: var(--vgai-surface-inset);
|
|
1176
|
+
background-image:
|
|
1177
|
+
linear-gradient(
|
|
1178
|
+
45deg,
|
|
1179
|
+
var(--vgai-content-dim) 25%,
|
|
1180
|
+
transparent 25%,
|
|
1181
|
+
transparent 75%,
|
|
1182
|
+
var(--vgai-content-dim) 75%
|
|
1183
|
+
),
|
|
1184
|
+
linear-gradient(
|
|
1185
|
+
45deg,
|
|
1186
|
+
var(--vgai-content-dim) 25%,
|
|
1187
|
+
transparent 25%,
|
|
1188
|
+
transparent 75%,
|
|
1189
|
+
var(--vgai-content-dim) 75%
|
|
1190
|
+
);
|
|
1191
|
+
background-position:
|
|
1192
|
+
0 0,
|
|
1193
|
+
4px 4px;
|
|
1194
|
+
background-size: 8px 8px;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
.vgai-section {
|
|
1198
|
+
border-bottom: var(--vgai-stroke-resting) solid var(--vgai-structural-divider);
|
|
1199
|
+
}
|
|
1200
|
+
.vgai-section-header {
|
|
1201
|
+
display: flex;
|
|
1202
|
+
width: 100%;
|
|
1203
|
+
min-height: var(--vgai-control-default-height);
|
|
1204
|
+
align-items: center;
|
|
1205
|
+
gap: var(--vgai-space-1);
|
|
1206
|
+
color: var(--vgai-content-primary);
|
|
1207
|
+
/* A header is a slab lifted off its panel (Blender's header sits a step above its panel),
|
|
1208
|
+
derived from the palette's own two surfaces so every skin keeps the
|
|
1209
|
+
relationship. */
|
|
1210
|
+
background: var(--vgai-surface-section);
|
|
1211
|
+
}
|
|
1212
|
+
.vgai-section-trigger {
|
|
1213
|
+
display: flex;
|
|
1214
|
+
min-width: 0;
|
|
1215
|
+
min-height: var(--vgai-control-default-height);
|
|
1216
|
+
flex: 1;
|
|
1217
|
+
align-items: center;
|
|
1218
|
+
gap: var(--vgai-space-2);
|
|
1219
|
+
padding: var(--vgai-space-2) var(--vgai-space-4);
|
|
1220
|
+
color: inherit;
|
|
1221
|
+
background: transparent;
|
|
1222
|
+
border: 0;
|
|
1223
|
+
font: inherit;
|
|
1224
|
+
font-size: var(--vgai-font-base);
|
|
1225
|
+
font-weight: 600;
|
|
1226
|
+
text-align: left;
|
|
1227
|
+
cursor: pointer;
|
|
1228
|
+
}
|
|
1229
|
+
.vgai-section-trigger:hover {
|
|
1230
|
+
background: var(--vgai-neutral-hover);
|
|
1231
|
+
}
|
|
1232
|
+
/* A section heading that cannot collapse is a label, not a control: no
|
|
1233
|
+
disclosure arrow, no pointer, no hover feedback promising a toggle. */
|
|
1234
|
+
.vgai-section-trigger[data-vgai-static],
|
|
1235
|
+
.vgai-section-trigger[data-vgai-static]:hover {
|
|
1236
|
+
cursor: default;
|
|
1237
|
+
background: transparent;
|
|
1238
|
+
}
|
|
1239
|
+
.vgai-section-trigger:focus-visible {
|
|
1240
|
+
outline: var(--vgai-focus-ring);
|
|
1241
|
+
outline-offset: -2px;
|
|
1242
|
+
}
|
|
1243
|
+
.vgai-section-title {
|
|
1244
|
+
display: grid;
|
|
1245
|
+
min-width: 0;
|
|
1246
|
+
flex: 1;
|
|
1247
|
+
}
|
|
1248
|
+
.vgai-section-title > span,
|
|
1249
|
+
.vgai-section-title > small {
|
|
1250
|
+
overflow: hidden;
|
|
1251
|
+
text-overflow: ellipsis;
|
|
1252
|
+
white-space: nowrap;
|
|
1253
|
+
}
|
|
1254
|
+
.vgai-section-title > small {
|
|
1255
|
+
color: var(--vgai-content-dim);
|
|
1256
|
+
font-size: var(--vgai-font-sm);
|
|
1257
|
+
font-weight: 400;
|
|
1258
|
+
}
|
|
1259
|
+
.vgai-section-actions {
|
|
1260
|
+
display: flex;
|
|
1261
|
+
flex: 0 0 auto;
|
|
1262
|
+
align-items: center;
|
|
1263
|
+
gap: var(--vgai-space-1);
|
|
1264
|
+
padding-right: var(--vgai-space-2);
|
|
1265
|
+
}
|
|
1266
|
+
.vgai-section-body {
|
|
1267
|
+
padding: 0 var(--vgai-space-4) var(--vgai-space-4);
|
|
1268
|
+
}
|
|
1269
|
+
/* One contributed inspector section's frame (`components/InspectorToolSection.tsx`).
|
|
1270
|
+
These three values were inline literals on that element; they are the same
|
|
1271
|
+
three, tokenized, so the narrow column is unchanged — the point of moving
|
|
1272
|
+
them is that the Properties presentation can now REPLACE them (Blender's
|
|
1273
|
+
Properties editor has no rule between its datablock row and its first panel,
|
|
1274
|
+
and insets its panel column once, not twice; `compact-inspector.css`). */
|
|
1275
|
+
.vgai-inspector-tool-section {
|
|
1276
|
+
padding: var(--vgai-space-4);
|
|
1277
|
+
margin-top: var(--vgai-space-2);
|
|
1278
|
+
border-top: var(--vgai-stroke-resting) solid var(--vgai-structural-divider);
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
.vgai-xstate-node {
|
|
1282
|
+
display: flex;
|
|
1283
|
+
flex-direction: column;
|
|
1284
|
+
align-items: flex-start;
|
|
1285
|
+
justify-content: center;
|
|
1286
|
+
gap: var(--vgai-space-1);
|
|
1287
|
+
padding: var(--vgai-space-3) var(--vgai-space-5);
|
|
1288
|
+
color: var(--vgai-content-primary);
|
|
1289
|
+
background: var(--vgai-surface-panel);
|
|
1290
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-strong);
|
|
1291
|
+
font-size: var(--vgai-font-base);
|
|
1292
|
+
text-align: left;
|
|
1293
|
+
transition:
|
|
1294
|
+
background 0.1s var(--vgai-ease-standard),
|
|
1295
|
+
border-color 0.1s var(--vgai-ease-standard),
|
|
1296
|
+
box-shadow 0.1s var(--vgai-ease-standard);
|
|
1297
|
+
}
|
|
1298
|
+
.vgai-xstate-node:hover {
|
|
1299
|
+
background: var(--vgai-surface-chrome);
|
|
1300
|
+
}
|
|
1301
|
+
.vgai-xstate-node[data-active="true"] {
|
|
1302
|
+
border-color: var(--vgai-success);
|
|
1303
|
+
}
|
|
1304
|
+
.vgai-xstate-node[data-selected="true"] {
|
|
1305
|
+
border-color: var(--vgai-selection-border);
|
|
1306
|
+
box-shadow: 0 0 0 var(--vgai-stroke-resting) var(--vgai-selection-border);
|
|
1307
|
+
}
|
|
1308
|
+
.vgai-xstate-node-type {
|
|
1309
|
+
color: var(--vgai-content-dim);
|
|
1310
|
+
transition: color 0.1s var(--vgai-ease-standard);
|
|
1311
|
+
}
|
|
1312
|
+
.vgai-xstate-node:hover .vgai-xstate-node-type,
|
|
1313
|
+
.vgai-xstate-node[data-selected="true"] .vgai-xstate-node-type {
|
|
1314
|
+
color: var(--vgai-content-primary);
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
/* ---------------------------------------------------------------------- */
|
|
1318
|
+
/* Layout, typography, and surface primitives. Product code composes these */
|
|
1319
|
+
/* roles instead of restating their visual recipes in inline objects. */
|
|
1320
|
+
/* ---------------------------------------------------------------------- */
|
|
1321
|
+
|
|
1322
|
+
.vgai-stack {
|
|
1323
|
+
display: flex;
|
|
1324
|
+
min-width: 0;
|
|
1325
|
+
flex-direction: column;
|
|
1326
|
+
}
|
|
1327
|
+
.vgai-inline {
|
|
1328
|
+
display: flex;
|
|
1329
|
+
min-width: 0;
|
|
1330
|
+
}
|
|
1331
|
+
.vgai-spacer {
|
|
1332
|
+
min-width: 0;
|
|
1333
|
+
flex: 1 1 auto;
|
|
1334
|
+
}
|
|
1335
|
+
.vgai-actions {
|
|
1336
|
+
flex: 0 0 auto;
|
|
1337
|
+
}
|
|
1338
|
+
.vgai-divider {
|
|
1339
|
+
flex: 0 0 auto;
|
|
1340
|
+
background: var(--vgai-boundary-default);
|
|
1341
|
+
}
|
|
1342
|
+
.vgai-divider[data-orientation="horizontal"] {
|
|
1343
|
+
width: 100%;
|
|
1344
|
+
height: var(--vgai-stroke-resting);
|
|
1345
|
+
}
|
|
1346
|
+
.vgai-divider[data-orientation="vertical"] {
|
|
1347
|
+
width: var(--vgai-stroke-resting);
|
|
1348
|
+
/* A rule between controls is exactly as tall as the controls it separates —
|
|
1349
|
+
measured in Blender's top bar, the rule closing the menu words is 20px,
|
|
1350
|
+
the same as every widget in that bar. It was a hard 16px, a literal that
|
|
1351
|
+
outranked whatever height the material asked for. */
|
|
1352
|
+
height: var(--vgai-control-compact-height);
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
.vgai-text {
|
|
1356
|
+
min-width: 0;
|
|
1357
|
+
margin: 0;
|
|
1358
|
+
color: var(--vgai-content-primary);
|
|
1359
|
+
font-size: var(--vgai-font-base);
|
|
1360
|
+
font-weight: 400;
|
|
1361
|
+
line-height: 1.35;
|
|
1362
|
+
}
|
|
1363
|
+
.vgai-text[data-variant="caption"] {
|
|
1364
|
+
font-size: var(--vgai-font-sm);
|
|
1365
|
+
}
|
|
1366
|
+
.vgai-text[data-variant="body"] {
|
|
1367
|
+
font-size: var(--vgai-font-base);
|
|
1368
|
+
}
|
|
1369
|
+
.vgai-text[data-variant="label"] {
|
|
1370
|
+
font-size: var(--vgai-font-base);
|
|
1371
|
+
font-weight: 600;
|
|
1372
|
+
}
|
|
1373
|
+
.vgai-text[data-variant="title"] {
|
|
1374
|
+
font-size: var(--vgai-font-md);
|
|
1375
|
+
font-weight: 600;
|
|
1376
|
+
}
|
|
1377
|
+
.vgai-text[data-variant="heading"] {
|
|
1378
|
+
font-size: var(--vgai-font-xl);
|
|
1379
|
+
font-weight: 600;
|
|
1380
|
+
}
|
|
1381
|
+
.vgai-text[data-variant="display"] {
|
|
1382
|
+
font-size: var(--vgai-font-heading);
|
|
1383
|
+
font-weight: 600;
|
|
1384
|
+
}
|
|
1385
|
+
.vgai-text[data-variant="code"] {
|
|
1386
|
+
font-family: var(--vgai-font-mono);
|
|
1387
|
+
font-size: var(--vgai-font-base);
|
|
1388
|
+
}
|
|
1389
|
+
.vgai-text[data-tone="muted"] {
|
|
1390
|
+
color: var(--vgai-content-muted);
|
|
1391
|
+
}
|
|
1392
|
+
.vgai-text[data-tone="dim"] {
|
|
1393
|
+
color: var(--vgai-content-dim);
|
|
1394
|
+
}
|
|
1395
|
+
.vgai-text[data-tone="accent"] {
|
|
1396
|
+
color: var(--vgai-accent);
|
|
1397
|
+
}
|
|
1398
|
+
.vgai-text[data-tone="danger"] {
|
|
1399
|
+
color: var(--vgai-danger);
|
|
1400
|
+
}
|
|
1401
|
+
.vgai-text[data-tone="warning"] {
|
|
1402
|
+
color: var(--vgai-warn);
|
|
1403
|
+
}
|
|
1404
|
+
.vgai-text[data-tone="success"] {
|
|
1405
|
+
color: var(--vgai-success);
|
|
1406
|
+
}
|
|
1407
|
+
.vgai-text[data-truncate="true"] {
|
|
1408
|
+
overflow: hidden;
|
|
1409
|
+
text-overflow: ellipsis;
|
|
1410
|
+
white-space: nowrap;
|
|
1411
|
+
}
|
|
1412
|
+
.vgai-text[data-selectable="true"] {
|
|
1413
|
+
user-select: text;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
.vgai-surface {
|
|
1417
|
+
min-width: 0;
|
|
1418
|
+
color: var(--vgai-content-primary);
|
|
1419
|
+
background: var(--vgai-surface-panel);
|
|
1420
|
+
box-sizing: border-box;
|
|
1421
|
+
}
|
|
1422
|
+
.vgai-surface[data-variant="shell"] {
|
|
1423
|
+
background: var(--vgai-surface-shell);
|
|
1424
|
+
}
|
|
1425
|
+
.vgai-surface[data-variant="panel"] {
|
|
1426
|
+
background: var(--vgai-surface-panel);
|
|
1427
|
+
}
|
|
1428
|
+
.vgai-surface[data-variant="chrome"] {
|
|
1429
|
+
background: var(--vgai-surface-chrome);
|
|
1430
|
+
}
|
|
1431
|
+
.vgai-surface[data-variant="raised"] {
|
|
1432
|
+
background: var(--vgai-surface-raised);
|
|
1433
|
+
}
|
|
1434
|
+
.vgai-surface[data-variant="inset"] {
|
|
1435
|
+
background: var(--vgai-surface-inset);
|
|
1436
|
+
}
|
|
1437
|
+
.vgai-surface[data-variant="overlay"] {
|
|
1438
|
+
background: var(--vgai-surface-overlay);
|
|
1439
|
+
}
|
|
1440
|
+
.vgai-surface[data-border="true"] {
|
|
1441
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
1442
|
+
}
|
|
1443
|
+
.vgai-surface[data-scroll="true"] {
|
|
1444
|
+
min-height: 0;
|
|
1445
|
+
overflow: auto;
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
/* Modal composition. Product dialogs supply content; this family owns chrome.
|
|
1449
|
+
Glass themes pair a LIGHTER dim with a scrim blur (the macOS modal read,
|
|
1450
|
+
P6-U6 owner taste decision 3) — the blur var is `none` for every
|
|
1451
|
+
treatment-less theme, whose heavier `--vgai-scrim` dim then paints
|
|
1452
|
+
byte-identically to before. */
|
|
1453
|
+
.vgai-dialog-scrim {
|
|
1454
|
+
position: fixed;
|
|
1455
|
+
inset: 0;
|
|
1456
|
+
z-index: var(--vgai-z-modal);
|
|
1457
|
+
display: flex;
|
|
1458
|
+
align-items: center;
|
|
1459
|
+
justify-content: center;
|
|
1460
|
+
padding: var(--vgai-space-10);
|
|
1461
|
+
background: var(--vgai-scrim);
|
|
1462
|
+
backdrop-filter: var(--vgai-scrim-backdrop-filter, none);
|
|
1463
|
+
-webkit-backdrop-filter: var(--vgai-scrim-backdrop-filter, none);
|
|
1464
|
+
pointer-events: auto;
|
|
1465
|
+
box-sizing: border-box;
|
|
1466
|
+
}
|
|
1467
|
+
.vgai-dialog-scrim[data-variant="command"] {
|
|
1468
|
+
align-items: flex-start;
|
|
1469
|
+
padding-top: calc(var(--vgai-space-12) + var(--vgai-space-10) + var(--vgai-space-8));
|
|
1470
|
+
}
|
|
1471
|
+
.vgai-dialog {
|
|
1472
|
+
display: flex;
|
|
1473
|
+
width: min(520px, calc(100vw - 48px));
|
|
1474
|
+
max-height: calc(100vh - 48px);
|
|
1475
|
+
min-width: 360px;
|
|
1476
|
+
flex-direction: column;
|
|
1477
|
+
overflow: hidden;
|
|
1478
|
+
color: var(--vgai-content-primary);
|
|
1479
|
+
background: var(--vgai-glass-regular-bg, var(--vgai-surface-chrome));
|
|
1480
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-strong);
|
|
1481
|
+
border-radius: var(--vgai-radius-lg);
|
|
1482
|
+
box-shadow: var(--vgai-shadow-lg);
|
|
1483
|
+
box-sizing: border-box;
|
|
1484
|
+
}
|
|
1485
|
+
.vgai-dialog[data-size="compact"] {
|
|
1486
|
+
width: min(420px, calc(100vw - 48px));
|
|
1487
|
+
}
|
|
1488
|
+
.vgai-dialog[data-size="wide"] {
|
|
1489
|
+
width: min(920px, calc(100vw - 48px));
|
|
1490
|
+
height: min(720px, calc(100vh - 48px));
|
|
1491
|
+
}
|
|
1492
|
+
.vgai-dialog[data-variant="command"] {
|
|
1493
|
+
width: min(500px, calc(100vw - 48px));
|
|
1494
|
+
max-height: min(480px, calc(100vh - 48px));
|
|
1495
|
+
}
|
|
1496
|
+
.vgai-command-results {
|
|
1497
|
+
min-height: 0;
|
|
1498
|
+
max-height: 400px;
|
|
1499
|
+
flex: 1;
|
|
1500
|
+
overflow-y: auto;
|
|
1501
|
+
}
|
|
1502
|
+
.vgai-command-category {
|
|
1503
|
+
padding: var(--vgai-space-3) calc(var(--vgai-space-6) + var(--vgai-space-1)) var(--vgai-space-1);
|
|
1504
|
+
color: var(--vgai-content-muted);
|
|
1505
|
+
font-size: var(--vgai-font-base);
|
|
1506
|
+
font-weight: 600;
|
|
1507
|
+
letter-spacing: 0.5px;
|
|
1508
|
+
text-transform: uppercase;
|
|
1509
|
+
}
|
|
1510
|
+
.vgai-command-row {
|
|
1511
|
+
display: flex;
|
|
1512
|
+
align-items: center;
|
|
1513
|
+
gap: var(--vgai-space-4);
|
|
1514
|
+
padding: 5px calc(var(--vgai-space-6) + var(--vgai-space-1));
|
|
1515
|
+
cursor: pointer;
|
|
1516
|
+
}
|
|
1517
|
+
.vgai-command-row[data-highlighted="true"] {
|
|
1518
|
+
background: var(--vgai-selection-bg);
|
|
1519
|
+
}
|
|
1520
|
+
.vgai-command-icon {
|
|
1521
|
+
width: 14px;
|
|
1522
|
+
flex-shrink: 0;
|
|
1523
|
+
color: var(--vgai-content-dim);
|
|
1524
|
+
font-size: var(--vgai-font-sm);
|
|
1525
|
+
text-align: center;
|
|
1526
|
+
}
|
|
1527
|
+
.vgai-command-label {
|
|
1528
|
+
min-width: 0;
|
|
1529
|
+
flex: 1;
|
|
1530
|
+
overflow: hidden;
|
|
1531
|
+
text-overflow: ellipsis;
|
|
1532
|
+
white-space: nowrap;
|
|
1533
|
+
}
|
|
1534
|
+
.vgai-command-shortcut {
|
|
1535
|
+
flex-shrink: 0;
|
|
1536
|
+
color: var(--vgai-content-dim);
|
|
1537
|
+
font-size: var(--vgai-font-base);
|
|
1538
|
+
}
|
|
1539
|
+
.vgai-command-empty {
|
|
1540
|
+
padding: var(--vgai-space-8) calc(var(--vgai-space-6) + var(--vgai-space-1));
|
|
1541
|
+
color: var(--vgai-content-dim);
|
|
1542
|
+
text-align: center;
|
|
1543
|
+
}
|
|
1544
|
+
.vgai-dialog-header {
|
|
1545
|
+
padding: var(--vgai-space-8) var(--vgai-space-10);
|
|
1546
|
+
border-bottom: var(--vgai-stroke-resting) solid var(--vgai-structural-divider);
|
|
1547
|
+
}
|
|
1548
|
+
.vgai-dialog-body {
|
|
1549
|
+
min-height: 0;
|
|
1550
|
+
padding: var(--vgai-space-8) var(--vgai-space-10);
|
|
1551
|
+
overflow: auto;
|
|
1552
|
+
}
|
|
1553
|
+
.vgai-dialog-footer {
|
|
1554
|
+
justify-content: flex-end;
|
|
1555
|
+
padding: var(--vgai-space-6) var(--vgai-space-10);
|
|
1556
|
+
border-top: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
1557
|
+
}
|
|
1558
|
+
.vgai-dialog-field {
|
|
1559
|
+
display: grid;
|
|
1560
|
+
min-width: 0;
|
|
1561
|
+
gap: var(--vgai-space-2);
|
|
1562
|
+
}
|
|
1563
|
+
.vgai-dialog-field > .vgai-input {
|
|
1564
|
+
width: 100%;
|
|
1565
|
+
}
|
|
1566
|
+
.vgai-joined-field {
|
|
1567
|
+
align-items: stretch;
|
|
1568
|
+
gap: 0;
|
|
1569
|
+
}
|
|
1570
|
+
.vgai-joined-field > .vgai-input {
|
|
1571
|
+
width: 100%;
|
|
1572
|
+
border-top-right-radius: 0;
|
|
1573
|
+
border-bottom-right-radius: 0;
|
|
1574
|
+
}
|
|
1575
|
+
.vgai-joined-field-suffix {
|
|
1576
|
+
display: inline-flex;
|
|
1577
|
+
flex: 0 0 auto;
|
|
1578
|
+
align-items: center;
|
|
1579
|
+
padding: 0 var(--vgai-space-4);
|
|
1580
|
+
color: var(--vgai-content-dim);
|
|
1581
|
+
background: var(--vgai-surface-raised);
|
|
1582
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
1583
|
+
border-left: 0;
|
|
1584
|
+
border-radius: 0 var(--vgai-radius-sm) var(--vgai-radius-sm) 0;
|
|
1585
|
+
white-space: nowrap;
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
/* ---------------------------------------------------------------------- */
|
|
1589
|
+
/* .vgai-menu / .vgai-menu-item — shared floating-menu classes (optional, */
|
|
1590
|
+
/* for later units). */
|
|
1591
|
+
/* ---------------------------------------------------------------------- */
|
|
1592
|
+
|
|
1593
|
+
/* REGULAR Liquid Glass (P3 overlay chrome, formalized as
|
|
1594
|
+
* `--vgai-glass-regular-*` in P6-U6 — the owner's Apple-HIG call: menus/
|
|
1595
|
+
* popovers/dialogs/palette are the REGULAR variant, "more solid", never the
|
|
1596
|
+
* refractive Clear family): transient surfaces are never
|
|
1597
|
+
* backdrop-classified — the material is self-sufficient on both luminance
|
|
1598
|
+
* sides instead. `--vgai-glass-regular-bg` is a raised light tint (adaptive
|
|
1599
|
+
* themes) or the theme's own chrome tone at high opacity (dark-side glass
|
|
1600
|
+
* themes) over a strong frost (`…-backdrop-filter`), statically paired with
|
|
1601
|
+
* the `-on-bright` ink ramp so they read over ANY backdrop (the ramp
|
|
1602
|
+
* mirrors the normal inks for non-adaptive themes, making the remap
|
|
1603
|
+
* inert). For every theme without a treatment these vars mirror the plain
|
|
1604
|
+
* chrome surface / `none` — byte-identical paint. Same text-shadow
|
|
1605
|
+
* re-declaration rationale as the bright-scope rule above. */
|
|
1606
|
+
.vgai-menu,
|
|
1607
|
+
.vgai-popover,
|
|
1608
|
+
.vgai-dialog {
|
|
1609
|
+
--vgai-content-primary: var(--vgai-content-primary-on-bright);
|
|
1610
|
+
--vgai-content-muted: var(--vgai-content-muted-on-bright);
|
|
1611
|
+
--vgai-content-dim: var(--vgai-content-dim-on-bright);
|
|
1612
|
+
--vgai-content-text-shadow: var(--vgai-content-text-shadow-on-bright);
|
|
1613
|
+
--vgai-content-frost-bg: var(--vgai-content-frost-bg-on-bright);
|
|
1614
|
+
--vgai-text-1: var(--vgai-content-primary);
|
|
1615
|
+
--vgai-text-2: var(--vgai-content-muted);
|
|
1616
|
+
--vgai-text-3: var(--vgai-content-dim);
|
|
1617
|
+
text-shadow: var(--vgai-content-text-shadow, none);
|
|
1618
|
+
backdrop-filter: var(--vgai-glass-regular-backdrop-filter, none);
|
|
1619
|
+
-webkit-backdrop-filter: var(--vgai-glass-regular-backdrop-filter, none);
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
.vgai-menu {
|
|
1623
|
+
/* Opaque skins: the shell, a step darker than the bar a menu opens from
|
|
1624
|
+
(Blender's popups are a step darker than its top bar). Glass keeps its own. */
|
|
1625
|
+
background: var(--vgai-glass-regular-bg, var(--vgai-surface-shell));
|
|
1626
|
+
border: 1px solid var(--vgai-border-1);
|
|
1627
|
+
border-radius: var(--vgai-radius-md);
|
|
1628
|
+
box-shadow: var(--vgai-shadow-md);
|
|
1629
|
+
padding: var(--vgai-space-2);
|
|
1630
|
+
z-index: var(--vgai-z-dropdown);
|
|
1631
|
+
/* Menus can portal directly under the theme root to escape a glass
|
|
1632
|
+
stacking context. Own typography at the primitive boundary instead of
|
|
1633
|
+
inheriting through `.vgai-shell`, or portaled dropdowns fall back to the
|
|
1634
|
+
browser's serif default. */
|
|
1635
|
+
}
|
|
1636
|
+
.vgai-menu-item {
|
|
1637
|
+
display: flex;
|
|
1638
|
+
align-items: center;
|
|
1639
|
+
width: 100%;
|
|
1640
|
+
min-height: var(--vgai-control-default-height);
|
|
1641
|
+
box-sizing: border-box;
|
|
1642
|
+
border: 0;
|
|
1643
|
+
background: transparent;
|
|
1644
|
+
padding: var(--vgai-space-2) var(--vgai-space-4);
|
|
1645
|
+
border-radius: var(--vgai-radius-sm);
|
|
1646
|
+
font-size: var(--vgai-font-base);
|
|
1647
|
+
color: var(--vgai-text-1);
|
|
1648
|
+
cursor: pointer;
|
|
1649
|
+
user-select: none;
|
|
1650
|
+
font-family: inherit;
|
|
1651
|
+
text-align: left;
|
|
1652
|
+
white-space: nowrap;
|
|
1653
|
+
}
|
|
1654
|
+
.vgai-menu-item:hover {
|
|
1655
|
+
background: var(--vgai-selection-bg);
|
|
1656
|
+
}
|
|
1657
|
+
.vgai-menu-item:focus-visible {
|
|
1658
|
+
outline: var(--vgai-focus-ring);
|
|
1659
|
+
outline-offset: -1px;
|
|
1660
|
+
}
|
|
1661
|
+
.vgai-menu-item:disabled {
|
|
1662
|
+
color: var(--vgai-text-3);
|
|
1663
|
+
cursor: default;
|
|
1664
|
+
}
|
|
1665
|
+
.vgai-menu-item:disabled:hover {
|
|
1666
|
+
background: transparent;
|
|
1667
|
+
}
|
|
1668
|
+
.vgai-menu-separator {
|
|
1669
|
+
height: var(--vgai-stroke-resting);
|
|
1670
|
+
margin: var(--vgai-space-1) var(--vgai-space-2);
|
|
1671
|
+
border: 0;
|
|
1672
|
+
background: var(--vgai-boundary-default);
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
/* A top-bar menu word (File/Edit/Render in Blender; Edit/View/Window here) is
|
|
1676
|
+
a WIDGET, not a line of text. Measured in Blender 5.2's own top bar at 2x
|
|
1677
|
+
(`topbar.png`, halved): the labels sit 16px ink-to-ink — 8px of padding
|
|
1678
|
+
each side with the buttons touching — and every widget in the bar is 20px
|
|
1679
|
+
tall. This rule used to give 6px of padding and no height at all, so the
|
|
1680
|
+
trigger collapsed to its 15px line box (font 11 x leading 1.4) and the row
|
|
1681
|
+
read as text floating in a bar. `min-height` rather than `height`: where a
|
|
1682
|
+
parent DOES have a definite height (a panel header), 100% still wins. */
|
|
1683
|
+
.vgai-menu-trigger {
|
|
1684
|
+
height: 100%;
|
|
1685
|
+
min-height: var(--vgai-control-compact-height);
|
|
1686
|
+
border: 0;
|
|
1687
|
+
border-radius: var(--vgai-radius-sm);
|
|
1688
|
+
background: transparent;
|
|
1689
|
+
/* A MENU WORD IS ITS OWN INK (`content.menu`; see theme.ts for the two
|
|
1690
|
+
backdrops that prove it opaque). This rule used to read `text-2` — the
|
|
1691
|
+
OUTLINER ROW's ink — so every unenclosed clickable word in an area header
|
|
1692
|
+
drew at row-text level while the top bar alone carried an override to
|
|
1693
|
+
primary: one role split across two members. The token falls back to
|
|
1694
|
+
`content.primary` in the emitter, which is what the top bar already
|
|
1695
|
+
painted, so a palette naming no menu ink leaves that bar untouched. */
|
|
1696
|
+
color: var(--vgai-content-menu);
|
|
1697
|
+
padding: 0 var(--vgai-space-4);
|
|
1698
|
+
cursor: pointer;
|
|
1699
|
+
font: inherit;
|
|
1700
|
+
}
|
|
1701
|
+
.vgai-menu-trigger:hover,
|
|
1702
|
+
.vgai-menu-trigger[aria-expanded="true"] {
|
|
1703
|
+
color: var(--vgai-text-1);
|
|
1704
|
+
background: var(--vgai-bg-3);
|
|
1705
|
+
}
|
|
1706
|
+
.vgai-menu-trigger:focus-visible {
|
|
1707
|
+
outline: var(--vgai-focus-ring);
|
|
1708
|
+
outline-offset: -1px;
|
|
1709
|
+
}
|
|
1710
|
+
|
|
1711
|
+
/* Persistent REGULAR Liquid Glass: large, text-heavy panels blur and adapt the
|
|
1712
|
+
* sampled backdrop instead of replacing it with a high-opacity card. The
|
|
1713
|
+
* normal light-ink state adds shade only when contrast begins to fail; bright
|
|
1714
|
+
* scenes switch to dark ink and nearly transparent fills. The panel host
|
|
1715
|
+
* owns the ONE body frost; dense `.vgai-content-frost` floors receive a
|
|
1716
|
+
* stronger correction, but never a second filter. */
|
|
1717
|
+
[data-vgai-chrome="islands"] .vgai-glass-regular-panel {
|
|
1718
|
+
color: var(--vgai-content-primary);
|
|
1719
|
+
text-shadow: var(--vgai-content-text-shadow, none);
|
|
1720
|
+
background: var(
|
|
1721
|
+
--vgai-glass-regular-panel-adaptive-bg,
|
|
1722
|
+
var(--vgai-glass-regular-panel-bg, var(--vgai-surface-panel))
|
|
1723
|
+
);
|
|
1724
|
+
backdrop-filter: var(--vgai-glass-regular-panel-backdrop-filter, none);
|
|
1725
|
+
-webkit-backdrop-filter: var(--vgai-glass-regular-panel-backdrop-filter, none);
|
|
1726
|
+
border: var(--vgai-stroke-resting) solid
|
|
1727
|
+
color-mix(in srgb, var(--vgai-content-primary) 22%, transparent);
|
|
1728
|
+
border-radius: var(--vgai-radius-lg);
|
|
1729
|
+
box-shadow: var(--vgai-card-specular-shadow, var(--vgai-shadow-lg));
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
[data-vgai-chrome="islands"] .vgai-glass-regular-panel .vgai-content-frost {
|
|
1733
|
+
background: var(
|
|
1734
|
+
--vgai-glass-regular-content-adaptive-bg,
|
|
1735
|
+
var(--vgai-content-frost-bg, transparent)
|
|
1736
|
+
);
|
|
1737
|
+
backdrop-filter: none;
|
|
1738
|
+
-webkit-backdrop-filter: none;
|
|
1739
|
+
}
|
|
1740
|
+
|
|
1741
|
+
/* ---------------------------------------------------------------------- */
|
|
1742
|
+
/* Editor composition patterns: toolbars, tabs, trees, fields, and states. */
|
|
1743
|
+
/* ---------------------------------------------------------------------- */
|
|
1744
|
+
|
|
1745
|
+
.vgai-toolbar {
|
|
1746
|
+
display: flex;
|
|
1747
|
+
min-width: 0;
|
|
1748
|
+
min-height: var(--vgai-local-toolbar-height);
|
|
1749
|
+
align-items: center;
|
|
1750
|
+
gap: var(--vgai-space-2);
|
|
1751
|
+
padding: 0 var(--vgai-space-3);
|
|
1752
|
+
color: var(--vgai-content-primary);
|
|
1753
|
+
/* Structural chrome is clear. Significant text floors own the single
|
|
1754
|
+
content-frost tier; a toolbar inside that floor must not blur again.
|
|
1755
|
+
Floating toolbars below remain independent glass islands. */
|
|
1756
|
+
background: transparent;
|
|
1757
|
+
border-bottom: var(--vgai-stroke-resting) solid var(--vgai-structural-divider);
|
|
1758
|
+
box-sizing: border-box;
|
|
1759
|
+
}
|
|
1760
|
+
.vgai-toolbar[data-compact="true"] {
|
|
1761
|
+
min-height: var(--vgai-control-default-height);
|
|
1762
|
+
padding-inline: var(--vgai-space-2);
|
|
1763
|
+
}
|
|
1764
|
+
.vgai-toolbar-group {
|
|
1765
|
+
display: inline-flex;
|
|
1766
|
+
min-width: 0;
|
|
1767
|
+
align-items: center;
|
|
1768
|
+
gap: var(--vgai-space-2);
|
|
1769
|
+
}
|
|
1770
|
+
.vgai-toolbar-divider {
|
|
1771
|
+
width: 1px;
|
|
1772
|
+
height: 16px;
|
|
1773
|
+
flex: 0 0 auto;
|
|
1774
|
+
margin: 0 var(--vgai-space-1);
|
|
1775
|
+
background: var(--vgai-boundary-default);
|
|
1776
|
+
}
|
|
1777
|
+
/* Floating toolbars are glass ISLANDS (P6 glass-native chrome, U2): the
|
|
1778
|
+
owner's "just transparent blurs" call-out. Fill, filter, radius, border,
|
|
1779
|
+
and shadow all arrive through the treatment-driven --vgai-island-* vars
|
|
1780
|
+
(theme.ts) — a glass theme paints the card material (panel-whisper fill,
|
|
1781
|
+
the theme's plain backdrop list, radius 17, deep shadow) and the
|
|
1782
|
+
refraction engine upgrades each `.vgai-glass-island` (the class
|
|
1783
|
+
patterns/Toolbar.tsx adds alongside this one) to its own url()
|
|
1784
|
+
displacement chain where capable; this declaration is the var-driven
|
|
1785
|
+
plain-list fallback it suspends to. Treatment-less themes emit the exact
|
|
1786
|
+
pre-P6 recipe through the same vars, so graphite/lite paint
|
|
1787
|
+
byte-identically. Text opts into the theme's content shadow (inert
|
|
1788
|
+
'none' without the axis). */
|
|
1789
|
+
.vgai-floating-toolbar {
|
|
1790
|
+
position: relative;
|
|
1791
|
+
min-height: auto;
|
|
1792
|
+
padding: var(--vgai-space-2) var(--vgai-space-3);
|
|
1793
|
+
border: var(--vgai-stroke-resting) solid
|
|
1794
|
+
var(--vgai-island-border-color, var(--vgai-boundary-strong));
|
|
1795
|
+
border-radius: var(--vgai-island-radius, var(--vgai-radius-md));
|
|
1796
|
+
/* Ambient-lift layer (P6-U6 taste decision 2): 'none' for every
|
|
1797
|
+
treatment-less theme, so the composed background stays byte-equivalent
|
|
1798
|
+
to the single-layer paint. */
|
|
1799
|
+
background:
|
|
1800
|
+
var(--vgai-ambient-lift, none), var(--vgai-backdrop-dim, none),
|
|
1801
|
+
var(--vgai-island-surface, color-mix(in srgb, var(--vgai-surface-panel) 90%, transparent));
|
|
1802
|
+
box-shadow: var(--vgai-island-shadow, var(--vgai-shadow-sm));
|
|
1803
|
+
backdrop-filter: var(--vgai-island-backdrop-filter, blur(8px));
|
|
1804
|
+
-webkit-backdrop-filter: var(--vgai-island-backdrop-filter, blur(8px));
|
|
1805
|
+
text-shadow: var(--vgai-content-text-shadow, none);
|
|
1806
|
+
pointer-events: auto;
|
|
1807
|
+
}
|
|
1808
|
+
/* Apple-style segmented chrome uses a neutral material lift for selection.
|
|
1809
|
+
Accent remains reserved for actions, focus, warnings, and authored color;
|
|
1810
|
+
choosing Move/Rotate/Scale or a viewport display toggle is not an accent
|
|
1811
|
+
action. This toolbar-scoped rule intentionally leaves pressed buttons in
|
|
1812
|
+
ordinary panels on their existing semantic treatment. */
|
|
1813
|
+
.vgai-floating-toolbar .vgai-btn[aria-pressed="true"] {
|
|
1814
|
+
color: var(--vgai-content-primary);
|
|
1815
|
+
background: var(--vgai-selection-bg);
|
|
1816
|
+
border-color: transparent;
|
|
1817
|
+
}
|
|
1818
|
+
/* Exclusive selection uses the same toolbar material and button geometry,
|
|
1819
|
+
but the one selected destination receives the stronger tab-style accent.
|
|
1820
|
+
Independent viewport toggles above intentionally keep the neutral state so
|
|
1821
|
+
several simultaneous selections don't compete for primary emphasis. */
|
|
1822
|
+
.vgai-floating-toolbar[data-selection-mode="single"] .vgai-btn[aria-pressed="true"] {
|
|
1823
|
+
color: var(--vgai-accent);
|
|
1824
|
+
background: var(--vgai-neutral-active);
|
|
1825
|
+
}
|
|
1826
|
+
/* Transform modes are segments, not isolated circular icon buttons. Keep
|
|
1827
|
+
every segment wider than it is tall so the neutral selection reads as a
|
|
1828
|
+
generous oval and changing modes never shifts the toolbar geometry. */
|
|
1829
|
+
.vgai-floating-toolbar .vgai-btn[data-shape="segment"] {
|
|
1830
|
+
width: calc(var(--vgai-control-comfortable-height) + 12px);
|
|
1831
|
+
}
|
|
1832
|
+
/* Specular rim, consistent with cards (workspace-dock.css's card ::before):
|
|
1833
|
+
the 1.5px gradient ring via the padding + mask-composite trick — only the
|
|
1834
|
+
rim band survives the XOR of content-box vs full-box masks. Paints
|
|
1835
|
+
nothing when the theme emits no specular ring ('none' for every
|
|
1836
|
+
treatment-less theme — that IS the degrade). The toolbar's
|
|
1837
|
+
backdrop-filter always makes it a stacking context. The ring sits at z0
|
|
1838
|
+
with interactive children explicitly above it; a huge decorative z-index
|
|
1839
|
+
made Chromium target the toolbar surface instead of its buttons despite
|
|
1840
|
+
`pointer-events:none`. */
|
|
1841
|
+
.vgai-floating-toolbar::before {
|
|
1842
|
+
content: "";
|
|
1843
|
+
position: absolute;
|
|
1844
|
+
inset: 0;
|
|
1845
|
+
z-index: var(--vgai-z-base);
|
|
1846
|
+
padding: 1px;
|
|
1847
|
+
border-radius: inherit;
|
|
1848
|
+
background: var(--vgai-island-specular-ring, none);
|
|
1849
|
+
-webkit-mask:
|
|
1850
|
+
linear-gradient(#000 0 0) content-box,
|
|
1851
|
+
linear-gradient(#000 0 0);
|
|
1852
|
+
-webkit-mask-composite: xor;
|
|
1853
|
+
mask:
|
|
1854
|
+
linear-gradient(#000 0 0) content-box exclude,
|
|
1855
|
+
linear-gradient(#000 0 0);
|
|
1856
|
+
pointer-events: none;
|
|
1857
|
+
}
|
|
1858
|
+
.vgai-floating-toolbar > * {
|
|
1859
|
+
position: relative;
|
|
1860
|
+
z-index: 1;
|
|
1861
|
+
}
|
|
1862
|
+
/* Header/footer chrome ISLANDS (P6 glass-native chrome, U3/U4): under
|
|
1863
|
+
islands chrome — `data-vgai-chrome="islands"` on the theme root, derived
|
|
1864
|
+
in theme.ts from the glass TREATMENT, never from theme identity — the
|
|
1865
|
+
command-bar clusters (ProjectHeader.css) and status-bar groups / tray
|
|
1866
|
+
button (EditorBottomBar.css) paint the same island material as
|
|
1867
|
+
.vgai-floating-toolbar above, through the same --vgai-island-* vars; the
|
|
1868
|
+
refraction engine upgrades each one (they all carry .vgai-glass-island)
|
|
1869
|
+
to the url() displacement chain where capable, and this declaration is
|
|
1870
|
+
the plain-list fallback it suspends to. `:not(:empty)` doubles as the
|
|
1871
|
+
auto-hide affordance: an empty status group paints NOTHING (no 2px
|
|
1872
|
+
border sliver), matching the pre-existing right-group :not(:empty)
|
|
1873
|
+
spacing rule. Under bars chrome the class is completely inert, so
|
|
1874
|
+
graphite/classic and the reduced-transparency/lite fallbacks (which
|
|
1875
|
+
strip `treatment`, and therefore resolve to bars) paint byte-identically
|
|
1876
|
+
to today. Geometry (heights/insets/padding) stays with each component's
|
|
1877
|
+
own stylesheet; only the shared material lives here. */
|
|
1878
|
+
/* THE NAVIGATION CLUSTER's own metrics — Blender's, measured in
|
|
1879
|
+
`modeling-object-none.png` at matched scale: a 28 CSS px button column
|
|
1880
|
+
with 16 px glyphs, in a capsule exactly as wide as the buttons. The
|
|
1881
|
+
Blender style flattens every control height to 20 for its menus and
|
|
1882
|
+
headers, which is right there and wrong here, so the cluster restates
|
|
1883
|
+
the one number it owns rather than bending the style's scale. */
|
|
1884
|
+
.vgai-viewport-navigation {
|
|
1885
|
+
--vgai-control-compact-height: 28px;
|
|
1886
|
+
--vgai-control-default-height: 28px;
|
|
1887
|
+
--vgai-control-comfortable-height: 28px;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
/* THE GLYPH INK IS 203, MEASURED (2026-09-19, `modeling-edit-none.png`,
|
|
1891
|
+
device x 2774..2805 across all four buttons): mode 203, max 204. Ours
|
|
1892
|
+
inked 194 because the cluster's buttons are `ghost`, and
|
|
1893
|
+
`.vgai-btn[data-variant="ghost"]` paints `content.muted` — which is the
|
|
1894
|
+
TREE ROW TEXT colour. The palette's own record already says that is the
|
|
1895
|
+
wrong family here: `category.tool`'s docblock (`theme.ts`, the derivation
|
|
1896
|
+
from the Properties rail's inactive `#a8a8a8`) states that Blender's
|
|
1897
|
+
hue-less ICON ink is LIGHTER than its row text, and lands on `#cbcbcb`
|
|
1898
|
+
— 203, this exact value, reached from a different frame by a different
|
|
1899
|
+
method. That agreement is what makes 203 a measured Blender ink rather
|
|
1900
|
+
than a number tuned here, and it is also a CORRECTION to the palette
|
|
1901
|
+
settlement's note that 203 is "nine levels from an existing member": the
|
|
1902
|
+
value is not nine levels from one, it IS one.
|
|
1903
|
+
NOT read from `category.tool` and NOT minted. Reading a category tint
|
|
1904
|
+
here would couple a datablock's colour to chrome glyphs — re-tinting the
|
|
1905
|
+
tool category would move these five. Minting costs three homes for one
|
|
1906
|
+
site, which is the refusal the ruler tick's 127 already took. So it is an
|
|
1907
|
+
ALPHA AT THE SITE, which is what the settlement ruled: `content.primary`
|
|
1908
|
+
(229) over this cluster's own plate.
|
|
1909
|
+
THE ARITHMETIC, and its one dependency: the plate composites to 48.6
|
|
1910
|
+
(`island-surface` = `surface-panel` #2f2f2f at 0.9 over the viewport's
|
|
1911
|
+
#3f3f3f), and 0.8556·229 + 0.1444·48.6 = 202.95 -> 203. It is robust to
|
|
1912
|
+
what the viewport paints underneath — over a grid line at 90 the plate
|
|
1913
|
+
reads 51.3 and the glyph still lands 203.3 -> 203 — but NOT to the plate
|
|
1914
|
+
itself moving.
|
|
1915
|
+
THE PLATE ITSELF, RE-MEASURED 2026-09-19, AND THE REFUSAL THAT STOOD HERE
|
|
1916
|
+
WAS WRONG ON BOTH COUNTS. It said Blender's plate is an opaque `#363636`
|
|
1917
|
+
and that "no alpha closes it, 54 has no derivation from a declared
|
|
1918
|
+
member". BLENDER'S PLATE IS TRANSLUCENT: a viewport grid line runs
|
|
1919
|
+
straight through it on `modeling-edit-none.png`, entering the capsule at
|
|
1920
|
+
its left border and leaving at its right, dimmed but unbroken — 54 is a
|
|
1921
|
+
COMPOSITE, not a colour. Two backdrops separate the two, which is the
|
|
1922
|
+
method the Outliner plate and the widget emboss were settled by:
|
|
1923
|
+
* `sculpting.png` has NO grid — 6,032 px of a pure 63 outside the
|
|
1924
|
+
capsule and 3,302 px of a pure 54 inside it.
|
|
1925
|
+
* `modeling-edit-none.png`: a line whose core reads 84-85 outside
|
|
1926
|
+
reads a flat 71 inside, on three independent columns and two
|
|
1927
|
+
crossings. Integrated line MASS (coverage-free) gives 0.794, the
|
|
1928
|
+
peak excess 17/21 = 0.810 — so (1-alpha) is 0.75..0.81.
|
|
1929
|
+
* `modeling-front-ortho.png` is the independent check: one faint line,
|
|
1930
|
+
core 79 outside, 66 inside — ratio 0.75.
|
|
1931
|
+
So the plate is a NEAR-BLACK at alpha ~0.21 (+/-0.03), and 54 = a·P +
|
|
1932
|
+
(1-a)·63 puts P in 16..27. THREE declared members sit in that band, and
|
|
1933
|
+
the measurement cannot separate them — the ROLE does: a plate is a
|
|
1934
|
+
SURFACE, so it is `surface.shell` `#171717` (23), the value Blender's own
|
|
1935
|
+
top bar and status band already take, at alpha 9/40 = 0.225. That
|
|
1936
|
+
reproduces 54 over the viewport EXACTLY and predicts both line cores
|
|
1937
|
+
within one 8-bit level (84 -> 70.3 against 71; 79 -> 66.4 against 66).
|
|
1938
|
+
WHAT THE PRIOR SLOPE OF 0.090 WAS: pairing an outside pixel with an
|
|
1939
|
+
inside pixel at the SAME ROW, across a border crossed by DIAGONAL lines.
|
|
1940
|
+
The two samples are then uncorrelated and a regression's slope collapses
|
|
1941
|
+
toward zero, which is the shape of 0.090 against the 0.79 two
|
|
1942
|
+
independent coverage-free estimators give here.
|
|
1943
|
+
IT IS STILL NOT TAKEN, and the reason is the SITE rather than the value.
|
|
1944
|
+
This rule cannot be gated to one palette (see below), and what it would
|
|
1945
|
+
have to say ungated — "a navigation island is the SHELL at 22.5%" — is a
|
|
1946
|
+
Blender measurement that is false elsewhere: driven to Classic and
|
|
1947
|
+
measured, its cluster plate reads 39 against the same 63 viewport, and
|
|
1948
|
+
shell-at-0.225 would put it at 54.7, dropping its separation from the
|
|
1949
|
+
stage from 24 levels to 8. The knob that could carry it is a per-look
|
|
1950
|
+
ISLAND SURFACE — `--vgai-island-surface` is emitted by `theme.ts`'s
|
|
1951
|
+
`islandSurfaceValue`, which branches on the MATERIAL and hardcodes
|
|
1952
|
+
`surface-panel at 90%` for every non-glass look — and giving a material
|
|
1953
|
+
or palette its own island recipe is a new noun, which is a decision, not
|
|
1954
|
+
a rule here. When it is taken, this alpha becomes 0.8514
|
|
1955
|
+
(229a + 54(1-a) = 203).
|
|
1956
|
+
TWO SELECTOR STEPS PAST THE GHOST RULE, and that is the bought lesson:
|
|
1957
|
+
the ghost rule is (0,2,0) and lives in this same file, so a single-class
|
|
1958
|
+
rule here would be a coin toss on source order.
|
|
1959
|
+
UNGATED, AND I TRIED TO GATE IT FIRST. A `[data-vgai-palette="blender"]`
|
|
1960
|
+
scope was written, and `validate-style-tokens`' `css-style-identity-
|
|
1961
|
+
selector` refused it by name — CSS may not branch on which palette is
|
|
1962
|
+
installed, because that makes every new palette a source edit. The gate
|
|
1963
|
+
is right and the refusal is load-bearing here: it means a
|
|
1964
|
+
palette-measured ALPHA cannot be kept to its own palette at all, which
|
|
1965
|
+
is a CORRECTION to the settlement's note that this value is "closable as
|
|
1966
|
+
an alpha at the site". At the site, yes; at the site FOR ONE PALETTE, no.
|
|
1967
|
+
So this rule joins the block above it on the same standing footing: the
|
|
1968
|
+
cluster's 28 and 16 are Blender's numbers for every skin already, stated
|
|
1969
|
+
there with no palette selector. What it says for a non-Blender skin is
|
|
1970
|
+
true of every skin — this glyph is an ICON, so it takes the primary ink
|
|
1971
|
+
softened onto its own plate, not `content.muted`, which is the TREE ROW
|
|
1972
|
+
TEXT role. `content.primary` is the readable ink in every palette and the
|
|
1973
|
+
mix only moves it toward the plate it sits on, so no skin can lose
|
|
1974
|
+
contrast by it. Classic cold-booted and read after. */
|
|
1975
|
+
.vgai-viewport-navigation .vgai-btn[data-variant="ghost"] {
|
|
1976
|
+
color: color-mix(in srgb, var(--vgai-content-primary) 85.56%, transparent);
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
[data-vgai-chrome="islands"] .vgai-chrome-island:not(:empty) {
|
|
1980
|
+
position: relative;
|
|
1981
|
+
border: var(--vgai-stroke-resting) solid
|
|
1982
|
+
var(--vgai-island-border-color, var(--vgai-boundary-strong));
|
|
1983
|
+
border-radius: var(--vgai-island-radius, var(--vgai-radius-md));
|
|
1984
|
+
background:
|
|
1985
|
+
var(--vgai-ambient-lift, none), var(--vgai-backdrop-dim, none),
|
|
1986
|
+
var(--vgai-island-surface, color-mix(in srgb, var(--vgai-surface-panel) 90%, transparent));
|
|
1987
|
+
box-shadow: var(--vgai-island-shadow, var(--vgai-shadow-sm));
|
|
1988
|
+
backdrop-filter: var(--vgai-island-backdrop-filter, blur(8px));
|
|
1989
|
+
-webkit-backdrop-filter: var(--vgai-island-backdrop-filter, blur(8px));
|
|
1990
|
+
text-shadow: var(--vgai-content-text-shadow, none);
|
|
1991
|
+
box-sizing: border-box;
|
|
1992
|
+
pointer-events: auto;
|
|
1993
|
+
}
|
|
1994
|
+
/* Same specular rim as .vgai-floating-toolbar::before. Keep decorative
|
|
1995
|
+
paint beneath interactive island children so it can never own a hit. */
|
|
1996
|
+
[data-vgai-chrome="islands"] .vgai-chrome-island:not(:empty)::before {
|
|
1997
|
+
content: "";
|
|
1998
|
+
position: absolute;
|
|
1999
|
+
inset: 0;
|
|
2000
|
+
z-index: 0;
|
|
2001
|
+
padding: 1px;
|
|
2002
|
+
border-radius: inherit;
|
|
2003
|
+
background: var(--vgai-island-specular-ring, none);
|
|
2004
|
+
-webkit-mask:
|
|
2005
|
+
linear-gradient(#000 0 0) content-box,
|
|
2006
|
+
linear-gradient(#000 0 0);
|
|
2007
|
+
-webkit-mask-composite: xor;
|
|
2008
|
+
mask:
|
|
2009
|
+
linear-gradient(#000 0 0) content-box exclude,
|
|
2010
|
+
linear-gradient(#000 0 0);
|
|
2011
|
+
pointer-events: none;
|
|
2012
|
+
}
|
|
2013
|
+
[data-vgai-chrome="islands"] .vgai-chrome-island:not(:empty) > * {
|
|
2014
|
+
position: relative;
|
|
2015
|
+
z-index: 1;
|
|
2016
|
+
}
|
|
2017
|
+
/* Size hierarchy (design-review item 2): small chrome must not wear
|
|
2018
|
+
big-chrome weight. Compact islands — the tray button and any other
|
|
2019
|
+
small single-control island — get a quieter rim, a smaller shadow, and
|
|
2020
|
+
a tighter radius than the full clusters/toolbars. */
|
|
2021
|
+
[data-vgai-chrome="islands"] .vgai-chrome-island[data-island-scale="compact"]:not(:empty) {
|
|
2022
|
+
border-radius: 12px;
|
|
2023
|
+
box-shadow: var(--vgai-shadow-sm);
|
|
2024
|
+
}
|
|
2025
|
+
[data-vgai-chrome="islands"] .vgai-chrome-island[data-island-scale="compact"]:not(:empty)::before {
|
|
2026
|
+
opacity: 0.55;
|
|
2027
|
+
}
|
|
2028
|
+
/* HUD islands (P6-U6): component-specific corrections the shared island
|
|
2029
|
+
material must not clobber. The camera pill is a READOUT — it must never
|
|
2030
|
+
start intercepting viewport pointers just because it became an island;
|
|
2031
|
+
the profiler chip's enabled state keeps its accent border signal. */
|
|
2032
|
+
[data-vgai-chrome="islands"] .vgai-camera-info.vgai-chrome-island:not(:empty),
|
|
2033
|
+
[data-vgai-chrome="islands"] .vgai-viewport-controls-hint.vgai-chrome-island:not(:empty) {
|
|
2034
|
+
pointer-events: none;
|
|
2035
|
+
}
|
|
2036
|
+
[data-vgai-chrome="islands"]
|
|
2037
|
+
.vgai-performance-overlay.vgai-chrome-island[data-enabled="true"]:not(:empty) {
|
|
2038
|
+
border-color: var(--vgai-accent);
|
|
2039
|
+
}
|
|
2040
|
+
/* Concentricity (owner design review, canonical HIG rule): highlights
|
|
2041
|
+
nested inside pill chrome follow the pill — capsule hover/active chips,
|
|
2042
|
+
not the flat design's small-radius rectangles. Var resolves to
|
|
2043
|
+
radius-full only for treatment themes; opaque themes keep radius-sm. */
|
|
2044
|
+
[data-vgai-chrome="islands"] .vgai-chrome-island .vgai-btn,
|
|
2045
|
+
.vgai-floating-toolbar .vgai-btn {
|
|
2046
|
+
border-radius: var(--vgai-island-control-radius, var(--vgai-radius-sm));
|
|
2047
|
+
}
|
|
2048
|
+
/* Singleton toolbar buttons ARE their own capsules (unrelated actions
|
|
2049
|
+
never share a glass tray — grouping is by relatedness, per the HIG). The
|
|
2050
|
+
one prominent action wears the tinted-glass capsule: accent as a
|
|
2051
|
+
translucent tint over the blur, never an opaque painted slab. */
|
|
2052
|
+
[data-vgai-chrome="islands"] .vgai-btn.vgai-chrome-island:not(:empty) {
|
|
2053
|
+
border-radius: var(--vgai-island-control-radius, var(--vgai-radius-sm));
|
|
2054
|
+
}
|
|
2055
|
+
[data-vgai-chrome="islands"] .vgai-btn.vgai-chrome-island[data-variant="primary"]:not(:empty) {
|
|
2056
|
+
background: var(--vgai-island-primary-bg, var(--vgai-accent));
|
|
2057
|
+
}
|
|
2058
|
+
.vgai-split-button {
|
|
2059
|
+
display: inline-flex;
|
|
2060
|
+
min-width: 0;
|
|
2061
|
+
align-items: stretch;
|
|
2062
|
+
}
|
|
2063
|
+
/* A SPLIT IS ONE WELL WITH ONE DIVIDER, and reaching the halves takes both
|
|
2064
|
+
shapes: `Tooltip` renders a `span.vgai-tooltip-anchor` AROUND its child, so
|
|
2065
|
+
`> .vgai-btn` silently matched nothing for every split whose halves carry
|
|
2066
|
+
tooltips — which is all of them but one. Measured 2026-09-18 through
|
|
2067
|
+
`editor.document.query` on the viewport header's snap group: the two halves
|
|
2068
|
+
each kept a full 1px border (2px of seam) and both kept their outer radii,
|
|
2069
|
+
where Blender's split shares ONE 1px #3c3c3c divider (native 2x
|
|
2070
|
+
`modeling.png` row y=62, x 1446..1447 between the magnet at #535353 and the
|
|
2071
|
+
snap dropdown at #272727). The tooltip anchor is `position: relative;
|
|
2072
|
+
display: inline-flex` and carries no paint of its own, so only the button
|
|
2073
|
+
inside it needs the rule. */
|
|
2074
|
+
.vgai-split-button > .vgai-btn:first-child,
|
|
2075
|
+
.vgai-split-button > :first-child > .vgai-btn {
|
|
2076
|
+
border-top-right-radius: 0;
|
|
2077
|
+
border-bottom-right-radius: 0;
|
|
2078
|
+
}
|
|
2079
|
+
.vgai-split-button > .vgai-btn + .vgai-btn,
|
|
2080
|
+
.vgai-split-button > * + .vgai-btn,
|
|
2081
|
+
.vgai-split-button > * + * > .vgai-btn {
|
|
2082
|
+
min-width: 20px;
|
|
2083
|
+
padding-inline: var(--vgai-space-1);
|
|
2084
|
+
border-left: 0;
|
|
2085
|
+
border-top-left-radius: 0;
|
|
2086
|
+
border-bottom-left-radius: 0;
|
|
2087
|
+
}
|
|
2088
|
+
.vgai-keycap {
|
|
2089
|
+
padding: 1px var(--vgai-space-2);
|
|
2090
|
+
color: var(--vgai-content-primary);
|
|
2091
|
+
background: var(--vgai-surface-raised);
|
|
2092
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
2093
|
+
border-radius: var(--vgai-radius-sm);
|
|
2094
|
+
font-family: var(--vgai-font-mono);
|
|
2095
|
+
font-size: var(--vgai-font-sm);
|
|
2096
|
+
}
|
|
2097
|
+
.vgai-viewport-toolbar {
|
|
2098
|
+
position: absolute;
|
|
2099
|
+
top: var(--vgai-viewport-overlay-top, var(--vgai-space-4));
|
|
2100
|
+
/* The full-canvas selection hit layer is z50. Keep viewport controls in
|
|
2101
|
+
the upper overlay band below menus (1000) but decisively above every
|
|
2102
|
+
canvas-local interaction surface, including nested stacking contexts. */
|
|
2103
|
+
z-index: calc(var(--vgai-z-dropdown, 1000) - 1);
|
|
2104
|
+
isolation: isolate;
|
|
2105
|
+
}
|
|
2106
|
+
.vgai-viewport-toolbar-left {
|
|
2107
|
+
left: var(--vgai-space-4);
|
|
2108
|
+
}
|
|
2109
|
+
.vgai-viewport-toolbar-right {
|
|
2110
|
+
right: var(--vgai-space-4);
|
|
2111
|
+
}
|
|
2112
|
+
/* U6.5 F1 — header-island clearance for viewport-overlay chrome. Under
|
|
2113
|
+
islands chrome over a BACKDROP document the header row is a
|
|
2114
|
+
position:absolute overlay (ProjectHeader.css full-bleed rule) and the
|
|
2115
|
+
dock runs edge-to-edge beneath it, so the viewport's own top-anchored
|
|
2116
|
+
chrome at viewport-local 8px sits exactly under the header islands band
|
|
2117
|
+
(y 8–46): the left toolstrip under the cluster island, the right
|
|
2118
|
+
view-controls under Export/Account — the stats toggle was 100%
|
|
2119
|
+
pointer-intercepted by the Account pill (the U6.5-FEED "Account ghost").
|
|
2120
|
+
Two inherited offsets move ALL of it below the 48px band instead:
|
|
2121
|
+
- `--vgai-viewport-overlay-top`: the toolbar rows' top — 48 + 8 = 56px.
|
|
2122
|
+
- `--vgai-viewport-overlay-hud-top`: the second HUD tier (stats /
|
|
2123
|
+
network readouts, StatsOverlay.tsx / NetworkInspectorPanel.tsx) — toolbar
|
|
2124
|
+
bottom (56 + 38) + the 8px breathing band (P2-18) = 102px.
|
|
2125
|
+
Under islands (glass) chrome the HUD tier gets the 8px breathing band:
|
|
2126
|
+
54px = toolbar bottom 46 + 8px (P2-18 — it had decayed to 2px). A BACKDROP
|
|
2127
|
+
document pushes it further to 102px for the header-island clearance.
|
|
2128
|
+
Treatment-less "bars" chrome (graphite/classic/lite/reduced) leaves the var
|
|
2129
|
+
UNSET so the components' bare 48px fallback applies — pixel-identical to
|
|
2130
|
+
pre-glass main (the degrade-ladder invariant). */
|
|
2131
|
+
[data-vgai-chrome="islands"] {
|
|
2132
|
+
--vgai-viewport-overlay-hud-top: 54px;
|
|
2133
|
+
}
|
|
2134
|
+
[data-vgai-chrome="islands"] .vgai-editor-shell:has(.vgai-workspace-dock[data-vgai-backdrop]) {
|
|
2135
|
+
--vgai-viewport-overlay-top: 56px;
|
|
2136
|
+
--vgai-viewport-overlay-hud-top: 102px;
|
|
2137
|
+
}
|
|
2138
|
+
.vgai-viewport-popover-anchor {
|
|
2139
|
+
position: relative;
|
|
2140
|
+
display: inline-flex;
|
|
2141
|
+
align-items: center;
|
|
2142
|
+
}
|
|
2143
|
+
.vgai-snap-popover {
|
|
2144
|
+
position: absolute;
|
|
2145
|
+
top: calc(100% + var(--vgai-space-2));
|
|
2146
|
+
left: 0;
|
|
2147
|
+
z-index: var(--vgai-z-dropdown);
|
|
2148
|
+
width: 170px;
|
|
2149
|
+
padding: var(--vgai-space-4);
|
|
2150
|
+
}
|
|
2151
|
+
.vgai-helpers-menu {
|
|
2152
|
+
position: absolute;
|
|
2153
|
+
top: calc(100% + var(--vgai-space-2));
|
|
2154
|
+
right: 0;
|
|
2155
|
+
z-index: var(--vgai-z-dropdown);
|
|
2156
|
+
min-width: 140px;
|
|
2157
|
+
}
|
|
2158
|
+
.vgai-menu-check {
|
|
2159
|
+
display: inline-flex;
|
|
2160
|
+
width: 14px;
|
|
2161
|
+
flex: 0 0 auto;
|
|
2162
|
+
justify-content: center;
|
|
2163
|
+
margin-right: var(--vgai-space-2);
|
|
2164
|
+
}
|
|
2165
|
+
.vgai-selectable {
|
|
2166
|
+
transition:
|
|
2167
|
+
background-color 0.12s var(--vgai-ease-standard),
|
|
2168
|
+
border-color 0.12s var(--vgai-ease-standard),
|
|
2169
|
+
color 0.12s var(--vgai-ease-standard);
|
|
2170
|
+
}
|
|
2171
|
+
.vgai-selectable:hover {
|
|
2172
|
+
background: var(--vgai-neutral-hover);
|
|
2173
|
+
}
|
|
2174
|
+
.vgai-selectable[data-selected="true"] {
|
|
2175
|
+
background: var(--vgai-selection-bg);
|
|
2176
|
+
}
|
|
2177
|
+
.vgai-list-button {
|
|
2178
|
+
display: block;
|
|
2179
|
+
width: 100%;
|
|
2180
|
+
min-width: 0;
|
|
2181
|
+
border: 0;
|
|
2182
|
+
border-left: var(--vgai-stroke-active) solid transparent;
|
|
2183
|
+
background: transparent;
|
|
2184
|
+
color: var(--vgai-content-muted);
|
|
2185
|
+
padding: var(--vgai-space-3) var(--vgai-space-4);
|
|
2186
|
+
text-align: left;
|
|
2187
|
+
font: inherit;
|
|
2188
|
+
cursor: pointer;
|
|
2189
|
+
box-sizing: border-box;
|
|
2190
|
+
}
|
|
2191
|
+
.vgai-list-button:hover {
|
|
2192
|
+
color: var(--vgai-content-primary);
|
|
2193
|
+
background: var(--vgai-neutral-hover);
|
|
2194
|
+
}
|
|
2195
|
+
.vgai-list-button[data-selected="true"] {
|
|
2196
|
+
color: var(--vgai-content-primary);
|
|
2197
|
+
background: var(--vgai-selection-bg);
|
|
2198
|
+
}
|
|
2199
|
+
.vgai-list-button[data-selected="true"][data-accent="bar"] {
|
|
2200
|
+
border-left-color: var(--vgai-selection-indicator);
|
|
2201
|
+
}
|
|
2202
|
+
.vgai-list-button:disabled {
|
|
2203
|
+
opacity: 0.5;
|
|
2204
|
+
cursor: default;
|
|
2205
|
+
}
|
|
2206
|
+
.vgai-list-button:focus-visible {
|
|
2207
|
+
outline: var(--vgai-focus-ring);
|
|
2208
|
+
outline-offset: -2px;
|
|
2209
|
+
}
|
|
2210
|
+
.vgai-playbar {
|
|
2211
|
+
pointer-events: auto;
|
|
2212
|
+
}
|
|
2213
|
+
.vgai-play-edit-regime {
|
|
2214
|
+
display: inline-flex;
|
|
2215
|
+
width: var(--vgai-control-compact-height);
|
|
2216
|
+
height: var(--vgai-control-compact-height);
|
|
2217
|
+
align-items: center;
|
|
2218
|
+
justify-content: center;
|
|
2219
|
+
color: var(--vgai-warn);
|
|
2220
|
+
}
|
|
2221
|
+
.vgai-play-edit-regime[data-regime="overlay"] {
|
|
2222
|
+
color: var(--vgai-success);
|
|
2223
|
+
}
|
|
2224
|
+
.vgai-playbar-popover-anchor {
|
|
2225
|
+
position: relative;
|
|
2226
|
+
}
|
|
2227
|
+
.vgai-resolution-menu {
|
|
2228
|
+
z-index: var(--vgai-z-dropdown);
|
|
2229
|
+
min-width: 220px;
|
|
2230
|
+
}
|
|
2231
|
+
.vgai-resolution-menu [aria-checked="true"] {
|
|
2232
|
+
color: var(--vgai-content-primary);
|
|
2233
|
+
background: var(--vgai-selection-bg);
|
|
2234
|
+
}
|
|
2235
|
+
.vgai-camera-info,
|
|
2236
|
+
.vgai-viewport-controls-hint {
|
|
2237
|
+
position: absolute;
|
|
2238
|
+
/* Bottom-LEFT: the bottom-right corner belongs to the compact inspector
|
|
2239
|
+
card (owner, 2026-08-07 — the readout was sitting underneath it). */
|
|
2240
|
+
left: var(--vgai-space-4);
|
|
2241
|
+
bottom: var(--vgai-space-4);
|
|
2242
|
+
padding: var(--vgai-space-2) var(--vgai-space-3);
|
|
2243
|
+
border-radius: var(--vgai-radius-md);
|
|
2244
|
+
backdrop-filter: blur(8px);
|
|
2245
|
+
pointer-events: none;
|
|
2246
|
+
}
|
|
2247
|
+
.vgai-camera-preview {
|
|
2248
|
+
position: absolute;
|
|
2249
|
+
z-index: calc(var(--vgai-z-dropdown, 1000) - 2);
|
|
2250
|
+
left: var(--vgai-space-4);
|
|
2251
|
+
bottom: 52px;
|
|
2252
|
+
width: clamp(220px, 26vw, 360px);
|
|
2253
|
+
max-width: calc(100% - var(--vgai-space-8));
|
|
2254
|
+
overflow: visible;
|
|
2255
|
+
border-radius: var(--vgai-radius-md);
|
|
2256
|
+
background: transparent;
|
|
2257
|
+
box-shadow: var(--vgai-shadow-md);
|
|
2258
|
+
}
|
|
2259
|
+
.vgai-camera-preview-header {
|
|
2260
|
+
min-height: 28px;
|
|
2261
|
+
flex-wrap: nowrap;
|
|
2262
|
+
padding: 0 var(--vgai-space-2);
|
|
2263
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
2264
|
+
border-bottom: 0;
|
|
2265
|
+
border-radius: var(--vgai-radius-md) var(--vgai-radius-md) 0 0;
|
|
2266
|
+
background: var(--vgai-surface-overlay);
|
|
2267
|
+
backdrop-filter: blur(12px);
|
|
2268
|
+
}
|
|
2269
|
+
.vgai-camera-preview-title {
|
|
2270
|
+
min-width: 0;
|
|
2271
|
+
flex: 1;
|
|
2272
|
+
}
|
|
2273
|
+
.vgai-camera-preview-image {
|
|
2274
|
+
width: 100%;
|
|
2275
|
+
min-height: 120px;
|
|
2276
|
+
overflow: hidden;
|
|
2277
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-default);
|
|
2278
|
+
border-top: 0;
|
|
2279
|
+
border-radius: 0 0 var(--vgai-radius-md) var(--vgai-radius-md);
|
|
2280
|
+
cursor: zoom-in;
|
|
2281
|
+
}
|
|
2282
|
+
.vgai-camera-preview-menu-anchor {
|
|
2283
|
+
position: relative;
|
|
2284
|
+
display: flex;
|
|
2285
|
+
}
|
|
2286
|
+
.vgai-camera-preview-menu {
|
|
2287
|
+
position: absolute;
|
|
2288
|
+
z-index: var(--vgai-z-dropdown);
|
|
2289
|
+
top: calc(100% + var(--vgai-space-1));
|
|
2290
|
+
right: 0;
|
|
2291
|
+
display: grid;
|
|
2292
|
+
width: max-content;
|
|
2293
|
+
min-width: 210px;
|
|
2294
|
+
padding: var(--vgai-space-1);
|
|
2295
|
+
}
|
|
2296
|
+
.vgai-camera-preview-menu .vgai-btn {
|
|
2297
|
+
justify-content: flex-start;
|
|
2298
|
+
}
|
|
2299
|
+
.vgai-camera-view-banner {
|
|
2300
|
+
position: absolute;
|
|
2301
|
+
z-index: calc(var(--vgai-z-dropdown, 1000) - 1);
|
|
2302
|
+
top: var(--vgai-viewport-overlay-top, var(--vgai-space-4));
|
|
2303
|
+
left: 50%;
|
|
2304
|
+
max-width: calc(100% - 520px);
|
|
2305
|
+
padding: var(--vgai-space-1) var(--vgai-space-2);
|
|
2306
|
+
border-radius: var(--vgai-radius-full);
|
|
2307
|
+
transform: translateX(-50%);
|
|
2308
|
+
backdrop-filter: blur(12px);
|
|
2309
|
+
}
|
|
2310
|
+
.vgai-camera-guides {
|
|
2311
|
+
position: absolute;
|
|
2312
|
+
z-index: calc(var(--vgai-z-sticky, 100) - 1);
|
|
2313
|
+
inset: 0;
|
|
2314
|
+
overflow: hidden;
|
|
2315
|
+
pointer-events: none;
|
|
2316
|
+
}
|
|
2317
|
+
.vgai-camera-guide {
|
|
2318
|
+
position: absolute;
|
|
2319
|
+
background: color-mix(in srgb, var(--vgai-content-primary) 40%, transparent);
|
|
2320
|
+
box-shadow: 0 0 1px color-mix(in srgb, var(--vgai-surface-shell) 70%, transparent);
|
|
2321
|
+
}
|
|
2322
|
+
.vgai-camera-guide-v1,
|
|
2323
|
+
.vgai-camera-guide-v2 {
|
|
2324
|
+
top: 0;
|
|
2325
|
+
bottom: 0;
|
|
2326
|
+
width: 1px;
|
|
2327
|
+
}
|
|
2328
|
+
.vgai-camera-guide-v1 {
|
|
2329
|
+
left: 33.333%;
|
|
2330
|
+
}
|
|
2331
|
+
.vgai-camera-guide-v2 {
|
|
2332
|
+
left: 66.666%;
|
|
2333
|
+
}
|
|
2334
|
+
.vgai-camera-guide-h1,
|
|
2335
|
+
.vgai-camera-guide-h2 {
|
|
2336
|
+
right: 0;
|
|
2337
|
+
left: 0;
|
|
2338
|
+
height: 1px;
|
|
2339
|
+
}
|
|
2340
|
+
.vgai-camera-guide-h1 {
|
|
2341
|
+
top: 33.333%;
|
|
2342
|
+
}
|
|
2343
|
+
.vgai-camera-guide-h2 {
|
|
2344
|
+
top: 66.666%;
|
|
2345
|
+
}
|
|
2346
|
+
.vgai-camera-safe-frame {
|
|
2347
|
+
position: absolute;
|
|
2348
|
+
inset: 6%;
|
|
2349
|
+
border: 1px solid color-mix(in srgb, var(--vgai-content-primary) 48%, transparent);
|
|
2350
|
+
}
|
|
2351
|
+
.vgai-camera-center-mark {
|
|
2352
|
+
position: absolute;
|
|
2353
|
+
top: 50%;
|
|
2354
|
+
left: 50%;
|
|
2355
|
+
width: 18px;
|
|
2356
|
+
height: 18px;
|
|
2357
|
+
transform: translate(-50%, -50%);
|
|
2358
|
+
}
|
|
2359
|
+
.vgai-camera-center-mark::before,
|
|
2360
|
+
.vgai-camera-center-mark::after {
|
|
2361
|
+
position: absolute;
|
|
2362
|
+
background: color-mix(in srgb, var(--vgai-content-primary) 60%, transparent);
|
|
2363
|
+
content: "";
|
|
2364
|
+
}
|
|
2365
|
+
.vgai-camera-center-mark::before {
|
|
2366
|
+
top: 8px;
|
|
2367
|
+
left: 0;
|
|
2368
|
+
width: 18px;
|
|
2369
|
+
height: 1px;
|
|
2370
|
+
}
|
|
2371
|
+
.vgai-camera-center-mark::after {
|
|
2372
|
+
top: 0;
|
|
2373
|
+
left: 8px;
|
|
2374
|
+
width: 1px;
|
|
2375
|
+
height: 18px;
|
|
2376
|
+
}
|
|
2377
|
+
@media (max-width: 900px) {
|
|
2378
|
+
.vgai-camera-view-banner {
|
|
2379
|
+
top: calc(var(--vgai-viewport-overlay-top, var(--vgai-space-4)) + 44px);
|
|
2380
|
+
max-width: calc(100% - var(--vgai-space-8));
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
.vgai-react-canvas-controls {
|
|
2384
|
+
position: absolute;
|
|
2385
|
+
right: var(--vgai-space-6);
|
|
2386
|
+
bottom: var(--vgai-space-6);
|
|
2387
|
+
z-index: var(--vgai-z-sticky);
|
|
2388
|
+
overflow: visible;
|
|
2389
|
+
}
|
|
2390
|
+
.vgai-canvas-scene-navigation {
|
|
2391
|
+
position: absolute;
|
|
2392
|
+
top: calc(var(--vgai-viewport-overlay-top, var(--vgai-space-4)) + 44px);
|
|
2393
|
+
left: var(--vgai-space-4);
|
|
2394
|
+
z-index: calc(var(--vgai-z-dropdown, 1000) - 1);
|
|
2395
|
+
overflow: visible;
|
|
2396
|
+
}
|
|
2397
|
+
.vgai-react-viewport-select {
|
|
2398
|
+
border-color: transparent;
|
|
2399
|
+
background-color: transparent;
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
.vgai-tabs {
|
|
2403
|
+
display: flex;
|
|
2404
|
+
height: var(--vgai-panel-header-height);
|
|
2405
|
+
min-width: 0;
|
|
2406
|
+
align-items: stretch;
|
|
2407
|
+
gap: var(--vgai-space-1);
|
|
2408
|
+
padding-inline: var(--vgai-space-2);
|
|
2409
|
+
overflow: hidden;
|
|
2410
|
+
background: var(--vgai-surface-sticky);
|
|
2411
|
+
border-bottom: var(--vgai-stroke-resting) solid var(--vgai-structural-divider);
|
|
2412
|
+
}
|
|
2413
|
+
.vgai-tab {
|
|
2414
|
+
position: relative;
|
|
2415
|
+
display: inline-flex;
|
|
2416
|
+
min-width: 0;
|
|
2417
|
+
max-width: 220px;
|
|
2418
|
+
align-items: center;
|
|
2419
|
+
gap: var(--vgai-space-2);
|
|
2420
|
+
padding: 0 var(--vgai-space-4);
|
|
2421
|
+
color: var(--vgai-content-muted);
|
|
2422
|
+
background: transparent;
|
|
2423
|
+
border: 0;
|
|
2424
|
+
font: inherit;
|
|
2425
|
+
cursor: pointer;
|
|
2426
|
+
}
|
|
2427
|
+
.vgai-tab:hover {
|
|
2428
|
+
color: var(--vgai-content-primary);
|
|
2429
|
+
background: var(--vgai-surface-raised);
|
|
2430
|
+
}
|
|
2431
|
+
.vgai-tab[data-selected="true"] {
|
|
2432
|
+
color: var(--vgai-content-primary);
|
|
2433
|
+
/* The active tab wears the panel it opens (Blender's tabs are filled
|
|
2434
|
+
slabs); the indicator below stays for the skins that read it. */
|
|
2435
|
+
background: var(--vgai-surface-panel);
|
|
2436
|
+
}
|
|
2437
|
+
.vgai-tab[data-selected="true"]::after {
|
|
2438
|
+
position: absolute;
|
|
2439
|
+
right: var(--vgai-space-4);
|
|
2440
|
+
bottom: 0;
|
|
2441
|
+
left: var(--vgai-space-4);
|
|
2442
|
+
height: var(--vgai-stroke-active);
|
|
2443
|
+
border-radius: 2px 2px 0 0;
|
|
2444
|
+
background: var(--vgai-selection-indicator);
|
|
2445
|
+
content: "";
|
|
2446
|
+
}
|
|
2447
|
+
.vgai-tab:focus-visible {
|
|
2448
|
+
outline: var(--vgai-focus-ring);
|
|
2449
|
+
outline-offset: -2px;
|
|
2450
|
+
}
|
|
2451
|
+
.vgai-tab-label {
|
|
2452
|
+
overflow: hidden;
|
|
2453
|
+
text-overflow: ellipsis;
|
|
2454
|
+
white-space: nowrap;
|
|
2455
|
+
}
|
|
2456
|
+
.vgai-tab-dirty {
|
|
2457
|
+
width: 6px;
|
|
2458
|
+
height: 6px;
|
|
2459
|
+
flex: 0 0 auto;
|
|
2460
|
+
border-radius: var(--vgai-radius-full);
|
|
2461
|
+
background: var(--vgai-warn);
|
|
2462
|
+
}
|
|
2463
|
+
.vgai-tab-badge {
|
|
2464
|
+
display: inline-flex;
|
|
2465
|
+
width: max-content;
|
|
2466
|
+
max-width: 100%;
|
|
2467
|
+
min-width: 15px;
|
|
2468
|
+
height: 15px;
|
|
2469
|
+
align-items: center;
|
|
2470
|
+
justify-content: center;
|
|
2471
|
+
/* space-2, not space-1: with true half-circle end caps (radius-full is
|
|
2472
|
+
* 9999px, no longer 50%) multi-char content needs breathing room past the
|
|
2473
|
+
* cap curve; border-box + min-width keeps a single digit a perfect circle. */
|
|
2474
|
+
padding: 0 var(--vgai-space-2);
|
|
2475
|
+
border-radius: var(--vgai-radius-full);
|
|
2476
|
+
color: var(--vgai-surface-shell);
|
|
2477
|
+
background: var(--vgai-content-muted);
|
|
2478
|
+
font-size: var(--vgai-font-xs);
|
|
2479
|
+
line-height: var(--vgai-leading-tight);
|
|
2480
|
+
box-sizing: border-box;
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
/* A badge is a compact LABEL by default. The fixed radius and intrinsic,
|
|
2484
|
+
* non-flexing box make multiword content safe: it cannot turn into the long
|
|
2485
|
+
* elliptical capsule produced by border-radius: 50% on a wide rectangle, nor
|
|
2486
|
+
* stretch to fill a grid/flex track. True counters opt into data-shape=count. */
|
|
2487
|
+
.vgai-badge {
|
|
2488
|
+
display: inline-flex;
|
|
2489
|
+
flex: 0 0 auto;
|
|
2490
|
+
align-self: center;
|
|
2491
|
+
width: fit-content;
|
|
2492
|
+
max-width: 100%;
|
|
2493
|
+
min-width: 0;
|
|
2494
|
+
min-height: 18px;
|
|
2495
|
+
align-items: center;
|
|
2496
|
+
justify-content: center;
|
|
2497
|
+
padding: 1px var(--vgai-space-2);
|
|
2498
|
+
overflow: hidden;
|
|
2499
|
+
border-radius: var(--vgai-radius-sm);
|
|
2500
|
+
color: var(--vgai-surface-shell);
|
|
2501
|
+
background: var(--vgai-content-muted);
|
|
2502
|
+
font-size: var(--vgai-font-xs);
|
|
2503
|
+
line-height: var(--vgai-leading-tight);
|
|
2504
|
+
white-space: nowrap;
|
|
2505
|
+
text-overflow: ellipsis;
|
|
2506
|
+
vertical-align: middle;
|
|
2507
|
+
box-sizing: border-box;
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2510
|
+
.vgai-badge[data-shape="count"] {
|
|
2511
|
+
min-width: 15px;
|
|
2512
|
+
min-height: 15px;
|
|
2513
|
+
height: 15px;
|
|
2514
|
+
/* space-2, not space-1: at 2–3 digits the 9999px end-caps eat into a
|
|
2515
|
+
* 2px pad and the glyphs graze the curve (reviewer finding, U0). */
|
|
2516
|
+
padding: 0 var(--vgai-space-2);
|
|
2517
|
+
border-radius: var(--vgai-radius-full);
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
.vgai-tree {
|
|
2521
|
+
min-width: 0;
|
|
2522
|
+
color: var(--vgai-content-primary);
|
|
2523
|
+
}
|
|
2524
|
+
.vgai-tree-row {
|
|
2525
|
+
display: flex;
|
|
2526
|
+
height: var(--vgai-tree-row-height);
|
|
2527
|
+
min-width: 0;
|
|
2528
|
+
align-items: center;
|
|
2529
|
+
gap: var(--vgai-space-2);
|
|
2530
|
+
padding-right: var(--vgai-space-2);
|
|
2531
|
+
color: var(--vgai-content-muted);
|
|
2532
|
+
border-left: var(--vgai-stroke-active) solid transparent;
|
|
2533
|
+
box-sizing: border-box;
|
|
2534
|
+
cursor: default;
|
|
2535
|
+
user-select: none;
|
|
2536
|
+
}
|
|
2537
|
+
/* Blender's outliner alternates rows by a few levels (a three-level step),
|
|
2538
|
+
phased on the row's ABSOLUTE index — `nth-child` counted this virtualized
|
|
2539
|
+
list's leading spacer div as sibling one, so row 0 always drew the alternate
|
|
2540
|
+
and the whole stripe flipped with the scroll window. */
|
|
2541
|
+
.vgai-tree-row[data-row-alt] {
|
|
2542
|
+
background: var(--vgai-surface-row-alt);
|
|
2543
|
+
}
|
|
2544
|
+
/* THE STRIPE BELONGS TO THE BODY, NOT TO THE ROWS — and that one rule is the
|
|
2545
|
+
largest area of the whole frame that differed from Blender.
|
|
2546
|
+
|
|
2547
|
+
MEASURED, `modeling-object-none.png` at native 2x (device y, column
|
|
2548
|
+
x=3300): the Outliner body starts at 100 and Blender stripes it to the
|
|
2549
|
+
bottom edge at a 40 px (20 CSS) pitch — 106..145 #272727, 146..185
|
|
2550
|
+
#2a2a2a, 186..225, 226..265, 266..305 for the five occupied rows, and then
|
|
2551
|
+
306..345 #2a2a2a, 346..385 #272727, 386..409 #2a2a2a with NOTHING IN THEM.
|
|
2552
|
+
Ours painted the occupied rows and stopped: flat 39 for 320 device px,
|
|
2553
|
+
which is why Blender's near-empty Outliner reads as a LIST and ours read
|
|
2554
|
+
as an empty dark box.
|
|
2555
|
+
|
|
2556
|
+
PHASE, measured rather than assumed: the ROOT row (Scene Collection,
|
|
2557
|
+
106..145) takes the panel value and the second row takes the alternate, so
|
|
2558
|
+
the body's parity is exactly the `rowIndex % 2 === 1` the occupied rows
|
|
2559
|
+
already use. The two painters therefore agree by construction; an occupied
|
|
2560
|
+
alternate row paints its own identical fill over this gradient, which is
|
|
2561
|
+
what keeps a region-substituted `--vgai-surface-row-alt` (the workspace host
|
|
2562
|
+
re-emits it per region) correct on both.
|
|
2563
|
+
|
|
2564
|
+
`background-attachment: local` is the whole trick, and it is what makes
|
|
2565
|
+
this the CONTENT's stripe rather than the viewport's: the gradient's origin
|
|
2566
|
+
scrolls with the rows, so the phase holds at any scroll offset and the
|
|
2567
|
+
virtualization spacers need no arithmetic of their own.
|
|
2568
|
+
|
|
2569
|
+
It paints UNDER every row, so the selection band, the active plate and
|
|
2570
|
+
hover all keep winning — each of those is a fill on the row itself.
|
|
2571
|
+
|
|
2572
|
+
SCOPED TO A PAINTED OUTLINER, and that scope is the whole of the gate. The
|
|
2573
|
+
stripe is a shape a reference frame justifies — Blender's Outliner reads as
|
|
2574
|
+
a LIST because it is striped to the bottom edge — so it belongs to the look
|
|
2575
|
+
that measured it and not to a host with none declared (ARCHITECTURE-CORE
|
|
2576
|
+
§The core is the workbench, "Host default versus skew"; Classic's frame is
|
|
2577
|
+
"no zebra"). The condition is the AREA, not a look: `data-vgai-region` is
|
|
2578
|
+
published on the tree body by the panel that IS the Outliner, and only
|
|
2579
|
+
while the installed palette names `color.region.outliner`
|
|
2580
|
+
(`components/GameHierarchy.tsx`, `theme-preference.ts`'s
|
|
2581
|
+
`editorPaintedRegions`). So any palette that paints editor areas gets the
|
|
2582
|
+
stripe and no rule here ever learns a palette's name. The ink stays
|
|
2583
|
+
`--vgai-surface-row-alt`, which every palette derives, so there is still no
|
|
2584
|
+
new theme member and no flag. */
|
|
2585
|
+
.vgai-tree-body[data-vgai-region="outliner"] {
|
|
2586
|
+
background-image: repeating-linear-gradient(
|
|
2587
|
+
to bottom,
|
|
2588
|
+
transparent 0,
|
|
2589
|
+
transparent var(--vgai-tree-row-height),
|
|
2590
|
+
var(--vgai-surface-row-alt) var(--vgai-tree-row-height),
|
|
2591
|
+
var(--vgai-surface-row-alt) calc(var(--vgai-tree-row-height) * 2)
|
|
2592
|
+
);
|
|
2593
|
+
background-attachment: local;
|
|
2594
|
+
}
|
|
2595
|
+
.vgai-tree-row:hover {
|
|
2596
|
+
color: var(--vgai-content-primary);
|
|
2597
|
+
background: var(--vgai-neutral-hover);
|
|
2598
|
+
}
|
|
2599
|
+
/* THE SELECTION BAND, and why it is a background LAYER rather than a fill.
|
|
2600
|
+
The canonical selected treatment is the FILL alone (the viewport menus'
|
|
2601
|
+
aria-checked rows, .vgai-selectable, the chat rows). The left accent bar this
|
|
2602
|
+
once added read as a stray one-sided border (owner, 2026-08-07). The fill is
|
|
2603
|
+
the TREE's own band, not `--vgai-selection-bg`: a selected Outliner row is a
|
|
2604
|
+
darker navy than the accent that variable resolves to, which Blender keeps
|
|
2605
|
+
for pressed widgets.
|
|
2606
|
+
|
|
2607
|
+
Measured in `modeling-object-selected.png` (Blender 5.2, object mode, every
|
|
2608
|
+
object selected; the values and the derivations are on
|
|
2609
|
+
`--vgai-tree-row-selected-bg` in theme.ts): Blender's band is 18 of the row's
|
|
2610
|
+
20 px, so ONE row of the ordinary #272727/#2a2a2a stripe shows above and
|
|
2611
|
+
below every selected row. Ours filled the whole 20, and the difference is not
|
|
2612
|
+
subtle at a multi-selection: eleven adjacent selected rows painted ONE
|
|
2613
|
+
continuous slab across the panel with no row boundary anywhere in it, where
|
|
2614
|
+
Blender paints eleven separated bars.
|
|
2615
|
+
|
|
2616
|
+
So the band is a background IMAGE, positioned and sized to the inset, and
|
|
2617
|
+
never a box: the row's height IS the Outliner's 20 px pitch (`chrome.treeIndent`'s
|
|
2618
|
+
sibling, and what `treeRowHeight` measures for hit-testing), so a border or a
|
|
2619
|
+
padding that produced the same picture would move every row. The positioning
|
|
2620
|
+
area is the PADDING box, which already starts after the row's transparent
|
|
2621
|
+
`border-left`, so `0` on the x axis lands 2 px in — Blender's own left inset
|
|
2622
|
+
(band at device x 7 against content from x 2). The right inset is 0 in the
|
|
2623
|
+
frame and 0 here. Blender rounds the box by 1 px; at that radius it is one
|
|
2624
|
+
corner pixel and it is deliberately not drawn. */
|
|
2625
|
+
.vgai-tree-row[data-selected="true"] {
|
|
2626
|
+
color: var(--vgai-content-primary);
|
|
2627
|
+
background-image: linear-gradient(
|
|
2628
|
+
var(--vgai-tree-row-selected-bg),
|
|
2629
|
+
var(--vgai-tree-row-selected-bg)
|
|
2630
|
+
);
|
|
2631
|
+
background-repeat: no-repeat;
|
|
2632
|
+
background-position: 0 1px;
|
|
2633
|
+
background-size: 100% calc(100% - 2px);
|
|
2634
|
+
}
|
|
2635
|
+
/* THE ACTIVE ROW — Blender's second selected state, and the one fact this
|
|
2636
|
+
editor already acts on without ever showing it. `selectedEntityId` (the
|
|
2637
|
+
store's `[...selection].at(-1)`, the insertion-ordered last) is what the
|
|
2638
|
+
gizmo binds to and what the inspector inspects; within a multi-selection
|
|
2639
|
+
nothing on screen said WHICH row that was. Blender's answer is its active
|
|
2640
|
+
object: the lighter band inside a hairline, against the dim band on every
|
|
2641
|
+
other selected row.
|
|
2642
|
+
|
|
2643
|
+
Two background layers make the hairline: the border colour sized to the whole
|
|
2644
|
+
inset box, the fill sized 1 px smaller on each side and offset to match. A
|
|
2645
|
+
`box-shadow: inset` would paint the ring on the BORDER box — the full 20 px —
|
|
2646
|
+
and miss the inset entirely. */
|
|
2647
|
+
.vgai-tree-row[data-selection-active="true"] {
|
|
2648
|
+
background-image:
|
|
2649
|
+
linear-gradient(var(--vgai-tree-row-active-bg), var(--vgai-tree-row-active-bg)),
|
|
2650
|
+
linear-gradient(var(--vgai-tree-row-active-border), var(--vgai-tree-row-active-border));
|
|
2651
|
+
background-position:
|
|
2652
|
+
1px 2px,
|
|
2653
|
+
0 1px;
|
|
2654
|
+
background-size:
|
|
2655
|
+
calc(100% - 2px) calc(100% - 4px),
|
|
2656
|
+
100% calc(100% - 2px);
|
|
2657
|
+
}
|
|
2658
|
+
.vgai-tree-row[data-muted="true"] {
|
|
2659
|
+
color: var(--vgai-content-dim);
|
|
2660
|
+
}
|
|
2661
|
+
.vgai-tree-row[data-dragging="true"] {
|
|
2662
|
+
color: var(--vgai-content-muted);
|
|
2663
|
+
background: var(--vgai-neutral-hover);
|
|
2664
|
+
outline: 1px dashed var(--vgai-boundary-strong);
|
|
2665
|
+
outline-offset: -1px;
|
|
2666
|
+
}
|
|
2667
|
+
/* THE INDENT GUIDE — the vertical rule an OPEN parent draws down its own
|
|
2668
|
+
disclosure column, through every row of its subtree. One span per ancestor
|
|
2669
|
+
column, absolutely positioned against the row's PADDING box (which starts at
|
|
2670
|
+
the same x on every row, before that row's own `padding-left`), so column k
|
|
2671
|
+
lands on the depth-k caret's centre for every descendant alike.
|
|
2672
|
+
|
|
2673
|
+
MEASURED on `modeling-object-none.png` / `modeling-object-selected.png`
|
|
2674
|
+
(Blender 5.2, native 2x, OBJECT mode; the Outliner crop is
|
|
2675
|
+
`modeling.png[y 53..419, x 2843..3452]` = `outliner.png`'s own box):
|
|
2676
|
+
|
|
2677
|
+
- ONE device pixel at x 59 — CSS 29.5..30.0 — against the Collection
|
|
2678
|
+
row's chevron centre of 30.25. Hence `width: 0.5px` placed half a pixel
|
|
2679
|
+
left of the column centre, which lands on Blender's own two device
|
|
2680
|
+
pixels at 2x; at 1x the browser antialiases it, which is the honest
|
|
2681
|
+
rendering of a one-device-pixel rule.
|
|
2682
|
+
- y 143..242 CONTINUOUS — 5 CSS px into the first child's row, 5 CSS px
|
|
2683
|
+
above the last child's row bottom (rows are 40 device px: Camera
|
|
2684
|
+
133..172, Cube 173..212, Light 213..252). Those two 5s are the `top`
|
|
2685
|
+
and `bottom` the row applies at the ENDS of a block only.
|
|
2686
|
+
- every one of those 100 pixels is exactly (101,101,101) over three
|
|
2687
|
+
different backdrops — the #272727/#2a2a2a stripe, the #1c304c selected
|
|
2688
|
+
bar and the #324c7f active bar — so the ink is OPAQUE and painted OVER
|
|
2689
|
+
the row's fill. That is why this is an element above the background and
|
|
2690
|
+
not another `background-image` layer: the selected and active rules
|
|
2691
|
+
already own `background-image` outright and would drop it.
|
|
2692
|
+
|
|
2693
|
+
WHERE THE EVIDENCE STOPS. The frame nests exactly ONE level, and its root
|
|
2694
|
+
row (Scene Collection) carries no chevron and no guide under it — x 0..48 is
|
|
2695
|
+
clear for the whole Collection row, measured. So "one rule per open
|
|
2696
|
+
ancestor" is EXTRAPOLATION beyond the first level; it is the reading taken
|
|
2697
|
+
because the alternative the frame equally supports — a rule under the
|
|
2698
|
+
IMMEDIATE parent only — breaks the very continuity the frame does show: a
|
|
2699
|
+
grandparent's rule would stop at its grandchildren and resume after them.
|
|
2700
|
+
The geometry is not a density member for the same reason `content.active`
|
|
2701
|
+
is not: a palette that names no `color.boundary.indent` draws no guide at
|
|
2702
|
+
all, so there is nothing for another skin to retune. */
|
|
2703
|
+
.vgai-tree-indent-guide {
|
|
2704
|
+
position: absolute;
|
|
2705
|
+
width: 0.5px;
|
|
2706
|
+
background: var(--vgai-tree-indent-guide);
|
|
2707
|
+
pointer-events: none;
|
|
2708
|
+
}
|
|
2709
|
+
.vgai-tree-remote-selection {
|
|
2710
|
+
display: inline-flex;
|
|
2711
|
+
flex: 0 0 auto;
|
|
2712
|
+
align-items: center;
|
|
2713
|
+
}
|
|
2714
|
+
.vgai-tree-remote-selection > span {
|
|
2715
|
+
width: 7px;
|
|
2716
|
+
height: 7px;
|
|
2717
|
+
margin-left: -2px;
|
|
2718
|
+
border: 1px solid var(--vgai-surface-panel);
|
|
2719
|
+
border-radius: var(--vgai-radius-full);
|
|
2720
|
+
}
|
|
2721
|
+
.vgai-tree-row:focus-visible {
|
|
2722
|
+
outline: var(--vgai-focus-ring);
|
|
2723
|
+
outline-offset: -2px;
|
|
2724
|
+
}
|
|
2725
|
+
/* THE GLYPH PLATE — ONE WIDGET, TWO SITES. Blender draws the same rounded
|
|
2726
|
+
plate behind the ACTIVE row's type glyph and behind the datablock glyph of
|
|
2727
|
+
the data it is editing, so the box lives here once and each site paints its
|
|
2728
|
+
own fill into it.
|
|
2729
|
+
|
|
2730
|
+
MEASURED at native 2x on the Cube row, and the three frames AGREE to the
|
|
2731
|
+
pixel: `modeling-object-none.png` (x 2964..3003, y 228..263 of the frame;
|
|
2732
|
+
x 121..160, y 175..210 of the `[x2843..3452, y53..419]` Outliner crop),
|
|
2733
|
+
`modeling-object-selected.png` and `outliner.png` all put it at 40x36
|
|
2734
|
+
device px — 20x18 CSS, one indent cell wide and one CSS px of stripe above
|
|
2735
|
+
and below, exactly the selection bar's own gutters — with a 10 device-px
|
|
2736
|
+
(5 CSS) corner: the outer edge is first full at y=184 on a box whose top is
|
|
2737
|
+
y=175, and the top edge is first full at x=131 on a box whose left is
|
|
2738
|
+
x=121. FIVE is not `radius.sm`'s four, and the one CSS px shows at 6x on a
|
|
2739
|
+
20-px box; it is this plate's own number and it has no token. */
|
|
2740
|
+
.vgai-tree-row {
|
|
2741
|
+
--vgai-tree-glyph-plate-width: var(--vgai-tree-indent);
|
|
2742
|
+
--vgai-tree-glyph-plate-height: calc(var(--vgai-tree-row-height) - var(--vgai-space-1));
|
|
2743
|
+
--vgai-tree-glyph-plate-radius: 5px;
|
|
2744
|
+
}
|
|
2745
|
+
/* THE ACTIVE OBJECT'S PLATE, and WHICH FACT IT MARKS. Blender puts this plate
|
|
2746
|
+
behind the type glyph of the ACTIVE object, and it is INDEPENDENT of
|
|
2747
|
+
selection: `modeling-object-none.png` has nothing selected at all and the
|
|
2748
|
+
Cube's glyph still wears it; `modeling-object-selected.png` has all three
|
|
2749
|
+
rows selected and only the Cube's — the active one — wears it. (The record
|
|
2750
|
+
this unit inherited said the plate marks the active object's DATA over
|
|
2751
|
+
selection state. It does not: in BOTH object-mode frames the Cube's mesh
|
|
2752
|
+
glyph carries NO plate while its OBJECT glyph does. What is absent from the
|
|
2753
|
+
object-mode frames is the DATA plate below, which is edit-mode's.)
|
|
2754
|
+
|
|
2755
|
+
Where Blender has an active object with nothing selected this editor has no
|
|
2756
|
+
active id at all, so the plate simply does not paint — the store's anchor is
|
|
2757
|
+
the only honest answer to "which row is active" and inventing a second one
|
|
2758
|
+
is a noun this editor does not have.
|
|
2759
|
+
|
|
2760
|
+
THE INK IS THE ROW'S OWN, AT TWO ALPHAS, and that is a fit rather than a
|
|
2761
|
+
taste call: over the stripe's #2a2a2a the plate measures #525252 fill /
|
|
2762
|
+
#686868 border, and over the active row's #324c7f it measures (87,107,144)
|
|
2763
|
+
fill / (108,124,154) border. Solving both backgrounds at once returns one
|
|
2764
|
+
ink of 190-194 at 26% and 41% — and `content.muted` (#c2c2c2, the ink the
|
|
2765
|
+
unselected row's own NAME already takes) reproduces every channel of both
|
|
2766
|
+
frames within one level. No new palette member: the plate is the row's text
|
|
2767
|
+
colour, thinned.
|
|
2768
|
+
|
|
2769
|
+
THE BORDER'S DECLARED ALPHA IS 20.3%, NOT THE MEASURED 41%, and the
|
|
2770
|
+
difference is the fill already lying under it: `background-clip` is
|
|
2771
|
+
`border-box`, so the border composites over the plate rather than over the
|
|
2772
|
+
row — the same model its datablock sibling below records. Solving
|
|
2773
|
+
(1-b)(1-0.26) = 1-0.41 gives b = 0.203, which puts the painted column back
|
|
2774
|
+
at 41% of the ink over the row. Measured before the correction: the border
|
|
2775
|
+
landed at an effective 56.5% and read as a bright hairline. */
|
|
2776
|
+
.vgai-tree-type-glyph {
|
|
2777
|
+
position: relative;
|
|
2778
|
+
z-index: 0;
|
|
2779
|
+
}
|
|
2780
|
+
/* The site's half of the category ink, on the GLYPH and not on the cell —
|
|
2781
|
+
the same split `.vgai-tree-datablock > *` makes, and for the same reason:
|
|
2782
|
+
the plate's fill and border are measured as PAINTED, and a group opacity
|
|
2783
|
+
on the cell would put 0.80 through them a second time. */
|
|
2784
|
+
.vgai-tree-type-glyph > * {
|
|
2785
|
+
opacity: 0.8;
|
|
2786
|
+
}
|
|
2787
|
+
.vgai-tree-row[data-selection-active="true"] .vgai-tree-type-glyph::before {
|
|
2788
|
+
content: "";
|
|
2789
|
+
position: absolute;
|
|
2790
|
+
z-index: -1;
|
|
2791
|
+
top: 50%;
|
|
2792
|
+
left: 50%;
|
|
2793
|
+
box-sizing: border-box;
|
|
2794
|
+
width: var(--vgai-tree-glyph-plate-width);
|
|
2795
|
+
height: var(--vgai-tree-glyph-plate-height);
|
|
2796
|
+
transform: translate(-50%, -50%);
|
|
2797
|
+
border: var(--vgai-stroke-resting) solid
|
|
2798
|
+
color-mix(in srgb, var(--vgai-content-muted) 20.3%, transparent);
|
|
2799
|
+
border-radius: var(--vgai-tree-glyph-plate-radius);
|
|
2800
|
+
background: color-mix(in srgb, var(--vgai-content-muted) 26%, transparent);
|
|
2801
|
+
pointer-events: none;
|
|
2802
|
+
}
|
|
2803
|
+
/* THE COLLAPSED ROW'S DATABLOCK GLYPH — Blender's rest state (the summary a
|
|
2804
|
+
`>` row draws for the datablock it is hiding; `GameHierarchy.tsx`'s `Row`
|
|
2805
|
+
carries the geometry's coordinates). One indent cell wide, two points
|
|
2806
|
+
shorter than the row, and the gap before it is one cell.
|
|
2807
|
+
|
|
2808
|
+
THE PLATE, and exactly which state earns it. In `outliner.png` the CUBE —
|
|
2809
|
+
the active object, the one Blender draws with an orange name — is the row
|
|
2810
|
+
whose datablock glyph sits on a rounded plate; the Light's, on an ordinary
|
|
2811
|
+
row, has none. This one is EDIT MODE's: it is absent from both object-mode
|
|
2812
|
+
frames, where the same Cube row's mesh glyph is bare, and the Model
|
|
2813
|
+
document — whose viewport header reads Edit Mode — is that frame's sibling.
|
|
2814
|
+
(The CAMERA's datablock carries a NEUTRAL grey plate in all three frames,
|
|
2815
|
+
`#4f4f4f` fill / `#666666` border over the row's `#272727` — the same box
|
|
2816
|
+
the active object's type glyph wears above, in the neutral ink rather than
|
|
2817
|
+
the data green. That one marks "the scene's active camera", a fact this
|
|
2818
|
+
editor has no analogue for and no way to answer honestly, so it is measured
|
|
2819
|
+
here and deliberately not drawn.)
|
|
2820
|
+
Ours takes the ACTIVE row, which is what "active object" means in this
|
|
2821
|
+
editor — see the gate's own comment in `GameHierarchy.tsx`.
|
|
2822
|
+
|
|
2823
|
+
THE TINT IS TRANSCRIBED, NOT MODELLED. Blender's plate under the Cube's
|
|
2824
|
+
mesh measures `#1f4038` fill with a `#506761` border over the alternate
|
|
2825
|
+
row's `#2a2a2a` (src x 263-302, y 175-210), and no single alpha of the data
|
|
2826
|
+
ink reproduces it — the fill's red falls 11 below the row where the ink's
|
|
2827
|
+
own red is already clamped at zero. What DOES reproduce it, every channel
|
|
2828
|
+
exactly, is the ink darkened to 60% and laid on at 26%: 42*0.74 = 31,
|
|
2829
|
+
42+0.26*(126.6-42) = 64, 42+0.26*(97.2-42) = 56.
|
|
2830
|
+
|
|
2831
|
+
THE BORDER CARRIES NO INK, and that is a solve rather than a simplification.
|
|
2832
|
+
Fitting a green-tinted light term to the frame's `#506761` returns a
|
|
2833
|
+
NEGATIVE ink weight, so the hue in that hairline is entirely the fill
|
|
2834
|
+
showing through: `content.primary` at 24% over the fill lands (79,104,98)
|
|
2835
|
+
against the frame's (80,103,97), one level anywhere. It composites over the
|
|
2836
|
+
PLATE, not the row — measured, not assumed: a temporary opaque border on the
|
|
2837
|
+
live surface showed the painted column is the border colour over the
|
|
2838
|
+
element's own background at exactly its declared alpha (the earlier
|
|
2839
|
+
41%-over-fill cut predicted (88,146,156) over our selection blue and the
|
|
2840
|
+
frame delivered (88,146,156)).
|
|
2841
|
+
|
|
2842
|
+
Both terms composite through `transparent`, so they still read over the
|
|
2843
|
+
selected row's own fill — which Blender does not paint at all: its outliner
|
|
2844
|
+
marks selection on the NAME (the Cube's label is orange) and leaves the row
|
|
2845
|
+
its ordinary stripe, so over our blue selection the plate reads as a teal
|
|
2846
|
+
chip rather than the frame's dark green. That difference is the row FILL's,
|
|
2847
|
+
not this plate's, and closing it is the selected row's own unit. */
|
|
2848
|
+
.vgai-tree-datablock {
|
|
2849
|
+
display: inline-flex;
|
|
2850
|
+
align-items: center;
|
|
2851
|
+
justify-content: center;
|
|
2852
|
+
box-sizing: border-box;
|
|
2853
|
+
flex-shrink: 0;
|
|
2854
|
+
vertical-align: middle;
|
|
2855
|
+
width: var(--vgai-tree-glyph-plate-width);
|
|
2856
|
+
height: var(--vgai-tree-glyph-plate-height);
|
|
2857
|
+
margin-left: var(--vgai-tree-indent);
|
|
2858
|
+
font-size: var(--vgai-icon-sm);
|
|
2859
|
+
border: var(--vgai-stroke-resting) solid transparent;
|
|
2860
|
+
/* The SAME corner as the active object's plate above — one widget, one
|
|
2861
|
+
number. It read `radius.sm` (4) against the frame's measured 5. */
|
|
2862
|
+
border-radius: var(--vgai-tree-glyph-plate-radius);
|
|
2863
|
+
}
|
|
2864
|
+
/* The site's half of the category ink — the Outliner composites its GLYPHS at
|
|
2865
|
+
0.80, the same measurement the row's own type glyph applies. On the glyph
|
|
2866
|
+
and not on the cell: the plate's own fill and border are measured as
|
|
2867
|
+
painted, and dimming the whole cell would put 0.80 through them twice. */
|
|
2868
|
+
.vgai-tree-datablock > * {
|
|
2869
|
+
opacity: 0.8;
|
|
2870
|
+
}
|
|
2871
|
+
.vgai-tree-datablock[data-active="true"] {
|
|
2872
|
+
background: color-mix(
|
|
2873
|
+
in srgb,
|
|
2874
|
+
color-mix(in srgb, var(--vgai-category-data, currentColor) 60%, black) 26%,
|
|
2875
|
+
transparent
|
|
2876
|
+
);
|
|
2877
|
+
border-color: color-mix(in srgb, var(--vgai-content-primary) 24%, transparent);
|
|
2878
|
+
}
|
|
2879
|
+
.vgai-tree-row-leading {
|
|
2880
|
+
display: inline-flex;
|
|
2881
|
+
width: 14px;
|
|
2882
|
+
flex: 0 0 auto;
|
|
2883
|
+
justify-content: center;
|
|
2884
|
+
}
|
|
2885
|
+
.vgai-tree-row-label {
|
|
2886
|
+
min-width: 0;
|
|
2887
|
+
flex: 1;
|
|
2888
|
+
overflow: hidden;
|
|
2889
|
+
text-overflow: ellipsis;
|
|
2890
|
+
white-space: nowrap;
|
|
2891
|
+
}
|
|
2892
|
+
.vgai-tree-row-actions {
|
|
2893
|
+
display: inline-flex;
|
|
2894
|
+
flex: 0 0 auto;
|
|
2895
|
+
align-items: center;
|
|
2896
|
+
gap: var(--vgai-space-1);
|
|
2897
|
+
}
|
|
2898
|
+
/* A ROW'S TOGGLES ARE BRIGHTER THAN ITS LABEL. Measured in `outliner.png`:
|
|
2899
|
+
the eye and camera toggles ink at #e5e5e5 (src x 510–586, y 98–172) while
|
|
2900
|
+
the row's own text is #c2c2c2 (src x 166–276) — which under the Blender
|
|
2901
|
+
palette are exactly `content.primary` and `content.muted`. A ghost
|
|
2902
|
+
IconButton reads `--vgai-content-muted`, i.e. the label's ink, so inside a
|
|
2903
|
+
tree row the toggles were as quiet as the name they act on. They are
|
|
2904
|
+
controls: the brighter token is `--vgai-content-primary`. Scoped to the
|
|
2905
|
+
row (both shapes — `patterns/Tree.tsx`'s actions slot and the flat rows
|
|
2906
|
+
`GameHierarchy.tsx` builds), never to ghost buttons at large. */
|
|
2907
|
+
.vgai-tree-row .vgai-btn[data-variant="ghost"]:not(.vgai-tree-caret) {
|
|
2908
|
+
color: var(--vgai-content-primary);
|
|
2909
|
+
}
|
|
2910
|
+
/* ...but the EXPANDER is not one of them. Same frame, same scale: the
|
|
2911
|
+
Collection row's open chevron inks #c2c2c2 (src x 52-69, y 110-119) — the
|
|
2912
|
+
row's own label ink, not the toggles' #e5e5e5. It is a disclosure mark on
|
|
2913
|
+
the name, not a control acting on the object, and the rule above had swept
|
|
2914
|
+
it up with the eye. */
|
|
2915
|
+
.vgai-tree-row .vgai-btn.vgai-tree-caret {
|
|
2916
|
+
color: var(--vgai-content-muted);
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2919
|
+
.vgai-field-group {
|
|
2920
|
+
display: grid;
|
|
2921
|
+
gap: var(--vgai-space-3);
|
|
2922
|
+
padding: var(--vgai-space-4);
|
|
2923
|
+
}
|
|
2924
|
+
.vgai-field-row {
|
|
2925
|
+
display: grid;
|
|
2926
|
+
grid-template-columns: minmax(64px, 84px) minmax(0, 1fr);
|
|
2927
|
+
min-width: 0;
|
|
2928
|
+
align-items: center;
|
|
2929
|
+
gap: var(--vgai-space-3);
|
|
2930
|
+
}
|
|
2931
|
+
.vgai-field-row[data-compact="true"] {
|
|
2932
|
+
grid-template-columns: minmax(52px, 72px) minmax(0, 1fr);
|
|
2933
|
+
}
|
|
2934
|
+
.vgai-field-label {
|
|
2935
|
+
min-width: 0;
|
|
2936
|
+
color: var(--vgai-content-muted);
|
|
2937
|
+
font-size: var(--vgai-font-base);
|
|
2938
|
+
}
|
|
2939
|
+
.vgai-field-control {
|
|
2940
|
+
display: flex;
|
|
2941
|
+
min-width: 0;
|
|
2942
|
+
align-items: center;
|
|
2943
|
+
gap: var(--vgai-space-2);
|
|
2944
|
+
}
|
|
2945
|
+
.vgai-field-hint {
|
|
2946
|
+
grid-column: 2;
|
|
2947
|
+
color: var(--vgai-content-dim);
|
|
2948
|
+
font-size: var(--vgai-font-sm);
|
|
2949
|
+
line-height: 1.35;
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2952
|
+
.vgai-state-surface {
|
|
2953
|
+
display: flex;
|
|
2954
|
+
min-width: 0;
|
|
2955
|
+
min-height: 120px;
|
|
2956
|
+
flex-direction: column;
|
|
2957
|
+
align-items: center;
|
|
2958
|
+
justify-content: center;
|
|
2959
|
+
gap: var(--vgai-space-3);
|
|
2960
|
+
padding: var(--vgai-space-8);
|
|
2961
|
+
color: var(--vgai-content-muted);
|
|
2962
|
+
text-align: center;
|
|
2963
|
+
box-sizing: border-box;
|
|
2964
|
+
}
|
|
2965
|
+
.vgai-state-surface[data-compact="true"] {
|
|
2966
|
+
min-height: 64px;
|
|
2967
|
+
padding: var(--vgai-space-4);
|
|
2968
|
+
}
|
|
2969
|
+
.vgai-state-surface[data-tone="error"] {
|
|
2970
|
+
color: var(--vgai-danger);
|
|
2971
|
+
}
|
|
2972
|
+
.vgai-state-surface[data-tone="success"] {
|
|
2973
|
+
color: var(--vgai-success);
|
|
2974
|
+
}
|
|
2975
|
+
.vgai-state-surface[data-tone="loading"] .vgai-state-surface-icon {
|
|
2976
|
+
animation: vgai-editor-spin 0.8s linear infinite;
|
|
2977
|
+
}
|
|
2978
|
+
.vgai-state-surface-icon {
|
|
2979
|
+
color: currentColor;
|
|
2980
|
+
font-size: var(--vgai-font-2xl);
|
|
2981
|
+
}
|
|
2982
|
+
.vgai-state-surface-title {
|
|
2983
|
+
color: var(--vgai-content-primary);
|
|
2984
|
+
font-size: var(--vgai-font-md);
|
|
2985
|
+
}
|
|
2986
|
+
.vgai-state-surface-description {
|
|
2987
|
+
max-width: 42ch;
|
|
2988
|
+
color: var(--vgai-content-dim);
|
|
2989
|
+
line-height: var(--vgai-leading-normal);
|
|
2990
|
+
}
|
|
2991
|
+
.vgai-state-surface-action {
|
|
2992
|
+
margin-top: var(--vgai-space-2);
|
|
2993
|
+
}
|
|
2994
|
+
|
|
2995
|
+
.vgai-banner {
|
|
2996
|
+
/* U6a: the tone tint is a custom property so the islands-gated glass rule
|
|
2997
|
+
* below can LAYER it over the island material instead of repeating the
|
|
2998
|
+
* four tone selectors. Inert for the base (bars) paint — the background
|
|
2999
|
+
* consumes it directly, byte-identical to the former literal. */
|
|
3000
|
+
--vgai-banner-tone-tint: var(--vgai-accent-muted);
|
|
3001
|
+
display: flex;
|
|
3002
|
+
min-width: 0;
|
|
3003
|
+
align-items: center;
|
|
3004
|
+
gap: var(--vgai-space-3);
|
|
3005
|
+
padding: var(--vgai-space-3) var(--vgai-space-5);
|
|
3006
|
+
border-bottom: var(--vgai-stroke-resting) solid var(--vgai-accent);
|
|
3007
|
+
color: var(--vgai-accent);
|
|
3008
|
+
background: var(--vgai-banner-tone-tint);
|
|
3009
|
+
box-sizing: border-box;
|
|
3010
|
+
}
|
|
3011
|
+
.vgai-banner[data-tone="warning"] {
|
|
3012
|
+
--vgai-banner-tone-tint: var(--vgai-warn-muted);
|
|
3013
|
+
color: var(--vgai-warn);
|
|
3014
|
+
border-color: var(--vgai-warn);
|
|
3015
|
+
}
|
|
3016
|
+
.vgai-banner[data-tone="error"] {
|
|
3017
|
+
--vgai-banner-tone-tint: var(--vgai-danger-faint);
|
|
3018
|
+
color: var(--vgai-danger);
|
|
3019
|
+
border-color: var(--vgai-danger);
|
|
3020
|
+
}
|
|
3021
|
+
.vgai-banner[data-tone="success"] {
|
|
3022
|
+
--vgai-banner-tone-tint: var(--vgai-success-muted);
|
|
3023
|
+
color: var(--vgai-success);
|
|
3024
|
+
border-color: var(--vgai-success);
|
|
3025
|
+
}
|
|
3026
|
+
/* U6a (P6 glass-native chrome, inventory row "scene banners"): under islands
|
|
3027
|
+
* chrome — treatment presence, never theme identity — a banner is glass: the
|
|
3028
|
+
* island material (surface + plain backdrop-filter list) with the SEMANTIC
|
|
3029
|
+
* TINT layered on top of it, so the tone still reads while the scene shows
|
|
3030
|
+
* through frosted. A flat blur, never a second refraction lens — banners
|
|
3031
|
+
* paint inside documents/cards, and the one-lens-per-card rule holds. Bars
|
|
3032
|
+
* chrome (graphite/classic and every reduced-transparency/lite fallback)
|
|
3033
|
+
* never matches this rule and keeps the flat tint byte-identically. */
|
|
3034
|
+
[data-vgai-chrome="islands"] .vgai-banner {
|
|
3035
|
+
background:
|
|
3036
|
+
linear-gradient(var(--vgai-banner-tone-tint), var(--vgai-banner-tone-tint)),
|
|
3037
|
+
var(--vgai-island-surface, transparent);
|
|
3038
|
+
backdrop-filter: var(--vgai-island-backdrop-filter, none);
|
|
3039
|
+
-webkit-backdrop-filter: var(--vgai-island-backdrop-filter, none);
|
|
3040
|
+
text-shadow: var(--vgai-content-text-shadow, none);
|
|
3041
|
+
}
|
|
3042
|
+
.vgai-banner-icon {
|
|
3043
|
+
display: inline-flex;
|
|
3044
|
+
flex: 0 0 auto;
|
|
3045
|
+
}
|
|
3046
|
+
.vgai-banner-content {
|
|
3047
|
+
min-width: 0;
|
|
3048
|
+
flex: 1;
|
|
3049
|
+
color: var(--vgai-content-primary);
|
|
3050
|
+
}
|
|
3051
|
+
.vgai-banner-actions {
|
|
3052
|
+
display: flex;
|
|
3053
|
+
flex: 0 0 auto;
|
|
3054
|
+
align-items: center;
|
|
3055
|
+
gap: var(--vgai-space-2);
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
.vgai-popover {
|
|
3059
|
+
color: var(--vgai-content-primary);
|
|
3060
|
+
background: var(--vgai-glass-regular-bg, var(--vgai-surface-chrome));
|
|
3061
|
+
border: var(--vgai-stroke-resting) solid var(--vgai-boundary-strong);
|
|
3062
|
+
border-radius: var(--vgai-radius-md);
|
|
3063
|
+
box-shadow: var(--vgai-shadow-md);
|
|
3064
|
+
}
|
|
3065
|
+
.vgai-drop-indicator {
|
|
3066
|
+
position: absolute;
|
|
3067
|
+
z-index: var(--vgai-z-overlay-low);
|
|
3068
|
+
pointer-events: none;
|
|
3069
|
+
border: var(--vgai-stroke-active) solid var(--vgai-selection-border);
|
|
3070
|
+
background: var(--vgai-selection-bg);
|
|
3071
|
+
box-sizing: border-box;
|
|
3072
|
+
}
|
|
3073
|
+
.vgai-drop-indicator[data-position="before"] {
|
|
3074
|
+
inset: 0 0 auto;
|
|
3075
|
+
height: var(--vgai-stroke-active);
|
|
3076
|
+
}
|
|
3077
|
+
.vgai-drop-indicator[data-position="after"] {
|
|
3078
|
+
inset: auto 0 0;
|
|
3079
|
+
height: var(--vgai-stroke-active);
|
|
3080
|
+
}
|
|
3081
|
+
.vgai-drop-indicator[data-position="inside"] {
|
|
3082
|
+
inset: 1px;
|
|
3083
|
+
border-radius: var(--vgai-radius-sm);
|
|
3084
|
+
}
|
|
3085
|
+
|
|
3086
|
+
.vgai-model-tree-item {
|
|
3087
|
+
text-align: left;
|
|
3088
|
+
}
|
|
3089
|
+
.vgai-btn.vgai-project-tool-card {
|
|
3090
|
+
display: grid;
|
|
3091
|
+
width: 100%;
|
|
3092
|
+
height: auto;
|
|
3093
|
+
align-items: start;
|
|
3094
|
+
justify-content: normal;
|
|
3095
|
+
gap: var(--vgai-space-2);
|
|
3096
|
+
padding-block: var(--vgai-space-3);
|
|
3097
|
+
text-align: left;
|
|
3098
|
+
}
|
|
3099
|
+
|
|
3100
|
+
.vgai-resize-handle {
|
|
3101
|
+
position: relative;
|
|
3102
|
+
z-index: var(--vgai-z-overlay-low);
|
|
3103
|
+
flex: 0 0 5px;
|
|
3104
|
+
background: transparent;
|
|
3105
|
+
touch-action: none;
|
|
3106
|
+
}
|
|
3107
|
+
.vgai-resize-handle[data-orientation="vertical"] {
|
|
3108
|
+
cursor: col-resize;
|
|
3109
|
+
}
|
|
3110
|
+
.vgai-resize-handle[data-orientation="horizontal"] {
|
|
3111
|
+
cursor: row-resize;
|
|
3112
|
+
}
|
|
3113
|
+
.vgai-resize-handle::before {
|
|
3114
|
+
position: absolute;
|
|
3115
|
+
background: var(--vgai-boundary-default);
|
|
3116
|
+
content: "";
|
|
3117
|
+
transition:
|
|
3118
|
+
background-color 80ms var(--vgai-ease-standard),
|
|
3119
|
+
transform 80ms var(--vgai-ease-standard);
|
|
3120
|
+
}
|
|
3121
|
+
.vgai-resize-handle[data-orientation="vertical"]::before {
|
|
3122
|
+
inset: 0 auto 0 2px;
|
|
3123
|
+
width: 1px;
|
|
3124
|
+
}
|
|
3125
|
+
.vgai-resize-handle[data-orientation="horizontal"]::before {
|
|
3126
|
+
inset: 2px 0 auto;
|
|
3127
|
+
height: 1px;
|
|
3128
|
+
}
|
|
3129
|
+
.vgai-resize-handle:hover::before,
|
|
3130
|
+
.vgai-resize-handle:focus-visible::before {
|
|
3131
|
+
background: var(--vgai-selection-indicator);
|
|
3132
|
+
}
|
|
3133
|
+
.vgai-resize-handle[data-orientation="vertical"]:hover::before,
|
|
3134
|
+
.vgai-resize-handle[data-orientation="vertical"]:focus-visible::before {
|
|
3135
|
+
transform: scaleX(2);
|
|
3136
|
+
}
|
|
3137
|
+
.vgai-resize-handle[data-orientation="horizontal"]:hover::before,
|
|
3138
|
+
.vgai-resize-handle[data-orientation="horizontal"]:focus-visible::before {
|
|
3139
|
+
transform: scaleY(2);
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
/* ---------------------------------------------------------------------- */
|
|
3143
|
+
/* Scrollbar policy (closes C-12, root cause of L-8/L-19) — REPLACES the */
|
|
3144
|
+
/* old global *::-webkit-scrollbar{display:none} suppression. Thin, dark, */
|
|
3145
|
+
/* themed; visible only where content actually overflows. */
|
|
3146
|
+
/* ---------------------------------------------------------------------- */
|
|
3147
|
+
|
|
3148
|
+
.vgai-editor-theme,
|
|
3149
|
+
.vgai-editor-theme :where(*):not([data-vgai-world-surface], [data-vgai-world-surface] *) {
|
|
3150
|
+
scrollbar-width: thin;
|
|
3151
|
+
scrollbar-color: var(--vgai-bg-3) transparent;
|
|
3152
|
+
}
|
|
3153
|
+
.vgai-editor-theme::-webkit-scrollbar,
|
|
3154
|
+
.vgai-editor-theme
|
|
3155
|
+
:where(*):not([data-vgai-world-surface], [data-vgai-world-surface] *)::-webkit-scrollbar {
|
|
3156
|
+
width: 9px;
|
|
3157
|
+
height: 9px;
|
|
3158
|
+
}
|
|
3159
|
+
.vgai-editor-theme::-webkit-scrollbar-track,
|
|
3160
|
+
.vgai-editor-theme
|
|
3161
|
+
:where(*):not([data-vgai-world-surface], [data-vgai-world-surface] *)::-webkit-scrollbar-track {
|
|
3162
|
+
background: transparent;
|
|
3163
|
+
}
|
|
3164
|
+
.vgai-editor-theme::-webkit-scrollbar-thumb,
|
|
3165
|
+
.vgai-editor-theme
|
|
3166
|
+
:where(*):not([data-vgai-world-surface], [data-vgai-world-surface] *)::-webkit-scrollbar-thumb {
|
|
3167
|
+
background-color: var(--vgai-bg-3);
|
|
3168
|
+
border-radius: var(--vgai-radius-full);
|
|
3169
|
+
border: 2px solid var(--vgai-bg-1);
|
|
3170
|
+
background-clip: padding-box;
|
|
3171
|
+
}
|
|
3172
|
+
.vgai-editor-theme::-webkit-scrollbar-thumb:hover,
|
|
3173
|
+
.vgai-editor-theme
|
|
3174
|
+
:where(*):not(
|
|
3175
|
+
[data-vgai-world-surface],
|
|
3176
|
+
[data-vgai-world-surface] *
|
|
3177
|
+
)::-webkit-scrollbar-thumb:hover {
|
|
3178
|
+
background-color: var(--vgai-border-2);
|
|
3179
|
+
}
|
|
3180
|
+
.vgai-editor-theme::-webkit-scrollbar-corner,
|
|
3181
|
+
.vgai-editor-theme
|
|
3182
|
+
:where(*):not([data-vgai-world-surface], [data-vgai-world-surface] *)::-webkit-scrollbar-corner {
|
|
3183
|
+
background: transparent;
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3186
|
+
/* ---------------------------------------------------------------------- */
|
|
3187
|
+
/* Keyframes — keep editor-spin as-is; add the missing blink keyframe */
|
|
3188
|
+
/* (closes C-9, referenced by BuildPanel.tsx:325's build-log cursor). */
|
|
3189
|
+
/* ---------------------------------------------------------------------- */
|
|
3190
|
+
|
|
3191
|
+
@keyframes vgai-editor-spin {
|
|
3192
|
+
to {
|
|
3193
|
+
transform: rotate(360deg);
|
|
3194
|
+
}
|
|
3195
|
+
}
|
|
3196
|
+
@keyframes vgai-editor-blink {
|
|
3197
|
+
0%,
|
|
3198
|
+
100% {
|
|
3199
|
+
opacity: 1;
|
|
3200
|
+
}
|
|
3201
|
+
50% {
|
|
3202
|
+
opacity: 0;
|
|
3203
|
+
}
|
|
3204
|
+
}
|
|
3205
|
+
|
|
3206
|
+
/* Shared animation roles — components apply these classes instead of inline
|
|
3207
|
+
`animation:` styles so the reduced-motion overrides below can reach them
|
|
3208
|
+
(a media-query rule cannot beat an inline style without !important). */
|
|
3209
|
+
.vgai-anim-spin {
|
|
3210
|
+
animation: vgai-editor-spin 0.8s linear infinite;
|
|
3211
|
+
}
|
|
3212
|
+
.vgai-anim-blink {
|
|
3213
|
+
animation: vgai-editor-blink 1s step-end infinite;
|
|
3214
|
+
}
|
|
3215
|
+
|
|
3216
|
+
/* Chrome is not prose — the VSCode model (glass-UI W7, report §2.23,
|
|
3217
|
+
inverted after the blanket panel-wide rule made inspector paths, console
|
|
3218
|
+
messages, and error text unselectable). Text is selectable by DEFAULT
|
|
3219
|
+
everywhere; only interaction chrome opts out below. The convicted
|
|
3220
|
+
defect's real vector stays closed: a drag that starts on chrome rather
|
|
3221
|
+
than on prose cannot anchor a selection, because chrome opts out below. A
|
|
3222
|
+
drag over plain prose selecting that prose
|
|
3223
|
+
is normal browser behavior, not a defect. `data-vgai-noselect`
|
|
3224
|
+
(the workspace host, static/utility panel wrappers; never documents, never
|
|
3225
|
+
the agent conversation) now only scopes the bare-element button rule so
|
|
3226
|
+
it cannot reach hosted-game DOM. */
|
|
3227
|
+
|
|
3228
|
+
/* Buttons and button-shaped triggers (labels are affordances, not text). */
|
|
3229
|
+
.vgai-btn,
|
|
3230
|
+
.vgai-list-button,
|
|
3231
|
+
.vgai-split-button,
|
|
3232
|
+
.vgai-menu,
|
|
3233
|
+
.vgai-menu-trigger,
|
|
3234
|
+
.vgai-field-trigger,
|
|
3235
|
+
.vgai-inspector-group-trigger,
|
|
3236
|
+
.vgai-status-action,
|
|
3237
|
+
/* Panel toolbars / headers / internal tab strips. */
|
|
3238
|
+
.vgai-toolbar,
|
|
3239
|
+
.vgai-dock-document-toolbar,
|
|
3240
|
+
.vgai-viewport-toolbar,
|
|
3241
|
+
.vgai-floating-toolbar,
|
|
3242
|
+
.vgai-playbar,
|
|
3243
|
+
.vgai-project-assets-toolbar,
|
|
3244
|
+
.vgai-section-header,
|
|
3245
|
+
.vgai-tabs,
|
|
3246
|
+
/* Drag-source rows/tiles: a reparent or place gesture must not paint
|
|
3247
|
+
selection (hierarchy rows are HTML5 drag sources; asset tiles are
|
|
3248
|
+
draggable when placeable; folder-tree rows are drop/drag chrome). */
|
|
3249
|
+
.vgai-tree-row,
|
|
3250
|
+
.vgai-asset-tree-row,
|
|
3251
|
+
.vgai-project-asset-entry,
|
|
3252
|
+
.vgai-model-tree-item,
|
|
3253
|
+
/* Scrub chrome: numeric scrubbing is a pointer drag on the readout and
|
|
3254
|
+
its axis label (base rules/inline styles already set these; kept here
|
|
3255
|
+
so the chrome inventory is complete in one place). */
|
|
3256
|
+
.vgai-number-input-label,
|
|
3257
|
+
.vgai-number-input-scrub,
|
|
3258
|
+
.vgai-scrub-label,
|
|
3259
|
+
/* Resize handles. */
|
|
3260
|
+
.vgai-resize-handle {
|
|
3261
|
+
user-select: none;
|
|
3262
|
+
}
|
|
3263
|
+
/* Bare <button>/[role=button] chrome inside editor panels only — scoped
|
|
3264
|
+
to the noselect markers so hosted-game DOM keeps its own defaults. */
|
|
3265
|
+
[data-vgai-noselect] button,
|
|
3266
|
+
[data-vgai-noselect] [role="button"] {
|
|
3267
|
+
user-select: none;
|
|
3268
|
+
}
|
|
3269
|
+
/* Form fields nested under chrome-none ancestors (e.g. the hierarchy
|
|
3270
|
+
rename input inside a tree row, toolbar search/filter inputs) stay
|
|
3271
|
+
selectable; `vgai-selectable-text` remains an explicit opt-in. */
|
|
3272
|
+
[data-vgai-noselect] input,
|
|
3273
|
+
[data-vgai-noselect] textarea,
|
|
3274
|
+
[data-vgai-noselect] [contenteditable="true"],
|
|
3275
|
+
.vgai-toolbar input,
|
|
3276
|
+
.vgai-dock-document-toolbar input,
|
|
3277
|
+
.vgai-project-assets-toolbar input,
|
|
3278
|
+
.vgai-tree-row input,
|
|
3279
|
+
.vgai-selectable-text {
|
|
3280
|
+
user-select: text;
|
|
3281
|
+
}
|
|
3282
|
+
|
|
3283
|
+
/* Light Explorer — a wide, scene-level audit table in the on-demand bottom
|
|
3284
|
+
utility group. Interaction paint stays on the shared controls; this block
|
|
3285
|
+
owns only the table's geometry and semantic selection/readability states. */
|
|
3286
|
+
.vgai-light-explorer {
|
|
3287
|
+
display: flex;
|
|
3288
|
+
flex-direction: column;
|
|
3289
|
+
min-width: 0;
|
|
3290
|
+
height: 100%;
|
|
3291
|
+
color: var(--vgai-content-primary);
|
|
3292
|
+
background: var(--vgai-surface-panel);
|
|
3293
|
+
}
|
|
3294
|
+
|
|
3295
|
+
.vgai-light-explorer-toolbar {
|
|
3296
|
+
display: flex;
|
|
3297
|
+
align-items: center;
|
|
3298
|
+
gap: var(--vgai-space-2);
|
|
3299
|
+
min-height: 38px;
|
|
3300
|
+
padding: var(--vgai-space-2) var(--vgai-space-3);
|
|
3301
|
+
border-bottom: var(--vgai-stroke-resting) solid var(--vgai-structural-divider);
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
|
+
.vgai-light-explorer-toolbar > .vgai-input {
|
|
3305
|
+
width: min(280px, 38vw);
|
|
3306
|
+
}
|
|
3307
|
+
|
|
3308
|
+
.vgai-light-explorer-summary {
|
|
3309
|
+
margin-left: auto;
|
|
3310
|
+
color: var(--vgai-content-muted);
|
|
3311
|
+
font-size: var(--vgai-font-small);
|
|
3312
|
+
white-space: nowrap;
|
|
3313
|
+
}
|
|
3314
|
+
|
|
3315
|
+
.vgai-light-explorer-scroll {
|
|
3316
|
+
min-height: 0;
|
|
3317
|
+
flex: 1;
|
|
3318
|
+
overflow: auto;
|
|
3319
|
+
}
|
|
3320
|
+
|
|
3321
|
+
.vgai-light-explorer-table {
|
|
3322
|
+
width: 100%;
|
|
3323
|
+
min-width: 760px;
|
|
3324
|
+
border-collapse: separate;
|
|
3325
|
+
border-spacing: 0;
|
|
3326
|
+
font-size: var(--vgai-font-base);
|
|
3327
|
+
}
|
|
3328
|
+
|
|
3329
|
+
.vgai-light-explorer-table th {
|
|
3330
|
+
position: sticky;
|
|
3331
|
+
top: 0;
|
|
3332
|
+
z-index: 1;
|
|
3333
|
+
height: 30px;
|
|
3334
|
+
padding: 0 var(--vgai-space-2);
|
|
3335
|
+
text-align: left;
|
|
3336
|
+
font-weight: var(--vgai-font-weight-medium);
|
|
3337
|
+
color: var(--vgai-content-muted);
|
|
3338
|
+
background: var(--vgai-surface-raised);
|
|
3339
|
+
border-bottom: var(--vgai-stroke-resting) solid var(--vgai-structural-divider);
|
|
3340
|
+
}
|
|
3341
|
+
|
|
3342
|
+
.vgai-light-explorer-table td {
|
|
3343
|
+
height: 34px;
|
|
3344
|
+
padding: var(--vgai-space-1) var(--vgai-space-2);
|
|
3345
|
+
border-bottom: var(--vgai-stroke-resting) solid var(--vgai-structural-divider);
|
|
3346
|
+
vertical-align: middle;
|
|
3347
|
+
}
|
|
3348
|
+
|
|
3349
|
+
.vgai-light-explorer-table tbody tr[data-selected="true"] td {
|
|
3350
|
+
background: var(--vgai-selection-bg);
|
|
3351
|
+
}
|
|
3352
|
+
|
|
3353
|
+
.vgai-light-explorer-table tbody tr:hover td {
|
|
3354
|
+
background: var(--vgai-neutral-hover);
|
|
3355
|
+
}
|
|
3356
|
+
|
|
3357
|
+
.vgai-light-explorer-table tbody tr[data-selected="true"]:hover td {
|
|
3358
|
+
background: var(--vgai-selection-bg);
|
|
3359
|
+
}
|
|
3360
|
+
|
|
3361
|
+
.vgai-light-explorer-check-column,
|
|
3362
|
+
.vgai-light-explorer-table td:first-child,
|
|
3363
|
+
.vgai-light-explorer-table td:last-child {
|
|
3364
|
+
width: 54px;
|
|
3365
|
+
text-align: center;
|
|
3366
|
+
}
|
|
3367
|
+
|
|
3368
|
+
.vgai-light-explorer-sort.vgai-btn,
|
|
3369
|
+
.vgai-light-explorer-name.vgai-btn {
|
|
3370
|
+
justify-content: flex-start;
|
|
3371
|
+
min-width: 0;
|
|
3372
|
+
padding-inline: 0;
|
|
3373
|
+
}
|
|
3374
|
+
|
|
3375
|
+
.vgai-light-explorer-name.vgai-btn {
|
|
3376
|
+
width: 100%;
|
|
3377
|
+
color: var(--vgai-content-primary);
|
|
3378
|
+
}
|
|
3379
|
+
|
|
3380
|
+
.vgai-light-explorer-type,
|
|
3381
|
+
.vgai-light-explorer-color span {
|
|
3382
|
+
color: var(--vgai-content-muted);
|
|
3383
|
+
font-family: var(--vgai-font-mono);
|
|
3384
|
+
font-size: var(--vgai-font-small);
|
|
3385
|
+
}
|
|
3386
|
+
|
|
3387
|
+
.vgai-light-explorer-color {
|
|
3388
|
+
display: flex;
|
|
3389
|
+
align-items: center;
|
|
3390
|
+
gap: var(--vgai-space-2);
|
|
3391
|
+
white-space: nowrap;
|
|
3392
|
+
}
|
|
3393
|
+
|
|
3394
|
+
.vgai-light-explorer-table .vgai-number-input {
|
|
3395
|
+
width: 86px;
|
|
3396
|
+
}
|
|
3397
|
+
|
|
3398
|
+
.vgai-light-explorer-unavailable {
|
|
3399
|
+
color: var(--vgai-content-dim);
|
|
3400
|
+
}
|
|
3401
|
+
|
|
3402
|
+
.vgai-light-explorer-empty {
|
|
3403
|
+
padding: var(--vgai-space-4);
|
|
3404
|
+
color: var(--vgai-content-muted);
|
|
3405
|
+
font-style: italic;
|
|
3406
|
+
}
|
|
3407
|
+
|
|
3408
|
+
/* ---------------------------------------------------------------------- */
|
|
3409
|
+
/* Reduced motion. Color/opacity fades elsewhere are not vestibular */
|
|
3410
|
+
/* triggers and stay; this gates the genuine motion: continuous rotation, */
|
|
3411
|
+
/* the flashing build-log cursor, and the resize-handle scale transition */
|
|
3412
|
+
/* (the widened hover state itself stays — instant, not animated). */
|
|
3413
|
+
/* ---------------------------------------------------------------------- */
|
|
3414
|
+
|
|
3415
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3416
|
+
.vgai-anim-spin,
|
|
3417
|
+
.vgai-state-surface[data-tone="loading"] .vgai-state-surface-icon {
|
|
3418
|
+
/* Stepped rotation still reads as activity without continuous motion. */
|
|
3419
|
+
animation-duration: 1.6s;
|
|
3420
|
+
animation-timing-function: steps(8, end);
|
|
3421
|
+
}
|
|
3422
|
+
.vgai-anim-blink {
|
|
3423
|
+
animation: none;
|
|
3424
|
+
opacity: 1;
|
|
3425
|
+
}
|
|
3426
|
+
.vgai-resize-handle::before {
|
|
3427
|
+
transition-property: background-color;
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
|
|
3431
|
+
/* Project-work conflict/stale notice — a ghost text-button in warning ink
|
|
3432
|
+
(stylesheet re-scope; inline Button color is guard-banned). */
|
|
3433
|
+
.vgai-project-work-conflict {
|
|
3434
|
+
color: var(--vgai-warn);
|
|
3435
|
+
font-size: var(--vgai-font-sm);
|
|
3436
|
+
text-align: left;
|
|
3437
|
+
}
|