@clubs.place/cli 0.0.0-stage → 0.1.17

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 (70) hide show
  1. package/.env.example +88 -0
  2. package/LICENSE +21 -0
  3. package/PROVENANCE.json +77 -0
  4. package/README.md +70 -2
  5. package/bin/clubs-nippo +7 -0
  6. package/bin/clubs-nippo-web.mjs +338 -0
  7. package/bin/clubs-nippo.mjs +527 -0
  8. package/docs/events-schema.md +76 -0
  9. package/examples/hermes-events.sample.jsonl +8 -0
  10. package/package.json +48 -4
  11. package/src/aggregate.mjs +105 -0
  12. package/src/autorun.mjs +25 -0
  13. package/src/autorun.test.mjs +43 -0
  14. package/src/cards.mjs +406 -0
  15. package/src/collect.mjs +111 -0
  16. package/src/config.mjs +173 -0
  17. package/src/generators/claude.mjs +31 -0
  18. package/src/generators/cli.mjs +81 -0
  19. package/src/generators/codex.mjs +28 -0
  20. package/src/generators/copilot.mjs +21 -0
  21. package/src/generators/gemini.mjs +20 -0
  22. package/src/generators/openai-compat.mjs +79 -0
  23. package/src/generators/openrouter.mjs +65 -0
  24. package/src/history.mjs +66 -0
  25. package/src/ingest.mjs +78 -0
  26. package/src/lemma.docHash.test.mjs +37 -0
  27. package/src/lemma.mjs +303 -0
  28. package/src/mask.mjs +45 -0
  29. package/src/mcp.mjs +269 -0
  30. package/src/narrative.mjs +191 -0
  31. package/src/prompt.mjs +184 -0
  32. package/src/prompt.test.mjs +146 -0
  33. package/src/remote-config.mjs +72 -0
  34. package/src/render.mjs +467 -0
  35. package/src/send.mjs +36 -0
  36. package/src/settings.mjs +54 -0
  37. package/src/sources/claude-code.mjs +174 -0
  38. package/src/sources/codex-cli.mjs +182 -0
  39. package/src/sources/copilot-cli.mjs +125 -0
  40. package/src/sources/cowork.mjs +193 -0
  41. package/src/sources/events-file.mjs +120 -0
  42. package/src/sources/gemini-cli.mjs +128 -0
  43. package/src/sources/hermes.mjs +427 -0
  44. package/src/store.mjs +227 -0
  45. package/src/tasks.mjs +229 -0
  46. package/src/tool-name.mjs +28 -0
  47. package/templates/report-v3.reference.html +162 -0
  48. package/web/assets/logo-clubs-white.png +0 -0
  49. package/web/assets/logo-clubs-white.svg +7 -0
  50. package/web/assets/logo-clubs-white.svg.tmp +30 -0
  51. package/web/assets/logo-clubs.svg +30 -0
  52. package/web/assets/qr.js +411 -0
  53. package/web/assets/sidebar.js +154 -0
  54. package/web/assets/twemoji.js +34 -0
  55. package/web/cards/achievements.html +230 -0
  56. package/web/cards/catalog.json +217 -0
  57. package/web/email/hero-v3.reference.html +123 -0
  58. package/web/home/index.html +269 -0
  59. package/web/preview.json +301 -0
  60. package/web/qr-selftest.html +46 -0
  61. package/web/reports/edit.html +255 -0
  62. package/web/reports/edit.reference.html +257 -0
  63. package/web/reports/index.html +196 -0
  64. package/web/settings/index.html +219 -0
  65. package/web/share/cards-reference.html +228 -0
  66. package/web/share/passport.html +214 -0
  67. package/web/share/teianbako.html +177 -0
  68. package/web/signup/index.html +326 -0
  69. package/web/tasks/index.html +229 -0
  70. package/web/verify/index.html +248 -0
