aboutsummaryrefslogtreecommitdiffstats
path: root/src/style.css
Commit message (Collapse)AuthorAgeFilesLines
* The unread dot holds stillAdam Soltys2026-08-031-2/+4
| | | | | | | | | | | | | | | It looked like the dot was flickering on and off after a refresh. It wasn't: measured over the first twelve seconds it appeared once and never went away, while its entrance animation started seven separate times. render() rebuilds the whole DOM, so the pop replayed on every repaint. A dot that means 'someone is waiting' has nothing to animate about, so the animation is gone rather than gated. tools/unread-dot-test.js counts animation starts against real appear/disappear transitions, so a future entrance effect here fails instead of shipping as a flicker. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* The chat window fits the screen, and the header stops asking questionsAdam Soltys2026-08-031-6/+17
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The message log had a fixed 62vh height, so the card was head + panels + log + composer tall and the input fell off the bottom of the screen. The card is now sized to the viewport and the log is the only part that flexes: opening the invite or member panel shrinks the scroll area instead of pushing the composer out of reach. Three header changes, all the same idea — don't show a control for a choice nobody is making: '+' becomes 'Add person', because a plus sign doesn't say what it adds. A lone channel isn't named at all. '#general' next to a composer that says 'Message #general' points at a choice of one; several channels become a select, which is what a choice looks like. The new-channel field hides behind a 'New channel' button. Sitting open right after you create a community, it reads as something you're supposed to fill in. tools/chat-layout-test.js holds the line at three viewport sizes with both panels open, and covers the header behaviour through actually adding a second channel. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Offer the signer back where you'd notice it's missingAdam Soltys2026-08-031-0/+1
| | | | | | | | | | | | | A remote signer dropped by a reload now says so above the composer, with a button that reconnects in place — rather than letting someone write a message and only then be told it can't be sent as them. Failing that it opens the nostr settings, where logging in again is the fallback. Every remote-signer login made before sessions were persisted lands in exactly this state once. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Messages in the header, and a room you can tell is aliveAdam Soltys2026-08-031-0/+26
| | | | | | | | | | | | | | | | | | | | | | | | | | | | The header carries a message button again, left of the wallet selector, with a red dot when a conversation is waiting. Unread is a per-thread watermark on the newest message from someone else, kept in the rumor's own created_at so it means the same thing on every device it syncs to. Rooms subscribe at startup now, or the dot could not speak for a community nobody was listening to. Communities no longer buzz a phone by default: push registration only carries the stream keys of communities you have opted in, per community, from a bell in the room header. DMs and payments are unchanged. Presence and typing ride the channel stream as 21059 wraps, so who is around stays inside the community's encryption rather than becoming a public status. Measured against relay.coinos.io and nos.lol, neither actually drops NIP-01 ephemeral kinds, so beats carry a NIP-40 expiration and relay.coinos.io sweeps kind 21059 hourly — and presence is dated by the beat, never by arrival, or a replayed beat would light up the whole member list. The member list follows Telegram: online, then last seen in minutes and hours, then a vague 'recently' rather than advertising how long someone has been gone. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Move money: shorter amount placeholder, row wraps on narrow phonesAdam Soltys2026-08-031-0/+5
| | | | | | | | | | The placeholder repeated a minimum the line below already states, and it was clipped anyway — the amount field had 14px of usable width at 360px because "Move to Spending" crushed it. The row wraps to two full-width lines when it's tight and stays on one line when there's room. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Drop the gold ribbon from the balance cardAdam Soltys2026-08-031-11/+1
| | | | | Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Balance card: drop the descriptor lineAdam Soltys2026-08-031-2/+1
| | | | | | | | | | "Instant · free to send" and "On-chain · mining fees apply" were one line that swapped with the account; the card is just the balance now. Strings, styles and stale translations removed with it, and the face's reserved height comes down to match. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Balance card: a real button to change account, not two dotsAdam Soltys2026-08-031-4/+9
| | | | | | | | | | | The dots were an indicator pressed into service as a control — fine under a thumb that can just swipe, too small for a mouse. They're replaced by a pill in the header row naming the account it takes you to (⇄ Savings / ⇄ Spending), which is both a proper click target and a clearer answer to "what's the other one?". Swiping the card still works. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Pay screens: bigger recipient chip, no loading-screen flashesAdam Soltys2026-08-031-0/+3
| | | | | | | | | | | | Resolving a recipient (ark advert → BIP-353 → lightning) no longer takes over the screen twice on the way: both steps keep the send form in place and report progress as one inline line, so picking someone goes straight to something actionable. The recipient chip on the zap card gets a large variant — a 30px avatar and full-size name, since it's who the money is going to. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Move money: Max on both directions, inline in the amount fieldAdam Soltys2026-08-031-1/+10
| | | | | | | | | | | | Into Spending gains a Max (fee-aware — it asks the tx builder what a sweep would actually deliver, so the mining fee can't make the board fail), and both directions now carry Max as a small affordance inside the input's right edge instead of a button eating a third of the row. It only appears when there's a balance to max. Balance face height trimmed to match its shorter content. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Balance card: one account at a time, swipe or dots to flipAdam Soltys2026-08-031-1/+7
| | | | | | | | | | | | | | | | | | Replaces the segmented toggle and the always-visible second balance. The card now shows the account you're in at full size with a plain-word descriptor ("Instant · free to send" / "On-chain · mining fees apply"), two dots to flip, and a sideways slide when it changes. A swipe that starts on the card switches account instead of tab; swipes anywhere else still move between Receive/Send/History. Fixes a real mobile bug found while testing: a touch sequence still fires a compatibility click at the release point, so every swipe was ALSO pressing whatever sat under the finger (which is what kept bouncing the test wallet back to the unlock screen). One click is now swallowed after a recognized swipe. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Onboarding: "Use <addr> for now", address in muted monoAdam Soltys2026-08-031-0/+1
| | | | | Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Onboarding: the nostr mark heads the nostr stepsAdam Soltys2026-08-031-0/+5
| | | | | | | | | 72px, centered above the question (and the sign-in step), with a purple glow and a slow float — the one place in the flow that isn't the coinos brand, so it should look like nostr. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Self-host the punks; skipping avatar still publishes your punkAdam Soltys2026-08-031-0/+1
| | | | | | | | | | | | | coinos.io serves 502 for a third of the punk set (both the numbered and hash endpoints), which is why a default avatar could come up blank. The 64 webps now ship with the app (53 salvaged, 11 gaps filled with donors) and every reference is same-origin. Skipping the avatar step publishes the deterministic punk as the kind-0 picture — your face is the same on every nostr client. Success screen: checkmark now sits below the title, bigger. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* First-run onboarding: a five-step wizard and a coach-mark tourAdam Soltys2026-08-021-0/+31
| | | | | | | | | | | | | | | | | | | Fresh devices land in a full-screen flow instead of the unlock screen: welcome → "do you have a nostr account?" (sign in brings wallet, name, and profile along; No mints a wallet on the spot) → claim a username (the background npub-default only surfaces a Keep button; a custom claim — or a restored login's recovered name — advances by itself) → pick a punk or upload a photo (nostr.build), published as the kind-0 name+picture → confetti. "Enter coinos" drops into a three-stop tour: the avatar menu, the Spending/Savings toggle, and the tabs with the swipe tip — each highlighted by a measured gold ring over a dimmed page. One time only (localStorage flag), with an "I already have a wallet" escape to the classic screen. New seams: names.namesClaimForm, messages.publishProfile. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Tab carousel, login avatar fix, signer callback hintAdam Soltys2026-08-021-5/+6
| | | | | | | | | | | | | | | | | | | | | | Tab changes no longer flash the whole page: only the content pane below the tab strip slides sideways with a soft cross-fade — swipe direction when a gesture caused it, index order for taps — while the balance card and strip stay planted. Full-page entrances remain for real page changes (settings, chat, profile, takeovers). After a nostr sign-in the header briefly wore the wallet key's face: nostrLoginIdentity now reports a just-connected live signer immediately instead of waiting for the persisted link that only lands after the wallet opens. The nostrconnect URI carries a callbackUrl hint (NIP-55 style) so signer apps that honor it can bounce back to the PWA after approval — apps that don't will still find the session signed in when the user returns, since the handshake completes over the relay in the background. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Swipe between Receive / Send / HistoryAdam Soltys2026-08-021-1/+7
| | | | | | | | | | | | | Horizontal-dominant quick swipes move through the main tabs, sliding the page in from the swipe's direction (the nav animation picks a directional variant when a gesture caused it). Gated to the wallet's own tab pages — never chat, profiles, takeovers, or offline-forced settings — with a vertical-dominance test so scrolling never navigates, a touchcancel reset, and overscroll-behavior-x: none so the browser's edge-back gesture doesn't fight ours. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Motion and polish: navigation choreography, counting balance, gold ribbonAdam Soltys2026-08-021-0/+62
| | | | | | | | | | | | | | | | | | | | | | | | | The renderer rebuilds the DOM on every render, so naive CSS mount animations would replay on every background repaint. Two primitives fix that: uiChanged() gates one-shot animations to the render where the thing actually happened, and animWindow() lets a rebuild that lands mid-animation RESUME it via a negative animation-delay instead of killing or restarting it. On top of those: every real navigation rises in (screen/tab/subpage/ chat/profile — one keyed check in render()); the balance counts to its new value and breathes green when money arrives; the avatar menu pops from its corner; the move panel unfolds; the success check springs and rings once when its page lands. Micro-transitions on buttons, tabs, segs, inputs, list rows, avatars, and the settings chevrons. One chromatic signature on the monochrome brand: a slow-drifting bitcoin-gold ribbon across the top of the balance card, echoed by a faint warm wash pooling at the top of the page, plus a film-grain overlay for texture. All of it honors prefers-reduced-motion. The nostr sign-in mark also gets a proper inset ostrich and a size bump. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Header menu survives watch-only walletsAdam Soltys2026-08-021-0/+1
| | | | | | | | | | A watch-only wallet has no nostr identity, and the whole avatar menu — including Settings and Logout — vanished with it. The menu now shows a neutral face and keeps the keyless items; Edit profile and Messages appear only when an identity exists. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Wallets screen: bigger gear and remove buttonsAdam Soltys2026-08-021-0/+1
| | | | | Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Avatars: no punk flash while profiles loadAdam Soltys2026-08-021-0/+1
| | | | | | | | | | | The punk is a statement about having no picture, not a loading state — in-flight profiles show a quiet empty circle instead. Known profiles persist (capped at 150, daily background refresh) so your own avatar and regular correspondents paint correctly on the first frame of the next session. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Header: wallet + avatar only; the avatar opens an identity menuAdam Soltys2026-08-021-0/+3
| | | | | | | | | | | The chat button leaves the header — the avatar's popup menu carries Edit profile, Settings, Messages, and Logout (lock()). The menu is available inside the chat takeover too, which now keeps the full header. Messages provides just the avatar node via the headerAvatar seam; the app owns the menu. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Settings: a hub of five subpagesAdam Soltys2026-08-021-0/+2
| | | | | | | | | | The main page is just doors — Wallet (name, public key, recovery phrase), Payments (payment address + Spending status), Network (chain + data source), Nostr, Advanced. Every subpage keeps its own back button and rides browser history via the existing settingsPage nav field. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Profile: copy icon inside the npub box instead of a "Copy key" buttonAdam Soltys2026-08-021-0/+3
| | | | | | | | An npub isn't a key — no button, no label; just a small copy glyph right-aligned in the box. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Punk default avatars, header profile button, owner channel creationAdam Soltys2026-08-021-0/+4
| | | | | | | | | | | | | | | | Everyone gets a face: profiles without a picture fall back to a coinos punk, picked deterministically by the pubkey's last byte — the same 64 webps and formula the coinos app uses (initials show through if the image can't load). Your own avatar moves from the chat home to the app header next to the wallet selector, opening your editable profile from anywhere. Community owners can add channels from the room's + panel: one owner-signed ChannelMetadata edition (CORD-03), and every member's channel switcher grows when the fold lands. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Settings: nostr cards move to their own subpageAdam Soltys2026-08-021-2/+0
| | | | | | | | | | The main page ends with two doors — Nostr settings and Advanced settings. The nostr subpage carries the address, account link, wallet connect, and device sync cards; the inline section heading (and its now-unused string/CSS) is gone. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Profiles: view pages, editable own kind 0, zap recipients in historyAdam Soltys2026-08-021-0/+4
| | | | | | | | | | | | | | | | | | | Tapping any avatar or author name (chat rooms, DM threads, the chat home) opens a profile page: avatar, name, nip05, lightning address, about, npub, with Message and Pay actions (Pay runs the npub payment cascade). Your own profile — reachable from your avatar on the chat home — gets an editor for name, about, picture, and lightning address (prefilled with your coinos address); saving merges over the newest published kind 0 so fields we don't understand survive the round trip. Zaps now remember who they went to: the ark feature keys the recipient by what the movement already records (destination address or invoice) and history rows wear a clickable avatar chip that opens the profile. The messages feature exposes showProfile/profileChip seams so any feature can do the same. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Recipient search: usernames and npubs, in chat and the Send formAdam Soltys2026-08-021-0/+1
| | | | | | | | | | | | | | | | | | | | A shared engine (src/recipient-search.js) merges three ranked sources: an exact npub/hex paste, coinos usernames from the registrar's new /search prefix endpoint, and NIP-50 kind-0 full-text search on relay.nostr.band — the approach the major web clients take, since ordinary relays don't index profiles. Results dedupe by pubkey, fill avatars in one batched kind-0 fetch, and cache per query so narrowing never re-hits the network. Input is debounced 300ms and gated by a searchable() heuristic so addresses, invoices, and keys never trigger a search. Chat's New message panel narrows as you type and opens the thread on pick; the Send form shows the same candidates under the destination input and picking one runs the normal paste path (payment address → BIP-353, npub → zap). Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* One global account: you're in Spending or Savings everywhereAdam Soltys2026-08-021-0/+1
| | | | | | | | | | | | | | | The balance card's label becomes a Spending/Savings toggle and the selection is app-wide state (persisted per device): the headline shows the selected balance with the other quiet below, Receive shows the payment address in Spending and a fresh on-chain address in Savings (the per-page dropdown and its iconSelect widget are gone), and a gift's source follows the account instead of its own toggle. Wallets without Ark see the old single-balance card. Send stays destination-driven — an invoice pays from Spending, an address from Savings, as before. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Chat behind a header button, full-screen; move-panel polishAdam Soltys2026-08-021-1/+3
| | | | | | | | | | | | | | | Chat leaves the tab bar (which returns to its four evenly spaced tabs) for an icon button in the header next to the wallet selector. It now takes over the whole screen — no balance card, no tabs — with a back button on the chat home view, and the logo still leads back to the wallet. The generic tabs/tabContent seams this reverts to unused are removed again. Move panel: the direction toggle stretches across the card, and the "X sats in Spending" line is gone — the balance sits right above it. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Ark: automatic vtxo upkeep, and Move money inline on the balance cardAdam Soltys2026-08-021-0/+3
| | | | | | | | | | | | | | | | Refresh/consolidation is no longer a user concern: after each sync the wallet renews automatically when any spendable vtxo is within ~a week of expiry or fragmentation reaches six vtxos (a send needs one vtxo that covers the amount), throttled to one attempt per half hour and never while another round is in flight. The manual refresh button is gone. The separate Move money page is gone too — the button on the balance card now unfolds an inline panel with an Into Spending / Into Savings toggle: boarding happens right there, and Into Savings hands off to the existing exit page (cooperative offboard + unilateral exit unchanged). Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Settings: surface wallet settings, add Nostr section, tuck rarities into ↵Adam Soltys2026-08-021-0/+3
| | | | | | | | | | | | | | | | | | Advanced The main Settings tab now inlines the active wallet's own cards (recovery phrase, name, public key) instead of linking to a sub-page, followed by payment address, Ark status, network, and data source. All nostr cards — address, account link, wallet connect, device sync — sit under one Nostr heading via a new nostrSettingsCards seam. Offline transfer, address rescan, and auto-logout move to an Advanced sub-page. The Ark provider picker is gone: mainnet always rides coinos (a stale stored choice no longer wins); dev networks keep their per-network defaults. The per-account screen (Accounts → ⚙) reuses the same card builders unchanged. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Chat v2: DMs, invites, and multi-community — coinos is the default, not ↵Adam Soltys2026-08-021-0/+13
| | | | | | | | | | | | | | | | | | | | | | | the only - NIP-17 private DMs (src/dm.js): kind-14 rumors in sender-signed seals under ephemeral wraps; interops with other nostr DM clients. Login signers gained encryptTo/decryptFrom so extensions and bunkers can seal to a peer; the inbox listens for both the login npub and the wallet key and publishes a kind-10050 DM-relay list for the wallet key when none exists. - Concord invites (CORD-05): mint shareable links (33301 bundle on relays, keys only in the URL fragment), join by pasting a link or opening v3.coinos.io/invite/…, and direct invites giftwrapped to an npub with the k-tag index hint. Bundles self-certify the founder before anything joins. - Multi-community: home view lists DM threads and communities; found your own community in-app (owner-signed genesis). coinos stays baked in as default. - Welcome DM: the names registrar DMs every first-time registrant from Adam's npub on claim (config: welcome{sk,message}; deduped in registrar state). Every new wallet auto-claims a payment address, so every new user gets one. - relay.coinos.io write policy now allows 33301/13302/13303. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Remove the Hal Finney tributeAdam Soltys2026-08-021-1/+0
| | | | | Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Chat: Concord encrypted community messaging, with a default coinos roomAdam Soltys2026-08-021-0/+56
| | | | | | | | | | | | Implements the Concord protocol (CORD-01..04) — private streams, the control-plane fold, guestbook membership, owner-rooted authority — and ships a built-in "coinos" community founded by Adam's npub (owner/admin). Messages sign with the nostr login identity when a signer is live, else the wallet's NIP-06 key; all encryption rides derived stream keys so remote signers only ever sign seals. Co-Authored-By: Claude Fable 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Wvj4aoeMZwA7VUGdJP9Swi
* Bigger header logoAdam Soltys2026-08-011-2/+2
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* Use the official coinos wordmark SVG in the headerAdam Soltys2026-08-011-4/+2
| | | | | | | The full logo from coinos.io (symbol + wordmark as drawn paths) at 28px, inheriting the ink color for both themes; replaces the mark + text pair. Co-Authored-By: Claude Fable 5 <[email protected]>
* The coinos mark in the headerAdam Soltys2026-08-011-2/+1
| | | | | | | Inline single-color SVG of the brand symbol (ring + half-moon) that inherits the ink color, next to the lowercase wordmark. Co-Authored-By: Claude Fable 5 <[email protected]>
* Grayscale button hover — the last orange hardcodeAdam Soltys2026-08-011-1/+3
| | | | Co-Authored-By: Claude Fable 5 <[email protected]>
* Coinos branding: logo and black & white themeAdam Soltys2026-08-011-8/+10
| | | | | | | | | Icons, favicon, and PWA assets come from the coinos brand set; the accent goes monochrome (black in light mode, white in dark, with a proper on-accent text variable so buttons stay legible both ways) and the inline bitcoin mark inherits the text color. Co-Authored-By: Claude Fable 5 <[email protected]>
* Icons in the receive selector and on silent-payment history rowsAdam Soltys2026-07-061-0/+21
| | | | | | | | | | | | | | The receive address-type picker was a native <select>, which can't render SVG in <option>s. Replace it with a lightweight custom dropdown (icon-select) that shows a glyph per rail — ₿ Bitcoin, ⚡ Lightning, the Second mark for Ark, 🕶️ Silent payment — closing on select or an outside tap. Receive modes gained an icon field; the address option is built in app.js. Silent-payment receipts (which merge into history as on-chain-looking rows) now get a rail glyph + SP tag via a decorateTxRow so they're distinguishable, matching how ark/gift rows already decorate. Co-Authored-By: Claude Fable 5 <[email protected]>
* Fix dark-mode contrast and stop install-link jitterAdam Soltys2026-06-241-6/+12
| | | | | | | | | | | - warn-box, addr-box, summary, toast and green badge/notice borders used hardcoded light colors that washed out or vanished in dark mode; route them through theme variables (new --toast-bg/-fg and --green-line pairs). - Drive the footer "Install app" link from a persisted localStorage flag instead of the live beforeinstallprompt event so it's present on first paint after a refresh, eliminating the layout shift. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* Add dark mode; gift amount unit toggle; multi-input giftsAdam Soltys2026-06-241-4/+33
| | | | | | | | | | | | | | - Dark mode: theme variables + a footer "Dark mode/Light mode" toggle, persisted and applied pre-paint via a small head script (defaults to the OS preference). Hardcoded surfaces moved to CSS variables. - Gift amount: the unit label is now the clickable sats/BTC toggle, and the amount is parsed in the selected unit. - Gifts can now span multiple coins: createGift selects several confirmed coins (first input SIGHASH_SINGLE to lock the change, the rest SIGHASH_NONE), so a gift larger than any single coin works. Claim/preview sum all inputs and size the fee by input count. Verified end-to-end. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* Add Hal Finney tribute line to How it worksAdam Soltys2026-06-241-0/+1
| | | | | | | | | A footnote at the bottom: "The name Hal Wallet is a tribute to legendary cypherpunk and Bitcoin pioneer, Hal Finney (1956–2014)", with his name linking to his Wikipedia article. The contextual nod, rather than leaning on his name up front. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* Choose your own block explorer; flatten How it worksAdam Soltys2026-06-241-5/+0
| | | | | | | | | | | | | | | - Settings → Block explorer: pick mempool.space (default, with blockstream.info as a silent failover), blockstream.info only, or a custom Esplora/electrs REST URL (e.g. your own node). The realtime WebSocket only applies to mempool.space; other explorers fall back to polling. Switching rebuilds the API and rescans. Replaces the old undocumented explorer-proxy hack. - How it works: merge the "For the technically curious" disclosure into the main body so it's all visible under "The basics", and dedupe the overlapping no-server/offline sentences. Mentions the new explorer setting. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* Rebrand to Hal Wallet; roomier language-select caretAdam Soltys2026-06-241-0/+6
| | | | | | | | | | | - Name the app "Hal Wallet" (header, title, PWA manifest, package.json). A nod to Hal Finney — just the name, no taglines or tributes. - appTitle is a brand name now, so it's constant across locales (dropped the translated overrides; they fall back to "Hal Wallet"). - Replace the native <select> caret with a custom chevron spaced off the right border (the native one is crammed against the edge in Chrome). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* Debit balance optimistically on pending send; pointer cursor on summariesAdam Soltys2026-06-231-0/+1
| | | | | | | | | | | | | - Headline balance now shows wallet.total (confirmed + mempool) instead of confirmed, so a pending outgoing spend is debited immediately rather than waiting for confirmation. The chain_stats-based confirmed balance counts a coin as yours until the spend is mined, which is why it didn't drop after broadcasting (incl. scanned-tx broadcasts). Incoming pending is still surfaced by the "+X pending" line. - summary { cursor: pointer } so the "Show QR" disclosure (and any other <summary>) shows the hand cursor. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* Show full recipient address below the input for verificationAdam Soltys2026-06-231-0/+2
| | | | | | | | | The address input scrolls/truncates on mobile, hiding the ends. Render the full address as wrapping text beneath it with the first/last 6 chars emphasized, so paste/type/scan can be verified without scrolling. Updated imperatively on input so the field keeps focus. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* Add QR scanner to the send page (lazy-loaded decoder)Adam Soltys2026-06-231-0/+7
| | | | | | | | | | | | | | | | | | | Scan a Bitcoin address, a BIP21 URI (fills address + amount), or a signed-transaction QR (opens a broadcast confirmation, then relays it) from a viewfinder button on the Send form. Decoder strategy keeps the main bundle small: - Prefer the native BarcodeDetector (Chrome desktop/Android) — no lib. - Otherwise lazy-load jsQR from a separate dist/jsqr.js, only when the scanner is opened. jsQR stays out of index.html (~424 KB vs ~551 KB) and off the initial load. - The service worker precaches jsqr.js so offline scanning works for installed PWAs on browsers without BarcodeDetector. The scanner needs a camera + secure context, so it never shows on a standalone file:// page; offline air-gapped signing is unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
* Make How it works copy more human; tidy passphrase fieldAdam Soltys2026-06-211-2/+1
| | | | | | | | | | | | | - Rewrite the How it works page in a plainer, less generated voice; drop the intro lead, the receive/send paragraph, and trim the rest. - Fix passphrase wording: "13th word" (12-word phrase), not 25th. - genIntro: "It's" instead of "It is". - Unlock screen: label the field "Passphrase" (was "Optional passphrase") and drop the "leave blank if unused" placeholder. - Remove now-unused hiwLead / optionalPassphrase / leaveBlank keys and the .lead style. Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>