From d0835b86ab4f802732265b8a3b1c64df51d9537b Mon Sep 17 00:00:00 2001 From: null Date: Thu, 11 Jun 2026 23:50:27 -0500 Subject: [PATCH] chore(cleanup): remove legacy/public HTML files, retire /legacy route, update docs and About page --- HISTORY.md | 4 + README.md | 1 - REVIEW.md | 6 +- client/pages/AboutPage.jsx | 14 - docs/Engineering_Reference_Manual.md | 2 +- legacy/admin.html | 766 ----------------------- legacy/css/style.css | 888 --------------------------- legacy/index.html | 234 ------- legacy/js/api.js | 51 -- legacy/js/app.js | 179 ------ legacy/js/bills.js | 161 ----- legacy/js/categories.js | 110 ---- legacy/js/settings.js | 207 ------- legacy/js/status.js | 103 ---- legacy/js/tracker.js | 424 ------------- legacy/login.html | 174 ------ public/admin.html | 766 ----------------------- public/css/style.css | 888 --------------------------- public/img/logo.png | Bin 146265 -> 0 bytes public/index.html | 234 ------- public/js/api.js | 51 -- public/js/app.js | 179 ------ public/js/bills.js | 161 ----- public/js/categories.js | 110 ---- public/js/settings.js | 207 ------- public/js/status.js | 103 ---- public/js/tracker.js | 424 ------------- public/login.html | 15 - server.js | 6 +- 29 files changed, 11 insertions(+), 6457 deletions(-) delete mode 100644 legacy/admin.html delete mode 100644 legacy/css/style.css delete mode 100644 legacy/index.html delete mode 100644 legacy/js/api.js delete mode 100644 legacy/js/app.js delete mode 100644 legacy/js/bills.js delete mode 100644 legacy/js/categories.js delete mode 100644 legacy/js/settings.js delete mode 100644 legacy/js/status.js delete mode 100644 legacy/js/tracker.js delete mode 100644 legacy/login.html delete mode 100644 public/admin.html delete mode 100644 public/css/style.css delete mode 100644 public/img/logo.png delete mode 100644 public/index.html delete mode 100644 public/js/api.js delete mode 100644 public/js/app.js delete mode 100644 public/js/bills.js delete mode 100644 public/js/categories.js delete mode 100644 public/js/settings.js delete mode 100644 public/js/status.js delete mode 100644 public/js/tracker.js delete mode 100644 public/login.html diff --git a/HISTORY.md b/HISTORY.md index 3b0d844..ac0cf69 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -5,6 +5,10 @@ - **Cents Migration Stage 2 β€” schema flip to integer cents** β€” The 12 dollar (REAL) columns across 8 tables defined in the cents-migration plan are now integer cents at rest. Migration v1.03 converts and back-fills existing rows; the schema, ~288 query sites in routes and services, CSV/spreadsheet import inserts, `userDbImportService` unit detection, and test fixtures are all cents-aware. CSV export divides by 100 for display. Float dollars are eliminated before the data grows further, and the units now match SimpleFIN transactions/accounts (already cents). Stage 1's `utils/money.js` remains the single source of truth for arithmetic. The full plan, migration SQL, and verification checklist live in `docs/cents-migration-plan.md`. +### 🧹 Cleanup + +- **Retired static UI removed** β€” Deleted the old `legacy/` and root `public/` static UI copies, including the broken duplicate `public/js/api.js` client. The server now returns `410 Gone` for `/legacy` instead of serving stale assets, the hidden About-page legacy link is gone, and current docs no longer list the retired static UI as part of the runtime structure. + ## v0.37.0 ### ✨ Added diff --git a/README.md b/README.md index 21570e6..6eb5838 100644 --- a/README.md +++ b/README.md @@ -448,7 +448,6 @@ bill-tracker/ | `-- pages/ # Route pages |-- db/ # SQLite schema, migrations, and database helpers |-- docs/ # Technical references and README screenshots -|-- legacy/ # Legacy static UI retained for reference |-- middleware/ # Auth, CSRF, rate limit, security, and error middleware |-- routes/ # Express API route handlers |-- scripts/ # Utility, migration, deployment, and smoke-test scripts diff --git a/REVIEW.md b/REVIEW.md index 78a5bde..637bf85 100644 --- a/REVIEW.md +++ b/REVIEW.md @@ -10,12 +10,11 @@ #### CSRF Token Handling Fixes **Issue:** Create user and other state-changing requests failing with CSRF errors. -**Root Cause:** Legacy and public API clients not sending CSRF tokens. +**Root Cause:** Retired static API clients were not sending CSRF tokens. **Fixes Applied:** 1. `client/api.js` - βœ… Already correct -2. `legacy/js/api.js` - βœ… Fixed - added `credentials: 'include'` and CSRF token extraction -3. `public/js/api.js` - βœ… Fixed - added `credentials: 'include'` and CSRF token extraction +2. Retired `legacy/js/api.js` and `public/js/api.js` - βœ… Removed with the static legacy UI cleanup #### CSRF Cookie httpOnly Configuration (Neo) - 2026-05-08 **Issue:** Need configurable CSRF cookie httpOnly setting for SPA vs secure mode. @@ -922,4 +921,3 @@ Command failed: cd /home/kaspa/.openclaw/Projects/bill-tracker && npx playwright The notes feature is implemented as **per-bill AND per-month**. Each bill has its own notes field, and each month has its own separate notes. --- - diff --git a/client/pages/AboutPage.jsx b/client/pages/AboutPage.jsx index d87a5f1..1a4c2b9 100644 --- a/client/pages/AboutPage.jsx +++ b/client/pages/AboutPage.jsx @@ -156,20 +156,6 @@ export default function AboutPage() { - - {/* Easter egg β€” barely visible, reveals on hover for curious explorers */} -
- -
); } diff --git a/docs/Engineering_Reference_Manual.md b/docs/Engineering_Reference_Manual.md index f4a4271..54f702a 100644 --- a/docs/Engineering_Reference_Manual.md +++ b/docs/Engineering_Reference_Manual.md @@ -83,7 +83,7 @@ Global middleware order: 4. `cookieParser()` 5. `csrfTokenProvider` 6. mounted API routers with route-level rate-limit/auth/CSRF middleware -7. static `legacy/`, redirect `/login.html` to `/login`, static `dist/` +7. retired `/legacy` route returns 410, redirect `/login.html` to `/login`, static `dist/` 8. SPA fallback `GET *` serving `dist/index.html` after ensuring a CSRF token cookie 9. `errorFormatter` 10. final JSON error handler for malformed JSON/body size/runtime errors diff --git a/legacy/admin.html b/legacy/admin.html deleted file mode 100644 index 163d0f2..0000000 --- a/legacy/admin.html +++ /dev/null @@ -1,766 +0,0 @@ - - - - - - Bill Tracker β€” Admin - - - - -
- -
- - -
- - -
-
-
-
-
-
- - -
-
-
🔒
-

