From 1ad70fe09a1c9bb395bddc0fa66c59726f20e8f2 Mon Sep 17 00:00:00 2001 From: grunch Date: Thu, 30 Jul 2026 15:07:13 -0300 Subject: [PATCH 1/2] feat(order-book): night-contrast refresh + selective glow on offer cards Applies the "Card Contrast Options" mock (option 06 combined with 07's selective glow) to the redesigned Order Book palette and offer card. - Palette: darker page background (#080B0F), lighter cards (#232C38), 9% white hairline on every card, textTertiary/red renudged to keep WCAG AA (4.5:1) on the new surfaces. - New glowBorder + glowRing tokens (dark and light) for the one card per screen that is selected or needs action. - OrderListItem gains an opt-in `highlighted` flag: glow ring on an outer DecoratedBox (Material shapes clip shadows) and the border on the Material shape so InkWell still clips to it. - Skeleton card carries the same hairline so it matches the loaded state. - Goldens regenerated; the gallery now highlights its first card, so the pair covers both the glow and the plain hairline. --- lib/core/app_theme.dart | 71 +++- .../home/widgets/order_list_item.dart | 335 ++++++++++-------- .../home/goldens/order_list_item_dark.png | Bin 7989 -> 9921 bytes .../home/goldens/order_list_item_light.png | Bin 8255 -> 10057 bytes .../home/order_list_item_golden_test.dart | 3 + 5 files changed, 239 insertions(+), 170 deletions(-) diff --git a/lib/core/app_theme.dart b/lib/core/app_theme.dart index 84f8d914..3ce95722 100644 --- a/lib/core/app_theme.dart +++ b/lib/core/app_theme.dart @@ -49,8 +49,10 @@ class AppColors extends ThemeExtension { final Color messageSent; final Color messageReceived; final Color systemMessage; + /// Dark-gold color used for the notification count badge. final Color badgeGold; + /// Amber used for time-sensitive warnings (running timers, backup nags). final Color warningAmber; @@ -146,7 +148,11 @@ class AppColors extends ThemeExtension { // ── Order Book redesign palette ─────────────────────────────────────────────── /// Palette of the "Mostro UX Redesign" mock (Claude Design, screen -/// #3 · Order book). Applied only to the redesigned Order Book screen while +/// #3 · Order book), with the night-contrast refresh ("Card Contrast +/// Options" mock, option 06 combined + 07's selective glow): darker page +/// background, lighter cards, a 9% hairline on every card, and a green glow +/// reserved for the one card per screen that is selected / needs action. +/// Applied only to the redesigned Order Book screen while /// the rest of the app migrates screen by screen; dark values follow the mock /// except where the mock fails WCAG AA (4.5:1) on its real rendered surface — /// [textTertiary] and [red] are lightened just enough to pass. The mock is @@ -172,6 +178,8 @@ class OrderBookPalette { required this.blueFill, required this.amber, required this.red, + required this.glowBorder, + required this.glowRing, }); final Color bg; @@ -195,15 +203,24 @@ class OrderBookPalette { final Color amber; final Color red; + /// Border of the one selected / action-required card per screen + /// (mock: `rgba(143,224,74,0.55)`). Pair with [glowRing]; every other + /// card keeps the plain [border] hairline — if all cards glow, none does. + final Color glowBorder; + + /// Soft green halo behind the selected card + /// (mock: `0 0 0 1px rgba(143,224,74,0.25), 0 0 22px rgba(143,224,74,0.18)`). + final List glowRing; + static const dark = OrderBookPalette( - bg: Color(0xFF0F151C), - bgCard: Color(0xFF1A2029), - bgElevated: Color(0xFF222A35), - border: Color(0x0FFFFFFF), // rgba(255,255,255,0.06) + bg: Color(0xFF080B0F), + bgCard: Color(0xFF232C38), + bgElevated: Color(0xFF2C3644), + border: Color(0x17FFFFFF), // rgba(255,255,255,0.09) textPrimary: Color(0xFFF2F4F7), textSecondary: Color(0xFFA8B0BC), - // Mock #6B7280 is 3.4:1 on the card — lightened to pass AA (4.8:1). - textTertiary: Color(0xFF848C9A), + // Mock #6B7280 is 3.5:1 on the card — lightened to pass AA (4.6:1). + textTertiary: Color(0xFF8B93A1), tabInactive: Color(0xFF4A5060), green: Color(0xFF8FE04A), greenDim: Color(0xFF2A4015), @@ -212,8 +229,19 @@ class OrderBookPalette { blue: Color(0xFF7BB4F0), blueFill: Color(0xFF1E2B42), amber: Color(0xFFE89C3C), - // Mock #E5484D is 3.7:1 on its 13% pill fill — lightened to pass AA. - red: Color(0xFFF27D81), + // Mock #E5484D is 3.8:1 on its 13% pill fill — lightened to pass AA. + red: Color(0xFFF48489), + glowBorder: Color(0x8C8FE04A), // rgba(143,224,74,0.55) + glowRing: [ + BoxShadow( + color: Color(0x408FE04A), // rgba(143,224,74,0.25) + spreadRadius: 1, + ), + BoxShadow( + color: Color(0x2E8FE04A), // rgba(143,224,74,0.18) + blurRadius: 22, + ), + ], ); static const light = OrderBookPalette( @@ -233,6 +261,12 @@ class OrderBookPalette { blueFill: Color(0x2635638F), amber: Color(0xFF845010), red: Color(0xFFAE3333), + // Same alphas as dark over the light theme's AA-safe green. + glowBorder: Color(0x8C426800), + glowRing: [ + BoxShadow(color: Color(0x40426800), spreadRadius: 1), + BoxShadow(color: Color(0x2E426800), blurRadius: 22), + ], ); static OrderBookPalette of(BuildContext context) => @@ -325,16 +359,16 @@ const _light = AppColors( // ── ThemeData factories ──────────────────────────────────────────────────────── ThemeData buildDarkTheme() => _buildTheme( - brightness: Brightness.dark, - colors: _dark, - scaffold: const Color(0xFF1B1E28), - ); + brightness: Brightness.dark, + colors: _dark, + scaffold: const Color(0xFF1B1E28), +); ThemeData buildLightTheme() => _buildTheme( - brightness: Brightness.light, - colors: _light, - scaffold: const Color(0xFFFFFFFF), - ); + brightness: Brightness.light, + colors: _light, + scaffold: const Color(0xFFFFFFFF), +); ThemeData _buildTheme({ required Brightness brightness, @@ -467,6 +501,5 @@ class _NoTransitionBuilder extends PageTransitionsBuilder { Animation animation, Animation secondaryAnimation, Widget child, - ) => - child; + ) => child; } diff --git a/lib/features/home/widgets/order_list_item.dart b/lib/features/home/widgets/order_list_item.dart index 2af25c2e..cc551523 100644 --- a/lib/features/home/widgets/order_list_item.dart +++ b/lib/features/home/widgets/order_list_item.dart @@ -13,6 +13,9 @@ import 'package:mostro/l10n/app_localizations.dart'; /// Layout, colors, and proportions mirror the mock's offer card: /// reason pill + timestamp, 26px amount row with premium pill, "Market price" /// caption, elevated numeric-reputation strip, and payment-method line. +/// Every card carries the palette's 9% hairline border; a [highlighted] card +/// swaps it for the green glow ring (at most one per screen — the selected / +/// action-required card). /// Each card may carry one [OrderReason] pill (computed once per visible list /// and passed in — never computed here). class OrderListItem extends StatelessWidget { @@ -22,6 +25,7 @@ class OrderListItem extends StatelessWidget { this.onTap, this.currencyFlags = const {}, this.reason, + this.highlighted = false, }); final OrderItem order; @@ -32,6 +36,12 @@ class OrderListItem extends StatelessWidget { /// visible list (see [orderReasonsProvider]) and passed in by the screen. final OrderReason? reason; + /// Marks this card as the screen's selected / action-required one: + /// green [OrderBookPalette.glowBorder] + [OrderBookPalette.glowRing] + /// instead of the plain hairline. Callers must set it on at most one + /// card per screen — if all cards glow, none stands out. + final bool highlighted; + @override Widget build(BuildContext context) { final pal = OrderBookPalette.of(context); @@ -40,9 +50,10 @@ class OrderListItem extends StatelessWidget { final flag = currencyFlags[order.fiatCode] ?? ''; // Premium pill: green < 2 (incl. negative), amber 2–5, red > 5. - final premiumColor = order.premium < 2 - ? pal.green - : order.premium > 5 + final premiumColor = + order.premium < 2 + ? pal.green + : order.premium > 5 ? pal.red : pal.amber; final premiumText = @@ -50,178 +61,199 @@ class OrderListItem extends StatelessWidget { final (reasonLabel, reasonColor, reasonBg) = switch (reason) { OrderReason.bestPremium => ( - l10n.reasonBestPremium, - pal.green, - pal.greenDim, - ), + l10n.reasonBestPremium, + pal.green, + pal.greenDim, + ), OrderReason.mostReputable => ( - l10n.reasonMostReputable, - pal.gold, - pal.goldDim, - ), + l10n.reasonMostReputable, + pal.gold, + pal.goldDim, + ), OrderReason.justPublished => ( - l10n.reasonJustPublished, - pal.blue, - pal.blueFill, - ), + l10n.reasonJustPublished, + pal.blue, + pal.blueFill, + ), null => (null, null, null), }; // The mock's cards carry no buy/sell pill (the tabs already scope the // side); the only functional signal kept is "yours" on own orders. - final mineLabel = order.isMine - ? (order.kind == 'sell' - ? l10n.orderPillYouAreSelling - : l10n.orderPillYouAreBuying) - : null; + final mineLabel = + order.isMine + ? (order.kind == 'sell' + ? l10n.orderPillYouAreSelling + : l10n.orderPillYouAreBuying) + : null; // Material + InkWell (not GestureDetector) so each offer card is - // focusable, keyboard-activatable, and announced as a button. - return Material( - color: pal.bgCard, - borderRadius: BorderRadius.circular(16), - child: InkWell( - onTap: onTap, + // focusable, keyboard-activatable, and announced as a button. The glow + // ring lives on an outer DecoratedBox because Material shapes clip + // shadows; the border rides the Material shape so InkWell clips to it. + return DecoratedBox( + decoration: BoxDecoration( borderRadius: BorderRadius.circular(16), - child: Padding( - padding: const EdgeInsets.fromLTRB(14, 12, 14, 14), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - // Row 1: reason pill (+ "yours" pill) · relative timestamp - Row( + boxShadow: highlighted ? pal.glowRing : null, + ), + child: Material( + color: pal.bgCard, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(16), + side: BorderSide(color: highlighted ? pal.glowBorder : pal.border), + ), + child: InkWell( + onTap: onTap, + borderRadius: BorderRadius.circular(16), + child: Padding( + padding: const EdgeInsets.fromLTRB(14, 12, 14, 14), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (reasonLabel != null) ...[ - Flexible( - child: _Pill( - label: reasonLabel, - color: reasonColor!, - background: reasonBg!, - ), - ), - const SizedBox(width: 6), - ], - if (mineLabel != null) ...[ - Flexible( - child: _Pill( - label: mineLabel, - color: pal.textSecondary, - background: pal.bgElevated, + // Row 1: reason pill (+ "yours" pill) · relative timestamp + Row( + children: [ + if (reasonLabel != null) ...[ + Flexible( + child: _Pill( + label: reasonLabel, + color: reasonColor!, + background: reasonBg!, + ), + ), + const SizedBox(width: 6), + ], + if (mineLabel != null) ...[ + Flexible( + child: _Pill( + label: mineLabel, + color: pal.textSecondary, + background: pal.bgElevated, + ), + ), + const SizedBox(width: 6), + ], + const Spacer(), + Text( + _relativeTime(order.createdAt, l10n), + style: TextStyle(fontSize: 11, color: pal.textTertiary), ), - ), - const SizedBox(width: 6), - ], - const Spacer(), - Text( - _relativeTime(order.createdAt, l10n), - style: TextStyle(fontSize: 11, color: pal.textTertiary), + ], ), - ], - ), - const SizedBox(height: 10), + const SizedBox(height: 10), - // Row 2: amount + currency + flag · premium pill - Row( - crossAxisAlignment: CrossAxisAlignment.baseline, - textBaseline: TextBaseline.alphabetic, - children: [ - Flexible( - child: Text( - order.displayAmount, - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.w700, - color: pal.textPrimary, - height: 1.2, + // Row 2: amount + currency + flag · premium pill + Row( + crossAxisAlignment: CrossAxisAlignment.baseline, + textBaseline: TextBaseline.alphabetic, + children: [ + Flexible( + child: Text( + order.displayAmount, + style: TextStyle( + fontSize: 26, + fontWeight: FontWeight.w700, + color: pal.textPrimary, + height: 1.2, + ), + overflow: TextOverflow.ellipsis, + ), ), - overflow: TextOverflow.ellipsis, - ), + const SizedBox(width: 8), + Text( + order.fiatCode, + style: TextStyle( + fontSize: 14, + fontWeight: FontWeight.w600, + color: pal.textSecondary, + ), + ), + if (flag.isNotEmpty) ...[ + const SizedBox(width: 8), + Text(flag, style: const TextStyle(fontSize: 18)), + ], + const Spacer(), + _Pill( + label: premiumText, + color: premiumColor, + background: premiumColor.withValues(alpha: 0.13), + ), + ], ), - const SizedBox(width: 8), + const SizedBox(height: 4), + + // Row 3: "Market price" caption Text( - order.fiatCode, - style: TextStyle( - fontSize: 14, - fontWeight: FontWeight.w600, - color: pal.textSecondary, - ), - ), - if (flag.isNotEmpty) ...[ - const SizedBox(width: 8), - Text(flag, style: const TextStyle(fontSize: 18)), - ], - const Spacer(), - _Pill( - label: premiumText, - color: premiumColor, - background: premiumColor.withValues(alpha: 0.13), + l10n.marketPriceCaption, + style: TextStyle(fontSize: 11, color: pal.textTertiary), ), - ], - ), - const SizedBox(height: 4), - - // Row 3: "Market price" caption - Text( - l10n.marketPriceCaption, - style: TextStyle(fontSize: 11, color: pal.textTertiary), - ), - const SizedBox(height: 10), + const SizedBox(height: 10), - // Row 4: numeric reputation — ★ 4.9 · 47 trades · 312 days - Container( - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), - decoration: BoxDecoration( - color: pal.bgElevated, - borderRadius: BorderRadius.circular(10), - ), - child: Row( - children: [ - Icon(Icons.star, size: 16, color: pal.gold), - const SizedBox(width: 4), - Text( - _formatRating(order.rating, locale), - style: TextStyle( - color: pal.textPrimary, - fontSize: 13, - fontWeight: FontWeight.w700, - ), + // Row 4: numeric reputation — ★ 4.9 · 47 trades · 312 days + Container( + width: double.infinity, + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 10, ), - const SizedBox(width: 14), - Text('·', - style: TextStyle(fontSize: 12, color: pal.textTertiary)), - const SizedBox(width: 14), - _StatText( - value: - NumberFormat.decimalPattern(locale).format(order.tradeCount), - label: l10n.reputationTradesLabel(order.tradeCount), - palette: pal, + decoration: BoxDecoration( + color: pal.bgElevated, + borderRadius: BorderRadius.circular(10), ), - const SizedBox(width: 14), - Text('·', - style: TextStyle(fontSize: 12, color: pal.textTertiary)), - const SizedBox(width: 14), - Flexible( - child: _StatText( - value: NumberFormat.decimalPattern(locale) - .format(order.daysActive), - label: l10n.reputationDaysLabel(order.daysActive), - palette: pal, - ), + child: Row( + children: [ + Icon(Icons.star, size: 16, color: pal.gold), + const SizedBox(width: 4), + Text( + _formatRating(order.rating, locale), + style: TextStyle( + color: pal.textPrimary, + fontSize: 13, + fontWeight: FontWeight.w700, + ), + ), + const SizedBox(width: 14), + Text( + '·', + style: TextStyle(fontSize: 12, color: pal.textTertiary), + ), + const SizedBox(width: 14), + _StatText( + value: NumberFormat.decimalPattern( + locale, + ).format(order.tradeCount), + label: l10n.reputationTradesLabel(order.tradeCount), + palette: pal, + ), + const SizedBox(width: 14), + Text( + '·', + style: TextStyle(fontSize: 12, color: pal.textTertiary), + ), + const SizedBox(width: 14), + Flexible( + child: _StatText( + value: NumberFormat.decimalPattern( + locale, + ).format(order.daysActive), + label: l10n.reputationDaysLabel(order.daysActive), + palette: pal, + ), + ), + ], ), - ], - ), - ), - const SizedBox(height: 8), + ), + const SizedBox(height: 8), - // Row 5: payment methods - Text( - order.paymentMethod, - style: TextStyle(fontSize: 12, color: pal.textSecondary), - overflow: TextOverflow.ellipsis, + // Row 5: payment methods + Text( + order.paymentMethod, + style: TextStyle(fontSize: 12, color: pal.textSecondary), + overflow: TextOverflow.ellipsis, + ), + ], ), - ], - ), + ), ), ), ); @@ -321,6 +353,7 @@ class OrderListItemSkeleton extends StatelessWidget { padding: const EdgeInsets.fromLTRB(14, 12, 14, 14), decoration: BoxDecoration( color: pal.bgCard, + border: Border.all(color: pal.border), borderRadius: BorderRadius.circular(16), ), child: Column( diff --git a/test/features/home/goldens/order_list_item_dark.png b/test/features/home/goldens/order_list_item_dark.png index f7918454de0a65ec2a1780b720f50bb53eb951cd..6c20a5446af6ff80d4093b14754f19bc006fdb9d 100644 GIT binary patch literal 9921 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

