@noodleseed/agent-kit 0.13.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (121) hide show
  1. package/README.md +3 -3
  2. package/manifest.json +575 -5
  3. package/package.json +1 -1
  4. package/skills/claude-code/SKILL.md +7 -2
  5. package/skills/claude-code/examples/acme-bistro/README.md +51 -0
  6. package/skills/claude-code/examples/acme-bistro/design/UX-Document.md +435 -0
  7. package/skills/claude-code/examples/acme-bistro/design/api-contract.md +161 -0
  8. package/skills/claude-code/examples/acme-bistro/design/wireframe.html +573 -0
  9. package/skills/claude-code/examples/acme-bistro/noodle.json +5 -0
  10. package/skills/claude-code/examples/acme-bistro/package.json +20 -0
  11. package/skills/claude-code/examples/acme-bistro/src/helpers.ts +7 -0
  12. package/skills/claude-code/examples/acme-bistro/src/server.ts +149 -0
  13. package/skills/claude-code/examples/acme-bistro/src/views/menu-cart.tsx +159 -0
  14. package/skills/claude-code/examples/acme-bistro/src/views/widget-style.css +228 -0
  15. package/skills/claude-code/examples/acme-bistro/test/server.test.ts +21 -0
  16. package/skills/claude-code/examples/acme-bistro/vitest.config.ts +7 -0
  17. package/skills/claude-code/examples/acme-discovery/README.md +85 -0
  18. package/skills/claude-code/examples/acme-discovery/design/UX-Document.md +441 -0
  19. package/skills/claude-code/examples/acme-discovery/design/wireframe.html +670 -0
  20. package/skills/claude-code/examples/acme-discovery/noodle.json +5 -0
  21. package/skills/claude-code/examples/acme-discovery/package.json +20 -0
  22. package/skills/claude-code/examples/acme-discovery/src/helpers.ts +7 -0
  23. package/skills/claude-code/examples/acme-discovery/src/server.ts +202 -0
  24. package/skills/claude-code/examples/acme-discovery/src/views/discovery-carousel.tsx +155 -0
  25. package/skills/claude-code/examples/acme-discovery/src/views/widget-style.css +207 -0
  26. package/skills/claude-code/examples/acme-discovery/test/server.test.ts +24 -0
  27. package/skills/claude-code/examples/acme-discovery/vitest.config.ts +7 -0
  28. package/skills/claude-code/examples/acme-tasks/README.md +80 -0
  29. package/skills/claude-code/examples/acme-tasks/design/UX-Document.md +277 -0
  30. package/skills/claude-code/examples/acme-tasks/design/wireframe.html +603 -0
  31. package/skills/claude-code/examples/acme-tasks/noodle.json +5 -0
  32. package/skills/claude-code/examples/acme-tasks/package.json +20 -0
  33. package/skills/claude-code/examples/acme-tasks/src/helpers.ts +6 -0
  34. package/skills/claude-code/examples/acme-tasks/src/server.ts +141 -0
  35. package/skills/claude-code/examples/acme-tasks/src/views/task-list.tsx +177 -0
  36. package/skills/claude-code/examples/acme-tasks/src/views/widget-style.css +227 -0
  37. package/skills/claude-code/examples/acme-tasks/test/server.test.ts +22 -0
  38. package/skills/claude-code/examples/acme-tasks/vitest.config.ts +7 -0
  39. package/skills/claude-code/examples/food-ordering/README.md +82 -0
  40. package/skills/claude-code/examples/food-ordering/noodle.json +5 -0
  41. package/skills/claude-code/examples/food-ordering/package.json +22 -0
  42. package/skills/claude-code/examples/food-ordering/src/helpers.ts +34 -0
  43. package/skills/claude-code/examples/food-ordering/src/server.ts +412 -0
  44. package/skills/claude-code/examples/food-ordering/src/views/capabilities-card.tsx +155 -0
  45. package/skills/claude-code/examples/food-ordering/src/views/ordering-flow.tsx +659 -0
  46. package/skills/claude-code/examples/food-ordering/src/views/widget-style.css +682 -0
  47. package/skills/claude-code/examples/food-ordering/test/server.test.ts +58 -0
  48. package/skills/claude-code/examples/food-ordering/vitest.config.ts +30 -0
  49. package/skills/claude-code/examples/hello/README.md +13 -0
  50. package/skills/claude-code/examples/hello/noodle.json +5 -0
  51. package/skills/claude-code/examples/hello/package.json +16 -0
  52. package/skills/claude-code/examples/hello/src/server.ts +29 -0
  53. package/skills/claude-code/examples/hello/test/server.test.ts +8 -0
  54. package/skills/claude-code/examples/weather/README.md +54 -0
  55. package/skills/claude-code/examples/weather/noodle.json +4 -0
  56. package/skills/claude-code/examples/weather/package.json +16 -0
  57. package/skills/claude-code/examples/weather/src/server.ts +190 -0
  58. package/skills/claude-code/examples/weather/test/server.test.ts +8 -0
  59. package/skills/claude-code/references/chatgpt-compliance.md +63 -0
  60. package/skills/claude-code/references/connect-an-api.md +76 -0
  61. package/skills/claude-code/references/examples.md +16 -4
  62. package/skills/claude-code/references/experience-design.md +142 -0
  63. package/skills/codex/SKILL.md +7 -2
  64. package/skills/codex/examples/acme-bistro/README.md +51 -0
  65. package/skills/codex/examples/acme-bistro/design/UX-Document.md +435 -0
  66. package/skills/codex/examples/acme-bistro/design/api-contract.md +161 -0
  67. package/skills/codex/examples/acme-bistro/design/wireframe.html +573 -0
  68. package/skills/codex/examples/acme-bistro/noodle.json +5 -0
  69. package/skills/codex/examples/acme-bistro/package.json +20 -0
  70. package/skills/codex/examples/acme-bistro/src/helpers.ts +7 -0
  71. package/skills/codex/examples/acme-bistro/src/server.ts +149 -0
  72. package/skills/codex/examples/acme-bistro/src/views/menu-cart.tsx +159 -0
  73. package/skills/codex/examples/acme-bistro/src/views/widget-style.css +228 -0
  74. package/skills/codex/examples/acme-bistro/test/server.test.ts +21 -0
  75. package/skills/codex/examples/acme-bistro/vitest.config.ts +7 -0
  76. package/skills/codex/examples/acme-discovery/README.md +85 -0
  77. package/skills/codex/examples/acme-discovery/design/UX-Document.md +441 -0
  78. package/skills/codex/examples/acme-discovery/design/wireframe.html +670 -0
  79. package/skills/codex/examples/acme-discovery/noodle.json +5 -0
  80. package/skills/codex/examples/acme-discovery/package.json +20 -0
  81. package/skills/codex/examples/acme-discovery/src/helpers.ts +7 -0
  82. package/skills/codex/examples/acme-discovery/src/server.ts +202 -0
  83. package/skills/codex/examples/acme-discovery/src/views/discovery-carousel.tsx +155 -0
  84. package/skills/codex/examples/acme-discovery/src/views/widget-style.css +207 -0
  85. package/skills/codex/examples/acme-discovery/test/server.test.ts +24 -0
  86. package/skills/codex/examples/acme-discovery/vitest.config.ts +7 -0
  87. package/skills/codex/examples/acme-tasks/README.md +80 -0
  88. package/skills/codex/examples/acme-tasks/design/UX-Document.md +277 -0
  89. package/skills/codex/examples/acme-tasks/design/wireframe.html +603 -0
  90. package/skills/codex/examples/acme-tasks/noodle.json +5 -0
  91. package/skills/codex/examples/acme-tasks/package.json +20 -0
  92. package/skills/codex/examples/acme-tasks/src/helpers.ts +6 -0
  93. package/skills/codex/examples/acme-tasks/src/server.ts +141 -0
  94. package/skills/codex/examples/acme-tasks/src/views/task-list.tsx +177 -0
  95. package/skills/codex/examples/acme-tasks/src/views/widget-style.css +227 -0
  96. package/skills/codex/examples/acme-tasks/test/server.test.ts +22 -0
  97. package/skills/codex/examples/acme-tasks/vitest.config.ts +7 -0
  98. package/skills/codex/examples/food-ordering/README.md +82 -0
  99. package/skills/codex/examples/food-ordering/noodle.json +5 -0
  100. package/skills/codex/examples/food-ordering/package.json +22 -0
  101. package/skills/codex/examples/food-ordering/src/helpers.ts +34 -0
  102. package/skills/codex/examples/food-ordering/src/server.ts +412 -0
  103. package/skills/codex/examples/food-ordering/src/views/capabilities-card.tsx +155 -0
  104. package/skills/codex/examples/food-ordering/src/views/ordering-flow.tsx +659 -0
  105. package/skills/codex/examples/food-ordering/src/views/widget-style.css +682 -0
  106. package/skills/codex/examples/food-ordering/test/server.test.ts +58 -0
  107. package/skills/codex/examples/food-ordering/vitest.config.ts +30 -0
  108. package/skills/codex/examples/hello/README.md +13 -0
  109. package/skills/codex/examples/hello/noodle.json +5 -0
  110. package/skills/codex/examples/hello/package.json +16 -0
  111. package/skills/codex/examples/hello/src/server.ts +29 -0
  112. package/skills/codex/examples/hello/test/server.test.ts +8 -0
  113. package/skills/codex/examples/weather/README.md +54 -0
  114. package/skills/codex/examples/weather/noodle.json +4 -0
  115. package/skills/codex/examples/weather/package.json +16 -0
  116. package/skills/codex/examples/weather/src/server.ts +190 -0
  117. package/skills/codex/examples/weather/test/server.test.ts +8 -0
  118. package/skills/codex/references/chatgpt-compliance.md +63 -0
  119. package/skills/codex/references/connect-an-api.md +76 -0
  120. package/skills/codex/references/examples.md +16 -4
  121. package/skills/codex/references/experience-design.md +142 -0
