@tensor_1/tokens 2.10.0 → 2.11.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.
@@ -207,8 +207,7 @@
207
207
  }
208
208
  .uix-checkbox > input:checked + .uix-checkbox__box,
209
209
  .uix-checkbox > input:indeterminate + .uix-checkbox__box { background: var(--uix-accent); border-color: var(--uix-accent); }
210
- .uix-checkbox > input:checked + .uix-checkbox__box svg,
211
- .uix-checkbox > input:indeterminate + .uix-checkbox__box svg { opacity: 1; transform: none; } /* indeterminate shows its dash icon, not just the filled box (UIX-A11Y-3) */
210
+ .uix-checkbox > input:checked + .uix-checkbox__box svg { opacity: 1; transform: none; }
212
211
  .uix-checkbox > input:focus-visible + .uix-checkbox__box { outline: 2px solid var(--uix-ring); outline-offset: 2px; }
213
212
  .uix-checkbox > input:disabled ~ * { opacity: .5; }
214
213
  }
@@ -260,7 +259,7 @@
260
259
  transition: background-color var(--uix-dur-fast) var(--uix-ease-out), color var(--uix-dur-fast) var(--uix-ease-out);
261
260
  }
262
261
  .uix-segmented__option:hover { color: var(--uix-text); }
263
- .uix-segmented__option[aria-pressed="true"] { background: var(--uix-surface); color: var(--uix-text); box-shadow: var(--uix-shadow-sm); }
262
+ .uix-segmented__option[aria-selected="true"], .uix-segmented__option[aria-pressed="true"] { background: var(--uix-surface); color: var(--uix-text); box-shadow: var(--uix-shadow-sm); }
264
263
  .uix-segmented__option:focus-visible { outline: 2px solid var(--uix-ring); outline-offset: 1px; }
265
264
  }
266
265
  /* uix slider (native range, styled) — depends only on --uix-* tokens. */
@@ -334,9 +333,7 @@
334
333
  display: inline-flex; align-items: center; gap: var(--uix-space-1); padding: var(--uix-space-1) var(--uix-space-1) var(--uix-space-1) var(--uix-space-2); border-radius: var(--uix-radius-sm);
335
334
  background: var(--uix-bg-active); color: var(--uix-text); font-size: var(--uix-text-meta);
336
335
  }
337
- .uix-tag__remove { position: relative; display: grid; place-items: center; width: 16px; height: 16px; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; border-radius: var(--uix-radius-xs); }
338
- /* Invisible overlay grows the 16px visual to a 24px hit target (UIX-A11Y-3). */
339
- .uix-tag__remove::before { content: ""; position: absolute; inset: -4px; }
336
+ .uix-tag__remove { display: grid; place-items: center; width: 16px; height: 16px; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; border-radius: var(--uix-radius-xs); }
340
337
  .uix-tag__remove:hover { background: var(--uix-bg-hover); color: var(--uix-text); }
341
338
  .uix-tag__remove svg { width: 12px; height: 12px; }
342
339
  }
@@ -345,11 +342,6 @@
345
342
  .uix-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--uix-space-5); }
346
343
  .uix-fieldset { border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); padding: var(--uix-space-6); }
347
344
  .uix-fieldset > legend { padding: 0 var(--uix-space-2); font-size: var(--uix-text-meta); font-weight: 600; color: var(--uix-text); }
348
- /* Labeled RadioGroup renders as a fieldset (UIX-A11Y-3): strip the UA chrome so it
349
- looks identical to the plain-div group; the legend spaces itself (fieldset gap
350
- doesn't reach a legend). */
351
- fieldset.uix-radio-group { border: 0; margin: 0; padding: 0; min-inline-size: auto; }
352
- .uix-radio-group__legend { padding: 0; margin: 0 0 var(--uix-space-2); font-size: var(--uix-text-meta); font-weight: 600; color: var(--uix-text); }
353
345
  .uix-form-inline { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--uix-space-4); }
354
346
  .uix-validation-summary {
355
347
  border: 1px solid var(--uix-danger); background: var(--uix-danger-bg); color: var(--uix-text);
@@ -370,7 +362,7 @@
370
362
  border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); overflow: hidden;
371
363
  transition: grid-template-columns var(--uix-dur) var(--uix-ease-out), grid-template-rows var(--uix-dur) var(--uix-ease-out);
372
364
  }
373
- .uix-shell__sidebar { grid-row: 1 / 3; background: var(--uix-bg-subtle); border-right: 1px solid var(--uix-border); overflow-y: auto; overflow-x: hidden; visibility: visible; transition: visibility var(--uix-dur) var(--uix-ease-out); }
365
+ .uix-shell__sidebar { grid-row: 1 / 3; background: var(--uix-bg-subtle); border-right: 1px solid var(--uix-border); overflow-y: auto; overflow-x: hidden; }
374
366
  .uix-shell__topbar { grid-column: 2; display: flex; align-items: center; gap: var(--uix-space-3); padding: 0 var(--uix-space-6); background: var(--uix-bg-app); border-bottom: 1px solid var(--uix-border); }
375
367
  .uix-shell__main { grid-column: 2; overflow: auto; padding: var(--uix-space-7); background: var(--uix-bg-app); }
376
368
 
@@ -379,39 +371,17 @@
379
371
  only) → hidden (0). data-collapsed stays a back-compat alias for the rail. */
380
372
  .uix-shell[data-nav="rail"], .uix-shell[data-collapsed] { grid-template-columns: var(--uix-sidebar-w-rail) 1fr; }
381
373
  .uix-shell[data-nav="hidden"] { grid-template-columns: 0 1fr; }
382
- /* the 0-width column still renders its links — visibility removes them from the tab
383
- order / accessibility tree while keeping the width transition (UIX-A11Y-2) */
384
- .uix-shell[data-nav="hidden"] .uix-shell__sidebar { visibility: hidden; }
385
374
 
386
375
  /* ── focus / immersive mode ───────────────────────────────────────────────────
387
376
  A table-scoped escape hatch: hide the sidebar AND the topbar so a dense grid
388
377
  uses the whole frame. The app toggles [data-focus] (from a toolbar maximize
389
378
  control) and restores the previous nav state + focus on Esc. */
390
379
  .uix-shell[data-focus] { grid-template-columns: 0 1fr; grid-template-rows: 0 1fr; }
391
- .uix-shell[data-focus] .uix-shell__sidebar { visibility: hidden; } /* see [data-nav="hidden"] above (UIX-A11Y-2) */
392
380
  .uix-shell[data-focus] .uix-shell__topbar { display: none; }
393
381
 
394
382
  /* a floating host for the "exit focus" affordance (Esc also exits) */
395
383
  .uix-shell__focus-exit { position: absolute; top: var(--uix-space-3); right: var(--uix-space-3); z-index: var(--uix-z-overlay); }
396
384
 
397
- /* ── skip link ────────────────────────────────────────────────────────────────
398
- First tab stop in the shell (UIX-A11Y-2): visually hidden until keyboard focus,
399
- then a small pill floating over the shell's top-left corner. */
400
- .uix-skiplink {
401
- position: absolute; top: var(--uix-space-3); left: var(--uix-space-3); z-index: var(--uix-z-overlay);
402
- width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap;
403
- }
404
- .uix-skiplink:focus-visible {
405
- width: auto; height: auto; clip: auto;
406
- display: inline-flex; align-items: center;
407
- padding: var(--uix-space-2) var(--uix-space-4);
408
- background: var(--uix-surface); color: var(--uix-text);
409
- border: 1px solid var(--uix-border); border-radius: var(--uix-radius-pill);
410
- box-shadow: var(--uix-shadow-popover);
411
- outline: 2px solid var(--uix-ring); outline-offset: 2px;
412
- font-size: var(--uix-text-meta); font-weight: 500; text-decoration: none;
413
- }
414
-
415
385
  /* ── full-bleed main ──────────────────────────────────────────────────────────
416
386
  Opt-in per surface: a genuinely wide grid drops the content gutter and runs
417
387
  edge to edge, reclaiming 2 x --uix-space-7. Not the default — most pages want
@@ -452,14 +422,9 @@
452
422
  .uix-navitem__badge { font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
453
423
  /* on the active tint, muted badge dips below AA — hushed composites darker on the tint */
454
424
  .uix-navitem[aria-current="page"] .uix-navitem__badge { color: var(--uix-text-hushed); }
455
- .uix-navitem__star { position: relative; display: grid; place-items: center; width: 22px; height: 22px; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; border-radius: var(--uix-radius-xs); opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out); }
456
- /* invisible halo → 24px effective target with zero visual change (UIX-A11Y-2) */
457
- .uix-navitem__star::before { content: ""; position: absolute; inset: -1px; }
425
+ .uix-navitem__star { display: grid; place-items: center; width: 22px; height: 22px; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; border-radius: var(--uix-radius-xs); opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out); }
458
426
  .uix-navitem__star svg { width: 15px; height: 15px; }
459
- /* keyboard reveal mirrors the hover reveal (UIX-A11Y-2) */
460
- .uix-navitem:hover .uix-navitem__star,
461
- .uix-navitem__star:focus-visible,
462
- .uix-navitem:focus-within .uix-navitem__star { opacity: 1; }
427
+ .uix-navitem:hover .uix-navitem__star { opacity: 1; }
463
428
  .uix-navitem__star[data-on] { opacity: 1; color: var(--uix-warning); }
464
429
  .uix-navitem__star[data-on] svg { fill: currentColor; }
465
430
 
@@ -470,32 +435,19 @@
470
435
  .uix-navgroup__chevron { width: var(--uix-icon-sm); height: var(--uix-icon-sm); }
471
436
  .uix-navgroup__panel { display: grid; grid-template-rows: 1fr; transition: grid-template-rows var(--uix-dur) var(--uix-ease-out); }
472
437
  .uix-navgroup__trigger[aria-expanded="false"] + .uix-navgroup__panel { grid-template-rows: 0fr; }
473
- /* visibility keeps the 0fr-collapsed links out of the tab order / accessibility tree
474
- (UIX-A11Y-2); the transition delays hiding until the row collapse finishes, and
475
- visibility snaps back to visible instantly on expand, so nothing visibly glitches. */
476
- .uix-navgroup__panel > div { overflow: hidden; visibility: visible; transition: visibility var(--uix-dur) var(--uix-ease-out); }
477
- .uix-navgroup__trigger[aria-expanded="false"] + .uix-navgroup__panel > div { visibility: hidden; }
438
+ .uix-navgroup__panel > div { overflow: hidden; }
478
439
  .uix-subitem { padding-left: var(--uix-space-5); }
479
440
  .uix-subitem .uix-navitem__label::before { content: ""; display: inline-block; width: 4px; height: 4px; border-radius: 50%; background: var(--uix-text-muted); margin-right: var(--uix-space-3); vertical-align: middle; }
480
441
 
481
442
  /* collapsed rail */
482
443
  .uix-sidebar[data-collapsed], .uix-sidebar[data-nav="rail"] { width: var(--uix-sidebar-w-rail); }
444
+ .uix-sidebar[data-collapsed] .uix-navitem__label,
483
445
  .uix-sidebar[data-collapsed] .uix-navitem__badge,
484
446
  .uix-sidebar[data-collapsed] .uix-navitem__star,
485
447
  .uix-sidebar[data-collapsed] .uix-sidebar__eyebrow,
486
448
  .uix-sidebar[data-collapsed] .uix-sidebar__brand,
487
449
  .uix-sidebar[data-collapsed] .uix-navgroup__chevron,
488
450
  .uix-sidebar[data-collapsed] .uix-navgroup__panel { display: none; }
489
- /* rail labels stay in the accessibility tree — clip pattern (mirrors .uix-visually-hidden),
490
- not display:none, so icon-only nav items keep their names (UIX-A11Y-2). position:absolute
491
- removes the label from the flex row, so the centered rail layout is unaffected. */
492
- .uix-sidebar[data-collapsed] .uix-navitem__label {
493
- position: absolute !important;
494
- width: 1px; height: 1px;
495
- padding: 0; margin: -1px;
496
- overflow: hidden; clip: rect(0, 0, 0, 0);
497
- white-space: nowrap; border: 0;
498
- }
499
451
  /* center the icon-only rail; head keeps just the toggle, centered */
500
452
  .uix-sidebar[data-collapsed] .uix-navitem { justify-content: center; padding: 0; gap: 0; }
501
453
  .uix-sidebar[data-collapsed] .uix-sidebar__head { justify-content: center; padding-inline: 0; }
@@ -504,7 +456,9 @@
504
456
  @layer uix.components {
505
457
  .uix-breadcrumbs { display: flex; align-items: center; gap: var(--uix-space-2); flex-wrap: wrap; font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
506
458
  .uix-breadcrumbs a { color: var(--uix-text-muted); text-decoration: none; }
507
- .uix-breadcrumbs a:hover { color: var(--uix-text); text-decoration: underline; }
459
+ /* already a quiet link by its own design — hover/focus parity with the quiet-link
460
+ contract in link.css, so the keyboard state matches the pointer state. */
461
+ .uix-breadcrumbs a:is(:hover, :focus-visible) { color: var(--uix-text); text-decoration: underline; }
508
462
  .uix-breadcrumbs__sep { opacity: .55; }
509
463
  .uix-breadcrumbs [aria-current="page"] { color: var(--uix-text); font-weight: 500; }
510
464
  }
@@ -576,9 +530,6 @@
576
530
  .uix-cmdk { width: min(560px, 92vw); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); background: var(--uix-surface-2); box-shadow: var(--uix-shadow-overlay); overflow: hidden; }
577
531
  .uix-cmdk__input { width: 100%; height: 48px; border: 0; border-bottom: 1px solid var(--uix-border); background: transparent; color: var(--uix-text); font: inherit; font-size: var(--uix-text-h3); padding: 0 var(--uix-space-4); }
578
532
  .uix-cmdk__input:focus { outline: none; }
579
- /* visible focus replacement for the suppressed outline (UIX-A11Y-1): the divider under the
580
- input thickens to a 2px ring-colored line */
581
- .uix-cmdk__input:focus-visible { border-bottom-color: var(--uix-ring); box-shadow: 0 1px 0 0 var(--uix-ring); }
582
533
  .uix-cmdk__list { max-height: 320px; overflow-y: auto; padding: var(--uix-space-2); }
583
534
  .uix-cmdk__group { font-size: var(--uix-text-eyebrow); letter-spacing: var(--uix-tracking-eyebrow); text-transform: uppercase; color: var(--uix-text-muted); padding: var(--uix-space-2) var(--uix-space-3) var(--uix-space-1); }
584
535
  .uix-cmdk__item { display: flex; align-items: center; gap: var(--uix-space-3); padding: var(--uix-space-3) var(--uix-space-3); border-radius: var(--uix-radius-sm); color: var(--uix-text); cursor: pointer; font-size: var(--uix-text-body); }
@@ -637,8 +588,6 @@
637
588
  .uix-stat__value { font-size: var(--uix-text-data-hero); font-weight: 600; line-height: var(--uix-leading-data-hero); margin-top: var(--uix-space-3); }
638
589
  .uix-stat__meta { font-size: var(--uix-text-meta); color: var(--uix-text-muted); margin-top: var(--uix-space-2); display: flex; align-items: center; gap: var(--uix-space-2); }
639
590
  .uix-stat__trend { display: inline-flex; align-items: center; gap: var(--uix-space-1); font-size: var(--uix-text-meta); font-weight: 600; padding: var(--uix-space-1) var(--uix-space-2); border-radius: var(--uix-radius-pill); }
640
- /* direction glyph inside the chip (UIX-A11Y-4) — sized to sit on the text baseline row */
641
- .uix-stat__trend svg { width: 10px; height: 10px; flex: none; }
642
591
  .uix-stat__trend--up { color: var(--uix-success); background: var(--uix-success-bg); }
643
592
  .uix-stat__trend--down { color: var(--uix-danger-text); background: var(--uix-danger-bg); }
644
593
  }
@@ -699,28 +648,18 @@
699
648
  /* multi-column sort ordinal (⇧+click adds a secondary key) */
700
649
  .uix-table th[data-sort-order]::before { content: attr(data-sort-order); display: inline-block; margin-right: var(--uix-space-1); font-size: var(--uix-text-eyebrow); font-variant-numeric: tabular-nums; color: var(--uix-accent); }
701
650
 
702
- /* sortable header's real <button> (UIX-A11Y-2): visually indistinguishable from the old
703
- plain-text th — inherited font/colour, no chrome — with an inset overlay so the whole
704
- cell stays the click target (the sticky th is its containing block). The sort arrow and
705
- ordinal stay as th pseudo-content so they never pollute the button's accessible name. */
706
- .uix-th__sortbtn { font: inherit; color: inherit; background: none; border: 0; padding: 0; text-align: inherit; cursor: pointer; }
707
- .uix-th__sortbtn::before { content: ""; position: absolute; inset: 0; }
708
-
709
651
  .uix-table td { padding: 0 var(--uix-space-4); height: var(--uix-row-h); border-bottom: 1px solid var(--uix-border); color: var(--uix-text); vertical-align: middle; }
710
652
  .uix-table tbody tr { background: var(--uix-row); }
711
653
  .uix-table tbody tr:nth-child(even) { background: var(--uix-row-alt); }
712
654
  .uix-table--no-zebra tbody tr, .uix-table--no-zebra tbody tr:nth-child(even) { background: var(--uix-row); }
713
655
  .uix-table tbody tr[data-pinned] { background: var(--uix-row-pinned-bg); }
714
- /* [data-selected] carries row-selection styling; aria-selected is invalid on a native
715
- table row — AT state comes from the row checkbox (UIX-A11Y-2). */
716
- .uix-table tbody tr[data-selected] { background: var(--uix-row-selected-bg); }
656
+ .uix-table tbody tr[aria-selected="true"] { background: var(--uix-row-selected-bg); }
717
657
  .uix-table tbody tr:hover { background: var(--uix-bg-hover); }
718
658
  .uix-table[data-density="compact"] td, .uix-table--compact td { height: var(--uix-row-h-compact); }
719
659
  .uix-table[data-density="comfortable"] td { height: var(--uix-row-h-comfortable); }
720
660
 
721
661
  .uix-table__pin { border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; padding: var(--uix-space-1); border-radius: var(--uix-radius-xs); opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out); }
722
- /* :focus-visible reveal mirrors .uix-rowact so keyboard users can find the pin (UIX-A11Y-2) */
723
- .uix-table tbody tr:hover .uix-table__pin, .uix-table__pin:focus-visible, .uix-table__pin[data-on] { opacity: 1; }
662
+ .uix-table tbody tr:hover .uix-table__pin, .uix-table__pin[data-on] { opacity: 1; }
724
663
  .uix-table__pin:hover { background: var(--uix-bg-active); color: var(--uix-text); }
725
664
  .uix-table__pin[data-on] { color: var(--uix-accent); }
726
665
  .uix-table__pin svg { width: 15px; height: 15px; }
@@ -734,7 +673,7 @@
734
673
  .uix-table--pinned-col.uix-table--no-zebra tbody tr td:first-child,
735
674
  .uix-table--pinned-col.uix-table--no-zebra tbody tr:nth-child(even) td:first-child { background: var(--uix-row); }
736
675
  .uix-table--pinned-col tbody tr[data-pinned] td:first-child { background: var(--uix-row-pinned-bg); }
737
- .uix-table--pinned-col tbody tr[data-selected] td:first-child { background: var(--uix-row-selected-bg); }
676
+ .uix-table--pinned-col tbody tr[aria-selected="true"] td:first-child { background: var(--uix-row-selected-bg); }
738
677
  .uix-table--pinned-col tbody tr:hover td:first-child { background: var(--uix-bg-hover); }
739
678
 
740
679
  /* ── column sizing + cell behaviour (a shared vocabulary, not per-app px) ──────── */
@@ -833,7 +772,7 @@
833
772
  .uix-table--cards thead { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
834
773
  .uix-table--cards tbody, .uix-table--cards tr, .uix-table--cards td { display: block; width: auto; }
835
774
  .uix-table--cards tbody tr { border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md); background: var(--uix-surface); margin: 0 0 var(--uix-space-3); padding: var(--uix-space-1) var(--uix-space-4); box-shadow: var(--uix-shadow-sm); }
836
- .uix-table--cards tbody tr[data-selected] { box-shadow: 0 0 0 2px var(--uix-accent); }
775
+ .uix-table--cards tbody tr[aria-selected="true"] { box-shadow: 0 0 0 2px var(--uix-accent); }
837
776
  .uix-table--cards td { height: auto; display: flex; justify-content: space-between; align-items: center; gap: var(--uix-space-5); padding: var(--uix-space-2) 0; border-bottom: 1px solid var(--uix-border); text-align: right; white-space: normal; }
838
777
  .uix-table--cards td:last-child { border-bottom: 0; }
839
778
  .uix-table--cards td::before { content: attr(data-label); color: var(--uix-text-muted); font-size: var(--uix-text-meta); font-weight: 500; text-align: left; flex: none; }
@@ -939,8 +878,7 @@
939
878
  background: var(--uix-text); color: var(--uix-bg-app);
940
879
  font-size: var(--uix-text-meta); font-weight: 500; line-height: 1.4;
941
880
  padding: var(--uix-space-2) var(--uix-space-3); border-radius: var(--uix-radius-sm);
942
- /* no pointer-events:none — the bubble must be hoverable (WCAG 1.4.13, UIX-A11Y-1) */
943
- box-shadow: var(--uix-shadow-popover); white-space: normal;
881
+ box-shadow: var(--uix-shadow-popover); white-space: normal; pointer-events: none;
944
882
  opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out);
945
883
  }
946
884
  .uix-tooltip__bubble:popover-open { opacity: 1; }
@@ -983,8 +921,7 @@
983
921
  }
984
922
  /* uix timeline / activity feed — depends only on --uix-* tokens. */
985
923
  @layer uix.components {
986
- /* list reset — the React Timeline renders <ol>/<li> for semantics; keep visuals pixel-identical (UIX-A11Y-4) */
987
- .uix-timeline { display: flex; flex-direction: column; list-style: none; margin: 0; padding: 0; }
924
+ .uix-timeline { display: flex; flex-direction: column; }
988
925
  .uix-timeline__item { display: grid; grid-template-columns: 24px 1fr; gap: var(--uix-space-3); }
989
926
  .uix-timeline__rail { display: flex; flex-direction: column; align-items: center; }
990
927
  .uix-timeline__node { width: 12px; height: 12px; border-radius: 50%; background: var(--uix-accent); margin-top: var(--uix-space-1); flex: none; box-shadow: 0 0 0 3px var(--uix-brand-muted); }
@@ -1106,9 +1043,7 @@
1106
1043
  @starting-style { .uix-dialog[open]::backdrop { opacity: 0; } }
1107
1044
 
1108
1045
  .uix-dialog__header { display: flex; align-items: center; gap: var(--uix-space-3); padding: var(--uix-space-4) var(--uix-space-5); border-bottom: 1px solid var(--uix-border); }
1109
- /* title is an <h2> for SR navigation (UIX-A11Y-1); inherits neutralize the base h2
1110
- heading font/tracking/leading so it renders exactly like the old <div> */
1111
- .uix-dialog__title { font-size: var(--uix-text-h3); font-weight: 600; font-family: inherit; letter-spacing: inherit; line-height: inherit; }
1046
+ .uix-dialog__title { font-size: var(--uix-text-h3); font-weight: 600; }
1112
1047
  .uix-dialog__close { margin-left: auto; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; width: 30px; height: 30px; display: grid; place-items: center; border-radius: var(--uix-radius-sm); }
1113
1048
  .uix-dialog__close:hover { background: var(--uix-bg-hover); color: var(--uix-text); }
1114
1049
  .uix-dialog__close svg { width: var(--uix-icon-md); height: var(--uix-icon-md); }
@@ -1168,13 +1103,7 @@
1168
1103
  .uix-peek__nav { display: inline-flex; gap: var(--uix-space-1); }
1169
1104
  .uix-peek__navbtn { width: 28px; height: 28px; display: grid; place-items: center; border: 1px solid var(--uix-border); background: var(--uix-surface); color: var(--uix-text); border-radius: var(--uix-radius-sm); cursor: pointer; }
1170
1105
  .uix-peek__navbtn:hover { background: var(--uix-bg-hover); }
1171
- /* boundary nav uses aria-disabled (still focusable, so focus isn't stranded — UIX-A11Y-1);
1172
- mute it and suppress the hover cue like a disabled control */
1173
- .uix-peek__navbtn[aria-disabled="true"] { color: var(--uix-text-muted); cursor: default; }
1174
- .uix-peek__navbtn[aria-disabled="true"]:hover { background: var(--uix-surface); }
1175
- /* title is an <h2> for SR navigation (UIX-A11Y-1); inherits neutralize the base h2
1176
- heading font/tracking/leading so it renders exactly like the old <div> */
1177
- .uix-peek__title { font-size: var(--uix-text-h3); font-weight: 600; font-family: inherit; letter-spacing: inherit; line-height: inherit; }
1106
+ .uix-peek__title { font-size: var(--uix-text-h3); font-weight: 600; }
1178
1107
  .uix-peek__title a { color: var(--uix-link); }
1179
1108
  .uix-peek__close { margin-left: auto; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; width: 30px; height: 30px; display: grid; place-items: center; border-radius: var(--uix-radius-sm); }
1180
1109
  .uix-peek__close:hover { background: var(--uix-bg-hover); color: var(--uix-text); }
@@ -1327,21 +1256,12 @@
1327
1256
  .uix-inbox__list { border-right: 1px solid var(--uix-border); overflow-y: auto; background: var(--uix-surface); }
1328
1257
  .uix-inbox__item { position: relative; display: flex; flex-direction: column; gap: var(--uix-space-1); padding: var(--uix-space-3) var(--uix-space-4); border-bottom: 1px solid var(--uix-border); cursor: pointer; }
1329
1258
  .uix-inbox__item:hover { background: var(--uix-bg-hover); }
1330
- /* keyboard active option (aria-activedescendant) mirrors the hover style (UIX-A11Y-2) */
1331
- .uix-inbox__item[data-active] { background: var(--uix-bg-hover); }
1332
1259
  .uix-inbox__item[aria-selected="true"] { background: linear-gradient(to right, var(--uix-accent) 3px, var(--uix-brand-muted) 3px); }
1333
1260
  .uix-inbox__item[data-unread] .uix-inbox__subject { font-weight: 600; }
1334
1261
  .uix-inbox__subject { font-size: var(--uix-text-body); }
1335
1262
  .uix-inbox__preview { font-size: var(--uix-text-meta); color: var(--uix-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1336
1263
  .uix-inbox__detail { overflow-y: auto; padding: var(--uix-space-5); background: var(--uix-bg-app); }
1337
- /* narrow viewports stack to one pane: list by default, detail when the app sets
1338
- view="detail" — with a consumer-rendered Back control in the detail pane (UIX-A11Y-2) */
1339
- @media (max-width: 700px) {
1340
- .uix-inbox { grid-template-columns: 1fr; }
1341
- .uix-inbox__detail { display: none; }
1342
- .uix-inbox[data-view="detail"] .uix-inbox__list { display: none; }
1343
- .uix-inbox[data-view="detail"] .uix-inbox__detail { display: block; }
1344
- }
1264
+ @media (max-width: 700px) { .uix-inbox { grid-template-columns: 1fr; } .uix-inbox__detail { display: none; } }
1345
1265
  }
1346
1266
  /* uix notification center — depends only on --uix-* tokens. */
1347
1267
  @layer uix.components {
@@ -1733,7 +1653,8 @@
1733
1653
  .uix-section-head { min-height: 36px; margin-bottom: var(--uix-space-3); display: flex; align-items: center; justify-content: space-between; gap: var(--uix-space-4); }
1734
1654
  .uix-section-title { margin: 0; font-family: var(--uix-font-heading); font-size: var(--uix-text-h2); font-weight: 400; letter-spacing: var(--uix-tracking-tight); }
1735
1655
  .uix-section-link { color: var(--uix-text-hushed); font-size: var(--uix-text-meta); text-decoration: none; }
1736
- .uix-section-link:hover { color: var(--uix-text); }
1656
+ /* already a quiet link by its own design — hover/focus parity with link.css */
1657
+ .uix-section-link:is(:hover, :focus-visible) { color: var(--uix-text); text-decoration: underline; }
1737
1658
 
1738
1659
  /* ── content grid + rail ───────────────────────────────────────────────────── */
1739
1660
  .uix-content-grid { display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(280px, 0.75fr); gap: var(--uix-space-7); align-items: start; }
@@ -1837,36 +1758,90 @@
1837
1758
  * noise at list density (TENSOR INTRA-04, operator-rejected).
1838
1759
  *
1839
1760
  * A quiet link inherits the surrounding text colour and shows its underline on
1840
- * hover/focus. 1.4.1 is not in play: the link is the whole text of its block (a title,
1841
- * a cell), not a link inside body copy. NEVER quiet a link inside prose — in-text links
1842
- * keep the base blue + underline.
1761
+ * hover/focus. The global :focus-visible ring (base.css) still fires, so the keyboard
1762
+ * affordance never rests on the underline alone. WCAG 1.4.1 is not in play for anything
1763
+ * below: the link is the WHOLE text of its block — a title, a name, a data cell — or it
1764
+ * is the block itself. It is never a phrase inside a sentence.
1843
1765
  *
1844
- * Two forms:
1845
- * • `.uix-link--quiet` — the opt-in utility, for block links outside the scoped slots
1846
- * (whole-card links, event rows composed by hand, app-specific list patterns).
1847
- * • quiet BY DEFAULT below — the editorial-home title slots and table data cells,
1848
- * where every anchor is a block-level navigation target. `.uix-table td` keeps
1849
- * `:not([class])` so class-bearing anchors in cells (`.uix-btn--link`, pills)
1850
- * stay styled.
1766
+ * A slot earns quiet-BY-DEFAULT only when BOTH hold:
1767
+ * (i) the anchor fills a named title/name slot or a data cell — the link text IS the
1768
+ * block, not a phrase inside running copy; and
1769
+ * (ii) the surrounding row/card/tile already reads as interactive (hover state, cursor,
1770
+ * bordered unit), or the slot is that record's primary label.
1771
+ *
1772
+ * Deliberate exclusions, so the next person doesn't "finish the job":
1773
+ * • Prose and message bodies — .uix-prose, .uix-note, .uix-notice__copy,
1774
+ * .uix-timeline__body, .uix-audit__detail, .uix-notif copy. Links there sit inside
1775
+ * sentences: 1.4.1 applies and the base treatment is correct.
1776
+ * • .uix-alert, .uix-toast, .uix-peek__title — nothing else in those containers signals
1777
+ * that the link navigates, so the colour IS the affordance. peek.css sets --uix-link
1778
+ * on its title anchor on purpose; do not quiet it.
1779
+ * • .uix-comment__author — a byline renders "Author · 22m ago", so the name is a phrase
1780
+ * inside a text run, not the whole block, and .uix-comment__meta is not interactive.
1781
+ * It fails test (i) above. Products wanting the GitHub-style quiet byline opt in with
1782
+ * .uix-link--quiet; that is what the utility is for.
1783
+ * • .uix-navitem, .uix-breadcrumbs a, .uix-section-link are already quiet by their own
1784
+ * design and need no class here.
1785
+ *
1786
+ * Four forms:
1787
+ * 1 · `.uix-link--quiet` — the opt-in utility, for block links outside the registry.
1788
+ * 2 · TITLE / NAME SLOTS — quiet by default. `:not(.uix-btn)` so an anchor deliberately
1789
+ * styled as a button inside a title slot keeps its button treatment.
1790
+ * 3 · DATA CELLS — table cells and description-list values. `:not([class])` so
1791
+ * class-bearing anchors (`.uix-btn--link`, pills, tags) stay styled.
1792
+ * 4 · CONTAINER ANCHORS — the anchor IS the kit block (`<a class="uix-card">`). Without
1793
+ * this the base `a { color }` tints every word in the block brand-blue.
1851
1794
  * Depends only on --uix-* tokens. */
1852
1795
  @layer uix.components {
1853
1796
  .uix-link--quiet,
1854
- .uix-content-list__title a,
1855
- .uix-news-lead__title a,
1856
- .uix-rundown__item-title a,
1857
- .uix-event-row__title a,
1858
- .uix-table td a:not([class]) { color: inherit; text-decoration: none; }
1859
-
1860
- .uix-link--quiet:hover,
1861
- .uix-link--quiet:focus-visible,
1862
- .uix-content-list__title a:hover,
1863
- .uix-content-list__title a:focus-visible,
1864
- .uix-news-lead__title a:hover,
1865
- .uix-news-lead__title a:focus-visible,
1866
- .uix-rundown__item-title a:hover,
1867
- .uix-rundown__item-title a:focus-visible,
1868
- .uix-event-row__title a:hover,
1869
- .uix-event-row__title a:focus-visible,
1870
- .uix-table td a:not([class]):hover,
1871
- .uix-table td a:not([class]):focus-visible { text-decoration: underline; }
1797
+
1798
+ /* 2 · title / name slots */
1799
+ :is(
1800
+ /* editorial-home */
1801
+ .uix-featured__title, .uix-rail-card__title, .uix-news-lead__title,
1802
+ .uix-content-list__title, .uix-rundown__item-title, .uix-event-row__title,
1803
+ .uix-status-row__name,
1804
+ /* records, rows, cards */
1805
+ .uix-card__title, .uix-list__title, .uix-inbox__subject, .uix-kanban__card-title,
1806
+ .uix-media__name, .uix-attachment__name, .uix-contact__name, .uix-user-chip__name,
1807
+ .uix-audit__actor
1808
+ ) a:not(.uix-btn),
1809
+
1810
+ /* 3 · data cells */
1811
+ :is(.uix-table td, .uix-dl dd) a:not([class]),
1812
+
1813
+ /* 4 · container anchors */
1814
+ a:is(
1815
+ .uix-card, .uix-stat, .uix-list__item, .uix-inbox__item, .uix-kanban__card,
1816
+ .uix-notif, .uix-media, .uix-attachment, .uix-contact, .uix-cmdk__item,
1817
+ .uix-content-list__item, .uix-event-row, .uix-status-row
1818
+ ) { color: inherit; text-decoration: none; }
1819
+
1820
+ .uix-link--quiet:is(:hover, :focus-visible),
1821
+
1822
+ :is(
1823
+ .uix-featured__title, .uix-rail-card__title, .uix-news-lead__title,
1824
+ .uix-content-list__title, .uix-rundown__item-title, .uix-event-row__title,
1825
+ .uix-status-row__name,
1826
+ .uix-card__title, .uix-list__title, .uix-inbox__subject, .uix-kanban__card-title,
1827
+ .uix-media__name, .uix-attachment__name, .uix-contact__name, .uix-user-chip__name,
1828
+ .uix-audit__actor
1829
+ ) a:not(.uix-btn):is(:hover, :focus-visible),
1830
+
1831
+ :is(.uix-table td, .uix-dl dd) a:not([class]):is(:hover, :focus-visible) { text-decoration: underline; }
1832
+
1833
+ /* Container anchors never underline: the anchor wraps the whole block, so an underline
1834
+ would strike through every word in it. They take the kit's standard row-hover tint
1835
+ instead — the same --uix-bg-hover that .uix-list__item / .uix-inbox__item / .uix-cmdk__item
1836
+ already use, so containers with a hover of their own just restate it. */
1837
+ a:is(
1838
+ .uix-card, .uix-stat, .uix-list__item, .uix-inbox__item, .uix-kanban__card,
1839
+ .uix-notif, .uix-media, .uix-attachment, .uix-contact, .uix-cmdk__item,
1840
+ .uix-content-list__item, .uix-event-row, .uix-status-row
1841
+ ):is(:hover, :focus-visible) { background: var(--uix-bg-hover); }
1842
+
1843
+ /* Container anchors that declare no display of their own would render inline as an <a>.
1844
+ The rest of form 4 (flex/grid rows) set theirs already and must NOT be overridden —
1845
+ link.css is imported last, so a blanket display here would flatten them. */
1846
+ a:is(.uix-card, .uix-stat, .uix-kanban__card) { display: block; }
1872
1847
  }
@@ -1,5 +1,5 @@
1
1
 
2
- @layer uix.tokens, uix.base, uix.util, uix.motion, uix.components, uix.forced-colors;
2
+ @layer uix.tokens, uix.base, uix.util, uix.motion, uix.components;
3
3
  /* uix-styleguide — aggregate stylesheet. Declares the cascade-layer order, then imports each layer.
4
4
  Component @imports are appended here as phases land (each component file declares @layer uix.components). */
5
5
  /* uix tokens — REDIRECT (no longer hand-authored).
@@ -149,19 +149,19 @@
149
149
  --uix-font-sans: "Inter",system-ui,sans-serif;
150
150
  --uix-font-heading: "IBM Plex Sans","Inter",system-ui,sans-serif;
151
151
  --uix-font-mono: "IBM Plex Mono",ui-monospace,monospace;
152
- --uix-text-display: 2.5rem;
152
+ --uix-text-display: 40px;
153
153
  --uix-leading-display: 1.05;
154
- --uix-text-data-hero: 2.125rem;
154
+ --uix-text-data-hero: 34px;
155
155
  --uix-leading-data-hero: 1.1;
156
- --uix-text-h2: 1.5rem;
156
+ --uix-text-h2: 24px;
157
157
  --uix-leading-h2: 1.15;
158
- --uix-text-h3: 0.9375rem;
158
+ --uix-text-h3: 15px;
159
159
  --uix-leading-h3: 1.3;
160
- --uix-text-body: 0.875rem;
160
+ --uix-text-body: 14px;
161
161
  --uix-leading-body: 1.5;
162
- --uix-text-meta: 0.78125rem;
162
+ --uix-text-meta: 12.5px;
163
163
  --uix-leading-meta: 1.4;
164
- --uix-text-eyebrow: 0.6875rem;
164
+ --uix-text-eyebrow: 11px;
165
165
  --uix-leading-eyebrow: 1.2;
166
166
  --uix-tracking-tight: -0.02em;
167
167
  --uix-tracking-eyebrow: 0.06em;
@@ -272,9 +272,6 @@
272
272
  h3 { font-size: var(--uix-text-h3); line-height: var(--uix-leading-h3); }
273
273
 
274
274
  img, svg, video, canvas { display: block; max-width: 100%; }
275
- /* the display:block reset above (and any component display) would defeat the `hidden`
276
- attribute; restore it globally. `until-found` keeps find-in-page auto-reveal (UIX-A11Y-4). */
277
- [hidden]:not([hidden="until-found"]) { display: none !important; }
278
275
  input, button, textarea, select { font: inherit; color: inherit; }
279
276
  code, kbd, pre, samp { font-family: var(--uix-font-mono); }
280
277
 
@@ -506,8 +503,7 @@
506
503
  }
507
504
  .uix-checkbox > input:checked + .uix-checkbox__box,
508
505
  .uix-checkbox > input:indeterminate + .uix-checkbox__box { background: var(--uix-accent); border-color: var(--uix-accent); }
509
- .uix-checkbox > input:checked + .uix-checkbox__box svg,
510
- .uix-checkbox > input:indeterminate + .uix-checkbox__box svg { opacity: 1; transform: none; } /* indeterminate shows its dash icon, not just the filled box (UIX-A11Y-3) */
506
+ .uix-checkbox > input:checked + .uix-checkbox__box svg { opacity: 1; transform: none; }
511
507
  .uix-checkbox > input:focus-visible + .uix-checkbox__box { outline: 2px solid var(--uix-ring); outline-offset: 2px; }
512
508
  .uix-checkbox > input:disabled ~ * { opacity: .5; }
513
509
  }
@@ -559,7 +555,7 @@
559
555
  transition: background-color var(--uix-dur-fast) var(--uix-ease-out), color var(--uix-dur-fast) var(--uix-ease-out);
560
556
  }
561
557
  .uix-segmented__option:hover { color: var(--uix-text); }
562
- .uix-segmented__option[aria-pressed="true"] { background: var(--uix-surface); color: var(--uix-text); box-shadow: var(--uix-shadow-sm); }
558
+ .uix-segmented__option[aria-selected="true"], .uix-segmented__option[aria-pressed="true"] { background: var(--uix-surface); color: var(--uix-text); box-shadow: var(--uix-shadow-sm); }
563
559
  .uix-segmented__option:focus-visible { outline: 2px solid var(--uix-ring); outline-offset: 1px; }
564
560
  }
565
561
  /* uix slider (native range, styled) — depends only on --uix-* tokens. */
@@ -633,9 +629,7 @@
633
629
  display: inline-flex; align-items: center; gap: var(--uix-space-1); padding: var(--uix-space-1) var(--uix-space-1) var(--uix-space-1) var(--uix-space-2); border-radius: var(--uix-radius-sm);
634
630
  background: var(--uix-bg-active); color: var(--uix-text); font-size: var(--uix-text-meta);
635
631
  }
636
- .uix-tag__remove { position: relative; display: grid; place-items: center; width: 16px; height: 16px; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; border-radius: var(--uix-radius-xs); }
637
- /* Invisible overlay grows the 16px visual to a 24px hit target (UIX-A11Y-3). */
638
- .uix-tag__remove::before { content: ""; position: absolute; inset: -4px; }
632
+ .uix-tag__remove { display: grid; place-items: center; width: 16px; height: 16px; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; border-radius: var(--uix-radius-xs); }
639
633
  .uix-tag__remove:hover { background: var(--uix-bg-hover); color: var(--uix-text); }
