agentbox-app 0.1.7 → 0.1.12

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 (255) hide show
  1. package/README.md +220 -58
  2. package/bin/agentbox.mjs +18 -3
  3. package/briefs/message-rules.md +24 -3
  4. package/briefs/worker.md +63 -49
  5. package/briefs/writing-rules.md +90 -131
  6. package/main/account-discovery.mjs +21 -20
  7. package/main/account-tooling.mjs +11 -11
  8. package/main/agent-activity.mjs +45 -5
  9. package/main/agent-schedule.mjs +14 -14
  10. package/main/agent-sessions.mjs +94 -10
  11. package/main/agent-updates.mjs +116 -0
  12. package/main/agents.mjs +52 -46
  13. package/main/analytics.mjs +27 -0
  14. package/main/approval-prompt-server.mjs +2 -2
  15. package/main/approvals.mjs +14 -5
  16. package/main/artifact-path.mjs +11 -0
  17. package/main/claude-bin.mjs +32 -5
  18. package/main/claude-input.mjs +45 -3
  19. package/main/claude-plan.mjs +25 -13
  20. package/main/code-change.mjs +3 -3
  21. package/main/codex-account.mjs +1 -1
  22. package/main/codex-bin.mjs +18 -0
  23. package/main/codex-launch-env.mjs +31 -0
  24. package/main/codex-memory-gate.mjs +260 -0
  25. package/main/codex-models.mjs +12 -7
  26. package/main/codex-threads.mjs +46 -23
  27. package/main/codex-usage-file.mjs +7 -7
  28. package/main/codex-usage.mjs +4 -4
  29. package/main/codex-watch.mjs +12 -12
  30. package/main/config.mjs +82 -17
  31. package/main/demo.mjs +17 -14
  32. package/main/dev-window.mjs +9 -9
  33. package/main/doc-scheme.mjs +2 -0
  34. package/main/engine-setup.mjs +204 -0
  35. package/main/feedback.mjs +55 -0
  36. package/main/folder-pictures.mjs +48 -0
  37. package/main/frame-scrollbars.mjs +90 -0
  38. package/main/fresh-user.mjs +7 -4
  39. package/main/git-change-offthread.mjs +70 -0
  40. package/main/git-change-thread.mjs +11 -0
  41. package/main/git-change.mjs +9 -3
  42. package/main/img-scheme.mjs +70 -1
  43. package/main/instruction-settings.mjs +134 -60
  44. package/main/ipc.mjs +335 -42
  45. package/main/leftovers.mjs +518 -0
  46. package/main/live-replies.mjs +43 -5
  47. package/main/machine.mjs +48 -1
  48. package/main/main.mjs +138 -15
  49. package/main/memory-gate-history.mjs +254 -0
  50. package/main/memory-gate-server.mjs +461 -0
  51. package/main/memory-gate.mjs +206 -0
  52. package/main/message-priority.mjs +87 -0
  53. package/main/notify.mjs +1 -1
  54. package/main/rail-note.mjs +2 -2
  55. package/main/refresh-agent-models.mjs +21 -0
  56. package/main/repeats.mjs +4 -4
  57. package/main/row-label.mjs +115 -51
  58. package/main/runs-on.mjs +93 -0
  59. package/main/serve.mjs +77 -5
  60. package/main/settings.mjs +245 -26
  61. package/main/ship-queue.mjs +279 -0
  62. package/main/sign-in-files.mjs +39 -0
  63. package/main/source-updater.mjs +298 -0
  64. package/main/store/home.mjs +84 -7
  65. package/main/store/project.mjs +15 -19
  66. package/main/store/work-items.mjs +150 -6
  67. package/main/store.mjs +245 -13
  68. package/main/supervisor.mjs +1634 -417
  69. package/main/task-commands.mjs +8 -10
  70. package/main/task-folders.mjs +94 -16
  71. package/main/task-remote-control.mjs +3 -3
  72. package/main/task-terminals.mjs +14 -2
  73. package/main/team/index.mjs +440 -0
  74. package/main/team/memory-cloud.mjs +247 -0
  75. package/main/team/projects.mjs +162 -0
  76. package/main/team/session.mjs +225 -0
  77. package/main/team/sign-in.mjs +106 -0
  78. package/main/team/supabase-backend.mjs +231 -0
  79. package/main/team/sync.mjs +163 -0
  80. package/main/updater.mjs +15 -5
  81. package/main/write-before-reload.mjs +50 -0
  82. package/mcp/core/page.mjs +10 -12
  83. package/mcp/core/work.mjs +123 -26
  84. package/mcp/tools.mjs +13 -6
  85. package/package.json +21 -9
  86. package/renderer/dist/assets/agentbox-icon-F1oN9nj_.svg +15 -0
  87. package/renderer/dist/assets/index-ChKsQkRw.js +1169 -0
  88. package/renderer/dist/assets/index-ClBXnq3B.css +32 -0
  89. package/renderer/dist/index.html +2 -2
  90. package/scripts/after-install.mjs +14 -0
  91. package/scripts/approval-server.sh +7 -2
  92. package/scripts/memory-gate-hook.sh +59 -0
  93. package/shared/agent-import.mjs +39 -16
  94. package/shared/agents.d.mts +26 -8
  95. package/shared/agents.mjs +100 -108
  96. package/shared/analytics-events.mjs +19 -2
  97. package/shared/answers.mjs +12 -0
  98. package/shared/bridge-map.d.mts +12 -0
  99. package/shared/bridge-map.mjs +38 -1
  100. package/shared/claude-commands.generated.mjs +2 -2
  101. package/shared/claude-models.generated.mjs +6 -6
  102. package/shared/claude-usage.mjs +6 -6
  103. package/shared/codex-import.mjs +7 -7
  104. package/shared/codex-modes.d.mts +50 -0
  105. package/shared/codex-modes.mjs +1 -1
  106. package/shared/codex-usage.mjs +7 -8
  107. package/shared/demo-world.mjs +6 -6
  108. package/shared/engines.mjs +27 -10
  109. package/shared/feedback.d.mts +14 -0
  110. package/shared/feedback.mjs +44 -0
  111. package/shared/first-run-examples.mjs +4 -4
  112. package/shared/first-run-practice.d.mts +16 -0
  113. package/shared/first-run-practice.mjs +176 -70
  114. package/shared/fresh-user-home.mjs +34 -4
  115. package/shared/instruction-defaults.json +2 -2
  116. package/shared/product-name.mjs +4 -2
  117. package/shared/project-folder-check.mjs +9 -3
  118. package/shared/rank.d.mts +1 -0
  119. package/shared/rank.mjs +22 -0
  120. package/shared/referenced-files.mjs +1 -1
  121. package/shared/runs-on.d.mts +20 -0
  122. package/shared/runs-on.mjs +79 -0
  123. package/shared/schemes.d.mts +11 -0
  124. package/shared/schemes.mjs +1 -1
  125. package/shared/shortcuts.d.mts +41 -0
  126. package/shared/shortcuts.mjs +236 -0
  127. package/shared/spawn-trouble.d.mts +2 -0
  128. package/shared/spawn-trouble.mjs +40 -19
  129. package/shared/team-rules.d.mts +17 -0
  130. package/shared/team-rules.mjs +230 -0
  131. package/shared/team-status.d.mts +11 -0
  132. package/shared/team-status.mjs +90 -0
  133. package/shared/terminal-links.d.mts +2 -0
  134. package/shared/terminal-links.mjs +55 -0
  135. package/shared/terminal-state.d.mts +1 -0
  136. package/shared/terminal-state.mjs +16 -0
  137. package/shared/thread-cards.d.mts +19 -0
  138. package/shared/thread-cards.mjs +254 -0
  139. package/shared/usage.d.mts +1 -1
  140. package/shared/usage.mjs +6 -7
  141. package/shared/work-items.mjs +258 -28
  142. package/shared/work-lines.mjs +393 -16
  143. package/worker-permissions.json +1 -1
  144. package/renderer/dist/assets/cel-dusk-CS5I7kJS.webp +0 -0
  145. package/renderer/dist/assets/cel-dusk-DUslqS6B.webp +0 -0
  146. package/renderer/dist/assets/cel-dusk-Jt_xVGxp.webp +0 -0
  147. package/renderer/dist/assets/cel-dusk-sm-BBkV-tWT.webp +0 -0
  148. package/renderer/dist/assets/frost-haze-CxPSOBEg.webp +0 -0
  149. package/renderer/dist/assets/frost-haze-sm-C_w21qgd.webp +0 -0
  150. package/renderer/dist/assets/ice-BC8luINc.webp +0 -0
  151. package/renderer/dist/assets/ice-CP9PrKHo.webp +0 -0
  152. package/renderer/dist/assets/ice-river-D6ziOhLY.webp +0 -0
  153. package/renderer/dist/assets/ice-river-UVM2-JY_.webp +0 -0
  154. package/renderer/dist/assets/ice-river-bErJwYWW.webp +0 -0
  155. package/renderer/dist/assets/ice-river-sm-Bg1U-SIj.webp +0 -0
  156. package/renderer/dist/assets/ice-sm-CbVcg3_D.webp +0 -0
  157. package/renderer/dist/assets/index-B7hhfHrT.js +0 -684
  158. package/renderer/dist/assets/index-CwiDv5bL.css +0 -32
  159. package/renderer/dist/assets/lake-C0WaW-6E.webp +0 -0
  160. package/renderer/dist/assets/lake-CSKjLC5K.webp +0 -0
  161. package/renderer/dist/assets/lake-ETGcOb25.webp +0 -0
  162. package/renderer/dist/assets/lake-harbour-BCQRbrHb.webp +0 -0
  163. package/renderer/dist/assets/lake-harbour-B_wfXTmE.webp +0 -0
  164. package/renderer/dist/assets/lake-harbour-Te1pEvBh.webp +0 -0
  165. package/renderer/dist/assets/lake-harbour-sm-Cme_ShEg.webp +0 -0
  166. package/renderer/dist/assets/lake-sm-CbG72Hbv.webp +0 -0
  167. package/renderer/dist/assets/lino-coast-CUZHcucI.webp +0 -0
  168. package/renderer/dist/assets/lino-coast-DP4J7cgd.webp +0 -0
  169. package/renderer/dist/assets/lino-coast-kOIAffr_.webp +0 -0
  170. package/renderer/dist/assets/lino-coast-sm-C1Mdbgit.webp +0 -0
  171. package/renderer/dist/assets/moon-pines-BskgnnXR.webp +0 -0
  172. package/renderer/dist/assets/moon-pines-CFSIIwt0.webp +0 -0
  173. package/renderer/dist/assets/moon-pines-PNhdOYww.webp +0 -0
  174. package/renderer/dist/assets/moon-pines-sm-C6K1NomK.webp +0 -0
  175. package/renderer/dist/assets/orbit-rings-2XV36Ch3.webp +0 -0
  176. package/renderer/dist/assets/orbit-rings-C4NrcYGQ.webp +0 -0
  177. package/renderer/dist/assets/orbit-rings-DGLk07dT.webp +0 -0
  178. package/renderer/dist/assets/orbit-rings-sm-Dky3YdvL.webp +0 -0
  179. package/renderer/dist/assets/peach-haze-2-C6f7xnWw.webp +0 -0
  180. package/renderer/dist/assets/peach-haze-2-sm-Dj_Ez_Sb.webp +0 -0
  181. package/renderer/dist/assets/pixel-harbour-DQjqMROg.webp +0 -0
  182. package/renderer/dist/assets/pixel-harbour-Dw71H_bc.webp +0 -0
  183. package/renderer/dist/assets/pixel-harbour-kOZfm-GM.webp +0 -0
  184. package/renderer/dist/assets/pixel-harbour-sm-Dturjuky.webp +0 -0
  185. package/renderer/dist/assets/pixel-orbit-C296JVMO.webp +0 -0
  186. package/renderer/dist/assets/pixel-orbit-C4oMRDSx.webp +0 -0
  187. package/renderer/dist/assets/pixel-orbit-CqVmQ4eh.webp +0 -0
  188. package/renderer/dist/assets/pixel-orbit-sm-CHagC_nO.webp +0 -0
  189. package/renderer/dist/assets/pixel-ridge-C6LYu6uE.webp +0 -0
  190. package/renderer/dist/assets/pixel-ridge-CIUCEESs.webp +0 -0
  191. package/renderer/dist/assets/pixel-ridge-sm-BnE0F_w-.webp +0 -0
  192. package/renderer/dist/assets/riso-hills-7heKVtry.webp +0 -0
  193. package/renderer/dist/assets/riso-hills-CIjAL3J6.webp +0 -0
  194. package/renderer/dist/assets/riso-hills-sm-DHsnbCfP.webp +0 -0
  195. package/renderer/dist/assets/slate-haze-BPWdkNsw.webp +0 -0
  196. package/renderer/dist/assets/slate-haze-sm-B0Cb5a2W.webp +0 -0
  197. package/renderer/dist/assets/valley-haze-BDHPqoJy.webp +0 -0
  198. package/renderer/dist/assets/valley-haze-sm-CTyjmPAG.webp +0 -0
  199. package/renderer/dist/assets/vector-dunes-DzzWLdKo.webp +0 -0
  200. package/renderer/dist/assets/vector-dunes-Yr9NBQUy.webp +0 -0
  201. package/renderer/dist/assets/vector-dunes-sm-D8MYY6ms.webp +0 -0
  202. package/renderer/dist/assets/watercolour-mist-BCGKN4u4.webp +0 -0
  203. package/renderer/dist/assets/watercolour-mist-BF-jk5MC.webp +0 -0
  204. package/renderer/dist/assets/watercolour-mist-sm-Ds1xzTw9.webp +0 -0
  205. package/renderer/dist/assets/woodblock-sea-B1um67Z9.webp +0 -0
  206. package/renderer/dist/assets/woodblock-sea-DKQdYs32.webp +0 -0
  207. package/renderer/dist/assets/woodblock-sea-sm-BJzNq8xh.webp +0 -0
  208. package/renderer/dist/emulator/audio-rules.mjs +0 -74
  209. package/renderer/dist/emulator/data/compression/README.md +0 -11
  210. package/renderer/dist/emulator/data/compression/extract7z.js +0 -1
  211. package/renderer/dist/emulator/data/compression/extractzip.js +0 -1
  212. package/renderer/dist/emulator/data/compression/libunrar.js +0 -519
  213. package/renderer/dist/emulator/data/compression/libunrar.wasm +0 -0
  214. package/renderer/dist/emulator/data/cores/README.md +0 -22
  215. package/renderer/dist/emulator/data/cores/mgba-legacy-wasm.data +0 -0
  216. package/renderer/dist/emulator/data/cores/mgba-thread-legacy-wasm.data +0 -0
  217. package/renderer/dist/emulator/data/cores/mgba-thread-wasm.data +0 -0
  218. package/renderer/dist/emulator/data/cores/mgba-wasm.data +0 -0
  219. package/renderer/dist/emulator/data/cores/package.json +0 -65
  220. package/renderer/dist/emulator/data/cores/reports/mgba.json +0 -1
  221. package/renderer/dist/emulator/data/emulator.css +0 -1614
  222. package/renderer/dist/emulator/data/loader.js +0 -170
  223. package/renderer/dist/emulator/data/localization/README.md +0 -63
  224. package/renderer/dist/emulator/data/localization/af-FR.json +0 -339
  225. package/renderer/dist/emulator/data/localization/ar-AR.json +0 -301
  226. package/renderer/dist/emulator/data/localization/ben-BEN.json +0 -301
  227. package/renderer/dist/emulator/data/localization/de-GER.json +0 -301
  228. package/renderer/dist/emulator/data/localization/el-GR.json +0 -301
  229. package/renderer/dist/emulator/data/localization/en-US.json +0 -339
  230. package/renderer/dist/emulator/data/localization/es-ES.json +0 -310
  231. package/renderer/dist/emulator/data/localization/fa-AF.json +0 -310
  232. package/renderer/dist/emulator/data/localization/hi-HI.json +0 -301
  233. package/renderer/dist/emulator/data/localization/it-IT.json +0 -302
  234. package/renderer/dist/emulator/data/localization/ja-JA.json +0 -301
  235. package/renderer/dist/emulator/data/localization/jv-JV.json +0 -301
  236. package/renderer/dist/emulator/data/localization/ko-KO.json +0 -336
  237. package/renderer/dist/emulator/data/localization/pt-BR.json +0 -361
  238. package/renderer/dist/emulator/data/localization/retroarch.json +0 -617
  239. package/renderer/dist/emulator/data/localization/ro-RO.json +0 -310
  240. package/renderer/dist/emulator/data/localization/ru-RU.json +0 -301
  241. package/renderer/dist/emulator/data/localization/tr-TR.json +0 -310
  242. package/renderer/dist/emulator/data/localization/vi-VN.json +0 -302
  243. package/renderer/dist/emulator/data/localization/zh-CN.json +0 -351
  244. package/renderer/dist/emulator/data/src/GameManager.js +0 -464
  245. package/renderer/dist/emulator/data/src/compression.js +0 -142
  246. package/renderer/dist/emulator/data/src/emulator.js +0 -6158
  247. package/renderer/dist/emulator/data/src/gamepad.js +0 -167
  248. package/renderer/dist/emulator/data/src/nipplejs.js +0 -1
  249. package/renderer/dist/emulator/data/src/shaders.js +0 -236
  250. package/renderer/dist/emulator/data/src/socket.io.min.js +0 -7
  251. package/renderer/dist/emulator/data/src/storage.js +0 -125
  252. package/renderer/dist/emulator/data/version.json +0 -5
  253. package/renderer/dist/emulator/host.js +0 -299
  254. package/renderer/dist/emulator/index.html +0 -28
  255. package/renderer/dist/emulator/provenance.json +0 -6
