bitwrench 2.0.13 → 2.0.14

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.
@@ -45,6 +45,88 @@ export var RADIUS_PRESETS = {
45
45
  pill: { btn: '50rem', card: '1rem', badge: '50rem', alert: '1rem', input: '50rem' }
46
46
  };
47
47
 
48
+ // ---- Typography scale presets ----
49
+
50
+ export var TYPE_RATIO_PRESETS = {
51
+ tight: 1.125,
52
+ normal: 1.200,
53
+ relaxed: 1.250,
54
+ dramatic: 1.333
55
+ };
56
+
57
+ /**
58
+ * Generate a modular type scale from a base size and ratio.
59
+ * @param {number} base - Base font size in px (default 16)
60
+ * @param {number} ratio - Scale ratio (default 1.200)
61
+ * @returns {Object} { xs, sm, base, lg, xl, '2xl', '3xl', '4xl' } in px
62
+ */
63
+ export function generateTypeScale(base, ratio) {
64
+ if (!base) base = 16;
65
+ if (!ratio) ratio = 1.200;
66
+ return {
67
+ xs: Math.round(base / (ratio * ratio)),
68
+ sm: Math.round(base / ratio),
69
+ base: base,
70
+ lg: Math.round(base * ratio),
71
+ xl: Math.round(base * ratio * ratio),
72
+ '2xl': Math.round(base * Math.pow(ratio, 3)),
73
+ '3xl': Math.round(base * Math.pow(ratio, 4)),
74
+ '4xl': Math.round(base * Math.pow(ratio, 5))
75
+ };
76
+ }
77
+
78
+ // ---- Elevation (shadow depth) presets ----
79
+
80
+ export var ELEVATION_PRESETS = {
81
+ flat: {
82
+ sm: 'none',
83
+ md: 'none',
84
+ lg: 'none',
85
+ xl: 'none'
86
+ },
87
+ sm: {
88
+ sm: '0 1px 2px rgba(0,0,0,0.05)',
89
+ md: '0 1px 3px rgba(0,0,0,0.08)',
90
+ lg: '0 2px 6px rgba(0,0,0,0.10)',
91
+ xl: '0 4px 12px rgba(0,0,0,0.12)'
92
+ },
93
+ md: {
94
+ sm: '0 1px 3px rgba(0,0,0,0.08)',
95
+ md: '0 2px 6px rgba(0,0,0,0.12)',
96
+ lg: '0 4px 12px rgba(0,0,0,0.16)',
97
+ xl: '0 8px 24px rgba(0,0,0,0.20)'
98
+ },
99
+ lg: {
100
+ sm: '0 2px 4px rgba(0,0,0,0.10)',
101
+ md: '0 4px 12px rgba(0,0,0,0.16)',
102
+ lg: '0 8px 24px rgba(0,0,0,0.22)',
103
+ xl: '0 16px 48px rgba(0,0,0,0.28)'
104
+ }
105
+ };
106
+
107
+ // ---- Motion (transition) presets ----
108
+
109
+ export var MOTION_PRESETS = {
110
+ reduced: {
111
+ fast: '0ms',
112
+ normal: '0ms',
113
+ slow: '0ms',
114
+ easing: 'linear'
115
+ },
116
+ standard: {
117
+ fast: '100ms',
118
+ normal: '200ms',
119
+ slow: '300ms',
120
+ easing: 'ease-out'
121
+ },
122
+ expressive: {
123
+ fast: '150ms',
124
+ normal: '300ms',
125
+ slow: '500ms',
126
+ easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)'
127
+ }
128
+ };
129
+
48
130
  /**
49
131
  * Default palette config — matches existing hardcoded colors
50
132
  */
@@ -54,8 +136,8 @@ export var DEFAULT_PALETTE_CONFIG = {
54
136
  tertiary: '#006666',
55
137
  success: '#198754',
56
138
  danger: '#dc3545',
57
- warning: '#ffc107',
58
- info: '#0dcaf0',
139
+ warning: '#b38600',
140
+ info: '#0891b2',
59
141
  light: '#f8f9fa',
60
142
  dark: '#212529'
61
143
  };
@@ -80,18 +162,32 @@ export var THEME_PRESETS = {
80
162
  };
81
163
 
82
164
  /**
83
- * Resolve layout config to spacing + radius objects
84
- * @param {Object} config - { spacing, radius, fontSize }
85
- * @returns {Object} { spacing, radius, fontSize }
165
+ * Resolve layout config to spacing, radius, typeScale, elevation, and motion objects.
166
+ * @param {Object} config - { spacing, radius, fontSize, typeRatio, elevation, motion }
167
+ * @returns {Object} { spacing, radius, fontSize, typeScale, elevation, motion }
86
168
  */
87
169
  export function resolveLayout(config) {
88
170
  var sp = (config && config.spacing) || 'normal';
89
171
  var rd = (config && config.radius) || 'md';
90
172
  var fs = (config && config.fontSize) || 1.0;
173
+
174
+ // typeRatio: accept preset name or number
175
+ var tr = (config && config.typeRatio) || 'normal';
176
+ var ratioNum = typeof tr === 'string' ? (TYPE_RATIO_PRESETS[tr] || TYPE_RATIO_PRESETS.normal) : tr;
177
+
178
+ // elevation: accept preset name or object
179
+ var el = (config && config.elevation) || 'md';
180
+
181
+ // motion: accept preset name or object
182
+ var mo = (config && config.motion) || 'standard';
183
+
91
184
  return {
92
185
  spacing: typeof sp === 'string' ? (SPACING_PRESETS[sp] || SPACING_PRESETS.normal) : sp,
93
186
  radius: typeof rd === 'string' ? (RADIUS_PRESETS[rd] || RADIUS_PRESETS.md) : rd,
94
- fontSize: fs
187
+ fontSize: fs,
188
+ typeScale: generateTypeScale(16, ratioNum),
189
+ elevation: typeof el === 'string' ? (ELEVATION_PRESETS[el] || ELEVATION_PRESETS.md) : el,
190
+ motion: typeof mo === 'string' ? (MOTION_PRESETS[mo] || MOTION_PRESETS.standard) : mo
95
191
  };
96
192
  }
97
193
 
