@africanies/angular-web-sdk 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/.nx/cache/{4082520855419352840 → 15302120112746851896}/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs +30 -8
  2. package/.nx/cache/15302120112746851896/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs.map +1 -0
  3. package/.nx/cache/{4082520855419352840 → 15302120112746851896}/dist/libs/africanies-theme/tailwind-preset.cjs +89 -12
  4. package/.nx/cache/{4082520855419352840 → 15302120112746851896}/dist/libs/africanies-theme/types/africanies-africanies-theme.d.ts +14 -4
  5. package/.nx/cache/{17491371155400585077 → 18393832731522001121}/dist/libs/africanies-core/fesm2022/africanies-africanies-core.mjs +139 -51
  6. package/.nx/cache/18393832731522001121/dist/libs/africanies-core/fesm2022/africanies-africanies-core.mjs.map +1 -0
  7. package/.nx/cache/{17491371155400585077 → 18393832731522001121}/dist/libs/africanies-core/types/africanies-africanies-core.d.ts +14 -11
  8. package/.nx/cache/5151121439688073678/dist/libs/africanies-icons/README.md +69 -0
  9. package/.nx/cache/5151121439688073678/dist/libs/africanies-icons/assets/icons.sprite.svg +1851 -0
  10. package/.nx/cache/5151121439688073678/dist/libs/africanies-icons/fesm2022/africanies-africanies-icons.mjs +833 -0
  11. package/.nx/cache/5151121439688073678/dist/libs/africanies-icons/fesm2022/africanies-africanies-icons.mjs.map +1 -0
  12. package/.nx/cache/5151121439688073678/dist/libs/africanies-icons/package.json +30 -0
  13. package/.nx/cache/5151121439688073678/dist/libs/africanies-icons/types/africanies-africanies-icons.d.ts +108 -0
  14. package/.nx/cache/877026836685850193/dist/libs/africanies-models/README.md +60 -0
  15. package/.nx/cache/877026836685850193/dist/libs/africanies-models/fesm2022/africanies-africanies-models.mjs +613 -0
  16. package/.nx/cache/877026836685850193/dist/libs/africanies-models/fesm2022/africanies-africanies-models.mjs.map +1 -0
  17. package/.nx/cache/877026836685850193/dist/libs/africanies-models/package.json +23 -0
  18. package/.nx/cache/877026836685850193/dist/libs/africanies-models/types/africanies-africanies-models.d.ts +1452 -0
  19. package/.nx/cache/{17499961385238663835 → 9406544675747598148}/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs +765 -615
  20. package/.nx/cache/9406544675747598148/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs.map +1 -0
  21. package/.nx/cache/{17499961385238663835 → 9406544675747598148}/dist/libs/africanies-ui/types/africanies-africanies-ui.d.ts +149 -116
  22. package/.nx/cache/run.json +40 -40
  23. package/.nx/cache/terminalOutputs/{7126777490381568487 → 15149466893522345489} +10 -5
  24. package/.nx/cache/terminalOutputs/{4082520855419352840 → 15302120112746851896} +1 -1
  25. package/.nx/cache/terminalOutputs/{8648260256613557249 → 15835338512221847842} +18 -8
  26. package/.nx/cache/terminalOutputs/{9408529484792607601 → 17960163310445607219} +1 -1
  27. package/.nx/cache/terminalOutputs/{17491371155400585077 → 18393832731522001121} +2 -2
  28. package/.nx/cache/terminalOutputs/{3314955264390318442 → 5151121439688073678} +6 -6
  29. package/.nx/cache/terminalOutputs/7462873189468732296 +17 -0
  30. package/.nx/cache/terminalOutputs/8032148447904822353 +184 -182
  31. package/.nx/cache/terminalOutputs/{12276756491762927325 → 877026836685850193} +7 -7
  32. package/.nx/cache/terminalOutputs/9406544675747598148 +21 -0
  33. package/.nx/workspace-data/0091ABA9-5C90-580D-953C-8C94E763ADB5-v3.db +0 -0
  34. package/.nx/workspace-data/0091ABA9-5C90-580D-953C-8C94E763ADB5-v3.db-shm +0 -0
  35. package/.nx/workspace-data/0091ABA9-5C90-580D-953C-8C94E763ADB5-v3.db-wal +0 -0
  36. package/.nx/workspace-data/d/daemon.log +2353 -0
  37. package/.nx/workspace-data/d/server-process.json +2 -2
  38. package/.nx/workspace-data/file-map.json +1802 -1736
  39. package/.nx/workspace-data/nx_files.nxt +0 -0
  40. package/.nx/workspace-data/project-graph.json +7 -2
  41. package/apps/playground/src/app/pages/tokens-page.ts +17 -13
  42. package/apps/playground/src/app/snippets/filters.snippets.ts +10 -0
  43. package/dist/libs/africanies-icons/assets/icons.sprite.svg +7 -0
  44. package/dist/libs/africanies-icons/fesm2022/africanies-africanies-icons.mjs +1 -0
  45. package/dist/libs/africanies-icons/fesm2022/africanies-africanies-icons.mjs.map +1 -1
  46. package/dist/libs/africanies-icons/types/africanies-africanies-icons.d.ts +2 -2
  47. package/dist/libs/africanies-models/fesm2022/africanies-africanies-models.mjs +22 -8
  48. package/dist/libs/africanies-models/fesm2022/africanies-africanies-models.mjs.map +1 -1
  49. package/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs +22 -10
  50. package/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs.map +1 -1
  51. package/dist/libs/africanies-theme/tailwind-preset.cjs +84 -16
  52. package/dist/libs/africanies-theme/types/africanies-africanies-theme.d.ts +4 -2
  53. package/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs +555 -425
  54. package/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs.map +1 -1
  55. package/dist/libs/africanies-ui/types/africanies-africanies-ui.d.ts +140 -110
  56. package/libs/africanies-icons/src/assets/icons.sprite.svg +7 -0
  57. package/libs/africanies-icons/src/lib/icon-name.ts +1 -0
  58. package/libs/africanies-models/src/lib/filters/configs/seed-configs.ts +22 -8
  59. package/libs/africanies-theme/src/lib/mode-color.safelist.ts +12 -0
  60. package/libs/africanies-theme/src/lib/mode-color.service.spec.ts +55 -0
  61. package/libs/africanies-theme/src/lib/mode-color.service.ts +11 -11
  62. package/libs/africanies-theme/tailwind-preset.cjs +84 -16
  63. package/libs/africanies-ui/src/lib/action-menu/action-menu.component.ts +3 -3
  64. package/libs/africanies-ui/src/lib/alert/alert.component.ts +4 -4
  65. package/libs/africanies-ui/src/lib/avatar/avatar-menu.component.ts +2 -2
  66. package/libs/africanies-ui/src/lib/button/button.component.spec.ts +7 -7
  67. package/libs/africanies-ui/src/lib/button/button.component.ts +5 -5
  68. package/libs/africanies-ui/src/lib/chip/chip.component.ts +4 -4
  69. package/libs/africanies-ui/src/lib/content-stack/content-stack.component.ts +1 -1
  70. package/libs/africanies-ui/src/lib/feedback/error-indicator.component.ts +3 -3
  71. package/libs/africanies-ui/src/lib/feedback/error-state.component.ts +2 -2
  72. package/libs/africanies-ui/src/lib/filters/filter-drawer.panel.ts +44 -27
  73. package/libs/africanies-ui/src/lib/forms/checkbox/checkbox.component.ts +2 -1
  74. package/libs/africanies-ui/src/lib/forms/file-upload/file-preview.dialog.ts +1 -1
  75. package/libs/africanies-ui/src/lib/forms/file-upload/file-upload.component.ts +1 -1
  76. package/libs/africanies-ui/src/lib/forms/form-field.classes.ts +36 -6
  77. package/libs/africanies-ui/src/lib/forms/otp-input/otp-input.component.ts +2 -1
  78. package/libs/africanies-ui/src/lib/forms/radio/radio.component.ts +2 -1
  79. package/libs/africanies-ui/src/lib/forms/select/select.component.ts +1 -1
  80. package/libs/africanies-ui/src/lib/forms/toggle/toggle.component.ts +1 -1
  81. package/libs/africanies-ui/src/lib/image/image.component.ts +1 -1
  82. package/libs/africanies-ui/src/lib/info-popover/info-popover.component.ts +2 -2
  83. package/libs/africanies-ui/src/lib/layout/app-shell-content-header.component.ts +1 -1
  84. package/libs/africanies-ui/src/lib/layout/app-shell-header.component.ts +5 -5
  85. package/libs/africanies-ui/src/lib/layout/app-shell.component.html +2 -2
  86. package/libs/africanies-ui/src/lib/layout/app-shell.component.ts +3 -3
  87. package/libs/africanies-ui/src/lib/navigation/shipping-mode-switch/shipping-mode-switch.component.ts +6 -6
  88. package/libs/africanies-ui/src/lib/navigation/side-nav/africanies-side-nav.component.html +21 -13
  89. package/libs/africanies-ui/src/lib/navigation/side-nav/africanies-side-nav.component.ts +13 -7
  90. package/libs/africanies-ui/src/lib/notifications/notification-drawer.panel.ts +6 -6
  91. package/libs/africanies-ui/src/lib/overlay/confirm-dialog.component.ts +2 -2
  92. package/libs/africanies-ui/src/lib/overlay/drawer.service.ts +2 -2
  93. package/libs/africanies-ui/src/lib/overlay/modal.service.ts +3 -3
  94. package/libs/africanies-ui/src/lib/overlay/overlay-frame.component.ts +1 -1
  95. package/libs/africanies-ui/src/lib/pagination/pagination.component.ts +1 -1
  96. package/libs/africanies-ui/src/lib/stepper/stepper.component.ts +7 -7
  97. package/libs/africanies-ui/src/lib/table/table-column.ts +9 -0
  98. package/libs/africanies-ui/src/lib/table/table.component.spec.ts +99 -0
  99. package/libs/africanies-ui/src/lib/table/table.component.ts +72 -30
  100. package/libs/africanies-ui/src/lib/toast/toast-item.component.ts +6 -6
  101. package/package.json +1 -1
  102. package/svg/hand-coins.svg +9 -0
  103. package/.nx/cache/12276756491762927325/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs +0 -215
  104. package/.nx/cache/12276756491762927325/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs.map +0 -1
  105. package/.nx/cache/12276756491762927325/dist/libs/africanies-theme/tailwind-preset.cjs +0 -245
  106. package/.nx/cache/12276756491762927325/dist/libs/africanies-theme/types/africanies-africanies-theme.d.ts +0 -157
  107. package/.nx/cache/17491371155400585077/dist/libs/africanies-core/fesm2022/africanies-africanies-core.mjs.map +0 -1
  108. package/.nx/cache/17499961385238663835/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs.map +0 -1
  109. package/.nx/cache/3314955264390318442/dist/libs/africanies-ui/README.md +0 -68
  110. package/.nx/cache/3314955264390318442/dist/libs/africanies-ui/assets/brand/africanies-logo-mini.png +0 -0
  111. package/.nx/cache/3314955264390318442/dist/libs/africanies-ui/assets/brand/africanies-logo.png +0 -0
  112. package/.nx/cache/3314955264390318442/dist/libs/africanies-ui/assets/brand/africanies-logo.svg +0 -5
  113. package/.nx/cache/3314955264390318442/dist/libs/africanies-ui/assets/carriers/dhl.svg +0 -7
  114. package/.nx/cache/3314955264390318442/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs +0 -19291
  115. package/.nx/cache/3314955264390318442/dist/libs/africanies-ui/fesm2022/africanies-africanies-ui.mjs.map +0 -1
  116. package/.nx/cache/3314955264390318442/dist/libs/africanies-ui/package.json +0 -35
  117. package/.nx/cache/3314955264390318442/dist/libs/africanies-ui/types/africanies-africanies-ui.d.ts +0 -5483
  118. package/.nx/cache/4082520855419352840/dist/libs/africanies-theme/README.md +0 -46
  119. package/.nx/cache/4082520855419352840/dist/libs/africanies-theme/fesm2022/africanies-africanies-theme.mjs.map +0 -1
  120. package/.nx/cache/4082520855419352840/dist/libs/africanies-theme/package.json +0 -35
  121. package/.nx/cache/terminalOutputs/17499961385238663835 +0 -21
  122. package/.nx/cache/terminalOutputs/3017748574492080228 +0 -28
  123. /package/.nx/cache/{12276756491762927325 → 15302120112746851896}/dist/libs/africanies-theme/README.md +0 -0
  124. /package/.nx/cache/{12276756491762927325 → 15302120112746851896}/dist/libs/africanies-theme/package.json +0 -0
  125. /package/.nx/cache/{17491371155400585077 → 18393832731522001121}/dist/libs/africanies-core/README.md +0 -0
  126. /package/.nx/cache/{17491371155400585077 → 18393832731522001121}/dist/libs/africanies-core/package.json +0 -0
  127. /package/.nx/cache/{17499961385238663835 → 9406544675747598148}/dist/libs/africanies-ui/README.md +0 -0
  128. /package/.nx/cache/{17499961385238663835 → 9406544675747598148}/dist/libs/africanies-ui/assets/brand/africanies-logo-mini.png +0 -0
  129. /package/.nx/cache/{17499961385238663835 → 9406544675747598148}/dist/libs/africanies-ui/assets/brand/africanies-logo.png +0 -0
  130. /package/.nx/cache/{17499961385238663835 → 9406544675747598148}/dist/libs/africanies-ui/assets/brand/africanies-logo.svg +0 -0
  131. /package/.nx/cache/{17499961385238663835 → 9406544675747598148}/dist/libs/africanies-ui/assets/carriers/dhl.svg +0 -0
  132. /package/.nx/cache/{17499961385238663835 → 9406544675747598148}/dist/libs/africanies-ui/package.json +0 -0
  133. /package/.nx/cache/terminalOutputs/{16279119293212733518 → 14005735098959303198} +0 -0
