@twentyfirstmedia/halo 0.4.0 → 0.6.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/dist/styles.css CHANGED
@@ -335,6 +335,11 @@
335
335
  --chart-lilac: var(--lilac);
336
336
  --chart-butter: var(--butter);
337
337
  --chart-blush: var(--blush);
338
+ --ramp-1: color-mix(in oklab, var(--chart-1) 12%, var(--background));
339
+ --ramp-2: color-mix(in oklab, var(--chart-1) 28%, var(--background));
340
+ --ramp-3: color-mix(in oklab, var(--chart-1) 46%, var(--background));
341
+ --ramp-4: color-mix(in oklab, var(--chart-1) 66%, var(--background));
342
+ --ramp-5: color-mix(in oklab, var(--chart-1) 88%, var(--background));
338
343
  --ok: #2f5d16;
339
344
  --ok-bg: #d6efc3;
340
345
  --info: #1f4f8a;
@@ -483,6 +488,11 @@
483
488
  --chart-lilac: var(--lilac-ink);
484
489
  --chart-butter: var(--butter-ink);
485
490
  --chart-blush: var(--blush-ink);
491
+ --ramp-1: color-mix(in oklab, var(--chart-1) 12%, var(--background));
492
+ --ramp-2: color-mix(in oklab, var(--chart-1) 28%, var(--background));
493
+ --ramp-3: color-mix(in oklab, var(--chart-1) 46%, var(--background));
494
+ --ramp-4: color-mix(in oklab, var(--chart-1) 66%, var(--background));
495
+ --ramp-5: color-mix(in oklab, var(--chart-1) 88%, var(--background));
486
496
  --ok: #a8db86;
487
497
  --ok-bg: #24401a;
488
498
  --info: #9cc6f7;
@@ -632,6 +642,11 @@
632
642
  --chart-lilac: var(--lilac-ink);
633
643
  --chart-butter: var(--butter-ink);
634
644
  --chart-blush: var(--blush-ink);
645
+ --ramp-1: color-mix(in oklab, var(--chart-1) 12%, var(--background));
646
+ --ramp-2: color-mix(in oklab, var(--chart-1) 28%, var(--background));
647
+ --ramp-3: color-mix(in oklab, var(--chart-1) 46%, var(--background));
648
+ --ramp-4: color-mix(in oklab, var(--chart-1) 66%, var(--background));
649
+ --ramp-5: color-mix(in oklab, var(--chart-1) 88%, var(--background));
635
650
  --ok: #a8db86;
636
651
  --ok-bg: #24401a;
637
652
  --info: #9cc6f7;
@@ -781,6 +796,11 @@
781
796
  --chart-lilac: var(--lilac);
782
797
  --chart-butter: var(--butter);
783
798
  --chart-blush: var(--blush);
799
+ --ramp-1: color-mix(in oklab, var(--chart-1) 12%, var(--background));
800
+ --ramp-2: color-mix(in oklab, var(--chart-1) 28%, var(--background));
801
+ --ramp-3: color-mix(in oklab, var(--chart-1) 46%, var(--background));
802
+ --ramp-4: color-mix(in oklab, var(--chart-1) 66%, var(--background));
803
+ --ramp-5: color-mix(in oklab, var(--chart-1) 88%, var(--background));
784
804
  --ok: #2f5d16;
785
805
  --ok-bg: #d6efc3;
786
806
  --info: #1f4f8a;
@@ -929,6 +949,11 @@
929
949
  --chart-lilac: var(--lilac-ink);
930
950
  --chart-butter: var(--butter-ink);
931
951
  --chart-blush: var(--blush-ink);
952
+ --ramp-1: color-mix(in oklab, var(--chart-1) 12%, var(--background));
953
+ --ramp-2: color-mix(in oklab, var(--chart-1) 28%, var(--background));
954
+ --ramp-3: color-mix(in oklab, var(--chart-1) 46%, var(--background));
955
+ --ramp-4: color-mix(in oklab, var(--chart-1) 66%, var(--background));
956
+ --ramp-5: color-mix(in oklab, var(--chart-1) 88%, var(--background));
932
957
  --ok: #a8db86;
933
958
  --ok-bg: #24401a;
934
959
  --info: #9cc6f7;
@@ -1076,6 +1101,11 @@
1076
1101
  --chart-lilac: var(--lilac);
1077
1102
  --chart-butter: var(--butter);
1078
1103
  --chart-blush: var(--blush);
1104
+ --ramp-1: color-mix(in oklab, var(--chart-1) 12%, var(--background));
1105
+ --ramp-2: color-mix(in oklab, var(--chart-1) 28%, var(--background));
1106
+ --ramp-3: color-mix(in oklab, var(--chart-1) 46%, var(--background));
1107
+ --ramp-4: color-mix(in oklab, var(--chart-1) 66%, var(--background));
1108
+ --ramp-5: color-mix(in oklab, var(--chart-1) 88%, var(--background));
1079
1109
  --ok: #2f5d16;
1080
1110
  --ok-bg: #d6efc3;
1081
1111
  --info: #1f4f8a;
@@ -1620,7 +1650,8 @@ select.tf-input {
1620
1650
  border-radius: var(--radius-pill);
1621
1651
  background: var(--surface-sunken);
1622
1652
  color: var(--ink-muted);
1623
- min-width: 220px;
1653
+ min-width: min(220px, 100%);
1654
+ box-sizing: border-box;
1624
1655
  }
