@opendata-ai/openchart-core 7.11.0 → 8.0.0-rc.10

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 (59) hide show
  1. package/dist/index.d.ts +1348 -132
  2. package/dist/index.js +556 -48
  3. package/dist/index.js.map +1 -1
  4. package/dist/styles.css +2 -1
  5. package/dist/styles.css.map +1 -0
  6. package/package.json +9 -3
  7. package/schema/chart.schema.json +9086 -0
  8. package/schema/table.schema.json +861 -0
  9. package/schema/vizspec.schema.json +17922 -0
  10. package/src/accessibility/alt-text.ts +39 -1
  11. package/src/accessibility/aria.ts +4 -2
  12. package/src/colors/__tests__/colorblind.test.ts +12 -0
  13. package/src/colors/colorblind.ts +11 -2
  14. package/src/colors/contrast.ts +11 -0
  15. package/src/colors/index.ts +9 -1
  16. package/src/colors/palettes.ts +47 -0
  17. package/src/helpers/__tests__/deep-merge.test.ts +54 -0
  18. package/src/helpers/__tests__/spec-builders.test.ts +3 -3
  19. package/src/helpers/deep-merge.ts +29 -0
  20. package/src/helpers/spec-builders.ts +7 -7
  21. package/src/index.ts +29 -1
  22. package/src/labels/collision.ts +1 -0
  23. package/src/layout/chrome.ts +24 -0
  24. package/src/layout/index.ts +1 -1
  25. package/src/locale/__tests__/format.test.ts +347 -11
  26. package/src/locale/format.ts +243 -18
  27. package/src/locale/index.ts +10 -1
  28. package/src/responsive/breakpoints.ts +7 -2
  29. package/src/responsive/index.ts +2 -0
  30. package/src/responsive/metrics.ts +77 -10
  31. package/src/schema/__tests__/generated-artifacts.test.ts +42 -0
  32. package/src/schema/__tests__/schema.test.ts +179 -0
  33. package/src/styles/__tests__/reduced-motion-selectors.test.ts +28 -0
  34. package/src/styles/animation.css +211 -168
  35. package/src/styles/base.css +89 -62
  36. package/src/styles/chrome.css +173 -179
  37. package/src/styles/dark.css +38 -35
  38. package/src/styles/graph.css +116 -111
  39. package/src/styles/index.css +5 -0
  40. package/src/styles/keyframes.css +130 -99
  41. package/src/styles/legend.css +14 -12
  42. package/src/styles/reduced-motion.css +61 -40
  43. package/src/styles/series-search.css +153 -0
  44. package/src/styles/sparkline.css +14 -12
  45. package/src/styles/table-animation.css +82 -80
  46. package/src/styles/table.css +314 -302
  47. package/src/styles/token-definitions.ts +199 -0
  48. package/src/styles/tokens.css +132 -128
  49. package/src/styles/tooltip.css +109 -115
  50. package/src/styles/you-draw-it.css +126 -0
  51. package/src/types/__tests__/encoding.test.ts +86 -17
  52. package/src/types/__tests__/spec.test.ts +16 -12
  53. package/src/types/encoding.ts +69 -25
  54. package/src/types/events.ts +107 -13
  55. package/src/types/index.ts +42 -3
  56. package/src/types/layout.ts +484 -11
  57. package/src/types/schema-roots.ts +32 -0
  58. package/src/types/spec.ts +718 -87
  59. package/src/types/table.ts +3 -2
