kira-wallet 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +116 -0
- package/THIRD_PARTY_NOTICES.md +13 -0
- package/bin/kira.cjs +8 -0
- package/curve_pricing.py +86 -0
- package/docs/AGENT_TOOLS.md +53 -0
- package/docs/CLI.md +144 -0
- package/docs/JOB_CONTRACT.md +111 -0
- package/docs/KIRA_JOBS_BUILD_REPORT.md +92 -0
- package/docs/KIRA_REDESIGN_REPORT.md +125 -0
- package/docs/ONBOARDING_CHAT_CONTRACT.md +36 -0
- package/docs/RELEASE.md +45 -0
- package/docs/WALLET_CAPABILITIES.md +98 -0
- package/docs/character/brand-generation.json +20 -0
- package/docs/character/workspace-generation.json +29 -0
- package/docs/screenshots/kira-jobs-desktop.jpg +0 -0
- package/kira_agent.py +280 -0
- package/kira_cli.py +263 -0
- package/kira_config.py +98 -0
- package/kira_jobs.py +504 -0
- package/kira_tools.py +104 -0
- package/networks.json +214 -0
- package/onchain.cjs +34 -0
- package/package.json +78 -0
- package/pipeline-onchain.cjs +284 -0
- package/research.py +39 -0
- package/sources/job-envelope-v1.schema.json +469 -0
- package/sources/job-request-v1.schema.json +352 -0
- package/sources/mintclub-bond-abi.json +1457 -0
- package/sources/rpc-candidates.json +294 -0
- package/sources/uniswap-deployments.json +18261 -0
- package/viewer/README.md +119 -0
- package/viewer/chain_images.py +21 -0
- package/viewer/details.py +119 -0
- package/viewer/model.py +216 -0
- package/viewer/refresh-curve-prices.cjs +35 -0
- package/viewer/refresh_prices.py +97 -0
- package/viewer/server.py +153 -0
- package/viewer/static/agent.css +100 -0
- package/viewer/static/agent.js +203 -0
- package/viewer/static/app.js +252 -0
- package/viewer/static/favicon.svg +1 -0
- package/viewer/static/index.html +139 -0
- package/viewer/static/jobs.js +113 -0
- package/viewer/static/kira-attention.png +0 -0
- package/viewer/static/kira-explain.png +0 -0
- package/viewer/static/kira-logo.png +0 -0
- package/viewer/static/kira-research.png +0 -0
- package/viewer/static/kira-review.png +0 -0
- package/viewer/static/kira.png +0 -0
- package/viewer/static/style.css +51 -0
- package/viewer/static/watching-model.js +129 -0
- package/viewer/static/watching.js +167 -0
- package/viewer/static/workspace-model.js +43 -0
- package/viewer/static/workspace.css +463 -0
- package/viewer/static/workspace.js +102 -0
- package/viewer/token_images.py +137 -0
- package/wallet.py +389 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
(function (root) {
|
|
3
|
+
const pageSize = 50;
|
|
4
|
+
function catalog(tokens, filters = {}) {
|
|
5
|
+
const search = (filters.search || '').trim().toLowerCase();
|
|
6
|
+
const rows = tokens.filter(t => (filters.testnets || t.environment !== 'testnet')
|
|
7
|
+
&& (!filters.network || filters.network === 'all' || String(t.chain_id) === String(filters.network))
|
|
8
|
+
&& (filters.pricing !== 'priced' || (t.value_usd != null && !t.unpriced_count))
|
|
9
|
+
&& (filters.pricing !== 'unpriced' || t.value_usd == null || t.unpriced_count > 0)
|
|
10
|
+
&& (!search || [t.symbol, t.name, t.address || 'native'].some(v => String(v || '').toLowerCase().includes(search))));
|
|
11
|
+
const order = filters.sort || 'value';
|
|
12
|
+
rows.sort((a, b) => (order === 'name' ? String(a.name || a.symbol).localeCompare(String(b.name || b.symbol))
|
|
13
|
+
: order === 'wallets' ? b.wallet_count - a.wallet_count
|
|
14
|
+
: (b.value_usd ?? -Infinity) - (a.value_usd ?? -Infinity)) || String(a.id).localeCompare(String(b.id)));
|
|
15
|
+
const pages = Math.max(1, Math.ceil(rows.length / pageSize));
|
|
16
|
+
const page = Math.min(Math.max(1, filters.page || 1), pages);
|
|
17
|
+
return { rows: rows.slice((page - 1) * pageSize, page * pageSize), count: rows.length, page, pages };
|
|
18
|
+
}
|
|
19
|
+
const active = job => ['queued', 'running'].includes(job.state);
|
|
20
|
+
function jobPresentation(job, now = Date.now(), connected = true) {
|
|
21
|
+
const labels = { queued: 'Queued', running: 'Running', succeeded: 'Completed', partial: 'Saved with gaps', interrupted: 'Interrupted', failed: 'Failed', cancelled: 'Stopped' };
|
|
22
|
+
const start = job.state === 'queued' ? job.updated_at || job.created_at : job.started_at || job.created_at;
|
|
23
|
+
const end = active(job) ? now : Date.parse(job.updated_at);
|
|
24
|
+
const elapsed = Math.max(0, Math.floor((end - Date.parse(start)) / 1000));
|
|
25
|
+
const last = job.events?.at(-1)?.observed_at || job.updated_at;
|
|
26
|
+
const quiet = job.state === 'running' && now - Date.parse(last) > 60000;
|
|
27
|
+
return {
|
|
28
|
+
label: job.cancel_requested && active(job) ? 'Stopping' : labels[job.state] || 'Unknown',
|
|
29
|
+
active: active(job), spinner: connected && job.state === 'running', quiet,
|
|
30
|
+
elapsed: Number.isFinite(elapsed) ? elapsed : null,
|
|
31
|
+
timerLabel: job.state === 'queued' ? 'Waiting' : job.started_at ? 'Elapsed' : 'Since request',
|
|
32
|
+
freshness: !connected ? 'Connection lost. Last recorded state shown.' : quiet ? 'Awaiting a new stage update. Still marked running.' : '',
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function duration(seconds) {
|
|
36
|
+
if (seconds == null) return 'Unknown';
|
|
37
|
+
const h = Math.floor(seconds / 3600), m = Math.floor(seconds % 3600 / 60), s = seconds % 60;
|
|
38
|
+
return (h ? h + 'h ' : '') + m + 'm ' + s + 's';
|
|
39
|
+
}
|
|
40
|
+
const api = { catalog, pageSize, active, jobPresentation, duration };
|
|
41
|
+
if (typeof module !== 'undefined' && module.exports) module.exports = api;
|
|
42
|
+
else root.KiraView = api;
|
|
43
|
+
})(typeof globalThis !== 'undefined' ? globalThis : this);
|
|
@@ -0,0 +1,463 @@
|
|
|
1
|
+
/* Workspace refinement: paper, ink and a lavender notebook.
|
|
2
|
+
Body and controls use the system UI face. Only scene captions use a serif. */
|
|
3
|
+
:root {
|
|
4
|
+
--bg: #f8f7f4;
|
|
5
|
+
--ink: #292733;
|
|
6
|
+
--secondary: #665e70;
|
|
7
|
+
--muted: #716779;
|
|
8
|
+
--line: #e4dfe8;
|
|
9
|
+
--accent: #69518b;
|
|
10
|
+
--accent-soft: #eee8f5;
|
|
11
|
+
--sidebar: #22232d;
|
|
12
|
+
--type-caption: 12px;
|
|
13
|
+
--type-body: 14px;
|
|
14
|
+
--type-label: 13px;
|
|
15
|
+
--control-height: 44px;
|
|
16
|
+
--icon-size: 18px;
|
|
17
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
|
|
18
|
+
}
|
|
19
|
+
body, main { background: var(--bg); color: var(--ink); }
|
|
20
|
+
body { font-size: var(--type-body); line-height: 1.5; letter-spacing: 0; }
|
|
21
|
+
p { letter-spacing: 0; }
|
|
22
|
+
button, input, textarea, select { font: inherit; letter-spacing: 0; }
|
|
23
|
+
button, a { touch-action: manipulation; }
|
|
24
|
+
:is(input, textarea, button, a, select, summary):focus-visible { outline: 2px solid #8064b1; outline-offset: 3px; }
|
|
25
|
+
h1, h2, h3 { letter-spacing: -.025em; }
|
|
26
|
+
.ui-icon { width: var(--icon-size); height: var(--icon-size); flex: none; display: block; stroke-width: 1.75; }
|
|
27
|
+
.primary-button, .quiet-button, .settings-button, .send-button, .icon-button, [data-close-dialog] {
|
|
28
|
+
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
|
|
29
|
+
min-height: var(--control-height); border-radius: 10px; line-height: 20px;
|
|
30
|
+
font-size: var(--type-label); font-weight: 500; padding: 11px 14px;
|
|
31
|
+
}
|
|
32
|
+
.primary-button { background: var(--accent); border-color: var(--accent); color: #fff; }
|
|
33
|
+
.primary-button:hover { background: #594176; border-color: #594176; }
|
|
34
|
+
.quiet-button { background: #fcfafc; border-color: #d8cfdf; color: #594469; }
|
|
35
|
+
.quiet-button:hover { background: #eee8f5; border-color: #bbaeC9; }
|
|
36
|
+
button:disabled { opacity: .55; }
|
|
37
|
+
.icon-button, [data-close-dialog] { padding: 0; min-width: 44px; color: var(--secondary); }
|
|
38
|
+
.icon-button svg, [data-close-dialog] svg { width: 18px; height: 18px; }
|
|
39
|
+
|
|
40
|
+
/* Navigation. The icon and name occupy two stable columns. */
|
|
41
|
+
.sidebar { width: 232px; background: var(--sidebar); border: 0; color: #eeeaf4; padding: 28px 18px 20px; z-index: 3; }
|
|
42
|
+
.brand { padding: 0 6px; gap: 10px; font-size: 28px; font-weight: 600; letter-spacing: -.035em; line-height: 1.15; }
|
|
43
|
+
.brand-logo { width: 44px; height: 44px; border-radius: 12px; }
|
|
44
|
+
.brand-caption { color: #bdb6ca; font-size: 10px; font-weight: 500; letter-spacing: .07em; line-height: 1.4; margin-top: 4px; }
|
|
45
|
+
.brand[aria-current] { color: #fff; }
|
|
46
|
+
.workspace-label, .sidebar-label { color: #bdb6ca; font-size: 11px; letter-spacing: .07em; font-weight: 500; }
|
|
47
|
+
.workspace-label { margin: 32px 8px 16px; }
|
|
48
|
+
.sidebar-intro { display: flex; gap: 12px; margin: 0 8px 8px; }
|
|
49
|
+
.sidebar-intro p { font-size: 13px; color: #d0c8dc; line-height: 1.6; margin: 0; }
|
|
50
|
+
.sidebar-line { width: 2px; background: #a590ce; border-radius: 2px; }
|
|
51
|
+
.sidebar-label { margin: 30px 8px 12px; padding: 0; }
|
|
52
|
+
.sidebar-label span { background: #393644; color: #d4c9e5; font-size: 11px; }
|
|
53
|
+
#wallet-list { overflow: auto; min-height: 70px; max-height: calc(100dvh - 490px); scrollbar-width: thin; }
|
|
54
|
+
.wallet-button:not(.home-button) { grid-template-columns: 20px minmax(0, 1fr); padding: 12px 10px; gap: 10px; border-radius: 10px; min-height: 60px; }
|
|
55
|
+
.wallet-button { color: #e2dceb; }
|
|
56
|
+
.wallet-button:hover { background: #2f2d3b; }
|
|
57
|
+
.wallet-button.active { background: #40374f; border-color: #625075; color: #f4edff; }
|
|
58
|
+
.wallet-nav-name { font-size: 14px; font-weight: 500; line-height: 1.4; }
|
|
59
|
+
.wallet-nav-address { display: block; font-size: 12px; color: #b6aac6; line-height: 1.5; margin-top: 3px; }
|
|
60
|
+
.wallet-glyph { color: #b9a7d1; width: 20px; height: 20px; }
|
|
61
|
+
.wallet-glyph svg { width: 20px; height: 20px; }
|
|
62
|
+
.wallet-arrow { display: none; }
|
|
63
|
+
.user-controls { margin-top: auto; padding-top: 24px; display: grid; gap: 8px; }
|
|
64
|
+
.user-controls .primary-button { justify-content: flex-start; background: #bda9df; border-color: #bda9df; color: #2e253d; font-size: 13px; padding: 11px 12px; }
|
|
65
|
+
.user-controls .primary-button:hover { background: #cbb8e9; }
|
|
66
|
+
.settings-button { justify-content: flex-start; background: transparent; border: 1px solid #5b5366; color: #e0d7eb; font-size: 13px; padding: 11px 12px; }
|
|
67
|
+
.settings-button:hover { background: #332d40; }
|
|
68
|
+
.user-controls p { font-size: 11px; color: #bcb0cb; line-height: 1.6; text-align: left; margin: 4px 2px 16px; }
|
|
69
|
+
.sidebar-bottom { margin-top: 0; border-color: #4d445b; color: #c8bdd5; font-size: 11px; gap: 7px; flex-wrap: wrap; }
|
|
70
|
+
.read-only { color: #bcb0cb; font-size: 11px; }
|
|
71
|
+
.status-dot { background: #abcdb7; }
|
|
72
|
+
|
|
73
|
+
/* Page hierarchy and recorded financial values. */
|
|
74
|
+
main { margin-left: 232px; width: calc(100% - 232px); }
|
|
75
|
+
.topbar { height: 60px; background: #fbfaf7; border-color: var(--line); padding: 0 28px; gap: 12px; }
|
|
76
|
+
.breadcrumb { font-size: 13px; }
|
|
77
|
+
.breadcrumb a { min-height: 44px; display: flex; align-items: center; }
|
|
78
|
+
.breadcrumb [aria-current] { color: #51465d; }
|
|
79
|
+
.sync-status { font-size: 12px; color: var(--secondary); }
|
|
80
|
+
.sync-status .sync-dot { background: #806692; }
|
|
81
|
+
.demo-badge { font-size: 10px; letter-spacing: .06em; color: #69527b; }
|
|
82
|
+
.workspace-tabs { min-height: 56px; border-bottom: 1px solid var(--line); display: flex; align-items: stretch; gap: 28px; padding: 0 28px; background: #fbfaf7; }
|
|
83
|
+
.workspace-tabs > a { position: relative; display: flex; align-items: center; gap: 8px; color: var(--secondary); font-size: 14px; white-space: nowrap; min-height: 56px; }
|
|
84
|
+
.workspace-tabs > a[aria-current] { color: #302639; font-weight: 600; }
|
|
85
|
+
.workspace-tabs > a[aria-current]::after { content: ""; position: absolute; bottom: -1px; left: 0; right: 0; height: 2px; background: #806299; }
|
|
86
|
+
.workspace-tabs > a > span:not(:empty) { font-size: 11px; background: #eae2f1; color: #624c79; padding: 1px 6px; border-radius: 5px; line-height: 18px; }
|
|
87
|
+
.mobile-pane-control { display: none; }
|
|
88
|
+
.content { padding: 28px; max-width: 1800px; }
|
|
89
|
+
.workspace { display: grid; grid-template-columns: minmax(0, 1fr) minmax(340px, 38%); gap: 28px; align-items: start; }
|
|
90
|
+
.evidence-pane { min-width: 0; }
|
|
91
|
+
.home-heading { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; padding: 4px 0; }
|
|
92
|
+
.home-heading h1 { font-size: clamp(32px, 2.7vw, 42px); font-weight: 600; line-height: 1.2; letter-spacing: -.035em; margin: 0 0 14px; }
|
|
93
|
+
.home-heading p { font-size: 14px; color: var(--secondary); line-height: 1.6; margin: 0; }
|
|
94
|
+
.eyebrow, .home-heading .eyebrow, .view-heading .eyebrow { font-size: 11px; line-height: 1.5; font-weight: 600; color: #705a80; letter-spacing: .075em; margin-bottom: 12px; }
|
|
95
|
+
.edition-mark { font: italic 28px Georgia, serif; color: #9a83aa; margin-bottom: 8px; white-space: nowrap; }
|
|
96
|
+
.home-summary { display: block; margin-top: 28px; padding: 24px; border: 1px solid #dfd6e8; border-radius: 16px; background: #efeaf5; }
|
|
97
|
+
.total-value, .wallet-card-value, .account-value { font-variant-numeric: tabular-nums; letter-spacing: -.035em; }
|
|
98
|
+
.home-summary .total-value { font-size: clamp(36px, 3.2vw, 48px); color: #372b43; font-weight: 500; line-height: 1.15; margin-top: 10px; }
|
|
99
|
+
.home-summary .valuation-note, .valuation-note { color: var(--secondary); font-size: 12px; line-height: 1.6; margin-top: 12px; max-width: none; }
|
|
100
|
+
.home-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; margin-top: 22px; padding-top: 20px; border-top: 1px solid #dcd1e6; }
|
|
101
|
+
.home-stats .summary-stat { padding-left: 0; border: none; gap: 6px; }
|
|
102
|
+
.summary-label, .home-stats .summary-label { font-size: 12px; color: #685571; line-height: 1.4; }
|
|
103
|
+
.stat-note, .home-stats .stat-note { font-size: 12px; color: var(--secondary); line-height: 1.5; white-space: normal; }
|
|
104
|
+
.home-stats strong { font-size: 26px; font-weight: 500; color: #463550; letter-spacing: -.025em; }
|
|
105
|
+
.dashboard-grid { grid-template-columns: 1fr; gap: 28px; margin-top: 28px; }
|
|
106
|
+
.section-heading { margin-bottom: 14px; gap: 12px; align-items: baseline; flex-wrap: wrap; }
|
|
107
|
+
.section-heading h2 { font-size: 18px; font-weight: 600; line-height: 1.4; }
|
|
108
|
+
.section-note { font-size: 12px; color: var(--secondary); line-height: 1.5; white-space: normal; }
|
|
109
|
+
.wallet-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
|
|
110
|
+
.wallet-card { padding: 18px; background: #fcfbfa; border-color: #e3dce7; border-radius: 12px; min-width: 0; }
|
|
111
|
+
.wallet-card-heading { gap: 10px; align-items: center; }
|
|
112
|
+
.wallet-card-identity { min-width: 0; overflow: hidden; }
|
|
113
|
+
.wallet-card-identity strong { font-size: 14px; font-weight: 500; line-height: 1.4; display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
114
|
+
.wallet-card-identity > span { font-size: 12px; color: var(--secondary); line-height: 1.5; }
|
|
115
|
+
.wallet-card-value { font-size: 28px; font-weight: 500; line-height: 1.2; margin: 20px 0 10px; }
|
|
116
|
+
.wallet-card-meta { font-size: 12px; color: var(--secondary); line-height: 1.6; display: block; }
|
|
117
|
+
.wallet-card-meta > span:last-child { display: none; }
|
|
118
|
+
.card-wallet-icon { width: 36px; height: 36px; border-radius: 10px; flex: none; background: #eee7f5; }
|
|
119
|
+
.card-wallet-icon svg { width: 20px; height: 20px; }
|
|
120
|
+
.card-arrow { font-size: 18px; line-height: 1; color: #796188; }
|
|
121
|
+
.card-arrow, .detail-arrow { display: inline-flex; align-items: center; flex: none; }
|
|
122
|
+
.card-arrow .ui-icon, .detail-arrow .ui-icon { width: 16px; height: 16px; }
|
|
123
|
+
.allocation-progress { height: 4px; }
|
|
124
|
+
.network-allocation { padding: 4px 18px; border-color: #e3dce7; border-radius: 12px; }
|
|
125
|
+
.network-row { padding: 18px 0; }
|
|
126
|
+
.network-label, .network-value { font-size: 14px; line-height: 1.4; }
|
|
127
|
+
.network-row-meta { font-size: 12px; color: var(--secondary); margin: 9px 0; }
|
|
128
|
+
.largest-holdings { margin-top: 28px; }
|
|
129
|
+
.home-holdings { display: block; border-radius: 12px; border-color: #e3dce7; padding: 0 18px; }
|
|
130
|
+
.home-holding { padding: 16px 0; border: 0; border-bottom: 1px solid #e7e0eb; background: transparent; }
|
|
131
|
+
.home-holding:last-child { border: 0; }
|
|
132
|
+
.home-holding:hover { background: transparent; }
|
|
133
|
+
.holding-value { font-size: 14px; }
|
|
134
|
+
.coin-icon { width: 32px; height: 32px; color: #66556e; background: #f0edf4; }
|
|
135
|
+
.chain-icon { color: #fff; background: #796489; }
|
|
136
|
+
.chain-fallback { font-size: 11px; }
|
|
137
|
+
.symbol { font-size: 14px; font-weight: 500; line-height: 1.4; color: #45354f; }
|
|
138
|
+
.token-description { font-size: 12px; line-height: 1.5; color: var(--secondary); }
|
|
139
|
+
.home-holding .token-description { font-size: 12px; color: var(--secondary); }
|
|
140
|
+
.empty p { font-size: 14px; color: var(--secondary); }
|
|
141
|
+
.page-footer { font-size: 12px; color: var(--secondary); flex-wrap: wrap; line-height: 1.6; margin-top: 24px; gap: 8px; }
|
|
142
|
+
|
|
143
|
+
/* Kira keeps a visible composer while her recorded notes scroll. */
|
|
144
|
+
.kira-panel { position: sticky; top: 24px; height: calc(100dvh - 168px); min-height: 500px; max-height: calc(100dvh - 48px); display: flex; flex-direction: column; background: #f0edf5; border: 1px solid #dfd6e8; border-radius: 16px; overflow: hidden; box-shadow: 0 6px 24px #3a294708; }
|
|
145
|
+
.kira-panel-heading { display: flex; justify-content: space-between; align-items: center; padding: 22px 22px 0; gap: 12px; flex: none; }
|
|
146
|
+
.kira-panel-heading .eyebrow { font-size: 10px; margin-bottom: 6px; color: #725781; letter-spacing: .065em; }
|
|
147
|
+
.kira-panel-heading h2 { font-size: 27px; font-weight: 600; color: #443050; gap: 9px; line-height: 1.2; }
|
|
148
|
+
.kira-spark { color: #9076a4; font-size: 20px; font-weight: 400; }
|
|
149
|
+
.local-badge { padding: 5px 8px; border: 1px solid #d6c8e2; border-radius: 7px; font-size: 11px; line-height: 1.5; color: #695076; white-space: nowrap; }
|
|
150
|
+
.kira-scene { height: 205px; position: relative; flex: none; overflow: hidden; margin: 8px 0 0; background: radial-gradient(ellipse at 78% 75%, #e1d5ea, transparent 67%); }
|
|
151
|
+
.kira-scene img { position: absolute; right: 4px; bottom: -17px; width: 180px; height: 228px; object-fit: contain; object-position: center bottom; }
|
|
152
|
+
.scene-caption { position: relative; z-index: 1; max-width: 47%; padding: 46px 0 0 22px; display: flex; flex-direction: column; gap: 12px; }
|
|
153
|
+
.scene-caption > span:first-child { font: italic 25px/1.2 Georgia, serif; color: #70537f; letter-spacing: -.02em; }
|
|
154
|
+
.scene-rule { width: 30px; height: 1px; background: #b3a0c4; }
|
|
155
|
+
.scene-caption small { font-size: 12px; line-height: 1.5; color: #705a7e; max-width: 145px; }
|
|
156
|
+
.kira-conversation { padding: 18px 22px 20px; overflow: auto; flex: 1; min-height: 80px; border-top: 1px solid #dfd5e8; scrollbar-width: thin; }
|
|
157
|
+
.briefing-meta { display: flex; align-items: center; gap: 7px; color: #6e537d; font-size: 12px; line-height: 1.5; margin-bottom: 14px; flex-wrap: wrap; }
|
|
158
|
+
.briefing-meta > span:last-child { margin-left: auto; font-size: 10px; letter-spacing: .035em; color: #71617d; }
|
|
159
|
+
.briefing-dot { height: 5px; width: 5px; border-radius: 50%; background: #8d72a2; flex: none; }
|
|
160
|
+
.kira-note { display: block; background: #fbfafc; border-color: #dfd5e8; border-radius: 12px; padding: 18px; margin: 0; color: #5f4b6e; }
|
|
161
|
+
.kira-note-label { font-size: 10px; letter-spacing: .065em; line-height: 1.5; color: #775b85; margin-bottom: 10px; }
|
|
162
|
+
.kira-note p { font-size: 14px; line-height: 1.65; letter-spacing: 0; color: #5e4b6a; }
|
|
163
|
+
.kira-note summary { font-size: 12px; line-height: 1.5; margin-top: 14px; color: #735481; padding: 6px 0; }
|
|
164
|
+
.kira-note details p { font-size: 13px; line-height: 1.65; color: #685374; }
|
|
165
|
+
.kira-quick-actions { display: grid; gap: 0; margin-top: 12px; }
|
|
166
|
+
.kira-quick-actions button { min-height: 44px; padding: 11px 0; display: flex; align-items: center; justify-content: space-between; gap: 12px; background: none; border: 0; border-bottom: 1px solid #ddd2e7; color: #6d507d; font-size: 13px; line-height: 20px; text-align: left; }
|
|
167
|
+
.kira-quick-actions button:hover { color: #4c2e60; }
|
|
168
|
+
.kira-quick-actions button:last-child { border: 0; }
|
|
169
|
+
.kira-quick-actions .ui-icon { width: 16px; height: 16px; }
|
|
170
|
+
.composer { background: #f8f5fb; border-top: 1px solid #dfd2e8; padding: 16px 22px; flex: none; }
|
|
171
|
+
.composer > label { font-size: 12px; color: #71547f; font-weight: 500; }
|
|
172
|
+
.composer textarea { width: 100%; resize: vertical; min-height: 56px; max-height: 100px; background: none; border: 0; display: block; padding: 10px 0 4px; color: #493254; font-size: 14px; line-height: 1.5; }
|
|
173
|
+
.composer textarea::placeholder { color: #7c6889; opacity: 1; }
|
|
174
|
+
.composer-footer { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
|
|
175
|
+
.composer-footer > span { font-size: 12px; line-height: 1.5; color: #766081; }
|
|
176
|
+
.send-button { border: 0; background: #e2d8ed; color: #745981; width: 44px; height: 44px; padding: 0; opacity: .65; }
|
|
177
|
+
.send-button .ui-icon { width: 20px; height: 20px; }
|
|
178
|
+
.composer > p { font-size: 12px; color: #765c83; margin: 8px 0 0; line-height: 1.5; }
|
|
179
|
+
.text-button { background: none; border: 0; padding: 6px 2px; color: #654378; font-size: inherit; line-height: 1.5; text-decoration: underline; text-underline-offset: 3px; }
|
|
180
|
+
.view-heading h1 { font-size: 36px; font-weight: 600; line-height: 1.2; letter-spacing: -.035em; }
|
|
181
|
+
.view-heading > p { font-size: 14px; line-height: 1.65; color: var(--secondary); max-width: 560px; margin-bottom: 24px; }
|
|
182
|
+
|
|
183
|
+
/* Wallets, token details and filters share the same type scale. */
|
|
184
|
+
.wallet-heading { flex-wrap: wrap; }
|
|
185
|
+
.wallet-heading h1 { font-size: 32px; line-height: 1.2; overflow-wrap: anywhere; }
|
|
186
|
+
.wallet-address { flex-wrap: wrap; font-size: 12px; overflow-wrap: anywhere; color: var(--secondary); }
|
|
187
|
+
#address { max-width: 100%; overflow-wrap: anywhere; }
|
|
188
|
+
.wallet-actions { background: #eeebf2; padding: 6px; border: 1px solid #dfd6e7; border-radius: 12px; justify-content: flex-start; gap: 6px; margin-bottom: 24px; display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
189
|
+
.wallet-actions button { background: #fcfafc; border: 0; white-space: normal; min-height: 44px; font-size: 13px; padding: 10px 8px; }
|
|
190
|
+
.portfolio-summary { grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 24px; padding-bottom: 24px; }
|
|
191
|
+
.portfolio-summary .valuation { grid-column: 1 / -1; }
|
|
192
|
+
.portfolio-summary .total-value { font-size: 42px; }
|
|
193
|
+
.portfolio-summary .summary-stat { border: 0; padding-left: 0; }
|
|
194
|
+
.summary-stat strong { font-size: 26px; }
|
|
195
|
+
.holdings-toolbar { flex-wrap: wrap; gap: 16px; margin-bottom: 20px; }
|
|
196
|
+
.holdings-toolbar .filters { flex-wrap: wrap; width: 100%; gap: 8px; }
|
|
197
|
+
.holdings h2 { font-size: 18px; }
|
|
198
|
+
.token-search { flex: 1; }
|
|
199
|
+
.token-search input { width: 100%; max-width: none; font-size: 14px; min-height: 44px; }
|
|
200
|
+
.chain-select select { font-size: 13px; min-height: 44px; }
|
|
201
|
+
.chain-select svg { top: 16px; }
|
|
202
|
+
.segment button { min-height: 38px; font-size: 13px; }
|
|
203
|
+
.chain-heading { gap: 12px; }
|
|
204
|
+
.chain-name { flex-wrap: wrap; font-size: 15px; }
|
|
205
|
+
.chain-assets, .chain-total, .filter-note, .tag, .count-badge { font-size: 12px; color: var(--secondary); }
|
|
206
|
+
.detail-heading h1 { font-size: 32px; line-height: 1.2; }
|
|
207
|
+
.detail-heading p { font-size: 14px; color: var(--secondary); line-height: 1.6; }
|
|
208
|
+
.detail-facts, .account-grid { grid-template-columns: 1fr; gap: 14px; }
|
|
209
|
+
.fact-panel, .account-card { padding: 22px; border-radius: 12px; }
|
|
210
|
+
.fact-panel h2 { font-size: 17px; }
|
|
211
|
+
.fact-panel dt, .account-facts dt, .account-meta, .account-footnote { color: var(--secondary); font-size: 12px; line-height: 1.5; }
|
|
212
|
+
.fact-panel dd, .account-facts dd { font-size: 13px; color: #5e4b6a; line-height: 1.5; }
|
|
213
|
+
.detail-note { font-size: 12px; line-height: 1.6; color: var(--secondary); }
|
|
214
|
+
.account-value { font-size: 32px; }
|
|
215
|
+
.table-wrap { border-radius: 12px; }
|
|
216
|
+
.token-table td, .token-table th { padding: 16px 12px; }
|
|
217
|
+
.token-table td { font-size: 14px; }
|
|
218
|
+
.amount, .token-price, .token-value { font-size: 14px; line-height: 1.5; }
|
|
219
|
+
.token-table th { font-size: 12px; color: var(--secondary); }
|
|
220
|
+
.coin-title { min-width: 0; overflow: hidden; }
|
|
221
|
+
.token-description, .symbol { max-width: 180px; }
|
|
222
|
+
.market-link { font-size: 12px; display: inline-flex; align-items: center; min-height: 32px; }
|
|
223
|
+
.price-basis, .native-label, .unpriced { font-size: 12px; line-height: 1.5; color: var(--secondary); }
|
|
224
|
+
.token-catalog-controls { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
|
|
225
|
+
.catalog-search { grid-column: 1 / -1; }
|
|
226
|
+
.token-catalog-controls input, .token-catalog-controls select, .activity-toolbar select { width: 100%; min-width: 0; border: 1px solid #d5cadd; background: #fdfbfe; color: #604a6c; border-radius: 10px; padding: 11px 12px; font-size: 13px; line-height: 20px; min-height: 44px; }
|
|
227
|
+
.catalog-meta { font-size: 12px; display: flex; justify-content: space-between; gap: 12px; align-items: center; margin: 20px 0 16px; color: var(--secondary); flex-wrap: wrap; }
|
|
228
|
+
.checkbox-label { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--secondary); min-height: 36px; }
|
|
229
|
+
.catalog-table { table-layout: fixed; }
|
|
230
|
+
.catalog-table th:first-child { width: 43%; }
|
|
231
|
+
.catalog-table th:nth-child(2) { width: 25%; }
|
|
232
|
+
.catalog-table th:nth-child(3) { width: 10%; }
|
|
233
|
+
.catalog-table th:nth-child(4) { width: 22%; text-align: right; }
|
|
234
|
+
.catalog-table td:last-child { text-align: right; }
|
|
235
|
+
.pagination { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 18px; color: var(--secondary); font-size: 12px; }
|
|
236
|
+
.pagination button { min-height: 44px; padding: 11px 12px; font-size: 13px; }
|
|
237
|
+
|
|
238
|
+
/* Job states remain evidence, with readable timing and stage details. */
|
|
239
|
+
.active-work { border: 1px solid #d1c2e0; background: #ece5f5; border-radius: 12px; padding: 14px 16px; margin-bottom: 24px; color: #665073; display: grid; gap: 8px; }
|
|
240
|
+
.active-work a { display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 13px; flex-wrap: wrap; }
|
|
241
|
+
.active-work strong { font-weight: 500; color: #5d4472; }
|
|
242
|
+
.active-work p { margin: 6px 0 0; font-size: 12px; line-height: 1.6; }
|
|
243
|
+
.active-work small { font-size: 12px; }
|
|
244
|
+
.active-work .spinner { margin-right: 7px; }
|
|
245
|
+
.research-jobs { padding: 20px; border-radius: 12px; background: #fcfafc; margin-bottom: 0; }
|
|
246
|
+
.activity-toolbar { display: flex; align-items: center; gap: 12px; margin: 18px 0; flex-wrap: wrap; }
|
|
247
|
+
.activity-toolbar select { width: 155px; }
|
|
248
|
+
.activity-toolbar > span { font-size: 12px; color: var(--secondary); line-height: 1.6; }
|
|
249
|
+
.job-row { align-items: flex-start; padding: 20px 0; gap: 12px; flex-wrap: wrap; }
|
|
250
|
+
.job-identity { font-size: 14px; flex: 1; min-width: min(100%, 200px); }
|
|
251
|
+
.job-identity p { font-size: 13px; line-height: 1.6; }
|
|
252
|
+
.job-identity strong { font-size: 14px; font-weight: 500; }
|
|
253
|
+
.job-state { font-size: 12px; border-radius: 6px; padding: 4px 8px; line-height: 20px; white-space: nowrap; }
|
|
254
|
+
.job-state.running, .job-state.queued { background: #ece4f5; color: #705087; }
|
|
255
|
+
.job-state.cancelled { background: #eeebf0; color: #6d5c7a; }
|
|
256
|
+
.job-state.failed { background: #f7e9e5; color: #93513f; }
|
|
257
|
+
.job-state.interrupted, .job-state.partial { background: #f8eddb; color: #806029; }
|
|
258
|
+
.job-state.succeeded { background: #e9f0eb; color: #446950; }
|
|
259
|
+
.job-actions { margin-left: auto; }
|
|
260
|
+
.job-actions .quiet-button { font-size: 13px; min-height: 44px; padding: 11px 12px; }
|
|
261
|
+
.job-identity small { font-size: 12px; line-height: 1.7; color: var(--secondary); }
|
|
262
|
+
.job-identity a { font-size: 13px; line-height: 1.5; }
|
|
263
|
+
.job-identity .job-freshness { color: #87662e; }
|
|
264
|
+
.job-stages { font-size: 13px; }
|
|
265
|
+
.job-stages summary { font-size: 13px; color: #755385; padding: 6px 0; }
|
|
266
|
+
.job-stages li span { font-size: 12px; line-height: 1.6; }
|
|
267
|
+
.job-timer { font-variant-numeric: tabular-nums; }
|
|
268
|
+
.spinner { display: inline-block; width: 12px; height: 12px; border: 1.5px solid #c7b5d9; border-top-color: #785295; border-radius: 50%; vertical-align: -1px; margin-right: 5px; animation: research-spin 1s linear infinite; }
|
|
269
|
+
@keyframes research-spin { to { transform: rotate(360deg); } }
|
|
270
|
+
.research-dialog { padding: 28px; }
|
|
271
|
+
.dialog-heading h2 { font-size: 21px; letter-spacing: -.025em; }
|
|
272
|
+
.dialog-heading button { min-width: 44px; min-height: 44px; flex: none; }
|
|
273
|
+
.research-dialog p, .research-dialog label { font-size: 14px; line-height: 1.6; }
|
|
274
|
+
.research-dialog .form-note, .assistant-gate p { font-size: 12px; line-height: 1.6; }
|
|
275
|
+
.research-dialog input:not([type=checkbox]), .research-dialog textarea, .research-dialog select { font-size: 14px; min-height: 44px; }
|
|
276
|
+
.history-row { font-size: 14px; line-height: 1.6; }
|
|
277
|
+
.history-row small, .comparison-result small { font-size: 12px; }
|
|
278
|
+
|
|
279
|
+
/* Watching connection keeps selection, session and saved addresses distinct. */
|
|
280
|
+
.watching-dialog { width: min(520px, calc(100% - 32px)); }
|
|
281
|
+
.watching-dialog [hidden], #wallet-session-panel[hidden] { display: none; }
|
|
282
|
+
.watching-dialog .text-button { min-height: 44px; padding: 10px 2px; margin-right: 12px; }
|
|
283
|
+
.wallet-entry-modes { display: grid; grid-template-columns: 1fr 1fr; gap: 4px; background: #eee9f3; padding: 4px; border-radius: 12px; margin: 22px 0; }
|
|
284
|
+
.wallet-entry-modes button { min-height: 44px; padding: 9px 8px; border: 0; background: transparent; color: var(--secondary); border-radius: 9px; font: inherit; font-weight: 500; cursor: pointer; }
|
|
285
|
+
.wallet-entry-modes button[aria-pressed=true] { color: var(--ink); background: #fff; box-shadow: 0 1px 4px #30213e12; }
|
|
286
|
+
.watching-dialog.is-review .wallet-entry-modes { margin: 16px 0; }
|
|
287
|
+
.watching-dialog.is-review .wallet-preview { padding: 16px; }
|
|
288
|
+
.watching-dialog h3 { font-size: 14px; font-weight: 600; letter-spacing: -.01em; margin: 0 0 8px; }
|
|
289
|
+
.wallet-choices { display: grid; gap: 8px; margin: 16px 0; }
|
|
290
|
+
.wallet-choice { display: flex; align-items: center; gap: 12px; padding: 14px; width: 100%; min-height: 64px; text-align: left; color: var(--ink); background: #fff; border: 1px solid #ded6e6; border-radius: 12px; font: inherit; cursor: pointer; }
|
|
291
|
+
.wallet-choice:hover, .wallet-choice[aria-pressed=true] { border-color: #9475aa; background: #f6f1fa; }
|
|
292
|
+
.wallet-choice img { width: 32px; height: 32px; border-radius: 8px; object-fit: contain; flex: none; }
|
|
293
|
+
.wallet-choice > span:not(.wallet-choice-arrow) { flex: 1; min-width: 0; }
|
|
294
|
+
.wallet-choice strong, .wallet-choice small { display: block; overflow-wrap: anywhere; }
|
|
295
|
+
.wallet-choice strong { font-size: 14px; font-weight: 500; line-height: 1.45; }
|
|
296
|
+
.wallet-choice small { color: var(--secondary); font-size: 12px; line-height: 1.5; margin-top: 3px; }
|
|
297
|
+
.wallet-choice-arrow { display: flex; flex: none; color: #76578e; }
|
|
298
|
+
.wallet-account img { display: none; }
|
|
299
|
+
.wallet-account small { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; line-height: 1.7; }
|
|
300
|
+
.wallet-accounts-section { border-top: 1px solid #e2dce8; padding-top: 20px; margin-top: 20px; }
|
|
301
|
+
.research-dialog .wallet-connection-status { font-size: 13px; color: #5f4474; }
|
|
302
|
+
.wallet-connection-status:empty { display: none; }
|
|
303
|
+
.wallet-preview { background: #f0edf5; border: 1px solid #ddd2e6; border-radius: 12px; padding: 18px; margin: 18px 0; }
|
|
304
|
+
.wallet-preview dl { margin: 12px 0 0; }
|
|
305
|
+
.wallet-preview dt { color: var(--secondary); font-size: 12px; line-height: 1.5; margin-top: 12px; }
|
|
306
|
+
.wallet-preview dd { margin: 4px 0 0; font-size: 14px; line-height: 1.6; overflow-wrap: anywhere; white-space: pre-wrap; }
|
|
307
|
+
#wallet-preview-address, #wallet-submission-address { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; }
|
|
308
|
+
.wallet-submission-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }
|
|
309
|
+
.wallet-submission-actions .quiet-button { min-height: 44px; padding: 10px 12px; }
|
|
310
|
+
.wallet-preview p { margin-bottom: 0; }
|
|
311
|
+
.wallet-demo-note, .wallet-unavailable { padding: 14px 16px; background: #f2edf6; border-radius: 10px; }
|
|
312
|
+
.wallet-existing a { color: #684484; text-underline-offset: 3px; }
|
|
313
|
+
#wallet-register { width: 100%; }
|
|
314
|
+
.wallet-session-panel { border-top: 1px solid #4b4058; padding-top: 8px; margin-bottom: 14px; }
|
|
315
|
+
#wallet-session { justify-content: flex-start; text-align: left; color: #d8cce4; font-size: 12px; min-height: 44px; }
|
|
316
|
+
#wallet-session-name { display: block; font-size: 12px; color: #c2b5cc; overflow-wrap: anywhere; }
|
|
317
|
+
#wallet-session-name:empty { display: none; }
|
|
318
|
+
|
|
319
|
+
/* Compact panes use the same card layout on every viewport. */
|
|
320
|
+
@media (max-width: 1400px) {
|
|
321
|
+
.wallet-cards { grid-template-columns: 1fr; }
|
|
322
|
+
.edition-mark { display: none; }
|
|
323
|
+
.token-catalog-controls { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
324
|
+
.token-catalog-controls > label:last-child { grid-column: 1 / -1; }
|
|
325
|
+
.evidence-pane .token-table, .evidence-pane .token-table tbody { display: block; }
|
|
326
|
+
.evidence-pane .token-table thead, .evidence-pane .token-table colgroup { display: none; }
|
|
327
|
+
.evidence-pane .token-table tr { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; padding: 16px; border-bottom: 1px solid var(--line); }
|
|
328
|
+
.evidence-pane .token-table tr:last-child { border-bottom: 0; }
|
|
329
|
+
.evidence-pane .token-table td { display: block; padding: 0; border: 0; text-align: right; }
|
|
330
|
+
.evidence-pane .token-table td:first-child { grid-column: 1; grid-row: 1; text-align: left; }
|
|
331
|
+
.evidence-pane .token-table td:nth-child(4) { grid-column: 2; grid-row: 1; align-self: center; }
|
|
332
|
+
.evidence-pane .token-table td:nth-child(2) { grid-column: 1; grid-row: 2; text-align: left; margin-left: 42px; }
|
|
333
|
+
.evidence-pane .token-table td:nth-child(3) { grid-column: 2; grid-row: 2; }
|
|
334
|
+
.evidence-pane .token-table td:nth-child(5) { grid-column: 1 / -1; grid-row: 3; text-align: left; margin-left: 42px; }
|
|
335
|
+
.evidence-pane .mobile-label { display: block; font-size: 11px; color: var(--secondary); margin-bottom: 3px; }
|
|
336
|
+
.evidence-pane .symbol, .evidence-pane .token-description { max-width: 100%; }
|
|
337
|
+
}
|
|
338
|
+
@media (min-width: 1550px) {
|
|
339
|
+
.workspace { grid-template-columns: minmax(0, 1fr) minmax(390px, 36%); gap: 36px; }
|
|
340
|
+
.content { padding: 36px 40px; }
|
|
341
|
+
.topbar, .workspace-tabs { padding-left: 40px; padding-right: 40px; }
|
|
342
|
+
.dashboard-grid { grid-template-columns: 1.12fr 1fr; gap: 24px; }
|
|
343
|
+
.wallet-cards { grid-template-columns: 1fr; }
|
|
344
|
+
.kira-scene { height: 260px; }
|
|
345
|
+
.kira-scene img { height: 280px; width: 220px; right: 16px; }
|
|
346
|
+
.scene-caption { padding-top: 70px; }
|
|
347
|
+
.scene-caption > span:first-child { font-size: 30px; }
|
|
348
|
+
}
|
|
349
|
+
@media (min-width: 981px) and (max-width: 1150px) {
|
|
350
|
+
.sidebar { width: 216px; padding-left: 14px; padding-right: 14px; }
|
|
351
|
+
main { margin-left: 216px; width: calc(100% - 216px); }
|
|
352
|
+
.content { padding: 24px; }
|
|
353
|
+
.workspace { gap: 20px; grid-template-columns: minmax(0, 1fr) 320px; }
|
|
354
|
+
.topbar, .workspace-tabs { padding-left: 24px; padding-right: 24px; }
|
|
355
|
+
.home-summary { padding: 20px; }
|
|
356
|
+
.home-summary .total-value { font-size: 36px; }
|
|
357
|
+
.home-stats { gap: 8px; }
|
|
358
|
+
.kira-panel-heading, .kira-conversation, .composer { padding-left: 18px; padding-right: 18px; }
|
|
359
|
+
.kira-panel-heading .eyebrow { max-width: 150px; }
|
|
360
|
+
.scene-caption { padding-left: 18px; }
|
|
361
|
+
.scene-caption > span:first-child { font-size: 23px; }
|
|
362
|
+
}
|
|
363
|
+
@media (min-width: 981px) and (max-height: 800px) {
|
|
364
|
+
.kira-panel { min-height: 0; }
|
|
365
|
+
.kira-scene { height: 150px; }
|
|
366
|
+
.kira-scene img { height: 178px; width: 150px; bottom: -18px; }
|
|
367
|
+
.scene-caption { padding-top: 26px; gap: 8px; }
|
|
368
|
+
.scene-caption > span:first-child { font-size: 23px; }
|
|
369
|
+
.kira-panel-heading { padding-top: 16px; }
|
|
370
|
+
.kira-panel-heading h2 { font-size: 25px; }
|
|
371
|
+
.composer { padding-top: 12px; padding-bottom: 12px; }
|
|
372
|
+
.kira-conversation { padding-top: 14px; }
|
|
373
|
+
}
|
|
374
|
+
/* Let short desktop windows scroll the complete panel, including its composer. */
|
|
375
|
+
@media (min-width: 981px) and (max-height: 650px) {
|
|
376
|
+
.kira-panel { position: static; height: auto; max-height: none; }
|
|
377
|
+
.kira-conversation { flex: none; overflow: visible; }
|
|
378
|
+
}
|
|
379
|
+
@media (max-width: 980px) {
|
|
380
|
+
.sidebar { position: static; width: 100%; padding: 16px 20px 12px; display: flex; flex-direction: row; flex-wrap: wrap; align-items: center; gap: 12px; }
|
|
381
|
+
.brand { padding: 0; font-size: 25px; }
|
|
382
|
+
.brand-logo { width: 40px; height: 40px; }
|
|
383
|
+
.brand-caption { font-size: 10px; }
|
|
384
|
+
.workspace-label, .sidebar-intro, .sidebar-label, .sidebar-bottom { display: none; }
|
|
385
|
+
#wallet-list { width: 100%; order: 3; display: flex; overflow: auto; max-height: none; min-height: 0; gap: 8px; margin: 0; }
|
|
386
|
+
.wallet-button:not(.home-button) { width: auto; min-width: 164px; padding: 9px 12px; min-height: 56px; flex-shrink: 0; border-color: #51445e; }
|
|
387
|
+
.user-controls { display: flex; gap: 8px; margin-left: auto; margin-top: 0; padding: 0; }
|
|
388
|
+
.user-controls .primary-button { min-height: 44px; padding: 11px 12px; white-space: nowrap; }
|
|
389
|
+
.settings-button { min-height: 44px; min-width: 44px; width: 44px; padding: 0; justify-content: center; }
|
|
390
|
+
.settings-label, .user-controls p { display: none; }
|
|
391
|
+
.wallet-session-panel { order: 4; width: 100%; display: flex; align-items: center; gap: 12px; margin: 0; padding: 0; }
|
|
392
|
+
#wallet-session { flex: none; }
|
|
393
|
+
#wallet-session-name { min-width: 0; }
|
|
394
|
+
.app { display: block; }
|
|
395
|
+
main { width: 100%; margin: 0; }
|
|
396
|
+
.topbar { height: 44px; padding: 0 20px; }
|
|
397
|
+
.sync-status { display: none; }
|
|
398
|
+
.demo-badge { font-size: 10px; margin: 0; }
|
|
399
|
+
.workspace-tabs { height: auto; min-height: 52px; padding: 0 20px; gap: 24px; flex-wrap: wrap; }
|
|
400
|
+
.workspace-tabs > a { min-height: 52px; }
|
|
401
|
+
.mobile-pane-control { display: flex; width: 100%; border-top: 1px solid var(--line); gap: 6px; padding: 10px 0; }
|
|
402
|
+
.mobile-pane-control button { font-size: 14px; min-height: 44px; border: 1px solid transparent; border-radius: 9px; padding: 10px 16px; background: none; color: #776384; flex: 1; font-weight: 500; }
|
|
403
|
+
.mobile-pane-control button[aria-pressed=true] { border-color: #d5c4e2; background: #eee6f5; color: #66427b; }
|
|
404
|
+
.content { padding: 26px 20px; }
|
|
405
|
+
.workspace { display: block; }
|
|
406
|
+
.kira-panel { display: none; position: static; height: max(600px, calc(100dvh - 370px)); min-height: 0; max-height: none; }
|
|
407
|
+
.workspace[data-pane=kira] .evidence-pane { display: none; }
|
|
408
|
+
.workspace[data-pane=kira] .kira-panel { display: flex; }
|
|
409
|
+
.home-heading h1 { font-size: 34px; }
|
|
410
|
+
.home-summary { padding: 24px; margin-top: 24px; }
|
|
411
|
+
.home-summary .total-value { font-size: 42px; }
|
|
412
|
+
.wallet-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
413
|
+
.edition-mark { display: block; }
|
|
414
|
+
.kira-scene { height: 170px; }
|
|
415
|
+
.kira-scene img { width: 170px; height: 195px; right: 12px; bottom: -15px; }
|
|
416
|
+
.scene-caption { padding-top: 30px; max-width: 46%; }
|
|
417
|
+
.scene-caption > span:first-child { font-size: 25px; }
|
|
418
|
+
.job-row { flex-direction: column; }
|
|
419
|
+
.job-actions { align-self: flex-end; }
|
|
420
|
+
.job-identity a { display: inline; margin-left: 8px; }
|
|
421
|
+
.research-jobs { padding: 18px; }
|
|
422
|
+
.research-dialog { padding: 22px; }
|
|
423
|
+
.research-dialog input:not([type=checkbox]), .research-dialog textarea, .research-dialog select,
|
|
424
|
+
.composer textarea, .token-search input, .token-catalog-controls input { font-size: 16px; }
|
|
425
|
+
}
|
|
426
|
+
@media (max-width: 520px) {
|
|
427
|
+
.brand-caption { display: none; }
|
|
428
|
+
.watching-label { display: none; }
|
|
429
|
+
.wallet-cards { grid-template-columns: 1fr; }
|
|
430
|
+
.edition-mark { display: none; }
|
|
431
|
+
.home-heading h1, .view-heading h1 { font-size: 32px; }
|
|
432
|
+
.home-summary { padding: 22px 20px; }
|
|
433
|
+
.home-stats { gap: 10px; }
|
|
434
|
+
.home-stats strong { font-size: 24px; }
|
|
435
|
+
.token-catalog-controls { grid-template-columns: 1fr; }
|
|
436
|
+
.token-catalog-controls > label { grid-column: 1 / -1; }
|
|
437
|
+
.kira-panel-heading, .kira-conversation, .composer { padding-left: 18px; padding-right: 18px; }
|
|
438
|
+
.scene-caption { padding-left: 18px; }
|
|
439
|
+
.kira-panel-heading .eyebrow { max-width: 150px; }
|
|
440
|
+
.kira-scene img { right: 4px; width: 160px; }
|
|
441
|
+
.wallet-heading h1, .detail-heading h1 { font-size: 30px; }
|
|
442
|
+
}
|
|
443
|
+
@media (max-width: 360px) {
|
|
444
|
+
.sidebar { padding: 14px 16px 12px; gap: 8px; }
|
|
445
|
+
.brand { font-size: 23px; gap: 7px; }
|
|
446
|
+
.brand-logo { width: 32px; height: 32px; }
|
|
447
|
+
.user-controls .primary-button { padding: 11px 9px; font-size: 12px; gap: 6px; }
|
|
448
|
+
.user-controls .primary-button .ui-icon { width: 16px; height: 16px; }
|
|
449
|
+
.topbar, .workspace-tabs { padding-left: 16px; padding-right: 16px; }
|
|
450
|
+
.workspace-tabs { gap: 20px; }
|
|
451
|
+
.workspace-tabs > a { font-size: 13px; gap: 5px; }
|
|
452
|
+
.content { padding: 24px 16px; }
|
|
453
|
+
.home-heading h1 { font-size: 29px; }
|
|
454
|
+
.home-summary .total-value { font-size: 36px; }
|
|
455
|
+
.home-stats { gap: 8px; }
|
|
456
|
+
.home-summary { padding: 20px 16px; }
|
|
457
|
+
.kira-panel-heading { gap: 8px; }
|
|
458
|
+
.kira-panel-heading .eyebrow { max-width: 138px; }
|
|
459
|
+
.local-badge { font-size: 10px; padding: 4px 6px; }
|
|
460
|
+
.scene-caption > span:first-child { font-size: 23px; }
|
|
461
|
+
.scene-caption small { max-width: 112px; }
|
|
462
|
+
}
|
|
463
|
+
@media (prefers-reduced-motion: reduce) { .spinner { animation: none; } }
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
let catalogPage = 1;
|
|
3
|
+
let briefingMode = 'view';
|
|
4
|
+
let catalogTimer;
|
|
5
|
+
function catalogFilters() {
|
|
6
|
+
return { search: $('all-token-search').value, network: $('all-token-network').value,
|
|
7
|
+
pricing: $('all-token-pricing').value, sort: $('all-token-sort').value,
|
|
8
|
+
testnets: $('all-token-testnets').checked, page: catalogPage };
|
|
9
|
+
}
|
|
10
|
+
function renderCatalog() {
|
|
11
|
+
if (!state) return;
|
|
12
|
+
const result = KiraView.catalog(state.details.tokens, catalogFilters());
|
|
13
|
+
catalogPage = result.page;
|
|
14
|
+
$('all-token-result').textContent = result.count + (result.count === 1 ? ' token · ' : ' tokens · ') + (result.count ? ((result.page - 1) * 50 + 1) + '–' + Math.min(result.page * 50, result.count) + ' shown' : 'none shown');
|
|
15
|
+
$('tokens-page').textContent = result.page + ' / ' + result.pages;
|
|
16
|
+
$('tokens-prev').disabled = result.page === 1;
|
|
17
|
+
$('tokens-next').disabled = result.page === result.pages;
|
|
18
|
+
$('all-token-empty').hidden = result.count > 0;
|
|
19
|
+
$('all-token-body').innerHTML = result.rows.map(a => {
|
|
20
|
+
const network = state.details.networks.find(n => n.id === a.chain_id);
|
|
21
|
+
return `<tr><td><a class="token-name token-link" href="${tokenHref(a.id)}">${coinIcon(a)}<div class="coin-title"><div class="symbol">${escapeHTML(a.symbol)}</div><div class="token-description">${escapeHTML(network?.name || 'Chain ' + a.chain_id)}${a.environment === 'testnet' ? ' · Testnet' : ''}</div></div></a></td><td><span class="mobile-label">Total balance</span><span class="amount" title="${escapeHTML(a.balance)}">${quantity(a.balance)}</span></td><td><span class="mobile-label">Wallets</span>${a.wallet_count}</td><td><span class="token-value">${a.environment === 'testnet' ? 'Testnet' : money(a.value_usd)}</span>${a.unpriced_count ? '<div class="price-basis">' + a.unpriced_count + ' unpriced</div>' : ''}</td></tr>`;
|
|
22
|
+
}).join('');
|
|
23
|
+
bindImages();
|
|
24
|
+
}
|
|
25
|
+
function renderWorkspace() {
|
|
26
|
+
if (!state) return;
|
|
27
|
+
$('tokens-view').hidden = selectedView !== 'tokens';
|
|
28
|
+
$('activity-view').hidden = selectedView !== 'activity';
|
|
29
|
+
document.querySelectorAll('[data-view]').forEach(link => {
|
|
30
|
+
const current = link.dataset.view === selectedView || (link.dataset.view === 'home' && ['wallet', 'token', 'network'].includes(selectedView));
|
|
31
|
+
if (current) link.setAttribute('aria-current', 'page'); else link.removeAttribute('aria-current');
|
|
32
|
+
});
|
|
33
|
+
if (selectedView === 'home') $('brand-home').setAttribute('aria-current', 'page'); else $('brand-home').removeAttribute('aria-current');
|
|
34
|
+
$('all-token-count').textContent = state.details.tokens.filter(t => t.environment !== 'testnet').length;
|
|
35
|
+
if (selectedView === 'tokens') {
|
|
36
|
+
renderBreadcrumb([{ label: 'Home', href: '#/home' }, { label: 'All tokens' }]);
|
|
37
|
+
document.title = 'All tokens · Kira Wallet';
|
|
38
|
+
const network = $('all-token-network').value;
|
|
39
|
+
const recordedChains = new Set(state.details.tokens.map(t => t.chain_id));
|
|
40
|
+
$('all-token-network').innerHTML = '<option value="all">All networks</option>' + state.details.networks.filter(n => recordedChains.has(n.id)).map(n => `<option value="${n.id}">${escapeHTML(n.name)}${n.environment === 'testnet' ? ' · Testnet' : ''}</option>`).join('');
|
|
41
|
+
$('all-token-network').value = [...$('all-token-network').options].some(o => o.value === network) ? network : 'all';
|
|
42
|
+
$('sync-label').textContent = 'Latest recorded holdings'; renderCatalog();
|
|
43
|
+
} else if (selectedView === 'activity') {
|
|
44
|
+
renderBreadcrumb([{ label: 'Home', href: '#/home' }, { label: 'Activity' }]);
|
|
45
|
+
document.title = 'Activity · Kira Wallet'; $('sync-label').textContent = 'Local research history';
|
|
46
|
+
}
|
|
47
|
+
renderBriefing();
|
|
48
|
+
}
|
|
49
|
+
function renderBriefing() {
|
|
50
|
+
if (!state) return;
|
|
51
|
+
renderKiraNote();
|
|
52
|
+
const active = typeof jobList !== 'undefined' && jobList.some(KiraView.active);
|
|
53
|
+
const gaps = state.wallets.reduce((sum, w) => sum + w.chains.filter(c => c.environment === 'mainnet' && (!c.complete || !c.rpc_available)).length, 0);
|
|
54
|
+
let art = 'welcome', caption = 'A little perspective.', note = 'Here to make sense of it.';
|
|
55
|
+
if (active) { art = 'research'; caption = 'Following the evidence.'; note = 'Research is in progress.'; }
|
|
56
|
+
else if (gaps && briefingMode === 'coverage') { art = 'attention'; caption = 'A closer look.'; note = 'Some facts are still missing.'; }
|
|
57
|
+
else if (selectedView === 'activity') { art = 'review'; caption = 'Every step, recorded.'; note = 'Good research leaves a trail.'; }
|
|
58
|
+
else if (['token', 'network', 'tokens', 'wallet'].includes(selectedView)) { art = 'explain'; caption = 'Let’s look a little closer.'; note = 'Context makes the difference.'; }
|
|
59
|
+
const src = art === 'welcome' ? '/kira.png' : '/kira-' + art + '.png';
|
|
60
|
+
if ($('kira-scene-art').getAttribute('src') !== src) $('kira-scene-art').src = src;
|
|
61
|
+
$('kira-scene-art').alt = { welcome: 'Kira holding her research notebook', research: 'Kira writing while researching', explain: 'Kira explaining a finding', review: 'Kira reviewing saved notes', attention: 'Kira carefully checking incomplete evidence' }[art];
|
|
62
|
+
$('kira-mood').textContent = caption; $('kira-scene-note').textContent = note;
|
|
63
|
+
$('kira-context').textContent = selectedView === 'wallet' ? currentWallet()?.name || 'Wallet' : selectedView === 'token' ? state.details.tokens.find(t => t.id === selectedToken)?.symbol || 'Token' : selectedView === 'network' ? state.details.networks.find(n => n.id === selectedNetwork)?.name || 'Network' : { home: 'Portfolio overview', tokens: 'All tokens', activity: 'Research activity' }[selectedView];
|
|
64
|
+
if (briefingMode === 'coverage') {
|
|
65
|
+
const selected = selectedView === 'wallet' ? [currentWallet()].filter(Boolean) : state.wallets;
|
|
66
|
+
const missing = selected.flatMap(w => w.chains.filter(c => c.environment === 'mainnet' && (!c.complete || !c.rpc_available)).map(c => w.name + ' · ' + c.name + (!c.rpc_available ? ': RPC unavailable' : ': incomplete discovery')));
|
|
67
|
+
$('kira-note-text').textContent = missing.length ? 'These recorded coverage gaps need a closer look: ' + missing.slice(0, 6).join('; ') + (missing.length > 6 ? '; and ' + (missing.length - 6) + ' more.' : '.') + ' Missing data does not mean zero holdings.' : 'No mainnet coverage gaps are flagged in this recorded view. This does not prove that every possible token has been discovered.';
|
|
68
|
+
} else if (selectedView === 'tokens') {
|
|
69
|
+
const tokens = state.details.tokens.filter(t => t.environment !== 'testnet');
|
|
70
|
+
$('kira-note-text').textContent = `There are ${tokens.length} recorded mainnet tokens. ${tokens.filter(t => t.value_usd == null || t.unpriced_count > 0).length} have unpriced amounts. I keep tokens on different networks separate, even when their symbols match.`;
|
|
71
|
+
} else if (selectedView === 'activity') {
|
|
72
|
+
const running = typeof jobList === 'undefined' ? 0 : jobList.filter(KiraView.active).length;
|
|
73
|
+
$('kira-note-text').textContent = running ? `${running} local research ${running === 1 ? 'job is' : 'jobs are'} in progress. The timeline shows the last recorded stage, elapsed time and freshness. A quiet stage is not proof that a worker stopped.` : 'There is no recorded job in progress. Completed work stays in the timeline, along with partial results, interruptions and failed attempts.';
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
for (const id of ['all-token-network', 'all-token-pricing', 'all-token-sort', 'all-token-testnets']) $(id).addEventListener('change', () => { catalogPage = 1; renderCatalog(); });
|
|
77
|
+
$('all-token-search').addEventListener('input', () => { clearTimeout(catalogTimer); catalogTimer = setTimeout(() => { catalogPage = 1; renderCatalog(); }, 120); });
|
|
78
|
+
$('tokens-prev').addEventListener('click', () => { catalogPage--; renderCatalog(); });
|
|
79
|
+
$('tokens-next').addEventListener('click', () => { catalogPage++; renderCatalog(); });
|
|
80
|
+
function setWorkspacePane(pane) {
|
|
81
|
+
document.querySelector('.workspace').dataset.pane = pane;
|
|
82
|
+
document.querySelectorAll('.mobile-pane-control [data-pane]').forEach(button => button.setAttribute('aria-pressed', String(button.dataset.pane === pane)));
|
|
83
|
+
}
|
|
84
|
+
document.querySelectorAll('.mobile-pane-control [data-pane]').forEach(button => button.addEventListener('click', () => {
|
|
85
|
+
setWorkspacePane(button.dataset.pane);
|
|
86
|
+
if (button.dataset.pane === 'kira' && matchMedia('(max-width: 980px)').matches) {
|
|
87
|
+
document.querySelector('.workspace').scrollIntoView({ block: 'start', behavior: 'instant' });
|
|
88
|
+
}
|
|
89
|
+
}));
|
|
90
|
+
// Explicit navigation must reveal the selected evidence, including same-route clicks.
|
|
91
|
+
document.addEventListener('click', event => {
|
|
92
|
+
if (event.target.closest('a[href^="#/"]')) setWorkspacePane('portfolio');
|
|
93
|
+
});
|
|
94
|
+
document.querySelectorAll('[data-brief]').forEach(button => button.addEventListener('click', () => {
|
|
95
|
+
if (button.dataset.brief === 'coverage') { briefingMode = 'coverage'; renderBriefing(); }
|
|
96
|
+
else if (button.dataset.brief === 'unpriced') { briefingMode = 'view'; $('all-token-pricing').value = 'unpriced'; catalogPage = 1; navigate('#/tokens'); renderCatalog(); }
|
|
97
|
+
else { briefingMode = 'view'; navigate('#/activity'); }
|
|
98
|
+
if (button.dataset.brief !== 'coverage') document.querySelector('.mobile-pane-control [data-pane="portfolio"]').click();
|
|
99
|
+
}));
|
|
100
|
+
window.addEventListener('hashchange', () => { briefingMode = 'view'; setWorkspacePane('portfolio'); renderWorkspace(); });
|
|
101
|
+
try { localStorage.removeItem('kira-draft'); } catch { /* Drafts are now memory-only. */ }
|
|
102
|
+
renderWorkspace();
|