@oracle-agent/oracle 0.35.36 → 0.35.38

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.
Files changed (47) hide show
  1. package/README.md +3 -2
  2. package/dist/agent-sessions.mjs +71 -8
  3. package/dist/assets/skills/oracle-desk-product/SKILL.md +1 -1
  4. package/dist/assets/skills/venue-capability-boundaries/SKILL.md +4 -0
  5. package/dist/bin/desk-server.mjs +36 -36
  6. package/dist/bin/oracle-data-mcp.mjs +17 -17
  7. package/dist/bin/oracle-gateway.mjs +53 -42
  8. package/dist/bin/oracle-public-server.mjs +5 -5
  9. package/dist/bin/oracle-route.mjs +11 -11
  10. package/dist/bin/oracle-telegram-mcp.mjs +4 -4
  11. package/dist/cli/commands/agent-session.mjs +73 -10
  12. package/dist/cli/commands/chat.mjs +238 -231
  13. package/dist/cli/commands/doctor.mjs +2 -2
  14. package/dist/cli/commands/eval.mjs +164 -158
  15. package/dist/cli/commands/farm.mjs +1 -1
  16. package/dist/cli/commands/model.mjs +242 -235
  17. package/dist/cli/commands/quickstart.mjs +1 -1
  18. package/dist/cli/commands/sign.mjs +1 -1
  19. package/dist/cli/commands/signer.mjs +1 -1
  20. package/dist/cli/commands/swap.mjs +24 -24
  21. package/dist/cli/commands/telegram.mjs +3 -3
  22. package/dist/cli/commands/venues.mjs +1 -1
  23. package/dist/data/desk-data.mjs +34 -34
  24. package/dist/data/providers/farming.mjs +1 -1
  25. package/dist/data/providers/lp-destination-discovery.mjs +4 -4
  26. package/dist/index.mjs +53 -52
  27. package/dist/local-signer/anvil-attestation-worker.mjs +1 -1
  28. package/dist/local-signer/index.mjs +1 -1
  29. package/dist/local-signer/runtime.mjs +1 -1
  30. package/dist/nft/universal-mint-router.mjs +4 -4
  31. package/dist/notifications/index.mjs +9 -3
  32. package/dist/router/index.mjs +3 -3
  33. package/dist/router/prepare-bridge.mjs +2 -2
  34. package/dist/router/prepare-route.mjs +4 -0
  35. package/dist/teams/index.mjs +5 -3
  36. package/dist/tui/standalone-client.mjs +107 -101
  37. package/package.json +2 -1
  38. package/public/agent-connect/index.html +2 -2
  39. package/public/eval-report.json +95 -95
  40. package/public/oracle-console/index.html +3 -2
  41. package/public/oracle-splash/_variants/ice.html +4 -4
  42. package/public/oracle-splash/_variants/ivory.html +4 -4
  43. package/public/oracle-splash/assets/vendor/gsap-3.13.0.min.js +10 -0
  44. package/public/oracle-splash/assets/vendor/gsap-scrolltrigger-3.13.0.min.js +10 -0
  45. package/public/oracle-splash/assets/vendor/lenis-1.3.11.min.js +1 -0
  46. package/public/oracle-splash/index.html +558 -71
  47. package/server.json +2 -2
@@ -6,11 +6,11 @@
6
6
  <title>ORACLE</title>
7
7
  <link rel="icon" href="/favicon.svg" type="image/svg+xml">
8
8
  <link rel="shortcut icon" href="/favicon.ico">
9
- <meta name="description" content="Trade, research, and build across every chain. Fully self-custodial.">
9
+ <meta name="description" content="Trade, research, and build across Oracle's working chain surfaces, with extensible EVM support and self-custodial signing.">
10
10
  <meta name="theme-color" content="#0B1018" />
11
11
  <meta name="robots" content="index,follow" />
12
12
  <meta property="og:title" content="ORACLE | The all-in-one multichain agent">
13
- <meta property="og:description" content="Trade, research, and build across every chain. Fully self-custodial.">
13
+ <meta property="og:description" content="Trade, research, and build across Oracle's working chain surfaces, with extensible EVM support and self-custodial signing.">
14
14
  <meta property="og:image" content="https://oracle.demi.la/assets/hero/orb-poster.jpg">
15
15
  <meta property="og:image:width" content="900">
16
16
  <meta property="og:image:height" content="900">
@@ -18,7 +18,7 @@
18
18
  <meta property="og:type" content="website">
19
19
  <meta name="twitter:card" content="summary_large_image">
20
20
  <meta name="twitter:title" content="ORACLE | The all-in-one multichain agent">
21
- <meta name="twitter:description" content="Trade, research, and build across every chain. Fully self-custodial.">
21
+ <meta name="twitter:description" content="Trade, research, and build across Oracle's working chain surfaces, with extensible EVM support and self-custodial signing.">
22
22
  <meta name="twitter:image" content="https://oracle.demi.la/assets/hero/orb-poster.jpg">
23
23
  <link rel="preconnect" href="https://fonts.googleapis.com" />
24
24
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
@@ -88,7 +88,12 @@
88
88
  html{scroll-behavior:smooth;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility;overflow-x:hidden;max-width:100%}
89
89
  body{
90
90
  min-height:100dvh;background:var(--bg);color:var(--ink);position:relative;isolation:isolate;
91
- font-family:var(--sans);font-weight:400;overflow-x:hidden;max-width:100vw;
91
+ font-family:var(--sans);font-weight:400;max-width:100vw;
92
+ /* `overflow-x:hidden` here computed overflow-y to `auto`, which turned <body>
93
+ into a scroll container and silently killed every `position:sticky` on the
94
+ page (the existing .atlas-sticky included). `clip` suppresses the same
95
+ horizontal overflow without creating a scrollport. */
96
+ overflow-x:clip;
92
97
  }
