theseus/bundled-addons/aegis/panel.html

1207 lines
79 KiB
HTML
Raw Normal View History

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Aegis Wallet</title>
<!-- Aegis brand mark from aegis.x/brand/favicon.svg — kept byte-close so
the sidebar-tab icon reads as the identity a user just downloaded from. -->
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;utf8,%3Csvg%20xmlns%3D'http%3A//www.w3.org/2000/svg'%20viewBox%3D'0%200%2032%2032'%20fill%3D'none'%3E%3Cpolygon%20points%3D'16%2C2%2028%2C9%2028%2C23%2016%2C30%204%2C23%204%2C9'%20fill%3D'%230a0a0d'%20stroke%3D'%23D6FF3D'%20stroke-width%3D'1.6'%20stroke-linejoin%3D'round'/%3E%3Ccircle%20cx%3D'16'%20cy%3D'16'%20r%3D'4.5'%20fill%3D'none'%20stroke%3D'%23D6FF3D'%20stroke-width%3D'1.4'/%3E%3Ccircle%20cx%3D'16'%20cy%3D'16'%20r%3D'1.6'%20fill%3D'%23D6FF3D'/%3E%3C/svg%3E">
<style>
:root { color-scheme: light dark;
--bg:#0e131c; --panel:#141a24; --card:#0f1621; --line:rgba(255,255,255,.09);
--ink:#e7eaf1; --mut:#8b98a9; --dim:#5e6678; --acid:#d6ff3d; --danger:#f6768a; --ok:#5ad38a;
--bch:#0ac18e; --trx:#ff060a; --trxNile:#4d9dff; }
@media (prefers-color-scheme: light) {
:root { --bg:#f8faff; --panel:#ffffff; --card:#f1f4fa; --line:rgba(0,0,0,.10);
--ink:#1a1f2b; --mut:#5c6577; --dim:#8a93a5;
/* Darker acid on light backgrounds — ~7:1 contrast on white. */
--acid: #0AC18E; }
}
* { box-sizing: border-box; }
html, body { margin: 0; height: 100%; }
body { background: var(--bg); color: var(--ink);
font: 13.5px/1.5 system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
display: flex; flex-direction: column; position: relative; }
header { padding: 10px 14px 10px; border-bottom: 1px solid var(--line); background: var(--panel); position: relative; }
.picker { display: flex; align-items: center; justify-content: space-between; gap: 8px; cursor: pointer; user-select: none; }
.picker .t { display: flex; align-items: center; gap: 7px; font-weight: 600; min-width: 0; }
.picker .t .badge { font-size: 15px; line-height: 1; }
.picker .t .lbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.picker .caret { color: var(--mut); font-size: 10px; }
.picker:hover { color: var(--acid); }
.net { display: flex; align-items: center; gap: 6px; color: var(--dim); font-size: 11.5px; white-space: nowrap; }
.dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dim); }
.dot.on { background: var(--ok); } .dot.busy { background: #e0b341; }
/* Balance hero. Every modern wallet leads with one large numeral and pushes
the fractional part back to ~40% opacity, so the eye reads magnitude
before precision; the ticker and the fiat conversion are annotations on
that number rather than peers of it. Baseline-aligned flex keeps them on
the numeral's baseline however long the amount grows. */
.bal { margin-top: 10px; font-variant-numeric: tabular-nums; }
.bal .big { font-size: 32px; font-weight: 680; letter-spacing: -.6px; line-height: 1.1;
display: flex; align-items: baseline; gap: 5px; flex-wrap: wrap; }
.bal .big .dec { color: var(--dim); font-weight: 620; }
.bal .big small { font-size: 13px; color: var(--mut); font-weight: 500; margin-left: 0; }
/* Scoped to the hero — .fiat is also the Send form's conversion line. */
.bal .big .fiat { font-size: 14px; margin-left: 6px; }
.bal .sub { color: var(--dim); font-size: 11.5px; display: flex; align-items: center; gap: 8px; margin-top: 3px; }
chore(aegis): 0.9.2 — Receive tab reorder, one balance, token history Receive was ordered QR → address → tokens, so 200px of always-on QR sat above the thing people came for and pushed the asset list off screen. - Address first, with Copy and a QR button; the QR expands inline and the choice sticks, because someone who receives by QR wants it every time and someone who copies never does. - Explorer and Faucet moved up to the header status row. They act on the selected wallet, not on the act of receiving, and down there they competed with Copy for the one row that gets used. - Assets card renamed from Tokens and now leads with the native coin, so "what does this wallet hold" is one list rather than two places. - "+ Add another <TICKER>" moved below the address list. The balance appeared three times — header, drilldown subtitle, address row. Now once in the header; the subtitle keeps only the per-unit price, and the per-address amount returns when a coin actually has more than one address to compare. The address row drops its truncated address (the full one is at the top of Receive) and keeps the wallet name. The per-address asset list added in 0.8.8 duplicated the Assets card and is removed — assets live in one place. Token amounts were unreadable: an 18-decimal balance rendered as 60000000.000000005435817984. Capped to 8 decimals with thousands separators, exact value on hover. A symbol claimed by more than one contract now carries a LOOK-ALIKE tag. The test wallet holds four different contracts all calling themselves "Test USDT" — spam mints borrowing a trusted ticker so a careless send lands on the wrong one. We can't tell which is genuine, so we mark every member of the clash rather than guessing. History showed native transfers only, so a wallet that had only ever moved USDT looked empty. TRC20 transfers are merged in newest-first, each carrying its own decimals and ticker (rendering a token against the chain's scale would be off by orders of magnitude). Both feeds are on by default; the checkboxes narrow rather than opt in, and the last one checked can't be unchecked into an empty list.
2026-09-23 01:17:33 +02:00
.bal .sub .netlbl { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* Full-panel sheet — fills most of the sidebar but stops above the
footer so the aegis.x brand + version chip stay visible. Users
opening + should still know which build they're on and be able
to hit the update button. */
#drop { position: fixed; left: 0; right: 0; top: 60px; bottom: 30px;
background: var(--panel); border-top: 1px solid var(--line);
box-shadow: 0 -6px 26px rgba(0,0,0,.35); z-index: 20;
display: flex; flex-direction: column; }
#drop[hidden] { display: none; }
#drop .droptabs { display: flex; border-bottom: 1px solid var(--line); flex: none; }
#drop .droptabs button { flex: 1; background: transparent; border: 0; color: var(--dim);
padding: 10px 8px; font: inherit; font-size: 13px; cursor: pointer; border-bottom: 2px solid transparent; }
#drop .droptabs button.on { color: var(--ink); border-bottom-color: var(--acid, #d6ff3d); font-weight: 600; }
#drop .droptabs .closex { flex: none; width: 40px; font-size: 16px; color: var(--dim); border-left: 1px solid var(--line); }
#drop .droppane { flex: 1; overflow-y: auto; padding: 6px; }
#drop .droppane[hidden] { display: none; }
#drop .row, #drop .coinrow { display: flex; align-items: center; gap: 9px; padding: 8px 10px; border-radius: 7px; cursor: pointer; }
#drop .row:hover, #drop .coinrow:hover { background: rgba(255,255,255,.05); }
#drop .row .m, #drop .coinrow .m { flex: 1; min-width: 0; }
#drop .row .m .l, #drop .coinrow .m .l { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#drop .row .m .s, #drop .coinrow .m .s { color: var(--dim); font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#drop .row .v { color: var(--mut); font-size: 12px; font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
#drop .row .v .fs { color: var(--dim); font-size: 11px; margin-top: 2px; }
#drop .row.on { background: rgb(from var(--acid) r g b / .10); }
#drop .coinrow .caret { color: var(--dim); font-size: 11px; }
#drop hr { border: 0; border-top: 1px solid var(--line); margin: 6px 0; }
#drop .addhdr { padding: 5px 8px 3px; color: var(--dim); font-size: 11px; text-transform: uppercase; letter-spacing: .04em; }
#drop .netgroup { padding: 2px 4px 6px 40px; }
#drop .netgroup[hidden] { display: none; }
#drop .netchoice { padding: 6px 8px; border-radius: 6px; cursor: pointer; font-size: 12.5px; color: var(--mut); }
#drop .netchoice:hover { background: rgba(255,255,255,.06); color: var(--ink); }
/* Currency-browse network chip row (0.8.0). Sits above the wallet list
under a coin; clicking a chip switches which subnetwork's wallets
are visible AND persists the choice per chain. */
#drop .brnetrow { display: flex; gap: 6px; padding: 8px 8px 4px; flex-wrap: wrap; border-bottom: 1px solid var(--line); }
#drop .brnet { background: transparent; border: 1px solid var(--line); color: var(--mut);
border-radius: 999px; padding: 3px 10px; font: inherit; font-size: 12px; cursor: pointer;
display: inline-flex; align-items: center; gap: 4px; }
#drop .brnet:hover { border-color: var(--acid, #d6ff3d); color: var(--acid, #d6ff3d); }
#drop .brnet.on { background: rgb(from var(--acid, #d6ff3d) r g b / .14); border-color: rgb(from var(--acid, #d6ff3d) r g b / .55);
color: var(--acid, #d6ff3d); font-weight: 600; }
#drop .brnet .hint { color: currentColor; opacity: .65; font-size: 11px; }
chore(aegis): 0.9.2 — Receive tab reorder, one balance, token history Receive was ordered QR → address → tokens, so 200px of always-on QR sat above the thing people came for and pushed the asset list off screen. - Address first, with Copy and a QR button; the QR expands inline and the choice sticks, because someone who receives by QR wants it every time and someone who copies never does. - Explorer and Faucet moved up to the header status row. They act on the selected wallet, not on the act of receiving, and down there they competed with Copy for the one row that gets used. - Assets card renamed from Tokens and now leads with the native coin, so "what does this wallet hold" is one list rather than two places. - "+ Add another <TICKER>" moved below the address list. The balance appeared three times — header, drilldown subtitle, address row. Now once in the header; the subtitle keeps only the per-unit price, and the per-address amount returns when a coin actually has more than one address to compare. The address row drops its truncated address (the full one is at the top of Receive) and keeps the wallet name. The per-address asset list added in 0.8.8 duplicated the Assets card and is removed — assets live in one place. Token amounts were unreadable: an 18-decimal balance rendered as 60000000.000000005435817984. Capped to 8 decimals with thousands separators, exact value on hover. A symbol claimed by more than one contract now carries a LOOK-ALIKE tag. The test wallet holds four different contracts all calling themselves "Test USDT" — spam mints borrowing a trusted ticker so a careless send lands on the wrong one. We can't tell which is genuine, so we mark every member of the clash rather than guessing. History showed native transfers only, so a wallet that had only ever moved USDT looked empty. TRC20 transfers are merged in newest-first, each carrying its own decimals and ticker (rendering a token against the chain's scale would be off by orders of magnitude). Both feeds are on by default; the checkboxes narrow rather than opt in, and the last one checked can't be unchecked into an empty list.
2026-09-23 01:17:33 +02:00
.histfilter { display: flex; align-items: center; gap: 14px; padding: 0 2px 10px;
border-bottom: 1px solid var(--line); margin-bottom: 8px; font-size: 12px; }
.histfilter[hidden] { display: none; }
/* Assets card rows (0.9.2). The native coin leads the list; a symbol
claimed by several contracts gets a LOOK-ALIKE tag so a borrowed
ticker can't pass for the real token. */
.tx.asset { padding: 7px 8px; border-radius: 6px; }
.tx.asset:hover { background: rgba(255,255,255,.04); }
.tx.asset.native { background: rgb(from var(--acid, #d6ff3d) r g b / .06); }
.ttag.tdupe { background: rgba(224,90,90,.18); color: #f6768a; cursor: help; }
.ttag { display: inline-block; font-size: 9.5px; letter-spacing: .06em; padding: 1px 5px; border-radius: 3px;
background: rgba(224,179,65,.18); color: #e0b341; font-weight: 700; vertical-align: middle; margin-left: 2px; }
/* 0.8.4: hNet became a proper chip on its own row (.netrow) so the
network the wallet is on is easy to spot AND easy to switch. */
.netrow { display: flex; margin-top: 6px; padding: 0 2px; }
.netchip { background: rgba(255,255,255,.05); border: 1px solid var(--line);
color: var(--mut); border-radius: 999px; padding: 3px 10px 3px 8px;
font: inherit; font-size: 11.5px; cursor: pointer; display: inline-flex;
align-items: center; gap: 6px; line-height: 1.2; }
.netchip:hover { border-color: var(--acid, #d6ff3d); color: var(--acid, #d6ff3d); }
.netchip::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; opacity: .7; }
/* Currency-picker search + all-coins catalogue (0.8.4). */
#drop .pickersearch { padding: 8px; border-bottom: 1px solid var(--line); }
2026-09-23 02:49:05 +02:00
/* Search + close share the top row now that the title row is gone. */
#drop .pickersearch-top { display: flex; align-items: center; gap: 6px; }
#drop .pickersearch-top input { flex: 1; min-width: 0; }
#drop .pickersearch input { width: 100%; box-sizing: border-box; background: rgba(255,255,255,.04);
border: 1px solid var(--line); color: var(--ink); border-radius: 7px;
padding: 7px 10px; font: inherit; font-size: 12.5px; outline: none; }
#drop .pickersearch input:focus { border-color: rgb(from var(--acid, #d6ff3d) r g b / .55); }
#drop .catgroup { padding: 4px 6px 2px 10px; color: var(--dim); font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; }
#drop .row.unowned { opacity: .8; }
#drop .row.unowned .v { color: var(--acid, #d6ff3d); font-weight: 600; font-size: 11px; }
chore(aegis): 0.9.2 — Receive tab reorder, one balance, token history Receive was ordered QR → address → tokens, so 200px of always-on QR sat above the thing people came for and pushed the asset list off screen. - Address first, with Copy and a QR button; the QR expands inline and the choice sticks, because someone who receives by QR wants it every time and someone who copies never does. - Explorer and Faucet moved up to the header status row. They act on the selected wallet, not on the act of receiving, and down there they competed with Copy for the one row that gets used. - Assets card renamed from Tokens and now leads with the native coin, so "what does this wallet hold" is one list rather than two places. - "+ Add another <TICKER>" moved below the address list. The balance appeared three times — header, drilldown subtitle, address row. Now once in the header; the subtitle keeps only the per-unit price, and the per-address amount returns when a coin actually has more than one address to compare. The address row drops its truncated address (the full one is at the top of Receive) and keeps the wallet name. The per-address asset list added in 0.8.8 duplicated the Assets card and is removed — assets live in one place. Token amounts were unreadable: an 18-decimal balance rendered as 60000000.000000005435817984. Capped to 8 decimals with thousands separators, exact value on hover. A symbol claimed by more than one contract now carries a LOOK-ALIKE tag. The test wallet holds four different contracts all calling themselves "Test USDT" — spam mints borrowing a trusted ticker so a careless send lands on the wrong one. We can't tell which is genuine, so we mark every member of the clash rather than guessing. History showed native transfers only, so a wallet that had only ever moved USDT looked empty. TRC20 transfers are merged in newest-first, each carrying its own decimals and ticker (rendering a token against the chain's scale would be off by orders of magnitude). Both feeds are on by default; the checkboxes narrow rather than opt in, and the last one checked can't be unchecked into an empty list.
2026-09-23 01:17:33 +02:00
/* Per-wallet actions promoted into the header's status row (0.9.2). */
.hdracts { margin-left: auto; display: inline-flex; gap: 4px; }
.hdract { background: transparent; border: 1px solid var(--line); color: var(--dim);
border-radius: 999px; padding: 1px 9px; font: inherit; font-size: 10.5px;
cursor: pointer; line-height: 1.5; }
.hdract:hover { border-color: var(--acid, #d6ff3d); color: var(--acid, #d6ff3d); }
.hdract[hidden] { display: none; }
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
.fiat { color: var(--dim); font-size: 12.5px; margin-left: 10px; font-weight: 500; letter-spacing: .2px; }
.portfolio { margin-top: 6px; color: var(--mut); font-size: 11.5px; }
.portfolio b { color: var(--ink); font-weight: 600; }
.portfolio[hidden] { display: none; }
.picker-actions { display: flex; align-items: center; gap: 6px; }
.chip { background: transparent; border: 1px solid var(--line); color: var(--mut); border-radius: 6px;
padding: 0 8px; height: 22px; cursor: pointer; font: inherit; font-size: 13.5px; line-height: 1;
display: inline-flex; align-items: center; justify-content: center; }
.chip:hover { border-color: var(--acid); color: var(--acid); }
/* Edit-this-wallet button living inside the label group. Compact and
borderless so it reads as an inline affordance, not a separate
action chip. Fades in on hover of the label row so the header
itself stays visually quiet when the user isn't targeting it. */
.editchip { background: transparent; border: 0; color: var(--dim); cursor: pointer;
padding: 2px 4px; border-radius: 4px; font: inherit; font-size: 12px; line-height: 1;
opacity: .5; transition: opacity .12s, color .12s; margin-left: 2px; }
.picker:hover .editchip { opacity: 1; }
.editchip:hover { color: var(--acid, #d6ff3d); background: rgba(255,255,255,.06); }
/* Send/Receive mode toggle (0.8.0). Segmented control at the top of a
tab; picks whether the body shows the normal flow or the consolidate
inline picker. */
.modetoggle { display: flex; gap: 0; border: 1px solid var(--line); border-radius: 8px; padding: 3px;
margin-bottom: 12px; background: rgba(255,255,255,.03); }
.modetoggle[hidden] { display: none; }
.modetoggle button { flex: 1; background: transparent; border: 0; color: var(--dim);
padding: 6px 8px; font: inherit; font-size: 12.5px; border-radius: 6px;
cursor: pointer; display: inline-flex; align-items: center; justify-content: center; gap: 5px; }
.modetoggle button.on { background: rgb(from var(--acid, #d6ff3d) r g b / .16); color: var(--acid, #d6ff3d); font-weight: 600; }
.modetoggle button:hover:not(.on) { color: var(--ink); }
.modetoggle .hint { color: currentColor; opacity: .65; font-size: 11px; }
/* Settings section chip nav (0.8.2). Segmented row that pages between
Security / Session / Wallet / Prices / Sites / About cards without
scrolling through the whole tab. */
.setsecnav { display: flex; flex-wrap: wrap; gap: 4px; border: 1px solid var(--line);
border-radius: 8px; padding: 3px; margin-bottom: 14px;
background: rgba(255,255,255,.03); }
.setsecnav button { flex: 1 0 auto; min-width: 62px; background: transparent; border: 0;
color: var(--dim); padding: 6px 10px; font: inherit; font-size: 12px;
border-radius: 6px; cursor: pointer; }
.setsecnav button.on { background: rgb(from var(--acid, #d6ff3d) r g b / .16);
color: var(--acid, #d6ff3d); font-weight: 600; }
.setsecnav button:hover:not(.on) { color: var(--ink); }
/* Segmented pill bar. The underline-tab treatment read as browser chrome,
and a 2px underline under a short label is nearly invisible once the
sidebar is narrow. A filled pill for the active section is what the
wallet apps use and it holds up at any width. The hover tint derives
from --ink so it also shows in the light theme, where a white overlay
would vanish. */
nav { display: flex; gap: 4px; padding: 6px 8px; border-bottom: 1px solid var(--line); background: var(--panel); }
nav button { flex: 1; padding: 7px 0; border: 0; border-radius: 999px; background: transparent;
color: var(--mut); cursor: pointer; font: inherit; font-size: 12.5px;
transition: background .12s, color .12s; }
nav button.on { background: var(--acid); color: #0b0f08; font-weight: 650; }
nav button:hover:not(.on) { background: rgb(from var(--ink) r g b / .08); color: var(--ink); }
main { flex: 1; overflow: auto; padding: 14px; }
/* Persistent aegis.x brand strip. Sticks to the panel's bottom edge so the
wallet always advertises its own front-door site — helps users bookmark
it, and doubles as a version marker for support triage. */
.brandfoot { flex: none; display: flex; align-items: center; justify-content: space-between;
padding: 6px 12px; border-top: 1px solid var(--line); background: var(--panel);
font-size: 11px; color: var(--dim); }
.brandlink { display: inline-flex; align-items: center; gap: 5px; color: var(--dim); text-decoration: none;
padding: 2px 4px; border-radius: 4px; }
.brandlink:hover { color: var(--acid, #d6ff3d); }
.brandlink svg { color: currentColor; }
.brandver { font-variant-numeric: tabular-nums; letter-spacing: .3px; }
.brandfoot-right { display: inline-flex; align-items: center; gap: 8px; }
.brandcheck { background: transparent; border: 0; color: var(--dim); cursor: pointer; padding: 0 2px;
font: inherit; font-size: 12px; line-height: 1; opacity: .7; transition: opacity .12s, color .12s; }
.brandcheck:hover { color: var(--acid, #d6ff3d); opacity: 1; }
.brandcheck.spin { animation: brandspin 1s linear infinite; }
@keyframes brandspin { to { transform: rotate(360deg); } }
.brandupd { display: inline-flex; align-items: center; gap: 5px; font-size: 11px; padding: 2px 8px;
border-radius: 999px; background: rgb(from var(--acid, #d6ff3d) r g b / .14); color: var(--acid, #d6ff3d);
cursor: pointer; text-decoration: none; font-weight: 600;
transition: opacity .2s; }
.brandupd[hidden] { display: none; }
.brandupd:hover { background: rgb(from var(--acid, #d6ff3d) r g b / .22); }
/* Transient states painted by paintFooterUpdate: "✓ Up to date" after a
manual check when no newer version is available, and "⚠ Check failed"
when the OTA fetch errors. Both auto-hide after ~2s; the styling reads
as ephemeral confirmation rather than a persistent chip. */
.brandupd.brandok { background: rgba(255,255,255,.06); color: var(--dim); font-weight: 500;
cursor: default; }
.brandupd.brandok:hover { background: rgba(255,255,255,.06); }
.brandupd.branderr { background: rgba(224,90,90,.18); color: #e05a5a; font-weight: 500;
cursor: default; }
.brandupd.branderr:hover { background: rgba(224,90,90,.18); }
/* In-progress state: painted while the panel is fetching / staging /
restarting. Not clickable, dimmer than the acid CTA chip so users
don't try to smash it. */
.brandupd.brandwait { background: rgba(255,255,255,.06); color: var(--mut);
font-weight: 500; cursor: default; }
.brandupd.brandwait:hover { background: rgba(255,255,255,.06); }
section[hidden] { display: none; }
.card { background: var(--card); border: 1px solid var(--line); border-radius: 10px; padding: 12px; }
.mono { font: 12.5px/1.45 ui-monospace, "Cascadia Code", Consolas, monospace; word-break: break-all; }
.lbl { color: var(--dim); font-size: 11.5px; margin-bottom: 4px; }
.btn { padding: 7px 12px; border-radius: 7px; border: 1px solid var(--line); background: var(--panel); color: var(--ink);
cursor: pointer; font: inherit; font-size: 12.5px; }
.btn:hover { border-color: rgb(from var(--acid) r g b / .4); }
.btn.primary { background: var(--acid); color: #0b0e14; border-color: transparent; font-weight: 650; }
.btn.primary:disabled { opacity: .45; cursor: default; }
.btn.danger { color: var(--danger); }
.btn.sm { padding: 4px 9px; font-size: 12px; }
.actions { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }
chore(aegis): 0.9.2 — Receive tab reorder, one balance, token history Receive was ordered QR → address → tokens, so 200px of always-on QR sat above the thing people came for and pushed the asset list off screen. - Address first, with Copy and a QR button; the QR expands inline and the choice sticks, because someone who receives by QR wants it every time and someone who copies never does. - Explorer and Faucet moved up to the header status row. They act on the selected wallet, not on the act of receiving, and down there they competed with Copy for the one row that gets used. - Assets card renamed from Tokens and now leads with the native coin, so "what does this wallet hold" is one list rather than two places. - "+ Add another <TICKER>" moved below the address list. The balance appeared three times — header, drilldown subtitle, address row. Now once in the header; the subtitle keeps only the per-unit price, and the per-address amount returns when a coin actually has more than one address to compare. The address row drops its truncated address (the full one is at the top of Receive) and keeps the wallet name. The per-address asset list added in 0.8.8 duplicated the Assets card and is removed — assets live in one place. Token amounts were unreadable: an 18-decimal balance rendered as 60000000.000000005435817984. Capped to 8 decimals with thousands separators, exact value on hover. A symbol claimed by more than one contract now carries a LOOK-ALIKE tag. The test wallet holds four different contracts all calling themselves "Test USDT" — spam mints borrowing a trusted ticker so a careless send lands on the wrong one. We can't tell which is genuine, so we mark every member of the clash rather than guessing. History showed native transfers only, so a wallet that had only ever moved USDT looked empty. TRC20 transfers are merged in newest-first, each carrying its own decimals and ticker (rendering a token against the chain's scale would be off by orders of magnitude). Both feeds are on by default; the checkboxes narrow rather than opt in, and the last one checked can't be unchecked into an empty list.
2026-09-23 01:17:33 +02:00
.qrwrap { display: grid; place-items: center; padding: 12px; background: #fff; border-radius: 10px; margin-top: 12px; }
.qrwrap[hidden] { display: none; }
fix(aegis): 0.9.8 — address row columns, resizable QR, inline copy The row's grid template still described the pre-0.9.2 layout — six columns including an address cell that no longer exists — while the row renders five. Every cell therefore sat one column left of where it belonged: copy landed in the label's space, the amount in the old label column, and the ⋯ in the amount column instead of the edge. That is the whole cause of "the copy button collides with the amount" and "the last edit button is not on the edge". Now five columns for five cells: icon · label · copy · amount · menu, 8px gaps. The label is the flexible one, left-aligned, so it takes the slack and truncates rather than squeezing the number. Verified at 520, 400 and 300px: no cell overlap at any width, no row overflow, and the amount never clips — only long labels give way. The copy glyph was the 📋 emoji, which has no glyph in this platform's font stack and rendered as a tofu box that read like a stray character stuck to the balance. Replaced with an inline SVG in both the row and the address card. Both confirmation flashes now swap innerHTML rather than textContent, which would have deleted the SVG and left a blank square. Address card: the address and its copy button share one row, so the button sits at the end of the value it copies. The address clamps to two lines and truncates beyond that instead of growing the card in a narrow sidebar. The QR is always visible and the panel is drag-resizable from a grip under it (pointer events, arrow keys as a non-mouse path, clamped 90–420px, capped against the panel's own width so a size set on a wide sidebar cannot overflow a narrow one, persisted). That replaces the 0.9.2 show/hide toggle — a size set once beats a binary, and it frees the row Copy was sharing with a QR button. drawQr was setting cv.style.width/height, which would have reset the panel to its intrinsic size on every redraw — i.e. every time the address changed. It now sets only the backing store and re-asserts the user's size after drawing. "Next unused address" is correct at the adapter level on both mainnet and chipnet (tested: the index advances and the address changes), so the reported failure is elsewhere. The handler was discarding the error and flashing a bare "Failed", which is why there was nothing to diagnose; it now surfaces the real message.
2026-09-24 22:30:10 +02:00
/* The canvas scales to whatever height the user dragged the panel to,
and never wider than the sidebar. aspect-ratio keeps it square. */
.qrwrap canvas { width: auto; height: auto; max-width: 100%;
aspect-ratio: 1 / 1; image-rendering: pixelated; }
/* Drag handle under the QR. A thin strip rather than a corner grip, so
it stays reachable at any sidebar width. */
.qrgrip { height: 14px; margin: 2px 0 -4px; display: grid; place-items: center;
cursor: ns-resize; touch-action: none; }
.qrgrip span { display: block; width: 34px; height: 3px; border-radius: 999px;
background: var(--line); transition: background .12s; }
.qrgrip:hover span, .qrgrip.dragging span { background: var(--acid, #d6ff3d); }
/* Address + inline copy. The value clamps to two lines; anything longer
is cut rather than growing the card. */
.addrrow { display: grid; grid-template-columns: minmax(0,1fr) 30px; gap: 6px;
align-items: start; }
.addrval { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
overflow: hidden; word-break: break-all; line-height: 1.35; }
.addrcopy { background: transparent; border: 1px solid var(--line); color: var(--dim);
cursor: pointer; width: 30px; height: 30px; border-radius: 7px;
display: inline-flex; align-items: center; justify-content: center;
line-height: 0; transition: color .12s, border-color .12s, background .12s; }
.addrcopy:hover { color: var(--acid, #d6ff3d); border-color: rgb(from var(--acid, #d6ff3d) r g b / .5); }
.addrcopy.copied { color: var(--acid, #d6ff3d); border-color: rgb(from var(--acid, #d6ff3d) r g b / .6); }
.addrcopy svg { width: 15px; height: 15px; display: block; }
/* Hide the action row entirely when its only child is hidden, so it
doesn't leave a gap under the address. */
#addrActions:not(:has(> :not([hidden]))) { display: none; }
canvas { image-rendering: pixelated; }
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
input[type=text], input[type=number], input[type=password], textarea { width: 100%; padding: 7px 9px; border-radius: 7px; background: var(--panel);
border: 1px solid var(--line); color: var(--ink); font: inherit; font-size: 13px; outline: none; }
input:focus, textarea:focus { border-color: rgb(from var(--acid) r g b / .5); }
textarea { resize: vertical; min-height: 96px; font: 12px/1.45 ui-monospace, Consolas, monospace; }
.field { margin-bottom: 12px; }
.hint { color: var(--dim); font-size: 11.5px; margin-top: 4px; }
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
.switch { display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none; font-size: 12.5px; color: var(--ink); }
.switch input { accent-color: var(--brand, #d6ff3d); width: 15px; height: 15px; margin: 0; }
.amt { display: flex; gap: 6px; }
.amt input { flex: 1; }
.unit { display: flex; border: 1px solid var(--line); border-radius: 7px; overflow: hidden; }
.unit button { border: 0; background: var(--panel); color: var(--mut); padding: 0 10px; cursor: pointer; font: inherit; font-size: 12px; }
.unit button.on { background: rgb(from var(--acid) r g b / .14); color: var(--acid); }
.fee { display: flex; align-items: center; gap: 10px; }
.fee input[type=range] { flex: 1; accent-color: var(--acid); }
.fee .v { color: var(--mut); font-size: 12px; min-width: 70px; text-align: right; font-variant-numeric: tabular-nums; }
.summary { display: grid; grid-template-columns: max-content 1fr; gap: 4px 12px; font-size: 12.5px; margin-top: 10px; }
.summary .k { color: var(--dim); } .summary .v { text-align: right; font-variant-numeric: tabular-nums; }
.msg { margin-top: 10px; font-size: 12.5px; padding: 8px 10px; border-radius: 7px; }
.msg.err { background: rgba(246,118,138,.12); color: var(--danger); }
.msg.ok { background: rgba(90,211,138,.12); color: var(--ok); }
.msg a { color: inherit; }
.tx { display: grid; grid-template-columns: 22px 1fr auto; gap: 2px 10px; padding: 9px 4px; border-bottom: 1px solid var(--line); cursor: pointer; }
.tx:hover { background: rgba(255,255,255,.03); }
.tx .ic { font-size: 15px; line-height: 1.3; }
.tx .ic.in { color: var(--ok); } .tx .ic.out { color: var(--danger); }
.tx .what { font-size: 12.5px; }
.tx .when { color: var(--dim); font-size: 11.5px; grid-column: 2; }
.tx .amt2 { text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; font-size: 12.5px; }
.tx .amt2.in { color: var(--ok); }
.tx .conf { grid-column: 3; text-align: right; color: var(--dim); font-size: 11px; }
.tx .conf.pending { color: #e0b341; }
.empty { color: var(--dim); text-align: center; padding: 30px 10px; font-size: 12.5px; }
.gate { padding: 40px 18px; text-align: center; color: var(--mut); }
.gate .big { font-size: 28px; margin-bottom: 8px; }
.gate b { color: var(--ink); }
.kv { margin-top: 10px; }
.kv .lbl { margin-top: 8px; }
a.link { color: var(--acid); text-decoration: none; cursor: pointer; }
/* Preset-server checkbox list — one row per known Electrum endpoint, plus
any URL the user added via the "Add a custom server" reveal. Rows show
the host + a small hover-to-remove for user-added entries. */
.serverlist { display: flex; flex-direction: column; gap: 3px; margin-top: 4px; }
.serverlist label { display: flex; align-items: center; gap: 8px; padding: 5px 6px;
border-radius: 6px; cursor: pointer; font-size: 12.5px; color: var(--mut); }
.serverlist label:hover { background: rgba(255,255,255,.04); color: var(--ink); }
.serverlist input[type=checkbox] { accent-color: var(--acid, #d6ff3d); width: 14px; height: 14px; margin: 0; }
.serverlist .surl { flex: 1; font: 11.5px/1.4 ui-monospace, Consolas, monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.serverlist .sremove { flex: none; background: transparent; border: 0; color: var(--dim); cursor: pointer; padding: 0 4px; opacity: 0; }
.serverlist label:hover .sremove { opacity: 1; }
.serverlist .sremove:hover { color: var(--danger, #f6768a); }
/* Always-visible wallet list — vertical column of rows so users can scan
names + balances without dragging chips sideways. Capped at ~40vh so a
giant list still leaves the main content readable; scrolls inside. */
.wstrip { flex: none; display: flex; flex-direction: column; gap: 1px; padding: 4px 6px 5px 6px;
max-height: 44vh; overflow-y: auto; scrollbar-width: thin;
background: var(--panel); border-bottom: 1px solid var(--line); }
.wstrip::-webkit-scrollbar { width: 4px; }
.wstrip::-webkit-scrollbar-thumb { background: var(--line); border-radius: 2px; }
.wstrip .wchip { display: flex; align-items: center; gap: 4px; padding: 4px 6px 4px 4px;
background: transparent; border: 1px solid transparent; border-radius: 7px;
font: inherit; font-size: 12.5px; color: var(--mut); min-width: 0; }
.wstrip .wchip:hover { background: rgba(255,255,255,.04); color: var(--ink); }
.wstrip .wchip.on { background: rgb(from var(--acid, #d6ff3d) r g b / .10);
border-color: rgb(from var(--acid, #d6ff3d) r g b / .35);
color: var(--ink); }
.wstrip .wchip .wclick { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0;
cursor: pointer; padding: 2px 4px; border-radius: 5px; }
.wstrip .wchip .wtext { flex: 1; min-width: 0; overflow: hidden; display: inline-flex;
align-items: center; gap: 6px; flex-wrap: nowrap; }
.wstrip .wchip .wname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wstrip .wchip .wsub { color: var(--dim); font-size: 10.5px; font-weight: 400; margin-left: 6px;
font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Price chip sitting right next to the wallet label. Acid tint with a
subtle glow lifts it off the grey row so users spot movement without
hunting; the small background gives it structural presence too. */
.wstrip .wchip .wprice { color: var(--acid, #d6ff3d); font-size: 11px; font-weight: 600;
font-variant-numeric: tabular-nums; white-space: nowrap;
padding: 1px 6px; border-radius: 999px;
background: rgb(from var(--acid, #d6ff3d) r g b / .10);
text-shadow: 0 0 6px rgb(from var(--acid, #d6ff3d) r g b / .35); }
.wstrip .wchip .wact { flex: none; background: transparent; border: 0; color: var(--dim);
cursor: pointer; padding: 3px 6px; border-radius: 5px; font-size: 12px; line-height: 1; }
.wstrip .wchip .wact:hover { color: var(--acid, #d6ff3d); background: rgba(255,255,255,.06); }
/* Four-column layout: [logo][ticker+price stack][amount+fiat stack][actions].
The old separate Price and Chain columns collapsed into the ticker cell —
per-unit price sits directly under the ticker so the eye can read
"BCH · $430" as one unit before jumping to the balance on the right.
A non-mainnet row also carries a small network pill inline with the
ticker (Chipnet / Sepolia / …); mainnet rows omit it entirely. */
.wstrip { padding: 4px 6px 6px 6px; }
.wstrip .wrow { display: grid; grid-template-columns: 18px minmax(72px,auto) minmax(0,1fr) auto auto;
gap: 8px; align-items: center; padding: 5px 4px;
border-radius: 6px; border: 1px solid transparent; cursor: pointer;
min-height: 30px; }
.wstrip .wrow:hover { background: rgba(255,255,255,.04); }
.wstrip .wrow.on { background: rgb(from var(--acid, #d6ff3d) r g b / .10);
border-color: rgb(from var(--acid, #d6ff3d) r g b / .35); }
.wstrip .wrow.dragging { opacity: .45; cursor: grabbing; }
.wstrip .wrow.drop-before { box-shadow: 0 -2px 0 0 var(--acid, #d6ff3d); }
.wstrip .wrow.drop-after { box-shadow: 0 2px 0 0 var(--acid, #d6ff3d); }
.wstrip .wgrip { display: inline-block; color: var(--dim); font-size: 10px; padding: 0 2px;
cursor: grab; user-select: none; opacity: 0; transition: opacity .12s; }
.wstrip .wrow:hover .wgrip { opacity: 1; }
.wstrip .wrow[draggable="true"] { cursor: grab; }
.wstrip .wcell { min-width: 0; display: inline-flex; align-items: center; gap: 3px; }
.wstrip .wclogo { justify-self: start; align-self: start; padding-top: 2px; }
/* Ticker cell: two-line stack. Line 1 has the ticker, an optional ▾
chevron (only when the chain has more than one network to switch
between), an optional Chipnet/Testnet pill, and the wallet count.
Line 2 is the per-unit price in acid-green. The cell as a whole is
the click target for the network dropdown. */
.wstrip .wcname { flex-direction: column; align-items: flex-start; line-height: 1.15; gap: 1px; }
.wstrip .wcname .wtline { display: inline-flex; align-items: center; gap: 5px; }
.wstrip .wcname .wtck { font-weight: 700; font-size: 13px; color: var(--ink); }
.wstrip .wcname .wchev { color: var(--dim); font-size: 9px; line-height: 1; padding: 0 1px;
transition: color .12s, transform .12s; }
.wstrip .wcname.wswitchable { cursor: pointer; }
.wstrip .wcname.wswitchable:hover .wchev { color: var(--acid, #d6ff3d); }
.wstrip .wcname .wnetpill { font-size: 10px; padding: 1px 6px; border-radius: 999px;
background: rgba(255,255,255,.06); color: var(--mut);
white-space: nowrap; line-height: 1.35; }
.wstrip .wcname .wnetpill.wchipnet { background: rgb(from var(--acid, #d6ff3d) r g b / .18);
color: var(--acid, #d6ff3d); font-weight: 600; }
.wstrip .wcname .wnetpill.wtestnet { background: rgba(224,179,65,.18); color: #e0b341; font-weight: 600; }
/* Multi-wallet count pill inside the ticker cell. When the group has
more than one wallet it doubles as the "swap active wallet" trigger
(▾ chevron), independent of the row's own click target which now
selects the current active wallet directly. */
.wstrip .wcname .wgcount.wgpick { cursor: pointer; }
.wstrip .wcname .wgcount.wgpick:hover { background: rgba(255,255,255,.12); color: var(--acid, #d6ff3d); }
.wstrip .wcname .wgcount .wgchev { color: var(--dim); font-size: 9px; margin-left: 1px; }
.wstrip .wcname .wgcount.wgpick:hover .wgchev { color: var(--acid, #d6ff3d); }
.wstrip .wcname .wgcount { color: var(--dim); font-size: 10.5px; padding: 0 6px; border-radius: 999px;
background: rgba(255,255,255,.06); font-variant-numeric: tabular-nums; line-height: 1.4; }
.wstrip .wcname .wcprice { color: var(--acid, #d6ff3d); font-size: 11px; font-weight: 600;
font-variant-numeric: tabular-nums; white-space: nowrap;
text-shadow: 0 0 5px rgb(from var(--acid, #d6ff3d) r g b / .30); }
.wstrip .wcamt { flex-direction: column; align-items: flex-end; text-align: right;
font-variant-numeric: tabular-nums; line-height: 1.2; }
.wstrip .wcamt .wnative { font-size: 12.5px; color: var(--ink); font-weight: 500; }
.wstrip .wcamt .wfiat { font-size: 11px; color: var(--dim); }
.wstrip .wcact { display: inline-flex; gap: 2px; }
.wstrip .wcact .wact { background: transparent; border: 0; color: var(--dim); cursor: pointer;
padding: 2px 5px; border-radius: 4px; font-size: 12.5px; line-height: 1; }
.wstrip .wcact .wact:hover { color: var(--acid, #d6ff3d); background: rgba(255,255,255,.06); }
/* Network dropdown menu — anchored below the ticker cell on click. Shows
every network under the chain (mainnet + testnets) with its own totals,
so switching networks feels like flipping a segment on the same coin
row rather than jumping to a separate wallet. */
.netmenu { position: absolute; z-index: 60; min-width: 180px; background: var(--panel, #1a1a1a);
border: 1px solid var(--line); border-radius: 8px; padding: 4px;
box-shadow: 0 6px 20px rgba(0,0,0,.35); }
.netmenu .nmitem { display: flex; align-items: center; justify-content: space-between;
gap: 10px; padding: 6px 8px; border-radius: 5px; cursor: pointer;
color: var(--ink); font-size: 12.5px; }
.netmenu .nmitem:hover { background: rgba(255,255,255,.06); }
.netmenu .nmitem.on { background: rgb(from var(--acid, #d6ff3d) r g b / .12);
color: var(--acid, #d6ff3d); }
.netmenu .nmitem .nmname { display: inline-flex; align-items: center; gap: 6px; }
.netmenu .nmitem .nmnet { font-weight: 600; }
.netmenu .nmitem .nmcount { color: var(--dim); font-size: 10.5px; padding: 0 5px; border-radius: 999px;
background: rgba(255,255,255,.06); }
.netmenu .nmitem .nmamt { font-variant-numeric: tabular-nums; font-size: 11.5px; color: var(--dim); }
.netmenu .nmitem.on .nmamt { color: var(--acid, #d6ff3d); }
/* Acid-green testnet tag for the Chipnet group. Overrides the warm-amber
default so chipnet reads as "the friendly BCH testnet" instead of
borrowing the caution palette. */
.ttag.acid { background: rgb(from var(--acid, #d6ff3d) r g b / .18); color: var(--acid, #d6ff3d); }
.wstrip .waddwrap { display: flex; gap: 5px; padding: 0 0 4px 0; margin-bottom: 4px; border-bottom: 1px solid var(--line); }
.wstrip .waddwrap button { flex: 1; background: transparent; border: 1px dashed var(--line); border-radius: 6px;
padding: 5px 8px; color: var(--dim); cursor: pointer; font: inherit; font-size: 12px; line-height: 1; }
.wstrip .waddwrap button:hover { color: var(--acid, #d6ff3d); border-color: var(--acid, #d6ff3d); }
/* Inline coin-address view — takes the place of the six-column grid when
a user opens a multi-wallet group. Back-arrow row + one row per wallet
under the coin. Same container so the visual context stays put. */
.wstrip .wcoinhead { display: flex; align-items: center; gap: 6px; padding: 3px 4px 4px 4px;
border-bottom: 1px solid var(--line); }
.wstrip .wcoinhead .wback { background: transparent; border: 0; color: var(--dim); cursor: pointer;
padding: 2px 4px; border-radius: 4px; font: inherit; font-size: 12px; line-height: 1; }
.wstrip .wcoinhead .wback:hover { color: var(--acid, #d6ff3d); background: rgba(255,255,255,.06); }
.wstrip .wcoinhead .wctitle { flex: 1; min-width: 0; display: inline-flex; align-items: center; gap: 6px;
font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wstrip .wcoinhead .wcount { color: var(--dim); font-size: 11.5px; font-weight: 500; }
/* Inline address-list row (per-coin drilldown). 0.6.35 layout: strictly
columnar so every row's fields line up in the same x positions no
matter how long each label happens to be. The address column is the
only flex one (minmax 0/1fr) — it fills whatever's left after the
fixed cells and truncates with an ellipsis, so a wider sidebar shows
more of the address without the label/balance jumping around. Every
other column has an explicit width — label pill is fixed to 68px so
"a" and "anthem…" occupy the same slot, amount is fixed to 90px so
"0" and "0.000123" right-align identically, actions are fixed to
46px. Net result: columns look like a table, not a flex mess. */
fix(aegis): 0.9.8 — address row columns, resizable QR, inline copy The row's grid template still described the pre-0.9.2 layout — six columns including an address cell that no longer exists — while the row renders five. Every cell therefore sat one column left of where it belonged: copy landed in the label's space, the amount in the old label column, and the ⋯ in the amount column instead of the edge. That is the whole cause of "the copy button collides with the amount" and "the last edit button is not on the edge". Now five columns for five cells: icon · label · copy · amount · menu, 8px gaps. The label is the flexible one, left-aligned, so it takes the slack and truncates rather than squeezing the number. Verified at 520, 400 and 300px: no cell overlap at any width, no row overflow, and the amount never clips — only long labels give way. The copy glyph was the 📋 emoji, which has no glyph in this platform's font stack and rendered as a tofu box that read like a stray character stuck to the balance. Replaced with an inline SVG in both the row and the address card. Both confirmation flashes now swap innerHTML rather than textContent, which would have deleted the SVG and left a blank square. Address card: the address and its copy button share one row, so the button sits at the end of the value it copies. The address clamps to two lines and truncates beyond that instead of growing the card in a narrow sidebar. The QR is always visible and the panel is drag-resizable from a grip under it (pointer events, arrow keys as a non-mouse path, clamped 90–420px, capped against the panel's own width so a size set on a wide sidebar cannot overflow a narrow one, persisted). That replaces the 0.9.2 show/hide toggle — a size set once beats a binary, and it frees the row Copy was sharing with a QR button. drawQr was setting cv.style.width/height, which would have reset the panel to its intrinsic size on every redraw — i.e. every time the address changed. It now sets only the backing store and re-asserts the user's size after drawing. "Next unused address" is correct at the adapter level on both mainnet and chipnet (tested: the index advances and the address changes), so the reported failure is elsewhere. The handler was discarding the error and flashing a bare "Failed", which is why there was nothing to diagnose; it now surfaces the real message.
2026-09-24 22:30:10 +02:00
/* 0.9.8: five columns for the five cells the row actually renders —
icon · label · copy · amount · menu. The template used to describe
the pre-0.9.2 layout (six columns, including an address cell that no
fix(aegis): 0.9.8 — address row columns, resizable QR, inline copy The row's grid template still described the pre-0.9.2 layout — six columns including an address cell that no longer exists — while the row renders five. Every cell therefore sat one column left of where it belonged: copy landed in the label's space, the amount in the old label column, and the ⋯ in the amount column instead of the edge. That is the whole cause of "the copy button collides with the amount" and "the last edit button is not on the edge". Now five columns for five cells: icon · label · copy · amount · menu, 8px gaps. The label is the flexible one, left-aligned, so it takes the slack and truncates rather than squeezing the number. Verified at 520, 400 and 300px: no cell overlap at any width, no row overflow, and the amount never clips — only long labels give way. The copy glyph was the 📋 emoji, which has no glyph in this platform's font stack and rendered as a tofu box that read like a stray character stuck to the balance. Replaced with an inline SVG in both the row and the address card. Both confirmation flashes now swap innerHTML rather than textContent, which would have deleted the SVG and left a blank square. Address card: the address and its copy button share one row, so the button sits at the end of the value it copies. The address clamps to two lines and truncates beyond that instead of growing the card in a narrow sidebar. The QR is always visible and the panel is drag-resizable from a grip under it (pointer events, arrow keys as a non-mouse path, clamped 90–420px, capped against the panel's own width so a size set on a wide sidebar cannot overflow a narrow one, persisted). That replaces the 0.9.2 show/hide toggle — a size set once beats a binary, and it frees the row Copy was sharing with a QR button. drawQr was setting cv.style.width/height, which would have reset the panel to its intrinsic size on every redraw — i.e. every time the address changed. It now sets only the backing store and re-asserts the user's size after drawing. "Next unused address" is correct at the adapter level on both mainnet and chipnet (tested: the index advances and the address changes), so the reported failure is elsewhere. The handler was discarding the error and flashing a bare "Failed", which is why there was nothing to diagnose; it now surfaces the real message.
2026-09-24 22:30:10 +02:00
longer exists), so every cell sat one column left of where it
belonged, which is what made copy and amount collide.
0.9.9: the columns are declared ONCE on the list and every row
inherits them via subgrid. Previously each row was its own grid, so
the `auto` amount column resolved per row — a row holding
0.3066756 got a narrower column than one holding 0.43789841, and the
copy button landed at a different x on every line. Column widths
must be shared to line up, and subgrid is what shares them. */
/* Column gap lives on the parent: a subgrid takes its gutters in the
subgridded axis from the grid it inherits, so setting it on the row
would be ignored. */
.wstrip .walist { display: grid;
grid-template-columns: 16px minmax(0,1fr) 24px auto 26px;
column-gap: 8px; row-gap: 2px; }
.wstrip .warow { display: grid;
grid-template-columns: subgrid; grid-column: 1 / -1;
align-items: center; padding: 5px 6px;
fix(aegis): 0.9.8 — address row columns, resizable QR, inline copy The row's grid template still described the pre-0.9.2 layout — six columns including an address cell that no longer exists — while the row renders five. Every cell therefore sat one column left of where it belonged: copy landed in the label's space, the amount in the old label column, and the ⋯ in the amount column instead of the edge. That is the whole cause of "the copy button collides with the amount" and "the last edit button is not on the edge". Now five columns for five cells: icon · label · copy · amount · menu, 8px gaps. The label is the flexible one, left-aligned, so it takes the slack and truncates rather than squeezing the number. Verified at 520, 400 and 300px: no cell overlap at any width, no row overflow, and the amount never clips — only long labels give way. The copy glyph was the 📋 emoji, which has no glyph in this platform's font stack and rendered as a tofu box that read like a stray character stuck to the balance. Replaced with an inline SVG in both the row and the address card. Both confirmation flashes now swap innerHTML rather than textContent, which would have deleted the SVG and left a blank square. Address card: the address and its copy button share one row, so the button sits at the end of the value it copies. The address clamps to two lines and truncates beyond that instead of growing the card in a narrow sidebar. The QR is always visible and the panel is drag-resizable from a grip under it (pointer events, arrow keys as a non-mouse path, clamped 90–420px, capped against the panel's own width so a size set on a wide sidebar cannot overflow a narrow one, persisted). That replaces the 0.9.2 show/hide toggle — a size set once beats a binary, and it frees the row Copy was sharing with a QR button. drawQr was setting cv.style.width/height, which would have reset the panel to its intrinsic size on every redraw — i.e. every time the address changed. It now sets only the backing store and re-asserts the user's size after drawing. "Next unused address" is correct at the adapter level on both mainnet and chipnet (tested: the index advances and the address changes), so the reported failure is elsewhere. The handler was discarding the error and flashing a bare "Failed", which is why there was nothing to diagnose; it now surfaces the real message.
2026-09-24 22:30:10 +02:00
border-radius: 6px; border: 1px solid transparent; cursor: pointer; min-height: 30px; }
/* Fallback for a host without subgrid: pin the amount column to a fixed
width so the copy column still lines up. Wide enough for eight
decimals of BCH plus its ticker. */
@supports not (grid-template-columns: subgrid) {
.wstrip .walist { display: block; }
.wstrip .warow { grid-template-columns: 16px minmax(0,1fr) 24px 104px 26px;
grid-column: auto; gap: 8px; }
}
.wstrip .warow:hover { background: rgba(255,255,255,.04); }
.wstrip .warow.on { background: rgb(from var(--acid, #d6ff3d) r g b / .10);
border-color: rgb(from var(--acid, #d6ff3d) r g b / .35); }
.wstrip .warow .waaddr { font: 12px/1.15 ui-monospace, Consolas, monospace; color: var(--ink);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
fix(aegis): 0.9.8 — address row columns, resizable QR, inline copy The row's grid template still described the pre-0.9.2 layout — six columns including an address cell that no longer exists — while the row renders five. Every cell therefore sat one column left of where it belonged: copy landed in the label's space, the amount in the old label column, and the ⋯ in the amount column instead of the edge. That is the whole cause of "the copy button collides with the amount" and "the last edit button is not on the edge". Now five columns for five cells: icon · label · copy · amount · menu, 8px gaps. The label is the flexible one, left-aligned, so it takes the slack and truncates rather than squeezing the number. Verified at 520, 400 and 300px: no cell overlap at any width, no row overflow, and the amount never clips — only long labels give way. The copy glyph was the 📋 emoji, which has no glyph in this platform's font stack and rendered as a tofu box that read like a stray character stuck to the balance. Replaced with an inline SVG in both the row and the address card. Both confirmation flashes now swap innerHTML rather than textContent, which would have deleted the SVG and left a blank square. Address card: the address and its copy button share one row, so the button sits at the end of the value it copies. The address clamps to two lines and truncates beyond that instead of growing the card in a narrow sidebar. The QR is always visible and the panel is drag-resizable from a grip under it (pointer events, arrow keys as a non-mouse path, clamped 90–420px, capped against the panel's own width so a size set on a wide sidebar cannot overflow a narrow one, persisted). That replaces the 0.9.2 show/hide toggle — a size set once beats a binary, and it frees the row Copy was sharing with a QR button. drawQr was setting cv.style.width/height, which would have reset the panel to its intrinsic size on every redraw — i.e. every time the address changed. It now sets only the backing store and re-asserts the user's size after drawing. "Next unused address" is correct at the adapter level on both mainnet and chipnet (tested: the index advances and the address changes), so the reported failure is elsewhere. The handler was discarding the error and flashing a bare "Failed", which is why there was nothing to diagnose; it now surfaces the real message.
2026-09-24 22:30:10 +02:00
/* Copy chip: its own 24px column between label and amount, so it can
never crowd the number. SVG rather than the 📋 emoji, which rendered
as a tofu box here and read as a glyph stuck to the balance. */
.wstrip .warow .wacopy { background: transparent; border: 0; color: var(--dim); cursor: pointer;
fix(aegis): 0.9.8 — address row columns, resizable QR, inline copy The row's grid template still described the pre-0.9.2 layout — six columns including an address cell that no longer exists — while the row renders five. Every cell therefore sat one column left of where it belonged: copy landed in the label's space, the amount in the old label column, and the ⋯ in the amount column instead of the edge. That is the whole cause of "the copy button collides with the amount" and "the last edit button is not on the edge". Now five columns for five cells: icon · label · copy · amount · menu, 8px gaps. The label is the flexible one, left-aligned, so it takes the slack and truncates rather than squeezing the number. Verified at 520, 400 and 300px: no cell overlap at any width, no row overflow, and the amount never clips — only long labels give way. The copy glyph was the 📋 emoji, which has no glyph in this platform's font stack and rendered as a tofu box that read like a stray character stuck to the balance. Replaced with an inline SVG in both the row and the address card. Both confirmation flashes now swap innerHTML rather than textContent, which would have deleted the SVG and left a blank square. Address card: the address and its copy button share one row, so the button sits at the end of the value it copies. The address clamps to two lines and truncates beyond that instead of growing the card in a narrow sidebar. The QR is always visible and the panel is drag-resizable from a grip under it (pointer events, arrow keys as a non-mouse path, clamped 90–420px, capped against the panel's own width so a size set on a wide sidebar cannot overflow a narrow one, persisted). That replaces the 0.9.2 show/hide toggle — a size set once beats a binary, and it frees the row Copy was sharing with a QR button. drawQr was setting cv.style.width/height, which would have reset the panel to its intrinsic size on every redraw — i.e. every time the address changed. It now sets only the backing store and re-asserts the user's size after drawing. "Next unused address" is correct at the adapter level on both mainnet and chipnet (tested: the index advances and the address changes), so the reported failure is elsewhere. The handler was discarding the error and flashing a bare "Failed", which is why there was nothing to diagnose; it now surfaces the real message.
2026-09-24 22:30:10 +02:00
padding: 0; border-radius: 5px; line-height: 0;
width: 24px; height: 22px; display: inline-flex;
align-items: center; justify-content: center;
transition: color .12s, background .12s; justify-self: center; }
.wstrip .warow .wacopy svg { width: 13px; height: 13px; display: block; }
.wstrip .warow .wacopy:hover { color: var(--acid, #d6ff3d); background: rgba(255,255,255,.06); }
.wstrip .warow .wacopy.copied { color: var(--acid, #d6ff3d); }
fix(aegis): 0.9.8 — address row columns, resizable QR, inline copy The row's grid template still described the pre-0.9.2 layout — six columns including an address cell that no longer exists — while the row renders five. Every cell therefore sat one column left of where it belonged: copy landed in the label's space, the amount in the old label column, and the ⋯ in the amount column instead of the edge. That is the whole cause of "the copy button collides with the amount" and "the last edit button is not on the edge". Now five columns for five cells: icon · label · copy · amount · menu, 8px gaps. The label is the flexible one, left-aligned, so it takes the slack and truncates rather than squeezing the number. Verified at 520, 400 and 300px: no cell overlap at any width, no row overflow, and the amount never clips — only long labels give way. The copy glyph was the 📋 emoji, which has no glyph in this platform's font stack and rendered as a tofu box that read like a stray character stuck to the balance. Replaced with an inline SVG in both the row and the address card. Both confirmation flashes now swap innerHTML rather than textContent, which would have deleted the SVG and left a blank square. Address card: the address and its copy button share one row, so the button sits at the end of the value it copies. The address clamps to two lines and truncates beyond that instead of growing the card in a narrow sidebar. The QR is always visible and the panel is drag-resizable from a grip under it (pointer events, arrow keys as a non-mouse path, clamped 90–420px, capped against the panel's own width so a size set on a wide sidebar cannot overflow a narrow one, persisted). That replaces the 0.9.2 show/hide toggle — a size set once beats a binary, and it frees the row Copy was sharing with a QR button. drawQr was setting cv.style.width/height, which would have reset the panel to its intrinsic size on every redraw — i.e. every time the address changed. It now sets only the backing store and re-asserts the user's size after drawing. "Next unused address" is correct at the adapter level on both mainnet and chipnet (tested: the index advances and the address changes), so the reported failure is elsewhere. The handler was discarding the error and flashing a bare "Failed", which is why there was nothing to diagnose; it now surfaces the real message.
2026-09-24 22:30:10 +02:00
/* Label pill, left-aligned in the flexible column so a name reads as
the row's identity rather than floating mid-row. Truncates with an
ellipsis instead of pushing the number around. */
.wstrip .warow .walabel { font-size: 11.5px; color: var(--ink);
padding: 2px 8px; border-radius: 999px;
background: rgba(255,255,255,.07);
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
max-width: 100%; box-sizing: border-box;
fix(aegis): 0.9.8 — address row columns, resizable QR, inline copy The row's grid template still described the pre-0.9.2 layout — six columns including an address cell that no longer exists — while the row renders five. Every cell therefore sat one column left of where it belonged: copy landed in the label's space, the amount in the old label column, and the ⋯ in the amount column instead of the edge. That is the whole cause of "the copy button collides with the amount" and "the last edit button is not on the edge". Now five columns for five cells: icon · label · copy · amount · menu, 8px gaps. The label is the flexible one, left-aligned, so it takes the slack and truncates rather than squeezing the number. Verified at 520, 400 and 300px: no cell overlap at any width, no row overflow, and the amount never clips — only long labels give way. The copy glyph was the 📋 emoji, which has no glyph in this platform's font stack and rendered as a tofu box that read like a stray character stuck to the balance. Replaced with an inline SVG in both the row and the address card. Both confirmation flashes now swap innerHTML rather than textContent, which would have deleted the SVG and left a blank square. Address card: the address and its copy button share one row, so the button sits at the end of the value it copies. The address clamps to two lines and truncates beyond that instead of growing the card in a narrow sidebar. The QR is always visible and the panel is drag-resizable from a grip under it (pointer events, arrow keys as a non-mouse path, clamped 90–420px, capped against the panel's own width so a size set on a wide sidebar cannot overflow a narrow one, persisted). That replaces the 0.9.2 show/hide toggle — a size set once beats a binary, and it frees the row Copy was sharing with a QR button. drawQr was setting cv.style.width/height, which would have reset the panel to its intrinsic size on every redraw — i.e. every time the address changed. It now sets only the backing store and re-asserts the user's size after drawing. "Next unused address" is correct at the adapter level on both mainnet and chipnet (tested: the index advances and the address changes), so the reported failure is elsewhere. The handler was discarding the error and flashing a bare "Failed", which is why there was nothing to diagnose; it now surfaces the real message.
2026-09-24 22:30:10 +02:00
justify-self: start; }
.wstrip .warow .walabel:empty { visibility: hidden; }
/* Balance shares a single line with everything else — no vertical
amount/fiat stack. Ticker follows the number in a dim tone so the
row reads "0 BCH" at a glance. Right-aligned within the fixed
amount column so short and long numbers line up. */
.wstrip .warow .waamt { text-align: right; font-variant-numeric: tabular-nums;
font-size: 12.5px; color: var(--ink); white-space: nowrap;
display: inline-flex; align-items: baseline; gap: 4px;
justify-self: end; overflow: hidden; }
.wstrip .warow .waamt .watkr { color: var(--dim); font-size: 11px; font-weight: 500; }
.wstrip .warow .wact { background: transparent; border: 0; color: var(--dim); cursor: pointer;
fix(aegis): 0.9.8 — address row columns, resizable QR, inline copy The row's grid template still described the pre-0.9.2 layout — six columns including an address cell that no longer exists — while the row renders five. Every cell therefore sat one column left of where it belonged: copy landed in the label's space, the amount in the old label column, and the ⋯ in the amount column instead of the edge. That is the whole cause of "the copy button collides with the amount" and "the last edit button is not on the edge". Now five columns for five cells: icon · label · copy · amount · menu, 8px gaps. The label is the flexible one, left-aligned, so it takes the slack and truncates rather than squeezing the number. Verified at 520, 400 and 300px: no cell overlap at any width, no row overflow, and the amount never clips — only long labels give way. The copy glyph was the 📋 emoji, which has no glyph in this platform's font stack and rendered as a tofu box that read like a stray character stuck to the balance. Replaced with an inline SVG in both the row and the address card. Both confirmation flashes now swap innerHTML rather than textContent, which would have deleted the SVG and left a blank square. Address card: the address and its copy button share one row, so the button sits at the end of the value it copies. The address clamps to two lines and truncates beyond that instead of growing the card in a narrow sidebar. The QR is always visible and the panel is drag-resizable from a grip under it (pointer events, arrow keys as a non-mouse path, clamped 90–420px, capped against the panel's own width so a size set on a wide sidebar cannot overflow a narrow one, persisted). That replaces the 0.9.2 show/hide toggle — a size set once beats a binary, and it frees the row Copy was sharing with a QR button. drawQr was setting cv.style.width/height, which would have reset the panel to its intrinsic size on every redraw — i.e. every time the address changed. It now sets only the backing store and re-asserts the user's size after drawing. "Next unused address" is correct at the adapter level on both mainnet and chipnet (tested: the index advances and the address changes), so the reported failure is elsewhere. The handler was discarding the error and flashing a bare "Failed", which is why there was nothing to diagnose; it now surfaces the real message.
2026-09-24 22:30:10 +02:00
padding: 2px 4px; border-radius: 4px; font-size: 13px; line-height: 1;
justify-self: end; }
.wstrip .warow .wact:hover { color: var(--acid, #d6ff3d); background: rgba(255,255,255,.06); }
chore(aegis): 0.8.8 — coin drilldown, per-address assets, WizardConnect from the page Wallet strip: - Clicking a coin opens that coin's page (addresses, price, totals, back and close) instead of only flipping the selection and leaving the list sitting there. The page already existed but was reachable only via the small count chip. - The per-coin second action was a gear that selected the wallet and opened the global Settings tab — the same destination for every coin, so it read as a per-coin control that wasn't one. It is now Remove, behind a confirm, with the default/legacy wallet showing a lock instead since it gates legacy funds. - Each address in the drilldown can expand to show what THAT address holds: TRC20/SPL via the adapter's tokens, BCH CashTokens via tokenBalances. walletSummary now carries both per wallet, so the view no longer has to borrow the selected wallet's assets. WizardConnect — the Connect pane was effectively unusable: - The locked-vault branch told the user to unlock and gave them nothing to click. It is reachable without the lock screen ever appearing, because a mounted imported wallet makes overallPhase read "ready". It now carries the same unlock form the lock screen uses. - Imported BCH wallets were never registered with the WC manager — startForWallet ran only in the vault-derived mount branch. They mount as ready, so they appeared in the "Sign with" picker and then failed on pair. They now register from their stored seed. WC derives a child key tree, so single-key (WIF) imports genuinely cannot pair; those are disabled in the picker with the reason, rather than failing on click. - Adds window.wizardconnect so a dapp can hand over the wiz:// URI it already generated instead of making the user copy it between tabs. The protocol is Nostr-relay pairing designed for phone-scans-QR, and the SDK has no in-page discovery at all, so this is our own surface: connect() + isReady(), plus a wizardconnect:announceProvider event shaped like EIP-6963 so several WC wallets can coexist. Pairing always goes through the approval modal; the URI is validated before any UI shows, and the wallet never reads the page to find one.
2026-09-22 23:08:16 +02:00
/* Per-address asset list (0.8.8). The count chip expands the row into a
nested list of what that ONE address holds beyond the native coin. */
.wstrip .waassets { background: rgba(255,255,255,.06); border: 0; color: var(--dim); cursor: pointer;
font: inherit; font-size: 10px; padding: 1px 6px; border-radius: 999px; line-height: 1.5; }
.wstrip .waassets:hover, .wstrip .waassets.on { color: var(--acid, #d6ff3d); background: rgb(from var(--acid, #d6ff3d) r g b / .14); }
.wstrip .waassetlist { padding: 2px 6px 6px 26px; display: flex; flex-direction: column; gap: 2px; }
.wstrip .waasset { display: grid; grid-template-columns: minmax(0,1fr) auto auto; gap: 8px; align-items: baseline;
font-size: 11px; color: var(--mut); padding: 2px 4px; border-radius: 4px; }
.wstrip .waasset:hover { background: rgba(255,255,255,.04); }
.wstrip .waasset .waaname { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wstrip .waasset .waaid { color: var(--dim); font-size: 10px; }
.wstrip .waasset .waaamt { font-variant-numeric: tabular-nums; color: var(--ink); }
/* Coin drilldown header: shows the coin's per-unit price + running
total of the addresses below, so the aggregate context isn't lost
when the user is deep in the per-address view. */
.wstrip .wcoinsub { display: flex; align-items: baseline; gap: 8px; padding: 2px 4px 5px 4px;
font-size: 11.5px; color: var(--mut); border-bottom: 1px solid var(--line);
margin-bottom: 3px; }
.wstrip .wcoinsub .wprice { color: var(--acid, #d6ff3d); font-weight: 600; font-variant-numeric: tabular-nums;
text-shadow: 0 0 5px rgb(from var(--acid, #d6ff3d) r g b / .30); }
.wstrip .wcoinsub .wsep { color: var(--dim); }
.wstrip .wcoinsub .wtot { color: var(--ink); font-variant-numeric: tabular-nums; font-weight: 500; }
.wstrip .wcoinsub .wtotfiat { color: var(--dim); font-variant-numeric: tabular-nums; }
/* Adapter-error line above the address rows. Shown only when at least
one wallet has a non-null .error — makes silent RPC failures visible
instead of the display quietly rendering 0. */
.wstrip .wcoinerr { color: #e05a5a; font-size: 11px; padding: 4px 6px;
background: rgba(224,90,90,.08); border-radius: 4px;
margin-bottom: 4px; overflow-wrap: anywhere; }
/* Full-panel lock screen — takes over the entire panel below the aegis
footer when the vault is locked or awaiting first-time setup. Rest of
the app (header picker, tabs, wallet strip) is hidden until unlocked
so nothing sensitive shows and there is no accidental interaction
surface. */
#lockScreen[hidden] { display: none; }
#lockScreen { position: absolute; inset: 0 0 30px 0; z-index: 50; background: var(--bg);
display: flex; flex-direction: column; align-items: center; justify-content: center;
padding: 24px 18px; color: var(--ink); text-align: center; }
#lockScreen .aegisMark { width: 64px; height: 64px; margin-bottom: 14px; }
#lockScreen .aegisMark svg { width: 100%; height: 100%; color: var(--acid, #d6ff3d);
filter: drop-shadow(0 0 12px rgb(from var(--acid, #d6ff3d) r g b / .35)); }
#lockScreen h1 { font: 600 16px/1.3 inherit; margin: 0 0 4px 0; letter-spacing: .2px; }
#lockScreen .subhint { color: var(--mut); font-size: 12px; max-width: 320px; margin: 0 0 20px 0; }
chore(aegis): 0.8.9 — ETH/SOL imported history + tokens, centred setup screen Completes the parity work 0.8.7 started for Tron. Imported ETH and SOL wallets showed a native balance and nothing else, because the JSON-RPC endpoints they poll have no history or token concept at all. - ETH history + ERC-20 balances via Blockscout, which needs no API key (Etherscan V2 does). Mainnet RPC moves off eth.llamarpc.com, which was answering 525 with an HTML error page — that parsed as a JSON error and showed as a 0 balance. - SOL history via getSignaturesForAddress and SPL balances via getTokenAccountsByOwner, both keyless on the public RPC. Three things the live testing turned up: - A Blockscout mempool entry is {result:"pending", status:null}. Reading that as "not ok, therefore failed" showed pending sends as failures. Now carries a distinct pending state through to the row. - History `delta` is now a number, a decimal string, or null. ETH wei needs the string (18 decimals overflows a JS number, and Math.abs was silently rounding it); Solana's signature feed carries no amount at all, and null >= 0 is true, so unknown amounts were rendering as a "+" that claimed a receive we cannot verify. Unknown now renders as a neutral row instead. - A real address came back with 855 ERC-20s and 3078 SPL mints, nearly all airdrop spam, some with blank, zero-width or bidi-override symbols that render as an empty row borrowing trust from its neighbours. Token text is sanitised and lists are capped at 50, sorted so named tokens survive the cap. Also: the first-run setup screen forced text-align:left on the form, so its helper copy ran ragged under a centred mark, title and description. The form now inherits the centred alignment; the mnemonic box stays left-aligned on purpose, since centring wrapped seed words makes them harder to check.
2026-09-23 00:05:14 +02:00
/* The form inherits the lock screen's centred alignment — it used to
force text-align:left, which left the setup screen's helper copy
running ragged against a centred title, mark and description. */
#lockScreen .lockform { width: min(320px, 100%); display: flex; flex-direction: column; gap: 10px; text-align: center; }
#lockScreen .lockform input[type=password],
chore(aegis): 0.8.9 — ETH/SOL imported history + tokens, centred setup screen Completes the parity work 0.8.7 started for Tron. Imported ETH and SOL wallets showed a native balance and nothing else, because the JSON-RPC endpoints they poll have no history or token concept at all. - ETH history + ERC-20 balances via Blockscout, which needs no API key (Etherscan V2 does). Mainnet RPC moves off eth.llamarpc.com, which was answering 525 with an HTML error page — that parsed as a JSON error and showed as a 0 balance. - SOL history via getSignaturesForAddress and SPL balances via getTokenAccountsByOwner, both keyless on the public RPC. Three things the live testing turned up: - A Blockscout mempool entry is {result:"pending", status:null}. Reading that as "not ok, therefore failed" showed pending sends as failures. Now carries a distinct pending state through to the row. - History `delta` is now a number, a decimal string, or null. ETH wei needs the string (18 decimals overflows a JS number, and Math.abs was silently rounding it); Solana's signature feed carries no amount at all, and null >= 0 is true, so unknown amounts were rendering as a "+" that claimed a receive we cannot verify. Unknown now renders as a neutral row instead. - A real address came back with 855 ERC-20s and 3078 SPL mints, nearly all airdrop spam, some with blank, zero-width or bidi-override symbols that render as an empty row borrowing trust from its neighbours. Token text is sanitised and lists are capped at 50, sorted so named tokens survive the cap. Also: the first-run setup screen forced text-align:left on the form, so its helper copy ran ragged under a centred mark, title and description. The form now inherits the centred alignment; the mnemonic box stays left-aligned on purpose, since centring wrapped seed words makes them harder to check.
2026-09-23 00:05:14 +02:00
#lockScreen .lockform input[type=text] { text-align: center; }
/* The mnemonic stays left-aligned on purpose: 12/24 words wrap across
several lines, and centring makes them ragged on both edges, which is
exactly the wrong thing when someone is checking a seed word by word. */
#lockScreen .lockform textarea { text-align: left; }
#lockScreen .lockform .hint { text-align: center; }
#lockScreen .altline { color: var(--dim); font-size: 11.5px; margin-top: 12px; text-align: center; }
#lockScreen .altline a { color: var(--acid, #d6ff3d); cursor: pointer; text-decoration: none; }
#lockScreen .altline a:hover { text-decoration: underline; }
/* PIN pad — six dots + a 3x4 keypad. Used both in lock screen and in the
PIN approval modal. */
.pinpad { display: flex; flex-direction: column; align-items: center; gap: 14px; }
.pinpad .pindots { display: flex; gap: 12px; }
.pinpad .pindot { width: 12px; height: 12px; border-radius: 50%; border: 1.5px solid var(--dim);
background: transparent; transition: background .12s, border-color .12s; }
.pinpad .pindot.on { background: var(--acid, #d6ff3d); border-color: var(--acid, #d6ff3d);
box-shadow: 0 0 6px rgb(from var(--acid, #d6ff3d) r g b / .5); }
.pinpad .pinkeys { display: grid; grid-template-columns: repeat(3, 62px); gap: 8px; }
.pinpad .pinkeys button { height: 46px; border-radius: 10px; border: 1px solid var(--line);
background: var(--card); color: var(--ink); font: 500 18px inherit;
cursor: pointer; }
.pinpad .pinkeys button:hover { border-color: var(--acid, #d6ff3d); color: var(--acid, #d6ff3d); }
.pinpad .pinkeys button.util { background: transparent; font-size: 13px; color: var(--dim); }
.pinpad .pinerr { color: var(--danger); font-size: 12px; text-align: center; min-height: 16px; }
/* PIN modal overlay — used for set-PIN / change-PIN / verify-PIN flows. */
.pinmodal { position: fixed; inset: 0; background: rgba(0,0,0,.55); display: flex;
align-items: center; justify-content: center; z-index: 9999; padding: 20px; }
.pinmodal .pincard { width: min(94vw, 340px); background: var(--panel); border: 1px solid var(--line);
border-radius: 12px; padding: 18px 16px 14px; box-shadow: 0 10px 40px rgba(0,0,0,.4); }
.pinmodal h2 { margin: 0 0 6px 0; font: 600 15px inherit; }
.pinmodal .pinsub { color: var(--mut); font-size: 12px; margin-bottom: 12px; text-align: center; }
.pinmodal .pinactions { display: flex; gap: 6px; justify-content: center; margin-top: 12px; }
/* General settings cards — pinned at top of Settings tab so cross-cutting
security/policy controls stay in one place, ahead of the per-wallet
stuff below. */
.gsec { margin-bottom: 14px; }
.gsec .gtitle { font: 600 13px inherit; color: var(--ink); margin-bottom: 6px; }
.gsec .gline { display: flex; align-items: center; justify-content: space-between; gap: 10px;
padding: 6px 0; border-top: 1px solid var(--line); }
.gsec .gline:first-of-type { border-top: 0; }
.gsec .gline .glabel { min-width: 0; font-size: 12.5px; color: var(--ink); }
.gsec .gline .ghint { display: block; color: var(--dim); font-size: 11px; margin-top: 2px; }
.gsec .gline .gactions { flex: none; display: inline-flex; gap: 6px; }
.gsec .gsoon { font-size: 10px; padding: 1px 6px; border-radius: 999px; letter-spacing: .04em;
background: rgba(224,179,65,.14); color: #e0b341; text-transform: uppercase; }
</style>
</head>
<body>
<header>
<div class="picker" id="pickerBtn">
<div class="t">
<span class="badge" id="hBadge"></span>
<span class="lbl" id="hLabel">Aegis Wallet</span>
<!-- Edit chip sits inline with the wallet name so it reads as
"edit THIS wallet". Was in picker-actions on the far right
until 0.7.2, which mixed poorly with the global + button. -->
<button type="button" id="hManage" class="editchip" title="Edit this wallet — rename, derivation path, remove">✎</button>
</div>
<div class="picker-actions">
<!-- Single right-corner chip. Opens a compact popover menu with
Create new / Import / Connect / About — replacing the old
three-chip cluster (+ ⋯ ✎). Method chosen there routes into
the coin picker inside #drop or an appropriate modal. -->
<button type="button" id="hAdd" class="chip" title="Add or import a wallet">+</button>
</div>
</div>
<!-- 0.8.4: network picker is its own row below the coin label so it
reads as "the network I'm on right now" instead of a tiny suffix
next to the wallet name. Click cycles / opens the network menu. -->
<div class="netrow" id="hNetRow" hidden>
<button type="button" class="netchip" id="hNet" title="Switch network"></button>
</div>
<div id="drop" hidden></div>
<div class="bal">
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
<div class="big">
<span id="balMain">—</span><small id="balTicker">—</small>
<span id="balFiat" class="fiat" hidden></span>
</div>
<div class="sub">
<span class="netlbl" id="netlbl">connecting…</span>
<span class="net"><span class="dot" id="dot"></span></span>
chore(aegis): 0.9.2 — Receive tab reorder, one balance, token history Receive was ordered QR → address → tokens, so 200px of always-on QR sat above the thing people came for and pushed the asset list off screen. - Address first, with Copy and a QR button; the QR expands inline and the choice sticks, because someone who receives by QR wants it every time and someone who copies never does. - Explorer and Faucet moved up to the header status row. They act on the selected wallet, not on the act of receiving, and down there they competed with Copy for the one row that gets used. - Assets card renamed from Tokens and now leads with the native coin, so "what does this wallet hold" is one list rather than two places. - "+ Add another <TICKER>" moved below the address list. The balance appeared three times — header, drilldown subtitle, address row. Now once in the header; the subtitle keeps only the per-unit price, and the per-address amount returns when a coin actually has more than one address to compare. The address row drops its truncated address (the full one is at the top of Receive) and keeps the wallet name. The per-address asset list added in 0.8.8 duplicated the Assets card and is removed — assets live in one place. Token amounts were unreadable: an 18-decimal balance rendered as 60000000.000000005435817984. Capped to 8 decimals with thousands separators, exact value on hover. A symbol claimed by more than one contract now carries a LOOK-ALIKE tag. The test wallet holds four different contracts all calling themselves "Test USDT" — spam mints borrowing a trusted ticker so a careless send lands on the wrong one. We can't tell which is genuine, so we mark every member of the clash rather than guessing. History showed native transfers only, so a wallet that had only ever moved USDT looked empty. TRC20 transfers are merged in newest-first, each carrying its own decimals and ticker (rendering a token against the chain's scale would be off by orders of magnitude). Both feeds are on by default; the checkboxes narrow rather than opt in, and the last one checked can't be unchecked into an empty list.
2026-09-23 01:17:33 +02:00
<!-- 0.9.2: Explorer / Faucet moved up out of the Receive address
card. They act on the selected wallet, not on the act of
receiving, and down there they competed with Copy + QR for
the one row people actually use. -->
<span class="hdracts">
<button class="hdract" id="viewAddr" type="button" title="Open this address in a block explorer">Explorer</button>
<button class="hdract" id="openFaucet" type="button" title="Open this testnet's faucet" hidden>Faucet</button>
</span>
</div>
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
<div id="portfolio" class="portfolio" hidden></div>
</div>
</header>
<nav>
<button data-tab="receive" class="on">Receive</button>
<button data-tab="send">Send</button>
<button data-tab="history">History</button>
<button data-tab="settings">Settings</button>
</nav>
<!-- Always-visible wallet list. Sits under the Receive/Send/History/Settings
tab bar so the top of the panel stays about the SELECTED wallet, and
the list of siblings/switch-targets reads as a secondary layer below.
[+ Add] opens the Add-only picker; [⋯ More] opens Import/Connect/Manage. -->
<div id="walletStrip" class="wstrip" aria-label="Your wallets"></div>
<main>
<div id="gate" class="gate" hidden></div>
<div id="tabs">
<section id="tab-receive">
<!-- Segmented mode toggle (0.8.0). Switches the tab body between
the normal Receive view (QR + address) and the Consolidate
view (inline picker for sweeping other-wallet balances into
this one). Hidden when there is nothing to consolidate. -->
<div id="rcvModeToggle" class="modetoggle" hidden>
<button data-rcv-mode="receive" class="on" type="button">Receive</button>
<button data-rcv-mode="consolidate" type="button">Consolidate <span id="rcvConsolidateCount" class="hint"></span></button>
</div>
<div id="rcvNormal">
chore(aegis): 0.9.2 — Receive tab reorder, one balance, token history Receive was ordered QR → address → tokens, so 200px of always-on QR sat above the thing people came for and pushed the asset list off screen. - Address first, with Copy and a QR button; the QR expands inline and the choice sticks, because someone who receives by QR wants it every time and someone who copies never does. - Explorer and Faucet moved up to the header status row. They act on the selected wallet, not on the act of receiving, and down there they competed with Copy for the one row that gets used. - Assets card renamed from Tokens and now leads with the native coin, so "what does this wallet hold" is one list rather than two places. - "+ Add another <TICKER>" moved below the address list. The balance appeared three times — header, drilldown subtitle, address row. Now once in the header; the subtitle keeps only the per-unit price, and the per-address amount returns when a coin actually has more than one address to compare. The address row drops its truncated address (the full one is at the top of Receive) and keeps the wallet name. The per-address asset list added in 0.8.8 duplicated the Assets card and is removed — assets live in one place. Token amounts were unreadable: an 18-decimal balance rendered as 60000000.000000005435817984. Capped to 8 decimals with thousands separators, exact value on hover. A symbol claimed by more than one contract now carries a LOOK-ALIKE tag. The test wallet holds four different contracts all calling themselves "Test USDT" — spam mints borrowing a trusted ticker so a careless send lands on the wrong one. We can't tell which is genuine, so we mark every member of the clash rather than guessing. History showed native transfers only, so a wallet that had only ever moved USDT looked empty. TRC20 transfers are merged in newest-first, each carrying its own decimals and ticker (rendering a token against the chain's scale would be off by orders of magnitude). Both feeds are on by default; the checkboxes narrow rather than opt in, and the last one checked can't be unchecked into an empty list.
2026-09-23 01:17:33 +02:00
<!-- 0.9.2: address first, assets next, QR last and collapsed.
The QR was 200px of always-on vertical space above the thing
people actually came for, and it pushed the token list below
the fold. Explorer / Faucet moved to the header. -->
<div class="card">
<div class="lbl">Receiving address <span id="addrMeta"></span></div>
fix(aegis): 0.9.8 — address row columns, resizable QR, inline copy The row's grid template still described the pre-0.9.2 layout — six columns including an address cell that no longer exists — while the row renders five. Every cell therefore sat one column left of where it belonged: copy landed in the label's space, the amount in the old label column, and the ⋯ in the amount column instead of the edge. That is the whole cause of "the copy button collides with the amount" and "the last edit button is not on the edge". Now five columns for five cells: icon · label · copy · amount · menu, 8px gaps. The label is the flexible one, left-aligned, so it takes the slack and truncates rather than squeezing the number. Verified at 520, 400 and 300px: no cell overlap at any width, no row overflow, and the amount never clips — only long labels give way. The copy glyph was the 📋 emoji, which has no glyph in this platform's font stack and rendered as a tofu box that read like a stray character stuck to the balance. Replaced with an inline SVG in both the row and the address card. Both confirmation flashes now swap innerHTML rather than textContent, which would have deleted the SVG and left a blank square. Address card: the address and its copy button share one row, so the button sits at the end of the value it copies. The address clamps to two lines and truncates beyond that instead of growing the card in a narrow sidebar. The QR is always visible and the panel is drag-resizable from a grip under it (pointer events, arrow keys as a non-mouse path, clamped 90–420px, capped against the panel's own width so a size set on a wide sidebar cannot overflow a narrow one, persisted). That replaces the 0.9.2 show/hide toggle — a size set once beats a binary, and it frees the row Copy was sharing with a QR button. drawQr was setting cv.style.width/height, which would have reset the panel to its intrinsic size on every redraw — i.e. every time the address changed. It now sets only the backing store and re-asserts the user's size after drawing. "Next unused address" is correct at the adapter level on both mainnet and chipnet (tested: the index advances and the address changes), so the reported failure is elsewhere. The handler was discarding the error and flashing a bare "Failed", which is why there was nothing to diagnose; it now surfaces the real message.
2026-09-24 22:30:10 +02:00
<!-- 0.9.8: address and its copy button share one row, so the
button sits at the end of the value it copies instead of on a
separate action line. The address clamps to two lines and
truncates beyond that, rather than growing the card in a
narrow sidebar. -->
<div class="addrrow">
<div class="mono addrval" id="addr">—</div>
<button class="addrcopy" id="copyAddr" title="Copy this address"></button>
</div>
<div class="actions" id="addrActions">
<button class="btn sm" id="nextAddr" hidden>Next unused address</button>
</div>
fix(aegis): 0.9.8 — address row columns, resizable QR, inline copy The row's grid template still described the pre-0.9.2 layout — six columns including an address cell that no longer exists — while the row renders five. Every cell therefore sat one column left of where it belonged: copy landed in the label's space, the amount in the old label column, and the ⋯ in the amount column instead of the edge. That is the whole cause of "the copy button collides with the amount" and "the last edit button is not on the edge". Now five columns for five cells: icon · label · copy · amount · menu, 8px gaps. The label is the flexible one, left-aligned, so it takes the slack and truncates rather than squeezing the number. Verified at 520, 400 and 300px: no cell overlap at any width, no row overflow, and the amount never clips — only long labels give way. The copy glyph was the 📋 emoji, which has no glyph in this platform's font stack and rendered as a tofu box that read like a stray character stuck to the balance. Replaced with an inline SVG in both the row and the address card. Both confirmation flashes now swap innerHTML rather than textContent, which would have deleted the SVG and left a blank square. Address card: the address and its copy button share one row, so the button sits at the end of the value it copies. The address clamps to two lines and truncates beyond that instead of growing the card in a narrow sidebar. The QR is always visible and the panel is drag-resizable from a grip under it (pointer events, arrow keys as a non-mouse path, clamped 90–420px, capped against the panel's own width so a size set on a wide sidebar cannot overflow a narrow one, persisted). That replaces the 0.9.2 show/hide toggle — a size set once beats a binary, and it frees the row Copy was sharing with a QR button. drawQr was setting cv.style.width/height, which would have reset the panel to its intrinsic size on every redraw — i.e. every time the address changed. It now sets only the backing store and re-asserts the user's size after drawing. "Next unused address" is correct at the adapter level on both mainnet and chipnet (tested: the index advances and the address changes), so the reported failure is elsewhere. The handler was discarding the error and flashing a bare "Failed", which is why there was nothing to diagnose; it now surfaces the real message.
2026-09-24 22:30:10 +02:00
<!-- Drag the bottom edge to resize the QR. Height persists. -->
<div class="qrwrap" id="qrWrap"><canvas id="qr" width="200" height="200"></canvas></div>
<div class="qrgrip" id="qrGrip" title="Drag to resize the QR code"><span></span></div>
</div>
<div class="card" id="tokensCard" hidden style="margin-top:12px">
chore(aegis): 0.9.2 — Receive tab reorder, one balance, token history Receive was ordered QR → address → tokens, so 200px of always-on QR sat above the thing people came for and pushed the asset list off screen. - Address first, with Copy and a QR button; the QR expands inline and the choice sticks, because someone who receives by QR wants it every time and someone who copies never does. - Explorer and Faucet moved up to the header status row. They act on the selected wallet, not on the act of receiving, and down there they competed with Copy for the one row that gets used. - Assets card renamed from Tokens and now leads with the native coin, so "what does this wallet hold" is one list rather than two places. - "+ Add another <TICKER>" moved below the address list. The balance appeared three times — header, drilldown subtitle, address row. Now once in the header; the subtitle keeps only the per-unit price, and the per-address amount returns when a coin actually has more than one address to compare. The address row drops its truncated address (the full one is at the top of Receive) and keeps the wallet name. The per-address asset list added in 0.8.8 duplicated the Assets card and is removed — assets live in one place. Token amounts were unreadable: an 18-decimal balance rendered as 60000000.000000005435817984. Capped to 8 decimals with thousands separators, exact value on hover. A symbol claimed by more than one contract now carries a LOOK-ALIKE tag. The test wallet holds four different contracts all calling themselves "Test USDT" — spam mints borrowing a trusted ticker so a careless send lands on the wrong one. We can't tell which is genuine, so we mark every member of the clash rather than guessing. History showed native transfers only, so a wallet that had only ever moved USDT looked empty. TRC20 transfers are merged in newest-first, each carrying its own decimals and ticker (rendering a token against the chain's scale would be off by orders of magnitude). Both feeds are on by default; the checkboxes narrow rather than opt in, and the last one checked can't be unchecked into an empty list.
2026-09-23 01:17:33 +02:00
<div class="lbl">Assets <span class="hint" id="tokensCount"></span></div>
<div id="tokensList" class="kv"></div>
<div class="hint" id="tokensHint">Tokens held by this wallet.</div>
</div>
</div><!-- /rcvNormal -->
<!-- Consolidate view (inline, replaces Receive body when active). -->
<div id="rcvConsolidate" hidden>
<div id="rcvConsolidateInline"></div>
</div>
</section>
<section id="tab-send" hidden>
<!-- Send/Consolidate mode toggle (0.8.0). Same pattern as Receive. -->
<div id="sendModeToggle" class="modetoggle" hidden>
<button data-send-mode="send" class="on" type="button">Send</button>
<button data-send-mode="consolidate" type="button">Consolidate <span id="sendConsolidateCount" class="hint"></span></button>
</div>
<div id="sendNormal">
<!-- Legacy chip retained but hidden — 0.7.7's chip is replaced by
the mode toggle above. Kept in the DOM so existing panel.js
code that reads it doesn't NPE mid-migration. -->
<div id="consolidateChipWrap" hidden style="margin-bottom:12px">
<button id="consolidateChip" class="btn sm" type="button" style="width:100%;text-align:left;display:flex;align-items:center;gap:8px;justify-content:space-between">
<span>⇢ Consolidate balances into <b id="consolidateChipDest">this wallet</b></span>
<span class="hint" id="consolidateChipCount"></span>
</button>
</div>
<div class="field" id="sendAssetField" hidden>
<div class="lbl">Asset</div>
<select id="sendAsset"></select>
<div class="hint">Pick the native coin or an SPL token in this wallet.</div>
</div>
<div class="field">
<div class="lbl">Recipient</div>
<input type="text" id="sendTo" spellcheck="false" autocomplete="off" placeholder="…">
<div class="hint" id="sendToHint"></div>
</div>
<div class="field">
<div class="lbl">Amount <span id="sendAmtFiat" class="fiat" style="margin-left:8px" hidden></span></div>
<div class="amt">
<input type="text" id="sendAmt" inputmode="decimal" autocomplete="off" placeholder="0.00">
<div class="unit" id="unitPicker"></div>
<button class="btn sm" id="sendMax" type="button">Max</button>
</div>
</div>
<div class="field" id="feeField">
<div class="lbl">Fee</div>
<div class="fee"><input type="range" id="feeRate" min="1" max="5" step="1" value="1"><span class="v" id="feeLbl">1 sat/B</span></div>
</div>
<!-- Optional OP_RETURN memo. BCH-only for now (UTXO chains only);
the field hides when a non-BCH wallet is selected. 220 byte cap
keeps the tx under standardness relay policy. Memo is public on
the ledger — the placeholder text warns before someone types. -->
<div class="field" id="memoField" hidden>
<div class="lbl">Memo <span class="hint" style="margin-left:8px;font-weight:normal">optional · public on-chain · ≤220 bytes</span></div>
<input type="text" id="sendMemo" maxlength="220" spellcheck="false" autocomplete="off"
placeholder="e.g. Invoice #1234 — visible to anyone">
</div>
<div class="card">
<div class="summary">
<div class="k">Amount</div><div class="v" id="sumAmt">—</div>
<div class="k">Network fee</div><div class="v" id="sumFee">—</div>
<div class="k">Total</div><div class="v" id="sumTotal">—</div>
</div>
</div>
<div class="actions"><button class="btn primary" id="sendBtn" disabled>Send</button></div>
<div class="msg" id="sendMsg" hidden></div>
</div><!-- /sendNormal -->
<div id="sendConsolidate" hidden>
<div id="sendConsolidateInline"></div>
</div>
</section>
<section id="tab-history" hidden>
chore(aegis): 0.9.2 — Receive tab reorder, one balance, token history Receive was ordered QR → address → tokens, so 200px of always-on QR sat above the thing people came for and pushed the asset list off screen. - Address first, with Copy and a QR button; the QR expands inline and the choice sticks, because someone who receives by QR wants it every time and someone who copies never does. - Explorer and Faucet moved up to the header status row. They act on the selected wallet, not on the act of receiving, and down there they competed with Copy for the one row that gets used. - Assets card renamed from Tokens and now leads with the native coin, so "what does this wallet hold" is one list rather than two places. - "+ Add another <TICKER>" moved below the address list. The balance appeared three times — header, drilldown subtitle, address row. Now once in the header; the subtitle keeps only the per-unit price, and the per-address amount returns when a coin actually has more than one address to compare. The address row drops its truncated address (the full one is at the top of Receive) and keeps the wallet name. The per-address asset list added in 0.8.8 duplicated the Assets card and is removed — assets live in one place. Token amounts were unreadable: an 18-decimal balance rendered as 60000000.000000005435817984. Capped to 8 decimals with thousands separators, exact value on hover. A symbol claimed by more than one contract now carries a LOOK-ALIKE tag. The test wallet holds four different contracts all calling themselves "Test USDT" — spam mints borrowing a trusted ticker so a careless send lands on the wrong one. We can't tell which is genuine, so we mark every member of the clash rather than guessing. History showed native transfers only, so a wallet that had only ever moved USDT looked empty. TRC20 transfers are merged in newest-first, each carrying its own decimals and ticker (rendering a token against the chain's scale would be off by orders of magnitude). Both feeds are on by default; the checkboxes narrow rather than opt in, and the last one checked can't be unchecked into an empty list.
2026-09-23 01:17:33 +02:00
<!-- 0.9.2: token movement used to be invisible here — a wallet that
only ever moved USDT looked like it had no history. Both feeds
are on by default; the filters exist to narrow, not to opt in. -->
<div class="histfilter" id="histFilter" hidden>
<label class="switch"><input type="checkbox" id="histNative" checked><span id="histNativeLbl">Coin</span></label>
<label class="switch"><input type="checkbox" id="histTokens" checked><span>Tokens</span></label>
<span class="hint" id="histCount" style="margin-left:auto"></span>
</div>
<div id="txlist"></div>
</section>
<section id="tab-settings" hidden>
<!-- 0.8.2: Settings sectioned. Chip row at top picks which section
is visible; each section wraps a group of related cards. The
chain-specific cards (bchSettings / trxSettings / …) sit
inside the "Wallet" section and their own hidden-vs-shown
toggle (per selected chain) still applies within it. -->
<div class="setsecnav" id="setsecnav">
<button data-setsec="security" class="on" type="button">Security</button>
<button data-setsec="session" type="button">Session</button>
<button data-setsec="wallet" type="button">Wallet</button>
<button data-setsec="prices" type="button">Prices</button>
<button data-setsec="sites" type="button">Sites</button>
<button data-setsec="about" type="button">About</button>
</div>
<div data-setsec-body="security">
<!-- Cross-cutting security / policy controls, ahead of anything
per-wallet or chain-specific. Present even when the vault is
still locked so users can set up a PIN or read the multi-sig
roadmap without unlocking first (they only do the ACTUAL PIN
enrollment after a fresh unlock, though). -->
<div class="card gsec" id="genSecurity" style="margin-bottom:14px">
<div class="gtitle">Security</div>
<div class="gline">
<div class="glabel">
Quick-access PIN
<span class="ghint" id="pinStatusHint">Off — Aegis asks for the master password every time.</span>
</div>
<div class="gactions">
<button class="btn sm" id="gsPinSet" hidden>Set PIN…</button>
<button class="btn sm" id="gsPinChange" hidden>Change…</button>
<button class="btn sm danger" id="gsPinRemove" hidden>Remove</button>
</div>
</div>
<div class="gline" id="gsRequirePinLine" hidden>
<div class="glabel">
Require PIN for sending
<span class="ghint">Prompts for your PIN on every panel-initiated Send. Dapp-driven approvals still use the standard approval overlay.</span>
</div>
<div class="gactions">
<label class="switch"><input type="checkbox" id="gsRequirePin"><span></span></label>
</div>
</div>
</div>
</div><!-- /security section (multi-sig card lives inside it below) -->
<div data-setsec-body="session" hidden>
<!-- Session: stay-signed-in + idle auto-lock + manual sign-out.
Uses electron.safeStorage under the hood so the master password
is only decryptable under this OS user account. When "Lock on
Navigator close" is on (the default), Aegis stores nothing on
disk and forces a fresh unlock on every launch. -->
<div class="card gsec" id="genSession" style="margin-bottom:14px">
<div class="gtitle">Session</div>
<div class="gline">
<div class="glabel">
Lock on Navigator close
<span class="ghint" id="gsSessionHint">On — Aegis asks for the master password (or PIN) every time Theseus starts. Turn off to stay signed in across restarts via the OS keystore.</span>
</div>
<div class="gactions">
<label class="switch"><input type="checkbox" id="gsLockOnClose" checked><span></span></label>
</div>
</div>
<div class="gline">
<div class="glabel">
Auto-lock when idle
<span class="ghint">Locks the vault after this long with no panel activity. Applies inside the wallet panel; a locked panel elsewhere in the browser doesn't count as idle.</span>
</div>
<div class="gactions">
<select id="gsIdleMinutes" style="padding:5px 8px;border-radius:6px;background:var(--panel);border:1px solid var(--line);color:var(--ink);font-size:12px">
<option value="0">Never</option>
<option value="5">5 min</option>
<option value="15" selected>15 min</option>
<option value="30">30 min</option>
<option value="60">1 hour</option>
<option value="180">3 hours</option>
</select>
</div>
</div>
<div class="gline">
<div class="glabel">
Sign out now
<span class="ghint">Locks the vault immediately. Any dapp connections stay paired, but Aegis will refuse to sign until you unlock again.</span>
</div>
<div class="gactions">
<button class="btn sm danger" id="gsSignOut">Sign out</button>
</div>
</div>
</div>
<div class="card gsec" id="genMasterPw" style="margin-bottom:14px">
<div class="gtitle">Master password</div>
<div class="gline">
<div class="glabel">
Change master password
<span class="ghint">Opens Theseus <span class="mono">Settings › Passwords</span>. The vault re-encrypts under the new password; every derived wallet keeps working.</span>
</div>
<div class="gactions">
<button class="btn sm" id="gsOpenPasswords">Open Passwords…</button>
</div>
</div>
</div>
</div><!-- /session section -->
<div data-setsec-body="security" hidden>
<div class="card gsec" id="genMultiSig" style="margin-bottom:14px">
<div class="gtitle">Second-device approval <span class="gsoon">soon</span></div>
<div class="gline">
<div class="glabel">
Co-sign sends from a second device
<span class="ghint">Aegis will pair with Ariadne on your phone so large transfers need a nod from both places before they broadcast. Not shipped yet.</span>
</div>
<div class="gactions">
<button class="btn sm" disabled title="Not shipped yet">Set up…</button>
</div>
</div>
</div>
</div><!-- /security-multisig -->
<div data-setsec-body="wallet" hidden>
<div class="card" id="walletManage" style="margin-bottom:14px">
<div class="lbl">This wallet</div>
<div class="field" style="margin-top:6px;margin-bottom:8px">
<input type="text" id="renameLabel" placeholder="Wallet name">
</div>
<div class="actions">
<button class="btn sm" id="renameBtn">Rename</button>
<button class="btn sm danger" id="removeBtn">Remove wallet</button>
</div>
<div class="hint" id="removeHint"></div>
</div>
<div id="bchSettings" hidden>
<div class="field">
<div class="lbl">Derivation path (account)</div>
<input type="text" id="setPath" spellcheck="false" placeholder="m/44'/145'/0'">
<div class="hint">Changing this switches to a different set of addresses under the same wallet seed.</div>
</div>
<div class="field" id="bchServersRow">
<div class="lbl">Electrum servers <span class="hint" style="font-weight:normal">(BCH mainnet — shared across BCH wallets)</span></div>
<div id="setServersList" class="serverlist"></div>
<details style="margin-top:6px">
<summary style="cursor:pointer;color:var(--dim);font-size:11.5px">Add a custom server…</summary>
<div style="display:flex;gap:6px;margin-top:6px">
<input type="text" id="setServersCustom" spellcheck="false" placeholder="wss://host:port" style="flex:1">
<button class="btn sm" id="addCustomServer" type="button">Add</button>
</div>
</details>
<div class="hint" id="serverHint"></div>
</div>
<div class="actions">
<button class="btn primary" id="applySettings">Apply</button>
<button class="btn" id="resetServers">Reset servers</button>
</div>
<div class="card" style="margin-top:16px">
<div class="lbl">Recovery info</div>
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="purpose"></span>. The same vault seed on another machine recreates this wallet.</div>
<div class="kv" id="recovery"></div>
<div class="actions">
<button class="btn" id="showXpub">Show account xpub</button>
<button class="btn danger" id="showXprv">Show account private key</button>
</div>
</div>
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
<div class="card" style="margin-top:16px" id="wcCard">
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
<div class="lbl">WizardConnect</div>
<div class="hint" style="margin-bottom:8px">
Pair this BCH wallet with a dapp that speaks the WizardConnect protocol
(Cauldron, Moria, or any site built on the SDK). Paste the <span class="mono">wiz://</span>
URI the dapp shows in its Connect dialog. Aegis signs every transaction only after you approve it.
</div>
<!-- Warning that appears when the selected wallet is imported —
WC signing needs the derive-based signer path, which imported
wallets don't have yet. Shown in place of the input so users
don't try to paste a URI and hit "wallet not ready". -->
<div class="msg err" id="wcImportedNotice" hidden style="margin-bottom:8px">
WizardConnect isn't available for imported wallets yet — pairing
uses Aegis' vault-derived signer path, and imported wallets are
read-only for now. Coming in a later release.
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
</div>
<div id="wcInputs">
<div class="field" style="margin-top:8px">
<input type="text" id="wcUri" spellcheck="false" placeholder="wiz://?p=…&amp;s=…">
</div>
<div class="actions">
<button class="btn primary" id="wcConnectBtn">Connect</button>
</div>
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
</div>
<div class="msg" id="wcMsg" hidden></div>
<div class="kv" id="wcSites" style="margin-top:8px"></div>
</div>
</div>
<div id="trxSettings" hidden>
<div class="card">
<div class="lbl">Recovery info</div>
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="trxPurpose"></span>. Import into TronLink with the derivation path <span class="mono">m/44'/195'/0'/0/0</span> from the same vault seed.</div>
</div>
</div>
<div id="scSettings" hidden>
<div class="field">
<div class="lbl">walletd URL</div>
<input type="text" id="setWalletdUrl" spellcheck="false" placeholder="https://your-walletd.example/api">
<div class="hint">Any public or self-hosted <span class="mono">go.sia.tech/walletd</span> in "full" index mode. The URL is per-wallet, so different Sia sub-accounts can point at different nodes. It is not shared with anyone else.</div>
</div>
<div class="actions">
<button class="btn primary" id="applyWalletdUrl">Apply</button>
</div>
<div class="card" style="margin-top:16px">
<div class="lbl">Recovery info</div>
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="scPurpose"></span>. Address scheme: walletd <span class="mono">KeyFromSeed(seed, index)</span>.</div>
<div class="kv" id="scRecovery"></div>
<div class="actions">
<button class="btn danger" id="showScSeed">Reveal wallet seed</button>
</div>
</div>
</div>
<div id="dgbSettings" hidden>
<div class="field">
<div class="lbl">Address family</div>
<select id="setDgbFamily"></select>
<div class="hint">Picks the BIP purpose that shapes your DGB addresses. Switching rebuilds the wallet against a different set of addresses under the same seed — old funds don't move; they still live under the family they were received on.</div>
</div>
<div class="field">
<div class="lbl">Derivation path (account)</div>
<input type="text" id="setDgbPath" spellcheck="false" placeholder="m/84'/20'/0'">
<div class="hint">Auto-filled from the family above. Edit only if you need a non-default account.</div>
</div>
<div class="actions">
<button class="btn primary" id="applyDgbPath">Apply</button>
</div>
<div class="card" style="margin-top:16px">
<div class="lbl">Recovery info</div>
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="dgbPurpose"></span>. Any BIP39 tool set to <span class="mono">DGB</span> (coin type 20) at the same purpose can reproduce this wallet.</div>
<div class="kv" id="dgbRecovery"></div>
<div class="actions">
<button class="btn" id="showDgbXpub">Show account xpub</button>
<button class="btn danger" id="showDgbXprv">Show account private key</button>
</div>
</div>
</div>
<div id="btcSettings" hidden>
<div class="field">
<div class="lbl">Address family</div>
<select id="setBtcFamily"></select>
<div class="hint">Picks the BIP purpose that shapes your Bitcoin addresses. Switching rebuilds the wallet against a different set of addresses under the same seed — old funds don't move; they still live under the family they were received on.</div>
</div>
<div class="field">
<div class="lbl">Derivation path (account)</div>
<input type="text" id="setBtcPath" spellcheck="false" placeholder="m/84'/0'/0'">
<div class="hint">Auto-filled from the family above. Edit only if you need a non-default account.</div>
</div>
<div class="actions">
<button class="btn primary" id="applyBtcPath">Apply</button>
</div>
<div class="card" style="margin-top:16px">
<div class="lbl">Recovery info</div>
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="btcPurpose"></span>. Any BIP39 tool at coin type 0 (mainnet) / 1 (testnet) and the same purpose can reproduce this wallet.</div>
<div class="kv" id="btcRecovery"></div>
<div class="actions">
<button class="btn" id="showBtcXpub">Show account xpub</button>
<button class="btn danger" id="showBtcXprv">Show account private key</button>
</div>
</div>
</div>
<div id="ethSettings" hidden>
<div class="field">
<div class="lbl">RPC URL</div>
<input type="text" id="setEthRpcUrl" spellcheck="false" placeholder="https://cloudflare-eth.com">
<div class="hint">JSON-RPC endpoint Aegis reads balances and broadcasts from. Any provider works — public gateways (Cloudflare, PublicNode), Alchemy, Infura, or your own node. Stored per-wallet; not shared.</div>
</div>
<div class="actions">
<button class="btn primary" id="applyEthRpc">Apply</button>
</div>
<div class="card" style="margin-top:16px">
<div class="lbl">Recovery info</div>
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="ethPurpose"></span>. Import into MetaMask / any Ethereum wallet using the derivation path <span class="mono">m/44'/60'/0'/0/0</span> from the same vault seed.</div>
<div class="kv" id="ethRecovery"></div>
<div class="actions">
<button class="btn danger" id="showEthKey">Reveal private key</button>
</div>
</div>
</div>
<div id="solSettings" hidden>
<div class="field">
<div class="lbl">RPC URL</div>
<input type="text" id="setSolRpcUrl" spellcheck="false" placeholder="https://api.mainnet-beta.solana.com">
<div class="hint">JSON-RPC endpoint. The public Solana RPCs are heavily rate-limited — for real use point Aegis at Helius / QuickNode / your own node.</div>
</div>
<div class="actions">
<button class="btn primary" id="applySolRpc">Apply</button>
</div>
<div class="card" style="margin-top:16px">
<div class="lbl">Recovery info</div>
<div class="hint">Keys come from your Theseus password vault under <span class="mono" id="solPurpose"></span>. Import into Phantom / Solflare with the derivation path <span class="mono">m/44'/501'/0'/0'</span> from the same vault seed.</div>
<div class="kv" id="solRecovery"></div>
<div class="actions">
<button class="btn danger" id="showSolKey">Reveal wallet seed</button>
</div>
</div>
</div>
</div><!-- /wallet section -->
<div data-setsec-body="prices" hidden>
<div class="card" style="margin-top:0">
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
<div class="lbl">Fiat prices</div>
<div class="hint" style="margin-bottom:10px">
Off by default. When enabled, Aegis polls every supported oracle in
parallel and reconciles the results — two or more sources agreeing
within ±3% form the trusted price, so no single oracle can quietly
make Aegis show a wrong number. Every enabled oracle sees your IP
+ a User-Agent every poll, which is a signal that a wallet is open
on this machine.
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
</div>
<div class="actions" style="align-items:center;gap:12px">
<label class="switch">
<input type="checkbox" id="pricesToggle">
<span>Enable USD prices</span>
</label>
<button class="btn sm" id="refreshPrices" hidden>Refresh now</button>
<span class="hint" id="pricesStatus" style="margin-left:auto"></span>
</div>
<!-- Per-source status: which oracles are up, which are down, and
the last per-chain reconciliation method (majority / median /
single). Populated from the priceFeed snapshot. -->
<div id="pricesSources" class="hint" style="margin-top:10px"></div>
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
</div>
<!-- Hidden legacy select so panel.js code that reads .value doesn't
NPE while we transition; select stays hidden and empty. -->
<select id="pricesSource" hidden></select>
<span id="pricesSourceHint" hidden></span>
</div><!-- /prices section -->
feat(theseus/aegis): 0.6.1 — in-panel vault setup/unlock, BCH wallet imports, opt-in fiat prices, WizardConnect Aegis Wallet 0.4.4 → 0.6.1: - Vault lifecycle from the wallet gate. The locked / not-yet-created states now show a master-password form (with optional BIP39 mnemonic on setup) instead of redirecting users to Settings › Passwords. New api.vault.lifecycle {status, setup, unlock, lock} in addons-host, gated by the existing "vault-derive" capability. api.openSettings(section) also added; settings.html honours a #section hash on open. - Imported BCH wallets (design M.1a, read-only). Paste a mnemonic + BIP44 path or a WIF; the cashaddr is derived in the add-on, the signer material goes to a separate wallet-imports.enc via api.vault.imports {list, add, remove, signer}. Argus password-vault gains createImports / unlockImports / saveImports with its own KDF salt so the imports key is disjoint from the passwords key. lib/chain-bch-imported.js is a single-address Electrum adapter; spend support is deferred to M.1b. - Opt-in USD prices via CoinGecko (lib/prices.js), off by default, persisted in add-on storage. Fiat lines under balances, in the wallet picker, and a portfolio total when 2+ wallets are open. Settings tab is now reachable while the vault is locked so the toggle is always available. - WizardConnect wallet-side pairing for BCH wallets (lib/wc.js, lib/wc-sign.js). @wizardconnect/{core,wallet} are loaded dynamically via api.import to stay on the right side of LGPL §4d. Sign requests go through approvalModal and are restricted to P2PKH inputs with SIGHASH_ALL|FORKID|UTXOS. - DGB adapter load is now soft-fail: when Aegis runs from userData/addons the bundled ESM can't resolve peer deps, so DGB becomes unavailable instead of taking the whole add-on down.
2026-09-09 10:33:21 +02:00
<div data-setsec-body="sites" hidden>
<div class="card" style="margin-top:0">
<div class="lbl">Connected sites</div>
<div class="hint">Sites allowed to see your address, allowances for silent BCH payments, and Tron dapps you've connected. Message signing always asks.</div>
<div id="sites" class="kv"></div>
</div>
</div><!-- /sites section -->
<div data-setsec-body="about" hidden>
<div class="card" style="margin-top:0">
<div class="lbl">About Aegis</div>
<div class="hint" style="margin-bottom:10px">
Aegis is Silent Mode's built-in multi-chain wallet. Keys are derived
from your Theseus vault — same vault, every wallet across every
chain. Aegis lives at <a class="link" id="aboutOpenAegisSite">aegis.x</a> and
this build's version + update chip sit at the bottom-right of the
panel.
</div>
<div class="hint">
Silent Mode — <a class="link" id="aboutOpenSilentmodeSite">silentmode.st</a> ·
docs on the plugin system live at <span class="mono">theseus.x/plug-ins</span>.
</div>
</div>
</div><!-- /about section -->
<div class="msg err" id="settingsMsg" hidden></div>
</section>
</div>
</main>
<!-- Full-panel lock screen. Absolutely positioned so it takes over the
entire content area (everything above the aegis footer) whenever the
vault is locked or awaiting first-time setup — the header picker, nav
tabs, and wallet strip stay in the DOM but sit visually under it. The
Settings tab still hides itself; nothing here interacts with it. -->
<div id="lockScreen" hidden>
<div class="aegisMark" aria-hidden="true">
<svg viewBox="0 0 32 32" fill="none">
<polygon points="16,2 28,9 28,23 16,30 4,23 4,9" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"/>
<circle cx="16" cy="16" r="4.5" fill="none" stroke="currentColor" stroke-width="1.4"/>
<circle cx="16" cy="16" r="1.6" fill="currentColor"/>
</svg>
</div>
<h1 id="lockTitle">Unlock Aegis</h1>
<div class="subhint" id="lockSub">Aegis derives its keys from your Theseus vault. There's nothing separate to unlock — the vault is your wallet.</div>
<div id="lockBody"></div>
</div>
<footer class="brandfoot" id="brandFoot">
<a href="#" id="brandLink" class="brandlink" title="Open aegis.x">
<svg viewBox="0 0 32 32" width="14" height="14" aria-hidden="true"><polygon points="16,2 28,9 28,23 16,30 4,23 4,9" fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/><circle cx="16" cy="16" r="4.3" fill="none" stroke="currentColor" stroke-width="1.4"/><circle cx="16" cy="16" r="1.3" fill="currentColor"/></svg>
<span>aegis.x</span>
</a>
<!-- Update controls (0.8.1): the update chip lives INSIDE the right-side
group, sharing the slot with the version marker. paintFooterUpdate()
hides brandVer when a newer build is available and shows brandUpdate
in its place — clicking the acid-green "↑ v0.8.1" text stages the
download and relaunches Theseus. Idle: brandVer visible, brandUpdate
hidden. Same one-click Update/Install path the user asked for, at
the exact spot they identified. -->
<span class="brandfoot-right">
<button id="brandCheck" class="brandcheck" type="button" title="Check for updates">↻</button>
<span id="brandUpdate" class="brandupd" hidden></span>
<span class="brandver" id="brandVer"></span>
</span>
</footer>
<script src="qr.js"></script>
<script src="panel.js"></script>
</body>
</html>