@lepid-labs/styles 1.0.0 → 1.0.2

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 (50) hide show
  1. package/css.d.ts +8 -0
  2. package/luminous-precision/base.css +6 -2
  3. package/luminous-precision/components/badge.css +25 -0
  4. package/luminous-precision/components/button-group.css +130 -0
  5. package/luminous-precision/components/button-hold.css +112 -0
  6. package/luminous-precision/components/icon-button.css +71 -0
  7. package/luminous-precision/components/layout.css +348 -0
  8. package/luminous-precision/components/page.css +85 -0
  9. package/luminous-precision/components/pre.css +75 -0
  10. package/luminous-precision/components/shell.css +165 -0
  11. package/luminous-precision/components/status-card.css +159 -0
  12. package/luminous-precision/components/stepper.css +108 -0
  13. package/luminous-precision/components/table.css +20 -0
  14. package/luminous-precision/components/tabs.css +42 -0
  15. package/luminous-precision/design.md +64 -4
  16. package/luminous-precision/index.css +8 -0
  17. package/luminous-precision/tokens.css +6 -0
  18. package/neon-butterfly/base.css +6 -2
  19. package/neon-butterfly/components/badge.css +25 -0
  20. package/neon-butterfly/components/button-group.css +128 -0
  21. package/neon-butterfly/components/button-hold.css +112 -0
  22. package/neon-butterfly/components/icon-button.css +66 -0
  23. package/neon-butterfly/components/layout.css +348 -0
  24. package/neon-butterfly/components/page.css +85 -0
  25. package/neon-butterfly/components/pre.css +75 -0
  26. package/neon-butterfly/components/shell.css +196 -0
  27. package/neon-butterfly/components/status-card.css +156 -0
  28. package/neon-butterfly/components/stepper.css +107 -0
  29. package/neon-butterfly/components/table.css +20 -0
  30. package/neon-butterfly/components/tabs.css +42 -0
  31. package/neon-butterfly/design.md +60 -4
  32. package/neon-butterfly/index.css +8 -0
  33. package/neon-butterfly/tokens.css +6 -0
  34. package/package.json +58 -15
  35. package/summer-cloud/base.css +6 -2
  36. package/summer-cloud/components/badge.css +26 -0
  37. package/summer-cloud/components/button-group.css +131 -0
  38. package/summer-cloud/components/button-hold.css +132 -0
  39. package/summer-cloud/components/icon-button.css +76 -0
  40. package/summer-cloud/components/layout.css +348 -0
  41. package/summer-cloud/components/page.css +85 -0
  42. package/summer-cloud/components/pre.css +74 -0
  43. package/summer-cloud/components/shell.css +197 -0
  44. package/summer-cloud/components/status-card.css +158 -0
  45. package/summer-cloud/components/stepper.css +101 -0
  46. package/summer-cloud/components/table.css +20 -0
  47. package/summer-cloud/components/tabs.css +42 -0
  48. package/summer-cloud/design.md +64 -2
  49. package/summer-cloud/index.css +8 -0
  50. package/summer-cloud/tokens.css +6 -0
