@mlola-ui/tokens 1.2.2 → 1.3.1

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.
@@ -1,15 +1,8 @@
1
- /* Library recipes — owned by Mlola, no utility framework. */
2
-
3
- /* engine/base */
4
- /* `hidden` must win over any display a recipe sets (display: grid on a
5
- collapsible body would otherwise keep it open). */
1
+ /* @mlola-ui/engine recipes.css, generated. The sources keep the comments. */
6
2
  :where([hidden]:not([hidden="until-found"])) {
7
3
  display: none !important;
8
4
  }
9
5
 
10
- /* Icons sit on the text's optical center and keep their size inside flex
11
- rows; a squeezed row shrinks text, not glyphs. The same rules ship in
12
- @mlola-ui/icons/glyphs.css for apps that use the icons without the engine. */
13
6
  :where(.mlola-glyph) {
14
7
  display: inline-block;
15
8
  flex-shrink: 0;
@@ -29,7 +22,6 @@
29
22
  --mlola-glyph-optical-scale: 1.03;
30
23
  }
31
24
 
32
- /* The mark after a link to another site, which opens in a new tab. */
33
25
  .ml-link-external {
34
26
  margin-inline-start: var(--ml-space-1);
35
27
  vertical-align: -.125em;
@@ -52,7 +44,6 @@
52
44
  z-index: var(--ml-layer-overlay);
53
45
  }
54
46
 
55
- /* A glyph inside a link flows with the text instead of breaking the line. */
56
47
  .ml-link > .mlola-glyph {
57
48
  display: inline;
58
49
  margin-inline-start: 0.15em;
@@ -151,7 +142,6 @@
151
142
  gap: var(--ml-space-2);
152
143
  }
153
144
 
154
- /* A list of benefits, each after a check. Pricing tiers and feature rows share it. */
155
145
  .ml-check-list {
156
146
  margin: 0;
157
147
  padding: 0;
@@ -176,12 +166,10 @@
176
166
 
177
167
  .ml-section {
178
168
  padding-block: var(--ml-space-fluid-xl);
179
- /* A section is a grid or flex item in a page shell; without this, a wide
180
- table inside it widens the whole page instead of scrolling in place. */
169
+
181
170
  min-width: 0;
182
171
  }
183
172
 
184
- /* A section a link jumps to clears the sticky navigation bar. */
185
173
  .ml-section[id] {
186
174
  scroll-margin-block-start: calc(var(--ml-control-md) + var(--ml-space-6));
187
175
  }
@@ -189,8 +177,7 @@
189
177
  .ml-section-shell {
190
178
  width: min(100% - 2rem,72rem);
191
179
  margin-inline: auto;
192
- /* A grid or flex item defaults to min-width: auto, which lets a wide
193
- table push the whole page sideways. */
180
+
194
181
  min-width: 0;
195
182
  }
196
183
 
@@ -207,8 +194,6 @@
207
194
  justify-items: center;
208
195
  }
209
196
 
210
- /* Its width is stated: centered by auto margins alone, a flex or grid item
211
- takes its text's width instead of its measure. */
212
197
  .ml-section-header-centered .ml-section-description {
213
198
  width: 100%;
214
199
  margin-inline: auto;
@@ -294,7 +279,6 @@
294
279
  }
295
280
  }
296
281
 
297
- /* Tablets keep two columns; only phones stack to one. */
298
282
  @media(max-width:48rem) {
299
283
  .ml-grid[data-columns="3"],
300
284
  .ml-grid[data-columns="4"],
@@ -383,7 +367,6 @@
383
367
  font-weight: 800;
384
368
  }
385
369
 
386
- /* A brand's own logo takes the mark's place: no chip, the text color, the mark's size. */
387
370
  .ml-brand-mark[data-kind="logo"] {
388
371
  background: none;
389
372
  color: var(--ml-text);
@@ -594,7 +577,6 @@
594
577
  font-size: var(--ml-type-base);
595
578
  }
596
579
 
597
- /* A full page: header, main and footer stacked on the page background. */
598
580
  .ml-page-shell {
599
581
  display: grid;
600
582
  grid-template-rows: auto 1fr auto;
@@ -603,13 +585,10 @@
603
585
  color: var(--ml-text);
604
586
  }
605
587
 
606
- /* The navigation, main and footer are grid items; they may be narrower than
607
- their widest content (a table that scrolls), so the page never does. */
608
588
  .ml-page-shell > * {
609
589
  min-width: 0;
610
590
  }
611
591
 
612
- /* components/accordion */
613
592
  .ml-accordion {
614
593
  width: 100%;
615
594
  }
@@ -678,7 +657,6 @@
678
657
  line-height: 1.55;
679
658
  }
680
659
 
681
- /* components/activity-heatmap */
682
660
  .ml-heatmap {
683
661
  --ml-heatmap-color: var(--ml-primary);
684
662
  --ml-heatmap-gap: var(--ml-space-1);
@@ -703,7 +681,6 @@
703
681
  --ml-heatmap-color: var(--ml-warning);
704
682
  }
705
683
 
706
- /* Weeks share the width, so the heatmap fills any container without scrolling. */
707
684
  .ml-heatmap-grid {
708
685
  display: grid;
709
686
  grid-template-columns: auto repeat(var(--ml-heatmap-weeks), minmax(0, 1fr));
@@ -775,8 +752,6 @@
775
752
  box-shadow: 0 0 0 2px var(--ml-focus);
776
753
  }
777
754
 
778
- /* A layer on <body> placed above its cell by script (useFloating), so no
779
- card or panel around the heatmap can cover or cut it. */
780
755
  .ml-heatmap-tooltip {
781
756
  position: fixed;
782
757
  z-index: var(--ml-layer-tooltip);
@@ -822,10 +797,6 @@
822
797
  font-variant-numeric: tabular-nums;
823
798
  }
824
799
 
825
- /* components/alert */
826
- /* A card like Card and Toast. The tone lives in one place, a solid icon
827
- mark, so a stack of alerts stays calm and each one still reads at a glance.
828
- `soft` tints the whole alert instead, for a banner across a page. */
829
800
  .ml-alert {
830
801
  --ml-alert-tone: var(--ml-text-muted);
831
802
  --ml-alert-on-tone: var(--ml-surface);
@@ -871,7 +842,6 @@
871
842
  --ml-alert-tone-text: var(--ml-danger-text);
872
843
  }
873
844
 
874
- /* soft: one even tint, a matching edge, and the title in the tone. */
875
845
  .ml-alert[data-variant="soft"] {
876
846
  border-color: color-mix(in oklab, var(--ml-alert-tone) 24%, transparent);
877
847
  background: color-mix(in oklab, var(--ml-alert-tone) 8%, var(--ml-surface));
@@ -900,7 +870,6 @@
900
870
  transition: opacity var(--ml-duration-fast) var(--ml-ease-standard), transform var(--ml-duration-normal) var(--ml-ease-standard);
901
871
  }
902
872
 
903
- /* A solid mark in the tone, centered on the first line of text. */
904
873
  .ml-alert-icon {
905
874
  position: relative;
906
875
  display: inline-grid;
@@ -932,8 +901,6 @@
932
901
  font-size: var(--ml-type-base);
933
902
  }
934
903
 
935
- /* Warnings and errors ask for attention as they arrive: a ring swells out
936
- of the mark and fades, twice. */
937
904
  .ml-alert[data-tone="warning"] .ml-alert-icon::after,
938
905
  .ml-alert[data-tone="danger"] .ml-alert-icon::after {
939
906
  position: absolute;
@@ -1021,7 +988,6 @@
1021
988
  }
1022
989
  }
1023
990
 
1024
- /* components/app-shell */
1025
991
  .ml-app-shell {
1026
992
  display: grid;
1027
993
  height: 100%;
@@ -1044,7 +1010,6 @@
1044
1010
  min-height: 0;
1045
1011
  }
1046
1012
 
1047
- /* Phones: the sidebar's track closes and its pane hides; the drawer takes over. */
1048
1013
  .ml-app-shell[data-narrow] .ml-app-shell-frame.ml-resizable[data-direction] {
1049
1014
  grid-template-columns: 0 0 minmax(0, 1fr);
1050
1015
  }
@@ -1229,7 +1194,6 @@
1229
1194
  opacity: 1;
1230
1195
  }
1231
1196
 
1232
- /* components/avatar */
1233
1197
  .ml-avatar-root {
1234
1198
  position: relative;
1235
1199
  display: inline-flex;
@@ -1247,6 +1211,8 @@
1247
1211
  height: 2.5rem;
1248
1212
  border: 0;
1249
1213
  border-radius: 50%;
1214
+
1215
+ box-shadow: inset 0 0 0 var(--ml-border-width) var(--ml-border);
1250
1216
  background: var(--ml-background-subtle);
1251
1217
  color: var(--ml-text-muted);
1252
1218
  font-size: var(--ml-type-xs);
@@ -1339,7 +1305,6 @@
1339
1305
  font-weight: 600;
1340
1306
  }
1341
1307
 
1342
- /* components/badge */
1343
1308
  .ml-badge {
1344
1309
  display: inline-flex;
1345
1310
  align-items: center;
@@ -1380,7 +1345,6 @@
1380
1345
  font-size: var(--ml-type-sm);
1381
1346
  }
1382
1347
 
1383
- /* Tone picks the color role; variant decides how it is worn. */
1384
1348
  .ml-badge[data-tone="primary"] {
1385
1349
  --ml-badge-tone: var(--ml-primary);
1386
1350
  --ml-badge-text: var(--ml-primary-text);
@@ -1411,11 +1375,9 @@
1411
1375
  --ml-badge-on: var(--ml-danger-foreground);
1412
1376
  }
1413
1377
 
1414
- /* Soft is the default, so plain markup with only data-tone is tinted too. */
1415
1378
  .ml-badge:where([data-tone]:not([data-tone="neutral"])) {
1416
1379
  background: color-mix(in oklab,var(--ml-badge-tone) 12%,transparent);
1417
- /* The -text roles clear 4.5:1 on a plain surface; on a tint they lean toward
1418
- the body text just enough to keep clearing it at badge size. */
1380
+
1419
1381
  color: color-mix(in oklab,var(--ml-badge-text) 78%,var(--ml-text));
1420
1382
  }
1421
1383
 
@@ -1451,7 +1413,6 @@
1451
1413
  background: color-mix(in srgb,currentColor 12%,transparent);
1452
1414
  }
1453
1415
 
1454
- /* components/breadcrumb */
1455
1416
  .ml-breadcrumb {
1456
1417
  display: block;
1457
1418
  color: var(--ml-text-muted);
@@ -1475,7 +1436,6 @@
1475
1436
  gap: var(--ml-space-1-5);
1476
1437
  }
1477
1438
 
1478
- /* Links, in-app buttons and the current page share one shape; a long title shortens instead of breaking the bar. */
1479
1439
  .ml-breadcrumb-link,
1480
1440
  .ml-breadcrumb-page {
1481
1441
  display: inline-flex;
@@ -1492,9 +1452,6 @@
1492
1452
  text-decoration: none;
1493
1453
  }
1494
1454
 
