benivo-ui-library 1.9.74 → 1.9.76

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 (117) hide show
  1. package/accordion.less +167 -0
  2. package/alert.less +278 -0
  3. package/alertBanner.less +145 -0
  4. package/avatar.less +280 -0
  5. package/{lib/badge.less → badge.less} +2 -2
  6. package/{lib/benivo-ui-lib.less → benivo-ui-lib.less} +20 -0
  7. package/breadcrumbs.less +92 -0
  8. package/button.less +635 -0
  9. package/checkIcon.less +47 -0
  10. package/checkItem.less +31 -0
  11. package/copyInput.less +98 -0
  12. package/{lib/datePicker.less → datePicker.less} +59 -33
  13. package/flag.less +44 -0
  14. package/formSection.less +162 -0
  15. package/{lib/forms.less → forms.less} +21 -23
  16. package/heroInput.less +322 -0
  17. package/index.js +2 -0
  18. package/{lib/index.js.LICENSE.txt → index.js.LICENSE.txt} +1 -1
  19. package/input.less +369 -0
  20. package/notificationCard.less +202 -0
  21. package/{lib/notifications.less → notifications.less} +13 -4
  22. package/package.json +4 -2
  23. package/{lib/phoneNumber.less → phoneNumber.less} +40 -16
  24. package/progress.less +242 -0
  25. package/select.less +358 -0
  26. package/slider.less +98 -0
  27. package/starIcon.less +25 -0
  28. package/{lib/tabGroup.less → tabGroup.less} +59 -12
  29. package/tabs.less +64 -0
  30. package/tag.less +204 -0
  31. package/tagsSelect.less +183 -0
  32. package/textarea.less +73 -0
  33. package/{lib/tooltip.less → tooltip.less} +45 -20
  34. package/{lib/variables.less → variables.less} +102 -10
  35. package/verificationCode.less +142 -0
  36. package/.design-sync/NOTES.md +0 -59
  37. package/.design-sync/config.json +0 -11
  38. package/.design-sync/conventions.md +0 -71
  39. package/.prettierrc.json +0 -8
  40. package/.storybook/main.js +0 -66
  41. package/.storybook/preview-head.html +0 -11
  42. package/.storybook/preview.js +0 -18
  43. package/.vscode/extensions.json +0 -5
  44. package/.vscode/mcp.json +0 -9
  45. package/.vscode/settings.json +0 -6
  46. package/Benivo.UI.lib.csproj +0 -21
  47. package/Benivo.UI.lib.sln +0 -33
  48. package/LICENSE +0 -21
  49. package/Properties/launchSettings.json +0 -27
  50. package/jest.config.js +0 -20
  51. package/lib/README.md +0 -38
  52. package/lib/button.less +0 -645
  53. package/lib/copyInput.less +0 -62
  54. package/lib/index.js +0 -2
  55. package/lib/input.less +0 -232
  56. package/lib/package.json +0 -138
  57. package/lib/select.less +0 -161
  58. package/lib/tabs.less +0 -26
  59. package/lib/tagsSelect.less +0 -114
  60. package/lib/textarea.less +0 -65
  61. package/mocking/fileMock.js +0 -7
  62. package/mocking/mock.worker.js +0 -25
  63. package/mocking/setup.js +0 -1
  64. package/mocking/styleMock.js +0 -1
  65. package/tsconfig.json +0 -18
  66. package/webpack.config.dev.js +0 -91
  67. /package/{lib/arrowButton.less → arrowButton.less} +0 -0
  68. /package/{lib/asideSummaryCard.less → asideSummaryCard.less} +0 -0
  69. /package/{lib/asideSummaryCardSection.less → asideSummaryCardSection.less} +0 -0
  70. /package/{lib/assignmentSelectBox.less → assignmentSelectBox.less} +0 -0
  71. /package/{lib/autoComplete.less → autoComplete.less} +0 -0
  72. /package/{lib/benivoLogo.less → benivoLogo.less} +0 -0
  73. /package/{lib/buttonOld.less → buttonOld.less} +0 -0
  74. /package/{lib/checkbox.less → checkbox.less} +0 -0
  75. /package/{lib/countryFlag.less → countryFlag.less} +0 -0
  76. /package/{lib/currencyInput.less → currencyInput.less} +0 -0
  77. /package/{lib/data-table.less → data-table.less} +0 -0
  78. /package/{lib/drawer.less → drawer.less} +0 -0
  79. /package/{lib/dropdownButton.less → dropdownButton.less} +0 -0
  80. /package/{lib/expander.less → expander.less} +0 -0
  81. /package/{lib/fantasyButton.less → fantasyButton.less} +0 -0
  82. /package/{lib/featuredIcon.less → featuredIcon.less} +0 -0
  83. /package/{lib/fileTypeIcon.less → fileTypeIcon.less} +0 -0
  84. /package/{lib/folderIcon.less → folderIcon.less} +0 -0
  85. /package/{lib/frame.less → frame.less} +0 -0
  86. /package/{lib/freshDeskChat.less → freshDeskChat.less} +0 -0
  87. /package/{lib/googleTranslate.less → googleTranslate.less} +0 -0
  88. /package/{lib/image.less → image.less} +0 -0
  89. /package/{lib/infoMessageBanner.less → infoMessageBanner.less} +0 -0
  90. /package/{lib/loader.less → loader.less} +0 -0
  91. /package/{lib/main.less → main.less} +0 -0
  92. /package/{lib/miIcon.less → miIcon.less} +0 -0
  93. /package/{lib/mixins.less → mixins.less} +0 -0
  94. /package/{lib/navigation.less → navigation.less} +0 -0
  95. /package/{lib/pageHeaderIcon.less → pageHeaderIcon.less} +0 -0
  96. /package/{lib/pop-up.less → pop-up.less} +0 -0
  97. /package/{lib/radiobutton.less → radiobutton.less} +0 -0
  98. /package/{lib/sidebarMenu.less → sidebarMenu.less} +0 -0
  99. /package/{lib/spacing.less → spacing.less} +0 -0
  100. /package/{lib/spinner.less → spinner.less} +0 -0
  101. /package/{lib/splashScreen.less → splashScreen.less} +0 -0
  102. /package/{lib/status.less → status.less} +0 -0
  103. /package/{lib/swiper-a11y.less → swiper-a11y.less} +0 -0
  104. /package/{lib/swiper-effect-cube.less → swiper-effect-cube.less} +0 -0
  105. /package/{lib/swiper-effect-fade.less → swiper-effect-fade.less} +0 -0
  106. /package/{lib/swiper-effect-flip.less → swiper-effect-flip.less} +0 -0
  107. /package/{lib/swiper-lazy.less → swiper-lazy.less} +0 -0
  108. /package/{lib/swiper-navigation.less → swiper-navigation.less} +0 -0
  109. /package/{lib/swiper-pagination.less → swiper-pagination.less} +0 -0
  110. /package/{lib/swiper-scrollbar.less → swiper-scrollbar.less} +0 -0
  111. /package/{lib/swiper-thumb.less → swiper-thumb.less} +0 -0
  112. /package/{lib/swiper-zoom.less → swiper-zoom.less} +0 -0
  113. /package/{lib/swiper.less → swiper.less} +0 -0
  114. /package/{lib/table-sort.less → table-sort.less} +0 -0
  115. /package/{lib/typography-helper.less → typography-helper.less} +0 -0
  116. /package/{lib/typography.less → typography.less} +0 -0
  117. /package/{lib/withPortal.less → withPortal.less} +0 -0
