theseus/bundled-addons/aegis/panel.html
Local Dev f46e9112b7 chore(theseus): 0.3.47 — plug-in category + panel-driven addon self-update, aegis 0.6.31
Theseus core:
- addons-host: manifest.category ("plugin") propagates through snapshot(); new
  addon API surface checkAndStageSelfUpdate() + restartApp() so a plug-in
  can offer in-panel "update now → restart to apply" without pushing the
  user to Settings.
- main.js: wires the two new hooks into the AddonHost constructor.
- settings.html: Extensions listing filters out category==="plugin"; those
  add-ons live in Plug-ins instead, single source of truth.

Aegis 0.6.31:
- BTC picker trimmed to Signet only; testnet3 hidden (adapter kept so any
  existing wallet still loads).
- Wallet strip groups by chain, not chain:network; ticker gets a ▾ chevron
  and a dropdown listing every subnetwork with its own totals. Mainnet
  reads as the plain ticker; testnets carry a small Chipnet/Signet/Sepolia
  pill inline.
- Per-unit price sits directly under the ticker; amount + fiat mirror on
  the right — one glance covers name/price/holding/value.
- + Add and ⋯ More promoted from the strip into the header's action row,
  next to the new ✎ chip (was the redundant top ⋯). Duplicate "Manage
  current wallet" entry removed from the More menu.
- Footer update chip is a two-step flow via the new API: stage → restart.
  Falls back to opening Settings on any Theseus that lacks the hooks.
- Manifest declares "category": "plugin".
2026-09-14 02:30:51 +02:00

843 lines
54 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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; }
.bal { margin-top: 8px; font-variant-numeric: tabular-nums; }
.bal .big { font-size: 22px; font-weight: 650; letter-spacing: .2px; }
.bal .big small { font-size: 13px; color: var(--mut); font-weight: 500; margin-left: 4px; }
.bal .sub { color: var(--dim); font-size: 11.5px; display: flex; justify-content: space-between; gap: 8px; }
.bal .sub .netlbl { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Full-panel sheet — fills the sidebar so long wallet lists and the
import form aren't squeezed into a small popover. */
#drop { position: fixed; left: 0; right: 0; top: 60px; bottom: 0;
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; }
#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); }
.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; }
#hNet { color: var(--dim); font-size: 11px; margin-left: 4px; font-weight: 500; }
.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); }
nav { display: flex; border-bottom: 1px solid var(--line); background: var(--panel); }
nav button { flex: 1; padding: 9px 0 8px; border: 0; background: transparent; color: var(--mut); cursor: pointer;
font: inherit; font-size: 12.5px; border-bottom: 2px solid transparent; }
nav button.on { color: var(--acid); border-bottom-color: var(--acid); }
nav button:hover { 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; }
.qrwrap { display: grid; place-items: center; padding: 12px; background: #fff; border-radius: 10px; margin-bottom: 12px; }
canvas { image-rendering: pixelated; }
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; }
.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; }
.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; }
.wstrip .warow { display: grid; grid-template-columns: 16px minmax(60px,1fr) auto auto auto;
gap: 6px; align-items: center; padding: 5px 4px;
border-radius: 6px; border: 1px solid transparent; cursor: pointer; min-height: 30px; }
.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 .waname { font-size: 13px; color: var(--ink); overflow: hidden; text-overflow: ellipsis;
white-space: nowrap; font-weight: 500; }
.wstrip .warow .waaddr { font: 11px/1.15 ui-monospace, Consolas, monospace; color: var(--dim); margin-top: 2px;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wstrip .warow .waamt { text-align: right; font-variant-numeric: tabular-nums; font-size: 12.5px; color: var(--ink); }
.wstrip .warow .wafiat { font-size: 11px; color: var(--dim); }
.wstrip .warow .wact { background: transparent; border: 0; color: var(--dim); cursor: pointer;
padding: 2px 5px; border-radius: 4px; font-size: 12.5px; line-height: 1; }
.wstrip .warow .wact:hover { color: var(--acid, #d6ff3d); background: rgba(255,255,255,.06); }
/* 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; }
#lockScreen .lockform { width: min(320px, 100%); display: flex; flex-direction: column; gap: 10px; text-align: left; }
#lockScreen .lockform input[type=password],
#lockScreen .lockform input[type=text],
#lockScreen .lockform textarea { 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>
<span id="hNet"></span>
</div>
<div class="picker-actions">
<button type="button" id="hAdd" class="chip" title="Add a new wallet"></button>
<button type="button" id="hMore" class="chip" title="Import / Connect / About"></button>
<button type="button" id="hManage" class="chip" title="Edit this wallet — rename, derivation path, remove"></button>
</div>
</div>
<div id="drop" hidden></div>
<div class="bal">
<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>
</div>
<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">
<div class="qrwrap"><canvas id="qr" width="200" height="200"></canvas></div>
<div class="card">
<div class="lbl">Receiving address <span id="addrMeta"></span></div>
<div class="mono" id="addr"></div>
<div class="actions">
<button class="btn sm" id="copyAddr">Copy</button>
<button class="btn sm" id="nextAddr" hidden>Next unused address</button>
<button class="btn sm" id="viewAddr">Explorer</button>
<button class="btn sm" id="openFaucet" hidden>Faucet</button>
</div>
</div>
<div class="card" id="tokensCard" hidden style="margin-top:12px">
<div class="lbl">Tokens</div>
<div id="tokensList" class="kv"></div>
<div class="hint">SPL tokens held by this wallet. Send by picking one under the Send tab's Asset dropdown.</div>
</div>
</section>
<section id="tab-send" hidden>
<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>
<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>
</section>
<section id="tab-history" hidden>
<div id="txlist"></div>
</section>
<section id="tab-settings" hidden>
<!-- 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>
<!-- 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 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 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>
<div class="card" style="margin-top:16px" id="wcCard">
<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.
</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>
</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 class="card" style="margin-top:16px">
<div class="lbl">Fiat prices</div>
<div class="hint" style="margin-bottom:10px">
Off by default. When enabled, Aegis polls the chosen oracle for USD prices
on each supported coin. No keys and no address data are ever sent — but the
oracle sees your IP + a User-Agent every poll, which is a signal that a
wallet is open on this machine.
</div>
<div class="field">
<div class="lbl">Oracle</div>
<select id="pricesSource" style="width:100%;padding:7px 9px;border-radius:7px;background:var(--panel);border:1px solid var(--line);color:var(--ink);font-size:13px"></select>
<div class="hint" id="pricesSourceHint"></div>
</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>
</div>
<div class="card" style="margin-top:16px">
<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 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: a subtle "check" link that polls the OTA manifest,
then swaps to an "Update to vX.Y.Z" chip when a newer version is
ready. Panel-only view since the addon can't promote itself; the
chip links to Settings > Extensions > Aegis where the Apply flow
lives. Version marker on the far right doubles as the up-to-date
affordance so a happy panel says nothing extra. -->
<span id="brandUpdate" class="brandupd" hidden></span>
<span class="brandfoot-right">
<button id="brandCheck" class="brandcheck" type="button" title="Check for updates"></button>
<span class="brandver" id="brandVer"></span>
</span>
</footer>
<script src="qr.js"></script>
<script src="panel.js"></script>
</body>
</html>