@skygraph/styles 0.1.0 → 0.2.1

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.
@@ -1,4 +1,25 @@
1
+ /* Checkbox — custom box element on top of a visually-hidden native input.
2
+ *
3
+ * The native `<input type="checkbox">` is kept in the DOM (for keyboard,
4
+ * form-association, accessibility, indeterminate) but visually hidden.
5
+ * A sibling `.sg-checkbox-box` element paints the actual UI so demos
6
+ * can rebrand through dedicated `--sg-checkbox-*` tokens without
7
+ * fighting the browser's `accent-color` limitations.
8
+ */
9
+
1
10
  .sg-checkbox {
11
+ /* Component-local tokens. Override these (not the globals) to rebrand
12
+ * one group of checkboxes — keeps `--sg-color-primary` intact for the
13
+ * rest of the page. */
14
+ --sg-checkbox-size: 16px;
15
+ --sg-checkbox-radius: 4px;
16
+ --sg-checkbox-border: var(--sg-color-border);
17
+ --sg-checkbox-border-hover: var(--sg-color-primary);
18
+ --sg-checkbox-bg: var(--sg-color-bg);
19
+ --sg-checkbox-bg-checked: var(--sg-color-primary);
20
+ --sg-checkbox-color-checked: var(--sg-color-white);
21
+
22
+ position: relative;
2
23
  display: inline-flex;
3
24
  align-items: center;
4
25
  gap: var(--sg-padding-sm);
@@ -13,11 +34,75 @@
13
34
  cursor: not-allowed;
14
35
  }
15
36
 
37
+ /* Visually hide the native checkbox but keep it focusable & screen-
38
+ * readable. Pointer events are forwarded to the wrapping <label>. */
16
39
  .sg-checkbox-input {
17
- width: 16px;
18
- height: 16px;
19
- accent-color: var(--sg-color-primary);
20
- cursor: inherit;
40
+ position: absolute;
41
+ width: var(--sg-checkbox-size);
42
+ height: var(--sg-checkbox-size);
43
+ margin: 0;
44
+ opacity: 0;
45
+ pointer-events: none;
46
+ }
47
+
48
+ .sg-checkbox-box {
49
+ position: relative;
50
+ flex-shrink: 0;
51
+ display: inline-block;
52
+ width: var(--sg-checkbox-size);
53
+ height: var(--sg-checkbox-size);
54
+ border: 1px solid var(--sg-checkbox-border);
55
+ border-radius: var(--sg-checkbox-radius);
56
+ background: var(--sg-checkbox-bg);
57
+ transition:
58
+ background var(--sg-transition-duration) var(--sg-transition-timing),
59
+ border-color var(--sg-transition-duration) var(--sg-transition-timing);
60
+ }
61
+
62
+ .sg-checkbox:hover .sg-checkbox-box {
63
+ border-color: var(--sg-checkbox-border-hover);
64
+ }
65
+
66
+ .sg-checkbox-input:focus-visible ~ .sg-checkbox-box {
67
+ outline: 2px solid var(--sg-color-primary);
68
+ outline-offset: 2px;
69
+ }
70
+
71
+ .sg-checkbox-input:checked ~ .sg-checkbox-box,
72
+ .sg-checkbox-input:indeterminate ~ .sg-checkbox-box {
73
+ background: var(--sg-checkbox-bg-checked);
74
+ border-color: var(--sg-checkbox-bg-checked);
75
+ }
76
+
77
+ /* Tick (checked) */
78
+ .sg-checkbox-input:checked ~ .sg-checkbox-box::after {
79
+ content: '';
80
+ position: absolute;
81
+ left: 5px;
82
+ top: 1px;
83
+ width: 5px;
84
+ height: 9px;
85
+ border: solid var(--sg-checkbox-color-checked);
86
+ border-width: 0 2px 2px 0;
87
+ transform: rotate(45deg);
88
+ }
89
+
90
+ /* Bar (indeterminate) */
91
+ .sg-checkbox-input:indeterminate ~ .sg-checkbox-box::after {
92
+ content: '';
93
+ position: absolute;
94
+ left: 3px;
95
+ right: 3px;
96
+ top: 50%;
97
+ height: 2px;
98
+ background: var(--sg-checkbox-color-checked);
99
+ transform: translateY(-50%);
100
+ }
101
+
102
+ .sg-checkbox-disabled .sg-checkbox-box {
103
+ background: var(--sg-color-bg-disabled, var(--sg-color-bg-secondary));
104
+ border-color: var(--sg-color-border);
105
+ opacity: 0.6;
21
106
  }
22
107
 
