@nim.zone/ui 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +681 -0
  3. package/dist/components/admin-shell.d.ts +121 -0
  4. package/dist/components/app-shell.d.ts +23 -0
  5. package/dist/components/auth-screen.d.ts +33 -0
  6. package/dist/components/avatar.d.ts +10 -0
  7. package/dist/components/badge.d.ts +14 -0
  8. package/dist/components/banner.d.ts +11 -0
  9. package/dist/components/breadcrumb.d.ts +12 -0
  10. package/dist/components/button.d.ts +21 -0
  11. package/dist/components/card.d.ts +15 -0
  12. package/dist/components/chat-composer.d.ts +52 -0
  13. package/dist/components/chat.d.ts +77 -0
  14. package/dist/components/checkout.d.ts +79 -0
  15. package/dist/components/choice.d.ts +15 -0
  16. package/dist/components/combobox.d.ts +31 -0
  17. package/dist/components/date-field.d.ts +58 -0
  18. package/dist/components/dialog.d.ts +20 -0
  19. package/dist/components/empty-state.d.ts +9 -0
  20. package/dist/components/feedback.d.ts +18 -0
  21. package/dist/components/field.d.ts +47 -0
  22. package/dist/components/icon-button.d.ts +12 -0
  23. package/dist/components/icon.d.ts +72 -0
  24. package/dist/components/layout.d.ts +13 -0
  25. package/dist/components/list.d.ts +16 -0
  26. package/dist/components/menu.d.ts +56 -0
  27. package/dist/components/onboarding.d.ts +50 -0
  28. package/dist/components/otp-input.d.ts +29 -0
  29. package/dist/components/pagination.d.ts +12 -0
  30. package/dist/components/password-field.d.ts +33 -0
  31. package/dist/components/phone-field.d.ts +44 -0
  32. package/dist/components/plan-card.d.ts +45 -0
  33. package/dist/components/plan-picker.d.ts +52 -0
  34. package/dist/components/profile-header.d.ts +47 -0
  35. package/dist/components/profile-screen.d.ts +44 -0
  36. package/dist/components/resource-meter.d.ts +22 -0
  37. package/dist/components/section-header.d.ts +8 -0
  38. package/dist/components/segmented.d.ts +18 -0
  39. package/dist/components/sheet.d.ts +18 -0
  40. package/dist/components/sign-in-flow.d.ts +60 -0
  41. package/dist/components/slider.d.ts +10 -0
  42. package/dist/components/stat.d.ts +10 -0
  43. package/dist/components/stepper.d.ts +17 -0
  44. package/dist/components/tab-bar.d.ts +40 -0
  45. package/dist/components/table.d.ts +33 -0
  46. package/dist/components/tabs.d.ts +23 -0
  47. package/dist/components/task-progress.d.ts +38 -0
  48. package/dist/components/theme.d.ts +49 -0
  49. package/dist/components/toast.d.ts +17 -0
  50. package/dist/components/tooltip.d.ts +18 -0
  51. package/dist/components/typography.d.ts +18 -0
  52. package/dist/components/wizard.d.ts +70 -0
  53. package/dist/index.d.ts +104 -0
  54. package/dist/lib/calendars.d.ts +81 -0
  55. package/dist/lib/cn.d.ts +7 -0
  56. package/dist/lib/countries.d.ts +33 -0
  57. package/dist/lib/use-anchor.d.ts +22 -0
  58. package/dist/nim.css +1 -0
  59. package/dist/nim.js +3266 -0
  60. package/package.json +83 -0
  61. package/src/components/admin-shell.tsx +338 -0
  62. package/src/components/app-shell.tsx +36 -0
  63. package/src/components/auth-screen.tsx +71 -0
  64. package/src/components/avatar.tsx +32 -0
  65. package/src/components/badge.tsx +44 -0
  66. package/src/components/banner.tsx +47 -0
  67. package/src/components/breadcrumb.tsx +45 -0
  68. package/src/components/button.tsx +64 -0
  69. package/src/components/card.tsx +46 -0
  70. package/src/components/chat-composer.tsx +331 -0
  71. package/src/components/chat.tsx +352 -0
  72. package/src/components/checkout.tsx +173 -0
  73. package/src/components/choice.tsx +46 -0
  74. package/src/components/combobox.tsx +157 -0
  75. package/src/components/date-field.tsx +394 -0
  76. package/src/components/dialog.tsx +77 -0
  77. package/src/components/empty-state.tsx +23 -0
  78. package/src/components/feedback.tsx +61 -0
  79. package/src/components/field.tsx +177 -0
  80. package/src/components/icon-button.tsx +35 -0
  81. package/src/components/icon.tsx +167 -0
  82. package/src/components/layout.tsx +38 -0
  83. package/src/components/list.tsx +78 -0
  84. package/src/components/menu.tsx +172 -0
  85. package/src/components/onboarding.tsx +157 -0
  86. package/src/components/otp-input.tsx +144 -0
  87. package/src/components/pagination.tsx +86 -0
  88. package/src/components/password-field.tsx +112 -0
  89. package/src/components/phone-field.tsx +242 -0
  90. package/src/components/plan-card.tsx +124 -0
  91. package/src/components/plan-picker.tsx +144 -0
  92. package/src/components/profile-header.tsx +134 -0
  93. package/src/components/profile-screen.tsx +104 -0
  94. package/src/components/resource-meter.tsx +60 -0
  95. package/src/components/section-header.tsx +31 -0
  96. package/src/components/segmented.tsx +53 -0
  97. package/src/components/sheet.tsx +74 -0
  98. package/src/components/sign-in-flow.tsx +322 -0
  99. package/src/components/slider.tsx +50 -0
  100. package/src/components/stat.tsx +30 -0
  101. package/src/components/stepper.tsx +77 -0
  102. package/src/components/tab-bar.tsx +82 -0
  103. package/src/components/table.tsx +81 -0
  104. package/src/components/tabs.tsx +72 -0
  105. package/src/components/task-progress.tsx +111 -0
  106. package/src/components/theme.tsx +112 -0
  107. package/src/components/toast.tsx +87 -0
  108. package/src/components/tooltip.tsx +30 -0
  109. package/src/components/typography.tsx +65 -0
  110. package/src/components/wizard.tsx +192 -0
  111. package/src/index.ts +216 -0
  112. package/src/lib/calendars.ts +227 -0
  113. package/src/lib/cn.ts +8 -0
  114. package/src/lib/countries.ts +110 -0
  115. package/src/lib/use-anchor.ts +92 -0
  116. package/src/theme/colorways/coral.css +62 -0
  117. package/src/theme/colorways/oxblood.css +23 -0
  118. package/src/theme/colorways/paper.css +68 -0
  119. package/src/theme/colorways/teal.css +56 -0
  120. package/src/theme/colorways/vermilion.css +21 -0
  121. package/src/theme/components.css +4606 -0
  122. package/src/theme/contract.css +204 -0
  123. package/src/theme/fonts.css +67 -0
  124. package/src/theme/index.css +33 -0
  125. package/src/theme/persian.css +47 -0
  126. package/src/theme/reset.css +118 -0
  127. package/src/theme/styles/ledger.css +106 -0
  128. package/src/theme/styles/vlora.css +91 -0
  129. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,4606 @@