Welcome to Bill Tracker

-

- You're logged in as the admin. Before you get started, - here's exactly what this account can and cannot do. -

-
    -
  • - - - Create user accounts - You control who can log in. - -
  • -
  • - - - Reset user passwords - If a user gets locked out, you can reset their password. - -
  • -
  • - - - Cannot access any financial data - Bills, payments, and tracker data are completely off-limits to this account β€” by design. - -
  • -
  • - - - Cannot view account balances or history - Your financial privacy is enforced at the API level, not just the UI. - -
  • -
- -
-
- - -
-
-
👤
-

Create Your User Account

-

- This account will have full access to the tracker, bills, and payments. - Use this account for your day-to-day bill tracking. -

-
-
-
- - -
-
-
- - -
-
- - -
-
-
- - -
-
-
-
-
- - -
-
-
- Admin Account Scope -
    -
  • You can create user accounts and reset passwords.
  • -
  • You cannot view, access, or modify any bills, payments, or financial data.
  • -
  • Users are informed that only their password can be reset by this account.
  • -
-
- -
-

Email Notifications

-

Loading…

-
- -
-

Login Mode

-

Loading…

-
- -
-

Add User

-
-
- - -
-
- - -
- -
-
-
- -
-

Users

-

Loading…

-
-
-
- - - - diff --git a/legacy/css/style.css b/legacy/css/style.css deleted file mode 100644 index 833c2c6..0000000 --- a/legacy/css/style.css +++ /dev/null @@ -1,888 +0,0 @@ -/* ── Reset & base ── */ -*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } - -:root { - --bg: #0d1526; - --surface: #162236; - --surface-2: #1c2d47; - --surface-3: #223558; - --border: rgba(255,255,255,0.07); - --border-strong: rgba(255,255,255,0.14); - --text: #e2e8f0; - --text-muted: #8faab8; - --text-faint: #506070; - --primary: #6366f1; - --primary-hover: #4f46e5; - --primary-light: rgba(99,102,241,0.18); - --success: #22d3a5; - --success-light: rgba(34,211,165,0.15); - --danger: #f43f5e; - --danger-light: rgba(244,63,94,0.15); - --warning: #fb923c; - --warning-light: rgba(251,146,60,0.15); - --info: #38bdf8; - --info-light: rgba(56,189,248,0.15); - --sidebar-w: 200px; - --header-h: 56px; - --radius: 6px; - --shadow: 0 1px 3px rgba(0,0,0,0.4), 0 0 0 1px var(--border); - --font: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; -} - -body { - font-family: var(--font); - font-size: 14px; - background: var(--bg); - color: var(--text); - line-height: 1.5; - min-height: 100vh; -} - -/* ── Scrollbar ── */ -::-webkit-scrollbar { width: 6px; height: 6px; } -::-webkit-scrollbar-track { background: transparent; } -::-webkit-scrollbar-thumb { background: var(--surface-3); border-radius: 3px; } -::-webkit-scrollbar-thumb:hover { background: var(--border-strong); } - -/* ── Layout ── */ -#app { - display: flex; - min-height: 100vh; -} - -.sidebar { - width: var(--sidebar-w); - background: #0a1120; - color: var(--text-muted); - display: flex; - flex-direction: column; - flex-shrink: 0; - position: fixed; - top: 0; left: 0; bottom: 0; - z-index: 100; - border-right: 1px solid var(--border); -} - -.logo { - display: flex; - align-items: center; - gap: 10px; - padding: 20px 16px 16px; - border-bottom: 1px solid var(--border); - margin-bottom: 8px; -} - -.logo-icon { - width: 30px; height: 30px; - background: var(--primary); - border-radius: var(--radius); - display: flex; align-items: center; justify-content: center; - font-weight: 800; font-size: 15px; color: white; - box-shadow: 0 0 12px rgba(99,102,241,0.35); -} - -.logo-text { - font-weight: 600; - color: var(--text); - font-size: 15px; -} - -.nav-links { - list-style: none; - padding: 0 8px; -} - -.nav-links li { margin: 2px 0; } - -.nav-link { - display: flex; - align-items: center; - gap: 10px; - padding: 8px 10px; - border-radius: var(--radius); - color: var(--text-muted); - text-decoration: none; - font-size: 13.5px; - transition: background .15s, color .15s; -} - -.nav-link:hover { background: var(--surface-2); color: var(--text); } -.nav-link.active { background: var(--primary-light); color: var(--primary); } - -.nav-icon { font-size: 12px; opacity: .8; } - -.sidebar-footer { - margin-top: auto; - padding: 8px 8px 12px; - border-top: 1px solid var(--border); -} - -#sidebar-username { - display: block; - font-size: 11px; - color: var(--text-faint); - padding: 4px 10px 6px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; -} - -.sidebar-logout { - font-size: 12px !important; - opacity: .7; -} -.sidebar-logout:hover { opacity: 1; } - -.main-content { - margin-left: var(--sidebar-w); - flex: 1; - min-height: 100vh; - padding: 24px; -} - -.page { display: none; } -.page.active { display: block; } - -/* ── Page header ── */ -.page-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 20px; -} - -.page-title { - font-size: 20px; - font-weight: 700; - color: var(--text); -} - -/* ── Summary cards ── */ -.summary-bar { - display: grid; - grid-template-columns: repeat(4, 1fr); - gap: 12px; - margin-bottom: 20px; -} - -.summary-card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - padding: 14px 16px; - box-shadow: var(--shadow); - position: relative; - overflow: hidden; -} - -.summary-card::before { - content: ''; - position: absolute; - top: 0; left: 0; right: 0; - height: 2px; - background: var(--border-strong); -} - -.summary-card.danger::before { background: var(--danger); } -.summary-card.success::before { background: var(--success); } -.summary-card.warning::before { background: var(--warning); } - -.summary-card .label { - font-size: 11px; - font-weight: 600; - text-transform: uppercase; - letter-spacing: .06em; - color: var(--text-muted); - margin-bottom: 6px; -} - -.summary-card .value { - font-size: 22px; - font-weight: 700; - color: var(--text); -} - -.summary-card.danger .value { color: var(--danger); } -.summary-card.success .value { color: var(--success); } -.summary-card.warning .value { color: var(--warning); } - -/* ── Month nav ── */ -.month-nav { - display: flex; - align-items: center; - gap: 12px; -} - -.month-nav .month-label { - font-size: 16px; - font-weight: 600; - min-width: 130px; - text-align: center; - color: var(--text); -} - -/* ── Tracker table ── */ -.bucket-section { - margin-bottom: 24px; -} - -.bucket-header { - display: flex; - align-items: center; - gap: 10px; - padding: 6px 0; - margin-bottom: 8px; - border-bottom: 2px solid var(--border); -} - -.bucket-label { - font-size: 12px; - font-weight: 700; - text-transform: uppercase; - letter-spacing: .07em; - color: var(--text-muted); -} - -.bucket-totals { - font-size: 12px; - color: var(--text-faint); - margin-left: auto; -} - -.tracker-table { - width: 100%; - border-collapse: collapse; - background: var(--surface); - border-radius: var(--radius); - overflow: hidden; - box-shadow: var(--shadow); - border: 1px solid var(--border); -} - -.tracker-table th { - background: var(--surface-2); - padding: 9px 12px; - text-align: left; - font-size: 11px; - font-weight: 700; - text-transform: uppercase; - letter-spacing: .06em; - color: var(--text-muted); - border-bottom: 1px solid var(--border-strong); - white-space: nowrap; -} - -.tracker-table td { - padding: 0; - border-bottom: 1px solid var(--border); - vertical-align: middle; -} - -.tracker-table tr:last-child td { border-bottom: none; } - -.tracker-table tr:hover td { background: var(--surface-2); } -.tracker-table tr.row-paid:hover td { background: rgba(34,211,165,0.07); } -.tracker-table tr.row-late:hover td { background: rgba(251,146,60,0.07); } -.tracker-table tr.row-missed:hover td { background: rgba(244,63,94,0.07); } - -.tracker-table tr.row-paid td { background: rgba(34,211,165,0.04); } -.tracker-table tr.row-late td { background: rgba(251,146,60,0.04); } -.tracker-table tr.row-missed td { background: rgba(244,63,94,0.04); } -.tracker-table tr.row-autodraft td { background: rgba(251,146,60,0.04); } - -.td-inner { - padding: 10px 12px; - display: flex; - align-items: center; - gap: 6px; - min-height: 44px; -} - -/* ── Status badge ── */ -.badge { - display: inline-flex; - align-items: center; - gap: 4px; - padding: 3px 8px; - border-radius: 20px; - font-size: 11px; - font-weight: 600; - white-space: nowrap; - letter-spacing: .02em; -} - -.badge-paid { background: var(--success-light); color: var(--success); } -.badge-upcoming { background: var(--surface-3); color: var(--text-muted); } -.badge-due-soon { background: var(--warning-light); color: var(--warning); } -.badge-late { background: var(--warning-light); color: var(--warning); } -.badge-missed { background: var(--danger-light); color: var(--danger); } -.badge-autodraft { background: var(--warning-light); color: var(--warning); } - -/* ── Inline editable cells ── */ -.editable-cell { - cursor: pointer; - border-radius: 4px; - padding: 4px 6px; - min-width: 80px; - transition: background .1s; -} - -.editable-cell:hover { background: var(--primary-light); } -.editable-cell.empty { color: var(--text-faint); } - -.editable-cell input { - border: none; - outline: none; - background: transparent; - font-size: inherit; - font-family: inherit; - color: var(--text); - width: 100%; - min-width: 80px; -} - -/* ── Bill name cell ── */ -.bill-name-cell { - font-weight: 500; - color: var(--text); -} -.bill-category { - font-size: 11px; - color: var(--text-faint); -} - -/* ── Quick pay group ── */ -.quick-pay-group { - display: flex; - flex-direction: row; - align-items: center; - gap: 6px; -} - -.quick-pay-group input[type="number"] { - width: 80px; - padding: 4px 8px; - font-size: 12px; -} - -/* ── Action buttons ── */ -.btn { - display: inline-flex; - align-items: center; - gap: 5px; - padding: 6px 12px; - border: none; - border-radius: var(--radius); - font-size: 13px; - font-family: var(--font); - font-weight: 500; - cursor: pointer; - transition: background .15s, color .15s, opacity .15s, box-shadow .15s; - white-space: nowrap; -} - -.btn:disabled { opacity: .4; cursor: not-allowed; } - -.btn-primary { background: var(--primary); color: white; } -.btn-primary:hover:not(:disabled) { background: var(--primary-hover); box-shadow: 0 0 0 3px rgba(99,102,241,0.25); } - -.btn-success { background: var(--success); color: #0d1526; } -.btn-success:hover:not(:disabled) { background: #1ab890; } - -.btn-ghost { - background: transparent; - color: var(--text-muted); - border: 1px solid var(--border-strong); -} -.btn-ghost:hover:not(:disabled) { background: var(--surface-2); color: var(--text); border-color: var(--border-strong); } - -.btn-danger { background: var(--danger); color: white; } -.btn-danger:hover:not(:disabled) { background: #e11d48; } - -.btn-sm { padding: 4px 8px; font-size: 12px; } - -.btn-pay { - background: var(--primary-light); - color: var(--primary); - border: 1px solid rgba(99,102,241,0.3); - padding: 4px 10px; - font-size: 12px; - font-weight: 600; - border-radius: var(--radius); -} -.btn-pay:hover { background: var(--primary); color: white; border-color: var(--primary); } - -.btn-icon { - background: transparent; - color: var(--text-faint); - border: none; - padding: 4px 6px; - font-size: 14px; - border-radius: 4px; - cursor: pointer; - transition: background .15s, color .15s; -} -.btn-icon:hover { background: var(--surface-2); color: var(--text); } - -/* ── Action cell ── */ -.action-cell { - display: flex; - align-items: center; - gap: 4px; - padding: 8px 10px; -} - -/* ── Amount display ── */ -.amount-expected { color: var(--text-muted); font-size: 13px; } -.amount-actual { font-weight: 600; color: var(--text); } -.amount-mismatch { color: var(--warning); } - -/* ── Bills management page ── */ -.bills-grid { - display: grid; - gap: 10px; -} - -.bill-card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - padding: 14px 16px; - display: flex; - align-items: center; - gap: 12px; - box-shadow: var(--shadow); - transition: border-color .15s, background .15s; -} - -.bill-card:hover { border-color: var(--primary); background: var(--surface-2); } -.bill-card.inactive { opacity: .45; } - -.bill-card-info { flex: 1; min-width: 0; } -.bill-card-name { font-weight: 600; font-size: 14px; color: var(--text); } -.bill-card-meta { font-size: 12px; color: var(--text-muted); margin-top: 2px; } - -.bill-card-amount { - font-size: 16px; - font-weight: 700; - color: var(--text); - min-width: 80px; - text-align: right; -} - -.bill-card-actions { display: flex; gap: 6px; } - -/* ── Categories page ── */ -.cat-list { display: flex; flex-direction: column; gap: 8px; } - -.cat-item { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - padding: 10px 14px; - display: flex; - align-items: center; - gap: 10px; - box-shadow: var(--shadow); - transition: border-color .15s; -} -.cat-item:hover { border-color: var(--border-strong); } - -.cat-name { flex: 1; font-weight: 500; color: var(--text); } - -.cat-add-form { - display: flex; - gap: 8px; - margin-bottom: 16px; -} - -/* ── Settings page ── */ -.settings-section { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - padding: 20px; - margin-bottom: 16px; - box-shadow: var(--shadow); -} - -.settings-section h3 { - font-size: 14px; - font-weight: 700; - margin-bottom: 16px; - color: var(--text); - border-bottom: 1px solid var(--border); - padding-bottom: 8px; -} - -.settings-row { - display: flex; - align-items: center; - gap: 12px; - margin-bottom: 12px; -} - -.settings-row:last-child { margin-bottom: 0; } - -.settings-row label { - min-width: 180px; - font-size: 13px; - color: var(--text-muted); - font-weight: 500; -} - -/* ── Forms ── */ -.form-group { - display: flex; - flex-direction: column; - gap: 5px; -} - -.form-group label { - font-size: 12px; - font-weight: 600; - color: var(--text-muted); - text-transform: uppercase; - letter-spacing: .04em; -} - -.form-grid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 14px; - margin-bottom: 16px; -} - -.form-group.full-width { grid-column: 1 / -1; } -.form-group.checkbox-group { flex-direction: row; flex-wrap: wrap; gap: 16px; } -.form-group.checkbox-group label { - display: flex; align-items: center; gap: 6px; - text-transform: none; letter-spacing: 0; font-size: 13px; font-weight: 500; color: var(--text); - cursor: pointer; -} - -input[type="text"], -input[type="number"], -input[type="date"], -input[type="email"], -input[type="password"], -select, -textarea { - padding: 7px 10px; - border: 1px solid var(--border-strong); - border-radius: var(--radius); - font-size: 13px; - font-family: var(--font); - color: var(--text); - background: var(--surface-2); - transition: border-color .15s, box-shadow .15s; - width: 100%; -} - -input:focus, select:focus, textarea:focus { - outline: none; - border-color: var(--primary); - box-shadow: 0 0 0 3px rgba(99,102,241,0.2); -} - -select option { - background: var(--surface-2); - color: var(--text); -} - -input::placeholder { color: var(--text-faint); } -textarea::placeholder { color: var(--text-faint); } -textarea { resize: vertical; } - -input[type="checkbox"] { - width: 15px; - height: 15px; - accent-color: var(--primary); - cursor: pointer; -} - -/* ── Modal ── */ -.modal { - position: fixed; - inset: 0; - z-index: 200; - display: flex; - align-items: center; - justify-content: center; -} - -.modal.hidden { display: none; } - -.modal-overlay { - position: absolute; - inset: 0; - background: rgba(0,0,0,0.65); - backdrop-filter: blur(2px); -} - -.modal-box { - position: relative; - background: var(--surface); - border: 1px solid var(--border-strong); - border-radius: 10px; - width: 100%; - max-width: 560px; - max-height: 90vh; - overflow-y: auto; - box-shadow: 0 24px 80px rgba(0,0,0,0.6), 0 0 0 1px var(--border); - padding: 24px; -} - -.modal-box-sm { max-width: 380px; } - -.modal-header { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 20px; -} - -.modal-header h2 { - font-size: 16px; - font-weight: 700; - color: var(--text); -} - -.modal-close { - background: none; - border: none; - font-size: 22px; - color: var(--text-faint); - cursor: pointer; - padding: 0 4px; - line-height: 1; - transition: color .15s; -} -.modal-close:hover { color: var(--text); } - -.modal-footer { - display: flex; - align-items: center; - justify-content: flex-end; - gap: 8px; - margin-top: 20px; - padding-top: 16px; - border-top: 1px solid var(--border); -} - -/* ── Toast notifications ── */ -#toast-container { - position: fixed; - bottom: 24px; - right: 24px; - z-index: 999; - display: flex; - flex-direction: column-reverse; - gap: 8px; - pointer-events: none; -} - -.toast { - display: flex; - align-items: flex-start; - gap: 10px; - min-width: 280px; - max-width: 380px; - padding: 12px 14px 12px 16px; - border-radius: var(--radius); - background: var(--surface-2); - border: 1px solid var(--border-strong); - border-left-width: 3px; - box-shadow: 0 8px 32px rgba(0,0,0,0.5), 0 1px 0 rgba(255,255,255,0.04); - font-size: 13px; - font-weight: 500; - color: var(--text); - opacity: 0; - transform: translateX(20px) translateY(4px); - transition: opacity .25s ease, transform .25s ease; - pointer-events: auto; -} - -.toast.show { - opacity: 1; - transform: translateX(0) translateY(0); -} - -.toast.hide { - opacity: 0; - transform: translateX(20px) translateY(4px); - transition: opacity .2s ease, transform .2s ease; -} - -.toast-icon { - font-size: 15px; - flex-shrink: 0; - margin-top: 1px; -} - -.toast-body { flex: 1; line-height: 1.4; } - -.toast.success { border-left-color: var(--success); } -.toast.success .toast-icon { color: var(--success); } - -.toast.error { border-left-color: var(--danger); } -.toast.error .toast-icon { color: var(--danger); } - -.toast.warning { border-left-color: var(--warning); } -.toast.warning .toast-icon { color: var(--warning); } - -.toast.info { border-left-color: var(--info); } -.toast.info .toast-icon { color: var(--info); } - -/* Legacy single #toast element (backwards compatibility) */ -#toast { - position: fixed; - bottom: 24px; - right: 24px; - background: var(--surface-2); - color: var(--text); - padding: 11px 16px 11px 18px; - border-radius: var(--radius); - border: 1px solid var(--border-strong); - border-left: 3px solid var(--primary); - font-size: 13px; - font-weight: 500; - box-shadow: 0 8px 32px rgba(0,0,0,0.5); - z-index: 999; - opacity: 0; - transform: translateX(20px); - transition: opacity .25s, transform .25s; - pointer-events: none; - max-width: 360px; -} - -#toast.show { opacity: 1; transform: translateX(0); } -#toast.success { border-left-color: var(--success); } -#toast.error { border-left-color: var(--danger); } -#toast.warning { border-left-color: var(--warning); } - -/* ── Status page ── */ -.status-page { - max-width: 700px; - margin: 0 auto; -} - -.status-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); - gap: 14px; - margin-bottom: 24px; -} - -.status-card { - background: var(--surface); - border: 1px solid var(--border); - border-radius: var(--radius); - padding: 16px 18px; - box-shadow: var(--shadow); - display: flex; - align-items: center; - gap: 14px; -} - -.status-dot { - width: 11px; - height: 11px; - border-radius: 50%; - flex-shrink: 0; - position: relative; -} - -.status-dot.green { - background: var(--success); - box-shadow: 0 0 0 0 rgba(34,211,165,0.4); - animation: pulse-green 2s infinite; -} - -.status-dot.red { - background: var(--danger); - box-shadow: 0 0 0 0 rgba(244,63,94,0.4); - animation: pulse-red 2s infinite; -} - -@keyframes pulse-green { - 0% { box-shadow: 0 0 0 0 rgba(34,211,165,0.5); } - 70% { box-shadow: 0 0 0 7px rgba(34,211,165,0); } - 100% { box-shadow: 0 0 0 0 rgba(34,211,165,0); } -} - -@keyframes pulse-red { - 0% { box-shadow: 0 0 0 0 rgba(244,63,94,0.5); } - 70% { box-shadow: 0 0 0 7px rgba(244,63,94,0); } - 100% { box-shadow: 0 0 0 0 rgba(244,63,94,0); } -} - -.stat-row { - display: flex; - align-items: center; - justify-content: space-between; - padding: 9px 0; - border-bottom: 1px solid var(--border); - font-size: 13px; -} - -.stat-row:last-child { border-bottom: none; } - -.stat-row .stat-label { color: var(--text-muted); } -.stat-row .stat-value { font-weight: 600; color: var(--text); } - -/* ── Misc ── */ -.empty-state { - text-align: center; - padding: 48px 20px; - color: var(--text-faint); -} -.empty-state p { font-size: 14px; margin-top: 8px; } - -.loading { - text-align: center; - padding: 32px; - color: var(--text-faint); - font-size: 13px; -} - -.autopay-dot { - display: inline-block; - width: 6px; height: 6px; - border-radius: 50%; - background: var(--warning); - margin-right: 2px; - vertical-align: middle; -} - -.text-muted { color: var(--text-muted); } -.text-faint { color: var(--text-faint); } -.text-sm { font-size: 12px; } -.mt-1 { margin-top: 4px; } -.gap-8 { gap: 8px; } - -/* ── Divider ── */ -hr { - border: none; - border-top: 1px solid var(--border); - margin: 12px 0; -} - -/* ── Code / monospace ── */ -code { - background: var(--surface-3); - color: var(--info); - padding: 1px 5px; - border-radius: 3px; - font-size: 12px; - font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace; -} - -/* ── Responsive ── */ -@media (max-width: 768px) { - .sidebar { width: 60px; } - .logo-text, .nav-link span:not(.nav-icon) { display: none; } - .main-content { margin-left: 60px; padding: 16px; } - .summary-bar { grid-template-columns: repeat(2, 1fr); } - .form-grid { grid-template-columns: 1fr; } -} diff --git a/legacy/index.html b/legacy/index.html deleted file mode 100644 index 22f7bae..0000000 --- a/legacy/index.html +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - Bill Tracker - - - -
- - -
-
-
-
-
-
-
-
- - - - - -