ltcai 4.0.1 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -24
- package/desktop/electron/main.cjs +44 -0
- package/docs/CHANGELOG.md +84 -0
- package/docs/V4_1_FRONTEND_ARCHITECTURE_REVIEW.md +65 -0
- package/docs/V4_1_FRONTEND_MIGRATION_REPORT.md +70 -0
- package/docs/V4_1_VALIDATION_REPORT.md +47 -0
- package/docs/V4_2_BRAIN_CORE_ARCHITECTURE.md +97 -0
- package/docs/V4_2_STORAGE_MIGRATION_REPORT.md +91 -0
- package/docs/V4_2_VALIDATION_REPORT.md +89 -0
- package/docs/V4_DIGITAL_BRAIN_RECOVERY.md +31 -26
- package/frontend/index.html +24 -0
- package/frontend/openapi.json +14436 -0
- package/frontend/src/App.tsx +184 -0
- package/frontend/src/api/client.ts +320 -0
- package/frontend/src/api/openapi.ts +16921 -0
- package/frontend/src/components/primitives.tsx +204 -0
- package/frontend/src/components/ui/badge.tsx +27 -0
- package/frontend/src/components/ui/button.tsx +37 -0
- package/frontend/src/components/ui/card.tsx +22 -0
- package/frontend/src/components/ui/input.tsx +16 -0
- package/frontend/src/components/ui/textarea.tsx +16 -0
- package/frontend/src/lib/utils.ts +33 -0
- package/frontend/src/main.tsx +23 -0
- package/frontend/src/pages/Act.tsx +245 -0
- package/frontend/src/pages/Ask.tsx +200 -0
- package/frontend/src/pages/Brain.tsx +267 -0
- package/frontend/src/pages/Capture.tsx +158 -0
- package/frontend/src/pages/Library.tsx +187 -0
- package/frontend/src/pages/System.tsx +378 -0
- package/frontend/src/routes.ts +85 -0
- package/frontend/src/store/appStore.ts +54 -0
- package/frontend/src/styles.css +107 -0
- package/kg_schema.py +1 -1
- package/knowledge_graph.py +4 -4
- package/lattice_brain/__init__.py +70 -0
- package/lattice_brain/_kg_common.py +1 -0
- package/lattice_brain/archive.py +133 -0
- package/lattice_brain/context.py +3 -0
- package/lattice_brain/conversations.py +3 -0
- package/lattice_brain/core.py +82 -0
- package/lattice_brain/discovery.py +1 -0
- package/lattice_brain/documents.py +1 -0
- package/lattice_brain/embeddings.py +82 -0
- package/lattice_brain/identity.py +13 -0
- package/lattice_brain/ingest.py +1 -0
- package/lattice_brain/memory.py +3 -0
- package/lattice_brain/network.py +1 -0
- package/lattice_brain/projection.py +1 -0
- package/lattice_brain/provenance.py +1 -0
- package/lattice_brain/retrieval.py +1 -0
- package/lattice_brain/schema.py +1 -0
- package/lattice_brain/storage/__init__.py +22 -0
- package/lattice_brain/storage/base.py +72 -0
- package/lattice_brain/storage/docker.py +105 -0
- package/lattice_brain/storage/factory.py +31 -0
- package/lattice_brain/storage/migration.py +190 -0
- package/lattice_brain/storage/postgres.py +123 -0
- package/lattice_brain/storage/sqlite.py +128 -0
- package/lattice_brain/store.py +3 -0
- package/lattice_brain/write_master.py +1 -0
- package/latticeai/__init__.py +1 -1
- package/latticeai/api/portability.py +69 -0
- package/latticeai/api/setup.py +5 -4
- package/latticeai/api/static_routes.py +4 -4
- package/latticeai/app_factory.py +17 -10
- package/latticeai/brain/__init__.py +6 -6
- package/latticeai/brain/_kg_common.py +1 -1
- package/latticeai/brain/network.py +1 -1
- package/latticeai/brain/retrieval.py +15 -0
- package/latticeai/brain/store.py +22 -6
- package/latticeai/core/config.py +8 -0
- package/latticeai/core/marketplace.py +1 -1
- package/latticeai/core/multi_agent.py +1 -1
- package/latticeai/core/workspace_os.py +1 -1
- package/latticeai/services/kg_portability.py +82 -1
- package/package.json +55 -15
- package/scripts/build_frontend_assets.mjs +38 -0
- package/scripts/bump_version.py +4 -1
- package/scripts/export_openapi.py +31 -0
- package/scripts/lint_frontend.mjs +91 -0
- package/scripts/migrate_brain_storage.py +53 -0
- package/scripts/run_python.mjs +47 -0
- package/scripts/wheel_smoke.py +3 -0
- package/src-tauri/Cargo.lock +4833 -0
- package/src-tauri/Cargo.toml +19 -0
- package/src-tauri/build.rs +3 -0
- package/src-tauri/capabilities/default.json +7 -0
- package/src-tauri/src/main.rs +78 -0
- package/src-tauri/tauri.conf.json +39 -0
- package/static/app/asset-manifest.json +32 -0
- package/static/app/assets/core-CwxXejkd.js +2 -0
- package/static/app/assets/core-CwxXejkd.js.map +1 -0
- package/static/app/assets/index-CDjiH_se.css +2 -0
- package/static/app/assets/index-C_HAkbAg.js +333 -0
- package/static/app/assets/index-C_HAkbAg.js.map +1 -0
- package/static/app/index.html +25 -0
- package/static/manifest.json +2 -2
- package/static/sw.js +4 -4
- package/scripts/build_v3_assets.mjs +0 -170
- package/scripts/lint_v3.mjs +0 -120
- package/static/v3/asset-manifest.json +0 -63
- package/static/v3/css/lattice.base.49deefb5.css +0 -128
- package/static/v3/css/lattice.base.css +0 -128
- package/static/v3/css/lattice.components.cde18231.css +0 -472
- package/static/v3/css/lattice.components.css +0 -472
- package/static/v3/css/lattice.shell.29d36d85.css +0 -452
- package/static/v3/css/lattice.shell.css +0 -452
- package/static/v3/css/lattice.tokens.304cbc40.css +0 -135
- package/static/v3/css/lattice.tokens.css +0 -135
- package/static/v3/css/lattice.views.0a18b6c5.css +0 -360
- package/static/v3/css/lattice.views.css +0 -360
- package/static/v3/index.html +0 -68
- package/static/v3/js/app.c5c80c46.js +0 -26
- package/static/v3/js/app.js +0 -26
- package/static/v3/js/core/api.ba0fbf14.js +0 -625
- package/static/v3/js/core/api.js +0 -625
- package/static/v3/js/core/components.f25b3b93.js +0 -230
- package/static/v3/js/core/components.js +0 -230
- package/static/v3/js/core/dom.a2773eb0.js +0 -148
- package/static/v3/js/core/dom.js +0 -148
- package/static/v3/js/core/i18n.880e1fec.js +0 -575
- package/static/v3/js/core/i18n.js +0 -575
- package/static/v3/js/core/router.584570f2.js +0 -37
- package/static/v3/js/core/router.js +0 -37
- package/static/v3/js/core/routes.37522821.js +0 -101
- package/static/v3/js/core/routes.js +0 -101
- package/static/v3/js/core/shell.e3f6bbfa.js +0 -420
- package/static/v3/js/core/shell.js +0 -420
- package/static/v3/js/core/store.7b2aa044.js +0 -123
- package/static/v3/js/core/store.js +0 -123
- package/static/v3/js/views/account.eff40715.js +0 -143
- package/static/v3/js/views/account.js +0 -143
- package/static/v3/js/views/activity.0d271ef9.js +0 -67
- package/static/v3/js/views/activity.js +0 -67
- package/static/v3/js/views/admin-audit.660a1fb1.js +0 -185
- package/static/v3/js/views/admin-audit.js +0 -185
- package/static/v3/js/views/admin-permissions.a7ae5f09.js +0 -177
- package/static/v3/js/views/admin-permissions.js +0 -177
- package/static/v3/js/views/admin-policies.3658fd86.js +0 -102
- package/static/v3/js/views/admin-policies.js +0 -102
- package/static/v3/js/views/admin-private-vpc.7d342d36.js +0 -135
- package/static/v3/js/views/admin-private-vpc.js +0 -135
- package/static/v3/js/views/admin-security.07c66b72.js +0 -180
- package/static/v3/js/views/admin-security.js +0 -180
- package/static/v3/js/views/admin-users.f7ac7b43.js +0 -166
- package/static/v3/js/views/admin-users.js +0 -166
- package/static/v3/js/views/agents.17c5288d.js +0 -564
- package/static/v3/js/views/agents.js +0 -564
- package/static/v3/js/views/chat.e250e2cc.js +0 -624
- package/static/v3/js/views/chat.js +0 -624
- package/static/v3/js/views/files.adad14c1.js +0 -365
- package/static/v3/js/views/files.js +0 -365
- package/static/v3/js/views/graph-canvas.17c15d65.js +0 -509
- package/static/v3/js/views/graph-canvas.js +0 -509
- package/static/v3/js/views/home.24f8b8ae.js +0 -200
- package/static/v3/js/views/home.js +0 -200
- package/static/v3/js/views/hooks.37895880.js +0 -220
- package/static/v3/js/views/hooks.js +0 -220
- package/static/v3/js/views/hybrid-search.2fb63ed9.js +0 -194
- package/static/v3/js/views/hybrid-search.js +0 -194
- package/static/v3/js/views/knowledge-graph.4d09c537.js +0 -529
- package/static/v3/js/views/knowledge-graph.js +0 -529
- package/static/v3/js/views/marketplace.ab0583d4.js +0 -141
- package/static/v3/js/views/marketplace.js +0 -141
- package/static/v3/js/views/mcp.99b5c6a7.js +0 -114
- package/static/v3/js/views/mcp.js +0 -114
- package/static/v3/js/views/memory.4ebdf474.js +0 -147
- package/static/v3/js/views/memory.js +0 -147
- package/static/v3/js/views/models.a1ffa147.js +0 -256
- package/static/v3/js/views/models.js +0 -256
- package/static/v3/js/views/my-computer.d9d9ae1c.js +0 -463
- package/static/v3/js/views/my-computer.js +0 -463
- package/static/v3/js/views/network.52a4f181.js +0 -97
- package/static/v3/js/views/network.js +0 -97
- package/static/v3/js/views/pipeline.c522f1ce.js +0 -157
- package/static/v3/js/views/pipeline.js +0 -157
- package/static/v3/js/views/planning.4876fd77.js +0 -174
- package/static/v3/js/views/planning.js +0 -174
- package/static/v3/js/views/runs.b63b2afa.js +0 -144
- package/static/v3/js/views/runs.js +0 -144
- package/static/v3/js/views/settings.b7140634.js +0 -317
- package/static/v3/js/views/settings.js +0 -317
- package/static/v3/js/views/skills.c6c2f965.js +0 -109
- package/static/v3/js/views/skills.js +0 -109
- package/static/v3/js/views/snapshots.6f5db095.js +0 -135
- package/static/v3/js/views/snapshots.js +0 -135
- package/static/v3/js/views/tools.e4f11276.js +0 -108
- package/static/v3/js/views/tools.js +0 -108
- package/static/v3/js/views/workflows.7752225a.js +0 -213
- package/static/v3/js/views/workflows.js +0 -213
- package/static/v3/js/views/workspace-admin.c466029b.js +0 -156
- package/static/v3/js/views/workspace-admin.js +0 -156
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
|
+
<meta name="color-scheme" content="dark light" />
|
|
7
|
+
<title>Lattice AI · Digital Brain</title>
|
|
8
|
+
<link rel="manifest" href="/manifest.json" />
|
|
9
|
+
<link rel="icon" type="image/png" sizes="32x32" href="/icons/favicon-32.png" />
|
|
10
|
+
<script>
|
|
11
|
+
(function () {
|
|
12
|
+
try {
|
|
13
|
+
var theme = localStorage.getItem("lattice.theme");
|
|
14
|
+
if (theme === "light" || theme === "dark") document.documentElement.dataset.theme = theme;
|
|
15
|
+
} catch (e) {}
|
|
16
|
+
})();
|
|
17
|
+
</script>
|
|
18
|
+
<script type="module" crossorigin src="/static/app/assets/index-C_HAkbAg.js"></script>
|
|
19
|
+
<link rel="stylesheet" crossorigin href="/static/app/assets/index-CDjiH_se.css">
|
|
20
|
+
</head>
|
|
21
|
+
<body>
|
|
22
|
+
<div id="root"></div>
|
|
23
|
+
<noscript>Lattice AI requires JavaScript for the local Digital Brain desktop shell.</noscript>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
package/static/manifest.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "Lattice AI",
|
|
3
3
|
"short_name": "LatticeAI",
|
|
4
|
-
"description": "Local-first
|
|
4
|
+
"description": "Local-first Digital Brain desktop platform for knowledge graphs, durable memory, hybrid search, agents, and signed brain exchange",
|
|
5
5
|
"start_url": "/app",
|
|
6
6
|
"id": "/",
|
|
7
7
|
"display": "standalone",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
{
|
|
29
29
|
"name": "새 대화",
|
|
30
30
|
"short_name": "대화",
|
|
31
|
-
"url": "/app#/
|
|
31
|
+
"url": "/app#/ask",
|
|
32
32
|
"icons": [{ "src": "/icons/icon-192.png", "sizes": "192x192" }]
|
|
33
33
|
}
|
|
34
34
|
]
|
package/static/sw.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// Lattice Service Worker — PWA install + offline shell for the /app SPA.
|
|
2
|
-
// Strategy: precache the
|
|
2
|
+
// Strategy: precache the Vite app bundle from its asset manifest,
|
|
3
3
|
// cache-first for static assets, network-only for everything dynamic.
|
|
4
|
-
const CACHE = "lattice-
|
|
5
|
-
const MANIFEST_URL = "/static/
|
|
4
|
+
const CACHE = "lattice-v410";
|
|
5
|
+
const MANIFEST_URL = "/static/app/asset-manifest.json";
|
|
6
6
|
|
|
7
7
|
// Non-manifest assets the shell needs offline.
|
|
8
8
|
const SHELL = [
|
|
@@ -29,7 +29,7 @@ async function precache() {
|
|
|
29
29
|
const res = await fetch(MANIFEST_URL, { cache: "no-cache" });
|
|
30
30
|
const manifest = await res.json();
|
|
31
31
|
const entry = manifest.entrypoints || {};
|
|
32
|
-
manifestPaths = [entry.app, ...
|
|
32
|
+
manifestPaths = [entry.app, ...Object.values(manifest.assets || {})]
|
|
33
33
|
.filter(Boolean);
|
|
34
34
|
} catch (err) {
|
|
35
35
|
// Offline install: shell precache below still applies.
|
|
@@ -1,170 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/*
|
|
3
|
-
* Build the v3 browser asset manifest.
|
|
4
|
-
*
|
|
5
|
-
* The source files stay importable in development. This script writes hashed
|
|
6
|
-
* siblings next to each runtime asset, rewrites ES-module imports to those
|
|
7
|
-
* hashed siblings, and emits static/v3/asset-manifest.json for /app.
|
|
8
|
-
*/
|
|
9
|
-
import { createHash } from "node:crypto";
|
|
10
|
-
import {
|
|
11
|
-
existsSync,
|
|
12
|
-
mkdirSync,
|
|
13
|
-
readdirSync,
|
|
14
|
-
readFileSync,
|
|
15
|
-
rmSync,
|
|
16
|
-
statSync,
|
|
17
|
-
writeFileSync,
|
|
18
|
-
} from "node:fs";
|
|
19
|
-
import { basename, dirname, extname, join, relative } from "node:path";
|
|
20
|
-
import { fileURLToPath } from "node:url";
|
|
21
|
-
|
|
22
|
-
const repoRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
23
|
-
const staticRoot = join(repoRoot, "static");
|
|
24
|
-
const manifestPath = join(staticRoot, "v3", "asset-manifest.json");
|
|
25
|
-
|
|
26
|
-
// Version is sourced from package.json — the single source of truth for the
|
|
27
|
-
// release. Never hard-code a version string in the generated manifest.
|
|
28
|
-
const pkgVersion = JSON.parse(
|
|
29
|
-
readFileSync(join(repoRoot, "package.json"), "utf8"),
|
|
30
|
-
).version;
|
|
31
|
-
|
|
32
|
-
const cssSources = [
|
|
33
|
-
"static/css/tokens.css",
|
|
34
|
-
"static/v3/css/lattice.tokens.css",
|
|
35
|
-
"static/v3/css/lattice.base.css",
|
|
36
|
-
"static/v3/css/lattice.components.css",
|
|
37
|
-
"static/v3/css/lattice.shell.css",
|
|
38
|
-
"static/v3/css/lattice.views.css",
|
|
39
|
-
];
|
|
40
|
-
|
|
41
|
-
const moduleRoot = join(staticRoot, "v3", "js");
|
|
42
|
-
const entry = "static/v3/js/app.js";
|
|
43
|
-
|
|
44
|
-
function posix(p) {
|
|
45
|
-
return p.replaceAll("\\", "/");
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function sha(text) {
|
|
49
|
-
return createHash("sha256").update(text).digest("hex").slice(0, 8);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function repoPath(abs) {
|
|
53
|
-
return posix(relative(repoRoot, abs));
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function publicUrl(repoRel) {
|
|
57
|
-
return "/" + posix(repoRel);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function walk(dir) {
|
|
61
|
-
const out = [];
|
|
62
|
-
for (const name of readdirSync(dir)) {
|
|
63
|
-
const p = join(dir, name);
|
|
64
|
-
const st = statSync(p);
|
|
65
|
-
if (st.isDirectory()) out.push(...walk(p));
|
|
66
|
-
else if (name.endsWith(".js")) out.push(p);
|
|
67
|
-
}
|
|
68
|
-
return out;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
function removeGenerated(dir, ext) {
|
|
72
|
-
if (!existsSync(dir)) return;
|
|
73
|
-
for (const name of readdirSync(dir)) {
|
|
74
|
-
const p = join(dir, name);
|
|
75
|
-
const st = statSync(p);
|
|
76
|
-
if (st.isDirectory()) removeGenerated(p, ext);
|
|
77
|
-
else if (new RegExp(`\\.[0-9a-f]{8}\\${ext}$`).test(name)) rmSync(p);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
removeGenerated(join(staticRoot, "css"), ".css");
|
|
82
|
-
removeGenerated(join(staticRoot, "v3", "css"), ".css");
|
|
83
|
-
removeGenerated(moduleRoot, ".js");
|
|
84
|
-
|
|
85
|
-
const modules = new Map();
|
|
86
|
-
for (const abs of walk(moduleRoot)) {
|
|
87
|
-
modules.set(repoPath(abs), {
|
|
88
|
-
abs,
|
|
89
|
-
rel: repoPath(abs),
|
|
90
|
-
source: readFileSync(abs, "utf8"),
|
|
91
|
-
deps: [],
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const importFromRe = /\b(?:import|export)\s+(?:[^"'()]*?\s+from\s*)?["']([^"']+\.js)["']/g;
|
|
96
|
-
for (const mod of modules.values()) {
|
|
97
|
-
const deps = [];
|
|
98
|
-
let match;
|
|
99
|
-
while ((match = importFromRe.exec(mod.source))) {
|
|
100
|
-
const spec = match[1];
|
|
101
|
-
if (!spec.startsWith(".")) continue;
|
|
102
|
-
const depRel = repoPath(join(dirname(mod.abs), spec));
|
|
103
|
-
if (modules.has(depRel)) deps.push(depRel);
|
|
104
|
-
}
|
|
105
|
-
mod.deps = deps;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const hashMemo = new Map();
|
|
109
|
-
function moduleHash(rel, stack = []) {
|
|
110
|
-
if (hashMemo.has(rel)) return hashMemo.get(rel);
|
|
111
|
-
if (stack.includes(rel)) return sha(modules.get(rel).source);
|
|
112
|
-
const mod = modules.get(rel);
|
|
113
|
-
const depHashes = mod.deps
|
|
114
|
-
.sort()
|
|
115
|
-
.map((dep) => `${dep}:${moduleHash(dep, [...stack, rel])}`)
|
|
116
|
-
.join("\n");
|
|
117
|
-
const h = sha(`${mod.source}\n/* dependency-hashes */\n${depHashes}`);
|
|
118
|
-
hashMemo.set(rel, h);
|
|
119
|
-
return h;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
for (const rel of modules.keys()) moduleHash(rel);
|
|
123
|
-
|
|
124
|
-
function hashedRel(rel, hash) {
|
|
125
|
-
const ext = extname(rel);
|
|
126
|
-
return posix(join(dirname(rel), `${basename(rel, ext)}.${hash}${ext}`));
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const assets = {};
|
|
130
|
-
|
|
131
|
-
for (const sourceRel of cssSources) {
|
|
132
|
-
const abs = join(repoRoot, sourceRel);
|
|
133
|
-
const source = readFileSync(abs, "utf8");
|
|
134
|
-
const outRel = hashedRel(sourceRel, sha(source));
|
|
135
|
-
writeFileSync(join(repoRoot, outRel), source, "utf8");
|
|
136
|
-
assets[sourceRel] = publicUrl(outRel);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function rewriteModule(mod) {
|
|
140
|
-
return mod.source.replace(importFromRe, (full, spec) => {
|
|
141
|
-
if (!spec.startsWith(".")) return full;
|
|
142
|
-
const depRel = repoPath(join(dirname(mod.abs), spec));
|
|
143
|
-
const depHash = hashMemo.get(depRel);
|
|
144
|
-
if (!depHash) return full;
|
|
145
|
-
const depOutAbs = join(repoRoot, hashedRel(depRel, depHash));
|
|
146
|
-
const nextSpec = posix(relative(dirname(join(repoRoot, hashedRel(mod.rel, hashMemo.get(mod.rel)))), depOutAbs));
|
|
147
|
-
const normalized = nextSpec.startsWith(".") ? nextSpec : `./${nextSpec}`;
|
|
148
|
-
return full.replace(spec, normalized);
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
for (const mod of modules.values()) {
|
|
153
|
-
const outRel = hashedRel(mod.rel, hashMemo.get(mod.rel));
|
|
154
|
-
mkdirSync(dirname(join(repoRoot, outRel)), { recursive: true });
|
|
155
|
-
writeFileSync(join(repoRoot, outRel), rewriteModule(mod), "utf8");
|
|
156
|
-
assets[mod.rel] = publicUrl(outRel);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const manifest = {
|
|
160
|
-
version: pkgVersion,
|
|
161
|
-
generated_at: "deterministic",
|
|
162
|
-
entrypoints: {
|
|
163
|
-
app: assets[entry],
|
|
164
|
-
styles: cssSources.map((rel) => assets[rel]),
|
|
165
|
-
},
|
|
166
|
-
assets,
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
|
|
170
|
-
console.log(`wrote ${repoPath(manifestPath)} with ${Object.keys(assets).length} assets`);
|
package/scripts/lint_v3.mjs
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/* Lattice v3 frontend lint. Gates `npm run lint`:
|
|
3
|
-
* 1. Syntax-check every v3 ES module (node --check).
|
|
4
|
-
* 2. Design tokens: no raw hex/rgb colors in static/v3/css outside the two
|
|
5
|
-
* token files (lattice.tokens.css, tokens.css) — themed surfaces must use
|
|
6
|
-
* var(--…) tokens.
|
|
7
|
-
* 3. No inline style colors in view JS (style="…color: #…" or
|
|
8
|
-
* style.color = "#…" literals).
|
|
9
|
-
* 4. Privacy: zero CDN/external URLs in shipped static HTML/CSS/JS —
|
|
10
|
-
* fonts/icons/libs are vendored under static/vendor.
|
|
11
|
-
* 5. i18n: routes, shell, and new v4 parity views must use the SPA i18n
|
|
12
|
-
* runtime instead of inert localStorage-only language toggles.
|
|
13
|
-
* Exits non-zero on any failure. */
|
|
14
|
-
import { readdirSync, statSync, readFileSync } from "node:fs";
|
|
15
|
-
import { join, dirname, relative } from "node:path";
|
|
16
|
-
import { fileURLToPath } from "node:url";
|
|
17
|
-
import { spawnSync } from "node:child_process";
|
|
18
|
-
|
|
19
|
-
const repo = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
20
|
-
const v3js = join(repo, "static", "v3", "js");
|
|
21
|
-
const v3css = join(repo, "static", "v3", "css");
|
|
22
|
-
const staticRoot = join(repo, "static");
|
|
23
|
-
|
|
24
|
-
function walk(dir, ext) {
|
|
25
|
-
const out = [];
|
|
26
|
-
for (const name of readdirSync(dir)) {
|
|
27
|
-
const p = join(dir, name);
|
|
28
|
-
if (statSync(p).isDirectory()) out.push(...walk(p, ext));
|
|
29
|
-
else if (ext.some((e) => name.endsWith(e))) out.push(p);
|
|
30
|
-
}
|
|
31
|
-
return out;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let failed = 0;
|
|
35
|
-
const fail = (msg) => { failed++; console.error(`FAIL ${msg}`); };
|
|
36
|
-
|
|
37
|
-
// ── 1. syntax ────────────────────────────────────────────────────────────
|
|
38
|
-
const modules = walk(v3js, [".js"]).sort();
|
|
39
|
-
let syntaxOk = 0;
|
|
40
|
-
for (const file of modules) {
|
|
41
|
-
const r = spawnSync(process.execPath, ["--check", file], { encoding: "utf8" });
|
|
42
|
-
if (r.status === 0) syntaxOk++;
|
|
43
|
-
else fail(`${relative(repo, file)}\n${r.stderr || r.stdout}`);
|
|
44
|
-
}
|
|
45
|
-
console.log(`syntax: ${syntaxOk}/${modules.length} v3 modules pass`);
|
|
46
|
-
|
|
47
|
-
// ── 2. raw colors in v3 css (outside token files) ────────────────────────
|
|
48
|
-
const TOKEN_FILES = new Set(["lattice.tokens.css", "tokens.css"]);
|
|
49
|
-
const colorRe = /#[0-9a-fA-F]{3,8}\b|rgba?\(/;
|
|
50
|
-
let cssChecked = 0;
|
|
51
|
-
for (const file of walk(v3css, [".css"]).sort()) {
|
|
52
|
-
const base = file.split("/").pop();
|
|
53
|
-
if (TOKEN_FILES.has(base) || /\.[0-9a-f]{8}\.css$/.test(base)) continue; // tokens + hashed builds
|
|
54
|
-
cssChecked++;
|
|
55
|
-
const lines = readFileSync(file, "utf8").split("\n");
|
|
56
|
-
lines.forEach((line, i) => {
|
|
57
|
-
const code = line.split("/*")[0];
|
|
58
|
-
// mask-image gradients use #000/transparent as ALPHA values, not themed
|
|
59
|
-
// colors — they are theme-independent and exempt.
|
|
60
|
-
if (/mask-image|-webkit-mask/.test(code)) return;
|
|
61
|
-
if (colorRe.test(code)) fail(`${relative(repo, file)}:${i + 1} raw color (use a var(--…) token): ${line.trim().slice(0, 90)}`);
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
console.log(`tokens: ${cssChecked} non-token v3 css files scanned for raw colors`);
|
|
65
|
-
|
|
66
|
-
// ── 3. inline style colors in view JS ────────────────────────────────────
|
|
67
|
-
const inlineColorRe = /style\s*=\s*["'`][^"'`]*(?:color|background)\s*:\s*(#|rgb)/i;
|
|
68
|
-
const styleAssignRe = /\.style\.(color|background(?:Color)?)\s*=\s*["'`](#|rgb)/i;
|
|
69
|
-
let jsChecked = 0;
|
|
70
|
-
for (const file of modules) {
|
|
71
|
-
if (/\.[0-9a-f]{8}\.js$/.test(file)) continue; // hashed builds mirror sources
|
|
72
|
-
jsChecked++;
|
|
73
|
-
const lines = readFileSync(file, "utf8").split("\n");
|
|
74
|
-
lines.forEach((line, i) => {
|
|
75
|
-
if (inlineColorRe.test(line) || styleAssignRe.test(line)) {
|
|
76
|
-
fail(`${relative(repo, file)}:${i + 1} inline style color (use a token/class): ${line.trim().slice(0, 90)}`);
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
console.log(`inline-style: ${jsChecked} v3 source modules scanned`);
|
|
81
|
-
|
|
82
|
-
// ── 4. no CDN/external asset URLs in shipped static files ────────────────
|
|
83
|
-
const cdnRe = /https?:\/\/(fonts\.googleapis\.com|fonts\.gstatic\.com|cdn\.jsdelivr\.net|unpkg\.com|cdnjs\.cloudflare\.com)/;
|
|
84
|
-
let shippedChecked = 0;
|
|
85
|
-
for (const file of walk(staticRoot, [".html", ".css", ".js"]).sort()) {
|
|
86
|
-
if (file.includes(`${join("static", "vendor")}`)) continue; // vendored copies may cite origins in comments
|
|
87
|
-
shippedChecked++;
|
|
88
|
-
const lines = readFileSync(file, "utf8").split("\n");
|
|
89
|
-
lines.forEach((line, i) => {
|
|
90
|
-
if (cdnRe.test(line)) fail(`${relative(repo, file)}:${i + 1} CDN reference (vendor it under static/vendor): ${line.trim().slice(0, 90)}`);
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
console.log(`privacy: ${shippedChecked} shipped static files scanned for CDN URLs`);
|
|
94
|
-
|
|
95
|
-
// ── 5. i18n acceptance for T9 surfaces ──────────────────────────────────
|
|
96
|
-
const i18nRequired = [
|
|
97
|
-
"static/v3/js/core/routes.js",
|
|
98
|
-
"static/v3/js/core/shell.js",
|
|
99
|
-
"static/v3/js/views/account.js",
|
|
100
|
-
"static/v3/js/views/workspace-admin.js",
|
|
101
|
-
"static/v3/js/views/snapshots.js",
|
|
102
|
-
"static/v3/js/views/activity.js",
|
|
103
|
-
"static/v3/js/views/runs.js",
|
|
104
|
-
"static/v3/js/views/network.js",
|
|
105
|
-
];
|
|
106
|
-
let i18nChecked = 0;
|
|
107
|
-
for (const rel of i18nRequired) {
|
|
108
|
-
const file = join(repo, rel);
|
|
109
|
-
const text = readFileSync(file, "utf8");
|
|
110
|
-
i18nChecked++;
|
|
111
|
-
if (!/i18n\.js/.test(text)) fail(`${rel}: missing i18n runtime import`);
|
|
112
|
-
if (!/\bt\(/.test(text)) fail(`${rel}: no translation lookup found`);
|
|
113
|
-
}
|
|
114
|
-
console.log(`i18n: ${i18nChecked} route/shell/parity modules checked`);
|
|
115
|
-
|
|
116
|
-
if (failed) {
|
|
117
|
-
console.error(`\nv3 frontend lint: ${failed} failure(s)`);
|
|
118
|
-
process.exit(1);
|
|
119
|
-
}
|
|
120
|
-
console.log(`\nv3 frontend lint: all checks pass`);
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "4.0.1",
|
|
3
|
-
"generated_at": "deterministic",
|
|
4
|
-
"entrypoints": {
|
|
5
|
-
"app": "/static/v3/js/app.c5c80c46.js",
|
|
6
|
-
"styles": [
|
|
7
|
-
"/static/css/tokens.3ba22e37.css",
|
|
8
|
-
"/static/v3/css/lattice.tokens.304cbc40.css",
|
|
9
|
-
"/static/v3/css/lattice.base.49deefb5.css",
|
|
10
|
-
"/static/v3/css/lattice.components.cde18231.css",
|
|
11
|
-
"/static/v3/css/lattice.shell.29d36d85.css",
|
|
12
|
-
"/static/v3/css/lattice.views.0a18b6c5.css"
|
|
13
|
-
]
|
|
14
|
-
},
|
|
15
|
-
"assets": {
|
|
16
|
-
"static/css/tokens.css": "/static/css/tokens.3ba22e37.css",
|
|
17
|
-
"static/v3/css/lattice.tokens.css": "/static/v3/css/lattice.tokens.304cbc40.css",
|
|
18
|
-
"static/v3/css/lattice.base.css": "/static/v3/css/lattice.base.49deefb5.css",
|
|
19
|
-
"static/v3/css/lattice.components.css": "/static/v3/css/lattice.components.cde18231.css",
|
|
20
|
-
"static/v3/css/lattice.shell.css": "/static/v3/css/lattice.shell.29d36d85.css",
|
|
21
|
-
"static/v3/css/lattice.views.css": "/static/v3/css/lattice.views.0a18b6c5.css",
|
|
22
|
-
"static/v3/js/app.js": "/static/v3/js/app.c5c80c46.js",
|
|
23
|
-
"static/v3/js/core/api.js": "/static/v3/js/core/api.ba0fbf14.js",
|
|
24
|
-
"static/v3/js/core/components.js": "/static/v3/js/core/components.f25b3b93.js",
|
|
25
|
-
"static/v3/js/core/dom.js": "/static/v3/js/core/dom.a2773eb0.js",
|
|
26
|
-
"static/v3/js/core/i18n.js": "/static/v3/js/core/i18n.880e1fec.js",
|
|
27
|
-
"static/v3/js/core/router.js": "/static/v3/js/core/router.584570f2.js",
|
|
28
|
-
"static/v3/js/core/routes.js": "/static/v3/js/core/routes.37522821.js",
|
|
29
|
-
"static/v3/js/core/shell.js": "/static/v3/js/core/shell.e3f6bbfa.js",
|
|
30
|
-
"static/v3/js/core/store.js": "/static/v3/js/core/store.7b2aa044.js",
|
|
31
|
-
"static/v3/js/views/account.js": "/static/v3/js/views/account.eff40715.js",
|
|
32
|
-
"static/v3/js/views/activity.js": "/static/v3/js/views/activity.0d271ef9.js",
|
|
33
|
-
"static/v3/js/views/admin-audit.js": "/static/v3/js/views/admin-audit.660a1fb1.js",
|
|
34
|
-
"static/v3/js/views/admin-permissions.js": "/static/v3/js/views/admin-permissions.a7ae5f09.js",
|
|
35
|
-
"static/v3/js/views/admin-policies.js": "/static/v3/js/views/admin-policies.3658fd86.js",
|
|
36
|
-
"static/v3/js/views/admin-private-vpc.js": "/static/v3/js/views/admin-private-vpc.7d342d36.js",
|
|
37
|
-
"static/v3/js/views/admin-security.js": "/static/v3/js/views/admin-security.07c66b72.js",
|
|
38
|
-
"static/v3/js/views/admin-users.js": "/static/v3/js/views/admin-users.f7ac7b43.js",
|
|
39
|
-
"static/v3/js/views/agents.js": "/static/v3/js/views/agents.17c5288d.js",
|
|
40
|
-
"static/v3/js/views/chat.js": "/static/v3/js/views/chat.e250e2cc.js",
|
|
41
|
-
"static/v3/js/views/files.js": "/static/v3/js/views/files.adad14c1.js",
|
|
42
|
-
"static/v3/js/views/graph-canvas.js": "/static/v3/js/views/graph-canvas.17c15d65.js",
|
|
43
|
-
"static/v3/js/views/home.js": "/static/v3/js/views/home.24f8b8ae.js",
|
|
44
|
-
"static/v3/js/views/hooks.js": "/static/v3/js/views/hooks.37895880.js",
|
|
45
|
-
"static/v3/js/views/hybrid-search.js": "/static/v3/js/views/hybrid-search.2fb63ed9.js",
|
|
46
|
-
"static/v3/js/views/knowledge-graph.js": "/static/v3/js/views/knowledge-graph.4d09c537.js",
|
|
47
|
-
"static/v3/js/views/marketplace.js": "/static/v3/js/views/marketplace.ab0583d4.js",
|
|
48
|
-
"static/v3/js/views/mcp.js": "/static/v3/js/views/mcp.99b5c6a7.js",
|
|
49
|
-
"static/v3/js/views/memory.js": "/static/v3/js/views/memory.4ebdf474.js",
|
|
50
|
-
"static/v3/js/views/models.js": "/static/v3/js/views/models.a1ffa147.js",
|
|
51
|
-
"static/v3/js/views/my-computer.js": "/static/v3/js/views/my-computer.d9d9ae1c.js",
|
|
52
|
-
"static/v3/js/views/network.js": "/static/v3/js/views/network.52a4f181.js",
|
|
53
|
-
"static/v3/js/views/pipeline.js": "/static/v3/js/views/pipeline.c522f1ce.js",
|
|
54
|
-
"static/v3/js/views/planning.js": "/static/v3/js/views/planning.4876fd77.js",
|
|
55
|
-
"static/v3/js/views/runs.js": "/static/v3/js/views/runs.b63b2afa.js",
|
|
56
|
-
"static/v3/js/views/settings.js": "/static/v3/js/views/settings.b7140634.js",
|
|
57
|
-
"static/v3/js/views/skills.js": "/static/v3/js/views/skills.c6c2f965.js",
|
|
58
|
-
"static/v3/js/views/snapshots.js": "/static/v3/js/views/snapshots.6f5db095.js",
|
|
59
|
-
"static/v3/js/views/tools.js": "/static/v3/js/views/tools.e4f11276.js",
|
|
60
|
-
"static/v3/js/views/workflows.js": "/static/v3/js/views/workflows.7752225a.js",
|
|
61
|
-
"static/v3/js/views/workspace-admin.js": "/static/v3/js/views/workspace-admin.c466029b.js"
|
|
62
|
-
}
|
|
63
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/* ============================================================================
|
|
2
|
-
* Lattice AI v3 — Base layer (reset + element defaults + lattice backdrop)
|
|
3
|
-
* Token-native: no themed hex values, everything via var(--*).
|
|
4
|
-
* ========================================================================== */
|
|
5
|
-
|
|
6
|
-
*, *::before, *::after { box-sizing: border-box; }
|
|
7
|
-
|
|
8
|
-
html, body { height: 100%; }
|
|
9
|
-
|
|
10
|
-
body {
|
|
11
|
-
margin: 0;
|
|
12
|
-
font-family: var(--lt3-font-sans);
|
|
13
|
-
font-size: var(--lt3-text-md);
|
|
14
|
-
line-height: var(--lt3-leading-normal);
|
|
15
|
-
color: var(--text);
|
|
16
|
-
background: var(--bg);
|
|
17
|
-
-webkit-font-smoothing: antialiased;
|
|
18
|
-
text-rendering: optimizeLegibility;
|
|
19
|
-
overflow: hidden; /* shell owns scroll regions */
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/* The signature lattice backdrop — a faint structural mesh of nodes+edges.
|
|
23
|
-
Sits behind the whole app; reinforces the "lattice" identity without noise. */
|
|
24
|
-
.lt3-app::before {
|
|
25
|
-
content: "";
|
|
26
|
-
position: fixed;
|
|
27
|
-
inset: 0;
|
|
28
|
-
z-index: 0;
|
|
29
|
-
pointer-events: none;
|
|
30
|
-
background:
|
|
31
|
-
radial-gradient(circle at center, var(--lt3-mesh-node) 0.9px, transparent 1.1px),
|
|
32
|
-
linear-gradient(var(--lt3-mesh-line) 1px, transparent 1px),
|
|
33
|
-
linear-gradient(90deg, var(--lt3-mesh-line) 1px, transparent 1px),
|
|
34
|
-
var(--app-bg);
|
|
35
|
-
background-size:
|
|
36
|
-
var(--lt3-mesh-size) var(--lt3-mesh-size),
|
|
37
|
-
var(--lt3-mesh-size) var(--lt3-mesh-size),
|
|
38
|
-
var(--lt3-mesh-size) var(--lt3-mesh-size),
|
|
39
|
-
cover;
|
|
40
|
-
background-position: center;
|
|
41
|
-
mask-image: radial-gradient(ellipse 120% 90% at 50% -10%, #000 55%, transparent 100%);
|
|
42
|
-
opacity: 0.9;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
h1, h2, h3, h4, p, figure { margin: 0; }
|
|
46
|
-
|
|
47
|
-
a { color: inherit; text-decoration: none; }
|
|
48
|
-
|
|
49
|
-
button {
|
|
50
|
-
font: inherit;
|
|
51
|
-
color: inherit;
|
|
52
|
-
cursor: pointer;
|
|
53
|
-
border: none;
|
|
54
|
-
background: none;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
input, select, textarea { font: inherit; color: inherit; }
|
|
58
|
-
|
|
59
|
-
textarea { resize: vertical; }
|
|
60
|
-
|
|
61
|
-
img, svg { display: block; max-width: 100%; }
|
|
62
|
-
|
|
63
|
-
code, pre, kbd, samp { font-family: var(--lt3-font-mono); }
|
|
64
|
-
|
|
65
|
-
:root[data-lt-icons="fallback"] .ti {
|
|
66
|
-
display: inline-grid;
|
|
67
|
-
place-items: center;
|
|
68
|
-
min-width: 1em;
|
|
69
|
-
min-height: 1em;
|
|
70
|
-
font-family: var(--lt3-font-mono);
|
|
71
|
-
font-size: 0.72em;
|
|
72
|
-
font-style: normal;
|
|
73
|
-
font-weight: 800;
|
|
74
|
-
line-height: 1;
|
|
75
|
-
text-transform: uppercase;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
:root[data-lt-icons="fallback"] .ti::before {
|
|
79
|
-
content: attr(data-fallback);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
:focus-visible {
|
|
83
|
-
outline: 2px solid var(--focus-ring);
|
|
84
|
-
outline-offset: 2px;
|
|
85
|
-
border-radius: var(--lt3-radius-xs);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
89
|
-
::-webkit-scrollbar-track { background: transparent; }
|
|
90
|
-
::-webkit-scrollbar-thumb {
|
|
91
|
-
background: color-mix(in srgb, var(--border-strong) 60%, transparent);
|
|
92
|
-
border-radius: 99px;
|
|
93
|
-
border: 2px solid transparent;
|
|
94
|
-
background-clip: padding-box;
|
|
95
|
-
}
|
|
96
|
-
::-webkit-scrollbar-thumb:hover { background: var(--border-strong); background-clip: padding-box; }
|
|
97
|
-
|
|
98
|
-
/* Accessible visually-hidden utility */
|
|
99
|
-
.lt3-sr {
|
|
100
|
-
position: absolute !important;
|
|
101
|
-
width: 1px; height: 1px;
|
|
102
|
-
padding: 0; margin: -1px;
|
|
103
|
-
overflow: hidden; clip: rect(0,0,0,0);
|
|
104
|
-
white-space: nowrap; border: 0;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.lt3-skip {
|
|
108
|
-
position: fixed;
|
|
109
|
-
top: var(--lt3-space-3);
|
|
110
|
-
left: var(--lt3-space-3);
|
|
111
|
-
z-index: var(--lt3-z-toast);
|
|
112
|
-
padding: var(--lt3-space-2) var(--lt3-space-4);
|
|
113
|
-
background: var(--accent);
|
|
114
|
-
color: var(--lt3-on-accent);
|
|
115
|
-
border-radius: var(--lt3-radius-sm);
|
|
116
|
-
transform: translateY(-200%);
|
|
117
|
-
transition: transform var(--lt3-dur-2) var(--lt3-ease);
|
|
118
|
-
}
|
|
119
|
-
.lt3-skip:focus { transform: translateY(0); }
|
|
120
|
-
|
|
121
|
-
@media (prefers-reduced-motion: reduce) {
|
|
122
|
-
*, *::before, *::after {
|
|
123
|
-
animation-duration: 0.001ms !important;
|
|
124
|
-
animation-iteration-count: 1 !important;
|
|
125
|
-
transition-duration: 0.001ms !important;
|
|
126
|
-
scroll-behavior: auto !important;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/* ============================================================================
|
|
2
|
-
* Lattice AI v3 — Base layer (reset + element defaults + lattice backdrop)
|
|
3
|
-
* Token-native: no themed hex values, everything via var(--*).
|
|
4
|
-
* ========================================================================== */
|
|
5
|
-
|
|
6
|
-
*, *::before, *::after { box-sizing: border-box; }
|
|
7
|
-
|
|
8
|
-
html, body { height: 100%; }
|
|
9
|
-
|
|
10
|
-
body {
|
|
11
|
-
margin: 0;
|
|
12
|
-
font-family: var(--lt3-font-sans);
|
|
13
|
-
font-size: var(--lt3-text-md);
|
|
14
|
-
line-height: var(--lt3-leading-normal);
|
|
15
|
-
color: var(--text);
|
|
16
|
-
background: var(--bg);
|
|
17
|
-
-webkit-font-smoothing: antialiased;
|
|
18
|
-
text-rendering: optimizeLegibility;
|
|
19
|
-
overflow: hidden; /* shell owns scroll regions */
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/* The signature lattice backdrop — a faint structural mesh of nodes+edges.
|
|
23
|
-
Sits behind the whole app; reinforces the "lattice" identity without noise. */
|
|
24
|
-
.lt3-app::before {
|
|
25
|
-
content: "";
|
|
26
|
-
position: fixed;
|
|
27
|
-
inset: 0;
|
|
28
|
-
z-index: 0;
|
|
29
|
-
pointer-events: none;
|
|
30
|
-
background:
|
|
31
|
-
radial-gradient(circle at center, var(--lt3-mesh-node) 0.9px, transparent 1.1px),
|
|
32
|
-
linear-gradient(var(--lt3-mesh-line) 1px, transparent 1px),
|
|
33
|
-
linear-gradient(90deg, var(--lt3-mesh-line) 1px, transparent 1px),
|
|
34
|
-
var(--app-bg);
|
|
35
|
-
background-size:
|
|
36
|
-
var(--lt3-mesh-size) var(--lt3-mesh-size),
|
|
37
|
-
var(--lt3-mesh-size) var(--lt3-mesh-size),
|
|
38
|
-
var(--lt3-mesh-size) var(--lt3-mesh-size),
|
|
39
|
-
cover;
|
|
40
|
-
background-position: center;
|
|
41
|
-
mask-image: radial-gradient(ellipse 120% 90% at 50% -10%, #000 55%, transparent 100%);
|
|
42
|
-
opacity: 0.9;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
h1, h2, h3, h4, p, figure { margin: 0; }
|
|
46
|
-
|
|
47
|
-
a { color: inherit; text-decoration: none; }
|
|
48
|
-
|
|
49
|
-
button {
|
|
50
|
-
font: inherit;
|
|
51
|
-
color: inherit;
|
|
52
|
-
cursor: pointer;
|
|
53
|
-
border: none;
|
|
54
|
-
background: none;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
input, select, textarea { font: inherit; color: inherit; }
|
|
58
|
-
|
|
59
|
-
textarea { resize: vertical; }
|
|
60
|
-
|
|
61
|
-
img, svg { display: block; max-width: 100%; }
|
|
62
|
-
|
|
63
|
-
code, pre, kbd, samp { font-family: var(--lt3-font-mono); }
|
|
64
|
-
|
|
65
|
-
:root[data-lt-icons="fallback"] .ti {
|
|
66
|
-
display: inline-grid;
|
|
67
|
-
place-items: center;
|
|
68
|
-
min-width: 1em;
|
|
69
|
-
min-height: 1em;
|
|
70
|
-
font-family: var(--lt3-font-mono);
|
|
71
|
-
font-size: 0.72em;
|
|
72
|
-
font-style: normal;
|
|
73
|
-
font-weight: 800;
|
|
74
|
-
line-height: 1;
|
|
75
|
-
text-transform: uppercase;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
:root[data-lt-icons="fallback"] .ti::before {
|
|
79
|
-
content: attr(data-fallback);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
:focus-visible {
|
|
83
|
-
outline: 2px solid var(--focus-ring);
|
|
84
|
-
outline-offset: 2px;
|
|
85
|
-
border-radius: var(--lt3-radius-xs);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
89
|
-
::-webkit-scrollbar-track { background: transparent; }
|
|
90
|
-
::-webkit-scrollbar-thumb {
|
|
91
|
-
background: color-mix(in srgb, var(--border-strong) 60%, transparent);
|
|
92
|
-
border-radius: 99px;
|
|
93
|
-
border: 2px solid transparent;
|
|
94
|
-
background-clip: padding-box;
|
|
95
|
-
}
|
|
96
|
-
::-webkit-scrollbar-thumb:hover { background: var(--border-strong); background-clip: padding-box; }
|
|
97
|
-
|
|
98
|
-
/* Accessible visually-hidden utility */
|
|
99
|
-
.lt3-sr {
|
|
100
|
-
position: absolute !important;
|
|
101
|
-
width: 1px; height: 1px;
|
|
102
|
-
padding: 0; margin: -1px;
|
|
103
|
-
overflow: hidden; clip: rect(0,0,0,0);
|
|
104
|
-
white-space: nowrap; border: 0;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
.lt3-skip {
|
|
108
|
-
position: fixed;
|
|
109
|
-
top: var(--lt3-space-3);
|
|
110
|
-
left: var(--lt3-space-3);
|
|
111
|
-
z-index: var(--lt3-z-toast);
|
|
112
|
-
padding: var(--lt3-space-2) var(--lt3-space-4);
|
|
113
|
-
background: var(--accent);
|
|
114
|
-
color: var(--lt3-on-accent);
|
|
115
|
-
border-radius: var(--lt3-radius-sm);
|
|
116
|
-
transform: translateY(-200%);
|
|
117
|
-
transition: transform var(--lt3-dur-2) var(--lt3-ease);
|
|
118
|
-
}
|
|
119
|
-
.lt3-skip:focus { transform: translateY(0); }
|
|
120
|
-
|
|
121
|
-
@media (prefers-reduced-motion: reduce) {
|
|
122
|
-
*, *::before, *::after {
|
|
123
|
-
animation-duration: 0.001ms !important;
|
|
124
|
-
animation-iteration-count: 1 !important;
|
|
125
|
-
transition-duration: 0.001ms !important;
|
|
126
|
-
scroll-behavior: auto !important;
|
|
127
|
-
}
|
|
128
|
-
}
|