@webority/theme 0.7.4 → 0.7.6

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.
@@ -260,6 +260,92 @@ a.info-row:hover .info-value {
260
260
  text-decoration: underline;
261
261
  }
262
262
 
263
+ // ============================================================================
264
+ // Labeled key-value grid — record details, definitions, attributes.
265
+ // ============================================================================
266
+ .descs {
267
+ display: flex;
268
+ flex-direction: column;
269
+ gap: 0;
270
+ }
271
+ .descs-title {
272
+ font-size: 14px;
273
+ font-weight: 600;
274
+ color: var(--color-text);
275
+ padding: 0 0 12px 0;
276
+ }
277
+ .descs-list {
278
+ display: grid;
279
+ grid-template-columns: repeat(var(--descs-cols, 2), 1fr);
280
+ gap: 0;
281
+ margin: 0;
282
+ padding: 0;
283
+ }
284
+ .descs-item {
285
+ display: contents;
286
+ grid-column: span var(--descs-span, 1);
287
+ }
288
+ .descs-label {
289
+ font-size: 12px;
290
+ font-weight: 600;
291
+ text-transform: uppercase;
292
+ letter-spacing: 0.04em;
293
+ color: var(--color-text-subtle);
294
+ padding: 12px 16px;
295
+ border-bottom: 1px solid var(--color-border);
296
+ margin: 0;
297
+ }
298
+ .descs-value {
299
+ font-size: 14px;
300
+ font-weight: 500;
301
+ color: var(--color-text);
302
+ padding: 12px 16px;
303
+ border-bottom: 1px solid var(--color-border);
304
+ margin: 0;
305
+ word-break: break-word;
306
+ }
307
+ // A blank value reads as a muted "no value", not a broken row.
308
+ .descs-value.is-empty {
309
+ font-weight: 400;
310
+ color: var(--color-text-subtle);
311
+ }
312
+ // Small size variant.
313
+ .descs-sm .descs-label,
314
+ .descs-sm .descs-value {
315
+ font-size: 12px;
316
+ padding: 8px 12px;
317
+ }
318
+ // Bordered variant removes inner dividers (only outer border on cells).
319
+ .descs-bordered .descs-label,
320
+ .descs-bordered .descs-value {
321
+ border-bottom: none;
322
+ border-right: 1px solid var(--color-border);
323
+ }
324
+ .descs-bordered .descs-item:last-child .descs-label,
325
+ .descs-bordered .descs-item:last-child .descs-value {
326
+ border-right: none;
327
+ }
328
+ .descs-bordered .descs-list > :nth-child(2n-1) {
329
+ border-bottom: 1px solid var(--color-border);
330
+ }
331
+ // Column variants — set the grid-template-columns.
332
+ .descs-col-1 .descs-list {
333
+ --descs-cols: 1;
334
+ }
335
+ .descs-col-2 .descs-list {
336
+ --descs-cols: 2;
337
+ }
338
+ .descs-col-3 .descs-list {
339
+ --descs-cols: 3;
340
+ }
341
+ // Media-breakpoint collapse to single column under md.
342
+ @include media-breakpoint-down(sm) {
343
+ .descs-col-2 .descs-list,
344
+ .descs-col-3 .descs-list {
345
+ --descs-cols: 1;
346
+ }
347
+ }
348
+
263
349
  // ============================================================================
264
350
  // Segmented control — 2–4 mutually-exclusive options shown side by side.
265
351
  // The theme toggle (light/dark/system) is the canonical use.
@@ -712,4 +798,77 @@ a.info-row:hover .info-value {
712
798
  }
713
799
  }
714
800
 
