@webority/theme 0.54.0 → 0.55.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@webority/theme",
3
- "version": "0.54.0",
3
+ "version": "0.55.0",
4
4
  "description": "Webority shared design system — Bootstrap 5.3 SCSS overrides, --wui-* tokens, and shared component CSS. The single source of brand chrome for React portals and Razor sites.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "publishConfig": {
@@ -22,6 +22,7 @@
22
22
  "style": "./dist/webority-theme.css",
23
23
  "default": "./index.scss"
24
24
  },
25
+ "./scss/wui/tour/*": "./scss/wui/tour/_*.scss",
25
26
  "./scss/wui/*": "./scss/wui/_*.scss",
26
27
  "./scss/*": "./scss/_*.scss",
27
28
  "./css": "./dist/webority-theme.css",
@@ -1,97 +1,18 @@
1
1
  // ── Product tour ──
2
- // AppTour / <app-tour> / <wui-tour>: a dimmed page with one highlighted element and a card
3
- // holding the step text and Back / Next / Skip. The element appends .wui-tour-layer to <body>
4
- // and positions .wui-tour-spot (over the target) and .wui-tour-card (against the target, through
5
- // anchorOverlay, which sets position, top and left inline). Everything visual is here, every
6
- // colour a theme token.
2
+ // AppTour / <app-tour> / <wui-tour>. The one entry for every tour rule: the partials under
3
+ // wui/tour/ hold one concern each, matching the element's modules (tourMotion.js, tourProgress.js,
4
+ // tourPlacement.js, tourMedia.js, tourAdvance.js, tourEnd.js). Nothing else imports them, so the
5
+ // tour's styles move as a whole by moving this one import.
6
+ //
7
+ // Isolated tours carry a sealed copy of every .wui-tour-* rule (packages/elements/src/tourIsolated.js),
8
+ // and a test pins that copy to the compiled theme.
7
9
  //
8
10
  // Part of the wui-components layer, see _wui-components.scss for load order.
9
11
 
