@dillingerstaffing/strand-ui 0.8.0 → 0.10.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/HTML_REFERENCE.md CHANGED
@@ -8,7 +8,9 @@
8
8
 
9
9
  > **Principle 1 (Cognitive Economy):** Every element must earn its place. Test: remove an element. If the task still works, it was decoration. If you're not adding back 10% of what you delete, you're not deleting enough. See [DL L61-69](./DESIGN_LANGUAGE.md#L61).
10
10
 
11
- > **Principle 2 (Biosynthetic Restraint):** Max 12 distinct visual elements per screen. See [DL L71-79](./DESIGN_LANGUAGE.md#L71).
11
+ > **Principle 2 (Biosynthetic Restraint):** Max 12 distinct visual elements per screen. Every composition must have exactly one visually dominant primary element. If all elements have equal visual weight, the composition has no focal point. An instrument without a focal point is a parts bin, not an instrument. See [DL L71-84](./DESIGN_LANGUAGE.md#L71).
12
+
13
+ > **Principle 9 (Typography Carries the Room):** The largest text and smallest text on the same screen must have at least a 3:1 size ratio. Uniform typography is a spreadsheet. Hierarchical typography is an instrument panel. See [DL L165-178](./DESIGN_LANGUAGE.md#L165).
12
14
 
13
15
  ## Required CSS
14
16
 
@@ -265,6 +267,8 @@ All container components (Grid, Stack, Card, Container) enforce boundary integri
265
267
 
266
268
  > **Elevation:** Cards at rest use Level 1 shadow. On hover, Level 2. See [DESIGN_LANGUAGE.md Principle 5: Earned Elevation (L114-L125)](./DESIGN_LANGUAGE.md#L114) and [7.2: Container Elevation Contexts (L698-L708)](./DESIGN_LANGUAGE.md#L698).
267
269
 
270
+ > **Cards are instrument panels, not generic containers.** Before placing multiple cards in a layout, apply [Principle 2 hierarchy test (L71-84)](./DESIGN_LANGUAGE.md#L71): which card is the primary instrument? It should be visually dominant. Apply [Principle 10 (L171-196)](./DESIGN_LANGUAGE.md#L171): describe the layout in laboratory vocabulary. If it sounds generic, redesign.
271
+
268
272
  ---
269
273
 
270
274
  ### Badge
@@ -407,6 +411,8 @@ All container components (Grid, Stack, Card, Container) enforce boundary integri
407
411
 
408
412
  > **The DataReadout pattern** is uniquely Strand: monospace overline + large light-weight value + tabular numerals. See [DESIGN_LANGUAGE.md 11.2: Data Display (L918-L955)](./DESIGN_LANGUAGE.md#L918).
409
413
 
414
+ > **DataReadout has three sizes for hierarchy, not preference.** Use ONE default or lg readout as the primary focal point, with sm readouts as supporting secondaries. If all readouts on a screen are the same size, apply [Principle 2 hierarchy test (L71-84)](./DESIGN_LANGUAGE.md#L71) and [Principle 9 contrast ratio test (L165-178)](./DESIGN_LANGUAGE.md#L165).
415
+
410
416
  ---
411
417
 
412
418
  ### CodeBlock
@@ -429,6 +435,10 @@ All container components (Grid, Stack, Card, Container) enforce boundary integri
429
435
 
430
436
  > **Spacing rules:** 4px base unit, padding tiers, and the gap > padding hierarchy: [DESIGN_LANGUAGE.md Part V: Spacing (L410-L496)](./DESIGN_LANGUAGE.md#L410). Responsive breakpoints and container system: [Part X: Layout (L829-L877)](./DESIGN_LANGUAGE.md#L829).
431
437
 
438
+ > **Before composing a layout, apply [Principle 2 (L71-84)](./DESIGN_LANGUAGE.md#L71) and [Principle 10 (L171-196)](./DESIGN_LANGUAGE.md#L171).** Identify the primary element. Describe the layout in laboratory vocabulary. If the description sounds generic ("a grid of data cards"), the composition doesn't embody the DL. An analytical readout panel has one dominant readout and supporting secondaries -- not four equal panels.
439
+
440
+ > **Before sizing text, apply [Principle 9 (L165-178)](./DESIGN_LANGUAGE.md#L165).** Largest to smallest text on the same screen must be at least 3:1. If all text is the same size, the typography is uniform. Uniform typography is a spreadsheet, not an instrument panel.
441
+
432
442
  ### Stack
433
443
 
434
444
  ```html
@@ -865,3 +875,111 @@ The monospace uppercase tracked label pattern. Used for section labels, category
865
875
  ```
866
876
 
867
877
  Intro paragraph. Max 50 characters per line. Used after headlines.
878
+
879
+ ### Secondary Text
880
+
881
+ ```html
882
+ <p class="strand-text-secondary">Supporting description for a card, feature, or section.</p>
883
+ <span class="strand-text-secondary strand-text-secondary--xs">Fine print or metadata.</span>
884
+ ```
885
+
886
+ Caption/description text. text-sm, gray-500, relaxed leading. The `--xs` modifier reduces to text-xs for metadata and fine print.
887
+
888
+ > **DL foundation:** [DESIGN_LANGUAGE.md Part III.8 Color Roles](./DESIGN_LANGUAGE.md#L290) defines gray-500 as the secondary text role. [Part IV.7 Named Text Patterns](./DESIGN_LANGUAGE.md#L408) specifies the Secondary pattern.
889
+
890
+ ---
891
+
892
+ ## Composition Molecules
893
+
894
+ Named CSS classes for common compositions. Each implements one or more productions from the [DL Composition Grammar (Part XI-B)](./DESIGN_LANGUAGE.md#L1085).
895
+
896
+ > **Composition rules:** [DL 11.10 Productions](./DESIGN_LANGUAGE.md#L1144) | [DL 11.11 Containment](./DESIGN_LANGUAGE.md#L1199) | [DL 11.12 Derivation](./DESIGN_LANGUAGE.md#L1215) | [DL 11.13 Tests](./DESIGN_LANGUAGE.md#L1246)
897
+
898
+ ### Card Section
899
+
900
+ Production: `section-boundary`.
901
+
902
+ ```html
903
+ <div class="strand-card strand-card--elevated strand-card--pad-md">
904
+ <div class="strand-card-section">
905
+ <span class="strand-overline">Section Label</span>
906
+ </div>
907
+ <!-- section content -->
908
+ </div>
909
+ ```
910
+
911
+ Multiple sections stack. Last section omits trailing border via `:last-child`.
912
+
913
+ ### Key-Value Row
914
+
915
+ Productions: `inline-pair` + `ranked-sequence`.
916
+
917
+ ```html
918
+ <div class="strand-kv">
919
+ <span class="strand-kv__label">Blend</span>
920
+ <span class="strand-kv__value">Ethiopian Yirgacheffe</span>
921
+ </div>
922
+ <div class="strand-kv">
923
+ <span class="strand-kv__label">Status</span>
924
+ <span class="strand-kv__value strand-kv__value--status">Active</span>
925
+ </div>
926
+ ```
927
+
928
+ **Modifier:** `strand-kv__value--status` applies semantic color.
929
+
930
+ ### Diagnostic Log Entry
931
+
932
+ Productions: `inline-sequence` + `ranked-sequence`.
933
+
934
+ ```html
935
+ <div class="strand-log">
936
+ <span class="strand-log__time">9:15</span>
937
+ <span class="strand-log__status strand-log__status--complete">Brewed</span>
938
+ <span class="strand-text-secondary">Pour over. 18g.</span>
939
+ </div>
940
+ <div class="strand-log">
941
+ <span class="strand-log__time">6:30</span>
942
+ <span class="strand-log__status strand-log__status--process">Brewing</span>
943
+ <span class="strand-text-secondary">Espresso. 18g.</span>
944
+ </div>
945
+ ```
946
+
947
+ **Status variants:** `--complete` (teal) | `--process` (blue) | `--warning` (amber) | `--error` (red)
948
+
949
+ ### Metric Row
950
+
951
+ Production: `centered-group`.
952
+
953
+ ```html
954
+ <div class="strand-metric-row">
955
+ <div class="strand-data-readout strand-data-readout--sm">
956
+ <span class="strand-data-readout__label">Daily</span>
957
+ <span class="strand-data-readout__value">36g</span>
958
+ </div>
959
+ <div class="strand-data-readout strand-data-readout--sm">
960
+ <span class="strand-data-readout__label">Days Left</span>
961
+ <span class="strand-data-readout__value">7.9</span>
962
+ </div>
963
+ </div>
964
+ ```
965
+
966
+ ### Bar Chart
967
+
968
+ Production: `column-array`.
969
+
970
+ ```html
971
+ <div class="strand-bar-chart">
972
+ <div class="strand-bar-chart__col">
973
+ <span class="strand-bar-chart__amount">284</span>
974
+ <div class="strand-bar-chart__bar" style="height: 100%"></div>
975
+ <span class="strand-bar-chart__label">Thu</span>
976
+ </div>
977
+ <div class="strand-bar-chart__col">
978
+ <span class="strand-bar-chart__amount">248</span>
979
+ <div class="strand-bar-chart__bar" style="height: 87%"></div>
980
+ <span class="strand-bar-chart__label">Fri</span>
981
+ </div>
982
+ </div>
983
+ ```
984
+
985
+ Heights are inline styles (data-driven). Place inside `.strand-instrument-viewport` for dual-surface treatment.
@@ -488,6 +488,7 @@
488
488
 
489
489
  /* ── Variants ── */
490
490
  .strand-card--elevated {
491
+ border: 1px solid var(--strand-border-subtle);
491
492
  box-shadow: var(--strand-elevation-1);
492
493
  }
493
494
 
@@ -497,6 +498,7 @@
497
498
  }
498
499
 
499
500
  .strand-card--interactive {
501
+ border: 1px solid var(--strand-border-subtle);
500
502
  box-shadow: var(--strand-elevation-1);
501
503
  cursor: pointer;
502
504
  transition:
@@ -960,11 +962,16 @@
960
962
  min-width: 0;
961
963
  }
962
964
 
963
- /* ── Column utilities ── */
965
+ /* ── Fixed column utilities ── */
964
966
  .strand-grid--cols-2 { grid-template-columns: repeat(2, 1fr); }
965
967
  .strand-grid--cols-3 { grid-template-columns: repeat(3, 1fr); }
966
968
  .strand-grid--cols-4 { grid-template-columns: repeat(4, 1fr); }
967
969
 
970
+ /* ── Responsive auto-fit (columns adjust to available width) ── */
971
+ .strand-grid--auto-sm { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
972
+ .strand-grid--auto-md { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
973
+ .strand-grid--auto-lg { grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); }
974
+
968
975
  /* ── Gap utilities ── */
969
976
  .strand-grid--gap-1 { gap: var(--strand-space-1); }
970
977
  .strand-grid--gap-2 { gap: var(--strand-space-2); }
@@ -2639,6 +2646,16 @@
2639
2646
  letter-spacing: var(--strand-tracking-tighter);
2640
2647
  }
2641
2648
 
2649
+ /* ── Title (human voice display, DL Part IV.7) ── */
2650
+ .strand-title {
2651
+ font-family: var(--strand-font-sans);
2652
+ font-weight: var(--strand-weight-light);
2653
+ letter-spacing: var(--strand-tracking-tighter);
2654
+ color: var(--strand-blue-midnight);
2655
+ font-size: clamp(1.5rem, 3vw + 0.5rem, 2.5rem);
2656
+ line-height: var(--strand-leading-snug);
2657
+ }
2658
+
2642
2659
  /* ── Lead (intro paragraph, DL Part IV.6) ── */
2643
2660
  .strand-lead {
2644
2661
  font-size: var(--strand-text-lg);
@@ -2647,4 +2664,162 @@
2647
2664
  line-height: var(--strand-leading-relaxed);
2648
2665
  }
2649
2666
 
2667
+ /* ── Secondary text (caption/description, DL Part III.8 Color Roles) ── */
2668
+ .strand-text-secondary {
2669
+ font-size: var(--strand-text-sm);
2670
+ color: var(--strand-gray-500);
2671
+ line-height: var(--strand-leading-relaxed);
2672
+ }
2673
+
2674
+ .strand-text-secondary--xs {
2675
+ font-size: var(--strand-text-xs);
2676
+ }
2677
+
2678
+ /* ══════════════════════════════════════════════════
2679
+ COMPOSITION MOLECULES (DL Part XI-B Grammar)
2680
+ Named derivations of DL composition primitives.
2681
+ Each molecule is a convenience class for a common
2682
+ derivation chain. See DL 11.10 Productions for the
2683
+ grammar rules; DL 11.12 Derivation for verification.
2684
+ ══════════════════════════════════════════════════ */
2685
+
2686
+ /* ── Card Section ──
2687
+ Derivation: section-boundary production (DL 11.10).
2688
+ OVERLINE + border-bottom + margin-bottom + padding-bottom */
2689
+ .strand-card-section {
2690
+ margin-bottom: var(--strand-space-3);
2691
+ padding-bottom: var(--strand-space-2);
2692
+ border-bottom: 1px solid var(--strand-gray-200);
2693
+ }
2694
+
2695
+ /* ── Key-Value Row ──
2696
+ Derivation: inline-pair + ranked-sequence (DL 11.10).
2697
+ identifier(OVERLINE) + quantifier(MONO_VALUE) + RANK_BORDER */
2698
+ .strand-kv {
2699
+ display: flex;
2700
+ justify-content: space-between;
2701
+ align-items: center;
2702
+ padding-block: var(--strand-space-2);
2703
+ }
2704
+
2705
+ .strand-kv + .strand-kv {
2706
+ border-top: 1px solid var(--strand-border-subtle);
2707
+ }
2708
+
2709
+ .strand-kv__label {
2710
+ font-family: var(--strand-font-mono);
2711
+ font-size: var(--strand-text-xs);
2712
+ font-weight: var(--strand-weight-medium);
2713
+ letter-spacing: var(--strand-tracking-wider);
2714
+ text-transform: uppercase;
2715
+ color: var(--strand-gray-500);
2716
+ }
2717
+
2718
+ .strand-kv__value {
2719
+ font-family: var(--strand-font-mono);
2720
+ font-size: var(--strand-text-xs);
2721
+ color: var(--strand-gray-600);
2722
+ font-variant-numeric: tabular-nums;
2723
+ }
2724
+
2725
+ .strand-kv__value--status {
2726
+ color: var(--strand-teal-vital);
2727
+ }
2728
+
2729
+ /* ── Diagnostic Log Entry ──
2730
+ Derivation: inline-sequence + ranked-sequence (DL 11.10).
2731
+ time(OVERLINE) + status(OVERLINE+COLOR_SEMANTIC) + text(SECONDARY) + RANK_BORDER */
2732
+ .strand-log {
2733
+ display: flex;
2734
+ gap: var(--strand-space-3);
2735
+ padding-block: var(--strand-space-2);
2736
+ }
2737
+
2738
+ .strand-log + .strand-log {
2739
+ border-top: 1px solid var(--strand-border-subtle);
2740
+ }
2741
+
2742
+ .strand-log__time {
2743
+ font-family: var(--strand-font-mono);
2744
+ font-size: var(--strand-text-xs);
2745
+ font-weight: var(--strand-weight-medium);
2746
+ letter-spacing: var(--strand-tracking-wider);
2747
+ text-transform: uppercase;
2748
+ color: var(--strand-gray-400);
2749
+ font-variant-numeric: tabular-nums;
2750
+ white-space: nowrap;
2751
+ }
2752
+
2753
+ .strand-log__status {
2754
+ font-family: var(--strand-font-mono);
2755
+ font-size: var(--strand-text-xs);
2756
+ font-weight: var(--strand-weight-semibold);
2757
+ letter-spacing: var(--strand-tracking-wider);
2758
+ text-transform: uppercase;
2759
+ white-space: nowrap;
2760
+ }
2761
+
2762
+ .strand-log__status--complete { color: var(--strand-teal-vital); }
2763
+ .strand-log__status--process { color: var(--strand-blue-primary); }
2764
+ .strand-log__status--warning { color: var(--strand-amber-caution); }
2765
+ .strand-log__status--error { color: var(--strand-red-alert); }
2766
+
2767
+ /* ── Metric Row ──
2768
+ Derivation: centered-group (DL 11.10).
2769
+ self-contained(atom)* with center distribution + responsive gap */
2770
+ .strand-metric-row {
2771
+ display: flex;
2772
+ justify-content: center;
2773
+ gap: clamp(2rem, 5vw, 4rem);
2774
+ text-align: center;
2775
+ }
2776
+
2777
+ /* ── Bar Chart ──
2778
+ Derivation: column-array (DL 11.10).
2779
+ column(amount? + bar + label)* with equal flex + flex-end alignment.
2780
+ Blue Discipline: one color (--strand-blue-indicator). Part XIII viz rules. */
2781
+ .strand-bar-chart {
2782
+ display: flex;
2783
+ gap: var(--strand-space-2);
2784
+ align-items: flex-end;
2785
+ height: var(--strand-space-24);
2786
+ padding: var(--strand-space-5);
2787
+ }
2788
+
2789
+ .strand-bar-chart__col {
2790
+ flex: 1;
2791
+ display: flex;
2792
+ flex-direction: column;
2793
+ align-items: center;
2794
+ gap: var(--strand-space-1);
2795
+ height: 100%;
2796
+ justify-content: flex-end;
2797
+ }
2798
+
2799
+ .strand-bar-chart__bar {
2800
+ width: 100%;
2801
+ background: var(--strand-blue-indicator);
2802
+ border-radius: var(--strand-radius-sm) var(--strand-radius-sm) 0 0;
2803
+ min-height: var(--strand-space-1);
2804
+ }
2805
+
2806
+ .strand-bar-chart__amount {
2807
+ font-family: var(--strand-font-mono);
2808
+ font-size: var(--strand-text-xs);
2809
+ font-weight: var(--strand-weight-medium);
2810
+ letter-spacing: var(--strand-tracking-wider);
2811
+ text-transform: uppercase;
2812
+ color: var(--strand-gray-300);
2813
+ font-variant-numeric: tabular-nums;
2814
+ }
2815
+
2816
+ .strand-bar-chart__label {
2817
+ font-family: var(--strand-font-mono);
2818
+ font-size: var(--strand-text-xs);
2819
+ font-weight: var(--strand-weight-medium);
2820
+ letter-spacing: var(--strand-tracking-wider);
2821
+ text-transform: uppercase;
2822
+ color: var(--strand-gray-400);
2823
+ }
2824
+
2650
2825
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dillingerstaffing/strand-ui",
3
- "version": "0.8.0",
3
+ "version": "0.10.0",
4
4
  "description": "Strand UI - Preact/React component library built on the Strand Design Language",
5
5
  "author": "Dillinger Staffing <engineering@dillingerstaffing.com> (https://dillingerstaffing.com)",
6
6
  "license": "MIT",
@@ -60,7 +60,7 @@
60
60
  }
61
61
  },
62
62
  "dependencies": {
63
- "@dillingerstaffing/strand": "^0.8.0"
63
+ "@dillingerstaffing/strand": "^0.10.0"
64
64
  },
65
65
  "devDependencies": {
66
66
  "@testing-library/preact": "^3.2.0",
@@ -12,6 +12,7 @@
12
12
 
13
13
  /* ── Variants ── */
14
14
  .strand-card--elevated {
15
+ border: 1px solid var(--strand-border-subtle);
15
16
  box-shadow: var(--strand-elevation-1);
16
17
  }
17
18
 
@@ -21,6 +22,7 @@
21
22
  }
22
23
 
23
24
  .strand-card--interactive {
25
+ border: 1px solid var(--strand-border-subtle);
24
26
  box-shadow: var(--strand-elevation-1);
25
27
  cursor: pointer;
26
28
  transition:
@@ -12,11 +12,16 @@
12
12
  min-width: 0;
13
13
  }
14
14
 
15
- /* ── Column utilities ── */
15
+ /* ── Fixed column utilities ── */
16
16
  .strand-grid--cols-2 { grid-template-columns: repeat(2, 1fr); }
17
17
  .strand-grid--cols-3 { grid-template-columns: repeat(3, 1fr); }
18
18
  .strand-grid--cols-4 { grid-template-columns: repeat(4, 1fr); }
19
19
 
20
+ /* ── Responsive auto-fit (columns adjust to available width) ── */
21
+ .strand-grid--auto-sm { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
22
+ .strand-grid--auto-md { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
23
+ .strand-grid--auto-lg { grid-template-columns: repeat(auto-fit, minmax(360px, 1fr)); }
24
+
20
25
  /* ── Gap utilities ── */
21
26
  .strand-grid--gap-1 { gap: var(--strand-space-1); }
22
27
  .strand-grid--gap-2 { gap: var(--strand-space-2); }
package/src/static.css CHANGED
@@ -77,6 +77,16 @@
77
77
  letter-spacing: var(--strand-tracking-tighter);
78
78
  }
79
79
 
80
+ /* ── Title (human voice display, DL Part IV.7) ── */
81
+ .strand-title {
82
+ font-family: var(--strand-font-sans);
83
+ font-weight: var(--strand-weight-light);
84
+ letter-spacing: var(--strand-tracking-tighter);
85
+ color: var(--strand-blue-midnight);
86
+ font-size: clamp(1.5rem, 3vw + 0.5rem, 2.5rem);
87
+ line-height: var(--strand-leading-snug);
88
+ }
89
+
80
90
  /* ── Lead (intro paragraph, DL Part IV.6) ── */
81
91
  .strand-lead {
82
92
  font-size: var(--strand-text-lg);
@@ -84,3 +94,161 @@
84
94
  max-width: 50ch;
85
95
  line-height: var(--strand-leading-relaxed);
86
96
  }
97
+
98
+ /* ── Secondary text (caption/description, DL Part III.8 Color Roles) ── */
99
+ .strand-text-secondary {
100
+ font-size: var(--strand-text-sm);
101
+ color: var(--strand-gray-500);
102
+ line-height: var(--strand-leading-relaxed);
103
+ }
104
+
105
+ .strand-text-secondary--xs {
106
+ font-size: var(--strand-text-xs);
107
+ }
108
+
109
+ /* ══════════════════════════════════════════════════
110
+ COMPOSITION MOLECULES (DL Part XI-B Grammar)
111
+ Named derivations of DL composition primitives.
112
+ Each molecule is a convenience class for a common
113
+ derivation chain. See DL 11.10 Productions for the
114
+ grammar rules; DL 11.12 Derivation for verification.
115
+ ══════════════════════════════════════════════════ */
116
+
117
+ /* ── Card Section ──
118
+ Derivation: section-boundary production (DL 11.10).
119
+ OVERLINE + border-bottom + margin-bottom + padding-bottom */
120
+ .strand-card-section {
121
+ margin-bottom: var(--strand-space-3);
122
+ padding-bottom: var(--strand-space-2);
123
+ border-bottom: 1px solid var(--strand-gray-200);
124
+ }
125
+
126
+ /* ── Key-Value Row ──
127
+ Derivation: inline-pair + ranked-sequence (DL 11.10).
128
+ identifier(OVERLINE) + quantifier(MONO_VALUE) + RANK_BORDER */
129
+ .strand-kv {
130
+ display: flex;
131
+ justify-content: space-between;
132
+ align-items: center;
133
+ padding-block: var(--strand-space-2);
134
+ }
135
+
136
+ .strand-kv + .strand-kv {
137
+ border-top: 1px solid var(--strand-border-subtle);
138
+ }
139
+
140
+ .strand-kv__label {
141
+ font-family: var(--strand-font-mono);
142
+ font-size: var(--strand-text-xs);
143
+ font-weight: var(--strand-weight-medium);
144
+ letter-spacing: var(--strand-tracking-wider);
145
+ text-transform: uppercase;
146
+ color: var(--strand-gray-500);
147
+ }
148
+
149
+ .strand-kv__value {
150
+ font-family: var(--strand-font-mono);
151
+ font-size: var(--strand-text-xs);
152
+ color: var(--strand-gray-600);
153
+ font-variant-numeric: tabular-nums;
154
+ }
155
+
156
+ .strand-kv__value--status {
157
+ color: var(--strand-teal-vital);
158
+ }
159
+
160
+ /* ── Diagnostic Log Entry ──
161
+ Derivation: inline-sequence + ranked-sequence (DL 11.10).
162
+ time(OVERLINE) + status(OVERLINE+COLOR_SEMANTIC) + text(SECONDARY) + RANK_BORDER */
163
+ .strand-log {
164
+ display: flex;
165
+ gap: var(--strand-space-3);
166
+ padding-block: var(--strand-space-2);
167
+ }
168
+
169
+ .strand-log + .strand-log {
170
+ border-top: 1px solid var(--strand-border-subtle);
171
+ }
172
+
173
+ .strand-log__time {
174
+ font-family: var(--strand-font-mono);
175
+ font-size: var(--strand-text-xs);
176
+ font-weight: var(--strand-weight-medium);
177
+ letter-spacing: var(--strand-tracking-wider);
178
+ text-transform: uppercase;
179
+ color: var(--strand-gray-400);
180
+ font-variant-numeric: tabular-nums;
181
+ white-space: nowrap;
182
+ }
183
+
184
+ .strand-log__status {
185
+ font-family: var(--strand-font-mono);
186
+ font-size: var(--strand-text-xs);
187
+ font-weight: var(--strand-weight-semibold);
188
+ letter-spacing: var(--strand-tracking-wider);
189
+ text-transform: uppercase;
190
+ white-space: nowrap;
191
+ }
192
+
193
+ .strand-log__status--complete { color: var(--strand-teal-vital); }
194
+ .strand-log__status--process { color: var(--strand-blue-primary); }
195
+ .strand-log__status--warning { color: var(--strand-amber-caution); }
196
+ .strand-log__status--error { color: var(--strand-red-alert); }
197
+
198
+ /* ── Metric Row ──
199
+ Derivation: centered-group (DL 11.10).
200
+ self-contained(atom)* with center distribution + responsive gap */
201
+ .strand-metric-row {
202
+ display: flex;
203
+ justify-content: center;
204
+ gap: clamp(2rem, 5vw, 4rem);
205
+ text-align: center;
206
+ }
207
+
208
+ /* ── Bar Chart ──
209
+ Derivation: column-array (DL 11.10).
210
+ column(amount? + bar + label)* with equal flex + flex-end alignment.
211
+ Blue Discipline: one color (--strand-blue-indicator). Part XIII viz rules. */
212
+ .strand-bar-chart {
213
+ display: flex;
214
+ gap: var(--strand-space-2);
215
+ align-items: flex-end;
216
+ height: var(--strand-space-24);
217
+ padding: var(--strand-space-5);
218
+ }
219
+
220
+ .strand-bar-chart__col {
221
+ flex: 1;
222
+ display: flex;
223
+ flex-direction: column;
224
+ align-items: center;
225
+ gap: var(--strand-space-1);
226
+ height: 100%;
227
+ justify-content: flex-end;
228
+ }
229
+
230
+ .strand-bar-chart__bar {
231
+ width: 100%;
232
+ background: var(--strand-blue-indicator);
233
+ border-radius: var(--strand-radius-sm) var(--strand-radius-sm) 0 0;
234
+ min-height: var(--strand-space-1);
235
+ }
236
+
237
+ .strand-bar-chart__amount {
238
+ font-family: var(--strand-font-mono);
239
+ font-size: var(--strand-text-xs);
240
+ font-weight: var(--strand-weight-medium);
241
+ letter-spacing: var(--strand-tracking-wider);
242
+ text-transform: uppercase;
243
+ color: var(--strand-gray-300);
244
+ font-variant-numeric: tabular-nums;
245
+ }
246
+
247
+ .strand-bar-chart__label {
248
+ font-family: var(--strand-font-mono);
249
+ font-size: var(--strand-text-xs);
250
+ font-weight: var(--strand-weight-medium);
251
+ letter-spacing: var(--strand-tracking-wider);
252
+ text-transform: uppercase;
253
+ color: var(--strand-gray-400);
254
+ }