640
634
  .uix-tag__remove svg { width: 12px; height: 12px; }
641
635
  }
@@ -644,11 +638,6 @@
644
638
  .uix-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--uix-space-5); }
645
639
  .uix-fieldset { border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); padding: var(--uix-space-6); }
646
640
  .uix-fieldset > legend { padding: 0 var(--uix-space-2); font-size: var(--uix-text-meta); font-weight: 600; color: var(--uix-text); }
647
- /* Labeled RadioGroup renders as a fieldset (UIX-A11Y-3): strip the UA chrome so it
648
- looks identical to the plain-div group; the legend spaces itself (fieldset gap
649
- doesn't reach a legend). */
650
- fieldset.uix-radio-group { border: 0; margin: 0; padding: 0; min-inline-size: auto; }
651
- .uix-radio-group__legend { padding: 0; margin: 0 0 var(--uix-space-2); font-size: var(--uix-text-meta); font-weight: 600; color: var(--uix-text); }
652
641
  .uix-form-inline { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--uix-space-4); }
653
642
  .uix-validation-summary {
654
643
  border: 1px solid var(--uix-danger); background: var(--uix-danger-bg); color: var(--uix-text);
@@ -669,7 +658,7 @@
669
658
  border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); overflow: hidden;
670
659
  transition: grid-template-columns var(--uix-dur) var(--uix-ease-out), grid-template-rows var(--uix-dur) var(--uix-ease-out);
671
660
  }
672
- .uix-shell__sidebar { grid-row: 1 / 3; background: var(--uix-bg-subtle); border-right: 1px solid var(--uix-border); overflow-y: auto; overflow-x: hidden; visibility: visible; transition: visibility var(--uix-dur) var(--uix-ease-out); }
661
+ .uix-shell__sidebar { grid-row: 1 / 3; background: var(--uix-bg-subtle); border-right: 1px solid var(--uix-border); overflow-y: auto; overflow-x: hidden; }
673
662
  .uix-shell__topbar { grid-column: 2; display: flex; align-items: center; gap: var(--uix-space-3); padding: 0 var(--uix-space-6); background: var(--uix-bg-app); border-bottom: 1px solid var(--uix-border); }
674
663
  .uix-shell__main { grid-column: 2; overflow: auto; padding: var(--uix-space-7); background: var(--uix-bg-app); }
675
664
 
@@ -678,39 +667,17 @@
678
667
  only) → hidden (0). data-collapsed stays a back-compat alias for the rail. */
679
668
  .uix-shell[data-nav="rail"], .uix-shell[data-collapsed] { grid-template-columns: var(--uix-sidebar-w-rail) 1fr; }
680
669
  .uix-shell[data-nav="hidden"] { grid-template-columns: 0 1fr; }
681
- /* the 0-width column still renders its links — visibility removes them from the tab
682
- order / accessibility tree while keeping the width transition (UIX-A11Y-2) */
683
- .uix-shell[data-nav="hidden"] .uix-shell__sidebar { visibility: hidden; }
684
670
 
685
671
  /* ── focus / immersive mode ───────────────────────────────────────────────────
686
672
  A table-scoped escape hatch: hide the sidebar AND the topbar so a dense grid
687
673
  uses the whole frame. The app toggles [data-focus] (from a toolbar maximize
688
674
  control) and restores the previous nav state + focus on Esc. */
689
675
  .uix-shell[data-focus] { grid-template-columns: 0 1fr; grid-template-rows: 0 1fr; }
690
- .uix-shell[data-focus] .uix-shell__sidebar { visibility: hidden; } /* see [data-nav="hidden"] above (UIX-A11Y-2) */
691
676
  .uix-shell[data-focus] .uix-shell__topbar { display: none; }
692
677
 
693
678
  /* a floating host for the "exit focus" affordance (Esc also exits) */
694
679
  .uix-shell__focus-exit { position: absolute; top: var(--uix-space-3); right: var(--uix-space-3); z-index: var(--uix-z-overlay); }
695
680
 
696
- /* ── skip link ────────────────────────────────────────────────────────────────
697
- First tab stop in the shell (UIX-A11Y-2): visually hidden until keyboard focus,
698
- then a small pill floating over the shell's top-left corner. */
699
- .uix-skiplink {
700
- position: absolute; top: var(--uix-space-3); left: var(--uix-space-3); z-index: var(--uix-z-overlay);
701
- width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap;
702
- }
703
- .uix-skiplink:focus-visible {
704
- width: auto; height: auto; clip: auto;
705
- display: inline-flex; align-items: center;
706
- padding: var(--uix-space-2) var(--uix-space-4);
707
- background: var(--uix-surface); color: var(--uix-text);
708
- border: 1px solid var(--uix-border); border-radius: var(--uix-radius-pill);
709
- box-shadow: var(--uix-shadow-popover);
710
- outline: 2px solid var(--uix-ring); outline-offset: 2px;
711
- font-size: var(--uix-text-meta); font-weight: 500; text-decoration: none;
712
- }
713
-
714
681
  /* ── full-bleed main ──────────────────────────────────────────────────────────
715
682
  Opt-in per surface: a genuinely wide grid drops the content gutter and runs
716
683
  edge to edge, reclaiming 2 x --uix-space-7. Not the default — most pages want
@@ -751,14 +718,9 @@
751
718
  .uix-navitem__badge { font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
752
719
  /* on the active tint, muted badge dips below AA — hushed composites darker on the tint */
753
720
  .uix-navitem[aria-current="page"] .uix-navitem__badge { color: var(--uix-text-hushed); }
754
- .uix-navitem__star { position: relative; display: grid; place-items: center; width: 22px; height: 22px; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; border-radius: var(--uix-radius-xs); opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out); }
755
- /* invisible halo → 24px effective target with zero visual change (UIX-A11Y-2) */
756
- .uix-navitem__star::before { content: ""; position: absolute; inset: -1px; }
721
+ .uix-navitem__star { display: grid; place-items: center; width: 22px; height: 22px; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; border-radius: var(--uix-radius-xs); opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out); }
757
722
  .uix-navitem__star svg { width: 15px; height: 15px; }
758
- /* keyboard reveal mirrors the hover reveal (UIX-A11Y-2) */
759
- .uix-navitem:hover .uix-navitem__star,
760
- .uix-navitem__star:focus-visible,
761
- .uix-navitem:focus-within .uix-navitem__star { opacity: 1; }
723
+ .uix-navitem:hover .uix-navitem__star { opacity: 1; }
762
724
  .uix-navitem__star[data-on] { opacity: 1; color: var(--uix-warning); }
763
725
  .uix-navitem__star[data-on] svg { fill: currentColor; }
764
726
 
@@ -769,32 +731,19 @@
769
731
  .uix-navgroup__chevron { width: var(--uix-icon-sm); height: var(--uix-icon-sm); }
770
732
  .uix-navgroup__panel { display: grid; grid-template-rows: 1fr; transition: grid-template-rows var(--uix-dur) var(--uix-ease-out); }
771
733
  .uix-navgroup__trigger[aria-expanded="false"] + .uix-navgroup__panel { grid-template-rows: 0fr; }
772
- /* visibility keeps the 0fr-collapsed links out of the tab order / accessibility tree
773
- (UIX-A11Y-2); the transition delays hiding until the row collapse finishes, and
774
- visibility snaps back to visible instantly on expand, so nothing visibly glitches. */
775
- .uix-navgroup__panel > div { overflow: hidden; visibility: visible; transition: visibility var(--uix-dur) var(--uix-ease-out); }
776
- .uix-navgroup__trigger[aria-expanded="false"] + .uix-navgroup__panel > div { visibility: hidden; }
734
+ .uix-navgroup__panel > div { overflow: hidden; }
777
735
  .uix-subitem { padding-left: var(--uix-space-5); }
778
736
  .uix-subitem .uix-navitem__label::before { content: ""; display: inline-block; width: 4px; height: 4px; border-radius: 50%; background: var(--uix-text-muted); margin-right: var(--uix-space-3); vertical-align: middle; }
779
737
 
780
738
  /* collapsed rail */
781
739
  .uix-sidebar[data-collapsed], .uix-sidebar[data-nav="rail"] { width: var(--uix-sidebar-w-rail); }
740
+ .uix-sidebar[data-collapsed] .uix-navitem__label,
782
741
  .uix-sidebar[data-collapsed] .uix-navitem__badge,
783
742
  .uix-sidebar[data-collapsed] .uix-navitem__star,
784
743
  .uix-sidebar[data-collapsed] .uix-sidebar__eyebrow,
785
744
  .uix-sidebar[data-collapsed] .uix-sidebar__brand,
786
745
  .uix-sidebar[data-collapsed] .uix-navgroup__chevron,
787
746
  .uix-sidebar[data-collapsed] .uix-navgroup__panel { display: none; }
788
- /* rail labels stay in the accessibility tree — clip pattern (mirrors .uix-visually-hidden),
789
- not display:none, so icon-only nav items keep their names (UIX-A11Y-2). position:absolute
790
- removes the label from the flex row, so the centered rail layout is unaffected. */
791
- .uix-sidebar[data-collapsed] .uix-navitem__label {
792
- position: absolute !important;
793
- width: 1px; height: 1px;
794
- padding: 0; margin: -1px;
795
- overflow: hidden; clip: rect(0, 0, 0, 0);
796
- white-space: nowrap; border: 0;
797
- }
798
747
  /* center the icon-only rail; head keeps just the toggle, centered */
799
748
  .uix-sidebar[data-collapsed] .uix-navitem { justify-content: center; padding: 0; gap: 0; }
800
749
  .uix-sidebar[data-collapsed] .uix-sidebar__head { justify-content: center; padding-inline: 0; }
@@ -803,7 +752,9 @@
803
752
  @layer uix.components {
804
753
  .uix-breadcrumbs { display: flex; align-items: center; gap: var(--uix-space-2); flex-wrap: wrap; font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
805
754
  .uix-breadcrumbs a { color: var(--uix-text-muted); text-decoration: none; }
806
- .uix-breadcrumbs a:hover { color: var(--uix-text); text-decoration: underline; }
755
+ /* already a quiet link by its own design — hover/focus parity with the quiet-link
756
+ contract in link.css, so the keyboard state matches the pointer state. */
757
+ .uix-breadcrumbs a:is(:hover, :focus-visible) { color: var(--uix-text); text-decoration: underline; }
807
758
  .uix-breadcrumbs__sep { opacity: .55; }
808
759
  .uix-breadcrumbs [aria-current="page"] { color: var(--uix-text); font-weight: 500; }
809
760
  }
@@ -875,9 +826,6 @@
875
826
  .uix-cmdk { width: min(560px, 92vw); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); background: var(--uix-surface-2); box-shadow: var(--uix-shadow-overlay); overflow: hidden; }
876
827
  .uix-cmdk__input { width: 100%; height: 48px; border: 0; border-bottom: 1px solid var(--uix-border); background: transparent; color: var(--uix-text); font: inherit; font-size: var(--uix-text-h3); padding: 0 var(--uix-space-4); }
877
828
  .uix-cmdk__input:focus { outline: none; }
878
- /* visible focus replacement for the suppressed outline (UIX-A11Y-1): the divider under the
879
- input thickens to a 2px ring-colored line */
880
- .uix-cmdk__input:focus-visible { border-bottom-color: var(--uix-ring); box-shadow: 0 1px 0 0 var(--uix-ring); }
881
829
  .uix-cmdk__list { max-height: 320px; overflow-y: auto; padding: var(--uix-space-2); }
882
830
  .uix-cmdk__group { font-size: var(--uix-text-eyebrow); letter-spacing: var(--uix-tracking-eyebrow); text-transform: uppercase; color: var(--uix-text-muted); padding: var(--uix-space-2) var(--uix-space-3) var(--uix-space-1); }
883
831
  .uix-cmdk__item { display: flex; align-items: center; gap: var(--uix-space-3); padding: var(--uix-space-3) var(--uix-space-3); border-radius: var(--uix-radius-sm); color: var(--uix-text); cursor: pointer; font-size: var(--uix-text-body); }
@@ -936,8 +884,6 @@
936
884
  .uix-stat__value { font-size: var(--uix-text-data-hero); font-weight: 600; line-height: var(--uix-leading-data-hero); margin-top: var(--uix-space-3); }
937
885
  .uix-stat__meta { font-size: var(--uix-text-meta); color: var(--uix-text-muted); margin-top: var(--uix-space-2); display: flex; align-items: center; gap: var(--uix-space-2); }
938
886
  .uix-stat__trend { display: inline-flex; align-items: center; gap: var(--uix-space-1); font-size: var(--uix-text-meta); font-weight: 600; padding: var(--uix-space-1) var(--uix-space-2); border-radius: var(--uix-radius-pill); }
939
- /* direction glyph inside the chip (UIX-A11Y-4) — sized to sit on the text baseline row */
940
- .uix-stat__trend svg { width: 10px; height: 10px; flex: none; }
941
887
  .uix-stat__trend--up { color: var(--uix-success); background: var(--uix-success-bg); }
942
888
  .uix-stat__trend--down { color: var(--uix-danger-text); background: var(--uix-danger-bg); }
943
889
  }
@@ -998,28 +944,18 @@
998
944
  /* multi-column sort ordinal (⇧+click adds a secondary key) */
999
945
  .uix-table th[data-sort-order]::before { content: attr(data-sort-order); display: inline-block; margin-right: var(--uix-space-1); font-size: var(--uix-text-eyebrow); font-variant-numeric: tabular-nums; color: var(--uix-accent); }
1000
946
 
1001
- /* sortable header's real <button> (UIX-A11Y-2): visually indistinguishable from the old
1002
- plain-text th — inherited font/colour, no chrome — with an inset overlay so the whole
1003
- cell stays the click target (the sticky th is its containing block). The sort arrow and
1004
- ordinal stay as th pseudo-content so they never pollute the button's accessible name. */
1005
- .uix-th__sortbtn { font: inherit; color: inherit; background: none; border: 0; padding: 0; text-align: inherit; cursor: pointer; }
1006
- .uix-th__sortbtn::before { content: ""; position: absolute; inset: 0; }
1007
-
1008
947
  .uix-table td { padding: 0 var(--uix-space-4); height: var(--uix-row-h); border-bottom: 1px solid var(--uix-border); color: var(--uix-text); vertical-align: middle; }
1009
948
  .uix-table tbody tr { background: var(--uix-row); }
1010
949
  .uix-table tbody tr:nth-child(even) { background: var(--uix-row-alt); }
1011
950
  .uix-table--no-zebra tbody tr, .uix-table--no-zebra tbody tr:nth-child(even) { background: var(--uix-row); }
1012
951
  .uix-table tbody tr[data-pinned] { background: var(--uix-row-pinned-bg); }
1013
- /* [data-selected] carries row-selection styling; aria-selected is invalid on a native
1014
- table row — AT state comes from the row checkbox (UIX-A11Y-2). */
1015
- .uix-table tbody tr[data-selected] { background: var(--uix-row-selected-bg); }
952
+ .uix-table tbody tr[aria-selected="true"] { background: var(--uix-row-selected-bg); }
1016
953
  .uix-table tbody tr:hover { background: var(--uix-bg-hover); }
1017
954
  .uix-table[data-density="compact"] td, .uix-table--compact td { height: var(--uix-row-h-compact); }
1018
955
  .uix-table[data-density="comfortable"] td { height: var(--uix-row-h-comfortable); }
1019
956
 
1020
957
  .uix-table__pin { border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; padding: var(--uix-space-1); border-radius: var(--uix-radius-xs); opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out); }
1021
- /* :focus-visible reveal mirrors .uix-rowact so keyboard users can find the pin (UIX-A11Y-2) */
1022
- .uix-table tbody tr:hover .uix-table__pin, .uix-table__pin:focus-visible, .uix-table__pin[data-on] { opacity: 1; }
958
+ .uix-table tbody tr:hover .uix-table__pin, .uix-table__pin[data-on] { opacity: 1; }
1023
959
  .uix-table__pin:hover { background: var(--uix-bg-active); color: var(--uix-text); }
1024
960
  .uix-table__pin[data-on] { color: var(--uix-accent); }
1025
961
  .uix-table__pin svg { width: 15px; height: 15px; }
@@ -1033,7 +969,7 @@
1033
969
  .uix-table--pinned-col.uix-table--no-zebra tbody tr td:first-child,
1034
970
  .uix-table--pinned-col.uix-table--no-zebra tbody tr:nth-child(even) td:first-child { background: var(--uix-row); }
1035
971
  .uix-table--pinned-col tbody tr[data-pinned] td:first-child { background: var(--uix-row-pinned-bg); }
1036
- .uix-table--pinned-col tbody tr[data-selected] td:first-child { background: var(--uix-row-selected-bg); }
972
+ .uix-table--pinned-col tbody tr[aria-selected="true"] td:first-child { background: var(--uix-row-selected-bg); }
1037
973
  .uix-table--pinned-col tbody tr:hover td:first-child { background: var(--uix-bg-hover); }
1038
974
 
1039
975
  /* ── column sizing + cell behaviour (a shared vocabulary, not per-app px) ──────── */
@@ -1132,7 +1068,7 @@
1132
1068
  .uix-table--cards thead { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
1133
1069
  .uix-table--cards tbody, .uix-table--cards tr, .uix-table--cards td { display: block; width: auto; }
1134
1070
  .uix-table--cards tbody tr { border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md); background: var(--uix-surface); margin: 0 0 var(--uix-space-3); padding: var(--uix-space-1) var(--uix-space-4); box-shadow: var(--uix-shadow-sm); }
1135
- .uix-table--cards tbody tr[data-selected] { box-shadow: 0 0 0 2px var(--uix-accent); }
1071
+ .uix-table--cards tbody tr[aria-selected="true"] { box-shadow: 0 0 0 2px var(--uix-accent); }
1136
1072
  .uix-table--cards td { height: auto; display: flex; justify-content: space-between; align-items: center; gap: var(--uix-space-5); padding: var(--uix-space-2) 0; border-bottom: 1px solid var(--uix-border); text-align: right; white-space: normal; }
1137
1073
  .uix-table--cards td:last-child { border-bottom: 0; }
1138
1074
  .uix-table--cards td::before { content: attr(data-label); color: var(--uix-text-muted); font-size: var(--uix-text-meta); font-weight: 500; text-align: left; flex: none; }
@@ -1283,8 +1219,7 @@
1283
1219
  background: var(--uix-text); color: var(--uix-bg-app);
1284
1220
  font-size: var(--uix-text-meta); font-weight: 500; line-height: 1.4;
1285
1221
  padding: var(--uix-space-2) var(--uix-space-3); border-radius: var(--uix-radius-sm);
1286
- /* no pointer-events:none — the bubble must be hoverable (WCAG 1.4.13, UIX-A11Y-1) */
1287
- box-shadow: var(--uix-shadow-popover); white-space: normal;
1222
+ box-shadow: var(--uix-shadow-popover); white-space: normal; pointer-events: none;
1288
1223
  opacity: 0; transition: opacity var(--uix-dur-fast) var(--uix-ease-out);
1289
1224
  }
1290
1225
  .uix-tooltip__bubble:popover-open { opacity: 1; }
@@ -1327,8 +1262,7 @@
1327
1262
  }
1328
1263
  /* uix timeline / activity feed — depends only on --uix-* tokens. */
