@nowline/layout 0.2.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.
Files changed (183) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +103 -0
  3. package/dist/band-scale.d.ts +56 -0
  4. package/dist/band-scale.d.ts.map +1 -0
  5. package/dist/band-scale.js +86 -0
  6. package/dist/band-scale.js.map +1 -0
  7. package/dist/calendar.d.ts +79 -0
  8. package/dist/calendar.d.ts.map +1 -0
  9. package/dist/calendar.js +210 -0
  10. package/dist/calendar.js.map +1 -0
  11. package/dist/capacity.d.ts +72 -0
  12. package/dist/capacity.d.ts.map +1 -0
  13. package/dist/capacity.js +163 -0
  14. package/dist/capacity.js.map +1 -0
  15. package/dist/dsl-utils.d.ts +5 -0
  16. package/dist/dsl-utils.d.ts.map +1 -0
  17. package/dist/dsl-utils.js +28 -0
  18. package/dist/dsl-utils.js.map +1 -0
  19. package/dist/edge-routing.d.ts +89 -0
  20. package/dist/edge-routing.d.ts.map +1 -0
  21. package/dist/edge-routing.js +435 -0
  22. package/dist/edge-routing.js.map +1 -0
  23. package/dist/frame-tab-geometry.d.ts +78 -0
  24. package/dist/frame-tab-geometry.d.ts.map +1 -0
  25. package/dist/frame-tab-geometry.js +115 -0
  26. package/dist/frame-tab-geometry.js.map +1 -0
  27. package/dist/header-card-geometry.d.ts +29 -0
  28. package/dist/header-card-geometry.d.ts.map +1 -0
  29. package/dist/header-card-geometry.js +41 -0
  30. package/dist/header-card-geometry.js.map +1 -0
  31. package/dist/i18n.d.ts +48 -0
  32. package/dist/i18n.d.ts.map +1 -0
  33. package/dist/i18n.js +114 -0
  34. package/dist/i18n.js.map +1 -0
  35. package/dist/include-chrome-geometry.d.ts +86 -0
  36. package/dist/include-chrome-geometry.d.ts.map +1 -0
  37. package/dist/include-chrome-geometry.js +104 -0
  38. package/dist/include-chrome-geometry.js.map +1 -0
  39. package/dist/index.d.ts +11 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +10 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/item-bar-geometry.d.ts +127 -0
  44. package/dist/item-bar-geometry.d.ts.map +1 -0
  45. package/dist/item-bar-geometry.js +173 -0
  46. package/dist/item-bar-geometry.js.map +1 -0
  47. package/dist/lane-utilization.d.ts +90 -0
  48. package/dist/lane-utilization.d.ts.map +1 -0
  49. package/dist/lane-utilization.js +206 -0
  50. package/dist/lane-utilization.js.map +1 -0
  51. package/dist/layout-context.d.ts +143 -0
  52. package/dist/layout-context.d.ts.map +1 -0
  53. package/dist/layout-context.js +8 -0
  54. package/dist/layout-context.js.map +1 -0
  55. package/dist/layout.d.ts +18 -0
  56. package/dist/layout.d.ts.map +1 -0
  57. package/dist/layout.js +1213 -0
  58. package/dist/layout.js.map +1 -0
  59. package/dist/nodes/anchor-node.d.ts +16 -0
  60. package/dist/nodes/anchor-node.d.ts.map +1 -0
  61. package/dist/nodes/anchor-node.js +68 -0
  62. package/dist/nodes/anchor-node.js.map +1 -0
  63. package/dist/nodes/footnote-node.d.ts +10 -0
  64. package/dist/nodes/footnote-node.d.ts.map +1 -0
  65. package/dist/nodes/footnote-node.js +41 -0
  66. package/dist/nodes/footnote-node.js.map +1 -0
  67. package/dist/nodes/group-node.d.ts +29 -0
  68. package/dist/nodes/group-node.d.ts.map +1 -0
  69. package/dist/nodes/group-node.js +187 -0
  70. package/dist/nodes/group-node.js.map +1 -0
  71. package/dist/nodes/include-node.d.ts +16 -0
  72. package/dist/nodes/include-node.d.ts.map +1 -0
  73. package/dist/nodes/include-node.js +117 -0
  74. package/dist/nodes/include-node.js.map +1 -0
  75. package/dist/nodes/item-node.d.ts +51 -0
  76. package/dist/nodes/item-node.d.ts.map +1 -0
  77. package/dist/nodes/item-node.js +108 -0
  78. package/dist/nodes/item-node.js.map +1 -0
  79. package/dist/nodes/marker-geometry.d.ts +22 -0
  80. package/dist/nodes/marker-geometry.d.ts.map +1 -0
  81. package/dist/nodes/marker-geometry.js +38 -0
  82. package/dist/nodes/marker-geometry.js.map +1 -0
  83. package/dist/nodes/milestone-node.d.ts +48 -0
  84. package/dist/nodes/milestone-node.d.ts.map +1 -0
  85. package/dist/nodes/milestone-node.js +210 -0
  86. package/dist/nodes/milestone-node.js.map +1 -0
  87. package/dist/nodes/parallel-node.d.ts +21 -0
  88. package/dist/nodes/parallel-node.d.ts.map +1 -0
  89. package/dist/nodes/parallel-node.js +80 -0
  90. package/dist/nodes/parallel-node.js.map +1 -0
  91. package/dist/nodes/roadmap-node.d.ts +76 -0
  92. package/dist/nodes/roadmap-node.d.ts.map +1 -0
  93. package/dist/nodes/roadmap-node.js +788 -0
  94. package/dist/nodes/roadmap-node.js.map +1 -0
  95. package/dist/nodes/swimlane-node.d.ts +38 -0
  96. package/dist/nodes/swimlane-node.d.ts.map +1 -0
  97. package/dist/nodes/swimlane-node.js +308 -0
  98. package/dist/nodes/swimlane-node.js.map +1 -0
  99. package/dist/renderable.d.ts +44 -0
  100. package/dist/renderable.d.ts.map +1 -0
  101. package/dist/renderable.js +21 -0
  102. package/dist/renderable.js.map +1 -0
  103. package/dist/row-packer.d.ts +125 -0
  104. package/dist/row-packer.d.ts.map +1 -0
  105. package/dist/row-packer.js +169 -0
  106. package/dist/row-packer.js.map +1 -0
  107. package/dist/style-resolution.d.ts +14 -0
  108. package/dist/style-resolution.d.ts.map +1 -0
  109. package/dist/style-resolution.js +191 -0
  110. package/dist/style-resolution.js.map +1 -0
  111. package/dist/themes/dark.d.ts +4 -0
  112. package/dist/themes/dark.d.ts.map +1 -0
  113. package/dist/themes/dark.js +241 -0
  114. package/dist/themes/dark.js.map +1 -0
  115. package/dist/themes/index.d.ts +15 -0
  116. package/dist/themes/index.d.ts.map +1 -0
  117. package/dist/themes/index.js +30 -0
  118. package/dist/themes/index.js.map +1 -0
  119. package/dist/themes/light.d.ts +4 -0
  120. package/dist/themes/light.d.ts.map +1 -0
  121. package/dist/themes/light.js +248 -0
  122. package/dist/themes/light.js.map +1 -0
  123. package/dist/themes/shape.d.ts +194 -0
  124. package/dist/themes/shape.d.ts.map +1 -0
  125. package/dist/themes/shape.js +6 -0
  126. package/dist/themes/shape.js.map +1 -0
  127. package/dist/themes/shared.d.ts +145 -0
  128. package/dist/themes/shared.d.ts.map +1 -0
  129. package/dist/themes/shared.js +310 -0
  130. package/dist/themes/shared.js.map +1 -0
  131. package/dist/time-scale.d.ts +39 -0
  132. package/dist/time-scale.d.ts.map +1 -0
  133. package/dist/time-scale.js +62 -0
  134. package/dist/time-scale.js.map +1 -0
  135. package/dist/types.d.ts +483 -0
  136. package/dist/types.d.ts.map +1 -0
  137. package/dist/types.js +6 -0
  138. package/dist/types.js.map +1 -0
  139. package/dist/view-preset.d.ts +23 -0
  140. package/dist/view-preset.d.ts.map +1 -0
  141. package/dist/view-preset.js +146 -0
  142. package/dist/view-preset.js.map +1 -0
  143. package/dist/working-calendar.d.ts +14 -0
  144. package/dist/working-calendar.d.ts.map +1 -0
  145. package/dist/working-calendar.js +74 -0
  146. package/dist/working-calendar.js.map +1 -0
  147. package/package.json +37 -0
  148. package/src/band-scale.ts +115 -0
  149. package/src/calendar.ts +244 -0
  150. package/src/capacity.ts +191 -0
  151. package/src/dsl-utils.ts +30 -0
  152. package/src/edge-routing.ts +550 -0
  153. package/src/frame-tab-geometry.ts +165 -0
  154. package/src/header-card-geometry.ts +48 -0
  155. package/src/i18n.ts +124 -0
  156. package/src/include-chrome-geometry.ts +156 -0
  157. package/src/index.ts +116 -0
  158. package/src/item-bar-geometry.ts +222 -0
  159. package/src/lane-utilization.ts +259 -0
  160. package/src/layout-context.ts +182 -0
  161. package/src/layout.ts +1446 -0
  162. package/src/nodes/anchor-node.ts +77 -0
  163. package/src/nodes/footnote-node.ts +60 -0
  164. package/src/nodes/group-node.ts +252 -0
  165. package/src/nodes/include-node.ts +168 -0
  166. package/src/nodes/item-node.ts +171 -0
  167. package/src/nodes/marker-geometry.ts +43 -0
  168. package/src/nodes/milestone-node.ts +263 -0
  169. package/src/nodes/parallel-node.ts +101 -0
  170. package/src/nodes/roadmap-node.ts +957 -0
  171. package/src/nodes/swimlane-node.ts +423 -0
  172. package/src/renderable.ts +68 -0
  173. package/src/row-packer.ts +271 -0
  174. package/src/style-resolution.ts +243 -0
  175. package/src/themes/dark.ts +244 -0
  176. package/src/themes/index.ts +36 -0
  177. package/src/themes/light.ts +251 -0
  178. package/src/themes/shape.ts +230 -0
  179. package/src/themes/shared.ts +369 -0
  180. package/src/time-scale.ts +78 -0
  181. package/src/types.ts +607 -0
  182. package/src/view-preset.ts +180 -0
  183. package/src/working-calendar.ts +91 -0
@@ -0,0 +1,244 @@
1
+ import type { EntityStyle, NamedColors, Theme } from './shape.js';
2
+
3
+ // Named-color mapping for dark theme. Tailwind's slate-on-near-black tints.
4
+ export const darkNamed: NamedColors = {
5
+ red: '#f87171',
6
+ blue: '#60a5fa',
7
+ yellow: '#facc15',
8
+ green: '#34d399',
9
+ orange: '#fb923c',
10
+ purple: '#a78bfa',
11
+ gray: '#94a3b8',
12
+ navy: '#818cf8',
13
+ white: '#e2e8f0',
14
+ };
15
+
16
+ const baseEntity: EntityStyle = {
17
+ bg: 'none',
18
+ fg: '#e2e8f0',
19
+ text: '#e2e8f0',
20
+ border: 'solid',
21
+ icon: 'none',
22
+ shadow: 'none',
23
+ font: 'sans',
24
+ weight: 'normal',
25
+ italic: false,
26
+ textSize: 'md',
27
+ padding: 'sm',
28
+ spacing: 'sm',
29
+ headerHeight: 'sm',
30
+ cornerRadius: 'sm',
31
+ bracket: 'none',
32
+ capacityIcon: 'multiplier',
33
+ };
34
+
35
+ export const darkTheme: Theme = {
36
+ name: 'dark',
37
+ surface: {
38
+ page: '#0b1220',
39
+ chart: '#111827',
40
+ headerBox: '#1e293b',
41
+ },
42
+ entities: {
43
+ roadmap: {
44
+ ...baseEntity,
45
+ headerHeight: 'md',
46
+ padding: 'md',
47
+ },
48
+ swimlane: {
49
+ ...baseEntity,
50
+ fg: '#e2e8f0',
51
+ text: '#e2e8f0',
52
+ padding: 'sm',
53
+ spacing: 'none',
54
+ textSize: 'sm',
55
+ },
56
+ item: {
57
+ ...baseEntity,
58
+ // Status-aware tint applied during layout when bg stays #0f172a.
59
+ bg: '#0f172a',
60
+ fg: '#94a3b8',
61
+ text: '#e2e8f0',
62
+ shadow: 'subtle',
63
+ cornerRadius: 'sm',
64
+ },
65
+ parallel: {
66
+ ...baseEntity,
67
+ bracket: 'none',
68
+ padding: 'xs',
69
+ },
70
+ group: {
71
+ ...baseEntity,
72
+ bracket: 'solid',
73
+ padding: 'xs',
74
+ fg: '#94a3b8',
75
+ },
76
+ anchor: {
77
+ ...baseEntity,
78
+ bg: '#0b1220',
79
+ fg: '#cbd5e1',
80
+ text: '#cbd5e1',
81
+ cornerRadius: 'sm',
82
+ },
83
+ milestone: {
84
+ ...baseEntity,
85
+ bg: '#e2e8f0',
86
+ fg: '#e2e8f0',
87
+ text: '#0b1220',
88
+ border: 'solid',
89
+ },
90
+ footnote: {
91
+ ...baseEntity,
92
+ bg: 'none',
93
+ fg: '#94a3b8',
94
+ text: '#e2e8f0',
95
+ textSize: 'sm',
96
+ },
97
+ label: {
98
+ ...baseEntity,
99
+ bg: '#1e293b',
100
+ fg: '#94a3b8',
101
+ text: '#e2e8f0',
102
+ textSize: 'xs',
103
+ padding: 'xs',
104
+ cornerRadius: 'full',
105
+ },
106
+ },
107
+ swimlane: {
108
+ bandEven: '#111827',
109
+ bandOdd: '#0f172a',
110
+ separator: '#1f2937',
111
+ frameTabText: '#e2e8f0',
112
+ frameTabMuted: '#94a3b8',
113
+ border: '#334155',
114
+ tabFill: '#1e293b',
115
+ tabStroke: '#475569',
116
+ tabText: '#e2e8f0',
117
+ ownerText: '#94a3b8',
118
+ footnoteIndicator: '#f87171',
119
+ rowTintEven: '#0f172a',
120
+ rowTintOdd: '#1e293b',
121
+ utilizationOk: '#34d399',
122
+ utilizationWarn: '#fbbf24',
123
+ utilizationOver: '#f87171',
124
+ },
125
+ timeline: {
126
+ gridLine: '#475569',
127
+ minorGridLine: '#334155',
128
+ tickMark: '#334155',
129
+ labelText: '#cbd5e1',
130
+ panelFill: '#0f172a',
131
+ border: '#334155',
132
+ },
133
+ header: {
134
+ cardBorder: '#475569',
135
+ author: '#94a3b8',
136
+ },
137
+ item: {
138
+ overflowX: '#f87171',
139
+ linkIconFg: '#94a3b8',
140
+ overflowTailFill: '#7f1d1d',
141
+ overflowTailStroke: '#f87171',
142
+ overflowCaption: '#fecaca',
143
+ },
144
+ parallel: {
145
+ bracketStroke: '#cbd5e1',
146
+ },
147
+ anchorDiamond: {
148
+ fill: '#0f172a',
149
+ stroke: '#cbd5e1',
150
+ label: '#cbd5e1',
151
+ cutLine: '#94a3b8',
152
+ },
153
+ milestoneDiamond: {
154
+ fill: '#e2e8f0',
155
+ label: '#e2e8f0',
156
+ cutLineNormal: '#a5b4fc',
157
+ cutLineOverrun: '#ef4444',
158
+ slack: '#cbd5e1',
159
+ },
160
+ footnotePanel: {
161
+ fill: '#0f172a',
162
+ border: '#334155',
163
+ header: '#e2e8f0',
164
+ title: '#e2e8f0',
165
+ description: '#94a3b8',
166
+ number: '#f87171',
167
+ },
168
+ nowline: {
169
+ stroke: '#f87171',
170
+ labelText: '#0b1220',
171
+ labelBg: '#f87171',
172
+ },
173
+ milestone: {
174
+ dashedInk: '#a5b4fc',
175
+ overrun: '#ef4444',
176
+ },
177
+ anchor: {
178
+ predecessorLine: '#94a3b8',
179
+ },
180
+ dependency: {
181
+ edgeStroke: '#cbd5e1',
182
+ overflowStroke: '#ef5350',
183
+ },
184
+ footnote: {
185
+ indicatorText: '#f87171',
186
+ descriptionMuted: '#94a3b8',
187
+ },
188
+ includeRegion: {
189
+ border: '#475569',
190
+ label: '#cbd5e1',
191
+ badge: '#94a3b8',
192
+ fill: '#0b1220',
193
+ tabFill: '#111827',
194
+ tabStroke: '#475569',
195
+ tabText: '#e2e8f0',
196
+ badgeFill: '#1e293b',
197
+ badgeStroke: '#475569',
198
+ badgeText: '#94a3b8',
199
+ },
200
+ arrowhead: {
201
+ neutral: '#94a3b8',
202
+ light: '#64748b',
203
+ dark: '#e2e8f0',
204
+ },
205
+ status: {
206
+ done: '#34d399',
207
+ inProgress: '#60a5fa',
208
+ atRisk: '#facc15',
209
+ blocked: '#ef4444',
210
+ planned: '#94a3b8',
211
+ neutral: '#94a3b8',
212
+ },
213
+ // Status-dot palettes — see `light.ts` for the contract. Same
214
+ // two palettes both themes; dark-theme bars come in BOTH dark
215
+ // (status-tint) and bright (label-driven) flavors, so a single
216
+ // palette can never satisfy both. The renderer picks per-bar
217
+ // based on the bar bg's relative luminance.
218
+ statusDot: {
219
+ onLight: {
220
+ done: '#065f46',
221
+ inProgress: '#1e3a8a',
222
+ atRisk: '#92400e',
223
+ blocked: '#991b1b',
224
+ planned: '#334155',
225
+ neutral: '#334155',
226
+ },
227
+ onDark: {
228
+ done: '#d1fae5',
229
+ inProgress: '#dbeafe',
230
+ atRisk: '#fef3c7',
231
+ blocked: '#fee2e2',
232
+ planned: '#e2e8f0',
233
+ neutral: '#e2e8f0',
234
+ },
235
+ },
236
+ attribution: {
237
+ mark: '#cbd5e1',
238
+ link: '#f87171',
239
+ },
240
+ diagnostic: {
241
+ overlayBg: '#7f1d1d',
242
+ errorText: '#fecaca',
243
+ },
244
+ };
@@ -0,0 +1,36 @@
1
+ export { darkNamed, darkTheme } from './dark.js';
2
+ export { lightNamed, lightTheme } from './light.js';
3
+ export type { EntityStyle, NamedColors, Theme } from './shape.js';
4
+
5
+ import { darkNamed, darkTheme } from './dark.js';
6
+ import { lightNamed, lightTheme } from './light.js';
7
+ import type { NamedColors, Theme } from './shape.js';
8
+
9
+ export type ThemeName = 'light' | 'dark';
10
+
11
+ export const themes: { light: Theme; dark: Theme } = {
12
+ light: lightTheme,
13
+ dark: darkTheme,
14
+ };
15
+
16
+ export const namedColors: { light: NamedColors; dark: NamedColors } = {
17
+ light: lightNamed,
18
+ dark: darkNamed,
19
+ };
20
+
21
+ // Aliases collapse internationally-friendlier spellings onto the canonical
22
+ // keys before lookup so themes only need to define each color once.
23
+ const COLOR_ALIASES: Record<string, string> = {
24
+ grey: 'gray',
25
+ violet: 'purple',
26
+ };
27
+
28
+ // Resolve a DSL color token (`blue`, `#ff00aa`, or `none`) against a theme.
29
+ export function resolveColor(token: string, theme: Theme): string {
30
+ if (token === 'none') return 'none';
31
+ if (token.startsWith('#')) return token;
32
+ const named = theme.name === 'dark' ? darkNamed : lightNamed;
33
+ const canonical = COLOR_ALIASES[token] ?? token;
34
+ const hit = (named as unknown as Record<string, string>)[canonical];
35
+ return typeof hit === 'string' ? hit : token;
36
+ }
@@ -0,0 +1,251 @@
1
+ import type { EntityStyle, NamedColors, Theme } from './shape.js';
2
+
3
+ // Named-color mapping for light theme. These are the DSL's `bg:blue`
4
+ // style tokens translated to concrete palette values.
5
+ export const lightNamed: NamedColors = {
6
+ red: '#e53935',
7
+ blue: '#1e88e5',
8
+ yellow: '#fdd835',
9
+ green: '#43a047',
10
+ orange: '#fb8c00',
11
+ purple: '#8e24aa',
12
+ gray: '#9e9e9e',
13
+ navy: '#0d47a1',
14
+ white: '#ffffff',
15
+ };
16
+
17
+ const baseEntity: EntityStyle = {
18
+ bg: 'none',
19
+ fg: '#0f172a',
20
+ text: '#0f172a',
21
+ border: 'solid',
22
+ icon: 'none',
23
+ shadow: 'none',
24
+ font: 'sans',
25
+ weight: 'normal',
26
+ italic: false,
27
+ textSize: 'md',
28
+ padding: 'sm',
29
+ spacing: 'sm',
30
+ headerHeight: 'sm',
31
+ cornerRadius: 'sm',
32
+ bracket: 'none',
33
+ capacityIcon: 'multiplier',
34
+ };
35
+
36
+ export const lightTheme: Theme = {
37
+ name: 'light',
38
+ surface: {
39
+ page: '#f8fafc',
40
+ chart: '#ffffff',
41
+ headerBox: '#ffffff',
42
+ },
43
+ entities: {
44
+ roadmap: {
45
+ ...baseEntity,
46
+ headerHeight: 'md',
47
+ padding: 'md',
48
+ },
49
+ swimlane: {
50
+ ...baseEntity,
51
+ fg: '#334155',
52
+ text: '#334155',
53
+ padding: 'sm',
54
+ spacing: 'none',
55
+ textSize: 'sm',
56
+ },
57
+ item: {
58
+ ...baseEntity,
59
+ // Status-aware tint applied during layout when bg stays white;
60
+ // see m2d handoff Resolution 3.
61
+ bg: '#ffffff',
62
+ fg: '#94a3b8',
63
+ text: '#0f172a',
64
+ shadow: 'subtle',
65
+ cornerRadius: 'sm',
66
+ },
67
+ parallel: {
68
+ ...baseEntity,
69
+ bracket: 'none',
70
+ padding: 'xs',
71
+ },
72
+ group: {
73
+ ...baseEntity,
74
+ bracket: 'solid',
75
+ padding: 'xs',
76
+ fg: '#475569',
77
+ },
78
+ anchor: {
79
+ ...baseEntity,
80
+ bg: '#0f172a',
81
+ fg: '#0f172a',
82
+ text: '#0f172a',
83
+ cornerRadius: 'sm',
84
+ },
85
+ milestone: {
86
+ ...baseEntity,
87
+ bg: '#312e81',
88
+ fg: '#312e81',
89
+ text: '#ffffff',
90
+ border: 'solid',
91
+ },
92
+ footnote: {
93
+ ...baseEntity,
94
+ bg: 'none',
95
+ fg: '#475569',
96
+ text: '#475569',
97
+ textSize: 'sm',
98
+ },
99
+ label: {
100
+ ...baseEntity,
101
+ bg: '#f1f5f9',
102
+ fg: '#475569',
103
+ text: '#475569',
104
+ textSize: 'xs',
105
+ padding: 'xs',
106
+ cornerRadius: 'full',
107
+ },
108
+ },
109
+ swimlane: {
110
+ bandEven: '#ffffff',
111
+ bandOdd: '#f8fafc',
112
+ separator: '#e2e8f0',
113
+ frameTabText: '#334155',
114
+ frameTabMuted: '#64748b',
115
+ border: '#e2e8f0',
116
+ tabFill: '#f1f5f9',
117
+ tabStroke: '#cbd5e1',
118
+ tabText: '#334155',
119
+ ownerText: '#64748b',
120
+ footnoteIndicator: '#dc2626',
121
+ rowTintEven: '#ffffff',
122
+ rowTintOdd: '#f8fafc',
123
+ utilizationOk: '#10b981',
124
+ utilizationWarn: '#f59e0b',
125
+ utilizationOver: '#ef4444',
126
+ },
127
+ timeline: {
128
+ gridLine: '#cbd5e1',
129
+ minorGridLine: '#e2e8f0',
130
+ tickMark: '#cbd5e1',
131
+ labelText: '#64748b',
132
+ panelFill: '#ffffff',
133
+ border: '#e2e8f0',
134
+ },
135
+ header: {
136
+ cardBorder: '#e2e8f0',
137
+ author: '#64748b',
138
+ },
139
+ item: {
140
+ overflowX: '#dc2626',
141
+ linkIconFg: '#0f172a',
142
+ overflowTailFill: '#fee2e2',
143
+ overflowTailStroke: '#ef4444',
144
+ overflowCaption: '#b91c1c',
145
+ },
146
+ parallel: {
147
+ bracketStroke: '#334155',
148
+ },
149
+ anchorDiamond: {
150
+ fill: '#ffffff',
151
+ stroke: '#334155',
152
+ label: '#334155',
153
+ cutLine: '#64748b',
154
+ },
155
+ milestoneDiamond: {
156
+ fill: '#0f172a',
157
+ label: '#0f172a',
158
+ cutLineNormal: '#1e1b4b',
159
+ cutLineOverrun: '#b91c1c',
160
+ slack: '#0f172a',
161
+ },
162
+ footnotePanel: {
163
+ fill: '#ffffff',
164
+ border: '#e2e8f0',
165
+ header: '#0f172a',
166
+ title: '#0f172a',
167
+ description: '#64748b',
168
+ number: '#dc2626',
169
+ },
170
+ nowline: {
171
+ stroke: '#e53e3e',
172
+ labelText: '#ffffff',
173
+ labelBg: '#e53e3e',
174
+ },
175
+ milestone: {
176
+ dashedInk: '#94a3b8',
177
+ overrun: '#ef4444',
178
+ },
179
+ anchor: {
180
+ predecessorLine: '#94a3b8',
181
+ },
182
+ dependency: {
183
+ edgeStroke: '#475569',
184
+ overflowStroke: '#d32f2f',
185
+ },
186
+ footnote: {
187
+ indicatorText: '#e53e3e',
188
+ descriptionMuted: '#64748b',
189
+ },
190
+ includeRegion: {
191
+ border: '#94a3b8',
192
+ label: '#334155',
193
+ badge: '#64748b',
194
+ fill: '#f8fafc',
195
+ tabFill: '#ffffff',
196
+ tabStroke: '#cbd5e1',
197
+ tabText: '#0f172a',
198
+ badgeFill: '#e2e8f0',
199
+ badgeStroke: '#cbd5e1',
200
+ badgeText: '#475569',
201
+ },
202
+ arrowhead: {
203
+ neutral: '#475569',
204
+ light: '#94a3b8',
205
+ dark: '#0f172a',
206
+ },
207
+ status: {
208
+ done: '#10b981',
209
+ inProgress: '#3b82f6',
210
+ atRisk: '#f59e0b',
211
+ blocked: '#ef4444',
212
+ planned: '#94a3b8',
213
+ neutral: '#94a3b8',
214
+ },
215
+ // Status-dot palettes — the renderer picks one based on the
216
+ // bar's effective bg luminance.
217
+ //
218
+ // `onLight`: deep / 800-900 level. Used when the bar bg is
219
+ // light (pale status tint OR a label-driven light hue). High
220
+ // contrast against either.
221
+ //
222
+ // `onDark`: pale / 100 level. Used when the bar bg is dark or
223
+ // saturated mid-tone (e.g. `bg:blue` → `#1e88e5`). Still
224
+ // hue-tinted so the status meaning carries.
225
+ statusDot: {
226
+ onLight: {
227
+ done: '#065f46',
228
+ inProgress: '#1e3a8a',
229
+ atRisk: '#92400e',
230
+ blocked: '#991b1b',
231
+ planned: '#334155',
232
+ neutral: '#334155',
233
+ },
234
+ onDark: {
235
+ done: '#d1fae5',
236
+ inProgress: '#dbeafe',
237
+ atRisk: '#fef3c7',
238
+ blocked: '#fee2e2',
239
+ planned: '#e2e8f0',
240
+ neutral: '#e2e8f0',
241
+ },
242
+ },
243
+ attribution: {
244
+ mark: '#94a3b8',
245
+ link: '#e53e3e',
246
+ },
247
+ diagnostic: {
248
+ overlayBg: '#fee2e2',
249
+ errorText: '#991b1b',
250
+ },
251
+ };