23
108
  .sg-checkbox-label {
@@ -220,13 +220,17 @@
220
220
 
221
221
  .sg-diagram-edge {
222
222
  stroke: var(--sg-diagram-edge-color);
223
- stroke-width: 1.75;
223
+ stroke-width: 1.5;
224
224
  fill: none;
225
- /* `linejoin` keeps orthogonal-routed edges crisp at corners; `linecap`
226
- * rounds the start/end so an edge feels finished where it meets the
227
- * node border instead of clipping abruptly. */
225
+ /* `linejoin: round` smooths orthogonal corners. `linecap: butt`
226
+ * means the path tip ends flush combined with the marker-end
227
+ * sitting at `refX/refY = 0`, the arrow glyph picks up exactly
228
+ * where the line stops, with no visible "pill" cap protruding
229
+ * beyond the arrowhead. Round caps used to leak a half-circle
230
+ * over the marker base and that was visible on every screenshot
231
+ * the user shared. */
228
232
  stroke-linejoin: round;
229
- stroke-linecap: round;
233
+ stroke-linecap: butt;
230
234
  transition:
231
235
  stroke var(--sg-transition-fast),
232
236
  stroke-width var(--sg-transition-fast);
@@ -236,7 +240,7 @@
236
240
  * naturally thins at the inflection point, which makes the same
237
241
  * stroke-width look lighter than its orthogonal counterpart. */
238
242
  .sg-diagram-edge-bezier {
239
- stroke-width: 2;
243
+ stroke-width: 1.75;
240
244
  }
241
245
 
242
246
  /* Dashed for manual-routed waypoints — visually distinguishes a hand-
@@ -248,7 +252,7 @@
248
252
  .sg-diagram-edge-hit:hover + .sg-diagram-edge,
249
253
  g[data-edge-id]:hover .sg-diagram-edge {
250
254
  stroke: var(--sg-diagram-edge-hover-stroke);
251
- stroke-width: 2.5;
255
+ stroke-width: 2.25;
252
256
  }
253
257
 
254
258
  /* Highlight edges connected to a selected node when the selection is
@@ -257,26 +261,35 @@ g[data-edge-id]:hover .sg-diagram-edge {
257
261
  * `selected` color on `:focus-within` of the SVG group. */
258
262
  g[data-edge-id]:focus-within .sg-diagram-edge {
259
263
  stroke: var(--sg-diagram-edge-color-selected);
260
- stroke-width: 2.5;
264
+ stroke-width: 2.25;
261
265
  }
262
266
 
263
267
  /* ─── Arrow markers ─────────────────────────────────────────────────── */
264
268
  /*
265
- * SVG markers don't inherit `stroke` from the path automatically the
266
- * `context-stroke` keyword in the marker `fill` solves it where
267
- * supported, and the fallback below keeps Firefox / Safari < TP rendering
268
- * the arrow in the right colour by using `currentColor`.
269
+ * The arrowhead is an "open V" two strokes meeting at the marker
270
+ * anchor, not a filled triangle. That gives the arrow visual cohesion
271
+ * with the line (same stroke), keeps it readable on dense graphs, and
272
+ * matches the look used by React Flow / draw.io / Lucidchart.
269
273
  *
270
- * `.sg-diagram-edges` carries `currentColor` from the token so the arrow
271
- * inherits the default colour; per-state overrides (`:hover`) below adjust
272
- * `currentColor` so the arrow lights up together with the line.
274
+ * SVG markers don't inherit `stroke` from the path automatically. We
275
+ * use `context-stroke` in the marker so modern browsers paint the arrow
276
+ * with the line colour, and rely on `currentColor` below as a fallback
277
+ * for Firefox / Safari versions that don't yet support context-stroke.
278
+ *
279
+ * `.sg-diagram-edges { color: ... }` is the lever per-edge state hooks
280
+ * (`:hover`) modulate so the arrow lights up together with the line.
273
281
  */
274
282
  .sg-diagram-edges {
275
283
  color: var(--sg-diagram-edge-color);
276
284
  }
277
285
 
286
+ /* Marker glyph: stroke takes the inherited `currentColor` so old
287
+ * browsers without context-stroke still render the arrow in the right
288
+ * colour. `fill: none` is essential — the marker is an open polyline,
289
+ * not a triangle. */
278
290
  .sg-diagram-arrow-fill {
279
- fill: currentColor;
291
+ stroke: currentColor;
292
+ fill: none;
280
293
  }
281
294
 
282
295
  g[data-edge-id]:hover {
@@ -51,6 +51,11 @@
51
51
  color: var(--sg-color-text-secondary);
52
52
  border-right: 1px solid var(--sg-color-border-secondary);
53
53
  box-sizing: border-box;
54
+ /* Clip the label when the tick is narrower than the rendered text
55
+ * (e.g. day scale with columnWidth=24) — without this, adjacent
56
+ * labels visually pile up on each other. */
57
+ overflow: hidden;
58
+ white-space: nowrap;
54
59
  }
55
60
 
56
61
  .sg-gantt-grid {
@@ -123,7 +128,7 @@
123
128
  /* Drop-shadow on the text increases legibility on saturated bar
124
129
  * fills (esp. the bright primary blue). Cheap, single-line filter
125
130
  * that doesn't disturb the bar background. */
126
- text-shadow: 0 1px 1px rgba(0, 0, 0, 0.20);
131
+ text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
127
132
  }
128
133
 
129
134
  .sg-gantt-bar-resize {
@@ -23,7 +23,8 @@
23
23
  background: var(--sg-input-bg);
24
24
  border: 1px solid var(--sg-input-border);
25
25
  border-radius: var(--sg-input-radius);
26
- transition: color var(--sg-transition-duration) var(--sg-transition-timing),
26
+ transition:
27
+ color var(--sg-transition-duration) var(--sg-transition-timing),
27
28
  background var(--sg-transition-duration) var(--sg-transition-timing),
28
29
  border-color var(--sg-transition-duration) var(--sg-transition-timing),
29
30
  box-shadow var(--sg-transition-duration) var(--sg-transition-timing);
@@ -108,3 +109,77 @@
108
109
  bottom: 0;
109
110
  margin: auto 0;
110
111
  }
112
+
113
+ /* ---- Prefix / Suffix ---- */
114
+ .sg-input-prefix,
115
+ .sg-input-suffix {
116
+ display: inline-flex;
117
+ align-items: center;
118
+ justify-content: center;
119
+ color: var(--sg-color-text-secondary);
120
+ pointer-events: none;
121
+ }
122
+
123
+ .sg-input-prefix {
124
+ position: absolute;
125
+ left: var(--sg-padding-sm);
126
+ top: 0;
127
+ bottom: 0;
128
+ }
129
+
130
+ .sg-input-suffix {
131
+ position: absolute;
132
+ right: var(--sg-padding-sm);
133
+ top: 0;
134
+ bottom: 0;
135
+ }
136
+
137
+ .sg-input-wrapper:has(.sg-input-prefix) .sg-input {
138
+ padding-left: calc(var(--sg-padding-md) + 16px);
139
+ }
140
+
141
+ .sg-input-wrapper:has(.sg-input-suffix) .sg-input {
142
+ padding-right: calc(var(--sg-padding-md) + 16px);
143
+ }
144
+
145
+ /* ---- Clear button ---- */
146
+ .sg-input-wrapper:has(.sg-input-clear) .sg-input {
147
+ padding-right: calc(var(--sg-padding-md) + 18px);
148
+ }
149
+
150
+ .sg-input-clear {
151
+ position: absolute;
152
+ right: var(--sg-padding-xs);
153
+ top: 50%;
154
+ transform: translateY(-50%);
155
+ display: inline-flex;
156
+ align-items: center;
157
+ justify-content: center;
158
+ width: 18px;
159
+ height: 18px;
160
+ padding: 0;
161
+ margin: 0;
162
+ border: none;
163
+ border-radius: 50%;
164
+ background: var(--sg-color-fill-tertiary);
165
+ color: var(--sg-color-text-secondary);
166
+ font-size: 14px;
167
+ line-height: 1;
168
+ cursor: pointer;
169
+ opacity: 0.7;
170
+ transition:
171
+ background var(--sg-transition-duration) var(--sg-transition-timing),
172
+ color var(--sg-transition-duration) var(--sg-transition-timing),
173
+ opacity var(--sg-transition-duration) var(--sg-transition-timing);
174
+ }
175
+
176
+ .sg-input-clear:hover {
177
+ background: var(--sg-color-fill);
178
+ color: var(--sg-color-text);
179
+ opacity: 1;
180
+ }
181
+
182
+ .sg-input-clear:focus-visible {
183
+ outline: 2px solid var(--sg-color-primary);
184
+ outline-offset: 2px;
185
+ }
@@ -1,3 +1,10 @@
1
+ /* Radio — custom painted dot on top of a visually-hidden native input.
2
+ *
3
+ * Like Checkbox, the native `<input type="radio">` stays in the DOM for
4
+ * keyboard / form / a11y but is visually hidden. `.sg-radio-box` paints
5
+ * the circle so demos can rebrand through `--sg-radio-*` tokens without
6
+ * fighting `accent-color` limitations across browsers. */
7
+
1
8
  .sg-radio-group {
2
9
  display: flex;
3
10
  gap: var(--sg-padding-md);
@@ -8,12 +15,21 @@
8
15
  }
9
16
 
10
17
  .sg-radio {
18
+ --sg-radio-size: 16px;
19
+ --sg-radio-border: var(--sg-color-border);
20
+ --sg-radio-border-hover: var(--sg-color-primary);
21
+ --sg-radio-bg: var(--sg-color-bg);
22
+ --sg-radio-bg-checked: var(--sg-color-primary);
23
+ --sg-radio-dot-color: var(--sg-color-white);
24
+
25
+ position: relative;
11
26
  display: inline-flex;
12
27
  align-items: center;
13
28
  gap: var(--sg-padding-xs);
14
29
  cursor: pointer;
15
30
  font-size: var(--sg-font-size);
16
31
  color: var(--sg-color-text);
32
+ line-height: var(--sg-line-height);
17
33
  }
18
34
 
19
35
  .sg-radio-disabled {
@@ -22,11 +38,52 @@
22
38
  }
23
39
 
24
40
  .sg-radio-input {
25
- width: 16px;
26
- height: 16px;
41
+ position: absolute;
42
+ width: var(--sg-radio-size);
43
+ height: var(--sg-radio-size);
27
44
  margin: 0;
28
- accent-color: var(--sg-color-primary);
29
- cursor: inherit;
45
+ opacity: 0;
46
+ pointer-events: none;
47
+ }
48
+
49
+ .sg-radio-box {
50
+ position: relative;
51
+ flex-shrink: 0;
52
+ display: inline-block;
53
+ width: var(--sg-radio-size);
54
+ height: var(--sg-radio-size);
55
+ border: 1px solid var(--sg-radio-border);
56
+ border-radius: 50%;
57
+ background: var(--sg-radio-bg);
58
+ transition:
59
+ background var(--sg-transition-duration) var(--sg-transition-timing),
60
+ border-color var(--sg-transition-duration) var(--sg-transition-timing);
61
+ }
62
+
63
+ .sg-radio:hover .sg-radio-box {
64
+ border-color: var(--sg-radio-border-hover);
65
+ }
66
+
67
+ .sg-radio-input:focus-visible ~ .sg-radio-box {
68
+ outline: 2px solid var(--sg-color-primary);
69
+ outline-offset: 2px;
70
+ }
71
+
72
+ .sg-radio-input:checked ~ .sg-radio-box {
73
+ background: var(--sg-radio-bg-checked);
74
+ border-color: var(--sg-radio-bg-checked);
75
+ }
76
+
77
+ .sg-radio-input:checked ~ .sg-radio-box::after {
78
+ content: '';
79
+ position: absolute;
80
+ top: 50%;
81
+ left: 50%;
82
+ width: 6px;
83
+ height: 6px;
84
+ border-radius: 50%;
85
+ background: var(--sg-radio-dot-color);
86
+ transform: translate(-50%, -50%);
30
87
  }
31
88
 
32
89
  .sg-radio-label {
@@ -71,6 +71,11 @@
71
71
  .sg-rcal-main {
72
72
  background: var(--sg-color-bg);
73
73
  position: relative;
74
+ /* Clip absolutely positioned blocks (assignments / ticks) so they
75
+ * can't bleed onto the sidebar when their dates fall outside the
76
+ * visible `range`. Interactive drag also clamps to range, so this
77
+ * is a safety net for props-supplied out-of-range assignments. */
78
+ overflow: hidden;
74
79
  }
75
80
 
76
81
  .sg-rcal-header {
@@ -183,7 +188,7 @@
183
188
  transform: none;
184
189
  box-shadow:
185
190
  0 0 0 1px var(--sg-rcal-conflict-color),
186
- 0 2px 6px rgba(245, 34, 45, 0.20);
191
+ 0 2px 6px rgba(245, 34, 45, 0.2);
187
192
  }
188
193
 
189
194
  .sg-rcal-assignment-draggable {
@@ -75,7 +75,9 @@
75
75
  .sg-sfe-body {
76
76
  display: grid;
77
77
  grid-template-columns: var(--sg-sfe-palette-width) 1fr var(--sg-sfe-inspector-width);
78
+ flex: 1;
78
79
  min-height: 480px;
80
+ overflow: hidden;
79
81
  }
80
82
 
81
83
  /* Palette (left) ---------------------------------------------------------- */
@@ -113,7 +115,8 @@
113
115
  border-radius: var(--sg-sfe-radius);
114
116
  cursor: grab;
115
117
  user-select: none;
116
- transition: border-color var(--sg-transition-duration) var(--sg-transition-timing),
118
+ transition:
119
+ border-color var(--sg-transition-duration) var(--sg-transition-timing),
117
120
  box-shadow var(--sg-transition-duration) var(--sg-transition-timing);
118
121
  }
119
122
 
@@ -162,6 +165,8 @@
162
165
  display: flex;
163
166
  flex-direction: column;
164
167
  min-width: 0;
168
+ min-height: 0;
169
+ overflow: hidden;
165
170
  background: var(--sg-sfe-bg);
166
171
  }
167
172
 
@@ -204,7 +209,8 @@
204
209
  border: 1px solid transparent;
205
210
  border-radius: var(--sg-sfe-radius);
206
211
  cursor: pointer;
207
- transition: border-color var(--sg-transition-duration) var(--sg-transition-timing),
212
+ transition:
213
+ border-color var(--sg-transition-duration) var(--sg-transition-timing),
208
214
  background var(--sg-transition-duration) var(--sg-transition-timing);
209
215
  }
210
216
 
@@ -370,6 +376,8 @@
370
376
  border-top: 1px solid var(--sg-sfe-border-secondary);
371
377
  background: var(--sg-sfe-bg-secondary);
372
378
  max-height: 320px;
379
+ flex-shrink: 0;
380
+ overflow-y: auto;
373
381
  }
