@elmts/cli 0.0.0-stage → 0.2.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.
Files changed (59) hide show
  1. package/.claude-plugin/marketplace.json +11 -0
  2. package/LICENSE +41 -0
  3. package/README.md +18 -2
  4. package/bin/el.js +47 -0
  5. package/claude-plugin/.claude-plugin/plugin.json +6 -0
  6. package/claude-plugin/hooks/chips.ts +1 -0
  7. package/claude-plugin/hooks/hooks.json +1 -0
  8. package/claude-plugin/hooks/register.tsx +2 -0
  9. package/claude-plugin/skills/element/SKILL.md +21 -0
  10. package/claude-plugin/types/index.d.ts +15 -0
  11. package/cursor-extension/extension.js +14 -0
  12. package/cursor-extension/package.json +30 -0
  13. package/extension/background.js +2 -0
  14. package/extension/fonts/figtree-latin-400-normal.woff2 +0 -0
  15. package/extension/fonts/figtree-latin-500-normal.woff2 +0 -0
  16. package/extension/fonts/figtree-latin-600-normal.woff2 +0 -0
  17. package/extension/fonts/geist-mono-latin-400-normal.woff2 +0 -0
  18. package/extension/fonts/geist-mono-latin-500-normal.woff2 +0 -0
  19. package/extension/hotkeys.js +1 -0
  20. package/extension/icons/tile-128.png +0 -0
  21. package/extension/icons/tile-48.png +0 -0
  22. package/extension/icons/toolbar-dark-16.png +0 -0
  23. package/extension/icons/toolbar-dark-32.png +0 -0
  24. package/extension/icons/toolbar-light-16.png +0 -0
  25. package/extension/icons/toolbar-light-32.png +0 -0
  26. package/extension/logos.js +1 -0
  27. package/extension/manifest.json +57 -0
  28. package/extension/offscreen.html +4 -0
  29. package/extension/offscreen.js +1 -0
  30. package/extension/picker.js +311 -0
  31. package/extension/popup.css +59 -0
  32. package/extension/popup.html +37 -0
  33. package/extension/popup.js +1 -0
  34. package/extension/shot.js +1 -0
  35. package/extension/snapshot.js +36 -0
  36. package/opencode-plugin/chips.js +3 -0
  37. package/opencode-plugin/server.js +2 -0
  38. package/opencode-plugin/tui.js +2 -0
  39. package/package.json +36 -4
  40. package/pi-extension/index.ts +10 -0
  41. package/src/account.js +8 -0
  42. package/src/codex.js +25 -0
  43. package/src/cursor-install.js +18 -0
  44. package/src/cursor.js +8 -0
  45. package/src/format.js +7 -0
  46. package/src/hook.js +4 -0
  47. package/src/hub.js +2 -0
  48. package/src/hubclient.js +4 -0
  49. package/src/install.js +47 -0
  50. package/src/license.js +5 -0
  51. package/src/limits.js +1 -0
  52. package/src/muse.js +2 -0
  53. package/src/native.js +2 -0
  54. package/src/notify.js +1 -0
  55. package/src/paths.js +1 -0
  56. package/src/proc.js +4 -0
  57. package/src/share.js +6 -0
  58. package/src/snaptext.js +26 -0
  59. package/src/statusline.js +2 -0