@@ -0,0 +1,154 @@
1
+ // clubs-nippo — AI業務日報 (CLUBS)
2
+ // Copyright (c) 2026 FRAME00 Inc.
3
+ // SPDX-License-Identifier: MIT
4
+ // https://github.com/frame00/clubs-nippo
5
+
6
+ /* CLUBS Console の共通サイドバー。
7
+ 3画面(日報一覧・日報編集・設定)から読む。ビルドは無し・依存も無し。
8
+ AI名は /api/settings の実データから入れる。固定値を出すと誰の日報か嘘になる。 */
9
+ const NAV_CSS = `.clubs-nav{
10
+ --side:#161A26; --side2:#1C2130; --side-text:#C7CBDB; --side-label:#7D8398;
11
+ --hl:#D2A64A; --hl-soft:rgba(210,166,74,.22);
12
+ --brand1:#4F6BF6; --brand2:#8B5CF6; --gold:#B7862B; --gold-t:#F7EFDD;
13
+ --body:'Inter','Noto Sans JP','Hiragino Sans','Yu Gothic',system-ui,sans-serif;
14
+ font-family:var(--body);
15
+ /* モックでは親の grid が幅を決めていたが、各ページは flex レイアウトなので
16
+ サイドバー自身が幅を持つ。持たないと内容なりに伸び縮みして崩れる。 */
17
+ width:244px; flex:none; box-sizing:border-box;
18
+ }
19
+ .clubs-nav *{box-sizing:border-box}
20
+
21
+ .clubs-nav{background:var(--side);color:var(--side-text);padding:16px 12px;position:sticky;top:0;height:100vh;display:flex;flex-direction:column;border-top:3px solid var(--hl)}
22
+ .clubs-nav .brand{display:flex;align-items:center;gap:9px;padding:4px 8px 14px}
23
+ .clubs-nav .brand .logo{display:flex;align-items:center}
24
+ .clubs-nav .brand .logo img{width:86px;height:20px;display:block}
25
+ .clubs-nav .brand .bn{font-weight:800;font-size:14px;color:#fff;letter-spacing:.01em;line-height:1.1}
26
+ .clubs-nav .brand .bs{font-size:8.5px;color:var(--side-label);letter-spacing:.04em}
27
+ .clubs-nav .who{display:flex;align-items:center;gap:10px;padding:10px 10px 12px;margin:2px 0 6px;background:var(--side2);border-radius:11px;border:1px solid rgba(210,166,74,.35)}
28
+ .clubs-nav .who .av{width:34px;height:34px;border-radius:9px;background:linear-gradient(160deg,#66B9D8,#3E93B5);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:800;font-size:15px;flex-shrink:0}
29
+ .clubs-nav .who .wn{color:#fff;font-weight:700;font-size:13px;line-height:1.2}
30
+ .clubs-nav .who .ws{color:var(--side-label);font-size:10px}
31
+ .clubs-nav .planbadge{display:inline-block;margin-top:3px;font-size:9px;font-weight:800;border-radius:999px;padding:1px 8px;background:var(--hl);color:#2A2008}
32
+ .clubs-nav .nav-sec{font-size:10px;text-transform:uppercase;letter-spacing:1px;color:var(--side-label);font-weight:700;padding:14px 10px 6px}
33
+ .clubs-nav a{display:flex;align-items:center;gap:11px;padding:9px 11px;border-radius:10px;text-decoration:none;color:var(--side-text);font-weight:600;font-size:13px;margin-bottom:2px}
34
+ .clubs-nav a.on{background:var(--hl-soft);color:#fff}
35
+ .clubs-nav a:hover{background:rgba(255,255,255,.06)}
36
+ .clubs-nav .ic{width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}
37
+ .clubs-nav .ic svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.5}
38
+ .clubs-nav .paidmark{margin-left:auto;font-size:8px;font-weight:800;background:var(--hl);color:#2A2008;border-radius:999px;padding:1px 6px}
39
+ /* まだ画面が無い項目。押せる見た目にすると、押しても何も起きないリンクになる。
40
+ この製品は「押せないものは押せないと見せる」で通してきたので、ここもそれに合わせる。 */
41
+ .clubs-nav .soon{display:flex;align-items:center;gap:11px;padding:9px 11px;border-radius:10px;color:var(--side-text);font-weight:600;font-size:13px;margin-bottom:2px;opacity:.45;cursor:default}
42
+ .clubs-nav .soon .ic{width:18px;height:18px;display:inline-flex;align-items:center;justify-content:center;flex-shrink:0}
43
+ .clubs-nav .soon .ic svg{width:18px;height:18px;stroke:currentColor;fill:none;stroke-width:1.5}
44
+ .clubs-nav .nav-spacer{flex:1}
45
+ .clubs-nav .upsell{background:var(--side2);border-radius:12px;padding:12px}
46
+ .clubs-nav .upsell .t{font-weight:700;font-size:12px;color:#fff}
47
+ .clubs-nav .upsell .s{font-size:10.5px;color:var(--side-label);margin:2px 0 8px}
48
+ .clubs-nav .upsell a{display:block;text-align:center;background:linear-gradient(135deg,var(--brand1),var(--brand2));color:#fff;border-radius:999px;padding:8px;font-weight:700;font-size:11.5px;text-decoration:none}
49
+ .clubs-nav .signout{font-size:11px;color:var(--side-label);text-align:center;padding:12px 0 2px;text-decoration:none;display:block}
50
+ .clubs-nav .hero .av{width:46px;height:46px;border-radius:13px;background:linear-gradient(160deg,#66B9D8,#3E93B5);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:800;font-size:19px}`;
51
+
52
+ const NAV_HTML = `<div class="brand">
53
+ <div class="logo"><img src="../assets/logo-clubs-white.svg" alt="CLUBS" style="width:86px;height:20px;display:block" /></div>
54
+ <div style="margin-top:1px"><div class="bs">あなたのAIのパスポート</div></div>
55
+ </div>
56
+ <div class="who">
57
+ <div class="av">H</div>
58
+ <div><div class="wn">Hermes</div><div class="ws">あなたのAI · 1体</div><span class="planbadge">個人プラン</span></div>
59
+ </div>
60
+
61
+ <div class="nav-sec">マイAI</div>
62
+ <a data-page="home" href="../home/"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="m2.25 12 8.954-8.955c.44-.439 1.152-.439 1.591 0L21.75 12M4.5 9.75v10.125c0 .621.504 1.125 1.125 1.125H9.75v-4.875c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21h4.125c.621 0 1.125-.504 1.125-1.125V9.75M8.25 21h8.25"/></svg></span>ホーム</a>
63
+ <a data-page="reports" href="../reports/"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M8.25 6.75h7.5M8.25 12h7.5m-7.5 5.25h4.5M4.5 3.75h15v16.5h-15z"/></svg></span>日報</a>
64
+ <a data-page="tasks" href="../tasks/"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M2.25 13.5h3.86a2.25 2.25 0 0 1 2.012 1.244l.256.512a2.25 2.25 0 0 0 2.013 1.244h3.218a2.25 2.25 0 0 0 2.013-1.244l.256-.512a2.25 2.25 0 0 1 2.013-1.244h3.859m-19.5.338V18a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18v-4.162c0-.224-.034-.447-.1-.661L19.24 5.338a2.25 2.25 0 0 0-2.15-1.588H6.911a2.25 2.25 0 0 0-2.15 1.588L2.35 13.177a2.25 2.25 0 0 0-.1.661Z"/></svg></span>AIから<span class="paidmark">PRO</span></a>
65
+ <a data-page="passport" href="../share/passport.html"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15 9h3.75M15 12h3.75M15 15h3.75M4.5 19.5h15a2.25 2.25 0 0 0 2.25-2.25V6.75A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25v10.5A2.25 2.25 0 0 0 4.5 19.5Zm6-10.125a1.875 1.875 0 1 1-3.75 0 1.875 1.875 0 0 1 3.75 0Zm1.294 6.336a5.98 5.98 0 0 0-6.338 0"/></svg></span>パスポート</a>
66
+ <a data-page="cards" href="../cards/achievements.html"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M16.5 18.75h-9m9 0a3 3 0 0 1 3 3h-15a3 3 0 0 1 3-3m9 0v-3.375c0-.621-.503-1.125-1.125-1.125h-.871M7.5 18.75v-3.375c0-.621.504-1.125 1.125-1.125h.872m5.007 0H9.497m5.007 0a7.454 7.454 0 0 1-.982-3.172M9.497 14.25a7.454 7.454 0 0 0 .981-3.172M5.25 4.236c-.982.143-1.954.317-2.916.52A6.003 6.003 0 0 0 7.73 9.728M5.25 4.236V4.5c0 2.108.966 3.99 2.48 5.228M5.25 4.236V2.721C7.456 2.41 9.71 2.25 12 2.25c2.291 0 4.545.16 6.75.47v1.516M7.73 9.728a6.726 6.726 0 0 0 2.748 1.35m8.272-6.842V4.5c0 2.108-.966 3.99-2.48 5.228m2.48-5.492a46.32 46.32 0 0 1 2.916.52 6.003 6.003 0 0 1-5.395 4.972m0 0a6.726 6.726 0 0 1-2.749 1.35m0 0a6.772 6.772 0 0 1-3.044 0"/></svg></span>実績</a>
67
+ <a data-page="verify" href="../verify/"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"/></svg></span>証明書</a>
68
+
69
+ <div class="nav-sec">共有・提出</div>
70
+ <span class="soon"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M6 12 3.269 3.125A59.769 59.769 0 0 1 21.485 12 59.768 59.768 0 0 1 3.27 20.875L5.999 12Zm0 0h7.5"/></svg></span>月次報告書<span class="paidmark">PRO</span></span>
71
+ <span class="soon"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 0 0 2.625.372 9.337 9.337 0 0 0 4.121-.952 4.125 4.125 0 0 0-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 0 1 8.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0 1 11.964-3.07M12 6.375a3.375 3.375 0 1 1-6.75 0 3.375 3.375 0 0 1 6.75 0Zm8.25 2.25a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Z"/></svg></span>クライアント共有<span class="paidmark">PRO</span></span>
72
+
73
+ <div class="nav-sec">設定</div>
74
+ <span class="soon"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M13.19 8.688a4.5 4.5 0 0 1 1.242 7.244l-4.5 4.5a4.5 4.5 0 0 1-6.364-6.364l1.757-1.757m13.35-.622 1.757-1.757a4.5 4.5 0 0 0-6.364-6.364l-4.5 4.5a4.5 4.5 0 0 0 1.242 7.244"/></svg></span>接続</span>
75
+ <span class="soon"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M3 16.5v2.25A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75V16.5M16.5 12 12 16.5m0 0L7.5 12m4.5 4.5V3"/></svg></span>データ(エクスポート)</span>
76
+ <span class="soon"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M2.25 8.25h19.5M2.25 9h19.5m-16.5 5.25h6m-6 2.25h3m-3.75 3h15a2.25 2.25 0 0 0 2.25-2.25V6.75A2.25 2.25 0 0 0 19.5 4.5h-15a2.25 2.25 0 0 0-2.25 2.25v10.5A2.25 2.25 0 0 0 4.5 19.5Z"/></svg></span>お支払い・請求</span>
77
+ <a data-page="settings" href="../settings/"><span class="ic"><svg viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.325.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 0 1 1.37.49l1.296 2.247a1.125 1.125 0 0 1-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 0 1 0 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 0 1-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 0 1-.22.128c-.331.183-.581.495-.644.869l-.213 1.281c-.09.543-.56.94-1.11.94h-2.594c-.55 0-1.019-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 0 1-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 0 1-1.369-.49l-1.297-2.247a1.125 1.125 0 0 1 .26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 0 1 0-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 0 1-.26-1.43l1.297-2.247a1.125 1.125 0 0 1 1.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.086.22-.128.332-.183.582-.495.644-.869l.214-1.28Z"/><path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z"/></svg></span>設定・通知</a>
78
+
79
+ <div class="nav-spacer"></div>
80
+ <div class="upsell">
81
+ <div class="t">2体目を足す?</div>
82
+ <div class="s">複数のAIはクラブで。席 ¥5,000/体・月〜</div>
83
+ <a href="#">クラブをはじめる</a>
84
+ </div>
85
+ <a class="signout" href="#">サインアウト</a>`;
86
+
87
+ export async function mountSidebar(activePage) {
88
+ const style = document.createElement("style");
89
+ style.textContent = NAV_CSS;
90
+ document.head.appendChild(style);
91
+
92
+ const aside = document.createElement("aside");
93
+ aside.className = "clubs-nav";
94
+ aside.innerHTML = NAV_HTML;
95
+
96
+ const old = document.querySelector("aside");
97
+ if (old) old.replaceWith(aside);
98
+ else document.body.prepend(aside);
99
+
100
+ const active = aside.querySelector(`[data-page="${activePage}"]`);
101
+ if (active) active.classList.add("on");
102
+
103
+ // 表示名は実データから。API → preview.json(実データのスナップショット)の順。
104
+ // どちらも取れなければ伏せる。NAV_HTML に焼いてある "Hermes" は見本なので、
105
+ // そのまま出すと共有URLに他人の名前が出る(実際にそうなっていた)。
106
+ const fill = (s) => {
107
+ aside.querySelector(".wn").textContent = s?.displayName ?? "—";
108
+ aside.querySelector(".av").textContent = [...(s?.agentName ?? "?")][0];
109
+ aside.querySelector(".ws").textContent = s
110
+ ? `あなたのAI · ${s.sources?.length ?? 1}面`
111
+ : "データに繋がっていません";
112
+ };
113
+
114
+ /* 「証明書」は特定の1件を見るページ。/verify/ を素で開くと「記録が見つかりません」に着地する。
115
+ なので最新の登録済み日報の docHash に繋ぐ。1件も無いときはリンクにしない
116
+ ——押せるのに壊れたページへ飛ぶリンクを、この製品は置かない。 */
117
+ const linkVerify = (reports) => {
118
+ const a = aside.querySelector('[data-page="verify"]');
119
+ if (!a) return;
120
+ const hash = (reports ?? []).find((r) => r.docHash)?.docHash;
121
+ if (hash) {
122
+ a.href = `../verify/?doc=${encodeURIComponent(hash)}`;
123
+ return;
124
+ }
125
+ a.removeAttribute("href");
126
+ a.classList.add("soon");
127
+ a.title = "まだ記録された証明書がありません";
128
+ };
129
+
130
+ const apply = (settings, reports) => {
131
+ fill(settings);
132
+ linkVerify(reports);
133
+ };
134
+
135
+ try {
136
+ const [s, r] = await Promise.all([fetch("/api/settings"), fetch("/api/reports")]);
137
+ if (s.ok && r.ok) return apply(await s.json(), (await r.json()).reports);
138
+ } catch {
139
+ /* 次を試す */
140
+ }
141
+
142
+ try {
143
+ const r = await fetch("../preview.json");
144
+ if (r.ok) {
145
+ const snap = await r.json();
146
+ return apply(snap.settings, snap.reports);
147
+ }
148
+ } catch {
149
+ /* 次を試す */
150
+ }
151
+
152
+ // 何も取れなければ伏せる。分からない名前を出さない。
153
+ apply(null, []);
154
+ }
@@ -0,0 +1,34 @@
1
+ // clubs-nippo — AI業務日報 (CLUBS)
2
+ // Copyright (c) 2026 FRAME00 Inc.
3
+ // SPDX-License-Identifier: MIT
4
+ // https://github.com/frame00/clubs-nippo
5
+
6
+ /**
7
+ * カードの主アイコン(Twemoji・インライン SVG)。
8
+ *
9
+ * 素の絵文字は端末で字形が変わり、印刷でも崩れる。外部 CDN の img は 404 で消える。
10
+ * だから SVG をこのファイルに焼き込む。Web・印刷・OGP すべて同じ絵になる。
11
+ *
12
+ * ライセンス: Twemoji graphics © Twitter, Inc and other contributors.
13
+ * Licensed under CC-BY 4.0 (https://creativecommons.org/licenses/by/4.0/).
14
+ * https://github.com/jdecked/twemoji
15
+ *
16
+ * 割り当ての根拠は docs/card-catalog.md §5。
17
+ */
18
+ export const TWEMOJI = {
19
+ "zero_dt": "<svg viewBox=\"0 0 36 36\"><path fill=\"#CCD6DD\" d=\"M33 3c-7-3-15-3-15-3S10 0 3 3C0 18 3 31 18 36c15-5 18-18 15-33z\"/><path fill=\"#55ACEE\" d=\"M18 33.884C6.412 29.729 1.961 19.831 4.76 4.444 11.063 2.029 17.928 2 18 2c.071 0 6.958.04 13.24 2.444 2.799 15.387-1.652 25.285-13.24 29.44z\"/><path fill=\"#269\" d=\"M31.24 4.444C24.958 2.04 18.071 2 18 2v31.884c11.588-4.155 16.039-14.053 13.24-29.44z\"/></svg>",
20
+ "iron": "<svg viewBox=\"0 0 36 36\"><path fill=\"#C1694F\" d=\"M35.627 10.826.373 16.56v9.722h.004c-.012.149.129.295.443.473.727.412 9.835 5.286 10.553 5.639.895.439 1.441.493 2.206.112.626-.312 19.236-10.173 20.932-11.074.863-.459 1.146-.711 1.099-.919h.018v-9.687z\"/><path fill=\"#A0041E\" d=\"M.373 16.56v9.722h.004c-.012.149.129.295.443.473.727.412 9.835 5.286 10.553 5.639.432.212.781.329 1.114.356V16.56H.373z\"/><path fill=\"#D99E82\" d=\"M22.224 4.682c1.076-.558 1.113-.628 2.249-.024 1.136.604 9.846 5.248 10.487 5.589.814.434 1.112.591-.449 1.421-1.696.902-20.306 10.763-20.932 11.074-.765.381-1.311.327-2.206-.112-.718-.352-9.826-5.226-10.553-5.639-.82-.465-.482-.706.769-1.37L22.224 4.682z\"/><ellipse cx=\"11.189\" cy=\"17.191\" fill=\"#C1694F\" rx=\"3.679\" ry=\"1.84\"/><path fill=\"#A0041E\" d=\"M11.642 16.734c-1.569-.516-3.352-.369-4.108.339-.005.04-.024.078-.024.118 0 1.016 1.647 1.84 3.679 1.84 1.063 0 2.013-.229 2.684-.589-.333-.692-1.086-1.332-2.231-1.708z\"/><ellipse cx=\"18\" cy=\"13.639\" fill=\"#C1694F\" rx=\"3.679\" ry=\"1.84\"/><path fill=\"#A0041E\" d=\"M18.453 13.182c-1.569-.516-3.352-.369-4.108.339-.005.04-.024.078-.024.118 0 1.016 1.647 1.84 3.679 1.84 1.063 0 2.013-.229 2.684-.589-.333-.692-1.086-1.332-2.231-1.708z\"/><ellipse cx=\"24.811\" cy=\"10.087\" fill=\"#C1694F\" rx=\"3.679\" ry=\"1.84\"/><path fill=\"#A0041E\" d=\"M25.264 9.63c-1.569-.516-3.352-.369-4.108.339-.005.04-.024.078-.024.118 0 1.016 1.647 1.84 3.679 1.84 1.063 0 2.012-.229 2.684-.589-.333-.692-1.086-1.332-2.231-1.708z\"/></svg>",
21
+ "comeback": "<svg viewBox=\"0 0 36 36\"><path fill=\"#3B88C3\" d=\"M36 32a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V4a4 4 0 0 1 4-4h28a4 4 0 0 1 4 4v28z\"/><path fill=\"#FFF\" d=\"M30.2 10 23 4v4h-8C9.477 8 5 12.477 5 18c0 1.414.297 2.758.827 3.978l3.3-2.75A6 6 0 0 1 15 12h8v4l7.2-6zm-.026 4.023-3.301 2.75A6 6 0 0 1 21 24h-8v-4l-7.2 6 7.2 6v-4h8c5.522 0 10-4.478 10-10a9.965 9.965 0 0 0-.826-3.977z\"/></svg>",
22
+ "clean": "<svg viewBox=\"0 0 36 36\"><path fill=\"#E1E8ED\" d=\"m32.415 9.586-9-9a2.001 2.001 0 0 0-2.829 2.829l-3.859 3.859 9 9 3.859-3.859a2 2 0 0 0 2.829-2.829z\"/><path fill=\"#CCD6DD\" d=\"M22 0H7a4 4 0 0 0-4 4v28a4 4 0 0 0 4 4h22a4 4 0 0 0 4-4V11h-9c-1 0-2-1-2-2V0z\"/><path fill=\"#99AAB5\" d=\"M22 0h-2v9a4 4 0 0 0 4 4h9v-2h-9c-1 0-2-1-2-2V0zm-5 8a1 1 0 0 1-1 1H8a1 1 0 0 1 0-2h8a1 1 0 0 1 1 1zm0 4a1 1 0 0 1-1 1H8a1 1 0 0 1 0-2h8a1 1 0 0 1 1 1zm12 4a1 1 0 0 1-1 1H8a1 1 0 0 1 0-2h20a1 1 0 0 1 1 1zm0 4a1 1 0 0 1-1 1H8a1 1 0 1 1 0-2h20a1 1 0 0 1 1 1zm0 4a1 1 0 0 1-1 1H8a1 1 0 1 1 0-2h20a1 1 0 0 1 1 1zm0 4a1 1 0 0 1-1 1H8a1 1 0 1 1 0-2h20a1 1 0 0 1 1 1z\"/></svg>",
23
+ "precision": "<svg viewBox=\"0 0 36 36\"><path fill=\"#CCD6DD\" d=\"M3 16v-2h30v2zm0 7v-2h30v2zm0 7v-2h30v2zM3 9V7h30v2z\"/><path fill=\"#D5AB88\" d=\"M35 33V1a1 1 0 0 0-1-1h-1a1 1 0 0 0-1 1H4a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v32h34zM4 4h28v29H4V4z\"/><path fill=\"#3B94D9\" d=\"M19 5.5A1.5 1.5 0 0 0 17.5 7a1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0v2a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0V7A1.5 1.5 0 0 0 19 5.5z\"/><path fill=\"#BE1931\" d=\"M19 12.5a1.5 1.5 0 0 0-1.5 1.5 1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0v2a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0v-2a1.5 1.5 0 0 0-1.5-1.5z\"/><path fill=\"#5C913B\" d=\"M19 19.5a1.5 1.5 0 0 0-1.5 1.5 1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0v2a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0v-2a1.5 1.5 0 0 0-1.5-1.5z\"/><path fill=\"#FFAC33\" d=\"M19 26.5a1.5 1.5 0 0 0-1.5 1.5 1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0 1.5 1.5 0 1 0-3 0v2a1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0 1.5 1.5 0 1 0 3 0v-2a1.5 1.5 0 0 0-1.5-1.5z\"/><path fill=\"#3B94D9\" d=\"M29 10.5A1.5 1.5 0 0 1 27.5 9V7a1.5 1.5 0 1 1 3 0v2a1.5 1.5 0 0 1-1.5 1.5z\"/><path fill=\"#BE1931\" d=\"M29 17.5a1.5 1.5 0 0 1-1.5-1.5v-2a1.5 1.5 0 1 1 3 0v2a1.5 1.5 0 0 1-1.5 1.5z\"/><path fill=\"#5C913B\" d=\"M29 24.5a1.5 1.5 0 0 1-1.5-1.5v-2a1.5 1.5 0 0 1 3 0v2a1.5 1.5 0 0 1-1.5 1.5z\"/><path fill=\"#FFAC33\" d=\"M29 31.5a1.5 1.5 0 0 1-1.5-1.5v-2a1.5 1.5 0 0 1 3 0v2a1.5 1.5 0 0 1-1.5 1.5z\"/><path fill=\"#BF6952\" d=\"M35 33H1a1 1 0 0 0-1 1v1a1 1 0 0 0 1 1h34a1 1 0 0 0 1-1v-1a1 1 0 0 0-1-1z\"/></svg>",
24
+ "owl": "<svg viewBox=\"0 0 36 36\"><path fill=\"#662113\" d=\"M7.317 11c-5.723 9.083.958 18 .958 18s2.874-.442 6.875-5.2c4-4.758-7.833-12.8-7.833-12.8zm21.342 0c5.723 9.083-.958 18-.958 18s-2.874-.442-6.875-5.2C16.825 19.042 28.659 11 28.659 11z\"/><path fill=\"#FFAC33\" d=\"M15.203 31.557a1.22 1.22 0 0 0-.531-.496c-2.032-2.172-.589-4.717-.589-4.717 0-.703 1.271-2.544 0-2.544l-1.272 1.272c-1.272 1.271-1.272 5.089-1.272 5.089H8.995a1.27 1.27 0 1 0 0 2.543h1.408l-.282.153a1.274 1.274 0 0 0 1.21 2.24l3.357-1.816a1.274 1.274 0 0 0 .515-1.724zm5.596 0c.123-.229.317-.384.53-.496 2.033-2.172.589-4.717.589-4.717 0-.703-1.271-2.544 0-2.544l1.272 1.272c1.273 1.271 1.273 5.089 1.273 5.089h2.544a1.27 1.27 0 0 1 1.271 1.272 1.27 1.27 0 0 1-1.271 1.271h-1.408l.281.153a1.273 1.273 0 1 1-1.211 2.24l-3.356-1.816a1.272 1.272 0 0 1-.514-1.724z\"/><path fill=\"#662113\" d=\"M28.278 11.292c2.891-6.092 0-10.542 0-10.542s-5.781.959-6.744 2.875c-1.219 2.424 6.744 7.667 6.744 7.667z\"/><path fill=\"#662113\" d=\"M29.562 12.738c0 10.297-3.152 20.595-11.562 20.595-8.409 0-11.563-10.298-11.563-20.595C6.437 2.44 11.614 2.083 18 2.083c6.387 0 11.562.357 11.562 10.655z\"/><path fill=\"#C1694F\" d=\"M27.666 17.738c0 10.297-7.774 14.595-9.666 14.595s-9.666-4.298-9.666-14.595c0-10.298 19.332-10.298 19.332 0z\"/><path fill=\"#662113\" d=\"M7.722 11.292C4.831 5.2 7.722.75 7.722.75s5.782.959 6.746 2.875c1.218 2.424-6.746 7.667-6.746 7.667z\"/><path fill=\"#C1694F\" d=\"M14.929 4.373C10.702 2.789 7.722.75 7.722.75s-2.076 3.221-.928 7.926c.446 2.137 1.94 4.195 3.904 4.662 2.637.627 7.302-.049 7.302-3.963 0-2.695-1.074-4.252-3.071-5.002zm6.142 0C25.298 2.789 28.277.75 28.277.75s2.076 3.221.928 7.926c-.445 2.137-1.939 4.195-3.902 4.662-2.638.627-7.303-.049-7.303-3.963 0-2.695 1.074-4.252 3.071-5.002z\"/><path fill=\"#FFD983\" d=\"M16.083 8.417a3.833 3.833 0 1 1-7.666 0 3.833 3.833 0 0 1 7.666 0zm11.5 0a3.833 3.833 0 1 1-7.666 0 3.833 3.833 0 0 1 7.666 0z\"/><path fill=\"#292F33\" d=\"M14.167 8.417a1.917 1.917 0 1 1-3.833 0 1.917 1.917 0 0 1 3.833 0zm11.5 0a1.917 1.917 0 1 1-3.833 0 1.917 1.917 0 0 1 3.833 0z\"/><path fill=\"#FFCC4D\" d=\"M20.875 12.729c0 2.382-2.875 3.354-2.875 3.354s-2.875-.973-2.875-3.354S18 9.375 18 9.375s2.875.972 2.875 3.354z\"/><path fill=\"#F4900C\" d=\"M20.875 12.729c0 2.382-2.875 3.354-2.875 3.354s-2.875-.973-2.875-3.354C16.323 13.927 18 14.167 18 14.167s1.677-.24 2.875-1.438z\"/></svg>",
25
+ "cleaner": "<svg viewBox=\"0 0 36 36\"><path fill=\"#C1694F\" d=\"M19.175 16.825a1.82 1.82 0 0 1 0-2.567L32.433 1A1.82 1.82 0 0 1 35 1a1.82 1.82 0 0 1 0 2.567L21.742 16.825a1.82 1.82 0 0 1-2.567 0z\"/><path fill=\"#66757F\" d=\"m8.839 27.365-.204-.204a2.425 2.425 0 0 1 0-3.42l8.35-8.35a2.425 2.425 0 0 1 3.42 0l.204.204c.941.941.941 2.48 0 3.42l-8.35 8.35c-.94.941-2.48.941-3.42 0z\"/><path fill=\"#FFCC4D\" d=\"M19.389 26.341c1.688-1.688.671-5.441-1.809-7.921s-6.233-3.497-7.921-1.809L0 26.16 9.84 36l9.549-9.659z\"/><path fill=\"#FFAC33\" d=\"m2.02 28.18 8.66-8.658.58.58L2.6 28.76zm1.74 1.74 8.66-8.659.58.58-8.66 8.66zm1.74 1.74L14.158 23l.58.58-8.66 8.66zm1.74 1.74 8.659-8.66.58.58-8.66 8.659z\"/><path fill=\"#55ACEE\" d=\"M9.875 16.43c-.073.059-.149.114-.216.181L7.46 18.779l9.761 9.761 2.167-2.199c.067-.067.123-.143.181-.216L9.875 16.43z\"/><path fill=\"#269\" d=\"m8.882 18.221.235-.568 9.225 9.224-.572.232z\"/></svg>",
26
+ "scout": "<svg viewBox=\"0 0 36 36\"><path fill=\"#9AAAB4\" d=\"M27.388 24.642 24.56 27.47l-4.95-4.95 2.828-2.828z\"/><path fill=\"#66757F\" d=\"m34.683 29.11-5.879-5.879a2 2 0 0 0-2.828 0l-2.828 2.828a2 2 0 0 0 0 2.828l5.879 5.879a4 4 0 1 0 5.656-5.656z\"/><circle cx=\"13.586\" cy=\"13.669\" r=\"13.5\" fill=\"#8899A6\"/><circle cx=\"13.586\" cy=\"13.669\" r=\"9.5\" fill=\"#BBDDF5\"/></svg>",
27
+ "night3": "<svg viewBox=\"0 0 36 36\"><path fill=\"#FFD983\" d=\"M30.312.776C32 19 20 32 .776 30.312c8.199 7.717 21.091 7.588 29.107-.429C37.9 21.867 38.03 8.975 30.312.776z\"/><path fill=\"#FFCC4D\" d=\"M30.705 15.915a1.163 1.163 0 1 0 1.643 1.641 1.163 1.163 0 0 0-1.643-1.641zm-16.022 14.38a1.74 1.74 0 0 0 0 2.465 1.742 1.742 0 1 0 0-2.465zm13.968-2.147a2.904 2.904 0 0 1-4.108 0 2.902 2.902 0 0 1 0-4.107 2.902 2.902 0 0 1 4.108 0 2.902 2.902 0 0 1 0 4.107z\"/></svg>",
28
+ "onetrick": "<svg viewBox=\"0 0 36 36\"><path fill=\"#DD2E44\" d=\"M33 33a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2l1-12h28l1 12z\"/><path fill=\"#EA596E\" d=\"M13 35c-.792-1.875-1.75-3.291-3.417-4.666 1.75-1.459 4.542-5.5 5.25-8.292s2.75 8.125 2.042 10.625S13 35 13 35zm10.303 0c.791-1.875 1.75-3.291 3.416-4.666-1.75-1.459-4.541-5.5-5.25-8.292-.707-2.792-2.75 8.125-2.04 10.625.708 2.5 3.874 2.333 3.874 2.333z\"/><path fill=\"#BE1931\" d=\"M3.728 24.263A2.5 2.5 0 0 0 8 22.5c0-.565-.195-1.081-.511-1.5H4l-.272 3.263zm28.544 0L32 21h-3.489A2.482 2.482 0 0 0 28 22.5a2.5 2.5 0 0 0 4.272 1.763z\"/><circle cx=\"14\" cy=\"23\" r=\"2\" fill=\"#BE1931\"/><circle cx=\"22\" cy=\"23\" r=\"2\" fill=\"#BE1931\"/><circle cx=\"10\" cy=\"23\" r=\"2\" fill=\"#BE1931\"/><circle cx=\"26\" cy=\"23\" r=\"2\" fill=\"#BE1931\"/><path d=\"M23 35H13s2-6 2-13h6c0 7 2 13 2 13zM17 2h2v7h-2z\"/><path fill=\"#55ACEE\" d=\"M18.838.206C17.667.042 17 .318 17 1.418v1c0 1.1.865 1.753 1.923 1.451l5.154-.901c1.715-.343 1.548-1.593.085-1.884L18.838.206z\"/><path fill=\"#CCD6DD\" d=\"m18 6-.081.123C10.938 16.981 3 15.015 3 19v2.5a2.5 2.5 0 0 0 4.95.5H12a2 2 0 0 0 4 0h4a2 2 0 0 0 4 0h4.05a2.5 2.5 0 0 0 4.95-.5V19c0-4-8-2-15-13z\"/><g fill=\"#F5F8FA\"><path d=\"m17.948 6.078-.03.045C17.132 11.619 10.811 16.126 8 18v4a2 2 0 0 0 4 0v-4c.982-.982 5.813-6.787 5.984-11.732-.01-.064-.027-.126-.036-.19zm.08.398C18.324 11.374 23.031 17.031 24 18v4a2 2 0 0 0 4 0v-4c-2.75-1.833-8.953-6.19-9.972-11.524z\"/><path d=\"M17.984 6.27C17.922 8.346 17.606 16.394 16 18v4a2 2 0 0 0 4 0v-4c-1.564-1.564-1.905-9.241-1.979-11.559-.011-.057-.027-.113-.037-.171z\"/></g></svg>",
29
+ "twoface": "<svg viewBox=\"0 0 36 36\"><path fill=\"#A6D388\" d=\"M22 4.587c0 6.075-3.667 18.333-11 18.333S0 10.663 0 4.587C0-2.593 8.25.92 11 .92c2.712 0 11-3.551 11 3.667z\"/><path fill=\"#5C913B\" d=\"M5.5 11.92c4.583 2.75 7.333 2.75 11 0 2.75-1.833-1.833 6.417-5.5 6.417s-8.25-8.25-5.5-6.417zM3.666 8.254a.917.917 0 0 1-.819-1.327c.636-1.272 1.933-2.15 3.303-2.235.839-.047 2.458.155 3.779 2.137a.917.917 0 0 1-1.525 1.017c-.61-.915-1.355-1.374-2.14-1.324-.73.045-1.428.526-1.777 1.226a.92.92 0 0 1-.821.506zm14.668 0a.916.916 0 0 1-.82-.507c-.35-.699-1.047-1.18-1.777-1.226-.776-.042-1.529.409-2.14 1.324a.916.916 0 1 1-1.525-1.017c1.32-1.983 2.931-2.186 3.779-2.137 1.37.085 2.667.963 3.303 2.235a.916.916 0 0 1-.82 1.328z\"/><path fill=\"#CBB7EA\" d=\"M36 17.667C36 23.741 32.333 36 25 36S14 23.741 14 17.667C14 10.486 22.25 14 25 14c2.713 0 11-3.552 11 3.667z\"/><path fill=\"#9266CC\" d=\"M29.5 30.151C26 28 24 28 20.5 30.151c-2.75 1.833.833-4.417 4.5-4.417s7.25 6.25 4.5 4.417zM17 21.917a.917.917 0 0 1-.82-1.327c.7-1.399 2.404-2.49 4.051-2.592 1.489-.099 2.815.585 3.698 1.911a.918.918 0 0 1-1.525 1.018c-.522-.782-1.215-1.148-2.059-1.099-1.121.069-2.164.859-2.526 1.583a.916.916 0 0 1-.819.506zm16.001 0a.916.916 0 0 1-.821-.508c-.36-.723-1.403-1.512-2.524-1.582-.842-.047-1.539.316-2.06 1.099a.917.917 0 1 1-1.525-1.018c.884-1.326 2.188-2.009 3.699-1.911 1.648.103 3.352 1.194 4.051 2.593a.916.916 0 0 1-.82 1.327z\"/></svg>",
30
+ "first_shot": "<svg viewBox=\"0 0 36 36\"><circle fill=\"#DD2E44\" cx=\"18\" cy=\"18\" r=\"18\"/><circle fill=\"#FFF\" cx=\"18\" cy=\"18\" r=\"13.5\"/><circle fill=\"#DD2E44\" cx=\"18\" cy=\"18\" r=\"10\"/><circle fill=\"#FFF\" cx=\"18\" cy=\"18\" r=\"6\"/><circle fill=\"#DD2E44\" cx=\"18\" cy=\"18\" r=\"3\"/><path opacity=\".2\" d=\"M18.24 18.282l13.144 11.754s-2.647 3.376-7.89 5.109L17.579 18.42l.661-.138z\"/><path fill=\"#FFAC33\" d=\"M18.294 19c-.255 0-.509-.097-.704-.292-.389-.389-.389-1.018 0-1.407l.563-.563c.389-.389 1.018-.389 1.408 0 .388.389.388 1.018 0 1.407l-.564.563c-.194.195-.448.292-.703.292z\"/><path fill=\"#55ACEE\" d=\"M24.016 6.981c-.403 2.079 0 4.691 0 4.691l7.054-7.388c.291-1.454-.528-3.932-1.718-4.238-1.19-.306-4.079.803-5.336 6.935zm5.003 5.003c-2.079.403-4.691 0-4.691 0l7.388-7.054c1.454-.291 3.932.528 4.238 1.718.306 1.19-.803 4.079-6.935 5.336z\"/><path fill=\"#3A87C2\" d=\"M32.798 4.485L21.176 17.587c-.362.362-1.673.882-2.51.046-.836-.836-.419-2.08-.057-2.443L31.815 3.501s.676-.635 1.159-.152-.176 1.136-.176 1.136z\"/></svg>",
31
+ "grit": "<svg viewBox=\"0 0 36 36\"><path fill=\"#EF9645\" d=\"M15.977 9.36h3.789c.114-.191.147-.439.058-.673l-3.846-4.705V9.36z\"/><path fill=\"#FFDC5D\" d=\"M12.804 22.277c-.057-.349-.124-.679-.206-.973-.62-2.223-1.14-3.164-.918-5.494.29-1.584.273-4.763 4.483-4.268 1.112.131 2.843.927 3.834.91.567-.01.98-1.157 1.017-1.539.051-.526-.865-1.42-1.248-1.554-.383-.134-2.012-.631-2.681-.824-1.039-.301-.985-1.705-1.051-2.205-.031-.235.084-.467.294-.591.21-.124.375-.008.579.125l.885.648c.497.426-.874 1.24-.503 1.376 0 0 1.755.659 2.507.796.412.075 1.834-1.529 1.917-2.47.065-.74-3.398-4.083-5.867-5.381-.868-.456-1.377-.721-1.949-.694-.683.032-.898.302-1.748 1.03C8.302 4.46 4.568 11.577 4.02 13.152c-2.246 6.461-2.597 9.865-2.677 11.788-.049.59-.076 1.177-.076 1.758.065 0-1 5 0 6s5.326 1 5.326 1c10 3.989 28.57 2.948 28.57-7.233 0-12.172-18.813-10.557-22.359-4.188z\"/><path fill=\"#EF9645\" d=\"M20.63 32.078c-3.16-.332-5.628-1.881-5.767-1.97-.465-.297-.601-.913-.305-1.379s.913-.603 1.38-.308c.04.025 4.003 2.492 7.846 1.467 2.125-.566 3.867-2.115 5.177-4.601.258-.49.866-.676 1.351-.419.488.257.676.862.419 1.351-1.585 3.006-3.754 4.893-6.447 5.606-1.257.332-2.502.374-3.654.253z\"/></svg>",
32
+ "builder": "<svg viewBox=\"0 0 36 36\"><path fill=\"#66757F\" d=\"M28.25 8.513c0-.145-.117-.263-.263-.263h-.475c-.145 0-.263.118-.263.263v11.475c0 .145.117.263.263.263h.475c.145 0 .263-.117.263-.263V8.513z\"/><g fill=\"#F19020\"><circle cx=\"27.75\" cy=\"19.75\" r=\"1.5\"/><circle cx=\"27.75\" cy=\"22.25\" r=\"1\"/></g><path fill=\"#BD2032\" d=\"M33.25 8.25h-4.129L9.946.29 9.944.289h-.001c-.016-.007-.032-.005-.047-.01C9.849.265 9.802.25 9.75.25h-.002c-.066 0-.13.014-.19.038-.045.02-.084.05-.122.082-.012.009-.026.014-.037.025-.047.046-.085.102-.11.164V.56c-.004.009-.003.02-.006.029l-5.541 7.81c-.003.004-.003.01-.006.014-.285.176-.486.477-.486.837v2c0 .552.448 1 1 1h1.495L2.031 34H.25v2h18.958v-2h-1.74l-3.713-21.75H33.25c.553 0 1-.448 1-1v-2c0-.552-.447-1-1-1zm-21.769 4L9.75 13.639 8.02 12.25h3.461zM9.75 21.3l3.667 2.404-3.667 2-3.667-2L9.75 21.3zm-3.639.71l.474-2.784 1.866 1.223-2.34 1.561zm4.938-1.561l1.87-1.225.477 2.789-2.347-1.564zm-1.299-.866l-2.828-1.885 2.828-2.322 2.828 2.322-2.828 1.885zm-2.563-3.887l.362-2.127 1.131.928-1.493 1.199zm3.633-1.198l1.132-.929.364 2.13-1.496-1.201zM5.073 8.25L9.25 2.362V6.25h-2c-.552 0-1 .448-1 1v1H5.073zm.53 16.738l2.73 1.489-3.29 1.794.56-3.283zM15.443 34H4.067l.686-4.024L9.75 27.25l5.006 2.731.687 4.019zm-1.54-9.015l.562 3.291-3.298-1.799 2.736-1.492zM13.25 8.25v-1c0-.552-.448-1-1-1h-2V1.499L26.513 8.25H13.25zm2 3h-1.16v-2h1.16v2zm3 0h-2v-2h2v2zm3 0h-2v-2h2v2zm3 0h-2v-2h2v2zm3 0h-2v-2h2v2zm3 0h-2v-2h2v2zm3-.5c0 .276-.224.5-.5.5h-1.5v-2h1.5c.276 0 .5.224.5.5v1z\"/><path fill=\"#4B545D\" d=\"M12.25 7.25h-2c-.552 0-1 .448-1 1v2c0 .552.448 1 1 1h3v-4h-1z\"/><path fill=\"#CDD7DF\" d=\"M11.25 7.25h2v4h-2z\"/><path fill=\"#66757F\" d=\"M34.844 24v-1H20.656v1h.844v2.469h-.844v1h14.188v-1H34V24z\"/></svg>",
33
+ "ballot": "<svg viewBox=\"0 0 36 36\"><path fill=\"#8CCAF7\" d=\"M34.5 24.995c0 2.209-1.791 2-4 2h-25c-2.209 0-4 .209-4-2L3.5 11c.293-1.75 1-2 2-2h25c1 0 1.791.208 2 2l2 13.995z\"/><path fill=\"#292F33\" d=\"M28.5 16.5A1.5 1.5 0 0 1 27 18H9a1.5 1.5 0 1 1 0-3h18a1.5 1.5 0 0 1 1.5 1.5z\"/><path fill=\"#FFD983\" d=\"M26.25 17.188v-14a2 2 0 0 0-2-2h-13a2 2 0 0 0-2 2v14h17z\"/><path fill=\"#5DADEC\" d=\"M34.5 25a2 2 0 0 0-2-2h-29a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h29a2 2 0 0 0 2-2v-8z\"/><path fill=\"#4289C1\" d=\"M13.5 23v6a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2v-6h-9z\"/><path fill=\"#5DADEC\" d=\"M22.5 23v-1a2 2 0 0 0-2-2h-5a2 2 0 0 0-2 2v1h9zm-3 4.5a1.5 1.5 0 0 1-3 0v-1a1.5 1.5 0 1 1 3 0v1z\"/><path fill=\"#C1694F\" d=\"M24 5a.5.5 0 0 1-.5.5H16a.5.5 0 0 1 0-1h7.5a.5.5 0 0 1 .5.5m0 4a.5.5 0 0 1-.5.5H16a.5.5 0 0 1 0-1h7.5a.5.5 0 0 1 .5.5m0 4a.5.5 0 0 1-.5.5H16a.5.5 0 0 1 0-1h7.5a.5.5 0 0 1 .5.5\"/><g fill=\"#C1694F\"><circle cx=\"13\" cy=\"5\" r=\"1\"/><circle cx=\"13\" cy=\"9\" r=\"1\"/><circle cx=\"13\" cy=\"13\" r=\"1\"/></g></svg>",
34
+ };
@@ -0,0 +1,230 @@
1
+ <!doctype html>
2
+ <html lang="ja">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>達成カード v4(Twemoji) — CLUBS</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
9
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Noto+Sans+JP:wght@400;500;700;800&display=swap" rel="stylesheet" />
10
+ <style>
11
+ :root{--ink:#161A26;--ink-2:#3A4155;--muted:#6B7280;--line:#E7E9F2;--card:#FFFFFF;
12
+ --indigo:#4F6BF6;--violet:#8B5CF6;--teal:#0E7C86;--amber:#E8730C;--pink:#D65B7C;--green:#0A8F66;--radius:16px;}
13
+ *{box-sizing:border-box}
14
+ body{margin:0;background:#F6F7FB;color:var(--ink);font-family:"Inter","Noto Sans JP",system-ui,sans-serif;line-height:1.6}
15
+ .wrap{max-width:960px;margin:0 auto;padding:32px 22px 60px}
16
+ .brand{display:flex;align-items:center;gap:9px;font-weight:700;margin-bottom:18px}
17
+ .brand .dot{width:22px;height:22px;border-radius:7px;background:linear-gradient(135deg,var(--indigo),var(--violet))}
18
+ .handoff{display:flex;align-items:center;gap:14px;background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:16px 20px;margin-bottom:14px}
19
+ .handoff .av{width:44px;height:44px;border-radius:50%;flex:none;background:linear-gradient(135deg,#8B5CF6,#4F6BF6);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:800;font-size:18px}
20
+ .handoff .t b{font-size:15px} .handoff .t p{margin:2px 0 0;font-size:13.5px;color:var(--ink-2)}
21
+ .rhythm{font-size:12px;color:var(--muted);background:#fff;border:1px solid var(--line);border-radius:12px;padding:11px 14px;margin-bottom:24px}
22
+ .rhythm b{color:var(--ink-2)}
23
+ .sec{display:flex;align-items:center;gap:10px;margin:0 0 12px}
24
+ .sec .n{font-size:14px;font-weight:800} .sec .d{font-size:12px;color:var(--muted)}
25
+ .toggle{margin-left:auto;display:inline-flex;background:#EEF0F6;border:1px solid var(--line);border-radius:999px;padding:3px}
26
+ .toggle button{font:inherit;font-size:12px;font-weight:700;color:var(--muted);background:transparent;border:0;padding:5px 13px;border-radius:999px;cursor:pointer}
27
+ .toggle button.on{color:#fff;background:linear-gradient(135deg,var(--indigo),var(--violet))}
28
+ .grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;margin-bottom:30px}
29
+ @media(max-width:760px){.grid{grid-template-columns:repeat(2,1fr)}}
30
+ @media(max-width:480px){.grid{grid-template-columns:1fr}}
31
+ .cardx{background:#fff;border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;box-shadow:0 2px 10px rgba(20,26,38,.05);display:flex;flex-direction:column}
32
+ .cap{height:96px;display:flex;align-items:center;justify-content:center;position:relative}
33
+ .cap .rar{position:absolute;top:10px;right:12px;font-size:9.5px;font-weight:800;letter-spacing:.05em;color:#fff;background:rgba(0,0,0,.24);padding:3px 8px;border-radius:999px}
34
+ .holder{width:64px;height:64px;border-radius:50%;background:#fff;box-shadow:0 3px 9px rgba(20,26,38,.18);display:flex;align-items:center;justify-content:center}
35
+ .holder svg{width:40px;height:40px;display:block}
36
+ .cx-indigo .cap{background:linear-gradient(135deg,#5E77F7,#8B5CF6)}
37
+ .cx-teal .cap{background:linear-gradient(135deg,#17B0BE,#0E7C86)}
38
+ .cx-amber .cap{background:linear-gradient(135deg,#F59E42,#E8730C)}
39
+ .cx-pink .cap{background:linear-gradient(135deg,#E27A97,#D65B7C)}
40
+ .body{padding:14px 15px 15px;display:flex;flex-direction:column;gap:6px;flex:1}
41
+ .body .name{font-size:15.5px;font-weight:800}
42
+ .body .cond{font-size:12px;color:var(--muted)} .body .cond b{color:var(--ink-2);font-weight:700}
43
+ .effect{font-size:11.5px;font-weight:700;color:var(--indigo);background:#EEF1FE;border:1px solid #DCE3FD;border-radius:8px;padding:5px 9px;display:flex;align-items:center;gap:6px}
44
+ .effect.teal{color:var(--teal);background:#E6F6F8;border-color:#BEE6EA}
45
+ .prog{height:6px;background:#EEF0F6;border-radius:99px;overflow:hidden;margin-top:2px}
46
+ .prog i{display:block;height:100%;background:linear-gradient(90deg,var(--indigo),var(--violet))}
47
+ .prog.teal i{background:linear-gradient(90deg,#17B0BE,#0E7C86)}
48
+ .progtxt{font-size:11px;color:var(--muted);margin-top:1px}
49
+ .quote{margin-top:auto;font-size:12px;color:var(--ink-2);background:#FAFBFF;border:1px solid #EEF0F8;border-left:3px solid var(--indigo);border-radius:8px;padding:7px 9px}
50
+ .quote .who{display:block;font-size:10px;color:var(--muted);font-weight:700;margin-bottom:2px}
51
+ .title-earned{border-color:#D8CEFB} .title-earned .cap{background:linear-gradient(135deg,#7C6BF2,#8B5CF6)}
52
+ .locked{background:#F1F2F7;border:1px dashed #D2D6E4;box-shadow:none}
53
+ .locked .cap{background:#E4E7F0} .locked .holder{background:#F6F7FB} .locked .holder svg{filter:grayscale(1);opacity:.45}
54
+ .locked .name{color:#9AA0AE} .locked .cond{color:#AEB3C0}
55
+ .once{font-size:10.5px;font-weight:700;color:var(--violet);background:#F3F0FF;border:1px solid #E2D9FB;border-radius:999px;padding:2px 8px;align-self:flex-start}
56
+ .note{font-size:12px;color:var(--muted);background:#fff;border:1px solid var(--line);border-radius:12px;padding:14px 16px}
57
+ .permrow{background:#fff;border:1px solid var(--line);border-radius:12px;padding:11px 14px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
58
+ .permrow code{font-family:ui-monospace,monospace;font-size:11px;color:var(--muted);background:#F4F6FB;border-radius:6px;padding:1px 6px}
59
+ .permrow .pstate{margin-left:auto;font-size:10.5px;font-weight:800;color:#6B7280;background:#F3F4F6;border-radius:999px;padding:3px 10px}
60
+ .permrow .pstate.on{color:#0A8F66;background:#E7F5EF}
61
+ .quote{font-size:11.5px;color:var(--muted);margin-top:6px;line-height:1.6}
62
+ body{display:flex;margin:0;align-items:flex-start}
63
+ .console-main{flex:1;min-width:0;padding:26px 30px 40px;max-width:1040px}
64
+ </style>
65
+ </head>
66
+ <body>
67
+ <aside></aside>
68
+ <main class="console-main">
69
+ <div class="wrap">
70
+ <div class="brand"><img src="../assets/logo-clubs.svg" alt="CLUBS" style="width:86px;height:22px;vertical-align:middle" /></div>
71
+ <div class="handoff"><div class="av" id="handoffAv">?</div><div class="t"><b id="handoffFrom">—</b><p>実績は権限につながります。うまくいった日だけ、前に進みます。</p></div></div>
72
+ <div class="rhythm"><b>毎日はもらえません。</b> 毎日あるのは日報。カードは①<b>効く実績</b>②<b>称号</b>③<b>ネタ</b>の3種で、ほとんどの日はゼロ。名前で遊ぶぶん、副題で「何の実績か」を必ず補います。アイコンは Twemoji で全環境一貫。</div>
73
+
74
+ <div class="sec"><span class="n">① 効く実績</span><span class="d">権限を前に進めるマイルストーン。うまくいかないと取れない。</span>
75
+ <span class="toggle" id="toggle"><button data-m="dev" class="on">開発</button><button data-m="tax">税理士</button></span>
76
+ </div>
77
+ <div class="grid" id="g-effect"></div>
78
+
79
+ <div class="sec"><span class="n">② 称号</span><span class="d">あなたのAIの型。条件を満たした初回に一度だけ。剥奪なし。</span></div>
80
+ <div class="grid" id="g-title"></div>
81
+
82
+ <div class="sec"><span class="n">③ ネタ</span><span class="d">狙って取れない・たまに起きる。シェアのタネ。剥奪なし。</span></div>
83
+ <div class="grid" id="g-neta"></div>
84
+
85
+ <div class="sec"><span class="n">④ 権限(解放可能フラグのみ)</span><span class="d">条件を満たしても<b>自動では付きません</b>。付与は人間が押します。</span></div>
86
+ <div id="g-perm" style="display:flex;flex-direction:column;gap:8px;margin-bottom:22px"></div>
87
+
88
+ <div class="note">①の「効く実績」だけが権限を動かします(②③は個性とネタ)。効く実績は<b>質でゲート</b>、量や連続では取れません。<b>名前はキャラ立ち・副題で条件補完</b>、<b>レアリティは条件難易度で機械判定</b>、<b>AI引用は EPIC 以上だけ</b>。アイコンは <b>Twemoji</b> で Web・印刷・OGP すべて同一。達成カードは剥奪なしです。</div>
89
+ </div>
90
+
91
+ <script type="module">
92
+ import { TWEMOJI as TW } from "../assets/twemoji.js";
93
+
94
+ /* ■ 差し替え箇所 : 発行済みカード
95
+ GET /api/cards から「カタログ+獲得済み」を読む。サーバが無ければ静的定義のまま。
96
+ 判定は src/cards.mjs(日報の検証済み集計だけを見る機械判定)。ここでは表示のみ。 */
97
+ const RARITY_CLASS = { COMMON: "cx-indigo", RARE: "cx-amber", EPIC: "cx-teal", LEGENDARY: "cx-pink" };
98
+
99
+ /* データは1本。API があれば獲得状況つき、無ければカタログだけ(獲得状況は不明)。
100
+ モックの数字は持たない。持つと、見本の偽の進捗が実物のように見える。 */
101
+ async function loadCards(){
102
+ try {
103
+ const r = await fetch("/api/cards");
104
+ if (r.ok) return await r.json();
105
+ } catch {}
106
+ try {
107
+ // 実データのスナップショット(獲得状況つき)
108
+ const r = await fetch("../preview.json");
109
+ if (r.ok) {
110
+ const s = await r.json();
111
+ return { cards: s.cards, permissions: s.permissions, snapshotAt: s.snapshotAt };
112
+ }
113
+ } catch {}
114
+ try {
115
+ // それも無ければカタログだけ(獲得状況は不明)
116
+ const r = await fetch("./catalog.json"); // src/cards.mjs から生成(scripts/gen-catalog.mjs)
117
+ if (r.ok) return await r.json();
118
+ } catch {}
119
+ return null;
120
+ }
121
+
122
+ function renderFromApi(data, mode = "dev"){
123
+ const esc = (t) => String(t ?? "").replace(/[&<>"]/g, c => ({ "&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;" }[c]));
124
+ const groups = { effect: [], title: [], neta: [] };
125
+ for (const c of data.cards) {
126
+ // 「効く実績」は開発/税理士でトグルする
127
+ if (c.kind === "effect" && c.domain && c.domain !== mode) continue;
128
+ groups[c.kind]?.push(c);
129
+ }
130
+
131
+ const cardHtml = (c) => {
132
+ const cls = c.earned === true ? (RARITY_CLASS[c.rarity] ?? "cx-indigo") : "locked";
133
+ const rar = c.kind === "title" ? "TITLE" : c.rarity;
134
+ // AI の引用は EPIC 以上だけ。それ未満は副題のみ(カタログ §0)。
135
+ const quote = c.earned === true && c.quote
136
+ ? `<div class="quote">「${esc(c.quote)}」</div>` : "";
137
+ return `<div class="cardx ${cls}">
138
+ <div class="cap">${c.earned === true ? `<span class="rar">${esc(rar)}</span>` : ""}<div class="holder" data-tw="${esc(c.tw)}"></div></div>
139
+ <div class="body">
140
+ <div class="nm">${esc(c.name)}</div>
141
+ <div class="cond">${esc(c.subtitle)}</div>
142
+ ${quote}
143
+ ${
144
+ c.earned === true ? `<div class="when">${esc(c.earnedAt ?? "")}</div>`
145
+ : c.earned === false ? `<div class="when">未獲得</div>`
146
+ : `<div class="when">獲得状況は不明(サーバ未接続)</div>`
147
+ }
148
+ </div>
149
+ </div>`;
150
+ };
151
+
152
+ for (const [kind, sel] of [["effect", "#g-effect"], ["title", "#g-title"], ["neta", "#g-neta"]]) {
153
+ const el = document.querySelector(sel);
154
+ if (el) el.innerHTML = groups[kind].map(cardHtml).join("");
155
+ }
156
+
157
+ const perm = document.querySelector("#g-perm");
158
+ if (perm) {
159
+ perm.innerHTML = data.permissions.map((p) =>
160
+ `<div class="permrow"><b>${esc(p.name)}</b> — ${esc(p.subtitle)} <code>${esc(p.scope)}</code>
161
+ <span class="pstate ${p.unlockable === true ? "on" : ""}">${
162
+ p.unlockable === true ? "解放可能(付与は人間の承認)"
163
+ : p.unlockable === false ? "未解放"
164
+ : "状態は不明(サーバ未接続)"
165
+ }</span></div>`
166
+ ).join("");
167
+ }
168
+ }
169
+
170
+ function fillIcons(){
171
+ document.querySelectorAll(".holder[data-tw]").forEach(el => {
172
+ if (!el.firstChild) el.innerHTML = TW[el.dataset.tw] || "";
173
+ });
174
+ }
175
+
176
+ let DATA = null;
177
+ let MODE = "dev";
178
+
179
+ const tg = document.getElementById("toggle");
180
+ tg.querySelectorAll("button").forEach(b => {
181
+ b.onclick = () => {
182
+ tg.querySelectorAll("button").forEach(x => x.classList.remove("on"));
183
+ b.classList.add("on");
184
+ MODE = b.dataset.m;
185
+ if (DATA) renderFromApi(DATA, MODE);
186
+ };
187
+ });
188
+
189
+ /* 「◯◯ からのカード」の名前は実データから入れる。"Hermes" が焼き込んであったが、
190
+ これは見本の名前で、そのまま出すと共有先に他人の名前が出る(サイドバーで同じことが起きた)。 */
191
+ async function fillHandoffName(){
192
+ const set = (s) => {
193
+ document.getElementById("handoffFrom").textContent = `${s.displayName} からのカード`;
194
+ document.getElementById("handoffAv").textContent = [...(s.agentName ?? "?")][0];
195
+ };
196
+ try {
197
+ const r = await fetch("/api/settings");
198
+ if (r.ok) return set(await r.json());
199
+ } catch {}
200
+ try {
201
+ const r = await fetch("../preview.json");
202
+ if (r.ok) return set((await r.json()).settings);
203
+ } catch {}
204
+ // 分からない名前は出さない。
205
+ document.getElementById("handoffFrom").textContent = "あなたのAIからのカード";
206
+ }
207
+
208
+ (async () => {
209
+ DATA = await loadCards();
210
+ if (DATA) renderFromApi(DATA, MODE);
211
+ await fillHandoffName();
212
+ if (DATA?.snapshotAt) {
213
+ // body は display:flex(サイドバー+本文の横並び)。sticky で prepend すると帯が
214
+ // 3つ目の列になり、幅を食ってレイアウトが崩れる。全幅に固定して浮かせる。
215
+ const el = document.createElement("div");
216
+ el.style.cssText = "position:fixed;top:0;left:0;right:0;z-index:99;background:#F7EFDD;color:#8A6520;font-size:12px;font-weight:700;padding:8px 14px;text-align:center;border-bottom:1px solid #E6D6BF";
217
+ el.textContent = `スナップショット(${DATA.snapshotAt} 時点)。サーバに繋がっていません。`;
218
+ document.body.prepend(el);
219
+ document.body.style.paddingTop = "34px";
220
+ }
221
+ fillIcons();
222
+ })();
223
+ </script>
224
+ </main>
225
+ <script type="module">
226
+ import { mountSidebar } from "../assets/sidebar.js";
227
+ mountSidebar("cards");
228
+ </script>
229
+ </body>
230
+ </html>