strata-css 1.1.0 → 1.2.6

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strata-css",
3
- "version": "1.1.0",
3
+ "version": "1.2.6",
4
4
  "_versioningNote": "Stable: 1.0.0 / 1.1.0 / 2.0.0 | Beta: 1.1.0-beta.1 / 1.1.0-beta.2",
5
5
  "description": "A modern CSS framework combining Bootstrap components with Tailwind JIT processing",
6
6
  "main": "src/index.js",
@@ -253,6 +253,10 @@ const BASE_CSS = `
253
253
  font-family: inherit;
254
254
  }
255
255
 
256
+ label {
257
+ display: inline-block;
258
+ }
259
+
256
260
  input, button, select, textarea {
257
261
  font-family: inherit;
258
262
  font-size: inherit;
@@ -18,6 +18,10 @@ function escapeClass(cls) {
18
18
  .replace(/\//g, '\\/')
19
19
  .replace(/:/g, '\\:')
20
20
  .replace(/\./g, '\\.')
21
+ .replace(/#/g, '\\#')
22
+ .replace(/\(/g, '\\(')
23
+ .replace(/\)/g, '\\)')
24
+ .replace(/,/g, '\\,')
21
25
  }
22
26
 
23
27
  function parseArbitrary(value) {
@@ -510,12 +514,13 @@ reg('card-img', 'components', `.card-img {
510
514
  }`)
511
515
 
512
516
  reg('card-img-overlay', 'components', `.card-img-overlay {
517
+ --st-card-overlay-color: #fff;
513
518
  position: absolute;
514
519
  inset: 0;
515
520
  padding: 1rem;
516
521
  border-radius: calc(var(--st-border-radius) - 1px);
517
522
  background: rgba(0, 0, 0, 0.45);
518
- color: #fff;
523
+ color: var(--st-card-overlay-color);
519
524
  }`)
520
525
 
521
526
  reg('card-group', 'components', `.card-group {
@@ -598,12 +603,13 @@ reg('alert-link', 'components', `.alert-link {
598
603
  // ─── Components — Badge ──────────────────────────────────────────────
599
604
 
600
605
  reg('badge', 'components', `.badge {
606
+ --st-badge-color: #fff;
601
607
  display: inline-block;
602
608
  padding: 0.35em 0.65em;
603
609
  font-size: 0.75em;
604
610
  font-weight: 700;
605
611
  line-height: 1;
606
- color: #fff;
612
+ color: var(--st-badge-color);
607
613
  text-align: center;
608
614
  white-space: nowrap;
609
615
  vertical-align: baseline;
@@ -613,23 +619,61 @@ reg('badge', 'components', `.badge {
613
619
 
614
620
  const BADGE_COLORS = ['primary','secondary','success','danger','warning','info','light','dark']
615
621
  BADGE_COLORS.forEach(color => {
616
- const textColor = ['warning','info','light'].includes(color) ? 'var(--st-dark)' : '#fff'
622
+ const defaultFg = ['warning','info','light'].includes(color) ? 'var(--st-dark)' : '#fff'
617
623
  reg(`badge-${color}`, 'components', `.badge-${color} {
624
+ --st-badge-color: ${defaultFg};
618
625
  background-color: var(--st-${color});
619
- color: ${textColor};
626
+ color: var(--st-badge-color);
620
627
  }`)
621
628
  })
622
629
 
623
630
  reg('badge-pill', 'components', `.badge-pill { border-radius: 999px; }`)
624
631
  reg('rounded-pill', 'components', `.rounded-pill { border-radius: 999px; }`)
625
632
 
633
+ // ─── Components — Label (Bootstrap 3 aliases) ────────────────────────
634
+ // .label and .label-{color} are Bootstrap 3's label component.
635
+ // Bootstrap 4+ renamed them to .badge / .badge-{color}.
636
+ // These are aliases — identical output to their badge equivalents so
637
+ // Bootstrap 3 markup works without changes.
638
+
639
+ reg('label', 'components', `.label {
640
+ --st-badge-color: #fff;
641
+ display: inline-block;
642
+ padding: 0.35em 0.65em;
643
+ font-size: 0.75em;
644
+ font-weight: 700;
645
+ line-height: 1;
646
+ color: var(--st-badge-color);
647
+ text-align: center;
648
+ white-space: nowrap;
649
+ vertical-align: baseline;
650
+ border-radius: var(--st-border-radius);
651
+ background-color: var(--st-secondary);
652
+ }`)
653
+
654
+ const LABEL_COLORS = ['default','primary','secondary','success','info','warning','danger','light','dark']
655
+ LABEL_COLORS.forEach(color => {
656
+ const mappedColor = color === 'default' ? 'secondary' : color
657
+ const defaultFg = ['warning','info','light'].includes(mappedColor) ? 'var(--st-dark)' : '#fff'
658
+ reg(`label-${color}`, 'components', `.label-${color} {
659
+ --st-badge-color: ${defaultFg};
660
+ background-color: var(--st-${mappedColor});
661
+ color: var(--st-badge-color);
662
+ }`)
663
+ })
664
+
626
665
  // ─── Components — Buttons ────────────────────────────────────────────
627
666
 
628
667
  const BTN_COLORS = ['primary','secondary','success','danger','warning','info','light','dark']
629
668
 
630
669
  BTN_COLORS.forEach(color => {
631
- const textColor = ['warning','info','light'].includes(color) ? 'var(--st-dark, #212529)' : '#fff'
670
+ const defaultFg = ['warning','info','light'].includes(color) ? 'var(--st-dark)' : '#fff'
632
671
  reg(`btn-${color}`, 'components', `.btn-${color} {
672
+ --st-btn-color: ${defaultFg};
673
+ --st-btn-bg: var(--st-${color});
674
+ --st-btn-border: var(--st-${color});
675
+ --st-btn-hover-bg: var(--st-${color}-hover, color-mix(in srgb, var(--st-${color}) 85%, black));
676
+ --st-btn-hover-border:var(--st-${color}-hover, color-mix(in srgb, var(--st-${color}) 85%, black));
633
677
  display: inline-flex;
634
678
  align-items: center;
635
679
  justify-content: center;
@@ -637,9 +681,9 @@ BTN_COLORS.forEach(color => {
637
681
  font-size: 1rem;
638
682
  font-weight: 400;
639
683
  line-height: 1.5;
640
- color: ${textColor};
641
- background-color: var(--st-${color});
642
- border: 1px solid var(--st-${color});
684
+ color: var(--st-btn-color);
685
+ background-color: var(--st-btn-bg);
686
+ border: 1px solid var(--st-btn-border);
643
687
  border-radius: var(--st-border-radius);
644
688
  cursor: pointer;
645
689
  text-decoration: none;
@@ -653,9 +697,9 @@ BTN_COLORS.forEach(color => {
653
697
  }
654
698
 
655
699
  .btn-${color}:hover {
656
- background-color: var(--st-${color}-hover, color-mix(in srgb, var(--st-${color}) 85%, black));
657
- border-color: var(--st-${color}-hover, color-mix(in srgb, var(--st-${color}) 85%, black));
658
- color: ${textColor};
700
+ background-color: var(--st-btn-hover-bg);
701
+ border-color: var(--st-btn-hover-border);
702
+ color: var(--st-btn-color);
659
703
  }
660
704
 
661
705
  .btn-${color}:focus-visible {
@@ -668,6 +712,9 @@ BTN_COLORS.forEach(color => {
668
712
  }`)
669
713
 
670
714
  reg(`btn-outline-${color}`, 'components', `.btn-outline-${color} {
715
+ --st-btn-outline-color: var(--st-${color});
716
+ --st-btn-outline-hover-color:${defaultFg};
717
+ --st-btn-outline-hover-bg: var(--st-${color});
671
718
  display: inline-flex;
672
719
  align-items: center;
673
720
  justify-content: center;
@@ -675,7 +722,7 @@ BTN_COLORS.forEach(color => {
675
722
  font-size: 1rem;
676
723
  font-weight: 400;
677
724
  line-height: 1.5;
678
- color: var(--st-${color});
725
+ color: var(--st-btn-outline-color);
679
726
  background-color: transparent;
680
727
  border: 1px solid var(--st-${color});
681
728
  border-radius: var(--st-border-radius);
@@ -689,8 +736,8 @@ BTN_COLORS.forEach(color => {
689
736
  }
690
737
 
691
738
  .btn-outline-${color}:hover {
692
- background-color: var(--st-${color});
693
- color: ${textColor};
739
+ background-color: var(--st-btn-outline-hover-bg);
740
+ color: var(--st-btn-outline-hover-color);
694
741
  }
695
742
 
696
743
  .btn-outline-${color}:focus-visible {
@@ -949,8 +996,9 @@ reg('nav-pills', 'components', `.nav-pills .nav-link {
949
996
  }
950
997
 
951
998
  .nav-pills .nav-link.active {
999
+ --st-nav-pills-active-color: #fff;
952
1000
  background-color: var(--st-primary);
953
- color: #fff;
1001
+ color: var(--st-nav-pills-active-color);
954
1002
  }`)
955
1003
 
956
1004
  reg('nav-fill', 'components', `.nav-fill .nav-item { flex: 1 1 auto; text-align: center; }`)
@@ -1333,10 +1381,11 @@ reg('list-group-item', 'components', `.list-group-item {
1333
1381
  }
1334
1382
 
1335
1383
  .list-group-item.active {
1384
+ --st-list-group-active-color: #fff;
1336
1385
  z-index: 2;
1337
1386
  background-color: var(--st-primary);
1338
1387
  border-color: var(--st-primary);
1339
- color: #fff;
1388
+ color: var(--st-list-group-active-color);
1340
1389
  }
1341
1390
 
1342
1391
  .list-group-item.disabled {
@@ -1410,11 +1459,12 @@ reg('progress', 'components', `.progress {
1410
1459
  }`)
1411
1460
 
1412
1461
  reg('progress-bar', 'components', `.progress-bar {
1462
+ --st-progress-bar-color: #fff;
1413
1463
  display: flex;
1414
1464
  flex-direction: column;
1415
1465
  justify-content: center;
1416
1466
  overflow: hidden;
1417
- color: #fff;
1467
+ color: var(--st-progress-bar-color);
1418
1468
  text-align: center;
1419
1469
  white-space: nowrap;
1420
1470
  background-color: var(--st-primary);
@@ -1531,9 +1581,10 @@ reg('page-item', 'components', `.page-item.disabled .page-link {
1531
1581
  }
1532
1582
 
1533
1583
  .page-item.active .page-link {
1584
+ --st-pagination-active-color: #fff;
1534
1585
  background-color: var(--st-primary);
1535
1586
  border-color: var(--st-primary);
1536
- color: #fff;
1587
+ color: var(--st-pagination-active-color);
1537
1588
  }`)
1538
1589
 
1539
1590
  reg('page-link', 'components', `.page-link {
@@ -1926,8 +1977,9 @@ reg('dropdown-item', 'components', `.dropdown-item {
1926
1977
 
1927
1978
  .dropdown-item.active,
1928
1979
  .dropdown-item:active {
1980
+ --st-dropdown-active-color: #fff;
1929
1981
  background-color: var(--st-primary);
1930
- color: #fff;
1982
+ color: var(--st-dropdown-active-color);
1931
1983
  }
1932
1984
 
1933
1985
  .dropdown-item.disabled {
@@ -2103,12 +2155,17 @@ Object.entries(TABLE_COLORS).forEach(([color, bg]) => {
2103
2155
  .table-${color} > :not(caption) > * > * { background-color: var(--st-table-bg); }`)
2104
2156
  })
2105
2157
  reg('table-dark', 'components', `.table-dark {
2106
- --st-table-bg: #212529;
2107
- color: #dee2e6;
2108
- border-color: #373b3e;
2109
- }
2110
- .table-dark > :not(caption) > * > * { background-color: var(--st-table-bg); color: #dee2e6; }
2111
- .table-dark > thead > tr > th { background-color: #1a1d20; color: #adb5bd; }`)
2158
+ --st-table-dark-bg: #212529;
2159
+ --st-table-dark-color: #dee2e6;
2160
+ --st-table-dark-border: #373b3e;
2161
+ --st-table-dark-head-bg: #1a1d20;
2162
+ --st-table-dark-head-color: #adb5bd;
2163
+ --st-table-bg: var(--st-table-dark-bg);
2164
+ color: var(--st-table-dark-color);
2165
+ border-color: var(--st-table-dark-border);
2166
+ }
2167
+ .table-dark > :not(caption) > * > * { background-color: var(--st-table-bg); color: var(--st-table-dark-color); }
2168
+ .table-dark > thead > tr > th { background-color: var(--st-table-dark-head-bg); color: var(--st-table-dark-head-color); }`)
2112
2169
  reg('table-striped-columns', 'components', `.table-striped-columns > :not(caption) > tr > :nth-child(even) {
2113
2170
  background-color: var(--st-bg-secondary);
2114
2171
  }`)
@@ -2171,22 +2228,25 @@ reg('carousel-item', 'components', `.carousel-item {
2171
2228
  .carousel-item-next,
2172
2229
  .carousel-item-prev { display: block; }`)
2173
2230
  reg('carousel-control-prev', 'components', `.carousel-control-prev {
2231
+ --st-carousel-control-color: #fff;
2174
2232
  position: absolute; top: 0; bottom: 0; left: 0;
2175
2233
  display: flex; align-items: center; justify-content: center;
2176
- width: 15%; padding: 0; color: #fff; text-align: center;
2234
+ width: 15%; padding: 0; color: var(--st-carousel-control-color); text-align: center;
2177
2235
  background: rgba(0,0,0,0.2); border: 0; opacity: 0.5;
2178
2236
  cursor: pointer; transition: opacity var(--st-duration) var(--st-easing);
2179
2237
  }
2180
2238
  .carousel-control-prev:hover { opacity: 0.9; }`)
2181
2239
  reg('carousel-control-next', 'components', `.carousel-control-next {
2240
+ --st-carousel-control-color: #fff;
2182
2241
  position: absolute; top: 0; right: 0; bottom: 0;
2183
2242
  display: flex; align-items: center; justify-content: center;
2184
- width: 15%; padding: 0; color: #fff; text-align: center;
2243
+ width: 15%; padding: 0; color: var(--st-carousel-control-color); text-align: center;
2185
2244
  background: rgba(0,0,0,0.2); border: 0; opacity: 0.5;
2186
2245
  cursor: pointer; transition: opacity var(--st-duration) var(--st-easing);
2187
2246
  }
2188
2247
  .carousel-control-next:hover { opacity: 0.9; }`)
2189
2248
  reg('carousel-indicators', 'components', `.carousel-indicators {
2249
+ --st-carousel-indicator-bg: #fff;
2190
2250
  position: absolute; right: 0; bottom: 0; left: 0;
2191
2251
  display: flex; justify-content: center;
2192
2252
  padding: 0; margin: 0 15%; list-style: none;
@@ -2194,13 +2254,14 @@ reg('carousel-indicators', 'components', `.carousel-indicators {
2194
2254
  .carousel-indicators [data-bs-target],
2195
2255
  .carousel-indicators button {
2196
2256
  width: 30px; height: 3px; margin: 0 3px;
2197
- background-color: #fff; border: none; cursor: pointer;
2257
+ background-color: var(--st-carousel-indicator-bg); border: none; cursor: pointer;
2198
2258
  opacity: 0.5; transition: opacity var(--st-duration) var(--st-easing);
2199
2259
  }
2200
2260
  .carousel-indicators .active { opacity: 1; }`)
2201
2261
  reg('carousel-caption', 'components', `.carousel-caption {
2262
+ --st-carousel-caption-color: #fff;
2202
2263
  position: absolute; right: 15%; bottom: 1.25rem; left: 15%;
2203
- padding: 1.25rem; color: #fff; text-align: center;
2264
+ padding: 1.25rem; color: var(--st-carousel-caption-color); text-align: center;
2204
2265
  }`)
2205
2266
  reg('carousel-fade', 'components', `.carousel-fade .carousel-item { opacity: 0; transition: opacity var(--st-duration-slow) var(--st-easing); transform: none; }
2206
2267
  .carousel-fade .carousel-item.active { opacity: 1; }`)
@@ -2297,13 +2358,15 @@ reg('navbar-expand', 'components', `.navbar-expand {
2297
2358
  .navbar-expand .navbar-collapse { display: flex; flex-basis: auto; }
2298
2359
  .navbar-expand .navbar-toggler { display: none; }`)
2299
2360
  reg('navbar-dark', 'components', `.navbar-dark {
2300
- --st-navbar-color: rgba(255,255,255,0.75);
2361
+ --st-navbar-dark-color: rgba(255,255,255,0.75);
2362
+ --st-navbar-dark-color-hover: rgba(255,255,255,0.9);
2363
+ --st-navbar-dark-toggler-border: rgba(255,255,255,0.1);
2301
2364
  background-color: var(--st-dark);
2302
2365
  border-color: transparent;
2303
2366
  }
2304
2367
  .navbar-dark .navbar-brand,
2305
- .navbar-dark .nav-link { color: rgba(255,255,255,0.9); }
2306
- .navbar-dark .navbar-toggler { border-color: rgba(255,255,255,0.1); color: rgba(255,255,255,0.75); }`)
2368
+ .navbar-dark .nav-link { color: var(--st-navbar-dark-color-hover); }
2369
+ .navbar-dark .navbar-toggler { border-color: var(--st-navbar-dark-toggler-border); color: var(--st-navbar-dark-color); }`)
2307
2370
  reg('navbar-light', 'components', `.navbar-light {
2308
2371
  background-color: var(--st-bg);
2309
2372
  border-color: var(--st-border);
@@ -2428,14 +2491,16 @@ reg('tooltip', 'components', `.tooltip {
2428
2491
  }
2429
2492
  .tooltip.show { opacity: 0.9; }`)
2430
2493
  reg('tooltip-inner', 'components', `.tooltip-inner {
2494
+ --st-tooltip-color: #fff;
2495
+ --st-tooltip-bg: #000;
2431
2496
  max-width: 200px; padding: 0.25rem 0.5rem;
2432
- color: #fff; text-align: center;
2433
- background-color: #000; border-radius: var(--st-border-radius);
2497
+ color: var(--st-tooltip-color); text-align: center;
2498
+ background-color: var(--st-tooltip-bg); border-radius: var(--st-border-radius);
2434
2499
  }`)
2435
2500
  reg('bs-tooltip-top', 'components', `.bs-tooltip-top { padding: 4px 0; }
2436
2501
  .bs-tooltip-top .tooltip-arrow::before {
2437
2502
  top: -1px; border-width: 4px 4px 0;
2438
- border-top-color: #000;
2503
+ border-top-color: var(--st-tooltip-bg, #000);
2439
2504
  }`)
2440
2505
  reg('popover', 'components', `.popover {
2441
2506
  position: absolute; z-index: var(--st-z-popover, 1070);
@@ -2654,6 +2719,40 @@ reg('translate-middle-y', 'utilities', `.translate-middle-y { transform: transla
2654
2719
  // ─── Sizing extras ────────────────────────────────────────────────────
2655
2720
  reg('mw-100', 'utilities', `.mw-100 { max-width: 100%; }`)
2656
2721
  reg('mh-100', 'utilities', `.mh-100 { max-height: 100%; }`)
2722
+
2723
+ // ─── max-w-* named scale (aligned to Bootstrap container breakpoints) ─
2724
+ // max-w-xs → 320px small phone portrait
2725
+ // max-w-sm → 540px Bootstrap sm container
2726
+ // max-w-md → 720px Bootstrap md container
2727
+ // max-w-lg → 960px Bootstrap lg container
2728
+ // max-w-xl → 1140px Bootstrap xl container
2729
+ // max-w-xxl → 1320px Bootstrap xxl container
2730
+ const MAX_W_SCALE = {
2731
+ 'xs': '320px',
2732
+ 'sm': '540px',
2733
+ 'md': '720px',
2734
+ 'lg': '960px',
2735
+ 'xl': '1140px',
2736
+ 'xxl': '1320px',
2737
+ 'full': '100%',
2738
+ 'none': 'none',
2739
+ }
2740
+ Object.entries(MAX_W_SCALE).forEach(([k, v]) => {
2741
+ reg(`max-w-${k}`, 'utilities', `.max-w-${k} { max-width: ${v}; }`)
2742
+ })
2743
+
2744
+ // ─── min-w-* ──────────────────────────────────────────────────────────
2745
+ reg('min-w-0', 'utilities', `.min-w-0 { min-width: 0; }`)
2746
+ reg('min-w-full', 'utilities', `.min-w-full { min-width: 100%; }`)
2747
+ reg('min-w-screen', 'utilities', `.min-w-screen { min-width: 100vw; }`)
2748
+
2749
+ // max-h-* and min-h-* common values
2750
+ reg('max-h-full', 'utilities', `.max-h-full { max-height: 100%; }`)
2751
+ reg('max-h-screen', 'utilities', `.max-h-screen { max-height: 100vh; }`)
2752
+ reg('max-h-none', 'utilities', `.max-h-none { max-height: none; }`)
2753
+ reg('min-h-0', 'utilities', `.min-h-0 { min-height: 0; }`)
2754
+ reg('min-h-full', 'utilities', `.min-h-full { min-height: 100%; }`)
2755
+ reg('min-h-screen', 'utilities', `.min-h-screen { min-height: 100vh; }`)
2657
2756
  reg('vw-100', 'utilities', `.vw-100 { width: 100vw; }`)
2658
2757
  reg('vh-100', 'utilities', `.vh-100 { height: 100vh; }`)
2659
2758
  reg('min-vw-100','utilities', `.min-vw-100{ min-width: 100vw; }`)
@@ -2799,18 +2898,21 @@ reg('tooltip-arrow', 'components', TOOLTIP_ARROW)
2799
2898
  })
2800
2899
 
2801
2900
  // ─── List utilities ───────────────────────────────────────────────────
2901
+
2902
+ // Remove list styling entirely — resets padding, margin, and list-style
2802
2903
  reg('list-unstyled', 'utilities', `.list-unstyled {
2803
- padding-left: 0;
2804
- margin-top: 0;
2904
+ padding-left: 0;
2905
+ margin-top: 0;
2805
2906
  margin-bottom: 0;
2806
- list-style: none;
2907
+ list-style: none;
2807
2908
  }`)
2808
2909
 
2910
+ // Inline list — items sit side by side
2809
2911
  reg('list-inline', 'utilities', `.list-inline {
2810
- padding-left: 0;
2811
- margin-top: 0;
2912
+ padding-left: 0;
2913
+ margin-top: 0;
2812
2914
  margin-bottom: 0;
2813
- list-style: none;
2915
+ list-style: none;
2814
2916
  }`)
2815
2917
 
2816
2918
  reg('list-inline-item', 'utilities', `.list-inline-item {
@@ -2821,6 +2923,24 @@ reg('list-inline-item', 'utilities', `.list-inline-item {
2821
2923
  margin-right: 0.5rem;
2822
2924
  }`)
2823
2925
 
2926
+ // list-style-type variants
2927
+ reg('list-disc', 'utilities', `.list-disc { list-style-type: disc; }`)
2928
+ reg('list-decimal', 'utilities', `.list-decimal { list-style-type: decimal; }`)
2929
+ reg('list-circle', 'utilities', `.list-circle { list-style-type: circle; }`)
2930
+ reg('list-square', 'utilities', `.list-square { list-style-type: square; }`)
2931
+ reg('list-none', 'utilities', `.list-none { list-style-type: none; }`)
2932
+ reg('list-lower-alpha', 'utilities', `.list-lower-alpha { list-style-type: lower-alpha; }`)
2933
+ reg('list-upper-alpha', 'utilities', `.list-upper-alpha { list-style-type: upper-alpha; }`)
2934
+ reg('list-lower-roman', 'utilities', `.list-lower-roman { list-style-type: lower-roman; }`)
2935
+ reg('list-upper-roman', 'utilities', `.list-upper-roman { list-style-type: upper-roman; }`)
2936
+
2937
+ // list-style-position variants
2938
+ reg('list-inside', 'utilities', `.list-inside { list-style-position: inside; }`)
2939
+ reg('list-outside', 'utilities', `.list-outside { list-style-position: outside; }`)
2940
+
2941
+ // Spaced list — adds breathing room between items
2942
+ reg('list-spaced', 'utilities', `.list-spaced > li + li { margin-top: 0.5rem; }`)
2943
+
2824
2944
  // ─── Form group ───────────────────────────────────────────────────────
2825
2945
  reg('form-group', 'components', `.form-group {
2826
2946
  margin-bottom: 1rem;
@@ -2851,6 +2971,166 @@ Object.entries(OUTLINE_COLOR_MAP).forEach(([k, v]) => {
2851
2971
  reg(`outline-${n}`, 'utilities', `.outline-${n} { outline-width: ${n}px; }`)
2852
2972
  })
2853
2973
 
2974
+ // ─── Responsive variants ─────────────────────────────────────────────
2975
+ // Breakpoint-prefixed versions of utilities that were previously static.
2976
+ // Pattern: {utility}-{bp}-{value} e.g. flex-md-row, fw-lg-bold, rounded-md-3
2977
+
2978
+ const BP_KEYS = Object.keys(BP_VALUES) // sm md lg xl xxl
2979
+
2980
+ // Flex direction
2981
+ ;['row','column','wrap','nowrap','row-reverse','column-reverse'].forEach(v => {
2982
+ const prop = ['wrap','nowrap'].includes(v)
2983
+ ? `flex-wrap: ${v === 'nowrap' ? 'nowrap' : 'wrap'};`
2984
+ : `flex-direction: ${v};`
2985
+ BP_KEYS.forEach(bp => {
2986
+ reg(`flex-${bp}-${v}`, 'utilities',
2987
+ mq(bp, `.flex-${bp}-${v} { ${prop} }`))
2988
+ })
2989
+ })
2990
+
2991
+ // Font weight
2992
+ const FW_MAP = {
2993
+ light: '300', lighter: 'lighter', normal: '400',
2994
+ medium: '500', semibold: '600', bold: '700', bolder: 'bolder',
2995
+ }
2996
+ Object.entries(FW_MAP).forEach(([k, v]) => {
2997
+ BP_KEYS.forEach(bp => {
2998
+ reg(`fw-${bp}-${k}`, 'utilities',
2999
+ mq(bp, `.fw-${bp}-${k} { font-weight: ${v}; }`))
3000
+ })
3001
+ })
3002
+
3003
+ // Font style
3004
+ ;['italic','normal'].forEach(v => {
3005
+ BP_KEYS.forEach(bp => {
3006
+ reg(`fst-${bp}-${v}`, 'utilities',
3007
+ mq(bp, `.fst-${bp}-${v} { font-style: ${v}; }`))
3008
+ })
3009
+ })
3010
+
3011
+ // Text transform
3012
+ ;['uppercase','lowercase','capitalize','none'].forEach(v => {
3013
+ BP_KEYS.forEach(bp => {
3014
+ reg(`text-${bp}-${v}`, 'utilities',
3015
+ mq(bp, `.text-${bp}-${v} { text-transform: ${v}; }`))
3016
+ })
3017
+ })
3018
+
3019
+ // Text decoration
3020
+ ;['none','underline','line-through'].forEach(v => {
3021
+ BP_KEYS.forEach(bp => {
3022
+ reg(`text-${bp}-decoration-${v}`, 'utilities',
3023
+ mq(bp, `.text-${bp}-decoration-${v} { text-decoration: ${v}; }`))
3024
+ })
3025
+ })
3026
+
3027
+ // Text wrap
3028
+ ;['wrap','nowrap'].forEach(v => {
3029
+ BP_KEYS.forEach(bp => {
3030
+ reg(`text-${bp}-${v}`, 'utilities',
3031
+ mq(bp, `.text-${bp}-${v} { white-space: ${v === 'nowrap' ? 'nowrap' : 'normal'}; }`))
3032
+ })
3033
+ })
3034
+
3035
+ // Border radius
3036
+ const ROUNDED_SCALE = {
3037
+ '0':'0', '1':'0.25rem', '2':'0.375rem', '3':'0.5rem',
3038
+ '4':'0.75rem', '5':'1rem',
3039
+ 'pill':'999px', 'circle':'50%',
3040
+ }
3041
+ Object.entries(ROUNDED_SCALE).forEach(([k, v]) => {
3042
+ BP_KEYS.forEach(bp => {
3043
+ reg(`rounded-${bp}-${k}`, 'utilities',
3044
+ mq(bp, `.rounded-${bp}-${k} { border-radius: ${v}; }`))
3045
+ })
3046
+ })
3047
+ BP_KEYS.forEach(bp => {
3048
+ reg(`rounded-${bp}`, 'utilities',
3049
+ mq(bp, `.rounded-${bp} { border-radius: var(--st-border-radius); }`))
3050
+ })
3051
+
3052
+ // Shadow
3053
+ const SHADOW_MAP = {
3054
+ 'sm': 'var(--st-shadow-sm)', '': 'var(--st-shadow)',
3055
+ 'lg': 'var(--st-shadow-lg)', 'none': 'none',
3056
+ }
3057
+ Object.entries(SHADOW_MAP).forEach(([k, v]) => {
3058
+ const cls = k ? `shadow-${k}` : 'shadow'
3059
+ BP_KEYS.forEach(bp => {
3060
+ reg(`shadow-${bp}${k ? '-' + k : ''}`, 'utilities',
3061
+ mq(bp, `.shadow-${bp}${k ? '-' + k : ''} { box-shadow: ${v}; }`))
3062
+ })
3063
+ })
3064
+
3065
+ // Width
3066
+ Object.entries(SIZE_SCALE).forEach(([k, v]) => {
3067
+ BP_KEYS.forEach(bp => {
3068
+ reg(`w-${bp}-${k}`, 'utilities',
3069
+ mq(bp, `.w-${bp}-${k} { width: ${v}; }`))
3070
+ })
3071
+ })
3072
+
3073
+ // Height
3074
+ Object.entries(SIZE_SCALE).forEach(([k, v]) => {
3075
+ BP_KEYS.forEach(bp => {
3076
+ reg(`h-${bp}-${k}`, 'utilities',
3077
+ mq(bp, `.h-${bp}-${k} { height: ${v}; }`))
3078
+ })
3079
+ })
3080
+
3081
+ // Opacity
3082
+ Object.entries(OPACITY_SCALE).forEach(([k, v]) => {
3083
+ BP_KEYS.forEach(bp => {
3084
+ reg(`opacity-${bp}-${k}`, 'utilities',
3085
+ mq(bp, `.opacity-${bp}-${k} { opacity: ${v}; }`))
3086
+ })
3087
+ })
3088
+
3089
+ // Overflow
3090
+ ;['auto','hidden','visible','scroll'].forEach(v => {
3091
+ BP_KEYS.forEach(bp => {
3092
+ reg(`overflow-${bp}-${v}`, 'utilities',
3093
+ mq(bp, `.overflow-${bp}-${v} { overflow: ${v}; }`))
3094
+ reg(`overflow-x-${bp}-${v}`, 'utilities',
3095
+ mq(bp, `.overflow-x-${bp}-${v} { overflow-x: ${v}; }`))
3096
+ reg(`overflow-y-${bp}-${v}`, 'utilities',
3097
+ mq(bp, `.overflow-y-${bp}-${v} { overflow-y: ${v}; }`))
3098
+ })
3099
+ })
3100
+
3101
+ // Position
3102
+ ;['static','relative','absolute','fixed','sticky'].forEach(v => {
3103
+ BP_KEYS.forEach(bp => {
3104
+ reg(`position-${bp}-${v}`, 'utilities',
3105
+ mq(bp, `.position-${bp}-${v} { position: ${v}; }`))
3106
+ })
3107
+ })
3108
+
3109
+ // Cursor
3110
+ ;['auto','default','pointer','wait','text','move','not-allowed','grab'].forEach(v => {
3111
+ BP_KEYS.forEach(bp => {
3112
+ reg(`cursor-${bp}-${v}`, 'utilities',
3113
+ mq(bp, `.cursor-${bp}-${v} { cursor: ${v}; }`))
3114
+ })
3115
+ })
3116
+
3117
+ // Line height
3118
+ const LH_MAP = { '1':'1', 'sm':'1.25', 'base':'1.5', 'lg':'2' }
3119
+ Object.entries(LH_MAP).forEach(([k, v]) => {
3120
+ BP_KEYS.forEach(bp => {
3121
+ reg(`lh-${bp}-${k}`, 'utilities',
3122
+ mq(bp, `.lh-${bp}-${k} { line-height: ${v}; }`))
3123
+ })
3124
+ })
3125
+
3126
+ // Visibility
3127
+ BP_KEYS.forEach(bp => {
3128
+ reg(`visible-${bp}`, 'utilities',
3129
+ mq(bp, `.visible-${bp} { visibility: visible; }`))
3130
+ reg(`invisible-${bp}`, 'utilities',
3131
+ mq(bp, `.invisible-${bp} { visibility: hidden; }`))
3132
+ })
3133
+
2854
3134
  // ─── Arbitrary value patterns — regex fallback ────────────────────────
2855
3135
  // Only used when no exact match found in EXACT_MAP
2856
3136
 
@@ -2864,10 +3144,15 @@ const ARBITRARY_PATTERNS = [
2864
3144
  const decl = props.map(p => ` ${p}: ${val}${i};`).join('\n')
2865
3145
  return { layer: 'utilities', css: `.${escapeClass(m[0])} {\n${decl}\n}` }
2866
3146
  }},
2867
- // Text color arbitrary: text-[#ff0000]
3147
+ // Text arbitrary: text-[#ff0000] → color, text-[15px] → font-size
3148
+ // Values ending in a CSS length unit are font-size; everything else is color.
2868
3149
  { re: /^(!?)text-\[(.+)\]$/, fn: (m) => {
2869
- const i = m[1] ? ' !important' : ''
2870
- return { layer: 'utilities', css: `.${escapeClass(m[0])} { color: ${m[2]}${i}; }` }
3150
+ const i = m[1] ? ' !important' : ''
3151
+ const val = m[2]
3152
+ const prop = /^[\d.]+(px|rem|em|%|vw|vh|ch|ex|pt|cm|mm)$/.test(val)
3153
+ ? 'font-size'
3154
+ : 'color'
3155
+ return { layer: 'utilities', css: `.${escapeClass(m[0])} { ${prop}: ${val}${i}; }` }
2871
3156
  }},
2872
3157
  // BG arbitrary: bg-[#ff0000]
2873
3158
  { re: /^(!?)bg-\[(.+)\]$/, fn: (m) => {
@@ -2889,6 +3174,26 @@ const ARBITRARY_PATTERNS = [
2889
3174
  const i = m[1] ? ' !important' : ''
2890
3175
  return { layer: 'utilities', css: `.${escapeClass(m[0])} { height: ${m[2]}${i}; }` }
2891
3176
  }},
3177
+ // Max-width arbitrary: max-w-[440px]
3178
+ { re: /^(!?)max-w-\[(.+)\]$/, fn: (m) => {
3179
+ const i = m[1] ? ' !important' : ''
3180
+ return { layer: 'utilities', css: `.${escapeClass(m[0])} { max-width: ${m[2]}${i}; }` }
3181
+ }},
3182
+ // Min-width arbitrary: min-w-[200px]
3183
+ { re: /^(!?)min-w-\[(.+)\]$/, fn: (m) => {
3184
+ const i = m[1] ? ' !important' : ''
3185
+ return { layer: 'utilities', css: `.${escapeClass(m[0])} { min-width: ${m[2]}${i}; }` }
3186
+ }},
3187
+ // Max-height arbitrary: max-h-[500px]
3188
+ { re: /^(!?)max-h-\[(.+)\]$/, fn: (m) => {
3189
+ const i = m[1] ? ' !important' : ''
3190
+ return { layer: 'utilities', css: `.${escapeClass(m[0])} { max-height: ${m[2]}${i}; }` }
3191
+ }},
3192
+ // Min-height arbitrary: min-h-[300px]
3193
+ { re: /^(!?)min-h-\[(.+)\]$/, fn: (m) => {
3194
+ const i = m[1] ? ' !important' : ''
3195
+ return { layer: 'utilities', css: `.${escapeClass(m[0])} { min-height: ${m[2]}${i}; }` }
3196
+ }},
2892
3197
  // Opacity arbitrary: opacity-[0.3]
2893
3198
  { re: /^(!?)opacity-\[(.+)\]$/, fn: (m) => {
2894
3199
  const i = m[1] ? ' !important' : ''