@taloswork/ose-shared 0.1.8 → 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.
- package/package.json +3 -3
- package/skills/cozy-static-svg/SKILL.md +76 -0
- package/skills/cozy-static-svg/references/approved-preview.png +0 -0
- package/skills/cozy-static-svg/references/cross-platform.md +73 -0
- package/skills/cozy-static-svg/references/moon_keeps_watch.svg +229 -0
- package/skills/cozy-static-svg/references/style-anchor.md +271 -0
- package/skills/cozy-static-svg/scripts/artkit.py +321 -0
- package/skills/cozy-static-svg/scripts/to_png.py +333 -0
- package/skills/diagram-design/SKILL.md +568 -0
- package/skills/diagram-design/assets/example-architecture-dark.html +182 -0
- package/skills/diagram-design/assets/example-architecture-full.html +194 -0
- package/skills/diagram-design/assets/example-architecture.html +183 -0
- package/skills/diagram-design/assets/example-bar-dark.html +129 -0
- package/skills/diagram-design/assets/example-bar-full.html +105 -0
- package/skills/diagram-design/assets/example-bar.html +129 -0
- package/skills/diagram-design/assets/example-data-flow-dark.html +143 -0
- package/skills/diagram-design/assets/example-data-flow-full.html +185 -0
- package/skills/diagram-design/assets/example-data-flow.html +143 -0
- package/skills/diagram-design/assets/example-datalake-dark.html +243 -0
- package/skills/diagram-design/assets/example-datalake-full.html +248 -0
- package/skills/diagram-design/assets/example-datalake.html +269 -0
- package/skills/diagram-design/assets/example-dp-integration-dark.html +80 -0
- package/skills/diagram-design/assets/example-dp-integration-full.html +90 -0
- package/skills/diagram-design/assets/example-dp-integration.html +80 -0
- package/skills/diagram-design/assets/example-dp-security-matrix-dark.html +31 -0
- package/skills/diagram-design/assets/example-dp-security-matrix-full.html +32 -0
- package/skills/diagram-design/assets/example-dp-security-matrix.html +88 -0
- package/skills/diagram-design/assets/example-er-dark.html +202 -0
- package/skills/diagram-design/assets/example-er-full.html +205 -0
- package/skills/diagram-design/assets/example-er.html +202 -0
- package/skills/diagram-design/assets/example-flowchart-dark.html +156 -0
- package/skills/diagram-design/assets/example-flowchart-full.html +159 -0
- package/skills/diagram-design/assets/example-flowchart.html +156 -0
- package/skills/diagram-design/assets/example-gantt-dark.html +137 -0
- package/skills/diagram-design/assets/example-gantt-full.html +127 -0
- package/skills/diagram-design/assets/example-gantt.html +137 -0
- package/skills/diagram-design/assets/example-high-level-dark.html +251 -0
- package/skills/diagram-design/assets/example-high-level-full.html +247 -0
- package/skills/diagram-design/assets/example-high-level-vertical-dark.html +274 -0
- package/skills/diagram-design/assets/example-high-level-vertical-full.html +252 -0
- package/skills/diagram-design/assets/example-high-level-vertical.html +325 -0
- package/skills/diagram-design/assets/example-high-level.html +301 -0
- package/skills/diagram-design/assets/example-import-drawio.html +185 -0
- package/skills/diagram-design/assets/example-import-mermaid.html +70 -0
- package/skills/diagram-design/assets/example-it-state-dark.html +90 -0
- package/skills/diagram-design/assets/example-it-state-full.html +69 -0
- package/skills/diagram-design/assets/example-it-state.html +128 -0
- package/skills/diagram-design/assets/example-layers-dark.html +123 -0
- package/skills/diagram-design/assets/example-layers-full.html +126 -0
- package/skills/diagram-design/assets/example-layers.html +123 -0
- package/skills/diagram-design/assets/example-line-dark.html +111 -0
- package/skills/diagram-design/assets/example-line-full.html +105 -0
- package/skills/diagram-design/assets/example-line.html +111 -0
- package/skills/diagram-design/assets/example-loop-dark.html +100 -0
- package/skills/diagram-design/assets/example-loop-full.html +137 -0
- package/skills/diagram-design/assets/example-loop-terminal.html +347 -0
- package/skills/diagram-design/assets/example-loop.html +100 -0
- package/skills/diagram-design/assets/example-medallion-dark.html +159 -0
- package/skills/diagram-design/assets/example-medallion-full.html +201 -0
- package/skills/diagram-design/assets/example-medallion.html +159 -0
- package/skills/diagram-design/assets/example-nested-dark.html +132 -0
- package/skills/diagram-design/assets/example-nested-full.html +135 -0
- package/skills/diagram-design/assets/example-nested.html +136 -0
- package/skills/diagram-design/assets/example-org-chart-dark.html +45 -0
- package/skills/diagram-design/assets/example-org-chart-full.html +45 -0
- package/skills/diagram-design/assets/example-org-chart.html +45 -0
- package/skills/diagram-design/assets/example-paved-road-animated.html +546 -0
- package/skills/diagram-design/assets/example-policy-trace-animated.html +490 -0
- package/skills/diagram-design/assets/example-process-dark.html +64 -0
- package/skills/diagram-design/assets/example-process-full.html +74 -0
- package/skills/diagram-design/assets/example-process.html +64 -0
- package/skills/diagram-design/assets/example-pyramid-dark.html +119 -0
- package/skills/diagram-design/assets/example-pyramid-full.html +122 -0
- package/skills/diagram-design/assets/example-pyramid.html +119 -0
- package/skills/diagram-design/assets/example-quadrant-consultant.html +166 -0
- package/skills/diagram-design/assets/example-quadrant-dark.html +135 -0
- package/skills/diagram-design/assets/example-quadrant-full.html +138 -0
- package/skills/diagram-design/assets/example-quadrant.html +135 -0
- package/skills/diagram-design/assets/example-queue-animated.html +577 -0
- package/skills/diagram-design/assets/example-radar-dark.html +139 -0
- package/skills/diagram-design/assets/example-radar-full.html +135 -0
- package/skills/diagram-design/assets/example-radar.html +139 -0
- package/skills/diagram-design/assets/example-scatter-dark.html +141 -0
- package/skills/diagram-design/assets/example-scatter-full.html +116 -0
- package/skills/diagram-design/assets/example-scatter.html +141 -0
- package/skills/diagram-design/assets/example-sequence-dark.html +222 -0
- package/skills/diagram-design/assets/example-sequence-full.html +388 -0
- package/skills/diagram-design/assets/example-sequence-oauth-dark.html +188 -0
- package/skills/diagram-design/assets/example-sequence-oauth-full.html +350 -0
- package/skills/diagram-design/assets/example-sequence-oauth.html +227 -0
- package/skills/diagram-design/assets/example-sequence.html +222 -0
- package/skills/diagram-design/assets/example-state-dark.html +147 -0
- package/skills/diagram-design/assets/example-state-full.html +150 -0
- package/skills/diagram-design/assets/example-state.html +147 -0
- package/skills/diagram-design/assets/example-swimlane-dark.html +172 -0
- package/skills/diagram-design/assets/example-swimlane-full.html +175 -0
- package/skills/diagram-design/assets/example-swimlane.html +172 -0
- package/skills/diagram-design/assets/example-timeline-dark.html +135 -0
- package/skills/diagram-design/assets/example-timeline-full.html +138 -0
- package/skills/diagram-design/assets/example-timeline.html +135 -0
- package/skills/diagram-design/assets/example-tree-dark.html +173 -0
- package/skills/diagram-design/assets/example-tree-full.html +176 -0
- package/skills/diagram-design/assets/example-tree.html +173 -0
- package/skills/diagram-design/assets/example-venn-dark.html +132 -0
- package/skills/diagram-design/assets/example-venn-full.html +135 -0
- package/skills/diagram-design/assets/example-venn.html +110 -0
- package/skills/diagram-design/assets/icons.html +230 -0
- package/skills/diagram-design/assets/index.html +369 -0
- package/skills/diagram-design/assets/template-dark.html +85 -0
- package/skills/diagram-design/assets/template-full.html +413 -0
- package/skills/diagram-design/assets/template-motion.html +434 -0
- package/skills/diagram-design/assets/template-terminal.html +173 -0
- package/skills/diagram-design/assets/template.html +86 -0
- package/skills/diagram-design/references/animation.md +141 -0
- package/skills/diagram-design/references/export.md +136 -0
- package/skills/diagram-design/references/import-drawio.md +171 -0
- package/skills/diagram-design/references/import-mermaid.md +126 -0
- package/skills/diagram-design/references/onboarding.md +297 -0
- package/skills/diagram-design/references/output-spec.md +181 -0
- package/skills/diagram-design/references/primitive-annotation.md +36 -0
- package/skills/diagram-design/references/primitive-icons.md +827 -0
- package/skills/diagram-design/references/primitive-sketchy.md +43 -0
- package/skills/diagram-design/references/primitive-terminal.md +76 -0
- package/skills/diagram-design/references/semantic-patterns.md +122 -0
- package/skills/diagram-design/references/style-guide.md +139 -0
- package/skills/diagram-design/references/type-architecture.md +78 -0
- package/skills/diagram-design/references/type-bar.md +48 -0
- package/skills/diagram-design/references/type-data-flow.md +374 -0
- package/skills/diagram-design/references/type-dp-integration.md +410 -0
- package/skills/diagram-design/references/type-dp-security-matrix.md +379 -0
- package/skills/diagram-design/references/type-er.md +23 -0
- package/skills/diagram-design/references/type-flowchart.md +23 -0
- package/skills/diagram-design/references/type-gantt.md +45 -0
- package/skills/diagram-design/references/type-high-level.md +458 -0
- package/skills/diagram-design/references/type-it-state.md +470 -0
- package/skills/diagram-design/references/type-layers.md +26 -0
- package/skills/diagram-design/references/type-line.md +44 -0
- package/skills/diagram-design/references/type-loop.md +223 -0
- package/skills/diagram-design/references/type-medallion.md +356 -0
- package/skills/diagram-design/references/type-nested.md +22 -0
- package/skills/diagram-design/references/type-org-chart.md +44 -0
- package/skills/diagram-design/references/type-process.md +495 -0
- package/skills/diagram-design/references/type-pyramid.md +33 -0
- package/skills/diagram-design/references/type-quadrant.md +81 -0
- package/skills/diagram-design/references/type-radar.md +80 -0
- package/skills/diagram-design/references/type-scatter.md +39 -0
- package/skills/diagram-design/references/type-sequence.md +130 -0
- package/skills/diagram-design/references/type-state.md +21 -0
- package/skills/diagram-design/references/type-swimlane.md +20 -0
- package/skills/diagram-design/references/type-timeline.md +20 -0
- package/skills/diagram-design/references/type-tree.md +24 -0
- package/skills/diagram-design/references/type-venn.md +26 -0
- package/skills/diagram-design/scripts/drawio_extract.py +856 -0
- package/skills/diagram-design/scripts/mermaid_extract.py +1285 -0
- package/skills/diagram-design/scripts/self_check.py +389 -0
|
@@ -0,0 +1,490 @@
|
|
|
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>Where policy traces diverge</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; }
|
|
10
|
+
:root {
|
|
11
|
+
--paper: #f5f5f5;
|
|
12
|
+
--paper-2: #ececec;
|
|
13
|
+
--ink: #2d3142;
|
|
14
|
+
--muted: #4f5d75;
|
|
15
|
+
--soft: #7a8399;
|
|
16
|
+
--rule: rgba(45,49,66,0.12);
|
|
17
|
+
--rule-strong: rgba(45,49,66,0.30);
|
|
18
|
+
--accent: #eb6c36;
|
|
19
|
+
--accent-tint: rgba(235,108,54,0.08);
|
|
20
|
+
--sans: 'Geist', system-ui, sans-serif;
|
|
21
|
+
--serif: 'Instrument Serif', serif;
|
|
22
|
+
--mono: 'Geist Mono', ui-monospace, monospace;
|
|
23
|
+
--motion-fast: 160ms;
|
|
24
|
+
--motion-step: 480ms;
|
|
25
|
+
--motion-hold: 720ms;
|
|
26
|
+
--motion-total: 3600ms;
|
|
27
|
+
--motion-ease: cubic-bezier(.2,.8,.2,1);
|
|
28
|
+
}
|
|
29
|
+
body {
|
|
30
|
+
margin: 0;
|
|
31
|
+
min-height: 100vh;
|
|
32
|
+
padding: 32px;
|
|
33
|
+
color: var(--ink);
|
|
34
|
+
background: var(--paper);
|
|
35
|
+
font-family: var(--sans);
|
|
36
|
+
}
|
|
37
|
+
[data-motion-root] {
|
|
38
|
+
width: min(100%, 1280px);
|
|
39
|
+
margin: 0 auto;
|
|
40
|
+
}
|
|
41
|
+
.page-header {
|
|
42
|
+
display: flex;
|
|
43
|
+
align-items: end;
|
|
44
|
+
justify-content: space-between;
|
|
45
|
+
gap: 32px;
|
|
46
|
+
margin-bottom: 16px;
|
|
47
|
+
}
|
|
48
|
+
.eyebrow {
|
|
49
|
+
margin: 0 0 8px;
|
|
50
|
+
color: var(--muted);
|
|
51
|
+
font: 500 8px/1.4 var(--mono);
|
|
52
|
+
letter-spacing: .18em;
|
|
53
|
+
text-transform: uppercase;
|
|
54
|
+
}
|
|
55
|
+
h1 {
|
|
56
|
+
margin: 0;
|
|
57
|
+
font: 400 clamp(28px, 3vw, 40px)/1.08 var(--serif);
|
|
58
|
+
letter-spacing: -.02em;
|
|
59
|
+
}
|
|
60
|
+
.lede {
|
|
61
|
+
max-width: 480px;
|
|
62
|
+
margin: 0 0 4px;
|
|
63
|
+
color: var(--muted);
|
|
64
|
+
font-size: 12px;
|
|
65
|
+
line-height: 1.6;
|
|
66
|
+
}
|
|
67
|
+
.diagram-wrap {
|
|
68
|
+
overflow-x: auto;
|
|
69
|
+
border-top: 1px solid var(--rule);
|
|
70
|
+
border-bottom: 1px solid var(--rule);
|
|
71
|
+
}
|
|
72
|
+
svg { display: block; width: 100%; min-width: 880px; }
|
|
73
|
+
|
|
74
|
+
[data-motion-controls] {
|
|
75
|
+
display: none;
|
|
76
|
+
align-items: center;
|
|
77
|
+
gap: 8px;
|
|
78
|
+
min-height: 60px;
|
|
79
|
+
padding: 8px 0;
|
|
80
|
+
}
|
|
81
|
+
.motion-ready [data-motion-controls] { display: flex; }
|
|
82
|
+
[data-motion-controls][hidden] { display: none !important; }
|
|
83
|
+
[data-motion-controls] button {
|
|
84
|
+
min-width: 44px;
|
|
85
|
+
min-height: 44px;
|
|
86
|
+
padding: 8px 12px;
|
|
87
|
+
border: 1px solid var(--muted);
|
|
88
|
+
border-radius: 4px;
|
|
89
|
+
color: var(--ink);
|
|
90
|
+
background: var(--paper);
|
|
91
|
+
font: 600 12px/1 var(--sans);
|
|
92
|
+
cursor: pointer;
|
|
93
|
+
}
|
|
94
|
+
[data-motion-controls] button:hover { border-color: var(--accent); }
|
|
95
|
+
[data-motion-controls] button:focus-visible,
|
|
96
|
+
[data-motion-root]:focus-visible {
|
|
97
|
+
outline: 3px solid var(--accent);
|
|
98
|
+
outline-offset: 2px;
|
|
99
|
+
}
|
|
100
|
+
[data-motion-controls] button:disabled { cursor: not-allowed; opacity: .45; }
|
|
101
|
+
.keyboard-help {
|
|
102
|
+
margin-left: 8px;
|
|
103
|
+
color: var(--soft);
|
|
104
|
+
font: 500 9px/1.4 var(--mono);
|
|
105
|
+
}
|
|
106
|
+
[data-motion-status] {
|
|
107
|
+
display: block;
|
|
108
|
+
min-width: 272px;
|
|
109
|
+
min-height: 16px;
|
|
110
|
+
margin: 8px 0 0;
|
|
111
|
+
color: var(--muted);
|
|
112
|
+
font: 500 10px/1.4 var(--mono);
|
|
113
|
+
text-align: right;
|
|
114
|
+
}
|
|
115
|
+
noscript p {
|
|
116
|
+
margin: 12px 0 0;
|
|
117
|
+
color: var(--muted);
|
|
118
|
+
font: 500 10px/1.4 var(--mono);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* The source frame is complete. Hiding begins only after user activation. */
|
|
122
|
+
.motion-ready [data-motion-item] {
|
|
123
|
+
opacity: .12;
|
|
124
|
+
transform: translateY(8px);
|
|
125
|
+
transform-box: fill-box;
|
|
126
|
+
transform-origin: center;
|
|
127
|
+
transition: opacity var(--motion-step) var(--motion-ease),
|
|
128
|
+
transform var(--motion-step) var(--motion-ease);
|
|
129
|
+
}
|
|
130
|
+
.motion-ready [data-motion-item].is-visible,
|
|
131
|
+
.motion-ready[data-frame="end"] [data-motion-item],
|
|
132
|
+
.motion-ready[data-frame="static"] [data-motion-item] {
|
|
133
|
+
opacity: 1;
|
|
134
|
+
transform: none;
|
|
135
|
+
}
|
|
136
|
+
.row-focus { fill: transparent; stroke: transparent; stroke-width: 1.2; }
|
|
137
|
+
.motion-ready [data-motion-item].is-current .row-focus {
|
|
138
|
+
stroke: var(--muted);
|
|
139
|
+
stroke-dasharray: 4 4;
|
|
140
|
+
}
|
|
141
|
+
html[data-motion="static"] [data-motion-controls] { display: none !important; }
|
|
142
|
+
html[data-motion="static"] [data-motion-item] {
|
|
143
|
+
opacity: 1 !important;
|
|
144
|
+
transform: none !important;
|
|
145
|
+
transition: none !important;
|
|
146
|
+
}
|
|
147
|
+
html[data-motion="step"] [data-motion-controls],
|
|
148
|
+
html[data-motion="step"] [data-motion-decorative] { display: none !important; }
|
|
149
|
+
html[data-motion="step"] [data-motion-item] {
|
|
150
|
+
animation: none !important;
|
|
151
|
+
transition: none !important;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
@media (prefers-reduced-motion: reduce) {
|
|
155
|
+
*, *::before, *::after {
|
|
156
|
+
animation-duration: .001ms !important;
|
|
157
|
+
animation-iteration-count: 1 !important;
|
|
158
|
+
scroll-behavior: auto !important;
|
|
159
|
+
transition-duration: .001ms !important;
|
|
160
|
+
}
|
|
161
|
+
[data-motion-item] { opacity: 1 !important; transform: none !important; }
|
|
162
|
+
[data-motion-decorative] { display: none !important; }
|
|
163
|
+
[data-motion-controls] { display: none !important; }
|
|
164
|
+
}
|
|
165
|
+
@media print {
|
|
166
|
+
body { padding: 0; }
|
|
167
|
+
[data-motion-controls], [data-motion-decorative] { display: none !important; }
|
|
168
|
+
[data-motion-item] { opacity: 1 !important; transform: none !important; }
|
|
169
|
+
}
|
|
170
|
+
@media (max-width: 800px) {
|
|
171
|
+
body { padding: 20px; }
|
|
172
|
+
.page-header { display: block; }
|
|
173
|
+
.lede { margin-top: 12px; }
|
|
174
|
+
[data-motion-status] { min-width: 200px; }
|
|
175
|
+
.keyboard-help { display: none; }
|
|
176
|
+
}
|
|
177
|
+
</style>
|
|
178
|
+
</head>
|
|
179
|
+
<body>
|
|
180
|
+
<!-- Use ?motion=static for deterministic screenshots and export. -->
|
|
181
|
+
<main data-motion-root data-motion-mode="step" data-step-count="5" data-step-current="5"
|
|
182
|
+
data-frame="static" data-static-frame="complete" tabindex="-1">
|
|
183
|
+
<header class="page-header">
|
|
184
|
+
<div>
|
|
185
|
+
<p class="eyebrow">Semantic pattern · Paired policy-evaluation traces</p>
|
|
186
|
+
<h1>Where policy traces diverge</h1>
|
|
187
|
+
</div>
|
|
188
|
+
<p class="lede">Two requests traverse the same ordered rules. Explicit states distinguish a rule that does not apply from one the evaluator never reaches.</p>
|
|
189
|
+
</header>
|
|
190
|
+
|
|
191
|
+
<div class="diagram-wrap">
|
|
192
|
+
<svg viewBox="0 0 1200 660" xmlns="http://www.w3.org/2000/svg" role="img"
|
|
193
|
+
aria-labelledby="policy-trace-animated-title policy-trace-animated-desc"
|
|
194
|
+
data-motion-primitive="policy-evaluation">
|
|
195
|
+
<title id="policy-trace-animated-title">Where two policy evaluations first diverge</title>
|
|
196
|
+
<desc id="policy-trace-animated-desc">Two requests pass identity and audience checks. At the data-class rule, the read-only request passes while the sensitive-write request fails; later rules are skipped or not reached, producing permitted and denied outcomes.</desc>
|
|
197
|
+
<rect width="1200" height="660" fill="#f5f5f5"/>
|
|
198
|
+
|
|
199
|
+
<!-- Persistent trace paths are meaningful in every frame. -->
|
|
200
|
+
<line x1="620" y1="104" x2="620" y2="576" stroke="rgba(45,49,66,0.30)" stroke-width="1"/>
|
|
201
|
+
<line data-trace-connector="trace-b" x1="936" y1="104" x2="936" y2="336" stroke="rgba(45,49,66,0.30)" stroke-width="1"/>
|
|
202
|
+
|
|
203
|
+
<!-- Shared rule column and trace headers. -->
|
|
204
|
+
<text x="72" y="76" fill="#4f5d75" font-family="'Geist Mono', monospace" font-size="12" letter-spacing="1.6">ORDERED POLICY</text>
|
|
205
|
+
<rect x="500" y="44" width="240" height="60" rx="6" fill="#ffffff" stroke="#2d3142"/>
|
|
206
|
+
<text x="620" y="72" text-anchor="middle" fill="#2d3142" font-family="'Geist', sans-serif" font-size="12" font-weight="600">Trace A · read-only</text>
|
|
207
|
+
<text x="620" y="92" text-anchor="middle" fill="#4f5d75" font-family="'Geist Mono', monospace" font-size="12">internal metrics request</text>
|
|
208
|
+
<rect x="816" y="44" width="240" height="60" rx="6" fill="#ffffff" stroke="#2d3142"/>
|
|
209
|
+
<text x="936" y="72" text-anchor="middle" fill="#2d3142" font-family="'Geist', sans-serif" font-size="12" font-weight="600">Trace B · sensitive write</text>
|
|
210
|
+
<text x="936" y="92" text-anchor="middle" fill="#4f5d75" font-family="'Geist Mono', monospace" font-size="12">restricted records request</text>
|
|
211
|
+
|
|
212
|
+
<g data-motion-item data-step="1" aria-label="Rule 1: Identity bound passes for both traces">
|
|
213
|
+
<rect class="row-focus" x="48" y="124" width="1080" height="68" rx="4"/>
|
|
214
|
+
<text x="72" y="152" fill="#2d3142" font-family="'Geist', sans-serif" font-size="12" font-weight="600">1 · Identity bound</text>
|
|
215
|
+
<text x="72" y="172" fill="#4f5d75" font-family="'Geist Mono', monospace" font-size="12">named principal required</text>
|
|
216
|
+
<rect x="532" y="132" width="176" height="52" rx="4" fill="rgba(45,49,66,0.05)" stroke="#4f5d75"/>
|
|
217
|
+
<text x="620" y="164" text-anchor="middle" fill="#2d3142" font-family="'Geist Mono', monospace" font-size="10" font-weight="600">✓ PASS</text>
|
|
218
|
+
<rect x="848" y="132" width="176" height="52" rx="4" fill="rgba(45,49,66,0.05)" stroke="#4f5d75"/>
|
|
219
|
+
<text x="936" y="164" text-anchor="middle" fill="#2d3142" font-family="'Geist Mono', monospace" font-size="10" font-weight="600">✓ PASS</text>
|
|
220
|
+
</g>
|
|
221
|
+
|
|
222
|
+
<g data-motion-item data-step="2" aria-label="Rule 2: Internal audience passes for both traces">
|
|
223
|
+
<rect class="row-focus" x="48" y="200" width="1080" height="68" rx="4"/>
|
|
224
|
+
<text x="72" y="228" fill="#2d3142" font-family="'Geist', sans-serif" font-size="12" font-weight="600">2 · Internal audience</text>
|
|
225
|
+
<text x="72" y="248" fill="#4f5d75" font-family="'Geist Mono', monospace" font-size="12">employees only</text>
|
|
226
|
+
<rect x="532" y="208" width="176" height="52" rx="4" fill="rgba(45,49,66,0.05)" stroke="#4f5d75"/>
|
|
227
|
+
<text x="620" y="240" text-anchor="middle" fill="#2d3142" font-family="'Geist Mono', monospace" font-size="10" font-weight="600">✓ PASS</text>
|
|
228
|
+
<rect x="848" y="208" width="176" height="52" rx="4" fill="rgba(45,49,66,0.05)" stroke="#4f5d75"/>
|
|
229
|
+
<text x="936" y="240" text-anchor="middle" fill="#2d3142" font-family="'Geist Mono', monospace" font-size="10" font-weight="600">✓ PASS</text>
|
|
230
|
+
</g>
|
|
231
|
+
|
|
232
|
+
<g data-motion-item data-step="3" aria-label="Rule 3 is the first divergence: Trace A passes and Trace B fails">
|
|
233
|
+
<rect class="row-focus" x="48" y="276" width="1080" height="80" rx="4"/>
|
|
234
|
+
<text x="72" y="304" fill="#2d3142" font-family="'Geist', sans-serif" font-size="12" font-weight="600">3 · Data class</text>
|
|
235
|
+
<text x="72" y="324" fill="#4f5d75" font-family="'Geist Mono', monospace" font-size="12">restricted writes denied</text>
|
|
236
|
+
<rect x="532" y="284" width="176" height="52" rx="4" fill="rgba(45,49,66,0.05)" stroke="#4f5d75"/>
|
|
237
|
+
<text x="620" y="316" text-anchor="middle" fill="#2d3142" font-family="'Geist Mono', monospace" font-size="10" font-weight="600">✓ PASS</text>
|
|
238
|
+
<rect data-trace-b-terminal="fail" x="848" y="284" width="176" height="52" rx="4" fill="rgba(235,108,54,0.08)" stroke="#eb6c36" stroke-width="1.2"/>
|
|
239
|
+
<text x="936" y="316" text-anchor="middle" fill="#eb6c36" font-family="'Geist Mono', monospace" font-size="10" font-weight="600">× FAIL</text>
|
|
240
|
+
<path d="M716 344 V352 H840 V344" fill="none" stroke="#eb6c36" stroke-width="1.2"/>
|
|
241
|
+
<rect x="712" y="336" width="132" height="20" rx="2" fill="#f5f5f5"/>
|
|
242
|
+
<text x="778" y="351" text-anchor="middle" fill="#eb6c36" font-family="'Geist Mono', monospace" font-size="12" font-weight="600" letter-spacing=".8">FIRST DIVERGENCE</text>
|
|
243
|
+
</g>
|
|
244
|
+
|
|
245
|
+
<g data-motion-item data-step="4" aria-label="Rule 4 is skipped for Trace A and not reached for Trace B">
|
|
246
|
+
<rect class="row-focus" x="48" y="364" width="1080" height="68" rx="4"/>
|
|
247
|
+
<text x="72" y="392" fill="#2d3142" font-family="'Geist', sans-serif" font-size="12" font-weight="600">4 · Human approval</text>
|
|
248
|
+
<text x="72" y="412" fill="#4f5d75" font-family="'Geist Mono', monospace" font-size="12">required only for writes</text>
|
|
249
|
+
<rect x="532" y="372" width="176" height="52" rx="4" fill="#f5f5f5" stroke="#7a8399" stroke-dasharray="4 4"/>
|
|
250
|
+
<text x="620" y="404" text-anchor="middle" fill="#4f5d75" font-family="'Geist Mono', monospace" font-size="10" font-weight="600">— SKIPPED</text>
|
|
251
|
+
<rect data-trace-b-state="not-reached" x="848" y="372" width="176" height="52" rx="4" fill="rgba(45,49,66,0.02)" stroke="rgba(45,49,66,0.30)" stroke-dasharray="4 4"/>
|
|
252
|
+
<text x="936" y="404" text-anchor="middle" fill="#7a8399" font-family="'Geist Mono', monospace" font-size="10" font-weight="600">○ NOT REACHED</text>
|
|
253
|
+
</g>
|
|
254
|
+
|
|
255
|
+
<g data-motion-item data-step="5" aria-label="Rule 5 passes for Trace A and is not reached for Trace B; outcomes are permitted and denied">
|
|
256
|
+
<rect class="row-focus" x="48" y="440" width="1080" height="152" rx="4"/>
|
|
257
|
+
<text x="72" y="468" fill="#2d3142" font-family="'Geist', sans-serif" font-size="12" font-weight="600">5 · Deploy gate</text>
|
|
258
|
+
<text x="72" y="488" fill="#4f5d75" font-family="'Geist Mono', monospace" font-size="12">all reached rules must pass</text>
|
|
259
|
+
<rect x="532" y="448" width="176" height="52" rx="4" fill="rgba(45,49,66,0.05)" stroke="#4f5d75"/>
|
|
260
|
+
<text x="620" y="480" text-anchor="middle" fill="#2d3142" font-family="'Geist Mono', monospace" font-size="10" font-weight="600">✓ PASS</text>
|
|
261
|
+
<rect data-trace-b-state="not-reached" x="848" y="448" width="176" height="52" rx="4" fill="rgba(45,49,66,0.02)" stroke="rgba(45,49,66,0.30)" stroke-dasharray="4 4"/>
|
|
262
|
+
<text x="936" y="480" text-anchor="middle" fill="#7a8399" font-family="'Geist Mono', monospace" font-size="10" font-weight="600">○ NOT REACHED</text>
|
|
263
|
+
|
|
264
|
+
<rect x="500" y="528" width="240" height="56" rx="6" fill="#2d3142" stroke="#2d3142"/>
|
|
265
|
+
<text x="620" y="552" text-anchor="middle" fill="#f5f5f5" font-family="'Geist Mono', monospace" font-size="12" letter-spacing="1.2">OUTCOME</text>
|
|
266
|
+
<text x="620" y="572" text-anchor="middle" fill="#f5f5f5" font-family="'Geist', sans-serif" font-size="12" font-weight="600">Permitted</text>
|
|
267
|
+
<rect data-trace-b-outcome="denied" x="816" y="528" width="240" height="56" rx="6" fill="#f5f5f5"/>
|
|
268
|
+
<rect x="816" y="528" width="240" height="56" rx="6" fill="rgba(235,108,54,0.08)" stroke="#eb6c36" stroke-width="1.2"/>
|
|
269
|
+
<text x="936" y="552" text-anchor="middle" fill="#eb6c36" font-family="'Geist Mono', monospace" font-size="12" letter-spacing="1.2">OUTCOME</text>
|
|
270
|
+
<text x="936" y="572" text-anchor="middle" fill="#2d3142" font-family="'Geist', sans-serif" font-size="12" font-weight="600">Denied · review</text>
|
|
271
|
+
</g>
|
|
272
|
+
|
|
273
|
+
<line x1="72" y1="620" x2="1128" y2="620" stroke="rgba(45,49,66,0.12)"/>
|
|
274
|
+
<text x="72" y="640" fill="#4f5d75" font-family="'Geist Mono', monospace" font-size="12">✓ PASS</text>
|
|
275
|
+
<text x="176" y="640" fill="#eb6c36" font-family="'Geist Mono', monospace" font-size="12">× FAIL</text>
|
|
276
|
+
<text x="272" y="640" fill="#4f5d75" font-family="'Geist Mono', monospace" font-size="12">— SKIPPED · rule intentionally bypassed</text>
|
|
277
|
+
<text x="564" y="640" fill="#7a8399" font-family="'Geist Mono', monospace" font-size="12">○ NOT REACHED · earlier terminal result</text>
|
|
278
|
+
</svg>
|
|
279
|
+
</div>
|
|
280
|
+
|
|
281
|
+
<div data-motion-controls role="group" aria-label="Policy trace playback controls">
|
|
282
|
+
<button type="button" data-motion-action="prev">Previous</button>
|
|
283
|
+
<button type="button" data-motion-action="play" aria-pressed="false">Play</button>
|
|
284
|
+
<button type="button" data-motion-action="pause" aria-pressed="true">Pause</button>
|
|
285
|
+
<button type="button" data-motion-action="next">Next</button>
|
|
286
|
+
<button type="button" data-motion-action="replay">Replay</button>
|
|
287
|
+
<span class="keyboard-help">←/→ step · Space play/pause · R replay · Home/End jump</span>
|
|
288
|
+
</div>
|
|
289
|
+
<span data-motion-status role="status" aria-live="polite" aria-atomic="true">Static frame · all 5 rules visible</span>
|
|
290
|
+
<noscript><p>Animation controls require JavaScript. The complete final policy trace is shown above.</p></noscript>
|
|
291
|
+
</main>
|
|
292
|
+
|
|
293
|
+
<script data-diagram-controls>
|
|
294
|
+
(() => {
|
|
295
|
+
const params = new URLSearchParams(location.search);
|
|
296
|
+
const staticOverride = params.get('motion') === 'static' || document.documentElement.dataset.motion === 'static';
|
|
297
|
+
const requestedStep = params.get('step');
|
|
298
|
+
const reduce = matchMedia('(prefers-reduced-motion: reduce)');
|
|
299
|
+
document.fonts.ready.then(() => { document.documentElement.dataset.fontsReady = 'true'; });
|
|
300
|
+
|
|
301
|
+
document.querySelectorAll('[data-motion-root]').forEach((root) => {
|
|
302
|
+
const count = Number(root.dataset.stepCount);
|
|
303
|
+
const hold = parseFloat(getComputedStyle(root).getPropertyValue('--motion-hold')) || 720;
|
|
304
|
+
const parsedStep = requestedStep !== null && /^\d+$/.test(requestedStep) ? Number(requestedStep) : null;
|
|
305
|
+
const exactStep = params.get('motion') === 'step' && Number.isSafeInteger(parsedStep) && parsedStep >= 0 && parsedStep <= count ? parsedStep : null;
|
|
306
|
+
const items = [...root.querySelectorAll('[data-motion-item]')];
|
|
307
|
+
const labels = Array.from({ length: count + 1 }, (_, index) => index === 0
|
|
308
|
+
? 'Ready'
|
|
309
|
+
: items.filter((item) => !item.hasAttribute('data-motion-decorative') && Number(item.dataset.step) === index)
|
|
310
|
+
.map((item) => item.getAttribute('aria-label')).join('; '));
|
|
311
|
+
const controls = root.querySelector('[data-motion-controls]');
|
|
312
|
+
const status = root.querySelector('[data-motion-status]');
|
|
313
|
+
const visibleStep = root.querySelector('[data-motion-step-label]');
|
|
314
|
+
let step = count;
|
|
315
|
+
let timer = 0;
|
|
316
|
+
let playing = false;
|
|
317
|
+
let stepBeforeReduce = 0;
|
|
318
|
+
let resumeAfterReduce = root.dataset.motionMode === 'reveal';
|
|
319
|
+
|
|
320
|
+
const buttons = (action) => controls.querySelector(`[data-motion-action="${action}"]`);
|
|
321
|
+
const clearClock = () => { window.clearTimeout(timer); timer = 0; };
|
|
322
|
+
const announce = () => { status.textContent = `Step ${step} of ${count}: ${labels[step] || 'Complete'}`; };
|
|
323
|
+
const setControlsAvailable = (available) => {
|
|
324
|
+
controls.hidden = !available;
|
|
325
|
+
controls.setAttribute('aria-hidden', String(!available));
|
|
326
|
+
controls.dataset.playbackDisabled = String(!available);
|
|
327
|
+
controls.querySelectorAll('button').forEach((control) => { control.disabled = !available; });
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
function render(next, userInitiated = false) {
|
|
331
|
+
step = Math.max(0, Math.min(count, next));
|
|
332
|
+
root.dataset.stepCurrent = String(step);
|
|
333
|
+
root.dataset.frame = step === count ? 'end' : step === 0 ? 'start' : 'step';
|
|
334
|
+
items.forEach((item) => {
|
|
335
|
+
const itemStep = Number(item.dataset.step);
|
|
336
|
+
item.classList.toggle('is-visible', itemStep <= step);
|
|
337
|
+
item.classList.toggle('is-current', itemStep === step);
|
|
338
|
+
});
|
|
339
|
+
if (visibleStep) visibleStep.textContent = String(step);
|
|
340
|
+
const unavailable = controls.dataset.playbackDisabled === 'true';
|
|
341
|
+
buttons('prev').disabled = unavailable || step === 0;
|
|
342
|
+
buttons('next').disabled = unavailable || step === count;
|
|
343
|
+
if (userInitiated) announce();
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function pause(userInitiated = false) {
|
|
347
|
+
clearClock();
|
|
348
|
+
playing = false;
|
|
349
|
+
root.classList.remove('is-playing');
|
|
350
|
+
buttons('play').setAttribute('aria-pressed', 'false');
|
|
351
|
+
buttons('pause').setAttribute('aria-pressed', 'true');
|
|
352
|
+
if (userInitiated) status.textContent = `Paused at step ${step} of ${count}`;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function finish() {
|
|
356
|
+
pause(false);
|
|
357
|
+
root.dataset.frame = 'end';
|
|
358
|
+
status.textContent = `Complete · step ${count} of ${count}`;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function tick() {
|
|
362
|
+
if (!playing) return;
|
|
363
|
+
if (step >= count) { finish(); return; }
|
|
364
|
+
render(step + 1, false);
|
|
365
|
+
if (step >= count) { finish(); return; }
|
|
366
|
+
timer = window.setTimeout(tick, hold);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function play(fromStart = false, userInitiated = false) {
|
|
370
|
+
clearClock();
|
|
371
|
+
if (fromStart || step >= count) render(0, userInitiated);
|
|
372
|
+
playing = true;
|
|
373
|
+
root.classList.add('is-playing');
|
|
374
|
+
buttons('play').setAttribute('aria-pressed', 'true');
|
|
375
|
+
buttons('pause').setAttribute('aria-pressed', 'false');
|
|
376
|
+
timer = window.setTimeout(tick, hold);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
controls.addEventListener('click', (event) => {
|
|
380
|
+
const button = event.target.closest('[data-motion-action]');
|
|
381
|
+
if (!button) return;
|
|
382
|
+
const action = button.dataset.motionAction;
|
|
383
|
+
if (action === 'play') play(false, true);
|
|
384
|
+
if (action === 'pause') pause(true);
|
|
385
|
+
if (action === 'replay') play(true, true);
|
|
386
|
+
if (action === 'prev') { pause(false); render(step - 1, true); }
|
|
387
|
+
if (action === 'next') { pause(false); render(step + 1, true); }
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
root.addEventListener('keydown', (event) => {
|
|
391
|
+
if (event.target.matches('input, textarea, select, a[href]')) return;
|
|
392
|
+
const keys = { ArrowLeft: step - 1, ArrowRight: step + 1, Home: 0, End: count };
|
|
393
|
+
if (event.code === 'Space' && !event.target.closest('button')) {
|
|
394
|
+
event.preventDefault();
|
|
395
|
+
playing ? pause(true) : play(false, true);
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
if (!event.ctrlKey && !event.metaKey && !event.altKey && event.key.toLowerCase() === 'r') {
|
|
399
|
+
event.preventDefault();
|
|
400
|
+
play(true, true);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
if (!(event.key in keys)) return;
|
|
404
|
+
event.preventDefault();
|
|
405
|
+
pause(false);
|
|
406
|
+
render(keys[event.key], true);
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
document.addEventListener('visibilitychange', () => {
|
|
410
|
+
if (document.visibilityState === 'hidden' && playing) pause(false);
|
|
411
|
+
});
|
|
412
|
+
reduce.addEventListener('change', (event) => {
|
|
413
|
+
if (event.matches && root.dataset.motionState !== 'reduced') {
|
|
414
|
+
stepBeforeReduce = step;
|
|
415
|
+
resumeAfterReduce = playing;
|
|
416
|
+
}
|
|
417
|
+
pause(false);
|
|
418
|
+
if (event.matches) {
|
|
419
|
+
setControlsAvailable(false);
|
|
420
|
+
render(count, false);
|
|
421
|
+
root.dataset.frame = 'static';
|
|
422
|
+
root.dataset.motionState = 'reduced';
|
|
423
|
+
status.textContent = 'Reduced motion · complete static frame · playback controls unavailable';
|
|
424
|
+
} else if (staticOverride || root.dataset.motionMode === 'none') {
|
|
425
|
+
setControlsAvailable(false);
|
|
426
|
+
render(count, false);
|
|
427
|
+
root.dataset.frame = 'static';
|
|
428
|
+
root.dataset.motionState = 'static';
|
|
429
|
+
status.textContent = 'Static frame · complete diagram · playback controls unavailable';
|
|
430
|
+
} else {
|
|
431
|
+
delete root.dataset.motionState;
|
|
432
|
+
if (exactStep !== null) {
|
|
433
|
+
setControlsAvailable(false);
|
|
434
|
+
render(exactStep, false);
|
|
435
|
+
root.dataset.frame = 'step';
|
|
436
|
+
root.dataset.motionState = 'test';
|
|
437
|
+
status.textContent = `Test frame · step ${step} of ${count} · playback controls unavailable`;
|
|
438
|
+
} else {
|
|
439
|
+
setControlsAvailable(true);
|
|
440
|
+
render(stepBeforeReduce, false);
|
|
441
|
+
status.textContent = `Ready · step ${step} of ${count}`;
|
|
442
|
+
if (resumeAfterReduce && root.dataset.motionMode === 'reveal') {
|
|
443
|
+
play(false, false);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
resumeAfterReduce = false;
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
|
|
450
|
+
if (staticOverride) {
|
|
451
|
+
document.documentElement.dataset.motion = 'static';
|
|
452
|
+
pause(false);
|
|
453
|
+
setControlsAvailable(false);
|
|
454
|
+
render(count, false);
|
|
455
|
+
root.dataset.frame = 'static';
|
|
456
|
+
root.dataset.motionState = 'static';
|
|
457
|
+
status.textContent = 'Static frame · complete diagram · playback controls unavailable';
|
|
458
|
+
} else if (reduce.matches || root.dataset.motionMode === 'none') {
|
|
459
|
+
pause(false);
|
|
460
|
+
setControlsAvailable(false);
|
|
461
|
+
render(count, false);
|
|
462
|
+
root.dataset.frame = 'static';
|
|
463
|
+
root.dataset.motionState = reduce.matches ? 'reduced' : 'static';
|
|
464
|
+
status.textContent = reduce.matches
|
|
465
|
+
? 'Reduced motion · complete static frame · playback controls unavailable'
|
|
466
|
+
: 'Static frame · complete diagram · playback controls unavailable';
|
|
467
|
+
} else if (exactStep !== null) {
|
|
468
|
+
document.documentElement.dataset.motion = 'step';
|
|
469
|
+
pause(false);
|
|
470
|
+
setControlsAvailable(false);
|
|
471
|
+
render(exactStep, false);
|
|
472
|
+
root.dataset.frame = 'step';
|
|
473
|
+
root.dataset.motionState = 'test';
|
|
474
|
+
status.textContent = `Test frame · step ${step} of ${count} · playback controls unavailable`;
|
|
475
|
+
} else if (root.dataset.motionMode === 'reveal') {
|
|
476
|
+
setControlsAvailable(true);
|
|
477
|
+
render(0, false);
|
|
478
|
+
play(false, false);
|
|
479
|
+
} else {
|
|
480
|
+
pause(false);
|
|
481
|
+
setControlsAvailable(true);
|
|
482
|
+
render(0, false);
|
|
483
|
+
status.textContent = `Ready · step 0 of ${count}`;
|
|
484
|
+
}
|
|
485
|
+
root.classList.add('motion-ready');
|
|
486
|
+
});
|
|
487
|
+
})();
|
|
488
|
+
</script>
|
|
489
|
+
</body>
|
|
490
|
+
</html>
|
|
@@ -0,0 +1,64 @@
|
|
|
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>Order fulfillment · Process (dark)</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{--paper:#f5f5f5;--ink:#2d3142;--muted:#4f5d75;--soft:#7a8399;--accent:#eb6c36;--accent-tint:rgba(235,108,54,.08);--rule:rgba(45,49,66,.12);--label-rule:rgba(45,49,66,.20);--lane:rgba(45,49,66,.018);--node:#fff;--node-stroke:rgba(45,49,66,.25);--chip:rgba(45,49,66,.12);--dot:rgba(245,245,245,.10);--db:#5e7a9b;--ls:#7c8f6f;--fl:#9c6b50;--tb:#b8915a;--wb:#6e6479;--sans:'Geist',system-ui,sans-serif;--serif:'Instrument Serif',serif;--mono:'Geist Mono',ui-monospace,monospace}
|
|
11
|
+
body{font-family:var(--sans);background:var(--paper);color:var(--ink);min-height:100vh;display:flex;align-items:center;justify-content:center;padding:3rem 2rem}
|
|
12
|
+
.frame{max-width:1120px;width:100%}.eyebrow{font:500 .66rem var(--mono);letter-spacing:.18em;text-transform:uppercase;color:var(--muted);margin-bottom:.5rem}h1{font:400 clamp(1.5rem,2.4vw + .75rem,2rem)/1.15 var(--serif);letter-spacing:-.02em;margin-bottom:1.5rem}svg{width:100%;min-width:1000px;display:block}
|
|
13
|
+
svg text{font-family:var(--sans)}.mono{font-family:var(--mono)}.lane{fill:var(--lane)}.rule{stroke:var(--rule)}.label-rule{stroke:var(--label-rule)}.actor{fill:var(--muted);font:500 8px var(--mono);letter-spacing:.08em}.step-label{fill:var(--muted);font:500 6px var(--mono);letter-spacing:.12em}.step-chip{fill:var(--chip)}.step-num{fill:var(--ink);font:600 7px var(--mono)}.connector{fill:none;stroke:var(--muted);stroke-width:1}.connector.focal{stroke:var(--accent);stroke-width:1.2}.node-mask{fill:var(--paper)}.node{fill:var(--node);stroke:var(--node-stroke)}.node.focal{fill:var(--accent-tint);stroke:var(--accent);stroke-width:1.2}.role{fill:rgba(245,245,245,.10)}.role.focal{fill:rgba(240,138,89,.26)}.role-text{fill:var(--ink);font:600 6px var(--mono)}.role-text.focal{fill:var(--accent)}.node-title{fill:var(--ink);font:600 9px var(--sans)}.node-sub{fill:var(--muted);font:6.5px var(--mono)}.node-tool{fill:var(--soft);font:6.5px var(--mono)}.data-text{fill:white;font:700 5px var(--mono)}.legend-key{fill:var(--muted);font:500 7px var(--mono);letter-spacing:.12em}.legend-text{fill:var(--muted);font:8px var(--sans)}
|
|
14
|
+
</style>
|
|
15
|
+
</head>
|
|
16
|
+
<body>
|
|
17
|
+
<div class="frame">
|
|
18
|
+
<p class="eyebrow">Process · Diagram Design</p>
|
|
19
|
+
<h1>Order fulfillment across four teams</h1>
|
|
20
|
+
<svg viewBox="0 0 1064 436" xmlns="http://www.w3.org/2000/svg" aria-label="Order fulfillment process from customer order to support closure" role="img" aria-labelledby="process-dark-title process-dark-desc">
|
|
21
|
+
<title id="process-dark-title">Order fulfillment across four teams</title>
|
|
22
|
+
<desc id="process-dark-desc">Process diagram showing an order moving through customer, support, warehouse, and finance ownership from placement to close.</desc>
|
|
23
|
+
<defs>
|
|
24
|
+
<pattern id="dots" width="22" height="22" patternUnits="userSpaceOnUse"><circle cx="11" cy="11" r="0.8" fill="var(--dot)"/></pattern>
|
|
25
|
+
<marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="var(--muted)"/></marker>
|
|
26
|
+
<marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto"><polygon points="0 0,8 3,0 6" fill="var(--accent)"/></marker>
|
|
27
|
+
<marker id="arrow-sm" markerWidth="6" markerHeight="5" refX="5" refY="2.5" orient="auto"><polygon points="0 0,6 2.5,0 5" fill="var(--muted)"/></marker>
|
|
28
|
+
</defs>
|
|
29
|
+
<rect width="1064" height="436" fill="var(--paper)"/><rect width="1064" height="436" fill="url(#dots)" opacity=".55"/>
|
|
30
|
+
<rect class="lane" x="140" y="36" width="924" height="80"/><rect class="lane" x="140" y="196" width="924" height="80"/>
|
|
31
|
+
<g class="rule" stroke-width=".8"><line x1="0" y1="36" x2="1064" y2="36"/><line x1="0" y1="116" x2="1064" y2="116"/><line x1="0" y1="196" x2="1064" y2="196"/><line x1="0" y1="276" x2="1064" y2="276"/><line x1="0" y1="356" x2="1064" y2="356"/></g>
|
|
32
|
+
<line class="label-rule" x1="140" y1="36" x2="140" y2="356"/>
|
|
33
|
+
<g class="actor" text-anchor="middle"><text x="70" y="80">CUSTOMER</text><text x="70" y="160">SUPPORT</text><text x="70" y="240">WAREHOUSE</text><text x="70" y="320">FINANCE</text></g>
|
|
34
|
+
<g text-anchor="middle">
|
|
35
|
+
<rect class="step-chip" x="190" y="8" width="16" height="16" rx="8"/><text class="step-num" x="198" y="19">1</text><text class="step-label" x="198" y="32">ORDER</text>
|
|
36
|
+
<rect class="step-chip" x="302" y="8" width="16" height="16" rx="8"/><text class="step-num" x="310" y="19">2</text><text class="step-label" x="310" y="32">VERIFY</text>
|
|
37
|
+
<rect x="414" y="8" width="16" height="16" rx="8" fill="rgba(240,138,89,.22)"/><text x="422" y="19" fill="var(--accent)" font-size="7" font-weight="600" class="mono">3</text><text x="422" y="32" fill="var(--accent)" font-size="6" font-weight="500" letter-spacing=".12em" class="mono">ALLOCATE</text>
|
|
38
|
+
<rect class="step-chip" x="526" y="8" width="16" height="16" rx="8"/><text class="step-num" x="534" y="19">4</text><text class="step-label" x="534" y="32">PICK</text>
|
|
39
|
+
<rect class="step-chip" x="638" y="8" width="16" height="16" rx="8"/><text class="step-num" x="646" y="19">5</text><text class="step-label" x="646" y="32">PACK</text>
|
|
40
|
+
<rect class="step-chip" x="750" y="8" width="16" height="16" rx="8"/><text class="step-num" x="758" y="19">6</text><text class="step-label" x="758" y="32">PAY</text>
|
|
41
|
+
<rect class="step-chip" x="862" y="8" width="16" height="16" rx="8"/><text class="step-num" x="870" y="19">7</text><text class="step-label" x="870" y="32">RECEIVE</text>
|
|
42
|
+
<rect class="step-chip" x="974" y="8" width="16" height="16" rx="8"/><text class="step-num" x="982" y="19">8</text><text class="step-label" x="982" y="32">CLOSE</text>
|
|
43
|
+
</g>
|
|
44
|
+
<!-- Connectors: right exit, r=8 orthogonal bend, top/bottom entry. -->
|
|
45
|
+
<path class="connector" d="M248 76 H302 Q310 76 310 84 V124" marker-end="url(#arrow)"/><path class="connector focal" d="M360 156 H414 Q422 156 422 164 V204" marker-end="url(#arrow-accent)"/><line class="connector focal" x1="472" y1="236" x2="484" y2="236" marker-end="url(#arrow-accent)"/><line class="connector" x1="584" y1="236" x2="596" y2="236" marker-end="url(#arrow)"/><path class="connector" d="M696 236 H750 Q758 236 758 244 V284" marker-end="url(#arrow)"/><path class="connector" d="M808 316 H862 Q870 316 870 308 V108" marker-end="url(#arrow)"/><path class="connector" d="M920 76 H974 Q982 76 982 84 V124" marker-end="url(#arrow)"/>
|
|
46
|
+
<!-- Nodes -->
|
|
47
|
+
<g text-anchor="middle">
|
|
48
|
+
<g><rect class="node-mask" x="148" y="44" width="100" height="64" rx="6"/><rect class="node" x="148" y="44" width="100" height="64" rx="6"/><rect class="role" x="152" y="48" width="20" height="10" rx="2"/><text class="role-text" x="162" y="56">CUS</text><text class="node-title" x="198" y="70">Place order</text><text class="node-sub" x="198" y="84">cart → order</text><text class="node-tool" x="198" y="96">storefront</text><rect x="228" y="98" width="16" height="8" rx="2" fill="var(--db)"/><text class="data-text" x="236" y="104">DB</text></g>
|
|
49
|
+
<g><rect class="node-mask" x="260" y="124" width="100" height="64" rx="6"/><rect class="node" x="260" y="124" width="100" height="64" rx="6"/><rect class="role" x="264" y="128" width="20" height="10" rx="2"/><text class="role-text" x="274" y="136">SUP</text><text class="node-title" x="310" y="150">Verify order</text><text class="node-sub" x="310" y="164">order → cleared</text><text class="node-tool" x="310" y="176">service desk</text><rect x="264" y="178" width="16" height="8" rx="2" fill="var(--db)"/><text class="data-text" x="272" y="184">DB</text><rect x="340" y="178" width="16" height="8" rx="2" fill="var(--db)"/><text class="data-text" x="348" y="184">DB</text></g>
|
|
50
|
+
<g><rect class="node-mask" x="372" y="204" width="100" height="64" rx="6"/><rect class="node focal" x="372" y="204" width="100" height="64" rx="6"/><rect class="role focal" x="376" y="208" width="20" height="10" rx="2"/><text class="role-text focal" x="386" y="216">WHS</text><text class="node-title" x="422" y="230">Allocate stock</text><text class="node-sub" x="422" y="244">order → pick list</text><text class="node-tool" x="422" y="256">inventory system</text><rect x="376" y="258" width="16" height="8" rx="2" fill="var(--db)"/><text class="data-text" x="384" y="264">DB</text><rect x="452" y="258" width="16" height="8" rx="2" fill="var(--ls)"/><text class="data-text" x="460" y="264">LS</text></g>
|
|
51
|
+
<g><rect class="node-mask" x="484" y="204" width="100" height="64" rx="6"/><rect class="node" x="484" y="204" width="100" height="64" rx="6"/><rect class="role" x="488" y="208" width="20" height="10" rx="2"/><text class="role-text" x="498" y="216">WHS</text><text class="node-title" x="534" y="230">Pick items</text><text class="node-sub" x="534" y="244">list → picked</text><text class="node-tool" x="534" y="256">handheld scanner</text><rect x="488" y="258" width="16" height="8" rx="2" fill="var(--ls)"/><text class="data-text" x="496" y="264">LS</text><rect x="564" y="258" width="16" height="8" rx="2" fill="var(--ls)"/><text class="data-text" x="572" y="264">LS</text></g>
|
|
52
|
+
<g><rect class="node-mask" x="596" y="204" width="100" height="64" rx="6"/><rect class="node" x="596" y="204" width="100" height="64" rx="6"/><rect class="role" x="600" y="208" width="20" height="10" rx="2"/><text class="role-text" x="610" y="216">WHS</text><text class="node-title" x="646" y="230">Pack order</text><text class="node-sub" x="646" y="244">picked → shipment</text><text class="node-tool" x="646" y="256">packing station</text><rect x="600" y="258" width="16" height="8" rx="2" fill="var(--ls)"/><text class="data-text" x="608" y="264">LS</text><rect x="676" y="258" width="16" height="8" rx="2" fill="var(--fl)"/><text class="data-text" x="684" y="264">FL</text></g>
|
|
53
|
+
<g><rect class="node-mask" x="708" y="284" width="100" height="64" rx="6"/><rect class="node" x="708" y="284" width="100" height="64" rx="6"/><rect class="role" x="712" y="288" width="20" height="10" rx="2"/><text class="role-text" x="722" y="296">FIN</text><text class="node-title" x="758" y="310">Capture payment</text><text class="node-sub" x="758" y="324">shipment → receipt</text><text class="node-tool" x="758" y="336">payment gateway</text><rect x="712" y="338" width="16" height="8" rx="2" fill="var(--fl)"/><text class="data-text" x="720" y="344">FL</text><rect x="788" y="338" width="16" height="8" rx="2" fill="var(--tb)"/><text class="data-text" x="796" y="344">TB</text></g>
|
|
54
|
+
<g><rect class="node-mask" x="820" y="44" width="100" height="64" rx="6"/><rect class="node" x="820" y="44" width="100" height="64" rx="6"/><rect class="role" x="824" y="48" width="20" height="10" rx="2"/><text class="role-text" x="834" y="56">CUS</text><text class="node-title" x="870" y="70">Receive shipment</text><text class="node-sub" x="870" y="84">receipt → confirmed</text><text class="node-tool" x="870" y="96">delivery portal</text><rect x="824" y="98" width="16" height="8" rx="2" fill="var(--tb)"/><text class="data-text" x="832" y="104">TB</text><rect x="900" y="98" width="16" height="8" rx="2" fill="var(--wb)"/><text class="data-text" x="908" y="104">WB</text></g>
|
|
55
|
+
<g><rect class="node-mask" x="932" y="124" width="100" height="64" rx="6"/><rect class="node" x="932" y="124" width="100" height="64" rx="6"/><rect class="role" x="936" y="128" width="20" height="10" rx="2"/><text class="role-text" x="946" y="136">SUP</text><text class="node-title" x="982" y="150">Close order</text><text class="node-sub" x="982" y="164">confirmed → closed</text><text class="node-tool" x="982" y="176">service desk</text><rect x="936" y="178" width="16" height="8" rx="2" fill="var(--wb)"/><text class="data-text" x="944" y="184">WB</text></g>
|
|
56
|
+
</g>
|
|
57
|
+
<!-- Three-row type key -->
|
|
58
|
+
<g><text class="legend-key" x="144" y="372">STEPS</text><g text-anchor="middle"><rect class="step-chip" x="208" y="364" width="16" height="16" rx="8"/><text class="step-num" x="216" y="375">1</text><text class="legend-text" x="248" y="375">ORDER</text><rect class="step-chip" x="300" y="364" width="16" height="16" rx="8"/><text class="step-num" x="308" y="375">2</text><text class="legend-text" x="340" y="375">VERIFY</text><rect x="392" y="364" width="16" height="16" rx="8" fill="rgba(240,138,89,.22)"/><text x="400" y="375" fill="var(--accent)" font-size="7" class="mono">3</text><text x="432" y="375" fill="var(--accent)" font-size="8">ALLOCATE</text><rect class="step-chip" x="496" y="364" width="16" height="16" rx="8"/><text class="step-num" x="504" y="375">4</text><text class="legend-text" x="532" y="375">PICK</text><rect class="step-chip" x="576" y="364" width="16" height="16" rx="8"/><text class="step-num" x="584" y="375">5</text><text class="legend-text" x="612" y="375">PACK</text><rect class="step-chip" x="656" y="364" width="16" height="16" rx="8"/><text class="step-num" x="664" y="375">6</text><text class="legend-text" x="692" y="375">PAY</text><rect class="step-chip" x="736" y="364" width="16" height="16" rx="8"/><text class="step-num" x="744" y="375">7</text><text class="legend-text" x="780" y="375">RECEIVE</text><rect class="step-chip" x="832" y="364" width="16" height="16" rx="8"/><text class="step-num" x="840" y="375">8</text><text class="legend-text" x="872" y="375">CLOSE</text></g>
|
|
59
|
+
<text class="legend-key" x="144" y="393">DATA TYPE</text><rect x="220" y="386" width="16" height="8" rx="2" fill="var(--db)"/><text class="legend-text" x="244" y="393">DB · records</text><rect x="328" y="386" width="16" height="8" rx="2" fill="var(--ls)"/><text class="legend-text" x="352" y="393">LS · task</text><rect x="428" y="386" width="16" height="8" rx="2" fill="var(--fl)"/><text class="legend-text" x="452" y="393">FL · document</text><rect x="552" y="386" width="16" height="8" rx="2" fill="var(--tb)"/><text class="legend-text" x="576" y="393">TB · transaction</text><rect x="688" y="386" width="16" height="8" rx="2" fill="var(--wb)"/><text class="legend-text" x="712" y="393">WB · web status</text><text class="legend-key" x="856" y="393">LEFT IN · RIGHT OUT</text>
|
|
60
|
+
<text class="legend-key" x="144" y="414">FLOW</text><line x1="200" y1="410" x2="228" y2="410" stroke="var(--accent)" stroke-width="1.2" marker-end="url(#arrow-accent)"/><text class="legend-text" x="240" y="414">Critical handoff</text><line x1="360" y1="410" x2="388" y2="410" stroke="var(--muted)" marker-end="url(#arrow)"/><text class="legend-text" x="400" y="414">Sequential handoff</text></g>
|
|
61
|
+
</svg>
|
|
62
|
+
</div>
|
|
63
|
+
</body>
|
|
64
|
+
</html>
|