/* Bitcoin Wallet — hand-rolled CSS. Clean light "paper wallet" look. */ :root { --bg: #eef0f3; --paper: #ffffff; --ink: #15171a; --muted: #6b7280; --faint: #9aa1ac; --line: #e6e8ec; --line-strong: #d4d8de; --accent: #15171a; /* coinos black */ --accent-hover: #2c3037; /* accent, slightly lifted */ --accent-fg: #ffffff; /* text on accent */ --accent-ink: #000000; --accent-soft: #ececef; --green: #14935a; --green-soft: #e7f6ee; --green-line: #c4e7d4; --red: #c43b3b; --red-soft: #fbeaea; --shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 10px 30px rgba(16, 24, 40, 0.07); --surface2: #f7f8fa; /* subtle raised surface (hover, mnemonic cells) */ --toast-bg: #15171a; /* dark toast on light page */ --toast-fg: #ffffff; --tab-bg: #ffffff; /* tab strip: paper, like the flat cards beside it */ --tab-border: var(--line); --tab-active: #ececef; /* the chosen tab: a quiet grey pill, no shadow */ --info: #3949ab; --info-soft: #eef2ff; --info-line: #d4ddfb; --radius: 16px; --wash: rgba(247, 147, 26, 0.05); /* warm glow behind the page top */ --mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace; --sans: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } /* Dark theme — applied via data-theme="dark" on . */ :root[data-theme="dark"] { --bg: #0f1216; --paper: #181b21; --ink: #e7e9ee; --muted: #9aa1ac; --faint: #6f7782; --line: #2a2f37; --line-strong: #3a414b; --accent: #ffffff; /* coinos white on dark */ --accent-hover: #d9dce1; /* accent, slightly dimmed */ --accent-fg: #0f1216; /* text on accent */ --accent-ink: #e7e9ee; --accent-soft: #262b33; --green: #2dbd80; --green-soft: #14271d; --green-line: #235340; --red: #e66a6a; --red-soft: #2c1a1a; --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 30px rgba(0, 0, 0, 0.5); --surface2: #20242b; --toast-bg: #2c323b; /* raised toast that reads against the dark page */ --toast-fg: #f3f5f8; --tab-bg: #20242b; --tab-border: transparent; --tab-active: var(--paper); --wash: rgba(247, 147, 26, 0.07); --info: #9db4ff; --info-soft: #1a2030; --info-line: #2c3a5e; } * { box-sizing: border-box; } html { /* Reserve the scrollbar's gutter always, so it doesn't appear the instant the history list fills the page and shrink the viewport — that width change re-centered the balance carousel's snapped card, the "slight move one last time" after a switch. Stable gutter = no reflow when content grows. */ scrollbar-gutter: stable; } html, body { margin: 0; padding: 0; background: var(--bg); color: var(--ink); font-family: var(--sans); -webkit-font-smoothing: antialiased; font-size: 16px; line-height: 1.45; } #app { max-width: 560px; margin: 0 auto; padding: 24px 16px 24px; /* A column the height of the window, so the footer sits at the bottom of short screens instead of floating under the content. svh, not dvh: dvh can resolve to the tall viewport (URL bar hidden) at first paint, which puts the footer just below the fold until you scroll — the phone browser showing its address bar is the case that has to fit. */ min-height: 100vh; min-height: 100svh; display: flex; flex-direction: column; } /* ---- typography ---- */ h1, h2, h3 { margin: 0; font-weight: 650; letter-spacing: -0.01em; } .muted { color: var(--muted); } .faint { color: var(--faint); } .small { font-size: 13px; } /* The reading size for a post or a message — the copy you actually read, as opposed to a caption or a row subtitle, which is what .small is for. Post bodies wore .small (13px) and a feed of them read like footnotes on a phone. 16px is Amethyst's own default for a note body, and at the inherited 1.45 line-height the line pitch lands within a pixel of what Amethyst renders. Measured on a Pixel 9, side by side. */ .note-text { font-size: 16px; } .mono { font-family: var(--mono); } .center { text-align: center; } .break { word-break: break-all; } a { color: var(--accent-ink); text-decoration: none; } a:hover { text-decoration: underline; } summary { cursor: pointer; } /* breathing room when an input is scrolled to the top for the keyboard */ input { scroll-margin-top: 12px; } /* room below the recipient candidates so the field can scroll to the top even when the page would otherwise be too short (the margin sits under the keyboard, never seen) */ @media (pointer: coarse) { .send-suggest { margin-bottom: 45vh; } } /* ---- layout helpers ---- */ .row { display: flex; align-items: center; gap: 10px; } .between { justify-content: space-between; } .wrap { flex-wrap: wrap; } .col { display: flex; flex-direction: column; gap: 10px; } .grow { flex: 1; } .gap6 { gap: 6px; } .mt8 { margin-top: 8px; } .mt16 { margin-top: 16px; } .mt24 { margin-top: 24px; } .hidden { display: none !important; } /* ---- brand / header ---- */ .brand { display: flex; align-items: center; gap: 10px; } .logo-full { height: 40px; flex: none; color: var(--ink); display: grid; place-items: center; } .logo-full svg { height: 40px; width: auto; display: block; } .brand h1 { font-size: 19px; } .badge { font-size: 12px; font-weight: 600; padding: 3px 9px; border-radius: 999px; border: 1px solid var(--line-strong); color: var(--muted); white-space: nowrap; } .badge.dot::before { content: ""; display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--green); margin-right: 6px; vertical-align: middle; } .badge.off.dot::before { background: var(--faint); } .badge.live { color: var(--green); border-color: var(--green-line); background: var(--green-soft); } .badge.live.dot::before { animation: pulse 1.5s ease-in-out infinite; } @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .3; } } .badge.testnet { color: var(--accent-ink); border-color: var(--accent); background: var(--accent-soft); } /* ---- card ---- */ .card { background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: 20px; } .card + .card { margin-top: 16px; } /* ---- balance card ---- */ /* Account identity at a glance: a symbol beside the label and a colored hairline across the card's crown — spending wears lightning + the ark mark (violet), savings the bitcoin disc (orange). Inset shadow stacks with the card's own and clips to the radius; no layout shift. */ .face-ico { display: inline-flex; align-items: center; gap: 3px; font-size: 12px; line-height: 1; flex-shrink: 0; } .face-ico.save { color: #f7931a; } .face-ico.spend { color: #7c3aed; } /* No drop shadow on the balance cards: it smeared as they slid and sat oddly against the Receive/Send bar beneath. The colour stripe stays. */ .balance, .history-card { box-shadow: none; } .balance.face-spending { box-shadow: inset 0 3px 0 rgba(124, 58, 237, .55); } .balance.face-savings { box-shadow: inset 0 3px 0 rgba(247, 147, 26, .6); } .balance .amt { font-size: 34px; font-weight: 700; letter-spacing: -0.02em; font-family: var(--mono); } .balance .amt .unit { font-size: 18px; color: var(--muted); margin-left: 6px; font-weight: 600; } .balance .usd { color: var(--muted); margin-top: 2px; } .balance .split { margin-top: 14px; display: flex; gap: 22px; } .balance .split .k { font-size: 12px; color: var(--faint); text-transform: uppercase; letter-spacing: .04em; } .balance .split .v { font-family: var(--mono); font-size: 14px; } .balance .split .v.pending { color: var(--accent-ink); } /* ---- tabs ---- */ .page-pick { width: auto; padding: 6px 28px 6px 10px; font-size: 13px; border-radius: 9px; background-color: var(--paper); } .tabs { display: flex; gap: 4px; background: var(--tab-bg); border: 1px solid var(--tab-border); border-radius: 12px; padding: 4px; margin: 16px 0; } .tabs button { flex: 1; border: 0; background: transparent; padding: 9px 4px; border-radius: 9px; font: inherit; font-weight: 600; font-size: 14px; color: var(--muted); cursor: pointer; } .tabs button.active { background: var(--tab-active); color: var(--ink); } /* ---- buttons ---- */ button, .btn { font: inherit; font-weight: 600; cursor: pointer; border-radius: 11px; border: 1px solid var(--line-strong); background: var(--paper); color: var(--ink); padding: 11px 16px; transition: filter .12s, background .12s, border-color .12s; /* no double-tap-zoom arbitration: taps commit immediately on mobile */ touch-action: manipulation; } button:hover { background: var(--surface2); } button:active { transform: translateY(1px); } button:disabled { opacity: .5; cursor: not-allowed; } .btn-primary { background: var(--accent); border-color: var(--accent); color: var(--accent-fg); } .btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); } .btn-ghost { background: transparent; } .btn-sm { padding: 7px 11px; font-size: 13px; border-radius: 9px; } .btn-block { width: 100%; display: block; } .btn-danger { color: var(--red); border-color: var(--red); background: var(--red-soft); } .iconbtn { padding: 9px 11px; line-height: 1; } /* ---- inputs ---- */ label.field { display: block; } .field .lab { font-size: 13px; font-weight: 600; color: var(--muted); margin-bottom: 6px; display: block; } input[type=text], input[type=password], input[type=number], textarea, select { width: 100%; font: inherit; color: var(--ink); background: var(--paper); border: 1px solid var(--line-strong); border-radius: 11px; padding: 11px 13px; } input:focus, textarea:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); } /* Custom caret so it isn't crammed against the right border (native is fixed). */ select { -webkit-appearance: none; appearance: none; padding-right: 38px; background-image: url('data:image/svg+xml;utf8,'); background-repeat: no-repeat; background-position: right 14px center; } textarea { resize: vertical; min-height: 84px; font-family: var(--mono); font-size: 15px; } .mono-input { font-family: var(--mono); } .input-group { display: flex; gap: 8px; } .input-group input { flex: 1; } /* unit toggle */ .seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 10px; overflow: hidden; } .seg button { border: 0; border-radius: 0; padding: 9px 14px; background: var(--paper); } .seg button.active { background: var(--accent-soft); color: var(--accent-ink); } /* ---- address / qr ---- */ .qr { width: 220px; height: 220px; display: block; border-radius: 12px; border: 1px solid var(--line); } .addr-box { font-family: var(--mono); font-size: 15px; color: var(--ink); background: var(--surface2); border: 1px dashed var(--line-strong); border-radius: 11px; padding: 12px 14px; word-break: break-all; text-align: center; } /* quiet edit/copy affordances living inside the address box */ .addr-editable { position: relative; padding-right: 62px; } .addr-actions { position: absolute; right: 4px; top: 50%; transform: translateY(-50%); display: flex; align-items: center; } .addr-actions button { background: none; border: none; box-shadow: none; padding: 5px; line-height: 0; color: var(--muted); cursor: pointer; } .addr-actions button:hover { color: var(--ink); background: none; } .addr-actions button:active { transform: none; } .path { font-family: var(--mono); font-size: 12px; color: var(--faint); } .addr-check { font-family: var(--mono); font-size: 12px; line-height: 1.5; color: var(--muted); word-break: break-all; padding: 0 2px; } .addr-check .hl { color: var(--ink); font-weight: 700; } /* ---- mnemonic grid ---- */ /* Three columns read ACROSS — 1 2 3 on the first line, 4 5 6 on the next — the way a printed sheet is read. Two columns (a phone) run DOWN instead, the way a hand copies a list: the first column is 1–6, not 1,3,5,…; that row count comes from the word count (--rows-2, set inline). */ .words { display: grid; grid-auto-flow: row; grid-template-columns: repeat(3, 1fr); gap: 8px; } .words .w { display: flex; align-items: baseline; gap: 7px; background: var(--surface2); border: 1px solid var(--line); border-radius: 10px; padding: 9px 11px; font-family: var(--mono); } .words .w .n { color: var(--faint); font-size: 12px; width: 18px; text-align: right; } .words .w .t { font-weight: 600; } .warn-box { background: var(--accent-soft); border: 1px solid var(--accent); color: var(--accent-ink); border-radius: 11px; padding: 12px 14px; font-size: 14px; } /* ---- lists (tx / utxo) ---- */ .list { display: flex; flex-direction: column; } .item { display: flex; align-items: center; gap: 12px; padding: 13px 2px; border-top: 1px solid var(--line); } .item:first-child { border-top: 0; } .ico { width: 34px; height: 34px; border-radius: 9px; flex: none; display: grid; place-items: center; font-size: 16px; } .ico.in { background: var(--green-soft); color: var(--green); } .ico.out { background: var(--red-soft); color: var(--red); } .amount-pos { color: var(--green); font-family: var(--mono); font-weight: 600; } .amount-neg { color: var(--red); font-family: var(--mono); font-weight: 600; } .amount { font-family: var(--mono); font-weight: 600; } .tag { font-size: 11px; font-weight: 700; padding: 2px 7px; border-radius: 6px; } .tag.pending { background: var(--accent-soft); color: var(--accent-ink); } .tag.conf { background: var(--green-soft); color: var(--green); } /* coin control rows */ .coin { display: flex; align-items: center; gap: 11px; padding: 11px 2px; border-top: 1px solid var(--line); } .coin:first-child { border-top: 0; } .coin input[type=checkbox] { width: 18px; height: 18px; accent-color: var(--accent); } /* the Spending coins table: labels once in the header, numbers right- aligned in tabular figures; on a narrow screen the WRAPPER scrolls sideways so the page itself never does */ .coin-scroll { overflow-x: auto; margin: 4px -2px 0; -webkit-overflow-scrolling: touch; } .coin-table { border-collapse: collapse; width: 100%; font-size: 13.5px; white-space: nowrap; } .coin-table th { text-align: left; font-weight: 600; font-size: 12px; color: var(--muted); padding: 4px 5px 8px; border-bottom: 1px solid var(--line-strong); } .coin-table td { padding: 10px 5px; border-top: 1px solid var(--line); vertical-align: middle; } .coin-table tbody tr:first-child td { border-top: 0; } .coin-table th:first-child, .coin-table td:first-child { width: 22px; padding-left: 2px; padding-right: 2px; } .coin-table .num { text-align: right; font-variant-numeric: tabular-nums; } .coin-table td.warn { color: var(--accent-ink); font-weight: 600; } .coin-table tr.clickable { cursor: pointer; } .coin-table input[type=checkbox] { width: 18px; height: 18px; accent-color: var(--accent); margin: 0; display: block; } /* ---- review / summary ---- */ .summary { background: var(--surface2); border: 1px solid var(--line); border-radius: 12px; padding: 14px; } .summary .line { display: flex; justify-content: space-between; gap: 12px; padding: 5px 0; font-size: 14px; align-items: baseline; } .summary .line .k { color: var(--muted); flex: none; } .summary .line .v { font-family: var(--mono); text-align: right; min-width: 0; word-break: break-word; } /* ---- misc ---- */ .notice { border-radius: 11px; padding: 11px 13px; font-size: 14px; } .notice.err { background: var(--red-soft); color: var(--red); border: 1px solid #f1c9c9; } .notice.ok { background: var(--green-soft); color: var(--green); border: 1px solid var(--green-line); } .notice.info { background: var(--info-soft); color: var(--info); border: 1px solid var(--info-line); } .spinner { width: 18px; height: 18px; border: 2px solid var(--line-strong); border-top-color: var(--accent); border-radius: 50%; animation: spin .7s linear infinite; display: inline-block; vertical-align: middle; } .spinner.sm { width: 13px; height: 13px; border-width: 2px; } /* ---- qr scanner overlay ---- */ .scan-overlay { position: fixed; inset: 0; z-index: 60; background: #000; display: flex; align-items: center; justify-content: center; overflow: hidden; } .scan-overlay video { width: 100%; height: 100%; object-fit: cover; } .scan-frame { position: absolute; width: min(70vw, 260px); height: min(70vw, 260px); border: 3px solid #fff; border-radius: 18px; box-shadow: 0 0 0 9999px rgba(0,0,0,0.45); } .scan-hint { position: absolute; bottom: 70px; left: 0; right: 0; text-align: center; color: #fff; font-size: 14px; padding: 0 24px; text-shadow: 0 1px 3px rgba(0,0,0,0.7); } .scan-close { position: absolute; top: 16px; right: 16px; width: 42px; height: 42px; border-radius: 50%; background: rgba(0,0,0,0.5); color: #fff; border: 1px solid rgba(255,255,255,0.4); font-size: 18px; line-height: 1; cursor: pointer; /* the base button rule's 11px/16px padding shoved the glyph off-center inside this fixed circle — center it properly and drop the padding */ display: flex; align-items: center; justify-content: center; padding: 0; } @keyframes spin { to { transform: rotate(360deg); } } .toast { position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%); background: var(--toast-bg); color: var(--toast-fg); padding: 10px 16px; border-radius: 10px; font-size: 14px; box-shadow: var(--shadow); z-index: 50; opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s; } .toast.show { opacity: 1; transform: translateX(-50%) translateY(0); } .words .w.masked .t { color: var(--faint); letter-spacing: 2px; } .check-badge { width: 64px; height: 64px; border-radius: 50%; flex: none; background: var(--green-soft); color: var(--green); display: grid; place-items: center; font-size: 34px; font-weight: 700; } .footer { margin-top: auto; padding-top: 28px; padding-bottom: 8px; } .footer a { color: var(--accent-ink); font-weight: 600; } /* Clickable unit labels (BTC/sats) — look like text, toggle the global unit. */ .unit-tag { background: none; border: 0; padding: 0; margin: 0; font: inherit; cursor: pointer; color: var(--muted); font-weight: 600; border-radius: 0; border-bottom: 1px dotted var(--line-strong); } .unit-tag:hover { background: none; color: var(--accent-ink); border-bottom-color: var(--accent); } .unit-tag:active { transform: none; } .divider { height: 1px; background: var(--line); margin: 16px 0; border: 0; } hr.divider { margin: 16px 0; } .linklike { background: none; border: 0; padding: 0; color: var(--accent-ink); font-weight: 600; cursor: pointer; } .linklike:hover { text-decoration: underline; background: none; } /* ---- how it works ---- */ @media (max-width: 420px) { .words { grid-auto-flow: column; grid-template-columns: none; grid-auto-columns: 1fr; grid-template-rows: repeat(var(--rows-2, 6), auto); } .balance .amt { font-size: 28px; } } /* Icon dropdown (receive mode) — a