| 1 |
# GoingsOn TODO |
| 2 |
|
| 3 |
## Launch readiness (Monday 2026-06-01) — IN PROGRESS |
| 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 |
- `src-tauri/src/commands/email.rs:598` — `std::fs::read` for attachments inside async command; wrap in `spawn_blocking` (pattern already at email.rs:422 and email_sync.rs:224). |
| 12 |
- `src-tauri/src/email/smtp_client.rs:291` — `ContentType::parse("application/octet-stream").unwrap()` on a static; replace with infallible mime constant. |
| 13 |
- `src-tauri/src/state.rs:173`, `commands/sync.rs:{75,177,203}`, `commands/oauth.rs:{131,166}`, `commands/email_sync.rs:49` — `.expect("...poisoned")` on `std::sync::Mutex`; switch to `unwrap_or_else(|e| e.into_inner())` since protected data is recoverable. |
| 14 |
- `src-tauri/src/db_watcher.rs:61` — shutdown latency = `MIN_EVENT_INTERVAL_MS`, thread unjoinable. Cosmetic. |
| 15 |
|
| 16 |
**use-fuzz** |
| 17 |
- `src-tauri/frontend/js/seed-data.js:393` — production `console.log` for demo seed instructions; strip from prod bundles or gate on debug flag. |
| 18 |
- `src-tauri/frontend/js/app.js:{12,28,37,...}` — chatty `console.log` on every launch; trim or gate. |
| 19 |
- `src-tauri/frontend/js/{emails,tasks,task-board}.js:*` — bare "Failed to load" without recovery actions; add "Try again" buttons per `ERROR_CODE_HINTS` pattern. |
| 20 |
- `src-tauri/frontend/js/settings.js:196` — empty-plugins hint hardcodes `~/.config/goingson/plugins/` (Linux path); platform-detect or replace with doc link. |
| 21 |
- `src-tauri/frontend/index.html:603` — task drawer close button uses literal `x` not `×`. |
| 22 |
- `src-tauri/frontend/index.html:18-57` — `?ui=mobile` URL param + localStorage override not gated for production per `ui_mode_separation_plan.md` Phase 5; risk of users landing in untested mobile UI on desktop. |
| 23 |
|
| 24 |
**creator-fuzz** |
| 25 |
- `CHANGELOG.md:24-26` — "Fixed: all issues identified in audit runs 1-12" is internal-process language; replace with concrete user-visible fixes. |
| 26 |
- `docs/data-export.md` (missing) — document JSON backup schema so "portable" is verifiable. |
| 27 |
- `tauri.conf.json:48-54` — add Settings toggle "Check for updates on launch" for parity with privacy-policy framing (currently no opt-out, though install is user-initiated). |
| 28 |
- README has no pricing / commercial-license-contact line for PolyForm-NC. |
| 29 |
|
| 30 |
**ux-audit** |
| 31 |
- `styles.css:590-660` — `.btn`/`.btn-primary`/`.btn-danger` lack the offset-shadow brand cue that `.card` and `.bulk-actions-bar` use; controls look flatter than chrome. One-pass fix on interactive primitives also resolves disabled-state contrast and `.pill.active`/`.tab.active` lift issues. |
| 32 |
- `styles.css:615` — disabled-button signal is opacity-only; swap to `transparent bg + muted color/border`. |
| 33 |
- `styles.css:4712` — `.sync-label` hidden in `ui-mode-mobile` leaves dot color as the only state cue; add shape variation or keep label for `error`/`warn`. |
| 34 |
- Single-item destructive actions (`tasks.js:657` etc.) lack `.btn-loading` during round-trip. |
| 35 |
- `index.html:466` straggler `row-flex-2` vs neighbors using `.row-flex row-flex-N` — will be caught by ongoing CSS dedup. |
| 36 |
- Back-arrow buttons inconsistent: `← Back` (index.html:220, 538) vs literal `←` (index.html:270). |
| 37 |
|
| 38 |
### §3.1 — DONE for emoji/About/error-copy. Remaining: |
| 39 |
- Mobile UI mode override hardening (see use-fuzz deferral above). |
| 40 |
|
| 41 |
### §3.2 distribution — NOT STARTED |
| 42 |
- Signed builds + notarization stapled + DMG smoke test on a clean macOS account. |
| 43 |
|
| 44 |
### §3.3 repo hygiene — NOT STARTED |
| 45 |
- Resolve stray root planning files (`css_refactor_plan_2026-05-24.md`, `css_refactor_plan.md`, `css_state_audit.md`, `ui_mode_separation_plan.md`); decide on `generate_pitch_pdf.py` + `GoingsOn-Pitch.pdf`; review `_archive/`. |
| 46 |
|
| 47 |
CSS dedup work below is the active in-progress stream; launch readiness is its own track. |
| 48 |
|
| 49 |
--- |
| 50 |
|
| 51 |
# GoingsOn CSS Dedup TODO |
| 52 |
|
| 53 |
Charter + primitive vocabulary lives at the top of |
| 54 |
`src-tauri/frontend/css/styles.css`. The constraint that "visual output |
| 55 |
must not change" has been relaxed: visual *changes* are OK as long as |
| 56 |
they're not worse. Prefer one consistent visual per element family. |
| 57 |
|
| 58 |
Always rebuild after changes: |
| 59 |
``` |
| 60 |
cd src-tauri/frontend && ./build-css.sh |
| 61 |
``` |
| 62 |
|
| 63 |
--- |
| 64 |
|
| 65 |
## A. Buttons — consolidate to one family |
| 66 |
|
| 67 |
53 button-related selectors live in `styles.css`. They cluster around 4 |
| 68 |
canonical primitives (`.btn`, `.btn-icon`, `.btn-link`, `.btn-loading`) |
| 69 |
plus ~15 bespoke `*-btn` classes that each invented their own padding / |
| 70 |
font / hover. |
| 71 |
|
| 72 |
### Canonical button family (target) |
| 73 |
- `.btn` — base. `inline-flex`, padding `0.625rem 1.25rem`, border, radius-sm, font 0.9rem/600. |
| 74 |
- Intents: `.btn-primary`, `.btn-secondary`, `.btn-danger`. |
| 75 |
- Sizes: `.btn-sm` (+ new `.btn-lg` if any of the bespoke ones genuinely need it). |
| 76 |
- Variants: `.btn-icon` (chrome icon button, no border), `.btn-link` (text-link button). |
| 77 |
- States: `:hover`, `:active`, `:disabled`, `.btn-loading`. |
| 78 |
|
| 79 |
### Bespoke buttons to migrate |
| 80 |
For each, find the closest canonical and migrate. Visual deltas are |
| 81 |
acceptable when they bring the button into the system. |
| 82 |
|
| 83 |
|
| 84 |
|
| 85 |
| ~~`.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`). | |
| 86 |
| ~~`.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`. | |
| 87 |
| ~~`.settings-back-btn`~~ | `.btn-link.mb-1.settings-back` | Done 2026-05-24. Marker class kept for mobile-pass override. | |
| 88 |
| `.settings-nav-item` | New `.btn-nav` *or* not-a-button | It's a nav item, not really a button. Keep as is. | |
| 89 |
| ~~`.undo-btn`~~ | `.btn.btn-sm.btn-primary` | Done 2026-05-24. Bespoke was custom accent-blue; .btn-primary matches. | |
| 90 |
| ~~`.account-delete-btn`~~ | `.btn.btn-sm.btn-danger` | Done 2026-05-24. | |
| 91 |
| ~~`.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. | |
| 92 |
| ~~`.email-attachment-remove-btn`~~ | (dead code) | Done 2026-05-24: rule deleted, no callsites. | |
| 93 |
| ~~`.toggle-cc-btn`~~ | `.btn-link` | Done 2026-05-24. Accepts underline visual delta. | |
| 94 |
| ~~`.attachment-delete-btn`~~ | `.text-accent-red` | Done 2026-05-24: already had `.btn.btn-sm.btn-secondary`; bespoke was only the red color. | |
| 95 |
| ~~`.welcome-step-btn`~~ | `.text-left` | Done 2026-05-24: already had `.btn.btn-secondary`; new `.text-left` utility added next to `.text-center`. | |
| 96 |
| ~~`.kebab-btn`~~ | `.btn-icon` + slim bespoke for hover-reveal/font-override | Done 2026-05-24. 5 callsites now `btn-icon kebab-btn`. | |
| 97 |
| ~~`.schedule-task-btn`~~ | (dead code) | Done 2026-05-24: rule deleted, no callsites. | |
| 98 |
| ~~`.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). | |
| 99 |
| ~~`.month-goal-status-btn`~~ | `.btn-icon` + slim bespoke for color/sizing | Done 2026-05-24. | |
| 100 |
| ~~`.month-goal-delete-btn`~~ | `.btn-icon` + slim bespoke for hover-reveal/color | Done 2026-05-24. | |
| 101 |
| `.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. | |
| 102 |
| ~~`.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. | |
| 103 |
|
| 104 |
Expected savings: ~80-120 source lines, ~2-3 KB min.css. |
| 105 |
|
| 106 |
### Migration approach |
| 107 |
1. Audit each bespoke class's callsites: `grep -rn "<class>" js/ *.html`. |
| 108 |
2. Edit one bespoke class at a time: |
| 109 |
a. Decide the canonical mapping. |
| 110 |
b. Update callsites to use canonical class(es). |
| 111 |
c. Delete bespoke rule from styles.css. |
| 112 |
3. After each migration, rebuild + eyeball the affected surface. |
| 113 |
4. If migration reveals a missing modifier (e.g. `.btn-icon--lg`), add |
| 114 |
it next to `.btn-icon` and document in the charter inventory. |
| 115 |
|
| 116 |
--- |
| 117 |
|
| 118 |
## B. Form inputs & selects — one input family |
| 119 |
|
| 120 |
### Canonical (target) |
| 121 |
- `.form-input` — base text input. |
| 122 |
- `.form-select` — base select. |
| 123 |
- Sizes: `.form-input--w-200`, `.form-select--compact` (already in place). |
| 124 |
- Variants: new `.form-input--ghost` (borderless, used by compose |
| 125 |
header rows), new `.form-input--search` (search affordance). |
| 126 |
|
| 127 |
### Migrate |
| 128 |
- ~~`.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. |
| 129 |
- `.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. |
| 130 |
- ~~`.header-input`~~ → `.form-input.form-input--ghost.flex-1`. Done 2026-05-24. New `.form-input--ghost` modifier added next to base in §20. |
| 131 |
- ~~`.header-select`~~ → `.form-select.form-select--ghost.flex-1`. Done 2026-05-24. New `.form-select--ghost` modifier added. |
| 132 |
|
| 133 |
Savings achieved: ~29 lines (29/(40-60) of estimate). |
| 134 |
|
| 135 |
--- |
| 136 |
|
| 137 |
## C. Cards — one card family with shell + muted variants |
| 138 |
|
| 139 |
### Canonical |
| 140 |
- `.card` — interactive tile (current). |
| 141 |
- `.card--list-item` — compact list row (already added). |
| 142 |
- New `.card--muted` — bg-secondary, no shadow/hover, no cursor (mini |
| 143 |
info card). |
| 144 |
- New `.card--shell` — container shell: no padding, no cursor, no |
| 145 |
hover, flex column, overflow handling. For list shells like |
| 146 |
`.email-list` and `.dashboard-column`. |
| 147 |
|
| 148 |
### Migrate |
| 149 |
- ~~`.email-list`~~ → `.card.card--shell.email-list`. Done 2026-05-24. Slim feature rule keeps only `flex: 1; min-height: 0;`. |
| 150 |
- `.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. |
| 151 |
- ~~`.contact-info-section`~~ → `.card.card--muted.contact-info-section`. Done 2026-05-24. Slim feature rule keeps gap + margin + tighter padding. |
| 152 |
- `.contact-summary-stat` → **Skip.** Page-scoped is appropriate (feature-specific stat tile with min-width 80px); not duplication of `.card`. |
| 153 |
- ~~`.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. |
| 154 |
- ~~`.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. |
| 155 |
|
| 156 |
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). |
| 157 |
|
| 158 |
--- |
| 159 |
|
| 160 |
## D. Badges & tags — unify the chip family |
| 161 |
|
| 162 |
### Canonical |
| 163 |
- `.tag, .badge` — bordered chip primitive (current). |
| 164 |
- Color variants via `[data-color="green|yellow|red|cyan|purple|muted"]` |
| 165 |
(already exists). |
| 166 |
- New size modifiers: `.badge--sm`, `.badge--xs`. |
| 167 |
- New intent modifier: `.badge--filled` (solid accent fill, no border). |
| 168 |
|
| 169 |
### Migrate |
| 170 |
- `.thread-badge` → **Skip.** Already audited 2026-05-21 as net-zero dedup; composing `.badge` would require overriding every declaration. Leave standalone. |
| 171 |
- ~~`.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). |
| 172 |
- `.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. |
| 173 |
- `.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`. |
| 174 |
- ~~`.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. |
| 175 |
|
| 176 |
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. |
| 177 |
|
| 178 |
--- |
| 179 |
|
| 180 |
## E. Avatars — DONE (2026-05-24) |
| 181 |
|
| 182 |
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). |
| 183 |
|
| 184 |
--- |
| 185 |
|
| 186 |
## F. Status dots — REVIEWED, SKIP (2026-05-24) |
| 187 |
|
| 188 |
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. |
| 189 |
|
| 190 |
--- |
| 191 |
|
| 192 |
## G. Toggles — REVIEWED, CLEAN (2026-05-24) |
| 193 |
|
| 194 |
`.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. |
| 195 |
|
| 196 |
--- |
| 197 |
|
| 198 |
## H. Empty states — REVIEWED, CLEAN (2026-05-24) |
| 199 |
|
| 200 |
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. |
| 201 |
|
| 202 |
--- |
| 203 |
|
| 204 |
## I. Misplaced / global utilities to relocate — DONE (2026-05-24) |
| 205 |
|
| 206 |
- ~~`.kbd-hint`~~ relocated from §41 Settings to §12 Tags & Badges (right after the `.badge--filled` color overrides). Comment added explaining the move. |
| 207 |
- `.visually-hidden` was already deleted previously. |
| 208 |
- 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. |
| 209 |
|
| 210 |
--- |
| 211 |
|
| 212 |
## J. Tier 3 (deferred, regression-prone) |
| 213 |
|
| 214 |
These were called out earlier as needing the dev server running for |
| 215 |
visual diffs. Do AFTER A–F so the consolidated primitives reduce |
| 216 |
surface area first. |
| 217 |
|
| 218 |
- ~~**Consolidate the 3 mobile sections** (§25 / §59 / §60) into one |
| 219 |
RESPONSIVE band at end-of-file.~~ Superseded by **K. UI Mode |
| 220 |
Separation** (2026-05-22). Mobile rules now live behind |
| 221 |
`.ui-mode-mobile` class selectors, not media queries — the original |
| 222 |
"one RESPONSIVE band" goal is moot. |
| 223 |
- ~~**Resolve V1/V2 Weekly Review.**~~ Done 2026-05-24. Audited every |
| 224 |
§49 class against actual JS/HTML usage: 20+ V1 classes had zero |
| 225 |
callsites (`.stat-card*`, `.review-section`, `.section-title`, |
| 226 |
`.review-details*`, `.review-task-list`, `.review-event-list`, |
| 227 |
`.review-task-item*`, `.review-event-item*`, `.project-badge`, |
| 228 |
`.due-badge*`, `.focus-task-list*`, `.focus-toggle*`, |
| 229 |
`.no-focus-message`, `.focused-projects`, `.project-tag`, |
| 230 |
`.notes-section`, `.review-notes-input*`, `.review-actions`, |
| 231 |
`.week-info`). Deleted all. Kept the surviving chrome still composed |
| 232 |
by `weekly-review.js` (header, status pill, week-dates, event-time, |
| 233 |
focus-section gradient) and tab indicators (`.tab-badge`, |
| 234 |
`.tab-status-dot`) used by tab nav + events.js. §49 went from 326 |
| 235 |
lines to 106. `mobile.js` had no V1 weekly-review classes — only a |
| 236 |
`getElementById('weekly-review-content')` lookup, still valid. |
| 237 |
Section header renamed to "Weekly Review — chrome around the V2 grid |
| 238 |
+ tab indicators." |
| 239 |
- ~~**Print consolidation** (§48 + §52).~~ Done 2026-05-24. §52 (152 |
| 240 |
lines, weekly-review-specific `@media print`) folded into §48 inside |
| 241 |
a single consolidated `@media print` block. Organized with three |
| 242 |
subsection comments: "Global chrome", "Tables", "Weekly review". |
| 243 |
Hidden-selector list deduplicated (e.g. one `display: none` block |
| 244 |
now lists global + weekly-review hide targets together). §52 |
| 245 |
vacated; only one `@media print` block remains in the file. |
| 246 |
|
| 247 |
--- |
| 248 |
|
| 249 |
## K. UI Mode Separation — DONE (2026-05-22) |
| 250 |
|
| 251 |
Architectural refactor: mobile vs desktop UI is no longer selected by |
| 252 |
viewport width. Set once at boot via `<html class="ui-mode-mobile|desktop">` |
| 253 |
from the inline detection script in `index.html`. Desktop binaries stay |
| 254 |
desktop even when the window is narrowed. |
| 255 |
|
| 256 |
Phases 1–5 complete (~3 hours total). Full plan and post-audit live at: |
| 257 |
- `ui_mode_separation_plan.md` (the plan) |
| 258 |
- `css_state_audit.md` (where things landed) |
| 259 |
|
| 260 |
### Key outcomes |
| 261 |
- 8 `@media (max-width: 768px)` blocks → 0. 228 selectors prefixed `.ui-mode-mobile`. |
| 262 |
- 6 stray non-768 mobile breakpoints (600/640/900/1100) → converted to `.ui-mode-mobile` rules. |
| 263 |
- Remaining `@media` queries: 1 `(hover: none)` (hover suppression), |
| 264 |
1 `(max-width: 1024px)` + 1 `(min-width: 1400px)` (both intra-desktop, |
| 265 |
selectors `.ui-mode-desktop`-prefixed), 2 `print`. Zero mode-switching queries. |
| 266 |
- `[style*="display:none"]` selector hack removed. |
| 267 |
- JS layout-mode checks (`innerWidth <= 768`/`<= 600`) → `GoingsOn.viewport.isMobile()`. |
| 268 |
- New `js/viewport.js` module; new inline detection script in `index.html` head. |
| 269 |
- Section header at `styles.css:159–185` rewritten to document the new model. |
| 270 |
- `#task-view-toggle { display: none }` moved out of `@media (hover: none)` |
| 271 |
(was wrong axis — input capability instead of UI mode). |
| 272 |
- Latent bug fixed: mobile `@keyframes modalSlideIn/Out` were globally |
| 273 |
overriding the desktop variants (last-keyframes-wins). Renamed to |
| 274 |
`*Mobile` and applied via `animation-name` override. |
| 275 |
|
| 276 |
### Phase 6 — remaining (not blocking) |
| 277 |
model for new contributors. Done 2026-05-24. Placed after "CSS |
| 278 |
Workflow"; covers CSS/JS surfaces, detection precedence, dev preview, |
| 279 |
the "mode is a build property, not viewport size" invariant, and the |
| 280 |
separate input-capability axis. |
| 281 |
detection script in `index.html` to read `window.__TAURI__.platform` |
| 282 |
before the UA fallback. Done 2026-05-24. Tauri 2's platform plugin |
| 283 |
is async (no sync `window.__TAURI__.platform`), which doesn't fit an |
| 284 |
inline-head script that must set the class before the stylesheet |
| 285 |
evaluates. Substituted: `navigator.userAgentData.mobile` (UA Client |
| 286 |
Hints) as a third tier, plus iPad-as-Mac detection |
| 287 |
(`navigator.maxTouchPoints > 1` on a Mac-reporting platform) in the |
| 288 |
UA regex tier. Works for WKWebView (iOS), Android WebView, and |
| 289 |
catches Safari 13+ iPads that report as Mac. Detail in |
| 290 |
`css_state_audit.md` "Detection script — updated 2026-05-24". |
| 291 |
- [ ] For production lockdown of the override (so users can't set |
| 292 |
`?ui=mobile` on a desktop build and break things): inject |
| 293 |
`__GO_BUILD_MODE__` at build time and gate the override branches. |
| 294 |
Defer until a production mobile-only desktop-binary distribution |
| 295 |
channel exists. (TestFlight iOS is its own binary; no override |
| 296 |
risk there.) |
| 297 |
|
| 298 |
### Divergences from the plan |
| 299 |
- Kept `.mobile-hide` utility class (plan called for removing it). |
| 300 |
Rationale: it's one rule, the marker class makes intent visible in |
| 301 |
markup, and removing it would shift verbosity from CSS to HTML. |
| 302 |
- Phase 4 scope: prefixed only the *layout* rules that mobile UI |
| 303 |
hides entirely (header, top tab nav, pills, sidebars). Did not |
| 304 |
prefix shared component rules (buttons, forms, modals, cards) — |
| 305 |
they correctly stay in the base scope. |
| 306 |
|
| 307 |
--- |
| 308 |
|
| 309 |
## Suggested order |
| 310 |
|
| 311 |
1. **A. Buttons** — biggest leverage, sets the design language. |
| 312 |
2. **B. Form inputs** — closely related (form chrome consistency). |
| 313 |
3. **D. Badges** — small surface, quick win once button pattern is set. |
| 314 |
4. **C. Cards** — falls into place once buttons + inputs unified. |
| 315 |
5. **E. Avatars / F. Status dots / G. Toggles / H. Empty states** — cleanup. |
| 316 |
6. **I. Relocate globals** — janitorial, do last. |
| 317 |
7. **J. Tier 3** — only when surface area is reduced. |
| 318 |
|
| 319 |
--- |
| 320 |
|
| 321 |
## Process notes |
| 322 |
|
| 323 |
- Rebuild `styles.min.css` via `./build-css.sh` after every batch. |
| 324 |
- The composition charter at the top of `styles.css` is the source of |
| 325 |
truth for what primitives exist. Update the EXISTING VOCABULARY |
| 326 |
inventory there whenever you add or rename a primitive/modifier. |
| 327 |
- Don't ship two ways to do the same thing during a migration; if A |
| 328 |
half-done blocks B, finish A first. |
| 329 |
- Spot-check after each surface migration: |
| 330 |
- Settings overlay (gear button, back button, nav) |
| 331 |
- Email list, email reader, compose modal, compose window |
| 332 |
- Project dashboard tiles |
| 333 |
- Task table action buttons |
| 334 |
- Toast undo |
| 335 |
- Bulk-select modal |
| 336 |
- Welcome wizard |
| 337 |
|