pipeup 0.8.0-beta.1 → 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.
@@ -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
- /** What kind of block `el` is ("Paragraph", "Heading", else "Block"), or the author's own name for it. */
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
- /** Its own words, cut short. innerText, where there is layout, keeps separate blocks apart ("Offline first Everything…"). */
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;
@@ -1,6 +1,6 @@
1
- export declare const VERSION = "0.8.0-beta.1";
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
- export declare const BUILT = "2026-10-13";
3
+ export declare const BUILT = "2026-10-15";
4
4
  export { PipeupDocument, UnsavedChangeError, type Listener, type OpenOptions } from "./document";
5
5
  export { DEFAULT_PROFILE_NAME, MemoryStore, loadOrCreateProfile, type OpStore, type Profile, } from "./storage/store";
6
6
  export { IndexedDbStore } from "./storage/indexeddb";
@@ -27,7 +27,7 @@ export interface AgentThread {
27
27
  }[];
28
28
  }
29
29
  export interface AgentComments {
30
- /** The same Markdown as Copy as Markdown. */
30
+ /** The same Markdown as Copy comments › As Markdown. */
31
31
  markdown: string;
32
32
  threads: AgentThread[];
33
33
  }
@@ -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; Escape still reaches the page's own handlers.
29
+ * added before comment mode started still hear events.
26
30
  */
27
31
  export declare function createCommentMode(ctx: Ctx): CommentMode;
@@ -1,15 +1,21 @@
1
1
  import { type Person } from "./mentions";
2
2
  import type { Mention } from "../model/types";
3
3
  export interface ComposerOptions {
4
+ /** The send button's word ("Comment", "Reply", "Save"), and the line's name for screen readers unless `name`. */
4
5
  label: string;
6
+ /** The line's name for screen readers, when it isn't the button's word ("Edit comment"). */
7
+ name?: string;
8
+ /** What the empty line says ("Comment or add others with @"). */
9
+ placeholder?: string;
10
+ /** Words already in the line (editing a comment). */
11
+ value?: string;
5
12
  /** A new comment, or a reply in `thread()`. */
6
13
  kind?: "comment" | "reply";
7
14
  thread?: () => string;
8
- /** Something to show before the line instead, such as the writer's avatar. */
9
- before?: Node;
10
15
  /** `mentions`: the people named in the words, found after trimming. */
11
16
  onSend(text: string, mentions: Mention[]): Promise<void> | void;
12
- onCancel?(): void;
17
+ /** Cancel or Esc: `words` are what was thrown away ("" when the line was empty). */
18
+ onCancel?(words: string): void;
13
19
  /** Who can be mentioned with `@`; without it, `@` is just a character. */
14
20
  people?(): Person[];
15
21
  }
@@ -60,5 +66,8 @@ export declare const setComposerSource: (s: ComposerSource | null) => void;
60
66
  export declare const composerNote: () => string | null;
61
67
  /** Sent to a writing line or a new-comment box when what add-ons put in it changes. */
62
68
  export declare const SOURCE_CHANGED = "pu-source";
63
- /** A writing line: no placeholder, Enter sends, Shift+Enter breaks, Esc cancels, a paper plane appears with text. */
69
+ /**
70
+ * A writing box: what it is for when empty, then Cancel and Send (named for what it does) while it is in use.
71
+ * Enter sends, Shift+Enter breaks, Esc cancels. Send stays grey, and out of Tab's reach, until there are words.
72
+ */
64
73
  export declare function composer(o: ComposerOptions): Composer;
@@ -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;
@@ -22,18 +24,24 @@ export interface UiState {
22
24
  showResolved: boolean;
23
25
  /** All comments shows only the threads that name this reviewer. */
24
26
  mine: boolean;
25
- /** Comments are out of sight: comment mode is off and All comments is closed. */
27
+ /** The reviewer chose Hide comments (remembered for this page in this browser). */
28
+ hide: boolean;
29
+ /** Comments are out of sight: Hide comments is on, and nothing is showing them for a while (comment mode, All comments, a draft). */
26
30
  hidden: boolean;
27
31
  mode: "column" | "bubbles";
28
32
  draft: Draft | null;
29
33
  /** Comment mode: the page is quiet and a click chooses a block to comment on. */
30
34
  commenting: boolean;
35
+ /** Comment mode is paused while Space is held: the page works as normal. */
36
+ paused: boolean;
31
37
  /** All comments is open on the right: in the column layout it takes the column's place. */
32
38
  listing: boolean;
33
39
  /** A thread chosen from All comments on a narrow screen is open: comments show until it closes. */
34
40
  reading: boolean;
35
41
  /** The comment control's menu is open: in comment mode a click outside it only closes it. */
36
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;
37
45
  }
38
46
  /** Something that draws: rebuilt on render, repositioned every frame. */
