@webority/theme 0.7.7 → 0.7.9

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.
@@ -5,9 +5,24 @@
5
5
  // partials are a split of one stylesheet, not independent modules, so a rule
6
6
  // here may be overridden by a later partial. Never reorder the imports.
7
7
 
8
- // Wizard stepper. Two variants of one component:
8
+ // Wizard stepper. Three variants of one component:
9
9
  // .stepper — compact: numbered circle above a label, line behind.
10
10
  // .stepper-journey — wide: 40px dot beside a label + title, for a page masthead.
11
+ // .stepper-icons — large connected icon badges with a "STEP n" eyebrow.
12
+ //
13
+ // Fully themable through a small set of `--wui-step-*` custom properties — set them on
14
+ // the stepper (or the wizard host, or any ancestor: they inherit), or flip the whole
15
+ // accent with a `.wui-step-tone-*` class. Every colour/size below reads a var with the
16
+ // historical value as the fallback, so an UNSET wizard looks exactly as before while a
17
+ // product can recolour or resize it without overriding a single selector:
18
+ // --wui-step-accent solid state colour (active fill, done fill/rail, active eyebrow)
19
+ // --wui-step-accent-fg text/icon on the accent fill
20
+ // --wui-step-soft soft tint (active ring; the journey/icons "done" badge bg)
21
+ // --wui-step-soft-fg text/icon on the soft tint (the "done" badge check)
22
+ // --wui-step-connector the incomplete-rail colour
23
+ // --wui-step-size compact/vertical badge diameter (default 28px)
24
+ // --wui-step-badge-size icons-variant badge diameter (default 56px)
25
+ // The icons variant defaults its accent to success (green); the others to primary.
11
26
  // ============================================================================