@@ -0,0 +1,197 @@
1
+ /* summer-cloud — shell chrome: unfilled bars with lit hairlines on the sky,
2
+ * Plus Jakarta labels, the current page a solid violet pill with the raised
3
+ * violet shadow; hover fills with sky tint. Structure is in layout.css. */
4
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__skip {
5
+ padding: var(--ld-space-2) var(--ld-space-3);
6
+ background: var(--ld-primary);
7
+ border-radius: var(--ld-radius-pill);
8
+ color: var(--ld-on-primary);
9
+ font-family: var(--ld-font-display);
10
+ font-weight: var(--ld-font-weight-medium);
11
+ font-size: var(--ld-text-sm);
12
+ }
13
+
14
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__header {
15
+ /* no fill: the shell background runs under the bar; the blur keeps
16
+ * content scrolling beneath it legible */
17
+ background: transparent;
18
+ border-bottom: 1px solid var(--ld-border-lit);
19
+ backdrop-filter: blur(var(--ld-blur-high));
20
+ }
21
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__toggle {
22
+ background: none;
23
+ border: none;
24
+ border-radius: var(--ld-radius-pill);
25
+ color: var(--ld-faint);
26
+ transition: background var(--ld-transition), color var(--ld-transition), transform var(--ld-transition) var(--ld-ease-bounce);
27
+ }
28
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__toggle:hover,
29
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__toggle:focus-visible {
30
+ background: var(--ld-sky-tint);
31
+ color: var(--ld-primary);
32
+ outline: none;
33
+ }
34
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__toggle:focus-visible {
35
+ box-shadow: 0 0 0 4px var(--ld-accent-glow);
36
+ }
37
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__toggle:active {
38
+ transform: scale(0.92);
39
+ }
40
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__brand {
41
+ color: var(--ld-primary);
42
+ font-family: var(--ld-font-display);
43
+ font-weight: 800;
44
+ font-size: 1.15rem;
45
+ letter-spacing: var(--ld-tracking-tight);
46
+ }
47
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-topnav__item {
48
+ padding: var(--ld-space-2) var(--ld-space-3);
49
+ border-radius: var(--ld-radius-pill);
50
+ color: var(--ld-faint);
51
+ font-family: var(--ld-font-display);
52
+ font-weight: var(--ld-font-weight-medium);
53
+ font-size: var(--ld-text-sm);
54
+ transition: background var(--ld-transition), color var(--ld-transition);
55
+ }
56
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-topnav__item:hover,
57
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-topnav__item:focus-visible {
58
+ background: var(--ld-sky-tint);
59
+ color: var(--ld-primary);
60
+ outline: none;
61
+ }
62
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-topnav__item--active,
63
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-topnav__item[aria-current="page"] {
64
+ color: var(--ld-primary);
65
+ font-weight: var(--ld-font-weight-bold);
66
+ box-shadow: inset 0 -2px 0 var(--ld-primary);
67
+ border-radius: 0;
68
+ }
69
+
70
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__nav {
71
+ background: transparent; /* the shell background shows through; a hairline divides */
72
+ border-right: 1px solid var(--ld-border-lit);
73
+ }
74
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__scrim {
75
+ background: rgba(23, 28, 31, 0.25);
76
+ backdrop-filter: blur(3px);
77
+ }
78
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav {
79
+ padding-inline: var(--ld-space-3);
80
+ }
81
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__heading {
82
+ color: var(--ld-faint);
83
+ font-family: var(--ld-font-display);
84
+ font-size: 11px;
85
+ font-weight: var(--ld-font-weight-bold);
86
+ text-transform: uppercase;
87
+ letter-spacing: 0.08em;
88
+ opacity: 0.75;
89
+ }
90
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item {
91
+ border-radius: var(--ld-radius-pill);
92
+ color: var(--ld-on-surface);
93
+ font-family: var(--ld-font-display);
94
+ font-size: var(--ld-text-sm);
95
+ font-weight: var(--ld-font-weight-medium);
96
+ transition: background var(--ld-transition), color var(--ld-transition), transform var(--ld-transition) var(--ld-ease-bounce), box-shadow var(--ld-transition);
97
+ }
98
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__icon {
99
+ color: var(--ld-faint);
100
+ }
101
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item:hover,
102
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item:focus-visible {
103
+ background: var(--ld-sky-tint);
104
+ color: var(--ld-primary);
105
+ outline: none;
106
+ }
107
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item:hover .ld-sidenav__icon,
108
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item:focus-visible .ld-sidenav__icon {
109
+ color: var(--ld-primary);
110
+ }
111
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item:focus-visible {
112
+ box-shadow: 0 0 0 4px var(--ld-accent-glow);
113
+ }
114
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item:active {
115
+ transform: scale(0.97);
116
+ }
117
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item--active,
118
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item[aria-current="page"] {
119
+ background: var(--ld-primary);
120
+ color: var(--ld-on-primary);
121
+ box-shadow: var(--ld-shadow-raised);
122
+ }
123
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item--active .ld-sidenav__icon,
124
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item[aria-current="page"] .ld-sidenav__icon,
125
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item--active:hover,
126
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item[aria-current="page"]:hover {
127
+ color: var(--ld-on-primary);
128
+ }
129
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item--active:hover,
130
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item[aria-current="page"]:hover {
131
+ background: var(--ld-primary-bright);
132
+ box-shadow: var(--ld-shadow-raised-hover);
133
+ }
134
+
135
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__footer {
136
+ border-top: 1px solid var(--ld-border);
137
+ color: var(--ld-faint);
138
+ font-size: 13px;
139
+ }
140
+
141
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-page__eyebrow {
142
+ color: var(--ld-accent-deep);
143
+ font-family: var(--ld-font-display);
144
+ font-size: 12px;
145
+ font-weight: var(--ld-font-weight-bold);
146
+ text-transform: uppercase;
147
+ letter-spacing: 0.08em;
148
+ }
149
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-page__title {
150
+ font-family: var(--ld-font-display);
151
+ font-size: clamp(1.625rem, 1.3rem + 1.2vw, 2.25rem);
152
+ font-weight: 800;
153
+ letter-spacing: var(--ld-tracking-tight);
154
+ }
155
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-page__subtitle {
156
+ color: var(--ld-faint);
157
+ }
158
+
159
+ @media (width <= 48rem) {
160
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__nav {
161
+ background: var(--ld-surface-glass-high);
162
+ backdrop-filter: blur(var(--ld-blur-high));
163
+ box-shadow: var(--ld-shadow);
164
+ }
165
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell--tabbar .ld-shell__nav {
166
+ border-right: none;
167
+ border-top: 1px solid var(--ld-border-lit);
168
+ }
169
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell--tabbar .ld-sidenav {
170
+ padding-inline: var(--ld-space-2);
171
+ }
172
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell--tabbar .ld-sidenav__item {
173
+ border-radius: var(--ld-radius);
174
+ }
175
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell--tabbar .ld-sidenav__item--active,
176
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell--tabbar .ld-sidenav__item[aria-current="page"] {
177
+ background: var(--ld-sky-tint);
178
+ color: var(--ld-primary);
179
+ box-shadow: none;
180
+ }
181
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell--tabbar .ld-sidenav__item--active .ld-sidenav__icon,
182
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell--tabbar .ld-sidenav__item[aria-current="page"] .ld-sidenav__icon {
183
+ color: var(--ld-primary);
184
+ }
185
+ }
186
+
187
+ @media (prefers-reduced-motion: reduce) {
188
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__toggle,
189
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-topnav__item,
190
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item {
191
+ transition: none;
192
+ }
193
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-shell__toggle:active,
194
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-sidenav__item:active {
195
+ transform: none;
196
+ }
197
+ }
@@ -0,0 +1,158 @@
1
+ /* summer-cloud — status card: a dense dashboard card whose left edge, ring, and
2
+ * flash carry state (generalized from pulse's repo card).
3
+ * .ld-status-card--<tone> left edge in the semantic color
4
+ * [data-ld-attention="<tone>"] outline + glow ring calling for action
5
+ * [data-ld-changed] replays the change flash while present */
6
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card {
7
+ --ld-status-attention: var(--ld-warning);
8
+ position: relative;
9
+ display: flex;
10
+ flex-direction: column;
11
+ padding: 0;
12
+ background: var(--ld-surface-glass-high);
13
+ border: 1px solid var(--ld-border);
14
+ border-left: 3px solid transparent;
15
+ border-radius: var(--ld-radius);
16
+ backdrop-filter: blur(var(--ld-blur));
17
+ -webkit-backdrop-filter: blur(var(--ld-blur));
18
+ box-shadow: var(--ld-shadow-soft);
19
+ color: var(--ld-on-surface);
20
+ overflow: hidden;
21
+ transition: background var(--ld-transition), box-shadow var(--ld-transition);
22
+ }
23
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card:hover { box-shadow: var(--ld-shadow-raised); }
24
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card--info { border-left-color: var(--ld-info); }
25
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card--success { border-left-color: var(--ld-success); }
26
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card--warning { border-left-color: var(--ld-warning); }
27
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card--danger { border-left-color: var(--ld-danger); }
28
+
29
+ /* attention ring — the tone rides on the attribute value */
30
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card[data-ld-attention] {
31
+ outline: 1px solid color-mix(in srgb, var(--ld-status-attention) 70%, transparent);
32
+ box-shadow: 0 0 14px color-mix(in srgb, var(--ld-status-attention) 35%, transparent);
33
+ }
34
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card[data-ld-attention]:hover {
35
+ box-shadow: 0 0 18px color-mix(in srgb, var(--ld-status-attention) 55%, transparent);
36
+ }
37
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card[data-ld-attention="info"] { --ld-status-attention: var(--ld-info); }
38
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card[data-ld-attention="success"] { --ld-status-attention: var(--ld-success); }
39
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card[data-ld-attention="danger"] { --ld-status-attention: var(--ld-danger); }
40
+
41
+ /* change flash — fades from a primary tint back to the resting glass */
42
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card[data-ld-changed] { animation: ld-sc-status-flash 30s ease-out forwards; }
43
+ @keyframes ld-sc-status-flash {
44
+ from { background: color-mix(in srgb, var(--ld-primary) 14%, var(--ld-surface)); }
45
+ to { background: var(--ld-surface-glass-high); }
46
+ }
47
+
48
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__watermark {
49
+ position: absolute;
50
+ top: 0;
51
+ left: -0.25rem;
52
+ width: 2rem;
53
+ height: 2rem;
54
+ color: var(--ld-on-surface);
55
+ opacity: 0.1;
56
+ pointer-events: none;
57
+ rotate: -25deg;
58
+ }
59
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__watermark > svg { width: 100%; height: 100%; }
60
+
61
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__head {
62
+ display: flex;
63
+ align-items: center;
64
+ justify-content: space-between;
65
+ gap: var(--ld-space-2);
66
+ padding: 0.625rem 0.75rem 0.5rem 0.875rem;
67
+ }
68
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__title {
69
+ min-width: 0;
70
+ overflow: hidden;
71
+ font-family: var(--ld-font-display);
72
+ font-size: var(--ld-text-sm);
73
+ font-weight: var(--ld-font-weight-bold);
74
+ white-space: nowrap;
75
+ text-overflow: ellipsis;
76
+ color: inherit;
77
+ text-decoration: none;
78
+ transition: color var(--ld-transition);
79
+ }
80
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__title[href]:hover { color: var(--ld-primary); }
81
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__prefix { color: var(--ld-faint); }
82
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__prefix::after { content: " / "; opacity: 0.5; }
83
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__meta {
84
+ display: flex;
85
+ align-items: center;
86
+ gap: 0.375rem;
87
+ flex-shrink: 0;
88
+ }
89
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__note {
90
+ font-size: 11px;
91
+ color: var(--ld-faint);
92
+ white-space: nowrap;
93
+ }
94
+
95
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__rows {
96
+ list-style: none;
97
+ margin: 0;
98
+ padding: 0;
99
+ border-top: 1px solid var(--ld-border);
100
+ }
101
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__row {
102
+ display: grid;
103
+ grid-template-columns: auto 1fr auto;
104
+ align-items: baseline;
105
+ gap: 0.375rem;
106
+ padding: 0.3rem 0.75rem 0.3rem 0.875rem;
107
+ font-size: 12px;
108
+ color: inherit;
109
+ text-decoration: none;
110
+ transition: background 0.1s;
111
+ }
112
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__row[href]:hover { background: var(--ld-sky-tint); }
113
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__row-lead {
114
+ min-width: 1.5rem;
115
+ font-size: 11px;
116
+ font-weight: var(--ld-font-weight-bold);
117
+ color: var(--ld-faint);
118
+ text-align: right;
119
+ font-variant-numeric: tabular-nums;
120
+ }
121
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__row-main {
122
+ min-width: 0;
123
+ overflow: hidden;
124
+ white-space: nowrap;
125
+ text-overflow: ellipsis;
126
+ color: var(--ld-on-surface);
127
+ }
128
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__row-trail {
129
+ display: flex;
130
+ align-items: center;
131
+ gap: var(--ld-space-1);
132
+ flex-shrink: 0;
133
+ font-size: 10px;
134
+ color: var(--ld-faint);
135
+ }
136
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__footer {
137
+ display: block;
138
+ padding: 0.3rem 0.875rem;
139
+ border-top: 1px solid var(--ld-border);
140
+ font-size: 11px;
141
+ color: var(--ld-faint);
142
+ text-decoration: none;
143
+ transition: color var(--ld-transition);
144
+ }
145
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__footer[href]:hover { color: var(--ld-primary); }
146
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card__empty {
147
+ margin: 0;
148
+ padding: 0.375rem 0.875rem 0.5rem;
149
+ border-top: 1px solid var(--ld-border);
150
+ font-size: 12px;
151
+ color: var(--ld-faint);
152
+ opacity: 0.7;
153
+ }
154
+
155
+ @media (prefers-reduced-motion: reduce) {
156
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card { transition: none; }
157
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-status-card[data-ld-changed] { animation: none; }
158
+ }
@@ -0,0 +1,101 @@
1
+ /* summer-cloud — stepper: a milestone rail with labelled step nodes (Retail
2
+ * Dashboard "Active Delivery"). Violet rail on a blend track; each step is
3
+ * .ld-stepper__step--complete solid violet node, white icon
4
+ * .ld-stepper__step--current white node, 2px violet border, raised shadow
5
+ * .ld-stepper__step--upcoming sunken node, faint icon
6
+ * The fill follows the state modifiers — no progress value to compute. */
7
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper {
8
+ display: flex;
9
+ align-items: flex-start;
10
+ list-style: none;
11
+ margin: 0;
12
+ padding: 0;
13
+ }
14
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step {
15
+ position: relative;
16
+ flex: 1 1 0;
17
+ min-width: 0;
18
+ display: flex;
19
+ flex-direction: column;
20
+ align-items: center;
21
+ gap: var(--ld-space-2);
22
+ text-align: center;
23
+ }
24
+ /* rail segment: from this node's centre to the next node's centre; the track is
25
+ * ::before, the fill ::after. Segments meet under the nodes, so the rail reads
26
+ * as one bar and the fill ends exactly at the current node. */
27
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step::before,
28
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step::after {
29
+ content: "";
30
+ position: absolute;
31
+ top: 0.75rem;
32
+ left: 50%;
33
+ width: 100%;
34
+ height: 0.5rem;
35
+ border-radius: var(--ld-radius-pill);
36
+ }
37
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step:last-child::before,
38
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step:last-child::after { display: none; }
39
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step::before { background: var(--ld-bg-blend); }
40
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step::after {
41
+ width: 0;
42
+ background: var(--ld-primary);
43
+ box-shadow: 0 0 10px rgba(69, 0, 217, 0.5);
44
+ transition: width var(--ld-transition);
45
+ }
46
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step--complete::after { width: 100%; }
47
+
48
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__node {
49
+ position: relative;
50
+ z-index: 1;
51
+ display: inline-flex;
52
+ align-items: center;
53
+ justify-content: center;
54
+ width: 2rem;
55
+ height: 2rem;
56
+ border-radius: 50%;
57
+ box-sizing: border-box;
58
+ font-family: var(--ld-font-mono);
59
+ font-size: 12px;
60
+ font-weight: var(--ld-font-weight-bold);
61
+ line-height: 1;
62
+ transition: background var(--ld-transition), color var(--ld-transition), box-shadow var(--ld-transition);
63
+ }
64
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__node > svg { width: 1rem; height: 1rem; }
65
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step--complete .ld-stepper__node {
66
+ background: var(--ld-primary);
67
+ color: var(--ld-on-primary);
68
+ }
69
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step--current .ld-stepper__node {
70
+ background: var(--ld-surface);
71
+ border: 2px solid var(--ld-primary);
72
+ color: var(--ld-primary);
73
+ box-shadow: var(--ld-shadow-raised);
74
+ }
75
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step--upcoming .ld-stepper__node {
76
+ background: var(--ld-surface-sunken);
77
+ color: var(--ld-faint);
78
+ }
79
+
80
+ /* label voice: mono 12px, tracked, sentence case */
81
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__label {
82
+ font-family: var(--ld-font-mono);
83
+ font-size: 12px;
84
+ font-weight: 500;
85
+ letter-spacing: var(--ld-tracking-wide);
86
+ line-height: 1.3;
87
+ color: var(--ld-faint);
88
+ transition: color var(--ld-transition);
89
+ }
90
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step--complete .ld-stepper__label { color: var(--ld-on-surface); }
91
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step--current .ld-stepper__label {
92
+ color: var(--ld-primary);
93
+ font-weight: var(--ld-font-weight-bold);
94
+ }
95
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step--upcoming .ld-stepper__label { color: var(--ld-faint); }
96
+
97
+ @media (prefers-reduced-motion: reduce) {
98
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__step::after,
99
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__node,
100
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-stepper__label { transition: none; }
101
+ }
@@ -32,3 +32,23 @@
32
32
  font-family: var(--ld-font-mono);