package/mcp/core/work.mjs CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  } from '../../main/store/work-items.mjs';
26
26
  import { matchesFilter } from '../../shared/work-items.mjs';
27
27
  import { unleaked } from '../../shared/agents.mjs';
28
+ import { CONTEXT_WORDS, DONE_STEPS, DONE_STEP_WORDS, SUMMARY_WORDS, doneSteps, wordsIn } from '../../shared/thread-cards.mjs';
28
29
  import {
29
30
  parkPendingWrite, readPendingWrites, collectPendingWrites,
30
31
  } from '../../main/store/pending-writes.mjs';
@@ -77,9 +78,9 @@ function locate(id, { product = null } = {}) {
77
78
  //
78
79
  // `unleaked` holds what leaks and the row it cost. It is applied here, at the
79
80
  // boundary where an agent's text arrives, and NOT in the store: the store also
80
- // holds what she typed, and her words are hers whatever they contain. The pane
81
- // cuts it again on the way out, because the rows that already carry it are
82
- // still on her screen.
81
+ // holds what the user typed, and the user's words are theirs whatever they
82
+ // contain. The pane cuts it again on the way out, because the rows that
83
+ // already carry it are still on screen.
83
84
  const WORDS = ['result', 'note', 'body', 'title', 'label'];
84
85
 
85
86
  function saidPlainly(fields, source) {
@@ -91,12 +92,35 @@ function saidPlainly(fields, source) {
91
92
  return out;
92
93
  }
93
94
 
94
- export function createItem(product, fields = {}, { source = 'agent' } = {}) {
95
+ export function createItem(product, fields = {}, { source = 'agent', from = [] } = {}) {
95
96
  const p = resolveProduct(product);
96
- const item = createWorkItem(p.dir, saidPlainly(fields, source), { source });
97
+ const sources = [...from, fields.parent].filter(Boolean).map((id) => { try { return locate(id).item; } catch { return null; } });
98
+ const kept = fields.visibility ? {} : privacyFrom(sources);
99
+ const item = createWorkItem(p.dir, saidPlainly({ ...fields, ...kept }, source), { source });
97
100
  return { ...item, product: p.id, productName: p.name };
98
101
  }
99
102
 
103
+ /*
104
+ * A TASK AN AGENT FILES IS SEEN BY NO MORE PEOPLE THAN THE TASKS IT CAME FROM
105
+ * (w-e053ed3581). The agent asked into a private chat holds a task seen only
106
+ * by the chat, and what it files from there is written out of that chat; with
107
+ * no word of its own, a filed task in a project that reads as the whole team
108
+ * went on every teammate's board. So it takes the narrowest of its sources:
109
+ * Private if any is, else only the people every one of them names. A source
110
+ * with no word of its own leaves the project to decide, as before.
111
+ */
112
+ export function privacyFrom(items) {
113
+ let people = null;
114
+ for (const item of items) {
115
+ if (item?.visibility === 'private') return { visibility: 'private' };
116
+ if (item?.visibility !== 'people') continue;
117
+ const named = Array.isArray(item.visibleTo) ? item.visibleTo.filter(Boolean) : [];
118
+ people = people ? people.filter((id) => named.includes(id)) : [...new Set(named)];
119
+ }
120
+ if (!people) return {};
121
+ return people.length ? { visibility: 'people', visibleTo: people } : { visibility: 'private' };
122
+ }
123
+
100
124
  export function updateItem(id, patch, { product = null, epoch = null, source = 'agent' } = {}) {
101
125
  const { project } = locate(id, { product });
102
126
  const item = updateWorkItem(project.dir, id, saidPlainly(patch, source), { epoch, source });
@@ -104,28 +128,26 @@ export function updateItem(id, patch, { product = null, epoch = null, source = '
104
128
  }
105
129
 
106
130
  /*
107
- * ONLY SHE CLOSES A ROW SHE WROTE, UNLESS SHE SAID TO (w-e372d22a99).
131
+ * ONLY THE USER CLOSES A ROW THEY WROTE, UNLESS THEY SAID TO (w-e372d22a99).
108
132
  *
109
- * Her words, 2026-09-27: "If I ask for something, its job is to return it back.
110
- * Only when I request it, 'Close it,' or say, 'All right, I'm done with this,'
111
- * or something like that, should it close it."
133
+ * A worker's job on a row the user wrote is to return what was asked for. The
134
+ * row closes only when the user asks for it to be closed.
112
135
  *
113
- * Until then a worker answered her ask and set it done in the same call, and
114
- * the row wore "Closed" from then on. On the row she reported, w-3384aa9e5c, a
115
- * worker claimed at 19:45:20 and closed at 19:46:09. She could not find it, and
116
- * found it in Closed. Measured across her store that night: 43 of her rows had
117
- * been closed by an agent against 361 closed by her.
136
+ * Until then a worker answered the ask and set it done in the same call, and
137
+ * the row wore "Closed" from then on: on w-3384aa9e5c a worker claimed and
138
+ * closed the row inside a minute, and the answer could only be found by
139
+ * looking in Closed.
118
140
  *
119
- * So a `done` on a row labelled `founder` needs HER WORDS asking for it, quoted
120
- * in `closeBecause` and found in what she wrote on the row. Without them the
121
- * rest of the write lands and the row stays open: the answer reaches her inbox
122
- * as an answer (`answeredHerAsk`, list-rules.ts), and `awaitingHer`
123
- * (supervisor.mjs) keeps a second worker off it until she speaks. The quote is
124
- * checked for being hers, not for meaning close; that judgement is the
125
- * worker's, and the quote is what makes it one it has to make on purpose.
141
+ * So a `done` on a row labelled `founder` needs THE USER'S WORDS asking for it,
142
+ * quoted in `closeBecause` and found in what they wrote on the row. Without
143
+ * them the rest of the write lands and the row stays open: the answer reaches
144
+ * the inbox as an answer (`answeredHerAsk`, list-rules.ts), and `awaitingHer`
145
+ * (supervisor.mjs) keeps a second worker off it until the user speaks. The
146
+ * quote is checked for being the user's, not for meaning close; that judgement
147
+ * is the worker's, and the quote is what makes it one it has to make on purpose.
126
148
  *
127
- * A run of a repeating task is not her ask. She set the task up to run daily
128
- * and close quietly when there is nothing to say, so `repeat:` rows keep that.
149
+ * A run of a repeating task is not a user's ask. The task was set up to run
150
+ * daily and close quietly when there is nothing to say, so `repeat:` rows keep that.
129
151
  */
130
152
  const plainly = (s) => String(s ?? '')
131
153
  .toLowerCase()
@@ -145,6 +167,53 @@ export function saidToClose(item, words) {
145
167
  return [item?.answer, item?.body, item?.title].some((t) => plainly(t).includes(quote));
146
168
  }
147
169
 
170
+ /*
171
+ * A PUT-OFF THE USER ASKED FOR IS THEIRS (w-d6ea290028).
172
+ *
173
+ * A runAt an agent writes brakes workers and never hides the row
174
+ * (`parkedByAgent`, list-rules.ts), so an agent cannot take its own question
175
+ * out of the inbox. But "remind me in 4 days" asks for exactly that, and the
176
+ * row sat in Needs you wearing Scheduled until Sunday, with the user unsure
177
+ * whether closing it would lose the reminder.
178
+ *
179
+ * So a worker that quotes the user's own words asking for the put-off, in
180
+ * `deferBecause`, checked exactly as `closeBecause` is, has the moment written
181
+ * as the user's. That is what hides a row until it comes due, puts it in
182
+ * Scheduled, and lets the user's L move it again.
183
+ */
184
+ const DEFERRED_AS_AGENT = 'The put-off was saved as YOURS, not theirs, so the row stays in their inbox until then: the words in deferBecause are not ones they wrote on this row. If they did ask for it to be put off, send runAt again with deferBecause set to their exact words.';
185
+
186
+ /*
187
+ * A SUMMARY LINE IS SHORT ENOUGH TO READ (w-b51b2e1c86). An agent's problem,
188
+ * progress or solution over SUMMARY_WORDS words is taken out of the write and
189
+ * the rest lands; the agent is told which line, how long, and to send it again.
190
+ * Refused rather than cut, because a cut sentence says less than a short one.
191
+ */
192
+ //
193
+ // Since w-54e9c7243f the summary is Context (`problem`, CONTEXT_WORDS) and Done
194
+ // (`progress`, at most DONE_STEPS lines of DONE_STEP_WORDS each); `solution`
195
+ // keeps the old one-sentence limit for any writer still sending it.
196
+ function takeOverLong(patch) {
197
+ const said = [];
198
+ if (typeof patch.problem === 'string' && wordsIn(patch.problem) > CONTEXT_WORDS) {
199
+ said.push(`context, the problem field (${wordsIn(patch.problem)} words; ${CONTEXT_WORDS} at most)`);
200
+ delete patch.problem;
201
+ }
202
+ if (typeof patch.progress === 'string') {
203
+ const steps = doneSteps(patch.progress);
204
+ const longest = Math.max(0, ...steps.map(wordsIn));
205
+ if (steps.length > DONE_STEPS) said.push(`done, the progress field (${steps.length} steps; ${DONE_STEPS} at most, so keep the ones that matter)`);
206
+ else if (longest > DONE_STEP_WORDS) said.push(`done, the progress field (a step of ${longest} words; ${DONE_STEP_WORDS} at most each)`);
207
+ if (steps.length > DONE_STEPS || longest > DONE_STEP_WORDS) delete patch.progress;
208
+ }
209
+ if (typeof patch.solution === 'string' && wordsIn(patch.solution) > SUMMARY_WORDS) {
210
+ said.push(`solution (${wordsIn(patch.solution)} words; ${SUMMARY_WORDS} at most)`);
211
+ delete patch.solution;
212
+ }
213
+ if (!said.length) return {};
214
+ return { summaryTooLong: `Not saved: ${said.join(', ')}. The summary has to fit the panel without scrolling; everything else you sent was written, and ${said.length === 1 ? 'that part keeps' : 'those parts keep'} what ${said.length === 1 ? 'it' : 'they'} said before. Send ${said.length === 1 ? 'it' : 'them'} again shorter.` };
215
+ }
216
+
148
217
  const LEFT_OPEN = 'The row was left OPEN. The founder wrote it, and only she closes her own rows unless she asked you to: everything else you sent was written, and your answer reaches her inbox as an answer. If she did ask you to close it, send status done again with closeBecause set to her exact words asking for it.';
149
218
 
150
219
  /**
@@ -182,6 +251,11 @@ export function createClaimRegistry({ heartbeatMs = HEARTBEAT_MS, holder } = {})
182
251
  for (const [id, { dir, epoch, live }] of held) {
183
252
  if (!live) continue;
184
253
  try {
254
+ const current = readWorkItem(dir, id);
255
+ if (!current?.claim || current.epoch !== epoch || current.claim.holder !== holder) {
256
+ held.get(id).live = false;
257
+ continue;
258
+ }
185
259
  heartbeatWorkItem(dir, id, { epoch, holder });
186
260
  } catch (err) {
187
261
  // A failed beat is not fatal: the lease still has two beats of margin,
@@ -190,6 +264,7 @@ export function createClaimRegistry({ heartbeatMs = HEARTBEAT_MS, holder } = {})
190
264
  console.error(`${LOG} heartbeat failed for ${id}: ${err?.message ?? err}`);
191
265
  }
192
266
  }
267
+ stopTimer();
193
268
  };
194
269
 
195
270
  const ensureTimer = () => {
@@ -297,7 +372,7 @@ export function createClaimRegistry({ heartbeatMs = HEARTBEAT_MS, holder } = {})
297
372
  // fence below still catches the case where somebody else took over.
298
373
  }
299
374
 
300
- const { closeBecause, ...asked } = patch;
375
+ const { closeBecause, deferBecause, ...asked } = patch;
301
376
  let leftOpen = false;
302
377
  if (asked.status === 'done') {
303
378
  const before = readWorkItem(holding.dir, id);
@@ -306,6 +381,18 @@ export function createClaimRegistry({ heartbeatMs = HEARTBEAT_MS, holder } = {})
306
381
  leftOpen = true;
307
382
  }
308
383
  }
384
+ let theirMoment = 0;
385
+ let deferredAsAgent = null;
386
+ if (deferBecause !== undefined && Number.isFinite(asked.runAt) && asked.runAt > 0) {
387
+ const before = readWorkItem(holding.dir, id);
388
+ if (herRow(before) && saidToClose(before, deferBecause)) {
389
+ theirMoment = asked.runAt;
390
+ delete asked.runAt;
391
+ } else {
392
+ deferredAsAgent = { deferredAsAgent: DEFERRED_AS_AGENT };
393
+ }
394
+ }
395
+ const summaryTooLong = takeOverLong(asked);
309
396
  patch = asked;
310
397
  let item = Object.keys(patch).length
311
398
  ? updateWorkItem(holding.dir, id, patch, { epoch: holding.epoch })
@@ -329,6 +416,10 @@ export function createClaimRegistry({ heartbeatMs = HEARTBEAT_MS, holder } = {})
329
416
  holding.pending = false;
330
417
  }
331
418
 
419
+ // Only now, past the fence, so a session that lost the row cannot still
420
+ // put it away in the user's name.
421
+ if (theirMoment) item = updateWorkItem(holding.dir, id, { runAt: theirMoment }, { source: 'founder' });
422
+
332
423
  // FINISHING A ROW GIVES THE CLAIM BACK NOW, not in five minutes. It used
333
424
  // to drop the row from this map and leave the claim line standing, so the
334
425
  // ledger went on reading "held by <this session>" for a full lease after
@@ -351,9 +442,9 @@ export function createClaimRegistry({ heartbeatMs = HEARTBEAT_MS, holder } = {})
351
442
  holding.live = false;
352
443
  stopTimer();
353
444
  }
354
- return { ...item, leftOpen: LEFT_OPEN };
445
+ return { ...item, leftOpen: LEFT_OPEN, ...deferredAsAgent, ...summaryTooLong };
355
446
  }
356
- return item;
447
+ return { ...item, ...deferredAsAgent, ...summaryTooLong };
357
448
  },
358
449
 
359
450
  release(id) {
@@ -365,6 +456,12 @@ export function createClaimRegistry({ heartbeatMs = HEARTBEAT_MS, holder } = {})
365
456
  return item;
366
457
  },
367
458
 
459
+ // Filing from this session: what it files is kept as private as every row
460
+ // it has held, finished ones too, since it may still be answering on them.
461
+ file(product, fields) {
462
+ return createItem(product, fields, { from: [...held.keys()] });
463
+ },
464
+
368
465
  holding: () => [...held.entries()].filter(([, h]) => h.live).map(([id]) => id),
369
466
  // Test seams; not part of normal use.
370
467
  _beat: beat,
package/mcp/tools.mjs CHANGED
@@ -16,10 +16,11 @@ import { resolveAccount } from './core/account.mjs';
16
16
  import { listProducts, getProduct, createProduct, updateProduct } from './core/products.mjs';
17
17
  import { listDocuments, readDocument, writeDocument } from './core/documents.mjs';
18
18
  import { listSkills, fetchSkill, fetchReference } from './core/skills.mjs';
19
- import { listWorkItems, createItem, updateItem, createClaimRegistry } from './core/work.mjs';
19
+ import { listWorkItems, updateItem, createClaimRegistry } from './core/work.mjs';
20
20
  import { listProductChats, readProductChat } from './core/chat.mjs';
21
21
  import { lookAtPage } from './core/page.mjs';
22
22
  import { WORK_ITEM_STATUSES } from '../shared/work-items.mjs';
23
+ import { CONTEXT_WORDS, DONE_STEPS, DONE_STEP_WORDS, SUMMARY_WORDS } from '../shared/thread-cards.mjs';
23
24
  import { AGENT_CREATION_KINDS } from '../shared/contracts.mjs';
24
25
  // The descriptions below are read by every agent on every run, so the app is
25
26
  // named in them from the one place it is named. They said "the app" while this
@@ -36,7 +37,7 @@ const CAPABILITIES = [
36
37
  ];
37
38
  const MISSING = [
38
39
  'create_database', 'deploy_app', 'connect_github', 'set_up_analytics',
39
- 'run_creation', 'browsing the web or anything she is signed into', 'ask_user',
40
+ 'run_creation', 'browsing the web or anything they are signed into', 'ask_user',
40
41
  ];
41
42
 
42
43
  const json = (value) => ({ content: [{ type: 'text', text: JSON.stringify(value, null, 2) }] });
@@ -172,7 +173,7 @@ export function buildTools({ holder } = {}) {
172
173
  parent: z.string().optional().describe('another work item id, for a subtask'),
173
174
  runAt: z.number().int().optional().describe('epoch ms before which nothing happens with this item: it cannot be claimed and will not start. Use it when the work genuinely belongs to a later moment. A missed moment is not lost; the item simply becomes available once it passes.'),
174
175
  },
175
- run: ({ product, ...fields }) => json(createItem(product, fields)),
176
+ run: ({ product, ...fields }) => json(claims.file(product, fields)),
176
177
  },
177
178
  {
178
179
  name: 'claim_work_item',
@@ -190,7 +191,7 @@ export function buildTools({ holder } = {}) {
190
191
  },
191
192
  {
192
193
  name: 'update_work_item',
193
- description: 'Report progress on an item: set status to done when it is finished, blocked when it cannot proceed until something outside it changes, and leave a note saying where things stand. A worker the app started for a row ends with its answer as its last message, and the app writes that message onto the row as the result, so such a worker does not pass result for its own row: the same answer written twice is what she then reads twice. A row the founder wrote (labelled founder) is closed only when she asked for it: answering her is not finishing it, so the row stays open for her. To close one, pass closeBecause with her exact words asking you to; without them the rest of the write lands and the row is left open. Writing to a row this session is not holding takes the row first, so there is no need to claim before you speak; the write is only refused when another session is genuinely on it, and that refusal is kept rather than thrown away, parked where the error says and handed to whoever takes the row next. Finishing a row hands the claim straight back, and you can still answer on it afterwards.',
194
+ description: 'Report progress on an item: set status to done when it is finished, blocked when it cannot proceed until something outside it changes, and leave a note saying where things stand. Keep the summary current with problem (shown as Context) and progress (shown as the Done list), which is all a teammate sees of the thread. A worker the app started for a row ends with its answer as its last message, and the app writes that message onto the row as the result, so such a worker does not pass result for its own row: the same answer written twice is what they then read twice. A row the founder wrote (labelled founder) is closed only when they asked for it: answering them is not finishing it, so the row stays open for them. To close one, pass closeBecause with their exact words asking you to; without them the rest of the write lands and the row is left open. A runAt you set holds workers off but keeps the row in their inbox; when they asked for it to be put off ("remind me Friday"), pass deferBecause with their exact words and it leaves their inbox until then. Writing to a row this session is not holding takes the row first, so there is no need to claim before you speak; the write is only refused when another session is genuinely on it, and that refusal is kept rather than thrown away, parked where the error says and handed to whoever takes the row next. Finishing a row hands the claim straight back, and you can still answer on it afterwards.',
194
195
  schema: {
195
196
  id: z.string(),
196
197
  status: z.enum(WORK_ITEM_STATUSES).optional(),
@@ -199,7 +200,13 @@ export function buildTools({ holder } = {}) {
199
200
  priority: z.number().int().optional(),
200
201
  labels: z.array(z.string()).optional(),
201
202
  runAt: z.number().int().optional().describe('epoch ms to defer this item until; 0 clears a schedule and makes it available now'),
202
- closeBecause: z.string().optional().describe('only with status done on a row the founder wrote: her own words, quoted exactly from the row, asking you to close it'),
203
+ closeBecause: z.string().optional().describe('only with status done on a row the founder wrote: their own words, quoted exactly from the row, asking you to close it'),
204
+ deferBecause: z.string().optional().describe('only with runAt on a row the founder wrote: their own words, quoted exactly from the row, asking for it to be put off or to be reminded later. Without them the row stays in their inbox'),
205
+ problem: z.string().optional().describe(`the summary's CONTEXT: a few plain sentences, ${CONTEXT_WORDS} words at most, that bring the thread back to someone who has forgotten it: what was asked, what was found, the facts needed to decide`),
206
+ progress: z.string().optional().describe(`the summary's DONE list: the steps taken so far, one per line, oldest first and newest last, ${DONE_STEPS} lines at most of ${DONE_STEP_WORDS} words each. Send the whole list each time; it replaces the last one`),
207
+ solution: z.string().optional().describe(`no longer shown; leave it out (older threads may still carry one, ${SUMMARY_WORDS} words at most)`),
208
+ blockedBy: z.array(z.string()).optional().describe('ids of threads this one waits on'),
209
+ blocks: z.array(z.string()).optional().describe('ids of threads that wait on this one'),
203
210
  },
204
211
  run: async ({ id, ...patch }) => json(await claims.update(id, patch)),
205
212
  },
@@ -238,7 +245,7 @@ export function buildTools({ holder } = {}) {
238
245
  // address can post anything it has read to any address.
239
246
  {
240
247
  name: 'look_at_page',
241
- description: `Open a page running on this machine, photograph it, and read its words back. For looking at what you just built: start the app, look at it, then name the picture in your message so she sees what you saw. Local addresses only, so it cannot reach the web or anything she is signed into. Returns the picture's path inside the product, plus the page's title and visible text.`,
248
+ description: `Open a page running on this machine, photograph it, and read its words back. For looking at what you just built: start the app, look at it, then name the picture in your message so they see what you saw. Local addresses only, so it cannot reach the web or anything they are signed into. Returns the picture's path inside the product, plus the page's title and visible text.`,
242
249
  schema: {
243
250
  product: z.string(),
244
251
  url: z.string().describe('a local address, as in http://localhost:3000/'),
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "agentbox-app",
3
- "productName": "agentbox",
4
- "version": "0.1.7",
3
+ "productName": "Agentbox",
4
+ "version": "0.1.12",
5
5
  "description": "An inbox for managing dozens of Claude Code and Codex agents.",
6
6
  "author": "Savannah Feder",
7
7
  "repository": {
@@ -42,6 +42,7 @@
42
42
  "scripts/before-publish.mjs",
43
43
  "scripts/after-install.mjs",
44
44
  "scripts/approval-server.sh",
45
+ "scripts/memory-gate-hook.sh",
45
46
  "worker-permissions.json",
46
47
  "LICENSE",
47
48
  "README.md"
@@ -49,21 +50,28 @@
49
50
  "scripts": {
50
51
  "dev": "node scripts/dev.mjs",
51
52
  "build": "node scripts/prepare-terminal.mjs && node scripts/read-claude-commands.mjs && node scripts/read-claude-models.mjs && vite build renderer",
52
- "start": "npm run build && electron .",
53
+ "start": "npm run build && node scripts/brand-electron.mjs && electron .",
53
54
  "test": "vitest run",
55
+ "typecheck": "node node_modules/typescript/bin/tsc --noEmit -p renderer/tsconfig.json",
56
+ "test:changed": "node scripts/test-what-changed.mjs",
54
57
  "icon": "electron scripts/make-icon.mjs",
55
58
  "pack": "node scripts/release.mjs --no-sign",
56
59
  "pack:side": "node scripts/pack-side.mjs",
57
60
  "release": "node scripts/release.mjs",
61
+ "setup:feedback": "node scripts/set-up-feedback.mjs",
58
62
  "fresh": "node scripts/fresh-user.mjs",
59
63
  "hooks:install": "node scripts/install-hooks.mjs",
64
+ "check:public": "node scripts/check-before-public.mjs --all",
65
+ "ship": "node scripts/ship.mjs",
60
66
  "prepare": "node scripts/install-hooks.mjs",
61
67
  "serve": "node bin/agentbox.mjs",
62
68
  "prepack": "npm run build",
63
69
  "postinstall": "node scripts/after-install.mjs",
64
- "prepublishOnly": "node scripts/before-publish.mjs"
70
+ "prepublishOnly": "node scripts/before-publish.mjs",
71
+ "app": "vite build renderer --logLevel warn && node scripts/prepare-terminal.mjs && node scripts/brand-electron.mjs && electron ."
65
72
  },
66
73
  "devDependencies": {
74
+ "@electric-sql/pglite": "^0.5.8",
67
75
  "@fontsource-variable/source-sans-3": "^5.3.0",
68
76
  "@tiptap/core": "^2.27.2",
69
77
  "@tiptap/extension-link": "^2.27.2",
@@ -96,6 +104,7 @@
96
104
  },
97
105
  "dependencies": {
98
106
  "@modelcontextprotocol/sdk": "^1.29.0",
107
+ "@supabase/supabase-js": "^2.117.2",
99
108
  "electron-updater": "^6.8.9",
100
109
  "node-pty": "^1.1.0",
101
110
  "posthog-node": "^5.21.2",
@@ -103,7 +112,7 @@
103
112
  },
104
113
  "build": {
105
114
  "appId": "ac.astral.app",
106
- "productName": "agentbox",
115
+ "productName": "Agentbox",
107
116
  "copyright": "Copyright © 2026 Agentbox",
108
117
  "directories": {
109
118
  "output": "release",
@@ -118,12 +127,14 @@
118
127
  "!briefs/writing-rules.md",
119
128
  "worker-permissions.json",
120
129
  "scripts/approval-server.sh",
130
+ "scripts/memory-gate-hook.sh",
121
131
  "renderer/dist/**/*",
122
132
  "package.json"
123
133
  ],
124
134
  "asarUnpack": [
125
135
  "worker-permissions.json",
126
136
  "scripts/approval-server.sh",
137
+ "scripts/memory-gate-hook.sh",
127
138
  "node_modules/node-pty/**"
128
139
  ],
129
140
  "mac": {
@@ -132,10 +143,11 @@
132
143
  "NSDocumentsFolderUsageDescription": "Agentbox needs this to let your agents work in a project you keep in Documents.",
133
144
  "NSDownloadsFolderUsageDescription": "Agentbox needs this to let your agents work in a project you keep in Downloads.",
134
145
  "NSRemovableVolumesUsageDescription": "Agentbox needs this to let your agents work in a project you keep on an external disk.",
135
- "NSAppleEventsUsageDescription": "Agentbox needs this to place the app you rest in, and when an agent you started asks another app to do something."
146
+ "NSAppleEventsUsageDescription": "Agentbox needs this when an agent you started asks another app to do something."
136
147
  },
137
148
  "category": "public.app-category.productivity",
138
149
  "icon": "build/icon.icns",
150
+ "x64ArchFiles": "Contents/Resources/app.asar.unpacked/node_modules/node-pty/prebuilds/darwin-*/*",
139
151
  "target": [
140
152
  {
141
153
  "target": "dmg",
@@ -157,7 +169,7 @@
157
169
  "notarize": false
158
170
  },
159
171
  "dmg": {
160
- "title": "agentbox",
172
+ "title": "Agentbox",
161
173
  "contents": [
162
174
  {
163
175
  "x": 140,
@@ -175,8 +187,8 @@
175
187
  "publish": [
176
188
  {
177
189
  "provider": "github",
178
- "owner": "Astral-Agent",
179
- "repo": "astral-releases"
190
+ "owner": "agentboxhq",
191
+ "repo": "agentbox-releases"
180
192
  }
181
193
  ]
182
194
  },
@@ -0,0 +1,15 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024"><defs><clipPath id="tile-clip"><path d="M924.0 512.0 L923.9 608.0 L923.8 638.6 L923.5 660.9 L923.1 679.0 L922.6 694.5 L922.0 708.2 L921.2 720.5 L920.4 731.8 L919.4 742.2 L918.3 751.9 L917.1 761.0 L915.8 769.6 L914.4 777.6 L912.8 785.3 L911.2 792.6 L909.4 799.5 L907.5 806.1 L905.4 812.4 L903.3 818.5 L901.0 824.2 L898.5 829.8 L896.0 835.1 L893.3 840.2 L890.5 845.1 L887.6 849.8 L884.5 854.3 L881.2 858.7 L877.9 862.8 L874.3 866.8 L870.7 870.7 L866.8 874.3 L862.8 877.9 L858.7 881.2 L854.3 884.5 L849.8 887.6 L845.1 890.5 L840.2 893.3 L835.1 896.0 L829.8 898.5 L824.2 901.0 L818.5 903.3 L812.4 905.4 L806.1 907.5 L799.5 909.4 L792.6 911.2 L785.3 912.8 L777.6 914.4 L769.6 915.8 L761.0 917.1 L751.9 918.3 L742.2 919.4 L731.8 920.4 L720.5 921.2 L708.2 922.0 L694.5 922.6 L679.0 923.1 L660.9 923.5 L638.6 923.8 L608.0 923.9 L512.0 924.0 L416.0 923.9 L385.4 923.8 L363.1 923.5 L345.0 923.1 L329.5 922.6 L315.8 922.0 L303.5 921.2 L292.2 920.4 L281.8 919.4 L272.1 918.3 L263.0 917.1 L254.4 915.8 L246.4 914.4 L238.7 912.8 L231.4 911.2 L224.5 909.4 L217.9 907.5 L211.6 905.4 L205.5 903.3 L199.8 901.0 L194.2 898.5 L188.9 896.0 L183.8 893.3 L178.9 890.5 L174.2 887.6 L169.7 884.5 L165.3 881.2 L161.2 877.9 L157.2 874.3 L153.3 870.7 L149.7 866.8 L146.1 862.8 L142.8 858.7 L139.5 854.3 L136.4 849.8 L133.5 845.1 L130.7 840.2 L128.0 835.1 L125.5 829.8 L123.0 824.2 L120.7 818.5 L118.6 812.4 L116.5 806.1 L114.6 799.5 L112.8 792.6 L111.2 785.3 L109.6 777.6 L108.2 769.6 L106.9 761.0 L105.7 751.9 L104.6 742.2 L103.6 731.8 L102.8 720.5 L102.0 708.2 L101.4 694.5 L100.9 679.0 L100.5 660.9 L100.2 638.6 L100.1 608.0 L100.0 512.0 L100.1 416.0 L100.2 385.4 L100.5 363.1 L100.9 345.0 L101.4 329.5 L102.0 315.8 L102.8 303.5 L103.6 292.2 L104.6 281.8 L105.7 272.1 L106.9 263.0 L108.2 254.4 L109.6 246.4 L111.2 238.7 L112.8 231.4 L114.6 224.5 L116.5 217.9 L118.6 211.6 L120.7 205.5 L123.0 199.8 L125.5 194.2 L128.0 188.9 L130.7 183.8 L133.5 178.9 L136.4 174.2 L139.5 169.7 L142.8 165.3 L146.1 161.2 L149.7 157.2 L153.3 153.3 L157.2 149.7 L161.2 146.1 L165.3 142.8 L169.7 139.5 L174.2 136.4 L178.9 133.5 L183.8 130.7 L188.9 128.0 L194.2 125.5 L199.8 123.0 L205.5 120.7 L211.6 118.6 L217.9 116.5 L224.5 114.6 L231.4 112.8 L238.7 111.2 L246.4 109.6 L254.4 108.2 L263.0 106.9 L272.1 105.7 L281.8 104.6 L292.2 103.6 L303.5 102.8 L315.8 102.0 L329.5 101.4 L345.0 100.9 L363.1 100.5 L385.4 100.2 L416.0 100.1 L512.0 100.0 L608.0 100.1 L638.6 100.2 L660.9 100.5 L679.0 100.9 L694.5 101.4 L708.2 102.0 L720.5 102.8 L731.8 103.6 L742.2 104.6 L751.9 105.7 L761.0 106.9 L769.6 108.2 L777.6 109.6 L785.3 111.2 L792.6 112.8 L799.5 114.6 L806.1 116.5 L812.4 118.6 L818.5 120.7 L824.2 123.0 L829.8 125.5 L835.1 128.0 L840.2 130.7 L845.1 133.5 L849.8 136.4 L854.3 139.5 L858.7 142.8 L862.8 146.1 L866.8 149.7 L870.7 153.3 L874.3 157.2 L877.9 161.2 L881.2 165.3 L884.5 169.7 L887.6 174.2 L890.5 178.9 L893.3 183.8 L896.0 188.9 L898.5 194.2 L901.0 199.8 L903.3 205.5 L905.4 211.6 L907.5 217.9 L909.4 224.5 L911.2 231.4 L912.8 238.7 L914.4 246.4 L915.8 254.4 L917.1 263.0 L918.3 272.1 L919.4 281.8 L920.4 292.2 L921.2 303.5 L922.0 315.8 L922.6 329.5 L923.1 345.0 L923.5 363.1 L923.8 385.4 L923.9 416.0Z"/></clipPath>
2
+ <linearGradient id="t-black" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#1b1a1a"/><stop offset="1" stop-color="#080808"/></linearGradient>
3
+ <linearGradient id="sheen-d" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#fff" stop-opacity=".07"/><stop offset=".5" stop-color="#fff" stop-opacity="0"/></linearGradient>
4
+ <linearGradient id="edge-d" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#fff" stop-opacity=".22"/><stop offset=".35" stop-color="#fff" stop-opacity=".05"/><stop offset="1" stop-color="#fff" stop-opacity=".03"/></linearGradient>
5
+ <linearGradient id="or" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#F47632"/><stop offset="1" stop-color="#E0530C"/></linearGradient>
6
+ <linearGradient id="sheen-or" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#fff" stop-opacity=".22"/><stop offset=".5" stop-color="#fff" stop-opacity="0"/><stop offset="1" stop-color="#7a2400" stop-opacity=".12"/></linearGradient>
7
+ <linearGradient id="row-film" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#f4f1ec"/><stop offset="1" stop-color="#dcd5cd"/></linearGradient>
8
+ <linearGradient id="sheen-row" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#fff" stop-opacity=".5"/><stop offset=".45" stop-color="#fff" stop-opacity="0"/></linearGradient>
9
+ <linearGradient id="or-edge" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="#fff" stop-opacity=".3"/><stop offset=".4" stop-color="#fff" stop-opacity=".04"/><stop offset="1" stop-color="#fff" stop-opacity=".08"/></linearGradient>
10
+ <filter id="b3" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="3"/></filter>
11
+ <filter id="b16" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="16"/></filter><filter id="b16" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="16"/></filter><filter id="b3" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="3"/></filter></defs><path d="M924.0 512.0 L923.9 608.0 L923.8 638.6 L923.5 660.9 L923.1 679.0 L922.6 694.5 L922.0 708.2 L921.2 720.5 L920.4 731.8 L919.4 742.2 L918.3 751.9 L917.1 761.0 L915.8 769.6 L914.4 777.6 L912.8 785.3 L911.2 792.6 L909.4 799.5 L907.5 806.1 L905.4 812.4 L903.3 818.5 L901.0 824.2 L898.5 829.8 L896.0 835.1 L893.3 840.2 L890.5 845.1 L887.6 849.8 L884.5 854.3 L881.2 858.7 L877.9 862.8 L874.3 866.8 L870.7 870.7 L866.8 874.3 L862.8 877.9 L858.7 881.2 L854.3 884.5 L849.8 887.6 L845.1 890.5 L840.2 893.3 L835.1 896.0 L829.8 898.5 L824.2 901.0 L818.5 903.3 L812.4 905.4 L806.1 907.5 L799.5 909.4 L792.6 911.2 L785.3 912.8 L777.6 914.4 L769.6 915.8 L761.0 917.1 L751.9 918.3 L742.2 919.4 L731.8 920.4 L720.5 921.2 L708.2 922.0 L694.5 922.6 L679.0 923.1 L660.9 923.5 L638.6 923.8 L608.0 923.9 L512.0 924.0 L416.0 923.9 L385.4 923.8 L363.1 923.5 L345.0 923.1 L329.5 922.6 L315.8 922.0 L303.5 921.2 L292.2 920.4 L281.8 919.4 L272.1 918.3 L263.0 917.1 L254.4 915.8 L246.4 914.4 L238.7 912.8 L231.4 911.2 L224.5 909.4 L217.9 907.5 L211.6 905.4 L205.5 903.3 L199.8 901.0 L194.2 898.5 L188.9 896.0 L183.8 893.3 L178.9 890.5 L174.2 887.6 L169.7 884.5 L165.3 881.2 L161.2 877.9 L157.2 874.3 L153.3 870.7 L149.7 866.8 L146.1 862.8 L142.8 858.7 L139.5 854.3 L136.4 849.8 L133.5 845.1 L130.7 840.2 L128.0 835.1 L125.5 829.8 L123.0 824.2 L120.7 818.5 L118.6 812.4 L116.5 806.1 L114.6 799.5 L112.8 792.6 L111.2 785.3 L109.6 777.6 L108.2 769.6 L106.9 761.0 L105.7 751.9 L104.6 742.2 L103.6 731.8 L102.8 720.5 L102.0 708.2 L101.4 694.5 L100.9 679.0 L100.5 660.9 L100.2 638.6 L100.1 608.0 L100.0 512.0 L100.1 416.0 L100.2 385.4 L100.5 363.1 L100.9 345.0 L101.4 329.5 L102.0 315.8 L102.8 303.5 L103.6 292.2 L104.6 281.8 L105.7 272.1 L106.9 263.0 L108.2 254.4 L109.6 246.4 L111.2 238.7 L112.8 231.4 L114.6 224.5 L116.5 217.9 L118.6 211.6 L120.7 205.5 L123.0 199.8 L125.5 194.2 L128.0 188.9 L130.7 183.8 L133.5 178.9 L136.4 174.2 L139.5 169.7 L142.8 165.3 L146.1 161.2 L149.7 157.2 L153.3 153.3 L157.2 149.7 L161.2 146.1 L165.3 142.8 L169.7 139.5 L174.2 136.4 L178.9 133.5 L183.8 130.7 L188.9 128.0 L194.2 125.5 L199.8 123.0 L205.5 120.7 L211.6 118.6 L217.9 116.5 L224.5 114.6 L231.4 112.8 L238.7 111.2 L246.4 109.6 L254.4 108.2 L263.0 106.9 L272.1 105.7 L281.8 104.6 L292.2 103.6 L303.5 102.8 L315.8 102.0 L329.5 101.4 L345.0 100.9 L363.1 100.5 L385.4 100.2 L416.0 100.1 L512.0 100.0 L608.0 100.1 L638.6 100.2 L660.9 100.5 L679.0 100.9 L694.5 101.4 L708.2 102.0 L720.5 102.8 L731.8 103.6 L742.2 104.6 L751.9 105.7 L761.0 106.9 L769.6 108.2 L777.6 109.6 L785.3 111.2 L792.6 112.8 L799.5 114.6 L806.1 116.5 L812.4 118.6 L818.5 120.7 L824.2 123.0 L829.8 125.5 L835.1 128.0 L840.2 130.7 L845.1 133.5 L849.8 136.4 L854.3 139.5 L858.7 142.8 L862.8 146.1 L866.8 149.7 L870.7 153.3 L874.3 157.2 L877.9 161.2 L881.2 165.3 L884.5 169.7 L887.6 174.2 L890.5 178.9 L893.3 183.8 L896.0 188.9 L898.5 194.2 L901.0 199.8 L903.3 205.5 L905.4 211.6 L907.5 217.9 L909.4 224.5 L911.2 231.4 L912.8 238.7 L914.4 246.4 L915.8 254.4 L917.1 263.0 L918.3 272.1 L919.4 281.8 L920.4 292.2 L921.2 303.5 L922.0 315.8 L922.6 329.5 L923.1 345.0 L923.5 363.1 L923.8 385.4 L923.9 416.0Z" transform="translate(0 12)" fill="#000" opacity="0.42" filter="url(#b16)" /><path d="M924.0 512.0 L923.9 608.0 L923.8 638.6 L923.5 660.9 L923.1 679.0 L922.6 694.5 L922.0 708.2 L921.2 720.5 L920.4 731.8 L919.4 742.2 L918.3 751.9 L917.1 761.0 L915.8 769.6 L914.4 777.6 L912.8 785.3 L911.2 792.6 L909.4 799.5 L907.5 806.1 L905.4 812.4 L903.3 818.5 L901.0 824.2 L898.5 829.8 L896.0 835.1 L893.3 840.2 L890.5 845.1 L887.6 849.8 L884.5 854.3 L881.2 858.7 L877.9 862.8 L874.3 866.8 L870.7 870.7 L866.8 874.3 L862.8 877.9 L858.7 881.2 L854.3 884.5 L849.8 887.6 L845.1 890.5 L840.2 893.3 L835.1 896.0 L829.8 898.5 L824.2 901.0 L818.5 903.3 L812.4 905.4 L806.1 907.5 L799.5 909.4 L792.6 911.2 L785.3 912.8 L777.6 914.4 L769.6 915.8 L761.0 917.1 L751.9 918.3 L742.2 919.4 L731.8 920.4 L720.5 921.2 L708.2 922.0 L694.5 922.6 L679.0 923.1 L660.9 923.5 L638.6 923.8 L608.0 923.9 L512.0 924.0 L416.0 923.9 L385.4 923.8 L363.1 923.5 L345.0 923.1 L329.5 922.6 L315.8 922.0 L303.5 921.2 L292.2 920.4 L281.8 919.4 L272.1 918.3 L263.0 917.1 L254.4 915.8 L246.4 914.4 L238.7 912.8 L231.4 911.2 L224.5 909.4 L217.9 907.5 L211.6 905.4 L205.5 903.3 L199.8 901.0 L194.2 898.5 L188.9 896.0 L183.8 893.3 L178.9 890.5 L174.2 887.6 L169.7 884.5 L165.3 881.2 L161.2 877.9 L157.2 874.3 L153.3 870.7 L149.7 866.8 L146.1 862.8 L142.8 858.7 L139.5 854.3 L136.4 849.8 L133.5 845.1 L130.7 840.2 L128.0 835.1 L125.5 829.8 L123.0 824.2 L120.7 818.5 L118.6 812.4 L116.5 806.1 L114.6 799.5 L112.8 792.6 L111.2 785.3 L109.6 777.6 L108.2 769.6 L106.9 761.0 L105.7 751.9 L104.6 742.2 L103.6 731.8 L102.8 720.5 L102.0 708.2 L101.4 694.5 L100.9 679.0 L100.5 660.9 L100.2 638.6 L100.1 608.0 L100.0 512.0 L100.1 416.0 L100.2 385.4 L100.5 363.1 L100.9 345.0 L101.4 329.5 L102.0 315.8 L102.8 303.5 L103.6 292.2 L104.6 281.8 L105.7 272.1 L106.9 263.0 L108.2 254.4 L109.6 246.4 L111.2 238.7 L112.8 231.4 L114.6 224.5 L116.5 217.9 L118.6 211.6 L120.7 205.5 L123.0 199.8 L125.5 194.2 L128.0 188.9 L130.7 183.8 L133.5 178.9 L136.4 174.2 L139.5 169.7 L142.8 165.3 L146.1 161.2 L149.7 157.2 L153.3 153.3 L157.2 149.7 L161.2 146.1 L165.3 142.8 L169.7 139.5 L174.2 136.4 L178.9 133.5 L183.8 130.7 L188.9 128.0 L194.2 125.5 L199.8 123.0 L205.5 120.7 L211.6 118.6 L217.9 116.5 L224.5 114.6 L231.4 112.8 L238.7 111.2 L246.4 109.6 L254.4 108.2 L263.0 106.9 L272.1 105.7 L281.8 104.6 L292.2 103.6 L303.5 102.8 L315.8 102.0 L329.5 101.4 L345.0 100.9 L363.1 100.5 L385.4 100.2 L416.0 100.1 L512.0 100.0 L608.0 100.1 L638.6 100.2 L660.9 100.5 L679.0 100.9 L694.5 101.4 L708.2 102.0 L720.5 102.8 L731.8 103.6 L742.2 104.6 L751.9 105.7 L761.0 106.9 L769.6 108.2 L777.6 109.6 L785.3 111.2 L792.6 112.8 L799.5 114.6 L806.1 116.5 L812.4 118.6 L818.5 120.7 L824.2 123.0 L829.8 125.5 L835.1 128.0 L840.2 130.7 L845.1 133.5 L849.8 136.4 L854.3 139.5 L858.7 142.8 L862.8 146.1 L866.8 149.7 L870.7 153.3 L874.3 157.2 L877.9 161.2 L881.2 165.3 L884.5 169.7 L887.6 174.2 L890.5 178.9 L893.3 183.8 L896.0 188.9 L898.5 194.2 L901.0 199.8 L903.3 205.5 L905.4 211.6 L907.5 217.9 L909.4 224.5 L911.2 231.4 L912.8 238.7 L914.4 246.4 L915.8 254.4 L917.1 263.0 L918.3 272.1 L919.4 281.8 L920.4 292.2 L921.2 303.5 L922.0 315.8 L922.6 329.5 L923.1 345.0 L923.5 363.1 L923.8 385.4 L923.9 416.0Z" transform="translate(0 2)" fill="#000" opacity="0.18" filter="url(#b3)" />
12
+ <path d="M924.0 512.0 L923.9 608.0 L923.8 638.6 L923.5 660.9 L923.1 679.0 L922.6 694.5 L922.0 708.2 L921.2 720.5 L920.4 731.8 L919.4 742.2 L918.3 751.9 L917.1 761.0 L915.8 769.6 L914.4 777.6 L912.8 785.3 L911.2 792.6 L909.4 799.5 L907.5 806.1 L905.4 812.4 L903.3 818.5 L901.0 824.2 L898.5 829.8 L896.0 835.1 L893.3 840.2 L890.5 845.1 L887.6 849.8 L884.5 854.3 L881.2 858.7 L877.9 862.8 L874.3 866.8 L870.7 870.7 L866.8 874.3 L862.8 877.9 L858.7 881.2 L854.3 884.5 L849.8 887.6 L845.1 890.5 L840.2 893.3 L835.1 896.0 L829.8 898.5 L824.2 901.0 L818.5 903.3 L812.4 905.4 L806.1 907.5 L799.5 909.4 L792.6 911.2 L785.3 912.8 L777.6 914.4 L769.6 915.8 L761.0 917.1 L751.9 918.3 L742.2 919.4 L731.8 920.4 L720.5 921.2 L708.2 922.0 L694.5 922.6 L679.0 923.1 L660.9 923.5 L638.6 923.8 L608.0 923.9 L512.0 924.0 L416.0 923.9 L385.4 923.8 L363.1 923.5 L345.0 923.1 L329.5 922.6 L315.8 922.0 L303.5 921.2 L292.2 920.4 L281.8 919.4 L272.1 918.3 L263.0 917.1 L254.4 915.8 L246.4 914.4 L238.7 912.8 L231.4 911.2 L224.5 909.4 L217.9 907.5 L211.6 905.4 L205.5 903.3 L199.8 901.0 L194.2 898.5 L188.9 896.0 L183.8 893.3 L178.9 890.5 L174.2 887.6 L169.7 884.5 L165.3 881.2 L161.2 877.9 L157.2 874.3 L153.3 870.7 L149.7 866.8 L146.1 862.8 L142.8 858.7 L139.5 854.3 L136.4 849.8 L133.5 845.1 L130.7 840.2 L128.0 835.1 L125.5 829.8 L123.0 824.2 L120.7 818.5 L118.6 812.4 L116.5 806.1 L114.6 799.5 L112.8 792.6 L111.2 785.3 L109.6 777.6 L108.2 769.6 L106.9 761.0 L105.7 751.9 L104.6 742.2 L103.6 731.8 L102.8 720.5 L102.0 708.2 L101.4 694.5 L100.9 679.0 L100.5 660.9 L100.2 638.6 L100.1 608.0 L100.0 512.0 L100.1 416.0 L100.2 385.4 L100.5 363.1 L100.9 345.0 L101.4 329.5 L102.0 315.8 L102.8 303.5 L103.6 292.2 L104.6 281.8 L105.7 272.1 L106.9 263.0 L108.2 254.4 L109.6 246.4 L111.2 238.7 L112.8 231.4 L114.6 224.5 L116.5 217.9 L118.6 211.6 L120.7 205.5 L123.0 199.8 L125.5 194.2 L128.0 188.9 L130.7 183.8 L133.5 178.9 L136.4 174.2 L139.5 169.7 L142.8 165.3 L146.1 161.2 L149.7 157.2 L153.3 153.3 L157.2 149.7 L161.2 146.1 L165.3 142.8 L169.7 139.5 L174.2 136.4 L178.9 133.5 L183.8 130.7 L188.9 128.0 L194.2 125.5 L199.8 123.0 L205.5 120.7 L211.6 118.6 L217.9 116.5 L224.5 114.6 L231.4 112.8 L238.7 111.2 L246.4 109.6 L254.4 108.2 L263.0 106.9 L272.1 105.7 L281.8 104.6 L292.2 103.6 L303.5 102.8 L315.8 102.0 L329.5 101.4 L345.0 100.9 L363.1 100.5 L385.4 100.2 L416.0 100.1 L512.0 100.0 L608.0 100.1 L638.6 100.2 L660.9 100.5 L679.0 100.9 L694.5 101.4 L708.2 102.0 L720.5 102.8 L731.8 103.6 L742.2 104.6 L751.9 105.7 L761.0 106.9 L769.6 108.2 L777.6 109.6 L785.3 111.2 L792.6 112.8 L799.5 114.6 L806.1 116.5 L812.4 118.6 L818.5 120.7 L824.2 123.0 L829.8 125.5 L835.1 128.0 L840.2 130.7 L845.1 133.5 L849.8 136.4 L854.3 139.5 L858.7 142.8 L862.8 146.1 L866.8 149.7 L870.7 153.3 L874.3 157.2 L877.9 161.2 L881.2 165.3 L884.5 169.7 L887.6 174.2 L890.5 178.9 L893.3 183.8 L896.0 188.9 L898.5 194.2 L901.0 199.8 L903.3 205.5 L905.4 211.6 L907.5 217.9 L909.4 224.5 L911.2 231.4 L912.8 238.7 L914.4 246.4 L915.8 254.4 L917.1 263.0 L918.3 272.1 L919.4 281.8 L920.4 292.2 L921.2 303.5 L922.0 315.8 L922.6 329.5 L923.1 345.0 L923.5 363.1 L923.8 385.4 L923.9 416.0Z" fill="url(#t-black)"/>
13
+ <path d="M924.0 512.0 L923.9 608.0 L923.8 638.6 L923.5 660.9 L923.1 679.0 L922.6 694.5 L922.0 708.2 L921.2 720.5 L920.4 731.8 L919.4 742.2 L918.3 751.9 L917.1 761.0 L915.8 769.6 L914.4 777.6 L912.8 785.3 L911.2 792.6 L909.4 799.5 L907.5 806.1 L905.4 812.4 L903.3 818.5 L901.0 824.2 L898.5 829.8 L896.0 835.1 L893.3 840.2 L890.5 845.1 L887.6 849.8 L884.5 854.3 L881.2 858.7 L877.9 862.8 L874.3 866.8 L870.7 870.7 L866.8 874.3 L862.8 877.9 L858.7 881.2 L854.3 884.5 L849.8 887.6 L845.1 890.5 L840.2 893.3 L835.1 896.0 L829.8 898.5 L824.2 901.0 L818.5 903.3 L812.4 905.4 L806.1 907.5 L799.5 909.4 L792.6 911.2 L785.3 912.8 L777.6 914.4 L769.6 915.8 L761.0 917.1 L751.9 918.3 L742.2 919.4 L731.8 920.4 L720.5 921.2 L708.2 922.0 L694.5 922.6 L679.0 923.1 L660.9 923.5 L638.6 923.8 L608.0 923.9 L512.0 924.0 L416.0 923.9 L385.4 923.8 L363.1 923.5 L345.0 923.1 L329.5 922.6 L315.8 922.0 L303.5 921.2 L292.2 920.4 L281.8 919.4 L272.1 918.3 L263.0 917.1 L254.4 915.8 L246.4 914.4 L238.7 912.8 L231.4 911.2 L224.5 909.4 L217.9 907.5 L211.6 905.4 L205.5 903.3 L199.8 901.0 L194.2 898.5 L188.9 896.0 L183.8 893.3 L178.9 890.5 L174.2 887.6 L169.7 884.5 L165.3 881.2 L161.2 877.9 L157.2 874.3 L153.3 870.7 L149.7 866.8 L146.1 862.8 L142.8 858.7 L139.5 854.3 L136.4 849.8 L133.5 845.1 L130.7 840.2 L128.0 835.1 L125.5 829.8 L123.0 824.2 L120.7 818.5 L118.6 812.4 L116.5 806.1 L114.6 799.5 L112.8 792.6 L111.2 785.3 L109.6 777.6 L108.2 769.6 L106.9 761.0 L105.7 751.9 L104.6 742.2 L103.6 731.8 L102.8 720.5 L102.0 708.2 L101.4 694.5 L100.9 679.0 L100.5 660.9 L100.2 638.6 L100.1 608.0 L100.0 512.0 L100.1 416.0 L100.2 385.4 L100.5 363.1 L100.9 345.0 L101.4 329.5 L102.0 315.8 L102.8 303.5 L103.6 292.2 L104.6 281.8 L105.7 272.1 L106.9 263.0 L108.2 254.4 L109.6 246.4 L111.2 238.7 L112.8 231.4 L114.6 224.5 L116.5 217.9 L118.6 211.6 L120.7 205.5 L123.0 199.8 L125.5 194.2 L128.0 188.9 L130.7 183.8 L133.5 178.9 L136.4 174.2 L139.5 169.7 L142.8 165.3 L146.1 161.2 L149.7 157.2 L153.3 153.3 L157.2 149.7 L161.2 146.1 L165.3 142.8 L169.7 139.5 L174.2 136.4 L178.9 133.5 L183.8 130.7 L188.9 128.0 L194.2 125.5 L199.8 123.0 L205.5 120.7 L211.6 118.6 L217.9 116.5 L224.5 114.6 L231.4 112.8 L238.7 111.2 L246.4 109.6 L254.4 108.2 L263.0 106.9 L272.1 105.7 L281.8 104.6 L292.2 103.6 L303.5 102.8 L315.8 102.0 L329.5 101.4 L345.0 100.9 L363.1 100.5 L385.4 100.2 L416.0 100.1 L512.0 100.0 L608.0 100.1 L638.6 100.2 L660.9 100.5 L679.0 100.9 L694.5 101.4 L708.2 102.0 L720.5 102.8 L731.8 103.6 L742.2 104.6 L751.9 105.7 L761.0 106.9 L769.6 108.2 L777.6 109.6 L785.3 111.2 L792.6 112.8 L799.5 114.6 L806.1 116.5 L812.4 118.6 L818.5 120.7 L824.2 123.0 L829.8 125.5 L835.1 128.0 L840.2 130.7 L845.1 133.5 L849.8 136.4 L854.3 139.5 L858.7 142.8 L862.8 146.1 L866.8 149.7 L870.7 153.3 L874.3 157.2 L877.9 161.2 L881.2 165.3 L884.5 169.7 L887.6 174.2 L890.5 178.9 L893.3 183.8 L896.0 188.9 L898.5 194.2 L901.0 199.8 L903.3 205.5 L905.4 211.6 L907.5 217.9 L909.4 224.5 L911.2 231.4 L912.8 238.7 L914.4 246.4 L915.8 254.4 L917.1 263.0 L918.3 272.1 L919.4 281.8 L920.4 292.2 L921.2 303.5 L922.0 315.8 L922.6 329.5 L923.1 345.0 L923.5 363.1 L923.8 385.4 L923.9 416.0Z" fill="url(#sheen-d)"/>
14
+ <path d="M260 284H652A28 28 0 0 1 680 312V368A28 28 0 0 1 652 396H260A28 28 0 0 1 232 368V312A28 28 0 0 1 260 284Z" fill="url(#row-film)"/><path d="M260 284H652A28 28 0 0 1 680 312V368A28 28 0 0 1 652 396H260A28 28 0 0 1 232 368V312A28 28 0 0 1 260 284Z" fill="url(#sheen-row)"/><path d="M260 620H652A28 28 0 0 1 680 648V704A28 28 0 0 1 652 732H260A28 28 0 0 1 232 704V648A28 28 0 0 1 260 620Z" fill="url(#row-film)"/><path d="M260 620H652A28 28 0 0 1 680 648V704A28 28 0 0 1 652 732H260A28 28 0 0 1 232 704V648A28 28 0 0 1 260 620Z" fill="url(#sheen-row)"/><path d="M372 452H764A28 28 0 0 1 792 480V536A28 28 0 0 1 764 564H372A28 28 0 0 1 344 536V480A28 28 0 0 1 372 452Z" transform="translate(0 14)" fill="#000" opacity="0.6" filter="url(#b16)" /><path d="M372 452H764A28 28 0 0 1 792 480V536A28 28 0 0 1 764 564H372A28 28 0 0 1 344 536V480A28 28 0 0 1 372 452Z" fill="url(#or)" /><path d="M372 452H764A28 28 0 0 1 792 480V536A28 28 0 0 1 764 564H372A28 28 0 0 1 344 536V480A28 28 0 0 1 372 452Z" fill="url(#sheen-or)" /><path d="M372 453H764A27 27 0 0 1 791 480V536A27 27 0 0 1 764 563H372A27 27 0 0 1 345 536V480A27 27 0 0 1 372 453Z" fill="none" stroke="url(#or-edge)" stroke-width="2" />
15
+ <path d="M924.0 512.0 L923.9 608.0 L923.8 638.6 L923.5 660.9 L923.1 679.0 L922.6 694.5 L922.0 708.2 L921.2 720.5 L920.4 731.8 L919.4 742.2 L918.3 751.9 L917.1 761.0 L915.8 769.6 L914.4 777.6 L912.8 785.3 L911.2 792.6 L909.4 799.5 L907.5 806.1 L905.4 812.4 L903.3 818.5 L901.0 824.2 L898.5 829.8 L896.0 835.1 L893.3 840.2 L890.5 845.1 L887.6 849.8 L884.5 854.3 L881.2 858.7 L877.9 862.8 L874.3 866.8 L870.7 870.7 L866.8 874.3 L862.8 877.9 L858.7 881.2 L854.3 884.5 L849.8 887.6 L845.1 890.5 L840.2 893.3 L835.1 896.0 L829.8 898.5 L824.2 901.0 L818.5 903.3 L812.4 905.4 L806.1 907.5 L799.5 909.4 L792.6 911.2 L785.3 912.8 L777.6 914.4 L769.6 915.8 L761.0 917.1 L751.9 918.3 L742.2 919.4 L731.8 920.4 L720.5 921.2 L708.2 922.0 L694.5 922.6 L679.0 923.1 L660.9 923.5 L638.6 923.8 L608.0 923.9 L512.0 924.0 L416.0 923.9 L385.4 923.8 L363.1 923.5 L345.0 923.1 L329.5 922.6 L315.8 922.0 L303.5 921.2 L292.2 920.4 L281.8 919.4 L272.1 918.3 L263.0 917.1 L254.4 915.8 L246.4 914.4 L238.7 912.8 L231.4 911.2 L224.5 909.4 L217.9 907.5 L211.6 905.4 L205.5 903.3 L199.8 901.0 L194.2 898.5 L188.9 896.0 L183.8 893.3 L178.9 890.5 L174.2 887.6 L169.7 884.5 L165.3 881.2 L161.2 877.9 L157.2 874.3 L153.3 870.7 L149.7 866.8 L146.1 862.8 L142.8 858.7 L139.5 854.3 L136.4 849.8 L133.5 845.1 L130.7 840.2 L128.0 835.1 L125.5 829.8 L123.0 824.2 L120.7 818.5 L118.6 812.4 L116.5 806.1 L114.6 799.5 L112.8 792.6 L111.2 785.3 L109.6 777.6 L108.2 769.6 L106.9 761.0 L105.7 751.9 L104.6 742.2 L103.6 731.8 L102.8 720.5 L102.0 708.2 L101.4 694.5 L100.9 679.0 L100.5 660.9 L100.2 638.6 L100.1 608.0 L100.0 512.0 L100.1 416.0 L100.2 385.4 L100.5 363.1 L100.9 345.0 L101.4 329.5 L102.0 315.8 L102.8 303.5 L103.6 292.2 L104.6 281.8 L105.7 272.1 L106.9 263.0 L108.2 254.4 L109.6 246.4 L111.2 238.7 L112.8 231.4 L114.6 224.5 L116.5 217.9 L118.6 211.6 L120.7 205.5 L123.0 199.8 L125.5 194.2 L128.0 188.9 L130.7 183.8 L133.5 178.9 L136.4 174.2 L139.5 169.7 L142.8 165.3 L146.1 161.2 L149.7 157.2 L153.3 153.3 L157.2 149.7 L161.2 146.1 L165.3 142.8 L169.7 139.5 L174.2 136.4 L178.9 133.5 L183.8 130.7 L188.9 128.0 L194.2 125.5 L199.8 123.0 L205.5 120.7 L211.6 118.6 L217.9 116.5 L224.5 114.6 L231.4 112.8 L238.7 111.2 L246.4 109.6 L254.4 108.2 L263.0 106.9 L272.1 105.7 L281.8 104.6 L292.2 103.6 L303.5 102.8 L315.8 102.0 L329.5 101.4 L345.0 100.9 L363.1 100.5 L385.4 100.2 L416.0 100.1 L512.0 100.0 L608.0 100.1 L638.6 100.2 L660.9 100.5 L679.0 100.9 L694.5 101.4 L708.2 102.0 L720.5 102.8 L731.8 103.6 L742.2 104.6 L751.9 105.7 L761.0 106.9 L769.6 108.2 L777.6 109.6 L785.3 111.2 L792.6 112.8 L799.5 114.6 L806.1 116.5 L812.4 118.6 L818.5 120.7 L824.2 123.0 L829.8 125.5 L835.1 128.0 L840.2 130.7 L845.1 133.5 L849.8 136.4 L854.3 139.5 L858.7 142.8 L862.8 146.1 L866.8 149.7 L870.7 153.3 L874.3 157.2 L877.9 161.2 L881.2 165.3 L884.5 169.7 L887.6 174.2 L890.5 178.9 L893.3 183.8 L896.0 188.9 L898.5 194.2 L901.0 199.8 L903.3 205.5 L905.4 211.6 L907.5 217.9 L909.4 224.5 L911.2 231.4 L912.8 238.7 L914.4 246.4 L915.8 254.4 L917.1 263.0 L918.3 272.1 L919.4 281.8 L920.4 292.2 L921.2 303.5 L922.0 315.8 L922.6 329.5 L923.1 345.0 L923.5 363.1 L923.8 385.4 L923.9 416.0Z" fill="none" stroke="url(#edge-d)" stroke-width="6" clip-path="url(#tile-clip)"/></svg>