max / goingson
1 file changed,
+29 insertions,
-324 deletions
| @@ -1,339 +1,44 @@ | |||
| 1 | 1 | # GoingsOn TODO | |
| 2 | 2 | ||
| 3 | - | ## Launch readiness (Monday 2026-06-01) — IN PROGRESS | |
| 3 | + | ## Launch readiness — IN PROGRESS (target 2026-06-01 slipped; correctness over deadline) | |
| 4 | 4 | ||
| 5 | - | ### §3.4 fuzz pass — DONE 2026-05-31 | |
| 6 | - | Four-axis parallel audit (rust-fuzz + use-fuzz + creator-fuzz + ux-audit) complete. 10 launch-critical fixes committed (emoji sweep in 3 empty-state strings, About modal + Settings → About both populated with publisher/license/contact/source/privacy/copyright, hard-fail error copy humanized, `questions@` → `info@` in privacy policy, README trust block + Your Data section, bulk-bar CSS color contradiction removed, four bulk Delete buttons given `.btn-danger`). CSS rebuilt via `build-css.sh`. | |
| 7 | - | ||
| 8 | - | ### Deferred to post-launch (audited but not blocking) | |
| 9 | - | ||
| 10 | - | **rust-fuzz** | |
| 11 | - | - ~~`email.rs:598` blocking `fs::read` in async.~~ Done 2026-06-02. Switched to `tokio::fs::read(...).await` — simpler than the `spawn_blocking` recipe and matches the existing async-IO style for tokio::fs::write a few lines above. | |
| 12 | - | - ~~`smtp_client.rs:291` `ContentType::parse(...).unwrap()`.~~ Done 2026-06-02. Replaced unwrap with `or_else` parse + `map_err(...)` to propagate as a real error. `lettre::ContentType` has no public const for octet-stream; this is the closest no-panic path. | |
| 13 | - | - ~~Mutex `.expect("poisoned")` sweep.~~ Done 2026-06-02. All 7 callsites (`state.rs:173`, `sync.rs:{75,177,203}`, `oauth.rs:{131,166}`, `email_sync.rs:49`) switched to `unwrap_or_else(|e| e.into_inner())`. `sync.rs:75` is an `RwLock::read`; the same pattern works. | |
| 14 | - | - `db_watcher.rs:61` — shutdown latency = `MIN_EVENT_INTERVAL_MS`, thread unjoinable. Cosmetic. Leaving. | |
| 15 | - | ||
| 16 | - | **use-fuzz** | |
| 17 | - | - ~~`seed-data.js:393` prod `console.log`.~~ Done 2026-06-02. Removed. | |
| 18 | - | - ~~`app.js` chatty launch logs.~~ Done 2026-06-02. Stripped the four informational `console.log` calls (Desktop loaded, Loaded N projects, Loaded N accounts, external-change/sync-changes/modal-skip/refresh-success). All `console.error` retained. | |
| 19 | - | - ~~`{emails,tasks,task-board}.js` bare "Failed to load".~~ Done 2026-06-02. All four inline error blocks (tasks.js:126, emails.js:105, events.js:419, task-board.js:92) now embed a "Try again" `.btn-link` that calls the corresponding load fn. The toast-side Retry action already existed; this is the parallel in-place recovery. | |
| 20 | - | - ~~`settings.js:196` Linux plugin path.~~ Done 2026-06-02. Replaced `~/.config/goingson/plugins/` with neutral OS-agnostic phrasing ("inside your OS app-data location"). | |
| 21 | - | - ~~`index.html:603` literal `x` close button.~~ Done 2026-06-02. Now `×`. | |
| 22 | - | - `index.html:18-57` — `?ui=mobile` prod lockdown. Deferred — same item as §K Phase 6, blocks on a desktop-mobile distribution channel existing. | |
| 23 | - | ||
| 24 | - | **creator-fuzz** | |
| 25 | - | - ~~`CHANGELOG.md:24-26` audit-runs language.~~ Done 2026-06-02. Replaced "all issues identified in audit runs 1–12" with six concrete user-visible fixes (empty-state copy, About/Settings populated, hard-fail copy, bulk-action danger color, mutex poisoning recovery, SMTP unwrap fix). | |
| 26 | - | - ~~`docs/data-export.md`.~~ Done 2026-06-02. Written. Covers all five export formats (JSON, gzipped backup, CSV, ICS, raw SQLite), the top-level JSON schema with version + `exportedAt`, per-entity field summaries pointing at `crates/core/src/` for full shapes, denormalized-field caveats, restore semantics (replace vs merge), a verification recipe a user can run with `gunzip` + a text editor, and the not-exported list (OAuth tokens, TOTP secrets, sync state, window state). Source-of-truth pointer at the bottom. | |
| 27 | - | - ~~Settings "Check for updates on launch" toggle.~~ Done 2026-06-02. New `commands::preferences` module persists a tiny JSON pref file in the Tauri app config dir (`preferences.json`, `update_check_on_launch: bool`, default true). Two commands wired: `get_preferences`, `set_update_check_on_launch`. `main.rs` setup hook gates the 10s-delay updater check on the preference. Settings → About now shows a toggle row (new `.settings-toggle-row` primitive) replacing the static "Updates are checked automatically on launch" line; toast confirms the save. API wrapper: `GoingsOn.api.preferences.{get, setUpdateCheckOnLaunch}`. Tauri config (`createUpdaterArtifacts`, endpoints, pubkey) untouched — the toggle gates the check, not the plugin. | |
| 28 | - | - ~~README PolyForm-NC commercial contact.~~ Done 2026-06-02. License section now invites commercial-use inquiries at `info@makenot.work`. | |
| 29 | - | ||
| 30 | - | **ux-audit** | |
| 31 | - | - ~~`styles.css:590-660` — `.btn` offset-shadow brand cue.~~ Done 2026-06-02. `.btn` base now carries `--shadow-brutal-xs` (1px). Hover lifts to 3px shadow + `translate(-1px,-1px)`; active presses to `translate(1px,1px)` + no shadow. Transition extended to include `transform` and `box-shadow`. `.btn-primary` / `.btn-danger` inherit. `.btn-link` and `.btn-icon` are sibling primitives (not `.btn` extenders) so unaffected. `.bulk-actions-bar .btn` inherits cleanly. | |
| 32 | - | - ~~`styles.css:615` — disabled-button contrast.~~ Done 2026-06-02. Opacity dropped; now `transparent bg + muted color + muted border + no shadow`. | |
| 33 | - | - `.pill.active` / `.tab.active` lift — Done 2026-06-02. Both gained `--shadow-brutal-xs` to distinguish active from inactive chrome. | |
| 34 | - | - ~~`styles.css:4712` — `.sync-label` mobile shape variation.~~ Done 2026-06-02. Shape now encodes state on the dot itself (works in mobile + monochrome + high-contrast): `connected`/`syncing` stay circular; `warn` is a rotated square (diamond); `error` is a square. Label-hiding behavior unchanged. | |
| 35 | - | - ~~Single-item destructive `.btn-loading`.~~ Reviewed 2026-06-02 — not applicable. Audit cited `tasks.js:657` but every single-item destructive flow (`tasks.js`, `projects.js`, `events.js`, `emails.js`) is optimistic with `showUndoToast`: the UI removes the item the instant the confirm modal closes, so there is no button still mounted to carry a loading state. Optimism + undo is a stronger UX than a spinner. Closing without code change. | |
| 36 | - | - ~~`index.html:466` straggler `row-flex-2`.~~ Done 2026-06-02. Now matches neighbors as `row-flex row-flex-2`. | |
| 37 | - | - ~~Back-arrow consistency.~~ Done 2026-06-02. `index.html:270` literal `← Back` → `← Back` matching the other three back-arrow buttons. | |
| 5 | + | ### §3.2 distribution — NEXT, blocks launch | |
| 6 | + | - Signed builds + notarization stapled + DMG smoke test on a clean macOS account. | |
| 7 | + | - Build on pop-os (x86_64) and astra (aarch64) natively per the no-cross-compile rule. | |
| 8 | + | - macOS notarization via altool key in `_private/`. | |
| 9 | + | - Smoke test: install DMG on a clean macOS user account, launch, verify Gatekeeper passes, run the welcome flow, exit, relaunch. | |
| 10 | + | - iOS TestFlight: re-check the appiconset alpha-flatten step (required every iOS build per memory). | |
| 38 | 11 | ||
| 39 | - | ### §3.1 — DONE for emoji/About/error-copy. Remaining: | |
| 40 | - | - Mobile UI mode override hardening (see use-fuzz deferral above). | |
| 12 | + | ### §3.1 mobile UI mode hardening — DEFERRED | |
| 13 | + | - `index.html:18-57` `?ui=mobile` prod lockdown. Same item as §K Phase 6; blocks on a desktop-mobile distribution channel existing. | |
| 41 | 14 | ||
| 42 | - | ### §3.2 distribution — NOT STARTED | |
| 43 | - | - Signed builds + notarization stapled + DMG smoke test on a clean macOS account. | |
| 15 | + | ### §3.4 fuzz pass — DONE 2026-05-31 | |
| 16 | + | Four-axis parallel audit (rust-fuzz + use-fuzz + creator-fuzz + ux-audit). Launch-critical fixes committed pre-launch; deferred items closed 2026-06-02 (commits `7421ead`, `9719e28`). One cosmetic item left: `db_watcher.rs:61` shutdown latency = `MIN_EVENT_INTERVAL_MS`, thread unjoinable. Not worth fixing. | |
| 44 | 17 | ||
| 45 | 18 | ### §3.3 repo hygiene — DONE 2026-06-02 | |
| 46 | - | - Stray root planning files: already moved to `docs/_archive/` pre-session. | |
| 47 | - | - `generate_pitch_pdf.py` + `GoingsOn-Pitch.pdf` deleted (regenerable; git preserves). | |
| 48 | - | - Root `_archive/` (pre-Tauri Rust HTTP server) deleted; migration shipped 2026-06-01, git history is the right home for pre-migration reference. | |
| 49 | - | ||
| 50 | - | CSS dedup work below is the active in-progress stream; launch readiness is its own track. | |
| 51 | 19 | ||
| 52 | 20 | --- | |
| 53 | 21 | ||
| 54 | - | # GoingsOn CSS Dedup TODO | |
| 22 | + | # GoingsOn CSS Dedup — DONE (2026-05-24) | |
| 55 | 23 | ||
| 56 | - | Charter + primitive vocabulary lives at the top of | |
| 57 | - | `src-tauri/frontend/css/styles.css`. The constraint that "visual output | |
| 58 | - | must not change" has been relaxed: visual *changes* are OK as long as | |
| 59 | - | they're not worse. Prefer one consistent visual per element family. | |
| 60 | - | ||
| 61 | - | Always rebuild after changes: | |
| 24 | + | Charter + primitive vocabulary lives at the top of `src-tauri/frontend/css/styles.css`. Always rebuild after changes: | |
| 62 | 25 | ``` | |
| 63 | 26 | cd src-tauri/frontend && ./build-css.sh | |
| 64 | 27 | ``` | |
| 65 | 28 | ||
| 66 | - | --- | |
| 67 | - | ||
| 68 | - | ## A. Buttons — consolidate to one family | |
| 69 | - | ||
| 70 | - | 53 button-related selectors live in `styles.css`. They cluster around 4 | |
| 71 | - | canonical primitives (`.btn`, `.btn-icon`, `.btn-link`, `.btn-loading`) | |
| 72 | - | plus ~15 bespoke `*-btn` classes that each invented their own padding / | |
| 73 | - | font / hover. | |
| 74 | - | ||
| 75 | - | ### Canonical button family (target) | |
| 76 | - | - `.btn` — base. `inline-flex`, padding `0.625rem 1.25rem`, border, radius-sm, font 0.9rem/600. | |
| 77 | - | - Intents: `.btn-primary`, `.btn-secondary`, `.btn-danger`. | |
| 78 | - | - Sizes: `.btn-sm` (+ new `.btn-lg` if any of the bespoke ones genuinely need it). | |
| 79 | - | - Variants: `.btn-icon` (chrome icon button, no border), `.btn-link` (text-link button). | |
| 80 | - | - States: `:hover`, `:active`, `:disabled`, `.btn-loading`. | |
| 81 | - | ||
| 82 | - | ### Bespoke buttons to migrate | |
| 83 | - | For each, find the closest canonical and migrate. Visual deltas are | |
| 84 | - | acceptable when they bring the button into the system. | |
| 85 | - | ||
| 86 | - | | Bespoke class | Maps to | Notes | | |
| 87 | - | |---------------|---------|-------| | |
| 88 | - | | ~~`.settings-btn`~~ | `.btn` | Done 2026-05-24. Structural styling (bg-card, border, radius-sm, hover/active) already matched `.btn`; only deltas were font-size (1.25rem → 0.9rem) and padding (tighter horizontal). Accepted smaller per charter. `margin-left` dropped — `.header-actions` parent already sets `gap: 0.5rem`. Mobile path unaffected (`.app-header` is `display:none` on `.ui-mode-mobile`). | | |
| 89 | - | | ~~`.shortcut-hint-btn`~~ | `.btn.shortcut-hint-btn` | Done 2026-05-24. Marker class retained for mono font + min-width + tighter padding override (single-glyph `?` button) and for the touch/mobile `display:none` rule. Bespoke chrome (border/bg/hover) dropped — now inherited from `.btn`. | | |
| 90 | - | | ~~`.settings-back-btn`~~ | `.btn-link.mb-1.settings-back` | Done 2026-05-24. Marker class kept for mobile-pass override. | | |
| 91 | - | | `.settings-nav-item` | New `.btn-nav` *or* not-a-button | It's a nav item, not really a button. Keep as is. | | |
| 92 | - | | ~~`.undo-btn`~~ | `.btn.btn-sm.btn-primary` | Done 2026-05-24. Bespoke was custom accent-blue; .btn-primary matches. | | |
| 93 | - | | ~~`.account-delete-btn`~~ | `.btn.btn-sm.btn-danger` | Done 2026-05-24. | | |
| 94 | - | | ~~`.bulk-modal-option-btn`~~ | `.btn.btn-sm.text-left.w-full` + marker class | Done 2026-05-24. New `.w-full` utility; `.bulk-modal-scroll` now flex column with gap; marker class retained for mobile padding override. Stale `btn-ghost` reference removed from callsites. | | |
| 95 | - | | ~~`.email-attachment-remove-btn`~~ | (dead code) | Done 2026-05-24: rule deleted, no callsites. | | |
| 96 | - | | ~~`.toggle-cc-btn`~~ | `.btn-link` | Done 2026-05-24. Accepts underline visual delta. | | |
| 97 | - | | ~~`.attachment-delete-btn`~~ | `.text-accent-red` | Done 2026-05-24: already had `.btn.btn-sm.btn-secondary`; bespoke was only the red color. | | |
| 98 | - | | ~~`.welcome-step-btn`~~ | `.text-left` | Done 2026-05-24: already had `.btn.btn-secondary`; new `.text-left` utility added next to `.text-center`. | | |
| 99 | - | | ~~`.kebab-btn`~~ | `.btn-icon` + slim bespoke for hover-reveal/font-override | Done 2026-05-24. 5 callsites now `btn-icon kebab-btn`. | | |
| 100 | - | | ~~`.schedule-task-btn`~~ | (dead code) | Done 2026-05-24: rule deleted, no callsites. | | |
| 101 | - | | ~~`.time-block-quick-btn`~~ | `.btn.btn-sm.btn-secondary` + marker class | Done 2026-05-24. Bespoke base styles dropped; only `.selected` state override retained. `.selected` JS class kept (not renamed to `.is-selected` — out of scope). | | |
| 102 | - | | ~~`.month-goal-status-btn`~~ | `.btn-icon` + slim bespoke for color/sizing | Done 2026-05-24. | | |
| 103 | - | | ~~`.month-goal-delete-btn`~~ | `.btn-icon` + slim bespoke for hover-reveal/color | Done 2026-05-24. | | |
| 104 | - | | `.view-toggle-btn` (+active) | Keep as-is | Reviewed 2026-05-24. Already its own primitive (joined borders, zero-gap segmented look); not duplication of `.btn`. Rename to `.segmented-control` deferred — cosmetic only. | | |
| 105 | - | | ~~`.btn-danger-text`~~ | `.text-accent-red` (generic utility) | Done 2026-05-24. Kept the secondary chrome on Delete buttons — button-shaped affordance matters for destructive actions; the red text is enough to signal intent. 5 callsites (emails.js, events.js, contact-dashboard.js, task-overview.js, tasks.js) now read `.btn.btn-secondary.text-accent-red`. Bespoke 1-line rule deleted; the existing `.text-accent-red` utility already provided the color. | | |
| 106 | - | ||
| 107 | - | Expected savings: ~80-120 source lines, ~2-3 KB min.css. | |
| 108 | - | ||
| 109 | - | ### Migration approach | |
| 110 | - | 1. Audit each bespoke class's callsites: `grep -rn "<class>" js/ *.html`. | |
| 111 | - | 2. Edit one bespoke class at a time: | |
| 112 | - | a. Decide the canonical mapping. | |
| 113 | - | b. Update callsites to use canonical class(es). | |
| 114 | - | c. Delete bespoke rule from styles.css. | |
| 115 | - | 3. After each migration, rebuild + eyeball the affected surface. | |
| 116 | - | 4. If migration reveals a missing modifier (e.g. `.btn-icon--lg`), add | |
| 117 | - | it next to `.btn-icon` and document in the charter inventory. | |
| 118 | - | ||
| 119 | - | --- | |
| 120 | - | ||
| 121 | - | ## B. Form inputs & selects — one input family | |
| 122 | - | ||
| 123 | - | ### Canonical (target) | |
| 124 | - | - `.form-input` — base text input. | |
| 125 | - | - `.form-select` — base select. | |
| 126 | - | - Sizes: `.form-input--w-200`, `.form-select--compact` (already in place). | |
| 127 | - | - Variants: new `.form-input--ghost` (borderless, used by compose | |
| 128 | - | header rows), new `.form-input--search` (search affordance). | |
| 129 | - | ||
| 130 | - | ### Migrate | |
| 131 | - | - ~~`.quick-add-input`~~ — Done 2026-05-24: dead code. `.quick-add` parent + `.quick-add-input` rules deleted (~28 lines). The actual quick-add modal at `keyboard.js:openQuickAddModal` uses `.form-input`. §10 section header vacated; navigation numbering preserved. | |
| 132 | - | - `.filter-select` → **Skip.** Reviewed 2026-05-24: not duplication. Bespoke focus styling (fills with accent-blue) is a distinctive UX cue, and the smaller padding/font-weight differ enough from `.form-select.form-select--compact` that the migration would lose visual identity for a ~5-line CSS win. Leave as-is. | |
| 133 | - | - ~~`.header-input`~~ → `.form-input.form-input--ghost.flex-1`. Done 2026-05-24. New `.form-input--ghost` modifier added next to base in §20. | |
| 134 | - | - ~~`.header-select`~~ → `.form-select.form-select--ghost.flex-1`. Done 2026-05-24. New `.form-select--ghost` modifier added. | |
| 135 | - | ||
| 136 | - | Savings achieved: ~29 lines (29/(40-60) of estimate). | |
| 137 | - | ||
| 138 | - | --- | |
| 139 | - | ||
| 140 | - | ## C. Cards — one card family with shell + muted variants | |
| 141 | - | ||
| 142 | - | ### Canonical | |
| 143 | - | - `.card` — interactive tile (current). | |
| 144 | - | - `.card--list-item` — compact list row (already added). | |
| 145 | - | - New `.card--muted` — bg-secondary, no shadow/hover, no cursor (mini | |
| 146 | - | info card). | |
| 147 | - | - New `.card--shell` — container shell: no padding, no cursor, no | |
| 148 | - | hover, flex column, overflow handling. For list shells like | |
| 149 | - | `.email-list` and `.dashboard-column`. | |
| 150 | - | ||
| 151 | - | ### Migrate | |
| 152 | - | - ~~`.email-list`~~ → `.card.card--shell.email-list`. Done 2026-05-24. Slim feature rule keeps only `flex: 1; min-height: 0;`. | |
| 153 | - | - `.dashboard-column` → **Skip.** Has no shadow + thinner border, doesn't actually match `.card`'s look; migrating would change visuals across project dashboard. Leave page-scoped. | |
| 154 | - | - ~~`.contact-info-section`~~ → `.card.card--muted.contact-info-section`. Done 2026-05-24. Slim feature rule keeps gap + margin + tighter padding. | |
| 155 | - | - `.contact-summary-stat` → **Skip.** Page-scoped is appropriate (feature-specific stat tile with min-width 80px); not duplication of `.card`. | |
| 156 | - | - ~~`.review-card`~~ → `.card.card--static.review-card`. Done 2026-05-24. New `.card--static` variant added next to `--shell` and `--muted` in §11 (cursor default + no-op hover, full card chrome retained). `.review-card` base slimmed to a single `padding: 1.5rem` declaration; descendants (`.card-header`, `.card-title`, `.card-icon`, `.card-badge`) trimmed to only their review-specific deltas (font-family/font-size/font-weight all inherit from the canonical `.card-*` descendants now). 14 callsites migrated across `plan-review-toggle.js`, `weekly-review-render.js`, `monthly-review-render.js`. Eyeball: weekly + monthly review screens. | |
| 157 | - | - ~~`.kanban-card`~~ → `.card.kanban-card`. Done 2026-05-24. Bespoke bg/border/box-shadow/transition/hover declarations dropped — all inherited from `.card`. Marker class slimmed to its deltas: `border-width-sm` (thinner), `border-radius: 0` (square), `padding: 0.75rem` (tighter), `cursor: grab`, `border-left: 4px solid transparent` (priority hook). Hover transform now inherited (was duplicate). 1 callsite in `tasks-kanban.js`. Eyeball: kanban board view + drag interaction. | |
| 158 | - | ||
| 159 | - | Savings achieved: ~30 net source lines (~17 lines from .review-card bespoke chrome + ~10 lines from .kanban-card duplicate hover/chrome; ~10 lines added for .card--static infra). min.css 152970 → 152465 (-505 bytes). | |
| 160 | - | ||
| 161 | - | --- | |
| 162 | - | ||
| 163 | - | ## D. Badges & tags — unify the chip family | |
| 164 | - | ||
| 165 | - | ### Canonical | |
| 166 | - | - `.tag, .badge` — bordered chip primitive (current). | |
| 167 | - | - Color variants via `[data-color="green|yellow|red|cyan|purple|muted"]` | |
| 168 | - | (already exists). | |
| 169 | - | - New size modifiers: `.badge--sm`, `.badge--xs`. | |
| 170 | - | - New intent modifier: `.badge--filled` (solid accent fill, no border). | |
| 171 | - | ||
| 172 | - | ### Migrate | |
| 173 | - | - `.thread-badge` → **Skip.** Already audited 2026-05-21 as net-zero dedup; composing `.badge` would require overriding every declaration. Leave standalone. | |
| 174 | - | - ~~`.email-label-badge`~~ → `.badge.badge--xs.badge--filled[data-color="blue"]`. Done 2026-05-24. 2 callsites in `emails.js`. Visual delta: text color now white-on-blue instead of lavender-on-blue (acceptable per charter). | |
| 175 | - | - `.subtask-linked-tag` → **Skip.** Tiny 2-property rule (color + font-size), 1 callsite, not really a chip — it's an inline "[Linked]" label. Page-scoped is appropriate. | |
| 176 | - | - `.card-badge--success/-warning/-info/-danger` → **Skip.** Self-contained BEM system inside `.review-card` context; base lives in parent-scoped rule. Already minimal; not duplication of `.badge`. | |
| 177 | - | - ~~`.badge-completed`, `.badge-started`, `.badge-pending`, `.badge-priority-h/m/l`, `.badge-focus`, `.badge-overdue`, `.badge-snoozed`~~ → Done 2026-05-24. All 9 bespoke rules deleted. `task-overview.js:322-326` rewritten with a `chip(color, text)` helper that emits `.badge.badge--xs.badge--filled[data-color="X"]`. New modifiers added in §12: `.badge--xs`, `.badge--sm`, `.badge--filled` (with per-color overrides), plus a new `data-color="blue"` variant on the base. | |
| 178 | - | ||
| 179 | - | Savings achieved: ~4 net source lines (added 22 of modifier infra to delete 22 of bespoke + 9 lines deleted from emails.js + task-overview.js path). Real win is qualitative: one composable badge system, no more invent-a-badge-per-feature. | |
| 180 | - | ||
| 181 | - | --- | |
| 182 | - | ||
| 183 | - | ## E. Avatars — DONE (2026-05-24) | |
| 184 | - | ||
| 185 | - | Promoted `.avatar` primitive in §47 Contacts with `.avatar--sm` (32px, no border), `.avatar--lg` (60px), `.avatar--unknown` (muted bg). All 5 callsites migrated: emails.js (×2), contact-dashboard.js (×1), contacts-render.js (×2). Bespoke rules deleted: `.contact-avatar`, `.contact-avatar-lg`, `.contact-avatar-large`, `.contact-avatar-sm`, `.contact-avatar-unknown`. Net ~30 source lines removed. `.contact-avatar-large` was 64px; new `.avatar--lg` is 60px (4px visual delta, accepted). | |
| 186 | - | ||
| 187 | - | --- | |
| 188 | - | ||
| 189 | - | ## F. Status dots — REVIEWED, SKIP (2026-05-24) | |
| 190 | - | ||
| 191 | - | Audited 2026-05-24. Three dot patterns exist: `.sync-dot` (8px, connect/sync/warn/error), `.sync-status-dot` (10px, fixed green), `.tab-status-dot` (8px, none/green/yellow/red with pulse animations). Variation in animations and positioning is real; unifying under `.status-dot` would either lose animation timing or require many overrides. Combined surface is ~25 lines; consolidation savings would be <10 lines after adding the primitive. Leave as-is. | |
| 192 | - | ||
| 193 | - | --- | |
| 194 | - | ||
| 195 | - | ## G. Toggles — REVIEWED, CLEAN (2026-05-24) | |
| 196 | - | ||
| 197 | - | `.toggle-switch` is the only on/off switch primitive in the codebase. `.past-events-toggle` and `.form-more-toggle` are `<summary>`-style disclosure controls (different pattern), not duplicates. Nothing to consolidate. | |
| 198 | - | ||
| 199 | - | --- | |
| 200 | - | ||
| 201 | - | ## H. Empty states — REVIEWED, CLEAN (2026-05-24) | |
| 202 | - | ||
| 203 | - | Audited 2026-05-24. No ad-hoc "No X yet" / "Nothing X" markup found in js/ or html. The `.empty-state` primitive + variants (`--compact`, `--dashboard`, `--error`) are the only empty-state surface. Nothing to migrate. | |
| 204 | - | ||
| 205 | - | --- | |
| 206 | - | ||
| 207 | - | ## I. Misplaced / global utilities to relocate — DONE (2026-05-24) | |
| 208 | - | ||
| 209 | - | - ~~`.kbd-hint`~~ relocated from §41 Settings to §12 Tags & Badges (right after the `.badge--filled` color overrides). Comment added explaining the move. | |
| 210 | - | - `.visually-hidden` was already deleted previously. | |
| 211 | - | - Audited `.address-highlight-mirror` and `.addr-*` color classes: tightly coupled to the address-highlighter overlay element (positional, feature-specific). Not generic text-color utilities. Leave page-scoped. | |
| 212 | - | ||
| 213 | - | --- | |
| 214 | - | ||
| 215 | - | ## J. Tier 3 (deferred, regression-prone) | |
| 216 | - | ||
| 217 | - | These were called out earlier as needing the dev server running for | |
| 218 | - | visual diffs. Do AFTER A–F so the consolidated primitives reduce | |
| 219 | - | surface area first. | |
| 220 | - | ||
| 221 | - | - ~~**Consolidate the 3 mobile sections** (§25 / §59 / §60) into one | |
| 222 | - | RESPONSIVE band at end-of-file.~~ Superseded by **K. UI Mode | |
| 223 | - | Separation** (2026-05-22). Mobile rules now live behind | |
| 224 | - | `.ui-mode-mobile` class selectors, not media queries — the original | |
| 225 | - | "one RESPONSIVE band" goal is moot. | |
| 226 | - | - ~~**Resolve V1/V2 Weekly Review.**~~ Done 2026-05-24. Audited every | |
| 227 | - | §49 class against actual JS/HTML usage: 20+ V1 classes had zero | |
| 228 | - | callsites (`.stat-card*`, `.review-section`, `.section-title`, | |
| 229 | - | `.review-details*`, `.review-task-list`, `.review-event-list`, | |
| 230 | - | `.review-task-item*`, `.review-event-item*`, `.project-badge`, | |
| 231 | - | `.due-badge*`, `.focus-task-list*`, `.focus-toggle*`, | |
| 232 | - | `.no-focus-message`, `.focused-projects`, `.project-tag`, | |
| 233 | - | `.notes-section`, `.review-notes-input*`, `.review-actions`, | |
| 234 | - | `.week-info`). Deleted all. Kept the surviving chrome still composed | |
| 235 | - | by `weekly-review.js` (header, status pill, week-dates, event-time, | |
| 236 | - | focus-section gradient) and tab indicators (`.tab-badge`, | |
| 237 | - | `.tab-status-dot`) used by tab nav + events.js. §49 went from 326 | |
| 238 | - | lines to 106. `mobile.js` had no V1 weekly-review classes — only a | |
| 239 | - | `getElementById('weekly-review-content')` lookup, still valid. | |
| 240 | - | Section header renamed to "Weekly Review — chrome around the V2 grid | |
| 241 | - | + tab indicators." | |
| 242 | - | - ~~**Print consolidation** (§48 + §52).~~ Done 2026-05-24. §52 (152 | |
| 243 | - | lines, weekly-review-specific `@media print`) folded into §48 inside | |
| 244 | - | a single consolidated `@media print` block. Organized with three | |
| 245 | - | subsection comments: "Global chrome", "Tables", "Weekly review". | |
| 246 | - | Hidden-selector list deduplicated (e.g. one `display: none` block | |
| 247 | - | now lists global + weekly-review hide targets together). §52 | |
| 248 | - | vacated; only one `@media print` block remains in the file. | |
| 249 | - | ||
| 250 | - | --- | |
| 251 | - | ||
| 252 | - | ## K. UI Mode Separation — DONE (2026-05-22) | |
| 253 | - | ||
| 254 | - | Architectural refactor: mobile vs desktop UI is no longer selected by | |
| 255 | - | viewport width. Set once at boot via `<html class="ui-mode-mobile|desktop">` | |
| 256 | - | from the inline detection script in `index.html`. Desktop binaries stay | |
| 257 | - | desktop even when the window is narrowed. | |
| 258 | - | ||
| 259 | - | Phases 1–5 complete (~3 hours total). Full plan and post-audit live at: | |
| 260 | - | - `ui_mode_separation_plan.md` (the plan) | |
| 261 | - | - `css_state_audit.md` (where things landed) | |
| 262 | - | ||
| 263 | - | ### Key outcomes | |
| 264 | - | - 8 `@media (max-width: 768px)` blocks → 0. 228 selectors prefixed `.ui-mode-mobile`. | |
| 265 | - | - 6 stray non-768 mobile breakpoints (600/640/900/1100) → converted to `.ui-mode-mobile` rules. | |
| 266 | - | - Remaining `@media` queries: 1 `(hover: none)` (hover suppression), | |
| 267 | - | 1 `(max-width: 1024px)` + 1 `(min-width: 1400px)` (both intra-desktop, | |
| 268 | - | selectors `.ui-mode-desktop`-prefixed), 2 `print`. Zero mode-switching queries. | |
| 269 | - | - `[style*="display:none"]` selector hack removed. | |
| 270 | - | - JS layout-mode checks (`innerWidth <= 768`/`<= 600`) → `GoingsOn.viewport.isMobile()`. | |
| 271 | - | - New `js/viewport.js` module; new inline detection script in `index.html` head. | |
| 272 | - | - Section header at `styles.css:159–185` rewritten to document the new model. | |
| 273 | - | - `#task-view-toggle { display: none }` moved out of `@media (hover: none)` | |
| 274 | - | (was wrong axis — input capability instead of UI mode). | |
| 275 | - | - Latent bug fixed: mobile `@keyframes modalSlideIn/Out` were globally | |
| 276 | - | overriding the desktop variants (last-keyframes-wins). Renamed to | |
| 277 | - | `*Mobile` and applied via `animation-name` override. | |
| 278 | - | ||
| 279 | - | ### Phase 6 — remaining (not blocking) | |
| 280 | - | model for new contributors. Done 2026-05-24. Placed after "CSS | |
| 281 | - | Workflow"; covers CSS/JS surfaces, detection precedence, dev preview, | |
| 282 | - | the "mode is a build property, not viewport size" invariant, and the | |
| 283 | - | separate input-capability axis. | |
| 284 | - | detection script in `index.html` to read `window.__TAURI__.platform` | |
| 285 | - | before the UA fallback. Done 2026-05-24. Tauri 2's platform plugin | |
| 286 | - | is async (no sync `window.__TAURI__.platform`), which doesn't fit an | |
| 287 | - | inline-head script that must set the class before the stylesheet | |
| 288 | - | evaluates. Substituted: `navigator.userAgentData.mobile` (UA Client | |
| 289 | - | Hints) as a third tier, plus iPad-as-Mac detection | |
| 290 | - | (`navigator.maxTouchPoints > 1` on a Mac-reporting platform) in the | |
| 291 | - | UA regex tier. Works for WKWebView (iOS), Android WebView, and | |
| 292 | - | catches Safari 13+ iPads that report as Mac. Detail in | |
| 293 | - | `css_state_audit.md` "Detection script — updated 2026-05-24". | |
| 294 | - | - [ ] For production lockdown of the override (so users can't set | |
| 295 | - | `?ui=mobile` on a desktop build and break things): inject | |
| 296 | - | `__GO_BUILD_MODE__` at build time and gate the override branches. | |
| 297 | - | Defer until a production mobile-only desktop-binary distribution | |
| 298 | - | channel exists. (TestFlight iOS is its own binary; no override | |
| 299 | - | risk there.) | |
| 300 | - | ||
| 301 | - | ### Divergences from the plan | |
| 302 | - | - Kept `.mobile-hide` utility class (plan called for removing it). | |
| 303 | - | Rationale: it's one rule, the marker class makes intent visible in | |
| 304 | - | markup, and removing it would shift verbosity from CSS to HTML. | |
| 305 | - | - Phase 4 scope: prefixed only the *layout* rules that mobile UI | |
| 306 | - | hides entirely (header, top tab nav, pills, sidebars). Did not | |
| 307 | - | prefix shared component rules (buttons, forms, modals, cards) — | |
| 308 | - | they correctly stay in the base scope. | |
| 309 | - | ||
| 310 | - | --- | |
| 311 | - | ||
| 312 | - | ## Suggested order | |
| 313 | - | ||
| 314 | - | 1. **A. Buttons** — biggest leverage, sets the design language. | |
| 315 | - | 2. **B. Form inputs** — closely related (form chrome consistency). | |
| 316 | - | 3. **D. Badges** — small surface, quick win once button pattern is set. | |
| 317 | - | 4. **C. Cards** — falls into place once buttons + inputs unified. | |
| 318 | - | 5. **E. Avatars / F. Status dots / G. Toggles / H. Empty states** — cleanup. | |
| 319 | - | 6. **I. Relocate globals** — janitorial, do last. | |
| 320 | - | 7. **J. Tier 3** — only when surface area is reduced. | |
| 321 | - | ||
| 322 | - | --- | |
| 323 | - | ||
| 324 | - | ## Process notes | |
| 325 | - | ||
| 326 | - | - Rebuild `styles.min.css` via `./build-css.sh` after every batch. | |
| 327 | - | - The composition charter at the top of `styles.css` is the source of | |
| 328 | - | truth for what primitives exist. Update the EXISTING VOCABULARY | |
| 329 | - | inventory there whenever you add or rename a primitive/modifier. | |
| 330 | - | - Don't ship two ways to do the same thing during a migration; if A | |
| 331 | - | half-done blocks B, finish A first. | |
| 332 | - | - Spot-check after each surface migration: | |
| 333 | - | - Settings overlay (gear button, back button, nav) | |
| 334 | - | - Email list, email reader, compose modal, compose window | |
| 335 | - | - Project dashboard tiles | |
| 336 | - | - Task table action buttons | |
| 337 | - | - Toast undo | |
| 338 | - | - Bulk-select modal | |
| 339 | - | - Welcome wizard | |
| 29 | + | All consolidation sweeps closed. Outcomes: | |
| 30 | + | ||
| 31 | + | - **A. Buttons** — 14 bespoke `*-btn` classes migrated to `.btn` family (intents/sizes/variants); 2 deleted as dead code. Remaining bespoke (`.view-toggle-btn`, `.kebab-btn`, `.shortcut-hint-btn`, etc.) are slim markers on top of canonical `.btn` and are correct as-is. | |
| 32 | + | - **B. Form inputs** — `.header-input`/`.header-select` migrated to `.form-input--ghost`/`.form-select--ghost`; `.quick-add-input` was dead code, deleted. `.filter-select` kept (distinctive UX cue). | |
| 33 | + | - **C. Cards** — `.email-list`, `.contact-info-section`, `.review-card`, `.kanban-card` migrated to `.card` + variants (`--shell`/`--muted`/`--static`). `.dashboard-column` and `.contact-summary-stat` kept page-scoped. | |
| 34 | + | - **D. Badges** — 9 task-status bespoke badges replaced with composable `chip(color, text)` helper emitting `.badge.badge--xs.badge--filled[data-color="X"]`. New `--xs`/`--sm`/`--filled` modifiers. | |
| 35 | + | - **E. Avatars** — `.avatar` primitive promoted with `--sm`/`--lg`/`--unknown`; all 5 bespoke contact-avatar rules deleted. | |
| 36 | + | - **F. Status dots** — reviewed, skip. Three variants (`.sync-dot`, `.sync-status-dot`, `.tab-status-dot`) have meaningfully different animation timing; unifying would lose nuance for <10 lines saved. | |
| 37 | + | - **G. Toggles** — clean. `.toggle-switch` is the only on/off primitive; `<summary>`-style disclosures are a different pattern. | |
| 38 | + | - **H. Empty states** — clean. `.empty-state` + variants are the only surface. | |
| 39 | + | - **I. Globals relocation** — `.kbd-hint` moved into §12; `.visually-hidden` already removed. | |
| 40 | + | - **J. Tier 3** — mobile section consolidation superseded by §K; V1/V2 weekly review resolved (§49 trimmed 326→106 lines); print consolidation done (§52 folded into §48). | |
| 41 | + | - **K. UI Mode Separation** — set once at boot via `<html class="ui-mode-mobile|desktop">`. 8 viewport media queries → 0. Phases 1–5 complete; full notes in `ui_mode_separation_plan.md` + `css_state_audit.md`. | |
| 42 | + | ||
| 43 | + | ### §K Phase 6 — open, blocked | |
| 44 | + | - [ ] Inject `__GO_BUILD_MODE__` at build time to gate `?ui=mobile` override branches against production tampering. Defer until a production mobile-only desktop-binary distribution channel exists. (TestFlight iOS is its own binary; no override risk there.) |