715
- // ============================================================================
801
+ // ============================================================================
802
+ // Result / outcome screen — post-checkout success, verification done, or error states.
803
+ // Distinct from AppEmptyState (which is a card/section "nothing here yet") — this is
804
+ // a self-contained result panel with a prominent status, heading, and actions.
805
+ // ============================================================================
806
+ .result {
807
+ text-align: center;
808
+ padding: 48px 24px;
809
+ color: var(--color-text-subtle);
810
+ }
811
+ .result-icon {
812
+ width: 64px;
813
+ height: 64px;
814
+ border-radius: var(--radius-lg);
815
+ display: inline-flex;
816
+ align-items: center;
817
+ justify-content: center;
818
+ margin-bottom: 24px;
819
+ }
820
+ .result-code {
821
+ font-size: 72px;
822
+ font-weight: 700;
823
+ line-height: 1;
824
+ margin-bottom: 20px;
825
+ color: var(--color-text-subtle);
826
+ letter-spacing: -0.04em;
827
+ }
828
+ .result-title {
829
+ font-size: 24px;
830
+ font-weight: 700;
831
+ line-height: 1.35;
832
+ color: var(--color-text);
833
+ margin: 0 0 12px 0;
834
+ }
835
+ .result-subtitle {
836
+ font-size: 16px;
837
+ line-height: 1.5;
838
+ color: var(--color-text-muted);
839
+ margin: 0 0 20px 0;
840
+ }
841
+ .result-actions {
842
+ margin-top: 20px;
843
+ display: flex;
844
+ align-items: center;
845
+ justify-content: center;
846
+ flex-wrap: wrap;
847
+ gap: 12px;
848
+ }
849
+ .result-extra {
850
+ margin-top: 24px;
851
+ font-size: 14px;
852
+ line-height: 1.5;
853
+ color: var(--color-text-muted);
854
+ }
855
+ // Tone variants — success/danger/warning/info for icon-driven results, muted for code numerics.
856
+ .result-success .result-icon {
857
+ background: var(--color-success-soft);
858
+ color: var(--color-success-text);
859
+ }
860
+ .result-danger .result-icon {
861
+ background: var(--color-danger-soft);
862
+ color: var(--color-danger-text);
863
+ }
864
+ .result-warning .result-icon {
865
+ background: var(--color-warning-soft);
866
+ color: var(--color-warning-text);
867
+ }
868
+ .result-info .result-icon {
869
+ background: var(--color-info-soft);
870
+ color: var(--color-info-text);
871
+ }
872
+ .result-muted .result-code {
873
+ color: var(--color-text-muted);
874
+ }
@@ -10,6 +10,10 @@
10
10
  // .stepper-journey — wide: 40px dot beside a label + title, for a page masthead.
11
11
  // ============================================================================
