@digithings-ai/ui 0.0.0-stage → 0.1.0
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/README.md +48 -2
- package/package.json +143 -4
- package/src/components/NavShell.tsx +776 -0
- package/src/components/SocialRow.tsx +87 -0
- package/src/components/Spinner.tsx +27 -0
- package/src/components/StackLogo.tsx +40 -0
- package/src/components/Terminal.tsx +110 -0
- package/src/components/TerminalManifest.tsx +212 -0
- package/src/components/ThemeProvider.tsx +271 -0
- package/src/components/account/AuthCard.tsx +309 -0
- package/src/components/assistant-ui/elements/mermaid-diagram.aui.tsx +63 -0
- package/src/components/assistant-ui/elements/mermaid-diagram.tsx +340 -0
- package/src/components/brand/BrandWordmark.tsx +32 -0
- package/src/components/changelog/ReleaseRail.tsx +81 -0
- package/src/components/changelog/index.ts +1 -0
- package/src/components/chat/ChatCodeBlock.tsx +67 -0
- package/src/components/chat/ChatMarkdown.tsx +66 -0
- package/src/components/chat/ChatMarkdownSource.tsx +203 -0
- package/src/components/chat/ChatMermaidBlock.tsx +202 -0
- package/src/components/chat/ChatMessage.tsx +77 -0
- package/src/components/chat/ChatPlayback.tsx +422 -0
- package/src/components/chat/ChatStreamCursor.tsx +25 -0
- package/src/components/chat/ChatThinking.tsx +113 -0
- package/src/components/chat/ChatToolCall.tsx +190 -0
- package/src/components/chat/ChatTranscript.tsx +60 -0
- package/src/components/chat/ChatWidgetFrame.tsx +107 -0
- package/src/components/chat/DigichatBootLoader.tsx +683 -0
- package/src/components/chat/DigichatLauncher.tsx +361 -0
- package/src/components/chat/DigichatThread.tsx +118 -0
- package/src/components/chat/DigichatThreadList.tsx +54 -0
- package/src/components/chat/DigichatWordmark.tsx +24 -0
- package/src/components/chat/DotMatrix.tsx +650 -0
- package/src/components/chat/boot-lab.tsx +766 -0
- package/src/components/chat/boot-signal.ts +144 -0
- package/src/components/chat/chat-surfaces.ts +52 -0
- package/src/components/chat/connection-status.ts +40 -0
- package/src/components/chat/digichat-wordmark.ts +355 -0
- package/src/components/chat/disclosure-chevron.tsx +49 -0
- package/src/components/chat/followable-href.ts +9 -0
- package/src/components/chat/gallery-thread/action-icons.tsx +25 -0
- package/src/components/chat/gallery-thread/attachment.aui.tsx +262 -0
- package/src/components/chat/gallery-thread/block-caret.tsx +439 -0
- package/src/components/chat/gallery-thread/cn.ts +1 -0
- package/src/components/chat/gallery-thread/composer-keyboard.ts +106 -0
- package/src/components/chat/gallery-thread/composer-trigger-popover.aui.tsx +235 -0
- package/src/components/chat/gallery-thread/css.d.ts +6 -0
- package/src/components/chat/gallery-thread/file.tsx +238 -0
- package/src/components/chat/gallery-thread/follow-up-suggestions.aui.tsx +92 -0
- package/src/components/chat/gallery-thread/format-json-dump.ts +112 -0
- package/src/components/chat/gallery-thread/hooks/use-attachment-src.ts +46 -0
- package/src/components/chat/gallery-thread/hooks/use-copy-to-clipboard.ts +9 -0
- package/src/components/chat/gallery-thread/image.tsx +519 -0
- package/src/components/chat/gallery-thread/markdown-text.tsx +278 -0
- package/src/components/chat/gallery-thread/message-error.aui.tsx +105 -0
- package/src/components/chat/gallery-thread/message-timing.aui.tsx +143 -0
- package/src/components/chat/gallery-thread/private-work-step.tsx +188 -0
- package/src/components/chat/gallery-thread/reasoning.tsx +332 -0
- package/src/components/chat/gallery-thread/scroll-mode.ts +174 -0
- package/src/components/chat/gallery-thread/source.tsx +76 -0
- package/src/components/chat/gallery-thread/thread.aui.tsx +1619 -0
- package/src/components/chat/gallery-thread/tooltip-icon-button.tsx +53 -0
- package/src/components/chat/gallery-thread/typed-welcome-copy.tsx +18 -0
- package/src/components/chat/gallery-thread/ui/tooltip.tsx +22 -0
- package/src/components/chat/gallery-thread/work-chain-summary.tsx +48 -0
- package/src/components/chat/gallery-thread/work-chain.tsx +110 -0
- package/src/components/chat/gallery-thread/work-status.ts +66 -0
- package/src/components/chat/overlay-scrollbar.tsx +86 -0
- package/src/components/chat/sanitize-mermaid-svg.ts +38 -0
- package/src/components/chat/skins/SOURCE.md +36 -0
- package/src/components/chat/skins/base/attachment.aui.tsx +287 -0
- package/src/components/chat/skins/base/aui-default/README.md +45 -0
- package/src/components/chat/skins/base/aui-default/collapsible-root.tsx +19 -0
- package/src/components/chat/skins/base/aui-default/collapsible.tsx +21 -0
- package/src/components/chat/skins/base/aui-default/reasoning.aui.tsx +120 -0
- package/src/components/chat/skins/base/aui-default/reasoning.tsx +331 -0
- package/src/components/chat/skins/base/aui-default/surfaces.ts +7 -0
- package/src/components/chat/skins/base/aui-default/tool-fallback.aui.tsx +772 -0
- package/src/components/chat/skins/base/aui-default/tool-group.aui.tsx +241 -0
- package/src/components/chat/skins/base/docs-model-options.ts +6 -0
- package/src/components/chat/skins/base/elements/assistant-trace.aui.tsx +169 -0
- package/src/components/chat/skins/base/elements/composer-trigger-popover.aui.tsx +271 -0
- package/src/components/chat/skins/base/elements/directive-text.aui.tsx +29 -0
- package/src/components/chat/skins/base/elements/directive-text.tsx +76 -0
- package/src/components/chat/skins/base/elements/message-timing.aui.tsx +104 -0
- package/src/components/chat/skins/base/elements/model-selector.aui.tsx +140 -0
- package/src/components/chat/skins/base/elements/model-selector.tsx +720 -0
- package/src/components/chat/skins/base/elements/quote.aui.tsx +290 -0
- package/src/components/chat/skins/base/elements/work-chain.tsx +100 -0
- package/src/components/chat/skins/base/markdown-text.tsx +294 -0
- package/src/components/chat/skins/base/model.ts +1 -0
- package/src/components/chat/skins/base/thread.tsx +1050 -0
- package/src/components/chat/skins/base/tooltip-icon-button.tsx +56 -0
- package/src/components/chat/skins/base/ui/avatar.tsx +115 -0
- package/src/components/chat/skins/base/ui/badge.tsx +51 -0
- package/src/components/chat/skins/base/ui/button.tsx +67 -0
- package/src/components/chat/skins/base/ui/command.tsx +185 -0
- package/src/components/chat/skins/base/ui/dialog.tsx +168 -0
- package/src/components/chat/skins/base/ui/dot-matrix.tsx +267 -0
- package/src/components/chat/skins/base/ui/popover.tsx +97 -0
- package/src/components/chat/skins/base/ui/skeleton.tsx +20 -0
- package/src/components/chat/skins/base/ui/textarea.tsx +24 -0
- package/src/components/chat/skins/base/ui/tooltip.tsx +73 -0
- package/src/components/chat/skins/base-assistant-ui/config-provider.tsx +90 -0
- package/src/components/chat/skins/base-assistant-ui/defaults.ts +419 -0
- package/src/components/chat/skins/base-assistant-ui/index.tsx +44 -0
- package/src/components/chat/skins/chatgpt.tsx +448 -0
- package/src/components/chat/skins/claude.tsx +380 -0
- package/src/components/chat/skins/digichat-composer-toolbar.tsx +151 -0
- package/src/components/chat/skins/digichat-context-meter-shares.ts +158 -0
- package/src/components/chat/skins/digichat-context-meter.tsx +243 -0
- package/src/components/chat/skins/digichat-meter-tone.ts +26 -0
- package/src/components/chat/skins/digichat-usage-meter.tsx +103 -0
- package/src/components/chat/skins/digichat.tsx +144 -0
- package/src/components/chat/skins/expo-react-native.tsx +29 -0
- package/src/components/chat/skins/gemini.tsx +322 -0
- package/src/components/chat/skins/grok-icon.tsx +34 -0
- package/src/components/chat/skins/grok.tsx +369 -0
- package/src/components/chat/skins/index.ts +46 -0
- package/src/components/chat/skins/perplexity.tsx +462 -0
- package/src/components/chat/skins/product-page-assistant/assistant-modal.tsx +73 -0
- package/src/components/chat/skins/product-page-assistant/index.tsx +19 -0
- package/src/components/chat/skins/product-page-assistant/product-dashboard.tsx +164 -0
- package/src/components/chat/skins/react-ink.tsx +97 -0
- package/src/components/chat/skins/thread-skin-host-contract.ts +102 -0
- package/src/components/chat/skins/thread-skin-view.tsx +156 -0
- package/src/components/chat/skins/thread-skins.ts +143 -0
- package/src/components/chat/skins/tooltip-icon-button.tsx +35 -0
- package/src/components/chat/skins/ui/dropdown-menu.tsx +272 -0
- package/src/components/chat/skins/webpage-assistant/assistant-config.ts +238 -0
- package/src/components/chat/skins/webpage-assistant/assistant-modal.tsx +78 -0
- package/src/components/chat/skins/webpage-assistant/config-provider.tsx +132 -0
- package/src/components/chat/skins/webpage-assistant/docs-app.tsx +106 -0
- package/src/components/chat/skins/webpage-assistant/docs-article.tsx +109 -0
- package/src/components/chat/skins/webpage-assistant/docs-assistant.tsx +73 -0
- package/src/components/chat/skins/webpage-assistant/docs-nav.tsx +81 -0
- package/src/components/chat/skins/webpage-assistant/host-ui.ts +79 -0
- package/src/components/chat/skins/webpage-assistant/index.tsx +12 -0
- package/src/components/chat/skins/webpage-assistant/markdown-page.tsx +11 -0
- package/src/components/chat/skins/webpage-assistant/pages.ts +9 -0
- package/src/components/chat/skins/webpage-assistant/types.ts +178 -0
- package/src/components/chat/skins/webpage-assistant/use-mobile.ts +19 -0
- package/src/components/chat/stock/SOURCE.md +90 -0
- package/src/components/chat/stock/artifacts-panel.tsx +305 -0
- package/src/components/chat/stock/attachment.aui.tsx +280 -0
- package/src/components/chat/stock/chat-notice.tsx +143 -0
- package/src/components/chat/stock/chat-private-mode.tsx +64 -0
- package/src/components/chat/stock/deploy-ui-context.tsx +89 -0
- package/src/components/chat/stock/embed-chat-prefs.tsx +471 -0
- package/src/components/chat/stock/file.tsx +265 -0
- package/src/components/chat/stock/follow-up-suggestions.aui.tsx +83 -0
- package/src/components/chat/stock/image.tsx +531 -0
- package/src/components/chat/stock/index.ts +129 -0
- package/src/components/chat/stock/json-view.tsx +140 -0
- package/src/components/chat/stock/markdown-text.tsx +319 -0
- package/src/components/chat/stock/message-error.aui.tsx +96 -0
- package/src/components/chat/stock/message-export-menu.tsx +156 -0
- package/src/components/chat/stock/palette-row-preview.tsx +26 -0
- package/src/components/chat/stock/reasoning.aui.tsx +120 -0
- package/src/components/chat/stock/reasoning.tsx +335 -0
- package/src/components/chat/stock/skin-chrome.tsx +81 -0
- package/src/components/chat/stock/skin-credit.tsx +63 -0
- package/src/components/chat/stock/skin-palette-bridge.tsx +235 -0
- package/src/components/chat/stock/skin-palette-context.ts +16 -0
- package/src/components/chat/stock/skin-runtime.tsx +52 -0
- package/src/components/chat/stock/skin-slash-palette.tsx +393 -0
- package/src/components/chat/stock/skin-types.ts +217 -0
- package/src/components/chat/stock/stock-chat-prefs-host.tsx +501 -0
- package/src/components/chat/stock/stock-send-gate.tsx +94 -0
- package/src/components/chat/stock/stock-shape.tsx +39 -0
- package/src/components/chat/stock/thread.aui.tsx +645 -0
- package/src/components/chat/stock/tool-display.ts +6 -0
- package/src/components/chat/stock/tool-fallback.aui.tsx +866 -0
- package/src/components/chat/stock/tool-group.aui.tsx +244 -0
- package/src/components/chat/stock/tool-surface.ts +120 -0
- package/src/components/chat/stock/tooltip-icon-button.tsx +49 -0
- package/src/components/chat/stock/ui/avatar.tsx +108 -0
- package/src/components/chat/stock/ui/button.tsx +81 -0
- package/src/components/chat/stock/ui/collapsible.tsx +21 -0
- package/src/components/chat/stock/ui/dialog.tsx +163 -0
- package/src/components/chat/stock/ui/skeleton.tsx +13 -0
- package/src/components/chat/stock/ui/textarea.tsx +20 -0
- package/src/components/chat/stock/ui/tooltip.tsx +68 -0
- package/src/components/chat/stock/use-attachment-src.ts +42 -0
- package/src/components/chat/stock/use-copy-to-clipboard.ts +29 -0
- package/src/components/chat/strip-model-boilerplate.ts +42 -0
- package/src/components/chat/suggestion-cycle.tsx +230 -0
- package/src/components/chat/suggestion-scroll-row.tsx +81 -0
- package/src/components/chat/trace-grouping/chain-group-by.ts +44 -0
- package/src/components/chat/trace-grouping/chain-state.ts +141 -0
- package/src/components/chat/trace-grouping/index.ts +32 -0
- package/src/components/chat/trace-grouping/tool-row.ts +74 -0
- package/src/components/chat/trace-grouping/use-deploy-work-disclosure.ts +35 -0
- package/src/components/chat/trace-grouping/use-work-chain.ts +103 -0
- package/src/components/chat/trace-i18n/core.ts +48 -0
- package/src/components/chat/trace-i18n/index.tsx +23 -0
- package/src/components/chat/trace-i18n/locales/en.ts +24 -0
- package/src/components/chat/trace-i18n/locales/fr.ts +28 -0
- package/src/components/chat/trace-i18n/types.ts +35 -0
- package/src/components/chat/trace-spacing.ts +249 -0
- package/src/components/chat/transcript/activity-view.ts +375 -0
- package/src/components/chat/transcript/chat-export.ts +133 -0
- package/src/components/chat/transcript/index.ts +10 -0
- package/src/components/chat/transcript/save-file.ts +209 -0
- package/src/components/chat/transcript/transcript-markdown.ts +428 -0
- package/src/components/chat/transcript/types.ts +81 -0
- package/src/components/chat/turn-outcome.ts +52 -0
- package/src/components/chat/use-warmup-phase.ts +18 -0
- package/src/components/chat/work-status-lead.tsx +49 -0
- package/src/components/chrome.tsx +264 -0
- package/src/components/command-palette/CommandPalette.tsx +404 -0
- package/src/components/command-palette/index.ts +6 -0
- package/src/components/contact/ContactMailto.tsx +112 -0
- package/src/components/contact/index.ts +5 -0
- package/src/components/conviction/ConvictionMeter.tsx +40 -0
- package/src/components/conviction/SignedConvictionBadge.tsx +26 -0
- package/src/components/conviction/index.ts +7 -0
- package/src/components/data-layout/BentoGrid.tsx +52 -0
- package/src/components/data-layout/CardRail.tsx +150 -0
- package/src/components/data-layout/DotMatrixStat.tsx +65 -0
- package/src/components/data-layout/FeatureCell.tsx +80 -0
- package/src/components/data-layout/MediaFrame.tsx +125 -0
- package/src/components/data-layout/ModuleGrid.tsx +735 -0
- package/src/components/data-layout/Odometer.tsx +149 -0
- package/src/components/data-layout/ProductFrame.tsx +79 -0
- package/src/components/data-layout/TestimonialWall.tsx +139 -0
- package/src/components/data-layout/index.ts +19 -0
- package/src/components/data-layout/treemap.ts +368 -0
- package/src/components/deck/DeckStack.tsx +243 -0
- package/src/components/desk/DataTable.tsx +373 -0
- package/src/components/desk/KpiGrid.tsx +80 -0
- package/src/components/desk/Sparkline.tsx +63 -0
- package/src/components/desk/StateBlock.tsx +132 -0
- package/src/components/desk/index.ts +18 -0
- package/src/components/diagrams/ArchitectureDiagram.tsx +350 -0
- package/src/components/diagrams/ArchitectureTour.tsx +912 -0
- package/src/components/diagrams/TerminalSchematic.tsx +192 -0
- package/src/components/diagrams/architecture-svg.tsx +384 -0
- package/src/components/diagrams/index.ts +30 -0
- package/src/components/diagrams/mermaid-theme.ts +115 -0
- package/src/components/diagrams/tour-camera.ts +171 -0
- package/src/components/docs/CodeTabs.tsx +90 -0
- package/src/components/docs/CopyCommand.tsx +151 -0
- package/src/components/docs/DocsLayout.tsx +197 -0
- package/src/components/docs/DocsSearch.tsx +97 -0
- package/src/components/docs/Endpoint.tsx +135 -0
- package/src/components/document/DocumentFrame.tsx +43 -0
- package/src/components/document/GlyphList.tsx +51 -0
- package/src/components/document/PageTitle.tsx +44 -0
- package/src/components/document/Prose.tsx +38 -0
- package/src/components/document/Section.tsx +55 -0
- package/src/components/document/index.ts +13 -0
- package/src/components/effects-chrome/AnnouncementBar.tsx +88 -0
- package/src/components/effects-chrome/HorizontalScrollTrack.tsx +461 -0
- package/src/components/effects-chrome/Pipeline.tsx +226 -0
- package/src/components/effects-chrome/RotatingPrompts.tsx +116 -0
- package/src/components/effects-chrome/StackingPanels.tsx +101 -0
- package/src/components/effects-chrome/TabStrip.tsx +232 -0
- package/src/components/effects-chrome/ToastStack.tsx +201 -0
- package/src/components/effects-chrome/horizontal-track-core.ts +70 -0
- package/src/components/effects-chrome/index.ts +35 -0
- package/src/components/emblems.tsx +188 -0
- package/src/components/faviconTheme.ts +23 -0
- package/src/components/figure/Figure.tsx +38 -0
- package/src/components/figure/index.ts +2 -0
- package/src/components/finance-charts/DrawdownPlot.tsx +76 -0
- package/src/components/finance-charts/EquityCurve.tsx +71 -0
- package/src/components/finance-charts/PriceChart.tsx +119 -0
- package/src/components/finance-charts/chart-host.tsx +236 -0
- package/src/components/finance-charts/chart-scale.ts +93 -0
- package/src/components/finance-charts/demo-data.ts +88 -0
- package/src/components/finance-charts/index.ts +46 -0
- package/src/components/finance-charts/lw-chart.tsx +292 -0
- package/src/components/finance-composites/MarketBar.tsx +243 -0
- package/src/components/finance-composites/OrderBook.tsx +133 -0
- package/src/components/finance-composites/PerformanceDashboard.tsx +185 -0
- package/src/components/finance-composites/SortableTable.tsx +144 -0
- package/src/components/finance-composites/StockTicker.tsx +65 -0
- package/src/components/finance-composites/SyncedTearsheet.tsx +226 -0
- package/src/components/finance-composites/index.ts +28 -0
- package/src/components/finance-tearsheet/KpiStrip.tsx +49 -0
- package/src/components/finance-tearsheet/LiveBadge.tsx +29 -0
- package/src/components/finance-tearsheet/ReturnsMatrix.tsx +321 -0
- package/src/components/finance-tearsheet/StrategyTearsheet.tsx +99 -0
- package/src/components/finance-tearsheet/TearsheetCard.tsx +54 -0
- package/src/components/finance-tearsheet/TradeLogTable.tsx +73 -0
- package/src/components/finance-tearsheet/charts.tsx +2624 -0
- package/src/components/finance-tearsheet/demo-data.ts +177 -0
- package/src/components/finance-tearsheet/format.ts +41 -0
- package/src/components/finance-tearsheet/index.ts +120 -0
- package/src/components/finance-tearsheet/print.ts +52 -0
- package/src/components/finance-tearsheet/risk-bands.ts +48 -0
- package/src/components/finance-tearsheet/stats.ts +35 -0
- package/src/components/finance-tearsheet/strategy-sheet-model.ts +238 -0
- package/src/components/finance-tearsheet/types.ts +58 -0
- package/src/components/footer/FooterCells.tsx +109 -0
- package/src/components/footer/index.ts +6 -0
- package/src/components/graph.tsx +158 -0
- package/src/components/icons.tsx +98 -0
- package/src/components/landing/PixelWordmark.tsx +36 -0
- package/src/components/logos.ts +39 -0
- package/src/components/marquee/Marquee.tsx +204 -0
- package/src/components/metrics/PerfMetrics.tsx +68 -0
- package/src/components/metrics/StatCounter.tsx +104 -0
- package/src/components/page-geometry.tsx +177 -0
- package/src/components/pricing/Pricing.tsx +174 -0
- package/src/components/pricing/PricingMatrix.tsx +219 -0
- package/src/components/prose/index.ts +2 -0
- package/src/components/prose/prose.tsx +86 -0
- package/src/components/repo-activity/RepoActivity.tsx +599 -0
- package/src/components/repo-activity/RepoHeatmap.tsx +225 -0
- package/src/components/repo-activity/demo.ts +201 -0
- package/src/components/repo-activity/fetch.ts +211 -0
- package/src/components/repo-activity/heatmap.ts +123 -0
- package/src/components/repo-activity/index.ts +28 -0
- package/src/components/repo-activity/types.ts +99 -0
- package/src/components/stages/NumberedStages.tsx +116 -0
- package/src/components/symbols/marks.tsx +116 -0
- package/src/components/symbols/terminal-lockup.tsx +136 -0
- package/src/components/symbols/terminal-marks.tsx +226 -0
- package/src/components/terminal/ChatResponseLoader.tsx +67 -0
- package/src/components/terminal/ContainerBootLoader.tsx +82 -0
- package/src/components/terminal/TerminalStepCaret.tsx +202 -0
- package/src/components/themeInit.ts +24 -0
- package/src/components/typography/MotionReveal.tsx +108 -0
- package/src/components/typography/TypewriterReveal.tsx +101 -0
- package/src/components/typography/WordReveal.tsx +143 -0
- package/src/data/modules.ts +378 -0
- package/src/data/subsystems.ts +101 -0
- package/src/index.ts +587 -0
- package/src/lib/base-path.ts +60 -0
- package/src/lib/cx.ts +25 -0
- package/src/lib/gloomberb.ts +69 -0
- package/src/lib/record.ts +19 -0
- package/src/lib/stub-payload.ts +183 -0
- package/src/lib/useBodyScrollLock.ts +44 -0
- package/src/lib/utils.ts +6 -0
- package/src/motion/primitives.tsx +105 -0
- package/src/motion/scroll-glide.ts +62 -0
- package/src/motion/scrolly-core.ts +38 -0
- package/src/motion/scrolly.tsx +95 -0
- package/src/navigation/HashScrollManager.tsx +167 -0
- package/src/navigation/hashScroll.ts +78 -0
- package/src/replay/browser.ts +280 -0
- package/src/replay/chat-export-run.ts +121 -0
- package/src/replay/export-format.ts +25 -0
- package/src/replay/export-mount.ts +32 -0
- package/src/replay/filename.ts +54 -0
- package/src/replay/index.ts +21 -0
- package/src/replay/redact-dom.ts +178 -0
- package/src/replay/redact.ts +113 -0
- package/src/replay/snapshot.ts +659 -0
- package/src/styles/account-auth.css +339 -0
- package/src/styles/brand-wordmark.css +11 -0
- package/src/styles/card-rail.css +120 -0
- package/src/styles/chat-aui.css +1143 -0
- package/src/styles/chat-core.css +469 -0
- package/src/styles/chat-digichat.css +2531 -0
- package/src/styles/chat-math.css +70 -0
- package/src/styles/chat-skin-palette.css +138 -0
- package/src/styles/chat-stock-menu.css +37 -0
- package/src/styles/chat-widgets.css +190 -0
- package/src/styles/command-palette.css +372 -0
- package/src/styles/controls-core.css +2261 -0
- package/src/styles/controls-overlay.css +603 -0
- package/src/styles/data-layout.css +288 -0
- package/src/styles/deck.css +141 -0
- package/src/styles/diagrams.css +1860 -0
- package/src/styles/digichat-app-theme.css +250 -0
- package/src/styles/digichat-boot-loader.css +487 -0
- package/src/styles/digichat-launcher.css +377 -0
- package/src/styles/docs.css +165 -0
- package/src/styles/effects-chrome.css +888 -0
- package/src/styles/finance-composites.css +214 -0
- package/src/styles/finance-tearsheet-overlay.css +90 -0
- package/src/styles/finance-tearsheet.css +945 -0
- package/src/styles/marquee.css +168 -0
- package/src/styles/metrics.css +82 -0
- package/src/styles/nav-shell.css +551 -0
- package/src/styles/pricing.css +79 -0
- package/src/styles/repo-activity.css +575 -0
- package/src/styles/stages.css +69 -0
- package/src/styles/terminal-loaders.css +122 -0
- package/src/styles/terminal-manifest.css +228 -0
- package/src/styles/web-theme.css +1007 -0
- package/src/styles/word-reveal.css +204 -0
- package/src/theme/apply-theme.ts +214 -0
- package/src/theme/index.ts +27 -0
- package/src/theme/palette-registry.ts +855 -0
- package/src/theme/tui-prefs.ts +64 -0
- package/src/ui/alert.tsx +78 -0
- package/src/ui/avatar.tsx +104 -0
- package/src/ui/badge.tsx +75 -0
- package/src/ui/breadcrumb.tsx +61 -0
- package/src/ui/button.tsx +67 -0
- package/src/ui/card.tsx +139 -0
- package/src/ui/checkbox.tsx +27 -0
- package/src/ui/collapsible.tsx +32 -0
- package/src/ui/date-pager.tsx +325 -0
- package/src/ui/dialog.tsx +157 -0
- package/src/ui/dropdown-menu.tsx +267 -0
- package/src/ui/empty-state.tsx +165 -0
- package/src/ui/field.tsx +104 -0
- package/src/ui/form.tsx +36 -0
- package/src/ui/icon-button.tsx +36 -0
- package/src/ui/index.ts +34 -0
- package/src/ui/input.tsx +33 -0
- package/src/ui/kbd.tsx +30 -0
- package/src/ui/label.tsx +32 -0
- package/src/ui/pager.tsx +119 -0
- package/src/ui/pagination.tsx +126 -0
- package/src/ui/radio-group.tsx +51 -0
- package/src/ui/search-bar.tsx +85 -0
- package/src/ui/segmented-control.tsx +76 -0
- package/src/ui/select.tsx +257 -0
- package/src/ui/separator.tsx +24 -0
- package/src/ui/sheet.tsx +141 -0
- package/src/ui/skeleton.tsx +76 -0
- package/src/ui/slider.tsx +76 -0
- package/src/ui/switch.tsx +31 -0
- package/src/ui/table.tsx +179 -0
- package/src/ui/tabs.tsx +89 -0
- package/src/ui/tags-input.tsx +168 -0
- package/src/ui/textarea.tsx +17 -0
- package/src/ui/tooltip.tsx +71 -0
|
@@ -0,0 +1,1860 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* diagrams.css — the architecture-diagram family.
|
|
3
|
+
*
|
|
4
|
+
* The mermaid SVG brings its own inline stylesheet, so this file does two jobs
|
|
5
|
+
* only:
|
|
6
|
+
* 1. FRAME the figure (border, surface, caption, source fallback) in the same
|
|
7
|
+
* hairline grammar as every other figure on the site.
|
|
8
|
+
* 2. RE-ASSERT the tokens mermaid cannot know about. Its architecture
|
|
9
|
+
* stylesheet hardcodes `#fff` for service label text, which is correct on
|
|
10
|
+
* the dark canon palette by luck and wrong on the light one, and it draws
|
|
11
|
+
* group borders dashed by default — the boundary is a solid box in this
|
|
12
|
+
* system.
|
|
13
|
+
*
|
|
14
|
+
* Import once in an app's globals.css, after web-theme.css:
|
|
15
|
+
* @import "@digithings-ai/ui/styles/diagrams.css";
|
|
16
|
+
* and add the source path so Tailwind sees the family:
|
|
17
|
+
* @source "<path-to>/packages/ui/src/components/diagrams";
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
.arch-figure {
|
|
21
|
+
/* Component sizing tokens. The figure is retunable from here; hairlines and
|
|
22
|
+
the pending floor stay literal (a fractional hairline rounds away, and the
|
|
23
|
+
floor is measured against the tallest placeholder, not a fluid ramp). */
|
|
24
|
+
--figure-gap: 0.6rem;
|
|
25
|
+
--figure-pad: 1.1rem;
|
|
26
|
+
--figure-pending-min-h: 14rem;
|
|
27
|
+
--figure-source-pad-block: var(--space-3);
|
|
28
|
+
--figure-source-pad-inline: 1.1rem;
|
|
29
|
+
--figure-source-size: 0.72rem;
|
|
30
|
+
--figure-source-leading: 1.6;
|
|
31
|
+
--figure-caption-size: 0.68rem;
|
|
32
|
+
--figure-caption-leading: var(--leading, 1.55);
|
|
33
|
+
--figure-svg-text-size: var(--text-xs, 11px);
|
|
34
|
+
--figure-svg-tracking: 0.02em;
|
|
35
|
+
margin: 0;
|
|
36
|
+
display: flex;
|
|
37
|
+
flex-direction: column;
|
|
38
|
+
gap: var(--figure-gap);
|
|
39
|
+
min-width: 0;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.arch-figure__body {
|
|
43
|
+
min-width: 0;
|
|
44
|
+
overflow-x: auto;
|
|
45
|
+
border: 1px solid var(--hair);
|
|
46
|
+
background: var(--surface);
|
|
47
|
+
padding: var(--figure-pad);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.arch-figure[data-state="pending"] .arch-figure__body {
|
|
51
|
+
min-height: var(--figure-pending-min-h);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.arch-figure__body > svg {
|
|
55
|
+
display: block;
|
|
56
|
+
width: 100%;
|
|
57
|
+
height: auto;
|
|
58
|
+
max-width: 100%;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.arch-figure__source {
|
|
62
|
+
margin: 0;
|
|
63
|
+
padding: var(--figure-source-pad-block) var(--figure-source-pad-inline);
|
|
64
|
+
border: 1px solid var(--hair);
|
|
65
|
+
background: var(--surface);
|
|
66
|
+
font-family: var(--font-mono);
|
|
67
|
+
font-size: var(--figure-source-size);
|
|
68
|
+
line-height: var(--figure-source-leading);
|
|
69
|
+
color: var(--ink-soft);
|
|
70
|
+
overflow-x: auto;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.arch-figure__caption {
|
|
74
|
+
margin: 0;
|
|
75
|
+
font-family: var(--font-mono);
|
|
76
|
+
font-size: var(--figure-caption-size);
|
|
77
|
+
line-height: var(--figure-caption-leading);
|
|
78
|
+
color: var(--ink-mute);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* mermaid's own chrome, brought back onto the palette. */
|
|
82
|
+
.arch-figure__body svg text,
|
|
83
|
+
.arch-figure__body svg .node-icon-text > div {
|
|
84
|
+
font-family: var(--font-mono);
|
|
85
|
+
color: var(--ink);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.arch-figure__body svg .node-icon-text > div {
|
|
89
|
+
fill: var(--ink);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.arch-figure__body svg .node-bkg {
|
|
93
|
+
stroke-dasharray: none;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/*
|
|
97
|
+
* mermaid's architecture chrome, forced back onto the palette.
|
|
98
|
+
*
|
|
99
|
+
* These need `!important` and that is not sloppiness: mermaid injects its own
|
|
100
|
+
* stylesheet from inside the rendered SVG, so it lands later in the document
|
|
101
|
+
* than this file and out-ranks it in source order. The icon plates are worse —
|
|
102
|
+
* they are drawn by mermaid's bundled icon set as an inline `style="fill:#087ebf"`
|
|
103
|
+
* on the plate rect, which nothing short of `!important` can reach.
|
|
104
|
+
*
|
|
105
|
+
* The icon plate is the only place a vendor-blue can appear, and it appears on
|
|
106
|
+
* every service, so leaving it is the difference between a canon diagram and a
|
|
107
|
+
* screenshot of one. If mermaid ever changes the built-in icon palette these
|
|
108
|
+
* overrides stop matching and the diagram reverts to mermaid's own colour —
|
|
109
|
+
* degraded, never broken.
|
|
110
|
+
*/
|
|
111
|
+
.arch-figure__body svg svg rect[width="80"],
|
|
112
|
+
.arch-figure__body svg svg rect[width="60"] {
|
|
113
|
+
fill: color-mix(in srgb, var(--ink) 9%, var(--surface)) !important;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.arch-figure__body svg svg circle,
|
|
117
|
+
.arch-figure__body svg svg path,
|
|
118
|
+
.arch-figure__body svg svg line,
|
|
119
|
+
.arch-figure__body svg svg polyline,
|
|
120
|
+
.arch-figure__body svg svg polygon {
|
|
121
|
+
stroke: var(--ink) !important;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/* the boundary is a rule in this system, not a dashed sketch. */
|
|
125
|
+
.arch-figure__body svg .node-bkg {
|
|
126
|
+
stroke-dasharray: none !important;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/*
|
|
130
|
+
* Terminal polish. The owner: "make it more still terminal look simplicity but
|
|
131
|
+
* still modern polish". mermaid's default chrome is a soft floating glyph on an
|
|
132
|
+
* unfilled plate; the house grammar is a stamped chip on a hairline, square, in
|
|
133
|
+
* the mono ramp — so the plate gets a border, and the type goes on the ramp
|
|
134
|
+
* rather than mermaid's own family.
|
|
135
|
+
*/
|
|
136
|
+
.arch-figure__body svg svg rect[width="80"],
|
|
137
|
+
.arch-figure__body svg svg rect[width="60"] {
|
|
138
|
+
stroke: var(--hair) !important;
|
|
139
|
+
stroke-width: 1 !important;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/*
|
|
143
|
+
* The icon is a fixed 80px plate in an 80px cell and mermaid draws the label on
|
|
144
|
+
* its bottom edge, so at full size each node reads as a wall of squares with the
|
|
145
|
+
* text sitting on top of the glyph. Scaling the plate back to half its cell
|
|
146
|
+
* gives the label clear air beneath it and turns the icon into what it should be
|
|
147
|
+
* here — a small monogram beside the words, not the whole node.
|
|
148
|
+
*/
|
|
149
|
+
.arch-figure__body svg [viewBox="0 0 80 80"] {
|
|
150
|
+
transform: scale(0.5);
|
|
151
|
+
transform-origin: 50% 50%;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.arch-figure__body svg .architecture-service text {
|
|
155
|
+
font-size: var(--figure-svg-text-size);
|
|
156
|
+
letter-spacing: var(--figure-svg-tracking);
|
|
157
|
+
fill: var(--ink) !important;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/*
|
|
161
|
+
* mermaid leaves the edge labels at the browser default — nearly half again the
|
|
162
|
+
* size of a node label — which pulls the eye off the boxes and reads as clutter.
|
|
163
|
+
* Everything in the drawing sits on the same mono step.
|
|
164
|
+
*/
|
|
165
|
+
.arch-figure__body svg text {
|
|
166
|
+
font-size: var(--figure-svg-text-size);
|
|
167
|
+
letter-spacing: var(--figure-svg-tracking);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/*
|
|
171
|
+
* mermaid sizes an edge label's box to the raw string and lets it wrap, which
|
|
172
|
+
* splits a word when the box is narrow ("heartbea / t"). The label is one line
|
|
173
|
+
* of mono here, so it is allowed to be wider than the box mermaid guessed.
|
|
174
|
+
*/
|
|
175
|
+
.arch-figure__body svg foreignObject {
|
|
176
|
+
overflow: visible !important;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
.arch-figure__body svg foreignObject > div {
|
|
180
|
+
white-space: nowrap !important;
|
|
181
|
+
overflow: visible !important;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/*
|
|
185
|
+
* ── the tour ────────────────────────────────────────────────────────────────
|
|
186
|
+
* Three treatments of one diagram. Static is the frame plus the steps; the two
|
|
187
|
+
* pinned treatments park the frame and let scroll drive it. The camera element
|
|
188
|
+
* gets its transform inline from JS (measured against the rendered SVG), so the
|
|
189
|
+
* only thing CSS owns here is the frame, the rail and the easing.
|
|
190
|
+
*/
|
|
191
|
+
|
|
192
|
+
.arch-tour {
|
|
193
|
+
display: flex;
|
|
194
|
+
flex-direction: column;
|
|
195
|
+
gap: var(--tour-gap);
|
|
196
|
+
min-width: 0;
|
|
197
|
+
|
|
198
|
+
/* Component sizing tokens. Breakpoints and 1px hairlines stay literal:
|
|
199
|
+
var() cannot appear in a media condition, and a fractional hairline
|
|
200
|
+
rounds away at small sizes. Everything else is named once here and
|
|
201
|
+
consumed by the rules below, so a consumer can retune the tour without
|
|
202
|
+
editing its geometry. */
|
|
203
|
+
--tour-nav-h: var(--dq-nav-h, 4.5rem);
|
|
204
|
+
--tour-pin-gap: 1rem;
|
|
205
|
+
--tour-pin-gap-narrow: 0.5rem;
|
|
206
|
+
--tour-pin-max: 46rem;
|
|
207
|
+
--tour-head-gap: 0.5rem;
|
|
208
|
+
--tour-head-gap-narrow: 0.35rem;
|
|
209
|
+
--tour-grid-gap: 1.8rem;
|
|
210
|
+
--tour-frame-gap: 0.4rem;
|
|
211
|
+
--tour-frame-pad: 1.1rem;
|
|
212
|
+
--tour-frame-pad-top: 1.85rem;
|
|
213
|
+
--tour-frame-pad-inline: 0.85rem;
|
|
214
|
+
--tour-frame-pad-bottom: 0.85rem;
|
|
215
|
+
--tour-rail-gap: 0.9rem;
|
|
216
|
+
--tour-rail-min: 13.25rem;
|
|
217
|
+
--tour-rail-min-short: 4.5rem;
|
|
218
|
+
--tour-step-gap: 0.15rem;
|
|
219
|
+
--tour-caption-size: 0.82rem;
|
|
220
|
+
--tour-caption-leading: 1.6;
|
|
221
|
+
--tour-label-size: 0.9rem;
|
|
222
|
+
--tour-tag-inset-block: 0.42rem;
|
|
223
|
+
--tour-tag-inset-inline: 0.72rem;
|
|
224
|
+
/* Wave-1 additions: the tour rules that were still carrying raw values.
|
|
225
|
+
Nothing above is renamed or re-valued. */
|
|
226
|
+
--tour-gap: 1.6rem;
|
|
227
|
+
--tour-side-gap: 1.8rem;
|
|
228
|
+
--tour-side-row-gap: 0.6rem;
|
|
229
|
+
--tour-side-col-gap: 2.4rem;
|
|
230
|
+
--tour-static-gap: 1.2rem;
|
|
231
|
+
--tour-tag-size: 0.62rem;
|
|
232
|
+
--tour-tag-tracking: 0.1em;
|
|
233
|
+
--tour-tag-pad-block: 0.1rem;
|
|
234
|
+
--tour-tag-pad-inline: 0.45rem;
|
|
235
|
+
--tour-side-tag-gap: 0.15rem;
|
|
236
|
+
--tour-step-pad: 0.9rem;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/* Morph carries its own five values: they only apply when the variant class is
|
|
240
|
+
present, so they do not belong on every tour. */
|
|
241
|
+
.arch-tour.arch-tour-morph {
|
|
242
|
+
--tour-morph-pin-offset: 0.35rem;
|
|
243
|
+
--tour-morph-frame-pad-block: 0.55rem;
|
|
244
|
+
--tour-morph-frame-pad-inline: 0.7rem;
|
|
245
|
+
--tour-morph-svg-max: 26rem;
|
|
246
|
+
--tour-morph-svg-reserve: 19rem;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
.arch-tour__frame {
|
|
250
|
+
border: 1px solid var(--hair);
|
|
251
|
+
background: var(--surface);
|
|
252
|
+
padding: var(--tour-frame-pad);
|
|
253
|
+
min-width: 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/*
|
|
257
|
+
* One diagram per side. The stage clips, which is what lets a leaving group
|
|
258
|
+
* travel past the frame edge and disappear instead of widening the page.
|
|
259
|
+
*/
|
|
260
|
+
.arch-tour__stage {
|
|
261
|
+
position: relative;
|
|
262
|
+
overflow: hidden;
|
|
263
|
+
display: grid;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.arch-tour__pane {
|
|
267
|
+
grid-area: 1 / 1;
|
|
268
|
+
min-width: 0;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/*
|
|
272
|
+
* The swap. Each side is one group — its diagram and its own step list — so the
|
|
273
|
+
* rented group leaves to the left as a unit (list travelling with its diagram)
|
|
274
|
+
* and the owned group arrives from the right. No opacity anywhere: the two never
|
|
275
|
+
* share the frame, so nothing has to be faded in. `--arch-out` runs over the
|
|
276
|
+
* first half of the window and `--arch-in` over the second, so they pass each
|
|
277
|
+
* other off-screen rather than crossing in view.
|
|
278
|
+
*/
|
|
279
|
+
.arch-tour__side {
|
|
280
|
+
display: grid;
|
|
281
|
+
/* Two tracks: the side tag on its own row at the top, then the diagram + its
|
|
282
|
+
* step list below. Without the explicit row the tag auto-placed into the
|
|
283
|
+
* diagram's cell and landed bottom-left. */
|
|
284
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
285
|
+
gap: var(--tour-side-gap);
|
|
286
|
+
min-width: 0;
|
|
287
|
+
transition: transform 1.7s cubic-bezier(0.22, 1, 0.36, 1);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/* Each rail's progress bar reads that side's own walk, not the whole walk. */
|
|
291
|
+
.arch-tour__side:nth-child(1) .arch-tour__rail {
|
|
292
|
+
--arch-rail-p: var(--arch-r0, 0);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.arch-tour__side:nth-child(2) .arch-tour__rail {
|
|
296
|
+
--arch-rail-p: var(--arch-r1, 0);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.arch-tour__side--leaving {
|
|
300
|
+
transform: translateX(calc(var(--arch-out, 0) * -112%));
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.arch-tour__side--entering {
|
|
304
|
+
transform: translateX(calc((1 - var(--arch-in, 1)) * 112%));
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.arch-tour__camera {
|
|
308
|
+
position: relative;
|
|
309
|
+
transform-origin: 0 0;
|
|
310
|
+
/* Short follow, not a 1.6s tween: the scroll pose writes the target every
|
|
311
|
+
frame, and a long transition would lag the narration. */
|
|
312
|
+
transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
|
|
313
|
+
will-change: transform;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/* Until the tour has painted its first pose (`data-settled`, set by the
|
|
317
|
+
scroll binding), sides and camera jump straight to it rather than tweening
|
|
318
|
+
in from the CSS defaults. */
|
|
319
|
+
.arch-tour:not([data-settled]) .arch-tour__side,
|
|
320
|
+
.arch-tour:not([data-settled]) .arch-tour__camera {
|
|
321
|
+
transition: none;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* Skip-through: while the page is moving, or the camera is settling onto the
|
|
325
|
+
narrated boxes, the scroll pose is the motion. A time-based follow here
|
|
326
|
+
lags a flick and reads as the section fighting the page. */
|
|
327
|
+
.arch-tour[data-skipping] .arch-tour__camera,
|
|
328
|
+
.arch-tour[data-skipping] .arch-tour__side,
|
|
329
|
+
.arch-tour[data-skipping] .arch-tour__rail::before {
|
|
330
|
+
transition: none;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/* the frame already draws the box; the diagram inside must not draw a second. */
|
|
334
|
+
.arch-tour__camera .arch-figure__body {
|
|
335
|
+
border: 0;
|
|
336
|
+
background: transparent;
|
|
337
|
+
padding: 0;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.arch-tour__camera .arch-figure__caption {
|
|
341
|
+
display: none;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/* The selected box glows and everything outside it drops back a step. The huge
|
|
345
|
+
* flat shadow is the spotlight: it dims the whole pane except the rectangle it
|
|
346
|
+
* is cast from, and the stage's own overflow clips it, so there is no second
|
|
347
|
+
* layer to keep in step with the camera. There is exactly ONE such rectangle per
|
|
348
|
+
* step (the union of the lit boxes) — with one per box the dim stacked once per
|
|
349
|
+
* lit box and the last rented steps, which light most of the diagram, went to
|
|
350
|
+
* near-black. The dim stays light for the same reason: the architecture outside
|
|
351
|
+
* the glow has to remain readable. */
|
|
352
|
+
.arch-tour__spot {
|
|
353
|
+
position: absolute;
|
|
354
|
+
inset-block-start: 0;
|
|
355
|
+
left: 0; /* physical: the spot's translate is the camera frame's physical x */
|
|
356
|
+
pointer-events: none;
|
|
357
|
+
opacity: 0;
|
|
358
|
+
border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
|
|
359
|
+
background: color-mix(in srgb, var(--accent) 4%, transparent);
|
|
360
|
+
box-shadow: 0 0 0 9999px color-mix(in srgb, var(--bg) 22%, transparent);
|
|
361
|
+
/* Geometry is written from the scroll pose, placed by translate so a frame
|
|
362
|
+
of travel is not a layout shift. Opacity is the only fade, so a
|
|
363
|
+
whole-graph beat can drop the spotlight without sliding a box. */
|
|
364
|
+
transition: opacity 0.35s var(--ease);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/* The glow itself breathes on its own layer so only opacity is animated — an
|
|
368
|
+
* animated 9999px spread would repaint the whole frame every tick. */
|
|
369
|
+
.arch-tour__spot::after {
|
|
370
|
+
content: "";
|
|
371
|
+
position: absolute;
|
|
372
|
+
inset: -1px;
|
|
373
|
+
box-shadow:
|
|
374
|
+
0 0 18px 2px color-mix(in srgb, var(--accent) 30%, transparent),
|
|
375
|
+
inset 0 0 10px color-mix(in srgb, var(--accent) 16%, transparent);
|
|
376
|
+
animation: arch-glow 2.6s ease-in-out infinite;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
@keyframes arch-glow {
|
|
380
|
+
0%,
|
|
381
|
+
100% {
|
|
382
|
+
opacity: 0.45;
|
|
383
|
+
}
|
|
384
|
+
50% {
|
|
385
|
+
opacity: 1;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/* The no-motion treatment renders both sides stacked, so it owns its own gap. */
|
|
390
|
+
.arch-tour__static {
|
|
391
|
+
display: flex;
|
|
392
|
+
flex-direction: column;
|
|
393
|
+
gap: var(--tour-static-gap);
|
|
394
|
+
min-width: 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
.arch-tour__tag,
|
|
398
|
+
.arch-tour__side-tag {
|
|
399
|
+
font-family: var(--font-mono);
|
|
400
|
+
font-size: var(--tour-tag-size);
|
|
401
|
+
letter-spacing: var(--tour-tag-tracking);
|
|
402
|
+
text-transform: uppercase;
|
|
403
|
+
color: var(--ink-mute);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
.arch-tour__side-tag {
|
|
407
|
+
display: block;
|
|
408
|
+
margin-bottom: var(--tour-side-tag-gap);
|
|
409
|
+
color: var(--accent);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/* Side emphasis is brightness, not hue (#4429 v16): the side being walked
|
|
413
|
+
reads bright white, the other subdued gray. The hooks are data attributes
|
|
414
|
+
the tour sets from its scroll state (`data-active` per side,
|
|
415
|
+
`data-active-side` on the root); the static fallback sets neither, so both
|
|
416
|
+
sides read full bright there. */
|
|
417
|
+
.arch-tour__tag[data-tag="their stack"],
|
|
418
|
+
.arch-tour__side-tag[data-tag="their stack"],
|
|
419
|
+
.arch-tour__tag[data-tag="digithings stack"],
|
|
420
|
+
.arch-tour__side-tag[data-tag="digithings stack"] {
|
|
421
|
+
color: var(--ink-mute);
|
|
422
|
+
border: 1px solid var(--hair);
|
|
423
|
+
padding: var(--tour-tag-pad-block) var(--tour-tag-pad-inline);
|
|
424
|
+
transition: color 0.35s var(--ease), border-color 0.35s var(--ease);
|
|
425
|
+
}
|
|
426
|
+
.arch-tour__side[data-active="true"] .arch-tour__tag,
|
|
427
|
+
.arch-tour__side[data-active="true"] > .arch-tour__side-tag,
|
|
428
|
+
.arch-tour[data-variant="static"] .arch-tour__tag {
|
|
429
|
+
color: var(--ink);
|
|
430
|
+
border-color: color-mix(in srgb, var(--ink) 45%, transparent);
|
|
431
|
+
}
|
|
432
|
+
/* The walked rail fills bright; the other rests on the hairline. The step
|
|
433
|
+
being walked keys off the same hook, both rail orientations. */
|
|
434
|
+
.arch-tour__side[data-active="true"] .arch-tour__rail::before {
|
|
435
|
+
background: var(--ink);
|
|
436
|
+
}
|
|
437
|
+
.arch-tour__side[data-active="true"] .arch-tour__step.on {
|
|
438
|
+
border-inline-start-color: var(--ink);
|
|
439
|
+
}
|
|
440
|
+
.arch-tour__side[data-active="true"][data-rail="end"] .arch-tour__step.on {
|
|
441
|
+
border-inline-end-color: var(--ink);
|
|
442
|
+
}
|
|
443
|
+
/* The why headline follows the walk: the side being walked reads bright
|
|
444
|
+
white, the other subdued gray, cross-fading on the swap. No attribute
|
|
445
|
+
(static fallback) leaves both halves bright. Kit-level hooks — the canon
|
|
446
|
+
guard refuses color literals in app files. */
|
|
447
|
+
.why-rent,
|
|
448
|
+
.why-own {
|
|
449
|
+
color: var(--ink);
|
|
450
|
+
transition: color 0.35s var(--ease);
|
|
451
|
+
}
|
|
452
|
+
.arch-tour[data-active-side="0"] .why-own,
|
|
453
|
+
.arch-tour[data-active-side="1"] .why-rent {
|
|
454
|
+
color: var(--ink-mute);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
/* App-first dimming: configured boxes rest dimmed unless the walk lights
|
|
458
|
+
them. One rule per dimmable box — the walk's `on` always wins, so a step
|
|
459
|
+
about a dimmed box still spotlights it. */
|
|
460
|
+
.arch-tour-dim-vault #arch-service-vault:not(.is-on) {
|
|
461
|
+
opacity: 0.32;
|
|
462
|
+
}
|
|
463
|
+
.arch-tour-dim-memory #arch-service-memory:not(.is-on) {
|
|
464
|
+
opacity: 0.32;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/* The side tag prints ONCE per side, on its own row at the TOP, right-aligned
|
|
468
|
+
* above the step column — never on every step and never bottom-left. */
|
|
469
|
+
.arch-tour__side > .arch-tour__side-tag {
|
|
470
|
+
grid-row: 1;
|
|
471
|
+
grid-column: -2 / -1;
|
|
472
|
+
justify-self: end;
|
|
473
|
+
align-self: start;
|
|
474
|
+
margin-bottom: 0;
|
|
475
|
+
text-align: end;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.arch-tour__grid {
|
|
479
|
+
display: grid;
|
|
480
|
+
grid-template-columns: minmax(0, 1fr);
|
|
481
|
+
gap: var(--tour-grid-gap);
|
|
482
|
+
align-items: start;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.arch-tour__pin {
|
|
486
|
+
position: sticky;
|
|
487
|
+
top: calc(var(--tour-nav-h) + var(--space-3, 1rem));
|
|
488
|
+
/* Fill the space left under the nav, then centre the held block inside it.
|
|
489
|
+
* `justify-content: center` needs free space to distribute: without a
|
|
490
|
+
* min-height the pin is only as tall as its content and the block sits at
|
|
491
|
+
* the top of the viewport, which is what read as top-aligned. The min-height
|
|
492
|
+
* makes the pin symmetric about the viewport centre (it fills the box it is
|
|
493
|
+
* stuck into), and the cap keeps it shorter than the viewport so the sticky
|
|
494
|
+
* can still hold. */
|
|
495
|
+
min-height: min(
|
|
496
|
+
calc(100svh - var(--tour-nav-h) - var(--space-5, 2rem)),
|
|
497
|
+
var(--tour-pin-max)
|
|
498
|
+
);
|
|
499
|
+
display: flex;
|
|
500
|
+
flex-direction: column;
|
|
501
|
+
gap: var(--tour-pin-gap);
|
|
502
|
+
justify-content: center;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.arch-tour__head {
|
|
506
|
+
max-width: var(--frame-w, 1180px);
|
|
507
|
+
margin-inline: auto;
|
|
508
|
+
width: 100%;
|
|
509
|
+
display: flex;
|
|
510
|
+
flex-direction: column;
|
|
511
|
+
gap: var(--tour-head-gap);
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.arch-tour__head p {
|
|
515
|
+
display: -webkit-box;
|
|
516
|
+
-webkit-box-orient: vertical;
|
|
517
|
+
-webkit-line-clamp: 3;
|
|
518
|
+
line-clamp: 3;
|
|
519
|
+
overflow: hidden;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.arch-tour__rail {
|
|
523
|
+
position: relative;
|
|
524
|
+
list-style: none;
|
|
525
|
+
margin: 0;
|
|
526
|
+
padding: 0;
|
|
527
|
+
display: grid;
|
|
528
|
+
align-content: start;
|
|
529
|
+
gap: var(--tour-rail-gap);
|
|
530
|
+
min-width: 0;
|
|
531
|
+
/* The rail owns the side it draws its rule on: the step column is text-start
|
|
532
|
+
* by default, and a right-side rail flips both the rule and the alignment
|
|
533
|
+
* (see [data-rail="end"]). */
|
|
534
|
+
--rail-rule: start;
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
.arch-tour__rail::before {
|
|
538
|
+
content: "";
|
|
539
|
+
position: absolute;
|
|
540
|
+
inset-block: 0;
|
|
541
|
+
inset-inline-start: 0;
|
|
542
|
+
width: 1px;
|
|
543
|
+
/* Neutral at rest — only the walked side's rail lights (ink), so no color
|
|
544
|
+
lingers on the subdued side after the swap. */
|
|
545
|
+
background: var(--hair-2);
|
|
546
|
+
transform-origin: 0 0;
|
|
547
|
+
/* The side-local walk progress, not the whole-walk value: on the rented rail
|
|
548
|
+
* the global value filled only its share and on the owned rail it was already
|
|
549
|
+
* full before that side began. Each side sets --arch-r<si> for its own rail. */
|
|
550
|
+
transform: scaleY(var(--arch-rail-p, 0));
|
|
551
|
+
transition: transform 0.35s linear;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
.arch-tour__step {
|
|
555
|
+
display: grid;
|
|
556
|
+
gap: var(--tour-step-gap);
|
|
557
|
+
border-inline-start: 1px solid var(--hair);
|
|
558
|
+
padding-inline-start: var(--tour-step-pad);
|
|
559
|
+
opacity: 0.42;
|
|
560
|
+
transition:
|
|
561
|
+
opacity 0.6s var(--ease),
|
|
562
|
+
border-color 0.6s var(--ease);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
.arch-tour__step.on {
|
|
566
|
+
opacity: 1;
|
|
567
|
+
border-inline-start-color: var(--accent);
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
/* Right-side rail: the vertical progress rule moves to the rail's right edge
|
|
571
|
+
* and the step text aligns to it. Set per side through `rail="end"`, so the
|
|
572
|
+
* rented column can sit right while the owned one keeps the left. */
|
|
573
|
+
.arch-tour__side[data-rail="end"] .arch-tour__rail {
|
|
574
|
+
--rail-rule: end;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
.arch-tour__side[data-rail="end"] .arch-tour__rail::before {
|
|
578
|
+
inset-inline-start: auto;
|
|
579
|
+
inset-inline-end: 0;
|
|
580
|
+
transform-origin: 100% 0;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
.arch-tour__side[data-rail="end"] .arch-tour__step {
|
|
584
|
+
border-inline-start: 0;
|
|
585
|
+
border-inline-end: 1px solid var(--hair);
|
|
586
|
+
padding-inline-start: 0;
|
|
587
|
+
padding-inline-end: var(--tour-step-pad);
|
|
588
|
+
text-align: end;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
.arch-tour__side[data-rail="end"] .arch-tour__step.on {
|
|
592
|
+
border-inline-end-color: var(--accent);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.arch-tour__side[data-rail="end"] > .arch-tour__side-tag {
|
|
596
|
+
text-align: end;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.arch-tour__index {
|
|
600
|
+
font-family: var(--font-mono);
|
|
601
|
+
font-size: var(--tour-tag-size);
|
|
602
|
+
letter-spacing: var(--tour-tag-tracking);
|
|
603
|
+
color: var(--ink-mute);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.arch-tour__label {
|
|
607
|
+
font-family: var(--font-mono);
|
|
608
|
+
font-size: var(--tour-label-size);
|
|
609
|
+
color: var(--ink);
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.arch-tour__line {
|
|
613
|
+
font-size: var(--tour-caption-size);
|
|
614
|
+
line-height: var(--tour-caption-leading);
|
|
615
|
+
color: var(--ink-soft);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/*
|
|
619
|
+
* The rail is an index, not a transcript: only the step being walked prints its
|
|
620
|
+
* line. Eleven full entries made the rail 1423px tall — taller than the viewport
|
|
621
|
+
* — and a sticky element taller than the viewport cannot hold, so the whole
|
|
622
|
+
* pinned treatment slid away instead of parking.
|
|
623
|
+
*/
|
|
624
|
+
.arch-tour__line {
|
|
625
|
+
display: none;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.arch-tour__step.on .arch-tour__line {
|
|
629
|
+
display: block;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/*
|
|
633
|
+
* The two-column row, and with it the swap. Each side lays out as one row —
|
|
634
|
+
* diagram wide, its own step list narrow beside it — and the two sides are
|
|
635
|
+
* stacked in the same grid cell so each can slide as a unit. The owned side
|
|
636
|
+
* mirrors its tracks so its list lands in the bottom-left corner and its diagram
|
|
637
|
+
* to the right. The grid clips, which is what keeps a group parked off-screen
|
|
638
|
+
* from widening the page.
|
|
639
|
+
*/
|
|
640
|
+
/* ── Narrow pinned tour: ONE pane ───────────────────────────────────────────
|
|
641
|
+
* Under the two-column breakpoint both stacks share a single graph box and the
|
|
642
|
+
* walk crossfades their-stack → digithings-stack inside it, with exactly one
|
|
643
|
+
* caption under the graph.
|
|
644
|
+
*
|
|
645
|
+
* READ THIS BEFORE CHANGING A ROW HERE. The pane's height must be owned by the
|
|
646
|
+
* pane, never by a drawing. The first cut of this layout left `align-items:
|
|
647
|
+
* start` on the grid and a content-sized row, so every side was exactly as tall
|
|
648
|
+
* as its own SVG — and because both sides sat in the same cell, the *hidden*
|
|
649
|
+
* one sized the row for both. The digithings drawing is taller (400px vs 315px
|
|
650
|
+
* at 390 wide), so the visible frame hung above a pane sized by a drawing nobody
|
|
651
|
+
* could see, the drawing spilled over the caption, and resizing re-measured into
|
|
652
|
+
* a different (equally wrong) answer. `align-items: stretch` + a definite
|
|
653
|
+
* `minmax(0, 1fr)` row + `height: 100%` down the frame → stage → pane chain is
|
|
654
|
+
* what makes the frame fill the space it is given, let the drawing shrink into
|
|
655
|
+
* it (`fitFrame` re-lays its gutters to the measured box), and keep the caption
|
|
656
|
+
* below the graph at every width and after any resize.
|
|
657
|
+
*/
|
|
658
|
+
@media (max-width: 1023.98px) {
|
|
659
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__pin {
|
|
660
|
+
/* The graph gets every pixel the header does not take: no 40rem cap (which
|
|
661
|
+
left a band under the pane) and no centring slack. `svh` keeps the pane
|
|
662
|
+
clear of the mobile URL bar; the app's max-height is the same sum. */
|
|
663
|
+
min-height: calc(100svh - var(--tour-nav-h) - var(--space-5, 2rem));
|
|
664
|
+
gap: var(--tour-pin-gap-narrow);
|
|
665
|
+
justify-content: flex-start;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__grid {
|
|
669
|
+
display: grid;
|
|
670
|
+
grid-template-columns: minmax(0, 1fr);
|
|
671
|
+
grid-template-rows: minmax(0, 1fr);
|
|
672
|
+
align-items: stretch;
|
|
673
|
+
gap: 0;
|
|
674
|
+
min-height: 0;
|
|
675
|
+
overflow: hidden;
|
|
676
|
+
flex: 1 1 0;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/* Both sides occupy the same cell as identical boxes, so the swap is a pure
|
|
680
|
+
crossfade: same frame, same caption baseline, no group sliding past a page
|
|
681
|
+
that is only one column wide. */
|
|
682
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side {
|
|
683
|
+
grid-area: 1 / 1;
|
|
684
|
+
position: relative;
|
|
685
|
+
display: grid;
|
|
686
|
+
grid-template-columns: minmax(0, 1fr);
|
|
687
|
+
grid-template-rows: minmax(0, 1fr) auto;
|
|
688
|
+
gap: var(--tour-frame-gap);
|
|
689
|
+
height: 100%;
|
|
690
|
+
min-height: 0;
|
|
691
|
+
min-width: 0;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/* The stack tag is a label on the pane's own top edge, not a row between the
|
|
695
|
+
tabs and the graph: it sits in the frame's reserved top band, so the graph
|
|
696
|
+
starts a half-rem under the header instead of 44.6px below it. */
|
|
697
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side > .arch-tour__side-tag {
|
|
698
|
+
position: absolute;
|
|
699
|
+
inset-block-start: var(--tour-tag-inset-block);
|
|
700
|
+
inset-inline-start: var(--tour-tag-inset-inline);
|
|
701
|
+
z-index: 2;
|
|
702
|
+
margin: 0;
|
|
703
|
+
/* A zoomed box can pass under the label; the chip stays legible on it. */
|
|
704
|
+
background: var(--surface);
|
|
705
|
+
text-align: start;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__frame {
|
|
709
|
+
grid-row: 1;
|
|
710
|
+
grid-column: 1;
|
|
711
|
+
display: grid;
|
|
712
|
+
grid-template-rows: minmax(0, 1fr);
|
|
713
|
+
/* top band = the tag; the rest is the graph */
|
|
714
|
+
padding: var(--tour-frame-pad-top) var(--tour-frame-pad-inline)
|
|
715
|
+
var(--tour-frame-pad-bottom);
|
|
716
|
+
min-height: 0;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
/* Definite heights all the way down, so the SVG is sized by the pane instead
|
|
720
|
+
of the pane being sized by the SVG. */
|
|
721
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__stage,
|
|
722
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__pane,
|
|
723
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__camera {
|
|
724
|
+
min-height: 0;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/* One caption at a time, under the graph, never on top of it. The floor is
|
|
728
|
+
the tallest full caption across all eleven steps at 390 (13.25rem = the
|
|
729
|
+
six-line mobile step plus its two-line label), measured rather than
|
|
730
|
+
guessed. Keeping the floor means the frame does not resize as the walk
|
|
731
|
+
moves between a short and a long caption; the caption itself is no longer
|
|
732
|
+
clamped, so a reader never loses the end of the explanation. */
|
|
733
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__rail {
|
|
734
|
+
grid-row: 2;
|
|
735
|
+
grid-column: 1;
|
|
736
|
+
display: block;
|
|
737
|
+
min-height: var(--tour-rail-min);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__step {
|
|
741
|
+
display: none;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__step.on {
|
|
745
|
+
display: grid;
|
|
746
|
+
border-inline-start: 0;
|
|
747
|
+
border-inline-end: 0;
|
|
748
|
+
padding-inline: 0;
|
|
749
|
+
text-align: start;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__rail::before {
|
|
753
|
+
display: none;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/* The step line is deliberately not clamped: on a phone the caption is the
|
|
757
|
+
explanation, so it takes as many lines as it needs and the frame gives up
|
|
758
|
+
the height (the rail floor below keeps that height stable step to step).
|
|
759
|
+
Short viewports hide the line entirely and keep the label only. */
|
|
760
|
+
|
|
761
|
+
/* The price aside folds itself away whenever the rail sits under the frame
|
|
762
|
+
(there is no room to the right of it in one column); removing it here also
|
|
763
|
+
keeps it from adding an empty grid row under the caption. */
|
|
764
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side > .arch-tour__aside {
|
|
765
|
+
display: none;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/* On a phone the graph is the pane; the copy that would otherwise sit
|
|
769
|
+
between the tabs and the graph is the step caption below it. */
|
|
770
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__head p {
|
|
771
|
+
display: none;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__head {
|
|
775
|
+
gap: var(--tour-head-gap-narrow);
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/* One pane: swap by crossfade instead of two groups sliding past each other,
|
|
779
|
+
so the frame is never empty mid-scroll. The fade is scroll-driven (the
|
|
780
|
+
`--arch-out` / `--arch-in` custom properties move with every frame), so the
|
|
781
|
+
sides themselves carry no transition — a leftover 1.7s transform tween was
|
|
782
|
+
what made a 1440→390 resize slide the whole pane across the phone. */
|
|
783
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side--leaving {
|
|
784
|
+
transform: none;
|
|
785
|
+
transition: none;
|
|
786
|
+
opacity: calc(1 - var(--arch-out, 0));
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side--entering {
|
|
790
|
+
transform: none;
|
|
791
|
+
transition: none;
|
|
792
|
+
opacity: var(--arch-in, 1);
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/* A short phone cannot hold the full explanation and a readable graph at the
|
|
797
|
+
same time. Show the step label only — never a mid-sentence ellipsis — and
|
|
798
|
+
give the frame the freed height. */
|
|
799
|
+
@media (max-width: 1023.98px) and (max-height: 700px) {
|
|
800
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__step.on .arch-tour__line {
|
|
801
|
+
display: none;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__rail {
|
|
805
|
+
min-height: var(--tour-rail-min-short);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
@media (min-width: 1024px) {
|
|
810
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__grid {
|
|
811
|
+
grid-template-columns: minmax(0, 1fr);
|
|
812
|
+
gap: 0;
|
|
813
|
+
overflow: hidden;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side {
|
|
817
|
+
grid-area: 1 / 1;
|
|
818
|
+
grid-template-columns: minmax(0, 1.35fr) minmax(0, 0.65fr);
|
|
819
|
+
grid-template-rows: auto minmax(0, 1fr);
|
|
820
|
+
gap: var(--tour-side-row-gap) var(--tour-side-col-gap);
|
|
821
|
+
align-items: start;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side--entering {
|
|
825
|
+
grid-template-columns: minmax(0, 0.65fr) minmax(0, 1.35fr);
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/* The tag sits above the RAIL column, so it must follow the rail as the
|
|
829
|
+
* tracks mirror: right column on the leaving side, left column on the
|
|
830
|
+
* entering side. */
|
|
831
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side > .arch-tour__side-tag {
|
|
832
|
+
grid-row: 1;
|
|
833
|
+
grid-column: 2;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side--entering > .arch-tour__side-tag {
|
|
837
|
+
grid-column: 1;
|
|
838
|
+
/* The owned column sits left, so its tag sits top-LEFT with it. */
|
|
839
|
+
justify-self: start;
|
|
840
|
+
text-align: start;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
/* Both runtime children are pinned to row 2: the tag owns row 1, and the
|
|
844
|
+
* owned side lists its columns in the opposite order, so grid auto-placement
|
|
845
|
+
* would otherwise drop the rail onto a third row below the diagram (which also
|
|
846
|
+
* made the pin taller than the viewport, so it could not hold). */
|
|
847
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__frame,
|
|
848
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side .arch-tour__rail {
|
|
849
|
+
grid-row: 2;
|
|
850
|
+
}
|
|
851
|
+
|
|
852
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side--entering .arch-tour__frame {
|
|
853
|
+
grid-column: 2;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side--entering .arch-tour__rail {
|
|
857
|
+
grid-column: 1;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
/* An aside takes a third row under the rail and sinks to the frame's
|
|
861
|
+
* bottom edge; the frame spans all three rows so the pin height holds. */
|
|
862
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side:has(> .arch-tour__aside) {
|
|
863
|
+
grid-template-rows: auto minmax(0, 1fr) auto;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side:where(:has(> .arch-tour__aside)) .arch-tour__frame {
|
|
867
|
+
grid-row: 2 / 4;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side > .arch-tour__aside {
|
|
871
|
+
grid-row: 3;
|
|
872
|
+
grid-column: 2;
|
|
873
|
+
align-self: end;
|
|
874
|
+
min-width: 0;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
.arch-tour:not([data-variant="static"]) .arch-tour__side--entering > .arch-tour__aside {
|
|
878
|
+
grid-column: 1;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
@media (prefers-reduced-motion: reduce) {
|
|
883
|
+
.arch-tour__camera,
|
|
884
|
+
.arch-tour__frame,
|
|
885
|
+
.arch-tour__rail,
|
|
886
|
+
.arch-tour__side,
|
|
887
|
+
.arch-tour__pane,
|
|
888
|
+
.arch-tour__spot,
|
|
889
|
+
.arch-tour__step,
|
|
890
|
+
.arch-tour__rail::before {
|
|
891
|
+
transition: none;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
.arch-tour__spot::after {
|
|
895
|
+
animation: none;
|
|
896
|
+
opacity: 1;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/* The component renders the static treatment under reduced motion, so the
|
|
900
|
+
* animated markup is not on the page — this is belt-and-braces for the case
|
|
901
|
+
* where the media query flips after mount. */
|
|
902
|
+
.arch-tour__pane,
|
|
903
|
+
.arch-tour__frame,
|
|
904
|
+
.arch-tour__rail,
|
|
905
|
+
.arch-tour__side {
|
|
906
|
+
transform: none;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
.arch-tour__rail::before {
|
|
910
|
+
transform: none;
|
|
911
|
+
display: none;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
/*
|
|
916
|
+
* mermaid parks a boundary's title on the boundary's own top edge, so it lands
|
|
917
|
+
* on top of whatever the force layout put nearest. A surface-coloured halo
|
|
918
|
+
* behind the glyphs (paint-order: stroke) makes it legible without moving it.
|
|
919
|
+
*/
|
|
920
|
+
.arch-figure__body svg .architecture-groups text {
|
|
921
|
+
paint-order: stroke;
|
|
922
|
+
stroke: var(--surface);
|
|
923
|
+
stroke-width: 4px;
|
|
924
|
+
stroke-linejoin: round;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
/* ════════════════════════════════════════════════════════════════════════════
|
|
928
|
+
* The kit's own architecture SVG (architecture-svg.tsx)
|
|
929
|
+
*
|
|
930
|
+
* Drawn, not solved: a box with the label inside it, a 22px kind glyph on the
|
|
931
|
+
* left, orthogonal hairline connectors, and the boundary title ABOVE its rule
|
|
932
|
+
* instead of painted onto it. Mono, squared, one accent — the terminal look.
|
|
933
|
+
* The tour's glow rides the same .is-on hook the mermaid path used, so nothing
|
|
934
|
+
* in the tour changed when the renderer did.
|
|
935
|
+
* ════════════════════════════════════════════════════════════════════════════ */
|
|
936
|
+
|
|
937
|
+
.arch-svg {
|
|
938
|
+
/* Component sizing tokens for the drawn diagram. SVG user units, so px is
|
|
939
|
+
the honest unit for label steps; hairlines and the paint-order halos stay
|
|
940
|
+
literal. */
|
|
941
|
+
--svg-text-size: var(--text-xs, 11px);
|
|
942
|
+
--svg-tracking: 0.02em;
|
|
943
|
+
--svg-group-label-size: 10px;
|
|
944
|
+
--svg-group-label-tracking: 0.08em;
|
|
945
|
+
--svg-edge-label-size: 10px;
|
|
946
|
+
--svg-node-label-size: 11.5px;
|
|
947
|
+
display: block;
|
|
948
|
+
width: 100%;
|
|
949
|
+
height: auto;
|
|
950
|
+
max-width: 100%;
|
|
951
|
+
overflow: visible;
|
|
952
|
+
font-family: var(--font-mono);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
.arch-svg text {
|
|
956
|
+
font-family: var(--font-mono);
|
|
957
|
+
font-size: var(--svg-text-size);
|
|
958
|
+
letter-spacing: var(--svg-tracking);
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
/* ── boundaries ─────────────────────────────────────────────────────────── */
|
|
962
|
+
|
|
963
|
+
.arch-svg .arch-group__box {
|
|
964
|
+
fill: color-mix(in srgb, var(--ink) 3%, transparent);
|
|
965
|
+
stroke: var(--hair-2);
|
|
966
|
+
stroke-width: 1;
|
|
967
|
+
stroke-dasharray: 4 3;
|
|
968
|
+
transition: stroke 0.25s var(--ease), fill 0.25s var(--ease);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
.arch-svg .arch-group.is-on .arch-group__box {
|
|
972
|
+
stroke: color-mix(in srgb, var(--accent) 55%, var(--hair-2));
|
|
973
|
+
fill: color-mix(in srgb, var(--accent) 5%, transparent);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
.arch-svg .arch-group__label {
|
|
977
|
+
fill: var(--ink-mute);
|
|
978
|
+
font-size: var(--svg-group-label-size);
|
|
979
|
+
letter-spacing: var(--svg-group-label-tracking);
|
|
980
|
+
text-transform: uppercase;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
.arch-svg .arch-group.is-on .arch-group__label {
|
|
984
|
+
fill: var(--ink-soft);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
/* ── connectors ─────────────────────────────────────────────────────────── */
|
|
988
|
+
|
|
989
|
+
.arch-svg .arch-edge__line {
|
|
990
|
+
fill: none;
|
|
991
|
+
stroke: var(--hair-2);
|
|
992
|
+
stroke-width: 1;
|
|
993
|
+
opacity: 0.5;
|
|
994
|
+
transition: stroke 0.25s var(--ease), opacity 0.25s var(--ease);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
.arch-svg .arch-edge.is-on .arch-edge__line {
|
|
998
|
+
stroke: color-mix(in srgb, var(--accent) 60%, var(--hair-2));
|
|
999
|
+
opacity: 1;
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
.arch-svg .arch-arrow {
|
|
1003
|
+
fill: var(--hair-2);
|
|
1004
|
+
stroke: none;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
.arch-svg .arch-edge.is-on .arch-arrow {
|
|
1008
|
+
fill: color-mix(in srgb, var(--accent) 60%, var(--hair-2));
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
.arch-svg .arch-edge__label {
|
|
1012
|
+
fill: var(--ink-soft);
|
|
1013
|
+
font-size: var(--svg-edge-label-size);
|
|
1014
|
+
text-anchor: middle;
|
|
1015
|
+
paint-order: stroke;
|
|
1016
|
+
stroke: var(--surface);
|
|
1017
|
+
stroke-width: 3px;
|
|
1018
|
+
stroke-linejoin: round;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
/* ── services ───────────────────────────────────────────────────────────── */
|
|
1022
|
+
|
|
1023
|
+
.arch-svg .arch-node__box {
|
|
1024
|
+
fill: var(--surface);
|
|
1025
|
+
stroke: var(--hair);
|
|
1026
|
+
stroke-width: 1;
|
|
1027
|
+
transition: stroke 0.25s var(--ease), fill 0.25s var(--ease);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
.arch-svg .arch-node.is-on .arch-node__box {
|
|
1031
|
+
fill: color-mix(in srgb, var(--accent) 6%, var(--surface));
|
|
1032
|
+
stroke: color-mix(in srgb, var(--accent) 55%, var(--hair));
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
.arch-svg .arch-node__glyph {
|
|
1036
|
+
color: var(--ink-mute);
|
|
1037
|
+
transition: color 0.25s var(--ease);
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
.arch-svg .arch-node.is-on .arch-node__glyph {
|
|
1041
|
+
color: var(--accent);
|
|
1042
|
+
}
|
|
1043
|
+
|
|
1044
|
+
.arch-svg .arch-node__label {
|
|
1045
|
+
fill: var(--ink-soft);
|
|
1046
|
+
font-size: var(--svg-node-label-size);
|
|
1047
|
+
transition: fill 0.25s var(--ease);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
.arch-svg .arch-node.is-on .arch-node__label {
|
|
1051
|
+
fill: var(--ink);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
.arch-svg .arch-node__glyph svg {
|
|
1055
|
+
overflow: visible;
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
/* ── morph variant (app-first why band) ────────────────────────────────────
|
|
1059
|
+
* Two diagrams share the frame: the provider stack rests full-lit on one
|
|
1060
|
+
* side while the other redraws box by box. No swipe — both transforms are
|
|
1061
|
+
* neutralised and the grid runs two columns. Boxes that have not swapped
|
|
1062
|
+
* yet rest dimmed (the walk's `on` always wins); boxes that never swap
|
|
1063
|
+
* (your product, sources, review) stay bright.
|
|
1064
|
+
*/
|
|
1065
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__grid {
|
|
1066
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
1067
|
+
gap: 0 var(--tour-side-col-gap);
|
|
1068
|
+
overflow: visible;
|
|
1069
|
+
}
|
|
1070
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__side {
|
|
1071
|
+
grid-area: auto;
|
|
1072
|
+
grid-template-columns: minmax(0, 1fr);
|
|
1073
|
+
transform: none;
|
|
1074
|
+
}
|
|
1075
|
+
.arch-tour.arch-tour-morph .arch-tour__side--leaving,
|
|
1076
|
+
.arch-tour.arch-tour-morph .arch-tour__side--entering {
|
|
1077
|
+
transform: none;
|
|
1078
|
+
}
|
|
1079
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__side--entering {
|
|
1080
|
+
grid-template-columns: minmax(0, 1fr);
|
|
1081
|
+
}
|
|
1082
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__side > .arch-tour__side-tag {
|
|
1083
|
+
grid-column: 1;
|
|
1084
|
+
justify-self: start;
|
|
1085
|
+
text-align: start;
|
|
1086
|
+
}
|
|
1087
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__side .arch-tour__frame,
|
|
1088
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__side .arch-tour__rail {
|
|
1089
|
+
grid-row: auto;
|
|
1090
|
+
}
|
|
1091
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__side--entering .arch-tour__frame,
|
|
1092
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__side--entering .arch-tour__rail {
|
|
1093
|
+
grid-column: auto;
|
|
1094
|
+
}
|
|
1095
|
+
.arch-tour.arch-tour-morph .arch-tour__side--entering [id^="arch-service-"]:not(.is-on):not(#arch-service-app):not(#arch-service-review):not(#arch-service-feeds):not(#arch-service-filings):not(#arch-service-sources) {
|
|
1096
|
+
opacity: 0.32;
|
|
1097
|
+
}
|
|
1098
|
+
@media (max-width: 1023px) {
|
|
1099
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__grid {
|
|
1100
|
+
grid-template-columns: minmax(0, 1fr);
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
/* The why band narrates from its own column, so the tour's step lists would
|
|
1105
|
+
be a second copy and would push the pin taller than the viewport. The
|
|
1106
|
+
diagrams sit under the nav and above the sticky invoice. */
|
|
1107
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__pin {
|
|
1108
|
+
min-height: 0;
|
|
1109
|
+
justify-content: flex-start;
|
|
1110
|
+
top: calc(var(--dq-nav-h, 4.5rem) + var(--tour-morph-pin-offset));
|
|
1111
|
+
}
|
|
1112
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__rail {
|
|
1113
|
+
display: none;
|
|
1114
|
+
}
|
|
1115
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-tour__frame {
|
|
1116
|
+
padding: var(--tour-morph-frame-pad-block) var(--tour-morph-frame-pad-inline);
|
|
1117
|
+
}
|
|
1118
|
+
.arch-tour.arch-tour-morph:not([data-variant="static"]) .arch-svg {
|
|
1119
|
+
width: 100%;
|
|
1120
|
+
height: auto;
|
|
1121
|
+
max-height: min(
|
|
1122
|
+
var(--tour-morph-svg-max),
|
|
1123
|
+
calc(100svh - var(--dq-nav-h, 4.5rem) - var(--tour-morph-svg-reserve))
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
/* Walk-through text rail (AppFirstSection): remounts per step (key), so a
|
|
1128
|
+
* short rise-and-fade marks each beat of the scroll journey. */
|
|
1129
|
+
@keyframes why-rail-in {
|
|
1130
|
+
from {
|
|
1131
|
+
opacity: 0;
|
|
1132
|
+
transform: translateY(8px);
|
|
1133
|
+
}
|
|
1134
|
+
to {
|
|
1135
|
+
opacity: 1;
|
|
1136
|
+
transform: none;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
.why-rail-step {
|
|
1140
|
+
animation: why-rail-in 0.5s cubic-bezier(0.22, 1, 0.36, 1);
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
/* ── build entrance ─────────────────────────────────────────────────────────
|
|
1144
|
+
* An ancestor carrying `.arch-build` makes every `.arch-svg` inside draw
|
|
1145
|
+
* itself: boundaries fade up, each box traces its outline in reading order and
|
|
1146
|
+
* then fills, and each connector draws once both of its ends exist
|
|
1147
|
+
* (`--arch-i`, set per element by the renderer). `.arch-build-pending` holds
|
|
1148
|
+
* the drawing blank until the caller starts the build. The end state is the
|
|
1149
|
+
* resting style, so the caller drops the class when the build is done and
|
|
1150
|
+
* nothing moves. */
|
|
1151
|
+
.arch-build-pending .arch-svg .arch-group,
|
|
1152
|
+
.arch-build-pending .arch-svg .arch-node,
|
|
1153
|
+
.arch-build-pending .arch-svg .arch-edge {
|
|
1154
|
+
opacity: 0;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
.arch-build .arch-svg .arch-group {
|
|
1158
|
+
animation: arch-build-fade 0.6s var(--ease) both;
|
|
1159
|
+
animation-delay: calc(var(--arch-i, 0) * 110ms);
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/* Opacity only on the box group: the tour measures box rects for its camera,
|
|
1163
|
+
and a scale here would read a few pixels short mid-build. */
|
|
1164
|
+
.arch-build .arch-svg .arch-node {
|
|
1165
|
+
animation: arch-build-fade 0.4s var(--ease) both;
|
|
1166
|
+
animation-delay: calc(180ms + var(--arch-i, 0) * 75ms);
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
.arch-build .arch-svg .arch-node__box {
|
|
1170
|
+
stroke-dasharray: 1;
|
|
1171
|
+
animation:
|
|
1172
|
+
arch-build-draw 0.55s var(--ease) both,
|
|
1173
|
+
arch-build-fill 0.35s var(--ease) both;
|
|
1174
|
+
animation-delay:
|
|
1175
|
+
calc(180ms + var(--arch-i, 0) * 75ms),
|
|
1176
|
+
calc(480ms + var(--arch-i, 0) * 75ms);
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
.arch-build .arch-svg .arch-node__glyph,
|
|
1180
|
+
.arch-build .arch-svg .arch-node__label {
|
|
1181
|
+
animation: arch-build-fade 0.35s var(--ease) both;
|
|
1182
|
+
animation-delay: calc(420ms + var(--arch-i, 0) * 75ms);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
.arch-build .arch-svg .arch-edge {
|
|
1186
|
+
animation: arch-build-fade 0.2s linear both;
|
|
1187
|
+
animation-delay: calc(560ms + var(--arch-i, 0) * 75ms);
|
|
1188
|
+
}
|
|
1189
|
+
|
|
1190
|
+
.arch-build .arch-svg .arch-edge__line {
|
|
1191
|
+
stroke-dasharray: 1;
|
|
1192
|
+
animation: arch-build-draw 0.5s var(--ease) both;
|
|
1193
|
+
animation-delay: calc(560ms + var(--arch-i, 0) * 75ms);
|
|
1194
|
+
}
|
|
1195
|
+
|
|
1196
|
+
.arch-build .arch-svg .arch-edge__label {
|
|
1197
|
+
animation: arch-build-fade 0.3s var(--ease) both;
|
|
1198
|
+
animation-delay: calc(900ms + var(--arch-i, 0) * 75ms);
|
|
1199
|
+
}
|
|
1200
|
+
|
|
1201
|
+
@keyframes arch-build-fade {
|
|
1202
|
+
from { opacity: 0; }
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
@keyframes arch-build-draw {
|
|
1206
|
+
from { stroke-dashoffset: 1; }
|
|
1207
|
+
to { stroke-dashoffset: 0; }
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
@keyframes arch-build-fill {
|
|
1211
|
+
from { fill-opacity: 0; }
|
|
1212
|
+
}
|
|
1213
|
+
|
|
1214
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1215
|
+
.arch-svg .arch-group__box,
|
|
1216
|
+
.arch-svg .arch-edge__line,
|
|
1217
|
+
.arch-svg .arch-node__box,
|
|
1218
|
+
.arch-svg .arch-node__glyph,
|
|
1219
|
+
.arch-svg .arch-node__label {
|
|
1220
|
+
transition: none;
|
|
1221
|
+
}
|
|
1222
|
+
.why-rail-step {
|
|
1223
|
+
animation: none;
|
|
1224
|
+
}
|
|
1225
|
+
.arch-build-pending .arch-svg .arch-group,
|
|
1226
|
+
.arch-build-pending .arch-svg .arch-node,
|
|
1227
|
+
.arch-build-pending .arch-svg .arch-edge {
|
|
1228
|
+
opacity: 1;
|
|
1229
|
+
}
|
|
1230
|
+
.arch-build .arch-svg * {
|
|
1231
|
+
animation: none !important;
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
/* Terminal schematic — fully drawn flow. The window is a dark terminal even
|
|
1236
|
+
when the page is light: light theme flips --term-* and --surface to paper,
|
|
1237
|
+
so the schematic pins the dark ground and the dark semantic hues locally.
|
|
1238
|
+
Structure stays light gray; color is only for live data. */
|
|
1239
|
+
.tschem {
|
|
1240
|
+
--term-bg: #08090b;
|
|
1241
|
+
--term-ink: #e7eaec;
|
|
1242
|
+
--term-mute: #7e858b;
|
|
1243
|
+
--term-hair: rgba(255, 255, 255, 0.09);
|
|
1244
|
+
--warn: #e0b341;
|
|
1245
|
+
--up: #3dd6c4;
|
|
1246
|
+
--down: #e5533e;
|
|
1247
|
+
--accent-digisearch: #5aa3c4;
|
|
1248
|
+
--accent-digitrace: #6fa3a3;
|
|
1249
|
+
/* Component sizing tokens (wave 1). A terminal cell has its own type steps and
|
|
1250
|
+
gutters, so they are named here instead of borrowed from the page scale.
|
|
1251
|
+
Hairlines, the dotted rules and the keyframe end-points stay literal. */
|
|
1252
|
+
--tschem-size: var(--type-meta, 0.75rem);
|
|
1253
|
+
--tschem-leading: 1.45;
|
|
1254
|
+
--tschem-pad-block: 0.4rem;
|
|
1255
|
+
--tschem-pad-inline: 0.7rem;
|
|
1256
|
+
--tschem-title-tracking: 0.04em;
|
|
1257
|
+
--tschem-body-pad-top: 0.75rem;
|
|
1258
|
+
--tschem-body-pad-bottom: 0.55rem;
|
|
1259
|
+
--tschem-body-gap: 0.85rem;
|
|
1260
|
+
--tschem-legend-col-min: 7.5rem;
|
|
1261
|
+
--tschem-legend-col-max: 9.5rem;
|
|
1262
|
+
--tschem-notes-col-min: 10rem;
|
|
1263
|
+
--tschem-notes-col-max: 16rem;
|
|
1264
|
+
--tschem-legend-gap: 0.35rem;
|
|
1265
|
+
--tschem-legend-item-gap: 0.4rem;
|
|
1266
|
+
--tschem-notes-gap: 0.4rem;
|
|
1267
|
+
--tschem-note-item-gap: 0.45rem;
|
|
1268
|
+
--tschem-swatch: 0.55rem;
|
|
1269
|
+
--tschem-stack-pad: 0.95rem;
|
|
1270
|
+
--tschem-stack-rule-inset: 0.28rem;
|
|
1271
|
+
--tschem-stack-rule-top: 0.2rem;
|
|
1272
|
+
--tschem-stack-rule-bottom: 1.6rem;
|
|
1273
|
+
--tschem-small-size: 0.68rem;
|
|
1274
|
+
--tschem-drop-size: 0.7rem;
|
|
1275
|
+
--tschem-join-h: 0.85rem;
|
|
1276
|
+
--tschem-join-inset: 0.65rem;
|
|
1277
|
+
--tschem-join-arrow-x: -0.32rem;
|
|
1278
|
+
--tschem-join-arrow-y: -0.45rem;
|
|
1279
|
+
--tschem-bus-h: 1rem;
|
|
1280
|
+
--tschem-bus-gap: 0.3rem;
|
|
1281
|
+
--tschem-cluster-top: -0.2rem;
|
|
1282
|
+
--tschem-cluster-tracking: 0.14em;
|
|
1283
|
+
--tschem-node-min: 8.5rem;
|
|
1284
|
+
--tschem-node-gap: 0.4rem;
|
|
1285
|
+
--tschem-box-gap: 0.15rem;
|
|
1286
|
+
--tschem-box-pad-block: 0.35rem;
|
|
1287
|
+
--tschem-box-pad-inline: 0.45rem;
|
|
1288
|
+
--tschem-state-leading: 1.2;
|
|
1289
|
+
--tschem-loop-gap: 0.55rem;
|
|
1290
|
+
--tschem-loop-pad: 0.35rem;
|
|
1291
|
+
--tschem-receipt-h: 4.8rem;
|
|
1292
|
+
--tschem-receipt-pad-top: 0.45rem;
|
|
1293
|
+
--tschem-receipt-track-gap: 0.12rem;
|
|
1294
|
+
--tschem-foot-gap-block: 0.7rem;
|
|
1295
|
+
--tschem-foot-gap-inline: 0.9rem;
|
|
1296
|
+
--tschem-meter-w: 4.5rem;
|
|
1297
|
+
--tschem-meter-h: 0.35rem;
|
|
1298
|
+
display: flex;
|
|
1299
|
+
flex-direction: column;
|
|
1300
|
+
margin: 0;
|
|
1301
|
+
min-width: 0;
|
|
1302
|
+
background: var(--term-bg);
|
|
1303
|
+
color: var(--term-ink);
|
|
1304
|
+
border: 1px solid var(--term-hair);
|
|
1305
|
+
border-radius: 0;
|
|
1306
|
+
font-family: var(--font-mono);
|
|
1307
|
+
font-size: var(--tschem-size);
|
|
1308
|
+
line-height: var(--tschem-leading);
|
|
1309
|
+
font-variant-numeric: tabular-nums;
|
|
1310
|
+
}
|
|
1311
|
+
|
|
1312
|
+
.tschem__title {
|
|
1313
|
+
margin: 0;
|
|
1314
|
+
padding: var(--tschem-pad-block) var(--tschem-pad-inline);
|
|
1315
|
+
border-bottom: 1px solid var(--term-hair);
|
|
1316
|
+
color: var(--term-mute);
|
|
1317
|
+
letter-spacing: var(--tschem-title-tracking);
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
.tschem__body {
|
|
1321
|
+
display: grid;
|
|
1322
|
+
grid-template-columns:
|
|
1323
|
+
minmax(var(--tschem-legend-col-min), var(--tschem-legend-col-max))
|
|
1324
|
+
minmax(0, 1fr)
|
|
1325
|
+
minmax(var(--tschem-notes-col-min), var(--tschem-notes-col-max));
|
|
1326
|
+
gap: var(--tschem-body-gap);
|
|
1327
|
+
padding: var(--tschem-body-pad-top) var(--tschem-pad-inline)
|
|
1328
|
+
var(--tschem-body-pad-bottom);
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
.tschem__legend,
|
|
1332
|
+
.tschem__notes,
|
|
1333
|
+
.tschem__rows {
|
|
1334
|
+
list-style: none;
|
|
1335
|
+
margin: 0;
|
|
1336
|
+
padding: 0;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
.tschem__legend {
|
|
1340
|
+
display: flex;
|
|
1341
|
+
flex-direction: column;
|
|
1342
|
+
gap: var(--tschem-legend-gap);
|
|
1343
|
+
color: var(--term-mute);
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
.tschem__legend li {
|
|
1347
|
+
display: flex;
|
|
1348
|
+
align-items: center;
|
|
1349
|
+
gap: var(--tschem-legend-item-gap);
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
.tschem__swatch {
|
|
1353
|
+
width: var(--tschem-swatch);
|
|
1354
|
+
height: var(--tschem-swatch);
|
|
1355
|
+
border: 1px solid currentColor;
|
|
1356
|
+
flex: none;
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
.tschem__swatch[data-tone="main"] { color: var(--warn); }
|
|
1360
|
+
.tschem__swatch[data-tone="model"] { color: var(--accent-digisearch); }
|
|
1361
|
+
.tschem__swatch[data-tone="side"] { color: var(--accent-digitrace); }
|
|
1362
|
+
.tschem__swatch[data-tone="ok"] { color: var(--up); }
|
|
1363
|
+
.tschem__swatch[data-tone="fallback"] { color: var(--down); }
|
|
1364
|
+
.tschem__swatch[data-tone="pending"] { color: var(--term-mute); }
|
|
1365
|
+
|
|
1366
|
+
.tschem__stack {
|
|
1367
|
+
position: relative;
|
|
1368
|
+
min-width: 0;
|
|
1369
|
+
padding-inline-start: var(--tschem-stack-pad);
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
.tschem__stack::before {
|
|
1373
|
+
content: "";
|
|
1374
|
+
position: absolute;
|
|
1375
|
+
inset-inline-start: var(--tschem-stack-rule-inset);
|
|
1376
|
+
top: var(--tschem-stack-rule-top);
|
|
1377
|
+
bottom: var(--tschem-stack-rule-bottom);
|
|
1378
|
+
border-inline-start: 1px dotted var(--term-mute);
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
.tschem__drop {
|
|
1382
|
+
position: absolute;
|
|
1383
|
+
inset-inline-start: 0;
|
|
1384
|
+
top: 0;
|
|
1385
|
+
color: var(--warn);
|
|
1386
|
+
font-size: var(--tschem-drop-size);
|
|
1387
|
+
line-height: 1;
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1390
|
+
.tschem[data-motion="on"] .tschem__drop {
|
|
1391
|
+
animation: tschem-drop 2.6s linear infinite;
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
.tschem__step {
|
|
1395
|
+
display: flex;
|
|
1396
|
+
flex-direction: column;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
.tschem__join {
|
|
1400
|
+
display: block;
|
|
1401
|
+
height: var(--tschem-join-h);
|
|
1402
|
+
margin-inline-start: var(--tschem-join-inset);
|
|
1403
|
+
border-inline-start: 1px dotted var(--term-mute);
|
|
1404
|
+
position: relative;
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
.tschem__join::after {
|
|
1408
|
+
content: "↓";
|
|
1409
|
+
position: absolute;
|
|
1410
|
+
left: var(--tschem-join-arrow-x);
|
|
1411
|
+
bottom: var(--tschem-join-arrow-y);
|
|
1412
|
+
color: var(--term-mute);
|
|
1413
|
+
font-size: var(--tschem-small-size);
|
|
1414
|
+
line-height: 1;
|
|
1415
|
+
}
|
|
1416
|
+
|
|
1417
|
+
.tschem__bus {
|
|
1418
|
+
position: relative;
|
|
1419
|
+
height: var(--tschem-bus-h);
|
|
1420
|
+
margin: 0 0 var(--tschem-bus-gap);
|
|
1421
|
+
border-bottom: 1px dotted var(--term-mute);
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
.tschem__par {
|
|
1425
|
+
color: var(--term-mute);
|
|
1426
|
+
font-size: var(--tschem-small-size);
|
|
1427
|
+
}
|
|
1428
|
+
|
|
1429
|
+
.tschem__cluster {
|
|
1430
|
+
position: absolute;
|
|
1431
|
+
left: 0;
|
|
1432
|
+
top: var(--tschem-cluster-top);
|
|
1433
|
+
color: var(--accent-digitrace);
|
|
1434
|
+
letter-spacing: var(--tschem-cluster-tracking);
|
|
1435
|
+
font-size: var(--tschem-small-size);
|
|
1436
|
+
visibility: hidden;
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1439
|
+
.tschem__row[data-live="true"] .tschem__cluster {
|
|
1440
|
+
visibility: visible;
|
|
1441
|
+
}
|
|
1442
|
+
|
|
1443
|
+
.tschem[data-motion="on"] .tschem__row[data-live="true"] .tschem__cluster {
|
|
1444
|
+
animation: tschem-bus 1.8s linear infinite;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
.tschem__nodes {
|
|
1448
|
+
display: grid;
|
|
1449
|
+
grid-template-columns: repeat(auto-fit, minmax(var(--tschem-node-min), 1fr));
|
|
1450
|
+
gap: var(--tschem-node-gap);
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1453
|
+
.tschem__box {
|
|
1454
|
+
min-width: 0;
|
|
1455
|
+
display: flex;
|
|
1456
|
+
flex-direction: column;
|
|
1457
|
+
align-items: stretch;
|
|
1458
|
+
gap: var(--tschem-box-gap);
|
|
1459
|
+
border: 1px solid var(--term-hair);
|
|
1460
|
+
background: transparent;
|
|
1461
|
+
color: var(--term-ink);
|
|
1462
|
+
padding: var(--tschem-box-pad-block) var(--tschem-box-pad-inline);
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
.tschem__name {
|
|
1466
|
+
min-width: 0;
|
|
1467
|
+
color: var(--term-ink);
|
|
1468
|
+
overflow-wrap: break-word;
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
.tschem__state {
|
|
1472
|
+
align-self: flex-end;
|
|
1473
|
+
white-space: nowrap;
|
|
1474
|
+
line-height: var(--tschem-state-leading);
|
|
1475
|
+
color: var(--term-mute);
|
|
1476
|
+
}
|
|
1477
|
+
|
|
1478
|
+
.tschem__box[data-status="running"][data-tone="main"] {
|
|
1479
|
+
border-color: var(--warn);
|
|
1480
|
+
}
|
|
1481
|
+
.tschem__box[data-status="running"][data-tone="main"] .tschem__state {
|
|
1482
|
+
color: var(--warn);
|
|
1483
|
+
}
|
|
1484
|
+
.tschem__box[data-status="running"][data-tone="model"] {
|
|
1485
|
+
border-color: var(--accent-digisearch);
|
|
1486
|
+
}
|
|
1487
|
+
.tschem__box[data-status="running"][data-tone="model"] .tschem__state {
|
|
1488
|
+
color: var(--accent-digisearch);
|
|
1489
|
+
}
|
|
1490
|
+
.tschem__box[data-status="running"][data-tone="side"] {
|
|
1491
|
+
border-color: var(--accent-digitrace);
|
|
1492
|
+
}
|
|
1493
|
+
.tschem__box[data-status="running"][data-tone="side"] .tschem__state {
|
|
1494
|
+
color: var(--accent-digitrace);
|
|
1495
|
+
}
|
|
1496
|
+
.tschem__box[data-status="running"][data-tone="fallback"] {
|
|
1497
|
+
border-color: var(--down);
|
|
1498
|
+
}
|
|
1499
|
+
.tschem__box[data-status="running"][data-tone="fallback"] .tschem__state {
|
|
1500
|
+
color: var(--down);
|
|
1501
|
+
}
|
|
1502
|
+
.tschem__box[data-status="ok"] {
|
|
1503
|
+
border-color: var(--up);
|
|
1504
|
+
}
|
|
1505
|
+
.tschem__box[data-status="ok"] .tschem__state {
|
|
1506
|
+
color: var(--up);
|
|
1507
|
+
}
|
|
1508
|
+
.tschem__box[data-status="pending"] {
|
|
1509
|
+
border-style: dashed;
|
|
1510
|
+
}
|
|
1511
|
+
.tschem__box[data-status="pending"] .tschem__name,
|
|
1512
|
+
.tschem__box[data-status="pending"] .tschem__state {
|
|
1513
|
+
color: var(--term-mute);
|
|
1514
|
+
}
|
|
1515
|
+
.tschem__box[data-status="hold"] {
|
|
1516
|
+
border-color: var(--down);
|
|
1517
|
+
}
|
|
1518
|
+
.tschem__box[data-status="hold"] .tschem__state {
|
|
1519
|
+
color: var(--down);
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
.tschem__loop {
|
|
1523
|
+
margin: var(--tschem-loop-gap) 0 0;
|
|
1524
|
+
padding-top: var(--tschem-loop-pad);
|
|
1525
|
+
border-top: 1px dotted var(--term-mute);
|
|
1526
|
+
color: var(--term-mute);
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1529
|
+
.tschem__notes {
|
|
1530
|
+
display: flex;
|
|
1531
|
+
flex-direction: column;
|
|
1532
|
+
gap: var(--tschem-notes-gap);
|
|
1533
|
+
color: var(--term-mute);
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
.tschem__notes li {
|
|
1537
|
+
display: flex;
|
|
1538
|
+
gap: var(--tschem-note-item-gap);
|
|
1539
|
+
}
|
|
1540
|
+
|
|
1541
|
+
.tschem__num {
|
|
1542
|
+
flex: none;
|
|
1543
|
+
color: var(--term-ink);
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
.tschem__receipt {
|
|
1547
|
+
box-sizing: border-box;
|
|
1548
|
+
flex: 0 0 auto;
|
|
1549
|
+
height: var(--tschem-receipt-h);
|
|
1550
|
+
overflow: hidden;
|
|
1551
|
+
border-top: 1px solid var(--term-hair);
|
|
1552
|
+
background: var(--term-bg);
|
|
1553
|
+
color: var(--term-mute);
|
|
1554
|
+
padding: var(--tschem-receipt-pad-top) var(--tschem-pad-inline)
|
|
1555
|
+
var(--tschem-pad-block);
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
.tschem__receipt-track {
|
|
1559
|
+
display: flex;
|
|
1560
|
+
flex-direction: column;
|
|
1561
|
+
gap: var(--tschem-receipt-track-gap);
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
.tschem[data-motion="on"] .tschem__receipt-track {
|
|
1565
|
+
animation: tschem-log 10s linear infinite;
|
|
1566
|
+
}
|
|
1567
|
+
|
|
1568
|
+
.tschem__foot {
|
|
1569
|
+
position: relative;
|
|
1570
|
+
z-index: 1;
|
|
1571
|
+
display: flex;
|
|
1572
|
+
flex: 0 0 auto;
|
|
1573
|
+
flex-wrap: wrap;
|
|
1574
|
+
align-items: center;
|
|
1575
|
+
gap: var(--tschem-foot-gap-block) var(--tschem-foot-gap-inline);
|
|
1576
|
+
margin: 0;
|
|
1577
|
+
border-top: 1px solid var(--term-hair);
|
|
1578
|
+
background: var(--term-bg);
|
|
1579
|
+
padding: var(--tschem-pad-block) var(--tschem-pad-inline);
|
|
1580
|
+
color: var(--term-mute);
|
|
1581
|
+
}
|
|
1582
|
+
|
|
1583
|
+
.tschem__foot b {
|
|
1584
|
+
font-weight: 500;
|
|
1585
|
+
color: var(--up);
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
.tschem__phrase {
|
|
1589
|
+
color: var(--warn);
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
.tschem__meter {
|
|
1593
|
+
width: var(--tschem-meter-w);
|
|
1594
|
+
height: var(--tschem-meter-h);
|
|
1595
|
+
border: 1px solid var(--term-hair);
|
|
1596
|
+
}
|
|
1597
|
+
|
|
1598
|
+
.tschem__meter > span {
|
|
1599
|
+
display: block;
|
|
1600
|
+
height: 100%;
|
|
1601
|
+
background: var(--up);
|
|
1602
|
+
transition: none;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
@keyframes tschem-drop {
|
|
1606
|
+
from { top: 0; }
|
|
1607
|
+
to { top: calc(100% - 1.7rem); }
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
@keyframes tschem-bus {
|
|
1611
|
+
from { transform: translateX(0); }
|
|
1612
|
+
to { transform: translateX(65%); }
|
|
1613
|
+
}
|
|
1614
|
+
|
|
1615
|
+
@keyframes tschem-log {
|
|
1616
|
+
from { transform: translateY(0); }
|
|
1617
|
+
to { transform: translateY(-50%); }
|
|
1618
|
+
}
|
|
1619
|
+
|
|
1620
|
+
@media (max-width: 800px) {
|
|
1621
|
+
.tschem__body {
|
|
1622
|
+
grid-template-columns: 1fr;
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
|
|
1626
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1627
|
+
.tschem[data-motion="on"] .tschem__drop,
|
|
1628
|
+
.tschem[data-motion="on"] .tschem__row[data-live="true"] .tschem__cluster,
|
|
1629
|
+
.tschem[data-motion="on"] .tschem__receipt-track {
|
|
1630
|
+
animation: none;
|
|
1631
|
+
}
|
|
1632
|
+
.tschem__meter > span {
|
|
1633
|
+
transition: none;
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
/* ════════════════════════════════════════════════════════════════════════════
|
|
1638
|
+
* Pipeline flow — DIG-3312.
|
|
1639
|
+
*
|
|
1640
|
+
* Replaces the terminal schematic inside the agent-orchestration cards. No
|
|
1641
|
+
* legend, no notes column, no receipt: the shape of the chain (how many
|
|
1642
|
+
* stages, which ones fan out) already tells the story, and the only job left
|
|
1643
|
+
* for motion is to make it look alive. A pulse rides every conduit on an
|
|
1644
|
+
* infinite loop, staggered by `--pflow-i` (the stage's own depth), so a
|
|
1645
|
+
* four-stage chain and a six-stage chain read as two different rhythms
|
|
1646
|
+
* without any per-card wiring — the data shapes the motion, not the other
|
|
1647
|
+
* way round.
|
|
1648
|
+
* ════════════════════════════════════════════════════════════════════════════ */
|
|
1649
|
+
|
|
1650
|
+
.pflow {
|
|
1651
|
+
--flow-bg: #08090b;
|
|
1652
|
+
--flow-ink: #e7eaec;
|
|
1653
|
+
--flow-mute: #7e858b;
|
|
1654
|
+
--flow-hair: rgba(255, 255, 255, 0.1);
|
|
1655
|
+
--flow-main: #e0b341;
|
|
1656
|
+
--flow-model: #5aa3c4;
|
|
1657
|
+
--flow-side: #6fa3a3;
|
|
1658
|
+
--flow-fallback: #e5533e;
|
|
1659
|
+
/* Component sizing tokens (wave 1). `--flow-*` is the colour set above, so
|
|
1660
|
+
these take the `--pflow-` prefix to stay out of its way. */
|
|
1661
|
+
--pflow-gap: 0.6rem;
|
|
1662
|
+
--pflow-size: 0.78rem;
|
|
1663
|
+
--pflow-leading: 1.4;
|
|
1664
|
+
--pflow-pad-block-start: 1.1rem;
|
|
1665
|
+
--pflow-pad-inline: 1rem;
|
|
1666
|
+
--pflow-pad-block-end: 0.9rem;
|
|
1667
|
+
--pflow-conduit-h: 1.5rem;
|
|
1668
|
+
--pflow-pulse-size: 5px;
|
|
1669
|
+
--pflow-pulse-inset-x: -2px;
|
|
1670
|
+
--pflow-pulse-inset-y: -3px;
|
|
1671
|
+
--pflow-nodes-gap: var(--space-2);
|
|
1672
|
+
--pflow-parallel-pad-top: 1.3rem;
|
|
1673
|
+
--pflow-bus-size: 0.62rem;
|
|
1674
|
+
--pflow-bus-tracking: 0.08em;
|
|
1675
|
+
--pflow-node-pad-block: 0.4rem;
|
|
1676
|
+
--pflow-node-pad-inline: 0.75rem;
|
|
1677
|
+
--pflow-loop-margin: 0.35rem;
|
|
1678
|
+
--pflow-loop-pad: 0.6rem;
|
|
1679
|
+
--pflow-loop-size: 0.7rem;
|
|
1680
|
+
--pflow-loop-gap: var(--space-2);
|
|
1681
|
+
--pflow-arc-size: 0.7rem;
|
|
1682
|
+
margin: 0;
|
|
1683
|
+
display: flex;
|
|
1684
|
+
flex-direction: column;
|
|
1685
|
+
gap: var(--pflow-gap);
|
|
1686
|
+
min-width: 0;
|
|
1687
|
+
background: var(--flow-bg);
|
|
1688
|
+
color: var(--flow-ink);
|
|
1689
|
+
border: 1px solid var(--flow-hair);
|
|
1690
|
+
padding: var(--pflow-pad-block-start) var(--pflow-pad-inline)
|
|
1691
|
+
var(--pflow-pad-block-end);
|
|
1692
|
+
font-family: var(--font-mono);
|
|
1693
|
+
font-size: var(--pflow-size);
|
|
1694
|
+
line-height: var(--pflow-leading);
|
|
1695
|
+
}
|
|
1696
|
+
|
|
1697
|
+
.pflow__chain {
|
|
1698
|
+
list-style: none;
|
|
1699
|
+
margin: 0;
|
|
1700
|
+
padding: 0;
|
|
1701
|
+
display: flex;
|
|
1702
|
+
flex-direction: column;
|
|
1703
|
+
min-width: 0;
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
.pflow__stage {
|
|
1707
|
+
display: flex;
|
|
1708
|
+
flex-direction: column;
|
|
1709
|
+
min-width: 0;
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
/* The conduit is the whole story's motion: a hairline trunk with a bright
|
|
1713
|
+
dot travelling its length forever, delayed per stage so the eye reads a
|
|
1714
|
+
single signal falling through the chain rather than four things blinking
|
|
1715
|
+
independently. */
|
|
1716
|
+
.pflow__conduit {
|
|
1717
|
+
position: relative;
|
|
1718
|
+
align-self: center;
|
|
1719
|
+
width: 1px;
|
|
1720
|
+
height: var(--pflow-conduit-h);
|
|
1721
|
+
background: var(--flow-hair);
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
.pflow__conduit[data-pending="true"] {
|
|
1725
|
+
background-image: linear-gradient(var(--flow-mute) 0 2px, transparent 2px 5px);
|
|
1726
|
+
background-repeat: repeat-y;
|
|
1727
|
+
background-size: 1px 5px;
|
|
1728
|
+
background-color: transparent;
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
.pflow__pulse {
|
|
1732
|
+
position: absolute;
|
|
1733
|
+
inset-inline-start: var(--pflow-pulse-inset-x);
|
|
1734
|
+
top: var(--pflow-pulse-inset-y);
|
|
1735
|
+
width: var(--pflow-pulse-size);
|
|
1736
|
+
height: var(--pflow-pulse-size);
|
|
1737
|
+
border-radius: 50%;
|
|
1738
|
+
background: var(--flow-side);
|
|
1739
|
+
box-shadow: 0 0 6px 1px var(--flow-side);
|
|
1740
|
+
opacity: 0;
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
.pflow[data-motion="on"] .pflow__conduit:not([data-pending="true"]) .pflow__pulse {
|
|
1744
|
+
animation: pflow-fall 2.6s linear infinite;
|
|
1745
|
+
animation-delay: calc(var(--pflow-i, 1) * -0.45s);
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
.pflow__nodes {
|
|
1749
|
+
display: flex;
|
|
1750
|
+
flex-wrap: wrap;
|
|
1751
|
+
justify-content: center;
|
|
1752
|
+
align-items: center;
|
|
1753
|
+
gap: var(--pflow-nodes-gap);
|
|
1754
|
+
position: relative;
|
|
1755
|
+
min-width: 0;
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
.pflow__nodes[data-parallel="true"] {
|
|
1759
|
+
padding-top: var(--pflow-parallel-pad-top);
|
|
1760
|
+
}
|
|
1761
|
+
|
|
1762
|
+
.pflow__bus {
|
|
1763
|
+
position: absolute;
|
|
1764
|
+
top: 0;
|
|
1765
|
+
left: 50%;
|
|
1766
|
+
transform: translateX(-50%);
|
|
1767
|
+
font-size: var(--pflow-bus-size);
|
|
1768
|
+
letter-spacing: var(--pflow-bus-tracking);
|
|
1769
|
+
text-transform: uppercase;
|
|
1770
|
+
color: var(--flow-mute);
|
|
1771
|
+
white-space: nowrap;
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
.pflow__node {
|
|
1775
|
+
min-width: 0;
|
|
1776
|
+
border: 1px solid var(--flow-hair);
|
|
1777
|
+
padding: var(--pflow-node-pad-block) var(--pflow-node-pad-inline);
|
|
1778
|
+
color: var(--flow-ink);
|
|
1779
|
+
text-align: center;
|
|
1780
|
+
transition: border-color 0.3s ease, box-shadow 0.3s ease;
|
|
1781
|
+
}
|
|
1782
|
+
|
|
1783
|
+
.pflow__node[data-tone="main"] { border-color: color-mix(in srgb, var(--flow-main) 55%, var(--flow-hair)); }
|
|
1784
|
+
.pflow__node[data-tone="model"] { border-color: color-mix(in srgb, var(--flow-model) 55%, var(--flow-hair)); }
|
|
1785
|
+
.pflow__node[data-tone="side"] { border-color: color-mix(in srgb, var(--flow-side) 45%, var(--flow-hair)); }
|
|
1786
|
+
.pflow__node[data-tone="fallback"] { border-color: color-mix(in srgb, var(--flow-fallback) 55%, var(--flow-hair)); }
|
|
1787
|
+
.pflow__node[data-tone="pending"] {
|
|
1788
|
+
border-style: dashed;
|
|
1789
|
+
color: var(--flow-mute);
|
|
1790
|
+
}
|
|
1791
|
+
|
|
1792
|
+
.pflow[data-motion="on"] .pflow__node[data-tone="main"] { animation: pflow-glow 3.2s ease-in-out infinite; }
|
|
1793
|
+
.pflow[data-motion="on"] .pflow__node[data-tone="model"] { animation: pflow-glow 3.2s ease-in-out infinite; animation-delay: 0.6s; }
|
|
1794
|
+
.pflow[data-motion="on"] .pflow__node[data-tone="side"] { animation: pflow-glow 3.2s ease-in-out infinite; animation-delay: 1.2s; }
|
|
1795
|
+
|
|
1796
|
+
.pflow__node[data-tone="main"] { --flow-glow: var(--flow-main); }
|
|
1797
|
+
.pflow__node[data-tone="model"] { --flow-glow: var(--flow-model); }
|
|
1798
|
+
.pflow__node[data-tone="side"] { --flow-glow: var(--flow-side); }
|
|
1799
|
+
|
|
1800
|
+
.pflow__loop {
|
|
1801
|
+
margin: var(--pflow-loop-margin) 0 0;
|
|
1802
|
+
padding-top: var(--pflow-loop-pad);
|
|
1803
|
+
border-top: 1px dotted var(--flow-hair);
|
|
1804
|
+
color: var(--flow-mute);
|
|
1805
|
+
font-size: var(--pflow-loop-size);
|
|
1806
|
+
display: flex;
|
|
1807
|
+
align-items: center;
|
|
1808
|
+
gap: var(--pflow-loop-gap);
|
|
1809
|
+
}
|
|
1810
|
+
|
|
1811
|
+
.pflow__loop-arc {
|
|
1812
|
+
display: inline-block;
|
|
1813
|
+
width: var(--pflow-arc-size);
|
|
1814
|
+
height: var(--pflow-arc-size);
|
|
1815
|
+
flex: none;
|
|
1816
|
+
border: 1px dotted var(--flow-mute);
|
|
1817
|
+
border-radius: 50%;
|
|
1818
|
+
border-right-color: transparent;
|
|
1819
|
+
border-bottom-color: transparent;
|
|
1820
|
+
}
|
|
1821
|
+
|
|
1822
|
+
.pflow[data-motion="on"] .pflow__loop-arc {
|
|
1823
|
+
animation: pflow-spin 3s linear infinite;
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
@keyframes pflow-fall {
|
|
1827
|
+
0% { top: -3px; opacity: 0; }
|
|
1828
|
+
8% { opacity: 1; }
|
|
1829
|
+
92% { opacity: 1; }
|
|
1830
|
+
100% { top: calc(100% - 2px); opacity: 0; }
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1833
|
+
@keyframes pflow-glow {
|
|
1834
|
+
0%, 100% { box-shadow: none; }
|
|
1835
|
+
50% { box-shadow: 0 0 10px 1px color-mix(in srgb, var(--flow-glow) 55%, transparent); }
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
@keyframes pflow-spin {
|
|
1839
|
+
to { transform: rotate(360deg); }
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
@media (max-width: 480px) {
|
|
1843
|
+
.pflow__nodes {
|
|
1844
|
+
flex-direction: column;
|
|
1845
|
+
align-items: stretch;
|
|
1846
|
+
}
|
|
1847
|
+
.pflow__node {
|
|
1848
|
+
text-align: start;
|
|
1849
|
+
}
|
|
1850
|
+
}
|
|
1851
|
+
|
|
1852
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1853
|
+
.pflow[data-motion="on"] .pflow__conduit:not([data-pending="true"]) .pflow__pulse,
|
|
1854
|
+
.pflow[data-motion="on"] .pflow__node[data-tone="main"],
|
|
1855
|
+
.pflow[data-motion="on"] .pflow__node[data-tone="model"],
|
|
1856
|
+
.pflow[data-motion="on"] .pflow__node[data-tone="side"],
|
|
1857
|
+
.pflow[data-motion="on"] .pflow__loop-arc {
|
|
1858
|
+
animation: none;
|
|
1859
|
+
}
|
|
1860
|
+
}
|