1
+ /* ═══════════════════════════════════════════════════════════════════════════
2
+ nim — COMPONENT LAYER
3
+
4
+ Every class here is written against the token contract and nothing else. A
5
+ literal colour, radius, shadow, or type value in this file is a bug: it is a
6
+ decision that belongs to a theme.
7
+
8
+ Conventions
9
+ · Block / modifier: `.nim-card` + `.nim-card--raised`, element: `__body`.
10
+ · Logical properties only — no left/right — so RTL needs no mirror rules.
11
+ · Every interactive element gets a hover, a press, a focus ring, a
12
+ disabled state, and a minimum 44px touch target.
13
+ · Components own layout of their own parts only. They never set outer
14
+ margin; spacing between components is the page's job.
15
+ ═══════════════════════════════════════════════════════════════════════════ */
16
+
17
+ @layer components {
18
+ /* ═══════════════════════════════════════════════════════════════════════
19
+ FOCUS · PRESS
20
+ Answered once, for every interactive surface in the kit. Until 0.2 the
21
+ focus token was defined by every theme and consumed by a single rule, so
22
+ tabbing through a nim screen showed nothing; and the press response was
23
+ copied per component, which is how interactive cards ended up applying
24
+ `scale` on a theme whose press language is `translate`.
25
+ ═══════════════════════════════════════════════════════════════════════ */
26
+ .nim-focusable:focus-visible,
27
+ .nim-button:focus-visible,
28
+ .nim-icon-button:focus-visible,
29
+ .nim-card--interactive:focus-visible,
30
+ .nim-list-row--interactive:focus-visible,
31
+ .nim-segmented__option:focus-visible,
32
+ .nim-tab:focus-visible,
33
+ .nim-menu__item:focus-visible,
34
+ .nim-pagination__item:focus-visible,
35
+ .nim-breadcrumb__link:focus-visible,
36
+ .nim-stepper__button:focus-visible,
37
+ .nim-calendar__day:focus-visible,
38
+ .nim-combobox__option:focus-visible,
39
+ .nim-input:focus-visible,
40
+ .nim-textarea:focus-visible,
41
+ .nim-select:focus-visible {
42
+ outline: none;
43
+ box-shadow: var(--nim-shadow-focus);
44
+ }
45
+
46
+ /* Surfaces flush with their neighbours cannot afford an outset ring — the
47
+ parent's `overflow: hidden` would clip it. They take an inset outline
48
+ instead, which is drawn inside the element's own box. */
49
+ .nim-menu__item:focus-visible,
50
+ .nim-calendar__day:focus-visible,
51
+ .nim-combobox__option:focus-visible,
52
+ .nim-stepper__button:focus-visible,
53
+ .nim-table__sort:focus-visible {
54
+ box-shadow: none;
55
+ outline: var(--nim-size-focus-ring) solid var(--nim-accent);
56
+ outline-offset: calc(-1 * var(--nim-size-focus-ring));
57
+ }
58
+
59
+ /* How a control answers a press is one theme decision (`--nim-press-*`),
60
+ applied identically everywhere. Ledger shifts into its offset shadow —
61
+ a key being struck; Vlora compresses. */
62
+ .nim-button:active:not(:disabled),
63
+ .nim-icon-button:active:not(:disabled),
64
+ .nim-card--interactive:active,
65
+ .nim-stepper__button:active:not(:disabled),
66
+ .nim-pagination__item:active:not(:disabled) {
67
+ scale: var(--nim-press-scale);
68
+ translate: var(--nim-press-translate) var(--nim-press-translate);
69
+ box-shadow: none;
70
+ }
71
+
72
+ /* ═══════════════════════════════════════════════════════════════════════
73
+ TYPOGRAPHY ROLES
74
+ Text primitives so a product never reaches for a raw font-size.
75
+ ═══════════════════════════════════════════════════════════════════════ */
76
+ .nim-display {
77
+ font-family: var(--nim-type-display-family);
78
+ font-size: var(--nim-type-display-size);
79
+ line-height: var(--nim-type-display-line);
80
+ font-weight: var(--nim-type-display-weight);
81
+ letter-spacing: var(--nim-type-display-tracking);
82
+ text-wrap: balance;
83
+ }
84
+
85
+ .nim-title {
86
+ font-size: var(--nim-type-title-lg-size);
87
+ line-height: var(--nim-type-title-lg-line);
88
+ font-weight: var(--nim-type-title-lg-weight);
89
+ letter-spacing: var(--nim-tracking-tight);
90
+ text-wrap: balance;
91
+ }
92
+
93
+ .nim-title--md {
94
+ font-size: var(--nim-type-title-md-size);
95
+ line-height: var(--nim-type-title-md-line);
96
+ font-weight: var(--nim-type-title-md-weight);
97
+ }
98
+
99
+ .nim-body {
100
+ font-size: var(--nim-type-body-size);
101
+ line-height: var(--nim-type-body-line);
102
+ color: var(--nim-ink-secondary);
103
+ text-wrap: pretty;
104
+ }
105
+
106
+ .nim-body--sm {
107
+ font-size: var(--nim-type-body-sm-size);
108
+ }
109
+
110
+ /* The label is the theme's signature: mono/uppercase/tracked in Ledger,
111
+ plain sentence case in Vlora — one pair of tokens decides which. */
112
+ .nim-label {
113
+ font-family: var(--nim-type-label-family);
114
+ font-size: var(--nim-type-label-size);
115
+ font-weight: var(--nim-type-label-weight);
116
+ letter-spacing: var(--nim-label-tracking);
117
+ text-transform: var(--nim-label-transform);
118
+ color: var(--nim-ink-tertiary);
119
+ }
120
+
121
+ .nim-caption {
122
+ font-size: var(--nim-type-caption-size);
123
+ line-height: var(--nim-type-caption-line);
124
+ color: var(--nim-ink-tertiary);
125
+ }
126
+
127
+ .nim-rule {
128
+ block-size: var(--nim-border-width);
129
+ background: var(--nim-line);
130
+ border: 0;
131
+ inline-size: 100%;
132
+ }
133
+
134
+ /* ═══════════════════════════════════════════════════════════════════════
135
+ BUTTON
136
+ One geometry, four emphases, three sizes. The press response is a theme
137
+ decision (`--nim-press-*`): Ledger shifts into its offset shadow, Vlora
138
+ compresses.
139
+ ═══════════════════════════════════════════════════════════════════════ */
140
+ .nim-button {
141
+ position: relative;
142
+ display: inline-flex;
143
+ align-items: center;
144
+ justify-content: center;
145
+ gap: var(--nim-space-2);
146
+ min-block-size: calc(var(--nim-control-md) * var(--nim-density));
147
+ padding-inline: var(--nim-space-6);
148
+ border: var(--nim-border-width) solid transparent;
149
+ border-radius: var(--nim-radius-sm);
150
+ font-family: var(--nim-type-control-family);
151
+ font-size: var(--nim-type-control-size);
152
+ font-weight: var(--nim-type-control-weight);
153
+ letter-spacing: var(--nim-type-control-tracking);
154
+ text-transform: var(--nim-type-control-transform);
155
+ white-space: nowrap;
156
+ cursor: pointer;
157
+ background: none;
158
+ -webkit-tap-highlight-color: transparent;
159
+ transition:
160
+ background-color var(--nim-dur-fast) var(--nim-ease-standard),
161
+ border-color var(--nim-dur-fast) var(--nim-ease-standard),
162
+ color var(--nim-dur-fast) var(--nim-ease-standard),
163
+ box-shadow var(--nim-dur-fast) var(--nim-ease-standard),
164
+ scale var(--nim-dur-fast) var(--nim-ease-standard),
165
+ translate var(--nim-dur-fast) var(--nim-ease-standard);
166
+ }
167
+
168
+ .nim-button--sm {
169
+ min-block-size: calc(var(--nim-control-sm) * var(--nim-density));
170
+ padding-inline: var(--nim-space-4);
171
+ }
172
+
173
+ .nim-button--lg {
174
+ min-block-size: calc(var(--nim-control-lg) * var(--nim-density));
175
+ padding-inline: var(--nim-space-7);
176
+ }
177
+
178
+ .nim-button--full {
179
+ inline-size: 100%;
180
+ }
181
+
182
+ .nim-button--primary {
183
+ background: var(--nim-ink);
184
+ border-color: var(--nim-ink);
185
+ color: var(--nim-canvas);
186
+ }
187
+
188
+ /* Primary hovers along its own tone ramp. Jumping to the accent made the
189
+ button change hue under the pointer and made primary and accent
190
+ indistinguishable at the exact moment of deciding between them. */
191
+ .nim-button--primary:hover:not(:disabled) {
192
+ background: var(--nim-ink-secondary);
193
+ border-color: var(--nim-ink-secondary);
194
+ }
195
+
196
+ .nim-button--accent {
197
+ background: var(--nim-accent);
198
+ border-color: var(--nim-accent);
199
+ color: var(--nim-on-accent);
200
+ }
201
+
202
+ .nim-button--accent:hover:not(:disabled) {
203
+ background: var(--nim-accent-hover);
204
+ border-color: var(--nim-accent-hover);
205
+ }
206
+
207
+ .nim-button--secondary {
208
+ border-color: var(--nim-line-strong);
209
+ color: var(--nim-ink);
210
+ box-shadow: var(--nim-shadow-md);
211
+ }
212
+
213
+ .nim-button--secondary:hover:not(:disabled) {
214
+ border-color: var(--nim-ink);
215
+ }
216
+
217
+ .nim-button--ghost {
218
+ color: var(--nim-ink-secondary);
219
+ padding-inline: var(--nim-space-4);
220
+ }
221
+
222
+ .nim-button--ghost:hover:not(:disabled) {
223
+ background: var(--nim-surface-muted);
224
+ color: var(--nim-ink);
225
+ }
226
+
227
+ .nim-button--danger {
228
+ background: var(--nim-danger);
229
+ border-color: var(--nim-danger);
230
+ color: var(--nim-on-accent);
231
+ }
232
+
233
+ /* `filter: brightness()` was the one variant styled by something no theme
234
+ could answer — and it inverts in dark, pushing a light-on-dark danger
235
+ colour toward the canvas instead of away from it. */
236
+ .nim-button--danger:hover:not(:disabled) {
237
+ background: var(--nim-danger-hover);
238
+ border-color: var(--nim-danger-hover);
239
+ }
240
+
241
+ .nim-button:disabled {
242
+ opacity: 0.45;
243
+ cursor: not-allowed;
244
+ }
245
+
246
+ .nim-button--loading .nim-button__label {
247
+ opacity: 0.65;
248
+ }
249
+
250
+ .nim-button__spinner {
251
+ inline-size: var(--nim-size-icon-xs);
252
+ block-size: var(--nim-size-icon-xs);
253
+ border: 2px solid currentColor;
254
+ border-block-start-color: transparent;
255
+ border-radius: var(--nim-radius-pill);
256
+ animation: nim-spin 700ms linear infinite;
257
+ }
258
+
259
+ /* ═══════════════════════════════════════════════════════════════════════
260
+ ICON BUTTON — a square target that never falls below the touch minimum
261
+ ═══════════════════════════════════════════════════════════════════════ */
262
+ .nim-icon-button {
263
+ position: relative;
264
+ display: inline-grid;
265
+ place-items: center;
266
+ inline-size: calc(var(--nim-control-md) * var(--nim-density));
267
+ block-size: calc(var(--nim-control-md) * var(--nim-density));
268
+ border: var(--nim-border-width) solid transparent;
269
+ border-radius: var(--nim-radius-sm);
270
+ color: var(--nim-ink-secondary);
271
+ background: none;
272
+ cursor: pointer;
273
+ -webkit-tap-highlight-color: transparent;
274
+ transition:
275
+ background-color var(--nim-dur-fast) var(--nim-ease-standard),
276
+ border-color var(--nim-dur-fast) var(--nim-ease-standard),
277
+ color var(--nim-dur-fast) var(--nim-ease-standard),
278
+ scale var(--nim-dur-fast) var(--nim-ease-standard);
279
+ }
280
+
281
+ .nim-icon-button--sm {
282
+ inline-size: calc(var(--nim-control-sm) * var(--nim-density));
283
+ block-size: calc(var(--nim-control-sm) * var(--nim-density));
284
+ }
285
+
286
+ .nim-icon-button--lg {
287
+ inline-size: calc(var(--nim-control-lg) * var(--nim-density));
288
+ block-size: calc(var(--nim-control-lg) * var(--nim-density));
289
+ }
290
+
291
+ /* The contract says 44px is "never reduced, only visually inset" — which the
292
+ small variant did not honour until 0.2. The box stays 36px; the target
293
+ does not shrink with it. */
294
+ .nim-icon-button::after {
295
+ content: '';
296
+ position: absolute;
297
+ inset-block-start: 50%;
298
+ inset-inline-start: 50%;
299
+ translate: -50% -50%;
300
+ min-inline-size: var(--nim-touch-min);
301
+ min-block-size: var(--nim-touch-min);
302
+ inline-size: 100%;
303
+ block-size: 100%;
304
+ }
305
+
306
+ .nim-icon-button:hover:not(:disabled) {
307
+ background: var(--nim-surface-muted);
308
+ color: var(--nim-ink);
309
+ }
310
+
311
+ .nim-icon-button--outline {
312
+ border-color: var(--nim-line);
313
+ }
314
+
315
+ .nim-icon-button--solid {
316
+ background: var(--nim-ink);
317
+ color: var(--nim-canvas);
318
+ }
319
+
320
+ .nim-icon-button--solid:hover:not(:disabled) {
321
+ background: var(--nim-accent);
322
+ color: var(--nim-on-accent);
323
+ }
324
+
325
+ .nim-icon-button:disabled {
326
+ opacity: 0.45;
327
+ cursor: not-allowed;
328
+ }
329
+
330
+ /* ═══════════════════════════════════════════════════════════════════════
331
+ ICON
332
+ ═══════════════════════════════════════════════════════════════════════ */
333
+ .nim-icon {
334
+ flex: none;
335
+ color: currentColor;
336
+ }
337
+
338
+ /* A directional glyph travels with the reading direction. The set of which
339
+ glyphs are directional lives in `icon.tsx`, so no component decides it. */
340
+ [dir='rtl'] .nim-icon[data-flip] {
341
+ scale: -1 1;
342
+ }
343
+
344
+ .nim-icon[data-tone='accent'] {
345
+ color: var(--nim-accent);
346
+ }
347
+ .nim-icon[data-tone='muted'] {
348
+ color: var(--nim-ink-tertiary);
349
+ }
350
+ .nim-icon[data-tone='success'] {
351
+ color: var(--nim-success);
352
+ }
353
+ .nim-icon[data-tone='warning'] {
354
+ color: var(--nim-warning);
355
+ }
356
+ .nim-icon[data-tone='danger'] {
357
+ color: var(--nim-danger);
358
+ }
359
+
360
+ /* ═══════════════════════════════════════════════════════════════════════
361
+ CARD
362
+ ═══════════════════════════════════════════════════════════════════════ */
363
+ .nim-card {
364
+ position: relative;
365
+ display: block;
366
+ background: var(--nim-surface);
367
+ border: var(--nim-border-width) solid var(--nim-line);
368
+ border-radius: var(--nim-radius-lg);
369
+ color: var(--nim-ink);
370
+ }
371
+
372
+ .nim-card--muted {
373
+ background: var(--nim-surface-muted);
374
+ }
375
+
376
+ .nim-card--raised {
377
+ background: var(--nim-surface-raised);
378
+ box-shadow: var(--nim-shadow-md);
379
+ }
380
+
381
+ .nim-card--outline {
382
+ background: transparent;
383
+ }
384
+
385
+ .nim-card--accent {
386
+ background: var(--nim-accent-soft);
387
+ border-color: var(--nim-accent-line);
388
+ }
389
+
390
+ .nim-card--pad-sm {
391
+ padding: var(--nim-space-3);
392
+ }
393
+ .nim-card--pad-md {
394
+ padding: var(--nim-space-5);
395
+ }
396
+ .nim-card--pad-lg {
397
+ padding: var(--nim-space-7);
398
+ }
399
+ .nim-card--pad-none {
400
+ padding: 0;
401
+ }
402
+
403
+ /* Interactive cards are real buttons/links; this only supplies the feedback
404
+ so the whole plate reads as one target. */
405
+ .nim-card--interactive {
406
+ inline-size: 100%;
407
+ text-align: start;
408
+ cursor: pointer;
409
+ transition:
410
+ border-color var(--nim-dur-base) var(--nim-ease-standard),
411
+ box-shadow var(--nim-dur-base) var(--nim-ease-standard),
412
+ scale var(--nim-dur-fast) var(--nim-ease-standard);
413
+ }
414
+
415
+ .nim-card--interactive:hover {
416
+ border-color: var(--nim-line-strong);
417
+ box-shadow: var(--nim-shadow-lg);
418
+ }
419
+
420
+
421
+ .nim-card__header {
422
+ display: flex;
423
+ align-items: center;
424
+ justify-content: space-between;
425
+ gap: var(--nim-space-3);
426
+ padding-block-end: var(--nim-space-4);
427
+ margin-block-end: var(--nim-space-4);
428
+ border-block-end: var(--nim-border-width) solid var(--nim-line-soft);
429
+ }
430
+
431
+ .nim-card__footer {
432
+ display: flex;
433
+ align-items: center;
434
+ gap: var(--nim-space-3);
435
+ padding-block-start: var(--nim-space-4);
436
+ margin-block-start: var(--nim-space-4);
437
+ border-block-start: var(--nim-border-width) solid var(--nim-line-soft);
438
+ }
439
+
440
+ /* ═══════════════════════════════════════════════════════════════════════
441
+ BADGE
442
+ ═══════════════════════════════════════════════════════════════════════ */
443
+ .nim-badge {
444
+ display: inline-flex;
445
+ align-items: center;
446
+ gap: var(--nim-space-2);
447
+ padding-inline: var(--nim-space-3);
448
+ padding-block: var(--nim-space-1);
449
+ border: var(--nim-border-width) solid transparent;
450
+ border-radius: var(--nim-radius-xs);
451
+ font-family: var(--nim-type-label-family);
452
+ font-size: var(--nim-type-label-size);
453
+ font-weight: var(--nim-weight-medium);
454
+ letter-spacing: var(--nim-label-tracking);
455
+ text-transform: var(--nim-label-transform);
456
+ line-height: 1.5;
457
+ white-space: nowrap;
458
+
459
+ /* Each variant sets only these two custom properties; the tone rules below
460
+ decide how they are used. That is what keeps 6 variants × 3 tones from
461
+ becoming 18 rules. */
462
+ --nim-badge-ink: var(--nim-ink-secondary);
463
+ --nim-badge-wash: var(--nim-surface-muted);
464
+ }
465
+
466
+ .nim-badge--pill {
467
+ border-radius: var(--nim-radius-pill);
468
+ padding-inline: var(--nim-space-4);
469
+ }
470
+
471
+ .nim-badge--sm {
472
+ font-size: var(--nim-text-11);
473
+ padding-inline: var(--nim-space-2);
474
+ }
475
+
476
+ .nim-badge--accent {
477
+ --nim-badge-ink: var(--nim-accent);
478
+ --nim-badge-wash: var(--nim-accent-soft);
479
+ }
480
+ .nim-badge--success {
481
+ --nim-badge-ink: var(--nim-success);
482
+ --nim-badge-wash: var(--nim-success-soft);
483
+ }
484
+ .nim-badge--warning {
485
+ --nim-badge-ink: var(--nim-warning);
486
+ --nim-badge-wash: var(--nim-warning-soft);
487
+ }
488
+ .nim-badge--danger {
489
+ --nim-badge-ink: var(--nim-danger);
490
+ --nim-badge-wash: var(--nim-danger-soft);
491
+ }
492
+ .nim-badge--info {
493
+ --nim-badge-ink: var(--nim-info);
494
+ --nim-badge-wash: var(--nim-info-soft);
495
+ }
496
+
497
+ .nim-badge--soft {
498
+ background: var(--nim-badge-wash);
499
+ color: var(--nim-badge-ink);
500
+ }
501
+
502
+ .nim-badge--solid {
503
+ background: var(--nim-badge-ink);
504
+ color: var(--nim-on-accent);
505
+ }
506
+
507
+ .nim-badge--outline {
508
+ border-color: var(--nim-line-strong);
509
+ color: var(--nim-badge-ink);
510
+ }
511
+
512
+ .nim-badge__dot {
513
+ inline-size: var(--nim-size-dot);
514
+ block-size: var(--nim-size-dot);
515
+ border-radius: var(--nim-radius-pill);
516
+ background: currentColor;
517
+ flex: none;
518
+ }
519
+
520
+ /* ═══════════════════════════════════════════════════════════════════════
521
+ FIELD — the shared frame for every form control
522
+ ═══════════════════════════════════════════════════════════════════════ */
523
+ .nim-field {
524
+ display: grid;
525
+ gap: var(--nim-space-2);
526
+ inline-size: 100%;
527
+ }
528
+
529
+ .nim-field__label {
530
+ font-family: var(--nim-type-label-family);
531
+ font-size: var(--nim-type-label-size);
532
+ font-weight: var(--nim-weight-medium);
533
+ letter-spacing: var(--nim-label-tracking);
534
+ text-transform: var(--nim-label-transform);
535
+ color: var(--nim-ink-secondary);
536
+ }
537
+
538
+ .nim-field__required {
539
+ color: var(--nim-accent);
540
+ margin-inline-start: var(--nim-space-1);
541
+ }
542
+
543
+ .nim-field__hint,
544
+ .nim-field__error {
545
+ font-size: var(--nim-type-caption-size);
546
+ line-height: var(--nim-type-caption-line);
547
+ }
548
+
549
+ .nim-field__hint {
550
+ color: var(--nim-ink-tertiary);
551
+ }
552
+
553
+ .nim-field__error {
554
+ color: var(--nim-danger);
555
+ }
556
+
557
+ .nim-input,
558
+ .nim-textarea,
559
+ .nim-select {
560
+ inline-size: 100%;
561
+ min-block-size: calc(var(--nim-control-md) * var(--nim-density));
562
+ padding-inline: var(--nim-space-4);
563
+ padding-block: var(--nim-space-2);
564
+ background: var(--nim-surface);
565
+ border: var(--nim-border-width) solid var(--nim-line);
566
+ border-radius: var(--nim-radius-sm);
567
+ color: var(--nim-ink);
568
+ font-size: var(--nim-type-body-size);
569
+ transition:
570
+ border-color var(--nim-dur-fast) var(--nim-ease-standard),
571
+ background-color var(--nim-dur-fast) var(--nim-ease-standard);
572
+ }
573
+
574
+ .nim-input::placeholder,
575
+ .nim-textarea::placeholder {
576
+ color: var(--nim-ink-tertiary);
577
+ }
578
+
579
+ .nim-input:hover:not(:disabled),
580
+ .nim-textarea:hover:not(:disabled),
581
+ .nim-select:hover:not(:disabled) {
582
+ border-color: var(--nim-line-strong);
583
+ }
584
+
585
+ /* The ring comes from the shared focus rule at the top of this layer; the
586
+ border colour is the resting-state half of the same signal. A 1px hue
587
+ shift is not a focus indicator on its own. */
588
+ .nim-input:focus-visible,
589
+ .nim-textarea:focus-visible,
590
+ .nim-select:focus-visible {
591
+ border-color: var(--nim-accent);
592
+ }
593
+
594
+ .nim-input:disabled,
595
+ .nim-textarea:disabled,
596
+ .nim-select:disabled {
597
+ opacity: 0.5;
598
+ cursor: not-allowed;
599
+ background: var(--nim-surface-muted);
600
+ }
601
+
602
+ .nim-field--invalid :is(.nim-input, .nim-textarea, .nim-select) {
603
+ border-color: var(--nim-danger);
604
+ }
605
+
606
+ /* An invalid field focuses in danger, so the ring never contradicts the
607
+ error message printed directly under it. */
608
+ .nim-field--invalid :is(.nim-input, .nim-textarea, .nim-select):focus-visible {
609
+ border-color: var(--nim-danger);
610
+ box-shadow: var(--nim-shadow-focus-danger);
611
+ }
612
+
613
+ .nim-textarea {
614
+ min-block-size: calc(calc(var(--nim-control-md) * var(--nim-density)) * 2);
615
+ resize: vertical;
616
+ line-height: var(--nim-type-body-line);
617
+ }
618
+
619
+ .nim-select {
620
+ appearance: none;
621
+ /* Room for the chevron the component renders on the trailing edge. */
622
+ padding-inline-end: var(--nim-space-9);
623
+ }
624
+
625
+ .nim-input-shell {
626
+ position: relative;
627
+ display: flex;
628
+ align-items: center;
629
+ }
630
+
631
+ .nim-input-shell__affix {
632
+ position: absolute;
633
+ inset-block: 0;
634
+ display: grid;
635
+ place-items: center;
636
+ inline-size: var(--nim-space-9);
637
+ color: var(--nim-ink-tertiary);
638
+ pointer-events: none;
639
+ }
640
+
641
+ .nim-input-shell__affix--start {
642
+ inset-inline-start: 0;
643
+ }
644
+ .nim-input-shell__affix--end {
645
+ inset-inline-end: 0;
646
+ }
647
+
648
+ .nim-input-shell--has-start .nim-input {
649
+ padding-inline-start: var(--nim-space-9);
650
+ }
651
+ .nim-input-shell--has-end .nim-input {
652
+ padding-inline-end: var(--nim-space-9);
653
+ }
654
+
655
+ /* ═══════════════════════════════════════════════════════════════════════
656
+ CHECKBOX & SWITCH
657
+ Both are real inputs with the native control hidden but focusable, so
658
+ keyboard behaviour, form submission, and assistive tech are untouched.
659
+ ═══════════════════════════════════════════════════════════════════════ */
660
+ .nim-choice {
661
+ display: inline-flex;
662
+ align-items: flex-start;
663
+ gap: var(--nim-space-3);
664
+ min-block-size: var(--nim-touch-min);
665
+ padding-block: var(--nim-space-2);
666
+ cursor: pointer;
667
+ }
668
+
669
+ .nim-choice__input {
670
+ position: absolute;
671
+ opacity: 0;
672
+ inline-size: 1px;
673
+ block-size: 1px;
674
+ }
675
+
676
+ .nim-choice__text {
677
+ font-size: var(--nim-type-body-sm-size);
678
+ line-height: var(--nim-leading-normal);
679
+ }
680
+
681
+ .nim-choice__description {
682
+ display: block;
683
+ font-size: var(--nim-type-caption-size);
684
+ color: var(--nim-ink-tertiary);
685
+ }
686
+
687
+ .nim-choice:has(.nim-choice__input:disabled) {
688
+ opacity: 0.5;
689
+ cursor: not-allowed;
690
+ }
691
+
692
+ .nim-checkbox__box {
693
+ flex: none;
694
+ display: grid;
695
+ place-items: center;
696
+ inline-size: 20px;
697
+ block-size: 20px;
698
+ margin-block-start: 2px;
699
+ border: var(--nim-border-width) solid var(--nim-line-strong);
700
+ border-radius: var(--nim-radius-xs);
701
+ background: var(--nim-surface);
702
+ color: transparent;
703
+ transition:
704
+ background-color var(--nim-dur-fast) var(--nim-ease-standard),
705
+ border-color var(--nim-dur-fast) var(--nim-ease-standard),
706
+ color var(--nim-dur-fast) var(--nim-ease-standard);
707
+ }
708
+
709
+ .nim-choice__input:checked + .nim-checkbox__box {
710
+ background: var(--nim-accent);
711
+ border-color: var(--nim-accent);
712
+ color: var(--nim-on-accent);
713
+ }
714
+
715
+ .nim-choice__input:focus-visible + .nim-checkbox__box {
716
+ box-shadow: var(--nim-shadow-focus);
717
+ }
718
+
719
+ .nim-switch__track {
720
+ flex: none;
721
+ position: relative;
722
+ inline-size: 44px;
723
+ block-size: 26px;
724
+ margin-block-start: 1px;
725
+ border: var(--nim-border-width) solid var(--nim-line-strong);
726
+ border-radius: var(--nim-radius-pill);
727
+ background: var(--nim-surface-muted);
728
+ transition:
729
+ background-color var(--nim-dur-base) var(--nim-ease-standard),
730
+ border-color var(--nim-dur-base) var(--nim-ease-standard);
731
+ }
732
+
733
+ .nim-switch__thumb {
734
+ position: absolute;
735
+ inset-block-start: 3px;
736
+ inset-inline-start: 3px;
737
+ inline-size: 18px;
738
+ block-size: 18px;
739
+ border-radius: var(--nim-radius-pill);
740
+ background: var(--nim-ink);
741
+ transition: translate var(--nim-dur-base) var(--nim-ease-spring);
742
+ }
743
+
744
+ .nim-choice__input:checked + .nim-switch__track {
745
+ background: var(--nim-accent);
746
+ border-color: var(--nim-accent);
747
+ }
748
+
749
+ .nim-choice__input:checked + .nim-switch__track .nim-switch__thumb {
750
+ translate: 18px 0;
751
+ background: var(--nim-on-accent);
752
+ }
753
+
754
+ /* The thumb travels toward the reading edge in either direction. */
755
+ [dir='rtl'] .nim-choice__input:checked + .nim-switch__track .nim-switch__thumb {
756
+ translate: -18px 0;
757
+ }
758
+
759
+ .nim-choice__input:focus-visible + .nim-switch__track {
760
+ box-shadow: var(--nim-shadow-focus);
761
+ }
762
+
763
+ /* ═══════════════════════════════════════════════════════════════════════
764
+ SLIDER
765
+ ═══════════════════════════════════════════════════════════════════════ */
766
+ .nim-slider {
767
+ inline-size: 100%;
768
+ block-size: var(--nim-touch-min);
769
+ background: transparent;
770
+ appearance: none;
771
+ cursor: pointer;
772
+ }
773
+
774
+ .nim-slider::-webkit-slider-runnable-track {
775
+ block-size: 3px;
776
+ border-radius: var(--nim-radius-pill);
777
+ background: linear-gradient(
778
+ to right,
779
+ var(--nim-accent) var(--nim-slider-progress, 50%),
780
+ var(--nim-line) var(--nim-slider-progress, 50%)
781
+ );
782
+ }
783
+
784
+ .nim-slider::-moz-range-track {
785
+ block-size: 3px;
786
+ border-radius: var(--nim-radius-pill);
787
+ background: linear-gradient(
788
+ to right,
789
+ var(--nim-accent) var(--nim-slider-progress, 50%),
790
+ var(--nim-line) var(--nim-slider-progress, 50%)
791
+ );
792
+ }
793
+
794
+ .nim-slider::-webkit-slider-thumb {
795
+ appearance: none;
796
+ inline-size: 18px;
797
+ block-size: 18px;
798
+ margin-block-start: -7px;
799
+ border: 0;
800
+ border-radius: var(--nim-radius-pill);
801
+ background: var(--nim-ink);
802
+ box-shadow: var(--nim-shadow-sm);
803
+ }
804
+
805
+ .nim-slider::-moz-range-thumb {
806
+ inline-size: 18px;
807
+ block-size: 18px;
808
+ border: 0;
809
+ border-radius: var(--nim-radius-pill);
810
+ background: var(--nim-ink);
811
+ }
812
+
813
+ .nim-slider:focus-visible {
814
+ outline: none;
815
+ }
816
+
817
+ .nim-slider:focus-visible::-webkit-slider-thumb {
818
+ box-shadow: var(--nim-shadow-focus);
819
+ }
820
+
821
+ .nim-slider:focus-visible::-moz-range-thumb {
822
+ box-shadow: var(--nim-shadow-focus);
823
+ }
824
+
825
+ .nim-slider:disabled {
826
+ opacity: 0.5;
827
+ cursor: not-allowed;
828
+ }
829
+
830
+ /* ═══════════════════════════════════════════════════════════════════════
831
+ LIST
832
+ A grouped list is one ruled block, not a stack of cards — which is why
833
+ the divider lives on the group rather than on the row.
834
+ ═══════════════════════════════════════════════════════════════════════ */
835
+ .nim-list {
836
+ display: flex;
837
+ flex-direction: column;
838
+ background: var(--nim-surface);
839
+ border: var(--nim-border-width) solid var(--nim-line);
840
+ border-radius: var(--nim-radius-lg);
841
+ overflow: hidden;
842
+ }
843
+
844
+ .nim-list--plain {
845
+ background: transparent;
846
+ border: 0;
847
+ border-radius: 0;
848
+ }
849
+
850
+ .nim-list > * + * {
851
+ border-block-start: var(--nim-border-width) solid var(--nim-line-soft);
852
+ }
853
+
854
+ .nim-list-row {
855
+ display: flex;
856
+ align-items: center;
857
+ gap: var(--nim-space-4);
858
+ inline-size: 100%;
859
+ /* Rows render as <button> or <a> when interactive, so the platform's own
860
+ button chrome has to be cleared explicitly. */
861
+ border: 0;
862
+ min-block-size: var(--nim-touch-min);
863
+ padding: calc(var(--nim-space-4) * var(--nim-density)) var(--nim-space-5);
864
+ text-align: start;
865
+ background: none;
866
+ color: inherit;
867
+ transition: background-color var(--nim-dur-fast) var(--nim-ease-standard);
868
+ }
869
+
870
+ .nim-list-row--interactive {
871
+ cursor: pointer;
872
+ }
873
+
874
+ .nim-list-row--interactive:hover {
875
+ background: var(--nim-surface-muted);
876
+ }
877
+
878
+ .nim-list-row--interactive:active {
879
+ background: var(--nim-canvas-sunken);
880
+ }
881
+
882
+ .nim-list-row__leading,
883
+ .nim-list-row__trailing {
884
+ flex: none;
885
+ display: flex;
886
+ align-items: center;
887
+ gap: var(--nim-space-2);
888
+ color: var(--nim-ink-tertiary);
889
+ }
890
+
891
+ .nim-list-row__content {
892
+ flex: 1;
893
+ min-inline-size: 0;
894
+ }
895
+
896
+ .nim-list-row__title {
897
+ display: block;
898
+ font-size: var(--nim-type-body-size);
899
+ font-weight: var(--nim-weight-medium);
900
+ line-height: var(--nim-leading-normal);
901
+ }
902
+
903
+ .nim-list-row__subtitle {
904
+ display: block;
905
+ margin-block-start: var(--nim-space-1);
906
+ font-size: var(--nim-type-caption-size);
907
+ line-height: var(--nim-type-caption-line);
908
+ color: var(--nim-ink-tertiary);
909
+ }
910
+
911
+ /* The chevron points the way the reader travels. */
912
+ .nim-list-row__chevron {
913
+ color: var(--nim-ink-tertiary);
914
+ transition: translate var(--nim-dur-fast) var(--nim-ease-standard);
915
+ }
916
+
917
+ .nim-list-row--interactive:hover .nim-list-row__chevron {
918
+ translate: 3px 0;
919
+ color: var(--nim-accent);
920
+ }
921
+
922
+ [dir='rtl'] .nim-list-row--interactive:hover .nim-list-row__chevron {
923
+ translate: -3px 0;
924
+ }
925
+
926
+ /* ═══════════════════════════════════════════════════════════════════════
927
+ SECTION HEADER
928
+ ═══════════════════════════════════════════════════════════════════════ */
929
+ .nim-section-header {
930
+ display: flex;
931
+ align-items: flex-end;
932
+ justify-content: space-between;
933
+ gap: var(--nim-space-4);
934
+ inline-size: 100%;
935
+ }
936
+
937
+ .nim-section-header__eyebrow {
938
+ display: inline-flex;
939
+ align-items: center;
940
+ gap: var(--nim-space-2);
941
+ margin-block-end: var(--nim-space-2);
942
+ }
943
+
944
+ .nim-section-header__eyebrow::before {
945
+ content: '';
946
+ inline-size: var(--nim-size-dot);
947
+ block-size: var(--nim-size-dot);
948
+ background: var(--nim-accent);
949
+ border-radius: var(--nim-radius-xs);
950
+ flex: none;
951
+ }
952
+
953
+ .nim-section-header__description {
954
+ margin-block-start: var(--nim-space-2);
955
+ max-inline-size: var(--nim-measure);
956
+ }
957
+
958
+ /* ═══════════════════════════════════════════════════════════════════════
959
+ STAT — a figure and what it means
960
+ ═══════════════════════════════════════════════════════════════════════ */
961
+ .nim-stat {
962
+ display: grid;
963
+ gap: var(--nim-space-2);
964
+ }
965
+
966
+ .nim-stat__value {
967
+ font-family: var(--nim-font-numeric);
968
+ /* A figure that updates in place must not shift the ones beside it. */
969
+ font-variant-numeric: tabular-nums;
970
+ font-size: var(--nim-text-32);
971
+ font-weight: var(--nim-weight-semibold);
972
+ line-height: 1;
973
+ letter-spacing: var(--nim-tracking-tight);
974
+ color: var(--nim-ink);
975
+ }
976
+
977
+ .nim-stat__unit {
978
+ font-size: var(--nim-type-caption-size);
979
+ color: var(--nim-ink-tertiary);
980
+ margin-inline-start: var(--nim-space-1);
981
+ }
982
+
983
+ .nim-stat__label {
984
+ color: var(--nim-ink-tertiary);
985
+ }
986
+
987
+ .nim-stat__delta {
988
+ display: inline-flex;
989
+ align-items: center;
990
+ gap: var(--nim-space-1);
991
+ font-size: var(--nim-type-caption-size);
992
+ }
993
+
994
+ .nim-stat__delta[data-direction='up'] {
995
+ color: var(--nim-success);
996
+ }
997
+ .nim-stat__delta[data-direction='down'] {
998
+ color: var(--nim-danger);
999
+ }
1000
+
1001
+ /* ═══════════════════════════════════════════════════════════════════════
1002
+ BANNER
1003
+ ═══════════════════════════════════════════════════════════════════════ */
1004
+ .nim-banner {
1005
+ display: flex;
1006
+ align-items: flex-start;
1007
+ gap: var(--nim-space-3);
1008
+ padding: var(--nim-space-4);
1009
+ border: var(--nim-border-width) solid transparent;
1010
+ border-radius: var(--nim-radius-md);
1011
+ background: var(--nim-surface-muted);
1012
+ color: var(--nim-ink-secondary);
1013
+ font-size: var(--nim-type-body-sm-size);
1014
+ line-height: var(--nim-leading-normal);
1015
+
1016
+ --nim-banner-ink: var(--nim-ink-secondary);
1017
+ }
1018
+
1019
+ .nim-banner--accent {
1020
+ background: var(--nim-accent-soft);
1021
+ border-color: var(--nim-accent-line);
1022
+ --nim-banner-ink: var(--nim-accent);
1023
+ }
1024
+ .nim-banner--success {
1025
+ background: var(--nim-success-soft);
1026
+ --nim-banner-ink: var(--nim-success);
1027
+ }
1028
+ .nim-banner--warning {
1029
+ background: var(--nim-warning-soft);
1030
+ --nim-banner-ink: var(--nim-warning);
1031
+ }
1032
+ .nim-banner--danger {
1033
+ background: var(--nim-danger-soft);
1034
+ --nim-banner-ink: var(--nim-danger);
1035
+ }
1036
+ .nim-banner--info {
1037
+ background: var(--nim-info-soft);
1038
+ --nim-banner-ink: var(--nim-info);
1039
+ }
1040
+
1041
+ .nim-banner__icon {
1042
+ color: var(--nim-banner-ink);
1043
+ margin-block-start: 1px;
1044
+ }
1045
+
1046
+ .nim-banner__title {
1047
+ font-weight: var(--nim-weight-medium);
1048
+ color: var(--nim-ink);
1049
+ }
1050
+
1051
+ .nim-banner__content {
1052
+ flex: 1;
1053
+ min-inline-size: 0;
1054
+ display: grid;
1055
+ gap: var(--nim-space-1);
1056
+ }
1057
+
1058
+ /* ═══════════════════════════════════════════════════════════════════════
1059
+ EMPTY STATE
1060
+ ═══════════════════════════════════════════════════════════════════════ */
1061
+ .nim-empty {
1062
+ display: grid;
1063
+ justify-items: center;
1064
+ gap: var(--nim-space-3);
1065
+ padding: var(--nim-space-9) var(--nim-space-5);
1066
+ text-align: center;
1067
+ }
1068
+
1069
+ .nim-empty__icon {
1070
+ display: grid;
1071
+ place-items: center;
1072
+ inline-size: 48px;
1073
+ block-size: 48px;
1074
+ border: var(--nim-border-width) solid var(--nim-line);
1075
+ border-radius: var(--nim-radius-md);
1076
+ color: var(--nim-ink-tertiary);
1077
+ margin-block-end: var(--nim-space-2);
1078
+ }
1079
+
1080
+ .nim-empty__body {
1081
+ max-inline-size: 42ch;
1082
+ }
1083
+
1084
+ .nim-empty__actions {
1085
+ display: flex;
1086
+ flex-wrap: wrap;
1087
+ justify-content: center;
1088
+ gap: var(--nim-space-3);
1089
+ margin-block-start: var(--nim-space-3);
1090
+ }
1091
+
1092
+ /* ═══════════════════════════════════════════════════════════════════════
1093
+ SEGMENTED CONTROL
1094
+ ═══════════════════════════════════════════════════════════════════════ */
1095
+ .nim-segmented {
1096
+ display: inline-flex;
1097
+ padding: var(--nim-space-1);
1098
+ background: var(--nim-surface-muted);
1099
+ border: var(--nim-border-width) solid var(--nim-line);
1100
+ border-radius: var(--nim-radius-md);
1101
+ gap: var(--nim-space-1);
1102
+ }
1103
+
1104
+ .nim-segmented--full {
1105
+ display: flex;
1106
+ inline-size: 100%;
1107
+ }
1108
+
1109
+ .nim-segmented__option {
1110
+ flex: 1;
1111
+ min-block-size: calc(var(--nim-control-sm) * var(--nim-density));
1112
+ padding-inline: var(--nim-space-4);
1113
+ border: var(--nim-border-width) solid transparent;
1114
+ border-radius: var(--nim-radius-xs);
1115
+ font-family: var(--nim-type-control-family);
1116
+ font-size: var(--nim-type-control-size);
1117
+ font-weight: var(--nim-type-control-weight);
1118
+ letter-spacing: var(--nim-type-control-tracking);
1119
+ text-transform: var(--nim-type-control-transform);
1120
+ color: var(--nim-ink-tertiary);
1121
+ white-space: nowrap;
1122
+ cursor: pointer;
1123
+ transition:
1124
+ background-color var(--nim-dur-fast) var(--nim-ease-standard),
1125
+ color var(--nim-dur-fast) var(--nim-ease-standard);
1126
+ }
1127
+
1128
+ .nim-segmented__option:hover {
1129
+ color: var(--nim-ink);
1130
+ }
1131
+
1132
+ /* A real border on four sides. `--nim-shadow-sm` is a bottom hairline on the
1133
+ ledger presets, so the selected segment read as an underline against a
1134
+ track only a few percent away from it. */
1135
+ .nim-segmented__option[aria-selected='true'] {
1136
+ background: var(--nim-surface);
1137
+ color: var(--nim-ink);
1138
+ border-color: var(--nim-line-strong);
1139
+ }
1140
+
1141
+ /* ═══════════════════════════════════════════════════════════════════════
1142
+ AVATAR
1143
+ ═══════════════════════════════════════════════════════════════════════ */
1144
+ .nim-avatar {
1145
+ position: relative;
1146
+ display: grid;
1147
+ place-items: center;
1148
+ flex: none;
1149
+ inline-size: var(--nim-size-avatar-md);
1150
+ block-size: var(--nim-size-avatar-md);
1151
+ border-radius: var(--nim-radius-pill);
1152
+ background: var(--nim-surface-muted);
1153
+ border: var(--nim-border-width) solid var(--nim-line);
1154
+ color: var(--nim-ink-secondary);
1155
+ font-size: var(--nim-type-caption-size);
1156
+ font-weight: var(--nim-weight-medium);
1157
+ overflow: hidden;
1158
+ }
1159
+
1160
+ .nim-avatar--sm {
1161
+ inline-size: var(--nim-size-avatar-sm);
1162
+ block-size: var(--nim-size-avatar-sm);
1163
+ font-size: var(--nim-text-11);
1164
+ }
1165
+ .nim-avatar--lg {
1166
+ inline-size: var(--nim-size-avatar-lg);
1167
+ block-size: var(--nim-size-avatar-lg);
1168
+ font-size: var(--nim-text-16);
1169
+ }
1170
+ .nim-avatar--square {
1171
+ border-radius: var(--nim-radius-md);
1172
+ }
1173
+
1174
+ .nim-avatar img {
1175
+ inline-size: 100%;
1176
+ block-size: 100%;
1177
+ object-fit: cover;
1178
+ }
1179
+
1180
+ /* ═══════════════════════════════════════════════════════════════════════
1181
+ PROGRESS · SPINNER · SKELETON
1182
+ ═══════════════════════════════════════════════════════════════════════ */
1183
+ .nim-progress {
1184
+ inline-size: 100%;
1185
+ block-size: var(--nim-size-track);
1186
+ background: var(--nim-line-soft);
1187
+ border-radius: var(--nim-radius-pill);
1188
+ overflow: hidden;
1189
+ }
1190
+
1191
+ .nim-progress__fill {
1192
+ block-size: 100%;
1193
+ background: var(--nim-accent);
1194
+ border-radius: inherit;
1195
+ transition: inline-size var(--nim-dur-slow) var(--nim-ease-decelerate);
1196
+ }
1197
+
1198
+ .nim-progress--indeterminate .nim-progress__fill {
1199
+ inline-size: 40%;
1200
+ animation: nim-slide 1.2s var(--nim-ease-standard) infinite;
1201
+ }
1202
+
1203
+ .nim-spinner {
1204
+ display: inline-block;
1205
+ inline-size: var(--nim-size-icon-md);
1206
+ block-size: var(--nim-size-icon-md);
1207
+ border: 2px solid var(--nim-line);
1208
+ border-block-start-color: var(--nim-accent);
1209
+ border-radius: var(--nim-radius-pill);
1210
+ animation: nim-spin 700ms linear infinite;
1211
+ }
1212
+
1213
+ .nim-spinner--sm {
1214
+ inline-size: var(--nim-size-icon-xs);
1215
+ block-size: var(--nim-size-icon-xs);
1216
+ border-width: 2px;
1217
+ }
1218
+ .nim-spinner--lg {
1219
+ inline-size: var(--nim-size-icon-xl);
1220
+ block-size: var(--nim-size-icon-xl);
1221
+ border-width: 3px;
1222
+ }
1223
+
1224
+ .nim-skeleton {
1225
+ display: block;
1226
+ background: var(--nim-surface-muted);
1227
+ border-radius: var(--nim-radius-xs);
1228
+ position: relative;
1229
+ overflow: hidden;
1230
+ }
1231
+
1232
+ .nim-skeleton::after {
1233
+ content: '';
1234
+ position: absolute;
1235
+ inset: 0;
1236
+ background: linear-gradient(90deg, transparent, var(--nim-line-soft), transparent);
1237
+ animation: nim-sweep 1.4s var(--nim-ease-standard) infinite;
1238
+ }
1239
+
1240
+ /* ═══════════════════════════════════════════════════════════════════════
1241
+ SHEET — the bottom sheet, nim's primary modal surface on mobile
1242
+ ═══════════════════════════════════════════════════════════════════════ */
1243
+ .nim-sheet__scrim {
1244
+ position: fixed;
1245
+ inset: 0;
1246
+ z-index: var(--nim-z-scrim);
1247
+ background: var(--nim-scrim);
1248
+ animation: nim-fade-in var(--nim-dur-base) var(--nim-ease-standard);
1249
+ }
1250
+
1251
+ .nim-sheet__panel {
1252
+ position: fixed;
1253
+ inset-inline: 0;
1254
+ inset-block-end: 0;
1255
+ z-index: var(--nim-z-sheet);
1256
+ display: flex;
1257
+ flex-direction: column;
1258
+ max-block-size: min(88dvh, 720px);
1259
+ padding-block-end: calc(var(--nim-space-5) + var(--nim-safe-bottom));
1260
+ margin-inline: auto;
1261
+ inline-size: min(100%, var(--nim-frame-max));
1262
+ background: var(--nim-surface);
1263
+ border-block-start: var(--nim-border-width) solid var(--nim-line);
1264
+ border-start-start-radius: var(--nim-radius-xl);
1265
+ border-start-end-radius: var(--nim-radius-xl);
1266
+ box-shadow: var(--nim-shadow-lg);
1267
+ animation: nim-rise var(--nim-dur-base) var(--nim-ease-decelerate);
1268
+ }
1269
+
1270
+ .nim-sheet__handle {
1271
+ inline-size: var(--nim-size-handle);
1272
+ block-size: var(--nim-size-handle-thickness);
1273
+ margin: var(--nim-space-3) auto var(--nim-space-1);
1274
+ border-radius: var(--nim-radius-pill);
1275
+ background: var(--nim-line-strong);
1276
+ flex: none;
1277
+ }
1278
+
1279
+ .nim-sheet__header {
1280
+ display: flex;
1281
+ align-items: center;
1282
+ justify-content: space-between;
1283
+ gap: var(--nim-space-3);
1284
+ padding: var(--nim-space-4) var(--nim-space-5);
1285
+ border-block-end: var(--nim-border-width) solid var(--nim-line-soft);
1286
+ flex: none;
1287
+ }
1288
+
1289
+ .nim-sheet__body {
1290
+ padding: var(--nim-space-5);
1291
+ overflow-y: auto;
1292
+ overscroll-behavior: contain;
1293
+ }
1294
+
1295
+ .nim-sheet__footer {
1296
+ display: flex;
1297
+ gap: var(--nim-space-3);
1298
+ padding: var(--nim-space-4) var(--nim-space-5) 0;
1299
+ border-block-start: var(--nim-border-width) solid var(--nim-line-soft);
1300
+ flex: none;
1301
+ }
1302
+
1303
+ /* ═══════════════════════════════════════════════════════════════════════
1304
+ TOAST
1305
+ ═══════════════════════════════════════════════════════════════════════ */
1306
+ .nim-toast-stack {
1307
+ position: fixed;
1308
+ inset-block-end: calc(var(--nim-space-5) + var(--nim-safe-bottom));
1309
+ inset-inline: 0;
1310
+ z-index: var(--nim-z-toast);
1311
+ display: grid;
1312
+ gap: var(--nim-space-2);
1313
+ justify-items: center;
1314
+ padding-inline: var(--nim-space-4);
1315
+ pointer-events: none;
1316
+ }
1317
+
1318
+ .nim-toast {
1319
+ display: flex;
1320
+ align-items: center;
1321
+ gap: var(--nim-space-3);
1322
+ inline-size: min(100%, 440px);
1323
+ padding: var(--nim-space-3) var(--nim-space-4);
1324
+ background: var(--nim-ink);
1325
+ color: var(--nim-canvas);
1326
+ border-radius: var(--nim-radius-md);
1327
+ box-shadow: var(--nim-shadow-lg);
1328
+ font-size: var(--nim-type-body-sm-size);
1329
+ pointer-events: auto;
1330
+ animation: nim-rise var(--nim-dur-base) var(--nim-ease-spring);
1331
+ }
1332
+
1333
+ .nim-toast__icon {
1334
+ flex: none;
1335
+ }
1336
+ .nim-toast--success .nim-toast__icon {
1337
+ color: var(--nim-success);
1338
+ }
1339
+ .nim-toast--danger .nim-toast__icon {
1340
+ color: var(--nim-danger);
1341
+ }
1342
+ .nim-toast--accent .nim-toast__icon {
1343
+ color: var(--nim-accent);
1344
+ }
1345
+
1346
+ .nim-toast__message {
1347
+ flex: 1;
1348
+ min-inline-size: 0;
1349
+ }
1350
+
1351
+ .nim-toast__action {
1352
+ flex: none;
1353
+ font-family: var(--nim-type-label-family);
1354
+ font-size: var(--nim-type-label-size);
1355
+ letter-spacing: var(--nim-label-tracking);
1356
+ text-transform: var(--nim-label-transform);
1357
+ color: var(--nim-accent);
1358
+ cursor: pointer;
1359
+ }
1360
+
1361
+ /* ═══════════════════════════════════════════════════════════════════════
1362
+ APP FRAME — the mobile viewport, centred on a desktop screen
1363
+ ═══════════════════════════════════════════════════════════════════════ */
1364
+ .nim-app-frame {
1365
+ position: relative;
1366
+ isolation: isolate;
1367
+ inline-size: min(100%, var(--nim-frame-max));
1368
+ margin-inline: auto;
1369
+ min-block-size: 100%;
1370
+ background: var(--nim-canvas);
1371
+ }
1372
+
1373
+ .nim-stack {
1374
+ display: grid;
1375
+ gap: var(--nim-space-4);
1376
+ }
1377
+ .nim-stack--tight {
1378
+ gap: var(--nim-space-2);
1379
+ }
1380
+ .nim-stack--loose {
1381
+ gap: var(--nim-space-7);
1382
+ }
1383
+
1384
+ .nim-inline {
1385
+ display: flex;
1386
+ align-items: center;
1387
+ flex-wrap: wrap;
1388
+ gap: var(--nim-space-3);
1389
+ }
1390
+
1391
+ /* ═══════════════════════════════════════════════════════════════════════
1392
+ MENU — a list of actions, dismissed by choosing one
1393
+ Anchored by the component to its trigger; this file owns only how it
1394
+ looks. A menu holds actions, never inputs — that is a popover.
1395
+ ═══════════════════════════════════════════════════════════════════════ */
1396
+ .nim-menu {
1397
+ position: fixed;
1398
+ z-index: var(--nim-z-nav);
1399
+ min-inline-size: 220px;
1400
+ max-inline-size: min(320px, 100vw - var(--nim-space-8));
1401
+ padding-block: var(--nim-space-1);
1402
+ background: var(--nim-surface-raised);
1403
+ border: var(--nim-border-width) solid var(--nim-line-strong);
1404
+ border-radius: var(--nim-radius-md);
1405
+ box-shadow: var(--nim-shadow-lg);
1406
+ animation: nim-pop var(--nim-dur-fast) var(--nim-ease-decelerate);
1407
+ }
1408
+
1409
+ .nim-menu__item {
1410
+ display: flex;
1411
+ align-items: center;
1412
+ gap: var(--nim-space-3);
1413
+ inline-size: 100%;
1414
+ min-block-size: calc(var(--nim-control-sm) * var(--nim-density));
1415
+ padding-inline: var(--nim-space-4);
1416
+ border: 0;
1417
+ background: none;
1418
+ text-align: start;
1419
+ color: var(--nim-ink);
1420
+ font-family: var(--nim-type-control-family);
1421
+ font-size: var(--nim-type-control-size);
1422
+ font-weight: var(--nim-weight-regular);
1423
+ letter-spacing: var(--nim-type-control-tracking);
1424
+ cursor: pointer;
1425
+ transition: background-color var(--nim-dur-fast) var(--nim-ease-standard);
1426
+ }
1427
+
1428
+ .nim-menu__item:hover:not(:disabled),
1429
+ .nim-menu__item[data-active='true'] {
1430
+ background: var(--nim-surface-muted);
1431
+ }
1432
+
1433
+ .nim-menu__item:disabled {
1434
+ opacity: 0.45;
1435
+ cursor: not-allowed;
1436
+ }
1437
+
1438
+ .nim-menu__item--danger {
1439
+ color: var(--nim-danger);
1440
+ }
1441
+
1442
+ .nim-menu__icon {
1443
+ flex: none;
1444
+ color: var(--nim-ink-tertiary);
1445
+ }
1446
+
1447
+ .nim-menu__item--danger .nim-menu__icon {
1448
+ color: currentColor;
1449
+ }
1450
+
1451
+ /* Shortcut hints stay in the mono — the one place on a control where the
1452
+ machine-shaped voice is the right one. */
1453
+ .nim-menu__shortcut {
1454
+ margin-inline-start: auto;
1455
+ font-family: var(--nim-font-mono);
1456
+ font-size: var(--nim-text-11);
1457
+ color: var(--nim-ink-tertiary);
1458
+ }
1459
+
1460
+ .nim-menu__label {
1461
+ padding: var(--nim-space-2) var(--nim-space-4) var(--nim-space-1);
1462
+ font-family: var(--nim-type-label-family);
1463
+ font-size: var(--nim-text-11);
1464
+ font-weight: var(--nim-weight-medium);
1465
+ letter-spacing: var(--nim-label-tracking);
1466
+ text-transform: var(--nim-label-transform);
1467
+ color: var(--nim-ink-tertiary);
1468
+ }
1469
+
1470
+ .nim-menu__separator {
1471
+ block-size: var(--nim-border-width);
1472
+ margin-block: var(--nim-space-1);
1473
+ background: var(--nim-line-soft);
1474
+ border: 0;
1475
+ }
1476
+
1477
+ /* ═══════════════════════════════════════════════════════════════════════
1478
+ DIALOG — the centred modal, for a decision that must be made now
1479
+ The sheet remains the mobile-first surface; a dialog is what a desktop
1480
+ confirmation wants, and it renders as a real <dialog> so the top layer and
1481
+ the focus trap come from the platform.
1482
+ ═══════════════════════════════════════════════════════════════════════ */
1483
+ .nim-dialog {
1484
+ inline-size: min(100% - var(--nim-space-7), 440px);
1485
+ max-block-size: min(84dvh, 720px);
1486
+ padding: 0;
1487
+ display: flex;
1488
+ flex-direction: column;
1489
+ background: var(--nim-surface);
1490
+ color: var(--nim-ink);
1491
+ border: var(--nim-border-width) solid var(--nim-line-strong);
1492
+ border-radius: var(--nim-radius-lg);
1493
+ box-shadow: var(--nim-shadow-lg);
1494
+ }
1495
+
1496
+ .nim-dialog[open] {
1497
+ animation: nim-rise var(--nim-dur-base) var(--nim-ease-decelerate);
1498
+ }
1499
+
1500
+ .nim-dialog::backdrop {
1501
+ background: var(--nim-scrim);
1502
+ animation: nim-fade-in var(--nim-dur-base) var(--nim-ease-standard);
1503
+ }
1504
+
1505
+ .nim-dialog__header {
1506
+ display: flex;
1507
+ align-items: flex-start;
1508
+ justify-content: space-between;
1509
+ gap: var(--nim-space-3);
1510
+ padding: var(--nim-space-5);
1511
+ border-block-end: var(--nim-border-width) solid var(--nim-line-soft);
1512
+ flex: none;
1513
+ }
1514
+
1515
+ .nim-dialog__body {
1516
+ padding: var(--nim-space-5);
1517
+ overflow-y: auto;
1518
+ overscroll-behavior: contain;
1519
+ }
1520
+
1521
+ .nim-dialog__footer {
1522
+ display: flex;
1523
+ align-items: center;
1524
+ justify-content: flex-end;
1525
+ gap: var(--nim-space-3);
1526
+ padding: var(--nim-space-5);
1527
+ border-block-start: var(--nim-border-width) solid var(--nim-line-soft);
1528
+ flex: none;
1529
+ }
1530
+
1531
+ /* ═══════════════════════════════════════════════════════════════════════
1532
+ POPOVER — a menu's geometry with a form's contents
1533
+ Unlike a menu it does not close on click-inside, because the thing inside
1534
+ is what the viewer came for.
1535
+ ═══════════════════════════════════════════════════════════════════════ */
1536
+ .nim-popover {
1537
+ position: fixed;
1538
+ z-index: var(--nim-z-nav);
1539
+ inline-size: min(320px, 100vw - var(--nim-space-8));
1540
+ padding: var(--nim-space-5);
1541
+ background: var(--nim-surface-raised);
1542
+ border: var(--nim-border-width) solid var(--nim-line-strong);
1543
+ border-radius: var(--nim-radius-md);
1544
+ box-shadow: var(--nim-shadow-lg);
1545
+ animation: nim-pop var(--nim-dur-fast) var(--nim-ease-decelerate);
1546
+ }
1547
+
1548
+ /* ═══════════════════════════════════════════════════════════════════════
1549
+ TOOLTIP — a name for a control that shows only an icon
1550
+ Never the only place a label lives: the trigger carries its own
1551
+ accessible name, and this repeats it for sighted pointer users.
1552
+ ═══════════════════════════════════════════════════════════════════════ */
1553
+ .nim-tooltip {
1554
+ position: relative;
1555
+ display: inline-flex;
1556
+ }
1557
+
1558
+ .nim-tooltip__bubble {
1559
+ position: absolute;
1560
+ inset-block-end: calc(100% + var(--nim-space-2));
1561
+ inset-inline-start: 50%;
1562
+ translate: -50% 0;
1563
+ z-index: var(--nim-z-nav);
1564
+ padding: var(--nim-space-1) var(--nim-space-3);
1565
+ background: var(--nim-ink);
1566
+ color: var(--nim-ink-inverse);
1567
+ border-radius: var(--nim-radius-xs);
1568
+ font-size: var(--nim-type-caption-size);
1569
+ line-height: var(--nim-type-caption-line);
1570
+ white-space: nowrap;
1571
+ opacity: 0;
1572
+ pointer-events: none;
1573
+ transition: opacity var(--nim-dur-fast) var(--nim-ease-standard) 200ms;
1574
+ }
1575
+
1576
+ /* Hover waits; keyboard focus does not — a viewer who tabbed here asked. */
1577
+ .nim-tooltip:hover .nim-tooltip__bubble {
1578
+ opacity: 1;
1579
+ }
1580
+
1581
+ .nim-tooltip:focus-within .nim-tooltip__bubble {
1582
+ opacity: 1;
1583
+ transition-delay: 0ms;
1584
+ }
1585
+
1586
+ /* ═══════════════════════════════════════════════════════════════════════
1587
+ TABS — switch a region of the page
1588
+ Distinct from the segmented control, and the distinction is the point:
1589
+ tabs change what is shown, a segmented control sets a value.
1590
+ ═══════════════════════════════════════════════════════════════════════ */
1591
+ .nim-tabs {
1592
+ display: flex;
1593
+ gap: var(--nim-space-6);
1594
+ border-block-end: var(--nim-border-width) solid var(--nim-line);
1595
+ overflow-x: auto;
1596
+ scrollbar-width: none;
1597
+ }
1598
+
1599
+ .nim-tabs::-webkit-scrollbar {
1600
+ display: none;
1601
+ }
1602
+
1603
+ .nim-tab {
1604
+ position: relative;
1605
+ display: inline-flex;
1606
+ align-items: center;
1607
+ gap: var(--nim-space-2);
1608
+ padding-block: var(--nim-space-3) var(--nim-space-4);
1609
+ border: 0;
1610
+ background: none;
1611
+ cursor: pointer;
1612
+ white-space: nowrap;
1613
+ color: var(--nim-ink-tertiary);
1614
+ font-family: var(--nim-type-control-family);
1615
+ font-size: var(--nim-type-control-size);
1616
+ font-weight: var(--nim-type-control-weight);
1617
+ letter-spacing: var(--nim-type-control-tracking);
1618
+ text-transform: var(--nim-type-control-transform);
1619
+ transition: color var(--nim-dur-fast) var(--nim-ease-standard);
1620
+ }
1621
+
1622
+ .nim-tab:hover:not(:disabled) {
1623
+ color: var(--nim-ink);
1624
+ }
1625
+
1626
+ .nim-tab[aria-selected='true'] {
1627
+ color: var(--nim-ink);
1628
+ }
1629
+
1630
+ .nim-tab[aria-selected='true']::after {
1631
+ content: '';
1632
+ position: absolute;
1633
+ inset-inline: 0;
1634
+ inset-block-end: calc(-1 * var(--nim-border-width));
1635
+ block-size: 2px;
1636
+ background: var(--nim-accent);
1637
+ }
1638
+
1639
+ .nim-tab:disabled {
1640
+ opacity: 0.45;
1641
+ cursor: not-allowed;
1642
+ }
1643
+
1644
+ .nim-tab__count {
1645
+ padding-inline: var(--nim-space-1);
1646
+ font-family: var(--nim-font-numeric);
1647
+ font-size: var(--nim-text-11);
1648
+ background: var(--nim-surface-muted);
1649
+ color: var(--nim-ink-tertiary);
1650
+ border-radius: var(--nim-radius-xs);
1651
+ }
1652
+
1653
+ .nim-tab[aria-selected='true'] .nim-tab__count {
1654
+ background: var(--nim-accent-soft);
1655
+ color: var(--nim-accent);
1656
+ }
1657
+
1658
+ /* ═══════════════════════════════════════════════════════════════════════
1659
+ TABLE
1660
+ Row height follows `--nim-density`, the same multiplier that drives the
1661
+ control scale — which is the whole reason density is a token rather than
1662
+ a prop on this component.
1663
+ ═══════════════════════════════════════════════════════════════════════ */
1664
+ .nim-table-wrap {
1665
+ inline-size: 100%;
1666
+ overflow-x: auto;
1667
+ border: var(--nim-border-width) solid var(--nim-line);
1668
+ border-radius: var(--nim-radius-lg);
1669
+ }
1670
+
1671
+ .nim-table {
1672
+ inline-size: 100%;
1673
+ border-collapse: collapse;
1674
+ background: var(--nim-surface);
1675
+ }
1676
+
1677
+ .nim-table th {
1678
+ position: sticky;
1679
+ inset-block-start: 0;
1680
+ z-index: var(--nim-z-sticky);
1681
+ text-align: start;
1682
+ padding: var(--nim-space-3) var(--nim-space-5);
1683
+ background: var(--nim-surface);
1684
+ border-block-end: var(--nim-border-width) solid var(--nim-line);
1685
+ font-family: var(--nim-type-label-family);
1686
+ font-size: var(--nim-text-11);
1687
+ font-weight: var(--nim-weight-medium);
1688
+ letter-spacing: var(--nim-label-tracking);
1689
+ text-transform: var(--nim-label-transform);
1690
+ color: var(--nim-ink-tertiary);
1691
+ white-space: nowrap;
1692
+ }
1693
+
1694
+ .nim-table td {
1695
+ padding: calc(var(--nim-space-4) * var(--nim-density)) var(--nim-space-5);
1696
+ border-block-end: var(--nim-border-width) solid var(--nim-line-soft);
1697
+ font-size: var(--nim-type-body-sm-size);
1698
+ letter-spacing: var(--nim-tracking-normal);
1699
+ }
1700
+
1701
+ .nim-table tbody tr:last-child td {
1702
+ border-block-end: 0;
1703
+ }
1704
+
1705
+ .nim-table tbody tr:hover td {
1706
+ background: var(--nim-surface-muted);
1707
+ }
1708
+
1709
+ /* Money and dates align to the trailing edge in tabular figures, so decimal
1710
+ points stack without anyone setting a column width. The `th`/`td` in the
1711
+ selector is not decoration: `.nim-table th` sets `text-align: start` at a
1712
+ higher specificity, so without it a numeric column's header sat over the
1713
+ opposite edge from its own figures. */
1714
+ .nim-table :is(th, td).nim-table__cell--numeric {
1715
+ text-align: end;
1716
+ font-family: var(--nim-font-numeric);
1717
+ font-variant-numeric: tabular-nums;
1718
+ }
1719
+
1720
+ .nim-table__sort {
1721
+ display: inline-flex;
1722
+ align-items: center;
1723
+ gap: var(--nim-space-1);
1724
+ padding: 0;
1725
+ border: 0;
1726
+ background: none;
1727
+ cursor: pointer;
1728
+ color: inherit;
1729
+ font: inherit;
1730
+ letter-spacing: inherit;
1731
+ text-transform: inherit;
1732
+ user-select: none;
1733
+ }
1734
+
1735
+ .nim-table__sort:hover {
1736
+ color: var(--nim-ink);
1737
+ }
1738
+
1739
+ .nim-table th[aria-sort] .nim-table__sort {
1740
+ color: var(--nim-accent);
1741
+ }
1742
+
1743
+ /* ═══════════════════════════════════════════════════════════════════════
1744
+ COMBOBOX — a text input that suggests, and can still be typed into
1745
+ ═══════════════════════════════════════════════════════════════════════ */
1746
+ .nim-combobox {
1747
+ position: relative;
1748
+ }
1749
+
1750
+ .nim-combobox__list {
1751
+ position: absolute;
1752
+ inset-inline: 0;
1753
+ z-index: var(--nim-z-nav);
1754
+ margin-block-start: calc(-1 * var(--nim-border-width));
1755
+ max-block-size: 240px;
1756
+ overflow-y: auto;
1757
+ overscroll-behavior: contain;
1758
+ background: var(--nim-surface-raised);
1759
+ border: var(--nim-border-width) solid var(--nim-line-strong);
1760
+ border-radius: var(--nim-radius-sm);
1761
+ box-shadow: var(--nim-shadow-lg);
1762
+ }
1763
+
1764
+ .nim-combobox__option {
1765
+ display: flex;
1766
+ align-items: center;
1767
+ gap: var(--nim-space-3);
1768
+ inline-size: 100%;
1769
+ min-block-size: calc(var(--nim-control-sm) * var(--nim-density));
1770
+ padding-inline: var(--nim-space-4);
1771
+ border: 0;
1772
+ background: none;
1773
+ text-align: start;
1774
+ cursor: pointer;
1775
+ color: var(--nim-ink);
1776
+ font-family: var(--nim-type-control-family);
1777
+ font-size: var(--nim-type-control-size);
1778
+ letter-spacing: var(--nim-type-control-tracking);
1779
+ }
1780
+
1781
+ .nim-combobox__option:hover,
1782
+ .nim-combobox__option[aria-selected='true'] {
1783
+ background: var(--nim-surface-muted);
1784
+ }
1785
+
1786
+ .nim-combobox__meta {
1787
+ margin-inline-start: auto;
1788
+ font-family: var(--nim-font-mono);
1789
+ font-size: var(--nim-text-11);
1790
+ color: var(--nim-ink-tertiary);
1791
+ }
1792
+
1793
+ /* A no-match state offers the way forward rather than dead-ending. */
1794
+ .nim-combobox__empty {
1795
+ padding: var(--nim-space-4);
1796
+ font-size: var(--nim-type-caption-size);
1797
+ line-height: var(--nim-type-caption-line);
1798
+ color: var(--nim-ink-tertiary);
1799
+ }
1800
+
1801
+ /* ═══════════════════════════════════════════════════════════════════════
1802
+ DATE FIELD — a text input, with a calendar as an aid
1803
+ Typing a date always works, which matters more than the grid does.
1804
+ ═══════════════════════════════════════════════════════════════════════ */
1805
+ /* ═══════════════════════════════════════════════════════════════════════
1806
+ DATE PICKER — the field, with the month behind a button
1807
+ ═══════════════════════════════════════════════════════════════════════ */
1808
+ .nim-date-picker {
1809
+ display: grid;
1810
+ gap: var(--nim-space-2);
1811
+ }
1812
+
1813
+ .nim-date-picker__group {
1814
+ display: flex;
1815
+ align-items: center;
1816
+ gap: var(--nim-space-1);
1817
+ }
1818
+
1819
+ .nim-date-picker__group > .nim-input {
1820
+ flex: 1;
1821
+ min-inline-size: 0;
1822
+ }
1823
+
1824
+ /* The same day on the other calendar. Quiet by design: it is a check, not
1825
+ a second value — the field above is the one being edited. */
1826
+ .nim-date-picker__equivalent {
1827
+ display: flex;
1828
+ align-items: center;
1829
+ gap: var(--nim-space-2);
1830
+ margin: 0;
1831
+ font-size: var(--nim-type-caption-size);
1832
+ color: var(--nim-ink-tertiary);
1833
+ }
1834
+
1835
+ .nim-date-picker__equivalent > span {
1836
+ font-family: var(--nim-font-numeric);
1837
+ font-variant-numeric: tabular-nums;
1838
+ }
1839
+
1840
+ .nim-calendar {
1841
+ inline-size: 100%;
1842
+ display: grid;
1843
+ gap: var(--nim-space-3);
1844
+ }
1845
+
1846
+ .nim-calendar__header {
1847
+ display: flex;
1848
+ align-items: center;
1849
+ justify-content: space-between;
1850
+ gap: var(--nim-space-2);
1851
+ }
1852
+
1853
+ .nim-calendar__month {
1854
+ font-family: var(--nim-type-control-family);
1855
+ font-size: var(--nim-type-control-size);
1856
+ font-weight: var(--nim-weight-medium);
1857
+ }
1858
+
1859
+ .nim-calendar__grid {
1860
+ display: grid;
1861
+ grid-template-columns: repeat(7, minmax(0, 1fr));
1862
+ gap: var(--nim-border-width);
1863
+ background: var(--nim-line-soft);
1864
+ border: var(--nim-border-width) solid var(--nim-line);
1865
+ border-radius: var(--nim-radius-sm);
1866
+ overflow: hidden;
1867
+ }
1868
+
1869
+ .nim-calendar__weekday {
1870
+ padding-block: var(--nim-space-2);
1871
+ background: var(--nim-surface);
1872
+ text-align: center;
1873
+ font-family: var(--nim-type-label-family);
1874
+ font-size: var(--nim-text-11);
1875
+ letter-spacing: var(--nim-label-tracking);
1876
+ text-transform: var(--nim-label-transform);
1877
+ color: var(--nim-ink-tertiary);
1878
+ }
1879
+
1880
+ .nim-calendar__day {
1881
+ aspect-ratio: 1;
1882
+ display: grid;
1883
+ place-items: center;
1884
+ border: 0;
1885
+ background: var(--nim-surface);
1886
+ cursor: pointer;
1887
+ color: var(--nim-ink);
1888
+ font-family: var(--nim-font-numeric);
1889
+ font-variant-numeric: tabular-nums;
1890
+ font-size: var(--nim-type-caption-size);
1891
+ transition: background-color var(--nim-dur-fast) var(--nim-ease-standard);
1892
+ }
1893
+
1894
+ .nim-calendar__day:hover:not(:disabled) {
1895
+ background: var(--nim-surface-muted);
1896
+ }
1897
+
1898
+ .nim-calendar__day--outside {
1899
+ color: var(--nim-ink-tertiary);
1900
+ opacity: 0.45;
1901
+ }
1902
+
1903
+ .nim-calendar__day--today {
1904
+ color: var(--nim-accent);
1905
+ font-weight: var(--nim-weight-semibold);
1906
+ }
1907
+
1908
+ .nim-calendar__day--marked {
1909
+ box-shadow: inset 0 -3px 0 var(--nim-accent);
1910
+ }
1911
+
1912
+ .nim-calendar__day[aria-selected='true'] {
1913
+ background: var(--nim-ink);
1914
+ color: var(--nim-canvas);
1915
+ font-weight: var(--nim-weight-semibold);
1916
+ }
1917
+
1918
+ .nim-calendar__day:disabled {
1919
+ opacity: 0.3;
1920
+ cursor: not-allowed;
1921
+ }
1922
+
1923
+ /* ═══════════════════════════════════════════════════════════════════════
1924
+ STEPPER — a number with two full-size targets
1925
+ Both buttons are control-height squares, so the pair clears the touch
1926
+ minimum instead of the usual cramped chevrons.
1927
+ ═══════════════════════════════════════════════════════════════════════ */
1928
+ .nim-stepper {
1929
+ display: inline-flex;
1930
+ align-items: stretch;
1931
+ background: var(--nim-surface);
1932
+ border: var(--nim-border-width) solid var(--nim-line-strong);
1933
+ border-radius: var(--nim-radius-sm);
1934
+ }
1935
+
1936
+ .nim-stepper__button {
1937
+ inline-size: calc(var(--nim-control-md) * var(--nim-density));
1938
+ display: grid;
1939
+ place-items: center;
1940
+ border: 0;
1941
+ background: none;
1942
+ cursor: pointer;
1943
+ color: var(--nim-ink-secondary);
1944
+ transition:
1945
+ background-color var(--nim-dur-fast) var(--nim-ease-standard),
1946
+ color var(--nim-dur-fast) var(--nim-ease-standard);
1947
+ }
1948
+
1949
+ .nim-stepper__button:hover:not(:disabled) {
1950
+ background: var(--nim-surface-muted);
1951
+ color: var(--nim-ink);
1952
+ }
1953
+
1954
+ .nim-stepper__button:disabled {
1955
+ opacity: 0.35;
1956
+ cursor: not-allowed;
1957
+ }
1958
+
1959
+ .nim-stepper__value {
1960
+ min-inline-size: calc(var(--nim-space-9) + var(--nim-space-4));
1961
+ display: grid;
1962
+ place-items: center;
1963
+ border-inline: var(--nim-border-width) solid var(--nim-line);
1964
+ font-family: var(--nim-font-numeric);
1965
+ font-variant-numeric: tabular-nums;
1966
+ font-size: var(--nim-type-body-size);
1967
+ }
1968
+
1969
+ /* ═══════════════════════════════════════════════════════════════════════
1970
+ PAGINATION
1971
+ ═══════════════════════════════════════════════════════════════════════ */
1972
+ .nim-pagination {
1973
+ display: flex;
1974
+ align-items: center;
1975
+ justify-content: space-between;
1976
+ gap: var(--nim-space-4);
1977
+ flex-wrap: wrap;
1978
+ }
1979
+
1980
+ .nim-pagination__summary {
1981
+ font-size: var(--nim-type-caption-size);
1982
+ color: var(--nim-ink-tertiary);
1983
+ }
1984
+
1985
+ .nim-pagination__list {
1986
+ display: flex;
1987
+ align-items: center;
1988
+ gap: var(--nim-space-1);
1989
+ }
1990
+
1991
+ .nim-pagination__item {
1992
+ min-inline-size: calc(var(--nim-control-sm) * var(--nim-density));
1993
+ block-size: calc(var(--nim-control-sm) * var(--nim-density));
1994
+ padding-inline: var(--nim-space-2);
1995
+ display: grid;
1996
+ place-items: center;
1997
+ border: var(--nim-border-width) solid transparent;
1998
+ border-radius: var(--nim-radius-xs);
1999
+ background: none;
2000
+ cursor: pointer;
2001
+ color: var(--nim-ink-secondary);
2002
+ font-family: var(--nim-font-numeric);
2003
+ font-variant-numeric: tabular-nums;
2004
+ font-size: var(--nim-type-caption-size);
2005
+ transition:
2006
+ background-color var(--nim-dur-fast) var(--nim-ease-standard),
2007
+ color var(--nim-dur-fast) var(--nim-ease-standard);
2008
+ }
2009
+
2010
+ .nim-pagination__item:hover:not(:disabled) {
2011
+ background: var(--nim-surface-muted);
2012
+ color: var(--nim-ink);
2013
+ }
2014
+
2015
+ .nim-pagination__item[aria-current='page'] {
2016
+ background: var(--nim-ink);
2017
+ color: var(--nim-canvas);
2018
+ }
2019
+
2020
+ .nim-pagination__item:disabled {
2021
+ opacity: 0.35;
2022
+ cursor: not-allowed;
2023
+ }
2024
+
2025
+ .nim-pagination__ellipsis {
2026
+ min-inline-size: calc(var(--nim-control-sm) * var(--nim-density));
2027
+ block-size: calc(var(--nim-control-sm) * var(--nim-density));
2028
+ display: grid;
2029
+ place-items: center;
2030
+ color: var(--nim-ink-tertiary);
2031
+ }
2032
+
2033
+ /* ═══════════════════════════════════════════════════════════════════════
2034
+ BREADCRUMB
2035
+ ═══════════════════════════════════════════════════════════════════════ */
2036
+ .nim-breadcrumb {
2037
+ display: flex;
2038
+ align-items: center;
2039
+ flex-wrap: wrap;
2040
+ gap: var(--nim-space-2);
2041
+ font-size: var(--nim-type-body-sm-size);
2042
+ }
2043
+
2044
+ .nim-breadcrumb__link {
2045
+ color: var(--nim-ink-tertiary);
2046
+ text-decoration: none;
2047
+ border-radius: var(--nim-radius-xs);
2048
+ transition: color var(--nim-dur-fast) var(--nim-ease-standard);
2049
+ }
2050
+
2051
+ .nim-breadcrumb__link:hover {
2052
+ color: var(--nim-accent);
2053
+ }
2054
+
2055
+ .nim-breadcrumb__separator {
2056
+ display: grid;
2057
+ place-items: center;
2058
+ color: var(--nim-line-strong);
2059
+ flex: none;
2060
+ }
2061
+
2062
+ .nim-breadcrumb__current {
2063
+ color: var(--nim-ink);
2064
+ font-weight: var(--nim-weight-medium);
2065
+ }
2066
+
2067
+ /* ═══════════════════════════════════════════════════════════════════════
2068
+ ONBOARDING — the first-run carousel
2069
+ A column with three fixed regions: art, copy, controls. The art region is
2070
+ sized in viewport units and the copy region takes the slack, so a long
2071
+ Persian paragraph pushes the illustration down rather than the CTA off
2072
+ the screen.
2073
+ ═══════════════════════════════════════════════════════════════════════ */
2074
+ .nim-onboarding {
2075
+ display: flex;
2076
+ flex-direction: column;
2077
+ min-block-size: 100%;
2078
+ inline-size: 100%;
2079
+ max-inline-size: var(--nim-frame-max);
2080
+ margin-inline: auto;
2081
+ padding-block: calc(var(--nim-safe-top) + var(--nim-space-4))
2082
+ calc(var(--nim-safe-bottom) + var(--nim-space-6));
2083
+ padding-inline: var(--nim-space-6);
2084
+ background: var(--nim-canvas);
2085
+ }
2086
+
2087
+ .nim-onboarding__bar {
2088
+ display: flex;
2089
+ align-items: center;
2090
+ justify-content: space-between;
2091
+ gap: var(--nim-space-4);
2092
+ min-block-size: var(--nim-touch-min);
2093
+ flex: none;
2094
+ }
2095
+
2096
+ .nim-onboarding__stage {
2097
+ flex: none;
2098
+ display: grid;
2099
+ justify-items: center;
2100
+ gap: var(--nim-space-4);
2101
+ padding-block: var(--nim-space-4);
2102
+ }
2103
+
2104
+ .nim-onboarding__art {
2105
+ inline-size: 100%;
2106
+ max-inline-size: 292px;
2107
+ }
2108
+
2109
+ .nim-onboarding__art > * {
2110
+ inline-size: 100%;
2111
+ block-size: auto;
2112
+ display: block;
2113
+ }
2114
+
2115
+ .nim-onboarding__proof {
2116
+ display: grid;
2117
+ grid-template-columns: auto 1fr;
2118
+ align-items: center;
2119
+ gap: var(--nim-space-3);
2120
+ inline-size: 100%;
2121
+ max-inline-size: 340px;
2122
+ padding: var(--nim-space-3);
2123
+ background: var(--nim-surface);
2124
+ border: var(--nim-border-width) solid var(--nim-line-soft);
2125
+ border-radius: var(--nim-radius-lg);
2126
+ box-shadow: var(--nim-shadow-sm);
2127
+ }
2128
+
2129
+ .nim-onboarding__proof-icon {
2130
+ display: inline-flex;
2131
+ align-items: center;
2132
+ justify-content: center;
2133
+ inline-size: var(--nim-size-avatar-md);
2134
+ block-size: var(--nim-size-avatar-md);
2135
+ border-radius: var(--nim-radius-pill);
2136
+ background: var(--nim-accent-soft);
2137
+ color: var(--nim-accent);
2138
+ flex: none;
2139
+ }
2140
+
2141
+ .nim-onboarding__proof-text {
2142
+ display: grid;
2143
+ gap: var(--nim-space-1);
2144
+ min-inline-size: 0;
2145
+ }
2146
+
2147
+ .nim-onboarding__proof-title {
2148
+ font-size: var(--nim-type-body-sm-size);
2149
+ font-weight: var(--nim-weight-semibold);
2150
+ color: var(--nim-ink);
2151
+ line-height: var(--nim-leading-tight);
2152
+ }
2153
+
2154
+ .nim-onboarding__proof-points {
2155
+ font-size: var(--nim-type-caption-size);
2156
+ color: var(--nim-ink-secondary);
2157
+ /* One line of supporting points, truncated rather than wrapped — it is a
2158
+ caption, and a two-line caption starts competing with the title. */
2159
+ white-space: nowrap;
2160
+ overflow: hidden;
2161
+ text-overflow: ellipsis;
2162
+ }
2163
+
2164
+ .nim-onboarding__copy {
2165
+ flex: 1;
2166
+ display: flex;
2167
+ flex-direction: column;
2168
+ justify-content: center;
2169
+ gap: var(--nim-space-3);
2170
+ padding-block: var(--nim-space-5);
2171
+ min-block-size: 0;
2172
+ }
2173
+
2174
+ .nim-onboarding__chip {
2175
+ align-self: start;
2176
+ padding-block: var(--nim-space-1);
2177
+ padding-inline: var(--nim-space-4);
2178
+ border-radius: var(--nim-radius-pill);
2179
+ border: var(--nim-border-width) solid var(--nim-accent-line);
2180
+ background: var(--nim-accent-soft);
2181
+ color: var(--nim-accent);
2182
+ font-size: var(--nim-type-label-size);
2183
+ font-weight: var(--nim-weight-semibold);
2184
+ }
2185
+
2186
+ .nim-onboarding__title {
2187
+ margin: 0;
2188
+ font-family: var(--nim-type-display-family);
2189
+ font-size: var(--nim-type-title-lg-size);
2190
+ font-weight: var(--nim-type-title-lg-weight);
2191
+ line-height: var(--nim-leading-tight);
2192
+ letter-spacing: var(--nim-tracking-tight);
2193
+ color: var(--nim-ink);
2194
+ /* Slides carry their own line breaks: the title is a two-line promise and
2195
+ where it breaks is a copy decision, not a layout accident. */
2196
+ white-space: pre-line;
2197
+ }
2198
+
2199
+ .nim-onboarding__body {
2200
+ margin: 0;
2201
+ max-inline-size: var(--nim-measure);
2202
+ font-size: var(--nim-type-body-size);
2203
+ line-height: var(--nim-type-body-line);
2204
+ color: var(--nim-ink-secondary);
2205
+ }
2206
+
2207
+ .nim-onboarding__controls {
2208
+ flex: none;
2209
+ display: grid;
2210
+ gap: var(--nim-space-4);
2211
+ }
2212
+
2213
+ .nim-onboarding__dots {
2214
+ display: flex;
2215
+ justify-content: center;
2216
+ align-items: center;
2217
+ gap: var(--nim-space-2);
2218
+ }
2219
+
2220
+ .nim-onboarding__dot {
2221
+ inline-size: var(--nim-space-2);
2222
+ block-size: var(--nim-space-2);
2223
+ padding: 0;
2224
+ border: 0;
2225
+ border-radius: var(--nim-radius-pill);
2226
+ background: var(--nim-line-strong);
2227
+ cursor: pointer;
2228
+ transition:
2229
+ inline-size var(--nim-dur-base) var(--nim-ease-spring),
2230
+ background-color var(--nim-dur-base) var(--nim-ease-standard);
2231
+ }
2232
+
2233
+ /* The dot row is small; the touch target is not. */
2234
+ .nim-onboarding__dot::before {
2235
+ content: '';
2236
+ position: absolute;
2237
+ inset-block: calc(-1 * var(--nim-space-4));
2238
+ inset-inline: calc(-1 * var(--nim-space-1));
2239
+ }
2240
+
2241
+ .nim-onboarding__dot {
2242
+ position: relative;
2243
+ }
2244
+
2245
+ .nim-onboarding__dot[aria-current='step'] {
2246
+ inline-size: calc(var(--nim-space-7) - var(--nim-space-1));
2247
+ background: var(--nim-accent);
2248
+ }
2249
+
2250
+ .nim-onboarding__cta {
2251
+ display: flex;
2252
+ align-items: center;
2253
+ gap: var(--nim-space-3);
2254
+ }
2255
+
2256
+ .nim-onboarding__footnote {
2257
+ margin: 0;
2258
+ text-align: center;
2259
+ font-size: var(--nim-type-caption-size);
2260
+ color: var(--nim-ink-tertiary);
2261
+ }
2262
+
2263
+ /* ═══════════════════════════════════════════════════════════════════════
2264
+ AUTH SCREEN — one step of a sign-in flow
2265
+ ═══════════════════════════════════════════════════════════════════════ */
2266
+ .nim-auth {
2267
+ display: flex;
2268
+ flex-direction: column;
2269
+ min-block-size: 100%;
2270
+ inline-size: 100%;
2271
+ max-inline-size: var(--nim-frame-max);
2272
+ margin-inline: auto;
2273
+ padding-block: calc(var(--nim-safe-top) + var(--nim-space-8))
2274
+ calc(var(--nim-safe-bottom) + var(--nim-space-5));
2275
+ padding-inline: var(--nim-space-6);
2276
+ background: var(--nim-canvas);
2277
+ }
2278
+
2279
+ .nim-auth__brand {
2280
+ display: grid;
2281
+ justify-items: center;
2282
+ gap: var(--nim-space-2);
2283
+ flex: none;
2284
+ }
2285
+
2286
+ .nim-auth__body {
2287
+ flex: 1;
2288
+ display: flex;
2289
+ flex-direction: column;
2290
+ padding-block-start: var(--nim-space-7);
2291
+ }
2292
+
2293
+ .nim-auth__back {
2294
+ align-self: start;
2295
+ margin-block-end: var(--nim-space-5);
2296
+ }
2297
+
2298
+ .nim-auth__title {
2299
+ margin: 0 0 var(--nim-space-2);
2300
+ font-size: var(--nim-type-title-lg-size);
2301
+ font-weight: var(--nim-type-title-lg-weight);
2302
+ line-height: var(--nim-leading-tight);
2303
+ letter-spacing: var(--nim-tracking-tight);
2304
+ color: var(--nim-ink);
2305
+ }
2306
+
2307
+ .nim-auth__subtitle {
2308
+ margin: 0 0 var(--nim-space-7);
2309
+ max-inline-size: var(--nim-measure);
2310
+ font-size: var(--nim-type-body-size);
2311
+ line-height: var(--nim-type-body-line);
2312
+ color: var(--nim-ink-secondary);
2313
+ }
2314
+
2315
+ .nim-auth__fields {
2316
+ display: grid;
2317
+ gap: var(--nim-space-4);
2318
+ }
2319
+
2320
+ .nim-auth__foot {
2321
+ flex: none;
2322
+ display: grid;
2323
+ gap: var(--nim-space-4);
2324
+ padding-block-start: var(--nim-space-6);
2325
+ }
2326
+
2327
+ .nim-auth__footer {
2328
+ text-align: center;
2329
+ font-size: var(--nim-type-caption-size);
2330
+ line-height: var(--nim-leading-normal);
2331
+ color: var(--nim-ink-tertiary);
2332
+ }
2333
+
2334
+ /* ═══════════════════════════════════════════════════════════════════════
2335
+ OTP INPUT
2336
+ ═══════════════════════════════════════════════════════════════════════ */
2337
+ .nim-otp {
2338
+ display: grid;
2339
+ gap: var(--nim-space-3);
2340
+ justify-items: center;
2341
+ }
2342
+
2343
+ .nim-otp__boxes {
2344
+ display: flex;
2345
+ gap: var(--nim-space-2);
2346
+ justify-content: center;
2347
+ }
2348
+
2349
+ .nim-otp__box {
2350
+ inline-size: calc(var(--nim-control-lg) - var(--nim-space-2));
2351
+ block-size: calc(var(--nim-control-lg) * var(--nim-density));
2352
+ padding: 0;
2353
+ text-align: center;
2354
+ font-family: var(--nim-font-numeric);
2355
+ font-size: var(--nim-text-24);
2356
+ font-weight: var(--nim-weight-semibold);
2357
+ color: var(--nim-ink);
2358
+ background: var(--nim-surface);
2359
+ border: var(--nim-border-width) solid var(--nim-line);
2360
+ border-radius: var(--nim-radius-md);
2361
+ caret-color: var(--nim-accent);
2362
+ transition:
2363
+ border-color var(--nim-dur-fast) var(--nim-ease-standard),
2364
+ background-color var(--nim-dur-fast) var(--nim-ease-standard);
2365
+ }
2366
+
2367
+ .nim-otp__box[data-filled='true'] {
2368
+ border-color: var(--nim-accent);
2369
+ background: var(--nim-accent-soft);
2370
+ }
2371
+
2372
+ .nim-otp__box:focus-visible {
2373
+ outline: none;
2374
+ border-color: var(--nim-accent);
2375
+ box-shadow: var(--nim-shadow-focus);
2376
+ }
2377
+
2378
+ .nim-otp--invalid .nim-otp__box {
2379
+ border-color: var(--nim-danger);
2380
+ }
2381
+
2382
+ .nim-otp__error {
2383
+ margin: 0;
2384
+ font-size: var(--nim-type-caption-size);
2385
+ color: var(--nim-danger);
2386
+ }
2387
+
2388
+ /* ═══════════════════════════════════════════════════════════════════════
2389
+ PHONE FIELD — country picker welded to a number input
2390
+ ═══════════════════════════════════════════════════════════════════════ */
2391
+ .nim-phone {
2392
+ position: relative;
2393
+ }
2394
+
2395
+ .nim-phone__shell {
2396
+ display: flex;
2397
+ align-items: stretch;
2398
+ block-size: calc(var(--nim-control-lg) * var(--nim-density));
2399
+ background: var(--nim-surface);
2400
+ border: var(--nim-border-width) solid var(--nim-line);
2401
+ border-radius: var(--nim-radius-md);
2402
+ overflow: hidden;
2403
+ transition:
2404
+ border-color var(--nim-dur-fast) var(--nim-ease-standard),
2405
+ box-shadow var(--nim-dur-fast) var(--nim-ease-standard);
2406
+ }
2407
+
2408
+ .nim-phone__shell:focus-within {
2409
+ border-color: var(--nim-accent);
2410
+ box-shadow: var(--nim-shadow-focus);
2411
+ }
2412
+
2413
+ .nim-phone__country {
2414
+ display: inline-flex;
2415
+ align-items: center;
2416
+ gap: var(--nim-space-2);
2417
+ padding-inline: var(--nim-space-4);
2418
+ /* The shell is pinned LTR, so this divider is a physical right border on
2419
+ purpose: it is the boundary of a number, not of the page. */
2420
+ border: 0;
2421
+ border-right: var(--nim-border-width) solid var(--nim-line);
2422
+ background: none;
2423
+ color: var(--nim-ink-secondary);
2424
+ font-size: var(--nim-type-control-size);
2425
+ font-weight: var(--nim-weight-medium);
2426
+ cursor: pointer;
2427
+ flex: none;
2428
+ }
2429
+
2430
+ .nim-phone__country:hover {
2431
+ background: var(--nim-surface-muted);
2432
+ }
2433
+
2434
+ .nim-phone__flag {
2435
+ font-size: var(--nim-text-18);
2436
+ line-height: 1;
2437
+ }
2438
+
2439
+ .nim-phone__dial {
2440
+ font-family: var(--nim-font-numeric);
2441
+ font-variant-numeric: tabular-nums;
2442
+ }
2443
+
2444
+ .nim-phone__caret {
2445
+ color: var(--nim-ink-tertiary);
2446
+ }
2447
+
2448
+ .nim-phone__input {
2449
+ flex: 1;
2450
+ min-inline-size: 0;
2451
+ border: 0;
2452
+ background: transparent;
2453
+ padding-inline: var(--nim-space-4);
2454
+ font-family: var(--nim-font-numeric);
2455
+ font-size: var(--nim-type-control-size);
2456
+ letter-spacing: 0.04em;
2457
+ color: var(--nim-ink);
2458
+ }
2459
+
2460
+ .nim-phone__input:focus-visible {
2461
+ outline: none;
2462
+ }
2463
+
2464
+ .nim-phone__picker {
2465
+ position: absolute;
2466
+ inset-inline: 0;
2467
+ inset-block-start: calc(100% + var(--nim-space-2));
2468
+ z-index: var(--nim-z-nav);
2469
+ display: grid;
2470
+ grid-template-rows: auto minmax(0, 1fr);
2471
+ max-block-size: 18rem;
2472
+ background: var(--nim-surface-raised);
2473
+ border: var(--nim-border-width) solid var(--nim-line);
2474
+ border-radius: var(--nim-radius-md);
2475
+ box-shadow: var(--nim-shadow-lg);
2476
+ overflow: hidden;
2477
+ }
2478
+
2479
+ .nim-phone__search {
2480
+ display: flex;
2481
+ align-items: center;
2482
+ gap: var(--nim-space-2);
2483
+ padding-inline: var(--nim-space-4);
2484
+ block-size: calc(var(--nim-control-md) * var(--nim-density));
2485
+ border-block-end: var(--nim-border-width) solid var(--nim-line-soft);
2486
+ color: var(--nim-ink-tertiary);
2487
+ }
2488
+
2489
+ .nim-phone__search-input {
2490
+ flex: 1;
2491
+ min-inline-size: 0;
2492
+ border: 0;
2493
+ background: transparent;
2494
+ font-size: var(--nim-type-control-size);
2495
+ color: var(--nim-ink);
2496
+ }
2497
+
2498
+ .nim-phone__search-input:focus-visible {
2499
+ outline: none;
2500
+ }
2501
+
2502
+ .nim-phone__list {
2503
+ margin: 0;
2504
+ padding: 0;
2505
+ list-style: none;
2506
+ overflow-y: auto;
2507
+ overscroll-behavior: contain;
2508
+ }
2509
+
2510
+ .nim-phone__option {
2511
+ display: flex;
2512
+ align-items: center;
2513
+ gap: var(--nim-space-3);
2514
+ inline-size: 100%;
2515
+ min-block-size: var(--nim-touch-min);
2516
+ padding-inline: var(--nim-space-4);
2517
+ border: 0;
2518
+ background: none;
2519
+ color: var(--nim-ink);
2520
+ font-size: var(--nim-type-body-sm-size);
2521
+ text-align: start;
2522
+ cursor: pointer;
2523
+ }
2524
+
2525
+ .nim-phone__option:hover,
2526
+ .nim-phone__option[aria-selected='true'] {
2527
+ background: var(--nim-surface-muted);
2528
+ }
2529
+
2530
+ .nim-phone__option:focus-visible {
2531
+ outline: var(--nim-size-focus-ring) solid var(--nim-accent);
2532
+ outline-offset: calc(-1 * var(--nim-size-focus-ring));
2533
+ }
2534
+
2535
+ .nim-phone__name {
2536
+ flex: 1;
2537
+ min-inline-size: 0;
2538
+ overflow: hidden;
2539
+ text-overflow: ellipsis;
2540
+ white-space: nowrap;
2541
+ }
2542
+
2543
+ .nim-phone__option-dial {
2544
+ font-family: var(--nim-font-numeric);
2545
+ font-variant-numeric: tabular-nums;
2546
+ color: var(--nim-ink-tertiary);
2547
+ }
2548
+
2549
+ .nim-phone__empty {
2550
+ padding: var(--nim-space-4);
2551
+ text-align: center;
2552
+ font-size: var(--nim-type-caption-size);
2553
+ color: var(--nim-ink-tertiary);
2554
+ }
2555
+
2556
+ /* ═══════════════════════════════════════════════════════════════════════
2557
+ PASSWORD FIELD — reveal toggle and strength meter
2558
+ ═══════════════════════════════════════════════════════════════════════ */
2559
+ .nim-password__toggle {
2560
+ position: absolute;
2561
+ inset-inline-end: var(--nim-space-2);
2562
+ inset-block: var(--nim-space-1);
2563
+ display: inline-flex;
2564
+ align-items: center;
2565
+ justify-content: center;
2566
+ inline-size: var(--nim-touch-min);
2567
+ border: 0;
2568
+ border-radius: var(--nim-radius-sm);
2569
+ background: none;
2570
+ color: var(--nim-ink-tertiary);
2571
+ cursor: pointer;
2572
+ }
2573
+
2574
+ .nim-password__toggle:hover {
2575
+ color: var(--nim-ink);
2576
+ }
2577
+
2578
+ .nim-password__toggle[aria-pressed='true'] {
2579
+ color: var(--nim-accent);
2580
+ }
2581
+
2582
+ .nim-password__toggle:focus-visible {
2583
+ outline: none;
2584
+ box-shadow: var(--nim-shadow-focus);
2585
+ }
2586
+
2587
+ .nim-password__meter {
2588
+ display: flex;
2589
+ gap: var(--nim-space-1);
2590
+ margin-block-start: var(--nim-space-2);
2591
+ }
2592
+
2593
+ .nim-password__step {
2594
+ flex: 1;
2595
+ block-size: var(--nim-space-1);
2596
+ border-radius: var(--nim-radius-pill);
2597
+ background: var(--nim-line);
2598
+ transition: background-color var(--nim-dur-base) var(--nim-ease-standard);
2599
+ }
2600
+
2601
+ .nim-password__meter[data-level='weak'] .nim-password__step[data-on] {
2602
+ background: var(--nim-danger);
2603
+ }
2604
+ .nim-password__meter[data-level='fair'] .nim-password__step[data-on] {
2605
+ background: var(--nim-warning);
2606
+ }
2607
+ .nim-password__meter[data-level='good'] .nim-password__step[data-on],
2608
+ .nim-password__meter[data-level='strong'] .nim-password__step[data-on] {
2609
+ background: var(--nim-success);
2610
+ }
2611
+
2612
+ /* ═══════════════════════════════════════════════════════════════════════
2613
+ TAB BAR — floating bottom navigation
2614
+ ═══════════════════════════════════════════════════════════════════════ */
2615
+ .nim-tab-bar {
2616
+ position: sticky;
2617
+ inset-block-end: calc(var(--nim-safe-bottom) + var(--nim-space-3));
2618
+ z-index: var(--nim-z-nav);
2619
+ inline-size: min(100%, var(--nim-content-max));
2620
+ margin-inline: auto;
2621
+ padding-inline: var(--nim-space-4);
2622
+ /* The bar floats; the page scrolls under it. Only the row takes pointer
2623
+ events so the gutters beside it stay tappable. */
2624
+ pointer-events: none;
2625
+ }
2626
+
2627
+ .nim-tab-bar__row {
2628
+ pointer-events: auto;
2629
+ display: grid;
2630
+ grid-template-columns: repeat(var(--nim-tab-count, 4), minmax(0, 1fr));
2631
+ align-items: center;
2632
+ justify-items: center;
2633
+ padding: var(--nim-space-2);
2634
+ background: var(--nim-surface-raised);
2635
+ border: var(--nim-border-width) solid var(--nim-line-soft);
2636
+ border-radius: var(--nim-radius-xl);
2637
+ box-shadow: var(--nim-shadow-lg);
2638
+ }
2639
+
2640
+ .nim-tab-bar__slot {
2641
+ display: contents;
2642
+ }
2643
+
2644
+ .nim-tab-bar__item {
2645
+ display: flex;
2646
+ flex-direction: column;
2647
+ align-items: center;
2648
+ justify-content: center;
2649
+ gap: var(--nim-space-1);
2650
+ inline-size: 100%;
2651
+ min-block-size: var(--nim-touch-min);
2652
+ padding-block: var(--nim-space-2);
2653
+ border: 0;
2654
+ border-radius: var(--nim-radius-md);
2655
+ background: none;
2656
+ color: var(--nim-ink-secondary);
2657
+ text-decoration: none;
2658
+ cursor: pointer;
2659
+ transition:
2660
+ background-color var(--nim-dur-fast) var(--nim-ease-standard),
2661
+ color var(--nim-dur-fast) var(--nim-ease-standard);
2662
+ }
2663
+
2664
+ .nim-tab-bar__item[data-active='true'] {
2665
+ background: var(--nim-accent-soft);
2666
+ color: var(--nim-accent);
2667
+ }
2668
+
2669
+ .nim-tab-bar__item:focus-visible {
2670
+ outline: none;
2671
+ box-shadow: var(--nim-shadow-focus);
2672
+ }
2673
+
2674
+ .nim-tab-bar__label {
2675
+ font-size: var(--nim-type-label-size);
2676
+ font-weight: var(--nim-weight-medium);
2677
+ line-height: 1;
2678
+ text-transform: var(--nim-label-transform);
2679
+ letter-spacing: var(--nim-label-tracking);
2680
+ }
2681
+
2682
+ /* The centre action is lifted out of the bar, which is what makes it read
2683
+ as the product's one verb rather than a fifth destination. */
2684
+ .nim-tab-bar__item--center {
2685
+ margin-block-start: calc(-1 * var(--nim-space-5));
2686
+ inline-size: calc(var(--nim-control-lg) + var(--nim-space-1));
2687
+ min-block-size: calc(var(--nim-control-lg) + var(--nim-space-3));
2688
+ background: var(--nim-accent);
2689
+ color: var(--nim-on-accent);
2690
+ border: var(--nim-border-width) solid var(--nim-accent-line);
2691
+ border-radius: var(--nim-radius-lg);
2692
+ box-shadow: var(--nim-shadow-md);
2693
+ }
2694
+
2695
+ .nim-tab-bar__item--center[data-active='true'] {
2696
+ background: var(--nim-accent-strong);
2697
+ color: var(--nim-on-accent);
2698
+ }
2699
+
2700
+ /* ═══════════════════════════════════════════════════════════════════════
2701
+ PLAN CARD — one subscription tier
2702
+ ═══════════════════════════════════════════════════════════════════════ */
2703
+ .nim-plan {
2704
+ display: grid;
2705
+ gap: var(--nim-space-4);
2706
+ inline-size: 100%;
2707
+ padding: var(--nim-space-5);
2708
+ text-align: start;
2709
+ background: var(--nim-surface);
2710
+ border: var(--nim-border-width) solid var(--nim-line);
2711
+ border-radius: var(--nim-radius-lg);
2712
+ color: inherit;
2713
+ font: inherit;
2714
+ cursor: pointer;
2715
+ transition:
2716
+ border-color var(--nim-dur-fast) var(--nim-ease-standard),
2717
+ box-shadow var(--nim-dur-fast) var(--nim-ease-standard);
2718
+ }
2719
+
2720
+ article.nim-plan {
2721
+ cursor: default;
2722
+ }
2723
+
2724
+ .nim-plan:hover {
2725
+ border-color: var(--nim-line-strong);
2726
+ }
2727
+
2728
+ .nim-plan--selected {
2729
+ border-color: var(--nim-accent);
2730
+ box-shadow: var(--nim-shadow-md);
2731
+ }
2732
+
2733
+ .nim-plan:focus-visible {
2734
+ outline: none;
2735
+ box-shadow: var(--nim-shadow-focus);
2736
+ }
2737
+
2738
+ .nim-plan__top {
2739
+ display: flex;
2740
+ align-items: center;
2741
+ gap: var(--nim-space-3);
2742
+ }
2743
+
2744
+ .nim-plan__icon {
2745
+ display: inline-flex;
2746
+ align-items: center;
2747
+ justify-content: center;
2748
+ inline-size: var(--nim-size-avatar-md);
2749
+ block-size: var(--nim-size-avatar-md);
2750
+ border-radius: var(--nim-radius-md);
2751
+ background: var(--nim-accent-soft);
2752
+ color: var(--nim-accent);
2753
+ flex: none;
2754
+ }
2755
+
2756
+ .nim-plan__heading {
2757
+ display: grid;
2758
+ gap: var(--nim-space-1);
2759
+ flex: 1;
2760
+ min-inline-size: 0;
2761
+ }
2762
+
2763
+ .nim-plan__name {
2764
+ font-size: var(--nim-type-title-md-size);
2765
+ font-weight: var(--nim-type-title-md-weight);
2766
+ color: var(--nim-ink);
2767
+ line-height: var(--nim-leading-tight);
2768
+ }
2769
+
2770
+ .nim-plan__tagline {
2771
+ font-size: var(--nim-type-caption-size);
2772
+ color: var(--nim-ink-tertiary);
2773
+ }
2774
+
2775
+ .nim-plan__badge {
2776
+ padding-block: var(--nim-space-1);
2777
+ padding-inline: var(--nim-space-3);
2778
+ border-radius: var(--nim-radius-pill);
2779
+ border: var(--nim-border-width) solid var(--nim-accent-line);
2780
+ background: var(--nim-accent-soft);
2781
+ color: var(--nim-accent);
2782
+ font-size: var(--nim-type-label-size);
2783
+ font-weight: var(--nim-weight-semibold);
2784
+ white-space: nowrap;
2785
+ }
2786
+
2787
+ .nim-plan__radio {
2788
+ display: inline-flex;
2789
+ align-items: center;
2790
+ justify-content: center;
2791
+ inline-size: var(--nim-size-icon-lg);
2792
+ block-size: var(--nim-size-icon-lg);
2793
+ border-radius: var(--nim-radius-pill);
2794
+ border: var(--nim-border-width) solid var(--nim-line-strong);
2795
+ color: var(--nim-on-accent);
2796
+ flex: none;
2797
+ }
2798
+
2799
+ .nim-plan--selected .nim-plan__radio {
2800
+ background: var(--nim-accent);
2801
+ border-color: var(--nim-accent);
2802
+ }
2803
+
2804
+ .nim-plan__price-box {
2805
+ display: flex;
2806
+ align-items: flex-end;
2807
+ justify-content: space-between;
2808
+ gap: var(--nim-space-4);
2809
+ padding: var(--nim-space-4);
2810
+ background: var(--nim-canvas-sunken);
2811
+ border-radius: var(--nim-radius-md);
2812
+ }
2813
+
2814
+ .nim-plan__price-caption {
2815
+ display: block;
2816
+ font-size: var(--nim-type-label-size);
2817
+ color: var(--nim-ink-tertiary);
2818
+ }
2819
+
2820
+ .nim-plan__price {
2821
+ display: block;
2822
+ margin-block-start: var(--nim-space-1);
2823
+ font-family: var(--nim-font-numeric);
2824
+ font-variant-numeric: tabular-nums;
2825
+ font-size: var(--nim-text-24);
2826
+ font-weight: var(--nim-weight-semibold);
2827
+ color: var(--nim-ink);
2828
+ line-height: var(--nim-leading-tight);
2829
+ }
2830
+
2831
+ .nim-plan__secondary {
2832
+ text-align: end;
2833
+ }
2834
+
2835
+ .nim-plan__secondary-value {
2836
+ display: block;
2837
+ margin-block-start: var(--nim-space-1);
2838
+ font-family: var(--nim-font-numeric);
2839
+ font-variant-numeric: tabular-nums;
2840
+ font-size: var(--nim-type-body-sm-size);
2841
+ color: var(--nim-ink-secondary);
2842
+ }
2843
+
2844
+ .nim-plan__features {
2845
+ display: grid;
2846
+ gap: var(--nim-space-2);
2847
+ margin: 0;
2848
+ padding: 0;
2849
+ list-style: none;
2850
+ }
2851
+
2852
+ .nim-plan__feature {
2853
+ display: flex;
2854
+ align-items: center;
2855
+ gap: var(--nim-space-2);
2856
+ font-size: var(--nim-type-body-sm-size);
2857
+ line-height: var(--nim-leading-normal);
2858
+ color: var(--nim-ink-secondary);
2859
+ }
2860
+
2861
+ .nim-plan__feature[data-state='included'] > .nim-icon {
2862
+ color: var(--nim-success);
2863
+ }
2864
+ .nim-plan__feature[data-state='pending'] > .nim-icon {
2865
+ color: var(--nim-warning);
2866
+ }
2867
+ .nim-plan__feature[data-state='excluded'] {
2868
+ color: var(--nim-ink-tertiary);
2869
+ }
2870
+ .nim-plan__feature[data-state='excluded'] > .nim-icon {
2871
+ color: var(--nim-ink-tertiary);
2872
+ }
2873
+
2874
+ .nim-plan__feature-label {
2875
+ flex: 1;
2876
+ min-inline-size: 0;
2877
+ }
2878
+
2879
+ .nim-plan__feature-note {
2880
+ font-size: var(--nim-type-label-size);
2881
+ color: var(--nim-ink-tertiary);
2882
+ white-space: nowrap;
2883
+ }
2884
+
2885
+ /* ═══════════════════════════════════════════════════════════════════════
2886
+ AVATAR RING · PROFILE HEADER
2887
+ ═══════════════════════════════════════════════════════════════════════ */
2888
+ .nim-avatar-ring {
2889
+ position: relative;
2890
+ inline-size: var(--nim-ring-size);
2891
+ block-size: var(--nim-ring-size);
2892
+ flex: none;
2893
+ }
2894
+
2895
+ .nim-avatar-ring__arc {
2896
+ position: absolute;
2897
+ inset: 0;
2898
+ /* Start the arc at twelve o'clock. Rotation, not a redrawn path, so the
2899
+ cap stays round. */
2900
+ rotate: -90deg;
2901
+ }
2902
+
2903
+ .nim-avatar-ring__track {
2904
+ stroke: var(--nim-line-soft);
2905
+ }
2906
+
2907
+ .nim-avatar-ring__fill {
2908
+ stroke: var(--nim-accent);
2909
+ transition: stroke-dasharray var(--nim-dur-slow) var(--nim-ease-decelerate);
2910
+ }
2911
+
2912
+ .nim-avatar-ring__face {
2913
+ position: absolute;
2914
+ inset: calc(var(--nim-ring-stroke) + var(--nim-space-1));
2915
+ display: flex;
2916
+ flex-direction: column;
2917
+ align-items: center;
2918
+ justify-content: center;
2919
+ border-radius: var(--nim-radius-pill);
2920
+ background: var(--nim-surface-muted);
2921
+ overflow: hidden;
2922
+ }
2923
+
2924
+ .nim-avatar-ring__image {
2925
+ inline-size: 100%;
2926
+ block-size: 100%;
2927
+ object-fit: cover;
2928
+ }
2929
+
2930
+ .nim-avatar-ring__initials {
2931
+ font-size: var(--nim-text-24);
2932
+ font-weight: var(--nim-weight-semibold);
2933
+ color: var(--nim-ink);
2934
+ line-height: 1;
2935
+ }
2936
+
2937
+ .nim-avatar-ring__caption {
2938
+ margin-block-start: var(--nim-space-1);
2939
+ font-size: var(--nim-type-label-size);
2940
+ color: var(--nim-accent);
2941
+ }
2942
+
2943
+ .nim-profile-header {
2944
+ display: grid;
2945
+ gap: var(--nim-space-5);
2946
+ padding: var(--nim-space-5);
2947
+ background: var(--nim-surface-raised);
2948
+ border: var(--nim-border-width) solid var(--nim-line-soft);
2949
+ border-radius: var(--nim-radius-xl);
2950
+ box-shadow: var(--nim-shadow-md);
2951
+ }
2952
+
2953
+ .nim-profile-header__identity {
2954
+ display: flex;
2955
+ align-items: center;
2956
+ gap: var(--nim-space-4);
2957
+ }
2958
+
2959
+ .nim-profile-header__who {
2960
+ min-inline-size: 0;
2961
+ flex: 1;
2962
+ }
2963
+
2964
+ .nim-profile-header__eyebrow {
2965
+ margin: 0;
2966
+ font-size: var(--nim-type-label-size);
2967
+ font-weight: var(--nim-weight-medium);
2968
+ color: var(--nim-accent);
2969
+ }
2970
+
2971
+ .nim-profile-header__name {
2972
+ margin: var(--nim-space-1) 0 0;
2973
+ font-size: var(--nim-type-title-md-size);
2974
+ font-weight: var(--nim-type-title-md-weight);
2975
+ line-height: var(--nim-leading-tight);
2976
+ color: var(--nim-ink);
2977
+ }
2978
+
2979
+ .nim-profile-header__chips {
2980
+ display: flex;
2981
+ flex-wrap: wrap;
2982
+ gap: var(--nim-space-2);
2983
+ margin-block-start: var(--nim-space-3);
2984
+ }
2985
+
2986
+ .nim-profile-header__stats {
2987
+ display: grid;
2988
+ grid-template-columns: repeat(auto-fit, minmax(5rem, 1fr));
2989
+ gap: var(--nim-space-3);
2990
+ margin: 0;
2991
+ }
2992
+
2993
+ /* Source order is label-then-figure so the pair reads correctly as a
2994
+ definition list; the figure is shown first because that is what the eye
2995
+ is scanning for. */
2996
+ .nim-profile-header__stat {
2997
+ display: flex;
2998
+ flex-direction: column-reverse;
2999
+ align-items: center;
3000
+ text-align: center;
3001
+ }
3002
+
3003
+ .nim-profile-header__stat-value {
3004
+ margin: 0;
3005
+ font-family: var(--nim-font-numeric);
3006
+ font-variant-numeric: tabular-nums;
3007
+ font-size: var(--nim-text-18);
3008
+ font-weight: var(--nim-weight-semibold);
3009
+ color: var(--nim-ink);
3010
+ line-height: var(--nim-leading-tight);
3011
+ }
3012
+
3013
+ .nim-profile-header__stat-label {
3014
+ font-size: var(--nim-type-label-size);
3015
+ color: var(--nim-ink-tertiary);
3016
+ }
3017
+
3018
+ .nim-profile-header__actions {
3019
+ display: grid;
3020
+ grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
3021
+ gap: var(--nim-space-2);
3022
+ }
3023
+
3024
+ /* ═══════════════════════════════════════════════════════════════════════
3025
+ APP SHELL — header, one scroll region, tab bar
3026
+ ═══════════════════════════════════════════════════════════════════════ */
3027
+ .nim-app-shell {
3028
+ display: flex;
3029
+ flex-direction: column;
3030
+ block-size: 100%;
3031
+ inline-size: 100%;
3032
+ max-inline-size: var(--nim-frame-max);
3033
+ margin-inline: auto;
3034
+ background: var(--nim-canvas);
3035
+ overflow: hidden;
3036
+ }
3037
+
3038
+ .nim-app-shell__header {
3039
+ flex: none;
3040
+ display: flex;
3041
+ align-items: center;
3042
+ gap: var(--nim-space-3);
3043
+ min-block-size: var(--nim-control-lg);
3044
+ padding-block: var(--nim-space-3);
3045
+ padding-inline: var(--nim-space-4);
3046
+ padding-block-start: calc(var(--nim-safe-top) + var(--nim-space-3));
3047
+ background: var(--nim-surface);
3048
+ border-block-end: var(--nim-border-width) solid var(--nim-line-soft);
3049
+ }
3050
+
3051
+ .nim-app-shell__content {
3052
+ flex: 1;
3053
+ min-block-size: 0;
3054
+ overflow-y: auto;
3055
+ overscroll-behavior-y: contain;
3056
+ padding-inline: var(--nim-space-4);
3057
+ padding-block: var(--nim-space-4);
3058
+ }
3059
+
3060
+ /* The bar floats over the content, so the content owes it the room its last
3061
+ row would otherwise be hidden under. */
3062
+ .nim-app-shell__content[data-has-tabs] {
3063
+ padding-block-end: 0;
3064
+ }
3065
+
3066
+ .nim-app-shell > .nim-tab-bar {
3067
+ flex: none;
3068
+ margin-block-start: calc(-1 * var(--nim-space-4));
3069
+ padding-block-end: var(--nim-space-3);
3070
+ }
3071
+
3072
+ /* ═══════════════════════════════════════════════════════════════════════
3073
+ PLAN PICKER
3074
+ ═══════════════════════════════════════════════════════════════════════ */
3075
+ .nim-plan-picker {
3076
+ display: grid;
3077
+ gap: var(--nim-space-5);
3078
+ }
3079
+
3080
+ .nim-plan-picker__cycles {
3081
+ display: grid;
3082
+ gap: var(--nim-space-2);
3083
+ justify-items: center;
3084
+ }
3085
+
3086
+ .nim-plan-picker__save {
3087
+ margin: 0;
3088
+ font-size: var(--nim-type-label-size);
3089
+ font-weight: var(--nim-weight-medium);
3090
+ color: var(--nim-accent);
3091
+ }
3092
+
3093
+ .nim-plan-picker__plans {
3094
+ display: grid;
3095
+ gap: var(--nim-space-3);
3096
+ }
3097
+
3098
+ .nim-plan-picker__foot {
3099
+ display: grid;
3100
+ gap: var(--nim-space-3);
3101
+ }
3102
+
3103
+ .nim-plan-picker__note {
3104
+ margin: 0;
3105
+ text-align: center;
3106
+ font-size: var(--nim-type-caption-size);
3107
+ color: var(--nim-ink-tertiary);
3108
+ }
3109
+
3110
+ /* ═══════════════════════════════════════════════════════════════════════
3111
+ PROFILE SCREEN
3112
+ ═══════════════════════════════════════════════════════════════════════ */
3113
+ .nim-profile-screen {
3114
+ display: grid;
3115
+ gap: var(--nim-space-6);
3116
+ }
3117
+
3118
+ .nim-profile-screen__section {
3119
+ display: grid;
3120
+ gap: var(--nim-space-3);
3121
+ }
3122
+
3123
+ .nim-profile-screen__value {
3124
+ font-size: var(--nim-type-body-sm-size);
3125
+ color: var(--nim-ink-tertiary);
3126
+ }
3127
+
3128
+ .nim-list-row--danger .nim-list-row__title,
3129
+ .nim-list-row--danger .nim-list-row__leading {
3130
+ color: var(--nim-danger);
3131
+ }
3132
+
3133
+ .nim-profile-screen__footer {
3134
+ display: grid;
3135
+ gap: var(--nim-space-2);
3136
+ }
3137
+
3138
+ /* ═══════════════════════════════════════════════════════════════════════
3139
+ CHAT — transcript, bubbles, media
3140
+ A conversation is one scroll region between a header and a composer, and
3141
+ the bubbles are the only thing in the kit that changes side by author.
3142
+ ═══════════════════════════════════════════════════════════════════════ */
3143
+ .nim-chat {
3144
+ display: flex;
3145
+ flex-direction: column;
3146
+ block-size: 100%;
3147
+ min-block-size: 0;
3148
+ inline-size: 100%;
3149
+ background: var(--nim-canvas);
3150
+ overflow: hidden;
3151
+ }
3152
+
3153
+ .nim-chat__header {
3154
+ flex: none;
3155
+ display: flex;
3156
+ align-items: center;
3157
+ gap: var(--nim-space-3);
3158
+ padding: var(--nim-space-3) var(--nim-space-4);
3159
+ background: var(--nim-surface);
3160
+ border-block-end: var(--nim-border-width) solid var(--nim-line-soft);
3161
+ }
3162
+
3163
+ .nim-chat__scroll {
3164
+ flex: 1;
3165
+ min-block-size: 0;
3166
+ overflow-y: auto;
3167
+ overscroll-behavior-y: contain;
3168
+ padding: var(--nim-space-4);
3169
+ }
3170
+
3171
+ .nim-chat__list {
3172
+ display: flex;
3173
+ flex-direction: column;
3174
+ /* Not `stretch`: a bubble is as wide as its message, and a stretched row
3175
+ makes `max-inline-size` and the trailing alignment below both inert. */
3176
+ align-items: flex-start;
3177
+ gap: var(--nim-space-4);
3178
+ margin: 0;
3179
+ padding: 0;
3180
+ list-style: none;
3181
+ }
3182
+
3183
+ .nim-chat-message {
3184
+ display: flex;
3185
+ align-items: flex-end;
3186
+ gap: var(--nim-space-2);
3187
+ max-inline-size: 88%;
3188
+ }
3189
+
3190
+ /* The viewer's own messages sit on the trailing edge — which mirrors under
3191
+ RTL for free, because it is a logical alignment and not a left. */
3192
+ .nim-chat-message--own {
3193
+ align-self: flex-end;
3194
+ flex-direction: row-reverse;
3195
+ }
3196
+
3197
+ .nim-chat-message__avatar {
3198
+ flex: none;
3199
+ }
3200
+
3201
+ .nim-chat-message__stack {
3202
+ display: grid;
3203
+ gap: var(--nim-space-1);
3204
+ min-inline-size: 0;
3205
+ }
3206
+
3207
+ .nim-chat-message__author {
3208
+ font-size: var(--nim-type-label-size);
3209
+ font-weight: var(--nim-weight-medium);
3210
+ color: var(--nim-ink-tertiary);
3211
+ }
3212
+
3213
+ .nim-chat-message__bubble {
3214
+ display: grid;
3215
+ gap: var(--nim-space-2);
3216
+ padding: var(--nim-space-3) var(--nim-space-4);
3217
+ background: var(--nim-surface);
3218
+ border: var(--nim-border-width) solid var(--nim-line-soft);
3219
+ /* Square off the corner nearest the speaker: the one shape cue that says
3220
+ who is talking without any colour at all. */
3221
+ border-radius: var(--nim-radius-lg);
3222
+ border-start-start-radius: var(--nim-radius-xs);
3223
+ box-shadow: var(--nim-shadow-sm);
3224
+ }
3225
+
3226
+ .nim-chat-message--own .nim-chat-message__bubble {
3227
+ background: var(--nim-accent-soft);
3228
+ border-color: var(--nim-accent-line);
3229
+ border-start-start-radius: var(--nim-radius-lg);
3230
+ border-start-end-radius: var(--nim-radius-xs);
3231
+ }
3232
+
3233
+ .nim-chat-message__text {
3234
+ margin: 0;
3235
+ font-size: var(--nim-type-body-size);
3236
+ line-height: var(--nim-type-body-line);
3237
+ color: var(--nim-ink);
3238
+ /* A message keeps the line breaks the sender typed, and a pasted URL
3239
+ breaks rather than stretching the bubble past the viewport. */
3240
+ white-space: pre-wrap;
3241
+ overflow-wrap: anywhere;
3242
+ }
3243
+
3244
+ .nim-chat-message__meta {
3245
+ display: flex;
3246
+ align-items: center;
3247
+ gap: var(--nim-space-2);
3248
+ font-size: var(--nim-type-label-size);
3249
+ color: var(--nim-ink-tertiary);
3250
+ font-variant-numeric: tabular-nums;
3251
+ }
3252
+
3253
+ .nim-chat-message--own .nim-chat-message__meta {
3254
+ justify-content: flex-end;
3255
+ }
3256
+
3257
+ .nim-chat-message__status[data-status='read'] {
3258
+ color: var(--nim-accent);
3259
+ }
3260
+
3261
+ .nim-chat-message__status[data-status='failed'] {
3262
+ color: var(--nim-danger);
3263
+ }
3264
+
3265
+ .nim-chat__typing {
3266
+ display: flex;
3267
+ align-items: center;
3268
+ gap: var(--nim-space-2);
3269
+ margin: var(--nim-space-4) 0 0;
3270
+ font-size: var(--nim-type-caption-size);
3271
+ color: var(--nim-ink-tertiary);
3272
+ }
3273
+
3274
+ .nim-chat__dots {
3275
+ display: inline-flex;
3276
+ gap: 3px;
3277
+ }
3278
+
3279
+ .nim-chat__dots i {
3280
+ inline-size: var(--nim-size-dot);
3281
+ block-size: var(--nim-size-dot);
3282
+ border-radius: var(--nim-radius-pill);
3283
+ background: var(--nim-ink-tertiary);
3284
+ animation: nim-typing 1.1s var(--nim-ease-standard) infinite;
3285
+ }
3286
+
3287
+ .nim-chat__dots i:nth-child(2) {
3288
+ animation-delay: 0.15s;
3289
+ }
3290
+
3291
+ .nim-chat__dots i:nth-child(3) {
3292
+ animation-delay: 0.3s;
3293
+ }
3294
+
3295
+ .nim-chat__footer {
3296
+ margin-block-start: var(--nim-space-4);
3297
+ text-align: center;
3298
+ font-size: var(--nim-type-caption-size);
3299
+ color: var(--nim-ink-tertiary);
3300
+ }
3301
+
3302
+ .nim-chat__composer {
3303
+ flex: none;
3304
+ padding: var(--nim-space-3) var(--nim-space-4)
3305
+ calc(var(--nim-safe-bottom) + var(--nim-space-3));
3306
+ background: var(--nim-surface);
3307
+ border-block-start: var(--nim-border-width) solid var(--nim-line-soft);
3308
+ }
3309
+
3310
+ /* ─── Voice message ─────────────────────────────────────────────────── */
3311
+ .nim-chat-voice {
3312
+ display: flex;
3313
+ align-items: center;
3314
+ gap: var(--nim-space-3);
3315
+ min-inline-size: 11rem;
3316
+ }
3317
+
3318
+ .nim-chat-voice__wave {
3319
+ flex: 1;
3320
+ display: flex;
3321
+ align-items: center;
3322
+ gap: 2px;
3323
+ block-size: var(--nim-space-6);
3324
+ }
3325
+
3326
+ .nim-chat-voice__bar {
3327
+ flex: 1;
3328
+ min-inline-size: 2px;
3329
+ border-radius: var(--nim-radius-pill);
3330
+ background: var(--nim-line-strong);
3331
+ }
3332
+
3333
+ .nim-chat-voice__bar[data-played] {
3334
+ background: var(--nim-accent);
3335
+ }
3336
+
3337
+ .nim-chat-voice__time {
3338
+ font-family: var(--nim-font-numeric);
3339
+ font-variant-numeric: tabular-nums;
3340
+ font-size: var(--nim-type-caption-size);
3341
+ color: var(--nim-ink-tertiary);
3342
+ }
3343
+
3344
+ /* ─── Image and video ───────────────────────────────────────────────── */
3345
+ .nim-chat-media {
3346
+ margin: 0;
3347
+ display: grid;
3348
+ gap: var(--nim-space-1);
3349
+ }
3350
+
3351
+ .nim-chat-media img,
3352
+ .nim-chat-media video {
3353
+ inline-size: 100%;
3354
+ max-inline-size: 17rem;
3355
+ max-block-size: 20rem;
3356
+ border-radius: var(--nim-radius-md);
3357
+ background: var(--nim-canvas-sunken);
3358
+ display: block;
3359
+ }
3360
+
3361
+ .nim-chat-media__meta {
3362
+ font-size: var(--nim-type-label-size);
3363
+ color: var(--nim-ink-tertiary);
3364
+ font-variant-numeric: tabular-nums;
3365
+ }
3366
+
3367
+ /* ─── File ──────────────────────────────────────────────────────────── */
3368
+ .nim-chat-file {
3369
+ display: flex;
3370
+ align-items: center;
3371
+ gap: var(--nim-space-3);
3372
+ min-block-size: var(--nim-touch-min);
3373
+ padding: var(--nim-space-2);
3374
+ border-radius: var(--nim-radius-md);
3375
+ background: var(--nim-canvas-sunken);
3376
+ color: inherit;
3377
+ text-decoration: none;
3378
+ }
3379
+
3380
+ .nim-chat-file:hover {
3381
+ background: var(--nim-surface-muted);
3382
+ }
3383
+
3384
+ .nim-chat-file__icon {
3385
+ display: inline-flex;
3386
+ align-items: center;
3387
+ justify-content: center;
3388
+ inline-size: var(--nim-size-avatar-md);
3389
+ block-size: var(--nim-size-avatar-md);
3390
+ border-radius: var(--nim-radius-sm);
3391
+ background: var(--nim-surface);
3392
+ color: var(--nim-accent);
3393
+ flex: none;
3394
+ }
3395
+
3396
+ .nim-chat-file__text {
3397
+ display: grid;
3398
+ min-inline-size: 0;
3399
+ flex: 1;
3400
+ }
3401
+
3402
+ .nim-chat-file__name {
3403
+ font-size: var(--nim-type-body-sm-size);
3404
+ font-weight: var(--nim-weight-medium);
3405
+ overflow: hidden;
3406
+ text-overflow: ellipsis;
3407
+ white-space: nowrap;
3408
+ }
3409
+
3410
+ .nim-chat-file__size {
3411
+ font-size: var(--nim-type-label-size);
3412
+ color: var(--nim-ink-tertiary);
3413
+ font-variant-numeric: tabular-nums;
3414
+ }
3415
+
3416
+ .nim-chat-file__action {
3417
+ color: var(--nim-ink-tertiary);
3418
+ flex: none;
3419
+ }
3420
+
3421
+ /* ═══════════════════════════════════════════════════════════════════════
3422
+ COMPOSER — text, attachments, and a voice recorder
3423
+ ═══════════════════════════════════════════════════════════════════════ */
3424
+ .nim-composer {
3425
+ display: grid;
3426
+ gap: var(--nim-space-2);
3427
+ }
3428
+
3429
+ .nim-composer__tray {
3430
+ display: flex;
3431
+ flex-wrap: wrap;
3432
+ gap: var(--nim-space-2);
3433
+ margin: 0;
3434
+ padding: 0;
3435
+ list-style: none;
3436
+ }
3437
+
3438
+ .nim-composer__chip {
3439
+ display: inline-flex;
3440
+ align-items: center;
3441
+ gap: var(--nim-space-2);
3442
+ max-inline-size: 14rem;
3443
+ padding-inline-start: var(--nim-space-3);
3444
+ border-radius: var(--nim-radius-pill);
3445
+ background: var(--nim-surface-muted);
3446
+ border: var(--nim-border-width) solid var(--nim-line-soft);
3447
+ color: var(--nim-ink-secondary);
3448
+ font-size: var(--nim-type-label-size);
3449
+ }
3450
+
3451
+ .nim-composer__chip-name {
3452
+ overflow: hidden;
3453
+ text-overflow: ellipsis;
3454
+ white-space: nowrap;
3455
+ }
3456
+
3457
+ .nim-composer__row {
3458
+ display: flex;
3459
+ align-items: flex-end;
3460
+ gap: var(--nim-space-1);
3461
+ padding: var(--nim-space-1);
3462
+ background: var(--nim-canvas-sunken);
3463
+ border: var(--nim-border-width) solid var(--nim-line);
3464
+ border-radius: var(--nim-radius-lg);
3465
+ }
3466
+
3467
+ .nim-composer__row:focus-within {
3468
+ border-color: var(--nim-accent);
3469
+ }
3470
+
3471
+ .nim-composer__input {
3472
+ flex: 1;
3473
+ min-inline-size: 0;
3474
+ /* Grows with the message and stops before it owns the screen. */
3475
+ min-block-size: calc(var(--nim-control-md) * var(--nim-density));
3476
+ max-block-size: 8rem;
3477
+ padding-block: var(--nim-space-3);
3478
+ padding-inline: var(--nim-space-2);
3479
+ border: 0;
3480
+ background: transparent;
3481
+ resize: none;
3482
+ font-family: inherit;
3483
+ font-size: var(--nim-type-control-size);
3484
+ line-height: var(--nim-leading-normal);
3485
+ color: var(--nim-ink);
3486
+ field-sizing: content;
3487
+ }
3488
+
3489
+ .nim-composer__input:focus-visible {
3490
+ outline: none;
3491
+ }
3492
+
3493
+ .nim-composer__recording {
3494
+ display: flex;
3495
+ align-items: center;
3496
+ gap: var(--nim-space-3);
3497
+ inline-size: 100%;
3498
+ padding-inline-start: var(--nim-space-3);
3499
+ min-block-size: calc(var(--nim-control-md) * var(--nim-density));
3500
+ }
3501
+
3502
+ .nim-composer__recording-label {
3503
+ flex: 1;
3504
+ font-size: var(--nim-type-body-sm-size);
3505
+ color: var(--nim-ink-secondary);
3506
+ }
3507
+
3508
+ .nim-composer__elapsed {
3509
+ font-family: var(--nim-font-numeric);
3510
+ font-variant-numeric: tabular-nums;
3511
+ font-size: var(--nim-type-caption-size);
3512
+ color: var(--nim-ink-tertiary);
3513
+ }
3514
+
3515
+ /* The recording indicator is the one animation here that is information:
3516
+ it is how the viewer knows the microphone is live. */
3517
+ .nim-composer__pulse {
3518
+ inline-size: var(--nim-space-3);
3519
+ block-size: var(--nim-space-3);
3520
+ border-radius: var(--nim-radius-pill);
3521
+ background: var(--nim-danger);
3522
+ animation: nim-pulse 1.2s var(--nim-ease-standard) infinite;
3523
+ }
3524
+
3525
+ /* ═══════════════════════════════════════════════════════════════════════
3526
+ WIZARD — one question per screen
3527
+ ═══════════════════════════════════════════════════════════════════════ */
3528
+ .nim-wizard {
3529
+ display: flex;
3530
+ flex-direction: column;
3531
+ block-size: 100%;
3532
+ inline-size: 100%;
3533
+ max-inline-size: var(--nim-frame-max);
3534
+ margin-inline: auto;
3535
+ padding-block: calc(var(--nim-safe-top) + var(--nim-space-3))
3536
+ calc(var(--nim-safe-bottom) + var(--nim-space-5));
3537
+ padding-inline: var(--nim-space-5);
3538
+ background: var(--nim-canvas);
3539
+ }
3540
+
3541
+ .nim-wizard__bar {
3542
+ flex: none;
3543
+ display: flex;
3544
+ align-items: center;
3545
+ gap: var(--nim-space-3);
3546
+ }
3547
+
3548
+ /* Fixed-width slots on both ends keep the dots centred whether or not a
3549
+ back control exists on this step. */
3550
+ .nim-wizard__slot {
3551
+ inline-size: var(--nim-touch-min);
3552
+ display: flex;
3553
+ justify-content: center;
3554
+ flex: none;
3555
+ }
3556
+
3557
+ .nim-wizard__dots {
3558
+ flex: 1;
3559
+ display: flex;
3560
+ align-items: center;
3561
+ justify-content: center;
3562
+ gap: var(--nim-space-2);
3563
+ margin: 0;
3564
+ padding: 0;
3565
+ list-style: none;
3566
+ }
3567
+
3568
+ .nim-wizard__dot {
3569
+ inline-size: var(--nim-space-2);
3570
+ block-size: var(--nim-space-2);
3571
+ border-radius: var(--nim-radius-pill);
3572
+ background: var(--nim-line-strong);
3573
+ transition:
3574
+ inline-size var(--nim-dur-base) var(--nim-ease-spring),
3575
+ background-color var(--nim-dur-base) var(--nim-ease-standard);
3576
+ }
3577
+
3578
+ .nim-wizard__dot[data-done] {
3579
+ background: var(--nim-accent-soft);
3580
+ }
3581
+
3582
+ .nim-wizard__dot[data-on] {
3583
+ inline-size: var(--nim-space-6);
3584
+ background: var(--nim-accent);
3585
+ }
3586
+
3587
+ .nim-wizard__ask {
3588
+ flex: none;
3589
+ padding-block: var(--nim-space-6) var(--nim-space-4);
3590
+ }
3591
+
3592
+ .nim-wizard__question {
3593
+ margin: 0;
3594
+ font-size: var(--nim-type-title-lg-size);
3595
+ font-weight: var(--nim-type-title-lg-weight);
3596
+ line-height: var(--nim-leading-tight);
3597
+ letter-spacing: var(--nim-tracking-tight);
3598
+ color: var(--nim-ink);
3599
+ text-wrap: balance;
3600
+ }
3601
+
3602
+ .nim-wizard__subtitle {
3603
+ margin: var(--nim-space-2) 0 0;
3604
+ max-inline-size: var(--nim-measure);
3605
+ font-size: var(--nim-type-body-sm-size);
3606
+ line-height: var(--nim-type-body-line);
3607
+ color: var(--nim-ink-secondary);
3608
+ }
3609
+
3610
+ .nim-wizard__content {
3611
+ flex: 1;
3612
+ min-block-size: 0;
3613
+ overflow-y: auto;
3614
+ padding-block: var(--nim-space-2);
3615
+ }
3616
+
3617
+ .nim-wizard__foot {
3618
+ flex: none;
3619
+ padding-block-start: var(--nim-space-4);
3620
+ }
3621
+
3622
+ /* ─── Choice grid ───────────────────────────────────────────────────── */
3623
+ .nim-choice-grid {
3624
+ display: grid;
3625
+ grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
3626
+ gap: var(--nim-space-3);
3627
+ }
3628
+
3629
+ .nim-choice-grid__tile {
3630
+ display: flex;
3631
+ flex-direction: column;
3632
+ align-items: center;
3633
+ justify-content: center;
3634
+ gap: var(--nim-space-2);
3635
+ min-block-size: 6rem;
3636
+ padding: var(--nim-space-3);
3637
+ background: var(--nim-surface);
3638
+ border: var(--nim-border-width) solid var(--nim-line);
3639
+ border-radius: var(--nim-radius-lg);
3640
+ color: var(--nim-ink-secondary);
3641
+ font-family: inherit;
3642
+ font-size: var(--nim-type-body-sm-size);
3643
+ text-align: center;
3644
+ cursor: pointer;
3645
+ transition:
3646
+ background-color var(--nim-dur-fast) var(--nim-ease-standard),
3647
+ border-color var(--nim-dur-fast) var(--nim-ease-standard),
3648
+ color var(--nim-dur-fast) var(--nim-ease-standard);
3649
+ }
3650
+
3651
+ .nim-choice-grid__tile:hover:not(:disabled) {
3652
+ border-color: var(--nim-line-strong);
3653
+ }
3654
+
3655
+ .nim-choice-grid__tile[data-on] {
3656
+ background: var(--nim-accent-soft);
3657
+ border-color: var(--nim-accent);
3658
+ color: var(--nim-accent);
3659
+ }
3660
+
3661
+ .nim-choice-grid__tile:focus-visible {
3662
+ outline: none;
3663
+ box-shadow: var(--nim-shadow-focus);
3664
+ }
3665
+
3666
+ .nim-choice-grid__tile:disabled {
3667
+ opacity: 0.45;
3668
+ cursor: not-allowed;
3669
+ }
3670
+
3671
+ .nim-choice-grid__icon {
3672
+ display: flex;
3673
+ align-items: center;
3674
+ justify-content: center;
3675
+ }
3676
+
3677
+ .nim-choice-grid__label {
3678
+ line-height: var(--nim-leading-tight);
3679
+ }
3680
+
3681
+ /* ═══════════════════════════════════════════════════════════════════════
3682
+ OPTION CARD — one choice among several
3683
+ ═══════════════════════════════════════════════════════════════════════ */
3684
+ .nim-option-card {
3685
+ position: relative;
3686
+ display: flex;
3687
+ align-items: center;
3688
+ gap: var(--nim-space-3);
3689
+ min-block-size: var(--nim-touch-min);
3690
+ padding: var(--nim-space-4);
3691
+ background: var(--nim-surface);
3692
+ border: var(--nim-border-width) solid var(--nim-line);
3693
+ border-radius: var(--nim-radius-lg);
3694
+ cursor: pointer;
3695
+ transition:
3696
+ background-color var(--nim-dur-fast) var(--nim-ease-standard),
3697
+ border-color var(--nim-dur-fast) var(--nim-ease-standard);
3698
+ }
3699
+
3700
+ .nim-option-card:hover {
3701
+ border-color: var(--nim-line-strong);
3702
+ }
3703
+
3704
+ .nim-option-card--selected {
3705
+ background: var(--nim-accent-soft);
3706
+ border-color: var(--nim-accent);
3707
+ }
3708
+
3709
+ /* The radio is real and focusable; the card is its label, so the ring is
3710
+ drawn on the plate the viewer is actually looking at. */
3711
+ .nim-option-card__input {
3712
+ position: absolute;
3713
+ opacity: 0;
3714
+ inline-size: 1px;
3715
+ block-size: 1px;
3716
+ margin: 0;
3717
+ }
3718
+
3719
+ .nim-option-card:has(.nim-option-card__input:focus-visible) {
3720
+ outline: none;
3721
+ box-shadow: var(--nim-shadow-focus);
3722
+ }
3723
+
3724
+ .nim-option-card:has(.nim-option-card__input:disabled) {
3725
+ opacity: 0.55;
3726
+ cursor: not-allowed;
3727
+ }
3728
+
3729
+ .nim-option-card__icon {
3730
+ display: inline-flex;
3731
+ align-items: center;
3732
+ justify-content: center;
3733
+ inline-size: var(--nim-size-avatar-md);
3734
+ block-size: var(--nim-size-avatar-md);
3735
+ border-radius: var(--nim-radius-md);
3736
+ background: var(--nim-canvas-sunken);
3737
+ color: var(--nim-accent);
3738
+ flex: none;
3739
+ }
3740
+
3741
+ .nim-option-card__text {
3742
+ display: grid;
3743
+ gap: var(--nim-space-1);
3744
+ flex: 1;
3745
+ min-inline-size: 0;
3746
+ }
3747
+
3748
+ .nim-option-card__title {
3749
+ font-size: var(--nim-type-body-size);
3750
+ font-weight: var(--nim-weight-medium);
3751
+ color: var(--nim-ink);
3752
+ line-height: var(--nim-leading-tight);
3753
+ }
3754
+
3755
+ .nim-option-card__description,
3756
+ .nim-option-card__detail {
3757
+ font-size: var(--nim-type-caption-size);
3758
+ line-height: var(--nim-leading-normal);
3759
+ color: var(--nim-ink-tertiary);
3760
+ }
3761
+
3762
+ .nim-option-card__detail {
3763
+ color: var(--nim-ink-secondary);
3764
+ font-family: var(--nim-font-numeric);
3765
+ }
3766
+
3767
+ .nim-option-card__badge {
3768
+ font-size: var(--nim-type-label-size);
3769
+ font-weight: var(--nim-weight-medium);
3770
+ color: var(--nim-ink-tertiary);
3771
+ white-space: nowrap;
3772
+ flex: none;
3773
+ }
3774
+
3775
+ .nim-option-card--selected .nim-option-card__badge {
3776
+ color: var(--nim-accent);
3777
+ }
3778
+
3779
+ .nim-option-card__dot {
3780
+ flex: none;
3781
+ inline-size: var(--nim-size-icon-md);
3782
+ block-size: var(--nim-size-icon-md);
3783
+ border-radius: var(--nim-radius-pill);
3784
+ border: var(--nim-border-width) solid var(--nim-line-strong);
3785
+ background: var(--nim-surface);
3786
+ transition: border-width var(--nim-dur-fast) var(--nim-ease-standard);
3787
+ }
3788
+
3789
+ .nim-option-card--selected .nim-option-card__dot {
3790
+ border: 6px solid var(--nim-accent);
3791
+ }
3792
+
3793
+ /* ═══════════════════════════════════════════════════════════════════════
3794
+ ORDER SUMMARY · ACTION BAR
3795
+ ═══════════════════════════════════════════════════════════════════════ */
3796
+ .nim-summary {
3797
+ display: grid;
3798
+ gap: var(--nim-space-4);
3799
+ padding: var(--nim-space-5);
3800
+ background: var(--nim-surface);
3801
+ border: var(--nim-border-width) solid var(--nim-line);
3802
+ border-radius: var(--nim-radius-lg);
3803
+ }
3804
+
3805
+ .nim-summary__title {
3806
+ margin: 0;
3807
+ font-size: var(--nim-type-title-md-size);
3808
+ font-weight: var(--nim-type-title-md-weight);
3809
+ color: var(--nim-ink);
3810
+ }
3811
+
3812
+ .nim-summary__lines {
3813
+ display: grid;
3814
+ gap: var(--nim-space-3);
3815
+ margin: 0;
3816
+ }
3817
+
3818
+ .nim-summary__lines--totals {
3819
+ gap: var(--nim-space-2);
3820
+ }
3821
+
3822
+ .nim-summary__line {
3823
+ display: flex;
3824
+ align-items: flex-start;
3825
+ justify-content: space-between;
3826
+ gap: var(--nim-space-4);
3827
+ }
3828
+
3829
+ .nim-summary__line > dt {
3830
+ display: grid;
3831
+ gap: 2px;
3832
+ min-inline-size: 0;
3833
+ }
3834
+
3835
+ .nim-summary__label {
3836
+ font-size: var(--nim-type-body-sm-size);
3837
+ color: var(--nim-ink);
3838
+ }
3839
+
3840
+ .nim-summary__meta {
3841
+ font-size: var(--nim-type-label-size);
3842
+ color: var(--nim-ink-tertiary);
3843
+ }
3844
+
3845
+ .nim-summary__value {
3846
+ margin: 0;
3847
+ flex: none;
3848
+ font-family: var(--nim-font-numeric);
3849
+ font-variant-numeric: tabular-nums;
3850
+ font-size: var(--nim-type-body-sm-size);
3851
+ color: var(--nim-ink-secondary);
3852
+ white-space: nowrap;
3853
+ }
3854
+
3855
+ .nim-summary__lines--totals .nim-summary__label,
3856
+ .nim-summary__lines--totals .nim-summary__value {
3857
+ color: var(--nim-ink-tertiary);
3858
+ }
3859
+
3860
+ /* The total is the one line the eye should land on, so it is the only one
3861
+ that gets weight — and there is at most one of it. */
3862
+ .nim-summary__line[data-emphasis] .nim-summary__label,
3863
+ .nim-summary__line[data-emphasis] .nim-summary__value {
3864
+ font-size: var(--nim-type-body-size);
3865
+ font-weight: var(--nim-weight-semibold);
3866
+ color: var(--nim-ink);
3867
+ }
3868
+
3869
+ .nim-summary__rule {
3870
+ margin: 0;
3871
+ border: 0;
3872
+ border-block-start: var(--nim-border-width) solid var(--nim-line-soft);
3873
+ }
3874
+
3875
+ .nim-action-bar {
3876
+ position: sticky;
3877
+ inset-block-end: 0;
3878
+ z-index: var(--nim-z-sticky);
3879
+ display: grid;
3880
+ gap: var(--nim-space-2);
3881
+ padding: var(--nim-space-4) var(--nim-space-4)
3882
+ calc(var(--nim-safe-bottom) + var(--nim-space-4));
3883
+ background: var(--nim-surface);
3884
+ border-block-start: var(--nim-border-width) solid var(--nim-line-soft);
3885
+ box-shadow: var(--nim-shadow-lg);
3886
+ }
3887
+
3888
+ .nim-action-bar__row {
3889
+ display: flex;
3890
+ align-items: center;
3891
+ gap: var(--nim-space-4);
3892
+ }
3893
+
3894
+ .nim-action-bar__total {
3895
+ display: grid;
3896
+ gap: 2px;
3897
+ flex: none;
3898
+ }
3899
+
3900
+ .nim-action-bar__total-label {
3901
+ font-size: var(--nim-type-label-size);
3902
+ color: var(--nim-ink-tertiary);
3903
+ }
3904
+
3905
+ .nim-action-bar__total-value {
3906
+ font-family: var(--nim-font-numeric);
3907
+ font-variant-numeric: tabular-nums;
3908
+ font-size: var(--nim-type-title-md-size);
3909
+ color: var(--nim-ink);
3910
+ line-height: var(--nim-leading-tight);
3911
+ }
3912
+
3913
+ .nim-action-bar__action {
3914
+ flex: 1;
3915
+ display: flex;
3916
+ justify-content: flex-end;
3917
+ }
3918
+
3919
+ .nim-action-bar__note {
3920
+ margin: 0;
3921
+ font-size: var(--nim-type-caption-size);
3922
+ color: var(--nim-ink-tertiary);
3923
+ }
3924
+
3925
+ /* ═══════════════════════════════════════════════════════════════════════
3926
+ TASK PROGRESS — a job with named stages
3927
+ ═══════════════════════════════════════════════════════════════════════ */
3928
+ .nim-task {
3929
+ display: grid;
3930
+ gap: var(--nim-space-5);
3931
+ padding: var(--nim-space-5);
3932
+ background: var(--nim-surface);
3933
+ border: var(--nim-border-width) solid var(--nim-line);
3934
+ border-radius: var(--nim-radius-lg);
3935
+ }
3936
+
3937
+ .nim-task__head {
3938
+ display: grid;
3939
+ gap: var(--nim-space-3);
3940
+ }
3941
+
3942
+ .nim-task__title {
3943
+ margin: 0;
3944
+ font-size: var(--nim-type-title-md-size);
3945
+ font-weight: var(--nim-type-title-md-weight);
3946
+ color: var(--nim-ink);
3947
+ }
3948
+
3949
+ .nim-task__caption {
3950
+ margin: 0;
3951
+ font-size: var(--nim-type-body-sm-size);
3952
+ color: var(--nim-ink-secondary);
3953
+ }
3954
+
3955
+ .nim-task--failed .nim-progress__fill {
3956
+ background: var(--nim-danger);
3957
+ }
3958
+
3959
+ .nim-task__steps {
3960
+ display: grid;
3961
+ gap: var(--nim-space-3);
3962
+ margin: 0;
3963
+ padding: 0;
3964
+ list-style: none;
3965
+ }
3966
+
3967
+ .nim-task__step {
3968
+ display: flex;
3969
+ align-items: flex-start;
3970
+ gap: var(--nim-space-3);
3971
+ }
3972
+
3973
+ .nim-task__marker {
3974
+ display: inline-flex;
3975
+ align-items: center;
3976
+ justify-content: center;
3977
+ inline-size: var(--nim-size-icon-lg);
3978
+ block-size: var(--nim-size-icon-lg);
3979
+ border-radius: var(--nim-radius-pill);
3980
+ background: var(--nim-canvas-sunken);
3981
+ color: var(--nim-ink-tertiary);
3982
+ flex: none;
3983
+ }
3984
+
3985
+ .nim-task__step[data-status='done'] .nim-task__marker {
3986
+ background: var(--nim-success-soft);
3987
+ color: var(--nim-success);
3988
+ }
3989
+
3990
+ .nim-task__step[data-status='failed'] .nim-task__marker {
3991
+ background: var(--nim-danger-soft);
3992
+ color: var(--nim-danger);
3993
+ }
3994
+
3995
+ .nim-task__step[data-status='active'] .nim-task__marker {
3996
+ background: var(--nim-accent-soft);
3997
+ color: var(--nim-accent);
3998
+ }
3999
+
4000
+ .nim-task__step-text {
4001
+ display: grid;
4002
+ gap: 2px;
4003
+ min-inline-size: 0;
4004
+ }
4005
+
4006
+ .nim-task__step-label {
4007
+ font-size: var(--nim-type-body-sm-size);
4008
+ color: var(--nim-ink);
4009
+ }
4010
+
4011
+ .nim-task__step[data-status='pending'] .nim-task__step-label,
4012
+ .nim-task__step[data-status='skipped'] .nim-task__step-label {
4013
+ color: var(--nim-ink-tertiary);
4014
+ }
4015
+
4016
+ .nim-task__step-detail {
4017
+ font-size: var(--nim-type-label-size);
4018
+ color: var(--nim-ink-tertiary);
4019
+ }
4020
+
4021
+ .nim-task__step[data-status='failed'] .nim-task__step-detail {
4022
+ color: var(--nim-danger);
4023
+ }
4024
+
4025
+ /* ═══════════════════════════════════════════════════════════════════════
4026
+ ADMIN SHELL — sidebar, topbar, workspace
4027
+ ═══════════════════════════════════════════════════════════════════════ */
4028
+ /* A flex row rather than a grid, and its own container: the console is as
4029
+ likely to be embedded in a panel as to fill a window, and a layout that
4030
+ only answers the viewport is wrong in the first case. Sizing the sidebar
4031
+ on the child instead of the parent is what lets the query below live on
4032
+ descendants, which is the only place a container query may. */
4033
+ .nim-admin {
4034
+ container-type: inline-size;
4035
+ display: flex;
4036
+ block-size: 100%;
4037
+ background: var(--nim-canvas-sunken);
4038
+ }
4039
+
4040
+ .nim-admin__sidebar {
4041
+ inline-size: 16rem;
4042
+ flex: none;
4043
+ display: flex;
4044
+ flex-direction: column;
4045
+ gap: var(--nim-space-5);
4046
+ min-block-size: 0;
4047
+ overflow-y: auto;
4048
+ padding: var(--nim-space-5) var(--nim-space-4);
4049
+ background: var(--nim-surface);
4050
+ border-inline-end: var(--nim-border-width) solid var(--nim-line-soft);
4051
+ }
4052
+
4053
+ .nim-admin__nav {
4054
+ display: grid;
4055
+ gap: var(--nim-space-5);
4056
+ flex: 1;
4057
+ }
4058
+
4059
+ .nim-admin__group {
4060
+ display: grid;
4061
+ gap: var(--nim-space-1);
4062
+ }
4063
+
4064
+ .nim-admin__group-label {
4065
+ display: flex;
4066
+ align-items: center;
4067
+ gap: var(--nim-space-2);
4068
+ margin: 0 0 var(--nim-space-1);
4069
+ padding-inline: var(--nim-space-3);
4070
+ font-size: var(--nim-type-label-size);
4071
+ font-weight: var(--nim-weight-medium);
4072
+ text-transform: var(--nim-label-transform);
4073
+ letter-spacing: var(--nim-label-tracking);
4074
+ color: var(--nim-ink-tertiary);
4075
+ }
4076
+
4077
+ .nim-admin__link {
4078
+ display: flex;
4079
+ align-items: center;
4080
+ gap: var(--nim-space-3);
4081
+ inline-size: 100%;
4082
+ min-block-size: calc(var(--nim-control-md) * var(--nim-density));
4083
+ padding-inline: var(--nim-space-3);
4084
+ border: 0;
4085
+ border-radius: var(--nim-radius-md);
4086
+ background: none;
4087
+ color: var(--nim-ink-secondary);
4088
+ font-family: inherit;
4089
+ font-size: var(--nim-type-body-sm-size);
4090
+ text-align: start;
4091
+ text-decoration: none;
4092
+ cursor: pointer;
4093
+ transition:
4094
+ background-color var(--nim-dur-fast) var(--nim-ease-standard),
4095
+ color var(--nim-dur-fast) var(--nim-ease-standard);
4096
+ }
4097
+
4098
+ .nim-admin__link:hover {
4099
+ background: var(--nim-surface-muted);
4100
+ color: var(--nim-ink);
4101
+ }
4102
+
4103
+ .nim-admin__link[data-active] {
4104
+ background: var(--nim-accent-soft);
4105
+ color: var(--nim-accent);
4106
+ font-weight: var(--nim-weight-medium);
4107
+ }
4108
+
4109
+ .nim-admin__link:focus-visible {
4110
+ outline: none;
4111
+ box-shadow: var(--nim-shadow-focus);
4112
+ }
4113
+
4114
+ .nim-admin__sidebar-foot {
4115
+ display: grid;
4116
+ gap: var(--nim-space-1);
4117
+ padding-block-start: var(--nim-space-4);
4118
+ border-block-start: var(--nim-border-width) solid var(--nim-line-soft);
4119
+ font-size: var(--nim-type-label-size);
4120
+ color: var(--nim-ink-tertiary);
4121
+ }
4122
+
4123
+ .nim-admin__workspace {
4124
+ display: flex;
4125
+ flex-direction: column;
4126
+ min-inline-size: 0;
4127
+ min-block-size: 0;
4128
+ }
4129
+
4130
+ .nim-admin__topbar {
4131
+ flex: none;
4132
+ display: flex;
4133
+ align-items: center;
4134
+ gap: var(--nim-space-3);
4135
+ min-block-size: var(--nim-control-lg);
4136
+ padding: var(--nim-space-3) var(--nim-space-5);
4137
+ background: var(--nim-surface);
4138
+ border-block-end: var(--nim-border-width) solid var(--nim-line-soft);
4139
+ }
4140
+
4141
+ .nim-admin__title {
4142
+ margin: 0;
4143
+ font-size: var(--nim-type-title-md-size);
4144
+ font-weight: var(--nim-type-title-md-weight);
4145
+ color: var(--nim-ink);
4146
+ }
4147
+
4148
+ .nim-admin__toolbar {
4149
+ margin-inline-start: auto;
4150
+ display: flex;
4151
+ align-items: center;
4152
+ gap: var(--nim-space-2);
4153
+ }
4154
+
4155
+ .nim-admin__main {
4156
+ flex: 1;
4157
+ min-block-size: 0;
4158
+ overflow-y: auto;
4159
+ padding: var(--nim-space-5);
4160
+ }
4161
+
4162
+ /* The drawer only exists below the breakpoint; above it the sidebar is the
4163
+ navigation and the trigger is not rendered at all. */
4164
+ .nim-admin__menu,
4165
+ .nim-admin__drawer {
4166
+ display: none;
4167
+ }
4168
+
4169
+ @container (max-width: 60rem) {
4170
+ .nim-admin__sidebar {
4171
+ display: none;
4172
+ }
4173
+
4174
+ .nim-admin__menu {
4175
+ display: inline-flex;
4176
+ }
4177
+
4178
+ .nim-admin[data-drawer='open'] .nim-admin__drawer {
4179
+ display: block;
4180
+ }
4181
+
4182
+ .nim-admin__scrim {
4183
+ position: fixed;
4184
+ inset: 0;
4185
+ z-index: var(--nim-z-scrim);
4186
+ background: var(--nim-scrim);
4187
+ }
4188
+
4189
+ .nim-admin__drawer-panel {
4190
+ position: fixed;
4191
+ inset-block: 0;
4192
+ inset-inline-start: 0;
4193
+ z-index: var(--nim-z-sheet);
4194
+ inline-size: min(18rem, 84vw);
4195
+ display: flex;
4196
+ flex-direction: column;
4197
+ gap: var(--nim-space-4);
4198
+ overflow-y: auto;
4199
+ padding: var(--nim-space-4);
4200
+ background: var(--nim-surface);
4201
+ box-shadow: var(--nim-shadow-lg);
4202
+ animation: nim-drawer var(--nim-dur-base) var(--nim-ease-decelerate);
4203
+ }
4204
+
4205
+ .nim-admin__drawer-head {
4206
+ display: flex;
4207
+ align-items: center;
4208
+ justify-content: space-between;
4209
+ gap: var(--nim-space-3);
4210
+ }
4211
+ }
4212
+
4213
+ /* ═══════════════════════════════════════════════════════════════════════
4214
+ DETAIL HEADER · FILTER CHIPS · ACTIVITY FEED
4215
+ ═══════════════════════════════════════════════════════════════════════ */
4216
+ .nim-detail-header {
4217
+ display: grid;
4218
+ gap: var(--nim-space-3);
4219
+ }
4220
+
4221
+ .nim-detail-header__back {
4222
+ display: inline-flex;
4223
+ align-items: center;
4224
+ gap: var(--nim-space-1);
4225
+ align-self: start;
4226
+ min-block-size: var(--nim-touch-min);
4227
+ padding: 0;
4228
+ border: 0;
4229
+ background: none;
4230
+ color: var(--nim-ink-tertiary);
4231
+ font-family: inherit;
4232
+ font-size: var(--nim-type-body-sm-size);
4233
+ text-decoration: none;
4234
+ cursor: pointer;
4235
+ }
4236
+
4237
+ .nim-detail-header__back:hover {
4238
+ color: var(--nim-accent);
4239
+ }
4240
+
4241
+ .nim-detail-header__row {
4242
+ display: flex;
4243
+ align-items: flex-start;
4244
+ justify-content: space-between;
4245
+ gap: var(--nim-space-4);
4246
+ flex-wrap: wrap;
4247
+ }
4248
+
4249
+ .nim-detail-header__headline {
4250
+ display: flex;
4251
+ align-items: center;
4252
+ gap: var(--nim-space-3);
4253
+ flex-wrap: wrap;
4254
+ }
4255
+
4256
+ .nim-detail-header__title {
4257
+ margin: 0;
4258
+ font-size: var(--nim-type-title-lg-size);
4259
+ font-weight: var(--nim-type-title-lg-weight);
4260
+ line-height: var(--nim-leading-tight);
4261
+ color: var(--nim-ink);
4262
+ }
4263
+
4264
+ .nim-detail-header__subtitle {
4265
+ margin: var(--nim-space-2) 0 0;
4266
+ max-inline-size: var(--nim-measure);
4267
+ font-size: var(--nim-type-body-sm-size);
4268
+ color: var(--nim-ink-secondary);
4269
+ }
4270
+
4271
+ .nim-detail-header__meta {
4272
+ margin: var(--nim-space-1) 0 0;
4273
+ font-size: var(--nim-type-label-size);
4274
+ color: var(--nim-ink-tertiary);
4275
+ }
4276
+
4277
+ .nim-detail-header__actions {
4278
+ display: flex;
4279
+ align-items: center;
4280
+ gap: var(--nim-space-2);
4281
+ flex-wrap: wrap;
4282
+ }
4283
+
4284
+ .nim-filter-chips {
4285
+ display: flex;
4286
+ flex-wrap: wrap;
4287
+ align-items: center;
4288
+ gap: var(--nim-space-2);
4289
+ }
4290
+
4291
+ .nim-filter-chip {
4292
+ display: inline-flex;
4293
+ align-items: center;
4294
+ gap: var(--nim-space-1);
4295
+ padding-inline-start: var(--nim-space-3);
4296
+ border-radius: var(--nim-radius-pill);
4297
+ border: var(--nim-border-width) solid var(--nim-accent-line);
4298
+ background: var(--nim-accent-soft);
4299
+ color: var(--nim-accent);
4300
+ font-size: var(--nim-type-label-size);
4301
+ font-weight: var(--nim-weight-medium);
4302
+ }
4303
+
4304
+ .nim-filter-chip__remove {
4305
+ display: inline-flex;
4306
+ align-items: center;
4307
+ justify-content: center;
4308
+ inline-size: var(--nim-control-sm);
4309
+ block-size: var(--nim-control-sm);
4310
+ border: 0;
4311
+ border-radius: var(--nim-radius-pill);
4312
+ background: none;
4313
+ color: inherit;
4314
+ cursor: pointer;
4315
+ }
4316
+
4317
+ .nim-filter-chip__remove:hover {
4318
+ background: color-mix(in srgb, var(--nim-accent) 14%, transparent);
4319
+ }
4320
+
4321
+ .nim-filter-chip__remove:focus-visible {
4322
+ outline: none;
4323
+ box-shadow: var(--nim-shadow-focus);
4324
+ }
4325
+
4326
+ .nim-filter-chips__clear {
4327
+ min-block-size: var(--nim-control-sm);
4328
+ padding-inline: var(--nim-space-2);
4329
+ border: 0;
4330
+ background: none;
4331
+ color: var(--nim-ink-tertiary);
4332
+ font-family: inherit;
4333
+ font-size: var(--nim-type-label-size);
4334
+ text-decoration: underline;
4335
+ text-underline-offset: 3px;
4336
+ cursor: pointer;
4337
+ }
4338
+
4339
+ .nim-activity {
4340
+ display: grid;
4341
+ gap: 0;
4342
+ margin: 0;
4343
+ padding: 0;
4344
+ list-style: none;
4345
+ }
4346
+
4347
+ .nim-activity__item {
4348
+ position: relative;
4349
+ display: flex;
4350
+ gap: var(--nim-space-3);
4351
+ padding-block: var(--nim-space-3);
4352
+ }
4353
+
4354
+ /* The thread between markers is drawn by the items, so the last one has no
4355
+ tail hanging off the end of the list. */
4356
+ .nim-activity__item:not(:last-child)::before {
4357
+ content: '';
4358
+ position: absolute;
4359
+ inset-block-start: calc(var(--nim-space-3) + var(--nim-size-icon-lg));
4360
+ inset-block-end: 0;
4361
+ inset-inline-start: calc(var(--nim-size-icon-lg) / 2);
4362
+ inline-size: var(--nim-border-width);
4363
+ background: var(--nim-line-soft);
4364
+ }
4365
+
4366
+ .nim-activity__marker {
4367
+ position: relative;
4368
+ display: inline-flex;
4369
+ align-items: center;
4370
+ justify-content: center;
4371
+ inline-size: var(--nim-size-icon-lg);
4372
+ block-size: var(--nim-size-icon-lg);
4373
+ border-radius: var(--nim-radius-pill);
4374
+ background: var(--nim-canvas-sunken);
4375
+ color: var(--nim-ink-tertiary);
4376
+ flex: none;
4377
+ }
4378
+
4379
+ .nim-activity__item[data-tone='accent'] .nim-activity__marker {
4380
+ background: var(--nim-accent-soft);
4381
+ color: var(--nim-accent);
4382
+ }
4383
+ .nim-activity__item[data-tone='success'] .nim-activity__marker {
4384
+ background: var(--nim-success-soft);
4385
+ color: var(--nim-success);
4386
+ }
4387
+ .nim-activity__item[data-tone='warning'] .nim-activity__marker {
4388
+ background: var(--nim-warning-soft);
4389
+ color: var(--nim-warning);
4390
+ }
4391
+ .nim-activity__item[data-tone='danger'] .nim-activity__marker {
4392
+ background: var(--nim-danger-soft);
4393
+ color: var(--nim-danger);
4394
+ }
4395
+
4396
+ .nim-activity__body {
4397
+ display: grid;
4398
+ gap: 2px;
4399
+ min-inline-size: 0;
4400
+ }
4401
+
4402
+ .nim-activity__action {
4403
+ margin: 0;
4404
+ font-size: var(--nim-type-body-sm-size);
4405
+ line-height: var(--nim-leading-normal);
4406
+ color: var(--nim-ink-secondary);
4407
+ }
4408
+
4409
+ .nim-activity__action strong {
4410
+ color: var(--nim-ink);
4411
+ font-weight: var(--nim-weight-medium);
4412
+ }
4413
+
4414
+ .nim-activity__target {
4415
+ color: var(--nim-accent);
4416
+ }
4417
+
4418
+ .nim-activity__time {
4419
+ font-size: var(--nim-type-label-size);
4420
+ color: var(--nim-ink-tertiary);
4421
+ font-variant-numeric: tabular-nums;
4422
+ }
4423
+
4424
+ /* ═══════════════════════════════════════════════════════════════════════
4425
+ RESOURCE METER — a labelled capacity reading for operator views
4426
+ ═══════════════════════════════════════════════════════════════════════ */
4427
+ .nim-resource-meter {
4428
+ display: grid;
4429
+ gap: var(--nim-space-2);
4430
+ min-inline-size: 0;
4431
+ }
4432
+
4433
+ .nim-resource-meter__head {
4434
+ display: flex;
4435
+ align-items: baseline;
4436
+ justify-content: space-between;
4437
+ gap: var(--nim-space-3);
4438
+ min-inline-size: 0;
4439
+ }
4440
+
4441
+ .nim-resource-meter__label {
4442
+ min-inline-size: 0;
4443
+ overflow: hidden;
4444
+ color: var(--nim-ink-secondary);
4445
+ font-size: var(--nim-type-label-size);
4446
+ text-overflow: ellipsis;
4447
+ white-space: nowrap;
4448
+ }
4449
+
4450
+ .nim-resource-meter__value {
4451
+ color: var(--nim-ink);
4452
+ font-size: var(--nim-type-label-size);
4453
+ font-variant-numeric: tabular-nums;
4454
+ white-space: nowrap;
4455
+ }
4456
+
4457
+ .nim-resource-meter__track {
4458
+ block-size: var(--nim-size-track);
4459
+ overflow: hidden;
4460
+ border-radius: var(--nim-radius-pill);
4461
+ background: var(--nim-line-soft);
4462
+ }
4463
+
4464
+ .nim-resource-meter__fill {
4465
+ display: block;
4466
+ block-size: 100%;
4467
+ border-radius: inherit;
4468
+ background: var(--nim-accent);
4469
+ transition: inline-size var(--nim-dur-slow) var(--nim-ease-decelerate);
4470
+ }
4471
+
4472
+ .nim-resource-meter[data-tone='success'] .nim-resource-meter__fill {
4473
+ background: var(--nim-success);
4474
+ }
4475
+
4476
+ .nim-resource-meter[data-tone='warning'] .nim-resource-meter__fill {
4477
+ background: var(--nim-warning);
4478
+ }
4479
+
4480
+ .nim-resource-meter[data-tone='danger'] .nim-resource-meter__fill {
4481
+ background: var(--nim-danger);
4482
+ }
4483
+
4484
+ .nim-resource-meter__detail {
4485
+ color: var(--nim-ink-tertiary);
4486
+ font-size: var(--nim-type-label-size);
4487
+ }
4488
+ }
4489
+
4490
+ /* ═══════════════════════════════════════════════════════════════════════════
4491
+ KEYFRAMES — outside @layer so they are never shadowed by a consumer layer
4492
+ ═══════════════════════════════════════════════════════════════════════════ */
4493
+ @keyframes nim-spin {
4494
+ to {
4495
+ rotate: 360deg;
4496
+ }
4497
+ }
4498
+
4499
+ @keyframes nim-fade-in {
4500
+ from {
4501
+ opacity: 0;
4502
+ }
4503
+ }
4504
+
4505
+ @keyframes nim-rise {
4506
+ from {
4507
+ opacity: 0;
4508
+ translate: 0 12px;
4509
+ }
4510
+ }
4511
+
4512
+ @keyframes nim-slide {
4513
+ from {
4514
+ translate: -100% 0;
4515
+ }
4516
+ to {
4517
+ translate: 300% 0;
4518
+ }
4519
+ }
4520
+
4521
+ @keyframes nim-sweep {
4522
+ from {
4523
+ translate: -100% 0;
4524
+ }
4525
+ to {
4526
+ translate: 100% 0;
4527
+ }
4528
+ }
4529
+
4530
+ @keyframes nim-typing {
4531
+ 0%,
4532
+ 60%,
4533
+ 100% {
4534
+ opacity: 0.3;
4535
+ translate: 0 0;
4536
+ }
4537
+ 30% {
4538
+ opacity: 1;
4539
+ translate: 0 -3px;
4540
+ }
4541
+ }
4542
+
4543
+ @keyframes nim-pulse {
4544
+ 50% {
4545
+ opacity: 0.35;
4546
+ scale: 0.8;
4547
+ }
4548
+ }
4549
+
4550
+ @keyframes nim-drawer {
4551
+ from {
4552
+ translate: -100% 0;
4553
+ }
4554
+ }
4555
+
4556
+ @keyframes nim-pop {
4557
+ from {
4558
+ opacity: 0;
4559
+ translate: 0 -4px;
4560
+ }
4561
+ }
4562
+
4563
+ /* ═══════════════════════════════════════════════════════════════════════════
4564
+ REDUCED MOTION
4565
+
4566
+ Outside `@layer` so it wins against every component rule above.
4567
+
4568
+ The blanket rule is deliberately not the whole answer. Three of the kit's
4569
+ animations are not decoration — they are the only signal that something is
4570
+ happening, and stopping them outright leaves a viewer unable to tell a busy
4571
+ interface from a hung one. Reduced motion is a vestibular accommodation, not
4572
+ a request for less information.
4573
+ ═══════════════════════════════════════════════════════════════════════════ */
4574
+ @media (prefers-reduced-motion: reduce) {
4575
+ .nim-root *,
4576
+ .nim-root *::before,
4577
+ .nim-root *::after {
4578
+ animation-duration: 1ms !important;
4579
+ animation-iteration-count: 1 !important;
4580
+ transition-duration: 1ms !important;
4581
+ scroll-behavior: auto !important;
4582
+ }
4583
+
4584
+ /* Still turning, slower: the spinner is the whole message. */
4585
+ .nim-root .nim-spinner,
4586
+ .nim-root .nim-button__spinner {
4587
+ animation: nim-spin 1.4s linear infinite !important;
4588
+ }
4589
+
4590
+ /* "Working, duration unknown" — said by filling rather than by sliding. */
4591
+ .nim-root .nim-progress--indeterminate .nim-progress__fill {
4592
+ inline-size: 100% !important;
4593
+ opacity: 0.4;
4594
+ }
4595
+
4596
+ /* "The microphone is live" — the pulse is the only thing saying so, and it
4597
+ slows rather than stops. */
4598
+ .nim-root .nim-composer__pulse {
4599
+ animation: nim-pulse 2.4s var(--nim-ease-standard) infinite !important;
4600
+ }
4601
+
4602
+ /* Pure decoration: the grey blocks already say what they need to. */
4603
+ .nim-root .nim-skeleton::after {
4604
+ display: none;
4605
+ }
4606
+ }