@@ -35,8 +35,8 @@ import { ButtonComponent } from '../button/button.component';
35
35
  class="flex flex-col items-center justify-center gap-3 py-10 px-4 text-center text-ink dark:text-white"
36
36
  role="alert"
37
37
  >
38
- <africanies-icon name="warning" [size]="32" class="text-danger" />
39
- <p class="m-0 text-body text-danger max-w-md">{{ message() }}</p>
38
+ <africanies-icon name="warning" [size]="32" class="text-danger-dark dark:text-danger" />
39
+ <p class="m-0 text-body text-danger-dark max-w-md dark:text-danger">{{ message() }}</p>
40
40
  <button
41
41
  africanies-button
42
42
  type="button"
@@ -26,10 +26,6 @@ import {
26
26
 
27
27
  import { ButtonComponent } from '../button/button.component';
28
28
  import { DatePickerComponent } from '../forms/date-picker/date-picker.component';
29
- import {
30
- RadioComponent,
31
- type RadioOption,
32
- } from '../forms/radio/radio.component';
33
29
  import { SelectComponent } from '../forms/select/select.component';
34
30
  import type { SelectOption } from '../forms/select/select.types';
35
31
  import { TextInputComponent } from '../forms/text-input/text-input.component';
@@ -62,7 +58,6 @@ import { FilterQueryService } from './filter-query.service';
62
58
  AfricaniesIconComponent,
63
59
  ButtonComponent,
64
60
  DatePickerComponent,
65
- RadioComponent,
66
61
  SelectComponent,
67
62
  TextInputComponent,
68
63
  ],
