pipeup 0.8.0-beta.2 → 0.8.0-beta.3
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 +5 -2
- package/dist/pipeup.core.js +1 -1
- package/dist/pipeup.esm.js +1 -1
- package/dist/pipeup.min.js +1 -1
- package/dist/types/anchor/locate.d.ts +11 -2
- package/dist/types/core.d.ts +1 -1
- package/dist/types/ui/column.d.ts +2 -0
- package/dist/types/ui/comment-mode.d.ts +7 -3
- package/dist/types/ui/composer.d.ts +5 -2
- package/dist/types/ui/context.d.ts +11 -1
- package/dist/types/ui/draft-view.d.ts +4 -1
- package/dist/types/ui/geometry.d.ts +2 -0
- package/dist/types/ui/here.d.ts +9 -3
- package/dist/types/ui/highlights.d.ts +8 -4
- package/dist/types/ui/host.d.ts +3 -1
- package/dist/types/ui/icons.d.ts +2 -1
- package/dist/types/ui/layout.d.ts +19 -4
- package/dist/types/ui/pick.d.ts +5 -0
- package/dist/types/ui/styles.d.ts +1 -1
- package/dist/types/ui/thread-view.d.ts +5 -1
- package/package.json +1 -1
- package/skills/pipeup-add/SKILL.md +2 -2
- 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
|
@@ -4,13 +4,22 @@ export interface Location {
|
|
|
4
4
|
/** "Slide 3 "Title" › Q4 bar", "Section "Pricing" › Link · Start free trial", or why it's missing. */
|
|
5
5
|
where: string;
|
|
6
6
|
element: string | null;
|
|
7
|
+
/** The data-pipeup-id of the element, or of the marked element it is in (`within`). */
|
|
7
8
|
id: string | null;
|
|
9
|
+
/** `id` names a marked element around this one (a slide, say), not this one. */
|
|
10
|
+
within?: boolean;
|
|
8
11
|
quote: string | null;
|
|
9
12
|
pin: string | null;
|
|
10
13
|
}
|
|
11
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* What kind of block `el` is ("Paragraph", "Checkbox", "Switch"), or the author's own name for it. With no kind and
|
|
16
|
+
* no words, a long thin shape is a "Bar" (a chart's, say) and any other a "Shape"; else it is a "Block".
|
|
17
|
+
*/
|
|
12
18
|
export declare function kindOf(el: Element): string;
|
|
13
|
-
/**
|
|
19
|
+
/**
|
|
20
|
+
* Its own words, cut short: its accessible name where it has one (a field's label, a dropdown's chosen option), else
|
|
21
|
+
* what it shows ("Offline first Everything…"), the same whether or not the page is showing it.
|
|
22
|
+
*/
|
|
14
23
|
export declare function wordsOf(el: Element): string;
|
|
15
24
|
/** "Paragraph · We will launch…": its kind and its own words, or the author's own name for it. */
|
|
16
25
|
export declare function labelOf(el: Element): string;
|
package/dist/types/core.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const VERSION = "0.8.0-beta.
|
|
1
|
+
export declare const VERSION = "0.8.0-beta.3";
|
|
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-15";
|
|
4
4
|
export { PipeupDocument, UnsavedChangeError, type Listener, type OpenOptions } from "./document";
|
|
@@ -11,5 +11,7 @@ export declare function columnSpot(root: Element, showing?: boolean): {
|
|
|
11
11
|
} | null;
|
|
12
12
|
/** The thread's content is gone (not just waiting for its fuzzy match). */
|
|
13
13
|
export declare function lost(ctx: Ctx, t: Thread): boolean;
|
|
14
|
+
/** The thread's content was found changed, or nearby: it is flagged Moved, for someone to confirm. */
|
|
15
|
+
export declare const moved: (ctx: Ctx, t: Thread) => boolean;
|
|
14
16
|
/** Threads beside the document, level with what they're about; the open one aligns exactly. */
|
|
15
17
|
export declare function createColumn(ctx: Ctx): View;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type { Ctx, View } from "./context";
|
|
1
|
+
import type { Ctx, Draft, View } from "./context";
|
|
2
2
|
/** Page controls Enter or Space would activate. */
|
|
3
3
|
export declare const ACTIVATES = "a,button,summary,[role=button],[role=link],[role=switch],[role=tab],[role=checkbox],input[type=checkbox],input[type=radio],input[type=submit],input[type=button],input[type=reset]";
|
|
4
4
|
/** The keyboard's hint: shown as a toast, and read with the block cursor's first landing. */
|
|
5
|
-
export declare const KEYS_HINT = "Tab moves between blocks \u00B7 \u2191 \u2193 change level \u00B7 Enter comments \u00B7 Esc to finish \u00B7 F7 selects text";
|
|
5
|
+
export declare const KEYS_HINT = "Tab moves between blocks \u00B7 \u2191 \u2193 change level \u00B7 Enter comments \u00B7 Hold Space to use the page \u00B7 Esc to finish \u00B7 F7 selects text";
|
|
6
6
|
/** Comment mode's view. */
|
|
7
7
|
export interface CommentMode extends View {
|
|
8
8
|
/** Escape's step: clears a chosen block; false when there was none (comment mode ends next). */
|
|
@@ -15,6 +15,10 @@ export interface CommentMode extends View {
|
|
|
15
15
|
resume(): boolean;
|
|
16
16
|
/** Focuses the block cursor on its block again, as a move, so its name is read afresh. */
|
|
17
17
|
refocus(): void;
|
|
18
|
+
/** Back to the open draft's block: it is outlined and named again, and the cursor (when out) is on it. */
|
|
19
|
+
toDraft(): void;
|
|
20
|
+
/** A draft brought back (Undo) belongs to its block again. */
|
|
21
|
+
adopt(d: Draft): void;
|
|
18
22
|
}
|
|
19
23
|
/**
|
|
20
24
|
* Comment mode: the page goes quiet, an outline glides to the obvious block under the pointer, and a click
|
|
@@ -22,6 +26,6 @@ export interface CommentMode extends View {
|
|
|
22
26
|
* handlers never run while Pipeup's other window listeners (selection, the menu) still do, whatever their order.
|
|
23
27
|
*
|
|
24
28
|
* Known limits: the page's CSS `:hover` still applies; page listeners on window in the capture phase that were
|
|
25
|
-
* added before comment mode started still hear events
|
|
29
|
+
* added before comment mode started still hear events.
|
|
26
30
|
*/
|
|
27
31
|
export declare function createCommentMode(ctx: Ctx): CommentMode;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type Person } from "./mentions";
|
|
2
2
|
import type { Mention } from "../model/types";
|
|
3
3
|
export interface ComposerOptions {
|
|
4
|
-
/** The
|
|
4
|
+
/** The send button's word ("Comment", "Reply", "Save"), and the line's name for screen readers unless `name`. */
|
|
5
5
|
label: string;
|
|
6
|
+
/** The line's name for screen readers, when it isn't the button's word ("Edit comment"). */
|
|
7
|
+
name?: string;
|
|
6
8
|
/** What the empty line says ("Comment or add others with @"). */
|
|
7
9
|
placeholder?: string;
|
|
8
10
|
/** Words already in the line (editing a comment). */
|
|
@@ -12,7 +14,8 @@ export interface ComposerOptions {
|
|
|
12
14
|
thread?: () => string;
|
|
13
15
|
/** `mentions`: the people named in the words, found after trimming. */
|
|
14
16
|
onSend(text: string, mentions: Mention[]): Promise<void> | void;
|
|
15
|
-
|
|
17
|
+
/** Cancel or Esc: `words` are what was thrown away ("" when the line was empty). */
|
|
18
|
+
onCancel?(words: string): void;
|
|
16
19
|
/** Who can be mentioned with `@`; without it, `@` is just a character. */
|
|
17
20
|
people?(): Person[];
|
|
18
21
|
}
|
|
@@ -15,6 +15,8 @@ export interface Draft {
|
|
|
15
15
|
ranges: Range[];
|
|
16
16
|
/** Where the draft's content is: its range for text, its element for blocks and pins. */
|
|
17
17
|
resolved: Resolved;
|
|
18
|
+
/** It has been sent and is becoming its thread: the column keeps the new thread for its place. */
|
|
19
|
+
sending?: boolean;
|
|
18
20
|
}
|
|
19
21
|
export interface UiState {
|
|
20
22
|
active: string | null;
|
|
@@ -38,6 +40,8 @@ export interface UiState {
|
|
|
38
40
|
reading: boolean;
|
|
39
41
|
/** The comment control's menu is open: in comment mode a click outside it only closes it. */
|
|
40
42
|
menu: boolean;
|
|
43
|
+
/** Pin was tapped on a touch screen: the next tap on the page is where the pin goes, even on a highlight. */
|
|
44
|
+
pinning: boolean;
|
|
41
45
|
}
|
|
42
46
|
/** Something that draws: rebuilt on render, repositioned every frame. */
|
|
43
47
|
export interface View {
|
|
@@ -107,13 +111,19 @@ export interface Ctx {
|
|
|
107
111
|
/** Runs `fn`, then puts focus and the caret back in the open draft as they were. */
|
|
108
112
|
keepCaret(fn: () => void): void;
|
|
109
113
|
/** Goes back to the open draft: to its slide or view if that has gone, then focus and the caret into it. */
|
|
114
|
+
focusDraft(): void;
|
|
115
|
+
/**
|
|
116
|
+
* The open draft has words and something else was asked for: back to it (its block outlined and named again), and
|
|
117
|
+
* the reviewer is told to finish or cancel it first.
|
|
118
|
+
*/
|
|
110
119
|
backToDraft(): void;
|
|
111
120
|
postDraft(text: string, mentions?: Mention[]): Promise<void>;
|
|
112
121
|
/** This reviewer has read the comments in `t` that name them: marks them seen, so every device knows. */
|
|
113
122
|
seen(t: Thread): void;
|
|
114
123
|
/** Who can be mentioned with `@`: people in this document, agents the page lists, and people supplied. */
|
|
115
124
|
people(): Person[];
|
|
116
|
-
|
|
125
|
+
/** Closes the open draft; `words` thrown away with it are offered back (Undo) for a few seconds. */
|
|
126
|
+
cancelDraft(words?: string): void;
|
|
117
127
|
/** Turns comment mode on or off. `keys`: from the keyboard (the block cursor starts). */
|
|
118
128
|
setCommenting(on: boolean, keys?: boolean): void;
|
|
119
129
|
/** What a click on the page does: cancels an empty draft (back to one with words), else closes the open thread. */
|
|
@@ -11,7 +11,8 @@ export interface DraftOptions {
|
|
|
11
11
|
/** Saves a new name (the same path as the menu's Your name). */
|
|
12
12
|
rename(name: string): Promise<void>;
|
|
13
13
|
onSend(text: string, mentions: Mention[]): Promise<void>;
|
|
14
|
-
|
|
14
|
+
/** `words`: what Cancel or Esc threw away ("" for an empty box). */
|
|
15
|
+
onCancel(words: string): void;
|
|
15
16
|
/** Who can be mentioned with `@`. */
|
|
16
17
|
people?(): Person[];
|
|
17
18
|
}
|
|
@@ -24,6 +25,8 @@ export interface DraftBox {
|
|
|
24
25
|
/** Remembers the caret; the returned function focuses the box and puts it back. */
|
|
25
26
|
caret(): () => void;
|
|
26
27
|
isEmpty(): boolean;
|
|
28
|
+
/** Puts words back in the box (Undo), with the caret after them. */
|
|
29
|
+
fill(words: string): void;
|
|
27
30
|
}
|
|
28
31
|
/**
|
|
29
32
|
* The box for a new comment, as a card: who is writing, what it's on, then the writing box. Nobody has to give a
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { Resolved } from "../anchor/resolve";
|
|
2
2
|
import type { Anchor } from "../model/types";
|
|
3
3
|
import type { AnchorPoint } from "./layout";
|
|
4
|
+
/** Page controls a click works: a bubble on one sits just outside it, so all of it stays the page's. */
|
|
5
|
+
export declare const INTERACTIVE = "a,button,input,select,textarea,label,summary,[role=button],[contenteditable]";
|
|
4
6
|
/** Where an element or pin comment's bubble sits (viewport coordinates). Text comments have no bubble. */
|
|
5
7
|
export declare function bubblePoint(a: Anchor, r: Resolved): {
|
|
6
8
|
x: number;
|
package/dist/types/ui/here.d.ts
CHANGED
|
@@ -50,10 +50,16 @@ export declare function setSlideHook(h: SlideHook | null): void;
|
|
|
50
50
|
/** The marked slide showing most: the most of the window covered, then the more opaque; still tied, `was` stays. */
|
|
51
51
|
export declare function pickSlide(slides: readonly Element[], look: SlideLook, was: Element | null): Element | null;
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
53
|
+
* The marked slides showing above or below `best` on a deck that scrolls: shown, partly in the window, and clear of it
|
|
54
|
+
* (a deck that stacks its slides in one place never has any).
|
|
55
55
|
*/
|
|
56
|
-
export declare function
|
|
56
|
+
export declare function besides(slides: readonly Element[], look: SlideLook, best: Element | null): Element[];
|
|
57
|
+
/**
|
|
58
|
+
* On a deck, a thread is here when it is on this slide, on another one showing (`also`, on a deck that scrolls), or
|
|
59
|
+
* on none; on other pages, when every key of its saved view but `label` matches the page's state (always, until the
|
|
60
|
+
* page reports one).
|
|
61
|
+
*/
|
|
62
|
+
export declare function isHere(saved: ViewState | undefined, slide: string | null, state: ViewState | null, also?: readonly string[]): boolean;
|
|
57
63
|
export declare function pageSlideLook(): SlideLook;
|
|
58
64
|
/**
|
|
59
65
|
* Follows here: the deck's hook, else reveal.js, else the marked slide that is showing; plus the page's
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether the words a range starts in are lighter than what is behind them (the first opaque background up from them,
|
|
3
|
+
* or the page's canvas). Over a picture, the words' own lightness decides.
|
|
4
|
+
*/
|
|
5
|
+
export declare function lightWords(r: Range): boolean;
|
|
1
6
|
export declare function highlightsSupported(): boolean;
|
|
2
7
|
export interface PageSheet {
|
|
3
8
|
/** Shows the picking cursor over the page while comment mode is on. */
|
|
@@ -6,8 +11,6 @@ export interface PageSheet {
|
|
|
6
11
|
gutter(px: number | null): void;
|
|
7
12
|
/** How strongly highlights are painted, 0 to 1. */
|
|
8
13
|
fade(k: number): void;
|
|
9
|
-
/** Paints the highlights for a dark page (true) or a light one. */
|
|
10
|
-
dark(on: boolean): void;
|
|
11
14
|
/**
|
|
12
15
|
* Makes room for the All comments panel: a right margin of `px` on the page, easing in and out unless
|
|
13
16
|
* `still`; 0 takes it away (the page eases back, then the rule goes). The width is also published as
|
|
@@ -22,10 +25,11 @@ export interface PageSheet {
|
|
|
22
25
|
* the page) and, on pages that ask for it, the gutter width. They live in a constructed stylesheet
|
|
23
26
|
* adopted by the document — no <style> element is added and no inline style is written.
|
|
24
27
|
*/
|
|
25
|
-
export declare function installPageSheet(doc?: Document
|
|
28
|
+
export declare function installPageSheet(doc?: Document): PageSheet;
|
|
29
|
+
/** Paints each group of ranges; `light` says which are light words on a dark ground. */
|
|
26
30
|
export declare function paintHighlights(g: {
|
|
27
31
|
quote: Range[];
|
|
28
32
|
on: Range[];
|
|
29
33
|
done: Range[];
|
|
30
|
-
}): void;
|
|
34
|
+
}, light: (r: Range) => boolean): void;
|
|
31
35
|
export declare function clearHighlights(): void;
|
package/dist/types/ui/host.d.ts
CHANGED
|
@@ -7,6 +7,8 @@ export interface Host {
|
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* Pipeup's only element in the page: a fixed, click-through <pipeup-root> under <html> with an open shadow
|
|
10
|
-
* root (open so tools like `pipeup check` can measure it). It never changes the page's layout.
|
|
10
|
+
* root (open so tools like `pipeup check` can measure it). It never changes the page's layout. It has the highest
|
|
11
|
+
* z-index there is and comes after <body>, so a page's own bar at that z-index (a consent banner, say) still sits under
|
|
12
|
+
* it: of two equals, the later one is drawn on top.
|
|
11
13
|
*/
|
|
12
14
|
export declare function createHost(theme: Theme, styles: string, doc?: Document): Host;
|
package/dist/types/ui/icons.d.ts
CHANGED
|
@@ -6,11 +6,12 @@ declare const PATHS: {
|
|
|
6
6
|
readonly lines: readonly ["M4 7h16M4 12h10M4 17h7"];
|
|
7
7
|
readonly list: readonly ["M3 6.5a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0M3 12a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0M3 17.5a1.5 1.5 0 1 0 3 0a1.5 1.5 0 1 0-3 0M9 6.5h11M9 12h11M9 17.5h7"];
|
|
8
8
|
readonly expand: readonly ["M5.5 10h7a1.5 1.5 0 0 1 1.5 1.5v7a1.5 1.5 0 0 1-1.5 1.5h-7A1.5 1.5 0 0 1 4 18.5v-7A1.5 1.5 0 0 1 5.5 10z", "M14 10l6-6M15 4h5v5"];
|
|
9
|
-
readonly pin: readonly ["
|
|
9
|
+
readonly pin: readonly ["M12 21c-4-4-7-7.5-7-11a7 7 0 0 1 14 0c0 3.5-3 7-7 11z", "M12 7.5a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5z"];
|
|
10
10
|
readonly at: readonly ["M9.1 12a2.9 2.9 0 1 0 5.8 0a2.9 2.9 0 1 0-5.8 0", "M14.9 12v1.1a1.8 1.8 0 0 0 3.6 0V12a6.5 6.5 0 1 0-3.97 5.98"];
|
|
11
11
|
readonly chev: readonly ["M9 6l6 6-6 6"];
|
|
12
12
|
readonly shrink: readonly ["M7 4h10a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3H7a3 3 0 0 1-3-3V7a3 3 0 0 1 3-3z", "M16 8l-7 7M9 10v5h5"];
|
|
13
13
|
readonly bubble: readonly ["M20.5 11.5a8 8 0 0 1-11.7 7.1L4 19.8l1.2-4.4A8 8 0 1 1 20.5 11.5z"];
|
|
14
|
+
readonly wide: readonly ["M23.2 11.2a10.8 8.2 0 0 1-14.85 7.6L2.6 21l.45-5.7A10.8 8.2 0 1 1 23.2 11.2z"];
|
|
14
15
|
readonly close: readonly ["M6 6l12 12M18 6L6 18"];
|
|
15
16
|
readonly smile: readonly ["M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18z", "M8.6 14.2c1.9 2.1 4.9 2.1 6.8 0", "M9.6 9.8a.6.6 0 1 1-1.2 0a.6.6 0 1 1 1.2 0M15.6 9.8a.6.6 0 1 1-1.2 0a.6.6 0 1 1 1.2 0"];
|
|
16
17
|
readonly edit: readonly ["M4 20h4L19 9l-4-4L4 16z"];
|
|
@@ -13,6 +13,14 @@ export interface Box {
|
|
|
13
13
|
export interface Viewport {
|
|
14
14
|
width: number;
|
|
15
15
|
height: number;
|
|
16
|
+
/**
|
|
17
|
+
* Where the comment control's corner starts (its left and top edges, and the left of comment mode's touch hint
|
|
18
|
+
* beside it): a box reaching past `left` stays above `top`, so nothing sits under the control.
|
|
19
|
+
*/
|
|
20
|
+
keep?: {
|
|
21
|
+
left: number;
|
|
22
|
+
top: number;
|
|
23
|
+
};
|
|
16
24
|
}
|
|
17
25
|
export interface AnchorPoint {
|
|
18
26
|
x: number;
|
|
@@ -35,6 +43,8 @@ export declare const popover: () => number;
|
|
|
35
43
|
/** On screens this narrow or less, All comments takes the whole width (it gets .full). */
|
|
36
44
|
export declare const NARROW = 480;
|
|
37
45
|
export declare const narrow: () => boolean;
|
|
46
|
+
/** A touch screen: a finger is the main pointer (the stylesheet's `pointer: coarse`). */
|
|
47
|
+
export declare const touch: () => boolean;
|
|
38
48
|
/** The viewport left for popovers: All comments, when open, takes its width from the right. */
|
|
39
49
|
export declare function room(listing: boolean): Viewport;
|
|
40
50
|
export declare function placePopover(at: AnchorPoint, size: {
|
|
@@ -47,7 +57,8 @@ export declare function placePopover(at: AnchorPoint, size: {
|
|
|
47
57
|
/**
|
|
48
58
|
* An element draft: just below its block, above it when there is no room below, never over the block or the
|
|
49
59
|
* naming bar (which sits above the block, or below it when there is no room above). A block too tall for either
|
|
50
|
-
* keeps the box on screen, as low as it fits.
|
|
60
|
+
* keeps the box on screen, as low as it fits. Where the comment control's corner is in the way below, the box moves left
|
|
61
|
+
* of the control if it can, rather than up over the block.
|
|
51
62
|
*/
|
|
52
63
|
export declare function placeDraft(block: Box, size: {
|
|
53
64
|
width: number;
|
|
@@ -57,7 +68,10 @@ export declare function placeDraft(block: Box, size: {
|
|
|
57
68
|
top: number;
|
|
58
69
|
above: boolean;
|
|
59
70
|
};
|
|
60
|
-
/**
|
|
71
|
+
/**
|
|
72
|
+
* The naming bar (and the selection's icon): centred above the target, or below it when there's no room; never covering
|
|
73
|
+
* it. A target taller than the window has room for neither: the bar sits at the window's top, over it.
|
|
74
|
+
*/
|
|
61
75
|
export declare function placeBar(target: Box, size: {
|
|
62
76
|
width: number;
|
|
63
77
|
height: number;
|
|
@@ -67,12 +81,13 @@ export declare function placeBar(target: Box, size: {
|
|
|
67
81
|
};
|
|
68
82
|
/**
|
|
69
83
|
* The selection's comment icon: just past the right of its block's text, level with the selection's last line, so it
|
|
70
|
-
* covers no words; above the selection (or below) when there's no room there.
|
|
84
|
+
* covers no words; above the selection (or below) when there's no room there. On a touch screen (`below`), below the
|
|
85
|
+
* selection, clear of the phone's own selection menu above it and its handles at its ends.
|
|
71
86
|
*/
|
|
72
87
|
export declare function placeIcon(sel: Box, line: Box, textRight: number, size: {
|
|
73
88
|
width: number;
|
|
74
89
|
height: number;
|
|
75
|
-
}, vp: Viewport): {
|
|
90
|
+
}, vp: Viewport, below?: boolean): {
|
|
76
91
|
left: number;
|
|
77
92
|
top: number;
|
|
78
93
|
};
|
package/dist/types/ui/pick.d.ts
CHANGED
|
@@ -27,6 +27,11 @@ export interface Flow {
|
|
|
27
27
|
clips: boolean;
|
|
28
28
|
off: boolean;
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* What comment mode leaves to the page: areas the author marked to ignore, and a deck framework's own controls
|
|
32
|
+
* (reveal.js's arrows, progress bar and slide number), which keep working without being marked.
|
|
33
|
+
*/
|
|
34
|
+
export declare const IGNORED = "[data-pipeup-ignore],.reveal>:is(.controls,.progress,.slide-number)";
|
|
30
35
|
/** `el` is a block a click would choose: big enough to see, and marked, obvious, drawn or grouping things. */
|
|
31
36
|
export declare function isBlock(el: Element, look: Look): boolean;
|
|
32
37
|
/** The obvious block under `from`: what the outline glides to in comment mode. */
|
|
@@ -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,.rest,.ctx,.ago{color:var(--fa)}\n.rest,.ago{font-size:12px}\n.rest{display:block;margin-top:3px}\n/* A card's top line: avatar, who (cut short on one line, never wrapped), how long ago, then its actions. */\n.hdr{position:relative;display:flex;align-items:center;gap:7px;min-height:22px}\n.who{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600;color:var(--k)}\n.ago{flex:none;white-space:nowrap}\n.ago::before{content:\"\u00B7\";margin-right:6px}\n.root>.tx,.it>.tx,.root>.ctx{margin-top:2px}\n.ctx[hidden]{display:none}\n.ctx{font-size:12px;margin-bottom:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.cd>.thread .tx{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/* Actions sit at the card's top right: always on an open card, on hover (or focus) on one at rest. In All comments a\nclosed card keeps them while its \u22EF menu is open, and focus put there for the keyboard (not a click) shows them. */\n.acts{margin-left:auto;display:flex;flex:none;transition:opacity var(--in) var(--eo)}\n.th:not(.on):not(:hover):not(:focus-within) .acts,.cd:not(.open):not(:hover):not(:has(:focus-visible,.pm)) .acts{opacity:0}\n.th.on .rest{display:none}\n/* A comment's \u22EF menu: Copy thread, Edit, Delete (asked twice). */\n.pm{position:absolute;right:0;top:100%;z-index:5;display:flex;flex-direction:column;min-width:150px;padding:4px;border:1px solid var(--ln);border-radius:10px;background:var(--su);box-shadow:var(--sh);animation:pu-in var(--in) var(--eo) both}\n.pm button{padding:6px 10px;border-radius:7px;text-align:left;font-size:13px;transition:background-color .2s var(--eo)}\n.pm button:hover,.pm button:focus-visible{background:var(--ho);outline:none}\n.pm .dl{color:#C9402F}.dark .pm .dl{color:#F08A7E}\n.edit{margin-top:2px}\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:8px}\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/* Writing boxes: a rounded box that says what it's for, then Cancel and Send (named) while it is in use. */\n.row{position:relative;padding-top:6px}\n.line{display:flex;align-items:center;gap:6px;padding:3px 12px;border:1px solid var(--ln);border-radius:16px;cursor:text;transition:border-color var(--in) var(--eo),box-shadow var(--in) var(--eo)}\n.line:hover{border-color:var(--mu)}\n.line:focus-within{border-color:var(--pu-accent);box-shadow:0 0 0 1px var(--pu-accent)}\n.input{flex:1;min-width:0;height:24px;display:block;border:0;outline:none;resize:none;overflow:hidden;\nfont:inherit;font-size:14px;line-height:1.5;padding:1px 0;color:var(--k);background:transparent}\n.input::placeholder{color:var(--fa);opacity:1}\n.bts{display:flex;justify-content:flex-end;gap:4px;max-height:0;opacity:0;overflow:hidden;transition:max-height var(--in) var(--eo),opacity var(--in) var(--eo),padding var(--in) var(--eo)}\n.row:focus-within .bts,.row.has .bts{max-height:40px;opacity:1;padding-top:4px}\n.bts button{padding:2px 10px;border-radius:14px;font-size:13px;font-weight:600;color:var(--pu-accent);transition:background-color .2s var(--eo),color .2s var(--eo)}\n.cnl:hover,.cnl:focus-visible{background:var(--as);outline:none}\n.send{background:var(--pu-accent);color:var(--pu-on,#fff)!important}\n.send:not(.show){background:var(--ru);color:var(--fa)!important;cursor:default}\n.ed{display:flex;gap:10px;align-items:center;min-height:34px;padding:6px 10px}\n.ed .input,.nf .input{font-size:13px;height:22px;border-bottom:1px solid var(--ln)}\n.ed .input:focus,.nf .input:focus{border-bottom-color:var(--pu-accent)}\n\n/* Avatars: a squircle with the writer's animal (or initial) on a soft colour, at the start of the card's top line. */\n.av{flex:none;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/* The animal nearly fills its tint (its drawing has room round it in its 24 grid), in a lighter line so it stays thin. */\n.av svg{width:122%;height:122%;stroke-width:1.3}\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.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.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%}\nbutton.me{flex:none;display:grid}\nbutton.me>.av{grid-area:1/1}\n/* Who you are, at the top of a new comment; a name field eases open in its place. */\n.you{flex:1;display:grid;min-width:0;min-height:22px;font-size:12px;color:var(--fa)}\n.you .nm{font-size:13px;font-weight:600;color:var(--k)}\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\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,.tt,.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:8px 10px 10px;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/* Each thread is a compact card; the open one lifts with a soft shadow. */\n.th{position:absolute;left:0;right:0;top:0;padding:8px 10px 10px;background:var(--su);border:1px solid var(--ln);border-radius:10px;pointer-events:auto;cursor:pointer;\ntransition:transform var(--mv) var(--eio),box-shadow var(--in) var(--eo),border-color var(--in) var(--eo),opacity var(--in) var(--eo)}\n.th.hot{border-color:var(--mu)}\n.th.on{border-color:transparent;box-shadow:var(--sh);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){outline:2px solid var(--pu-accent);outline-offset:2px}\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: a small square of frosted glass tucked into the page's corner (flush right and bottom, its\ntop left rounded), with the open count inside a comment bubble. Pointed at, it reaches left just far enough to show\nits shortcut (and anything add-ons say). Its layers and numbers cross-fade in place. */\n.launch{position:fixed;right:0;bottom:0;display:flex;flex-direction:row-reverse;align-items:center;border-top-left-radius:10px;pointer-events:auto;transform-origin:100% 100%;\nbackground:color-mix(in srgb,var(--su) 62%,transparent);-webkit-backdrop-filter:blur(10px) saturate(1.5);backdrop-filter:blur(10px) saturate(1.5);\ntransition:opacity var(--in) var(--eo),transform var(--mv) var(--eo),background-color .3s var(--eo),color .3s var(--eo)}\n.launch:has(.mode.on){background:color-mix(in srgb,var(--pu-accent) 90%,transparent);color:var(--pu-on,#fff)}\n/* While All comments is open, the control is the panel's footer: it draws in, and the footer takes its place. */\n.layer.listing .launch{opacity:0;transform:scale(.6);pointer-events:none}\n.layer.listing .menu{right:8px;bottom:60px;z-index:1}\n.layer.listing .menu :is([data-item=comment],[data-item=all]){display:none}\n.launch .mode{position:relative;display:grid;place-items:center;width:32px;height:32px;border-radius:10px 0 0}\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:11px;font-weight:500;line-height:1;margin:-1.2px 0 0 1.2px;font-variant-numeric:tabular-nums;opacity:0;transition:opacity var(--in) var(--eo)}\n.n.s{font-size:8.5px;letter-spacing:-.04em}\n.n.on{opacity:1}\n.launch .mode:focus-visible{outline:2px solid var(--pu-accent);outline-offset:-2px}\n/* Open threads on other slides or views: a small dot at the bubble's top right, easing in and out. */\n.mode>.dot{position:absolute;top:2px;right:2px;width:8px;height:8px;border-radius:50%;background:var(--pu-accent);opacity:0}\n.mode.else>.dot{opacity:1}\n/* What it reaches out to show when pointed at: the shortcut, after anything add-ons say. Its width eases to exactly what\nthe words need (a 0fr to 1fr column), so it opens and folds evenly, and it folds at once when the pointer leaves. */\n.ttip{display:grid;grid-template-columns:minmax(0,0fr);overflow:hidden;font-size:12px;color:var(--mu);pointer-events:none;opacity:0;transition:grid-template-columns var(--out) var(--ei),opacity var(--out) var(--ei)}\n.ttip>span{min-width:0;white-space:nowrap;padding-left:10px}\n.ttip small{font-size:12px}\n.ttip small,.mi .kc{color:var(--fa)}\n.launch:has(.mode.on) :is(.ttip,.ttip small){color:inherit}\n.launch:hover .ttip{grid-template-columns:minmax(0,1fr);opacity:1;transition:grid-template-columns var(--mv) var(--eo) .4s,opacity var(--in) var(--eo) .4s}\n.launch .mode[aria-expanded=true]+.ttip{grid-template-columns:minmax(0,0fr);opacity:0}\n@media (hover:none){.ttip,.tt,.cd>.thread .acts{display:none}}\n.menu{position:fixed;right:8px;bottom:40px;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/* Copy comments opens to its two choices beneath it, set in under it; folding and unfolding ease. */\n.subs{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--in) var(--eo),opacity var(--in) var(--eo)}\n.subs.open{grid-template-rows:1fr;opacity:1}\n.subs>div{min-height:0;overflow:hidden}\n.subs .mi{padding-left:30px}\n.chev{display:grid;transition:transform var(--in) var(--eo)}\n[aria-expanded=true]>.chev{transform:rotate(90deg)}\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/* The header: no title, two filters (an icon and a word in a pill: grey off, a soft accent fill on) and Close. */\n.hd{display:flex;align-items:center;gap:4px;padding:8px 8px 6px}\n.sp{flex:1}\n.tg{position:relative;display:flex;align-items:center;gap:5px;height:28px;padding:0 11px 0 9px;border-radius:99px;white-space:nowrap;line-height:1;color:var(--mu);transition:background-color .2s var(--eo),color .2s var(--eo)}\n.tg:hover{background:var(--ho);color:var(--k)}\n.tg[aria-pressed=true]{background:var(--as);color:var(--pu-accent)}\n.tg[aria-pressed=true]:hover{background:color-mix(in srgb,var(--pu-accent) 20%,transparent)}\n.tg:focus-visible{outline:2px solid var(--pu-accent);outline-offset:1px}\n/* What each filter does: a tooltip under it that eases in after a moment, on hover or focus. */\n.tg::after{content:attr(data-tip);position:absolute;left:0;top:calc(100% + 4px);z-index:3;width:max-content;max-width:220px;padding:4px 9px;border:1px solid var(--ln);border-radius:8px;background:var(--su);box-shadow:var(--sh);font-size:12px;line-height:1.4;color:var(--mu);pointer-events:none;opacity:0;transform:translateY(-3px);transition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.tg:hover::after,.tg:focus-visible::after{opacity:1;transform:none;transition:opacity var(--in) var(--eo) .4s,transform var(--in) var(--eo) .4s}\n.list{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:4px 8px 8px;background:var(--so)}\n/* Threads in the panel are the same cards; opened, a card shows the thread beneath the words it's about. */\n.cd{position:relative;margin-top:6px;background:var(--su);border:1px solid var(--ln);border-radius:10px;transition:box-shadow var(--in) var(--eo),border-color var(--in) var(--eo),background-color .2s var(--eo)}\n.cd.open{border-color:transparent;box-shadow:var(--sh)}\n.cd.done{opacity:.6}\n/* Closed, its button lies over it (choosing the card opens it), beneath its actions and what they open. */\n.cd>.mi{position:absolute;inset:0;border-radius:10px;background:none}\n.cd>.thread :is(.acts,.refs,.edit){position:relative;z-index:1}\n.cd:not(.open,.new):is(:hover,:has(>.mi:focus-visible)){background:var(--so)}\n/* Resolved from its actions, it fades and folds away. */\n.cd.out{opacity:0;margin-top:0;border-width:0;overflow:hidden;transition:height var(--mv) var(--eio),margin var(--mv) var(--eio),border-width var(--mv) var(--eio),opacity var(--out) var(--ei)}\n.cd.open>.mi{display:none}\n.cd.open .root>.hdr{cursor:pointer}\n.cd.new,.xr,.cd>.thread{padding:8px 10px 10px}\n/* The footer: who you are, Comment (its shortcut and switch), and \u22EF for the menu. */\n.pf{display:flex;align-items:center;gap:8px;min-height:52px;padding:0 8px 0 14px;border-top:1px solid var(--ln)}\n.fs{display:flex;align-items:center;gap:6px;padding:4px 6px;border-radius:8px;font-size:13px;transition:background-color .2s var(--eo)}\n.fs:hover,.fs:focus-visible{background:var(--ho);outline:none}\n.fs small{font-size:12px;color:var(--fa)}\n.pf .ib{width:30px;height:30px}\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/* Messages sit beside the comment control, never over the page's own bottom bar; beside the panel while it is open,\nand above its footer when it fills the screen. */\n.toast{--r:40px;position:fixed;right:var(--r);bottom:4px;max-width:min(320px,calc(100vw - var(--r) - 16px));border-radius:10px;padding:8px 14px;font-size:13px;opacity:0;transform:translateY(6px);transition:.3s var(--eo)}\n.toast.show{opacity:1;transform:none}\n.layer:is(.listing,:has(.xp.show)) .toast{--r:calc(var(--pu-panel) + 16px)}\n@media (max-width:480px){.layer:is(.listing,:has(.xp.show)) .toast{--r:12px;bottom:64px}}\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.bts button,.tg{min-height:36px}\n.launch .mode{width:44px;height:44px}\n}\n\n@media (forced-colors: active){\n.pick.kf{border:3px solid Highlight}\n.layer :is(.ib,.mi,.nb,.tg,.fs,.selbar button,.say button,.xb button):focus-visible{outline:2px solid Highlight}\n.tg[aria-pressed=true]{background:Highlight;color:HighlightText}\n}\n\n@media (prefers-reduced-motion: reduce){\n.ln,.subs{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,.tt,.toast,.ref .rc,.rxp,.mnl{transform:none!important}\n.ttip{transition-property:opacity!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,.toast{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,.launch{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,.rest,.ctx,.ago{color:var(--fa)}\n.rest,.ago{font-size:12px}\n.rest{display:block;margin-top:3px}\n/* A card's top line: avatar, who (cut short on one line, never wrapped), how long ago, then its actions. */\n.hdr{position:relative;display:flex;align-items:center;gap:7px;min-height:22px}\n.who{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:600;color:var(--k)}\n.ago{flex:none;white-space:nowrap}\n.ago::before{content:\"\u00B7\";margin-right:6px}\n.root>.tx,.it>.tx,.root>.ctx{margin-top:2px}\n.ctx[hidden]{display:none}\n.ctx{font-size:12px;margin-bottom:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.cd>.thread .tx,.clamp{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n/* A long comment at rest in the column: its first four lines, fading out, then \"more\"; opened, it eases out to all of it. */\n.th.long .root>.tx{max-height:var(--full);overflow:hidden;transition:max-height var(--mv) var(--eio)}\n.th.long:not(.on) .root>.tx{max-height:84px;mask-image:linear-gradient(#000 calc(100% - 21px),transparent)}\n.mr{display:grid;grid-template-rows:0fr;opacity:0;font-size:12px;color:var(--pu-accent);text-align:end;transition:grid-template-rows var(--mv) var(--eio),opacity var(--in) var(--eo)}\n.mr>span{min-height:0;overflow:hidden}\n.th.long:not(.on) .mr{grid-template-rows:1fr;opacity:1}\n.tx a{color:var(--pu-accent);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}\n\n/* Actions sit at the card's top right: always on an open card, on hover (or focus) on one at rest. In All comments a\nclosed card keeps them while its \u22EF menu is open, and focus put there for the keyboard (not a click) shows them. */\n.acts{margin-left:auto;display:flex;flex:none;transition:opacity var(--in) var(--eo)}\n.th:not(.on):not(:hover):not(:focus-within) .acts,.cd:not(.open):not(:hover):not(:has(:focus-visible,.pm)) .acts,.still .th:not(.on):not(:focus-within) .acts,.still .cd:not(.open):not(:has(:focus-visible,.pm)) .acts{opacity:0;pointer-events:none}\n/* On a closed card they lie over the end of the top line, on the card's own colour, so the name has the whole line\nwhile they're hidden and the card never changes size as they ease in. */\n.th:not(.on) .acts,.cd:not(.open) .acts{position:absolute;right:0;padding-left:16px;background:linear-gradient(90deg,transparent,var(--bg) 14px)}\n.th.on .rest{display:none}\n/* A comment's \u22EF menu: Copy thread, Edit, Delete (asked twice). */\n.pm{position:absolute;right:0;top:100%;z-index:5;display:flex;flex-direction:column;min-width:150px;padding:4px;border:1px solid var(--ln);border-radius:10px;background:var(--su);box-shadow:var(--sh)}\n.pm.in{animation:pu-in var(--in) var(--eo) both}\n.pm button{padding:6px 10px;border-radius:7px;text-align:left;font-size:13px;transition:background-color .2s var(--eo),color .2s var(--eo)}\n.pm button:hover,.pm button:focus-visible{background:var(--ho)}\n.pm .dl{color:#C9402F}.dark .pm .dl{color:#F08A7E}\n.edit{margin-top:2px}\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)}\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:8px}\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/* Writing boxes: a rounded box that says what it's for, then Cancel and Send (named) while it is in use. */\n.row{position:relative;padding-top:6px}\n.line{display:flex;align-items:center;gap:6px;padding:3px 12px;border:1px solid var(--ln);border-radius:16px;cursor:text;transition:border-color var(--in) var(--eo),box-shadow var(--in) var(--eo)}\n.line:hover{border-color:var(--mu)}\n.line:focus-within{border-color:var(--pu-accent);box-shadow:0 0 0 1px var(--pu-accent)}\n.input{flex:1;min-width:0;height:24px;display:block;border:0;outline:none;resize:none;overflow:hidden;\nfont:inherit;font-size:14px;line-height:1.5;padding:1px 0;color:var(--k);background:transparent}\n.input::placeholder{color:var(--fa);opacity:1}\n.bts{display:flex;justify-content:flex-end;gap:4px;max-height:0;opacity:0;overflow:hidden;transition:max-height var(--in) var(--eo),opacity var(--in) var(--eo),padding var(--in) var(--eo)}\n.row:focus-within .bts,.row.has .bts{max-height:40px;opacity:1;padding-top:4px}\n.bts button{padding:2px 10px;border-radius:14px;font-size:13px;font-weight:600;color:var(--pu-accent);transition:background-color .2s var(--eo),color .2s var(--eo)}\n.cnl:hover,.cnl:focus-visible{background:var(--as)}\n.send{background:var(--pu-accent);color:var(--pu-on,#fff)!important}\n.send:not(.show){background:var(--ru);color:var(--fa)!important;cursor:default}\n.ed{display:flex;gap:10px;align-items:center;min-height:34px;padding:6px 10px}\n.ed .input,.nf .input{font-size:13px;height:22px;border-bottom:1px solid var(--ln)}\n.ed .input:focus,.nf .input:focus{border-bottom-color:var(--pu-accent)}\n\n/* Avatars: a squircle with the writer's animal (or initial) on a soft colour, at the start of the card's top line. */\n.av{flex:none;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/* The animal nearly fills its tint (its drawing has room round it in its 24 grid), in a lighter line so it stays thin. */\n.av svg{width:122%;height:122%;stroke-width:1.3}\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.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)}\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{display:flex;align-items:center}.toast.show .ta{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;font-variant-numeric:tabular-nums}\n.rx.mine{background:var(--as);color:var(--pu-accent);border-color:var(--pu-accent)}\n.rx:disabled{cursor:default;opacity:.7}\n.rx{-webkit-touch-callout:none;-webkit-user-select:none}\n.rx.new,.rxq.new{animation:pu-in var(--mv) var(--eo) backwards}\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)}\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,.ref.held .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)}\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%}\nbutton.me{flex:none;display:grid;place-items:center}\nbutton.me>.av{grid-area:1/1}\n/* Who you are, at the top of a new comment; a name field eases open in its place. */\n.you{flex:1;display:grid;min-width:0;min-height:22px;font-size:12px;color:var(--fa)}\n.you .nm{font-size:13px;font-weight:600;color:var(--k)}\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)}\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\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,.tt,.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:8px 10px 10px;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/* Each thread is a compact card; the open one lifts with a soft shadow. */\n.th,.cd{--bg:var(--su);background:var(--bg);opacity:var(--o,1)}\n.th{position:absolute;left:0;right:0;top:0;padding:8px 10px 10px;border:1px solid var(--ln);border-radius:10px;pointer-events:auto;cursor:pointer;\ntransition:transform var(--mv) var(--eio),box-shadow var(--in) var(--eo),border-color var(--in) var(--eo),opacity var(--in) var(--eo)}\n.th.hot{border-color:var(--mu)}\n.th.on{border-color:transparent;box-shadow:var(--sh);cursor:default}\n.th.dim{--o:.45}\n.th.resolved:not(.on):not(.hot){--o:.6}\n.th.lost .ctx{white-space:normal}\n.th.wait{opacity:0!important;pointer-events:none}\n.th:is(.out,.hop){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){outline:2px solid var(--pu-accent);outline-offset:2px}\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)}\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.pkw{position:fixed;left:0;top:0;border:2px dashed color-mix(in srgb,var(--pu-accent) 70%,transparent);border-radius:8px;pointer-events:none;opacity:0;transition:opacity var(--out) var(--ei)}\n.pkw.show{opacity:.6;transition:opacity var(--in) var(--eo)}\n.draft{transition:opacity var(--in) var(--eo)}.draft.wait:not(:focus-within){opacity:.6}\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,.hh{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;max-width:calc(100% - 16px);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/* It sits over the page's words beside its block: pointed at anywhere but its icons, it fades so they can be read. */\n.namebar:hover:not(:has(.nb:hover)){opacity:.15}\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)}\n.namebar .nb.on{background:var(--as);color:var(--pu-accent)}\n.namebar .nb[hidden]{display:none}\n\n/* The comment control: a small square of frosted glass tucked into the page's corner (flush right and bottom, its\ntop left rounded), with the open count inside a comment bubble. Pointed at, it reaches left just far enough to show\nits shortcut (and anything add-ons say). Its layers and numbers cross-fade in place. */\n.launch{position:fixed;right:0;bottom:var(--pu-lift);display:flex;flex-direction:row-reverse;align-items:center;border-top-left-radius:10px;pointer-events:auto;transform-origin:100% 100%;\nbackground:color-mix(in srgb,var(--su) 62%,transparent);-webkit-backdrop-filter:blur(10px) saturate(1.5);backdrop-filter:blur(10px) saturate(1.5);\ntransition:opacity var(--in) var(--eo),transform var(--mv) var(--eo),background-color .3s var(--eo),color .3s var(--eo),bottom var(--mv) var(--eio)}\n.launch:has(.mode.on){background:color-mix(in srgb,var(--pu-accent) 90%,transparent);color:var(--pu-on,#fff)}\n/* While All comments is open, the control is the panel's footer: it draws in, and the footer takes its place. */\n.layer.listing .launch{opacity:0;transform:scale(.6);pointer-events:none}\n.menu.inp{--b:60px;right:8px;z-index:1}\n.menu.inp :is([data-item=comment],[data-item=all]){display:none}\n.launch .mode{position:relative;display:grid;place-items:center;width:32px;height:32px;border-radius:10px 0 0}\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.cnt>.n{font-size:11px;font-weight:500;line-height:1;margin:-1.2px 0 0 1.2px;font-variant-numeric:tabular-nums lining-nums;opacity:0;transition:opacity var(--in) var(--eo)}\n.w>.n{margin-top:-3.4px}\n.cnt>svg{transition:opacity var(--in) var(--eo)}\n.cnt>svg+svg,.cnt.w>svg{opacity:0}\n.cnt.w>svg+svg{opacity:1}\n.n.on{opacity:1}\n.launch .mode:focus-visible{outline:2px solid var(--pu-accent);outline-offset:-2px}\n/* Open threads on other slides or views: a small dot at the bubble's top right, easing in and out. */\n.mode>.dot{position:absolute;top:2px;right:2px;width:8px;height:8px;border-radius:50%;background:var(--pu-accent);opacity:0;transition:opacity var(--in) var(--eo),background-color .3s var(--eo)}\n.mode.else>.dot{opacity:1}\n.mode.on>.dot{background:var(--pu-on,#fff)}\n/* What it reaches out to show when pointed at: the shortcut, after anything add-ons say. Its width eases to exactly what\nthe words need (a 0fr to 1fr column), so it opens and folds evenly, and it folds at once when the pointer leaves. */\n.ttip{display:grid;grid-template-columns:minmax(0,0fr);overflow:hidden;font-size:12px;color:var(--mu);pointer-events:none;opacity:0;transition:grid-template-columns var(--out) var(--ei),opacity var(--out) var(--ei)}\n.ttip>span{min-width:0;white-space:nowrap;padding-left:10px}\n.ttip small{font-size:12px}\n.ttip small,.mi .kc{color:var(--fa)}\n.launch:has(.mode.on) :is(.ttip,.ttip small){color:inherit}\n.launch:hover .ttip{grid-template-columns:minmax(0,1fr);opacity:1;transition:grid-template-columns var(--mv) var(--eo) .4s,opacity var(--in) var(--eo) .4s}\n.launch .mode[aria-expanded=true]+.ttip{grid-template-columns:minmax(0,0fr);opacity:0}\n@media (hover:none){.ttip,.tt,.cd>.thread .acts{display:none}}\n.menu{--b:calc(40px + var(--pu-lift));position:fixed;right:8px;bottom:var(--b);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@media (max-height:600px){.menu{max-height:calc(100% - var(--b) - 8px);overflow-y:auto;overscroll-behavior:contain}}\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)}\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/* Copy comments opens to its two choices beneath it, set in under it; folding and unfolding ease. */\n.subs{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--in) var(--eo),opacity var(--in) var(--eo)}\n.subs.open{grid-template-rows:1fr;opacity:1}\n.subs>div{min-height:0;overflow:hidden}\n.subs .mi{padding-left:30px}\n.chev{display:grid;transition:transform var(--in) var(--eo)}\n[aria-expanded=true]>.chev{transform:rotate(90deg)}\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/* The header: no title, two filters (an icon and a word in a pill: grey off, a soft accent fill on) and Close. */\n.hd{display:flex;align-items:center;gap:4px;padding:8px 8px 6px}\n.sp{flex:1}\n.tg{position:relative;display:flex;align-items:center;gap:5px;height:28px;padding:0 11px 0 9px;border-radius:99px;white-space:nowrap;line-height:1;color:var(--mu);transition:background-color .2s var(--eo),color .2s var(--eo)}\n.tg:hover{background:var(--ho);color:var(--k)}\n.tg[aria-pressed=true]{background:var(--as);color:var(--pu-accent)}\n.tg[aria-pressed=true]:hover{background:color-mix(in srgb,var(--pu-accent) 20%,transparent)}\n.tg:focus-visible{outline:2px solid var(--pu-accent);outline-offset:1px}\n/* What each filter does: a tooltip under it that eases in after a moment, on hover or focus. */\n.tg::after{content:attr(data-tip);position:absolute;left:0;top:calc(100% + 4px);z-index:3;width:max-content;max-width:220px;padding:4px 9px;border:1px solid var(--ln);border-radius:8px;background:var(--su);box-shadow:var(--sh);font-size:12px;line-height:1.4;color:var(--mu);pointer-events:none;opacity:0;transform:translateY(-3px);transition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.tg:not([aria-pressed=true]):is(:hover,:focus-visible)::after{opacity:1;transform:none;transition:opacity var(--in) var(--eo) .4s,transform var(--in) var(--eo) .4s}\n.list{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:4px 8px 8px;background:var(--so)}\n/* Threads in the panel are the same cards; opened, a card shows the thread beneath the words it's about. */\n.cd{position:relative;margin-top:6px;border:1px solid var(--ln);border-radius:10px}\n/* What filters take away or bring back folds out or in, and a card opening or closing eases to its new height. */\n.list :is(.cd,[role=listitem],.sec){transition:all var(--mv) var(--eio)}\n.list .out{opacity:0!important;margin-top:0;padding-block:0;border-width:0;overflow:hidden}\n.cd.open{border-color:transparent;box-shadow:var(--sh)}\n.cd.done{--o:.6}\n/* Closed, its button lies over it (choosing the card opens it), beneath its actions and what they open. */\n.cd>.mi{position:absolute;inset:0;border-radius:10px;background:none}\n.cd>.thread :is(.acts,.refs,.edit){position:relative;z-index:1}\n.cd:not(.open,.new):is(:hover,:has(>.mi:focus-visible)){--bg:var(--so)}\n.cd.open>.mi{display:none}\n.cd.open .root>.hdr{cursor:pointer}\n.cd.new,.xr,.cd>.thread{padding:8px 10px 10px}\n/* The footer: who you are, Comment (its shortcut and switch), and \u22EF for the menu. */\n.pf{display:flex;align-items:center;gap:8px;min-height:52px;padding:0 8px 0 14px;border-top:1px solid var(--ln)}\n.fs{display:flex;align-items:center;gap:6px;padding:4px 6px;border-radius:8px;font-size:13px;transition:background-color .2s var(--eo)}\n.fs:hover,.fs:focus-visible{background:var(--ho)}\n.fs small{font-size:12px;color:var(--fa)}\n.pf .ib{width:30px;height:30px}\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)}.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)}\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/* Messages sit beside the comment control, never over the page's own bottom bar; beside the panel while it is open,\nand above its footer when it fills the screen. */\n.toast{--r:40px;position:fixed;right:var(--r);bottom:calc(4px + var(--pu-lift));max-width:min(320px,calc(100vw - var(--r) - 16px));border-radius:10px;padding:8px 14px;font-size:13px;opacity:0;transform:translateY(6px);transition:.3s var(--eo)}\n.toast.show{opacity:1;transform:none}\n.layer:is(.listing,:has(.xp.show)) .toast{--r:calc(var(--pu-panel) + 16px)}\n/* While the menu is open, beside it (above it on a narrow screen), never under it. */\n.layer:not(.listing):has(.menu.show) .toast{--r:314px}\n@media (max-width:640px){.layer:not(.listing):has(.menu.show) .toast{--r:12px;bottom:auto;top:12px}}\n@media (max-width:480px){.layer:is(.listing,:has(.xp.show)) .toast{--r:12px;bottom:64px}}\n\n/* Touch: everything a finger presses is at least 44 px across. A bubble keeps its small look round a larger hit area.\nThe control is 44 px, so the menu and messages sit further from it. Shortcuts aren't shown where there is no keyboard. */\n@media (pointer:coarse){\n.mi,.ib,.rxo,.refs .ref,.mnl li,.bts button,.tg,.fs,.pm button,.ta,.nb,.selbar button,button.me,.say button,.line,.seen button,.ag button,.go button{min-height:44px}\n.ib,.rxo,.refs .ref,.nb,.selbar button,button.me,.ta{min-width:44px}\n.bub::before{content:\"\";position:absolute;inset:-14px;border-radius:50%}\n.row:focus-within .bts,.row.has .bts{max-height:52px}\n.hd{padding:4px 8px}\n.toast{--r:52px;display:flex;align-items:center;min-height:44px;padding:4px 14px;line-height:1.25}\n.ta{display:grid;place-items:center;margin:-5px -10px -5px 6px;padding:0 10px}\n.launch .mode{width:44px;height:44px}\n.menu{--b:calc(52px + var(--pu-lift))}\n}\n@media (pointer:coarse) and (hover:none){.ks{display:none}}\n\n/* Keyboard focus is always plainly marked: a 2 px ring in the accent, which reads at 4.5 to 1 on Pipeup's surfaces. */\n.layer :is(button,a):not(.mi,.opn,.mode,.tg):focus-visible{outline:2px solid var(--pu-accent);outline-offset:1px}\n.layer .mi:focus-visible{outline:2px solid var(--pu-accent);outline-offset:-2px}\n/* A look that differs from the page's keeps its see-through parts solid: a dimmed card dims its words, not the card. */\n.flip .launch{background:var(--su)}\n.flip :is(.th,.cd){opacity:1}\n.flip :is(.th,.cd)>*{opacity:var(--o,1);transition:opacity var(--in) var(--eo)}\n\n@media (forced-colors: active){\n.pick.kf{border:3px solid Highlight}\n.layer :is(.ib,.mi,.nb,.tg,.fs,.selbar button,.say button,.xb button):focus-visible{outline:2px solid Highlight}\n/* Switches, the filters, your own reactions and comment mode draw in system colours, so every state shows. */\n.sw{forced-color-adjust:none;border:1px solid CanvasText;background:Canvas}\n.sw::before,.sw::after{top:1px;left:1px;background:CanvasText}\n[aria-checked=true]>.sw{background:Highlight;border-color:Highlight}\n[aria-checked=true]>.sw::before,[aria-checked=true]>.sw::after{background:HighlightText}\n.layer :is(.tg,.rxo,.rx)[aria-pressed=true],.launch:has(.mode.on){forced-color-adjust:none;background:Highlight;color:HighlightText;border-color:Highlight}\n}\n\n@media (prefers-reduced-motion: reduce){\n.ln,.subs{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,.tt,.toast,.ref .rc,.rxp,.mnl{transform:none!important}\n.ttip{transition-property:opacity!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,.th.long .root>.tx,.mr,.list :is(.cd,[role=listitem],.sec){transition-property:opacity,box-shadow}\n.tip.show,.toast{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,.launch{transform:none!important}\n@keyframes pu-pulse{0%{opacity:0}35%{opacity:.85}100%{opacity:0}}\n}\n";
|
|
@@ -20,7 +20,9 @@ export interface ThreadActions {
|
|
|
20
20
|
/** "Still not right" on an addressed thread: reopens it and puts the cursor in its reply line. */
|
|
21
21
|
notRight(threadId: string): Promise<void>;
|
|
22
22
|
copy(threadId: string): void;
|
|
23
|
-
/** Esc
|
|
23
|
+
/** Cancel or Esc threw away the words in thread `threadId`'s reply line: offers them back. */
|
|
24
|
+
drop(threadId: string, words: string): void;
|
|
25
|
+
/** Esc in an empty reply line: closes the thread. */
|
|
24
26
|
close(): void;
|
|
25
27
|
}
|
|
26
28
|
export interface ThreadViewOptions {
|
|
@@ -31,6 +33,8 @@ export interface ThreadViewOptions {
|
|
|
31
33
|
lost?: string | null;
|
|
32
34
|
/** Where that content is, when it isn't gone ("On slide 3"); default "No longer on the page". */
|
|
33
35
|
place?: string | null;
|
|
36
|
+
/** Its content was found changed or nearby: flagged Moved, with what it was about, for someone to confirm. */
|
|
37
|
+
moved?: boolean;
|
|
34
38
|
/** A card's line about what it's on, as written (in place of the quote). */
|
|
35
39
|
note?: string | null;
|
|
36
40
|
/** A card's quiet last line (its replies and reactions), as written. */
|
package/package.json
CHANGED
|
@@ -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.0-beta.
|
|
8
|
+
Written for Pipeup 0.8.0-beta.3 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.8.0-beta.
|
|
17
|
+
<script src="https://cdn.jsdelivr.net/npm/pipeup@0.8.0-beta.3/dist/pipeup.min.js"
|
|
18
18
|
integrity="sha384-…" crossorigin="anonymous"></script>
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -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.0-beta.
|
|
8
|
+
Written for Pipeup 0.8.0-beta.3 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.0-beta.
|
|
8
|
+
Written for Pipeup 0.8.0-beta.3 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.8.0-beta.
|
|
78
|
+
<script src="https://cdn.jsdelivr.net/npm/pipeup@0.8.0-beta.3/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.8.0-beta.
|
|
160
|
+
(`https://cdn.jsdelivr.net/npm/pipeup@0.8.0-beta.3/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.8.0-beta.
|
|
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.3/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.0-beta.
|
|
8
|
+
Written for Pipeup 0.8.0-beta.3 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 comments › 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.0-beta.
|
|
8
|
+
Written for Pipeup 0.8.0-beta.3 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
|
|