93
98
  ::selection{background:var(--blue);color:#071018}
94
99
  a{color:inherit;text-decoration:none}
@@ -968,6 +973,15 @@ a.chip:hover{border-color:rgba(124,196,255,.3);background:rgba(21,32,49,.6);tran
968
973
  text-transform:uppercase;color:var(--mute);
969
974
  }
970
975
  .hero-note-line code{color:var(--blue2);font-size:var(--fs-micro)}
976
+ /* Two unbreakable halves joined by a centered dot. On wide viewports they sit
977
+ on one line; below 1180px they stack and the dot is dropped, so nothing strands. */
978
+ .hero-note-line{display:flex;flex-wrap:nowrap;align-items:baseline;column-gap:.9em;row-gap:4px}
979
+ .hero-note-line span{white-space:nowrap}
980
+ .hero-note-sep{font-style:normal;color:var(--blue2)}
981
+ @media (max-width:1180px){
982
+ .hero-note-line{flex-direction:column;align-items:flex-start}
983
+ .hero-note-sep{display:none}
984
+ }
971
985
  .hero-installer{
972
986
  margin:clamp(24px,4vw,38px) 0 0;width:100%;border:1px solid var(--line-2);border-radius:var(--r-md);
973
987
  overflow:hidden;background:linear-gradient(145deg,rgba(17,25,37,.95),rgba(10,16,25,.98));
@@ -1029,7 +1043,9 @@ a.chip:hover{border-color:rgba(124,196,255,.3);background:rgba(21,32,49,.6);tran
1029
1043
  letter-spacing:.2em;text-transform:uppercase;color:var(--mute);text-align:right;
1030
1044
  }
1031
1045
  @media (max-width:960px){
1032
- .hero-split{grid-template-columns:minmax(0,1fr);gap:36px}
1046
+ /* The orb poster carries its own breathing room inside the square, so the
1047
+ stacked layout needs less grid gap or the mark floats away from the copy. */
1048
+ .hero-split{grid-template-columns:minmax(0,1fr);gap:16px}
1033
1049
  .hero-shot{transform:none;width:100%}
1034
1050
  .hero-product .hero-art{inset:-10% -6%;opacity:.34}
1035
1051
  .hero-product figcaption{text-align:left}
@@ -1228,10 +1244,261 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1228
1244
  .wires circle{opacity:1}
1229
1245
  .node:hover,.chain:hover{transform:none}
1230
1246
  }
1247
+
1248
+ /* ══════════════════════════════════════════════════════════════════
1249
+ SIGNAL RIDGE — the scroll narrative
1250
+ One idea carried the length of the page: raw market noise (the far,
1251
+ jagged ridge) resolving line by line into a single routed signal you
1252
+ can read and sign. Every piece below is visible by default and is
1253
+ only *scrubbed* by JS, so a failed CDN or a blocked script leaves a
1254
+ readable page rather than a blank one. Motion is transform/opacity.
1255
+ ══════════════════════════════════════════════════════════════════ */
1256
+ .ridge-defs{position:absolute;width:0;height:0;overflow:hidden;pointer-events:none}
1257
+ .ridge{display:block;width:100%;height:100%;overflow:visible;pointer-events:none}
1258
+ .ridge use{fill:none;stroke:inherit;stroke-width:inherit;stroke-linecap:round;stroke-linejoin:round;vector-effect:non-scaling-stroke}
1259
+ .ridge .rg{fill:none}
1260
+ .ridge .rg-0{stroke:rgba(124,196,255,.26);stroke-width:1}
1261
+ .ridge .rg-1{stroke:rgba(124,196,255,.34);stroke-width:1.05}
1262
+ .ridge .rg-2{stroke:rgba(140,208,255,.46);stroke-width:1.15}
1263
+ .ridge .rg-3{stroke:rgba(167,216,255,.64);stroke-width:1.3}
1264
+ .ridge .rg-4{stroke:rgba(120,232,214,.95);stroke-width:1.8;filter:drop-shadow(0 0 8px rgba(80,210,193,.45))}
1265
+
1266
+ /* ── chapter 01 · the opening viewport ───────────────────────────── */
1267
+ /* The horizon sits at the fold, not at the foot of the section, so the ridge
1268
+ is part of the opening composition rather than something you scroll to. */
1269
+ .hero-ridge{
1270
+ position:absolute;left:50%;top:50%;width:min(1680px,150vw);
1271
+ height:clamp(240px,44vh,470px);transform:translateX(-50%);
1272
+ z-index:0;pointer-events:none;
1273
+ -webkit-mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent);
1274
+ mask-image:linear-gradient(90deg,transparent,#000 12%,#000 88%,transparent);
1275
+ }
1276
+ .hero-index{
1277
+ display:flex;align-items:center;gap:14px;width:100%;margin-bottom:18px;
1278
+ font-family:var(--mono);font-size:var(--fs-micro);letter-spacing:.3em;text-transform:uppercase;color:var(--mute);
1279
+ }
1280
+ .hero-index b{font-weight:500;color:var(--blue2)}
1281
+ .hero-index i{flex:1;height:1px;background:linear-gradient(90deg,var(--line-2),transparent);font-style:normal;transform-origin:0 50%}
1282
+ .home{align-content:center}
1283
+ /* The old centred hairline was an unlabelled decoration. One cue, anchored to
1284
+ the editorial left edge, that says what the next chapter is. */
1285
+ .home::after{display:none}
1286
+ .hero-cue{
1287
+ position:relative;z-index:3;margin-top:clamp(26px,5vh,54px);
1288
+ display:flex;align-items:center;gap:10px;
1289
+ font-family:var(--mono);font-size:var(--fs-micro);letter-spacing:.24em;text-transform:uppercase;color:var(--mute);
1290
+ }
1291
+ .hero-cue span{display:block;width:34px;height:1px;background:linear-gradient(90deg,var(--blue),transparent);transform-origin:0 50%;animation:cue-sweep 3.4s var(--ease) infinite}
1292
+ @keyframes cue-sweep{0%,100%{transform:scaleX(.3);opacity:.4}50%{transform:scaleX(1);opacity:1}}
1293
+ .home-inner{z-index:2}
1294
+ .hero-installer{max-width:min(660px,100%)}
1295
+
1296
+ /* ── chapter 02 · the thesis passage (masked line reveal) ────────── */
1297
+ .thesis{
1298
+ position:relative;z-index:2;max-width:var(--max);margin:0 auto;
1299
+ padding:clamp(70px,16vh,190px) var(--pad) clamp(60px,14vh,160px);
1300
+ }
1301
+ .thesis-label{
1302
+ font-family:var(--mono);font-size:var(--fs-micro);letter-spacing:.34em;text-transform:uppercase;
1303
+ color:var(--blue);margin-bottom:clamp(28px,5vh,54px);
1304
+ }
1305
+ .thesis-lines{list-style:none;display:flex;flex-direction:column;gap:clamp(20px,3.4vh,40px);margin:0}
1306
+ .thesis-lines li{
1307
+ font-family:var(--display);font-weight:300;font-size:var(--fs-2xl);line-height:1.14;letter-spacing:-.02em;
1308
+ color:var(--ink);max-width:20ch;
1309
+ }
1310
+ .thesis-lines li em{font-style:italic;color:var(--blue2)}
1311
+ /* Alternating indents and widths: the eye travels rather than scanning a
1312
+ justified block, and the short lines carry the load-bearing claims. */
1313
+ .thesis-lines li:nth-child(even){margin-left:clamp(0px,9vw,150px)}
1314
+ .thesis-lines li:nth-child(3),
1315
+ .thesis-lines li:nth-child(4){max-width:28ch}
1316
+ .thesis-close{
1317
+ margin-top:clamp(36px,7vh,80px);margin-left:auto;max-width:34ch;
1318
+ font-family:var(--mono);font-size:var(--fs-xs);line-height:1.9;letter-spacing:.1em;
1319
+ text-transform:uppercase;color:var(--mute);text-align:right;
1320
+ }
1321
+ .premium-motion .thesis-lines li{opacity:.2}
1322
+ @media (max-width:720px){
1323
+ .thesis-lines{max-width:100%}
1324
+ .thesis-lines li{font-size:var(--fs-xl);max-width:100%}
1325
+ .thesis-lines li:nth-child(even){margin-left:0}
1326
+ .thesis-close{text-align:left;margin-left:0}
1327
+ }
1328
+
1329
+ /* ── chapter 03 · the instrument (pinned, scrubbed) ──────────────── */
1330
+ .stack-scene{max-width:min(1240px,100%);padding-bottom:0}
1331
+ .stack-run{position:relative}
1332
+ .premium-motion .stack-run{height:300vh}
1333
+ .stack-sticky{position:static;padding-block:clamp(8px,2vh,20px)}
1334
+ .premium-motion .stack-sticky{
1335
+ position:sticky;top:92px;min-height:calc(100dvh - 92px);
1336
+ display:flex;flex-direction:column;justify-content:center;
1337
+ }
1338
+ .stack-head{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:18px;align-items:end;margin-bottom:clamp(14px,2.4vh,26px)}
1339
+ .stack-head .section-title{margin-bottom:0;max-width:26ch;font-size:var(--fs-xl)}
1340
+ .stack-head .section-label{margin-bottom:8px}
1341
+ .stack-readout{
1342
+ font-family:var(--mono);font-size:var(--fs-micro);letter-spacing:.18em;text-transform:uppercase;
1343
+ color:var(--mute);text-align:right;line-height:1.9;white-space:nowrap;
1344
+ }
1345
+ .stack-readout b{display:block;color:var(--blue2);font-weight:500;font-size:var(--fs-sm);letter-spacing:.1em}
1346
+ .stack-layers{list-style:none;display:grid;gap:0;border-top:1px solid var(--line);margin:0}
1347
+ .stack-layer{
1348
+ position:relative;display:grid;grid-template-columns:auto minmax(0,1fr) auto;
1349
+ gap:clamp(14px,2.6vw,34px);align-items:center;
1350
+ padding:clamp(12px,1.7vh,20px) 0;border-bottom:1px solid var(--line);
1351
+ isolation:isolate;overflow:hidden;
1352
+ }
1353
+ .stack-layer .layer-ridge{
1354
+ position:absolute;inset:0;z-index:0;opacity:.9;
1355
+ -webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
1356
+ mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
1357
+ }
1358
+ .stack-layer > *:not(.layer-ridge){position:relative;z-index:1}
1359
+ .stack-idx{
1360
+ font-family:var(--mono);font-size:var(--fs-micro);letter-spacing:.2em;color:var(--blue);
1361
+ min-width:2.4em;
1362
+ }
1363
+ .stack-body{min-width:0}
1364
+ .stack-body h3{
1365
+ font-family:var(--display);font-weight:400;font-size:var(--fs-lg);line-height:1.04;letter-spacing:-.02em;
1366
+ color:var(--ink);margin-bottom:5px;
1367
+ }
1368
+ .stack-body p{color:var(--cool);font-size:var(--fs-sm);line-height:1.55;max-width:58ch;margin:0}
1369
+ .stack-sig{
1370
+ font-family:var(--mono);font-size:var(--fs-micro);letter-spacing:.14em;text-transform:uppercase;
1371
+ color:var(--mute);text-align:right;white-space:nowrap;
1372
+ border:1px solid var(--line);border-radius:999px;padding:6px 11px;
1373
+ transition:color .45s var(--ease),border-color .45s var(--ease);
1374
+ }
1375
+ .stack-layer.is-live .stack-sig{color:var(--blue2);border-color:var(--line-2)}
1376
+ .stack-layer.is-live .stack-body h3{color:#fff}
1377
+ .stack-meter{height:2px;background:var(--line);border-radius:2px;overflow:hidden;margin-top:clamp(14px,2.4vh,26px)}
1378
+ .stack-meter i{display:block;height:100%;width:100%;transform:scaleX(var(--stack-p,1));transform-origin:0 50%;
1379
+ background:linear-gradient(90deg,var(--blue),var(--hl))}
1380
+ @media (max-width:900px){
1381
+ .premium-motion .stack-run{height:auto}
1382
+ .premium-motion .stack-sticky{position:static}
1383
+ .stack-head{grid-template-columns:1fr}
1384
+ .stack-readout{text-align:left;white-space:normal}
1385
+ .stack-layer{grid-template-columns:auto minmax(0,1fr)}
1386
+ .stack-sig{grid-column:1/-1;justify-self:start;text-align:left;white-space:normal}
1387
+ /* A 900-unit ridge squeezed into a phone column reads as hatching over the
1388
+ copy rather than as depth. Drop it back to a texture. */
1389
+ .stack-layer .layer-ridge{opacity:.26}
1390
+ }
1391
+
1392
+ /* ── kinetic telemetry strip (velocity responsive) ───────────────── */
1393
+ .telemetry{
1394
+ position:relative;margin-top:clamp(26px,5vh,56px);border-block:1px solid var(--line);
1395
+ overflow:hidden;padding:14px 0;background:rgba(11,16,24,.4);
1396
+ -webkit-mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
1397
+ mask-image:linear-gradient(90deg,transparent,#000 8%,#000 92%,transparent);
1398
+ }
1399
+ .telemetry-track{
1400
+ display:flex;align-items:center;gap:clamp(20px,3vw,44px);width:max-content;
1401
+ transform:translate3d(var(--tele-x,0%),0,0) skewX(var(--kin-skew,0deg));
1402
+ transition:transform .38s var(--ease);will-change:transform;
1403
+ }
1404
+ .telemetry-track span{
1405
+ font-family:var(--mono);font-size:var(--fs-xs);letter-spacing:.2em;text-transform:uppercase;
1406
+ color:var(--cool);white-space:nowrap;
1407
+ }
1408
+ .telemetry-track span::before{content:"";display:inline-block;width:5px;height:5px;border-radius:50%;
1409
+ background:var(--blue);margin-right:12px;vertical-align:.14em;box-shadow:0 0 10px rgba(124,196,255,.7)}
1410
+ .telemetry-track span.k{color:var(--blue2)}
1411
+ .telemetry-track span.k::before{background:var(--hl);box-shadow:0 0 10px rgba(80,210,193,.7)}
1412
+ .marquee{transform:skewX(var(--kin-skew,0deg));transition:transform .42s var(--ease)}
1413
+
1414
+ /* ── sticky chapter tabs on the existing capability sections ─────── */
1415
+ .chapter-tab{
1416
+ position:sticky;top:84px;z-index:6;display:flex;width:fit-content;align-items:center;gap:12px;
1417
+ margin-bottom:clamp(14px,2.4vh,26px);padding:7px 14px 7px 10px;
1418
+ border:1px solid var(--line);border-radius:999px;background:rgba(11,16,24,.82);
1419
+ backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
1420
+ font-family:var(--mono);font-size:var(--fs-micro);letter-spacing:.2em;text-transform:uppercase;color:var(--mute);
1421
+ transition:border-color .5s var(--ease),color .5s var(--ease);
1422
+ }
1423
+ .chapter-tab b{
1424
+ display:grid;place-items:center;min-width:26px;height:20px;border-radius:999px;
1425
+ background:rgba(124,196,255,.12);color:var(--blue2);font-weight:500;letter-spacing:.08em;
1426
+ }
1427
+ .section.is-scene .chapter-tab{border-color:var(--line-2);color:var(--cool)}
1428
+
1429
+ /* ── chapter 06 · the close ──────────────────────────────────────── */
1430
+ .close-scene{
1431
+ position:relative;z-index:2;margin-top:clamp(60px,12vh,140px);
1432
+ padding:clamp(64px,13vh,150px) var(--pad) 0;overflow:hidden;
1433
+ }
1434
+ /* Sits low enough that both resolved lines run through the display title, not
1435
+ through the eyebrow above it, which a hairline made unreadable on phones. */
1436
+ .close-ridge{
1437
+ position:absolute;left:50%;top:clamp(28px,5vh,46px);width:min(1680px,150vw);height:clamp(200px,34vh,380px);
1438
+ transform:translateX(-50%);z-index:0;
1439
+ -webkit-mask-image:linear-gradient(180deg,transparent,#000 46%,transparent);
1440
+ mask-image:linear-gradient(180deg,transparent,#000 46%,transparent);
1441
+ }
1442
+ .close-inner{position:relative;z-index:1;max-width:var(--max);margin:0 auto}
1443
+ .close-eyebrow{font-family:var(--mono);font-size:var(--fs-micro);letter-spacing:.34em;text-transform:uppercase;color:var(--blue);margin-bottom:16px}
1444
+ .close-title{
1445
+ font-family:var(--display);font-weight:300;font-size:var(--fs-3xl);line-height:.96;letter-spacing:-.04em;
1446
+ max-width:16ch;margin-bottom:20px;
1447
+ }
1448
+ .close-title em{font-style:italic;color:var(--blue2)}
1449
+ .close-lede{max-width:50ch;color:var(--cool);font-size:var(--fs-base);line-height:1.7}
1450
+ .close-grid{
1451
+ display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,.75fr);
1452
+ gap:clamp(20px,4vw,54px);align-items:end;margin-top:clamp(26px,5vh,48px);
1453
+ }
1454
+ .close-cmds{display:flex;flex-direction:column;gap:12px;min-width:0}
1455
+ .close-cmd{
1456
+ display:flex;align-items:center;justify-content:space-between;gap:16px;min-width:0;
1457
+ border:1px solid var(--line-2);border-radius:var(--r-sm);padding:14px 16px;
1458
+ background:rgba(17,25,37,.9);
1459
+ }
1460
+ .close-cmd code{min-width:0;overflow-x:auto;white-space:nowrap;font-size:clamp(11px,1.3vw,15px);color:var(--blue2);scrollbar-width:none}
1461
+ .close-cmd code::-webkit-scrollbar{display:none}
1462
+ .close-cmd em{flex:none;font-style:normal;font-family:var(--mono);font-size:var(--fs-micro);letter-spacing:.14em;text-transform:uppercase;color:var(--mute)}
1463
+ .close-side{display:flex;flex-direction:column;gap:12px;min-width:0}
1464
+ .close-note{font-family:var(--mono);font-size:var(--fs-micro);letter-spacing:.14em;text-transform:uppercase;color:var(--mute);line-height:1.9}
1465
+ .close-scene .os-dl{margin-top:4px}
1466
+ /* The wordmark and footer used to follow the fees grid; behind the close they
1467
+ are tightened so the whole handoff — eyebrow, title, commands — fits the
1468
+ final resting viewport on a desktop instead of sliding under the nav. */
1469
+ .close-scene + .mega-oracle{margin-top:clamp(36px,5vw,60px)}
1470
+ .close-scene ~ footer{margin-top:clamp(52px,8vh,76px)}
1471
+ @media (max-width:860px){.close-grid{grid-template-columns:1fr;align-items:start}}
1472
+
1473
+ /* ── environment + failure posture ───────────────────────────────── */
1474
+ @media (max-width:900px){
1475
+ .marquee{transform:none}
1476
+ .telemetry-track{transform:translate3d(var(--tele-x,0%),0,0)}
1477
+ }
1478
+ @media (prefers-reduced-motion:reduce){
1479
+ .hero-cue span{animation:none;transform:scaleX(1)}
1480
+ .premium-motion .thesis-lines li{opacity:1}
1481
+ .telemetry-track,.marquee{transform:none;transition:none}
1482
+ .stack-sticky,.premium-motion .stack-sticky{position:static}
1483
+ .premium-motion .stack-run{height:auto}
1484
+ .chapter-tab{position:static}
1485
+ .stack-meter i{transform:scaleX(1)}
1486
+ }
1231
1487
  </style>
1232
1488
  </head>
1233
1489
  <body>
1234
1490
  <div class="grain" aria-hidden="true"></div>
1491
+ <!-- Signal-ridge geometry, drawn once and re-used by the hero, the instrument
1492
+ and the close. rg0 is raw noise; each successive line is the same field
1493
+ resolved further, until rg4 is a single routed signal. Original curves,
1494
+ generated deterministically for this page. -->
1495
+ <svg class="ridge-defs" aria-hidden="true" focusable="false"><defs>
1496
+ <path id="rg0" d="M0 114.9C4.4 114.6 17.6 114.7 26.5 113.1C35.3 111.6 44.1 106.6 52.9 105.6C61.8 104.7 70.6 111.2 79.4 107.3C88.2 103.5 97.1 81.5 105.9 82.3C114.7 83.2 123.5 100 132.4 112.3C141.2 124.7 150 156.2 158.8 156.3C167.6 156.4 176.5 121.5 185.3 113.1C194.1 104.6 202.9 104.4 211.8 105.7C220.6 106.9 229.4 118.7 238.2 120.8C247.1 122.8 255.9 124.2 264.7 117.9C273.5 111.6 282.4 82.1 291.2 83C300 84 308.8 120.9 317.6 123.7C326.5 126.5 335.3 103.8 344.1 99.7C352.9 95.5 361.8 90.4 370.6 98.6C379.4 106.7 388.2 140.5 397.1 148.6C405.9 156.6 414.7 148.7 423.5 146.9C432.4 145 441.2 141 450 137.5C458.8 134 467.6 127.6 476.5 126C485.3 124.4 494.1 130.8 502.9 127.8C511.8 124.8 520.6 104.1 529.4 108.1C538.2 112.1 547.1 152 555.9 151.8C564.7 151.5 573.5 113.9 582.4 106.7C591.2 99.5 600 105.8 608.8 108.7C617.6 111.5 626.5 128.1 635.3 123.8C644.1 119.5 652.9 89.1 661.8 83C670.6 76.8 679.4 85.5 688.2 86.7C697.1 87.9 705.9 82.4 714.7 90.2C723.5 98 732.4 131.2 741.2 133.5C750 135.8 758.8 103.1 767.6 104.2C776.5 105.2 785.3 130.8 794.1 139.8C802.9 148.9 811.8 166.4 820.6 158.6C829.4 150.8 838.2 107.6 847.1 92.9C855.9 78.1 864.7 63 873.5 70.1C882.4 77.2 895.6 124.6 900 135.5"/>
1497
+ <path id="rg1" d="M0 217.4C5.8 217.9 23.1 225.2 34.6 220.2C46.2 215.3 57.7 189.3 69.2 187.5C80.8 185.6 92.3 205.2 103.8 208.9C115.4 212.5 126.9 207.9 138.5 209.3C150 210.7 161.5 218.9 173.1 217.4C184.6 216 196.2 207.8 207.7 200.7C219.2 193.6 230.8 177.9 242.3 175C253.8 172.2 265.4 173.9 276.9 183.7C288.5 193.5 300 232.7 311.5 234C323.1 235.4 334.6 193.8 346.2 191.8C357.7 189.9 369.2 216 380.8 222.3C392.3 228.6 403.8 237.5 415.4 229.5C426.9 221.4 438.5 182.1 450 174.2C461.5 166.3 473.1 177.3 484.6 182.2C496.2 187.1 507.7 202.8 519.2 203.4C530.8 204 542.3 182 553.8 185.7C565.4 189.5 576.9 223.6 588.5 226C600 228.4 611.5 206.9 623.1 200.3C634.6 193.7 646.2 192.3 657.7 186.4C669.2 180.5 680.8 160.8 692.3 164.8C703.8 168.8 715.4 209.4 726.9 210.4C738.5 211.4 750 171.2 761.5 170.7C773.1 170.2 784.6 200.8 796.2 207.1C807.7 213.5 819.2 214.6 830.8 208.8C842.3 203 853.8 172.1 865.4 172.3C876.9 172.6 894.2 203.9 900 210.2"/>
1498
+ <path id="rg2" d="M0 252.1C7.5 249.8 30 234.9 45 237.9C60 240.9 75 268.6 90 270.1C105 271.6 120 248 135 246.9C150 245.8 165 263.2 180 263.6C195 264 210 249.9 225 249.5C240 249 255 263.5 270 260.7C285 257.9 300 236.2 315 232.8C330 229.4 345 238.8 360 240.3C375 241.9 390 242.8 405 242.1C420 241.4 435 238.5 450 236C465 233.5 480 226 495 227.3C510 228.6 525 244.2 540 243.9C555 243.7 570 229.9 585 225.8C600 221.7 615 220.2 630 219.4C645 218.6 660 221 675 221.1C690 221.1 705 215.5 720 219.5C735 223.5 750 242.4 765 245C780 247.6 795 237.1 810 235.1C825 233.1 840 229.3 855 232.9C870 236.4 892.5 252.6 900 256.5"/>
1499
+ <path id="rg3" d="M0 313.2C10.7 311.1 42.9 301.9 64.3 300.8C85.7 299.7 107.1 307.9 128.6 306.5C150 305.2 171.4 293.6 192.9 292.7C214.3 291.8 235.7 300.8 257.1 301.1C278.6 301.4 300 294.8 321.4 294.7C342.9 294.6 364.3 300.6 385.7 300.4C407.1 300.2 428.6 293.8 450 293.5C471.4 293.3 492.9 298.3 514.3 298.9C535.7 299.5 557.1 296.2 578.6 297.1C600 298 621.4 303.1 642.9 304.2C664.3 305.3 685.7 303 707.1 303.8C728.6 304.5 750 307.8 771.4 308.7C792.9 309.5 814.3 309.1 835.7 308.8C857.1 308.6 889.3 307.4 900 307.1"/>
1500
+ <path id="rg4" d="M0 335.6C16.7 335.9 66.7 337.2 100 337.7C133.3 338.3 166.7 338.1 200 338.8C233.3 339.4 266.7 340.4 300 341.4C333.3 342.3 366.7 343.5 400 344.3C433.3 345.2 466.7 346.2 500 346.5C533.3 346.8 566.7 346.7 600 346.2C633.3 345.7 666.7 344.1 700 343.3C733.3 342.5 766.7 342.3 800 341.5C833.3 340.7 883.3 339 900 338.5"/>
1501
+ </defs></svg>
1235
1502
  <div class="progress" id="progress" aria-hidden="true"></div>
1236
1503
  <div class="scroll-craft" aria-hidden="true">
1237
1504
  <div class="craft-grid"></div>
@@ -1277,17 +1544,25 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1277
1544
  <div class="veil" aria-hidden="true"></div>
1278
1545
 
1279
1546
  <section class="home" id="home">
1547
+ <svg class="ridge hero-ridge" viewBox="0 40 900 340" preserveAspectRatio="none" aria-hidden="true" focusable="false">
1548
+ <g class="rg rg-0"><use href="#rg0"/></g>
1549
+ <g class="rg rg-1"><use href="#rg1"/></g>
1550
+ <g class="rg rg-2"><use href="#rg2"/></g>
1551
+ <g class="rg rg-3"><use href="#rg3"/></g>
1552
+ <g class="rg rg-4"><use href="#rg4"/></g>
1553
+ </svg>
1280
1554
  <div class="home-inner">
1281
1555
  <div class="hero-split">
1282
1556
  <div class="hero-lede">
1557
+ <p class="hero-index rv"><b>01</b> <i></i> the premise</p>
1283
1558
  <p class="home-kicker rv">self-custody agent control</p>
1284
- <h1 class="home-title rv" data-split>Trade every chain<br>from <em>one</em> agent</h1>
1285
- <p class="hero-sub rv">Hyperliquid, EVM, Bitcoin, Solana, Stable and Robinhood Chain in a single control plane. Oracle reads state, prices routes and prepares the transaction. Your wallet signs it.</p>
1559
+ <h1 class="home-title rv" data-split>Trade across chains<br>from <em>one</em> agent</h1>
1560
+ <p class="hero-sub rv">Eleven built-in EVM chains, Solana, Bitcoin, Canton reads and the Polymarket venue share one control plane; registered EVM chains extend it. Hosted Oracle reads state, prices routes and prepares unsigned artifacts without receiving a key. Your wallet signs.</p>
1286
1561
  <div class="home-actions">
1287
1562
  <a class="enter-cta primary" href="#cli">Download</a>
1288
1563
  <a class="enter-cta ghost" href="#cli">See the CLI</a>
1289
1564
  </div>
1290
- <p class="hero-note-line">macOS · Windows · Linux &nbsp;/&nbsp; desktop app or public CLI</p>
1565
+ <p class="hero-note-line"><span>macOS · Windows · Linux</span><i class="hero-note-sep" aria-hidden="true">·</i><span>desktop app or public CLI</span></p>
1291
1566
  </div>
1292
1567
 
1293
1568
  <figure class="hero-product">
@@ -1341,11 +1616,102 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1341
1616
  <div class="home-stat"><b id="hero-protocol-count" data-count="221">221</b><span>protocols / venues wired</span></div>
1342
1617
  <div class="home-stat"><b id="hero-provider-count" data-count="134">134</b><span>data providers</span></div>
1343
1618
  <div class="home-stat"><b id="hero-op-count" data-count="594">594</b><span>data operations</span></div>
1344
- <div class="home-stat"><b id="hero-chain-count">15 + EVM</b><span>chains wired</span></div>
1619
+ <div class="home-stat"><b id="hero-chain-count">15 + EVM</b><span>working chain / venue surfaces</span></div>
1620
+ </div>
1621
+ <p class="hero-cue" aria-hidden="true"><span></span> scroll · 02 the read</p>
1622
+ </div>
1623
+ </section>
1624
+
1625
+ <!-- ── 02 · the thesis. A deliberately quiet passage: big type, long gaps,
1626
+ one claim per line. The lines dim until the scroll reaches them, so
1627
+ reading pace and scroll pace are the same thing. ── -->
1628
+ <section class="thesis" id="thesis" aria-labelledby="thesis-title">
1629
+ <p class="thesis-label rv" id="thesis-title">02 — the read</p>
1630
+ <ol class="thesis-lines">
1631
+ <li>A market emits noise continuously.</li>
1632
+ <li>Most tooling hands you <em>more of it.</em></li>
1633
+ <li>Oracle reads the state first — balances, positions, pools, books, venue status.</li>
1634
+ <li>Then it prices routes against each other and holds every value-moving path against policy you set on your own machine.</li>
1635
+ <li>What comes out is an <em>unsigned</em> action you can read before it exists.</li>
1636
+ </ol>
1637
+ <p class="thesis-close rv">Oracle prepares.<br>Your wallet signs.<br>Broadcast stays behind explicit arming.</p>
1638
+ </section>
1639
+
1640
+ <!-- ── 03 · the instrument. The frame pins and the five capability layers
1641
+ resolve on scrub, each sitting on its own ridge line: raw noise at
1642
+ the top, a single routed signal at the bottom. Without JS the frame
1643
+ is a normal static list and every layer is already legible. ── -->
1644
+ <section class="section stack-scene" id="resolve" aria-labelledby="resolve-title">
1645
+ <div class="stack-run">
1646
+ <div class="stack-sticky">
1647
+ <div class="stack-head">
1648
+ <div>
1649
+ <p class="section-label rv">03 — the instrument</p>
1650
+ <h2 class="section-title" id="resolve-title" data-split>Noise in. <em>Structure out.</em></h2>
1651
+ </div>
1652
+ <p class="stack-readout"><b data-stack-stage>read</b>five layers · one handoff</p>
1653
+ </div>
1654
+ <ol class="stack-layers">
1655
+ <li class="stack-layer" data-stack-layer="0" data-stage="read">
1656
+ <svg class="ridge layer-ridge" viewBox="0 56 900 120" preserveAspectRatio="none" aria-hidden="true" focusable="false"><g class="rg rg-0"><use href="#rg0"/></g></svg>
1657
+ <div class="stack-idx">01</div>
1658
+ <div class="stack-body">
1659
+ <h3>Read</h3>
1660
+ <p>Portfolio, markets, positions, pools, NFTs, ordinals and venue state are pulled from public RPCs and venue APIs before anything is proposed.</p>
1661
+ </div>
1662
+ <div class="stack-sig">state before opinion</div>
1663
+ </li>
1664
+ <li class="stack-layer" data-stack-layer="1" data-stage="route">
1665
+ <svg class="ridge layer-ridge" viewBox="0 137 900 120" preserveAspectRatio="none" aria-hidden="true" focusable="false"><g class="rg rg-1"><use href="#rg1"/></g></svg>
1666
+ <div class="stack-idx">02</div>
1667
+ <div class="stack-body">
1668
+ <h3>Route</h3>
1669
+ <p>Quotes and bridges normalize into comparable intents, then rank net of cost — so a cheaper headline price with worse slippage cannot win by looking good.</p>
1670
+ </div>
1671
+ <div class="stack-sig">ranked net of cost</div>
1672
+ </li>
1673
+ <li class="stack-layer" data-stack-layer="2" data-stage="bound">
1674
+ <svg class="ridge layer-ridge" viewBox="0 184 900 120" preserveAspectRatio="none" aria-hidden="true" focusable="false"><g class="rg rg-2"><use href="#rg2"/></g></svg>
1675
+ <div class="stack-idx">03</div>
1676
+ <div class="stack-body">
1677
+ <h3>Bound</h3>
1678
+ <p>Chain, spender, destination, amount, TTL and simulation posture are checked locally. Unconfigured means refused; an empty allowlist refuses everything.</p>
1679
+ </div>
1680
+ <div class="stack-sig">fail closed</div>
1681
+ </li>
1682
+ <li class="stack-layer" data-stack-layer="3" data-stage="prepare">
1683
+ <svg class="ridge layer-ridge" viewBox="0 244 900 120" preserveAspectRatio="none" aria-hidden="true" focusable="false"><g class="rg rg-3"><use href="#rg3"/></g></svg>
1684
+ <div class="stack-idx">04</div>
1685
+ <div class="stack-body">
1686
+ <h3>Prepare</h3>
1687
+ <p>The output is an unsigned artifact: what you receive, the expected cost, the calldata shape and which app is being granted permission.</p>
1688
+ </div>
1689
+ <div class="stack-sig">unsigned artifact</div>
1690
+ </li>
1691
+ <li class="stack-layer" data-stack-layer="4" data-stage="sign">
1692
+ <svg class="ridge layer-ridge" viewBox="0 281 900 120" preserveAspectRatio="none" aria-hidden="true" focusable="false"><g class="rg rg-4"><use href="#rg4"/></g></svg>
1693
+ <div class="stack-idx">05</div>
1694
+ <div class="stack-body">
1695
+ <h3>Sign</h3>
1696
+ <p>Your wallet closes the loop. Prepare is not sign, sign is not broadcast, and broadcast needs explicit arming and local signer approval.</p>
1697
+ </div>
1698
+ <div class="stack-sig">you sign</div>
1699
+ </li>
1700
+ </ol>
1701
+ <div class="stack-meter" aria-hidden="true"><i></i></div>
1702
+ </div>
1703
+ </div>
1704
+ <div class="telemetry" aria-hidden="true">
1705
+ <div class="telemetry-track">
1706
+ <span>read state</span><span>price routes</span><span>simulate</span><span class="k">bound by policy</span><span>prepare unsigned</span><span class="k">you sign</span><span>self custody</span><span>no hosted keys</span><span>fail closed</span><span>local signer</span><span>receipts</span>
1707
+ <span>read state</span><span>price routes</span><span>simulate</span><span class="k">bound by policy</span><span>prepare unsigned</span><span class="k">you sign</span><span>self custody</span><span>no hosted keys</span><span>fail closed</span><span>local signer</span><span>receipts</span>
1708
+ <span>read state</span><span>price routes</span><span>simulate</span><span class="k">bound by policy</span><span>prepare unsigned</span><span class="k">you sign</span><span>self custody</span><span>no hosted keys</span><span>fail closed</span><span>local signer</span><span>receipts</span>
1345
1709
  </div>
1346
1710
  </div>
1347
1711
  </section>
1712
+
1348
1713
  <section class="section" id="orchestration">
1714
+ <p class="chapter-tab"><b>04</b> the control plane</p>
1349
1715
  <p class="section-label rv">Profiles</p>
1350
1716
  <h2 class="section-title rv" data-split>Multi-profile. <em>Customizable.</em></h2>
1351
1717
  <p class="section-lede rv">Input hits the Oracle control plane and routes across venue profiles, multi-chain EVM, Bitcoin, Solana, and the protocol builder. Any MCP harness drives a single agent.</p>
@@ -1421,7 +1787,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1421
1787
  <div class="tag">profile</div>
1422
1788
  <div class="name">hyperliquid agent</div>
1423
1789
  <div class="sub">perps · hip-3/4 · funding</div>
1424
- <div class="chains"><span class="ch">Hyperliquid <img src="https://icons.llamao.fi/icons/protocols/hyperliquid?w=24&h=24" alt="" loading="lazy"></span><span class="ch">Hyperliquid 999 <img src="https://icons.llamao.fi/icons/chains/rsz_hyperliquid?w=24&h=24" alt="" loading="lazy"></span></div>
1790
+ <div class="chains"><span class="ch">Hyperliquid <img src="https://icons.llamao.fi/icons/protocols/hyperliquid?w=24&h=24" alt="" loading="lazy"></span><span class="ch">HyperEVM 999 <img src="https://icons.llamao.fi/icons/chains/rsz_hyperliquid?w=24&h=24" alt="" loading="lazy"></span></div>
1425
1791
  </div>
1426
1792
  <div class="node route p-rh">
1427
1793
  <div class="tag">profile</div>
@@ -1502,11 +1868,11 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1502
1868
  <article class="route-card p-hl">
1503
1869
  <div class="where">hyperliquid agent →</div>
1504
1870
  <h3>Hyperliquid <img src="https://icons.llamao.fi/icons/protocols/hyperliquid?w=40&h=40" alt="Hyperliquid" loading="lazy"></h3>
1505
- <p>Native perps, HIP-3/4 asset resolve, funding, event risk, and Hyperliquid when you need HL's EVM surface.</p>
1871
+ <p>Native perps, HIP-3/4 asset resolve, funding, event risk, and HyperEVM when you need HL's EVM surface.</p>
1506
1872
  <div class="chips">
1507
1873
  <span class="chip-s">perps</span>
1508
1874
  <span class="chip-s">HIP-3/4</span>
1509
- <span class="chip-s">Hyperliquid</span>
1875
+ <span class="chip-s">HyperEVM</span>
1510
1876
  </div>
1511
1877
  </article>
1512
1878
  <article class="route-card p-rh">
@@ -1553,7 +1919,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1553
1919
  <article class="route-card p-nft">
1554
1920
  <div class="where">nft agent →</div>
1555
1921
  <h3>Cross-chain NFTs <img src="assets/protocols/opensea.png" alt="OpenSea" loading="lazy"></h3>
1556
- <p>List across 22 EVM chains and Solana via OpenSea, Ordinals via Satflow with proven PSBT provenance, Solana via Magic Eden. Floors, holdings and PnL read first, then prepared for your signature.</p>
1922
+ <p>Research floors, holdings and PnL across 26 OpenSea chains; prepare OpenSea list, mint and cancel on six EVM networks. Ordinals via Satflow with proven PSBT provenance, Solana via Magic Eden. Reads come first, then artifacts prepared for your signature.</p>
1557
1923
  <div class="chips">
1558
1924
  <span class="chip-s">list</span>
1559
1925
  <span class="chip-s">buy</span>
@@ -1584,8 +1950,8 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1584
1950
  </div>
1585
1951
  </div>
1586
1952
  <figure class="build-bench">
1587
- <img src="assets/protocol-build-time.jpg" width="1280" height="720" alt="EVM protocol build time benchmark: Codex and Claude with Oracle versus a plain harness on a gated safe ERC-721 drop. Quality gate 24/24. One controlled trial." loading="lazy" decoding="async">
1588
- <figcaption>identical prompt · clean tool isolation · own tests green · 24/24 hidden acceptance</figcaption>
1953
+ <img src="assets/protocol-build-time.jpg" width="1280" height="720" alt="Captured EVM protocol build-time comparison for a safe ERC-721 drop using Oracle-assisted and plain harness runs in one controlled trial." loading="lazy" decoding="async">
1954
+ <figcaption>captured controlled comparison · safe ERC-721 drop · repository benchmark asset</figcaption>
1589
1955
  </figure>
1590
1956
  </div>
1591
1957
  </article>
@@ -1607,8 +1973,8 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1607
1973
  </article>
1608
1974
  <article class="moat-card">
1609
1975
  <div class="n">bounded surfaces</div>
1610
- <h3>Three local-signer lanes, each with its own decoder</h3>
1611
- <p>evm, btc, sol transfers. Hyperliquid, Polymarket, swaps, and bridges stay wallet-signed. Each lane decodes its own envelope and proves every value-moving field. CEX execution ships sealed — order routing with Coinbase order paths pinned.</p>
1976
+ <h3>Bounded signer families with format-specific decoders</h3>
1977
+ <p>The optional self-hosted loopback signer decodes bounded native EVM transfers, recognized approvals, strict EVM swap and bridge calldata, EVM NFT mint envelopes, Bitcoin PSBTs, and Solana messages. It acts only after owner arming and an exact grant; hosted/keyless Oracle never receives a key. Separately installed same-host executors may expose additional exact actions under their own owner policy.</p>
1612
1978
  </article>
1613
1979
  <article class="moat-card">
1614
1980
  <div class="n">evidence</div>
@@ -1618,14 +1984,14 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1618
1984
  <article class="moat-card">
1619
1985
  <div class="n">fail closed</div>
1620
1986
  <h3>Unconfigured means refused</h3>
1621
- <p>A fresh install signs nothing. Destination allowlists stop silent router drift; empty allowlists refuse everything until you add entries. Tenant RBAC scopes who may prepare what; governance votes prepare unsigned.</p>
1987
+ <p>A fresh install signs nothing. Prepare is not sign, and sign is not broadcast. Destination allowlists stop silent router drift; empty allowlists refuse everything until you add entries. Tenant RBAC scopes who may prepare what; governance votes prepare unsigned.</p>
1622
1988
  </article>
1623
1989
  </div>
1624
1990
 
1625
1991
  <div class="selfcustody rv">
1626
1992
  <p class="section-label rv">Works in any harness</p>
1627
1993
  <h2 class="section-title rv" data-split>Ask in <em>your</em> agent.</h2>
1628
- <p class="section-lede rv">Oracle installs as an MCP server — Claude, Codex, Cursor and the rest get Oracle skills, live swap cards, quotes, and prepare. With <code>oracle signer</code> armed, fills queue for your ack and clear through the local signer, same path as Telegram Allow. Keys stay here. You authorize.</p>
1994
+ <p class="section-lede rv">Oracle installs into supported MCP clients for skills, quotes, cards, and unsigned prepare. Prepare is not sign, and sign is not broadcast. The optional self-hosted local signer (<code>oracle signer</code>) is loopback-only, owner-policy and exact-grant bounded; hosted/keyless Oracle receives no key.</p>
1629
1995
  <div class="agent-install rv">
1630
1996
  <span>Add Oracle to your agent:</span>
1631
1997
  <div class="install-cmds">
@@ -1635,10 +2001,9 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1635
2001
  <button class="btn btn-cursor" onclick="navigator.clipboard.writeText('oracle mcp install cursor');var b=this;b.textContent='Copied ✓';setTimeout(function(){b.textContent='Cursor'},1500)">Cursor</button>
1636
2002
  <button class="btn btn-vscode" onclick="navigator.clipboard.writeText('oracle mcp install claude-desktop');var b=this;b.textContent='Copied ✓';setTimeout(function(){b.textContent='Claude Desktop'},1500)">Claude Desktop</button>
1637
2003
  <button class="btn btn-copilot" onclick="navigator.clipboard.writeText('oracle mcp install codex');var b=this;b.textContent='Copied ✓';setTimeout(function(){b.textContent='Codex'},1500)">Codex</button>
1638
- <button class="btn" onclick="navigator.clipboard.writeText('oracle mcp install generic');var b=this;b.textContent='Copied ✓';setTimeout(function(){b.textContent='Hermes'},1500)">Hermes</button>
1639
- <button class="btn" onclick="navigator.clipboard.writeText('oracle mcp install generic');var b=this;b.textContent='Copied ✓';setTimeout(function(){b.textContent='OpenClaw'},1500)">OpenClaw</button>
1640
- <button class="btn" onclick="navigator.clipboard.writeText('oracle mcp install generic');var b=this;b.textContent='Copied ✓';setTimeout(function(){b.textContent='Perplexity'},1500)">Perplexity</button>
1641
- <button class="btn" onclick="navigator.clipboard.writeText('oracle mcp install generic');var b=this;b.textContent='Copied ✓';setTimeout(function(){b.textContent='Manus'},1500)">Manus</button>
2004
+ <button class="btn" onclick="navigator.clipboard.writeText('oracle mcp install copilot');var b=this;b.textContent='Copied ✓';setTimeout(function(){b.textContent='Copilot'},1500)">Copilot</button>
2005
+ <button class="btn" onclick="navigator.clipboard.writeText('oracle mcp install vscode');var b=this;b.textContent='Copied ✓';setTimeout(function(){b.textContent='VS Code'},1500)">VS Code</button>
2006
+ <button class="btn" onclick="navigator.clipboard.writeText('oracle mcp install generic');var b=this;b.textContent='Copied ✓';setTimeout(function(){b.textContent='Generic MCP'},1500)">Generic MCP</button>
1642
2007
  </div>
1643
2008
  <p class="cmd-hint">Click copies the install command — paste it in your terminal</p>
1644
2009
  </div>
@@ -1680,7 +2045,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1680
2045
  <span class="cx-eff">High</span>
1681
2046
  <span class="cx-ring"></span>
1682
2047
  </div>
1683
- <p class="agent-out" hidden>best route across 5 aggregators &middot; quoted live &middot; <b>unsigned</b> &mdash; your wallet signs</p>
2048
+ <p class="agent-out" hidden>best route across available source adapters &middot; quoted live &middot; <b>unsigned</b> &mdash; your wallet signs</p>
1684
2049
  <noscript><p class="agent-ask">move 5k usdc into weth, cheapest route</p></noscript>
1685
2050
  </figure>
1686
2051
  </div>
@@ -1730,7 +2095,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1730
2095
  <div class="selfcustody-grid">
1731
2096
  <div>
1732
2097
  <h4>Everything runs on your machine</h4>
1733
- <p>The CLI and the desktop app are the whole product. No Oracle account, no hosted wallet, no broker server. Reads go straight to public RPCs and venue APIs.</p>
2098
+ <p>The CLI and desktop app are public clients. Hosted/keyless services may read and prepare unsigned artifacts, but they receive no wallet key. Signing stays with your wallet or an optional owner-operated local signer.</p>
1734
2099
  </div>
1735
2100
  <div>
1736
2101
  <h4>Hosted keys never reach Oracle</h4>
@@ -1764,11 +2129,11 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1764
2129
  </div>
1765
2130
  <div class="atlas-copy">
1766
2131
  <div class="atlas-count"><span id="atlas-protocol-count">110</span></div>
1767
- <p class="atlas-sub">Source-backed roster stays in the runtime. The landing page shows the control system, not a grocery list.</p>
2132
+ <p class="atlas-sub">Featured logo-rail subset. The source-backed 221 protocol and venue total remains in the hero.</p>
1768
2133
  <div class="atlas-ledger">
1769
2134
  <div><span>quote / route</span><b id="atlas-route-count">0</b></div>
1770
2135
  <div><span>prepare / policy</span><b id="atlas-prepare-count">0</b></div>
1771
- <div><span>chains</span><b id="atlas-chain-count">13 + EVM</b></div>
2136
+ <div><span>featured chains</span><b id="atlas-chain-count">13</b></div>
1772
2137
  <div><span>custody</span><b>self</b></div>
1773
2138
  </div>
1774
2139
  </div>
@@ -1804,7 +2169,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1804
2169
  <source src="assets/hero/agent-session.webm" type="video/webm">
1805
2170
  <source src="assets/hero/agent-session.mp4" type="video/mp4">
1806
2171
  </video>
1807
- <img id="route-still" src="assets/hero/agent-session-poster.jpg" alt="Oracle preparing 500 USDC to 6.14 HYPE on HyperEVM via LI.FI, ranked net of cost, awaiting signature" width="1280" height="720" loading="lazy" decoding="async">
2172
+ <img id="route-still" src="assets/hero/agent-session-poster.jpg" alt="Oracle agent session showing a route comparison, NFT mint pipeline, and protocol scaffold awaiting user review" width="1280" height="720" loading="lazy" decoding="async">
1808
2173
  <figcaption>swap · mint · scaffold · you sign</figcaption>
1809
2174
  </figure>
1810
2175
  <figure class="route-proof rv" style="margin-top:18px">
@@ -1960,6 +2325,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1960
2325
  </div>
1961
2326
 
1962
2327
  <section class="section" id="chains">
2328
+ <p class="chapter-tab"><b>05</b> the surface area</p>
1963
2329
  <p class="section-label rv">Chains</p>
1964
2330
  <h2 class="section-title rv" data-split>Where you can <em>operate.</em></h2>
1965
2331
  <p class="section-lede rv">Every built-in EVM chain exposes the full scanner set. <b>Route</b> means Oracle can price and prepare a swap there. Register any extra EVM chain with a chain id and an RPC; unsupported paths fail closed.</p>
@@ -1977,8 +2343,9 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
1977
2343
  </div>
1978
2344
  </section>
1979
2345
  <section class="section cli-section" id="cli">
2346
+ <p class="chapter-tab"><b>06</b> the product</p>
1980
2347
  <p class="section-label rv">Oracle CLI</p>
1981
- <h2 class="section-title rv" data-split>One surface. <em>Every chain.</em></h2>
2348
+ <h2 class="section-title rv" data-split>One surface. <em>Working chain intelligence.</em></h2>
1982
2349
  <div class="cli-install rv">
1983
2350
  <div class="cli-install-cmd"><code>curl -fL https://oracle.demi.la/install.sh | bash</code> <span class="cli-install-hint">then oracle setup model && oracle chat</span></div>
1984
2351
  </div>
@@ -2004,7 +2371,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
2004
2371
  </div>
2005
2372
  <h2 class="section-title app-shot-title">Oracle Desktop App <sup style="font-size:14px;color:var(--blue);font-weight:400">beta</sup></h2>
2006
2373
  <figure class="app-shot">
2007
- <img src="assets/desktop-app.jpg?v=20260830" width="1280" height="860" loading="lazy" decoding="async" alt="Oracle desktop 0.4.14 setup: connect Claude, Codex or Grok, local llama.cpp or Ollama, then pick model and chain.">
2374
+ <img src="assets/desktop-app.jpg?v=20260830" width="1280" height="860" loading="lazy" decoding="async" alt="Oracle desktop 0.4.16 setup: connect Claude, Codex or Grok, local llama.cpp or Ollama, then pick model and chain.">
2008
2375
  <figcaption>Native desktop. Connect a provider, then chat.</figcaption>
2009
2376
  </figure>
2010
2377
  <div class="os-dl">
@@ -2015,6 +2382,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
2015
2382
  </section>
2016
2383
 
2017
2384
  <section class="section" id="fees">
2385
+ <p class="chapter-tab"><b>07</b> what it costs</p>
2018
2386
  <p class="section-label rv">Fees</p>
2019
2387
  <h2 class="section-title rv" data-split>5 bps. <em>Holders zero.</em></h2>
2020
2388
  <p class="section-lede rv">5 basis points (0.05%) on swaps Oracle routes. Eligible Hyperliquid orders can add a 1–2 bps builder fee after wallet approval. Both show before you sign.</p>
@@ -2043,6 +2411,35 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
2043
2411
  </div>
2044
2412
  </section>
2045
2413
 
2414
+ <!-- ── 08 · the close. The ridge that opened the page arrives resolved: the
2415
+ noisy layers have collapsed into the single routed line, and the only
2416
+ thing left to do is the same install action the hero offered. ── -->
2417
+ <section class="close-scene" id="close" aria-labelledby="close-title">
2418
+ <svg class="ridge close-ridge" viewBox="0 240 900 140" preserveAspectRatio="none" aria-hidden="true" focusable="false">
2419
+ <g class="rg rg-3"><use href="#rg3"/></g>
2420
+ <g class="rg rg-4"><use href="#rg4"/></g>
2421
+ </svg>
2422
+ <div class="close-inner">
2423
+ <p class="close-eyebrow rv">08 — the handoff</p>
2424
+ <h2 class="close-title" id="close-title" data-split>Read the chain. <em>Sign your own</em> transactions.</h2>
2425
+ <p class="close-lede rv">One install puts the whole control plane on your machine — CLI, desktop app, or as an MCP server inside the agent you already use. No Oracle account, no hosted wallet.</p>
2426
+ <div class="close-grid">
2427
+ <div class="close-cmds rv">
2428
+ <div class="close-cmd"><code>curl -fL https://oracle.demi.la/install.sh | bash</code><em>macOS · Linux</em></div>
2429
+ <div class="close-cmd"><code>iex (irm https://oracle.demi.la/install.ps1)</code><em>Windows</em></div>
2430
+ <div class="os-dl">
2431
+ <a class="os-link" href="/downloads/artifacts/Oracle-0.4.16.AppImage">Linux AppImage</a>
2432
+ <a class="os-link" href="/downloads/artifacts/Oracle-0.4.16-arm64.dmg">macOS DMG</a>
2433
+ <a class="os-link" href="/downloads/artifacts/Oracle-Setup-0.4.16.exe">Windows Setup</a>
2434
+ </div>
2435
+ </div>
2436
+ <div class="close-side rv">
2437
+ <p class="close-note">then <code>oracle setup model</code><br>then <code>oracle chat</code></p>
2438
+ <p class="close-note">reads run locally<br>keys never leave your machine<br>a fresh install signs nothing</p>
2439
+ </div>
2440
+ </div>
2441
+ </div>
2442
+ </section>
2046
2443
  <div class="mega-oracle rv" aria-hidden="true">oracle</div>
2047
2444
  <footer>
2048
2445
  <div class="foot-row">
@@ -2063,28 +2460,40 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
2063
2460
  </footer>
2064
2461
 
2065
2462
  <script>
2066
- // Load optional animation libraries in background — page works without them
2463
+ // Load optional animation libraries in background — page works without them.
2464
+ //
2465
+ // The libraries are vendored, not pulled from a CDN. This page carries the
2466
+ // install commands and download links for a wallet-adjacent tool, so no
2467
+ // third-party origin may execute code here. Each file is byte-identical to
2468
+ // the published npm artifact (gsap@3.13.0/dist, lenis@1.3.11/dist); the SRI
2469
+ // hash pins that, and a mismatch degrades to the static page, never to a
2470
+ // different script.
2067
2471
  (function loadExtras(){
2068
- var s1 = document.createElement("script");
2069
- s1.src = "https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/gsap.min.js";
2070
- var s2 = document.createElement("script");
2071
- s2.src = "https://cdn.jsdelivr.net/npm/gsap@3.13.0/dist/ScrollTrigger.min.js";
2072
- var s3 = document.createElement("script");
2073
- s3.src = "https://cdn.jsdelivr.net/npm/lenis@1.3.11/dist/lenis.min.js";
2074
- var loaded = 0;
2075
- function onLoad(){
2076
- loaded++;
2077
- if (loaded === 3) {
2472
+ var libs = [
2473
+ ["assets/vendor/gsap-3.13.0.min.js", "sha384-ZQM47dxemavqCeTvz4hdNVKt+v4pKNkIrfmve4Tz/dQ0N5JJ2LCG5fIrdbu3MTRn"],
2474
+ ["assets/vendor/gsap-scrolltrigger-3.13.0.min.js", "sha384-8OvHTRXcQvo7eXlNE8pVpVQi6sbtk0k0YBaRBLcOHxZFf16V/Jebonn0+GvHNNEy"],
2475
+ ["assets/vendor/lenis-1.3.11.min.js", "sha384-kdY9hFBPoAPpxcrLihsO3APivFOxtQwSeYdzFD5CIIfLurwhdMrEHhkQxZJDkxgk"]
2476
+ ];
2477
+ var settled = 0;
2478
+ // Fires once every request has finished, loaded or failed. Deciding what is
2479
+ // actually usable belongs to initPremiumMotion, which checks the globals it
2480
+ // needs rather than trusting a load count.
2481
+ function settle(){
2482
+ settled++;
2483
+ if (settled === libs.length) {
2078
2484
  window.__oracleMotionReady = true;
2079
2485
  window.dispatchEvent(new Event("oracle:motion-ready"));
2080
2486
  }
2081
2487
  }
2082
- s1.onload = onLoad; s1.onerror = function(){ loaded++; };
2083
- s2.onload = onLoad; s2.onerror = function(){ loaded++; };
2084
- s3.onload = onLoad; s3.onerror = function(){ loaded++; };
2085
- document.head.appendChild(s1);
2086
- document.head.appendChild(s2);
2087
- document.head.appendChild(s3);
2488
+ libs.forEach(function (lib) {
2489
+ var s = document.createElement("script");
2490
+ s.src = lib[0];
2491
+ s.integrity = lib[1];
2492
+ s.async = false; // keep document order: gsap before its plugin
2493
+ s.onload = settle;
2494
+ s.onerror = settle;
2495
+ document.head.appendChild(s);
2496
+ });
2088
2497
  })();
2089
2498
 
2090
2499
  (function () {
@@ -2093,7 +2502,7 @@ footer{margin-top:clamp(72px,12vh,120px);border-top:1px solid var(--line);paddin
2093
2502
 
2094
2503
  var ICON = "https://icons.llamao.fi/icons/";
2095
2504
  var CHAINS = [
2096
- { name: "Hyperliquid", id: "999", logo: "chains/rsz_hyperliquid", note: "hyperliquid agent", badge: "route" },
2505
+ { name: "HyperEVM", id: "999", logo: "chains/rsz_hyperliquid", note: "hyperliquid agent", badge: "route" },
2097
2506
  { name: "Ethereum", id: "1", logo: "chains/rsz_ethereum", note: "evm / bridge agent", badge: "route" },
2098
2507
  { name: "Base", id: "8453", logo: "chains/rsz_base", note: "evm / bridge agent", badge: "route" },
2099
2508
  { name: "Arbitrum", id: "42161", logo: "chains/rsz_arbitrum", note: "evm / bridge agent", badge: "route" },
@@ -2341,9 +2750,8 @@ var PROTOS_B = [
2341
2750
  }
2342
2751
  (function () {
2343
2752
  // Marquee is the BREADTH signal (every brand, moving). The per-tier chip
2344
- // wall that used to sit below it was removed: this section states "110
2345
- // protocol entries without the list wall", and printing all 110 names in
2346
- // three stacked grids WAS the list wall.
2753
+ // wall that used to sit below it was removed. This is a presentation subset;
2754
+ // the source-derived hero total remains separate.
2347
2755
  var marqueeSeen = Object.create(null);
2348
2756
  var trackA = document.getElementById("proto-track-a");
2349
2757
  var trackB = document.getElementById("proto-track-b");
@@ -2378,9 +2786,9 @@ var PROTOS_B = [
2378
2786
  // subset (117) that has been added to and trimmed over time. Writing it here
2379
2787
  // silently overwrote the real claim with a rail count, so the hero rendered
2380
2788
  // 117 while the markup, README and tests all said 221.
2381
- // Only the atlas count tracks the splash's own chain cards. The hero stat
2382
- // reports the catalog's 21 wired chainIds, which is a different, larger set.
2383
- ["atlas-chain-count"].forEach(function (id) { var el = document.getElementById(id); if (el) el.textContent = CHAINS.length + " + EVM"; });
2789
+ // Only the atlas count tracks the splash's featured chain cards. The hero
2790
+ // reports the CLI's 15 working chain/venue surfaces plus extensible EVM.
2791
+ ["atlas-chain-count"].forEach(function (id) { var el = document.getElementById(id); if (el) el.textContent = String(CHAINS.length); });
2384
2792
  var r = document.getElementById("atlas-route-count"); if (r) r.textContent = String(routeCount);
2385
2793
  var pr = document.getElementById("atlas-prepare-count"); if (pr) pr.textContent = String(prepareCount);
2386
2794
  if (!root) return;
@@ -2492,6 +2900,14 @@ var activeLenis = null;
2492
2900
  document.documentElement.style.setProperty("--scroll-rot", (p * 620).toFixed(2) + "deg");
2493
2901
  document.documentElement.style.setProperty("--scroll-rot-neg", (p * -620).toFixed(2) + "deg");
2494
2902
  document.documentElement.style.setProperty("--scroll-zoom", (.94 + p * .16).toFixed(3));
2903
+ // Kinetic telemetry rides this one spine rather than opening its own rAF
2904
+ // loop: --tele-x is page position, --kin-skew is instantaneous velocity.
2905
+ // The decay back to rest is a CSS transition on the consuming element, so
2906
+ // nothing keeps running once the scroll stops.
2907
+ if (!reduced) {
2908
+ document.documentElement.style.setProperty("--kin-skew", (clamp(velocity, -60, 60) * .05).toFixed(2) + "deg");
2909
+ document.documentElement.style.setProperty("--tele-x", (-6 - p * 26).toFixed(2) + "%");
2910
+ }
2495
2911
  if (sceneSections.length) pickScene();
2496
2912
  ticking = false;
2497
2913
  });
@@ -2583,33 +2999,104 @@ var activeLenis = null;
2583
2999
  });
2584
3000
  }
2585
3001
  function initPremiumMotion() {
2586
- if (reduced || coarse || !window.gsap) return;
3002
+ // Every scene below is driven by ScrollTrigger, and the `premium-motion`
3003
+ // styles (dimmed thesis lines, the 300vh instrument runway) are only correct
3004
+ // while those scenes are driving them. A partial load — gsap present, plugin
3005
+ // missing — has to stay on the static page, so both are required up front.
3006
+ // Lenis is smoothing only; without it the scenes run on native scroll.
3007
+ if (reduced || coarse || !window.gsap || !window.ScrollTrigger) return;
2587
3008
  var gsap = window.gsap;
2588
- if (window.ScrollTrigger) gsap.registerPlugin(window.ScrollTrigger);
3009
+ gsap.registerPlugin(window.ScrollTrigger);
2589
3010
  var LenisCtor = typeof window.Lenis === "function" ? window.Lenis : (window.Lenis && window.Lenis.Lenis);
2590
- if (LenisCtor && window.ScrollTrigger) {
3011
+ if (LenisCtor) {
2591
3012
  activeLenis = new LenisCtor({ lerp:.08, smoothWheel:true, wheelMultiplier:.86 });
2592
3013
  activeLenis.on("scroll", window.ScrollTrigger.update);
2593
3014
  gsap.ticker.add(function (time) { activeLenis.raf(time * 1000); });
2594
3015
  gsap.ticker.lagSmoothing(0);
2595
3016
  }
2596
3017
  splitWords(document);
2597
- if (window.ScrollTrigger) {
2598
- document.querySelectorAll("[data-split]").forEach(function (el) {
2599
- el.classList.add("in", "done");
2600
- gsap.fromTo(el.querySelectorAll(".word-mask > span"), { yPercent:112 }, { yPercent:0, duration:1.05, ease:"power4.out", stagger:.04, scrollTrigger:{ trigger:el, start:"top 82%" }, clearProps:"transform" });
3018
+ // Set before any trigger is built: the sticky instrument only grows its tall
3019
+ // scroll run once premium motion is actually on, so ScrollTrigger measures
3020
+ // the final layout rather than the fallback one.
3021
+ document.documentElement.classList.add("premium-motion");
3022
+ document.querySelectorAll("[data-split]").forEach(function (el) {
3023
+ el.classList.add("in", "done");
3024
+ gsap.fromTo(el.querySelectorAll(".word-mask > span"), { yPercent:112 }, { yPercent:0, duration:1.05, ease:"power4.out", stagger:.04, scrollTrigger:{ trigger:el, start:"top 82%" }, clearProps:"transform" });
3025
+ });
3026
+ gsap.to(".hero-art", { yPercent:18, scale:.9, ease:"none", scrollTrigger:{ trigger:".home", start:"top top", end:"bottom top", scrub:true } });
3027
+ gsap.fromTo(".hero-installer", { y:26, filter:"brightness(.92)" }, { y:0, filter:"brightness(1)", duration:1.1, ease:"power4.out", scrollTrigger:{ trigger:".hero-installer", start:"top 88%" }, clearProps:"transform,filter" });
3028
+ gsap.fromTo(".motion-card", { y:44, scale:.97 }, { y:0, scale:1, duration:1.15, ease:"power4.out", stagger:.07, scrollTrigger:{ trigger:".operator-grid", start:"top 82%" }, clearProps:"transform" });
3029
+ gsap.to(".motion-command", { y:-54, ease:"none", scrollTrigger:{ trigger:".motion-lab", start:"top 76%", end:"bottom top", scrub:true } });
3030
+ gsap.fromTo(".chain", { y:28, opacity:.55 }, { y:0, opacity:1, duration:.85, ease:"power3.out", stagger:.03, scrollTrigger:{ trigger:"#chains", start:"top 76%" }, clearProps:"transform,opacity" });
3031
+ gsap.fromTo(".strategy-card", { y:30, opacity:.58 }, { y:0, opacity:1, duration:.95, ease:"power3.out", stagger:.025, scrollTrigger:{ trigger:".strategy-grid", start:"top 78%" }, clearProps:"transform,opacity" });
3032
+ gsap.fromTo(".cli-proof", { scale:.96, y:30 }, { scale:1, y:0, ease:"none", scrollTrigger:{ trigger:".cli-proof", start:"top 86%", end:"bottom 38%", scrub:1 }, clearProps:"transform" });
3033
+ gsap.to(".route-tree", { scale:1.018, ease:"none", transformOrigin:"50% 50%", scrollTrigger:{ trigger:".route-tree", start:"top 82%", end:"bottom 40%", scrub:1 } });
3034
+ gsap.to(".mega-oracle", { xPercent:-14, letterSpacing:".02em", ease:"none", scrollTrigger:{ trigger:".mega-oracle", start:"top bottom", end:"bottom top", scrub:true } });
3035
+
3036
+ // ── 01 · the ridge separates into depth as the opening viewport leaves ──
3037
+ [-64, -44, -27, -13, -4].forEach(function (dy, i) {
3038
+ gsap.to(".hero-ridge .rg-" + i, {
3039
+ y: dy, opacity: i < 4 ? .3 : .85, ease: "none",
3040
+ scrollTrigger: { trigger: ".home", start: "top top", end: "bottom top", scrub: .6 }
3041
+ });
3042
+ });
3043
+ gsap.fromTo(".hero-index i", { scaleX: 0 }, { scaleX: 1, duration: 1.2, ease: "power4.out",
3044
+ scrollTrigger: { trigger: ".hero-index", start: "top 92%" } });
3045
+
3046
+ // ── 02 · the thesis lines light as the scroll reaches them, and stay lit.
3047
+ // Reading pace and scroll pace become the same thing. ──
3048
+ gsap.utils.toArray(".thesis-lines li").forEach(function (line) {
3049
+ gsap.fromTo(line, { opacity: .18, y: 28 }, { opacity: 1, y: 0, ease: "none",
3050
+ scrollTrigger: { trigger: line, start: "top 88%", end: "top 54%", scrub: .5 } });
3051
+ });
3052
+
3053
+ // ── 03 · the instrument. The frame is held by CSS `position:sticky`, not a
3054
+ // GSAP pin, so a script failure degrades to a plain readable list instead of
3055
+ // a stranded pin-spacer. This trigger only decides which layer is resolved. ──
3056
+ var stackRun = document.querySelector(".stack-run");
3057
+ var stackLayers = gsap.utils.toArray(".stack-layer");
3058
+ var stackMeter = document.querySelector(".stack-meter i");
3059
+ var stackStage = document.querySelector("[data-stack-stage]");
3060
+ if (stackRun && stackLayers.length) {
3061
+ // Rest state = the state the scrub produces at progress 0: layer 01 lit and
3062
+ // live, the rest held back, the meter empty. The meter's CSS fallback is
3063
+ // full (that is the correct no-JS reading), so it is zeroed here explicitly.
3064
+ stackLayers.forEach(function (layer, i) {
3065
+ layer.classList.toggle("is-live", i === 0);
3066
+ gsap.set(layer, { opacity: i === 0 ? 1 : .24 });
3067
+ gsap.set(layer.querySelector(".layer-ridge"), { xPercent: i === 0 ? 0 : -7, opacity: i === 0 ? 1 : .22 });
3068
+ });
3069
+ if (stackMeter) stackMeter.style.setProperty("--stack-p", "0");
3070
+ window.ScrollTrigger.create({
3071
+ trigger: stackRun, start: "top top+=110", end: "bottom bottom", scrub: true,
3072
+ onUpdate: function (self) {
3073
+ // `reach` starts at 1 so layer 01 never dips below its rest state when the
3074
+ // pin engages; layers 02–05 resolve across the run and the last stretch
3075
+ // holds the fully resolved instrument before it scrolls away.
3076
+ var reach = 1 + self.progress * (stackLayers.length - 1 + .35);
3077
+ if (stackMeter) stackMeter.style.setProperty("--stack-p", self.progress.toFixed(3));
3078
+ var stage = stackLayers[0].dataset.stage;
3079
+ stackLayers.forEach(function (layer, i) {
3080
+ var k = Math.max(0, Math.min(1, reach - i));
3081
+ layer.classList.toggle("is-live", k > .4);
3082
+ if (k > .4) stage = layer.dataset.stage;
3083
+ gsap.set(layer, { opacity: .24 + k * .76 });
3084
+ var ridge = layer.querySelector(".layer-ridge");
3085
+ if (ridge) gsap.set(ridge, { xPercent: -7 + k * 7, opacity: .22 + k * .78 });
3086
+ });
3087
+ if (stackStage && stackStage.textContent !== stage) stackStage.textContent = stage;
3088
+ }
2601
3089
  });
2602
- gsap.to(".hero-art", { yPercent:18, scale:.9, ease:"none", scrollTrigger:{ trigger:".home", start:"top top", end:"bottom top", scrub:true } });
2603
- gsap.fromTo(".hero-installer", { y:26, filter:"brightness(.92)" }, { y:0, filter:"brightness(1)", duration:1.1, ease:"power4.out", scrollTrigger:{ trigger:".hero-installer", start:"top 88%" }, clearProps:"transform,filter" });
2604
- gsap.fromTo(".motion-card", { y:44, scale:.97 }, { y:0, scale:1, duration:1.15, ease:"power4.out", stagger:.07, scrollTrigger:{ trigger:".operator-grid", start:"top 82%" }, clearProps:"transform" });
2605
- gsap.to(".motion-command", { y:-54, ease:"none", scrollTrigger:{ trigger:".motion-lab", start:"top 76%", end:"bottom top", scrub:true } });
2606
- gsap.fromTo(".chain", { y:28, opacity:.55 }, { y:0, opacity:1, duration:.85, ease:"power3.out", stagger:.03, scrollTrigger:{ trigger:"#chains", start:"top 76%" }, clearProps:"transform,opacity" });
2607
- gsap.fromTo(".strategy-card", { y:30, opacity:.58 }, { y:0, opacity:1, duration:.95, ease:"power3.out", stagger:.025, scrollTrigger:{ trigger:".strategy-grid", start:"top 78%" }, clearProps:"transform,opacity" });
2608
- gsap.fromTo(".cli-proof", { scale:.96, y:30 }, { scale:1, y:0, ease:"none", scrollTrigger:{ trigger:".cli-proof", start:"top 86%", end:"bottom 38%", scrub:1 }, clearProps:"transform" });
2609
- gsap.to(".route-tree", { scale:1.018, ease:"none", transformOrigin:"50% 50%", scrollTrigger:{ trigger:".route-tree", start:"top 82%", end:"bottom 40%", scrub:1 } });
2610
- gsap.to(".mega-oracle", { xPercent:-14, letterSpacing:".02em", ease:"none", scrollTrigger:{ trigger:".mega-oracle", start:"top bottom", end:"bottom top", scrub:true } });
2611
3090
  }
2612
- document.documentElement.classList.add("premium-motion");
3091
+
3092
+ // ── 08 · the close: the noisy field arrives as one resolved line ──
3093
+ gsap.fromTo(".close-ridge .rg-3", { y: 40, opacity: 0 }, { y: 0, opacity: 1, ease: "none",
3094
+ scrollTrigger: { trigger: ".close-scene", start: "top 96%", end: "top 34%", scrub: .6 } });
3095
+ gsap.fromTo(".close-ridge .rg-4", { y: 62, opacity: 0 }, { y: 0, opacity: 1, ease: "none",
3096
+ scrollTrigger: { trigger: ".close-scene", start: "top 92%", end: "top 24%", scrub: .6 } });
3097
+
3098
+ window.ScrollTrigger.refresh();
3099
+ window.addEventListener("load", function () { window.ScrollTrigger.refresh(); });
2613
3100
  }
2614
3101
  window.addEventListener("oracle:motion-ready", initPremiumMotion);
2615
3102
  if (window.__oracleMotionReady) initPremiumMotion();