@@ -220,12 +215,37 @@ import { FilterQueryService } from './filter-query.service';
220
215
  </div>
221
216
  }
222
217
  @case ('boolean') {
223
- <africanies-radio
224
- label=""
225
- [options]="toRadioOptions(field.options)"
226
- [value]="draft().values[field.key] ?? null"
227
- (valueChange)="onRadioChange(field.key, $event)"
228
- />
218
+ <div class="flex flex-wrap gap-2">
219
+ @for (opt of booleanOptions(field); track opt.value) {
220
+ <button
221
+ type="button"
222
+ class="cursor-pointer rounded-md border px-2.5 py-1.5 text-body-sm transition-colors"
223
+ [style.color]="
224
+ draft().values[field.key] === opt.value
225
+ ? opt.color ?? null
226
+ : null
227
+ "
228
+ [style.border-color]="
229
+ draft().values[field.key] === opt.value
230
+ ? opt.color ?? null
231
+ : null
232
+ "
233
+ [style.background-color]="
234
+ draft().values[field.key] === opt.value && opt.color
235
+ ? opt.color + '1A'
236
+ : null
237
+ "
238
+ [class]="
239
+ draft().values[field.key] === opt.value
240
+ ? 'font-medium'
241
+ : 'border-neutral-300 text-neutral-600 hover:border-neutral-400 dark:border-white/15 dark:text-neutral-300'
242
+ "
243
+ (click)="setFieldValue(field.key, opt.value)"
244
+ >
245
+ {{ opt.label }}
246
+ </button>
247
+ }
248
+ </div>
229
249
  }