12
27
  .stepper {
13
28
  // Full width so the flex:1 steps spread evenly across the container. Without it,
@@ -34,23 +49,23 @@
34
49
  .step + .step::before {
35
50
  content: "";
36
51
  position: absolute;
37
- // 13px = half the 28px circle, minus 1 for the 2px line's own height.
38
- top: 13px;
39
- left: calc(-50% + 18px);
40
- right: calc(50% + 18px);
52
+ // Centred on the badge: half the diameter, minus 1 for the 2px line's own height.
53
+ top: calc(var(--wui-step-size, 28px) / 2 - 1px);
54
+ left: calc(-50% + var(--wui-step-size, 28px) / 2 + 4px);
55
+ right: calc(50% + var(--wui-step-size, 28px) / 2 + 4px);
41
56
  height: 2px;
42
- background: var(--color-border);
57
+ background: var(--wui-step-connector, var(--color-border));
43
58
  z-index: 0;
44
59
  }
45
60
  .step.done + .step::before {
46
- background: var(--color-primary);
61
+ background: var(--wui-step-accent, var(--color-primary));
47
62
  }
48
63
  .step-circle {
49
64
  position: relative;
50
65
  z-index: 1;
51
66
  flex: none;
52
- width: 28px;
53
- height: 28px;
67
+ width: var(--wui-step-size, 28px);
68
+ height: var(--wui-step-size, 28px);
54
69
  display: inline-grid;
55
70
  place-items: center;
56
71
  border: 1.5px solid var(--color-border);
@@ -61,15 +76,15 @@
61
76
  color: var(--color-text-subtle);
62
77
  }
63
78
  .step.active .step-circle {
64
- border-color: var(--color-primary);
65
- background: var(--color-primary);
66
- color: var(--color-on-scrim);
67
- box-shadow: 0 0 0 4px var(--color-primary-soft);
79
+ border-color: var(--wui-step-accent, var(--color-primary));
80
+ background: var(--wui-step-accent, var(--color-primary));
81
+ color: var(--wui-step-accent-fg, var(--color-on-scrim));
82
+ box-shadow: 0 0 0 4px var(--wui-step-soft, var(--color-primary-soft));
68
83
  }
69
84
  .step.done .step-circle {
70
- border-color: var(--color-primary);
71
- background: var(--color-primary);
72
- color: var(--color-on-scrim);
85
+ border-color: var(--wui-step-accent, var(--color-primary));
86
+ background: var(--wui-step-accent, var(--color-primary));
87
+ color: var(--wui-step-accent-fg, var(--color-on-scrim));
73
88
  }
74
89
  .step-label {
75
90
  max-width: 130px;
@@ -101,12 +116,12 @@ button.step {
101
116
  }
102
117
  a.step:hover .step-circle,
103
118
  button.step:hover .step-circle {
104
- box-shadow: 0 0 0 4px var(--color-primary-soft);
119
+ box-shadow: 0 0 0 4px var(--wui-step-soft, var(--color-primary-soft));
105
120
  transform: scale(1.04);
106
121
  }
107
122
  a.step:hover .step-label,
108
123
  button.step:hover .step-label {
109
- color: var(--color-primary);
124
+ color: var(--wui-step-accent, var(--color-primary));
110
125
  }
111
126
  a.step:focus-visible,
112
127
  button.step:focus-visible {
@@ -116,8 +131,8 @@ button.step:focus-visible {
116
131
  a.step:focus-visible .step-circle,
117
132
  button.step:focus-visible .step-circle {
118
133
  box-shadow:
119
- 0 0 0 4px var(--color-primary-soft),
120
- 0 0 0 6px var(--color-primary);
134
+ 0 0 0 4px var(--wui-step-soft, var(--color-primary-soft)),
135
+ 0 0 0 6px var(--wui-step-accent, var(--color-primary));
121
136
  }
122
137
  // A step that failed its stage — a red circle with an alert, so an invalid step
123
138
  // reads as wrong at a glance rather than merely "not done".
@@ -173,12 +188,12 @@ button.step:focus-visible .step-circle {
173
188
  transform 0.2s ease;
174
189
  }
175
190
  .stepper-journey .step.done .step-circle {
176
- background: var(--color-success-soft);
177
- color: var(--color-success-text);
191
+ background: var(--wui-step-soft, var(--color-success-soft));
192
+ color: var(--wui-step-soft-fg, var(--color-success-text));
178
193
  }
179
194
  .stepper-journey .step.active .step-circle {
180
- background: var(--color-primary);
181
- color: var(--color-on-scrim);
195
+ background: var(--wui-step-accent, var(--color-primary));
196
+ color: var(--wui-step-accent-fg, var(--color-on-scrim));
182
197
  box-shadow: none;
183
198
  transform: scale(1.06);
184
199
  }
@@ -199,10 +214,10 @@ button.step:focus-visible .step-circle {
199
214
  color: var(--color-text-subtle);
200
215
  }
201
216
  .stepper-journey .step.done .step-index {
202
- color: var(--color-success-text);
217
+ color: var(--wui-step-soft-fg, var(--color-success-text));
203
218
  }
204
219
  .stepper-journey .step.active .step-index {
205
- color: var(--color-primary);
220
+ color: var(--wui-step-accent, var(--color-primary));
206
221
  }
207
222
  .stepper-journey .step.error .step-circle {
208
223
  background: var(--color-danger-soft);
@@ -240,7 +255,7 @@ button.step:focus-visible .step-circle {
240
255
  background: var(--color-border-strong);
241
256
  }
242
257
  .stepper-journey .step-line.done {
243
- background: var(--color-success);
258
+ background: var(--wui-step-accent, var(--color-success));
244
259
  }
245
260
  // Below xl the four label+title pairs no longer fit side by side, so the bar
246
261
  // becomes a vertical list and the connectors go away.
@@ -270,7 +285,7 @@ button.step:focus-visible .step-circle {
270
285
  // left, the label and its description stacked on the right.
271
286
  .stepper-vertical .step {
272
287
  display: grid;
273
- grid-template-columns: 28px 1fr;
288
+ grid-template-columns: var(--wui-step-size, 28px) 1fr;
274
289
  column-gap: 12px;
275
290
  // No gap between the label and its description — they read as one block; the
276
291
  // base .step gap of 10px is for the horizontal circle→label spacing.
@@ -307,18 +322,18 @@ button.step:focus-visible .step-circle {
307
322
  .stepper-vertical .step:not(:last-child)::after {
308
323
  content: "";
309
324
  position: absolute;
310
- // 13px = half the 28px circle minus 1 for the 2px line's own width.
311
- left: 13px;
312
- top: 28px;
325
+ // Half the badge minus 1 for the 2px line's own width; runs from below the circle.
326
+ left: calc(var(--wui-step-size, 28px) / 2 - 1px);
327
+ top: var(--wui-step-size, 28px);
313
328
  // Reaches through the 18px inter-step gap to meet the next circle's top; keep
314
329
  // this in sync with the .stepper-vertical `gap`.
315
330
  bottom: -18px;
316
331
  width: 2px;
317
- background: var(--color-border);
332
+ background: var(--wui-step-connector, var(--color-border));
318
333
  z-index: 0;
319
334
  }
320
335
  .stepper-vertical .step.done:not(:last-child)::after {
321
- background: var(--color-primary);
336
+ background: var(--wui-step-accent, var(--color-primary));
322
337
  }
323
338
  // The journey bar stacked vertically reuses its own narrow-width treatment: a plain
324
339
  // column with the horizontal connectors dropped (a real vertical rail here would
@@ -332,15 +347,169 @@ button.step:focus-visible .step-circle {
332
347
  display: none;
333
348
  }
334
349
 
350
+ // .stepper-icons — large icon badges joined by a rail, with a "STEP n" eyebrow above
351
+ // each title. Done tints green with a filled connector; active is a solid primary
352
+ // badge; pending is a muted badge. Built for icon-per-step flows — each step sets `icon`
353
+ // (a step with no icon falls back to its number).
354
+ // ----------------------------------------------------------------------------
355
+ .stepper-icons {
356
+ align-items: flex-start;
357
+ padding: 8px 8px 0;
358
+ }
359
+ .stepper-icons .step {
360
+ gap: 6px;
361
+ }
362
+ .stepper-icons .step-circle {
363
+ width: var(--wui-step-badge-size, 56px);
364
+ height: var(--wui-step-badge-size, 56px);
365
+ border: none;
366
+ background: var(--color-bg-muted);
367
+ color: var(--color-text-subtle);
368
+ font-size: 22px;
369
+ transition:
370
+ background 0.2s ease,
371
+ color 0.2s ease,
372
+ transform 0.2s ease;
373
+ }
374
+ // The icons variant defaults its accent to success (green), so an untoned icons wizard
375
+ // reads green — solid-green active badge, soft-green done badge, green rail. Every colour
376
+ // still routes through the shared --wui-step-* vars, so a tone class or an override recolours it.
377
+ .stepper-icons .step.active .step-circle {
378
+ background: var(--wui-step-accent, var(--color-success));
379
+ color: var(--wui-step-accent-fg, var(--color-on-scrim));
380
+ // The compact variant rings the active circle; here the solid fill carries it, so
381
+ // drop the ring to match the flat badge look.
382
+ box-shadow: none;
383
+ }
384
+ .stepper-icons .step.done .step-circle {
385
+ border: none;
386
+ background: var(--wui-step-soft, var(--color-success-soft));
387
+ color: var(--wui-step-soft-fg, var(--color-success-text));
388
+ }
389
+ .stepper-icons .step.error .step-circle {
390
+ background: var(--color-danger-soft);
391
+ color: var(--color-danger-text);
392
+ }
393
+ .stepper-icons .step.skipped .step-circle {
394
+ background: var(--color-bg-muted);
395
+ border: 1px dashed var(--color-border-strong);
396
+ color: var(--color-text-muted);
397
+ }
398
+ // The "STEP n" eyebrow sits between the badge and the title, colour-matched to the state.
399
+ .stepper-icons .step-index {
400
+ margin-top: 4px;
401
+ font-size: 12px;
402
+ font-weight: 600;
403
+ line-height: 1.2;
404
+ text-transform: uppercase;
405
+ letter-spacing: 0.06em;
406
+ color: var(--color-text-subtle);
407
+ }
408
+ .stepper-icons .step.active .step-index {
409
+ color: var(--wui-step-accent, var(--color-success));
410
+ }
411
+ .stepper-icons .step.done .step-index {
412
+ color: var(--wui-step-soft-fg, var(--color-success-text));
413
+ }
414
+ .stepper-icons .step.error .step-index {
415
+ color: var(--color-danger-text);
416
+ }
417
+ .stepper-icons .step-label {
418
+ max-width: 150px;
419
+ font-size: 15px;
420
+ font-weight: 600;
421
+ color: var(--color-text-subtle);
422
+ }
423
+ .stepper-icons .step.active .step-label,
424
+ .stepper-icons .step.done .step-label {
425
+ color: var(--color-text);
426
+ }
427
+ // The rail: thicker and rounded, recentred on the badge (half the diameter − 2 for the
428
+ // 4px line's own height), and filled with the accent once the step to its left is done.
429
+ .stepper-icons .step + .step::before {
430
+ top: calc(var(--wui-step-badge-size, 56px) / 2 - 2px);
431
+ left: calc(-50% + var(--wui-step-badge-size, 56px) / 2 + 8px);
432
+ right: calc(50% + var(--wui-step-badge-size, 56px) / 2 + 8px);
433
+ height: 4px;
434
+ border-radius: 999px;
435
+ background: var(--wui-step-connector, var(--color-border));
436
+ }
437
+ .stepper-icons .step.done + .step::before {
438
+ background: var(--wui-step-accent, var(--color-success));
439
+ }
440
+ // The compact hover ring is calibrated to the 28px badge; the 56px icon badge just
441
+ // lifts on hover instead.
442
+ .stepper-icons a.step:hover .step-circle,
443
+ .stepper-icons button.step:hover .step-circle {
444
+ box-shadow: none;
445
+ transform: scale(1.04);
446
+ }
447
+ // Below md the six badges no longer fit across, so the icons stepper stacks into a
448
+ // vertical list — the shared .stepper-vertical rules take over from here.
449
+ @include media-breakpoint-down(md) {
450
+ .stepper-icons.stepper-icons {
451
+ flex-direction: column;
452
+ align-items: stretch;
453
+ gap: 20px;
454
+ }
455
+ .stepper-icons.stepper-icons .step {
456
+ flex-direction: row;
457
+ align-items: center;
458
+ gap: 14px;
459
+ text-align: left;
460
+ }
461
+ .stepper-icons.stepper-icons .step + .step::before {
462
+ content: none;
463
+ }
464
+ }
465
+
335
466
  @media (prefers-reduced-motion: reduce) {
336
467
  a.step:hover .step-circle,
337
468
  button.step:hover .step-circle,
338
- .stepper-journey .step-circle {
469
+ .stepper-journey .step-circle,
470
+ .stepper-icons .step-circle {
339
471
  transition: none;
340
472
  transform: none;
341
473
  }
342
474
  }
343
475
 
476
+ // Tone presets — flip the whole accent (active fill, done rail, ring, journey/icons
477
+ // done tint) to a semantic ramp in one class. Because custom properties inherit, the
478
+ // class can sit on the stepper itself OR on an ancestor (the wizard host), and an inline
479
+ // `style="--wui-step-accent: …"` on a closer element still wins over it. Placing the
480
+ // class recolours every variant consistently; error steps stay red regardless (semantic).
481
+ // ----------------------------------------------------------------------------
482
+ .wui-step-tone-primary {
483
+ --wui-step-accent: var(--color-primary);
484
+ --wui-step-accent-fg: var(--color-on-scrim);
485
+ --wui-step-soft: var(--color-primary-soft);
486
+ --wui-step-soft-fg: var(--color-primary);
487
+ }
488
+ .wui-step-tone-success {
489
+ --wui-step-accent: var(--color-success);
490
+ --wui-step-accent-fg: var(--color-on-scrim);
491
+ --wui-step-soft: var(--color-success-soft);
492
+ --wui-step-soft-fg: var(--color-success-text);
493
+ }
494
+ .wui-step-tone-warning {
495
+ --wui-step-accent: var(--color-warning);
496
+ --wui-step-accent-fg: var(--color-on-scrim);
497
+ --wui-step-soft: var(--color-warning-soft);
498
+ --wui-step-soft-fg: var(--color-warning-text);
499
+ }
500
+ .wui-step-tone-danger {
501
+ --wui-step-accent: var(--color-danger);
502
+ --wui-step-accent-fg: var(--color-on-scrim);
503
+ --wui-step-soft: var(--color-danger-soft);
504
+ --wui-step-soft-fg: var(--color-danger-text);
505
+ }
506
+ .wui-step-tone-info {
507
+ --wui-step-accent: var(--color-info);
508
+ --wui-step-accent-fg: var(--color-on-scrim);
509
+ --wui-step-soft: var(--color-info-soft);
510
+ --wui-step-soft-fg: var(--color-info-text);
511
+ }
512
+
344
513
  // ============================================================================
345
514
  // Pricing card. A tier's name, price, pitch, feature list and CTA.
346
515
  //
@@ -616,4 +785,51 @@ button.step:focus-visible .step-circle {
616
785
  .form-actions-sticky {
617
786
  transition: none;
618
787
  }
788
+ }
789
+
790
+ // ============================================================================
791
+ // AppWizard (<wui-wizard>) — stepper header + one visible step panel + a sticky
792
+ // Back/Skip/Next/Finish footer. Composes .stepper and .form-actions above.
793
+ // ============================================================================
794
+ wui-wizard {
795
+ display: block;
796
+ }
797
+ // Custom elements don't inherit the UA `[hidden] { display: none }` once we give the
798
+ // tag its own `display`, so the inactive panels need it stated explicitly.
799
+ wui-wizard-step {
800
+ display: block;
801
+ }
802
+ wui-wizard-step[hidden] {
803
+ display: none;
804
+ }
805
+ .wizard-stepper {
806
+ margin-bottom: 24px;
807
+ }
808
+ // A skipped step reads as "passed over", not "achieved": a dashed, muted circle so it
809
+ // is visibly distinct from a ticked (done) step.
810
+ .step.skipped .step-circle {
811
+ background: var(--color-bg-muted);
812
+ border: 1px dashed var(--color-border-strong);
813
+ color: var(--color-text-muted);
814
+ }
815
+ .wizard-panel {
816
+ // A resting min-height so the footer doesn't jump as steps of different length
817
+ // swap in; content taller than this simply grows the panel.
818
+ min-height: 96px;
819
+ }
820
+ .wizard-footer {
821
+ // The sticky Back/Skip/Next/Finish bar — pinned to the bottom of a scrolling flow
822
+ // so the actions (and the Skip on an optional step) are always in reach.
823
+ position: sticky;
824
+ bottom: 0;
825
+ margin-top: 24px;
826
+ padding: 16px 0;
827
+ border-top: 1px solid var(--color-border);
828
+ background: var(--color-surface);
829
+ z-index: 1;
830
+ }
831
+ .wizard-footer-actions {
832
+ display: flex;
833
+ align-items: center;
834
+ gap: 12px;
619
835
  }
@@ -127,7 +127,7 @@
127
127
  padding: 0 4px;
128
128
  border-radius: 999px;
129
129
  background: var(--color-danger);
130
- color: #fff;
130
+ color: var(--wui-bg-light);
131
131
  font-size: 10px;
132
132
  font-weight: 700;
133
133
  line-height: 1;