From 56a07cbd97cacfb0683c14c7235591989b3cc40a Mon Sep 17 00:00:00 2001
From: Bret Comnes
Date: Tue, 15 Sep 2026 20:42:15 -0700
Subject: [PATCH 1/6] refactor: improve DOMStack outputs, authoring, and
incremental indexing
---
.github/workflows/docs-audit.yml | 2 +
.github/workflows/pages.yml | 1 +
README.md | 125 +-
docs/migration.md | 69 +-
package-lock.json | 8 +-
package.json | 9 +-
src/CNAME.template.ts | 4 +
src/artifacts.template.ts | 80 -
src/blog/page.vars.ts | 8 +-
src/cname.template.ts | 6 -
src/docs/client.ts | 3 +
src/docs/page.vars.ts | 8 +-
src/global.data.ts | 32 -
src/globals/global.client.js | 214 -
src/globals/global.client.ts | 2 +
src/globals/global.css | 4158 +++++------------
src/globals/global.data.ts | 71 +
src/{ => globals}/global.vars.ts | 0
src/layouts/docs.layout.client.ts | 27 +-
src/layouts/docs.layout.ts | 102 +-
src/layouts/learn.layout.client.ts | 2 +-
src/layouts/learn.layout.css | 732 +++
src/layouts/learn.layout.ts | 2 +-
src/layouts/product.layout.client.ts | 1 -
src/layouts/registry.ts | 20 +
src/layouts/root.layout.ts | 46 +-
src/layouts/spec.layout.client.ts | 7 +-
src/layouts/spec.layout.ts | 23 +-
src/lib/article-client.ts | 2 +-
src/lib/artifacts.ts | 16 +
src/lib/ask-ai-client.ts | 165 +
src/lib/{clipboard.js => clipboard.ts} | 2 +-
src/lib/docs-page-outputs.ts | 7 +
src/lib/docs.ts | 86 +-
src/lib/learn-client.js | 151 -
src/lib/learn-client.ts | 127 +
src/lib/markdown.ts | 14 +-
src/lib/navigation.ts | 6 +-
src/lib/page-vars.ts | 10 +
src/lib/redirects.ts | 73 +
src/lib/rendering.ts | 69 +
src/lib/{silk.js => silk.ts} | 6 +-
src/lib/{tabs.js => tabs.ts} | 18 +-
src/lib/titles.ts | 19 +
src/lib/{toml.js => toml.ts} | 4 +-
src/lib/{zig.js => zig.ts} | 4 +-
src/llms.txt.template.ts | 10 +
src/markdown-it.settings.ts | 4 +-
src/nojekyll.template.ts | 2 +
src/page.vars.ts | 8 +-
src/redirects.pages.ts | 47 +-
src/runtime/docs/cli/build/page.md | 1 -
src/runtime/docs/cli/config/page.md | 1 -
src/runtime/docs/cli/env/page.md | 1 -
src/runtime/docs/cli/help/page.md | 1 -
src/runtime/docs/cli/init/page.md | 1 -
src/runtime/docs/cli/install-app/page.md | 1 -
src/runtime/docs/cli/list-devices/page.md | 1 -
src/runtime/docs/cli/mcp/page.md | 1 -
src/runtime/docs/cli/oroc/page.md | 1 -
src/runtime/docs/cli/print-build-dir/page.md | 1 -
src/runtime/docs/cli/run/page.md | 1 -
src/runtime/docs/cli/setup/page.md | 1 -
src/runtime/docs/cli/update/bundle/page.md | 1 -
src/runtime/docs/cli/update/extract/page.md | 1 -
src/runtime/docs/cli/update/info/page.md | 1 -
src/runtime/docs/cli/update/init/page.md | 1 -
src/runtime/docs/cli/update/keygen/page.md | 1 -
src/runtime/docs/cli/update/page.md | 1 -
src/runtime/docs/cli/update/server/page.md | 1 -
src/runtime/docs/cli/update/sign/page.md | 1 -
src/runtime/docs/cli/update/validate/page.md | 1 -
src/runtime/docs/cli/update/verify/page.md | 1 -
src/runtime/docs/cli/version/page.md | 1 -
src/runtime/docs/cli/versions/page.md | 1 -
src/runtime/docs/config/copy-map/page.md | 1 -
src/runtime/docs/config/overview/page.md | 1 -
src/runtime/docs/config/reference/page.md | 1 -
.../docs/guides/build-and-package/page.md | 1 -
.../docs/guides/calling-http-apis/page.md | 1 -
.../configure-your-runtime-project/page.md | 1 -
.../custom-protocols-and-routing/page.md | 1 -
.../docs/guides/desktop-integrations/page.md | 1 -
.../docs/guides/files-and-sandboxing/page.md | 1 -
.../guides/from-zero-to-first-run/page.md | 1 -
.../guides/frontend-build-pipeline/page.md | 1 -
src/runtime/docs/guides/hello-world/page.md | 1 -
.../lifecycle-hooks-and-deep-links/page.md | 1 -
.../guides/local-data-with-sqlite/page.md | 1 -
.../guides/mcp-and-agent-automation/page.md | 1 -
.../page.md | 1 -
.../docs/guides/native-extensions/page.md | 1 -
.../page.md | 1 -
.../docs/guides/project-layout/page.md | 1 -
.../page.md | 1 -
.../secure-storage-and-sessions/page.md | 1 -
.../shared-workers-across-windows/page.md | 1 -
.../guides/testing-and-diagnostics/page.md | 1 -
.../docs/guides/windows-and-messaging/page.md | 1 -
.../worker-threads-for-heavy-work/page.md | 1 -
src/runtime/docs/javascript/ai/page.md | 1 -
.../docs/javascript/all-modules/page.md | 1 -
.../docs/javascript/application/page.md | 1 -
src/runtime/docs/javascript/asn1/page.md | 1 -
src/runtime/docs/javascript/assert/page.md | 1 -
src/runtime/docs/javascript/async/page.md | 1 -
.../docs/javascript/async_hooks/page.md | 1 -
.../docs/javascript/background/page.md | 1 -
src/runtime/docs/javascript/buffer/page.md | 1 -
src/runtime/docs/javascript/cdp/page.md | 1 -
.../docs/javascript/child_process/page.md | 1 -
src/runtime/docs/javascript/clipboard/page.md | 1 -
src/runtime/docs/javascript/commonjs/page.md | 1 -
src/runtime/docs/javascript/conduit/page.md | 1 -
src/runtime/docs/javascript/console/page.md | 1 -
src/runtime/docs/javascript/constants/page.md | 1 -
src/runtime/docs/javascript/cookies/page.md | 1 -
src/runtime/docs/javascript/crypto/page.md | 1 -
src/runtime/docs/javascript/dbus/page.md | 1 -
src/runtime/docs/javascript/dgram/page.md | 1 -
.../docs/javascript/diagnostics/page.md | 1 -
src/runtime/docs/javascript/did/page.md | 1 -
src/runtime/docs/javascript/dns/page.md | 1 -
.../docs/javascript/enumeration/page.md | 1 -
src/runtime/docs/javascript/errno/page.md | 1 -
src/runtime/docs/javascript/errors/page.md | 1 -
src/runtime/docs/javascript/events/page.md | 1 -
src/runtime/docs/javascript/extension/page.md | 1 -
src/runtime/docs/javascript/fetch/page.md | 1 -
src/runtime/docs/javascript/fs/page.md | 1 -
src/runtime/docs/javascript/gc/page.md | 1 -
src/runtime/docs/javascript/hci/page.md | 1 -
src/runtime/docs/javascript/hooks/page.md | 1 -
src/runtime/docs/javascript/http/page.md | 1 -
src/runtime/docs/javascript/https/page.md | 1 -
src/runtime/docs/javascript/i18n/page.md | 1 -
src/runtime/docs/javascript/ip/page.md | 1 -
src/runtime/docs/javascript/ipc/page.md | 1 -
src/runtime/docs/javascript/ipfs/page.md | 1 -
src/runtime/docs/javascript/iroh/page.md | 1 -
src/runtime/docs/javascript/language/page.md | 1 -
src/runtime/docs/javascript/latica/page.md | 1 -
src/runtime/docs/javascript/location/page.md | 1 -
src/runtime/docs/javascript/mcp/page.md | 1 -
src/runtime/docs/javascript/mime/page.md | 1 -
src/runtime/docs/javascript/module/page.md | 1 -
.../docs/javascript/navigation/page.md | 1 -
src/runtime/docs/javascript/net/page.md | 1 -
src/runtime/docs/javascript/network/page.md | 1 -
.../docs/javascript/notification/page.md | 1 -
src/runtime/docs/javascript/npm/page.md | 1 -
src/runtime/docs/javascript/os/page.md | 1 -
src/runtime/docs/javascript/overview/page.md | 1 -
src/runtime/docs/javascript/path/page.md | 1 -
src/runtime/docs/javascript/process/page.md | 1 -
.../docs/javascript/protocol-handlers/page.md | 1 -
.../docs/javascript/querystring/page.md | 1 -
.../docs/javascript/secure-storage/page.md | 1 -
src/runtime/docs/javascript/semver/page.md | 1 -
.../docs/javascript/service-worker/page.md | 1 -
.../docs/javascript/shared-worker/page.md | 1 -
src/runtime/docs/javascript/signal/page.md | 1 -
src/runtime/docs/javascript/sqlite/page.md | 1 -
src/runtime/docs/javascript/stream/page.md | 1 -
.../docs/javascript/string_decoder/page.md | 1 -
src/runtime/docs/javascript/tar/page.md | 1 -
src/runtime/docs/javascript/tcp/page.md | 1 -
src/runtime/docs/javascript/test/page.md | 1 -
src/runtime/docs/javascript/timers/page.md | 1 -
src/runtime/docs/javascript/tls/page.md | 1 -
src/runtime/docs/javascript/toml/page.md | 1 -
src/runtime/docs/javascript/tty/page.md | 1 -
src/runtime/docs/javascript/url/page.md | 1 -
src/runtime/docs/javascript/usb/page.md | 1 -
src/runtime/docs/javascript/util/page.md | 1 -
src/runtime/docs/javascript/vm/page.md | 1 -
src/runtime/docs/javascript/window/page.md | 1 -
src/runtime/docs/javascript/worker/page.md | 1 -
.../docs/javascript/worker_threads/page.md | 1 -
src/runtime/docs/javascript/xpc/page.md | 1 -
src/runtime/docs/javascript/zlib/page.md | 1 -
src/runtime/docs/page.md | 1 -
src/runtime/docs/search.json.template.ts | 6 +
src/runtime/learn/configuration/page.vars.ts | 8 +-
.../learn/desktop-integrations/page.vars.ts | 8 +-
.../learn/getting-started/page.vars.ts | 8 +-
src/runtime/learn/page.vars.ts | 8 +-
src/runtime/learn/project-layout/page.vars.ts | 8 +-
.../learn/windows-and-messaging/page.vars.ts | 8 +-
src/runtime/llms.txt.template.ts | 6 +
src/runtime/page.vars.ts | 8 +-
src/sage/docs/cli/configuration/page.md | 1 -
src/sage/docs/cli/diagnostics/page.md | 1 -
.../docs/cli/environment-and-files/page.md | 1 -
src/sage/docs/cli/inputs-and-modes/page.md | 1 -
src/sage/docs/cli/keys-and-commands/page.md | 1 -
src/sage/docs/cli/options/page.md | 1 -
src/sage/docs/cli/sage/page.md | 1 -
src/sage/docs/cli/syntax-and-cache/page.md | 1 -
src/sage/docs/guides/getting-started/page.md | 1 -
src/sage/docs/guides/pager-workflows/page.md | 1 -
.../docs/guides/plugins-quickstart/page.md | 1 -
src/sage/docs/javascript/all-modules/page.md | 1 -
src/sage/docs/javascript/crypto/page.md | 1 -
src/sage/docs/javascript/dom/page.md | 1 -
src/sage/docs/javascript/env/page.md | 1 -
src/sage/docs/javascript/fetch/page.md | 1 -
src/sage/docs/javascript/fs/page.md | 1 -
src/sage/docs/javascript/module-index/page.md | 1 -
src/sage/docs/javascript/navigator/page.md | 1 -
src/sage/docs/javascript/overview/page.md | 1 -
src/sage/docs/javascript/path/page.md | 1 -
src/sage/docs/javascript/performance/page.md | 1 -
src/sage/docs/javascript/process/page.md | 1 -
src/sage/docs/javascript/runtime/page.md | 1 -
src/sage/docs/javascript/url/page.md | 1 -
src/sage/docs/javascript/uuid/page.md | 1 -
src/sage/docs/javascript/web/page.md | 1 -
src/sage/docs/man/sage-1/page.md | 1 -
src/sage/docs/man/sage-7/page.md | 1 -
src/sage/docs/man/sage-plugin-api-3/page.md | 1 -
src/sage/docs/page.md | 1 -
src/sage/docs/search.json.template.ts | 6 +
src/sage/llms.txt.template.ts | 6 +
src/sage/page.vars.ts | 8 +-
src/silk/docs/compiler/abi-libsilk/page.md | 1 -
src/silk/docs/compiler/architecture/page.md | 1 -
src/silk/docs/compiler/async-runtime/page.md | 1 -
src/silk/docs/compiler/backend-amdgpu/page.md | 1 -
src/silk/docs/compiler/backend-gpu/page.md | 1 -
src/silk/docs/compiler/backend-nvidia/page.md | 1 -
src/silk/docs/compiler/backend-wasm/page.md | 1 -
src/silk/docs/compiler/build-scripts/page.md | 1 -
src/silk/docs/compiler/builtin-deps/page.md | 1 -
src/silk/docs/compiler/cache-silk/page.md | 1 -
src/silk/docs/compiler/cli-silk/page.md | 1 -
src/silk/docs/compiler/diagnostics/page.md | 1 -
.../compiler/implementation-status/page.md | 1 -
src/silk/docs/compiler/ir-overview/page.md | 1 -
.../docs/compiler/libsilk-quickstart/page.md | 1 -
src/silk/docs/compiler/limits/page.md | 1 -
src/silk/docs/compiler/lsp-silk/page.md | 1 -
.../compiler/package-distribution/page.md | 1 -
.../docs/compiler/package-manifests/page.md | 1 -
.../docs/compiler/stdlib-integration/page.md | 1 -
.../docs/compiler/testing-strategy/page.md | 1 -
src/silk/docs/compiler/vendored-deps/page.md | 1 -
src/silk/docs/compiler/zig-api/page.md | 1 -
src/silk/docs/guides/cli/page.md | 1 -
src/silk/docs/guides/formal-silk/page.md | 1 -
src/silk/docs/guides/hello-world/page.md | 1 -
src/silk/docs/guides/language-tour/page.md | 1 -
.../docs/guides/modules-and-packages/page.md | 1 -
.../guides/practical-logger-module/page.md | 2 +-
.../docs/guides/project-dependencies/page.md | 1 -
src/silk/docs/guides/purpose/page.md | 1 -
src/silk/docs/guides/standard-library/page.md | 1 -
src/silk/docs/guides/testing/page.md | 1 -
src/silk/docs/language/asm/page.md | 1 -
src/silk/docs/language/atomics/page.md | 1 -
src/silk/docs/language/attributes/page.md | 1 -
src/silk/docs/language/borrow-checker/page.md | 1 -
src/silk/docs/language/buffers/page.md | 1 -
src/silk/docs/language/build-metadata/page.md | 1 -
src/silk/docs/language/cheat-sheet/page.md | 1 -
src/silk/docs/language/concurrency/page.md | 1 -
.../docs/language/const-functions/page.md | 1 -
src/silk/docs/language/conventions/page.md | 1 -
.../docs/language/dependent-types/page.md | 1 -
src/silk/docs/language/doc-comments/page.md | 1 -
.../docs/language/duration-instant/page.md | 1 -
src/silk/docs/language/enums/page.md | 1 -
src/silk/docs/language/errors/page.md | 1 -
src/silk/docs/language/ext/page.md | 1 -
.../language/flow-blocks-statements/page.md | 1 -
src/silk/docs/language/flow-break/page.md | 1 -
src/silk/docs/language/flow-continue/page.md | 1 -
.../flow-expression-statements/page.md | 1 -
src/silk/docs/language/flow-for/page.md | 1 -
src/silk/docs/language/flow-if-else/page.md | 1 -
src/silk/docs/language/flow-loop/page.md | 1 -
src/silk/docs/language/flow-match/page.md | 1 -
src/silk/docs/language/flow-overview/page.md | 1 -
src/silk/docs/language/flow-return/page.md | 1 -
src/silk/docs/language/flow-while/page.md | 1 -
.../docs/language/formal-verification/page.md | 1 -
.../language/function-disciplines/page.md | 1 -
src/silk/docs/language/generics/page.md | 1 -
src/silk/docs/language/gpu-execution/page.md | 1 -
.../docs/language/gpu-launch-blocks/page.md | 1 -
src/silk/docs/language/grammar/page.md | 1 -
src/silk/docs/language/interfaces/page.md | 1 -
.../docs/language/literals-aggregate/page.md | 1 -
.../docs/language/literals-boolean/page.md | 1 -
.../docs/language/literals-character/page.md | 1 -
.../docs/language/literals-duration/page.md | 1 -
.../docs/language/literals-numeric/page.md | 1 -
.../docs/language/literals-overview/page.md | 1 -
.../docs/language/literals-regexp/page.md | 1 -
.../docs/language/literals-string/page.md | 1 -
src/silk/docs/language/memory-model/page.md | 1 -
src/silk/docs/language/mutability/page.md | 1 -
src/silk/docs/language/operators/page.md | 1 -
src/silk/docs/language/optional/page.md | 1 -
.../language/packages-imports-exports/page.md | 1 -
src/silk/docs/language/regions/page.md | 1 -
.../docs/language/struct-requirements/page.md | 1 -
.../language/structs-impls-layout/page.md | 1 -
src/silk/docs/language/syntax-tour/page.md | 1 -
.../docs/language/target-metadata/page.md | 1 -
src/silk/docs/language/testing/page.md | 1 -
.../docs/language/toolchain-metadata/page.md | 1 -
src/silk/docs/language/type-unions/page.md | 1 -
src/silk/docs/language/typed-errors/page.md | 1 -
src/silk/docs/language/types/page.md | 1 -
src/silk/docs/language/using/page.md | 1 -
src/silk/docs/language/varargs/page.md | 1 -
src/silk/docs/man/libsilk.7/page.md | 1 -
src/silk/docs/man/silk-build.1/page.md | 1 -
src/silk/docs/man/silk-cache.1/page.md | 1 -
src/silk/docs/man/silk-cc.1/page.md | 1 -
src/silk/docs/man/silk-check.1/page.md | 1 -
src/silk/docs/man/silk-codesign.1/page.md | 1 -
src/silk/docs/man/silk-devices.1/page.md | 1 -
src/silk/docs/man/silk-doc.1/page.md | 1 -
src/silk/docs/man/silk-env.1/page.md | 1 -
src/silk/docs/man/silk-error.1/page.md | 1 -
src/silk/docs/man/silk-format.1/page.md | 1 -
src/silk/docs/man/silk-graph.1/page.md | 1 -
src/silk/docs/man/silk-guide.1/page.md | 1 -
src/silk/docs/man/silk-help.1/page.md | 1 -
src/silk/docs/man/silk-lsp.1/page.md | 1 -
src/silk/docs/man/silk-man.1/page.md | 1 -
src/silk/docs/man/silk-package.1/page.md | 1 -
src/silk/docs/man/silk-proto.1/page.md | 1 -
src/silk/docs/man/silk-repl.1/page.md | 1 -
src/silk/docs/man/silk-size.1/page.md | 1 -
src/silk/docs/man/silk-targets.1/page.md | 1 -
src/silk/docs/man/silk-test.1/page.md | 1 -
src/silk/docs/man/silk.1/page.md | 1 -
src/silk/docs/man/silk.7/page.md | 1 -
.../docs/man/silk_abi_get_version.3/page.md | 1 -
.../page.md | 1 -
src/silk/docs/man/silk_bytes.3/page.md | 1 -
src/silk/docs/man/silk_compiler.3/page.md | 1 -
src/silk/docs/man/silk_error.3/page.md | 1 -
src/silk/docs/man/slc.1/page.md | 1 -
src/silk/docs/man/slcc.1/page.md | 1 -
src/silk/docs/page.md | 1 -
src/silk/docs/search.json.template.ts | 6 +
src/silk/docs/std/abort-controller/page.md | 1 -
src/silk/docs/std/abort_controller/page.md | 1 -
src/silk/docs/std/algorithms/page.md | 1 -
src/silk/docs/std/args/page.md | 1 -
src/silk/docs/std/arrays/page.md | 1 -
src/silk/docs/std/atomic/page.md | 1 -
src/silk/docs/std/bits/page.md | 1 -
src/silk/docs/std/boolean/page.md | 1 -
src/silk/docs/std/boxed-values/page.md | 1 -
src/silk/docs/std/buffer/page.md | 1 -
src/silk/docs/std/build/page.md | 1 -
src/silk/docs/std/bytes/page.md | 1 -
src/silk/docs/std/conventions/page.md | 1 -
src/silk/docs/std/crypto-aead/page.md | 1 -
src/silk/docs/std/crypto-box/page.md | 1 -
src/silk/docs/std/crypto-hash/page.md | 1 -
src/silk/docs/std/crypto-random/page.md | 1 -
src/silk/docs/std/crypto-secretbox/page.md | 1 -
src/silk/docs/std/crypto-sign/page.md | 1 -
src/silk/docs/std/crypto/page.md | 1 -
src/silk/docs/std/dylib/page.md | 1 -
src/silk/docs/std/env/page.md | 1 -
src/silk/docs/std/ffi-c/page.md | 1 -
src/silk/docs/std/ffi-c_owned/page.md | 1 -
src/silk/docs/std/filesystem/page.md | 1 -
src/silk/docs/std/flag/page.md | 1 -
src/silk/docs/std/fmt/page.md | 1 -
src/silk/docs/std/formal/page.md | 1 -
src/silk/docs/std/fs-stream/page.md | 1 -
src/silk/docs/std/fs/page.md | 1 -
src/silk/docs/std/function/page.md | 1 -
src/silk/docs/std/ggml/page.md | 1 -
src/silk/docs/std/gpu-device/page.md | 1 -
src/silk/docs/std/gpu-isa/page.md | 1 -
src/silk/docs/std/gpu/page.md | 1 -
src/silk/docs/std/graphics-metal/page.md | 1 -
src/silk/docs/std/graphics-opengl/page.md | 1 -
src/silk/docs/std/graphics-opengles/page.md | 1 -
src/silk/docs/std/graphics-vulkan/page.md | 1 -
src/silk/docs/std/graphics-window/page.md | 1 -
src/silk/docs/std/graphics/page.md | 1 -
src/silk/docs/std/http/page.md | 1 -
src/silk/docs/std/https/page.md | 1 -
src/silk/docs/std/idl-web/page.md | 1 -
src/silk/docs/std/image-color/page.md | 1 -
src/silk/docs/std/image-jpeg/page.md | 1 -
src/silk/docs/std/image-png/page.md | 1 -
src/silk/docs/std/image/page.md | 1 -
src/silk/docs/std/interfaces/page.md | 1 -
src/silk/docs/std/io-async/page.md | 1 -
src/silk/docs/std/io-stream/page.md | 1 -
src/silk/docs/std/io/page.md | 1 -
src/silk/docs/std/js-ecma/page.md | 1 -
src/silk/docs/std/json/page.md | 1 -
src/silk/docs/std/limits/page.md | 1 -
src/silk/docs/std/list/page.md | 1 -
src/silk/docs/std/map/page.md | 1 -
src/silk/docs/std/math-matrix/page.md | 1 -
src/silk/docs/std/math-vector/page.md | 1 -
src/silk/docs/std/math/page.md | 1 -
src/silk/docs/std/memory/page.md | 1 -
src/silk/docs/std/mime/page.md | 1 -
src/silk/docs/std/module-catalog/page.md | 1 -
src/silk/docs/std/net-stream/page.md | 1 -
src/silk/docs/std/net/page.md | 1 -
src/silk/docs/std/networking/page.md | 1 -
src/silk/docs/std/number/page.md | 1 -
src/silk/docs/std/optional/page.md | 1 -
src/silk/docs/std/os/page.md | 1 -
src/silk/docs/std/overview/page.md | 1 -
src/silk/docs/std/package-structure/page.md | 1 -
src/silk/docs/std/path/page.md | 1 -
src/silk/docs/std/process-child/page.md | 1 -
src/silk/docs/std/process/page.md | 1 -
src/silk/docs/std/protobuf/page.md | 1 -
src/silk/docs/std/queue/page.md | 1 -
src/silk/docs/std/range/page.md | 1 -
src/silk/docs/std/readline/page.md | 1 -
src/silk/docs/std/regex/page.md | 1 -
src/silk/docs/std/result/page.md | 1 -
src/silk/docs/std/runtime-atomic/page.md | 1 -
src/silk/docs/std/runtime-build/page.md | 1 -
src/silk/docs/std/runtime-dylib/page.md | 1 -
src/silk/docs/std/runtime-env/page.md | 1 -
src/silk/docs/std/runtime-event_loop/page.md | 1 -
src/silk/docs/std/runtime-fs/page.md | 1 -
src/silk/docs/std/runtime-globals/page.md | 1 -
src/silk/docs/std/runtime-gpu/page.md | 1 -
.../docs/std/runtime-graphics-metal/page.md | 1 -
src/silk/docs/std/runtime-io/page.md | 1 -
.../docs/std/runtime-linux-event_loop/page.md | 1 -
src/silk/docs/std/runtime-mem/page.md | 1 -
src/silk/docs/std/runtime-net/page.md | 1 -
src/silk/docs/std/runtime-number/page.md | 1 -
.../docs/std/runtime-posix-atomic/page.md | 1 -
src/silk/docs/std/runtime-posix-dylib/page.md | 1 -
src/silk/docs/std/runtime-posix-env/page.md | 1 -
.../docs/std/runtime-posix-event_loop/page.md | 1 -
src/silk/docs/std/runtime-posix-fs/page.md | 1 -
src/silk/docs/std/runtime-posix-io/page.md | 1 -
src/silk/docs/std/runtime-posix-mem/page.md | 1 -
src/silk/docs/std/runtime-posix-net/page.md | 1 -
.../docs/std/runtime-posix-process/page.md | 1 -
.../docs/std/runtime-posix-signal/page.md | 1 -
src/silk/docs/std/runtime-posix-sync/page.md | 1 -
src/silk/docs/std/runtime-posix-task/page.md | 1 -
src/silk/docs/std/runtime-posix-time/page.md | 1 -
src/silk/docs/std/runtime-process/page.md | 1 -
src/silk/docs/std/runtime-readline/page.md | 1 -
src/silk/docs/std/runtime-regex/page.md | 1 -
src/silk/docs/std/runtime-signal/page.md | 1 -
src/silk/docs/std/runtime-sync/page.md | 1 -
src/silk/docs/std/runtime-task/page.md | 1 -
src/silk/docs/std/runtime-time/page.md | 1 -
src/silk/docs/std/runtime-unicode/page.md | 1 -
src/silk/docs/std/runtime-wasi-cwd/page.md | 1 -
src/silk/docs/std/runtime-wasi-env/page.md | 1 -
.../docs/std/runtime-wasi-event_loop/page.md | 1 -
src/silk/docs/std/runtime-wasi-fs/page.md | 1 -
src/silk/docs/std/runtime-wasi-io/page.md | 1 -
src/silk/docs/std/runtime-wasi-mem/page.md | 1 -
src/silk/docs/std/runtime-wasi-net/page.md | 1 -
.../docs/std/runtime-wasi-preopen/page.md | 1 -
.../docs/std/runtime-wasi-process/page.md | 1 -
src/silk/docs/std/runtime-wasi-signal/page.md | 1 -
src/silk/docs/std/runtime-wasi-sync/page.md | 1 -
src/silk/docs/std/runtime-wasi-task/page.md | 1 -
src/silk/docs/std/runtime-wasi-time/page.md | 1 -
src/silk/docs/std/runtime-window/page.md | 1 -
src/silk/docs/std/runtime-z3/page.md | 1 -
src/silk/docs/std/runtime/page.md | 1 -
src/silk/docs/std/semver/page.md | 1 -
src/silk/docs/std/set/page.md | 1 -
src/silk/docs/std/signal/page.md | 1 -
src/silk/docs/std/sqlite/page.md | 1 -
src/silk/docs/std/ssh/page.md | 1 -
src/silk/docs/std/ssh2/page.md | 1 -
src/silk/docs/std/stack/page.md | 1 -
src/silk/docs/std/stream/page.md | 1 -
src/silk/docs/std/strings/page.md | 1 -
src/silk/docs/std/sync/page.md | 1 -
src/silk/docs/std/tar-async/page.md | 1 -
src/silk/docs/std/tar/page.md | 1 -
src/silk/docs/std/task/page.md | 1 -
src/silk/docs/std/temporal/page.md | 1 -
src/silk/docs/std/test/page.md | 1 -
src/silk/docs/std/time/page.md | 1 -
src/silk/docs/std/tls/page.md | 1 -
src/silk/docs/std/toml/page.md | 1 -
src/silk/docs/std/unicode/page.md | 1 -
src/silk/docs/std/url/page.md | 1 -
src/silk/docs/std/uuid-random/page.md | 1 -
src/silk/docs/std/uuid/page.md | 1 -
src/silk/docs/std/vector/page.md | 1 -
src/silk/docs/std/wasm/page.md | 1 -
src/silk/docs/std/websocket/page.md | 1 -
src/silk/docs/std/window-gtk/page.md | 1 -
src/silk/docs/std/window-ios/page.md | 1 -
src/silk/docs/std/window-macos/page.md | 1 -
src/silk/docs/std/window/page.md | 1 -
src/silk/docs/std/xml/page.md | 1 -
src/silk/docs/std/z3/page.md | 1 -
src/silk/docs/usage/cli-examples/page.md | 1 -
src/silk/docs/usage/editor-coc-nvim/page.md | 1 -
src/silk/docs/usage/editor-ctags/page.md | 1 -
src/silk/docs/usage/editor-textmate/page.md | 1 -
src/silk/docs/usage/editor-vim/page.md | 1 -
src/silk/docs/usage/getting-started/page.md | 1 -
src/silk/docs/usage/github-actions/page.md | 1 -
src/silk/docs/usage/github-linguist/page.md | 1 -
src/silk/docs/usage/guide-examples/page.md | 1 -
.../usage/howto-custom-stdlib-root/page.md | 1 -
.../usage/howto-dynamic-libraries/page.md | 1 -
src/silk/docs/usage/howto-lumen-trail/page.md | 1 -
.../docs/usage/howto-run-wasi-node/page.md | 1 -
src/silk/docs/usage/pure-silk-gpu-ml/page.md | 1 -
src/silk/docs/usage/pure-silk-gpu/page.md | 1 -
.../usage/tutorials/01-first-program/page.md | 1 -
.../tutorials/02-structs-and-impls/page.md | 1 -
.../tutorials/03-arrays-and-slices/page.md | 1 -
.../usage/tutorials/04-filesystem/page.md | 1 -
.../usage/tutorials/05-concurrency/page.md | 1 -
.../06-async-io-streams-abort/page.md | 1 -
.../usage/tutorials/07-formal-silk/page.md | 1 -
src/silk/learn/getting-started/page.vars.ts | 8 +-
src/silk/learn/language-tour/page.vars.ts | 8 +-
.../learn/modules-and-packages/page.vars.ts | 8 +-
src/silk/learn/page.vars.ts | 8 +-
.../learn/results-and-errors/page.vars.ts | 8 +-
.../learn/types-and-optionals/page.vars.ts | 8 +-
src/silk/llms.txt.template.ts | 6 +
src/silk/page.vars.ts | 8 +-
src/silk/spec/2026/page.md | 2 +-
src/silk/wiki/language/borrow-checker/page.md | 1 -
src/silk/wiki/language/buffers/page.md | 1 -
src/silk/wiki/language/cheat-sheet/page.md | 1 -
src/silk/wiki/language/concurrency/page.md | 1 -
.../wiki/language/const-functions/page.md | 1 -
src/silk/wiki/language/conventions/page.md | 1 -
.../wiki/language/dependent-types/page.md | 1 -
src/silk/wiki/language/doc-comments/page.md | 1 -
.../wiki/language/duration-instant/page.md | 1 -
src/silk/wiki/language/enums/page.md | 1 -
src/silk/wiki/language/errors/page.md | 1 -
src/silk/wiki/language/ext/page.md | 1 -
.../language/flow-blocks-statements/page.md | 1 -
src/silk/wiki/language/flow-break/page.md | 1 -
src/silk/wiki/language/flow-continue/page.md | 1 -
.../flow-expression-statements/page.md | 1 -
src/silk/wiki/language/flow-for/page.md | 1 -
src/silk/wiki/language/flow-if-else/page.md | 1 -
src/silk/wiki/language/flow-loop/page.md | 1 -
src/silk/wiki/language/flow-match/page.md | 1 -
src/silk/wiki/language/flow-overview/page.md | 1 -
src/silk/wiki/language/flow-return/page.md | 1 -
src/silk/wiki/language/flow-while/page.md | 1 -
.../wiki/language/formal-verification/page.md | 1 -
.../language/function-disciplines/page.md | 1 -
src/silk/wiki/language/generics/page.md | 1 -
src/silk/wiki/language/grammar/page.md | 1 -
src/silk/wiki/language/interfaces/page.md | 1 -
.../wiki/language/literals-aggregate/page.md | 1 -
.../wiki/language/literals-boolean/page.md | 1 -
.../wiki/language/literals-character/page.md | 1 -
.../wiki/language/literals-duration/page.md | 1 -
.../wiki/language/literals-numeric/page.md | 1 -
.../wiki/language/literals-overview/page.md | 1 -
.../wiki/language/literals-string/page.md | 1 -
src/silk/wiki/language/memory-model/page.md | 1 -
src/silk/wiki/language/mutability/page.md | 1 -
src/silk/wiki/language/operators/page.md | 1 -
src/silk/wiki/language/optional/page.md | 1 -
.../language/packages-imports-exports/page.md | 1 -
src/silk/wiki/language/regions/page.md | 1 -
.../wiki/language/struct-requirements/page.md | 1 -
.../language/structs-impls-layout/page.md | 1 -
src/silk/wiki/language/syntax-tour/page.md | 1 -
src/silk/wiki/language/testing/page.md | 1 -
src/silk/wiki/language/typed-errors/page.md | 1 -
src/silk/wiki/language/types/page.md | 1 -
src/silk/wiki/language/varargs/page.md | 1 -
src/silk/wiki/page.md | 1 -
src/silk/wiki/search.json.template.ts | 6 +
src/silk/wiki/std/algorithms/page.md | 1 -
src/silk/wiki/std/args/page.md | 1 -
src/silk/wiki/std/arrays/page.md | 1 -
src/silk/wiki/std/bits/page.md | 1 -
src/silk/wiki/std/buffer/page.md | 1 -
src/silk/wiki/std/conventions/page.md | 1 -
src/silk/wiki/std/crypto/page.md | 1 -
src/silk/wiki/std/env/page.md | 1 -
src/silk/wiki/std/filesystem/page.md | 1 -
src/silk/wiki/std/fmt/page.md | 1 -
src/silk/wiki/std/formal/page.md | 1 -
src/silk/wiki/std/interfaces/page.md | 1 -
src/silk/wiki/std/io/page.md | 1 -
src/silk/wiki/std/json/page.md | 1 -
src/silk/wiki/std/map/page.md | 1 -
src/silk/wiki/std/memory/page.md | 1 -
src/silk/wiki/std/networking/page.md | 1 -
src/silk/wiki/std/overview/page.md | 1 -
src/silk/wiki/std/package-structure/page.md | 1 -
src/silk/wiki/std/path/page.md | 1 -
src/silk/wiki/std/process/page.md | 1 -
src/silk/wiki/std/result/page.md | 1 -
src/silk/wiki/std/runtime/page.md | 1 -
src/silk/wiki/std/semver/page.md | 1 -
src/silk/wiki/std/set/page.md | 1 -
src/silk/wiki/std/strings/page.md | 1 -
src/silk/wiki/std/sync/page.md | 1 -
src/silk/wiki/std/task/page.md | 1 -
src/silk/wiki/std/temporal/page.md | 1 -
src/silk/wiki/std/tls/page.md | 1 -
src/silk/wiki/std/toml/page.md | 1 -
src/silk/wiki/std/url/page.md | 1 -
src/silk/wiki/std/uuid/page.md | 1 -
src/silk/wiki/std/vector/page.md | 1 -
src/sitemap.xml.template.ts | 6 +
src/slg/docs/cli/diagnostics/page.md | 1 -
.../docs/cli/input-types-and-parsing/page.md | 1 -
src/slg/docs/cli/options-reference/page.md | 1 -
.../docs/cli/output-and-exit-codes/page.md | 1 -
src/slg/docs/cli/parallelism/page.md | 1 -
.../docs/cli/patterns-and-matching/page.md | 1 -
src/slg/docs/cli/slg/page.md | 1 -
.../docs/cli/traversal-and-ignores/page.md | 1 -
src/slg/docs/guides/getting-started/page.md | 1 -
src/slg/docs/guides/search-recipes/page.md | 1 -
src/slg/docs/man/slg-1/page.md | 1 -
src/slg/docs/page.md | 1 -
src/slg/docs/search.json.template.ts | 6 +
src/slg/llms.txt.template.ts | 6 +
src/slg/page.vars.ts | 8 +-
src/style.css | 1228 +++++
.../docs/cli/virtnosis-agent/page.md | 1 -
src/virtnosis/docs/cli/vnactl/page.md | 1 -
src/virtnosis/docs/guides/deployment/page.md | 1 -
.../docs/guides/getting-started/page.md | 1 -
.../docs/guides/install-and-package/page.md | 1 -
.../docs/guides/operator-guide/page.md | 1 -
.../docs/guides/output-and-automation/page.md | 1 -
src/virtnosis/docs/guides/systemd/page.md | 1 -
src/virtnosis/docs/man/virtnosis-7/page.md | 1 -
.../docs/man/virtnosis-agent-1/page.md | 1 -
.../man/virtnosis-agent-protocol-7/page.md | 1 -
.../docs/man/virtnosis-scan-report-7/page.md | 1 -
src/virtnosis/docs/man/vnactl-1/page.md | 1 -
src/virtnosis/docs/page.md | 1 -
.../docs/reference/architecture/page.md | 1 -
.../docs/reference/development/page.md | 1 -
src/virtnosis/docs/reference/overview/page.md | 1 -
.../docs/reference/repository-docs/page.md | 1 -
.../docs/reference/scan-analysis/page.md | 1 -
src/virtnosis/docs/search.json.template.ts | 6 +
src/virtnosis/llms.txt.template.ts | 6 +
src/virtnosis/page.vars.ts | 8 +-
tests/browser/client.spec.ts | 72 +
tests/browser/docs.spec.ts | 8 +-
tests/content.test.ts | 57 +-
tests/docs-data.test.ts | 67 +
tests/docs-index.test.ts | 283 ++
tests/docs-watch.test.ts | 99 +
tests/import-roundtrip.test.ts | 36 +-
tests/layout-types.typecheck.ts | 47 +
tests/redirects-watch.test.ts | 124 +
tests/redirects.test.ts | 106 +
tests/site/output.test.ts | 70 +-
tests/titles.test.ts | 23 +
tests/tooling/watch.test.ts | 179 +-
tools/import-public.ts | 34 +-
tools/migration/content.ts | 20 +-
tools/migration/migrate.ts | 16 +-
tools/migration/references.ts | 4 +-
tsconfig.json | 3 +-
684 files changed, 5467 insertions(+), 4416 deletions(-)
create mode 100644 src/CNAME.template.ts
delete mode 100644 src/artifacts.template.ts
delete mode 100644 src/cname.template.ts
create mode 100644 src/docs/client.ts
delete mode 100644 src/global.data.ts
delete mode 100644 src/globals/global.client.js
create mode 100644 src/globals/global.client.ts
create mode 100644 src/globals/global.data.ts
rename src/{ => globals}/global.vars.ts (100%)
create mode 100644 src/layouts/learn.layout.css
delete mode 100644 src/layouts/product.layout.client.ts
create mode 100644 src/layouts/registry.ts
create mode 100644 src/lib/artifacts.ts
create mode 100644 src/lib/ask-ai-client.ts
rename src/lib/{clipboard.js => clipboard.ts} (89%)
create mode 100644 src/lib/docs-page-outputs.ts
delete mode 100644 src/lib/learn-client.js
create mode 100644 src/lib/learn-client.ts
create mode 100644 src/lib/page-vars.ts
create mode 100644 src/lib/redirects.ts
create mode 100644 src/lib/rendering.ts
rename src/lib/{silk.js => silk.ts} (97%)
rename src/lib/{tabs.js => tabs.ts} (85%)
create mode 100644 src/lib/titles.ts
rename src/lib/{toml.js => toml.ts} (94%)
rename src/lib/{zig.js => zig.ts} (94%)
create mode 100644 src/llms.txt.template.ts
create mode 100644 src/nojekyll.template.ts
create mode 100644 src/runtime/docs/search.json.template.ts
create mode 100644 src/runtime/llms.txt.template.ts
create mode 100644 src/sage/docs/search.json.template.ts
create mode 100644 src/sage/llms.txt.template.ts
create mode 100644 src/silk/docs/search.json.template.ts
create mode 100644 src/silk/llms.txt.template.ts
create mode 100644 src/silk/wiki/search.json.template.ts
create mode 100644 src/sitemap.xml.template.ts
create mode 100644 src/slg/docs/search.json.template.ts
create mode 100644 src/slg/llms.txt.template.ts
create mode 100644 src/style.css
create mode 100644 src/virtnosis/docs/search.json.template.ts
create mode 100644 src/virtnosis/llms.txt.template.ts
create mode 100644 tests/browser/client.spec.ts
create mode 100644 tests/docs-data.test.ts
create mode 100644 tests/docs-index.test.ts
create mode 100644 tests/docs-watch.test.ts
create mode 100644 tests/layout-types.typecheck.ts
create mode 100644 tests/redirects-watch.test.ts
create mode 100644 tests/redirects.test.ts
create mode 100644 tests/titles.test.ts
diff --git a/.github/workflows/docs-audit.yml b/.github/workflows/docs-audit.yml
index b8a9880f..361f4724 100644
--- a/.github/workflows/docs-audit.yml
+++ b/.github/workflows/docs-audit.yml
@@ -2,6 +2,7 @@ name: Docs Audit
on:
pull_request:
+
workflow_dispatch:
permissions:
@@ -16,6 +17,7 @@ jobs:
with:
node-version: '24'
cache: npm
+
- run: npm ci
- run: npx playwright install --with-deps chromium
- run: npm run check
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 98fdaea3..16e7a962 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -21,6 +21,7 @@ jobs:
with:
node-version: '24'
cache: npm
+
- run: npm ci
# Upstream ingestion is manual. Validate only the committed public sources.
- run: npx playwright install --with-deps chromium
diff --git a/README.md b/README.md
index b712dd4f..4b347cf3 100644
--- a/README.md
+++ b/README.md
@@ -5,8 +5,8 @@ chapters, and documentation for Runtime, Silk, Virtnosis, Sage, and slg.
## Local development
-Use Node 24. Builds, ingestion tools, audits, and tests run on Node; Python is
-not required. No sibling checkout is needed to build the site.
+Use Node 24. Builds, ingestion tools, audits, and tests run in TypeScript on Node;
+Python is not required. No sibling checkout is needed to build the site.
```sh
npm ci
@@ -22,23 +22,67 @@ are output files; do not commit `public/`.
- `src/**/page.html`: authored page fragments, with metadata in `page.vars.ts`.
- `src/**/page.md`: public documentation, including YAML frontmatter.
- `src/layouts/`: shared page chrome, navigation, and progressive browser clients.
-- `src/globals/global.css`: Oro styles, based on `docs/branding/`.
+ `registry.ts` registers actual layout exports with DOMStack's type-only registry.
+ HTML `page.vars.ts` companions use `CheckedPageVars` from `#lib/page-vars.ts`
+ to validate supplied metadata against their layout chain and global vars during
+ `npm run typecheck`; this adds no runtime registry or subscriptions.
+- `src/globals/global.css`: shared Oro styles, based on `docs/branding/`.
+ Homepage styles live in `src/style.css`; learn styles in `src/layouts/learn.layout.css`.
- `src/lib/`: rendering, URL, collection, and navigation helpers.
-- `src/global.data.ts`: collection data derived from source pages.
-- `src/artifacts.template.ts`: navigation/search JSON, raw Markdown, LLM packs,
- and sitemap output.
+- `src/globals/global.vars.ts`: shared site configuration.
+- `src/globals/global.data.ts`: a watch-session index keyed by DOMStack `sourceId`,
+ caching validated document metadata, Markdown, and rendered search text. Navigation,
+ search, and LLM-export views are derived from those cached entries.
+- `src/layouts/docs.layout.ts`: the shared documentation renderer, consuming one
+ lightweight navigation key for all collections.
+- `src/{product}/llms.txt.template.ts`: product LLM packs; Silk includes its wiki.
+- `src/{product}/docs/search.json.template.ts`: collection search indexes;
+ the wiki uses `src/silk/wiki/`.
+- `src/lib/docs-page-outputs.ts`: shared `pageOutputs` hook exported by the `docs`
+ and `spec` layouts. Each page owns its raw Markdown export at its existing
+ collection `source/` URL, using its `sourcePath`.
+- `src/llms.txt.template.ts`, `sitemap.xml.template.ts`, `CNAME.template.ts`,
+ and `nojekyll.template.ts`: site-wide artifacts.
+
+Templates live beside their output locations. Single-file templates return strings
+and use their filenames without `.template.ts` as output names. The root
+`nojekyll.template.ts` explicitly names its hidden output `.nojekyll`.
+Raw Markdown uses DOMStack page outputs instead of collection templates: body
+edits update only that page's raw copy, and watch rebuilds retain unchanged copies
+without rewriting them. Deleted pages and changed raw paths clean up owned files.
+Navigation is rendered into HTML from global data; the legacy navigation
+`index.json` endpoints are no longer generated.
Consult `docs/branding/` before changing visual design or copy tone. The approved
logo originals remain in `docs/branding/assets/`; their checked mirrors in `src/docs/branding/assets/` retain
the same public URLs. Update both when replacing an asset. Handlebars is disabled globally so literal `{{ ... }}` code
-examples remain intact.
-
-Each documentation page declares `title`, `description`, `docsCollection`,
-`section`, `order`, `sourcePath`, `githubRepo`, and `githubRef`. Preserve
+examples remain intact. The Markdown parser deliberately keeps the existing
+plugin policy: tables, strikethrough, HTML, linkification, GitHub alerts, syntax
+highlighting, and legacy heading IDs. DOMStack's other default extensions are
+not implicitly enabled; review fragment and rendered-output compatibility before
+adding plugins.
+
+Each documentation page declares `description`, `docsCollection`, `section`,
+`order`, `sourcePath`, `githubRepo`, and `githubRef`. Its first Markdown H1 is the
+default title; do not repeat it in frontmatter. Preserve
`sourcePath`: it defines the stable raw Markdown endpoint and import identity.
The `start` document lives at its collection root; the specification lives at
`src/silk/spec/2026/page.md`. Order is explicit and does not depend on filenames.
New imported pages are appended; review their section and order after syncing.
+DOMStack infers the first H1 as inline Markdown. `src/lib/titles.ts` converts that
+value to plain text for document/social metadata, navigation, search titles, and
+LLM-pack headings, while the article keeps its formatted heading and anchor.
+An optional frontmatter `title` overrides the inferred title; use it only for an
+intentional difference (inline Markdown is reduced to plain text there too).
+An H1 edit changes navigation metadata, while a body edit below it does not.
+Imports infer titles from H1s, retain explicit overrides, and use a filename
+fallback only for new documents without an H1. Raw Markdown remains unchanged.
+
+Use `layout: "docs"` for documentation pages in every collection (`spec` for the
+specification). All docs share one lightweight navigation dependency: navigation
+changes rebuild all docs, while body-only edits remain isolated to the changed
+article, its raw output, and its collection's search and LLM exports. Search and
+LLM artifacts retain separate, per-collection dependencies; raw outputs need none.
Use canonical directory links such as `/runtime/docs/guides/hello-world/`.
Collection roots redirect legacy `?p=` links while preserving fragments. Static
@@ -46,6 +90,59 @@ redirect pages retain Silk's old logger-guide and specification aliases. The
articles, sidebar, previous/next navigation, and ToC work without JavaScript;
search, tabs, copy controls, and Ask AI progressively enhance them.
+### Incremental global data
+
+DOMStack beta.7 supplies private `previousState`, reset/delta `changes`, and
+`setState()` to the data callback. Initial builds and resets process all documents;
+watch deltas replace only `changes.upserted` entries and delete `changes.removed`
+IDs. Pages leaving a docs collection retain only their route/redirect metadata.
+The cache contains plain data, never page instances or renderers, and DOMStack
+commits its snapshot only after a successful build. It does not persist across
+watch sessions or change the clean-build/ingestion workflow.
+
+Collection views are still rebuilt from cached document references, and existing
+DOMStack fingerprints plus `dataDeps` remain the only downstream invalidation
+system. There are no extra application hashes or changed-key declarations.
+Source initialization, projection, state cloning, and fingerprinting still have
+collection-wide costs; a body edit no longer rereads/renders the whole corpus for
+search. The standalone watcher test measures these reads/renders directly.
+
+Beta.7's dependency tracking is conservative and incomplete for package import
+aliases and static re-exports. Restart the watcher after changing shared helpers
+reached through `#lib/*` or re-exports, or inputs read outside tracked imports.
+Editing `global.data.ts` itself resets the index; ordinary page edits are tracked.
+
+### Redirects from old URLs
+
+Follow the [DOMStack redirect-pages recipe](https://domstack.net/docs/cookbook/redirect-pages/):
+keep old paths on the **destination page**, rather than in a separate route map.
+For Markdown, add frontmatter:
+
+```yaml
+redirectFrom:
+ - /old-guide/
+ - /old-guide.html
+```
+
+HTML pages can declare the same array in their `page.vars.ts` object. Global data
+validates and collects these aliases; `src/redirects.pages.ts` subscribes only to
+`redirects` and renders each old URL through the existing `redirect` layout. The
+target comes from the destination page's actual URL, so retained aliases follow
+it when it moves. Removing an alias or destination removes its generated redirect
+in watch mode. Body edits do not change the redirect collection.
+
+Use same-origin paths beginning with `/`, with trailing `/` for directory URLs.
+Queries, fragments, unsafe paths, duplicate aliases, and aliases colliding with
+source pages are rejected. Choose paths that do not overlap assets or other
+generated outputs. Redirect pages have a canonical target and a no-JavaScript
+meta-refresh/fallback link; with JavaScript they preserve the incoming query and
+fragment. These are static client-side redirects, not HTTP 301 responses.
+
+Legacy `?p=` document IDs still use the separate client resolver; do not put them
+in `redirectFrom`. Manual content imports preserve existing page metadata,
+including aliases. The logger guide and specification now declare their old
+paths this way without changing their Markdown bodies or raw exports.
+
## Refreshing upstream content
Ingestion is separate from building and CI. These commands read explicit upstream
@@ -71,10 +168,10 @@ catalog includes new pages in the same import batch. Runtime's generated
reference markers retain surrounding prose.
The generators call the TypeScript importer directly; they never run during a
-DOMStack build. Search indexes and LLM exports remain DOMStack templates.
-Content audits derive document IDs and expected raw filenames from committed
-Markdown frontmatter rather than public navigation JSON, which is still generated.
-They inspect `public/` by default; set `ORO_SITE_OUTPUT` to inspect
+DOMStack build. Search indexes and LLM exports are DOMStack templates, not ingestion
+outputs. Content audits derive document IDs and expected raw filenames from committed
+Markdown frontmatter, then inspect the generated files in `public/` by default.
+They do not depend on public navigation JSON. Set `ORO_SITE_OUTPUT` to inspect
another output directory. Set `ORO_RUNTIME_REPO` explicitly to additionally audit
against a particular upstream Runtime checkout; ordinary checks are independent
of whatever happens to be checked out next door.
diff --git a/docs/migration.md b/docs/migration.md
index 6498babb..bcc470e1 100644
--- a/docs/migration.md
+++ b/docs/migration.md
@@ -1,7 +1,7 @@
# DOMStack migration status
The repository implementation now builds the entire Oro website with
-`@domstack/static@beta`. The lockfile records the resolved beta so `npm ci`
+`@domstack/static@12.0.0-beta.7`. The lockfile records the pinned beta so `npm ci`
remains reproducible. Production cutover is complete; deployment evidence is recorded below.
## Implemented
@@ -13,16 +13,79 @@ remains reproducible. Production cutover is complete; deployment evidence is rec
| Compatibility | Original collection roots, all valid legacy document IDs, aliases, fragments, and raw Markdown endpoints are retained. |
| Page chrome | Headers, footers, metadata, product navigation, learn chapter bars, documentation sidebars, breadcrumbs, previous/next links, and heading lists render at build time. |
| Progressive features | Search, keyboard tabs, copy controls, Ask AI, mobile sidebar controls, active headings, and tab fragments work with browser JavaScript. |
-| Artifacts | One build emits HTML, indexes, search data, raw Markdown, LLM packs, the sitemap, CNAME, and `.nojekyll`. |
-| Ingestion | Native TypeScript tools for Silk and Runtime retain their upstream/editorial ownership rules and accept explicit upstream checkout paths. Unchanged public pages retain exact Markdown and metadata. |
+| Artifacts | One build emits HTML, search indexes, raw Markdown, LLM packs, the sitemap, CNAME, and `.nojekyll`. Legacy navigation JSON exports are retired. |
+| Ingestion | Native TypeScript tools retain Silk and Runtime upstream/editorial ownership rules and explicit checkout paths. Unchanged public pages retain exact Markdown and metadata. |
| Cleanup | The browser Markdown renderers, vendored rendering libraries, old HTML shells, duplicate Python exporters, generated source-tree indexes, and Jekyll configuration are retired. |
| CI | Node 24 runs ingestion, audits, browser serving, and the `npm run check` gate without Python. Pull requests validate in Docs Audit; production pushes validate and deploy the same artifact in Pages, without a duplicate push audit. |
+All six documentation collections use the single `docs` layout; the Silk
+specification retains `spec`. The `docs` layout subscribes to one shared,
+lightweight navigation key covering all collections. Navigation changes rebuild
+all docs. Body-only edits update the changed article and its page-owned raw copy,
+plus its collection's search and LLM templates, which retain per-collection
+dependencies. DOMStack 12.0.0-beta.6 supplies the `pageOutputs` hook shared by
+`docs` and `spec`; no collection subscription is needed for raw exports. Watch
+rebuilds skip unchanged raw writes and clean up removed or renamed outputs.
+Global data now uses beta.7's optional stateful API to cache processed documents
+by `sourceId`. Initial/reset builds index all docs; deltas reread and render only
+upserted docs and remove deleted entries. Lightweight route/redirect records also
+cover non-doc pages. Collection views reference cached entries, while existing
+fingerprints and `dataDeps` alone decide downstream invalidation. State is saved
+only after successful validation and committed by DOMStack after a successful
+build. Source initialization, state transfer, projections, and fingerprinting
+still have whole-site costs. Ingestion remains separate from building.
+
+The actual watcher regression measured 585 initial Markdown reads/search renders,
+then one of each for a body edit, title override, or raw-path change, and zero
+for deletion. All 1,238 clean outputs matched the pre-index beta.7 build byte for
+byte. Restart watch mode for aliased/re-exported helper changes that beta.7 does
+not track; no framework patch or duplicate invalidation system is introduced.
+Shared article transforms remain page-local rather than storing rendered articles
+in global data. Markdown keeps the existing alerts, highlighting, and legacy
+heading-ID policy; enabling
+additional DOMStack Markdown plugins is an explicit compatibility decision.
+Homepage and learn styles are scoped to their consumers, and progressive clients
+are TypeScript modules rather than unchecked global initializers.
+
+Artifact templates are co-located with their output directories: product
+`llms.txt.template.ts` files and collection `search.json.template.ts` files.
+The former six `source/sources.template.ts` exporters are replaced by the shared
+`src/lib/docs-page-outputs.ts` hook, with each source page owning its raw output.
+The wiki uses `src/silk/wiki/`; other collections use `src/{product}/docs/`.
+Navigation remains in global data for HTML rendering, not as public `index.json`
+exports. Content audits read committed Markdown metadata for document IDs and
+expected raw exports. Single-file outputs use the template filename without `.template.ts`;
+raw page outputs use destination-root paths derived from collection metadata and
+`sourcePath`, preserving public URLs and Markdown bytes with frontmatter stripped. Site-wide `llms.txt`, sitemap, CNAME, and `.nojekyll` templates
+remain at the source root, with an explicit hidden-output name for `.nojekyll`.
+
The route inventory is in `tools/migration/baseline.json`; original Markdown
links and heading text are in `tools/migration/link-inventory.json`. The migration
utility can reconstruct the initial conversion from a legacy checkout. It is
not part of ordinary builds or content refreshes.
+HTML page companions now validate their supplied vars with DOMStack's type-only
+layout registry and `ValidatePageVars`, via `CheckedPageVars`. The registry
+references actual renderer, parent, and default exports for all seven layouts;
+it does not alter runtime discovery, rendering, or subscriptions. Markdown
+frontmatter continues to use runtime metadata validation rather than per-page
+TypeScript companions.
+
+Path redirects follow the DOMStack `redirectFrom` cookbook pattern: old paths
+live in destination-page metadata, global data validates a separate redirects
+projection, and a typed pages factory uses the existing redirect layout. The
+logger-guide and specification aliases now use this path; legacy `?p=` links
+retain their query-aware client resolver. Alias changes and destination moves
+update generated pages, while body-only edits leave redirects untouched.
+
+All 585 documentation pages now use their Markdown H1 as the default title,
+removing redundant frontmatter titles without changing article bodies. Because
+DOMStack beta.6 infers raw inline Markdown, shared title helpers reduce it to
+plain text at metadata consumers and in ingestion. Formatted H1s and anchors
+remain unchanged; intentional frontmatter overrides remain supported. This also
+removes stale link syntax from 31 metadata titles. Imports no longer regenerate
+redundant title fields and preserve explicit overrides during upstream refreshes.
+
## Acceptance checks
`npm run check` runs:
diff --git a/package-lock.json b/package-lock.json
index 26f45920..2b37545d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,7 +6,7 @@
"": {
"name": "oro-website",
"devDependencies": {
- "@domstack/static": "beta",
+ "@domstack/static": "12.0.0-beta.7",
"@playwright/test": "^1.55.0",
"@types/markdown-it": "^14.1.2",
"@types/node": "^24.0.0",
@@ -75,9 +75,9 @@
}
},
"node_modules/@domstack/static": {
- "version": "12.0.0-beta.5",
- "resolved": "https://registry.npmjs.org/@domstack/static/-/static-12.0.0-beta.5.tgz",
- "integrity": "sha512-9MnBvELmRHVftEvmbKoRcuJe/xrrHTah6+jXnDAQVYaPBqlUpc/AVdfCpjPSo/wIoMCo0uWTUVVplb2KSEpN1A==",
+ "version": "12.0.0-beta.7",
+ "resolved": "https://registry.npmjs.org/@domstack/static/-/static-12.0.0-beta.7.tgz",
+ "integrity": "sha512-tbsSGef9m9dPM/QAtYNdcyLMIRBGNKgDX8Krxr04sStDk94C/W0GAb8rQxemSl575Dplrv5gBWENqN3f7NQhPQ==",
"dev": true,
"license": "MIT",
"workspaces": [
diff --git a/package.json b/package.json
index f7a78e21..3d08577a 100644
--- a/package.json
+++ b/package.json
@@ -5,9 +5,13 @@
"engines": {
"node": ">=24"
},
+ "imports": {
+ "#lib/*": "./src/lib/*"
+ },
"scripts": {
"clean": "node tools/clean.ts",
"build": "npm run clean && domstack",
+ "start": "domstack --serve",
"dev": "domstack --watch",
"preview": "domstack --serve",
"typecheck": "tsc --noEmit",
@@ -21,7 +25,7 @@
"check": "npm run typecheck && npm test && npm run build && npm run audit && npm run audit:content && npm run test:site && npm run test:browser && npm run test:tooling && npm run test:reproducibility"
},
"devDependencies": {
- "@domstack/static": "beta",
+ "@domstack/static": "12.0.0-beta.7",
"@playwright/test": "^1.55.0",
"@types/markdown-it": "^14.1.2",
"@types/node": "^24.0.0",
@@ -32,8 +36,5 @@
"markdown-it": "^15.0.0",
"markdown-it-github-alerts": "^1.0.1",
"typescript": "^5.9.2"
- },
- "imports": {
- "#lib/*": "./src/lib/*"
}
}
diff --git a/src/CNAME.template.ts b/src/CNAME.template.ts
new file mode 100644
index 00000000..e77d0705
--- /dev/null
+++ b/src/CNAME.template.ts
@@ -0,0 +1,4 @@
+import { readFile } from 'node:fs/promises'
+// Keep the custom domain in the repository's canonical CNAME file.
+export const dataDeps = []
+export default () => readFile(new URL('../CNAME', import.meta.url), 'utf8')
diff --git a/src/artifacts.template.ts b/src/artifacts.template.ts
deleted file mode 100644
index 3b9e24cf..00000000
--- a/src/artifacts.template.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-import type { TemplateFunction } from '@domstack/static/types.js'
-import { collections } from './lib/collections.ts'
-import { rawUrl, type DocsData, type Doc } from './lib/docs.ts'
-export const dataDeps = ['docs', 'routes']
-const artifacts: TemplateFunction, DocsData> = ({
- data,
-}) => {
- const outputs: { outputName: string; content: string }[] = []
- const emit = (name: string, content: string) =>
- outputs.push({ outputName: name.replace(/^\//, ''), content })
- const json = (name: string, value: unknown) =>
- emit(name, JSON.stringify(value, null, 2) + '\n')
- const packs: Record = {}
- for (const [key, c] of Object.entries(collections)) {
- const docs = data.docs[key as keyof typeof collections]
- const sections = [...new Set(docs.map((d) => d.section))].map((name) => ({
- name,
- items: docs
- .filter((d) => d.section === name)
- .map((d) => ({
- id: d.id,
- title: d.title,
- file: d.sourcePath,
- url: d.url,
- })),
- }))
- json(c.base + 'index.json', {
- kind: key === 'silkWiki' ? 'wiki' : 'docs',
- count: docs.length,
- sections,
- })
- json(c.base + 'search.json', {
- kind: key === 'silkWiki' ? 'wiki' : 'docs',
- count: docs.length,
- items: docs.map((d) => ({
- id: d.id,
- title: d.title,
- file: d.sourcePath,
- url: d.url,
- section: d.section,
- summary: d.description,
- text: d.searchText,
- })),
- })
- for (const doc of docs) emit(rawUrl(doc), doc.markdown)
- ;(packs[c.product] ||= []).push(...docs)
- }
- for (const [product, docs] of Object.entries(packs))
- emit(
- `/${product}/llms.txt`,
- `# ${product} documentation\n\n` +
- docs
- .map(
- (d) =>
- `## ${d.title}\n\nURL: https://oro.computer${d.url}\nSource: https://oro.computer${rawUrl(d)}\n\n${d.markdown}`,
- )
- .join('\n---\n\n'),
- )
- emit(
- '/llms.txt',
- '# Oro Computer\n\n' +
- Object.keys(packs)
- .map(
- (p) => `- [${p} documentation](https://oro.computer/${p}/llms.txt)`,
- )
- .join('\n') +
- '\n',
- )
- emit(
- '/sitemap.xml',
- '\n' +
- data.routes
- .map((url) => `https://oro.computer${url}`)
- .join('') +
- '\n',
- )
- emit('/.nojekyll', '')
- return outputs
-}
-export default artifacts
diff --git a/src/blog/page.vars.ts b/src/blog/page.vars.ts
index 46e06463..71b62305 100644
--- a/src/blog/page.vars.ts
+++ b/src/blog/page.vars.ts
@@ -1,5 +1,7 @@
-export default {
- "layout": "marketing",
+import type { CheckedPageVars } from '#lib/page-vars.ts'
+
+const vars = {
+ "layout": "marketing" as const,
"title": "Blog · Oro Computer",
"description": "The Oro Computer blog is coming soon.",
"bodyClass": "site-dark blog-page",
@@ -7,3 +9,5 @@ export default {
"product": "blog",
"footerLabel": "Oro Computer Blog"
}
+
+export default vars satisfies CheckedPageVars
diff --git a/src/cname.template.ts b/src/cname.template.ts
deleted file mode 100644
index 1c03a990..00000000
--- a/src/cname.template.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { readFile } from 'node:fs/promises'
-// Keep the custom domain in the repository's canonical CNAME file.
-export default async () => ({
- outputName: 'CNAME',
- content: await readFile(new URL('../CNAME', import.meta.url), 'utf8'),
-})
diff --git a/src/docs/client.ts b/src/docs/client.ts
new file mode 100644
index 00000000..506a227f
--- /dev/null
+++ b/src/docs/client.ts
@@ -0,0 +1,3 @@
+import { initAskAiMenu } from '#lib/ask-ai-client.ts'
+
+initAskAiMenu()
diff --git a/src/docs/page.vars.ts b/src/docs/page.vars.ts
index fb38a2cb..7de56fc3 100644
--- a/src/docs/page.vars.ts
+++ b/src/docs/page.vars.ts
@@ -1,5 +1,7 @@
-export default {
- "layout": "marketing",
+import type { CheckedPageVars } from '#lib/page-vars.ts'
+
+const vars = {
+ "layout": "marketing" as const,
"title": "Docs · Oro Computer",
"description": "Oro Computer documentation hub for Oro Runtime and Silk, with quick starts, guides, full references, CLI docs, embedders, and Formal Silk.",
"bodyClass": "site-dark docs-landing-page",
@@ -7,3 +9,5 @@ export default {
"product": "docs",
"footerLabel": "Oro Computer Docs"
}
+
+export default vars satisfies CheckedPageVars
diff --git a/src/global.data.ts b/src/global.data.ts
deleted file mode 100644
index b522c90d..00000000
--- a/src/global.data.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import type { GlobalDataFunction } from '@domstack/static/types.js'
-import { collections, type Collection } from './lib/collections.ts'
-import { plainText, type Doc, type DocsData } from './lib/docs.ts'
-const globalData: GlobalDataFunction = async ({ pages }) => {
- const docs = Object.fromEntries(
- Object.keys(collections).map((k) => [k, []]),
- ) as unknown as Record
- for (const page of pages) {
- const v = page.vars
- if (!v.docsCollection) continue
- const collection = v.docsCollection as Collection
- const markdown = await page.readMarkdownContent()
- docs[collection].push({
- collection,
- id: v.sourcePath.replace(/\.(md|txt)$/, ''),
- title: v.title,
- description: v.description,
- section: v.section,
- order: v.order,
- url: page.pageInfo.url,
- sourcePath: v.sourcePath,
- markdown,
- searchText: plainText(await page.renderInnerPage()),
- githubRepo: v.githubRepo,
- githubRef: v.githubRef,
- })
- }
- for (const list of Object.values(docs))
- list.sort((a, b) => a.order - b.order || a.id.localeCompare(b.id, 'en'))
- return { docs, routes: pages.map((p) => p.pageInfo.url).sort() }
-}
-export default globalData
diff --git a/src/globals/global.client.js b/src/globals/global.client.js
deleted file mode 100644
index 6d471a75..00000000
--- a/src/globals/global.client.js
+++ /dev/null
@@ -1,214 +0,0 @@
-import { writeClipboard } from "../lib/clipboard.js";
-(() => {
- const yearNode = document.querySelector("[data-year]");
- if (yearNode) yearNode.textContent = String(new Date().getFullYear());
- const source = document.querySelector("[data-markdown]");
- if (source) globalThis.oroPageMarkdown = {url:new URL(source.dataset.markdown, location.href).href};
- function getSiteRootUrl() {
- const brand = document.querySelector("a.brand[href]");
- if (brand && brand.href) {
- try {
- return new URL(brand.href);
- } catch {}
- }
- try {
- return new URL("./", globalThis.location.href);
- } catch {
- return new URL("https://example.invalid/");
- }
- }
-
- function buildChatGPTUrl(targetUrl) {
- const prompt = `Hi ChatGPT! Can you please read [this page](${targetUrl}) and prepare to answer questions about it?`;
- const params = new URLSearchParams({ prompt });
- return `https://chatgpt.com/?${params.toString()}`;
- }
-
- function buildClaudeUrl(targetUrl) {
- const prompt = `Hi Claude! Can you please read [this page](${targetUrl}) and prepare to answer questions about it?`;
- const params = new URLSearchParams({ q: prompt });
- return `https://claude.ai/new?${params.toString()}`;
- }
-
- function inferLlmsUrl() {
- const root = getSiteRootUrl();
- const path = String(globalThis.location.pathname || "");
- if (path.includes("/silk/") || path.endsWith("/silk")) {
- return new URL("silk/llms.txt", root).toString();
- }
- if (path.includes("/runtime/") || path.endsWith("/runtime")) {
- return new URL("runtime/llms.txt", root).toString();
- }
- if (path.includes("/sage/") || path.endsWith("/sage")) {
- return new URL("sage/llms.txt", root).toString();
- }
- if (path.includes("/slg/") || path.endsWith("/slg")) {
- return new URL("slg/llms.txt", root).toString();
- }
- if (path.includes("/virtnosis/") || path.endsWith("/virtnosis")) {
- return new URL("virtnosis/llms.txt", root).toString();
- }
- return new URL("llms.txt", root).toString();
- }
-
- function shouldShowAskAiMenu() {
- const body = document.body;
- const path = String(globalThis.location.pathname || "");
- if (body?.dataset?.askAi === "true") return true;
- if (body?.classList?.contains("docs-page")) return true;
- if (body?.classList?.contains("docs-landing-page")) return true;
- return /(^|\/)docs(\/|$)/.test(path);
- }
-
- function initAskAiMenu() {
- if (!shouldShowAskAiMenu()) return;
-
- const nav = document.querySelector(".nav");
- if (!nav) return;
- if (nav.querySelector("[data-ask-ai]")) return;
-
- const menu = document.createElement("details");
- menu.className = "menu ask-ai-menu";
- menu.dataset.askAi = "true";
-
- const summary = document.createElement("summary");
- summary.className = "button button-quiet";
- summary.textContent = "Ask AI";
- menu.appendChild(summary);
-
- const panel = document.createElement("div");
- panel.className = "menu-panel";
-
- function itemLink(label, hint) {
- const a = document.createElement("a");
- a.className = "menu-item";
- a.target = "_blank";
- a.rel = "noreferrer";
- const left = document.createElement("span");
- left.textContent = label;
- const right = document.createElement("small");
- right.textContent = hint || "";
- a.appendChild(left);
- a.appendChild(right);
- return a;
- }
-
- function itemButton(label, hint) {
- const b = document.createElement("button");
- b.className = "menu-item";
- b.type = "button";
- const left = document.createElement("span");
- left.textContent = label;
- const right = document.createElement("small");
- right.textContent = hint || "";
- b.appendChild(left);
- b.appendChild(right);
- return b;
- }
-
- function sep() {
- const d = document.createElement("div");
- d.className = "menu-sep";
- return d;
- }
-
- const chatgpt = itemLink("ChatGPT", "New tab");
- const claude = itemLink("Claude", "New tab");
- const viewMd = itemLink("View Markdown", "Raw");
- viewMd.dataset.askAiViewMarkdown = "true";
- const copyMd = itemButton("Copy Markdown", "Clipboard");
- copyMd.dataset.askAiCopyMarkdown = "true";
- const llms = itemLink("Open llms.txt", "Pack");
-
- const hint = document.createElement("div");
- hint.className = "menu-hint";
- hint.textContent = "Uses page Markdown when available.";
-
- panel.appendChild(chatgpt);
- panel.appendChild(claude);
- panel.appendChild(sep());
- panel.appendChild(viewMd);
- panel.appendChild(copyMd);
- panel.appendChild(sep());
- panel.appendChild(llms);
- panel.appendChild(hint);
- menu.appendChild(panel);
-
- const primaryButton = nav.querySelector(".button.button-primary");
- if (primaryButton && primaryButton.parentElement === nav) {
- nav.insertBefore(menu, primaryButton);
- } else {
- nav.appendChild(menu);
- }
-
- function getContext() {
- const md = globalThis.oroPageMarkdown;
- const markdownUrl = md && md.url ? String(md.url) : "";
- const markdownText = md && md.text ? String(md.text) : "";
- const pageUrl = String(globalThis.location.href || "");
- const llmsUrl = inferLlmsUrl();
- return { markdownUrl, markdownText, pageUrl, llmsUrl };
- }
-
- function updateMenu() {
- const ctx = getContext();
- const target = ctx.markdownUrl || ctx.pageUrl;
- chatgpt.href = buildChatGPTUrl(target);
- claude.href = buildClaudeUrl(target);
- llms.href = ctx.llmsUrl;
-
- const hasMd = Boolean(ctx.markdownUrl);
- viewMd.hidden = !hasMd;
- copyMd.hidden = !hasMd;
- if (hasMd) viewMd.href = ctx.markdownUrl;
- }
-
- async function onCopyMarkdown() {
- const ctx = getContext();
- if (!ctx.markdownUrl) return;
-
- let text = ctx.markdownText;
- if (!text) {
- try {
- const res = await fetch(ctx.markdownUrl);
- if (res.ok) text = await res.text();
- } catch {}
- }
-
- const ok = await writeClipboard(text);
- const right = copyMd.querySelector("small");
- if (!right) return;
- const prev = right.textContent;
- right.textContent = ok ? "Copied" : "Failed";
- globalThis.setTimeout(() => {
- right.textContent = prev || "Clipboard";
- }, 900);
- }
-
- copyMd.addEventListener("click", onCopyMarkdown);
-
- panel.addEventListener("click", (event) => {
- const a = event.target && event.target.closest ? event.target.closest("a.menu-item") : null;
- if (!a) return;
- menu.open = false;
- });
-
- document.addEventListener("click", (event) => {
- if (!menu.open) return;
- const t = event.target;
- if (t && menu.contains(t)) return;
- menu.open = false;
- });
-
- document.addEventListener("keydown", (event) => {
- if (!menu.open) return;
- if (event.key === "Escape") menu.open = false;
- });
-
- globalThis.addEventListener("oro:page-markdown", updateMenu);
- updateMenu();
- }
-
- initAskAiMenu();
-
-})();
diff --git a/src/globals/global.client.ts b/src/globals/global.client.ts
new file mode 100644
index 00000000..17b562d6
--- /dev/null
+++ b/src/globals/global.client.ts
@@ -0,0 +1,2 @@
+const yearNode = document.querySelector('[data-year]')
+if (yearNode) yearNode.textContent = String(new Date().getFullYear())
diff --git a/src/globals/global.css b/src/globals/global.css
index b492fd12..42d1616d 100644
--- a/src/globals/global.css
+++ b/src/globals/global.css
@@ -363,7 +363,8 @@ pre {
position: relative;
}
-.menu summary {
+.menu summary,
+.menu .menu-trigger {
list-style: none;
}
@@ -371,7 +372,8 @@ pre {
display: none;
}
-.menu summary::after {
+.menu summary::after,
+.menu .menu-trigger::after {
content: "";
display: inline-block;
width: 0.42rem;
@@ -384,7 +386,8 @@ pre {
transition: transform 140ms ease;
}
-.menu[open] summary::after {
+.menu[open] summary::after,
+.menu .menu-trigger[aria-expanded="true"]::after {
transform: rotate(225deg) translateY(-0.02em);
}
@@ -1591,3443 +1594,1627 @@ pre code {
}
-/* Home redesign */
.container-wide {
max-width: var(--container-wide);
}
-.home-page {
+/* Oro repositioning */
+.site-dark {
--color-bg: #11100f;
--color-fg: #f7f3ea;
- --color-muted: rgba(247, 243, 234, 0.68);
+ --color-muted: rgba(247, 243, 234, 0.66);
--color-border: rgba(250, 248, 244, 0.12);
--color-border-strong: rgba(250, 248, 244, 0.22);
- --color-surface: rgba(250, 248, 244, 0.06);
- --color-surface-2: rgba(250, 248, 244, 0.1);
- --color-surface-3: rgba(250, 248, 244, 0.14);
- --color-code-bg: #171616;
- --color-code-bg-2: #211b2a;
- --shadow: 0 18px 42px rgba(0, 0, 0, 0.26);
+ --color-surface: rgba(250, 248, 244, 0.055);
+ --color-surface-2: rgba(250, 248, 244, 0.085);
+ --color-surface-3: rgba(250, 248, 244, 0.12);
+ --color-code-bg: #151414;
+ --color-code-bg-2: #1f1928;
+ --shadow: 0 18px 42px rgba(0, 0, 0, 0.28);
--shadow-elevated: 0 30px 80px rgba(0, 0, 0, 0.34);
- background: var(--color-bg);
+ background: #11100f;
color: var(--color-fg);
}
-.home-page::before {
+.site-dark::before {
background:
linear-gradient(rgba(250, 248, 244, 0.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(250, 248, 244, 0.035) 1px, transparent 1px),
- linear-gradient(180deg, rgba(91, 59, 162, 0.12), transparent 44%),
- linear-gradient(140deg, rgba(246, 201, 69, 0.06), transparent 38%);
+ linear-gradient(180deg, rgba(91, 59, 162, 0.12), transparent 42%),
+ linear-gradient(140deg, rgba(62, 155, 101, 0.08), transparent 46%);
background-size: 72px 72px, 72px 72px, auto, auto;
- mask-image: linear-gradient(to bottom, black 0%, black 62%, transparent 100%);
opacity: 1;
}
-.home-page a {
- color: #d9cbff;
- text-decoration-color: rgba(246, 201, 69, 0.35);
-}
-
-.home-page .site-top {
- background: rgba(17, 16, 15, 0.82);
- border-bottom-color: rgba(250, 248, 244, 0.08);
+.site-dark .site-top {
+ background: rgba(17, 16, 15, 0.9);
+ border-bottom-color: rgba(250, 248, 244, 0.1);
box-shadow: none;
}
-.home-page .brand,
-.home-page .nav a,
-.home-page .footer-inner strong {
+.site-dark .brand,
+.site-dark .footer-inner strong {
color: var(--color-fg);
}
-.home-page .brand-mark {
- border-color: rgba(250, 248, 244, 0.16);
+.site-dark .brand-mark {
+ border-color: rgba(250, 248, 244, 0.18);
background: rgba(250, 248, 244, 0.08);
box-shadow: 0 0 0 1px rgba(246, 201, 69, 0.08);
}
-.home-page .nav {
- color: rgba(247, 243, 234, 0.66);
+.site-dark .nav {
+ color: rgba(247, 243, 234, 0.64);
+}
+
+.site-dark .nav a {
+ padding: 0.35rem 0;
+}
+
+.site-dark .nav a:hover,
+.site-dark .nav a:focus-visible {
+ color: var(--color-fg);
}
-.home-page .nav a:hover,
-.home-page .nav a:focus-visible {
+.site-dark .nav a[aria-current="page"] {
color: var(--color-fg);
- border-color: rgba(250, 248, 244, 0.12);
- background: rgba(250, 248, 244, 0.06);
}
-.home-page .button {
+.site-dark .button {
border-color: rgba(250, 248, 244, 0.14);
background: rgba(250, 248, 244, 0.06);
color: var(--color-fg);
}
-.home-page .button:hover,
-.home-page .button:focus-visible {
+.site-dark .button:hover,
+.site-dark .button:focus-visible {
border-color: rgba(246, 201, 69, 0.42);
background: rgba(250, 248, 244, 0.1);
}
-.home-page .button-primary {
+.site-dark .button-primary {
border-color: rgba(246, 201, 69, 0.68);
background: linear-gradient(135deg, rgba(246, 201, 69, 0.92), rgba(244, 122, 40, 0.72));
color: #1f1f1f;
box-shadow: 0 16px 40px rgba(246, 201, 69, 0.12);
}
-.home-page .button-primary:hover,
-.home-page .button-primary:focus-visible {
+.site-dark .button-primary:hover,
+.site-dark .button-primary:focus-visible {
background: linear-gradient(135deg, #f6c945, #f47a28);
color: #1f1f1f;
}
-.home-header {
- padding: 0.72rem 0;
+.site-dark .menu-panel {
+ border-color: rgba(250, 248, 244, 0.12);
+ background: rgba(20, 18, 23, 0.96);
+ box-shadow: 0 24px 64px rgba(0, 0, 0, 0.34);
}
-.home-header .nav {
- gap: 0.35rem;
- font-size: 0.86rem;
+.site-dark .menu-item {
+ color: rgba(247, 243, 234, 0.82);
}
-.home-header .nav a {
- padding: 0.45rem 0.68rem;
+.site-dark .menu-item:hover,
+.site-dark .menu-item:focus-visible {
+ border-color: rgba(246, 201, 69, 0.24);
+ background: rgba(250, 248, 244, 0.08);
+ color: var(--color-fg);
}
-.home-header .nav .button {
- padding: 0.62rem 0.82rem;
+.site-dark .menu-item small,
+.site-dark .menu-hint {
+ color: rgba(247, 243, 234, 0.54);
}
-.home-hero {
- position: relative;
- min-height: 780px;
- display: flex;
- align-items: center;
- padding: 5.5rem 0 4.5rem;
- overflow: hidden;
- border-bottom: 1px solid rgba(250, 248, 244, 0.08);
+.site-dark .menu-sep {
+ background: rgba(250, 248, 244, 0.1);
}
-.home-hero::after {
- content: "";
- position: absolute;
- inset: auto 0 0;
- height: 34%;
- pointer-events: none;
- background: linear-gradient(to bottom, transparent, var(--color-bg));
+.site-dark .site-subnav {
+ border-top-color: rgba(250, 248, 244, 0.08);
}
-.home-hero-grid {
- position: absolute;
- inset: 0;
- pointer-events: none;
- background:
- linear-gradient(rgba(250, 248, 244, 0.055) 1px, transparent 1px),
- linear-gradient(90deg, rgba(250, 248, 244, 0.055) 1px, transparent 1px);
- background-size: 88px 88px;
- opacity: 0.42;
- mask-image: linear-gradient(to bottom, black 0%, black 72%, transparent 100%);
+.site-dark .site-subnav-label {
+ color: rgba(247, 243, 234, 0.52);
}
-.home-hero-layout {
- position: relative;
- z-index: 2;
- display: grid;
- grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
- gap: 3rem;
- align-items: center;
+.site-dark .site-subnav-parent {
+ border-color: rgba(250, 248, 244, 0.16);
+ background: rgba(250, 248, 244, 0.07);
+ color: var(--color-fg);
}
-.home-hero-copy {
- max-width: 700px;
+.site-dark .site-subnav-links a {
+ color: rgba(247, 243, 234, 0.62);
+ background: rgba(250, 248, 244, 0.04);
}
-.home-eyebrow {
- display: inline-flex;
- align-items: center;
- gap: 0.65rem;
- margin-bottom: 1.1rem;
- color: rgba(247, 243, 234, 0.76);
- font-size: 0.78rem;
- font-weight: 750;
- text-transform: uppercase;
- letter-spacing: 0.08em;
+.site-dark .site-subnav-links a:hover,
+.site-dark .site-subnav-links a:focus-visible,
+.site-dark .site-subnav-links a[aria-current="page"] {
+ color: var(--color-fg);
+ border-color: rgba(246, 201, 69, 0.28);
+ background: rgba(250, 248, 244, 0.08);
}
-.home-eyebrow-mark {
- width: 12px;
- height: 12px;
- border-radius: 50%;
+.site-dark .hero::before {
background:
- linear-gradient(90deg, transparent 42%, var(--color-gold) 42% 58%, transparent 58%),
- linear-gradient(0deg, transparent 42%, var(--color-green) 42% 58%, transparent 58%),
- var(--color-purple);
- box-shadow: 0 0 0 5px rgba(246, 201, 69, 0.09);
+ linear-gradient(rgba(250, 248, 244, 0.035) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(250, 248, 244, 0.035) 1px, transparent 1px),
+ linear-gradient(120deg, rgba(91, 59, 162, 0.14), transparent 52%);
+ background-size: 84px 84px, 84px 84px, auto;
}
-.home-hero-copy h1 {
- max-width: 700px;
- margin: 0;
- font-size: 5.6rem;
- line-height: 0.95;
- letter-spacing: 0;
- text-wrap: balance;
+.site-dark .hero-kicker {
+ border-color: rgba(250, 248, 244, 0.14);
+ background: rgba(250, 248, 244, 0.06);
+ color: rgba(247, 243, 234, 0.74);
}
-.home-lede {
- max-width: 640px;
- margin: 1.25rem 0 0;
- color: var(--color-muted);
- font-size: 1.18rem;
- line-height: 1.62;
- text-wrap: balance;
+.site-dark .panel,
+.site-dark .card,
+.site-dark .list {
+ border-color: rgba(250, 248, 244, 0.12);
+ background: rgba(250, 248, 244, 0.045);
+ box-shadow: var(--shadow);
}
-.home-actions {
- justify-content: flex-start;
- margin-top: 1.65rem;
+.site-dark .card::before {
+ background:
+ linear-gradient(135deg, rgba(246, 201, 69, 0.14), transparent 48%),
+ linear-gradient(210deg, rgba(91, 59, 162, 0.18), transparent 56%);
+ opacity: 1;
}
-.home-actions-left {
- margin-top: 1.35rem;
+.site-dark .panel-header {
+ border-bottom-color: rgba(250, 248, 244, 0.1);
+ background: rgba(250, 248, 244, 0.045);
}
-.home-metrics {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 0.8rem;
- max-width: 650px;
- margin-top: 2.2rem;
+.site-dark .card-title,
+.site-dark .list-title,
+.site-dark .panel-title {
+ color: var(--color-fg);
}
-.home-metrics div {
- min-width: 0;
- padding: 0.9rem 0;
- border-top: 1px solid rgba(250, 248, 244, 0.14);
+.site-dark .card-meta,
+.site-dark .list-desc,
+.site-dark p {
+ color: var(--color-muted);
}
-.home-metrics strong,
-.home-metrics span {
- display: block;
+.site-dark .list-row {
+ border-top-color: rgba(250, 248, 244, 0.1);
}
-.home-metrics strong {
- color: var(--color-fg);
- font-family: var(--font-display);
- font-size: 1.08rem;
- line-height: 1.2;
+.site-dark .list-row:hover,
+.site-dark .list-row:focus-visible {
+ background: rgba(250, 248, 244, 0.06);
}
-.home-metrics span {
+.site-dark .list-meta,
+.site-dark .footer-inner {
color: rgba(247, 243, 234, 0.54);
- font-size: 0.9rem;
- line-height: 1.35;
}
-.home-orbit {
- position: relative;
- min-height: 610px;
- perspective: 1100px;
+.site-dark code {
+ background: rgba(246, 201, 69, 0.1);
+ color: rgba(247, 243, 234, 0.92);
}
-.home-orbit::before {
- content: "";
- position: absolute;
- inset: 4% 2% 0;
- border: 1px solid rgba(91, 59, 162, 0.26);
- transform: rotateX(61deg) rotateZ(-28deg);
- transform-origin: center;
- background:
- linear-gradient(rgba(91, 59, 162, 0.16) 1px, transparent 1px),
- linear-gradient(90deg, rgba(91, 59, 162, 0.16) 1px, transparent 1px);
- background-size: 74px 74px;
- opacity: 0.92;
+.site-dark pre code {
+ background: transparent;
+ color: inherit;
}
-.home-orbit-plane {
- position: absolute;
- inset: 0;
- transform: rotateX(61deg) rotateZ(-28deg);
- transform-style: preserve-3d;
+.site-dark pre {
+ border-color: rgba(250, 248, 244, 0.12);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 18px 44px rgba(0, 0, 0, 0.24);
}
-.home-tile {
- position: absolute;
- width: 178px;
- min-height: 74px;
- padding: 0.75rem 0.85rem;
- border-radius: 8px;
- border: 1px solid rgba(250, 248, 244, 0.13);
- background: linear-gradient(180deg, rgba(91, 59, 162, 0.5), rgba(23, 20, 30, 0.9));
- color: var(--color-fg);
- box-shadow: 0 20px 30px rgba(0, 0, 0, 0.24);
- transform: translateZ(28px);
+.site-dark .site-footer {
+ border-top-color: rgba(250, 248, 244, 0.1);
}
-.home-tile::before {
- content: "";
- position: absolute;
- inset: 0;
- border-radius: inherit;
- background: linear-gradient(135deg, rgba(246, 201, 69, 0.18), transparent 48%);
- pointer-events: none;
+.section-heading {
+ max-width: 760px;
}
-.home-tile span,
-.home-tile small {
- position: relative;
- display: block;
+.section-heading h2,
+.docs-hub-tech-copy h2,
+.coming-soon-copy h1,
+.docs-hub-copy h1,
+.tech-hero-copy h1 {
+ letter-spacing: 0;
}
-.home-tile span {
+.section-kicker {
+ margin-bottom: 0.8rem;
+ color: var(--color-gold);
+ font-size: 0.78rem;
font-weight: 800;
- line-height: 1.15;
+ text-transform: uppercase;
+ letter-spacing: 0.1em;
}
-.home-tile small {
- margin-top: 0.24rem;
- color: rgba(247, 243, 234, 0.58);
- font-size: 0.74rem;
- line-height: 1.15;
+.tech-hero,
+.docs-hub-hero,
+.coming-soon {
+ position: relative;
+ overflow: hidden;
+ min-height: 760px;
+ display: flex;
+ align-items: center;
+ border-bottom: 1px solid rgba(250, 248, 244, 0.08);
}
-.tile-runtime {
- left: 14%;
- top: 26%;
+.tech-hero-grid,
+.docs-hub-grid,
+.coming-soon-grid {
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ background:
+ linear-gradient(rgba(250, 248, 244, 0.05) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(250, 248, 244, 0.05) 1px, transparent 1px);
+ background-size: 88px 88px;
+ opacity: 0.4;
+ mask-image: linear-gradient(to bottom, black 0%, black 72%, transparent 100%);
}
-.tile-silk {
- left: 40%;
- top: 18%;
- border-color: rgba(246, 201, 69, 0.36);
+.tech-system-map {
+ position: absolute;
+ inset: 8rem max(5vw, calc((100vw - var(--container)) / 2)) 6rem auto;
+ width: min(390px, 28vw);
+ pointer-events: none;
}
-.tile-sage {
- left: 62%;
- top: 31%;
+.system-map-frame {
+ position: relative;
+ height: 100%;
+ min-height: 460px;
}
-.tile-slg {
- left: 28%;
- top: 52%;
- border-color: rgba(244, 122, 40, 0.32);
+.system-map-line {
+ position: absolute;
+ background: rgba(250, 248, 244, 0.16);
}
-.tile-virtnosis {
- left: 55%;
- top: 58%;
- border-color: rgba(62, 155, 101, 0.34);
+.system-map-line-main {
+ left: 50%;
+ top: 0;
+ width: 1px;
+ height: 100%;
+ background: linear-gradient(180deg, transparent, rgba(246, 201, 69, 0.34), rgba(62, 155, 101, 0.24), transparent);
}
-.tile-edge {
- left: 73%;
- top: 52%;
+.system-map-line-runtime,
+.system-map-line-silk,
+.system-map-line-virtnosis {
+ left: 21%;
+ width: 58%;
+ height: 1px;
}
-.tile-policy {
- left: 5%;
- top: 47%;
- width: 138px;
+.system-map-line-runtime {
+ top: 22%;
}
-.tile-packages {
- left: 78%;
- top: 20%;
- width: 148px;
+.system-map-line-silk {
+ top: 50%;
}
-.tile-center {
- left: 43%;
- top: 40%;
- width: 152px;
- min-height: 96px;
- display: grid;
- place-items: center;
- text-align: center;
- background: linear-gradient(180deg, rgba(246, 201, 69, 0.24), rgba(91, 59, 162, 0.6));
- border-color: rgba(246, 201, 69, 0.48);
- transform: translateZ(64px);
-}
-
-.tile-center img {
- width: 34px;
- height: 34px;
- border-radius: 10px;
-}
-
-.tile-center span {
- margin-top: 0.35rem;
+.system-map-line-virtnosis {
+ top: 78%;
}
-.home-strip {
- padding: 2.5rem 0 3.5rem;
+.system-node {
+ position: absolute;
+ display: grid;
+ grid-template-columns: minmax(0, 1fr);
+ row-gap: 0.1rem;
+ width: min(245px, 100%);
+ padding: 0.95rem 0 0.95rem 1rem;
+ border-left: 1px solid rgba(250, 248, 244, 0.22);
+ background: linear-gradient(90deg, rgba(250, 248, 244, 0.07), transparent 82%);
+ color: rgba(247, 243, 234, 0.9);
}
-.home-project-strip {
- display: grid;
- grid-template-columns: repeat(5, minmax(0, 1fr));
- gap: 1rem;
- align-items: center;
+.system-node strong {
+ font-size: 1rem;
}
-.home-project-strip a {
- display: flex;
- align-items: center;
- justify-content: center;
- min-height: 76px;
- border: 1px solid rgba(250, 248, 244, 0.1);
- border-radius: 8px;
- background: rgba(250, 248, 244, 0.035);
- color: rgba(247, 243, 234, 0.62);
- text-decoration: none;
- font-family: var(--font-display);
- font-size: 1.08rem;
- font-weight: 800;
+.system-node small {
+ color: rgba(247, 243, 234, 0.52);
+ font-size: 0.82rem;
}
-.home-project-strip a:hover,
-.home-project-strip a:focus-visible {
- border-color: rgba(246, 201, 69, 0.34);
- color: var(--color-fg);
- background: rgba(250, 248, 244, 0.065);
+.node-runtime {
+ left: 0;
+ top: 16%;
}
-.home-proof {
- padding: 4.5rem 0 5rem;
- border-top: 1px solid rgba(250, 248, 244, 0.08);
- border-bottom: 1px solid rgba(250, 248, 244, 0.08);
+.node-silk {
+ right: 0;
+ top: 44%;
+ border-left-color: rgba(91, 59, 162, 0.5);
}
-.home-proof-grid {
- display: grid;
- grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
- gap: 4rem;
- align-items: center;
+.node-virtnosis {
+ left: 10%;
+ top: 72%;
+ border-left-color: rgba(62, 155, 101, 0.46);
}
-.home-proof-copy {
- display: grid;
- gap: 1.15rem;
+.tech-hero-copy,
+.docs-hub-copy,
+.coming-soon-copy {
+ position: relative;
+ z-index: 2;
+ padding: 7rem 0;
}
-.home-rule-item {
- padding: 0.3rem 0 0.35rem 1.25rem;
- border-left: 2px solid rgba(250, 248, 244, 0.14);
+.tech-hero-copy {
+ max-width: 720px;
}
-.home-rule-item[data-active="true"] {
- border-left-color: var(--color-gold);
+.docs-hub-copy,
+.coming-soon-copy {
+ max-width: 820px;
}
-.home-rule-item h2,
-.home-rule-item h3 {
+.tech-hero-copy h1 {
+ max-width: 720px;
margin: 0;
- line-height: 1.1;
- letter-spacing: 0;
+ color: var(--color-fg);
+ font-size: 4.75rem;
+ line-height: 1;
}
-.home-rule-item h2 {
- font-size: 2.4rem;
+.docs-hub-copy h1,
+.coming-soon-copy h1 {
+ max-width: 820px;
+ margin: 0;
+ color: var(--color-fg);
+ font-size: 5.1rem;
+ line-height: 0.98;
}
-.home-rule-item h3 {
- font-size: 1.35rem;
- color: rgba(247, 243, 234, 0.78);
+.tech-hero-copy p,
+.docs-hub-copy p,
+.coming-soon-copy p {
+ max-width: 680px;
+ margin-top: 1.25rem;
+ font-size: 1.16rem;
+ line-height: 1.62;
}
-.home-rule-item p {
- max-width: 460px;
- margin-top: 0.65rem;
- color: var(--color-muted);
- font-size: 1rem;
+.technology-section,
+.docs-hub-section {
+ padding: 5.5rem 0;
}
-.home-device-map {
+.technology-section {
position: relative;
- min-height: 390px;
- border: 1px solid rgba(91, 59, 162, 0.28);
- border-radius: 8px;
- background:
- linear-gradient(rgba(250, 248, 244, 0.04) 1px, transparent 1px),
- linear-gradient(90deg, rgba(250, 248, 244, 0.04) 1px, transparent 1px),
- rgba(250, 248, 244, 0.025);
- background-size: 64px 64px;
+ border-top: 1px solid rgba(250, 248, 244, 0.08);
overflow: hidden;
}
-.map-root,
-.map-node {
+.technology-section::before {
+ content: "";
position: absolute;
- display: grid;
- place-items: center;
- border-radius: 8px;
- border: 1px solid rgba(250, 248, 244, 0.14);
- background: rgba(17, 16, 15, 0.76);
- color: var(--color-fg);
- font-weight: 800;
+ inset: 0;
+ pointer-events: none;
+ background:
+ linear-gradient(rgba(250, 248, 244, 0.035) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(250, 248, 244, 0.035) 1px, transparent 1px);
+ background-size: 88px 88px;
+ opacity: 0.42;
+ mask-image: linear-gradient(90deg, transparent 0%, black 18%, black 82%, transparent 100%);
}
-.map-root {
- left: 50%;
- top: 18%;
- width: 132px;
- height: 48px;
- transform: translateX(-50%);
- border-color: rgba(246, 201, 69, 0.5);
- color: var(--color-gold);
+.technology-section-silk {
+ background: rgba(91, 59, 162, 0.035);
}
-.map-node {
- width: 122px;
- height: 72px;
- color: rgba(247, 243, 234, 0.76);
+.technology-section-virtnosis {
+ background: rgba(62, 155, 101, 0.026);
}
-.node-runtime {
- left: 12%;
- top: 62%;
+.technology-layout {
+ position: relative;
+ z-index: 1;
+ display: grid;
+ grid-template-columns: minmax(0, 0.95fr) minmax(360px, 0.85fr);
+ gap: 5rem;
+ align-items: center;
}
-.node-silk {
- left: 36%;
- top: 62%;
+.technology-layout-reverse {
+ grid-template-columns: minmax(360px, 0.85fr) minmax(0, 0.95fr);
}
-.node-slg {
- left: 60%;
- top: 62%;
+.technology-layout-reverse .technology-copy {
+ order: 2;
}
-.node-edge {
- left: 80%;
- top: 62%;
+.technology-copy h2 {
+ max-width: 760px;
+ margin: 0;
+ color: var(--color-fg);
+ font-size: 3.4rem;
+ line-height: 1.04;
+ letter-spacing: 0;
}
-.map-line {
- position: absolute;
- left: 18%;
- right: 12%;
- top: 40%;
- height: 1px;
- background: rgba(91, 59, 162, 0.75);
+.technology-copy p {
+ max-width: 680px;
+ margin-top: 1.15rem;
+ font-size: 1.06rem;
+ line-height: 1.65;
}
-.map-line::before,
-.map-line::after {
- content: "";
- position: absolute;
- width: 1px;
- height: 92px;
- top: 0;
- background: rgba(91, 59, 162, 0.75);
+.technology-feature-list {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 0.75rem;
+ max-width: 680px;
+ margin-top: 1.6rem;
+ padding: 0;
+ list-style: none;
}
-.map-line::before {
- left: 16%;
+.technology-feature-list li {
+ position: relative;
+ min-width: 0;
+ min-height: 86px;
+ padding: 0.86rem 0.95rem 0.88rem;
+ overflow: hidden;
+ border: 1px solid rgba(250, 248, 244, 0.12);
+ border-radius: 8px;
+ background:
+ linear-gradient(135deg, rgba(250, 248, 244, 0.072), rgba(250, 248, 244, 0.022)),
+ linear-gradient(90deg, rgba(246, 201, 69, 0.14), transparent 32%);
+ transition:
+ border-color 160ms ease,
+ background-color 160ms ease,
+ transform 160ms ease;
}
-.map-line::after {
- right: 18%;
+.technology-feature-list li::before {
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 0.8rem;
+ bottom: 0.8rem;
+ width: 2px;
+ border-radius: 999px;
+ background: var(--color-gold);
}
-.map-line-b {
- left: 42%;
- right: auto;
- width: 1px;
- height: 92px;
+.technology-feature-list li:nth-child(2)::before {
+ background: var(--color-purple);
}
-.map-line-c {
- left: 66%;
- right: auto;
- width: 1px;
- height: 92px;
+.technology-feature-list li:nth-child(3)::before {
+ background: var(--color-green);
}
-.map-line-b::before,
-.map-line-b::after,
-.map-line-c::before,
-.map-line-c::after {
- display: none;
+.technology-feature-list li:nth-child(4)::before {
+ background: var(--color-orange);
}
-.home-quote {
- position: relative;
- padding: 4.75rem 0;
- overflow: hidden;
- background:
- linear-gradient(115deg, rgba(91, 59, 162, 0.22) 0 48%, rgba(246, 201, 69, 0.08) 48% 49%, rgba(17, 16, 15, 0.4) 49%),
- #151311;
- border-bottom: 1px solid rgba(250, 248, 244, 0.08);
+.technology-feature-list li:hover {
+ border-color: rgba(246, 201, 69, 0.32);
+ background-color: rgba(250, 248, 244, 0.035);
+ transform: translateY(-1px);
}
-.home-quote blockquote {
- max-width: 920px;
- margin: 0 auto;
+.technology-feature-list strong {
+ display: block;
color: var(--color-fg);
- font-family: var(--font-display);
- font-size: 1.45rem;
- font-weight: 800;
- line-height: 1.35;
- text-align: center;
+ font-size: 0.96rem;
+ line-height: 1.25;
}
-.home-build {
- padding: 5.5rem 0 6rem;
+.technology-feature-list small {
+ display: block;
+ margin-top: 0.28rem;
+ color: rgba(247, 243, 234, 0.58);
+ font-size: 0.82rem;
+ line-height: 1.45;
}
-.home-build-grid {
- display: grid;
- grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
- gap: 4rem;
- align-items: center;
+.technology-feature-list code {
+ padding: 0.08rem 0.28rem;
+ font-size: 0.78em;
+}
+
+.technology-feature-list span {
+ min-width: 0;
+ padding: 0.62rem 0.8rem;
+ border: 1px solid rgba(250, 248, 244, 0.11);
+ border-radius: 999px;
+ background: rgba(250, 248, 244, 0.04);
+ color: rgba(247, 243, 234, 0.78);
+ font-size: 0.93rem;
+ font-weight: 700;
}
-.home-build-copy h2 {
+.technology-code pre {
margin: 0;
- font-size: 3rem;
- line-height: 1;
- letter-spacing: 0;
+ font-size: 0.9rem;
}
-.home-build-copy p {
- max-width: 460px;
- margin-top: 1rem;
- color: var(--color-muted);
+.technology-code {
+ min-width: 0;
}
-.home-build-mark {
- width: 34px;
- height: 34px;
+.runtime-example {
display: grid;
- place-items: center;
- margin-bottom: 1.1rem;
- border-radius: 50%;
- border: 1px solid rgba(244, 122, 40, 0.5);
- color: var(--color-orange);
- font-weight: 900;
+ gap: 0.8rem;
}
-.home-code-card {
- border: 1px solid rgba(250, 248, 244, 0.12);
+.runtime-code-tabs {
+ border-color: rgba(250, 248, 244, 0.13);
border-radius: 8px;
- background: rgba(250, 248, 244, 0.04);
- box-shadow: var(--shadow-elevated);
- overflow: hidden;
+ background: rgba(18, 15, 22, 0.86);
+ box-shadow: 0 18px 44px rgba(0, 0, 0, 0.24);
}
-.home-code-title {
- padding: 0.75rem 1rem;
- border-bottom: 1px solid rgba(250, 248, 244, 0.1);
- color: rgba(247, 243, 234, 0.78);
- font-family: var(--font-mono);
+.runtime-code-tabs .tabs-list {
+ gap: 0.35rem;
+ padding: 0.42rem;
+ border-bottom-color: rgba(250, 248, 244, 0.1);
+ background: rgba(250, 248, 244, 0.035);
+}
+
+.runtime-code-tabs .tabs-tab {
+ min-height: 34px;
+ padding: 0.42rem 0.72rem;
+ color: rgba(247, 243, 234, 0.58);
font-size: 0.82rem;
- font-weight: 800;
}
-.home-code-card pre {
+.runtime-code-tabs .tabs-tab:hover,
+.runtime-code-tabs .tabs-tab:focus-visible {
+ border-color: rgba(246, 201, 69, 0.32);
+ background: rgba(250, 248, 244, 0.07);
+ color: var(--color-fg);
+}
+
+.runtime-code-tabs .tabs-tab[aria-selected="true"] {
+ border-color: rgba(246, 201, 69, 0.42);
+ background: rgba(246, 201, 69, 0.12);
+ color: var(--color-fg);
+}
+
+.runtime-code-tabs .tabs-panel {
+ padding: 0;
+}
+
+.runtime-code-tabs pre {
+ max-height: 360px;
+ overflow: auto;
border: 0;
border-radius: 0;
+ background: transparent;
box-shadow: none;
- background: linear-gradient(180deg, #171616 0%, #1d1727 100%);
- font-size: 0.95rem;
}
-.home-section {
- position: relative;
- padding: 4rem 0 4.5rem;
+.technology-section-silk .technology-code pre {
+ max-height: 560px;
+ overflow: auto;
}
-.contact-panel {
- display: flex;
- justify-content: space-between;
- gap: 2rem;
+.technology-section-virtnosis .technology-code pre {
+ max-height: 520px;
+ overflow: auto;
+}
+
+.runtime-command {
+ display: grid;
+ grid-template-columns: auto minmax(0, 1fr);
+ gap: 0.8rem;
align-items: center;
- padding: 1.25rem 0;
- border-top: 1px solid rgba(250, 248, 244, 0.12);
+ padding: 0.62rem 0.75rem;
+ border: 1px solid rgba(250, 248, 244, 0.12);
+ border-radius: 8px;
+ background: rgba(250, 248, 244, 0.045);
}
-.contact-panel h2 {
- margin: 0;
- font-size: 1.8rem;
- line-height: 1;
- letter-spacing: 0;
+.runtime-command span {
+ color: rgba(247, 243, 234, 0.58);
+ font-size: 0.76rem;
+ font-weight: 800;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ white-space: nowrap;
+}
+
+.runtime-command pre {
+ padding: 0.35rem 0;
+ border: 0;
+ background: transparent;
+ box-shadow: none;
}
-.contact-links {
+.technology-links,
+.docs-selector {
display: flex;
flex-wrap: wrap;
- justify-content: flex-end;
gap: 0.55rem;
}
-.contact-links a {
- padding: 0.65rem 0.85rem;
- border-radius: 999px;
+.technology-links {
+ margin-top: 1.55rem;
+}
+
+.technology-links a,
+.docs-selector a,
+.docs-link-group a {
+ display: inline-flex;
+ align-items: center;
+ min-height: 42px;
+ padding: 0.58rem 0.75rem;
border: 1px solid rgba(250, 248, 244, 0.12);
- background: rgba(250, 248, 244, 0.06);
+ border-radius: 999px;
+ background: rgba(250, 248, 244, 0.045);
color: var(--color-fg);
text-decoration: none;
font-weight: 700;
}
-.contact-links a:hover,
-.contact-links a:focus-visible {
- border-color: rgba(246, 201, 69, 0.34);
- background: rgba(250, 248, 244, 0.1);
+.technology-links a:hover,
+.technology-links a:focus-visible,
+.docs-selector a:hover,
+.docs-selector a:focus-visible,
+.docs-link-group a:hover,
+.docs-link-group a:focus-visible {
+ border-color: rgba(246, 201, 69, 0.4);
+ background: rgba(250, 248, 244, 0.08);
}
-.home-footer {
- border-top-color: rgba(250, 248, 244, 0.08);
+.coming-soon {
+ min-height: 840px;
}
-.home-footer .footer-inner {
- color: rgba(247, 243, 234, 0.56);
+.blog-lanes {
+ position: relative;
+ z-index: 2;
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 1rem;
+ margin-top: 1.5rem;
}
-@media (max-width: 1180px) {
- .home-hero-layout,
- .home-proof-grid,
- .home-build-grid {
- grid-template-columns: 1fr;
- }
-
- .home-hero-copy {
- max-width: 780px;
- }
-
- .home-hero-copy h1 {
- max-width: 780px;
- font-size: 4.2rem;
- }
-
- .home-orbit {
- min-height: 500px;
- }
+.blog-lanes article,
+.blog-placeholder,
+.docs-link-group {
+ border: 1px solid rgba(250, 248, 244, 0.12);
+ border-radius: 8px;
+ background: rgba(250, 248, 244, 0.045);
}
-@media (max-width: 820px) {
- .home-hero {
- min-height: auto;
- padding: 4.25rem 0 3rem;
- }
-
- .home-hero-copy h1 {
- font-size: 3rem;
- line-height: 1;
- }
-
- .home-lede {
- font-size: 1.05rem;
- }
-
- .home-metrics,
- .home-project-strip {
- grid-template-columns: 1fr;
- }
+.blog-lanes article {
+ padding: 1rem;
+}
- .home-orbit {
- min-height: 360px;
- margin-top: 1rem;
- overflow: hidden;
- }
+.blog-lanes span {
+ color: var(--color-gold);
+ font-size: 0.78rem;
+ font-weight: 800;
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
+}
- .home-orbit::before,
- .home-orbit-plane {
- left: -30%;
- right: -22%;
- transform: rotateX(58deg) rotateZ(-24deg) scale(0.78);
- }
+.blog-lanes h2 {
+ margin-top: 0.6rem;
+ font-size: 1.35rem;
+}
- .home-tile {
- width: 150px;
- min-height: 68px;
- }
+.blog-lanes p {
+ margin-top: 0.55rem;
+ font-size: 0.98rem;
+}
- .home-proof,
- .home-build {
- padding: 3.75rem 0;
- }
+.blog-placeholder {
+ position: relative;
+ z-index: 2;
+ display: grid;
+ grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
+ gap: 2rem;
+ margin-top: 1rem;
+ padding: 1.2rem;
+}
- .home-rule-item h2,
- .home-build-copy h2 {
- font-size: 2.35rem;
- }
+.blog-placeholder h2 {
+ font-size: 1.7rem;
+}
- .home-device-map {
- min-height: 330px;
- }
+.docs-hub-hero {
+ min-height: 600px;
+}
- .map-root {
- top: 10%;
- }
+.docs-selector {
+ position: relative;
+ z-index: 2;
+ margin-top: 1.8rem;
+}
- .map-node {
- width: 112px;
- height: 60px;
- font-size: 0.84rem;
- }
+.docs-hub-tech {
+ display: grid;
+ grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
+ gap: 3rem;
+ align-items: start;
+}
- .node-runtime {
- left: 6%;
- top: 62%;
- }
+.docs-hub-tech-copy h2 {
+ max-width: 680px;
+ font-size: 3rem;
+ line-height: 1.04;
+}
- .node-silk {
- left: 35%;
- top: 62%;
- }
+.docs-hub-tech-copy p {
+ max-width: 620px;
+ margin-top: 1rem;
+}
- .node-slg {
- left: 64%;
- top: 62%;
- }
+.docs-link-groups {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 0.9rem;
+}
- .node-edge {
- display: none;
- }
+.docs-link-group {
+ display: flex;
+ flex-direction: column;
+ gap: 0.55rem;
+ min-width: 0;
+ padding: 0.95rem;
+}
- .contact-panel {
- align-items: flex-start;
- flex-direction: column;
- }
+.docs-link-group h3 {
+ color: var(--color-fg);
+ font-size: 1.1rem;
+ letter-spacing: 0;
+}
- .contact-links {
- justify-content: flex-start;
- }
+.docs-link-group a {
+ justify-content: flex-start;
+ border-radius: 8px;
}
-@media (max-width: 520px) {
- .home-hero-copy h1 {
- font-size: 2.45rem;
- }
+.docs-flow {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) 44px minmax(0, 1fr) 44px minmax(0, 1fr) 44px minmax(0, 1fr);
+ gap: 0.35rem;
+ align-items: center;
+ margin-top: 2rem;
+}
- .home-actions {
- align-items: stretch;
- flex-direction: column;
- }
+.docs-flow div {
+ display: grid;
+ min-height: 74px;
+ place-items: center;
+ border: 1px solid rgba(250, 248, 244, 0.12);
+ border-radius: 8px;
+ background: rgba(250, 248, 244, 0.045);
+ color: var(--color-fg);
+ font-weight: 800;
+}
- .home-actions .button {
- width: 100%;
- }
+.docs-flow span {
+ height: 1px;
+ background: rgba(246, 201, 69, 0.5);
}
+.docs-flow-silk span {
+ background: rgba(62, 155, 101, 0.5);
+}
-/* Oro repositioning */
-.site-dark {
- --color-bg: #11100f;
- --color-fg: #f7f3ea;
- --color-muted: rgba(247, 243, 234, 0.66);
- --color-border: rgba(250, 248, 244, 0.12);
- --color-border-strong: rgba(250, 248, 244, 0.22);
- --color-surface: rgba(250, 248, 244, 0.055);
- --color-surface-2: rgba(250, 248, 244, 0.085);
- --color-surface-3: rgba(250, 248, 244, 0.12);
- --color-code-bg: #151414;
- --color-code-bg-2: #1f1928;
- --shadow: 0 18px 42px rgba(0, 0, 0, 0.28);
- --shadow-elevated: 0 30px 80px rgba(0, 0, 0, 0.34);
+.docs-landing-page {
background: #11100f;
- color: var(--color-fg);
}
-.site-dark::before {
+.docs-landing-main {
+ position: relative;
+ border-top: 1px solid rgba(250, 248, 244, 0.08);
background:
linear-gradient(rgba(250, 248, 244, 0.035) 1px, transparent 1px),
linear-gradient(90deg, rgba(250, 248, 244, 0.035) 1px, transparent 1px),
- linear-gradient(180deg, rgba(91, 59, 162, 0.12), transparent 42%),
- linear-gradient(140deg, rgba(62, 155, 101, 0.08), transparent 46%);
- background-size: 72px 72px, 72px 72px, auto, auto;
- opacity: 1;
-}
-
-.site-dark .site-top {
- background: rgba(17, 16, 15, 0.9);
- border-bottom-color: rgba(250, 248, 244, 0.1);
- box-shadow: none;
+ radial-gradient(circle at 22% 12%, rgba(246, 201, 69, 0.08), transparent 32%),
+ radial-gradient(circle at 88% 18%, rgba(91, 59, 162, 0.12), transparent 34%),
+ #11100f;
+ background-size: 48px 48px, 48px 48px, auto, auto, auto;
}
-.site-dark .brand,
-.site-dark .footer-inner strong {
- color: var(--color-fg);
+.docs-landing-shell {
+ position: relative;
+ z-index: 1;
+ display: grid;
+ grid-template-columns: 280px minmax(0, 920px) 220px;
+ gap: 2.75rem;
+ width: min(100%, 1500px);
+ margin: 0 auto;
+ padding: 3rem var(--gutter) 5rem;
}
-.site-dark .brand-mark {
- border-color: rgba(250, 248, 244, 0.18);
- background: rgba(250, 248, 244, 0.08);
- box-shadow: 0 0 0 1px rgba(246, 201, 69, 0.08);
+.docs-landing-sidebar,
+.docs-landing-toc {
+ position: sticky;
+ top: 112px;
+ align-self: start;
}
-.site-dark .nav {
- color: rgba(247, 243, 234, 0.64);
+.docs-landing-sidebar {
+ max-height: calc(100vh - 140px);
+ overflow: auto;
+ padding-right: 1.25rem;
+ border-right: 1px solid rgba(250, 248, 244, 0.1);
}
-.site-dark .nav a {
- padding: 0.35rem 0;
+.docs-sidebar-home {
+ display: inline-flex;
+ min-height: 36px;
+ align-items: center;
+ color: var(--color-fg);
+ font-weight: 800;
+ text-decoration: none;
}
-.site-dark .nav a:hover,
-.site-dark .nav a:focus-visible {
- color: var(--color-fg);
+.docs-sidebar-nav {
+ display: grid;
+ gap: 1.8rem;
+ margin-top: 1.5rem;
}
-.site-dark .nav a[aria-current="page"] {
- color: var(--color-fg);
+.docs-sidebar-nav section {
+ display: grid;
+ gap: 0.22rem;
}
-.site-dark .button {
- border-color: rgba(250, 248, 244, 0.14);
- background: rgba(250, 248, 244, 0.06);
- color: var(--color-fg);
+.docs-sidebar-nav h2,
+.docs-landing-toc p,
+.docs-landing-kicker {
+ color: rgba(250, 248, 244, 0.62);
+ font-size: 0.72rem;
+ font-weight: 900;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
}
-.site-dark .button:hover,
-.site-dark .button:focus-visible {
- border-color: rgba(246, 201, 69, 0.42);
- background: rgba(250, 248, 244, 0.1);
+.docs-sidebar-nav a,
+.docs-landing-toc a {
+ display: flex;
+ min-height: 34px;
+ align-items: center;
+ border-radius: 8px;
+ color: rgba(250, 248, 244, 0.74);
+ text-decoration: none;
}
-.site-dark .button-primary {
- border-color: rgba(246, 201, 69, 0.68);
- background: linear-gradient(135deg, rgba(246, 201, 69, 0.92), rgba(244, 122, 40, 0.72));
- color: #1f1f1f;
- box-shadow: 0 16px 40px rgba(246, 201, 69, 0.12);
+.docs-sidebar-nav a {
+ padding: 0.28rem 0.55rem;
}
-.site-dark .button-primary:hover,
-.site-dark .button-primary:focus-visible {
- background: linear-gradient(135deg, #f6c945, #f47a28);
- color: #1f1f1f;
+.docs-sidebar-nav a:hover,
+.docs-sidebar-nav a:focus-visible,
+.docs-landing-toc a:hover,
+.docs-landing-toc a:focus-visible {
+ background: rgba(250, 248, 244, 0.06);
+ color: var(--color-fg);
}
-.site-dark .menu-panel {
- border-color: rgba(250, 248, 244, 0.12);
- background: rgba(20, 18, 23, 0.96);
- box-shadow: 0 24px 64px rgba(0, 0, 0, 0.34);
+.docs-landing-content {
+ min-width: 0;
}
-.site-dark .menu-item {
- color: rgba(247, 243, 234, 0.82);
+.docs-landing-intro {
+ padding: 1.2rem 0 2.5rem;
+ border-bottom: 1px solid rgba(250, 248, 244, 0.1);
}
-.site-dark .menu-item:hover,
-.site-dark .menu-item:focus-visible {
- border-color: rgba(246, 201, 69, 0.24);
- background: rgba(250, 248, 244, 0.08);
+.docs-landing-content h1 {
+ max-width: 760px;
+ margin-top: 0.85rem;
color: var(--color-fg);
+ font-size: 3.45rem;
+ line-height: 1.03;
}
-.site-dark .menu-item small,
-.site-dark .menu-hint {
- color: rgba(247, 243, 234, 0.54);
+.docs-landing-content h2 {
+ max-width: 700px;
+ color: var(--color-fg);
+ font-size: 2.3rem;
+ line-height: 1.08;
}
-.site-dark .menu-sep {
- background: rgba(250, 248, 244, 0.1);
+.docs-landing-content p {
+ color: rgba(250, 248, 244, 0.7);
+ line-height: 1.65;
}
-.site-dark .site-subnav {
- border-top-color: rgba(250, 248, 244, 0.08);
+.docs-landing-intro > p:not(.docs-landing-kicker) {
+ max-width: 760px;
+ margin-top: 1rem;
+ font-size: 1.05rem;
}
-.site-dark .site-subnav-label {
- color: rgba(247, 243, 234, 0.52);
+.docs-quick-select {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 0.8rem;
+ margin-top: 2rem;
}
-.site-dark .site-subnav-parent {
- border-color: rgba(250, 248, 244, 0.16);
- background: rgba(250, 248, 244, 0.07);
+.docs-quick-select a {
+ display: grid;
+ gap: 0.35rem;
+ min-height: 112px;
+ align-content: center;
+ padding: 1rem;
+ border: 1px solid rgba(250, 248, 244, 0.12);
+ border-radius: 8px;
+ background: rgba(250, 248, 244, 0.045);
color: var(--color-fg);
+ text-decoration: none;
}
-.site-dark .site-subnav-links a {
- color: rgba(247, 243, 234, 0.62);
- background: rgba(250, 248, 244, 0.04);
-}
-
-.site-dark .site-subnav-links a:hover,
-.site-dark .site-subnav-links a:focus-visible,
-.site-dark .site-subnav-links a[aria-current="page"] {
- color: var(--color-fg);
- border-color: rgba(246, 201, 69, 0.28);
- background: rgba(250, 248, 244, 0.08);
+.docs-quick-select a:first-child {
+ border-color: rgba(246, 201, 69, 0.26);
}
-.site-dark .hero::before {
- background:
- linear-gradient(rgba(250, 248, 244, 0.035) 1px, transparent 1px),
- linear-gradient(90deg, rgba(250, 248, 244, 0.035) 1px, transparent 1px),
- linear-gradient(120deg, rgba(91, 59, 162, 0.14), transparent 52%);
- background-size: 84px 84px, 84px 84px, auto;
+.docs-quick-select a:last-child {
+ border-color: rgba(91, 59, 162, 0.34);
}
-.site-dark .hero-kicker {
- border-color: rgba(250, 248, 244, 0.14);
- background: rgba(250, 248, 244, 0.06);
- color: rgba(247, 243, 234, 0.74);
+.docs-quick-select a:hover,
+.docs-quick-select a:focus-visible,
+.docs-section-action:hover,
+.docs-section-action:focus-visible,
+.docs-link-block a:hover,
+.docs-link-block a:focus-visible {
+ border-color: rgba(246, 201, 69, 0.5);
+ background: rgba(250, 248, 244, 0.075);
}
-.site-dark .panel,
-.site-dark .card,
-.site-dark .list {
- border-color: rgba(250, 248, 244, 0.12);
- background: rgba(250, 248, 244, 0.045);
- box-shadow: var(--shadow);
+.docs-quick-select span {
+ font-weight: 900;
}
-.site-dark .card::before {
- background:
- linear-gradient(135deg, rgba(246, 201, 69, 0.14), transparent 48%),
- linear-gradient(210deg, rgba(91, 59, 162, 0.18), transparent 56%);
- opacity: 1;
+.docs-quick-select small,
+.docs-link-block small {
+ color: rgba(250, 248, 244, 0.58);
+ line-height: 1.45;
}
-.site-dark .panel-header {
- border-bottom-color: rgba(250, 248, 244, 0.1);
- background: rgba(250, 248, 244, 0.045);
+.docs-tech-section {
+ padding: 3rem 0;
+ border-bottom: 1px solid rgba(250, 248, 244, 0.1);
}
-.site-dark .card-title,
-.site-dark .list-title,
-.site-dark .panel-title {
- color: var(--color-fg);
+.docs-tech-heading {
+ display: flex;
+ gap: 1.5rem;
+ align-items: flex-start;
+ justify-content: space-between;
}
-.site-dark .card-meta,
-.site-dark .list-desc,
-.site-dark p {
- color: var(--color-muted);
+.docs-tech-heading h2 {
+ margin-top: 0.7rem;
}
-.site-dark .list-row {
- border-top-color: rgba(250, 248, 244, 0.1);
+.docs-section-action {
+ display: inline-flex;
+ min-width: 150px;
+ min-height: 42px;
+ align-items: center;
+ justify-content: center;
+ padding: 0.55rem 0.9rem;
+ border: 1px solid rgba(246, 201, 69, 0.34);
+ border-radius: 999px;
+ background: rgba(246, 201, 69, 0.08);
+ color: var(--color-fg);
+ font-weight: 800;
+ text-decoration: none;
+ white-space: nowrap;
}
-.site-dark .list-row:hover,
-.site-dark .list-row:focus-visible {
- background: rgba(250, 248, 244, 0.06);
+.docs-tech-summary {
+ max-width: 780px;
+ margin-top: 1rem;
}
-.site-dark .list-meta,
-.site-dark .footer-inner {
- color: rgba(247, 243, 234, 0.54);
+.docs-link-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 1.1rem;
+ margin-top: 2rem;
}
-.site-dark code {
- background: rgba(246, 201, 69, 0.1);
- color: rgba(247, 243, 234, 0.92);
+.docs-link-block {
+ min-width: 0;
+ padding-top: 1rem;
+ border-top: 1px solid rgba(250, 248, 244, 0.12);
}
-.site-dark pre code {
- background: transparent;
- color: inherit;
+.docs-link-block h3 {
+ color: var(--color-fg);
+ font-size: 1rem;
}
-.site-dark pre {
- border-color: rgba(250, 248, 244, 0.12);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04), 0 18px 44px rgba(0, 0, 0, 0.24);
+.docs-link-block a {
+ display: grid;
+ gap: 0.18rem;
+ margin-top: 0.7rem;
+ min-height: 72px;
+ padding: 0.82rem 0.9rem;
+ border: 1px solid rgba(250, 248, 244, 0.1);
+ border-radius: 8px;
+ background: rgba(250, 248, 244, 0.035);
+ color: var(--color-fg);
+ text-decoration: none;
}
-.site-dark .site-footer {
- border-top-color: rgba(250, 248, 244, 0.1);
+.docs-link-block span {
+ font-weight: 800;
}
-.section-heading {
- max-width: 760px;
+.docs-link-block code {
+ background: rgba(246, 201, 69, 0.12);
+ color: var(--color-gold);
}
-.section-heading h2,
-.docs-hub-tech-copy h2,
-.coming-soon-copy h1,
-.docs-hub-copy h1,
-.tech-hero-copy h1 {
- letter-spacing: 0;
+.docs-landing-toc {
+ display: grid;
+ gap: 0.18rem;
+ padding-left: 1rem;
+ border-left: 1px solid rgba(250, 248, 244, 0.1);
}
-.section-kicker {
- margin-bottom: 0.8rem;
- color: var(--color-gold);
- font-size: 0.78rem;
- font-weight: 800;
- text-transform: uppercase;
- letter-spacing: 0.1em;
+.docs-landing-toc p {
+ margin-bottom: 0.35rem;
+ color: var(--color-fg);
}
-.tech-hero,
-.docs-hub-hero,
-.coming-soon {
- position: relative;
- overflow: hidden;
- min-height: 760px;
- display: flex;
- align-items: center;
- border-bottom: 1px solid rgba(250, 248, 244, 0.08);
+.docs-landing-toc a {
+ padding: 0.25rem 0.5rem;
+ font-size: 0.92rem;
}
-.tech-hero-grid,
-.docs-hub-grid,
-.coming-soon-grid {
- position: absolute;
- inset: 0;
- pointer-events: none;
- background:
- linear-gradient(rgba(250, 248, 244, 0.05) 1px, transparent 1px),
- linear-gradient(90deg, rgba(250, 248, 244, 0.05) 1px, transparent 1px);
- background-size: 88px 88px;
- opacity: 0.4;
- mask-image: linear-gradient(to bottom, black 0%, black 72%, transparent 100%);
+.product-page .hero h1 {
+ max-width: 760px;
+ font-size: 4.4rem;
+ line-height: 1;
+ letter-spacing: 0;
}
-.tech-system-map {
- position: absolute;
- inset: 8rem max(5vw, calc((100vw - var(--container)) / 2)) 6rem auto;
- width: min(390px, 28vw);
- pointer-events: none;
+.product-page .hero {
+ padding: 5.25rem 0;
+ border-bottom: 1px solid rgba(250, 248, 244, 0.08);
}
-.system-map-frame {
- position: relative;
- height: 100%;
- min-height: 460px;
+.product-page .section {
+ border-top: 1px solid rgba(250, 248, 244, 0.06);
}
-.system-map-line {
- position: absolute;
- background: rgba(250, 248, 244, 0.16);
+.learn-copy {
+ position: relative;
+ flex: 0 0 auto;
+ width: 36px;
+ height: 36px;
+ border: 1px solid rgba(250, 248, 244, 0.28);
+ border-radius: 6px;
+ background: rgba(250, 248, 244, 0.08);
+ color: rgba(250, 248, 244, 0.92);
+ cursor: pointer;
+ -webkit-appearance: none;
+ appearance: none;
}
-.system-map-line-main {
- left: 50%;
- top: 0;
- width: 1px;
- height: 100%;
- background: linear-gradient(180deg, transparent, rgba(246, 201, 69, 0.34), rgba(62, 155, 101, 0.24), transparent);
+.learn-copy::before,
+.learn-copy::after {
+ content: "";
+ position: absolute;
+ width: 11px;
+ height: 13px;
+ border: 2px solid currentColor;
+ border-radius: 2px;
}
-.system-map-line-runtime,
-.system-map-line-silk,
-.system-map-line-virtnosis {
- left: 21%;
- width: 58%;
- height: 1px;
+.learn-copy::before {
+ left: 10px;
+ top: 8px;
+ opacity: 0.72;
}
-.system-map-line-runtime {
- top: 22%;
+.learn-copy::after {
+ left: 14px;
+ top: 12px;
+ background: rgba(6, 5, 7, 0.92);
}
-.system-map-line-silk {
- top: 50%;
+.learn-copy:hover,
+.learn-copy:focus-visible {
+ border-color: rgba(246, 201, 69, 0.62);
+ background: rgba(250, 248, 244, 0.14);
+ color: #fffdf9;
}
-.system-map-line-virtnosis {
- top: 78%;
+.learn-copy[data-copy-state="copied"] {
+ border-color: rgba(62, 155, 101, 0.58);
+ color: #8fd4aa;
}
-.system-node {
- position: absolute;
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- row-gap: 0.1rem;
- width: min(245px, 100%);
- padding: 0.95rem 0 0.95rem 1rem;
- border-left: 1px solid rgba(250, 248, 244, 0.22);
- background: linear-gradient(90deg, rgba(250, 248, 244, 0.07), transparent 82%);
- color: rgba(247, 243, 234, 0.9);
+.learn-copy[data-copy-state="failed"] {
+ border-color: rgba(244, 122, 40, 0.58);
+ color: #ffb17f;
}
-.system-node strong {
- font-size: 1rem;
+.docs-page .section {
+ padding: 2.2rem 0 4.5rem;
}
-.system-node small {
- color: rgba(247, 243, 234, 0.52);
- font-size: 0.82rem;
+.docs-page .docs-layout {
+ gap: 2.75rem;
}
-.node-runtime {
- left: 0;
- top: 16%;
+.docs-page .docs-layout[data-has-toc="true"] {
+ grid-template-columns: 300px minmax(0, 900px) 260px;
}
-.node-silk {
- right: 0;
- top: 44%;
- border-left-color: rgba(91, 59, 162, 0.5);
+.docs-page .docs-sidebar,
+.docs-page .docs-toc {
+ border-color: rgba(250, 248, 244, 0.12);
+ background: rgba(250, 248, 244, 0.035);
+ box-shadow: none;
}
-.node-virtnosis {
- left: 10%;
- top: 72%;
- border-left-color: rgba(62, 155, 101, 0.46);
+.docs-page .docs-sidebar {
+ border-radius: 0;
+ border-width: 0 1px 0 0;
+ padding-right: 1.2rem;
}
-.tech-hero-copy,
-.docs-hub-copy,
-.coming-soon-copy {
- position: relative;
- z-index: 2;
- padding: 7rem 0;
+.docs-page .docs-toc {
+ border-radius: 0;
+ border-width: 0 0 0 1px;
+ padding-left: 1.2rem;
}
-.tech-hero-copy {
- max-width: 720px;
+.docs-page .docs-sidebar-header {
+ border-bottom-color: rgba(250, 248, 244, 0.1);
}
-.docs-hub-copy,
-.coming-soon-copy {
- max-width: 820px;
+.docs-page .docs-sidebar-title,
+.docs-page .docs-toc-title,
+.docs-page .docs-search-result-title,
+.docs-page .docs-prevnext-title,
+.docs-page .docs-content h1,
+.docs-page .docs-content h2,
+.docs-page .docs-content h3,
+.docs-page .docs-content h4 {
+ color: var(--color-fg);
}
-.tech-hero-copy h1 {
- max-width: 720px;
- margin: 0;
- color: var(--color-fg);
- font-size: 4.75rem;
- line-height: 1;
-}
-
-.docs-hub-copy h1,
-.coming-soon-copy h1 {
- max-width: 820px;
- margin: 0;
+.docs-page .docs-search {
+ border-color: rgba(250, 248, 244, 0.14);
+ background: rgba(250, 248, 244, 0.055);
color: var(--color-fg);
- font-size: 5.1rem;
- line-height: 0.98;
-}
-
-.tech-hero-copy p,
-.docs-hub-copy p,
-.coming-soon-copy p {
- max-width: 680px;
- margin-top: 1.25rem;
- font-size: 1.16rem;
- line-height: 1.62;
-}
-
-.technology-section,
-.docs-hub-section {
- padding: 5.5rem 0;
-}
-
-.technology-section {
- position: relative;
- border-top: 1px solid rgba(250, 248, 244, 0.08);
- overflow: hidden;
-}
-
-.technology-section::before {
- content: "";
- position: absolute;
- inset: 0;
- pointer-events: none;
- background:
- linear-gradient(rgba(250, 248, 244, 0.035) 1px, transparent 1px),
- linear-gradient(90deg, rgba(250, 248, 244, 0.035) 1px, transparent 1px);
- background-size: 88px 88px;
- opacity: 0.42;
- mask-image: linear-gradient(90deg, transparent 0%, black 18%, black 82%, transparent 100%);
}
-.technology-section-silk {
- background: rgba(91, 59, 162, 0.035);
+.docs-page .docs-search::placeholder {
+ color: rgba(247, 243, 234, 0.44);
}
-.technology-section-virtnosis {
- background: rgba(62, 155, 101, 0.026);
+.docs-page .docs-nav-section,
+.docs-page .docs-search-result-meta,
+.docs-page .docs-breadcrumb,
+.docs-page .docs-prevnext-label,
+.docs-page .spec-toc-title {
+ color: rgba(247, 243, 234, 0.48);
}
-.technology-layout {
- position: relative;
- z-index: 1;
- display: grid;
- grid-template-columns: minmax(0, 0.95fr) minmax(360px, 0.85fr);
- gap: 5rem;
- align-items: center;
+.docs-page .docs-nav a,
+.docs-page .docs-toc-list a,
+.docs-page .spec-toc a {
+ color: rgba(247, 243, 234, 0.62);
}
-.technology-layout-reverse {
- grid-template-columns: minmax(360px, 0.85fr) minmax(0, 0.95fr);
+.docs-page .docs-nav a:hover,
+.docs-page .docs-nav a:focus-visible,
+.docs-page .docs-nav a[data-active="true"],
+.docs-page .docs-toc-list a:hover,
+.docs-page .docs-toc-list a:focus-visible,
+.docs-page .spec-toc a:hover,
+.docs-page .spec-toc a:focus-visible,
+.docs-page .spec-toc a[data-active="true"] {
+ color: var(--color-fg);
+ background: rgba(250, 248, 244, 0.07);
}
-.technology-layout-reverse .technology-copy {
- order: 2;
+.docs-page .docs-content .prose,
+.docs-page .spec-prose {
+ max-width: 92ch;
}
-.technology-copy h2 {
- max-width: 760px;
- margin: 0;
- color: var(--color-fg);
- font-size: 3.4rem;
- line-height: 1.04;
+.docs-page .docs-content .prose > h1:first-child,
+.docs-page .spec-prose > h1:first-child {
+ font-size: 3.05rem;
+ line-height: 1.05;
letter-spacing: 0;
}
-.technology-copy p {
- max-width: 680px;
- margin-top: 1.15rem;
- font-size: 1.06rem;
- line-height: 1.65;
+.docs-page .docs-content p,
+.docs-page .docs-content li,
+.docs-page .docs-content dd,
+.docs-page .spec-prose p,
+.docs-page .spec-prose li,
+.docs-page .spec-prose dd {
+ color: rgba(247, 243, 234, 0.68);
}
-.technology-feature-list {
+.docs-layout .prose ul,
+.docs-layout .prose ol,
+.spec-prose ul,
+.spec-prose ol {
display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 0.75rem;
- max-width: 680px;
- margin-top: 1.6rem;
+ gap: 0.55rem;
+ margin: 1.1rem 0;
padding: 0;
list-style: none;
}
-.technology-feature-list li {
+.docs-layout .prose li,
+.spec-prose li {
position: relative;
- min-width: 0;
- min-height: 86px;
- padding: 0.86rem 0.95rem 0.88rem;
- overflow: hidden;
- border: 1px solid rgba(250, 248, 244, 0.12);
+ margin: 0;
+ padding: 0.72rem 0.86rem 0.72rem 1rem;
+ border: 1px solid rgba(31, 31, 31, 0.1);
+ border-left: 2px solid rgba(246, 201, 69, 0.44);
border-radius: 8px;
- background:
- linear-gradient(135deg, rgba(250, 248, 244, 0.072), rgba(250, 248, 244, 0.022)),
- linear-gradient(90deg, rgba(246, 201, 69, 0.14), transparent 32%);
- transition:
- border-color 160ms ease,
- background-color 160ms ease,
- transform 160ms ease;
+ background: rgba(255, 255, 255, 0.6);
}
-.technology-feature-list li::before {
- content: "";
- position: absolute;
- left: 0;
- top: 0.8rem;
- bottom: 0.8rem;
- width: 2px;
- border-radius: 999px;
- background: var(--color-gold);
+.docs-layout .prose li + li,
+.spec-prose li + li {
+ margin-top: 0;
}
-.technology-feature-list li:nth-child(2)::before {
- background: var(--color-purple);
+.docs-layout .prose ol,
+.spec-prose ol {
+ counter-reset: docs-ordered-list;
}
-.technology-feature-list li:nth-child(3)::before {
- background: var(--color-green);
+.docs-layout .prose ol > li,
+.spec-prose ol > li {
+ counter-increment: docs-ordered-list;
+ padding-left: 2.75rem;
}
-.technology-feature-list li:nth-child(4)::before {
- background: var(--color-orange);
+.docs-layout .prose ol > li::before,
+.spec-prose ol > li::before {
+ content: counter(docs-ordered-list);
+ position: absolute;
+ left: 0.78rem;
+ top: 0.72rem;
+ display: inline-grid;
+ place-items: center;
+ min-width: 1.32rem;
+ height: 1.32rem;
+ padding: 0 0.18rem;
+ border: 1px solid rgba(246, 201, 69, 0.38);
+ border-radius: 999px;
+ background: rgba(246, 201, 69, 0.12);
+ color: var(--color-gold);
+ font-family: var(--font-mono);
+ font-size: 0.7rem;
+ font-weight: 800;
+ line-height: 1;
}
-.technology-feature-list li:hover {
- border-color: rgba(246, 201, 69, 0.32);
- background-color: rgba(250, 248, 244, 0.035);
- transform: translateY(-1px);
+.docs-layout .prose li > p:first-child,
+.spec-prose li > p:first-child {
+ margin-top: 0;
}
-.technology-feature-list strong {
- display: block;
- color: var(--color-fg);
- font-size: 0.96rem;
- line-height: 1.25;
+.docs-layout .prose li > p:last-child,
+.spec-prose li > p:last-child {
+ margin-bottom: 0;
}
-.technology-feature-list small {
- display: block;
- margin-top: 0.28rem;
- color: rgba(247, 243, 234, 0.58);
- font-size: 0.82rem;
- line-height: 1.45;
+.docs-layout .prose li > ul,
+.docs-layout .prose li > ol,
+.spec-prose li > ul,
+.spec-prose li > ol {
+ gap: 0.42rem;
+ margin: 0.64rem 0 0;
}
-.technology-feature-list code {
- padding: 0.08rem 0.28rem;
- font-size: 0.78em;
+.docs-layout .prose li > ul > li,
+.docs-layout .prose li > ol > li,
+.spec-prose li > ul > li,
+.spec-prose li > ol > li {
+ padding-top: 0.56rem;
+ padding-bottom: 0.56rem;
+ background: rgba(31, 31, 31, 0.035);
}
-.technology-feature-list span {
- min-width: 0;
- padding: 0.62rem 0.8rem;
- border: 1px solid rgba(250, 248, 244, 0.11);
- border-radius: 999px;
- background: rgba(250, 248, 244, 0.04);
- color: rgba(247, 243, 234, 0.78);
- font-size: 0.93rem;
- font-weight: 700;
+.site-dark .docs-layout .prose li,
+.site-dark .spec-prose li,
+.docs-page .docs-layout .prose li,
+.docs-page .spec-prose li {
+ border-color: rgba(250, 248, 244, 0.1);
+ border-left-color: rgba(246, 201, 69, 0.46);
+ background: rgba(250, 248, 244, 0.045);
}
-.technology-code pre {
- margin: 0;
- font-size: 0.9rem;
+.site-dark .docs-layout .prose li > ul > li,
+.site-dark .docs-layout .prose li > ol > li,
+.site-dark .spec-prose li > ul > li,
+.site-dark .spec-prose li > ol > li,
+.docs-page .docs-layout .prose li > ul > li,
+.docs-page .docs-layout .prose li > ol > li,
+.docs-page .spec-prose li > ul > li,
+.docs-page .spec-prose li > ol > li {
+ background: rgba(250, 248, 244, 0.035);
}
-.technology-code {
- min-width: 0;
+.docs-page .docs-inline-ref {
+ color: var(--color-fg);
+ text-decoration-color: rgba(246, 201, 69, 0.35);
}
-.runtime-example {
- display: grid;
- gap: 0.8rem;
-}
-
-.runtime-code-tabs {
- border-color: rgba(250, 248, 244, 0.13);
- border-radius: 8px;
- background: rgba(18, 15, 22, 0.86);
- box-shadow: 0 18px 44px rgba(0, 0, 0, 0.24);
-}
-
-.runtime-code-tabs .tabs-list {
- gap: 0.35rem;
- padding: 0.42rem;
- border-bottom-color: rgba(250, 248, 244, 0.1);
- background: rgba(250, 248, 244, 0.035);
-}
-
-.runtime-code-tabs .tabs-tab {
- min-height: 34px;
- padding: 0.42rem 0.72rem;
- color: rgba(247, 243, 234, 0.58);
- font-size: 0.82rem;
-}
-
-.runtime-code-tabs .tabs-tab:hover,
-.runtime-code-tabs .tabs-tab:focus-visible {
- border-color: rgba(246, 201, 69, 0.32);
- background: rgba(250, 248, 244, 0.07);
- color: var(--color-fg);
-}
-
-.runtime-code-tabs .tabs-tab[aria-selected="true"] {
- border-color: rgba(246, 201, 69, 0.42);
- background: rgba(246, 201, 69, 0.12);
- color: var(--color-fg);
-}
-
-.runtime-code-tabs .tabs-panel {
- padding: 0;
-}
-
-.runtime-code-tabs pre {
- max-height: 360px;
- overflow: auto;
- border: 0;
- border-radius: 0;
- background: transparent;
- box-shadow: none;
-}
-
-.technology-section-silk .technology-code pre {
- max-height: 560px;
- overflow: auto;
-}
-
-.technology-section-virtnosis .technology-code pre {
- max-height: 520px;
- overflow: auto;
-}
-
-.runtime-command {
- display: grid;
- grid-template-columns: auto minmax(0, 1fr);
- gap: 0.8rem;
- align-items: center;
- padding: 0.62rem 0.75rem;
- border: 1px solid rgba(250, 248, 244, 0.12);
- border-radius: 8px;
- background: rgba(250, 248, 244, 0.045);
-}
-
-.runtime-command span {
- color: rgba(247, 243, 234, 0.58);
- font-size: 0.76rem;
- font-weight: 800;
- letter-spacing: 0.08em;
- text-transform: uppercase;
- white-space: nowrap;
-}
-
-.runtime-command pre {
- padding: 0.35rem 0;
- border: 0;
- background: transparent;
- box-shadow: none;
-}
-
-.technology-links,
-.docs-selector {
- display: flex;
- flex-wrap: wrap;
- gap: 0.55rem;
-}
-
-.technology-links {
- margin-top: 1.55rem;
-}
-
-.technology-links a,
-.docs-selector a,
-.docs-link-group a {
- display: inline-flex;
- align-items: center;
- min-height: 42px;
- padding: 0.58rem 0.75rem;
- border: 1px solid rgba(250, 248, 244, 0.12);
- border-radius: 999px;
- background: rgba(250, 248, 244, 0.045);
- color: var(--color-fg);
- text-decoration: none;
- font-weight: 700;
-}
-
-.technology-links a:hover,
-.technology-links a:focus-visible,
-.docs-selector a:hover,
-.docs-selector a:focus-visible,
-.docs-link-group a:hover,
-.docs-link-group a:focus-visible {
- border-color: rgba(246, 201, 69, 0.4);
+.docs-page .docs-inline-code,
+.docs-page .prose code {
background: rgba(250, 248, 244, 0.08);
+ color: rgba(247, 243, 234, 0.92);
}
-.coming-soon {
- min-height: 840px;
-}
-
-.blog-lanes {
- position: relative;
- z-index: 2;
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 1rem;
- margin-top: 1.5rem;
-}
-
-.blog-lanes article,
-.blog-placeholder,
-.docs-link-group {
- border: 1px solid rgba(250, 248, 244, 0.12);
- border-radius: 8px;
- background: rgba(250, 248, 244, 0.045);
+.docs-page .prose pre {
+ padding: 0;
}
-.blog-lanes article {
+.docs-page .prose pre code,
+.docs-page .prose pre code.hljs {
+ display: block;
padding: 1rem;
+ background: transparent;
}
-.blog-lanes span {
- color: var(--color-gold);
- font-size: 0.78rem;
- font-weight: 800;
- text-transform: uppercase;
- letter-spacing: 0.08em;
-}
-
-.blog-lanes h2 {
- margin-top: 0.6rem;
- font-size: 1.35rem;
-}
-
-.blog-lanes p {
- margin-top: 0.55rem;
- font-size: 0.98rem;
-}
-
-.blog-placeholder {
- position: relative;
- z-index: 2;
- display: grid;
- grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
- gap: 2rem;
- margin-top: 1rem;
- padding: 1.2rem;
-}
-
-.blog-placeholder h2 {
- font-size: 1.7rem;
-}
-
-.docs-hub-hero {
- min-height: 600px;
-}
-
-.docs-selector {
- position: relative;
- z-index: 2;
- margin-top: 1.8rem;
-}
-
-.docs-hub-tech {
- display: grid;
- grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
- gap: 3rem;
- align-items: start;
-}
-
-.docs-hub-tech-copy h2 {
- max-width: 680px;
- font-size: 3rem;
- line-height: 1.04;
-}
-
-.docs-hub-tech-copy p {
- max-width: 620px;
- margin-top: 1rem;
-}
-
-.docs-link-groups {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 0.9rem;
-}
-
-.docs-link-group {
- display: flex;
- flex-direction: column;
- gap: 0.55rem;
- min-width: 0;
- padding: 0.95rem;
-}
-
-.docs-link-group h3 {
- color: var(--color-fg);
- font-size: 1.1rem;
- letter-spacing: 0;
-}
-
-.docs-link-group a {
- justify-content: flex-start;
- border-radius: 8px;
-}
-
-.docs-flow {
- display: grid;
- grid-template-columns: minmax(0, 1fr) 44px minmax(0, 1fr) 44px minmax(0, 1fr) 44px minmax(0, 1fr);
- gap: 0.35rem;
- align-items: center;
- margin-top: 2rem;
-}
-
-.docs-flow div {
- display: grid;
- min-height: 74px;
- place-items: center;
- border: 1px solid rgba(250, 248, 244, 0.12);
- border-radius: 8px;
- background: rgba(250, 248, 244, 0.045);
- color: var(--color-fg);
- font-weight: 800;
-}
-
-.docs-flow span {
- height: 1px;
- background: rgba(246, 201, 69, 0.5);
-}
-
-.docs-flow-silk span {
- background: rgba(62, 155, 101, 0.5);
-}
-
-.docs-landing-page {
- background: #11100f;
-}
-
-.docs-landing-main {
- position: relative;
- border-top: 1px solid rgba(250, 248, 244, 0.08);
- background:
- linear-gradient(rgba(250, 248, 244, 0.035) 1px, transparent 1px),
- linear-gradient(90deg, rgba(250, 248, 244, 0.035) 1px, transparent 1px),
- radial-gradient(circle at 22% 12%, rgba(246, 201, 69, 0.08), transparent 32%),
- radial-gradient(circle at 88% 18%, rgba(91, 59, 162, 0.12), transparent 34%),
- #11100f;
- background-size: 48px 48px, 48px 48px, auto, auto, auto;
-}
-
-.docs-landing-shell {
- position: relative;
- z-index: 1;
- display: grid;
- grid-template-columns: 280px minmax(0, 920px) 220px;
- gap: 2.75rem;
- width: min(100%, 1500px);
- margin: 0 auto;
- padding: 3rem var(--gutter) 5rem;
-}
-
-.docs-landing-sidebar,
-.docs-landing-toc {
- position: sticky;
- top: 112px;
- align-self: start;
-}
-
-.docs-landing-sidebar {
- max-height: calc(100vh - 140px);
- overflow: auto;
- padding-right: 1.25rem;
- border-right: 1px solid rgba(250, 248, 244, 0.1);
-}
-
-.docs-sidebar-home {
- display: inline-flex;
- min-height: 36px;
- align-items: center;
- color: var(--color-fg);
- font-weight: 800;
- text-decoration: none;
-}
-
-.docs-sidebar-nav {
- display: grid;
- gap: 1.8rem;
- margin-top: 1.5rem;
-}
-
-.docs-sidebar-nav section {
- display: grid;
- gap: 0.22rem;
-}
-
-.docs-sidebar-nav h2,
-.docs-landing-toc p,
-.docs-landing-kicker {
- color: rgba(250, 248, 244, 0.62);
- font-size: 0.72rem;
- font-weight: 900;
- letter-spacing: 0.12em;
- text-transform: uppercase;
-}
-
-.docs-sidebar-nav a,
-.docs-landing-toc a {
- display: flex;
- min-height: 34px;
- align-items: center;
- border-radius: 8px;
- color: rgba(250, 248, 244, 0.74);
- text-decoration: none;
-}
-
-.docs-sidebar-nav a {
- padding: 0.28rem 0.55rem;
-}
-
-.docs-sidebar-nav a:hover,
-.docs-sidebar-nav a:focus-visible,
-.docs-landing-toc a:hover,
-.docs-landing-toc a:focus-visible {
- background: rgba(250, 248, 244, 0.06);
- color: var(--color-fg);
-}
-
-.docs-landing-content {
- min-width: 0;
-}
-
-.docs-landing-intro {
- padding: 1.2rem 0 2.5rem;
- border-bottom: 1px solid rgba(250, 248, 244, 0.1);
-}
-
-.docs-landing-content h1 {
- max-width: 760px;
- margin-top: 0.85rem;
- color: var(--color-fg);
- font-size: 3.45rem;
- line-height: 1.03;
-}
-
-.docs-landing-content h2 {
- max-width: 700px;
- color: var(--color-fg);
- font-size: 2.3rem;
- line-height: 1.08;
-}
-
-.docs-landing-content p {
- color: rgba(250, 248, 244, 0.7);
- line-height: 1.65;
-}
-
-.docs-landing-intro > p:not(.docs-landing-kicker) {
- max-width: 760px;
- margin-top: 1rem;
- font-size: 1.05rem;
-}
-
-.docs-quick-select {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 0.8rem;
- margin-top: 2rem;
-}
-
-.docs-quick-select a {
- display: grid;
- gap: 0.35rem;
- min-height: 112px;
- align-content: center;
- padding: 1rem;
- border: 1px solid rgba(250, 248, 244, 0.12);
- border-radius: 8px;
- background: rgba(250, 248, 244, 0.045);
- color: var(--color-fg);
- text-decoration: none;
-}
-
-.docs-quick-select a:first-child {
- border-color: rgba(246, 201, 69, 0.26);
-}
-
-.docs-quick-select a:last-child {
- border-color: rgba(91, 59, 162, 0.34);
-}
-
-.docs-quick-select a:hover,
-.docs-quick-select a:focus-visible,
-.docs-section-action:hover,
-.docs-section-action:focus-visible,
-.docs-link-block a:hover,
-.docs-link-block a:focus-visible {
- border-color: rgba(246, 201, 69, 0.5);
- background: rgba(250, 248, 244, 0.075);
-}
-
-.docs-quick-select span {
- font-weight: 900;
-}
-
-.docs-quick-select small,
-.docs-link-block small {
- color: rgba(250, 248, 244, 0.58);
- line-height: 1.45;
-}
-
-.docs-tech-section {
- padding: 3rem 0;
- border-bottom: 1px solid rgba(250, 248, 244, 0.1);
-}
-
-.docs-tech-heading {
- display: flex;
- gap: 1.5rem;
- align-items: flex-start;
- justify-content: space-between;
-}
-
-.docs-tech-heading h2 {
- margin-top: 0.7rem;
-}
-
-.docs-section-action {
- display: inline-flex;
- min-width: 150px;
- min-height: 42px;
- align-items: center;
- justify-content: center;
- padding: 0.55rem 0.9rem;
- border: 1px solid rgba(246, 201, 69, 0.34);
- border-radius: 999px;
- background: rgba(246, 201, 69, 0.08);
- color: var(--color-fg);
- font-weight: 800;
- text-decoration: none;
- white-space: nowrap;
-}
-
-.docs-tech-summary {
- max-width: 780px;
- margin-top: 1rem;
-}
-
-.docs-link-grid {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 1.1rem;
- margin-top: 2rem;
-}
-
-.docs-link-block {
- min-width: 0;
- padding-top: 1rem;
- border-top: 1px solid rgba(250, 248, 244, 0.12);
-}
-
-.docs-link-block h3 {
- color: var(--color-fg);
- font-size: 1rem;
-}
-
-.docs-link-block a {
- display: grid;
- gap: 0.18rem;
- margin-top: 0.7rem;
- min-height: 72px;
- padding: 0.82rem 0.9rem;
- border: 1px solid rgba(250, 248, 244, 0.1);
- border-radius: 8px;
- background: rgba(250, 248, 244, 0.035);
- color: var(--color-fg);
- text-decoration: none;
-}
-
-.docs-link-block span {
- font-weight: 800;
-}
-
-.docs-link-block code {
- background: rgba(246, 201, 69, 0.12);
- color: var(--color-gold);
-}
-
-.docs-landing-toc {
- display: grid;
- gap: 0.18rem;
- padding-left: 1rem;
- border-left: 1px solid rgba(250, 248, 244, 0.1);
-}
-
-.docs-landing-toc p {
- margin-bottom: 0.35rem;
- color: var(--color-fg);
-}
-
-.docs-landing-toc a {
- padding: 0.25rem 0.5rem;
- font-size: 0.92rem;
-}
-
-.product-page .hero h1 {
- max-width: 760px;
- font-size: 4.4rem;
- line-height: 1;
- letter-spacing: 0;
-}
-
-.product-page .hero {
- padding: 5.25rem 0;
- border-bottom: 1px solid rgba(250, 248, 244, 0.08);
-}
-
-.product-page .section {
- border-top: 1px solid rgba(250, 248, 244, 0.06);
-}
-
-.learn-page .hero {
- padding: clamp(4rem, 7vw, 6.5rem) 0 3rem;
-}
-
-.learn-hero {
- position: relative;
- z-index: 1;
- max-width: 780px;
- margin: 0 auto;
- text-align: center;
-}
-
-.learn-hero h1 {
- max-width: none;
- margin-top: 1rem;
- font-size: clamp(3.1rem, 7vw, 5.7rem);
- line-height: 0.98;
- letter-spacing: 0;
-}
-
-.learn-hero .lede {
- max-width: 62ch;
- margin: 1.15rem auto 0;
-}
-
-.learn-hero-actions {
- justify-content: center;
-}
-
-.learn-hero-art {
- position: relative;
- display: grid;
- place-items: center;
- min-height: clamp(18rem, 31vw, 28rem);
- margin-top: clamp(2rem, 5vw, 4rem);
- overflow: hidden;
- border-bottom: 1px solid rgba(250, 248, 244, 0.08);
- background:
- linear-gradient(rgba(250, 248, 244, 0.035) 1px, transparent 1px),
- linear-gradient(90deg, rgba(250, 248, 244, 0.035) 1px, transparent 1px),
- radial-gradient(60% 80% at 50% 110%, rgba(62, 155, 101, 0.28), transparent 58%),
- radial-gradient(80% 90% at 50% 115%, rgba(91, 59, 162, 0.18), transparent 64%);
- background-size: 56px 56px, 56px 56px, auto, auto;
-}
-
-.learn-course-panel {
- position: relative;
- width: min(100%, 560px);
- padding: 1.4rem;
- border: 1px solid rgba(250, 248, 244, 0.12);
- border-radius: 8px;
- background: rgba(12, 11, 14, 0.86);
- box-shadow: 0 28px 80px rgba(0, 0, 0, 0.36);
-}
-
-.learn-course-mark {
- display: grid;
- place-items: center;
- width: 72px;
- height: 72px;
- margin: -3rem auto 1.1rem;
- border: 1px solid rgba(250, 248, 244, 0.16);
- border-radius: 8px;
- background:
- linear-gradient(135deg, rgba(250, 248, 244, 0.96), rgba(250, 248, 244, 0.78)),
- linear-gradient(135deg, rgba(246, 201, 69, 0.3), rgba(91, 59, 162, 0.22));
-}
-
-.learn-course-mark img {
- width: 42px;
- height: 42px;
-}
-
-.learn-course-panel h2 {
- text-align: center;
-}
-
-.learn-course-panel p {
- max-width: 44ch;
- margin: 0.55rem auto 0;
- text-align: center;
-}
-
-.learn-current-row {
- display: grid;
- grid-template-columns: minmax(0, 1fr) auto;
- gap: 1rem;
- align-items: center;
- margin: 1.4rem auto 0;
- padding: 0.82rem 0.95rem;
- max-width: 380px;
- border: 1px solid rgba(250, 248, 244, 0.1);
- border-radius: 999px;
- background: rgba(250, 248, 244, 0.06);
- text-align: left;
-}
-
-.learn-current-row strong {
- display: block;
- color: var(--color-fg);
- line-height: 1.2;
-}
-
-.learn-current-row span {
- display: block;
- margin-top: 0.18rem;
- color: rgba(247, 243, 234, 0.56);
- font-size: 0.85rem;
- line-height: 1.35;
-}
-
-.learn-current-dot {
- width: 28px;
- height: 28px;
- border: 1px solid rgba(246, 201, 69, 0.34);
- border-radius: 999px;
- background: rgba(246, 201, 69, 0.12);
-}
-
-.learn-section-heading {
- display: flex;
- align-items: baseline;
- justify-content: center;
- gap: 1rem;
- flex-wrap: wrap;
- text-align: center;
-}
-
-.learn-section-heading p {
- font-size: 1rem;
-}
-
-.learn-chapter-grid {
- display: grid;
- grid-template-columns: repeat(3, minmax(0, 1fr));
- gap: 0.8rem;
-}
-
-.learn-chapter {
- display: grid;
- grid-template-columns: auto minmax(0, 1fr);
- gap: 0.78rem;
- min-height: 112px;
- padding: 1rem;
- border: 1px solid rgba(250, 248, 244, 0.12);
- border-radius: 8px;
- background: rgba(250, 248, 244, 0.045);
- color: inherit;
- text-decoration: none;
- transition: transform 140ms ease, background 140ms ease, border-color 140ms ease;
-}
-
-.learn-chapter:hover,
-.learn-chapter:focus-visible {
- border-color: rgba(246, 201, 69, 0.36);
- background: rgba(250, 248, 244, 0.07);
- transform: translateY(-1px);
-}
-
-.learn-chapter-number {
- display: inline-grid;
- place-items: center;
- width: 1.7rem;
- height: 1.7rem;
- margin-top: 0;
- border-radius: 999px;
- background: rgba(246, 201, 69, 0.16);
- color: var(--color-gold);
- font-family: var(--font-mono);
- font-size: 0.78rem;
- font-weight: 800;
- line-height: 1;
- text-align: center;
-}
-
-.learn-chapter:nth-child(3n + 2) .learn-chapter-number {
- background: rgba(62, 155, 101, 0.16);
- color: #8fd4aa;
-}
-
-.learn-chapter:nth-child(3n) .learn-chapter-number {
- background: rgba(244, 122, 40, 0.16);
- color: #ffb17f;
-}
-
-.learn-chapter strong {
- display: block;
- color: var(--color-fg);
- line-height: 1.25;
-}
-
-.learn-chapter > span:not(.learn-chapter-number) {
- display: block;
- min-width: 0;
-}
-
-.learn-chapter > span:not(.learn-chapter-number) > span {
- display: block;
- margin-top: 0.38rem;
- color: rgba(247, 243, 234, 0.62);
- font-size: 0.92rem;
- line-height: 1.45;
-}
-
-.learn-info-grid {
- display: grid;
- grid-template-columns: repeat(2, minmax(0, 1fr));
- gap: 1rem;
-}
-
-.learn-info {
- padding: 1.15rem;
- border: 1px solid rgba(250, 248, 244, 0.12);
- border-radius: 8px;
- background: rgba(250, 248, 244, 0.04);
-}
-
-.learn-info h3 {
- font-size: 1.2rem;
-}
-
-.learn-info p {
- margin-top: 0.45rem;
-}
-
-.learn-lesson-page .section {
- padding-top: 2.2rem;
-}
-
-.learn-lesson-page {
- --learn-lesson-bar-top: 126px;
-}
-
-.learn-lesson-shell {
- max-width: 920px;
- margin: 0 auto;
-}
-
-.learn-lesson-bar {
- position: sticky;
- top: var(--learn-lesson-bar-top);
- z-index: 80;
- display: flex;
- gap: 0.75rem;
- align-items: center;
- margin-bottom: 2rem;
- padding: 0.55rem 0.72rem;
- border: 1px solid rgba(250, 248, 244, 0.12);
- border-radius: 999px;
- background: rgba(10, 9, 12, 0.88);
- backdrop-filter: blur(16px);
-}
-
-.learn-lesson-menu {
- width: 36px;
- height: 36px;
- border: 1px solid rgba(250, 248, 244, 0.1);
- border-radius: 999px;
- background: rgba(250, 248, 244, 0.045);
- position: relative;
-}
-
-.learn-lesson-menu::before,
-.learn-lesson-menu::after {
- content: "";
- position: absolute;
- left: 10px;
- width: 14px;
- height: 1px;
- background: rgba(247, 243, 234, 0.72);
-}
-
-.learn-lesson-menu::before {
- top: 13px;
- box-shadow: 0 5px 0 rgba(247, 243, 234, 0.72);
-}
-
-.learn-lesson-menu::after {
- top: 23px;
-}
-
-.learn-lesson-title {
- display: flex;
- align-items: center;
- gap: 0.7rem;
- min-width: 0;
- flex: 0 1 auto;
-}
-
-.learn-lesson-title img {
- width: 30px;
- height: 30px;
- border-radius: 8px;
- border: 1px solid rgba(250, 248, 244, 0.12);
- background: rgba(250, 248, 244, 0.08);
-}
-
-.learn-lesson-title strong,
-.learn-lesson-title span {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.learn-lesson-title strong {
- color: var(--color-fg);
- font-size: 0.9rem;
- line-height: 1.15;
-}
-
-.learn-lesson-title span {
- color: rgba(247, 243, 234, 0.55);
- font-size: 0.78rem;
- line-height: 1.25;
-}
-
-.learn-lesson-top {
- margin-left: auto;
- padding-left: 0.9rem;
- border-left: 1px solid rgba(250, 248, 244, 0.1);
- color: rgba(247, 243, 234, 0.68);
- font-size: 0.82rem;
- font-weight: 650;
- text-decoration: none;
-}
-
-.learn-lesson-nav {
- display: flex;
- align-items: center;
- gap: 0.4rem;
- margin-left: auto;
- padding-left: 0.85rem;
- border-left: 1px solid rgba(250, 248, 244, 0.1);
-}
-
-.learn-lesson-nav a,
-.learn-lesson-nav span {
- display: inline-flex;
- align-items: center;
- min-height: 2rem;
- padding: 0 0.68rem;
- border-radius: 999px;
- color: rgba(247, 243, 234, 0.68);
- font-size: 0.78rem;
- font-weight: 700;
- line-height: 1;
- text-decoration: none;
- white-space: nowrap;
-}
-
-.learn-lesson-nav a {
- border: 1px solid rgba(250, 248, 244, 0.1);
- background: rgba(250, 248, 244, 0.045);
-}
-
-.learn-lesson-nav a:hover,
-.learn-lesson-nav a:focus-visible {
- border-color: rgba(246, 201, 69, 0.28);
- color: var(--color-fg);
- background: rgba(250, 248, 244, 0.08);
-}
-
-.learn-lesson-nav span {
- color: rgba(247, 243, 234, 0.5);
-}
-
-.learn-lesson-heading {
- display: grid;
- grid-template-columns: auto minmax(0, 1fr);
- gap: 1.2rem;
- align-items: center;
- padding-bottom: 2rem;
- border-bottom: 1px solid rgba(250, 248, 244, 0.1);
-}
-
-.learn-lesson-number {
- display: grid;
- place-items: center;
- width: 68px;
- height: 68px;
- border-radius: 999px;
- background: rgba(246, 201, 69, 0.14);
- color: var(--color-gold);
- font-family: var(--font-mono);
- font-size: 2rem;
- font-weight: 800;
-}
-
-.learn-lesson-heading small {
- color: rgba(247, 243, 234, 0.56);
- font-weight: 700;
-}
-
-.learn-lesson-heading h1 {
- margin-top: 0.2rem;
- font-size: clamp(2.5rem, 5.5vw, 4rem);
- line-height: 1;
-}
-
-.learn-prose {
- max-width: none;
-}
-
-.learn-prose > * + * {
- margin-top: 1.2rem;
-}
-
-.learn-prose h2 {
- margin-top: 3.2rem;
- padding-top: 0.2rem;
- font-size: 1.7rem;
-}
-
-.learn-prose ul {
- margin: 1rem 0;
- padding-left: 1.25rem;
-}
-
-.learn-prose li {
- color: rgba(247, 243, 234, 0.7);
-}
-
-.learn-code {
- margin: 1rem 0 1.4rem;
- overflow: hidden;
- border: 1px solid rgba(250, 248, 244, 0.13);
- border-radius: 8px;
- background: rgba(6, 5, 7, 0.92);
-}
-
-.learn-code-header {
- display: flex;
- align-items: center;
- justify-content: space-between;
- gap: 1rem;
- min-height: 46px;
- padding: 0.55rem 0.68rem 0.55rem 0.9rem;
- border-bottom: 1px solid rgba(250, 248, 244, 0.1);
- background: rgba(250, 248, 244, 0.025);
-}
-
-.learn-code-title {
- display: inline-flex;
- align-items: center;
- gap: 0.55rem;
- min-width: 0;
- color: rgba(247, 243, 234, 0.68);
- font-size: 0.82rem;
- font-weight: 650;
-}
-
-.learn-code-title::before {
- content: "";
- flex: 0 0 auto;
- width: 16px;
- height: 16px;
- border: 1px solid rgba(250, 248, 244, 0.48);
- border-radius: 3px;
-}
-
-.learn-code[data-code-kind="terminal"] .learn-code-title::before {
- border: 0;
- border-radius: 0;
- background:
- linear-gradient(45deg, transparent 44%, rgba(250, 248, 244, 0.72) 46%, rgba(250, 248, 244, 0.72) 58%, transparent 60%) 0 2px / 8px 10px no-repeat,
- linear-gradient(rgba(250, 248, 244, 0.72), rgba(250, 248, 244, 0.72)) 10px 12px / 8px 1.5px no-repeat;
-}
-
-.learn-copy {
- position: relative;
- flex: 0 0 auto;
- width: 36px;
- height: 36px;
- border: 1px solid rgba(250, 248, 244, 0.28);
- border-radius: 6px;
- background: rgba(250, 248, 244, 0.08);
- color: rgba(250, 248, 244, 0.92);
- cursor: pointer;
- -webkit-appearance: none;
- appearance: none;
-}
-
-.learn-copy::before,
-.learn-copy::after {
- content: "";
- position: absolute;
- width: 11px;
- height: 13px;
- border: 2px solid currentColor;
- border-radius: 2px;
-}
-
-.learn-copy::before {
- left: 10px;
- top: 8px;
- opacity: 0.72;
-}
-
-.learn-copy::after {
- left: 14px;
- top: 12px;
- background: rgba(6, 5, 7, 0.92);
-}
-
-.learn-copy:hover,
-.learn-copy:focus-visible {
- border-color: rgba(246, 201, 69, 0.62);
- background: rgba(250, 248, 244, 0.14);
- color: #fffdf9;
-}
-
-.learn-copy[data-copy-state="copied"] {
- border-color: rgba(62, 155, 101, 0.58);
- color: #8fd4aa;
-}
-
-.learn-copy[data-copy-state="failed"] {
- border-color: rgba(244, 122, 40, 0.58);
- color: #ffb17f;
-}
-
-.learn-code pre {
- padding: 1rem 1.1rem;
- border: 0;
- border-radius: 0;
- background: transparent;
- box-shadow: none;
-}
-
-.learn-code pre code {
- display: block;
- min-width: max-content;
- font-size: 0.9rem;
- line-height: 1.6;
-}
-
-.learn-callout {
- padding: 1rem 1.1rem;
- border: 1px solid rgba(246, 201, 69, 0.24);
- border-radius: 8px;
- background: rgba(246, 201, 69, 0.07);
-}
-
-.learn-complete {
- margin-top: 3rem;
- padding: 2rem;
- border: 1px solid rgba(250, 248, 244, 0.12);
- border-radius: 8px;
- background: rgba(250, 248, 244, 0.04);
- text-align: center;
-}
-
-.learn-complete h2 {
- margin-top: 0;
-}
-
-.learn-complete .button {
- margin-top: 1.25rem;
-}
-
-.docs-page .section {
- padding: 2.2rem 0 4.5rem;
-}
-
-.docs-page .docs-layout {
- gap: 2.75rem;
-}
-
-.docs-page .docs-layout[data-has-toc="true"] {
- grid-template-columns: 300px minmax(0, 900px) 260px;
-}
-
-.docs-page .docs-sidebar,
-.docs-page .docs-toc {
- border-color: rgba(250, 248, 244, 0.12);
- background: rgba(250, 248, 244, 0.035);
- box-shadow: none;
-}
-
-.docs-page .docs-sidebar {
- border-radius: 0;
- border-width: 0 1px 0 0;
- padding-right: 1.2rem;
-}
-
-.docs-page .docs-toc {
- border-radius: 0;
- border-width: 0 0 0 1px;
- padding-left: 1.2rem;
-}
-
-.docs-page .docs-sidebar-header {
- border-bottom-color: rgba(250, 248, 244, 0.1);
-}
-
-.docs-page .docs-sidebar-title,
-.docs-page .docs-toc-title,
-.docs-page .docs-search-result-title,
-.docs-page .docs-prevnext-title,
-.docs-page .docs-content h1,
-.docs-page .docs-content h2,
-.docs-page .docs-content h3,
-.docs-page .docs-content h4 {
- color: var(--color-fg);
-}
-
-.docs-page .docs-search {
- border-color: rgba(250, 248, 244, 0.14);
- background: rgba(250, 248, 244, 0.055);
- color: var(--color-fg);
-}
-
-.docs-page .docs-search::placeholder {
- color: rgba(247, 243, 234, 0.44);
-}
-
-.docs-page .docs-nav-section,
-.docs-page .docs-search-result-meta,
-.docs-page .docs-breadcrumb,
-.docs-page .docs-prevnext-label,
-.docs-page .spec-toc-title {
- color: rgba(247, 243, 234, 0.48);
-}
-
-.docs-page .docs-nav a,
-.docs-page .docs-toc-list a,
-.docs-page .spec-toc a {
- color: rgba(247, 243, 234, 0.62);
-}
-
-.docs-page .docs-nav a:hover,
-.docs-page .docs-nav a:focus-visible,
-.docs-page .docs-nav a[data-active="true"],
-.docs-page .docs-toc-list a:hover,
-.docs-page .docs-toc-list a:focus-visible,
-.docs-page .spec-toc a:hover,
-.docs-page .spec-toc a:focus-visible,
-.docs-page .spec-toc a[data-active="true"] {
- color: var(--color-fg);
- background: rgba(250, 248, 244, 0.07);
-}
-
-.docs-page .docs-content .prose,
-.docs-page .spec-prose {
- max-width: 92ch;
-}
-
-.docs-page .docs-content .prose > h1:first-child,
-.docs-page .spec-prose > h1:first-child {
- font-size: 3.05rem;
- line-height: 1.05;
- letter-spacing: 0;
-}
-
-.docs-page .docs-content p,
-.docs-page .docs-content li,
-.docs-page .docs-content dd,
-.docs-page .spec-prose p,
-.docs-page .spec-prose li,
-.docs-page .spec-prose dd {
- color: rgba(247, 243, 234, 0.68);
-}
-
-.docs-layout .prose ul,
-.docs-layout .prose ol,
-.spec-prose ul,
-.spec-prose ol {
- display: grid;
- gap: 0.55rem;
- margin: 1.1rem 0;
- padding: 0;
- list-style: none;
-}
-
-.docs-layout .prose li,
-.spec-prose li {
- position: relative;
- margin: 0;
- padding: 0.72rem 0.86rem 0.72rem 1rem;
- border: 1px solid rgba(31, 31, 31, 0.1);
- border-left: 2px solid rgba(246, 201, 69, 0.44);
- border-radius: 8px;
- background: rgba(255, 255, 255, 0.6);
-}
-
-.docs-layout .prose li + li,
-.spec-prose li + li {
- margin-top: 0;
-}
-
-.docs-layout .prose ol,
-.spec-prose ol {
- counter-reset: docs-ordered-list;
-}
-
-.docs-layout .prose ol > li,
-.spec-prose ol > li {
- counter-increment: docs-ordered-list;
- padding-left: 2.75rem;
-}
-
-.docs-layout .prose ol > li::before,
-.spec-prose ol > li::before {
- content: counter(docs-ordered-list);
- position: absolute;
- left: 0.78rem;
- top: 0.72rem;
- display: inline-grid;
- place-items: center;
- min-width: 1.32rem;
- height: 1.32rem;
- padding: 0 0.18rem;
- border: 1px solid rgba(246, 201, 69, 0.38);
- border-radius: 999px;
- background: rgba(246, 201, 69, 0.12);
- color: var(--color-gold);
- font-family: var(--font-mono);
- font-size: 0.7rem;
- font-weight: 800;
- line-height: 1;
-}
-
-.docs-layout .prose li > p:first-child,
-.spec-prose li > p:first-child {
- margin-top: 0;
-}
-
-.docs-layout .prose li > p:last-child,
-.spec-prose li > p:last-child {
- margin-bottom: 0;
-}
-
-.docs-layout .prose li > ul,
-.docs-layout .prose li > ol,
-.spec-prose li > ul,
-.spec-prose li > ol {
- gap: 0.42rem;
- margin: 0.64rem 0 0;
-}
-
-.docs-layout .prose li > ul > li,
-.docs-layout .prose li > ol > li,
-.spec-prose li > ul > li,
-.spec-prose li > ol > li {
- padding-top: 0.56rem;
- padding-bottom: 0.56rem;
- background: rgba(31, 31, 31, 0.035);
-}
-
-.site-dark .docs-layout .prose li,
-.site-dark .spec-prose li,
-.docs-page .docs-layout .prose li,
-.docs-page .spec-prose li {
- border-color: rgba(250, 248, 244, 0.1);
- border-left-color: rgba(246, 201, 69, 0.46);
- background: rgba(250, 248, 244, 0.045);
-}
-
-.site-dark .docs-layout .prose li > ul > li,
-.site-dark .docs-layout .prose li > ol > li,
-.site-dark .spec-prose li > ul > li,
-.site-dark .spec-prose li > ol > li,
-.docs-page .docs-layout .prose li > ul > li,
-.docs-page .docs-layout .prose li > ol > li,
-.docs-page .spec-prose li > ul > li,
-.docs-page .spec-prose li > ol > li {
- background: rgba(250, 248, 244, 0.035);
-}
-
-.docs-page .docs-inline-ref {
- color: var(--color-fg);
- text-decoration-color: rgba(246, 201, 69, 0.35);
-}
-
-.docs-page .docs-inline-code,
-.docs-page .prose code {
- background: rgba(250, 248, 244, 0.08);
- color: rgba(247, 243, 234, 0.92);
-}
-
-.docs-page .prose pre {
- padding: 0;
-}
-
-.docs-page .prose pre code,
-.docs-page .prose pre code.hljs {
- display: block;
- padding: 1rem;
- background: transparent;
-}
-
-.docs-page .prose h1 code,
-.docs-page .prose h2 code,
-.docs-page .prose h3 code,
-.docs-page .prose h4 code,
-.docs-page .docs-nav code,
-.docs-page .docs-breadcrumb code,
-.docs-page .docs-search-result-title code,
-.docs-page .docs-prevnext-title code {
- background: transparent;
- color: var(--color-gold);
-}
-
-.docs-page .prose table {
- border-color: rgba(250, 248, 244, 0.12);
- background: rgba(250, 248, 244, 0.035);
-}
-
-.docs-page .prose th,
-.docs-page .prose td {
- border-color: rgba(250, 248, 244, 0.1);
-}
-
-.docs-page .prose th {
- background: rgba(246, 201, 69, 0.08);
-}
-
-.docs-page .prose tbody tr:nth-child(even) td {
- background: rgba(250, 248, 244, 0.025);
-}
-
-.docs-page .prose blockquote {
- border-left-color: rgba(246, 201, 69, 0.42);
-}
-
-.docs-page .prose details {
- border-color: rgba(250, 248, 244, 0.12);
- background: rgba(250, 248, 244, 0.045);
-}
-
-.docs-page .prose summary:hover,
-.docs-page .prose summary:focus-visible {
- background: rgba(250, 248, 244, 0.07);
-}
-
-.docs-page .docs-prevnext {
- border-top-color: rgba(250, 248, 244, 0.1);
-}
-
-.docs-page .docs-prevnext-link {
- border-color: rgba(250, 248, 244, 0.12);
- background: rgba(250, 248, 244, 0.045);
-}
-
-.docs-page .docs-prevnext-link:hover,
-.docs-page .docs-prevnext-link:focus-visible {
- background: rgba(250, 248, 244, 0.08);
-}
-
-@media (max-width: 980px) {
- .learn-chapter-grid {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
-}
-
-@media (max-width: 1180px) {
- .tech-hero-copy h1,
- .docs-hub-copy h1,
- .coming-soon-copy h1,
- .product-page .hero h1 {
- font-size: 3.7rem;
- }
-
- .tech-system-map {
- opacity: 0.26;
- width: 38vw;
- }
-
- .technology-layout,
- .technology-layout-reverse,
- .docs-hub-tech,
- .blog-placeholder {
- grid-template-columns: 1fr;
- }
-
- .technology-layout-reverse .technology-copy {
- order: 0;
- }
-
- .docs-link-groups,
- .blog-lanes {
- grid-template-columns: repeat(2, minmax(0, 1fr));
- }
-
- .docs-page .docs-layout,
- .docs-page .docs-layout[data-has-toc="true"] {
- grid-template-columns: 300px minmax(0, 1fr);
- }
-
- .docs-page .docs-toc {
- display: none;
- }
-
- .docs-landing-shell {
- grid-template-columns: 250px minmax(0, 1fr);
- gap: 2rem;
- }
-
- .docs-landing-toc {
- display: none;
- }
-}
-
-@media (max-width: 820px) {
- .tech-hero,
- .docs-hub-hero,
- .coming-soon {
- min-height: auto;
- }
-
- .tech-hero-copy,
- .docs-hub-copy,
- .coming-soon-copy {
- padding: 4.25rem 0 3rem;
- }
-
- .tech-hero-copy h1,
- .docs-hub-copy h1,
- .coming-soon-copy h1,
- .product-page .hero h1,
- .docs-page .docs-content .prose > h1:first-child,
- .docs-page .spec-prose > h1:first-child {
- font-size: 2.75rem;
- line-height: 1.04;
- }
-
- .tech-system-map {
- display: none;
- }
-
- .technology-section,
- .docs-hub-section {
- padding: 3.5rem 0;
- }
-
- .technology-copy h2,
- .docs-hub-tech-copy h2 {
- font-size: 2.25rem;
- }
-
- .technology-feature-list,
- .docs-link-groups,
- .blog-lanes,
- .docs-flow {
- grid-template-columns: 1fr;
- }
-
- .docs-flow span {
- width: 1px;
- height: 28px;
- justify-self: center;
- }
-
- .docs-page .docs-sidebar,
- .docs-page .docs-toc {
- border-width: 1px;
- border-radius: 8px;
- }
-
- .docs-page .docs-layout,
- .docs-page .docs-layout[data-has-toc="true"] {
- grid-template-columns: minmax(0, 1fr);
- }
-
- .docs-landing-shell {
- display: block;
- padding: 2rem var(--gutter) 3.5rem;
- }
-
- .docs-landing-sidebar {
- display: none;
- }
-
- .docs-landing-content h1 {
- font-size: 2.65rem;
- }
-
- .docs-landing-content h2 {
- font-size: 2rem;
- }
-
- .docs-quick-select,
- .docs-link-grid {
- grid-template-columns: minmax(0, 1fr);
- }
-
- .docs-tech-heading {
- display: block;
- }
-
- .docs-section-action {
- margin-top: 1rem;
- }
-
- .learn-hero-art {
- margin-inline: calc(var(--gutter) * -1);
- }
-
- .learn-section-heading {
- display: block;
- }
-
- .learn-section-heading p {
- margin-top: 0.45rem;
- }
-
- .learn-chapter-grid,
- .learn-info-grid {
- grid-template-columns: minmax(0, 1fr);
- }
-
- .learn-lesson-bar {
- position: static;
- flex-wrap: wrap;
- border-radius: 8px;
- }
-
- .learn-lesson-title {
- flex: 1 1 0;
- }
-
- .learn-lesson-nav {
- flex: 1 0 100%;
- margin-left: 0;
- padding: 0.55rem 0 0;
- border-top: 1px solid rgba(250, 248, 244, 0.1);
- border-left: 0;
- }
-
- .learn-lesson-top {
- display: none;
- }
-
- .learn-lesson-heading {
- grid-template-columns: minmax(0, 1fr);
- }
-}
-
-@media (max-width: 520px) {
- .tech-hero-copy h1,
- .docs-hub-copy h1,
- .coming-soon-copy h1,
- .product-page .hero h1 {
- font-size: 2.35rem;
- }
-
- .technology-feature-list li,
- .technology-feature-list span,
- .blog-placeholder,
- .docs-link-group {
- padding: 0.9rem;
- }
-
- .runtime-command {
- grid-template-columns: minmax(0, 1fr);
- }
-
- .runtime-code-tabs pre {
- max-height: 300px;
- }
-
- .docs-sidebar-nav {
- grid-template-columns: minmax(0, 1fr);
- }
-
- .docs-landing-content h1 {
- font-size: 2.25rem;
- }
-
- .docs-landing-content h2 {
- font-size: 1.8rem;
- }
-
- .learn-page .hero {
- padding-top: 3rem;
- }
-
- .learn-course-panel {
- width: calc(100% - 2rem);
- padding: 1.1rem;
- }
-
- .learn-current-row {
- grid-template-columns: minmax(0, 1fr);
- border-radius: 8px;
- }
-
- .learn-current-dot {
- display: none;
- }
-
- .learn-chapter {
- grid-template-columns: minmax(0, 1fr);
- }
-
- .learn-lesson-number {
- width: 56px;
- height: 56px;
- font-size: 1.55rem;
- }
-
- .learn-code pre code {
- font-size: 0.82rem;
- }
-}
-
-/* Oro editorial homepage */
-.editorial-layout {
- --editorial-rail: 220px;
- --editorial-column-gap: 4rem;
- --editorial-page-max: 1440px;
- min-height: 100vh;
- display: grid;
- grid-template-columns: var(--editorial-rail) minmax(0, 1fr);
- grid-template-rows: minmax(0, 1fr) auto;
- column-gap: var(--editorial-column-gap);
- max-width: var(--editorial-page-max);
- margin: 0 auto;
- padding: 0 2rem;
- background: linear-gradient(180deg, #fffdf9 0%, var(--color-bg) 52%, #f5eee1 100%);
- color: var(--color-fg);
-}
-
-.editorial-layout::before {
- content: none;
-}
-
-.editorial-layout .site-top {
- grid-column: 1;
- grid-row: 1;
- position: sticky;
- top: 0;
- align-self: start;
- height: fit-content;
- padding-top: 6rem;
- background: transparent;
- border-bottom: 0;
- box-shadow: none;
- backdrop-filter: none;
-}
-
-.editorial-layout .site-top .container,
-.editorial-layout .site-top .container-wide {
- max-width: none;
- padding: 0;
-}
-
-.editorial-layout .site-header {
- flex-direction: column;
- align-items: flex-start;
- justify-content: flex-start;
- gap: 4rem;
- min-height: 0;
-}
-
-.editorial-layout .brand {
- color: var(--color-fg);
-}
-
-.editorial-layout .brand-mark {
- width: 30px;
- height: 30px;
- border-color: rgba(31, 31, 31, 0.14);
- background: rgba(255, 255, 255, 0.72);
-}
-
-.editorial-layout .brand-name {
- font-size: 1.48rem;
-}
-
-.editorial-layout .nav {
- flex-direction: column;
- align-items: flex-start;
- gap: 0.4rem;
- margin-left: 0;
- color: rgba(31, 31, 31, 0.55);
- font-size: 0.88rem;
- line-height: 1.2;
-}
-
-.editorial-layout .nav a {
- padding: 0.22rem 0;
-}
-
-.editorial-layout .nav a::after {
- display: none;
-}
-
-.editorial-layout .nav a:hover,
-.editorial-layout .nav a:focus-visible {
- color: var(--color-fg);
-}
-
-.editorial-main {
- grid-column: 2;
- grid-row: 1;
- min-width: 0;
- padding: 6rem 0 0;
-}
-
-.editorial-layout .section-kicker {
- margin: 0;
- color: var(--color-purple);
- font-size: 0.78rem;
- font-weight: 760;
- letter-spacing: 0.08em;
-}
-
-.editorial-hero {
- max-width: 760px;
- padding-bottom: 5rem;
-}
-
-.editorial-hero h1 {
- max-width: 760px;
- margin: 0;
- font-family: var(--font-display);
- font-size: 5.6rem;
- font-weight: 820;
- line-height: 0.95;
- letter-spacing: 0;
-}
-
-.editorial-hero p:not(.section-kicker) {
- max-width: 650px;
- margin: 1.35rem 0 0;
- color: var(--color-muted);
- font-size: 1.1rem;
- line-height: 1.65;
-}
-
-.editorial-actions {
- display: flex;
- flex-wrap: wrap;
- gap: 0.75rem;
- margin-top: 1.8rem;
-}
-
-.editorial-layout .button {
- min-height: 44px;
- border-radius: var(--radius);
- font-size: 0.94rem;
-}
-
-.editorial-layout .button-primary {
- border-color: rgba(31, 31, 31, 0.9);
- background: var(--color-fg);
- color: var(--color-bg);
- box-shadow: 0 14px 32px rgba(31, 31, 31, 0.14);
+.docs-page .prose h1 code,
+.docs-page .prose h2 code,
+.docs-page .prose h3 code,
+.docs-page .prose h4 code,
+.docs-page .docs-nav code,
+.docs-page .docs-breadcrumb code,
+.docs-page .docs-search-result-title code,
+.docs-page .docs-prevnext-title code {
+ background: transparent;
+ color: var(--color-gold);
}
-.editorial-layout .button-primary:hover,
-.editorial-layout .button-primary:focus-visible {
- border-color: rgba(31, 31, 31, 0.9);
- background: #000;
- color: var(--color-bg);
+.docs-page .prose table {
+ border-color: rgba(250, 248, 244, 0.12);
+ background: rgba(250, 248, 244, 0.035);
}
-.editorial-layout .button-quiet {
- border-color: rgba(31, 31, 31, 0.14);
- background: rgba(255, 255, 255, 0.54);
- color: var(--color-fg);
+.docs-page .prose th,
+.docs-page .prose td {
+ border-color: rgba(250, 248, 244, 0.1);
}
-.editorial-layout .button-quiet:hover,
-.editorial-layout .button-quiet:focus-visible {
- border-color: rgba(31, 31, 31, 0.24);
- background: rgba(255, 255, 255, 0.84);
+.docs-page .prose th {
+ background: rgba(246, 201, 69, 0.08);
}
-.editorial-products {
- padding: 0 0 4.5rem;
+.docs-page .prose tbody tr:nth-child(even) td {
+ background: rgba(250, 248, 244, 0.025);
}
-.editorial-section-heading {
- margin-bottom: 1.4rem;
+.docs-page .prose blockquote {
+ border-left-color: rgba(246, 201, 69, 0.42);
}
-.editorial-section-heading h2 {
- margin: 0;
- font-family: var(--font-display);
- font-size: 2.65rem;
- font-weight: 740;
- line-height: 1.08;
- letter-spacing: 0;
+.docs-page .prose details {
+ border-color: rgba(250, 248, 244, 0.12);
+ background: rgba(250, 248, 244, 0.045);
}
-.editorial-product {
- display: grid;
- grid-template-columns: 64px minmax(0, 760px);
- gap: 2rem;
- align-items: start;
- padding: 1.8rem 0;
- border-top: 1px solid rgba(31, 31, 31, 0.12);
+.docs-page .prose summary:hover,
+.docs-page .prose summary:focus-visible {
+ background: rgba(250, 248, 244, 0.07);
}
-.editorial-product:last-child {
- border-bottom: 1px solid rgba(31, 31, 31, 0.12);
+.docs-page .docs-prevnext {
+ border-top-color: rgba(250, 248, 244, 0.1);
}
-.editorial-product-index {
- color: rgba(91, 59, 162, 0.84);
- font-family: var(--font-mono);
- font-size: 0.84rem;
- font-weight: 720;
- line-height: 1.9;
+.docs-page .docs-prevnext-link {
+ border-color: rgba(250, 248, 244, 0.12);
+ background: rgba(250, 248, 244, 0.045);
}
-.editorial-product h3 {
- margin: 0;
- font-family: var(--font-display);
- font-size: 1.55rem;
- font-weight: 740;
- line-height: 1.15;
+.docs-page .docs-prevnext-link:hover,
+.docs-page .docs-prevnext-link:focus-visible {
+ background: rgba(250, 248, 244, 0.08);
}
-.editorial-product p {
- max-width: 560px;
- margin: 0.55rem 0 0;
- color: var(--color-muted);
- line-height: 1.62;
-}
+@media (max-width: 1180px) {
+ .tech-hero-copy h1,
+ .docs-hub-copy h1,
+ .coming-soon-copy h1,
+ .product-page .hero h1 {
+ font-size: 3.7rem;
+ }
-.editorial-product-links {
- display: flex;
- justify-content: flex-end;
- gap: 0.5rem;
- flex-wrap: wrap;
-}
+ .tech-system-map {
+ opacity: 0.26;
+ width: 38vw;
+ }
-.editorial-product-links a {
- display: inline-flex;
- align-items: center;
- min-height: 34px;
- padding: 0.42rem 0.68rem;
- border: 1px solid rgba(31, 31, 31, 0.12);
- border-radius: 999px;
- background: rgba(255, 255, 255, 0.46);
- color: rgba(31, 31, 31, 0.72);
- text-decoration: none;
- font-size: 0.82rem;
- font-weight: 680;
- line-height: 1.1;
-}
+ .technology-layout,
+ .technology-layout-reverse,
+ .docs-hub-tech,
+ .blog-placeholder {
+ grid-template-columns: 1fr;
+ }
-.editorial-product-links a:hover,
-.editorial-product-links a:focus-visible {
- border-color: rgba(91, 59, 162, 0.34);
- background: rgba(255, 255, 255, 0.78);
- color: var(--color-fg);
-}
+ .technology-layout-reverse .technology-copy {
+ order: 0;
+ }
-.editorial-footer {
- grid-column: 1 / -1;
- display: grid;
- grid-template-columns: var(--editorial-rail) minmax(0, 1fr) auto;
- gap: var(--editorial-column-gap);
- align-items: center;
- padding: 2.5rem 0 4rem;
- border-top: 1px solid rgba(31, 31, 31, 0.12);
- color: rgba(31, 31, 31, 0.58);
- font-size: 0.88rem;
- line-height: 1.35;
-}
+ .docs-link-groups,
+ .blog-lanes {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
-.editorial-footer-contact {
- display: grid;
- gap: 0.4rem;
-}
+ .docs-page .docs-layout,
+ .docs-page .docs-layout[data-has-toc="true"] {
+ grid-template-columns: 300px minmax(0, 1fr);
+ }
-.editorial-footer-contact span {
- color: var(--color-fg);
- font-weight: 720;
-}
+ .docs-page .docs-toc {
+ display: none;
+ }
-.editorial-footer a {
- color: rgba(31, 31, 31, 0.62);
- text-decoration: none;
-}
+ .docs-landing-shell {
+ grid-template-columns: 250px minmax(0, 1fr);
+ gap: 2rem;
+ }
-.editorial-footer a:hover,
-.editorial-footer a:focus-visible {
- color: var(--color-fg);
+ .docs-landing-toc {
+ display: none;
+ }
}
-.editorial-footer-links {
- display: flex;
- flex-wrap: wrap;
- gap: 0.95rem;
- align-items: center;
-}
+@media (max-width: 820px) {
+ .tech-hero,
+ .docs-hub-hero,
+ .coming-soon {
+ min-height: auto;
+ }
-.editorial-footer-links:last-child {
- justify-content: flex-end;
-}
+ .tech-hero-copy,
+ .docs-hub-copy,
+ .coming-soon-copy {
+ padding: 4.25rem 0 3rem;
+ }
-@media (max-width: 1080px) {
- .editorial-layout {
- --editorial-rail: 180px;
- --editorial-column-gap: 2.5rem;
+ .tech-hero-copy h1,
+ .docs-hub-copy h1,
+ .coming-soon-copy h1,
+ .product-page .hero h1,
+ .docs-page .docs-content .prose > h1:first-child,
+ .docs-page .spec-prose > h1:first-child {
+ font-size: 2.75rem;
+ line-height: 1.04;
}
- .editorial-hero h1 {
- font-size: 4.6rem;
+ .tech-system-map {
+ display: none;
}
- .editorial-product {
- grid-template-columns: 48px minmax(0, 1fr);
+ .technology-section,
+ .docs-hub-section {
+ padding: 3.5rem 0;
}
-}
-@media (max-width: 940px) {
- .editorial-layout {
- display: block;
- padding: 0;
+ .technology-copy h2,
+ .docs-hub-tech-copy h2 {
+ font-size: 2.25rem;
}
- .editorial-layout .site-top {
- position: sticky;
- top: 0;
- padding-top: 0;
- background: rgba(250, 248, 244, 0.92);
- border-bottom: 1px solid rgba(31, 31, 31, 0.08);
- backdrop-filter: blur(16px);
+ .technology-feature-list,
+ .docs-link-groups,
+ .blog-lanes,
+ .docs-flow {
+ grid-template-columns: 1fr;
}
- .editorial-layout .site-top .container,
- .editorial-layout .site-top .container-wide {
- max-width: none;
- padding: 0 var(--gutter);
+ .docs-flow span {
+ width: 1px;
+ height: 28px;
+ justify-self: center;
}
- .editorial-layout .site-header {
- min-height: 68px;
- flex-direction: row;
- align-items: center;
- gap: 1rem;
+ .docs-page .docs-sidebar,
+ .docs-page .docs-toc {
+ border-width: 1px;
+ border-radius: 8px;
}
- .editorial-layout .nav {
- flex: 1 1 100%;
- flex-direction: row;
- flex-wrap: nowrap;
- gap: 0.72rem;
- width: 100%;
- padding: 0 0 0.75rem;
- overflow-x: auto;
- font-size: 0.82rem;
- white-space: nowrap;
- scrollbar-width: none;
+ .docs-page .docs-layout,
+ .docs-page .docs-layout[data-has-toc="true"] {
+ grid-template-columns: minmax(0, 1fr);
}
- .editorial-layout .nav::-webkit-scrollbar {
- display: none;
+ .docs-landing-shell {
+ display: block;
+ padding: 2rem var(--gutter) 3.5rem;
}
- .editorial-main {
- padding: 3.75rem var(--gutter) 0;
+ .docs-landing-sidebar {
+ display: none;
}
- .editorial-hero {
- padding-bottom: 3.5rem;
+ .docs-landing-content h1 {
+ font-size: 2.65rem;
}
- .editorial-hero h1 {
- font-size: 3.8rem;
+ .docs-landing-content h2 {
+ font-size: 2rem;
}
- .editorial-section-heading,
- .editorial-product {
+ .docs-quick-select,
+ .docs-link-grid {
grid-template-columns: minmax(0, 1fr);
- gap: 0.8rem;
}
- .editorial-footer {
- display: grid;
- grid-template-columns: minmax(0, 1fr);
- gap: 1.35rem;
- padding: 2rem var(--gutter) 3rem;
+ .docs-tech-heading {
+ display: block;
}
- .editorial-footer-links:last-child {
- justify-content: flex-start;
+ .docs-section-action {
+ margin-top: 1rem;
}
}
-@media (max-width: 560px) {
- .editorial-main {
- padding-top: 3rem;
+@media (max-width: 520px) {
+ .tech-hero-copy h1,
+ .docs-hub-copy h1,
+ .coming-soon-copy h1,
+ .product-page .hero h1 {
+ font-size: 2.35rem;
}
- .editorial-hero h1 {
- font-size: 3rem;
- line-height: 1.02;
+ .technology-feature-list li,
+ .technology-feature-list span,
+ .blog-placeholder,
+ .docs-link-group {
+ padding: 0.9rem;
}
- .editorial-hero p:not(.section-kicker) {
- font-size: 1rem;
+ .runtime-command {
+ grid-template-columns: minmax(0, 1fr);
}
- .editorial-actions .button {
- width: 100%;
+ .runtime-code-tabs pre {
+ max-height: 300px;
+ }
+
+ .docs-sidebar-nav {
+ grid-template-columns: minmax(0, 1fr);
}
- .editorial-section-heading h2 {
- font-size: 2.1rem;
+ .docs-landing-content h1 {
+ font-size: 2.25rem;
}
- .editorial-product {
- padding: 1.45rem 0;
+ .docs-landing-content h2 {
+ font-size: 1.8rem;
}
}
@@ -5155,7 +3342,6 @@ body:not(.editorial-layout) .hero-grid {
}
body:not(.editorial-layout) .hero-copy,
-body:not(.editorial-layout) .learn-hero,
body:not(.editorial-layout) .coming-soon-copy {
max-width: 840px;
padding: 0;
@@ -5189,7 +3375,6 @@ body:not(.editorial-layout) .docs-landing-content h1 {
}
body:not(.editorial-layout) .hero-copy p,
-body:not(.editorial-layout) .learn-hero p,
body:not(.editorial-layout) .docs-landing-intro > p:not(.docs-landing-kicker),
body:not(.editorial-layout) .docs-tech-summary {
max-width: 680px;
@@ -5255,13 +3440,7 @@ body:not(.editorial-layout) .docs-sidebar,
body:not(.editorial-layout) .docs-toc,
body:not(.editorial-layout) .docs-prevnext-link,
body:not(.editorial-layout) .docs-quick-select a,
-body:not(.editorial-layout) .docs-link-block,
-body:not(.editorial-layout) .learn-course-panel,
-body:not(.editorial-layout) .learn-info,
-body:not(.editorial-layout) .learn-current-row,
-body:not(.editorial-layout) .learn-lesson-bar,
-body:not(.editorial-layout) .learn-code,
-body:not(.editorial-layout) .learn-callout {
+body:not(.editorial-layout) .docs-link-block {
border-color: rgba(31, 31, 31, 0.12);
background: rgba(255, 255, 255, 0.5);
box-shadow: none;
@@ -5441,10 +3620,6 @@ body:not(.editorial-layout).docs-page .spec-prose > h1:first-child {
color: var(--color-fg);
}
-body:not(.editorial-layout) .learn-hero-art {
- display: none;
-}
-
body:not(.editorial-layout) .button,
body:not(.editorial-layout) .site-subnav-parent,
body:not(.editorial-layout) .site-subnav-links a,
@@ -5458,13 +3633,7 @@ body:not(.editorial-layout) .docs-search-result,
body:not(.editorial-layout) .docs-prevnext-link,
body:not(.editorial-layout) .docs-quick-select a,
body:not(.editorial-layout) .docs-link-block a,
-body:not(.editorial-layout) .docs-section-action,
-body:not(.editorial-layout) .learn-course-panel,
-body:not(.editorial-layout) .learn-info,
-body:not(.editorial-layout) .learn-current-row,
-body:not(.editorial-layout) .learn-lesson-bar,
-body:not(.editorial-layout) .learn-code,
-body:not(.editorial-layout) .learn-callout {
+body:not(.editorial-layout) .docs-section-action {
border-radius: var(--radius);
}
@@ -5486,14 +3655,12 @@ body:not(.editorial-layout) pre {
body:not(.editorial-layout) pre code,
body:not(.editorial-layout) pre code.hljs,
body:not(.editorial-layout).docs-page .prose pre code,
-body:not(.editorial-layout).docs-page .prose pre code.hljs,
-body:not(.editorial-layout) .learn-code pre code {
+body:not(.editorial-layout).docs-page .prose pre code.hljs {
background: transparent;
color: inherit;
}
-body:not(.editorial-layout).docs-page .prose pre,
-body:not(.editorial-layout) .learn-code pre {
+body:not(.editorial-layout).docs-page .prose pre {
border-radius: var(--radius);
background: linear-gradient(180deg, #171513 0%, #241d31 100%);
color: rgba(250, 248, 244, 0.94);
@@ -5573,16 +3740,6 @@ body:not(.editorial-layout) .docs-tech-heading h2,
body:not(.editorial-layout) .docs-quick-select span,
body:not(.editorial-layout) .docs-link-block h3,
body:not(.editorial-layout) .docs-link-block span,
-body:not(.editorial-layout) .learn-section-heading h2,
-body:not(.editorial-layout) .learn-course-panel h2,
-body:not(.editorial-layout) .learn-current-row strong,
-body:not(.editorial-layout) .learn-chapter strong,
-body:not(.editorial-layout) .learn-info h3,
-body:not(.editorial-layout) .learn-lesson-heading h1,
-body:not(.editorial-layout) .learn-lesson-title strong,
-body:not(.editorial-layout) .learn-prose h2,
-body:not(.editorial-layout) .learn-prose h3,
-body:not(.editorial-layout) .learn-complete h2,
body:not(.editorial-layout).docs-page .docs-sidebar-title,
body:not(.editorial-layout).docs-page .docs-toc-title,
body:not(.editorial-layout).docs-page .docs-search-result-title,
@@ -5609,19 +3766,6 @@ body:not(.editorial-layout) .docs-landing-content p,
body:not(.editorial-layout) .docs-tech-summary,
body:not(.editorial-layout) .docs-quick-select small,
body:not(.editorial-layout) .docs-link-block small,
-body:not(.editorial-layout) .learn-hero .lede,
-body:not(.editorial-layout) .learn-section-heading p,
-body:not(.editorial-layout) .learn-course-panel p,
-body:not(.editorial-layout) .learn-current-row span,
-body:not(.editorial-layout) .learn-chapter > span:not(.learn-chapter-number) > span,
-body:not(.editorial-layout) .learn-info p,
-body:not(.editorial-layout) .learn-lesson-title span,
-body:not(.editorial-layout) .learn-lesson-heading small,
-body:not(.editorial-layout) .learn-prose p,
-body:not(.editorial-layout) .learn-prose li,
-body:not(.editorial-layout) .learn-callout,
-body:not(.editorial-layout) .learn-callout p,
-body:not(.editorial-layout) .learn-complete p,
body:not(.editorial-layout).docs-page .docs-content p,
body:not(.editorial-layout).docs-page .docs-content li,
body:not(.editorial-layout).docs-page .docs-content dd,
@@ -5642,10 +3786,7 @@ body:not(.editorial-layout).docs-page .spec-toc-title {
body:not(.editorial-layout).docs-page .docs-nav a,
body:not(.editorial-layout).docs-page .docs-toc-list a,
-body:not(.editorial-layout).docs-page .spec-toc a,
-body:not(.editorial-layout) .learn-lesson-top,
-body:not(.editorial-layout) .learn-lesson-nav a,
-body:not(.editorial-layout) .learn-lesson-nav span {
+body:not(.editorial-layout).docs-page .spec-toc a {
color: rgba(31, 31, 31, 0.64);
}
@@ -5656,11 +3797,7 @@ body:not(.editorial-layout).docs-page .docs-toc-list a:hover,
body:not(.editorial-layout).docs-page .docs-toc-list a:focus-visible,
body:not(.editorial-layout).docs-page .spec-toc a:hover,
body:not(.editorial-layout).docs-page .spec-toc a:focus-visible,
-body:not(.editorial-layout).docs-page .spec-toc a[data-active="true"],
-body:not(.editorial-layout) .learn-lesson-top:hover,
-body:not(.editorial-layout) .learn-lesson-top:focus-visible,
-body:not(.editorial-layout) .learn-lesson-nav a:hover,
-body:not(.editorial-layout) .learn-lesson-nav a:focus-visible {
+body:not(.editorial-layout).docs-page .spec-toc a[data-active="true"] {
background: rgba(31, 31, 31, 0.05);
color: var(--color-fg);
}
@@ -5674,10 +3811,6 @@ body:not(.editorial-layout).product-page .section,
body:not(.editorial-layout) .docs-landing-intro,
body:not(.editorial-layout) .docs-tech-section,
body:not(.editorial-layout) .docs-link-block,
-body:not(.editorial-layout) .learn-hero-art,
-body:not(.editorial-layout) .learn-lesson-heading,
-body:not(.editorial-layout) .learn-lesson-top,
-body:not(.editorial-layout) .learn-lesson-nav,
body:not(.editorial-layout).docs-page .docs-sidebar-header,
body:not(.editorial-layout).docs-page .docs-prevnext {
border-color: rgba(31, 31, 31, 0.1);
@@ -5691,14 +3824,6 @@ body:not(.editorial-layout) .docs-link-group a,
body:not(.editorial-layout) .blog-lanes article,
body:not(.editorial-layout) .blog-placeholder,
body:not(.editorial-layout) .docs-flow div,
-body:not(.editorial-layout) .learn-course-panel,
-body:not(.editorial-layout) .learn-current-row,
-body:not(.editorial-layout) .learn-chapter,
-body:not(.editorial-layout) .learn-info,
-body:not(.editorial-layout) .learn-lesson-bar,
-body:not(.editorial-layout) .learn-lesson-menu,
-body:not(.editorial-layout) .learn-lesson-nav a,
-body:not(.editorial-layout) .learn-complete,
body:not(.editorial-layout).docs-page .docs-search,
body:not(.editorial-layout).docs-page .docs-search-result,
body:not(.editorial-layout).docs-page .docs-prevnext-link,
@@ -5707,32 +3832,6 @@ body:not(.editorial-layout).docs-page .prose details {
background: rgba(255, 255, 255, 0.5);
}
-body:not(.editorial-layout) .learn-lesson-menu::before,
-body:not(.editorial-layout) .learn-lesson-menu::after {
- background: rgba(31, 31, 31, 0.72);
-}
-
-body:not(.editorial-layout) .learn-lesson-menu::before {
- box-shadow: 0 5px 0 rgba(31, 31, 31, 0.72);
-}
-
-body:not(.editorial-layout) .learn-lesson-title img {
- border-color: rgba(31, 31, 31, 0.12);
- background: rgba(255, 255, 255, 0.56);
-}
-
-body:not(.editorial-layout) .learn-code {
- border-color: rgba(246, 201, 69, 0.22);
- background: linear-gradient(180deg, #171513 0%, #241d31 100%);
- color: rgba(250, 248, 244, 0.94);
-}
-
-body:not(.editorial-layout) .learn-code-header {
- border-bottom-color: rgba(250, 248, 244, 0.1);
- background: rgba(250, 248, 244, 0.035);
-}
-
-body:not(.editorial-layout) .learn-code-title,
body:not(.editorial-layout) .learn-copy {
color: rgba(250, 248, 244, 0.72);
}
@@ -5791,38 +3890,38 @@ body:not(.editorial-layout).docs-page .prose tbody tr:nth-child(even) td {
background: rgba(31, 31, 31, 0.035);
}
-body:not(.editorial-layout) .nav .menu-panel {
+body:not(.editorial-layout) .site-header .menu-panel {
border-color: rgba(31, 31, 31, 0.12);
background: rgba(255, 255, 255, 0.96);
color: var(--color-fg);
box-shadow: 0 18px 42px rgba(31, 31, 31, 0.12);
}
-body:not(.editorial-layout) .nav .menu-item {
+body:not(.editorial-layout) .site-header .menu-item {
position: relative;
padding: 0.54rem 0.62rem;
border-radius: var(--radius);
color: var(--color-fg);
}
-body:not(.editorial-layout) .nav .menu-item::after {
+body:not(.editorial-layout) .site-header .menu-item::after {
content: none;
display: none;
}
-body:not(.editorial-layout) .nav .menu-item:hover,
-body:not(.editorial-layout) .nav .menu-item:focus-visible {
+body:not(.editorial-layout) .site-header .menu-item:hover,
+body:not(.editorial-layout) .site-header .menu-item:focus-visible {
border-color: rgba(31, 31, 31, 0.12);
background: rgba(31, 31, 31, 0.06);
color: var(--color-fg);
}
-body:not(.editorial-layout) .nav .menu-item small,
-body:not(.editorial-layout) .nav .menu-hint {
+body:not(.editorial-layout) .site-header .menu-item small,
+body:not(.editorial-layout) .site-header .menu-hint {
color: rgba(31, 31, 31, 0.58);
}
-body:not(.editorial-layout) .nav .menu-sep {
+body:not(.editorial-layout) .site-header .menu-sep {
background: rgba(31, 31, 31, 0.1);
}
@@ -5847,3 +3946,14 @@ body:not(.editorial-layout) .nav .menu-sep {
.markdown-alert-warning, .markdown-alert-caution { border-color: var(--color-orange); }
.docs-tab-anchor { display: block; scroll-margin-top: var(--site-top-offset, 144px); }
+
+/* The Ask AI panel is a sibling of the scrolling nav, anchored by its client. */
+.ask-ai-panel {
+ font-size: 0.82rem;
+ font-weight: 650;
+ right: auto;
+ min-width: min(224px, calc(100vw - 16px));
+ max-width: calc(100vw - 16px);
+ max-height: calc(100dvh - 160px);
+ overflow-y: auto;
+}
diff --git a/src/globals/global.data.ts b/src/globals/global.data.ts
new file mode 100644
index 00000000..9c8c4057
--- /dev/null
+++ b/src/globals/global.data.ts
@@ -0,0 +1,71 @@
+import type { GlobalDataFunction } from '@domstack/static/types.js'
+import { collections, type Collection } from '#lib/collections.ts'
+import { collectRedirects, type RedirectPage } from '#lib/redirects.ts'
+import { editUrl, plainText, projectCollection, validateDocVars, type Doc, type DocsData } from '#lib/docs.ts'
+
+type IndexedPage = RedirectPage & { doc?: Doc }
+export type DocsIndex = Map
+
+const globalData: GlobalDataFunction, string, DocsIndex> = async ({
+ pages, previousState, changes, setState,
+}) => {
+ const reset = changes.kind === 'reset' || previousState === undefined
+ const index: DocsIndex = reset ? new Map() : new Map(previousState)
+ const inputs = changes.kind === 'delta' && !reset ? changes.upserted : pages
+ if (changes.kind === 'delta') {
+ for (const sourceId of changes.removed) index.delete(sourceId)
+ }
+
+ for (const page of inputs) {
+ const { url, outputRelname, pageFile } = page.pageInfo
+ const source = page.sourceId
+ // Retain only cloneable projections, never PageData or renderer instances.
+ const entry: IndexedPage = {
+ pageInfo: { url, outputRelname, pageFile: { relname: pageFile.relname } },
+ vars: { redirectFrom: page.vars.redirectFrom },
+ }
+ if (page.vars.docsCollection !== undefined) {
+ const v = validateDocVars(page.vars, source)
+ if (page.pageInfo.type !== 'md') throw new Error(`${source}: documentation must be Markdown`)
+ entry.doc = {
+ collection: v.docsCollection,
+ id: v.sourcePath.replace(/\.(md|txt)$/, ''),
+ title: v.title, description: v.description, section: v.section, order: v.order,
+ url, sourcePath: v.sourcePath,
+ markdown: await page.readMarkdownContent(),
+ searchText: plainText(await page.renderInnerPage()),
+ githubRepo: v.githubRepo, githubRef: v.githubRef,
+ editUrl: editUrl(source),
+ }
+ }
+ index.set(source, entry)
+ }
+
+ // Cheap views reference cached documents; existing data fingerprints decide
+ // whether their consumers rebuild, without a second invalidation system.
+ const indexedPages = [...index.values()]
+ const docs: Record = {
+ runtime: [], silk: [], silkWiki: [], virtnosis: [], sage: [], slg: [],
+ }
+ for (const { doc } of indexedPages) {
+ if (doc) docs[doc.collection].push(doc)
+ }
+ const data = {
+ redirects: collectRedirects(indexedPages),
+ routes: indexedPages.map(page => page.pageInfo.url).sort(),
+ navigation: {},
+ } as DocsData
+ for (const collection of Object.keys(collections) as Collection[]) {
+ const list = docs[collection]
+ list.sort((a, b) => a.order - b.order || a.id.localeCompare(b.id, 'en'))
+ data.navigation[collection] = projectCollection(list)
+ data[`${collection}Exports`] = list.map(({ collection, id, title, sourcePath, url, markdown }) => ({ collection, id, title, sourcePath, url, markdown }))
+ data[`${collection}Search`] = {
+ kind: collection === 'silkWiki' ? 'wiki' : 'docs', count: list.length,
+ items: list.map(d => ({ id: d.id, title: d.title, file: d.sourcePath, url: d.url, section: d.section, summary: d.description, text: d.searchText })),
+ }
+ }
+ setState(index)
+ return data
+}
+export default globalData
diff --git a/src/global.vars.ts b/src/globals/global.vars.ts
similarity index 100%
rename from src/global.vars.ts
rename to src/globals/global.vars.ts
diff --git a/src/layouts/docs.layout.client.ts b/src/layouts/docs.layout.client.ts
index 04294aab..b5b55085 100644
--- a/src/layouts/docs.layout.client.ts
+++ b/src/layouts/docs.layout.client.ts
@@ -1,8 +1,9 @@
-import { legacyTarget } from '../lib/legacy.ts'
-import { enhanceSidebar } from '../lib/sidebar-client.ts'
-import '../lib/learn-client.js'
-import { renderTabs } from '../lib/tabs.js'
-import { enhanceArticle } from '../lib/article-client.ts'
+import { initAskAiMenu } from '#lib/ask-ai-client.ts'
+import { legacyTarget } from '#lib/legacy.ts'
+import { enhanceSidebar } from '#lib/sidebar-client.ts'
+import { initLearn } from '#lib/learn-client.ts'
+import { renderTabs } from '#lib/tabs.ts'
+import { enhanceArticle } from '#lib/article-client.ts'
const app = document.querySelector('[data-docs-app]')
if (app) {
const routes = document.querySelector('[data-legacy-routes]')
@@ -20,10 +21,7 @@ if (app) {
}
const content = app.querySelector('[data-docs-content]')!
renderTabs(content)
- const oro = globalThis as typeof globalThis & {
- oroInitTabs?: (root: HTMLElement) => void
- }
- oro.oroInitTabs?.(content)
+ initLearn(content)
enhanceArticle(app)
enhanceSidebar(app)
const input = app.querySelector('[data-docs-search]')!
@@ -51,7 +49,13 @@ if (app) {
return r.json()
})
.then((data) => data.items)
- const docs = await index
+ const pending = index
+ // Evict failures even when the query was cleared while fetching. An older
+ // request must never evict a replacement cached by a later input event.
+ void pending.catch(() => {
+ if (index === pending) index = undefined
+ })
+ const docs = await pending
if (current !== version) return
const scored = docs
.map((d) => ({
@@ -88,7 +92,6 @@ if (app) {
results.textContent =
'Search is unavailable. Browse the navigation below.'
nav.hidden = false
- index = undefined
}
}
})
@@ -109,3 +112,5 @@ function revealHashTarget() {
}
revealHashTarget()
addEventListener('hashchange', revealHashTarget)
+
+initAskAiMenu()
diff --git a/src/layouts/docs.layout.ts b/src/layouts/docs.layout.ts
index 54d767b6..fdb939d9 100644
--- a/src/layouts/docs.layout.ts
+++ b/src/layouts/docs.layout.ts
@@ -1,68 +1,17 @@
import { html, raw, render } from 'fragtml'
-import { load } from 'cheerio'
-import type { LayoutFunction } from '@domstack/static/types.js'
+import { article } from '#lib/rendering.ts'
+import type { DataDeps, LayoutFunction } from '@domstack/static/types.js'
import {
collections,
sectionTitle,
- type Collection,
-} from '../lib/collections.ts'
-import { rawUrl, type Doc, type DocsData } from '../lib/docs.ts'
+} from '#lib/collections.ts'
+import { rawUrl, type DocLink, type NavigationData, type DocVars } from '#lib/docs.ts'
+export { pageOutputs } from '#lib/docs-page-outputs.ts'
export const parentLayout = 'root'
-export const vars = { dataDeps: ['docs'] }
-export function article(
- content: string,
- spec = false,
-): { body: string; toc: string } {
- const $ = load(content, {}, false)
- const headings: { id: string; title: string; level: string }[] = []
- $('h2,h3,h4,h5').each((_i, h) => {
- const id = $(h).attr('id') || ''
- const title = $(h).text()
- if (id) {
- headings.push({ id, title, level: h.tagName })
- $(h).append(
- render(
- html`#`,
- ),
- )
- }
- })
- return {
- body: $.html(),
- toc: render(
- spec
- ? html`Table of contents
-
- ${headings.map(
- (h) =>
- html`
${h.title}`,
- )}
-
`
- : html`On this page
-
- ${headings
- .filter((h) => ['h2', 'h3'].includes(h.level))
- .map(
- (h) =>
- html`-
- ${h.title}
-
`,
- )}
-
`,
- ),
- }
+export const vars = {
+ dataDeps: ['navigation'] satisfies DataDeps,
}
-function prevNext(doc: Doc | undefined, label: string): string {
+function prevNext(doc: DocLink | null, label: string): string {
return doc
? render(
html`,
- string,
- string,
- DocsData
-> = ({ vars: v, children, data }) => {
- const collection = v.docsCollection as Collection
- const c = collections[collection]
- const docs = data.docs[collection]
- const idx = docs.findIndex((d) => d.sourcePath === v.sourcePath)
- const doc = docs[idx]
- const sections = [...new Set(docs.map((d) => d.section))]
+const docsLayout: LayoutFunction = ({ vars: v, children, data }) => {
+ const navigation = data.navigation[v.docsCollection]
+ const c = collections[v.docsCollection]
+ const doc = navigation.bySource[v.sourcePath]
+ if (!doc) throw new Error(`Missing navigation document: ${v.docsCollection}/${v.sourcePath}`)
+ const sections = navigation.sections
const { body, toc } = article(children)
- const legacy =
- doc.id === 'start'
- ? JSON.stringify(Object.fromEntries(docs.map((d) => [d.id, d.url])))
- : ''
+ const legacy = doc.id === 'start' ? JSON.stringify(navigation.legacy) : ''
return render(
html`
@@ -116,11 +56,9 @@ const docsLayout: LayoutFunction<
- ${raw(prevNext(docs[idx - 1], 'Previous'))}
+ ${raw(prevNext(doc.previous, 'Previous'))}
- ${raw(prevNext(docs[idx + 1], 'Next'))}
+ ${raw(prevNext(doc.next, 'Next'))}
diff --git a/src/layouts/learn.layout.client.ts b/src/layouts/learn.layout.client.ts
index 31da9879..caa7ffa4 100644
--- a/src/layouts/learn.layout.client.ts
+++ b/src/layouts/learn.layout.client.ts
@@ -1 +1 @@
-import '../lib/learn-client.js'
+import '#lib/learn-client.ts'
diff --git a/src/layouts/learn.layout.css b/src/layouts/learn.layout.css
new file mode 100644
index 00000000..e60e1a7a
--- /dev/null
+++ b/src/layouts/learn.layout.css
@@ -0,0 +1,732 @@
+/* Learn layout rules, in their original cascade order. Shared tabs and copy controls remain global. */
+.learn-page .hero {
+ padding: clamp(4rem, 7vw, 6.5rem) 0 3rem;
+}
+
+.learn-hero {
+ position: relative;
+ z-index: 1;
+ max-width: 780px;
+ margin: 0 auto;
+ text-align: center;
+}
+
+.learn-hero h1 {
+ max-width: none;
+ margin-top: 1rem;
+ font-size: clamp(3.1rem, 7vw, 5.7rem);
+ line-height: 0.98;
+ letter-spacing: 0;
+}
+
+.learn-hero .lede {
+ max-width: 62ch;
+ margin: 1.15rem auto 0;
+}
+
+.learn-hero-actions {
+ justify-content: center;
+}
+
+.learn-hero-art {
+ position: relative;
+ display: grid;
+ place-items: center;
+ min-height: clamp(18rem, 31vw, 28rem);
+ margin-top: clamp(2rem, 5vw, 4rem);
+ overflow: hidden;
+ border-bottom: 1px solid rgba(250, 248, 244, 0.08);
+ background:
+ linear-gradient(rgba(250, 248, 244, 0.035) 1px, transparent 1px),
+ linear-gradient(90deg, rgba(250, 248, 244, 0.035) 1px, transparent 1px),
+ radial-gradient(60% 80% at 50% 110%, rgba(62, 155, 101, 0.28), transparent 58%),
+ radial-gradient(80% 90% at 50% 115%, rgba(91, 59, 162, 0.18), transparent 64%);
+ background-size: 56px 56px, 56px 56px, auto, auto;
+}
+
+.learn-course-panel {
+ position: relative;
+ width: min(100%, 560px);
+ padding: 1.4rem;
+ border: 1px solid rgba(250, 248, 244, 0.12);
+ border-radius: 8px;
+ background: rgba(12, 11, 14, 0.86);
+ box-shadow: 0 28px 80px rgba(0, 0, 0, 0.36);
+}
+
+.learn-course-mark {
+ display: grid;
+ place-items: center;
+ width: 72px;
+ height: 72px;
+ margin: -3rem auto 1.1rem;
+ border: 1px solid rgba(250, 248, 244, 0.16);
+ border-radius: 8px;
+ background:
+ linear-gradient(135deg, rgba(250, 248, 244, 0.96), rgba(250, 248, 244, 0.78)),
+ linear-gradient(135deg, rgba(246, 201, 69, 0.3), rgba(91, 59, 162, 0.22));
+}
+
+.learn-course-mark img {
+ width: 42px;
+ height: 42px;
+}
+
+.learn-course-panel h2 {
+ text-align: center;
+}
+
+.learn-course-panel p {
+ max-width: 44ch;
+ margin: 0.55rem auto 0;
+ text-align: center;
+}
+
+.learn-current-row {
+ display: grid;
+ grid-template-columns: minmax(0, 1fr) auto;
+ gap: 1rem;
+ align-items: center;
+ margin: 1.4rem auto 0;
+ padding: 0.82rem 0.95rem;
+ max-width: 380px;
+ border: 1px solid rgba(250, 248, 244, 0.1);
+ border-radius: 999px;
+ background: rgba(250, 248, 244, 0.06);
+ text-align: left;
+}
+
+.learn-current-row strong {
+ display: block;
+ color: var(--color-fg);
+ line-height: 1.2;
+}
+
+.learn-current-row span {
+ display: block;
+ margin-top: 0.18rem;
+ color: rgba(247, 243, 234, 0.56);
+ font-size: 0.85rem;
+ line-height: 1.35;
+}
+
+.learn-current-dot {
+ width: 28px;
+ height: 28px;
+ border: 1px solid rgba(246, 201, 69, 0.34);
+ border-radius: 999px;
+ background: rgba(246, 201, 69, 0.12);
+}
+
+.learn-section-heading {
+ display: flex;
+ align-items: baseline;
+ justify-content: center;
+ gap: 1rem;
+ flex-wrap: wrap;
+ text-align: center;
+}
+
+.learn-section-heading p {
+ font-size: 1rem;
+}
+
+.learn-chapter-grid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 0.8rem;
+}
+
+.learn-chapter {
+ display: grid;
+ grid-template-columns: auto minmax(0, 1fr);
+ gap: 0.78rem;
+ min-height: 112px;
+ padding: 1rem;
+ border: 1px solid rgba(250, 248, 244, 0.12);
+ border-radius: 8px;
+ background: rgba(250, 248, 244, 0.045);
+ color: inherit;
+ text-decoration: none;
+ transition: transform 140ms ease, background 140ms ease, border-color 140ms ease;
+}
+
+.learn-chapter:hover,
+.learn-chapter:focus-visible {
+ border-color: rgba(246, 201, 69, 0.36);
+ background: rgba(250, 248, 244, 0.07);
+ transform: translateY(-1px);
+}
+
+.learn-chapter-number {
+ display: inline-grid;
+ place-items: center;
+ width: 1.7rem;
+ height: 1.7rem;
+ margin-top: 0;
+ border-radius: 999px;
+ background: rgba(246, 201, 69, 0.16);
+ color: var(--color-gold);
+ font-family: var(--font-mono);
+ font-size: 0.78rem;
+ font-weight: 800;
+ line-height: 1;
+ text-align: center;
+}
+
+.learn-chapter:nth-child(3n + 2) .learn-chapter-number {
+ background: rgba(62, 155, 101, 0.16);
+ color: #8fd4aa;
+}
+
+.learn-chapter:nth-child(3n) .learn-chapter-number {
+ background: rgba(244, 122, 40, 0.16);
+ color: #ffb17f;
+}
+
+.learn-chapter strong {
+ display: block;
+ color: var(--color-fg);
+ line-height: 1.25;
+}
+
+.learn-chapter > span:not(.learn-chapter-number) {
+ display: block;
+ min-width: 0;
+}
+
+.learn-chapter > span:not(.learn-chapter-number) > span {
+ display: block;
+ margin-top: 0.38rem;
+ color: rgba(247, 243, 234, 0.62);
+ font-size: 0.92rem;
+ line-height: 1.45;
+}
+
+.learn-info-grid {
+ display: grid;
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ gap: 1rem;
+}
+
+.learn-info {
+ padding: 1.15rem;
+ border: 1px solid rgba(250, 248, 244, 0.12);
+ border-radius: 8px;
+ background: rgba(250, 248, 244, 0.04);
+}
+
+.learn-info h3 {
+ font-size: 1.2rem;
+}
+
+.learn-info p {
+ margin-top: 0.45rem;
+}
+
+.learn-lesson-page .section {
+ padding-top: 2.2rem;
+}
+
+.learn-lesson-page {
+ --learn-lesson-bar-top: 126px;
+}
+
+.learn-lesson-shell {
+ max-width: 920px;
+ margin: 0 auto;
+}
+
+.learn-lesson-bar {
+ position: sticky;
+ top: var(--learn-lesson-bar-top);
+ z-index: 80;
+ display: flex;
+ gap: 0.75rem;
+ align-items: center;
+ margin-bottom: 2rem;
+ padding: 0.55rem 0.72rem;
+ border: 1px solid rgba(250, 248, 244, 0.12);
+ border-radius: 999px;
+ background: rgba(10, 9, 12, 0.88);
+ backdrop-filter: blur(16px);
+}
+
+.learn-lesson-menu {
+ width: 36px;
+ height: 36px;
+ border: 1px solid rgba(250, 248, 244, 0.1);
+ border-radius: 999px;
+ background: rgba(250, 248, 244, 0.045);
+ position: relative;
+}
+
+.learn-lesson-menu::before,
+.learn-lesson-menu::after {
+ content: "";
+ position: absolute;
+ left: 10px;
+ width: 14px;
+ height: 1px;
+ background: rgba(247, 243, 234, 0.72);
+}
+
+.learn-lesson-menu::before {
+ top: 13px;
+ box-shadow: 0 5px 0 rgba(247, 243, 234, 0.72);
+}
+
+.learn-lesson-menu::after {
+ top: 23px;
+}
+
+.learn-lesson-title {
+ display: flex;
+ align-items: center;
+ gap: 0.7rem;
+ min-width: 0;
+ flex: 0 1 auto;
+}
+
+.learn-lesson-title img {
+ width: 30px;
+ height: 30px;
+ border-radius: 8px;
+ border: 1px solid rgba(250, 248, 244, 0.12);
+ background: rgba(250, 248, 244, 0.08);
+}
+
+.learn-lesson-title strong,
+.learn-lesson-title span {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.learn-lesson-title strong {
+ color: var(--color-fg);
+ font-size: 0.9rem;
+ line-height: 1.15;
+}
+
+.learn-lesson-title span {
+ color: rgba(247, 243, 234, 0.55);
+ font-size: 0.78rem;
+ line-height: 1.25;
+}
+
+.learn-lesson-top {
+ margin-left: auto;
+ padding-left: 0.9rem;
+ border-left: 1px solid rgba(250, 248, 244, 0.1);
+ color: rgba(247, 243, 234, 0.68);
+ font-size: 0.82rem;
+ font-weight: 650;
+ text-decoration: none;
+}
+
+.learn-lesson-nav {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ margin-left: auto;
+ padding-left: 0.85rem;
+ border-left: 1px solid rgba(250, 248, 244, 0.1);
+}
+
+.learn-lesson-nav a,
+.learn-lesson-nav span {
+ display: inline-flex;
+ align-items: center;
+ min-height: 2rem;
+ padding: 0 0.68rem;
+ border-radius: 999px;
+ color: rgba(247, 243, 234, 0.68);
+ font-size: 0.78rem;
+ font-weight: 700;
+ line-height: 1;
+ text-decoration: none;
+ white-space: nowrap;
+}
+
+.learn-lesson-nav a {
+ border: 1px solid rgba(250, 248, 244, 0.1);
+ background: rgba(250, 248, 244, 0.045);
+}
+
+.learn-lesson-nav a:hover,
+.learn-lesson-nav a:focus-visible {
+ border-color: rgba(246, 201, 69, 0.28);
+ color: var(--color-fg);
+ background: rgba(250, 248, 244, 0.08);
+}
+
+.learn-lesson-nav span {
+ color: rgba(247, 243, 234, 0.5);
+}
+
+.learn-lesson-heading {
+ display: grid;
+ grid-template-columns: auto minmax(0, 1fr);
+ gap: 1.2rem;
+ align-items: center;
+ padding-bottom: 2rem;
+ border-bottom: 1px solid rgba(250, 248, 244, 0.1);
+}
+
+.learn-lesson-number {
+ display: grid;
+ place-items: center;
+ width: 68px;
+ height: 68px;
+ border-radius: 999px;
+ background: rgba(246, 201, 69, 0.14);
+ color: var(--color-gold);
+ font-family: var(--font-mono);
+ font-size: 2rem;
+ font-weight: 800;
+}
+
+.learn-lesson-heading small {
+ color: rgba(247, 243, 234, 0.56);
+ font-weight: 700;
+}
+
+.learn-lesson-heading h1 {
+ margin-top: 0.2rem;
+ font-size: clamp(2.5rem, 5.5vw, 4rem);
+ line-height: 1;
+}
+
+.learn-prose {
+ max-width: none;
+}
+
+.learn-prose > * + * {
+ margin-top: 1.2rem;
+}
+
+.learn-prose h2 {
+ margin-top: 3.2rem;
+ padding-top: 0.2rem;
+ font-size: 1.7rem;
+}
+
+.learn-prose ul {
+ margin: 1rem 0;
+ padding-left: 1.25rem;
+}
+
+.learn-prose li {
+ color: rgba(247, 243, 234, 0.7);
+}
+
+.learn-code {
+ margin: 1rem 0 1.4rem;
+ overflow: hidden;
+ border: 1px solid rgba(250, 248, 244, 0.13);
+ border-radius: 8px;
+ background: rgba(6, 5, 7, 0.92);
+}
+
+.learn-code-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 1rem;
+ min-height: 46px;
+ padding: 0.55rem 0.68rem 0.55rem 0.9rem;
+ border-bottom: 1px solid rgba(250, 248, 244, 0.1);
+ background: rgba(250, 248, 244, 0.025);
+}
+
+.learn-code-title {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.55rem;
+ min-width: 0;
+ color: rgba(247, 243, 234, 0.68);
+ font-size: 0.82rem;
+ font-weight: 650;
+}
+
+.learn-code-title::before {
+ content: "";
+ flex: 0 0 auto;
+ width: 16px;
+ height: 16px;
+ border: 1px solid rgba(250, 248, 244, 0.48);
+ border-radius: 3px;
+}
+
+.learn-code[data-code-kind="terminal"] .learn-code-title::before {
+ border: 0;
+ border-radius: 0;
+ background:
+ linear-gradient(45deg, transparent 44%, rgba(250, 248, 244, 0.72) 46%, rgba(250, 248, 244, 0.72) 58%, transparent 60%) 0 2px / 8px 10px no-repeat,
+ linear-gradient(rgba(250, 248, 244, 0.72), rgba(250, 248, 244, 0.72)) 10px 12px / 8px 1.5px no-repeat;
+}
+
+.learn-code pre {
+ padding: 1rem 1.1rem;
+ border: 0;
+ border-radius: 0;
+ background: transparent;
+ box-shadow: none;
+}
+
+.learn-code pre code {
+ display: block;
+ min-width: max-content;
+ font-size: 0.9rem;
+ line-height: 1.6;
+}
+
+.learn-callout {
+ padding: 1rem 1.1rem;
+ border: 1px solid rgba(246, 201, 69, 0.24);
+ border-radius: 8px;
+ background: rgba(246, 201, 69, 0.07);
+}
+
+.learn-complete {
+ margin-top: 3rem;
+ padding: 2rem;
+ border: 1px solid rgba(250, 248, 244, 0.12);
+ border-radius: 8px;
+ background: rgba(250, 248, 244, 0.04);
+ text-align: center;
+}
+
+.learn-complete h2 {
+ margin-top: 0;
+}
+
+.learn-complete .button {
+ margin-top: 1.25rem;
+}
+
+@media (max-width: 980px) {
+ .learn-chapter-grid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }}
+
+@media (max-width: 820px) {
+
+ .learn-hero-art {
+ margin-inline: calc(var(--gutter) * -1);
+ }
+
+ .learn-section-heading {
+ display: block;
+ }
+
+ .learn-section-heading p {
+ margin-top: 0.45rem;
+ }
+
+ .learn-chapter-grid,
+ .learn-info-grid {
+ grid-template-columns: minmax(0, 1fr);
+ }
+
+ .learn-lesson-bar {
+ position: static;
+ flex-wrap: wrap;
+ border-radius: 8px;
+ }
+
+ .learn-lesson-title {
+ flex: 1 1 0;
+ }
+
+ .learn-lesson-nav {
+ flex: 1 0 100%;
+ margin-left: 0;
+ padding: 0.55rem 0 0;
+ border-top: 1px solid rgba(250, 248, 244, 0.1);
+ border-left: 0;
+ }
+
+ .learn-lesson-top {
+ display: none;
+ }
+
+ .learn-lesson-heading {
+ grid-template-columns: minmax(0, 1fr);
+ }}
+
+@media (max-width: 520px) {
+
+ .learn-page .hero {
+ padding-top: 3rem;
+ }
+
+ .learn-course-panel {
+ width: calc(100% - 2rem);
+ padding: 1.1rem;
+ }
+
+ .learn-current-row {
+ grid-template-columns: minmax(0, 1fr);
+ border-radius: 8px;
+ }
+
+ .learn-current-dot {
+ display: none;
+ }
+
+ .learn-chapter {
+ grid-template-columns: minmax(0, 1fr);
+ }
+
+ .learn-lesson-number {
+ width: 56px;
+ height: 56px;
+ font-size: 1.55rem;
+ }
+
+ .learn-code pre code {
+ font-size: 0.82rem;
+ }}
+
+body:not(.editorial-layout) .learn-hero {
+ max-width: 840px;
+ padding: 0;
+}
+
+body:not(.editorial-layout) .learn-hero p {
+ max-width: 680px;
+ margin-top: 1.25rem;
+ color: var(--color-muted);
+ font-size: 1.08rem;
+ line-height: 1.65;
+}
+
+body:not(.editorial-layout) .learn-course-panel,
+body:not(.editorial-layout) .learn-info,
+body:not(.editorial-layout) .learn-current-row,
+body:not(.editorial-layout) .learn-lesson-bar,
+body:not(.editorial-layout) .learn-code,
+body:not(.editorial-layout) .learn-callout {
+ border-color: rgba(31, 31, 31, 0.12);
+ background: rgba(255, 255, 255, 0.5);
+ box-shadow: none;
+}
+
+body:not(.editorial-layout) .learn-hero-art {
+ display: none;
+}
+
+body:not(.editorial-layout) .learn-course-panel,
+body:not(.editorial-layout) .learn-info,
+body:not(.editorial-layout) .learn-current-row,
+body:not(.editorial-layout) .learn-lesson-bar,
+body:not(.editorial-layout) .learn-code,
+body:not(.editorial-layout) .learn-callout {
+ border-radius: var(--radius);
+}
+
+body:not(.editorial-layout) .learn-code pre code {
+ background: transparent;
+ color: inherit;
+}
+
+body:not(.editorial-layout) .learn-code pre {
+ border-radius: var(--radius);
+ background: linear-gradient(180deg, #171513 0%, #241d31 100%);
+ color: rgba(250, 248, 244, 0.94);
+}
+
+/* Light-theme contrast cleanup for components inherited from the dark presentation. */
+body:not(.editorial-layout) .learn-section-heading h2,
+body:not(.editorial-layout) .learn-course-panel h2,
+body:not(.editorial-layout) .learn-current-row strong,
+body:not(.editorial-layout) .learn-chapter strong,
+body:not(.editorial-layout) .learn-info h3,
+body:not(.editorial-layout) .learn-lesson-heading h1,
+body:not(.editorial-layout) .learn-lesson-title strong,
+body:not(.editorial-layout) .learn-prose h2,
+body:not(.editorial-layout) .learn-prose h3,
+body:not(.editorial-layout) .learn-complete h2 {
+ color: var(--color-fg);
+}
+
+body:not(.editorial-layout) .learn-hero .lede,
+body:not(.editorial-layout) .learn-section-heading p,
+body:not(.editorial-layout) .learn-course-panel p,
+body:not(.editorial-layout) .learn-current-row span,
+body:not(.editorial-layout) .learn-chapter > span:not(.learn-chapter-number) > span,
+body:not(.editorial-layout) .learn-info p,
+body:not(.editorial-layout) .learn-lesson-title span,
+body:not(.editorial-layout) .learn-lesson-heading small,
+body:not(.editorial-layout) .learn-prose p,
+body:not(.editorial-layout) .learn-prose li,
+body:not(.editorial-layout) .learn-callout,
+body:not(.editorial-layout) .learn-callout p,
+body:not(.editorial-layout) .learn-complete p {
+ color: var(--color-muted);
+}
+
+body:not(.editorial-layout) .learn-lesson-top,
+body:not(.editorial-layout) .learn-lesson-nav a,
+body:not(.editorial-layout) .learn-lesson-nav span {
+ color: rgba(31, 31, 31, 0.64);
+}
+
+body:not(.editorial-layout) .learn-lesson-top:hover,
+body:not(.editorial-layout) .learn-lesson-top:focus-visible,
+body:not(.editorial-layout) .learn-lesson-nav a:hover,
+body:not(.editorial-layout) .learn-lesson-nav a:focus-visible {
+ background: rgba(31, 31, 31, 0.05);
+ color: var(--color-fg);
+}
+
+body:not(.editorial-layout) .learn-hero-art,
+body:not(.editorial-layout) .learn-lesson-heading,
+body:not(.editorial-layout) .learn-lesson-top,
+body:not(.editorial-layout) .learn-lesson-nav {
+ border-color: rgba(31, 31, 31, 0.1);
+}
+
+body:not(.editorial-layout) .learn-course-panel,
+body:not(.editorial-layout) .learn-current-row,
+body:not(.editorial-layout) .learn-chapter,
+body:not(.editorial-layout) .learn-info,
+body:not(.editorial-layout) .learn-lesson-bar,
+body:not(.editorial-layout) .learn-lesson-menu,
+body:not(.editorial-layout) .learn-lesson-nav a,
+body:not(.editorial-layout) .learn-complete {
+ border-color: rgba(31, 31, 31, 0.12);
+ background: rgba(255, 255, 255, 0.5);
+}
+
+body:not(.editorial-layout) .learn-lesson-menu::before,
+body:not(.editorial-layout) .learn-lesson-menu::after {
+ background: rgba(31, 31, 31, 0.72);
+}
+
+body:not(.editorial-layout) .learn-lesson-menu::before {
+ box-shadow: 0 5px 0 rgba(31, 31, 31, 0.72);
+}
+
+body:not(.editorial-layout) .learn-lesson-title img {
+ border-color: rgba(31, 31, 31, 0.12);
+ background: rgba(255, 255, 255, 0.56);
+}
+
+body:not(.editorial-layout) .learn-code {
+ border-color: rgba(246, 201, 69, 0.22);
+ background: linear-gradient(180deg, #171513 0%, #241d31 100%);
+ color: rgba(250, 248, 244, 0.94);
+}
+
+body:not(.editorial-layout) .learn-code-header {
+ border-bottom-color: rgba(250, 248, 244, 0.1);
+ background: rgba(250, 248, 244, 0.035);
+}
+
+body:not(.editorial-layout) .learn-code-title {
+ color: rgba(250, 248, 244, 0.72);
+}
diff --git a/src/layouts/learn.layout.ts b/src/layouts/learn.layout.ts
index 8ef98e48..b9120383 100644
--- a/src/layouts/learn.layout.ts
+++ b/src/layouts/learn.layout.ts
@@ -1,6 +1,6 @@
import { html, render } from 'fragtml'
import type { LayoutFunction } from '@domstack/static/types.js'
-import { names } from '../lib/navigation.ts'
+import { names } from '#lib/navigation.ts'
export const parentLayout = 'root'
interface LearnVars {
product: string
diff --git a/src/layouts/product.layout.client.ts b/src/layouts/product.layout.client.ts
deleted file mode 100644
index 31da9879..00000000
--- a/src/layouts/product.layout.client.ts
+++ /dev/null
@@ -1 +0,0 @@
-import '../lib/learn-client.js'
diff --git a/src/layouts/registry.ts b/src/layouts/registry.ts
new file mode 100644
index 00000000..8e575b2c
--- /dev/null
+++ b/src/layouts/registry.ts
@@ -0,0 +1,20 @@
+import type * as root from './root.layout.ts'
+import type * as marketing from './marketing.layout.ts'
+import type * as product from './product.layout.ts'
+import type * as learn from './learn.layout.ts'
+import type * as redirect from './redirect.layout.ts'
+import type * as docs from './docs.layout.ts'
+import type * as spec from './spec.layout.ts'
+
+// DOMStack's type registry names the renderer `render`; layout modules export it as default.
+declare module '@domstack/static/types.js' {
+ interface LayoutRegistry {
+ root: typeof root & { render: typeof root.default }
+ marketing: typeof marketing & { render: typeof marketing.default }
+ product: typeof product & { render: typeof product.default }
+ learn: typeof learn & { render: typeof learn.default }
+ redirect: typeof redirect & { render: typeof redirect.default }
+ docs: typeof docs & { render: typeof docs.default }
+ spec: typeof spec & { render: typeof spec.default }
+ }
+}
diff --git a/src/layouts/root.layout.ts b/src/layouts/root.layout.ts
index 80c191b4..3431e8cc 100644
--- a/src/layouts/root.layout.ts
+++ b/src/layouts/root.layout.ts
@@ -1,10 +1,24 @@
-import { load } from 'cheerio'
-import { highlight } from '../lib/markdown.ts'
+import { rootContent } from '#lib/rendering.ts'
+import { plainTitle } from '#lib/titles.ts'
import { html, raw, render } from 'fragtml'
import type { LayoutFunction } from '@domstack/static/types.js'
-import { header, footer } from '../lib/navigation.ts'
-import { collections, type Collection } from '../lib/collections.ts'
-const root: LayoutFunction, string> = ({
+import { header, footer } from '#lib/navigation.ts'
+import { collections, type Collection } from '#lib/collections.ts'
+interface RootVars {
+ title: string
+ siteUrl: string
+ siteName?: string
+ lang?: string
+ layout: string
+ docsCollection?: Collection
+ description?: string
+ bodyClass?: string
+ product?: string
+ redirect?: string
+ footerLabel?: string
+ bodyAttrs?: { 'data-ask-ai'?: string | boolean }
+}
+const root: LayoutFunction = ({
vars: v,
children,
page,
@@ -12,30 +26,18 @@ const root: LayoutFunction, string> = ({
styles = [],
}) => {
const collection = v.docsCollection
- ? collections[v.docsCollection as Collection]
+ ? collections[v.docsCollection]
: undefined
const editorial = (v.bodyClass || '').includes('editorial-layout')
const product = collection?.product || v.product || ''
const title = collection
- ? `${v.title} · ${v.layout === 'spec' ? 'Silk Spec' : collection.title} · Oro Computer`
+ ? `${plainTitle(v.title)} · ${v.layout === 'spec' ? 'Silk Spec' : collection.title} · ${v.siteName ?? 'Oro Computer'}`
: v.title
- if (!collection && children.includes(' {
- const language = $(el)
- .attr('class')
- ?.match(/language-([\w+-]+)/)?.[1]
- if (language) {
- const highlighted = highlight($(el).text(), language)
- if (highlighted) $(el).html(highlighted).addClass('hljs')
- }
- })
- children = $.html()
- }
+ if (!collection) children = rootContent(children)
const canonical = new URL(v.redirect || page.url, v.siteUrl).href
return render(
html`
-
+
@@ -49,7 +51,7 @@ const root: LayoutFunction, string> = ({
('[data-spec-app]')
if (app) {
enhanceArticle(app)
@@ -16,3 +17,5 @@ if (app) {
if (p && !/^spec\/2026(?:\.md)?$/.test(p))
location.replace('/silk/docs/?p=' + encodeURIComponent(p) + location.hash)
}
+
+initAskAiMenu()
diff --git a/src/layouts/spec.layout.ts b/src/layouts/spec.layout.ts
index 2d6f6c65..511fddca 100644
--- a/src/layouts/spec.layout.ts
+++ b/src/layouts/spec.layout.ts
@@ -1,9 +1,20 @@
import { html, raw, render } from 'fragtml'
import type { LayoutFunction } from '@domstack/static/types.js'
-import { article } from './docs.layout.ts'
+import { article } from '#lib/rendering.ts'
+import { plainTitle } from '#lib/titles.ts'
+import { collections } from '#lib/collections.ts'
+import { rawUrl, type DocVars } from '#lib/docs.ts'
+export { pageOutputs } from '#lib/docs-page-outputs.ts'
export const parentLayout = 'root'
-const spec: LayoutFunction, string> = ({ children }) => {
+type SpecVars = DocVars & { specLabel?: string }
+const spec: LayoutFunction = ({ vars: v, children }) => {
const { body, toc } = article(children, true)
+ const markdownUrl = rawUrl({ collection: v.docsCollection, sourcePath: v.sourcePath })
+ const year = v.sourcePath.match(/(?:^|\/)(\d{4})\.(?:md|txt)$/)?.[1]
+ const productLabel = collections[v.docsCollection].title.replace(/ (?:Docs|Wiki)$/, '')
+ const label = v.specLabel ?? (year ? `${productLabel} Spec (${year})` : plainTitle(v.title))
+ const upstreamPath = v.sourcePath.split('/').map(encodeURIComponent).join('/')
+ const upstreamUrl = `https://github.com/${v.githubRepo}/blob/${encodeURIComponent(v.githubRef)}/docs/${upstreamPath}`
return render(
html`
@@ -11,14 +22,14 @@ const spec: LayoutFunction, string> = ({ children }) => {