Skip to content

feat(binary-codec): Binary V3 codec + Invoice schema refactoring#2

Merged
ignromanov merged 12 commits into
masterfrom
007-binary-codec
Dec 30, 2025
Merged

feat(binary-codec): Binary V3 codec + Invoice schema refactoring#2
ignromanov merged 12 commits into
masterfrom
007-binary-codec

Conversation

@ignromanov
Copy link
Copy Markdown
Owner

@ignromanov ignromanov commented Dec 24, 2025

Summary

This PR implements the Binary V3 codec for invoice URL compression and refactors the invoice schema for better readability.

Binary Codec V3

  • feat(binary-codec): implement optimized URL encoding with pako compression
  • docs(binary-codec): add comprehensive technical documentation
  • feat(invoice-codec): integrate Binary V3 with hash fragment URLs
  • chore(binary-codec): remove V1/V2, keep only V3

Invoice Schema Refactoring

  • refactor(invoice): rename schema fields to readable names + add taxId
    • vversion, idinvoiceId, ississuedAt, duedueAt
    • netnetworkId, curcurrency, ttokenAddress
    • ffrom, cclient, ititems
    • Added taxId field for counterparties
  • refactor(invoice): migrate to InvoiceSchemaV2 with version: 2

CreatorStore Migration

  • refactor(creator): unify Invoice type, add DraftState, migrate CreatorStore
    • Remove InvoiceDraft, use DraftState (meta + Partial<Invoice>)
    • Add separate LineItem[] for React key management
    • Rename: recipient→client, sender→from, chainId→networkId
    • Convert dates: ISO strings to Unix timestamps

Cleanup

  • chore: remove specs from code repo (moved to .ai)

Files Changed

50 files changed, +2608 / -897 lines

Breaking Changes

  • Invoice schema fields renamed (MVP, no production URLs)
  • CreatorStore schema changed (auto-migrated)
  • Binary codec V1/V2 removed (MVP, no production users)

Test plan

  • pnpm type-check passes
  • pnpm lint passes
  • pnpm test passes
  • Manual: Create invoice, verify LocalStorage migration works
  • Manual: Generate invoice URL and decode — verify roundtrip

🤖 Generated with Claude Code

@vercel
Copy link
Copy Markdown

vercel Bot commented Dec 24, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
voidpay Ready Ready Preview, Comment Dec 30, 2025 5:56am

ignromanov and others added 3 commits December 29, 2025 23:06
…ssion

- Add binary codec library with base62 encoding for URL-safe output
- Implement encoder/decoder v1, v2, v3 with progressive optimizations
- Add dictionary-based compression for common invoice fields
- Add pako for gzip compression (better ratio than lz-string)
- Include /compare page for testing compression strategies
- Add invoice generator test utilities

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Visual documentation covering:
- Architecture overview with ASCII diagrams
- Compression pipeline (V1 → V2 → V3)
- Binary format specification with byte layouts
- Data type transformations (UUID, Address, VarInt)
- Dictionary system for currencies/tokens
- Benchmarks showing 2-3x capacity improvement

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
P0.15.6 Invoice Schema Field Renaming

BREAKING CHANGE: All InvoiceSchemaV1 field names changed from abbreviated
to human-readable format. Old URLs will not decode.

Field renames:
- v → version
- id → invoiceId
- iss → issuedAt
- due → dueAt
- nt → notes
- net → networkId
- cur → currency
- t → tokenAddress
- dec → decimals
- f → from
- c → client
- it → items
- dsc → discount

Nested party fields (from/client):
- n → name
- a → walletAddress
- e → email
- ads → physicalAddress
- ph → phone
- NEW: taxId (optional)