1329
1264
  @layer uix.components {
1330
- /* list reset — the React Timeline renders <ol>/<li> for semantics; keep visuals pixel-identical (UIX-A11Y-4) */
1331
- .uix-timeline { display: flex; flex-direction: column; list-style: none; margin: 0; padding: 0; }
1265
+ .uix-timeline { display: flex; flex-direction: column; }
1332
1266
  .uix-timeline__item { display: grid; grid-template-columns: 24px 1fr; gap: var(--uix-space-3); }
1333
1267
  .uix-timeline__rail { display: flex; flex-direction: column; align-items: center; }
1334
1268
  .uix-timeline__node { width: 12px; height: 12px; border-radius: 50%; background: var(--uix-accent); margin-top: var(--uix-space-1); flex: none; box-shadow: 0 0 0 3px var(--uix-brand-muted); }
@@ -1450,9 +1384,7 @@
1450
1384
  @starting-style { .uix-dialog[open]::backdrop { opacity: 0; } }
1451
1385
 
1452
1386
  .uix-dialog__header { display: flex; align-items: center; gap: var(--uix-space-3); padding: var(--uix-space-4) var(--uix-space-5); border-bottom: 1px solid var(--uix-border); }
1453
- /* title is an <h2> for SR navigation (UIX-A11Y-1); inherits neutralize the base h2
1454
- heading font/tracking/leading so it renders exactly like the old <div> */
1455
- .uix-dialog__title { font-size: var(--uix-text-h3); font-weight: 600; font-family: inherit; letter-spacing: inherit; line-height: inherit; }
1387
+ .uix-dialog__title { font-size: var(--uix-text-h3); font-weight: 600; }
1456
1388
  .uix-dialog__close { margin-left: auto; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; width: 30px; height: 30px; display: grid; place-items: center; border-radius: var(--uix-radius-sm); }
1457
1389
  .uix-dialog__close:hover { background: var(--uix-bg-hover); color: var(--uix-text); }
1458
1390
  .uix-dialog__close svg { width: var(--uix-icon-md); height: var(--uix-icon-md); }
@@ -1512,13 +1444,7 @@
1512
1444
  .uix-peek__nav { display: inline-flex; gap: var(--uix-space-1); }
1513
1445
  .uix-peek__navbtn { width: 28px; height: 28px; display: grid; place-items: center; border: 1px solid var(--uix-border); background: var(--uix-surface); color: var(--uix-text); border-radius: var(--uix-radius-sm); cursor: pointer; }
1514
1446
  .uix-peek__navbtn:hover { background: var(--uix-bg-hover); }
1515
- /* boundary nav uses aria-disabled (still focusable, so focus isn't stranded — UIX-A11Y-1);
1516
- mute it and suppress the hover cue like a disabled control */
1517
- .uix-peek__navbtn[aria-disabled="true"] { color: var(--uix-text-muted); cursor: default; }
1518
- .uix-peek__navbtn[aria-disabled="true"]:hover { background: var(--uix-surface); }
1519
- /* title is an <h2> for SR navigation (UIX-A11Y-1); inherits neutralize the base h2
1520
- heading font/tracking/leading so it renders exactly like the old <div> */
1521
- .uix-peek__title { font-size: var(--uix-text-h3); font-weight: 600; font-family: inherit; letter-spacing: inherit; line-height: inherit; }
1447
+ .uix-peek__title { font-size: var(--uix-text-h3); font-weight: 600; }
1522
1448
  .uix-peek__title a { color: var(--uix-link); }
1523
1449
  .uix-peek__close { margin-left: auto; border: 0; background: transparent; color: var(--uix-text-muted); cursor: pointer; width: 30px; height: 30px; display: grid; place-items: center; border-radius: var(--uix-radius-sm); }
1524
1450
  .uix-peek__close:hover { background: var(--uix-bg-hover); color: var(--uix-text); }
@@ -1671,21 +1597,12 @@
1671
1597
  .uix-inbox__list { border-right: 1px solid var(--uix-border); overflow-y: auto; background: var(--uix-surface); }
1672
1598
  .uix-inbox__item { position: relative; display: flex; flex-direction: column; gap: var(--uix-space-1); padding: var(--uix-space-3) var(--uix-space-4); border-bottom: 1px solid var(--uix-border); cursor: pointer; }
1673
1599
  .uix-inbox__item:hover { background: var(--uix-bg-hover); }
1674
- /* keyboard active option (aria-activedescendant) mirrors the hover style (UIX-A11Y-2) */
1675
- .uix-inbox__item[data-active] { background: var(--uix-bg-hover); }
1676
1600
  .uix-inbox__item[aria-selected="true"] { background: linear-gradient(to right, var(--uix-accent) 3px, var(--uix-brand-muted) 3px); }
1677
1601
  .uix-inbox__item[data-unread] .uix-inbox__subject { font-weight: 600; }
1678
1602
  .uix-inbox__subject { font-size: var(--uix-text-body); }
1679
1603
  .uix-inbox__preview { font-size: var(--uix-text-meta); color: var(--uix-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1680
1604
  .uix-inbox__detail { overflow-y: auto; padding: var(--uix-space-5); background: var(--uix-bg-app); }
1681
- /* narrow viewports stack to one pane: list by default, detail when the app sets
1682
- view="detail" — with a consumer-rendered Back control in the detail pane (UIX-A11Y-2) */
1683
- @media (max-width: 700px) {
1684
- .uix-inbox { grid-template-columns: 1fr; }
1685
- .uix-inbox__detail { display: none; }
1686
- .uix-inbox[data-view="detail"] .uix-inbox__list { display: none; }
1687
- .uix-inbox[data-view="detail"] .uix-inbox__detail { display: block; }
1688
- }
1605
+ @media (max-width: 700px) { .uix-inbox { grid-template-columns: 1fr; } .uix-inbox__detail { display: none; } }
1689
1606
  }
1690
1607
  /* uix notification center — depends only on --uix-* tokens. */
1691
1608
  @layer uix.components {
@@ -2077,7 +1994,8 @@
2077
1994
  .uix-section-head { min-height: 36px; margin-bottom: var(--uix-space-3); display: flex; align-items: center; justify-content: space-between; gap: var(--uix-space-4); }
2078
1995
  .uix-section-title { margin: 0; font-family: var(--uix-font-heading); font-size: var(--uix-text-h2); font-weight: 400; letter-spacing: var(--uix-tracking-tight); }
2079
1996
  .uix-section-link { color: var(--uix-text-hushed); font-size: var(--uix-text-meta); text-decoration: none; }
2080
- .uix-section-link:hover { color: var(--uix-text); }
1997
+ /* already a quiet link by its own design — hover/focus parity with link.css */
1998
+ .uix-section-link:is(:hover, :focus-visible) { color: var(--uix-text); text-decoration: underline; }
2081
1999
 
2082
2000
  /* ── content grid + rail ───────────────────────────────────────────────────── */
2083
2001
  .uix-content-grid { display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(280px, 0.75fr); gap: var(--uix-space-7); align-items: start; }
@@ -2181,70 +2099,90 @@
2181
2099
  * noise at list density (TENSOR INTRA-04, operator-rejected).
2182
2100
  *
2183
2101
  * A quiet link inherits the surrounding text colour and shows its underline on
2184
- * hover/focus. 1.4.1 is not in play: the link is the whole text of its block (a title,
2185
- * a cell), not a link inside body copy. NEVER quiet a link inside prose — in-text links
2186
- * keep the base blue + underline.
2102
+ * hover/focus. The global :focus-visible ring (base.css) still fires, so the keyboard
2103
+ * affordance never rests on the underline alone. WCAG 1.4.1 is not in play for anything
2104
+ * below: the link is the WHOLE text of its block — a title, a name, a data cell — or it
2105
+ * is the block itself. It is never a phrase inside a sentence.
2106
+ *
2107
+ * A slot earns quiet-BY-DEFAULT only when BOTH hold:
2108
+ * (i) the anchor fills a named title/name slot or a data cell — the link text IS the
2109
+ * block, not a phrase inside running copy; and
2110
+ * (ii) the surrounding row/card/tile already reads as interactive (hover state, cursor,
2111
+ * bordered unit), or the slot is that record's primary label.
2112
+ *
2113
+ * Deliberate exclusions, so the next person doesn't "finish the job":
2114
+ * • Prose and message bodies — .uix-prose, .uix-note, .uix-notice__copy,
2115
+ * .uix-timeline__body, .uix-audit__detail, .uix-notif copy. Links there sit inside
2116
+ * sentences: 1.4.1 applies and the base treatment is correct.
2117
+ * • .uix-alert, .uix-toast, .uix-peek__title — nothing else in those containers signals
2118
+ * that the link navigates, so the colour IS the affordance. peek.css sets --uix-link
2119
+ * on its title anchor on purpose; do not quiet it.
2120
+ * • .uix-comment__author — a byline renders "Author · 22m ago", so the name is a phrase
2121
+ * inside a text run, not the whole block, and .uix-comment__meta is not interactive.
2122
+ * It fails test (i) above. Products wanting the GitHub-style quiet byline opt in with
2123
+ * .uix-link--quiet; that is what the utility is for.
2124
+ * • .uix-navitem, .uix-breadcrumbs a, .uix-section-link are already quiet by their own
2125
+ * design and need no class here.
2187
2126
  *
2188
- * Two forms:
2189
- * • `.uix-link--quiet` — the opt-in utility, for block links outside the scoped slots
2190
- * (whole-card links, event rows composed by hand, app-specific list patterns).
2191
- * • quiet BY DEFAULT below — the editorial-home title slots and table data cells,
2192
- * where every anchor is a block-level navigation target. `.uix-table td` keeps
2193
- * `:not([class])` so class-bearing anchors in cells (`.uix-btn--link`, pills)
2194
- * stay styled.
2127
+ * Four forms:
2128
+ * 1 · `.uix-link--quiet` — the opt-in utility, for block links outside the registry.
2129
+ * 2 · TITLE / NAME SLOTS — quiet by default. `:not(.uix-btn)` so an anchor deliberately
2130
+ * styled as a button inside a title slot keeps its button treatment.
2131
+ * 3 · DATA CELLS — table cells and description-list values. `:not([class])` so
2132
+ * class-bearing anchors (`.uix-btn--link`, pills, tags) stay styled.
2133
+ * 4 · CONTAINER ANCHORS — the anchor IS the kit block (`<a class="uix-card">`). Without
2134
+ * this the base `a { color }` tints every word in the block brand-blue.
2195
2135
  * Depends only on --uix-* tokens. */
2196
2136
  @layer uix.components {
2197
2137
  .uix-link--quiet,
2198
- .uix-content-list__title a,
2199
- .uix-news-lead__title a,
2200
- .uix-rundown__item-title a,
2201
- .uix-event-row__title a,
2202
- .uix-table td a:not([class]) { color: inherit; text-decoration: none; }
2203
-
2204
- .uix-link--quiet:hover,
2205
- .uix-link--quiet:focus-visible,
2206
- .uix-content-list__title a:hover,
2207
- .uix-content-list__title a:focus-visible,
2208
- .uix-news-lead__title a:hover,
2209
- .uix-news-lead__title a:focus-visible,
2210
- .uix-rundown__item-title a:hover,
2211
- .uix-rundown__item-title a:focus-visible,
2212
- .uix-event-row__title a:hover,
2213
- .uix-event-row__title a:focus-visible,
2214
- .uix-table td a:not([class]):hover,
2215
- .uix-table td a:not([class]):focus-visible { text-decoration: underline; }
2216
- }
2217
- /* forced-colors (WHCM) repairs — last layer so its system-color fixes win over component rules (UIX-A11Y-4) */
2218
- /* uix forced-colors — Windows High Contrast / forced-colors repairs (UIX-A11Y-4).
2219
- Forced-colors mode strips author backgrounds and box-shadows, so controls whose state or
2220
- focus cue rides on those go invisible. Repairs below redraw ONLY those affordances with
2221
- CSS system colors; everything else stays honest to the user's forced palette. Loaded as
2222
- the last layer (see main.css) so these rules win over component declarations. */
2223
- @layer uix.forced-colors {
2224
- @media (forced-colors: active) {
2225
- /* switch — track + thumb are background-only; redraw with system colors */
2226
- .uix-switch__track { border: 1px solid ButtonText; background: Canvas; forced-color-adjust: none; }
2227
- .uix-switch__track::after { background: ButtonText; box-shadow: none; }
2228
- .uix-switch > input:checked + .uix-switch__track { background: SelectedItem; border-color: SelectedItem; }
2229
- .uix-switch > input:checked + .uix-switch__track::after { background: SelectedItemText; }
2230
-
2231
- /* radio — the checked ::after dot is a token background, forced away otherwise */
2232
- .uix-radio > input:checked + .uix-radio__dot::after { background: SelectedItem; forced-color-adjust: none; }
2233
-
2234
- /* checkbox — checked/indeterminate box fill + check glyph */
2235
- .uix-checkbox > input:checked + .uix-checkbox__box,
2236
- .uix-checkbox > input:indeterminate + .uix-checkbox__box {
2237
- background: SelectedItem; border-color: SelectedItem; forced-color-adjust: none;
2238
- }
2239
- .uix-checkbox > input:checked + .uix-checkbox__box svg { color: SelectedItemText; }
2240
-
2241
- /* progress + meter — track and fill are both plain backgrounds */
2242
- .uix-progress, .uix-meter { border: 1px solid ButtonText; }
2243
- .uix-progress__bar, .uix-meter__fill { background: SelectedItem; forced-color-adjust: none; }
2244
2138
 
2245
- /* text fields — components replace the focus outline with a box-shadow ring, which WHCM strips */
2246
- .uix-input:focus-visible, .uix-textarea:focus-visible, .uix-select:focus-visible {
2247
- outline: 2px solid Highlight; outline-offset: 1px;
2248
- }
2249
- }
2139
+ /* 2 · title / name slots */
2140
+ :is(
2141
+ /* editorial-home */
2142
+ .uix-featured__title, .uix-rail-card__title, .uix-news-lead__title,
2143
+ .uix-content-list__title, .uix-rundown__item-title, .uix-event-row__title,
2144
+ .uix-status-row__name,
2145
+ /* records, rows, cards */
2146
+ .uix-card__title, .uix-list__title, .uix-inbox__subject, .uix-kanban__card-title,
2147
+ .uix-media__name, .uix-attachment__name, .uix-contact__name, .uix-user-chip__name,
2148
+ .uix-audit__actor
2149
+ ) a:not(.uix-btn),
2150
+
2151
+ /* 3 · data cells */
2152
+ :is(.uix-table td, .uix-dl dd) a:not([class]),
2153
+
2154
+ /* 4 · container anchors */
2155
+ a:is(
2156
+ .uix-card, .uix-stat, .uix-list__item, .uix-inbox__item, .uix-kanban__card,
2157
+ .uix-notif, .uix-media, .uix-attachment, .uix-contact, .uix-cmdk__item,
2158
+ .uix-content-list__item, .uix-event-row, .uix-status-row
2159
+ ) { color: inherit; text-decoration: none; }
2160
+
2161
+ .uix-link--quiet:is(:hover, :focus-visible),
2162
+
2163
+ :is(
2164
+ .uix-featured__title, .uix-rail-card__title, .uix-news-lead__title,
2165
+ .uix-content-list__title, .uix-rundown__item-title, .uix-event-row__title,
2166
+ .uix-status-row__name,
2167
+ .uix-card__title, .uix-list__title, .uix-inbox__subject, .uix-kanban__card-title,
2168
+ .uix-media__name, .uix-attachment__name, .uix-contact__name, .uix-user-chip__name,
2169
+ .uix-audit__actor
2170
+ ) a:not(.uix-btn):is(:hover, :focus-visible),
2171
+
2172
+ :is(.uix-table td, .uix-dl dd) a:not([class]):is(:hover, :focus-visible) { text-decoration: underline; }
2173
+
2174
+ /* Container anchors never underline: the anchor wraps the whole block, so an underline
2175
+ would strike through every word in it. They take the kit's standard row-hover tint
2176
+ instead — the same --uix-bg-hover that .uix-list__item / .uix-inbox__item / .uix-cmdk__item
2177
+ already use, so containers with a hover of their own just restate it. */
2178
+ a:is(
2179
+ .uix-card, .uix-stat, .uix-list__item, .uix-inbox__item, .uix-kanban__card,
2180
+ .uix-notif, .uix-media, .uix-attachment, .uix-contact, .uix-cmdk__item,
2181
+ .uix-content-list__item, .uix-event-row, .uix-status-row
2182
+ ):is(:hover, :focus-visible) { background: var(--uix-bg-hover); }
2183
+
2184
+ /* Container anchors that declare no display of their own would render inline as an <a>.
2185
+ The rest of form 4 (flex/grid rows) set theirs already and must NOT be overridden —
2186
+ link.css is imported last, so a blanket display here would flatten them. */
2187
+ a:is(.uix-card, .uix-stat, .uix-kanban__card) { display: block; }
2250
2188
  }
@@ -138,19 +138,19 @@
138
138
  --uix-font-sans: "Inter",system-ui,sans-serif;
139
139
  --uix-font-heading: "IBM Plex Sans","Inter",system-ui,sans-serif;
140
140
  --uix-font-mono: "IBM Plex Mono",ui-monospace,monospace;
141
- --uix-text-display: 2.5rem;
141
+ --uix-text-display: 40px;
142
142
  --uix-leading-display: 1.05;
143
- --uix-text-data-hero: 2.125rem;
143
+ --uix-text-data-hero: 34px;
144
144
  --uix-leading-data-hero: 1.1;
145
- --uix-text-h2: 1.5rem;
145
+ --uix-text-h2: 24px;
146
146
  --uix-leading-h2: 1.15;
147
- --uix-text-h3: 0.9375rem;
147
+ --uix-text-h3: 15px;
148
148
  --uix-leading-h3: 1.3;
149
- --uix-text-body: 0.875rem;
149
+ --uix-text-body: 14px;
150
150
  --uix-leading-body: 1.5;
151
- --uix-text-meta: 0.78125rem;
151
+ --uix-text-meta: 12.5px;
152
152
  --uix-leading-meta: 1.4;
153
- --uix-text-eyebrow: 0.6875rem;
153
+ --uix-text-eyebrow: 11px;
154
154
  --uix-leading-eyebrow: 1.2;
155
155
  --uix-tracking-tight: -0.02em;
156
156
  --uix-tracking-eyebrow: 0.06em;
@@ -293,19 +293,19 @@ export const light = {
293
293
  "font-sans": "\"Inter\",system-ui,sans-serif",
294
294
  "font-heading": "\"IBM Plex Sans\",\"Inter\",system-ui,sans-serif",
295
295
  "font-mono": "\"IBM Plex Mono\",ui-monospace,monospace",
296
- "text-display": "2.5rem",
296
+ "text-display": "40px",
297
297
  "leading-display": "1.05",
298
- "text-data-hero": "2.125rem",
298
+ "text-data-hero": "34px",
299
299
  "leading-data-hero": "1.1",
300
- "text-h2": "1.5rem",
300
+ "text-h2": "24px",
301
301
  "leading-h2": "1.15",
302
- "text-h3": "0.9375rem",
302
+ "text-h3": "15px",
303
303
  "leading-h3": "1.3",
304
- "text-body": "0.875rem",
304
+ "text-body": "14px",
305
305
  "leading-body": "1.5",
306
- "text-meta": "0.78125rem",
306
+ "text-meta": "12.5px",
307
307
  "leading-meta": "1.4",
308
- "text-eyebrow": "0.6875rem",
308
+ "text-eyebrow": "11px",
309
309
  "leading-eyebrow": "1.2",
310
310
  "tracking-tight": "-0.02em",
311
311
  "tracking-eyebrow": "0.06em",
@@ -414,4 +414,11 @@ export const num = {
414
414
  "space-10": 64,
415
415
  "space-11": 80,
416
416
  "space-12": 96,
417
+ "text-display": 40,
418
+ "text-data-hero": 34,
419
+ "text-h2": 24,
420
+ "text-h3": 15,
421
+ "text-body": 14,
422
+ "text-meta": 12.5,
423
+ "text-eyebrow": 11,
417
424
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tensor_1/tokens",
3
- "version": "2.10.0",
3
+ "version": "2.11.0",
4
4
  "description": "UIx v2 design tokens — the --uix-* contract for house products (Tensor, POSx, SHOPx). One DTCG source -> CSS variables, Tailwind theme, and typed TS constants.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -3,19 +3,19 @@
3
3
  "font-heading": { "$type": "fontFamily", "$value": "\"IBM Plex Sans\",\"Inter\",system-ui,sans-serif" },
4
4
  "font-mono": { "$type": "fontFamily", "$value": "\"IBM Plex Mono\",ui-monospace,monospace" },
5
5
 
6
- "text-display": { "$type": "dimension", "$value": "2.5rem" },
6
+ "text-display": { "$type": "dimension", "$value": "40px" },
7
7
  "leading-display":{ "$type": "number", "$value": "1.05" },
8
- "text-data-hero": { "$type": "dimension", "$value": "2.125rem" },
8
+ "text-data-hero": { "$type": "dimension", "$value": "34px" },
9
9
  "leading-data-hero": { "$type": "number", "$value": "1.1" },
10
- "text-h2": { "$type": "dimension", "$value": "1.5rem" },
10
+ "text-h2": { "$type": "dimension", "$value": "24px" },
11
11
  "leading-h2":{ "$type": "number", "$value": "1.15" },
12
- "text-h3": { "$type": "dimension", "$value": "0.9375rem" },
12
+ "text-h3": { "$type": "dimension", "$value": "15px" },
13
13
  "leading-h3":{ "$type": "number", "$value": "1.3" },
14
- "text-body": { "$type": "dimension", "$value": "0.875rem" },
14
+ "text-body": { "$type": "dimension", "$value": "14px" },
15
15
  "leading-body":{ "$type": "number", "$value": "1.5" },
16
- "text-meta": { "$type": "dimension", "$value": "0.78125rem" },
16
+ "text-meta": { "$type": "dimension", "$value": "12.5px" },
17
17
  "leading-meta":{ "$type": "number", "$value": "1.4" },
18
- "text-eyebrow": { "$type": "dimension", "$value": "0.6875rem" },
18
+ "text-eyebrow": { "$type": "dimension", "$value": "11px" },
19
19
  "leading-eyebrow":{ "$type": "number", "$value": "1.2" },
20
20
 
21
21
  "tracking-tight": { "$type": "dimension", "$value": "-0.02em" },