@swiftbrowser/web 0.2.0 → 0.3.0

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/src/styles.css CHANGED
@@ -63,13 +63,15 @@
63
63
  color-scheme: light;
64
64
  --sb-color-primary: #000000;
65
65
  --sb-color-secondary: rgba(60, 60, 67, 0.6);
66
- --sb-color-accent: #007aff;
66
+ --sb-color-accent: #0088ff;
67
67
  --sb-color-system-background: #ffffff;
68
68
  --sb-color-secondary-system-background: #f2f2f7;
69
69
  --sb-color-separator: rgba(60, 60, 67, 0.29);
70
+ /* iOS 26 draws the hairlines between list rows lighter than `separator`. */
71
+ --sb-color-row-separator: rgba(0, 0, 0, 0.09);
70
72
  --sb-color-tertiary-label: rgba(60, 60, 67, 0.3);
71
73
  --sb-color-quaternary-label: rgba(60, 60, 67, 0.18);
72
- --sb-color-red: #ff3b30;
74
+ --sb-color-red: #ff383c;
73
75
  --sb-color-green: #34c759;
74
76
  --sb-color-grouped-background: #f2f2f7;
75
77
  --sb-color-grouped-cell: #ffffff;
@@ -88,7 +90,11 @@
88
90
  --sb-color-system-gray6: #f2f2f7;
89
91
  /* Phase 6 materials: rgb components of the color blurred over the backdrop. */
90
92
  --sb-color-material-base: 255, 255, 255;
91
- --sb-color-switch-off: #e9e9ea;
93
+ /* iOS 26 (measured on its simulator, as the dark values below). */
94
+ --sb-color-switch-off: rgba(120, 120, 128, 0.42);
95
+ --sb-tint-fill-amount: 18%;
96
+ --sb-alert-scrim: rgba(0, 0, 0, 0.2);
97
+ --sb-alert-card: rgba(255, 255, 255, 0.7);
92
98
  --sb-color-field-border: #c6c6c8;
93
99
  --sb-color-field-background: #ffffff;
94
100
  --sb-color-placeholder: rgba(60, 60, 67, 0.3);
@@ -96,6 +102,12 @@
96
102
  --sb-color-grabber: rgba(60, 60, 67, 0.3);
97
103
  /* Phase 4 */
98
104
  --sb-color-tabbar-background: rgba(249, 249, 249, 0.94);
105
+ /* iOS 26 Liquid Glass, approximated: a near-white translucent fill over a
106
+ blurred backdrop with a soft shadow (bar buttons, the tab bar, the
107
+ bottom search field). */
108
+ --sb-glass-background: rgba(252, 252, 255, 0.86);
109
+ --sb-glass-shadow: 0 4px 24px rgba(0, 0, 0, 0.08), 0 0 0 0.5px rgba(0, 0, 0, 0.04);
110
+ --sb-glass-selected: rgba(120, 120, 128, 0.16);
99
111
  --sb-color-segment-track: rgba(118, 118, 128, 0.12);
100
112
  --sb-color-segment-selected: #ffffff;
101
113
  --sb-color-menu-background: rgba(250, 250, 250, 0.96);
@@ -105,13 +117,14 @@
105
117
  color-scheme: dark;
106
118
  --sb-color-primary: #ffffff;
107
119
  --sb-color-secondary: rgba(235, 235, 245, 0.6);
108
- --sb-color-accent: #0a84ff;
120
+ --sb-color-accent: #0091ff;
109
121
  --sb-color-system-background: #000000;
110
122
  --sb-color-secondary-system-background: #1c1c1e;
111
123
  --sb-color-separator: rgba(84, 84, 88, 0.6);
124
+ --sb-color-row-separator: rgba(84, 84, 88, 0.6);
112
125
  --sb-color-tertiary-label: rgba(235, 235, 245, 0.3);
113
126
  --sb-color-quaternary-label: rgba(235, 235, 245, 0.16);
114
- --sb-color-red: #ff453a;
127
+ --sb-color-red: #ff4245;
115
128
  --sb-color-green: #30d158;
116
129
  --sb-color-grouped-background: #000000;
117
130
  --sb-color-grouped-cell: #1c1c1e;
@@ -128,17 +141,23 @@
128
141
  --sb-color-system-gray5: #2c2c2e;
129
142
  --sb-color-system-gray6: #1c1c1e;
130
143
  --sb-color-material-base: 30, 30, 30;
131
- --sb-color-switch-off: #39393d;
144
+ --sb-color-switch-off: rgba(120, 120, 128, 0.68);
145
+ --sb-tint-fill-amount: 25%;
146
+ --sb-alert-scrim: rgba(0, 0, 0, 0.46);
147
+ --sb-alert-card: rgba(22, 22, 23, 0.9);
132
148
  --sb-color-field-border: #3a3a3c;
133
149
  --sb-color-field-background: #1c1c1e;
134
150
  --sb-color-placeholder: rgba(235, 235, 245, 0.3);