1625
1656
  .tf-search input {
1626
1657
  border: 0;
@@ -1629,6 +1660,7 @@ select.tf-input {
1629
1660
  font: 500 14px/20px var(--font-sans);
1630
1661
  color: var(--ink);
1631
1662
  width: 100%;
1663
+ min-width: 0;
1632
1664
  }
1633
1665
  .tf-search input::placeholder {
1634
1666
  color: var(--ink-subtle);
@@ -1710,7 +1742,7 @@ select.tf-input {
1710
1742
  display: flex;
1711
1743
  }
1712
1744
  .tf-tabs-block .tf-tab {
1713
- flex: 1;
1745
+ flex: 1 1 0;
1714
1746
  }
1715
1747
 
1716
1748
  /* StatTile */
@@ -2027,6 +2059,36 @@ select.tf-input {
2027
2059
  background: var(--accent);
2028
2060
  color: var(--accent-foreground);
2029
2061
  }
2062
+ /* expanded: names next to the icons (the sheet's first column follows the rail's width) */
2063
+ .tf-rail {
2064
+ transition: width var(--dur-base) var(--ease-out);
2065
+ }
2066
+ .tf-rail.expanded {
2067
+ width: 200px;
2068
+ }
2069
+ .tf-rail.expanded .tf-rail-group {
2070
+ align-items: stretch;
2071
+ }
2072
+ .tf-rail.expanded .tf-rail-btn {
2073
+ display: flex;
2074
+ align-items: center;
2075
+ gap: 12px;
2076
+ width: 100%;
2077
+ padding: 0 10px;
2078
+ box-sizing: border-box;
2079
+ border-radius: var(--radius-pill);
2080
+ }
2081
+ .tf-rail-label {
2082
+ min-width: 0;
2083
+ overflow: hidden;
2084
+ text-overflow: ellipsis;
2085
+ white-space: nowrap;
2086
+ font: 600 13px/18px var(--font-sans);
2087
+ }
2088
+ .tf-rail.expanded .tf-dotcount {
2089
+ position: static;
2090
+ margin-left: auto;
2091
+ }
2030
2092
  .tf-rail-btn[aria-current="page"] {
2031
2093
  background: var(--primary);
2032
2094
  color: var(--primary-foreground);
@@ -2176,9 +2238,28 @@ select.tf-input {
2176
2238
  .tf-shell .tf-topbar {
2177
2239
  padding: 0 var(--space-6);
2178
2240
  }
2241
+ /* AppShell with navigation="sidebar": the labelled sidebar on the frame, the sheet beside it */
2242
+ .tf-shell.tf-shell-sidebar {
2243
+ display: grid;
2244
+ grid-template-columns: auto minmax(0, 1fr);
2245
+ align-items: stretch;
2246
+ padding: 8px;
2247
+ }
2248
+ .tf-shell-tools {
2249
+ display: flex;
2250
+ justify-content: flex-end;
2251
+ flex-wrap: wrap;
2252
+ gap: 8px;
2253
+ }
2254
+ .tf-sheet.tf-sheet-norail {
2255
+ grid-template-columns: minmax(0, 1fr) 300px;
2256
+ }
2257
+ .tf-sheet.tf-sheet-norail.tf-sheet-2 {
2258
+ grid-template-columns: minmax(0, 1fr);
2259
+ }
2179
2260
  .tf-sheet {
2180
2261
  display: grid;
2181
- grid-template-columns: 44px 1fr 300px;
2262
+ grid-template-columns: auto 1fr 300px;
2182
2263
  gap: var(--space-6);
2183
2264
  padding: var(--space-6);
2184
2265
  background: var(--canvas);
@@ -2695,6 +2776,64 @@ select.tf-input {
2695
2776
  background: var(--accent);
2696
2777
  color: var(--accent-foreground);
2697
2778
  }
2779
+ a.tf-row-item {
2780
+ text-decoration: none;
2781
+ }
2782
+ .tf-row-text {
2783
+ min-width: 0;
2784
+ }
2785
+ /* not interactive: no hover, no pointer */
2786
+ .tf-row-item.static {
2787
+ cursor: default;
2788
+ }
2789
+ .tf-row-item.static:hover {
2790
+ background: transparent;
2791
+ color: var(--ink);
2792
+ }
2793
+ /* own buttons: the title is the link or button and its hit area stretches over the row */
2794
+ .tf-row-item.has-hit {
2795
+ position: relative;
2796
+ }
2797
+ .tf-row-item.has-hit:hover {
2798
+ background: transparent;
2799
+ color: var(--ink);
2800
+ }
2801
+ .tf-row-item.has-hit:has(.tf-row-hit:hover) {
2802
+ background: var(--accent);
2803
+ color: var(--accent-foreground);
2804
+ }
2805
+ .tf-row-item.has-hit:has(.tf-row-hit:focus-visible) {
2806
+ outline: 2px solid var(--focus);
2807
+ outline-offset: 2px;
2808
+ }
2809
+ .tf-row-hit {
2810
+ display: block;
2811
+ padding: 0;
2812
+ border: 0;
2813
+ background: none;
2814
+ color: inherit;
2815
+ font: inherit;
2816
+ text-align: left;
2817
+ text-decoration: none;
2818
+ cursor: pointer;
2819
+ outline: none;
2820
+ }
2821
+ .tf-row-hit::after {
2822
+ content: "";
2823
+ position: absolute;
2824
+ inset: 0;
2825
+ border-radius: inherit;
2826
+ }
2827
+ .tf-row-item.has-actions {
2828
+ grid-template-columns: auto 1fr auto auto;
2829
+ }
2830
+ .tf-row-actions {
2831
+ position: relative;
2832
+ z-index: 1;
2833
+ display: flex;
2834
+ align-items: center;
2835
+ gap: 4px;
2836
+ }
2698
2837
  .tf-row-item[aria-current="true"] {
2699
2838
  background: var(--surface);
2700
2839
  box-shadow: var(--shadow-card);
@@ -2706,12 +2845,27 @@ select.tf-input {
2706
2845
  gap: 8px;
2707
2846
  }
2708
2847
  .tf-row-sub {
2848
+ display: block;
2709
2849
  font: 500 13px/18px var(--font-sans);
2710
2850
  color: var(--ink-muted);
2711
2851
  white-space: nowrap;
2712
2852
  overflow: hidden;
2713
2853
  text-overflow: ellipsis;
2714
2854
  }
2855
+ /* titleLines / subtitleLines: wrap, then end in an ellipsis after that many lines */
2856
+ .tf-row-sub.clamp,
2857
+ .tf-row-clamp {
2858
+ display: -webkit-box;
2859
+ -webkit-box-orient: vertical;
2860
+ -webkit-line-clamp: var(--lines, 2);
2861
+ line-clamp: var(--lines, 2);
2862
+ white-space: normal;
2863
+ overflow: hidden;
2864
+ min-width: 0;
2865
+ }
2866
+ .tf-row-title.clamp {
2867
+ align-items: flex-start;
2868
+ }
2715
2869
  .tf-row-meta {
2716
2870
  font: 600 12px/16px var(--font-sans);
2717
2871
  color: var(--ink-muted);
@@ -2898,6 +3052,13 @@ select.tf-input {
2898
3052
  font: 600 13px/1 var(--font-sans);
2899
3053
  cursor: pointer;
2900
3054
  }
3055
+ a.tf-page {
3056
+ display: inline-flex;
3057
+ align-items: center;
3058
+ justify-content: center;
3059
+ box-sizing: border-box;
3060
+ text-decoration: none;
3061
+ }
2901
3062
  .tf-page:hover {
2902
3063
  background: var(--accent);
2903
3064
  color: var(--ink);
@@ -2908,18 +3069,42 @@ select.tf-input {
2908
3069
  }
2909
3070
  .tf-crumbs {
2910
3071
  display: flex;
3072
+ flex-wrap: wrap;
2911
3073
  align-items: center;
2912
3074
  gap: 6px;
3075
+ min-width: 0;
2913
3076
  font: 600 13px/18px var(--font-sans);
2914
3077
  color: var(--ink-muted);
2915
3078
  }
2916
- .tf-crumbs a {
3079
+ /* links and buttons get a 24px target without moving the text */
3080
+ .tf-crumb {
3081
+ display: inline-flex;
3082
+ align-items: center;
3083
+ min-height: 24px;
3084
+ max-width: 100%;
3085
+ padding: 0 4px;
3086
+ /* the target grows to 24px around the 18px line without moving the text */
3087
+ margin: -3px -4px;
3088
+ border: 0;
3089
+ border-radius: var(--radius-sm);
3090
+ background: none;
2917
3091
  color: inherit;
3092
+ font: inherit;
2918
3093
  text-decoration: none;
3094
+ overflow-wrap: anywhere;
3095
+ }
3096
+ a.tf-crumb,
3097
+ button.tf-crumb {
3098
+ cursor: pointer;
2919
3099
  }
2920
- .tf-crumbs a:hover {
3100
+ a.tf-crumb:hover,
3101
+ button.tf-crumb:hover {
2921
3102
  color: var(--ink);
2922
3103
  }
3104
+ .tf-crumb:focus-visible {
3105
+ outline: 2px solid var(--focus);
3106
+ outline-offset: 0;
3107
+ }
2923
3108
  .tf-crumbs [aria-current] {
2924
3109
  color: var(--ink);
2925
3110
  }
@@ -2961,7 +3146,7 @@ select.tf-input {
2961
3146
  cursor: pointer;
2962
3147
  }
2963
3148
  .tf-sheet-2 {
2964
- grid-template-columns: 44px 1fr;
3149
+ grid-template-columns: auto 1fr;
2965
3150
  }
2966
3151
  .tf-main {
2967
3152
  display: flex;
@@ -3031,6 +3216,26 @@ select.tf-input {
3031
3216
  justify-content: center;
3032
3217
  }
3033
3218
  }
3219
+ /* the TopBar measured that the labels do not fit: icons only, at any width */
3220
+ .tf-nav.tight .tf-nav-label {
3221
+ display: none;
3222
+ }
3223
+ .tf-nav.tight .tf-nav-item {
3224
+ position: relative;
3225
+ width: 36px;
3226
+ padding: 0;
3227
+ justify-content: center;
3228
+ }
3229
+ .tf-nav.tight .tf-nav-item .tf-nav-count {
3230
+ position: absolute;
3231
+ top: -2px;
3232
+ right: -4px;
3233
+ min-width: 16px;
3234
+ height: 16px;
3235
+ padding: 0 4px;
3236
+ font-size: 10px;
3237
+ line-height: 16px;
3238
+ }
3034
3239
  .tf-main {
3035
3240
  animation: none;
3036
3241
  }
@@ -3156,6 +3361,19 @@ select.tf-input {
3156
3361
  .tf-user-text {
3157
3362
  display: flex;
3158
3363
  flex-direction: column;
3364
+ min-width: 0;
3365
+ max-width: 200px;
3366
+ }
3367
+ /* a long name or address ends in an ellipsis instead of pushing the nav out (title has it whole) */
3368
+ .tf-user-name,
3369
+ .tf-user-mail {
3370
+ overflow: hidden;
3371
+ text-overflow: ellipsis;
3372
+ white-space: nowrap;
3373
+ }
3374
+ .tf-user {
3375
+ min-width: 0;
3376
+ flex-shrink: 1;
3159
3377
  }
3160
3378
 
3161
3379
  /* Checkbox: real box + SVG check (no pseudo-elements on the input) */
@@ -3168,9 +3386,12 @@ select.tf-input {
3168
3386
  }
3169
3387
  .tf-checkbox input {
3170
3388
  position: absolute;
3171
- inset: 0;
3172
- width: 100%;
3173
- height: 100%;
3389
+ /* the box keeps its size; the hit area is at least 24px (WCAG 2.2 target size) */
3390
+ top: 50%;
3391
+ left: 50%;
3392
+ translate: -50% -50%;
3393
+ width: max(24px, 100%);
3394
+ height: max(24px, 100%);
3174
3395
  margin: 0;
3175
3396
  opacity: 0;
3176
3397
  cursor: pointer;
@@ -4244,6 +4465,23 @@ select.tf-input {
4244
4465
  font: 600 13px/18px var(--font-sans);
4245
4466
  pointer-events: none;
4246
4467
  }
4468
+ /* an interactive control at the end (reveal password, clear, copy) */
4469
+ .tf-input-action {
4470
+ position: absolute;
4471
+ right: 4px;
4472
+ top: 50%;
4473
+ transform: translateY(-50%);
4474
+ display: inline-flex;
4475
+ }
4476
+ .tf-inputwrap.has-action .tf-input {
4477
+ padding-right: 44px;
4478
+ }
4479
+ .tf-inputwrap.has-action.has-suffix .tf-input {
4480
+ padding-right: 72px;
4481
+ }
4482
+ .tf-inputwrap.has-action .tf-input-suffix {
4483
+ right: 44px;
4484
+ }
4247
4485
  .tf-input-suffix.err {
4248
4486
  color: var(--blush-ink);
4249
4487
  }
@@ -4403,7 +4641,7 @@ select.tf-input {
4403
4641
  display: flex;
4404
4642
  }
4405
4643
  .tf-seg.block .tf-seg-item {
4406
- flex: 1;
4644
+ flex: 1 1 0;
4407
4645
  }
4408
4646
  .tf-seg-item {
4409
4647
  position: relative;
@@ -5015,6 +5253,10 @@ label.tf-menu-item {
5015
5253
  border-color var(--dur-fast) ease,
5016
5254
  background-color var(--dur-fast) ease;
5017
5255
  }
5256
+ .tf-drop.disabled {
5257
+ opacity: 0.5;
5258
+ cursor: not-allowed;
5259
+ }
5018
5260
  .tf-drop b {
5019
5261
  font: 600 14px/20px var(--font-sans);
5020
5262
  margin-top: 4px;
@@ -5077,6 +5319,7 @@ label.tf-menu-item {
5077
5319
  /* Alert, confirm, toaster */
5078
5320
  .tf-alert {
5079
5321
  display: flex;
5322
+ flex-wrap: wrap;
5080
5323
  align-items: flex-start;
5081
5324
  gap: 12px;
5082
5325
  padding: 12px 12px 12px 16px;
@@ -5120,7 +5363,8 @@ label.tf-menu-item {
5120
5363
  color: var(--lilac-ink);
5121
5364
  }
5122
5365
  .tf-alert-body {
5123
- flex: 1;
5366
+ /* when the alert is too narrow for text and actions, the actions move to their own line */
5367
+ flex: 1 1 200px;
5124
5368
  min-width: 0;
5125
5369
  display: flex;
5126
5370
  flex-direction: column;
@@ -5136,8 +5380,11 @@ label.tf-menu-item {
5136
5380
  .tf-alert-actions {
5137
5381
  flex: none;
5138
5382
  display: flex;
5383
+ flex-wrap: wrap;
5139
5384
  align-items: center;
5140
5385
  gap: 4px;
5386
+ max-width: 100%;
5387
+ margin-left: auto;
5141
5388
  }
5142
5389
  .tf-alert .tf-iconbtn-ghost {
5143
5390
  background: transparent;
@@ -6141,14 +6388,29 @@ label.tf-menu-item {
6141
6388
  display: inline-flex;
6142
6389
  align-items: center;
6143
6390
  gap: 8px;
6144
- height: 32px;
6145
- padding: 0 12px 0 4px;
6391
+ /* grows with a long title (two lines at most) instead of spilling over */
6392
+ min-height: 32px;
6393
+ box-sizing: border-box;
6394
+ padding: 4px 12px 4px 4px;
6146
6395
  border-radius: var(--radius-pill);
6147
6396
  background: var(--surface-sunken);
6148
6397
  color: var(--ink);
6149
6398
  text-decoration: none;
6150
6399
  font: 600 12px/16px var(--font-sans);
6151
- max-width: 260px;
6400
+ max-width: min(260px, 100%);
6401
+ }
6402
+ .tf-source-title {
6403
+ min-width: 0;
6404
+ display: -webkit-box;
6405
+ -webkit-box-orient: vertical;
6406
+ -webkit-line-clamp: 2;
6407
+ line-clamp: 2;
6408
+ overflow: hidden;
6409
+ overflow-wrap: anywhere;
6410
+ }
6411
+ .tf-source > .tf-ico,
6412
+ .tf-source-n {
6413
+ flex: none;
6152
6414
  }
6153
6415
  .tf-source:hover {
6154
6416
  background: var(--line);
@@ -7271,17 +7533,25 @@ label.tf-menu-item {
7271
7533
  color: var(--ink-muted);
7272
7534
  }
7273
7535
  .tf-csteps {
7536
+ /* one row at every width: steps shrink to their numbers instead of wrapping */
7537
+ container: tf-csteps / inline-size;
7274
7538
  display: flex;
7275
7539
  gap: 8px;
7276
7540
  margin: 0;
7277
7541
  padding: 0;
7278
7542
  list-style: none;
7279
- flex-wrap: wrap;
7280
7543
  }
7281
7544
  .tf-csteps li {
7282
7545
  display: flex;
7283
7546
  align-items: center;
7284
7547
  gap: 8px;
7548
+ min-width: 0;
7549
+ }
7550
+ .tf-cstep-label {
7551
+ min-width: 0;
7552
+ overflow: hidden;
7553
+ text-overflow: ellipsis;
7554
+ white-space: nowrap;
7285
7555
  }
7286
7556
  .tf-csteps li + li::before {
7287
7557
  content: "";
@@ -7310,6 +7580,40 @@ label.tf-menu-item {
7310
7580
  .tf-csteps button:disabled {
7311
7581
  cursor: default;
7312
7582
  }
7583
+ .tf-csteps button {
7584
+ min-width: 0;
7585
+ max-width: 100%;
7586
+ }
7587
+ .tf-csteps.compact li:not(.cur) .tf-cstep-label {
7588
+ position: absolute;
7589
+ width: 1px;
7590
+ height: 1px;
7591
+ overflow: hidden;
7592
+ clip-path: inset(50%);
7593
+ white-space: nowrap;
7594
+ }
7595
+ .tf-csteps.compact li:not(.cur) button {
7596
+ padding: 0 4px;
7597
+ }
7598
+ .tf-csteps.compact li + li::before {
7599
+ width: 12px;
7600
+ }
7601
+ @container tf-csteps (max-width: 560px) {
7602
+ .tf-csteps li:not(.cur) .tf-cstep-label {
7603
+ position: absolute;
7604
+ width: 1px;
7605
+ height: 1px;
7606
+ overflow: hidden;
7607
+ clip-path: inset(50%);
7608
+ white-space: nowrap;
7609
+ }
7610
+ .tf-csteps li:not(.cur) button {
7611
+ padding: 0 4px;
7612
+ }
7613
+ .tf-csteps li + li::before {
7614
+ width: 12px;
7615
+ }
7616
+ }
7313
7617
  .tf-csteps li.cur button {
7314
7618
  background: var(--surface);
7315
7619
  color: var(--ink);
@@ -7476,7 +7780,7 @@ label.tf-menu-item {
7476
7780
  color: var(--on-frame);
7477
7781
  box-shadow: var(--shadow-float);
7478
7782
  }
7479
- .tf-plan.featured .tf-plan-head span,
7783
+ .tf-plan.featured .tf-plan-head span:not(.tf-badge),
7480
7784
  .tf-plan.featured .tf-plan-price span,
7481
7785
  .tf-plan.featured .tf-plan-price s,
7482
7786
  .tf-plan.featured .tf-plan-feats li.no {
@@ -7507,10 +7811,22 @@ label.tf-menu-item {
7507
7811
  .tf-plan-head b {
7508
7812
  font: 700 20px/26px var(--font-sans);
7509
7813
  }
7510
- .tf-plan-head span {
7814
+ .tf-plan-head span:not(.tf-badge) {
7511
7815
  font: 500 13px/18px var(--font-sans);
7512
7816
  color: var(--ink-muted);
7513
7817
  }
7818
+ /* "Current plan" next to the name, and the note under the price */
7819
+ .tf-plan-head .tf-plan-current {
7820
+ align-self: flex-start;
7821
+ }
7822
+ .tf-plan-note {
7823
+ margin: -4px 0 0;
7824
+ font: 500 12px/16px var(--font-sans);
7825
+ color: var(--ink-muted);
7826
+ }
7827
+ a.tf-plan-cta {
7828
+ text-decoration: none;
7829
+ }
7514
7830
  .tf-plan-price {
7515
7831
  display: flex;
7516
7832
  align-items: baseline;
@@ -9610,7 +9926,7 @@ label.tf-menu-item {
9610
9926
  .tf-tabbar {
9611
9927
  display: grid;
9612
9928
  grid-auto-flow: column;
9613
- grid-auto-columns: 1fr;
9929
+ grid-auto-columns: minmax(0, 1fr);
9614
9930
  padding: 4px 8px calc(4px + env(safe-area-inset-bottom, 0px));
9615
9931
  background: var(--frame);
9616
9932
  border-radius: 24px 24px 0 0;
@@ -9629,6 +9945,17 @@ label.tf-menu-item {
9629
9945
  cursor: pointer;
9630
9946
  border-radius: 16px;
9631
9947
  }
9948
+ .tf-tabbar-item {
9949
+ min-width: 0;
9950
+ }
9951
+ .tf-tabbar-label {
9952
+ max-width: 100%;
9953
+ padding: 0 4px;
9954
+ box-sizing: border-box;
9955
+ overflow: hidden;
9956
+ text-overflow: ellipsis;
9957
+ white-space: nowrap;
9958
+ }
9632
9959
  .tf-tabbar-item.on {
9633
9960
  color: var(--on-frame);
9634
9961
  background: var(--frame-hover);
@@ -9936,6 +10263,22 @@ label.tf-menu-item {
9936
10263
  padding-bottom: 10px;
9937
10264
  color: var(--ink-muted);
9938
10265
  }
10266
+ /* in a narrow column (a filter sidebar) the number fields give their padding to the digits */
10267
+ .tf-range {
10268
+ container: tf-range / inline-size;
10269
+ }
10270
+ @container tf-range (max-width: 280px) {
10271
+ .tf-range-inputs {
10272
+ gap: 4px;
10273
+ }
10274
+ .tf-range-num .tf-input {
10275
+ padding-left: 10px;
10276
+ padding-right: 24px;
10277
+ }
10278
+ .tf-range-num > span {
10279
+ right: 10px;
10280
+ }
10281
+ }
9939
10282
  .tf-range-vals {
9940
10283
  display: flex;
9941
10284
  justify-content: space-between;
@@ -10089,6 +10432,31 @@ label.tf-menu-item {
10089
10432
  font: 500 12px/16px var(--font-sans);
10090
10433
  color: var(--ink-muted);
10091
10434
  }
10435
+ /* layout="list": compact rows */
10436
+ .tf-tiles.list {
10437
+ grid-template-columns: minmax(0, 1fr);
10438
+ gap: 8px;
10439
+ }
10440
+ .tf-tiles.list .tf-tile {
10441
+ flex-direction: row;
10442
+ align-items: center;
10443
+ gap: 12px;
10444
+ padding: 8px 44px 8px 8px;
10445
+ }
10446
+ .tf-tiles.list .tf-tile-art {
10447
+ flex: none;
10448
+ width: 40px;
10449
+ height: 40px;
10450
+ aspect-ratio: auto;
10451
+ }
10452
+ .tf-tiles.list .tf-tile-label {
10453
+ min-width: 0;
10454
+ padding: 0;
10455
+ }
10456
+ .tf-tiles.list .tf-tile-check {
10457
+ top: 50%;
10458
+ translate: 0 -50%;
10459
+ }
10092
10460
  .tf-tile-check {
10093
10461
  position: absolute;
10094
10462
  top: 14px;
@@ -11198,6 +11566,16 @@ button.tf-runs-main[aria-expanded]:hover {
11198
11566
  color: var(--paper-ink);
11199
11567
  box-shadow: inset 0 0 0 1px var(--line);
11200
11568
  }
11569
+ /* QrCode: dark modules on paper, in every theme (scanners expect dark on light) */
11570
+ .tf-qr {
11571
+ display: block;
11572
+ width: 100%;
11573
+ height: auto;
11574
+ color: var(--paper-ink);
11575
+ }
11576
+ .tf-qr-bg {
11577
+ fill: var(--paper);
11578
+ }
11201
11579
  .tf-2fa-qr > * {
11202
11580
  max-width: 100%;
11203
11581
  max-height: 100%;
@@ -11449,7 +11827,8 @@ button.tf-runs-main[aria-expanded]:hover {
11449
11827
  border-radius: var(--radius-md);
11450
11828
  overflow: hidden;
11451
11829
  background: var(--surface-sunken);
11452
- touch-action: none;
11830
+ /* sideways drags move the divider; the page still scrolls up and down over it */
11831
+ touch-action: pan-y;
11453
11832
  user-select: none;
11454
11833
  cursor: ew-resize;
11455
11834
  }
@@ -12348,6 +12727,14 @@ button.tf-runs-main[aria-expanded]:hover {
12348
12727
  .tf-togglegroup .tf-toggle {
12349
12728
  height: 32px;
12350
12729
  }
12730
+ .tf-togglegroup.block {
12731
+ display: flex;
12732
+ flex-wrap: nowrap;
12733
+ width: auto;
12734
+ }
12735
+ .tf-togglegroup.block .tf-toggle {
12736
+ flex: 1 1 0;
12737
+ }
12351
12738
  .tf-togglegroup .tf-toggle.icon {
12352
12739
  width: 32px;
12353
12740
  }
@@ -12558,6 +12945,11 @@ button.tf-runs-main[aria-expanded]:hover {
12558
12945
  text-align: left;
12559
12946
  cursor: pointer;
12560
12947
  }
12948
+ .tf-selectmenu.sm {
12949
+ height: 32px;
12950
+ padding: 0 12px;
12951
+ font-size: 13px;
12952
+ }
12561
12953
  .tf-selectmenu.empty .tf-selectmenu-value {
12562
12954
  color: var(--ink-subtle);
12563
12955
  }
@@ -12834,26 +13226,44 @@ button.tf-runs-main[aria-expanded]:hover {
12834
13226
  outline-offset: -2px;
12835
13227
  }
12836
13228
 
12837
- /* Sidebar */
13229
+ /* Sidebar: floating (a card), attached (flush with the screen's edge) or on the AppShell frame */
12838
13230
  .tf-sidebar {
12839
13231
  display: flex;
12840
13232
  flex-direction: column;
12841
- gap: 16px;
13233
+ flex: none;
13234
+ gap: 12px;
12842
13235
  width: 248px;
12843
13236
  padding: 12px;
12844
13237
  box-sizing: border-box;
12845
13238
  border-radius: var(--radius-lg);
12846
13239
  background: var(--surface);
12847
13240
  box-shadow: var(--shadow-card);
13241
+ color: var(--ink);
12848
13242
  transition: width var(--dur-base) var(--ease-out);
12849
13243
  }
12850
13244
  .tf-sidebar.collapsed {
12851
13245
  width: 64px;
12852
13246
  }
13247
+ .tf-sidebar.attached {
13248
+ align-self: stretch;
13249
+ min-height: 100%;
13250
+ border-radius: 0;
13251
+ box-shadow: none;
13252
+ background: var(--sidebar);
13253
+ border-right: 1px solid var(--sidebar-border);
13254
+ }
13255
+ .tf-sidebar-head {
13256
+ display: flex;
13257
+ align-items: center;
13258
+ gap: 8px;
13259
+ min-height: 40px;
13260
+ padding: 0 4px;
13261
+ }
12853
13262
  .tf-sidebar-body {
12854
13263
  display: flex;
12855
13264
  flex-direction: column;
12856
- gap: 16px;
13265
+ /* groups sit clearly apart; a label sits close to its own items */
13266
+ gap: 20px;
12857
13267
  flex: 1;
12858
13268
  min-height: 0;
12859
13269
  overflow-y: auto;
@@ -12866,13 +13276,49 @@ button.tf-runs-main[aria-expanded]:hover {
12866
13276
  padding: 0;
12867
13277
  list-style: none;
12868
13278
  }
13279
+ .tf-sidebar-grouphead {
13280
+ display: flex;
13281
+ align-items: center;
13282
+ gap: 4px;
13283
+ min-height: 24px;
13284
+ margin-bottom: 8px;
13285
+ padding: 0 4px 0 12px;
13286
+ }
12869
13287
  .tf-sidebar-grouplabel {
12870
- padding: 0 12px 6px;
13288
+ display: flex;
13289
+ align-items: center;
13290
+ gap: 4px;
13291
+ flex: 1;
13292
+ min-width: 0;
13293
+ padding: 0;
13294
+ border: 0;
13295
+ background: none;
12871
13296
  font: 600 11px/14px var(--font-sans);
12872
13297
  letter-spacing: 0.06em;
12873
13298
  text-transform: uppercase;
13299
+ text-align: left;
12874
13300
  color: var(--ink-muted);
12875
13301
  }
13302
+ button.tf-sidebar-grouplabel {
13303
+ cursor: pointer;
13304
+ }
13305
+ button.tf-sidebar-grouplabel:hover {
13306
+ color: var(--ink);
13307
+ }
13308
+ button.tf-sidebar-grouplabel:focus-visible {
13309
+ outline: 2px solid var(--focus);
13310
+ outline-offset: 2px;
13311
+ }
13312
+ .tf-sidebar-grouplabel[aria-expanded="false"] .tf-sidebar-chev {
13313
+ transform: rotate(-90deg);
13314
+ }
13315
+ .tf-sidebar-groupaction {
13316
+ flex: none;
13317
+ margin-left: auto;
13318
+ }
13319
+ .tf-sidebar-li {
13320
+ position: relative;
13321
+ }
12876
13322
  .tf-sidebar-item {
12877
13323
  display: flex;
12878
13324
  align-items: center;
@@ -12880,15 +13326,86 @@ button.tf-runs-main[aria-expanded]:hover {
12880
13326
  width: 100%;
12881
13327
  height: 40px;
12882
13328
  padding: 0 12px;
13329
+ box-sizing: border-box;
12883
13330
  border: 0;
12884
13331
  border-radius: var(--radius-pill);
12885
13332
  background: transparent;
12886
13333
  color: var(--ink-muted);
12887
13334
  font: 600 13px/18px var(--font-sans);
12888
13335
  text-align: left;
13336
+ text-decoration: none;
12889
13337
  cursor: pointer;
12890
13338
  }
12891
- .tf-sidebar-item:hover {
13339
+ /* Filter options (Sidebar as="aside"): a checkbox or radio mark, the label and a count */
13340
+ .tf-sidebar-option {
13341
+ position: relative;
13342
+ }
13343
+ .tf-sidebar-option.disabled {
13344
+ opacity: 0.45;
13345
+ cursor: default;
13346
+ }
13347
+ .tf-sidebar-input {
13348
+ position: absolute;
13349
+ width: 1px;
13350
+ height: 1px;
13351
+ margin: 0;
13352
+ opacity: 0;
13353
+ pointer-events: none;
13354
+ }
13355
+ .tf-sidebar-mark {
13356
+ display: grid;
13357
+ place-items: center;
13358
+ flex: none;
13359
+ width: 18px;
13360
+ height: 18px;
13361
+ box-sizing: border-box;
13362
+ border-radius: 6px;
13363
+ border: 1.5px solid var(--line-strong);
13364
+ background: var(--surface);
13365
+ color: var(--primary-foreground);
13366
+ transition:
13367
+ background-color var(--dur-fast) var(--ease-out),
13368
+ border-color var(--dur-fast) var(--ease-out);
13369
+ }
13370
+ .tf-sidebar-mark.radio {
13371
+ border-radius: 50%;
13372
+ }
13373
+ .tf-sidebar-mark svg {
13374
+ opacity: 0;
13375
+ }
13376
+ .tf-sidebar-input:checked + .tf-sidebar-mark {
13377
+ background: var(--primary);
13378
+ border-color: var(--primary);
13379
+ }
13380
+ .tf-sidebar-input:checked + .tf-sidebar-mark.radio {
13381
+ box-shadow: inset 0 0 0 3px var(--surface);
13382
+ }
13383
+ .tf-sidebar-input:checked + .tf-sidebar-mark svg {
13384
+ opacity: 1;
13385
+ }
13386
+ .tf-sidebar-input:focus-visible + .tf-sidebar-mark {
13387
+ outline: 2px solid var(--focus);
13388
+ outline-offset: 2px;
13389
+ }
13390
+ .tf-sidebar-option:has(.tf-sidebar-input:checked) {
13391
+ color: var(--ink);
13392
+ }
13393
+ /* free content in a group (sliders, date fields, chips) */
13394
+ .tf-sidebar-content {
13395
+ display: flex;
13396
+ flex-direction: column;
13397
+ gap: 12px;
13398
+ padding: 4px 12px 0;
13399
+ min-width: 0;
13400
+ }
13401
+ .tf-sidebar-groupbody {
13402
+ display: flex;
13403
+ flex-direction: column;
13404
+ gap: 2px;
13405
+ min-width: 0;
13406
+ }
13407
+ .tf-sidebar-item:hover,
13408
+ .tf-sidebar-item.flying {
12892
13409
  background: var(--sidebar-accent);
12893
13410
  color: var(--ink);
12894
13411
  }
@@ -12903,10 +13420,21 @@ button.tf-runs-main[aria-expanded]:hover {
12903
13420
  outline: 2px solid var(--focus);
12904
13421
  outline-offset: 2px;
12905
13422
  }
13423
+ .tf-sidebar-item:disabled {
13424
+ opacity: 0.45;
13425
+ cursor: not-allowed;
13426
+ }
13427
+ .tf-sidebar-item:disabled:hover {
13428
+ background: transparent;
13429
+ color: var(--ink-muted);
13430
+ }
12906
13431
  .tf-sidebar-item.nested {
12907
13432
  height: 32px;
12908
13433
  padding-left: 40px;
12909
13434
  }
13435
+ .tf-sidebar-sub {
13436
+ margin-top: 2px !important;
13437
+ }
12910
13438
  .tf-sidebar-label {
12911
13439
  flex: 1;
12912
13440
  min-width: 0;
@@ -12915,22 +13443,107 @@ button.tf-runs-main[aria-expanded]:hover {
12915
13443
  white-space: nowrap;
12916
13444
  }
12917
13445
  .tf-sidebar-chev {
13446
+ flex: none;
12918
13447
  transition: transform var(--dur-base) var(--ease-out);
12919
13448
  }
12920
13449
  .tf-sidebar-item[aria-expanded="true"] .tf-sidebar-chev {
12921
13450
  transform: rotate(180deg);
12922
13451
  }
13452
+ .tf-sidebar-ext {
13453
+ flex: none;
13454
+ opacity: 0.7;
13455
+ }
13456
+ .tf-sidebar-count {
13457
+ flex: none;
13458
+ min-width: 20px;
13459
+ height: 20px;
13460
+ padding: 0 6px;
13461
+ box-sizing: border-box;
13462
+ border-radius: var(--radius-pill);
13463
+ background: var(--count);
13464
+ color: var(--on-count);
13465
+ font: 700 11px/20px var(--font-sans);
13466
+ text-align: center;
13467
+ }
13468
+ .tf-sidebar-badge {
13469
+ flex: none;
13470
+ height: 20px;
13471
+ padding: 0 8px;
13472
+ box-sizing: border-box;
13473
+ border-radius: var(--radius-pill);
13474
+ background: var(--count);
13475
+ color: var(--on-count);
13476
+ font: 700 10px/20px var(--font-sans);
13477
+ letter-spacing: 0.04em;
13478
+ text-transform: uppercase;
13479
+ }
13480
+ .tf-sidebar-dot {
13481
+ flex: none;
13482
+ width: 8px;
13483
+ height: 8px;
13484
+ border-radius: 50%;
13485
+ background: var(--count);
13486
+ }
13487
+ .tf-sidebar-sr {
13488
+ position: absolute;
13489
+ width: 1px;
13490
+ height: 1px;
13491
+ overflow: hidden;
13492
+ clip-path: inset(50%);
13493
+ white-space: nowrap;
13494
+ }
13495
+ /* the "…" menu of an item shows on hover and focus */
13496
+ .tf-sidebar-li.with-actions > .tf-sidebar-item {
13497
+ padding-right: 40px;
13498
+ }
13499
+ .tf-sidebar-more {
13500
+ position: absolute;
13501
+ top: 4px;
13502
+ right: 4px;
13503
+ opacity: 0;
13504
+ transition: opacity var(--dur-fast) var(--ease-out);
13505
+ }
13506
+ .tf-sidebar-li:hover > .tf-sidebar-more,
13507
+ .tf-sidebar-more:focus-visible,
13508
+ .tf-sidebar-more[aria-expanded="true"] {
13509
+ opacity: 1;
13510
+ }
12923
13511
  .tf-sidebar-foot {
12924
13512
  display: flex;
12925
13513
  align-items: center;
12926
- justify-content: space-between;
12927
13514
  gap: 8px;
12928
13515
  padding-top: 12px;
12929
13516
  border-top: 1px solid var(--sidebar-border);
12930
13517
  }
13518
+ .tf-sidebar-foot > :not(.tf-sidebar-toggle) {
13519
+ flex: 1;
13520
+ min-width: 0;
13521
+ }
13522
+ .tf-sidebar-toggle {
13523
+ flex: none;
13524
+ margin-left: auto;
13525
+ }
13526
+ .tf-sidebar-head .tf-pop-anchor,
13527
+ .tf-sidebar-foot .tf-pop-anchor {
13528
+ display: block;
13529
+ min-width: 0;
13530
+ }
13531
+ .tf-sidebar-head .tf-wssw {
13532
+ width: 100%;
13533
+ }
13534
+ .tf-sidebar-head .tf-wssw .tf-option-text {
13535
+ flex: 1;
13536
+ min-width: 0;
13537
+ }
13538
+
13539
+ /* collapsed: icons only; labels stay the accessible names, tooltips and flyouts show them */
13540
+ .tf-sidebar.collapsed .tf-sidebar-body {
13541
+ gap: 12px;
13542
+ }
12931
13543
  .tf-sidebar.collapsed .tf-sidebar-label,
12932
13544
  .tf-sidebar.collapsed .tf-sidebar-chev,
12933
- .tf-sidebar.collapsed .tf-sidebar-grouplabel {
13545
+ .tf-sidebar.collapsed .tf-sidebar-ext,
13546
+ .tf-sidebar.collapsed .tf-sidebar-grouphead {
12934
13547
  position: absolute;
12935
13548
  width: 1px;
12936
13549
  height: 1px;
@@ -12938,12 +13551,19 @@ button.tf-runs-main[aria-expanded]:hover {
12938
13551
  clip-path: inset(50%);
12939
13552
  white-space: nowrap;
12940
13553
  }
13554
+ .tf-sidebar.collapsed .tf-sidebar-group + .tf-sidebar-group {
13555
+ padding-top: 12px;
13556
+ border-top: 1px solid var(--sidebar-border);
13557
+ }
12941
13558
  .tf-sidebar.collapsed .tf-sidebar-item {
12942
13559
  position: relative;
12943
13560
  justify-content: center;
12944
13561
  padding: 0;
12945
13562
  }
12946
- .tf-sidebar.collapsed .tf-subnav-count {
13563
+ .tf-sidebar.collapsed .tf-sidebar-item.has-current {
13564
+ background: var(--sidebar-accent);
13565
+ }
13566
+ .tf-sidebar.collapsed .tf-sidebar-count {
12947
13567
  position: absolute;
12948
13568
  top: -2px;
12949
13569
  right: -2px;
@@ -12953,13 +13573,273 @@ button.tf-runs-main[aria-expanded]:hover {
12953
13573
  font-size: 10px;
12954
13574
  line-height: 16px;
12955
13575
  }
13576
+ .tf-sidebar.collapsed .tf-sidebar-dot,
13577
+ .tf-sidebar.collapsed .tf-sidebar-badge {
13578
+ position: absolute;
13579
+ top: 6px;
13580
+ right: 8px;
13581
+ width: 8px;
13582
+ height: 8px;
13583
+ padding: 0;
13584
+ font-size: 0;
13585
+ }
13586
+ .tf-sidebar.collapsed .tf-sidebar-head {
13587
+ justify-content: center;
13588
+ padding: 0;
13589
+ }
12956
13590
  .tf-sidebar.collapsed .tf-sidebar-foot {
12957
13591
  flex-direction: column;
12958
13592
  }
13593
+ .tf-sidebar.collapsed .tf-sidebar-foot > :not(.tf-sidebar-toggle) {
13594
+ flex: none;
13595
+ }
13596
+ .tf-sidebar.collapsed .tf-sidebar-toggle {
13597
+ margin-left: 0;
13598
+ }
13599
+
13600
+ /* tooltips, flyouts and item menus float in the portal, so the scrolling body does not clip them */
13601
+ .tf-sidebar-layer {
13602
+ position: fixed;
13603
+ z-index: var(--z-palette);
13604
+ }
13605
+ .tf-sidebar-tip {
13606
+ display: inline-flex;
13607
+ align-items: center;
13608
+ gap: 8px;
13609
+ padding: 4px 8px;
13610
+ border-radius: var(--radius-sm);
13611
+ background: var(--frame);
13612
+ color: var(--on-frame);
13613
+ font: 600 12px/16px var(--font-sans);
13614
+ white-space: nowrap;
13615
+ pointer-events: none;
13616
+ animation: tf-fade var(--dur-fast) var(--ease-out) both;
13617
+ }
13618
+ .tf-sidebar-tipcount {
13619
+ color: var(--on-frame-muted);
13620
+ }
13621
+ .tf-sidebar-flyout {
13622
+ min-width: 200px;
13623
+ padding: 6px;
13624
+ border-radius: var(--radius-md);
13625
+ background: var(--surface);
13626
+ color: var(--ink);
13627
+ box-shadow: var(--shadow-float);
13628
+ animation: tf-fade var(--dur-fast) var(--ease-out) both;
13629
+ }
13630
+ .tf-sidebar-flyout ul {
13631
+ display: flex;
13632
+ flex-direction: column;
13633
+ gap: 2px;
13634
+ margin: 0;
13635
+ padding: 0;
13636
+ list-style: none;
13637
+ }
13638
+ .tf-sidebar-flytitle {
13639
+ padding: 6px 12px 8px;
13640
+ font: 600 11px/14px var(--font-sans);
13641
+ letter-spacing: 0.06em;
13642
+ text-transform: uppercase;
13643
+ color: var(--ink-muted);
13644
+ }
13645
+ .tf-sidebar-flyout .tf-sidebar-item.nested {
13646
+ padding-left: 12px;
13647
+ }
13648
+
13649
+ /* on the AppShell frame */
13650
+ .tf-sidebar.shell {
13651
+ align-self: stretch;
13652
+ padding: 16px 8px 8px;
13653
+ border-radius: 0;
13654
+ background: transparent;
13655
+ box-shadow: none;
13656
+ color: var(--on-frame);
13657
+ }
13658
+ .tf-sidebar.shell .tf-sidebar-item,
13659
+ .tf-sidebar.shell .tf-sidebar-grouplabel {
13660
+ color: var(--on-frame-muted);
13661
+ }
13662
+ .tf-sidebar.shell .tf-sidebar-item:hover,
13663
+ .tf-sidebar.shell .tf-sidebar-item.flying,
13664
+ .tf-sidebar.shell.collapsed .tf-sidebar-item.has-current {
13665
+ background: var(--frame-hover);
13666
+ color: var(--on-frame);
13667
+ }
13668
+ .tf-sidebar.shell .tf-sidebar-item.has-current,
13669
+ .tf-sidebar.shell button.tf-sidebar-grouplabel:hover {
13670
+ color: var(--on-frame);
13671
+ }
13672
+ .tf-sidebar.shell .tf-sidebar-item[aria-current="page"] {
13673
+ background: var(--frame-active);
13674
+ color: var(--on-frame);
13675
+ }
13676
+ .tf-sidebar.shell .tf-sidebar-item:disabled:hover {
13677
+ background: transparent;
13678
+ color: var(--on-frame-muted);
13679
+ }
13680
+ .tf-sidebar.shell .tf-sidebar-foot,
13681
+ .tf-sidebar.shell.collapsed .tf-sidebar-group + .tf-sidebar-group {
13682
+ border-color: var(--frame-hover);
13683
+ }
13684
+ .tf-sidebar.shell .tf-iconbtn-ghost {
13685
+ color: var(--on-frame-muted);
13686
+ }
13687
+ .tf-sidebar.shell .tf-iconbtn-ghost:hover {
13688
+ background: var(--frame-hover);
13689
+ color: var(--on-frame);
13690
+ }
13691
+ .tf-sidebar.shell .tf-sidebar-head {
13692
+ min-height: 44px;
13693
+ }
13694
+
13695
+ /* UserMenu: the signed-in person, opening their account menu */
13696
+ .tf-usermenu {
13697
+ display: flex;
13698
+ align-items: center;
13699
+ gap: 10px;
13700
+ width: 100%;
13701
+ min-height: 44px;
13702
+ padding: 4px 8px 4px 4px;
13703
+ box-sizing: border-box;
13704
+ border: 0;
13705
+ border-radius: var(--radius-pill);
13706
+ background: transparent;
13707
+ color: var(--ink);
13708
+ font: inherit;
13709
+ text-align: left;
13710
+ cursor: pointer;
13711
+ }
13712
+ .tf-usermenu.compact {
13713
+ width: auto;
13714
+ padding: 4px;
13715
+ }
13716
+ .tf-usermenu:hover,
13717
+ .tf-usermenu[aria-expanded="true"] {
13718
+ background: var(--sidebar-accent);
13719
+ }
13720
+ .tf-usermenu:focus-visible {
13721
+ outline: 2px solid var(--focus);
13722
+ outline-offset: 2px;
13723
+ }
13724
+ .tf-usermenu-avatar {
13725
+ display: inline-flex;
13726
+ flex: none;
13727
+ }
13728
+ .tf-usermenu-text {
13729
+ display: flex;
13730
+ flex-direction: column;
13731
+ flex: 1;
13732
+ min-width: 0;
13733
+ }
13734
+ .tf-usermenu-name {
13735
+ font: 600 13px/18px var(--font-sans);
13736
+ overflow: hidden;
13737
+ text-overflow: ellipsis;
13738
+ white-space: nowrap;
13739
+ }
13740
+ .tf-usermenu-mail {
13741
+ font: 500 11px/14px var(--font-sans);
13742
+ color: var(--ink-muted);
13743
+ overflow: hidden;
13744
+ text-overflow: ellipsis;
13745
+ white-space: nowrap;
13746
+ }
13747
+ .tf-sidebar.shell .tf-usermenu {
13748
+ color: var(--on-frame);
13749
+ }
13750
+ .tf-sidebar.shell .tf-usermenu:hover,
13751
+ .tf-sidebar.shell .tf-usermenu[aria-expanded="true"] {
13752
+ background: var(--frame-hover);
13753
+ }
13754
+ .tf-sidebar.shell .tf-usermenu-mail {
13755
+ color: var(--on-frame-muted);
13756
+ }
13757
+ .tf-wssw.compact {
13758
+ padding: 4px;
13759
+ }
13760
+
13761
+ /* the bar that opens the sidebar as a drawer on phones */
13762
+ .tf-sidebar-bar,
13763
+ .tf-sidebar-scrim {
13764
+ display: none;
13765
+ }
12959
13766
  @media (max-width: 760px) {
12960
- .tf-sidebar {
12961
- width: 100%;
13767
+ .tf-sidebar-bar {
13768
+ display: flex;
13769
+ align-items: center;
13770
+ gap: 8px;
13771
+ min-height: 52px;
13772
+ padding: 6px 12px 6px 6px;
13773
+ box-sizing: border-box;
13774
+ border-radius: var(--radius-lg);
13775
+ background: var(--surface);
13776
+ box-shadow: var(--shadow-card);
13777
+ color: var(--ink);
13778
+ }
13779
+ .tf-sidebar-bar.attached {
13780
+ border-radius: 0;
13781
+ box-shadow: none;
13782
+ background: var(--sidebar);
13783
+ border-bottom: 1px solid var(--sidebar-border);
13784
+ }
13785
+ .tf-sidebar-bar.shell {
13786
+ min-height: 56px;
13787
+ padding: 8px 8px 8px 0;
13788
+ border-radius: 0;
13789
+ box-shadow: none;
13790
+ background: transparent;
13791
+ color: var(--on-frame);
13792
+ }
13793
+ .tf-sidebar-bar.shell .tf-iconbtn-ghost {
13794
+ color: var(--on-frame);
13795
+ }
13796
+ .tf-sidebar-bar > :not(.tf-iconbtn) {
13797
+ min-width: 0;
13798
+ }
13799
+ .tf-sidebar,
13800
+ .tf-sidebar.attached,
13801
+ .tf-sidebar.shell {
13802
+ position: fixed;
13803
+ top: 0;
13804
+ bottom: 0;
13805
+ left: 0;
13806
+ z-index: var(--z-overlay);
13807
+ width: min(300px, 86vw);
13808
+ min-height: 0;
13809
+ padding: 12px;
13810
+ border-radius: 0 var(--radius-lg) var(--radius-lg) 0;
13811
+ box-shadow: var(--shadow-float);
13812
+ transform: translateX(-105%);
13813
+ visibility: hidden;
13814
+ transition:
13815
+ transform var(--dur-base) var(--ease-out),
13816
+ visibility 0s linear var(--dur-base);
13817
+ }
13818
+ .tf-sidebar.shell {
13819
+ background: var(--frame);
13820
+ }
13821
+ .tf-sidebar.attached {
13822
+ background: var(--sidebar);
13823
+ }
13824
+ .tf-sidebar.open {
13825
+ transform: none;
13826
+ visibility: visible;
13827
+ transition: transform var(--dur-base) var(--ease-out);
12962
13828
  }
13829
+ .tf-sidebar-toggle {
13830
+ display: none;
13831
+ }
13832
+ .tf-sidebar-scrim {
13833
+ display: block;
13834
+ position: fixed;
13835
+ inset: 0;
13836
+ z-index: var(--z-overlay);
13837
+ background: var(--scrim-strong);
13838
+ animation: tf-fade var(--dur-base) var(--ease-out) both;
13839
+ }
13840
+ }
13841
+
13842
+ @media (max-width: 760px) {
12963
13843
  .tf-navmenu-panel.with-feature {
12964
13844
  grid-template-columns: minmax(0, 1fr);
12965
13845
  }
@@ -13141,7 +14021,7 @@ a.tf-iconbtn {
13141
14021
  /* Tablet: asides move below the main column, nav labels and the page nav shrink to icons */
13142
14022
  @container tf-shell (max-width: 1180px) {
13143
14023
  .tf-sheet:not(.tf-sheet-2):not(.tf-sheet-nav) {
13144
- grid-template-columns: 44px minmax(0, 1fr);
14024
+ grid-template-columns: auto minmax(0, 1fr);
13145
14025
  }
13146
14026
  .tf-sheet-nav.tf-sheet-aside {
13147
14027
  grid-template-columns: 208px minmax(0, 1fr);
@@ -13149,6 +14029,13 @@ a.tf-iconbtn {
13149
14029
  .tf-sheet > .tf-main ~ :not(.tf-dock-float) {
13150
14030
  grid-column: 2;
13151
14031
  }
14032
+ /* with the sidebar there is no rail column: asides go below the main column */
14033
+ .tf-sheet.tf-sheet-norail:not(.tf-sheet-2) {
14034
+ grid-template-columns: minmax(0, 1fr);
14035
+ }
14036
+ .tf-sheet-norail > .tf-main ~ :not(.tf-dock-float) {
14037
+ grid-column: 1;
14038
+ }
13152
14039
  /* the dock floats over the end of the sheet, not of the main column (asides follow it) */
13153
14040
  .tf-main-dock {
13154
14041
  padding-bottom: 0;
@@ -13179,7 +14066,7 @@ a.tf-iconbtn {
13179
14066
  @container tf-shell (max-width: 1040px) {
13180
14067
  .tf-sheet-nav,
13181
14068
  .tf-sheet-nav.tf-sheet-aside {
13182
- grid-template-columns: 44px minmax(0, 1fr);
14069
+ grid-template-columns: auto minmax(0, 1fr);
13183
14070
  }
13184
14071
  .tf-subnav-eyebrow {
13185
14072
  display: none;
@@ -13276,6 +14163,21 @@ a.tf-iconbtn {
13276
14163
  .tf-rail-group {
13277
14164
  flex-direction: row;
13278
14165
  }
14166
+ /* on phones the rail is a row of icons, expanded or not */
14167
+ .tf-rail.expanded {
14168
+ width: auto;
14169
+ }
14170
+ .tf-rail.expanded .tf-rail-btn {
14171
+ display: grid;
14172
+ width: 40px;
14173
+ padding: 0;
14174
+ }
14175
+ .tf-rail.expanded .tf-rail-label {
14176
+ display: none;
14177
+ }
14178
+ .tf-rail.expanded .tf-dotcount {
14179
+ position: absolute;
14180
+ }
13279
14181
  .tf-main {
13280
14182
  gap: var(--space-4);
13281
14183
  }
@@ -13367,6 +14269,56 @@ a.tf-iconbtn {
13367
14269
  max-width: 100%;
13368
14270
  overflow-x: auto;
13369
14271
  }
14272
+ /* Table stack: narrow boxes show every row as a card, each cell with its column label */
14273
+ .tf-table-stackbox {
14274
+ container: tf-table / inline-size;
14275
+ }
14276
+ @container tf-table (max-width: 600px) {
14277
+ .tf-table.stack thead {
14278
+ position: absolute;
14279
+ width: 1px;
14280
+ height: 1px;
14281
+ overflow: hidden;
14282
+ clip-path: inset(50%);
14283
+ }
14284
+ .tf-table.stack,
14285
+ .tf-table.stack tbody,
14286
+ .tf-table.stack tr {
14287
+ display: block;
14288
+ }
14289
+ .tf-table.stack tr {
14290
+ padding: 8px 0;
14291
+ border-bottom: 1px solid var(--line);
14292
+ }
14293
+ .tf-table.stack tr:last-child {
14294
+ border-bottom: 0;
14295
+ }
14296
+ .tf-table.stack td {
14297
+ display: flex;
14298
+ align-items: center;
14299
+ justify-content: space-between;
14300
+ gap: 16px;
14301
+ height: auto;
14302
+ min-height: 32px;
14303
+ padding: 4px 0;
14304
+ border-bottom: 0;
14305
+ text-align: right;
14306
+ white-space: normal;
14307
+ }
14308
+ .tf-table.stack td::before {
14309
+ content: attr(data-label);
14310
+ flex: none;
14311
+ max-width: 50%;
14312
+ text-align: left;
14313
+ font: 600 11px/14px var(--font-sans);
14314
+ letter-spacing: 0.06em;
14315
+ text-transform: uppercase;
14316
+ color: var(--ink-muted);
14317
+ }
14318
+ .tf-table.stack tbody tr:hover td {
14319
+ background: transparent;
14320
+ }
14321
+ }
13370
14322
 
13371
14323
  /* ── Phone: components ── */
13372
14324
  @media (max-width: 760px) {
@@ -13401,15 +14353,15 @@ a.tf-iconbtn {
13401
14353
  height: 52px;
13402
14354
  }
13403
14355
 
13404
- /* segmented controls and tabs scroll sideways when the labels do not fit */
13405
- .tf-seg,
13406
- .tf-tabs {
14356
+ /* segmented controls and tabs scroll sideways when the labels do not fit (block ones shrink) */
14357
+ .tf-seg:not(.block),
14358
+ .tf-tabs:not(.tf-tabs-block) {
13407
14359
  max-width: 100%;
13408
14360
  overflow-x: auto;
13409
14361
  scrollbar-width: none;
13410
14362
  }
13411
- .tf-seg-item,
13412
- .tf-tab {
14363
+ .tf-seg:not(.block) .tf-seg-item,
14364
+ .tf-tabs:not(.tf-tabs-block) .tf-tab {
13413
14365
  flex: none;
13414
14366
  }
13415
14367
  .tf-seg,
@@ -13558,6 +14510,40 @@ a.tf-iconbtn {
13558
14510
  }
13559
14511
  }
13560
14512
 
14513
+ /* AppShell with a sidebar on phones: the sidebar's bar on top of the frame, the sheet below */
14514
+ @media (max-width: 760px) {
14515
+ .tf-shell.tf-shell-sidebar {
14516
+ grid-template-columns: minmax(0, 1fr);
14517
+ padding: 0 8px 8px;
14518
+ }
14519
+ }
14520
+
14521
+ /* Fluid at every width: segmented controls, tabs and toggle groups never push past their
14522
+ container. When space runs short the items shrink and their labels end in an ellipsis. */
14523
+ .tf-tabs {
14524
+ max-width: 100%;
14525
+ box-sizing: border-box;
14526
+ }
14527
+ .tf-seg-item,
14528
+ .tf-tab,
14529
+ .tf-togglegroup .tf-toggle {
14530
+ min-width: 0;
14531
+ }
14532
+ .tf-seg-label,
14533
+ .tf-tab,
14534
+ .tf-toggle-label {
14535
+ overflow: hidden;
14536
+ text-overflow: ellipsis;
14537
+ white-space: nowrap;
14538
+ }
14539
+
14540
+ /* key hints mean nothing on touch screens */
14541
+ @media (pointer: coarse) {
14542
+ .tf-search .tf-kbd {
14543
+ display: none;
14544
+ }
14545
+ }
14546
+
13561
14547
  /* 07-polish.css */
13562
14548
  /* ───────────── Polish ─────────────
13563
14549
  Small consistency fixes found by auditing every preview in both kits and themes. Zero
@@ -13987,11 +14973,13 @@ textarea.tf-input,
13987
14973
  inset: 0;
13988
14974
  z-index: 1;
13989
14975
  display: grid;
13990
- grid-template-columns: minmax(0, 320px) minmax(0, 1fr) minmax(0, 340px);
14976
+ grid-template-columns:
14977
+ minmax(0, var(--floating-start, 320px)) minmax(0, 1fr)
14978
+ minmax(0, var(--floating-end, 340px));
13991
14979
  grid-template-rows: auto minmax(0, 1fr) auto;
13992
14980
  grid-template-areas:
13993
14981
  "top top top"
13994
- "start . end"
14982
+ "start controls end"
13995
14983
  "bottom bottom bottom";
13996
14984
  gap: var(--space-4);
13997
14985
  padding: var(--space-4);
@@ -14022,6 +15010,32 @@ textarea.tf-input,
14022
15010
  grid-area: bottom;
14023
15011
  justify-self: center;
14024
15012
  }
15013
+ /* background controls and source notes: the free corner, clear of the panels and the dock */
15014
+ .tf-floating-ui > .tf-floating-controls {
15015
+ grid-area: controls;
15016
+ align-self: end;
15017
+ justify-self: end;
15018
+ display: flex;
15019
+ flex-direction: column;
15020
+ align-items: flex-end;
15021
+ gap: var(--space-2);
15022
+ pointer-events: none;
15023
+ }
15024
+ .tf-floating-controls > * {
15025
+ pointer-events: auto;
15026
+ }
15027
+ .tf-floating-attribution {
15028
+ max-width: 100%;
15029
+ padding: 2px 8px;
15030
+ border-radius: var(--radius-sm);
15031
+ background: var(--surface);
15032
+ color: var(--ink-muted);
15033
+ font: 500 11px/16px var(--font-sans);
15034
+ overflow-wrap: anywhere;
15035
+ }
15036
+ .tf-floating-handle {
15037
+ display: none;
15038
+ }
14025
15039
  .tf-floating-ui > :is(.tf-floating-top, .tf-floating-bottom) {
14026
15040
  pointer-events: none;
14027
15041
  }
@@ -14047,6 +15061,75 @@ textarea.tf-input,
14047
15061
  gap: var(--space-3);
14048
15062
  padding: var(--space-3);
14049
15063
  }
15064
+ .tf-floating-ui > .tf-floating-controls {
15065
+ grid-area: auto;
15066
+ grid-row: 3;
15067
+ }
15068
+ /* the end slot as a bottom sheet over the background: a peek, or most of the height */
15069
+ .tf-floating.has-sheet .tf-floating-ui {
15070
+ grid-template-rows: auto auto minmax(120px, 1fr) auto;
15071
+ grid-template-areas:
15072
+ "top"
15073
+ "start"
15074
+ "."
15075
+ "bottom";
15076
+ padding-bottom: calc(var(--space-3) + 96px);
15077
+ }
15078
+ .tf-floating.has-sheet .tf-floating-end {
15079
+ position: absolute;
15080
+ left: var(--space-3);
15081
+ right: var(--space-3);
15082
+ bottom: 0;
15083
+ z-index: 2;
15084
+ max-height: 96px;
15085
+ overflow: hidden;
15086
+ border-radius: var(--radius-lg) var(--radius-lg) 0 0;
15087
+ background: var(--surface);
15088
+ box-shadow: var(--shadow-card);
15089
+ transition: max-height var(--dur-base) var(--ease-out);
15090
+ }
15091
+ [data-surface="glass"].tf-floating.has-sheet .tf-floating-end {
15092
+ background: var(--glass);
15093
+ -webkit-backdrop-filter: var(--glass-filter);
15094
+ backdrop-filter: var(--glass-filter);
15095
+ }
15096
+ .tf-floating.has-sheet.sheet-full .tf-floating-end {
15097
+ max-height: 75%;
15098
+ overflow-y: auto;
15099
+ }
15100
+ .tf-floating.has-sheet .tf-floating-handle {
15101
+ display: block;
15102
+ position: sticky;
15103
+ top: 0;
15104
+ z-index: 1;
15105
+ width: 100%;
15106
+ height: 24px;
15107
+ margin: 0;
15108
+ padding: 0;
15109
+ border: 0;
15110
+ background: transparent;
15111
+ cursor: pointer;
15112
+ }
15113
+ .tf-floating.has-sheet .tf-floating-handle::before {
15114
+ content: "";
15115
+ display: block;
15116
+ width: 40px;
15117
+ height: 4px;
15118
+ margin: 10px auto;
15119
+ border-radius: var(--radius-pill);
15120
+ background: var(--line-strong);
15121
+ }
15122
+ .tf-floating.has-sheet .tf-floating-handle:focus-visible {
15123
+ outline: 2px solid var(--focus);
15124
+ outline-offset: -2px;
15125
+ }
15126
+ }
15127
+
15128
+ /* in a glass layout the attribution is glass too */
15129
+ [data-surface="glass"] .tf-floating-attribution {
15130
+ background: var(--glass);
15131
+ -webkit-backdrop-filter: var(--glass-filter);
15132
+ backdrop-filter: var(--glass-filter);
14050
15133
  }
14051
15134
 
14052
15135
  /* 09-motion.css */