kitfly 0.2.1 → 0.2.4

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 (132) hide show
  1. package/CHANGELOG.md +79 -0
  2. package/README.md +38 -21
  3. package/VERSION +1 -1
  4. package/dist/_raw/content/guide/branding.md +146 -0
  5. package/dist/_raw/content/guide/data-driven-content.md +204 -0
  6. package/dist/_raw/content/reference/configuration.md +145 -7
  7. package/dist/_raw/content/reference/environment-variables.md +26 -1
  8. package/dist/_raw/content/reference/gantt-widget.md +468 -0
  9. package/dist/_raw/content/reference/glossary.md +25 -1
  10. package/dist/_raw/content/reference/key-concepts.md +30 -2
  11. package/dist/_raw/content/reference/plugins.md +170 -1
  12. package/dist/_raw/docs/decisions/ADR-0006-data-driven-content.md +350 -0
  13. package/dist/content/deployment/preflight.html +11 -8
  14. package/dist/content/deployment/recipes/aws-s3.html +11 -8
  15. package/dist/content/deployment/recipes/cloudflare-pages.html +11 -8
  16. package/dist/content/deployment/recipes/cloudflare-r2.html +11 -8
  17. package/dist/content/deployment/recipes/fly-io.html +11 -8
  18. package/dist/content/deployment/recipes/github-pages.html +11 -8
  19. package/dist/content/deployment/recipes/netlify.html +11 -8
  20. package/dist/content/deployment/recipes/vercel.html +11 -8
  21. package/dist/content/deployment/secrets-and-env-vars.html +11 -8
  22. package/dist/content/deployment.html +11 -8
  23. package/dist/content/guide/approaches.html +11 -8
  24. package/dist/content/guide/branding.html +509 -0
  25. package/dist/content/guide/data-driven-content.html +542 -0
  26. package/dist/content/guide/features.html +11 -8
  27. package/dist/content/guide/getting-started.html +11 -8
  28. package/dist/content/guide/kitfly-overview.html +11 -8
  29. package/dist/content/reference/configuration.html +136 -11
  30. package/dist/content/reference/design-catalog.html +11 -8
  31. package/dist/content/reference/environment-variables.html +51 -10
  32. package/dist/content/reference/gantt-widget.html +899 -0
  33. package/dist/content/reference/glossary.html +25 -10
  34. package/dist/content/reference/key-concepts.html +34 -11
  35. package/dist/content/reference/plugins.html +261 -10
  36. package/dist/content/reference/slides-authoring-guidelines.html +11 -8
  37. package/dist/content/reference/structure.html +11 -8
  38. package/dist/content/reference.html +11 -8
  39. package/dist/content/templates/crucible.html +11 -8
  40. package/dist/content/templates/handbook.html +11 -8
  41. package/dist/content/templates/minimal.html +11 -8
  42. package/dist/content/templates/overview.html +11 -8
  43. package/dist/content/templates/pipeline.html +11 -8
  44. package/dist/content/templates/productbook.html +11 -8
  45. package/dist/content/templates/runbook.html +11 -8
  46. package/dist/content/templates/servicebook.html +11 -8
  47. package/dist/content-index.json +37 -2
  48. package/dist/docs/decisions/ADR-0001-minimalist-site-code.html +11 -8
  49. package/dist/docs/decisions/ADR-0002-ai-accessibility.html +11 -8
  50. package/dist/docs/decisions/ADR-0003-single-file-bundle.html +11 -8
  51. package/dist/docs/decisions/ADR-0004-bun-runtime.html +11 -8
  52. package/dist/docs/decisions/ADR-0005-plugin-contract-and-distribution.html +11 -8
  53. package/dist/docs/decisions/ADR-0006-data-driven-content.html +751 -0
  54. package/dist/docs/decisions/DDR-0001-viewport-locked-layout.html +11 -8
  55. package/dist/docs/decisions/DDR-0002-theme-system.html +11 -8
  56. package/dist/docs/decisions/DDR-0003-bounded-logo-slot.html +11 -8
  57. package/dist/docs/decisions/DDR-0004-slides-rendering-model.html +11 -8
  58. package/dist/docs/decisions/DDR-0005-deterministic-layout-boundary.html +11 -8
  59. package/dist/docs/userguide/cli/build.html +11 -8
  60. package/dist/docs/userguide/cli/bundle.html +11 -8
  61. package/dist/docs/userguide/cli/dev.html +11 -8
  62. package/dist/docs/userguide/cli/init.html +11 -8
  63. package/dist/docs/userguide/cli/servers.html +11 -8
  64. package/dist/docs/userguide/cli/stop.html +11 -8
  65. package/dist/docs/userguide/cli/update.html +11 -8
  66. package/dist/docs/userguide/cli/version.html +11 -8
  67. package/dist/docs/userguide/cli.html +11 -8
  68. package/dist/docs/userguide/sharing.html +11 -8
  69. package/dist/index.html +11 -8
  70. package/dist/llms.txt +3 -3
  71. package/dist/provenance.json +4 -5
  72. package/dist/reports/license-inventory.csv +199 -0
  73. package/dist/schemas/plugin-registry.schema.html +11 -8
  74. package/dist/schemas/plugin-schemas-notes.html +11 -8
  75. package/dist/schemas/plugin.schema.html +11 -8
  76. package/dist/schemas/plugins.schema.html +11 -8
  77. package/dist/schemas/v0/common.schema.html +15 -12
  78. package/dist/schemas/v0/plugin-registry.schema.html +14 -11
  79. package/dist/schemas/v0/plugin.schema.html +14 -11
  80. package/dist/schemas/v0/plugins.schema.html +14 -11
  81. package/dist/schemas/v0/site.schema.html +68 -9
  82. package/dist/schemas/v0/theme.schema.html +22 -19
  83. package/dist/schemas.html +11 -8
  84. package/dist/styles.css +39 -4
  85. package/package.json +1 -1
  86. package/plugins-dist/latex-runtime.js +140 -0
  87. package/plugins-dist/latex.js +178 -0
  88. package/plugins-dist/planning-visuals.css +261 -0
  89. package/plugins-dist/planning-visuals.js +669 -0
  90. package/plugins-dist/slides-charts-lite-runtime.js +179 -0
  91. package/plugins-dist/slides-charts-lite.js +198 -0
  92. package/registry/plugins.yaml +40 -1
  93. package/schemas/v0/site.schema.json +56 -0
  94. package/scripts/build-all.ts +5 -0
  95. package/scripts/build.ts +264 -80
  96. package/scripts/bundle.ts +188 -17
  97. package/scripts/dev.ts +294 -171
  98. package/scripts/embed-docs.ts +119 -0
  99. package/src/__tests__/brief.test.ts +151 -0
  100. package/src/__tests__/build.test.ts +293 -1
  101. package/src/__tests__/bundle.test.ts +195 -0
  102. package/src/__tests__/docs.test.ts +117 -0
  103. package/src/__tests__/fixtures/fences/planning-visuals/invalid/bad-month-format.md +10 -0
  104. package/src/__tests__/fixtures/fences/planning-visuals/invalid/marker-format-mismatch.md +13 -0
  105. package/src/__tests__/fixtures/fences/planning-visuals/invalid/milestone-format-mismatch.md +13 -0
  106. package/src/__tests__/fixtures/fences/planning-visuals/invalid/missing-tracks.md +5 -0
  107. package/src/__tests__/fixtures/fences/planning-visuals/invalid/track-reversed.md +10 -0
  108. package/src/__tests__/fixtures/fences/planning-visuals/valid/markers-basic.md +15 -0
  109. package/src/__tests__/fixtures/fences/planning-visuals/valid/markers-no-milestones.md +13 -0
  110. package/src/__tests__/fixtures/fences/planning-visuals/valid/month-basic.md +16 -0
  111. package/src/__tests__/fixtures/fences/planning-visuals/valid/no-milestones.md +10 -0
  112. package/src/__tests__/fixtures/fences/planning-visuals/valid/week-basic.md +20 -0
  113. package/src/__tests__/init.test.ts +51 -2
  114. package/src/__tests__/latex-runtime.bun.test.ts +35 -0
  115. package/src/__tests__/planning-visuals-fence-contract.test.ts +28 -0
  116. package/src/__tests__/planning-visuals-runtime-regressions.bun.test.ts +68 -0
  117. package/src/__tests__/planning-visuals-runtime.bun.test.ts +192 -0
  118. package/src/__tests__/shared.test.ts +719 -1
  119. package/src/__tests__/slides-charts-lite-runtime.bun.test.ts +45 -0
  120. package/src/cli.ts +124 -22
  121. package/src/commands/docs.ts +71 -0
  122. package/src/commands/init.ts +1 -1
  123. package/src/generated/embedded-docs.ts +2384 -0
  124. package/src/server-registry.ts +50 -10
  125. package/src/shared.ts +1174 -43
  126. package/src/site/styles.css +39 -4
  127. package/src/site/template.html +5 -2
  128. package/src/templates/brief.ts +486 -0
  129. package/src/templates/deck.ts +59 -0
  130. package/src/templates/driver.ts +46 -13
  131. package/src/templates/handbook.ts +32 -0
  132. package/src/templates/runbook.ts +32 -0
