@viberaven/cli 1.6.9 → 1.6.10

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 CHANGED
@@ -10,10 +10,10 @@ Requires Node.js 20 or newer. Run from the app's project root:
10
10
 
11
11
  ```bash
12
12
  # Open the local Studio
13
- npx -y viberaven@1.6.9
13
+ npx -y viberaven@1.6.10
14
14
 
15
15
  # Fresh terminal check
16
- npx -y viberaven@1.6.9 check
16
+ npx -y viberaven@1.6.10 check
17
17
  ```
18
18
 
19
19
  The `viberaven` package launches this CLI. Studio combines findings, provider context and git comparisons. For chat, select an installed/authenticated Codex CLI, Claude Code or Gemini CLI and use **Test connection**. Access modes: `ask`, `approve`, `full`. Stop Studio with Ctrl+C.
@@ -27,10 +27,10 @@ Checks include migration tables without RLS, unrestricted policy conditions such
27
27
  `check --json` prints a findings summary and artifact paths. `--json` without `check` runs a fresh scan and prints the full gate object.
28
28
 
29
29
  ```bash
30
- npx -y viberaven@1.6.9 check --json
31
- npx -y viberaven@1.6.9 audit --vercel-supabase --json
32
- npx -y viberaven@1.6.9 fix --gap <gapId> --dry-run
33
- npx -y viberaven@1.6.9 init --agents all --dry-run
30
+ npx -y viberaven@1.6.10 check --json
31
+ npx -y viberaven@1.6.10 audit --vercel-supabase --json
32
+ npx -y viberaven@1.6.10 fix --gap <gapId> --dry-run
33
+ npx -y viberaven@1.6.10 init --agents all --dry-run
34
34
  ```
35
35
 
36
36
  Read tasks and source before targeted edits. Preview fixes first. The `rls_disabled` recipe adds an RLS migration without policies: agree before applying, because browser roles lose row access until policies exist. Apply/test through your database workflow; recheck after a batch. Provider actions require provider evidence.
@@ -41,9 +41,9 @@ Read tasks and source before targeted edits. Preview fixes first. The `rls_disab
41
41
 
42
42
  ```bash
43
43
  # Fail on blockers
44
- npx -y viberaven@1.6.9 --strict --json
44
+ npx -y viberaven@1.6.10 --strict --json
45
45
  # Also fail on warnings
