theseus/bundled-addons/aegis/panel.html
Local Dev 570e9e6213 feat(aegis): 0.10.0 — one status row above the balance instead of two around it
The network chip sat on its own row holding a single chip and ~300px of dead
space, while the connection state and the per-wallet actions sat on a second
row underneath the balance. Two thin rows sandwiching the number people open
the panel for pushed it into the middle of the header. They are now one row
above it: [network] [state] ......... [Explorer] [Faucet].

Neither half belongs in Settings. The status line is not a hostname label —
it is also where "connecting…", "· syncing", "· <n> unconfirmed" and the
walletd setup prompt are written, so filing it away would hide an unconfirmed
balance and an instruction. Explorer and Faucet are verbs on the selected
wallet rather than configuration, which is why 0.9.2 lifted them out of the
Receive card in the first place.

Only the hostname may shrink. Left to itself the flexbox took width off the
network chip first and clipped "Chipnet testnet" to "Chipnet" — the one label
on that row that must never be ambiguous, since it says whether the next
action moves real money.
2026-09-27 01:09:49 +02:00

1222 lines
80 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; }
/* 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; }
/* .sub is gone — its contents moved up into .netrow, see below. */
/* 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; }
#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; }
.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.
0.10.0: that row carried one small chip and ~300px of dead space, while
a second row under the balance carried the connection state and the
per-wallet actions. Two thin rows sandwiching the balance pushed the
number people open the panel for into the middle of the header. They are
one row now: [network] [state] ........ [Explorer] [Faucet], above the
balance. The whole row hides together when there is no wallet context,
which is the only case the old .netrow hid in. */
.netrow { display: flex; align-items: center; gap: 7px; margin-top: 8px;
padding: 0 2px; min-width: 0; }
/* Only the hostname may shrink. Without this the flexbox took width off
the network chip first, clipping "Chipnet testnet" to "Chipnet" — the
one label on the row that must never be ambiguous, since it is what
tells you whether you are about to move real money. */
.netrow .netchip, .netrow .net, .netrow .hdracts { flex: none; }
.netrow .netlbl { flex: 1 1 auto; color: var(--dim); font-size: 11.5px; min-width: 0;
overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.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); }
/* 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; }
/* 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; }
.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; }
.qrwrap { display: grid; place-items: center; padding: 12px; background: #fff; border-radius: 10px; margin-top: 12px; }
.qrwrap[hidden] { display: none; }
/* 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; }
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; }
/* 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. */
/* 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
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;
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; }
/* 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;
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); }
/* 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;
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;
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); }
/* 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; }
/* 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],
#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>
<span class="net"><span class="dot" id="dot"></span></span>
<!-- Not just a hostname: this line is also where "connecting…",
"· syncing", "· <n> unconfirmed" and the walletd setup prompt are
written, so it cannot move to Settings without hiding an
unconfirmed balance and a setup instruction. -->
<span class="netlbl" id="netlbl">connecting…</span>
<!-- 0.9.2 moved Explorer/Faucet out of the Receive card because they act
on the selected wallet, not on the act of receiving. They stay a
per-wallet action for the same reason they are not Settings: they
are verbs on the current wallet, not configuration. -->
<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>
<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 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">
<!-- 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>
<!-- 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>
<!-- 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">
<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>
<!-- 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>
<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><!-- /wallet section -->
<div data-setsec-body="prices" hidden>
<div class="card" style="margin-top:0">
<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.
</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>
</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 -->
<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>