claude-rpc 0.7.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,6 +10,8 @@
10
10
  **Discord Rich Presence for [Claude Code](https://claude.com/claude-code).**
11
11
  Your live model, project, current tool, tokens, and lifetime stats — in your Discord profile. Driven by the hooks Claude Code already fires. Zero polling between sessions.
12
12
 
13
+ **→ [claude-rpc.vercel.app](https://claude-rpc.vercel.app)** — what it looks like, in one page.
14
+
13
15
  [![community · sessions](https://claude-rpc-totals.claude-rpc.workers.dev/sessions.svg)](#community-totals)   [![community · tokens](https://claude-rpc-totals.claude-rpc.workers.dev/tokens.svg)](#community-totals)
14
16
 
15
17
  <sub>live — on by default for fresh installs, opt out any time. see [community totals](#community-totals)</sub>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-rpc",
3
- "version": "0.7.1",
3
+ "version": "0.7.2",
4
4
  "description": "Discord Rich Presence for Claude Code — live model, project, tokens, and lifetime stats driven by Claude Code's hook system.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -20,305 +20,286 @@
20
20
 
21
21
  const CSS = `
22
22
  :root {
23
- --bg: #0a0a0a;
24
- --bg-2: #111;
25
- --surface: rgba(255,255,255,0.025);
26
- --surface-hover: rgba(255,255,255,0.05);
27
- --border: rgba(255,255,255,0.08);
28
- --border-strong: rgba(255,255,255,0.16);
29
- --text: #ffffff;
30
- --text-2: rgba(255,255,255,0.62);
31
- --text-3: rgba(255,255,255,0.36);
32
- --text-4: rgba(255,255,255,0.16);
33
- --green: #4ade80;
34
- --amber: #fbbf24;
35
- --red: #f87171;
36
- --blue: #60a5fa;
37
- --purple: #a78bfa;
38
- --pink: #f472b6;
39
- --radius: 14px;
40
- }
41
- html.light {
42
- --bg: #fafaf9;
43
- --bg-2: #fff;
44
- --surface: rgba(0,0,0,0.025);
45
- --surface-hover: rgba(0,0,0,0.05);
46
- --border: rgba(0,0,0,0.08);
47
- --border-strong: rgba(0,0,0,0.16);
48
- --text: #18181b;
49
- --text-2: rgba(0,0,0,0.62);
50
- --text-3: rgba(0,0,0,0.36);
51
- --text-4: rgba(0,0,0,0.16);
23
+ --paper: #f4ede0;
24
+ --paper-dark: #ebe2d2;
25
+ --ink: #1a1611;
26
+ --ink-soft: #2d2520;
27
+ --ink-mute: #5c5147;
28
+ --ink-faint: #8a7c6d;
29
+
30
+ --rust: #c2491e;
31
+ --tape: #f2d76e;
32
+ --grass: #4a9462;
33
+
34
+ --font-sans: 'Inter', system-ui, sans-serif;
35
+ --font-mono: 'JetBrains Mono', monospace;
36
+ --font-disp: 'Space Grotesk', sans-serif;
37
+
38
+ --shadow: 3px 3px 0 var(--ink);
39
+ --shadow-hover: 5px 5px 0 var(--ink);
40
+ --radius: 0;
41
+
42
+ /* Fallbacks for existing variables used by page.js */
43
+ --bg: var(--paper);
44
+ --text: var(--ink);
45
+ --text-2: var(--ink-soft);
46
+ --text-3: var(--ink-mute);
47
+ --text-4: var(--ink-faint);
48
+ --border: var(--ink);
49
+ --surface: #fff;
50
+ --surface-hover: var(--paper);
51
+ --green: var(--grass);
52
+ --red: #c54a3a;
53
+ --purple: #5865f2; /* using blurple */
54
+ --amber: var(--tape);
52
55
  }
56
+
53
57
  * { box-sizing: border-box; margin: 0; padding: 0; }
54
- ::selection { background: rgba(255,255,255,0.16); }
55
- html, body { background: var(--bg); color: var(--text); }
58
+ ::selection { background: rgba(26,22,17,0.16); }
59
+ html, body { background: var(--paper); color: var(--ink); }
56
60
  body {
57
- font-family: 'Inter', system-ui, sans-serif;
61
+ font-family: var(--font-sans);
58
62
  font-size: 14px; line-height: 1.5;
59
- font-feature-settings: 'cv11','ss01';
60
- -webkit-font-smoothing: antialiased;
61
- font-variant-numeric: tabular-nums;
62
63
  min-height: 100vh;
64
+ background-image: radial-gradient(circle at 1px 1px, rgba(26,22,17,0.07) 1px, transparent 0);
65
+ background-size: 20px 20px;
63
66
  }
64
67
  .num { font-variant-numeric: tabular-nums; }
65
68
  a { color: inherit; text-decoration: none; }
66
69
  button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
70
+ h1, h2, h3 { font-family: var(--font-disp); }
67
71
 
68
- .page { max-width: 1200px; margin: 0 auto; padding: 28px 40px 100px; }
72
+ .page { max-width: 1000px; margin: 0 auto; padding: 40px 40px 100px; }
69
73
 
70
74
  /* ── Top bar ─────────────────────────────────────────── */
71
75
  .topbar {
72
- display: flex; align-items: center; gap: 16px;
73
- padding-bottom: 14px;
74
- margin-bottom: 28px;
75
- border-bottom: 1px solid var(--border);
76
+ display: flex; justify-content: space-between; align-items: center;
77
+ padding-bottom: 24px;
78
+ border-bottom: 2px dashed var(--ink-mute);
79
+ margin-bottom: 40px;
76
80
  }
77
81
  .brand {
78
- display: flex; align-items: center; gap: 10px;
79
- font-weight: 500; font-size: 15px;
82
+ display: flex; align-items: center; gap: 12px;
83
+ font-family: var(--font-disp);
84
+ font-weight: 700; font-size: 24px;
80
85
  }
81
86
  .brand .mark {
82
- width: 22px; height: 22px;
87
+ width: 32px; height: 32px;
88
+ background: var(--ink); color: var(--paper);
89
+ font-family: var(--font-mono); font-size: 14px;
83
90
  display: grid; place-items: center;
84
- background: linear-gradient(135deg, #fff, #c0c0c0);
85
- color: #0a0a0a; border-radius: 6px;
86
- font-weight: 700; font-size: 12px;
91
+ border: 2px solid var(--ink);
92
+ box-shadow: 2px 2px 0 var(--rust);
93
+ transform: rotate(-3deg);
87
94
  }
88
- .brand .sep { color: var(--text-4); }
89
- .brand .meta { color: var(--text-3); font-weight: 400; font-size: 13px; }
90
- .top-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
95
+ .brand .sep { display: none; }
96
+ .brand .meta { display: none; }
97
+ .top-right { margin-left: auto; display: flex; align-items: center; gap: 16px; }
91
98
 
92
99
  .range-pills {
93
- display: inline-flex; gap: 2px; padding: 3px;
94
- background: var(--surface); border: 1px solid var(--border);
95
- border-radius: 999px;
100
+ display: inline-flex; gap: 4px;
96
101
  }
97
102
  .range-pills button {
98
- font-size: 12px; padding: 5px 11px;
99
- color: var(--text-3); border-radius: 999px;
100
- transition: background 0.12s, color 0.12s;
103
+ font-family: var(--font-mono);
104
+ font-size: 12px; padding: 6px 12px; font-weight: 700;
105
+ border: 2px solid transparent; text-transform: uppercase;
106
+ transition: transform 0.12s;
107
+ }
108
+ .range-pills button:hover { transform: translateY(-2px); }
109
+ .range-pills button.active {
110
+ background: var(--tape);
111
+ border-color: var(--ink);
112
+ box-shadow: 2px 2px 0 var(--ink);
113
+ transform: rotate(2deg);
101
114
  }
102
- .range-pills button:hover { color: var(--text); }
103
- .range-pills button.active { background: var(--text); color: var(--bg); }
104
115
 
105
116
  .status {
106
117
  display: inline-flex; align-items: center; gap: 8px;
107
- font-size: 13px; color: var(--text-2);
108
- padding: 6px 12px; border: 1px solid var(--border); border-radius: 999px;
109
- }
110
- .status .dot {
111
- width: 6px; height: 6px; border-radius: 50%;
112
- background: var(--green);
113
- box-shadow: 0 0 0 3px rgba(74,222,128,0.16);
114
- animation: pulse 2s ease-in-out infinite;
115
- }
116
- .status .dot.idle { background: var(--amber); box-shadow: 0 0 0 3px rgba(251,191,36,0.16); animation: none; }
117
- .status .dot.stale { background: var(--text-4); box-shadow: none; animation: none; }
118
- @keyframes pulse {
119
- 0%,100% { box-shadow: 0 0 0 3px rgba(74,222,128,0.16); }
120
- 50% { box-shadow: 0 0 0 6px rgba(74,222,128,0.04); }
118
+ font-family: var(--font-mono);
119
+ font-size: 12px; font-weight: 700; text-transform: uppercase;
120
+ background: var(--grass); color: var(--paper);
121
+ padding: 6px 12px; border: 2px solid var(--ink); box-shadow: 2px 2px 0 var(--ink);
122
+ transform: rotate(-2deg);
121
123
  }
122
- .theme-btn {
123
- padding: 6px 10px; border-radius: 999px; border: 1px solid var(--border);
124
- font-size: 13px; color: var(--text-2);
125
- }
126
- .theme-btn:hover { color: var(--text); }
127
- .model { font-size: 13px; color: var(--text-3); }
124
+ .status .dot { display: none; }
125
+ .theme-btn { display: none; } /* Hide theme toggle, we only use paper now */
126
+ .model { font-family: var(--font-mono); font-size: 12px; font-weight: 700; background: #fff; padding: 4px 8px; border: 2px solid var(--ink); box-shadow: 2px 2px 0 var(--ink); }
128
127
 
129
128
  /* ── Live rail ───────────────────────────────────────── */
130
129
  .live-rail {
131
- display: grid; grid-template-columns: 72px 1fr auto; gap: 16px; align-items: center;
132
- padding: 18px 22px; margin-bottom: 28px;
133
- background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
130
+ display: grid; grid-template-columns: 80px 1fr auto; gap: 24px; align-items: center;
131
+ background: #fff; padding: 24px;
132
+ border: 2px solid var(--ink); box-shadow: var(--shadow);
133
+ margin-bottom: 48px; position: relative;
134
+ transform: rotate(-0.5deg); transition: transform 0.2s, box-shadow 0.2s;
135
+ }
136
+ .live-rail:hover { transform: rotate(0deg) translate(-2px, -2px); box-shadow: var(--shadow-hover); }
137
+ .live-rail::before {
138
+ content: "LIVE PREVIEW"; position: absolute; top: -12px; right: 24px;
139
+ background: var(--tape); font-family: var(--font-mono); font-weight: 700; font-size: 11px;
140
+ padding: 4px 10px; border: 2px solid var(--ink); box-shadow: 2px 2px 0 var(--ink); transform: rotate(3deg);
134
141
  }
135
142
  .live-rail .avatar {
136
- width: 64px; height: 64px; border-radius: 14px;
137
- background: linear-gradient(135deg, rgba(167,139,250,0.18), rgba(167,139,250,0.05));
138
- overflow: hidden; position: relative;
143
+ width: 80px; height: 80px; background: var(--paper-dark);
144
+ border: 2px solid var(--ink); box-shadow: 2px 2px 0 var(--ink) inset; overflow: hidden;
139
145
  }
140
146
  .live-rail .avatar img { width: 100%; height: 100%; object-fit: cover; }
141
- .live-rail .frame-app { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-3); font-weight: 600; }
142
- .live-rail .frame-details { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; margin-top: 2px; }
143
- .live-rail .frame-state { font-size: 13px; color: var(--text-2); margin-top: 2px; }
144
- .live-rail .right { text-align: right; font-size: 12px; color: var(--text-3); }
145
- .live-rail .right .frame-num { color: var(--text-2); font-size: 12px; margin-bottom: 6px; }
146
- .live-rail .right .elapsed { font-size: 16px; font-weight: 500; color: var(--text); letter-spacing: -0.01em; }
147
+ .live-rail .frame-app { display: none; }
148
+ .live-rail .frame-details { font-family: var(--font-disp); font-size: 22px; font-weight: 700; margin-bottom: 4px; }
149
+ .live-rail .frame-state { font-family: var(--font-mono); font-size: 13px; color: var(--ink-mute); }
150
+ .live-rail .right { text-align: right; border-left: 2px dashed var(--ink); padding-left: 24px; }
151
+ .live-rail .right .frame-num { font-family: var(--font-mono); font-size: 11px; font-weight: 700; color: var(--ink-mute); margin-bottom: 8px; text-transform: uppercase; }
152
+ .live-rail .right .elapsed { font-family: var(--font-mono); font-size: 24px; font-weight: 700; }
147
153
 
148
154
  /* ── Hero ────────────────────────────────────────────── */
149
155
  .hero {
150
156
  display: grid; grid-template-columns: 1fr 1.4fr; gap: 56px;
151
- align-items: end; margin-bottom: 28px;
157
+ align-items: end; margin-bottom: 48px;
152
158
  }
153
159
  .hero .eyebrow {
154
- font-size: 12px; color: var(--text-3);
155
- text-transform: uppercase; letter-spacing: 0.12em;
156
- font-weight: 500; margin-bottom: 16px;
160
+ font-family: var(--font-mono); font-size: 12px; font-weight: 700; color: var(--ink-mute);
161
+ text-transform: uppercase; margin-bottom: 12px;
162
+ border-bottom: 2px solid var(--rust); display: inline-block; padding-bottom: 4px;
157
163
  }
158
- .hero .figure { font-size: 86px; font-weight: 600; line-height: 0.92; letter-spacing: -0.05em; }
159
- .hero .unit { font-size: 20px; color: var(--text-2); margin-left: 10px; }
160
- .hero .caption { margin-top: 20px; color: var(--text-2); max-width: 380px; }
161
- .hero .caption strong { color: var(--text); font-weight: 500; }
162
-
163
- .chart-block .chart-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 12px; }
164
- .chart-block .chart-title { font-size: 12px; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.12em; }
165
- .chart-block .chart-side { font-size: 12px; color: var(--text-3); }
166
- .chart-block .chart-side strong { color: var(--text-2); font-weight: 500; }
167
- .chart-wrap { position: relative; height: 130px; }
164
+ .hero .figure { font-family: var(--font-disp); font-size: 86px; font-weight: 700; line-height: 0.92; letter-spacing: -0.05em; }
165
+ .hero .unit { font-family: var(--font-mono); font-size: 24px; color: var(--ink-mute); margin-left: 10px; font-weight: 700; }
166
+ .hero .caption { margin-top: 20px; font-family: var(--font-mono); font-size: 13px; color: var(--ink-soft); max-width: 380px; }
167
+
168
+ .chart-block .chart-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 12px; font-family: var(--font-mono); font-weight: 700; }
169
+ .chart-block .chart-title { font-size: 12px; color: var(--ink-mute); text-transform: uppercase; }
170
+ .chart-block .chart-side { font-size: 12px; color: var(--ink-mute); }
171
+ .chart-block .chart-side strong { color: var(--ink); }
172
+ .chart-wrap { position: relative; height: 130px; background: #fff; border: 2px solid var(--ink); box-shadow: var(--shadow); padding: 12px; }
168
173
  svg.chart { width: 100%; height: 100%; overflow: visible; }
169
- svg.chart .grid { stroke: var(--border); stroke-width: 1; }
174
+ svg.chart .grid { stroke: var(--ink-faint); stroke-width: 1; stroke-dasharray: 2 2; }
170
175
  svg.chart .area { fill: url(#whiteGrad); }
171
- svg.chart .line { fill: none; stroke: var(--text); stroke-width: 1.4; stroke-linecap: round; stroke-linejoin: round; }
172
- svg.chart .dot { fill: var(--text); }
173
- svg.chart .ax { fill: var(--text-3); font-size: 10px; font-family: 'Inter', sans-serif; font-weight: 500; letter-spacing: 0.04em; }
174
-
175
- /* ── Insights strip ─────────────────────────────────── */
176
- .insights {
177
- background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
178
- padding: 16px 20px; margin-bottom: 28px;
179
- display: grid; gap: 6px;
180
- }
181
- .insights .insight {
182
- display: flex; align-items: baseline; gap: 10px;
183
- font-size: 13px; color: var(--text-2); line-height: 1.45;
184
- }
185
- .insights .insight::before {
186
- content: '→'; color: var(--text-4); flex-shrink: 0; font-size: 13px;
187
- }
176
+ svg.chart .line { fill: none; stroke: var(--rust); stroke-width: 2.5; stroke-linecap: round; stroke-linejoin: round; }
177
+ svg.chart .dot { fill: var(--rust); stroke: #fff; stroke-width: 2px; }
178
+ svg.chart .ax { fill: var(--ink-mute); font-size: 10px; font-family: var(--font-mono); font-weight: 700; }
188
179
 
189
180
  /* ── Stat cards ──────────────────────────────────────── */
190
181
  .stat-row {
191
- display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px;
192
- margin-bottom: 28px;
182
+ display: grid; grid-template-columns: repeat(4, 1fr); gap: 24px;
183
+ margin-bottom: 48px;
193
184
  }
194
185
  .stat-card {
195
- background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
196
- padding: 18px 20px;
197
- transition: background 0.18s, border-color 0.18s;
186
+ background: #fff; border: 2px solid var(--ink); padding: 24px;
187
+ box-shadow: var(--shadow); position: relative;
188
+ transition: transform 0.2s, box-shadow 0.2s;
198
189
  }
199
- .stat-card:hover { background: var(--surface-hover); border-color: var(--border-strong); }
200
- .stat-card .label { font-size: 12px; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.1em; font-weight: 500; }
201
- .stat-card .value { margin-top: 12px; display: flex; align-items: baseline; gap: 6px; font-size: 28px; font-weight: 600; letter-spacing: -0.03em; line-height: 1; }
202
- .stat-card .value .unit { font-size: 13px; color: var(--text-3); font-weight: 400; }
203
- .stat-card .meta { margin-top: 10px; font-size: 12px; color: var(--text-2); display: flex; align-items: center; gap: 8px; }
204
- .delta { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 500; padding: 2px 6px; background: rgba(255,255,255,0.04); border-radius: 4px; }
205
- .delta.up { color: var(--green); background: rgba(74,222,128,0.08); }
206
- .delta.down { color: var(--red); background: rgba(248,113,113,0.08); }
207
- .delta.flat { color: var(--text-3); }
208
-
209
- /* ── Section heading ─────────────────────────────────── */
210
- .section-head {
211
- display: flex; align-items: baseline; justify-content: space-between;
212
- margin-bottom: 16px;
213
- }
214
- .section-head h2 { font-size: 13px; font-weight: 500; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.12em; }
215
- .section-head .right { font-size: 12px; color: var(--text-3); }
216
- section { margin-bottom: 28px; }
217
-
218
- /* ── Leaderboards ────────────────────────────────────── */
219
- .lb-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
220
- .lb { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
221
- .lb-h { display: flex; justify-content: space-between; align-items: baseline; padding: 14px 16px 10px; }
222
- .lb-h .t { font-size: 13px; font-weight: 500; }
223
- .lb-h .s { font-size: 11px; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.08em; }
224
- .lb table { width: 100%; border-collapse: collapse; }
225
- .lb td { padding: 7px 16px; font-size: 12.5px; }
226
- .lb tr { border-top: 1px solid var(--border); transition: background 0.12s; }
227
- .lb tr:hover td { background: rgba(255,255,255,0.025); }
228
- .lb tr.clickable td { cursor: pointer; }
229
- .lb td.name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 1px; }
230
- .lb td.val { color: var(--text-2); text-align: right; white-space: nowrap; }
231
- .lb td.val .u { color: var(--text-3); margin-left: 3px; font-size: 11px; }
232
- .lb td.name .ico { width: 12px; height: 12px; border-radius: 2px; vertical-align: -2px; margin-right: 7px; opacity: 0.7; }
233
-
234
- /* ── Cost & languages ────────────────────────────────── */
235
- .split-row { display: grid; grid-template-columns: 1.2fr 1fr; gap: 12px; margin-bottom: 28px; }
236
- .card {
237
- background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
238
- padding: 20px 22px;
190
+ .stat-card:hover { transform: translate(-2px, -2px); box-shadow: var(--shadow-hover); }
191
+ .stat-card::before {
192
+ content: ''; position: absolute; top: -8px; left: 50%; transform: translateX(-50%);
193
+ width: 40px; height: 16px; background: rgba(0,0,0,0.05); /* tape piece effect */
239
194
  }
240
- .card-h { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 14px; }
241
- .card-h h3 { font-size: 13px; font-weight: 500; color: var(--text-3); text-transform: uppercase; letter-spacing: 0.12em; }
242
- .card-h .meta { font-size: 12px; color: var(--text-3); }
195
+ .stat-card .label { font-family: var(--font-mono); font-size: 11px; font-weight: 700; color: var(--ink-mute); text-transform: uppercase; border-bottom: 2px solid var(--rust); display: inline-block; padding-bottom: 4px; }
196
+ .stat-card .value { margin-top: 16px; display: flex; align-items: baseline; gap: 6px; font-family: var(--font-disp); font-size: 36px; font-weight: 700; line-height: 1; }
197
+ .stat-card .value .unit { font-family: var(--font-mono); font-size: 16px; color: var(--ink-mute); font-weight: 700; }
198
+ .stat-card .meta { margin-top: 12px; font-family: var(--font-mono); font-size: 12px; color: var(--ink-mute); font-weight: 500; }
199
+ .delta { font-weight: 700; }
200
+ .delta.up { color: var(--grass); }
201
+ .delta.down { color: var(--rust); }
202
+ .delta.flat { color: var(--ink-mute); }
203
+
204
+ /* ── Split: cost + languages ─────────────────────── */
205
+ .split-row { display: grid; grid-template-columns: 1.2fr 1fr; gap: 24px; margin-bottom: 48px; }
206
+ .card { background: #fff; border: 2px solid var(--ink); padding: 24px; box-shadow: var(--shadow); position: relative; }
207
+ .card-h { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 20px; font-family: var(--font-mono); font-weight: 700; }
208
+ .card-h h3 { font-size: 14px; text-transform: uppercase; border-bottom: 2px solid var(--rust); display: inline-block; padding-bottom: 4px; }
209
+ .card-h .meta { font-size: 11px; color: var(--ink-mute); }
243
210
 
244
211
  .cost-grid { display: grid; grid-template-columns: 1.2fr 1fr; gap: 24px; align-items: center; }
245
- .cost-figure { font-size: 48px; font-weight: 600; letter-spacing: -0.04em; line-height: 1; }
246
- .cost-sub { color: var(--text-2); font-size: 13px; margin-top: 8px; }
247
- .cost-bars { display: grid; gap: 6px; font-size: 12px; }
212
+ .cost-figure { font-family: var(--font-disp); font-size: 48px; font-weight: 700; line-height: 1; }
213
+ .cost-sub { font-family: var(--font-mono); color: var(--ink-mute); font-size: 12px; margin-top: 8px; font-weight: 700; }
214
+ .cost-bars { display: grid; gap: 12px; font-family: var(--font-mono); font-size: 12px; font-weight: 700; }
248
215
  .cost-bar { display: grid; grid-template-columns: 60px 1fr auto; gap: 8px; align-items: center; }
249
- .cost-bar .name { color: var(--text-2); }
250
- .cost-bar .track { height: 6px; background: rgba(255,255,255,0.06); border-radius: 99px; overflow: hidden; }
251
- .cost-bar .fill { height: 100%; background: var(--purple); }
252
- .cost-bar .val { color: var(--text); font-variant-numeric: tabular-nums; font-size: 12px; }
253
-
254
- .lang-stack { display: flex; height: 14px; border-radius: 4px; overflow: hidden; background: rgba(255,255,255,0.06); margin-bottom: 14px; }
255
- .lang-stack > span { display: block; }
256
- .lang-list { display: grid; gap: 4px; }
257
- .lang-list .row { display: grid; grid-template-columns: 12px 1fr auto; gap: 8px; align-items: center; font-size: 12.5px; }
258
- .lang-list .swatch { width: 10px; height: 10px; border-radius: 2px; }
259
- .lang-list .name { color: var(--text); }
260
- .lang-list .val { color: var(--text-3); font-size: 11px; }
261
-
262
- .churn-row { display: grid; grid-template-columns: 1fr 200px; gap: 28px; align-items: end; }
263
- .churn-spark svg { width: 100%; height: 60px; display: block; }
264
- .churn-spark .add { fill: var(--green); opacity: 0.85; }
265
- .churn-spark .rem { fill: var(--red); opacity: 0.55; }
266
- .churn-numbers { display: grid; gap: 4px; }
267
- .churn-numbers .row { display: flex; justify-content: space-between; font-size: 12.5px; }
268
- .churn-numbers .label { color: var(--text-3); }
269
- .churn-numbers .added { color: var(--green); font-weight: 500; }
270
- .churn-numbers .removed { color: var(--red); font-weight: 500; }
271
- .churn-numbers .net { color: var(--text); font-weight: 500; }
216
+ .cost-bar .name { color: var(--ink-soft); }
217
+ .cost-bar .track { height: 8px; background: var(--paper-dark); border: 1.5px solid var(--ink); overflow: hidden; }
218
+ .cost-bar .fill { height: 100%; background: var(--purple); border-right: 1.5px solid var(--ink); }
219
+ .cost-bar .val { color: var(--ink); }
220
+
221
+ .lang-stack { display: flex; height: 16px; background: var(--paper-dark); border: 2px solid var(--ink); margin-bottom: 20px; box-shadow: 2px 2px 0 var(--ink); }
222
+ .lang-stack > span { display: block; border-right: 1.5px solid var(--ink); }
223
+ .lang-stack > span:last-child { border-right: none; }
224
+ .lang-list { display: grid; gap: 8px; font-family: var(--font-mono); font-size: 12px; font-weight: 700; }
225
+ .lang-list .row { display: grid; grid-template-columns: 14px 1fr auto; gap: 10px; align-items: center; }
226
+ .lang-list .swatch { width: 14px; height: 14px; border: 2px solid var(--ink); }
227
+ .lang-list .val { color: var(--ink-mute); }
228
+
229
+ /* ── Code churn ──────────────────────────────────── */
230
+ .churn-row { display: grid; grid-template-columns: 1fr 200px; gap: 32px; align-items: center; }
231
+ .churn-spark svg { width: 100%; height: 60px; display: block; overflow: visible; }
232
+ .churn-spark .add { fill: var(--grass); stroke: var(--ink); stroke-width: 1.5; }
233
+ .churn-spark .rem { fill: var(--rust); stroke: var(--ink); stroke-width: 1.5; }
234
+ .churn-numbers { display: grid; gap: 8px; font-family: var(--font-mono); font-size: 13px; font-weight: 700; }
235
+ .churn-numbers .row { display: flex; justify-content: space-between; padding-bottom: 4px; border-bottom: 1.5px dashed var(--ink-faint); }
236
+ .churn-numbers .row:last-child { border-bottom: none; }
237
+ .churn-numbers .label { color: var(--ink-mute); }
238
+ .churn-numbers .added { color: var(--grass); }
239
+ .churn-numbers .removed { color: var(--rust); }
240
+ .churn-numbers .net { color: var(--ink); }
241
+
242
+ /* ── Section heading ─────────────────────────────────── */
243
+ .section-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 20px; font-family: var(--font-mono); font-weight: 700; }
244
+ .section-head h2 { font-size: 16px; text-transform: uppercase; background: var(--tape); display: inline-block; padding: 4px 12px; border: 2px solid var(--ink); box-shadow: 2px 2px 0 var(--ink); transform: rotate(-1deg); }
245
+ .section-head .right { font-size: 12px; color: var(--ink-mute); }
246
+ section { margin-bottom: 48px; }
247
+
248
+ /* ── Leaderboards ────────────────────────────────────── */
249
+ .lb-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 24px; }
250
+ .lb { background: #fff; border: 2px solid var(--ink); box-shadow: var(--shadow); position: relative; }
251
+ .lb-h { display: flex; justify-content: space-between; align-items: baseline; padding: 16px 20px 12px; font-family: var(--font-mono); font-weight: 700; border-bottom: 2px solid var(--ink); background: var(--paper-dark); }
252
+ .lb-h .t { font-size: 13px; text-transform: uppercase; }
253
+ .lb-h .s { font-size: 11px; color: var(--ink-mute); }
254
+ .lb table { width: 100%; border-collapse: collapse; font-family: var(--font-mono); font-weight: 600; font-size: 12px; }
255
+ .lb td { padding: 10px 20px; border-bottom: 1.5px dashed var(--ink-faint); }
256
+ .lb tr:last-child td { border-bottom: none; }
257
+ .lb tr:hover td { background: var(--paper); }
258
+ .lb td.name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 1px; color: var(--ink); }
259
+ .lb td.val { color: var(--ink-soft); text-align: right; white-space: nowrap; }
260
+ .lb td.name .ico { width: 12px; height: 12px; border: 1.5px solid var(--ink); margin-right: 8px; vertical-align: -2px; }
272
261
 
273
262
  /* ── Discord card ────────────────────────────────────── */
274
- .discord {
275
- background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
276
- padding: 24px 28px;
277
- }
278
- .discord-h { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 16px; }
279
- .discord-h .t { font-size: 13px; font-weight: 500; }
280
- .discord-h .s { font-size: 12px; color: var(--text-3); }
281
- .live-frame {
282
- padding: 22px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border);
283
- }
284
- .live-frame .label-tag {
285
- font-size: 10px; color: var(--green); letter-spacing: 0.16em; text-transform: uppercase;
286
- font-weight: 600; margin-bottom: 8px;
287
- display: inline-flex; align-items: center; gap: 6px;
288
- }
289
- .live-frame .label-tag::before {
290
- content: ''; width: 4px; height: 4px; border-radius: 50%;
291
- background: var(--green); box-shadow: 0 0 0 2px rgba(74,222,128,0.2);
292
- }
293
- .live-frame .details { font-size: 20px; font-weight: 500; letter-spacing: -0.01em; line-height: 1.2; margin-bottom: 4px; }
294
- .live-frame .state { font-size: 13px; color: var(--text-2); }
295
- .rotation-list {
296
- list-style: none; margin-top: 16px;
297
- display: grid; grid-template-columns: repeat(2, 1fr); gap: 4px 18px;
298
- }
299
- .rotation-list li {
300
- display: flex; align-items: center; gap: 10px;
301
- font-size: 12px; color: var(--text-2); padding: 4px 0;
302
- }
303
- .rotation-list li .pip { width: 4px; height: 4px; border-radius: 50%; background: var(--text-4); flex-shrink: 0; }
304
- .rotation-list li.live .pip { background: var(--green); }
305
- .rotation-list li.current { color: var(--text); }
306
- .rotation-list li.current .pip { background: var(--text); box-shadow: 0 0 0 2px rgba(255,255,255,0.2); }
307
- .rotation-list li.skip { color: var(--text-3); }
308
- .rotation-list li .frame-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; }
309
-
310
- /* ── Achievements ────────────────────────────────────── */
311
- .achievements { display: grid; grid-template-columns: repeat(6, 1fr); gap: 8px; margin-bottom: 28px; }
312
- .achievement {
313
- background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
314
- padding: 12px 14px;
315
- opacity: 0.32;
316
- transition: opacity 0.18s, border-color 0.18s, background 0.18s;
317
- }
318
- .achievement.unlocked { opacity: 1; border-color: var(--border-strong); }
319
- .achievement .ico { font-size: 18px; margin-bottom: 6px; display: block; }
320
- .achievement .t { font-size: 12px; font-weight: 500; }
321
- .achievement .s { font-size: 10.5px; color: var(--text-3); margin-top: 2px; }
263
+ .discord { background: #fff; border: 2px solid var(--ink); padding: 32px; box-shadow: var(--shadow); position: relative; }
264
+ .discord-h { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 24px; font-family: var(--font-mono); font-weight: 700; }
265
+ .discord-h .t { font-size: 14px; text-transform: uppercase; border-bottom: 2px solid var(--rust); padding-bottom: 4px; }
266
+ .live-frame { padding: 24px 0; border-top: 2px solid var(--ink); border-bottom: 2px dashed var(--ink); }
267
+ .live-frame .label-tag { font-family: var(--font-mono); font-size: 11px; font-weight: 700; background: var(--grass); color: #fff; padding: 4px 8px; border: 1.5px solid var(--ink); box-shadow: 2px 2px 0 var(--ink); display: inline-block; margin-bottom: 12px; transform: rotate(-2deg); }
268
+ .live-frame .label-tag::before { display: none; }
269
+ .live-frame .details { font-family: var(--font-disp); font-size: 24px; font-weight: 700; margin-bottom: 4px; }
270
+ .live-frame .state { font-family: var(--font-mono); font-size: 13px; color: var(--ink-soft); font-weight: 600; }
271
+ .rotation-list { list-style: none; margin-top: 24px; display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px 24px; font-family: var(--font-mono); font-size: 12px; font-weight: 700; }
272
+ .rotation-list li { display: flex; align-items: center; gap: 10px; color: var(--ink-soft); }
273
+ .rotation-list li .pip { width: 8px; height: 8px; background: var(--paper-dark); border: 1.5px solid var(--ink); flex-shrink: 0; }
274
+ .rotation-list li.live .pip { background: var(--grass); }
275
+ .rotation-list li.current { color: var(--ink); }
276
+ .rotation-list li.current .pip { background: var(--ink); box-shadow: 2px 2px 0 var(--ink); }
277
+
278
+ /* ── Achievements, Insights, Modals ─────────────────── */
279
+ .achievements { display: grid; grid-template-columns: repeat(6, 1fr); gap: 16px; margin-bottom: 48px; }
280
+ .achievement { background: #fff; border: 2px dashed var(--ink-faint); padding: 16px; text-align: center; opacity: 0.5; transition: all 0.2s; }
281
+ .achievement.unlocked { opacity: 1; border: 2px solid var(--ink); box-shadow: var(--shadow); transform: rotate(1deg); }
282
+ .achievement .ico { font-size: 24px; margin-bottom: 8px; display: block; }
283
+ .achievement .t { font-family: var(--font-mono); font-size: 12px; font-weight: 700; text-transform: uppercase; margin-bottom: 4px; }
284
+ .achievement .s { font-size: 11px; color: var(--ink-mute); }
285
+
286
+ .insights { background: #fff; border: 2px solid var(--ink); padding: 24px; margin-bottom: 48px; box-shadow: var(--shadow); display: grid; gap: 12px; }
287
+ .insights .insight { display: flex; align-items: baseline; gap: 12px; font-family: var(--font-mono); font-size: 13px; font-weight: 600; }
288
+ .insights .insight::before { content: '→'; color: var(--rust); font-weight: 700; }
289
+
290
+ .scrim { position: fixed; inset: 0; background: rgba(26,22,17,0.4); backdrop-filter: blur(2px); display: none; z-index: 50; }
291
+ .scrim.open { display: block; }
292
+ .drawer { position: fixed; top: 0; right: 0; bottom: 0; width: 480px; max-width: 100%; background: var(--paper); border-left: 2px solid var(--ink); transform: translateX(100%); transition: transform 0.2s ease; z-index: 60; padding: 40px; overflow-y: auto; box-shadow: -10px 0 30px rgba(0,0,0,0.1); }
293
+ .drawer.open { transform: translateX(0); }
294
+ .drawer h3 { font-family: var(--font-disp); font-size: 28px; margin-bottom: 8px; }
295
+ .drawer .sub { font-family: var(--font-mono); color: var(--ink-mute); font-weight: 700; margin-bottom: 32px; }
296
+
297
+ .modal { position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.96); background: var(--paper); border: 2px solid var(--ink); padding: 40px; box-shadow: 10px 10px 0 var(--ink); z-index: 60; opacity: 0; pointer-events: none; transition: all 0.2s; }
298
+ .modal.open { opacity: 1; transform: translate(-50%, -50%) scale(1); pointer-events: auto; }
299
+ .modal h4 { font-family: var(--font-disp); font-size: 24px; margin-bottom: 8px; }
300
+
301
+ footer { margin-top: 60px; padding-top: 32px; border-top: 2px dashed var(--ink); display: flex; justify-content: space-between; align-items: center; font-family: var(--font-mono); font-weight: 700; font-size: 12px; color: var(--ink-mute); }
302
+ footer .pulse-dot { background: var(--grass); border: 1.5px solid var(--ink); }
322
303
 
323
304
  /* ── Heatmap ─────────────────────────────────────────── */
324
305
  .heatmap-card { padding: 20px 22px; }
@@ -328,55 +309,16 @@ section { margin-bottom: 28px; }
328
309
  display: grid; grid-auto-flow: column; grid-template-rows: repeat(7, 12px); gap: 3px;
329
310
  font-size: 0;
330
311
  }
331
- .heatmap .cell { width: 12px; height: 12px; border-radius: 2px; background: rgba(255,255,255,0.04); cursor: pointer; transition: transform 0.1s; }
312
+ .heatmap .cell { width: 12px; height: 12px; border-radius: 2px; background: rgba(0,0,0,0.06); cursor: pointer; transition: transform 0.1s; }
332
313
  .heatmap .cell:hover { transform: scale(1.4); outline: 1px solid var(--text); }
333
314
 
334
- /* ── Drawer / modal ─────────────────────────────────── */
335
- .scrim { position: fixed; inset: 0; background: rgba(0,0,0,0.55); display: none; z-index: 50; }
336
- .scrim.open { display: block; }
337
- .drawer {
338
- position: fixed; top: 0; right: 0; bottom: 0; width: 480px; max-width: 100%;
339
- background: var(--bg); border-left: 1px solid var(--border);
340
- transform: translateX(100%); transition: transform 0.22s ease;
341
- z-index: 60; padding: 32px 28px; overflow-y: auto;
342
- }
343
- .drawer.open { transform: translateX(0); }
344
- .drawer .close { position: absolute; top: 20px; right: 22px; font-size: 22px; color: var(--text-3); }
345
- .drawer h3 { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; margin-bottom: 6px; }
346
- .drawer .sub { color: var(--text-3); font-size: 13px; margin-bottom: 22px; }
347
- .drawer .grid { display: grid; gap: 12px; }
348
- .drawer .kv { display: flex; justify-content: space-between; font-size: 13px; padding: 8px 0; border-bottom: 1px solid var(--border); }
349
- .drawer .kv .k { color: var(--text-3); }
350
- .drawer .kv .v { color: var(--text); font-weight: 500; }
351
-
352
- .modal {
353
- position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%) scale(0.96);
354
- background: var(--bg); border: 1px solid var(--border-strong); border-radius: 14px;
355
- padding: 28px 32px; min-width: 360px; max-width: 480px;
356
- z-index: 60; opacity: 0; pointer-events: none; transition: opacity 0.18s, transform 0.18s;
357
- }
358
- .modal.open { opacity: 1; transform: translate(-50%, -50%) scale(1); pointer-events: auto; }
359
- .modal .close { position: absolute; top: 14px; right: 16px; font-size: 22px; color: var(--text-3); }
360
- .modal h4 { font-size: 18px; font-weight: 600; margin-bottom: 6px; }
361
- .modal .sub { color: var(--text-3); font-size: 12px; margin-bottom: 18px; }
362
-
363
- footer {
364
- margin-top: 36px; padding-top: 22px;
365
- border-top: 1px solid var(--border);
366
- display: flex; justify-content: space-between; align-items: center;
367
- font-size: 12px; color: var(--text-3);
368
- }
369
- footer .pulse { display: inline-flex; align-items: center; gap: 6px; }
370
- footer .pulse-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--green); opacity: 0.6; }
371
- footer a:hover { color: var(--text-2); }
372
-
373
315
  /* ── Help overlay ────────────────────────────────────── */
374
- .help { position: fixed; inset: 0; background: rgba(0,0,0,0.7); display: none; z-index: 70; align-items: center; justify-content: center; }
316
+ .help { position: fixed; inset: 0; background: rgba(26,22,17,0.7); display: none; z-index: 70; align-items: center; justify-content: center; }
375
317
  .help.open { display: flex; }
376
- .help-card { background: var(--bg); border: 1px solid var(--border-strong); border-radius: 14px; padding: 28px 32px; max-width: 420px; width: 90%; }
377
- .help-card h4 { font-size: 16px; margin-bottom: 16px; }
378
- .help-card .kbd { display: inline-block; padding: 2px 6px; border: 1px solid var(--border-strong); border-radius: 4px; font-size: 11px; font-family: monospace; margin-right: 8px; }
379
- .help-card .row { display: flex; padding: 6px 0; border-top: 1px solid var(--border); font-size: 13px; color: var(--text-2); }
318
+ .help-card { background: var(--paper); border: 2px solid var(--ink); box-shadow: var(--shadow); padding: 28px 32px; max-width: 420px; width: 90%; }
319
+ .help-card h4 { font-family: var(--font-disp); font-size: 20px; margin-bottom: 16px; }
320
+ .help-card .kbd { display: inline-block; padding: 2px 6px; border: 1.5px solid var(--ink); background: #fff; font-size: 11px; font-family: var(--font-mono); margin-right: 8px; font-weight: 700; box-shadow: 1.5px 1.5px 0 var(--ink); }
321
+ .help-card .row { display: flex; padding: 8px 0; border-top: 1.5px dashed var(--ink-faint); font-family: var(--font-mono); font-size: 12px; font-weight: 700; color: var(--ink-soft); }
380
322
  .help-card .row:first-of-type { border-top: 0; }
381
323
  .help-card .keys { width: 110px; }
382
324
 
package/src/version.js CHANGED
@@ -11,7 +11,7 @@ import { readFileSync } from 'node:fs';
11
11
  import { join } from 'node:path';
12
12
  import { ROOT } from './paths.js';
13
13
 
14
- const BAKED = '0.7.1';
14
+ const BAKED = '0.7.2';
15
15
 
16
16
  function readPkgVersion() {
17
17
  try {