UI Professionalization Audit β Aldilaijan & Khobara App β
Date: 2026-07-18 Scope: Full Flutter frontend β lib/ (~900 Dart files, ~272 screens, 48 feature modules), theme layer, shared primitives, all feature clusters, plus an external benchmark review (premium SaaS + Arabic/RTL enterprise standards). Method: 9 parallel specialist audits (theme system, core widgets, shell/nav, properties, public web, CRM/comms, valuations/finance/admin, quantitative hardcode sweep, design-benchmark research).
1. Executive Summary β
The foundation is not generic β the adoption is. The app already owns the assets of a professional product: a generated design-token pipeline (lib/core/theme/tokens.dart), a hand-built 30-slot Material 3 ColorScheme (not ColorScheme.fromSeed), a distinctive 5-font type system (Readex Pro / Plus Jakarta Sans / Cairo Arabic fallback / Noto Naskh / IBM Plex Mono with tabular figures), a bespoke SVG icon family (Daleel), a real illustration system, and flagship surfaces (PropertyCard, WhatsApp inbox, deals kanban, auth backdrop) that are genuinely well designed.
What makes it read as generic in practice is a consistent set of leaks and contradictions:
- Stock Material leaks through the seams β unthemed tooltips/menus/date-pickers, 2,237 default
Icons.*usages vs only 27 bespokeDaleelIconsuses, default spinners next to bespoke skeletons. - Tokens are bypassed at scale β ~4,500 raw spacing call sites (only ~16% adoption of
AkSpace), 500 rawBorderRadius.circular, 807 inlineTextStyle, and ~230 off-grid values that silently break the 4px rhythm. - Sibling screens improvise their own idioms β three different metric tiles, two chip dialects, three divider rules, rogue private palettes.
- Dev-build artifacts are visible to users β untranslated
intake/qualify/executewire strings on chips, hardcoded'en_GB'dates in 19 files, a π emoji in a list tile, raw'$e'error text. - Arabic/RTL polish gaps β 14 synthesized (fake-slanted) italic sites,
toUpperCase()+ letter-spacing applied to Arabic,Icons.chevron_rightnever mirroring (14+ sites). - The brand system contradicts itself β dead amber/navy dual-brand tokens still generated while the app is unified navy/cyan; amber map pins leak; the "cyan points, navy fills" rule is violated by a full-width cyan selection bar.
Bottom line: this is not a redesign problem β it is a convergence problem. The fastest path to a professional look is (a) closing the unthemed-component gaps, (b) enforcing token discipline with codemods + lints, (c) unifying the 3β4 competing idioms per pattern into the kit that already exists, and (d) eliminating the dev-look artifacts. A phased roadmap with effort estimates is in Β§5.
2. What's Already Professional (keep and extend) β
| Asset | Evidence | Why it matters |
|---|---|---|
| Canonical token file | lib/core/theme/tokens.dart (hand-authored; no generator, no upstream), re-exported via ak_scheme.dart | Single source of truth for this repo; values can't drift between the Ak layer and the palette |
| Hand-built ColorScheme | color_scheme.dart:1-32, all surfaceContainer* tiers filled | Deliberate anti-generic choice; dark mode is a real designed scheme |
| 5-font type system | text_theme.dart:22-115, fonts bundled in pubspec.yaml:356-400 | Signature typography; Arabic fallback wired into every style; tabular figures for data |
| TokenCard hairline aesthetic | token_card.dart:51-98; elevation-0 + hairline border + ink-tinted shadow | The "one product" surface language β exactly the Stripe/Vercel pattern |
| Daleel bespoke icons | daleel_icons.g.dart, RTL auto-mirroring, line/solid weights | A custom icon family exists β it is purely an adoption problem |
| Illustration system | illustrations.dart:97-288 (14 slots, currentColor SVG + painters) | Empty states can look bespoke everywhere |
| Flagship surfaces | property_card.dart, whatsapp_inbox_screen.dart:631-786, deals_kanban_screen.dart:204-455, auth_backdrop.dart:55-115 | Proof the team can hit professional bar; these are the reference standard |
3. The Generic-Look Drivers (ranked by visual impact) β
3.1 Stock Material leaking through the seams β
- 13+ component themes missing β no
tooltipTheme,popupMenuTheme,menuTheme,checkboxTheme,radioTheme,datePickerTheme,timePickerTheme,drawerTheme,dataTableTheme,expansionTileTheme,searchBarTheme,textSelectionThemeincomponent_themes.dart. Every tooltip, overflow menu, and date picker renders stock M3 gray-blue. - Default icon domination β 2,237
Icons.*hits across 386 files vs 27DaleelIconsuses in 7 files (mostly bottom nav). Quick actions mixshopping_cart_outlined,beach_access_outlined,construction_outlined(dashboard_quick_actions.dart:104-200). The single biggest generic-look driver. - Default spinners next to bespoke skeletons β
ceo_dashboard_screen.dart:64,agent_dashboard_screen.dart:42,engagements_list_screen.dart:99,smart_alerts_screen.dart:35use bareCircularProgressIndicatorwhile siblings useCardSkeletonList. - 56% of empty states use stock icons β 139
EmptyState(calls but only 61 pass a bespokeillustration:; default isIcons.inbox_outlinedat 56px (empty_state.dart:24,80-82). - Two parallel toast systems β stock
SnackBarfor errors (error_snackbar.dart:27-33) while the styledAkToastexists (ak_feedback.dart:101-139).
3.2 Token adoption gap (the "almost aligned" amateur feel) β
- Spacing: ~1,874
EdgeInsets+ ~2,639 numericSizedBoxsites;AkSpaceused in only 143/900 files. Off-grid values (14 Γ73, 10 Γ69, 6 Γ54, 3, 5, 7, 9, 13β¦) silently break the 4px grid. Worst files:valuation_workflow_screen.dart(56),hermes_dashboard_screen.dart(50),properties_filters_sheet.dart(37). - Radius: 500 raw
BorderRadius.circular(N)in 199 files (worst:add_property_screen.dart15,site_inspection_screen.dart13). - Type: 807 inline
TextStyle(across 226 files re-specifying size/weight (worst:comparables_screen.dart25,site_inspection_screen.dart24), incl. fractional sizes 13.5/12.5/10.5/9.5 in comms screens. - Color: 182 stock
Colors.*hits in 90 files (data_completeness_screen.dartΓ11 green/orange), 45 hardcodedColor(0xβ¦)outside the theme, and a rogue 17β20-color private theme inlaunch_checklist_screen.dart:29-49. - Buttons:
AkButtonused in only 10 files; 47 per-screenstyleFromoverrides in 29 files.
3.3 Competing idioms for the same pattern β
- Metric tiles Γ3:
AkMetricTilevs_MiniMetrictonal box (dashboard_welcome_panel.dart:204-211) vs rawCard(margin:4)(ceo_dashboard_screen.dart:269-275). - Chips Γ2: tokenized
BrandChipvs rawChoiceChip/FilterChipone nav level apart (engagements_list_screen.dart:160,filter_primitives.dart:75-87). - Dividers Γ3 rules: indent 16 / indent 76 / full-bleed across deals, WhatsApp, reminders.
- Sheets Γ2 chrome: quick-add sheet bare (
shell_quick_add_sheet.dart:12-15) vs tools sheet with drag handle + radius 20 (bottom_nav_tools_sheet.dart:83-90). - Cards: raw
Card()beside hairlineTokenCardon the same screens (property_detail_tabs.dart:842,1008,showcases_list_screen.dart:104, contact/services/about public pages).
3.4 Dev-build artifacts visible to users β
- Untranslated wire strings as labels:
Text(p.wire)/row.phase.wirerender rawintake/qualify/executein the Arabic UI (engagements_list_screen.dart:212,288). - Broken i18n keys: reports hub tiles render English-only in Arabic (
reports_hub_screen.dart:220passes human strings tol.t('reports.$titleKey')). - Hardcoded
'en_GB'dates: 25 sites in 19 files (English "MAR" in Arabic UI) despite a locale-aware helper existing atcore/formatting/app_dates.dart:27-30. - Emoji in UI: raw π in
showcases_list_screen.dart:104-123; raw'$e'error text ininvoice_revenue_chart.dart:67-70. - Dead code telling on itself:
color: featured ? scheme.primary : scheme.primary(public_tool_tile.dart:41).
3.5 Arabic / RTL polish gaps β
- Synthesized italics: 14
FontStyle.italicsites but only upright fonts registered β Flutter fake-slants Arabic glyphs (individuals_list_screen.dart:917,tiptap_parser.dart:187). - Latin-only idioms applied to Arabic:
toUpperCase()+ 0.8 letter-spacing insection_divider.dart:42-46(Arabic has no case; spacing breaks cursive joining); same innotifications_screen.dart:404-416. - Non-mirroring chevrons:
Icons.chevron_right(never auto-mirrors) at 14+ drill-in sites incl.smart_alerts_screen.dart:121,deal_detail_screen.dart:301,public_landing_screen.dart:386,514. - LTR/RTL inconsistency:
EdgeInsets.fromLTRB(brokerage_drawer.dart:65) vsEdgeInsetsDirectional(khobara_drawer.dart:46); internal chat bubble tail uses non-directional corners β tail on the wrong side in RTL (internal_chat_thread_screen.dart:221-226). - Numeral-locale strategy undefined: Kuwaiti/Saudi enterprise convention is Eastern Arabic numerals (Ω Ω‘Ω’Ω£); dates currently hardcode
en_GB. Numbers/phones must stay LTR inside RTL.
3.6 Brand-system contradictions β
- Dead dual-brand ramps:
AldilaijanTokens(amber) /KhobaraTokensstill generated whilecolor_scheme.dart:15-18declares one unified navy/cyan palette; amber leaks onto map pins (daleel_pin.dart:176,350); stale comment promises gold accents (app.dart:30-32). - Brand-blind accent rail: the 2px rail on every app bar (
app_bar.dart:103) is hardwired to unified cyan β the most visible brand signal ignores brand mode. MultiSelectBarviolates the documented "navy fills, cyan points" rule with a full-width cyan slab (multi_select_bar.dart:41-74).- Hardcoded
AkColors.cyanon shared widgets (deal_detail_stepper.dart:70,mailbox_screen.dart:132,463) instead ofscheme.primary.
3.7 Missing professional patterns β
- No real data tables β invoices, AR aging, audit log, admin users all use
ListTilelists (35+ sites); ledgers read as chat lists. Onlybulk_valuation_screen.dartusesDataTable. - Flat settings/admin IA β settings is one 543-line flat
ListViewwith 12 identical chevron tiles (settings_screen.dart:190-319); admin hub is a raw 24-row list (admin_config_hub_screen.dart:153-164). - Drawers are stock
NavigationDrawerβ no brand block, no grouping, no user footer (brokerage_drawer.dart:28,khobara_drawer.dart:25); nav rail carries no brand mark. - Public landing is a stretched mobile screen β 640px-capped text column, no property imagery, icon-in-circle
ListTiles for featured listings (public_landing_screen.dart:69,111-173,public_property_tile.dart:36-44). - Timeline with no timeline β interactions are divider-separated rows, no rail/nodes/date grouping (
interaction_timeline.dart:108-277). - One listing density β the compact
PropertyListTileexists but is never instantiated; no grid/compact toggle. - Wizard progress is stock M3 β bare
LinearProgressIndicator+ "N of M" (property_form_screen.dart:3030-3059).
4. Benchmark Scorecard (2025β26 premium SaaS + Arabic enterprise standards) β
| # | Quality (benchmark) | Verdict | Notes |
|---|---|---|---|
| 1 | Signature custom font identity | β PASS | Readex Pro / Jakarta / Cairo stack, bundled |
| 2 | Arabic-first font stack (no system fallback) | β PASS | Cairo fallback on every style |
| 3 | Per-script type tuning (Arabic line-height 1.6β1.8) | β PASS | text_theme.dart:16-17,83-85 |
| 4 | No positive letter-spacing on Arabic | β FAIL | section_divider.dart:42-46, notifications_screen.dart:404 |
| 5 | Weights β€3, hierarchy via size/tracking | β οΈ PARTIAL | 807 inline TextStyles improvise weights |
| 6 | Tabular numerals on all data | β οΈ PARTIAL | Strong on KPIs; fractional raw sizes elsewhere |
| 7 | Deliberate numeral-locale strategy (Ω Ω‘Ω’Ω£ for KW/SA) | β FAIL | en_GB hardcoded Γ25; no Eastern-Arabic policy |
| 8 | Single accent discipline | β οΈ PARTIAL | Amber leak, cyan slab violations, raw greens |
| 9 | Neutral-first palette, no stock Material hues | β οΈ PARTIAL | 182 Colors.* leaks in 90 files |
| 10 | 4/8pt grid, token-only spacing | β FAIL | ~4,500 raw sites, ~230 off-grid values |
| 11 | Consistent density rhythm | β FAIL | 3 metric-tile densities; per-screen improvisation |
| 12 | β€3 elevation levels, hairline borders over shadows | β PASS | TokenCard idiom + shadow discipline (9 literals) |
| 13 | Conservative radius scale, token-only | β οΈ PARTIAL | 500 raw radii incl. off-scale 10px |
| 14 | One icon family, RTL-mirroring policy | β FAIL | 2,237 stock icons vs 27 bespoke; chevrons don't mirror |
| 15 | Logical-property RTL correctness | β οΈ PARTIAL | Mostly good; drawers/chat tail/LTRB leaks |
| 16 | Motion spec (150β250ms), hover/focus states | β FAIL | Motion tokens adopted in 5 files; 62 hardcoded durations |
| 17 | Status via tinted chips, not saturated fills | β οΈ PARTIAL | StatusBadge does this; raw Colors.green/orange bypass |
| 18 | Bilingual parity (real Arabic content everywhere) | β FAIL | Wire strings, English dates, broken report keys |
Score: 4 pass / 7 partial / 7 fail. Every FAIL is an adoption/enforcement fix, not a redesign.
5. Roadmap: Generic β Professional β
Phase 0 β Kill the dev-look artifacts (1β3 days, pure polish-per-effort) β
Status 2026-07-18: shipped. All 10 items landed (full
flutter analyzeclean, 3410/3410 tests). Notes: items 7, 8 and 10 were already conformant in-tree and were verified rather than re-done; item 2's numeral policy was already decided inapp_dates.dart(Western digits in both locales) β 71 hardcoded-locale date sites across 57 files were routed through it, while 33NumberFormat('en_GB')sites were deliberately kept (the pinned locale is what forces Western digits); item 9's 4 named sites were already skeleton-based, so the next 4 worst full-page spinners (reports dashboards) were converted instead.
- Engagements: translate phase labels, never render
.wire(engagements_list_screen.dart:212,288). - Centralize dates through
app_dates.dart; sweep all 25'en_GB'sites. Decide the numeral-locale policy (Eastern Arabic forar-KW/ar-SA) in the same helper. - Fix reports hub i18n keys β existing camelCase set (
reports_hub_screen.dart:24-225). - Sweep
Icons.chevron_rightβ direction-aware chevron (sharedTrailingChevronwidget); fix the public landing pair first. - Replace
Colors.green/orange/shade600withSharedTokens.status*/AkColorsindata_completeness_screen.dart,follow_up_dashboard_screen.dart:492-505,price_index_screen.dart:302,property_portfolio_screen.dart. - Remove π emoji (
showcases_list_screen.dart), route raw'$e'throughErrorState. daleel_pin.dart:176,350amber β cyan/warning tokens; fix stale brand comment inapp.dart:30-32.MultiSelectBarcyan slab β navy fill (multi_select_bar.dart:41);AkBadge(solid)Colors.whiteβscheme.onPrimary.- Swap the 4 bare
CircularProgressIndicatorfull-page loads forCardSkeletonList. - Add
tooltipTheme+popupMenuTheme+textSelectionThemetocomponent_themes.dart(~25 lines, kills the most frequent stock-Material sightings).
Phase 1 β System hardening: close the leaks (1β2 weeks) β
- Complete
component_themes.dart: menu, checkbox/radio, date/time picker (incl. Hijri), navigation bar, drawer, data table, expansion tile, search bar themes.Status 2026-07-18: shipped.
timePickerTheme(dial hand as cyan selection point),navigationBarTheme(soft navy-wash indicator),drawerTheme(directional 16px open-edge radius),dataTableTheme(recessed header + hairline rules),expansionTileTheme(flat, no stock-grey fill), andsearchBarTheme(input-matching recessed fill + hairline) joined the existing menu/checkbox/radio/datePicker set. Remaining gap: the customHijriDatePicker's on-system pass (Phase 2 item 8). - Codemods to tokens: raw spacing β
AkSpace(start with the 5 worst files β180 hits); off-grid values snap to the 4px grid (or add intermediate tokens totokens.json); 500 raw radii βAkRadius; inlineTextStyleβ textTheme roles (add alabelSmall-adjacent micro role where 10β11px recurs).Status 2026-07-18 (radii, wave 1): exact-scale radius codemod shipped β 102 files fully migrated to
AkRadius(4βsm, 8βmd, 12βlg, 16βxl, 999/1000/9999βfull) and removed from the burn-down list, zero pixel changes. Remaining 75 files/225 hits carry off-scale values (10, 6, 20, 14, 3, 2 β¦) that need the snap-vs-new-tokens decision (intermediateRadiusTokensslots viatokens.jsonregeneration) β deliberately untouched in this wave. Status 2026-07-18 (spacing, wave 1): exact-scale spacing codemod shipped β 5,314 call-site args rewritten toAkSpaceacross 383 files (132 fully migrated), zero pixel changes. Newraw_spacingban added toaudit_design_tokens_test(6th class); remainder 254 files/989 hits (off-grid 6/10/14/2/3β¦ + multiline calls) allowlisted for wave 2 (snap or newSpacingTokensslots β 6, 10, 14, 2 are the obvious candidates). TextStyle codemod not started. Status 2026-07-18 (wave 2 β conservative snap): withdesign-tokens/tokens.jsonabsent from this repo, new intermediate slots were impossible β so off-grid values β€2px from a scale slot were snapped (radius 5/7/9/10/14/18/20 β sm/md/md/md/lg/xl/xl; spacing 5/7/9/10/14/18 β s1/s2/s2/s2/s3/s4), max delta 2px except radius 20βxl (β4, lands on the 4px grid). Zero test/overflow failures. Radii 75 β 47 files/145 hits, spacing 254 β 217 files/626 hits. Remainder: ties (6), hairlines (1β3), multiline calls β these genuinely need intermediate token slots, deferred untiltokens.jsonis back in-tree. - Custom lints / CI greps: ban raw
EdgeInsets.all(<num>),BorderRadius.circular(<num>),Color(0xβ¦),Colors.green|orange, hardcodedDuration(, andFontStyle.italicoutsidelib/core/theme/. AddMotionDurationsenforcement (62 literals today).Status 2026-07-18: shipped (5 of 6 bans).
test/tool/audit_design_tokens_test.dartenforces status hues (Colors.green/orange/amberβ 0 hits, enforced clean),Color(0xβ¦)(9 files),BorderRadius/Radius.circular(<num>)(75 files/225 hits after the wave-1 codemod),Duration(<num>)(61 files/102 hits), andFontStyle.italic(13 files/14 hits) via burn-down allowlists intest/tool/design_tokens_allowlists/(same only-shrinks mechanics as the formatters audit). Deferred: theEdgeInsets.all(<num>)ban β 4,500 raw spacing sites make the allowlist dead weight until the item-2 codemods burn it down. - Delete rogue palettes:
_ChecklistTheme(20 colors),animated_splash.dartliterals, deadAldilaijanTokens/KhobaraTokensramps fromtokens.json.Status 2026-07-18: shipped.
_ChecklistThemedeleted β launch checklist now reads the shared DS dark ramp + status hues (gold accent β unified cyan). Splash gradient/overlay literals snapped toAkColorsnavy/cyan aliases. Dead ramps removed fromtokens.dartwith a hand-edit note (the generator inputdesign-tokens/tokens.jsonis not in this repo β if a regeneration ever happens, delete the ramps at the source instead).raw_color_literalsburn-down: 9 files/40 hits β 7 files/15 hits. - Unify idioms into the kit: one
MetricTile(+ compact variant), one chip (BrandChipwith multi-select mode), oneAkListDivider, one sheet chrome, one toast (AkToast), one FAB theme,AkButtonvariants absorbing the 47styleFromoverrides.Status 2026-07-18 (slices 1β2):
MetricTilegainedicon/accent/compact; migrated the 5 private_StatChipfamilies (14 sites),_MiniMetric(3), andceo_dashboard's raw-Card_Tile(10). NewAkListDivider(full-bleed /.content()/.afterLeading()) replaces the indent-16/indent-76/full-bleed divider idioms in deals, WhatsApp inbox, reminders.BrandChipabsorbed the rawChoiceChip/FilterChipsites (engagements Γ4, filter_primitives multi-select). Tools sheet's manual drag handle + radius-20 shape deleted (showAppBottomSheet's themed chrome wins). 2 rawCard()sites in property_detail_tabs βAkCard. Status 2026-07-18 (slice 3 β buttons):AkButtonextended withaccent(info fill),success,dangerGhostvariants,xssize (36px floor), and aloadingbusy flag; 18styleFromsites absorbed across two rounds (danger reject/discard, approve, 5 accent AI buttons, 3 loading submit/send, 3 destructive ghosts, dense/dense-block actions). Remaining ~22 overrides are deliberately bespoke and documented: tonal constructors (no variant), sub-36px density (below the a11y floor), circular/aligned one-offs,WidgetStatePropertystyles, and the brand-cyan add-property CTA (brandAccentgap). Sheet/toast/FAB were already unified (showAppBottomSheet +bottomSheetTheme,AkToast,floatingActionButtonTheme). Status 2026-07-18 (rounds 4β5 β metric tiles, COMPLETE): the metric-tile family is unified β 32 more private classes migrated (dense chips βMetricTile compact, hero stacks β standard), totaling 54 classes eliminated across the epic. Documented remainders:valuation_data_quality's 18 key-value rows (needs anAkKeyValueRowpass), the twoFittedBoxscale-to-fit tiles (S-015 fix β needs a scale slot),block_renderer._MetricTile(unit-suffix slot), and entity scorecard/progress-bar tiles (not KPI tiles). Judgment calls:valuation_statsaccent colors icon+value;individualswarning conveyed by error-colored value. - Arabic emphasis: replace all 14 italics with a weight/color emphasis helper; locale-gate caps/letter-spacing in
SectionDivider/_SectionLabel.Status 2026-07-18: shipped. Caps/letter-spacing were already locale-gated via
core/i18n/locale_text.dart(Phase 0). All 12 UI-chrome italics (11 files) dropped in favor of the muted color already present (the honest de-emphasis);AkType.strong/AkType.softadded as the documented Arabic-safe emphasis helpers for future needs. Remaining 2 hits are deliberate keepers βtiptap_parser+block_rendererpreserve user-authored italic marks (content fidelity), allowlisted with reasons. Burn-down: 13 files/14 hits β 2 files/2 hits. - Dark-mode status tints: per-brightness
successTint/warningTint/dangerTintpairs onAkScheme.Status 2026-07-18: shipped.
AkSchemenow carriessuccessTint/warningTint/dangerTint/infoTint(info included to complete the family); dark values are 22% washes of the status hues oversurfaceDark, mirroring the light tints' restraint. All 17 consumer call sites (13 files) migrated from the light-onlyAkColors.*Tintconstants toAkScheme.of(context).*; the sharedaiPricingDataAccentLightconst alias was retired in favor of context reads.
Phase 2 β Flagship surface upgrades (2β6 weeks, highest visible payoff) β
Status 2026-07-18: PHASE COMPLETE (8/8 items shipped in one day). Full suite 3424/3424 green after every item; each shipped with its own commit.
- Brand the frame:
AkDrawer(brand block + grouped sections + user footer) for both brands; brand mark onShellNavigationRail; wire brand accent rail toAkScheme.of(context).Shipped (
45230f94):AkDrawerwidget with mode-flipping brand block,SectionDividergroups, user footer (avatar + settings shortcut); both drawers rebuilt on it; rail brand mark + tools FAB βDaleelIcons.grid. - Data-table/ledger component (
AkDataRowβ sortableDataTableon wide) for invoices, AR aging, audit log, admin users; document-grade line-items tables on invoice/quotation details.Shipped (
2cbd1c5c):AkDataTable<T>primitive (narrow cards / wide sortableDataTable); 4 screens migrated; invoice + quotation detail gained line-items sections (new repo list fns + providers); 6 component tests. - Settings/admin IA: grouped TokenCard sections (iOS/Linear-style) for settings and the 24-row admin hub.
Shipped (
da164e80): both screens grouped (SectionDivider + TokenCard + hairlines); admin hub into 4 labeled groups with newadminConfig.groups.*keys. - Public web: responsive two-column hero with real property imagery (break the 640px cap), photo-based
PublicPropertyTile, real featured-tile hierarchy in the tools grid, unifiedPublicScaffoldchrome,AuthBackdropcarried through the OTP step.Shipped (
3812824e): two-column hero β₯840dp with featured-property photo; photo tiles; MoJ hero tile; newPublicScaffoldunifying marketing chrome (OTP already had the backdrop). Follow-up noted: 21 calculator/portal screens still on rawAppBar. - Properties: listing density toggle (wire the dead
PropertyListTileas compact view / 2-col grid β₯720dp), property-detail facts row + display-family name, labeled wizard step indicator, sequential heat ramp for the heatmap, gallery empty state.Shipped (
ce437b2c): all 5 sub-items (density toggle + 2-col grid, facts row, labeled wizard steps, sequential heat ramp, galleryEmptyState). - CRM: interaction timeline with rail + channel nodes + date grouping; internal chat rebuilt on
AkMessageBubble(fixes RTL tail); reminders re-skin with severity bar + Overdue/Today/Upcoming sections; fix kanban desktop width bug (deals_kanban_screen.dart:205).Shipped (
391bd910+569da33bfor the kanban width fix): timeline rail + Daleel channel nodes + date groups; chat onAkMessageBubble; reminders sections with severity bars. - Icon coverage: extend Daleel glyphs to quick actions, tools sheet, rail FAB, notifications bell; set the policy "Daleel for domain glyphs,
Icons.*only for generic chrome."Shipped (
11207bd9): tools sheet glyph-aware, quick-add 7/8 Daleel, FAB β pencil, 8 new destination glyph mappings; policy stated indaleel_icon.dart. - HijriDatePicker on-system:
AkDialogwrapper,InkWellcells, token radii/spacing, β₯9.5px secondary numeral.Shipped (
e744e5c6):AkDialogwrapper (+scrollable-body hardening),InkWellcells, 9.5px secondary numeral.
Guardrails (permanent) β
- Token-only policy enforced by the Phase 1 lints; treat violations as build failures.
- Extend the existing overflow/golden test catalog (
test/overflow/screen_catalog.dart) with dark-mode + Arabic snapshots per screen. - Visual review checklist per PR: tokens only, Daleel icon policy, skeleton not spinner, mirrored chevrons, locale dates, no raw strings.
Remaining-work close-out (2026-07-18) β
All follow-ups shipped. PublicScaffold sweep (23 calculator/portal screens;
3432fa83),AkKeyValueRow+ onTap forvaluation_data_quality(d66dc842),MetricTileunit/fit/background slots with their consumer migrations (31124b2b),AkButtonbrandAccent/secondaryDanger/tonal +AkIconButtonfilled-loading (a517cb5d), and the dark-lane overflow catalog (241 screens Γ 2 themes Γ 6 widths Γ en/ar, zero new skips;29dcf88d).Wave-3 token burn-down (
f3f6c193): radii 140β51 hits (documented micro-radius keepers), spacing 595β235 hits (the 6βs1 snap alone took 352), durations 102β82 hits (newMotionDurations.gentle=300; timeouts/debounce/choreography kept with concrete reasons), color literals 15β14 hits (5 documented keepers + persona gold). What remains on the lists is deliberately kept raw with per-file reasons β the lists are now exception registries, not debt.Not agent-actionable (needs humans): native Kuwaiti-Arabic review of the ~135
l.*keys; TestFlight beta + on-device QA (mailbox, voice notes); Add Property submit path (product decision on Arabic-prefixedproperties_basecolumns); comparables subject/chart/AI-estimate pipelines (3 backend pipelines needing product specs).
6. Module-by-Module Highlights β
- Theme system β Excellent bones; gaps are unthemed components, dead brand ramps, unadopted motion tokens, light-only status tints.
- Core/shared widgets β TokenCard, Daleel icons, illustrations, ErrorState are the standard; AppBar hardcodes title type, MultiSelectBar breaks the color rule, Avatar hash-hues clash with palette.
- Shell/nav β Custom bottom nav is genuinely designed; drawers and exec dashboards are the weak link (stock drawer, 3 metric idioms, spinner loads).
- Properties β PropertyCard/detail hero are premium; radius/token leaks, stock filter chips, dead compact tile, and a control-panel header (~40% of viewport) hold it back.
- Public web β Auth/splash/onboarding are the brand high-water mark; landing/tools/OTP are where the "generic Flutter web" impression concentrates.
- CRM/comms β WhatsApp/mailbox/comms are a designed product; reminders/timeline/internal-chat/engagements are stock Material lists β closing the gap is mostly reusing the existing kit.
- Valuations/finance/admin β Chart house style + mono money type are fintech-grade; the absence of real tables, flat admin/settings lists, and broken report i18n are the gaps.
Full per-module evidence (file:line) is preserved in the audit working notes; every claim above cites its source inline.