Nested item fields:
- d → description
- q → quantity
- r → rate

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update encode.ts to use Binary V3 encoder with hash fragments (#)
- Update decode.ts to use Binary V3 decoder
- Fix encoder/decoder to treat invoiceId as user string (not UUID)
- Add OG preview encoder/decoder for social sharing
- Add useHashFragment hook for SSR-safe hash reading
- Update URL format: /pay?d=... → /pay#H... (privacy-first)
- Add @deprecated to LZ-String compression functions
- Update tests for Binary V3 format and address normalization

BREAKING CHANGE: URL format changed from query params to hash fragments.
Existing URLs using ?d= will no longer work.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Rename schema.ts → schema-v2.ts
- Update interface name: InvoiceSchemaV1 → InvoiceSchemaV2
- Bump wire format version from 1 to 2
- Update all decoders (v1, v2, v3) to return version: 2
- Update validation schema to expect version: 2
- Update all tests, demo data, and invoice generator
- Breaking change: existing URLs with version: 1 will fail validation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…rStore

- Remove InvoiceDraft, use DraftState (meta + Partial<Invoice>)
- Add separate LineItem[] for React key management
- Migrate v0 (old InvoiceDraft) to v1 store with version: 2 Invoice
- Rename: recipient→client, sender→from, chainId→networkId
- Convert dates: ISO strings to Unix timestamps
- Update auto-save, generate-invoice, TemplateList

chore(binary-codec): remove V1/V2, keep only V3

- Delete encoder.ts, encoder-v2.ts, decoder.ts, decoder-v2.ts
- Update index.ts to export only V3 functions
- Remove /compare benchmark page (no longer needed)

Breaking: CreatorStore schema changed (auto-migrated)
Breaking: Binary codec V1/V2 removed (MVP, no production users)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ignromanov ignromanov changed the title feat(binary-codec): implement optimized URL encoding with pako compression refactor(creator): unify Invoice type, add DraftState, migrate CreatorStore Dec 30, 2025
@ignromanov ignromanov changed the title refactor(creator): unify Invoice type, add DraftState, migrate CreatorStore feat(binary-codec): Binary V3 codec + Invoice schema refactoring Dec 30, 2025
Specs belong in voidpay-ai repository, not voidpay code repo.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract network short codes from og-preview.ts to entities/network
following FSD principles - business constants belong in entities layer.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replaced by Binary V3 codec with 40-50% better compression.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Replace separate fields (invoiceId, recipientName, totalAmount) with `invoice: Invoice`
- Add formatInvoiceTotal() helper for display
- Update all consumers: search, sort, import, UI
- Delete unused migrations.ts
- Rewrite invoice-codec README for Binary V3

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add taxId field rendering to PartyInfo for both from/client sections
- Migrate lucide-react icons to inline SVGs (Mail, Phone, MapPin, Wallet, Hash)
- Export new icons from shared/ui for bundle optimization
- Add first:mt-0 to fix margin when wallet/address is first element
- Update demo invoices with diverse optional field combinations
- Add taxId to test mock data and new test case

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@ignromanov ignromanov merged commit bfdb554 into master Dec 30, 2025
4 checks passed
@ignromanov ignromanov deleted the 007-binary-codec branch December 30, 2025 06:16
ignromanov added a commit that referenced this pull request Mar 31, 2026
- Fix txHash #1 missing 2 hex chars (62→64 hex digits)
- Remove redundant "(40 hours)" from description where qty=40
- Change Invoice #2 discount from 8% to 5% so tax/discount don't cancel out
- Fix native token (ETH, POL) not recognized when loading invoice as template:
  spread merge didn't clear default tokenAddress when decoded data omits the key
ignromanov added a commit that referenced this pull request Apr 14, 2026
…ity (#137)

* docs: update privacy policy with Umami analytics details

Add dedicated "Product Analytics" section, add Umami to Third-Party
Services, fix misleading "Analytics or telemetry" item in
"What We Don't Collect" section.

* fix(demo): correct demo invoice data and native token template loading

- Fix txHash #1 missing 2 hex chars (62→64 hex digits)
- Remove redundant "(40 hours)" from description where qty=40
- Change Invoice #2 discount from 8% to 5% so tax/discount don't cancel out
- Fix native token (ETH, POL) not recognized when loading invoice as template:
  spread merge didn't clear default tokenAddress when decoded data omits the key

* docs: add community files, security policy, README redesign

- LICENSE (MIT)
- SECURITY.md + public/.well-known/security.txt (RFC 9116)
- CONTRIBUTING.md, CODE_OF_CONDUCT.md (Contributor Covenant v2.1)
- README.md full redesign: badges, How It Works, features, quick start
- .github/FUNDING.yml (GitHub Sponsors + Giveth)
- .github/dependabot.yml (weekly npm, monthly GHA)
- .github/pull_request_template.md
- .github/ISSUE_TEMPLATE/feature_request.md

* fix(docs): simplify PR template to match existing style

Summary + Test plan (lowercase), no generic checklist — CI handles validation.

* fix(docs): PR template with structured summary and specific test plan

Matches PR #45 style: subsections for larger PRs, concrete test checkboxes.

* ci: add Dependabot auto-merge for patch and minor updates

Auto-approve and squash-merge Dependabot PRs for patch/minor versions
after CI passes. Major version updates require manual review.

* build(deps-dev): bump tailwindcss from 4.1.18 to 4.2.2 (#70)

Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) from 4.1.18 to 4.2.2.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/tailwindcss)

---
updated-dependencies:
- dependency-name: tailwindcss
  dependency-version: 4.2.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump tailwind-merge from 3.4.0 to 3.5.0 (#62)

Bumps [tailwind-merge](https://github.com/dcastil/tailwind-merge) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/dcastil/tailwind-merge/releases)
- [Commits](https://github.com/dcastil/tailwind-merge/compare/v3.4.0...v3.5.0)

---
updated-dependencies:
- dependency-name: tailwind-merge
  dependency-version: 3.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump zustand from 5.0.9 to 5.0.12 (#68)

Bumps [zustand](https://github.com/pmndrs/zustand) from 5.0.9 to 5.0.12.
- [Release notes](https://github.com/pmndrs/zustand/releases)
- [Commits](https://github.com/pmndrs/zustand/compare/v5.0.9...v5.0.12)

---
updated-dependencies:
- dependency-name: zustand
  dependency-version: 5.0.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump lint-staged from 16.2.7 to 16.4.0 (#61)

Bumps [lint-staged](https://github.com/lint-staged/lint-staged) from 16.2.7 to 16.4.0.
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v16.2.7...v16.4.0)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-version: 16.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump viem from 2.43.4 to 2.47.6 (#63)

Bumps [viem](https://github.com/wevm/viem) from 2.43.4 to 2.47.6.
- [Release notes](https://github.com/wevm/viem/releases)
- [Commits](https://github.com/wevm/viem/compare/viem@2.43.4...viem@2.47.6)

---
updated-dependencies:
- dependency-name: viem
  dependency-version: 2.47.6
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @next/eslint-plugin-next from 16.1.1 to 16.2.1 (#69)

Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.1.1 to 16.2.1.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.2.1/packages/eslint-plugin-next)

---
updated-dependencies:
- dependency-name: "@next/eslint-plugin-next"
  dependency-version: 16.2.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump zod from 4.3.4 to 4.3.6 (#66)

Bumps [zod](https://github.com/colinhacks/zod) from 4.3.4 to 4.3.6.
- [Release notes](https://github.com/colinhacks/zod/releases)
- [Commits](https://github.com/colinhacks/zod/compare/v4.3.4...v4.3.6)

---
updated-dependencies:
- dependency-name: zod
  dependency-version: 4.3.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(github): issue templates frontmatter, dependabot auto-merge workflow

- Add name/about/title/assignees to issue templates so GitHub recognizes them
- Create config.yml disabling blank issues with security advisory link
- Replace dependabot-auto-merge.yml with simplified dependabot-automerge.yml

* build(deps-dev): bump lucide-static from 0.577.0 to 1.7.0 (#67)

Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 0.577.0 to 1.7.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/compare/0.577.0...1.7.0)

---
updated-dependencies:
- dependency-name: lucide-static
  dependency-version: 1.7.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @types/node from 22.19.3 to 25.5.0 (#65)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.3 to 25.5.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.5.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/upload-artifact from 4 to 7 (#60)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump pnpm/action-setup from 4 to 5 (#59)

Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 4 to 5.
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v4...v5)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/checkout from 4 to 6 (#58)

Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/cache from 4 to 5 (#57)

Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/setup-node from 4 to 6 (#56)

Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump picomatch from 2.3.1 to 2.3.2 (#55)

Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2.
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump vitest and @vitest/coverage-istanbul (#64)

Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) and [@vitest/coverage-istanbul](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-istanbul). These dependencies needed to be updated together.

Updates `vitest` from 4.0.16 to 4.1.2
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/vitest)

Updates `@vitest/coverage-istanbul` from 4.0.16 to 4.1.2
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/coverage-istanbul)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
- dependency-name: "@vitest/coverage-istanbul"
  dependency-version: 4.1.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump the npm_and_yarn group across 1 directory with 11 updates (#71)

Bumps the npm_and_yarn group with 11 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [next](https://github.com/vercel/next.js) | `15.5.9` | `15.5.14` |
| [happy-dom](https://github.com/capricorn86/happy-dom) | `20.0.11` | `20.8.9` |
| [ajv](https://github.com/ajv-validator/ajv) | `6.12.6` | `6.14.0` |
| [axios](https://github.com/axios/axios) | `1.13.2` | `1.14.0` |
| [brace-expansion](https://github.com/juliangruber/brace-expansion) | `1.1.12` | `1.1.13` |
| [flatted](https://github.com/WebReflection/flatted) | `3.3.3` | `3.4.2` |
| [h3](https://github.com/h3js/h3) | `1.15.4` | `1.15.10` |
| [hono](https://github.com/honojs/hono) | `4.11.3` | `4.12.9` |
| [minimatch](https://github.com/isaacs/minimatch) | `3.1.2` | `3.1.5` |
| [rollup](https://github.com/rollup/rollup) | `4.54.0` | `4.60.1` |
| [socket.io-parser](https://github.com/socketio/socket.io) | `4.2.5` | `4.2.6` |



Updates `next` from 15.5.9 to 15.5.14
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.5.9...v15.5.14)

Updates `happy-dom` from 20.0.11 to 20.8.9
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](https://github.com/capricorn86/happy-dom/compare/v20.0.11...v20.8.9)

Updates `ajv` from 6.12.6 to 6.14.0
- [Release notes](https://github.com/ajv-validator/ajv/releases)
- [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.6...v6.14.0)

Updates `axios` from 1.13.2 to 1.14.0
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.13.2...v1.14.0)

Updates `brace-expansion` from 1.1.12 to 1.1.13
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13)

Updates `flatted` from 3.3.3 to 3.4.2
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2)

Updates `h3` from 1.15.4 to 1.15.10
- [Release notes](https://github.com/h3js/h3/releases)
- [Changelog](https://github.com/h3js/h3/blob/v1.15.10/CHANGELOG.md)
- [Commits](https://github.com/h3js/h3/compare/v1.15.4...v1.15.10)

Updates `hono` from 4.11.3 to 4.12.9
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.11.3...v4.12.9)

Updates `minimatch` from 3.1.2 to 3.1.5
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

Updates `rollup` from 4.54.0 to 4.60.1
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.54.0...v4.60.1)

Updates `socket.io-parser` from 4.2.5 to 4.2.6
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-parser@4.2.5...socket.io-parser@4.2.6)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 15.5.14
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: happy-dom
  dependency-version: 20.8.9
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: ajv
  dependency-version: 6.14.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: axios
  dependency-version: 1.14.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: brace-expansion
  dependency-version: 1.1.13
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: h3
  dependency-version: 1.15.10
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: hono
  dependency-version: 4.12.9
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: rollup
  dependency-version: 4.60.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: socket.io-parser
  dependency-version: 4.2.6
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump yaml from 2.8.2 to 2.8.3 (#53)

Bumps [yaml](https://github.com/eemeli/yaml) from 2.8.2 to 2.8.3.
- [Release notes](https://github.com/eemeli/yaml/releases)
- [Commits](https://github.com/eemeli/yaml/compare/v2.8.2...v2.8.3)

---
updated-dependencies:
- dependency-name: yaml
  dependency-version: 2.8.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @xmldom/xmldom (#72)

Bumps the npm_and_yarn group with 1 update in the / directory: [@xmldom/xmldom](https://github.com/xmldom/xmldom).


Updates `@xmldom/xmldom` from 0.8.11 to 0.8.12
- [Release notes](https://github.com/xmldom/xmldom/releases)
- [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xmldom/xmldom/compare/0.8.11...0.8.12)

---
updated-dependencies:
- dependency-name: "@xmldom/xmldom"
  dependency-version: 0.8.12
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* docs: add Drips FUNDING.json + fix Giveth URL in FUNDING.yml

- FUNDING.json: Drips Network project claim (treasury wallet)
- FUNDING.yml: correct Giveth project URL slug

* Add newline at end of FUNDING.json

Fix formatting by adding a newline at the end of the file.

* docs: add OP Atlas projectId to FUNDING.json

* docs: add Optimism network to Drips FUNDING.json

* docs: add Buy Me a Coffee to FUNDING.yml

* build(deps): bump lodash in the npm_and_yarn group across 1 directory (#78)

Bumps the npm_and_yarn group with 1 update in the / directory: [lodash](https://github.com/lodash/lodash).


Updates `lodash` from 4.17.21 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump defu in the npm_and_yarn group across 1 directory (#80)

Bumps the npm_and_yarn group with 1 update in the / directory: [defu](https://github.com/unjs/defu).


Updates `defu` from 6.1.4 to 6.1.6
- [Release notes](https://github.com/unjs/defu/releases)
- [Changelog](https://github.com/unjs/defu/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unjs/defu/compare/v6.1.4...v6.1.6)

---
updated-dependencies:
- dependency-name: defu
  dependency-version: 6.1.6
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: remove robots.txt (static export doesn't serve it)

* feat: add 512x512 app icon for PWA and social sharing

* feat: add TalentApp domain verification meta tag

* build(deps): bump @tanstack/react-query from 5.90.16 to 5.96.2 (#82)

Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.90.16 to 5.96.2.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.96.2/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.96.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @next/eslint-plugin-next from 16.2.1 to 16.2.2 (#84)

Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.1 to 16.2.2.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.2.2/packages/eslint-plugin-next)

---
updated-dependencies:
- dependency-name: "@next/eslint-plugin-next"
  dependency-version: 16.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump framer-motion from 12.23.26 to 12.38.0 (#87)

Bumps [framer-motion](https://github.com/motiondivision/motion) from 12.23.26 to 12.38.0.
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v12.23.26...v12.38.0)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-version: 12.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @vitejs/plugin-react from 5.1.2 to 5.2.0 (#88)

Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 5.1.2 to 5.2.0.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/plugin-react@5.2.0/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@5.2.0/packages/plugin-react)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 5.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump postcss from 8.5.6 to 8.5.8 (#89)

Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.8.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.6...8.5.8)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump typescript-eslint from 8.51.0 to 8.58.0 (#92)

Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.51.0 to 8.58.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.58.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @testing-library/react from 16.3.1 to 16.3.2 (#93)

Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 16.3.1 to 16.3.2.
- [Release notes](https://github.com/testing-library/react-testing-library/releases)
- [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/react-testing-library/compare/v16.3.1...v16.3.2)

---
updated-dependencies:
- dependency-name: "@testing-library/react"
  dependency-version: 16.3.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @web3icons/react from 4.1.14 to 4.1.17 (#94)

Bumps [@web3icons/react](https://github.com/0xa3k5/web3icons/tree/HEAD/packages/react) from 4.1.14 to 4.1.17.
- [Release notes](https://github.com/0xa3k5/web3icons/releases)
- [Changelog](https://github.com/0xa3k5/web3icons/blob/main/packages/react/CHANGELOG.md)
- [Commits](https://github.com/0xa3k5/web3icons/commits/@web3icons/react@4.1.17/packages/react)

---
updated-dependencies:
- dependency-name: "@web3icons/react"
  dependency-version: 4.1.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @upstash/ratelimit from 2.0.7 to 2.0.8 (#91)

Bumps [@upstash/ratelimit](https://github.com/upstash/ratelimit) from 2.0.7 to 2.0.8.
- [Release notes](https://github.com/upstash/ratelimit/releases)
- [Commits](https://github.com/upstash/ratelimit/compare/v2.0.7...v2.0.8)

---
updated-dependencies:
- dependency-name: "@upstash/ratelimit"
  dependency-version: 2.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @eslint/eslintrc from 3.3.3 to 3.3.5 (#96)

Bumps [@eslint/eslintrc](https://github.com/eslint/eslintrc) from 3.3.3 to 3.3.5.
- [Release notes](https://github.com/eslint/eslintrc/releases)
- [Changelog](https://github.com/eslint/eslintrc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslintrc/compare/eslintrc-v3.3.3...eslintrc-v3.3.5)

---
updated-dependencies:
- dependency-name: "@eslint/eslintrc"
  dependency-version: 3.3.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump pixi.js from 8.14.3 to 8.17.1 (#100)

Bumps [pixi.js](https://github.com/pixijs/pixijs) from 8.14.3 to 8.17.1.
- [Release notes](https://github.com/pixijs/pixijs/releases)
- [Commits](https://github.com/pixijs/pixijs/compare/v8.14.3...v8.17.1)

---
updated-dependencies:
- dependency-name: pixi.js
  dependency-version: 8.17.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump geist from 1.5.1 to 1.7.0 (#98)

Bumps [geist](https://github.com/vercel/geist-font/tree/HEAD/packages/next) from 1.5.1 to 1.7.0.
- [Release notes](https://github.com/vercel/geist-font/releases)
- [Changelog](https://github.com/vercel/geist-font/blob/main/packages/next/CHANGELOG.md)
- [Commits](https://github.com/vercel/geist-font/commits/geist@1.7.0/packages/next)

---
updated-dependencies:
- dependency-name: geist
  dependency-version: 1.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @types/node from 25.5.0 to 25.5.2 (#99)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.0 to 25.5.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.5.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump viem from 2.47.6 to 2.47.10 (#97)

Bumps [viem](https://github.com/wevm/viem) from 2.47.6 to 2.47.10.
- [Release notes](https://github.com/wevm/viem/releases)
- [Commits](https://github.com/wevm/viem/compare/viem@2.47.6...viem@2.47.10)

---
updated-dependencies:
- dependency-name: viem
  dependency-version: 2.47.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @eslint/js from 9.39.2 to 9.39.4 (#101)

Bumps [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) from 9.39.2 to 9.39.4.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/commits/v9.39.4/packages/js)

---
updated-dependencies:
- dependency-name: "@eslint/js"
  dependency-version: 9.39.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump vite in the npm_and_yarn group across 1 directory (#102)

Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 7.3.0 to 7.3.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.3.2
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* refactor(history): redesign history page cards with payment panel style (#103)

* feat(history): add StatusGradientBar component

* feat(history): add NetworkBadge component with tests

* refactor(history): redesign InvoiceStatusBadge with dot + glow

* refactor(history): restyle InvoiceCardShell with zinc-900 + gradient bar

* refactor(history): rewrite HistoryList with new card layout, network badge, subtotal

* refactor(history): rewrite ReceivedInvoiceList with unified card design + Template button

* refactor(history): update HistoryWorkspace colors gray→zinc

* fix(history): remove unused type imports in ReceivedInvoiceList

* refactor(history): extract shared InvoiceCard, remove duplicate card components

Unified HistoryEntryCard and ReceivedInvoiceCard (~95% identical) into a
single InvoiceCard with a nameLabel prop. Removed defeated memo(), pointless
useMemo, dead source prop, and unnecessary JSX comments. Collapsed identical
DecodedReceivedInvoice type into alias for DecodedHistoryEntry.

* refactor(history): consolidate duplicated configs, merge list components

- Merge HistoryList + ReceivedInvoiceList into unified InvoiceList with
  variant prop ('created'|'received') controlling route, name, empty text
- Extract INVOICE_STATUS_CHIPS to entities/invoice for shared status colors
  consumed by InvoiceStatusBadge (features) and StatusChip (widgets)
- Move network badge dark-mode colors to entities/network (NETWORK_BADGES_DARK)
- Add formatDateMedium, formatDateCompact, isoToUnix to shared/lib/date-time
- Remove deprecated DecodedReceivedInvoice type alias
- Net -54 lines, 59/59 tests pass, tsc + lint clean

* feat: add Base network (8453) + refactor network visual system (#79)

* fix: remove robots.txt (static export doesn't serve it)

* feat: add BaseIcon SVG component for Base network

* feat: add Base (8453) and Base Sepolia (84532) to chain config

* feat: add Base network metadata and codes

* feat: add Base token registry (ETH, USDC, USDT)

* feat: add Base provider slugs for Alchemy and Infura

* feat: add Base confirmation config (OP Stack)

* feat: add Base block estimation parameters

* feat: add Base UI theming, badges, glows, and explorer

* feat: add Base RPC URL env vars to schema

* fix: add Base to theme configs, update chain count tests and snapshots

* fix: add Base to NetworkIcon component (web3icons + fallback)

* fix: update Base reference block from live explorer data

* refactor: remove unused BaseIcon (NetworkIcon uses @web3icons/react)

* fix: boost Base glow opacity (blue is subtle on dark background)

* revert: restore original Base glow values

* fix: resolve testnet glow/shadow/badge lookups via withTestnets helper

Visual config Records (NETWORK_SHADOWS, NETWORK_GLOWS, NETWORK_GLOW_SHADOWS,
NETWORK_GLOW_BORDERS, NETWORK_BADGES) were keyed by mainnet chain IDs only,
causing missing glow on testnet invoices (e.g. Base Sepolia 84532).

Added withTestnets() helper that auto-derives testnet entries from
TESTNET_PARENT, so new networks only need one mapping update.

* docs: update supported networks count and add Base to README and snapshot tests

* docs: add Base to all network references across landing, legal, and test files

* refactor: create canonical network palette and testnet utilities

* chore: bump Node.js version to v24 in .nvmrc

* chore: gitignore AI tool facades, plugins, and supabase local config

* refactor: rename getNetworkTheme→getNetworkName, extract testnet utils, lowercase addresses

* refactor: derive brand-tokens from palette, remove dead env vars, fix NetworkIcon a11y

- NetworkTheme now aliases NetworkThemeName from network-palette (canonical source)
- isValidNetworkTheme validates against NETWORK_PALETTE instead of NETWORK_THEMES
- Remove 10 dead NEXT_PUBLIC_ALCHEMY/INFURA_*_URL env vars (RPC proxy uses API keys + slug maps)
- NetworkIcon resolves testnet chain IDs to mainnet for icon/color/letter lookup
- Add aria-label to both branded and fallback NetworkIcon paths
- Export NETWORK_PALETTE and NetworkThemeName from shared/ui public API

* refactor: derive network-themes from canonical palette + withTestnets

* refactor: update consumers to use getNetworkThemeName, hoist widget colors

* feat: add Base demo invoice, fix tokenAddress not clearing for native tokens

Add 5th demo invoice for Base network (USDC, pending status) to landing
page carousel. Fix react-hook-form reset() not clearing tokenAddress when
loading native token templates (ETH/POL) — undefined must be mapped to ''
so RHF treats it as an explicit value rather than "keep current".

* fix: address PR review findings — remove unverified USDT, harden env, stabilize snapshots

- Remove Base USDT token (no official Tether deployment on Base)
- Add BLOCK_EXPLORERS comment explaining withTestnets exclusion
- Update Base Sepolia block anchor from live RPC (28M → 39.88M)
- Replace Math.random() with crypto.randomUUID() in RPC proxy
- Harden validateEnv to throw in production on missing vars
- Add Radix UI snapshot serializer for stable aria-controls IDs

* fix: prevent stale total when switching tokens, add replaceDraft for clean data loading

Total was stored as pre-calculated atomic units tied to a specific token's
decimals. Switching tokens reconverted line item rates but left total stale,
causing the preview to format ETH-scale values with USDC decimals (e.g.
5,510,000,000,000 instead of 5.80).

- Add replaceDraft() for atomic draft replacement (hash decode, template load)
- Extract toInvoiceItems/draftWithItems helpers, DRY 4 line item methods
- Clear stale total on: token switch, item mutations, template save/load
- Strip total from hash decode in CreateWorkspace (editor recalculates)
- Handle string quantities in invoiceItemsToLineItems (old localStorage)

* fix(history): resolve testnet networks showing as "Unknown" in history badges

Use getNetworkName() for O(1) lookup across all networks instead of
NETWORK_CONFIG.find() which only covered mainnets. Wrap NETWORK_BADGES_DARK
with withTestnets() so testnet badges inherit parent network brand colors.

* fix(create): reset all draft fields on form clear, extract store→form adapter

draftSyncStatus leaked through reset because createNewDraft/clearDraft/replaceDraft
didn't explicitly set it to 'idle'. Tax/discount/notes leaked because
react-hook-form treats undefined in reset() as "keep previous value".

Extract draftDataToFormValues() adapter as single source of truth for
PartialInvoice→InvoiceFormValues conversion, replacing duplicated 60-line
inline mappings. All optional string fields now coerced to '' on reset.

* fix(test): align NetworkBadge test with getNetworkName fallback to chain ID

* feat: update comparison table data to April 2026 research

RF pricing changed to \$250+/mo subscription, data storage corrected to
Centralized (hybrid API + on-chain, not pure IPFS), KYC/KYB updated to
required (yes). Disclaimer and comment block updated to April 2026.

* feat: add comparison page content data (VP vs Request Finance)

* feat: add /compare/request-finance comparison page

* feat: add /compare pages priority to sitemap config

* feat: add link to detailed comparison from landing table

* test: add comparison page tests

* fix: improve comparison page UI and remove duplicate footer

Apply UI/UX audit improvements: text-pretty headings, tabular-nums
table, hover states, glow CTA button, visual star rating, TL;DR label,
violet accent on bottom-line boxes. Remove duplicate footer links
since app-level footer already exists.

* ci: add project-sync workflow for auto VP Roadmap sync

New issues automatically added to VP Roadmap project board
with fields (Status, Priority, Advisor, Type, Source Repo)
parsed from labels. Agents no longer need manual item-add.

* fix(ci): use GraphQL API for project-sync workflow

gh project item-add/item-edit fail with "unknown owner type"
on user-level projects. Switch to direct GraphQL mutations.

* chore: add .superpowers/ to gitignore

* fix: invoice generation bugs — flash, source immutability, cross-tab sync (#105)

* fix: prevent invoice flash on generate, preserve source immutability, add cross-tab sync

- Remove clearDraft setTimeout that caused visible flash during navigation
- Make TrackedInvoice.source immutable (first-write-wins) so visiting /pay
  doesn't overwrite 'created' to 'received'
- Add localStorage storage event listener for cross-tab store rehydration

* fix(ui): add cursor-pointer to CreatorHintBanner dismiss button

* fix(store): key TrackedInvoice by contentHash (SHA-256) instead of invoiceId (#112)

* feat(codec): add computeContentHash — SHA-256 bytes32 digest for invoice identity

* feat(codec): return contentHash from parseInvoiceHash

* feat(store): key TrackedInvoice by contentHash instead of invoiceId

* feat(create): compute contentHash on invoice generation

* feat(view): compute and expose contentHash from useInvoiceView

* feat(import): compute contentHash for imported invoices

* refactor(ui): wire contentHash through component hierarchy

* refactor(payment): all hooks key by contentHash instead of invoiceId

Updates SmartPayButtonProps, UsePaymentFlowParams, UsePaymentVerificationParams,
UseFinalizationTrackerParams, UsePaymentPollingParams, and UseManualVerifyParams
to accept contentHash. All store action calls (setTxHash, setError, setValidated,
setFinalized, resetPaymentState, setConfirmations) now use contentHash as the key.
Internal polling helpers (loops, visibility-handler) updated consistently.

* fix: use contentHash key in polling params

* test: update all tests for contentHash-based store key

* fix: review fixes — runtime bugs, security hardening, perf improvements

- Fix PaymentPanel using invoiceId instead of contentHash for store lookup (BUG-01: PDF export lost paidAt)
- Fix DevStatusToggle passing invoiceId to contentHash-keyed store methods (BUG-02)
- Use Promise.allSettled in migration to survive partial failures (S-01)
- Always recompute contentHash on import, never trust pre-supplied values (S-02)
- Add empty fragment guard in addToHistory (H-1)
- Early return in setTxHash for unknown invoice (M-2)
- Add console.warn to migration catch block (F-04)
- Parallelize decode + hash in parseInvoiceHash via Promise.all
- Parallelize import hash computation, eliminate in-place mutation

* fix: resolve history page flickering and infinite migration loop

- Replace non-reactive hasHydrated() with useStoreHydrated() hook that
  subscribes via onFinishHydration for proper React re-render on hydration
- Make persist migration synchronous to avoid zustand v5 hydrationVersion
  race condition that cancelled in-flight async migrations
- Compute contentHash post-hydration via onFinishHydration + hasHydrated
  guard to handle both sync and async hydration paths
- Remove cross-tab storage event listener that triggered rehydrate() loops
  from stale tabs still writing version 1

* fix: show full invoice data in debug panel instead of decode flag

* fix: skip post-hydration hash computation on v2+ stores

Add _pendingHashComputation flag set only by migrate() during v1→v2
transition. _computeMissingContentHashes() now exits immediately on
v2+ stores instead of reading store state on every hydration.

* fix: remove console.info logs and fix test type errors

Remove informational console logs from TrackedInvoiceStore (keep warnings).
Add missing contentHash to SmartPayButton test fixtures.
Add scrollMargin to MockIntersectionObserver for TS 5.5+ compat.

* refactor: replace async crypto.subtle with sync @noble/hashes for SHA-256

Async two-phase migration (sync migrate → async post-hydration hash)
caused store data loss: zustand persisted entries with empty contentHash
between phases, and any failure in the async phase dropped invoices.

Switch to sync SHA-256 via @noble/hashes (already a dependency via viem)
so contentHash is computed atomically inside migrate(). Removes ~55 lines
of async infrastructure: _pendingHashComputation, _computeMissingContentHashes,
_sha256, onFinishHydration/hasHydrated fallback.

* docs: fix SECURITY.md — styled-components → inline style injection, add /api/health to out-of-scope

* fix(wallet): sync connection state between scoped Web3Providers

LazyWalletButton in the header could stay in static placeholder state
("Connect") while PayButton's scoped provider already had the wallet
connected. Root cause: LazyWalletButton only checked localStorage on
mount and had no way to detect connections from other providers.

Add WalletStateSync component that dispatches a custom DOM event
on wallet connect, and a listener in LazyWalletButton to activate
when the event fires.

* fix(wallet): prevent rehydration race in scoped Web3Providers

Multiple WagmiProvider instances sharing one wagmiConfig caused
connector state corruption: each mount triggered rehydrate() which
overwrote live connector instances with serialized plain objects
from localStorage. Between rehydrate() and reconnect() completing,
writeContract/sendTransaction crashed with "getChainId is not a
function" because the connector lacked methods.

Use WagmiContext.Provider (context-only, no hydration) for all
Web3Provider instances after the first one. A module-level flag
ensures only the primary instance triggers full WagmiProvider
hydration + reconnect.

* fix(payment): keyframe rotate to prevent SmartPay spinner freeze on Rabby

framer-motion v12 with WAAPI backend stalls single-value rotate loops
on the second iteration when a wallet extension's content script forces
a re-render mid-mount. The breathing label kept animating (keyframes
array) while the spinner icon froze (single value 360).

Switching to explicit keyframes [0, 360] gives WAAPI an unambiguous
start/end on every iteration and matches the pattern already used by
FluidOverlay for all other infinite loops in the button tree.

* fix(history): batch-check unpaid for both created and received invoices

Parametrize useBatchCheck by invoice source so the History page can verify
pending payments for both own and counterparty invoices, not just created.
Add a Check Unpaid button to the Received section mirroring the Created
one. Make invoice number and counterparty name in InvoiceCard clickable —
both trigger the View action with hover/focus styling.

* build(deps): bump viem from 2.47.10 to 2.47.16 (#122)

Bumps [viem](https://github.com/wevm/viem) from 2.47.10 to 2.47.16.
- [Release notes](https://github.com/wevm/viem/releases)
- [Commits](https://github.com/wevm/viem/compare/viem@2.47.10...viem@2.47.16)

---
updated-dependencies:
- dependency-name: viem
  dependency-version: 2.47.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump typescript-eslint from 8.58.0 to 8.58.2 (#124)

Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.58.0 to 8.58.2.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.2/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.58.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @noble/hashes from 2.0.1 to 2.2.0 (#125)

Bumps [@noble/hashes](https://github.com/paulmillr/noble-hashes) from 2.0.1 to 2.2.0.
- [Release notes](https://github.com/paulmillr/noble-hashes/releases)
- [Commits](https://github.com/paulmillr/noble-hashes/compare/2.0.1...2.2.0)

---
updated-dependencies:
- dependency-name: "@noble/hashes"
  dependency-version: 2.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump prettier from 3.7.4 to 3.8.2 (#126)

Bumps [prettier](https://github.com/prettier/prettier) from 3.7.4 to 3.8.2.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.7.4...3.8.2)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.8.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump use-debounce from 10.0.6 to 10.1.1 (#127)

Bumps [use-debounce](https://github.com/xnimorz/use-debounce) from 10.0.6 to 10.1.1.
- [Release notes](https://github.com/xnimorz/use-debounce/releases)
- [Changelog](https://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xnimorz/use-debounce/commits)

---
updated-dependencies:
- dependency-name: use-debounce
  dependency-version: 10.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump hono in the npm_and_yarn group across 1 directory (#104)

Bumps the npm_and_yarn group with 1 update in the / directory: [hono](https://github.com/honojs/hono).


Updates `hono` from 4.12.9 to 4.12.12
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.12.9...v4.12.12)

---
updated-dependencies:
- dependency-name: hono
  dependency-version: 4.12.12
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump react-hook-form from 7.70.0 to 7.72.1 (#130)

Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.70.0 to 7.72.1.
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.70.0...v7.72.1)

---
updated-dependencies:
- dependency-name: react-hook-form
  dependency-version: 7.72.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @tailwindcss/postcss from 4.1.18 to 4.2.2 (#131)

Bumps [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) from 4.1.18 to 4.2.2.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/@tailwindcss-postcss)

---
updated-dependencies:
- dependency-name: "@tailwindcss/postcss"
  dependency-version: 4.2.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump lucide-static from 1.7.0 to 1.8.0 (#123)

Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/compare/1.7.0...1.8.0)

---
updated-dependencies:
- dependency-name: lucide-static
  dependency-version: 1.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @tanstack/react-query from 5.96.2 to 5.99.0 (#128)

Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.96.2 to 5.99.0.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.99.0/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.99.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @types/node from 25.5.2 to 25.6.0 (#132)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.2 to 25.6.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @next/eslint-plugin-next from 16.2.2 to 16.2.3 (#134)

Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.2 to 16.2.3.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.2.3/packages/eslint-plugin-next)

---
updated-dependencies:
- dependency-name: "@next/eslint-plugin-next"
  dependency-version: 16.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat(payment): typed wagmi error handling + onReplaced support (#115)

* feat(payment): typed wagmi error handling + onReplaced support

Replace fragile string-matching error classification with typed detection
via viem's BaseError.walk() across the payment and wallet-connect features.
Add onReplaced callback to handle user speedup/cancel of pending transactions.

Component A: shared/lib/web3-errors
- New module with isUserRejected, isInsufficientFunds, isChainMismatch,
  isReceiptNotFound, isReceiptTimeout, isTxReverted, walkCause
- Walks BaseError cause chain via viem's typed API, falls back to string
  matching for non-BaseError edge cases (mobile WalletConnect)
- 38 unit tests covering direct, wrapped, and fallback paths

Component B: classifier refactor
- classify-error.ts rewritten to use typed detectors before string matching
- Removed step-based NETWORK_SWITCH_FAILED fallback — was masking user
  rejections of network switches
- Added TX_REPLACED to PaymentErrorType + ERROR_MESSAGES entry
- CANCELED_COPY constant for message unification
- connection-error.ts now calls isUserRejected first for typed detection

Component C: payment flow integration
- use-payment-flow.ts: console.error moved below USER_REJECTED early return
  (fixes verbose wagmi stack in console on user cancel)
- useWaitForTransactionReceipt now receives onReplaced callback:
  - reason 'cancelled' → toast + RESET (user intent)
  - reason 'replaced'/'repriced' → update hash + continue
- New REPLACED reducer action for hash swap during confirming state
- use-payment-verification.ts: sanitize raw viem errors through
  formatErrorMessage before writing to store + onReplaced observability

* refactor(payment): address review feedback on typed wagmi error handling

- Drop unused _step parameter from classifyPaymentError (dead arg after
  step-based fallback removal); update call site and 20+ test cases.
- Fix incorrect comment in usePaymentVerification onReplaced — both hooks
  consume useWaitForTransactionReceipt in parallel, not sequentially.
- Add TransactionExecutionError coverage to detect.test.ts (revert vs OOG
  shortMessage branches).

* feat(payment-panel): persistent network chip across all states

Adds a branded NetworkIcon + name chip at the top of PaymentPanel so
payers always see which chain the payment targets — visible in pending,
paid, paid-fallback and overdue states. Reserves right-side space via
pr-12 to avoid overlap with the minimize button.

Also migrates AmountDisplay assertions from toBeDefined() to
toBeInTheDocument() per testing rules.

* refactor(payment-panel): anchor network chip to amount, own minimize button

Move the network chip from the panel header into each state's heading row
(Total Due / Payment Successful / Expired / paid-fallback) so it sits
beside the amount it qualifies — semantically tying chain to value
instead of floating in an empty header strip.

Extract NetworkChip into a shared presentational component to drop
duplication across states. Pull the minimize button into PaymentPanel
behind an onMinimize prop, removing the duplicated absolute overlay
from PayWorkspace and InvoiceWorkspace. The button now coordinates with
the pr-12 right-side clearance baked into every heading row.

* fix(history): network icons, button sizing, robust template flow

- NetworkBadge: render NetworkIcon (web3icons) before name
- InvoiceCard: match Confirm/Cancel button height to regular buttons
  (min-h-[44px] py-2.5) to prevent layout shift on delete toggle
- InvoiceList: replace fragile duplicateFromUrl + setState + push flow
  with hash-based navigation /create?template=1#<hash>
- CreateWorkspace: detect ?template=1 and reset issuedAt/dueAt/total/
  magicDust after replaceDraft so templates start with fresh dates
- Remove unused duplicate-invoice.ts and its test mock

* refactor(payment-panel): group network chip with due/paid date

Relocates NetworkChip into a compact metadata row next to the due
date (pending) or relative paidAt (paid/expired). Drops the "TOTAL
DUE" label — the amount is self-explanatory and the label created
a "Total Due ... Due May 2" tautology with the date chunk.

- pending: [chip] Due <date>    above the amount
- paid:    [chip] Funds sent · <relative>    under Payment Successful
- expired: [chip] Was due <date> · Payment disabled    under header

Adds formatRelativeTime() in shared/lib/date-time for ISO →
"Just now" / "5 min ago" / "2 h ago" rendering. PaymentPanel now
subscribes to tracked paidAt via a store selector so the subtitle
reactively updates when the payment transitions to paid.

Clears the chip out of the emerald amount accent box on paid
state — zinc chip no longer clashes with the emerald tint.

* fix(wallet): visible loading state during wagmi reconnect

SmartPayButton and WalletButton both appeared frozen while wagmi
restored the persisted connection: the pay button stayed on "Pay X Y"
while disabled, and the header wallet button was hidden via opacity:0
so clicks fell through. Now both surfaces render an explicit disabled
"Reconnecting…" state with a visible spinner and aria-busy.

Covered by 6 new tests (3 SmartPayButton reconnect cases, 3 WalletButton).

* fix(wallet): cover SSR pre-hydration gap in pay + header buttons

Two bugs under one symptom ("click during page-load race gets stuck at
Connecting"):

1. Pre-hydration gap: wagmi with `ssr: true` reports `status: 'disconnected'`
   on the first client render even when a persisted connection exists in
   localStorage. `isReconnecting` is false in that window, so the previous
   fix did not catch it — SmartPayButton flashed a clickable "Connect Wallet"
   and WalletButton did the same in the header.

2. Stuck-at-connecting race: when a user clicked through the flash,
   `handlePay` entered `connecting` and opened the Rainbow modal. Meanwhile
   wagmi finished the background reconnect. The lifecycle effect in
   `usePaymentFlow` checked `connectModalOpen` before `isConnected`, so if
   Rainbow's modal state didn't cleanly flip through the expected order the
   flow stayed in `connecting` forever.

Fix:
- New shared hook `useWagmiHydrating` detects pre-hydration (persisted
  connector id in localStorage + wagmi still on initial disconnected),
  plus the normal `connecting` / `reconnecting` statuses. Drops the
  pre-hydration heuristic once wagmi leaves the initial snapshot so later
  manual disconnect/reconnect cycles behave normally.
- SmartPayButton and WalletButton now use `useWagmiHydrating` instead of
  `isReconnecting`. Both render a disabled loading button with
  aria-busy=true across the whole hydration window.
- `usePaymentFlow` connecting effect now checks `isConnected` before
  `connectModalOpen`, so a background reconnect always wins and the flow
  cannot strand in `connecting`.
- Regression tests: reorder-safe race in `use-payment-flow`, pre-hydration
  coverage in SmartPayButton + WalletButton suites. 387 payment +
  wallet-connect tests green.

* fix(payment): cap wait-for-receipt timeout at 60s, disable retry

Ensures a stuck transaction surfaces a user-visible RPC_ERROR banner
within one block window instead of hanging on the spinner. Previously,
viem's 180s default timeout combined with TanStack Query's default
retry (3) meant the first user-visible error could be delayed by up
to 9 minutes.

Also drops the TEMP DEBUG console.logs added during manual test
verification — all three test paths (USER_REJECTED silence, onReplaced
cancel, onReplaced speedup) have been validated on Eth Sepolia + Rabby.

Part of PR #115.

* fix(payment): raise wait-for-receipt timeout to viem default 180s

60s was too aggressive — near-zero-gas transactions legitimately need
several blocks on L1 before inclusion. Combined with retry: 0 this
still caps the hidden wait at 3 minutes (vs viem's default retry × 180s
= 9 minutes that motivated the original fix).

Field-verified on Base Sepolia: a stuck tx now surfaces the RPC_ERROR
banner as expected — only thing that needed tuning was the ceiling.

Part of PR #115.

* fix(payment-panel): make error banner X button clickable and cursor visible

Tailwind v4 dropped the default pointer cursor on <button>, and dismissError
only cleared the store — local paymentError stayed set, so the X appeared dead.
Add cursor-pointer + type=button, and wire a composite handler that clears
both paymentError and the tracked-invoice store error.

* refactor(payment): simplify PR #115 after parallel review

Findings from three parallel review agents (reuse, quality, efficiency)
aggregated and fixed:

- Remove dead TX_REPLACED PaymentErrorType: defined but never emitted
  (onReplaced dispatches REPLACED/RESET directly, classifier never
  returns it)
- Remove walkCause from web3-errors barrel export: internal-only,
  test file imports from ../detect
- Memoize onReplaced + extract RECEIPT_QUERY_OPTIONS/TIMEOUT_MS to
  module level in use-payment-flow.ts (inline refs were re-subscribing
  TanStack Query / viem watcher every render during confirming step)
- Hoist stateless handleVerificationReplaced + memoize receiptQuery in
  use-payment-verification.ts (compounded by useBlockNumber watch: true)
- Unwrap naked <div> wrapper with no props/layout in WalletButton.tsx
- Fix misleading CANCELED_COPY comment (claimed cross-feature usage
  that never existed)

Follow-ups tracked in #120 (NetworkChip/NetworkBadge unification),
#121 (nowUnix migration).

Net: -71 / +66 lines. Type-check, lint, 277 affected tests pass.

* fix(payment): address PR #115 review findings

- use receipt.transactionHash on CONFIRMED so replaced/repriced tx
  hashes aren't overwritten by the stale wagmi send hash
- REPLACED reducer explicitly clears error for future-proofing
- console.error logs shortMessage only to avoid leaking calldata
  if observability is wired later
- use-payment-verification: consolidate imports above function decl
- add reducer test covering REPLACED error preservation

* fix(payment): correct block-time drift breaking creator-side verification

Root cause: AVG_BLOCK_TIME_MS[11155111] was 12_000 but Sepolia actually runs
~13s/block. Over 35 days of forward drift estimateFromBlockHex returned a
block above the real chain head; alchemy_getAssetTransfers returned empty and
creators saw "payment not found" on confirmed transactions. Arbitrum Sepolia
had the same class of bug (250ms assumed vs ~286ms measured).

- AVG_BLOCK_TIME_MS: Sepolia 12000→13000, Arb Sepolia 250→286 (measured via
  10k-block samples across all 10 supported chains). REFERENCE_BLOCKS left
  frozen — v1.0 shipped Mar 28, old invoices must decode with the same
  calibration they were created with.
- /api/transfers: defense-in-depth safety net. Fetches eth_blockNumber in
  parallel with the transfers query, and on drifted client fromBlock retries
  with a 3-day lookback anchored to the real chain head. Drift logged via
  console.warn for observability. Eliminates the bug class regardless of
  anchor staleness.
- scripts/measure-block-times.ts + pnpm check:block-drift: diagnostic that
  measures real avgBlockTime for every chain, compares vs hardcoded values,
  reports lookback margin, and exits non-zero on BROKEN verdict.
- Route tests updated for the new parallel fetch; added cases covering both
  retry and no-retry paths of t…
ignromanov added a commit that referenced this pull request May 18, 2026
…k variants (AI#58) (#237)

* feat(video): MicroLabel pill design — readable on any background

* feat(invoice-form): InvoiceFormView renders network + token icons when ids provided

* chore(video): final render p5 + S4 fix link spacing

* fix(video): S0 doubled beats + remove S1 echo overlay

- ThesisHookScene: beat1 visible 12→48 (was 12→30), beat2 fade-in 42→60
  then holds to scene end; each beat now fully readable
- scenes.ts: thesisHook 45 → 90 frames (3s)
- MAGIC_DUST_PEAK_FRAME 831 → 876 (+45 for S0 extension)
- CreateScene: removed echo "…is the URL." Caption (S0 holds long enough)

* refactor(video): S1 inline GenerateButton + 4s scroll + correct field order

- New phase frames: FROM(15) WALLET(30) CLIENT(45) LINE_DESC(60)
  LINE_PRICE(75) NETWORK(90) TOKEN(105) BUTTON_VISIBLE(120)
- viewValue now includes walletAddress (frame>=30) and client.name
  "Acme Corp" (frame>=45) for more realistic form fill sequence
- Line items appear progressively: description at 60, rate at 75
- focusedField sequence: from→from(wallet)→client→lineItem→network→token→undefined
- Scroll keyframes [0,40,80,120] → offsets [0,-200,-400,-560] so
  Generate button scrolls into view at frame 120
- Dropped sticky footer div; using showGenerateButton=true so inline
  button lives inside InvoiceFormView scroll flow
- Void glow overlay (rgba 124,58,237) pulses behind card once button appears
- Removed "Link contains everything" MicroLabel (moved to ShareScene in commit 3)
- "Entire invoice encoded in URL" pill repositioned to frames 130-180

* fix(video): MicroLabel + Caption stronger neon glow + bigger padding

MicroLabel pill: padding 10/16 → 16/28, border opacity 0.3 → 0.6,
boxShadow gains dual neon halo (24px + 48px violet) for visibility
against zinc-950 background.

Caption pill: border opacity 0.4 → 0.7, padding 14/28 → 18/36,
boxShadow gains dual neon halo (32px + 64px violet) to match visual
weight of the larger pill.

* fix(video): S2 modal 512w + 4x longer URL + match real ShareModal layout + InvoiceSummary

- ShareScene: modal width 760 → 512, recentered (left: width/2-256)
- URL hash payload extended to ~560 chars so LinkTab visibly truncates
- Header padding 24/32 → 16/24 to match real ShareModal px-6 pt-6
- Added InvoiceSummary block between header and tabs (real widget component,
  pure presentational — no client-side hooks, safe for Remotion)
- Tabs wrapper padding 0/32/32 → 0/24/24 (px-6 pb-6); removed mb-4 on TabsList
- Added "Link contains everything" MicroLabel at y=14% frames 70-150
  (moved from S1 CreateScene per plan)
- share-modal/index.ts: exported InvoiceSummary from public API

* fix(video): S3 panel vertical-center + faster Magic Dust + longer paid hold

- Panel positioning: top fixed-px → top:"50%" + translate(0,-50%)
  for true vertical centering; removed PANEL_HEIGHT constant
- Timeline compressed (round 3):
    MAGIC_DUST_HIGHLIGHT  240 → 180
    MAGIC_DUST_PEAK_END   360 → 300
    CONFIRMING            360 → 300
    SUCCESS               480 → 390
- Caption "Cryptographic receipt": startAt 240→180, endAt 360→300
- MicroLabel "Micro-amount added": startAt 240→180, endAt 330→270
- MicroLabel "Verified on-chain": startAt 990→420, endAt 1050→500
  (fixes pre-existing bug: 990 was outside scene bounds)
- Toast "Confirming on-chain": startAt 360→300
- Toast "Payment received": startAt 480→390

* fix(video): S1 reorder fields (Invoice No + Dates first) + delay scroll start

Invoice No appears at frame 10, Dates at frame 25 — before Your Name (35)
so viewer understands the document type before the form fills out.

Scroll keyframes shifted from [0,40,80,120] to [10,50,90,130] so the form
holds still while the "is the URL" cross-fade from S0 completes.

focusedField returns undefined before FROM_START=35 (Invoice No / Dates
are not part of InvoiceFormViewProps focusedField enum).

MicroLabel hints shifted: "Filling out" 0-45 → 5-55, "Encoded in URL"
130-180 → 140-190 to align with BUTTON_VISIBLE delay.

* fix(video): S1 lock form Card height + always-on glow border

Card gets explicit height: height * 0.88 so the form panel never expands
beyond its bounds regardless of InvoiceFormView content.

Glow border changed from conditional (only when buttonGlowOpacity > 0) to
always-rendered: baseGlow=0.25 gives ~0.15 opacity from frame 0, then
pulseDelta adds 0.05-0.4 after BUTTON_VISIBLE=130. This eliminates the
jarring pop-in that was visible in p6 render.

* fix(video): caption + microlabel timing — S2 + S4

S2 (ShareScene):
- Caption "No signup" delayed 25fr so it clears the cross-fade entrance.
- MicroLabel order swapped: "Link contains everything" now leads (5-65, y=84%),
  "Hash fragment" follows at top (70-130, y=14%), "Same invoice" closes (95-170,
  y=84%) — windows don't overlap (65 < 95 for bottom slot).

S4 (ThesisOutroScene):
- MicroLabel shifted 30→10 / 100→75 so it shows during scene entrance and
  fades before the voidpay.xyz pill enters, eliminating the empty tail.

* fix(video): S1 timeline shift — scroll stops at 5s, button press at 7s, merge URL captions

Round 5: pull field-reveal constants earlier (all fields by fr 125), scroll
finishes at fr 80 (mp4 5.000s), button press scale feedback at fr 140 (mp4
7.000s). Relocate "No signup" MicroLabel from S2 Caption → S1 MicroLabel
(fr 26–65). Merge two URL labels into one in S2. S1 duration 306→170,
thesisOutro 150→286. Recompute MAGIC_DUST_PEAK_FRAME 876→680.

* fix(video): S1 round-6 — compress field timing + scroll ends at mp4 04.133s

* fix(video): S1 round-6 — sequential Captions (No backend → No signup) + persistent No login MicroLabel

* fix(video): S1 round-6 — Generate button overlay (active state + button-only press-scale)

* refactor(payment): extract SmartPayButtonView for headless reuse (Container/View split)

* fix(video): S3 round-6 — 6-phase CTA flow with per-transition press-scale + Verified label top

* fix(video): S2 round-6 — persistent No login MicroLabel across S1→S2 cross-fade

* fix(video): S1 round-7 — 1s pause before scroll + less aggressive offsets

* fix(video): S1 round-7 — real GenerateButton inside scroll (replaces overlay; matches production form)

* fix(video): S1+S2 round-7 — No login bottom-left + QR shortened to last 1s of S2

* fix(video): S3 round-7 — kill reorg-blink + Cryptographic receipt at 25s

* fix(video): S4 round-7 — remove leftover No-login MicroLabel (moved to S1+S2 in round 6)

* fix(video): round-8 — redistribute create=260 / thesisOutro=196 + recompute MAGIC_DUST_PEAK_FRAME=770

* fix(video): S1 round-8 — +60fr sympathetic shift (2s pause-before-fill) + scroll slowed to 54fr motion

* fix(video): S2 round-8 — Same-invoice MicroLabel synced to QR display window

* fix(video): S3 round-8 — Verified-onchain MicroLabel bottom-left (no collision with Cryptographic-receipt Caption)

* chore(video): scenes.ts round-9a durations + ThesisHook beat shift -12fr

- SCENE_DURATIONS: create 260→320, share 240→260, pay 510→575, thesisOutro 196→175
- TOTAL_DURATION stays 1350 (sum 1420 - 80 crossfades = 1340 visible; 10fr black tail)
- MAGIC_DUST_PEAK_FRAME: 770→860 (S3 starts at global 610; peak midpoint S-local 250)
- MAGIC_DUST_PEAK_HOLD stays 120 (creative-brief §8)
- ThesisHook beats shifted -12fr: beat1 fades in 0-18 (was 12-30), beat2 fades in 30-48 (was 42-60)

* feat(video): CreateScene round-9a — 2× cascade, post-fill paper, button-after-paper, remove messages

- Field cascade widened: INVOICE_NO_APPEAR=65, TOKEN_APPEAR=179, FILL_COMPLETE=195 (+130fr span)
- InvoicePaper now gated on PAPER_APPEAR=200 (post-fill), violet accent pulse 230→280
- BUTTON_VISIBLE=280 (after paper hold), PRESS_START=290, PRESS_END=307
- Glow pulse active throughout fill (INVOICE_NO_APPEAR→BUTTON_VISIBLE), settles to calm halo after
- Removed Caption and MicroLabel imports + JSX (round-9a: no messages in S1)
- GenerateButton stays production component; will swap to GenerateButtonView in C6

* feat(video): ShareScene round-9a — Link 80fr read + 110fr QR + remove messages + Copy single-fire

- COPY_CLICK_FRAME: 60→110 (gives 80fr Link-tab idle read window before copy fires)
- QR_TAB_FROM_FRAME: 210→150 (expands QR window 30fr→110fr / 3.667s)
- Removed MicroLabel import + all 4 MicroLabel JSX nodes (round-9a: no messages in S2)
- Copy double-fire: Fix B chosen — copied boolean flip is stable per-frame;
  CopyOverlay motion.div animate restarts each Remotion frame but palette swap is
  instantaneous so visual is acceptable for p12 preview; production snapshot unaffected

* feat(video): PayScene round-9a — connecting/switching states, reorg progress restored, remove messages

- New phase constants: PRESS_CONNECT=58, PHASE_CONNECTING=65, PHASE_WRONG_NETWORK=95,
  PRESS_SWITCH=153, PHASE_SWITCHING=160, PHASE_READY=190, PRESS_PAY=268,
  PHASE_SENDING=275, PHASE_CONFIRMING=365, SUCCESS=455
- stepAt() extended: returns idle:connecting (65-95) and idle:switching (160-190)
- ctaPressTriggerFrame extended: handles connecting→PRESS_CONNECT, switching→PRESS_SWITCH
- Magic Dust anchors: MAGIC_DUST_HIGHLIGHT=170, MAGIC_DUST_PEAK_END=310
- Reorg progress restored: RemotionPaidConfirmationProgress fork (no framer-motion)
  rendered as overlay during step===confirming; production widget stays byte-identical
- Toast anchors re-anchored to new phase frames (58/153/273/365/455)
- Removed Caption + MicroLabel imports + JSX (round-9a: no messages in S3)
- KEEP RemotionFakeToast (spec requirement)

* feat(payment): extend IdleSubState with connecting/switching for video v2 round-9a

- IdleSubState widened: 'disconnected' | 'connecting' | 'wrong-network' | 'switching' | 'ready'
- Production Container (SmartPayButton) unaffected: deriveIdleSubState() still returns only
  the 3 production values; new states are Remotion-only transitions in PayScene stepAt()
- SmartPayButton snapshot tests: 29/29 unchanged (production Container does not emit new states)
- Type-check: clean (production code uses subset of wider type)

* feat(invoice-form): extract GenerateButtonView for Remotion compatibility (round-9a)

- GenerateButtonView: presentational component with hoverState/pressState props
  for Remotion frame-driven hover/press simulation (no framer-motion, no CSS transitions)
- GenerateButton (Container): delegates to GenerateButtonView; production toast fallback
  preserved; snapshot test 2/2 byte-identical unchanged
- Exported from ui/sections/index.ts and widgets/invoice-form/index.ts (FSD public API)
- CreateScene: swapped GenerateButton → GenerateButtonView with prop-driven states
  (hoverState: BUTTON_VISIBLE→PRESS_START, pressState: PRESS_START→PRESS_END)

* fix(video): CreateScene round-9a-patch1 — scroll stops at 8.6s + button mount earlier

B1: SCROLL_FRAMES end 200 → 188 so scroll stops before empty space below last field.
B2: Button mounts at FILL_COMPLETE (195) instead of BUTTON_VISIBLE (280) so user
sees the GenerateButton during scroll; hover halo still gates on BUTTON_VISIBLE (280).

* fix(video): PayScene round-9a-patch1 — canonical PaymentStep + widened CTA gate + toast retiming

B3: stepAt() returns step:'connecting'/'switching' (PaymentStep canonical) so getButtonLabel
    routes correctly instead of falling through to default 'Pay'.
B4: auto-fixed — getProgress() now returns 0.25/0.45 for connecting/switching steps.
B5: T1 toast startAt 58→95 (wrong-network activates), T2 153→190 (ready activates) —
    toasts fire after transition completes, not at press moment.
B6: CTA render gate widened from (idle||sending) to (!=confirming && !=success) so
    SmartPayButtonView renders during connecting/switching/sending phases.

* chore(video): scenes.ts round-9a-patch2 — durations rebalance + MAGIC_DUST_PEAK_FRAME=940

create 320→350 (+30fr, C4 generating hold)
share 260→300 (+40fr, C5 extended copy hold)
thesisOutro 175→105 (-70fr, funds S1+S2 per Ignat directive)
pay 575 unchanged (C7 is internal reshuffle only)
TOTAL_DURATION=1350 locked; black tail=10fr preserved.
MAGIC_DUST_PEAK_FRAME: 860→940 (S3 single-press model, S-local peak midpoint 260 → global 940)

* feat(video): CreateScene round-9a-patch2 — always-mounted button + scroll trim + magic dust toggle + generating state + draft paper

C1: Remove FILL_COMPLETE mount gate — button always rendered in scroll content; canGenerate=false until FILL_COMPLETE (disabled visual until form fills).
C2: SCROLL_OFFSETS final -420 → -360; proportional intermediate keyframes updated (0, -120, -240, -360). Final endpoint to be verified via still at frame 258.
C3: magicDustEnabled: frame >= MAGIC_DUST_TOGGLE_FRAME (200) — toggle animates off→on after TOKEN_APPEAR=179.
C4: isGenerating={frame >= PRESS_END} — spinner + "Generating…" visible 307→350 (scene end).
C6: Path A — status="draft" (valid InvoicePaperStatus value; no production widget fork needed).

* feat(video): ShareScene round-9a-patch2 — extended copied state hold (80fr/2.667s feedback)

C5: QR_TAB_FROM_FRAME 150→190. COPY_CLICK_FRAME stays 110.
Copied state now visible frames 120-190 (70fr / 2.333s) before QR tab switches.
S2 duration funded the extra 40fr (260→300) without compressing QR window.

* feat(video): PayScene round-9a-patch2 — single-press model + retimed phases + magic dust 940 + toasts at transitions

C7: Remove PRESS_SWITCH, PRESS_PAY, PHASE_WRONG_NETWORK, PHASE_READY.
Phase walk: disconnected(0) → press(48) → connecting(50) → switching(130) → sending(200) → confirming(310) → success(440).
ctaPressTriggerFrame: single PRESS_CONNECT=48 only; pressScale clamps after +7fr.
Magic Dust: HIGHLIGHT=180, PEAK_END=320 (120fr peak straddles sending→confirming).
Toasts: T1=130, T2=200, T3=205+stackOffset=1 (staggered from T2 to avoid collision), T4=310, T5=440.
Snapshot tests: 237/237 payment, 56/56 invoice-form, 157/157 payment-panel — all byte-identical.

* fix(video): PayScene round-9a-patch3 — remove redundant Sending toast (D1)

* fix(video): RemotionFakeToast round-9a-patch3 — below-panel anchor aligns to panel LEFT edge (D2)

* fix(video): PayScene round-9a-patch3 — InvoicePaper flips to paid at confirming (D3)

* fix(video): RemotionFakeToast revert below-panel anchor to right-edge alignment (D2 reverted)

* feat(video): add VoidPayDemo-9x16 primary composition + RemotionAuroraText component

Round 9c C1+C2: add portrait 1080×1920 composition as primary (phone-first GTM per L1).
VoidPayDemo-16x9 becomes secondary with comment noting round 9d will re-derive layout.
RemotionAuroraText: frame-driven gradient text (no CSS animations) matching landing
aurora colours — violet-500/indigo-500/purple-500, 5-stop 200% sweep, deterministic.

* feat(video): ThesisHookScene + ThesisOutroScene aurora-gradient thesis (round 9c L4)

C3: ThesisHookScene wraps both beats in RemotionAuroraText with phaseFrames=30 stagger.
Adaptive fontSize: 84px portrait / 72px landscape.
C4: ThesisOutroScene wraps "Cryptographic receipts." in RemotionAuroraText; "Not audit
logs." stays dim white for visual hierarchy. url-pill "voidpay" gets gradient with
phaseFrames=45. Adaptive heroFontSize 110/96, urlFontSize 42/36 for portrait.

* feat(video): ShareScene full-bleed paper backdrop + tab slide (round 9c L2 L5)

* feat(video): PayScene bottom-sheet panel + paper backdrop + pre-CTA exit (round 9c L2 L3 L6)

* feat(video): CreateScene portrait re-layout (round 9c L7)

* feat(video): ShareScene floating-center modal + solid bg (round 9c-β1 β3)

* feat(video): PayScene floating-center panel + revised exit (round 9c-β1 β3)

* feat(video): CreateScene paper backdrop + form vertical dominance (round 9c-β2 β3 β4)

* feat(video): ThesisHookScene + ThesisOutroScene NetworkBackground (round 9c-β6)

* feat(video): CreateScene true-center form + scale + single neon (round 9c-γ1 γ2 γ3)

* feat(video): ShareScene true-center modal (round 9c-γ4)

* feat(video): PayScene true-center panel + 3× paper-alone window (round 9c-γ4 γ6)

* feat(video): RemotionFakeToast top-center portrait positioning (round 9c-γ5)

* fix(video): round 9c-δ — form z-stack + tail bg + ts unused-vars cleanup

- CreateScene: add zIndex: 2 to form Card so it renders above PaperBackdrop (z=1)
- VoidPayDemo: set AbsoluteFill background to #000 so fade() composites against black (no white tail frames 1336-1349)
- ShareScene + PayScene: remove unused width/height from useVideoConfig() destructure (TS6133)

* feat(video): CreateScene drop transform-scale + font-size CSS + right-pad (round 9c-ε1)

* feat(video): ShareScene RemotionLinkTab fork + Copy Link primary + drop QR tab (round 9c-ε2)

* feat(video): ThesisOutroScene delay text entrance 12fr (round 9c-ε3)

* feat(video): RemotionFakeToast bigger text + hold (round 9c-ε4)

* feat(video): PayScene panel size reduction (round 9c-ε5)

* feat(video): CreateScene paper backdrop scrim (round 9c-ε6)

* fix(video): CreateScene overflow axis split (round 9c-ζ1, fix Iris BLOCKER)

overflowX:visible preserves right-column TOTAL visibility (ε1 intent).
overflowY:hidden clips form content at Card bottom so "Generate Invoice
Link" button and "Generating..." state are no longer clipped at the
viewport bottom (f280/f410). Fixes ε1 regression introduced in round 9c-ε.

* fix(video): ShareScene modal vertical balance + "URL = invoice." caption (round 9c-ζ3+ζ4)

ζ3: Shift modal top 50%→48% — paper mass creates visual top-heaviness;
48% places modal in the visual center of the dark space below the paper.
Spring (damping:200) confirmed settled by f20, no oscillation at f480.

ζ4: Add Caption "URL = invoice." (top, startAt=60, endAt=250, fontSize=38).
Content Anchor #3 — names the architectural fact that the URL IS the
invoice, not a link to one stored on a server. Appears after modal lands,
persists through Copy click at ~f120, fades before quiet hold.

* feat(video): PayScene "Not our servers." caption (round 9c-ζ5)

Add Caption "Not our servers." (top, startAt=460, fontSize=38, no endAt).
Content Anchor #1 — enters 20fr after T4 "Payment received" toast fires
(f440), reframing the confirmed payment as a privacy proof: the chain
confirmed it, not VoidPay servers. Persists to scene end through paid
invoice paper reveal window.

* feat(video): HintBadge component for inline annotations

Spring fade-in (smooth config) + linear fade-out, two variants: ghost
(violet text only) and arrow (violet text + dark pill). API mirrors
Caption.tsx — startAt/endAt frame window, absolute style prop for
caller-controlled placement.

* feat(video): CreateScene η1+η2+η6+η7 (No signup caption + 3 hints)

η1: Caption "No signup." bottom position frames 280–340 (Spark Beat 11,
button reveal moment — answers viewer's account question).
η2: HintBadge "+ 0.000042 ← magic dust" arrow variant frames 220–280
(R1: startAt=220, 20fr after PAPER_APPEAR=200 to avoid paper-reveal
collision).
η6: HintBadge "any address, no KYC" arrow variant frames 115–175 (near
wallet field during recipient typewriter cascade).
η7: HintBadge "auto-generated" ghost variant frames 65–95 (near Invoice
No field, early cascade appearance).

* feat(video): PayScene η3+η4 (Open link Pay caption + Magic Dust hint)

η3: Caption "Open link. Pay." top position frames 15–80 (Spark Beat 18,
scene framing before Connect Wallet press; startAt=15 per R3 to let
cardScale spring animate before caption enters).
η4: HintBadge "unique micro-amount ← payment ID" arrow variant frames
210–300 (during MAGIC_DUST_HIGHLIGHT violet glow window, below panel
centered; exits before T3 Confirming toast at 310).

* feat(video): ShareScene η5 (invoice data hint on URL hash field)

η5: HintBadge "invoice data →" ghost variant frames 80–160 (Spark Beat
15; R2: startAt=80, 20fr after ζ4 "URL = invoice." caption enters at 60,
avoids 3-layer density peak; exits at 160, before quiet hold at 250).
Positioned bottom-right of permalink box pointing at the hash fragment,
reinforcing the ζ4 caption's "URL = invoice" thesis.

* feat(video): HintBadge readability bump (round 9c-θ3)

Default fontSize 15→20px (floor for 9:16 portrait phone playback per
ui-ux-pro-max mobile-first rules). Arrow variant: darker bg (0.75→0.88
opacity), stronger violet border (0.35→0.55), proportional padding
(4px 10px→6px 14px). Font weight 500→600. Color rgba(139,92,246,0.9)→
rgba(167,139,250,1) — full saturation for WCAG contrast floor.

* feat(video): RemotionFakeToast bottom positioning (round 9c-θ7)

Portrait toasts move from top-center to bottom-center. Top zone is now
exclusively reserved for Caption.tsx pills. Slide direction reversed:
enters from below (+100px), exits drifting down (+60px). Landscape
behavior unchanged (right-side slide). Cross-impact: η1 and η4 hints
repositioned in their respective scenes.

* feat(video): RemotionLinkTab restore production density (round 9c-θ5)

Reverts ε2 simplification (Copy Link only). Restores full production
ShareModal LinkTab density: color-coded permalink (protocol/domain/path/
hash color-coded matching production), Copy Link primary CTA, 3-col
social share row (Telegram/Twitter/Email with production color scheme),
OG toggle (amber), Privacy by design note. Adds ogEnabled prop for
narrative OG state. No animate-* Tailwind, no browser hooks — Remotion
render path safe.

* feat(video): CreateScene θ1+θ2+θ4 — header, width, paper centering + η1 reposition (round 9c)

θ1: Add 'Invoice Details' header at top of form Card matching production
InvoiceFormView page header (violet 'Invoice' + white 'Details', 22px
bold, divider border below).

θ2: Form width reduced from min(800,74%) to min(560,52%) — ~67% of
prior width. Base font-size bumped 20px→26px proportionally to preserve
visual mass per field. Sub-label override floor raised 16px→18px. Form
now reads as focused central column with breathing room for paper
backdrop on both sides.

θ4: PaperBackdrop vertical centering balanced — paper now centered in
[80px, height-100px] band (caption zone top, toast zone bottom) so top
margin equals bottom margin.

η1 cross-impact (θ7): 'No signup.' caption moved bottom→top. Bottom
zone is now reserved for toasts after θ7 move.

* feat(video): PayScene θ6 panel +1.5× + η4 reposition (round 9c)

θ6: PANEL_WIDTH 520→780 (1.5× per spec). Reverts ε5 reduction. Drops
×0.92 scale wrapper — panel now renders at full production size. Panel
occupies ~72% of 1080 viewport matching production PaymentPanel
proportions.

η4 cross-impact (θ7): 'unique micro-amount ← payment ID' hint moved
from bottom:28% to top:80. bottom zone now has toasts (θ7). Top zone
clear at f210-300 — η3 exited at f80, ζ5 starts at f460. fontSize
bumped 14→20 to match θ3 HintBadge default floor.

* feat(video): ShareScene θ5 modal density + η5 reposition (round 9c)

θ5: Modal width 512→600 to accommodate full production density. Adds
tab bar (Link/QR Code) above RemotionLinkTab — Link tab active before
COPY_CLICK_FRAME (f110), QR Code tab active after, demonstrating
tab-switching in scene. Reverts ε2 'info overload' simplification per
user override (density wins).

η5 cross-impact: 'invoice data →' hint repositioned top:28→top:8 to
account for wider modal. fontSize 13→15 (above legibility floor).

* feat(video): HintBadge text ×2 (round 9c-ι4)

Default fontSize 20→40px, arrow padding 6px 14px→12px 28px.
Callers with layout constraints pass explicit override (e.g. η5=24px).

* feat(video): CreateScene form internals ×1.3 (round 9c-ι1) + η hint bump

Base fontSize 26→34px, sub-label override 18→23px, Invoice Details header
22→29px with proportional margin/padding. η7/η6/η2 hint fontSize 14→28px
(×2 per ι4 rule). Card outer width unchanged at θ2 560px.

* feat(video): RemotionLinkTab modal internals ×1.5 (round 9c-ι2) + η5 adjustment

RemotionLinkTab: all text/spacing/heights ×1.5 (Permalink label 11→17px,
URL box 11→17px, Copy Link button 14→21px h52→78, social row 12→18px h40→60,
OG/privacy 11-12→17-18px). ShareScene: modal width 600→660px (+10% to absorb
scaling), header 20→30px, subheader 14→21px, tab height 34→44px fontSize 13→20px,
section paddings scaled. η5 exempted from ×2: 15→24px (×1.6) — right:12 top:8
position inside permalink wrapper cannot fit 30px without overflowing above bounds.

* feat(video): PayScene panel internals scaled (round 9c-ι3) + η4 ×2

Panel wrapper fontSize:24px drives em-cascade into PaymentPanel internals
(24px = 1.5× browser default 16px). Panel outer width unchanged at θ6's 780px.
η4 hint fontSize 20→40px (×2 per ι4), top nudged 80→90px to avoid edge clip.

* fix(video): F1 ThesisHook cross-fade window symmetric (κ-1)

Widen beat1 fade-out from [30,36] to [30,48] so it matches beat2's
fade-in window. At f39 both beats are ~50%, producing a true
symmetric cross-fade. Fixes RC-2 BLOCKER from p21 diff-report.

* Revert "fix(video): F1 ThesisHook cross-fade window symmetric (κ-1)"

This reverts commit a35ac2026571b14b84c163ab3ae66b7a26ded5b7.

* fix(payment-panel): voice-gate compliant CTA copy (κ-1 RC-3)

Changes success-state CTA from "Create your own invoice with VoidPay" to
"Create an invoice" per voice-guide §"We Don't Say" (no possessive, no
brand-drop). Conversion impact expected neutral; Spark to review post-deploy.

* fix(video): demo invoice Bill-To matches form (κ-2 RC-5)

Paper Bill-To now reads 'Acme Corp' to match the form's typed value, fixing the F4→F12 data inconsistency reported in the p21 diff.

* fix(video): PayScene 5-beat timing reshuffle (κ-3 RC-1)

Phase window changes (S3-local frames):

| Phase      | Old window  | New window  | Delta |
|------------|-------------|-------------|-------|
| idle       | 0–50        | 0–90        | +40fr |
| PRESS_CONNECT | 48       | 85          | +37fr |
| connecting | 50–130      | 90–170      | +40fr |
| switching  | 130–200     | 170–240     | +40fr |
| sending    | 200–310     | 240–340     | +40fr |
| confirming | 310–440     | 340–470     | +30fr |
| success    | 440–575     | 470–575     | +30fr |
| MAGIC_DUST_HIGHLIGHT | 180 | 240      | +60fr |
| MAGIC_DUST_PEAK_END  | 320 | 390      | +70fr |
| PANEL_EXIT | 495–515     | 525–545     | +30fr |

Key fixes:
- Idle window 50→90fr: B1 Connect Wallet beat now visible through crossfade entry
- paperPaid: confirming||success → success only: B4 (confirming) shows pending
  paper + progress bar, visually distinct from B5 (paid paper + success panel)
- All captions/hints/toasts shifted to match new phase boundaries:
  ε3 endAt 80→88, η4 startAt/endAt 210-300→255-345, ζ5 startAt 460→490
  T1 130→170, T2 200→240, T3 310→340 (hold 90→140), T4 440→470
- S3 total duration 575fr unchanged; TOTAL_DURATION 1350 unchanged

* fix(video): hint repositioning — η6 + η2 + η5 (κ-4 RC-4)

η6: move "any address, no KYC" above wallet field label (was at 0.28×height, overlapping address text; now 0.16×height in clear annotation zone)
η2: move "+ 0.000042 ← magic dust" to right-anchored outside form card (was 0.30×width inside form pointing at fields; now right:16 with ← pointing at paper TOTAL column)
η5: move "invoice data →" outside Card overflow:hidden clip (was inside relative div at right:12 top:8 — never rendered; now AbsoluteFill-level at permalink box zone, calc(48%-90px))

* fix(video): QR tab body sync (κ-5 RC-6)

Tab indicator flipped to QR Code at COPY_CLICK_FRAME but body always rendered
RemotionLinkTab (permalink view) — no RemotionQRTab existed. Fix: create
RemotionQRTab (QRCodeSVG + scan hint + Download QR button, production-parity) and
swap body in sync with tab indicator at the same frame. Copied! flash fires 10fr
before swap so Link tab shows affordance before QR transition.

* feat(video): unified NetworkBackground orb layer (import point #1)

Create NetworkBackgroundLayer.tsx with Mocks v2 .nb-orb formula (inline
styles, absolute positioning, Remotion-safe). Mount in all 5 scenes:
strong variant (55% orbs, blur 56px) for Hook/Outro, soft variant
(50% orbs, blur 48px) for Create/Share/Pay content scenes.

* feat(video): import F1 thesis-hook hero layout + typography (#2)

Replace single-line cross-fade with Mocks v2 hero structure: VoidPay
mono pre-line, two-line H1 (dimmed "The invoice" + aurora "is the URL."),
and sub-text. Beat timing (0-18/30-48) unchanged; layout now uses
flex-column centering per mock .hero spec. Font sizes ×3 of mock's
360px design viewport.

* refactor(video): rebuild HintBadge with v2 design tokens (#3, style only)

Replace ghost/arrow pill with Mocks v2 .hint spec: zinc-900 background,
violet-700 border, triple box-shadow, leading violet dot with glow, inline
→/← arrow spans in violet-300. Font sizes proportional to fontSize prop
(mock values ×3 for 1080 viewport). Variant prop kept for API compat.

* chore(video): reposition hints per Mocks v2 anchors (#3, positions)

Switch all hint positions from form-relative px math to percentage anchors
matching mock's 360×640 design viewport. Update hint copy to canonical
Mocks v2 text: η7 "No DB → link is the data", η6 "Your wallet. No KYC.
No bank.", η2 "Magic dust → unique payment ID", η5 "invoice data → in
the hash", η4 "unique micro-amount ← payment ID".

* feat(video): apply Mocks v2 sizing/typography to CreateScene form (#4)

Card background rgba(14,14,19,0.95), border rgba(63,63,70,0.5),
border-radius 12px, shadow 0 16px 50px rgba(0,0,0,0.5) — matching
mock .form spec. Header updated to "/ Create invoice" with Geist Mono
slash prefix (zinc-500) + bold sans title per mock .form .h pattern.

* feat(video): paper blur+dim when modal/CTA foregrounded (#5)

CreateScene F5 (Generate pressed): paper dims 0.65→0.4, blur 0→0.5px
over 8fr ramp starting at PRESS_START. ShareScene F6-F8: paper
dimOpacity 0.35→0.3, blurPx 1.5→2.0 across COPY_CLICK_FRAME. PayScene
paper stays at 1.0 (paper is co-equal in S3 per spec §5 table).

* feat(video): browser chrome (BrowserChrome component) for PayScene (#6)

New BrowserChrome.tsx renders mock .chrome spec: dark bar at top:0,
traffic-light dots (red/amber/green), URL pill with lock emoji + violet
host + zinc path. Mounts across full S3 duration with 20fr opacity ramp.
Also includes WalletPill.tsx stub (C7) — both needed in PayScene import.

* refactor(video): align Caption to v2 design + emerald success variant (#8)

Rebuild Caption with Mocks v2 .caption spec: rgba(20,20,27,0.85) bg,
backdrop-filter blur(8px), violet-400/45 border, 0 0 24px glow, top
anchored at 114px (38px mock × 3). Add emerald variant for success
state — emerald-400 text/border/shadow. Wire PayScene "Not our
servers." caption to emerald variant.

* feat(video): rebuild ThesisOutro with v2 hero + center-block layout (#9)

Replace "Cryptographic receipts / Not audit logs" copy with Mocks v2
F13 structure: mono pre-line "No accounts · no DB · no servers", full
aurora h1 "The invoice\nis the URL.", sub "Open. Pay. Done.", voidpay.xyz
wordmark. All 4 elements form one centered flex-column block — drops
margin-top:auto on wordmark per Ignat centering directive.

* refactor(video): center-anchoring per Mocks v2 (#10, partial)

PayScene: paper sits at top:64px below browser chrome (CHROME_HEIGHT
constant), centered in remaining viewport. ShareScene: paper backdrop
uses true vertical center (height-scaledH)/2 — was biased upward
by -80px to clear modal at bottom; modal now uses top:50% transform
per Mocks v2 .paper anchor.

CreateScene PaperBackdrop deferred — atlas exhausted context before
applying same true-center pass. Visual diff will reveal whether it
needs the same treatment or stays as-is.

* fix(video): F1 thesis hook — full phrase visible from frame 0 (drop cross-fade)

* feat(video): RemotionInvoiceFormSkin — internal form styles from Mocks v2

* feat(video): RemotionShareModalSkin — modal fonts/sizes from Mocks v2

* feat(video): RemotionPaymentPanelSkin — panel fonts/sizes from Mocks v2

* fix(video): PayScene paper blurred while panel foreground; sharp at F12 paper-alone (#6 corrected)

* chore(video): re-render p24 assets (post-style-internal-import)

* fix(video): F1 muted "The invoice" text more visible (opacity 0.35 → 0.50)

* refactor(video): revert form skin — production InvoiceFormView with surgical width/padding from Mocks v2

* refactor(video): revert share modal skin — production component with width/padding + F8 text sizes

* refactor(video): revert payment panel skin — production PaymentPanel with width/padding + F10 text sizes (spinner kept at frame*8)

* chore(video): re-render p25 assets (post-skin-revert + surgical overrides)

* fix(video): confirming beat outside panel + dust halo + panel exit + voice-gate (Phase 1-2)

C3 (F1.A2): RemotionPaidConfirmationProgress rendered outside PaymentPanel — it was
  wired as children but PaymentPanel.children only renders when isPending=true; during
  confirming isPaid=true so children never appeared. Now overlaid below panel.

C4 (F1.C1): Magic dust halo replaced with anchored bottom-right ellipse (blur 14px)
  per Mocks v2 spec. Text-shadow injection on dust digits via .remotion-dust-glow style.

C6 (F2.A4): panelExitOpacity window shifted 525-545 → 505-525 (20fr earlier),
  giving paper-alone window 525-575 = 50fr (1.67s) vs previous 30fr.

C7 (F2.D1): CreateYourOwnCta link suppressed via CSS (.remotion-pay-panel a[href="/create"])
  — voice-gate violation (self-referential CTA in a product demo video).

C13 (F4.3): .text-xs floor raised to 24px inside .remotion-pay-panel — payment widget
  secondary text was sub-10px illegible at 9:16 mobile preview scale.

* fix(video): F7 sub-line 24px + F8→F9 tab swap cross-fade 8fr (Phase 4 iris polish)

C12 (F4.2): InvoiceSummary secondary text (.text-xs) forced to 24px inside
  .remotion-summary-override wrapper — was rendering ~9px illegible at 9:16 mobile scale.
  Color bump zinc-500 → zinc-400 (#a1a1aa) for better contrast.

C14 (F4.4): Link→QR tab body transition cross-fades over 8fr using interpolate
  opacity drivers (linkTabOpacity / qrTabOpacity). Previously hard-cut at COPY_CLICK_FRAME,
  now reads as a natural UI interaction. Tab indicator retains crisp swap (no blur on chrome).

* chore(video): re-render p26 assets (followup BLOCKER pack + iris polish)

* style(video): ShareScene Link tab dominant timing (COPY_CLICK_FRAME 110→200)

- COPY_CLICK_FRAME: 110 → 200 (Link tab dominant 0-208 ~6.9s, QR demonstrative 200-300 ~3.3s)
- Updated comment to reflect new pacing rationale (Ignat 2026-05-11)
- Caption "URL = invoice." endAt: 250 → 290 (lingers ~1.3s into QR tab, reinforcing URL=invoice as viewer sees QR)
- TAB_CROSSFADE_DURATION=8 unchanged
- PaperBackdrop (T3c) true-center untouched — canonical reference for atlas-A/C

* style(video): CreateScene Tailwind cascade ×2 + paper true-center (Mocks v2)

* refactor(video): PayScene cascade ×2 + flat panel (no shadow/border) + paper true-center

T4a: Replace minimal CSS block with full Tailwind ×2 cascade scoped to
.remotion-pay-panel (text-xs→text-4xl, h-7→h-11, w-3→w-6, padding,
gap, border-radius). Drop outer fontSize:"24px" → fontSize:"inherit".
Keep a[href="/create"] display:none (voice-gate CTA suppression).

T4b: Remove boxShadow + zinc border from panel div wrapper.
PayPanel becomes flat modal on dark bg — matches Image 3 mock per
Ignat 2026-05-11 17:43.

T4c: PaperBackdrop true-center alignment — replace chrome-offset
formula with canonical top = (height - scaledH) / 2 (identical to
ShareScene). Drop unused CHROME_HEIGHT constant.

* style(video): CreateScene HintBadge chips fontSize 28→34 (×1.2 vs body cascade)

* style(video): Thesis intro/outro text colors match landing Hero (D1+D11)

Split H1 rendering in ThesisHookScene and ThesisOutroScene:
- "The invoice" → bold white (#FFFFFF), was muted grey/aurora
- "is the URL." → RemotionAuroraText violet aurora (unchanged in Hook, fixed in Outro)

* style(video): PayScene cascade strict matches production sizes (D8)

Add h-12/h-14 for Connect Wallet button (production uses h-14 via Button
size="lg"), w-11/h-11 for minimize icon, px-4/px-6/py-0.5/pt-5/pr-12,
gap-2.5/gap-0.5, space-y-2/space-y-4 vertical rhythm, rounded/rounded-full,
and a shadow/border strip on [data-testid="payment-panel"] to cancel
PaymentPanel's own shadow-[...] and conditional border-emerald classes.

* style(video): CreateScene header matches production InvoiceFormView (D2)

Replace "/ Create invoice" (grey slash prefix) with violet "Invoice" +
white " Details" to match production CreateWorkspace header pattern.
Remove now-unused FONT_MONO import from CreateScene.

* fix(video): PayScene flat panel + drop reorg overlay (D9+D10)

D9: add [data-testid="payment-panel"] box-shadow/border strip in cascade
to cancel PaymentPanel's own shadow-[...] and isPaid border-emerald class.

D10: delete "Protecting against chain reorgs" JSX overlay block (step===
'confirming'), remove unused RemotionPaidConfirmationProgress import and
orphaned confirmingProgress interpolate declaration. Component source file
RemotionPaidConfirmationProgress.tsx is left untouched.

* style(video): ShareScene cascade + Copy button violet + gaps match production (D6+D7)

D6: extend remotion-summary-override cascade to scale amount sum (text-base/lg→36px),
network chip (text-xs→22px), inner padding/gap; add violet inset underline on active tab.
D7: increase RemotionLinkTab section gap 21→30px for production-parity vertical spacing.
Copy button violet gradient was already correct; gaps and amount sizing now match Image #13/#15.

* fix(video): CreateScene date icons + extended scroll past Token & Network (D3+D5)

Atlas-B leftover from round-9e Phase 1 — committed by Kai after atlas timeout
during verification phase. Code passes type-check + lint clean.

D3: SVG icons inside text-[10px] labels — cascade override 24x24px to match
production calendar icons in date inputs.
D5: SCROLL_FRAMES extend 188->195, SCROLL_OFFSETS extend -360->-900, drop
height:100% + overflowY:hidden so cascade-2x form scrolls past Token & Network
into Notes/Currency block.

* fix(video): PayScene strip residual emerald border + gradient bar (D9 deeper)

Atlas-D leftover from round-9e Phase 1 — committed by Kai after atlas timeout
during verification phase. Code passes type-check + lint clean.

D9 (deeper): T4b first pass cleared border/shadow but left:
- Emerald conditional border (border-emerald-500/30 from PaymentPanel isPaid state)
- Top gradient bar from PaymentPanel chrome

Strip via:
- Multiple-specificity .remotion-pay-panel selectors zeroing border-width/style/color
- [data-testid=gradient-bar] display:none
- Inner padding wrapper around <PaymentPanel> so outer overflow:hidden clips
  any conditional border flush to our rounded corners (padding moved from outer
  to inner to maintain visual inset while clipping panel's own border)

* fix(video): HintBadge intrinsic width + chip anchor inside viewport (D4)

Outer wrapper: add display:inline-block so right:-anchored chips shrink
to content width instead of stretching to full block width.
Inner chip: remove maxWidth:540px cap that caused nowrap text to visually
overflow the pill border on longer chip texts (chip 3: 31 chars at 34px).
All 3 chips now render with full pill border + text inside 1080px viewport.

* style(video): ShareScene tabs underline-only style (D16)

Remove grey background fill from active tab; keep violet inset box-shadow
underline and bold text as the sole active indicator, matching production
ShareModal tab design.

* fix(video): PayScene drop outer dark frame (D17)

Outer panel div had backgroundColor rgba(24,24,27,0.96) with padding:0,
causing a visible dark border around PaymentPanel where the inner padding
wrapper created a gap. Set outer backgroundColor to transparent — inner
PaymentPanel provides its own background; viewer sees through to scene bg
in any gap region.

* fix(video): PayScene spinner rotation rate + drop extra Sending loader (D18+D19)

D18: SmartPayButtonView's CSS animate-spin class is a real-time CSS animation
(non-deterministic in Remotion). Override with animation:none + frame-driven
rotate(frame*8deg) = 240deg/s = 1 rev/1.5s, matching production speed exactly.

D19: Removed the extra centered overlay spinner that rendered during sending step
inside PaymentPanel. The spinner was an absolute-positioned DIV overlapping the
entire panel center. SmartPayButtonView already renders its own button-inline
spinner for the sending state — the overlay was a duplicate.

* style(video): PayScene Payment Successful block sizing (D20)

Two cascade gaps caused mis-proportioned success state:
1. w-12 missing from width cascade — checkmark circle was 96px tall
   (h-12 overridden) but only 48px wide (Tailwind default 3rem).
   Added w-12: 96px to keep circle square.
2. CheckCheckIcon/CheckIcon use size={24} prop (absolute px, bypasses
   Tailwind cascade). Added .h-12.w-12 svg override to 48x48px so the
   icon fills the scaled container proportionally.

* style(video): CreateScene icon cascade + unified scroll to Generate button (D15)

Problem A: Icons using size={N} prop (CoinsIcon/FingerprintIcon/NetworkIcon/TokenIcon/
Share2Icon/ArrowRightIcon) rendered SVG width/height attributes directly — not caught by
the Tailwind w-N/h-N class cascade. Added svg[width="N"] attribute selectors scaled ×2
for sizes 12/16/20/24px under .remotion-create-portrait.

Problem B: Single master translateY interpolation extended with 5th keyframe
[265, -2000] so the scroll completes before BUTTON_VISIBLE=280. Generate button
fully in view at frame 270. No secondary translateY motions stacked.

* style(video): PayScene Exact amount magic dust text size (D25)

Add text-[9px] cascade entry (22px) to .remotion-pay-panel so MagicDustBadge
"Exact amount: 250.000042 USDC" line renders at readable size. Previous cascade
covered text-[10px]/text-[11px] but missed the [9px] class used in MagicDustBadge.

* refactor(video): CreateScene unified scroll audit + endpoint clamp (D21)

Audited all interpolate/translateY sources: confirmed single Y-motion driver
(line 256). Previous -2000px endpoint overshot — Generate button scrolled
off the top of the card before BUTTON_VISIBLE=280. Calibrated to -1100px
so button lands flush at card bottom at f280.

* style(video): ShareScene tabs + Copy button match production exactly (D24)

Tabs: replace violet underline with dark card active state (bg-background
zinc-900 pill + box-shadow), matching TabsTrigger data-[state=active] in
production. Solid container opacity 0.6→1.

Copy button: replace solid violet gradient with production Button
variant=void — black bg, electric-violet/30 border, subtle violet glow
shadow, with CopyOverlay radial gradient (violet idle / emerald success).

* fix(video): CreateScene Generate spinner rotation rate normalize (D23)

frame * 10 → frame * 8: 240 deg/s @ 30fps = 1.5s/rev, matching
production animate-spin. Pattern consistent with PayScene D18 fix.
D22: GenerateButtonView already uses production glow variant (bg-violet-600)
with Share2Icon+ArrowRightIcon — cascade confirmed correct, no change needed.

* feat(video): ShareScene landscape two-column layout (D12+D13+D14)

Implements 16:9 two-column layout for ShareScene via useVideoConfig()
width>height branch. Left column: InvoicePaper backdrop scaled to
containerWidth=(width/2). Right column: Share modal capped at 640px.
Caption stays at AbsoluteFill level spanning full viewport. Portrait
(9:16) path unchanged — verified with stills at f450 and f600.

* feat(video): CreateScene landscape two-column layout (D12+D13+D14)

- isLandscape (width > height) gate renders separate AbsoluteFill with
  paper LEFT column and form RIGHT column (maxWidth 640px)
- PaperBackdrop accepts columnWidth prop to scale within left half-viewport
  using 0.85× factor instead of 0.92× portrait full-width
- HintBadges moved inside right-column wrapper for landscape; scaled to
  fontSize=22 to fit column proportions
- Portrait (9x16) branch untouched — identical rendering verified at f150/f275

* feat(video): PayScene landscape two-column layout (D12+D13+D14)

- useVideoConfig() isLandscape branch: paper LEFT, PaymentPanel RIGHT
- BrowserChrome full-width top overlay over both columns
- WalletPill anchored to full-viewport top-right (not column-confined)
- PaperBackdrop: added containerWidth/containerHeight/offsetTop props for column-scoped layout
- Magic dust halo pixel-anchored to paper totals area in left column
- Portrait (9x16) render path unchanged — verified identical to p30
- panelCascadeStyle / panelBorderStrip / paymentPanelContent factored to shared variables (DRY)
- PANEL_MAX_WIDTH=640, CHROME_HEIGHT=51 module constants

* fix(video): ShareScene instant tab swap (no blink) (D27)

TAB_CROSSFADE_DURATION 8→1: eliminates the mid-swap frame where both
Link and QR tab bodies were at ~0.5 opacity simultaneously, causing
the visible "blink". Tab indicator already swapped instantly via
showQR binary; body now matches.

* fix(video): CreateScene Magic Dust toggle visual render (D26)

Switch thumb was rendering at mid-track (overlapping circles) because:
1. The ×2 portrait cascade scaled track to 80px but translate-x-5 stayed
   at 20px — thumb was mid-track instead of right edge.
2. CSS transition-transform on thumb was rendering at an intermediate state
   since Remotion renders static frames.

Fix: add cascade rules under .remotion-create-portrait [role="switch"] to
null all transitions and hard-set thumb position via translateX(44px) for
aria-checked=true (80px track - 32px thumb - 4px inset = 44px).

* fix(video): PayScene ALL spinner instances rotation rate normalize (D28)

Extend frame-driven spinner cascade to cover all three Tailwind
animate-spin variants used across PaymentPanel widget components:
- motion-safe:animate-[spin_1.5s_linear_infinite] (SmartPayButtonView)
- motion-safe:animate-spin (SecondaryActions, StatusBadge, PollingStatus)
- animate-spin (fallback)

All three now get animation:none + transform:rotate(frame*8deg) so no
spinner runs at CSS keyframe speed in Remotion render.

* style(video): PayScene magic dust + footer icons sizes (D29)

Add svg[width="N"] cascade selectors for lucide icons rendered via
size={N} prop (SVG attribute, not Tailwind class):
- FingerprintIcon size={10} in MagicDustBadge → 20px
- DownloadIcon/QrCodeIcon/FlagIcon size={12} in PanelFooter → 24px
- Loader2Icon size={14} in PollingStatus → 28px

Production-parity ratio: text-xs cascades to 24px; icons scale 2× to match.

* fix(video): CreateScene Magic Dust toggle design refinement (D30)

Root cause: w-10 track width was missing from portrait cascade (only
w-3..w-6 covered), leaving the track at 40px wide × 40px tall — a
square pill instead of the intended 2:1 ratio. Also fixes OFF-state
translateX: was 2px (double-counting left-0.5 base inset), now 0px.

Changes:
- Add .w-10 → 80px to portrait cascade (track width now 80px × 40px)
- OFF state: translateX(0px) — left-0.5 naturally provides 2px inset
- ON state: translateX(44px) unchanged (80 - 32 - 2 - 2 = 44px math correct)

* fix(video): PayScene restore top gradient bar on PaymentPanel (D31)

Removed overly-aggressive `display: none !important` rule on
`[data-testid="gradient-bar"]` that was hiding the violet→emerald
top stripe on the payment panel.

Replaced with:
- `height: 12px !important` on the gradient bar (h-1 = 4px production
  is invisible at video resolution; 12px is visible without being
  disproportionate)
- `animation: none !important` on `motion-safe:animate-pulse` to prevent
  CSS flicker at video FPS (gradient bar uses this class when pending)

Both portrait (9x16) and landscape (16x9) affected via shared panelBorderStrip.

* fix(video): PayScene kill text pulse animation + larger spinner (D32)

Two fixes for connecting/sending button state in Remotion video:

1. `animate-breathing` override: SmartPayButtonView applies
   `motion-safe:animate-breathing` to the text label span during
   in-progress states. CSS animations run at arbitrary speed in Remotion
   (not frame-locked), causing scale-pulse flicker. Killed with
   `animation: none !important`.

2. Spinner size bump: Loader2Icon uses `size={18}` SVG prop (px attribute,
   not Tailwind class). Added `svg[width="18"]` cascade entry mapping to
   48px — consistent with w-6/h-6 (48px) territory and visually proportional
   to the scaled-up button text.

* fix(video): ShareScene tab swap layout stability (D33)

Pre-mount QR tab one frame before swap (COPY_CLICK_FRAME-1) so QR content
is in the DOM at the exact swap frame. Switch Link tab to position:absolute
based on showQR flag (not linkTabOpacity float) so the container has a
stable height holder (QR, position:relative) at every frame — eliminates
the one-frame collapse that caused the stretch flicker on portrait and
landscape.

* fix(video): ShareScene landscape paper no-blur + top fit (D36+D37)

D36: clamp PaperBackdrop top to Math.max(16, centered) — at 16:9 the
paper (1123px tall at 0.92 scale) is taller than viewport height, giving
negative top and overflowing above screen edge.

D37: pass dimOpacity=1 blurPx=0 to landscape PaperBackdrop — landscape
layout uses paper as persistent side-by-side context, not a backgrounded
element, so blur/dim must never be applied.

* fix(video): PayScene D34+D35+D36+D37+D38 round-9j fixes

D34: emerald gradient bar override for data-status="paid" in panelBorderStrip
D35: WalletPill connected only after PHASE_SWITCHING (170) not PHASE_CONNECTING (90)
D36: landscape paper scale clamped by height (92% availableH) to prevent top overflow
D37: landscape paper no blur/dim filter (removed opacity/filter from left column div)
D38: PANEL_MAX_WIDTH 640→880 for proportional right column width

* fix(video): CreateScene landscape paper height fit + scroll budget (D36)

Paper: switch PaperBackdrop to height-driven sizing in landscape column mode
(availableHeight * 0.92 → derive width from A4 ratio) to prevent top/bottom
overflow on 16:9 (794×1123 paper at width-driven scale exceeded 1080px height).

Scroll: add SCROLL_FRAMES_LANDSCAPE / SCROLL_OFFSETS_LANDSCAPE with endpoint
-1160 (calibrated via stills) so Generate button is visible at BUTTON_VISIBLE=280.
Portrait SCROLL_FRAMES/SCROLL_OFFSETS unchanged — 9:16 unaffected.

* style(video): Caption visibility accent (D45)

Raise border opacity 0.45→0.75, weight 1px→1.5px, glow 0.25→0.45,
bg alpha 0.85→0.88, fontWeight 600→700. Add leading dot (12px filled
circle with glow) matching HintBadge chip signature. Double boxShadow
for stronger halo. Applies to all scenes using Caption.

* style(video): ThesisOutro voidpay.xyz non-glow color (D46)

Replace <RemotionAuroraText> wrapper on wordmark with plain violet-400
spans (#a78bfa). Both "voidpay" and ".xyz" use same color at fw700,
"voidpay" gets text-decoration underline. Calm, brand-aligned link
without animated aurora glow on final screen.

* fix(video): ShareScene paper canonical sizing landscape (D39)

Replace atlas-T Math.max(16, topCentered) clamp in PaperBackdrop with
Kai-locked canonical formula: PAPER_VPAD=48, scaleByH=availH/BASE_HEIGHT,
scaleByW=colW*0.85/BASE_WIDTH, scale=Math.min(scaleByW,scaleByH),
top=PAPER_VPAD+(availH-BASE_HEIGHT*scale)/2. Guarantees ≥48px top/bottom
margin and true centering in landscape column with no Math.max clamps.

* fix(video): PayScene paper canonical sizing landscape (D39)

Apply Kai-locked formula (PAPER_VPAD=48, availH excludes CHROME_HEIGHT,
Math.min scale, centered with padding) to landscape branch, replacing
the ad-hoc D36 formula. Column container heights kept as colH=height-CHROME_HEIGHT.

* fix(video): PayScene WalletPill truly post-connection-complete (D42)

Add PHASE_CONNECTED = PHASE_SENDING (frame 240) — the point after both
connecting (90) and switching (170) animations complete and tx send begins.
Apply to both portrait and landscape branches, replacing PHASE_CONNECTING
(portrait) and PHASE_SWITCHING (landscape) which fired too early.

* feat(video): extend Caption v2 API with kinetic typography mode

Add position "center"|number, weight 700|500, emphasizedWord, and
springConfig "smooth"|"overshoot" props per round-9l-spec §5/§6-A1.

New kinetic mode activates only when new props are used — existing
callers (pill chip UI) are fully backward-compatible.

Animation helpers extracted to Caption.helpers.ts:
- computeEntry: spring (700/overshoot) or bezier (500)
- computeExit: universal 5fr opacity fade, no translateY
- computeWordPopScale: scale 1→1.06→1 (700) or 1→1.04→1 (500)
- computeWordPopColorOpacity: white→violet over 4fr, holds 90%, 6fr out
- resolveYPercent: "top"=10% "bottom"=87% "center"=50% number=passthrough

* feat(video): add S1 Create caption arrays per round-9l spec

- New file: src/video/src/scenes/captions/create-captions.ts
  CaptionEntry type + CREATE_CAPTIONS_VERTICAL (4 entries, 9:16)
  and CREATE_CAPTIONS_LANDSCAPE (4 entries, 16:9) per §3/§4/§6-A3.

- CreateScene.tsx: replace single "No signup." Caption with
  aspect-aware captions loop using useAspect() + captions array.
  Both portrait and landscape paths updated. HintBadges η7/η6/η2
  (startAt 65/115/220) untouched.

* feat(video): add Pay scene caption arrays + drop hint η (A5)

- Create pay-captions.ts with PAY_CAPTIONS_VERTICAL (7) and PAY_CAPTIONS_LANDSCAPE (6)
- Magic Dust hero caption (S-local 220-340) uses springConfig overshoot, position 50% center
- Emerald variant activates from S-local 425 onward in both orientations
- Replace hardcoded Captions in PayScene with array-driven map (portrait + landscape)
- Remove HintBadge "unique micro-amount ← payment ID" from both branches (narrative duplication)

* feat(video): add S2 Share caption arrays and drop η5 HintBadge

Implements round-9l spec §3+§4 for ShareScene:
- create share-captions.ts with SHARE_CAPTIONS_VERTICAL (4 entries, 9:16)
  and SHARE_CAPTIONS_LANDSCAPE (4 entries, 16:9) arrays
- replace single legacy "URL = invoice." Caption with captions.map loop
  in both portrait and landscape branches
- remove η5 HintBadge ("invoice data → in the hash") from both branches;
  narrative covered by "Hash never leaves the browser." caption
- remove unused HintBadge import

* feat(video): add 6 hook-variant compositions + wire hookVariant prop

Round 9l (row A7): split VoidPayDemo into 6 compositions (3 hook
variants × 2 aspect ratios). Old IDs VoidPayDemo-9x16 and
VoidPayDemo-16x9 kept as v1 aliases for backward-compat.

- VoidPayDemo.tsx: add hookVariant prop (default "v1"), pass to ThesisHookScene
- Root.tsx: 6 named compositions (-v1/-v2/-v3 × 9x16/16x9) + 2 legacy aliases
- AC2: no <Audio> components in composition tree (silent video confirmed)

* feat(video): apply Path C pill backdrop to kinetic Caption mode

Kinetic mode now renders a dark pill wrapper (rgba(20,20,27,0.85),
blur(10px), violet/emerald border+glow, border-radius 28px) with an
18×18 leading dot and spec-canonical padding/gap. TranslateY entry
animation applies to the outer pill so the whole pill slides in/out.
Word-pop emphasized-word transition (white→#a78bfa scale 1→1.18→1)
is preserved. Compact path activates when fontSize<=80 (22px 44px /
18px gap). -webkit-backdropFilter added for Safari.

Legacy pill mode: unchanged.

* fix(video): round-9m PayScene — re-sequence S2→S3 timing, MD halo, captions, hint

- Blocker #1: re-sequence stepAt() — idle:disconnected 0-200, idle:connected 200-220,
  sending 220-310, confirming 310-440, success 440+ (was: connecting/switching intermediate steps)
- Blocker #2: paperPaid gate already correct (step==='success'); confirmed no regression
- Blocker #3: violet halo opacity now keyed to [220,240,310,330] per brief spec
- UI dim wrap: BrowserChrome+panel wrapped in opacity div [200,212,308,320]→[1.0,0.4,0.4,1.0]
- Caption ε3: "Open link. Pay." inline at S3-local 15→80 (portrait pos=920, landscape pos=80%)
- Hint η4: HintBadge "unique micro-amount ← payment ID" at S3-local 230→310
- Toast timings realigned: wallet-connected→200, network-switched→210, confirming→310, success→440
- Import: added HintBadge from ../components/HintBadge

* refactor(video): round-9p font shrink, drop ε3 inline, hint size down

Task A — caption font one register down (vertical only, landscape untouched):
- hero 86→72, sub 60→50 in create/share/pay/thesis caption data
- ThesisHookScene + ThesisOutroScene captionFontSize override 60→50

Task B — drop ε3 inline "Open link. Pay." from PayScene (landscape + portrait);
PAY_CAPTIONS_VERTICAL[0] already renders "Payer opens the link." in the same window,
so removing the duplicate eliminates the f15-70 overlap.

Task C — HintBadge size one register down:
- portrait 32→28 (PayScene η4, ShareScene η5, CreateScene 3×)
- landscape 24→22 (CreateScene 3×, PayScene η4)

* feat(video): round-9q caption and hint-badge overhaul

S0 (ThesisHookScene): hook window shortened 5→45; second caption
"Raw addresses look unprofessional." added at frames 50-85 (aspect-aware).

S1 (CreateScene): new caption arc — Create an invoice → No signup →
No account. No KYC. → Get a link. Both portrait and landscape arrays
rebuilt per round-9q spec. Inline ε1 "No signup." Caption removed.
Dead "Fill a form." filter removed.

S1/S2/S3: all 8 HintBadge JSX instances removed (3 portrait + 3 landscape
in CreateScene, 1 in ShareScene, 2 in PayScene). Three HintBadge imports
removed. Component file kept.

* chore(video): commit Round 9n leftover before develop merge

Preserves uncommitted prior-session work as stable point ahead of
develop sync (216 commits behind):

- invoice-paper: magicDustEmphasis prop (5 files) — violet-highlighted
  magic-dust digits in merged total per Round 9n Kai-sweep
- src/video/src/Root.tsx: hookVariant schema (v1/v2/v3) for A/B hook copy
- src/video/src/components/Caption.tsx: Path-C pill kinetic-mode alignment
- src/video/src/hooks/useAspect.ts: aspect-aware sizing helper (untracked)

All paths match handoff 2026-05-15-video-captions-9q.md "Files touched
in prior rounds (stable)". Type-check + lint were green at end of 9q.

* feat(video): round-9r PayScene phase reshuffle + toast/caption polish

PayScene: split Connect → Switch → Pay into three distinct presses;
expand stepAt to cover connecting/wrong-network/switching/ready substates;
shift confirming/success back by 60fr for longer paid-alone window.

RemotionFakeToast: rightAlign prop for landscape to avoid caption collision;
drop z-index from 9999 → 90 so captions (z=100) sit above.

ShareScene: gradient bar 4px → 8px (matches production ShareModal).

Captions: nudge landscape Magic-Dust + hook + outro captions to position=80
to clear paper/panel in 16:9.

Pre-refactor snapshot — next commits split scenes into sub-directories.

* feat(video): unified PaperBackdrop component (D39 canonical sizing)

Adds src/video/src/components/PaperBackdrop.tsx — shared component for use
in Phase 2 refactor of CreateScene/PayScene/ShareScene local copies.
Implements Kai-locked D39 formula: PAD=48, scale=min(scaleByW,scaleByH),
top centered within available height. No internal animation; scenes own
entrance/dim envelopes.

* refactor(video): split PayScene into scene/ sub-modules, adopt shared PaperBackdrop

Extracts constants, stepAt+pressScale, panel cascade/border style components,
MagicDustHalo, PaymentPanelContent, and landscape/portrait branches into
scenes/pay/ sub-directory.

Local PaperBackdrop replaced by shared components/PaperBackdrop.
Landscape paper unchanged (already D39 canonical). Portrait paper sizing
shifts from 0.92×width to 0.85×width with PAD=48 — drift fix approved by
Kai (2026-05-16). CHROME_HEIGHT now passed via containerHeight + parent
top offset, replacing the legacy offsetTop prop.

* refactor(video): split ShareScene into scene/ sub-modules, adopt shared PaperBackdrop

Extracts constants, SummaryCascade style components, and landscape/portrait
branches into scenes/share/ sub-directory.

Local PaperBackdrop replaced by shared components/PaperBackdrop. Visual
identical — ShareScene was already on D39 canonical formula (the reference
for Kai's drift fix). Modal shell duplication between branches preserved;
consolidation deferred to a future refactor.

* refactor(video): split CreateScene into scene/ sub-modules, adopt shared PaperBackdrop

Extracts constants, typewrite helper, PortraitCascade style block, and
landscape/portrait branches into scenes/create/ sub-directory.
Local PaperBackdrop replaced by shared components/PaperBackdrop wrapped
in CreateScenePaperEnvelope (preserves entrance animation + scale ramp).

Visual: landscape unchanged (already D39 canonical). Portrait paper
sizing shifts from 0.92×width to 0.85×width with PAD=48 — drift fix
approved by Kai (2026-05-16).

* refactor(video): PayScene drift cleanup — adopt shared PaperBackdrop in landscape, dedupe constants

Replaces inline InvoicePaper rendering in PaySceneLandscape with shared
components/PaperBackdrop (math is identical — was accidental duplication).
Replaces literal DEMO_TX_HASH and hardcoded confirmations counts with
imports from scenes/pay/constants.

* feat(ui): add readOnly prop to Input for display-only contexts

* refactor(invoice-form): split MetadataSection into Container + View

* refactor(invoice-form): split PartySection into Container + View

* refactor(payment): split IdleSubState — production union narrow, AnimatedIdleSubState for Views

IdleSubState is now the 3-element production union (disconnected|wrong-network|ready).
AnimatedIdleSubState is the 5-element superset adding connecting|switching for Remotion scenes.
SmartPayButtonView.tsx props/helpers updated to AnimatedIdleSubState.
parseDevOverride return type updated accordingly.
Container (SmartPayButton.tsx) stays IdleSubState via usePaymentFlow; widens to
AnimatedIdleSubState when passed to View — no cast needed.

* refactor(invoice-form): split LineItemsSection into Container + View

* refactor(invoice-form): split PaymentSection into Container + View

* refactor(invoice-form): split LinkOptionsSection into Container + View

* refactor(invoice-form): compose InvoiceFormView from real SectionViews

- Delete inline MetadataSectionView, PartySectionView, LineItemsSectionView,
  LineItemsViewRow, PaymentSectionView, MagicDustView, focusRing() helper
- Compose from ./sections/*SectionView components
- Replace ReadonlyInput with <Input readOnly /> (ReadonlyInput.tsx emptied)
- InvoiceFormView reduced from 382 LOC to ~115 LOC

* refactor(payment): lift IN_PROGRESS_STEPS to model/types

Moved IN_PROGRESS_STEPS Set from SmartPayButtonView.tsx inline const
into model/types.ts as the single source of truth.
SmartPayButtonView imports it from model; local duplicate removed.

* refactor(invoice-form): move View exports to /video-internals subpath

- sections/index.ts: export all *SectionView components alongside Containers
- index.ts: remove all View exports (InvoiceFormView, GenerateButton*View, *SectionView)
- video-internals.ts: new subpath barrel for Remotion — exports InvoiceFormView
  + all SectionViews + GenerateButtonView

FOLLOWUP: update src/video imports to use @/widgets/invoice-form/video-internals

* fix(invoice-form): exactOptionalPropertyTypes fixes in InvoiceFormView and LineItemsSectionView

* refactor(payment): move SmartPayButtonView to /video-internals subpath

- Create src/features/payment/video-internals.ts barrel exporting
  SmartPayButtonView, SmartPayButtonViewProps, AnimatedIdleSubState
- Remove SmartPayButtonView/SmartPayButtonViewProps from main index.ts barrel
- SmartPayButtonView helpers (getButtonLabel, getProgress, getAriaLabel)
  made private — no longer exported; View is the single source of truth
- getStepCount returns number directly (offset field was never read)
- SmartPayButton: drop getAriaLabel import and ariaLabel prop pass-through;
  View self-computes via isHydrating+idleSubState
- SmartPayButton: use IN_PROGRESS_STEPS.has() instead of inline array check

* fix(ui): re-tokenize Tabs to VoidPay zinc/violet palette

Replaced stock shadcn tokens (bg-muted, text-muted-foreground, ring-ring,
ring-offset-background, bg-background, text-foreground) which are undefined
in VoidPay's Tailwind config with explicit zinc/violet classes matching
the removed TabSwitcher.tsx palette:
- TabsList: border-zinc-800 bg-zinc-950/50 text-zinc-500
- TabsTrigger active: bg-zinc-800 text-zinc-100
- Focus ring: violet-500 on zinc-950 offset
Also converted double quotes to single quotes (project convention).

* fix(share-modal): restore tab icons, narrow tab value coercion

- Restore LinkIcon + QrCodeIcon in TabsTrigger children (UX regression
  from TabSwitcher→Tabs migration — icons were present in original TabSwitcher)
- Replace (v as ShareTab) cast with toShareTab() narrow guard
  ('qr' | fallback 'link') — eliminates unchecked type assertion

* fix(video): update imports to /video-internals subpaths after barrel migration

* refactor(invoice): move…
ignromanov added a commit that referenced this pull request May 19, 2026
…#240)

* docs: update privacy policy with Umami analytics details

Add dedicated "Product Analytics" section, add Umami to Third-Party
Services, fix misleading "Analytics or telemetry" item in
"What We Don't Collect" section.

* fix(demo): correct demo invoice data and native token template loading

- Fix txHash #1 missing 2 hex chars (62→64 hex digits)
- Remove redundant "(40 hours)" from description where qty=40
- Change Invoice #2 discount from 8% to 5% so tax/discount don't cancel out
- Fix native token (ETH, POL) not recognized when loading invoice as template:
  spread merge didn't clear default tokenAddress when decoded data omits the key

* docs: add community files, security policy, README redesign

- LICENSE (MIT)
- SECURITY.md + public/.well-known/security.txt (RFC 9116)
- CONTRIBUTING.md, CODE_OF_CONDUCT.md (Contributor Covenant v2.1)
- README.md full redesign: badges, How It Works, features, quick start
- .github/FUNDING.yml (GitHub Sponsors + Giveth)
- .github/dependabot.yml (weekly npm, monthly GHA)
- .github/pull_request_template.md
- .github/ISSUE_TEMPLATE/feature_request.md

* fix(docs): simplify PR template to match existing style

Summary + Test plan (lowercase), no generic checklist — CI handles validation.

* fix(docs): PR template with structured summary and specific test plan

Matches PR #45 style: subsections for larger PRs, concrete test checkboxes.

* ci: add Dependabot auto-merge for patch and minor updates

Auto-approve and squash-merge Dependabot PRs for patch/minor versions
after CI passes. Major version updates require manual review.

* build(deps-dev): bump tailwindcss from 4.1.18 to 4.2.2 (#70)

Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) from 4.1.18 to 4.2.2.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/tailwindcss)

---
updated-dependencies:
- dependency-name: tailwindcss
  dependency-version: 4.2.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump tailwind-merge from 3.4.0 to 3.5.0 (#62)

Bumps [tailwind-merge](https://github.com/dcastil/tailwind-merge) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/dcastil/tailwind-merge/releases)
- [Commits](https://github.com/dcastil/tailwind-merge/compare/v3.4.0...v3.5.0)

---
updated-dependencies:
- dependency-name: tailwind-merge
  dependency-version: 3.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump zustand from 5.0.9 to 5.0.12 (#68)

Bumps [zustand](https://github.com/pmndrs/zustand) from 5.0.9 to 5.0.12.
- [Release notes](https://github.com/pmndrs/zustand/releases)
- [Commits](https://github.com/pmndrs/zustand/compare/v5.0.9...v5.0.12)

---
updated-dependencies:
- dependency-name: zustand
  dependency-version: 5.0.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump lint-staged from 16.2.7 to 16.4.0 (#61)

Bumps [lint-staged](https://github.com/lint-staged/lint-staged) from 16.2.7 to 16.4.0.
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v16.2.7...v16.4.0)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-version: 16.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump viem from 2.43.4 to 2.47.6 (#63)

Bumps [viem](https://github.com/wevm/viem) from 2.43.4 to 2.47.6.
- [Release notes](https://github.com/wevm/viem/releases)
- [Commits](https://github.com/wevm/viem/compare/viem@2.43.4...viem@2.47.6)

---
updated-dependencies:
- dependency-name: viem
  dependency-version: 2.47.6
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @next/eslint-plugin-next from 16.1.1 to 16.2.1 (#69)

Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.1.1 to 16.2.1.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.2.1/packages/eslint-plugin-next)

---
updated-dependencies:
- dependency-name: "@next/eslint-plugin-next"
  dependency-version: 16.2.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump zod from 4.3.4 to 4.3.6 (#66)

Bumps [zod](https://github.com/colinhacks/zod) from 4.3.4 to 4.3.6.
- [Release notes](https://github.com/colinhacks/zod/releases)
- [Commits](https://github.com/colinhacks/zod/compare/v4.3.4...v4.3.6)

---
updated-dependencies:
- dependency-name: zod
  dependency-version: 4.3.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(github): issue templates frontmatter, dependabot auto-merge workflow

- Add name/about/title/assignees to issue templates so GitHub recognizes them
- Create config.yml disabling blank issues with security advisory link
- Replace dependabot-auto-merge.yml with simplified dependabot-automerge.yml

* build(deps-dev): bump lucide-static from 0.577.0 to 1.7.0 (#67)

Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 0.577.0 to 1.7.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/compare/0.577.0...1.7.0)

---
updated-dependencies:
- dependency-name: lucide-static
  dependency-version: 1.7.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @types/node from 22.19.3 to 25.5.0 (#65)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.3 to 25.5.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.5.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/upload-artifact from 4 to 7 (#60)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump pnpm/action-setup from 4 to 5 (#59)

Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 4 to 5.
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v4...v5)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/checkout from 4 to 6 (#58)

Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/cache from 4 to 5 (#57)

Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/setup-node from 4 to 6 (#56)

Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump picomatch from 2.3.1 to 2.3.2 (#55)

Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2.
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump vitest and @vitest/coverage-istanbul (#64)

Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) and [@vitest/coverage-istanbul](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-istanbul). These dependencies needed to be updated together.

Updates `vitest` from 4.0.16 to 4.1.2
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/vitest)

Updates `@vitest/coverage-istanbul` from 4.0.16 to 4.1.2
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/coverage-istanbul)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
- dependency-name: "@vitest/coverage-istanbul"
  dependency-version: 4.1.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump the npm_and_yarn group across 1 directory with 11 updates (#71)

Bumps the npm_and_yarn group with 11 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [next](https://github.com/vercel/next.js) | `15.5.9` | `15.5.14` |
| [happy-dom](https://github.com/capricorn86/happy-dom) | `20.0.11` | `20.8.9` |
| [ajv](https://github.com/ajv-validator/ajv) | `6.12.6` | `6.14.0` |
| [axios](https://github.com/axios/axios) | `1.13.2` | `1.14.0` |
| [brace-expansion](https://github.com/juliangruber/brace-expansion) | `1.1.12` | `1.1.13` |
| [flatted](https://github.com/WebReflection/flatted) | `3.3.3` | `3.4.2` |
| [h3](https://github.com/h3js/h3) | `1.15.4` | `1.15.10` |
| [hono](https://github.com/honojs/hono) | `4.11.3` | `4.12.9` |
| [minimatch](https://github.com/isaacs/minimatch) | `3.1.2` | `3.1.5` |
| [rollup](https://github.com/rollup/rollup) | `4.54.0` | `4.60.1` |
| [socket.io-parser](https://github.com/socketio/socket.io) | `4.2.5` | `4.2.6` |



Updates `next` from 15.5.9 to 15.5.14
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.5.9...v15.5.14)

Updates `happy-dom` from 20.0.11 to 20.8.9
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](https://github.com/capricorn86/happy-dom/compare/v20.0.11...v20.8.9)

Updates `ajv` from 6.12.6 to 6.14.0
- [Release notes](https://github.com/ajv-validator/ajv/releases)
- [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.6...v6.14.0)

Updates `axios` from 1.13.2 to 1.14.0
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.13.2...v1.14.0)

Updates `brace-expansion` from 1.1.12 to 1.1.13
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13)

Updates `flatted` from 3.3.3 to 3.4.2
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2)

Updates `h3` from 1.15.4 to 1.15.10
- [Release notes](https://github.com/h3js/h3/releases)
- [Changelog](https://github.com/h3js/h3/blob/v1.15.10/CHANGELOG.md)
- [Commits](https://github.com/h3js/h3/compare/v1.15.4...v1.15.10)

Updates `hono` from 4.11.3 to 4.12.9
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.11.3...v4.12.9)

Updates `minimatch` from 3.1.2 to 3.1.5
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

Updates `rollup` from 4.54.0 to 4.60.1
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.54.0...v4.60.1)

Updates `socket.io-parser` from 4.2.5 to 4.2.6
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-parser@4.2.5...socket.io-parser@4.2.6)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 15.5.14
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: happy-dom
  dependency-version: 20.8.9
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: ajv
  dependency-version: 6.14.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: axios
  dependency-version: 1.14.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: brace-expansion
  dependency-version: 1.1.13
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: h3
  dependency-version: 1.15.10
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: hono
  dependency-version: 4.12.9
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: rollup
  dependency-version: 4.60.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: socket.io-parser
  dependency-version: 4.2.6
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump yaml from 2.8.2 to 2.8.3 (#53)

Bumps [yaml](https://github.com/eemeli/yaml) from 2.8.2 to 2.8.3.
- [Release notes](https://github.com/eemeli/yaml/releases)
- [Commits](https://github.com/eemeli/yaml/compare/v2.8.2...v2.8.3)

---
updated-dependencies:
- dependency-name: yaml
  dependency-version: 2.8.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @xmldom/xmldom (#72)

Bumps the npm_and_yarn group with 1 update in the / directory: [@xmldom/xmldom](https://github.com/xmldom/xmldom).


Updates `@xmldom/xmldom` from 0.8.11 to 0.8.12
- [Release notes](https://github.com/xmldom/xmldom/releases)
- [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xmldom/xmldom/compare/0.8.11...0.8.12)

---
updated-dependencies:
- dependency-name: "@xmldom/xmldom"
  dependency-version: 0.8.12
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* docs: add Drips FUNDING.json + fix Giveth URL in FUNDING.yml

- FUNDING.json: Drips Network project claim (treasury wallet)
- FUNDING.yml: correct Giveth project URL slug

* Add newline at end of FUNDING.json

Fix formatting by adding a newline at the end of the file.

* docs: add OP Atlas projectId to FUNDING.json

* docs: add Optimism network to Drips FUNDING.json

* docs: add Buy Me a Coffee to FUNDING.yml

* build(deps): bump lodash in the npm_and_yarn group across 1 directory (#78)

Bumps the npm_and_yarn group with 1 update in the / directory: [lodash](https://github.com/lodash/lodash).


Updates `lodash` from 4.17.21 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump defu in the npm_and_yarn group across 1 directory (#80)

Bumps the npm_and_yarn group with 1 update in the / directory: [defu](https://github.com/unjs/defu).


Updates `defu` from 6.1.4 to 6.1.6
- [Release notes](https://github.com/unjs/defu/releases)
- [Changelog](https://github.com/unjs/defu/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unjs/defu/compare/v6.1.4...v6.1.6)

---
updated-dependencies:
- dependency-name: defu
  dependency-version: 6.1.6
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: remove robots.txt (static export doesn't serve it)

* feat: add 512x512 app icon for PWA and social sharing

* feat: add TalentApp domain verification meta tag

* build(deps): bump @tanstack/react-query from 5.90.16 to 5.96.2 (#82)

Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.90.16 to 5.96.2.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.96.2/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.96.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @next/eslint-plugin-next from 16.2.1 to 16.2.2 (#84)

Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.1 to 16.2.2.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.2.2/packages/eslint-plugin-next)

---
updated-dependencies:
- dependency-name: "@next/eslint-plugin-next"
  dependency-version: 16.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump framer-motion from 12.23.26 to 12.38.0 (#87)

Bumps [framer-motion](https://github.com/motiondivision/motion) from 12.23.26 to 12.38.0.
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v12.23.26...v12.38.0)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-version: 12.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @vitejs/plugin-react from 5.1.2 to 5.2.0 (#88)

Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 5.1.2 to 5.2.0.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/plugin-react@5.2.0/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@5.2.0/packages/plugin-react)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 5.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump postcss from 8.5.6 to 8.5.8 (#89)

Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.8.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.6...8.5.8)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump typescript-eslint from 8.51.0 to 8.58.0 (#92)

Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.51.0 to 8.58.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.58.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @testing-library/react from 16.3.1 to 16.3.2 (#93)

Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 16.3.1 to 16.3.2.
- [Release notes](https://github.com/testing-library/react-testing-library/releases)
- [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/react-testing-library/compare/v16.3.1...v16.3.2)

---
updated-dependencies:
- dependency-name: "@testing-library/react"
  dependency-version: 16.3.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @web3icons/react from 4.1.14 to 4.1.17 (#94)

Bumps [@web3icons/react](https://github.com/0xa3k5/web3icons/tree/HEAD/packages/react) from 4.1.14 to 4.1.17.
- [Release notes](https://github.com/0xa3k5/web3icons/releases)
- [Changelog](https://github.com/0xa3k5/web3icons/blob/main/packages/react/CHANGELOG.md)
- [Commits](https://github.com/0xa3k5/web3icons/commits/@web3icons/react@4.1.17/packages/react)

---
updated-dependencies:
- dependency-name: "@web3icons/react"
  dependency-version: 4.1.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @upstash/ratelimit from 2.0.7 to 2.0.8 (#91)

Bumps [@upstash/ratelimit](https://github.com/upstash/ratelimit) from 2.0.7 to 2.0.8.
- [Release notes](https://github.com/upstash/ratelimit/releases)
- [Commits](https://github.com/upstash/ratelimit/compare/v2.0.7...v2.0.8)

---
updated-dependencies:
- dependency-name: "@upstash/ratelimit"
  dependency-version: 2.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @eslint/eslintrc from 3.3.3 to 3.3.5 (#96)

Bumps [@eslint/eslintrc](https://github.com/eslint/eslintrc) from 3.3.3 to 3.3.5.
- [Release notes](https://github.com/eslint/eslintrc/releases)
- [Changelog](https://github.com/eslint/eslintrc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslintrc/compare/eslintrc-v3.3.3...eslintrc-v3.3.5)

---
updated-dependencies:
- dependency-name: "@eslint/eslintrc"
  dependency-version: 3.3.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump pixi.js from 8.14.3 to 8.17.1 (#100)

Bumps [pixi.js](https://github.com/pixijs/pixijs) from 8.14.3 to 8.17.1.
- [Release notes](https://github.com/pixijs/pixijs/releases)
- [Commits](https://github.com/pixijs/pixijs/compare/v8.14.3...v8.17.1)

---
updated-dependencies:
- dependency-name: pixi.js
  dependency-version: 8.17.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump geist from 1.5.1 to 1.7.0 (#98)

Bumps [geist](https://github.com/vercel/geist-font/tree/HEAD/packages/next) from 1.5.1 to 1.7.0.
- [Release notes](https://github.com/vercel/geist-font/releases)
- [Changelog](https://github.com/vercel/geist-font/blob/main/packages/next/CHANGELOG.md)
- [Commits](https://github.com/vercel/geist-font/commits/geist@1.7.0/packages/next)

---
updated-dependencies:
- dependency-name: geist
  dependency-version: 1.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @types/node from 25.5.0 to 25.5.2 (#99)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.0 to 25.5.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.5.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump viem from 2.47.6 to 2.47.10 (#97)

Bumps [viem](https://github.com/wevm/viem) from 2.47.6 to 2.47.10.
- [Release notes](https://github.com/wevm/viem/releases)
- [Commits](https://github.com/wevm/viem/compare/viem@2.47.6...viem@2.47.10)

---
updated-dependencies:
- dependency-name: viem
  dependency-version: 2.47.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @eslint/js from 9.39.2 to 9.39.4 (#101)

Bumps [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) from 9.39.2 to 9.39.4.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/commits/v9.39.4/packages/js)

---
updated-dependencies:
- dependency-name: "@eslint/js"
  dependency-version: 9.39.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump vite in the npm_and_yarn group across 1 directory (#102)

Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 7.3.0 to 7.3.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.3.2
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* refactor(history): redesign history page cards with payment panel style (#103)

* feat(history): add StatusGradientBar component

* feat(history): add NetworkBadge component with tests

* refactor(history): redesign InvoiceStatusBadge with dot + glow

* refactor(history): restyle InvoiceCardShell with zinc-900 + gradient bar

* refactor(history): rewrite HistoryList with new card layout, network badge, subtotal

* refactor(history): rewrite ReceivedInvoiceList with unified card design + Template button

* refactor(history): update HistoryWorkspace colors gray→zinc

* fix(history): remove unused type imports in ReceivedInvoiceList

* refactor(history): extract shared InvoiceCard, remove duplicate card components

Unified HistoryEntryCard and ReceivedInvoiceCard (~95% identical) into a
single InvoiceCard with a nameLabel prop. Removed defeated memo(), pointless
useMemo, dead source prop, and unnecessary JSX comments. Collapsed identical
DecodedReceivedInvoice type into alias for DecodedHistoryEntry.

* refactor(history): consolidate duplicated configs, merge list components

- Merge HistoryList + ReceivedInvoiceList into unified InvoiceList with
  variant prop ('created'|'received') controlling route, name, empty text
- Extract INVOICE_STATUS_CHIPS to entities/invoice for shared status colors
  consumed by InvoiceStatusBadge (features) and StatusChip (widgets)
- Move network badge dark-mode colors to entities/network (NETWORK_BADGES_DARK)
- Add formatDateMedium, formatDateCompact, isoToUnix to shared/lib/date-time
- Remove deprecated DecodedReceivedInvoice type alias
- Net -54 lines, 59/59 tests pass, tsc + lint clean

* feat: add Base network (8453) + refactor network visual system (#79)

* fix: remove robots.txt (static export doesn't serve it)

* feat: add BaseIcon SVG component for Base network

* feat: add Base (8453) and Base Sepolia (84532) to chain config

* feat: add Base network metadata and codes

* feat: add Base token registry (ETH, USDC, USDT)

* feat: add Base provider slugs for Alchemy and Infura

* feat: add Base confirmation config (OP Stack)

* feat: add Base block estimation parameters

* feat: add Base UI theming, badges, glows, and explorer

* feat: add Base RPC URL env vars to schema

* fix: add Base to theme configs, update chain count tests and snapshots

* fix: add Base to NetworkIcon component (web3icons + fallback)

* fix: update Base reference block from live explorer data

* refactor: remove unused BaseIcon (NetworkIcon uses @web3icons/react)

* fix: boost Base glow opacity (blue is subtle on dark background)

* revert: restore original Base glow values

* fix: resolve testnet glow/shadow/badge lookups via withTestnets helper

Visual config Records (NETWORK_SHADOWS, NETWORK_GLOWS, NETWORK_GLOW_SHADOWS,
NETWORK_GLOW_BORDERS, NETWORK_BADGES) were keyed by mainnet chain IDs only,
causing missing glow on testnet invoices (e.g. Base Sepolia 84532).

Added withTestnets() helper that auto-derives testnet entries from
TESTNET_PARENT, so new networks only need one mapping update.

* docs: update supported networks count and add Base to README and snapshot tests

* docs: add Base to all network references across landing, legal, and test files

* refactor: create canonical network palette and testnet utilities

* chore: bump Node.js version to v24 in .nvmrc

* chore: gitignore AI tool facades, plugins, and supabase local config

* refactor: rename getNetworkTheme→getNetworkName, extract testnet utils, lowercase addresses

* refactor: derive brand-tokens from palette, remove dead env vars, fix NetworkIcon a11y

- NetworkTheme now aliases NetworkThemeName from network-palette (canonical source)
- isValidNetworkTheme validates against NETWORK_PALETTE instead of NETWORK_THEMES
- Remove 10 dead NEXT_PUBLIC_ALCHEMY/INFURA_*_URL env vars (RPC proxy uses API keys + slug maps)
- NetworkIcon resolves testnet chain IDs to mainnet for icon/color/letter lookup
- Add aria-label to both branded and fallback NetworkIcon paths
- Export NETWORK_PALETTE and NetworkThemeName from shared/ui public API

* refactor: derive network-themes from canonical palette + withTestnets

* refactor: update consumers to use getNetworkThemeName, hoist widget colors

* feat: add Base demo invoice, fix tokenAddress not clearing for native tokens

Add 5th demo invoice for Base network (USDC, pending status) to landing
page carousel. Fix react-hook-form reset() not clearing tokenAddress when
loading native token templates (ETH/POL) — undefined must be mapped to ''
so RHF treats it as an explicit value rather than "keep current".

* fix: address PR review findings — remove unverified USDT, harden env, stabilize snapshots

- Remove Base USDT token (no official Tether deployment on Base)
- Add BLOCK_EXPLORERS comment explaining withTestnets exclusion
- Update Base Sepolia block anchor from live RPC (28M → 39.88M)
- Replace Math.random() with crypto.randomUUID() in RPC proxy
- Harden validateEnv to throw in production on missing vars
- Add Radix UI snapshot serializer for stable aria-controls IDs

* fix: prevent stale total when switching tokens, add replaceDraft for clean data loading

Total was stored as pre-calculated atomic units tied to a specific token's
decimals. Switching tokens reconverted line item rates but left total stale,
causing the preview to format ETH-scale values with USDC decimals (e.g.
5,510,000,000,000 instead of 5.80).

- Add replaceDraft() for atomic draft replacement (hash decode, template load)
- Extract toInvoiceItems/draftWithItems helpers, DRY 4 line item methods
- Clear stale total on: token switch, item mutations, template save/load
- Strip total from hash decode in CreateWorkspace (editor recalculates)
- Handle string quantities in invoiceItemsToLineItems (old localStorage)

* fix(history): resolve testnet networks showing as "Unknown" in history badges

Use getNetworkName() for O(1) lookup across all networks instead of
NETWORK_CONFIG.find() which only covered mainnets. Wrap NETWORK_BADGES_DARK
with withTestnets() so testnet badges inherit parent network brand colors.

* fix(create): reset all draft fields on form clear, extract store→form adapter

draftSyncStatus leaked through reset because createNewDraft/clearDraft/replaceDraft
didn't explicitly set it to 'idle'. Tax/discount/notes leaked because
react-hook-form treats undefined in reset() as "keep previous value".

Extract draftDataToFormValues() adapter as single source of truth for
PartialInvoice→InvoiceFormValues conversion, replacing duplicated 60-line
inline mappings. All optional string fields now coerced to '' on reset.

* fix(test): align NetworkBadge test with getNetworkName fallback to chain ID

* feat: update comparison table data to April 2026 research

RF pricing changed to \$250+/mo subscription, data storage corrected to
Centralized (hybrid API + on-chain, not pure IPFS), KYC/KYB updated to
required (yes). Disclaimer and comment block updated to April 2026.

* feat: add comparison page content data (VP vs Request Finance)

* feat: add /compare/request-finance comparison page

* feat: add /compare pages priority to sitemap config

* feat: add link to detailed comparison from landing table

* test: add comparison page tests

* fix: improve comparison page UI and remove duplicate footer

Apply UI/UX audit improvements: text-pretty headings, tabular-nums
table, hover states, glow CTA button, visual star rating, TL;DR label,
violet accent on bottom-line boxes. Remove duplicate footer links
since app-level footer already exists.

* ci: add project-sync workflow for auto VP Roadmap sync

New issues automatically added to VP Roadmap project board
with fields (Status, Priority, Advisor, Type, Source Repo)
parsed from labels. Agents no longer need manual item-add.

* fix(ci): use GraphQL API for project-sync workflow

gh project item-add/item-edit fail with "unknown owner type"
on user-level projects. Switch to direct GraphQL mutations.

* chore: add .superpowers/ to gitignore

* fix: invoice generation bugs — flash, source immutability, cross-tab sync (#105)

* fix: prevent invoice flash on generate, preserve source immutability, add cross-tab sync

- Remove clearDraft setTimeout that caused visible flash during navigation
- Make TrackedInvoice.source immutable (first-write-wins) so visiting /pay
  doesn't overwrite 'created' to 'received'
- Add localStorage storage event listener for cross-tab store rehydration

* fix(ui): add cursor-pointer to CreatorHintBanner dismiss button

* fix(store): key TrackedInvoice by contentHash (SHA-256) instead of invoiceId (#112)

* feat(codec): add computeContentHash — SHA-256 bytes32 digest for invoice identity

* feat(codec): return contentHash from parseInvoiceHash

* feat(store): key TrackedInvoice by contentHash instead of invoiceId

* feat(create): compute contentHash on invoice generation

* feat(view): compute and expose contentHash from useInvoiceView

* feat(import): compute contentHash for imported invoices

* refactor(ui): wire contentHash through component hierarchy

* refactor(payment): all hooks key by contentHash instead of invoiceId

Updates SmartPayButtonProps, UsePaymentFlowParams, UsePaymentVerificationParams,
UseFinalizationTrackerParams, UsePaymentPollingParams, and UseManualVerifyParams
to accept contentHash. All store action calls (setTxHash, setError, setValidated,
setFinalized, resetPaymentState, setConfirmations) now use contentHash as the key.
Internal polling helpers (loops, visibility-handler) updated consistently.

* fix: use contentHash key in polling params

* test: update all tests for contentHash-based store key

* fix: review fixes — runtime bugs, security hardening, perf improvements

- Fix PaymentPanel using invoiceId instead of contentHash for store lookup (BUG-01: PDF export lost paidAt)
- Fix DevStatusToggle passing invoiceId to contentHash-keyed store methods (BUG-02)
- Use Promise.allSettled in migration to survive partial failures (S-01)
- Always recompute contentHash on import, never trust pre-supplied values (S-02)
- Add empty fragment guard in addToHistory (H-1)
- Early return in setTxHash for unknown invoice (M-2)
- Add console.warn to migration catch block (F-04)
- Parallelize decode + hash in parseInvoiceHash via Promise.all
- Parallelize import hash computation, eliminate in-place mutation

* fix: resolve history page flickering and infinite migration loop

- Replace non-reactive hasHydrated() with useStoreHydrated() hook that
  subscribes via onFinishHydration for proper React re-render on hydration
- Make persist migration synchronous to avoid zustand v5 hydrationVersion
  race condition that cancelled in-flight async migrations
- Compute contentHash post-hydration via onFinishHydration + hasHydrated
  guard to handle both sync and async hydration paths
- Remove cross-tab storage event listener that triggered rehydrate() loops
  from stale tabs still writing version 1

* fix: show full invoice data in debug panel instead of decode flag

* fix: skip post-hydration hash computation on v2+ stores

Add _pendingHashComputation flag set only by migrate() during v1→v2
transition. _computeMissingContentHashes() now exits immediately on
v2+ stores instead of reading store state on every hydration.

* fix: remove console.info logs and fix test type errors

Remove informational console logs from TrackedInvoiceStore (keep warnings).
Add missing contentHash to SmartPayButton test fixtures.
Add scrollMargin to MockIntersectionObserver for TS 5.5+ compat.

* refactor: replace async crypto.subtle with sync @noble/hashes for SHA-256

Async two-phase migration (sync migrate → async post-hydration hash)
caused store data loss: zustand persisted entries with empty contentHash
between phases, and any failure in the async phase dropped invoices.

Switch to sync SHA-256 via @noble/hashes (already a dependency via viem)
so contentHash is computed atomically inside migrate(). Removes ~55 lines
of async infrastructure: _pendingHashComputation, _computeMissingContentHashes,
_sha256, onFinishHydration/hasHydrated fallback.

* docs: fix SECURITY.md — styled-components → inline style injection, add /api/health to out-of-scope

* fix(wallet): sync connection state between scoped Web3Providers

LazyWalletButton in the header could stay in static placeholder state
("Connect") while PayButton's scoped provider already had the wallet
connected. Root cause: LazyWalletButton only checked localStorage on
mount and had no way to detect connections from other providers.

Add WalletStateSync component that dispatches a custom DOM event
on wallet connect, and a listener in LazyWalletButton to activate
when the event fires.

* fix(wallet): prevent rehydration race in scoped Web3Providers

Multiple WagmiProvider instances sharing one wagmiConfig caused
connector state corruption: each mount triggered rehydrate() which
overwrote live connector instances with serialized plain objects
from localStorage. Between rehydrate() and reconnect() completing,
writeContract/sendTransaction crashed with "getChainId is not a
function" because the connector lacked methods.

Use WagmiContext.Provider (context-only, no hydration) for all
Web3Provider instances after the first one. A module-level flag
ensures only the primary instance triggers full WagmiProvider
hydration + reconnect.

* fix(payment): keyframe rotate to prevent SmartPay spinner freeze on Rabby

framer-motion v12 with WAAPI backend stalls single-value rotate loops
on the second iteration when a wallet extension's content script forces
a re-render mid-mount. The breathing label kept animating (keyframes
array) while the spinner icon froze (single value 360).

Switching to explicit keyframes [0, 360] gives WAAPI an unambiguous
start/end on every iteration and matches the pattern already used by
FluidOverlay for all other infinite loops in the button tree.

* fix(history): batch-check unpaid for both created and received invoices

Parametrize useBatchCheck by invoice source so the History page can verify
pending payments for both own and counterparty invoices, not just created.
Add a Check Unpaid button to the Received section mirroring the Created
one. Make invoice number and counterparty name in InvoiceCard clickable —
both trigger the View action with hover/focus styling.

* build(deps): bump viem from 2.47.10 to 2.47.16 (#122)

Bumps [viem](https://github.com/wevm/viem) from 2.47.10 to 2.47.16.
- [Release notes](https://github.com/wevm/viem/releases)
- [Commits](https://github.com/wevm/viem/compare/viem@2.47.10...viem@2.47.16)

---
updated-dependencies:
- dependency-name: viem
  dependency-version: 2.47.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump typescript-eslint from 8.58.0 to 8.58.2 (#124)

Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.58.0 to 8.58.2.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.2/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.58.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @noble/hashes from 2.0.1 to 2.2.0 (#125)

Bumps [@noble/hashes](https://github.com/paulmillr/noble-hashes) from 2.0.1 to 2.2.0.
- [Release notes](https://github.com/paulmillr/noble-hashes/releases)
- [Commits](https://github.com/paulmillr/noble-hashes/compare/2.0.1...2.2.0)

---
updated-dependencies:
- dependency-name: "@noble/hashes"
  dependency-version: 2.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump prettier from 3.7.4 to 3.8.2 (#126)

Bumps [prettier](https://github.com/prettier/prettier) from 3.7.4 to 3.8.2.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.7.4...3.8.2)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.8.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump use-debounce from 10.0.6 to 10.1.1 (#127)

Bumps [use-debounce](https://github.com/xnimorz/use-debounce) from 10.0.6 to 10.1.1.
- [Release notes](https://github.com/xnimorz/use-debounce/releases)
- [Changelog](https://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xnimorz/use-debounce/commits)

---
updated-dependencies:
- dependency-name: use-debounce
  dependency-version: 10.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump hono in the npm_and_yarn group across 1 directory (#104)

Bumps the npm_and_yarn group with 1 update in the / directory: [hono](https://github.com/honojs/hono).


Updates `hono` from 4.12.9 to 4.12.12
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.12.9...v4.12.12)

---
updated-dependencies:
- dependency-name: hono
  dependency-version: 4.12.12
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump react-hook-form from 7.70.0 to 7.72.1 (#130)

Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.70.0 to 7.72.1.
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.70.0...v7.72.1)

---
updated-dependencies:
- dependency-name: react-hook-form
  dependency-version: 7.72.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @tailwindcss/postcss from 4.1.18 to 4.2.2 (#131)

Bumps [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) from 4.1.18 to 4.2.2.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/@tailwindcss-postcss)

---
updated-dependencies:
- dependency-name: "@tailwindcss/postcss"
  dependency-version: 4.2.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump lucide-static from 1.7.0 to 1.8.0 (#123)

Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/compare/1.7.0...1.8.0)

---
updated-dependencies:
- dependency-name: lucide-static
  dependency-version: 1.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @tanstack/react-query from 5.96.2 to 5.99.0 (#128)

Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.96.2 to 5.99.0.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.99.0/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.99.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @types/node from 25.5.2 to 25.6.0 (#132)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.2 to 25.6.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @next/eslint-plugin-next from 16.2.2 to 16.2.3 (#134)

Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.2 to 16.2.3.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.2.3/packages/eslint-plugin-next)

---
updated-dependencies:
- dependency-name: "@next/eslint-plugin-next"
  dependency-version: 16.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat(payment): typed wagmi error handling + onReplaced support (#115)

* feat(payment): typed wagmi error handling + onReplaced support

Replace fragile string-matching error classification with typed detection
via viem's BaseError.walk() across the payment and wallet-connect features.
Add onReplaced callback to handle user speedup/cancel of pending transactions.

Component A: shared/lib/web3-errors
- New module with isUserRejected, isInsufficientFunds, isChainMismatch,
  isReceiptNotFound, isReceiptTimeout, isTxReverted, walkCause
- Walks BaseError cause chain via viem's typed API, falls back to string
  matching for non-BaseError edge cases (mobile WalletConnect)
- 38 unit tests covering direct, wrapped, and fallback paths

Component B: classifier refactor
- classify-error.ts rewritten to use typed detectors before string matching
- Removed step-based NETWORK_SWITCH_FAILED fallback — was masking user
  rejections of network switches
- Added TX_REPLACED to PaymentErrorType + ERROR_MESSAGES entry
- CANCELED_COPY constant for message unification
- connection-error.ts now calls isUserRejected first for typed detection

Component C: payment flow integration
- use-payment-flow.ts: console.error moved below USER_REJECTED early return
  (fixes verbose wagmi stack in console on user cancel)
- useWaitForTransactionReceipt now receives onReplaced callback:
  - reason 'cancelled' → toast + RESET (user intent)
  - reason 'replaced'/'repriced' → update hash + continue
- New REPLACED reducer action for hash swap during confirming state
- use-payment-verification.ts: sanitize raw viem errors through
  formatErrorMessage before writing to store + onReplaced observability

* refactor(payment): address review feedback on typed wagmi error handling

- Drop unused _step parameter from classifyPaymentError (dead arg after
  step-based fallback removal); update call site and 20+ test cases.
- Fix incorrect comment in usePaymentVerification onReplaced — both hooks
  consume useWaitForTransactionReceipt in parallel, not sequentially.
- Add TransactionExecutionError coverage to detect.test.ts (revert vs OOG
  shortMessage branches).

* feat(payment-panel): persistent network chip across all states

Adds a branded NetworkIcon + name chip at the top of PaymentPanel so
payers always see which chain the payment targets — visible in pending,
paid, paid-fallback and overdue states. Reserves right-side space via
pr-12 to avoid overlap with the minimize button.

Also migrates AmountDisplay assertions from toBeDefined() to
toBeInTheDocument() per testing rules.

* refactor(payment-panel): anchor network chip to amount, own minimize button

Move the network chip from the panel header into each state's heading row
(Total Due / Payment Successful / Expired / paid-fallback) so it sits
beside the amount it qualifies — semantically tying chain to value
instead of floating in an empty header strip.

Extract NetworkChip into a shared presentational component to drop
duplication across states. Pull the minimize button into PaymentPanel
behind an onMinimize prop, removing the duplicated absolute overlay
from PayWorkspace and InvoiceWorkspace. The button now coordinates with
the pr-12 right-side clearance baked into every heading row.

* fix(history): network icons, button sizing, robust template flow

- NetworkBadge: render NetworkIcon (web3icons) before name
- InvoiceCard: match Confirm/Cancel button height to regular buttons
  (min-h-[44px] py-2.5) to prevent layout shift on delete toggle
- InvoiceList: replace fragile duplicateFromUrl + setState + push flow
  with hash-based navigation /create?template=1#<hash>
- CreateWorkspace: detect ?template=1 and reset issuedAt/dueAt/total/
  magicDust after replaceDraft so templates start with fresh dates
- Remove unused duplicate-invoice.ts and its test mock

* refactor(payment-panel): group network chip with due/paid date

Relocates NetworkChip into a compact metadata row next to the due
date (pending) or relative paidAt (paid/expired). Drops the "TOTAL
DUE" label — the amount is self-explanatory and the label created
a "Total Due ... Due May 2" tautology with the date chunk.

- pending: [chip] Due <date>    above the amount
- paid:    [chip] Funds sent · <relative>    under Payment Successful
- expired: [chip] Was due <date> · Payment disabled    under header

Adds formatRelativeTime() in shared/lib/date-time for ISO →
"Just now" / "5 min ago" / "2 h ago" rendering. PaymentPanel now
subscribes to tracked paidAt via a store selector so the subtitle
reactively updates when the payment transitions to paid.

Clears the chip out of the emerald amount accent box on paid
state — zinc chip no longer clashes with the emerald tint.

* fix(wallet): visible loading state during wagmi reconnect

SmartPayButton and WalletButton both appeared frozen while wagmi
restored the persisted connection: the pay button stayed on "Pay X Y"
while disabled, and the header wallet button was hidden via opacity:0
so clicks fell through. Now both surfaces render an explicit disabled
"Reconnecting…" state with a visible spinner and aria-busy.

Covered by 6 new tests (3 SmartPayButton reconnect cases, 3 WalletButton).

* fix(wallet): cover SSR pre-hydration gap in pay + header buttons

Two bugs under one symptom ("click during page-load race gets stuck at
Connecting"):

1. Pre-hydration gap: wagmi with `ssr: true` reports `status: 'disconnected'`
   on the first client render even when a persisted connection exists in
   localStorage. `isReconnecting` is false in that window, so the previous
   fix did not catch it — SmartPayButton flashed a clickable "Connect Wallet"
   and WalletButton did the same in the header.

2. Stuck-at-connecting race: when a user clicked through the flash,
   `handlePay` entered `connecting` and opened the Rainbow modal. Meanwhile
   wagmi finished the background reconnect. The lifecycle effect in
   `usePaymentFlow` checked `connectModalOpen` before `isConnected`, so if
   Rainbow's modal state didn't cleanly flip through the expected order the
   flow stayed in `connecting` forever.

Fix:
- New shared hook `useWagmiHydrating` detects pre-hydration (persisted
  connector id in localStorage + wagmi still on initial disconnected),
  plus the normal `connecting` / `reconnecting` statuses. Drops the
  pre-hydration heuristic once wagmi leaves the initial snapshot so later
  manual disconnect/reconnect cycles behave normally.
- SmartPayButton and WalletButton now use `useWagmiHydrating` instead of
  `isReconnecting`. Both render a disabled loading button with
  aria-busy=true across the whole hydration window.
- `usePaymentFlow` connecting effect now checks `isConnected` before
  `connectModalOpen`, so a background reconnect always wins and the flow
  cannot strand in `connecting`.
- Regression tests: reorder-safe race in `use-payment-flow`, pre-hydration
  coverage in SmartPayButton + WalletButton suites. 387 payment +
  wallet-connect tests green.

* fix(payment): cap wait-for-receipt timeout at 60s, disable retry

Ensures a stuck transaction surfaces a user-visible RPC_ERROR banner
within one block window instead of hanging on the spinner. Previously,
viem's 180s default timeout combined with TanStack Query's default
retry (3) meant the first user-visible error could be delayed by up
to 9 minutes.

Also drops the TEMP DEBUG console.logs added during manual test
verification — all three test paths (USER_REJECTED silence, onReplaced
cancel, onReplaced speedup) have been validated on Eth Sepolia + Rabby.

Part of PR #115.

* fix(payment): raise wait-for-receipt timeout to viem default 180s

60s was too aggressive — near-zero-gas transactions legitimately need
several blocks on L1 before inclusion. Combined with retry: 0 this
still caps the hidden wait at 3 minutes (vs viem's default retry × 180s
= 9 minutes that motivated the original fix).

Field-verified on Base Sepolia: a stuck tx now surfaces the RPC_ERROR
banner as expected — only thing that needed tuning was the ceiling.

Part of PR #115.

* fix(payment-panel): make error banner X button clickable and cursor visible

Tailwind v4 dropped the default pointer cursor on <button>, and dismissError
only cleared the store — local paymentError stayed set, so the X appeared dead.
Add cursor-pointer + type=button, and wire a composite handler that clears
both paymentError and the tracked-invoice store error.

* refactor(payment): simplify PR #115 after parallel review

Findings from three parallel review agents (reuse, quality, efficiency)
aggregated and fixed:

- Remove dead TX_REPLACED PaymentErrorType: defined but never emitted
  (onReplaced dispatches REPLACED/RESET directly, classifier never
  returns it)
- Remove walkCause from web3-errors barrel export: internal-only,
  test file imports from ../detect
- Memoize onReplaced + extract RECEIPT_QUERY_OPTIONS/TIMEOUT_MS to
  module level in use-payment-flow.ts (inline refs were re-subscribing
  TanStack Query / viem watcher every render during confirming step)
- Hoist stateless handleVerificationReplaced + memoize receiptQuery in
  use-payment-verification.ts (compounded by useBlockNumber watch: true)
- Unwrap naked <div> wrapper with no props/layout in WalletButton.tsx
- Fix misleading CANCELED_COPY comment (claimed cross-feature usage
  that never existed)

Follow-ups tracked in #120 (NetworkChip/NetworkBadge unification),
#121 (nowUnix migration).

Net: -71 / +66 lines. Type-check, lint, 277 affected tests pass.

* fix(payment): address PR #115 review findings

- use receipt.transactionHash on CONFIRMED so replaced/repriced tx
  hashes aren't overwritten by the stale wagmi send hash
- REPLACED reducer explicitly clears error for future-proofing
- console.error logs shortMessage only to avoid leaking calldata
  if observability is wired later
- use-payment-verification: consolidate imports above function decl
- add reducer test covering REPLACED error preservation

* fix(payment): correct block-time drift breaking creator-side verification

Root cause: AVG_BLOCK_TIME_MS[11155111] was 12_000 but Sepolia actually runs
~13s/block. Over 35 days of forward drift estimateFromBlockHex returned a
block above the real chain head; alchemy_getAssetTransfers returned empty and
creators saw "payment not found" on confirmed transactions. Arbitrum Sepolia
had the same class of bug (250ms assumed vs ~286ms measured).

- AVG_BLOCK_TIME_MS: Sepolia 12000→13000, Arb Sepolia 250→286 (measured via
  10k-block samples across all 10 supported chains). REFERENCE_BLOCKS left
  frozen — v1.0 shipped Mar 28, old invoices must decode with the same
  calibration they were created with.
- /api/transfers: defense-in-depth safety net. Fetches eth_blockNumber in
  parallel with the transfers query, and on drifted client fromBlock retries
  with a 3-day lookback anchored to the real chain head. Drift logged via
  console.warn for observability. Eliminates the bug class regardless of
  anchor staleness.
- scripts/measure-block-times.ts + pnpm check:block-drift: diagnostic that
  measures real avgBlockTime for every chain, compares vs hardcoded values,
  reports lookback margin, and exits non-zero on BROKEN verdict.
- Route tests updated for the new parallel fetch; added cases covering both
  retry and no-retry paths of the …
ignromanov added a commit that referenced this pull request Jun 6, 2026
… a11y 84→100 + video captions (#302)

* perf(landing): inline render-blocking CSS via experimental.inlineCss

Enables Next.js experimental.inlineCss so the 3 stylesheet requests that
blocked the first render (global Tailwind 21.5KB + 2 component chunks
2.1/2.4KB) are merged into a single <style> tag in <head>.

PSI target: #2 render-blocking-resources, ~600ms LCP+FCP savings.
CSP already allows unsafe-inline for style-src — no CSP change needed.

Build evidence: index.html head now contains
  <style data-precedence="next" data-href="531c... b063... 67c5...">
with full Tailwind + component CSS inlined. Zero <link rel="stylesheet">
blocking tags remain.

* perf(landing): add modern browserslist to eliminate SWC polyfills

Targets chrome 111, safari 16.4, firefox 128, edge 111 — all ES2022-class,
matching the Telegram/Meta/X WebViews from spec 073 IAB gate.

Without an explicit browserslist Next.js ships SWC polyfills (Object.assign,
Object.fromEntries, globalThis shims etc.). These four targets already
support all ES2022 features natively so SWC emits no polyfill helpers.

PSI target: #3 legacy JS, ~12KB gzip / ~150ms savings off chunk 5028.
Verified: `npx browserslist` resolves to exactly {chrome 111, edge 111,
firefox 128, safari 16.4}.

* fix(a11y): add accessible names to nav links and wallet button

* fix(a11y): add role=img to NetworkIcon spans

* fix(a11y): improve caption contrast and remove superfluous figcaption

* feat(landing): add video captions VTT track and DOM transcript

* fix(landing): correct overlapping VTT cue timing
ignromanov added a commit that referenced this pull request Jun 6, 2026
…303)

* docs: update privacy policy with Umami analytics details

Add dedicated "Product Analytics" section, add Umami to Third-Party
Services, fix misleading "Analytics or telemetry" item in
"What We Don't Collect" section.

* fix(demo): correct demo invoice data and native token template loading

- Fix txHash #1 missing 2 hex chars (62→64 hex digits)
- Remove redundant "(40 hours)" from description where qty=40
- Change Invoice #2 discount from 8% to 5% so tax/discount don't cancel out
- Fix native token (ETH, POL) not recognized when loading invoice as template:
  spread merge didn't clear default tokenAddress when decoded data omits the key

* docs: add community files, security policy, README redesign

- LICENSE (MIT)
- SECURITY.md + public/.well-known/security.txt (RFC 9116)
- CONTRIBUTING.md, CODE_OF_CONDUCT.md (Contributor Covenant v2.1)
- README.md full redesign: badges, How It Works, features, quick start
- .github/FUNDING.yml (GitHub Sponsors + Giveth)
- .github/dependabot.yml (weekly npm, monthly GHA)
- .github/pull_request_template.md
- .github/ISSUE_TEMPLATE/feature_request.md

* fix(docs): simplify PR template to match existing style

Summary + Test plan (lowercase), no generic checklist — CI handles validation.

* fix(docs): PR template with structured summary and specific test plan

Matches PR #45 style: subsections for larger PRs, concrete test checkboxes.

* ci: add Dependabot auto-merge for patch and minor updates

Auto-approve and squash-merge Dependabot PRs for patch/minor versions
after CI passes. Major version updates require manual review.

* build(deps-dev): bump tailwindcss from 4.1.18 to 4.2.2 (#70)

Bumps [tailwindcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/tailwindcss) from 4.1.18 to 4.2.2.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/tailwindcss)

---
updated-dependencies:
- dependency-name: tailwindcss
  dependency-version: 4.2.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump tailwind-merge from 3.4.0 to 3.5.0 (#62)

Bumps [tailwind-merge](https://github.com/dcastil/tailwind-merge) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/dcastil/tailwind-merge/releases)
- [Commits](https://github.com/dcastil/tailwind-merge/compare/v3.4.0...v3.5.0)

---
updated-dependencies:
- dependency-name: tailwind-merge
  dependency-version: 3.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump zustand from 5.0.9 to 5.0.12 (#68)

Bumps [zustand](https://github.com/pmndrs/zustand) from 5.0.9 to 5.0.12.
- [Release notes](https://github.com/pmndrs/zustand/releases)
- [Commits](https://github.com/pmndrs/zustand/compare/v5.0.9...v5.0.12)

---
updated-dependencies:
- dependency-name: zustand
  dependency-version: 5.0.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump lint-staged from 16.2.7 to 16.4.0 (#61)

Bumps [lint-staged](https://github.com/lint-staged/lint-staged) from 16.2.7 to 16.4.0.
- [Release notes](https://github.com/lint-staged/lint-staged/releases)
- [Changelog](https://github.com/lint-staged/lint-staged/blob/main/CHANGELOG.md)
- [Commits](https://github.com/lint-staged/lint-staged/compare/v16.2.7...v16.4.0)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-version: 16.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump viem from 2.43.4 to 2.47.6 (#63)

Bumps [viem](https://github.com/wevm/viem) from 2.43.4 to 2.47.6.
- [Release notes](https://github.com/wevm/viem/releases)
- [Commits](https://github.com/wevm/viem/compare/viem@2.43.4...viem@2.47.6)

---
updated-dependencies:
- dependency-name: viem
  dependency-version: 2.47.6
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @next/eslint-plugin-next from 16.1.1 to 16.2.1 (#69)

Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.1.1 to 16.2.1.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.2.1/packages/eslint-plugin-next)

---
updated-dependencies:
- dependency-name: "@next/eslint-plugin-next"
  dependency-version: 16.2.1
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump zod from 4.3.4 to 4.3.6 (#66)

Bumps [zod](https://github.com/colinhacks/zod) from 4.3.4 to 4.3.6.
- [Release notes](https://github.com/colinhacks/zod/releases)
- [Commits](https://github.com/colinhacks/zod/compare/v4.3.4...v4.3.6)

---
updated-dependencies:
- dependency-name: zod
  dependency-version: 4.3.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(github): issue templates frontmatter, dependabot auto-merge workflow

- Add name/about/title/assignees to issue templates so GitHub recognizes them
- Create config.yml disabling blank issues with security advisory link
- Replace dependabot-auto-merge.yml with simplified dependabot-automerge.yml

* build(deps-dev): bump lucide-static from 0.577.0 to 1.7.0 (#67)

Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 0.577.0 to 1.7.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/compare/0.577.0...1.7.0)

---
updated-dependencies:
- dependency-name: lucide-static
  dependency-version: 1.7.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @types/node from 22.19.3 to 25.5.0 (#65)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.19.3 to 25.5.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.5.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/upload-artifact from 4 to 7 (#60)

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 7.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v7)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump pnpm/action-setup from 4 to 5 (#59)

Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 4 to 5.
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v4...v5)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/checkout from 4 to 6 (#58)

Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/cache from 4 to 5 (#57)

Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump actions/setup-node from 4 to 6 (#56)

Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 6.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v6)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump picomatch from 2.3.1 to 2.3.2 (#55)

Bumps [picomatch](https://github.com/micromatch/picomatch) from 2.3.1 to 2.3.2.
- [Release notes](https://github.com/micromatch/picomatch/releases)
- [Changelog](https://github.com/micromatch/picomatch/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/picomatch/compare/2.3.1...2.3.2)

---
updated-dependencies:
- dependency-name: picomatch
  dependency-version: 2.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump vitest and @vitest/coverage-istanbul (#64)

Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) and [@vitest/coverage-istanbul](https://github.com/vitest-dev/vitest/tree/HEAD/packages/coverage-istanbul). These dependencies needed to be updated together.

Updates `vitest` from 4.0.16 to 4.1.2
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/vitest)

Updates `@vitest/coverage-istanbul` from 4.0.16 to 4.1.2
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.1.2/packages/coverage-istanbul)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.1.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
- dependency-name: "@vitest/coverage-istanbul"
  dependency-version: 4.1.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump the npm_and_yarn group across 1 directory with 11 updates (#71)

Bumps the npm_and_yarn group with 11 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [next](https://github.com/vercel/next.js) | `15.5.9` | `15.5.14` |
| [happy-dom](https://github.com/capricorn86/happy-dom) | `20.0.11` | `20.8.9` |
| [ajv](https://github.com/ajv-validator/ajv) | `6.12.6` | `6.14.0` |
| [axios](https://github.com/axios/axios) | `1.13.2` | `1.14.0` |
| [brace-expansion](https://github.com/juliangruber/brace-expansion) | `1.1.12` | `1.1.13` |
| [flatted](https://github.com/WebReflection/flatted) | `3.3.3` | `3.4.2` |
| [h3](https://github.com/h3js/h3) | `1.15.4` | `1.15.10` |
| [hono](https://github.com/honojs/hono) | `4.11.3` | `4.12.9` |
| [minimatch](https://github.com/isaacs/minimatch) | `3.1.2` | `3.1.5` |
| [rollup](https://github.com/rollup/rollup) | `4.54.0` | `4.60.1` |
| [socket.io-parser](https://github.com/socketio/socket.io) | `4.2.5` | `4.2.6` |



Updates `next` from 15.5.9 to 15.5.14
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/compare/v15.5.9...v15.5.14)

Updates `happy-dom` from 20.0.11 to 20.8.9
- [Release notes](https://github.com/capricorn86/happy-dom/releases)
- [Commits](https://github.com/capricorn86/happy-dom/compare/v20.0.11...v20.8.9)

Updates `ajv` from 6.12.6 to 6.14.0
- [Release notes](https://github.com/ajv-validator/ajv/releases)
- [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.6...v6.14.0)

Updates `axios` from 1.13.2 to 1.14.0
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](https://github.com/axios/axios/compare/v1.13.2...v1.14.0)

Updates `brace-expansion` from 1.1.12 to 1.1.13
- [Release notes](https://github.com/juliangruber/brace-expansion/releases)
- [Commits](https://github.com/juliangruber/brace-expansion/compare/v1.1.12...v1.1.13)

Updates `flatted` from 3.3.3 to 3.4.2
- [Commits](https://github.com/WebReflection/flatted/compare/v3.3.3...v3.4.2)

Updates `h3` from 1.15.4 to 1.15.10
- [Release notes](https://github.com/h3js/h3/releases)
- [Changelog](https://github.com/h3js/h3/blob/v1.15.10/CHANGELOG.md)
- [Commits](https://github.com/h3js/h3/compare/v1.15.4...v1.15.10)

Updates `hono` from 4.11.3 to 4.12.9
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.11.3...v4.12.9)

Updates `minimatch` from 3.1.2 to 3.1.5
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

Updates `rollup` from 4.54.0 to 4.60.1
- [Release notes](https://github.com/rollup/rollup/releases)
- [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rollup/rollup/compare/v4.54.0...v4.60.1)

Updates `socket.io-parser` from 4.2.5 to 4.2.6
- [Release notes](https://github.com/socketio/socket.io/releases)
- [Changelog](https://github.com/socketio/socket.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io/compare/socket.io-parser@4.2.5...socket.io-parser@4.2.6)

---
updated-dependencies:
- dependency-name: next
  dependency-version: 15.5.14
  dependency-type: direct:production
  dependency-group: npm_and_yarn
- dependency-name: happy-dom
  dependency-version: 20.8.9
  dependency-type: direct:development
  dependency-group: npm_and_yarn
- dependency-name: ajv
  dependency-version: 6.14.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: axios
  dependency-version: 1.14.0
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: brace-expansion
  dependency-version: 1.1.13
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: flatted
  dependency-version: 3.4.2
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: h3
  dependency-version: 1.15.10
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: hono
  dependency-version: 4.12.9
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: rollup
  dependency-version: 4.60.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
- dependency-name: socket.io-parser
  dependency-version: 4.2.6
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump yaml from 2.8.2 to 2.8.3 (#53)

Bumps [yaml](https://github.com/eemeli/yaml) from 2.8.2 to 2.8.3.
- [Release notes](https://github.com/eemeli/yaml/releases)
- [Commits](https://github.com/eemeli/yaml/compare/v2.8.2...v2.8.3)

---
updated-dependencies:
- dependency-name: yaml
  dependency-version: 2.8.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @xmldom/xmldom (#72)

Bumps the npm_and_yarn group with 1 update in the / directory: [@xmldom/xmldom](https://github.com/xmldom/xmldom).


Updates `@xmldom/xmldom` from 0.8.11 to 0.8.12
- [Release notes](https://github.com/xmldom/xmldom/releases)
- [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xmldom/xmldom/compare/0.8.11...0.8.12)

---
updated-dependencies:
- dependency-name: "@xmldom/xmldom"
  dependency-version: 0.8.12
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* docs: add Drips FUNDING.json + fix Giveth URL in FUNDING.yml

- FUNDING.json: Drips Network project claim (treasury wallet)
- FUNDING.yml: correct Giveth project URL slug

* Add newline at end of FUNDING.json

Fix formatting by adding a newline at the end of the file.

* docs: add OP Atlas projectId to FUNDING.json

* docs: add Optimism network to Drips FUNDING.json

* docs: add Buy Me a Coffee to FUNDING.yml

* build(deps): bump lodash in the npm_and_yarn group across 1 directory (#78)

Bumps the npm_and_yarn group with 1 update in the / directory: [lodash](https://github.com/lodash/lodash).


Updates `lodash` from 4.17.21 to 4.18.1
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.18.1)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.18.1
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump defu in the npm_and_yarn group across 1 directory (#80)

Bumps the npm_and_yarn group with 1 update in the / directory: [defu](https://github.com/unjs/defu).


Updates `defu` from 6.1.4 to 6.1.6
- [Release notes](https://github.com/unjs/defu/releases)
- [Changelog](https://github.com/unjs/defu/blob/main/CHANGELOG.md)
- [Commits](https://github.com/unjs/defu/compare/v6.1.4...v6.1.6)

---
updated-dependencies:
- dependency-name: defu
  dependency-version: 6.1.6
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix: remove robots.txt (static export doesn't serve it)

* feat: add 512x512 app icon for PWA and social sharing

* feat: add TalentApp domain verification meta tag

* build(deps): bump @tanstack/react-query from 5.90.16 to 5.96.2 (#82)

Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.90.16 to 5.96.2.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.96.2/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.96.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @next/eslint-plugin-next from 16.2.1 to 16.2.2 (#84)

Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.1 to 16.2.2.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.2.2/packages/eslint-plugin-next)

---
updated-dependencies:
- dependency-name: "@next/eslint-plugin-next"
  dependency-version: 16.2.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump framer-motion from 12.23.26 to 12.38.0 (#87)

Bumps [framer-motion](https://github.com/motiondivision/motion) from 12.23.26 to 12.38.0.
- [Changelog](https://github.com/motiondivision/motion/blob/main/CHANGELOG.md)
- [Commits](https://github.com/motiondivision/motion/compare/v12.23.26...v12.38.0)

---
updated-dependencies:
- dependency-name: framer-motion
  dependency-version: 12.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @vitejs/plugin-react from 5.1.2 to 5.2.0 (#88)

Bumps [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react) from 5.1.2 to 5.2.0.
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/plugin-react@5.2.0/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@5.2.0/packages/plugin-react)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 5.2.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump postcss from 8.5.6 to 8.5.8 (#89)

Bumps [postcss](https://github.com/postcss/postcss) from 8.5.6 to 8.5.8.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.5.6...8.5.8)

---
updated-dependencies:
- dependency-name: postcss
  dependency-version: 8.5.8
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump typescript-eslint from 8.51.0 to 8.58.0 (#92)

Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.51.0 to 8.58.0.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.0/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.58.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @testing-library/react from 16.3.1 to 16.3.2 (#93)

Bumps [@testing-library/react](https://github.com/testing-library/react-testing-library) from 16.3.1 to 16.3.2.
- [Release notes](https://github.com/testing-library/react-testing-library/releases)
- [Changelog](https://github.com/testing-library/react-testing-library/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/react-testing-library/compare/v16.3.1...v16.3.2)

---
updated-dependencies:
- dependency-name: "@testing-library/react"
  dependency-version: 16.3.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @web3icons/react from 4.1.14 to 4.1.17 (#94)

Bumps [@web3icons/react](https://github.com/0xa3k5/web3icons/tree/HEAD/packages/react) from 4.1.14 to 4.1.17.
- [Release notes](https://github.com/0xa3k5/web3icons/releases)
- [Changelog](https://github.com/0xa3k5/web3icons/blob/main/packages/react/CHANGELOG.md)
- [Commits](https://github.com/0xa3k5/web3icons/commits/@web3icons/react@4.1.17/packages/react)

---
updated-dependencies:
- dependency-name: "@web3icons/react"
  dependency-version: 4.1.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @upstash/ratelimit from 2.0.7 to 2.0.8 (#91)

Bumps [@upstash/ratelimit](https://github.com/upstash/ratelimit) from 2.0.7 to 2.0.8.
- [Release notes](https://github.com/upstash/ratelimit/releases)
- [Commits](https://github.com/upstash/ratelimit/compare/v2.0.7...v2.0.8)

---
updated-dependencies:
- dependency-name: "@upstash/ratelimit"
  dependency-version: 2.0.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @eslint/eslintrc from 3.3.3 to 3.3.5 (#96)

Bumps [@eslint/eslintrc](https://github.com/eslint/eslintrc) from 3.3.3 to 3.3.5.
- [Release notes](https://github.com/eslint/eslintrc/releases)
- [Changelog](https://github.com/eslint/eslintrc/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslintrc/compare/eslintrc-v3.3.3...eslintrc-v3.3.5)

---
updated-dependencies:
- dependency-name: "@eslint/eslintrc"
  dependency-version: 3.3.5
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump pixi.js from 8.14.3 to 8.17.1 (#100)

Bumps [pixi.js](https://github.com/pixijs/pixijs) from 8.14.3 to 8.17.1.
- [Release notes](https://github.com/pixijs/pixijs/releases)
- [Commits](https://github.com/pixijs/pixijs/compare/v8.14.3...v8.17.1)

---
updated-dependencies:
- dependency-name: pixi.js
  dependency-version: 8.17.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump geist from 1.5.1 to 1.7.0 (#98)

Bumps [geist](https://github.com/vercel/geist-font/tree/HEAD/packages/next) from 1.5.1 to 1.7.0.
- [Release notes](https://github.com/vercel/geist-font/releases)
- [Changelog](https://github.com/vercel/geist-font/blob/main/packages/next/CHANGELOG.md)
- [Commits](https://github.com/vercel/geist-font/commits/geist@1.7.0/packages/next)

---
updated-dependencies:
- dependency-name: geist
  dependency-version: 1.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @types/node from 25.5.0 to 25.5.2 (#99)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.0 to 25.5.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.5.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump viem from 2.47.6 to 2.47.10 (#97)

Bumps [viem](https://github.com/wevm/viem) from 2.47.6 to 2.47.10.
- [Release notes](https://github.com/wevm/viem/releases)
- [Commits](https://github.com/wevm/viem/compare/viem@2.47.6...viem@2.47.10)

---
updated-dependencies:
- dependency-name: viem
  dependency-version: 2.47.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @eslint/js from 9.39.2 to 9.39.4 (#101)

Bumps [@eslint/js](https://github.com/eslint/eslint/tree/HEAD/packages/js) from 9.39.2 to 9.39.4.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Commits](https://github.com/eslint/eslint/commits/v9.39.4/packages/js)

---
updated-dependencies:
- dependency-name: "@eslint/js"
  dependency-version: 9.39.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump vite in the npm_and_yarn group across 1 directory (#102)

Bumps the npm_and_yarn group with 1 update in the / directory: [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite).


Updates `vite` from 7.3.0 to 7.3.2
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/v7.3.2/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v7.3.2/packages/vite)

---
updated-dependencies:
- dependency-name: vite
  dependency-version: 7.3.2
  dependency-type: direct:development
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* refactor(history): redesign history page cards with payment panel style (#103)

* feat(history): add StatusGradientBar component

* feat(history): add NetworkBadge component with tests

* refactor(history): redesign InvoiceStatusBadge with dot + glow

* refactor(history): restyle InvoiceCardShell with zinc-900 + gradient bar

* refactor(history): rewrite HistoryList with new card layout, network badge, subtotal

* refactor(history): rewrite ReceivedInvoiceList with unified card design + Template button

* refactor(history): update HistoryWorkspace colors gray→zinc

* fix(history): remove unused type imports in ReceivedInvoiceList

* refactor(history): extract shared InvoiceCard, remove duplicate card components

Unified HistoryEntryCard and ReceivedInvoiceCard (~95% identical) into a
single InvoiceCard with a nameLabel prop. Removed defeated memo(), pointless
useMemo, dead source prop, and unnecessary JSX comments. Collapsed identical
DecodedReceivedInvoice type into alias for DecodedHistoryEntry.

* refactor(history): consolidate duplicated configs, merge list components

- Merge HistoryList + ReceivedInvoiceList into unified InvoiceList with
  variant prop ('created'|'received') controlling route, name, empty text
- Extract INVOICE_STATUS_CHIPS to entities/invoice for shared status colors
  consumed by InvoiceStatusBadge (features) and StatusChip (widgets)
- Move network badge dark-mode colors to entities/network (NETWORK_BADGES_DARK)
- Add formatDateMedium, formatDateCompact, isoToUnix to shared/lib/date-time
- Remove deprecated DecodedReceivedInvoice type alias
- Net -54 lines, 59/59 tests pass, tsc + lint clean

* feat: add Base network (8453) + refactor network visual system (#79)

* fix: remove robots.txt (static export doesn't serve it)

* feat: add BaseIcon SVG component for Base network

* feat: add Base (8453) and Base Sepolia (84532) to chain config

* feat: add Base network metadata and codes

* feat: add Base token registry (ETH, USDC, USDT)

* feat: add Base provider slugs for Alchemy and Infura

* feat: add Base confirmation config (OP Stack)

* feat: add Base block estimation parameters

* feat: add Base UI theming, badges, glows, and explorer

* feat: add Base RPC URL env vars to schema

* fix: add Base to theme configs, update chain count tests and snapshots

* fix: add Base to NetworkIcon component (web3icons + fallback)

* fix: update Base reference block from live explorer data

* refactor: remove unused BaseIcon (NetworkIcon uses @web3icons/react)

* fix: boost Base glow opacity (blue is subtle on dark background)

* revert: restore original Base glow values

* fix: resolve testnet glow/shadow/badge lookups via withTestnets helper

Visual config Records (NETWORK_SHADOWS, NETWORK_GLOWS, NETWORK_GLOW_SHADOWS,
NETWORK_GLOW_BORDERS, NETWORK_BADGES) were keyed by mainnet chain IDs only,
causing missing glow on testnet invoices (e.g. Base Sepolia 84532).

Added withTestnets() helper that auto-derives testnet entries from
TESTNET_PARENT, so new networks only need one mapping update.

* docs: update supported networks count and add Base to README and snapshot tests

* docs: add Base to all network references across landing, legal, and test files

* refactor: create canonical network palette and testnet utilities

* chore: bump Node.js version to v24 in .nvmrc

* chore: gitignore AI tool facades, plugins, and supabase local config

* refactor: rename getNetworkTheme→getNetworkName, extract testnet utils, lowercase addresses

* refactor: derive brand-tokens from palette, remove dead env vars, fix NetworkIcon a11y

- NetworkTheme now aliases NetworkThemeName from network-palette (canonical source)
- isValidNetworkTheme validates against NETWORK_PALETTE instead of NETWORK_THEMES
- Remove 10 dead NEXT_PUBLIC_ALCHEMY/INFURA_*_URL env vars (RPC proxy uses API keys + slug maps)
- NetworkIcon resolves testnet chain IDs to mainnet for icon/color/letter lookup
- Add aria-label to both branded and fallback NetworkIcon paths
- Export NETWORK_PALETTE and NetworkThemeName from shared/ui public API

* refactor: derive network-themes from canonical palette + withTestnets

* refactor: update consumers to use getNetworkThemeName, hoist widget colors

* feat: add Base demo invoice, fix tokenAddress not clearing for native tokens

Add 5th demo invoice for Base network (USDC, pending status) to landing
page carousel. Fix react-hook-form reset() not clearing tokenAddress when
loading native token templates (ETH/POL) — undefined must be mapped to ''
so RHF treats it as an explicit value rather than "keep current".

* fix: address PR review findings — remove unverified USDT, harden env, stabilize snapshots

- Remove Base USDT token (no official Tether deployment on Base)
- Add BLOCK_EXPLORERS comment explaining withTestnets exclusion
- Update Base Sepolia block anchor from live RPC (28M → 39.88M)
- Replace Math.random() with crypto.randomUUID() in RPC proxy
- Harden validateEnv to throw in production on missing vars
- Add Radix UI snapshot serializer for stable aria-controls IDs

* fix: prevent stale total when switching tokens, add replaceDraft for clean data loading

Total was stored as pre-calculated atomic units tied to a specific token's
decimals. Switching tokens reconverted line item rates but left total stale,
causing the preview to format ETH-scale values with USDC decimals (e.g.
5,510,000,000,000 instead of 5.80).

- Add replaceDraft() for atomic draft replacement (hash decode, template load)
- Extract toInvoiceItems/draftWithItems helpers, DRY 4 line item methods
- Clear stale total on: token switch, item mutations, template save/load
- Strip total from hash decode in CreateWorkspace (editor recalculates)
- Handle string quantities in invoiceItemsToLineItems (old localStorage)

* fix(history): resolve testnet networks showing as "Unknown" in history badges

Use getNetworkName() for O(1) lookup across all networks instead of
NETWORK_CONFIG.find() which only covered mainnets. Wrap NETWORK_BADGES_DARK
with withTestnets() so testnet badges inherit parent network brand colors.

* fix(create): reset all draft fields on form clear, extract store→form adapter

draftSyncStatus leaked through reset because createNewDraft/clearDraft/replaceDraft
didn't explicitly set it to 'idle'. Tax/discount/notes leaked because
react-hook-form treats undefined in reset() as "keep previous value".

Extract draftDataToFormValues() adapter as single source of truth for
PartialInvoice→InvoiceFormValues conversion, replacing duplicated 60-line
inline mappings. All optional string fields now coerced to '' on reset.

* fix(test): align NetworkBadge test with getNetworkName fallback to chain ID

* feat: update comparison table data to April 2026 research

RF pricing changed to \$250+/mo subscription, data storage corrected to
Centralized (hybrid API + on-chain, not pure IPFS), KYC/KYB updated to
required (yes). Disclaimer and comment block updated to April 2026.

* feat: add comparison page content data (VP vs Request Finance)

* feat: add /compare/request-finance comparison page

* feat: add /compare pages priority to sitemap config

* feat: add link to detailed comparison from landing table

* test: add comparison page tests

* fix: improve comparison page UI and remove duplicate footer

Apply UI/UX audit improvements: text-pretty headings, tabular-nums
table, hover states, glow CTA button, visual star rating, TL;DR label,
violet accent on bottom-line boxes. Remove duplicate footer links
since app-level footer already exists.

* ci: add project-sync workflow for auto VP Roadmap sync

New issues automatically added to VP Roadmap project board
with fields (Status, Priority, Advisor, Type, Source Repo)
parsed from labels. Agents no longer need manual item-add.

* fix(ci): use GraphQL API for project-sync workflow

gh project item-add/item-edit fail with "unknown owner type"
on user-level projects. Switch to direct GraphQL mutations.

* chore: add .superpowers/ to gitignore

* fix: invoice generation bugs — flash, source immutability, cross-tab sync (#105)

* fix: prevent invoice flash on generate, preserve source immutability, add cross-tab sync

- Remove clearDraft setTimeout that caused visible flash during navigation
- Make TrackedInvoice.source immutable (first-write-wins) so visiting /pay
  doesn't overwrite 'created' to 'received'
- Add localStorage storage event listener for cross-tab store rehydration

* fix(ui): add cursor-pointer to CreatorHintBanner dismiss button

* fix(store): key TrackedInvoice by contentHash (SHA-256) instead of invoiceId (#112)

* feat(codec): add computeContentHash — SHA-256 bytes32 digest for invoice identity

* feat(codec): return contentHash from parseInvoiceHash

* feat(store): key TrackedInvoice by contentHash instead of invoiceId

* feat(create): compute contentHash on invoice generation

* feat(view): compute and expose contentHash from useInvoiceView

* feat(import): compute contentHash for imported invoices

* refactor(ui): wire contentHash through component hierarchy

* refactor(payment): all hooks key by contentHash instead of invoiceId

Updates SmartPayButtonProps, UsePaymentFlowParams, UsePaymentVerificationParams,
UseFinalizationTrackerParams, UsePaymentPollingParams, and UseManualVerifyParams
to accept contentHash. All store action calls (setTxHash, setError, setValidated,
setFinalized, resetPaymentState, setConfirmations) now use contentHash as the key.
Internal polling helpers (loops, visibility-handler) updated consistently.

* fix: use contentHash key in polling params

* test: update all tests for contentHash-based store key

* fix: review fixes — runtime bugs, security hardening, perf improvements

- Fix PaymentPanel using invoiceId instead of contentHash for store lookup (BUG-01: PDF export lost paidAt)
- Fix DevStatusToggle passing invoiceId to contentHash-keyed store methods (BUG-02)
- Use Promise.allSettled in migration to survive partial failures (S-01)
- Always recompute contentHash on import, never trust pre-supplied values (S-02)
- Add empty fragment guard in addToHistory (H-1)
- Early return in setTxHash for unknown invoice (M-2)
- Add console.warn to migration catch block (F-04)
- Parallelize decode + hash in parseInvoiceHash via Promise.all
- Parallelize import hash computation, eliminate in-place mutation

* fix: resolve history page flickering and infinite migration loop

- Replace non-reactive hasHydrated() with useStoreHydrated() hook that
  subscribes via onFinishHydration for proper React re-render on hydration
- Make persist migration synchronous to avoid zustand v5 hydrationVersion
  race condition that cancelled in-flight async migrations
- Compute contentHash post-hydration via onFinishHydration + hasHydrated
  guard to handle both sync and async hydration paths
- Remove cross-tab storage event listener that triggered rehydrate() loops
  from stale tabs still writing version 1

* fix: show full invoice data in debug panel instead of decode flag

* fix: skip post-hydration hash computation on v2+ stores

Add _pendingHashComputation flag set only by migrate() during v1→v2
transition. _computeMissingContentHashes() now exits immediately on
v2+ stores instead of reading store state on every hydration.

* fix: remove console.info logs and fix test type errors

Remove informational console logs from TrackedInvoiceStore (keep warnings).
Add missing contentHash to SmartPayButton test fixtures.
Add scrollMargin to MockIntersectionObserver for TS 5.5+ compat.

* refactor: replace async crypto.subtle with sync @noble/hashes for SHA-256

Async two-phase migration (sync migrate → async post-hydration hash)
caused store data loss: zustand persisted entries with empty contentHash
between phases, and any failure in the async phase dropped invoices.

Switch to sync SHA-256 via @noble/hashes (already a dependency via viem)
so contentHash is computed atomically inside migrate(). Removes ~55 lines
of async infrastructure: _pendingHashComputation, _computeMissingContentHashes,
_sha256, onFinishHydration/hasHydrated fallback.

* docs: fix SECURITY.md — styled-components → inline style injection, add /api/health to out-of-scope

* fix(wallet): sync connection state between scoped Web3Providers

LazyWalletButton in the header could stay in static placeholder state
("Connect") while PayButton's scoped provider already had the wallet
connected. Root cause: LazyWalletButton only checked localStorage on
mount and had no way to detect connections from other providers.

Add WalletStateSync component that dispatches a custom DOM event
on wallet connect, and a listener in LazyWalletButton to activate
when the event fires.

* fix(wallet): prevent rehydration race in scoped Web3Providers

Multiple WagmiProvider instances sharing one wagmiConfig caused
connector state corruption: each mount triggered rehydrate() which
overwrote live connector instances with serialized plain objects
from localStorage. Between rehydrate() and reconnect() completing,
writeContract/sendTransaction crashed with "getChainId is not a
function" because the connector lacked methods.

Use WagmiContext.Provider (context-only, no hydration) for all
Web3Provider instances after the first one. A module-level flag
ensures only the primary instance triggers full WagmiProvider
hydration + reconnect.

* fix(payment): keyframe rotate to prevent SmartPay spinner freeze on Rabby

framer-motion v12 with WAAPI backend stalls single-value rotate loops
on the second iteration when a wallet extension's content script forces
a re-render mid-mount. The breathing label kept animating (keyframes
array) while the spinner icon froze (single value 360).

Switching to explicit keyframes [0, 360] gives WAAPI an unambiguous
start/end on every iteration and matches the pattern already used by
FluidOverlay for all other infinite loops in the button tree.

* fix(history): batch-check unpaid for both created and received invoices

Parametrize useBatchCheck by invoice source so the History page can verify
pending payments for both own and counterparty invoices, not just created.
Add a Check Unpaid button to the Received section mirroring the Created
one. Make invoice number and counterparty name in InvoiceCard clickable —
both trigger the View action with hover/focus styling.

* build(deps): bump viem from 2.47.10 to 2.47.16 (#122)

Bumps [viem](https://github.com/wevm/viem) from 2.47.10 to 2.47.16.
- [Release notes](https://github.com/wevm/viem/releases)
- [Commits](https://github.com/wevm/viem/compare/viem@2.47.10...viem@2.47.16)

---
updated-dependencies:
- dependency-name: viem
  dependency-version: 2.47.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump typescript-eslint from 8.58.0 to 8.58.2 (#124)

Bumps [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint) from 8.58.0 to 8.58.2.
- [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases)
- [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md)
- [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.58.2/packages/typescript-eslint)

---
updated-dependencies:
- dependency-name: typescript-eslint
  dependency-version: 8.58.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @noble/hashes from 2.0.1 to 2.2.0 (#125)

Bumps [@noble/hashes](https://github.com/paulmillr/noble-hashes) from 2.0.1 to 2.2.0.
- [Release notes](https://github.com/paulmillr/noble-hashes/releases)
- [Commits](https://github.com/paulmillr/noble-hashes/compare/2.0.1...2.2.0)

---
updated-dependencies:
- dependency-name: "@noble/hashes"
  dependency-version: 2.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump prettier from 3.7.4 to 3.8.2 (#126)

Bumps [prettier](https://github.com/prettier/prettier) from 3.7.4 to 3.8.2.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/3.7.4...3.8.2)

---
updated-dependencies:
- dependency-name: prettier
  dependency-version: 3.8.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump use-debounce from 10.0.6 to 10.1.1 (#127)

Bumps [use-debounce](https://github.com/xnimorz/use-debounce) from 10.0.6 to 10.1.1.
- [Release notes](https://github.com/xnimorz/use-debounce/releases)
- [Changelog](https://github.com/xnimorz/use-debounce/blob/master/CHANGELOG.md)
- [Commits](https://github.com/xnimorz/use-debounce/commits)

---
updated-dependencies:
- dependency-name: use-debounce
  dependency-version: 10.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump hono in the npm_and_yarn group across 1 directory (#104)

Bumps the npm_and_yarn group with 1 update in the / directory: [hono](https://github.com/honojs/hono).


Updates `hono` from 4.12.9 to 4.12.12
- [Release notes](https://github.com/honojs/hono/releases)
- [Commits](https://github.com/honojs/hono/compare/v4.12.9...v4.12.12)

---
updated-dependencies:
- dependency-name: hono
  dependency-version: 4.12.12
  dependency-type: indirect
  dependency-group: npm_and_yarn
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump react-hook-form from 7.70.0 to 7.72.1 (#130)

Bumps [react-hook-form](https://github.com/react-hook-form/react-hook-form) from 7.70.0 to 7.72.1.
- [Release notes](https://github.com/react-hook-form/react-hook-form/releases)
- [Changelog](https://github.com/react-hook-form/react-hook-form/blob/master/CHANGELOG.md)
- [Commits](https://github.com/react-hook-form/react-hook-form/compare/v7.70.0...v7.72.1)

---
updated-dependencies:
- dependency-name: react-hook-form
  dependency-version: 7.72.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @tailwindcss/postcss from 4.1.18 to 4.2.2 (#131)

Bumps [@tailwindcss/postcss](https://github.com/tailwindlabs/tailwindcss/tree/HEAD/packages/@tailwindcss-postcss) from 4.1.18 to 4.2.2.
- [Release notes](https://github.com/tailwindlabs/tailwindcss/releases)
- [Changelog](https://github.com/tailwindlabs/tailwindcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tailwindlabs/tailwindcss/commits/v4.2.2/packages/@tailwindcss-postcss)

---
updated-dependencies:
- dependency-name: "@tailwindcss/postcss"
  dependency-version: 4.2.2
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump lucide-static from 1.7.0 to 1.8.0 (#123)

Bumps [lucide-static](https://github.com/lucide-icons/lucide) from 1.7.0 to 1.8.0.
- [Release notes](https://github.com/lucide-icons/lucide/releases)
- [Commits](https://github.com/lucide-icons/lucide/compare/1.7.0...1.8.0)

---
updated-dependencies:
- dependency-name: lucide-static
  dependency-version: 1.8.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps): bump @tanstack/react-query from 5.96.2 to 5.99.0 (#128)

Bumps [@tanstack/react-query](https://github.com/TanStack/query/tree/HEAD/packages/react-query) from 5.96.2 to 5.99.0.
- [Release notes](https://github.com/TanStack/query/releases)
- [Changelog](https://github.com/TanStack/query/blob/main/packages/react-query/CHANGELOG.md)
- [Commits](https://github.com/TanStack/query/commits/@tanstack/react-query@5.99.0/packages/react-query)

---
updated-dependencies:
- dependency-name: "@tanstack/react-query"
  dependency-version: 5.99.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @types/node from 25.5.2 to 25.6.0 (#132)

Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 25.5.2 to 25.6.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

---
updated-dependencies:
- dependency-name: "@types/node"
  dependency-version: 25.6.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* build(deps-dev): bump @next/eslint-plugin-next from 16.2.2 to 16.2.3 (#134)

Bumps [@next/eslint-plugin-next](https://github.com/vercel/next.js/tree/HEAD/packages/eslint-plugin-next) from 16.2.2 to 16.2.3.
- [Release notes](https://github.com/vercel/next.js/releases)
- [Changelog](https://github.com/vercel/next.js/blob/canary/release.js)
- [Commits](https://github.com/vercel/next.js/commits/v16.2.3/packages/eslint-plugin-next)

---
updated-dependencies:
- dependency-name: "@next/eslint-plugin-next"
  dependency-version: 16.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat(payment): typed wagmi error handling + onReplaced support (#115)

* feat(payment): typed wagmi error handling + onReplaced support

Replace fragile string-matching error classification with typed detection
via viem's BaseError.walk() across the payment and wallet-connect features.
Add onReplaced callback to handle user speedup/cancel of pending transactions.

Component A: shared/lib/web3-errors
- New module with isUserRejected, isInsufficientFunds, isChainMismatch,
  isReceiptNotFound, isReceiptTimeout, isTxReverted, walkCause
- Walks BaseError cause chain via viem's typed API, falls back to string
  matching for non-BaseError edge cases (mobile WalletConnect)
- 38 unit tests covering direct, wrapped, and fallback paths

Component B: classifier refactor
- classify-error.ts rewritten to use typed detectors before string matching
- Removed step-based NETWORK_SWITCH_FAILED fallback — was masking user
  rejections of network switches
- Added TX_REPLACED to PaymentErrorType + ERROR_MESSAGES entry
- CANCELED_COPY constant for message unification
- connection-error.ts now calls isUserRejected first for typed detection

Component C: payment flow integration
- use-payment-flow.ts: console.error moved below USER_REJECTED early return
  (fixes verbose wagmi stack in console on user cancel)
- useWaitForTransactionReceipt now receives onReplaced callback:
  - reason 'cancelled' → toast + RESET (user intent)
  - reason 'replaced'/'repriced' → update hash + continue
- New REPLACED reducer action for hash swap during confirming state
- use-payment-verification.ts: sanitize raw viem errors through
  formatErrorMessage before writing to store + onReplaced observability

* refactor(payment): address review feedback on typed wagmi error handling

- Drop unused _step parameter from classifyPaymentError (dead arg after
  step-based fallback removal); update call site and 20+ test cases.
- Fix incorrect comment in usePaymentVerification onReplaced — both hooks
  consume useWaitForTransactionReceipt in parallel, not sequentially.
- Add TransactionExecutionError coverage to detect.test.ts (revert vs OOG
  shortMessage branches).

* feat(payment-panel): persistent network chip across all states

Adds a branded NetworkIcon + name chip at the top of PaymentPanel so
payers always see which chain the payment targets — visible in pending,
paid, paid-fallback and overdue states. Reserves right-side space via
pr-12 to avoid overlap with the minimize button.

Also migrates AmountDisplay assertions from toBeDefined() to
toBeInTheDocument() per testing rules.

* refactor(payment-panel): anchor network chip to amount, own minimize button

Move the network chip from the panel header into each state's heading row
(Total Due / Payment Successful / Expired / paid-fallback) so it sits
beside the amount it qualifies — semantically tying chain to value
instead of floating in an empty header strip.

Extract NetworkChip into a shared presentational component to drop
duplication across states. Pull the minimize button into PaymentPanel
behind an onMinimize prop, removing the duplicated absolute overlay
from PayWorkspace and InvoiceWorkspace. The button now coordinates with
the pr-12 right-side clearance baked into every heading row.

* fix(history): network icons, button sizing, robust template flow

- NetworkBadge: render NetworkIcon (web3icons) before name
- InvoiceCard: match Confirm/Cancel button height to regular buttons
  (min-h-[44px] py-2.5) to prevent layout shift on delete toggle
- InvoiceList: replace fragile duplicateFromUrl + setState + push flow
  with hash-based navigation /create?template=1#<hash>
- CreateWorkspace: detect ?template=1 and reset issuedAt/dueAt/total/
  magicDust after replaceDraft so templates start with fresh dates
- Remove unused duplicate-invoice.ts and its test mock

* refactor(payment-panel): group network chip with due/paid date

Relocates NetworkChip into a compact metadata row next to the due
date (pending) or relative paidAt (paid/expired). Drops the "TOTAL
DUE" label — the amount is self-explanatory and the label created
a "Total Due ... Due May 2" tautology with the date chunk.

- pending: [chip] Due <date>    above the amount
- paid:    [chip] Funds sent · <relative>    under Payment Successful
- expired: [chip] Was due <date> · Payment disabled    under header

Adds formatRelativeTime() in shared/lib/date-time for ISO →
"Just now" / "5 min ago" / "2 h ago" rendering. PaymentPanel now
subscribes to tracked paidAt via a store selector so the subtitle
reactively updates when the payment transitions to paid.

Clears the chip out of the emerald amount accent box on paid
state — zinc chip no longer clashes with the emerald tint.

* fix(wallet): visible loading state during wagmi reconnect

SmartPayButton and WalletButton both appeared frozen while wagmi
restored the persisted connection: the pay button stayed on "Pay X Y"
while disabled, and the header wallet button was hidden via opacity:0
so clicks fell through. Now both surfaces render an explicit disabled
"Reconnecting…" state with a visible spinner and aria-busy.

Covered by 6 new tests (3 SmartPayButton reconnect cases, 3 WalletButton).

* fix(wallet): cover SSR pre-hydration gap in pay + header buttons

Two bugs under one symptom ("click during page-load race gets stuck at
Connecting"):

1. Pre-hydration gap: wagmi with `ssr: true` reports `status: 'disconnected'`
   on the first client render even when a persisted connection exists in
   localStorage. `isReconnecting` is false in that window, so the previous
   fix did not catch it — SmartPayButton flashed a clickable "Connect Wallet"
   and WalletButton did the same in the header.

2. Stuck-at-connecting race: when a user clicked through the flash,
   `handlePay` entered `connecting` and opened the Rainbow modal. Meanwhile
   wagmi finished the background reconnect. The lifecycle effect in
   `usePaymentFlow` checked `connectModalOpen` before `isConnected`, so if
   Rainbow's modal state didn't cleanly flip through the expected order the
   flow stayed in `connecting` forever.

Fix:
- New shared hook `useWagmiHydrating` detects pre-hydration (persisted
  connector id in localStorage + wagmi still on initial disconnected),
  plus the normal `connecting` / `reconnecting` statuses. Drops the
  pre-hydration heuristic once wagmi leaves the initial snapshot so later
  manual disconnect/reconnect cycles behave normally.
- SmartPayButton and WalletButton now use `useWagmiHydrating` instead of
  `isReconnecting`. Both render a disabled loading button with
  aria-busy=true across the whole hydration window.
- `usePaymentFlow` connecting effect now checks `isConnected` before
  `connectModalOpen`, so a background reconnect always wins and the flow
  cannot strand in `connecting`.
- Regression tests: reorder-safe race in `use-payment-flow`, pre-hydration
  coverage in SmartPayButton + WalletButton suites. 387 payment +
  wallet-connect tests green.

* fix(payment): cap wait-for-receipt timeout at 60s, disable retry

Ensures a stuck transaction surfaces a user-visible RPC_ERROR banner
within one block window instead of hanging on the spinner. Previously,
viem's 180s default timeout combined with TanStack Query's default
retry (3) meant the first user-visible error could be delayed by up
to 9 minutes.

Also drops the TEMP DEBUG console.logs added during manual test
verification — all three test paths (USER_REJECTED silence, onReplaced
cancel, onReplaced speedup) have been validated on Eth Sepolia + Rabby.

Part of PR #115.

* fix(payment): raise wait-for-receipt timeout to viem default 180s

60s was too aggressive — near-zero-gas transactions legitimately need
several blocks on L1 before inclusion. Combined with retry: 0 this
still caps the hidden wait at 3 minutes (vs viem's default retry × 180s
= 9 minutes that motivated the original fix).

Field-verified on Base Sepolia: a stuck tx now surfaces the RPC_ERROR
banner as expected — only thing that needed tuning was the ceiling.

Part of PR #115.

* fix(payment-panel): make error banner X button clickable and cursor visible

Tailwind v4 dropped the default pointer cursor on <button>, and dismissError
only cleared the store — local paymentError stayed set, so the X appeared dead.
Add cursor-pointer + type=button, and wire a composite handler that clears
both paymentError and the tracked-invoice store error.

* refactor(payment): simplify PR #115 after parallel review

Findings from three parallel review agents (reuse, quality, efficiency)
aggregated and fixed:

- Remove dead TX_REPLACED PaymentErrorType: defined but never emitted
  (onReplaced dispatches REPLACED/RESET directly, classifier never
  returns it)
- Remove walkCause from web3-errors barrel export: internal-only,
  test file imports from ../detect
- Memoize onReplaced + extract RECEIPT_QUERY_OPTIONS/TIMEOUT_MS to
  module level in use-payment-flow.ts (inline refs were re-subscribing
  TanStack Query / viem watcher every render during confirming step)
- Hoist stateless handleVerificationReplaced + memoize receiptQuery in
  use-payment-verification.ts (compounded by useBlockNumber watch: true)
- Unwrap naked <div> wrapper with no props/layout in WalletButton.tsx
- Fix misleading CANCELED_COPY comment (claimed cross-feature usage
  that never existed)

Follow-ups tracked in #120 (NetworkChip/NetworkBadge unification),
#121 (nowUnix migration).

Net: -71 / +66 lines. Type-check, lint, 277 affected tests pass.

* fix(payment): address PR #115 review findings

- use receipt.transactionHash on CONFIRMED so replaced/repriced tx
  hashes aren't overwritten by the stale wagmi send hash
- REPLACED reducer explicitly clears error for future-proofing
- console.error logs shortMessage only to avoid leaking calldata
  if observability is wired later
- use-payment-verification: consolidate imports above function decl
- add reducer test covering REPLACED error preservation

* fix(payment): correct block-time drift breaking creator-side verification

Root cause: AVG_BLOCK_TIME_MS[11155111] was 12_000 but Sepolia actually runs
~13s/block. Over 35 days of forward drift estimateFromBlockHex returned a
block above the real chain head; alchemy_getAssetTransfers returned empty and
creators saw "payment not found" on confirmed transactions. Arbitrum Sepolia
had the same class of bug (250ms assumed vs ~286ms measured).

- AVG_BLOCK_TIME_MS: Sepolia 12000→13000, Arb Sepolia 250→286 (measured via
  10k-block samples across all 10 supported chains). REFERENCE_BLOCKS left
  frozen — v1.0 shipped Mar 28, old invoices must decode with the same
  calibration they were created with.
- /api/transfers: defense-in-depth safety net. Fetches eth_blockNumber in
  parallel with the transfers query, and on drifted client fromBlock retries
  with a 3-day lookback anchored to the real chain head. Drift logged via
  console.warn for observability. Eliminates the bug class regardless of
  anchor staleness.
- scripts/measure-block-times.ts + pnpm check:block-drift: diagnostic that
  measures real avgBlockTime for every chain, compares vs hardcoded values,
  reports lookback margin, and exits non-zero on BROKEN verdict.
- Route tests updated for the new parallel fetch; added cases covering both
  retry and no-retry paths of the s…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant