* feat(mobile): add SureFontWeights design tokens
Introduce named font-weight tokens so widgets reference a DS tier instead
of a raw FontWeight, mirroring the web design system's Tailwind weight
utilities (font-medium / font-semibold).
- design/tokens/sure.tokens.json: add font.weight.medium (500) and
.semibold (600) as the canonical source.
- generate_sure_tokens.mjs: emit SureTokens.weightMedium / weightSemibold
(with a font-weight resolver + validation), regenerate sure_tokens.dart.
- sure_tokens_test.dart: assert the generated weights match canonical.
- Migrate the dashboard-area money/hierarchy sites onto the tokens
(net_worth_card, account_card, dashboard, recent_transactions,
transactions_list): FontWeight.w500 -> SureTokens.weightMedium,
FontWeight.w600 -> SureTokens.weightSemibold.
Weight-only; other screens adopt the tokens in their own polish PRs.
166 tests pass; flutter analyze: no new issues; token generator --check
is clean.
* build(tokens): regenerate web _generated.css for new font weights
Adding font.weight.medium/semibold to sure.tokens.json also flows through
the web token generator (bin/tokens.mjs), which emits --font-weight-medium
and --font-weight-semibold. Commit the regenerated _generated.css so the
tokens:check gate stays green (node bin/tokens.mjs + git diff --quiet).
* test(system): de-flake account edit via account-menu
AccountsTest#assert_account_created opened the account menu and clicked
Edit immediately after visiting the account page. That page issues a
Turbo morph refresh shortly after load (turbo_refreshes_with :morph
reacting to a family-stream broadcast), which can detach the menu node
mid-click — "Selenium::WebDriver::Error: Node with given id does not
belong to the document" — or wipe the just-opened edit form. Capybara
does not auto-retry that inspector error, so the test flaked
intermittently in CI.
Extract open_account_edit_dialog, which retries the menu interaction
until the edit form is present, rescuing the transient detach/stale
errors. Mirrors the existing PropertyTest#open_account_edit_dialog
precedent for the same morph race, but also tolerates the click itself
raising while the refresh is in flight.
Extend mobile/tool/generate_sure_tokens.mjs to emit, from the canonical design/tokens/sure.tokens.json: a mode-aware box-shadow scale (shadowXs..shadowXl, parsed from shadow.xs..xl into List<BoxShadow>), plus the focus-ring (color.focus-ring) and bg-inverse (utility.bg-inverse) colors on SureTokenPalette. Regenerates mobile/lib/theme/sure_tokens.dart (import dart:ui -> package:flutter/painting.dart for BoxShadow/Offset); keeps the --check parity gate; adds token tests for the new values incl. the negative xl spread.
Radii are already complete (the source only defines md/lg); a type-scale is not in the token source, so both are intentionally untouched. The shadow-border composites are deferred (derivable in-widget as a shadow + a 1px border from existing border tokens). This unblocks SureCard/elevated surfaces.
Part of #2235.
On screens not yet redesigned with SureColors (the Chats list, etc.), Material's
primary/secondary *container* roles were unset, so they fell back to defaults
that read as blue on the FAB, unread-badge, and avatar surfaces.
- Pin `primaryContainer`/`secondaryContainer` to a neutral Sure surface
(`surfaceInset` + `textPrimary`), and add a `FloatingActionButtonThemeData` so
FABs use Sure's neutral primary action color (`buttonPrimary`). `primary` /
`secondary` stay `link` / `info`, so existing link/accent callers are unchanged.
- Add a `SureLogo` widget that renders `logomark.svg` with the wordmark's
`currentColor` strokes tinted to the theme's secondary text color, and route
every logomark consumer (nav bar, login) through it — so the mark stays legible
in dark mode (the hardcoded grey was too dim) and no caller renders the strokes
as the flutter_svg default (black). The green brand mark keeps its fill.
Refs #2235.
* feat(mobile): standardize money typography and semantic amount color
Add a brightness-aware SureColors theme extension and a MoneyText/SureMoney
primitive (semantic success/destructive/subdued tokens + tabular figures for
column-aligned digits), then migrate the transaction lists and balance cards
off raw Colors.green/red/grey.
Step 2 of the mobile design-system sequence (#2235), after #2237's theme
foundation. Primitive-first: screens consume shared tokens/typography.
* fix: review feedback — brightness-aware token fallback, de-flake Setting tests, Pipelock localhost FP
- SureColors.of falls back to the palette matching the active brightness (not
always light) when the extension is missing, so dark surfaces stay correct.
- Clear the rails-settings-cached cache before each test; its in-memory cache
survives the per-test transaction rollback, leaking Setting.* across tests and
flaking Settings::HostingsControllerTest (stale empty string vs nil).
Full unit suite: 4952 runs, 0 failures.
- Suppress the localhost test-DB DATABASE_URL false positive with line-level
`# pipelock:ignore` in ci.yml + llm-evals.yml instead of excluding whole files,
so those workflows stay scanned for real secrets.
* feat(mobile): align theme foundation with Sure tokens
Generate typed Flutter token constants from the canonical Sure token JSON and route the app through shared light/dark ThemeData construction. This keeps the first mobile design-system step scoped to foundation wiring and regression tests without restyling screens directly.
* fix(mobile): define Sure error container colors
Populate the manual Flutter ColorScheme error container pair from Sure tokens so validation and connection banners keep visible icon/text contrast. Add theme assertions for both light and dark modes.
* fix(mobile): preserve full-width action buttons