10
- // The step data of a server-rendered tour is plain markup the element reads and the page never shows.
11
- wui-tour,
12
- wui-tour-step {
13
- display: none;
14
- }
15
-
16
- .wui-tour-layer {
17
- position: fixed;
18
- inset: 0;
19
- z-index: var(--wui-z-tour);
20
- }
21
-
22
- // The dim is the spot's own shadow, so the hole around the target needs no clip-path.
23
- .wui-tour-spot {
24
- position: fixed;
25
- border-radius: var(--wui-radius-sm);
26
- box-shadow:
27
- 0 0 0 2px var(--color-primary),
28
- 0 0 0 100vmax var(--color-scrim-strong);
29
- pointer-events: none;
30
- }
31
- @media (prefers-reduced-motion: no-preference) {
32
- .wui-tour-spot {
33
- transition:
34
- top 160ms ease,
35
- left 160ms ease,
36
- width 160ms ease,
37
- height 160ms ease;
38
- }
39
- }
40
-
41
- .wui-tour-card {
42
- display: flex;
43
- flex-direction: column;
44
- gap: 8px;
45
- width: min(360px, calc(100vw - 16px));
46
- padding: 16px;
47
- overflow-y: auto;
48
- background: var(--color-surface);
49
- color: var(--color-text);
50
- border: 1px solid var(--color-border);
51
- border-radius: var(--wui-radius-lg);
52
- corner-shape: squircle;
53
- box-shadow: var(--wui-shadow-overlay);
54
- &:focus {
55
- outline: none;
56
- }
57
- &:focus-visible {
58
- outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
59
- outline-offset: var(--wui-focus-ring-offset);
60
- }
61
- }
62
-
63
- .wui-tour-position {
64
- margin: 0;
65
- font-size: 12px;
66
- color: var(--color-text-muted);
67
- }
68
- .wui-tour-title {
69
- margin: 0;
70
- font-size: 16px;
71
- font-weight: 600;
72
- }
73
- .wui-tour-text {
74
- margin: 0;
75
- font-size: 14px;
76
- color: var(--color-text-muted);
77
- }
78
- .wui-tour-actions {
79
- display: flex;
80
- align-items: center;
81
- justify-content: space-between;
82
- gap: 8px;
83
- margin-top: 4px;
84
- }
85
- .wui-tour-nav {
86
- display: flex;
87
- gap: 8px;
88
- }
89
- // The buttons keep Bootstrap's look; the width stops the label change between Next and Done from
90
- // moving the row, and Skip reads as the quiet action.
91
- .wui-tour-skip {
92
- color: var(--color-text-muted);
93
- }
94
- .wui-tour-back,
95
- .wui-tour-next {
96
- min-width: 64px;
97
- }
12
+ @import "tour/base";
13
+ @import "tour/motion";
14
+ @import "tour/progress";
15
+ @import "tour/placement";
16
+ @import "tour/media";
17
+ @import "tour/advance";
18
+ @import "tour/end";
@@ -0,0 +1,67 @@
1
+ // ── Product tour: click-to-advance steps ──
2
+ // A step with `advance-on="click"` lets clicks through the spotlight to its target, and the
3
+ // tour moves on when the target is used (tourAdvance.js). The cue is one pulse of the ring as the
4
+ // step arrives and the .wui-tour-hint sentence; Next turns into a link there (tourAdvance.js
5
+ // swaps its class).
6
+ //
7
+ // `data-advance` on the layer makes the hole clickable. The layer then lets every click through,
8
+ // and the spot's ::before catches them again everywhere but over the spot: it reaches 100vmax
9
+ // past each edge, as the dim does, and its clip-path cuts the spot's own box out. Riding on the
10
+ // spot, the hole follows the target through the glide and a scroll with nothing to update. A
11
+ // leaving layer keeps the motion rule's click-through for the whole page.
12
+
13
+ .wui-tour-layer[data-advance] {
14
+ pointer-events: none;
15
+ }
16
+ .wui-tour-layer[data-advance]:not([data-state="leaving"]) .wui-tour-card {
17
+ pointer-events: auto;
18
+ }
19
+ .wui-tour-layer[data-advance]:not([data-state="leaving"]) .wui-tour-spot::before {
20
+ content: "";
21
+ position: absolute;
22
+ inset: -100vmax;
23
+ pointer-events: auto;
24
+ clip-path: polygon(
25
+ evenodd,
26
+ 0 0,
27
+ 100% 0,
28
+ 100% 100%,
29
+ 0 100%,
30
+ 0 0,
31
+ 100vmax 100vmax,
32
+ calc(100% - 100vmax) 100vmax,
33
+ calc(100% - 100vmax) calc(100% - 100vmax),
34
+ 100vmax calc(100% - 100vmax),
35
+ 100vmax 100vmax
36
+ );
37
+ }
38
+
39
+ .wui-tour-hint {
40
+ margin: 0;
41
+ font-size: 14px;
42
+ font-weight: 600;
43
+ color: var(--color-text);
44
+ }
45
+
46
+ @keyframes wui-tour-pulse {
47
+ from {
48
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--color-primary) 85%, transparent);
49
+ }
50
+ to {
51
+ box-shadow: 0 0 0 14px color-mix(in srgb, var(--color-primary) 0%, transparent);
52
+ }
53
+ }
54
+
55
+ // The pulse waits out the spot's glide, so the ring grows from where the target is. It runs once
56
+ // per step: tourAdvance.js sets `data-advance` again on each arrival to restart it.
57
+ @media (prefers-reduced-motion: no-preference) {
58
+ .wui-tour-spot[data-advance]::after {
59
+ content: "";
60
+ position: absolute;
61
+ inset: 0;
62
+ border-radius: inherit;
63
+ corner-shape: inherit;
64
+ pointer-events: none;
65
+ animation: wui-tour-pulse 600ms var(--wui-ease-out-quart) var(--wui-tour-spot-duration);
66
+ }
67
+ }
@@ -0,0 +1,82 @@
1
+ // ── Product tour: layer, spotlight and card ──
2
+ // AppTour / <app-tour> / <wui-tour>: a dimmed page with one highlighted element and a card
3
+ // holding the step text and Back / Next / Skip. The element appends .wui-tour-layer to <body>;
4
+ // tourPlacement.js fits .wui-tour-spot to the target's box and corners and places .wui-tour-card
5
+ // beside the target, over its lower part, or centred for a message, setting both inline. Every
6
+ // colour is a theme token.
7
+
8
+ // The step data of a server-rendered tour is plain markup the element reads and the page never shows.
9
+ wui-tour,
10
+ wui-tour-step {
11
+ display: none;
12
+ }
13
+
14
+ .wui-tour-layer {
15
+ position: fixed;
16
+ inset: 0;
17
+ z-index: var(--wui-z-tour);
18
+ }
19
+
20
+ // The dim is the spot's own shadow, so the hole around the target needs no clip-path. The spot
21
+ // has no radius of its own: tourPlacement.js copies the target's, so the 2px line runs just
22
+ // outside the target's own edge.
23
+ .wui-tour-spot {
24
+ position: fixed;
25
+ box-shadow:
26
+ 0 0 0 2px var(--color-primary),
27
+ 0 0 0 100vmax var(--color-scrim-strong);
28
+ pointer-events: none;
29
+ }
30
+
31
+ .wui-tour-card {
32
+ display: flex;
33
+ flex-direction: column;
34
+ gap: 8px;
35
+ width: min(360px, calc(100vw - 16px));
36
+ padding: 16px;
37
+ overflow-y: auto;
38
+ background: var(--color-surface);
39
+ color: var(--color-text);
40
+ border: 1px solid var(--color-border);
41
+ border-radius: var(--wui-radius-lg);
42
+ corner-shape: squircle;
43
+ box-shadow: var(--wui-shadow-overlay);
44
+ &:focus {
45
+ outline: none;
46
+ }
47
+ &:focus-visible {
48
+ outline: var(--wui-focus-ring-width) solid var(--color-focus-ring);
49
+ outline-offset: var(--wui-focus-ring-offset);
50
+ }
51
+ }
52
+
53
+ .wui-tour-title {
54
+ margin: 0;
55
+ font-size: 16px;
56
+ font-weight: 600;
57
+ }
58
+ .wui-tour-text {
59
+ margin: 0;
60
+ font-size: 14px;
61
+ color: var(--color-text-muted);
62
+ }
63
+ .wui-tour-actions {
64
+ display: flex;
65
+ align-items: center;
66
+ justify-content: space-between;
67
+ gap: 8px;
68
+ margin-top: 4px;
69
+ }
70
+ .wui-tour-nav {
71
+ display: flex;
72
+ gap: 8px;
73
+ }
74
+ // The buttons keep Bootstrap's look; the width stops the label change between Next and Done from
75
+ // moving the row, and Skip reads as the quiet action.
76
+ .wui-tour-skip {
77
+ color: var(--color-text-muted);
78
+ }
79
+ .wui-tour-back,
80
+ .wui-tour-next {
81
+ min-width: 64px;
82
+ }
@@ -0,0 +1,82 @@
1
+ // ── Product tour: closing dialog ──
2
+ // The "You're all set" dialog after the last step (.wui-tour-end), shown by tourEnd.js. It is a
3
+ // .wui-tour-card too, so it takes the card's look and its entrance from _motion.scss (a fade under
4
+ // reduced motion), and it is centred here rather than placed by tourPlacement.js. On a phone its
5
+ // button is a 44px touch target through the card rule in _placement.scss.
6
+
7
+ @keyframes wui-tour-check {
8
+ from {
9
+ stroke-dashoffset: 24;
10
+ }
11
+ to {
12
+ stroke-dashoffset: 0;
13
+ }
14
+ }
15
+
16
+ // As wide as a welcome card, so the default message fits on one line. The standalone `scale` and
17
+ // `translate` of the entrance compose with this `transform`, around the centre.
18
+ .wui-tour-end[data-layout="center"] {
19
+ --wui-tour-card-lift: 0 0;
20
+
21
+ position: fixed;
22
+ top: 50%;
23
+ left: 50%;
24
+ transform: translate(-50%, -50%);
25
+ transform-origin: center;
26
+ align-items: center;
27
+ gap: 8px;
28
+ width: min(420px, calc(100vw - 16px));
29
+ max-height: calc(100vh - 16px);
30
+ padding: 24px;
31
+ text-align: center;
32
+ .wui-tour-actions {
33
+ justify-content: center;
34
+ margin-top: 8px;
35
+ }
36
+ }
37
+
38
+ .wui-tour-end-mark {
39
+ display: inline-flex;
40
+ flex: none;
41
+ align-items: center;
42
+ justify-content: center;
43
+ width: 48px;
44
+ height: 48px;
45
+ border-radius: 50%;
46
+ background: var(--color-success-soft);
47
+ color: var(--color-success-text);
48
+ > svg {
49
+ width: 26px;
50
+ height: 26px;
51
+ }
52
+ path {
53
+ fill: none;
54
+ stroke: currentColor;
55
+ stroke-width: 2.5;
56
+ stroke-linecap: round;
57
+ stroke-linejoin: round;
58
+ stroke-dasharray: 24;
59
+ }
60
+ }
61
+
62
+ .wui-tour-end-title {
63
+ font-size: 18px;
64
+ }
65
+
66
+ // The default message fits on one line; a longer one, or the dialog on a phone, wraps into even
67
+ // lines under the centred title rather than leaving one word alone.
68
+ .wui-tour-end-message {
69
+ text-wrap: balance;
70
+ }
71
+
72
+ .wui-tour-end-button {
73
+ min-width: 120px;
74
+ }
75
+
76
+ // The check draws once the dialog has entered: its delay adds the card's own entrance delay
77
+ // (set inline by tourMotion.js and inherited). Under reduced motion it shows at once.
78
+ @media (prefers-reduced-motion: no-preference) {
79
+ .wui-tour-end-mark path {
80
+ animation: wui-tour-check 300ms var(--wui-ease-out-quart) calc(var(--wui-tour-card-delay, 0ms) + 120ms) both;
81
+ }
82
+ }
@@ -0,0 +1,54 @@
1
+ // ── Product tour: step media ──
2
+ // A step's optional image or short loop, full-bleed at the card top (.wui-tour-media), rendered
3
+ // by tourMedia.js. The frame is 16:9 before the file loads, so the card keeps its size. Its
4
+ // negative margin cancels the card's 16px padding (_base.scss); the card's own overflow and
5
+ // corner radius clip it, so the frame needs no radius.
6
+
7
+ .wui-tour-media {
8
+ position: relative;
9
+ order: -1;
10
+ flex: none;
11
+ aspect-ratio: 16 / 9;
12
+ margin: -16px -16px 4px;
13
+ overflow: hidden;
14
+ background: var(--color-border);
15
+ > img,
16
+ > video {
17
+ display: block;
18
+ width: 100%;
19
+ height: 100%;
20
+ object-fit: cover;
21
+ }
22
+ }
23
+
24
+ // A card with no target is a welcome card, wider than a step card.
25
+ .wui-tour-card[data-media="welcome"] {
26
+ width: min(420px, calc(100vw - 16px));
27
+ }
28
+
29
+ // The pause control sits on the picture, so it carries its own scrim and its ink.
30
+ .wui-tour-media-toggle {
31
+ position: absolute;
32
+ inset-block-end: 8px;
33
+ inset-inline-end: 8px;
34
+ display: inline-flex;
35
+ align-items: center;
36
+ justify-content: center;
37
+ width: 44px;
38
+ height: 44px;
39
+ padding: 0;
40
+ border: 0;
41
+ border-radius: 50%;
42
+ background: var(--color-scrim-strong);
43
+ color: var(--color-on-scrim);
44
+ cursor: pointer;
45
+ > svg {
46
+ width: 20px;
47
+ height: 20px;
48
+ fill: currentColor;
49
+ }
50
+ &:focus-visible {
51
+ outline: 2px solid var(--color-on-scrim);
52
+ outline-offset: 2px;
53
+ }
54
+ }
@@ -0,0 +1,133 @@
1
+ // ── Product tour: motion ──
2
+ // The dim fading in and out, the spotlight's glide between targets, and the card's entrance and
3
+ // exit (its `data-state`: entering | shown | leaving, and the layer's `data-state="leaving"`, both
4
+ // set by tourMotion.js). tourMotion.js waits on the animations these rules start, so every
5
+ // duration lives here.
6
+ //
7
+ // The tour's timings are tour-scoped custom properties on the theme's easing tokens, so tuning
8
+ // them never touches the other overlays' motion. As in wui/_menu-motion.scss, the entrance
9
+ // animates the standalone `scale` and `translate` properties, never `transform`, which placement
10
+ // sets inline to centre a message card.
11
+ //
12
+ // Leaving is an opacity transition, not a keyframe animation: a card or layer that leaves halfway
13
+ // through its entrance fades from the opacity it has reached instead of flashing back to full.
14
+
15
+ :root {
16
+ --wui-tour-motion-duration: 200ms;
17
+ --wui-tour-motion-ease: var(--wui-ease-out-quart);
18
+ --wui-tour-spot-duration: 240ms;
19
+ --wui-tour-spot-ease: var(--wui-ease-ui);
20
+ }
21
+
22
+ @keyframes wui-tour-fade-in {
23
+ from {
24
+ opacity: 0;
25
+ }
26
+ to {
27
+ opacity: 1;
28
+ }
29
+ }
30
+
31
+ @keyframes wui-tour-card-enter {
32
+ from {
33
+ opacity: 0;
34
+ scale: 0.96;
35
+ translate: var(--wui-tour-card-lift, 0 6px);
36
+ }
37
+ to {
38
+ opacity: 1;
39
+ scale: 1;
40
+ translate: 0 0;
41
+ }
42
+ }
43
+
44
+ .wui-tour-layer[data-state="leaving"],
45
+ .wui-tour-card[data-state="leaving"] {
46
+ opacity: 0;
47
+ }
48
+
49
+ // A closing layer stays on the page until its fade ends; the page under it is usable at once.
50
+ .wui-tour-layer[data-state="leaving"],
51
+ .wui-tour-layer[data-state="leaving"] * {
52
+ pointer-events: none;
53
+ }
54
+
55
+ @media (prefers-reduced-motion: no-preference) {
56
+ .wui-tour-layer {
57
+ animation: wui-tour-fade-in var(--wui-tour-motion-duration) var(--wui-tour-motion-ease);
58
+ }
59
+ .wui-tour-layer[data-state="leaving"] {
60
+ transition: opacity var(--wui-tour-motion-duration) var(--wui-tour-motion-ease);
61
+ }
62
+
63
+ .wui-tour-spot {
64
+ transition:
65
+ top var(--wui-tour-spot-duration) var(--wui-tour-spot-ease),
66
+ left var(--wui-tour-spot-duration) var(--wui-tour-spot-ease),
67
+ width var(--wui-tour-spot-duration) var(--wui-tour-spot-ease),
68
+ height var(--wui-tour-spot-duration) var(--wui-tour-spot-ease),
69
+ border-radius var(--wui-tour-spot-duration) var(--wui-tour-spot-ease);
70
+ }
71
+ // Set by WuiTour.js while the spot follows its target through a scroll or resize, so it never trails it.
72
+ .wui-tour-spot[data-tracking] {
73
+ transition: none;
74
+ }
75
+
76
+ // The card starts 6px further from its target and scales from the edge facing it, so it
77
+ // lifts toward the target. A card below its target is the default. A card over its target or
78
+ // centred for a message has no edge facing it, so it scales in place.
79
+ .wui-tour-card {
80
+ --wui-tour-card-lift: 0 6px;
81
+
82
+ transform-origin: top center;
83
+ }
84
+ .wui-tour-card[data-placement="top"] {
85
+ --wui-tour-card-lift: 0 -6px;
86
+
87
+ transform-origin: bottom center;
88
+ }
89
+ .wui-tour-card[data-placement="bottom"] {
90
+ --wui-tour-card-lift: 0 6px;
91
+
92
+ transform-origin: top center;
93
+ }
94
+ .wui-tour-card[data-placement="left"] {
95
+ --wui-tour-card-lift: -6px 0;
96
+
97
+ transform-origin: right center;
98
+ }
99
+ .wui-tour-card[data-placement="right"] {
100
+ --wui-tour-card-lift: 6px 0;
101
+
102
+ transform-origin: left center;
103
+ }
104
+ .wui-tour-card[data-placement="overlap"],
105
+ .wui-tour-card[data-placement="center"] {
106
+ --wui-tour-card-lift: 0 0;
107
+
108
+ transform-origin: center;
109
+ }
110
+
111
+ // --wui-tour-card-delay is two-thirds of the spot's glide, set by tourMotion.js only while the
112
+ // spot is moving; `both` keeps the card hidden through that delay.
113
+ .wui-tour-card[data-state="entering"] {
114
+ animation: wui-tour-card-enter var(--wui-tour-motion-duration) var(--wui-tour-motion-ease) var(--wui-tour-card-delay, 0ms) both;
115
+ }
116
+ .wui-tour-card[data-state="leaving"] {
117
+ transition: opacity calc(var(--wui-tour-motion-duration) / 2) var(--wui-tour-motion-ease);
118
+ }
119
+ }
120
+
121
+ // Nothing moves or scales and the spot jumps: the card hides at once and fades in, and the dim
122
+ // fades, each within 120ms.
123
+ @media (prefers-reduced-motion: reduce) {
124
+ .wui-tour-layer {
125
+ animation: wui-tour-fade-in 120ms linear;
126
+ }
127
+ .wui-tour-layer[data-state="leaving"] {
128
+ transition: opacity 120ms linear;
129
+ }
130
+ .wui-tour-card[data-state="entering"] {
131
+ animation: wui-tour-fade-in 120ms linear both;
132
+ }
133
+ }
@@ -0,0 +1,65 @@
1
+ // ── Product tour: placement ──
2
+ // Where the card sits against its target: the card's `data-placement` (top | bottom | left |
3
+ // right | center | overlap) and the .wui-tour-arrow pointing at the target, set by tourPlacement.js.
4
+ // A center or overlap card has no target edge to point at: tourPlacement.js sets its arrow
5
+ // `hidden`, so it needs no rule here, and the card keeps its own scroll.
6
+
7
+ // The layer's padding is the device's safe area, which tourPlacement.js reads to keep the card
8
+ // clear of a notch or a home bar. The spot and the card are fixed, so the padding moves neither.
9
+ .wui-tour-layer {
10
+ padding: env(safe-area-inset-top, 0px) env(safe-area-inset-right, 0px) env(safe-area-inset-bottom, 0px)
11
+ env(safe-area-inset-left, 0px);
12
+ }
13
+
14
+ // The arrow sits half outside the card, where the card's own scroll would clip it. It shows only
15
+ // on a card at full height, which never scrolls.
16
+ .wui-tour-card:has(.wui-tour-arrow:not([hidden])) {
17
+ overflow: visible;
18
+ }
19
+
20
+ // An 8px square turned 45deg, in the card's colours. The two borders facing into the card are
21
+ // transparent, so the card's border runs on around the point. tourPlacement.js sets its offset
22
+ // along the edge; -5px (half the square plus the card's 1px border) centres it on the edge.
23
+ .wui-tour-arrow {
24
+ position: absolute;
25
+ width: 8px;
26
+ height: 8px;
27
+ background: var(--color-surface);
28
+ border: 1px solid var(--color-border);
29
+ rotate: 45deg;
30
+ pointer-events: none;
31
+ }
32
+ .wui-tour-card[data-placement="bottom"] .wui-tour-arrow {
33
+ top: -5px;
34
+ border-right-color: transparent;
35
+ border-bottom-color: transparent;
36
+ }
37
+ .wui-tour-card[data-placement="top"] .wui-tour-arrow {
38
+ bottom: -5px;
39
+ border-top-color: transparent;
40
+ border-left-color: transparent;
41
+ }
42
+ .wui-tour-card[data-placement="right"] .wui-tour-arrow {
43
+ left: -5px;
44
+ border-top-color: transparent;
45
+ border-right-color: transparent;
46
+ }
47
+ .wui-tour-card[data-placement="left"] .wui-tour-arrow {
48
+ right: -5px;
49
+ border-bottom-color: transparent;
50
+ border-left-color: transparent;
51
+ }
52
+
53
+ // On a phone the card spans the window, 8px from each edge, and stays above or below its target;
54
+ // tourPlacement.js checks the same breakpoint. Each card button is a 44px touch target.
55
+ @include media-breakpoint-down(sm) {
56
+ .wui-tour-card {
57
+ width: calc(100vw - 16px);
58
+ }
59
+ .wui-tour-actions .btn {
60
+ display: inline-flex;
61
+ align-items: center;
62
+ justify-content: center;
63
+ min-height: 44px;
64
+ }
65
+ }
@@ -0,0 +1,26 @@
1
+ // ── Product tour: progress ──
2
+ // The step count above the title: a thin segmented bar (.wui-tour-progress holds
3
+ // .wui-tour-progress-bar, which holds one .wui-tour-progress-segment per counted step) and the
4
+ // "Step N of M" text (.wui-tour-position), all filled by tourProgress.js. The bar is aria-hidden;
5
+ // the text carries the count. The segments up to the current step carry data-filled.
6
+
7
+ .wui-tour-progress-bar {
8
+ display: flex;
9
+ gap: 4px;
10
+ }
11
+
12
+ .wui-tour-progress-segment {
13
+ flex: 1 1 0;
14
+ height: 4px;
15
+ border-radius: 999px;
16
+ background: var(--color-border);
17
+ &[data-filled] {
18
+ background: var(--color-primary);
19
+ }
20
+ }
21
+
22
+ .wui-tour-position {
23
+ margin: 0;
24
+ font-size: 12px;
25
+ color: var(--color-text-muted);
26
+ }