@attrus-ds/core 1.0.13 → 1.0.17

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.
@@ -317,3 +317,71 @@
317
317
  color: var(--color-foreground-muted);
318
318
  margin-bottom: var(--space-2-5);
319
319
  }
320
+
321
+ /* ----------------------------------------------------------------
322
+ PROGRESS — one tone scale, two shapes
323
+ ----------------------------------------------------------------
324
+ Shape and tone are independent axes. Shape answers "is the count
325
+ meaningful?" — a bar at 60% invites estimation, a filled 3rd segment states
326
+ "3 of 5". Tone answers "what does this progress mean?" and uses the same
327
+ semantic pairs as the pills, so a bar reads consistently with the status
328
+ beside it.
329
+
330
+ Both shapes resolve --progress-tone, so a tone is declared ONCE and works in
331
+ either. Adding a tone is a single line; it used to be two rules per tone and
332
+ a tone added to one shape silently missed the other.
333
+
334
+ Shapes: .progress (continuous) · .progress-seg (discrete steps)
335
+ Tones: default (brand) · is-success · is-warning · is-danger · is-critical
336
+ Sizes: is-sm 4px · default 6px · is-lg 10px
337
+ ---------------------------------------------------------------- */
338
+
339
+ /* Tone scale — read by both shapes */
340
+ .progress, .progress-seg { --progress-tone: var(--color-brand-solid); }
341
+ .is-success { --progress-tone: var(--color-feedback-success-foreground); }
342
+ .is-warning { --progress-tone: var(--color-feedback-warning-foreground); }
343
+ .is-danger { --progress-tone: var(--color-feedback-danger-foreground); }
344
+ .is-critical { --progress-tone: var(--color-feedback-danger-foreground); }
345
+ .is-info { --progress-tone: var(--color-feedback-info-foreground); }
346
+
347
+ /* Shape: continuous */
348
+ .progress .progress-fill { background: var(--progress-tone); }
349
+ /* the default tone keeps the brand gradient, which reads richer than flat navy */
350
+ .progress:not([class*="is-success"]):not([class*="is-warning"]):not([class*="is-danger"]):not([class*="is-critical"]):not([class*="is-info"]) .progress-fill {
351
+ background: var(--grad-brand-soft);
352
+ }
353
+
354
+ /* Shape: segmented */
355
+ .progress-seg { display: inline-flex; gap: var(--space-1); width: 100%; }
356
+ .progress-seg > i {
357
+ flex: 1;
358
+ height: var(--progress-h, 6px);
359
+ border-radius: var(--radius-2xs);
360
+ background: var(--progress-track, var(--color-border-default));
361
+ }
362
+ .progress-seg > i.is-done { background: var(--progress-tone); }
363
+ .progress-seg > i.is-current { background: color-mix(in srgb, var(--progress-tone) 45%, transparent); }
364
+
365
+ /* Critical — danger that is also URGENT. Danger states a failed fact; critical
366
+ says the clock is running (a cut-off hours away, a limit about to bind). The
367
+ pulse is what separates them: colour alone cannot express time pressure, and
368
+ a table full of red would flatten the distinction. */
369
+ .progress.is-critical .progress-fill,
370
+ .progress-seg.is-critical > i.is-current {
371
+ animation: progress-critical 1.6s var(--ease-standard) infinite;
372
+ }
373
+ .progress.is-critical { box-shadow: 0 0 0 1px color-mix(in srgb, var(--progress-tone) 30%, transparent); }
374
+ @keyframes progress-critical { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
375
+
376
+ /* Sizes */
377
+ .progress.is-sm, .progress-seg.is-sm > i { --progress-h: 4px; }
378
+ .progress.is-lg, .progress-seg.is-lg > i { --progress-h: 10px; }
379
+
380
+ @media (prefers-reduced-motion: reduce) {
381
+ .progress.is-critical .progress-fill,
382
+ .progress-seg.is-critical > i.is-current { animation: none; }
383
+ }
384
+ }
385
+ /* Sizes */
386
+ .progress.is-sm, .progress-seg.is-sm > i { --progress-h: 4px; }
387
+ .progress.is-lg, .progress-seg.is-lg > i { --progress-h: 10px; }
@@ -192,3 +192,36 @@
192
192
  background: var(--color-background-subtle);