33
33
  text-align: right;
34
34
  }
35
+
36
+ /* Interactive rows (.ld-table--interactive): the cursor is the affordance —
37
+ * plain tables hover too. Focus is an outline so it
38
+ * composes with the selected state (aria-selected="true"), which sits last
39
+ * so it outranks hover. */
40
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-table--interactive tbody tr {
41
+ cursor: pointer;
42
+ }
43
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-table--interactive tbody tr:focus-visible {
44
+ outline: 2px solid var(--ld-accent);
45
+ outline-offset: -2px;
46
+ background: var(--ld-sky-tint);
47
+ }
48
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-table--interactive tbody tr:active {
49
+ background: rgba(12, 179, 255, 0.08);
50
+ }
51
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-table--interactive tbody tr[aria-selected="true"] {
52
+ background: rgba(93, 43, 255, 0.07);
53
+ box-shadow: inset 3px 0 0 0 var(--ld-primary);
54
+ }
@@ -36,3 +36,45 @@
36
36
  :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-tabpanel {
37
37
  padding: var(--ld-space-3) 0;
38
38
  }
39
+
40
+ /* Sliding indicator: one bar on the tablist, pinned to the active tab by
41
+ * anchor positioning, takes over the underline. Its inline edges transition
42
+ * separately — with data-ld-dir ("forward" | "back", set by the Tabs
43
+ * component) the edge nearer the target leads and the far edge trails, so the
44
+ * bar reaches for the tab; without it the bar just slides. Browsers without
45
+ * anchor positioning keep the static underline above. */
46
+ @supports (anchor-name: --ld-a) and (anchor-scope: --ld-a) {
47
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-tabs {
48
+ position: relative;
49
+ anchor-scope: --ld-tab-active;
50
+ }
51
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-tabs :is(.ld-tab--active, .ld-tab[aria-selected="true"]) {
52
+ anchor-name: --ld-tab-active;
53
+ border-bottom-color: transparent;
54
+ }
55
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-tabs:where(:has(.ld-tab--active, .ld-tab[aria-selected="true"]))::after {
56
+ content: "";
57
+ position: absolute;
58
+ position-anchor: --ld-tab-active;
59
+ inset-block-end: anchor(bottom);
60
+ inset-inline: anchor(start) anchor(end);
61
+ block-size: 2px;
62
+ background: var(--ld-primary);
63
+ border-radius: 2px 2px 0 0;
64
+ pointer-events: none;
65
+ transition: inset-inline-start var(--ld-slide-lead), inset-inline-end var(--ld-slide-lead);
66
+ }
67
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-tabs[data-ld-dir="forward"]::after {
68
+ transition: inset-inline-start var(--ld-slide-trail), inset-inline-end var(--ld-slide-lead);
69
+ }
70
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-tabs[data-ld-dir="back"]::after {
71
+ transition: inset-inline-start var(--ld-slide-lead), inset-inline-end var(--ld-slide-trail);
72
+ }
73
+ }
74
+
75
+ @media (prefers-reduced-motion: reduce) {
76
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-tabs::after,
77
+ :where([data-ld-style="summer-cloud"], [data-ld-style="summer-cloud"] *).ld-tabs[data-ld-dir]::after {
78
+ transition: none;
79
+ }
80
+ }
@@ -80,31 +80,93 @@ Class prefix `ld-` (shared across themes so `@lepid-labs/ui-react` stays
80
80
  theme-agnostic). Variants use BEM-ish modifiers (`ld-btn--primary`).
81
81
 
82
82
  - **Card** `.ld-card` — glass panel; `--floating` adds the Level 2 hover lift.
83
+ - **Status card** `.ld-status-card` — dense dashboard card on high glass, raised shadow on hover (from pulse's repo
84
+ card): 3px left edge takes a semantic `--<tone>`, `data-ld-attention="<tone>"`
85
+ adds an outline + glow ring, `data-ld-changed` replays a 30s tint flash.
86
+ Parts: `__watermark`, `__head`, `__prefix`, `__title`, `__meta`, `__note`,
87
+ `__rows`, `__row` (`-lead`/`-main`/`-trail`), `__footer`, `__empty`.
83
88
  - **NavLink** `.ld-link` — pill, sky-tint wash, `→` slides 4px on hover;
84
89
  `--active` / `[aria-current=page]` becomes the violet underline rule.
85
90
  - **Button** `.ld-btn` — glass by default; `--primary` (solid violet CTA, one
86
91
  per view), `--accent` (sky-edged glass), `--ghost`, `--danger`. `--sm` is a
87
92
  compact size scaled to `.ld-badge`, for inline/table-row actions; the pill
88
93
  shape is kept.
94
+ - **Hold button** `.ld-btn--hold` (+ `__ring`, `__body`, `__label`, `__hint`,
95
+ `__meter`) — hold-to-confirm: a 3px conic **violet** ring around the icon
96
+ well fills as `--ld-hold` goes 0→1, on the glass pill. With `--danger` the
97
+ pill stays glass with deep-red text (the ring and hint carry the state; a
98
+ violet ring on the solid red CTA would fight it). Press does not shrink
99
+ the pill — the ring is the feedback. `data-ld-hold="fired"` bounces to
100
+ 1.06 (dropped under reduced motion; the fill stays). Window:
101
+ `--ld-hold-duration` 350 ms — soft and unhurried.
102
+ - **Button group** `.ld-btn-group` (+ `--block`) — one long track with
103
+ `.ld-btn` segments lined up inside; the track owns the chrome and the
104
+ segments drop theirs. A long glass pill; segments are pills inside it.
105
+ The pressed segment (`aria-pressed="true"` / `.ld-btn--active`) floats up as
106
+ a white chip with bold violet text and a violet-tinted shadow. No hover
107
+ scale inside the pill (neighbours would overlap); the 0.97 press stays.
108
+ With one pressed segment the chrome is a single sliding chip: the edge
109
+ nearer the new segment leads, the far edge trails on the bounciest spring of the three themes
110
+ (`--ld-slide-lead` / `--ld-slide-trail`, direction from `data-ld-dir`).
111
+ Variants tint the label only; `--block` fills the row with equal-width
112
+ segments. Use `role="group"` + `aria-label`.
113
+ - **Icon button** `.ld-icon-btn` (+ `--active`, `--danger`) — chromeless
114
+ round 2rem pill for icon-only actions (`<button>` or `<a>`; always
115
+ `aria-label`). Faint glyph; hover fills sky-white, turns violet and
116
+ bounces up; press squishes. Active (`--active`, `aria-pressed="true"`,
117
+ `aria-current="page"`) keeps the sky-white fill and violet glyph.
118
+ `--danger` turns the glyph deep red on hover. Child `svg` 1.25em.
89
119
  - **Form** `.ld-input`, `.ld-textarea`, `.ld-select`, `.ld-label`, `.ld-field`,
