@taloswork/ose-shared 0.1.7 → 0.1.9

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 (166) hide show
  1. package/package.json +3 -3
  2. package/skills/cozy-static-svg/SKILL.md +76 -0
  3. package/skills/cozy-static-svg/references/approved-preview.png +0 -0
  4. package/skills/cozy-static-svg/references/cross-platform.md +73 -0
  5. package/skills/cozy-static-svg/references/moon_keeps_watch.svg +229 -0
  6. package/skills/cozy-static-svg/references/style-anchor.md +271 -0
  7. package/skills/cozy-static-svg/scripts/artkit.py +321 -0
  8. package/skills/cozy-static-svg/scripts/to_png.py +333 -0
  9. package/skills/diagram-design/SKILL.md +568 -0
  10. package/skills/diagram-design/assets/example-architecture-dark.html +182 -0
  11. package/skills/diagram-design/assets/example-architecture-full.html +194 -0
  12. package/skills/diagram-design/assets/example-architecture.html +183 -0
  13. package/skills/diagram-design/assets/example-bar-dark.html +129 -0
  14. package/skills/diagram-design/assets/example-bar-full.html +105 -0
  15. package/skills/diagram-design/assets/example-bar.html +129 -0
  16. package/skills/diagram-design/assets/example-data-flow-dark.html +143 -0
  17. package/skills/diagram-design/assets/example-data-flow-full.html +185 -0
  18. package/skills/diagram-design/assets/example-data-flow.html +143 -0
  19. package/skills/diagram-design/assets/example-datalake-dark.html +243 -0
  20. package/skills/diagram-design/assets/example-datalake-full.html +248 -0
  21. package/skills/diagram-design/assets/example-datalake.html +269 -0
  22. package/skills/diagram-design/assets/example-dp-integration-dark.html +80 -0
  23. package/skills/diagram-design/assets/example-dp-integration-full.html +90 -0
  24. package/skills/diagram-design/assets/example-dp-integration.html +80 -0
  25. package/skills/diagram-design/assets/example-dp-security-matrix-dark.html +31 -0
  26. package/skills/diagram-design/assets/example-dp-security-matrix-full.html +32 -0
  27. package/skills/diagram-design/assets/example-dp-security-matrix.html +88 -0
  28. package/skills/diagram-design/assets/example-er-dark.html +202 -0
  29. package/skills/diagram-design/assets/example-er-full.html +205 -0
  30. package/skills/diagram-design/assets/example-er.html +202 -0
  31. package/skills/diagram-design/assets/example-flowchart-dark.html +156 -0
  32. package/skills/diagram-design/assets/example-flowchart-full.html +159 -0
  33. package/skills/diagram-design/assets/example-flowchart.html +156 -0
  34. package/skills/diagram-design/assets/example-gantt-dark.html +137 -0
  35. package/skills/diagram-design/assets/example-gantt-full.html +127 -0
  36. package/skills/diagram-design/assets/example-gantt.html +137 -0
  37. package/skills/diagram-design/assets/example-high-level-dark.html +251 -0
  38. package/skills/diagram-design/assets/example-high-level-full.html +247 -0
  39. package/skills/diagram-design/assets/example-high-level-vertical-dark.html +274 -0
  40. package/skills/diagram-design/assets/example-high-level-vertical-full.html +252 -0
  41. package/skills/diagram-design/assets/example-high-level-vertical.html +325 -0
  42. package/skills/diagram-design/assets/example-high-level.html +301 -0
  43. package/skills/diagram-design/assets/example-import-drawio.html +185 -0
  44. package/skills/diagram-design/assets/example-import-mermaid.html +70 -0
  45. package/skills/diagram-design/assets/example-it-state-dark.html +90 -0
  46. package/skills/diagram-design/assets/example-it-state-full.html +69 -0
  47. package/skills/diagram-design/assets/example-it-state.html +128 -0
  48. package/skills/diagram-design/assets/example-layers-dark.html +123 -0
  49. package/skills/diagram-design/assets/example-layers-full.html +126 -0
  50. package/skills/diagram-design/assets/example-layers.html +123 -0
  51. package/skills/diagram-design/assets/example-line-dark.html +111 -0
  52. package/skills/diagram-design/assets/example-line-full.html +105 -0
  53. package/skills/diagram-design/assets/example-line.html +111 -0
  54. package/skills/diagram-design/assets/example-loop-dark.html +100 -0
  55. package/skills/diagram-design/assets/example-loop-full.html +137 -0
  56. package/skills/diagram-design/assets/example-loop-terminal.html +347 -0
  57. package/skills/diagram-design/assets/example-loop.html +100 -0
  58. package/skills/diagram-design/assets/example-medallion-dark.html +159 -0
  59. package/skills/diagram-design/assets/example-medallion-full.html +201 -0
  60. package/skills/diagram-design/assets/example-medallion.html +159 -0
  61. package/skills/diagram-design/assets/example-nested-dark.html +132 -0
  62. package/skills/diagram-design/assets/example-nested-full.html +135 -0
  63. package/skills/diagram-design/assets/example-nested.html +136 -0
  64. package/skills/diagram-design/assets/example-org-chart-dark.html +45 -0
  65. package/skills/diagram-design/assets/example-org-chart-full.html +45 -0
  66. package/skills/diagram-design/assets/example-org-chart.html +45 -0
  67. package/skills/diagram-design/assets/example-paved-road-animated.html +546 -0
  68. package/skills/diagram-design/assets/example-policy-trace-animated.html +490 -0
  69. package/skills/diagram-design/assets/example-process-dark.html +64 -0
  70. package/skills/diagram-design/assets/example-process-full.html +74 -0
  71. package/skills/diagram-design/assets/example-process.html +64 -0
  72. package/skills/diagram-design/assets/example-pyramid-dark.html +119 -0
  73. package/skills/diagram-design/assets/example-pyramid-full.html +122 -0
  74. package/skills/diagram-design/assets/example-pyramid.html +119 -0
  75. package/skills/diagram-design/assets/example-quadrant-consultant.html +166 -0
  76. package/skills/diagram-design/assets/example-quadrant-dark.html +135 -0
  77. package/skills/diagram-design/assets/example-quadrant-full.html +138 -0
  78. package/skills/diagram-design/assets/example-quadrant.html +135 -0
  79. package/skills/diagram-design/assets/example-queue-animated.html +577 -0
  80. package/skills/diagram-design/assets/example-radar-dark.html +139 -0
  81. package/skills/diagram-design/assets/example-radar-full.html +135 -0
  82. package/skills/diagram-design/assets/example-radar.html +139 -0
  83. package/skills/diagram-design/assets/example-scatter-dark.html +141 -0
  84. package/skills/diagram-design/assets/example-scatter-full.html +116 -0
  85. package/skills/diagram-design/assets/example-scatter.html +141 -0
  86. package/skills/diagram-design/assets/example-sequence-dark.html +222 -0
  87. package/skills/diagram-design/assets/example-sequence-full.html +388 -0
  88. package/skills/diagram-design/assets/example-sequence-oauth-dark.html +188 -0
  89. package/skills/diagram-design/assets/example-sequence-oauth-full.html +350 -0
  90. package/skills/diagram-design/assets/example-sequence-oauth.html +227 -0
  91. package/skills/diagram-design/assets/example-sequence.html +222 -0
  92. package/skills/diagram-design/assets/example-state-dark.html +147 -0
  93. package/skills/diagram-design/assets/example-state-full.html +150 -0
  94. package/skills/diagram-design/assets/example-state.html +147 -0
  95. package/skills/diagram-design/assets/example-swimlane-dark.html +172 -0
  96. package/skills/diagram-design/assets/example-swimlane-full.html +175 -0
  97. package/skills/diagram-design/assets/example-swimlane.html +172 -0
  98. package/skills/diagram-design/assets/example-timeline-dark.html +135 -0
  99. package/skills/diagram-design/assets/example-timeline-full.html +138 -0
  100. package/skills/diagram-design/assets/example-timeline.html +135 -0
  101. package/skills/diagram-design/assets/example-tree-dark.html +173 -0
  102. package/skills/diagram-design/assets/example-tree-full.html +176 -0
  103. package/skills/diagram-design/assets/example-tree.html +173 -0
  104. package/skills/diagram-design/assets/example-venn-dark.html +132 -0
  105. package/skills/diagram-design/assets/example-venn-full.html +135 -0
  106. package/skills/diagram-design/assets/example-venn.html +110 -0
  107. package/skills/diagram-design/assets/icons.html +230 -0
  108. package/skills/diagram-design/assets/index.html +369 -0
  109. package/skills/diagram-design/assets/template-dark.html +85 -0
  110. package/skills/diagram-design/assets/template-full.html +413 -0
  111. package/skills/diagram-design/assets/template-motion.html +434 -0
  112. package/skills/diagram-design/assets/template-terminal.html +173 -0
  113. package/skills/diagram-design/assets/template.html +86 -0
  114. package/skills/diagram-design/references/animation.md +141 -0
  115. package/skills/diagram-design/references/export.md +136 -0
  116. package/skills/diagram-design/references/import-drawio.md +171 -0
  117. package/skills/diagram-design/references/import-mermaid.md +126 -0
  118. package/skills/diagram-design/references/onboarding.md +297 -0
  119. package/skills/diagram-design/references/output-spec.md +181 -0
  120. package/skills/diagram-design/references/primitive-annotation.md +36 -0
  121. package/skills/diagram-design/references/primitive-icons.md +827 -0
  122. package/skills/diagram-design/references/primitive-sketchy.md +43 -0
  123. package/skills/diagram-design/references/primitive-terminal.md +76 -0
  124. package/skills/diagram-design/references/semantic-patterns.md +122 -0
  125. package/skills/diagram-design/references/style-guide.md +139 -0
  126. package/skills/diagram-design/references/type-architecture.md +78 -0
  127. package/skills/diagram-design/references/type-bar.md +48 -0
  128. package/skills/diagram-design/references/type-data-flow.md +374 -0
  129. package/skills/diagram-design/references/type-dp-integration.md +410 -0
  130. package/skills/diagram-design/references/type-dp-security-matrix.md +379 -0
  131. package/skills/diagram-design/references/type-er.md +23 -0
  132. package/skills/diagram-design/references/type-flowchart.md +23 -0
  133. package/skills/diagram-design/references/type-gantt.md +45 -0
  134. package/skills/diagram-design/references/type-high-level.md +458 -0
  135. package/skills/diagram-design/references/type-it-state.md +470 -0
  136. package/skills/diagram-design/references/type-layers.md +26 -0
  137. package/skills/diagram-design/references/type-line.md +44 -0
  138. package/skills/diagram-design/references/type-loop.md +223 -0
  139. package/skills/diagram-design/references/type-medallion.md +356 -0
  140. package/skills/diagram-design/references/type-nested.md +22 -0
  141. package/skills/diagram-design/references/type-org-chart.md +44 -0
  142. package/skills/diagram-design/references/type-process.md +495 -0
  143. package/skills/diagram-design/references/type-pyramid.md +33 -0
  144. package/skills/diagram-design/references/type-quadrant.md +81 -0
  145. package/skills/diagram-design/references/type-radar.md +80 -0
  146. package/skills/diagram-design/references/type-scatter.md +39 -0
  147. package/skills/diagram-design/references/type-sequence.md +130 -0
  148. package/skills/diagram-design/references/type-state.md +21 -0
  149. package/skills/diagram-design/references/type-swimlane.md +20 -0
  150. package/skills/diagram-design/references/type-timeline.md +20 -0
  151. package/skills/diagram-design/references/type-tree.md +24 -0
  152. package/skills/diagram-design/references/type-venn.md +26 -0
  153. package/skills/diagram-design/scripts/drawio_extract.py +856 -0
  154. package/skills/diagram-design/scripts/mermaid_extract.py +1285 -0
  155. package/skills/diagram-design/scripts/self_check.py +389 -0
  156. package/skills/document/bin/doc-gen.cjs +3 -6
  157. package/skills/document/bin/html2pptx.cjs +17 -9
  158. package/skills/document/bin/pptx-clone.cjs +41 -30
  159. package/skills/document/bin/pptx-embed-fonts.cjs +6 -2
  160. package/skills/document/bin/pptx-slide.cjs +46 -50
  161. package/skills/document/content-pipeline.md +54 -5
  162. package/skills/document/layouts/README.md +8 -0
  163. package/skills/document/layouts/blocks-2x2.tpl +19 -9
  164. package/skills/document/layouts/cards-3.tpl +1 -1
  165. package/skills/document/layouts/org-tree.tpl +1 -1
  166. package/skills/document/layouts/steps-vertical.tpl +1 -1