@@ -0,0 +1,573 @@
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>Acme Bistro × ChatGPT — End-to-End Wireframes</title>
7
+ <style>
8
+ @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;600&display=swap');
9
+ * { margin: 0; padding: 0; box-sizing: border-box; }
10
+ body { font-family: 'Inter', -apple-system, sans-serif; background: #f4f5f7; color: #1a1211; line-height: 1.55; }
11
+
12
+ /* ── Acme Bistro brand tokens (from server branding) ── */
13
+ :root {
14
+ --acme-red: #B91C1C;
15
+ --acme-red-deep: #991B1B;
16
+ --acme-red-soft: #FEF3F2;
17
+ --acme-red-border: #FBD5D2;
18
+ --acme-dark: #1A1211;
19
+ --green: #15803D; --green-soft: #F0FDF4; --green-border: #BBF7D0;
20
+ --amber: #B45309; --amber-soft: #FFFBEB; --amber-border: #FDE68A;
21
+ }
22
+
23
+ /* ── Page Header ── */
24
+ .page-header { background: #fff; border-bottom: 1px solid #e0dddb; padding: 30px 48px; position: sticky; top: 0; z-index: 100; }
25
+ .page-header h1 { font-size: 22px; font-weight: 800; letter-spacing: -0.4px; }
26
+ .page-header h1 .brand { color: var(--acme-red); }
27
+ .page-header p { font-size: 13px; color: #8a8580; margin-top: 4px; }
28
+ .page-header .scope { display: inline-block; margin-top: 10px; font-size: 11px; font-weight: 700; letter-spacing: 0.5px; padding: 5px 13px; background: var(--acme-dark); color: #fff; border-radius: 5px; }
29
+ .page-header .scope b { color: var(--acme-red-border); }
30
+
31
+ /* ── Section Nav ── */
32
+ .section-nav { background: #fff; border-bottom: 1px solid #eee; padding: 11px 48px; display: flex; gap: 22px; font-size: 12px; font-weight: 600; position: sticky; top: 92px; z-index: 99; }
33
+ .section-nav a { color: #8a8580; text-decoration: none; }
34
+ .section-nav a:hover { color: var(--acme-red); }
35
+
36
+ .container { max-width: 1440px; margin: 0 auto; padding: 36px 48px 80px; }
37
+
38
+ /* ── Legend ── */
39
+ .vocab { display: flex; gap: 16px; flex-wrap: wrap; margin: 0 0 20px; padding: 14px 18px; background: #fff; border: 1px solid #e6e3e0; border-radius: 12px; font-size: 12px; color: #555; }
40
+ .vocab-item { display: flex; align-items: center; gap: 8px; }
41
+ .vocab-sw { width: 16px; height: 16px; border-radius: 4px; border: 1px solid rgba(0,0,0,0.08); }
42
+ .sw-red { background: var(--acme-red); } .sw-green { background: var(--green); }
43
+ .sw-amber { background: var(--amber); } .sw-dark { background: var(--acme-dark); }
44
+ .sw-grey { background: #cfcac5; } .sw-dash { background: repeating-linear-gradient(45deg,#fff,#fff 3px,#cfcac5 3px,#cfcac5 5px); }
45
+
46
+ /* ── Section ── */
47
+ .section { margin-bottom: 56px; }
48
+ .section-label { font-size: 11px; font-weight: 700; letter-spacing: 1.5px; text-transform: uppercase; color: #a39d97; margin-bottom: 8px; display: block; }
49
+ .section-title { font-size: 27px; font-weight: 800; letter-spacing: -0.5px; margin-bottom: 6px; }
50
+ .section-subtitle { font-size: 14px; color: #6b655f; margin-bottom: 22px; max-width: 820px; }
51
+
52
+ /* ── Rationale Block ── */
53
+ .rationale { background: #fff; border: 1px solid #e6e3e0; border-left: 3px solid var(--acme-red); border-radius: 10px; padding: 16px 20px; margin-bottom: 22px; max-width: 960px; }
54
+ .rationale h4 { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.8px; color: #a39d97; margin-bottom: 9px; }
55
+ .rationale p { font-size: 13px; color: #46413c; line-height: 1.65; margin-bottom: 8px; }
56
+ .rationale p:last-child { margin-bottom: 0; }
57
+ .r-tag { display: inline-block; font-size: 10px; font-weight: 700; padding: 2px 8px; border-radius: 4px; margin-right: 4px; letter-spacing: 0.3px; }
58
+ .r-tag.ux { background: #EEF2FF; color: #4338CA; }
59
+ .r-tag.ui { background: #ECFEFF; color: #0E7490; }
60
+ .r-tag.acme { background: var(--acme-red-soft); color: var(--acme-red-deep); }
61
+ .r-tag.trust { background: var(--green-soft); color: var(--green); }
62
+ code { background: #f1efec; padding: 1px 5px; border-radius: 3px; font-size: 11px; font-family: 'JetBrains Mono', monospace; }
63
+
64
+ /* ── Phone Row ── */
65
+ .phones-row { display: flex; gap: 24px; overflow-x: auto; padding-bottom: 12px; align-items: flex-start; }
66
+ .phone-step { flex-shrink: 0; display: flex; flex-direction: column; align-items: center; }
67
+ .step-label { font-size: 11px; font-weight: 700; color: #8a8580; text-transform: uppercase; letter-spacing: 0.8px; margin-bottom: 12px; text-align: center; max-width: 300px; }
68
+ .step-label small { display: block; font-weight: 400; letter-spacing: 0; text-transform: none; color: #b0aaa4; margin-top: 3px; }
69
+ .phone { width: 300px; min-height: 600px; background: #fff; border: 2px solid var(--acme-dark); border-radius: 30px; overflow: hidden; display: flex; flex-direction: column; }
70
+ .phone.offapp { border: 2px dashed #b0aaa4; }
71
+ .phone-notch { width: 90px; height: 22px; background: var(--acme-dark); border-radius: 0 0 12px 12px; margin: 0 auto; flex-shrink: 0; }
72
+ .phone.offapp .phone-notch { background: #b0aaa4; }
73
+ .phone-screen { padding: 14px; display: flex; flex-direction: column; gap: 10px; flex: 1; }
74
+ .step-arrow { display: flex; align-items: center; justify-content: center; flex-shrink: 0; align-self: center; width: 32px; font-size: 22px; color: #cfcac5; padding-top: 260px; }
75
+
76
+ /* ── Chrome ── */
77
+ .chatgpt-header { display: flex; align-items: center; justify-content: space-between; padding: 6px 0 9px; border-bottom: 1px solid #eee; }
78
+ .chatgpt-header .model-name { font-size: 13px; font-weight: 600; }
79
+ .chatgpt-header .dots { font-size: 17px; color: #b0aaa4; letter-spacing: 2px; }
80
+ .browser-header { display: flex; align-items: center; gap: 7px; padding: 7px 9px; background: #f1efec; border-radius: 8px; font-size: 10px; color: #6b655f; }
81
+ .browser-header .lock { font-size: 10px; }
82
+ .browser-header .url { font-family: 'JetBrains Mono', monospace; font-size: 9.5px; color: #46413c; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
83
+
84
+ /* ── Messages ── */
85
+ .msg { max-width: 92%; font-size: 12.5px; line-height: 1.55; }
86
+ .msg.user { align-self: flex-end; background: var(--acme-dark); color: #fff; padding: 9px 13px; border-radius: 16px 16px 4px 16px; margin-left: auto; }
87
+ .msg.assistant { color: #1a1211; padding: 2px 0; }
88
+ .msg.assistant strong { font-weight: 600; }
89
+
90
+ /* ── Tool Call ── */
91
+ .tool-call { display: flex; align-items: center; gap: 8px; padding: 7px 11px; background: #faf8f6; border: 1px solid #e6e3e0; border-radius: 9px; font-size: 10.5px; color: #6b655f; }
92
+ .tool-call .icon { width: 19px; height: 19px; background: var(--acme-red); border-radius: 5px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
93
+ .tool-call .icon svg { width: 12px; height: 12px; stroke: #fff; fill: none; stroke-width: 2; }
94
+ .tool-call .label { font-weight: 700; color: var(--acme-dark); font-family: 'JetBrains Mono', monospace; font-size: 10px; }
95
+ .tool-call .mono-tool { font-family: 'JetBrains Mono', monospace; font-size: 9.5px; color: #8a8580; }
96
+
97
+ /* ── MenuCart widget ── */
98
+ .wcard { border: 1.5px solid var(--acme-red-border); border-radius: 14px; overflow: hidden; background: #fff; }
99
+ .wcard-head { display: flex; align-items: center; gap: 9px; padding: 11px 13px; background: var(--acme-red-soft); border-bottom: 1px solid var(--acme-red-border); }
100
+ .wcard-head .logo { width: 26px; height: 26px; border-radius: 7px; background: var(--acme-red); display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
101
+ .wcard-head .logo svg { width: 15px; height: 15px; stroke: #fff; fill: none; stroke-width: 1.7; }
102
+ .wc-title { font-size: 13px; font-weight: 800; }
103
+ .wc-status { font-size: 10px; color: #8a8580; margin-top: 1px; line-height: 1.35; }
104
+ .wc-chip { margin-left: auto; font-size: 9.5px; font-weight: 700; padding: 3px 8px; background: #fff; border: 1px solid var(--acme-red-border); color: var(--acme-red-deep); border-radius: 20px; white-space: nowrap; }
105
+ .menu-row { display: flex; align-items: center; gap: 8px; padding: 9px 13px; border-bottom: 1px solid #f4f2ef; }
106
+ .mr-main { flex: 1; }
107
+ .mr-name { font-size: 12px; font-weight: 600; }
108
+ .mr-kind { font-size: 9.5px; color: #a39d97; text-transform: uppercase; letter-spacing: 0.4px; }
109
+ .mr-price { font-size: 12px; font-weight: 700; color: #46413c; }
110
+ .mr-qty { display: flex; align-items: center; gap: 7px; }
111
+ .step-btn { width: 20px; height: 20px; border: 1px solid #d8d3ce; border-radius: 6px; display: flex; align-items: center; justify-content: center; font-size: 12px; color: #46413c; background: #fff; }
112
+ .step-btn.on { border-color: var(--acme-red); color: var(--acme-red); }
113
+ .step-btn.dis { opacity: 0.3; }
114
+ .mr-count { font-size: 12px; font-weight: 700; min-width: 12px; text-align: center; }
115
+ .wc-foot { display: flex; align-items: center; gap: 10px; padding: 12px 13px 8px; }
116
+ .wc-total { font-size: 13px; color: #46413c; }
117
+ .wc-total strong { font-size: 16px; font-weight: 800; color: var(--acme-dark); margin-left: 4px; }
118
+ .wc-cta { margin-left: auto; display: inline-flex; align-items: center; gap: 6px; padding: 9px 15px; background: var(--acme-red); color: #fff; border: none; border-radius: 10px; font-size: 12px; font-weight: 700; cursor: pointer; }
119
+ .wc-cta svg { width: 14px; height: 14px; stroke: #fff; fill: none; stroke-width: 2; }
120
+ .wc-cta.dis { opacity: 0.4; }
121
+ .wc-note { padding: 0 13px 12px; font-size: 9.5px; color: #a39d97; line-height: 1.45; }
122
+ .wc-note b { color: var(--green); }
123
+
124
+ /* ── Handoff card ── */
125
+ .handoff-card { border: 1.5px solid var(--acme-red-border); border-radius: 14px; background: #fff; text-align: center; padding: 16px 15px 13px; }
126
+ .handoff-card .glyph { width: 42px; height: 42px; margin: 0 auto 8px; border-radius: 11px; background: var(--acme-red-soft); display: flex; align-items: center; justify-content: center; }
127
+ .handoff-card .glyph svg { width: 22px; height: 22px; stroke: var(--acme-red); fill: none; stroke-width: 1.6; }
128
+ .handoff-card h4 { font-size: 13.5px; font-weight: 800; margin-bottom: 4px; }
129
+ .handoff-card p { font-size: 11px; color: #6b655f; margin-bottom: 11px; line-height: 1.5; }
130
+ .mini-sum { background: #faf8f6; border: 1px solid #eae7e3; border-radius: 9px; padding: 9px 11px; margin: 0 0 11px; text-align: left; }
131
+ .mini-sum .row { display: flex; justify-content: space-between; font-size: 11px; color: #6b655f; padding: 2px 0; }
132
+ .mini-sum .row.total { font-size: 12.5px; font-weight: 800; color: var(--acme-dark); border-top: 1px solid #eae7e3; margin-top: 4px; padding-top: 5px; }
133
+ .pay-link { font-size: 9px; color: #a39d97; margin-top: 10px; line-height: 1.55; }
134
+ .pay-link code { font-size: 8.5px; }
135
+ .pay-link b { color: var(--acme-dark); }
136
+
137
+ .cta-primary { display: inline-flex; align-items: center; justify-content: center; gap: 6px; width: 100%; padding: 10px; background: var(--acme-red); color: #fff; border: none; border-radius: 10px; font-size: 12.5px; font-weight: 700; cursor: pointer; margin-bottom: 6px; }
138
+ .cta-ghost { display: block; width: 100%; padding: 9px; background: transparent; color: var(--acme-dark); border: 1.5px solid #d8d3ce; border-radius: 10px; font-size: 12px; font-weight: 600; cursor: pointer; }
139
+
140
+ /* ── Off-app checkout body ── */
141
+ .checkout-body { flex: 1; display: flex; flex-direction: column; gap: 9px; padding-top: 4px; }
142
+ .co-brand { font-size: 14px; font-weight: 800; color: var(--acme-red); }
143
+ .co-sub { font-size: 10px; color: #8a8580; }
144
+ .co-field { border: 1px solid #e6e3e0; border-radius: 9px; padding: 9px 11px; }
145
+ .co-field .lbl { font-size: 9px; color: #a39d97; text-transform: uppercase; letter-spacing: 0.5px; }
146
+ .co-field .val { font-size: 12px; color: #46413c; margin-top: 3px; font-family: 'JetBrains Mono', monospace; }
147
+ .co-field.card { background: var(--amber-soft); border-color: var(--amber-border); }
148
+ .co-line { display: flex; justify-content: space-between; font-size: 11px; color: #6b655f; padding: 2px 0; }
149
+ .co-line.total { font-weight: 800; color: var(--acme-dark); font-size: 13px; border-top: 1px solid #eee; padding-top: 5px; margin-top: 3px; }
150
+ .co-pay { padding: 11px; background: var(--acme-red); color: #fff; border: none; border-radius: 10px; font-size: 13px; font-weight: 700; text-align: center; margin-top: auto; }
151
+ .co-secure { font-size: 9.5px; color: #a39d97; text-align: center; margin-top: 7px; }
152
+
153
+ /* ── Composer ── */
154
+ .composer { margin-top: auto; padding: 9px 0 2px; border-top: 1px solid #eee; }
155
+ .composer-bar { display: flex; align-items: center; background: #f1efec; border-radius: 20px; padding: 8px 12px; font-size: 11.5px; color: #a39d97; }
156
+ .composer-bar .send { width: 24px; height: 24px; background: var(--acme-dark); border-radius: 50%; margin-left: auto; display: flex; align-items: center; justify-content: center; color: #fff; font-size: 12px; }
157
+
158
+ /* ── Widget Gallery ── */
159
+ .gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px,1fr)); gap: 22px; }
160
+ .sf { }
161
+ .sf-name { font-size: 12px; font-weight: 700; margin-bottom: 8px; color: #46413c; }
162
+ .sf-name span { font-weight: 400; color: #a39d97; }
163
+
164
+ /* ── API appendix ── */
165
+ .api-panel { background: #fff; border: 1px solid #e6e3e0; border-radius: 12px; overflow: hidden; margin-bottom: 18px; }
166
+ .api-panel-header { background: var(--acme-dark); color: #fff; padding: 12px 18px; font-size: 13px; font-weight: 700; }
167
+ .api-step { padding: 14px 18px; border-bottom: 1px solid #f1efec; }
168
+ .api-step:last-child { border-bottom: none; }
169
+ .api-step-label { font-size: 10.5px; font-weight: 700; color: #a39d97; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 7px; }
170
+ .api-endpoint { background: #faf8f6; border: 1px solid #eae7e3; border-radius: 8px; padding: 9px 12px; margin-bottom: 7px; }
171
+ .api-endpoint .kind { display: inline-block; font-size: 9px; font-weight: 700; padding: 2px 6px; border-radius: 3px; margin-right: 6px; letter-spacing: 0.4px; font-family: 'JetBrains Mono', monospace; }
172
+ .kind.read { background: var(--green-soft); color: var(--green); }
173
+ .kind.write { background: #ECFEFF; color: #0E7490; }
174
+ .kind.link { background: var(--acme-red-soft); color: var(--acme-red-deep); }
175
+ .api-endpoint .path { font-size: 12.5px; font-weight: 700; color: var(--acme-dark); font-family: 'JetBrains Mono', monospace; }
176
+ .api-endpoint .desc { font-size: 11px; color: #8a8580; margin-top: 3px; }
177
+ .api-note { font-size: 11px; color: #5f594f; background: var(--amber-soft); border-left: 3px solid var(--amber-border); padding: 8px 12px; border-radius: 0 6px 6px 0; margin-top: 6px; }
178
+ .api-note strong { color: #46413c; }
179
+
180
+ /* ── Audit table ── */
181
+ .audit-table { width: 100%; border-collapse: collapse; font-size: 12px; margin-top: 14px; }
182
+ .audit-table th { text-align: left; padding: 9px 13px; background: #faf8f6; font-weight: 700; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.5px; color: #a39d97; border-bottom: 1px solid #e6e3e0; }
183
+ .audit-table td { padding: 9px 13px; border-bottom: 1px solid #f1efec; vertical-align: top; color: #46413c; }
184
+ .audit-table td:first-child { font-weight: 600; color: #2d2825; }
185
+ .audit-pass { color: var(--green); font-weight: 700; white-space: nowrap; }
186
+ .audit-guard td:first-child { color: var(--acme-red-deep); }
187
+
188
+ .page-divider { border: none; border-top: 2px solid #e6e3e0; margin: 48px 0; }
189
+ .footer { text-align: center; font-size: 11px; color: #b0aaa4; padding: 24px 0 8px; }
190
+ </style>
191
+ </head>
192
+ <body>
193
+
194
+ <div class="page-header">
195
+ <h1><span class="brand">Acme Bistro</span> × ChatGPT App — End-to-End Wireframes</h1>
196
+ <p>Prepared by Noodle Seed · Browse → Build order → Confirm → Hand off to pay · Single-restaurant storefront</p>
197
+ <span class="scope">FUNNEL BOUNDARY: menu, order &amp; confirmation IN CHATGPT · <b>PAYMENT ONLY OFF-APP</b> (pay.acme.example) · no per-user auth</span>
198
+ </div>
199
+
200
+ <div class="section-nav">
201
+ <a href="#legend">Legend</a>
202
+ <a href="#flow">End-to-End Flow</a>
203
+ <a href="#build">Build &amp; Total</a>
204
+ <a href="#handoff">Payment Handoff</a>
205
+ <a href="#gallery">Widget Gallery</a>
206
+ <a href="#api">MCP Tools</a>
207
+ <a href="#compliance">Compliance Audit</a>
208
+ </div>
209
+
210
+ <div class="container">
211
+
212
+ <!-- ── LEGEND ── -->
213
+ <div class="section" id="legend">
214
+ <div class="vocab">
215
+ <div class="vocab-item"><div class="vocab-sw sw-red"></div><strong>Acme Red</strong> — primary CTA + logo mark only</div>
216
+ <div class="vocab-item"><div class="vocab-sw sw-green"></div><strong>Green</strong> — trust / "card never in chat"</div>
217
+ <div class="vocab-item"><div class="vocab-sw sw-amber"></div><strong>Amber</strong> — off-app payment surface</div>
218
+ <div class="vocab-item"><div class="vocab-sw sw-dark"></div><strong>Dark</strong> — text, user bubbles</div>
219
+ <div class="vocab-item"><div class="vocab-sw sw-grey"></div><strong>Grey</strong> — neutral / host UI</div>
220
+ <div class="vocab-item"><div class="vocab-sw sw-dash"></div><strong>Dashed frame</strong> — off-app destination</div>
221
+ </div>
222
+ <div class="rationale">
223
+ <h4>How to read these wireframes</h4>
224
+ <p><span class="r-tag ui">UI</span> <strong>Solid-border phones are the ChatGPT App</strong> (the Noodle Seed <code>MenuCart</code> widget rendered inline). <strong>Dashed-border phones are off-app</strong> — reached only after the payment hand-off, on Acme's own checkout. Every widget is preceded by its <code>tool-call</code> chip so you can see exactly which tool the model invoked.</p>
225
+ <p><span class="r-tag trust">TRUST</span> <strong>The app never guesses and never touches a card.</strong> Menu, prices, and totals are grounded in the <code>show_menu</code> data; the diner's card is entered only on the amber off-app checkout. This is the whole safety story of the app, and it is visible in the pixels.</p>
226
+ </div>
227
+ </div>
228
+
229
+ <!-- ═══ SECTION 1: END-TO-END FLOW ═══ -->
230
+ <div class="section" id="flow">
231
+ <span class="section-label">The whole journey</span>
232
+ <div class="section-title">One conversation, from craving to a paid-ready cart</div>
233
+ <div class="section-subtitle">A diner names Acme and their order in plain language; the model renders the menu, reflects the order into a live cart, confirms the total, and mints a signed payment link. Only the final step — entering a card — leaves ChatGPT.</div>
234
+
235
+ <div class="phones-row">
236
+
237
+ <!-- Step 1: Menu -->
238
+ <div class="phone-step">
239
+ <div class="step-label">1 · Show the menu<small>show_menu → MenuCart</small></div>
240
+ <div class="phone"><div class="phone-notch"></div><div class="phone-screen">
241
+ <div class="chatgpt-header"><span class="model-name">ChatGPT</span><span class="dots">···</span></div>
242
+ <div class="msg user">Order me two margheritas and a lemon tart from Acme Bistro.</div>
243
+ <div class="tool-call"><span class="icon"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="4"/></svg></span><span><span class="label">show_menu</span> <span class="mono-tool">{customer:"Guest"}</span></span></div>
244
+ <div class="msg assistant">Here's your Acme Bistro order — building it now:</div>
245
+ <div class="wcard">
246
+ <div class="wcard-head">
247
+ <span class="logo"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="4"/></svg></span>
248
+ <div><div class="wc-title">Acme Bistro</div><div class="wc-status">Menu ready. Build the order here; pay at checkout.</div></div>
249
+ <span class="wc-chip">0 in cart</span>
250
+ </div>
251
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Stone-baked Margherita</span> <span class="mr-kind">Mains</span></span><span class="mr-price">$14</span><span class="mr-qty"><span class="step-btn dis">−</span><span class="mr-count">0</span><span class="step-btn">+</span></span></div>
252
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Harvest Roast Bowl</span> <span class="mr-kind">Mains</span></span><span class="mr-price">$13</span><span class="mr-qty"><span class="step-btn dis">−</span><span class="mr-count">0</span><span class="step-btn">+</span></span></div>
253
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">House Garden Salad</span> <span class="mr-kind">Starters</span></span><span class="mr-price">$11</span><span class="mr-qty"><span class="step-btn dis">−</span><span class="mr-count">0</span><span class="step-btn">+</span></span></div>
254
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Lemon Tart</span> <span class="mr-kind">Desserts</span></span><span class="mr-price">$8</span><span class="mr-qty"><span class="step-btn dis">−</span><span class="mr-count">0</span><span class="step-btn">+</span></span></div>
255
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Sparkling Water</span> <span class="mr-kind">Drinks</span></span><span class="mr-price">$4</span><span class="mr-qty"><span class="step-btn dis">−</span><span class="mr-count">0</span><span class="step-btn">+</span></span></div>
256
+ <div class="wc-foot"><span class="wc-total">Total <strong>$0</strong></span><button class="wc-cta dis"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/></svg>Check out &amp; pay</button></div>
257
+ <div class="wc-note">Payment happens on acme.example — <b>your card is never entered in chat.</b></div>
258
+ </div>
259
+ <div class="composer"><div class="composer-bar">Message<span class="send">↑</span></div></div>
260
+ </div></div>
261
+ </div>
262
+ <div class="step-arrow">→</div>
263
+
264
+ <!-- Step 2: NL order reflected -->
265
+ <div class="phone-step">
266
+ <div class="step-label">2 · Parse the order<small>add_to_cart ×2 from language</small></div>
267
+ <div class="phone"><div class="phone-notch"></div><div class="phone-screen">
268
+ <div class="chatgpt-header"><span class="model-name">ChatGPT</span><span class="dots">···</span></div>
269
+ <div class="tool-call"><span class="icon"><svg viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></svg></span><span><span class="label">add_to_cart</span> <span class="mono-tool">{item:"stone_pizza", quantity:2}</span></span></div>
270
+ <div class="tool-call"><span class="icon"><svg viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></svg></span><span><span class="label">add_to_cart</span> <span class="mono-tool">{item:"lemon_tart", quantity:1}</span></span></div>
271
+ <div class="msg assistant">Two Stone-baked Margheritas and a Lemon Tart — <strong>$36</strong> so far. Want a drink or a side, or shall I take you to checkout?</div>
272
+ <div class="wcard">
273
+ <div class="wcard-head">
274
+ <span class="logo"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="4"/></svg></span>
275
+ <div><div class="wc-title">Acme Bistro</div><div class="wc-status">Added 2 × Stone-baked Margherita.</div></div>
276
+ <span class="wc-chip">3 in cart</span>
277
+ </div>
278
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Stone-baked Margherita</span> <span class="mr-kind">Mains</span></span><span class="mr-price">$14</span><span class="mr-qty"><span class="step-btn on">−</span><span class="mr-count">2</span><span class="step-btn">+</span></span></div>
279
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Harvest Roast Bowl</span> <span class="mr-kind">Mains</span></span><span class="mr-price">$13</span><span class="mr-qty"><span class="step-btn dis">−</span><span class="mr-count">0</span><span class="step-btn">+</span></span></div>
280
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">House Garden Salad</span> <span class="mr-kind">Starters</span></span><span class="mr-price">$11</span><span class="mr-qty"><span class="step-btn dis">−</span><span class="mr-count">0</span><span class="step-btn">+</span></span></div>
281
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Lemon Tart</span> <span class="mr-kind">Desserts</span></span><span class="mr-price">$8</span><span class="mr-qty"><span class="step-btn on">−</span><span class="mr-count">1</span><span class="step-btn">+</span></span></div>
282
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Sparkling Water</span> <span class="mr-kind">Drinks</span></span><span class="mr-price">$4</span><span class="mr-qty"><span class="step-btn dis">−</span><span class="mr-count">0</span><span class="step-btn">+</span></span></div>
283
+ <div class="wc-foot"><span class="wc-total">Total <strong>$36</strong></span><button class="wc-cta"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/></svg>Check out &amp; pay</button></div>
284
+ <div class="wc-note">Payment happens on acme.example — <b>your card is never entered in chat.</b></div>
285
+ </div>
286
+ <div class="composer"><div class="composer-bar">"add a sparkling water"<span class="send">↑</span></div></div>
287
+ </div></div>
288
+ </div>
289
+ <div class="step-arrow">→</div>
290
+
291
+ <!-- Step 3: Edit + confirm total -->
292
+ <div class="phone-step">
293
+ <div class="step-label">3 · Edit &amp; confirm total<small>add / remove · live sum</small></div>
294
+ <div class="phone"><div class="phone-notch"></div><div class="phone-screen">
295
+ <div class="chatgpt-header"><span class="model-name">ChatGPT</span><span class="dots">···</span></div>
296
+ <div class="msg user">Add a sparkling water too.</div>
297
+ <div class="tool-call"><span class="icon"><svg viewBox="0 0 24 24"><path d="M12 5v14M5 12h14"/></svg></span><span><span class="label">add_to_cart</span> <span class="mono-tool">{item:"sparkling", quantity:1}</span></span></div>
298
+ <div class="msg assistant">Added a Sparkling Water — your total is <strong>$40</strong> for four items. Ready to pay whenever you are.</div>
299
+ <div class="wcard">
300
+ <div class="wcard-head">
301
+ <span class="logo"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="4"/></svg></span>
302
+ <div><div class="wc-title">Acme Bistro</div><div class="wc-status">Added Sparkling Water.</div></div>
303
+ <span class="wc-chip">4 in cart</span>
304
+ </div>
305
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Stone-baked Margherita</span> <span class="mr-kind">Mains</span></span><span class="mr-price">$14</span><span class="mr-qty"><span class="step-btn on">−</span><span class="mr-count">2</span><span class="step-btn">+</span></span></div>
306
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Lemon Tart</span> <span class="mr-kind">Desserts</span></span><span class="mr-price">$8</span><span class="mr-qty"><span class="step-btn on">−</span><span class="mr-count">1</span><span class="step-btn">+</span></span></div>
307
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Sparkling Water</span> <span class="mr-kind">Drinks</span></span><span class="mr-price">$4</span><span class="mr-qty"><span class="step-btn on">−</span><span class="mr-count">1</span><span class="step-btn">+</span></span></div>
308
+ <div class="wc-foot"><span class="wc-total">Total <strong>$40</strong></span><button class="wc-cta"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/></svg>Check out &amp; pay</button></div>
309
+ <div class="wc-note">Payment happens on acme.example — <b>your card is never entered in chat.</b></div>
310
+ </div>
311
+ <div class="composer"><div class="composer-bar">"check out and pay"<span class="send">↑</span></div></div>
312
+ </div></div>
313
+ </div>
314
+ <div class="step-arrow">→</div>
315
+
316
+ <!-- Step 4: Checkout handoff card -->
317
+ <div class="phone-step">
318
+ <div class="step-label">4 · Mint the payment link<small>create_checkout (in-chat)</small></div>
319
+ <div class="phone"><div class="phone-notch"></div><div class="phone-screen">
320
+ <div class="chatgpt-header"><span class="model-name">ChatGPT</span><span class="dots">···</span></div>
321
+ <div class="msg user">Check out and pay.</div>
322
+ <div class="tool-call"><span class="icon"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/></svg></span><span><span class="label">create_checkout</span> <span class="mono-tool">{total:40, cartToken:"…"}</span></span></div>
323
+ <div class="msg assistant">Your order's ready — I've opened Acme's secure checkout to take payment:</div>
324
+ <div class="handoff-card">
325
+ <div class="glyph"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/></svg></div>
326
+ <h4>Pay on Acme Bistro checkout</h4>
327
+ <p>Your order is staged and ready. Enter your card on <strong>acme.example</strong> — it's never typed in chat.</p>
328
+ <div class="mini-sum">
329
+ <div class="row"><span>2 × Stone-baked Margherita</span><span>$28</span></div>
330
+ <div class="row"><span>1 × Lemon Tart</span><span>$8</span></div>
331
+ <div class="row"><span>1 × Sparkling Water</span><span>$4</span></div>
332
+ <div class="row total"><span>Total</span><span>$40</span></div>
333
+ </div>
334
+ <button class="cta-primary"><svg viewBox="0 0 24 24" style="width:14px;height:14px;stroke:#fff;fill:none;stroke-width:2"><path d="M5 12h14M13 6l6 6-6 6"/></svg>Pay $40 on acme.example ↗</button>
335
+ <button class="cta-ghost">Keep editing</button>
336
+ <div class="pay-link">Opens <code>pay.acme.example/checkout?cart=…&amp;total=40&amp;src=chatgpt</code><br>Signed link · expires in <b>15 min</b> · 🔒 payment handled by Acme</div>
337
+ </div>
338
+ <div class="composer"><div class="composer-bar">Message<span class="send">↑</span></div></div>
339
+ </div></div>
340
+ </div>
341
+ <div class="step-arrow">→</div>
342
+
343
+ <!-- Step 5: OFF-APP checkout -->
344
+ <div class="phone-step">
345
+ <div class="step-label">5 · Pay (OFF-APP)<small>pay.acme.example · Acme PCI checkout</small></div>
346
+ <div class="phone offapp"><div class="phone-notch"></div><div class="phone-screen">
347
+ <div class="browser-header"><span class="lock">🔒</span><span class="url">pay.acme.example/checkout?cart=…&amp;total=40&amp;src=chatgpt</span></div>
348
+ <div class="checkout-body">
349
+ <div><div class="co-brand">Acme Bistro</div><div class="co-sub">Secure checkout · order from ChatGPT</div></div>
350
+ <div class="co-field"><div class="lbl">Order</div><div class="val" style="font-family:'Inter'">2 Margherita · 1 Lemon Tart · 1 Sparkling</div></div>
351
+ <div class="co-field card"><div class="lbl">Card number</div><div class="val">•••• •••• •••• ____</div></div>
352
+ <div class="co-field"><div class="lbl">Contact (optional)</div><div class="val" style="font-family:'Inter'">name@example.com</div></div>
353
+ <div style="padding:2px 2px 0">
354
+ <div class="co-line"><span>Subtotal</span><span>$40.00</span></div>
355
+ <div class="co-line"><span>Tax (recomputed by Acme)</span><span>$3.30</span></div>
356
+ <div class="co-line total"><span>Total</span><span>$43.30</span></div>
357
+ </div>
358
+ <button class="co-pay">Pay $43.30</button>
359
+ <div class="co-secure">🔒 PCI-scoped · card stays on acme.example · the ChatGPT App never sees it</div>
360
+ </div>
361
+ </div></div>
362
+ </div>
363
+
364
+ </div>
365
+ </div>
366
+
367
+ <hr class="page-divider">
368
+
369
+ <!-- ═══ SECTION 2: BUILD & TOTAL (deep dive) ═══ -->
370
+ <div class="section" id="build">
371
+ <span class="section-label">Capability · Order building</span>
372
+ <div class="section-title">Build the order in language, confirm it in pixels</div>
373
+ <div class="section-subtitle">The whole menu, the cart, the running total, and the pay button live in one inline widget. The diner drives it two ways — by talking to the model or by tapping the steppers — and both land in the same place.</div>
374
+
375
+ <div class="rationale">
376
+ <h4>Why this approach</h4>
377
+ <p><span class="r-tag acme">ACME</span> <strong>One kitchen, one widget.</strong> A single restaurant with five items doesn't need discovery, carousels, or a fullscreen menu — it needs the fastest path from craving to a confirmed cart. <code>MenuCart</code> collapses menu, cart, and checkout into one card the diner never scrolls out of.</p>
378
+ <p><span class="r-tag ux">UX</span> <strong>Language is the input; the widget is the receipt.</strong> "Two margheritas and a lemon tart" parses into two <code>add_to_cart</code> calls — no tapping required — and the widget instantly shows the result so the diner can trust what the model heard. Editing works the same in both directions.</p>
379
+ <p><span class="r-tag ui">UI</span> <strong>Inline Card, brand accent on the CTA only.</strong> Acme red (<code>#B91C1C</code>) appears only on the header mark and the <strong>Check out &amp; pay</strong> button; everything else uses host theme tokens via cascade layers, so the widget is native in ChatGPT light or dark. No nested scroll — five rows fit.</p>
380
+ <p><span class="r-tag trust">TRUST</span> <strong>The total is honest and display-only.</strong> The widget sums line items live, but the amount that charges is recomputed by Acme at checkout. The reassurance line ("your card is never entered in chat") is present in every frame, not just the last one.</p>
381
+ </div>
382
+ </div>
383
+
384
+ <hr class="page-divider">
385
+
386
+ <!-- ═══ SECTION 3: PAYMENT HANDOFF ═══ -->
387
+ <div class="section" id="handoff">
388
+ <span class="section-label">Capability · The one handoff</span>
389
+ <div class="section-title">Payment is the only step that leaves ChatGPT</div>
390
+ <div class="section-subtitle">When the order is right, <code>create_checkout</code> mints a signed, expiring link carrying the cart token, the total, and an attribution tag. ChatGPT opens Acme's own PCI checkout. The MCP server is never in the payment path.</div>
391
+
392
+ <div class="rationale">
393
+ <h4>Why this approach</h4>
394
+ <p><span class="r-tag trust">TRUST</span> <strong>The card never touches the app.</strong> No in-chat card field, no wallet, no stored payment method. Keeping capture on <code>pay.acme.example</code> means the ChatGPT surface adds zero PCI scope — the single most important safety property of the design.</p>
395
+ <p><span class="r-tag acme">ACME</span> <strong>The link is signed, expiring, and attributable.</strong> Acme signs the URL server-side, sets an <code>expires_at</code> (proposed 15 min), and carries <code>src=chatgpt</code> so ChatGPT-sourced revenue is measurable. <code>handoff.allowedDomains</code> lists <code>pay.acme.example</code> and <code>acme.example</code> so the compiler derives the redirect domain and the link opens without a safe-link warning.</p>
396
+ <p><span class="r-tag ux">UX</span> <strong>Context survives the jump.</strong> The cart token (<code>stone_pizzax2-lemon_tartx1-sparklingx1</code>) rehydrates the exact order on Acme's checkout — the diner never re-enters what they already told the model. State is re-validated past the boundary: Acme recomputes pricing and tax and enforces its own total.</p>
397
+ </div>
398
+
399
+ <div class="phones-row">
400
+ <div class="phone-step">
401
+ <div class="step-label">In-chat: the hand-off card<small>CheckoutHandoff · create_checkout</small></div>
402
+ <div class="phone"><div class="phone-notch"></div><div class="phone-screen">
403
+ <div class="chatgpt-header"><span class="model-name">ChatGPT</span><span class="dots">···</span></div>
404
+ <div class="msg assistant">Your $40 order is staged. Tap to pay on Acme's checkout:</div>
405
+ <div class="handoff-card">
406
+ <div class="glyph"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/></svg></div>
407
+ <h4>Pay on Acme Bistro checkout</h4>
408
+ <p>Sign in (if you like) and pay with your card on <strong>acme.example</strong>.</p>
409
+ <div class="mini-sum">
410
+ <div class="row"><span>4 items</span><span>$40</span></div>
411
+ <div class="row total"><span>Pay on acme.example</span><span>$40+tax</span></div>
412
+ </div>
413
+ <button class="cta-primary">Pay $40 on acme.example ↗</button>
414
+ <div class="pay-link">Signed · <b>expires 15 min</b> · <code>src=chatgpt</code></div>
415
+ </div>
416
+ <div class="composer"><div class="composer-bar">Message<span class="send">↑</span></div></div>
417
+ </div></div>
418
+ </div>
419
+ <div class="step-arrow">→</div>
420
+ <div class="phone-step">
421
+ <div class="step-label">Off-app: Acme checkout<small>dashed = not our app</small></div>
422
+ <div class="phone offapp"><div class="phone-notch"></div><div class="phone-screen">
423
+ <div class="browser-header"><span class="lock">🔒</span><span class="url">pay.acme.example/checkout?cart=stone_pizzax2-lemon_tartx1-sparklingx1&amp;total=40&amp;src=chatgpt</span></div>
424
+ <div class="checkout-body">
425
+ <div><div class="co-brand">Acme Bistro</div><div class="co-sub">Secure checkout</div></div>
426
+ <div class="co-field"><div class="lbl">Order (rehydrated from token)</div><div class="val" style="font-family:'Inter'">2 Margherita · 1 Lemon Tart · 1 Sparkling</div></div>
427
+ <div class="co-field card"><div class="lbl">Card number · PCI-scoped</div><div class="val">•••• •••• •••• ____</div></div>
428
+ <div style="padding:2px 2px 0">
429
+ <div class="co-line"><span>Subtotal (re-validated)</span><span>$40.00</span></div>
430
+ <div class="co-line"><span>Tax</span><span>$3.30</span></div>
431
+ <div class="co-line total"><span>Total</span><span>$43.30</span></div>
432
+ </div>
433
+ <button class="co-pay">Pay $43.30</button>
434
+ <div class="co-secure">🔒 card never leaves acme.example · app has no post-handoff visibility in v1</div>
435
+ </div>
436
+ </div></div>
437
+ </div>
438
+ </div>
439
+ </div>
440
+
441
+ <hr class="page-divider">
442
+
443
+ <!-- ═══ WIDGET GALLERY ═══ -->
444
+ <div class="section" id="gallery">
445
+ <span class="section-label">Specimen grid</span>
446
+ <div class="section-title">Widget Gallery</div>
447
+ <div class="section-subtitle">Every widget state rendered once at rest. One widget ships: <code>MenuCart</code>. This is what engineers screenshot against the build.</div>
448
+
449
+ <div class="gallery">
450
+ <div class="sf">
451
+ <div class="sf-name">MenuCart <span>· empty (CTA disabled)</span></div>
452
+ <div class="wcard">
453
+ <div class="wcard-head"><span class="logo"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="4"/></svg></span><div><div class="wc-title">Acme Bistro</div><div class="wc-status">Build your order, then check out to pay.</div></div><span class="wc-chip">0 in cart</span></div>
454
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Stone-baked Margherita</span> <span class="mr-kind">Mains</span></span><span class="mr-price">$14</span><span class="mr-qty"><span class="step-btn dis">−</span><span class="mr-count">0</span><span class="step-btn">+</span></span></div>
455
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">House Garden Salad</span> <span class="mr-kind">Starters</span></span><span class="mr-price">$11</span><span class="mr-qty"><span class="step-btn dis">−</span><span class="mr-count">0</span><span class="step-btn">+</span></span></div>
456
+ <div class="wc-foot"><span class="wc-total">Total <strong>$0</strong></span><button class="wc-cta dis"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/></svg>Check out &amp; pay</button></div>
457
+ <div class="wc-note">Payment happens on acme.example — <b>your card is never entered in chat.</b></div>
458
+ </div>
459
+ </div>
460
+
461
+ <div class="sf">
462
+ <div class="sf-name">MenuCart <span>· filled ($40, 4 items)</span></div>
463
+ <div class="wcard">
464
+ <div class="wcard-head"><span class="logo"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="12" r="4"/></svg></span><div><div class="wc-title">Acme Bistro</div><div class="wc-status">Added Sparkling Water.</div></div><span class="wc-chip">4 in cart</span></div>
465
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Stone-baked Margherita</span> <span class="mr-kind">Mains</span></span><span class="mr-price">$14</span><span class="mr-qty"><span class="step-btn on">−</span><span class="mr-count">2</span><span class="step-btn">+</span></span></div>
466
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Lemon Tart</span> <span class="mr-kind">Desserts</span></span><span class="mr-price">$8</span><span class="mr-qty"><span class="step-btn on">−</span><span class="mr-count">1</span><span class="step-btn">+</span></span></div>
467
+ <div class="menu-row"><span class="mr-main"><span class="mr-name">Sparkling Water</span> <span class="mr-kind">Drinks</span></span><span class="mr-price">$4</span><span class="mr-qty"><span class="step-btn on">−</span><span class="mr-count">1</span><span class="step-btn">+</span></span></div>
468
+ <div class="wc-foot"><span class="wc-total">Total <strong>$40</strong></span><button class="wc-cta"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/></svg>Check out &amp; pay</button></div>
469
+ <div class="wc-note">Payment happens on acme.example — <b>your card is never entered in chat.</b></div>
470
+ </div>
471
+ </div>
472
+
473
+ <div class="sf">
474
+ <div class="sf-name">CheckoutHandoff <span>· signed link (create_checkout)</span></div>
475
+ <div class="handoff-card">
476
+ <div class="glyph"><svg viewBox="0 0 24 24"><rect x="3" y="5" width="18" height="14" rx="2"/><path d="M3 10h18"/></svg></div>
477
+ <h4>Pay on Acme Bistro checkout</h4>
478
+ <p>Your order is staged and ready. Card entered on <strong>acme.example</strong>, never in chat.</p>
479
+ <div class="mini-sum"><div class="row"><span>4 items</span><span>$40</span></div><div class="row total"><span>Total</span><span>$40+tax</span></div></div>
480
+ <button class="cta-primary">Pay $40 on acme.example ↗</button>
481
+ <div class="pay-link">Signed · expires 15 min · <code>src=chatgpt</code></div>
482
+ </div>
483
+ </div>
484
+ </div>
485
+ </div>
486
+
487
+ <hr class="page-divider">
488
+
489
+ <!-- ═══ MCP TOOLS APPENDIX ═══ -->
490
+ <div class="section" id="api">
491
+ <span class="section-label">Technical appendix</span>
492
+ <div class="section-title">MCP Tools &amp; Call Sequence</div>
493
+ <div class="section-subtitle">Tool mapping for each wireframe step. Four tools, served by the Noodle Seed–authored <code>acme_bistro</code> server. Concrete request/response JSON lives in <code>api-contract.md</code>.</div>
494
+
495
+ <div class="api-panel">
496
+ <div class="api-panel-header">Browse &amp; Build (Steps 1–3)</div>
497
+ <div class="api-step">
498
+ <div class="api-step-label">Step 1 — Show the menu</div>
499
+ <div class="api-endpoint"><span class="kind read">READ</span><span class="path">show_menu</span><span class="desc">— toolWithWidget. Returns the 5-item menu and renders MenuCart.</span></div>
500
+ <div class="api-note"><strong>Design intent:</strong> the menu is small and static, so it ships in one read — no pagination, no follow-up call. The <code>items[]</code> array is the model's only source of dish names and prices.</div>
501
+ </div>
502
+ <div class="api-step">
503
+ <div class="api-step-label">Steps 2–3 — Build &amp; edit the cart</div>
504
+ <div class="api-endpoint"><span class="kind write">WRITE</span><span class="path">add_to_cart</span><span class="desc">— toolForWidget. Reflects a natural-language addition (item + quantity) into the visible cart.</span></div>
505
+ <div class="api-endpoint"><span class="kind write">WRITE</span><span class="path">remove_from_cart</span><span class="desc">— toolForWidget. Removes one unit; the widget's − button calls the same tool.</span></div>
506
+ <div class="api-note"><strong>Natural-language parsing:</strong> "two margheritas and a lemon tart" becomes <code>add_to_cart{item:"stone_pizza",quantity:2}</code> + <code>add_to_cart{item:"lemon_tart",quantity:1}</code> — the model fills the fields; no UI round-trip. The running total is summed live in the widget (React), not in a tool.</div>
507
+ </div>
508
+ </div>
509
+
510
+ <div class="api-panel">
511
+ <div class="api-panel-header">Confirm &amp; Hand off (Step 4 → off-app)</div>
512
+ <div class="api-step">
513
+ <div class="api-step-label">Step 4 — Mint the payment link</div>
514
+ <div class="api-endpoint"><span class="kind link">OPEN-LINK</span><span class="path">create_checkout</span><span class="desc">— model-visible tool. Returns a signed deep link + summary; ChatGPT opens it.</span></div>
515
+ <div class="api-note"><strong>No payment in-chat.</strong> The widget passes a url-safe cart token and the numeric total; <code>create_checkout</code> returns <code>checkoutUrl = https://pay.acme.example/checkout?cart=…&amp;total=…&amp;src=chatgpt</code> (production adds a signed <code>expires_at</code>). The app never sees card data. Acme recomputes pricing/tax and enforces the total past the boundary. No <code>submit_order</code> tool exists by design — fulfilment is Acme's.</div>
516
+ </div>
517
+ </div>
518
+ </div>
519
+
520
+ <hr class="page-divider">
521
+
522
+ <!-- ═══ COMPLIANCE AUDIT ═══ -->
523
+ <div class="section" id="compliance">
524
+ <span class="section-label">Compliance</span>
525
+ <div class="section-title">OpenAI Apps SDK Compliance Audit</div>
526
+ <div class="section-subtitle">How Acme Bistro maps to OpenAI's published ChatGPT Apps UX Principles and UI Guidelines. Verified in the build with <code>noodle check --target chatgpt</code>.</div>
527
+
528
+ <div class="rationale" style="max-width:100%">
529
+ <h4>Pre-publishing checklist</h4>
530
+ <table class="audit-table">
531
+ <tr><th style="width:32%">Requirement</th><th>How Acme Bistro addresses it</th><th style="width:70px">Status</th></tr>
532
+ <tr><td>Conversational value — relies on ChatGPT's strengths</td><td>Natural-language ordering ("two margheritas and a lemon tart") parses into <code>add_to_cart</code> calls with item + quantity — no tap-driven menu can do this. Editing by sentence ("drop a margherita") works the same way.</td><td class="audit-pass">✓ Pass</td></tr>
533
+ <tr><td>Beyond base ChatGPT — new knowledge/actions</td><td>Live single-restaurant menu, a running cart, and a signed checkout hand-off to Acme's real payment page. None available in base ChatGPT.</td><td class="audit-pass">✓ Pass</td></tr>
534
+ <tr><td>Atomic, model-friendly actions</td><td>Four tools with explicit Zod-typed input/output: <code>show_menu</code> (read), <code>add_to_cart</code>/<code>remove_from_cart</code> (local write), <code>create_checkout</code> (open-link). No ambiguity.</td><td class="audit-pass">✓ Pass</td></tr>
535
+ <tr><td>Helpful UI only — would plain text degrade UX?</td><td>Yes for the menu/cart — price rows and steppers are faster to scan than prose, and the running total needs a layout. <strong>No payment widget is built</strong> — card capture is off-platform, so a widget there would be wrong.</td><td class="audit-pass">✓ Pass</td></tr>
536
+ <tr><td>Meaningful task completion in-chat</td><td>The full order — browse, build, edit, confirm total — completes in ChatGPT. The one intentional hand-off is payment, on Acme's checkout.</td><td class="audit-pass">✓ Pass</td></tr>
537
+ <tr><td>Performance &amp; responsiveness</td><td>One read on entry; cart edits are local to the widget; one link mint at checkout. Static menu keeps <code>show_menu</code> well under target latency.</td><td class="audit-pass">✓ Pass</td></tr>
538
+ <tr><td>Discoverability</td><td>Broad natural triggers: "show me the Acme Bistro menu", "order two margheritas from Acme", "what's my Acme total?", "check out and pay".</td><td class="audit-pass">✓ Pass</td></tr>
539
+ <tr><td>Platform fit</td><td>Rich prompts (order + quantity in one sentence), multi-turn cart building, in-session memory of the cart. No per-user auth needed for the pre-payment surface.</td><td class="audit-pass">✓ Pass</td></tr>
540
+ </table>
541
+ </div>
542
+
543
+ <div class="rationale" style="max-width:100%;margin-top:18px">
544
+ <h4>UI guidelines compliance</h4>
545
+ <table class="audit-table">
546
+ <tr><th style="width:32%">Guideline</th><th>Implementation</th><th style="width:70px">Status</th></tr>
547
+ <tr><td>Colour — system tokens; brand only on accents/CTA</td><td>Text, borders, and surfaces use host semantic tokens via cascade layers. Acme red <code>#B91C1C</code> appears only on the header mark and the primary <strong>Check out &amp; pay</strong> button.</td><td class="audit-pass">✓ Pass</td></tr>
548
+ <tr><td>Typography — inherit system fonts</td><td>System font stack; no custom Acme typeface inside the widget.</td><td class="audit-pass">✓ Pass</td></tr>
549
+ <tr><td>Inline Card — ≤2 actions, no nested scroll, no deep nav</td><td>MenuCart has one primary action (Check out &amp; pay) plus in-card steppers; five rows fit with no inner scroller and no drill-in.</td><td class="audit-pass">✓ Pass</td></tr>
550
+ <tr><td>Icons — monochromatic, outlined</td><td>Outlined plate mark and card glyph; no filled brand logo rendered in the response body.</td><td class="audit-pass">✓ Pass</td></tr>
551
+ <tr><td>Accessibility — WCAG AA, theme-aware</td><td>Acme red used only as a fill behind light text or as a 1px mark, never as body text on white. Widget adapts to host light/dark via <code>branding.surface</code> / <code>surfaceDark</code>.</td><td class="audit-pass">✓ Pass</td></tr>
552
+ <tr><td>Display mode — correct per intent</td><td>Inline Card only. No Carousel/Fullscreen/PiP — a flat 5-item menu doesn't warrant them.</td><td class="audit-pass">✓ Pass</td></tr>
553
+ </table>
554
+ </div>
555
+
556
+ <div class="rationale" style="max-width:100%;margin-top:18px">
557
+ <h4>Domain guardrails (Acme-specific trust rows)</h4>
558
+ <table class="audit-table">
559
+ <tr><th style="width:32%">Guardrail</th><th>How Acme Bistro enforces it</th><th style="width:70px">Status</th></tr>
560
+ <tr class="audit-guard"><td>No payment in chat</td><td>No card field, wallet, or stored method anywhere in the app. Card capture happens only on <code>pay.acme.example</code> after the hand-off. The MCP server never enters PCI scope. The "your card is never entered in chat" note is in every widget frame.</td><td class="audit-pass">✓ Pass</td></tr>
561
+ <tr class="audit-guard"><td>Allergen / dietary honesty</td><td>The model states only what the menu data holds (name, course, price). Ingredient-level or cross-contact questions are deferred to Acme directly — never "this is vegetarian/gluten-free" without a menu flag.</td><td class="audit-pass">✓ Pass</td></tr>
562
+ <tr class="audit-guard"><td>No invented items or prices</td><td>Grounded strictly in the <code>show_menu</code> <code>items[]</code> — only the five dishes, only their listed prices. The total is display-only; Acme recomputes the charge.</td><td class="audit-pass">✓ Pass</td></tr>
563
+ <tr class="audit-guard"><td>Signed, expiring, attributable hand-off</td><td>Checkout link is signed server-side, carries <code>src=chatgpt</code>, and expires (proposed 15 min). <code>handoff.allowedDomains</code> whitelists the redirect domains so the link opens without a safe-link warning.</td><td class="audit-pass">✓ Pass</td></tr>
564
+ <tr class="audit-guard"><td>No unseen fulfilment claims</td><td>The app builds and hands off the order; it makes no pickup-time or order-status promise it can't verify (no post-handoff visibility in v1).</td><td class="audit-pass">✓ Pass</td></tr>
565
+ </table>
566
+ </div>
567
+ </div>
568
+
569
+ <div class="footer">Acme Bistro (illustrative) · Prepared by Noodle Seed · End-to-end wireframes · matches the runnable <code>acme_bistro</code> server</div>
570
+
571
+ </div>
572
+ </body>
573
+ </html>