46
- npx -y viberaven@1.6.9 --strict=warning --json
46
+ npx -y viberaven@1.6.10 --strict=warning --json
47
47
  ```
48
48
 
49
49
  Default `--strict` returns 0 for `clear`/`warning`, 1 for `not_clear`, 2 for `error`, 3 for `unknown` or unavailable results. `--strict=warning` also returns 1 for warnings.
package/dist/cli.js CHANGED
@@ -15051,7 +15051,7 @@ var VERSION;
15051
15051
  var init_version = __esm({
15052
15052
  "src/version.ts"() {
15053
15053
  "use strict";
15054
- VERSION = "1.6.9";
15054
+ VERSION = "1.6.10";
15055
15055
  }
15056
15056
  });
15057
15057
 
@@ -21533,6 +21533,9 @@ async function readMaybe(path) {
21533
21533
  return null;
21534
21534
  }
21535
21535
  }
21536
+ function blobId(content, like) {
21537
+ return (0, import_node_crypto5.createHash)(like.length === 64 ? "sha256" : "sha1").update(`blob ${content.length}\0`).update(content).digest("hex");
21538
+ }
21536
21539
  function parsePorcelain(raw) {
21537
21540
  const parts = raw.split("\0");
21538
21541
  const entries = [];
@@ -21578,17 +21581,61 @@ async function takeBaseline(cwd) {
21578
21581
  secret: secret || void 0
21579
21582
  };
21580
21583
  }
21581
- return { git: true, root, head: head.code === 0 ? head.stdout.toString("utf8").trim() : null, takenAt, dirty };
21584
+ const headId = head.code === 0 ? head.stdout.toString("utf8").trim() : null;
21585
+ const checkout = headId ? await checkoutForms(cwd, root, headId, dirty, MAX_SNAPSHOT_TOTAL - total) : {};
21586
+ return { git: true, root, head: headId, takenAt, dirty, checkout };
21587
+ }
21588
+ async function checkoutForms(cwd, root, head, dirty, budget) {
21589
+ const tree = await safeGit(cwd, ["ls-tree", "-r", "-z", "--full-name", head], 15e3);
21590
+ if (tree.code !== 0) return {};
21591
+ const files = [];
21592
+ for (const record of tree.stdout.toString("utf8").split("\0")) {
21593
+ const tab = record.indexOf(" ");
21594
+ if (tab < 0) continue;
21595
+ const [mode, type, id] = record.slice(0, tab).split(" ");
21596
+ const path = record.slice(tab + 1);
21597
+ if (type !== "blob" || mode !== "100644" && mode !== "100755") continue;
21598
+ if (path in dirty || isSecretPath(path) || /(?:^|\/)\.viberaven\//.test(path)) continue;
21599
+ files.push({ path, id });
21600
+ }
21601
+ const forms = {};
21602
+ let scanned = 0;
21603
+ const look = async ({ path, id }) => {
21604
+ const target = (0, import_node_path42.join)(root, path);
21605
+ const size = await (0, import_promises33.stat)(target).then((info) => info.size, () => null);
21606
+ if (size === null || scanned + size > MAX_CHECKOUT_SCAN) return;
21607
+ scanned += size;
21608
+ const content = await readMaybe(target);
21609
+ if (!content || blobId(content, id) === id) return;
21610
+ const asLf = withoutCrlf(content);
21611
+ if (asLf.length < content.length && blobId(asLf, id) === id && withCrlf(asLf).equals(content)) {
21612
+ forms[path] = { eol: "crlf" };
21613
+ } else if (content.length <= MAX_SNAPSHOT_BYTES && content.length <= budget) {
21614
+ budget -= content.length;
21615
+ forms[path] = { content: content.toString("base64") };
21616
+ } else {
21617
+ forms[path] = { tooLarge: true };
21618
+ }
21619
+ };
21620
+ let next = 0;
21621
+ await Promise.all(Array.from({ length: CHECKOUT_READS_AT_ONCE }, async () => {
21622
+ while (next < files.length) await look(files[next++]);
21623
+ }));
21624
+ return forms;
21582
21625
  }
21583
21626
  async function baseContent(baseline, path) {
21584
21627
  const entry = baseline.dirty[path];
21585
21628
  if (entry) {
21586
21629
  if (entry.hash === null) return null;
21587
- return entry.content ? Buffer.from(entry.content, "base64") : void 0;
21630
+ return entry.content !== void 0 ? Buffer.from(entry.content, "base64") : void 0;
21588
21631
  }
21589
21632
  if (!baseline.root || !baseline.head) return null;
21633
+ const checkout = baseline.checkout?.[path];
21634
+ if (checkout?.content !== void 0) return Buffer.from(checkout.content, "base64");
21635
+ if (checkout?.tooLarge) return void 0;
21590
21636
  const shown = await safeGit(baseline.root, ["show", `${baseline.head}:${path}`]);
21591
- return shown.code === 0 ? shown.stdout : null;
21637
+ if (shown.code !== 0) return null;
21638
+ return checkout?.eol === "crlf" ? withCrlf(shown.stdout) : shown.stdout;
21592
21639
  }
21593
21640
  function lineStats(before, after) {
21594
21641
  const count = (text2) => {
@@ -21794,7 +21841,7 @@ async function loadBaseline(runsDir, runId) {
21794
21841
  return null;
21795
21842
  }
21796
21843
  }
21797
- var import_node_child_process9, import_node_crypto5, import_promises33, import_node_os3, import_node_path42, STATUS_PATHSPEC, MAX_SNAPSHOT_FILES, MAX_SNAPSHOT_BYTES, MAX_SNAPSHOT_TOTAL, SECRET_FILE, lf, NOT_PROVEN;
21844
+ var import_node_child_process9, import_node_crypto5, import_promises33, import_node_os3, import_node_path42, STATUS_PATHSPEC, MAX_SNAPSHOT_FILES, MAX_SNAPSHOT_BYTES, MAX_SNAPSHOT_TOTAL, MAX_CHECKOUT_SCAN, CHECKOUT_READS_AT_ONCE, SECRET_FILE, withCrlf, withoutCrlf, lf, NOT_PROVEN;
21798
21845
  var init_workspace = __esm({
21799
21846
  "src/local-ui/actions/workspace.ts"() {
21800
21847
  "use strict";
@@ -21808,7 +21855,11 @@ var init_workspace = __esm({
21808
21855
  MAX_SNAPSHOT_FILES = 300;
21809
21856
  MAX_SNAPSHOT_BYTES = 1e6;
21810
21857
  MAX_SNAPSHOT_TOTAL = 2e7;
21858
+ MAX_CHECKOUT_SCAN = 2e8;
21859
+ CHECKOUT_READS_AT_ONCE = 16;
21811
21860
  SECRET_FILE = /(?:^|\/)\.env(?:\.[^/]*)?$|\.(?:pem|key|p12|pfx|keystore)$|(?:^|\/)id_(?:rsa|ed25519|ecdsa)$/i;
21861
+ withCrlf = (content) => Buffer.from(content.toString("latin1").replace(/\n/g, "\r\n"), "latin1");
21862
+ withoutCrlf = (content) => Buffer.from(content.toString("latin1").replace(/\r\n/g, "\n"), "latin1");
21812
21863
  lf = (text2) => text2.replace(/\r\n/g, "\n");
21813
21864
  NOT_PROVEN = "Changed during the run, but not proven to be only the agent\u2019s edit (you or another tool may have changed it), so Undo left it alone. Review it and put it back yourself if you want.";
21814
21865
  }
@@ -24253,9 +24304,13 @@ async function sendStackAppJs(response) {
24253
24304
  }
24254
24305
  async function sendStackAppCss(response) {
24255
24306
  try {
24256
- const body = await (0, import_promises36.readFile)((0, import_node_path45.join)(__dirname, "stack", "stack.css"));
24307
+ const [shell, scene] = await Promise.all([
24308
+ (0, import_promises36.readFile)((0, import_node_path45.join)(__dirname, "stack", "stack.css"), "utf8"),
24309
+ (0, import_promises36.readFile)((0, import_node_path45.join)(__dirname, "stack", "scene.css"), "utf8").catch(() => "")
24310
+ ]);
24257
24311
  response.writeHead(200, { "content-type": "text/css; charset=utf-8", "cache-control": "no-store" });
24258
- response.end(body);
24312
+ response.end(`${shell}
24313
+ ${scene}`);
24259
24314
  } catch {
24260
24315
  sendText(response, 404, "Stack stylesheet not found: src/local-ui/stack/stack.css is missing.");
24261
24316
  }
@@ -0,0 +1,484 @@
1
+ /* The 3D construction scene (scene.ts), shared by the local Studio and viberaven.dev.
2
+ The Studio serves it after stack.css as /stack/app.css; the site imports it inside a .sw-scene container that
3
+ sets the same variables (--ink, --line-2, --font, --mono, --ease...). Only .scene rules live here. */
4
+ /* ---------- the construction scene: a small isometric world for the action in progress ----------
5
+ Planned parts are traced outlines; a part works while its step is active; it settles solid only when its
6
+ evidence arrives. Activity is calm (slow flows, a gentle hover); milestones get one short spring. */
7
+ :root {
8
+ --spring: cubic-bezier(0.34, 1.45, 0.64, 1);
9
+ --sc-amber: #f2c15f;
10
+ --sc-green: #6fd08c;
11
+ --sc-red: #f4715f;
12
+ }
13
+ .scene-stage { position: relative; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; min-width: 0; min-height: 0; }
14
+ .scene-head { display: flex; align-items: center; gap: 12px; min-width: 0; }
15
+ .scene-tag { display: inline-flex; align-items: center; height: 24px; padding: 0 10px; border-radius: 999px; border: 1px solid rgba(242, 193, 95, 0.45); color: var(--sc-amber); font-size: 11.5px; font-weight: 600; letter-spacing: 0.02em; white-space: nowrap; }
16
+ .scene-tag.is-demo { border-style: dashed; border-color: rgba(255, 255, 255, 0.35); color: var(--ink-2); }
17
+ .scene-note { font-size: 12.5px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
18
+ .scene { display: block; width: 100%; height: 100%; min-height: 0; overflow: visible; }
19
+ .scene-caption { justify-self: center; display: inline-flex; align-items: center; gap: 10px; max-width: 100%; min-height: 36px; padding: 8px 16px; border-radius: 999px; border: 1px solid var(--line-2); background: rgba(14, 14, 17, 0.94); font-size: 13.5px; color: var(--ink); animation: settle 0.4s var(--ease) both; }
20
+ .scene-caption > span:first-of-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
21
+ .scene-caption i { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--ink-3); }
22
+ .scene-caption.is-work i { background: var(--sc-amber); animation: pulse-dot 1.4s ease-in-out infinite; }
23
+ .scene-caption.is-wait { border-color: rgba(242, 193, 95, 0.5); }
24
+ .scene-caption.is-wait i { background: var(--sc-amber); }
25
+ .scene-caption.is-pass i { background: var(--sc-green); }
26
+ .scene-caption.is-fail { border-color: rgba(244, 113, 95, 0.45); }
27
+ .scene-caption.is-fail i { background: var(--sc-red); }
28
+ .scene-when { font-size: 12px; color: var(--ink-3); }
29
+ .scene-inspect { position: absolute; left: 0; bottom: 52px; z-index: 2; width: min(320px, 70%); display: grid; gap: 8px; padding: 14px 16px; border-radius: 14px; border: 1px solid var(--line-2); background: rgba(12, 12, 15, 0.97); box-shadow: 0 24px 50px -20px rgba(0, 0, 0, 0.9); animation: settle 0.3s var(--ease) both; }
30
+ .scene-inspect header { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
31
+ .scene-inspect strong { font-size: 14px; font-weight: 600; }
32
+ .scene-inspect p { font-size: 12.5px; line-height: 1.5; color: var(--ink-2); }
33
+ /* Faces. */
34
+ .scene polygon, .scene path, .scene ellipse, .scene rect { stroke-linejoin: round; }
35
+ .scene .f-top, .scene .f-left, .scene .f-right { stroke: rgba(255, 255, 255, 0.07); stroke-width: 0.8; transition: fill 0.45s var(--ease), stroke 0.45s var(--ease), fill-opacity 0.45s var(--ease); }
36
+ .scene .box .f-top { fill: #2a2a31; }
37
+ .scene .box .f-left { fill: #1d1d23; }
38
+ .scene .box .f-right { fill: #141418; }
39
+ .scene .ground .f-top { fill: url(#sc-floor); }
40
+ .scene .ground .f-left { fill: #131316; }
41
+ .scene .ground .f-right { fill: #0d0d10; }
42
+ .scene .pad .ground .f-top { fill: #1d1d24; }
43
+ .scene .grid-lines .grid { stroke: rgba(255, 255, 255, 0.05); stroke-width: 1; vector-effect: non-scaling-stroke; fill: none; }
44
+ .scene .rim { fill: none; stroke: rgba(255, 255, 255, 0.13); stroke-width: 1; transition: stroke 0.8s var(--ease); }
45
+ .scene .raven { fill: rgba(245, 245, 247, 0.9); }
46
+ /* Labels painted on a slanted face: world-unit sizes, a sans face and no hinting, so they stay smooth at an angle. */
47
+ .scene text { text-rendering: geometricPrecision; }
48
+ .scene .ground-label { fill: rgba(245, 245, 247, 0.5); font-family: var(--font); font-size: 0.36px; font-weight: 700; letter-spacing: 0.16em; }
49
+ .scene .shadow { fill: rgba(0, 0, 0, 0.5); filter: url(#sc-soft); }
50
+ .scene .shadow.soft { fill: rgba(0, 0, 0, 0.42); }
51
+ /* The app window. */
52
+ .scene .frame .f-top { fill: #34343d; }
53
+ .scene .frame .f-left { fill: #26262d; }
54
+ .scene .frame .f-right { fill: #1b1b21; }
55
+ .scene .win * { vector-effect: non-scaling-stroke; }
56
+ .scene .win-face { fill: #0e0e12; }
57
+ .scene .win-bar { fill: #1b1b21; }
58
+ .scene .dot { fill: rgba(255, 255, 255, 0.22); }
59
+ .scene .win-url { fill: rgba(255, 255, 255, 0.07); }
60
+ .scene .win-outline { fill: none; stroke: none; }
61
+ .scene .panel { fill: #202027; stroke: rgba(255, 255, 255, 0.12); stroke-width: 1; }
62
+ .scene .panel.added { stroke: rgba(242, 193, 95, 0.75); fill: #26221a; }
63
+ .scene .panel.modified { stroke: rgba(255, 255, 255, 0.32); }
64
+ .scene .panel-line { fill: rgba(255, 255, 255, 0.2); }
65
+ .scene .panel-name { fill: rgba(245, 245, 247, 0.78); font-family: var(--font); font-size: 0.34px; font-weight: 600; }
66
+ .scene .panel-in { animation: panel-in 0.7s var(--spring) both; }
67
+ @keyframes panel-in { from { opacity: 0; transform: translate(0, -0.9px); } }
68
+ .scene .ghost-panel { fill: none; stroke: rgba(255, 255, 255, 0.16); stroke-width: 1; stroke-dasharray: 0.02 0.015; }
69
+ .scene .ghost-panel.sketch { stroke: rgba(242, 193, 95, 0.7); stroke-width: 1.4; stroke-dasharray: 0.22 0.78; animation: sketch 2.6s linear infinite; }
70
+ .scene .ghost-panel.sketch:nth-child(2) { animation-delay: -0.9s; }
71
+ .scene .ghost-panel.sketch:nth-child(3) { animation-delay: -1.7s; }
72
+ @keyframes sketch { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
73
+ .scene .key-sign circle { fill: rgba(242, 193, 95, 0.12); stroke: var(--sc-amber); stroke-width: 1.4; }
74
+ .scene .key-sign path { fill: none; stroke: var(--sc-amber); stroke-width: 1.6; stroke-linecap: round; }
75
+ /* The agent unit. */
76
+ .scene .unit .f-top { fill: #2c2c34; }
77
+ .scene .unit .f-left { fill: #202027; }
78
+ .scene .unit .f-right { fill: #16161b; }
79
+ .scene .unit-plate { fill: #121216; stroke: rgba(255, 255, 255, 0.1); stroke-width: 1; vector-effect: non-scaling-stroke; }
80
+ .scene .unit-led { fill: rgba(255, 255, 255, 0.18); }
81
+ .scene .p-active .unit-led { fill: var(--sc-amber); animation: led 1.6s ease-in-out infinite; }
82
+ .scene .p-done .unit-led { fill: var(--sc-green); }
83
+ .scene .p-active .hover { animation: hover 3.6s ease-in-out infinite; }
84
+ @keyframes hover { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
85
+ @keyframes led { 50% { opacity: 0.35; } }
86
+ /* Posts, lamps, ports, towers, crates. */
87
+ .scene .post .f-top { fill: #2e2e36; }
88
+ .scene .post .f-left { fill: #222229; }
89
+ .scene .post .f-right { fill: #18181d; }
90
+ .scene .lamp .f-top { fill: #3a3a42; }
91
+ .scene .lamp .f-left { fill: #2b2b32; }
92
+ .scene .lamp .f-right { fill: #222228; }
93
+ .scene .p-active .lamp .f-top { fill: #f6d58a; }
94
+ .scene .p-active .lamp .f-left { fill: #c99a3f; }
95
+ .scene .p-active .lamp .f-right { fill: #a87e30; }
96
+ .scene .p-active .lamp { animation: led 1.8s ease-in-out infinite; }
97
+ .scene .p-done .lamp .f-top { fill: #9be3b1; }
98
+ .scene .p-done .lamp .f-left { fill: #57b673; }
99
+ .scene .p-done .lamp .f-right { fill: #3f8f57; }
100
+ .scene .p-failed .lamp .f-top { fill: #f8a597; }
101
+ .scene .p-failed .lamp .f-left { fill: #d35a49; }
102
+ .scene .p-failed .lamp .f-right { fill: #a9463a; }
103
+ .scene .port .f-top { fill: #2e2e36; }
104
+ .scene .port-led { fill: rgba(255, 255, 255, 0.18); }
105
+ .scene .p-done .port-led { fill: var(--sc-green); }
106
+ .scene .p-failed .port-led { fill: var(--sc-red); }
107
+ .scene .tower .f-top { fill: #303039; }
108
+ .scene .tower .f-left { fill: #23232a; }
109
+ .scene .tower .f-right { fill: #18181e; }
110
+ .scene .vent { fill: rgba(255, 255, 255, 0.07); }
111
+ .scene .tower-led { fill: rgba(255, 255, 255, 0.18); }
112
+ .scene .p-active .tower-led { fill: var(--sc-amber); animation: led 1.2s ease-in-out infinite; }
113
+ .scene .p-done .tower-led { fill: var(--sc-green); }
114
+ .scene .p-failed .tower-led { fill: var(--sc-red); }
115
+ .scene .crate .f-top { fill: #3a342a; }
116
+ .scene .crate .f-left { fill: #2b261f; }
117
+ .scene .crate .f-right { fill: #221e18; }
118
+ .scene .crate-x { stroke: rgba(255, 255, 255, 0.14); stroke-width: 1; vector-effect: non-scaling-stroke; fill: none; }
119
+ /* Database layers, gateway, barrier. */
120
+ .scene .cyl .f-left { fill: #1c1f1e; stroke: rgba(62, 207, 142, 0.18); }
121
+ .scene .cyl .f-top { fill: #262b29; stroke: rgba(62, 207, 142, 0.38); }
122
+ .scene .cyl { animation: layer-in 0.7s var(--spring) both; }
123
+ .scene .cyl.ghost { animation: none; }
124
+ .scene .cyl.ghost .f-left, .scene .cyl.ghost .f-top { fill: transparent; stroke: rgba(255, 255, 255, 0.22); stroke-dasharray: 4 5; }
125
+ @keyframes layer-in { from { opacity: 0; transform: translateY(-16px); } }
126
+ .scene .table { fill: rgba(62, 207, 142, 0.16); stroke: rgba(62, 207, 142, 0.7); stroke-width: 1; vector-effect: non-scaling-stroke; animation: panel-in 0.6s var(--spring) both; }
127
+ .scene .pillar .f-top, .scene .lintel .f-top { fill: #33333b; }
128
+ .scene .pillar .f-left, .scene .lintel .f-left { fill: #26262d; }
129
+ .scene .pillar .f-right, .scene .lintel .f-right { fill: #1b1b20; }
130
+ .scene .lintel-plate { fill: #f5f5f7; }
131
+ .scene .bar .f-top { fill: #3b3222; }
132
+ .scene .bar .f-left { fill: #2c261a; }
133
+ .scene .bar .f-right { fill: #231e15; }
134
+ .scene .bar-stripes { stroke: rgba(242, 193, 95, 0.8); stroke-width: 2; vector-effect: non-scaling-stroke; fill: none; }
135
+ /* Connections. */
136
+ .scene .pipe-base { fill: none; stroke: rgba(255, 255, 255, 0.09); stroke-width: 4; stroke-linecap: round; }
137
+ .scene .pipe { fill: none; stroke: rgba(245, 245, 247, 0.75); stroke-width: 1.8; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; }
138
+ .scene .pipe-flow { fill: none; stroke: transparent; stroke-width: 2; stroke-linecap: round; stroke-dasharray: 3 10; }
139
+ .scene .p-planned .pipe-base { stroke: rgba(255, 255, 255, 0.18); stroke-width: 1.4; stroke-dasharray: 3 5; }
140
+ .scene .p-active .pipe-base { stroke: rgba(242, 193, 95, 0.14); }
141
+ .scene .p-active .pipe-flow { stroke: var(--sc-amber); animation: flow 1.4s linear infinite; }
142
+ .scene .p-done .pipe { animation: trace 0.9s var(--ease) forwards; }
143
+ .scene .p-failed .pipe-base { stroke: rgba(244, 113, 95, 0.55); stroke-width: 2; stroke-dasharray: 4 4; }
144
+ .scene .p-idle .pipe-base { stroke: rgba(255, 255, 255, 0.07); }
145
+ @keyframes flow { to { stroke-dashoffset: -13; } }
146
+ @keyframes trace { to { stroke-dashoffset: 0; } }
147
+ /* Travellers. */
148
+ .scene .token { fill: #f5f5f7; }
149
+ .scene .token-halo { fill: rgba(245, 245, 247, 0.16); }
150
+ .scene .spark .token { fill: #fbe2a6; }
151
+ .scene .spark .token-halo { fill: rgba(242, 193, 95, 0.22); }
152
+ .scene .record .token { fill: #7fe0b0; }
153
+ .scene .record .token-halo { fill: rgba(62, 207, 142, 0.22); }
154
+ .scene .blocked .token, .scene .leak .token { fill: #f8a597; }
155
+ .scene .blocked .token-halo, .scene .leak .token-halo { fill: rgba(244, 113, 95, 0.22); }
156
+ .scene .package .token { fill: #f5f5f7; }
157
+ /* Labels pinned to the world. */
158
+ .scene .tag rect { fill: rgba(12, 12, 15, 0.94); stroke: rgba(255, 255, 255, 0.14); stroke-width: 1; }
159
+ .scene .tag text { fill: #d9d9df; font-family: var(--font); font-size: 9.5px; font-weight: 600; }
160
+ .scene .p-done .tag-check rect, .scene .p-done .tag-port rect { stroke: rgba(111, 208, 140, 0.55); }
161
+ .scene .p-done .tag-check text, .scene .p-done .tag-port text { fill: var(--sc-green); }
162
+ .scene .p-failed .tag-check rect { stroke: rgba(244, 113, 95, 0.6); }
163
+ .scene .p-failed .tag-check text { fill: var(--red-ink); }
164
+ .scene .p-active .tag-check rect { stroke: rgba(242, 193, 95, 0.6); }
165
+ /* Part states. */
166
+ .scene .part { outline: none; cursor: pointer; }
167
+ .scene .part.p-planned .f-top, .scene .part.p-planned .f-left, .scene .part.p-planned .f-right { fill-opacity: 0.06; stroke: rgba(255, 255, 255, 0.28); stroke-width: 1; stroke-dasharray: 600; stroke-dashoffset: 600; animation: trace 1.2s var(--ease) forwards; }
168
+ .scene .part.p-planned .win-face, .scene .part.p-planned .win-bar, .scene .part.p-planned image, .scene .part.p-planned .raven { opacity: 0.25; }
169
+ .scene .part.p-planned .shadow { opacity: 0.3; }
170
+ .scene .part.p-idle { opacity: 0.55; }
171
+ .scene .part.p-done { animation: settle-part 0.6s var(--spring) both; }
172
+ @keyframes settle-part { from { transform: translateY(-6px); } }
173
+ .scene .part.p-failed .f-top { fill: #3c1f1c; stroke: rgba(244, 113, 95, 0.75); }
174
+ .scene .part.p-failed .f-left { fill: #2c1715; stroke: rgba(244, 113, 95, 0.5); }
175
+ .scene .part.p-failed .f-right { fill: #211211; stroke: rgba(244, 113, 95, 0.4); }
176
+ .scene .part.p-failed .win-face { fill: #1a0f0e; }
177
+ .scene .part.p-waiting .f-top, .scene .part.p-waiting .f-left, .scene .part.p-waiting .f-right { stroke: rgba(242, 193, 95, 0.8); stroke-dasharray: 5 4; }
178
+ .scene .part.p-waiting .win-face { fill: #17140c; }
179
+ .scene .part.is-focus { filter: drop-shadow(0 0 10px rgba(242, 193, 95, 0.22)); }
180
+ .scene .part.is-focus.p-active .frame .f-top { fill: #3b3a33; }
181
+ .scene .part.is-selected .f-top, .scene .part.is-selected .f-left, .scene .part.is-selected .f-right { stroke: rgba(245, 245, 247, 0.85); stroke-width: 1.4; }
182
+ .scene .part:focus-visible .f-top, .scene .part:focus-visible .f-left, .scene .part:focus-visible .f-right { stroke: var(--sc-amber); stroke-width: 2; }
183
+ .scene .part:hover .f-top { stroke: rgba(255, 255, 255, 0.35); }
184
+ /* Phases: a waiting scene holds still around the part that needs you; a failed one marks it. */
185
+ .scene.is-wait .part:not(.p-waiting):not([data-part="platform"]) { opacity: 0.5; transition: opacity 0.5s var(--ease); }
186
+ .scene.is-wait .pipe-flow, .scene.is-wait .hover, .scene.is-wait .sketch, .scene.is-wait .token-g { animation-play-state: paused; }
187
+ .scene.is-fail .part:not(.p-failed):not([data-part="platform"]) { opacity: 0.7; }
188
+ .scene.is-done [data-part="platform"] .rim { stroke: rgba(111, 208, 140, 0.5); }
189
+ .scene.is-stopped .part { opacity: 0.6; }
190
+ .scene .fx-payoff .ring { fill: none; stroke: rgba(111, 208, 140, 0.55); stroke-width: 1.5; transform-box: fill-box; transform-origin: center; animation: payoff 1.6s cubic-bezier(0.2, 0.7, 0.2, 1) forwards; }
191
+ .scene .fx-payoff .ring.two { stroke: rgba(245, 245, 247, 0.35); animation-delay: 0.22s; }
192
+ @keyframes payoff { from { opacity: 0.9; transform: scale(0.35); } to { opacity: 0; transform: scale(1.15); } }
193
+ .scene.is-demo .tag rect { stroke-dasharray: 3 3; }
194
+ @media (prefers-reduced-motion: reduce) {
195
+ .scene *, .scene .part, .scene-caption, .scene-inspect { animation: none !important; transition: none !important; }
196
+ .scene .p-done .pipe { stroke-dashoffset: 0; }
197
+ .scene .part.p-planned .f-top, .scene .part.p-planned .f-left, .scene .part.p-planned .f-right { stroke-dashoffset: 0; }
198
+ .scene .p-active .pipe-flow { stroke-dasharray: none; }
199
+ .scene .fx-payoff { display: none; }
200
+ }
201
+ .scene .box .f-top { fill: #3c3c46; }
202
+ .scene .box .f-left { fill: #2b2b33; }
203
+ .scene .box .f-right { fill: #1f1f26; }
204
+ .scene .edge { fill: none; stroke: rgba(255, 255, 255, 0.26); stroke-width: 1; stroke-linecap: round; }
205
+ .scene .ground .f-top { fill: #202027; }
206
+ .scene .ground .f-left { fill: #18181d; }
207
+ .scene .ground .f-right { fill: #111115; }
208
+ .scene .ground .edge { stroke: rgba(255, 255, 255, 0.16); }
209
+ .scene .grid-lines .grid { stroke: rgba(255, 255, 255, 0.06); }
210
+ .scene .frame .f-top { fill: #4b4b56; }
211
+ .scene .frame .f-left { fill: #35353e; }
212
+ .scene .frame .f-right { fill: #27272e; }
213
+ .scene .unit .f-top { fill: #44444e; }
214
+ .scene .unit .f-left { fill: #31313a; }
215
+ .scene .unit .f-right { fill: #24242b; }
216
+ .scene .post .f-top { fill: #42424c; }
217
+ .scene .post .f-left { fill: #30303a; }
218
+ .scene .post .f-right { fill: #23232a; }
219
+ .scene .lamp .f-top { fill: #55555f; }
220
+ .scene .lamp .f-left { fill: #3e3e47; }
221
+ .scene .lamp .f-right { fill: #2f2f37; }
222
+ .scene .tower .f-top { fill: #45454f; }
223
+ .scene .tower .f-left { fill: #32323b; }
224
+ .scene .tower .f-right { fill: #25252c; }
225
+ .scene .pillar .f-top, .scene .lintel .f-top { fill: #474752; }
226
+ .scene .pillar .f-left, .scene .lintel .f-left { fill: #34343d; }
227
+ .scene .pillar .f-right, .scene .lintel .f-right { fill: #26262e; }
228
+ .scene .crate .f-top { fill: #4a4133; }
229
+ .scene .crate .f-left { fill: #383126; }
230
+ .scene .crate .f-right { fill: #2b261e; }
231
+ .scene .port .f-top { fill: #42424c; }
232
+ .scene .cyl .f-left { fill: #232826; }
233
+ .scene .cyl .f-top { fill: #303733; }
234
+ .scene .part.p-planned .edge { stroke: none; }
235
+ .scene .part.p-failed .edge { stroke: rgba(244, 113, 95, 0.6); }
236
+ .scene .part.p-done .edge { stroke: rgba(255, 255, 255, 0.34); }
237
+ .scene-stage::before { content: ""; position: absolute; left: 10%; right: 10%; top: 22%; bottom: 18%; border-radius: 50%; background: radial-gradient(closest-side, rgba(255, 255, 255, 0.045), transparent); pointer-events: none; }
238
+ /* ---------- units and brands: every object is a machined unit with its mark; providers wear their own colours ---------- */
239
+ .scene .unit .f-top { fill: #41414b; }
240
+ .scene .unit .f-left { fill: #2e2e36; }
241
+ .scene .unit .f-right { fill: #222229; }
242
+ .scene .pedestal .f-top { fill: #2a2a31; }
243
+ .scene .pedestal .f-left { fill: #1e1e24; }
244
+ .scene .pedestal .f-right { fill: #16161b; }
245
+ .scene .unit-ring { fill: none; stroke: var(--brand); stroke-opacity: 0.55; stroke-width: 1.3; vector-effect: non-scaling-stroke; transition: stroke 0.4s var(--ease), stroke-opacity 0.4s var(--ease); }
246
+ .scene .unit-led { fill: var(--brand); fill-opacity: 0.35; }
247
+ .scene .p-planned .unit-ring { stroke-opacity: 0.15; }
248
+ .scene .p-active .unit-ring { stroke: var(--sc-amber); stroke-opacity: 0.95; }
249
+ .scene .p-active .unit-led { fill: var(--sc-amber); fill-opacity: 1; animation: led 1.6s ease-in-out infinite; }
250
+ .scene .p-done .unit-ring { stroke: var(--sc-green); stroke-opacity: 0.9; }
251
+ .scene .p-done .unit-led { fill: var(--sc-green); fill-opacity: 1; }
252
+ .scene .p-failed .unit-ring { stroke: var(--sc-red); stroke-opacity: 0.95; }
253
+ .scene .p-failed .unit-led { fill: var(--sc-red); fill-opacity: 1; }
254
+ .scene .p-waiting .unit-ring { stroke: var(--sc-amber); stroke-dasharray: 4 3; }
255
+ .scene .p-waiting .unit-led { fill: var(--sc-amber); fill-opacity: 1; }
256
+ .scene .p-done .unit-wrap .edge, .scene .p-active .unit-wrap .edge { stroke: rgba(255, 255, 255, 0.4); }
257
+ /* Supabase: green seams between layers, the bolt on a dark badge. */
258
+ .scene .brand-supabase .cyl .f-top { fill: #2c3530; stroke: rgba(62, 207, 142, 0.55); }
259
+ .scene .brand-supabase .cyl .f-left { fill: #1f2522; stroke: rgba(62, 207, 142, 0.22); }
260
+ .scene .seam { fill: none; stroke: var(--brand); stroke-opacity: 0.7; stroke-width: 1.4; stroke-linecap: round; filter: url(#sc-glow); }
261
+ .scene .p-active .seam { animation: led 1.8s ease-in-out infinite; }
262
+ .scene .brand-badge { fill: #0f1512; stroke: rgba(62, 207, 142, 0.6); stroke-width: 1; vector-effect: non-scaling-stroke; }
263
+ /* Google: coloured caps on the pillars, four lights by the G. */
264
+ .scene .cap.g-blue .f-top { fill: #4285F4; }
265
+ .scene .cap.g-blue .f-left { fill: #3367c7; }
266
+ .scene .cap.g-blue .f-right { fill: #2a55a6; }
267
+ .scene .cap.g-green .f-top { fill: #34A853; }
268
+ .scene .cap.g-green .f-left { fill: #2b8a45; }
269
+ .scene .cap.g-green .f-right { fill: #237038; }
270
+ .scene .brand-google .lintel .f-top { fill: #4a4a55; }
271
+ .scene .lintel-plate { fill: #f5f5f7; }
272
+ .scene .gdot { opacity: 0.85; }
273
+ .scene .p-active .gdot { animation: led 1.4s ease-in-out infinite; }
274
+ .scene .p-planned .cap .f-top, .scene .p-planned .cap .f-left, .scene .p-planned .cap .f-right { fill-opacity: 0.08; }
275
+ /* GitHub: a dark vault with a commit graph. */
276
+ .scene .vault .f-top { fill: #2d333b; }
277
+ .scene .vault .f-left { fill: #22272e; }
278
+ .scene .vault .f-right { fill: #1c2128; }
279
+ .scene .gitgraph path { fill: none; stroke: rgba(240, 246, 252, 0.7); stroke-width: 1.4; vector-effect: non-scaling-stroke; }
280
+ .scene .gitgraph .branch { stroke: #3fb950; }
281
+ .scene .gitgraph circle { fill: #0d1117; stroke: rgba(240, 246, 252, 0.85); stroke-width: 1.3; vector-effect: non-scaling-stroke; }
282
+ .scene .gitgraph .branch-dot { stroke: #3fb950; }
283
+ .scene .gitgraph .tip { fill: #f5f5f7; }
284
+ .scene .p-active .gitgraph .tip { animation: led 1.4s ease-in-out infinite; }
285
+ /* Vercel: a black pad and the white triangle. */
286
+ .scene .brand-vercel .ground .f-top { fill: #0c0c0e; }
287
+ .scene .brand-vercel .ground .f-left { fill: #08080a; }
288
+ .scene .brand-vercel .ground .f-right { fill: #050506; }
289
+ .scene .brand-vercel .ground .edge { stroke: rgba(245, 245, 247, 0.35); }
290
+ .scene .pyramid .f-left { fill: #f5f5f7; stroke: rgba(255, 255, 255, 0.4); stroke-width: 0.8; }
291
+ .scene .pyramid .f-right { fill: #b4b4bc; stroke: rgba(255, 255, 255, 0.25); stroke-width: 0.8; }
292
+ .scene .pyramid .edge { fill: none; stroke: #ffffff; stroke-width: 1.2; }
293
+ .scene .part.p-planned .pyramid .f-left, .scene .part.p-planned .pyramid .f-right { fill-opacity: 0.06; stroke: rgba(255, 255, 255, 0.3); }
294
+ .scene .part.p-failed .pyramid .f-left { fill: #f2b3a9; }
295
+ /* npm's command unit and the framework plate on the dev server. */
296
+ .scene .unit-wrap .shadow { opacity: 0.9; }
297
+ @media (prefers-reduced-motion: reduce) {
298
+ .scene .seam, .scene .gdot, .scene .gitgraph .tip { animation: none !important; }
299
+ }
300
+ .scene .sign .f-top { fill: #4a4a55; }
301
+ .scene .sign .f-left { fill: #3a3a44; }
302
+ .scene .sign .f-right { fill: #2a2a32; }
303
+ /* Mascots: a provider's mark walks, rolls or hops along the connection while that step works. */
304
+ .scene .walker-shadow { fill: rgba(0, 0, 0, 0.45); }
305
+ .scene .walker-body { transform-box: fill-box; transform-origin: 50% 100%; }
306
+ .scene .walker.is-walk .walker-body { animation: waddle 0.42s ease-in-out infinite alternate; }
307
+ .scene .walker.is-hop .walker-body { animation: hop 0.6s cubic-bezier(0.3, 0, 0.4, 1) infinite; }
308
+ .scene .walker.is-roll .walker-body { transform-origin: 50% 50%; animation: roll 0.9s linear infinite; }
309
+ .scene .walker image { filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.6)); }
310
+ @keyframes waddle { from { transform: translateY(0) rotate(-7deg); } to { transform: translateY(-3px) rotate(7deg); } }
311
+ @keyframes hop { 0%, 100% { transform: translateY(0) scale(1.08, 0.9); } 45% { transform: translateY(-9px) scale(0.95, 1.06); } 70% { transform: translateY(-2px) scale(1, 1); } }
312
+ @keyframes roll { to { transform: rotate(360deg); } }
313
+ .scene.is-wait .walker { display: none; }
314
+ @media (prefers-reduced-motion: reduce) { .scene .walker { display: none; } }
315
+ /* ---------- characters and hype ---------- */
316
+ /* Claude Code's voxel critter. */
317
+ .scene .cc .f-top { fill: #eda186; }
318
+ .scene .cc .f-left { fill: #D97757; }
319
+ .scene .cc .f-right { fill: #b05a3e; }
320
+ .scene .cc .edge { stroke: rgba(255, 220, 200, 0.55); }
321
+ .scene .cc-eye { fill: #1b0f0a; }
322
+ .scene .critter .cc-torso, .scene .critter .cc-legs { transform-box: fill-box; transform-origin: 50% 100%; }
323
+ .scene .p-active .critter .cc-torso, .scene .critter.is-busy .cc-torso { animation: chomp 0.1s ease-in-out infinite alternate; }
324
+ .scene .p-active .critter .cc-legs.a, .scene .critter.is-busy .cc-legs.a { animation: step 0.1s ease-in-out infinite alternate; }
325
+ .scene .p-active .critter .cc-legs.b, .scene .critter.is-busy .cc-legs.b { animation: step 0.1s ease-in-out infinite alternate-reverse; }
326
+ .scene .p-done .critter { animation: happy 0.5s var(--spring) 2 alternate; transform-box: fill-box; transform-origin: 50% 100%; }
327
+ .scene .p-planned .critter .f-top, .scene .p-planned .critter .f-left, .scene .p-planned .critter .f-right { fill-opacity: 0.12; stroke: rgba(217, 119, 87, 0.5); stroke-dasharray: none; stroke-dashoffset: 0; animation: none; }
328
+ @keyframes chomp { from { transform: scale(1, 1); } to { transform: scale(1.06, 0.9); } }
329
+ @keyframes step { from { transform: translateY(0); } to { transform: translateY(-3px); } }
330
+ @keyframes happy { to { transform: translateY(-8px) scale(1.04); } }
331
+ .scene .tok rect { fill: #fbe2a6; stroke: #f2c15f; stroke-width: 1; filter: drop-shadow(0 0 4px rgba(242, 193, 95, 0.8)); }
332
+ /* Supabase lightning. */
333
+ .scene .zap { opacity: 0; animation: strike 1.65s linear infinite; }
334
+ .scene .zap-glow { fill: none; stroke: #3ECF8E; stroke-width: 10; stroke-opacity: 0.35; stroke-linejoin: round; filter: url(#sc-glow); }
335
+ .scene .zap-core { fill: none; stroke: #d9ffe9; stroke-width: 2.6; stroke-linejoin: round; stroke-linecap: round; }
336
+ .scene .zap-core.thin { stroke-width: 1.6; stroke: #8ff0c2; }
337
+ .scene .zap-hit { fill: rgba(62, 207, 142, 0.45); filter: url(#sc-glow); }
338
+ .scene .zap-spark { stroke: #b6ffd9; stroke-width: 2; stroke-linecap: round; }
339
+ @keyframes strike { 0% { opacity: 0; } 3% { opacity: 1; } 7% { opacity: 0.25; } 11% { opacity: 1; } 24% { opacity: 0; } 100% { opacity: 0; } }
340
+ /* PostHog: hedgehog, events, bars. */
341
+ .scene .ph-body .f-top { fill: #8b5e3c; }
342
+ .scene .ph-body .f-left { fill: #6e4930; }
343
+ .scene .ph-body .f-right { fill: #573925; }
344
+ .scene .ph-head .f-top { fill: #c9926a; }
345
+ .scene .ph-head .f-left { fill: #a97750; }
346
+ .scene .ph-head .f-right { fill: #8d6141; }
347
+ .scene .ph-nose .f-top, .scene .ph-nose .f-left, .scene .ph-nose .f-right { fill: #1d1f27; }
348
+ .scene .ph-leg .f-top, .scene .ph-leg .f-left, .scene .ph-leg .f-right { fill: #4a3020; }
349
+ .scene .ph-eye { fill: #111; }
350
+ .scene .ph-spike.c0 .f-top { fill: #F54E00; }
351
+ .scene .ph-spike.c0 .f-left { fill: #c43e00; }
352
+ .scene .ph-spike.c0 .f-right { fill: #9a3100; }
353
+ .scene .ph-spike.c1 .f-top { fill: #F9BD2B; }
354
+ .scene .ph-spike.c1 .f-left { fill: #d39c17; }
355
+ .scene .ph-spike.c1 .f-right { fill: #a87b10; }
356
+ .scene .ph-spike.c2 .f-top { fill: #3b63ff; }
357
+ .scene .ph-spike.c2 .f-left { fill: #1D4AFF; }
358
+ .scene .ph-spike.c2 .f-right { fill: #1538c4; }
359
+ .scene .ph-bar.c0 .f-top { fill: #F54E00; }
360
+ .scene .ph-bar.c0 .f-left { fill: #c43e00; }
361
+ .scene .ph-bar.c0 .f-right { fill: #9a3100; }
362
+ .scene .ph-bar.c1 .f-top { fill: #F9BD2B; }
363
+ .scene .ph-bar.c1 .f-left { fill: #d39c17; }
364
+ .scene .ph-bar.c1 .f-right { fill: #a87b10; }
365
+ .scene .ph-bar.c2 .f-top { fill: #3b63ff; }
366
+ .scene .ph-bar.c2 .f-left { fill: #1D4AFF; }
367
+ .scene .ph-bar.c2 .f-right { fill: #1538c4; }
368
+ .scene .hedgehog .ph-legs { transform-box: fill-box; }
369
+ .scene .p-active .hedgehog .ph-legs.a { animation: step 0.16s ease-in-out infinite alternate; }
370
+ .scene .p-active .hedgehog .ph-legs.b { animation: step 0.16s ease-in-out infinite alternate-reverse; }
371
+ .scene .p-planned .hedgehog, .scene .p-idle .hedgehog { opacity: 0.35; }
372
+ .scene .bar-g { transform-box: fill-box; transform-origin: 50% 100%; animation: pump 0.7s ease-in-out infinite alternate; }
373
+ @keyframes pump { from { transform: scaleY(0.35); } to { transform: scaleY(1); } }
374
+ .scene .evt.c0 { fill: #F54E00; }
375
+ .scene .evt.c1 { fill: #F9BD2B; }
376
+ .scene .evt.c2 { fill: #3b63ff; }
377
+ .scene .evt { filter: drop-shadow(0 0 3px rgba(255, 255, 255, 0.35)); }
378
+ /* GitHub commits, Vercel launch, Google orbit. */
379
+ .scene .commit .token { fill: #3fb950; }
380
+ .scene .commit .token-halo { fill: rgba(63, 185, 80, 0.25); }
381
+ .scene .ring-launch { fill: none; stroke: #f5f5f7; stroke-width: 2; transform-box: fill-box; transform-origin: center; animation: launch 1.2s cubic-bezier(0.2, 0.6, 0.2, 1) infinite; }
382
+ @keyframes launch { from { opacity: 0.9; transform: translateY(0) scale(0.4); } to { opacity: 0; transform: translateY(-46px) scale(1.5); } }
383
+ .scene .speed { stroke: rgba(245, 245, 247, 0.55); stroke-width: 1.6; stroke-linecap: round; stroke-dasharray: 8 14; animation: speed 0.45s linear infinite; }
384
+ @keyframes speed { to { stroke-dashoffset: 22; } }
385
+ .scene .orbit-spin { animation: orbit 1.1s linear infinite; transform-origin: 0 0; }
386
+ .scene .orbit circle { filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.35)); }
387
+ @keyframes orbit { to { transform: rotate(360deg); } }
388
+ .scene.is-wait .hype, .scene.is-wait .critter * { animation-play-state: paused; }
389
+ @media (prefers-reduced-motion: reduce) { .scene .hype, .scene .tok { display: none; } .scene .critter * { animation: none !important; } }
390
+ /* ---------- premium kit: solid emblems, plinths, gateway doors, insight card, travelling payloads ---------- */
391
+ .scene .emb-side { filter: brightness(0.34) saturate(0.85); }
392
+ .scene .emb-face { filter: drop-shadow(0 0 0.02px rgba(0, 0, 0, 0)); }
393
+ .scene .emb-sheen { fill: url(#sc-sheen); mix-blend-mode: screen; }
394
+ .scene .emb-float { transform-box: fill-box; }
395
+ .scene .p-active .emb-float { animation: hover 3.8s ease-in-out infinite; }
396
+ .scene .p-done .emb-float { animation: settle-part 0.7s var(--spring) both; }
397
+ .scene .part.p-planned .emblem, .scene .part.p-idle .emblem { opacity: 0.28; }
398
+ .scene .part.p-planned .emb-sheen { display: none; }
399
+ .scene .plinth .f-top { fill: #3a3a44; }
400
+ .scene .plinth .f-left { fill: #2a2a31; }
401
+ .scene .plinth .f-right { fill: #1f1f25; }
402
+ .scene .emblem-unit .plinth .edge { stroke: var(--brand); stroke-opacity: 0.55; }
403
+ .scene .door .f-top { fill: #52525e; }
404
+ .scene .door .f-left { fill: #3c3c46; }
405
+ .scene .door .f-right { fill: #2e2e36; }
406
+ .scene .door.google .f-left { fill: #2f3f5e; }
407
+ .scene .door.github .f-left { fill: #2d333b; }
408
+ .scene .door .edge { stroke: rgba(255, 255, 255, 0.35); }
409
+ .scene .cap.g-dark .f-top { fill: #2d333b; }
410
+ .scene .cap.g-dark .f-left { fill: #22272e; }
411
+ .scene .cap.g-dark .f-right { fill: #1c2128; }
412
+ .scene .cap.g-light .f-top { fill: #f0f6fc; }
413
+ .scene .cap.g-light .f-left { fill: #c9d1d9; }
414
+ .scene .cap.g-light .f-right { fill: #a0a8b0; }
415
+ .scene .brand-github .lintel .f-top { fill: #2d333b; }
416
+ .scene .brand-github .lintel .f-left { fill: #22272e; }
417
+ .scene .brand-github .lintel .f-right { fill: #1c2128; }
418
+ .scene .insight .card .f-top { fill: #3a3a44; }
419
+ .scene .insight .card .f-left { fill: #26262d; }
420
+ .scene .insight .card .f-right { fill: #1b1b21; }
421
+ .scene .insight .stand .f-top { fill: #2e2e36; }
422
+ .scene .insight .stand .f-left { fill: #22222a; }
423
+ .scene .insight .stand .f-right { fill: #18181d; }
424
+ .scene .ins-bg { fill: #0f0f13; }
425
+ .scene .ins-title { fill: rgba(255, 255, 255, 0.25); }
426
+ .scene .ins-grid { fill: none; stroke: rgba(255, 255, 255, 0.07); stroke-width: 1; vector-effect: non-scaling-stroke; }
427
+ .scene .ins-line { fill: none; stroke: #F9BD2B; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
428
+ .scene .ins-dot { fill: #F54E00; }
429
+ .scene .pl { filter: drop-shadow(0 6px 4px rgba(0, 0, 0, 0.55)); }
430
+ @media (prefers-reduced-motion: reduce) { .scene .emb-float { animation: none !important; } .scene .emb-sheen { display: none; } }
431
+ /* ---------- mascots: GitHub's Octocat, PostHog's hedgehog, Claude polishing ---------- */
432
+ .scene .oc .f-top { fill: #3d444d; }
433
+ .scene .oc .f-left { fill: #2b3137; }
434
+ .scene .oc .f-right { fill: #1c2127; }
435
+ .scene .oc .edge { stroke: rgba(240, 246, 252, 0.4); }
436
+ .scene .oc-face { fill: #f6c8b3; }
437
+ .scene .oc-eye { fill: #1c2127; }
438
+ .scene .oc-shine { fill: #fff; }
439
+ .scene .oc-mouth { fill: #a5524a; }
440
+ .scene .octocat .oc-tent { transform-box: fill-box; transform-origin: 50% 0; animation: wiggle 0.24s ease-in-out infinite alternate; }
441
+ .scene .octocat .oc-tent.t1 { animation-direction: alternate-reverse; }
442
+ @keyframes wiggle { from { transform: rotate(-6deg); } to { transform: rotate(6deg); } }
443
+ .scene .mx-body .f-top { fill: #e0b07a; }
444
+ .scene .mx-body .f-left { fill: #c49360; }
445
+ .scene .mx-body .f-right { fill: #a47746; }
446
+ .scene .mx-face .f-top { fill: #f0cfa2; }
447
+ .scene .mx-face .f-left { fill: #ddb684; }
448
+ .scene .mx-face .f-right { fill: #bf9564; }
449
+ .scene .mx-spike .f-top { fill: #4a3524; }
450
+ .scene .mx-spike .f-left { fill: #35251a; }
451
+ .scene .mx-spike .f-right { fill: #251912; }
452
+ .scene .mx-leg .f-top, .scene .mx-leg .f-left, .scene .mx-leg .f-right { fill: #6b4a2e; }
453
+ .scene .mx-nose .f-top, .scene .mx-nose .f-left, .scene .mx-nose .f-right { fill: #15161b; }
454
+ .scene .mx-eye { fill: #15161b; }
455
+ .scene .mx-cheek { fill: #f08a6b; opacity: 0.8; }
456
+ .scene .mx-pole .f-top { fill: #c8c8d0; }
457
+ .scene .mx-pole .f-left { fill: #9a9aa5; }
458
+ .scene .mx-pole .f-right { fill: #74747e; }
459
+ .scene .mx-flag { stroke: rgba(255, 255, 255, 0.25); stroke-width: 0.6; }
460
+ .scene .flag-text { fill: #fff; font: 800 0.26px/1 var(--font-sans, system-ui); letter-spacing: 0.02px; }
461
+ .scene .mx-pole .edge, .scene .mx-body .edge, .scene .mx-face .edge, .scene .mx-spike .edge, .scene .mx-leg .edge, .scene .mx-nose .edge { stroke: rgba(255, 240, 220, 0.3); }
462
+ .scene .sparkle { fill: #fff; filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.9)); }
463
+ .scene .burst { fill: rgba(137, 87, 229, 0.35); stroke: #c9b3ff; stroke-width: 2; }
464
+ .scene .say { fill: #8957e5; stroke: rgba(255, 255, 255, 0.5); stroke-width: 1; }
465
+ .scene .say-text { fill: #fff; font: 800 11px/1 var(--font-sans, system-ui); letter-spacing: 0.02em; }
466
+ @media (prefers-reduced-motion: reduce) { .scene .skit { display: none; } }
467
+ .scene .mx-belly { fill: #f7e3c4; }
468
+ .scene .mx-snout .f-top { fill: #f7e3c4; }
469
+ .scene .mx-snout .f-left { fill: #e6cba6; }
470
+ .scene .mx-snout .f-right { fill: #c9ab84; }
471
+ .scene .mx-brow { fill: #4a2a16; }
472
+ .scene .mx-hat .f-top { fill: #ffd25a; }
473
+ .scene .mx-hat .f-left { fill: #F9BD2B; }
474
+ .scene .mx-hat .f-right { fill: #c9921a; }
475
+ .scene .mx-hat-ridge .f-top, .scene .mx-hat-ridge .f-left, .scene .mx-hat-ridge .f-right { fill: #e0a51f; }
476
+ .scene .mx-hat .edge, .scene .mx-snout .edge { stroke: rgba(255, 245, 220, 0.45); }
477
+ .scene .smudge { fill: rgba(214, 206, 192, 0.3); filter: blur(0.05px); }
478
+ .scene .smudge .streak { fill: none; stroke: rgba(214, 206, 192, 0.35); stroke-width: 0.07; stroke-linecap: round; }
479
+ .scene .bubble { fill: rgba(220, 240, 255, 0.18); stroke: rgba(235, 248, 255, 0.85); stroke-width: 1; }
480
+ .scene .foam { fill: rgba(250, 252, 255, 0.85); }
481
+
482
+ /* Shared with stack.css, copied so this file stands alone. */
483
+ @keyframes pulse-dot { 50% { opacity: 0.3; } }
484
+ @keyframes settle { from { transform: translateY(4px); } to { transform: none; } }
@@ -1262,42 +1262,13 @@ select.sel:focus, input.sel:focus { outline: none; box-shadow: inset 0 0 0 1px #
1262
1262
  .app .board.has-screen.is-side { grid-template-columns: minmax(250px, 320px) minmax(0, 250px); column-gap: clamp(32px, 7cqi, 56px); }
1263
1263
  }
1264
1264
 
1265
- /* ---------- the construction scene: a small isometric world for the action in progress ----------
1266
- Planned parts are traced outlines; a part works while its step is active; it settles solid only when its
1267
- evidence arrives. Activity is calm (slow flows, a gentle hover); milestones get one short spring. */
1268
- :root {
1269
- --spring: cubic-bezier(0.34, 1.45, 0.64, 1);
1270
- --sc-amber: #f2c15f;
1271
- --sc-green: #6fd08c;
1272
- --sc-red: #f4715f;
1273
- }
1274
-
1275
1265
  /* Layout: the scene takes the canvas, the panel narrows, the real app gets its own window. */
1276
1266
  .stage.is-work.has-panel .canvas { right: min(440px, 36%); }
1277
1267
  .stage.is-work .stage-body.panel { width: calc(min(440px, 36%) - 28px); }
1278
1268
  .app:has(.stage.is-work) .rail { left: calc((100% - min(440px, 36%)) / 2); }
1279
1269
  .app:has(.stage.is-work) .appwin { right: min(440px, 36vw); }
1280
1270
  .canvas.is-scene { display: grid; grid-template-columns: minmax(0, 1fr) 290px; grid-template-rows: minmax(0, 1fr); align-items: stretch; place-items: stretch; gap: 16px; padding: 18px 18px 84px; cursor: default; overflow: hidden; background: radial-gradient(1200px 600px at 40% 30%, rgba(242, 193, 95, 0.035), transparent 60%), radial-gradient(rgba(255, 255, 255, 0.07) 1px, transparent 1.2px) 0 0 / 22px 22px, #060607; }
1281
- .scene-stage { position: relative; display: grid; grid-template-rows: auto minmax(0, 1fr) auto; min-width: 0; min-height: 0; }
1282
- .scene-head { display: flex; align-items: center; gap: 12px; min-width: 0; }
1283
- .scene-tag { display: inline-flex; align-items: center; height: 24px; padding: 0 10px; border-radius: 999px; border: 1px solid rgba(242, 193, 95, 0.45); color: var(--sc-amber); font-size: 11.5px; font-weight: 600; letter-spacing: 0.02em; white-space: nowrap; }
1284
- .scene-tag.is-demo { border-style: dashed; border-color: rgba(255, 255, 255, 0.35); color: var(--ink-2); }
1285
- .scene-note { font-size: 12.5px; color: var(--ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1286
- .scene { display: block; width: 100%; height: 100%; min-height: 0; overflow: visible; }
1287
- .scene-caption { justify-self: center; display: inline-flex; align-items: center; gap: 10px; max-width: 100%; min-height: 36px; padding: 8px 16px; border-radius: 999px; border: 1px solid var(--line-2); background: rgba(14, 14, 17, 0.94); font-size: 13.5px; color: var(--ink); animation: settle 0.4s var(--ease) both; }
1288
- .scene-caption > span:first-of-type { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1289
- .scene-caption i { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--ink-3); }
1290
- .scene-caption.is-work i { background: var(--sc-amber); animation: pulse-dot 1.4s ease-in-out infinite; }
1291
- .scene-caption.is-wait { border-color: rgba(242, 193, 95, 0.5); }
1292
- .scene-caption.is-wait i { background: var(--sc-amber); }
1293
- .scene-caption.is-pass i { background: var(--sc-green); }
1294
- .scene-caption.is-fail { border-color: rgba(244, 113, 95, 0.45); }
1295
- .scene-caption.is-fail i { background: var(--sc-red); }
1296
- .scene-when { font-size: 12px; color: var(--ink-3); }
1297
- .scene-inspect { position: absolute; left: 0; bottom: 52px; z-index: 2; width: min(320px, 70%); display: grid; gap: 8px; padding: 14px 16px; border-radius: 14px; border: 1px solid var(--line-2); background: rgba(12, 12, 15, 0.97); box-shadow: 0 24px 50px -20px rgba(0, 0, 0, 0.9); animation: settle 0.3s var(--ease) both; }
1298
- .scene-inspect header { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
1299
- .scene-inspect strong { font-size: 14px; font-weight: 600; }
1300
- .scene-inspect p { font-size: 12.5px; line-height: 1.5; color: var(--ink-2); }
1271
+
1301
1272
  .insp-state { font-size: 11.5px; color: var(--ink-3); white-space: nowrap; }
1302
1273
  .insp-state.is-done { color: var(--sc-green); } .insp-state.is-active, .insp-state.is-waiting { color: var(--sc-amber); } .insp-state.is-failed { color: var(--red-ink); }
1303
1274
  .insp-files { list-style: none; display: grid; gap: 3px; }
@@ -1316,147 +1287,31 @@ select.sel:focus, input.sel:focus { outline: none; box-shadow: inset 0 0 0 1px #
1316
1287
  .live-window header span { font-size: 11.5px; color: var(--ink-3); }
1317
1288
  .live-window .screen { margin-top: 0; }
1318
1289
 
1319
- /* Faces. */
1320
- .scene polygon, .scene path, .scene ellipse, .scene rect { stroke-linejoin: round; }
1321
- .scene .f-top, .scene .f-left, .scene .f-right { stroke: rgba(255, 255, 255, 0.07); stroke-width: 0.8; transition: fill 0.45s var(--ease), stroke 0.45s var(--ease), fill-opacity 0.45s var(--ease); }
1322
- .scene .box .f-top { fill: #2a2a31; } .scene .box .f-left { fill: #1d1d23; } .scene .box .f-right { fill: #141418; }
1323
- .scene .ground .f-top { fill: url(#sc-floor); } .scene .ground .f-left { fill: #131316; } .scene .ground .f-right { fill: #0d0d10; }
1324
- .scene .pad .ground .f-top { fill: #1d1d24; }
1325
- .scene .grid-lines .grid { stroke: rgba(255, 255, 255, 0.05); stroke-width: 1; vector-effect: non-scaling-stroke; fill: none; }
1326
- .scene .rim { fill: none; stroke: rgba(255, 255, 255, 0.13); stroke-width: 1; transition: stroke 0.8s var(--ease); }
1327
- .scene .raven { fill: rgba(245, 245, 247, 0.9); }
1328
- /* Labels painted on a slanted face: world-unit sizes, a sans face and no hinting, so they stay smooth at an angle. */
1329
- .scene text { text-rendering: geometricPrecision; }
1330
- .scene .ground-label { fill: rgba(245, 245, 247, 0.5); font-family: var(--font); font-size: 0.36px; font-weight: 700; letter-spacing: 0.16em; }
1331
- .scene .shadow { fill: rgba(0, 0, 0, 0.5); filter: url(#sc-soft); }
1332
- .scene .shadow.soft { fill: rgba(0, 0, 0, 0.42); }
1333
-
1334
- /* The app window. */
1335
- .scene .frame .f-top { fill: #34343d; } .scene .frame .f-left { fill: #26262d; } .scene .frame .f-right { fill: #1b1b21; }
1336
- .scene .win * { vector-effect: non-scaling-stroke; }
1337
- .scene .win-face { fill: #0e0e12; }
1338
- .scene .win-bar { fill: #1b1b21; }
1339
- .scene .dot { fill: rgba(255, 255, 255, 0.22); }
1340
- .scene .win-url { fill: rgba(255, 255, 255, 0.07); }
1341
- .scene .win-outline { fill: none; stroke: none; }
1342
- .scene .panel { fill: #202027; stroke: rgba(255, 255, 255, 0.12); stroke-width: 1; }
1343
- .scene .panel.added { stroke: rgba(242, 193, 95, 0.75); fill: #26221a; }
1344
- .scene .panel.modified { stroke: rgba(255, 255, 255, 0.32); }
1345
- .scene .panel-line { fill: rgba(255, 255, 255, 0.2); }
1346
- .scene .panel-name { fill: rgba(245, 245, 247, 0.78); font-family: var(--font); font-size: 0.34px; font-weight: 600; }
1347
- .scene .panel-in { animation: panel-in 0.7s var(--spring) both; }
1348
- @keyframes panel-in { from { opacity: 0; transform: translate(0, -0.9px); } }
1349
- .scene .ghost-panel { fill: none; stroke: rgba(255, 255, 255, 0.16); stroke-width: 1; stroke-dasharray: 0.02 0.015; }
1350
- .scene .ghost-panel.sketch { stroke: rgba(242, 193, 95, 0.7); stroke-width: 1.4; stroke-dasharray: 0.22 0.78; animation: sketch 2.6s linear infinite; }
1351
- .scene .ghost-panel.sketch:nth-child(2) { animation-delay: -0.9s; }
1352
- .scene .ghost-panel.sketch:nth-child(3) { animation-delay: -1.7s; }
1353
- @keyframes sketch { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
1354
- .scene .key-sign circle { fill: rgba(242, 193, 95, 0.12); stroke: var(--sc-amber); stroke-width: 1.4; }
1355
- .scene .key-sign path { fill: none; stroke: var(--sc-amber); stroke-width: 1.6; stroke-linecap: round; }
1356
-
1357
- /* The agent unit. */
1358
- .scene .unit .f-top { fill: #2c2c34; } .scene .unit .f-left { fill: #202027; } .scene .unit .f-right { fill: #16161b; }
1359
- .scene .unit-plate { fill: #121216; stroke: rgba(255, 255, 255, 0.1); stroke-width: 1; vector-effect: non-scaling-stroke; }
1360
- .scene .unit-led { fill: rgba(255, 255, 255, 0.18); }
1361
- .scene .p-active .unit-led { fill: var(--sc-amber); animation: led 1.6s ease-in-out infinite; }
1362
- .scene .p-done .unit-led { fill: var(--sc-green); }
1363
- .scene .p-active .hover { animation: hover 3.6s ease-in-out infinite; }
1364
- @keyframes hover { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
1365
- @keyframes led { 50% { opacity: 0.35; } }
1366
-
1367
- /* Posts, lamps, ports, towers, crates. */
1368
- .scene .post .f-top { fill: #2e2e36; } .scene .post .f-left { fill: #222229; } .scene .post .f-right { fill: #18181d; }
1369
- .scene .lamp .f-top { fill: #3a3a42; } .scene .lamp .f-left { fill: #2b2b32; } .scene .lamp .f-right { fill: #222228; }
1370
- .scene .p-active .lamp .f-top { fill: #f6d58a; } .scene .p-active .lamp .f-left { fill: #c99a3f; } .scene .p-active .lamp .f-right { fill: #a87e30; }
1371
- .scene .p-active .lamp { animation: led 1.8s ease-in-out infinite; }
1372
- .scene .p-done .lamp .f-top { fill: #9be3b1; } .scene .p-done .lamp .f-left { fill: #57b673; } .scene .p-done .lamp .f-right { fill: #3f8f57; }
1373
- .scene .p-failed .lamp .f-top { fill: #f8a597; } .scene .p-failed .lamp .f-left { fill: #d35a49; } .scene .p-failed .lamp .f-right { fill: #a9463a; }
1374
- .scene .port .f-top { fill: #2e2e36; }
1375
- .scene .port-led { fill: rgba(255, 255, 255, 0.18); }
1376
- .scene .p-done .port-led { fill: var(--sc-green); }
1377
- .scene .p-failed .port-led { fill: var(--sc-red); }
1378
- .scene .tower .f-top { fill: #303039; } .scene .tower .f-left { fill: #23232a; } .scene .tower .f-right { fill: #18181e; }
1379
- .scene .vent { fill: rgba(255, 255, 255, 0.07); }
1380
- .scene .tower-led { fill: rgba(255, 255, 255, 0.18); }
1381
- .scene .p-active .tower-led { fill: var(--sc-amber); animation: led 1.2s ease-in-out infinite; }
1382
- .scene .p-done .tower-led { fill: var(--sc-green); }
1383
- .scene .p-failed .tower-led { fill: var(--sc-red); }
1384
- .scene .crate .f-top { fill: #3a342a; } .scene .crate .f-left { fill: #2b261f; } .scene .crate .f-right { fill: #221e18; }
1385
- .scene .crate-x { stroke: rgba(255, 255, 255, 0.14); stroke-width: 1; vector-effect: non-scaling-stroke; fill: none; }
1386
-
1387
- /* Database layers, gateway, barrier. */
1388
- .scene .cyl .f-left { fill: #1c1f1e; stroke: rgba(62, 207, 142, 0.18); }
1389
- .scene .cyl .f-top { fill: #262b29; stroke: rgba(62, 207, 142, 0.38); }
1390
- .scene .cyl { animation: layer-in 0.7s var(--spring) both; }
1391
- .scene .cyl.ghost { animation: none; }
1392
- .scene .cyl.ghost .f-left, .scene .cyl.ghost .f-top { fill: transparent; stroke: rgba(255, 255, 255, 0.22); stroke-dasharray: 4 5; }
1393
- @keyframes layer-in { from { opacity: 0; transform: translateY(-16px); } }
1394
- .scene .table { fill: rgba(62, 207, 142, 0.16); stroke: rgba(62, 207, 142, 0.7); stroke-width: 1; vector-effect: non-scaling-stroke; animation: panel-in 0.6s var(--spring) both; }
1395
- .scene .pillar .f-top, .scene .lintel .f-top { fill: #33333b; } .scene .pillar .f-left, .scene .lintel .f-left { fill: #26262d; } .scene .pillar .f-right, .scene .lintel .f-right { fill: #1b1b20; }
1396
- .scene .lintel-plate { fill: #f5f5f7; }
1397
- .scene .bar .f-top { fill: #3b3222; } .scene .bar .f-left { fill: #2c261a; } .scene .bar .f-right { fill: #231e15; }
1398
- .scene .bar-stripes { stroke: rgba(242, 193, 95, 0.8); stroke-width: 2; vector-effect: non-scaling-stroke; fill: none; }
1399
-
1400
- /* Connections. */
1401
- .scene .pipe-base { fill: none; stroke: rgba(255, 255, 255, 0.09); stroke-width: 4; stroke-linecap: round; }
1402
- .scene .pipe { fill: none; stroke: rgba(245, 245, 247, 0.75); stroke-width: 1.8; stroke-linecap: round; stroke-dasharray: 1; stroke-dashoffset: 1; }
1403
- .scene .pipe-flow { fill: none; stroke: transparent; stroke-width: 2; stroke-linecap: round; stroke-dasharray: 3 10; }
1404
- .scene .p-planned .pipe-base { stroke: rgba(255, 255, 255, 0.18); stroke-width: 1.4; stroke-dasharray: 3 5; }
1405
- .scene .p-active .pipe-base { stroke: rgba(242, 193, 95, 0.14); }
1406
- .scene .p-active .pipe-flow { stroke: var(--sc-amber); animation: flow 1.4s linear infinite; }
1407
- .scene .p-done .pipe { animation: trace 0.9s var(--ease) forwards; }
1408
- .scene .p-failed .pipe-base { stroke: rgba(244, 113, 95, 0.55); stroke-width: 2; stroke-dasharray: 4 4; }
1409
- .scene .p-idle .pipe-base { stroke: rgba(255, 255, 255, 0.07); }
1410
- @keyframes flow { to { stroke-dashoffset: -13; } }
1411
- @keyframes trace { to { stroke-dashoffset: 0; } }
1412
-
1413
- /* Travellers. */
1414
- .scene .token { fill: #f5f5f7; }
1415
- .scene .token-halo { fill: rgba(245, 245, 247, 0.16); }
1416
- .scene .spark .token { fill: #fbe2a6; } .scene .spark .token-halo { fill: rgba(242, 193, 95, 0.22); }
1417
- .scene .record .token { fill: #7fe0b0; } .scene .record .token-halo { fill: rgba(62, 207, 142, 0.22); }
1418
- .scene .blocked .token, .scene .leak .token { fill: #f8a597; } .scene .blocked .token-halo, .scene .leak .token-halo { fill: rgba(244, 113, 95, 0.22); }
1419
- .scene .package .token { fill: #f5f5f7; }
1420
-
1421
- /* Labels pinned to the world. */
1422
- .scene .tag rect { fill: rgba(12, 12, 15, 0.94); stroke: rgba(255, 255, 255, 0.14); stroke-width: 1; }
1423
- .scene .tag text { fill: #d9d9df; font-family: var(--font); font-size: 9.5px; font-weight: 600; }
1424
- .scene .p-done .tag-check rect, .scene .p-done .tag-port rect { stroke: rgba(111, 208, 140, 0.55); }
1425
- .scene .p-done .tag-check text, .scene .p-done .tag-port text { fill: var(--sc-green); }
1426
- .scene .p-failed .tag-check rect { stroke: rgba(244, 113, 95, 0.6); }
1427
- .scene .p-failed .tag-check text { fill: var(--red-ink); }
1428
- .scene .p-active .tag-check rect { stroke: rgba(242, 193, 95, 0.6); }
1429
-
1430
- /* Part states. */
1431
- .scene .part { outline: none; cursor: pointer; }
1432
- .scene .part.p-planned .f-top, .scene .part.p-planned .f-left, .scene .part.p-planned .f-right { fill-opacity: 0.06; stroke: rgba(255, 255, 255, 0.28); stroke-width: 1; stroke-dasharray: 600; stroke-dashoffset: 600; animation: trace 1.2s var(--ease) forwards; }
1433
- .scene .part.p-planned .win-face, .scene .part.p-planned .win-bar, .scene .part.p-planned image, .scene .part.p-planned .raven { opacity: 0.25; }
1434
- .scene .part.p-planned .shadow { opacity: 0.3; }
1435
- .scene .part.p-idle { opacity: 0.55; }
1436
- .scene .part.p-done { animation: settle-part 0.6s var(--spring) both; }
1437
- @keyframes settle-part { from { transform: translateY(-6px); } }
1438
- .scene .part.p-failed .f-top { fill: #3c1f1c; stroke: rgba(244, 113, 95, 0.75); }
1439
- .scene .part.p-failed .f-left { fill: #2c1715; stroke: rgba(244, 113, 95, 0.5); }
1440
- .scene .part.p-failed .f-right { fill: #211211; stroke: rgba(244, 113, 95, 0.4); }
1441
- .scene .part.p-failed .win-face { fill: #1a0f0e; }
1442
- .scene .part.p-waiting .f-top, .scene .part.p-waiting .f-left, .scene .part.p-waiting .f-right { stroke: rgba(242, 193, 95, 0.8); stroke-dasharray: 5 4; }
1443
- .scene .part.p-waiting .win-face { fill: #17140c; }
1444
- .scene .part.is-focus { filter: drop-shadow(0 0 10px rgba(242, 193, 95, 0.22)); }
1445
- .scene .part.is-focus.p-active .frame .f-top { fill: #3b3a33; }
1446
- .scene .part.is-selected .f-top, .scene .part.is-selected .f-left, .scene .part.is-selected .f-right { stroke: rgba(245, 245, 247, 0.85); stroke-width: 1.4; }
1447
- .scene .part:focus-visible .f-top, .scene .part:focus-visible .f-left, .scene .part:focus-visible .f-right { stroke: var(--sc-amber); stroke-width: 2; }
1448
- .scene .part:hover .f-top { stroke: rgba(255, 255, 255, 0.35); }
1449
-
1450
- /* Phases: a waiting scene holds still around the part that needs you; a failed one marks it. */
1451
- .scene.is-wait .part:not(.p-waiting):not([data-part="platform"]) { opacity: 0.5; transition: opacity 0.5s var(--ease); }
1452
- .scene.is-wait .pipe-flow, .scene.is-wait .hover, .scene.is-wait .sketch, .scene.is-wait .token-g { animation-play-state: paused; }
1453
- .scene.is-fail .part:not(.p-failed):not([data-part="platform"]) { opacity: 0.7; }
1454
- .scene.is-done [data-part="platform"] .rim { stroke: rgba(111, 208, 140, 0.5); }
1455
- .scene.is-stopped .part { opacity: 0.6; }
1456
- .scene .fx-payoff .ring { fill: none; stroke: rgba(111, 208, 140, 0.55); stroke-width: 1.5; transform-box: fill-box; transform-origin: center; animation: payoff 1.6s cubic-bezier(0.2, 0.7, 0.2, 1) forwards; }
1457
- .scene .fx-payoff .ring.two { stroke: rgba(245, 245, 247, 0.35); animation-delay: 0.22s; }
1458
- @keyframes payoff { from { opacity: 0.9; transform: scale(0.35); } to { opacity: 0; transform: scale(1.15); } }
1459
- .scene.is-demo .tag rect { stroke-dasharray: 3 3; }
1290
+
1291
+
1292
+
1293
+
1294
+
1295
+
1296
+
1297
+
1298
+
1299
+
1300
+
1301
+
1302
+
1303
+
1304
+
1305
+
1306
+
1307
+
1308
+
1309
+
1310
+
1311
+
1312
+
1313
+
1314
+
1460
1315
 
1461
1316
  .work-wait { margin-top: 16px; display: grid; gap: 6px; padding: 14px 16px; border-radius: 12px; background: rgba(242, 193, 95, 0.08); box-shadow: inset 0 0 0 1px rgba(242, 193, 95, 0.35); }
1462
1317
  .work-wait strong { font-size: 14px; font-weight: 600; color: var(--warn-ink); }
@@ -1474,91 +1329,34 @@ select.sel:focus, input.sel:focus { outline: none; box-shadow: inset 0 0 0 1px #
1474
1329
  .stage.is-work .stage-body.panel { left: 10px; right: 10px; width: auto; top: auto; max-height: 46%; }
1475
1330
  .live-window { width: 180px; }
1476
1331
  }
1477
- @media (prefers-reduced-motion: reduce) {
1478
- .scene *, .scene .part, .scene-caption, .scene-inspect { animation: none !important; transition: none !important; }
1479
- .scene .p-done .pipe { stroke-dashoffset: 0; }
1480
- .scene .part.p-planned .f-top, .scene .part.p-planned .f-left, .scene .part.p-planned .f-right { stroke-dashoffset: 0; }
1481
- .scene .p-active .pipe-flow { stroke-dasharray: none; }
1482
- .scene .fx-payoff { display: none; }
1483
- }
1484
1332
 
1485
1333
  /* Scene light: brighter faces and a lit front edge, so objects read as solid against the floor. */
1486
1334
  .canvas.is-scene:not(:has(.live-window)) { grid-template-columns: minmax(0, 1fr); }
1487
- .scene .box .f-top { fill: #3c3c46; } .scene .box .f-left { fill: #2b2b33; } .scene .box .f-right { fill: #1f1f26; }
1488
- .scene .edge { fill: none; stroke: rgba(255, 255, 255, 0.26); stroke-width: 1; stroke-linecap: round; }
1489
- .scene .ground .f-top { fill: #202027; } .scene .ground .f-left { fill: #18181d; } .scene .ground .f-right { fill: #111115; }
1490
- .scene .ground .edge { stroke: rgba(255, 255, 255, 0.16); }
1491
- .scene .grid-lines .grid { stroke: rgba(255, 255, 255, 0.06); }
1492
- .scene .frame .f-top { fill: #4b4b56; } .scene .frame .f-left { fill: #35353e; } .scene .frame .f-right { fill: #27272e; }
1493
- .scene .unit .f-top { fill: #44444e; } .scene .unit .f-left { fill: #31313a; } .scene .unit .f-right { fill: #24242b; }
1494
- .scene .post .f-top { fill: #42424c; } .scene .post .f-left { fill: #30303a; } .scene .post .f-right { fill: #23232a; }
1495
- .scene .lamp .f-top { fill: #55555f; } .scene .lamp .f-left { fill: #3e3e47; } .scene .lamp .f-right { fill: #2f2f37; }
1496
- .scene .tower .f-top { fill: #45454f; } .scene .tower .f-left { fill: #32323b; } .scene .tower .f-right { fill: #25252c; }
1497
- .scene .pillar .f-top, .scene .lintel .f-top { fill: #474752; } .scene .pillar .f-left, .scene .lintel .f-left { fill: #34343d; } .scene .pillar .f-right, .scene .lintel .f-right { fill: #26262e; }
1498
- .scene .crate .f-top { fill: #4a4133; } .scene .crate .f-left { fill: #383126; } .scene .crate .f-right { fill: #2b261e; }
1499
- .scene .port .f-top { fill: #42424c; }
1500
- .scene .cyl .f-left { fill: #232826; } .scene .cyl .f-top { fill: #303733; }
1501
- .scene .part.p-planned .edge { stroke: none; }
1502
- .scene .part.p-failed .edge { stroke: rgba(244, 113, 95, 0.6); }
1503
- .scene .part.p-done .edge { stroke: rgba(255, 255, 255, 0.34); }
1504
- .scene-stage::before { content: ""; position: absolute; left: 10%; right: 10%; top: 22%; bottom: 18%; border-radius: 50%; background: radial-gradient(closest-side, rgba(255, 255, 255, 0.045), transparent); pointer-events: none; }
1505
-
1506
- /* ---------- units and brands: every object is a machined unit with its mark; providers wear their own colours ---------- */
1507
- .scene .unit .f-top { fill: #41414b; } .scene .unit .f-left { fill: #2e2e36; } .scene .unit .f-right { fill: #222229; }
1508
- .scene .pedestal .f-top { fill: #2a2a31; } .scene .pedestal .f-left { fill: #1e1e24; } .scene .pedestal .f-right { fill: #16161b; }
1509
- .scene .unit-ring { fill: none; stroke: var(--brand); stroke-opacity: 0.55; stroke-width: 1.3; vector-effect: non-scaling-stroke; transition: stroke 0.4s var(--ease), stroke-opacity 0.4s var(--ease); }
1510
- .scene .unit-led { fill: var(--brand); fill-opacity: 0.35; }
1511
- .scene .p-planned .unit-ring { stroke-opacity: 0.15; }
1512
- .scene .p-active .unit-ring { stroke: var(--sc-amber); stroke-opacity: 0.95; }
1513
- .scene .p-active .unit-led { fill: var(--sc-amber); fill-opacity: 1; animation: led 1.6s ease-in-out infinite; }
1514
- .scene .p-done .unit-ring { stroke: var(--sc-green); stroke-opacity: 0.9; }
1515
- .scene .p-done .unit-led { fill: var(--sc-green); fill-opacity: 1; }
1516
- .scene .p-failed .unit-ring { stroke: var(--sc-red); stroke-opacity: 0.95; }
1517
- .scene .p-failed .unit-led { fill: var(--sc-red); fill-opacity: 1; }
1518
- .scene .p-waiting .unit-ring { stroke: var(--sc-amber); stroke-dasharray: 4 3; }
1519
- .scene .p-waiting .unit-led { fill: var(--sc-amber); fill-opacity: 1; }
1520
- .scene .p-done .unit-wrap .edge, .scene .p-active .unit-wrap .edge { stroke: rgba(255, 255, 255, 0.4); }
1521
-
1522
- /* Supabase: green seams between layers, the bolt on a dark badge. */
1523
- .scene .brand-supabase .cyl .f-top { fill: #2c3530; stroke: rgba(62, 207, 142, 0.55); }
1524
- .scene .brand-supabase .cyl .f-left { fill: #1f2522; stroke: rgba(62, 207, 142, 0.22); }
1525
- .scene .seam { fill: none; stroke: var(--brand); stroke-opacity: 0.7; stroke-width: 1.4; stroke-linecap: round; filter: url(#sc-glow); }
1526
- .scene .p-active .seam { animation: led 1.8s ease-in-out infinite; }
1527
- .scene .brand-badge { fill: #0f1512; stroke: rgba(62, 207, 142, 0.6); stroke-width: 1; vector-effect: non-scaling-stroke; }
1528
-
1529
- /* Google: coloured caps on the pillars, four lights by the G. */
1530
- .scene .cap.g-blue .f-top { fill: #4285F4; } .scene .cap.g-blue .f-left { fill: #3367c7; } .scene .cap.g-blue .f-right { fill: #2a55a6; }
1531
- .scene .cap.g-green .f-top { fill: #34A853; } .scene .cap.g-green .f-left { fill: #2b8a45; } .scene .cap.g-green .f-right { fill: #237038; }
1532
- .scene .brand-google .lintel .f-top { fill: #4a4a55; }
1533
- .scene .lintel-plate { fill: #f5f5f7; }
1534
- .scene .gdot { opacity: 0.85; }
1535
- .scene .p-active .gdot { animation: led 1.4s ease-in-out infinite; }
1536
- .scene .p-planned .cap .f-top, .scene .p-planned .cap .f-left, .scene .p-planned .cap .f-right { fill-opacity: 0.08; }
1537
-
1538
- /* GitHub: a dark vault with a commit graph. */
1539
- .scene .vault .f-top { fill: #2d333b; } .scene .vault .f-left { fill: #22272e; } .scene .vault .f-right { fill: #1c2128; }
1540
- .scene .gitgraph path { fill: none; stroke: rgba(240, 246, 252, 0.7); stroke-width: 1.4; vector-effect: non-scaling-stroke; }
1541
- .scene .gitgraph .branch { stroke: #3fb950; }
1542
- .scene .gitgraph circle { fill: #0d1117; stroke: rgba(240, 246, 252, 0.85); stroke-width: 1.3; vector-effect: non-scaling-stroke; }
1543
- .scene .gitgraph .branch-dot { stroke: #3fb950; }
1544
- .scene .gitgraph .tip { fill: #f5f5f7; }
1545
- .scene .p-active .gitgraph .tip { animation: led 1.4s ease-in-out infinite; }
1546
-
1547
- /* Vercel: a black pad and the white triangle. */
1548
- .scene .brand-vercel .ground .f-top { fill: #0c0c0e; } .scene .brand-vercel .ground .f-left { fill: #08080a; } .scene .brand-vercel .ground .f-right { fill: #050506; }
1549
- .scene .brand-vercel .ground .edge { stroke: rgba(245, 245, 247, 0.35); }
1550
- .scene .pyramid .f-left { fill: #f5f5f7; stroke: rgba(255, 255, 255, 0.4); stroke-width: 0.8; }
1551
- .scene .pyramid .f-right { fill: #b4b4bc; stroke: rgba(255, 255, 255, 0.25); stroke-width: 0.8; }
1552
- .scene .pyramid .edge { fill: none; stroke: #ffffff; stroke-width: 1.2; }
1553
- .scene .part.p-planned .pyramid .f-left, .scene .part.p-planned .pyramid .f-right { fill-opacity: 0.06; stroke: rgba(255, 255, 255, 0.3); }
1554
- .scene .part.p-failed .pyramid .f-left { fill: #f2b3a9; }
1555
-
1556
- /* npm's command unit and the framework plate on the dev server. */
1557
- .scene .unit-wrap .shadow { opacity: 0.9; }
1558
- @media (prefers-reduced-motion: reduce) {
1559
- .scene .seam, .scene .gdot, .scene .gitgraph .tip { animation: none !important; }
1560
- }
1561
- .scene .sign .f-top { fill: #4a4a55; } .scene .sign .f-left { fill: #3a3a44; } .scene .sign .f-right { fill: #2a2a32; }
1335
+
1336
+
1337
+
1338
+
1339
+
1340
+
1341
+
1342
+
1343
+
1344
+
1345
+
1346
+
1347
+
1348
+
1349
+
1350
+
1351
+
1352
+
1353
+
1354
+
1355
+
1356
+
1357
+
1358
+
1359
+
1562
1360
 
1563
1361
  /* ---------- the work panel: a title, a line, a few chips, big tiles. Detail waits behind "Details". ---------- */
1564
1362
  .panel h1.wtitle { font-size: 24px; line-height: 1.2; letter-spacing: -0.025em; font-weight: 600; max-width: none; }
@@ -1570,7 +1368,7 @@ select.sel:focus, input.sel:focus { outline: none; box-shadow: inset 0 0 0 1px #
1570
1368
  .wbadge.is-warn { background: var(--warn); }
1571
1369
  .wbadge.is-wait { background: var(--warn); }
1572
1370
  .wbadge.is-stop, .wbadge.is-plan { background: var(--panel-3); color: var(--ink-2); }
1573
- @keyframes badge-in { from { transform: scale(0.6); opacity: 0; } }
1371
+
1574
1372
  .wline { margin-top: 10px; font-size: 14.5px; line-height: 1.5; color: var(--ink-2); }
1575
1373
  .wchips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 16px; }
1576
1374
  .wchip { display: inline-flex; align-items: center; gap: 7px; height: 30px; padding: 0 11px; border-radius: 999px; background: rgba(255, 255, 255, 0.05); border: 1px solid var(--line-2); font-size: 12.5px; font-weight: 500; color: var(--ink); white-space: nowrap; }
@@ -1631,19 +1429,6 @@ select.sel:focus, input.sel:focus { outline: none; box-shadow: inset 0 0 0 1px #
1631
1429
  .screen-body.is-live iframe.is-loaded { opacity: 1; }
1632
1430
  .screen-wait { position: absolute; inset: 0; display: grid; place-items: center; font-size: 12px; color: var(--ink-3); }
1633
1431
 
1634
- /* Mascots: a provider's mark walks, rolls or hops along the connection while that step works. */
1635
- .scene .walker-shadow { fill: rgba(0, 0, 0, 0.45); }
1636
- .scene .walker-body { transform-box: fill-box; transform-origin: 50% 100%; }
1637
- .scene .walker.is-walk .walker-body { animation: waddle 0.42s ease-in-out infinite alternate; }
1638
- .scene .walker.is-hop .walker-body { animation: hop 0.6s cubic-bezier(0.3, 0, 0.4, 1) infinite; }
1639
- .scene .walker.is-roll .walker-body { transform-origin: 50% 50%; animation: roll 0.9s linear infinite; }
1640
- .scene .walker image { filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.6)); }
1641
- @keyframes waddle { from { transform: translateY(0) rotate(-7deg); } to { transform: translateY(-3px) rotate(7deg); } }
1642
- @keyframes hop { 0%, 100% { transform: translateY(0) scale(1.08, 0.9); } 45% { transform: translateY(-9px) scale(0.95, 1.06); } 70% { transform: translateY(-2px) scale(1, 1); } }
1643
- @keyframes roll { to { transform: rotate(360deg); } }
1644
- .scene.is-wait .walker { display: none; }
1645
- @media (prefers-reduced-motion: reduce) { .scene .walker { display: none; } }
1646
-
1647
1432
  /* ---------- windows: findings, agents, releases and chat in the same calm kit as the work panel ---------- */
1648
1433
 
1649
1434
  /* Drawer frame: a round close, a short line. */
@@ -1778,7 +1563,7 @@ select.sel:focus, input.sel:focus { outline: none; box-shadow: inset 0 0 0 1px #
1778
1563
  .chat-typing { display: inline-flex; gap: 3px; }
1779
1564
  .chat-typing i { width: 5px; height: 5px; border-radius: 50%; background: var(--ink-2); animation: typing 1.2s ease-in-out infinite; }
1780
1565
  .chat-typing i:nth-child(2) { animation-delay: 0.15s; } .chat-typing i:nth-child(3) { animation-delay: 0.3s; }
1781
- @keyframes typing { 0%, 60%, 100% { opacity: 0.3; transform: none; } 30% { opacity: 1; transform: translateY(-3px); } }
1566
+
1782
1567
  .chat-connect { margin: 0 14px 10px; padding: 12px 14px; border-radius: 14px; background: rgba(242, 193, 95, 0.08); box-shadow: inset 0 0 0 1px rgba(242, 193, 95, 0.3); }
1783
1568
  .chat-connect p { font-size: 12.5px; line-height: 1.45; color: var(--warn-ink); }
1784
1569
  .chat-connect-row { display: flex; gap: 8px; margin-top: 10px; }
@@ -1793,132 +1578,49 @@ select.sel:focus, input.sel:focus { outline: none; box-shadow: inset 0 0 0 1px #
1793
1578
  .side.chat .btn.send:disabled { background: var(--panel-3); color: var(--ink-3); }
1794
1579
  @media (prefers-reduced-motion: reduce) { .chat-typing i { animation: none; } }
1795
1580
 
1796
- /* ---------- characters and hype ---------- */
1797
- /* Claude Code's voxel critter. */
1798
- .scene .cc .f-top { fill: #eda186; } .scene .cc .f-left { fill: #D97757; } .scene .cc .f-right { fill: #b05a3e; }
1799
- .scene .cc .edge { stroke: rgba(255, 220, 200, 0.55); }
1800
- .scene .cc-eye { fill: #1b0f0a; }
1801
- .scene .critter .cc-torso, .scene .critter .cc-legs { transform-box: fill-box; transform-origin: 50% 100%; }
1802
- .scene .p-active .critter .cc-torso, .scene .critter.is-busy .cc-torso { animation: chomp 0.1s ease-in-out infinite alternate; }
1803
- .scene .p-active .critter .cc-legs.a, .scene .critter.is-busy .cc-legs.a { animation: step 0.1s ease-in-out infinite alternate; }
1804
- .scene .p-active .critter .cc-legs.b, .scene .critter.is-busy .cc-legs.b { animation: step 0.1s ease-in-out infinite alternate-reverse; }
1805
- .scene .p-done .critter { animation: happy 0.5s var(--spring) 2 alternate; transform-box: fill-box; transform-origin: 50% 100%; }
1806
- .scene .p-planned .critter .f-top, .scene .p-planned .critter .f-left, .scene .p-planned .critter .f-right { fill-opacity: 0.12; stroke: rgba(217, 119, 87, 0.5); stroke-dasharray: none; stroke-dashoffset: 0; animation: none; }
1807
- @keyframes chomp { from { transform: scale(1, 1); } to { transform: scale(1.06, 0.9); } }
1808
- @keyframes step { from { transform: translateY(0); } to { transform: translateY(-3px); } }
1809
- @keyframes happy { to { transform: translateY(-8px) scale(1.04); } }
1810
- .scene .tok rect { fill: #fbe2a6; stroke: #f2c15f; stroke-width: 1; filter: drop-shadow(0 0 4px rgba(242, 193, 95, 0.8)); }
1811
-
1812
- /* Supabase lightning. */
1813
- .scene .zap { opacity: 0; animation: strike 1.65s linear infinite; }
1814
- .scene .zap-glow { fill: none; stroke: #3ECF8E; stroke-width: 10; stroke-opacity: 0.35; stroke-linejoin: round; filter: url(#sc-glow); }
1815
- .scene .zap-core { fill: none; stroke: #d9ffe9; stroke-width: 2.6; stroke-linejoin: round; stroke-linecap: round; }
1816
- .scene .zap-core.thin { stroke-width: 1.6; stroke: #8ff0c2; }
1817
- .scene .zap-hit { fill: rgba(62, 207, 142, 0.45); filter: url(#sc-glow); }
1818
- .scene .zap-spark { stroke: #b6ffd9; stroke-width: 2; stroke-linecap: round; }
1819
- @keyframes strike { 0% { opacity: 0; } 3% { opacity: 1; } 7% { opacity: 0.25; } 11% { opacity: 1; } 24% { opacity: 0; } 100% { opacity: 0; } }
1820
-
1821
- /* PostHog: hedgehog, events, bars. */
1822
- .scene .ph-body .f-top { fill: #8b5e3c; } .scene .ph-body .f-left { fill: #6e4930; } .scene .ph-body .f-right { fill: #573925; }
1823
- .scene .ph-head .f-top { fill: #c9926a; } .scene .ph-head .f-left { fill: #a97750; } .scene .ph-head .f-right { fill: #8d6141; }
1824
- .scene .ph-nose .f-top, .scene .ph-nose .f-left, .scene .ph-nose .f-right { fill: #1d1f27; }
1825
- .scene .ph-leg .f-top, .scene .ph-leg .f-left, .scene .ph-leg .f-right { fill: #4a3020; }
1826
- .scene .ph-eye { fill: #111; }
1827
- .scene .ph-spike.c0 .f-top { fill: #F54E00; } .scene .ph-spike.c0 .f-left { fill: #c43e00; } .scene .ph-spike.c0 .f-right { fill: #9a3100; }
1828
- .scene .ph-spike.c1 .f-top { fill: #F9BD2B; } .scene .ph-spike.c1 .f-left { fill: #d39c17; } .scene .ph-spike.c1 .f-right { fill: #a87b10; }
1829
- .scene .ph-spike.c2 .f-top { fill: #3b63ff; } .scene .ph-spike.c2 .f-left { fill: #1D4AFF; } .scene .ph-spike.c2 .f-right { fill: #1538c4; }
1830
- .scene .ph-bar.c0 .f-top { fill: #F54E00; } .scene .ph-bar.c0 .f-left { fill: #c43e00; } .scene .ph-bar.c0 .f-right { fill: #9a3100; }
1831
- .scene .ph-bar.c1 .f-top { fill: #F9BD2B; } .scene .ph-bar.c1 .f-left { fill: #d39c17; } .scene .ph-bar.c1 .f-right { fill: #a87b10; }
1832
- .scene .ph-bar.c2 .f-top { fill: #3b63ff; } .scene .ph-bar.c2 .f-left { fill: #1D4AFF; } .scene .ph-bar.c2 .f-right { fill: #1538c4; }
1833
- .scene .hedgehog .ph-legs { transform-box: fill-box; }
1834
- .scene .p-active .hedgehog .ph-legs.a { animation: step 0.16s ease-in-out infinite alternate; }
1835
- .scene .p-active .hedgehog .ph-legs.b { animation: step 0.16s ease-in-out infinite alternate-reverse; }
1836
- .scene .p-planned .hedgehog, .scene .p-idle .hedgehog { opacity: 0.35; }
1837
- .scene .bar-g { transform-box: fill-box; transform-origin: 50% 100%; animation: pump 0.7s ease-in-out infinite alternate; }
1838
- @keyframes pump { from { transform: scaleY(0.35); } to { transform: scaleY(1); } }
1839
- .scene .evt.c0 { fill: #F54E00; } .scene .evt.c1 { fill: #F9BD2B; } .scene .evt.c2 { fill: #3b63ff; }
1840
- .scene .evt { filter: drop-shadow(0 0 3px rgba(255, 255, 255, 0.35)); }
1841
-
1842
- /* GitHub commits, Vercel launch, Google orbit. */
1843
- .scene .commit .token { fill: #3fb950; } .scene .commit .token-halo { fill: rgba(63, 185, 80, 0.25); }
1844
- .scene .ring-launch { fill: none; stroke: #f5f5f7; stroke-width: 2; transform-box: fill-box; transform-origin: center; animation: launch 1.2s cubic-bezier(0.2, 0.6, 0.2, 1) infinite; }
1845
- @keyframes launch { from { opacity: 0.9; transform: translateY(0) scale(0.4); } to { opacity: 0; transform: translateY(-46px) scale(1.5); } }
1846
- .scene .speed { stroke: rgba(245, 245, 247, 0.55); stroke-width: 1.6; stroke-linecap: round; stroke-dasharray: 8 14; animation: speed 0.45s linear infinite; }
1847
- @keyframes speed { to { stroke-dashoffset: 22; } }
1848
- .scene .orbit-spin { animation: orbit 1.1s linear infinite; transform-origin: 0 0; }
1849
- .scene .orbit circle { filter: drop-shadow(0 0 5px rgba(255, 255, 255, 0.35)); }
1850
- @keyframes orbit { to { transform: rotate(360deg); } }
1851
-
1852
- .scene.is-wait .hype, .scene.is-wait .critter * { animation-play-state: paused; }
1853
- @media (prefers-reduced-motion: reduce) { .scene .hype, .scene .tok { display: none; } .scene .critter * { animation: none !important; } }
1854
-
1855
- /* ---------- premium kit: solid emblems, plinths, gateway doors, insight card, travelling payloads ---------- */
1856
- .scene .emb-side { filter: brightness(0.34) saturate(0.85); }
1857
- .scene .emb-face { filter: drop-shadow(0 0 0.02px rgba(0, 0, 0, 0)); }
1858
- .scene .emb-sheen { fill: url(#sc-sheen); mix-blend-mode: screen; }
1859
- .scene .emb-float { transform-box: fill-box; }
1860
- .scene .p-active .emb-float { animation: hover 3.8s ease-in-out infinite; }
1861
- .scene .p-done .emb-float { animation: settle-part 0.7s var(--spring) both; }
1862
- .scene .part.p-planned .emblem, .scene .part.p-idle .emblem { opacity: 0.28; }
1863
- .scene .part.p-planned .emb-sheen { display: none; }
1864
- .scene .plinth .f-top { fill: #3a3a44; } .scene .plinth .f-left { fill: #2a2a31; } .scene .plinth .f-right { fill: #1f1f25; }
1865
- .scene .emblem-unit .plinth .edge { stroke: var(--brand); stroke-opacity: 0.55; }
1866
- .scene .door .f-top { fill: #52525e; } .scene .door .f-left { fill: #3c3c46; } .scene .door .f-right { fill: #2e2e36; }
1867
- .scene .door.google .f-left { fill: #2f3f5e; } .scene .door.github .f-left { fill: #2d333b; }
1868
- .scene .door .edge { stroke: rgba(255, 255, 255, 0.35); }
1869
- .scene .cap.g-dark .f-top { fill: #2d333b; } .scene .cap.g-dark .f-left { fill: #22272e; } .scene .cap.g-dark .f-right { fill: #1c2128; }
1870
- .scene .cap.g-light .f-top { fill: #f0f6fc; } .scene .cap.g-light .f-left { fill: #c9d1d9; } .scene .cap.g-light .f-right { fill: #a0a8b0; }
1871
- .scene .brand-github .lintel .f-top { fill: #2d333b; } .scene .brand-github .lintel .f-left { fill: #22272e; } .scene .brand-github .lintel .f-right { fill: #1c2128; }
1872
- .scene .insight .card .f-top { fill: #3a3a44; } .scene .insight .card .f-left { fill: #26262d; } .scene .insight .card .f-right { fill: #1b1b21; }
1873
- .scene .insight .stand .f-top { fill: #2e2e36; } .scene .insight .stand .f-left { fill: #22222a; } .scene .insight .stand .f-right { fill: #18181d; }
1874
- .scene .ins-bg { fill: #0f0f13; }
1875
- .scene .ins-title { fill: rgba(255, 255, 255, 0.25); }
1876
- .scene .ins-grid { fill: none; stroke: rgba(255, 255, 255, 0.07); stroke-width: 1; vector-effect: non-scaling-stroke; }
1877
- .scene .ins-line { fill: none; stroke: #F9BD2B; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
1878
- .scene .ins-dot { fill: #F54E00; }
1879
- .scene .pl { filter: drop-shadow(0 6px 4px rgba(0, 0, 0, 0.55)); }
1581
+
1582
+
1583
+
1584
+
1585
+
1586
+
1587
+
1588
+
1589
+
1590
+
1591
+
1592
+
1593
+
1594
+
1595
+
1596
+
1597
+
1598
+
1599
+
1600
+
1601
+
1602
+
1603
+
1604
+
1605
+
1606
+
1607
+
1880
1608
  .wproviders { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; margin-top: 12px; }
1881
1609
  .wprov { display: grid; place-items: center; height: 42px; border-radius: 12px; border: 1px solid var(--line-2); background: rgba(255, 255, 255, 0.03); transition: border-color 0.14s, background 0.14s; }
1882
1610
  .wprov:hover { background: rgba(255, 255, 255, 0.07); }
1883
1611
  .wprov.on { border-color: rgba(245, 245, 247, 0.85); background: rgba(255, 255, 255, 0.09); }
1884
- @media (prefers-reduced-motion: reduce) { .scene .emb-float { animation: none !important; } .scene .emb-sheen { display: none; } }
1885
-
1886
- /* ---------- mascots: GitHub's Octocat, PostHog's hedgehog, Claude polishing ---------- */
1887
- .scene .oc .f-top { fill: #3d444d; } .scene .oc .f-left { fill: #2b3137; } .scene .oc .f-right { fill: #1c2127; }
1888
- .scene .oc .edge { stroke: rgba(240, 246, 252, 0.4); }
1889
- .scene .oc-face { fill: #f6c8b3; }
1890
- .scene .oc-eye { fill: #1c2127; }
1891
- .scene .oc-shine { fill: #fff; }
1892
- .scene .oc-mouth { fill: #a5524a; }
1893
- .scene .octocat .oc-tent { transform-box: fill-box; transform-origin: 50% 0; animation: wiggle 0.24s ease-in-out infinite alternate; }
1894
- .scene .octocat .oc-tent.t1 { animation-direction: alternate-reverse; }
1895
- @keyframes wiggle { from { transform: rotate(-6deg); } to { transform: rotate(6deg); } }
1896
- .scene .mx-body .f-top { fill: #e0b07a; } .scene .mx-body .f-left { fill: #c49360; } .scene .mx-body .f-right { fill: #a47746; }
1897
- .scene .mx-face .f-top { fill: #f0cfa2; } .scene .mx-face .f-left { fill: #ddb684; } .scene .mx-face .f-right { fill: #bf9564; }
1898
- .scene .mx-spike .f-top { fill: #4a3524; } .scene .mx-spike .f-left { fill: #35251a; } .scene .mx-spike .f-right { fill: #251912; }
1899
- .scene .mx-leg .f-top, .scene .mx-leg .f-left, .scene .mx-leg .f-right { fill: #6b4a2e; }
1900
- .scene .mx-nose .f-top, .scene .mx-nose .f-left, .scene .mx-nose .f-right { fill: #15161b; }
1901
- .scene .mx-eye { fill: #15161b; }
1902
- .scene .mx-cheek { fill: #f08a6b; opacity: 0.8; }
1903
- .scene .mx-pole .f-top { fill: #c8c8d0; } .scene .mx-pole .f-left { fill: #9a9aa5; } .scene .mx-pole .f-right { fill: #74747e; }
1904
- .scene .mx-flag { stroke: rgba(255, 255, 255, 0.25); stroke-width: 0.6; }
1905
- .scene .flag-text { fill: #fff; font: 800 0.26px/1 var(--font-sans, system-ui); letter-spacing: 0.02px; }
1906
- .scene .mx-pole .edge, .scene .mx-body .edge, .scene .mx-face .edge, .scene .mx-spike .edge, .scene .mx-leg .edge, .scene .mx-nose .edge { stroke: rgba(255, 240, 220, 0.3); }
1907
- .scene .sparkle { fill: #fff; filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.9)); }
1908
- .scene .burst { fill: rgba(137, 87, 229, 0.35); stroke: #c9b3ff; stroke-width: 2; }
1909
- .scene .say { fill: #8957e5; stroke: rgba(255, 255, 255, 0.5); stroke-width: 1; }
1910
- .scene .say-text { fill: #fff; font: 800 11px/1 var(--font-sans, system-ui); letter-spacing: 0.02em; }
1911
- @media (prefers-reduced-motion: reduce) { .scene .skit { display: none; } }
1912
- .scene .mx-belly { fill: #f7e3c4; }
1913
- .scene .mx-snout .f-top { fill: #f7e3c4; } .scene .mx-snout .f-left { fill: #e6cba6; } .scene .mx-snout .f-right { fill: #c9ab84; }
1914
- .scene .mx-brow { fill: #4a2a16; }
1915
- .scene .mx-hat .f-top { fill: #ffd25a; } .scene .mx-hat .f-left { fill: #F9BD2B; } .scene .mx-hat .f-right { fill: #c9921a; }
1916
- .scene .mx-hat-ridge .f-top, .scene .mx-hat-ridge .f-left, .scene .mx-hat-ridge .f-right { fill: #e0a51f; }
1917
- .scene .mx-hat .edge, .scene .mx-snout .edge { stroke: rgba(255, 245, 220, 0.45); }
1918
- .scene .smudge { fill: rgba(214, 206, 192, 0.3); filter: blur(0.05px); }
1919
- .scene .smudge .streak { fill: none; stroke: rgba(214, 206, 192, 0.35); stroke-width: 0.07; stroke-linecap: round; }
1920
- .scene .bubble { fill: rgba(220, 240, 255, 0.18); stroke: rgba(235, 248, 255, 0.85); stroke-width: 1; }
1921
- .scene .foam { fill: rgba(250, 252, 255, 0.85); }
1612
+
1613
+
1614
+
1615
+
1616
+
1617
+
1618
+
1619
+
1620
+
1621
+
1622
+
1623
+
1922
1624
 
1923
1625
  /* Review: files Undo leaves alone, and putting one back by hand. */
1924
1626
  .work-diff-file h3 { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
@@ -1984,3 +1686,6 @@ select.sel:focus, input.sel:focus { outline: none; box-shadow: inset 0 0 0 1px #
1984
1686
  .act-side { grid-column: 2; }
1985
1687
  }
1986
1688
  @media (prefers-reduced-motion: reduce) { .act-item .act-art, .act-item:hover .act-art { transition: none; transform: none; } }
1689
+
1690
+ @keyframes badge-in { from { transform: scale(0.6); opacity: 0; } }
1691
+ @keyframes typing { 0%, 60%, 100% { opacity: 0.3; transform: none; } 30% { opacity: 1; transform: translateY(-3px); } }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viberaven/cli",
3
- "version": "1.6.9",
3
+ "version": "1.6.10",
4
4
  "description": "VibeRaven CLI and local Studio: Supabase RLS and security check for AI-built Vercel + Supabase apps, with an agent task list and fix prompts.",
5
5
  "license": "MIT",
6
6
  "author": "VibeRaven",