clauddy 1.15.0 → 1.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/renderer/index.html +28 -66
- package/renderer/pet.js +64 -8
- package/renderer/style.css +198 -62
package/package.json
CHANGED
package/renderer/index.html
CHANGED
|
@@ -240,6 +240,7 @@
|
|
|
240
240
|
<div class="divider"></div>
|
|
241
241
|
|
|
242
242
|
<!-- session + weekly (real usage; needs login) -->
|
|
243
|
+
<div id="home-success" hidden>✓ Logged in — your real usage is live</div>
|
|
243
244
|
<div id="limits">
|
|
244
245
|
<div id="limits-meters">
|
|
245
246
|
<div class="meter">
|
|
@@ -303,91 +304,52 @@
|
|
|
303
304
|
|
|
304
305
|
<!-- settings panel -->
|
|
305
306
|
<div id="settings">
|
|
306
|
-
<div class="set-title">Settings</div>
|
|
307
|
-
|
|
308
307
|
<div id="account">
|
|
309
308
|
<div id="acc-disconnected">
|
|
310
|
-
<div class="set-hint">Connect your account to show your real usage
|
|
309
|
+
<div class="set-hint set-hint-left">Connect your Claude account to show your real usage.</div>
|
|
311
310
|
<button id="acc-connect" class="acc-btn">Log in with browser</button>
|
|
312
311
|
<div id="acc-paste">
|
|
313
|
-
<div class="set-hint">
|
|
312
|
+
<div class="set-hint set-hint-left">Paste the code from the browser page:</div>
|
|
314
313
|
<input id="acc-code" type="text" placeholder="authentication code" />
|
|
315
314
|
<button id="acc-confirm" class="acc-btn">Connect</button>
|
|
316
315
|
<div id="acc-msg"></div>
|
|
317
316
|
</div>
|
|
318
317
|
</div>
|
|
319
318
|
<div id="acc-connected">
|
|
320
|
-
<span class="acc-ok">● Connected
|
|
319
|
+
<span class="acc-ok" id="acc-ok">● Connected</span>
|
|
321
320
|
<button id="acc-logout" class="acc-link">Disconnect</button>
|
|
322
321
|
</div>
|
|
323
322
|
</div>
|
|
324
323
|
|
|
325
|
-
<div
|
|
326
|
-
<div class="set-
|
|
327
|
-
|
|
328
|
-
<
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
</div>
|
|
332
|
-
|
|
333
|
-
<div class="set-section">
|
|
334
|
-
<div class="set-sec-title">Zoom</div>
|
|
335
|
-
<div class="set-thresholds">
|
|
336
|
-
<span class="thr">
|
|
337
|
-
<span class="thr-cap">size</span>
|
|
338
|
-
<span class="num">
|
|
339
|
-
<input id="set-zoom" type="number" min="100" max="200" step="25" />
|
|
340
|
-
<span class="num-spin">
|
|
341
|
-
<button type="button" class="num-btn" data-for="set-zoom" data-step="25">▲</button>
|
|
342
|
-
<button type="button" class="num-btn" data-for="set-zoom" data-step="-25">▼</button>
|
|
343
|
-
</span>
|
|
344
|
-
</span>
|
|
324
|
+
<div id="set-rows">
|
|
325
|
+
<div class="set-row">
|
|
326
|
+
<span class="set-row-label">Display</span>
|
|
327
|
+
<span class="seg" id="set-mode">
|
|
328
|
+
<button type="button" class="seg-btn" data-mode="floating">Floating pet</button>
|
|
329
|
+
<button type="button" class="seg-btn" data-mode="menubar">Menu bar</button>
|
|
345
330
|
</span>
|
|
346
331
|
</div>
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
<div class="set-section">
|
|
350
|
-
<div class="set-sec-title">
|
|
351
|
-
Alerts
|
|
332
|
+
<div class="set-row">
|
|
333
|
+
<span class="set-row-label">Alerts</span>
|
|
352
334
|
<input id="set-alerts" class="set-toggle" type="checkbox" aria-label="Enable alerts" />
|
|
353
335
|
</div>
|
|
354
|
-
<div class="set-
|
|
355
|
-
<
|
|
356
|
-
<span class="
|
|
357
|
-
<span class="num">
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
</span>
|
|
364
|
-
</span>
|
|
365
|
-
<span class="thr">
|
|
366
|
-
<span class="thr-cap">near limit</span>
|
|
367
|
-
<span class="num">
|
|
368
|
-
<input id="set-t2" type="number" min="1" max="100" />
|
|
369
|
-
<span class="num-spin">
|
|
370
|
-
<button type="button" class="num-btn" data-for="set-t2" data-step="1">▲</button>
|
|
371
|
-
<button type="button" class="num-btn" data-for="set-t2" data-step="-1">▼</button>
|
|
372
|
-
</span>
|
|
373
|
-
</span>
|
|
374
|
-
</span>
|
|
336
|
+
<div class="set-subgroup">
|
|
337
|
+
<div class="set-row set-sub">
|
|
338
|
+
<span class="set-row-label sub-label">heads-up</span>
|
|
339
|
+
<span class="num"><button type="button" class="num-btn" data-for="set-t1" data-step="-1">−</button><span class="num-val"><input id="set-t1" type="number" min="1" max="100" step="1" /><i>%</i></span><button type="button" class="num-btn" data-for="set-t1" data-step="1">+</button></span>
|
|
340
|
+
</div>
|
|
341
|
+
<div class="set-row set-sub">
|
|
342
|
+
<span class="set-row-label sub-label">near limit</span>
|
|
343
|
+
<span class="num"><button type="button" class="num-btn" data-for="set-t2" data-step="-1">−</button><span class="num-val"><input id="set-t2" type="number" min="1" max="100" step="1" /><i>%</i></span><button type="button" class="num-btn" data-for="set-t2" data-step="1">+</button></span>
|
|
344
|
+
</div>
|
|
375
345
|
</div>
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
<div class="set-
|
|
381
|
-
<span class="
|
|
382
|
-
|
|
383
|
-
<span class="num">
|
|
384
|
-
<input id="set-fire" type="number" min="1" max="99" />
|
|
385
|
-
<span class="num-spin">
|
|
386
|
-
<button type="button" class="num-btn" data-for="set-fire" data-step="1">▲</button>
|
|
387
|
-
<button type="button" class="num-btn" data-for="set-fire" data-step="-1">▼</button>
|
|
388
|
-
</span>
|
|
389
|
-
</span>
|
|
390
|
-
</span>
|
|
346
|
+
<div class="set-row">
|
|
347
|
+
<span class="set-row-label">Catch fire<i class="set-row-hint">at this session %</i></span>
|
|
348
|
+
<span class="num"><button type="button" class="num-btn" data-for="set-fire" data-step="-1">−</button><span class="num-val"><input id="set-fire" type="number" min="1" max="99" step="1" /><i>%</i></span><button type="button" class="num-btn" data-for="set-fire" data-step="1">+</button></span>
|
|
349
|
+
</div>
|
|
350
|
+
<div class="set-row">
|
|
351
|
+
<span class="set-row-label">Zoom</span>
|
|
352
|
+
<span class="num"><button type="button" class="num-btn" data-for="set-zoom" data-step="-25">−</button><span class="num-val"><input id="set-zoom" type="number" min="100" max="200" step="25" /><i>%</i></span><button type="button" class="num-btn" data-for="set-zoom" data-step="25">+</button></span>
|
|
391
353
|
</div>
|
|
392
354
|
</div>
|
|
393
355
|
|
package/renderer/pet.js
CHANGED
|
@@ -89,9 +89,9 @@ const SPRITE = [
|
|
|
89
89
|
}
|
|
90
90
|
// clouds (blocky, dark gray)
|
|
91
91
|
const cloud = (x, y, b, m, t) => {
|
|
92
|
-
add('rect', { x: x + 12, y: y, width: t, height: 9, fill: '#3a3a3a' })
|
|
93
|
-
add('rect', { x: x + 5, y: y + 7, width: m, height: 9, fill: '#3a3a3a' })
|
|
94
|
-
add('rect', { x: x, y: y + 14, width: b, height: 10, fill: '#3a3a3a' })
|
|
92
|
+
add('rect', { x: x + 12, y: y, width: t, height: 9, fill: '#3a3a3a', class: 'cloud' })
|
|
93
|
+
add('rect', { x: x + 5, y: y + 7, width: m, height: 9, fill: '#3a3a3a', class: 'cloud' })
|
|
94
|
+
add('rect', { x: x, y: y + 14, width: b, height: 10, fill: '#3a3a3a', class: 'cloud' })
|
|
95
95
|
}
|
|
96
96
|
cloud(16, 10, 58, 42, 22)
|
|
97
97
|
cloud(120, 50, 40, 28, 15)
|
|
@@ -162,6 +162,19 @@ function fmtReset(ms) {
|
|
|
162
162
|
const m = Math.floor((ms % 3600000) / 60000)
|
|
163
163
|
return h > 0 ? `${h}h ${m}m` : `${m}m`
|
|
164
164
|
}
|
|
165
|
+
// wall-clock time of the reset, in the machine's own locale + timezone.
|
|
166
|
+
// Past 24h the day matters too, so prefix the weekday.
|
|
167
|
+
function fmtResetClock(ms) {
|
|
168
|
+
if (!ms || ms <= 0) return null
|
|
169
|
+
const at = new Date(Date.now() + ms)
|
|
170
|
+
const time = at.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })
|
|
171
|
+
return ms >= 86400000 ? `${at.toLocaleDateString([], { weekday: 'short' })} ${time}` : time
|
|
172
|
+
}
|
|
173
|
+
// "2h 22m (14:35)" — countdown plus the clock time it lands on
|
|
174
|
+
function fmtResetIn(ms) {
|
|
175
|
+
const at = fmtResetClock(ms)
|
|
176
|
+
return at ? `${fmtReset(ms)} (${at})` : fmtReset(ms)
|
|
177
|
+
}
|
|
165
178
|
// burn-rate projection lives in burn.js (shared with the tests)
|
|
166
179
|
const burn = Burn.createBurnTracker()
|
|
167
180
|
|
|
@@ -420,7 +433,7 @@ function renderScoped(list, byModel) {
|
|
|
420
433
|
m.innerHTML =
|
|
421
434
|
`<div class="meter-top"><span>weekly · ${esc(key)}</span><span>${Math.round(s.pct)}%</span></div>` +
|
|
422
435
|
`<div class="track"><div class="fill week${s.pct >= 80 ? ' high' : ''}" style="width:${s.pct}%"></div></div>` +
|
|
423
|
-
`<div class="sub">${s.resetMs != null ? `resets in ${
|
|
436
|
+
`<div class="sub">${s.resetMs != null ? `resets in ${fmtResetIn(s.resetMs)} · ` : ''}${fmtTokens(tokens)} tokens</div>`
|
|
424
437
|
box.appendChild(m)
|
|
425
438
|
}
|
|
426
439
|
}
|
|
@@ -568,7 +581,7 @@ function render(d) {
|
|
|
568
581
|
sf.style.width = `${sessPct}%`
|
|
569
582
|
sf.classList.toggle('high', sessPct >= 80)
|
|
570
583
|
el('session-sub').textContent = sessActive
|
|
571
|
-
? `resets in ${
|
|
584
|
+
? `resets in ${fmtResetIn(sessReset)} · ${fmtTokens(d.session.tokens)} tokens`
|
|
572
585
|
: 'no active session'
|
|
573
586
|
|
|
574
587
|
// where this pace is taking you — hidden until there's enough trail to tell
|
|
@@ -589,7 +602,7 @@ function render(d) {
|
|
|
589
602
|
wf.classList.toggle('high', wkPct >= 80)
|
|
590
603
|
el('week-sub').textContent =
|
|
591
604
|
wkReset != null
|
|
592
|
-
? `resets in ${
|
|
605
|
+
? `resets in ${fmtResetIn(wkReset)} · ${fmtTokens(d.week.tokens)} tokens`
|
|
593
606
|
: `${fmtTokens(d.week.tokens)} tokens · last 7 days`
|
|
594
607
|
|
|
595
608
|
renderScoped(liveOn ? realUsage.scoped || [] : [], d.byModel || [])
|
|
@@ -677,6 +690,10 @@ window.api.onAuthState((s) => {
|
|
|
677
690
|
|
|
678
691
|
// logged-in account chip (email + plan) shown top-left when connected
|
|
679
692
|
function showProfile(p) {
|
|
693
|
+
// the settings line says who is connected, not just that someone is
|
|
694
|
+
el('acc-ok').textContent = p?.email
|
|
695
|
+
? `● ${p.email}${p.plan ? ` · ${p.plan}` : ''}`
|
|
696
|
+
: '● Connected'
|
|
680
697
|
const chip = el('account-chip')
|
|
681
698
|
const mini = el('mini-acct')
|
|
682
699
|
if (!p?.email) {
|
|
@@ -703,11 +720,23 @@ function setPlan(node, plan) {
|
|
|
703
720
|
}
|
|
704
721
|
}
|
|
705
722
|
window.api.onProfile(showProfile)
|
|
723
|
+
let successTimer = null
|
|
706
724
|
window.api.onAuthResult((r) => {
|
|
707
725
|
if (r?.ok) {
|
|
708
726
|
el('acc-msg').textContent = ''
|
|
709
727
|
el('acc-code').value = ''
|
|
710
728
|
el('acc-paste').classList.remove('show')
|
|
729
|
+
// logging in is done: land back on the home panel, where the fresh live
|
|
730
|
+
// meters show up under a short-lived cheer — and the pet throws confetti
|
|
731
|
+
document.body.classList.remove('settings-open')
|
|
732
|
+
clearSaveDirty()
|
|
733
|
+
el('home-success').hidden = false
|
|
734
|
+
clearTimeout(successTimer)
|
|
735
|
+
successTimer = setTimeout(() => {
|
|
736
|
+
el('home-success').hidden = true
|
|
737
|
+
fitSize()
|
|
738
|
+
}, 6000)
|
|
739
|
+
celebrate()
|
|
711
740
|
} else {
|
|
712
741
|
const e = r?.error || ''
|
|
713
742
|
el('acc-msg').textContent = /429|rate_limit/i.test(e)
|
|
@@ -770,6 +799,10 @@ el('acc-connect').addEventListener('click', () => {
|
|
|
770
799
|
el('acc-paste').classList.add('show') // reveal the code field
|
|
771
800
|
fitSize()
|
|
772
801
|
})
|
|
802
|
+
// the Connect button only lights up once there's a code to submit
|
|
803
|
+
el('acc-code').addEventListener('input', () => {
|
|
804
|
+
el('acc-confirm').classList.toggle('ready', !!el('acc-code').value.trim())
|
|
805
|
+
})
|
|
773
806
|
el('acc-confirm').addEventListener('click', () => {
|
|
774
807
|
const code = el('acc-code').value.trim()
|
|
775
808
|
if (!code) return
|
|
@@ -848,16 +881,34 @@ function snapshotSettings() {
|
|
|
848
881
|
}
|
|
849
882
|
function refreshSaveDirty() {
|
|
850
883
|
if (settingsBaseline == null) return
|
|
851
|
-
|
|
884
|
+
const dirty = snapshotSettings() !== settingsBaseline
|
|
885
|
+
const b = el('set-save')
|
|
886
|
+
b.classList.toggle('dirty', dirty)
|
|
887
|
+
b.disabled = !dirty // nothing to save, nothing to click
|
|
852
888
|
}
|
|
853
889
|
function clearSaveDirty() {
|
|
854
890
|
settingsBaseline = snapshotSettings()
|
|
855
|
-
el('set-save')
|
|
891
|
+
const b = el('set-save')
|
|
892
|
+
b.classList.remove('dirty')
|
|
893
|
+
b.disabled = true
|
|
894
|
+
}
|
|
895
|
+
function reflectAlertsOn() {
|
|
896
|
+
el('set-rows').classList.toggle('alerts-off', !el('set-alerts').checked)
|
|
897
|
+
}
|
|
898
|
+
// zoom applies as you step it, so the widget shows the size right away;
|
|
899
|
+
// Cancel puts the saved value back
|
|
900
|
+
function previewZoom() {
|
|
901
|
+
const v = Number.parseFloat(el('set-zoom').value)
|
|
902
|
+
if (v >= 100 && v <= 200) {
|
|
903
|
+
applyZoom(v)
|
|
904
|
+
fitSize()
|
|
905
|
+
}
|
|
856
906
|
}
|
|
857
907
|
function populateSettings() {
|
|
858
908
|
const c = currentConfig || {}
|
|
859
909
|
setModeUI(c.mode)
|
|
860
910
|
el('set-alerts').checked = c.alerts !== false
|
|
911
|
+
reflectAlertsOn()
|
|
861
912
|
const th = c.alertThresholds || [80, 95]
|
|
862
913
|
el('set-t1').value = th[0] != null ? th[0] : 80
|
|
863
914
|
el('set-t2').value = th[1] != null ? th[1] : 95
|
|
@@ -883,6 +934,7 @@ for (const b of document.querySelectorAll('.num-btn')) {
|
|
|
883
934
|
const next = (Number.parseInt(input.value, 10) || 0) + Number(b.dataset.step)
|
|
884
935
|
input.value = Math.min(max, Math.max(min, next))
|
|
885
936
|
refreshSaveDirty() // steppers change the value without an 'input' event
|
|
937
|
+
if (input.id === 'set-zoom') previewZoom()
|
|
886
938
|
})
|
|
887
939
|
}
|
|
888
940
|
// light up Save whenever an editable field changes
|
|
@@ -890,6 +942,8 @@ for (const id of ['set-alerts', 'set-t1', 'set-t2', 'set-fire', 'set-zoom']) {
|
|
|
890
942
|
el(id).addEventListener('input', refreshSaveDirty)
|
|
891
943
|
el(id).addEventListener('change', refreshSaveDirty)
|
|
892
944
|
}
|
|
945
|
+
el('set-alerts').addEventListener('change', reflectAlertsOn)
|
|
946
|
+
el('set-zoom').addEventListener('input', previewZoom)
|
|
893
947
|
// display-mode segmented control (floating pet | menu bar)
|
|
894
948
|
for (const b of document.querySelectorAll('#set-mode .seg-btn')) {
|
|
895
949
|
b.addEventListener('click', () => {
|
|
@@ -900,6 +954,7 @@ for (const b of document.querySelectorAll('#set-mode .seg-btn')) {
|
|
|
900
954
|
el('set-cancel').addEventListener('click', () => {
|
|
901
955
|
document.body.classList.remove('settings-open')
|
|
902
956
|
clearSaveDirty()
|
|
957
|
+
applyZoom(currentConfig?.zoom != null ? currentConfig.zoom : 100) // undo the preview
|
|
903
958
|
fitSize()
|
|
904
959
|
})
|
|
905
960
|
el('set-save').addEventListener('click', () => {
|
|
@@ -964,6 +1019,7 @@ if (typeof module === 'object' && module.exports) {
|
|
|
964
1019
|
render,
|
|
965
1020
|
fmtTokens,
|
|
966
1021
|
fmtReset,
|
|
1022
|
+
fmtResetIn,
|
|
967
1023
|
setState,
|
|
968
1024
|
renderModels,
|
|
969
1025
|
renderProjects,
|
package/renderer/style.css
CHANGED
|
@@ -221,13 +221,17 @@ body.settings-open #mini {
|
|
|
221
221
|
}
|
|
222
222
|
body.settings-open #settings {
|
|
223
223
|
display: block;
|
|
224
|
+
animation: set-in 0.18s ease;
|
|
224
225
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
226
|
+
@keyframes set-in {
|
|
227
|
+
from {
|
|
228
|
+
opacity: 0;
|
|
229
|
+
transform: translateY(4px);
|
|
230
|
+
}
|
|
231
|
+
to {
|
|
232
|
+
opacity: 1;
|
|
233
|
+
transform: none;
|
|
234
|
+
}
|
|
231
235
|
}
|
|
232
236
|
.set-hint {
|
|
233
237
|
font-size: 9px;
|
|
@@ -302,94 +306,168 @@ input[type="number"]::-webkit-outer-spin-button {
|
|
|
302
306
|
body.is-menubar #min {
|
|
303
307
|
display: none;
|
|
304
308
|
}
|
|
305
|
-
/* settings
|
|
306
|
-
|
|
307
|
-
.
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
.set-section + .set-section {
|
|
311
|
-
border-top: 0.5px solid var(--hair);
|
|
312
|
-
padding-top: 10px;
|
|
309
|
+
/* settings rows: label on the left, control on the right — one setting per
|
|
310
|
+
line so the screen stays short. Alert thresholds indent under their toggle
|
|
311
|
+
and dim while alerts are off. */
|
|
312
|
+
#set-rows {
|
|
313
|
+
margin-bottom: 10px; /* #account above already draws the divider */
|
|
313
314
|
}
|
|
314
|
-
.set-
|
|
315
|
+
.set-row {
|
|
315
316
|
display: flex;
|
|
316
317
|
align-items: center;
|
|
317
318
|
justify-content: space-between;
|
|
319
|
+
gap: 8px;
|
|
320
|
+
min-height: 34px;
|
|
321
|
+
border-bottom: 0.5px solid var(--hair);
|
|
322
|
+
}
|
|
323
|
+
/* the threshold pair lives in an inset card under its toggle row */
|
|
324
|
+
.set-row:has(+ .set-subgroup) {
|
|
325
|
+
border-bottom: none;
|
|
326
|
+
}
|
|
327
|
+
/* flat, but visibly nested: a soft coral guide bar ties the pair to the
|
|
328
|
+
toggle above, and each label hugs its own stepper */
|
|
329
|
+
.set-subgroup {
|
|
330
|
+
position: relative;
|
|
331
|
+
padding-left: 14px;
|
|
332
|
+
border-bottom: 0.5px solid var(--hair);
|
|
333
|
+
padding-bottom: 3px;
|
|
334
|
+
transition: opacity 0.15s;
|
|
335
|
+
}
|
|
336
|
+
.set-subgroup::before {
|
|
337
|
+
content: "";
|
|
338
|
+
position: absolute;
|
|
339
|
+
left: 3px;
|
|
340
|
+
top: 5px;
|
|
341
|
+
bottom: 10px;
|
|
342
|
+
width: 2px;
|
|
343
|
+
border-radius: 1px;
|
|
344
|
+
background: var(--coral);
|
|
345
|
+
opacity: 0.35;
|
|
346
|
+
}
|
|
347
|
+
.set-subgroup .set-row {
|
|
348
|
+
border-bottom: none;
|
|
349
|
+
justify-content: flex-end;
|
|
350
|
+
gap: 10px;
|
|
351
|
+
}
|
|
352
|
+
.set-row-label {
|
|
318
353
|
font-size: 11px;
|
|
319
354
|
font-weight: 600;
|
|
320
355
|
color: var(--text);
|
|
321
|
-
margin-bottom: 8px;
|
|
322
356
|
}
|
|
323
|
-
|
|
357
|
+
.set-row-hint {
|
|
358
|
+
display: block;
|
|
359
|
+
white-space: nowrap;
|
|
360
|
+
font-style: normal;
|
|
361
|
+
font-weight: 400;
|
|
362
|
+
font-size: 9px;
|
|
363
|
+
color: var(--muted);
|
|
364
|
+
margin-top: 2px;
|
|
365
|
+
}
|
|
366
|
+
.set-row.set-sub {
|
|
367
|
+
min-height: 31px;
|
|
368
|
+
}
|
|
369
|
+
.set-row.set-sub .set-row-label {
|
|
370
|
+
font-weight: 400;
|
|
371
|
+
font-size: 10.5px;
|
|
372
|
+
color: var(--muted);
|
|
373
|
+
}
|
|
374
|
+
#set-rows.alerts-off .set-subgroup {
|
|
375
|
+
opacity: 0.35;
|
|
376
|
+
pointer-events: none;
|
|
377
|
+
}
|
|
378
|
+
.set-row .seg {
|
|
379
|
+
margin-top: 0;
|
|
380
|
+
flex: none;
|
|
381
|
+
}
|
|
382
|
+
.set-row .seg-btn {
|
|
383
|
+
flex: none;
|
|
384
|
+
padding: 4px 9px;
|
|
385
|
+
}
|
|
386
|
+
/* alerts on/off pill switch (still an <input type=checkbox> underneath) */
|
|
324
387
|
.set-toggle {
|
|
388
|
+
appearance: none;
|
|
389
|
+
-webkit-appearance: none;
|
|
325
390
|
margin: 0;
|
|
326
|
-
width:
|
|
327
|
-
height:
|
|
328
|
-
|
|
391
|
+
width: 30px;
|
|
392
|
+
height: 18px;
|
|
393
|
+
border-radius: 9px;
|
|
394
|
+
background: rgba(255, 255, 255, 0.14);
|
|
395
|
+
position: relative;
|
|
329
396
|
cursor: pointer;
|
|
397
|
+
-webkit-app-region: no-drag;
|
|
398
|
+
transition: background 0.18s;
|
|
330
399
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
400
|
+
.set-toggle::after {
|
|
401
|
+
content: "";
|
|
402
|
+
position: absolute;
|
|
403
|
+
top: 2px;
|
|
404
|
+
left: 2px;
|
|
405
|
+
width: 14px;
|
|
406
|
+
height: 14px;
|
|
407
|
+
border-radius: 50%;
|
|
408
|
+
background: #fff;
|
|
409
|
+
opacity: 0.85;
|
|
410
|
+
transition:
|
|
411
|
+
left 0.18s,
|
|
412
|
+
opacity 0.18s;
|
|
336
413
|
}
|
|
337
|
-
.
|
|
338
|
-
|
|
339
|
-
flex-direction: column;
|
|
340
|
-
gap: 4px;
|
|
414
|
+
.set-toggle:checked {
|
|
415
|
+
background: var(--coral);
|
|
341
416
|
}
|
|
342
|
-
.
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
height: 12px;
|
|
346
|
-
line-height: 12px;
|
|
417
|
+
.set-toggle:checked::after {
|
|
418
|
+
left: 14px;
|
|
419
|
+
opacity: 1;
|
|
347
420
|
}
|
|
348
|
-
/* number field
|
|
421
|
+
/* number field: minus / value% / plus */
|
|
349
422
|
.num {
|
|
350
|
-
|
|
423
|
+
display: flex;
|
|
424
|
+
align-items: center;
|
|
425
|
+
gap: 4px;
|
|
351
426
|
flex: none;
|
|
352
|
-
width: 66px;
|
|
353
427
|
}
|
|
354
|
-
.num
|
|
428
|
+
.num-val {
|
|
429
|
+
position: relative;
|
|
430
|
+
width: 54px;
|
|
431
|
+
}
|
|
432
|
+
.num-val input {
|
|
355
433
|
width: 100%;
|
|
356
434
|
background: rgba(255, 255, 255, 0.06);
|
|
357
435
|
border: 0.5px solid var(--hair);
|
|
358
|
-
border-radius:
|
|
436
|
+
border-radius: 7px;
|
|
359
437
|
color: var(--text);
|
|
360
|
-
font-size:
|
|
438
|
+
font-size: 12px;
|
|
361
439
|
font-weight: 600;
|
|
362
440
|
font-variant-numeric: tabular-nums;
|
|
363
|
-
|
|
441
|
+
text-align: right;
|
|
442
|
+
padding: 4px 20px 4px 6px;
|
|
364
443
|
outline: none;
|
|
365
444
|
transition:
|
|
366
445
|
border-color 0.15s,
|
|
367
446
|
background 0.15s;
|
|
368
447
|
}
|
|
369
|
-
.num input:focus {
|
|
448
|
+
.num-val input:focus {
|
|
370
449
|
border-color: var(--coral);
|
|
371
450
|
background: rgba(255, 255, 255, 0.09);
|
|
372
451
|
}
|
|
373
|
-
.num-
|
|
452
|
+
.num-val i {
|
|
374
453
|
position: absolute;
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
gap: 2px;
|
|
454
|
+
right: 7px;
|
|
455
|
+
top: 50%;
|
|
456
|
+
transform: translateY(-50%);
|
|
457
|
+
font-style: normal;
|
|
458
|
+
font-size: 10px;
|
|
459
|
+
color: var(--muted);
|
|
460
|
+
pointer-events: none;
|
|
383
461
|
}
|
|
384
462
|
.num-btn {
|
|
385
463
|
-webkit-app-region: no-drag;
|
|
386
464
|
border: none;
|
|
387
465
|
background: rgba(255, 255, 255, 0.1);
|
|
388
466
|
color: var(--muted);
|
|
389
|
-
width:
|
|
390
|
-
height:
|
|
391
|
-
border-radius:
|
|
392
|
-
font-size:
|
|
467
|
+
width: 20px;
|
|
468
|
+
height: 20px;
|
|
469
|
+
border-radius: 6px;
|
|
470
|
+
font-size: 12px;
|
|
393
471
|
line-height: 1;
|
|
394
472
|
display: flex;
|
|
395
473
|
align-items: center;
|
|
@@ -432,7 +510,7 @@ body.is-menubar #min {
|
|
|
432
510
|
background 0.18s,
|
|
433
511
|
transform 0.1s;
|
|
434
512
|
}
|
|
435
|
-
.set-actions button:active {
|
|
513
|
+
.set-actions button:active:not(:disabled) {
|
|
436
514
|
transform: scale(0.97);
|
|
437
515
|
}
|
|
438
516
|
#set-cancel {
|
|
@@ -443,10 +521,18 @@ body.is-menubar #min {
|
|
|
443
521
|
background: rgba(255, 255, 255, 0.2);
|
|
444
522
|
}
|
|
445
523
|
#set-save {
|
|
446
|
-
background: rgba(
|
|
524
|
+
background: rgba(255, 255, 255, 0.12); /* rests like Cancel; dirty lights it */
|
|
525
|
+
color: var(--text);
|
|
526
|
+
}
|
|
527
|
+
#set-save:disabled {
|
|
528
|
+
opacity: 0.45;
|
|
529
|
+
cursor: default;
|
|
530
|
+
}
|
|
531
|
+
#set-save.dirty,
|
|
532
|
+
#set-save.dirty:hover {
|
|
447
533
|
color: #fff;
|
|
448
534
|
}
|
|
449
|
-
#set-save:hover {
|
|
535
|
+
#set-save.dirty:hover {
|
|
450
536
|
background: #e2876a;
|
|
451
537
|
}
|
|
452
538
|
/* unsaved changes: light up and pulse so you don't forget to save */
|
|
@@ -562,6 +648,10 @@ body.live .live-only {
|
|
|
562
648
|
opacity: 0.5;
|
|
563
649
|
cursor: default;
|
|
564
650
|
}
|
|
651
|
+
#acc-confirm:not(.ready) {
|
|
652
|
+
background: rgba(255, 255, 255, 0.12);
|
|
653
|
+
color: var(--muted);
|
|
654
|
+
}
|
|
565
655
|
.acc-link {
|
|
566
656
|
border: none;
|
|
567
657
|
background: none;
|
|
@@ -580,11 +670,18 @@ body.live .live-only {
|
|
|
580
670
|
color: var(--green);
|
|
581
671
|
font-size: 11px;
|
|
582
672
|
font-weight: 600;
|
|
673
|
+
flex: 1;
|
|
674
|
+
min-width: 0;
|
|
675
|
+
overflow: hidden;
|
|
676
|
+
text-overflow: ellipsis;
|
|
677
|
+
white-space: nowrap;
|
|
583
678
|
}
|
|
584
679
|
#acc-connected {
|
|
585
680
|
display: none;
|
|
586
681
|
align-items: center;
|
|
587
682
|
justify-content: space-between;
|
|
683
|
+
gap: 10px; /* the email ellipsizes instead of touching Disconnect */
|
|
684
|
+
flex-wrap: wrap; /* the success line drops to its own row */
|
|
588
685
|
}
|
|
589
686
|
#acc-paste {
|
|
590
687
|
display: none;
|
|
@@ -616,6 +713,16 @@ body.auth-on #acc-connected {
|
|
|
616
713
|
display: flex;
|
|
617
714
|
}
|
|
618
715
|
|
|
716
|
+
/* just logged in: a short-lived green cheer at the top of the home panel */
|
|
717
|
+
#home-success {
|
|
718
|
+
font-size: 10px;
|
|
719
|
+
font-weight: 600;
|
|
720
|
+
color: var(--green);
|
|
721
|
+
text-align: center;
|
|
722
|
+
margin-bottom: 8px;
|
|
723
|
+
animation: set-in 0.18s ease;
|
|
724
|
+
}
|
|
725
|
+
|
|
619
726
|
/* limits: real meters when connected, a "connect" prompt otherwise */
|
|
620
727
|
#limits-connect {
|
|
621
728
|
display: flex;
|
|
@@ -775,6 +882,24 @@ body.settings-open #min {
|
|
|
775
882
|
|
|
776
883
|
/* pet */
|
|
777
884
|
/* expanded: a little night scene */
|
|
885
|
+
body.settings-open #stage {
|
|
886
|
+
height: 100px;
|
|
887
|
+
}
|
|
888
|
+
/* the ground layers stretch to fill the stage; while it's shortened, pin them
|
|
889
|
+
at their natural height so the gears stay round — the top just clips away.
|
|
890
|
+
#scene keeps stretching (dots and stars tolerate it) so its frame rows stay
|
|
891
|
+
at the edges; the blocky clouds don't, so they sit this screen out. */
|
|
892
|
+
body.settings-open #gears {
|
|
893
|
+
top: auto;
|
|
894
|
+
bottom: 0;
|
|
895
|
+
height: 132px;
|
|
896
|
+
}
|
|
897
|
+
body.settings-open .cloud {
|
|
898
|
+
display: none;
|
|
899
|
+
}
|
|
900
|
+
body.settings-open #pet {
|
|
901
|
+
zoom: 0.65;
|
|
902
|
+
}
|
|
778
903
|
#stage {
|
|
779
904
|
position: relative;
|
|
780
905
|
height: 132px;
|
|
@@ -908,10 +1033,17 @@ body.settings-open #robot,
|
|
|
908
1033
|
body.settings-open #gears {
|
|
909
1034
|
opacity: 1;
|
|
910
1035
|
}
|
|
911
|
-
/* declutter the scene while configuring
|
|
1036
|
+
/* declutter the scene while configuring: mood marks AND activity props —
|
|
1037
|
+
the shortened stage only fits the pet and its gears */
|
|
912
1038
|
body.settings-open #zzz,
|
|
913
1039
|
body.settings-open #flames,
|
|
914
|
-
body.settings-open #sweat
|
|
1040
|
+
body.settings-open #sweat,
|
|
1041
|
+
body.settings-open #terminal,
|
|
1042
|
+
body.settings-open #reading,
|
|
1043
|
+
body.settings-open #mug,
|
|
1044
|
+
body.settings-open #desk,
|
|
1045
|
+
body.settings-open #plant,
|
|
1046
|
+
body.settings-open #glasses {
|
|
915
1047
|
display: none;
|
|
916
1048
|
}
|
|
917
1049
|
/* reading mode: an open book with a magnifying glass scanning the lines */
|
|
@@ -1612,10 +1744,14 @@ body.state-tired #status-text {
|
|
|
1612
1744
|
|
|
1613
1745
|
/* meter subtitle */
|
|
1614
1746
|
.sub {
|
|
1615
|
-
|
|
1747
|
+
/* small enough that "resets in 69h 15m (Fri 7:01 AM) · 1.02B tokens" stays on one line */
|
|
1748
|
+
font-size: 9px;
|
|
1616
1749
|
color: var(--muted);
|
|
1617
1750
|
margin-top: 4px;
|
|
1618
|
-
letter-spacing:
|
|
1751
|
+
letter-spacing: 0px;
|
|
1752
|
+
white-space: nowrap;
|
|
1753
|
+
overflow: hidden;
|
|
1754
|
+
text-overflow: ellipsis;
|
|
1619
1755
|
}
|
|
1620
1756
|
|
|
1621
1757
|
/* burn-rate projection — calm by default, warm when you'd run out first */
|