374
382
 
375
383
  .sg-sfe-tabs {
@@ -1,4 +1,10 @@
1
1
  .sg-switch {
2
+ /* Off state uses a dedicated token so demos can rebrand without
3
+ * touching `--sg-color-text-disabled` (which is also used by the
4
+ * disabled visual state — overriding it makes every control look
5
+ * disabled). */
6
+ --sg-switch-bg: color-mix(in srgb, var(--sg-color-text) 25%, transparent);
7
+ --sg-switch-bg-checked: var(--sg-color-primary);
2
8
  position: relative;
3
9
  display: inline-flex;
4
10
  align-items: center;
@@ -7,7 +13,7 @@
7
13
  padding: 0;
8
14
  border: none;
9
15
  border-radius: 11px;
10
- background: var(--sg-color-text-disabled);
16
+ background: var(--sg-switch-bg);
11
17
  cursor: pointer;
12
18
  transition: background var(--sg-transition-duration) var(--sg-transition-timing);
13
19
  }
@@ -19,7 +25,7 @@
19
25
  }
20
26
 
21
27
  .sg-switch-checked {
22
- background: var(--sg-color-primary);
28
+ background: var(--sg-switch-bg-checked);
23
29
  }
24
30
 
25
31
  .sg-switch-disabled {
@@ -71,6 +71,25 @@
71
71
  position: relative;
72
72
  }
