@leftoff/cli 0.9.17-beta.4 → 0.9.17-beta.6
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/CHANGELOG.md +2 -0
- package/bin/leftoff.js +28 -28
- package/mod/.claude-plugin/plugin.json +1 -1
- package/mod/hooks/register.js +1 -1
- package/package.json +1 -1
- package/ui/app.css +121 -20
- package/ui/app.js +277 -22
- package/ui/icons.js +9 -0
- package/ui/index.html +16 -12
- package/ui/live-view.js +2 -0
- package/ui/navrail.js +99 -0
- package/ui/semdiff.js +73 -20
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leftoff",
|
|
3
|
-
"version": "0.9.17-beta.
|
|
3
|
+
"version": "0.9.17-beta.6",
|
|
4
4
|
"description": "Leftoff (formerly Checkpoints): WTF was I working on? Tracks every Claude Code session on this machine, writes a 3-line checkpoint when one goes quiet, and adds /cp (checkpoint now), /cp-name and a /leftoff pane. Talks to the local Leftoff daemon on 127.0.0.1:7429 and falls back to writing markdown in ~/checkpoints.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "One Silly App"
|
package/mod/hooks/register.js
CHANGED
|
@@ -28,7 +28,7 @@ const END_TIMEOUT_MS = 1000
|
|
|
28
28
|
const MODEL_TIMEOUT_MS = 20000
|
|
29
29
|
|
|
30
30
|
// Module state. $.state is not used: the pane redraws with $.ui.invalidate.
|
|
31
|
-
const MOD_VERSION = '0.9.17-beta.
|
|
31
|
+
const MOD_VERSION = '0.9.17-beta.6' // keep in step with .claude-plugin/plugin.json
|
|
32
32
|
|
|
33
33
|
const st = {
|
|
34
34
|
internal: false,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leftoff/cli",
|
|
3
|
-
"version": "0.9.17-beta.
|
|
3
|
+
"version": "0.9.17-beta.6",
|
|
4
4
|
"description": "Leftoff: WTF was I working on? Tracks every Claude Code session, writes a 3-line checkpoint when one goes quiet, and gives you a daily digest and a board, on your Mac and (optionally) your phone.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
package/ui/app.css
CHANGED
|
@@ -2862,12 +2862,21 @@ mark.tx, .co-snip mark, .tx-snip mark, .tx-msg-text mark { background: var(--tx-
|
|
|
2862
2862
|
.tab-all[hidden] { display: none; }
|
|
2863
2863
|
}
|
|
2864
2864
|
@media (min-width: 700px) and (pointer: coarse) { .tab-keep { opacity: 1; } }
|
|
2865
|
-
/* the rail as icons
|
|
2865
|
+
/* the rail as icons: collapsed by you or by a short room (html.nav-slim, ui/navrail.js); before the
|
|
2866
|
+
script runs, 700–1099px starts that way. The labels stay for screen readers. */
|
|
2866
2867
|
@media (min-width: 700px) and (max-width: 1099.98px) {
|
|
2867
|
-
:
|
|
2868
|
-
.tabs a .lbl, .topright .lbl, .topright .sb-lbl, .topright .health .label { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
|
|
2869
|
-
|
|
2870
|
-
|
|
2868
|
+
html:not(.nav-ready) { --rail-w: 56px; }
|
|
2869
|
+
html:not(.nav-ready) :is(.tabs a .lbl, .topright .lbl, .topright .sb-lbl, .topright .health .label) { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
|
|
2870
|
+
}
|
|
2871
|
+
@media (min-width: 700px) {
|
|
2872
|
+
html.nav-slim { --rail-w: 56px; }
|
|
2873
|
+
html.nav-slim :is(.tabs a .lbl, .topright .lbl, .topright .sb-lbl, .topright .health .label) { position: absolute !important; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
|
|
2874
|
+
html.nav-slim :is(.tabs a, .topright .searchbtn, .topright .iconbtn, .topright .health) { min-height: 44px; padding: 6px 2px; }
|
|
2875
|
+
html.nav-slim .navcount { left: calc(50% + 2px); top: 1px; }
|
|
2876
|
+
html.nav-slim .brand .logo { width: 26px; height: 26px; }
|
|
2877
|
+
}
|
|
2878
|
+
@media (min-width: 700px) and (hover: hover) and (pointer: fine) { /* 44px is for fingers */
|
|
2879
|
+
html.nav-slim :is(.tabs a, .topright .searchbtn, .topright .iconbtn, .topright .health) { min-height: 34px; padding: 4px 2px; }
|
|
2871
2880
|
}
|
|
2872
2881
|
/* phones (under 700px): the Open row on the board, ‹ N of M › on a session page */
|
|
2873
2882
|
@media (max-width: 699.98px) {
|
|
@@ -3192,22 +3201,23 @@ html.pv-open, html.pv-open body { overflow: hidden; }
|
|
|
3192
3201
|
.wid-base { font-weight: 650; color: var(--text); }
|
|
3193
3202
|
.gd-bar { display: inline-flex; gap: 1px; margin-left: 6px; vertical-align: -1px; }
|
|
3194
3203
|
.gd-bar i { width: 8px; height: 8px; border-radius: 2px; background: var(--line-strong); }
|
|
3195
|
-
.gd-bar i.gd-ba { background: var(--
|
|
3196
|
-
.gd-bar i.gd-bd { background: var(--
|
|
3204
|
+
.gd-bar i.gd-ba { background: var(--diff-add-fg); }
|
|
3205
|
+
.gd-bar i.gd-bd { background: var(--diff-del-fg); }
|
|
3197
3206
|
.wid-item.open > .wid-file { position: sticky; top: var(--wid-sticky, 56px); z-index: 3; background: var(--card); border-bottom: 1px solid var(--line); }
|
|
3198
3207
|
.wid-item.open > .wid-file:hover { background: var(--bg2); }
|
|
3199
3208
|
.wid-item.open > .wid-out:has(.gd-wrap) { padding: 0; }
|
|
3200
3209
|
.gd-wrap .copy-float { top: 0; right: 0; z-index: 2; }
|
|
3201
3210
|
.gd {
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
--gd-
|
|
3206
|
-
--gd-del
|
|
3207
|
-
--gd-del-word: color-mix(in srgb, var(--red) 38%, transparent);
|
|
3211
|
+
/* 0.9.18 (Joel: "always look green"): GitHub's diff colours, the same as the .html export;
|
|
3212
|
+
the theme's teal --green was murky here. The row is a pale tint, its number gutter a step
|
|
3213
|
+
stronger, the changed words a step darker again; context stays neutral; +/− always shown */
|
|
3214
|
+
--gd-add: var(--diff-add); --gd-add-gut: var(--diff-add-gut); --gd-add-word: var(--diff-add-word);
|
|
3215
|
+
--gd-del: var(--diff-del); --gd-del-gut: var(--diff-del-gut); --gd-del-word: var(--diff-del-word);
|
|
3208
3216
|
--gd-gw: 3.6ch;
|
|
3209
3217
|
font-family: var(--mono); font-size: 12px; line-height: 20px; color: var(--text); background: var(--card2);
|
|
3210
3218
|
}
|
|
3219
|
+
:root, [data-theme="dark"] { --diff-add: rgba(46, 160, 67, .15); --diff-add-gut: rgba(63, 185, 80, .3); --diff-add-word: rgba(46, 160, 67, .4); --diff-add-fg: #3fb950; --diff-del: rgba(248, 81, 73, .1); --diff-del-gut: rgba(248, 81, 73, .3); --diff-del-word: rgba(248, 81, 73, .4); --diff-del-fg: #f85149; --diff-mod-fg: #d29922; --diff-ren-fg: #9198a1; }
|
|
3220
|
+
[data-theme="light"] { --diff-add: #e6ffec; --diff-add-gut: #ccffd8; --diff-add-word: #abf2bc; --diff-add-fg: #1a7f37; --diff-del: #ffebe9; --diff-del-gut: #ffd7d5; --diff-del-word: rgba(255, 129, 130, .4); --diff-del-fg: #d1242f; --diff-mod-fg: #9a6700; --diff-ren-fg: #59636e; }
|
|
3211
3221
|
.gd.gd-w2 { --gd-gw: 3.6ch; } .gd.gd-w3 { --gd-gw: 4.6ch; } .gd.gd-w4 { --gd-gw: 5.6ch; } .gd.gd-w5 { --gd-gw: 6.6ch; } .gd.gd-w6 { --gd-gw: 7.6ch; }
|
|
3212
3222
|
.gd-row { display: grid; grid-template-columns: var(--gd-gw) var(--gd-gw) 2ch minmax(0, 1fr); min-width: 0; }
|
|
3213
3223
|
.gd-gut { padding: 0 6px 0 0; text-align: right; color: var(--faint); font-size: 11.5px; -webkit-user-select: none; user-select: none; font-variant-numeric: tabular-nums; }
|
|
@@ -3219,10 +3229,10 @@ html.pv-open, html.pv-open body { overflow: hidden; }
|
|
|
3219
3229
|
.gd-hunk .gd-c, .gd-gap .gd-c, .gd-note .gd-c { grid-column: 3 / 5; padding-left: 8px; }
|
|
3220
3230
|
.gd-add { background: var(--gd-add); }
|
|
3221
3231
|
.gd-add .gd-gut { background: var(--gd-add-gut); color: var(--text2); }
|
|
3222
|
-
.gd-add .gd-m { color: var(--
|
|
3232
|
+
.gd-add .gd-m { color: var(--diff-add-fg); }
|
|
3223
3233
|
.gd-del { background: var(--gd-del); }
|
|
3224
3234
|
.gd-del .gd-gut { background: var(--gd-del-gut); color: var(--text2); }
|
|
3225
|
-
.gd-del .gd-m { color: var(--
|
|
3235
|
+
.gd-del .gd-m { color: var(--diff-del-fg); }
|
|
3226
3236
|
.gd-x { text-decoration: none; border-radius: 3px; padding: 1px 0; color: inherit; }
|
|
3227
3237
|
ins.gd-x { background: var(--gd-add-word); }
|
|
3228
3238
|
del.gd-x { background: var(--gd-del-word); }
|
|
@@ -3979,13 +3989,11 @@ a.fact.fact-link[data-tip]::after { content: attr(data-tip); display: none; posi
|
|
|
3979
3989
|
|
|
3980
3990
|
/* ------------------------------------------------------------ 0.9.14 full screen keeps the open tabs
|
|
3981
3991
|
From 700px: the board's own tab bar stays pinned at the top, full screen fills the
|
|
3982
|
-
space under it
|
|
3992
|
+
space under it and beside the left rail (0.9.18: the rail no longer steps aside).
|
|
3983
3993
|
Under 700px (no tab bar there): one row of compact chips under the bar, 44px tall,
|
|
3984
3994
|
never two rows: it scrolls sideways. */
|
|
3985
3995
|
@media (min-width: 700px) {
|
|
3986
|
-
html.live-full
|
|
3987
|
-
html.live-full .top { display: none !important; }
|
|
3988
|
-
html.live-full .tabstrip { position: fixed; top: 0; left: 0; right: 0; z-index: 33; }
|
|
3996
|
+
html.live-full .tabstrip { position: fixed; top: 0; left: calc(var(--rail-w) + env(safe-area-inset-left)); right: 0; z-index: 33; } /* 0.9.18: the rail stays beside full screen */
|
|
3989
3997
|
html.live-full .live-box.full { top: calc(var(--lf-top, 0px) + var(--lf-bar, 44px)); height: calc(var(--lf-h, 100vh) - var(--lf-bar, 44px)); height: calc(var(--lf-h, 100dvh) - var(--lf-bar, 44px)); }
|
|
3990
3998
|
.lf-tabs { display: none !important; }
|
|
3991
3999
|
}
|
|
@@ -4638,7 +4646,7 @@ details[open] > summary .wt-g-chev { transform: rotate(90deg); }
|
|
|
4638
4646
|
.wt-file > summary { display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 12px; cursor: pointer; list-style: none; font-size: 13px; }
|
|
4639
4647
|
.wt-file-p { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--text); font-size: 12.5px; }
|
|
4640
4648
|
.wt-file-n { margin-left: auto; font-family: var(--mono); font-size: 12px; white-space: nowrap; }
|
|
4641
|
-
.wt-add { color: var(--
|
|
4649
|
+
.wt-add { color: var(--diff-add-fg); } .wt-del { color: var(--diff-del-fg); }
|
|
4642
4650
|
.wt-file .wt-snip-d, .wt-file .wt-g-p { padding: 0 12px 12px; }
|
|
4643
4651
|
/* the file map, for big changes */
|
|
4644
4652
|
.wt-fm { position: sticky; top: 0; align-self: start; max-height: 100%; overflow-y: auto; padding: 14px 0 20px 16px; font-size: 13px; }
|
|
@@ -4655,6 +4663,38 @@ details[open] > summary .wt-g-chev { transform: rotate(90deg); }
|
|
|
4655
4663
|
.wt-fm-x { display: inline-flex; color: var(--muted); } .wt-fm-x .ic { width: 13px; height: 13px; }
|
|
4656
4664
|
.wt-fm-k { display: flex; align-items: center; gap: 4px; margin: 16px 8px 0; font-size: 12px; color: var(--muted); }
|
|
4657
4665
|
.wt-fm-k .kbd { display: inline-flex; align-items: center; justify-content: center; height: 18px; min-width: 18px; padding: 1px 5px 0; box-sizing: border-box; border: 1px solid var(--line-strong); border-radius: 5px; font: 500 11px/1 var(--mono); color: var(--text2); }
|
|
4666
|
+
/* 0.9.18 (Joel): a file list on the left (the file map, or the Files view's list) and the reading
|
|
4667
|
+
on the right, each in its own scroll box filling the height; pinned headers stay in theirs */
|
|
4668
|
+
.wt-2p { flex: 1 1 auto; min-height: 0; display: flex; }
|
|
4669
|
+
.wt-2p > .wt-side { flex: 0 0 256px; box-sizing: border-box; position: static; align-self: stretch; max-height: none; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 14px 8px 20px 12px; border-right: 1px solid var(--line); }
|
|
4670
|
+
.wt-2p > .wt-scroll { flex: 1 1 auto; min-width: 0; }
|
|
4671
|
+
.wt-2p .wt-hw { max-width: 1000px; }
|
|
4672
|
+
.wt.wt-big .wt-2p .wt-hw { display: block; max-width: 1000px; }
|
|
4673
|
+
.wt-2p .wt-in { padding-left: 24px; }
|
|
4674
|
+
/* a file's status, GitHub style: a square with + / a dot / − / an arrow (shape first; colour helps) */
|
|
4675
|
+
.wt-fst { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; line-height: 1; }
|
|
4676
|
+
.wt-fst .ic { width: 15px; height: 15px; margin: 0; }
|
|
4677
|
+
.wt-fst-added { color: var(--diff-add-fg); } .wt-fst-deleted { color: var(--diff-del-fg); } .wt-fst-modified { color: var(--diff-mod-fg); } .wt-fst-renamed { color: var(--diff-ren-fg); }
|
|
4678
|
+
.wt-fm-i .wt-fst { margin-left: 2px; }
|
|
4679
|
+
.wt-fl-i .wt-fst { margin-left: 0; }
|
|
4680
|
+
.wt-fl-n { flex: none; display: inline-flex; gap: 5px; font: 500 11px/1 var(--mono); font-variant-numeric: tabular-nums; }
|
|
4681
|
+
.wt-fl-tot { display: inline-flex; gap: 5px; margin-left: 8px; font: 500 11px/1 var(--mono); text-transform: none; letter-spacing: 0; }
|
|
4682
|
+
.wt-fl .wt-fm-h { display: flex; align-items: center; gap: 6px; }
|
|
4683
|
+
.wt-fl .wt-fl-tot { margin-left: auto; margin-right: 6px; }
|
|
4684
|
+
.wt-file > summary .wt-fst { margin-right: -2px; }
|
|
4685
|
+
.wt-file-o { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; }
|
|
4686
|
+
/* each open file's name bar stays at the top of the diff pane while you read it */
|
|
4687
|
+
.wt-file[open] > summary { position: sticky; top: 0; z-index: 2; background: var(--card); border-radius: 12px 12px 0 0; border-bottom: 1px solid var(--line); }
|
|
4688
|
+
.wt-file[open] > summary + * { margin-top: 8px; }
|
|
4689
|
+
/* a phone (or a narrow window): the list folds above the diff, inside the one scroll (no box in a box) */
|
|
4690
|
+
.wt-fl-m { display: none; margin: 10px 0 0; border: 1px solid var(--line); border-radius: 12px; background: var(--card); }
|
|
4691
|
+
.wt-fl-m > summary { display: flex; align-items: center; gap: 8px; min-height: 44px; padding: 0 12px; cursor: pointer; list-style: none; font-size: 13px; font-weight: 650; color: var(--text2); }
|
|
4692
|
+
.wt-fl-m > summary::-webkit-details-marker { display: none; }
|
|
4693
|
+
.wt-fl-m > summary .wt-fl-tot { margin-left: auto; }
|
|
4694
|
+
.wt-fl-m[open] > summary .wt-g-chev { transform: rotate(90deg); }
|
|
4695
|
+
.wt-fl-m > .wt-fl { position: static; max-height: none; overflow: visible; padding: 0 6px 8px; }
|
|
4696
|
+
@media (max-width: 900px) { .wt.wt-fls .wt-2p > .wt-side { display: none; } .wt.wt-fls .wt-fl-m { display: block; } .wt.wt-fls .wt-2p .wt-in { padding-left: 16px; } }
|
|
4697
|
+
@media (max-width: 1100px) { .wt.wt-big .wt-2p > .wt-side { display: none; } }
|
|
4658
4698
|
/* the ask box: the question goes into the chat box, with the step's file:line */
|
|
4659
4699
|
.wt-ask { flex: none; display: flex; align-items: center; gap: 8px; max-width: 804px; width: calc(100% - 32px); margin: 6px auto 0; min-height: 52px; padding: 0 6px 0 14px; box-sizing: border-box; border: 1px solid var(--line-strong); border-radius: 14px; background: var(--card); }
|
|
4660
4700
|
.wt-big ~ .wt-ask, .wt.wt-big .wt-ask { max-width: 1000px; }
|
|
@@ -4902,3 +4942,64 @@ details[open] > summary .wt-g-chev { transform: rotate(90deg); }
|
|
|
4902
4942
|
/* narrow / a phone: arrows and dots only */
|
|
4903
4943
|
@media (max-width: 699.98px) { .wt-dnow, .wt-dcount, .wt-dl { display: none; } .wt-dnav { gap: 4px; padding: 4px 6px calc(4px + env(safe-area-inset-bottom)); } .wt-dnav .btn { width: 44px; padding: 0; justify-content: center; } }
|
|
4904
4944
|
@container (max-width: 560px) { .wt-dnow { display: none; } }
|
|
4945
|
+
|
|
4946
|
+
/* ------------------------------------------------------------ 0.9.18 the left nav on every screen (ui/navrail.js)
|
|
4947
|
+
From 700px the rail stays beside every page, full screen and the walkthrough too: expanded
|
|
4948
|
+
(84px, icon over label) or collapsed (56px, icons with a tip), its toggle at the foot or [.
|
|
4949
|
+
The current item: a filled pill and a bar at the rail's edge (shape, not color alone).
|
|
4950
|
+
Under 700px: a menu button in full screen's bar (and an edge swipe) opens it as a drawer. */
|
|
4951
|
+
.navtoggle, .lf-menu { display: none; }
|
|
4952
|
+
.railtip { position: fixed; z-index: 60; left: 0; top: 0; transform: translateY(-50%); width: max-content; max-width: 260px; padding: 4px 8px; border-radius: 7px; background: var(--card2); border: 1px solid var(--line-strong); box-shadow: var(--toast-shadow); color: var(--text2); font-size: 12px; line-height: 1.3; font-weight: 500; white-space: nowrap; pointer-events: none; animation: railtip-in .12s ease-out both; }
|
|
4953
|
+
@keyframes railtip-in { from { opacity: 0; } to { opacity: 1; } }
|
|
4954
|
+
.railtip[hidden] { display: none; }
|
|
4955
|
+
@media (min-width: 700px) {
|
|
4956
|
+
html.live-full .top { z-index: 34; }
|
|
4957
|
+
html.live-full .live-box.full { left: calc(var(--rail-w) + env(safe-area-inset-left)); }
|
|
4958
|
+
.term-dock { left: calc(var(--rail-w) + env(safe-area-inset-left)); } /* the terminal docks beside the rail, its toggle stays reachable */
|
|
4959
|
+
.top [data-tip]::after { display: none !important; } /* the rail scrolls and would cut a CSS tip off: one floating .railtip instead */
|
|
4960
|
+
.tabs a.on::before, .topright .iconbtn.on::before { content: ''; position: absolute; left: -8px; top: 50%; width: 3px; height: 22px; transform: translateY(-50%); border-radius: 0 3px 3px 0; background: var(--accent); }
|
|
4961
|
+
.topright .navtoggle { order: 10; display: flex; color: var(--faint); }
|
|
4962
|
+
.topright .navtoggle:hover { color: var(--text); }
|
|
4963
|
+
.topright .navtoggle[aria-disabled="true"] { opacity: .55; cursor: default; }
|
|
4964
|
+
.topright .navtoggle[aria-disabled="true"]:hover { background: none; color: var(--faint); }
|
|
4965
|
+
.top :is(a, button):focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
4966
|
+
html.nav-anim .top { transition: width .18s ease; }
|
|
4967
|
+
html.nav-anim body { transition: padding-left .18s ease; }
|
|
4968
|
+
html.nav-anim .live-box.full, html.nav-anim .tabstrip, html.nav-anim .term-dock { transition: left .18s ease; }
|
|
4969
|
+
.navdrawer, .navscrim { display: none !important; }
|
|
4970
|
+
}
|
|
4971
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4972
|
+
.railtip { animation: none; }
|
|
4973
|
+
html.nav-anim .top, html.nav-anim body, html.nav-anim .live-box.full, html.nav-anim .tabstrip, html.nav-anim .term-dock { transition: none; }
|
|
4974
|
+
}
|
|
4975
|
+
@media (max-width: 699.98px) {
|
|
4976
|
+
.live-fbar .lf-menu { display: inline-flex; align-items: center; justify-content: center; flex: none; position: relative; width: 44px; height: 44px; min-height: 44px; padding: 0; border-color: transparent; background: none; box-shadow: none; color: var(--muted); }
|
|
4977
|
+
.live-fbar .lf-menu .ic { width: 20px; height: 20px; margin: 0; }
|
|
4978
|
+
.live-fbar .lf-menu:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|
|
4979
|
+
.live-fbar .lf-menu + .live-fs-x { margin-left: -6px; }
|
|
4980
|
+
.navtoggle { display: none !important; }
|
|
4981
|
+
}
|
|
4982
|
+
.navscrim { position: fixed; inset: 0; z-index: 70; background: rgba(8, 10, 16, .42); opacity: 0; transition: opacity .2s ease; -webkit-tap-highlight-color: transparent; }
|
|
4983
|
+
.navscrim.open { opacity: 1; }
|
|
4984
|
+
.navscrim[hidden], .navdrawer[hidden] { display: none; }
|
|
4985
|
+
.navdrawer { position: fixed; z-index: 71; top: 0; bottom: 0; left: 0; width: min(300px, 84vw); display: flex; flex-direction: column; box-sizing: border-box; padding: max(10px, env(safe-area-inset-top)) 10px max(12px, env(safe-area-inset-bottom)) max(10px, env(safe-area-inset-left)); background: var(--bg); border-right: 1px solid var(--line); box-shadow: 0 0 40px rgba(0, 0, 0, .25); overflow-y: auto; overscroll-behavior: contain; transform: translateX(-100%); transition: transform .2s ease; outline: none; }
|
|
4986
|
+
.navdrawer.open { transform: none; }
|
|
4987
|
+
@media (prefers-reduced-motion: reduce) { .navdrawer, .navscrim { transition: none; } }
|
|
4988
|
+
html.nav-drawer-open, html.nav-drawer-open body { overflow: hidden; }
|
|
4989
|
+
.nd-head { display: flex; align-items: center; gap: 10px; min-height: 44px; margin: 0 0 6px; padding: 0 0 6px 8px; border-bottom: 1px solid var(--line); }
|
|
4990
|
+
.nd-head .logo { width: 22px; height: 22px; }
|
|
4991
|
+
.nd-title { flex: 1 1 auto; font-size: 15px; font-weight: 650; color: var(--text); }
|
|
4992
|
+
.nd-x { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; padding: 0; border: 0; border-radius: 10px; background: none; color: var(--muted); cursor: pointer; }
|
|
4993
|
+
.nd-x:hover { color: var(--text); background: var(--bg2); }
|
|
4994
|
+
.nd-x .ic { width: 18px; height: 18px; }
|
|
4995
|
+
.nd-list { display: flex; flex-direction: column; gap: 2px; }
|
|
4996
|
+
.nd-item { position: relative; display: flex; align-items: center; gap: 12px; min-height: 44px; padding: 0 12px; border-radius: 10px; color: var(--text2); font-size: 15px; font-weight: 550; text-decoration: none; -webkit-tap-highlight-color: transparent; }
|
|
4997
|
+
.nd-item .ic { flex: none; width: 20px; height: 20px; }
|
|
4998
|
+
.nd-item:hover { background: var(--bg2); color: var(--text); }
|
|
4999
|
+
.nd-item.on { background: var(--rail-on); color: var(--text); }
|
|
5000
|
+
.nd-item.on .ic { color: var(--accent); }
|
|
5001
|
+
.nd-item.on::before { content: ''; position: absolute; left: 0; top: 50%; width: 3px; height: 22px; transform: translateY(-50%); border-radius: 0 3px 3px 0; background: var(--accent); }
|
|
5002
|
+
.nd-lbl { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
5003
|
+
.nd-cur { flex: none; font-size: 12px; font-weight: 500; color: var(--muted); }
|
|
5004
|
+
.nd-n { flex: none; display: inline-flex; align-items: center; justify-content: center; height: 20px; min-width: 20px; padding: 0 6px; box-sizing: border-box; border-radius: 10px; background: var(--red); color: #fff; font-size: 11.5px; font-weight: 650; line-height: 1; }
|
|
5005
|
+
.nd-item:focus-visible, .nd-x:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
|