90
120
  `.ld-checkbox`, `.ld-radio`, `.ld-switch`, `.ld-choice` — sunken fields, no
91
121
  resting border, sky-blue ring on focus. The switch is the oversized
92
122
  "cloud-toggle": squishy, and green when live.
93
123
  - **Badge** `.ld-badge` + semantic modifiers — solid pills, mono uppercase.
124
+ `--sm` is the 9px dashboard pill; `--pulse` the amber call to action with a
125
+ breathing glow.
94
126
  **Chip** `.ld-chip` — outlined filter chip; `--selected` fills violet.
95
127
  - **Alert** `.ld-alert` — glass card with a 4px semantic left rule.
96
128
  - **Dialog** `.ld-dialog` — native `<dialog>`, opaque white, blurred backdrop.
97
- - **Tabs** `.ld-tabs`/`.ld-tab`/`.ld-tabpanel` — violet underline when active.
129
+ - **Tabs** `.ld-tabs`/`.ld-tab`/`.ld-tabpanel` — violet underline when active; it stretches to the new tab and bounces back to width (same slide tokens).
98
130
  - **Table** `.ld-table` — mono uppercase headers, sky-tint row hover; add
99
131
  `.ld-num` to numeric cells for the mono/right-aligned treatment.
132
+ `.ld-table--interactive` adds the pointer, a sky focus outline, and a
133
+ selected row (`aria-selected`) with a violet wash and left bar.
100
134
  - **Progress** `.ld-progress`, **Spinner** `.ld-spinner` — glowing violet.