73
73
 
74
+ /* Mobile fallback — when there's no explicit `scroll.x`, the table tries
75
+ * to flex into the available width which, on narrow viewports, collapses
76
+ * cells into illegible vertical stacks. Forcing horizontal overflow with
77
+ * `width: max-content` on the inner grid restores tabular layout and
78
+ * exposes a native horizontal scrollbar so users can pan instead of
79
+ * losing data. Only applies when `.sg-table-scroll-x` wasn't already set
80
+ * (which means the consumer opted-in to a controlled scroll width). */
81
+ @media (max-width: 640px) {
82
+ .sg-table-scroll:not(.sg-table-scroll-x) {
83
+ overflow-x: auto;
84
+ }
85
+ .sg-table-scroll:not(.sg-table-scroll-x) .sg-table-grid,
86
+ .sg-table-scroll:not(.sg-table-scroll-x) .sg-table-pinned-top,
87
+ .sg-table-scroll:not(.sg-table-scroll-x) .sg-table-pinned-bottom {
88
+ min-width: 100%;
89
+ width: max-content;
90
+ }
91
+ }
92
+
74
93
  /* Grid base.
75
94
  * The grid carries a solid base background so body cells (transparent by
76
95
  * default) and fixed-sticky cells draw over the same colour. Without this,
@@ -117,6 +136,19 @@
117
136
  display: flex;
118
137
  align-items: center;
119
138
  gap: var(--sg-padding-xs);
139
+ /* В узких колонках с одновременно sortable + filters заголовок мог
140
+ * "наезжать" на filter-trigger / resize-handle: длинный title + ▲▼
141
+ * не помещались, sort и filter сливались. Скрываем переполнение и
142
+ * усекаем сам title через .sg-table-th-title — иконки всегда видны. */
143
+ overflow: hidden;
144
+ }
145
+
146
+ .sg-table-th-title {
147
+ flex: 0 1 auto;
148
+ min-width: 0;
149
+ overflow: hidden;
150
+ text-overflow: ellipsis;
151
+ white-space: nowrap;
120
152
  }