193
193
  padding: 1px 6px; border-radius: var(--radius-xs);
194
194
  }
195
+
196
+ /* ============================================================
197
+ GLASS VARIANT — .sb.is-glass
198
+ ============================================================
199
+ Same idea as .topbar.is-glass, with one extra concern: a sidebar is tall, so
200
+ the blur samples a lot of moving content and the active-item tint has to stay
201
+ legible against all of it. The active row therefore keeps an opaque backing
202
+ instead of inheriting the translucent field.
203
+
204
+ The right edge is the boundary here (the sidebar has no bottom border), so it
205
+ takes the stronger token for the same reason the topbar's hairline does. */
206
+ .sb.is-glass {
207
+ background: var(--glass-chrome);
208
+ color: var(--glass-chrome-fg);
209
+ -webkit-backdrop-filter: var(--glass-blur);
210
+ backdrop-filter: var(--glass-blur);
211
+ border-right-color: var(--color-border-strong);
212
+ }
213
+ /* Active item must not dissolve into the blur */
214
+ .sb.is-glass .sb-item.active {
215
+ background: var(--color-background-selected);
216
+ -webkit-backdrop-filter: none;
217
+ backdrop-filter: none;
218
+ }
219
+ /* Head and foot read as their own planes over a translucent field */
220
+ .sb.is-glass .sb-head,
221
+ .sb.is-glass .sb-foot {
222
+ background: color-mix(in srgb, var(--color-background-surface) 40%, transparent);
223
+ border-color: var(--color-border-default);
224
+ }
225
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
226
+ .sb.is-glass { background: var(--color-background-surface); }
227
+ }
@@ -6,23 +6,26 @@
6
6
  Consumed by the SmartSearch TSX component.
7
7
  ============================================================ */
8
8
  /* Smart-search combobox */
9
- .ss { width: 100%; max-width: 380px; background: var(--color-background-surface); border: 1px solid var(--color-border-default); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); overflow: hidden; font-size: var(--fs-sm); }
10
- .ss-input { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--color-border-subtle); }
9
+ /* 380px: comfortable reading measure for a result list, and narrow enough that
10
+ the palette does not blanket the page it floats over. Not a token — it is a
11
+ layout decision local to this component. */
12
+ .ss { width: 100%; max-width: 380px; background: var(--color-background-surface); border: var(--border-hairline) solid var(--color-border-default); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); overflow: hidden; font-size: var(--fs-sm); }
13
+ .ss-input { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-4); border-bottom: var(--border-hairline) solid var(--color-border-subtle); }
11
14
  .ss-input.ss-input-flat { border-bottom: 0; }
12
15
  .ss-input svg, .ss-input i { width: var(--icon-sm); height: var(--icon-sm); stroke-width: var(--icon-stroke); color: var(--color-foreground-muted); flex-shrink: 0; }
13
16
  .ss-input input { flex: 1; border: 0; outline: 0; background: transparent; font: inherit; color: var(--color-foreground-default); }
14
17
  .ss-input input::placeholder { color: var(--color-foreground-placeholder); }
15
- .ss-clear { display: inline-flex; align-items: center; justify-content: center; width: 18px; height: 18px; border: 0; padding: 0; border-radius: var(--radius-pill); background: transparent; color: var(--color-foreground-muted); cursor: pointer; }
18
+ .ss-clear { display: inline-flex; align-items: center; justify-content: center; width: var(--icon-sm); height: var(--icon-sm); border: 0; padding: 0; border-radius: var(--radius-pill); background: transparent; color: var(--color-foreground-muted); cursor: pointer; }
16
19
  .ss-clear:hover { background: var(--color-background-hover); color: var(--color-foreground-default); }
17
- .ss-clear svg, .ss-clear i { width: 12px; height: 12px; }
20
+ .ss-clear svg, .ss-clear i { width: var(--icon-xs); height: var(--icon-xs); }
18
21
 
19
- .ss-section { padding: var(--space-3) var(--space-2); border-bottom: 1px solid var(--color-border-subtle); }
22
+ .ss-section { padding: var(--space-3) var(--space-2); border-bottom: var(--border-hairline) solid var(--color-border-subtle); }
20
23
  .ss-section:last-of-type { border-bottom: 0; }
21
24
  .ss-section-label { font-size: var(--fs-xxs); font-weight: var(--w-regular); letter-spacing: var(--ls-caps); text-transform: uppercase; color: var(--color-foreground-muted); padding: 0 var(--space-2); margin-bottom: var(--space-2); }
22
25
 
23
26
  /* Suggestion chips (active state) */
24
27
  .ss-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); padding: 0 var(--space-2); }
25
- .ss-chip { display: inline-flex; align-items: center; gap: var(--space-2); padding: 4px var(--space-3); background: var(--color-background-canvas); border: 1px solid var(--color-border-default); border-radius: var(--radius-pill); font-size: var(--fs-xs); font-weight: var(--w-regular); color: var(--color-foreground-default); cursor: pointer; transition: var(--transition-fast); }
28
+ .ss-chip { display: inline-flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3); background: var(--color-background-canvas); border: var(--border-hairline) solid var(--color-border-default); border-radius: var(--radius-pill); font-size: var(--fs-xs); font-weight: var(--w-regular); color: var(--color-foreground-default); cursor: pointer; transition: var(--transition-fast); }
26
29
  .ss-chip:hover { background: var(--color-background-hover); border-color: var(--color-border-strong); }
27
30
  .ss-chip svg, .ss-chip i { width: 11px; height: 11px; stroke-width: var(--icon-stroke); color: var(--color-foreground-muted); }
28
31
 
@@ -30,18 +33,18 @@
30
33
  .ss-list { list-style: none; margin: 0; padding: 0; }
31
34
  .ss-list-item { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); cursor: pointer; transition: var(--transition-fast); }
32
35
  .ss-list-item:hover, .ss-list-item.is-active { background: var(--color-background-hover); }
33
- .ss-list-item .icon-leading { width: 28px; height: 28px; border-radius: var(--radius-sm); background: var(--color-background-canvas); display: inline-flex; align-items: center; justify-content: center; color: var(--color-foreground-secondary); flex-shrink: 0; }
34
- .ss-list-item .icon-leading svg, .ss-list-item .icon-leading i { width: 14px; height: 14px; stroke-width: var(--icon-stroke); }
36
+ .ss-list-item .icon-leading { width: var(--control-h-xs); height: var(--control-h-xs); border-radius: var(--radius-sm); background: var(--color-background-canvas); display: inline-flex; align-items: center; justify-content: center; color: var(--color-foreground-secondary); flex-shrink: 0; }
37
+ .ss-list-item .icon-leading svg, .ss-list-item .icon-leading i { width: var(--icon-xs); height: var(--icon-xs); stroke-width: var(--icon-stroke); }
35
38
  .ss-list-item .icon-leading.brand { background: var(--color-brand-subtle-solid); color: var(--color-brand-text-on-light); }
36
39
  .ss-list-item .text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
37
40
  .ss-list-item .text .label { font-size: var(--fs-sm); font-weight: var(--w-regular); color: var(--color-foreground-default); }
