@tensor_1/tokens 2.11.0 → 2.12.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.
Files changed (75) hide show
  1. package/README.md +2 -0
  2. package/build/css/components.css +1 -1847
  3. package/build/css/styles.css +1 -2188
  4. package/package.json +12 -2
  5. package/styles/components/alert.css +16 -0
  6. package/styles/components/app-shell.css +37 -0
  7. package/styles/components/attachment.css +10 -0
  8. package/styles/components/audit-log.css +11 -0
  9. package/styles/components/avatar.css +25 -0
  10. package/styles/components/breadcrumbs.css +10 -0
  11. package/styles/components/button.css +49 -0
  12. package/styles/components/calendar.css +13 -0
  13. package/styles/components/card.css +9 -0
  14. package/styles/components/chart.css +9 -0
  15. package/styles/components/checkbox.css +20 -0
  16. package/styles/components/combobox.css +16 -0
  17. package/styles/components/command-palette.css +14 -0
  18. package/styles/components/comments.css +17 -0
  19. package/styles/components/contact-card.css +12 -0
  20. package/styles/components/description-list.css +6 -0
  21. package/styles/components/detail-layout.css +7 -0
  22. package/styles/components/drawer.css +24 -0
  23. package/styles/components/editorial-home.css +185 -0
  24. package/styles/components/file-upload.css +14 -0
  25. package/styles/components/flow.css +196 -0
  26. package/styles/components/form.css +14 -0
  27. package/styles/components/heartbeat.css +12 -0
  28. package/styles/components/inbox.css +13 -0
  29. package/styles/components/input.css +39 -0
  30. package/styles/components/kanban.css +14 -0
  31. package/styles/components/kbd.css +8 -0
  32. package/styles/components/labels.css +13 -0
  33. package/styles/components/lightbox.css +13 -0
  34. package/styles/components/link.css +98 -0
  35. package/styles/components/list.css +10 -0
  36. package/styles/components/media.css +9 -0
  37. package/styles/components/menu.css +15 -0
  38. package/styles/components/meter.css +9 -0
  39. package/styles/components/modal.css +31 -0
  40. package/styles/components/notification-center.css +14 -0
  41. package/styles/components/page-header.css +9 -0
  42. package/styles/components/pagination.css +14 -0
  43. package/styles/components/peek.css +46 -0
  44. package/styles/components/pipeline.css +9 -0
  45. package/styles/components/popover.css +11 -0
  46. package/styles/components/progress.css +12 -0
  47. package/styles/components/prose.css +27 -0
  48. package/styles/components/radio.css +20 -0
  49. package/styles/components/reactions.css +22 -0
  50. package/styles/components/segmented.css +12 -0
  51. package/styles/components/select.css +23 -0
  52. package/styles/components/sidebar.css +102 -0
  53. package/styles/components/sla.css +8 -0
  54. package/styles/components/slider.css +16 -0
  55. package/styles/components/spinner.css +10 -0
  56. package/styles/components/stat-tile.css +11 -0
  57. package/styles/components/states.css +13 -0
  58. package/styles/components/status-pill.css +37 -0
  59. package/styles/components/stepper.css +13 -0
  60. package/styles/components/steps.css +18 -0
  61. package/styles/components/switch.css +19 -0
  62. package/styles/components/table-toolbar.css +20 -0
  63. package/styles/components/table.css +160 -0
  64. package/styles/components/tabs.css +31 -0
  65. package/styles/components/tag-input.css +16 -0
  66. package/styles/components/textarea.css +15 -0
  67. package/styles/components/timeline.css +11 -0
  68. package/styles/components/toast.css +21 -0
  69. package/styles/components/tooltip.css +35 -0
  70. package/styles/components/tree.css +17 -0
  71. package/styles/components/typography.css +45 -0
  72. package/styles/components/utility-bits.css +14 -0
  73. package/styles/components/view-menu.css +14 -0
  74. package/styles/motion.css +35 -0
  75. package/styles/utilities.css +26 -0