135
+ - **App shell** `.ld-shell` (+ `__skip`, `__header`, `__toggle`, `__brand`,
136
+ `__actions`, `__nav`, `__scrim`, `__main`, `__footer`; `.ld-topnav`/`__item`;
137
+ `.ld-sidenav` + `__section`, `__heading`, `__item`, `__icon`, `__label`,
138
+ `__badge`, `__footer`) — brand in Plus Jakarta 800 violet. Items are pills that fill with sky tint on hover and press in on click; the current page is the solid violet pill with the raised violet shadow (sky-tinted in the tab bar); top-nav current page takes the violet underline. The header and nav are unfilled — hairline
139
+ borders over the page background (`.ld-bg`), which the shell paints; the
140
+ header blurs what scrolls under it. The drawer and tab bar take a fill. Structure (`components/layout.css`) is shared by every theme:
141
+ collapsed rail on `data-ld-nav-collapsed`, drawer on `data-ld-nav-open`
142
+ below 48rem, `--tabbar` docks the nav at the bottom. The header
143
+ always spans the full width above the nav.
144
+ - **Page layouts** `.ld-page` (`--narrow`/`--wide`/`--full`, `__header`,
145
+ `__eyebrow`, `__title`, `__subtitle`, `__actions`), `.ld-grid`,
146
+ `.ld-split`, `.ld-aside-layout`, `.ld-center` — structure only
147
+ (`components/page.css`, shared by every theme); the page
148
+ title uses the display face.
149
+ - **Stepper** `.ld-stepper` (+ `__step`, `__node`, `__label`) — milestone
150
+ rail from the Retail Dashboard "Active Delivery" box: glowing violet fill on
151
+ a blend track, 2rem nodes. `__step--complete` is a solid violet node with a
152
+ white icon and an on-surface label; `--current` a white node with a 2px
153
+ violet border, violet icon, raised shadow, and violet label; `--upcoming` a
154
+ sunken node with faint icon and label. The rail is per-step
155
+ (`::before` track, `::after` fill), so the fill follows the modifiers and
156
+ `aria-current="step"` marks the active node.
101
157
  - **Muted text** `.ld-muted` — faint secondary/empty-state text;