package/dist/styles.css CHANGED
@@ -161,14 +161,33 @@ body {
161
161
  }
162
162
 
163
163
  /* Logo dark mode - brighten for visibility */
164
- [data-theme="dark"] .logo-img,
165
- [data-theme="dark"] .logo-icon img {
164
+ .logo-dark {
165
+ display: none;
166
+ }
167
+
168
+ [data-theme="dark"] .logo-light {
169
+ display: none;
170
+ }
171
+
172
+ [data-theme="dark"] .logo-dark {
173
+ display: block;
174
+ }
175
+
176
+ /* Logo dark mode - brighten for visibility (only when no dark variant provided) */
177
+ [data-theme="dark"] .logo-img:not(.logo-light):not(.logo-dark),
178
+ [data-theme="dark"] .logo-icon img:not(.logo-light):not(.logo-dark) {
166
179
  filter: brightness(1.3) saturate(1.2);
167
180
  }
168
181
 
169
182
  @media (prefers-color-scheme: dark) {
170
- :root:not([data-theme="light"]) .logo-img,
171
- :root:not([data-theme="light"]) .logo-icon img {
183
+ :root:not([data-theme="light"]) .logo-light {
184
+ display: none;
185
+ }
186
+ :root:not([data-theme="light"]) .logo-dark {
187
+ display: block;
188
+ }
189
+ :root:not([data-theme="light"]) .logo-img:not(.logo-light):not(.logo-dark),
190
+ :root:not([data-theme="light"]) .logo-icon img:not(.logo-light):not(.logo-dark) {
172
191
  filter: brightness(1.3) saturate(1.2);
173
192
  }
174
193
  }
@@ -945,6 +964,22 @@ body {
945
964
  color: var(--color-link);
946
965
  }
947
966
 
967
+ .footer-logo-link {
968
+ display: inline-flex;
969
+ align-items: center;
970
+ }
971
+
972
+ .footer-logo-img {
973
+ height: auto;
974
+ width: auto;
975
+ vertical-align: middle;
976
+ opacity: 0.8;
977
+ }
978
+
979
+ .footer-logo-img:hover {
980
+ opacity: 1;
981
+ }
982
+
948
983
  /* Mermaid diagrams */
949
984
  .mermaid {
950
985
  background: transparent;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kitfly",
3
- "version": "0.2.1",
3
+ "version": "0.2.4",
4
4
  "type": "module",
5
5
  "description": "Turn your writing into a website",
6
6
  "bin": {
@@ -0,0 +1,140 @@
1
+ (() => {
2
+ function isCurrency(expr) {
3
+ return /^\d[\d,]*(?:\.\d+)?(?:\s*(?:to|-)\s*\d[\d,]*(?:\.\d+)?)?$/.test(expr.trim());
4
+ }
5
+
6
+ function shouldTreatAsLiteralInline(expr, text, closingIndex) {
7
+ if (/^\s|\s$/.test(expr) || /\n/.test(expr) || isCurrency(expr)) return true;
8
+ // Guard common currency range form "$5-$10" where expr becomes "5-".
9
+ if (/-\s*$/.test(expr)) {
10
+ const tail = text.slice(closingIndex + 1);
11
+ if (/^\d/.test(tail)) return true;
12
+ }
13
+ return false;
14
+ }
15
+
16
+ function findClosing(text, start, display) {
17
+ for (let i = start; i < text.length; i++) {
18
+ if (text[i] === "\\" && text[i + 1] === "$") {
19
+ i++;
20
+ continue;
21
+ }
22
+ if (display) {
23
+ if (text[i] === "$" && text[i + 1] === "$") return i;
24
+ } else if (text[i] === "$" && text[i - 1] !== "$" && text[i + 1] !== "$") {
25
+ return i;
26
+ }
27
+ }
28
+ return -1;
29
+ }
30
+
31
+ function splitMath(text) {
32
+ const out = [];
33
+ let buf = "";
34
+ let i = 0;
35
+
36
+ while (i < text.length) {
37
+ if (text[i] === "\\" && text[i + 1] === "$") {
38
+ buf += "$";
39
+ i += 2;
40
+ continue;
41
+ }
42
+ if (text[i] !== "$") {
43
+ buf += text[i++];
44
+ continue;
45
+ }
46
+
47
+ const display = text[i + 1] === "$";
48
+ const openLen = display ? 2 : 1;
49
+ const end = findClosing(text, i + openLen, display);
50
+ if (end < 0) {
51
+ buf += display ? "$$" : "$";
52
+ i += openLen;
53
+ continue;
54
+ }
55
+
56
+ const expr = text.slice(i + openLen, end);
57
+ if (!display && shouldTreatAsLiteralInline(expr, text, end)) {
58
+ buf += `$${expr}$`;
59
+ i = end + 1;
60
+ continue;
61
+ }
62
+
63
+ if (buf) out.push({ text: buf });
64
+ out.push({ math: expr, display });
65
+ buf = "";
66
+ i = end + openLen;
67
+ }
68
+
69
+ if (buf) out.push({ text: buf });
70
+ return out;
71
+ }
72
+
73
+ function renderFencedMath() {
74
+ document.querySelectorAll("pre > code.language-math").forEach((code) => {
75
+ const pre = code.parentElement;
76
+ if (!pre || pre.tagName !== "PRE") return;
77
+ const host = document.createElement("div");
78
+ host.className = "kitfly-katex-display";
79
+ window.katex.render(code.textContent || "", host, { displayMode: true, throwOnError: false });
80
+ pre.replaceWith(host);
81
+ });
82
+ }
83
+
84
+ function renderDelimitedMath() {
85
+ const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
86
+ const nodes = [];
87
+ while (walker.nextNode()) {
88
+ const node = walker.currentNode;
89
+ const parent = node.parentElement;
90
+ if (!parent || parent.closest("pre, code, script, style, textarea, .katex")) continue;
91
+ if (!(node.textContent || "").includes("$")) continue;
92
+ nodes.push(node);
93
+ }
94
+
95
+ for (const node of nodes) {
96
+ const parts = splitMath(node.textContent || "");
97
+ if (!parts.some((p) => p.math)) continue;
98
+ const frag = document.createDocumentFragment();
99
+ for (const p of parts) {
100
+ if (p.text != null) {
101
+ frag.appendChild(document.createTextNode(p.text));
102
+ } else if (p.math != null) {
103
+ const host = document.createElement("span");
104
+ host.className = p.display ? "kitfly-katex-display" : "kitfly-katex-inline";
105
+ window.katex.render(p.math, host, { displayMode: Boolean(p.display), throwOnError: false });
106
+ frag.appendChild(host);
107
+ }
108
+ }
109
+ node.replaceWith(frag);
110
+ }
111
+ }
112
+
113
+ function apply() {
114
+ const styleId = "kitfly-latex-style";
115
+ if (!document.getElementById(styleId)) {
116
+ const style = document.createElement("style");
117
+ style.id = styleId;
118
+ style.textContent = ".kitfly-katex-display{display:block;text-align:center;margin:1em 0;overflow-x:auto}";
119
+ document.head.appendChild(style);
120
+ }
121
+
122
+ if (!window.katex?.render) {
123
+ console.warn("[kitfly:latex] KaTeX unavailable");
124
+ return;
125
+ }
126
+
127
+ renderFencedMath();
128
+ renderDelimitedMath();
129
+ }
130
+
131
+ if (typeof document === "undefined") {
132
+ globalThis.__kitflyLatexTest = { splitMath, isCurrency, shouldTreatAsLiteralInline };
133
+ return;
134
+ }
135
+ if (document.readyState === "loading") {
136
+ document.addEventListener("DOMContentLoaded", apply);
137
+ } else {
138
+ apply();
139
+ }
140
+ })();
@@ -0,0 +1,178 @@
1
+ (() => {
2
+ const KATEX_CSS_URL = "https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css";
3
+ const KATEX_CSS_SRI = "sha384-zh0CIslj+VczCZtlzBcjt5ppRcsAmDnRem7ESsYwWwg3m/OaJ2l4x7YBZl9Kxxib";
4
+ const KATEX_JS_URL = "https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js";
5
+ const KATEX_JS_SRI = "sha384-Rma6DA2IPUwhNxmrB/7S3Tno0YY7sFu9WSYMCuulLhIqYSGZ2gKCJWIqhBWqMQfh";
6
+
7
+ function isCurrency(expr) {
8
+ return /^\d[\d,]*(?:\.\d+)?(?:\s*(?:to|-)\s*\d[\d,]*(?:\.\d+)?)?$/.test(expr.trim());
9
+ }
10
+
11
+ function shouldTreatAsLiteralInline(expr, text, closingIndex) {
12
+ if (/^\s|\s$/.test(expr) || /\n/.test(expr) || isCurrency(expr)) return true;
13
+ // Guard common currency range form "$5-$10" where expr becomes "5-".
14
+ if (/-\s*$/.test(expr)) {
15
+ const tail = text.slice(closingIndex + 1);
16
+ if (/^\d/.test(tail)) return true;
17
+ }
18
+ return false;
19
+ }
20
+
21
+ function findClosing(text, start, display) {
22
+ for (let i = start; i < text.length; i++) {
23
+ if (text[i] === "\\" && text[i + 1] === "$") {
24
+ i++;
25
+ continue;
26
+ }
27
+ if (display) {
28
+ if (text[i] === "$" && text[i + 1] === "$") return i;
29
+ } else if (text[i] === "$" && text[i - 1] !== "$" && text[i + 1] !== "$") {
30
+ return i;
31
+ }
32
+ }
33
+ return -1;
34
+ }
35
+
36
+ function splitMath(text) {
37
+ const out = [];
38
+ let buf = "";
39
+ let i = 0;
40
+
41
+ while (i < text.length) {
42
+ if (text[i] === "\\" && text[i + 1] === "$") {
43
+ buf += "$";
44
+ i += 2;
45
+ continue;
46
+ }
47
+ if (text[i] !== "$") {
48
+ buf += text[i++];
49
+ continue;
50
+ }
51
+
52
+ const display = text[i + 1] === "$";
53
+ const openLen = display ? 2 : 1;
54
+ const end = findClosing(text, i + openLen, display);
55
+ if (end < 0) {
56
+ buf += display ? "$$" : "$";
57
+ i += openLen;
58
+ continue;
59
+ }
60
+
61
+ const expr = text.slice(i + openLen, end);
62
+ if (!display && shouldTreatAsLiteralInline(expr, text, end)) {
63
+ buf += `$${expr}$`;
64
+ i = end + 1;
65
+ continue;
66
+ }
67
+
68
+ if (buf) out.push({ text: buf });
69
+ out.push({ math: expr, display });
70
+ buf = "";
71
+ i = end + openLen;
72
+ }
73
+
74
+ if (buf) out.push({ text: buf });
75
+ return out;
76
+ }
77
+
78
+ function ensureTag(tag, attrs) {
79
+ const id = attrs["data-kitfly-latex"];
80
+ const existing = document.querySelector(`${tag}[data-kitfly-latex="${id}"]`);
81
+ if (existing) return Promise.resolve(existing);
82
+ return new Promise((resolve, reject) => {
83
+ const el = document.createElement(tag);
84
+ Object.entries(attrs).forEach(([k, v]) => el.setAttribute(k, v));
85
+ el.addEventListener("load", () => resolve(el), { once: true });
86
+ el.addEventListener("error", () => reject(new Error(`Failed to load ${attrs.href || attrs.src}`)), {
87
+ once: true,
88
+ });
89
+ document.head.appendChild(el);
90
+ });
91
+ }
92
+
93
+ function renderFencedMath() {
94
+ document.querySelectorAll("pre > code.language-math").forEach((code) => {
95
+ const pre = code.parentElement;
96
+ if (!pre || pre.tagName !== "PRE") return;
97
+ const host = document.createElement("div");
98
+ host.className = "kitfly-katex-display";
99
+ window.katex.render(code.textContent || "", host, { displayMode: true, throwOnError: false });
100
+ pre.replaceWith(host);
101
+ });
102
+ }
103
+
104
+ function renderDelimitedMath() {
105
+ const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT);
106
+ const nodes = [];
107
+ while (walker.nextNode()) {
108
+ const node = walker.currentNode;
109
+ const parent = node.parentElement;
110
+ if (!parent || parent.closest("pre, code, script, style, textarea, .katex")) continue;
111
+ if (!(node.textContent || "").includes("$")) continue;
112
+ nodes.push(node);
113
+ }
114
+
115
+ for (const node of nodes) {
116
+ const parts = splitMath(node.textContent || "");
117
+ if (!parts.some((p) => p.math)) continue;
118
+ const frag = document.createDocumentFragment();
119
+ for (const p of parts) {
120
+ if (p.text != null) {
121
+ frag.appendChild(document.createTextNode(p.text));
122
+ } else if (p.math != null) {
123
+ const host = document.createElement("span");
124
+ host.className = p.display ? "kitfly-katex-display" : "kitfly-katex-inline";
125
+ window.katex.render(p.math, host, { displayMode: Boolean(p.display), throwOnError: false });
126
+ frag.appendChild(host);
127
+ }
128
+ }
129
+ node.replaceWith(frag);
130
+ }
131
+ }
132
+
133
+ function apply() {
134
+ const styleId = "kitfly-latex-style";
135
+ if (!document.getElementById(styleId)) {
136
+ const style = document.createElement("style");
137
+ style.id = styleId;
138
+ style.textContent = ".kitfly-katex-display{display:block;text-align:center;margin:1em 0;overflow-x:auto}";
139
+ document.head.appendChild(style);
140
+ }
141
+
142
+ Promise.all([
143
+ ensureTag("link", {
144
+ rel: "stylesheet",
145
+ href: KATEX_CSS_URL,
146
+ integrity: KATEX_CSS_SRI,
147
+ crossorigin: "anonymous",
148
+ "data-kitfly-latex": "css",
149
+ }),
150
+ ensureTag("script", {
151
+ src: KATEX_JS_URL,
152
+ integrity: KATEX_JS_SRI,
153
+ crossorigin: "anonymous",
154
+ defer: "",
155
+ "data-kitfly-latex": "js",
156
+ }),
157
+ ])
158
+ .then(() => {
159
+ if (!window.katex?.render) {
160
+ console.warn("[kitfly:latex] KaTeX unavailable");
161
+ return;
162
+ }
163
+ renderFencedMath();
164
+ renderDelimitedMath();
165
+ })
166
+ .catch((e) => console.warn("[kitfly:latex]", e instanceof Error ? e.message : String(e)));
167
+ }
168
+
169
+ if (typeof document === "undefined") {
170
+ globalThis.__kitflyLatexTest = { splitMath, isCurrency, shouldTreatAsLiteralInline };
171
+ return;
172
+ }
173
+ if (document.readyState === "loading") {
174
+ document.addEventListener("DOMContentLoaded", apply);
175
+ } else {
176
+ apply();
177
+ }
178
+ })();
@@ -0,0 +1,261 @@
1
+ :root {
2
+ --kitfly-visual-border: var(--color-border);
3
+ --kitfly-visual-bg: color-mix(in srgb, var(--color-bg-sidebar) 88%, var(--color-bg));
4
+ --kitfly-visual-muted: var(--color-text-muted);
5
+ --kitfly-visual-accent: var(--color-link);
6
+ --kitfly-visual-success: #16a34a;
7
+ --kitfly-visual-warning: #d97706;
8
+ }
9
+
10
+ @media (prefers-color-scheme: dark) {
11
+ :root {
12
+ --kitfly-visual-success: #4ade80;
13
+ --kitfly-visual-warning: #fbbf24;
14
+ }
15
+ }
16
+
17
+ .kitfly-visual {
18
+ border: 1px solid var(--kitfly-visual-border);
19
+ background: var(--kitfly-visual-bg);
20
+ border-radius: 12px;
21
+ padding: 0.85rem;
22
+ margin: 0.75rem 0;
23
+ }
24
+
25
+ .kitfly-planning-gantt {
26
+ display: grid;
27
+ gap: 0.45rem;
28
+ overflow-x: auto;
29
+ }
30
+
31
+ .kitfly-gantt-title {
32
+ font-weight: 800;
33
+ font-size: 0.95rem;
34
+ }
35
+
36
+ .kitfly-gantt-row {
37
+ display: grid;
38
+ grid-template-columns: minmax(10rem, 30%) 1fr;
39
+ gap: 0.65rem;
40
+ align-items: center;
41
+ min-width: 38rem;
42
+ }
43
+
44
+ .kitfly-gantt-label {
45
+ min-width: 0;
46
+ overflow: hidden;
47
+ text-overflow: ellipsis;
48
+ white-space: nowrap;
49
+ font-size: 0.92rem;
50
+ padding-left: calc((var(--kitfly-gantt-depth, 1) - 1) * 0.9rem);
51
+ }
52
+
53
+ .kitfly-gantt-label.depth-1 {
54
+ font-weight: 800;
55
+ }
56
+
57
+ .kitfly-gantt-axis {
58
+ position: relative;
59
+ display: grid;
60
+ grid-template-columns: repeat(var(--kitfly-gantt-units), minmax(0, 1fr));
61
+ border: 1px solid color-mix(in srgb, var(--kitfly-visual-border) 78%, transparent);
62
+ border-radius: 8px;
63
+ background: color-mix(in srgb, var(--kitfly-visual-bg) 75%, var(--color-bg));
64
+ overflow: hidden;
65
+ }
66
+
67
+ .kitfly-gantt-axis-cell {
68
+ min-width: 0;
69
+ padding: 0.2rem 0.12rem;
70
+ font-size: 0.72rem;
71
+ color: var(--kitfly-visual-muted);
72
+ border-right: 1px solid color-mix(in srgb, var(--kitfly-visual-border) 45%, transparent);
73
+ white-space: nowrap;
74
+ overflow: hidden;
75
+ text-overflow: ellipsis;
76
+ text-align: center;
77
+ }
78
+
79
+ .kitfly-gantt-axis-cell:last-child {
80
+ border-right: 0;
81
+ }
82
+
83
+ .kitfly-gantt-axis-context-row {
84
+ margin-bottom: -0.2rem;
85
+ }
86
+
87
+ .kitfly-gantt-axis-context {
88
+ font-size: 0.68rem;
89
+ letter-spacing: 0.01em;
90
+ color: var(--kitfly-visual-muted);
91
+ text-transform: uppercase;
92
+ }
93
+
94
+ .kitfly-planning-gantt.is-week-compact .kitfly-gantt-axis-cell {
95
+ font-size: 0.66rem;
96
+ padding-inline: 0.06rem;
97
+ }
98
+
99
+ .kitfly-planning-gantt.is-week-ultra-compact .kitfly-gantt-axis-cell {
100
+ font-size: 0.62rem;
101
+ padding-inline: 0.04rem;
102
+ }
103
+
104
+ .kitfly-planning-gantt.is-week .kitfly-gantt-axis-cell.is-labeled {
105
+ overflow: visible;
106
+ text-overflow: clip;
107
+ position: relative;
108
+ z-index: 1;
109
+ }
110
+
111
+ .kitfly-planning-gantt.is-week .kitfly-gantt-axis-cell.is-edge:first-child {
112
+ text-align: left;
113
+ }
114
+
115
+ .kitfly-planning-gantt.is-week .kitfly-gantt-axis-cell.is-edge:last-child {
116
+ text-align: right;
117
+ }
118
+
119
+ .kitfly-gantt-chart {
120
+ position: relative;
121
+ min-height: 1.6rem;
122
+ border: 1px solid color-mix(in srgb, var(--kitfly-visual-border) 70%, transparent);
123
+ border-radius: 8px;
124
+ background-color: color-mix(in srgb, var(--kitfly-visual-bg) 78%, var(--color-bg));
125
+ background-image: linear-gradient(
126
+ to right,
127
+ color-mix(in srgb, var(--kitfly-visual-border) 45%, transparent) 1px,
128
+ transparent 1px
129
+ );
130
+ background-size: calc(100% / var(--kitfly-gantt-units)) 100%;
131
+ overflow: hidden;
132
+ }
133
+
134
+ .kitfly-gantt-bar {
135
+ position: absolute;
136
+ top: 50%;
137
+ transform: translateY(-50%);
138
+ border-radius: 999px;
139
+ min-width: 0.35rem;
140
+ }
141
+
142
+ .kitfly-gantt-bar.depth-1 {
143
+ height: 0.56rem;
144
+ }
145
+
146
+ .kitfly-gantt-bar.depth-2 {
147
+ height: 0.46rem;
148
+ }
149
+
150
+ .kitfly-gantt-bar.depth-3 {
151
+ height: 0.4rem;
152
+ }
153
+
154
+ .kitfly-gantt-bar.is-planned {
155
+ background: color-mix(in srgb, var(--kitfly-visual-muted) 50%, transparent);
156
+ }
157
+
158
+ .kitfly-gantt-bar.is-active {
159
+ background: color-mix(in srgb, var(--kitfly-visual-accent) 78%, var(--color-text));
160
+ }
161
+
162
+ .kitfly-gantt-bar.is-complete {
163
+ background: var(--kitfly-visual-success);
164
+ }
165
+
166
+ .kitfly-gantt-bar.is-blocked {
167
+ background: var(--kitfly-visual-warning);
168
+ }
169
+
170
+ .kitfly-gantt-milestone {
171
+ position: absolute;
172
+ top: 50%;
173
+ width: 0.62rem;
174
+ height: 0.62rem;
175
+ transform: translate(-50%, -50%) rotate(45deg);
176
+ background: color-mix(in srgb, var(--kitfly-visual-accent) 70%, var(--color-text));
177
+ border: 1px solid color-mix(in srgb, var(--kitfly-visual-border) 80%, transparent);
178
+ }
179
+
180
+ .kitfly-gantt-today {
181
+ position: absolute;
182
+ top: 0;
183
+ bottom: 0;
184
+ width: 0;
185
+ border-left: 1px dashed color-mix(in srgb, var(--kitfly-visual-muted) 55%, transparent);
186
+ transform: translateX(-50%);
187
+ pointer-events: none;
188
+ z-index: 2;
189
+ }
190
+
191
+ .kitfly-gantt-marker-line {
192
+ --kitfly-marker-color: color-mix(in srgb, var(--kitfly-visual-accent) 95%, var(--color-text));
193
+ position: absolute;
194
+ top: 0;
195
+ bottom: 0;
196
+ width: 0;
197
+ border-left: 3px solid var(--kitfly-marker-color);
198
+ transform: translateX(-50%);
199
+ pointer-events: none;
200
+ z-index: 3;
201
+ }
202
+
203
+ .kitfly-gantt-marker-line::before {
204
+ content: "";
205
+ position: absolute;
206
+ top: 0.14rem;
207
+ left: -0.22rem;
208
+ width: 0.38rem;
209
+ height: 0.38rem;
210
+ transform: rotate(45deg);
211
+ background: var(--kitfly-marker-color);
212
+ border: 1px solid color-mix(in srgb, var(--kitfly-visual-border) 75%, transparent);
213
+ border-radius: 0.1rem;
214
+ }
215
+
216
+ .kitfly-gantt-marker-row {
217
+ margin-bottom: 0.08rem;
218
+ }
219
+
220
+ .kitfly-gantt-marker-area {
221
+ position: relative;
222
+ min-height: calc(1.38rem + (var(--kitfly-marker-lanes, 1) - 1) * 0.98rem);
223
+ }
224
+
225
+ .kitfly-gantt-marker-label {
226
+ --kitfly-marker-color: color-mix(in srgb, var(--kitfly-visual-accent) 95%, var(--color-text));
227
+ position: absolute;
228
+ top: calc(0.08rem + var(--kitfly-marker-lane, 0) * 0.96rem);
229
+ font-size: 0.72rem;
230
+ font-weight: 700;
231
+ line-height: 1.25;
232
+ color: color-mix(in srgb, var(--kitfly-marker-color) 88%, var(--color-text));
233
+ white-space: nowrap;
234
+ max-width: 10rem;
235
+ padding: 0.08rem 0.38rem;
236
+ border-radius: 999px;
237
+ border: 1px solid color-mix(in srgb, var(--kitfly-marker-color) 45%, var(--kitfly-visual-border));
238
+ background: color-mix(in srgb, var(--kitfly-visual-bg) 72%, var(--color-bg));
239
+ box-shadow: 0 1px 0 color-mix(in srgb, var(--kitfly-visual-border) 55%, transparent);
240
+ overflow: hidden;
241
+ text-overflow: ellipsis;
242
+ transform: translateX(0.35rem);
243
+ pointer-events: none;
244
+ z-index: 4;
245
+ }
246
+
247
+ .kitfly-gantt-marker-label.is-flipped {
248
+ transform: translateX(calc(-100% - 0.3rem));
249
+ }
250
+
251
+ .kitfly-gantt-overflow-row .kitfly-gantt-label {
252
+ color: var(--kitfly-visual-muted);
253
+ font-style: italic;
254
+ }
255
+
256
+ @media (max-width: 700px) {
257
+ .kitfly-gantt-row {
258
+ min-width: 32rem;
259
+ grid-template-columns: minmax(8rem, 36%) 1fr;
260
+ }
261
+ }