package/accordion.less ADDED
@@ -0,0 +1,167 @@
1
+ //
2
+ // Accordion
3
+ //
4
+ // One row: a chevron, a title, and a panel that opens under it.
5
+ //
6
+ // padding border radius
7
+ // none — — —
8
+ // stroke 24px top 1px top —
9
+ // card 16px all 1px all 12px
10
+ //
11
+ // Only those three lines differ between the looks. Everything else — the 24px
12
+ // gap, the 18/28 title, the 16/24 body, the 8px above the panel — is shared.
13
+ //
14
+ // Figma also carries a Breakpoint property, which is not a variant here: the
15
+ // mobile frames are identical to the desktop ones apart from being narrower, so
16
+ // this reflows rather than switching on a prop.
17
+ //
18
+ //
19
+ // The group holds a set of rows and does nothing else — no border, no padding,
20
+ // no background. It only decides how far apart they sit, and that depends on the
21
+ // divider: a stroke needs clear air either side of its rule, while cards carry
22
+ // their own edges and sit closer.
23
+ //
24
+ // none 24px
25
+ // stroke 24px
26
+ // card 10px
27
+ //
28
+ // `align-items` is left alone so the rows stretch to the group's width. Figma
29
+ // says items-start with w-full on each row, which comes to the same thing without
30
+ // reaching into the children.
31
+ //
32
+ .bnv-accordion-group {
33
+ display: flex;
34
+ flex-direction: column;
35
+ gap: 1.5rem;
36
+ width: 100%;
37
+
38
+ &--card {
39
+ gap: .625rem;
40
+ }
41
+ }
42
+
43
+ .bnv-accordion {
44
+ box-sizing: border-box;
45
+ min-width: 320px;
46
+
47
+ // Structural only. The row needs to appear in a screen reader's heading list,
48
+ // but its size comes from __title, not from whichever level is used.
49
+ &__heading {
50
+ margin: 0;
51
+ font: inherit;
52
+ }
53
+
54
+ &__trigger {
55
+ display: flex;
56
+ align-items: flex-start;
57
+ gap: 1.5rem;
58
+ width: 100%;
59
+ margin: 0;
60
+ padding: 0;
61
+ border: 0;
62
+ background: none;
63
+ cursor: pointer;
64
+ text-align: left;
65
+ font-family: @font-family;
66
+
67
+ // Keyboard only, so clicking a row does not leave a ring behind. Written
68
+ // out rather than sharing the button restyle's variables, which are not on
69
+ // main yet — worth folding together once that lands.
70
+ &:focus-visible {
71
+ outline: 2px solid var(--brand-400);
72
+ outline-offset: 2px;
73
+ }
74
+ }
75
+
76
+ &__icon {
77
+ display: inline-flex;
78
+ flex-shrink: 0;
79
+ // Figma nudges the 24px chevron 2px down so it reads as centred against
80
+ // the 28px title line instead of sitting flush with its ascender.
81
+ padding-top: 2px;
82
+ color: var(--text-400);
83
+
84
+ svg {
85
+ display: block;
86
+ }
87
+ }
88
+
89
+ // --- hover -----------------------------------------------------------
90
+ //
91
+ // Guarded on a device that genuinely hovers: a touch device latches :hover
92
+ // after a tap, which would leave the last-tapped row looking permanently
93
+ // active.
94
+ //
95
+ // The hover belongs to the trigger, not the whole row — the panel is not
96
+ // clickable, so hovering the answer must not suggest that it is. For the card
97
+ // that means matching on the trigger but colouring the card, hence `:has()`
98
+ // rather than a plain `:hover` on the root.
99
+ @media (hover: hover) {
100
+ .bnv-accordion__trigger:hover .bnv-accordion__icon {
101
+ color: var(--text-600);
102
+ }
103
+
104
+ &--card:has(.bnv-accordion__trigger:hover) {
105
+ background: var(--bg-50);
106
+ }
107
+ }
108
+
109
+ &__title {
110
+ flex: 1 0 0;
111
+ min-width: 0;
112
+ color: var(--black);
113
+ font-size: 1.125rem;
114
+ line-height: 1.75rem;
115
+ font-weight: @font-weight-medium;
116
+ }
117
+
118
+ // No `display` here on purpose: the panel is hidden with the `hidden`
119
+ // attribute, and a display rule would override the browser's own
120
+ // `[hidden] { display: none }` and leave the answer on screen when closed.
121
+ &__panel {
122
+ margin-top: .5rem;
123
+ // 24px chevron + 24px gap, so the body lines up under the title rather
124
+ // than under the icon.
125
+ padding-left: 3rem;
126
+ color: var(--text-600);
127
+ font-size: 1rem;
128
+ line-height: 1.5rem;
129
+ font-weight: @font-weight-normal;
130
+ }
131
+
132
+ // --- icon position ---------------------------------------------------
133
+ // `order` rather than row-reverse: the chevron moves but the DOM does not,
134
+ // so the title stays first for anything reading the markup.
135
+ &--icon-right {
136
+ .bnv-accordion__icon { order: 1; }
137
+
138
+ .bnv-accordion__panel {
139
+ padding-left: 0;
140
+ padding-right: 3rem;
141
+ }
142
+ }
143
+
144
+ // --- dividers --------------------------------------------------------
145
+ //
146
+ // Both rules are drawn with an inset shadow rather than a border, because
147
+ // Figma puts its strokes *inside* the frame while a CSS border adds to it.
148
+ // With a border, stroke came out 1px taller than the design and card 2px
149
+ // taller AND 2px narrower — which moved where the body copy wraps, so it was
150
+ // not only a total-height rounding difference. An inset shadow occupies no
151
+ // space, which is exactly what Figma is doing.
152
+ //
153
+ // The rule sits on top of each row, so stacking rows draws the lines between
154
+ // them without needing a wrapper. The first row gets one too, which is
155
+ // Figma's.
156
+ &--stroke {
157
+ box-shadow: inset 0 1px 0 0 var(--border-200);
158
+ padding-top: 1.5rem;
159
+ }
160
+
161
+ &--card {
162
+ background: var(--white);
163
+ box-shadow: inset 0 0 0 1px var(--border-200);
164
+ border-radius: 12px;
165
+ padding: 1rem;
166
+ }
167
+ }
package/alert.less ADDED
@@ -0,0 +1,278 @@
1
+ //
2
+ // Alert
3
+ //
4
+ // Two sizes:
5
+ // floating bordered card, icon + text stacked with actions beneath
6
+ // full-width spans the viewport with a single bottom rule; title and
7
+ // supporting text sit inline and the actions move to the right
8
+ //
9
+ // Six colours. Every colour but `default` uses a tinted FeaturedIcon; `default`
10
+ // is a white, bordered container instead.
11
+ //
12
+ @alert-radius: 0.75rem; // 12px
13
+ @alert-pad: 16px;
14
+ @alert-gap: 16px;
15
+ @alert-shadow: 0 1px 1px rgba(16, 24, 40, 0.05);
16
+ @alert-icon-plain: 40px;
17
+ @alert-full-max: 1280px;
18
+
19
+ .bnv-alert {
20
+ font-family: @font-family;
21
+ background-color: var(--white);
22
+ // --border-300 arrives with the Input PR; until then this falls back to the
23
+ // identical colour under its other name, so the border is right either way.
24
+ border: 1px solid var(--border-300, var(--text-300));
25
+ color: var(--black);
26
+
27
+ &__container {
28
+ display: flex;
29
+ align-items: flex-start;
30
+ gap: @alert-gap;
31
+ position: relative;
32
+ }
33
+
34
+ // ---------- leading icon ----------
35
+ &__icon {
36
+ flex-shrink: 0;
37
+ }
38
+
39
+ // `default` has no tint: a white box with a border and the same shadow as
40
+ // the alert itself.
41
+ &__icon--plain {
42
+ display: inline-flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ box-sizing: border-box;
46
+ width: @alert-icon-plain;
47
+ height: @alert-icon-plain;
48
+ background-color: var(--white);
49
+ border: 1px solid var(--bg-200);
50
+ border-radius: 0.5rem;
51
+ box-shadow: @alert-shadow;
52
+ color: var(--text-600);
53
+
54
+ svg {
55
+ width: 20px;
56
+ height: 20px;
57
+ display: block;
58
+ }
59
+ }
60
+
61
+ // ---------- text ----------
62
+ &__content {
63
+ display: flex;
64
+ flex: 1 0 0;
65
+ min-width: 0;
66
+ flex-direction: column;
67
+ gap: 12px;
68
+ }
69
+
70
+ &__text {
71
+ display: flex;
72
+ flex-direction: column;
73
+ gap: 4px;
74
+ min-width: 0;
75
+ }
76
+
77
+ &__title,
78
+ &__supporting {
79
+ margin: 0;
80
+ font-size: @font-size;
81
+ line-height: 24px;
82
+ }
83
+
84
+ &__title {
85
+ font-weight: @font-weight-semibold;
86
+ color: var(--black);
87
+ }
88
+
89
+ &__supporting {
90
+ font-weight: @font-weight-normal;
91
+ color: var(--text-600);
92
+ }
93
+
94
+ // ---------- actions ----------
95
+ &__actions {
96
+ display: flex;
97
+ align-items: center;
98
+ gap: 12px;
99
+ flex-shrink: 0;
100
+ }
101
+
102
+ &__action {
103
+ font-family: inherit;
104
+ font-weight: @font-weight-semibold;
105
+ cursor: pointer;
106
+ border: 0;
107
+ background: none;
108
+ padding: 0;
109
+
110
+ &:focus-visible {
111
+ outline: 2px solid var(--primary);
112
+ outline-offset: 2px;
113
+ border-radius: 0.25rem;
114
+ }
115
+ }
116
+
117
+ // ---------- close ----------
118
+ &__close {
119
+ display: inline-flex;
120
+ align-items: center;
121
+ justify-content: center;
122
+ flex-shrink: 0;
123
+ width: 36px;
124
+ height: 36px;
125
+ padding: 8px;
126
+ border: 0;
127
+ background: none;
128
+ border-radius: 0.5rem;
129
+ color: var(--text-400);
130
+ cursor: pointer;
131
+
132
+ svg {
133
+ width: 20px;
134
+ height: 20px;
135
+ display: block;
136
+ }
137
+
138
+ &:hover {
139
+ background-color: var(--bg-100);
140
+ color: var(--text-600);
141
+ }
142
+
143
+ &:focus-visible {
144
+ outline: 2px solid var(--primary);
145
+ outline-offset: 2px;
146
+ }
147
+ }
148
+
149
+ // ---------- floating ----------
150
+ &--floating {
151
+ position: relative;
152
+ padding: @alert-pad;
153
+ border-radius: @alert-radius;
154
+ box-shadow: @alert-shadow;
155
+
156
+ // the close X is placed against the card, not the padded content, so
157
+ // it can sit 7px from the alert's own edge as Figma draws it
158
+ .bnv-alert__container {
159
+ position: static;
160
+ }
161
+
162
+ // the title clears the absolutely-positioned close button
163
+ .bnv-alert__text {
164
+ padding-right: 32px;
165
+ }
166
+
167
+ .bnv-alert__action {
168
+ font-size: @font-size-sm;
169
+ line-height: 20px;
170
+ }
171
+
172
+ .bnv-alert__action--secondary {
173
+ color: var(--black);
174
+ }
175
+
176
+ .bnv-alert__action--primary {
177
+ color: var(--brand-700);
178
+ }
179
+
180
+ .bnv-alert__close {
181
+ position: absolute;
182
+ top: 7px;
183
+ right: 7px;
184
+ }
185
+
186
+ @media @md-max {
187
+ .bnv-alert__container {
188
+ gap: 12px;
189
+ }
190
+ }
191
+ }
192
+
193
+ // ---------- full-width ----------
194
+ // A page-level bar: no radius, no shadow, a single rule underneath.
195
+ &--full-width {
196
+ border-width: 0 0 1px;
197
+ border-radius: 0;
198
+ box-shadow: none;
199
+
200
+ .bnv-alert__container {
201
+ align-items: center;
202
+ gap: 12px;
203
+ max-width: @alert-full-max;
204
+ margin: 0 auto;
205
+ padding: 12px 32px;
206
+ }
207
+
208
+ .bnv-alert__content {
209
+ flex-direction: row;
210
+ align-items: center;
211
+ gap: 16px;
212
+ }
213
+
214
+ // title and supporting text run inline here, wrapping as one block
215
+ .bnv-alert__text {
216
+ flex: 1 0 0;
217
+ flex-direction: row;
218
+ flex-wrap: wrap;
219
+ align-items: baseline;
220
+ gap: 2px 6px;
221
+ }
222
+
223
+ // Link actions, not buttons — a page-level bar shouldn't carry a CTA
224
+ // that competes with the page's own primary action.
225
+ .bnv-alert__action {
226
+ font-size: @font-size-sm;
227
+ line-height: 20px;
228
+ }
229
+
230
+ .bnv-alert__action--secondary {
231
+ color: var(--black);
232
+ }
233
+
234
+ .bnv-alert__action--primary {
235
+ color: var(--brand-700);
236
+ }
237
+
238
+ @media @md-max {
239
+ position: relative;
240
+
241
+ // everything stacks: the actions are a sibling of the content here,
242
+ // so it is the container that has to turn, not the content
243
+ .bnv-alert__container {
244
+ flex-direction: column;
245
+ align-items: stretch;
246
+ gap: 16px;
247
+ padding: 16px;
248
+ }
249
+
250
+ // Figma drops the leading icon on mobile — the message carries itself
251
+ .bnv-alert__icon {
252
+ display: none;
253
+ }
254
+
255
+ .bnv-alert__content {
256
+ flex-direction: column;
257
+ }
258
+
259
+ // title and supporting text stop running inline
260
+ .bnv-alert__text {
261
+ flex-direction: column;
262
+ gap: 4px;
263
+ padding-right: 32px; // clears the close X
264
+ }
265
+
266
+ // links stay inline on mobile too — there is no button to stack
267
+ .bnv-alert__actions {
268
+ gap: 12px;
269
+ }
270
+
271
+ .bnv-alert__close {
272
+ position: absolute;
273
+ top: 7px;
274
+ right: 7px;
275
+ }
276
+ }
277
+ }
278
+ }
@@ -0,0 +1,145 @@
1
+ //
2
+ // Alert banner
3
+ //
4
+ // A short inline message in a tinted pill — smaller than Alert, with no title
5
+ // and no actions. Four colours, and the text sits centred or left.
6
+ //
7
+ // Namespaced `bnv-` deliberately: MPApp and VPApp both ship a local
8
+ // `.alert-banner` class, and this LESS is global.
9
+ //
10
+ @alert-banner-radius: 0.75rem; // 12px
11
+ @alert-banner-pad-y: 8px;
12
+ @alert-banner-pad-x: 12px;
13
+ @alert-banner-gap: 8px;
14
+ @alert-banner-icon: 20px;
15
+
16
+ .bnv-alert-banner {
17
+ display: flex;
18
+ align-items: center;
19
+ gap: @alert-banner-gap;
20
+ width: 100%;
21
+ box-sizing: border-box;
22
+ padding: @alert-banner-pad-y @alert-banner-pad-x;
23
+ border-radius: @alert-banner-radius;
24
+ font-family: @font-family;
25
+
26
+ &__slot {
27
+ display: flex;
28
+ align-items: center;
29
+ justify-content: center;
30
+ flex-shrink: 0;
31
+ }
32
+
33
+ // An empty slot collapses by default, so it never indents left-aligned text.
34
+ &__slot:empty {
35
+ display: none;
36
+ }
37
+
38
+ &__icon {
39
+ display: inline-flex;
40
+ flex-shrink: 0;
41
+
42
+ svg {
43
+ width: @alert-banner-icon;
44
+ height: @alert-banner-icon;
45
+ display: block;
46
+ }
47
+ }
48
+
49
+ // The text takes the remaining width, so `align` decides where a short
50
+ // message sits rather than the flexbox packing.
51
+ &__text {
52
+ flex: 1 0 0;
53
+ min-width: 0;
54
+ margin: 0;
55
+ font-size: @font-size-sm;
56
+ line-height: 20px;
57
+ font-weight: @font-weight-semibold;
58
+ word-break: break-word;
59
+ }
60
+
61
+ // Centred text only sits true if both sides reserve the same width, so here
62
+ // the slots hold their size even when empty. Without it a lone icon drags
63
+ // the text ~14px off centre. Left-aligned text needs no such balancing.
64
+ &--center &__slot,
65
+ &--center &__slot:empty {
66
+ display: flex;
67
+ width: @alert-banner-icon;
68
+ height: @alert-banner-icon;
69
+ }
70
+
71
+ &--center &__text {
72
+ text-align: center;
73
+ }
74
+
75
+ &--left &__text {
76
+ text-align: left;
77
+ }
78
+
79
+ // The same control as the Badge's dismiss — Figma calls it "_Badge close X"
80
+ // in both components, so the hover and focus treatment matches: a 16% tint
81
+ // of whatever colour the X is already carrying.
82
+ //
83
+ // Blending keeps the resting X sitting inside the banner tint; hover and
84
+ // focus turn it off so the fill renders predictably.
85
+ &__close {
86
+ display: inline-flex;
87
+ align-items: center;
88
+ justify-content: center;
89
+ flex-shrink: 0;
90
+ padding: 2px;
91
+ border: 0;
92
+ background-color: transparent;
93
+ border-radius: 3px;
94
+ cursor: pointer;
95
+ color: inherit;
96
+ mix-blend-mode: darken;
97
+ .transition(background-color .15s ease);
98
+
99
+ svg {
100
+ width: 12px;
101
+ height: 12px;
102
+ display: block;
103
+ }
104
+
105
+ &:hover {
106
+ mix-blend-mode: normal;
107
+ background-color: color-mix(in srgb, currentColor 16%, transparent);
108
+ }
109
+
110
+ &:focus-visible {
111
+ mix-blend-mode: normal;
112
+ background-color: color-mix(in srgb, currentColor 16%, transparent);
113
+ outline: 2px solid currentColor;
114
+ outline-offset: -1px;
115
+ }
116
+ }
117
+
118
+ // ---------- colours ----------
119
+ // Tint carries the fill, and the text and icon share one colour.
120
+ &--grey {
121
+ background-color: var(--bg-100);
122
+ color: var(--text-600);
123
+ }
124
+
125
+ &--success {
126
+ background-color: var(--success-light);
127
+ color: var(--success-main);
128
+ }
129
+
130
+ &--warning {
131
+ background-color: var(--warning-light);
132
+ color: var(--warning-main);
133
+ }
134
+
135
+ &--error {
136
+ background-color: var(--error-light);
137
+ color: var(--error-main);
138
+
139
+ // The only colour whose X is not the text colour — Figma softens it to
140
+ // rose-400 so the dismiss control doesn't shout as loudly as the message.
141
+ .bnv-alert-banner__close {
142
+ color: var(--rose-400);
143
+ }
144
+ }
145
+ }