38
41
  .ss-list-item .text .meta { font-size: var(--fs-xs); color: var(--color-foreground-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
39
- .ss-list-item .icon-trailing { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; flex-shrink: 0; color: var(--color-foreground-muted); }
40
- .ss-list-item .icon-trailing svg, .ss-list-item .icon-trailing i { width: 14px; height: 14px; stroke-width: var(--icon-stroke); }
42
+ .ss-list-item .icon-trailing { display: inline-flex; align-items: center; justify-content: center; width: var(--icon-sm); height: var(--icon-sm); flex-shrink: 0; color: var(--color-foreground-muted); }
43
+ .ss-list-item .icon-trailing svg, .ss-list-item .icon-trailing i { width: var(--icon-xs); height: var(--icon-xs); stroke-width: var(--icon-stroke); }
41
44
 
42
45
  /* Recent searches — clock icon + dim text */
43
- .ss-recent .ss-list-item .icon-leading { background: transparent; border: 0; width: 18px; height: 18px; }
44
- .ss-recent .ss-list-item .icon-leading svg, .ss-recent .ss-list-item .icon-leading i { width: 13px; height: 13px; color: var(--color-foreground-muted); }
46
+ .ss-recent .ss-list-item .icon-leading { background: transparent; border: 0; width: var(--icon-sm); height: var(--icon-sm); }
47
+ .ss-recent .ss-list-item .icon-leading svg, .ss-recent .ss-list-item .icon-leading i { width: var(--icon-xs); height: var(--icon-xs); color: var(--color-foreground-muted); }
45
48
  .ss-recent .ss-list-item .text .label { font-weight: var(--w-regular); color: var(--color-foreground-secondary); }
46
49
 
47
50
  /* Empty/result label */
@@ -51,9 +54,9 @@
51
54
  .ss-no-result strong { color: var(--color-foreground-default); font-weight: var(--w-regular); }
52
55
 
53
56
  /* Tip / hint card (similar match suggestion, ID format hint) */
54
- .ss-hint { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3); background: var(--color-background-subtle); border: 1px solid var(--color-border-subtle); border-radius: var(--radius-sm); margin: var(--space-3) var(--space-2) 0; }
55
- .ss-hint .icon-leading { color: var(--color-foreground-muted); flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; }
56
- .ss-hint .icon-leading svg, .ss-hint .icon-leading i { width: 14px; height: 14px; stroke-width: var(--icon-stroke); }
57
+ .ss-hint { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3); background: var(--color-background-subtle); border: var(--border-hairline) solid var(--color-border-subtle); border-radius: var(--radius-sm); margin: var(--space-3) var(--space-2) 0; }
58
+ .ss-hint .icon-leading { color: var(--color-foreground-muted); flex-shrink: 0; display: inline-flex; align-items: center; justify-content: center; width: var(--icon-xs); height: var(--icon-xs); }
59
+ .ss-hint .icon-leading svg, .ss-hint .icon-leading i { width: var(--icon-xs); height: var(--icon-xs); stroke-width: var(--icon-stroke); }
57
60
  .ss-hint .body { font-size: var(--fs-sm); color: var(--color-foreground-secondary); line-height: var(--lh-relaxed); }
58
61
  .ss-hint .body strong { color: var(--color-foreground-default); font-weight: var(--w-regular); }
59
62
  .ss-hint .body code { font-family: var(--font-mono);
@@ -61,16 +64,16 @@
61
64
 
62
65
  /* ID type-picker buttons */
63
66
  .ss-typebtns { display: flex; flex-direction: column; gap: var(--space-2); padding: 0 var(--space-2); }
64
- .ss-typebtn { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-3); background: var(--color-background-canvas); border: 1px solid var(--color-border-default); border-radius: var(--radius-sm); font-size: var(--fs-sm); font-weight: var(--w-regular); color: var(--color-foreground-default); cursor: pointer; transition: var(--transition-fast); text-align: left; width: 100%; }
67
+ .ss-typebtn { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-3) var(--space-3); background: var(--color-background-canvas); border: var(--border-hairline) solid var(--color-border-default); border-radius: var(--radius-sm); font-size: var(--fs-sm); font-weight: var(--w-regular); color: var(--color-foreground-default); cursor: pointer; transition: var(--transition-fast); text-align: left; width: 100%; }
65
68
  .ss-typebtn:hover { background: var(--color-background-hover); border-color: var(--color-border-strong); }
66
- .ss-typebtn svg, .ss-typebtn i { width: 16px; height: 16px; stroke-width: var(--icon-stroke); color: var(--color-foreground-muted); }
69
+ .ss-typebtn svg, .ss-typebtn i { width: var(--icon-sm); height: var(--icon-sm); stroke-width: var(--icon-stroke); color: var(--color-foreground-muted); }
67
70
  .ss-typebtn .grow { flex: 1; }
68
71
  .ss-typebtn .chev { color: var(--color-foreground-muted); }
69
72
 
70
73
  /* Loading skeleton + spinner illustration */
71
74
  .ss-skeleton { padding: var(--space-3) var(--space-2); display: flex; flex-direction: column; gap: var(--space-3); }
72
75
  .ss-skel-row { display: flex; align-items: center; gap: var(--space-3); }
73
- .ss-skel-circle { width: 28px; height: 28px; border-radius: var(--radius-sm); background: var(--color-border-default); flex-shrink: 0; }
76
+ .ss-skel-circle { width: var(--control-h-xs); height: var(--control-h-xs); border-radius: var(--radius-sm); background: var(--color-border-default); flex-shrink: 0; }
74
77
  .ss-skel-bars { flex: 1; display: flex; flex-direction: column; gap: 5px; }
75
78
  .ss-skel-bar { height: 8px; border-radius: var(--radius-xs); background: var(--color-border-default); }
76
79
  .ss-skel-bar.short { width: 40%; }