39
47
  export interface View {
@@ -45,6 +53,8 @@ export interface MenuActions {
45
53
  copyAll(as: CopyAs): Promise<void>;
46
54
  toggleResolved(): void;
47
55
  toggleMine(): void;
56
+ /** Hide comments on or off, remembered for this page in this browser. */
57
+ setHide(on: boolean): void;
48
58
  rename(name: string): Promise<void>;
49
59
  /** The reviewer's name; "" until they add one. */
50
60
  name(): string;
@@ -101,18 +111,26 @@ export interface Ctx {
101
111
  /** Runs `fn`, then puts focus and the caret back in the open draft as they were. */
102
112
  keepCaret(fn: () => void): void;
103
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
+ */
104
119
  backToDraft(): void;
105
120
  postDraft(text: string, mentions?: Mention[]): Promise<void>;
106
121
  /** This reviewer has read the comments in `t` that name them: marks them seen, so every device knows. */
107
122
  seen(t: Thread): void;
108
123
  /** Who can be mentioned with `@`: people in this document, agents the page lists, and people supplied. */
109
124
  people(): Person[];
110
- cancelDraft(): void;
111
- /** Turns comment mode on or off; comments show while it is on. `keys`: from the keyboard (the block cursor starts). */
125
+ /** Closes the open draft; `words` thrown away with it are offered back (Undo) for a few seconds. */
126
+ cancelDraft(words?: string): void;
127
+ /** Turns comment mode on or off. `keys`: from the keyboard (the block cursor starts). */
112
128
  setCommenting(on: boolean, keys?: boolean): void;
113
129
  /** What a click on the page does: cancels an empty draft (back to one with words), else closes the open thread. */
114
130
  dismiss(): void;
115
131
  registerDraft(box: DraftBox | null): void;
132
+ /** All comments opens thread `id` in its panel (while the panel is open, opening a thread goes there). */
133
+ registerList(open: ((id: string) => void) | null): void;
116
134
  toast(message: string): void;
117
135
  /** Tells screen readers (a polite live region), once. */
118
136
  say(text: string): void;
@@ -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
- onCancel(): void;
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,11 +25,12 @@ 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
- * The box for a new comment: what it's on, then the writing line with the writer's avatar beside it. Nobody
30
- * has to give a name; a quiet line says who they are ("You're Otter · add your name") and opens a name
31
- * field in its place.
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
33
+ * name; the top line says who they are ("You're Otter · add your name") and opens a name field in its place.
32
34
  */
33
35
  export declare function renderDraft(o: DraftOptions): DraftBox;
34
36
  /**
@@ -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;
@@ -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
- * On a deck, a thread is here when it is on this slide (or on none); on other pages, when every key of its
54
- * saved view but `label` matches the page's state (always, until the page reports one).
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 isHere(saved: ViewState | undefined, slide: string | null, state: ViewState | null): boolean;
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, dark?: boolean): PageSheet;
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;
@@ -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;
@@ -1,18 +1,22 @@
1
1
  declare const PATHS: {
2
2
  readonly comment: 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", "M12.3 8.2v6.6M9 11.5h6.6"];
3
- readonly send: readonly ["M21 12L3.5 4.5 6.2 12l-2.7 7.5zM6.2 12H13"];
4
3
  readonly copy: readonly ["M10 8h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2h-8a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2z", "M16 8V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h2"];
5
4
  readonly resolve: readonly ["M5 12.5l4.5 4.5L19 7.5"];
6
5
  readonly reopen: readonly ["M3 12a9 9 0 1 0 3-6.7", "M3 4v5h5"];
7
6
  readonly lines: readonly ["M4 7h16M4 12h10M4 17h7"];
8
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"];
9
- readonly expand: readonly ["M14 4h6v6M20 4l-6 6M10 20H4v-6M4 20l6-6M20 14v6h-6M20 20l-6-6M4 10V4h6M4 4l6 6"];
10
- readonly pin: readonly ["M6 18v-6a6 6 0 1 1 6 6z"];
11
- readonly shrink: readonly ["M20 10h-6V4M14 10l6-6M4 14h6v6M10 14l-6 6M14 20v-6h6M14 14l6 6M10 4v6H4M10 10L4 4"];
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 ["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
+ 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
+ readonly chev: readonly ["M9 6l6 6-6 6"];
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"];
12
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"];
13
15
  readonly close: readonly ["M6 6l12 12M18 6L6 18"];
14
- readonly smile: readonly ["M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18z", "M8.5 14a4.5 4.5 0 0 0 7 0", "M9 9.6h.01M15 9.6h.01"];
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"];
15
17
  readonly edit: readonly ["M4 20h4L19 9l-4-4L4 16z"];
18
+ readonly hide: readonly ["M2.5 12S6 5.5 12 5.5 21.5 12 21.5 12 18 18.5 12 18.5 2.5 12 2.5 12z", "M12 9.5a2.5 2.5 0 1 0 0 5a2.5 2.5 0 0 0 0-5z", "M4 4l16 16"];
19
+ readonly more: readonly ["M5.5 12h.01M12 12h.01M18.5 12h.01"];
16
20
  readonly look: readonly ["M12 3a9 9 0 1 0 0 18a9 9 0 0 0 0-18z", "M12 3v18"];
17
21
  };
18
22
  export type IconName = keyof typeof PATHS;
@@ -13,12 +13,22 @@ 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;
19
27
  y: number;
20
28
  /** Text comments open below their line; element comments open beside. */
21
29
  below: boolean;
30
+ /** What it is about: with no room beside, an element or pin's popover goes below it or above, not over it. */
31
+ box: Box;
22
32
  }
23
33
  /** Threads sit level with what they're about; overlaps push down; the open thread aligns exactly. */
24
34
  export declare function stackColumn(items: StackItem[], activeId: string | null, gap?: number): Map<string, number>;
@@ -33,6 +43,8 @@ export declare const popover: () => number;
33
43
  /** On screens this narrow or less, All comments takes the whole width (it gets .full). */
34
44
  export declare const NARROW = 480;
35
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;
36
48
  /** The viewport left for popovers: All comments, when open, takes its width from the right. */
37
49
  export declare function room(listing: boolean): Viewport;
38
50
  export declare function placePopover(at: AnchorPoint, size: {
@@ -44,7 +56,9 @@ export declare function placePopover(at: AnchorPoint, size: {
44
56
  };
45
57
  /**
46
58
  * An element draft: just below its block, above it when there is no room below, never over the block or the
47
- * naming bar (which sits above the block, or below it when there is no room above).
59
+ * naming bar (which sits above the block, or below it when there is no room above). A block too tall for either
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.
48
62
  */
49
63
  export declare function placeDraft(block: Box, size: {
50
64
  width: number;
@@ -54,7 +68,10 @@ export declare function placeDraft(block: Box, size: {
54
68
  top: number;
55
69
  above: boolean;
56
70
  };
57
- /** The selection bar: centred above the target, or below it when there's no room; never covering it. */
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
+ */
58
75
  export declare function placeBar(target: Box, size: {
59
76
  width: number;
60
77
  height: number;
@@ -62,3 +79,15 @@ export declare function placeBar(target: Box, size: {
62
79
  left: number;
63
80
  top: number;
64
81
  };
82
+ /**
83
+ * The selection's comment icon: just past the right of its block's text, level with the selection's last line, so it
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.
86
+ */
87
+ export declare function placeIcon(sel: Box, line: Box, textRight: number, size: {
88
+ width: number;
89
+ height: number;
90
+ }, vp: Viewport, below?: boolean): {
91
+ left: number;
92
+ top: number;
93
+ };
@@ -4,7 +4,7 @@ export declare const PAIRS: Record<Look, [string, string]>;
4
4
  export interface Appearance {
5
5
  /** The look Pipeup is showing. */
6
6
  look: Look;
7
- /** Who chose it: the reviewer (the Look row), the author (data-pipeup-theme) or what the page shows. */
7
+ /** Who chose it: the reviewer (the Theme row), the author (data-pipeup-theme) or what the page shows. */
8
8
  source: "reviewer" | "author" | "page";
9
9
  /** Contrast of Pipeup's words on its own surface, as the page's styles leave it; 3 is the least that reads. */
10
10
  ratio: number;
@@ -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. */
@@ -19,6 +19,8 @@ export interface ReactionOptions {
19
19
  resolved: boolean;
20
20
  /** The quick row is open under this comment. */
21
21
  quick: boolean;
22
+ /** Only the quick row, never the chips (a closed card in All comments counts reactions in its last line). */
23
+ bare?: boolean;
22
24
  /** Gives or takes back a reaction. */
23
25
  react(emoji: string, on: boolean): void;
24
26
  /** Chips and quick buttons already on the page once, so only new ones ease in. */
@@ -1,3 +1,3 @@
1
1
  import type { Ctx, View } from "./context";
2
- /** In comment mode, selecting text offers commenting: one comment icon, centred above the selection, never over it. */
2
+ /** In comment mode, selecting text offers commenting: one comment icon beside the selection's block, never over its words. */
3
3
  export declare function createSelection(ctx: Ctx): View;
@@ -5,6 +5,12 @@ export declare const SHORTCUT: {
5
5
  };
6
6
  /** The key's label: symbols on Apple platforms, words elsewhere. */
7
7
  export declare const SHORTCUT_LABEL: string;
8
+ /**
9
+ * The key held to pause comment mode (`KeyboardEvent.key`), and its label: Space, the one key that changes nothing about
10
+ * a click (Command, Ctrl, Shift and Option all make a click on a link do something else).
11
+ */
12
+ export declare const HOLD = " ";
13
+ export declare const HOLD_LABEL = "Space";
8
14
  export declare const SHORTCUT_ARIA = "Shift+Alt+C";
9
15
  /**
10
16
  * Shift+Option+C (Shift+Alt+C): never a key repeat, Command or Ctrl, or AltGr (which types characters).
@@ -1,2 +1,2 @@
1
1
  /** Pipeup's stylesheet, scoped to its shadow root. Light by default; `.dark` follows a dark page. */
2
- export declare const STYLES = "\n/* Inherited page styles are reset on .layer below; custom properties pass through all:initial. */\n:host{all:initial;direction:ltr;unicode-bidi:normal}\n*{box-sizing:border-box}\nbutton{appearance:none;font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer}\nsvg{display:block}\n.layer{all:initial;direction:ltr;unicode-bidi:normal;display:block;position:fixed;inset:0;pointer-events:none;font:13px/1.5 var(--pu-font,system-ui,sans-serif);color:var(--k);\n--k:#2C2C2A;--mu:#5F5E5A;--fa:#6B6A64;--ln:#E5E3DA;--ru:#ECEAE2;--so:#FAFAF7;--su:#FFFFFF;--ho:#F1EFE8;\n--as:color-mix(in srgb,var(--pu-accent,#534AB7) 12%,transparent);\n--sh:0 8px 28px rgba(44,44,42,.10);\n--in:.26s;--mv:.34s;--out:.2s;--pl:1.2s;\n--eo:cubic-bezier(.22,.61,.36,1);--eio:cubic-bezier(.4,0,.2,1);--ei:cubic-bezier(.4,0,1,1);\n--pu-text:var(--k);--pu-muted:var(--mu);--pu-faint:var(--fa);--pu-line:var(--ln);--pu-surface:var(--su);--pu-soft:var(--so);--pu-hover:var(--ho);--pu-shadow:var(--sh);--pu-ease:var(--eo)}\n.layer{transition:opacity .24s var(--eo)}.layer.sw{opacity:0;transition-duration:.16s;transition-timing-function:var(--ei)}\n.layer.dark{--k:#ECEBE6;--mu:#B4B2A9;--fa:#9A9892;--ln:#3A3936;--ru:#34332F;--so:#22221F;--su:#1B1B19;--ho:#2C2C29;--sh:0 8px 28px rgba(0,0,0,.45)}\n.layer.hidden .bub,.layer.hidden .col,.layer.hidden .pop,.layer.hidden .tip,.layer.hidden .mark,.layer.hidden .selbar{opacity:0!important;pointer-events:none!important}\n\n.tx{font-size:14px;line-height:1.5;color:var(--k);white-space:pre-wrap;overflow-wrap:anywhere}\n.tx.del,.who,.rest,.ctx{color:var(--fa)}\n.who,.rest{font-size:12px}\n/* Long names are cut short on one line, never wrapped. */\n.who{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.rft>.who{display:block}\n.ctx[hidden]{display:none}\n.ctx{font-size:12px;margin-bottom:3px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.clamp{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n.tx a{color:var(--pu-accent);text-decoration:underline;text-decoration-thickness:1px;text-underline-offset:2px}\n\n/* Footers: details take no space until hovered, then ease open beneath the words. */\n.ft,.rft{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--in) var(--eo),opacity var(--in) var(--eo)}\n.ft>*,.rft>*{overflow:hidden;min-height:0;display:flex;align-items:center}\n.root:hover>.ft,.root:focus-within>.ft,.it:hover>.rft,.it:focus-within>.rft{grid-template-rows:1fr;opacity:1}\n.ft.has-rest,.ft.open,.rft.open{grid-template-rows:1fr;opacity:1}\n.ft.has-rest>*{grid-area:1/1}\n.ft .hover{opacity:0;transition:opacity var(--in) var(--eo)}\n.ft .rest{transition:opacity var(--in) var(--eo)}\n.root:hover>.ft .hover,.root:focus-within>.ft .hover,.ft:not(.has-rest) .hover{opacity:1}\n.root:hover>.ft .rest,.root:focus-within>.ft .rest{opacity:0}\n.acts{margin-left:6px;display:flex;flex:none}\n.ib{width:24px;height:22px;display:grid;place-items:center;border-radius:6px;color:var(--mu);transition:background-color .2s var(--eo),color .2s var(--eo)}\n.ib:hover,.ib:focus-visible{background:var(--ho);color:var(--k);outline:none}\n\n/* Replies: one level in, oldest first; the reply line ends the thread at the same indent. */\n.rps,.rbox{padding-left:14px}\n.rps .it{padding-top:6px}\n.more{display:grid;grid-template-rows:1fr;transition:grid-template-rows var(--mv) var(--eio)}\n.more>div{overflow:hidden;min-height:0}\n.th:not(.on) .more{grid-template-rows:0fr}\n\n.row{position:relative;display:flex;align-items:center;gap:8px;padding:8px 0 2px;cursor:text}\n.input{flex:1;min-width:0;height:27px;display:block;border:0;border-bottom:1px solid var(--ln);outline:none;resize:none;overflow:hidden;\nfont:inherit;font-size:14px;line-height:1.5;padding:3px 0;color:var(--k);background:transparent;transition:border-color var(--in) var(--eo)}\n.row:hover .input,.input:hover{border-bottom-color:var(--mu)}\n.input:focus{border-bottom-color:var(--pu-accent)}\n.ed{display:flex;gap:10px;align-items:center;min-height:34px;padding:6px 10px}\n.ed .input{font-size:13px;height:22px}\n\n/* Avatars: a squircle with the writer's animal (or initial) on a soft colour. Each comment keeps a fixed area\nat its top right for one, so its words are the same width with or without it. */\n.root,.it{position:relative;padding-right:30px}\n.av{display:grid;place-items:center;width:22px;height:22px;border-radius:32%;\nfont-size:12px;font-weight:600;line-height:1;opacity:0;transform:scale(.85);transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.av.in{opacity:1;transform:none}\n.av svg{width:80%;height:80%}\n.root>.av,.it>.av{position:absolute;top:0;right:0}\n.it>.av{top:6px}\n/* Ten colours (.c0 Red to .c9 Grey, as COLOURS): a soft tint and a dark drawing, swapped round on dark pages. */\n.av{--av-l:92%;--av-d:30%;--s:60%;background:hsl(var(--h) var(--s) var(--av-l));color:hsl(var(--h) var(--s) var(--av-d))}\n.dark .av{--av-l:20%;--av-d:78%}\n/* An AI's reply: a plain disc with a violet ring, all inside the avatar's own box so nothing is cropped. */\n.av.ai{position:relative;border-radius:50%;background:var(--su);color:var(--pu-accent);font-size:9px;letter-spacing:.02em}\n.av.ai::before{content:\"\";position:absolute;inset:3px;border-radius:50%;border:1.5px solid var(--pu-accent);pointer-events:none}\n.root>.av.ai,.it>.av.ai{position:absolute}\n.refs{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px;white-space:normal}\n.refs .ref{display:inline-flex;align-items:center;gap:5px;max-width:160px;padding:1px 9px;border:1px solid var(--ln);border-radius:999px;background:var(--so);color:var(--mu);font:inherit;font-size:11.5px;line-height:1.6;text-decoration:none;cursor:pointer;transition:background-color .2s var(--eo),color .2s var(--eo),border-color .2s var(--eo)}\n.refs .ref:hover,.refs .ref:focus-visible{background:var(--as);color:var(--pu-accent);border-color:var(--pu-accent);outline:none}\n.ref span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.rxp{position:fixed;width:320px;height:340px;border-radius:12px;overflow:hidden;pointer-events:none;opacity:0;transform:translateY(4px);transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.rxp.show{opacity:1;transform:none;pointer-events:auto}\n.mn{border-radius:4px;padding:0 2px;background:var(--as);color:var(--pu-accent)}\n.mn.me{font-weight:600}\n.mnl{position:absolute;left:0;bottom:100%;margin:0 0 4px;padding:4px;list-style:none;min-width:180px;max-width:100%;border:1px solid var(--ln);border-radius:10px;background:var(--su);box-shadow:var(--sh);opacity:0;transform:translateY(4px);pointer-events:none;z-index:4;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.mnl.show{opacity:1;transform:none;pointer-events:auto}\n.mnl li{display:flex;align-items:baseline;gap:8px;padding:5px 8px;border-radius:6px;font-size:13px;color:var(--k);cursor:pointer}\n.mnl li small{font-size:11px;color:var(--fa)}\n.mnl li.on,.mnl li:hover{background:var(--as);color:var(--pu-accent)}\n.dlg{position:fixed;left:50%;top:18vh;width:min(380px,calc(100vw - 32px));padding:16px 18px;border:1px solid var(--ln);border-radius:14px;background:var(--su);box-shadow:var(--sh);color:var(--k);opacity:0;transform:translate(-50%,6px);pointer-events:none;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.dlg.show{opacity:1;transform:translate(-50%,0);pointer-events:auto}\n.toast.act{pointer-events:auto}\n.ta{margin-left:4px;color:var(--pu-accent);text-decoration:underline;text-underline-offset:2px}\n.rx .n{font-size:11px}\n.rx.mine{background:var(--as);color:var(--pu-accent);border-color:var(--pu-accent)}\n.rx:disabled{cursor:default;opacity:.7}\n.rx.new,.rxq.new{animation:pu-in var(--mv) var(--eo) both}\n.rxs{align-items:center}\n.rxq{display:inline-flex;gap:2px}\n.rxo{padding:2px 5px;border-radius:8px;font-size:16px;line-height:1.3;transition:background-color .2s var(--eo)}\n.rxo:hover,.rxo:focus-visible,.rxo[aria-pressed=true]{background:var(--as);outline:none}\n.rrow{min-width:0;flex:1;display:flex;align-items:center}\n.refs .ref{position:relative}.ref .rc{position:absolute;left:0;top:calc(100% + 6px);z-index:3;width:max-content;max-width:min(240px,70vw);padding:6px 9px;border:1px solid var(--ln);border-radius:8px;background:var(--su);box-shadow:var(--sh);color:var(--k);font-size:12px;line-height:1.45;white-space:normal;text-align:left;overflow:visible;opacity:0;visibility:hidden;transform:translateY(-3px);pointer-events:none;transition:opacity .2s var(--eo),transform .2s var(--eo),visibility 0s .2s}.ref:hover .rc,.ref:focus-visible .rc{opacity:1;visibility:visible;transform:none;transition-delay:0s}\n.ref .sl{width:10px;height:7px;border:1.3px solid currentColor;border-radius:2px;flex:none}\n.seen{display:flex;align-items:center;gap:6px;padding:6px 0 0 14px;font-size:12px;color:var(--fa)}\n.seen button{margin-left:auto;padding:0 6px;border:0;border-radius:6px;background:none;color:var(--fa);font:inherit;cursor:pointer;transition:color .2s var(--eo),background-color .2s var(--eo)}.seen button:hover,.seen button:focus-visible{color:var(--pu-accent);background:var(--as);outline:none}\n.seen i{width:12px;height:12px;border-radius:50%;border:1.5px solid var(--pu-accent);flex:none}\n.c0{--h:0}.c1{--h:25}.c2{--h:50}.c3{--h:130}.c4{--h:175}.c5{--h:215}.c6{--h:270}.c7{--h:330}.c8{--h:28;--s:35%}.c9{--h:220;--s:8%}\n.me{flex:none;display:grid}\n.me>.av{grid-area:1/1;width:26px;height:26px;font-size:13px}\n/* Who you are, under the comment line; a name field eases open in its place. */\n.you{display:grid;padding:0 34px;min-height:24px;font-size:12px;color:var(--fa)}\n.you>*{grid-area:1/1;display:flex;align-items:center;min-width:0;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.say{white-space:pre;overflow:hidden}\n.nm{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.say button{flex:none}\n.say button{color:var(--mu);text-decoration:underline;text-decoration-color:var(--ln);text-underline-offset:2px;transition:color .2s var(--eo)}\n.say button:hover,.say button:focus-visible{color:var(--pu-accent);outline:none}\n.nf{opacity:0;transform:translateY(-4px);pointer-events:none}\n.nf .input{font-size:13px;height:24px}\n.you.naming .nf{opacity:1;transform:none;pointer-events:auto}\n.you.naming .say{opacity:0;pointer-events:none}\n.send{width:26px;height:26px;border-radius:50%;display:grid;place-items:center;color:var(--pu-accent);flex:none;opacity:0;pointer-events:none;\ntransition:opacity var(--in) var(--eo),background-color .2s var(--eo)}\n.send.show{opacity:1;pointer-events:auto}\n.send:hover{background:var(--as)}\n\n/* Bubbles, tips, popovers, marks, pulses. */\n.bub{position:fixed;left:0;top:0;width:20px;height:20px;margin:-20px 0 0 -2px;border-radius:50% 50% 50% 0;background:var(--pu-accent);\nborder:2px solid var(--su);box-shadow:0 1px 4px rgba(0,0,0,.2);pointer-events:auto;opacity:0;transform:translateY(-6px) scale(.9);transform-origin:2px 20px;\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.bub.in{opacity:1;transform:none;transition:opacity var(--in) var(--eo),transform var(--in) var(--eo)}\n.bub.in:hover,.bub.on{transform:scale(1.18)}\n.bub.done{background:var(--fa)}\n.bub.ghost{pointer-events:none}\n.tip,.pop,.menu,.all,.xp,.toast,.selbar,.namebar,.ttip,.tt,.mode,.rxp{background:var(--su);border:1px solid var(--ln);box-shadow:var(--sh)}\n.tip{position:fixed;max-width:260px;border-radius:10px;padding:7px 10px;opacity:0;transform:translateY(3px);\ntransition:opacity .22s var(--eo),transform .26s var(--eo)}\n.tip.show{opacity:1;transform:none;pointer-events:auto;cursor:pointer;\ntransition:opacity .22s var(--eo),transform .26s var(--eo),left var(--mv) var(--eio),top var(--mv) var(--eio)}\n.pop{position:fixed;width:var(--pu-pop);border-radius:12px;padding:10px 12px 8px;pointer-events:none;opacity:0;transform:translateY(6px) scale(.98);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.pop.show{opacity:1;transform:none;pointer-events:auto;transition:opacity var(--in) var(--eo),transform var(--mv) var(--eo)}\n.pop.show.glide{transition:opacity var(--in) var(--eo),transform var(--mv) var(--eo),left var(--mv) var(--eio),top var(--mv) var(--eio)}\n.mark{position:fixed;border:2px solid color-mix(in srgb,var(--pu-accent) 50%,transparent);background:var(--as);border-radius:8px;opacity:0;\ntransition:opacity .3s var(--eo)}\n.mark.show{opacity:1}\n.pulse{position:fixed;border:2px solid var(--pu-accent);border-radius:8px;background:var(--as);animation:pu-pulse var(--pl) var(--eio) forwards}\n@keyframes pu-pulse{0%{opacity:0;transform:scale(.985)}35%{opacity:.85;transform:scale(1)}100%{opacity:0;transform:scale(1.02)}}\n\n/* Document column. */\n.col{position:fixed;left:0;top:0;pointer-events:none;transition:opacity var(--in) var(--eo)}\n.th{position:absolute;left:0;right:0;top:0;padding:4px 4px 4px 12px;background:var(--su);border-radius:8px;pointer-events:auto;cursor:pointer;box-shadow:inset 2px 0 0 transparent;\ntransition:transform var(--mv) var(--eio),box-shadow var(--in) var(--eo),opacity var(--in) var(--eo)}\n.th.hot{box-shadow:inset 2px 0 0 var(--ln)}\n.th.on{box-shadow:inset 2px 0 0 var(--pu-accent);cursor:default}\n.th.dim{opacity:.45}\n.th.resolved:not(.on):not(.hot){opacity:.6}\n.th.lost .ctx{white-space:normal}\n.th.wait{opacity:0!important;pointer-events:none}\n.th.out{opacity:0!important;pointer-events:none;transition:opacity var(--out) var(--ei)}\n/* A closed thread's button has no box of its own: the thread shows its focus. */\n.th:has(.opn:focus-visible){box-shadow:inset 2px 0 0 var(--ln);outline:2px solid var(--pu-accent);outline-offset:2px;border-radius:4px}\n\n/* Selection bar. */\n.selbar{position:fixed;display:flex;border-radius:10px;padding:2px;opacity:0;transform:translateY(4px);pointer-events:none;\ntransition:opacity var(--in) var(--eo),transform .3s var(--eo)}\n.selbar.show{opacity:1;transform:none;pointer-events:auto}\n.selbar button{width:32px;height:30px;display:grid;place-items:center;border-radius:8px;color:var(--pu-accent);transition:background-color .2s var(--eo)}\n.selbar button:hover,.selbar button:focus-visible{background:var(--as);outline:none}\n\n/* Comment mode's outline: glides between blocks; solid accent once chosen. */\n.pick{position:fixed;left:0;top:0;border:2px solid color-mix(in srgb,var(--pu-accent) 70%,transparent);background:color-mix(in srgb,var(--pu-accent) 6%,transparent);\nborder-radius:8px;pointer-events:none;opacity:0;transition:opacity var(--out) var(--ei),border-color var(--out) var(--ei),border-width var(--out) var(--ei),box-shadow var(--out) var(--ei)}\n.pick.show{opacity:1;transition-duration:var(--in);transition-timing-function:var(--eo)}\n.pick.show.glide{transition-property:all;transition-duration:var(--mv);transition-timing-function:var(--eio)}\n.pick.on{border-color:var(--pu-accent)}\n/* The block cursor: its focus is drawn on the outline (3px accent with a surface halo, 3:1 on any page); the\nmarkers that hold focus are invisible. */\n.pick.kf{border:3px solid var(--pu-accent);box-shadow:0 0 0 2px var(--su)}\n.km{position:fixed;left:0;top:0;pointer-events:none;outline:none}\n.sr,.mn-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}\n.namebar{position:fixed;left:0;top:0;display:flex;align-items:center;gap:2px;padding:2px 2px 2px 10px;border-radius:10px;font-size:12px;color:var(--mu);\nwhite-space:nowrap;pointer-events:none;opacity:0;transform:translateY(4px);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.namebar.show{opacity:1;transform:none;pointer-events:auto;transition:opacity var(--in) var(--eo),transform .3s var(--eo)}\n.namebar.show.glide{transition-property:all;transition-duration:var(--mv);transition-timing-function:var(--eio)}\n.namebar .lbl{margin-right:6px;max-width:260px;overflow:hidden;text-overflow:ellipsis}\n.namebar .nb{padding:4px;display:grid;place-items:center;border-radius:7px;transition:background-color .2s var(--eo),color .2s var(--eo)}\n.namebar .nb:hover,.namebar .nb:focus-visible{background:var(--ho);color:var(--k);outline:none}\n.namebar .nb[hidden]{display:none}\n\n/* The comment control: one round button; the open count sits inside a comment bubble. Nothing about it\ngrows or slides: its layers and numbers cross-fade in place. */\n.launch{position:fixed;right:20px;bottom:20px;pointer-events:auto}\n.launch .mode{position:relative;display:grid;place-items:center;width:46px;height:46px;border-radius:50%;transition:background-color .3s var(--eo),color .3s var(--eo)}\n.mode>*,.cnt>*{grid-area:1/1}\n.mode>*{display:grid;place-items:center;transition:opacity var(--in) var(--eo)}\n.cnt,.has>.plus{opacity:0}\n.has>.cnt{opacity:1}\n.n{font-size:12px;font-weight:500;line-height:1;margin:-1.4px 0 0 1.4px;font-variant-numeric:tabular-nums;opacity:0;transition:opacity var(--in) var(--eo)}\n.n.s{font-size:9.5px;letter-spacing:-.04em}\n.n.on{opacity:1}\n.launch .mode:hover,.launch .mode[aria-expanded=true]{background:var(--ho)}\n.launch .mode.on{background:var(--pu-accent);color:var(--pu-on,#fff)}\n/* Open threads on other slides or views: a small dot at the button's top right, easing in and out. */\n.mode>.dot{position:absolute;top:3px;right:3px;width:9px;height:9px;border-radius:50%;background:var(--pu-accent);border:2px solid var(--su);opacity:0}\n.mode.else>.dot{opacity:1}\n/* The tooltip eases in after a moment, above the button, and never moves it. */\n.ttip{position:absolute;right:0;bottom:54px;white-space:nowrap;border-radius:8px;padding:4px 9px;font-size:12px;pointer-events:none;opacity:0;transform:translateY(3px);transition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.ttip small{margin-left:8px}\n.ttip small,.mi .kc{font-size:12px;color:var(--fa)}\n.mode:hover+.ttip,.mode:focus-visible+.ttip{opacity:1;transform:none;transition:opacity var(--in) var(--eo) .5s,transform var(--in) var(--eo) .5s}\n.launch .mode[aria-expanded=true]+.ttip{opacity:0;transition:opacity var(--out) var(--ei)}\n@media (hover:none){.ttip,.tt{display:none}}\n.menu{position:fixed;right:20px;bottom:76px;width:290px;border-radius:12px;padding:4px;pointer-events:none;opacity:0;transform:translateY(6px);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.menu.show{opacity:1;transform:none;pointer-events:auto;transition:opacity var(--in) var(--eo),transform var(--mv) var(--eo)}\n/* Menu rows: one line each; the explanation is a tooltip beside the menu that eases in after a moment. */\n.mi{position:relative;display:flex;gap:10px;align-items:center;width:100%;min-height:34px;text-align:left;padding:6px 10px;border-radius:8px;transition:background-color .2s var(--eo)}\n.mi:hover,.mi:focus-visible{background:var(--so);outline:none}\n.mi svg{color:var(--mu);flex:none}\n.mi small{display:block;color:var(--fa);font-size:12px}\n.lb{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.ma{flex:none;display:grid;margin:-2px 0}\n.ma .av{width:20px;height:20px;font-size:11px}\n.mi .av svg{color:inherit}\n.sep{height:1px;margin:4px 10px;background:var(--ru)}\n.tt{position:absolute;right:calc(100% + 14px);top:50%;translate:0 -50%;width:max-content;max-width:220px;padding:4px 9px;border-radius:8px;font-size:12px;line-height:1.4;\ncolor:var(--mu);pointer-events:none;opacity:0;transform:translateX(3px);\ntransition:opacity var(--out) var(--ei),transform var(--out) var(--ei)}\n.mi:hover>.tt,.mi:focus-visible>.tt{opacity:1;transform:none;transition:opacity var(--in) var(--eo) .5s,transform var(--in) var(--eo) .5s}\n@media (max-width:600px){.tt{right:8px;top:auto;bottom:100%;translate:none;transform:translateY(3px)}}\n/* Switches: a track and a knob that slides (cross-fades with reduced motion). */\n.sw{position:relative;flex:none;width:26px;height:16px;border-radius:8px;background:var(--ln);transition:background-color var(--mv) var(--eio)}\n.sw::before,.sw::after{content:\"\";position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.25);\ntransition:transform var(--mv) var(--eio),opacity var(--mv) var(--eio)}\n.sw::before{opacity:0;transform:translateX(10px)}\n[aria-checked=true]>.sw{background:var(--pu-accent)}\n[aria-checked=true]>.sw::after{transform:translateX(10px)}\n.tools{display:flex;flex:none;gap:2px}\n.tools[hidden]{display:none}\n.tool[aria-pressed=true]{background:var(--as);color:var(--pu-accent)}\n.note{display:block;padding:0 0 4px;font-size:12px;color:var(--fa)}\n.note[hidden]{display:none}\n.ov{position:absolute;inset:0;pointer-events:none;overflow:hidden}\n/* An add-on's panel (.xp) is the same full-height panel as All comments (.all), with its own body. */\n.xb{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:4px 16px 16px;font-size:13px}\n.xb p{margin:0 0 10px}\n/* All comments: a full-height panel on the right that slides in (fades, with reduced motion). */\n.all,.xp{position:fixed;top:0;right:0;bottom:0;width:var(--pu-panel);display:flex;flex-direction:column;border-width:0 0 0 1px;opacity:0;transform:translateX(100%);\ntransition:transform var(--out) var(--ei),opacity var(--out) var(--ei)}\n.all.show,.xp.show{opacity:1;transform:none;pointer-events:auto;transition:transform var(--mv) var(--eo),opacity var(--in) var(--eo)}\n.all.full{width:100%}\n.hd{display:flex;align-items:center;gap:8px;padding:12px 10px 8px 16px;font-weight:600}\n.pn{font-weight:400;color:var(--fa)}\n.hs{margin-left:auto;display:flex;align-items:center;gap:6px;padding:3px 4px 3px 6px;border-radius:6px;font-size:12px;font-weight:400;color:var(--mu);\ntransition:background-color .2s var(--eo)}\n.hs:hover,.hs:focus-visible{background:var(--ho);outline:none}\n.list{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:4px}\n.all .mi{align-items:flex-start}\n.all .mi>.av{flex:none}\n.all .mi>span:last-child{flex:1;min-width:0}\n.all .mi small{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n.all .mi.done{opacity:.6}\n.all .mi.open{background:var(--so)}\n.all .mi.open>.av,.all .mi.open .clamp{display:none}\n.xr{padding:2px 12px 10px 16px}\n/* The line from an open thread in the panel to its place on the page. */\n.cx{position:fixed;inset:0;width:100%;height:100%;overflow:visible;pointer-events:none;opacity:0;transition:opacity var(--in) var(--eo)}\n.cx.show{opacity:1}\n.cx path{fill:none;stroke:var(--pu-accent);stroke-width:1.5;stroke-linecap:round;opacity:.7}\n.cx circle{fill:var(--pu-accent)}\n.layer.listing .col{opacity:0;transition:opacity var(--out) var(--ei)}\n.sec{padding:8px 10px 2px;font-size:12px;color:var(--fa)}\n.ag{display:flex;align-items:center;gap:8px;padding:6px 14px;font-size:12px;color:var(--fa);border-bottom:1px solid var(--ln)}\n.ag[hidden]{display:none}\n.lns{display:flex;flex-direction:column}\n.ln{display:grid;grid-template-rows:0fr;opacity:0;transition:grid-template-rows var(--in) var(--eo),opacity var(--in) var(--eo)}\n.ln.show{grid-template-rows:1fr;opacity:1}\n.ln>.lw{overflow:hidden;min-height:0}\n.ag button{margin-left:auto;flex:none;padding:0 6px;border-radius:6px;color:var(--fa);transition:color .2s var(--eo),background-color .2s var(--eo)}.ag button:hover:not(:disabled),.ag button:focus-visible{color:var(--pu-accent);background:var(--as);outline:none}.ag button:disabled{opacity:.5;cursor:default}\n.adr{margin:8px 0 0 14px;padding:8px 10px;border-radius:8px;background:var(--so);font-size:13px;color:var(--k);animation:pu-in var(--mv) var(--eo) both}\n.adr small{display:block;font-size:12px;color:var(--fa)}\n.adr .go{display:flex;gap:6px;margin-top:6px}\n.adr .go button{padding:2px 8px;border-radius:6px;font-size:12px;color:var(--mu);transition:color .2s var(--eo),background-color .2s var(--eo)}.adr .go button:hover,.adr .go button:focus-visible{color:var(--pu-accent);background:var(--as);outline:none}\n@keyframes pu-in{0%{opacity:0;transform:translateY(3px)}100%{opacity:1;transform:none}}\n.sec b{margin-left:6px;font-weight:500;color:var(--pu-accent)}\n.toast{position:fixed;left:50%;bottom:28px;border-radius:10px;padding:8px 14px;font-size:13px;opacity:0;transform:translate(-50%,6px);\ntransition:opacity .3s var(--eo),transform .36s var(--eo)}\n.toast.show{opacity:1;transform:translate(-50%,0)}\n\n/* Touch: fingers need bigger targets than pointers (44 px for the menu's rows, 36 and more for buttons). */\n@media (pointer:coarse){\n.mi{min-height:44px}\n.ib{min-width:36px;min-height:36px}\n.rxo{min-width:40px;min-height:40px}\n.refs .ref{min-height:34px}\n.mnl li{min-height:40px}\n.send{min-width:36px;min-height:36px}\n}\n\n@media (forced-colors: active){\n.pick.kf{border:3px solid Highlight}\n.layer :is(.ib,.mi,.nb,.hs,.selbar button,.say button,.xb button):focus-visible{outline:2px solid Highlight}\n}\n\n@media (prefers-reduced-motion: reduce){\n.ln{transition-property:opacity}\n@keyframes pu-in{0%{opacity:0}100%{opacity:1}}\n.bub,.bub.in,.bub.in:hover,.bub.on,.tip,.pop,.selbar,.menu,.all,.xp,.ttip,.tt,.toast,.ref .rc,.rxp,.mnl{transform:none!important}\n.dlg{transform:translate(-50%,0)!important}\n.sw::after{transform:none!important;transition-property:opacity}\n[aria-checked=true]>.sw::after{opacity:0}\n[aria-checked=true]>.sw::before{opacity:1}\n.th{transition-property:opacity,box-shadow}\n.tip.show{transition-property:opacity}\n.pick,.pick.show{transition:opacity .16s ease-in-out}\n.all,.all.show,.xp,.xp.show{transition-property:opacity}\n.namebar,.namebar.show{transform:none!important;transition:opacity .16s ease-in-out}\n.av,.nf{transform:none!important}\n@keyframes pu-pulse{0%{opacity:0}35%{opacity:.85}100%{opacity:0}}\n}\n";
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";