151
+ --sb-glass-background: rgba(30, 30, 30, 0.84);
152
+ --sb-glass-shadow: 0 4px 24px rgba(0, 0, 0, 0.4), 0 0 0 0.5px rgba(255, 255, 255, 0.08);
153
+ --sb-glass-selected: rgba(120, 120, 128, 0.32);
135
154
  /* Sheets float above the window and take the elevated system background. */
136
155
  --sb-color-sheet-background: #1c1c1e;
137
156
  --sb-color-grabber: rgba(235, 235, 245, 0.3);
138
157
  /* Phase 4 */
139
158
  --sb-color-tabbar-background: rgba(29, 29, 29, 0.94);
140
159
  --sb-color-segment-track: rgba(118, 118, 128, 0.24);
141
- --sb-color-segment-selected: #636366;
160
+ --sb-color-segment-selected: #5a5a5f;
142
161
  --sb-color-menu-background: rgba(37, 37, 37, 0.96);
143
162
  }
144
163
 
@@ -353,7 +372,7 @@ body {
353
372
  position: absolute;
354
373
  top: 11px;
355
374
  left: 50%;
356
- width: 126px;
375
+ width: 125px;
357
376
  height: 37px;
358
377
  transform: translateX(-50%);
359
378
  border-radius: 20px;
@@ -370,23 +389,30 @@ body {
370
389
  display: flex;
371
390
  align-items: center;
372
391
  justify-content: space-between;
373
- padding: 0 32px 6px 40px;
392
+ /* As iOS 26 draws it (measured on an iPhone 16 simulator): the row is
393
+ centered 29.5pt down, the time centered 70pt from the leading edge, the
394
+ glyphs 7.67pt apart ending 32pt from the trailing edge. */
395
+ padding: 0 32px 0 38px;
374
396
  pointer-events: none;
375
397
  z-index: 2;
376
398
  color: var(--sb-color-primary);
377
399
  }
378
400
 
379
401
  .status-time {
402
+ min-width: 64px;
403
+ text-align: center;
404
+ /* The digits' optical center, not the line box's, sits on the row's. */
405
+ position: relative;
406
+ top: 1.67px;
380
407
  font-size: 17px;
381
408
  font-weight: 600;
382
409
  letter-spacing: -0.02em;
383
- font-variant-numeric: tabular-nums;
384
410
  }
385
411
 
386
412
  .status-glyphs {
387
413
  display: flex;
388
414
  align-items: center;
389
- gap: 7px;
415
+ gap: 7.67px;
390
416
  }
391
417
 
392
418
  .glyph {
@@ -394,6 +420,12 @@ body {
394
420
  fill: currentColor;
395
421
  }
396
422
 
423
+ .glyph-wifi .wifi-band {
424
+ fill: none;
425
+ stroke: currentColor;
426
+ stroke-linecap: round;
427
+ }
428
+
397
429
  .glyph-battery .battery-shell {
398
430
  fill: none;
399
431
  stroke: currentColor;
@@ -623,7 +655,8 @@ html[data-sb-mode="device"] .status {
623
655
  }
624
656
 
625
657
  .sb-button[data-sb-style="bordered"] {
626
- background: var(--sb-color-fill);
658
+ /* iOS 26: secondarySystemFill, or the view's tint at 18% (dark 25%). */
659
+ background: var(--sb-tint-fill, var(--sb-color-secondary-fill));
627
660
  color: var(--sb-button-color, var(--sb-tint, var(--sb-color-accent)));
628
661
  }
629
662
 
@@ -641,6 +674,18 @@ html[data-sb-mode="device"] .status {
641
674
  color: #ffffff;
642
675
  }
643
676
 
677
+ /* iOS 26 draws a disabled bordered button gray rather than faded
678
+ (`.disabled` marks the element around the button and dims it inline; the
679
+ renderer keeps the undimmed opacity in `--sb-undimmed-opacity`). */
680
+ [data-sb-disabled]:has(> .sb-button:is([data-sb-style="bordered"], [data-sb-style="borderedProminent"])) {
681
+ opacity: var(--sb-undimmed-opacity, 1) !important;
682
+ }
683
+
684
+ [data-sb-disabled] > .sb-button:is([data-sb-style="bordered"], [data-sb-style="borderedProminent"]) {
685
+ background: var(--sb-color-secondary-fill);
686
+ color: var(--sb-color-tertiary-label);
687
+ }
688
+
644
689
  /* .disabled(true): opacity and pointer-events are set inline by the renderer
645
690
  (so update() clears them); the attribute carries the state for tooling. */
646
691
  [data-sb-disabled] {
@@ -663,6 +708,47 @@ html[data-sb-mode="device"] .status {
663
708
  stroke: currentColor;
664
709
  }
665
710
 
711
+ /* An indeterminate ProgressView: the activity indicator (symbols.ts), in
712
+ the secondary label color (or the view's tint). As on iOS the spokes stay
713
+ put and the fade steps around them clockwise, once a second: each spoke
714
+ runs the same ramp an eighth of a second after the one before it.
715
+ (Rotating the glyph instead resamples it at every step, which wobbles.) */
716
+ svg[data-sb-symbol="progress.indicator"] {
717
+ color: var(--sb-tint, var(--sb-color-secondary));
718
+ }
719
+
720
+ svg[data-sb-symbol="progress.indicator"] > line {
721
+ animation: sb-activity-spoke 1s step-end infinite;
722
+ }
723
+
724
+ svg[data-sb-symbol="progress.indicator"] > line:nth-child(2) { animation-delay: -0.875s; }
725
+ svg[data-sb-symbol="progress.indicator"] > line:nth-child(3) { animation-delay: -0.75s; }
726
+ svg[data-sb-symbol="progress.indicator"] > line:nth-child(4) { animation-delay: -0.625s; }
727
+ svg[data-sb-symbol="progress.indicator"] > line:nth-child(5) { animation-delay: -0.5s; }
728
+ svg[data-sb-symbol="progress.indicator"] > line:nth-child(6) { animation-delay: -0.375s; }
729
+ svg[data-sb-symbol="progress.indicator"] > line:nth-child(7) { animation-delay: -0.25s; }
730
+ svg[data-sb-symbol="progress.indicator"] > line:nth-child(8) { animation-delay: -0.125s; }
731
+
732
+ /* A spoke's strength from the moment it leads: the ramp symbols.ts draws. */
733
+ @keyframes sb-activity-spoke {
734
+ 0% {
735
+ stroke-opacity: 1;
736
+ }
737
+ 12.5% {
738
+ stroke-opacity: 0.83;
739
+ }
740
+ 25% {
741
+ stroke-opacity: 0.66;
742
+ }
743
+ 37.5% {
744
+ stroke-opacity: 0.49;
745
+ }
746
+ 50%,
747
+ 100% {
748
+ stroke-opacity: 0.31;
749
+ }
750
+ }
751
+
666
752
  /* Unknown symbol or catalog image: a dashed box named by `title`. */
667
753
  .sb-image[data-sb-missing] {
668
754
  border: 1px dashed currentColor;
@@ -801,8 +887,9 @@ html[data-sb-mode="device"] .status {
801
887
  .sb-switch {
802
888
  appearance: none;
803
889
  position: absolute;
804
- width: 51px;
805
- height: 31px;
890
+ /* iOS 26: 63 × 28 with a pill knob. */
891
+ width: 63px;
892
+ height: 28px;
806
893
  margin: 0;
807
894
  padding: 0;
808
895
  border: 0;
@@ -827,9 +914,9 @@ html[data-sb-mode="device"] .status {
827
914
  position: absolute;
828
915
  top: 2px;
829
916
  left: 2px;
830
- width: 27px;
831
- height: 27px;
832
- border-radius: 50%;
917
+ width: 37px;
918
+ height: 24px;
919
+ border-radius: 12px;
833
920
  background: #ffffff;
834
921
  box-shadow:
835
922
  0 3px 8px rgba(0, 0, 0, 0.15),
@@ -838,7 +925,7 @@ html[data-sb-mode="device"] .status {
838
925
  }
839
926
 
840
927
  .sb-switch[aria-checked="true"] .sb-switch-knob {
841
- transform: translateX(20px);
928
+ transform: translateX(22px);
842
929
  }
843
930
 
844
931
  /* ---------------------------------------------------------------------------
@@ -869,7 +956,8 @@ html[data-sb-mode="device"] .status {
869
956
 
870
957
  .sb-section-rows {
871
958
  position: absolute;
872
- border-radius: 10px;
959
+ /* iOS 26's inset grouped cards. */
960
+ border-radius: 26px;
873
961
  background: var(--sb-color-grouped-cell);
874
962
  overflow: hidden;
875
963
  }
@@ -885,14 +973,14 @@ html[data-sb-mode="device"] .status {
885
973
 
886
974
  .sb-list-content > :not(.sb-section):first-child,
887
975
  .sb-list-content > .sb-section + :not(.sb-section) {
888
- border-top-left-radius: 10px;
889
- border-top-right-radius: 10px;
976
+ border-top-left-radius: 26px;
977
+ border-top-right-radius: 26px;
890
978
  }
891
979
 
892
980
  .sb-list-content > :not(.sb-section):last-child,
893
981
  .sb-list-content > :not(.sb-section):has(+ .sb-section) {
894
- border-bottom-left-radius: 10px;
895
- border-bottom-right-radius: 10px;
982
+ border-bottom-left-radius: 26px;
983
+ border-bottom-right-radius: 26px;
896
984
  }
897
985
 
898
986
  /* Lazy rows not built yet (a trailing `lazyspacer`): no cell of their own, and
@@ -903,8 +991,8 @@ html[data-sb-mode="device"] .status {
903
991
  }
904
992
 
905
993
  .sb-list-content > :not(.sb-section):has(+ .sb-lazyspacer:last-child) {
906
- border-bottom-left-radius: 10px;
907
- border-bottom-right-radius: 10px;
994
+ border-bottom-left-radius: 26px;
995
+ border-bottom-right-radius: 26px;
908
996
  }
909
997
 
910
998
  .sb-section-rows > :has(+ .sb-lazyspacer:last-child)::after,
@@ -923,16 +1011,18 @@ html[data-sb-mode="device"] .status {
923
1011
  display: none !important;
924
1012
  }
925
1013
 
926
- /* Hairline separators, inset 16px from the leading edge. */
1014
+ /* Separators: iOS 26 starts the line at the row's first text (the engine's
1015
+ `--sb-separator-leading`, else 16px) and ends it 16px before the trailing
1016
+ edge. */
927
1017
  .sb-section-rows > :not(:last-child)::after,
928
1018
  .sb-list-content > :not(.sb-section):not(:last-child):not(:has(+ .sb-section))::after {
929
1019
  content: "";
930
1020
  position: absolute;
931
- left: 16px;
932
- right: 0;
1021
+ left: var(--sb-separator-leading, 16px);
1022
+ right: 16px;
933
1023
  bottom: 0;
934
1024
  height: 1px;
935
- background: var(--sb-color-separator);
1025
+ background: var(--sb-color-row-separator);
936
1026
  pointer-events: none;
937
1027
  }
938
1028
 
@@ -1024,7 +1114,7 @@ html[data-sb-mode="device"] .status {
1024
1114
  display: grid;
1025
1115
  grid-template-columns: 1fr auto 1fr;
1026
1116
  align-items: center;
1027
- padding: 0 8px;
1117
+ padding: 0 16px;
1028
1118
  box-sizing: border-box;
1029
1119
  background: transparent;
1030
1120
  /* Phase 8: content that ignores the safe area paints under the bar; the
@@ -1047,14 +1137,21 @@ html[data-sb-mode="device"] .status {
1047
1137
  justify-self: start;
1048
1138
  display: inline-flex;
1049
1139
  align-items: center;
1140
+ justify-content: center;
1050
1141
  gap: 2px;
1051
- /* Width comes from the layout engine (chrome.back); this is only a fallback. */
1142
+ /* iOS 26: a 44pt glass circle with the chevron (chrome.back). */
1143
+ width: 44px;
1144
+ height: 44px;
1052
1145
  max-width: 45%;
1053
1146
  margin: 0;
1054
1147
  padding: 0;
1055
1148
  border: 0;
1056
- background: none;
1057
- color: var(--sb-color-accent);
1149
+ border-radius: 22px;
1150
+ background: var(--sb-glass-background);
1151
+ box-shadow: var(--sb-glass-shadow);
1152
+ backdrop-filter: blur(12px) saturate(180%);
1153
+ -webkit-backdrop-filter: blur(12px) saturate(180%);
1154
+ color: var(--sb-color-primary);
1058
1155
  font: inherit;
1059
1156
  font-size: var(--sb-font-size-body);
1060
1157
  line-height: 1.3;
@@ -1074,11 +1171,15 @@ html[data-sb-mode="device"] .status {
1074
1171
  .sb-navbar-back > svg {
1075
1172
  width: 1.4em;
1076
1173
  height: 1.4em;
1077
- margin-left: -4px;
1078
- stroke-width: 2.5;
1174
+ margin-left: -2px;
1175
+ stroke-width: 2.25;
1079
1176
  flex-shrink: 0;
1080
1177
  }
1081
1178
 
1179
+ .sb-navbar-back-label:empty {
1180
+ display: none;
1181
+ }
1182
+
1082
1183
  .sb-navbar-back-label {
1083
1184
  overflow: hidden;
1084
1185
  text-overflow: ellipsis;
@@ -1116,14 +1217,16 @@ html[data-sb-mode="device"] .status {
1116
1217
  display: block;
1117
1218
  }
1118
1219
 
1119
- /* Large title: the engine's `largeTitle` rect (52px row), text already
1220
+ /* Large title: the engine's `largeTitle` rect (62px row), text already
1120
1221
  truncated to one line. */
1121
1222
  .sb-navbar-large-title {
1122
1223
  position: absolute;
1123
1224
  z-index: 1; /* Phase 8: above content that ignores the safe area */
1124
1225
  display: flex;
1125
- align-items: center;
1126
- padding: 0 16px;
1226
+ /* iOS 26: the title's line starts 13 into its 62px row. */
1227
+ align-items: flex-start;
1228
+ line-height: 41px;
1229
+ padding: 13px 16px 0;
1127
1230
  box-sizing: border-box;
1128
1231
  font-size: var(--sb-ts-largeTitle-size, 34px);
1129
1232
  font-weight: 700;
@@ -1138,6 +1241,30 @@ html[data-sb-mode="device"] .status {
1138
1241
  display: none;
1139
1242
  }
1140
1243
 
1244
+ /* The large title scrolls with the screen's root list or scroll view
1245
+ (src/largeTitle.ts moves it); drags on it scroll that view. */
1246
+ .sb-navbar-large-title {
1247
+ pointer-events: none;
1248
+ }
1249
+
1250
+ /* Until the large title has scrolled under the bar, the inline title (whose
1251
+ rect the engine reports for a title that can collapse) stays hidden. */
1252
+ .sb-navscreen[data-sb-display="large"] > .sb-navbar > .sb-navbar-title {
1253
+ opacity: 0;
1254
+ transition: opacity 0.15s ease;
1255
+ }
1256
+
1257
+ .sb-navscreen[data-sb-display="large"][data-sb-collapsed] > .sb-navbar > .sb-navbar-title {
1258
+ opacity: 1;
1259
+ }
1260
+
1261
+ /* iOS 26's scroll edge effect, simplified: scrolled content fades in over
1262
+ 16px below the bar instead of being cut off at it (src/largeTitle.ts). */
1263
+ [data-sb-scrolls-title][data-sb-scrolled] {
1264
+ -webkit-mask-image: linear-gradient(to bottom, transparent, #000 16px);
1265
+ mask-image: linear-gradient(to bottom, transparent, #000 16px);
1266
+ }
1267
+
1141
1268
  /* NavigationLink: a tappable label. Inside a list it is a row with a chevron
1142
1269
  at the engine's `chevron` rect, its label in the primary color (also when
1143
1270
  the row is wrapped: a selectable or deletable `listrow`, a modifier);
@@ -1239,6 +1366,26 @@ html[data-sb-mode="device"] .status {
1239
1366
  transition: transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1);
1240
1367
  }
1241
1368
 
1369
+ /* iOS 26: a sheet at a partial detent floats inset from the screen edges,
1370
+ rounded all around, over a lighter dim. */
1371
+ .sb-sheet[data-sb-floating] > .sb-sheet-card {
1372
+ border-radius: 38px;
1373
+ background: color-mix(in srgb, var(--sb-color-sheet-background) 55%, transparent);
1374
+ backdrop-filter: blur(24px) saturate(180%);
1375
+ -webkit-backdrop-filter: blur(24px) saturate(180%);
1376
+ box-shadow: 0 8px 40px rgba(0, 0, 0, 0.18);
1377
+ }
1378
+
1379
+ /* The sheet's glass shows through a navigation stack in it, as on iOS 26
1380
+ (an opaque screen would paint over it). */
1381
+ .sb-sheet[data-sb-floating] .sb-navscreen {
1382
+ background: transparent;
1383
+ }
1384
+
1385
+ .sb-sheet[data-sb-floating] > .sb-sheet-scrim {
1386
+ background: rgba(0, 0, 0, 0.22);
1387
+ }
1388
+
1242
1389
  .sb-sheet-grabber {
1243
1390
  position: absolute;
1244
1391
  border-radius: 2.5px;
@@ -1378,8 +1525,8 @@ html[data-sb-mode="device"] .status {
1378
1525
  /* ---------------------------------------------------------------------------
1379
1526
  Phase 4: tab views. The tabs are stacked in the content slot (every tab has
1380
1527
  the tab view's frame); the selected one is visible, the others keep their
1381
- DOM hidden. The bar is the engine's `bar` rect (49 + bottom safe area):
1382
- translucent system background, hairline on top, items in the 49px row.
1528
+ DOM hidden. The bar is the engine's `bar` rect: iOS 26's glass capsule
1529
+ floating over the content, the selected item on a gray pill.
1383
1530
  ------------------------------------------------------------------------- */
1384
1531
 
1385
1532
  .sb-tabview {
@@ -1403,35 +1550,27 @@ html[data-sb-mode="device"] .status {
1403
1550
  .sb-tabbar {
1404
1551
  position: absolute;
1405
1552
  z-index: 3;
1406
- background: var(--sb-color-tabbar-background);
1553
+ border-radius: 31px;
1554
+ background: var(--sb-glass-background);
1555
+ box-shadow: var(--sb-glass-shadow);
1407
1556
  backdrop-filter: blur(20px) saturate(180%);
1408
1557
  -webkit-backdrop-filter: blur(20px) saturate(180%);
1409
1558
  }
1410
1559
 
1411
- .sb-tabbar::before {
1412
- content: "";
1413
- position: absolute;
1414
- left: 0;
1415
- right: 0;
1416
- top: 0;
1417
- height: 1px;
1418
- background: var(--sb-color-separator);
1419
- pointer-events: none;
1420
- }
1421
-
1422
1560
  .sb-tabbar-item {
1423
1561
  appearance: none;
1424
1562
  position: absolute;
1425
1563
  display: flex;
1426
1564
  flex-direction: column;
1427
1565
  align-items: center;
1428
- justify-content: flex-start;
1429
- gap: 2px;
1566
+ justify-content: center;
1567
+ gap: 1px;
1430
1568
  margin: 0;
1431
- padding: 6px 0 0;
1569
+ padding: 0;
1432
1570
  border: 0;
1571
+ border-radius: 27px;
1433
1572
  background: none;
1434
- color: var(--sb-color-secondary);
1573
+ color: var(--sb-color-primary);
1435
1574
  font-family: var(--sb-font-family);
1436
1575
  cursor: pointer;
1437
1576
  touch-action: manipulation;
@@ -1440,6 +1579,7 @@ html[data-sb-mode="device"] .status {
1440
1579
 
1441
1580
  .sb-tabbar-item[aria-selected="true"] {
1442
1581
  color: var(--sb-color-accent);
1582
+ background: var(--sb-glass-selected);
1443
1583
  }
1444
1584
 
1445
1585
  .sb-tabbar-item:focus-visible {
@@ -1479,7 +1619,7 @@ html[data-sb-mode="device"] .status {
1479
1619
  .sb-tabbar-title {
1480
1620
  font-size: 10px;
1481
1621
  line-height: 12px;
1482
- font-weight: 500;
1622
+ font-weight: 600;
1483
1623
  letter-spacing: -0.01em;
1484
1624
  white-space: nowrap;
1485
1625
  }
@@ -1523,7 +1663,8 @@ html[data-sb-mode="device"] .status {
1523
1663
  box is the whole row, so the track cannot be the element's background). */
1524
1664
  .sb-segment-track {
1525
1665
  position: absolute;
1526
- border-radius: 8px;
1666
+ /* iOS 26: a capsule track with a capsule for the selected segment. */
1667
+ border-radius: 9999px;
1527
1668
  background: var(--sb-color-segment-track);
1528
1669
  pointer-events: none;
1529
1670
  }
@@ -1551,7 +1692,7 @@ html[data-sb-mode="device"] .status {
1551
1692
  content: "";
1552
1693
  position: absolute;
1553
1694
  inset: 2px;
1554
- border-radius: 7px;
1695
+ border-radius: 9999px;
1555
1696
  transition: background-color 0.15s ease, box-shadow 0.15s ease;
1556
1697
  }
1557
1698
 
@@ -1958,7 +2099,7 @@ html[data-sb-mode="device"] .status {
1958
2099
  right: 0;
1959
2100
  top: 0;
1960
2101
  height: 1px;
1961
- background: var(--sb-color-separator);
2102
+ background: var(--sb-color-row-separator);
1962
2103
  pointer-events: none;
1963
2104
  }
1964
2105
 
@@ -1981,6 +2122,25 @@ html[data-sb-mode="device"] .status {
1981
2122
  display: block;
1982
2123
  }
1983
2124
 
2125
+ /* iOS 26: a bar's leading and trailing items share a glass capsule (the
2126
+ engine sizes the group: 44 tall, each item in a slot at least 44 wide),
2127
+ drawn in the label color unless tinted. */
2128
+ .sb-toolbar[data-sb-placement="leading"],
2129
+ .sb-toolbar[data-sb-placement="trailing"] {
2130
+ border-radius: 22px;
2131
+ background: var(--sb-glass-background);
2132
+ box-shadow: var(--sb-glass-shadow);
2133
+ backdrop-filter: blur(12px) saturate(180%);
2134
+ -webkit-backdrop-filter: blur(12px) saturate(180%);
2135
+ --sb-color-accent: var(--sb-color-primary);
2136
+ }
2137
+
2138
+ /* Their symbols are drawn larger and heavier, as iOS 26 draws bar buttons. */
2139
+ .sb-toolbar:is([data-sb-placement="leading"], [data-sb-placement="trailing"]) .sb-image > svg {
2140
+ transform: scale(1.25);
2141
+ stroke-width: 2.1;
2142
+ }
2143
+
1984
2144
  .sb-toolbar[data-sb-placement="bottom"] {
1985
2145
  z-index: 3;
1986
2146
  background: var(--sb-color-tabbar-background);
@@ -1999,16 +2159,21 @@ html[data-sb-mode="device"] .status {
1999
2159
  pointer-events: none;
2000
2160
  }
2001
2161
 
2002
- /* Search field: a 36px rounded gray field (engine `searchField` rect) with a
2162
+ /* Search field: a capsule (engine `searchField` rect) with a
2003
2163
  magnifier leading; the input sends `text` events like a textfield. */
2004
2164
  .sb-searchfield {
2005
2165
  display: flex;
2006
2166
  align-items: center;
2007
- gap: 6px;
2008
- padding: 0 8px;
2009
- border-radius: 10px;
2010
- background: var(--sb-color-fill);
2167
+ gap: 8px;
2168
+ padding: 0 16px;
2169
+ /* iOS 26: a glass capsule floating at the bottom (engine `searchField`). */
2170
+ border-radius: 9999px;
2171
+ background: var(--sb-glass-background);
2172
+ box-shadow: var(--sb-glass-shadow);
2173
+ backdrop-filter: blur(20px) saturate(180%);
2174
+ -webkit-backdrop-filter: blur(20px) saturate(180%);
2011
2175
  color: var(--sb-color-primary);
2176
+ z-index: 2;
2012
2177
  }
2013
2178
 
2014
2179
  .sb-searchfield > svg {
@@ -2166,33 +2331,34 @@ html[data-sb-mode="device"] .status {
2166
2331
  }
2167
2332
 
2168
2333
  /* The SwiftUI chart palette (and the other system colors) as `--sb-color-<name>`,
2169
- which a named `Color` without a semantic token resolves to (src/styles.ts). */
2334
+ which a named `Color` without a semantic token resolves to (src/styles.ts).
2335
+ iOS 26's palette (measured in the iOS 26.2 simulator, Examples/Fidelity). */
2170
2336
  .device,
2171
2337
  .device[data-theme="light"] {
2172
- --sb-color-blue: #007aff;
2173
- --sb-color-orange: #ff9500;
2338
+ --sb-color-blue: #0088ff;
2339
+ --sb-color-orange: #ff8d28;
2174
2340
  --sb-color-yellow: #ffcc00;
2175
- --sb-color-purple: #af52de;
2341
+ --sb-color-purple: #cb30e0;
2176
2342
  --sb-color-pink: #ff2d55;
2177
- --sb-color-teal: #30b0c7;
2178
- --sb-color-indigo: #5856d6;
2179
- --sb-color-mint: #00c7be;
2180
- --sb-color-cyan: #32ade6;
2181
- --sb-color-brown: #a2845e;
2343
+ --sb-color-teal: #00c3d0;
2344
+ --sb-color-indigo: #6155f5;
2345
+ --sb-color-mint: #00c8b3;
2346
+ --sb-color-cyan: #00c0e8;
2347
+ --sb-color-brown: #ac7f5e;
2182
2348
  --sb-color-gray: #8e8e93;
2183
2349
  }
2184
2350
 
2185
2351
  .device[data-theme="dark"] {
2186
- --sb-color-blue: #0a84ff;
2187
- --sb-color-orange: #ff9f0a;
2188
- --sb-color-yellow: #ffd60a;
2189
- --sb-color-purple: #bf5af2;
2352
+ --sb-color-blue: #0091ff;
2353
+ --sb-color-orange: #ff9230;
2354
+ --sb-color-yellow: #ffd600;
2355
+ --sb-color-purple: #db34f2;
2190
2356
  --sb-color-pink: #ff375f;
2191
- --sb-color-teal: #40c8e0;
2192
- --sb-color-indigo: #5e5ce6;
2193
- --sb-color-mint: #63e6e2;
2194
- --sb-color-cyan: #64d2ff;
2195
- --sb-color-brown: #ac8e68;
2357
+ --sb-color-teal: #00d2e0;
2358
+ --sb-color-indigo: #6d7cff;
2359
+ --sb-color-mint: #00dac3;
2360
+ --sb-color-cyan: #3cd3fe;
2361
+ --sb-color-brown: #b78a66;
2196
2362
  --sb-color-gray: #8e8e93;
2197
2363
  }
2198
2364
 
@@ -2603,7 +2769,7 @@ html[data-sb-mode="device"] .status {
2603
2769
  .sb-alert-scrim {
2604
2770
  position: absolute;
2605
2771
  inset: 0;
2606
- background: rgba(0, 0, 0, 0.3);
2772
+ background: var(--sb-alert-scrim);
2607
2773
  animation: sb-alert-fade-in 0.25s ease-out both;
2608
2774
  }
2609
2775
 
@@ -2661,6 +2827,13 @@ html[data-sb-mode="device"] .status {
2661
2827
  background: var(--sb-color-sheet-background);
2662
2828
  }
2663
2829
 
2830
+ /* iOS 26: the alert is a rounder glass card. */
2831
+ .sb-alert[data-sb-style="alert"] .sb-alert-card {
2832
+ border-radius: 34px;
2833
+ background: var(--sb-alert-card);
2834
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.12);
2835
+ }
2836
+
2664
2837
  .sb-alert-title,
2665
2838
  .sb-alert-message {
2666
2839
  position: absolute;
@@ -2671,6 +2844,16 @@ html[data-sb-mode="device"] .status {
2671
2844
  overflow: hidden;
2672
2845
  }
2673
2846
 
2847
+ /* iOS 26: an alert's title and message are leading-aligned, the message dim. */
2848
+ .sb-alert[data-sb-style="alert"] .sb-alert-title,
2849
+ .sb-alert[data-sb-style="alert"] .sb-alert-message {
2850
+ text-align: left;
2851
+ }
2852
+
2853
+ .sb-alert[data-sb-style="alert"] .sb-alert-message {
2854
+ color: var(--sb-color-secondary);
2855
+ }
2856
+
2674
2857
  /* The action sheet's title and message are a dim caption. */
2675
2858
  .sb-alert[data-sb-style="dialog"] .sb-alert-title,
2676
2859
  .sb-alert[data-sb-style="dialog"] .sb-alert-message {
@@ -2711,11 +2894,32 @@ html[data-sb-mode="device"] .status {
2711
2894
  pointer-events: none;
2712
2895
  }
2713
2896
 
2714
- .sb-alert-buttons > .sb-button[data-sb-role="cancel"] {
2897
+ /* iOS 26: an alert's buttons are gray capsules, in the label color. */
2898
+ .sb-alert[data-sb-style="alert"] .sb-alert-buttons > .sb-button,
2899
+ .sb-alert[data-sb-style="alert"] .sb-alert-ok {
2900
+ border-radius: 9999px;
2901
+ background: var(--sb-color-fill);
2902
+ color: var(--sb-color-primary);
2903
+ }
2904
+
2905
+ .sb-alert[data-sb-style="alert"] .sb-alert-buttons > .sb-button::before,
2906
+ .sb-alert[data-sb-style="alert"] .sb-alert-buttons > .sb-button::after,
2907
+ .sb-alert[data-sb-style="alert"] .sb-alert-ok::before {
2908
+ display: none;
2909
+ }
2910
+
2911
+ .sb-alert[data-sb-style="alert"] .sb-alert-buttons > .sb-button:active,
2912
+ .sb-alert[data-sb-style="alert"] .sb-alert-ok:active {
2913
+ background: var(--sb-color-secondary-fill);
2914
+ filter: brightness(0.92);
2915
+ }
2916
+
2917
+ .sb-alert[data-sb-style="dialog"] .sb-alert-buttons > .sb-button[data-sb-role="cancel"] {
2715
2918
  font-weight: 600;
2716
2919
  }
2717
2920
 
2718
- .sb-alert-buttons > .sb-button[data-sb-role="destructive"] {
2921
+ .sb-alert-buttons > .sb-button[data-sb-role="destructive"],
2922
+ .sb-alert[data-sb-style="alert"] .sb-alert-buttons > .sb-button[data-sb-role="destructive"] {
2719
2923
  color: var(--sb-color-red);
2720
2924
  }
2721
2925
 
@@ -2796,14 +3000,14 @@ html[data-sb-mode="device"] .status {
2796
3000
 
2797
3001
  /* ---------------------------------------------------------------------------
2798
3002
  Stepper: the label children are positioned by their frames; the 94×32
2799
- segmented control sits at the engine's `control` rect, its halves divided
2800
- by a hairline. A dimmed half (`aria-disabled`) swallows taps.
3003
+ capsule (iOS 26) sits at the engine's `control` rect, its halves divided
3004
+ by a short line. A dimmed half (`aria-disabled`) swallows taps.
2801
3005
  ------------------------------------------------------------------------- */
2802
3006
  .sb-stepper-control {
2803
3007
  position: absolute;
2804
3008
  display: flex;
2805
3009
  box-sizing: border-box;
2806
- border-radius: 8px;
3010
+ border-radius: 16px;
2807
3011
  background: var(--sb-color-tertiary-fill);
2808
3012
  overflow: hidden;
2809
3013
  }
@@ -2827,7 +3031,17 @@ html[data-sb-mode="device"] .status {
2827
3031
  }
2828
3032
 
2829
3033
  .sb-stepper-button + .sb-stepper-button {
2830
- box-shadow: -1px 0 0 var(--sb-color-separator);
3034
+ position: relative;
3035
+ }
3036
+
3037
+ .sb-stepper-button + .sb-stepper-button::before {
3038
+ content: "";
3039
+ position: absolute;
3040
+ left: 0;
3041
+ top: 7px;
3042
+ bottom: 7px;
3043
+ width: 1px;
3044
+ background: var(--sb-color-opaque-separator);
2831
3045
  }
2832
3046
 
2833
3047
  .sb-stepper-button > svg {
@@ -2848,8 +3062,9 @@ html[data-sb-mode="device"] .status {
2848
3062
  }
2849
3063
 
2850
3064
  /* ---------------------------------------------------------------------------
2851
- Slider: the label children are positioned by their frames; the 4pt track,
2852
- the accent fill and the 27pt thumb are chrome at the engine's rects. A
3065
+ Slider: the label children are positioned by their frames; the 6pt track,
3066
+ the accent fill and the 38 × 24 pill thumb (iOS 26) are chrome at the
3067
+ engine's rects. A
2853
3068
  pointer anywhere on the slider moves the thumb (touch-action none).
2854
3069
  ------------------------------------------------------------------------- */
2855
3070
  .sb-slider {
@@ -2860,20 +3075,20 @@ html[data-sb-mode="device"] .status {
2860
3075
 
2861
3076
  .sb-slider-track {
2862
3077
  position: absolute;
2863
- border-radius: 2px;
3078
+ border-radius: 3px;
2864
3079
  background: var(--sb-color-tertiary-fill);
2865
3080
  }
2866
3081
 
2867
3082
  .sb-slider-fill {
2868
3083
  position: absolute;
2869
- border-radius: 2px;
3084
+ border-radius: 3px;
2870
3085
  background: var(--sb-tint, var(--sb-color-accent));
2871
3086
  }
2872
3087
 
2873
3088
  .sb-slider-thumb {
2874
3089
  position: absolute;
2875
3090
  box-sizing: border-box;
2876
- border-radius: 50%;
3091
+ border-radius: 12px;
2877
3092
  background: #ffffff;
2878
3093
  box-shadow:
2879
3094
  0 3px 8px rgba(0, 0, 0, 0.15),
@@ -3004,8 +3219,9 @@ textarea.sb-textfield[data-sb-style="roundedBorder"] {
3004
3219
  padding: 5px 7px;
3005
3220
  }
3006
3221
 
3007
- /* A section's view header / footer: footnote-sized secondary text above or
3008
- below the card (the engine sets the fonts of the texts inside). */
3222
+ /* A section's view header / footer: secondary text above or below the card
3223
+ (the engine sets the fonts of the texts inside: headline headers, footnote
3224
+ footers). */
3009
3225
  .sb-sectionheader,
3010
3226
  .sb-sectionfooter {
3011
3227
  color: var(--sb-color-secondary);