pipeup 0.7.0 → 0.8.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/cli/init.mjs +581 -0
- package/cli/pipeup.mjs +70 -1
- package/cli/read.mjs +299 -0
- package/dist/addons.json +54 -0
- package/dist/pipeup.core.js +1 -1
- package/dist/pipeup.esm.js +1 -1
- package/dist/pipeup.min.js +1 -1
- package/dist/types/core.d.ts +3 -1
- package/dist/types/document.d.ts +2 -2
- package/dist/types/index.d.ts +0 -1
- package/dist/types/ui/addons.d.ts +24 -1
- package/dist/types/ui/app.d.ts +2 -3
- package/dist/types/ui/context.d.ts +0 -2
- package/dist/types/ui/host.d.ts +1 -1
- package/dist/types/ui/styles.d.ts +1 -1
- package/package.json +2 -1
- package/skills/pipeup-add/SKILL.md +3 -3
- package/skills/pipeup-apply/SKILL.md +1 -1
- package/skills/pipeup-integrate/SKILL.md +4 -4
- package/skills/pipeup-send-to-git-setup/SKILL.md +1 -1
- package/skills/pipeup-summarise/SKILL.md +1 -1
- package/dist/types/crypto/portable.d.ts +0 -15
- package/dist/types/ui/identity.d.ts +0 -27
package/dist/types/core.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.8.0-beta.1";
|
|
2
2
|
/** The day this version was made (set with the version): Pipeup says so, once, in the console when it is over a year old. */
|
|
3
3
|
export declare const BUILT = "2026-10-13";
|
|
4
4
|
export { PipeupDocument, UnsavedChangeError, type Listener, type OpenOptions } from "./document";
|
|
@@ -12,5 +12,7 @@ export { describeElement, describeRange } from "./anchor/describe";
|
|
|
12
12
|
export { resolveAnchor, type AnchorState, type Resolved, type ResolveOptions } from "./anchor/resolve";
|
|
13
13
|
export { labelOf, locate, type Location } from "./anchor/locate";
|
|
14
14
|
export { copyAll, copyThread, formatAgo, type CopyAs, type ExportItem, type ExportMeta, } from "./export/format";
|
|
15
|
+
export { readFeedbackFile } from "./storage/feedback-file";
|
|
16
|
+
export { agentComments, type AgentComments, type AgentThread } from "./export/agent";
|
|
15
17
|
export { AI_NAME, ANIMALS, COLOURS, animalName, isAiName, nameOf, type Animal } from "./model/animals";
|
|
16
18
|
export type { Anchor, Comment, OpBody, SignedOp, Thread } from "./model/types";
|
package/dist/types/document.d.ts
CHANGED
|
@@ -54,8 +54,8 @@ export declare class PipeupDocument {
|
|
|
54
54
|
contacts(): Map<string, string>;
|
|
55
55
|
/** This reviewer's identity was made portable, so it has a recovery code (an ordinary one can't leave the browser). */
|
|
56
56
|
get portable(): boolean;
|
|
57
|
-
/** The
|
|
58
|
-
|
|
57
|
+
/** The 32-byte seed of a portable identity, for backing it up; null for an ordinary one. */
|
|
58
|
+
seed(): Promise<Uint8Array | null>;
|
|
59
59
|
/** Marks comments read by this reviewer (one `seen` op each, for those not already marked), so every device knows. */
|
|
60
60
|
seen(commentIds: readonly string[]): Promise<void>;
|
|
61
61
|
/** Reacts to a comment with one emoji; reacting twice with the same emoji changes nothing. */
|
package/dist/types/index.d.ts
CHANGED
|
@@ -3,5 +3,4 @@ export { comments, mount, type MountOptions, type PipeupInstance } from "./ui/mo
|
|
|
3
3
|
export type { Appearance } from "./ui/legible";
|
|
4
4
|
export { setPeople, type Person } from "./ui/mentions";
|
|
5
5
|
export { ADDON_API, addons, use, type AddonDocument, type AddonHost, type AddonInfo, type Capability, type ComposerHandle, type ComposerTool, type Dictation, type ItemHandle, type ListNote, type ReactionPicker, type MenuItem, type NetworkUse, type Off, type PanelHandle, type PanelOptions, type PipeupAddon, type Status, type Teardown, type UiSnapshot, } from "./ui/addons";
|
|
6
|
-
export { type AgentComments, type AgentThread } from "./export/agent";
|
|
7
6
|
export { onReveal, setViewState, type SlideHook, type ViewState } from "./ui/here";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Identity } from "../crypto/identity";
|
|
1
2
|
import type { Listener, PipeupDocument } from "../document";
|
|
2
3
|
import type { SignedOp, Thread } from "../model/types";
|
|
3
4
|
import { type ComposerTool } from "./composer";
|
|
@@ -7,7 +8,7 @@ import type { ViewState } from "./here";
|
|
|
7
8
|
export declare const ADDON_API = 1;
|
|
8
9
|
export type Teardown = () => void;
|
|
9
10
|
export type Off = () => void;
|
|
10
|
-
export type Capability = "sync" | "menu" | "notify" | "note" | "composer" | "panel" | "styles" | "status" | "overlay" | "here" | "sign" | "listnote" | "reactions";
|
|
11
|
+
export type Capability = "sync" | "menu" | "notify" | "note" | "composer" | "panel" | "styles" | "status" | "overlay" | "here" | "sign" | "listnote" | "reactions" | "identity" | "dialog";
|
|
11
12
|
export interface NetworkUse {
|
|
12
13
|
when: "never" | "after-consent" | "page-configured";
|
|
13
14
|
/** Hosts; "page" is an address the page names. */
|
|
@@ -107,6 +108,22 @@ export interface UiSnapshot {
|
|
|
107
108
|
import type { ReactionPicker } from "./reactions";
|
|
108
109
|
export type { ReactionPicker } from "./reactions";
|
|
109
110
|
export type { ComposerHandle, ComposerTool, Dictation } from "./composer";
|
|
111
|
+
export interface DialogHandle {
|
|
112
|
+
close(): void;
|
|
113
|
+
}
|
|
114
|
+
/** This reviewer's identity, for an add-on that backs it up or replaces it (the add-on is trusted with it, as with any script on the page). */
|
|
115
|
+
export interface IdentityAccess {
|
|
116
|
+
/** The identity was made portable: its key can be backed up. An ordinary one can't leave the browser. */
|
|
117
|
+
readonly portable: boolean;
|
|
118
|
+
/** The 32-byte seed of a portable identity; null for an ordinary one. */
|
|
119
|
+
seed(): Promise<Uint8Array | null>;
|
|
120
|
+
/** Keeps `key`, an extractable Ed25519 private key, as this browser's identity from the next load on. */
|
|
121
|
+
use(key: CryptoKey): Promise<void>;
|
|
122
|
+
/** Shares how to reach this reviewer (an email address or `gh:name`) with everyone who has the comments; false if it isn't one. */
|
|
123
|
+
share(contact: string): Promise<boolean>;
|
|
124
|
+
/** Stops sharing it. */
|
|
125
|
+
unshare(): Promise<void>;
|
|
126
|
+
}
|
|
110
127
|
export interface AddonHost {
|
|
111
128
|
readonly api: number;
|
|
112
129
|
/** The core's version, for diagnostics only. */
|
|
@@ -154,6 +171,9 @@ export interface AddonHost {
|
|
|
154
171
|
onUi(fn: (ui: UiSnapshot) => void): Off;
|
|
155
172
|
avatar(key: string, name: string): HTMLElement;
|
|
156
173
|
sign(name: string, data: string): Promise<string>;
|
|
174
|
+
readonly identity: IdentityAccess;
|
|
175
|
+
/** A small dialog over the page, labelled `label`; Escape closes it, and it goes with the add-on. */
|
|
176
|
+
openDialog(content: Node, label: string): DialogHandle;
|
|
157
177
|
}
|
|
158
178
|
/**
|
|
159
179
|
* Everything add-ons put on the page, held by the app (not by the views) so it survives layout rebuilds. Each
|
|
@@ -231,6 +251,7 @@ export declare class Surface {
|
|
|
231
251
|
private call;
|
|
232
252
|
/** A side panel: the rest of Pipeup's UI is inert while it is open; Escape closes it before anything else. */
|
|
233
253
|
panel(id: string, content: Node, o: PanelOptions): PanelHandle;
|
|
254
|
+
dialog(id: string, content: Node, label: string): DialogHandle;
|
|
234
255
|
/** Removes everything one add-on added. */
|
|
235
256
|
clear(id: string): void;
|
|
236
257
|
destroy(): void;
|
|
@@ -242,6 +263,8 @@ interface Live {
|
|
|
242
263
|
ephemeral: boolean;
|
|
243
264
|
version: string;
|
|
244
265
|
active: boolean;
|
|
266
|
+
/** Keeps another identity for this browser, used from the next load. */
|
|
267
|
+
onIdentity(identity: Identity): Promise<void>;
|
|
245
268
|
}
|
|
246
269
|
/**
|
|
247
270
|
* A Pipeup already on the page when this copy loaded (the classic build assigns its global only when it ends, so
|
package/dist/types/ui/app.d.ts
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { type PipeupDocument } from "../document";
|
|
2
|
-
import type { Identity } from "../crypto/identity";
|
|
3
2
|
import type { Ctx, UiState, View } from "./context";
|
|
4
3
|
import { type Appearance } from "./legible";
|
|
5
4
|
export interface AppOptions {
|
|
6
5
|
doc: PipeupDocument;
|
|
7
6
|
root: Element;
|
|
8
7
|
onName(name: string): Promise<void>;
|
|
9
|
-
/**
|
|
10
|
-
|
|
8
|
+
/** Pipeup's stylesheet (passed in so the bundles can carry it last, where it compresses best). */
|
|
9
|
+
styles: string;
|
|
11
10
|
}
|
|
12
11
|
export interface App {
|
|
13
12
|
readonly ctx: Ctx;
|
|
@@ -45,8 +45,6 @@ export interface MenuActions {
|
|
|
45
45
|
copyAll(as: CopyAs): Promise<void>;
|
|
46
46
|
toggleResolved(): void;
|
|
47
47
|
toggleMine(): void;
|
|
48
|
-
/** Opens the dialog for making the identity portable, backing it up, or using one that was backed up. */
|
|
49
|
-
identity(): void;
|
|
50
48
|
rename(name: string): Promise<void>;
|
|
51
49
|
/** The reviewer's name; "" until they add one. */
|
|
52
50
|
name(): string;
|
package/dist/types/ui/host.d.ts
CHANGED
|
@@ -9,4 +9,4 @@ export interface Host {
|
|
|
9
9
|
* Pipeup's only element in the page: a fixed, click-through <pipeup-root> under <html> with an open shadow
|
|
10
10
|
* root (open so tools like `pipeup check` can measure it). It never changes the page's layout.
|
|
11
11
|
*/
|
|
12
|
-
export declare function createHost(theme: Theme, doc?: Document): Host;
|
|
12
|
+
export declare function createHost(theme: Theme, styles: string, doc?: Document): Host;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Pipeup's stylesheet, scoped to its shadow root. Light by default; `.dark` follows a dark page. */
|
|
2
|
-
export declare const STYLES = "\n/* Inherited page styles are reset on .layer below; custom properties pass through all:initial. */\n:host{all:initial;direction:ltr;unicode-bidi:normal}\n*{box-sizing:border-box}\nbutton{appearance:none;font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer}\nsvg{display:block}\n.layer{all:initial;direction:ltr;unicode-bidi:normal;display:block;position:fixed;inset:0;pointer-events:none;font:13px/1.5 var(--pu-font,system-ui,sans-serif);color:var(--k);\n--k:#2C2C2A;--mu:#5F5E5A;--fa:#6B6A64;--ln:#E5E3DA;--ru:#ECEAE2;--so:#FAFAF7;--su:#FFFFFF;--ho:#F1EFE8;\n--as:color-mix(in srgb,var(--pu-accent,#534AB7) 12%,transparent);\n--sh:0 8px 28px rgba(44,44,42,.10);\n--in:.26s;--mv:.34s;--out:.2s;--pl:1.2s;\n--eo:cubic-bezier(.22,.61,.36,1);--eio:cubic-bezier(.4,0,.2,1);--ei:cubic-bezier(.4,0,1,1);\n--pu-text:var(--k);--pu-muted:var(--mu);--pu-faint:var(--fa);--pu-line:var(--ln);--pu-surface:var(--su);--pu-soft:var(--so);--pu-hover:var(--ho);--pu-shadow:var(--sh);--pu-ease:var(--eo)}\n.layer{transition:opacity .24s var(--eo)}.layer.sw{opacity:0;transition-duration:.16s;transition-timing-function:var(--ei)}\n.layer.dark{--k:#ECEBE6;--mu:#B4B2A9;--fa:#9A9892;--ln:#3A3936;--ru:#34332F;--so:#22221F;--su:#1B1B19;--ho:#2C2C29;--sh:0 8px 28px rgba(0,0,0,.45)}\n.layer.hidden .bub,.layer.hidden .col,.layer.hidden .pop,.layer.hidden .tip,.layer.hidden .mark,.layer.hidden .selbar{opacity:0!important;pointer-events:none!important}\n\n.tx{font-size:14px;line-height:1.5;color:var(--k);white-space:pre-wrap;overflow-wrap:anywhere}\n.tx.del,.who,.rest,.ctx{color:var(--fa)}\n.who,.rest{font-size:12px}\n/* Long names are cut short on one line, never wrapped. */\n.who{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.rft>.who{display:block}\n.ctx[hidden]{display:none}\n.ctx{font-size:12px;margin-bottom:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.clamp{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.tx a{color:var(--pu-accent);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}\n\n/* Footers: details take no space until hovered, then ease open beneath the words. */\n.ft,.rft{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--in) var(--eo),opacity var(--in) var(--eo)}\n.ft>*,.rft>*{overflow:hidden;min-height:0;display:flex;align-items:center}\n.root:hover>.ft,.root:focus-within>.ft,.it:hover>.rft,.it:focus-within>.rft{grid-template-rows:1fr;opacity:1}\n.ft.has-rest,.ft.open,.rft.open{grid-template-rows:1fr;opacity:1}\n.ft.has-rest>*{grid-area:1/1}\n.ft .hover{opacity:0;transition:opacity var(--in) var(--eo)}\n.ft .rest{transition:opacity var(--in) var(--eo)}\n.root:hover>.ft .hover,.root:focus-within>.ft .hover,.ft:not(.has-rest) .hover{opacity:1}\n.root:hover>.ft .rest,.root:focus-within>.ft .rest{opacity:0}\n.acts{margin-left:6px;display:flex;flex:none}\n.ib{width:24px;height:22px;display:grid;place-items:center;border-radius:6px;color:var(--mu);transition:background-color .2s var(--eo),color .2s var(--eo)}\n.ib:hover,.ib:focus-visible{background:var(--ho);color:var(--k);outline:none}\n\n/* Replies: one level in, oldest first; the reply line ends the thread at the same indent. */\n.rps,.rbox{padding-left:14px}\n.rps .it{padding-top:6px}\n.more{display:grid;grid-template-rows:1fr;transition:grid-template-rows var(--mv) var(--eio)}\n.more>div{overflow:hidden;min-height:0}\n.th:not(.on) .more{grid-template-rows:0fr}\n\n.row{position:relative;display:flex;align-items:center;gap:8px;padding:8px 0 2px;cursor:text}\n.input{flex:1;min-width:0;height:27px;display:block;border:0;border-bottom:1px solid var(--ln);outline:none;resize:none;overflow:hidden;\nfont:inherit;font-size:14px;line-height:1.5;padding:3px 0;color:var(--k);background:transparent;transition:border-color var(--in) var(--eo)}\n.row:hover .input,.input:hover{border-bottom-color:var(--mu)}\n.input:focus{border-bottom-color:var(--pu-accent)}\n.ed{display:flex;gap:10px;align-items:center;min-height:34px;padding:6px 10px}\n.ed .input{font-size:13px;height:22px}\n\n/* Avatars: a squircle with the writer's animal (or initial) on a soft colour. Each comment keeps a fixed area\nat its top right for one, so its words are the same width with or without it. */\n.root,.it{position:relative;padding-right:30px}\n.av{display:grid;place-items:center;width:22px;height:22px;border-radius:32%;\nfont-size:12px;font-weight:600;line-height:1;opacity:0;transform:scale(.85);transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.av.in{opacity:1;transform:none}\n.av svg{width:80%;height:80%}\n.root>.av,.it>.av{position:absolute;top:0;right:0}\n.it>.av{top:6px}\n/* Ten colours (.c0 Red to .c9 Grey, as COLOURS): a soft tint and a dark drawing, swapped round on dark pages. */\n.av{--av-l:92%;--av-d:30%;--s:60%;background:hsl(var(--h) var(--s) var(--av-l));color:hsl(var(--h) var(--s) var(--av-d))}\n.dark .av{--av-l:20%;--av-d:78%}\n/* An AI's reply: a plain disc with a violet ring, all inside the avatar's own box so nothing is cropped. */\n.av.ai{position:relative;border-radius:50%;background:var(--su);color:var(--pu-accent);font-size:9px;letter-spacing:.02em}\n.av.ai::before{content:\"\";position:absolute;inset:3px;border-radius:50%;border:1.5px solid var(--pu-accent);pointer-events:none}\n.root>.av.ai,.it>.av.ai{position:absolute}\n.refs{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px;white-space:normal}\n.refs .ref{display:inline-flex;align-items:center;gap:5px;max-width:160px;padding:1px 9px;border:1px solid var(--ln);border-radius:999px;background:var(--so);color:var(--mu);font:inherit;font-size:11.5px;line-height:1.6;text-decoration:none;cursor:pointer;transition:background-color .2s var(--eo),color .2s var(--eo),border-color .2s var(--eo)}\n.refs .ref:hover,.refs .ref:focus-visible{background:var(--as);color:var(--pu-accent);border-color:var(--pu-accent);outline:none}\n.ref span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.rxp{position:fixed;width:320px;height:340px;border-radius:12px;overflow:hidden;pointer-events:none;opacity:0;transform:translateY(4px);transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.rxp.show{opacity:1;transform:none;pointer-events:auto}\n.mn{border-radius:4px;padding:0 2px;background:var(--as);color:var(--pu-accent)}\n.mn.me{font-weight:600}\n.mnl{position:absolute;left:0;bottom:100%;margin:0 0 4px;padding:4px;list-style:none;min-width:180px;max-width:100%;border:1px solid var(--ln);border-radius:10px;background:var(--su);box-shadow:var(--sh);opacity:0;transform:translateY(4px);pointer-events:none;z-index:4;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.mnl.show{opacity:1;transform:none;pointer-events:auto}\n.mnl li{display:flex;align-items:baseline;gap:8px;padding:5px 8px;border-radius:6px;font-size:13px;color:var(--k);cursor:pointer}\n.mnl li small{font-size:11px;color:var(--fa)}\n.mnl li.on,.mnl li:hover{background:var(--as);color:var(--pu-accent)}\n.dlg{position:fixed;left:50%;top:18vh;width:min(380px,calc(100vw - 32px));padding:16px 18px;border:1px solid var(--ln);border-radius:14px;background:var(--su);box-shadow:var(--sh);color:var(--k);opacity:0;transform:translate(-50%,6px);pointer-events:none;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.dlg.show{opacity:1;transform:translate(-50%,0);pointer-events:auto}\n.dlg-t{margin:0 0 8px;font-size:15px;font-weight:600}\n.dlg-b p{margin:0 0 8px;font-size:13px;line-height:1.5;color:var(--mu)}\n.dlg-c{display:block;margin:8px 0;padding:8px 10px;border-radius:8px;background:var(--so);font:12px/1.6 ui-monospace,monospace;word-break:break-all;user-select:all}\n.dlg-f{width:100%;margin:6px 0;padding:8px;border:1px solid var(--ln);border-radius:8px;background:var(--so);color:var(--k);font:12px/1.5 ui-monospace,monospace}\n.dlg-m{min-height:1.2em;margin:4px 0;font-size:12px;color:var(--pu-accent)}\n.dlg-a{display:flex;gap:6px;justify-content:flex-end;margin-top:6px}\n.dlg-btn{padding:6px 12px;border:1px solid var(--ln);border-radius:8px;font-size:13px;color:var(--k);transition:background-color .2s var(--eo)}\n.dlg-btn:hover,.dlg-btn:focus-visible{background:var(--ho);outline:none}\n.dlg-btn.primary{border-color:var(--pu-accent);color:var(--pu-accent)}\n.toast.act{pointer-events:auto}\n.ta{margin-left:4px;color:var(--pu-accent);text-decoration:underline;text-underline-offset:2px}\n.dlg-h{margin:12px 0 4px;font-size:13px;font-weight:600}\n.rx .n{font-size:11px}\n.rx.mine{background:var(--as);color:var(--pu-accent);border-color:var(--pu-accent)}\n.rx:disabled{cursor:default;opacity:.7}\n.rx.new,.rxq.new{animation:pu-in var(--mv) var(--eo) both}\n.rxs{align-items:center}\n.rxq{display:inline-flex;gap:2px}\n.rxo{padding:2px 5px;border-radius:8px;font-size:16px;line-height:1.3;transition:background-color .2s var(--eo)}\n.rxo:hover,.rxo:focus-visible,.rxo[aria-pressed=true]{background:var(--as);outline:none}\n.rrow{min-width:0;flex:1;display:flex;align-items:center}\n.refs .ref{position:relative}.ref .rc{position:absolute;left:0;top:calc(100% + 6px);z-index:3;width:max-content;max-width:min(240px,70vw);padding:6px 9px;border:1px solid var(--ln);border-radius:8px;background:var(--su);box-shadow:var(--sh);color:var(--k);font-size:12px;line-height:1.45;white-space:normal;text-align:left;overflow:visible;opacity:0;visibility:hidden;transform:translateY(-3px);pointer-events:none;transition:opacity .2s var(--eo),transform .2s var(--eo),visibility 0s .2s}.ref:hover .rc,.ref:focus-visible .rc{opacity:1;visibility:visible;transform:none;transition-delay:0s}\n.ref .sl{width:10px;height:7px;border:1.3px solid currentColor;border-radius:2px;flex:none}\n.seen{display:flex;align-items:center;gap:6px;padding:6px 0 0 14px;font-size:12px;color:var(--fa)}\n.seen button{margin-left:auto;padding:0 6px;border:0;border-radius:6px;background:none;color:var(--fa);font:inherit;cursor:pointer;transition:color .2s var(--eo),background-color .2s var(--eo)}.seen button:hover,.seen button:focus-visible{color:var(--pu-accent);background:var(--as);outline:none}\n.seen i{width:12px;height:12px;border-radius:50%;border:1.5px solid var(--pu-accent);flex:none}\n.c0{--h:0}.c1{--h:25}.c2{--h:50}.c3{--h:130}.c4{--h:175}.c5{--h:215}.c6{--h:270}.c7{--h:330}.c8{--h:28;--s:35%}.c9{--h:220;--s:8%}\n.me{flex:none;display:grid}\n.me>.av{grid-area:1/1;width:26px;height:26px;font-size:13px}\n/* Who you are, under the comment line; a name field eases open in its place. */\n.you{display:grid;padding:0 34px;min-height:24px;font-size:12px;color:var(--fa)}\n.you>*{grid-area:1/1;display:flex;align-items:center;min-width:0;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.say{white-space:pre;overflow:hidden}\n.nm{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.say button{flex:none}\n.say button{color:var(--mu);text-decoration:underline;text-decoration-color:var(--ln);text-underline-offset:2px;transition:color .2s var(--eo)}\n.say button:hover,.say button:focus-visible{color:var(--pu-accent);outline:none}\n.nf{opacity:0;transform:translateY(-4px);pointer-events:none}\n.nf .input{font-size:13px;height:24px}\n.you.naming .nf{opacity:1;transform:none;pointer-events:auto}\n.you.naming .say{opacity:0;pointer-events:none}\n.send{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;color:var(--pu-accent);flex:none;opacity:0;pointer-events:none;\ntransition:opacity var(--in) var(--eo),background-color .2s var(--eo)}\n.send.show{opacity:1;pointer-events:auto}\n.send:hover{background:var(--as)}\n\n/* Bubbles, tips, popovers, marks, pulses. */\n.bub{position:fixed;left:0;top:0;width:20px;height:20px;margin:-20px 0 0 -2px;border-radius:50% 50% 50% 0;background:var(--pu-accent);\nborder:2px solid var(--su);box-shadow:0 1px 4px rgba(0,0,0,.2);pointer-events:auto;opacity:0;transform:translateY(-6px) scale(.9);transform-origin:2px 20px;\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.bub.in{opacity:1;transform:none;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.bub.in:hover,.bub.on{transform:scale(1.18)}\n.bub.done{background:var(--fa)}\n.bub.ghost{pointer-events:none}\n.tip,.pop,.menu,.all,.xp,.toast,.selbar,.namebar,.ttip,.tt,.mode,.rxp{background:var(--su);border:1px solid var(--ln);box-shadow:var(--sh)}\n.tip{position:fixed;max-width:260px;border-radius:10px;padding:7px 10px;opacity:0;transform:translateY(3px);\ntransition:opacity .22s var(--eo),transform .26s var(--eo)}\n.tip.show{opacity:1;transform:none;pointer-events:auto;cursor:pointer;\ntransition:opacity .22s var(--eo),transform .26s var(--eo),left var(--mv) var(--eio),top var(--mv) var(--eio)}\n.pop{position:fixed;width:var(--pu-pop);border-radius:12px;padding:10px 12px 8px;pointer-events:none;opacity:0;transform:translateY(6px) scale(.98);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.pop.show{opacity:1;transform:none;pointer-events:auto;transition:opacity var(--in) var(--eo),transform var(--mv) var(--eo)}\n.pop.show.glide{transition:opacity var(--in) var(--eo),transform var(--mv) var(--eo),left var(--mv) var(--eio),top var(--mv) var(--eio)}\n.mark{position:fixed;border:2px solid color-mix(in srgb,var(--pu-accent) 50%,transparent);background:var(--as);border-radius:8px;opacity:0;\ntransition:opacity .3s var(--eo)}\n.mark.show{opacity:1}\n.pulse{position:fixed;border:2px solid var(--pu-accent);border-radius:8px;background:var(--as);animation:pu-pulse var(--pl) var(--eio) forwards}\n@keyframes pu-pulse{0%{opacity:0;transform:scale(.985)}35%{opacity:.85;transform:scale(1)}100%{opacity:0;transform:scale(1.02)}}\n\n/* Document column. */\n.col{position:fixed;left:0;top:0;pointer-events:none;transition:opacity var(--in) var(--eo)}\n.th{position:absolute;left:0;right:0;top:0;padding:4px 4px 4px 12px;background:var(--su);border-radius:8px;pointer-events:auto;cursor:pointer;box-shadow:inset 2px 0 0 transparent;\ntransition:transform var(--mv) var(--eio),box-shadow var(--in) var(--eo),opacity var(--in) var(--eo)}\n.th.hot{box-shadow:inset 2px 0 0 var(--ln)}\n.th.on{box-shadow:inset 2px 0 0 var(--pu-accent);cursor:default}\n.th.dim{opacity:.45}\n.th.resolved:not(.on):not(.hot){opacity:.6}\n.th.lost .ctx{white-space:normal}\n.th.wait{opacity:0!important;pointer-events:none}\n.th.out{opacity:0!important;pointer-events:none;transition:opacity var(--out) var(--ei)}\n/* A closed thread's button has no box of its own: the thread shows its focus. */\n.th:has(.opn:focus-visible){box-shadow:inset 2px 0 0 var(--ln);outline:2px solid var(--pu-accent);outline-offset:2px;border-radius:4px}\n\n/* Selection bar. */\n.selbar{position:fixed;display:flex;border-radius:10px;padding:2px;opacity:0;transform:translateY(4px);pointer-events:none;\ntransition:opacity var(--in) var(--eo),transform .3s var(--eo)}\n.selbar.show{opacity:1;transform:none;pointer-events:auto}\n.selbar button{width:32px;height:30px;display:grid;place-items:center;border-radius:8px;color:var(--pu-accent);transition:background-color .2s var(--eo)}\n.selbar button:hover,.selbar button:focus-visible{background:var(--as);outline:none}\n\n/* Comment mode's outline: glides between blocks; solid accent once chosen. */\n.pick{position:fixed;left:0;top:0;border:2px solid color-mix(in srgb,var(--pu-accent) 70%,transparent);background:color-mix(in srgb,var(--pu-accent) 6%,transparent);\nborder-radius:8px;pointer-events:none;opacity:0;transition:opacity var(--out) var(--ei),border-color var(--out) var(--ei),border-width var(--out) var(--ei),box-shadow var(--out) var(--ei)}\n.pick.show{opacity:1;transition-duration:var(--in);transition-timing-function:var(--eo)}\n.pick.show.glide{transition-property:all;transition-duration:var(--mv);transition-timing-function:var(--eio)}\n.pick.on{border-color:var(--pu-accent)}\n/* The block cursor: its focus is drawn on the outline (3px accent with a surface halo, 3:1 on any page); the\nmarkers that hold focus are invisible. */\n.pick.kf{border:3px solid var(--pu-accent);box-shadow:0 0 0 2px var(--su)}\n.km{position:fixed;left:0;top:0;pointer-events:none;outline:none}\n.sr,.mn-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n.namebar{position:fixed;left:0;top:0;display:flex;align-items:center;gap:2px;padding:2px 2px 2px 10px;border-radius:10px;font-size:12px;color:var(--mu);\nwhite-space:nowrap;pointer-events:none;opacity:0;transform:translateY(4px);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.namebar.show{opacity:1;transform:none;pointer-events:auto;transition:opacity var(--in) var(--eo),transform .3s var(--eo)}\n.namebar.show.glide{transition-property:all;transition-duration:var(--mv);transition-timing-function:var(--eio)}\n.namebar .lbl{margin-right:6px;max-width:260px;overflow:hidden;text-overflow:ellipsis}\n.namebar .nb{padding:4px;display:grid;place-items:center;border-radius:7px;transition:background-color .2s var(--eo),color .2s var(--eo)}\n.namebar .nb:hover,.namebar .nb:focus-visible{background:var(--ho);color:var(--k);outline:none}\n.namebar .nb[hidden]{display:none}\n\n/* The comment control: one round button; the open count sits inside a comment bubble. Nothing about it\ngrows or slides: its layers and numbers cross-fade in place. */\n.launch{position:fixed;right:20px;bottom:20px;pointer-events:auto}\n.launch .mode{position:relative;display:grid;place-items:center;width:46px;height:46px;border-radius:50%;transition:background-color .3s var(--eo),color .3s var(--eo)}\n.mode>*,.cnt>*{grid-area:1/1}\n.mode>*{display:grid;place-items:center;transition:opacity var(--in) var(--eo)}\n.cnt,.has>.plus{opacity:0}\n.has>.cnt{opacity:1}\n.n{font-size:12px;font-weight:500;line-height:1;margin:-1.4px 0 0 1.4px;font-variant-numeric:tabular-nums;opacity:0;transition:opacity var(--in) var(--eo)}\n.n.s{font-size:9.5px;letter-spacing:-.04em}\n.n.on{opacity:1}\n.launch .mode:hover,.launch .mode[aria-expanded=true]{background:var(--ho)}\n.launch .mode.on{background:var(--pu-accent);color:var(--pu-on,#fff)}\n/* Open threads on other slides or views: a small dot at the button's top right, easing in and out. */\n.mode>.dot{position:absolute;top:3px;right:3px;width:9px;height:9px;border-radius:50%;background:var(--pu-accent);border:2px solid var(--su);opacity:0}\n.mode.else>.dot{opacity:1}\n/* The tooltip eases in after a moment, above the button, and never moves it. */\n.ttip{position:absolute;right:0;bottom:54px;white-space:nowrap;border-radius:8px;padding:4px 9px;font-size:12px;pointer-events:none;opacity:0;transform:translateY(3px);transition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.ttip small{margin-left:8px}\n.ttip small,.mi .kc{font-size:12px;color:var(--fa)}\n.mode:hover+.ttip,.mode:focus-visible+.ttip{opacity:1;transform:none;transition:opacity var(--in) var(--eo) .5s,transform var(--in) var(--eo) .5s}\n.launch .mode[aria-expanded=true]+.ttip{opacity:0;transition:opacity var(--out) var(--ei)}\n@media (hover:none){.ttip,.tt{display:none}}\n.menu{position:fixed;right:20px;bottom:76px;width:290px;border-radius:12px;padding:4px;pointer-events:none;opacity:0;transform:translateY(6px);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.menu.show{opacity:1;transform:none;pointer-events:auto;transition:opacity var(--in) var(--eo),transform var(--mv) var(--eo)}\n/* Menu rows: one line each; the explanation is a tooltip beside the menu that eases in after a moment. */\n.mi{position:relative;display:flex;gap:10px;align-items:center;width:100%;min-height:34px;text-align:left;padding:6px 10px;border-radius:8px;transition:background-color .2s var(--eo)}\n.mi:hover,.mi:focus-visible{background:var(--so);outline:none}\n.mi svg{color:var(--mu);flex:none}\n.mi small{display:block;color:var(--fa);font-size:12px}\n.lb{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.ma{flex:none;display:grid;margin:-2px 0}\n.ma .av{width:20px;height:20px;font-size:11px}\n.mi .av svg{color:inherit}\n.sep{height:1px;margin:4px 10px;background:var(--ru)}\n.tt{position:absolute;right:calc(100% + 14px);top:50%;translate:0 -50%;width:max-content;max-width:220px;padding:4px 9px;border-radius:8px;font-size:12px;line-height:1.4;\ncolor:var(--mu);pointer-events:none;opacity:0;transform:translateX(3px);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.mi:hover>.tt,.mi:focus-visible>.tt{opacity:1;transform:none;transition:opacity var(--in) var(--eo) .5s,transform var(--in) var(--eo) .5s}\n@media (max-width:600px){.tt{right:8px;top:auto;bottom:100%;translate:none;transform:translateY(3px)}}\n/* Switches: a track and a knob that slides (cross-fades with reduced motion). */\n.sw{position:relative;flex:none;width:26px;height:16px;border-radius:8px;background:var(--ln);transition:background-color var(--mv) var(--eio)}\n.sw::before,.sw::after{content:\"\";position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);\ntransition:transform var(--mv) var(--eio),opacity var(--mv) var(--eio)}\n.sw::before{opacity:0;transform:translateX(10px)}\n[aria-checked=true]>.sw{background:var(--pu-accent)}\n[aria-checked=true]>.sw::after{transform:translateX(10px)}\n.tools{display:flex;flex:none;gap:2px}\n.tools[hidden]{display:none}\n.tool[aria-pressed=true]{background:var(--as);color:var(--pu-accent)}\n.note{display:block;padding:0 0 4px;font-size:12px;color:var(--fa)}\n.note[hidden]{display:none}\n.ov{position:absolute;inset:0;pointer-events:none;overflow:hidden}\n/* An add-on's panel (.xp) is the same full-height panel as All comments (.all), with its own body. */\n.xb{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:4px 16px 16px;font-size:13px}\n.xb p{margin:0 0 10px}\n/* All comments: a full-height panel on the right that slides in (fades, with reduced motion). */\n.all,.xp{position:fixed;top:0;right:0;bottom:0;width:var(--pu-panel);display:flex;flex-direction:column;border-width:0 0 0 1px;opacity:0;transform:translateX(100%);\ntransition:transform var(--out) var(--ei),opacity var(--out) var(--ei)}\n.all.show,.xp.show{opacity:1;transform:none;pointer-events:auto;transition:transform var(--mv) var(--eo),opacity var(--in) var(--eo)}\n.all.full{width:100%}\n.hd{display:flex;align-items:center;gap:8px;padding:12px 10px 8px 16px;font-weight:600}\n.pn{font-weight:400;color:var(--fa)}\n.hs{margin-left:auto;display:flex;align-items:center;gap:6px;padding:3px 4px 3px 6px;border-radius:6px;font-size:12px;font-weight:400;color:var(--mu);\ntransition:background-color .2s var(--eo)}\n.hs:hover,.hs:focus-visible{background:var(--ho);outline:none}\n.list{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:4px}\n.all .mi{align-items:flex-start}\n.all .mi>.av{flex:none}\n.all .mi>span:last-child{flex:1;min-width:0}\n.all .mi small{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.all .mi.done{opacity:.6}\n.all .mi.open{background:var(--so)}\n.all .mi.open>.av,.all .mi.open .clamp{display:none}\n.xr{padding:2px 12px 10px 16px}\n/* The line from an open thread in the panel to its place on the page. */\n.cx{position:fixed;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;opacity:0;transition:opacity var(--in) var(--eo)}\n.cx.show{opacity:1}\n.cx path{fill:none;stroke:var(--pu-accent);stroke-width:1.5;stroke-linecap:round;opacity:.7}\n.cx circle{fill:var(--pu-accent)}\n.layer.listing .col{opacity:0;transition:opacity var(--out) var(--ei)}\n.sec{padding:8px 10px 2px;font-size:12px;color:var(--fa)}\n.ag{display:flex;align-items:center;gap:8px;padding:6px 14px;font-size:12px;color:var(--fa);border-bottom:1px solid var(--ln)}\n.ag[hidden]{display:none}\n.lns{display:flex;flex-direction:column}\n.ln{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--in) var(--eo),opacity var(--in) var(--eo)}\n.ln.show{grid-template-rows:1fr;opacity:1}\n.ln>.lw{overflow:hidden;min-height:0}\n.ag button{margin-left:auto;flex:none;padding:0 6px;border-radius:6px;color:var(--fa);transition:color .2s var(--eo),background-color .2s var(--eo)}.ag button:hover:not(:disabled),.ag button:focus-visible{color:var(--pu-accent);background:var(--as);outline:none}.ag button:disabled{opacity:.5;cursor:default}\n.adr{margin:8px 0 0 14px;padding:8px 10px;border-radius:8px;background:var(--so);font-size:13px;color:var(--k);animation:pu-in var(--mv) var(--eo) both}\n.adr small{display:block;font-size:12px;color:var(--fa)}\n.adr .go{display:flex;gap:6px;margin-top:6px}\n.adr .go button{padding:2px 8px;border-radius:6px;font-size:12px;color:var(--mu);transition:color .2s var(--eo),background-color .2s var(--eo)}.adr .go button:hover,.adr .go button:focus-visible{color:var(--pu-accent);background:var(--as);outline:none}\n@keyframes pu-in{0%{opacity:0;transform:translateY(3px)}100%{opacity:1;transform:none}}\n.sec b{margin-left:6px;font-weight:500;color:var(--pu-accent)}\n.toast{position:fixed;left:50%;bottom:28px;border-radius:10px;padding:8px 14px;font-size:13px;opacity:0;transform:translate(-50%,6px);\ntransition:opacity .3s var(--eo),transform .36s var(--eo)}\n.toast.show{opacity:1;transform:translate(-50%,0)}\n\n/* Touch: fingers need bigger targets than pointers (44 px for the menu's rows, 36 and more for buttons). */\n@media (pointer:coarse){\n.mi{min-height:44px}\n.ib{min-width:36px;min-height:36px}\n.rxo{min-width:40px;min-height:40px}\n.refs .ref{min-height:34px}\n.mnl li{min-height:40px}\n.dlg-btn,.hs{min-height:40px}\n.send{min-width:36px;min-height:36px}\n}\n\n@media (forced-colors: active){\n.pick.kf{border:3px solid Highlight}\n.layer :is(.ib,.mi,.nb,.hs,.selbar button,.say button,.xb button):focus-visible{outline:2px solid Highlight}\n}\n\n@media (prefers-reduced-motion: reduce){\n.ln{transition-property:opacity}\n@keyframes pu-in{0%{opacity:0}100%{opacity:1}}\n.bub,.bub.in,.bub.in:hover,.bub.on,.tip,.pop,.selbar,.menu,.all,.xp,.ttip,.tt,.toast,.ref .rc,.rxp,.mnl{transform:none!important}\n.dlg{transform:translate(-50%,0)!important}\n.sw::after{transform:none!important;transition-property:opacity}\n[aria-checked=true]>.sw::after{opacity:0}\n[aria-checked=true]>.sw::before{opacity:1}\n.th{transition-property:opacity,box-shadow}\n.tip.show{transition-property:opacity}\n.pick,.pick.show{transition:opacity .16s ease-in-out}\n.all,.all.show,.xp,.xp.show{transition-property:opacity}\n.namebar,.namebar.show{transform:none!important;transition:opacity .16s ease-in-out}\n.av,.nf{transform:none!important}\n@keyframes pu-pulse{0%{opacity:0}35%{opacity:.85}100%{opacity:0}}\n}\n";
|
|
2
|
+
export declare const STYLES = "\n/* Inherited page styles are reset on .layer below; custom properties pass through all:initial. */\n:host{all:initial;direction:ltr;unicode-bidi:normal}\n*{box-sizing:border-box}\nbutton{appearance:none;font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer}\nsvg{display:block}\n.layer{all:initial;direction:ltr;unicode-bidi:normal;display:block;position:fixed;inset:0;pointer-events:none;font:13px/1.5 var(--pu-font,system-ui,sans-serif);color:var(--k);\n--k:#2C2C2A;--mu:#5F5E5A;--fa:#6B6A64;--ln:#E5E3DA;--ru:#ECEAE2;--so:#FAFAF7;--su:#FFFFFF;--ho:#F1EFE8;\n--as:color-mix(in srgb,var(--pu-accent,#534AB7) 12%,transparent);\n--sh:0 8px 28px rgba(44,44,42,.10);\n--in:.26s;--mv:.34s;--out:.2s;--pl:1.2s;\n--eo:cubic-bezier(.22,.61,.36,1);--eio:cubic-bezier(.4,0,.2,1);--ei:cubic-bezier(.4,0,1,1);\n--pu-text:var(--k);--pu-muted:var(--mu);--pu-faint:var(--fa);--pu-line:var(--ln);--pu-surface:var(--su);--pu-soft:var(--so);--pu-hover:var(--ho);--pu-shadow:var(--sh);--pu-ease:var(--eo)}\n.layer{transition:opacity .24s var(--eo)}.layer.sw{opacity:0;transition-duration:.16s;transition-timing-function:var(--ei)}\n.layer.dark{--k:#ECEBE6;--mu:#B4B2A9;--fa:#9A9892;--ln:#3A3936;--ru:#34332F;--so:#22221F;--su:#1B1B19;--ho:#2C2C29;--sh:0 8px 28px rgba(0,0,0,.45)}\n.layer.hidden .bub,.layer.hidden .col,.layer.hidden .pop,.layer.hidden .tip,.layer.hidden .mark,.layer.hidden .selbar{opacity:0!important;pointer-events:none!important}\n\n.tx{font-size:14px;line-height:1.5;color:var(--k);white-space:pre-wrap;overflow-wrap:anywhere}\n.tx.del,.who,.rest,.ctx{color:var(--fa)}\n.who,.rest{font-size:12px}\n/* Long names are cut short on one line, never wrapped. */\n.who{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.rft>.who{display:block}\n.ctx[hidden]{display:none}\n.ctx{font-size:12px;margin-bottom:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.clamp{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.tx a{color:var(--pu-accent);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}\n\n/* Footers: details take no space until hovered, then ease open beneath the words. */\n.ft,.rft{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--in) var(--eo),opacity var(--in) var(--eo)}\n.ft>*,.rft>*{overflow:hidden;min-height:0;display:flex;align-items:center}\n.root:hover>.ft,.root:focus-within>.ft,.it:hover>.rft,.it:focus-within>.rft{grid-template-rows:1fr;opacity:1}\n.ft.has-rest,.ft.open,.rft.open{grid-template-rows:1fr;opacity:1}\n.ft.has-rest>*{grid-area:1/1}\n.ft .hover{opacity:0;transition:opacity var(--in) var(--eo)}\n.ft .rest{transition:opacity var(--in) var(--eo)}\n.root:hover>.ft .hover,.root:focus-within>.ft .hover,.ft:not(.has-rest) .hover{opacity:1}\n.root:hover>.ft .rest,.root:focus-within>.ft .rest{opacity:0}\n.acts{margin-left:6px;display:flex;flex:none}\n.ib{width:24px;height:22px;display:grid;place-items:center;border-radius:6px;color:var(--mu);transition:background-color .2s var(--eo),color .2s var(--eo)}\n.ib:hover,.ib:focus-visible{background:var(--ho);color:var(--k);outline:none}\n\n/* Replies: one level in, oldest first; the reply line ends the thread at the same indent. */\n.rps,.rbox{padding-left:14px}\n.rps .it{padding-top:6px}\n.more{display:grid;grid-template-rows:1fr;transition:grid-template-rows var(--mv) var(--eio)}\n.more>div{overflow:hidden;min-height:0}\n.th:not(.on) .more{grid-template-rows:0fr}\n\n.row{position:relative;display:flex;align-items:center;gap:8px;padding:8px 0 2px;cursor:text}\n.input{flex:1;min-width:0;height:27px;display:block;border:0;border-bottom:1px solid var(--ln);outline:none;resize:none;overflow:hidden;\nfont:inherit;font-size:14px;line-height:1.5;padding:3px 0;color:var(--k);background:transparent;transition:border-color var(--in) var(--eo)}\n.row:hover .input,.input:hover{border-bottom-color:var(--mu)}\n.input:focus{border-bottom-color:var(--pu-accent)}\n.ed{display:flex;gap:10px;align-items:center;min-height:34px;padding:6px 10px}\n.ed .input{font-size:13px;height:22px}\n\n/* Avatars: a squircle with the writer's animal (or initial) on a soft colour. Each comment keeps a fixed area\nat its top right for one, so its words are the same width with or without it. */\n.root,.it{position:relative;padding-right:30px}\n.av{display:grid;place-items:center;width:22px;height:22px;border-radius:32%;\nfont-size:12px;font-weight:600;line-height:1;opacity:0;transform:scale(.85);transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.av.in{opacity:1;transform:none}\n.av svg{width:80%;height:80%}\n.root>.av,.it>.av{position:absolute;top:0;right:0}\n.it>.av{top:6px}\n/* Ten colours (.c0 Red to .c9 Grey, as COLOURS): a soft tint and a dark drawing, swapped round on dark pages. */\n.av{--av-l:92%;--av-d:30%;--s:60%;background:hsl(var(--h) var(--s) var(--av-l));color:hsl(var(--h) var(--s) var(--av-d))}\n.dark .av{--av-l:20%;--av-d:78%}\n/* An AI's reply: a plain disc with a violet ring, all inside the avatar's own box so nothing is cropped. */\n.av.ai{position:relative;border-radius:50%;background:var(--su);color:var(--pu-accent);font-size:9px;letter-spacing:.02em}\n.av.ai::before{content:\"\";position:absolute;inset:3px;border-radius:50%;border:1.5px solid var(--pu-accent);pointer-events:none}\n.root>.av.ai,.it>.av.ai{position:absolute}\n.refs{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px;white-space:normal}\n.refs .ref{display:inline-flex;align-items:center;gap:5px;max-width:160px;padding:1px 9px;border:1px solid var(--ln);border-radius:999px;background:var(--so);color:var(--mu);font:inherit;font-size:11.5px;line-height:1.6;text-decoration:none;cursor:pointer;transition:background-color .2s var(--eo),color .2s var(--eo),border-color .2s var(--eo)}\n.refs .ref:hover,.refs .ref:focus-visible{background:var(--as);color:var(--pu-accent);border-color:var(--pu-accent);outline:none}\n.ref span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.rxp{position:fixed;width:320px;height:340px;border-radius:12px;overflow:hidden;pointer-events:none;opacity:0;transform:translateY(4px);transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.rxp.show{opacity:1;transform:none;pointer-events:auto}\n.mn{border-radius:4px;padding:0 2px;background:var(--as);color:var(--pu-accent)}\n.mn.me{font-weight:600}\n.mnl{position:absolute;left:0;bottom:100%;margin:0 0 4px;padding:4px;list-style:none;min-width:180px;max-width:100%;border:1px solid var(--ln);border-radius:10px;background:var(--su);box-shadow:var(--sh);opacity:0;transform:translateY(4px);pointer-events:none;z-index:4;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.mnl.show{opacity:1;transform:none;pointer-events:auto}\n.mnl li{display:flex;align-items:baseline;gap:8px;padding:5px 8px;border-radius:6px;font-size:13px;color:var(--k);cursor:pointer}\n.mnl li small{font-size:11px;color:var(--fa)}\n.mnl li.on,.mnl li:hover{background:var(--as);color:var(--pu-accent)}\n.dlg{position:fixed;left:50%;top:18vh;width:min(380px,calc(100vw - 32px));padding:16px 18px;border:1px solid var(--ln);border-radius:14px;background:var(--su);box-shadow:var(--sh);color:var(--k);opacity:0;transform:translate(-50%,6px);pointer-events:none;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.dlg.show{opacity:1;transform:translate(-50%,0);pointer-events:auto}\n.toast.act{pointer-events:auto}\n.ta{margin-left:4px;color:var(--pu-accent);text-decoration:underline;text-underline-offset:2px}\n.rx .n{font-size:11px}\n.rx.mine{background:var(--as);color:var(--pu-accent);border-color:var(--pu-accent)}\n.rx:disabled{cursor:default;opacity:.7}\n.rx.new,.rxq.new{animation:pu-in var(--mv) var(--eo) both}\n.rxs{align-items:center}\n.rxq{display:inline-flex;gap:2px}\n.rxo{padding:2px 5px;border-radius:8px;font-size:16px;line-height:1.3;transition:background-color .2s var(--eo)}\n.rxo:hover,.rxo:focus-visible,.rxo[aria-pressed=true]{background:var(--as);outline:none}\n.rrow{min-width:0;flex:1;display:flex;align-items:center}\n.refs .ref{position:relative}.ref .rc{position:absolute;left:0;top:calc(100% + 6px);z-index:3;width:max-content;max-width:min(240px,70vw);padding:6px 9px;border:1px solid var(--ln);border-radius:8px;background:var(--su);box-shadow:var(--sh);color:var(--k);font-size:12px;line-height:1.45;white-space:normal;text-align:left;overflow:visible;opacity:0;visibility:hidden;transform:translateY(-3px);pointer-events:none;transition:opacity .2s var(--eo),transform .2s var(--eo),visibility 0s .2s}.ref:hover .rc,.ref:focus-visible .rc{opacity:1;visibility:visible;transform:none;transition-delay:0s}\n.ref .sl{width:10px;height:7px;border:1.3px solid currentColor;border-radius:2px;flex:none}\n.seen{display:flex;align-items:center;gap:6px;padding:6px 0 0 14px;font-size:12px;color:var(--fa)}\n.seen button{margin-left:auto;padding:0 6px;border:0;border-radius:6px;background:none;color:var(--fa);font:inherit;cursor:pointer;transition:color .2s var(--eo),background-color .2s var(--eo)}.seen button:hover,.seen button:focus-visible{color:var(--pu-accent);background:var(--as);outline:none}\n.seen i{width:12px;height:12px;border-radius:50%;border:1.5px solid var(--pu-accent);flex:none}\n.c0{--h:0}.c1{--h:25}.c2{--h:50}.c3{--h:130}.c4{--h:175}.c5{--h:215}.c6{--h:270}.c7{--h:330}.c8{--h:28;--s:35%}.c9{--h:220;--s:8%}\n.me{flex:none;display:grid}\n.me>.av{grid-area:1/1;width:26px;height:26px;font-size:13px}\n/* Who you are, under the comment line; a name field eases open in its place. */\n.you{display:grid;padding:0 34px;min-height:24px;font-size:12px;color:var(--fa)}\n.you>*{grid-area:1/1;display:flex;align-items:center;min-width:0;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.say{white-space:pre;overflow:hidden}\n.nm{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.say button{flex:none}\n.say button{color:var(--mu);text-decoration:underline;text-decoration-color:var(--ln);text-underline-offset:2px;transition:color .2s var(--eo)}\n.say button:hover,.say button:focus-visible{color:var(--pu-accent);outline:none}\n.nf{opacity:0;transform:translateY(-4px);pointer-events:none}\n.nf .input{font-size:13px;height:24px}\n.you.naming .nf{opacity:1;transform:none;pointer-events:auto}\n.you.naming .say{opacity:0;pointer-events:none}\n.send{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;color:var(--pu-accent);flex:none;opacity:0;pointer-events:none;\ntransition:opacity var(--in) var(--eo),background-color .2s var(--eo)}\n.send.show{opacity:1;pointer-events:auto}\n.send:hover{background:var(--as)}\n\n/* Bubbles, tips, popovers, marks, pulses. */\n.bub{position:fixed;left:0;top:0;width:20px;height:20px;margin:-20px 0 0 -2px;border-radius:50% 50% 50% 0;background:var(--pu-accent);\nborder:2px solid var(--su);box-shadow:0 1px 4px rgba(0,0,0,.2);pointer-events:auto;opacity:0;transform:translateY(-6px) scale(.9);transform-origin:2px 20px;\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.bub.in{opacity:1;transform:none;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.bub.in:hover,.bub.on{transform:scale(1.18)}\n.bub.done{background:var(--fa)}\n.bub.ghost{pointer-events:none}\n.tip,.pop,.menu,.all,.xp,.toast,.selbar,.namebar,.ttip,.tt,.mode,.rxp{background:var(--su);border:1px solid var(--ln);box-shadow:var(--sh)}\n.tip{position:fixed;max-width:260px;border-radius:10px;padding:7px 10px;opacity:0;transform:translateY(3px);\ntransition:opacity .22s var(--eo),transform .26s var(--eo)}\n.tip.show{opacity:1;transform:none;pointer-events:auto;cursor:pointer;\ntransition:opacity .22s var(--eo),transform .26s var(--eo),left var(--mv) var(--eio),top var(--mv) var(--eio)}\n.pop{position:fixed;width:var(--pu-pop);border-radius:12px;padding:10px 12px 8px;pointer-events:none;opacity:0;transform:translateY(6px) scale(.98);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.pop.show{opacity:1;transform:none;pointer-events:auto;transition:opacity var(--in) var(--eo),transform var(--mv) var(--eo)}\n.pop.show.glide{transition:opacity var(--in) var(--eo),transform var(--mv) var(--eo),left var(--mv) var(--eio),top var(--mv) var(--eio)}\n.mark{position:fixed;border:2px solid color-mix(in srgb,var(--pu-accent) 50%,transparent);background:var(--as);border-radius:8px;opacity:0;\ntransition:opacity .3s var(--eo)}\n.mark.show{opacity:1}\n.pulse{position:fixed;border:2px solid var(--pu-accent);border-radius:8px;background:var(--as);animation:pu-pulse var(--pl) var(--eio) forwards}\n@keyframes pu-pulse{0%{opacity:0;transform:scale(.985)}35%{opacity:.85;transform:scale(1)}100%{opacity:0;transform:scale(1.02)}}\n\n/* Document column. */\n.col{position:fixed;left:0;top:0;pointer-events:none;transition:opacity var(--in) var(--eo)}\n.th{position:absolute;left:0;right:0;top:0;padding:4px 4px 4px 12px;background:var(--su);border-radius:8px;pointer-events:auto;cursor:pointer;box-shadow:inset 2px 0 0 transparent;\ntransition:transform var(--mv) var(--eio),box-shadow var(--in) var(--eo),opacity var(--in) var(--eo)}\n.th.hot{box-shadow:inset 2px 0 0 var(--ln)}\n.th.on{box-shadow:inset 2px 0 0 var(--pu-accent);cursor:default}\n.th.dim{opacity:.45}\n.th.resolved:not(.on):not(.hot){opacity:.6}\n.th.lost .ctx{white-space:normal}\n.th.wait{opacity:0!important;pointer-events:none}\n.th.out{opacity:0!important;pointer-events:none;transition:opacity var(--out) var(--ei)}\n/* A closed thread's button has no box of its own: the thread shows its focus. */\n.th:has(.opn:focus-visible){box-shadow:inset 2px 0 0 var(--ln);outline:2px solid var(--pu-accent);outline-offset:2px;border-radius:4px}\n\n/* Selection bar. */\n.selbar{position:fixed;display:flex;border-radius:10px;padding:2px;opacity:0;transform:translateY(4px);pointer-events:none;\ntransition:opacity var(--in) var(--eo),transform .3s var(--eo)}\n.selbar.show{opacity:1;transform:none;pointer-events:auto}\n.selbar button{width:32px;height:30px;display:grid;place-items:center;border-radius:8px;color:var(--pu-accent);transition:background-color .2s var(--eo)}\n.selbar button:hover,.selbar button:focus-visible{background:var(--as);outline:none}\n\n/* Comment mode's outline: glides between blocks; solid accent once chosen. */\n.pick{position:fixed;left:0;top:0;border:2px solid color-mix(in srgb,var(--pu-accent) 70%,transparent);background:color-mix(in srgb,var(--pu-accent) 6%,transparent);\nborder-radius:8px;pointer-events:none;opacity:0;transition:opacity var(--out) var(--ei),border-color var(--out) var(--ei),border-width var(--out) var(--ei),box-shadow var(--out) var(--ei)}\n.pick.show{opacity:1;transition-duration:var(--in);transition-timing-function:var(--eo)}\n.pick.show.glide{transition-property:all;transition-duration:var(--mv);transition-timing-function:var(--eio)}\n.pick.on{border-color:var(--pu-accent)}\n/* The block cursor: its focus is drawn on the outline (3px accent with a surface halo, 3:1 on any page); the\nmarkers that hold focus are invisible. */\n.pick.kf{border:3px solid var(--pu-accent);box-shadow:0 0 0 2px var(--su)}\n.km{position:fixed;left:0;top:0;pointer-events:none;outline:none}\n.sr,.mn-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n.namebar{position:fixed;left:0;top:0;display:flex;align-items:center;gap:2px;padding:2px 2px 2px 10px;border-radius:10px;font-size:12px;color:var(--mu);\nwhite-space:nowrap;pointer-events:none;opacity:0;transform:translateY(4px);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.namebar.show{opacity:1;transform:none;pointer-events:auto;transition:opacity var(--in) var(--eo),transform .3s var(--eo)}\n.namebar.show.glide{transition-property:all;transition-duration:var(--mv);transition-timing-function:var(--eio)}\n.namebar .lbl{margin-right:6px;max-width:260px;overflow:hidden;text-overflow:ellipsis}\n.namebar .nb{padding:4px;display:grid;place-items:center;border-radius:7px;transition:background-color .2s var(--eo),color .2s var(--eo)}\n.namebar .nb:hover,.namebar .nb:focus-visible{background:var(--ho);color:var(--k);outline:none}\n.namebar .nb[hidden]{display:none}\n\n/* The comment control: one round button; the open count sits inside a comment bubble. Nothing about it\ngrows or slides: its layers and numbers cross-fade in place. */\n.launch{position:fixed;right:20px;bottom:20px;pointer-events:auto}\n.launch .mode{position:relative;display:grid;place-items:center;width:46px;height:46px;border-radius:50%;transition:background-color .3s var(--eo),color .3s var(--eo)}\n.mode>*,.cnt>*{grid-area:1/1}\n.mode>*{display:grid;place-items:center;transition:opacity var(--in) var(--eo)}\n.cnt,.has>.plus{opacity:0}\n.has>.cnt{opacity:1}\n.n{font-size:12px;font-weight:500;line-height:1;margin:-1.4px 0 0 1.4px;font-variant-numeric:tabular-nums;opacity:0;transition:opacity var(--in) var(--eo)}\n.n.s{font-size:9.5px;letter-spacing:-.04em}\n.n.on{opacity:1}\n.launch .mode:hover,.launch .mode[aria-expanded=true]{background:var(--ho)}\n.launch .mode.on{background:var(--pu-accent);color:var(--pu-on,#fff)}\n/* Open threads on other slides or views: a small dot at the button's top right, easing in and out. */\n.mode>.dot{position:absolute;top:3px;right:3px;width:9px;height:9px;border-radius:50%;background:var(--pu-accent);border:2px solid var(--su);opacity:0}\n.mode.else>.dot{opacity:1}\n/* The tooltip eases in after a moment, above the button, and never moves it. */\n.ttip{position:absolute;right:0;bottom:54px;white-space:nowrap;border-radius:8px;padding:4px 9px;font-size:12px;pointer-events:none;opacity:0;transform:translateY(3px);transition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.ttip small{margin-left:8px}\n.ttip small,.mi .kc{font-size:12px;color:var(--fa)}\n.mode:hover+.ttip,.mode:focus-visible+.ttip{opacity:1;transform:none;transition:opacity var(--in) var(--eo) .5s,transform var(--in) var(--eo) .5s}\n.launch .mode[aria-expanded=true]+.ttip{opacity:0;transition:opacity var(--out) var(--ei)}\n@media (hover:none){.ttip,.tt{display:none}}\n.menu{position:fixed;right:20px;bottom:76px;width:290px;border-radius:12px;padding:4px;pointer-events:none;opacity:0;transform:translateY(6px);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.menu.show{opacity:1;transform:none;pointer-events:auto;transition:opacity var(--in) var(--eo),transform var(--mv) var(--eo)}\n/* Menu rows: one line each; the explanation is a tooltip beside the menu that eases in after a moment. */\n.mi{position:relative;display:flex;gap:10px;align-items:center;width:100%;min-height:34px;text-align:left;padding:6px 10px;border-radius:8px;transition:background-color .2s var(--eo)}\n.mi:hover,.mi:focus-visible{background:var(--so);outline:none}\n.mi svg{color:var(--mu);flex:none}\n.mi small{display:block;color:var(--fa);font-size:12px}\n.lb{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.ma{flex:none;display:grid;margin:-2px 0}\n.ma .av{width:20px;height:20px;font-size:11px}\n.mi .av svg{color:inherit}\n.sep{height:1px;margin:4px 10px;background:var(--ru)}\n.tt{position:absolute;right:calc(100% + 14px);top:50%;translate:0 -50%;width:max-content;max-width:220px;padding:4px 9px;border-radius:8px;font-size:12px;line-height:1.4;\ncolor:var(--mu);pointer-events:none;opacity:0;transform:translateX(3px);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.mi:hover>.tt,.mi:focus-visible>.tt{opacity:1;transform:none;transition:opacity var(--in) var(--eo) .5s,transform var(--in) var(--eo) .5s}\n@media (max-width:600px){.tt{right:8px;top:auto;bottom:100%;translate:none;transform:translateY(3px)}}\n/* Switches: a track and a knob that slides (cross-fades with reduced motion). */\n.sw{position:relative;flex:none;width:26px;height:16px;border-radius:8px;background:var(--ln);transition:background-color var(--mv) var(--eio)}\n.sw::before,.sw::after{content:\"\";position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);\ntransition:transform var(--mv) var(--eio),opacity var(--mv) var(--eio)}\n.sw::before{opacity:0;transform:translateX(10px)}\n[aria-checked=true]>.sw{background:var(--pu-accent)}\n[aria-checked=true]>.sw::after{transform:translateX(10px)}\n.tools{display:flex;flex:none;gap:2px}\n.tools[hidden]{display:none}\n.tool[aria-pressed=true]{background:var(--as);color:var(--pu-accent)}\n.note{display:block;padding:0 0 4px;font-size:12px;color:var(--fa)}\n.note[hidden]{display:none}\n.ov{position:absolute;inset:0;pointer-events:none;overflow:hidden}\n/* An add-on's panel (.xp) is the same full-height panel as All comments (.all), with its own body. */\n.xb{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:4px 16px 16px;font-size:13px}\n.xb p{margin:0 0 10px}\n/* All comments: a full-height panel on the right that slides in (fades, with reduced motion). */\n.all,.xp{position:fixed;top:0;right:0;bottom:0;width:var(--pu-panel);display:flex;flex-direction:column;border-width:0 0 0 1px;opacity:0;transform:translateX(100%);\ntransition:transform var(--out) var(--ei),opacity var(--out) var(--ei)}\n.all.show,.xp.show{opacity:1;transform:none;pointer-events:auto;transition:transform var(--mv) var(--eo),opacity var(--in) var(--eo)}\n.all.full{width:100%}\n.hd{display:flex;align-items:center;gap:8px;padding:12px 10px 8px 16px;font-weight:600}\n.pn{font-weight:400;color:var(--fa)}\n.hs{margin-left:auto;display:flex;align-items:center;gap:6px;padding:3px 4px 3px 6px;border-radius:6px;font-size:12px;font-weight:400;color:var(--mu);\ntransition:background-color .2s var(--eo)}\n.hs:hover,.hs:focus-visible{background:var(--ho);outline:none}\n.list{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:4px}\n.all .mi{align-items:flex-start}\n.all .mi>.av{flex:none}\n.all .mi>span:last-child{flex:1;min-width:0}\n.all .mi small{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.all .mi.done{opacity:.6}\n.all .mi.open{background:var(--so)}\n.all .mi.open>.av,.all .mi.open .clamp{display:none}\n.xr{padding:2px 12px 10px 16px}\n/* The line from an open thread in the panel to its place on the page. */\n.cx{position:fixed;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;opacity:0;transition:opacity var(--in) var(--eo)}\n.cx.show{opacity:1}\n.cx path{fill:none;stroke:var(--pu-accent);stroke-width:1.5;stroke-linecap:round;opacity:.7}\n.cx circle{fill:var(--pu-accent)}\n.layer.listing .col{opacity:0;transition:opacity var(--out) var(--ei)}\n.sec{padding:8px 10px 2px;font-size:12px;color:var(--fa)}\n.ag{display:flex;align-items:center;gap:8px;padding:6px 14px;font-size:12px;color:var(--fa);border-bottom:1px solid var(--ln)}\n.ag[hidden]{display:none}\n.lns{display:flex;flex-direction:column}\n.ln{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--in) var(--eo),opacity var(--in) var(--eo)}\n.ln.show{grid-template-rows:1fr;opacity:1}\n.ln>.lw{overflow:hidden;min-height:0}\n.ag button{margin-left:auto;flex:none;padding:0 6px;border-radius:6px;color:var(--fa);transition:color .2s var(--eo),background-color .2s var(--eo)}.ag button:hover:not(:disabled),.ag button:focus-visible{color:var(--pu-accent);background:var(--as);outline:none}.ag button:disabled{opacity:.5;cursor:default}\n.adr{margin:8px 0 0 14px;padding:8px 10px;border-radius:8px;background:var(--so);font-size:13px;color:var(--k);animation:pu-in var(--mv) var(--eo) both}\n.adr small{display:block;font-size:12px;color:var(--fa)}\n.adr .go{display:flex;gap:6px;margin-top:6px}\n.adr .go button{padding:2px 8px;border-radius:6px;font-size:12px;color:var(--mu);transition:color .2s var(--eo),background-color .2s var(--eo)}.adr .go button:hover,.adr .go button:focus-visible{color:var(--pu-accent);background:var(--as);outline:none}\n@keyframes pu-in{0%{opacity:0;transform:translateY(3px)}100%{opacity:1;transform:none}}\n.sec b{margin-left:6px;font-weight:500;color:var(--pu-accent)}\n.toast{position:fixed;left:50%;bottom:28px;border-radius:10px;padding:8px 14px;font-size:13px;opacity:0;transform:translate(-50%,6px);\ntransition:opacity .3s var(--eo),transform .36s var(--eo)}\n.toast.show{opacity:1;transform:translate(-50%,0)}\n\n/* Touch: fingers need bigger targets than pointers (44 px for the menu's rows, 36 and more for buttons). */\n@media (pointer:coarse){\n.mi{min-height:44px}\n.ib{min-width:36px;min-height:36px}\n.rxo{min-width:40px;min-height:40px}\n.refs .ref{min-height:34px}\n.mnl li{min-height:40px}\n.send{min-width:36px;min-height:36px}\n}\n\n@media (forced-colors: active){\n.pick.kf{border:3px solid Highlight}\n.layer :is(.ib,.mi,.nb,.hs,.selbar button,.say button,.xb button):focus-visible{outline:2px solid Highlight}\n}\n\n@media (prefers-reduced-motion: reduce){\n.ln{transition-property:opacity}\n@keyframes pu-in{0%{opacity:0}100%{opacity:1}}\n.bub,.bub.in,.bub.in:hover,.bub.on,.tip,.pop,.selbar,.menu,.all,.xp,.ttip,.tt,.toast,.ref .rc,.rxp,.mnl{transform:none!important}\n.dlg{transform:translate(-50%,0)!important}\n.sw::after{transform:none!important;transition-property:opacity}\n[aria-checked=true]>.sw::after{opacity:0}\n[aria-checked=true]>.sw::before{opacity:1}\n.th{transition-property:opacity,box-shadow}\n.tip.show{transition-property:opacity}\n.pick,.pick.show{transition:opacity .16s ease-in-out}\n.all,.all.show,.xp,.xp.show{transition-property:opacity}\n.namebar,.namebar.show{transform:none!important;transition:opacity .16s ease-in-out}\n.av,.nf{transform:none!important}\n@keyframes pu-pulse{0%{opacity:0}35%{opacity:.85}100%{opacity:0}}\n}\n";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pipeup",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0-beta.1",
|
|
4
4
|
"description": "Comments and feedback right on any HTML page: documents, slide decks and whole sites.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"comments",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"files": [
|
|
44
44
|
"dist/*.js",
|
|
45
|
+
"dist/addons.json",
|
|
45
46
|
"dist/types",
|
|
46
47
|
"cli",
|
|
47
48
|
"skills",
|
|
@@ -5,7 +5,7 @@ description: Use when someone asks you to add comments to an HTML page, make it
|
|
|
5
5
|
|
|
6
6
|
# Add Pipeup to this page
|
|
7
7
|
|
|
8
|
-
Written for Pipeup 0.
|
|
8
|
+
Written for Pipeup 0.8.0-beta.1 This skill is published at https://pipeup-ai.github.io/pipeup/skills/pipeup-add/SKILL.md. Its companions: [integrate](https://pipeup-ai.github.io/pipeup/skills/pipeup-integrate/SKILL.md) (the full reference: layouts, decks, tabs, every option), [apply](https://pipeup-ai.github.io/pipeup/skills/pipeup-apply/SKILL.md) (answering the comments) and [summarise](https://pipeup-ai.github.io/pipeup/skills/pipeup-summarise/SKILL.md).
|
|
9
9
|
|
|
10
10
|
Pipeup lets people comment on an HTML page in place. **When the page already exists, never change its layout, styling or behaviour to make room for Pipeup**: it draws in its own layer, and you only add attributes and one script tag. Edit the HTML file only; don't download, fetch or run anything yourself.
|
|
11
11
|
|
|
@@ -14,7 +14,7 @@ Pipeup lets people comment on an HTML page in place. **When the page already exi
|
|
|
14
14
|
1. **Pin the script.** Just before `</body>`:
|
|
15
15
|
|
|
16
16
|
```html
|
|
17
|
-
<script src="https://cdn.jsdelivr.net/npm/pipeup@0.
|
|
17
|
+
<script src="https://cdn.jsdelivr.net/npm/pipeup@0.8.0-beta.1/dist/pipeup.min.js"
|
|
18
18
|
integrity="sha384-…" crossorigin="anonymous"></script>
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -30,7 +30,7 @@ Pipeup lets people comment on an HTML page in place. **When the page already exi
|
|
|
30
30
|
4. **Add-ons: none unless the author asks.** Pipeup itself sends nothing anywhere. If they want sharing, voice, live
|
|
31
31
|
comments, the assistant, the full emoji set for reactions (`@pipeup/emoji`), notes for mentioned people (`@pipeup/inbox`,
|
|
32
32
|
which needs an inbox service address the author gives you), GitHub issues for mentions (`@pipeup/github`, which needs
|
|
33
|
-
`data-pipeup-github-repo`)
|
|
33
|
+
`data-pipeup-github-repo`), update notices (`@pipeup/updates`) or recovery codes so reviewers can move their identity (`@pipeup/identity`), ask first, say in plain words what it sends and to whom, and pin it like the core script.
|
|
34
34
|
Then list its id in `data-pipeup-addons` on `<html>` (append, never remove an entry) so only chosen add-ons run, and
|
|
35
35
|
tell the author about a Content-Security-Policy that allows scripts only from the page and the CDN. Don't apply the
|
|
36
36
|
policy yourself: a strict one can break a page.
|
|
@@ -5,7 +5,7 @@ description: Use when someone asks you to act on Pipeup feedback for an HTML pag
|
|
|
5
5
|
|
|
6
6
|
# Apply Pipeup feedback
|
|
7
7
|
|
|
8
|
-
Written for Pipeup 0.
|
|
8
|
+
Written for Pipeup 0.8.0-beta.1 This skill is published at https://pipeup-ai.github.io/pipeup/skills/pipeup-apply/SKILL.md. Its companions: [integrate](https://pipeup-ai.github.io/pipeup/skills/pipeup-integrate/SKILL.md), [summarise](https://pipeup-ai.github.io/pipeup/skills/pipeup-summarise/SKILL.md).
|
|
9
9
|
|
|
10
10
|
## 1. Read the comments
|
|
11
11
|
|
|
@@ -5,7 +5,7 @@ description: Use when creating or editing an HTML document, slide deck, report,
|
|
|
5
5
|
|
|
6
6
|
# Add Pipeup to a page: the full reference
|
|
7
7
|
|
|
8
|
-
Written for Pipeup 0.
|
|
8
|
+
Written for Pipeup 0.8.0-beta.1 For a quick "add comments to this page", [pipeup-add](https://pipeup-ai.github.io/pipeup/skills/pipeup-add/SKILL.md) is the short version; this is the full reference. This skill is published at https://pipeup-ai.github.io/pipeup/skills/pipeup-integrate/SKILL.md. Its companions: [summarise](https://pipeup-ai.github.io/pipeup/skills/pipeup-summarise/SKILL.md), [apply](https://pipeup-ai.github.io/pipeup/skills/pipeup-apply/SKILL.md).
|
|
9
9
|
|
|
10
10
|
Pipeup lets people comment on an HTML page in place: select text, click any element (including
|
|
11
11
|
buttons and charts) or drop a pin on a slide. Your job is to make the page *reviewable* while it
|
|
@@ -75,7 +75,7 @@ Then choose the options (see "Options" below): usually just the defaults.
|
|
|
75
75
|
- Just before `</body>`, add the script pinned to an exact version:
|
|
76
76
|
|
|
77
77
|
```html
|
|
78
|
-
<script src="https://cdn.jsdelivr.net/npm/pipeup@0.
|
|
78
|
+
<script src="https://cdn.jsdelivr.net/npm/pipeup@0.8.0-beta.1/dist/pipeup.min.js"
|
|
79
79
|
integrity="sha384-…" crossorigin="anonymous"></script>
|
|
80
80
|
```
|
|
81
81
|
|
|
@@ -157,7 +157,7 @@ Then choose the options (see "Options" below): usually just the defaults.
|
|
|
157
157
|
- Don't wrap content in new elements or add classes for Pipeup.
|
|
158
158
|
- Don't add inline styles, z-index changes or padding "for the comment column".
|
|
159
159
|
- Don't load the script from anywhere but the pinned CDN URL
|
|
160
|
-
(`https://cdn.jsdelivr.net/npm/pipeup@0.
|
|
160
|
+
(`https://cdn.jsdelivr.net/npm/pipeup@0.8.0-beta.1/dist/pipeup.min.js`, with the `integrity` value from
|
|
161
161
|
the release notes) or a copy of that same file next to the page. Never use an unpinned URL.
|
|
162
162
|
- Don't put secrets in `data-pipeup-doc`; it *is* the document's key — anyone with the file can
|
|
163
163
|
read its feedback, which is the intended audience.
|
|
@@ -175,7 +175,7 @@ page opened from disk and in any script order, and they are released with Pipeup
|
|
|
175
175
|
|
|
176
176
|
- **Ask first, and say in plain words what it sends and to whom** (the line above, and the add-on's README). Never
|
|
177
177
|
pick a sharing service yourself: the author chooses one.
|
|
178
|
-
- Add it as one more `<script>` after Pipeup's, pinned the same way (`https://cdn.jsdelivr.net/npm/@pipeup/share@0.
|
|
178
|
+
- Add it as one more `<script>` after Pipeup's, pinned the same way (`https://cdn.jsdelivr.net/npm/@pipeup/share@0.8.0-beta.1/dist/share.min.js`
|
|
179
179
|
with its `integrity` from the release notes), or use the combined file `pipeup+share.min.js` instead of Pipeup's.
|
|
180
180
|
- Sharing is set up by the author with the command line (`npx @pipeup/share create page.html --server …`), which writes
|
|
181
181
|
`data-pipeup-share` into the file and prints a stop key once. **Never write `data-pipeup-share` yourself and never
|
|
@@ -5,7 +5,7 @@ description: Use when someone wants Pipeup reviews saved as Markdown files in th
|
|
|
5
5
|
|
|
6
6
|
# Set up "Save to GitHub" or "Send to Git"
|
|
7
7
|
|
|
8
|
-
Written for Pipeup 0.
|
|
8
|
+
Written for Pipeup 0.8.0-beta.1 This skill is published at https://pipeup-ai.github.io/pipeup/skills/pipeup-send-to-git-setup/SKILL.md.
|
|
9
9
|
|
|
10
10
|
Two example add-ons (written the way a company writes its own; **not** from the Pipeup project) get a review into Git as a
|
|
11
11
|
Markdown file, the same Markdown that Copy as Markdown makes (each comment says where it is, ready for an AI to act on):
|
|
@@ -5,7 +5,7 @@ description: Use when someone has Pipeup feedback on an HTML page — text a rev
|
|
|
5
5
|
|
|
6
6
|
# Summarise Pipeup feedback
|
|
7
7
|
|
|
8
|
-
Written for Pipeup 0.
|
|
8
|
+
Written for Pipeup 0.8.0-beta.1 This skill is published at https://pipeup-ai.github.io/pipeup/skills/pipeup-summarise/SKILL.md. Its companions: [integrate](https://pipeup-ai.github.io/pipeup/skills/pipeup-integrate/SKILL.md), [apply](https://pipeup-ai.github.io/pipeup/skills/pipeup-apply/SKILL.md).
|
|
9
9
|
|
|
10
10
|
## 1. Get the feedback as text
|
|
11
11
|
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { Identity } from "./identity";
|
|
2
|
-
/** A new identity the reviewer can back up, and its recovery code. */
|
|
3
|
-
export declare function makePortable(): Promise<{
|
|
4
|
-
identity: Identity;
|
|
5
|
-
code: string;
|
|
6
|
-
}>;
|
|
7
|
-
/** The recovery code of an identity that was made portable; null for an ordinary one, which can't be exported. */
|
|
8
|
-
export declare function codeOf(identity: Identity): Promise<string | null>;
|
|
9
|
-
export type CodeProblem = "shape" | "mistake";
|
|
10
|
-
/** The identity a recovery code stands for, or what is wrong with the code, in a word the UI turns into a sentence. */
|
|
11
|
-
export declare function identityFromCode(text: string): Promise<{
|
|
12
|
-
identity: Identity;
|
|
13
|
-
} | {
|
|
14
|
-
problem: CodeProblem;
|
|
15
|
-
}>;
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { CodeProblem } from "../crypto/portable";
|
|
2
|
-
export interface IdentityDeps {
|
|
3
|
-
/** This identity was made portable: it has a recovery code. */
|
|
4
|
-
portable: boolean;
|
|
5
|
-
/** The recovery code of a portable identity. */
|
|
6
|
-
code(): Promise<string | null>;
|
|
7
|
-
/** Makes a new portable identity, keeps it, and returns its recovery code. */
|
|
8
|
-
make(): Promise<string>;
|
|
9
|
-
/** Keeps the identity a code stands for, or says what is wrong with the code. */
|
|
10
|
-
use(code: string): Promise<CodeProblem | null>;
|
|
11
|
-
copy(text: string): Promise<void>;
|
|
12
|
-
/** Starts over with the identity now kept (the page reloads). */
|
|
13
|
-
reload(): void;
|
|
14
|
-
/** Whether the comments on this page were written by the current identity (so a change is felt). */
|
|
15
|
-
hasComments: boolean;
|
|
16
|
-
/** The way to reach this reviewer they have shared ("" when none), and how to share or stop sharing one. */
|
|
17
|
-
contact: {
|
|
18
|
-
value: string;
|
|
19
|
-
share(value: string): Promise<boolean>;
|
|
20
|
-
stop(): Promise<void>;
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* A small dialog over the page for what a reviewer can do with their identity: make it portable or back it up (see the
|
|
25
|
-
* code, copy it, save it as a file), or use one they backed up. Plain words say what each does.
|
|
26
|
-
*/
|
|
27
|
-
export declare function openIdentity(layer: HTMLElement, deps: IdentityDeps): void;
|