S87*`>IWHB(_Lon$$bH0xR_rh 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 diff --git a/test/features/home/goldens/order_list_item_light.png b/test/features/home/goldens/order_list_item_light.png index 4e0a5c339c744c4df37ebf04b19223142196c58c..266d4189862a0dfe300f41cab2d02db16ca2d0aa 100644 GIT binary patch literal 10057 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 bink0SB;mYVbKbc?;P0q~&Ec{`o|paun}nki literal 8255 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 Yx Date: Fri, 31 Jul 2026 12:39:39 -0600 Subject: [PATCH 2/2] =?UTF-8?q?feat(order-book):=20v1=20tonal=20recipe=20?= =?UTF-8?q?=E2=80=94=20dark=20cards=20on=20a=20lighter=20list=20well?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces the night-contrast surfaces (option 06: near-black page, light cards) with v1 mobile's exact recipe, restoring the app-wide tonal family the rest of the screens already use: - Palette: chrome and card share v1's backgroundDark (#171A23); new bgWell token (#1D212C, v1's dark1) paints the list area behind the cards, so cards read as darker panels floating on a lighter well. Inner panels on bgElevated (#1E2230), hairline down from 9% to v1's 5%. - New cardShadow token with v1's exact depth shadow (black 70% blur 15 + top-edge white sheen); every card carries it now, the highlighted card combines it with the selective glow ring, which stays. - Radii to v1: card 16 → 20, reputation panel 10 → 12. - FILTER pill on bgElevated (bgCard now equals the chrome tone) and the skeleton shimmer back to bgCard ↔ bgElevated, visible against the well. - Light palette follows the same structure: white cards on a #F4F4F6 well with a soft 12% drop shadow. - AA contrast test extended with the bgWell pairs (empty/error state copy); all roles pass without re-nudging any text token. Goldens regenerated. --- lib/core/app_theme.dart | 66 +++++++++-- lib/features/home/screens/home_screen.dart | 105 ++++++++++-------- .../home/widgets/order_list_item.dart | 23 ++-- lib/shared/widgets/order_list_skeleton.dart | 4 +- .../order_book_palette_contrast_test.dart | 3 + .../home/goldens/order_list_item_dark.png | Bin 9921 -> 10599 bytes .../home/goldens/order_list_item_light.png | Bin 10057 -> 10907 bytes 7 files changed, 132 insertions(+), 69 deletions(-) diff --git a/lib/core/app_theme.dart b/lib/core/app_theme.dart index 3ce95722..17abb1a0 100644 --- a/lib/core/app_theme.dart +++ b/lib/core/app_theme.dart @@ -148,13 +148,16 @@ class AppColors extends ThemeExtension { // ── Order Book redesign palette ─────────────────────────────────────────────── /// Palette of the "Mostro UX Redesign" mock (Claude Design, screen -/// #3 · Order book), with the night-contrast refresh ("Card Contrast -/// Options" mock, option 06 combined + 07's selective glow): darker page -/// background, lighter cards, a 9% hairline on every card, and a green glow -/// reserved for the one card per screen that is selected / needs action. +/// #3 · Order book), on the v1 tonal recipe: app bar, tabs and card share one +/// surface tone ([bg] == [bgCard]) while the list area behind the cards sits +/// on the slightly lighter [bgWell] — v1's inverted contrast: dark cards on a +/// lighter well, deepened by [cardShadow] and the [border] hairline, with +/// inner panels one more step up on [bgElevated]. The green glow of the +/// "Card Contrast Options" mock (option 07) stays, reserved for the one card +/// per screen that is selected / needs action. /// Applied only to the redesigned Order Book screen while -/// the rest of the app migrates screen by screen; dark values follow the mock -/// except where the mock fails WCAG AA (4.5:1) on its real rendered surface — +/// the rest of the app migrates screen by screen; values follow the mock +/// except where it fails WCAG AA (4.5:1) on its real rendered surface — /// [textTertiary] and [red] are lightened just enough to pass. The mock is /// dark-only, so [light] is a legibility mapping onto the existing light /// surfaces, darkened where needed to pass AA. Every text-role/surface pair is @@ -163,6 +166,7 @@ class AppColors extends ThemeExtension { class OrderBookPalette { const OrderBookPalette({ required this.bg, + required this.bgWell, required this.bgCard, required this.bgElevated, required this.border, @@ -180,9 +184,15 @@ class OrderBookPalette { required this.red, required this.glowBorder, required this.glowRing, + required this.cardShadow, }); final Color bg; + + /// Background of the list area behind the offer cards, one step lighter + /// than [bg] (v1's `dark1` well): the cards — which share [bg]'s tone — + /// read as darker panels floating on it. + final Color bgWell; final Color bgCard; final Color bgElevated; final Color border; @@ -212,11 +222,21 @@ class OrderBookPalette { /// (mock: `0 0 0 1px rgba(143,224,74,0.25), 0 0 22px rgba(143,224,74,0.18)`). final List glowRing; + /// Depth shadow every offer card carries. With [bgCard] equal to [bg] + /// (the v1 recipe) this shadow — not fill contrast — is what makes the + /// card read as a card: a strong drop below plus a subtle sheen along the + /// top edge (v1's `AppTheme.cardShadow`). + final List cardShadow; + static const dark = OrderBookPalette( - bg: Color(0xFF080B0F), - bgCard: Color(0xFF232C38), - bgElevated: Color(0xFF2C3644), - border: Color(0x17FFFFFF), // rgba(255,255,255,0.09) + // v1's exact surface family (mobile `AppTheme`): chrome and card share + // `backgroundDark`, the list well is `dark1`, inner panels sit on + // `backgroundCard`. + bg: Color(0xFF171A23), + bgWell: Color(0xFF1D212C), + bgCard: Color(0xFF171A23), + bgElevated: Color(0xFF1E2230), + border: Color(0x0DFFFFFF), // rgba(255,255,255,0.05), v1's hairline textPrimary: Color(0xFFF2F4F7), textSecondary: Color(0xFFA8B0BC), // Mock #6B7280 is 3.5:1 on the card — lightened to pass AA (4.6:1). @@ -242,11 +262,27 @@ class OrderBookPalette { blurRadius: 22, ), ], + cardShadow: [ + BoxShadow( + color: Color(0xB3000000), // black 70% + blurRadius: 15, + offset: Offset(0, 5), + spreadRadius: -3, + ), + BoxShadow( + color: Color(0x12FFFFFF), // white 7% — top-edge sheen + blurRadius: 1, + offset: Offset(0, -1), + ), + ], ); static const light = OrderBookPalette( + // Same structural recipe as dark: white cards on a faintly darker list + // well, depth from [cardShadow]; inner panels one more step down. bg: Color(0xFFFFFFFF), - bgCard: Color(0xFFF5F5F5), + bgWell: Color(0xFFF4F4F6), + bgCard: Color(0xFFFFFFFF), bgElevated: Color(0xFFEEEEEE), border: Color(0x14000000), textPrimary: Color(0xFF1A1A1A), @@ -267,6 +303,14 @@ class OrderBookPalette { BoxShadow(color: Color(0x40426800), spreadRadius: 1), BoxShadow(color: Color(0x2E426800), blurRadius: 22), ], + cardShadow: [ + BoxShadow( + color: Color(0x1F000000), // black 12% — soft daylight drop + blurRadius: 15, + offset: Offset(0, 5), + spreadRadius: -3, + ), + ], ); static OrderBookPalette of(BuildContext context) => diff --git a/lib/features/home/screens/home_screen.dart b/lib/features/home/screens/home_screen.dart index ccfe53e0..9022bf2d 100644 --- a/lib/features/home/screens/home_screen.dart +++ b/lib/features/home/screens/home_screen.dart @@ -66,9 +66,10 @@ class _HomeScreenState extends ConsumerState final isDesktop = screenWidth >= AppBreakpoints.desktop; // ── Order list: responsive column count ────────────────────────────────── - final columns = screenWidth >= AppBreakpoints.desktop - ? 3 - : screenWidth >= AppBreakpoints.tablet + final columns = + screenWidth >= AppBreakpoints.desktop + ? 3 + : screenWidth >= AppBreakpoints.tablet ? 2 : 1; @@ -155,10 +156,7 @@ class _HomeScreenState extends ConsumerState fontWeight: FontWeight.w700, letterSpacing: 1, ), - tabs: [ - Tab(text: l10n.tabBuyBtc), - Tab(text: l10n.tabSellBtc), - ], + tabs: [Tab(text: l10n.tabBuyBtc), Tab(text: l10n.tabSellBtc)], ), ), @@ -171,7 +169,10 @@ class _HomeScreenState extends ConsumerState // 320px-wide screens without a RenderFlex overflow. Flexible( child: Material( - color: pal.bgCard, + // bgElevated, not bgCard: with the v1 recipe bgCard equals + // the page tone, which would make the pill invisible (v1's + // filter uses its lighter input tone for the same reason). + color: pal.bgElevated, shape: StadiumBorder(side: BorderSide(color: pal.border)), child: InkWell( customBorder: const StadiumBorder(), @@ -229,28 +230,38 @@ class _HomeScreenState extends ConsumerState ), // Order list — shimmer while loading, error state, or live data. + // The well is one step lighter than the chrome (v1's `dark1` + // container): the cards share the chrome's tone, so this inverted + // contrast is what makes them read as panels. Expanded( - child: ref.watch(orderBookProvider).when( - loading: () => const OrderListSkeleton(), - error: (e, _) => Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Text( - l10n.errorLoadingOrders, - style: TextStyle(color: pal.textSecondary), - textAlign: TextAlign.center, - ), - const SizedBox(height: AppSpacing.md), - TextButton( - onPressed: () => ref.invalidate(orderBookProvider), - child: Text(l10n.retry), + child: ColoredBox( + color: pal.bgWell, + child: ref + .watch(orderBookProvider) + .when( + loading: () => const OrderListSkeleton(), + error: + (e, _) => Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + l10n.errorLoadingOrders, + style: TextStyle(color: pal.textSecondary), + textAlign: TextAlign.center, + ), + const SizedBox(height: AppSpacing.md), + TextButton( + onPressed: + () => ref.invalidate(orderBookProvider), + child: Text(l10n.retry), + ), + ], + ), ), - ], - ), + data: (_) => orderContent(onOrderTap), ), - data: (_) => orderContent(onOrderTap), - ), + ), ), ], ); @@ -258,23 +269,24 @@ class _HomeScreenState extends ConsumerState // ── Scaffold layout ─────────────────────────────────────────────────────── // Desktop: persistent sidebar + main content in a Row (no overlay drawer). // Mobile/tablet: Stack with optional overlay drawer. - final body = isDesktop - ? Row( - children: [ - const DrawerMenu(persistent: true), - const VerticalDivider(width: 1), - Expanded(child: mainContent), - ], - ) - : Stack( - children: [ - mainContent, - if (_drawerOpen) - DrawerMenu( - onClose: () => setState(() => _drawerOpen = false), - ), - ], - ); + final body = + isDesktop + ? Row( + children: [ + const DrawerMenu(persistent: true), + const VerticalDivider(width: 1), + Expanded(child: mainContent), + ], + ) + : Stack( + children: [ + mainContent, + if (_drawerOpen) + DrawerMenu( + onClose: () => setState(() => _drawerOpen = false), + ), + ], + ); // The scaffold background is overridden at the theme level so shared // chrome that reads scaffoldBackgroundColor (bottom nav) matches the @@ -294,10 +306,7 @@ class _HomeScreenState extends ConsumerState /// Custom app bar per the mock: hamburger left, notification bell right, /// empty center, 52px tall over a 1px hairline. class _MostroAppBar extends StatelessWidget { - const _MostroAppBar({ - required this.palette, - required this.onMenuTap, - }); + const _MostroAppBar({required this.palette, required this.onMenuTap}); final OrderBookPalette palette; diff --git a/lib/features/home/widgets/order_list_item.dart b/lib/features/home/widgets/order_list_item.dart index cc551523..e0d41164 100644 --- a/lib/features/home/widgets/order_list_item.dart +++ b/lib/features/home/widgets/order_list_item.dart @@ -88,23 +88,27 @@ class OrderListItem extends StatelessWidget { : null; // Material + InkWell (not GestureDetector) so each offer card is - // focusable, keyboard-activatable, and announced as a button. The glow - // ring lives on an outer DecoratedBox because Material shapes clip - // shadows; the border rides the Material shape so InkWell clips to it. + // focusable, keyboard-activatable, and announced as a button. The depth + // shadow (and the glow ring) live on an outer DecoratedBox because + // Material shapes clip shadows; the border rides the Material shape so + // InkWell clips to it. With bgCard == bg the shadow is what separates + // the card from the page. return DecoratedBox( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - boxShadow: highlighted ? pal.glowRing : null, + borderRadius: BorderRadius.circular(20), + boxShadow: highlighted + ? [...pal.glowRing, ...pal.cardShadow] + : pal.cardShadow, ), child: Material( color: pal.bgCard, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.circular(20), side: BorderSide(color: highlighted ? pal.glowBorder : pal.border), ), child: InkWell( onTap: onTap, - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.circular(20), child: Padding( padding: const EdgeInsets.fromLTRB(14, 12, 14, 14), child: Column( @@ -198,7 +202,7 @@ class OrderListItem extends StatelessWidget { ), decoration: BoxDecoration( color: pal.bgElevated, - borderRadius: BorderRadius.circular(10), + borderRadius: BorderRadius.circular(12), ), child: Row( children: [ @@ -354,7 +358,8 @@ class OrderListItemSkeleton extends StatelessWidget { decoration: BoxDecoration( color: pal.bgCard, border: Border.all(color: pal.border), - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.circular(20), + boxShadow: pal.cardShadow, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/shared/widgets/order_list_skeleton.dart b/lib/shared/widgets/order_list_skeleton.dart index 52a8a9b4..a7bf9548 100644 --- a/lib/shared/widgets/order_list_skeleton.dart +++ b/lib/shared/widgets/order_list_skeleton.dart @@ -17,6 +17,8 @@ class OrderListSkeleton extends StatelessWidget { return Semantics( label: AppLocalizations.of(context).loadingOrders, child: Shimmer.fromColors( + // Card tone over the lighter list well, pulsing toward the inner + // panel tone — matches how a loaded card sits on [bgWell]. baseColor: pal.bgCard, highlightColor: pal.bgElevated, child: ListView.builder( @@ -42,7 +44,7 @@ class _SkeletonCard extends StatelessWidget { margin: const EdgeInsets.only(bottom: 12), decoration: BoxDecoration( color: Colors.white, - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.circular(20), ), ); } diff --git a/test/core/order_book_palette_contrast_test.dart b/test/core/order_book_palette_contrast_test.dart index aa812821..8acb4b77 100644 --- a/test/core/order_book_palette_contrast_test.dart +++ b/test/core/order_book_palette_contrast_test.dart @@ -65,9 +65,12 @@ void main() { _expectAA( '$mode textSecondary/bgElevated', pal.textSecondary, pal.bgElevated); _expectAA('$mode textSecondary/bg', pal.textSecondary, pal.bg); + // Empty/error state copy renders on the list well behind the cards. + _expectAA('$mode textSecondary/bgWell', pal.textSecondary, pal.bgWell); // Timestamps, "Market price", the sort caption, and separators. _expectAA('$mode textTertiary/bgCard', pal.textTertiary, pal.bgCard); _expectAA('$mode textTertiary/bg', pal.textTertiary, pal.bg); + _expectAA('$mode textTertiary/bgWell', pal.textTertiary, pal.bgWell); }); test('reason pills on their fills', () { diff --git a/test/features/home/goldens/order_list_item_dark.png b/test/features/home/goldens/order_list_item_dark.png index 6c20a5446af6ff80d4093b14754f19bc006fdb9d..b29d9df6eacf90e26f5808322545481f29ba13a5 100644 GIT binary patch literal 10599 zcmeI2cT^MG+W#kjfPw@>iUI+_gQyfyq#24zITqj`f}m2Qst}6wmIS#p1o(!Jo7x??`KcQZ@St? zkDNRLLD10~ziQlpAVv`gVlZZ927BT>o;!mtnCl(wYY?GRa2{+hxn8?*mlb^cSgnI0 zNCdi}arLfO!s3`oxDCyJaC5?B>COXBqN+;I!l}z)L7_)O3M9_zTC;^8jyh&B6fAc0 z4e0_l9Q$13D$^+}T%Ns}laqNm@Gr=Qmw%kT_~gumYs})@qDSglbRUPr-#!=Gk~HPa z>#?~oX4+@ysdNkR)VA~sySGz58MBnJLxUoi%ZV8j^3&e3OB*IXhHq<-r!*Gz3t+6y@(d%C;=-x6c?Zm?t*Y z6)DG+FZv)YU<^z~#26JL()P& zigWeJrM~0Q*J0^iaMCs`%CET+W=~vdUbnh8T)i%Owe6>*|%)paeJ=m zsSI!SVmlY-oY2{%w~c*al(%{#AH{XPoXOGK!xlyHnXosRydfc(@sgdRmxJSpaMHT& z34sC1VA;&=+r$o1S=f%tVn!Kf0M8rna9vetJxDauUjY}VbTiHyI7@E&R?`Mb{Ph{RPCf00h<(KJV zUu~D3oCo=?gbtniB_Y(H#Gw&P zjnMqO=!|;G^^p=@7s^nFqCX*`)r`lSw(d9}21`&hr}a7tE*Ryz7Kg+W9h;~*nge2W z_rWkxmaiIhW?$yJ`f?4Wgo2JU*-pbEua0Q>(YWv7M;}}6^ou$wD}-B4K9rmbg#scI z$_v9g5?vM&?5F8_6SObq?q6w1CpY9I$osfkeYW_K({Rde@VxWL_8xql!M!KZ*vjC_fRBWy1%Ix zFZlfAq5p40%11lz-e^${Gk&d+t>e6RhHCCKf2eue(658%ciIu;EuTCCKPC`f$nO}F z@9)bSOMm9`M{bl2SA2=?^g4|!tEv)KrzNH8^9R42>}V!9g(nH#duHtNiO*Tinr^q> zaG3BZl|h92Lr}(H&R-o!Zd|0rtDjH;14(f*RcNJ5(z=Roz6)i+_`6t6r30zAY;UmK z|Coui=&2X>v9sO9sPGcze3xM<g}wszzP4lgn?oq8hC|^KOzd=Q zn$s&hYqo6n`gA<9J}`dMQS-c)pmfFT@eu8geFE%FC#m_Eh}wFg9jSRg%#}^bcX9s7 zZq~%^*U#n^f_?gti0C)$XbklNaJVe`jB+R}cPm#XLiFJh|v<}F9Pse~7^ zUUPxM#$H3Joq}AlLs@wKPx@~Nuz+4B*3&VuCdUKo`D$!_$2ayriI-R1$*oxpRl`sw z%oidqjh%fN0R=FnRp@*Rlzc{H2>5nz$czcQ7FV>GAk5_ZFpj>mdMkIUP=P+{DO08M z^_f5XkAoouwZ6T80(u{MA2Mwbi+f7Df+)N7wKX=Df$7f2G?X=m{IxTGs^Kn2SrdLc zn5Q`{=$&gK4C{E9Q!$_b`C!W^Uve`c`a!1?Vh0I1zXrP>snWZh{D>@EYl|`7ovn3C zmT+Ar$Se^G;Ijsu~*mb0D?`L9~>@l|VC zQhG(GxgC7>Jt|F`tex^PM6dMlU`g?cF#p9f)o$+ZXDnMW6W{Lh!09`)y!*rLnduDH ziT*!uswa}S@p>LAO?S2xFLg=57*y`)gz>v^iZs(+`toFdt;vn^xp)#f6OS8C(N4R^ z(k-uBubg4)8~D-g=ed~8r)dB1MhqmIEja3|-!ibt-+V)V0O_iNo-S3%2M;Z!kY!8j zsM1avWN}6)8#aJdhcB892iFx{b(nDB^d9n1;g|@bZCs=#4F{(k6Na)`z@e9G%$k1B zb!v7_53SSU35-x)yV|p1ESVB_TvkoO5?vKes~)=mksHqouN#k8%T_4|&l{#&!=Sy% zlmDT%GVoA=^4=!X-X%xYYBkIRK+j@60#theB*0tLGYs!vXX^^ zf;RbTC{o*1?i>zSbsz-mAI~WnDIlJVEhZ)oj*OZ5R3#=F^Kd?7USGZsCd47O`TjcMz;PV(c_D3fUlBd`Lwy>szfXTKbY+y8TTOVS)3O zPQ&KPV^6qBmcFenI2LvlkRCNy7k8y{ajn|veVK0CKVL&_x)2s&!plN93^O~e4oxx- z@}oEHRmbUt>3sY5E270cn!-$rs=pL8&zGpWNU84q-kP;P*8eLOn&{m_utB=mtKAz+ zSy__(b5H#yeUFJi&Wv8sd&8l~{vVMRwVr1V`fRDH+b8&8u(AJ=-XYR zUP&z=!=TC2ZwFB9?E~n+Miw>n<wn*w>uaPM6tF$L)rRh>89!!GugUtzy`NPtc6%d`3TYG^d zj|=uz7agpS&itp%DlgE710)!$LApuWYB&S30r*>iVBA6^jo4fICNyTaAlS@Y(V~lb zBc(oFrCWkthki!n_#Y9im6196h(J-xS9Vd!E73_K@|I@Wcijb8DDvX2Gq6f!(6Bir zQ;bk9&NRuRyEQ8dLAB@pfxq#rdyb&7EN{=0QWi|vq;^_fsY1*#kgrJI(l>=`h;aWEMm8BX$n+W0zviu01vxFGDwp@@)>Aez=H*`5g;1@s z>z@u*JjCYn4Njj-_Efp%q_SQIcT-`2CRq>M+3WuUclO2<4vk8f9M?SIt*;d`6J=wf zVQmUOhud8fAnRcj{2%8Yvm&ar`AqNV*hJ~hmQFUEZy zRkO5P<~6-~2ImiQZV-CMGuDg+`t=qTV)GrSKtGvxw=Fbb4{9G%-jX0|z!|;`Oi-3S z#9$Wkn@M=#ovr+i`lmiSBjYFGNau;q?aNC`P0M@x!U*zhNZ~aUaCz;%w!B%vLe%T% z=>arJA?E(Rr|SB9G1RQ^-kRFOr!=D9cfHsnuY~vV6`G0k&sTWO_A}CxLa!{9T4lV8 zF`doN#i%TK?~!pR8h%#*O{rRb@RSx?NlIJ}ABi38ub~Y#Pj~0~qvjVYXQb3lIAKN} z@R{uk@X1ICiPUV2z@>_IUFbEKDc58ihBk$hyv*HYPJsPuwjasD)ZbFBI?D(d3q}6K z2#O30_LIIUFd;~UNBbv75QM>asVtZknHaNK_gP{iH%`raf$XP-p1m%7vmg;eCDMcb zdbwin@4I5QhqgwO(H^ZC#=SM$D?!l?vj)lAC9B_}V|mTco}QlbsNL_r6D8})kit!m zO&ZGxAqeZfR<3|*5I|cVPu@klo2WL7ui2M0;_2vIihUeZtkGNq7A zQ_vNQt90NW-j^q7n|72V7*j48UXCbF@>F4VW&-UpGt*>~g}flXJlo;7L=HbzMip`O zl;*g!(4qBmww{0@i)5BF*M~Ns+RbznTUXioO~PB-zQ3Da?Otx8JGZf+zh37=gUNryu#_dy)|J18lD zL(W}87R-#%0>u+38COm|YoP*MOm@b|M>|w_@$MGP&F0hZ+A1h~#t1<>pok>IdAk1# z_>rq#M-2^`oa4m9}8XFrV?J zI>VCB&ku}&eDWuKowz~Y;?P1h#U&p>Y>_K9LLi^+C)D>x2(95m-m5q$fJ5-1{qzq5 zozcB}3YMh1-5ZLKy_H{PaG{f6b6>l=;6wLq9=EGlbrxz;MrxA0%f=lZwH59MKaJ_q zp1=c_jb}U?*%4#uS%l_*qSNXrjD6V=Rdzp0eKH~+EDJSKr3i;$ijEIT-nfhiXt^v} z3i%Ry_3!D{JeLOH+ESFB3Csl2^${<fI@$BZr z3j%2Vt3k=?XKspO>2Q-nO+*cqY7q5=6DuIyF1kNVOo*J{5Es7}@3kM|E$4_nl*lF0 z^?r}<$Dn^^=y|<Sh>=Gyua*a@e3=bvFris=qbB;94{&F_;fmE0M#&)dwcqwcG~LaXv*WKY6Z~5 zIhlge`B4$a3a8_qdy|Su=q(ZPfwhn6C?vfBNl=@OgB$+>IM{DWZPUF%HV)$t8}^qr z2Fr57uLuu@bQ>XvYO1*N6K@;$`;<8d{VvWQBAir6n=IsSwWPB2}cFusN!>=gR%ItEcFsB zW_~a%8fd7$3$Mev-fM#%3MBE8VJ(#18FR-*w(Ky_`IER{BpBik?5UEWgF~w9QLWZL0#6#t z9vtylF;p__Z3n#GNL%Rs;=52d_7^!F?&#Lj92^{}gshe@Bxo^~&1iIRA@YlgcytV! z9poeS_88M2!2E=Nlt=FE1-|XD?UpliK%v}Kj;)A-XXMq zMZpF?Ra~ovA0!ytYJHO8%@bHBvNpOQ()9~Kb0=}lvbmXWZzp&ha!vpv%)6a5G;Mq= z2hydnJ;(^JXKC%}W@SA*wX44Kj|iGcN=F!kK+jR#kB=9TRiW2$9k%*??%@F6b%F$S zbEK&bqdR5?ypZF#HzG>&ZeJx(wf&v9cE&|F?2k{-U;K&u)KISr@78{9uby$DyY05bWBlIR2$!w&m2U2{@ZP5? z+7Za&acPmDo1z|zQ%du2p%#i{W?OV8to)9lyY)M^?)Pk9B3)VMySPao4G5a9{#*MiJ?ClOreyHR4?Jc zVF&rH^ZkkY{K?yhSM2Nt5^A3}G?5-HESfI+uw#pgtEzaSTeHcs7K=c-{bvH&=+cUoPdbi-&qc0<3p%Y7eO#A@Bh9jxZ?p~`=Sn(q>9O>EXKl{>jy_Fs@Hw^ zs<&sGFA_bUj>s2CUZF063*wF5WwDeot2~Y&r;qzAjKH>Se0|T0N1F^-)egHH;r+)8 zRe)|o>%W2ZgVJ}}vMr)Ag}*vqFVnrOqhU~_PaJu>sGv_AYv2an15zilD^La%O*NiZ z*yM&IaVYW1>6l><>>wAStrAB`0_+PF8#89Ic z++6Xiyb{`kH{Yc^c5BJl4?f?XYVWk*z4IGK%{|_o5EVtxr_m3q6fup-P6^VfNk!eg9D(ZQfHcen)M+7x z>;-of>1iEXdi&%Dkv0{SKyhY)Fd=sn+adhcT4NTVj7S{6gSG4!fbM*eBnEZ(oBGS; z(|$Lq6}n^&P9%ljs}(JEu!XjSrLe5stJ!6o5SRlI`OjlV9WLiSz@04(+Q%M{4D50a zVYnsi9%g!zWIk&C!#=`u?d^g*n^eWmDTP(lo7)cA*ak1JI%Q{hOyx4V>0u$kLd<3} z{T|Y9Dhm*cswyF0UtjIv@6=A+g~cW5s_~gyv5}utBF$BttSA+{b02!>el{<`p)q0YU{2|hk)q~F3wM&`Nkz4OaT)WzBxpt4$)Mrq3)Fbw3z zQ=hSJ_+0$L5(U0J2pto^1?87`R*_|~s%@f8R~qjpNA?wS^^iNJxZW?5Outa6Mz_Ta z1(Z(aLBKYp=ndERM1GHULL6;vmt5mU-*N8|OnPYqLRLslpXi4^;{OY174*YIfaTJ_ zU!XnL&uTJ2UK@q{eIiiG#=G94<~1PGoM^Xv|8D?Wpn75E79U^IqoJADcO`PZO@frdT1A;6G<#qn~-~(OdP=R3R@9;u~ zS5<-K6Ifn9s6L=9xvMZ|3;oqG{{4LNZ!J?FB%evG)>MhMmavNjk~px!B}(>@z=}P^ zqedRbgM=JfP7qC9^pTik2I9ljBt}!8126H?6vyDqXagXKwI%}a5T)RcWRqSXNsNNk zlMi#wHMBDd~V)1Wvu&g8Fas22N=m|A4RV zx(B@7M~QkKm@NbyK6LOd0JE82K#@@l9zc-+D@YsUdAqgB;Aa<>KsxUHJ<#P_Sz+sY zC*Uu`#e|`WyKf?&t51N+6(!m3H_WmkwN~l3T1+~4r02L+VJkPO5eE;Z&uP!PUuw?} zDqO2MXp7twV_QjF5O{CC+i)#ck$7VAcd((CAa~e)G9Q;<@|5O_UTw?Tr|pdIWZiPw z`I|4-&_J$_)Kma_t$rVX!oiC1ja#>JFU5CQDn4B5uhTX;+cA_zftAUq0p)_#*EYB}3CC-w0yX))Yc-Vj zaG@tx=yS33sXOhM@0T#;cd@&3xGE*|KHqr$%9@_a#@$huW}#ahpB9vH{(EE>BH0|{ z&@MbPu@b-RKXIqM=9|#6pWSG6L-Bq`vnnqRy=Z^SX;#XK*6IadOZm#$M5))4d5D%X zfqtAZgWI9+u_f>L?E*1ro$(I44=B_>t{Q&=vm_;vJgxo>C1I%chx1P=*TltX%s4?l zJO@_Q{#r7l|KB2pU+v8QQuuMRYV%&~pRvdPUf#2N+rHyfy=yoXs+Zrom9Sc|x3SIv zn;`|TEIsg|jg5_MRZYm?4sd(hCqG4m-03Qz@_L5zXv=bitFD|&iOaZui~xbh!>O&kU>(-0Ps7ea^OG=~v3gyN(0! zB$Mpj`+JZbjGUF3rawR-G((Z{-?#M^Z;)&jTpY58ar=m6J9Qp0TN75UjR4-z*pphJR!FVQ^gZZ ztO*A)OwQfQn;9~C2N2GG^oq*u1A;O=4gkdyuxz*Rxm|6$NPGIIn)7nL6o&To!-wx7 z!CM>VG^d#R2uRW7&$$a!zkl|wOn|O6NF4*$0Whfd&)d6j;LEj{Sk*l_HtSG8tK0{| zG~hNCay!>v&>{!}%{`MbzwKYQB&}W$kA8C3ux~>Gvd@rg=f`QuzUu^Np+6Fooq+PE zqQpJGJ3dGN8J`BUnv^#SlhDT>%54P;2O`ce#^#IAidP$f zNZQiDOp012ys`*fYNl-@S{>YZw`@ZE<2d;yygpzl3C5&V#kjPHa$eysu&R7MCG$ti znxq!sXfFjKw4!Xh@BVI(YrzAYGZ)2M$UCXI$!oz)5-T9mUNAVwubnh2o9sI$l6?dm zI=$la>YQl1rIl6vi+N}w2uZZEvJw+5cuPD#;9q;>>_LEeP`o$R*k*yl7;@+bXrbz& zAcwi%paqZnVnATtQ@@5I=RZD)J8(Dhh7OL7S|%}5*^<}+>Q_eQ5_tvulT7f_G^5cQ zF_FAf4kE9FrRV1TH<}GiO}d}DwM++O)HKK+%pvmW_JUXpk0wIXWy`~szU}xWEt)@4 z{xgBgC>EG1g_9@^(|fDC6r#q6e13izPko&P$oWVjJeSACi^-S|C7{z&xoa;!h6@bb zYbg+wm-jS_^cHYU9IRU-$~#BpykHx-UN zk)K>!(*cznlCyY8|G;G~39I&%c+bDd)_Mzo%GA6OZED#Y5m+bj5+5Pa{%8OXJE%SB zZFLvg0{G0K6!U}Czke3t{}#ggZ{wc;{Qp4C{9D@R|L?~8n6ozIa?`4HV+ee1XzFSZ Iu30?)A3deC761SM literal 9921 zcmeHtdo+}5-~T-bZRHS&9HWiRL}Vk!sT{IZQjJ57ImC8s5@Sr5QW?Y~Az>7i43hKt zPz<)ykVM8HV@8Gd=H<`=X=MW zJ!7@|hy6bQ0I=Kor1?1j;8g?w9!Eibu;o$s%`4ysU+8h`3xeR!bwO_|_&+4{oYisQ zWxwnk04M_1=Ep8XWHTuN#VQ=v(WS}WP$SY&-^GS%&VBZn_PeKL=N})`6|dlFan-`w*#c#mkO8OM`*SBZvcUTEg5)8aZQbLF~e$R6gm+1?NwyBF2$dl~;*vV2PmxC#v4a=idJ zM|vCp0f75riU0u9;o$>-la?5;`8PpPaL&>Y9soF~3lDx(+m>}B{AfMJe&)=)w`|DwF^CU)V!#fI(nsh!*DysZvi)g zR6=~pxG%$@3Vs&vyFEvqxIyI>EJL&t?e%f?s)@aIHW)1SMFQ5-#X?)ttJaP<_ROxh zWLG|v;Mn5Q&Mr`~lY~>ect{6e9$8)GSlS8ZXq2y!;ij?hc#~8j*ATHer=$7pyqJtb zkCX^OD(HgU22mbnZa!0jWqC^G+=iwL&y>wx(K^%EtT3O^iJPlGL+vHQ~Er&;)7Symq*dX3TR=@^nx-qf}x-ihT|VNY2`*v&M#%QADO+g z)Vtm%^)d}Xi?=&%baL=E)MBAH+5XLxkaI1D_qugGrvL} zsA==7NQn75eptBWxg2tI2`JH zjGlx7;5_w4UuB7HCfD(Ckp61+q-t&nwlxyfM+`JME1aDx0z&x|EGRnz^8jtML7x$U%}msb3v z{u%OGo^!1SS&bn-B@Ftz#26xfl6==HE&Ad$UYY4QI-G2;ic@Vie2JFD)FJ2^)K9C< zgOil_CabUVk_<(dVp+I;;>1-AVM>jZt?4vg1oM=DRaKDgeB!|Ix`fmibLHHG`SbAY zaURXFLYB!jJ+m*qejWontzPc4UQKr%oU6&NStt>GN{0)?A6f_|PB))%F>yAhz4gM( zbX&I%hgv|H^X+d~_7rOCIATfp;QKkBvf2W5Q}-){x}UK>$%cTD#A2od+7Zi0 zuO^M|zbnmz!|W$q&Qg_U<*^@S<^>(tPFzGI6~lQD{t;kL+H$8k!0()`elw{NZ*@dpew&AEXGg@y7L4Mj0kZQT+B zYmj*j{IsUqaP`?yD#PAKL& z2PYTb6u0mBMI(6$Eos=CaoLZM<$48E+0v~!uk$5M(Fmz6>d2Whn^hHSYRhYi-M?L% z3<$^TH!YoBYULF)e=0+tZwm%nffQ;uZk$5D-@!P(%gP1M%318C%W9DN^&IDsF-vUrQ;M z{wBi<6R+DT_vqlt%o{mUg$pqH@lS~mAtJbNwv_v^P3vo0?<^SN*n1RT@%o_j*j7Xx za_AXhS@-c}6yTvMuK23$IxQv#{Xsx%nRyx2{~Mi9kjC4p0fwfyO!k3T0Qd=f%>Jk9 zHErS@AI_z1bpQ*2{TNv6g;Y0hO41B>v%xkecSAm&NXZ$kHO2cge?J4)x0SDoh*p%|qmMOWXF%S-##IG^_^B*(RUxkB;keHwp+7o6#U zB51PMRY-YSNNr6lb9J!@T$)if=(NWYUbC>>J>doFaW-~)bLu+*%pqFNF5Q#xYo6uN zuUOinJn#<*OJj0jI0)c;1_Nu8h;_9S&X|{vB?p#A7F0L`y*oG<7;lop;@#`D8e=^g zDKxyzpf}A=TO}YaPhBn<@=zpt`q+uIe4>-MV18Vexe4<+C zW_>3F^AtQnr?kmh?Wk7`ENcLGK7G^c-@_(DFVTR9;ns%0X&*G54-bTvu^3~#!lDjWjU0MGUcYR# zFOU3kIV)8^e+2QczNSuYro3&3LQV0dut(vI!l{i((L}2uPh|B&NVuLtn-KWu0yu|{>_BeVJ#|!e4>-nW6)yeahwD*FQlH<- zYC^yUelEQn`n-8-$LRW>y!4-A+nQre?@eB>!Qo=GM6-i(4^J>bOpM9#aIw7RKE1d_ z-q&52dwUR^`cXVfj_axF>19kAF?l6{KtkOizyP6(-Dw(2G_9CAmbPE*YlFN6cnW%kQ&UL5vM*821LS!0_U5S-VFP083r3^g zTfy(T(HBGyyJtgg+%X8H$A2k`YkA=9&S}~(H{R$Qa&E~*FUDIbps)9E#7WUx9z{XP z${SR5NyGk|?G>EpVnZ&(7zf2n=9Pl!fhQ-RQ>W=Ujv#>f-r<-31!lAzeWua^s>V`gQQjyp1Y8Cq0AySe z4!3ZUv`h1O;3I9JU5Gw7wHFM{9!}|2H6w|}A;Ts=w5E5JLob$uw^zi~l|wysWi8=p zAg&x&%J4XLqKcg3_=!UlIP9?8xL0U1x^gV1-U|2ey^TQDk?^>O^i9YSIcPn;bf;)mzzDrW{9IxJx!S z|GH)s<4X?$FqM3QhpUjAy|%rLeSW&h!N}@@y_4N~gBSp{NNVwY&bGyy?2B10$R(Gf zM)4DC@AW&QIQWN=n`2{?M0&6wVa8=4NtNHIA|}^t zxF}LXbmVik`?u~%l7wO@`t$2ADaghs20KI3H6d0&q+fTan4E2b)=ZWI3ByL{?DXj1 z+{k2i%ST>?uLGy%TWE42F=$zXD;^AX%+flkGu4;W-Dt0Dk>4r$OA9xbM84I75xJC7G z7}PRhk=2Q8_Hj4ytsSYu*!MSi{r6Q0>JS7kkmLjBx?av$r%t1r-*O9ielNe;KDTP!q(E6-1uUN{R~QD*6g>NlYYcG5I+%y&wr(IM8x)=3wMSckmxS@)2S ztx`%rP*PjJE(r_nkqJsKLxjn4aWxG29Uj346 zR?dz z*(|iatDoT5WRM)QmL7bIA2J&0)V>+Q>|hskXiG~VHs3sD#d~P(6n$|_`=uxIoLGj! zB=#E~%0fjIuu_2VM)c%B(!|wv+L8IP>T~8Fl_Q==g5zG@EJW-YNi^V84I8X7s=3F2 z>Vc1o{++MU&WN>{i@RQCAecYpwg`oZDV|L&$2zXl)$SBoWE)jUcDjwki}&9G#=|*{ z&ElmS`*IABR}b9@NOeR7N~EDlPxL+vQaMIjf

S87*`>IWHB(_Lon$$bH0xR_rh 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 literal 10057 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 bink0SB;mYVbKbc?;P0q~&Ec{`o|paun}nki