@@ -0,0 +1,196 @@
1
+ /* uix flow — workflow & pipeline diagrams: boxed nodes + connectors.
2
+ Depends only on --uix-* tokens. Edges are decorative inline SVG (aria-hidden);
3
+ straight runs use pure-CSS connectors. Node state follows the tone-API pattern
4
+ (see status-pill.css): state --modifiers set only --tone-* vars, the base reads them. */
5
+ @layer uix.components {
6
+
7
+ /* ============================================================ node */
8
+ .uix-node {
9
+ position: relative;
10
+ display: inline-grid; grid-template-columns: auto 1fr; align-items: center;
11
+ gap: var(--uix-space-3); min-width: 132px; width: max-content; max-width: 220px; padding: var(--uix-space-3) var(--uix-space-3);
12
+ background: var(--uix-surface);
13
+ border: 1px solid var(--tone-border, var(--uix-border-strong));
14
+ border-radius: var(--uix-radius-md);
15
+ box-shadow: var(--uix-shadow-sm);
16
+ color: var(--uix-text); font-size: var(--uix-text-body); text-align: left;
17
+ }
18
+ .uix-node__icon {
19
+ display: grid; place-items: center; width: 30px; height: 30px; flex: none;
20
+ border-radius: var(--uix-radius-sm);
21
+ background: var(--tone-bg, var(--uix-bg-subtle));
22
+ color: var(--tone-fg, var(--uix-text-muted));
23
+ }
24
+ .uix-node__icon svg { width: var(--uix-icon-sm); height: var(--uix-icon-sm); }
25
+ .uix-node__body { min-width: 0; }
26
+ .uix-node__title { font-weight: 500; line-height: 1.25; }
27
+ .uix-node__meta { font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
28
+ .uix-node__status {
29
+ display: inline-flex; align-items: center; gap: var(--uix-space-2); margin-top: var(--uix-space-1);
30
+ font-size: var(--uix-text-eyebrow); letter-spacing: var(--uix-tracking-eyebrow);
31
+ text-transform: uppercase; color: var(--tone-fg, var(--uix-text-muted));
32
+ }
33
+ .uix-node__status::before {
34
+ content: ""; width: 7px; height: 7px; flex: none; border-radius: 50%;
35
+ background: var(--tone-dot, var(--uix-text-muted));
36
+ }
37
+
38
+ /* connection handles — decorative connection-point affordance */
39
+ .uix-node__handle {
40
+ position: absolute; top: 50%; width: 9px; height: 9px; border-radius: 50%;
41
+ background: var(--uix-surface); border: 1.5px solid var(--uix-border-strong);
42
+ transform: translateY(-50%);
43
+ }
44
+ .uix-node__handle--in { left: -5px; }
45
+ .uix-node__handle--out { right: -5px; }
46
+
47
+ /* ---- state modifiers: set tone vars only ---- */
48
+ .uix-node--pending { --tone-bg: var(--uix-bg-subtle); --tone-fg: var(--uix-text-muted); --tone-dot: var(--uix-text-muted); --tone-border: var(--uix-border); }
49
+ .uix-node--active { --tone-bg: var(--uix-brand-muted); --tone-fg: var(--uix-link); --tone-dot: var(--uix-accent); --tone-border: var(--uix-accent); }
50
+ .uix-node--running { --tone-bg: var(--uix-info-bg); --tone-fg: var(--uix-info-text); --tone-dot: var(--uix-info); --tone-border: var(--uix-info); }
51
+ .uix-node--done { --tone-bg: var(--uix-success-bg); --tone-fg: var(--uix-success); --tone-dot: var(--uix-success); --tone-border: var(--uix-success); }
52
+ .uix-node--error { --tone-bg: var(--uix-danger-bg); --tone-fg: var(--uix-danger-text); --tone-dot: var(--uix-danger); --tone-border: var(--uix-danger); }
53
+ /* active/running read as "current" via a soft halo in their own tone */
54
+ .uix-node--active, .uix-node--running { box-shadow: var(--uix-shadow-sm), 0 0 0 3px var(--tone-bg); }
55
+
56
+ /* running node spins its icon */
57
+ .uix-node--running .uix-node__icon svg { animation: uix-flow-spin 1s linear infinite; }
58
+
59
+ /* ---- decision / diamond ---- */
60
+ .uix-node--decision {
61
+ min-width: 0; width: 112px; height: 112px; padding: 0; overflow: visible;
62
+ /* reset the base node's `auto 1fr` columns to one full-width track, else the lone title is
63
+ trapped in the left `auto` column and place-items:center can't center it over the diamond. */
64
+ display: grid; grid-template-columns: 1fr; place-items: center; background: transparent; border: 0; box-shadow: none;
65
+ }
66
+ .uix-node--decision::before {
67
+ content: ""; position: absolute; left: 50%; top: 50%; width: 78px; height: 78px;
68
+ transform: translate(-50%, -50%) rotate(45deg);
69
+ background: var(--tone-bg, var(--uix-surface));
70
+ border: 1px solid var(--tone-border, var(--uix-border-strong));
71
+ border-radius: var(--uix-radius-sm); box-shadow: var(--uix-shadow-sm);
72
+ }
73
+ .uix-node--decision .uix-node__title {
74
+ position: relative; z-index: var(--uix-z-raised); max-width: 88px; text-align: center;
75
+ font-size: var(--uix-text-meta); color: var(--tone-fg, var(--uix-text));
76
+ }
77
+
78
+ /* ---- start / end terminals (pills) ---- */
79
+ .uix-node--start, .uix-node--end {
80
+ grid-template-columns: 1fr; min-width: 0; justify-items: center;
81
+ padding: var(--uix-space-2) var(--uix-space-5); border-radius: var(--uix-radius-pill);
82
+ background: var(--uix-bg-active); color: var(--uix-text-hushed); font-weight: 500;
83
+ }
84
+
85
+ /* ============================================================ flow + edges */
86
+ .uix-flow {
87
+ position: relative; width: 100%;
88
+ color: var(--uix-border-strong); /* edges inherit via currentColor */
89
+ }
90
+ .uix-flow__edges {
91
+ position: absolute; inset: 0; width: 100%; height: 100%;
92
+ overflow: visible; pointer-events: none; /* never block node hover/focus */
93
+ }
94
+ .uix-flow__edge { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; }
95
+ .uix-flow__edge--branch-yes { stroke: var(--uix-success); }
96
+ .uix-flow__edge--branch-no { stroke: var(--uix-danger); }
97
+ .uix-flow__edge--loop { stroke: var(--uix-accent); stroke-dasharray: 5 4; }
98
+ .uix-flow__arrow { fill: currentColor; }
99
+ .uix-flow__edge-label { fill: var(--uix-text-muted); font-family: var(--uix-font-sans); font-size: var(--uix-text-eyebrow); }
100
+ .uix-flow__edge-label--loop { fill: var(--uix-accent); }
101
+
102
+ /* hovering/focusing a diagram sets its edges "flowing" (marching dashes) to read direction */
103
+ @media (hover: hover) and (pointer: fine) {
104
+ .uix-flow:hover .uix-flow__edge,
105
+ .uix-flow:focus-within .uix-flow__edge {
106
+ stroke-dasharray: 5 4; animation: uix-flow-march var(--uix-dur-slow) linear infinite;
107
+ }
108
+ }
109
+
110
+ /* ---- linear: flex row of nodes + pure-CSS connectors (no SVG) ---- */
111
+ .uix-flow--linear .uix-flow__row { display: flex; align-items: center; flex-wrap: wrap; gap: var(--uix-space-1); }
112
+ .uix-flow__connector {
113
+ position: relative; flex: 1 1 30px; min-width: 30px; height: 0;
114
+ border-top: 1.5px solid var(--uix-border-strong); margin: 0 var(--uix-space-1);
115
+ }
116
+ .uix-flow__connector::after {
117
+ content: ""; position: absolute; right: -1px; top: 50%; width: 6px; height: 6px;
118
+ border-top: 1.5px solid var(--uix-border-strong); border-right: 1.5px solid var(--uix-border-strong);
119
+ transform: translate(0, -50%) rotate(45deg);
120
+ }
121
+ .uix-flow__connector[data-done] { border-color: var(--uix-success); }
122
+ .uix-flow__connector[data-done]::after { border-color: var(--uix-success); }
123
+
124
+ /* ---- branch / loop / mindmap: absolutely-positioned nodes over an SVG edge layer.
125
+ Container aspect-ratio matches each SVG viewBox so % node positions and path
126
+ coordinates scale together (uniform), keeping edges glued to nodes at any width. */
127
+ .uix-flow--branch, .uix-flow--loop { aspect-ratio: 5 / 2; }
128
+ .uix-flow--mindmap { aspect-ratio: 2 / 1; }
129
+ .uix-flow--branch .uix-node,
130
+ .uix-flow--loop .uix-node,
131
+ .uix-flow--mindmap .uix-node,
132
+ .uix-flow--canvas .uix-node { position: absolute; transform: translate(-50%, -50%); }
133
+
134
+ /* mindmap leaves sit tighter than default nodes */
135
+ .uix-flow--mindmap .uix-node { min-width: 0; }
136
+ .uix-flow--mindmap .uix-node--hub { min-width: 120px; }
137
+
138
+ /* ============================================================ builder canvas */
139
+ .uix-flow--canvas {
140
+ display: grid; grid-template-columns: 188px 1fr;
141
+ border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg);
142
+ overflow: hidden; background: var(--uix-surface); width: 100%;
143
+ }
144
+ .uix-flow__palette {
145
+ display: flex; flex-direction: column; gap: var(--uix-space-2); padding: var(--uix-space-4);
146
+ border-right: 1px solid var(--uix-border); background: var(--uix-surface);
147
+ }
148
+ .uix-flow__palette-title {
149
+ font-size: var(--uix-text-eyebrow); letter-spacing: var(--uix-tracking-eyebrow);
150
+ text-transform: uppercase; color: var(--uix-text-muted); margin-bottom: var(--uix-space-1);
151
+ }
152
+ .uix-flow__chip {
153
+ display: flex; align-items: center; gap: var(--uix-space-2); padding: var(--uix-space-2) var(--uix-space-3);
154
+ border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md);
155
+ background: var(--uix-surface); color: var(--uix-text);
156
+ font-size: var(--uix-text-meta); cursor: grab; box-shadow: var(--uix-shadow-sm);
157
+ transition: box-shadow var(--uix-dur-fast) var(--uix-ease-out),
158
+ transform var(--uix-dur-fast) var(--uix-ease-out);
159
+ }
160
+ .uix-flow__chip svg { width: var(--uix-icon-sm); height: var(--uix-icon-sm); color: var(--uix-text-muted); flex: none; }
161
+ .uix-flow__chip:active { cursor: grabbing; }
162
+ @media (hover: hover) and (pointer: fine) {
163
+ .uix-flow__chip:hover { box-shadow: var(--uix-shadow-popover); transform: translateY(calc(-1 * var(--uix-lift))); }
164
+ }
165
+ /* the canvas: a dotted grid, free-placed nodes, one SVG edge layer */
166
+ .uix-flow__canvas {
167
+ position: relative; aspect-ratio: 16 / 9; min-height: 280px;
168
+ background-color: var(--uix-bg-subtle);
169
+ background-image: radial-gradient(var(--uix-border-strong) 1px, transparent 1px);
170
+ background-size: 22px 22px; background-position: -1px -1px;
171
+ }
172
+ .uix-flow--canvas .uix-node { cursor: grab; }
173
+ .uix-flow--canvas .uix-node:active { cursor: grabbing; }
174
+
175
+ /* selected node ring — mirrors the focus-ring construction (double box-shadow on --uix-ring) */
176
+ .uix-flow .uix-node[data-selected] {
177
+ border-color: var(--uix-ring);
178
+ box-shadow: 0 0 0 2px var(--uix-surface), 0 0 0 4px var(--uix-ring);
179
+ }
180
+ /* keyboard/click selection on focusable canvas pieces — no JS needed */
181
+ .uix-flow__chip:focus-visible,
182
+ .uix-flow--canvas .uix-node:focus-visible {
183
+ outline: none; border-color: var(--uix-ring);
184
+ box-shadow: 0 0 0 2px var(--uix-surface), 0 0 0 4px var(--uix-ring);
185
+ }
186
+
187
+ /* ============================================================ motion */
188
+ @keyframes uix-flow-spin { to { transform: rotate(360deg); } }
189
+ @keyframes uix-flow-march { to { stroke-dashoffset: -18; } }
190
+
191
+ @media (prefers-reduced-motion: reduce) {
192
+ .uix-node--running .uix-node__icon svg,
193
+ .uix-flow:hover .uix-flow__edge,
194
+ .uix-flow:focus-within .uix-flow__edge { animation: none; }
195
+ }
196
+ }
@@ -0,0 +1,14 @@
1
+ /* uix form layout — depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--uix-space-5); }
4
+ .uix-fieldset { border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); padding: var(--uix-space-6); }
5
+ .uix-fieldset > legend { padding: 0 var(--uix-space-2); font-size: var(--uix-text-meta); font-weight: 600; color: var(--uix-text); }
6
+ .uix-form-inline { display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--uix-space-4); }
7
+ .uix-validation-summary {
8
+ border: 1px solid var(--uix-danger); background: var(--uix-danger-bg); color: var(--uix-text);
9
+ border-radius: var(--uix-radius-md); padding: var(--uix-space-3) var(--uix-space-4); font-size: var(--uix-text-meta);
10
+ }
11
+ .uix-validation-summary strong { color: var(--uix-danger-text); }
12
+ .uix-validation-summary ul { margin: var(--uix-space-2) 0 0; padding-left: var(--uix-space-5); }
13
+ .uix-validation-summary a { color: var(--uix-danger-text); text-decoration: underline; }
14
+ }
@@ -0,0 +1,12 @@
1
+ /* uix heartbeat / live status indicator — a pulsing ping. Respects reduced-motion (guard stops the ping). */
2
+ @layer uix.components {
3
+ .uix-heartbeat { position: relative; display: inline-grid; place-items: center; width: 8px; height: 8px; flex: none; }
4
+ .uix-heartbeat__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--uix-success); z-index: var(--uix-z-raised); }
5
+ .uix-heartbeat__ping { position: absolute; inset: 0; border-radius: 50%; background: var(--uix-success); animation: uix-ping 1.6s var(--uix-ease-out) infinite; }
6
+ @keyframes uix-ping { 0% { transform: scale(1); opacity: .55; } 100% { transform: scale(2.8); opacity: 0; } }
7
+ .uix-heartbeat--warning .uix-heartbeat__dot, .uix-heartbeat--warning .uix-heartbeat__ping { background: var(--uix-warning); }
8
+ .uix-heartbeat--danger .uix-heartbeat__dot, .uix-heartbeat--danger .uix-heartbeat__ping { background: var(--uix-danger); }
9
+ .uix-heartbeat--idle .uix-heartbeat__dot { background: var(--uix-text-muted); }
10
+ .uix-heartbeat--idle .uix-heartbeat__ping { display: none; }
11
+ .uix-live { display: inline-flex; align-items: center; gap: var(--uix-space-2); font-size: var(--uix-text-meta); font-weight: 500; color: var(--uix-text-hushed); }
12
+ }
@@ -0,0 +1,13 @@
1
+ /* uix inbox master-detail — depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-inbox { display: grid; grid-template-columns: 300px 1fr; border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); overflow: hidden; height: 420px; }
4
+ .uix-inbox__list { border-right: 1px solid var(--uix-border); overflow-y: auto; background: var(--uix-surface); }
5
+ .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; }
6
+ .uix-inbox__item:hover { background: var(--uix-bg-hover); }
7
+ .uix-inbox__item[aria-selected="true"] { background: linear-gradient(to right, var(--uix-accent) 3px, var(--uix-brand-muted) 3px); }
8
+ .uix-inbox__item[data-unread] .uix-inbox__subject { font-weight: 600; }
9
+ .uix-inbox__subject { font-size: var(--uix-text-body); }
10
+ .uix-inbox__preview { font-size: var(--uix-text-meta); color: var(--uix-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
11
+ .uix-inbox__detail { overflow-y: auto; padding: var(--uix-space-5); background: var(--uix-bg-app); }
12
+ @media (max-width: 700px) { .uix-inbox { grid-template-columns: 1fr; } .uix-inbox__detail { display: none; } }
13
+ }
@@ -0,0 +1,39 @@
1
+ /* uix input + field wrapper — depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-field { display: flex; flex-direction: column; gap: var(--uix-space-2); }
4
+ .uix-field__label { font-size: var(--uix-text-meta); font-weight: 500; color: var(--uix-text); }
5
+ .uix-field__label[data-required]::after { content: " *"; color: var(--uix-danger-text); }
6
+ /* message slot for hint / error / success — reserves one line so an appearing error never
7
+ shifts the layout (UIX-FIX-04); the React <Field> always renders it. */
8
+ .uix-field__msg { font-size: var(--uix-text-meta); line-height: 1.45; min-height: 1.45em; }
9
+ .uix-field__hint { font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
10
+ .uix-field__error { font-size: var(--uix-text-meta); color: var(--uix-danger-text); display: inline-flex; align-items: center; gap: var(--uix-space-2); }
11
+ .uix-field__error svg, .uix-field__success svg { width: 14px; height: 14px; flex: none; }
12
+ .uix-field__success { font-size: var(--uix-text-meta); color: var(--uix-success); display: inline-flex; align-items: center; gap: var(--uix-space-2); }
13
+
14
+ .uix-input {
15
+ height: var(--uix-control-h); width: 100%;
16
+ padding: 0 var(--uix-space-3); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md);
17
+ background: var(--uix-surface); color: var(--uix-text); font: inherit; font-size: var(--uix-text-body);
18
+ transition: border-color var(--uix-dur-fast) var(--uix-ease-out), box-shadow var(--uix-dur-fast) var(--uix-ease-out);
19
+ }
20
+ .uix-input::placeholder { color: var(--uix-text-muted); }
21
+ .uix-input:hover { border-color: var(--uix-border-strong); }
22
+ .uix-input:focus { outline: none; border-color: var(--uix-ring); box-shadow: 0 0 0 3px var(--uix-brand-muted); }
23
+ .uix-input:disabled { opacity: .55; cursor: not-allowed; background: var(--uix-bg-subtle); }
24
+ .uix-input[readonly] { background: var(--uix-bg-subtle); }
25
+ .uix-input[aria-invalid="true"] { border-color: var(--uix-danger); }
26
+ .uix-input[aria-invalid="true"]:focus { box-shadow: 0 0 0 3px var(--uix-danger-bg); }
27
+ .uix-input--sm { height: 28px; font-size: var(--uix-text-meta); }
28
+
29
+ /* leading/trailing adornments */
30
+ .uix-input-group { position: relative; display: flex; align-items: center; }
31
+ .uix-input-group__icon { position: absolute; left: 10px; color: var(--uix-text-muted); display: inline-flex; pointer-events: none; }
32
+ .uix-input-group__icon svg { width: var(--uix-icon-md); height: var(--uix-icon-md); }
33
+ .uix-input-group--has-leading .uix-input { padding-left: 38px; }
34
+ /* validation microinteractions */
35
+ .uix-input[data-valid] { border-color: var(--uix-success); }
36
+ .uix-input[data-valid]:focus { box-shadow: 0 0 0 3px var(--uix-success-bg); }
37
+ .uix-input-group--has-trailing .uix-input { padding-right: 38px; }
38
+ .uix-input-group__icon--trailing { left: auto; right: 10px; }
39
+ }
@@ -0,0 +1,14 @@
1
+ /* uix kanban board / column — depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-kanban { display: flex; gap: var(--uix-space-4); overflow-x: auto; padding-bottom: var(--uix-space-2); }
4
+ .uix-kanban__col { flex: 0 0 260px; background: var(--uix-bg-subtle); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); display: flex; flex-direction: column; max-height: 460px; }
5
+ .uix-kanban__head { display: flex; align-items: center; gap: var(--uix-space-2); padding: var(--uix-space-3) var(--uix-space-4); font-weight: 600; font-size: var(--uix-text-meta); }
6
+ .uix-kanban__count { margin-left: auto; color: var(--uix-text-muted); font-weight: 500; }
7
+ .uix-kanban__body { padding: 0 var(--uix-space-3) var(--uix-space-3); display: flex; flex-direction: column; gap: var(--uix-space-2); overflow-y: auto; }
8
+ .uix-kanban__card { background: var(--uix-surface); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md); padding: var(--uix-space-3); box-shadow: var(--uix-shadow-sm); cursor: grab; transition: box-shadow var(--uix-dur-fast) var(--uix-ease-out), transform var(--uix-dur-fast) var(--uix-ease-out); }
9
+ .uix-kanban__card:hover { box-shadow: var(--uix-shadow-popover); }
10
+ @media (hover: hover) and (pointer: fine) { .uix-kanban__card:hover { transform: translateY(calc(-1 * var(--uix-lift))); } }
11
+ .uix-kanban__card:active { cursor: grabbing; }
12
+ .uix-kanban__card-title { font-weight: 500; font-size: var(--uix-text-body); margin-bottom: var(--uix-space-2); }
13
+ .uix-kanban__card-meta { display: flex; align-items: center; gap: var(--uix-space-2); }
14
+ }
@@ -0,0 +1,8 @@
1
+ /* uix keyboard-shortcut chip — depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-kbd {
4
+ display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 var(--uix-space-2);
5
+ font-family: var(--uix-font-mono); font-size: var(--uix-text-eyebrow); color: var(--uix-text-muted);
6
+ background: var(--uix-bg-subtle); border: 1px solid var(--uix-border); border-bottom-width: 2px; border-radius: var(--uix-radius-xs);
7
+ }
8
+ }
@@ -0,0 +1,13 @@
1
+ /* uix label / tag taxonomy — colored via --label-color (set to a --uix-chart-* token). */
2
+ @layer uix.components {
3
+ .uix-label {
4
+ display: inline-flex; align-items: center; gap: var(--uix-space-2); padding: 1px var(--uix-space-2); border-radius: var(--uix-radius-sm);
5
+ font-size: var(--uix-text-meta); font-weight: 500;
6
+ background: color-mix(in srgb, var(--label-color, var(--uix-accent)) 16%, transparent);
7
+ /* Pull the hue toward the theme foreground so the text clears WCAG AA on its own 16% tint.
8
+ Raw chart hues (esp. amber #F59E0B at 1.9:1) are tuned for fills, not text-on-tint; the dot
9
+ keeps the full hue. --uix-text flips per theme, so this darkens on light and lightens on dark. */
10
+ color: color-mix(in srgb, var(--label-color, var(--uix-accent)) 55%, var(--uix-text));
11
+ }
12
+ .uix-label__dot { width: 7px; height: 7px; border-radius: 50%; background: var(--label-color, var(--uix-accent)); }
13
+ }
@@ -0,0 +1,13 @@
1
+ /* uix image lightbox — native <dialog>, click a thumbnail to enlarge. Depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ /* margin:auto centers the modal <dialog> in the viewport. Set explicitly (not
4
+ left to the UA default) so centering is robust regardless of any consumer
5
+ reset — base.css scopes its margin reset to typographic/form elements and
6
+ deliberately leaves <dialog> alone. Matches .uix-dialog. */
7
+ .uix-lightbox { margin: auto; border: 0; background: transparent; padding: 0; max-width: 92vw; max-height: 92vh; box-shadow: var(--uix-shadow-overlay); overflow: visible; }
8
+ /* A definite width is required: an SVG with a viewBox but no intrinsic width/height collapses to
9
+ 0×0 under width:auto, which then shrink-wraps the fit-content <dialog> to nothing (nothing shows
10
+ on open). min() keeps it within the viewport; height:auto preserves the aspect ratio. */
11
+ .uix-lightbox img { display: block; width: min(720px, 92vw); height: auto; max-height: 92vh; border-radius: var(--uix-radius-md); }
12
+ .uix-lightbox::backdrop { background: var(--uix-scrim-strong); }
13
+ }
@@ -0,0 +1,98 @@
1
+ /* uix link patterns — the quiet link, for anchors whose CONTAINER is the affordance.
2
+ *
3
+ * The base layer styles anchors as in-text content links: --uix-link colour, and
4
+ * classless [href] anchors carry a persistent underline (WCAG 1.4.1 / link-in-text-block —
5
+ * a link sitting inside a run of same-coloured prose must not be distinguished by colour
6
+ * alone). That contract is right for prose and wrong for composition slots where the
7
+ * surrounding row/card already communicates interactivity: framework <Link>s passed into
8
+ * kit title slots and table cells rendered brand-blue + bold + underlined — unreadable
9
+ * noise at list density (TENSOR INTRA-04, operator-rejected).
10
+ *
11
+ * A quiet link inherits the surrounding text colour and shows its underline on
12
+ * hover/focus. The global :focus-visible ring (base.css) still fires, so the keyboard
13
+ * affordance never rests on the underline alone. WCAG 1.4.1 is not in play for anything
14
+ * below: the link is the WHOLE text of its block — a title, a name, a data cell — or it
15
+ * is the block itself. It is never a phrase inside a sentence.
16
+ *
17
+ * A slot earns quiet-BY-DEFAULT only when BOTH hold:
18
+ * (i) the anchor fills a named title/name slot or a data cell — the link text IS the
19
+ * block, not a phrase inside running copy; and
20
+ * (ii) the surrounding row/card/tile already reads as interactive (hover state, cursor,
21
+ * bordered unit), or the slot is that record's primary label.
22
+ *
23
+ * Deliberate exclusions, so the next person doesn't "finish the job":
24
+ * • Prose and message bodies — .uix-prose, .uix-note, .uix-notice__copy,
25
+ * .uix-timeline__body, .uix-audit__detail, .uix-notif copy. Links there sit inside
26
+ * sentences: 1.4.1 applies and the base treatment is correct.
27
+ * • .uix-alert, .uix-toast, .uix-peek__title — nothing else in those containers signals
28
+ * that the link navigates, so the colour IS the affordance. peek.css sets --uix-link
29
+ * on its title anchor on purpose; do not quiet it.
30
+ * • .uix-comment__author — a byline renders "Author · 22m ago", so the name is a phrase
31
+ * inside a text run, not the whole block, and .uix-comment__meta is not interactive.
32
+ * It fails test (i) above. Products wanting the GitHub-style quiet byline opt in with
33
+ * .uix-link--quiet; that is what the utility is for.
34
+ * • .uix-navitem, .uix-breadcrumbs a, .uix-section-link are already quiet by their own
35
+ * design and need no class here.
36
+ *
37
+ * Four forms:
38
+ * 1 · `.uix-link--quiet` — the opt-in utility, for block links outside the registry.
39
+ * 2 · TITLE / NAME SLOTS — quiet by default. `:not(.uix-btn)` so an anchor deliberately
40
+ * styled as a button inside a title slot keeps its button treatment.
41
+ * 3 · DATA CELLS — table cells and description-list values. `:not([class])` so
42
+ * class-bearing anchors (`.uix-btn--link`, pills, tags) stay styled.
43
+ * 4 · CONTAINER ANCHORS — the anchor IS the kit block (`<a class="uix-card">`). Without
44
+ * this the base `a { color }` tints every word in the block brand-blue.
45
+ * Depends only on --uix-* tokens. */
46
+ @layer uix.components {
47
+ .uix-link--quiet,
48
+
49
+ /* 2 · title / name slots */
50
+ :is(
51
+ /* editorial-home */
52
+ .uix-featured__title, .uix-rail-card__title, .uix-news-lead__title,
53
+ .uix-content-list__title, .uix-rundown__item-title, .uix-event-row__title,
54
+ .uix-status-row__name,
55
+ /* records, rows, cards */
56
+ .uix-card__title, .uix-list__title, .uix-inbox__subject, .uix-kanban__card-title,
57
+ .uix-media__name, .uix-attachment__name, .uix-contact__name, .uix-user-chip__name,
58
+ .uix-audit__actor
59
+ ) a:not(.uix-btn),
60
+
61
+ /* 3 · data cells */
62
+ :is(.uix-table td, .uix-dl dd) a:not([class]),
63
+
64
+ /* 4 · container anchors */
65
+ a:is(
66
+ .uix-card, .uix-stat, .uix-list__item, .uix-inbox__item, .uix-kanban__card,
67
+ .uix-notif, .uix-media, .uix-attachment, .uix-contact, .uix-cmdk__item,
68
+ .uix-content-list__item, .uix-event-row, .uix-status-row
69
+ ) { color: inherit; text-decoration: none; }
70
+
71
+ .uix-link--quiet:is(:hover, :focus-visible),
72
+
73
+ :is(
74
+ .uix-featured__title, .uix-rail-card__title, .uix-news-lead__title,
75
+ .uix-content-list__title, .uix-rundown__item-title, .uix-event-row__title,
76
+ .uix-status-row__name,
77
+ .uix-card__title, .uix-list__title, .uix-inbox__subject, .uix-kanban__card-title,
78
+ .uix-media__name, .uix-attachment__name, .uix-contact__name, .uix-user-chip__name,
79
+ .uix-audit__actor
80
+ ) a:not(.uix-btn):is(:hover, :focus-visible),
81
+
82
+ :is(.uix-table td, .uix-dl dd) a:not([class]):is(:hover, :focus-visible) { text-decoration: underline; }
83
+
84
+ /* Container anchors never underline: the anchor wraps the whole block, so an underline
85
+ would strike through every word in it. They take the kit's standard row-hover tint
86
+ instead — the same --uix-bg-hover that .uix-list__item / .uix-inbox__item / .uix-cmdk__item
87
+ already use, so containers with a hover of their own just restate it. */
88
+ a:is(
89
+ .uix-card, .uix-stat, .uix-list__item, .uix-inbox__item, .uix-kanban__card,
90
+ .uix-notif, .uix-media, .uix-attachment, .uix-contact, .uix-cmdk__item,
91
+ .uix-content-list__item, .uix-event-row, .uix-status-row
92
+ ):is(:hover, :focus-visible) { background: var(--uix-bg-hover); }
93
+
94
+ /* Container anchors that declare no display of their own would render inline as an <a>.
95
+ The rest of form 4 (flex/grid rows) set theirs already and must NOT be overridden —
96
+ link.css is imported last, so a blanket display here would flatten them. */
97
+ a:is(.uix-card, .uix-stat, .uix-kanban__card) { display: block; }
98
+ }
@@ -0,0 +1,10 @@
1
+ /* uix list + list-item — depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-list { display: flex; flex-direction: column; border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); overflow: hidden; background: var(--uix-surface); }
4
+ .uix-list__item { 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); }
5
+ .uix-list__item:last-child { border-bottom: 0; }
6
+ .uix-list__item:hover { background: var(--uix-bg-hover); }
7
+ .uix-list__title { font-weight: 500; }
8
+ .uix-list__meta { font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
9
+ .uix-list__trail { margin-left: auto; display: flex; align-items: center; gap: var(--uix-space-2); }
10
+ }
@@ -0,0 +1,9 @@
1
+ /* uix media / device-asset card — image (or icon placeholder) + name + meta. Depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-media { display: flex; gap: var(--uix-space-3); align-items: center; }
4
+ .uix-media__thumb { width: 64px; height: 64px; flex: none; border-radius: var(--uix-radius-md); overflow: hidden; background: var(--uix-bg-subtle); border: 1px solid var(--uix-border); display: grid; place-items: center; }
5
+ .uix-media__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
6
+ .uix-media__thumb svg { width: 28px; height: 28px; color: var(--uix-text-muted); }
7
+ .uix-media__name { font-weight: 600; }
8
+ .uix-media__meta { font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
9
+ }
@@ -0,0 +1,15 @@
1
+ /* uix menu / dropdown / context menu — popover-anchored surface. Depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-menu { min-width: 200px; margin: 0; padding: var(--uix-space-1); list-style: none; background: var(--uix-surface-2); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md); box-shadow: var(--uix-shadow-popover); }
4
+ .uix-menu__item {
5
+ display: flex; align-items: center; gap: var(--uix-space-3); width: 100%; text-align: left; padding: var(--uix-space-2) var(--uix-space-3);
6
+ border: 0; background: transparent; border-radius: var(--uix-radius-sm); color: var(--uix-text); font: inherit; font-size: var(--uix-text-body); cursor: pointer;
7
+ }
8
+ .uix-menu__item svg { width: var(--uix-icon-md); height: var(--uix-icon-md); color: var(--uix-text-muted); }
9
+ .uix-menu__item:hover, .uix-menu__item[data-active] { background: var(--uix-bg-hover); }
10
+ .uix-menu__item--danger { color: var(--uix-danger-text); }
11
+ .uix-menu__item--danger svg { color: var(--uix-danger-text); }
12
+ .uix-menu__item .uix-kbd { margin-left: auto; }
13
+ .uix-menu__sep { height: 1px; background: var(--uix-border); margin: var(--uix-space-1) 0; }
14
+ .uix-menu__label { 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); }
15
+ }
@@ -0,0 +1,9 @@
1
+ /* uix meter / utilization bar (threshold tones) — depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-meter { height: 8px; background: var(--uix-bg-active); border-radius: var(--uix-radius-pill); overflow: hidden; }
4
+ .uix-meter__fill { height: 100%; border-radius: inherit; background: var(--uix-success); transition: width var(--uix-dur) var(--uix-ease-out); }
5
+ .uix-meter__fill[data-tone="warning"] { background: var(--uix-warning); }
6
+ .uix-meter__fill[data-tone="danger"] { background: var(--uix-danger); }
7
+ .uix-meter__fill[data-tone="attention"] { background: var(--uix-attention); }
8
+ .uix-meter__fill[data-tone="overdue"] { background: var(--uix-overdue); }
9
+ }
@@ -0,0 +1,31 @@
1
+ /* uix modal / dialog — native <dialog>, animated enter/exit via @starting-style + allow-discrete. */
2
+ @layer uix.components {
3
+ .uix-dialog {
4
+ margin: auto; width: 100%; max-width: min(520px, 92vw); padding: 0; color: var(--uix-text);
5
+ border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg);
6
+ background: var(--uix-surface-2); box-shadow: var(--uix-shadow-overlay);
7
+ opacity: 0; transform: translateY(8px) scale(.98);
8
+ transition: opacity var(--uix-dur-slow) var(--uix-ease-out), transform var(--uix-dur-slow) var(--uix-ease-out),
9
+ overlay var(--uix-dur-slow) allow-discrete, display var(--uix-dur-slow) allow-discrete;
10
+ /* Author display values for both states required for the fade-in to animate: the allow-discrete
11
+ `display` transition only engages with author values, which also lets @starting-style fire.
12
+ With only the UA dialog display, the modal stays at opacity:0. Closed = none; open = block. */
13
+ display: none;
14
+ }
15
+ .uix-dialog[open] { opacity: 1; transform: none; display: block; }
16
+ @starting-style { .uix-dialog[open] { opacity: 0; transform: translateY(8px) scale(.98); } }
17
+ .uix-dialog::backdrop {
18
+ background: var(--uix-scrim); opacity: 0;
19
+ transition: opacity var(--uix-dur-slow) var(--uix-ease-out), overlay var(--uix-dur-slow) allow-discrete, display var(--uix-dur-slow) allow-discrete;
20
+ }
21
+ .uix-dialog[open]::backdrop { opacity: 1; }
22
+ @starting-style { .uix-dialog[open]::backdrop { opacity: 0; } }
23
+
24
+ .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); }
25
+ .uix-dialog__title { font-size: var(--uix-text-h3); font-weight: 600; }
26
+ .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); }
27
+ .uix-dialog__close:hover { background: var(--uix-bg-hover); color: var(--uix-text); }
28
+ .uix-dialog__close svg { width: var(--uix-icon-md); height: var(--uix-icon-md); }
29
+ .uix-dialog__body { padding: var(--uix-space-5); color: var(--uix-text-hushed); }
30
+ .uix-dialog__footer { display: flex; gap: var(--uix-space-2); justify-content: flex-end; padding: var(--uix-space-4) var(--uix-space-5); border-top: 1px solid var(--uix-border); }
31
+ }
@@ -0,0 +1,14 @@
1
+ /* uix notification center — depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-notifs { background: var(--uix-surface-2); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-lg); overflow: hidden; }
4
+ .uix-notifs__head { display: flex; align-items: center; padding: var(--uix-space-3) var(--uix-space-4); border-bottom: 1px solid var(--uix-border); font-weight: 600; }
5
+ .uix-notif { display: grid; grid-template-columns: auto 1fr; gap: var(--uix-space-3); padding: var(--uix-space-3) var(--uix-space-4); border-bottom: 1px solid var(--uix-border); }
6
+ .uix-notif:last-child { border-bottom: 0; }
7
+ .uix-notif[data-unread] { background: var(--uix-brand-muted); }
8
+ .uix-notif__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--uix-accent); margin-top: var(--uix-space-2); }
9
+ .uix-notif[data-unread] .uix-notif__dot { background: var(--uix-accent); }
10
+ .uix-notif:not([data-unread]) .uix-notif__dot { background: transparent; }
11
+ .uix-notif__meta { font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
12
+ /* on the unread brand-muted tint, muted meta dips below AA — hushed composites darker on the tint */
13
+ .uix-notif[data-unread] .uix-notif__meta { color: var(--uix-text-hushed); }
14
+ }
@@ -0,0 +1,9 @@
1
+ /* uix page header — title/subtitle/actions row. Depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-page-header { display: flex; align-items: flex-start; gap: var(--uix-space-5); flex-wrap: wrap; padding-bottom: var(--uix-space-6); margin-bottom: var(--uix-space-7); border-bottom: 1px solid var(--uix-border); }
4
+ .uix-page-header__titles { flex: 1; min-width: 220px; }
5
+ .uix-page-header__eyebrow { font-size: var(--uix-text-eyebrow); letter-spacing: var(--uix-tracking-eyebrow); text-transform: uppercase; font-weight: 600; color: var(--uix-text-muted); margin-bottom: var(--uix-space-2); }
6
+ .uix-page-header__title { font-size: var(--uix-text-h2); font-weight: 600; letter-spacing: var(--uix-tracking-tight); }
7
+ .uix-page-header__subtitle { color: var(--uix-text-muted); font-size: var(--uix-text-meta); margin-top: var(--uix-space-2); max-width: 70ch; }
8
+ .uix-page-header__actions { display: flex; gap: var(--uix-space-2); align-items: center; flex-wrap: wrap; }
9
+ }
@@ -0,0 +1,14 @@
1
+ /* uix pagination — depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-pagination { display: inline-flex; align-items: center; gap: var(--uix-space-1); }
4
+ .uix-pagination__btn {
5
+ min-width: 32px; height: 32px; padding: 0 var(--uix-space-2); display: inline-flex; align-items: center; justify-content: center;
6
+ border: 1px solid var(--uix-border); border-radius: var(--uix-radius-sm); background: var(--uix-surface);
7
+ color: var(--uix-text); font: inherit; font-size: var(--uix-text-meta); line-height: 1; cursor: pointer;
8
+ transition: background-color var(--uix-dur-fast) var(--uix-ease-out), border-color var(--uix-dur-fast) var(--uix-ease-out);
9
+ }
10
+ .uix-pagination__btn:hover { background: var(--uix-bg-hover); }
11
+ .uix-pagination__btn[aria-current="page"] { background: var(--uix-accent); border-color: var(--uix-accent); color: var(--uix-accent-fg); }
12
+ .uix-pagination__btn:disabled { opacity: .45; pointer-events: none; }
13
+ .uix-pagination__ellipsis { padding: 0 var(--uix-space-1); color: var(--uix-text-muted); }
14
+ }
@@ -0,0 +1,46 @@
1
+ /* uix side-peek drawer (the §5.8 peek pattern, reused by table rows + sidebar items).
2
+ Native <dialog>, slides from the right; keyboard ↑/↓ navigates records (app.js). */
3
+ @layer uix.components {
4
+ .uix-peek {
5
+ margin: 0 0 0 auto; height: 100dvh; max-height: 100dvh; width: var(--uix-peek-w); padding: 0; color: var(--uix-text);
6
+ border: 0; border-left: 1px solid var(--uix-border); border-radius: 0;
7
+ background: var(--uix-surface); box-shadow: var(--uix-shadow-overlay);
8
+ transform: translateX(100%);
9
+ transition: transform var(--uix-dur-slow) var(--uix-ease-out),
10
+ overlay var(--uix-dur-slow) allow-discrete, display var(--uix-dur-slow) allow-discrete;
11
+ /* Author display values for BOTH states are required for the slide-in to animate: the
12
+ allow-discrete `display` transition only engages with author values, and that gating also
13
+ lets the @starting-style entrance fire. With only the UA dialog display, the panel stays
14
+ parked at translateX(100%). Closed = none; open = flex. */
15
+ display: none;
16
+ }
17
+ .uix-peek[open] { transform: none; display: flex; flex-direction: column; }
18
+ @starting-style { .uix-peek[open] { transform: translateX(100%); } }
19
+ .uix-peek::backdrop {
20
+ background: var(--uix-scrim); opacity: 0;
21
+ transition: opacity var(--uix-dur-slow) var(--uix-ease-out), overlay var(--uix-dur-slow) allow-discrete, display var(--uix-dur-slow) allow-discrete;
22
+ }
23
+ .uix-peek[open]::backdrop { opacity: 1; }
24
+ @starting-style { .uix-peek[open]::backdrop { opacity: 0; } }
25
+
26
+ .uix-peek__header { display: flex; align-items: center; gap: var(--uix-space-3); padding: var(--uix-space-4) var(--uix-space-4); border-bottom: 1px solid var(--uix-border); }
27
+ .uix-peek__nav { display: inline-flex; gap: var(--uix-space-1); }
28
+ .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; }
29
+ .uix-peek__navbtn:hover { background: var(--uix-bg-hover); }
30
+ .uix-peek__title { font-size: var(--uix-text-h3); font-weight: 600; }
31
+ .uix-peek__title a { color: var(--uix-link); }
32
+ .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); }
33
+ .uix-peek__close:hover { background: var(--uix-bg-hover); color: var(--uix-text); }
34
+ .uix-peek__body { padding: var(--uix-space-5); overflow-y: auto; flex: 1; }
35
+ .uix-peek__hint { font-size: var(--uix-text-meta); color: var(--uix-text-muted); }
36
+ .uix-peek__footer { display: flex; gap: var(--uix-space-2); padding: var(--uix-space-4) var(--uix-space-4); border-top: 1px solid var(--uix-border); }
37
+
38
+ /* a table wired to open the peek (app.js sets data-uix-rowpeek): its rows read as clickable,
39
+ since clicking a ticket row is the queue's primary way to open the side-peek. */
40
+ [data-uix-rowpeek] tbody tr { cursor: pointer; }
41
+ [data-uix-rowpeek] tbody tr:hover td { background: var(--uix-bg-hover); }
42
+
43
+ /* Column sizing + the id-cell click-through pattern now live in table.css (one story for
44
+ "table cells"). Size columns with .uix-col--w-* / .uix-col--flex + .uix-col--truncate
45
+ instead of the old [data-uix-table-v2] :nth-child(2) title cap. */
46
+ }
@@ -0,0 +1,9 @@
1
+ /* uix deal / pipeline stage bar — depends only on --uix-* tokens. */
2
+ @layer uix.components {
3
+ .uix-pipeline { display: flex; gap: var(--uix-space-1); }
4
+ .uix-pipeline__stage { flex: 1; text-align: center; padding: var(--uix-space-2) var(--uix-space-2); font-size: var(--uix-text-meta); color: var(--uix-text-muted); background: var(--uix-bg-subtle); }
5
+ .uix-pipeline__stage:first-child { border-radius: var(--uix-radius-pill) 0 0 var(--uix-radius-pill); }
6
+ .uix-pipeline__stage:last-child { border-radius: 0 var(--uix-radius-pill) var(--uix-radius-pill) 0; }
7
+ .uix-pipeline__stage[data-state="done"] { background: var(--uix-accent); color: var(--uix-accent-fg); }
8
+ .uix-pipeline__stage[data-state="active"] { background: var(--uix-brand-muted); color: var(--uix-link); font-weight: 600; }
9
+ }
@@ -0,0 +1,11 @@
1
+ /* uix popover — generic anchored surface via the native Popover API; animated with @starting-style. */
2
+ @layer uix.components {
3
+ .uix-popover { margin: 0; padding: var(--uix-space-2); background: var(--uix-surface-2); border: 1px solid var(--uix-border); border-radius: var(--uix-radius-md); box-shadow: var(--uix-shadow-popover); color: var(--uix-text); }
4
+ [popover].uix-popover {
5
+ opacity: 0; transform: translateY(calc(-1 * var(--uix-lift)));
6
+ transition: opacity var(--uix-dur-fast) var(--uix-ease-out), transform var(--uix-dur-fast) var(--uix-ease-out),
7
+ overlay var(--uix-dur-fast) allow-discrete, display var(--uix-dur-fast) allow-discrete;
8
+ }
9
+ [popover].uix-popover:popover-open { opacity: 1; transform: none; }
10
+ @starting-style { [popover].uix-popover:popover-open { opacity: 0; transform: translateY(calc(-1 * var(--uix-lift))); } }
11
+ }