12
12
  .stepper {
13
+ // Full width so the flex:1 steps spread evenly across the container. Without it,
14
+ // a stepper dropped into a flex/grid parent shrinks to its content and the steps
15
+ // bunch at one edge, colliding their labels.
16
+ width: 100%;
13
17
  display: flex;
14
18
  align-items: flex-start;
15
19
  gap: 0;
@@ -79,27 +83,61 @@
79
83
  .step.done .step-label {
80
84
  color: var(--color-text);
81
85
  }
82
- // A step that is an <a> is a deep link back to an earlier stage of the wizard.
86
+ // An interactive step — an <a> deep-linking back to a stage, or a <button> in a
87
+ // JS-driven wizard. A button needs its chrome stripped so it reads as a step.
88
+ button.step {
89
+ border: none;
90
+ background: none;
91
+ padding: 0;
92
+ font: inherit;
93
+ color: inherit;
94
+ }
83
95
  a.step {
84
96
  text-decoration: none;
97
+ }
98
+ a.step,
99
+ button.step {
85
100
  cursor: pointer;
86
101
  }
87
- a.step:hover .step-circle {
102
+ a.step:hover .step-circle,
103
+ button.step:hover .step-circle {
88
104
  box-shadow: 0 0 0 4px var(--color-primary-soft);
89
105
  transform: scale(1.04);
90
106
  }
91
- a.step:hover .step-label {
107
+ a.step:hover .step-label,
108
+ button.step:hover .step-label {
92
109
  color: var(--color-primary);
93
110
  }
94
- a.step:focus-visible {
111
+ a.step:focus-visible,
112
+ button.step:focus-visible {
95
113
  outline: none;
96
114
  }
97
- // The ring moves onto the circle: an outline on the <a> would box the whole column.
98
- a.step:focus-visible .step-circle {
115
+ // The ring moves onto the circle: an outline on the <a>/<button> would box the whole column.
116
+ a.step:focus-visible .step-circle,
117
+ button.step:focus-visible .step-circle {
99
118
  box-shadow:
100
119
  0 0 0 4px var(--color-primary-soft),
101
120
  0 0 0 6px var(--color-primary);
102
121
  }
122
+ // A step that failed its stage — a red circle with an alert, so an invalid step
123
+ // reads as wrong at a glance rather than merely "not done".
124
+ .step.error .step-circle {
125
+ border-color: var(--color-danger);
126
+ background: var(--color-danger);
127
+ color: var(--color-on-scrim);
128
+ }
129
+ .step.error .step-label {
130
+ color: var(--color-danger-text);
131
+ }
132
+ // A secondary line under the label — a short "what this step is for". Muted and
133
+ // narrow so it never competes with the label it explains.
134
+ .step-desc {
135
+ max-width: 130px;
136
+ font-size: 12px;
137
+ line-height: 1.3;
138
+ color: var(--color-text-muted);
139
+ overflow-wrap: break-word;
140
+ }
103
141
 
104
142
  .stepper-journey {
105
143
  display: flex;
@@ -166,6 +204,15 @@ a.step:focus-visible .step-circle {
166
204
  .stepper-journey .step.active .step-index {
167
205
  color: var(--color-primary);
168
206
  }
207
+ .stepper-journey .step.error .step-circle {
208
+ background: var(--color-danger-soft);
209
+ color: var(--color-danger-text);
210
+ box-shadow: none;
211
+ transform: none;
212
+ }
213
+ .stepper-journey .step.error .step-index {
214
+ color: var(--color-danger-text);
215
+ }
169
216
  .stepper-journey .step-label {
170
217
  max-width: none;
171
218
  margin-top: 8px;
@@ -176,6 +223,15 @@ a.step:focus-visible .step-circle {
176
223
  text-overflow: ellipsis;
177
224
  color: var(--color-text);
178
225
  }
226
+ // In the journey bar the description sits inside the text column, under the label —
227
+ // wider and left-aligned to match, not the centred compact treatment.
228
+ .stepper-journey .step-desc {
229
+ max-width: none;
230
+ margin-top: 2px;
231
+ white-space: nowrap;
232
+ overflow: hidden;
233
+ text-overflow: ellipsis;
234
+ }
179
235
  .stepper-journey .step-line {
180
236
  flex: none;
181
237
  width: 32px;
@@ -199,8 +255,86 @@ a.step:focus-visible .step-circle {
199
255
  display: none;
200
256
  }
201
257
  }
258
+ // Vertical orientation. The steps run down a side rail instead of across — for a
259
+ // narrow column, a drawer, or a settings wizard.
260
+ // ----------------------------------------------------------------------------
261
+ .stepper-vertical {
262
+ flex-direction: column;
263
+ align-items: stretch;
264
+ // The gap between steps; kept in sync with the ::after `bottom` so the connector
265
+ // spans it exactly and still meets the next circle.
266
+ gap: 18px;
267
+ padding: 0;
268
+ }
269
+ // Each compact step becomes a two-column row: the circle in a fixed rail on the
270
+ // left, the label and its description stacked on the right.
271
+ .stepper-vertical .step {
272
+ display: grid;
273
+ grid-template-columns: 28px 1fr;
274
+ column-gap: 12px;
275
+ // No gap between the label and its description — they read as one block; the
276
+ // base .step gap of 10px is for the horizontal circle→label spacing.
277
+ row-gap: 0;
278
+ align-items: start;
279
+ text-align: left;
280
+ }
281
+ // The circle spans the whole text block rather than sitting in the first row: a
282
+ // row sized to the 28px circle would leave dead space below a single-line label
283
+ // before the description. Spanning lets each row size to its text instead.
284
+ .stepper-vertical .step-circle {
285
+ grid-column: 1;
286
+ grid-row: 1 / -1;
287
+ align-self: start;
288
+ }
289
+ .stepper-vertical .step-label {
290
+ grid-column: 2;
291
+ grid-row: 1;
292
+ max-width: none;
293
+ // Centred against the circle when the step has no description (single 28px row);
294
+ // a no-op when a description makes the row size to the label.
295
+ align-self: center;
296
+ }
297
+ .stepper-vertical .step-desc {
298
+ grid-column: 2;
299
+ grid-row: 2;
300
+ max-width: none;
301
+ }
302
+ // The compact connector is horizontal (::before); redraw it as a vertical segment
303
+ // down the circle's centre, from below one circle to the top of the next.
304
+ .stepper-vertical .step + .step::before {
305
+ content: none;
306
+ }
307
+ .stepper-vertical .step:not(:last-child)::after {
308
+ content: "";
309
+ position: absolute;
310
+ // 13px = half the 28px circle minus 1 for the 2px line's own width.
311
+ left: 13px;
312
+ top: 28px;
313
+ // Reaches through the 18px inter-step gap to meet the next circle's top; keep
314
+ // this in sync with the .stepper-vertical `gap`.
315
+ bottom: -18px;
316
+ width: 2px;
317
+ background: var(--color-border);
318
+ z-index: 0;
319
+ }
320
+ .stepper-vertical .step.done:not(:last-child)::after {
321
+ background: var(--color-primary);
322
+ }
323
+ // The journey bar stacked vertically reuses its own narrow-width treatment: a plain
324
+ // column with the horizontal connectors dropped (a real vertical rail here would
325
+ // fight the two-line text blocks for alignment).
326
+ .stepper-journey.stepper-vertical {
327
+ flex-direction: column;
328
+ align-items: stretch;
329
+ gap: 10px;
330
+ }
331
+ .stepper-journey.stepper-vertical .step-line {
332
+ display: none;
333
+ }
334
+
202
335
  @media (prefers-reduced-motion: reduce) {
203
336
  a.step:hover .step-circle,
337
+ button.step:hover .step-circle,
204
338
  .stepper-journey .step-circle {
205
339
  transition: none;
206
340
  transform: none;
@@ -407,4 +541,79 @@ a.step:focus-visible .step-circle {
407
541
  text-align: center;
408
542
  }
409
543
 
410
- // ============================================================================
544
+ // ============================================================================
545
+ // Form layout helpers — section, row (grid), actions footer.
546
+ //
547
+ // AppFormSection wraps related fields with a title + description intro.
548
+ // AppFormRow arranges fields in a responsive grid (1/2/3 columns).
549
+ // AppFormActions is an action button footer, optionally sticky-bottom.
550
+ // ============================================================================
551
+ .form-section {
552
+ display: flex;
553
+ flex-direction: column;
554
+ gap: 20px;
555
+ }
556
+ .form-section-head {
557
+ display: flex;
558
+ flex-direction: column;
559
+ gap: 6px;
560
+ }
561
+ .form-section-title {
562
+ margin: 0;
563
+ font-size: 17px;
564
+ font-weight: 600;
565
+ line-height: 1.3;
566
+ color: var(--color-text);
567
+ }
568
+ .form-section-desc {
569
+ margin: 0;
570
+ font-size: 14px;
571
+ line-height: 1.4;
572
+ color: var(--color-text-muted);
573
+ }
574
+ .form-section-body {
575
+ display: flex;
576
+ flex-direction: column;
577
+ gap: 16px;
578
+ }
579
+
580
+ // ============================================================================
581
+ .form-row-grid {
582
+ display: grid;
583
+ grid-template-columns: repeat(var(--form-cols, 2), minmax(0, 1fr));
584
+ gap: 16px;
585
+ align-items: start;
586
+ }
587
+ // Below md, collapse to 1 column.
588
+ @include media-breakpoint-down(md) {
589
+ .form-row-grid.form-row-grid {
590
+ grid-template-columns: 1fr;
591
+ }
592
+ }
593
+
594
+ // ============================================================================
595
+ .form-actions {
596
+ display: flex;
597
+ align-items: center;
598
+ gap: 12px;
599
+ justify-content: flex-end;
600
+ }
601
+ .form-actions-start {
602
+ justify-content: flex-start;
603
+ }
604
+ .form-actions-between {
605
+ justify-content: space-between;
606
+ }
607
+ .form-actions-sticky {
608
+ position: sticky;
609
+ bottom: 0;
610
+ padding: 16px 0;
611
+ margin-top: 24px;
612
+ border-top: 1px solid var(--color-border);
613
+ background: var(--color-surface);
614
+ }
615
+ @media (prefers-reduced-motion: reduce) {
616
+ .form-actions-sticky {
617
+ transition: none;
618
+ }
619
+ }