@@ -115,12 +211,13 @@ function scopeSelector(name, sel) {
115
211
  // Themed CSS generators
116
212
  // =========================================================================
117
213
 
118
- function generateTypographyThemed(scope, palette) {
214
+ function generateTypographyThemed(scope, palette, layout) {
215
+ var mot = layout.motion;
119
216
  var rules = {};
120
217
  rules[scopeSelector(scope, 'a')] = {
121
218
  'color': palette.primary.base,
122
219
  'text-decoration': 'none',
123
- 'transition': 'color 0.15s'
220
+ 'transition': 'color ' + mot.fast + ' ' + mot.easing
124
221
  };
125
222
  rules[scopeSelector(scope, 'a:hover')] = {
126
223
  'color': palette.primary.hover,
@@ -140,7 +237,8 @@ function generateButtons(scope, palette, layout) {
140
237
  'border-radius': rd.btn
141
238
  };
142
239
  rules[scopeSelector(scope, '.bw-btn:focus-visible')] = {
143
- 'outline': '0',
240
+ 'outline': '2px solid currentColor',
241
+ 'outline-offset': '2px',
144
242
  'box-shadow': '0 0 0 3px ' + palette.primary.focus
145
243
  };
146
244
 
@@ -230,14 +328,15 @@ function generateCards(scope, palette, layout) {
230
328
  var sp = layout.spacing;
231
329
  var rd = layout.radius;
232
330
 
331
+ var elev = layout.elevation;
233
332
  rules[scopeSelector(scope, '.bw-card')] = {
234
333
  'background-color': '#fff',
235
334
  'border': '1px solid ' + palette.light.border,
236
335
  'border-radius': rd.card,
237
- 'box-shadow': '0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04)'
336
+ 'box-shadow': elev.sm
238
337
  };
239
338
  rules[scopeSelector(scope, '.bw-card:hover')] = {
240
- 'box-shadow': '0 4px 12px rgba(0,0,0,.1), 0 2px 4px rgba(0,0,0,.06)'
339
+ 'box-shadow': elev.md
241
340
  };
242
341
  rules[scopeSelector(scope, '.bw-card-body')] = {
243
342
  'padding': sp.card
@@ -284,6 +383,8 @@ function generateForms(scope, palette, layout) {
284
383
  };
285
384
  rules[scopeSelector(scope, '.bw-form-control:focus')] = {
286
385
  'border-color': palette.primary.border,
386
+ 'outline': '2px solid ' + palette.primary.base,
387
+ 'outline-offset': '-1px',
287
388
  'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
288
389
  };
289
390
  rules[scopeSelector(scope, '.bw-form-control::placeholder')] = {
@@ -441,7 +542,8 @@ function generatePagination(scope, palette) {
441
542
  'border-color': palette.light.border
442
543
  };
443
544
  rules[scopeSelector(scope, '.bw-page-link:focus')] = {
444
- 'box-shadow': '0 0 0 0.25rem ' + palette.primary.focus
545
+ 'outline': '2px solid ' + palette.primary.base,
546
+ 'outline-offset': '-2px'
445
547
  };
446
548
  rules[scopeSelector(scope, '.bw-page-item.bw-active .bw-page-link')] = {
447
549
  'color': palette.primary.textOn,
@@ -600,12 +702,12 @@ function generateCarouselThemed(scope, palette) {
600
702
  return rules;
601
703
  }
602
704
 
603
- function generateModalThemed(scope, palette) {
705
+ function generateModalThemed(scope, palette, layout) {
604
706
  var rules = {};
605
707
  rules[scopeSelector(scope, '.bw-modal-content')] = {
606
708
  'background-color': '#fff',
607
709
  'border-color': palette.light.border,
608
- 'box-shadow': '0 0.5rem 1rem rgba(0,0,0,0.15)'
710
+ 'box-shadow': layout.elevation.lg
609
711
  };
610
712
  rules[scopeSelector(scope, '.bw-modal-header')] = {
611
713
  'border-bottom-color': palette.light.border
@@ -619,12 +721,12 @@ function generateModalThemed(scope, palette) {
619
721
  return rules;
620
722
  }
621
723
 
622
- function generateToastThemed(scope, palette) {
724
+ function generateToastThemed(scope, palette, layout) {
623
725
  var rules = {};
624
726
  rules[scopeSelector(scope, '.bw-toast')] = {
625
727
  'background-color': '#fff',
626
728
  'border-color': 'rgba(0,0,0,0.1)',
627
- 'box-shadow': '0 0.5rem 1rem rgba(0,0,0,0.15)'
729
+ 'box-shadow': layout.elevation.lg
628
730
  };
629
731
  rules[scopeSelector(scope, '.bw-toast-header')] = {
630
732
  'border-bottom-color': 'rgba(0,0,0,0.05)'
@@ -638,12 +740,12 @@ function generateToastThemed(scope, palette) {
638
740
  return rules;
639
741
  }
640
742
 
641
- function generateDropdownThemed(scope, palette) {
743
+ function generateDropdownThemed(scope, palette, layout) {
642
744
  var rules = {};
643
745
  rules[scopeSelector(scope, '.bw-dropdown-menu')] = {
644
746
  'background-color': '#fff',
645
747
  'border-color': palette.light.border,
646
- 'box-shadow': '0 0.5rem 1rem rgba(0,0,0,0.15)'
748
+ 'box-shadow': layout.elevation.md
647
749
  };
648
750
  rules[scopeSelector(scope, '.bw-dropdown-item')] = {
649
751
  'color': palette.dark.base
@@ -709,7 +811,7 @@ function generateAvatarThemed(scope, palette) {
709
811
  export function generateThemedCSS(scopeName, palette, layout) {
710
812
  return Object.assign({},
711
813
  generateResetThemed(scopeName, palette),
712
- generateTypographyThemed(scopeName, palette),
814
+ generateTypographyThemed(scopeName, palette, layout),
713
815
  generateButtons(scopeName, palette, layout),
714
816
  generateAlerts(scopeName, palette, layout),
715
817
  generateBadges(scopeName, palette),
@@ -728,9 +830,9 @@ export function generateThemedCSS(scopeName, palette, layout) {
728
830
  generateSectionsThemed(scopeName, palette),
729
831
  generateAccordionThemed(scopeName, palette),
730
832
  generateCarouselThemed(scopeName, palette),
731
- generateModalThemed(scopeName, palette),
732
- generateToastThemed(scopeName, palette),
733
- generateDropdownThemed(scopeName, palette),
833
+ generateModalThemed(scopeName, palette, layout),
834
+ generateToastThemed(scopeName, palette, layout),
835
+ generateDropdownThemed(scopeName, palette, layout),
734
836
  generateSwitchThemed(scopeName, palette),
735
837
  generateSkeletonThemed(scopeName, palette),
736
838
  generateAvatarThemed(scopeName, palette),
@@ -763,10 +865,10 @@ export const defaultStyles = {
763
865
  '--bw-pink': '#d63384',
764
866
  '--bw-red': '#dc3545',
765
867
  '--bw-orange': '#fd7e14',
766
- '--bw-yellow': '#ffc107',
868
+ '--bw-yellow': '#b38600',
767
869
  '--bw-green': '#198754',
768
870
  '--bw-teal': '#20c997',
769
- '--bw-cyan': '#0dcaf0',
871
+ '--bw-cyan': '#0891b2',
770
872
  '--bw-black': '#000',
771
873
  '--bw-white': '#fff',
772
874
  '--bw-gray': '#6c757d',
@@ -783,8 +885,8 @@ export const defaultStyles = {
783
885
  '--bw-primary': '#006666',
784
886
  '--bw-secondary': '#6c757d',
785
887
  '--bw-success': '#198754',
786
- '--bw-info': '#0dcaf0',
787
- '--bw-warning': '#ffc107',
888
+ '--bw-info': '#0891b2',
889
+ '--bw-warning': '#b38600',
788
890
  '--bw-danger': '#dc3545',
789
891
  '--bw-light': '#f8f9fa',
790
892
  '--bw-dark': '#212529',
@@ -1017,7 +1119,7 @@ export const defaultStyles = {
1017
1119
  'font-size': '0.875rem',
1018
1120
  'font-family': 'inherit',
1019
1121
  'border-radius': '6px',
1020
- 'transition': 'all 0.15s cubic-bezier(0.4, 0, 0.2, 1)',
1122
+ 'transition': 'all 0.15s ease-out',
1021
1123
  'box-shadow': '0 1px 2px rgba(0,0,0,.05)',
1022
1124
  'gap': '0.5rem'
1023
1125
  },
@@ -1031,7 +1133,8 @@ export const defaultStyles = {
1031
1133
  'box-shadow': '0 1px 2px rgba(0,0,0,.05)'
1032
1134
  },
1033
1135
  '.bw-btn:focus-visible': {
1034
- 'outline': '0',
1136
+ 'outline': '2px solid currentColor',
1137
+ 'outline-offset': '2px',
1035
1138
  'box-shadow': '0 0 0 3px rgba(0, 102, 102, 0.3)'
1036
1139
  },
1037
1140
  '.bw-btn:disabled': {
@@ -1087,8 +1190,8 @@ export const defaultStyles = {
1087
1190
 
1088
1191
  '.bw-btn-warning': {
1089
1192
  'color': '#000',
1090
- 'background-color': '#ffc107',
1091
- 'border-color': '#ffc107'
1193
+ 'background-color': '#b38600',
1194
+ 'border-color': '#b38600'
1092
1195
  },
1093
1196
  '.bw-btn-warning:hover': {
1094
1197
  'color': '#000',
@@ -1098,8 +1201,8 @@ export const defaultStyles = {
1098
1201
 
1099
1202
  '.bw-btn-info': {
1100
1203
  'color': '#000',
1101
- 'background-color': '#0dcaf0',
1102
- 'border-color': '#0dcaf0'
1204
+ 'background-color': '#0891b2',
1205
+ 'border-color': '#0891b2'
1103
1206
  },
1104
1207
  '.bw-btn-info:hover': {
1105
1208
  'color': '#000',
@@ -1175,25 +1278,25 @@ export const defaultStyles = {
1175
1278
  },
1176
1279
 
1177
1280
  '.bw-btn-outline-warning': {
1178
- 'color': '#ffc107',
1179
- 'border-color': '#ffc107',
1281
+ 'color': '#b38600',
1282
+ 'border-color': '#b38600',
1180
1283
  'background-color': 'transparent'
1181
1284
  },
1182
1285
  '.bw-btn-outline-warning:hover': {
1183
1286
  'color': '#000',
1184
- 'background-color': '#ffc107',
1185
- 'border-color': '#ffc107'
1287
+ 'background-color': '#b38600',
1288
+ 'border-color': '#b38600'
1186
1289
  },
1187
1290
 
1188
1291
  '.bw-btn-outline-info': {
1189
- 'color': '#0dcaf0',
1190
- 'border-color': '#0dcaf0',
1292
+ 'color': '#0891b2',
1293
+ 'border-color': '#0891b2',
1191
1294
  'background-color': 'transparent'
1192
1295
  },
1193
1296
  '.bw-btn-outline-info:hover': {
1194
1297
  'color': '#000',
1195
- 'background-color': '#0dcaf0',
1196
- 'border-color': '#0dcaf0'
1298
+ 'background-color': '#0891b2',
1299
+ 'border-color': '#0891b2'
1197
1300
  },
1198
1301
 
1199
1302
  '.bw-btn-outline-light': {
@@ -1247,7 +1350,7 @@ export const defaultStyles = {
1247
1350
  'border': '1px solid #e5e5e5',
1248
1351
  'border-radius': '8px',
1249
1352
  'box-shadow': '0 1px 3px rgba(0,0,0,.06), 0 1px 2px rgba(0,0,0,.04)',
1250
- 'transition': 'box-shadow 0.2s cubic-bezier(0.4,0,0.2,1), transform 0.2s cubic-bezier(0.4,0,0.2,1)',
1353
+ 'transition': 'box-shadow 0.2s ease-out, transform 0.2s ease-out',
1251
1354
  'margin-bottom': '1.5rem',
1252
1355
  'overflow': 'hidden'
1253
1356
  },
@@ -1317,14 +1420,15 @@ export const defaultStyles = {
1317
1420
  'border': '1px solid #ccc',
1318
1421
  'appearance': 'none',
1319
1422
  'border-radius': '6px',
1320
- 'transition': 'border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out',
1423
+ 'transition': 'border-color 0.15s ease-out, box-shadow 0.15s ease-out',
1321
1424
  'font-family': 'inherit'
1322
1425
  },
1323
1426
  '.bw-form-control:focus': {
1324
1427
  'color': '#1a1a1a',
1325
1428
  'background-color': '#fff',
1326
1429
  'border-color': '#80cccc',
1327
- 'outline': '0',
1430
+ 'outline': '2px solid #006666',
1431
+ 'outline-offset': '-1px',
1328
1432
  'box-shadow': '0 0 0 0.25rem rgba(0, 102, 102, 0.25)'
1329
1433
  },
1330
1434
  '.bw-form-control::placeholder': {
@@ -1356,6 +1460,33 @@ export const defaultStyles = {
1356
1460
  'textarea.bw-form-control': {
1357
1461
  'min-height': '5rem',
1358
1462
  'resize': 'vertical'
1463
+ },
1464
+ // Validation states
1465
+ '.bw-form-control.bw-is-valid': {
1466
+ 'border-color': '#198754'
1467
+ },
1468
+ '.bw-form-control.bw-is-valid:focus': {
1469
+ 'border-color': '#198754',
1470
+ 'box-shadow': '0 0 0 0.2rem rgba(25, 135, 84, 0.25)'
1471
+ },
1472
+ '.bw-form-control.bw-is-invalid': {
1473
+ 'border-color': '#dc3545'
1474
+ },
1475
+ '.bw-form-control.bw-is-invalid:focus': {
1476
+ 'border-color': '#dc3545',
1477
+ 'box-shadow': '0 0 0 0.2rem rgba(220, 53, 69, 0.25)'
1478
+ },
1479
+ '.bw-valid-feedback': {
1480
+ 'display': 'block',
1481
+ 'font-size': '0.875rem',
1482
+ 'color': '#198754',
1483
+ 'margin-top': '0.25rem'
1484
+ },
1485
+ '.bw-invalid-feedback': {
1486
+ 'display': 'block',
1487
+ 'font-size': '0.875rem',
1488
+ 'color': '#dc3545',
1489
+ 'margin-top': '0.25rem'
1359
1490
  }
1360
1491
  },
1361
1492
 
@@ -1595,8 +1726,8 @@ export const defaultStyles = {
1595
1726
  badges: {
1596
1727
  '.bw-badge': {
1597
1728
  'display': 'inline-block',
1598
- 'padding': '.4em .75em',
1599
- 'font-size': '.875em',
1729
+ 'padding': '0.375rem 0.625rem',
1730
+ 'font-size': '0.875rem',
1600
1731
  'font-weight': '600',
1601
1732
  'line-height': '1.3',
1602
1733
  'color': '#fff',
@@ -1609,12 +1740,12 @@ export const defaultStyles = {
1609
1740
  'display': 'none'
1610
1741
  },
1611
1742
  '.bw-badge-sm': {
1612
- 'font-size': '.75em',
1613
- 'padding': '.25em .5em'
1743
+ 'font-size': '0.75rem',
1744
+ 'padding': '0.25rem 0.5rem'
1614
1745
  },
1615
1746
  '.bw-badge-lg': {
1616
- 'font-size': '1em',
1617
- 'padding': '.5em .9em'
1747
+ 'font-size': '1rem',
1748
+ 'padding': '0.5rem 0.875rem'
1618
1749
  },
1619
1750
  '.bw-badge-pill': {
1620
1751
  'border-radius': '50rem'
@@ -1637,11 +1768,11 @@ export const defaultStyles = {
1637
1768
  },
1638
1769
  '.bw-badge-info': {
1639
1770
  'color': '#000',
1640
- 'background-color': '#0dcaf0'
1771
+ 'background-color': '#0891b2'
1641
1772
  },
1642
1773
  '.bw-badge-warning': {
1643
1774
  'color': '#000',
1644
- 'background-color': '#ffc107'
1775
+ 'background-color': '#b38600'
1645
1776
  },
1646
1777
  '.bw-badge-danger': {
1647
1778
  'color': '#fff',
@@ -1679,7 +1810,7 @@ export const defaultStyles = {
1679
1810
  'text-align': 'center',
1680
1811
  'white-space': 'nowrap',
1681
1812
  'background-color': '#006666',
1682
- 'transition': 'width .6s ease',
1813
+ 'transition': 'width 0.3s ease-out',
1683
1814
  'box-shadow': 'inset 0 -1px 0 rgba(0,0,0,.15)',
1684
1815
  'font-weight': '600'
1685
1816
  },
@@ -1697,8 +1828,8 @@ export const defaultStyles = {
1697
1828
  '.bw-progress-bar-secondary': { 'background-color': '#6c757d' },
1698
1829
  '.bw-progress-bar-success': { 'background-color': '#198754' },
1699
1830
  '.bw-progress-bar-danger': { 'background-color': '#dc3545' },
1700
- '.bw-progress-bar-warning': { 'background-color': '#ffc107' },
1701
- '.bw-progress-bar-info': { 'background-color': '#0dcaf0' }
1831
+ '.bw-progress-bar-warning': { 'background-color': '#b38600' },
1832
+ '.bw-progress-bar-info': { 'background-color': '#0891b2' }
1702
1833
  },
1703
1834
 
1704
1835
  /**
@@ -1836,6 +1967,11 @@ export const defaultStyles = {
1836
1967
  'text-decoration': 'none',
1837
1968
  'background-color': '#f8f9fa'
1838
1969
  },
1970
+ 'a.bw-list-group-item:focus-visible, .bw-list-group-item:focus-visible': {
1971
+ 'z-index': '2',
1972
+ 'outline': '2px solid #006666',
1973
+ 'outline-offset': '-2px'
1974
+ },
1839
1975
  '.bw-list-group-flush': {
1840
1976
  'border-radius': '0'
1841
1977
  },
@@ -1872,7 +2008,7 @@ export const defaultStyles = {
1872
2008
  'text-decoration': 'none',
1873
2009
  'background-color': '#fff',
1874
2010
  'border': '1px solid #dee2e6',
1875
- 'transition': 'color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out'
2011
+ 'transition': 'color 0.15s ease-out, background-color 0.15s ease-out, border-color 0.15s ease-out'
1876
2012
  },
1877
2013
  '.bw-page-link:hover': {
1878
2014
  'z-index': '2',
@@ -1884,8 +2020,8 @@ export const defaultStyles = {
1884
2020
  'z-index': '3',
1885
2021
  'color': '#004d4d',
1886
2022
  'background-color': '#e9ecef',
1887
- 'outline': '0',
1888
- 'box-shadow': '0 0 0 0.25rem rgba(0, 102, 102, 0.25)'
2023
+ 'outline': '2px solid #006666',
2024
+ 'outline-offset': '-2px'
1889
2025
  },
1890
2026
  '.bw-page-item:first-child .bw-page-link': {
1891
2027
  'margin-left': '0',
@@ -1934,8 +2070,18 @@ export const defaultStyles = {
1934
2070
  'color': '#6c757d',
1935
2071
  'content': '"/"'
1936
2072
  },
2073
+ '.bw-breadcrumb-item a': {
2074
+ 'color': '#006666',
2075
+ 'text-decoration': 'none',
2076
+ 'transition': 'color 0.15s ease-out'
2077
+ },
2078
+ '.bw-breadcrumb-item a:hover': {
2079
+ 'color': '#004d4d',
2080
+ 'text-decoration': 'underline'
2081
+ },
1937
2082
  '.bw-breadcrumb-item.active': {
1938
- 'color': '#6c757d'
2083
+ 'color': '#6c757d',
2084
+ 'font-weight': '500'
1939
2085
  }
1940
2086
  },
1941
2087
 
@@ -2041,7 +2187,7 @@ export const defaultStyles = {
2041
2187
  */
2042
2188
  enhancedCards: {
2043
2189
  '.bw-card-hoverable': {
2044
- 'transition': 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'
2190
+ 'transition': 'all 0.3s ease-out'
2045
2191
  },
2046
2192
  '.bw-card-hoverable:hover': {
2047
2193
  'transform': 'translateY(-4px)',
@@ -2368,6 +2514,11 @@ export const defaultStyles = {
2368
2514
  'cursor': 'pointer',
2369
2515
  'font-family': 'inherit',
2370
2516
  'transition': 'all 0.15s'
2517
+ },
2518
+ '.bw-code-copy-btn-copied': {
2519
+ 'background': '#198754',
2520
+ 'color': '#fff',
2521
+ 'border-color': '#198754'
2371
2522
  }
2372
2523
  },
2373
2524
 
@@ -2469,7 +2620,7 @@ export const defaultStyles = {
2469
2620
  'overflow-anchor': 'none',
2470
2621
  'cursor': 'pointer',
2471
2622
  'font-family': 'inherit',
2472
- 'transition': 'color 0.15s ease-in-out, background-color 0.15s ease-in-out'
2623
+ 'transition': 'color 0.15s ease-out, background-color 0.15s ease-out'
2473
2624
  },
2474
2625
  '.bw-accordion-button::after': {
2475
2626
  'flex-shrink': '0',
@@ -2480,7 +2631,7 @@ export const defaultStyles = {
2480
2631
  'background-image': "url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e\")",
2481
2632
  'background-repeat': 'no-repeat',
2482
2633
  'background-size': '1.25rem',
2483
- 'transition': 'transform 0.2s ease-in-out'
2634
+ 'transition': 'transform 0.2s ease-out'
2484
2635
  },
2485
2636
  // Expanded header: tinted background + darker text (Bootstrap pattern)
2486
2637
  '.bw-accordion-button:not(.bw-collapsed)': {
@@ -2528,7 +2679,7 @@ export const defaultStyles = {
2528
2679
  },
2529
2680
  '.bw-carousel-track': {
2530
2681
  'display': 'flex',
2531
- 'transition': 'transform 0.4s ease',
2682
+ 'transition': 'transform 0.3s ease-out',
2532
2683
  'height': '100%'
2533
2684
  },
2534
2685
  '.bw-carousel-slide': {
@@ -2553,7 +2704,7 @@ export const defaultStyles = {
2553
2704
  'padding': '0.75rem 1rem',
2554
2705
  'background': 'linear-gradient(transparent, rgba(0,0,0,0.6))',
2555
2706
  'color': '#fff',
2556
- 'font-size': '0.9rem'
2707
+ 'font-size': '0.875rem'
2557
2708
  },
2558
2709
  '.bw-carousel-control': {
2559
2710
  'position': 'absolute',
@@ -2620,7 +2771,9 @@ export const defaultStyles = {
2620
2771
  */
2621
2772
  modal: {
2622
2773
  '.bw-modal': {
2623
- 'display': 'none',
2774
+ 'display': 'flex',
2775
+ 'align-items': 'center',
2776
+ 'justify-content': 'center',
2624
2777
  'position': 'fixed',
2625
2778
  'top': '0',
2626
2779
  'left': '0',
@@ -2631,13 +2784,14 @@ export const defaultStyles = {
2631
2784
  'overflow-x': 'hidden',
2632
2785
  'overflow-y': 'auto',
2633
2786
  'opacity': '0',
2634
- 'transition': 'opacity 0.15s linear'
2787
+ 'visibility': 'hidden',
2788
+ 'pointer-events': 'none',
2789
+ 'transition': 'opacity 0.2s ease, visibility 0.2s ease'
2635
2790
  },
2636
2791
  '.bw-modal.bw-modal-show': {
2637
- 'display': 'flex',
2638
- 'align-items': 'center',
2639
- 'justify-content': 'center',
2640
- 'opacity': '1'
2792
+ 'opacity': '1',
2793
+ 'visibility': 'visible',
2794
+ 'pointer-events': 'auto'
2641
2795
  },
2642
2796
  '.bw-modal-dialog': {
2643
2797
  'position': 'relative',
@@ -2778,7 +2932,7 @@ export const defaultStyles = {
2778
2932
  'top': '100%',
2779
2933
  'left': '0',
2780
2934
  'z-index': '1000',
2781
- 'display': 'none',
2935
+ 'display': 'block',
2782
2936
  'min-width': '10rem',
2783
2937
  'padding': '0.5rem 0',
2784
2938
  'margin': '0.125rem 0 0',
@@ -2786,10 +2940,18 @@ export const defaultStyles = {
2786
2940
  'background-clip': 'padding-box',
2787
2941
  'border': '1px solid rgba(0,0,0,0.15)',
2788
2942
  'border-radius': '6px',
2789
- 'box-shadow': '0 0.5rem 1rem rgba(0,0,0,0.15)'
2943
+ 'box-shadow': '0 0.5rem 1rem rgba(0,0,0,0.15)',
2944
+ 'opacity': '0',
2945
+ 'visibility': 'hidden',
2946
+ 'transform': 'translateY(-4px)',
2947
+ 'pointer-events': 'none',
2948
+ 'transition': 'opacity 0.15s ease, transform 0.15s ease, visibility 0.15s ease'
2790
2949
  },
2791
2950
  '.bw-dropdown-menu.bw-dropdown-show': {
2792
- 'display': 'block'
2951
+ 'opacity': '1',
2952
+ 'visibility': 'visible',
2953
+ 'transform': 'translateY(0)',
2954
+ 'pointer-events': 'auto'
2793
2955
  },
2794
2956
  '.bw-dropdown-menu-end': {
2795
2957
  'left': 'auto',
@@ -2814,6 +2976,11 @@ export const defaultStyles = {
2814
2976
  'color': '#1e2125',
2815
2977
  'background-color': '#f8f9fa'
2816
2978
  },
2979
+ '.bw-dropdown-item:focus-visible': {
2980
+ 'outline': '2px solid #006666',
2981
+ 'outline-offset': '-2px',
2982
+ 'background-color': '#f8f9fa'
2983
+ },
2817
2984
  '.bw-dropdown-item.disabled': {
2818
2985
  'color': '#adb5bd',
2819
2986
  'pointer-events': 'none',
@@ -2847,7 +3014,7 @@ export const defaultStyles = {
2847
3014
  'background-position': 'left center',
2848
3015
  'background-repeat': 'no-repeat',
2849
3016
  'background-size': 'contain',
2850
- 'transition': 'background-position 0.15s ease-in-out, background-color 0.15s ease-in-out',
3017
+ 'transition': 'background-position 0.15s ease-out, background-color 0.15s ease-out',
2851
3018
  'cursor': 'pointer'
2852
3019
  },
2853
3020
  '.bw-form-switch .bw-switch-input:checked': {
@@ -2934,12 +3101,583 @@ export const defaultStyles = {
2934
3101
  '.bw-avatar-secondary': { 'background-color': '#6c757d', 'color': '#fff' },
2935
3102
  '.bw-avatar-success': { 'background-color': '#198754', 'color': '#fff' },
2936
3103
  '.bw-avatar-danger': { 'background-color': '#dc3545', 'color': '#fff' },
2937
- '.bw-avatar-warning': { 'background-color': '#ffc107', 'color': '#000' },
2938
- '.bw-avatar-info': { 'background-color': '#0dcaf0', 'color': '#000' },
3104
+ '.bw-avatar-warning': { 'background-color': '#b38600', 'color': '#000' },
3105
+ '.bw-avatar-info': { 'background-color': '#0891b2', 'color': '#000' },
2939
3106
  '.bw-avatar-light': { 'background-color': '#f8f9fa', 'color': '#212529' },
2940
3107
  '.bw-avatar-dark': { 'background-color': '#212529', 'color': '#fff' }
2941
3108
  },
2942
3109
 
3110
+ /**
3111
+ * Stat card styles
3112
+ */
3113
+ statCard: {
3114
+ '.bw-stat-card': {
3115
+ 'background-color': '#fff',
3116
+ 'border': '1px solid rgba(0,0,0,0.1)',
3117
+ 'border-left': '4px solid #006666',
3118
+ 'border-radius': '8px',
3119
+ 'padding': '1.25rem',
3120
+ 'box-shadow': '0 1px 3px rgba(0,0,0,0.08)',
3121
+ 'transition': 'box-shadow 0.15s ease-out, transform 0.15s ease-out'
3122
+ },
3123
+ '.bw-stat-card:hover': {
3124
+ 'box-shadow': '0 4px 12px rgba(0,0,0,0.12)',
3125
+ 'transform': 'translateY(-1px)'
3126
+ },
3127
+ '.bw-stat-icon': {
3128
+ 'font-size': '1.5rem',
3129
+ 'margin-bottom': '0.5rem'
3130
+ },
3131
+ '.bw-stat-value': {
3132
+ 'font-size': '2rem',
3133
+ 'font-weight': '700',
3134
+ 'line-height': '1.2',
3135
+ 'color': '#212529'
3136
+ },
3137
+ '.bw-stat-label': {
3138
+ 'font-size': '0.875rem',
3139
+ 'color': '#6c757d',
3140
+ 'margin-top': '0.25rem'
3141
+ },
3142
+ '.bw-stat-change': {
3143
+ 'font-size': '0.875rem',
3144
+ 'font-weight': '500',
3145
+ 'margin-top': '0.5rem'
3146
+ },
3147
+ '.bw-stat-change-up': { 'color': '#198754' },
3148
+ '.bw-stat-change-down': { 'color': '#dc3545' },
3149
+ '.bw-stat-card-primary': { 'border-left-color': '#006666' },
3150
+ '.bw-stat-card-secondary': { 'border-left-color': '#6c757d' },
3151
+ '.bw-stat-card-success': { 'border-left-color': '#198754' },
3152
+ '.bw-stat-card-danger': { 'border-left-color': '#dc3545' },
3153
+ '.bw-stat-card-warning': { 'border-left-color': '#b38600' },
3154
+ '.bw-stat-card-info': { 'border-left-color': '#0891b2' }
3155
+ },
3156
+
3157
+ /**
3158
+ * Tooltip styles
3159
+ */
3160
+ tooltip: {
3161
+ '.bw-tooltip-wrapper': {
3162
+ 'position': 'relative',
3163
+ 'display': 'inline-block'
3164
+ },
3165
+ '.bw-tooltip': {
3166
+ 'position': 'absolute',
3167
+ 'z-index': '999',
3168
+ 'background-color': '#212529',
3169
+ 'color': '#fff',
3170
+ 'padding': '0.375rem 0.75rem',
3171
+ 'border-radius': '4px',
3172
+ 'font-size': '0.875rem',
3173
+ 'white-space': 'nowrap',
3174
+ 'pointer-events': 'none',
3175
+ 'opacity': '0',
3176
+ 'visibility': 'hidden',
3177
+ 'transition': 'opacity 0.15s ease, visibility 0.15s ease, transform 0.15s ease'
3178
+ },
3179
+ '.bw-tooltip.bw-tooltip-show': {
3180
+ 'opacity': '1',
3181
+ 'visibility': 'visible'
3182
+ },
3183
+ '.bw-tooltip-top': {
3184
+ 'bottom': '100%',
3185
+ 'left': '50%',
3186
+ 'transform': 'translateX(-50%) translateY(-4px)',
3187
+ 'margin-bottom': '4px'
3188
+ },
3189
+ '.bw-tooltip-top.bw-tooltip-show': {
3190
+ 'transform': 'translateX(-50%) translateY(0)'
3191
+ },
3192
+ '.bw-tooltip-bottom': {
3193
+ 'top': '100%',
3194
+ 'left': '50%',
3195
+ 'transform': 'translateX(-50%) translateY(4px)',
3196
+ 'margin-top': '4px'
3197
+ },
3198
+ '.bw-tooltip-bottom.bw-tooltip-show': {
3199
+ 'transform': 'translateX(-50%) translateY(0)'
3200
+ },
3201
+ '.bw-tooltip-left': {
3202
+ 'right': '100%',
3203
+ 'top': '50%',
3204
+ 'transform': 'translateY(-50%) translateX(-4px)',
3205
+ 'margin-right': '4px'
3206
+ },
3207
+ '.bw-tooltip-left.bw-tooltip-show': {
3208
+ 'transform': 'translateY(-50%) translateX(0)'
3209
+ },
3210
+ '.bw-tooltip-right': {
3211
+ 'left': '100%',
3212
+ 'top': '50%',
3213
+ 'transform': 'translateY(-50%) translateX(4px)',
3214
+ 'margin-left': '4px'
3215
+ },
3216
+ '.bw-tooltip-right.bw-tooltip-show': {
3217
+ 'transform': 'translateY(-50%) translateX(0)'
3218
+ }
3219
+ },
3220
+
3221
+ /**
3222
+ * Popover styles
3223
+ */
3224
+ popover: {
3225
+ '.bw-popover-wrapper': {
3226
+ 'position': 'relative',
3227
+ 'display': 'inline-block'
3228
+ },
3229
+ '.bw-popover-trigger': {
3230
+ 'cursor': 'pointer'
3231
+ },
3232
+ '.bw-popover': {
3233
+ 'position': 'absolute',
3234
+ 'z-index': '1000',
3235
+ 'background-color': '#fff',
3236
+ 'color': '#212529',
3237
+ 'border': '1px solid rgba(0,0,0,0.15)',
3238
+ 'border-radius': '8px',
3239
+ 'box-shadow': '0 0.5rem 1rem rgba(0,0,0,0.15)',
3240
+ 'min-width': '200px',
3241
+ 'max-width': '320px',
3242
+ 'pointer-events': 'none',
3243
+ 'opacity': '0',
3244
+ 'visibility': 'hidden',
3245
+ 'transition': 'opacity 0.15s ease, visibility 0.15s ease, transform 0.15s ease'
3246
+ },
3247
+ '.bw-popover.bw-popover-show': {
3248
+ 'opacity': '1',
3249
+ 'visibility': 'visible',
3250
+ 'pointer-events': 'auto'
3251
+ },
3252
+ '.bw-popover-header': {
3253
+ 'padding': '0.625rem 0.875rem',
3254
+ 'font-weight': '600',
3255
+ 'font-size': '0.9375rem',
3256
+ 'border-bottom': '1px solid rgba(0,0,0,0.1)',
3257
+ 'border-radius': '8px 8px 0 0',
3258
+ 'background-color': '#f8f9fa'
3259
+ },
3260
+ '.bw-popover-body': {
3261
+ 'padding': '0.75rem 0.875rem',
3262
+ 'font-size': '0.875rem',
3263
+ 'line-height': '1.5'
3264
+ },
3265
+ '.bw-popover-top': {
3266
+ 'bottom': '100%',
3267
+ 'left': '50%',
3268
+ 'transform': 'translateX(-50%) translateY(-8px)',
3269
+ 'margin-bottom': '8px'
3270
+ },
3271
+ '.bw-popover-top.bw-popover-show': {
3272
+ 'transform': 'translateX(-50%) translateY(0)'
3273
+ },
3274
+ '.bw-popover-bottom': {
3275
+ 'top': '100%',
3276
+ 'left': '50%',
3277
+ 'transform': 'translateX(-50%) translateY(8px)',
3278
+ 'margin-top': '8px'
3279
+ },
3280
+ '.bw-popover-bottom.bw-popover-show': {
3281
+ 'transform': 'translateX(-50%) translateY(0)'
3282
+ },
3283
+ '.bw-popover-left': {
3284
+ 'right': '100%',
3285
+ 'top': '50%',
3286
+ 'transform': 'translateY(-50%) translateX(-8px)',
3287
+ 'margin-right': '8px'
3288
+ },
3289
+ '.bw-popover-left.bw-popover-show': {
3290
+ 'transform': 'translateY(-50%) translateX(0)'
3291
+ },
3292
+ '.bw-popover-right': {
3293
+ 'left': '100%',
3294
+ 'top': '50%',
3295
+ 'transform': 'translateY(-50%) translateX(8px)',
3296
+ 'margin-left': '8px'
3297
+ },
3298
+ '.bw-popover-right.bw-popover-show': {
3299
+ 'transform': 'translateY(-50%) translateX(0)'
3300
+ }
3301
+ },
3302
+
3303
+ /**
3304
+ * Search input styles
3305
+ */
3306
+ searchInput: {
3307
+ '.bw-search-input': {
3308
+ 'position': 'relative',
3309
+ 'display': 'flex',
3310
+ 'align-items': 'center'
3311
+ },
3312
+ '.bw-search-input .bw-search-field': {
3313
+ 'padding-right': '2.5rem'
3314
+ },
3315
+ '.bw-search-clear': {
3316
+ 'position': 'absolute',
3317
+ 'right': '0.5rem',
3318
+ 'display': 'flex',
3319
+ 'align-items': 'center',
3320
+ 'justify-content': 'center',
3321
+ 'width': '1.5rem',
3322
+ 'height': '1.5rem',
3323
+ 'border': 'none',
3324
+ 'background': 'none',
3325
+ 'color': '#6c757d',
3326
+ 'font-size': '1.25rem',
3327
+ 'cursor': 'pointer',
3328
+ 'padding': '0',
3329
+ 'line-height': '1',
3330
+ 'border-radius': '50%',
3331
+ 'transition': 'color 0.15s ease-out'
3332
+ },
3333
+ '.bw-search-clear:hover': {
3334
+ 'color': '#212529'
3335
+ }
3336
+ },
3337
+
3338
+ /**
3339
+ * Range slider styles
3340
+ */
3341
+ range: {
3342
+ '.bw-range-wrapper': {
3343
+ 'margin-bottom': '1rem'
3344
+ },
3345
+ '.bw-range-label': {
3346
+ 'display': 'flex',
3347
+ 'justify-content': 'space-between',
3348
+ 'align-items': 'center',
3349
+ 'margin-bottom': '0.5rem',
3350
+ 'font-size': '0.875rem',
3351
+ 'font-weight': '500'
3352
+ },
3353
+ '.bw-range-value': {
3354
+ 'font-weight': '600',
3355
+ 'color': '#006666'
3356
+ },
3357
+ '.bw-range': {
3358
+ 'width': '100%',
3359
+ 'height': '0.5rem',
3360
+ 'padding': '0',
3361
+ 'appearance': 'none',
3362
+ 'background-color': '#dee2e6',
3363
+ 'border': 'none',
3364
+ 'border-radius': '0.25rem',
3365
+ 'cursor': 'pointer',
3366
+ 'outline': 'none'
3367
+ },
3368
+ '.bw-range:focus': {
3369
+ 'outline': 'none'
3370
+ },
3371
+ '.bw-range::-webkit-slider-thumb': {
3372
+ 'appearance': 'none',
3373
+ 'width': '1.25rem',
3374
+ 'height': '1.25rem',
3375
+ 'border-radius': '50%',
3376
+ 'background-color': '#006666',
3377
+ 'border': '2px solid #fff',
3378
+ 'box-shadow': '0 1px 3px rgba(0,0,0,0.2)',
3379
+ 'cursor': 'pointer',
3380
+ 'transition': 'background-color 0.15s ease-out, transform 0.15s ease-out'
3381
+ },
3382
+ '.bw-range::-webkit-slider-thumb:hover': {
3383
+ 'transform': 'scale(1.15)'
3384
+ },
3385
+ '.bw-range::-moz-range-thumb': {
3386
+ 'width': '1.25rem',
3387
+ 'height': '1.25rem',
3388
+ 'border-radius': '50%',
3389
+ 'background-color': '#006666',
3390
+ 'border': '2px solid #fff',
3391
+ 'box-shadow': '0 1px 3px rgba(0,0,0,0.2)',
3392
+ 'cursor': 'pointer'
3393
+ },
3394
+ '.bw-range:disabled': {
3395
+ 'opacity': '0.5',
3396
+ 'cursor': 'not-allowed'
3397
+ }
3398
+ },
3399
+
3400
+ /**
3401
+ * Media object styles
3402
+ */
3403
+ mediaObject: {
3404
+ '.bw-media': {
3405
+ 'display': 'flex',
3406
+ 'align-items': 'flex-start',
3407
+ 'gap': '1rem'
3408
+ },
3409
+ '.bw-media-reverse': {
3410
+ 'flex-direction': 'row-reverse'
3411
+ },
3412
+ '.bw-media-img': {
3413
+ 'border-radius': '50%',
3414
+ 'object-fit': 'cover',
3415
+ 'flex-shrink': '0'
3416
+ },
3417
+ '.bw-media-body': {
3418
+ 'flex': '1',
3419
+ 'min-width': '0'
3420
+ },
3421
+ '.bw-media-title': {
3422
+ 'margin': '0 0 0.25rem 0',
3423
+ 'font-size': '1rem',
3424
+ 'font-weight': '600',
3425
+ 'line-height': '1.3'
3426
+ }
3427
+ },
3428
+
3429
+ /**
3430
+ * File upload styles
3431
+ */
3432
+ fileUpload: {
3433
+ '.bw-file-upload': {
3434
+ 'display': 'flex',
3435
+ 'flex-direction': 'column',
3436
+ 'align-items': 'center',
3437
+ 'justify-content': 'center',
3438
+ 'padding': '2rem',
3439
+ 'border': '2px dashed #dee2e6',
3440
+ 'border-radius': '8px',
3441
+ 'background-color': '#f8f9fa',
3442
+ 'cursor': 'pointer',
3443
+ 'text-align': 'center',
3444
+ 'transition': 'border-color 0.15s ease-out, background-color 0.15s ease-out',
3445
+ 'position': 'relative'
3446
+ },
3447
+ '.bw-file-upload:hover': {
3448
+ 'border-color': '#006666',
3449
+ 'background-color': '#f0fafa'
3450
+ },
3451
+ '.bw-file-upload.bw-file-upload-active': {
3452
+ 'border-color': '#006666',
3453
+ 'background-color': '#e6f7f7',
3454
+ 'border-style': 'solid'
3455
+ },
3456
+ '.bw-file-upload-icon': {
3457
+ 'font-size': '2rem',
3458
+ 'margin-bottom': '0.5rem'
3459
+ },
3460
+ '.bw-file-upload-text': {
3461
+ 'font-size': '0.875rem',
3462
+ 'color': '#6c757d'
3463
+ },
3464
+ '.bw-file-upload-input': {
3465
+ 'position': 'absolute',
3466
+ 'width': '1px',
3467
+ 'height': '1px',
3468
+ 'padding': '0',
3469
+ 'margin': '-1px',
3470
+ 'overflow': 'hidden',
3471
+ 'clip': 'rect(0,0,0,0)',
3472
+ 'border': '0'
3473
+ },
3474
+ '.bw-file-upload:focus': {
3475
+ 'outline': '2px solid #006666',
3476
+ 'outline-offset': '2px'
3477
+ }
3478
+ },
3479
+
3480
+ /**
3481
+ * Timeline styles
3482
+ */
3483
+ timeline: {
3484
+ '.bw-timeline': {
3485
+ 'position': 'relative',
3486
+ 'padding-left': '2rem'
3487
+ },
3488
+ '.bw-timeline::before': {
3489
+ 'content': '""',
3490
+ 'position': 'absolute',
3491
+ 'left': '0.5rem',
3492
+ 'top': '0',
3493
+ 'bottom': '0',
3494
+ 'width': '2px',
3495
+ 'background-color': '#dee2e6'
3496
+ },
3497
+ '.bw-timeline-item': {
3498
+ 'position': 'relative',
3499
+ 'padding-bottom': '1.5rem'
3500
+ },
3501
+ '.bw-timeline-item:last-child': {
3502
+ 'padding-bottom': '0'
3503
+ },
3504
+ '.bw-timeline-marker': {
3505
+ 'position': 'absolute',
3506
+ 'left': '-1.75rem',
3507
+ 'top': '0.25rem',
3508
+ 'width': '0.75rem',
3509
+ 'height': '0.75rem',
3510
+ 'border-radius': '50%',
3511
+ 'border': '2px solid #fff',
3512
+ 'box-shadow': '0 0 0 2px #dee2e6'
3513
+ },
3514
+ '.bw-timeline-marker-primary': { 'background-color': '#006666', 'box-shadow': '0 0 0 2px #006666' },
3515
+ '.bw-timeline-marker-secondary': { 'background-color': '#6c757d', 'box-shadow': '0 0 0 2px #6c757d' },
3516
+ '.bw-timeline-marker-success': { 'background-color': '#198754', 'box-shadow': '0 0 0 2px #198754' },
3517
+ '.bw-timeline-marker-danger': { 'background-color': '#dc3545', 'box-shadow': '0 0 0 2px #dc3545' },
3518
+ '.bw-timeline-marker-warning': { 'background-color': '#b38600', 'box-shadow': '0 0 0 2px #b38600' },
3519
+ '.bw-timeline-marker-info': { 'background-color': '#0891b2', 'box-shadow': '0 0 0 2px #0891b2' },
3520
+ '.bw-timeline-content': {
3521
+ 'padding-left': '0.5rem'
3522
+ },
3523
+ '.bw-timeline-date': {
3524
+ 'font-size': '0.75rem',
3525
+ 'color': '#6c757d',
3526
+ 'margin-bottom': '0.25rem',
3527
+ 'font-weight': '500'
3528
+ },
3529
+ '.bw-timeline-title': {
3530
+ 'font-size': '1rem',
3531
+ 'font-weight': '600',
3532
+ 'margin': '0 0 0.25rem 0',
3533
+ 'line-height': '1.3'
3534
+ },
3535
+ '.bw-timeline-text': {
3536
+ 'font-size': '0.875rem',
3537
+ 'color': '#495057',
3538
+ 'margin': '0',
3539
+ 'line-height': '1.5'
3540
+ }
3541
+ },
3542
+
3543
+ /**
3544
+ * Stepper styles
3545
+ */
3546
+ stepper: {
3547
+ '.bw-stepper': {
3548
+ 'display': 'flex',
3549
+ 'gap': '0',
3550
+ 'counter-reset': 'step'
3551
+ },
3552
+ '.bw-step': {
3553
+ 'flex': '1',
3554
+ 'display': 'flex',
3555
+ 'flex-direction': 'column',
3556
+ 'align-items': 'center',
3557
+ 'text-align': 'center',
3558
+ 'position': 'relative'
3559
+ },
3560
+ '.bw-step + .bw-step::before': {
3561
+ 'content': '""',
3562
+ 'position': 'absolute',
3563
+ 'top': '1rem',
3564
+ 'left': '-50%',
3565
+ 'right': '50%',
3566
+ 'height': '2px',
3567
+ 'background-color': '#dee2e6'
3568
+ },
3569
+ '.bw-step-completed + .bw-step::before': {
3570
+ 'background-color': '#006666'
3571
+ },
3572
+ '.bw-step-indicator': {
3573
+ 'width': '2rem',
3574
+ 'height': '2rem',
3575
+ 'border-radius': '50%',
3576
+ 'display': 'flex',
3577
+ 'align-items': 'center',
3578
+ 'justify-content': 'center',
3579
+ 'font-size': '0.875rem',
3580
+ 'font-weight': '600',
3581
+ 'background-color': '#dee2e6',
3582
+ 'color': '#6c757d',
3583
+ 'position': 'relative',
3584
+ 'z-index': '1',
3585
+ 'transition': 'background-color 0.2s ease-out, color 0.2s ease-out'
3586
+ },
3587
+ '.bw-step-active .bw-step-indicator': {
3588
+ 'background-color': '#006666',
3589
+ 'color': '#fff'
3590
+ },
3591
+ '.bw-step-completed .bw-step-indicator': {
3592
+ 'background-color': '#006666',
3593
+ 'color': '#fff'
3594
+ },
3595
+ '.bw-step-body': {
3596
+ 'margin-top': '0.5rem'
3597
+ },
3598
+ '.bw-step-label': {
3599
+ 'font-size': '0.875rem',
3600
+ 'font-weight': '500',
3601
+ 'color': '#6c757d'
3602
+ },
3603
+ '.bw-step-active .bw-step-label': {
3604
+ 'color': '#212529',
3605
+ 'font-weight': '600'
3606
+ },
3607
+ '.bw-step-completed .bw-step-label': {
3608
+ 'color': '#006666'
3609
+ },
3610
+ '.bw-step-description': {
3611
+ 'font-size': '0.75rem',
3612
+ 'color': '#6c757d',
3613
+ 'margin-top': '0.125rem'
3614
+ }
3615
+ },
3616
+
3617
+ /**
3618
+ * Chip input styles
3619
+ */
3620
+ chipInput: {
3621
+ '.bw-chip-input': {
3622
+ 'display': 'flex',
3623
+ 'flex-wrap': 'wrap',
3624
+ 'align-items': 'center',
3625
+ 'gap': '0.375rem',
3626
+ 'padding': '0.375rem 0.5rem',
3627
+ 'border': '1px solid #ced4da',
3628
+ 'border-radius': '6px',
3629
+ 'background-color': '#fff',
3630
+ 'min-height': '2.5rem',
3631
+ 'cursor': 'text',
3632
+ 'transition': 'border-color 0.15s ease-out, box-shadow 0.15s ease-out'
3633
+ },
3634
+ '.bw-chip-input:focus-within': {
3635
+ 'border-color': '#006666',
3636
+ 'box-shadow': '0 0 0 0.2rem rgba(0, 102, 102, 0.25)'
3637
+ },
3638
+ '.bw-chip': {
3639
+ 'display': 'inline-flex',
3640
+ 'align-items': 'center',
3641
+ 'gap': '0.25rem',
3642
+ 'padding': '0.125rem 0.5rem',
3643
+ 'background-color': '#e9ecef',
3644
+ 'border-radius': '1rem',
3645
+ 'font-size': '0.8125rem',
3646
+ 'line-height': '1.5',
3647
+ 'color': '#212529',
3648
+ 'white-space': 'nowrap'
3649
+ },
3650
+ '.bw-chip-remove': {
3651
+ 'display': 'inline-flex',
3652
+ 'align-items': 'center',
3653
+ 'justify-content': 'center',
3654
+ 'width': '1rem',
3655
+ 'height': '1rem',
3656
+ 'border': 'none',
3657
+ 'background': 'none',
3658
+ 'color': '#6c757d',
3659
+ 'font-size': '0.875rem',
3660
+ 'cursor': 'pointer',
3661
+ 'padding': '0',
3662
+ 'line-height': '1',
3663
+ 'border-radius': '50%',
3664
+ 'transition': 'color 0.15s ease-out, background-color 0.15s ease-out'
3665
+ },
3666
+ '.bw-chip-remove:hover': {
3667
+ 'color': '#dc3545',
3668
+ 'background-color': 'rgba(220, 53, 69, 0.1)'
3669
+ },
3670
+ '.bw-chip-field': {
3671
+ 'flex': '1',
3672
+ 'min-width': '80px',
3673
+ 'border': 'none',
3674
+ 'outline': 'none',
3675
+ 'font-size': '0.875rem',
3676
+ 'padding': '0.125rem 0',
3677
+ 'background': 'transparent'
3678
+ }
3679
+ },
3680
+
2943
3681
  /**
2944
3682
  * Utility classes
2945
3683
  */
@@ -3044,8 +3782,8 @@ export const defaultStyles = {
3044
3782
  '.bw-text-secondary': { 'color': '#6c757d' },
3045
3783
  '.bw-text-success': { 'color': '#198754' },
3046
3784
  '.bw-text-danger': { 'color': '#dc3545' },
3047
- '.bw-text-warning': { 'color': '#ffc107' },
3048
- '.bw-text-info': { 'color': '#0dcaf0' },
3785
+ '.bw-text-warning': { 'color': '#b38600' },
3786
+ '.bw-text-info': { 'color': '#0891b2' },
3049
3787
  '.bw-text-light': { 'color': '#f8f9fa' },
3050
3788
  '.bw-text-dark': { 'color': '#212529' },
3051
3789
  '.bw-text-muted': { 'color': '#6c757d' },
@@ -3054,8 +3792,8 @@ export const defaultStyles = {
3054
3792
  '.bw-bg-secondary': { 'background-color': '#6c757d' },
3055
3793
  '.bw-bg-success': { 'background-color': '#198754' },
3056
3794
  '.bw-bg-danger': { 'background-color': '#dc3545' },
3057
- '.bw-bg-warning': { 'background-color': '#ffc107' },
3058
- '.bw-bg-info': { 'background-color': '#0dcaf0' },
3795
+ '.bw-bg-warning': { 'background-color': '#b38600' },
3796
+ '.bw-bg-info': { 'background-color': '#0891b2' },
3059
3797
  '.bw-bg-light': { 'background-color': '#f8f9fa' },
3060
3798
  '.bw-bg-dark': { 'background-color': '#212529' },
3061
3799
 
@@ -3255,11 +3993,23 @@ export const defaultStyles = {
3255
3993
  // =========================================================================
3256
3994
 
3257
3995
  /**
3258
- * Structural styles contain only layout, sizing, spacing, and behavior
3259
- * properties. No colors, backgrounds, shadows, or border-colors.
3260
- * These never change with themes.
3996
+ * Structural styles layout, sizing, spacing, positioning, and behavior.
3261
3997
  *
3262
- * @returns {Object} CSS rules object
3998
+ * POLICY: No colors, backgrounds, shadows, or border-colors in this function.
3999
+ * All cosmetic values belong in `defaultStyles.*` sections (unthemed defaults)
4000
+ * or in `generateThemedCSS()` (theme-driven colors).
4001
+ *
4002
+ * Exception: `.bw-progress-bar-striped` uses rgba(255,255,255,.15) for the
4003
+ * stripe pattern overlay. This is theme-neutral — a semi-transparent white
4004
+ * gradient that creates visible stripes on any background color.
4005
+ *
4006
+ * Architecture:
4007
+ * getStructuralStyles() → layout-only rules (never change with themes)
4008
+ * defaultStyles.* → cosmetic defaults (colors, shadows, borders)
4009
+ * generateThemedCSS() → palette-driven cosmetics from seed colors
4010
+ * generateAlternateCSS() → alternate palette (luminance-inverted)
4011
+ *
4012
+ * @returns {Object} CSS rules object (layout-only, theme-independent)
3263
4013
  */
3264
4014
  export function getStructuralStyles() {
3265
4015
  var rules = {};
@@ -3310,12 +4060,12 @@ export function getStructuralStyles() {
3310
4060
  'text-decoration': 'none', 'vertical-align': 'middle', 'cursor': 'pointer',
3311
4061
  'user-select': 'none', 'border': '1px solid transparent',
3312
4062
  'padding': '0.5rem 1.125rem', 'font-size': '0.875rem', 'font-family': 'inherit',
3313
- 'border-radius': '6px', 'transition': 'all 0.15s cubic-bezier(0.4, 0, 0.2, 1)',
4063
+ 'border-radius': '6px', 'transition': 'all 0.15s ease-out',
3314
4064
  'gap': '0.5rem'
3315
4065
  };
3316
4066
  rules['.bw-btn:hover'] = { 'text-decoration': 'none', 'transform': 'translateY(-1px)' };
3317
4067
  rules['.bw-btn:active'] = { 'transform': 'translateY(0)' };
3318
- rules['.bw-btn:focus-visible'] = { 'outline': '0' };
4068
+ rules['.bw-btn:focus-visible'] = { 'outline': '2px solid currentColor', 'outline-offset': '2px' };
3319
4069
  rules['.bw-btn:disabled'] = { 'opacity': '0.5', 'cursor': 'not-allowed', 'pointer-events': 'none' };
3320
4070
  rules['.bw-btn-lg'] = { 'padding': '0.625rem 1.5rem', 'font-size': '1rem', 'border-radius': '8px' };
3321
4071
  rules['.bw-btn-sm'] = { 'padding': '0.25rem 0.75rem', 'font-size': '0.8125rem', 'border-radius': '5px' };
@@ -3325,7 +4075,7 @@ export function getStructuralStyles() {
3325
4075
  'position': 'relative', 'display': 'flex', 'flex-direction': 'column',
3326
4076
  'min-width': '0', 'height': '100%', 'word-wrap': 'break-word',
3327
4077
  'background-clip': 'border-box', 'border': '1px solid transparent',
3328
- 'border-radius': '8px', 'transition': 'box-shadow 0.2s cubic-bezier(0.4,0,0.2,1), transform 0.2s cubic-bezier(0.4,0,0.2,1)',
4078
+ 'border-radius': '8px', 'transition': 'box-shadow 0.2s ease-out, transform 0.2s ease-out',
3329
4079
  'margin-bottom': '1.5rem', 'overflow': 'hidden'
3330
4080
  };
3331
4081
  rules['.bw-card-body'] = { 'flex': '1 1 auto', 'padding': '1.25rem 1.5rem' };
@@ -3334,7 +4084,7 @@ export function getStructuralStyles() {
3334
4084
  rules['.bw-card-text'] = { 'margin-bottom': '0', 'font-size': '0.9375rem', 'line-height': '1.6' };
3335
4085
  rules['.bw-card-header'] = { 'padding': '0.875rem 1.5rem', 'margin-bottom': '0', 'font-weight': '600', 'font-size': '0.875rem' };
3336
4086
  rules['.bw-card-footer'] = { 'padding': '0.75rem 1.5rem', 'font-size': '0.875rem' };
3337
- rules['.bw-card-hoverable'] = { 'transition': 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)' };
4087
+ rules['.bw-card-hoverable'] = { 'transition': 'all 0.3s ease-out' };
3338
4088
  rules['.bw-card-img-top'] = { 'width': '100%', 'border-top-left-radius': '7px', 'border-top-right-radius': '7px' };
3339
4089
  rules['.bw-card-img-bottom'] = { 'width': '100%', 'border-bottom-left-radius': '7px', 'border-bottom-right-radius': '7px' };
3340
4090
  rules['.bw-card-img-left'] = { 'width': '40%', 'object-fit': 'cover' };
@@ -3347,10 +4097,10 @@ export function getStructuralStyles() {
3347
4097
  'font-size': '0.9375rem', 'font-weight': '400', 'line-height': '1.5',
3348
4098
  'background-clip': 'padding-box', 'appearance': 'none',
3349
4099
  'border': '1px solid transparent', 'border-radius': '6px',
3350
- 'transition': 'border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out',
4100
+ 'transition': 'border-color 0.15s ease-out, box-shadow 0.15s ease-out',
3351
4101
  'font-family': 'inherit'
3352
4102
  };
3353
- rules['.bw-form-control:focus'] = { 'outline': '0' };
4103
+ rules['.bw-form-control:focus'] = { 'outline': '2px solid currentColor', 'outline-offset': '-1px' };
3354
4104
  rules['.bw-form-control::placeholder'] = { 'opacity': '1' };
3355
4105
  rules['.bw-form-label'] = { 'display': 'block', 'margin-bottom': '0.375rem', 'font-size': '0.875rem', 'font-weight': '600' };
3356
4106
  rules['.bw-form-group'] = { 'margin-bottom': '1.25rem' };
@@ -3362,6 +4112,10 @@ export function getStructuralStyles() {
3362
4112
  };
3363
4113
  rules['textarea.bw-form-control'] = { 'min-height': '5rem', 'resize': 'vertical' };
3364
4114
 
4115
+ // Form validation (structural)
4116
+ rules['.bw-valid-feedback'] = { 'display': 'block', 'font-size': '0.875rem', 'margin-top': '0.25rem' };
4117
+ rules['.bw-invalid-feedback'] = { 'display': 'block', 'font-size': '0.875rem', 'margin-top': '0.25rem' };
4118
+
3365
4119
  // Form checks (structural)
3366
4120
  Object.assign(rules, {
3367
4121
  '.bw-form-check': { 'display': 'flex', 'align-items': 'center', 'gap': '0.5rem', 'min-height': '1.5rem', 'margin-bottom': '0.25rem' },
@@ -3420,13 +4174,13 @@ export function getStructuralStyles() {
3420
4174
 
3421
4175
  // Badges (structural)
3422
4176
  rules['.bw-badge'] = {
3423
- 'display': 'inline-block', 'padding': '.4em .75em', 'font-size': '.875em',
4177
+ 'display': 'inline-block', 'padding': '0.375rem 0.625rem', 'font-size': '0.875rem',
3424
4178
  'font-weight': '600', 'line-height': '1.3', 'text-align': 'center',
3425
4179
  'white-space': 'nowrap', 'vertical-align': 'baseline', 'border-radius': '.375rem'
3426
4180
  };
3427
4181
  rules['.bw-badge:empty'] = { 'display': 'none' };
3428
- rules['.bw-badge-sm'] = { 'font-size': '.75em', 'padding': '.25em .5em' };
3429
- rules['.bw-badge-lg'] = { 'font-size': '1em', 'padding': '.5em .9em' };
4182
+ rules['.bw-badge-sm'] = { 'font-size': '0.75rem', 'padding': '0.25rem 0.5rem' };
4183
+ rules['.bw-badge-lg'] = { 'font-size': '1rem', 'padding': '0.5rem 0.875rem' };
3430
4184
  rules['.bw-badge-pill'] = { 'border-radius': '50rem' };
3431
4185
 
3432
4186
  // Progress (structural)
@@ -3434,7 +4188,7 @@ export function getStructuralStyles() {
3434
4188
  rules['.bw-progress-bar'] = {
3435
4189
  'display': 'flex', 'flex-direction': 'column', 'justify-content': 'center',
3436
4190
  'overflow': 'hidden', 'text-align': 'center', 'white-space': 'nowrap',
3437
- 'transition': 'width .6s ease', 'font-weight': '600'
4191
+ 'transition': 'width 0.3s ease-out', 'font-weight': '600'
3438
4192
  };
3439
4193
  rules['.bw-progress-bar-striped'] = {
3440
4194
  'background-image': 'linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)',
@@ -3451,7 +4205,7 @@ export function getStructuralStyles() {
3451
4205
  'display': 'block', 'padding': '0.625rem 1rem', 'font-size': '0.875rem',
3452
4206
  'font-weight': '500', 'text-decoration': 'none', 'cursor': 'pointer',
3453
4207
  'border': 'none', 'background': 'transparent',
3454
- 'transition': 'color 0.15s, border-color 0.15s', 'font-family': 'inherit'
4208
+ 'transition': 'color 0.15s ease-out, background-color 0.15s ease-out, border-color 0.15s ease-out', 'font-family': 'inherit'
3455
4209
  };
3456
4210
  rules['.bw-nav-tabs .bw-nav-link'] = { 'border': 'none', 'border-bottom': '2px solid transparent', 'border-radius': '0', 'background-color': 'transparent' };
3457
4211
  rules['.bw-nav-pills .bw-nav-link'] = { 'border-radius': '6px' };
@@ -3469,7 +4223,8 @@ export function getStructuralStyles() {
3469
4223
  rules['.bw-list-group-item:last-child'] = { 'border-bottom-right-radius': 'inherit', 'border-bottom-left-radius': 'inherit' };
3470
4224
  rules['.bw-list-group-item + .bw-list-group-item'] = { 'border-top-width': '0' };
3471
4225
  rules['.bw-list-group-item.disabled'] = { 'pointer-events': 'none' };
3472
- rules['a.bw-list-group-item'] = { 'cursor': 'pointer' };
4226
+ rules['a.bw-list-group-item'] = { 'cursor': 'pointer', 'transition': 'background-color 0.15s ease-out, color 0.15s ease-out' };
4227
+ rules['a.bw-list-group-item:focus-visible, .bw-list-group-item:focus-visible'] = { 'z-index': '2', 'outline': '2px solid currentColor', 'outline-offset': '-2px' };
3473
4228
  rules['.bw-list-group-flush'] = { 'border-radius': '0' };
3474
4229
  rules['.bw-list-group-flush > .bw-list-group-item'] = { 'border-width': '0 0 1px', 'border-radius': '0' };
3475
4230
  rules['.bw-list-group-flush > .bw-list-group-item:last-child'] = { 'border-bottom-width': '0' };
@@ -3480,16 +4235,19 @@ export function getStructuralStyles() {
3480
4235
  rules['.bw-page-link'] = {
3481
4236
  'position': 'relative', 'display': 'block', 'padding': '0.375rem 0.75rem',
3482
4237
  'margin-left': '-1px', 'line-height': '1.25', 'text-decoration': 'none',
3483
- 'transition': 'color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out'
4238
+ 'transition': 'color 0.15s ease-out, background-color 0.15s ease-out, border-color 0.15s ease-out'
3484
4239
  };
3485
4240
  rules['.bw-page-item:first-child .bw-page-link'] = { 'margin-left': '0', 'border-top-left-radius': '0.375rem', 'border-bottom-left-radius': '0.375rem' };
3486
4241
  rules['.bw-page-item:last-child .bw-page-link'] = { 'border-top-right-radius': '0.375rem', 'border-bottom-right-radius': '0.375rem' };
4242
+ rules['.bw-page-link:focus-visible'] = { 'z-index': '3', 'outline': '2px solid currentColor', 'outline-offset': '-2px' };
3487
4243
 
3488
4244
  // Breadcrumb (structural)
3489
4245
  rules['.bw-breadcrumb'] = { 'display': 'flex', 'flex-wrap': 'wrap', 'padding': '0 0', 'margin-bottom': '1rem', 'list-style': 'none' };
3490
4246
  rules['.bw-breadcrumb-item'] = { 'display': 'flex' };
3491
4247
  rules['.bw-breadcrumb-item + .bw-breadcrumb-item'] = { 'padding-left': '0.5rem' };
3492
4248
  rules['.bw-breadcrumb-item + .bw-breadcrumb-item::before'] = { 'float': 'left', 'padding-right': '0.5rem', 'content': '"/"' };
4249
+ rules['.bw-breadcrumb-item a'] = { 'text-decoration': 'none', 'transition': 'color 0.15s ease-out' };
4250
+ rules['.bw-breadcrumb-item.active'] = { 'font-weight': '500' };
3493
4251
 
3494
4252
  // Hero (structural)
3495
4253
  rules['.bw-hero'] = { 'position': 'relative', 'overflow': 'hidden' };
@@ -3592,12 +4350,12 @@ export function getStructuralStyles() {
3592
4350
  'position': 'relative', 'display': 'flex', 'align-items': 'center', 'width': '100%',
3593
4351
  'padding': '1rem 1.25rem', 'font-size': '1rem', 'font-weight': '500', 'text-align': 'left',
3594
4352
  'background-color': 'transparent', 'border': '0', 'overflow-anchor': 'none', 'cursor': 'pointer',
3595
- 'font-family': 'inherit', 'transition': 'color 0.15s ease-in-out, background-color 0.15s ease-in-out'
4353
+ 'font-family': 'inherit', 'transition': 'color 0.15s ease-out, background-color 0.15s ease-out'
3596
4354
  };
3597
4355
  rules['.bw-accordion-button::after'] = {
3598
4356
  'flex-shrink': '0', 'width': '1.25rem', 'height': '1.25rem', 'margin-left': 'auto',
3599
4357
  'content': '""', 'background-repeat': 'no-repeat', 'background-size': '1.25rem',
3600
- 'transition': 'transform 0.2s ease-in-out'
4358
+ 'transition': 'transform 0.2s ease-out'
3601
4359
  };
3602
4360
  rules['.bw-accordion-button:not(.bw-collapsed)::after'] = { 'transform': 'rotate(-180deg)' };
3603
4361
  rules['.bw-accordion-collapse'] = { 'max-height': '0', 'overflow': 'hidden', 'transition': 'max-height 0.3s ease' };
@@ -3606,10 +4364,13 @@ export function getStructuralStyles() {
3606
4364
 
3607
4365
  // Modal (structural)
3608
4366
  rules['.bw-modal'] = {
3609
- 'display': 'none', 'position': 'fixed', 'top': '0', 'left': '0', 'width': '100%', 'height': '100%',
3610
- 'z-index': '1050', 'overflow-x': 'hidden', 'overflow-y': 'auto', 'opacity': '0', 'transition': 'opacity 0.15s linear'
4367
+ 'display': 'flex', 'align-items': 'center', 'justify-content': 'center',
4368
+ 'position': 'fixed', 'top': '0', 'left': '0', 'width': '100%', 'height': '100%',
4369
+ 'z-index': '1050', 'overflow-x': 'hidden', 'overflow-y': 'auto',
4370
+ 'opacity': '0', 'visibility': 'hidden', 'pointer-events': 'none',
4371
+ 'transition': 'opacity 0.2s ease, visibility 0.2s ease'
3611
4372
  };
3612
- rules['.bw-modal.bw-modal-show'] = { 'display': 'flex', 'align-items': 'center', 'justify-content': 'center', 'opacity': '1' };
4373
+ rules['.bw-modal.bw-modal-show'] = { 'opacity': '1', 'visibility': 'visible', 'pointer-events': 'auto' };
3613
4374
  rules['.bw-modal-dialog'] = {
3614
4375
  'position': 'relative', 'width': '100%', 'max-width': '500px', 'margin': '1.75rem auto',
3615
4376
  'pointer-events': 'none', 'transform': 'translateY(-20px)', 'transition': 'transform 0.2s ease-out'
@@ -3629,7 +4390,7 @@ export function getStructuralStyles() {
3629
4390
 
3630
4391
  // Carousel (structural)
3631
4392
  rules['.bw-carousel'] = { 'position': 'relative', 'overflow': 'hidden', 'border-radius': '8px' };
3632
- rules['.bw-carousel-track'] = { 'display': 'flex', 'transition': 'transform 0.4s ease', 'height': '100%' };
4393
+ rules['.bw-carousel-track'] = { 'display': 'flex', 'transition': 'transform 0.3s ease-out', 'height': '100%' };
3633
4394
  rules['.bw-carousel-slide'] = { 'min-width': '100%', 'flex-shrink': '0', 'overflow': 'hidden', 'position': 'relative', 'display': 'flex', 'align-items': 'center', 'justify-content': 'center' };
3634
4395
  rules['.bw-carousel-slide img'] = { 'width': '100%', 'height': '100%', 'object-fit': 'cover' };
3635
4396
  rules['.bw-carousel-caption'] = { 'position': 'absolute', 'bottom': '0', 'left': '0', 'right': '0', 'padding': '0.75rem 1rem' };
@@ -3673,11 +4434,14 @@ export function getStructuralStyles() {
3673
4434
  'border-bottom': '0', 'border-left': '0.3em solid transparent'
3674
4435
  };
3675
4436
  rules['.bw-dropdown-menu'] = {
3676
- 'position': 'absolute', 'top': '100%', 'left': '0', 'z-index': '1000', 'display': 'none',
4437
+ 'position': 'absolute', 'top': '100%', 'left': '0', 'z-index': '1000', 'display': 'block',
3677
4438
  'min-width': '10rem', 'padding': '0.5rem 0', 'margin': '0.125rem 0 0',
3678
- 'background-clip': 'padding-box', 'border-radius': '6px'
4439
+ 'background-clip': 'padding-box', 'border-radius': '6px',
4440
+ 'opacity': '0', 'visibility': 'hidden', 'transform': 'translateY(-4px)',
4441
+ 'pointer-events': 'none',
4442
+ 'transition': 'opacity 0.15s ease, transform 0.15s ease, visibility 0.15s ease'
3679
4443
  };
3680
- rules['.bw-dropdown-menu.bw-dropdown-show'] = { 'display': 'block' };
4444
+ rules['.bw-dropdown-menu.bw-dropdown-show'] = { 'opacity': '1', 'visibility': 'visible', 'transform': 'translateY(0)', 'pointer-events': 'auto' };
3681
4445
  rules['.bw-dropdown-menu-end'] = { 'left': 'auto', 'right': '0' };
3682
4446
  rules['.bw-dropdown-item'] = {
3683
4447
  'display': 'block', 'width': '100%', 'padding': '0.375rem 1rem', 'clear': 'both',
@@ -3685,6 +4449,7 @@ export function getStructuralStyles() {
3685
4449
  'background-color': 'transparent', 'border': '0', 'font-size': '0.9375rem',
3686
4450
  'transition': 'background-color 0.15s, color 0.15s'
3687
4451
  };
4452
+ rules['.bw-dropdown-item:focus-visible'] = { 'outline': '2px solid currentColor', 'outline-offset': '-2px' };
3688
4453
  rules['.bw-dropdown-divider'] = { 'height': '0', 'margin': '0.5rem 0', 'overflow': 'hidden', 'opacity': '1' };
3689
4454
 
3690
4455
  // Switch (structural)
@@ -3692,7 +4457,7 @@ export function getStructuralStyles() {
3692
4457
  rules['.bw-form-switch .bw-switch-input'] = {
3693
4458
  'width': '2em', 'height': '1.125em', 'margin-left': '-2.5em', 'border-radius': '2em',
3694
4459
  'appearance': 'none', 'background-position': 'left center', 'background-repeat': 'no-repeat',
3695
- 'background-size': 'contain', 'transition': 'background-position 0.15s ease-in-out, background-color 0.15s ease-in-out',
4460
+ 'background-size': 'contain', 'transition': 'background-position 0.15s ease-out, background-color 0.15s ease-out',
3696
4461
  'cursor': 'pointer'
3697
4462
  };
3698
4463
  rules['.bw-form-switch .bw-switch-input:checked'] = { 'background-position': 'right center' };
@@ -3717,6 +4482,123 @@ export function getStructuralStyles() {
3717
4482
  rules['.bw-avatar-lg'] = { 'width': '4rem', 'height': '4rem', 'font-size': '1.25rem' };
3718
4483
  rules['.bw-avatar-xl'] = { 'width': '5rem', 'height': '5rem', 'font-size': '1.5rem' };
3719
4484
 
4485
+ // Stat card (structural)
4486
+ rules['.bw-stat-card'] = {
4487
+ 'border-radius': '8px', 'padding': '1.25rem',
4488
+ 'border-left': '4px solid transparent',
4489
+ 'transition': 'box-shadow 0.15s ease-out, transform 0.15s ease-out'
4490
+ };
4491
+ rules['.bw-stat-card:hover'] = { 'transform': 'translateY(-1px)' };
4492
+ rules['.bw-stat-icon'] = { 'font-size': '1.5rem', 'margin-bottom': '0.5rem' };
4493
+ rules['.bw-stat-value'] = { 'font-size': '2rem', 'font-weight': '700', 'line-height': '1.2' };
4494
+ rules['.bw-stat-label'] = { 'font-size': '0.875rem', 'margin-top': '0.25rem' };
4495
+ rules['.bw-stat-change'] = { 'font-size': '0.875rem', 'font-weight': '500', 'margin-top': '0.5rem' };
4496
+
4497
+ // Tooltip (structural)
4498
+ rules['.bw-tooltip-wrapper'] = { 'position': 'relative', 'display': 'inline-block' };
4499
+ rules['.bw-tooltip'] = {
4500
+ 'position': 'absolute', 'z-index': '999',
4501
+ 'padding': '0.375rem 0.75rem', 'border-radius': '4px', 'font-size': '0.875rem',
4502
+ 'white-space': 'nowrap', 'pointer-events': 'none',
4503
+ 'opacity': '0', 'visibility': 'hidden',
4504
+ 'transition': 'opacity 0.15s ease, visibility 0.15s ease, transform 0.15s ease'
4505
+ };
4506
+ rules['.bw-tooltip.bw-tooltip-show'] = { 'opacity': '1', 'visibility': 'visible' };
4507
+ rules['.bw-tooltip-top'] = { 'bottom': '100%', 'left': '50%', 'transform': 'translateX(-50%) translateY(-4px)', 'margin-bottom': '4px' };
4508
+ rules['.bw-tooltip-top.bw-tooltip-show'] = { 'transform': 'translateX(-50%) translateY(0)' };
4509
+ rules['.bw-tooltip-bottom'] = { 'top': '100%', 'left': '50%', 'transform': 'translateX(-50%) translateY(4px)', 'margin-top': '4px' };
4510
+ rules['.bw-tooltip-bottom.bw-tooltip-show'] = { 'transform': 'translateX(-50%) translateY(0)' };
4511
+ rules['.bw-tooltip-left'] = { 'right': '100%', 'top': '50%', 'transform': 'translateY(-50%) translateX(-4px)', 'margin-right': '4px' };
4512
+ rules['.bw-tooltip-left.bw-tooltip-show'] = { 'transform': 'translateY(-50%) translateX(0)' };
4513
+ rules['.bw-tooltip-right'] = { 'left': '100%', 'top': '50%', 'transform': 'translateY(-50%) translateX(4px)', 'margin-left': '4px' };
4514
+ rules['.bw-tooltip-right.bw-tooltip-show'] = { 'transform': 'translateY(-50%) translateX(0)' };
4515
+
4516
+ // Search input (structural)
4517
+ rules['.bw-search-input'] = { 'position': 'relative', 'display': 'flex', 'align-items': 'center' };
4518
+ rules['.bw-search-input .bw-search-field'] = { 'padding-right': '2.5rem' };
4519
+ rules['.bw-search-clear'] = {
4520
+ 'position': 'absolute', 'right': '0.5rem',
4521
+ 'display': 'flex', 'align-items': 'center', 'justify-content': 'center',
4522
+ 'width': '1.5rem', 'height': '1.5rem',
4523
+ 'border': 'none', 'background': 'none',
4524
+ 'font-size': '1.25rem', 'cursor': 'pointer', 'padding': '0',
4525
+ 'border-radius': '50%', 'transition': 'color 0.15s ease-out'
4526
+ };
4527
+
4528
+ // Range slider (structural)
4529
+ rules['.bw-range-wrapper'] = { 'margin-bottom': '1rem' };
4530
+ rules['.bw-range-label'] = { 'display': 'flex', 'justify-content': 'space-between', 'align-items': 'center', 'margin-bottom': '0.5rem', 'font-size': '0.875rem', 'font-weight': '500' };
4531
+ rules['.bw-range-value'] = { 'font-weight': '600' };
4532
+ rules['.bw-range'] = { 'width': '100%', 'height': '0.5rem', 'padding': '0', 'appearance': 'none', 'border': 'none', 'border-radius': '0.25rem', 'cursor': 'pointer', 'outline': 'none' };
4533
+ rules['.bw-range:disabled'] = { 'opacity': '0.5', 'cursor': 'not-allowed' };
4534
+
4535
+ // Media object (structural)
4536
+ rules['.bw-media'] = { 'display': 'flex', 'align-items': 'flex-start', 'gap': '1rem' };
4537
+ rules['.bw-media-reverse'] = { 'flex-direction': 'row-reverse' };
4538
+ rules['.bw-media-img'] = { 'border-radius': '50%', 'object-fit': 'cover', 'flex-shrink': '0' };
4539
+ rules['.bw-media-body'] = { 'flex': '1', 'min-width': '0' };
4540
+ rules['.bw-media-title'] = { 'margin': '0 0 0.25rem 0', 'font-size': '1rem', 'font-weight': '600', 'line-height': '1.3' };
4541
+
4542
+ // File upload (structural)
4543
+ rules['.bw-file-upload'] = {
4544
+ 'display': 'flex', 'flex-direction': 'column', 'align-items': 'center', 'justify-content': 'center',
4545
+ 'padding': '2rem', 'border': '2px dashed transparent', 'border-radius': '8px',
4546
+ 'cursor': 'pointer', 'text-align': 'center', 'position': 'relative',
4547
+ 'transition': 'border-color 0.15s ease-out, background-color 0.15s ease-out'
4548
+ };
4549
+ rules['.bw-file-upload-icon'] = { 'font-size': '2rem', 'margin-bottom': '0.5rem' };
4550
+ rules['.bw-file-upload-text'] = { 'font-size': '0.875rem' };
4551
+ rules['.bw-file-upload-input'] = {
4552
+ 'position': 'absolute', 'width': '1px', 'height': '1px', 'padding': '0',
4553
+ 'margin': '-1px', 'overflow': 'hidden', 'clip': 'rect(0,0,0,0)', 'border': '0'
4554
+ };
4555
+
4556
+ // Timeline (structural)
4557
+ rules['.bw-timeline'] = { 'position': 'relative', 'padding-left': '2rem' };
4558
+ rules['.bw-timeline-item'] = { 'position': 'relative', 'padding-bottom': '1.5rem' };
4559
+ rules['.bw-timeline-item:last-child'] = { 'padding-bottom': '0' };
4560
+ rules['.bw-timeline-marker'] = { 'position': 'absolute', 'left': '-1.75rem', 'top': '0.25rem', 'width': '0.75rem', 'height': '0.75rem', 'border-radius': '50%' };
4561
+ rules['.bw-timeline-content'] = { 'padding-left': '0.5rem' };
4562
+ rules['.bw-timeline-date'] = { 'font-size': '0.75rem', 'margin-bottom': '0.25rem', 'font-weight': '500' };
4563
+ rules['.bw-timeline-title'] = { 'font-size': '1rem', 'font-weight': '600', 'margin': '0 0 0.25rem 0', 'line-height': '1.3' };
4564
+ rules['.bw-timeline-text'] = { 'font-size': '0.875rem', 'margin': '0', 'line-height': '1.5' };
4565
+
4566
+ // Stepper (structural)
4567
+ rules['.bw-stepper'] = { 'display': 'flex', 'gap': '0' };
4568
+ rules['.bw-step'] = { 'flex': '1', 'display': 'flex', 'flex-direction': 'column', 'align-items': 'center', 'text-align': 'center', 'position': 'relative' };
4569
+ rules['.bw-step-indicator'] = { 'width': '2rem', 'height': '2rem', 'border-radius': '50%', 'display': 'flex', 'align-items': 'center', 'justify-content': 'center', 'font-size': '0.875rem', 'font-weight': '600', 'position': 'relative', 'z-index': '1', 'transition': 'background-color 0.2s ease-out, color 0.2s ease-out' };
4570
+ rules['.bw-step-body'] = { 'margin-top': '0.5rem' };
4571
+ rules['.bw-step-label'] = { 'font-size': '0.875rem', 'font-weight': '500' };
4572
+ rules['.bw-step-description'] = { 'font-size': '0.75rem', 'margin-top': '0.125rem' };
4573
+
4574
+ // Chip input (structural)
4575
+ rules['.bw-chip-input'] = { 'display': 'flex', 'flex-wrap': 'wrap', 'align-items': 'center', 'gap': '0.375rem', 'padding': '0.375rem 0.5rem', 'border-radius': '6px', 'min-height': '2.5rem', 'cursor': 'text', 'transition': 'border-color 0.15s ease-out, box-shadow 0.15s ease-out' };
4576
+ rules['.bw-chip'] = { 'display': 'inline-flex', 'align-items': 'center', 'gap': '0.25rem', 'padding': '0.125rem 0.5rem', 'border-radius': '1rem', 'font-size': '0.8125rem', 'line-height': '1.5', 'white-space': 'nowrap' };
4577
+ rules['.bw-chip-remove'] = { 'display': 'inline-flex', 'align-items': 'center', 'justify-content': 'center', 'width': '1rem', 'height': '1rem', 'border': 'none', 'background': 'none', 'font-size': '0.875rem', 'cursor': 'pointer', 'padding': '0', 'border-radius': '50%', 'transition': 'color 0.15s ease-out, background-color 0.15s ease-out' };
4578
+ rules['.bw-chip-field'] = { 'flex': '1', 'min-width': '80px', 'border': 'none', 'outline': 'none', 'font-size': '0.875rem', 'padding': '0.125rem 0', 'background': 'transparent' };
4579
+
4580
+ // Popover (structural)
4581
+ rules['.bw-popover-wrapper'] = { 'position': 'relative', 'display': 'inline-block' };
4582
+ rules['.bw-popover-trigger'] = { 'cursor': 'pointer' };
4583
+ rules['.bw-popover'] = {
4584
+ 'position': 'absolute', 'z-index': '1000',
4585
+ 'min-width': '200px', 'max-width': '320px',
4586
+ 'border-radius': '8px',
4587
+ 'pointer-events': 'none', 'opacity': '0', 'visibility': 'hidden',
4588
+ 'transition': 'opacity 0.15s ease, visibility 0.15s ease, transform 0.15s ease'
4589
+ };
4590
+ rules['.bw-popover.bw-popover-show'] = { 'opacity': '1', 'visibility': 'visible', 'pointer-events': 'auto' };
4591
+ rules['.bw-popover-header'] = { 'padding': '0.625rem 0.875rem', 'font-weight': '600', 'font-size': '0.9375rem' };
4592
+ rules['.bw-popover-body'] = { 'padding': '0.75rem 0.875rem', 'font-size': '0.875rem', 'line-height': '1.5' };
4593
+ rules['.bw-popover-top'] = { 'bottom': '100%', 'left': '50%', 'transform': 'translateX(-50%) translateY(-8px)', 'margin-bottom': '8px' };
4594
+ rules['.bw-popover-top.bw-popover-show'] = { 'transform': 'translateX(-50%) translateY(0)' };
4595
+ rules['.bw-popover-bottom'] = { 'top': '100%', 'left': '50%', 'transform': 'translateX(-50%) translateY(8px)', 'margin-top': '8px' };
4596
+ rules['.bw-popover-bottom.bw-popover-show'] = { 'transform': 'translateX(-50%) translateY(0)' };
4597
+ rules['.bw-popover-left'] = { 'right': '100%', 'top': '50%', 'transform': 'translateY(-50%) translateX(-8px)', 'margin-right': '8px' };
4598
+ rules['.bw-popover-left.bw-popover-show'] = { 'transform': 'translateY(-50%) translateX(0)' };
4599
+ rules['.bw-popover-right'] = { 'left': '100%', 'top': '50%', 'transform': 'translateY(-50%) translateX(8px)', 'margin-left': '8px' };
4600
+ rules['.bw-popover-right.bw-popover-show'] = { 'transform': 'translateY(-50%) translateX(0)' };
4601
+
3720
4602
  // Bar chart (structural)
3721
4603
  rules['.bw-bar-chart-container'] = {
3722
4604
  'padding': '1rem', 'border': '1px solid transparent', 'border-radius': '8px'
@@ -3730,7 +4612,7 @@ export function getStructuralStyles() {
3730
4612
  };
3731
4613
  rules['.bw-bar'] = {
3732
4614
  'width': '100%', 'border-radius': '3px 3px 0 0',
3733
- 'transition': 'height 0.5s ease', 'min-height': '4px'
4615
+ 'transition': 'height 0.3s ease-out', 'min-height': '4px'
3734
4616
  };
3735
4617
  rules['.bw-bar:hover'] = { 'opacity': '0.85' };
3736
4618
  rules['.bw-bar-value'] = {
@@ -3859,6 +4741,16 @@ export function getStructuralStyles() {
3859
4741
  // Responsive grid
3860
4742
  Object.assign(rules, defaultStyles.responsive);
3861
4743
 
4744
+ // Accessibility: reduce motion for users who prefer it
4745
+ rules['@media (prefers-reduced-motion: reduce)'] = {
4746
+ '*, *::before, *::after': {
4747
+ 'animation-duration': '0.01ms !important',
4748
+ 'animation-iteration-count': '1 !important',
4749
+ 'transition-duration': '0.01ms !important',
4750
+ 'scroll-behavior': 'auto !important'
4751
+ }
4752
+ };
4753
+
3862
4754
  return addUnderscoreAliases(rules);
3863
4755
  }
3864
4756
 
@@ -3867,9 +4759,25 @@ export function getStructuralStyles() {
3867
4759
  // =========================================================================
3868
4760
 
3869
4761
  /**
3870
- * Add underscore aliases for all bw- selectors
4762
+ * Add underscore aliases for all `.bw-` selectors.
4763
+ *
4764
+ * CSS CLASS NAMING CONVENTION:
4765
+ *
4766
+ * Canonical form: `.bw-btn`, `.bw-card`, `.bw-table-hover` (hyphens)
4767
+ * Underscore alias: `.bw_btn`, `.bw_card`, `.bw_table_hover` (underscores)
4768
+ *
4769
+ * Both forms are valid in HTML and produce identical results. The hyphen
4770
+ * form is canonical (used in docs, generated CSS, component output).
4771
+ * Underscore aliases exist because:
4772
+ * 1. TACO attribute keys use underscores (`bw_id`, `bw_meta`) — no
4773
+ * quoting needed in JS object literals
4774
+ * 2. Some users prefer underscores for consistency with JS identifiers
4775
+ *
4776
+ * Use `bw.normalizeClass()` to convert underscore classes to canonical
4777
+ * hyphen form at runtime if needed.
4778
+ *
3871
4779
  * @param {Object} rules - CSS rules object
3872
- * @returns {Object} - Rules with underscore aliases added
4780
+ * @returns {Object} Rules with underscore aliases added (both forms work)
3873
4781
  */
3874
4782
  export function addUnderscoreAliases(rules) {
3875
4783
  const result = {};
@@ -3922,6 +4830,16 @@ export function getAllStyles() {
3922
4830
  defaultStyles.formSwitch,
3923
4831
  defaultStyles.skeleton,
3924
4832
  defaultStyles.avatar,
4833
+ defaultStyles.statCard,
4834
+ defaultStyles.tooltip,
4835
+ defaultStyles.popover,
4836
+ defaultStyles.searchInput,
4837
+ defaultStyles.range,
4838
+ defaultStyles.mediaObject,
4839
+ defaultStyles.fileUpload,
4840
+ defaultStyles.timeline,
4841
+ defaultStyles.stepper,
4842
+ defaultStyles.chipInput,
3925
4843
  defaultStyles.utilities,
3926
4844
  defaultStyles.responsive
3927
4845
  );
@@ -3931,6 +4849,27 @@ export function getAllStyles() {
3931
4849
  // =========================================================================
3932
4850
  // Theme tokens (backwards compatible)
3933
4851
  // =========================================================================
4852
+ //
4853
+ // DESIGN NOTE — Why no CSS custom properties (CSS variables)?
4854
+ //
4855
+ // Bitwrench targets IE11 as Tier 1 (see dev/bw2x-compatibility.md).
4856
+ // CSS custom properties (var(--color-primary)) are not supported in IE11.
4857
+ //
4858
+ // Instead, bitwrench uses class-scoped CSS generation:
4859
+ // 1. `defaultStyles.*` provides hardcoded cosmetic defaults
4860
+ // 2. `generateTheme(name, config)` generates a complete set of
4861
+ // class-scoped CSS rules from 3 seed colors (primary, secondary,
4862
+ // tertiary) — all components are restyled with the new palette
4863
+ // 3. `generateAlternateCSS()` produces the alternate (dark/light)
4864
+ // variant scoped under `.bw-theme-alt`
4865
+ //
4866
+ // This achieves full theme customization without CSS variables:
4867
+ // bw.generateTheme('ocean', { primary: '#006666', secondary: '#cc6633' })
4868
+ // → generates .ocean .bw-btn-primary { background: #006666; } etc.
4869
+ //
4870
+ // When IE11 support is dropped, CSS custom properties can be added as
4871
+ // an optimization (one rule with var() instead of many scoped rules).
4872
+ // The generateTheme() API stays the same — only the output format changes.
3934
4873
 
3935
4874
  export let theme = {
3936
4875
  colors: {
@@ -3938,8 +4877,8 @@ export let theme = {
3938
4877
  secondary: '#6c757d',
3939
4878
  success: '#198754',
3940
4879
  danger: '#dc3545',
3941
- warning: '#ffc107',
3942
- info: '#0dcaf0',
4880
+ warning: '#b38600',
4881
+ info: '#0891b2',
3943
4882
  light: '#f8f9fa',
3944
4883
  dark: '#212529',
3945
4884
  white: '#fff',
@@ -3975,274 +4914,63 @@ export let theme = {
3975
4914
  '5xl': '3rem'
3976
4915
  }
3977
4916
  },
3978
- darkMode: false
3979
- };
3980
-
3981
- export const darkModeColors = {
3982
- '--bw-body-color': '#e9ecef',
3983
- '--bw-body-bg': '#1a1a2e',
3984
- '--bw-border-color': '#495057',
3985
- '--bw-gray-100': '#212529',
3986
- '--bw-gray-200': '#343a40',
3987
- '--bw-gray-300': '#495057',
3988
- '--bw-gray-800': '#e9ecef',
3989
- '--bw-gray-900': '#f8f9fa'
3990
4917
  };
3991
4918
 
3992
4919
  /**
3993
- * Generate theme-aware dark mode CSS from a palette.
3994
- * Derives dark variants from the palette colors instead of using hardcoded values.
4920
+ * Generate alternate-palette CSS scoped under `.bw-theme-alt`.
4921
+ * Uses the same `generateThemedCSS()` pipeline as the primary palette
4922
+ * both sides go through identical code paths.
3995
4923
  *
3996
- * @param {Object} palette - From derivePalette()
3997
- * @returns {Object} CSS rules object for dark mode
4924
+ * @param {string} name - Theme scope name (e.g. 'ocean'). '' for global.
4925
+ * @param {Object} altPalette - From derivePalette(deriveAlternateConfig(...))
4926
+ * @param {Object} layout - From resolveLayout()
4927
+ * @returns {Object} CSS rules object scoped under .bw-theme-alt (+ optional .name)
3998
4928
  */
3999
- export function generateDarkModeCSS(palette) {
4000
- var darkBg = adjustLightness(palette.primary.base, -15);
4001
- var darkBgHsl = hexToHsl(darkBg);
4002
- // Make it very dark (lightness 8-12%)
4003
- var bodyBg = hslToHex([darkBgHsl[0], Math.min(darkBgHsl[1], 30), 10]);
4004
- var surfaceBg = hslToHex([darkBgHsl[0], Math.min(darkBgHsl[1], 25), 15]);
4005
- var textColor = adjustLightness(palette.light.base, 5);
4006
- var borderColor = hslToHex([darkBgHsl[0], Math.min(darkBgHsl[1], 15), 30]);
4007
-
4008
- return {
4009
- ':root.bw-dark': {
4010
- '--bw-body-color': textColor,
4011
- '--bw-body-bg': bodyBg
4012
- },
4013
- '.bw-dark body, :root.bw-dark body': {
4014
- 'color': textColor,
4015
- 'background-color': bodyBg
4016
- },
4017
- '.bw-dark .bw-card': {
4018
- 'background-color': surfaceBg,
4019
- 'border-color': borderColor,
4020
- 'color': textColor
4021
- },
4022
- '.bw-dark .bw-card-header': {
4023
- 'background-color': bodyBg,
4024
- 'border-bottom-color': borderColor,
4025
- 'color': textColor
4026
- },
4027
- '.bw-dark .bw-card-footer': {
4028
- 'background-color': bodyBg,
4029
- 'border-top-color': borderColor,
4030
- 'color': textColor
4031
- },
4032
- '.bw-dark .bw-card-title': {
4033
- 'color': textColor
4034
- },
4035
- '.bw-dark .bw-navbar': {
4036
- 'background-color': surfaceBg,
4037
- 'border-bottom-color': borderColor
4038
- },
4039
- '.bw-dark .bw-navbar-brand': {
4040
- 'color': textColor
4041
- },
4042
- '.bw-dark .bw-navbar-nav .bw-nav-link': {
4043
- 'color': adjustLightness(textColor, -15)
4044
- },
4045
- '.bw-dark .bw-navbar-nav .bw-nav-link:hover': {
4046
- 'color': textColor
4047
- },
4048
- '.bw-dark .bw-form-control': {
4049
- 'background-color': surfaceBg,
4050
- 'border-color': borderColor,
4051
- 'color': textColor
4052
- },
4053
- '.bw-dark .bw-form-label': {
4054
- 'color': textColor
4055
- },
4056
- '.bw-dark .bw-form-text': {
4057
- 'color': adjustLightness(textColor, -20)
4058
- },
4059
- '.bw-dark .bw-table': {
4060
- 'color': textColor
4061
- },
4062
- '.bw-dark .bw-table > :not(caption) > * > *': {
4063
- 'border-bottom-color': borderColor
4064
- },
4065
- '.bw-dark .bw-table > thead > tr > *': {
4066
- 'background-color': bodyBg,
4067
- 'color': adjustLightness(textColor, -10),
4068
- 'border-bottom-color': borderColor
4069
- },
4070
- '.bw-dark .bw-table-striped > tbody > tr:nth-of-type(odd) > *': {
4071
- 'background-color': 'rgba(255, 255, 255, 0.05)'
4072
- },
4073
- '.bw-dark .bw-alert': {
4074
- 'border-color': borderColor
4075
- },
4076
- '.bw-dark .bw-list-group-item': {
4077
- 'background-color': surfaceBg,
4078
- 'border-color': borderColor,
4079
- 'color': textColor
4080
- },
4081
- '.bw-dark .bw-badge': {
4082
- 'color': textColor
4083
- },
4084
- '.bw-dark .bw-nav-tabs': {
4085
- 'border-bottom-color': borderColor
4086
- },
4087
- '.bw-dark .bw-nav-link': {
4088
- 'color': adjustLightness(textColor, -15)
4089
- },
4090
- '.bw-dark .bw-nav-tabs .bw-nav-link:hover': {
4091
- 'color': textColor,
4092
- 'border-bottom-color': borderColor
4093
- },
4094
- '.bw-dark .bw-pagination .bw-page-link': {
4095
- 'background-color': surfaceBg,
4096
- 'border-color': borderColor,
4097
- 'color': textColor
4098
- },
4099
- '.bw-dark .bw-breadcrumb-item + .bw-breadcrumb-item::before': {
4100
- 'color': adjustLightness(textColor, -20)
4101
- },
4102
- '.bw-dark .bw-breadcrumb-item.active': {
4103
- 'color': adjustLightness(textColor, -10)
4104
- },
4105
- '.bw-dark .bw-hero-light': {
4106
- 'background': surfaceBg,
4107
- 'color': textColor
4108
- },
4109
- '.bw-dark .bw-progress': {
4110
- 'background-color': surfaceBg
4111
- },
4112
- '.bw-dark .bw-section-subtitle': {
4113
- 'color': adjustLightness(textColor, -15)
4114
- },
4115
- '.bw-dark .bw-close': {
4116
- 'color': textColor
4117
- },
4118
- '.bw-dark .bw-accordion-item': {
4119
- 'background-color': surfaceBg,
4120
- 'border-color': borderColor
4121
- },
4122
- '.bw-dark .bw-accordion-button': {
4123
- 'color': textColor
4124
- },
4125
- '.bw-dark .bw-accordion-button:not(.bw-collapsed)': {
4126
- 'color': '#7dd3e0',
4127
- 'background-color': 'rgba(125, 211, 224, 0.1)'
4128
- },
4129
- '.bw-dark .bw-accordion-button:hover': {
4130
- 'background-color': bodyBg
4131
- },
4132
- '.bw-dark .bw-accordion-button:not(.bw-collapsed):hover': {
4133
- 'background-color': 'rgba(125, 211, 224, 0.15)'
4134
- },
4135
- '.bw-dark .bw-accordion-button:focus-visible': {
4136
- 'box-shadow': '0 0 0 0.2rem rgba(125, 211, 224, 0.3)'
4137
- },
4138
- '.bw-dark .bw-accordion-body': {
4139
- 'border-top-color': borderColor
4140
- },
4141
- '.bw-dark .bw-carousel': {
4142
- 'background-color': bodyBg
4143
- },
4144
- '.bw-dark .bw-carousel-control': {
4145
- 'background-color': 'rgba(255,255,255,0.15)'
4146
- },
4147
- '.bw-dark .bw-carousel-control:hover': {
4148
- 'background-color': 'rgba(255,255,255,0.25)'
4149
- },
4150
- '.bw-dark .bw-modal-content': {
4151
- 'background-color': surfaceBg,
4152
- 'border-color': borderColor
4153
- },
4154
- '.bw-dark .bw-modal-header': {
4155
- 'border-bottom-color': borderColor
4156
- },
4157
- '.bw-dark .bw-modal-footer': {
4158
- 'border-top-color': borderColor
4159
- },
4160
- '.bw-dark .bw-modal-title': {
4161
- 'color': textColor
4162
- },
4163
- '.bw-dark .bw-toast': {
4164
- 'background-color': surfaceBg,
4165
- 'border-color': borderColor
4166
- },
4167
- '.bw-dark .bw-toast-header': {
4168
- 'border-bottom-color': borderColor,
4169
- 'color': textColor
4170
- },
4171
- '.bw-dark .bw-dropdown-menu': {
4172
- 'background-color': surfaceBg,
4173
- 'border-color': borderColor
4174
- },
4175
- '.bw-dark .bw-dropdown-item': {
4176
- 'color': textColor
4177
- },
4178
- '.bw-dark .bw-dropdown-item:hover': {
4179
- 'background-color': bodyBg
4180
- },
4181
- '.bw-dark .bw-dropdown-divider': {
4182
- 'border-top-color': borderColor
4183
- },
4184
- '.bw-dark .bw-skeleton': {
4185
- 'background': 'linear-gradient(90deg, ' + borderColor + ' 25%, ' + surfaceBg + ' 37%, ' + borderColor + ' 63%)'
4186
- },
4187
- '.bw-dark h1, .bw-dark h2, .bw-dark h3, .bw-dark h4, .bw-dark h5, .bw-dark h6': {
4188
- 'color': textColor
4189
- },
4190
- '@media (prefers-color-scheme: dark)': {
4191
- ':root.bw-auto-dark body': {
4192
- 'color': textColor,
4193
- 'background-color': bodyBg
4929
+ export function generateAlternateCSS(name, altPalette, layout) {
4930
+ // Generate themed CSS using the same pipeline as primary
4931
+ var rawRules = generateThemedCSS('', altPalette, layout);
4932
+
4933
+ // Re-scope every selector under .bw-theme-alt (+ optional theme name)
4934
+ var altPrefix = name ? '.' + name + '.bw-theme-alt' : '.bw-theme-alt';
4935
+ var altRules = {};
4936
+
4937
+ for (var sel in rawRules) {
4938
+ if (!rawRules.hasOwnProperty(sel)) continue;
4939
+
4940
+ if (sel.charAt(0) === '@') {
4941
+ // @media / @keyframes — recurse into the block
4942
+ var innerBlock = rawRules[sel];
4943
+ var altInner = {};
4944
+ for (var innerSel in innerBlock) {
4945
+ if (!innerBlock.hasOwnProperty(innerSel)) continue;
4946
+ altInner[altPrefix + ' ' + innerSel] = innerBlock[innerSel];
4194
4947
  }
4195
- }
4196
- };
4197
- }
4198
-
4199
- export function getDarkModeStyles() {
4200
- return {
4201
- ':root.bw-dark': {
4202
- '--bw-body-color': '#e9ecef',
4203
- '--bw-body-bg': '#1a1a2e'
4204
- },
4205
- '.bw-dark body, :root.bw-dark body': {
4206
- 'color': '#e9ecef',
4207
- 'background-color': '#1a1a2e'
4208
- },
4209
- '.bw-dark .bw-card': {
4210
- 'background-color': '#16213e',
4211
- 'border-color': '#495057',
4212
- 'color': '#e9ecef'
4213
- },
4214
- '.bw-dark .bw-navbar': {
4215
- 'background-color': '#0f3460'
4216
- },
4217
- '.bw-dark .bw-form-control': {
4218
- 'background-color': '#16213e',
4219
- 'border-color': '#495057',
4220
- 'color': '#e9ecef'
4221
- },
4222
- '.bw-dark .bw-table': {
4223
- 'color': '#e9ecef'
4224
- },
4225
- '.bw-dark .bw-table > :not(caption) > * > *': {
4226
- 'border-bottom-color': '#495057'
4227
- },
4228
- '.bw-dark .bw-table-striped > tbody > tr:nth-of-type(odd) > *': {
4229
- 'background-color': 'rgba(255, 255, 255, 0.05)'
4230
- },
4231
- '.bw-dark .bw-alert': {
4232
- 'border-color': '#495057'
4233
- },
4234
- '.bw-dark .bw-list-group-item': {
4235
- 'background-color': '#16213e',
4236
- 'border-color': '#495057',
4237
- 'color': '#e9ecef'
4238
- },
4239
- '@media (prefers-color-scheme: dark)': {
4240
- ':root.bw-auto-dark body': {
4241
- 'color': '#e9ecef',
4242
- 'background-color': '#1a1a2e'
4948
+ altRules[sel] = altInner;
4949
+ } else {
4950
+ // Regular selector — prefix with alt scope
4951
+ // Handle comma-separated selectors
4952
+ var parts = sel.split(',');
4953
+ var scopedParts = [];
4954
+ for (var i = 0; i < parts.length; i++) {
4955
+ var s = parts[i].trim();
4956
+ // 'body' selector gets special treatment: .bw-theme-alt body
4957
+ if (s === 'body' || s.indexOf('body') === 0) {
4958
+ scopedParts.push(altPrefix + ' ' + s);
4959
+ } else {
4960
+ scopedParts.push(altPrefix + ' ' + s);
4961
+ }
4243
4962
  }
4963
+ altRules[scopedParts.join(', ')] = rawRules[sel];
4244
4964
  }
4965
+ }
4966
+
4967
+ // Add body-level overrides for the alternate surface
4968
+ altRules[altPrefix + ' body, :root' + altPrefix + ' body'] = {
4969
+ 'color': altPalette.dark.base,
4970
+ 'background-color': altPalette.light.base
4245
4971
  };
4972
+
4973
+ return altRules;
4246
4974
  }
4247
4975
 
4248
4976
  export function deepMerge(target, source) {