@@ -0,0 +1,222 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Article request · Sequence</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
8
+ <style>
9
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
10
+ :root {
11
+ --color-paper: #f5f5f5;
12
+ --color-ink: #2d3142;
13
+ --color-muted: #4f5d75;
14
+ --color-accent: #eb6c36;
15
+ --font-sans: 'Geist', system-ui, sans-serif;
16
+ --font-serif: 'Instrument Serif', serif;
17
+ --font-mono: 'Geist Mono', ui-monospace, monospace;
18
+ }
19
+
20
+ body {
21
+ font-family: var(--font-sans);
22
+ background: var(--color-paper);
23
+ color: var(--color-ink);
24
+ min-height: 100vh;
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ padding: 3rem 2rem;
29
+ }
30
+
31
+ .frame { max-width: 1200px; width: 100%; }
32
+
33
+ .eyebrow {
34
+ font-family: var(--font-mono);
35
+ font-size: 0.66rem;
36
+ font-weight: 500;
37
+ letter-spacing: 0.18em;
38
+ text-transform: uppercase;
39
+ color: var(--color-muted);
40
+ margin-bottom: 0.5rem;
41
+ }
42
+
43
+ h1 {
44
+ font-family: var(--font-serif);
45
+ font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
46
+ font-weight: 400;
47
+ letter-spacing: -0.02em;
48
+ line-height: 1.15;
49
+ color: var(--color-ink);
50
+ margin-bottom: 1.5rem;
51
+ }
52
+
53
+ svg { width: 100%; min-width: 900px; display: block; }
54
+ </style>
55
+ </head>
56
+ <body>
57
+ <div class="frame">
58
+ <p class="eyebrow">Sequence · Diagram Design</p>
59
+ <h1>Article request, cold cache</h1>
60
+
61
+ <svg viewBox="0 0 1000 584" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="sequence-title sequence-desc">
62
+ <title id="sequence-title">Article request, cold cache</title>
63
+ <desc id="sequence-desc">Sequence diagram showing a cold-cache article request moving from reader and browser through Cloudflare to an Astro origin and analytics beacon.</desc>
64
+ <defs>
65
+ <!-- Dot grid background -->
66
+ <pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
67
+ <circle cx="1" cy="1" r="0.9" fill="rgba(45,49,66,0.10)"/>
68
+ </pattern>
69
+
70
+ <!-- Arrow markers -->
71
+ <marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
72
+ <polygon points="0 0, 8 3, 0 6" fill="#4f5d75"/>
73
+ </marker>
74
+ <marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
75
+ <polygon points="0 0, 8 3, 0 6" fill="#eb6c36"/>
76
+ </marker>
77
+ <marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
78
+ <polygon points="0 0, 8 3, 0 6" fill="#2e5aa8"/>
79
+ </marker>
80
+ </defs>
81
+
82
+ <!-- Background: paper + dot grid -->
83
+ <rect width="100%" height="100%" fill="#f5f5f5"/>
84
+ <rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
85
+
86
+ <!-- =================================================================
87
+ LIFELINES — dashed vertical lines from each actor, behind everything.
88
+ Actor lifeline x-coords: 128, 352, 584, 800
89
+ ================================================================= -->
90
+ <line x1="128" y1="128" x2="128" y2="488" stroke="rgba(45,49,66,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
91
+ <line x1="352" y1="128" x2="352" y2="488" stroke="rgba(45,49,66,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
92
+ <line x1="584" y1="128" x2="584" y2="488" stroke="rgba(45,49,66,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
93
+ <line x1="800" y1="128" x2="800" y2="488" stroke="rgba(45,49,66,0.22)" stroke-width="1" stroke-dasharray="3,3"/>
94
+
95
+ <!-- =================================================================
96
+ ACTIVATION BARS — w=8 rects on lifelines showing control duration.
97
+ Drawn before message arrows so arrows land on their edges.
98
+ ================================================================= -->
99
+ <!-- Cloudflare activation: receives at y=176, responds at y=408 -->
100
+ <rect x="348" y="180" width="8" height="232" fill="rgba(45,49,66,0.06)" stroke="#4f5d75" stroke-width="0.8"/>
101
+ <!-- Astro activation: called at y=232, returns at y=352 -->
102
+ <rect x="580" y="236" width="8" height="120" fill="rgba(45,49,66,0.06)" stroke="#4f5d75" stroke-width="0.8"/>
103
+
104
+ <!-- =================================================================
105
+ MESSAGE ARROWS — time flows top→down.
106
+ Draw before labels so label masks cover the line.
107
+ ================================================================= -->
108
+
109
+ <!-- M1: Reader → Cloudflare (HTTPS request · link-blue) -->
110
+ <line x1="128" y1="176" x2="352" y2="176" stroke="#2e5aa8" stroke-width="1.2" marker-end="url(#arrow-link)"/>
111
+
112
+ <!-- M2: Cloudflare → Astro (cache miss · muted) -->
113
+ <line x1="352" y1="232" x2="580" y2="232" stroke="#4f5d75" stroke-width="1.2" marker-end="url(#arrow)"/>
114
+
115
+ <!-- M3: Astro self-message (render MDX · muted U-loop) -->
116
+ <path d="M 588 284 L 624 284 L 624 316 L 588 316" fill="none" stroke="#4f5d75" stroke-width="1.2" marker-end="url(#arrow)"/>
117
+
118
+ <!-- M4: Astro → Cloudflare (return HTML · muted dashed) -->
119
+ <line x1="580" y1="352" x2="356" y2="352" stroke="#4f5d75" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
120
+
121
+ <!-- M5: Cloudflare → Reader (primary success · coral) -->
122
+ <line x1="348" y1="408" x2="128" y2="408" stroke="#eb6c36" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
123
+
124
+ <!-- M6: Reader → Analytics (async beacon · muted dashed) -->
125
+ <line x1="128" y1="464" x2="800" y2="464" stroke="#4f5d75" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
126
+
127
+ <!-- =================================================================
128
+ MESSAGE LABELS — each with an opaque paper-colored mask.
129
+ ================================================================= -->
130
+
131
+ <!-- M1 label -->
132
+ <rect x="188" y="160" width="104" height="12" rx="2" fill="#f5f5f5"/>
133
+ <text x="240" y="170" fill="#2e5aa8" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">GET /ARTICLES/SLUG</text>
134
+
135
+ <!-- M2 label -->
136
+ <rect x="416" y="216" width="100" height="12" rx="2" fill="#f5f5f5"/>
137
+ <text x="466" y="226" fill="#4f5d75" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CACHE MISS · ORIGIN</text>
138
+
139
+ <!-- M3 label (to the right of the self-loop) -->
140
+ <rect x="632" y="292" width="72" height="12" rx="2" fill="#f5f5f5"/>
141
+ <text x="668" y="302" fill="#4f5d75" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">RENDER MDX</text>
142
+
143
+ <!-- M4 label -->
144
+ <rect x="420" y="336" width="96" height="12" rx="2" fill="#f5f5f5"/>
145
+ <text x="468" y="346" fill="#4f5d75" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">200 · HTML + MAX-AGE</text>
146
+
147
+ <!-- M5 label (coral · primary response) -->
148
+ <rect x="192" y="392" width="96" height="12" rx="2" fill="#f5f5f5"/>
149
+ <text x="240" y="402" fill="#eb6c36" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">200 · EDGE-CACHED</text>
150
+
151
+ <!-- M6 label (placed between Astro and Analytics lifelines, a clear gap) -->
152
+ <rect x="648" y="448" width="96" height="12" rx="2" fill="#f5f5f5"/>
153
+ <text x="696" y="458" fill="#4f5d75" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">PAGEVIEW BEACON</text>
154
+
155
+ <!-- =================================================================
156
+ ACTOR BOXES — drawn after arrows/labels.
157
+ Each actor: 144–160 wide × 56 tall. Centers: 128, 352, 584, 800.
158
+ ================================================================= -->
159
+
160
+ <!-- Actor 1: Reader (external / soft) -->
161
+ <rect x="56" y="72" width="144" height="56" rx="6" fill="#f5f5f5"/>
162
+ <rect x="56" y="72" width="144" height="56" rx="6" fill="rgba(79,93,117,0.10)" stroke="#7a8399" stroke-width="1"/>
163
+ <rect x="64" y="80" width="28" height="12" rx="2" fill="transparent" stroke="rgba(122,131,153,0.40)" stroke-width="0.8"/>
164
+ <text x="78" y="89" fill="#7a8399" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXT</text>
165
+ <text x="128" y="104" fill="#2d3142" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Reader</text>
166
+ <text x="128" y="119" fill="#4f5d75" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Browser</text>
167
+
168
+ <!-- Actor 2: Cloudflare (cloud / muted) -->
169
+ <rect x="280" y="72" width="144" height="56" rx="6" fill="#f5f5f5"/>
170
+ <rect x="280" y="72" width="144" height="56" rx="6" fill="rgba(45,49,66,0.03)" stroke="rgba(45,49,66,0.30)" stroke-width="1"/>
171
+ <rect x="288" y="80" width="32" height="12" rx="2" fill="transparent" stroke="rgba(45,49,66,0.22)" stroke-width="0.8"/>
172
+ <text x="304" y="89" fill="#7a8399" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EDGE</text>
173
+ <text x="352" y="104" fill="#2d3142" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Cloudflare</text>
174
+ <text x="352" y="119" fill="#4f5d75" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Pages · cache</text>
175
+
176
+ <!-- Actor 3: Astro Origin (focal / coral) -->
177
+ <rect x="504" y="72" width="160" height="56" rx="6" fill="#f5f5f5"/>
178
+ <rect x="504" y="72" width="160" height="56" rx="6" fill="rgba(235,108,54,0.08)" stroke="#eb6c36" stroke-width="1"/>
179
+ <rect x="512" y="80" width="32" height="12" rx="2" fill="transparent" stroke="rgba(235,108,54,0.50)" stroke-width="0.8"/>
180
+ <text x="528" y="89" fill="#eb6c36" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ORIG</text>
181
+ <text x="584" y="104" fill="#2d3142" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Astro Origin</text>
182
+ <text x="584" y="119" fill="#4f5d75" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">SSR + MDX</text>
183
+
184
+ <!-- Actor 4: Analytics (optional / dashed) -->
185
+ <rect x="728" y="72" width="144" height="56" rx="6" fill="#f5f5f5"/>
186
+ <rect x="728" y="72" width="144" height="56" rx="6" fill="rgba(45,49,66,0.02)" stroke="rgba(45,49,66,0.22)" stroke-width="1" stroke-dasharray="4,3"/>
187
+ <rect x="736" y="80" width="28" height="12" rx="2" fill="transparent" stroke="rgba(45,49,66,0.22)" stroke-width="0.8"/>
188
+ <text x="750" y="89" fill="#7a8399" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">ASY</text>
189
+ <text x="800" y="104" fill="#2d3142" font-size="12" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Analytics</text>
190
+ <text x="800" y="119" fill="#4f5d75" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">Beacon · async</text>
191
+
192
+ <!-- =================================================================
193
+ LEGEND — horizontal strip at the bottom.
194
+ Separator at y=504, eyebrow at y=520, items at y=540–548.
195
+ ================================================================= -->
196
+ <line x1="56" y1="504" x2="944" y2="504" stroke="rgba(45,49,66,0.10)" stroke-width="0.8"/>
197
+ <text x="56" y="520" fill="#4f5d75" font-size="8" font-family="'Geist Mono', monospace" letter-spacing="0.18em">LEGEND</text>
198
+
199
+ <!-- Item 1: Actor swatch (coral focal) -->
200
+ <rect x="56" y="540" width="14" height="10" rx="2" fill="rgba(235,108,54,0.08)" stroke="#eb6c36" stroke-width="1"/>
201
+ <text x="76" y="548" fill="#4f5d75" font-size="8.5" font-family="'Geist', sans-serif">Focal actor</text>
202
+
203
+ <!-- Item 2: Activation bar swatch -->
204
+ <rect x="188" y="536" width="4" height="18" fill="rgba(45,49,66,0.06)" stroke="#4f5d75" stroke-width="0.8"/>
205
+ <text x="200" y="548" fill="#4f5d75" font-size="8.5" font-family="'Geist', sans-serif">Activation</text>
206
+
207
+ <!-- Item 3: Request arrow (link-blue) -->
208
+ <line x1="308" y1="546" x2="336" y2="546" stroke="#2e5aa8" stroke-width="1.2" marker-end="url(#arrow-link)"/>
209
+ <text x="344" y="548" fill="#4f5d75" font-size="8.5" font-family="'Geist', sans-serif">HTTP request</text>
210
+
211
+ <!-- Item 4: Return / async (muted dashed) -->
212
+ <line x1="476" y1="546" x2="504" y2="546" stroke="#4f5d75" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
213
+ <text x="512" y="548" fill="#4f5d75" font-size="8.5" font-family="'Geist', sans-serif">Return / async</text>
214
+
215
+ <!-- Item 5: Primary response (coral) -->
216
+ <line x1="652" y1="546" x2="680" y2="546" stroke="#eb6c36" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
217
+ <text x="688" y="548" fill="#4f5d75" font-size="8.5" font-family="'Geist', sans-serif">Primary response</text>
218
+
219
+ </svg>
220
+ </div>
221
+ </body>
222
+ </html>
@@ -0,0 +1,147 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Article lifecycle · State machine</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
8
+ <style>
9
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
10
+ :root {
11
+ --color-paper: #2d3142;
12
+ --color-ink: #f5f5f5;
13
+ --color-muted: #bfc0c0;
14
+ --color-accent: #f08a59;
15
+ --font-sans: 'Geist', system-ui, sans-serif;
16
+ --font-serif: 'Instrument Serif', serif;
17
+ --font-mono: 'Geist Mono', ui-monospace, monospace;
18
+ }
19
+
20
+ body {
21
+ font-family: var(--font-sans);
22
+ background: var(--color-paper);
23
+ color: var(--color-ink);
24
+ min-height: 100vh;
25
+ display: flex;
26
+ align-items: center;
27
+ justify-content: center;
28
+ padding: 3rem 2rem;
29
+ }
30
+
31
+ .frame { max-width: 1200px; width: 100%; }
32
+
33
+ .eyebrow {
34
+ font-family: var(--font-mono);
35
+ font-size: 0.66rem;
36
+ font-weight: 500;
37
+ letter-spacing: 0.18em;
38
+ text-transform: uppercase;
39
+ color: var(--color-muted);
40
+ margin-bottom: 0.5rem;
41
+ }
42
+
43
+ h1 {
44
+ font-family: var(--font-serif);
45
+ font-size: clamp(1.5rem, 2.4vw + 0.75rem, 2rem);
46
+ font-weight: 400;
47
+ letter-spacing: -0.02em;
48
+ line-height: 1.15;
49
+ color: var(--color-ink);
50
+ margin-bottom: 1.5rem;
51
+ }
52
+
53
+ svg { width: 100%; min-width: 900px; display: block; }
54
+ </style>
55
+ </head>
56
+ <body>
57
+ <div class="frame">
58
+ <p class="eyebrow">State machine · Diagram Design</p>
59
+ <h1>Article lifecycle</h1>
60
+
61
+ <svg viewBox="0 0 1000 460" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="state-dark-title state-dark-desc">
62
+ <title id="state-dark-title">Article lifecycle</title>
63
+ <desc id="state-dark-desc">State machine showing an article moving from Draft through In Review and Published to Archived, including rejection and revision.</desc>
64
+ <defs>
65
+ <pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
66
+ <circle cx="1" cy="1" r="0.9" fill="rgba(245,245,245,0.10)"/>
67
+ </pattern>
68
+ <marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#bfc0c0"/></marker>
69
+ <marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#f08a59"/></marker>
70
+ </defs>
71
+
72
+ <rect width="100%" height="100%" fill="#2d3142"/>
73
+ <rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
74
+
75
+ <!-- Transitions (drawn first) -->
76
+ <!-- Start → Draft -->
77
+ <line x1="68" y1="200" x2="120" y2="200" stroke="#bfc0c0" stroke-width="1.2" marker-end="url(#arrow)"/>
78
+ <!-- Draft → In Review -->
79
+ <line x1="280" y1="200" x2="340" y2="200" stroke="#bfc0c0" stroke-width="1.2" marker-end="url(#arrow)"/>
80
+ <!-- In Review → Published (coral — happy path) -->
81
+ <line x1="500" y1="200" x2="560" y2="200" stroke="#f08a59" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
82
+ <!-- Published → Archived (down) -->
83
+ <line x1="640" y1="240" x2="640" y2="300" stroke="#bfc0c0" stroke-width="1.2" marker-end="url(#arrow)"/>
84
+ <!-- Archived → End (down) -->
85
+ <line x1="640" y1="400" x2="640" y2="432" stroke="#bfc0c0" stroke-width="1.2" marker-end="url(#arrow)"/>
86
+ <!-- In Review → Draft (curved back up-and-left) -->
87
+ <path d="M 420 160 C 420 96, 200 96, 200 160" fill="none" stroke="#bfc0c0" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
88
+
89
+ <!-- Transition labels -->
90
+ <rect x="172" y="184" width="48" height="12" rx="2" fill="#2d3142"/>
91
+ <text x="196" y="194" fill="#bfc0c0" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CREATE</text>
92
+
93
+ <rect x="288" y="184" width="48" height="12" rx="2" fill="#2d3142"/>
94
+ <text x="312" y="194" fill="#bfc0c0" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">SUBMIT</text>
95
+
96
+ <rect x="500" y="184" width="60" height="12" rx="2" fill="#2d3142"/>
97
+ <text x="530" y="194" fill="#f08a59" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">APPROVE</text>
98
+
99
+ <rect x="612" y="264" width="56" height="12" rx="2" fill="#2d3142"/>
100
+ <text x="640" y="274" fill="#bfc0c0" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXPIRE</text>
101
+
102
+ <rect x="620" y="416" width="40" height="12" rx="2" fill="#2d3142"/>
103
+ <text x="640" y="426" fill="#bfc0c0" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">PURGE</text>
104
+
105
+ <!-- Reject label on curved path -->
106
+ <rect x="276" y="92" width="80" height="12" rx="2" fill="#2d3142"/>
107
+ <text x="316" y="102" fill="#bfc0c0" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">REJECT · REVISE</text>
108
+
109
+ <!-- Start dot (filled ink) -->
110
+ <circle cx="60" cy="200" r="6" fill="#f5f5f5"/>
111
+
112
+ <!-- State: Draft -->
113
+ <rect x="120" y="160" width="160" height="80" rx="8" fill="#393e53" stroke="#f5f5f5" stroke-width="1"/>
114
+ <rect x="128" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(245,245,245,0.40)" stroke-width="0.8"/>
115
+ <text x="148" y="177" fill="#f5f5f5" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
116
+ <text x="200" y="208" fill="#f5f5f5" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Draft</text>
117
+ <text x="200" y="224" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">unpublished</text>
118
+
119
+ <!-- State: In Review -->
120
+ <rect x="340" y="160" width="160" height="80" rx="8" fill="#393e53" stroke="#f5f5f5" stroke-width="1"/>
121
+ <rect x="348" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(245,245,245,0.40)" stroke-width="0.8"/>
122
+ <text x="368" y="177" fill="#f5f5f5" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
123
+ <text x="420" y="208" fill="#f5f5f5" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">In Review</text>
124
+ <text x="420" y="224" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">awaiting approval</text>
125
+
126
+ <!-- State: Published (focal coral) -->
127
+ <rect x="560" y="160" width="160" height="80" rx="8" fill="rgba(240,138,89,0.08)" stroke="#f08a59" stroke-width="1"/>
128
+ <rect x="568" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(240,138,89,0.50)" stroke-width="0.8"/>
129
+ <text x="588" y="177" fill="#f08a59" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
130
+ <text x="640" y="208" fill="#f5f5f5" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Published</text>
131
+ <text x="640" y="224" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">live on site</text>
132
+
133
+ <!-- State: Archived -->
134
+ <rect x="560" y="300" width="160" height="100" rx="8" fill="rgba(245,245,245,0.05)" stroke="#bfc0c0" stroke-width="1"/>
135
+ <rect x="568" y="308" width="40" height="12" rx="2" fill="transparent" stroke="rgba(191,192,192,0.50)" stroke-width="0.8"/>
136
+ <text x="588" y="317" fill="#bfc0c0" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
137
+ <text x="640" y="348" fill="#f5f5f5" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Archived</text>
138
+ <text x="640" y="364" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">noindex · hidden</text>
139
+ <text x="640" y="382" fill="#bfc0c0" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">redirect retained</text>
140
+
141
+ <!-- End ring dot -->
142
+ <circle cx="640" cy="440" r="8" fill="none" stroke="#f5f5f5" stroke-width="1"/>
143
+ <circle cx="640" cy="440" r="5" fill="#f5f5f5"/>
144
+ </svg>
145
+ </div>
146
+ </body>
147
+ </html>
@@ -0,0 +1,150 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Article lifecycle · state machine</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap" rel="stylesheet">
8
+ <style>
9
+ *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
10
+ :root { --color-paper:#f5f5f5; --color-paper-2:#ececec; --color-ink:#2d3142; --color-muted:#4f5d75; --color-soft:#7a8399; --color-rule:rgba(45,49,66,0.12); --color-accent:#eb6c36; --color-link:#2e5aa8; --font-sans:'Geist',system-ui,sans-serif; --font-serif:'Instrument Serif',serif; --font-mono:'Geist Mono',ui-monospace,monospace; }
11
+ body { font-family: var(--font-sans); background: var(--color-paper); min-height: 100vh; padding: 3rem 2rem; color: var(--color-ink); }
12
+ .container { max-width: 1200px; margin: 0 auto; }
13
+ .header { margin-bottom: 2.5rem; }
14
+ .header-eyebrow { font-family: var(--font-mono); font-size: 0.66rem; font-weight: 500; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.75rem; }
15
+ h1 { font-family: var(--font-serif); font-size: clamp(1.75rem, 3vw + 1rem, 2.5rem); font-weight: 400; letter-spacing: -0.02em; line-height: 1.1; margin-bottom: 0.5rem; }
16
+ .subtitle { font-size: 1rem; line-height: 1.55; color: var(--color-muted); max-width: 58ch; }
17
+ .diagram-container { background: var(--color-paper-2); border-radius: 8px; border: 1px solid var(--color-rule); padding: 1.5rem; overflow-x: auto; }
18
+ svg { width: 100%; min-width: 900px; display: block; }
19
+ .cards { display: grid; grid-template-columns: 1.1fr 1fr 0.9fr; gap: 1rem; margin-top: 1.5rem; }
20
+ @media (max-width: 820px) { .cards { grid-template-columns: 1fr; } }
21
+ .card { background: #fff; border-radius: 6px; border: 1px solid var(--color-rule); padding: 1.25rem; }
22
+ .card .eyebrow { font-family: var(--font-mono); font-size: 0.5rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--color-muted); margin-bottom: 0.5rem; }
23
+ .card-header { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.875rem; padding-bottom: 0.875rem; border-bottom: 1px solid rgba(45,49,66,0.08); }
24
+ .card-dot { width: 7px; height: 7px; border-radius: 50%; }
25
+ .card-dot.ink { background: var(--color-ink); } .card-dot.muted { background: var(--color-muted); } .card-dot.coral { background: var(--color-accent); }
26
+ .card h3 { font-size: 0.875rem; font-weight: 600; }
27
+ .card p, .card ul { color: var(--color-muted); font-size: 0.8125rem; line-height: 1.55; list-style: none; }
28
+ .card li { margin-bottom: 0.3rem; padding-left: 0.875rem; position: relative; }
29
+ .card li::before { content: '—'; position: absolute; left: 0; color: rgba(45,49,66,0.25); font-size: 0.75rem; }
30
+ .footer { margin-top: 2rem; padding-top: 1.5rem; border-top: 1px solid rgba(45,49,66,0.10); font-family: var(--font-mono); font-size: 0.72rem; letter-spacing: 0.06em; color: var(--color-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; }
31
+ </style>
32
+ </head>
33
+ <body>
34
+ <div class="container">
35
+ <div class="header">
36
+ <p class="header-eyebrow">State machine · Diagram Design</p>
37
+ <h1>Article lifecycle</h1>
38
+ <p class="subtitle">The four states a post passes through from draft to archive, with the rejection loop made explicit. Published is the state the team optimizes for — hence coral.</p>
39
+ </div>
40
+
41
+ <div class="diagram-container">
42
+ <svg viewBox="0 0 1000 460" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="state-full-title state-full-desc">
43
+ <title id="state-full-title">Article lifecycle</title>
44
+ <desc id="state-full-desc">State machine showing an article moving from Draft through In Review and Published to Archived, including rejection and revision.</desc>
45
+ <defs>
46
+ <pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse">
47
+ <circle cx="1" cy="1" r="0.9" fill="rgba(45,49,66,0.10)"/>
48
+ </pattern>
49
+ <marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#4f5d75"/></marker>
50
+ <marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0, 8 3, 0 6" fill="#eb6c36"/></marker>
51
+ </defs>
52
+
53
+ <rect width="100%" height="100%" fill="#f5f5f5"/>
54
+ <rect width="100%" height="100%" fill="url(#dots)" opacity="0.55"/>
55
+
56
+ <!-- Transitions (drawn first) -->
57
+ <!-- Start → Draft -->
58
+ <line x1="68" y1="200" x2="120" y2="200" stroke="#4f5d75" stroke-width="1.2" marker-end="url(#arrow)"/>
59
+ <!-- Draft → In Review -->
60
+ <line x1="280" y1="200" x2="340" y2="200" stroke="#4f5d75" stroke-width="1.2" marker-end="url(#arrow)"/>
61
+ <!-- In Review → Published (coral — happy path) -->
62
+ <line x1="500" y1="200" x2="560" y2="200" stroke="#eb6c36" stroke-width="1.4" marker-end="url(#arrow-accent)"/>
63
+ <!-- Published → Archived (down) -->
64
+ <line x1="640" y1="240" x2="640" y2="300" stroke="#4f5d75" stroke-width="1.2" marker-end="url(#arrow)"/>
65
+ <!-- Archived → End (down) -->
66
+ <line x1="640" y1="400" x2="640" y2="432" stroke="#4f5d75" stroke-width="1.2" marker-end="url(#arrow)"/>
67
+ <!-- In Review → Draft (curved back up-and-left) -->
68
+ <path d="M 420 160 C 420 96, 200 96, 200 160" fill="none" stroke="#4f5d75" stroke-width="1.2" stroke-dasharray="5,4" marker-end="url(#arrow)"/>
69
+
70
+ <!-- Transition labels -->
71
+ <rect x="172" y="184" width="48" height="12" rx="2" fill="#f5f5f5"/>
72
+ <text x="196" y="194" fill="#4f5d75" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">CREATE</text>
73
+
74
+ <rect x="288" y="184" width="48" height="12" rx="2" fill="#f5f5f5"/>
75
+ <text x="312" y="194" fill="#4f5d75" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">SUBMIT</text>
76
+
77
+ <rect x="500" y="184" width="60" height="12" rx="2" fill="#f5f5f5"/>
78
+ <text x="530" y="194" fill="#eb6c36" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">APPROVE</text>
79
+
80
+ <rect x="612" y="264" width="56" height="12" rx="2" fill="#f5f5f5"/>
81
+ <text x="640" y="274" fill="#4f5d75" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">EXPIRE</text>
82
+
83
+ <rect x="620" y="416" width="40" height="12" rx="2" fill="#f5f5f5"/>
84
+ <text x="640" y="426" fill="#4f5d75" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">PURGE</text>
85
+
86
+ <!-- Reject label on curved path -->
87
+ <rect x="276" y="92" width="80" height="12" rx="2" fill="#f5f5f5"/>
88
+ <text x="316" y="102" fill="#4f5d75" font-size="8" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">REJECT · REVISE</text>
89
+
90
+ <!-- Start dot (filled ink) -->
91
+ <circle cx="60" cy="200" r="6" fill="#2d3142"/>
92
+
93
+ <!-- State: Draft -->
94
+ <rect x="120" y="160" width="160" height="80" rx="8" fill="#ffffff" stroke="#2d3142" stroke-width="1"/>
95
+ <rect x="128" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(45,49,66,0.40)" stroke-width="0.8"/>
96
+ <text x="148" y="177" fill="#2d3142" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
97
+ <text x="200" y="208" fill="#2d3142" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Draft</text>
98
+ <text x="200" y="224" fill="#4f5d75" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">unpublished</text>
99
+
100
+ <!-- State: In Review -->
101
+ <rect x="340" y="160" width="160" height="80" rx="8" fill="#ffffff" stroke="#2d3142" stroke-width="1"/>
102
+ <rect x="348" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(45,49,66,0.40)" stroke-width="0.8"/>
103
+ <text x="368" y="177" fill="#2d3142" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
104
+ <text x="420" y="208" fill="#2d3142" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">In Review</text>
105
+ <text x="420" y="224" fill="#4f5d75" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">awaiting approval</text>
106
+
107
+ <!-- State: Published (focal coral) -->
108
+ <rect x="560" y="160" width="160" height="80" rx="8" fill="rgba(235,108,54,0.08)" stroke="#eb6c36" stroke-width="1"/>
109
+ <rect x="568" y="168" width="40" height="12" rx="2" fill="transparent" stroke="rgba(235,108,54,0.50)" stroke-width="0.8"/>
110
+ <text x="588" y="177" fill="#eb6c36" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
111
+ <text x="640" y="208" fill="#2d3142" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Published</text>
112
+ <text x="640" y="224" fill="#4f5d75" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">live on site</text>
113
+
114
+ <!-- State: Archived -->
115
+ <rect x="560" y="300" width="160" height="100" rx="8" fill="rgba(45,49,66,0.05)" stroke="#4f5d75" stroke-width="1"/>
116
+ <rect x="568" y="308" width="40" height="12" rx="2" fill="transparent" stroke="rgba(79,93,117,0.50)" stroke-width="0.8"/>
117
+ <text x="588" y="317" fill="#4f5d75" font-size="7" font-family="'Geist Mono', monospace" text-anchor="middle" letter-spacing="0.08em">STATE</text>
118
+ <text x="640" y="348" fill="#2d3142" font-size="14" font-weight="600" font-family="'Geist', sans-serif" text-anchor="middle">Archived</text>
119
+ <text x="640" y="364" fill="#4f5d75" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">noindex · hidden</text>
120
+ <text x="640" y="382" fill="#4f5d75" font-size="9" font-family="'Geist Mono', monospace" text-anchor="middle">redirect retained</text>
121
+
122
+ <!-- End ring dot -->
123
+ <circle cx="640" cy="440" r="8" fill="none" stroke="#2d3142" stroke-width="1"/>
124
+ <circle cx="640" cy="440" r="5" fill="#2d3142"/>
125
+ </svg>
126
+ </div>
127
+
128
+ <div class="cards">
129
+ <div class="card">
130
+ <p class="eyebrow">THE HEADLINE</p>
131
+ <div class="card-header"><span class="card-dot coral"></span><h3>Published is the win state</h3></div>
132
+ <p>Everything flows toward Published. The rejection loop is dashed because it's a detour, not a failure — the article is still in-progress.</p>
133
+ </div>
134
+ <div class="card">
135
+ <div class="card-header"><span class="card-dot ink"></span><h3>Reject is a loop, not a dead-end</h3></div>
136
+ <ul><li>Dashed to signal detour</li><li>Returns to Draft, not a new state</li><li>Review feedback is the action</li></ul>
137
+ </div>
138
+ <div class="card">
139
+ <div class="card-header"><span class="card-dot muted"></span><h3>Archive keeps the URL</h3></div>
140
+ <p>Archived preserves the redirect map so inbound links survive. Only Purge removes the record entirely.</p>
141
+ </div>
142
+ </div>
143
+
144
+ <div class="footer">
145
+ <span>article lifecycle · state machine</span>
146
+ <span>example · schematic skill</span>
147
+ </div>
148
+ </div>
149
+ </body>
150
+ </html>