@@ -79,15 +82,45 @@
79
82
  @keyframes skel { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
80
83
 
81
84
  .ss-illo { display: flex; flex-direction: column; align-items: center; gap: var(--space-3); padding: var(--space-7) var(--space-5); text-align: center; }
82
- .ss-illo svg.illustration { width: 84px; height: 60px; }
85
+ .ss-illo svg.illustration { width: 84px; /* 60px: two rows of the empty illustration, sized to the same optical block */
86
+ height: 60px; }
83
87
  .ss-illo .title { font-size: var(--fs-md); font-weight: var(--w-regular); color: var(--color-foreground-default); }
84
88
  .ss-illo .body { font-size: var(--fs-xs); color: var(--color-foreground-muted); max-width: 32ch; line-height: var(--lh-relaxed); }
85
89
 
86
90
  /* Footer with keyboard shortcuts */
87
- .ss-foot { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-2) var(--space-3); background: var(--color-background-subtle); border-top: 1px solid var(--color-border-subtle); font-size: var(--fs-xxs); color: var(--color-foreground-muted); }
88
- .ss-foot .kbd-group { display: inline-flex; align-items: center; gap: 4px; }
89
- kbd.ss-kbd { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 4px; background: var(--color-background-surface); border: 1px solid var(--color-border-default); border-radius: var(--radius-xs); font-family: var(--font-mono);
91
+ .ss-foot { display: flex; align-items: center; gap: var(--space-4); padding: var(--space-2) var(--space-3); background: var(--color-background-subtle); border-top: var(--border-hairline) solid var(--color-border-subtle); font-size: var(--fs-xxs); color: var(--color-foreground-muted); }
92
+ .ss-foot .kbd-group { display: inline-flex; align-items: center; gap: var(--space-2); }
93
+ kbd.ss-kbd { display: inline-flex; align-items: center; justify-content: center; min-width: var(--icon-sm); height: var(--icon-sm); padding: 0 var(--space-2); background: var(--color-background-surface); border: var(--border-hairline) solid var(--color-border-default); border-radius: var(--radius-xs); font-family: var(--font-mono);
90
94
  font-size-adjust: var(--font-mono-adjust); font-size: 10px; font-weight: var(--w-regular); color: var(--color-foreground-secondary); }
91
- .ss-foot .sep { width: 1px; height: 12px; background: var(--color-border-default); }
95
+ .ss-foot .sep { width: 1px; height: var(--icon-xs); background: var(--color-border-default); }
92
96
 
93
97
 
98
+
99
+ /* Searching illustration — one belt, four cards, a fade mask.
100
+ Three independently-animated cards could not work: staggering their delays by
101
+ a third means their slides are also staggered, so a card slides into a slot
102
+ the previous one has not left yet and they cross over (measured: overlap in
103
+ 20 of 10 sampled frames). The fix is to stop animating cards and animate the
104
+ BELT — the cards keep a fixed 42px pitch, so they physically cannot overlap.
105
+
106
+ Opacity comes from position rather than from each card's own timeline: an SVG
107
+ fade mask makes the middle of the frame fully opaque and the edges transparent,
108
+ so a card loses its transparency BECAUSE it reached the centre. Four cards make
109
+ the loop seamless — after one pitch of travel the arrangement repeats. */
110
+ @keyframes ss-doc-belt {
111
+ /* Push in, hold, push out. A linear belt never pauses, so nothing was ever
112
+ "in the spotlight" — the hold is what makes it read as one document being
113
+ examined rather than a strip scrolling past.
114
+ 0.9s cycle: ~0.4s of travel, 0.5s parked at centre. The belt still advances
115
+ exactly one 42px pitch per cycle, so the loop stays seamless. */
116
+ 0%, 44% { transform: translateX(0); }
117
+ 100% { transform: translateX(-42px); }
118
+ }
119
+ .ss-illo .illustration .doc-belt {
120
+ /* Ease on the move; the flat 0→44% span is the half-second hold. */
121
+ animation: ss-doc-belt .9s var(--ease-standard) infinite;
122
+ }
123
+
124
+ @media (prefers-reduced-motion: reduce) {
125
+ .ss-illo .illustration .doc-belt { animation: none; }
126
+ }
@@ -134,12 +134,12 @@
134
134
  .pill.solid.brand { background: var(--color-brand-solid); color: var(--color-brand-on-solid); border-color: transparent; }
135
135
  .pill.solid > .dot { background: currentColor; }
136
136
 
137
- .pill.outline.success { background: transparent; color: var(--color-feedback-success-foreground); border-color: var(--color-success-500); }
138
- .pill.outline.warning { background: transparent; color: var(--color-feedback-warning-foreground); border-color: var(--color-warning-500); }
139
- .pill.outline.danger { background: transparent; color: var(--color-feedback-danger-foreground); border-color: var(--color-danger-500); }
140
- .pill.outline.info { background: transparent; color: var(--color-feedback-info-foreground); border-color: var(--color-info-500); }
141
- .pill.outline.neutral { background: transparent; color: var(--color-foreground-secondary); border-color: var(--color-border-strong); }
142
- .pill.outline.brand { background: transparent; color: var(--color-foreground-accent); border-color: var(--color-brand-solid); }
137
+ .pill.outline.success { background: transparent; color: var(--color-feedback-success-foreground); border-color: var(--color-feedback-success-border); }
138
+ .pill.outline.warning { background: transparent; color: var(--color-feedback-warning-foreground); border-color: var(--color-feedback-warning-border); }
139
+ .pill.outline.danger { background: transparent; color: var(--color-feedback-danger-foreground); border-color: var(--color-feedback-danger-border); }
140
+ .pill.outline.info { background: transparent; color: var(--color-feedback-info-foreground); border-color: var(--color-feedback-info-border); }
141
+ .pill.outline.neutral { background: transparent; color: var(--color-foreground-secondary); border-color: var(--color-border-default); }
142
+ .pill.outline.brand { background: transparent; color: var(--color-foreground-accent); border-color: var(--color-brand-border); }
143
143
 
144
144
 
145
145
  /* ----------------------------------------------------------------