230
250
  @case ('select') {
231
251
  <!-- Label already shown in the section header — avoid double label. -->
@@ -284,7 +304,7 @@ import { FilterQueryService } from './filter-query.service';
284
304
  type="button"
285
305
  variant="ghost"
286
306
  size="sm"
287
- class="shrink-0 !min-h-0 self-start !px-1 !py-0 text-neutral-500 hover:text-ink dark:text-neutral-400 dark:hover:text-white"
307
+ class="shrink-0 !min-h-0 self-start !px-1 !py-0 text-neutral-600 hover:text-ink dark:text-neutral-400 dark:hover:text-white"
288
308
  aria-label="Dismiss"
289
309
  (click)="applyError.set(null)"
290
310
  >
@@ -507,14 +527,6 @@ export class FilterDrawerPanel {
507
527
  this.draft.update((s) => ({ ...s, order: opt?.value }));
508
528
  }
509
529
 
510
- protected onRadioChange(key: string, value: string | null): void {
511
- if (value == null) {
512
- this.clearField(key);
513
- return;
514
- }
515
- this.setFieldValue(key, value);
516
- }
517
-
518
530
  protected onSelectChange(
519
531
  key: string,
520
532
  selected: SelectOption<string> | SelectOption<string>[] | null,
@@ -678,13 +690,18 @@ export class FilterDrawerPanel {
678
690
  );
679
691
  }
680
692
 
681
- protected toRadioOptions(
682
- options: FilterOptionModel[] | undefined,
683
- ): RadioOption<string>[] {
684
- return (options ?? []).map((o) => ({
685
- label: o.label,
686
- value: o.value,
687
- }));
693
+ /**
694
+ * Boolean Yes/No chips. Prefer field.options when present; otherwise default
695
+ * colored Yes/No so every boolean filter stays visually distinct.
696
+ */
697
+ protected booleanOptions(field: FilterFieldModel): FilterOptionModel[] {
698
+ if (field.options?.length) {
699
+ return field.options;
700
+ }
701
+ return [
702
+ { value: '1', label: 'Yes', color: '#25945c' },
703
+ { value: '0', label: 'No', color: '#FF001C' },
704
+ ];
688
705
  }
689
706
 
690
707
  protected onReset(): void {
@@ -19,6 +19,7 @@ import { ModeColorService } from '@africanies/africanies-theme';
19
19
 
20
20
  import {
21
21
  FORM_ERROR_CLASS,
22
+ FORM_FOCUS_VISIBLE_PEER_CLASS,
22
23
  FORM_HINT_CLASS,
23
24
  } from '../form-field.classes';
24
25
 
@@ -132,7 +133,7 @@ export class CheckboxComponent implements ControlValueAccessor {
132
133
  protected readonly markClass = computed(() => {
133
134
  const base =
134
135
  'pointer-events-none flex size-4 items-center justify-center rounded border text-white transition-colors ' +
135
- 'peer-focus-visible:outline peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-ink';
136
+ FORM_FOCUS_VISIBLE_PEER_CLASS;
136
137
  const err = this.error() ? ' !border-danger dark:!border-danger' : '';
137
138
  if (this.value()) {
138
139
  const c = this.modeColor.classes();
@@ -83,7 +83,7 @@ type PreviewKind = 'image' | 'unavailable';
83
83
  <div
84
84
  class="flex flex-col items-center gap-3 rounded-md bg-background-welcome px-6 py-10 text-center ring-1 ring-border dark:bg-white/5 dark:ring-white/15"
85
85
  >
86
- <africanies-icon name="eye-slash" [size]="32" class="text-neutral-500" />
86
+ <africanies-icon name="eye-slash" [size]="32" class="text-neutral-600" />
87
87
  <p class="m-0 text-body font-medium text-ink dark:text-white">
88
88
  Preview not available
89
89
  </p>
@@ -341,7 +341,7 @@ let nextFileUploadId = 0;
341
341
  <span> · </span>
342
342
  <button
343
343
  type="button"
344
- class="cursor-pointer bg-transparent p-0 text-caption font-medium text-ink underline underline-offset-2 hover:text-neutral-700 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink dark:text-white dark:hover:text-neutral-200"
344
+ class="cursor-pointer bg-transparent p-0 text-caption font-medium text-ink underline underline-offset-2 hover:text-neutral-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ink dark:text-white dark:hover:text-neutral-200"
345
345
  (click)="openPreview(item); $event.stopPropagation()"
346
346
  >
347
347
  View
@@ -6,29 +6,59 @@
6
6
  * when consumers scan the published UI bundle.
7
7
  */
8
8
 
9
+ /**
10
+ * Inset focus ring — stays inside the control border box.
11
+ *
12
+ * Prefer this over `outline` + `outline-offset`. Those paint *outside* the box
13
+ * and are clipped by `overflow: hidden|clip|auto` ancestors (modals, drawers,
14
+ * steppers, scroll panes). `box-sizing` does not affect outlines.
15
+ */
16
+ export const FORM_FOCUS_WITHIN_CLASS =
17
+ 'focus-within:outline-none focus-within:ring-2 focus-within:ring-inset focus-within:ring-focus';
18
+
19
+ /** Same inset ring for host / button-style focus-visible. */
20
+ export const FORM_FOCUS_VISIBLE_CLASS =
21
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus';
22
+
23
+ /** Peer-driven inset ring (checkbox / radio control chrome). */
24
+ export const FORM_FOCUS_VISIBLE_PEER_CLASS =
25
+ 'peer-focus-visible:outline-none peer-focus-visible:ring-2 peer-focus-visible:ring-inset peer-focus-visible:ring-focus';
26
+
27
+ /** Direct focus (OTP cells and similar). */
28
+ export const FORM_FOCUS_CLASS =
29
+ 'focus:outline-none focus:ring-2 focus:ring-inset focus:ring-focus';
30
+
9
31
  /** Label above the control. Hidden when empty so callers can omit a label. */
10
32
  export const FORM_LABEL_CLASS =
11
33
  'block text-body-sm font-medium text-ink dark:text-white mb-1.5 empty:hidden';
12
34
 
13
- /** Default control shell — `h-10` matches md `africanies-button`. */
35
+ /**
36
+ * Default control shell — `h-10` matches md `africanies-button`.
37
+ *
38
+ * Focus utilities are inlined (not concatenated) so Tailwind content scanning
39
+ * always sees the full class names in this string literal.
40
+ */
14
41
  export const FORM_FIELD_CLASS =
15
- 'flex items-center w-full h-10 box-border rounded-md border border-border bg-white dark:bg-ink-950 text-ink dark:text-white dark:border-white/25 ' +
16
- 'focus-within:outline focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-ink';
42
+ 'flex items-center w-full h-10 box-border rounded-control border border-control bg-surface dark:bg-ink-950 text-ink dark:text-white dark:border-white/25 ' +
43
+ 'focus-within:outline-none focus-within:ring-2 focus-within:ring-inset focus-within:ring-focus';
17
44
 
18
45
  /**
19
46
  * Error border — `!` so it wins over shell `border-border` /
20
47
  * `dark:border-white/25` (same specificity; those utilities sort later in the
21
48
  * generated CSS and otherwise paint over `border-danger`).
22
49
  *
50
+ * Use `danger` (`#ff001c`) for both border and focus ring so field chrome
51
+ * matches validation copy (not the darker accessible `danger-dark` text token).
52
+ *
23
53
  * Keep these literals static for Tailwind content scanning in consumer apps.
24
54
  */
25
55
  export const FORM_FIELD_ERROR_CLASS =
26
- '!border-danger dark:!border-danger focus-within:!outline-danger';
56
+ '!border-danger dark:!border-danger focus-within:!ring-danger focus:!ring-danger';
27
57
 
28
58
  /** Native input / textarea inside a shell. */
29
59
  export const FORM_CONTROL_INNER_CLASS =
30
60
  'flex-1 min-w-0 min-h-0 h-full w-full bg-transparent border-0 outline-none text-body text-ink dark:text-white px-3 py-0 ' +
31
- 'placeholder:text-neutral-400 disabled:cursor-not-allowed';
61
+ 'placeholder:text-neutral-500 disabled:cursor-not-allowed';
32
62
 
33
63
  /** Prefix / suffix projection gutters. Hidden when nothing is projected. */
34
64
  export const FORM_AFFIX_CLASS =
@@ -50,7 +80,7 @@ export const FORM_DATE_INNER_CLASS =
50
80
  export const FORM_HINT_CLASS =
51
81
  'mt-1.5 text-caption text-neutral-600 dark:text-neutral-400 m-0';
52
82
 
53
- /** Field-level validation message (not ErrorStateComponent). */
83
+ /** Field-level validation message (not ErrorStateComponent). Matches `#ff001c`. */
54
84
  export const FORM_ERROR_CLASS = 'mt-1.5 text-caption text-danger m-0';
55
85
 
56
86
  /** Disabled shell — dimmed with not-allowed cursor over the full field chrome. */
@@ -24,6 +24,7 @@ import { ButtonComponent } from '../../button/button.component';
24
24
  import {
25
25
  FORM_ERROR_CLASS,
26
26
  FORM_FIELD_ERROR_CLASS,
27
+ FORM_FOCUS_CLASS,
27
28
  FORM_HINT_CLASS,
28
29
  FORM_LABEL_CLASS,
29
30
  } from '../form-field.classes';
@@ -165,7 +166,7 @@ export class OtpInputComponent implements ControlValueAccessor, OnDestroy {
165
166
  let classes =
166
167
  'size-10 shrink-0 rounded-md border border-neutral-300 bg-white text-center text-body font-medium text-ink outline-none transition-colors ' +
167
168
  'dark:border-white/25 dark:bg-ink-950 dark:text-white ' +
168
- 'focus:outline focus:outline-2 focus:outline-offset-2 focus:outline-ink disabled:cursor-not-allowed';
169
+ `${FORM_FOCUS_CLASS} disabled:cursor-not-allowed`;
169
170
  if (this.masked()) {
170
171
  classes += ' africanies-otp-cell-masked text-body-lg';
171
172
  }
@@ -18,6 +18,7 @@ import { ModeColorService } from '@africanies/africanies-theme';
18
18
 
19
19
  import {
20
20
  FORM_ERROR_CLASS,
21
+ FORM_FOCUS_VISIBLE_PEER_CLASS,
21
22
  FORM_HINT_CLASS,
22
23
  FORM_LABEL_CLASS,
23
24
  } from '../form-field.classes';
@@ -178,7 +179,7 @@ export class RadioComponent<T = string> implements ControlValueAccessor {
178
179
  protected markClass(opt: RadioOption<T>): string {
179
180
  const base =
180
181
  'pointer-events-none flex size-4 items-center justify-center rounded-full border-2 bg-transparent transition-colors ' +
181
- 'peer-focus-visible:outline peer-focus-visible:outline-2 peer-focus-visible:outline-offset-2 peer-focus-visible:outline-ink';
182
+ FORM_FOCUS_VISIBLE_PEER_CLASS;
182
183
  const err = this.error() ? ' !border-danger dark:!border-danger' : '';
183
184
  if (this.isSelected(opt)) {
184
185
  // Ring uses mode accent; fill stays transparent so the center dot reads clearly.
@@ -305,7 +305,7 @@ const SELECT_PANEL_POSITIONS: ConnectedPosition[] = [
305
305
  <input
306
306
  #searchInput
307
307
  type="search"
308
- class="w-full rounded-md border border-neutral-300 dark:border-white/25 bg-transparent text-body text-ink dark:text-white px-2.5 py-1.5 outline-none focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink"
308
+ class="w-full rounded-md border border-neutral-300 dark:border-white/25 bg-transparent text-body text-ink dark:text-white px-2.5 py-1.5 outline-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ink"
309
309
  [value]="searchQuery()"
310
310
  placeholder="Search…"
311
311
  (input)="onSearchInput($event)"
@@ -71,7 +71,7 @@ let nextToggleId = 0;
71
71
  [id]="controlId"
72
72
  type="button"
73
73
  role="switch"
74
- class="relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-border p-0.5 box-border transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink dark:border-white/15"
74
+ class="relative inline-flex h-5 w-9 shrink-0 items-center rounded-full border border-border p-0.5 box-border transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-ink dark:border-white/15"
75
75
  [ngClass]="trackClass()"
76
76
  [attr.aria-checked]="on()"
77
77
  [attr.aria-busy]="loading() ? true : null"
@@ -70,7 +70,7 @@ export type ImageFit = 'cover' | 'contain';
70
70
 
71
71
  @if (showPlaceholder()) {
72
72
  <div
73
- class="absolute inset-0 flex items-center justify-center bg-neutral-200 text-neutral-500 dark:bg-white/10 dark:text-neutral-400"
73
+ class="absolute inset-0 flex items-center justify-center bg-neutral-200 text-neutral-600 dark:bg-white/10 dark:text-neutral-400"
74
74
  [class.animate-pulse]="pending()"
75
75
  aria-hidden="true"
76
76
  >
@@ -245,9 +245,9 @@ export class InfoPopoverComponent {
245
245
  */
246
246
  protected readonly panelArrowClass = computed(() => {
247
247
  const card =
248
- 'relative z-10 w-max max-w-xs rounded-lg border border-border bg-white px-4 py-3 text-ink shadow-lg dark:border-white/15 dark:bg-ink-950 dark:text-white';
248
+ 'relative z-10 w-max max-w-xs rounded-panel border border-border bg-surface px-4 py-3 text-ink shadow-floating dark:border-white/15 dark:bg-ink-950 dark:text-white';
249
249
  const base =
250
- "before:pointer-events-none before:absolute before:z-0 before:h-2.5 before:w-2.5 before:rotate-45 before:border before:border-border before:bg-white before:content-[''] dark:before:border-white/15 dark:before:bg-ink-950";
250
+ "before:pointer-events-none before:absolute before:z-0 before:h-2.5 before:w-2.5 before:rotate-45 before:border before:border-border before:bg-surface before:content-[''] dark:before:border-white/15 dark:before:bg-ink-950";
251
251
  switch (this.placement()) {
252
252
  case 'bottom':
253
253
  return `${card} ${base} before:left-1/2 before:top-0 before:-translate-x-1/2 before:-translate-y-1/2 before:border-b-0 before:border-r-0`;
@@ -39,7 +39,7 @@ import { PageHeaderComponent } from './page-header.component';
39
39
  <div class="flex min-w-0 items-center gap-2 sm:gap-3">
40
40
  @if (showBackButton()) {
41
41
  <a
42
- class="inline-flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-lg text-neutral-600 transition-colors hover:bg-background-welcome hover:text-ink focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink dark:text-neutral-400 dark:hover:bg-white/10 dark:hover:text-white"
42
+ class="inline-flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-lg text-neutral-600 transition-colors hover:bg-background-hover hover:text-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus dark:text-neutral-400 dark:hover:bg-white/10 dark:hover:text-white"
43
43
  [attr.aria-label]="backLabel()"
44
44
  [routerLink]="backTarget()!.routerLink"
45
45
  [queryParams]="backTarget()!.queryParams"
@@ -81,7 +81,7 @@ export class AppShellHeaderEndDirective {}
81
81
  @if (greeting(); as hello) {
82
82
  <div class="min-w-0 overflow-hidden">
83
83
  <p
84
- class="m-0 truncate text-caption leading-none text-neutral-500 dark:text-neutral-400"
84
+ class="m-0 truncate text-caption leading-none text-neutral-600 dark:text-neutral-400"
85
85
  >
86
86
  {{ hello.kicker }}
87
87
  </p>
@@ -107,7 +107,7 @@ export class AppShellHeaderEndDirective {}
107
107
  <africanies-icon
108
108
  [name]="weatherIcon()"
109
109
  [size]="18"
110
- class="text-neutral-500 dark:text-neutral-400"
110
+ class="text-neutral-600 dark:text-neutral-400"
111
111
  />
112
112
  @if (weatherTemp(); as temp) {
113
113
  <span
@@ -117,7 +117,7 @@ export class AppShellHeaderEndDirective {}
117
117
  </span>
118
118
  }
119
119
  <span
120
- class="hidden text-caption text-neutral-500 md:inline dark:text-neutral-400"
120
+ class="hidden text-caption text-neutral-600 md:inline dark:text-neutral-400"
121
121
  >
122
122
  {{ weatherPlace() }}
123
123
  </span>
@@ -127,7 +127,7 @@ export class AppShellHeaderEndDirective {}
127
127
  @if (showClock()) {
128
128
  <div class="flex items-baseline gap-2" aria-live="polite">
129
129
  <time
130
- class="hidden text-caption text-neutral-500 md:inline dark:text-neutral-400"
130
+ class="hidden text-caption text-neutral-600 md:inline dark:text-neutral-400"
131
131
  [dateTime]="nowIso()"
132
132
  >
133
133
  {{ now() | date: clockDateFormat() }}
@@ -157,7 +157,7 @@ export class AppShellHeaderEndDirective {}
157
157
  @if (showNotifications()) {
158
158
  <button
159
159
  type="button"
160
- class="relative inline-flex size-9 cursor-pointer items-center justify-center rounded-lg text-neutral-600 transition-colors hover:bg-background-welcome hover:text-ink focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink dark:text-neutral-400 dark:hover:bg-white/10 dark:hover:text-white"
160
+ class="relative inline-flex size-9 cursor-pointer items-center justify-center rounded-lg text-neutral-600 transition-colors hover:bg-background-hover hover:text-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus dark:text-neutral-400 dark:hover:bg-white/10 dark:hover:text-white"
161
161
  [attr.aria-label]="notificationAriaLabel()"
162
162
  (click)="openNotifications()"
163
163
  >
@@ -21,7 +21,7 @@
21
21
  >
22
22
  <button
23
23
  type="button"
24
- class="inline-flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-lg border border-border text-ink transition-colors hover:bg-background-welcome dark:border-white/15 dark:text-white dark:hover:bg-white/10"
24
+ class="inline-flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-lg border border-control text-ink transition-colors hover:bg-background-hover dark:border-white/15 dark:text-white dark:hover:bg-white/10"
25
25
  [attr.aria-label]="mobileNavOpen() ? 'Close navigation' : 'Open navigation'"
26
26
  [attr.aria-expanded]="mobileNavOpen()"
27
27
  (click)="toggleMobileNav()"
@@ -37,7 +37,7 @@
37
37
  }
38
38
 
39
39
  <div
40
- class="sticky top-0 z-30 border-b border-border bg-white/90 backdrop-blur-md dark:border-white/10 dark:bg-ink-950/90"
40
+ class="sticky top-0 z-30 border-b border-border bg-surface/90 backdrop-blur-md dark:border-white/10 dark:bg-ink-950/90"
41
41
  >
42
42
  @if (hasCustomHeader()) {
43
43
  <ng-content select="[africaniesAppShellHeader]" />
@@ -229,16 +229,16 @@ export class AppShellComponent {
229
229
  // Preview embeds: absolute/h-full so the drawer stays inside the frame.
230
230
  // Production: h-dvh so the rail fills the viewport (h-full only matches parent).
231
231
  if (preview === 'desktop') {
232
- return 'z-50 shrink-0 self-start sticky top-0 block h-full';
232
+ return 'z-50 shrink-0 self-start sticky top-0 block h-full min-h-0';
233
233
  }
234
234
 
235
235
  if (preview === 'mobile' || preview === 'tablet') {
236
236
  return open
237
- ? 'z-50 shrink-0 self-start absolute inset-y-0 left-0 h-full shadow-xl'
237
+ ? 'z-50 shrink-0 self-start absolute inset-y-0 left-0 h-full min-h-0 shadow-xl'
238
238
  : 'hidden';
239
239
  }
240
240
 
241
- const base = 'z-50 shrink-0 self-start h-dvh';
241
+ const base = 'z-50 shrink-0 self-start h-dvh min-h-0';
242
242
  if (open) {
243
243
  return `${base} fixed inset-y-0 left-0 shadow-xl lg:sticky lg:top-0 lg:block`;
244
244
  }
@@ -131,8 +131,8 @@ export class ShippingModeSwitchComponent {
131
131
  /** Host padding / divider — tighter when the rail is collapsed. */
132
132
  protected readonly hostClass = computed(() =>
133
133
  this.collapsed()
134
- ? 'block shrink-0 border-t border-strong px-1.5 py-3 dark:border-white/10'
135
- : 'block shrink-0 border-t border-strong px-2 py-3 dark:border-white/10',
134
+ ? 'block shrink-0 border-t border-border px-1.5 py-3 dark:border-white/10'
135
+ : 'block shrink-0 border-t border-border px-2 py-3 dark:border-white/10',
136
136
  );
137
137
 
138
138
  /**
@@ -159,18 +159,18 @@ export class ShippingModeSwitchComponent {
159
159
  const compact = this.collapsed();
160
160
  const base =
161
161
  'flex w-full cursor-pointer flex-col items-center justify-center gap-1 rounded-lg border text-center text-caption font-medium transition-colors ' +
162
- 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink ' +
162
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus ' +
163
163
  (compact ? 'min-h-9 px-1 py-1.5' : 'min-h-[4.5rem] px-1.5 py-2');
164
164
  const idle =
165
- 'border-border bg-white text-ink hover:bg-background-welcome dark:border-white/15 dark:bg-ink-950 dark:text-white dark:hover:bg-white/10';
165
+ 'border-control bg-surface text-ink hover:bg-background-hover dark:border-white/15 dark:bg-ink-950 dark:text-white dark:hover:bg-white/10';
166
166
 
167
167
  if (option === 'stn') {
168
168
  return selected
169
- ? `${base} border-import bg-import text-white`
169
+ ? `${base} border-import-strong bg-import-strong text-white dark:border-import dark:bg-import`
170
170
  : `${base} ${idle}`;
171
171
  }
172
172
  return selected
173
- ? `${base} border-export bg-export text-white`
173
+ ? `${base} border-export-strong bg-export-strong text-white dark:border-export dark:bg-export`
174
174
  : `${base} ${idle}`;
175
175
  }
176
176
  }
@@ -1,5 +1,5 @@
1
1
  <aside
2
- class="relative flex h-full flex-col overflow-visible border-r border-border bg-white transition-[width] duration-200 ease-out dark:border-white/10 dark:bg-ink-950"
2
+ class="relative flex h-full min-h-0 flex-col overflow-visible border-r border-border bg-surface transition-[width] duration-200 ease-out dark:border-white/10 dark:bg-ink-950"
3
3
  [style.width]="collapsed() ? '3.75rem' : '15rem'"
4
4
  [attr.aria-label]="ariaLabel()"
5
5
  >
@@ -10,7 +10,7 @@
10
10
  ></div>
11
11
 
12
12
  <div
13
- class="flex shrink-0 items-center gap-2 border-b border-border py-3 dark:border-white/10"
13
+ class="sticky top-0 z-20 flex shrink-0 items-center gap-2 border-b border-border bg-surface py-3 dark:border-white/10 dark:bg-ink-950"
14
14
  [class.flex-col]="collapsed()"
15
15
  [class.px-3]="collapsed()"
16
16
  [class.pl-4]="!collapsed()"
@@ -43,7 +43,8 @@
43
43
  }
44
44
  <button
45
45
  type="button"
46
- class="inline-flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md text-neutral-600 transition-colors hover:bg-background-welcome hover:text-ink focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink dark:text-neutral-400 dark:hover:bg-white/10 dark:hover:text-white"
46
+ class="inline-flex size-8 shrink-0 cursor-pointer items-center justify-center rounded-md text-neutral-600 transition-colors hover:bg-background-hover hover:text-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus dark:text-neutral-400 dark:hover:bg-white/10 dark:hover:text-white"
47
+ data-onboarding="nav-collapse"
47
48
  [attr.aria-label]="
48
49
  collapsed() ? 'Expand navigation' : 'Collapse navigation'
49
50
  "
@@ -57,21 +58,28 @@
57
58
  </button>
58
59
  </div>
59
60
 
60
- <nav class="africanies-overlay-scroll relative flex-1 overflow-y-auto overflow-x-visible px-3 py-3">
61
+ <nav
62
+ class="africanies-overlay-scroll relative min-h-0 flex-1 overflow-y-auto overflow-x-visible px-3 py-3"
63
+ >
61
64
  @if (!collapsed() && expandParents() && hasOpenBranches()) {
62
- <button
63
- type="button"
64
- class="absolute right-1.5 top-1.5 z-10 inline-flex size-7 cursor-pointer items-center justify-center rounded-md bg-white text-neutral-500 shadow-sm ring-1 ring-border/80 transition-colors hover:bg-background-welcome hover:text-ink focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink dark:bg-ink-950 dark:text-neutral-400 dark:ring-white/15 dark:hover:bg-white/10 dark:hover:text-white"
65
- aria-label="Collapse all"
66
- (click)="collapseAllBranches()"
67
- >
68
- <africanies-icon name="compress" [size]="14" />
69
- </button>
65
+ <!-- Zero-height sticky host: keeps the control pinned without reserving a row. -->
66
+ <div class="sticky top-0 z-10 h-0 overflow-visible">
67
+ <button
68
+ type="button"
69
+ class="absolute right-0 top-0 inline-flex size-7 cursor-pointer items-center justify-center rounded-md bg-surface text-neutral-600 shadow-sm ring-1 ring-border-strong transition-colors hover:bg-background-hover hover:text-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus dark:bg-ink-950 dark:text-neutral-400 dark:ring-white/15 dark:hover:bg-white/10 dark:hover:text-white"
70
+ data-onboarding="nav-branches-collapse"
71
+ aria-label="Collapse all"
72
+ (click)="collapseAllBranches()"
73
+ >
74
+ <africanies-icon name="compress" [size]="14" />
75
+ </button>
76
+ </div>
70
77
  }
71
78
  <ul class="m-0 flex list-none flex-col gap-0.5 p-0">
72
79
  @for (item of items(); track item.id) {
73
80
  <li
74
- class="relative overflow-visible"
81
+ class="relative overflow-visible last:mb-0"
82
+ [class.mb-3]="!collapsed() && !item.children?.length"
75
83
  (mouseenter)="onItemEnter(item.id)"
76
84
  (mouseleave)="onItemLeave(item.id)"
77
85
  >
@@ -46,7 +46,8 @@ const DEFAULT_LINK_ACTIVE: IsActiveMatchOptions = {
46
46
  * ## Parent items with children
47
47
  * **Expanded rail:** branches start open by default (`expandBranchesByDefault`).
48
48
  * Clicking a parent only opens/closes the branch (no route change). When any
49
- * branch is open, a collapse-all control sits above the list (top right).
49
+ * branch is open, a sticky collapse-all control sits above the list (top right).
50
+ * The rail expand/collapse control stays pinned in the logo header.
50
51
  * **Collapsed rail:** clicking a parent expands the rail, opens the
51
52
  * branch, and activates the first enabled child (router or `activeId`).
52
53
  *
@@ -73,7 +74,7 @@ const DEFAULT_LINK_ACTIVE: IsActiveMatchOptions = {
73
74
  changeDetection: ChangeDetectionStrategy.OnPush,
74
75
  imports: [AfricaniesIconComponent, RouterLink, NgTemplateOutlet],
75
76
  host: {
76
- class: 'relative z-20 block h-full',
77
+ class: 'relative z-20 block h-full min-h-0',
77
78
  },
78
79
  styleUrl: './africanies-side-nav.component.css',
79
80
  templateUrl: './africanies-side-nav.component.html',
@@ -197,10 +198,15 @@ export class SideNavComponent {
197
198
  }
198
199
 
199
200
  /** Fold every parent branch on the expanded rail. */
200
- protected collapseAllBranches(): void {
201
+ collapseAllBranches(): void {
201
202
  this.openBranches.set(new Set());
202
203
  }
203
204
 
205
+ /** Open every parent branch (e.g. so the collapse-all control is visible). */
206
+ expandAllBranches(): void {
207
+ this.openBranches.set(new Set(this.collectParentIds(this.items())));
208
+ }
209
+
204
210
  protected onItemEnter(id: string): void {
205
211
  if (this.collapsed()) {
206
212
  this.hoverId.set(id);
@@ -239,7 +245,7 @@ export class SideNavComponent {
239
245
  protected rowClass(item: AfricaniesSideNavItem): string {
240
246
  const base =
241
247
  'group relative flex w-full items-center gap-2 rounded-lg text-body-sm no-underline transition-colors ' +
242
- 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink ' +
248
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus ' +
243
249
  (this.collapsed() ? 'justify-center px-1.5 py-2' : 'px-3 py-2') +
244
250
  (item.disabled ? ' cursor-not-allowed opacity-50' : ' cursor-pointer');
245
251
 
@@ -256,7 +262,7 @@ export class SideNavComponent {
256
262
  return `${base} bg-transparent ${colors.text} font-semibold`;
257
263
  }
258
264
  return (
259
- `${base} font-medium text-neutral-600 hover:bg-background-welcome hover:text-ink ` +
265
+ `${base} font-medium text-neutral-600 hover:bg-background-hover hover:text-ink ` +
260
266
  'dark:text-neutral-400 dark:hover:bg-white/10 dark:hover:text-white'
261
267
  );
262
268
  }
@@ -264,14 +270,14 @@ export class SideNavComponent {
264
270
  protected childRowClass(item: AfricaniesSideNavItem): string {
265
271
  const base =
266
272
  'relative flex w-full items-center gap-2 rounded-lg px-3 py-1.5 text-body-sm no-underline transition-colors ' +
267
- 'focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ink ' +
273
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-focus ' +
268
274
  (item.disabled ? 'cursor-not-allowed opacity-50 ' : 'cursor-pointer ');
269
275
 
270
276
  if (this.isLeafActive(item)) {
271
277
  return `${base} ${this.modeColor.classes().activeFill} font-semibold`;
272
278
  }
273
279
  return (
274
- `${base} font-medium text-neutral-600 hover:bg-background-welcome hover:text-ink ` +
280
+ `${base} font-medium text-neutral-600 hover:bg-background-hover hover:text-ink ` +
275
281
  'dark:text-neutral-400 dark:hover:bg-white/10 dark:hover:text-white'
276
282
  );
277
283
  }
@@ -66,7 +66,7 @@ const MARK_ALL_CONFIRM_MS = 4000;
66
66
  {{ title() }}
67
67
  </h2>
68
68
  @if (hasUnread()) {
69
- <p class="m-0 text-caption text-neutral-500 dark:text-neutral-400">
69
+ <p class="m-0 text-caption text-neutral-600 dark:text-neutral-400">
70
70
  {{ unreadCount() }} unread
71
71
  </p>
72
72
  }
@@ -112,7 +112,7 @@ const MARK_ALL_CONFIRM_MS = 4000;
112
112
  <africanies-icon
113
113
  name="spinner"
114
114
  [size]="24"
115
- class="animate-spin text-neutral-500 dark:text-neutral-400"
115
+ class="animate-spin text-neutral-600 dark:text-neutral-400"
116
116
  />
117
117
  <p class="m-0 text-body-sm text-neutral-600 dark:text-neutral-400">
118
118
  Loading notifications…
@@ -179,7 +179,7 @@ const MARK_ALL_CONFIRM_MS = 4000;
179
179
  </h3>
180
180
  @if (item.timestamp) {
181
181
  <time
182
- class="shrink-0 whitespace-nowrap text-[11px] tabular-nums text-neutral-500 dark:text-neutral-400"
182
+ class="shrink-0 whitespace-nowrap text-[11px] tabular-nums text-neutral-600 dark:text-neutral-400"
183
183
  [dateTime]="item.timestamp"
184
184
  >
185
185
  {{ formatTimestamp(item.timestamp) }}
@@ -258,7 +258,7 @@ const MARK_ALL_CONFIRM_MS = 4000;
258
258
  >
259
259
  @if (loadingMore()) {
260
260
  <span
261
- class="inline-flex items-center gap-2 text-caption text-neutral-500 dark:text-neutral-400"
261
+ class="inline-flex items-center gap-2 text-caption text-neutral-600 dark:text-neutral-400"
262
262
  aria-live="polite"
263
263
  >
264
264
  <africanies-icon name="spinner" [size]="14" class="animate-spin" />
@@ -290,9 +290,9 @@ export class NotificationDrawerPanel {
290
290
  const base =
291
291
  'inline-flex cursor-pointer items-center gap-1 self-start text-caption font-semibold underline underline-offset-[3px] transition-colors';
292
292
  if (this.shipping.mode() === 'stn') {
293
- return `${base} text-import decoration-import/35 hover:decoration-import dark:text-import-light dark:decoration-import-light/40 dark:hover:decoration-import-light`;
293
+ return `${base} text-import-strong decoration-import-strong/35 hover:decoration-import-strong dark:text-import-light dark:decoration-import-light/40 dark:hover:decoration-import-light`;
294
294
  }
295
- return `${base} text-export decoration-export/35 hover:decoration-export dark:text-export-light dark:decoration-export-light/40 dark:hover:decoration-export-light`;
295
+ return `${base} text-export-strong decoration-export-strong/35 hover:decoration-export-strong dark:text-export-light dark:decoration-export-light/40 dark:hover:decoration-export-light`;
296
296
  });
297
297
 
298
298
  protected readonly title = computed(() => this.data.title ?? 'Notifications');