diff --git a/.gitignore b/.gitignore
index e3f3986..fe7feff 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,4 +22,5 @@ dist-ssr
*.njsproj
*.sln
*.sw?
-REFERENCE
\ No newline at end of file
+REFERENCE
+.Ref
\ No newline at end of file
diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md
deleted file mode 100644
index 05655b7..0000000
--- a/DEVELOPMENT.md
+++ /dev/null
@@ -1,291 +0,0 @@
-Here's your `DEVELOPMENT.md`:
-
-```markdown
-# Development Guide - SeedPGP v1.4.4
-
-## Architecture Quick Reference
-
-### Core Types
-
-```typescript
-// src/lib/types.ts
-interface SeedPgpPlaintext {
- v: number; // Version (always 1)
- t: string; // Type ("bip39")
- w: string; // Mnemonic words (normalized)
- l: string; // Language ("en")
- pp: number; // BIP39 passphrase used? (0 or 1)
- fpr?: string[]; // Optional recipient fingerprints
-}
-
-interface ParsedSeedPgpFrame {
- kind: "single"; // Frame type
- crc16: string; // 4-digit hex checksum
- b45: string; // Base45 payload
-}
-```
-
-### Frame Format
-
-```
-SEEDPGP1:0:ABCD:BASE45DATA
-
-SEEDPGP1 - Protocol identifier + version
-0 - Frame number (single frame)
-ABCD - CRC16-CCITT-FALSE checksum (4 hex digits)
-BASE45 - Base45-encoded PGP binary message
-```
-
-### Key Functions
-
-#### Encryption Flow
-```typescript
-buildPlaintext(mnemonic, bip39PassphraseUsed, recipientFingerprints?)
- → SeedPgpPlaintext
-
-encryptToSeedPgp({ plaintext, publicKeyArmored?, messagePassword? })
- → { framed: string, pgpBytes: Uint8Array, recipientFingerprint?: string }
-```
-
-#### Decryption Flow
-```typescript
-decryptSeedPgp({ frameText, privateKeyArmored?, privateKeyPassphrase?, messagePassword? })
- → SeedPgpPlaintext
-
-frameDecodeToPgpBytes(frameText)
- → Uint8Array (with CRC16 validation)
-```
-
-#### Encoding/Decoding
-```typescript
-frameEncode(pgpBinary: Uint8Array) → "SEEDPGP1:0:CRC16:BASE45"
-frameParse(text: string) → ParsedSeedPgpFrame
-frameDecodeToPgpBytes(frameText: string) → Uint8Array
-```
-
-### Dependencies
-
-```json
-{
- "openpgp": "^6.3.0", // PGP encryption (curve25519Legacy)
- "bun-types": "latest", // Bun runtime types
- "react": "^18.x", // UI framework
- "vite": "^5.x" // Build tool
-}
-```
-
-### OpenPGP.js v6 Quirks
-
-⚠️ **Important compatibility notes:**
-
-1. **Empty password array bug**: Never pass `passwords: []` to `decrypt()`. Only include if non-empty:
- ```typescript
- if (msgPw) {
- decryptOptions.passwords = [msgPw];
- }
- ```
-
-2. **Curve naming**: Use `curve25519Legacy` (not `curve25519`) in `generateKey()`
-
-3. **Key validation**: Always call `getEncryptionKey()` to verify public key has usable subkeys
-
-## Project Structure
-
-```
-seedpgp-web/
-├── src/
-│ ├── lib/
-│ │ ├── seedpgp.ts # Core encrypt/decrypt logic
-│ │ ├── seedpgp.test.ts # Test vectors (15 tests)
-│ │ ├── base45.ts # Base45 encoder/decoder
-│ │ ├── crc16.ts # CRC16-CCITT-FALSE
-│ │ └── types.ts # TypeScript interfaces
-│ ├── App.tsx # React UI entry
-│ └── main.tsx # Vite bootstrap
-├── package.json
-├── tsconfig.json
-├── vite.config.ts
-├── README.md
-└── DEVELOPMENT.md # This file
-```
-
-## Development Workflow
-
-### Running Tests
-
-```bash
-# All tests
-bun test
-
-# Watch mode
-bun test --watch
-
-# Verbose output
-bun test --verbose
-```
-
-### Development Server
-
-```bash
-bun run dev # Start Vite dev server
-bun run build # Production build
-bun run preview # Preview production build
-```
-
-### Adding Features
-
-1. **Write tests first** in `seedpgp.test.ts`
-2. **Implement in** `src/lib/seedpgp.ts`
-3. **Update types** in `types.ts` if needed
-4. **Run full test suite**: `bun test`
-5. **Commit with conventional commits**: `feat: add QR generation`
-
-## Feature Agenda
-
-### 🚧 v1.2.0 - QR Code Round-Trip
-
-**Goal**: Read back QR code and decrypt with user-provided credentials
-
-**Tasks**:
-- [ ] Add QR code generation from `encrypted.framed`
- - Library: `qrcode` or `qr-code-styling`
- - Input: SEEDPGP1 frame string
- - Output: QR code image/canvas/SVG
-
-- [ ] Add QR code scanner UI
- - Library: `html5-qrcode` or `jsqr`
- - Camera/file upload input
- - Parse scanned text → `frameText`
-
-- [ ] Build decrypt UI form
- - Input fields:
- - Scanned QR text (auto-filled)
- - Private key (file upload or paste)
- - Key passphrase (password input)
- - OR message password (alternative)
- - Call `decryptSeedPgp()`
- - Display recovered mnemonic + metadata
-
-- [ ] Add visual feedback
- - CRC16 validation status
- - Key fingerprint match indicator
- - Decryption success/error states
-
-**API Usage**:
-```typescript
-// Generate QR
-import QRCode from 'qrcode';
-const { framed } = await encryptToSeedPgp({ ... });
-const qrDataUrl = await QRCode.toDataURL(framed);
-
-// Scan and decrypt
-const scannedText = "SEEDPGP1:0:ABCD:..."; // from scanner
-const decrypted = await decryptSeedPgp({
- frameText: scannedText,
- privateKeyArmored: userKey,
- privateKeyPassphrase: userPassword,
-});
-console.log(decrypted.w); // Recovered mnemonic
-```
-
-**Security Notes**:
-- Never log decrypted mnemonics in production
-- Clear sensitive data from memory after use
-- Validate CRC16 before attempting decrypt
-- Show key fingerprint for user verification
-
----
-
-### 🔮 Future Ideas (v1.3+)
-
-- [ ] Multi-frame support (for larger payloads)
-- [ ] Password-only (SKESK) encryption flow
-- [ ] Shamir Secret Sharing integration
-- [ ] Hardware wallet key generation
-- [ ] Mobile companion app (React Native)
-- [ ] Printable paper backup templates
-- [ ] Encrypted cloud backup with PBKDF2
-- [ ] BIP85 child mnemonic derivation
-
-## Debugging Tips
-
-### Enable verbose PGP logging
-
-Uncomment in `seedpgp.ts`:
-```typescript
-console.log("Raw PGP hex:", Array.from(pgpBytes).map(...));
-console.log("SeedPGP: message packets:", ...);
-console.log("SeedPGP: encryption key IDs:", ...);
-```
-
-### Test with known vectors
-
-Use Trezor vectors from test file:
-```bash
-bun test "Trezor" # Run only Trezor tests
-```
-
-### Validate frame manually
-
-```typescript
-import { frameParse } from "./lib/seedpgp";
-const parsed = frameParse("SEEDPGP1:0:ABCD:...");
-console.log(parsed); // Check structure
-```
-
-## Code Style
-
-- **Functions**: Async by default, explicit return types
-- **Errors**: Throw descriptive Error objects with context
-- **Naming**: `camelCase` for functions, `PascalCase` for types
-- **Comments**: Only for non-obvious crypto/encoding logic
-- **Testing**: One test per edge case, descriptive names
-
-## Git Workflow
-
-```bash
-# Feature branch
-git checkout -b feat/qr-generation
-
-# Conventional commits
-git commit -m "feat(qr): add QR code generation"
-git commit -m "test(qr): add QR round-trip test"
-
-# Tag releases
-git tag -a v1.2.0 -m "Release v1.2.0 - QR round-trip"
-git push origin main --tags
-```
-
-## Questions for Next Session
-
-When continuing development, provide:
-
-1. **Feature context**: "Adding QR code generation for v1.2.0"
-2. **Current code**: Paste relevant files you're modifying
-3. **Specific question**: "How should I structure the QR scanner component?"
-
-Example starter prompt:
-```
-I'm working on seedpgp-web v1.1.0 (BIP39 PGP encryption tool).
-
-[Paste this DEVELOPMENT.md section]
-[Paste relevant source files]
-
-I want to add QR code generation. Here's my current seedpgp.ts...
-```
-
----
-
-**Last Updated**: 2026-01-28
-**Maintainer**: @kccleoc
-```
-
-Now commit it:
-
-```bash
-git add DEVELOPMENT.md
-git commit -m "docs: add development guide with v1.2.0 QR agenda"
-git push origin main
-```
-
-Ready for your next feature sprint! 🚀📋
diff --git a/public/README.md b/public/README.md
deleted file mode 100644
index 84fcad4..0000000
--- a/public/README.md
+++ /dev/null
@@ -1,121 +0,0 @@
-# SeedPGP Web App
-
-**Secure BIP39 mnemonic backup tool using OpenPGP encryption**
-
-🔗 **Live App**: https://kccleoc.github.io/seedpgp-web-app/
-
-## About
-
-Client-side web application for encrypting cryptocurrency seed phrases (BIP39 mnemonics) using OpenPGP encryption with QR code generation and scanning capabilities.
-
-### ✨ Features
-
-- 🔐 **OpenPGP Encryption** - Curve25519Legacy (cv25519) encryption
-- 📱 **QR Code Generation** - High-quality 512x512px PNG with download
-- 📸 **QR Code Scanner** - Camera or image upload with live preview
-- 🔄 **Round-trip Flow** - Encrypt → QR → Scan → Decrypt seamlessly
-- ✅ **BIP39 Support** - 12/18/24-word mnemonics with optional passphrase
-- 🔒 **Symmetric Encryption** - Optional password-only encryption (SKESK)
-- 🎯 **CRC16 Validation** - Frame integrity checking
-- 📦 **Base45 Encoding** - Compact QR-friendly format (RFC 9285)
-- 🌐 **100% Client-Side** - No backend, no data transmission
-
-## 🔒 Security Notice
-
-⚠️ **Your private keys and seed phrases never leave your browser**
-
-- Static web app with **no backend server**
-- All cryptographic operations run **locally in your browser**
-- **No data transmitted** to any server
-- Camera access requires **HTTPS or localhost**
-- Always verify you're on the correct URL before use
-
-### For Maximum Security
-
-For production use with real funds:
-- 🏠 Download and run locally (\`bun run dev\`)
-- 🔐 Use on airgapped device
-- 📥 Self-host on your own domain
-- 🔍 Source code: https://github.com/kccleoc/seedpgp-web (private)
-
-## 📖 How to Use
-
-### Backup Flow
-1. **Enter** your 12/24-word BIP39 mnemonic
-2. **Add** PGP public key and/or message password (optional)
-3. **Generate** encrypted QR code
-4. **Download** or scan QR code for backup
-
-### Restore Flow
-1. **Scan QR Code** using camera or upload image
-2. **Provide** private key and/or message password
-3. **Decrypt** to recover your mnemonic
-
-### QR Scanner Features
-- 📷 **Camera Mode** - Live scanning with environment camera (iPhone Continuity Camera supported on macOS)
-- 📁 **Upload Mode** - Scan from saved images or screenshots
-- ✅ **Auto-validation** - Verifies SEEDPGP1 format before accepting
-
-## 🛠 Technical Stack
-
-- **TypeScript** - Type-safe development
-- **React 18** - Modern UI framework
-- **Vite 6** - Lightning-fast build tool
-- **OpenPGP.js v6** - RFC 4880 compliant encryption
-- **html5-qrcode** - QR scanning library
-- **TailwindCSS** - Utility-first styling
-- **Lucide React** - Beautiful icons
-
-## 📋 Protocol Format
-
-\`\`\`
-SEEDPGP1:0:ABCD:BASE45DATA
-
-SEEDPGP1 - Protocol identifier + version
-0 - Frame number (single frame)
-ABCD - CRC16-CCITT-FALSE checksum
-BASE45 - Base45-encoded OpenPGP binary message
-\`\`\`
-
-## 🔐 Encryption Details
-
-- **Algorithm**: AES-256 (preferred symmetric cipher)
-- **Curve**: Curve25519Legacy for modern security
-- **Key Format**: OpenPGP RFC 4880 compliant
-- **Error Correction**: QR Level M (15% recovery)
-- **Integrity**: CRC16-CCITT-FALSE frame validation
-
-## 📱 Browser Compatibility
-
-- ✅ Chrome/Edge (latest)
-- ✅ Safari 16+ (macOS/iOS)
-- ✅ Firefox (latest)
-- 📷 Camera requires HTTPS or localhost
-
-## 📦 Version
-
-**Current deployment: v1.2.0**
-
-### Changelog
-
-#### v1.2.0 (2026-01-29)
-- ✨ Added QR scanner with camera/upload support
-- 📥 Added QR code download with auto-naming
-- 🔧 Split state for backup/restore tabs
-- 🎨 Improved QR generation quality
-- 🐛 Fixed Safari camera permissions
-- 📱 Added Continuity Camera support
-
-#### v1.1.0 (2026-01-28)
-- 🎉 Initial public release
-- 🔐 OpenPGP encryption/decryption
-- 📱 QR code generation
-- ✅ BIP39 validation
-
----
-
-**Last updated**: 2026-01-29
-
-**Built with** ❤️ using TypeScript, React, Vite, and OpenPGP.js
-
-**License**: Private source code - deployment only
diff --git a/public/_headers b/public/_headers
deleted file mode 100644
index 146475c..0000000
--- a/public/_headers
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
- Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; connect-src 'none'; form-action 'none'; base-uri 'self';
- X-Frame-Options: DENY
- X-Content-Type-Options: nosniff
- X-XSS-Protection: 1; mode=block
- Referrer-Policy: strict-origin-when-cross-origin
diff --git a/public/vite.svg b/public/vite.svg
deleted file mode 100644
index e7b8dfb..0000000
--- a/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/src/components/SeedBlender.tsx b/src/components/SeedBlender.tsx
index c2dfc78..07713b9 100644
--- a/src/components/SeedBlender.tsx
+++ b/src/components/SeedBlender.tsx
@@ -161,7 +161,6 @@ export function SeedBlender({ onDirtyStateChange, setMnemonicForBackup, requestT
const handleScanSuccess = useCallback(async (scannedData: string | Uint8Array) => {
if (scanTargetIndex === null) return;
- // Convert binary data to hex string if necessary
const scannedText = typeof scannedData === 'string'
? scannedData
: Array.from(scannedData).map(b => b.toString(16).padStart(2, '0')).join('');
diff --git a/src/lib/seedpgp.ts b/src/lib/seedpgp.ts
index 4cd3b3a..0bfcbe4 100644
--- a/src/lib/seedpgp.ts
+++ b/src/lib/seedpgp.ts
@@ -2,6 +2,7 @@ import * as openpgp from "openpgp";
import { base45Encode, base45Decode } from "./base45";
import { crc16CcittFalse } from "./crc16";
import { encryptToKrux, decryptFromKrux } from "./krux";
+import { decodeSeedQR } from './seedqr';
import type {
SeedPgpPlaintext,
ParsedSeedPgpFrame,
@@ -302,6 +303,25 @@ export async function decryptFromSeed(params: DecryptionParams): Promise