102
158
  `color: var(--ld-faint)`, italic — a friendly, soft touch consistent with
103
159
  the theme's airy, optimistic voice.
104
160
  - **Pre / log block** `.ld-pre` — command/log `<pre>`; sunken background,
105
161
  `--ld-outline` hairline (not `--ld-border`, which is the glass-only token
106
162
  and would be invisible on this opaque surface), radius, small mono,
107
- horizontal scroll.
163
+ horizontal scroll. `.ld-pre--log` bounds it (`--ld-log-max-height`,
164
+ 420px), scrolls both ways, and wraps long lines — flat, no scanlines.
165
+ - **Copy control** `.ld-pre-copy` — an `.ld-icon-btn` pinned top-right in
166
+ a `.ld-pre-wrap`; fades in on hover/focus-within, always shown on touch
167
+ (`hover: none`). `data-ld-copy="copied"` swaps the copy glyph for a
168
+ success-tinted check; `"failed"` tints it danger. Status goes to a
169
+ visually hidden `aria-live` `.ld-pre-copy-status`.
108
170
 
109
171
  ## Deviations from the Stitch source
110
172
 
@@ -1,9 +1,16 @@
1
1
  /* summer-cloud — full theme entry point */
2
2
  @import "./tokens.css";
3
3
  @import "./base.css";