1495
- /* A fingertip's target. The link clips its own text for the ellipsis, which
1496
- would clip the invisible target data-hit="expand" draws around it, so on a
1497
- touch screen the link itself grows instead, without moving the bar. */
1498
1455
  @media (pointer: coarse) {
1499
1456
  .ml-breadcrumb-link {
1500
1457
  padding-block: var(--ml-space-2);
@@ -1547,7 +1504,6 @@ button.ml-breadcrumb-link {
1547
1504
  }
1548
1505
  }
1549
1506
 
1550
- /* components/button */
1551
1507
  .ml-button {
1552
1508
  position: relative;
1553
1509
  display: inline-flex;
@@ -1630,10 +1586,6 @@ button.ml-breadcrumb-link {
1630
1586
  background: color-mix(in oklab,var(--ml-surface) 100%,var(--ml-text) 4%);
1631
1587
  }
1632
1588
 
1633
- /* A toggle button that is on reads as filled ink, so its state is visible
1634
- without relying on color alone. It stays ink under the pointer, a shade
1635
- lighter: a variant's own hover fill under this ink-colored text would
1636
- leave the label unreadable. After the variants' hovers, and above them. */
1637
1589
  .ml-button:is([data-variant="secondary"], [data-variant="subtle"], [data-variant="outline"])[aria-pressed="true"] {
1638
1590
  border-color: transparent;
1639
1591
  background: var(--ml-text);
@@ -1672,9 +1624,6 @@ button.ml-breadcrumb-link {
1672
1624
  color: var(--ml-primary-text);
1673
1625
  }
1674
1626
 
1675
- /* A link button is drawn as text, a line tall. On touch it keeps that look
1676
- and gains an invisible target around it, as a control marked
1677
- data-hit="expand" does, so a finger reaches it (WCAG 2.5.8). */
1678
1627
  @media (pointer: coarse) {
1679
1628
  .ml-button[data-variant="link"]::after {
1680
1629
  position: absolute;
@@ -1702,9 +1651,6 @@ button.ml-breadcrumb-link {
1702
1651
  padding: 0;
1703
1652
  }
1704
1653
 
1705
- /* A label too long for the space wraps onto balanced lines instead of
1706
- spilling out. The taller line height is taken back by the margins, so a
1707
- one-line button is exactly as tall as before. */
1708
1654
  .ml-button-label {
1709
1655
  display: inline-flex;
1710
1656
  align-items: center;
@@ -1726,16 +1672,11 @@ button.ml-breadcrumb-link {
1726
1672
  color: var(--ml-success-foreground);
1727
1673
  }
1728
1674
 
1729
- /* A busy button keeps its color: the spinner says it is working, and its
1730
- label ("Saving…") stays readable. Only a disabled button fades, so the two
1731
- never look alike. */
1732
1675
  .ml-button[data-loading] {
1733
1676
  pointer-events: none;
1734
1677
  opacity: 1;
1735
1678
  }
1736
1679
 
1737
- /* A shortcut inside a filled button takes the button's own ink: an outline
1738
- of the text color, no fill of its own, so it reads on any variant. */
1739
1680
  .ml-button .ml-kbd {
1740
1681
  border-color: color-mix(in oklab, currentColor 40%, transparent);
1741
1682
  background: transparent;
@@ -1743,12 +1684,10 @@ button.ml-breadcrumb-link {
1743
1684
  color: inherit;
1744
1685
  }
1745
1686
 
1746
- /* components/calendar */
1747
1687
  .ml-calendar {
1748
1688
  --ml-calendar-day: 2.25rem;
1749
1689
  display: inline-grid;
1750
- /* One column no wider than the calendar, so two months wrap into a stack
1751
- when the space is narrower than both side by side. */
1690
+
1752
1691
  grid-template-columns: minmax(0, 1fr);
1753
1692
  width: max-content;
1754
1693
  max-width: 100%;
@@ -1762,7 +1701,6 @@ button.ml-breadcrumb-link {
1762
1701
  gap: var(--ml-space-2);
1763
1702
  }
1764
1703
 
1765
- /* Each month has its own caption; the arrows sit on the outer ones. */
1766
1704
  .ml-calendar-caption {
1767
1705
  display: grid;
1768
1706
  grid-template-columns: 2rem minmax(0, 1fr) 2rem;
@@ -1835,7 +1773,6 @@ button.ml-breadcrumb-link {
1835
1773
  place-items: center;
1836
1774
  }
1837
1775
 
1838
- /* A range reads as one band: filled between its ends, rounded at them. */
1839
1776
  .ml-calendar-cell[data-range] {
1840
1777
  background: color-mix(in oklab, var(--ml-primary) 12%, transparent);
1841
1778
  }
@@ -1882,7 +1819,6 @@ button.ml-breadcrumb-link {
1882
1819
  color: var(--ml-text-faint);
1883
1820
  }
1884
1821
 
1885
- /* Today is marked with a dot, so it never competes with the selection. */
1886
1822
  .ml-calendar-day[data-today]::after {
1887
1823
  position: absolute;
1888
1824
  bottom: var(--ml-space-1);
@@ -1909,7 +1845,6 @@ button.ml-breadcrumb-link {
1909
1845
  background: var(--ml-primary-foreground);
1910
1846
  }
1911
1847
 
1912
- /* Out of reach for the range being drawn: still clickable, to start a new one. */
1913
1848
  .ml-calendar-day[data-unreachable] {
1914
1849
  color: var(--ml-text-faint);
1915
1850
  }
@@ -1927,7 +1862,6 @@ button.ml-breadcrumb-link {
1927
1862
  }
1928
1863
  }
1929
1864
 
1930
- /* components/card */
1931
1865
  .ml-card {
1932
1866
  color: var(--ml-text);
1933
1867
  border: var(--ml-border-width) solid var(--ml-border-subtle);
@@ -2014,7 +1948,6 @@ button.ml-breadcrumb-link {
2014
1948
  margin-block-start: var(--ml-space-6);
2015
1949
  }
2016
1950
 
2017
- /* components/carousel */
2018
1951
  .ml-carousel {
2019
1952
  --ml-carousel-gap: var(--ml-space-4);
2020
1953
  display: grid;
@@ -2027,8 +1960,6 @@ button.ml-breadcrumb-link {
2027
1960
  min-width: 0;
2028
1961
  }
2029
1962
 
2030
- /* A native scroll-snap track: swipe, trackpad and wheel all work, and each
2031
- slide takes an equal share of the width left after gaps and the peek. */
2032
1963
  .ml-carousel-track {
2033
1964
  position: relative;
2034
1965
  display: grid;
@@ -2061,9 +1992,6 @@ button.ml-breadcrumb-link {
2061
1992
  height: 100%;
2062
1993
  }
2063
1994
 
2064
- /* With a pointer that hovers, the arrows sit in a gutter beside the slides,
2065
- never over them. On touch the reader swipes, the arrows stay hidden until
2066
- focused, and the slides keep the full width. */
2067
1995
  @media (hover: hover) and (pointer: fine) {
2068
1996
  .ml-carousel[data-arrows] .ml-carousel-viewport {
2069
1997
  padding-inline: calc(var(--ml-control-md) + var(--ml-space-3));
@@ -2078,7 +2006,6 @@ button.ml-breadcrumb-link {
2078
2006
  }
2079
2007
  }
2080
2008
 
2081
- /* The arrows come forward when the reader is near. */
2082
2009
  .ml-carousel-arrow {
2083
2010
  position: absolute;
2084
2011
  top: 50%;
@@ -2127,7 +2054,6 @@ button.ml-breadcrumb-link {
2127
2054
  outline-offset: 2px;
2128
2055
  }
2129
2056
 
2130
- /* Touch screens swipe; the arrows would only cover the slide. */
2131
2057
  @media (hover: none) {
2132
2058
  .ml-carousel-arrow {
2133
2059
  display: none;
@@ -2155,7 +2081,6 @@ button.ml-breadcrumb-link {
2155
2081
  transition: width var(--ml-duration-normal) var(--ml-ease-spring), background-color var(--ml-duration-fast) var(--ml-ease-standard);
2156
2082
  }
2157
2083
 
2158
- /* A comfortable target around a small mark. */
2159
2084
  .ml-carousel-dot::before {
2160
2085
  position: absolute;
2161
2086
  inset: calc(-1 * var(--ml-space-2)) calc(-1 * var(--ml-space-0-5));
@@ -2171,7 +2096,6 @@ button.ml-breadcrumb-link {
2171
2096
  background: var(--ml-primary);
2172
2097
  }
2173
2098
 
2174
- /* While autoplay runs, the active dot fills over the slide's time. */
2175
2099
  .ml-carousel[data-playing] .ml-carousel-dot[aria-current="true"] {
2176
2100
  background: var(--ml-track);
2177
2101
  }
@@ -2211,7 +2135,6 @@ button.ml-breadcrumb-link {
2211
2135
  }
2212
2136
  }
2213
2137
 
2214
- /* components/checkbox */
2215
2138
  .ml-checkbox-field {
2216
2139
  display: grid;
2217
2140
  grid-template-columns: auto 1fr;
@@ -2278,7 +2201,6 @@ button.ml-breadcrumb-link {
2278
2201
  min-width: 0;
2279
2202
  }
2280
2203
 
2281
-
2282
2204
  .ml-checkbox-copy {
2283
2205
  display: grid;
2284
2206
  gap: var(--ml-space-1);
@@ -2294,8 +2216,6 @@ button.ml-breadcrumb-link {
2294
2216
  color: var(--ml-danger-text);
2295
2217
  }
2296
2218
 
2297
- /* components/color-picker */
2298
- /* A swatch and a value in any format. */
2299
2219
  .ml-color-picker {
2300
2220
  min-inline-size: 10rem;
2301
2221
  }
@@ -2308,7 +2228,6 @@ button.ml-breadcrumb-link {
2308
2228
  cursor: pointer;
2309
2229
  }
2310
2230
 
2311
- /* Swatches sit on a checkerboard, so transparency reads as transparency. */
2312
2231
  .ml-color-picker-swatch,
2313
2232
  .ml-color-picker-preset,
2314
2233
  .ml-color-picker-sample {
@@ -2343,12 +2262,11 @@ button.ml-breadcrumb-link {
2343
2262
  gap: var(--ml-space-3);
2344
2263
  }
2345
2264
 
2346
- /* Saturation left to right, brightness bottom to top, over the current hue. */
2347
2265
  .ml-color-picker-area {
2348
2266
  position: relative;
2349
2267
  height: 9.5rem;
2350
2268
  border-radius: var(--ml-radius-md);
2351
- /* audit-allow: color.literal — this is the color model itself: value falls to black, saturation to white. */
2269
+
2352
2270
  background: linear-gradient(to top, #000, transparent), linear-gradient(to right, #fff, transparent), var(--ml-color-hue);
2353
2271
  cursor: crosshair;
2354
2272
  outline: none;
@@ -2364,9 +2282,6 @@ button.ml-breadcrumb-link {
2364
2282
  display: grid;
2365
2283
  }
2366
2284
 
2367
- /* A slider is a row a fingertip can land on (24 px, as the Slider's), with
2368
- its thin stripe drawn inside. A finger moving up and down still scrolls;
2369
- sideways it moves the value. */
2370
2285
  .ml-color-picker-track {
2371
2286
  position: relative;
2372
2287
  height: var(--ml-space-6);
@@ -2508,7 +2423,7 @@ button.ml-breadcrumb-link {
2508
2423
 
2509
2424
  .ml-color-picker-sample {
2510
2425
  display: grid;
2511
- /* White or black, whichever reads better on the picked color (set by the component). */
2426
+
2512
2427
  color: var(--ml-color-ink);
2513
2428
  width: 2.25rem;
2514
2429
  height: 2.25rem;
@@ -2529,8 +2444,6 @@ button.ml-breadcrumb-link {
2529
2444
  color: var(--ml-success-text);
2530
2445
  }
2531
2446
 
2532
- /* components/combobox */
2533
- /* Wide enough to read a choice and type a search. */
2534
2447
  .ml-combobox {
2535
2448
  min-inline-size: 12rem;
2536
2449
  }
@@ -2541,7 +2454,6 @@ button.ml-breadcrumb-link {
2541
2454
  grid-template-columns: minmax(0, 1fr);
2542
2455
  }
2543
2456
 
2544
- /* The input keeps the field's surface; room at the end for clear and chevron. */
2545
2457
  .ml-combobox-input.ml-combobox-input {
2546
2458
  padding-inline-end: var(--ml-space-9);
2547
2459
  }
@@ -2599,9 +2511,6 @@ button.ml-breadcrumb-link {
2599
2511
  color: var(--ml-text);
2600
2512
  }
2601
2513
 
2602
- /* The list: the same floating surface as Select's, a layer on <body>
2603
- placed beside the field by script (useFloating), so no card, panel or
2604
- scroll area around the field can cover or cut it. */
2605
2514
  .ml-combobox-popover {
2606
2515
  position: fixed;
2607
2516
  z-index: var(--ml-layer-popover);
@@ -2609,8 +2518,7 @@ button.ml-breadcrumb-link {
2609
2518
  left: 0;
2610
2519
  display: flex;
2611
2520
  flex-direction: column;
2612
- /* No taller than the room on the side it opened (--ml-floating-room, from
2613
- useFloating), so it fits beside its trigger, even with a phone's keyboard up. */
2521
+
2614
2522
  max-height: var(--ml-floating-room, none);
2615
2523
  padding: var(--ml-space-1);
2616
2524
  border: var(--ml-border-width) solid var(--ml-border-subtle);
@@ -2717,7 +2625,6 @@ button.ml-breadcrumb-link {
2717
2625
  font-size: var(--ml-type-sm);
2718
2626
  }
2719
2627
 
2720
- /* components/command-menu */
2721
2628
  .ml-command.ml-modal {
2722
2629
  top: clamp(var(--ml-space-8), 18vh, var(--ml-space-16));
2723
2630
  grid-template-rows: auto minmax(0, 1fr) auto;
@@ -2747,7 +2654,7 @@ button.ml-breadcrumb-link {
2747
2654
  flex: 1;
2748
2655
  min-width: 0;
2749
2656
  border: 0;
2750
- /* audit-allow: focus.removed — the search field is the open dialog's only field; its caret shows focus. */
2657
+
2751
2658
  outline: none;
2752
2659
  background: transparent;
2753
2660
  color: var(--ml-text);
@@ -2851,12 +2758,10 @@ button.ml-breadcrumb-link {
2851
2758
  gap: var(--ml-space-1);
2852
2759
  }
2853
2760
 
2854
- /* components/context-menu */
2855
2761
  .ml-context-menu-area {
2856
2762
  min-width: 0;
2857
2763
  }
2858
2764
 
2859
- /* The same floating surface as the dropdown menu, placed at the pointer. */
2860
2765
  .ml-context-menu {
2861
2766
  position: fixed;
2862
2767
  z-index: var(--ml-layer-toast);
@@ -2867,7 +2772,7 @@ button.ml-breadcrumb-link {
2867
2772
  border-radius: var(--ml-radius-lg);
2868
2773
  box-shadow: var(--ml-surface-highlight), var(--ml-shadow-lg);
2869
2774
  color: var(--ml-text);
2870
- /* audit-allow: focus.removed — a menu container, focused only by script (tabindex -1); its items carry the focus style. */
2775
+
2871
2776
  outline: none;
2872
2777
  background-color: color-mix(in oklab, var(--ml-surface-elevated) var(--ml-surface-alpha), transparent);
2873
2778
  background-image: var(--ml-surface-grain);
@@ -2941,15 +2846,10 @@ button.ml-breadcrumb-link {
2941
2846
  background: var(--ml-border-subtle);
2942
2847
  }
2943
2848
 
2944
- /* components/copy-button */
2945
- /* A copy the browser refused reads as a problem, not as a success. On a
2946
- filled button the label keeps its own ink; the spoken message carries it. */
2947
2849
  .ml-copy-button[data-status="error"]:not([data-variant="primary"], [data-variant="danger"]) {
2948
2850
  color: var(--ml-danger-text);
2949
2851
  }
2950
2852
 
2951
- /* components/date-picker */
2952
- /* Wide enough for a range in the reader's format. */
2953
2853
  .ml-date-picker {
2954
2854
  min-inline-size: 13rem;
2955
2855
  }
@@ -2959,8 +2859,6 @@ button.ml-breadcrumb-link {
2959
2859
  display: grid;
2960
2860
  }
2961
2861
 
2962
- /* The trigger wears the input's surface, so date fields line up with text fields.
2963
- The doubled class outranks the input's padding, keeping room for the clear button. */
2964
2862
  .ml-date-picker-trigger.ml-date-picker-trigger {
2965
2863
  padding-inline-end: var(--ml-space-8);
2966
2864
  }
@@ -3016,7 +2914,6 @@ button.ml-breadcrumb-link {
3016
2914
  outline-offset: -1px;
3017
2915
  }
3018
2916
 
3019
- /* The popover grows to the calendars it holds, never past the screen. */
3020
2917
  .ml-popover.ml-date-picker-popover {
3021
2918
  max-width: calc(100vw - 2 * var(--ml-space-4));
3022
2919
  }
@@ -3064,7 +2961,6 @@ button.ml-breadcrumb-link {
3064
2961
  outline-offset: -1px;
3065
2962
  }
3066
2963
 
3067
- /* Phones: presets become a row above the calendar. */
3068
2964
  @media (max-width: 40rem) {
3069
2965
  .ml-date-picker-panel[data-presets] {
3070
2966
  flex-direction: column;
@@ -3083,7 +2979,205 @@ button.ml-breadcrumb-link {
3083
2979
  }
3084
2980
  }
3085
2981
 
3086
- /* components/dropdown-menu */
2982
+ .ml-dial-field {
2983
+ --ml-dial-size: 10rem;
2984
+ --ml-dial-tone: var(--ml-primary-text);
2985
+ display: inline-grid;
2986
+ justify-items: center;
2987
+ align-content: start;
2988
+ gap: var(--ml-space-2);
2989
+ }
2990
+
2991
+ .ml-dial-field[data-size="sm"] {
2992
+ --ml-dial-size: 6rem;
2993
+ }
2994
+
2995
+ .ml-dial-field[data-size="lg"] {
2996
+ --ml-dial-size: 14rem;
2997
+ }
2998
+
2999
+ .ml-dial-field[data-tone="info"] {
3000
+ --ml-dial-tone: var(--ml-info-text);
3001
+ }
3002
+
3003
+ .ml-dial-field[data-tone="success"] {
3004
+ --ml-dial-tone: var(--ml-success-text);
3005
+ }
3006
+
3007
+ .ml-dial-field[data-tone="warning"] {
3008
+ --ml-dial-tone: var(--ml-warning-text);
3009
+ }
3010
+
3011
+ .ml-dial-field[data-tone="danger"] {
3012
+ --ml-dial-tone: var(--ml-danger-text);
3013
+ }
3014
+
3015
+ .ml-dial-label {
3016
+ font-size: var(--ml-type-sm);
3017
+ font-weight: 500;
3018
+ text-align: center;
3019
+ }
3020
+
3021
+ .ml-dial-caption {
3022
+ max-width: var(--ml-dial-size);
3023
+ color: var(--ml-text-muted);
3024
+ font-size: var(--ml-type-xs);
3025
+ line-height: var(--ml-leading-snug);
3026
+ text-align: center;
3027
+ }
3028
+
3029
+ .ml-dial {
3030
+ position: relative;
3031
+ width: var(--ml-dial-size);
3032
+ aspect-ratio: 1;
3033
+ border-radius: 50%;
3034
+ cursor: grab;
3035
+ -webkit-touch-callout: none;
3036
+ -webkit-user-select: none;
3037
+ user-select: none;
3038
+ }
3039
+
3040
+ .ml-dial[data-turning] {
3041
+ cursor: grabbing;
3042
+ }
3043
+
3044
+ .ml-dial:focus-visible {
3045
+ outline: 2px solid var(--ml-focus);
3046
+ outline-offset: 2px;
3047
+ }
3048
+
3049
+ .ml-dial-arc {
3050
+ position: absolute;
3051
+ inset: 0;
3052
+ width: 100%;
3053
+ height: 100%;
3054
+ overflow: visible;
3055
+ }
3056
+
3057
+ .ml-dial-ticks,
3058
+ .ml-dial-track,
3059
+ .ml-dial-range {
3060
+ fill: none;
3061
+ stroke-linecap: round;
3062
+ }
3063
+
3064
+ .ml-dial-ticks {
3065
+ stroke: var(--ml-border);
3066
+ stroke-width: 0.8;
3067
+ }
3068
+
3069
+ .ml-dial-field[data-size="sm"] .ml-dial-ticks {
3070
+ display: none;
3071
+ }
3072
+
3073
+ .ml-dial-track {
3074
+ stroke: var(--ml-track);
3075
+ stroke-width: 5;
3076
+ }
3077
+
3078
+ .ml-dial-range {
3079
+ stroke: var(--ml-dial-tone);
3080
+ stroke-width: 5;
3081
+ }
3082
+
3083
+ .ml-dial-knob {
3084
+ position: absolute;
3085
+ inset: 16%;
3086
+ border-radius: 50%;
3087
+ background:
3088
+ var(--ml-sheen),
3089
+ radial-gradient(circle at 50% 28%, color-mix(in oklab, var(--ml-surface-elevated) var(--ml-surface-alpha), transparent), color-mix(in oklab, var(--ml-background-subtle) var(--ml-surface-alpha), transparent) 78%);
3090
+ box-shadow:
3091
+ var(--ml-surface-highlight),
3092
+ inset 0 0 0 var(--ml-border-width) var(--ml-border-subtle),
3093
+ var(--ml-shadow-md);
3094
+ -webkit-backdrop-filter: var(--ml-surface-blur);
3095
+ backdrop-filter: var(--ml-surface-blur);
3096
+ rotate: var(--ml-dial-angle, 0deg);
3097
+ transition: rotate var(--ml-duration-normal) var(--ml-ease-spring);
3098
+ }
3099
+
3100
+ .ml-dial-knob::before {
3101
+ content: "";
3102
+ position: absolute;
3103
+ inset: 0;
3104
+ border-radius: inherit;
3105
+ background-image: var(--ml-surface-grain);
3106
+ background-size: 4px 4px;
3107
+ }
3108
+
3109
+ .ml-dial-knob::after {
3110
+ content: "";
3111
+ position: absolute;
3112
+ top: 3%;
3113
+ left: 50%;
3114
+ width: 5%;
3115
+ height: 9%;
3116
+ border-radius: var(--ml-radius-pill);
3117
+ background: var(--ml-dial-tone);
3118
+ translate: -50% 0;
3119
+ }
3120
+
3121
+ .ml-dial[data-turning] .ml-dial-knob {
3122
+ transition: none;
3123
+ }
3124
+
3125
+ .ml-dial-readout {
3126
+ position: absolute;
3127
+ inset: 0;
3128
+ display: grid;
3129
+ place-items: center;
3130
+ pointer-events: none;
3131
+ }
3132
+
3133
+ .ml-dial-value {
3134
+ color: var(--ml-text);
3135
+ font-family: var(--ml-font-display);
3136
+ font-size: var(--ml-type-2xl);
3137
+ font-variant-numeric: tabular-nums;
3138
+ font-weight: 600;
3139
+ letter-spacing: -0.02em;
3140
+ line-height: 1;
3141
+ white-space: nowrap;
3142
+
3143
+ scale: var(--ml-dial-fit, 1);
3144
+ }
3145
+
3146
+ .ml-dial-field[data-size="sm"] .ml-dial-value {
3147
+ font-size: var(--ml-type-md);
3148
+ }
3149
+
3150
+ .ml-dial-field[data-size="lg"] .ml-dial-value {
3151
+ font-size: var(--ml-type-display-sm);
3152
+ }
3153
+
3154
+ .ml-dial-field[data-disabled] .ml-dial {
3155
+ cursor: not-allowed;
3156
+ opacity: 0.48;
3157
+ }
3158
+
3159
+ @media (prefers-reduced-motion: reduce) {
3160
+ .ml-dial-knob {
3161
+ transition: none;
3162
+ }
3163
+ }
3164
+
3165
+ @media (forced-colors: active) {
3166
+ .ml-dial-track {
3167
+ stroke: GrayText;
3168
+ }
3169
+
3170
+ .ml-dial-range,
3171
+ .ml-dial-knob::after {
3172
+ stroke: Highlight;
3173
+ background: Highlight;
3174
+ }
3175
+
3176
+ .ml-dial-knob {
3177
+ border: 1px solid CanvasText;
3178
+ }
3179
+ }
3180
+
3087
3181
  .ml-dropdown {
3088
3182
  position: relative;
3089
3183
  display: inline-block;
@@ -3113,7 +3207,6 @@ button.ml-breadcrumb-link {
3113
3207
  background: color-mix(in oklab,var(--ml-surface) 100%,var(--ml-text) 4%);
3114
3208
  }
3115
3209
 
3116
- /* An icon-only trigger: a small quiet button, named by its label. */
3117
3210
  .ml-dropdown-trigger[data-variant="icon"] {
3118
3211
  min-height: var(--ml-control-sm);
3119
3212
  min-width: var(--ml-control-sm);
@@ -3142,11 +3235,6 @@ button.ml-breadcrumb-link {
3142
3235
  color: var(--ml-text-muted);
3143
3236
  }
3144
3237
 
3145
- /* A layer above the page, placed beside its trigger by script (React's
3146
- useFloating, the runtime's floatingLayer), so no card, panel or modal
3147
- around the trigger can cut it off. It sits above a modal it opens from.
3148
- In the top layer (the Popover API) the browser's own popover styles are
3149
- set back: no centering margin, no stretching inset, the theme's ink. */
3150
3238
  .ml-dropdown-menu {
3151
3239
  position: fixed;
3152
3240
  z-index: var(--ml-layer-popover);
@@ -3155,8 +3243,7 @@ button.ml-breadcrumb-link {
3155
3243
  left: 0;
3156
3244
  margin: 0;
3157
3245
  min-width: 14rem;
3158
- /* No taller than the room on the side it opened (--ml-floating-room, from
3159
- useFloating), so it fits beside its trigger, even with a phone's keyboard up. */
3246
+
3160
3247
  max-height: var(--ml-floating-room, none);
3161
3248
  overflow-y: auto;
3162
3249
  overscroll-behavior: contain;
@@ -3257,7 +3344,6 @@ button.ml-breadcrumb-link {
3257
3344
  color: var(--ml-text-muted);
3258
3345
  }
3259
3346
 
3260
- /* components/dropzone */
3261
3347
  .ml-dropzone-root {
3262
3348
  display: grid;
3263
3349
  gap: var(--ml-space-2);
@@ -3405,7 +3491,6 @@ button.ml-breadcrumb-link {
3405
3491
  transition: width var(--ml-duration-normal) var(--ml-ease-standard);
3406
3492
  }
3407
3493
 
3408
- /* components/empty-state */
3409
3494
  .ml-empty {
3410
3495
  display: grid;
3411
3496
  justify-items: center;
@@ -3459,7 +3544,6 @@ button.ml-breadcrumb-link {
3459
3544
  margin-block-start: var(--ml-space-2);
3460
3545
  }
3461
3546
 
3462
- /* components/hover-card */
3463
3547
  .ml-hover-card {
3464
3548
  position: fixed;
3465
3549
  z-index: var(--ml-layer-popover);
@@ -3494,13 +3578,12 @@ button.ml-breadcrumb-link {
3494
3578
  }
3495
3579
  }
3496
3580
 
3497
- /* components/input */
3498
3581
  .ml-input-field {
3499
3582
  display: grid;
3500
3583
  grid-template-columns: minmax(0, 1fr);
3501
3584
  gap: var(--ml-space-1-5);
3502
3585
  width: 100%;
3503
- /* In a form row taller than itself, a field keeps its own height instead of stretching its label and control apart. */
3586
+
3504
3587
  align-content: start;
3505
3588
  }
3506
3589
 
@@ -3522,9 +3605,6 @@ button.ml-breadcrumb-link {
3522
3605
  transition: border-color var(--ml-duration-fast),box-shadow var(--ml-duration-fast);
3523
3606
  }
3524
3607
 
3525
- /* A single-line field is exactly its size's control height, like the button
3526
- beside it: the height comes from density, and the text sits centered in
3527
- it, instead of padding around the text setting a height of its own. */
3528
3608
  .ml-input {
3529
3609
  padding-block: 0;
3530
3610
  }
@@ -3619,7 +3699,6 @@ button.ml-breadcrumb-link {
3619
3699
  font-size: var(--ml-type-md);
3620
3700
  }
3621
3701
 
3622
- /* A field that is a button or a group says it is invalid with data-invalid: aria-invalid belongs to inputs. */
3623
3702
  .ml-input-field[data-invalid] .ml-input,
3624
3703
  .ml-input[aria-invalid="true"],
3625
3704
  .ml-input[data-invalid] {
@@ -3662,14 +3741,12 @@ button.ml-breadcrumb-link {
3662
3741
  pointer-events: none;
3663
3742
  }
3664
3743
 
3665
- /* A text affix ("https://", a domain, a unit) reads at the size of what is typed beside it. */
3666
3744
  .ml-input-leading,
3667
3745
  .ml-input-trailing {
3668
3746
  font-size: var(--ml-type-base);
3669
3747
  line-height: var(--ml-leading-snug);
3670
3748
  }
3671
3749
 
3672
- /* components/kbd */
3673
3750
  .ml-kbd {
3674
3751
  display: inline-grid;
3675
3752
  min-width: 1.5em;
@@ -3695,7 +3772,6 @@ button.ml-breadcrumb-link {
3695
3772
  font: inherit;
3696
3773
  }
3697
3774
 
3698
- /* components/modal */
3699
3775
  .ml-modal-overlay {
3700
3776
  position: fixed;
3701
3777
  inset: 0;
@@ -3798,13 +3874,10 @@ button.ml-breadcrumb-link {
3798
3874
  padding: var(--ml-space-4) var(--ml-space-6) var(--ml-space-6);
3799
3875
  }
3800
3876
 
3801
- /* components/number-input */
3802
- /* A number and its steppers, never squeezed below readable. */
3803
3877
  .ml-number-input {
3804
3878
  min-inline-size: 9rem;
3805
3879
  }
3806
3880
 
3807
- /* The input's surface, with the steppers inside its right edge. */
3808
3881
  .ml-number-input-control {
3809
3882
  display: flex;
3810
3883
  min-height: var(--ml-control-md);
@@ -3837,7 +3910,7 @@ button.ml-breadcrumb-link {
3837
3910
  .ml-number-input-field {
3838
3911
  flex: 1;
3839
3912
  min-width: 0;
3840
- /* The control's height comes from density, like a text field's. */
3913
+
3841
3914
  padding: 0 var(--ml-space-3);
3842
3915
  border: 0;
3843
3916
  background: transparent;
@@ -3858,9 +3931,6 @@ button.ml-breadcrumb-link {
3858
3931
  border-inline-start: var(--ml-border-width) solid var(--ml-border-subtle);
3859
3932
  }
3860
3933
 
3861
- /* Square at any height: where touch sizing makes the field taller, the steps
3862
- grow with it instead of stretching into tall slivers. They sit inside the
3863
- control's border, so their side is the height within it. */
3864
3934
  .ml-number-input-step {
3865
3935
  display: inline-grid;
3866
3936
  min-width: calc(var(--ml-control-md) - 2 * var(--ml-border-width));
@@ -3894,7 +3964,6 @@ button.ml-breadcrumb-link {
3894
3964
  opacity: 0.5;
3895
3965
  }
3896
3966
 
3897
- /* components/otp-input */
3898
3967
  .ml-otp {
3899
3968
  display: flex;
3900
3969
  max-width: 100%;
@@ -3902,7 +3971,6 @@ button.ml-breadcrumb-link {
3902
3971
  gap: var(--ml-space-2);
3903
3972
  }
3904
3973
 
3905
- /* Boxes give a little way on the narrowest phones instead of running past the edge. */
3906
3974
  .ml-otp-box {
3907
3975
  flex: 0 1 var(--ml-control-lg);
3908
3976
  width: var(--ml-control-lg);
@@ -3944,7 +4012,6 @@ button.ml-breadcrumb-link {
3944
4012
  background: var(--ml-border);
3945
4013
  }
3946
4014
 
3947
- /* components/pagination */
3948
4015
  .ml-pagination {
3949
4016
  display: flex;
3950
4017
  align-items: center;
@@ -4009,14 +4076,11 @@ button.ml-breadcrumb-link {
4009
4076
  color: var(--ml-text-muted);
4010
4077
  }
4011
4078
 
4012
- /* components/password-input */
4013
4079
  .ml-password-input {
4014
4080
  display: grid;
4015
4081
  gap: var(--ml-space-2);
4016
4082
  }
4017
4083
 
4018
- /* While the password shows, the toggle takes full ink: its state is seen,
4019
- not only announced. */
4020
4084
  .ml-password-input-toggle[aria-pressed="true"] {
4021
4085
  color: var(--ml-text);
4022
4086
  }
@@ -4037,8 +4101,6 @@ button.ml-breadcrumb-link {
4037
4101
  font-weight: 600;
4038
4102
  }
4039
4103
 
4040
- /* Three segments light up as the password grows. They are marks on the page,
4041
- so they take the -text roles, which clear 3:1 against it. */
4042
4104
  .ml-password-input-meter {
4043
4105
  display: grid;
4044
4106
  grid-template-columns: repeat(3, 1fr);
@@ -4085,7 +4147,6 @@ button.ml-breadcrumb-link {
4085
4147
  }
4086
4148
  }
4087
4149
 
4088
- /* components/popover */
4089
4150
  .ml-popover {
4090
4151
  position: fixed;
4091
4152
  z-index: var(--ml-layer-popover);
@@ -4093,8 +4154,7 @@ button.ml-breadcrumb-link {
4093
4154
  left: 0;
4094
4155
  min-width: 12rem;
4095
4156
  max-width: min(22rem, calc(100vw - 1rem));
4096
- /* No taller than the room on the side it opened (--ml-floating-room, from
4097
- useFloating), so it fits beside its trigger, even with a phone's keyboard up. */
4157
+
4098
4158
  max-height: var(--ml-floating-room, none);
4099
4159
  overflow-y: auto;
4100
4160
  overscroll-behavior: contain;
@@ -4116,7 +4176,6 @@ button.ml-breadcrumb-link {
4116
4176
  outline: none;
4117
4177
  }
4118
4178
 
4119
- /* It grows out of the side it opened from. */
4120
4179
  .ml-popover[data-side="bottom"] {
4121
4180
  --ml-popover-from: translateY(-4px);
4122
4181
  }
@@ -4140,7 +4199,6 @@ button.ml-breadcrumb-link {
4140
4199
  }
4141
4200
  }
4142
4201
 
4143
- /* components/priority-icon */
4144
4202
  .ml-priority-icon {
4145
4203
  --ml-priority-mark: var(--ml-danger-foreground);
4146
4204
  flex: none;
@@ -4160,7 +4218,6 @@ button.ml-breadcrumb-link {
4160
4218
  color: var(--ml-text);
4161
4219
  }
4162
4220
 
4163
- /* components/progress */
4164
4221
  .ml-progress-root {
4165
4222
  --ml-progress-tone: var(--ml-primary);
4166
4223
  --ml-progress-height: var(--ml-space-1-5);
@@ -4221,15 +4278,13 @@ button.ml-breadcrumb-link {
4221
4278
  box-shadow: inset 0 1px 1px color-mix(in oklab, var(--ml-text) 6%, transparent);
4222
4279
  }
4223
4280
 
4224
- /* The fill deepens towards its leading edge, so the bar reads as moving forward. */
4225
4281
  .ml-progress-fill {
4226
4282
  position: relative;
4227
4283
  height: 100%;
4228
4284
  overflow: hidden;
4229
4285
  border-radius: inherit;
4230
4286
  background: linear-gradient(90deg, color-mix(in oklab, var(--ml-progress-tone) 72%, var(--ml-surface)), var(--ml-progress-tone));
4231
- /* A steady chase toward each new value: frequent updates blend into one
4232
- motion instead of restarting a spring every time. */
4287
+
4233
4288
  transition: width var(--ml-duration-slow) var(--ml-ease-standard);
4234
4289
  animation: ml-progress-grow var(--ml-duration-reveal) var(--ml-ease-spring) both;
4235
4290
  }
@@ -4240,7 +4295,6 @@ button.ml-breadcrumb-link {
4240
4295
  }
4241
4296
  }
4242
4297
 
4243
- /* While work runs, a soft light sweeps along the fill. */
4244
4298
  .ml-progress-root[data-active] .ml-progress-fill::after {
4245
4299
  position: absolute;
4246
4300
  inset: 0;
@@ -4256,7 +4310,6 @@ button.ml-breadcrumb-link {
4256
4310
  }
4257
4311
  }
4258
4312
 
4259
- /* Done: one glow around the finished bar. */
4260
4313
  .ml-progress-root[data-state="complete"] .ml-progress-track {
4261
4314
  animation: ml-progress-done var(--ml-duration-reveal) var(--ml-ease-standard) var(--ml-duration-slow) both;
4262
4315
  }
@@ -4270,7 +4323,6 @@ button.ml-breadcrumb-link {
4270
4323
  }
4271
4324
  }
4272
4325
 
4273
- /* Unknown length: a segment glides across and loops. */
4274
4326
  .ml-progress-root[data-state="indeterminate"] .ml-progress-fill {
4275
4327
  position: absolute;
4276
4328
  inset-block: 0;
@@ -4423,7 +4475,6 @@ button.ml-breadcrumb-link {
4423
4475
  }
4424
4476
  }
4425
4477
 
4426
- /* components/radio-group */
4427
4478
  .ml-radio-item {
4428
4479
  display: grid;
4429
4480
  grid-template-columns: auto 1fr;
@@ -4540,7 +4591,6 @@ button.ml-breadcrumb-link {
4540
4591
  align-content: start;
4541
4592
  }
4542
4593
 
4543
- /* components/rating */
4544
4594
  .ml-rating {
4545
4595
  display: inline-flex;
4546
4596
  align-items: center;
@@ -4574,10 +4624,6 @@ button.ml-breadcrumb-link {
4574
4624
  font-variant-numeric: tabular-nums;
4575
4625
  }
4576
4626
 
4577
- /* components/resizable */
4578
- /* The handle's width is a setting (an app shell draws a hairline): its
4579
- default weighs nothing, so one class on the same element sets it, in any
4580
- stylesheet order. */
4581
4627
  :where(.ml-resizable) {
4582
4628
  --ml-resizable-handle: var(--ml-space-2);
4583
4629
  }
@@ -4587,13 +4633,12 @@ button.ml-breadcrumb-link {
4587
4633
  height: 100%;
4588
4634
  min-width: 0;
4589
4635
  min-height: 0;
4590
- /* A folded or zero-width pane keeps its content mounted; nothing of it may widen the page. */
4636
+
4591
4637
  overflow: clip;
4592
- /* The handle's layer stays inside the component. */
4638
+
4593
4639
  isolation: isolate;
4594
4640
  }
4595
4641
 
4596
- /* The anchored pane takes the size; the other takes the rest. */
4597
4642
  .ml-resizable[data-direction="horizontal"] {
4598
4643
  grid-template-columns: minmax(0, var(--ml-resizable-size)) var(--ml-resizable-handle) minmax(0, 1fr);
4599
4644
  }
@@ -4610,28 +4655,23 @@ button.ml-breadcrumb-link {
4610
4655
  grid-template-rows: minmax(0, 1fr) var(--ml-resizable-handle) minmax(0, var(--ml-resizable-size));
4611
4656
  }
4612
4657
 
4613
- /* Each pane is a containing block, so absolutely placed content (visually
4614
- hidden labels, popover anchors) is clipped with it instead of escaping. */
4615
4658
  .ml-resizable-pane {
4616
4659
  position: relative;
4617
- /* A pane's own layers (sticky headers, raised rows) stay inside it, so they
4618
- never paint over the handle's line or its grab area. */
4660
+
4619
4661
  isolation: isolate;
4620
4662
  min-width: 0;
4621
4663
  min-height: 0;
4622
4664
  overflow: auto;
4623
4665
  }
4624
4666
 
4625
- /* A folded pane keeps its content mounted but out of reach. */
4626
4667
  .ml-resizable-pane[data-folded] {
4627
4668
  visibility: hidden;
4628
4669
  overflow: clip;
4629
4670
  }
4630
4671
 
4631
- /* A hairline that thickens into a grip on hover, focus or drag. */
4632
4672
  .ml-resizable-handle {
4633
4673
  position: relative;
4634
- /* The line and its grab area are wider than a hairline handle, so they sit above both panes. */
4674
+
4635
4675
  z-index: var(--ml-layer-raised);
4636
4676
  display: grid;
4637
4677
  place-items: center;
@@ -4675,7 +4715,6 @@ button.ml-breadcrumb-link {
4675
4715
  outline: none;
4676
4716
  }
4677
4717
 
4678
- /* The grab area is wider than the line, so a 1px handle in an app shell is still easy to catch. */
4679
4718
  .ml-resizable-handle::after {
4680
4719
  position: absolute;
4681
4720
  inset: 0 calc(-1 * var(--ml-space-1));
@@ -4687,7 +4726,6 @@ button.ml-breadcrumb-link {
4687
4726
  inset: calc(-1 * var(--ml-space-1)) 0;
4688
4727
  }
4689
4728
 
4690
- /* A finger needs more: 24 px of grab area on a touch screen. */
4691
4729
  @media (pointer: coarse) {
4692
4730
  .ml-resizable-handle::after {
4693
4731
  inset: 0 calc(-1 * var(--ml-space-2));
@@ -4698,8 +4736,6 @@ button.ml-breadcrumb-link {
4698
4736
  }
4699
4737
  }
4700
4738
 
4701
- /* components/segmented-control */
4702
- /* In a narrow container the options wrap onto a second row instead of spilling out. */
4703
4739
  .ml-segmented-control {
4704
4740
  display: inline-flex;
4705
4741
  flex-wrap: wrap;
@@ -4712,8 +4748,6 @@ button.ml-breadcrumb-link {
4712
4748
  gap: var(--ml-space-0-5);
4713
4749
  }
4714
4750
 
4715
- /* Each option is a small control inside the track, so the whole control is
4716
- as tall as a medium one and sits level with the fields beside it. */
4717
4751
  .ml-segmented-control-item {
4718
4752
  min-height: var(--ml-control-sm);
4719
4753
  padding: 0 var(--ml-space-3);
@@ -4738,14 +4772,11 @@ button.ml-breadcrumb-link {
4738
4772
  box-shadow: var(--ml-shadow-sm);
4739
4773
  }
4740
4774
 
4741
- /* components/select */
4742
- /* minmax(0, 1fr) and min-width: 0 let a long value truncate instead of
4743
- widening the select past its container. */
4744
4775
  .ml-select-root {
4745
4776
  position: relative;
4746
4777
  display: grid;
4747
4778
  grid-template-columns: minmax(0, 1fr);
4748
- /* In a form row taller than itself, the trigger keeps a field's height instead of stretching. */
4779
+
4749
4780
  align-content: start;
4750
4781
  gap: var(--ml-space-1-5);
4751
4782
  width: 100%;
@@ -4765,14 +4796,14 @@ button.ml-breadcrumb-link {
4765
4796
  align-items: center;
4766
4797
  justify-content: space-between;
4767
4798
  gap: var(--ml-space-2);
4768
- /* As tall as its size's control height, level with an input or a button. */
4799
+
4769
4800
  padding: 0 var(--ml-space-3);
4770
4801
  color: var(--ml-text);
4771
4802
  background: var(--ml-surface);
4772
4803
  border: var(--ml-border-width) solid var(--ml-border);
4773
4804
  border-radius: var(--ml-radius-md);
4774
4805
  box-shadow: var(--ml-shadow-xs);
4775
- /* The same type as a text field, so a select and an input sit level in a row. */
4806
+
4776
4807
  font-family: var(--ml-font-sans);
4777
4808
  font-size: var(--ml-type-base);
4778
4809
  line-height: var(--ml-leading-snug);
@@ -4864,8 +4895,6 @@ button.ml-breadcrumb-link {
4864
4895
  color: var(--ml-text);
4865
4896
  }
4866
4897
 
4867
- /* In the top layer (the Popover API) the browser's own popover styles are
4868
- set back: no centering margin, no stretching inset, the theme's ink. */
4869
4898
  .ml-select-popover {
4870
4899
  position: fixed;
4871
4900
  z-index: var(--ml-layer-top);
@@ -4876,8 +4905,7 @@ button.ml-breadcrumb-link {
4876
4905
  color: var(--ml-text);
4877
4906
  display: flex;
4878
4907
  flex-direction: column;
4879
- /* No taller than the room on the side it opened (--ml-floating-room, from
4880
- useFloating), so it fits beside its trigger, even with a phone's keyboard up. */
4908
+
4881
4909
  max-height: var(--ml-floating-room, none);
4882
4910
  max-width: calc(100vw - var(--ml-space-4));
4883
4911
  padding: var(--ml-space-1);
@@ -4911,7 +4939,7 @@ button.ml-breadcrumb-link {
4911
4939
  border-radius: var(--ml-radius-sm);
4912
4940
  background: transparent;
4913
4941
  font-size: var(--ml-type-sm);
4914
- /* audit-allow: focus.removed — the search field inside an open listbox; its caret shows focus. */
4942
+
4915
4943
  outline: none;
4916
4944
  }
4917
4945
 
@@ -5021,7 +5049,6 @@ button.ml-breadcrumb-link {
5021
5049
  color: var(--ml-danger-text);
5022
5050
  }
5023
5051
 
5024
- /* components/sheet */
5025
5052
  .ml-sheet-overlay {
5026
5053
  position: fixed;
5027
5054
  inset: 0;
@@ -5058,8 +5085,6 @@ button.ml-breadcrumb-link {
5058
5085
  z-index: var(--ml-layer-overlay);
5059
5086
  }
5060
5087
 
5061
- /* The panel floats a hairline in from its edge, rounded like every other
5062
- surface, instead of being glued to the viewport. */
5063
5088
  .ml-sheet-panel {
5064
5089
  --ml-sheet-inset: var(--ml-space-2);
5065
5090
  --ml-sheet-radius: calc(var(--ml-radius-lg) + 2px);
@@ -5161,10 +5186,6 @@ button.ml-breadcrumb-link {
5161
5186
  padding: var(--ml-space-4) var(--ml-space-6) var(--ml-space-6);
5162
5187
  }
5163
5188
 
5164
- /* components/skeleton */
5165
- /* One light band sweeps the whole viewport, so every placeholder on the page
5166
- glints in unison instead of each shimmering at its own speed. Where fixed
5167
- backgrounds are ignored (iOS), each shape still shimmers on its own. */
5168
5189
  .ml-skeleton {
5169
5190
  --ml-skeleton-base: color-mix(in oklab, var(--ml-text) 8%, transparent);
5170
5191
  --ml-skeleton-glint: color-mix(in oklab, var(--ml-text) 3%, transparent);
@@ -5176,7 +5197,7 @@ button.ml-breadcrumb-link {
5176
5197
  var(--ml-skeleton-base) 60%
5177
5198
  )
5178
5199
  0 0 / 200vw 100% fixed;
5179
- /* Quick loads never flash a placeholder: it appears only after a beat. */
5200
+
5180
5201
  animation:
5181
5202
  ml-skeleton-appear 240ms var(--ml-ease-standard) 160ms both,
5182
5203
  ml-skeleton-sweep 1.6s linear infinite;
@@ -5206,8 +5227,6 @@ button.ml-breadcrumb-link {
5206
5227
  width: 100%;
5207
5228
  }
5208
5229
 
5209
- /* Each line is one line box of the surrounding text: a bar about the height
5210
- of lowercase letters, centered in 1lh. */
5211
5230
  .ml-skeleton-line {
5212
5231
  height: 0.62em;
5213
5232
  margin-block: calc((1lh - 0.62em) / 2);
@@ -5263,7 +5282,6 @@ button.ml-breadcrumb-link {
5263
5282
  }
5264
5283
  }
5265
5284
 
5266
- /* components/slider */
5267
5285
  .ml-slider-field {
5268
5286
  display: grid;
5269
5287
  gap: var(--ml-space-2-5);
@@ -5294,7 +5312,7 @@ button.ml-breadcrumb-link {
5294
5312
  width: 100%;
5295
5313
  align-items: center;
5296
5314
  min-height: var(--ml-space-6);
5297
- /* A finger scrolls the page up and down; sideways it moves the value. */
5315
+
5298
5316
  touch-action: pan-y;
5299
5317
  cursor: pointer;
5300
5318
  }
@@ -5343,8 +5361,7 @@ button.ml-breadcrumb-link {
5343
5361
  }
5344
5362
 
5345
5363
  .ml-slider-thumb:hover,
5346
- /* Focus lands on the slider (it carries role="slider"); the ring is drawn
5347
- on the thumb, where the eye already is. */
5364
+
5348
5365
  .ml-slider:focus-visible {
5349
5366
  outline: none;
5350
5367
  }
@@ -5354,10 +5371,6 @@ button.ml-breadcrumb-link {
5354
5371
  outline-offset: 2px;
5355
5372
  }
5356
5373
 
5357
- /* components/spinner */
5358
- /* A ring of the current text color with one bright arc. It is drawn from
5359
- currentColor alone, so it matches the label beside it in a button, a
5360
- toast or a line of text, in every theme and mode. */
5361
5374
  .ml-spinner {
5362
5375
  display: inline-block;
5363
5376
  flex: none;
@@ -5382,8 +5395,6 @@ button.ml-breadcrumb-link {
5382
5395
  border-width: 2.5px;
5383
5396
  }
5384
5397
 
5385
- /* Under forced colors the ring is the system's text color, and the arc is
5386
- a real border that stays visible. */
5387
5398
  @media (forced-colors: active) {
5388
5399
  .ml-spinner {
5389
5400
  border-color: CanvasText;
@@ -5391,8 +5402,6 @@ button.ml-breadcrumb-link {
5391
5402
  }
5392
5403
  }
5393
5404
 
5394
- /* components/status-icon */
5395
- /* Color carries the stage; the glyph carries it without color too. */
5396
5405
  .ml-status-icon {
5397
5406
  --ml-status-mark: var(--ml-surface);
5398
5407
  flex: none;
@@ -5412,9 +5421,8 @@ button.ml-breadcrumb-link {
5412
5421
  color: var(--ml-success-text);
5413
5422
  }
5414
5423
 
5415
- /* Done is a filled disc carrying its check in the foreground: a fill and its pair. */
5416
5424
  .ml-status-icon[data-status="done"] {
5417
- /* audit-allow: color.role — the disc is a fill; its mark takes --ml-primary-foreground. */
5425
+
5418
5426
  color: var(--ml-primary);
5419
5427
  --ml-status-mark: var(--ml-primary-foreground);
5420
5428
  }
@@ -5423,8 +5431,6 @@ button.ml-breadcrumb-link {
5423
5431
  color: var(--ml-text-faint);
5424
5432
  }
5425
5433
 
5426
- /* components/stepper */
5427
- /* The container, not the screen, decides when the row condenses. */
5428
5434
  .ml-stepper {
5429
5435
  --ml-stepper-marker: 1.75rem;
5430
5436
  container: ml-stepper / inline-size;
@@ -5454,8 +5460,6 @@ button.ml-breadcrumb-link {
5454
5460
  flex: none;
5455
5461
  }
5456
5462
 
5457
- /* Horizontal: the connector is a flex item after the step, level with the
5458
- marker's center, and fills once the step is done. */
5459
5463
  .ml-stepper[data-orientation="horizontal"] .ml-stepper-step:not(:last-child)::after {
5460
5464
  min-width: var(--ml-space-4);
5461
5465
  height: 2px;
@@ -5584,7 +5588,6 @@ button.ml-stepper-target:focus-visible {
5584
5588
  font-size: var(--ml-type-xs);
5585
5589
  }
5586
5590
 
5587
- /* Compact: one line with the current step and a meter. */
5588
5591
  .ml-stepper-summary {
5589
5592
  display: none;
5590
5593
  grid-template-columns: auto 1fr;
@@ -5616,10 +5619,8 @@ button.ml-stepper-target:focus-visible {
5616
5619
  }
5617
5620
  }
5618
5621
 
5619
- /* components/table */
5620
5622
  .ml-table-container {
5621
- /* The containing block for anything positioned inside, such as visually
5622
- hidden cell text, so it scrolls with the table instead of widening the page. */
5623
+
5623
5624
  position: relative;
5624
5625
  width: 100%;
5625
5626
  overflow-x: auto;
@@ -5629,7 +5630,6 @@ button.ml-stepper-target:focus-visible {
5629
5630
  box-shadow: var(--ml-shadow-xs);
5630
5631
  }
5631
5632
 
5632
- /* Focusable only while it scrolls; the ring sits inside, where it cannot be clipped. */
5633
5633
  .ml-table-container:focus-visible {
5634
5634
  outline: 2px solid var(--ml-focus);
5635
5635
  outline-offset: -2px;
@@ -5665,8 +5665,6 @@ button.ml-stepper-target:focus-visible {
5665
5665
  background: transparent;
5666
5666
  }
5667
5667
 
5668
- /* A header cell lines up with its column. Browsers center th by default, which
5669
- a table's own text-align does not reach. */
5670
5668
  .ml-table th,
5671
5669
  .ml-table-header th,
5672
5670
  .ml-table-head {
@@ -5786,7 +5784,6 @@ button.ml-stepper-target:focus-visible {
5786
5784
  color: var(--ml-text-faint);
5787
5785
  }
5788
5786
 
5789
- /* components/tabs */
5790
5787
  .ml-tabs {
5791
5788
  display: grid;
5792
5789
  grid-template-columns: minmax(0, 1fr);
@@ -5907,13 +5904,10 @@ button.ml-stepper-target:focus-visible {
5907
5904
  display: none;
5908
5905
  }
5909
5906
 
5910
- /* components/tag-input */
5911
- /* Room for a couple of tags beside the caret. */
5912
5907
  .ml-tag-input {
5913
5908
  min-inline-size: 14rem;
5914
5909
  }
5915
5910
 
5916
- /* The control wears the input's surface, with tags flowing before the caret. */
5917
5911
  .ml-tag-input-control {
5918
5912
  position: relative;
5919
5913
  display: flex;
@@ -5974,7 +5968,6 @@ button.ml-stepper-target:focus-visible {
5974
5968
  transition: background-color var(--ml-duration-fast), border-color var(--ml-duration-fast);
5975
5969
  }
5976
5970
 
5977
- /* Marked by Backspace or the arrows: the next Backspace removes it. */
5978
5971
  .ml-tag-input-tag[data-armed] {
5979
5972
  border-color: var(--ml-danger);
5980
5973
  background: color-mix(in oklab, var(--ml-danger) 12%, var(--ml-surface));
@@ -6029,9 +6022,6 @@ button.ml-stepper-target:focus-visible {
6029
6022
  font-variant-numeric: tabular-nums;
6030
6023
  }
6031
6024
 
6032
- /* components/textarea */
6033
- /* Shares its surface with Input (input.css); this file adds only growth and
6034
- the counter. */
6035
6025
  .ml-textarea {
6036
6026
  max-height: calc(var(--ml-textarea-max-rows, 12) * 1lh + 2 * var(--ml-space-2));
6037
6027
  field-sizing: content;
@@ -6050,13 +6040,10 @@ button.ml-stepper-target:focus-visible {
6050
6040
  color: var(--ml-danger-text);
6051
6041
  }
6052
6042
 
6053
- /* components/time-picker */
6054
- /* Room for hours, minutes and AM/PM without the field collapsing. */
6055
6043
  .ml-time-picker {
6056
6044
  min-inline-size: 8rem;
6057
6045
  }
6058
6046
 
6059
- /* The control wears the input's surface; its segments are the fields inside. */
6060
6047
  .ml-time-picker-control {
6061
6048
  display: flex;
6062
6049
  align-items: center;
@@ -6177,15 +6164,10 @@ button.ml-stepper-target:focus-visible {
6177
6164
  outline-offset: -1px;
6178
6165
  }
6179
6166
 
6180
- /* A typed time the rules refuse reads as an error until focus leaves and it snaps. */
6181
6167
  .ml-time-picker-control[data-unavailable] .ml-time-picker-segment {
6182
6168
  color: var(--ml-danger-text);
6183
6169
  }
6184
6170
 
6185
- /* components/timeline */
6186
- /* A rail of markers and a column of text. Each item draws the segment of
6187
- rail below its own marker, so the line always runs through the centers,
6188
- whatever each item holds, and fills in as the sequence progresses. */
6189
6171
  .ml-timeline {
6190
6172
  --ml-timeline-marker: 1.5rem;
6191
6173
  --ml-timeline-rail: 2px;
@@ -6219,7 +6201,6 @@ button.ml-stepper-target:focus-visible {
6219
6201
  content: "";
6220
6202
  }
6221
6203
 
6222
- /* Done: the rail is drawn in; from the current step it fades toward what is next. */
6223
6204
  .ml-timeline-item[data-status="complete"]:not(:last-child)::before {
6224
6205
  background: var(--ml-primary);
6225
6206
  }
@@ -6274,7 +6255,6 @@ button.ml-stepper-target:focus-visible {
6274
6255
  }
6275
6256
  }
6276
6257
 
6277
- /* Event tones for activity feeds; they win over the status fill. */
6278
6258
  .ml-timeline-marker[data-tone] {
6279
6259
  --ml-timeline-tone: var(--ml-text);
6280
6260
  --ml-timeline-tone-text: var(--ml-text);
@@ -6313,7 +6293,6 @@ button.ml-stepper-target:focus-visible {
6313
6293
  min-width: 0;
6314
6294
  }
6315
6295
 
6316
- /* The heading row is as tall as the marker, so a one-line title sits on its center. */
6317
6296
  .ml-timeline-heading {
6318
6297
  display: flex;
6319
6298
  flex-wrap: wrap;
@@ -6361,14 +6340,11 @@ button.ml-stepper-target:focus-visible {
6361
6340
  }
6362
6341
  }
6363
6342
 
6364
- /* components/toast */
6365
- /* The stack sits a set distance from the viewport edges. Apps with a sticky
6366
- header move top stacks below it with --ml-toaster-offset-top. */
6367
6343
  .ml-toaster {
6368
6344
  --ml-toaster-offset: var(--ml-space-4);
6369
6345
  position: fixed;
6370
6346
  z-index: var(--ml-layer-toast);
6371
- /* In the top layer (the Popover API, framework-free) the browser's own popover styles are set back. */
6347
+
6372
6348
  inset: auto;
6373
6349
  margin: 0;
6374
6350
  padding: 0;
@@ -6392,8 +6368,6 @@ button.ml-stepper-target:focus-visible {
6392
6368
  bottom: var(--ml-toaster-offset-bottom, var(--ml-toaster-offset));
6393
6369
  }
6394
6370
 
6395
- /* --ml-scroll-lock-offset is the padding a scroll lock adds, so a toast
6396
- stays put when an overlay opens. */
6397
6371
  .ml-toaster[data-position="top-right"],
6398
6372
  .ml-toaster[data-position="bottom-right"] {
6399
6373
  right: calc(var(--ml-toaster-offset) + var(--ml-scroll-lock-offset, 0px));
@@ -6405,7 +6379,6 @@ button.ml-stepper-target:focus-visible {
6405
6379
  translate: -50% 0;
6406
6380
  }
6407
6381
 
6408
- /* On a phone the stack spans the screen with even margins. */
6409
6382
  @media (max-width: 30rem) {
6410
6383
  .ml-toaster {
6411
6384
  left: var(--ml-toaster-offset);
@@ -6415,8 +6388,6 @@ button.ml-stepper-target:focus-visible {
6415
6388
  }
6416
6389
  }
6417
6390
 
6418
- /* Each toast lives in a slot that can fold to nothing, so when one leaves
6419
- the others glide into its place instead of jumping. */
6420
6391
  .ml-toast-slot {
6421
6392
  display: grid;
6422
6393
  grid-template-rows: 1fr;
@@ -6485,7 +6456,6 @@ button.ml-stepper-target:focus-visible {
6485
6456
  transition: none;
6486
6457
  }
6487
6458
 
6488
- /* With a description the icon and actions sit on the first line, not the middle. */
6489
6459
  .ml-toast[data-has-description] {
6490
6460
  align-items: flex-start;
6491
6461
  }
@@ -6588,7 +6558,6 @@ button.ml-stepper-target:focus-visible {
6588
6558
  }
6589
6559
  }
6590
6560
 
6591
- /* components/toggle */
6592
6561
  .ml-switch-field {
6593
6562
  display: inline-flex;
6594
6563
  align-items: center;
@@ -6698,16 +6667,11 @@ button.ml-stepper-target:focus-visible {
6698
6667
  color: var(--ml-text);
6699
6668
  }
6700
6669
 
6701
- /* components/tooltip */
6702
6670
  .ml-tooltip-root {
6703
6671
  position: relative;
6704
6672
  display: inline-flex;
6705
6673
  }
6706
6674
 
6707
- /* A layer above the page, placed beside its trigger by script (React's
6708
- useFloating, the runtime's floatingLayer), so no panel, card or scroll
6709
- area around the trigger can cover or cut it. In the top layer (the
6710
- Popover API) the browser's own popover styles are set back. */
6711
6675
  .ml-tooltip {
6712
6676
  position: fixed;
6713
6677
  z-index: var(--ml-layer-tooltip);
@@ -6725,7 +6689,7 @@ button.ml-stepper-target:focus-visible {
6725
6689
  font-size: var(--ml-type-xs);
6726
6690
  font-weight: 500;
6727
6691
  line-height: 1.4;
6728
- /* One line when it fits; a long tip wraps within the window instead of running past it. */
6692
+
6729
6693
  width: max-content;
6730
6694
  max-width: min(20rem, calc(100vw - 2 * var(--ml-space-2)));
6731
6695
  white-space: normal;
@@ -6741,7 +6705,6 @@ button.ml-stepper-target:focus-visible {
6741
6705
  transform: rotate(45deg);
6742
6706
  }
6743
6707
 
6744
- /* The arrow slides back by the tooltip's shift, so it keeps pointing at the trigger. */
6745
6708
  .ml-tooltip[data-side="top"] .ml-tooltip-arrow,
6746
6709
  .ml-tooltip:not([data-side]) .ml-tooltip-arrow {
6747
6710
  bottom: -.2rem;
@@ -6767,14 +6730,12 @@ button.ml-stepper-target:focus-visible {
6767
6730
  margin-top: calc(var(--ml-space-1) * -1 - var(--ml-floating-shift, 0px));
6768
6731
  }
6769
6732
 
6770
- /* components/tour */
6771
6733
  .ml-tour {
6772
6734
  position: fixed;
6773
6735
  inset: 0;
6774
6736
  z-index: var(--ml-layer-top);
6775
6737
  }
6776
6738
 
6777
- /* Without a target the whole page dims; with one, the spotlight casts the dimming. */
6778
6739
  .ml-tour-scrim {
6779
6740
  position: absolute;
6780
6741
  inset: 0;
@@ -6806,7 +6767,7 @@ button.ml-stepper-target:focus-visible {
6806
6767
  background: var(--ml-surface-elevated);
6807
6768
  box-shadow: var(--ml-shadow-xl);
6808
6769
  color: var(--ml-text);
6809
- /* audit-allow: focus.removed — the tour card is focused by script (tabindex -1); its buttons carry the focus style. */
6770
+
6810
6771
  outline: none;
6811
6772
  animation: ml-pop-in var(--ml-duration-fast) var(--ml-ease-spring);
6812
6773
  }
@@ -6915,7 +6876,6 @@ button.ml-stepper-target:focus-visible {
6915
6876
  }
6916
6877
  }
6917
6878
 
6918
- /* components/virtual-list */
6919
6879
  .ml-virtual-list {
6920
6880
  position: relative;
6921
6881
  overflow-y: auto;
@@ -6928,7 +6888,6 @@ button.ml-stepper-target:focus-visible {
6928
6888
  box-shadow: inset 0 0 0 2px var(--ml-focus);
6929
6889
  }
6930
6890
 
6931
- /* The full height of every row, so the scrollbar tells the truth. */
6932
6891
  .ml-virtual-list-space {
6933
6892
  position: relative;
6934
6893
  width: 100%;