@@ -0,0 +1,311 @@
1
+ (()=>{if(window.__elementPicker)return;window.__elementPicker=!0;let z=!1,V=!1,Y={},A=null,rt=[],j=null,m=null,it=null,Re=!1,st=!1,Xe=null,ze=null,Ie=null,E=null,W=!1,at=0,_e=!1;const F=globalThis.ELEMENT_HOTKEYS;let te=F.read(null);chrome.storage.local.get("hotkeys").then(e=>te=F.read(e.hotkeys)).catch(()=>{}),chrome.storage.onChanged.addListener((e,i)=>{i!=="local"||!e.hotkeys||(te=F.read(e.hotkeys.newValue),z&&Y.hold&&re())});const He=e=>F.match(F.fromEvent(e),te),En=()=>Y.hold&&!W&&F.isMac&&te.pick.includes("ctrl"),Z='"el-Figtree", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif',$='"el-Geist-Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace',An=`
2
+ :host { all: initial; }
3
+ .layer { position: fixed; inset: 0; pointer-events: none; z-index: 2147483647; font: 500 13px/1.4 ${Z}; color: #fff; -webkit-font-smoothing: antialiased; }
4
+ svg { display: block; flex: none; }
5
+ .pill { background: #0A0A0A; color: #fff; box-shadow: 0 0 0 1px rgba(255,255,255,.16), 0 10px 30px -8px rgba(0,0,0,.45); }
6
+
7
+ .box { position: fixed; display: none; box-sizing: border-box;
8
+ transition: left 140ms cubic-bezier(.3,1.3,.5,1), top 140ms cubic-bezier(.3,1.3,.5,1), width 140ms cubic-bezier(.3,1.3,.5,1), height 140ms cubic-bezier(.3,1.3,.5,1); }
9
+ /* Adaptive wash: dark on light pages, light on dark pages, frosted on images/gradients. */
10
+ .hair { position: absolute; inset: 1px; border-radius: 5px; box-shadow: 0 0 0 1.5px rgba(10,10,10,.55), 0 0 0 2.5px rgba(255,255,255,.6); background: rgba(10,10,10,.10); }
11
+ .box.on-dark .hair { box-shadow: 0 0 0 1.5px rgba(255,255,255,.7), 0 0 0 2.5px rgba(0,0,0,.6); background: rgba(255,255,255,.12); }
12
+ .box.on-dark .k { border-color: #fff; filter: drop-shadow(0 0 1px #000) drop-shadow(0 0 1px #000); }
13
+ .box.on-busy .hair { box-shadow: 0 0 0 1.5px rgba(10,10,10,.6), 0 0 0 3px rgba(255,255,255,.75); background: rgba(255,255,255,.28); }
14
+ .k { position: absolute; width: 12px; height: 12px; box-sizing: border-box; border: 2.5px solid #0A0A0A; filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff); }
15
+ .k1 { left: -3px; top: -3px; border-right: 0; border-bottom: 0; border-top-left-radius: 6px; }
16
+ .k2 { right: -3px; top: -3px; border-left: 0; border-bottom: 0; border-top-right-radius: 6px; }
17
+ .k3 { left: -3px; bottom: -3px; border-right: 0; border-top: 0; border-bottom-left-radius: 6px; }
18
+ .k4 { right: -3px; bottom: -3px; border-left: 0; border-top: 0; border-bottom-right-radius: 6px; }
19
+
20
+ .tag { position: fixed; display: none; align-items: center; gap: 6px; height: 24px; padding: 0 8px 0 6px; border-radius: 7px; font: 500 11.5px/24px ${$}; white-space: nowrap; max-width: 70vw; overflow: hidden; }
21
+ .tag svg { width: 13px; height: 13px; }
22
+ .tag .dim { opacity: .55; }
23
+ .tag .to { display: flex; align-items: center; gap: 5px; padding-left: 7px; border-left: 1px solid rgba(255,255,255,.2); opacity: .85; }
24
+ .tag .to svg { width: 12px; height: 12px; }
25
+
26
+ kbd { font: 500 11px ${$}; padding: 3px 7px; border-radius: 6px; background: rgba(255,255,255,.12); color: rgba(255,255,255,.75); }
27
+
28
+ /* Toasts stack bottom-right, newest at the bottom: share progress toasts, then the pick toast. */
29
+ .stack { position: fixed; right: 16px; bottom: 16px; display: flex; flex-direction: column; align-items: flex-end; gap: 8px; max-width: calc(100vw - 32px); }
30
+ .layer.mod-open .stack { right: calc(min(380px, 100vw - 20px) + 22px); }
31
+ .stack [hidden] { display: none !important; }
32
+ .toast { display: none; align-items: center; gap: 10px; padding: 9px 12px 9px 10px; border-radius: 12px; max-width: 70vw; }
33
+ .st { pointer-events: auto; width: 300px; max-width: 100%; box-sizing: border-box; border-radius: 12px; padding: 9px 10px 10px; display: grid; grid-template-columns: 30px minmax(0, 1fr) auto; column-gap: 10px; row-gap: 7px; align-items: center;
34
+ font: 400 12.5px/1.4 ${Z}; animation: el-rise .22s ease-out; transition: opacity .3s, transform .3s; }
35
+ @keyframes el-rise { from { transform: translateY(8px); opacity: 0; } }
36
+ .st .th { width: 30px; height: 22px; border-radius: 4px; background: rgba(255,255,255,.14) center top / cover no-repeat; }
37
+ .st .lbl { min-width: 0; display: flex; flex-direction: column; }
38
+ .st .lbl b { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
39
+ .st .lbl small { font: 400 11px/1.45 ${$}; color: rgba(255,255,255,.6); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; user-select: text; }
40
+ .st .act { all: unset; cursor: pointer; font: 500 11.5px ${Z}; padding: 3px 8px; border-radius: 6px; background: #FAFAFA; color: #0A0A0A; }
41
+ .st .act:focus-visible { outline: 2px solid #2E6BFF; outline-offset: 2px; }
42
+ .st .acts { display: flex; gap: 6px; }
43
+ .st .act.ghost { background: transparent; color: #FAFAFA; box-shadow: inset 0 0 0 1px rgba(255,255,255,.28); }
44
+ .st .bar { grid-column: 1 / -1; height: 3px; border-radius: 2px; background: rgba(255,255,255,.16); overflow: hidden; }
45
+ .st .bar i { display: block; height: 100%; width: 0; background: #FAFAFA; border-radius: 2px; transition: width .25s ease; }
46
+ .st.done .bar i { background: #30A46C; }
47
+ .st.done .bar { opacity: 0; transition: opacity .4s .6s; }
48
+ .st.err .bar i { background: #E5484D; }
49
+ .st.err .lbl small { color: #FF9592; white-space: normal; }
50
+ .st.out { opacity: 0; transform: translateX(12px); }
51
+ .more { pointer-events: auto; font: 500 11.5px ${$}; color: #FAFAFA; background: #0A0A0A; border-radius: 999px; padding: 4px 10px; opacity: .85; box-shadow: 0 0 0 1px rgba(255,255,255,.16); }
52
+
53
+ /* The module (\u2325\u21E7S): a drawer on the right. Light by default, .dark per the Appearance setting. */
54
+ .mod { --surface: #fff; --line: #E5E5E3; --ink: #0A0A0A; --ink-2: #404040; --muted: #737373; --hover: #F2F2F1; --sel: #EDEDEB; --focus: #2E6BFF; --err: #CE2C31;
55
+ position: fixed; top: 10px; right: 10px; bottom: 10px; width: min(440px, calc(100vw - 20px)); box-sizing: border-box; border-radius: 16px; pointer-events: auto;
56
+ display: none; flex-direction: column; background: var(--surface); color: var(--ink); font: 400 13px/1.5 ${Z}; text-align: left;
57
+ box-shadow: 0 0 0 1px var(--line), 0 30px 70px -20px rgba(0,0,0,.45); animation: el-slide .2s ease-out; }
58
+ .mod.dark { --surface: #141414; --line: #262626; --ink: #FAFAFA; --ink-2: #D4D4D4; --muted: #A3A3A3; --hover: #1E1E1E; --sel: #242424; --err: #FF9592; color-scheme: dark; }
59
+ .mod.open { display: flex; }
60
+ @keyframes el-slide { from { transform: translateX(16px); opacity: 0; } }
61
+ .mod *, .mod *::before, .mod *::after { box-sizing: border-box; }
62
+ .mod button { font-family: inherit; }
63
+ .mod :focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
64
+ .mod [hidden] { display: none !important; }
65
+ .mod .kb { font: 500 11px ${$}; color: var(--muted); border: 1px solid var(--line); border-radius: 5px; padding: 0 5px; background: none; white-space: nowrap; }
66
+ .mh { display: flex; align-items: center; gap: 10px; padding: 10px 12px 0; }
67
+ .mh .mark { display: flex; align-items: center; gap: 6px; font-weight: 600; letter-spacing: -.03em; font-size: 14px; }
68
+ .mh .mark svg { width: 14px; height: 14px; }
69
+ .tabs { display: flex; gap: 2px; margin-left: 6px; }
70
+ .tabs button { all: unset; cursor: pointer; font: 500 12.5px ${Z}; padding: 5px 10px; border-radius: 8px; color: var(--muted); }
71
+ .tabs button[aria-selected="true"] { background: var(--sel); color: var(--ink); }
72
+ .tabs button:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
73
+ .tabs .n { font: 400 11px ${$}; margin-left: 4px; color: var(--muted); }
74
+ .mh .esc { margin-left: auto; cursor: pointer; }
75
+ .search { margin: 10px 12px 4px; display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; border: 1px solid var(--line); border-radius: 9px; color: var(--muted); }
76
+ .search svg { width: 14px; height: 14px; }
77
+ .search:focus-within { border-color: var(--muted); }
78
+ .search input { all: unset; flex: 1; min-width: 0; color: var(--ink); font: 400 13px ${Z}; }
79
+ .search input::placeholder { color: var(--muted); }
80
+ .mod .search input:focus-visible { outline: none; }
81
+ .mbody { overflow: auto; padding: 4px 6px 6px; flex: 1; min-height: 0; overscroll-behavior: contain; }
82
+ .grp { font: 500 11px ${$}; color: var(--muted); padding: 10px 8px 4px; letter-spacing: .02em; text-transform: uppercase; }
83
+ .note { padding: 8px 8px 12px; color: var(--muted); font-size: 12.5px; }
84
+ .note code { font: 400 11.5px ${$}; color: var(--ink); background: var(--sel); border-radius: 5px; padding: 1px 5px; }
85
+ .row { display: grid; grid-template-columns: 18px 52px minmax(0,1fr) auto; gap: 10px; align-items: center; padding: 7px 8px; border-radius: 10px; cursor: default; outline-offset: -2px; }
86
+ .row:hover, .row.sel, .row:focus-within { background: var(--hover); }
87
+ .row input { margin: 0; accent-color: var(--ink); width: 14px; height: 14px; cursor: pointer; }
88
+ .row .th { width: 52px; height: 36px; border-radius: 6px; box-shadow: inset 0 0 0 1px rgba(0,0,0,.06); background: var(--sel) center top / cover no-repeat; }
89
+ .row .t { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
90
+ .row .t b { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
91
+ .row .t small { font: 400 11px/1.45 ${$}; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-variant-numeric: tabular-nums; }
92
+ .row.err .t small { color: var(--err); }
93
+ .row .bar { height: 3px; border-radius: 2px; background: var(--sel); overflow: hidden; margin-top: 4px; }
94
+ .row .bar i { display: block; height: 100%; background: var(--ink); transition: width .25s ease; }
95
+ .row .end { display: grid; justify-items: end; align-items: center; min-width: 132px; }
96
+ .row .end > * { grid-area: 1 / 1; }
97
+ .row .acts { display: flex; gap: 4px; opacity: 0; visibility: hidden; transition: opacity .12s; }
98
+ .row:hover .acts, .row:focus-within .acts { opacity: 1; visibility: visible; }
99
+ .ib { all: unset; cursor: pointer; font: 500 11.5px ${Z}; padding: 4px 8px; border-radius: 7px; border: 1px solid var(--line); background: var(--surface); color: var(--ink); white-space: nowrap; }
100
+ .ib.pri { background: var(--ink); color: var(--surface); border-color: var(--ink); }
101
+ .ib:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
102
+ .ib.ic { display: inline-flex; align-items: center; justify-content: center; padding: 4px 5px; color: var(--muted); }
103
+ .ib.ic:hover { color: var(--err); }
104
+ .ib.ic svg { width: 14px; height: 14px; display: block; }
105
+ .ib.danger { background: var(--err); border-color: var(--err); color: #fff; }
106
+ .row .cf { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 6px 0 2px 28px; }
107
+ .row .cf p { flex: 1 0 100%; margin: 0 0 2px; font-size: 12.5px; color: var(--ink-2); }
108
+ .row .cf p.err { color: var(--err); }
109
+ .row.asking .end > * { visibility: hidden !important; }
110
+ .row .cf .ib:disabled, .selbar .ib:disabled { cursor: default; opacity: .5; }
111
+ .selbar.asking { flex-wrap: wrap; }
112
+ .selbar .cfm { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; flex: 1 0 100%; }
113
+ .selbar .cfm p { flex: 1 0 100%; margin: 0 0 2px; }
114
+ .selbar .cfm p.err { color: #FF9592; }
115
+ .selbar .ib.danger { background: var(--err); color: #fff; border-color: var(--err); }
116
+ .mod .sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
117
+ .row .when { font: 400 11px ${$}; color: var(--muted); white-space: nowrap; transition: opacity .12s; font-variant-numeric: tabular-nums; pointer-events: none; } /* stacked over .acts: never take their clicks */
118
+ .row:hover .acts ~ .when, .row:focus-within .acts ~ .when { opacity: 0; }
119
+ .selbar { display: flex; align-items: center; gap: 8px; margin: 0 8px 8px; padding: 8px 8px 8px 12px; border-radius: 10px; background: var(--ink); color: var(--surface); font-size: 12.5px; }
120
+ .selbar span { flex: 1; }
121
+ .selbar .ib { background: var(--surface); color: var(--ink); border-color: transparent; }
122
+ .selbar .ib.gh { background: transparent; color: var(--surface); border-color: rgba(127,127,127,.4); }
123
+ .mf { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 9px 14px; border-top: 1px solid var(--line); font: 400 11px ${$}; color: var(--muted); flex-wrap: wrap; }
124
+ .sess { all: unset; box-sizing: border-box; width: 100%; display: grid; grid-template-columns: 18px minmax(0,1fr) auto; column-gap: 10px; align-items: center; padding: 9px 10px; border-radius: 10px; cursor: pointer; }
125
+ .sess:hover, .sess:focus-visible { background: var(--hover); }
126
+ .sess:focus-visible { outline: 2px solid var(--focus); outline-offset: -2px; }
127
+ .sess svg { width: 16px; height: 16px; justify-self: center; }
128
+ .sess .nm { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
129
+ .sess b { font-weight: 600; font-size: 13px; }
130
+ .sess small { font: 400 11px ${$}; color: var(--muted); margin-left: 6px; }
131
+ .sess .pr { grid-column: 2 / 4; font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
132
+ .sess.un .nm { color: var(--muted); }
133
+ .sess[aria-disabled="true"] { cursor: default; opacity: .5; }
134
+ .sess[aria-disabled="true"]:hover { background: none; }
135
+ .cur { font: 500 10.5px ${$}; padding: 1px 7px; border-radius: 999px; background: var(--ink); color: var(--surface); white-space: nowrap; }
136
+ .set { display: flex; flex-direction: column; gap: 2px; padding: 6px; }
137
+ .set .li { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 9px 6px; border-bottom: 1px solid var(--line); flex-wrap: wrap; }
138
+ .set .li:last-child { border-bottom: 0; }
139
+ .set .li > span:first-child { color: var(--ink-2); }
140
+ .set .li .v { display: flex; align-items: center; gap: 6px; font: 400 11.5px ${$}; color: var(--muted); }
141
+ .set .grp { padding-left: 6px; }
142
+ .set .hkc { display: inline-flex; align-items: center; gap: 8px; }
143
+ .set .hkc .kb { display: inline-block; min-width: 122px; text-align: center; padding: 3px 6px; font-size: 11.5px; color: var(--ink-2); }
144
+ .set .hkc .kb.none { color: var(--muted); font-style: italic; }
145
+ .set .hkc .kb.rec { color: var(--focus); border-color: var(--focus); border-style: dashed; animation: el-rec 1.2s ease-in-out infinite; }
146
+ @keyframes el-rec { 50% { opacity: .55; } }
147
+ .set .hkc .ib { min-width: 62px; text-align: center; box-sizing: border-box; }
148
+ .set .hkbtn[aria-pressed="true"] { border-color: var(--focus); color: var(--focus); }
149
+ .set .hkfoot { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 9px 6px 4px; }
150
+ .set .hkmsg { flex: 1; min-height: calc(2 * 1.45em); font-size: 12px; line-height: 1.45; color: var(--muted); }
151
+ .set .hkmsg.err { color: var(--err); }
152
+ .set .hkmsg.ok { color: var(--ink-2); }
153
+ .set .hkmsg.warn { color: #B45309; }
154
+ .mod.dark .set .hkmsg.warn { color: #F5B454; }
155
+ .set .hkmsg.rec:not(.err) { color: var(--focus); }
156
+ .mod .ib:disabled { cursor: default; opacity: .45; }
157
+ .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--muted); }
158
+ .dot.up { background: #30A46C; }
159
+ .seg { display: inline-flex; border: 1px solid var(--line); border-radius: 999px; padding: 2px; background: var(--surface); }
160
+ .seg button { all: unset; cursor: pointer; font: 500 12.5px ${Z}; padding: 4px 11px; border-radius: 999px; color: var(--muted); }
161
+ .seg button[aria-pressed="true"] { background: var(--ink); color: var(--surface); }
162
+ .seg button:focus-visible { outline: 2px solid var(--focus); outline-offset: 1px; }
163
+ @media (prefers-reduced-motion: reduce) { .st, .mod, .st .bar i, .row .bar i, .row .acts, .row .when, .st.done .bar, .set .hkc .kb.rec { animation: none !important; transition: none !important; } }
164
+ .toast .ok { width: 18px; height: 18px; border-radius: 50%; background: #fff; color: #0A0A0A; display: grid; place-items: center; flex: none; font: 700 11px ${Z}; }
165
+ .toast .ok svg { width: 11px; height: 11px; }
166
+ .toast.err .ok { background: #E5484D; color: #fff; }
167
+ .toast .who { display: flex; align-items: center; gap: 6px; white-space: nowrap; }
168
+ .toast .who svg { width: 14px; height: 14px; }
169
+ .toast .chip { display: flex; align-items: center; gap: 5px; height: 22px; padding: 0 7px 0 5px; border-radius: 6px; border: 1px solid rgba(255,255,255,.22); font: 11.5px ${$}; color: rgba(255,255,255,.65); white-space: nowrap; }
170
+ .toast .chip b { color: #fff; font-weight: 500; }
171
+ .toast .chip svg { width: 12px; height: 12px; color: #fff; }
172
+
173
+ /* \u2303\u2325 share mode: blue, so it never reads as a pick. */
174
+ .box.share .hair { box-shadow: 0 0 0 1.5px #2563EB, 0 0 0 3px rgba(255,255,255,.7); background: rgba(37,99,235,.14); }
175
+ .box.share .k { border-color: #2563EB; filter: drop-shadow(0 0 1px #fff) drop-shadow(0 0 1px #fff); }
176
+ .tag.share { background: #2563EB; }
177
+ @media (prefers-reduced-motion: reduce) { .box { transition: none; } }
178
+
179
+ /* Gate toasts (signed out, out of save & shares): the share toast's pill and grid; the thumb slot
180
+ holds the link glyph (nothing was captured), the title may wrap, a second row has the meter or
181
+ note on the left and the buttons on the right. No progress bar. */
182
+ .st.gate { row-gap: 8px; }
183
+ .st.gate .th { display: grid; place-items: center; color: rgba(255,255,255,.85); }
184
+ .st.gate .th svg { width: 13px; height: 13px; }
185
+ .st.gate .lbl { grid-column: 2 / -1; }
186
+ .st.gate .lbl b { white-space: normal; text-wrap: pretty; }
187
+ .st .foot { grid-column: 2 / -1; display: flex; align-items: center; gap: 10px; min-width: 0; }
188
+ .st .foot .acts { margin-left: auto; }
189
+ .st .foot small { font: 400 11px/1.3 ${$}; color: rgba(255,255,255,.6); min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
190
+ .st .meterrow { grid-column: 2 / -1; height: 3px; border-radius: 2px; background: rgba(255,255,255,.16); overflow: hidden; }
191
+ .st .meterrow i { display: block; height: 100%; background: #FAFAFA; border-radius: 2px; }
192
+ .st .left { grid-column: 2 / -1; font: 400 11px/1.3 ${$}; color: rgba(255,255,255,.6); }
193
+ /* The Free limits' toasts (sign in to pick, the week's picks used up): two wide buttons. */
194
+ .st .full { grid-column: 1 / -1; display: flex; gap: 6px; }
195
+ .st .full .act { flex: 1; justify-content: center; padding: 5px 9px; }
196
+ .st.gate .lbl small { white-space: normal; text-wrap: pretty; }
197
+ .st.gate .lbl small + small { margin-top: 1px; }
198
+ .st.done.has-left .bar { display: none; }
199
+
200
+ /* The drawer's Account section, its usage meter, and the quiet usage line in Saves. */
201
+ .acct { display: flex; align-items: center; gap: 10px; padding: 10px 6px; border-bottom: 1px solid var(--line); }
202
+ .av { width: 28px; height: 28px; border-radius: 50%; flex: none; display: grid; place-items: center; font: 600 11.5px ${Z}; background: var(--sel); color: var(--ink-2); }
203
+ .av svg { width: 14px; height: 14px; }
204
+ .acct .who { min-width: 0; flex: 1; display: flex; flex-direction: column; }
205
+ .acct .who b { font-weight: 500; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
206
+ .acct .who small { font: 400 11px ${$}; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
207
+ .acct .btns { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
208
+ .planchip { font: 500 10.5px ${$}; padding: 1px 7px; border-radius: 999px; border: 1px solid var(--line); color: var(--ink-2); white-space: nowrap; }
209
+ .planchip.paid { background: var(--ink); color: var(--surface); border-color: var(--ink); }
210
+ .meter { padding: 10px 6px 11px; border-bottom: 1px solid var(--line); display: flex; flex-direction: column; gap: 7px; }
211
+ .meter .mt { display: flex; justify-content: space-between; gap: 10px; flex-wrap: wrap; font-size: 12.5px; color: var(--ink-2); }
212
+ .meter .mt span:last-child { font: 400 11px ${$}; color: var(--muted); font-variant-numeric: tabular-nums; align-self: center; }
213
+ .meter .num { font-variant-numeric: tabular-nums; }
214
+ .tr { height: 4px; border-radius: 2px; background: var(--sel); overflow: hidden; }
215
+ .tr i { display: block; height: 100%; background: var(--ink); border-radius: 2px; }
216
+ .tr.full i { background: var(--err); }
217
+ .flow { margin: 8px 6px 4px; padding: 10px 12px; border-radius: 10px; background: var(--hover); font-size: 12.5px; color: var(--ink-2); display: flex; flex-direction: column; gap: 8px; }
218
+ .flow .code { font: 500 15px ${$}; letter-spacing: .08em; color: var(--ink); user-select: text; }
219
+ .flow .r { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
220
+ .flow small { color: var(--muted); font-size: 12px; }
221
+ .flow small.err { color: var(--err); }
222
+ .flow code { font: 400 11.5px ${$}; color: var(--ink); background: var(--sel); border-radius: 5px; padding: 1px 5px; }
223
+ .flow .spin { width: 12px; height: 12px; border-radius: 50%; border: 2px solid var(--line); border-top-color: var(--ink); animation: el-spin 1s linear infinite; display: inline-block; vertical-align: -2px; margin-right: 6px; box-sizing: border-box; }
224
+ @keyframes el-spin { to { transform: rotate(360deg); } }
225
+ .lockhint { font: 400 11px ${$}; color: var(--muted); width: 100%; text-align: right; }
226
+ .seg button:disabled { cursor: default; }
227
+ .usage { display: flex; align-items: center; gap: 8px; margin: 2px 12px 2px; padding: 4px 2px; font: 400 11px ${$}; color: var(--muted); font-variant-numeric: tabular-nums; }
228
+ .usage .tr { width: 56px; height: 3px; flex: none; }
229
+ .usage .sp { margin-left: auto; white-space: nowrap; }
230
+ .usage a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--line); cursor: pointer; white-space: nowrap; }
231
+ .usage .t1 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0; }
232
+ /* Free, while the Free limits are live: this week's picks and save & shares, two meters. */
233
+ .usage.meters { display: grid; gap: 8px; margin: 6px 12px 4px; padding: 10px 12px; border-radius: 10px; background: var(--hover); box-shadow: inset 0 0 0 1px var(--line); font: 400 12.5px ${Z}; color: var(--ink-2); }
234
+ .usage.meters .u { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 4px 10px; align-items: center; }
235
+ .usage.meters .u small { font: 400 11px ${$}; color: var(--muted); white-space: nowrap; }
236
+ .usage.meters .u .tr { grid-column: 1 / -1; width: auto; height: 4px; }
237
+ .usage.meters .ft { display: flex; justify-content: space-between; align-items: center; gap: 10px; font: 400 11px ${$}; color: var(--muted); }
238
+ @media (prefers-reduced-motion: reduce) { .flow .spin { animation: none !important; } }
239
+
240
+ /* Private links: the visibility chip and \u22EF in toasts, the \u22EF menu (toasts and drawer), the lock and
241
+ request count on Saves rows, the People & requests panel under a row, the Settings rows. */
242
+ .st .act { display: inline-flex; align-items: center; gap: 4px; }
243
+ .st .act svg { width: 12px; height: 12px; }
244
+ .st .act.icon { padding: 3px 5px; }
245
+ .st .lbl small .pv, .row .t small .lk svg { width: 11px; height: 11px; display: inline-block; vertical-align: -1.5px; margin-right: 4px; }
246
+ .dd { position: fixed; z-index: 3; pointer-events: auto; box-sizing: border-box; width: 236px; background: #141414; color: #FAFAFA; border-radius: 10px; padding: 5px;
247
+ box-shadow: 0 0 0 1px #262626, 0 18px 40px -12px rgba(0,0,0,.7); font: 400 12.5px/1.4 ${Z}; animation: el-rise .14s ease-out; }
248
+ .dd .mi { all: unset; box-sizing: border-box; width: 100%; cursor: pointer; display: flex; align-items: center; gap: 9px; padding: 6px 8px; border-radius: 7px; color: #D4D4D4; }
249
+ .dd .mi:hover, .dd .mi:focus-visible { background: #1E1E1E; color: #FAFAFA; }
250
+ .dd .mi svg { width: 13px; height: 13px; display: block; flex: none; }
251
+ .dd .mi .ck { margin-left: auto; display: flex; }
252
+ .dd .mi small { margin-left: auto; font: 400 10.5px ${$}; color: #737373; }
253
+ .dd .mi.danger { color: #FF9592; }
254
+ .dd .sep { height: 1px; background: #262626; margin: 4px 2px; }
255
+ .mod .dd { background: var(--surface); color: var(--ink); box-shadow: 0 0 0 1px var(--line), 0 18px 40px -12px rgba(0,0,0,.35); }
256
+ .mod .dd .mi { color: var(--ink-2); }
257
+ .mod .dd .mi:hover, .mod .dd .mi:focus-visible { background: var(--hover); color: var(--ink); }
258
+ .mod .dd .mi.danger { color: var(--err); }
259
+ .mod .dd .sep { background: var(--line); }
260
+ .badge { font: 500 10px/16px ${$}; padding: 0 6px; border-radius: 999px; background: #2563EB; color: #fff; white-space: nowrap; }
261
+ .tabs .badge { margin-left: 5px; }
262
+ .row .when { display: flex; align-items: center; gap: 6px; }
263
+ .row .t small .lk { color: var(--ink-2); }
264
+ .ap { grid-column: 1 / -1; margin: 4px 0 2px; padding: 10px; border-radius: 10px; background: var(--sunk, #F7F7F6); box-shadow: inset 0 0 0 1px var(--line); display: flex; flex-direction: column; gap: 8px; }
265
+ .mod.dark .ap { --sunk: #0E0E0E; }
266
+ .ap .seg { align-self: flex-start; }
267
+ .seg button svg { width: 12px; height: 12px; display: inline-block; vertical-align: -2px; margin-right: 5px; }
268
+ .ap .seg button, .set .seg.sm button { font-size: 11.5px; padding: 3px 9px; }
269
+ .ap .inp { display: flex; gap: 6px; margin: 0; }
270
+ .ap input { flex: 1; min-width: 0; height: 28px; padding: 0 9px; border-radius: 7px; border: 1px solid var(--line); background: var(--surface); color: var(--ink); font: 400 12.5px ${Z}; outline: none; }
271
+ .ap input:focus { border-color: var(--muted); }
272
+ .ap .ppl { display: flex; flex-direction: column; gap: 2px; }
273
+ .ap .p { display: flex; align-items: center; gap: 8px; padding: 4px 2px; font-size: 12.5px; color: var(--ink-2); min-width: 0; }
274
+ .ap .p .nm { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
275
+ .ap .p .av { width: 20px; height: 20px; flex: none; border-radius: 50%; background: var(--sel); display: grid; place-items: center; font: 500 9.5px ${$}; color: var(--ink); }
276
+ .ap .p .r { margin-left: auto; font: 400 11px ${$}; color: var(--muted); white-space: nowrap; }
277
+ .ap .p.req { background: rgba(37,99,235,.10); border-radius: 7px; padding: 5px 6px; }
278
+ .ap .p.req .r { color: #2563EB; }
279
+ .mod.dark .ap .p.req { background: rgba(37,99,235,.14); }
280
+ .mod.dark .ap .p.req .r { color: #9DB8FF; }
281
+ .ap .note2 { margin: 0; font-size: 12px; color: var(--muted); }
282
+ .ap .note2.err { color: var(--err); }
283
+ .ap .ib:disabled { cursor: default; opacity: .5; }
284
+ .set .li .hint { flex: 1 0 100%; font-size: 12px; color: var(--muted); margin-top: -2px; }
285
+ `,I={lock:'<svg class="pv" viewBox="0 0 24 24" aria-hidden="true"><rect x="5" y="11" width="14" height="9" rx="2" fill="none" stroke="currentColor" stroke-width="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3" fill="none" stroke="currentColor" stroke-width="2"/></svg>',globe:'<svg class="pv" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="2"/><path d="M3.5 12h17M12 3.5c2.6 2.6 2.6 14.4 0 17M12 3.5c-2.6 2.6-2.6 14.4 0 17" fill="none" stroke="currentColor" stroke-width="1.6"/></svg>',dots:'<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="5" cy="12" r="1.8" fill="currentColor"/><circle cx="12" cy="12" r="1.8" fill="currentColor"/><circle cx="19" cy="12" r="1.8" fill="currentColor"/></svg>',check:'<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 12.5l4.5 4.5L19 7.5" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>',people:'<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="9" cy="8.5" r="3.5" fill="none" stroke="currentColor" stroke-width="2"/><path d="M2.5 19.5c.8-3.4 3.4-5 6.5-5s5.7 1.6 6.5 5M16 5.5a3.2 3.2 0 0 1 0 6.2M18.5 14.8c1.6.8 2.6 2.4 3 4.7" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg>'},Je="Private links are part of Pro and Max",$n={github:'<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M12 2a10 10 0 0 0-3.2 19.5c.5.1.7-.2.7-.5v-1.7c-2.8.6-3.4-1.3-3.4-1.3-.5-1.2-1.1-1.5-1.1-1.5-.9-.6.1-.6.1-.6 1 .1 1.5 1 1.5 1 .9 1.5 2.4 1.1 2.9.8.1-.6.4-1.1.6-1.3-2.2-.3-4.6-1.1-4.6-5 0-1.1.4-2 1-2.7-.1-.3-.4-1.3.1-2.7 0 0 .8-.3 2.7 1a9.4 9.4 0 0 1 5 0c1.9-1.3 2.7-1 2.7-1 .5 1.4.2 2.4.1 2.7.6.7 1 1.6 1 2.7 0 3.9-2.4 4.7-4.6 5 .4.3.7.9.7 1.9v2.8c0 .3.2.6.7.5A10 10 0 0 0 12 2z"/></svg>',google:'<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M21.6 12.2c0-.7-.1-1.4-.2-2H12v3.8h5.4a4.6 4.6 0 0 1-2 3v2.5h3.2c1.9-1.7 3-4.3 3-7.3zM12 22c2.7 0 5-.9 6.6-2.4l-3.2-2.5c-.9.6-2 1-3.4 1-2.6 0-4.8-1.8-5.6-4.1H3.1v2.6A10 10 0 0 0 12 22zM6.4 14a6 6 0 0 1 0-3.9V7.5H3.1a10 10 0 0 0 0 9zM12 5.9c1.5 0 2.8.5 3.8 1.5l2.9-2.9A10 10 0 0 0 3.1 7.5l3.3 2.6C7.2 7.8 9.4 5.9 12 5.9z"/></svg>'},Ke=e=>`this ${e?.window==="week"?"week":"month"}`,X=globalThis.ELEMENT_ICONS;function P(e){const i=document.createElement("template");return i.innerHTML=e,i.content.firstElementChild}function r(e,i,l){const d=document.createElement(e);return i&&(d.className=i),l!=null&&(d.textContent=l),d}const Ln=e=>e.branch&&e.branch!=="HEAD"?e.branch:"";function de(){if(clearTimeout(it),j&&j.isConnected)return;j=document.createElement("element-picker-overlay");const e=j.attachShadow({mode:"closed"});e.innerHTML=`<style>${An}</style>
286
+ <div class="layer">
287
+ <div class="box"><span class="hair"></span><b class="k k1"></b><b class="k k2"></b><b class="k k3"></b><b class="k k4"></b></div>
288
+ <div class="tag pill"></div>
289
+ <div class="stack" aria-live="polite"><div class="toast pill"></div></div>
290
+ <div class="mod" role="dialog" aria-label="element"></div>
291
+ </div>`,m={root:e,layer:e.querySelector(".layer"),box:e.querySelector(".box"),tag:e.querySelector(".tag"),stack:e.querySelector(".stack"),toast:e.querySelector(".toast"),mod:e.querySelector(".mod")},document.documentElement.appendChild(j)}function je(e){clearTimeout(it),it=setTimeout(()=>{!z&&!E&&!at&&!Ve.size&&!me&&j&&(j.remove(),j=null)},e)}const Mn=/^[a-zA-Z][a-zA-Z0-9_-]{1,40}$/,Tn=/(^|[-_])(css|sc|jsx|emotion|styled)[-_]|[a-z]+_[a-zA-Z0-9]{5,}$|^[a-zA-Z]{1,3}[0-9][a-zA-Z0-9]{3,}$|__[a-zA-Z0-9]{5}$/;function lt(e){return[...e.classList].filter(i=>Mn.test(i)&&!Tn.test(i)&&!i.includes(":"))}function ct(e){try{return document.querySelectorAll(e).length===1}catch{return!1}}function Dt(e){for(const i of["data-testid","data-test","data-cy","data-qa","data-test-id"]){const l=e.getAttribute(i);if(l){const d=`[${i}="${CSS.escape(l)}"]`;if(ct(d))return d}}return null}function Fn(e){if(e.id&&!/\d{3,}|:/.test(e.id))return`#${CSS.escape(e.id)}`;let i=e.tagName.toLowerCase();const l=lt(e).slice(0,2);l.length&&(i+=l.map(u=>"."+CSS.escape(u)).join(""));const d=e.parentElement;if(d){const u=[...d.children].filter(p=>p.tagName===e.tagName);u.length>1&&(i+=`:nth-of-type(${u.indexOf(e)+1})`)}return i}function Pn(e){if(e.id&&ct(`#${CSS.escape(e.id)}`))return`#${CSS.escape(e.id)}`;const i=Dt(e);if(i)return i;const l=[];for(let d=e;d&&d.nodeType===1&&d!==document.documentElement;d=d.parentElement){const u=d!==e&&Dt(d);l.unshift(u||Fn(d));const p=l.join(" > ");if(ct(p))return p;if(u)break}return l.join(" > ")}function dt(e){let i=e.tagName.toLowerCase();if(e.id)return`${i}#${e.id}`;const l=lt(e)[0];return l?`${i}.${l}`:i}const Dn={button:"button",nav:"navigation",main:"main",header:"banner",footer:"contentinfo",ul:"list",ol:"list",li:"listitem",table:"table",form:"form",dialog:"dialog",select:"combobox",textarea:"textbox",img:"img",h1:"heading",h2:"heading",h3:"heading",h4:"heading",h5:"heading",h6:"heading",aside:"complementary"};function _n(e){const i=e.getAttribute("role");if(i)return i;const l=e.tagName.toLowerCase();if(l==="a"&&e.hasAttribute("href"))return"link";if(l==="input"){const d=(e.getAttribute("type")||"text").toLowerCase();return{checkbox:"checkbox",radio:"radio",button:"button",submit:"button",range:"slider"}[d]||"textbox"}return Dn[l]||""}function Se(e,i){return e=(e||"").replace(/\s+/g," ").trim(),e.length>i?e.slice(0,i)+"\u2026":e}function _t(e){const i=e.getAttribute("aria-labelledby");if(i){const d=i.split(/\s+/).map(u=>document.getElementById(u)?.innerText||"").join(" ");if(d.trim())return Se(d,80)}const l=e.getAttribute("aria-label")||e.getAttribute("alt")||e.getAttribute("title")||e.getAttribute("placeholder");return l?Se(l,80):e.labels&&e.labels[0]?Se(e.labels[0].innerText,80):/^(button|a|h[1-6]|label|summary|option|li)$/i.test(e.tagName)?Se(e.innerText,80):""}const Nn=["display","position","width","height","margin","padding","color","background-color","background-image","font-family","font-size","font-weight","line-height","text-align","border","border-radius","box-shadow","opacity","z-index","gap","flex-direction","justify-content","align-items","grid-template-columns","overflow","transform"],qn=new Set(["none","normal","auto","0px","rgba(0, 0, 0, 0)","static","visible","start","1","0px none rgb(0, 0, 0)"]);function Un(e){const i=getComputedStyle(e),l=/flex|grid/.test(i.display),d={};for(const u of Nn){if(!l&&/^(gap|flex-direction|justify-content|align-items|grid-template-columns)$/.test(u))continue;let p=i.getPropertyValue(u);!p||qn.has(p)&&u!=="display"||/^0px none/.test(p)||(u==="font-family"&&(p=p.split(",")[0].replace(/"/g,"").trim()),p.length>120&&(p=p.slice(0,120)+"\u2026"),d[u]=p)}return d}function On(e){let i=e.cloneNode(!0),l=[i,...i.querySelectorAll("*")];l.length>300&&(i=e.cloneNode(!1),i.textContent=`\u2026${e.querySelectorAll("*").length} descendants\u2026`,l=[i]);for(const u of l){if(u!==i&&/^(SCRIPT|STYLE|NOSCRIPT|TEMPLATE)$/.test(u.tagName)){u.remove();continue}u.tagName==="svg"&&u.querySelectorAll("*").length>4&&(u.innerHTML="\u2026"),u.tagName==="INPUT"&&(u.getAttribute("type")||"").toLowerCase()==="password"&&u.removeAttribute("value");for(const p of[...u.attributes])p.value.length>120&&u.setAttribute(p.name,p.value.slice(0,120)+"\u2026")}let d=i.outerHTML.replace(/\s+/g," ");return d.length>2500&&(d=d.slice(0,2500)+"\u2026(truncated)"),d}function Bn(e){const i=["id","class","href","src","alt","type","name","role","aria-label","placeholder","for","action"],l={};for(const d of e.attributes){if(i.includes(d.name)||d.name.startsWith("data-")){if(d.name==="data-el-mark")continue;l[d.name]=d.value.length>100?d.value.slice(0,100)+"\u2026":d.value}if(Object.keys(l).length>=12)break}return l}function Nt(e){const i=e.getBoundingClientRect(),l=[];for(let p=e.parentElement;p&&l.length<5&&p!==document.body&&p!==document.documentElement;p=p.parentElement)l.unshift(dt(p));const d={url:location.href,title:document.title,tag:e.tagName.toLowerCase(),selector:Pn(e),role:_n(e),name:_t(e),text:Se(e.innerText||e.textContent,300),attrs:Bn(e),styles:Un(e),html:On(e),ancestors:l,rect:{x:Math.round(i.left),y:Math.round(i.top),w:Math.round(i.width),h:Math.round(i.height)},viewport:{w:window.innerWidth,h:window.innerHeight,dpr:window.devicePixelRatio,scrollY:Math.round(window.scrollY)}},u=e.tagName==="INPUT"&&(e.type||"").toLowerCase()==="password";return/^(INPUT|TEXTAREA|SELECT)$/.test(e.tagName)&&!u&&(d.value=Se(e.value,200)),d}function qt(e,i){let l=document.elementFromPoint(e,i);for(;l&&l.shadowRoot;){const d=l.shadowRoot.elementFromPoint(e,i);if(!d||d===l)break;l=d}return l}function Rn(e){for(let i=e.parentElement;i;i=i.parentElement){const l=getComputedStyle(i);if(l.backgroundImage!=="none")return"busy";const d=l.backgroundColor.match(/[\d.]+/g);if(d&&(d[3]===void 0||+d[3]>.5)){const[u,p,n]=d.slice(0,3).map(L=>(L/=255,L<=.03928?L/12.92:((L+.055)/1.055)**2.4)),y=.2126*u+.7152*p+.0722*n;return y>.4?"light":y<.15?"dark":"busy"}}return/dark/.test(getComputedStyle(document.documentElement).colorScheme)&&!/light/.test(getComputedStyle(document.documentElement).colorScheme)?"dark":"light"}let Ut=null;function pe(){if(!A||!m)return;Ut!==A&&(Ut=A,m.box.className="box on-"+Rn(A));const e=A.getBoundingClientRect(),i=3;Object.assign(m.box.style,{display:"block",left:`${e.left-i}px`,top:`${e.top-i}px`,width:`${e.width+i*2}px`,height:`${e.height+i*2}px`});const l=A.id?`#${A.id}`:"",d=lt(A).slice(0,2).map(p=>"."+p).join("");if(m.box.classList.toggle("share",W),m.tag.classList.toggle("share",W),m.tag.replaceChildren(P(X.mark),r("span",null,A.tagName.toLowerCase()+l+d),r("span","dim",`${Math.round(e.width)}\xD7${Math.round(e.height)}`)),W){const p=r("span","to");p.append(P(X.link),"save & share"),m.tag.append(p)}else if(Ie){const p=r("span","to");p.append(P(X.harness(Ie.harness)),Ie.label),m.tag.append(p)}m.tag.style.display="flex";const u=e.top>40;m.tag.style.left=`${Math.max(4,Math.min(e.left-i,window.innerWidth-m.tag.offsetWidth-4))}px`,m.tag.style.top=u?`${e.top-i-30}px`:`${Math.min(e.bottom+i+6,window.innerHeight-30)}px`}function Ot(){m&&(m.box.style.display="none",m.tag.style.display="none")}let Bt=null;function Ee(e,i=!1){de();const l=m.toast;if(l.replaceChildren(),l.className=i?"toast pill err":"toast pill",i)l.append(r("span","ok","!"),r("span",null,e));else{const d=r("span","ok");d.append(P(X.check));const u=r("span","who",e.text||e.to||"sent to ");if(e.text||u.append(P(X.harness(e.harness)),e.label||"agent"),l.append(d,u),e.id){const p=r("span","chip");p.append(P(X.mark),`${e.id} `,r("b",null,e.tag||"")),l.append(p)}}l.style.display="flex",zn(i?5e3:2200)}function zn(e){clearTimeout(Bt),e!=null&&(Bt=setTimeout(()=>{m&&(m.toast.style.display="none"),!z&&!E&&je(100)},e))}let fe=null,pt=null;function oe(e){pt?.abort(),pt=null;const i=fe;fe=null,i&&(i.remove(),e&&i.anchor?.isConnected&&i.anchor.focus(),i.onClose?.())}function Rt(e,i,{parent:l=m.layer,onClose:d,label:u="More"}={}){oe();const p=r("div","dd");p.setAttribute("role","menu"),p.setAttribute("aria-label",u);for(const C of i){if(C==="-"){p.append(r("div","sep"));continue}const T=r("button",C.danger?"mi danger":"mi");if(T.type="button",T.setAttribute("role",C.checked!=null?"menuitemradio":"menuitem"),C.checked!=null&&T.setAttribute("aria-checked",String(!!C.checked)),C.icon&&T.append(P(C.icon)),T.append(r("span",null,C.label)),C.checked){const N=r("span","ck");N.append(P(I.check)),T.append(N)}C.count&&T.append(r("small",null,String(C.count))),T.addEventListener("click",N=>{N.stopPropagation(),C.keep||oe(),C.run(T)}),p.append(T)}p.anchor=e,p.onClose=d,l.append(p);const n=e.getBoundingClientRect(),y=p.offsetHeight,L=p.offsetWidth;let b=n.bottom+6;b+y>innerHeight-8&&(b=Math.max(8,n.top-y-6)),p.style.top=`${b}px`,p.style.left=`${Math.min(innerWidth-L-8,Math.max(8,n.right-L))}px`,fe=p,e.setAttribute("aria-expanded","true");const M=pt=new AbortController;M.signal.addEventListener("abort",()=>e.setAttribute("aria-expanded","false"));const O={capture:!0,signal:M.signal};return window.addEventListener("keydown",C=>{C.key==="Escape"&&(C.preventDefault(),C.stopPropagation(),oe(!0))},O),m.root.addEventListener("pointerdown",C=>!p.contains(C.target)&&!e.contains(C.target)&&oe(),O),window.addEventListener("pointerdown",C=>!$e(C)&&oe(),O),p.addEventListener("keydown",C=>{if(C.key!=="ArrowDown"&&C.key!=="ArrowUp")return;C.preventDefault();const T=[...p.querySelectorAll(".mi")],N=T.indexOf(m.root.activeElement);T[(N+(C.key==="ArrowDown"?1:-1)+T.length)%T.length].focus()}),p.querySelector(".mi")?.focus({preventScroll:!0}),p}const Ve=new Map,zt=e=>String(e||"").replace(/^https?:\/\//,""),It=e=>typeof e=="string"&&/^data:image\/(webp|png|jpeg);base64,[A-Za-z0-9+/=]+$/.test(e)?`url("${e}")`:"";function ut(){if(!m)return;const e=[...m.stack.querySelectorAll(".st")];m.stack.querySelector(".more")?.remove(),e.forEach((i,l)=>i.hidden=l<e.length-3),e.length>3&&m.stack.prepend(r("div","more",`+${e.length-3} more`))}function In(e,i){de();const l=r("div","st pill");l.setAttribute("role","status");const d=r("div","th"),u=r("div","lbl"),p=r("b",null,i),n=r("small",null,"capturing\u2026");u.append(p,n);const y=r("button","act","Copy");y.type="button",y.hidden=!0;const L=r("button","act ghost","Open");L.type="button",L.hidden=!0;const b=r("button","act ghost");b.type="button",b.hidden=!0;const M=r("button","act ghost icon");M.type="button",M.hidden=!0,M.append(P(I.dots)),M.setAttribute("aria-label","More"),M.title="More",M.setAttribute("aria-haspopup","menu");const O=r("div","acts");O.append(b,L,y,M);const C=r("div","bar"),T=r("i");C.append(T),l.append(d,u,O,C),m.stack.insertBefore(l,m.toast);let N=!1,ue=null,ie=null,Le="";const Ne=()=>{n.replaceChildren(...ie==="private"?[P(I.lock),`private \xB7 ${zt(Le)}`]:[zt(Le)]),n.title=Le},xe=async U=>{const H=await chrome.runtime.sendMessage({type:"share_visibility",token:e,visibility:U}).catch(ve=>({ok:!1,error:String(ve.message||ve)}));if(H?.ok)return qe.vis(H.access?.visibility||H.visibility||U),!0;const se=H?.code==="private_not_allowed"?Je:H?.error||"Couldn't change it";return N?n.replaceChildren(se):b.title=se,!1};b.addEventListener("click",()=>xe(ie==="private"?"unlisted":"private"));const ne=U=>{clearTimeout(ue),ue=setTimeout(()=>{l.classList.add("out"),setTimeout(()=>{l.remove(),Ve.delete(e),ut(),!z&&!E&&je(100)},Zn()?0:300)},U)},qe={set(U,H){N||(T.style.width=`${Math.max(0,Math.min(100,U))}%`,H&&(n.textContent=H))},thumb(U){const H=It(U);H&&(d.style.backgroundImage=H)},vis(U){ie=U==="private"?"private":"unlisted",b.replaceChildren(P(ie==="private"?I.lock:I.globe),ie==="private"?"Private":"Anyone"),b.setAttribute("aria-label",ie==="private"?"Private: only people you allow. Make it open to anyone with the link":"Anyone with the link. Make it private"),b.hidden=N,N&&Le&&Ne()},done(U,H,se,ve){N=!0,l.classList.add("done");const ae=se&&se.limit!=null?se.limit-se.used:null;ae!=null&&ae<=3&&(l.classList.add("has-left"),l.append(r("div","left",`${Math.max(0,ae)} left ${Ke(se)}`))),T.style.width="100%",p.textContent=H?"Link copied":"Link ready",Le=U,b.hidden=!0,ve&&(ie=ve),Ne(),y.hidden=!1,M.hidden=!1,M.onclick=()=>{if(fe?.anchor===M)return oe();clearTimeout(ue);const Me=ie==="private";Rt(M,[{label:"Anyone with the link",icon:I.globe,checked:!Me,run:()=>xe("unlisted")},{label:"Private",icon:I.lock,checked:Me,run:()=>xe("private")},{label:"Share with people\u2026",icon:I.people,run:()=>(ne(800),xt({tab:"saves",people:e}))},"-",{label:"Delete link",icon:X.trash,danger:!0,keep:!0,run:async Ge=>{if(Ge.dataset.sure!=="1"){Ge.dataset.sure="1",Ge.lastChild.textContent="Click again to delete";return}oe();const we=await chrome.runtime.sendMessage({type:"delete_saves",ids:[e],link:!0}).catch(()=>null);we?.ok?(p.textContent="Link deleted",n.replaceChildren("Nobody can open it now"),O.hidden=!0):n.replaceChildren(`Couldn't delete: ${we?.failed?.[0]?.error||"try again"}`),ne(2500)}}],{onClose:()=>ne(6e3)})},y.onclick=async()=>{y.textContent=await Ht(U)||(await chrome.runtime.sendMessage({type:"copy",text:U}).catch(()=>null))?.ok?"Copied":"Select it",ne(2500)},/^https?:/.test(U)&&(L.hidden=!1,L.onclick=()=>{window.open(U,"_blank","noopener"),ne(800)}),ne(H?4200:2e4)},remove(){N=!0,fe?.anchor===M&&oe(),clearTimeout(ue),l.remove(),Ve.delete(e),ut()},fail(U){N=!0,l.classList.add("err"),l.setAttribute("role","alert"),T.style.width="100%",p.textContent="Couldn't share",n.textContent=U,y.hidden=!1,y.textContent="Dismiss",y.onclick=()=>ne(0)}};return Ve.set(e,qe),ut(),qe.set(4,"capturing\u2026"),qe}async function Ht(e){try{return await navigator.clipboard.writeText(e),!0}catch{const i=document.createElement("textarea");i.value=e,i.style.cssText="position:fixed;opacity:0;left:0;top:0",document.documentElement.appendChild(i),i.select();let l=!1;try{l=document.execCommand("copy")}catch{}return i.remove(),l}}async function Kt(e){de(),on();const i=await chrome.runtime.sendMessage({type:"share_gate"}).catch(()=>({ok:!0}));if(i&&i.ok===!1)return Vt(i);const l=Nt(e),d=Math.random().toString(36).slice(2),u=_t(e)||Se(e.innerText||e.textContent,48)||dt(e),p=In(d,u);at++;let n;try{n=await chrome.runtime.sendMessage({type:"share_shot",token:d,data:l,label:u,sel:dt(e)}).catch(L=>({ok:!1,error:String(L.message||L)})),n?.thumb&&p.thumb(n.thumb),n?.ok&&p.vis(n.visibility),n&&n.ok&&(n=await chrome.runtime.sendMessage({type:"share",token:n.token,data:l}).catch(L=>({ok:!1,error:String(L.message||L)})))}finally{at--}if(n&&(n.code==="signed_out"||n.code==="quota_exceeded"||n.code==="private_not_allowed"))return p.remove(),Vt(n);if(!n||!n.ok)return p.fail(n?.error||"could not share this element");let y=!1;try{await navigator.clipboard.writeText(n.url),y=!0}catch{y=!!(await chrome.runtime.sendMessage({type:"copy",text:n.url}).catch(()=>null))?.ok}p.done(n.url,y,n.usage,n.visibility)}const ft="https://accounts.elmts.dev",Ae={upgradePro:`${ft}/upgrade?plan=pro&interval=month`,upgradeMax:`${ft}/upgrade?plan=max&interval=month`,billing:`${ft}/billing`},ht=e=>{const i=new Date(e);return Number.isNaN(i.getTime())?"":i.toLocaleDateString("en-US",{month:"short",day:"numeric",timeZone:"UTC"})},jt=e=>{const i=new Date(e);return Number.isNaN(i.getTime())?"Mon":i.toLocaleDateString("en-US",{weekday:"short",timeZone:"UTC"})},Qe=e=>e?.window==="week"?`resets ${jt(e.resetsAt)}`:ht(e?.resetsAt)?`resets ${ht(e.resetsAt)}`:"resets on the 1st",he=e=>chrome.runtime.sendMessage({type:"open_url",url:e}).catch(()=>{});let me=null,ge=null;function J(){ge?.abort(),ge=null,me?.remove(),me=null,!z&&!E&&je(100)}function be(e,i,l){const d=r("button",i?"act ghost":"act",e);return d.type="button",d.addEventListener("click",l),d}function Vt(e){de(),J();const i=r("div","st pill gate");i.setAttribute("role","alert");const l=r("div","th");l.append(P(X.link));const d=r("div","lbl"),u=r("b");d.append(u);const p=r("div","foot"),n=r("small"),y=r("div","acts");if(p.append(n,y),i.append(l,d),e.code==="signed_out"){u.textContent="Sign in to save & share";const b=e.data?.limits;n.textContent=b?`Free: ${b.sharesPerWeek} a week`:"Free: 10 a month";const M=be("Sign in",!1,async()=>{M.disabled=!0;const O=await chrome.runtime.sendMessage({type:"login_start"}).catch(C=>({ok:!1,error:String(C.message||C)}));if(!O||!O.ok||!O.userCode){M.disabled=!1,n.textContent=/hub/i.test(O?.error||"")?"Run el install first":O?.error||"Couldn't start sign-in";return}u.textContent="Confirm the code in the new tab",n.textContent=`code ${O.userCode}`,M.remove()});y.append(be("Not now",!0,J),M)}else if(e.code==="private_not_allowed")u.textContent=Je,n.textContent="nothing was shared",y.append(be("Upgrade",!1,()=>(he(Ae.upgradePro),J())));else{const b=e.data||{};u.textContent=`You've used ${b.used??b.limit} of ${b.limit} save & shares ${Ke(b)}`,n.textContent=Qe(b);const M=r("div","meterrow"),O=r("i");O.style.width="100%",M.append(O),i.append(M),b.plan==="free"?y.append(be("Upgrade",!1,()=>(he(Ae.upgradePro),J()))):b.plan==="pro"&&y.append(be("Upgrade to Max",!1,()=>(he(Ae.upgradeMax),J())))}i.append(p),m.stack.insertBefore(i,m.toast),me=i,ge=new AbortController;const L={capture:!0,signal:ge.signal};if(window.addEventListener("keydown",b=>b.key==="Escape"&&J(),L),window.addEventListener("pointerdown",b=>!$e(b)&&!b.altKey&&J(),L),e.code!=="signed_out"){const b=i;setTimeout(()=>me===b&&J(),8e3)}}function Hn(e){de(),J();const i=e.data||{},l=r("div","st pill gate");l.setAttribute("role","alert");const d=r("div","th"),u=r("div","lbl"),p=r("b"),n=r("small");u.append(p,n);const y=r("div","full");if(l.append(d,u,y),e.code==="pick_signed_out"){d.append(P(X.mark)),p.textContent="Sign in to start picking",n.textContent=`free \xB7 ${i.limit||50} picks a week`;const b=(M,O)=>{const C=be("",!1,async()=>{for(const N of y.querySelectorAll("button"))N.disabled=!0;const T=await chrome.runtime.sendMessage({type:"login_start",provider:M}).catch(N=>({ok:!1,error:String(N.message||N)}));if(!T||!T.ok||!T.userCode){for(const N of y.querySelectorAll("button"))N.disabled=!1;n.textContent=/hub/i.test(T?.error||"")?"Run el install first":T?.error||"Couldn't start sign-in";return}p.textContent="Confirm the code in the new tab",n.textContent=`code ${T.userCode} \xB7 your pick goes once you're in`,y.remove()});return C.append(P($n[M]),O),C};y.append(b("github","GitHub"),b("google","Google"))}else d.append(P(I.lock)),p.textContent=`That's ${i.limit||50} picks this week`,n.textContent="Your pick is saved: upgrade to send it",u.append(r("small",null,`resets ${jt(i.resetsAt)} \xB7 Pro is unlimited`)),y.append(be("Not now",!0,()=>{chrome.runtime.sendMessage({type:"held_drop"}).catch(()=>{}),J()}),be("Get Pro \xB7 $8/mo",!1,()=>{chrome.runtime.sendMessage({type:"held_upgrade"}).catch(()=>{}),he(Ae.upgradePro),J()}));m.stack.insertBefore(l,m.toast),me=l,ge=new AbortController;const L={capture:!0,signal:ge.signal};window.addEventListener("keydown",b=>b.key==="Escape"&&J(),L),window.addEventListener("pointerdown",b=>!$e(b)&&!b.altKey&&J(),L)}function mt(e){W!==e&&(W=e,z&&pe())}function $e(e){return j&&e.target===j}function ee(e){return $e(e)?!0:(V&&E&&e.type==="pointerdown"&&E.close(),e.preventDefault(),e.stopPropagation(),e.stopImmediatePropagation(),!1)}function Wt(e){if(V)return;if(Y.hold){const l=He(e);if(!l)return Xt();mt(l==="save")}const i=qt(e.clientX,e.clientY);i&&i!==A&&i!==j&&(A=i,rt=[],pe())}function Gt(e){if(!ee(e)){if(_e||W){_e=!1;return}V||!A||et(A,e.shiftKey)}}function Yt(e){$e(e)||V||(e.type==="pointerdown"&&(_e=!1),!(W||En()))||(ee(e),!(e.type!=="pointerdown"||e.button!==0&&e.button!==2||!A)&&(!W&&Re||(_e=!0,W?Kt(A):et(A,e.shiftKey))))}function Zt(e){const i=Y.hold?He(e):null;(W||_e||i==="save"||i&&e.ctrlKey)&&ee(e)}function Xt(){Re?st=!0:re()}function Jt(e){if(Y.hold&&!V){if(F.modOfKey(e.key)){const i=He(e);if(!i)return re();mt(i==="save")}else if(!["Escape","Enter","ArrowUp","ArrowDown"].includes(e.key))return re()}if(V){e.key==="Escape"&&(ee(e),E?.close());return}e.key==="Escape"?(ee(e),re()):e.key==="ArrowUp"&&A?.parentElement&&A.parentElement!==document.documentElement?(ee(e),rt.push(A),A=A.parentElement,pe()):e.key==="ArrowDown"&&A?(ee(e),A=rt.pop()||A.firstElementChild||A,pe()):e.key==="Enter"&&A&&(ee(e),W?Kt(A):et(A,e.shiftKey))}const Qt=["mousedown","mouseup","pointerdown","pointerup","dblclick","auxclick"];function gt(e){if(E&&E.close(),Y=e||{},W=!!(Y.hold&&Y.share),z=!0,V=!1,A=null,de(),Ie=null,chrome.runtime.sendMessage({type:"tab_owner"}).then(i=>{Ie=i||null,z&&pe()}).catch(()=>{}),Xe){const i=qt(Xe.x,Xe.y);i&&i!==j&&(A=i,pe())}window.addEventListener("mousemove",Wt,!0),window.addEventListener("click",Gt,!0),window.addEventListener("keydown",Jt,!0),window.addEventListener("scroll",pe,!0),window.addEventListener("contextmenu",Zt,!0);for(const i of["pointerdown","mousedown","pointerup","mouseup"])window.addEventListener(i,Yt,!0);for(const i of Qt)window.addEventListener(i,ee,!0)}function re(){z=!1,V=!1,window.removeEventListener("mousemove",Wt,!0),window.removeEventListener("click",Gt,!0),window.removeEventListener("keydown",Jt,!0),window.removeEventListener("scroll",pe,!0),window.removeEventListener("contextmenu",Zt,!0);for(const e of["pointerdown","mousedown","pointerup","mouseup"])window.removeEventListener(e,Yt,!0);for(const e of Qt)window.removeEventListener(e,ee,!0);W=!1,_e=!1,Ot(),V&&E&&E.close(),A=null,je(3e3)}const en=()=>new Promise(e=>requestAnimationFrame(()=>e())),Kn={purple:"#8E4EC6",blue:"#2E6BFF",green:"#30A46C",orange:"#F76B15",pink:"#D6409F",cyan:"#00A2C7",yellow:"#D9A400",red:"#E5484D",grey:"#8D8D8D"},tn={"1d":"1 day","7d":"7 days","30d":"30 days",never:"Never"},jn='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="12" cy="8" r="4"/><path d="M4 21c1.5-4 4.5-6 8-6s6.5 2 8 6"/></svg>',Vn={free:"Free",pro:"Pro",max:"Max"},nn=e=>Vn[e]||(e?e.charAt(0).toUpperCase()+e.slice(1):""),Wn={github:"GitHub",google:"Google"},Gn=e=>e==="never"?"never expire":`last ${e==="1d"?"24 hours":tn[e]||"7 days"}`,Yn='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg>',Zn=()=>matchMedia("(prefers-reduced-motion: reduce)").matches,Xn=e=>{const i=`${e.harness} \xB7 `;return e.label&&e.label.startsWith(i)?e.label.slice(i.length):e.label||e.project||"session"};function Jn(e){const i=Math.max(0,Math.round((Date.now()-e)/1e3));if(i<45)return"just now";if(i<3600)return`${Math.max(1,Math.round(i/60))} min`;if(i<86400)return`${Math.round(i/3600)} h`;const l=Math.round(i/86400);return l<=1?"yesterday":`${l} days`}const Qn=e=>new Date(e).toDateString()===new Date().toDateString();function We(e){const i=String(e.title||"").split(/\s[|–—·:-]\s/)[0].trim().slice(0,40)||e.host||"Untitled";return e.name?`${i} \xB7 ${e.name}`:i}let bt=!1;function on(){bt||(bt=!0,chrome.runtime.sendMessage({type:"fonts"}).then(e=>{for(const i of e||[]){const l=atob(i.data),d=new Uint8Array(l.length);for(let p=0;p<l.length;p++)d[p]=l.charCodeAt(p);const u=new FontFace(i.family,d.buffer,{weight:String(i.weight),display:"swap"});u.load().then(()=>document.fonts.add(u)).catch(()=>{})}}).catch(()=>bt=!1))}const eo=`
292
+ <div class="mh">
293
+ <span class="mark"></span>
294
+ <div class="tabs" role="tablist" aria-label="element">
295
+ <button type="button" role="tab" data-tab="saves">Saves<span class="n"></span><span class="badge rq" hidden></span></button>
296
+ <button type="button" role="tab" data-tab="sessions">Sessions</button>
297
+ <button type="button" role="tab" data-tab="settings">Settings</button>
298
+ </div>
299
+ <span class="kb esc" role="button" title="Close (esc)">esc</span>
300
+ </div>
301
+ <label class="search" data-for="saves">${Yn}<input type="text" placeholder="Search saves" autocomplete="off" spellcheck="false" aria-label="Search saves"></label>
302
+ <div class="usage" hidden></div>
303
+ <div class="mbody">
304
+ <div class="pane" data-pane="saves" role="tabpanel"></div>
305
+ <div class="pane" data-pane="sessions" role="tabpanel"></div>
306
+ <div class="pane set" data-pane="settings" role="tabpanel"></div>
307
+ </div>
308
+ <div class="selbar" hidden><span></span><button type="button" class="ib">Copy links</button><button type="button" class="ib">Delete</button><button type="button" class="ib gh">Clear</button><div class="cfm" role="group" aria-label="Delete the selected saves" hidden><p></p><button type="button" class="ib danger">Delete links</button><button type="button" class="ib">Remove from list</button><button type="button" class="ib gh">Cancel</button></div></div>
309
+ <div class="sr" role="status" aria-live="polite"></div>
310
+ <div class="mf"><span class="where"></span><span class="whom"></span></div>`;async function xt(e={}){if(E&&!e.choose&&!E.choose&&!e.people&&(!e.tab||e.tab===E.tab))return E.close();E&&E.close(),z&&!e.choose&&re(),de(),on();const i=m.mod;i.innerHTML=eo,i.querySelector(".mark").append(P(X.mark),"element");const l=t=>i.querySelector(t),d=l(".search input"),u={saves:l('[data-pane="saves"]'),sessions:l('[data-pane="sessions"]'),settings:l('[data-pane="settings"]')},p=l(".selbar"),n={tab:e.choose?"sessions":e.tab||"saves",choose:!!e.choose,sessions:e.sessions||[],owner:e.owner||null,tabId:e.tabId,hubUp:e.hubUp!==!1,lastError:e.lastError||"",plan:e.plan||null,saves:[],picked:new Set,rows:new Map,expiry:"7d",theme:"system",resolve:null,acct:null,signing:null};E=n;const y=await chrome.storage.local.get(["saves","expiry","theme","newVisibility","privateWho"]).catch(()=>({}));if(E!==n)return null;n.newVisibility=y.newVisibility,n.privateWho=y.privateWho,n.saves=Array.isArray(y.saves)?y.saves:[],n.storedExpiry=y.expiry,n.theme=y.theme||"system";const L=()=>i.classList.toggle("dark",n.theme==="dark"||n.theme!=="light"&&matchMedia("(prefers-color-scheme: dark)").matches);L();const b=[...i.querySelectorAll(".tabs button")];function M(t,o=!1){n.tab=t;for(const s of b){const a=s.dataset.tab===t;s.setAttribute("aria-selected",String(a)),s.tabIndex=a?0:-1,a&&o&&s.focus()}for(const[s,a]of Object.entries(u))a.hidden=s!==t;l(".search").hidden=t!=="saves",Tt(),tt(),t==="sessions"&&cn(),t==="settings"&&Ce()}b.forEach(t=>t.addEventListener("click",()=>M(t.dataset.tab))),l(".esc").addEventListener("click",()=>n.close());function O(){const t=d.value.trim().toLowerCase();return n.saves.filter(o=>!t||`${We(o)} ${o.host} ${o.selector} ${o.url}`.toLowerCase().includes(t))}function C(t,o,s,a){Promise.resolve(Ht(t)).then(async c=>{c=c||!!(await chrome.runtime.sendMessage({type:"copy",text:t}).catch(()=>null))?.ok;const h=o.textContent;o.textContent=c?s:"Copy failed",setTimeout(()=>{o.textContent=h,a?.()},1100)})}function T(t){const o=r("div","row");o.tabIndex=0,o.dataset.id=t.id;const s=document.createElement("input");s.type="checkbox",s.tabIndex=-1;const a=r("div","th"),c=r("div","t"),h=r("b"),x=r("small"),k=r("div","bar");k.append(r("i")),c.append(h,x,k);const f=r("div","end"),g=r("div","acts"),v=r("button","ib pri","Copy link"),D=r("button","ib","Open"),S=r("button","ib ic");S.append(P(I.dots)),S.setAttribute("aria-label","More"),S.setAttribute("aria-haspopup","menu"),S.title="More",v.type=D.type=S.type="button",g.append(v,D,S);const q=r("span","when");return f.append(g,q),o.append(s,a,c,f),s.addEventListener("change",()=>{s.checked?n.picked.add(t.id):n.picked.delete(t.id),o.classList.toggle("sel",s.checked),Ue(),tt()}),S.addEventListener("click",()=>fe?.anchor===S?oe():Le(o,t.id)),v.addEventListener("click",()=>{const w=n.saves.find(K=>K.id===t.id);if(w?.status==="error")return chrome.runtime.sendMessage({type:"remove_saves",ids:[t.id]}).catch(()=>{});w?.viewUrl&&C(w.viewUrl,v,"Copied")}),D.addEventListener("click",()=>{const w=n.saves.find(K=>K.id===t.id);w?.viewUrl&&/^https?:/.test(w.viewUrl)&&window.open(w.viewUrl,"_blank","noopener")}),o.refs={cb:s,th:a,b:h,small:x,bar:k,fill:k.firstChild,acts:g,copy:v,open:D,del:S,when:q,cf:null,ap:null},o}const N=t=>!!(t&&t.status==="done"&&t.viewUrl&&n.hubUp&&le()),ue=new Map;function ie(t,o){ue.set(t,o),ae(o),Q(),setTimeout(()=>ue.get(t)===o&&(ue.delete(t),E===n&&Q()),5e3)}function Le(t,o){const s=n.saves.find(c=>c.id===o);if(!s||s.status==="active")return;const a=[];if(N(s)){const c=s.visibility==="private";a.push({label:"Anyone with the link",icon:I.globe,checked:!c,run:()=>Ne(o,"unlisted")},{label:"Private",icon:I.lock,checked:c,run:()=>Ne(o,"private")},{label:"People & requests",icon:I.people,count:(s.requests||[]).length,run:()=>ne(t,o,!0)},"-")}a.push({label:"Remove from list",icon:X.trash,run:()=>we([o],!1)}),Me(s)&&a.push({label:"Delete link",icon:X.trash,danger:!0,run:()=>rn(t,o)}),Rt(t.refs.del,a,{parent:m.mod})}async function Ne(t,o){const s=await chrome.runtime.sendMessage({type:"share_visibility",token:t,visibility:o}).catch(a=>({ok:!1,error:String(a.message||a)}));return E!==n||(s?.ok?ae(o==="private"?"Private: only people you allow":"Anyone with the link can open it"):ie(t,s?.code==="private_not_allowed"?Je:`Couldn't change it: ${s?.error||"try again"}`)),s}async function xe(t,o){const s=await chrome.runtime.sendMessage({type:"link_access",id:t,action:"update",change:o}).catch(h=>({ok:!1,error:String(h.message||h)})),a=n.rows.get(t);if(E!==n||!a?.refs.ap)return s;const c=a.refs.ap.querySelector(".note2");return!s?.ok&&c&&(c.textContent=s?.code==="private_not_allowed"?Je:s?.error||"Couldn't change it",c.classList.add("err")),s}function ne(t,o,s=!t.refs.ap){if(!s){t.refs.ap?.remove(),t.refs.ap=null;return}t.refs.ap||(t.refs.ap=r("div","ap"),t.refs.ap.setAttribute("role","group"),t.append(t.refs.ap)),H(t,n.saves.find(a=>a.id===o),!0),chrome.runtime.sendMessage({type:"link_access",id:o,action:"get"}).catch(()=>{}),(t.refs.ap.querySelector("input")||t.refs.ap.querySelector('[aria-pressed="true"]'))?.focus({preventScroll:!0}),t.scrollIntoView({block:"nearest"})}const qe=t=>t.startsWith("@")?"@":t.replace(/@.*/,"").split(/[._+-]+/).filter(Boolean).slice(0,2).map(o=>o[0]).join("").toUpperCase()||"?";function U(t,o,s,...a){const c=r("div","p");return c.append(r("span","av",qe(o)),r("span","nm",t),r("span","r",s),...a),c}function H(t,o,s=!1){const a=t.refs.ap;if(!a||!o)return;const c=JSON.stringify([o.visibility,o.allow,o.requests]);if(!s&&a.dataset.k===c)return;a.dataset.k=c,a.setAttribute("aria-label",`Who can open ${We(o)}`);const h=o.visibility==="private",x=Ze([["unlisted","Anyone with link"],["private","Private"]],h?"private":"unlisted",S=>Ne(o.id,S));x.classList.add("sm"),x.children[0].prepend(P(I.globe)),x.children[1].prepend(P(I.lock));const k=[x],f=r("p","note2",h?"":"Anyone with the link can open it. Make it private to choose who.");if(h){const S=r("form","inp"),q=r("input");q.type="text",q.placeholder="Add email or @domain",q.setAttribute("aria-label","Add email or @domain"),q.autocomplete="off",q.spellcheck=!1;const w=r("button","ib pri","Add");w.type="submit",S.append(q,w),S.addEventListener("submit",async R=>{R.preventDefault();const G=q.value.trim();if(!G)return;w.disabled=!0;const _=await xe(o.id,{add:G.split(/[\s,;]+/).filter(Boolean)});w.disabled=!1,_?.ok&&(q.value="",ae(`Added ${G}`))});const K=r("div","ppl");for(const R of o.requests||[]){const G=U(R.email,R.email,"wants access",ce("Deny","ib",()=>xe(o.id,{deny:[R.email]})),ce("Allow","ib pri",()=>xe(o.id,{approve:[R.email]})));G.classList.add("req"),K.append(G)}K.append(U("you",n.acct?.email||"you","owner"));for(const R of o.allow||[]){const G=ce("\xD7","ib ic",()=>xe(o.id,{remove:[R]}));G.setAttribute("aria-label",`Remove ${R}`),K.append(U(R.startsWith("@")?`anyone at ${R}`:R,R,"can open",G))}k.push(S,K)}k.push(f);const g=a.contains(m.root.activeElement)?m.root.activeElement:null,v=a.querySelector("input")?.value||"";a.replaceChildren(...k);const D=a.querySelector("input");D&&v&&(D.value=v),g&&!g.isConnected&&(D||x.querySelector('[aria-pressed="true"]'))?.focus({preventScroll:!0})}function se(t,o){const s=t.refs,a=o.status==="active",c=o.status==="error";t.classList.toggle("err",c),t.classList.toggle("sel",n.picked.has(o.id)),s.cb.checked=n.picked.has(o.id),s.cb.disabled=a||c||!o.viewUrl,s.cb.setAttribute("aria-label",`Select ${We(o)}`);const h=It(o.thumb);s.th.dataset.thumb!==h&&(s.th.style.backgroundImage=h,s.th.dataset.thumb=h),s.b.textContent=We(o),s.b.title=o.url||"";const x=a?o.stage||"uploading":c?`failed \xB7 ${o.error||"unknown error"}`:ue.get(o.id)||[o.host,o.selector].filter(Boolean).join(" \xB7 "),k=!a&&!c&&o.visibility==="private"?r("span","lk"):null;k&&(k.append(P(I.lock)),k.title="Private"),s.small.replaceChildren(...k?[k]:[],x),s.bar.hidden=!a,s.fill.style.width=`${Math.round(o.progress||0)}%`,s.acts.hidden=a,a&&wt(t,!1),s.copy.textContent=c?"Remove":s.copy.textContent==="Copied"?"Copied":"Copy link",s.open.hidden=c;const f=!a&&!c&&o.visibility==="private"?(o.requests||[]).length:0,g=f?r("span","badge",String(f)):null;g&&(g.title=`${f} ${f===1?"person wants":"people want"} access`),s.when.replaceChildren(...g?[g]:[],a?`${Math.round(o.progress||0)}%`:c?"failed":Jn(o.createdAt)),s.ap&&H(t,o)}const ve=l(".sr");function ae(t){ve.textContent="",setTimeout(()=>ve.textContent=t,50)}const Me=t=>!!(t&&t.deleteToken&&t.status==="done"&&t.viewUrl);function Ge(t){const o=[...u.saves.querySelectorAll(".row")],s=o.findIndex(c=>t.includes(c.dataset.id)),a=o.filter(c=>!t.includes(c.dataset.id));return a.find(c=>o.indexOf(c)>s)||a.filter(c=>o.indexOf(c)<s).pop()||null}async function we(t,o){n.nextFocus=Ge(t);const s=o&&n.saves.some(h=>t.includes(h.id)&&Me(h)),a=await chrome.runtime.sendMessage({type:"delete_saves",ids:t,link:o}).catch(()=>null)||{ok:!1,removed:[],failed:t.map(h=>({id:h,error:"reload the page and try again"}))};if(E!==n)return a;const c=a.removed||[];if(c.length){n.saves=n.saves.filter(x=>!c.includes(x.id));for(const x of c)n.picked.delete(x);Q();const h=m.root.activeElement;(!h||!h.isConnected||h.disabled)&&(n.nextFocus?.isConnected?n.nextFocus:d).focus(),ae(`${s?"Deleted":"Removed"}${c.length>1?` ${c.length} saves`:""}`)}return a}function wt(t,o){t.refs.cf&&(t.refs.cf.remove(),t.refs.cf=null,t.classList.remove("asking"),o&&t.refs.del.focus())}function rn(t,o){const s=n.saves.find(v=>v.id===o);if(!s||s.status==="active")return;if(!Me(s))return we([o],!1);if(t.refs.cf)return t.refs.cf.querySelector("button").focus();const a=r("div","cf");a.setAttribute("role","group"),a.setAttribute("aria-label",`Delete ${We(s)}`);const c=r("p","","Delete the link too? People who have it won't be able to open it."),h=c.textContent,x=r("button","ib danger","Delete link"),k=r("button","ib","Remove from list"),f=r("button","ib","Cancel");x.type=k.type=f.type="button",a.append(c,x,k,f),t.refs.cf=a,t.classList.add("asking"),t.append(a);const g=(v,D)=>{for(const S of[x,k,f])S.disabled=v;c.classList.remove("err"),c.textContent=D||h};x.addEventListener("click",async()=>{g(!0,"Deleting the link\u2026");const v=await we([o],!0);!t.isConnected||!v.failed?.length||(g(!1),c.textContent=`Couldn't delete the link: ${v.failed[0].error}.`,c.classList.add("err"),ae(c.textContent),x.focus())}),k.addEventListener("click",async()=>{g(!0,"Removing\u2026");const v=await we([o],!1);t.isConnected&&v.failed?.length&&g(!1)}),f.addEventListener("click",()=>wt(t,!0)),f.focus()}function Q(){l(".tabs .n").textContent=String(n.saves.length);const t=n.saves.reduce((f,g)=>f+(g.visibility==="private"&&g.status==="done"?(g.requests||[]).length:0),0),o=l(".tabs .rq");o.hidden=!t,o.textContent=String(t),o.title=`${t} access request${t===1?"":"s"}`,l(".where").textContent=`Saved on this device \xB7 links ${Gn(n.expiry)}`;for(const f of n.picked)n.saves.some(g=>g.id===f&&g.viewUrl)||n.picked.delete(f);const s=O(),a=[];let c="";for(const f of s){const g=Qn(f.createdAt)?"Today":"Earlier";g!==c&&(c=g,a.push(r("div","grp",g)));let v=n.rows.get(f.id);v||(v=T(f),n.rows.set(f.id,v)),se(v,f),a.push(v)}for(const[f,g]of n.rows)s.some(v=>v.id===f)||n.rows.delete(f)&&g.remove();s.length||a.push(n.saves.length?r("div","grp","No saves match"):r("div","note",`Nothing saved yet. Hold ${F.format(te.save)} and click any element: its share link is copied and lands here.`));const h=u.saves,x=[...h.children];if(!(x.length===a.length&&x.every((f,g)=>f===a[g]||f.className==="grp"&&a[g].className==="grp"&&f.textContent===a[g].textContent))){const f=m.root.activeElement;h.replaceChildren(...a),f&&!f.isConnected?(n.nextFocus?.isConnected?n.nextFocus:d).focus():f&&f!==m.root.activeElement&&f.focus()}tt()}function tt(){p.hidden=!(n.tab==="saves"&&n.picked.size),p.hidden&&Ue(),p.querySelector("span").textContent=`${n.picked.size} selected`}const[sn,an,no]=p.querySelectorAll(":scope > button"),ke=p.querySelector(".cfm"),[Te,Ye,kt,nt]=[ke.querySelector("p"),...ke.querySelectorAll("button")];function Ue(t){if(!ke.hidden){ke.hidden=!0,p.classList.remove("asking");for(const o of p.querySelectorAll(":scope > span, :scope > button"))o.hidden=!1;t&&an.focus()}}const ln=()=>n.saves.filter(t=>n.picked.has(t.id));async function yt(t){const o=ln().map(a=>a.id);if(!o.length)return Ue();for(const a of[Ye,kt,nt])a.disabled=!0;Te.classList.remove("err"),ke.hidden||(Te.textContent=t?"Deleting the links\u2026":"Removing\u2026");const s=await we(o,t);if(E===n){for(const a of[Ye,kt,nt])a.disabled=!1;if(s.failed?.length){n.picked=new Set(s.failed.map(c=>c.id).filter(c=>n.saves.some(h=>h.id===c))),Q();const a=s.failed.length;Te.textContent=`Couldn't delete ${a===1?"a link":`${a} links`}: ${s.failed[0].error}. Still selected.`,Te.classList.add("err"),ae(Te.textContent),ke.hidden||Ye.focus();return}Ue(),tt(),(n.nextFocus?.isConnected?n.nextFocus:d).focus()}}an.addEventListener("click",()=>{const t=ln().filter(Me).length;if(!t)return yt(!1);const o=t>1;Te.classList.remove("err"),Te.textContent=o?`Delete the ${t} links too? People who have them won't be able to open them.`:"Delete the link too? People who have it won't be able to open it.",Ye.textContent=o?"Delete links":"Delete link";for(const s of p.querySelectorAll(":scope > span, :scope > button"))s.hidden=!0;p.classList.add("asking"),ke.hidden=!1,nt.focus()}),Ye.addEventListener("click",()=>yt(!0)),kt.addEventListener("click",()=>yt(!1)),nt.addEventListener("click",()=>Ue(!0)),sn.addEventListener("click",()=>{const t=n.saves.filter(o=>n.picked.has(o.id)&&o.viewUrl).map(o=>o.viewUrl);C(t.join(`
311
+ `),sn,`Copied ${t.length} link${t.length===1?"":"s"}`,()=>{n.picked.clear(),Q()})}),no.addEventListener("click",()=>{n.picked.clear(),Q()}),d.addEventListener("input",Q);function Ct(){return[...u.sessions.querySelectorAll('.sess:not([aria-disabled="true"])')]}function cn(){const t=u.sessions,o=JSON.stringify([n.hubUp,n.choose,n.owner,n.sessions.map(f=>[f.id,f.label,f.harness,f.color,f.branch,f.lastPrompt,f.cwd])]);if(t.dataset.sig===o&&t.childElementCount)return;t.dataset.sig=o;const s=m.root.activeElement,a=s&&t.contains(s)?s.dataset.session||(s.classList.contains("un")?"un":null):null,c=l(".mbody"),h=c.scrollTop,x=n.sessions.some(f=>f.id===n.owner)?n.owner:null,k=[];if(n.hubUp){if(k.push(r("div","grp",n.choose?"Send to which session? This tab will stick to it.":"This tab sends to")),!n.sessions.length){const f=r("div","note","No agent sessions running. Start Claude Code, Codex or Cursor (after `el install --claude`, `--codex` or `--cursor`), or run ");f.append(r("code",null,"el open <url>")," from your agent."),k.push(f)}if(n.sessions.forEach((f,g)=>{const v=r("button","sess");v.type="button",v.dataset.session=f.id;const D=P(X.harness(f.harness));D.style.color=Kn[f.color]||"currentColor";const S=r("span","nm");S.append(r("b",null,Xn(f)));const q=Ln(f);q&&S.append(r("small",null,q));const w=f.id===x&&!n.choose?r("span","cur","this tab"):g<9?r("span","kb",String(g+1)):r("span");v.append(D,S,w),f.lastPrompt&&v.append(r("span","pr",`\u201C${f.lastPrompt}\u201D`)),v.title=f.cwd||f.label,v.addEventListener("click",()=>St(f.id)),k.push(v)}),!n.choose&&n.sessions.length){k.push(r("div","grp","Tab"));const f=r("button","sess un");f.type="button",f.append(r("span"),r("span","nm","Unassign this tab"),r("span")),x?f.addEventListener("click",()=>St("unassign")):f.setAttribute("aria-disabled","true"),k.push(f)}}else{const f=r("div","note","Can't reach the local hub. Run ");f.append(r("code",null,"el install"),", then reload the extension."),k.push(r("div","grp","Sessions"),f)}t.replaceChildren(...k),a&&((a==="un"?t.querySelector(".sess.un"):t.querySelector(`[data-session="${CSS.escape(a)}"]`))||Ct()[0]||b[1]).focus({preventScroll:!0}),n.tab==="sessions"&&(c.scrollTop=h)}async function St(t){if(n.choose)return n.close(t);const o=n.tabId,s=n.sessions.find(a=>a.id===t);if(n.close(),t==="unassign"){const a=await chrome.runtime.sendMessage({type:"unassign",tabIds:[o]}).catch(c=>({ok:!1,error:String(c.message||c)}));a&&a.ok?Ee({text:"this tab is unassigned"}):Ee(a?.error||"could not unassign this tab",!0)}else if(s&&t!==n.owner){const a=await chrome.runtime.sendMessage({type:"module_assign",session:t}).catch(c=>({ok:!1,error:String(c.message||c)}));a&&a.ok?Ee({to:a.tabs>1?`${a.tabs} tabs \u2192 `:"this tab \u2192 ",label:s.label,harness:s.harness}):Ee(a?.error||"could not switch session",!0)}}function Ze(t,o,s){const a=r("div","seg");a.setAttribute("role","group");for(const[c,h]of t){const x=r("button",null,h);x.type="button",x.setAttribute("aria-pressed",String(c===o)),x.addEventListener("click",()=>{for(const k of a.children)k.setAttribute("aria-pressed",String(k===x));s(c)}),a.append(x)}return a}const Fe=(t,...o)=>{const s=r("div","li");return s.append(r("span",null,t),...o),s},Oe=r("div","hkmsg");Oe.setAttribute("aria-live","polite"),Oe.id="el-hkmsg";const Et="Hold the keys and click. Modifier keys only.",Pe=(t,o="")=>{Oe.textContent=t||Et,Oe.className=`hkmsg${o?" "+o:""}`};Pe();const At={pick:"Pick",save:"Save"};let B=null;const Be=r("div","keys"),$t=r("div","li");function dn(t){const o=r("span","kb hkchip",F.chip(te[t])),s=r("button","ib hkbtn","Change");s.type="button",s.dataset.hk=t,s.setAttribute("aria-describedby",Oe.id),s.setAttribute("aria-label",`Change the ${At[t]} hotkey, now ${F.chip(te[t])}`),s.addEventListener("click",()=>B?.which===t?ye("Cancelled. "+Et):oo(t,o,s)),s.addEventListener("blur",()=>B?.btn===s&&ye());const a=r("span","hkc");return a.append(o,s),Fe(t==="pick"?"Pick an element":"Save an element",a)}function oo(t,o,s){B&&ye(),B={which:t,held:[],chip:o,btn:s},o.classList.add("rec"),o.textContent="Hold the keys\u2026",s.textContent="Cancel",s.setAttribute("aria-pressed","true"),s.focus(),Pe(`Recording ${At[t]}: hold the modifier keys (\u2303 \u2325 \u21E7 \u2318), then let go. Enter keeps them, esc cancels.`,"rec")}function ye(t,o){if(!B)return;const{which:s,chip:a,btn:c}=B;B=null,a.classList.remove("rec"),a.textContent=F.chip(te[s]),c.textContent="Change",c.removeAttribute("aria-pressed"),t!==void 0?Pe(t,o):Pe()}function pn(t){const o=B.which,s={...te,[o]:F.norm(t)},a=F.validate(s);if(a.errors[o])return ye(a.errors[o],"err");ye(`${At[o]} is now ${F.chip(s[o])}.${a.warnings[o]?" "+a.warnings[o]:""}`,a.warnings[o]?"warn":"ok"),F.same(s[o],te[o])||chrome.storage.local.set({hotkeys:{pick:s.pick,save:s.save}}).catch(()=>{})}function un(t){if(t.key==="Tab")return ye();if(t.preventDefault(),t.type==="keyup"){F.modOfKey(t.key)&&!F.fromEvent(t).length&&B.held.length&&pn(B.held);return}if(!t.repeat){if(t.key==="Escape")return ye("Cancelled. "+Et);if(t.key==="Enter")return B.held.length?pn(B.held):Pe("Hold one or more modifier keys first: \u2303 \u2325 \u21E7 \u2318 (Ctrl, Alt, Shift, Win).","err rec");if(!F.modOfKey(t.key))return B.held=[],B.chip.textContent="Hold the keys\u2026",Pe(`Modifier keys only (\u2303 \u2325 \u21E7 \u2318): you hold them while you click, so ${t.key.length===1?t.key.toUpperCase():t.key} can't be part of it. Esc cancels.`,"err rec");B.held=F.norm([...B.held,...F.fromEvent(t),F.modOfKey(t.key)]),B.chip.textContent=`${F.format(B.held)}\u2026`}}async function fn(){const o=(await chrome.runtime.sendMessage({type:"commands"}).catch(()=>[])||[]).find(h=>h.name==="switch-session")?.shortcut||"",s=r("button","ib",o?"Change":"Set");s.type="button",s.title=o?"Chrome sets extension shortcuts: change it at chrome://extensions/shortcuts":"Chrome dropped this shortcut (it clashes with another): set one at chrome://extensions/shortcuts",s.setAttribute("aria-label",o?`Change the Open element shortcut, now ${o}, in Chrome's shortcut settings`:"Set the Open element shortcut in Chrome's shortcut settings"),s.addEventListener("click",()=>chrome.runtime.sendMessage({type:"open_shortcuts"}).catch(()=>{}));const a=r("span","hkc");a.append(o?r("span","kb",o):r("span","kb none","not set"),s);const c=m.root.activeElement&&$t.contains(m.root.activeElement);$t.replaceChildren(r("span",null,"Open element"),a),c&&s.focus({preventScroll:!0})}function hn(){B&&ye();const t=m.root.activeElement?.dataset?.hk,o=m.root.activeElement?.classList?.contains("hkreset"),s=r("button","ib hkreset","Reset to defaults");s.type="button",s.disabled=F.isDefault(te),s.addEventListener("click",()=>{chrome.storage.local.remove("hotkeys").catch(()=>{}),Pe(`Reset: Pick is ${F.chip(F.DEFAULTS.pick)}, Save is ${F.chip(F.DEFAULTS.save)}.`,"ok")});const a=r("div","hkfoot");a.append(Oe,s),Be.replaceChildren(dn("pick"),dn("save"),$t,a),t?Be.querySelector(`[data-hk="${t}"]`)?.focus({preventScroll:!0}):o&&(s.disabled?Be.querySelector('[data-hk="pick"]'):s).focus({preventScroll:!0})}const le=()=>n.acct?n.acct.signedIn:!!n.plan?.signedIn,mn=()=>(le()?n.acct?.lifetimes:null)||(le()?["1d","7d","30d"]:["1d"]);function Lt(){const t=mn(),o=n.acct?.defaultLifetime&&t.includes(n.acct.defaultLifetime)?n.acct.defaultLifetime:t.includes("7d")?"7d":t[0];n.expiry=t.includes(n.storedExpiry)?n.storedExpiry:o}async function Mt(t=!1){const o=await chrome.runtime.sendMessage({type:"account",fresh:t}).catch(()=>null);if(!(E!==n||!o?.ok)){if(n.acct=o.account||null,n.acct?.signedIn)n.signing=null;else if(n.signing?.userCode&&n.acct&&!n.acct.login){const s=await chrome.runtime.sendMessage({type:"module_login_status"}).catch(()=>null);s?.state==="error"&&(n.signing={error:s.error||"Sign-in failed"})}ro()}}function ro(){Lt(),Q(),Tt(),n.tab==="settings"&&Ce()}function io(t){const o=String(t.name||"").trim().split(/\s+/).filter(Boolean);return o.length>=2?(o[0][0]+o.at(-1)[0]).toUpperCase():(o[0]||t.email||"?").charAt(0).toUpperCase()}async function so(){n.signing={starting:!0},Ce();const t=await chrome.runtime.sendMessage({type:"login_start"}).catch(o=>({ok:!1,error:String(o.message||o)}));E===n&&(n.signing=t?.ok&&t.userCode?{userCode:t.userCode,verificationUrl:t.verificationUrl}:{error:t?.error||"Couldn't start sign-in"},Ce())}async function ao(){n.signing=null,Ce(),await chrome.runtime.sendMessage({type:"login_cancel"}).catch(()=>{})}function ce(t,o,s){const a=r("button",o,t);return a.type="button",a.addEventListener("click",s),a}function lo(t){const o=r("div","meter"),s=r("div","mt");if(t.limit==null)return s.append(r("span",null,"Save & shares"),r("span",null,"unlimited \xB7 fair use")),o.append(s),o;const a=r("span");a.append(r("span","num",`${t.used} of ${t.limit}`),` save & shares ${Ke(t)}`),s.append(a,r("span",null,Qe(t)));const c=r("div",t.used>=t.limit?"tr full":"tr"),h=r("i");return h.style.width=`${Math.min(100,t.used/Math.max(1,t.limit)*100)}%`,c.append(h),o.append(s,c),o}function co(t){const o=r("div","meter"),s=r("div","mt");if(o.append(s),t.limit==null)return s.append(r("span",null,"Picks"),r("span",null,"unlimited")),o;const a=r("span");a.append(r("span","num",`${t.used} of ${t.limit}`)," picks this week"),s.append(a,r("span",null,Qe(t)));const c=r("div",t.used>=t.limit?"tr full":"tr"),h=r("i");return h.style.width=`${Math.min(100,t.used/Math.max(1,t.limit)*100)}%`,c.append(h),o.append(c),o}function po(){const t=[r("div","grp","Account")],o=n.acct,s=r("div","acct"),a=r("span","av"),c=r("div","who"),h=r("div","btns");if(s.append(a,c,h),t.push(s),!le()||!n.hubUp){a.append(P(jn));const D=n.plan?.limits;if(c.append(r("b",null,"Not signed in"),r("small",null,D?"Sign in to pick and save & share":"Sign in to save & share")),!n.hubUp){const w=ce("Run el install first","ib",()=>{});return w.disabled=!0,h.append(w),t}const S=n.signing,q=ce("Sign in","ib pri",so);if(q.disabled=!!(S&&!S.error),h.append(q),S&&!S.error){const w=r("div","flow");w.setAttribute("role","status");const K=r("div","r"),R=r("span");R.append(r("span","spin"),S.starting?"Starting sign-in\u2026":"Confirm this code in the tab we opened"),K.append(R,ce("Cancel","ib",ao)),w.append(K),S.userCode&&w.append(r("div","code",S.userCode));const G=r("small",null,"accounts.elmts.dev \xB7 sign in with GitHub or Google. Or run ");G.append(r("code",null,"el login")," in a terminal."),w.append(G),t.push(w)}else{if(S?.error){const w=r("div","flow");w.append(r("small","err",/hub/i.test(S.error)?"Run el install first.":`Couldn't sign in: ${S.error}`)),t.push(w)}if(D){const w=D.sharesPerWeek,K=r("div","note",`Free with an account: ${D.picksPerWeek} picks and ${w} save & share${w===1?"":"s"} a week, links last 24 hours. Same as `);K.append(r("code",null,"el login"),"."),t.push(K)}else{const w=r("div","note","Free with an account: 10 save & shares a month, links last 24 hours. Same as ");w.append(r("code",null,"el login"),". Picking never needs an account."),t.push(w)}}return t}const x=o?.plan||n.plan?.plan||"free",k=o?.email||n.plan?.email||"";a.textContent=io({name:o?.name,email:k}),c.append(r("b",null,o?.name&&!k?o.name:k||"Signed in"));const f=r("small"),g=o?.account===!1?"License key":Wn[o?.provider]||"";g&&f.append(`${g} \xB7 `),f.append(r("span",x==="free"?"planchip":"planchip paid",nn(x))),c.append(f);const v={...Ae,...o?.links||{}};return x==="free"?h.append(ce("Upgrade","ib pri",()=>he(v.upgradePro))):o?.account!==!1&&(n.plan?.account??!0)&&h.append(ce("Manage billing","ib",()=>he(v.billing))),o?.picks&&!o.signInToPick&&t.push(co(o.picks)),o?.usage&&t.push(lo(o.usage)),t}function Tt(){const t=l(".usage"),o=le()&&n.acct?.usage,s=le()&&n.acct?.plan==="free"&&n.acct?.picks?.limit!=null?n.acct.picks:null;if(t.classList.toggle("meters",!!s),t.hidden=n.tab!=="saves"||!s&&(!o||o.limit==null),l(".whom").textContent=le()?[nn(n.acct?.plan||n.plan?.plan),n.acct?.email||n.plan?.email].filter(Boolean).join(" \xB7 "):"not signed in",t.hidden)return t.replaceChildren();if(s){const x=(f,g)=>{const v=r("div","u"),D=r("span",g.used>=g.limit?"tr full":"tr"),S=r("i");return S.style.width=`${Math.min(100,g.used/Math.max(1,g.limit)*100)}%`,D.append(S),v.append(r("span",null,f),r("small",null,`${g.used} of ${g.limit} ${Ke(g)}`),D),v},k=r("div","ft");k.append(r("span",null,`Free \xB7 ${Qe(s)}`),ce("Upgrade","ib pri",()=>he({...Ae,...n.acct.links||{}}.upgradePro))),t.replaceChildren(x("Picks",s),...o&&o.limit!=null?[x("Save & shares",o)]:[],k);return}const a=r("span",o.used>=o.limit?"tr full":"tr"),c=r("i");c.style.width=`${Math.min(100,o.used/Math.max(1,o.limit)*100)}%`,a.append(c);const h=ht(o.resetsAt);if(t.replaceChildren(r("span","t1",`${o.used} of ${o.limit} ${Ke(o)}`),a,r("span","sp",h?`resets ${h}`:"")),n.acct.plan==="free"){const x=r("a",null,"Upgrade");x.tabIndex=0,x.setAttribute("role","link"),x.addEventListener("click",()=>he({...Ae,...n.acct.links||{}}.upgradePro)),t.append(x)}}async function Ce(){const t=u.settings,o=r("span","v"),s=r("span",n.hubUp?"dot up":"dot");o.append(s,n.hubUp?"connected":"not connected");const a=mn(),c=a.length===1,h=a.map(_=>[_,c&&_==="1d"?"24 hours":tn[_]]),x=Ze(h,n.expiry,_=>chrome.storage.local.set({expiry:_}));if(c)for(const _ of x.children)_.disabled=!0;const k=Fe("Links expire after",x);c&&k.append(r("span","lockhint","Pro: 1, 7 or 30 days"));const f=!!(le()&&n.acct?.privateLinks),g=f&&n.newVisibility==="private",v=Ze([["unlisted","Anyone with link"],["private","Private"]],g?"private":"unlisted",_=>chrome.storage.local.set({newVisibility:_}));v.classList.add("sm"),v.children[0].prepend(P(I.globe)),v.children[1].prepend(P(I.lock)),f||(v.children[1].disabled=!0);const D=Fe("New links are",v);f||D.append(r("span","lockhint","Pro: private links"));const S=[D];if(g){const _=n.acct?.privateDomain,go=_&&n.privateWho==="domain"?"domain":"me",Cn=Ze([["me","Only me"],..._?[["domain",_]]:[]],go,bo=>chrome.storage.local.set({privateWho:bo}));Cn.classList.add("sm");const Sn=Fe("Private links open for",Cn);Sn.append(r("span","hint","Add people per link.")),S.push(Sn)}const q=[...po(),r("div","grp","General"),Fe("Appearance",Ze([["system","System"],["light","Light"],["dark","Dark"]],n.theme,_=>chrome.storage.local.set({theme:_}))),k,...S,r("div","grp","Shortcuts")];if(q.push(Be),q.push(r("div","grp","Status"),Fe("Local hub",o)),!n.hubUp){const _=r("div","note","Run ");_.append(r("code",null,"el install")," in a terminal, then reload the extension."),n.lastError&&_.append(r("br"),n.lastError),q.push(_)}n.hubUp&&le()&&n.acct?.account!==!1&&n.plan?.account!==!1&&q.push(Fe("Signed in",ce("Sign out","ib",async()=>{await chrome.runtime.sendMessage({type:"logout"}).catch(()=>{}),n.acct=null,Mt()}))),Be.childElementCount||hn();const w=m.root.activeElement,K=w&&t.contains(w)&&!Be.contains(w)?w.textContent:null,R=l(".mbody"),G=R.scrollTop;t.replaceChildren(...q),K!=null&&!w.isConnected?[...t.querySelectorAll("button, a")].find(_=>_.textContent===K&&!_.disabled)?.focus({preventScroll:!0}):w&&w!==m.root.activeElement&&w.isConnected&&w.focus({preventScroll:!0}),n.tab==="settings"&&(R.scrollTop=G),await fn()}function uo(t,o){if(!t.length)return;const s=t.indexOf(m.root.activeElement);t[s<0?o>0?0:t.length-1:Math.max(0,Math.min(t.length-1,s+o))].focus()}function fo(t){if(t.stopPropagation(),B)return un(t);const o=m.root.activeElement;if(t.key==="Escape"){t.preventDefault();const s=o?.closest?.(".row");return s?.refs?.cf?wt(s,!0):s?.refs?.ap?(ne(s,s.dataset.id,!1),s.focus()):o?.closest?.(".selbar")&&!ke.hidden?Ue(!0):n.close()}if(o&&o.getAttribute("role")==="tab"&&(t.key==="ArrowRight"||t.key==="ArrowLeft")){t.preventDefault();const s=b.indexOf(o);return M(b[(s+(t.key==="ArrowRight"?1:-1)+3)%3].dataset.tab,!0)}if(n.tab==="saves"){const s=[...u.saves.querySelectorAll(".row")];if(t.key==="ArrowDown"||t.key==="ArrowUp"){if(t.preventDefault(),o===d)return t.key==="ArrowDown"&&s[0]?.focus();const a=o?.closest?.(".row");return a&&t.key==="ArrowUp"&&s[0]===a?d.focus():a?s[s.indexOf(a)+(t.key==="ArrowDown"?1:-1)]?.focus():s[0]?.focus()}o?.classList?.contains("row")&&(t.key==="Enter"?(t.preventDefault(),o.refs.copy.click()):t.key===" "?(t.preventDefault(),o.refs.cb.disabled||o.refs.cb.click()):(t.key==="Delete"||t.key==="Backspace")&&(t.preventDefault(),rn(o,o.dataset.id)));return}n.tab==="sessions"&&o!==d&&gn(t)}function gn(t){return t.metaKey||t.ctrlKey||t.altKey?!1:t.key==="ArrowDown"||t.key==="ArrowUp"?(t.preventDefault(),uo(Ct(),t.key==="ArrowDown"?1:-1),!0):/^[1-9]$/.test(t.key)&&n.sessions[Number(t.key)-1]?(t.preventDefault(),St(n.sessions[Number(t.key)-1].id),!0):!1}const bn=new AbortController,Ft={signal:bn.signal};i.addEventListener("keydown",fo,Ft);for(const t of["keyup","keypress","input","beforeinput"])i.addEventListener(t,o=>o.stopPropagation(),Ft);i.addEventListener("keyup",t=>B&&un(t),Ft);const xn=t=>{$e(t)||(t.key==="Escape"?(ee(t),n.close()):n.tab==="sessions"&&gn(t)&&ee(t))},vn=t=>{$e(t)||n.close()},wn=(t,o)=>{o==="local"&&(t.saves&&(n.saves=Array.isArray(t.saves.newValue)?t.saves.newValue:[],Q()),t.theme&&(n.theme=t.theme.newValue||"system",L()),(t.newVisibility||t.privateWho)&&(t.newVisibility&&(n.newVisibility=t.newVisibility.newValue),t.privateWho&&(n.privateWho=t.privateWho.newValue),n.tab==="settings"&&Ce()),t.expiry&&(n.storedExpiry=t.expiry.newValue,Lt(),Q()),t.hotkeys&&(hn(),Q(),n.tab==="settings"&&Ce()))},ot=()=>n.tab==="settings"&&!document.hidden&&fn(),kn=matchMedia("(prefers-color-scheme: dark)"),ho=setInterval(Q,3e4);window.addEventListener("keydown",xn,!0),window.addEventListener("pointerdown",vn,!0),window.addEventListener("focus",ot),document.addEventListener("visibilitychange",ot),chrome.storage.onChanged.addListener(wn),kn.addEventListener("change",L);let Pt="";n.refresh=t=>{const o=JSON.stringify(n.plan);Object.assign(n,{sessions:t.sessions||[],owner:t.owner||null,hubUp:t.hubUp!==!1,lastError:t.lastError||"",plan:t.plan||null}),n.tab==="sessions"&&cn();const s=JSON.stringify([n.hubUp,n.lastError,n.plan]);n.tab==="settings"&&s!==Pt&&Ce(),Pt=s,Tt(),(t.accountStale||JSON.stringify(n.plan)!==o)&&Mt()};let De=null;const yn=()=>{try{De=chrome.runtime.connect({name:"module"})}catch{return}De.onMessage.addListener(t=>t.type==="module_state"&&E===n&&n.refresh(t)),De.onDisconnect.addListener(()=>{De=null,E===n&&setTimeout(()=>E===n&&!De&&yn(),500)})};yn();const mo=new Promise(t=>n.resolve=t);return n.close=(t=null)=>{if(E!==n)return;E=null,fe&&m.mod.contains(fe)&&oe(),window.removeEventListener("keydown",xn,!0),window.removeEventListener("pointerdown",vn,!0),window.removeEventListener("focus",ot),document.removeEventListener("visibilitychange",ot),chrome.storage.onChanged.removeListener(wn),kn.removeEventListener("change",L),clearInterval(ho),bn.abort();const o=De;De=null,o?.disconnect(),i.classList.remove("open"),i.replaceChildren(),m.layer.classList.remove("mod-open"),n.resolve(t),z||je(3e3)},Lt(),Q(),M(n.tab),Pt=JSON.stringify([n.hubUp,n.lastError,n.plan]),Mt().then(()=>E===n&&n.hubUp&&le()&&chrome.runtime.sendMessage({type:"refresh_key"}).catch(()=>{})),i.classList.add("open"),m.layer.classList.add("mod-open"),n.tab==="saves"&&e.people&&n.rows.get(e.people)?ne(n.rows.get(e.people),e.people,!0):n.tab==="saves"?d.focus({preventScroll:!0}):n.tab==="sessions"?(Ct()[Math.max(0,n.sessions.findIndex(t=>t.id===n.owner))]||b[1]).focus({preventScroll:!0}):b[2].focus({preventScroll:!0}),mo}async function to({token:e,sessions:i}){V=!0,Ot();const l=await chrome.runtime.sendMessage({type:"module_state"}).catch(()=>({})),d=await xt({...l,sessions:i,owner:null,choose:!0});return V=!1,chrome.runtime.sendMessage({type:"choose",token:e,session:d}).catch(()=>({ok:!1}))}async function et(e,i){i=i||!!Y.hold,Re=!0;const l=Nt(e),d=Math.random().toString(36).slice(2);e.setAttribute("data-el-mark",d),j.style.display="none",await en(),await en();let u;try{u=await chrome.runtime.sendMessage({type:"picked",data:l,mark:d})}catch(p){u={ok:!1,error:String(p.message||p)}}e.removeAttribute("data-el-mark"),j.style.display="",u&&u.needChoice&&(u=await to(u)),u&&u.ok?Ee({label:u.label,harness:u.harness,id:u.id,tag:l.tag}):u&&(u.code==="pick_signed_out"||u.code==="pick_limit")?Hn(u):u&&u.error&&Ee(u.error,!0),Re=!1,!i||!u||!u.ok||st?re():pe(),st=!1}let vt=0;if(chrome.runtime.onMessage.addListener((e,i,l)=>e.type!=="overlay"||(vt=Math.max(0,vt+(e.hidden?1:-1)),j&&(j.style.visibility=vt?"hidden":""),!e.hidden)?!1:(requestAnimationFrame(()=>requestAnimationFrame(()=>l(!0))),!0)),chrome.runtime.onMessage.addListener(e=>{if(e.type==="picker_start")z&&!Y.hold?re():gt(e);else if(e.type==="picker_stop")z&&re();else if(e.type==="module_open")V||xt(e);else if(e.type==="pick_sent"){if(window!==window.top)return;de(),Ee({label:e.label,harness:e.harness,id:e.id,tag:e.tag}),ge?.abort(),ge=null,me?.remove(),me=null}else e.type==="share_progress"?Ve.get(e.token)?.set(e.progress,e.stage):e.type==="pick_target"&&(ze&&ze.isConnected&&!z?(Y={},de(),A=ze,et(ze,!1)):z||gt({}))}),window===window.top){const e=matchMedia("(prefers-color-scheme: dark)"),i=async()=>{const{dark:l}=await chrome.storage.local.get("dark").catch(()=>({}));l!==e.matches&&chrome.runtime.sendMessage({type:"theme",dark:e.matches}).catch(()=>{})};i(),e.addEventListener("change",i)}window.addEventListener("mousemove",e=>{if(Xe={x:e.clientX,y:e.clientY},z||E||!(e.altKey||e.ctrlKey||e.shiftKey||e.metaKey))return;const i=He(e);i&&gt({hold:!0,share:i==="save"})},{capture:!0,passive:!0}),window.addEventListener("keyup",e=>{if(!z||!Y.hold||!F.modOfKey(e.key))return;const i=He(e);i?mt(i==="save"):V||Xt()},!0),window.addEventListener("blur",()=>{z&&Y.hold&&!V&&!Re&&re()}),window.addEventListener("contextmenu",e=>{ze=e.composedPath()[0]instanceof Element?e.composedPath()[0]:e.target},!0)})();
@@ -0,0 +1,59 @@
1
+ @font-face { font-family: Figtree; font-weight: 400; src: url(fonts/figtree-latin-400-normal.woff2) format("woff2"); }
2
+ @font-face { font-family: Figtree; font-weight: 500; src: url(fonts/figtree-latin-500-normal.woff2) format("woff2"); }
3
+ @font-face { font-family: Figtree; font-weight: 600; src: url(fonts/figtree-latin-600-normal.woff2) format("woff2"); }
4
+ @font-face { font-family: "Geist Mono"; font-weight: 400; src: url(fonts/geist-mono-latin-400-normal.woff2) format("woff2"); }
5
+ @font-face { font-family: "Geist Mono"; font-weight: 500; src: url(fonts/geist-mono-latin-500-normal.woff2) format("woff2"); }
6
+
7
+ :root {
8
+ --bg: #FFFFFF; --card: #F4F4F3; --line: #E7E7E5; --fg: #0A0A0A; --ink-2: #404040; --muted: #737373;
9
+ --pri: #0A0A0A; --pri-ink: #FFFFFF; --ok: #30A46C; --bad: #E5484D;
10
+ --font: Figtree, system-ui, sans-serif; --mono: "Geist Mono", ui-monospace, monospace;
11
+ }
12
+ /* data-theme comes from the Appearance setting (the module's Settings); without it, follow the system. */
13
+ :root[data-theme="dark"] { --bg: #161616; --card: #202020; --line: #2A2A2A; --fg: #FAFAFA; --ink-2: #D4D4D4; --muted: #9A9A9A; --pri: #FAFAFA; --pri-ink: #0A0A0A; color-scheme: dark; }
14
+ @media (prefers-color-scheme: dark) {
15
+ :root:not([data-theme="light"]) { --bg: #161616; --card: #202020; --line: #2A2A2A; --fg: #FAFAFA; --ink-2: #D4D4D4; --muted: #9A9A9A; --pri: #FAFAFA; --pri-ink: #0A0A0A; color-scheme: dark; }
16
+ }
17
+ * { box-sizing: border-box; }
18
+ body { margin: 0; width: 340px; background: var(--bg); color: var(--fg); font: 400 13px/1.45 var(--font); -webkit-font-smoothing: antialiased; }
19
+ svg { display: block; }
20
+ button { font: inherit; color: inherit; cursor: pointer; }
21
+ [hidden] { display: none !important; }
22
+
23
+ header { display: flex; align-items: center; gap: 8px; padding: 14px 14px 0; }
24
+ .logo { display: inline-flex; align-items: center; gap: 6px; font: 600 16px/1 var(--font); letter-spacing: -0.03em; }
25
+ .logo svg { width: 15px; height: 15px; }
26
+ .plan { margin-left: auto; font: 500 11px var(--mono); padding: 1px 7px; border-radius: 999px; border: 1px solid var(--line); color: var(--muted); text-transform: lowercase; }
27
+ .plan.pro { border-color: var(--pri); background: var(--pri); color: var(--pri-ink); }
28
+ .plan + .status { margin-left: 4px; }
29
+ .status { margin-left: auto; display: flex; align-items: center; gap: 5px; font: 400 11.5px var(--mono); color: var(--muted); }
30
+ .status::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--bad); }
31
+ .status.up::before { background: var(--ok); }
32
+
33
+ main { padding: 12px 14px 14px; }
34
+ section { display: flex; flex-direction: column; gap: 12px; }
35
+ .note { background: var(--card); border-radius: 10px; padding: 12px; display: grid; grid-template-columns: 20px 1fr; gap: 10px; align-items: start; }
36
+ .note svg { width: 18px; height: 18px; color: var(--muted); margin-top: 1px; }
37
+ .note b { display: block; font-weight: 600; font-size: 13.5px; }
38
+ .note span { color: var(--muted); font-size: 12.5px; line-height: 1.45; }
39
+ .note.slim { background: none; padding: 0 2px; grid-template-columns: 16px 1fr; gap: 8px; align-items: center; }
40
+ .note.slim svg { width: 15px; height: 15px; margin: 0; }
41
+ .fix { gap: 8px; }
42
+ .cmd { display: flex; align-items: center; gap: 8px; background: var(--card); border-radius: 8px; padding: 8px 8px 8px 10px; font: 12px var(--mono); }
43
+ .cmd code { flex: 1; min-width: 0; overflow-x: auto; white-space: nowrap; }
44
+ .err { margin: 0; font: 11px var(--mono); color: var(--muted); word-break: break-word; }
45
+ .err:empty { display: none; }
46
+
47
+ .lab { display: flex; justify-content: space-between; gap: 8px; font: 400 11px var(--mono); color: var(--muted); letter-spacing: .04em; margin: 2px 0 -6px; }
48
+ .lab span:last-child { letter-spacing: 0; }
49
+ #saves { display: flex; flex-direction: column; }
50
+ .row { display: grid; grid-template-columns: 44px minmax(0, 1fr) auto; gap: 10px; align-items: center; padding: 6px; border-radius: 9px; }
51
+ .row:hover, .row:focus-within { background: var(--card); }
52
+ .th { width: 44px; height: 30px; border-radius: 5px; background: var(--card) center top / cover no-repeat; box-shadow: inset 0 0 0 1px rgba(0,0,0,.06); }
53
+ .t { min-width: 0; }
54
+ .t b { display: block; font-weight: 500; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
55
+ .t small { display: block; font: 400 11px var(--mono); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
56
+ .ib { all: unset; cursor: pointer; font: 500 11.5px var(--font); padding: 4px 9px; border-radius: 7px; border: 1px solid var(--line); color: var(--fg); white-space: nowrap; }
57
+ .ib:focus-visible { outline: 2px solid var(--fg); outline-offset: 1px; }
58
+ .ib:disabled { opacity: .45; cursor: default; }
59
+ .empty { margin: 0; padding: 6px 2px; color: var(--muted); font-size: 12.5px; }
@@ -0,0 +1,37 @@
1
+ <!doctype html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <link rel="stylesheet" href="popup.css">
6
+ </head>
7
+ <body>
8
+ <!-- Shown only where element can't run (Chrome's own pages, the web store, PDFs); everywhere else
9
+ the toolbar icon opens the module in the page. -->
10
+ <header>
11
+ <span class="logo"><span id="logo-mark"></span>element</span>
12
+ <span id="plan" class="plan" hidden></span>
13
+ <span id="status" class="status"></span>
14
+ </header>
15
+ <main>
16
+ <section id="offline" class="fix" hidden>
17
+ <div class="note">
18
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M12 9v4M12 17h.01"/><circle cx="12" cy="12" r="9"/></svg>
19
+ <div><b id="fix-title"></b><span id="fix-text"></span></div>
20
+ </div>
21
+ <div class="cmd"><code id="fix-cmd"></code><button id="copy" class="ib" type="button">Copy</button></div>
22
+ <p id="error" class="err"></p>
23
+ </section>
24
+ <section id="main" hidden>
25
+ <div class="note slim">
26
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><rect x="5" y="11" width="14" height="9" rx="2"/><path d="M8 11V8a4 4 0 0 1 8 0v3"/></svg>
27
+ <span>element can't run on this page. Switch to a website tab.</span>
28
+ </div>
29
+ <div class="lab"><span>RECENT SAVES</span><span id="all-hint">on a website for all</span></div>
30
+ <div id="saves"></div>
31
+ </section>
32
+ </main>
33
+ <script src="logos.js"></script>
34
+ <script src="hotkeys.js"></script>
35
+ <script src="popup.js"></script>
36
+ </body>
37
+ </html>
@@ -0,0 +1 @@
1
+ const $=e=>document.getElementById(e),ICONS=globalThis.ELEMENT_ICONS,HK=globalThis.ELEMENT_HOTKEYS;let hk=HK.read(null);function el(e,t,n){const o=document.createElement(e);return t&&(o.className=t),n!=null&&(o.textContent=n),o}function icon(e){const t=document.createElement("template");return t.innerHTML=e,t.content.firstElementChild}function ago(e){const t=Math.max(0,Math.round((Date.now()-e)/1e3));return t<60?"now":t<3600?`${Math.round(t/60)}m`:t<86400?`${Math.round(t/3600)}h`:`${Math.round(t/86400)}d`}function saveTitle(e){const t=String(e.title||"").split(/\s[|–—·:-]\s/)[0].trim().slice(0,40)||e.host||"Untitled";return e.name?`${t} \xB7 ${e.name}`:t}const safeThumb=e=>typeof e=="string"&&/^data:image\/(webp|png|jpeg);base64,[A-Za-z0-9+/=]+$/.test(e)?`url("${e}")`:"",forTab=Number(new URLSearchParams(location.search).get("tab"))||void 0,applyTheme=e=>{e==="light"||e==="dark"?document.documentElement.dataset.theme=e:delete document.documentElement.dataset.theme};chrome.storage.local.get("theme").then(e=>applyTheme(e.theme)),$("logo-mark").replaceWith(icon(ICONS.mark)),chrome.commands.getAll().then(e=>{const t=e.find(n=>n.name==="switch-session")?.shortcut;$("all-hint").textContent=t?`${t} on a website for all`:"open element on a website for all"});async function copy(e,t){let n=!0;try{await navigator.clipboard.writeText(e)}catch{n=!!(await chrome.runtime.sendMessage({type:"copy",text:e}).catch(()=>null))?.ok}const o=t.textContent;t.textContent=n?"Copied":"Copy failed",setTimeout(()=>t.textContent=o,1100)}$("copy").onclick=()=>copy($("fix-cmd").textContent,$("copy"));let state=null,saves=[];async function load(){const[e,t]=await Promise.all([chrome.runtime.sendMessage({type:"popup_state",tabId:forTab}),chrome.storage.local.get(["saves","hotkeys"])]);state=e,saves=Array.isArray(t.saves)?t.saves:[],hk=HK.read(t.hotkeys),render()}function render(){const{hubUp:e,lastError:t,plan:n}=state;if($("status").textContent=e?"connected":"not connected",$("status").classList.toggle("up",e),$("plan").hidden=!e||!n,n){const a=n.signedIn&&n.plan!=="free";$("plan").textContent=n.signedIn===!1?"not signed in":n.plan,$("plan").classList.toggle("pro",a),$("plan").title=n.signedIn===!1?"Sign in (drawer \u2192 Settings, or el login) to save & share":`element ${n.plan}${n.email?` \xB7 ${n.email}`:""}`}if($("offline").hidden=e,$("main").hidden=!e,!e){const a=/native messaging host|not found|forbidden/i.test(t||"");$("fix-title").textContent=a?"element isn't set up in this browser":"element isn't running on this Mac",$("fix-text").textContent=a?"Run this once in a terminal, then reload the extension.":"Start it once in a terminal. It keeps running in the background after that.",$("fix-cmd").textContent=a?"el install":"el hub",$("error").textContent=t&&t!=="disconnected"?t:"";return}const o=$("saves");o.replaceChildren();const i=saves.filter(a=>a.status!=="error").slice(0,3);i.length||o.append(el("p","empty",`No saves yet. On a website, hold ${HK.format(hk.save)} and click an element: its share link is copied and kept here.`));for(const a of i){const l=el("div","row"),r=el("div","th");r.style.backgroundImage=safeThumb(a.thumb);const c=el("div","t"),d=a.status==="active";c.append(el("b",null,saveTitle(a)),el("small",null,d?`${a.stage||"uploading"} \xB7 ${Math.round(a.progress||0)}%`:`${a.host} \xB7 ${ago(a.createdAt)}`));const s=el("button","ib","Copy link");s.type="button",s.disabled=!a.viewUrl,s.onclick=()=>copy(a.viewUrl,s),l.append(r,c,s),o.append(l)}}chrome.storage.onChanged.addListener((e,t)=>{t==="local"&&(e.theme&&applyTheme(e.theme.newValue),e.saves&&(saves=Array.isArray(e.saves.newValue)?e.saves.newValue:[]),e.hotkeys&&(hk=HK.read(e.hotkeys.newValue)),(e.saves||e.hotkeys)&&state&&render())}),load();