@@ -1,75 +1,102 @@
1
- /* ---------------------------------------------------------------------------
2
- * Wrapper roots
3
- * --------------------------------------------------------------------------- */
1
+ @layer oc.base {
2
+ /* ---------------------------------------------------------------------------
3
+ * Wrapper roots
4
+ * --------------------------------------------------------------------------- */
4
5
 
5
- .oc-chart-root {
6
- width: 100%;
7
- height: 100%;
8
- }
6
+ .oc-chart-root {
7
+ width: 100%;
8
+ height: 100%;
9
+ }
9
10
 
10
- .oc-table-root,
11
- .oc-graph-root,
12
- .oc-sankey-root,
13
- .oc-barlist-root {
14
- width: 100%;
15
- height: 100%;
16
- }
11
+ .oc-table-root,
12
+ .oc-graph-root,
13
+ .oc-sankey-root,
14
+ .oc-barlist-root,
15
+ .oc-tilemap-root,
16
+ .oc-map-root {
17
+ width: 100%;
18
+ height: 100%;
19
+ }
17
20
 
18
- .oc-tilemap-root {
19
- width: 100%;
20
- }
21
+ .oc-table-root {
22
+ overflow: auto;
23
+ }
21
24
 
22
- .oc-table-root {
23
- overflow: auto;
24
- }
25
+ /* ---------------------------------------------------------------------------
26
+ * Chart container
27
+ * --------------------------------------------------------------------------- */
25
28
 
26
- /* ---------------------------------------------------------------------------
27
- * Chart container
28
- * --------------------------------------------------------------------------- */
29
+ .oc-chart {
30
+ font-family: var(--oc-font-family);
31
+ display: block;
32
+ width: 100%;
33
+ }
29
34
 
30
- .oc-chart {
31
- font-family: var(--oc-font-family);
32
- display: block;
33
- width: 100%;
34
- }
35
+ /* ---------------------------------------------------------------------------
36
+ * BarList SVG container
37
+ * --------------------------------------------------------------------------- */
35
38
 
36
- /* ---------------------------------------------------------------------------
37
- * BarList SVG container
38
- * --------------------------------------------------------------------------- */
39
+ .oc-tilemap,
40
+ .oc-map {
41
+ display: block;
42
+ width: 100%;
43
+ height: auto;
44
+ }
39
45
 
40
- .oc-tilemap {
41
- display: block;
42
- width: 100%;
43
- height: auto;
44
- }
46
+ .oc-map-feature {
47
+ transition: opacity 400ms ease;
48
+ }
45
49
 
46
- .oc-barlist {
47
- display: block;
48
- width: 100%;
49
- }
50
+ .oc-barlist {
51
+ display: block;
52
+ width: 100%;
53
+ }
50
54
 
51
- /* ---------------------------------------------------------------------------
52
- * Screen reader only utility
53
- * --------------------------------------------------------------------------- */
54
-
55
- .oc-sr-only {
56
- position: absolute;
57
- width: 1px;
58
- height: 1px;
59
- padding: 0;
60
- margin: -1px;
61
- overflow: hidden;
62
- clip-path: inset(50%);
63
- white-space: nowrap;
64
- border-width: 0;
65
- }
55
+ /* ---------------------------------------------------------------------------
56
+ * Screen reader only utility
57
+ * --------------------------------------------------------------------------- */
58
+
59
+ .oc-sr-only {
60
+ position: absolute;
61
+ width: 1px;
62
+ height: 1px;
63
+ padding: 0;
64
+ margin: -1px;
65
+ overflow: hidden;
66
+ clip-path: inset(50%);
67
+ white-space: nowrap;
68
+ border-width: 0;
69
+ }
70
+
71
+ /* ---------------------------------------------------------------------------
72
+ * Editable hover feedback
73
+ * --------------------------------------------------------------------------- */
74
+
75
+ .oc-editable-hover {
76
+ outline: 1.5px solid var(--oc-editable-hover);
77
+ outline-offset: 2px;
78
+ border-radius: 2px;
79
+ }
80
+
81
+ /* ---------------------------------------------------------------------------
82
+ * Keyboard focus indicators
83
+ *
84
+ * --oc-focus carries a light value in tokens.css and a dark value in
85
+ * dark.css, so both rings stay visible in either mode.
86
+ * --------------------------------------------------------------------------- */
66
87
 
67
- /* ---------------------------------------------------------------------------
68
- * Editable hover feedback
69
- * --------------------------------------------------------------------------- */
88
+ /* Container ring when the chart itself receives keyboard focus. */
89
+ .oc-root:focus-visible {
90
+ outline: 2px solid var(--oc-focus);
91
+ outline-offset: 2px;
92
+ }
70
93
 
71
- .oc-editable-hover {
72
- outline: 1.5px solid rgba(79, 70, 229, 0.35);
73
- outline-offset: 2px;
74
- border-radius: 2px;
94
+ /* Mark ring during arrow-key navigation (see wireKeyboardNav). Outline on
95
+ * SVG elements draws around the mark's bounding box, same technique as
96
+ * .oc-editable-hover above. */
97
+ .oc-mark-focused {
98
+ outline: 2px solid var(--oc-focus);
99
+ outline-offset: 1px;
100
+ border-radius: 2px;
101
+ }
75
102
  }
@@ -1,180 +1,174 @@
1
- /* ---------------------------------------------------------------------------
2
- * Chrome (eyebrow, title, subtitle, source, byline, footer, brand)
3
- * --------------------------------------------------------------------------- */
4
-
5
- .oc-chrome {
6
- font-family: var(--oc-font-family);
7
- }
8
-
9
- .oc-eyebrow {
10
- font-size: var(--oc-eyebrow-size);
11
- font-weight: var(--oc-eyebrow-weight);
12
- letter-spacing: var(--oc-eyebrow-tracking);
13
- text-transform: uppercase;
14
- fill: var(--oc-accent);
15
- }
16
-
17
- .oc-title {
18
- font-size: var(--oc-title-size);
19
- font-weight: var(--oc-title-weight);
20
- letter-spacing: var(--oc-title-tracking);
21
- fill: var(--oc-text);
22
- }
23
-
24
- .oc-subtitle {
25
- font-size: var(--oc-subtitle-size);
26
- font-weight: var(--oc-subtitle-weight);
27
- fill: var(--oc-text-muted);
28
- }
29
-
30
- .oc-source,
31
- .oc-byline,
32
- .oc-footer {
33
- font-size: var(--oc-source-size);
34
- font-weight: var(--oc-source-weight);
35
- fill: var(--oc-text-muted);
36
- }
37
-
38
- .oc-brand {
39
- font-size: 11px;
40
- font-weight: 510;
41
- letter-spacing: 0.02em;
42
- fill: var(--oc-text-faint);
43
- }
44
-
45
- .oc-brand-dot {
46
- fill: var(--oc-accent);
47
- }
48
-
49
- .oc-eyebrow-dot {
50
- fill: var(--oc-accent);
51
- }
52
-
53
- /* ---------------------------------------------------------------------------
54
- * Metric bar (.oc-metrics) — optional row of label/value cells above chart
55
- * --------------------------------------------------------------------------- */
56
-
57
- .oc-metrics {
58
- font-family: var(--oc-font-family);
59
- }
60
-
61
- .oc-metric-label {
62
- font-size: 10px;
63
- font-weight: 510;
64
- letter-spacing: 0.08em;
65
- text-transform: uppercase;
66
- fill: var(--oc-text-muted);
67
- }
68
-
69
- .oc-metric-value {
70
- font-size: 22px;
71
- font-weight: 510;
72
- letter-spacing: -0.01em;
73
- fill: var(--oc-text);
74
- font-variant-numeric: tabular-nums;
75
- }
76
-
77
- .oc-metric-delta-up {
78
- fill: var(--oc-positive);
79
- font-size: 12px;
80
- font-weight: 510;
81
- }
82
-
83
- .oc-metric-delta-down {
84
- fill: var(--oc-negative);
85
- font-size: 12px;
86
- font-weight: 510;
87
- }
88
-
89
- .oc-metric-secondary {
90
- fill: var(--oc-positive);
91
- font-size: 12px;
92
- font-weight: 400;
93
- }
94
-
95
- /* ---------------------------------------------------------------------------
96
- * Axis tick labels — inline variant sits above each gridline at the
97
- * chart-area left edge (no left gutter). Used by line/area y-axes.
98
- * --------------------------------------------------------------------------- */
99
-
100
- .oc-axis-tick-inline {
101
- font-size: 11px;
102
- font-weight: 400;
103
- fill: var(--oc-text-muted);
104
- }
105
-
106
- /* ---------------------------------------------------------------------------
107
- * Endpoint labels (right-side per-series column for line/area charts)
108
- *
109
- * Swatch idiom: a thicker colored stroke segment with an optional thinner
110
- * lighter strip below. Mirrors the refreshed traditional legend swatch so a
111
- * single chart never shows two swatch idioms (mock-2 alignment). Per-series
112
- * color is stamped inline by the renderer; CSS tokens here cover the muted
113
- * value text and the leader line so theme overrides flow through naturally.
114
- * --------------------------------------------------------------------------- */
115
-
116
- .oc-endpoint-labels {
117
- font-family: var(--oc-font-family);
118
- }
119
-
120
- .oc-endpoint-label {
121
- /* Color set inline per series; this fallback only kicks in if the renderer
122
- ever omits the inline fill. */
123
- fill: var(--oc-endpoint-label-color, var(--oc-text));
124
- }
125
-
126
- .oc-endpoint-value {
127
- fill: var(--oc-endpoint-value-color, var(--oc-text-muted));
128
- }
129
-
130
- .oc-endpoint-leader {
131
- stroke: var(--oc-endpoint-leader-color, currentColor);
132
- }
133
-
134
- .oc-endpoint-marker {
135
- /* Fill/stroke set inline (open-ring style: bg fill, series stroke). */
136
- }
137
-
138
- .oc-endpoint-swatch {
139
- /* Color set inline per series. */
140
- }
141
-
142
- /* ---------------------------------------------------------------------------
143
- * Annotation dot + subtitle (text-annotation extensions)
144
- * --------------------------------------------------------------------------- */
145
-
146
- .oc-annotation-dot {
147
- /* Fill/stroke resolved by the engine. Open-ring default = bg fill, series
148
- stroke. */
149
- }
150
-
151
- .oc-annotation-subtitle {
152
- fill: var(--oc-annotation-subtitle-color, var(--oc-text-muted));
153
- }
154
-
155
- /* ---------------------------------------------------------------------------
156
- * Table footer chrome
157
- * --------------------------------------------------------------------------- */
158
-
159
- /* Footer row: source/footer text on the left, brand watermark on the right,
160
- * sharing a single baseline. gap keeps them apart if the row gets narrow. */
161
- .oc-table-footer-row {
162
- display: flex;
163
- align-items: baseline;
164
- gap: 16px;
165
- padding: 16px 16px 4px;
166
- }
167
-
168
- /* Chrome block sits inside the flex row now, so it no longer owns the
169
- * footer's top padding or horizontal inset (the row provides both). */
170
- .oc-chrome-footer {
171
- padding-top: 0;
172
- }
173
-
174
- /* Brand watermark: pushed to the right edge (margin-left:auto holds it there
175
- * even when the source text is absent), never shrinks below its own text. */
176
- .oc-table-footer-row .oc-table-ref {
177
- margin-left: auto;
178
- flex-shrink: 0;
179
- text-align: right;
1
+ @layer oc.components {
2
+ /* ---------------------------------------------------------------------------
3
+ * Chrome (eyebrow, title, subtitle, source, byline, footer, brand)
4
+ * --------------------------------------------------------------------------- */
5
+
6
+ .oc-chrome {
7
+ font-family: var(--oc-font-family);
8
+ }
9
+
10
+ .oc-eyebrow {
11
+ font-size: var(--oc-eyebrow-size);
12
+ font-weight: var(--oc-eyebrow-weight);
13
+ letter-spacing: var(--oc-eyebrow-tracking);
14
+ text-transform: uppercase;
15
+ fill: var(--oc-accent);
16
+ }
17
+
18
+ .oc-title {
19
+ font-size: var(--oc-title-size);
20
+ font-weight: var(--oc-title-weight);
21
+ letter-spacing: var(--oc-title-tracking);
22
+ fill: var(--oc-text);
23
+ }
24
+
25
+ .oc-subtitle {
26
+ font-size: var(--oc-subtitle-size);
27
+ font-weight: var(--oc-subtitle-weight);
28
+ fill: var(--oc-text-muted);
29
+ }
30
+
31
+ .oc-source,
32
+ .oc-byline,
33
+ .oc-footer {
34
+ font-size: var(--oc-source-size);
35
+ font-weight: var(--oc-source-weight);
36
+ fill: var(--oc-text-muted);
37
+ }
38
+
39
+ .oc-brand {
40
+ font-size: 11px;
41
+ font-weight: 510;
42
+ letter-spacing: 0.02em;
43
+ fill: var(--oc-text-faint);
44
+ }
45
+
46
+ .oc-brand-dot {
47
+ fill: var(--oc-accent);
48
+ }
49
+
50
+ .oc-eyebrow-dot {
51
+ fill: var(--oc-accent);
52
+ }
53
+
54
+ /* ---------------------------------------------------------------------------
55
+ * Metric bar (.oc-metrics) — optional row of label/value cells above chart
56
+ * --------------------------------------------------------------------------- */
57
+
58
+ .oc-metrics {
59
+ font-family: var(--oc-font-family);
60
+ }
61
+
62
+ .oc-metric-label {
63
+ font-size: 10px;
64
+ font-weight: 510;
65
+ letter-spacing: 0.08em;
66
+ text-transform: uppercase;
67
+ fill: var(--oc-text-muted);
68
+ }
69
+
70
+ .oc-metric-value {
71
+ font-size: 22px;
72
+ font-weight: 510;
73
+ letter-spacing: -0.01em;
74
+ fill: var(--oc-text);
75
+ font-variant-numeric: tabular-nums;
76
+ }
77
+
78
+ .oc-metric-delta-up {
79
+ fill: var(--oc-positive);
80
+ font-size: 12px;
81
+ font-weight: 510;
82
+ }
83
+
84
+ .oc-metric-delta-down {
85
+ fill: var(--oc-negative);
86
+ font-size: 12px;
87
+ font-weight: 510;
88
+ }
89
+
90
+ .oc-metric-secondary {
91
+ fill: var(--oc-positive);
92
+ font-size: 12px;
93
+ font-weight: 400;
94
+ }
95
+
96
+ /* ---------------------------------------------------------------------------
97
+ * Axis tick labels — inline variant sits above each gridline at the
98
+ * chart-area left edge (no left gutter). Used by line/area y-axes.
99
+ * --------------------------------------------------------------------------- */
100
+
101
+ .oc-axis-tick-inline {
102
+ font-size: 11px;
103
+ font-weight: 400;
104
+ fill: var(--oc-text-muted);
105
+ }
106
+
107
+ /* ---------------------------------------------------------------------------
108
+ * Endpoint labels (right-side per-series column for line/area charts)
109
+ *
110
+ * Swatch idiom: a thicker colored stroke segment with an optional thinner
111
+ * lighter strip below. Mirrors the refreshed traditional legend swatch so a
112
+ * single chart never shows two swatch idioms (mock-2 alignment). Per-series
113
+ * color is stamped inline by the renderer; CSS tokens here cover the muted
114
+ * value text and the leader line so theme overrides flow through naturally.
115
+ * --------------------------------------------------------------------------- */
116
+
117
+ .oc-endpoint-labels {
118
+ font-family: var(--oc-font-family);
119
+ }
120
+
121
+ .oc-endpoint-label {
122
+ /* Color set inline per series; this fallback only kicks in if the renderer
123
+ ever omits the inline fill. */
124
+ fill: var(--oc-endpoint-label-color, var(--oc-text));
125
+ }
126
+
127
+ .oc-endpoint-value {
128
+ fill: var(--oc-endpoint-value-color, var(--oc-text-muted));
129
+ }
130
+
131
+ .oc-endpoint-leader {
132
+ stroke: var(--oc-endpoint-leader-color, currentColor);
133
+ }
134
+
135
+ /* .oc-endpoint-marker — fill/stroke set inline (open-ring style: bg fill, series stroke). */
136
+ /* .oc-endpoint-swatch — color set inline per series. */
137
+
138
+ /* ---------------------------------------------------------------------------
139
+ * Annotation dot + subtitle (text-annotation extensions)
140
+ * --------------------------------------------------------------------------- */
141
+
142
+ /* .oc-annotation-dot — fill/stroke resolved by the engine (open-ring default = bg fill, series stroke). */
143
+
144
+ .oc-annotation-subtitle {
145
+ fill: var(--oc-annotation-subtitle-color, var(--oc-text-muted));
146
+ }
147
+
148
+ /* ---------------------------------------------------------------------------
149
+ * Table footer chrome
150
+ * --------------------------------------------------------------------------- */
151
+
152
+ /* Footer row: source/footer text on the left, brand watermark on the right,
153
+ * sharing a single baseline. gap keeps them apart if the row gets narrow. */
154
+ .oc-table-footer-row {
155
+ display: flex;
156
+ align-items: baseline;
157
+ gap: 16px;
158
+ padding: 16px 16px 4px;
159
+ }
160
+
161
+ /* Chrome block sits inside the flex row now, so it no longer owns the
162
+ * footer's top padding or horizontal inset (the row provides both). */
163
+ .oc-chrome-footer {
164
+ padding-top: 0;
165
+ }
166
+
167
+ /* Brand watermark: pushed to the right edge (margin-left:auto holds it there
168
+ * even when the source text is absent), never shrinks below its own text. */
169
+ .oc-table-footer-row .oc-table-ref {
170
+ margin-left: auto;
171
+ flex-shrink: 0;
172
+ text-align: right;
173
+ }
180
174
  }
@@ -1,41 +1,44 @@
1
- /* ---------------------------------------------------------------------------
2
- * Dark mode overrides (fallback defaults)
3
- *
4
- * At runtime, the JS theme engine stamps dark-adapted --oc-* custom
5
- * properties on each .oc-root container. These CSS values serve as
6
- * fallbacks for contexts where JS hasn't mounted yet.
7
- * --------------------------------------------------------------------------- */
1
+ /* GENERATED FILE — do not edit. Source: packages/core/src/styles/token-definitions.ts. Regenerate: bun run generate:tokens */
8
2
 
9
- .oc-dark {
10
- /* Surfaces (zinc-based achromatic ramp) */
11
- --oc-bg: #09090b;
12
- --oc-card: #111113;
13
- --oc-secondary: #27272a;
3
+ @layer oc.tokens {
4
+ /* ---------------------------------------------------------------------------
5
+ * Dark mode overrides (fallback defaults)
6
+ *
7
+ * At runtime, the JS theme engine stamps dark-adapted --oc-* custom
8
+ * properties on each .oc-root container. These CSS values serve as
9
+ * fallbacks for contexts where JS hasn't mounted yet.
10
+ * --------------------------------------------------------------------------- */
14
11
 
15
- /* Text levels — see tokens.css for the cross-mode naming rationale */
16
- --oc-text: #f7f8f8;
17
- --oc-text-secondary: #d0d6e0;
18
- --oc-text-muted: #a1a1aa;
19
- --oc-text-subtle: #71717a;
20
- --oc-text-faint: #52525b;
12
+ .oc-dark {
13
+ /* Surfaces (zinc-based achromatic ramp) */
14
+ --oc-bg: #09090b;
15
+ --oc-card: #111113;
16
+ --oc-secondary: #27272a;
21
17
 
22
- /* Lines */
23
- --oc-gridline: rgba(255, 255, 255, 0.05);
24
- --oc-axis: rgba(255, 255, 255, 0.1);
25
- --oc-border: rgba(255, 255, 255, 0.1);
18
+ /* Text levels — see tokens.css for the cross-mode naming rationale */
19
+ --oc-text: #f7f8f8;
20
+ --oc-text-secondary: #d0d6e0;
21
+ --oc-text-muted: #a1a1aa;
22
+ --oc-text-faint: #52525b;
26
23
 
27
- /* Brand and semantic — accent stays cyan (no darkening on dark bg) */
28
- --oc-accent: #06b6d4;
29
- --oc-accent-strong: #06b6d4;
30
- --oc-positive: #34d399;
31
- --oc-negative: #fb7185;
32
- --oc-focus: #60a5fa;
24
+ /* Lines */
25
+ --oc-gridline: rgba(255, 255, 255, 0.05);
26
+ --oc-axis: rgba(255, 255, 255, 0.1);
27
+ --oc-border: rgba(255, 255, 255, 0.1);
33
28
 
34
- /* Interactive states */
35
- --oc-hover-bg: rgba(255, 255, 255, 0.05);
36
- --oc-tooltip-bg: rgba(17, 17, 19, 0.92);
37
- --oc-tooltip-border: rgba(255, 255, 255, 0.08);
38
- --oc-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.3), 0 0 1px rgba(0, 0, 0, 0.4);
39
- --oc-tooltip-text: #f7f8f8;
40
- --oc-legend-text: #d0d6e0;
29
+ /* Brand and semantic — accent stays cyan (no darkening on dark bg) */
30
+ --oc-accent: #06b6d4;
31
+ --oc-accent-strong: #06b6d4;
32
+ --oc-positive: #34d399;
33
+ --oc-negative: #fb7185;
34
+ --oc-focus: #60a5fa;
35
+
36
+ /* Interactive states */
37
+ --oc-hover-bg: rgba(255, 255, 255, 0.05);
38
+ --oc-tooltip-bg: rgba(17, 17, 19, 0.92);
39
+ --oc-tooltip-border: rgba(255, 255, 255, 0.08);
40
+ --oc-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.3), 0 0 1px rgba(0, 0, 0, 0.4);
41
+ --oc-tooltip-text: #f7f8f8;
42
+ --oc-legend-text: #d0d6e0;
43
+ }
41
44
  }