browserzap 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +71 -0
- package/README.md +31 -19
- package/THIRD_PARTY_NOTICES.md +3 -3
- package/bridge-server/extension-id.js +64 -1
- package/bridge-server/extension-version.js +65 -0
- package/bridge-server/feedback.js +12 -5
- package/bridge-server/index.js +36 -24
- package/bridge-server/limits.js +1 -1
- package/bridge-server/mcp-server.js +79 -4
- package/bridge-server/native-host.js +22 -3
- package/bridge-server/probe.js +56 -1
- package/bridge-server/server.js +11 -4
- package/bridge-server/setup.js +84 -25
- package/bridge-server/tools.js +28 -1
- package/package.json +4 -5
- package/extension/background.js +0 -1
- package/extension/engine.js +0 -1
- package/extension/fonts/inter-latin-wght-normal.woff2 +0 -0
- package/extension/icons/icon128.png +0 -0
- package/extension/icons/icon16.png +0 -0
- package/extension/icons/icon32.png +0 -0
- package/extension/icons/icon48.png +0 -0
- package/extension/logo.svg +0 -7
- package/extension/manifest.json +0 -47
- package/extension/sidepanel.css +0 -2
- package/extension/sidepanel.html +0 -138
- package/extension/sidepanel.js +0 -1
package/extension/sidepanel.css
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
/*! tailwindcss v4.3.0 | MIT License | https://tailwindcss.com */
|
|
2
|
-
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-ease:initial;--tw-divide-x-reverse:0}}}@layer theme{:root,:host{--font-sans:"Inter Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;--font-serif:ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;--font-mono:ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-emerald-50:oklch(97.9% .021 166.113);--color-emerald-100:oklch(95% .052 163.051);--color-emerald-200:oklch(90.5% .093 164.15);--color-emerald-300:oklch(84.5% .143 164.978);--color-emerald-400:oklch(76.5% .177 163.223);--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:oklch(50.8% .118 165.612);--color-emerald-800:oklch(43.2% .095 166.913);--color-emerald-900:oklch(37.8% .077 168.94);--color-sky-50:oklch(97.7% .013 236.62);--color-sky-100:oklch(95.1% .026 236.824);--color-sky-200:oklch(90.1% .058 230.902);--color-sky-300:oklch(82.8% .111 230.318);--color-sky-500:oklch(68.5% .169 237.323);--color-sky-700:oklch(50% .134 242.749);--color-sky-800:oklch(44.3% .11 240.79);--color-sky-900:oklch(39.1% .09 240.876);--color-indigo-50:oklch(96.2% .018 272.314);--color-indigo-200:oklch(87% .065 274.039);--color-indigo-300:oklch(78.5% .115 274.713);--color-indigo-500:oklch(58.5% .233 277.117);--color-indigo-600:oklch(51.1% .262 276.966);--color-indigo-700:oklch(45.7% .24 277.023);--color-rose-50:oklch(96.9% .015 12.422);--color-rose-100:oklch(94.1% .03 12.58);--color-rose-200:oklch(89.2% .058 10.001);--color-rose-300:oklch(81% .117 11.638);--color-rose-700:oklch(51.4% .222 16.935);--color-rose-800:oklch(45.5% .188 13.697);--color-rose-900:oklch(41% .159 10.272);--color-slate-50:oklch(98.4% .003 247.858);--color-slate-100:oklch(96.8% .007 247.896);--color-slate-200:oklch(92.9% .013 255.508);--color-slate-300:oklch(86.9% .022 252.894);--color-slate-400:oklch(70.4% .04 256.788);--color-slate-500:oklch(55.4% .046 257.417);--color-slate-600:oklch(44.6% .043 257.281);--color-slate-800:oklch(27.9% .041 260.031);--color-slate-900:oklch(20.8% .042 265.755);--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--container-2xl:42rem;--container-3xl:48rem;--container-4xl:56rem;--container-5xl:64rem;--container-6xl:72rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2 / 1.5);--text-3xl:1.875rem;--text-3xl--line-height:calc(2.25 / 1.875);--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-5xl:3rem;--text-5xl--line-height:1;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--font-weight-extrabold:800;--tracking-wide:.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-snug:1.375;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--radius-3xl:1.5rem;--ease-out:cubic-bezier(0, 0, .2, 1);--ease-in-out:cubic-bezier(.4, 0, .2, 1);--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:"Inter Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;--default-mono-font-family:ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}body{margin:calc(var(--spacing) * 0);background-color:var(--bz-bg-0);--tw-leading:var(--leading-snug);font-family:Inter Variable,-apple-system,BlinkMacSystemFont,Segoe UI,system-ui,sans-serif;font-size:13px;line-height:var(--leading-snug);color:var(--bz-fg-0);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}:focus-visible{outline:2px solid var(--bz-accent);outline-offset:2px}code{background-color:var(--bz-bg-3);padding-inline:calc(var(--spacing) * 1);border-radius:.25rem;font-family:ui-monospace,SF Mono,Cascadia Mono,Consolas,monospace;font-size:11px}input[type=text],input[type=password],input[type=number],textarea{border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;border-color:var(--bz-line);background-color:var(--bz-bg-2);width:100%;padding-inline:calc(var(--spacing) * 2);padding-block:calc(var(--spacing) * 1);color:var(--bz-fg-0);--tw-outline-style:none;outline-style:none;font-size:12px}:is(input[type=text],input[type=password],input[type=number],textarea):focus{border-color:var(--bz-accent)}[hidden]{display:none!important}}@layer components{.panel{margin-inline:calc(var(--spacing) * 2);margin-block:calc(var(--spacing) * 2);border-radius:var(--radius-xl);background-color:var(--bz-bg-1);padding:calc(var(--spacing) * 3);box-shadow:var(--bz-ring)}.panel-title{margin:calc(var(--spacing) * 0);--tw-font-weight:var(--font-weight-bold);font-size:11px;font-weight:var(--font-weight-bold);--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider);color:var(--bz-fg-2);text-transform:uppercase}.hint{margin:calc(var(--spacing) * 0);color:var(--bz-fg-2);font-size:11px}.btn{cursor:pointer;border-radius:var(--radius-lg);border-style:var(--tw-border-style);border-width:1px;border-color:var(--bz-line);background-color:var(--bz-bg-1);padding-inline:calc(var(--spacing) * 2.5);padding-block:calc(var(--spacing) * 1);--tw-font-weight:var(--font-weight-medium);font-size:12px;font-weight:var(--font-weight-medium);color:var(--bz-fg-0);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}@media (hover:hover){.btn:hover{background-color:var(--bz-bg-2)}}.btn:disabled{opacity:.5}.btn-primary{border-color:var(--bz-ink);background-color:var(--bz-ink);color:var(--bz-ink-fg)}@media (hover:hover){.btn-primary:hover{background-color:var(--bz-ink)}@supports (color:color-mix(in lab, red, red)){.btn-primary:hover{background-color:color-mix(in oklab, var(--bz-ink) 85%, transparent)}}}.btn-ghost{background-color:#0000}@media (hover:hover){.btn-ghost:hover{background-color:var(--bz-bg-2)}}.btn-danger{border-color:var(--bz-danger)}@supports (color:color-mix(in lab, red, red)){.btn-danger{border-color:color-mix(in oklab, var(--bz-danger) 40%, transparent)}}.btn-danger{background-color:var(--bz-danger)}@supports (color:color-mix(in lab, red, red)){.btn-danger{background-color:color-mix(in oklab, var(--bz-danger) 10%, transparent)}}.btn-danger{color:var(--bz-danger)}@media (hover:hover){.btn-danger:hover{background-color:var(--bz-danger)}@supports (color:color-mix(in lab, red, red)){.btn-danger:hover{background-color:color-mix(in oklab, var(--bz-danger) 20%, transparent)}}}.card{gap:calc(var(--spacing) * 1.5);border-radius:var(--radius-lg);border-style:var(--tw-border-style);border-width:1px;border-color:var(--bz-line);background-color:var(--bz-bg-1);padding:calc(var(--spacing) * 2.5);flex-direction:column;display:flex}.pill{padding-inline:calc(var(--spacing) * 2);--tw-font-weight:var(--font-weight-bold);font-size:10px;font-weight:var(--font-weight-bold);--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide);text-transform:uppercase;border-radius:3.40282e38px;padding-block:1px}.pill-ok{background-color:var(--bz-ok)}@supports (color:color-mix(in lab, red, red)){.pill-ok{background-color:color-mix(in oklab, var(--bz-ok) 15%, transparent)}}.pill-ok{color:var(--bz-ok)}.pill-warn{background-color:var(--bz-warn)}@supports (color:color-mix(in lab, red, red)){.pill-warn{background-color:color-mix(in oklab, var(--bz-warn) 15%, transparent)}}.pill-warn{color:var(--bz-warn)}.pill-bad{background-color:var(--bz-danger)}@supports (color:color-mix(in lab, red, red)){.pill-bad{background-color:color-mix(in oklab, var(--bz-danger) 15%, transparent)}}.pill-bad{color:var(--bz-danger)}.pill-muted{background-color:var(--bz-bg-3);color:var(--bz-fg-2)}.meta{color:var(--bz-fg-1);font-size:11px}}@layer utilities{.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.static{position:static}.sticky{position:sticky}.inset-x-0{inset-inline:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.right-0{right:calc(var(--spacing) * 0)}.z-10{z-index:10}.z-40{z-index:40}.container{width:100%}@media (min-width:40rem){.container{max-width:40rem}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}.m-0{margin:calc(var(--spacing) * 0)}.mx-2{margin-inline:calc(var(--spacing) * 2)}.mx-3{margin-inline:calc(var(--spacing) * 3)}.mx-auto{margin-inline:auto}.my-1{margin-block:calc(var(--spacing) * 1)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-1\.5{margin-top:calc(var(--spacing) * 1.5)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-3{margin-top:calc(var(--spacing) * 3)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-5{margin-top:calc(var(--spacing) * 5)}.mt-6{margin-top:calc(var(--spacing) * 6)}.mt-7{margin-top:calc(var(--spacing) * 7)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-9{margin-top:calc(var(--spacing) * 9)}.mt-10{margin-top:calc(var(--spacing) * 10)}.mt-12{margin-top:calc(var(--spacing) * 12)}.mt-14{margin-top:calc(var(--spacing) * 14)}.mr-1{margin-right:calc(var(--spacing) * 1)}.mr-1\.5{margin-right:calc(var(--spacing) * 1.5)}.mb-1{margin-bottom:calc(var(--spacing) * 1)}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2{margin-bottom:calc(var(--spacing) * 2)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-4{margin-bottom:calc(var(--spacing) * 4)}.mb-6{margin-bottom:calc(var(--spacing) * 6)}.ml-1{margin-left:calc(var(--spacing) * 1)}.ml-1\.5{margin-left:calc(var(--spacing) * 1.5)}.ml-2{margin-left:calc(var(--spacing) * 2)}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.table{display:table}.aspect-\[4\/3\]{aspect-ratio:4/3}.size-1{width:calc(var(--spacing) * 1);height:calc(var(--spacing) * 1)}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-2{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.size-2\.5{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.h-16{height:calc(var(--spacing) * 16)}.h-24{height:calc(var(--spacing) * 24)}.h-\[520px\]{height:520px}.h-full{height:100%}.max-h-20{max-height:calc(var(--spacing) * 20)}.max-h-28{max-height:calc(var(--spacing) * 28)}.max-h-72{max-height:calc(var(--spacing) * 72)}.min-h-screen{min-height:100vh}.w-1{width:calc(var(--spacing) * 1)}.w-1\/3{width:33.3333%}.w-fit{width:fit-content}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-3xl{max-width:var(--container-3xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-5xl{max-width:var(--container-5xl)}.max-w-6xl{max-width:var(--container-6xl)}.max-w-\[8rem\]{max-width:8rem}.max-w-full{max-width:100%}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-xl{max-width:var(--container-xl)}.max-w-xs{max-width:var(--container-xs)}.min-w-0{min-width:calc(var(--spacing) * 0)}.flex-1{flex:1}.flex-shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.border-collapse{border-collapse:collapse}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.cursor-pointer{cursor:pointer}.resize{resize:both}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-row{flex-direction:row}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-0{gap:calc(var(--spacing) * 0)}.gap-0\.5{gap:calc(var(--spacing) * .5)}.gap-1{gap:calc(var(--spacing) * 1)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-4{gap:calc(var(--spacing) * 4)}.gap-10{gap:calc(var(--spacing) * 10)}.gap-12{gap:calc(var(--spacing) * 12)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * .5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * .5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 1.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 1.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2.5) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 3) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 3) * calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.gap-x-10{column-gap:calc(var(--spacing) * 10)}.gap-y-8{row-gap:calc(var(--spacing) * 8)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px * var(--tw-divide-y-reverse));border-bottom-width:calc(1px * calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-line>:not(:last-child)){border-color:var(--bz-line)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-3xl{border-radius:var(--radius-3xl)}.rounded-\[32px\]{border-radius:32px}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-accent,.border-accent\/40{border-color:var(--bz-accent)}@supports (color:color-mix(in lab, red, red)){.border-accent\/40{border-color:color-mix(in oklab, var(--bz-accent) 40%, transparent)}}.border-amber-300{border-color:var(--color-amber-300)}.border-amber-400{border-color:var(--color-amber-400)}.border-danger\/30{border-color:var(--bz-danger)}@supports (color:color-mix(in lab, red, red)){.border-danger\/30{border-color:color-mix(in oklab, var(--bz-danger) 30%, transparent)}}.border-danger\/40{border-color:var(--bz-danger)}@supports (color:color-mix(in lab, red, red)){.border-danger\/40{border-color:color-mix(in oklab, var(--bz-danger) 40%, transparent)}}.border-emerald-200{border-color:var(--color-emerald-200)}.border-emerald-300{border-color:var(--color-emerald-300)}.border-emerald-400{border-color:var(--color-emerald-400)}.border-emerald-500{border-color:var(--color-emerald-500)}.border-indigo-200{border-color:var(--color-indigo-200)}.border-indigo-300{border-color:var(--color-indigo-300)}.border-indigo-500{border-color:var(--color-indigo-500)}.border-line{border-color:var(--bz-line)}.border-ok\/40{border-color:var(--bz-ok)}@supports (color:color-mix(in lab, red, red)){.border-ok\/40{border-color:color-mix(in oklab, var(--bz-ok) 40%, transparent)}}.border-rose-200{border-color:var(--color-rose-200)}.border-rose-300{border-color:var(--color-rose-300)}.border-sky-300{border-color:var(--color-sky-300)}.border-slate-200{border-color:var(--color-slate-200)}.border-slate-300{border-color:var(--color-slate-300)}.border-slate-600{border-color:var(--color-slate-600)}.border-warn\/40{border-color:var(--bz-warn)}@supports (color:color-mix(in lab, red, red)){.border-warn\/40{border-color:color-mix(in oklab, var(--bz-warn) 40%, transparent)}}.bg-accent\/10{background-color:var(--bz-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/10{background-color:color-mix(in oklab, var(--bz-accent) 10%, transparent)}}.bg-accent\/15{background-color:var(--bz-accent)}@supports (color:color-mix(in lab, red, red)){.bg-accent\/15{background-color:color-mix(in oklab, var(--bz-accent) 15%, transparent)}}.bg-amber-50{background-color:var(--color-amber-50)}.bg-bg-1{background-color:var(--bz-bg-1)}.bg-danger,.bg-danger\/5{background-color:var(--bz-danger)}@supports (color:color-mix(in lab, red, red)){.bg-danger\/5{background-color:color-mix(in oklab, var(--bz-danger) 5%, transparent)}}.bg-danger\/10{background-color:var(--bz-danger)}@supports (color:color-mix(in lab, red, red)){.bg-danger\/10{background-color:color-mix(in oklab, var(--bz-danger) 10%, transparent)}}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-emerald-900{background-color:var(--color-emerald-900)}.bg-emerald-900\/40{background-color:#004e3b66}@supports (color:color-mix(in lab, red, red)){.bg-emerald-900\/40{background-color:color-mix(in oklab, var(--color-emerald-900) 40%, transparent)}}.bg-emerald-900\/60{background-color:#004e3b99}@supports (color:color-mix(in lab, red, red)){.bg-emerald-900\/60{background-color:color-mix(in oklab, var(--color-emerald-900) 60%, transparent)}}.bg-fg-2{background-color:var(--bz-fg-2)}.bg-indigo-50{background-color:var(--color-indigo-50)}.bg-line{background-color:var(--bz-line)}.bg-ok,.bg-ok\/10{background-color:var(--bz-ok)}@supports (color:color-mix(in lab, red, red)){.bg-ok\/10{background-color:color-mix(in oklab, var(--bz-ok) 10%, transparent)}}.bg-rose-50{background-color:var(--color-rose-50)}.bg-sky-50{background-color:var(--color-sky-50)}.bg-sky-900{background-color:var(--color-sky-900)}.bg-sky-900\/60{background-color:#024a7099}@supports (color:color-mix(in lab, red, red)){.bg-sky-900\/60{background-color:color-mix(in oklab, var(--color-sky-900) 60%, transparent)}}.bg-slate-50{background-color:var(--color-slate-50)}.bg-slate-100{background-color:var(--color-slate-100)}.bg-slate-800{background-color:var(--color-slate-800)}.bg-slate-900{background-color:var(--color-slate-900)}.bg-warn,.bg-warn\/10{background-color:var(--bz-warn)}@supports (color:color-mix(in lab, red, red)){.bg-warn\/10{background-color:color-mix(in oklab, var(--bz-warn) 10%, transparent)}}.object-contain{object-fit:contain}.p-0{padding:calc(var(--spacing) * 0)}.p-1{padding:calc(var(--spacing) * 1)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-6{padding:calc(var(--spacing) * 6)}.p-8{padding:calc(var(--spacing) * 8)}.px-1{padding-inline:calc(var(--spacing) * 1)}.px-1\.5{padding-inline:calc(var(--spacing) * 1.5)}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-0{padding-block:calc(var(--spacing) * 0)}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:calc(var(--spacing) * 1)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-4{padding-block:calc(var(--spacing) * 4)}.py-5{padding-block:calc(var(--spacing) * 5)}.py-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-10{padding-block:calc(var(--spacing) * 10)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-14{padding-block:calc(var(--spacing) * 14)}.py-16{padding-block:calc(var(--spacing) * 16)}.py-24{padding-block:calc(var(--spacing) * 24)}.py-28{padding-block:calc(var(--spacing) * 28)}.py-px{padding-block:1px}.pt-6{padding-top:calc(var(--spacing) * 6)}.pt-20{padding-top:calc(var(--spacing) * 20)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-4{padding-bottom:calc(var(--spacing) * 4)}.pb-14{padding-bottom:calc(var(--spacing) * 14)}.pb-16{padding-bottom:calc(var(--spacing) * 16)}.pb-24{padding-bottom:calc(var(--spacing) * 24)}.pb-28{padding-bottom:calc(var(--spacing) * 28)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-5{padding-left:calc(var(--spacing) * 5)}.text-center{text-align:center}.text-left{text-align:left}.align-middle{vertical-align:middle}.font-mono{font-family:ui-monospace,SF Mono,Cascadia Mono,Consolas,monospace}.font-sans{font-family:Inter Variable,-apple-system,BlinkMacSystemFont,Segoe UI,system-ui,sans-serif}.font-serif{font-family:var(--font-serif)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-5xl{font-size:var(--text-5xl);line-height:var(--tw-leading,var(--text-5xl--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[15px\]{font-size:15px}.text-\[17px\]{font-size:17px}.text-\[18px\]{font-size:18px}.text-\[19px\]{font-size:19px}.text-\[20px\]{font-size:20px}.text-\[38px\]{font-size:38px}.text-\[40px\]{font-size:40px}.text-\[44px\]{font-size:44px}.text-\[52px\]{font-size:52px}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-\[1\.04\]{--tw-leading:1.04;line-height:1.04}.leading-\[1\.06\]{--tw-leading:1.06;line-height:1.06}.leading-\[1\.08\]{--tw-leading:1.08;line-height:1.08}.leading-none{--tw-leading:1;line-height:1}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-extrabold{--tw-font-weight:var(--font-weight-extrabold);font-weight:var(--font-weight-extrabold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-\[-0\.01em\]{--tw-tracking:-.01em;letter-spacing:-.01em}.tracking-\[-0\.03em\]{--tw-tracking:-.03em;letter-spacing:-.03em}.tracking-\[-0\.04em\]{--tw-tracking:-.04em;letter-spacing:-.04em}.tracking-\[-0\.015em\]{--tw-tracking:-.015em;letter-spacing:-.015em}.tracking-\[0\.08em\]{--tw-tracking:.08em;letter-spacing:.08em}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.text-accent{color:var(--bz-accent)}.text-amber-600{color:var(--color-amber-600)}.text-amber-800{color:var(--color-amber-800)}.text-amber-900{color:var(--color-amber-900)}.text-danger{color:var(--bz-danger)}.text-emerald-200{color:var(--color-emerald-200)}.text-emerald-300{color:var(--color-emerald-300)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-emerald-800{color:var(--color-emerald-800)}.text-emerald-900{color:var(--color-emerald-900)}.text-fg-1{color:var(--bz-fg-1)}.text-fg-2{color:var(--bz-fg-2)}.text-indigo-300{color:var(--color-indigo-300)}.text-indigo-600{color:var(--color-indigo-600)}.text-indigo-700{color:var(--color-indigo-700)}.text-ok{color:var(--bz-ok)}.text-rose-700{color:var(--color-rose-700)}.text-rose-800{color:var(--color-rose-800)}.text-rose-900{color:var(--color-rose-900)}.text-sky-200{color:var(--color-sky-200)}.text-sky-700{color:var(--color-sky-700)}.text-sky-800{color:var(--color-sky-800)}.text-sky-900{color:var(--color-sky-900)}.text-slate-100{color:var(--color-slate-100)}.text-slate-200{color:var(--color-slate-200)}.text-slate-300{color:var(--color-slate-300)}.text-slate-400{color:var(--color-slate-400)}.text-slate-500{color:var(--color-slate-500)}.text-slate-600{color:var(--color-slate-600)}.text-slate-800{color:var(--color-slate-800)}.text-warn{color:var(--bz-warn)}.text-white{color:var(--color-white)}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.no-underline{text-decoration-line:none}.underline{text-decoration-line:underline}.antialiased{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.accent-emerald-600{accent-color:var(--color-emerald-600)}.accent-indigo-600{accent-color:var(--color-indigo-600)}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring,.ring-1{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.ring-amber-200{--tw-ring-color:var(--color-amber-200)}.ring-emerald-200{--tw-ring-color:var(--color-emerald-200)}.ring-emerald-500{--tw-ring-color:var(--color-emerald-500)}.ring-emerald-500\/40{--tw-ring-color:#00bb7f66}@supports (color:color-mix(in lab, red, red)){.ring-emerald-500\/40{--tw-ring-color:color-mix(in oklab, var(--color-emerald-500) 40%, transparent)}}.ring-rose-200{--tw-ring-color:var(--color-rose-200)}.ring-sky-200{--tw-ring-color:var(--color-sky-200)}.ring-sky-500{--tw-ring-color:var(--color-sky-500)}.ring-sky-500\/40{--tw-ring-color:#00a5ef66}@supports (color:color-mix(in lab, red, red)){.ring-sky-500\/40{--tw-ring-color:color-mix(in oklab, var(--color-sky-500) 40%, transparent)}}.ring-slate-200{--tw-ring-color:var(--color-slate-200)}.ring-slate-600{--tw-ring-color:var(--color-slate-600)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur{--tw-backdrop-blur:blur(8px);-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.\[bridge\:restart\]{bridge:restart}.group-open\:rotate-45:is(:where(.group):is([open],:popover-open,:open) *){rotate:45deg}@media (hover:hover){.hover\:bg-slate-800:hover{background-color:var(--color-slate-800)}}.focus\:not-sr-only:focus{clip-path:none;white-space:normal;width:auto;height:auto;margin:0;padding:0;position:static;overflow:visible}.focus\:fixed:focus{position:fixed}.focus\:top-4:focus{top:calc(var(--spacing) * 4)}.focus\:left-4:focus{left:calc(var(--spacing) * 4)}.focus\:z-50:focus{z-index:50}.focus\:rounded-lg:focus{border-radius:var(--radius-lg)}.focus\:px-3:focus{padding-inline:calc(var(--spacing) * 3)}.focus\:py-2:focus{padding-block:calc(var(--spacing) * 2)}@media (prefers-reduced-motion:reduce){.motion-reduce\:animate-none{animation:none}}@media (min-width:40rem){.sm\:col-span-2{grid-column:span 2/span 2}.sm\:inline{display:inline}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:items-center{align-items:center}.sm\:justify-between{justify-content:space-between}:where(.sm\:divide-x>:not(:last-child)){--tw-divide-x-reverse:0;border-inline-style:var(--tw-border-style);border-inline-start-width:calc(1px * var(--tw-divide-x-reverse));border-inline-end-width:calc(1px * calc(1 - var(--tw-divide-x-reverse)))}.sm\:p-7{padding:calc(var(--spacing) * 7)}.sm\:p-8{padding:calc(var(--spacing) * 8)}.sm\:px-7{padding-inline:calc(var(--spacing) * 7)}.sm\:py-16{padding-block:calc(var(--spacing) * 16)}.sm\:py-20{padding-block:calc(var(--spacing) * 20)}.sm\:py-28{padding-block:calc(var(--spacing) * 28)}.sm\:py-32{padding-block:calc(var(--spacing) * 32)}.sm\:pt-28{padding-top:calc(var(--spacing) * 28)}.sm\:pb-32{padding-bottom:calc(var(--spacing) * 32)}.sm\:pb-36{padding-bottom:calc(var(--spacing) * 36)}.sm\:text-\[48px\]{font-size:48px}.sm\:text-\[52px\]{font-size:52px}.sm\:text-\[56px\]{font-size:56px}.sm\:text-\[68px\]{font-size:68px}}@media (min-width:48rem){.md\:col-span-2{grid-column:span 2/span 2}.md\:flex{display:flex}.md\:hidden{display:none}.md\:inline-flex{display:inline-flex}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}}@media (min-width:64rem){.lg\:sticky{position:sticky}.lg\:top-24{top:calc(var(--spacing) * 24)}.lg\:col-span-2{grid-column:span 2/span 2}.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:grid-cols-\[1\.6fr_1fr_1\.4fr_1fr_1fr\]{grid-template-columns:1.6fr 1fr 1.4fr 1fr 1fr}.lg\:grid-cols-\[1fr_2fr\]{grid-template-columns:1fr 2fr}.lg\:grid-cols-\[1fr_300px\]{grid-template-columns:1fr 300px}.lg\:grid-cols-\[220px_1fr\]{grid-template-columns:220px 1fr}.lg\:items-center{align-items:center}.lg\:self-start{align-self:flex-start}.lg\:border-t-0{border-top-style:var(--tw-border-style);border-top-width:0}.lg\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}}}@font-face{font-family:Inter Variable;font-style:normal;font-display:swap;font-weight:100 900;src:url(fonts/inter-latin-wght-normal.woff2)format("woff2-variations")}:root{--bz-bg-0:#fafafa;--bz-bg-1:#fff;--bz-bg-2:#f2f2f2;--bz-bg-3:#e8e8e8;--bz-fg-0:#0a0a0a;--bz-fg-1:#404040;--bz-fg-2:#6b6b6b;--bz-accent:#3f5fe8;--bz-ink:#171717;--bz-ink-fg:#fafafa;--bz-ok:#15803d;--bz-warn:#b45309;--bz-danger:#dc2626;--bz-line:#e5e5e5;--bz-ring:0 0 0 1px #0000000f, 0 1px 2px -1px #0000000f, 0 2px 4px 0 #0000000a;color-scheme:light}@media (prefers-color-scheme:dark){:root{--bz-bg-0:#0d0d0d;--bz-bg-1:#171717;--bz-bg-2:#1f1f1f;--bz-bg-3:#2a2a2a;--bz-fg-0:#fafafa;--bz-fg-1:#d4d4d4;--bz-fg-2:#a1a1a1;--bz-accent:#8ea2ff;--bz-ink:#ededed;--bz-ink-fg:#171717;--bz-ok:#4ade80;--bz-warn:#fbbf24;--bz-danger:#f87171;--bz-line:#ffffff1a;--bz-ring:0 0 0 1px #ffffff14;color-scheme:dark}}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-divide-x-reverse{syntax:"*";inherits:false;initial-value:0}@keyframes pulse{50%{opacity:.5}}
|
package/extension/sidepanel.html
DELETED
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
<!doctype html><html lang=en><head><meta charset=UTF-8><meta name=viewport content="width=device-width,initial-scale=1.0"><title>BrowserZap</title><link rel=stylesheet href=sidepanel.css></head><body>
|
|
2
|
-
<div id=app class="flex min-h-screen flex-col pb-2">
|
|
3
|
-
|
|
4
|
-
<header id=header class="sticky top-0 z-10 border-b border-line bg-bg-1 px-3 py-2">
|
|
5
|
-
<div class="flex items-center justify-between">
|
|
6
|
-
<div class="flex items-center gap-2 font-bold">
|
|
7
|
-
<img src=logo.svg width=20 height=20 alt class=size-5>
|
|
8
|
-
<span class="text-[14px] font-semibold tracking-[-0.01em]">BrowserZap</span>
|
|
9
|
-
</div>
|
|
10
|
-
<div class="flex items-center gap-1.5">
|
|
11
|
-
<span id=plan-badge class="pill pill-muted">free</span>
|
|
12
|
-
<span id=status-badge class="pill pill-muted">offline</span>
|
|
13
|
-
</div>
|
|
14
|
-
</div>
|
|
15
|
-
</header>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
<section id=connection-panel class=panel>
|
|
19
|
-
<div id=connection-status class="flex items-start gap-2">
|
|
20
|
-
<span class="status-dot mt-1 inline-block size-2 shrink-0 rounded-full bg-fg-2"></span>
|
|
21
|
-
<div class="flex flex-col gap-0.5">
|
|
22
|
-
<span id=status-message>Waiting for the bridge on port <strong id=port-display>9334</strong></span>
|
|
23
|
-
<span id=status-hint class=hint>Open your MCP client. If this stays grey, run: browserzap doctor</span>
|
|
24
|
-
</div>
|
|
25
|
-
</div>
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<div id=pairing-notice class="mt-2 rounded-md border border-warn/40 bg-warn/10 p-2 text-[12px]" hidden>
|
|
29
|
-
<strong>Not paired yet</strong>
|
|
30
|
-
<p id=pairing-setup class=my-1>
|
|
31
|
-
Run <code>npm install -g browserzap</code> and <code>browserzap setup</code> once, then reload this extension. Setup registers the helper that
|
|
32
|
-
hands this extension its pairing token; there is no token to copy.
|
|
33
|
-
</p>
|
|
34
|
-
<p id=pairing-fallback class=my-1>
|
|
35
|
-
If setup cannot be run on this machine, run <code>browserzap --print-token</code> and paste the
|
|
36
|
-
token under Settings → Pairing token. The bridge only accepts authenticated connections from this machine.
|
|
37
|
-
</p>
|
|
38
|
-
</div>
|
|
39
|
-
|
|
40
|
-
<details class=mt-2>
|
|
41
|
-
<summary class="cursor-pointer text-[12px] text-fg-1">Settings</summary>
|
|
42
|
-
<div class="mt-2 flex flex-col gap-3">
|
|
43
|
-
<div class="flex flex-col gap-1">
|
|
44
|
-
<label for=token-input class=meta>Pairing token</label>
|
|
45
|
-
<div class="flex gap-1.5">
|
|
46
|
-
<input type=password id=token-input placeholder="paste token" autocomplete=off spellcheck=false>
|
|
47
|
-
<button id=save-token-btn class=btn>Save</button>
|
|
48
|
-
</div>
|
|
49
|
-
<p class=hint>Stored in this browser profile only. Never logged, never sent anywhere but the local bridge.</p>
|
|
50
|
-
</div>
|
|
51
|
-
<div class="flex flex-col gap-1">
|
|
52
|
-
<label for=profile-input class=meta>Profile name</label>
|
|
53
|
-
<div class="flex gap-1.5">
|
|
54
|
-
<input type=text id=profile-input placeholder="e.g. Work" maxlength=40 autocomplete=off>
|
|
55
|
-
<button id=save-profile-btn class=btn>Save</button>
|
|
56
|
-
</div>
|
|
57
|
-
<p class=hint>Using BrowserZap in more than one Chrome profile? Name each one, so an agent can choose the right account.</p>
|
|
58
|
-
</div>
|
|
59
|
-
<div class="flex flex-col gap-1">
|
|
60
|
-
<label for=port-input class=meta>Bridge port</label>
|
|
61
|
-
<div class="flex gap-1.5">
|
|
62
|
-
<input type=number id=port-input value=9334 min=1024 max=65535>
|
|
63
|
-
<button id=save-port-btn class=btn>Save</button>
|
|
64
|
-
</div>
|
|
65
|
-
</div>
|
|
66
|
-
<div class="flex flex-col gap-1">
|
|
67
|
-
<label for=licence-input class=meta>Licence</label>
|
|
68
|
-
<div class="flex gap-1.5">
|
|
69
|
-
<input type=password id=licence-input placeholder="paste licence token" autocomplete=off spellcheck=false>
|
|
70
|
-
<button id=licence-save-btn class=btn>Activate</button>
|
|
71
|
-
</div>
|
|
72
|
-
<p id=licence-status class=hint>Free plan — every browser tool and every safety control. No licence needed. Pro (bulk runs, history, reports) is coming soon.</p>
|
|
73
|
-
<p class=hint>Device <code id=device-id>…</code> — this install's identity, created automatically on first run.</p>
|
|
74
|
-
<button id=licence-remove-btn class="btn btn-ghost w-full" hidden>Remove licence</button>
|
|
75
|
-
</div>
|
|
76
|
-
<button id=reconnect-btn class="btn w-full">Reconnect</button>
|
|
77
|
-
</div>
|
|
78
|
-
</details>
|
|
79
|
-
</section>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
<div id=conflict-banner class="mx-2 rounded-md border border-danger/40 bg-danger/10 p-2 text-[12px] text-danger" hidden></div>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
<section id=comments-panel class="panel flex flex-col gap-2">
|
|
86
|
-
<div class="flex items-center justify-between">
|
|
87
|
-
<h2 class=panel-title>Comments</h2>
|
|
88
|
-
<button id=cm-toggle-btn class=btn title="Click elements on this page and write what should change">Comment on this page</button>
|
|
89
|
-
</div>
|
|
90
|
-
<p id=cm-message class=hint role=status>Point at what is wrong on the page, write a note, and send every note to your agent at once. Saved only on this computer.</p>
|
|
91
|
-
<div id=cm-list class="flex flex-col gap-2"></div>
|
|
92
|
-
<div id=cm-footer class="flex gap-1.5" hidden>
|
|
93
|
-
<button id=cm-send-btn class="btn btn-primary flex-1">Send to agent</button>
|
|
94
|
-
<button id=cm-clear-btn class="btn btn-ghost">Clear</button>
|
|
95
|
-
</div>
|
|
96
|
-
<div id=cm-sent class="rounded-md border border-ok/40 bg-ok/10 p-2 text-[12px]" hidden>
|
|
97
|
-
<strong>Sent.</strong> Ask your agent:
|
|
98
|
-
<div class="mt-1 flex gap-1.5">
|
|
99
|
-
<code id=cm-prompt class="flex-1 break-words py-1">Apply my BrowserZap feedback</code>
|
|
100
|
-
<button id=cm-copy-btn class=btn>Copy</button>
|
|
101
|
-
</div>
|
|
102
|
-
</div>
|
|
103
|
-
</section>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
<section id=workflows-panel class="panel flex flex-col gap-2">
|
|
107
|
-
<div class="flex items-center justify-between">
|
|
108
|
-
<h2 class=panel-title>Workflows</h2>
|
|
109
|
-
<div class="flex gap-1.5">
|
|
110
|
-
<button id=wf-record-btn class=btn title="Record what you do in the current tab">Record</button>
|
|
111
|
-
<button id=wf-refresh-btn class="btn btn-ghost">Refresh</button>
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
<div id=wf-recording></div>
|
|
115
|
-
<div id=wf-run></div>
|
|
116
|
-
<p id=wf-message class=hint role=status></p>
|
|
117
|
-
<div id=wf-list class="flex flex-col gap-2"></div>
|
|
118
|
-
</section>
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
<div id=sessions-container class="flex flex-col"></div>
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
<section id=log-panel class=panel>
|
|
125
|
-
<div class="mb-1.5 flex items-center justify-between">
|
|
126
|
-
<h2 class=panel-title>Activity</h2>
|
|
127
|
-
<button id=clear-log-btn class="btn btn-ghost">Clear</button>
|
|
128
|
-
</div>
|
|
129
|
-
<div id=action-log class="flex max-h-72 flex-col overflow-y-auto">
|
|
130
|
-
<div class="hint py-2">Waiting for an agent</div>
|
|
131
|
-
</div>
|
|
132
|
-
</section>
|
|
133
|
-
</div>
|
|
134
|
-
|
|
135
|
-
<script src=sidepanel.js></script>
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
</body></html>
|
package/extension/sidepanel.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
(()=>{"use strict";const e=document.getElementById("status-badge"),t=document.querySelector(".status-dot"),n=document.getElementById("status-message"),a=document.getElementById("status-hint"),s=document.getElementById("port-display"),o=document.getElementById("port-input"),i=document.getElementById("save-port-btn"),l=document.getElementById("token-input"),r=document.getElementById("save-token-btn"),c=document.getElementById("profile-input"),d=document.getElementById("save-profile-btn"),p=document.getElementById("pairing-notice"),m=document.getElementById("pairing-setup"),u=document.getElementById("pairing-fallback"),f=document.getElementById("conflict-banner"),g=document.getElementById("reconnect-btn"),b=document.getElementById("sessions-container"),v=document.getElementById("action-log"),x=document.getElementById("clear-log-btn"),w=document.getElementById("plan-badge"),h=document.getElementById("licence-input"),$=document.getElementById("licence-save-btn"),y=document.getElementById("licence-remove-btn"),k=document.getElementById("licence-status"),E=document.getElementById("device-id"),I="pill pill-muted",C="mt-1 inline-block size-2 shrink-0 rounded-full",L={on:`status-dot connected ${C} bg-ok`,off:`status-dot disconnected ${C} bg-fg-2`},B={success:"bg-ok",error:"bg-danger",pending:"bg-warn"},_=e=>e?"active border-accent bg-accent/15 text-accent":"";let T=null;function S(e,t){return chrome.runtime.sendMessage({source:"sidepanel",type:e,...t})}function j(){if(!T)return;const o=!T.paired||Boolean(T.authorizationError);if(p.hidden=!o,o){const s=!1===T.nativeHost;m.hidden=!1,u.hidden=!s&&!T.authorizationError,e.textContent=T.paired?"token rejected":"not paired",e.className=I,t.className=L.off,n.textContent=T.authorizationError?"The bridge rejected the saved pairing token":"Pair this extension with the bridge to begin",a.textContent=s?"Run: npm install -g browserzap, then browserzap setup":null===T.nativeHost?"Starting the bridge through the native host…":"The bridge only accepts authenticated connections from this machine."}else if(T.versionError){e.textContent="update needed",e.className=I,t.className=L.off,n.textContent=T.versionError;const s=/bridge speaks protocol (\d+), the client sent (\d+)/.exec(T.versionError);a.textContent=s&&Number(s[1])<Number(s[2])?"An older BrowserZap bridge is still running. Run: browserzap restart-bridge":"Update both parts: npm install -g browserzap@latest, browserzap setup, reload the extension, then browserzap restart-bridge"}else if(T.connected){const s=A(T.sessions).length;e.textContent=s>0?`${s} agent${s>1?"s":""}`:"online",e.className="pill pill-ok",t.className=L.on,n.textContent=s>0?`${s} agent session${s>1?"s":""} active`:"Bridge connected, waiting for an agent";const o=T.profile;a.textContent=o&&o.connected>1?`This profile: ${o.label}. ${o.connected} Chrome profiles are connected; agents choose one with browser_select_profile.`:o&&o.label&&!/^Profile \d+$/.test(o.label)?`This profile: ${o.label}`:""}else T.conflictReason?(e.textContent="conflict",e.className=I,t.className=L.off,n.textContent=T.conflictReason,a.textContent="Close the other browser, or disable its BrowserZap extension, to use this one."):(e.textContent="offline",e.className=I,t.className=L.off,"bridge_foreign"===T.nativeError?(n.textContent="Another BrowserZap bridge is using the port and will not pair with this install",a.textContent="Run: browserzap restart-bridge, then press Reconnect under Settings"):(n.innerHTML=`Waiting for the bridge on port <strong>${s.textContent}</strong>`,a.textContent="The extension retries automatically"));const i=T.authorizationError??T.versionError??T.conflictReason??"";var l;f.hidden=0===i.length,f.textContent=i,0!==(l=T.sessions.filter(e=>e.id!==R||(e.approvals??[]).length>0||e.pendingUserAction)).length?b.innerHTML=l.map(e=>{const t=M(e.id),n=e.pendingUserAction?`\n <div class="user-action-alert mt-1 flex flex-col gap-1.5 rounded-md border border-warn/40 bg-warn/10 p-2">\n <h3 class="m-0 text-[12px] font-bold">Action needed</h3>\n <p>${M(e.pendingUserAction)}</p>\n <textarea data-session="${t}" placeholder="Describe what you did (optional)" rows="2"></textarea>\n <button class="btn btn-primary w-full user-done-btn" data-session="${t}">\n Hand back to AI\n </button>\n </div>\n `:"",a=(e.approvals??[]).map(e=>`\n <div class="user-action-alert approval-alert mt-1 flex flex-col gap-1.5 rounded-md border border-accent/40 bg-accent/10 p-2">\n <h3 class="m-0 text-[12px] font-bold">Approve this action?</h3>\n <p>${M(e.summary)}</p>\n <p class="meta m-0">${M(e.risk.replace(/_/g," "))} · ${M(e.origin)}</p>\n <div class="flex gap-1.5">\n <button class="btn btn-primary approval-btn" data-session="${t}" data-approval="${M(e.id)}" data-decision="approve">Approve once</button>\n <button class="btn btn-ghost approval-btn" data-session="${t}" data-approval="${M(e.id)}" data-decision="deny">Deny</button>\n </div>\n </div>\n `).join("");return`\n <section class="session-card panel flex flex-col gap-2">\n <div class="flex items-center justify-between gap-2">\n <span class="font-semibold">${M(e.name)}</span>\n <span class="font-mono text-[10px] text-fg-2">${t}</span>\n </div>\n <div class="flex gap-1">\n <button class="mode-btn btn flex-1 ${_("collaborative"===e.controlMode)}"\n data-session="${t}" data-mode="collaborative" title="Both user and AI">\n <span>Collab</span>\n </button>\n <button class="mode-btn btn flex-1 ${_("ai"===e.controlMode)}"\n data-session="${t}" data-mode="ai" title="AI has full control">\n <span>AI</span>\n </button>\n <button class="mode-btn btn flex-1 ${_("user"===e.controlMode)}"\n data-session="${t}" data-mode="user" title="User has control">\n <span>User</span>\n </button>\n </div>\n ${a}\n ${n}\n </section>\n `}).join(""):b.innerHTML=T?.connected?'<div class="hint mx-3 my-1">Waiting for agent sessions…</div>':"",function(e){if(0===e.length)return void(v.innerHTML='<div class="hint py-2">Waiting for an agent</div>');const t=e.slice(-50);v.innerHTML=t.map(e=>{const t=new Date(e.timestamp).toLocaleTimeString("en-US",{hour12:!1,hour:"2-digit",minute:"2-digit",second:"2-digit"}),n=e.session?`<span class="font-mono text-fg-2">${e.session.slice(0,4)}</span>`:"";return`\n <div class="log-entry flex items-start gap-1.5 border-b border-line py-1 text-[11px]">\n <div class="log-status ${e.status} mt-1 size-1.5 shrink-0 rounded-full ${B[e.status]??"bg-fg-2"}"></div>\n <span class="log-source ${e.source} text-[9px] font-bold uppercase text-fg-2">${e.source}</span>\n ${n}\n <div class="min-w-0 flex-1">\n <div>${M(e.action)}</div>\n ${e.details?`<div class="truncate text-fg-2" title="${M(e.details)}">${M(e.details)}</div>`:""}\n </div>\n <span class="font-mono text-[10px] text-fg-2">${t}</span>\n </div>\n `}).join(""),v.scrollTop=v.scrollHeight}(T.actionLog),X(),function(){const e=T?.comments??{activeTabId:null,comments:[]},t=null!==e.activeTabId;te.textContent=t?"Finish commenting":"Comment on this page",te.classList.toggle("btn-primary",t),se.hidden=0===e.comments.length,oe.textContent=`Send ${e.comments.length} comment${1===e.comments.length?"":"s"} to agent`,oe.disabled=!T?.connected;const n=e.comments.map(e=>`${e.cid}:${e.n}:${e.attachments.length}:${e.screenshot?1:0}`).join("|");n!==re&&(re=n,ae.innerHTML=e.comments.map(e=>{const t=M(e.cid),n=[e.screenshot?`<img src="data:image/png;base64,${e.screenshot}" alt="Screenshot of the element" class="max-h-28 max-w-full rounded border border-line object-contain">`:"",...e.attachments.map((e,n)=>`<span class="relative inline-block"><img src="data:${M(e.mimeType)};base64,${e.data}" alt="Attached image ${n+1}" class="max-h-20 max-w-[8rem] rounded border border-line object-contain"><button class="btn btn-ghost cm-detach absolute right-0 top-0 px-1 py-0 text-[10px]" data-cid="${t}" data-index="${n}" title="Remove image">×</button></span>`)].filter(Boolean).join("");return`<div class="card cm-item" data-cid="${t}">\n <div class="flex items-start justify-between gap-2">\n <span class="flex items-center gap-1.5"><span class="pill pill-warn">${e.n}</span><span class="meta break-words">${M(function(e){const t=e.component,n=t?.source?.file?`${t.source.file.split(/[\\/]/).slice(-2).join("/")}${t.source.line?`:${t.source.line}`:""}`:"";return[e.info.name?`${e.info.role??e.info.tag} "${e.info.name}"`:e.info.role&&"generic"!==e.info.role?e.info.role:e.info.tag??"element",t?.component?`<${t.component}>`:"",n].filter(Boolean).join(" · ")}(e))}</span></span>\n <button class="btn btn-ghost cm-delete px-1.5 py-0" data-cid="${t}" title="Delete comment">Delete</button>\n </div>\n <textarea class="cm-text h-16" data-cid="${t}" maxlength="2000" spellcheck="true">${M(e.text)}</textarea>\n ${n?`<div class="flex flex-wrap items-start gap-1.5">${n}</div>`:""}\n <div class="flex items-center justify-between gap-2">\n <span class="meta truncate" title="${M(e.page.url)}">${M(function(e){try{const t=new URL(e);return t.host+t.pathname}catch{return""}}(e.page.url))}</span>\n ${e.attachments.length<3?`<label class="btn btn-ghost cursor-pointer px-1.5 py-0">Add image<input type="file" accept="image/png,image/jpeg,image/webp,image/gif" class="cm-file hidden" data-cid="${t}"></label>`:""}\n </div>\n </div>`}).join(""))}()}!function e(){const t=chrome.runtime.connect({name:"sidepanel-keepalive"});t.onDisconnect.addListener(()=>{setTimeout(e,1e3)}),setTimeout(()=>{try{t.disconnect()}catch{}},2e4)}(),chrome.runtime.onMessage.addListener(e=>{"background"===e.source&&"state_update"===e.type&&(T=e.data,j())}),i.addEventListener("click",async()=>{const e=parseInt(o.value,10);e>=1024&&e<=65535&&(await chrome.storage.local.set({bridgePort:e}),s.textContent=String(e),await S("disconnect"),await S("connect",{port:e}))}),r.addEventListener("click",async()=>{const e=l.value.trim();await S("set_token",{token:e}),l.value="",l.placeholder=e?"paired — paste a new token to replace":"paste token"}),d.addEventListener("click",async()=>{await S("set_profile_label",{label:c.value})}),$.addEventListener("click",async()=>{const e=h.value.trim();if(!e)return;const t=await K("licence_activate",{token:e});h.value="",t.ok?await V():k.textContent=t.error?.message??"That licence was not accepted."}),y.addEventListener("click",async()=>{await K("licence_remove"),await V()}),chrome.storage.local.get(["bz_profile_label"]).then(e=>{"string"==typeof e.bz_profile_label&&(c.value=e.bz_profile_label)}).catch(()=>{}),g.addEventListener("click",async()=>{const e=parseInt(o.value,10);await S("disconnect"),await S("connect",{port:e})}),x.addEventListener("click",()=>{v.innerHTML='<div class="hint py-2">Log cleared</div>'}),b.addEventListener("click",e=>{const t=e.target,n=t.closest(".mode-btn");if(n)return void S("set_control_mode",{sessionId:n.dataset.session,data:n.dataset.mode});const a=t.closest(".approval-btn");if(a)return void S("decide_approval",{sessionId:a.dataset.session,approvalId:a.dataset.approval,approve:"approve"===a.dataset.decision});const s=t.closest(".user-done-btn");if(s){const e=s.dataset.session,t=b.querySelector(`textarea[data-session="${CSS.escape(e)}"]`);S("set_control_mode",{sessionId:e,data:"collaborative",userMessage:t?.value?.trim()||void 0}),t&&(t.value="")}});const R="panel",A=e=>e.filter(e=>e.id!==R);function M(e){return String(e).replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}const N=document.getElementById("workflows-panel"),D=document.getElementById("wf-recording"),H=document.getElementById("wf-run"),z=document.getElementById("wf-message"),P=document.getElementById("wf-list");let U=[],q={},F=null,O={},W="";const Z=e=>/is sensitive/.test(e?.description??"");function K(e,t={}){return S("panel",{op:e,args:t})}function Q(e,t=!1){z.textContent=e,z.classList.toggle("text-danger",t)}async function V(){const e=await K("list");e?.ok?(U=e.data?.workflows??[],q=e.data?.lastRuns??{},function(e,t){if(t?.short&&(E.textContent=t.short),!e)return;const n="pro"===e.plan;w.textContent=n?"pro":"free",w.className="pill "+(n?"pill-ok":"pill-muted");const a=n?`Pro${e.expiresAt?` until ${new Date(e.expiresAt).toLocaleDateString()}`:" — no expiry"}${e.licenseId?` · ${e.licenseId}`:""}.`:"Free plan — every browser tool and every safety control. No licence needed. Pro (bulk runs, history, reports) is coming soon.";k.textContent=[a,e.notice,e.reason].filter(Boolean).join(" "),y.hidden=!n}(e.data?.plan,e.data?.device),Q("")):(U=[],Q(e?.error?.message??"Could not load workflows.",!0)),Y()}function Y(){0!==U.length?P.innerHTML=U.map(e=>{const t=M(e.name);if(e.broken)return`<div class="card"><span class="break-words font-semibold">${t}</span><span class="meta">Cannot be used: ${M(e.broken)}</span></div>`;const n=q[e.name],a=n?`<span class="pill ${n.ok?"pill-ok":"USER_ACTION_REQUIRED"===n.code?"pill-warn":"pill-bad"}">${n.ok?"last run ok":M((n.code??"failed").toLowerCase().replace(/_/g," "))}</span>`:'<span class="pill pill-muted">never run</span>',s=F?.name===e.name?function(e){const t=M(e.name),n=Object.entries(e.params??{}).map(([e,t])=>{const n=M(e);return Z(t)?`<label class="flex flex-col gap-0.5 meta">${n}<span class="meta">Sensitive: the run pauses and you type it yourself in the page.</span></label>`:`<label class="flex flex-col gap-0.5 meta">${M(t.description||e)}\n <input type="text" data-param="${n}" value="${M(t.default??"")}" autocomplete="off" spellcheck="false"></label>`}).join(""),a=Object.entries(e.params??{}).filter(([,e])=>!Z(e)).map(([e])=>e);return`\n <div class="wf-form flex flex-col gap-1.5" data-name="${t}">\n ${n||'<span class="meta">No values needed.</span>'}\n <div class="flex flex-wrap gap-1.5">\n <button class="btn btn-primary wf-start" data-name="${t}">Start</button>\n <button class="btn btn-ghost wf-close">Close</button>\n </div>\n ${a.length?`\n <details class="wf-many">\n <summary class="meta cursor-pointer">Run for many (Pro)</summary>\n <div class="mt-1.5 flex flex-col gap-1.5">\n <label class="flex flex-col gap-0.5 meta">One row per run. First row: ${M(a.join(","))}${1===a.length?" (or just one value per line)":""}\n <textarea class="wf-many-text h-24 font-mono" spellcheck="false" placeholder="${M(a.join(","))}"></textarea></label>\n <span class="meta">Runs one after the other. A row that fails is reported and the next one runs.</span>\n <div class="flex flex-wrap gap-1.5"><button class="btn btn-primary wf-start-many" data-name="${t}">Run all</button></div>\n </div>\n </details>`:""}\n </div>`}(F.detail):"";return`\n <div class="card">\n <div class="flex items-center justify-between gap-2"><span class="break-words font-semibold">${t}</span>${a}</div>\n ${e.description?`<span class="meta">${M(e.description)}</span>`:""}\n <span class="meta">${e.steps??0} steps · ${M((e.origins??[]).join(", "))}${n?` · ${M(new Date(n.at).toLocaleString())}`:""}</span>\n ${n&&!n.ok?`<span class="meta">${M(n.summary)}</span>`:""}\n ${s||`<div class="flex flex-wrap gap-1.5"><button class="btn btn-primary wf-open" data-name="${t}">Run…</button></div>`}\n </div>`}).join(""):P.innerHTML='<div class="hint">No workflows yet. Press <b>Record</b>, do a task once in the current tab, then save it.</div>'}let G="",J=!1;function X(){T?.connected&&!J&&V(),J=Boolean(T?.connected);const e=T?.workflowRun??null;!function(e){if(!e)return void(D.innerHTML="");const t=e.steps.map((e,t)=>`\n <li>${M(e.label)}${e.sensitive?'<span class="ml-1 text-[10px] font-bold text-accent" title="You type this yourself on every run">sensitive</span>':""}${e.ambiguous?'<span class="ml-1 text-[10px] font-bold text-warn" title="This target is not unique; the run may stop here">check</span>':""}\n ${t>0?`<button class="btn btn-ghost wf-remove ml-1 px-1 py-0 text-[10px]" data-index="${t}" title="Remove this step">✕</button>`:""}</li>`).join("");e.stopped?D.innerHTML=`\n <div class="card border-accent/40 bg-accent/10">\n <div class="flex items-center justify-between gap-2"><span class="break-words font-semibold">Review and save</span><span class="meta">${e.steps.length} steps</span></div>\n <ol class="m-0 flex list-decimal flex-col gap-0.5 pl-4 text-[12px]">${t}</ol>\n <div class="wf-form flex flex-col gap-1.5">\n <label class="flex flex-col gap-0.5 meta">Name (lowercase letters, digits, - and _)<input type="text" id="wf-save-name" placeholder="e.g. enable-comments" autocomplete="off" spellcheck="false"></label>\n <label class="flex flex-col gap-0.5 meta">Description<input type="text" id="wf-save-desc" autocomplete="off"></label>\n <label class="flex flex-row items-center gap-1.5 meta"><input type="checkbox" id="wf-save-keep"> Keep what I typed as default values</label>\n <label class="flex flex-row items-center gap-1.5 meta"><input type="checkbox" id="wf-save-overwrite"> Replace a workflow with the same name</label>\n <div class="flex flex-wrap gap-1.5">\n <button class="btn btn-primary wf-rec-save">Save workflow</button>\n <button class="btn btn-ghost wf-rec-discard">Discard</button>\n </div>\n </div>\n </div>`:D.innerHTML=`\n <div class="card border-danger/40 bg-danger/10">\n <div class="flex items-center justify-between gap-2"><span class="break-words font-semibold"><span class="mr-1.5 inline-block size-2 animate-pulse rounded-full bg-danger motion-reduce:animate-none"></span>Recording</span><span class="meta">${e.steps.length} steps</span></div>\n <span class="meta">Do the task in the tab as you normally would. Only your own clicks and typing are recorded.</span>\n <ol class="m-0 flex list-decimal flex-col gap-0.5 pl-4 text-[12px]">${t}</ol>\n <div class="flex flex-wrap gap-1.5">\n <button class="btn btn-primary wf-rec-stop">Stop</button>\n <button class="btn btn-ghost wf-rec-discard">Discard</button>\n </div>\n </div>`}(T?.recording??null),function(e){if(!e)return void(H.innerHTML="");const t="running"===e.status||"awaiting_approval"===e.status,n="completed"===e.status?"ok":t||"needs_user"===e.status?"wait":"bad",a=e.batch&&!t?"":e.steps.map(e=>`<li>${e.ok?"✓":"✗"} ${M(e.tool)}${e.ok?"":` — ${M(e.summary)}`}</li>`).join(""),s=e.batch,o=s?`\n <span class="meta">${t?`Set ${s.index+1} of ${s.total} · `:""}${s.done} done${s.failed?` · ${s.failed} need attention`:""}</span>\n ${s.attention.length?`<ul class="m-0 flex list-none flex-col gap-1 p-0 text-[12px]">${s.attention.map(e=>`\n <li class="rounded-md border border-danger/30 bg-danger/5 px-2 py-1">\n <span class="font-semibold">${M(e.label)}</span>: ${e.step?`step ${e.step} (${M(e.tool??"")}${e.target?` ${M(e.target)}`:""})`:"did not start"} — ${M((e.code??"failed").toLowerCase().replace(/_/g," "))}${e.cause?`, ${M(e.cause.replace(/_/g," "))}`:""}\n ${e.screenshot?`<span class="block break-all meta" title="Saved on this computer">Screenshot: ${M(e.screenshot)}</span>`:""}\n </li>`).join("")}</ul>`:""}\n ${s.report?`<span class="meta break-all">Report: ${M(s.report)}</span>`:""}`:"";H.innerHTML=`\n <div class="card border-accent/40 bg-accent/10">\n <div class="flex items-center justify-between gap-2"><span class="break-words font-semibold">${M(e.workflow)}</span><span class="pill pill-${n}">${M(e.status.replace(/_/g," "))}</span></div>\n ${s&&!t?"":`<span class="meta">Step ${Math.min(e.stepIndex+1,e.totalSteps)} of ${e.totalSteps}</span>`}\n ${o}\n <span class="meta">${M(e.summary)}</span>\n ${"awaiting_approval"===e.status?'<span class="text-[12px] font-semibold">Approve or deny the step below, under "BrowserZap workflows".</span>':""}\n ${e.nextAction?`<span class="text-[12px] font-semibold">${M(e.nextAction)}</span>`:""}\n ${a?`<ol class="m-0 flex list-decimal flex-col gap-0.5 pl-4 text-[12px]">${a}</ol>`:""}\n <div class="flex flex-wrap gap-1.5">\n ${t?'<button class="btn btn-danger wf-cancel">Cancel run</button>':""}\n ${s?.canRerun&&!t?'<button class="btn btn-primary wf-rerun-failed">Re-run failed</button>':""}\n ${null===e.canContinueFrom||t?"":`<button class="btn btn-primary wf-continue" data-name="${M(e.workflow)}" data-start="${e.canContinueFrom}">Continue</button>`}\n ${t?"":'<button class="btn btn-ghost wf-dismiss">Dismiss</button>'}\n </div>\n </div>`}(e&&e.runId!==G?e:null);const t=e?`${e.runId}:${e.status}`:"";if(t!==W){const n=e&&!["running","awaiting_approval"].includes(e.status);W=t,n&&V()}}N.addEventListener("click",async e=>{const t=e.target.closest("button");if(t){if("wf-refresh-btn"===t.id)return V();if("wf-record-btn"===t.id){const[e]=await chrome.tabs.query({active:!0,currentWindow:!0}),t=await S("record_start",{tabId:e?.id});return void Q(t?.ok?"":t?.error??"Could not start recording.",!t?.ok)}if(t.classList.contains("wf-rec-stop"))S("record_stop");else if(t.classList.contains("wf-rec-discard"))S("record_discard");else if(t.classList.contains("wf-remove"))S("record_remove_step",{index:Number(t.dataset.index)});else{if(t.classList.contains("wf-rec-save")){const e=document.getElementById("wf-save-name").value.trim(),t=await S("record_save",{name:e,description:document.getElementById("wf-save-desc").value.trim(),keepValues:document.getElementById("wf-save-keep").checked,overwrite:document.getElementById("wf-save-overwrite").checked});return Q(t?.ok?`Saved "${e}".`:t?.error?.message??"Could not save.",!t?.ok),void(t?.ok&&V())}if(t.classList.contains("wf-open")){const e=await K("get",{name:t.dataset.name});return e?.ok?(F={name:t.dataset.name,detail:e.data.workflow},Y()):Q(e?.error?.message??"Could not open the workflow.",!0)}if(t.classList.contains("wf-close"))return F=null,Y();if(t.classList.contains("wf-start")){const e=t.closest(".wf-form"),n={};for(const[e,t]of Object.entries(F?.detail.params??{}))Z(t)&&(n[e]="");e.querySelectorAll("input[data-param]").forEach(e=>{n[e.dataset.param]=e.value}),O=n;const a=await K("run",{name:t.dataset.name,params:n});return a?.ok?(Q(""),G="",F=null,Y()):Q(a?.error?.message??"Could not start the run.",!0)}if(t.classList.contains("wf-start-many")){const e=t.closest(".wf-form").querySelector(".wf-many-text").value,n=await K("run_batch",{name:t.dataset.name,text:e});return n?.ok?(Q(""),G="",F=null,Y()):Q(n?.error?.message??"Could not start the runs.",!0)}if(t.classList.contains("wf-rerun-failed")){const e=await K("rerun_failed");return Q(e?.ok?"":e?.error?.message??"Could not run the failed sets again.",!e?.ok),void(e?.ok&&(G=""))}if(t.classList.contains("wf-continue")){const e=await K("continue",{name:t.dataset.name,params:O,startAt:Number(t.dataset.start)});return void Q(e?.ok?"":e?.error?.message??"Could not continue.",!e?.ok)}if(!t.classList.contains("wf-cancel"))return t.classList.contains("wf-dismiss")?(G=T?.workflowRun?.runId??"",O={},X()):void 0;K("cancel")}}}),async function(){const e=await chrome.storage.local.get(["bridgePort","bridgeToken"]);"number"==typeof e.bridgePort&&(o.value=String(e.bridgePort),s.textContent=String(e.bridgePort)),"string"==typeof e.bridgeToken&&e.bridgeToken&&(l.placeholder="paired — paste a new token to replace"),V();try{const e=await S("get_state");e&&(T=e,j())}catch{}}();const ee=document.getElementById("comments-panel"),te=document.getElementById("cm-toggle-btn"),ne=document.getElementById("cm-message"),ae=document.getElementById("cm-list"),se=document.getElementById("cm-footer"),oe=document.getElementById("cm-send-btn"),ie=document.getElementById("cm-sent"),le=ne.textContent??"";let re="";function ce(e,t=!1){ne.textContent=e||le,ne.classList.toggle("text-danger",t)}function de(e){return new Promise((t,n)=>{const a=new FileReader;a.onload=()=>t(String(a.result)),a.onerror=()=>n(a.error),a.readAsDataURL(e)})}async function pe(e,t){const n=await S("comment_attach",{cid:e,dataUrl:await de(t)});ce(n?.ok?"":n?.error??"Could not add the image.",!n?.ok)}ee.addEventListener("click",async e=>{const t=e.target.closest("button");if(t){if("cm-toggle-btn"===t.id){ie.hidden=!0;const e=T?.comments?.activeTabId;if(null!=e)return await S("comment_stop"),void ce("");const[t]=await chrome.tabs.query({active:!0,currentWindow:!0}),n=await S("comment_start",{tabId:t?.id});return void ce(n?.ok?"Click an element on the page, write your note, press Save. Esc finishes.":n?.error??"Could not start Comment mode.",!n?.ok)}if("cm-send-btn"===t.id){oe.disabled=!0;const e=await S("comment_send");return oe.disabled=!1,ie.hidden=!e?.ok,void ce(e?.ok?"":e?.error??"Could not send the comments.",!e?.ok)}if("cm-copy-btn"===t.id)return await navigator.clipboard.writeText(document.getElementById("cm-prompt").textContent??"").catch(()=>{}),t.textContent="Copied",void setTimeout(()=>{t.textContent="Copy"},1500);"cm-clear-btn"!==t.id?t.classList.contains("cm-delete")?S("comment_delete",{cid:t.dataset.cid}):t.classList.contains("cm-detach")&&S("comment_detach",{cid:t.dataset.cid,index:Number(t.dataset.index)}):S("comment_clear")}}),ee.addEventListener("change",e=>{const t=e.target;t.classList.contains("cm-file")&&t.files?.[0]&&pe(String(t.dataset.cid),t.files[0])}),ee.addEventListener("focusout",e=>{const t=e.target;t.classList?.contains("cm-text")&&S("comment_update",{cid:t.dataset.cid,text:t.value})}),ee.addEventListener("paste",e=>{const t=e.target;if(!t.classList?.contains("cm-text"))return;const n=Array.from(e.clipboardData?.items??[]).find(e=>e.type.startsWith("image/"))?.getAsFile();n&&(e.preventDefault(),pe(String(t.dataset.cid),n))})})();
|