4
+ @import "./components/layout.css";
5
+ @import "./components/shell.css";
6
+ @import "./components/page.css";
4
7
  @import "./components/card.css";
8
+ @import "./components/status-card.css";
5
9
  @import "./components/link.css";
6
10
  @import "./components/button.css";
11
+ @import "./components/button-hold.css";
12
+ @import "./components/button-group.css";
13
+ @import "./components/icon-button.css";
7
14
  @import "./components/form.css";
8
15
  @import "./components/badge.css";
9
16
  @import "./components/alert.css";
@@ -11,5 +18,6 @@
11
18
  @import "./components/tabs.css";
12
19
  @import "./components/table.css";
13
20
  @import "./components/progress.css";
21
+ @import "./components/stepper.css";
14
22
  @import "./components/muted.css";
15
23
  @import "./components/pre.css";
@@ -76,6 +76,12 @@
76
76
  --ld-blur: 12px;
77
77
  --ld-blur-high: 20px; /* (extra) */
78
78
  --ld-transition: 0.3s;
79
+ --ld-hold-duration: 350ms; /* (extra) hold-to-confirm commitment window */
80
+ /* (extra) sliding indicator — tabs underline, button-group pill. The edge
81
+ * nearer the target leads; the far edge trails on a soft, bouncy spring that overshoots
82
+ * inward, so the indicator stretches across the gap and snaps back to shape. */
83
+ --ld-slide-lead: 0.26s cubic-bezier(0.2, 0.9, 0.3, 1);
84
+ --ld-slide-trail: 0.65s linear(0, 0.092, 0.301, 0.545, 0.767, 0.939, 1.052, 1.11, 1.126, 1.114, 1.088, 1.057, 1.029, 1.008, 0.993, 0.986, 0.984, 0.986, 0.989, 0.993, 0.996, 0.999, 1.001, 1.002, 1);
79
85
  --ld-ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1); /* (extra) */
80
86
 
81
87
  /* elevation (extra) — tinted with the primary, never grey */