121
153
 
122
154
  .sg-table-th-sortable {
@@ -143,6 +175,13 @@
143
175
  line-height: 8px;
144
176
  color: var(--sg-color-text-quaternary, var(--sg-color-text-tertiary));
145
177
  transition: color var(--sg-transition-duration);
178
+ /* Defensive: keep the sort glyph compact even if the locale ships a long
179
+ * aria-quality label instead of a single ▲/▼ glyph. The cell would
180
+ * otherwise stretch by the full label width and clash with the column
181
+ * title or filter trigger. */
182
+ max-width: 1em;
183
+ overflow: hidden;
184
+ white-space: nowrap;
146
185
  }
147
186
 
148
187
  .sg-table-sort-current {
@@ -604,6 +643,11 @@
604
643
  * changes — that drift is what shows up as the scrollbar thumb lagging
605
644
  * behind the cursor while the user drags it. Locking visible row cells to
606
645
  * the configured `rowHeight` removes the mismatch entirely. */
646
+ .sg-table-grid-virtual-fixed {
647
+ /* Overridden inline by Table when `rowHeight` is set */
648
+ --sg-virtual-row-height: var(--sg-height-md);
649
+ }
650
+
607
651
  .sg-table-grid-virtual-fixed .sg-table-row[data-sg-virtual-row-index] > .sg-table-td {
608
652
  height: var(--sg-virtual-row-height);
609
653
  min-height: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skygraph/styles",
3
- "version": "0.1.0",
3
+ "version": "0.2.1",
4
4
  "description": "SkyGraph framework-agnostic CSS — tokens, themes, transitions, print and 60+ component stylesheets",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/tokens.css CHANGED
@@ -91,7 +91,7 @@
91
91
 
92
92
  /* === Semantic tokens — Light theme (default) === */
93
93
  :root,
94
- [data-sg-theme="light"] {
94
+ [data-sg-theme='light'] {
95
95
  --sg-color-bg: var(--sg-gray-1);
96
96
  --sg-color-bg-secondary: var(--sg-gray-2);
97
97
  --sg-color-bg-elevated: var(--sg-gray-1);
@@ -109,6 +109,12 @@
109
109
  --sg-color-border: var(--sg-gray-5);
110
110
  --sg-color-border-secondary: var(--sg-gray-4);
111
111
 
112
+ /* Subtle fills (tracks, clear buttons, skeletons) */
113
+ --sg-color-fill: rgba(0, 0, 0, 0.15);
114
+ --sg-color-fill-secondary: rgba(0, 0, 0, 0.06);
115
+ --sg-color-fill-tertiary: rgba(0, 0, 0, 0.06);
116
+ --sg-color-fill-quaternary: rgba(0, 0, 0, 0.02);
117
+
112
118
  --sg-color-primary: var(--sg-blue-6);
113
119
  --sg-color-primary-hover: var(--sg-blue-5);
114
120
  --sg-color-primary-active: var(--sg-blue-7);
@@ -138,19 +144,12 @@
138
144
  --sg-diagram-canvas-bg: var(--sg-color-bg);
139
145
  --sg-diagram-grid-line-color: rgba(0, 0, 0, 0.04);
140
146
  --sg-diagram-grid-line-color-strong: rgba(0, 0, 0, 0.08);
141
- --sg-diagram-node-shadow:
142
- 0 1px 2px rgba(0, 0, 0, 0.06),
143
- 0 0 0 1px rgba(0, 0, 0, 0.04);
144
- --sg-diagram-node-shadow-hover:
145
- 0 4px 12px rgba(0, 0, 0, 0.10),
146
- 0 1px 3px rgba(0, 0, 0, 0.06);
147
+ --sg-diagram-node-shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 0 0 1px rgba(0, 0, 0, 0.04);
148
+ --sg-diagram-node-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.06);
147
149
  --sg-diagram-node-shadow-selected:
148
- 0 0 0 2px var(--sg-color-primary-bg),
149
- 0 6px 16px rgba(22, 119, 255, 0.18),
150
+ 0 0 0 2px var(--sg-color-primary-bg), 0 6px 16px rgba(22, 119, 255, 0.18),
150
151
  0 1px 3px rgba(0, 0, 0, 0.08);
151
- --sg-diagram-node-shadow-dragging:
152
- 0 12px 28px rgba(0, 0, 0, 0.20),
153
- 0 2px 6px rgba(0, 0, 0, 0.10);
152
+ --sg-diagram-node-shadow-dragging: 0 12px 28px rgba(0, 0, 0, 0.2), 0 2px 6px rgba(0, 0, 0, 0.1);
154
153
  --sg-diagram-edge-color: var(--sg-gray-6);
155
154
  --sg-diagram-edge-color-hover: var(--sg-color-text-secondary);
156
155
  --sg-diagram-edge-color-selected: var(--sg-color-primary);
@@ -159,53 +158,43 @@
159
158
 
160
159
  /* Charts — tooltip, crosshair, brush, legend */
161
160
  --sg-chart-tooltip-bg: var(--sg-color-bg-elevated);
162
- --sg-chart-tooltip-shadow:
163
- 0 6px 20px rgba(0, 0, 0, 0.12),
164
- 0 1px 3px rgba(0, 0, 0, 0.06);
161
+ --sg-chart-tooltip-shadow: 0 6px 20px rgba(0, 0, 0, 0.12), 0 1px 3px rgba(0, 0, 0, 0.06);
165
162
  --sg-chart-crosshair-color: rgba(0, 0, 0, 0.32);
166
- --sg-chart-brush-fill: rgba(22, 119, 255, 0.10);
163
+ --sg-chart-brush-fill: rgba(22, 119, 255, 0.1);
167
164
  --sg-chart-brush-stroke: var(--sg-color-primary);
168
165
  --sg-chart-legend-hover-bg: var(--sg-color-bg-hover);
169
166
 
170
167
  /* Dashboard — widget elevation, editor affordances */
171
168
  --sg-dashboard-widget-shadow: var(--sg-shadow-sm);
172
- --sg-dashboard-widget-shadow-hover:
173
- 0 4px 12px rgba(0, 0, 0, 0.08),
174
- 0 1px 3px rgba(0, 0, 0, 0.04);
169
+ --sg-dashboard-widget-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.08), 0 1px 3px rgba(0, 0, 0, 0.04);
175
170
  --sg-dashboard-editor-grid-color: rgba(22, 119, 255, 0.06);
176
171
  --sg-dashboard-editor-widget-border: var(--sg-color-primary);
177
172
  --sg-dashboard-editor-drop-zone-bg: rgba(22, 119, 255, 0.06);
178
173
  --sg-dashboard-editor-drop-zone-border: var(--sg-color-primary);
179
174
 
180
175
  /* Gantt — bars, today marker, dependency arrows */
181
- --sg-gantt-bar-shadow:
182
- 0 1px 2px rgba(0, 0, 0, 0.10),
183
- inset 0 1px 0 rgba(255, 255, 255, 0.18);
176
+ --sg-gantt-bar-shadow: 0 1px 2px rgba(0, 0, 0, 0.1), inset 0 1px 0 rgba(255, 255, 255, 0.18);
184
177
  --sg-gantt-bar-shadow-hover:
185
- 0 3px 8px rgba(0, 0, 0, 0.14),
186
- inset 0 1px 0 rgba(255, 255, 255, 0.22);
178
+ 0 3px 8px rgba(0, 0, 0, 0.14), inset 0 1px 0 rgba(255, 255, 255, 0.22);
187
179
  --sg-gantt-today-marker-color: var(--sg-color-error);
188
180
  --sg-gantt-today-marker-bg: rgba(245, 34, 45, 0.06);
189
181
  --sg-gantt-dep-color: var(--sg-color-text-tertiary);
190
182
 
191
183
  /* Timeline / EventTimeline — connector + event dot */
192
184
  --sg-timeline-tail-color: var(--sg-color-border-secondary);
193
- --sg-event-timeline-dot-shadow:
194
- 0 0 0 3px var(--sg-color-bg),
195
- 0 1px 3px rgba(22, 119, 255, 0.30);
185
+ --sg-event-timeline-dot-shadow: 0 0 0 3px var(--sg-color-bg), 0 1px 3px rgba(22, 119, 255, 0.3);
196
186
  --sg-event-timeline-dot-shadow-hover:
197
- 0 0 0 3px var(--sg-color-bg),
198
- 0 2px 8px rgba(22, 119, 255, 0.45);
187
+ 0 0 0 3px var(--sg-color-bg), 0 2px 8px rgba(22, 119, 255, 0.45);
199
188
 
200
189
  /* ResourceCalendar — today, lane separators, conflict overlay */
201
190
  --sg-rcal-today-bg: rgba(22, 119, 255, 0.05);
202
191
  --sg-rcal-today-marker-color: var(--sg-color-primary);
203
192
  --sg-rcal-lane-divider: var(--sg-color-border-secondary);
204
- --sg-rcal-conflict-overlay-bg: rgba(245, 34, 45, 0.10);
193
+ --sg-rcal-conflict-overlay-bg: rgba(245, 34, 45, 0.1);
205
194
  }
206
195
 
207
196
  /* === Semantic tokens — Dark theme === */
208
- [data-sg-theme="dark"] {
197
+ [data-sg-theme='dark'] {
209
198
  --sg-color-bg: var(--sg-gray-10);
210
199
  --sg-color-bg-secondary: #1f1f1f;
211
200
  --sg-color-bg-elevated: #1f1f1f;
@@ -223,6 +212,11 @@
223
212
  --sg-color-border: #424242;
224
213
  --sg-color-border-secondary: #303030;
225
214
 
215
+ --sg-color-fill: rgba(255, 255, 255, 0.15);
216
+ --sg-color-fill-secondary: rgba(255, 255, 255, 0.08);
217
+ --sg-color-fill-tertiary: rgba(255, 255, 255, 0.06);
218
+ --sg-color-fill-quaternary: rgba(255, 255, 255, 0.04);
219
+
226
220
  --sg-color-primary: var(--sg-blue-5);
227
221
  --sg-color-primary-hover: var(--sg-blue-6);
228
222
  --sg-color-primary-active: var(--sg-blue-7);
@@ -250,19 +244,12 @@
250
244
  --sg-diagram-canvas-bg: var(--sg-color-bg);
251
245
  --sg-diagram-grid-line-color: rgba(255, 255, 255, 0.04);
252
246
  --sg-diagram-grid-line-color-strong: rgba(255, 255, 255, 0.08);
253
- --sg-diagram-node-shadow:
254
- 0 1px 2px rgba(0, 0, 0, 0.40),
255
- 0 0 0 1px rgba(255, 255, 255, 0.04);
256
- --sg-diagram-node-shadow-hover:
257
- 0 4px 12px rgba(0, 0, 0, 0.50),
258
- 0 1px 3px rgba(0, 0, 0, 0.40);
247
+ --sg-diagram-node-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 0 0 1px rgba(255, 255, 255, 0.04);
248
+ --sg-diagram-node-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.5), 0 1px 3px rgba(0, 0, 0, 0.4);
259
249
  --sg-diagram-node-shadow-selected:
260
- 0 0 0 2px var(--sg-color-primary-bg),
261
- 0 6px 16px rgba(64, 150, 255, 0.30),
262
- 0 1px 3px rgba(0, 0, 0, 0.40);
263
- --sg-diagram-node-shadow-dragging:
264
- 0 12px 28px rgba(0, 0, 0, 0.60),
265
- 0 2px 6px rgba(0, 0, 0, 0.40);
250
+ 0 0 0 2px var(--sg-color-primary-bg), 0 6px 16px rgba(64, 150, 255, 0.3),
251
+ 0 1px 3px rgba(0, 0, 0, 0.4);
252
+ --sg-diagram-node-shadow-dragging: 0 12px 28px rgba(0, 0, 0, 0.6), 0 2px 6px rgba(0, 0, 0, 0.4);
266
253
  --sg-diagram-edge-color: var(--sg-gray-7);
267
254
  --sg-diagram-edge-color-hover: var(--sg-color-text-secondary);
268
255
  --sg-diagram-edge-color-selected: var(--sg-color-primary);
@@ -270,40 +257,30 @@
270
257
  --sg-diagram-lasso-fill: rgba(64, 150, 255, 0.12);
271
258
 
272
259
  --sg-chart-tooltip-bg: var(--sg-color-bg-elevated);
273
- --sg-chart-tooltip-shadow:
274
- 0 6px 20px rgba(0, 0, 0, 0.50),
275
- 0 1px 3px rgba(0, 0, 0, 0.30);
276
- --sg-chart-crosshair-color: rgba(255, 255, 255, 0.40);
260
+ --sg-chart-tooltip-shadow: 0 6px 20px rgba(0, 0, 0, 0.5), 0 1px 3px rgba(0, 0, 0, 0.3);
261
+ --sg-chart-crosshair-color: rgba(255, 255, 255, 0.4);
277
262
  --sg-chart-brush-fill: rgba(64, 150, 255, 0.16);
278
263
  --sg-chart-brush-stroke: var(--sg-color-primary);
279
264
  --sg-chart-legend-hover-bg: var(--sg-color-bg-hover);
280
265
 
281
266
  --sg-dashboard-widget-shadow: var(--sg-shadow-sm);
282
- --sg-dashboard-widget-shadow-hover:
283
- 0 4px 12px rgba(0, 0, 0, 0.40),
284
- 0 1px 3px rgba(0, 0, 0, 0.30);
267
+ --sg-dashboard-widget-shadow-hover: 0 4px 12px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.3);
285
268
  --sg-dashboard-editor-grid-color: rgba(64, 150, 255, 0.08);
286
269
  --sg-dashboard-editor-widget-border: var(--sg-color-primary);
287
- --sg-dashboard-editor-drop-zone-bg: rgba(64, 150, 255, 0.10);
270
+ --sg-dashboard-editor-drop-zone-bg: rgba(64, 150, 255, 0.1);
288
271
  --sg-dashboard-editor-drop-zone-border: var(--sg-color-primary);
289
272
 
290
- --sg-gantt-bar-shadow:
291
- 0 1px 2px rgba(0, 0, 0, 0.40),
292
- inset 0 1px 0 rgba(255, 255, 255, 0.10);
273
+ --sg-gantt-bar-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.1);
293
274
  --sg-gantt-bar-shadow-hover:
294
- 0 3px 8px rgba(0, 0, 0, 0.50),
295
- inset 0 1px 0 rgba(255, 255, 255, 0.14);
275
+ 0 3px 8px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.14);
296
276
  --sg-gantt-today-marker-color: var(--sg-color-error);
297
- --sg-gantt-today-marker-bg: rgba(220, 68, 70, 0.10);
277
+ --sg-gantt-today-marker-bg: rgba(220, 68, 70, 0.1);
298
278
  --sg-gantt-dep-color: var(--sg-color-text-tertiary);
299
279
 
300
280
  --sg-timeline-tail-color: var(--sg-color-border-secondary);
301
- --sg-event-timeline-dot-shadow:
302
- 0 0 0 3px var(--sg-color-bg),
303
- 0 1px 3px rgba(64, 150, 255, 0.45);
281
+ --sg-event-timeline-dot-shadow: 0 0 0 3px var(--sg-color-bg), 0 1px 3px rgba(64, 150, 255, 0.45);
304
282
  --sg-event-timeline-dot-shadow-hover:
305
- 0 0 0 3px var(--sg-color-bg),
306
- 0 2px 10px rgba(64, 150, 255, 0.65);
283
+ 0 0 0 3px var(--sg-color-bg), 0 2px 10px rgba(64, 150, 255, 0.65);
307
284
 
308
285
  --sg-rcal-today-bg: rgba(64, 150, 255, 0.08);
309
286
  --sg-rcal-today-marker-color: var(--sg-color-primary);