@devaccel-labs/comment-service 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -206,11 +206,11 @@ function overlayFor(element) {
206
206
  return { role, name: labelFor(node) || "dialog" };
207
207
  }
208
208
  function fiberNames(element) {
209
- const key = Object.keys(element).find((name) => name.startsWith("__reactFiber$") || name.startsWith("__reactInternalInstance$"));
210
- if (!key)
209
+ const key2 = Object.keys(element).find((name) => name.startsWith("__reactFiber$") || name.startsWith("__reactInternalInstance$"));
210
+ if (!key2)
211
211
  return [];
212
212
  const names2 = [];
213
- let fiber = element[key];
213
+ let fiber = element[key2];
214
214
  for (let guard = 0; fiber && guard < 40; guard++) {
215
215
  const type = fiber.type;
216
216
  if (typeof type === "function") {
@@ -267,7 +267,7 @@ function ownership(element) {
267
267
  owner: null
268
268
  };
269
269
  }
270
- function candidateFromElement(element, route, key) {
270
+ function candidateFromElement(element, route, key2) {
271
271
  const owned = ownership(element);
272
272
  const label = labelFor(element);
273
273
  const explicit = EXPLICIT.flatMap((attr) => {
@@ -275,7 +275,7 @@ function candidateFromElement(element, route, key) {
275
275
  return value && usableExplicit(attr, value) ? [{ attr, value }] : [];
276
276
  });
277
277
  return {
278
- key,
278
+ key: key2,
279
279
  route,
280
280
  visible: !obviouslyHidden(element),
281
281
  path: domPath(element),
@@ -354,8 +354,8 @@ function describeElement(element) {
354
354
  }
355
355
 
356
356
  // ../react/dist/toolbar.js
357
- import { jsx as _jsx5, jsxs as _jsxs5, Fragment as _Fragment3 } from "react/jsx-runtime";
358
- import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef3, useState as useState4 } from "react";
357
+ import { jsx as _jsx6, jsxs as _jsxs6, Fragment as _Fragment3 } from "react/jsx-runtime";
358
+ import { useCallback as useCallback2, useEffect as useEffect2, useMemo as useMemo3, useRef as useRef3, useState as useState5 } from "react";
359
359
  import { createPortal as createPortal2 } from "react-dom";
360
360
 
361
361
  // ../react/dist/client.js
@@ -499,6 +499,8 @@ var Paperclip = () => _jsx(Icon, { size: 15, children: _jsx("path", { d: "m21.44
499
499
  var Camera = () => _jsxs(Icon, { size: 15, children: [_jsx("path", { d: "M14.5 4h-5L7 7H4a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2h-3l-2.5-3z" }), _jsx("circle", { cx: "12", cy: "13", r: "3" })] });
500
500
  var FileIcon = () => _jsxs(Icon, { size: 15, children: [_jsx("path", { d: "M14.5 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7.5L14.5 2z" }), _jsx("polyline", { points: "14 2 14 8 20 8" })] });
501
501
  var Back = () => _jsx(Icon, { children: _jsx("path", { d: "m15 18-6-6 6-6" }) });
502
+ var Table = () => _jsxs(Icon, { children: [_jsx("rect", { x: "3", y: "4", width: "18", height: "16", rx: "2" }), _jsx("path", { d: "M3 10h18M3 15h18M9 10v10" })] });
503
+ var List = () => _jsx(Icon, { children: _jsx("path", { d: "M8 6h13M8 12h13M8 18h13M3.5 6h.01M3.5 12h.01M3.5 18h.01" }) });
502
504
 
503
505
  // ../react/dist/details.js
504
506
  var noDetails = { role: null, fields: {} };
@@ -673,7 +675,7 @@ function useAttachments(session, memberToken, onError) {
673
675
  const [items, setItems] = useState2([]);
674
676
  const itemsRef = useRef(items);
675
677
  itemsRef.current = items;
676
- const patch = (key, next) => setItems((current) => current.map((item) => item.key === key ? { ...item, ...next } : item));
678
+ const patch = (key2, next) => setItems((current) => current.map((item) => item.key === key2 ? { ...item, ...next } : item));
677
679
  const add = useCallback((files) => {
678
680
  if (!session || !memberToken)
679
681
  return;
@@ -689,22 +691,22 @@ function useAttachments(session, memberToken, onError) {
689
691
  onError(`${name} is over 10 MB.`);
690
692
  continue;
691
693
  }
692
- const key = crypto.randomUUID();
694
+ const key2 = crypto.randomUUID();
693
695
  const preview = blob.type.startsWith("image/") ? URL.createObjectURL(blob) : null;
694
- setItems((current) => [...current, { key, name, size: blob.size, contentType: blob.type, preview, status: "uploading" }]);
695
- uploadAttachment(session, memberToken, blob, name).then((attachment) => patch(key, { status: "ready", id: attachment.id })).catch((caught) => {
696
+ setItems((current) => [...current, { key: key2, name, size: blob.size, contentType: blob.type, preview, status: "uploading" }]);
697
+ uploadAttachment(session, memberToken, blob, name).then((attachment) => patch(key2, { status: "ready", id: attachment.id })).catch((caught) => {
696
698
  const message = caught instanceof Error ? caught.message : "Upload failed.";
697
- patch(key, { status: "failed", error: message });
699
+ patch(key2, { status: "failed", error: message });
698
700
  onError(`${name}: ${message}`);
699
701
  });
700
702
  }
701
703
  }, [memberToken, onError, session]);
702
- const remove = useCallback((key) => {
704
+ const remove = useCallback((key2) => {
703
705
  setItems((current) => {
704
- const item = current.find((candidate) => candidate.key === key);
706
+ const item = current.find((candidate) => candidate.key === key2);
705
707
  if (item?.preview)
706
708
  URL.revokeObjectURL(item.preview);
707
- return current.filter((candidate) => candidate.key !== key);
709
+ return current.filter((candidate) => candidate.key !== key2);
708
710
  });
709
711
  }, []);
710
712
  const reset = useCallback(() => {
@@ -1146,14 +1148,14 @@ async function createContext(node, options) {
1146
1148
  drawImageCount: 0,
1147
1149
  tasks: [],
1148
1150
  features,
1149
- isEnable: (key) => {
1150
- if (key === "restoreScrollPosition") {
1151
- return typeof features === "boolean" ? false : features[key] ?? false;
1151
+ isEnable: (key2) => {
1152
+ if (key2 === "restoreScrollPosition") {
1153
+ return typeof features === "boolean" ? false : features[key2] ?? false;
1152
1154
  }
1153
1155
  if (typeof features === "boolean") {
1154
1156
  return features;
1155
1157
  }
1156
- return features[key] ?? true;
1158
+ return features[key2] ?? true;
1157
1159
  },
1158
1160
  shadowRoots: []
1159
1161
  };
@@ -1394,14 +1396,14 @@ function getDefaultStyle(node, pseudoElement, context) {
1394
1396
  const nodeName = node.nodeName.toLowerCase();
1395
1397
  const isSvgNode = isSVGElementNode(node) && nodeName !== "svg";
1396
1398
  const attributes = isSvgNode ? includedAttributes.map((name) => [name, node.getAttribute(name)]).filter(([, value]) => value !== null) : [];
1397
- const key = [
1399
+ const key2 = [
1398
1400
  isSvgNode && "svg",
1399
1401
  nodeName,
1400
1402
  attributes.map((name, value) => `${name}=${value}`).join(","),
1401
1403
  pseudoElement
1402
1404
  ].filter(Boolean).join(":");
1403
- if (defaultComputedStyles.has(key))
1404
- return defaultComputedStyles.get(key);
1405
+ if (defaultComputedStyles.has(key2))
1406
+ return defaultComputedStyles.get(key2);
1405
1407
  const sandbox = getSandBox(context);
1406
1408
  const sandboxWindow = sandbox?.contentWindow;
1407
1409
  if (!sandboxWindow)
@@ -1430,7 +1432,7 @@ function getDefaultStyle(node, pseudoElement, context) {
1430
1432
  styles.set(name, computedStyle.getPropertyValue(name));
1431
1433
  }
1432
1434
  sandboxDocument.body.removeChild(root);
1433
- defaultComputedStyles.set(key, styles);
1435
+ defaultComputedStyles.set(key2, styles);
1434
1436
  return styles;
1435
1437
  }
1436
1438
  function getDiffStyle(style, defaultStyle, includeStyleProperties) {
@@ -1478,8 +1480,8 @@ function copyCssStyles(node, cloned, isRoot, context) {
1478
1480
  const clonedStyle = cloned.style;
1479
1481
  const computedStyle = ownerWindow.getComputedStyle(node);
1480
1482
  const defaultStyle = getDefaultStyle(node, null, context);
1481
- currentParentNodeStyle?.forEach((_, key) => {
1482
- defaultStyle.delete(key);
1483
+ currentParentNodeStyle?.forEach((_, key2) => {
1484
+ defaultStyle.delete(key2);
1483
1485
  });
1484
1486
  const style = getDiffStyle(computedStyle, defaultStyle, includeStyleProperties);
1485
1487
  style.delete("transition-property");
@@ -1550,8 +1552,8 @@ function copyPseudoClass(node, cloned, copyScrollbar, context, addWordToFontFami
1550
1552
  content = content.replace(/(')|(")|(counter\(.+\))/g, "");
1551
1553
  const klasses = [uuid()];
1552
1554
  const defaultStyle = getDefaultStyle(node, pseudoClass, context);
1553
- currentNodeStyle?.forEach((_, key) => {
1554
- defaultStyle.delete(key);
1555
+ currentNodeStyle?.forEach((_, key2) => {
1556
+ defaultStyle.delete(key2);
1555
1557
  });
1556
1558
  const style = getDiffStyle(computedStyle, defaultStyle, context.includeStyleProperties);
1557
1559
  style.delete("content");
@@ -2340,6 +2342,145 @@ async function captureAround(element) {
2340
2342
  return out.toDataURL("image/jpeg", 0.82);
2341
2343
  }
2342
2344
 
2345
+ // ../react/dist/table.js
2346
+ import { jsx as _jsx5, jsxs as _jsxs5 } from "react/jsx-runtime";
2347
+ import { useMemo as useMemo2, useState as useState4 } from "react";
2348
+ var columns = [
2349
+ { key: "comment", label: "Comment" },
2350
+ { key: "role", label: "Role" },
2351
+ { key: "page", label: "Page" },
2352
+ { key: "author", label: "Author" },
2353
+ { key: "replies", label: "Replies" },
2354
+ { key: "status", label: "Status" },
2355
+ { key: "updated", label: "Updated" }
2356
+ ];
2357
+ function sortValue(thread, key2) {
2358
+ if (key2 === "comment")
2359
+ return thread.messages[0]?.body ?? "";
2360
+ if (key2 === "role")
2361
+ return thread.role ?? "";
2362
+ if (key2 === "page")
2363
+ return thread.url || thread.route;
2364
+ if (key2 === "author")
2365
+ return thread.createdBy;
2366
+ if (key2 === "replies")
2367
+ return thread.messages.length;
2368
+ if (key2 === "status")
2369
+ return thread.status;
2370
+ return thread.updatedAt;
2371
+ }
2372
+ function searchText(thread) {
2373
+ return [
2374
+ thread.createdBy,
2375
+ thread.role ?? "",
2376
+ thread.url || thread.route,
2377
+ targetName(thread.anchor),
2378
+ ...thread.messages.map((message) => message.body),
2379
+ ...thread.fields.map((field) => `${field.label} ${field.value}`)
2380
+ ].join("\n").toLowerCase();
2381
+ }
2382
+ function CommentTable({ rows, route, activeId, tabs, onSelect, onList, onClose }) {
2383
+ const [query, setQuery] = useState4("");
2384
+ const [sort, setSort] = useState4({ key: "updated", desc: true });
2385
+ const showRole = rows.some((row) => row.thread.role);
2386
+ const fieldLabels = useMemo2(() => {
2387
+ const labels = [];
2388
+ for (const { thread } of rows)
2389
+ for (const field of thread.fields)
2390
+ if (!labels.includes(field.label))
2391
+ labels.push(field.label);
2392
+ return labels;
2393
+ }, [rows]);
2394
+ const shown = useMemo2(() => {
2395
+ const needle = query.trim().toLowerCase();
2396
+ const matched = needle ? rows.filter((row) => searchText(row.thread).includes(needle)) : rows;
2397
+ return [...matched].sort((a, b) => {
2398
+ const left = sortValue(a.thread, sort.key);
2399
+ const right = sortValue(b.thread, sort.key);
2400
+ const order = typeof left === "number" && typeof right === "number" ? left - right : String(left).localeCompare(String(right));
2401
+ return sort.desc ? -order : order;
2402
+ });
2403
+ }, [query, rows, sort]);
2404
+ const visible = columns.filter((column) => column.key !== "role" || showRole);
2405
+ const header = (column) => _jsx5("th", { "aria-sort": sort.key === column.key ? sort.desc ? "descending" : "ascending" : "none", children: _jsxs5("button", { type: "button", onClick: () => setSort((current) => ({ key: column.key, desc: current.key === column.key ? !current.desc : column.key === "updated" })), children: [column.label, sort.key === column.key ? _jsx5("span", { className: "cs-sort", children: sort.desc ? "\u2193" : "\u2191" }) : null] }) }, column.key);
2406
+ return _jsxs5("section", { className: "cs-card cs-table-sheet cs-hit", "data-cs-ui": "panel", "aria-label": "Comments table", children: [_jsxs5("header", { className: "cs-sheet-head", children: [_jsx5("h2", { children: "Comments" }), _jsx5("input", { className: "cs-table-search", "data-cs-ui": "table-search", type: "search", "aria-label": "Search comments", placeholder: "Search", value: query, onChange: (event) => setQuery(event.target.value) }), _jsx5("button", { className: "cs-icon-button", "data-cs-ui": "list-view", type: "button", "aria-label": "List view", onClick: onList, children: _jsx5(List, {}) }), _jsx5("button", { className: "cs-icon-button", type: "button", "aria-label": "Close comments", onClick: onClose, children: _jsx5(Close, {}) })] }), tabs, _jsx5("div", { className: "cs-table-wrap", children: shown.length === 0 ? _jsx5("p", { className: "cs-empty", children: query ? "No comments match." : "No comments here." }) : _jsxs5("table", { className: "cs-table", "data-cs-ui": "table", children: [_jsx5("thead", { children: _jsxs5("tr", { children: [visible.slice(0, showRole ? 2 : 1).map(header), fieldLabels.map((label) => _jsx5("th", { children: _jsx5("span", { children: label }) }, `field:${label}`)), visible.slice(showRole ? 2 : 1).map(header)] }) }), _jsx5("tbody", { children: shown.map((row) => {
2407
+ const { thread } = row;
2408
+ const first = thread.messages[0];
2409
+ const note = statusNote(row.status, thread.anchor, thread.route === route);
2410
+ return _jsxs5("tr", { className: activeId === thread.id ? "is-active" : void 0, "data-cs-ui": "table-row", "data-thread-id": thread.id, tabIndex: 0, onClick: () => onSelect(row), onKeyDown: (event) => {
2411
+ if (event.key === "Enter") {
2412
+ event.preventDefault();
2413
+ onSelect(row);
2414
+ }
2415
+ }, children: [_jsxs5("td", { className: "cs-cell-comment", children: [_jsx5("span", { className: "cs-cell-clamp", children: first?.body || "\u2014" }), _jsx5("small", { children: targetName(thread.anchor) })] }), showRole ? _jsx5("td", { children: thread.role ? _jsx5("span", { className: "cs-role", children: thread.role }) : null }) : null, fieldLabels.map((label) => _jsx5("td", { children: _jsx5("span", { className: "cs-cell-clamp", children: thread.fields.find((field) => field.label === label)?.value ?? "" }) }, `field:${label}`)), _jsx5("td", { className: "cs-cell-page", title: thread.url || thread.route, children: thread.url || thread.route }), _jsx5("td", { className: "cs-cell-nowrap", children: thread.createdBy }), _jsx5("td", { className: "cs-cell-num", children: thread.messages.length - 1 || "" }), _jsxs5("td", { className: "cs-cell-nowrap", children: [_jsx5("span", { className: thread.status === "resolved" ? "cs-state is-done" : "cs-state", children: thread.status === "resolved" ? "Resolved" : "Open" }), note && thread.status === "open" ? _jsx5("small", { className: `cs-note is-${note.tone}`, children: note.text }) : null] }), _jsx5("td", { className: "cs-cell-nowrap", children: _jsx5("time", { dateTime: thread.updatedAt, children: ago(thread.updatedAt) }) })] }, thread.id);
2416
+ }) })] }) })] });
2417
+ }
2418
+
2419
+ // ../react/dist/handoff.js
2420
+ var key = "devaccel.comment.handoff";
2421
+ var ttl = 30 * 60 * 1e3;
2422
+ function readHandoff() {
2423
+ try {
2424
+ const value = JSON.parse(sessionStorage.getItem(key) ?? "null");
2425
+ return value && Date.now() - value.at < ttl ? value : null;
2426
+ } catch {
2427
+ return null;
2428
+ }
2429
+ }
2430
+ function write(value) {
2431
+ try {
2432
+ if (value.invite || value.thread)
2433
+ sessionStorage.setItem(key, JSON.stringify(value));
2434
+ else
2435
+ sessionStorage.removeItem(key);
2436
+ } catch {
2437
+ }
2438
+ }
2439
+ function linkParams() {
2440
+ const url = new URL(window.location.href);
2441
+ const hash = new URLSearchParams(url.hash.slice(1));
2442
+ return {
2443
+ url,
2444
+ hash,
2445
+ invite: url.searchParams.get("cs-invite") ?? hash.get("cs-invite"),
2446
+ thread: url.searchParams.get("cs-thread") ?? hash.get("cs-thread")
2447
+ };
2448
+ }
2449
+ function captureHandoff() {
2450
+ if (typeof window === "undefined")
2451
+ return;
2452
+ const { invite, thread } = linkParams();
2453
+ if (!invite && !thread)
2454
+ return;
2455
+ write({ ...readHandoff(), ...invite ? { invite } : {}, ...thread ? { thread } : {}, at: Date.now() });
2456
+ }
2457
+ function dropHandoff(part) {
2458
+ const current = readHandoff();
2459
+ if (!current)
2460
+ return;
2461
+ const { [part]: _dropped, ...rest } = current;
2462
+ write(rest);
2463
+ }
2464
+ function stripHandoffFromUrl() {
2465
+ const { url, hash } = linkParams();
2466
+ const inQuery = url.searchParams.has("cs-invite") || url.searchParams.has("cs-thread");
2467
+ const inHash = hash.has("cs-invite") || hash.has("cs-thread");
2468
+ if (!inQuery && !inHash)
2469
+ return;
2470
+ url.searchParams.delete("cs-invite");
2471
+ url.searchParams.delete("cs-thread");
2472
+ if (inHash)
2473
+ url.hash = "";
2474
+ history.replaceState(history.state, "", url);
2475
+ }
2476
+ function linkWith(href, name, value) {
2477
+ const url = new URL(href, window.location.origin);
2478
+ url.searchParams.delete("cs-invite");
2479
+ url.searchParams.delete("cs-thread");
2480
+ url.hash = `${name}=${encodeURIComponent(value)}`;
2481
+ return url.toString();
2482
+ }
2483
+
2343
2484
  // ../react/dist/styles.js
2344
2485
  var toolbarCss = `
2345
2486
  #cs-root {
@@ -2593,6 +2734,7 @@ var toolbarCss = `
2593
2734
  display: flex; flex-direction: column; overflow: hidden;
2594
2735
  }
2595
2736
  #cs-root .cs-sheet-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 10px 4px 16px; }
2737
+ #cs-root .cs-sheet-head .cs-push { margin-left: auto; }
2596
2738
  #cs-root .cs-sheet-head h2 { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }
2597
2739
  #cs-root .cs-tabs { display: flex; gap: 2px; margin: 4px 12px 6px; padding: 2px; border-radius: 9px; background: var(--cs-fill); }
2598
2740
  #cs-root .cs-tabs button {
@@ -2708,6 +2850,44 @@ var toolbarCss = `
2708
2850
  #cs-root .cs-add-row input { padding: 5px 8px; }
2709
2851
  #cs-root .cs-settings .cs-hint { padding: 6px 8px 4px; }
2710
2852
 
2853
+ /* Table */
2854
+ #cs-root .cs-table-sheet {
2855
+ top: 12px; right: 12px; width: min(1100px, calc(100vw - 24px)); max-height: calc(100% - 88px);
2856
+ display: flex; flex-direction: column; overflow: hidden;
2857
+ }
2858
+ #cs-root .cs-table-sheet .cs-sheet-head { gap: 6px; }
2859
+ #cs-root .cs-table-sheet .cs-sheet-head h2 { margin-right: auto; }
2860
+ #cs-root .cs-table-search { width: 220px; padding: 5px 10px; }
2861
+ #cs-root .cs-table-sheet .cs-tabs { max-width: 420px; }
2862
+ #cs-root .cs-table-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; border-top: 1px solid var(--cs-line); overscroll-behavior: contain; }
2863
+ #cs-root .cs-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
2864
+ #cs-root .cs-table th {
2865
+ position: sticky; top: 0; z-index: 1; background: var(--cs-card); text-align: left; font-weight: 600;
2866
+ font-size: 11px; color: var(--cs-text-3); text-transform: uppercase; letter-spacing: 0.03em;
2867
+ padding: 0; border-bottom: 1px solid var(--cs-line); white-space: nowrap;
2868
+ }
2869
+ #cs-root .cs-table th > button, #cs-root .cs-table th > span {
2870
+ display: inline-flex; align-items: center; gap: 4px; padding: 8px 10px; font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
2871
+ }
2872
+ #cs-root .cs-table th > button:hover { color: var(--cs-text); }
2873
+ #cs-root .cs-sort { color: var(--cs-accent); }
2874
+ #cs-root .cs-table td { padding: 8px 10px; vertical-align: top; border-bottom: 1px solid var(--cs-line); max-width: 260px; }
2875
+ #cs-root .cs-table tbody tr { cursor: pointer; }
2876
+ #cs-root .cs-table tbody tr:hover { background: var(--cs-fill); }
2877
+ #cs-root .cs-table tbody tr.is-active { background: var(--cs-accent-soft); }
2878
+ #cs-root .cs-table tbody tr:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: -2px; }
2879
+ #cs-root .cs-cell-comment { min-width: 220px; }
2880
+ #cs-root .cs-cell-comment small, #cs-root .cs-table td small { display: block; margin-top: 2px; font-size: 11.5px; color: var(--cs-text-3); }
2881
+ #cs-root .cs-cell-clamp { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; white-space: pre-wrap; overflow-wrap: anywhere; }
2882
+ #cs-root .cs-cell-page { font: 11.5px ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--cs-text-2); max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2883
+ #cs-root .cs-cell-nowrap { white-space: nowrap; }
2884
+ #cs-root .cs-cell-num { text-align: right; font-variant-numeric: tabular-nums; color: var(--cs-text-2); }
2885
+ #cs-root .cs-state { display: inline-flex; align-items: center; gap: 5px; font-weight: 500; }
2886
+ #cs-root .cs-state::before { content: ""; width: 6px; height: 6px; border-radius: 999px; background: #34c759; }
2887
+ #cs-root .cs-state.is-done { color: var(--cs-text-3); }
2888
+ #cs-root .cs-state.is-done::before { background: var(--cs-text-3); }
2889
+ #cs-root .cs-table .cs-note { display: flex; margin-top: 2px; font-size: 11px; }
2890
+
2711
2891
  /* Attachments */
2712
2892
  #cs-root .cs-attach { display: inline-flex; gap: 0; flex: none; }
2713
2893
  #cs-root .cs-tray { display: flex; flex-wrap: wrap; gap: 6px; padding: 4px 12px 2px 46px; }
@@ -2798,6 +2978,7 @@ var toolbarCss = `
2798
2978
  `;
2799
2979
 
2800
2980
  // ../react/dist/toolbar.js
2981
+ captureHandoff();
2801
2982
  var historyFlag = "__devaccelCommentHistory";
2802
2983
  var prefsKey = "devaccel.comment.prefs";
2803
2984
  var positions = [
@@ -2834,7 +3015,8 @@ function pageHref() {
2834
3015
  const url = new URL(window.location.href);
2835
3016
  url.searchParams.delete("cs-thread");
2836
3017
  url.searchParams.delete("cs-invite");
2837
- return `${url.pathname}${url.search}${url.hash}`;
3018
+ const hash = url.hash.includes("cs-thread=") || url.hash.includes("cs-invite=") ? "" : url.hash;
3019
+ return `${url.pathname}${url.search}${hash}`;
2838
3020
  }
2839
3021
  function isTyping(target) {
2840
3022
  if (!(target instanceof HTMLElement))
@@ -2858,47 +3040,48 @@ async function loadSession(sessionPath) {
2858
3040
  return { apiUrl: payload.apiUrl, project: payload.project, environment: payload.environment, hostToken: payload.hostToken };
2859
3041
  }
2860
3042
  function Avatar({ name, size = 24 }) {
2861
- return _jsx5("span", { className: "cs-avatar", style: { width: size, height: size, fontSize: size * 0.4, background: colorFor(name) }, children: initials(name) });
3043
+ return _jsx6("span", { className: "cs-avatar", style: { width: size, height: size, fontSize: size * 0.4, background: colorFor(name) }, children: initials(name) });
2862
3044
  }
2863
3045
  function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs = 4e3, position = "bottom-center", theme = "light", navigate }) {
2864
- const [phase, setPhase] = useState4("boot");
2865
- const [session, setSession] = useState4(null);
2866
- const [member, setMember] = useState4(null);
2867
- const [threads, setThreads] = useState4([]);
2868
- const [route, setRoute] = useState4("/");
2869
- const [surface, setSurface] = useState4("none");
2870
- const [tab, setTab] = useState4("page");
2871
- const [mode, setMode] = useState4("browse");
2872
- const [reattachId, setReattachId] = useState4(null);
2873
- const [activeId, setActiveId] = useState4(null);
2874
- const [peekId, setPeekId] = useState4(null);
2875
- const [draft, setDraft] = useState4(null);
2876
- const [body, setBody] = useState4("");
2877
- const [reply, setReply] = useState4("");
2878
- const [name, setName] = useState4("");
2879
- const [passphrase, setPassphrase] = useState4("");
2880
- const [email, setEmail] = useState4("");
2881
- const [members, setMembers] = useState4([]);
2882
- const [profile, setProfile] = useState4(null);
2883
- const [deliveries, setDeliveries] = useState4({});
2884
- const [invite, setInvite] = useState4(null);
2885
- const [capturing, setCapturing] = useState4(false);
2886
- const [inviteLink, setInviteLink] = useState4(null);
2887
- const [renaming, setRenaming] = useState4(null);
2888
- const [confirmReset, setConfirmReset] = useState4(false);
2889
- const [error, setError] = useState4("");
2890
- const [toast, setToast] = useState4("");
2891
- const [busy, setBusy] = useState4(false);
2892
- const [prefs, setPrefs] = useState4({});
2893
- const [portal, setPortal] = useState4(null);
2894
- const [mounted, setMounted] = useState4(false);
2895
- const [highlight, setHighlight] = useState4(null);
2896
- const [flash, setFlash] = useState4(null);
2897
- const [placed, setPlaced] = useState4([]);
2898
- const [systemDark, setSystemDark] = useState4(false);
2899
- const [settings, setSettings] = useState4(null);
2900
- const [draftDetails, setDraftDetails] = useState4(noDetails);
2901
- const [editingId, setEditingId] = useState4(null);
3046
+ const [phase, setPhase] = useState5("boot");
3047
+ const [session, setSession] = useState5(null);
3048
+ const [member, setMember] = useState5(null);
3049
+ const [threads, setThreads] = useState5([]);
3050
+ const [route, setRoute] = useState5("/");
3051
+ const [surface, setSurface] = useState5("none");
3052
+ const [tab, setTab] = useState5("page");
3053
+ const [mode, setMode] = useState5("browse");
3054
+ const [reattachId, setReattachId] = useState5(null);
3055
+ const [activeId, setActiveId] = useState5(null);
3056
+ const [peekId, setPeekId] = useState5(null);
3057
+ const [draft, setDraft] = useState5(null);
3058
+ const [body, setBody] = useState5("");
3059
+ const [reply, setReply] = useState5("");
3060
+ const [name, setName] = useState5("");
3061
+ const [passphrase, setPassphrase] = useState5("");
3062
+ const [email, setEmail] = useState5("");
3063
+ const [members, setMembers] = useState5([]);
3064
+ const [profile, setProfile] = useState5(null);
3065
+ const [deliveries, setDeliveries] = useState5({});
3066
+ const [invite, setInvite] = useState5(null);
3067
+ const [capturing, setCapturing] = useState5(false);
3068
+ const [inviteLink, setInviteLink] = useState5(null);
3069
+ const [renaming, setRenaming] = useState5(null);
3070
+ const [confirmReset, setConfirmReset] = useState5(false);
3071
+ const [error, setError] = useState5("");
3072
+ const [toast, setToast] = useState5("");
3073
+ const [busy, setBusy] = useState5(false);
3074
+ const [prefs, setPrefs] = useState5({});
3075
+ const [portal, setPortal] = useState5(null);
3076
+ const [mounted, setMounted] = useState5(false);
3077
+ const [highlight, setHighlight] = useState5(null);
3078
+ const [flash, setFlash] = useState5(null);
3079
+ const [placed, setPlaced] = useState5([]);
3080
+ const [systemDark, setSystemDark] = useState5(false);
3081
+ const [settings, setSettings] = useState5(null);
3082
+ const [draftDetails, setDraftDetails] = useState5(noDetails);
3083
+ const [editingId, setEditingId] = useState5(null);
3084
+ const [view, setView] = useState5("list");
2902
3085
  const threadsRef = useRef3(threads);
2903
3086
  threadsRef.current = threads;
2904
3087
  const modeRef = useRef3(mode);
@@ -3054,22 +3237,23 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3054
3237
  };
3055
3238
  }, [member, session]);
3056
3239
  useEffect2(() => {
3057
- const params = new URLSearchParams(window.location.search);
3058
- pendingThread.current = params.get("cs-thread");
3059
- const code = params.get("cs-invite");
3060
- if (code) {
3061
- setInvite(code);
3062
- const url = new URL(window.location.href);
3063
- url.searchParams.delete("cs-invite");
3064
- history.replaceState(history.state, "", url);
3065
- }
3240
+ captureHandoff();
3241
+ const handoff = readHandoff();
3242
+ pendingThread.current = handoff?.thread ?? null;
3243
+ if (handoff?.invite)
3244
+ setInvite(handoff.invite);
3245
+ stripHandoffFromUrl();
3246
+ }, []);
3247
+ const dropInvite = useCallback2(() => {
3248
+ setInvite(null);
3249
+ dropHandoff("invite");
3066
3250
  }, []);
3067
3251
  useEffect2(() => {
3068
3252
  if (phase === "ready" && !member && (pendingThread.current || invite))
3069
3253
  setSurface("unlock");
3070
3254
  if (member && invite)
3071
- setInvite(null);
3072
- }, [invite, member, phase]);
3255
+ dropInvite();
3256
+ }, [dropInvite, invite, member, phase]);
3073
3257
  useEffect2(() => {
3074
3258
  if (!mounted)
3075
3259
  return;
@@ -3157,12 +3341,13 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3157
3341
  }
3158
3342
  if (!member || event.metaKey || event.ctrlKey || event.altKey || isTyping(event.target))
3159
3343
  return;
3160
- const key = event.key.toLowerCase();
3161
- if (key === "c")
3344
+ const key2 = event.key.toLowerCase();
3345
+ if (key2 === "c")
3162
3346
  startComment();
3163
- else if (key === "i")
3347
+ else if (key2 === "i") {
3348
+ setView(prefs.view ?? "list");
3164
3349
  setSurface((current) => current === "inbox" ? "none" : "inbox");
3165
- else if (key === "h")
3350
+ } else if (key2 === "h")
3166
3351
  togglePins();
3167
3352
  else
3168
3353
  return;
@@ -3170,7 +3355,7 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3170
3355
  };
3171
3356
  document.addEventListener("keydown", onKey);
3172
3357
  return () => document.removeEventListener("keydown", onKey);
3173
- }, [draft, member, mode, startComment, surface, togglePins]);
3358
+ }, [draft, member, mode, prefs.view, startComment, surface, togglePins]);
3174
3359
  useEffect2(() => {
3175
3360
  if (mode === "browse") {
3176
3361
  setHighlight(null);
@@ -3255,19 +3440,19 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3255
3440
  all: open.length,
3256
3441
  resolved: placed.length - open.length
3257
3442
  };
3258
- const listed = useMemo2(() => {
3443
+ const listed = useMemo3(() => {
3259
3444
  if (tab === "resolved")
3260
3445
  return placed.filter((item) => item.thread.status === "resolved");
3261
3446
  const openOnly = placed.filter((item) => item.thread.status === "open");
3262
3447
  return tab === "page" ? openOnly.filter((item) => item.thread.route === route) : openOnly;
3263
3448
  }, [placed, route, tab]);
3264
- const groups = useMemo2(() => {
3449
+ const groups = useMemo3(() => {
3265
3450
  if (tab !== "all")
3266
3451
  return [{ route: null, items: listed }];
3267
3452
  const byRoute = /* @__PURE__ */ new Map();
3268
3453
  for (const item of listed)
3269
3454
  byRoute.set(item.thread.route, [...byRoute.get(item.thread.route) ?? [], item]);
3270
- return [...byRoute.entries()].sort(([a], [b]) => a === route ? -1 : b === route ? 1 : a.localeCompare(b)).map(([key, items]) => ({ route: key, items }));
3455
+ return [...byRoute.entries()].sort(([a], [b]) => a === route ? -1 : b === route ? 1 : a.localeCompare(b)).map(([key2, items]) => ({ route: key2, items }));
3271
3456
  }, [listed, route, tab]);
3272
3457
  const showOnPage = useCallback2((thread) => {
3273
3458
  const { element } = resolveInDocument(thread.anchor, window.location.pathname);
@@ -3288,9 +3473,7 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3288
3473
  if (!item)
3289
3474
  return;
3290
3475
  pendingThread.current = null;
3291
- const url = new URL(window.location.href);
3292
- url.searchParams.delete("cs-thread");
3293
- history.replaceState(history.state, "", url);
3476
+ dropHandoff("thread");
3294
3477
  setTab(item.thread.status === "resolved" ? "resolved" : item.thread.route === route ? "page" : "all");
3295
3478
  setActiveId(id);
3296
3479
  setSurface("inbox");
@@ -3313,9 +3496,9 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3313
3496
  arrival.current = null;
3314
3497
  showOnPage(item.thread);
3315
3498
  }, [placed, showOnPage]);
3316
- const select = useCallback2((item) => {
3499
+ const select = useCallback2((item, keepOpen = false) => {
3317
3500
  const { thread } = item;
3318
- if (activeId === thread.id) {
3501
+ if (!keepOpen && activeId === thread.id) {
3319
3502
  setActiveId(null);
3320
3503
  return;
3321
3504
  }
@@ -3331,9 +3514,7 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3331
3514
  navigate(target);
3332
3515
  return;
3333
3516
  }
3334
- const url = new URL(target, window.location.origin);
3335
- url.searchParams.set("cs-thread", thread.id);
3336
- window.location.assign(url.toString());
3517
+ window.location.assign(linkWith(target, "cs-thread", thread.id));
3337
3518
  }, [activeId, navigate, route]);
3338
3519
  if (!mounted || phase !== "ready" || !session)
3339
3520
  return null;
@@ -3378,22 +3559,23 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3378
3559
  setDraft(null);
3379
3560
  setSurface("unlock");
3380
3561
  };
3381
- const bar = _jsx5("div", { className: "cs-bar cs-hit", "data-cs-ui": "bar", role: "toolbar", "aria-label": "Comments toolbar", children: !member ? _jsxs5("button", { className: "cs-bar-lock", "data-cs-ui": "launcher", type: "button", "aria-label": "Comments", onClick: () => {
3562
+ const bar = _jsx6("div", { className: "cs-bar cs-hit", "data-cs-ui": "bar", role: "toolbar", "aria-label": "Comments toolbar", children: !member ? _jsxs6("button", { className: "cs-bar-lock", "data-cs-ui": "launcher", type: "button", "aria-label": "Comments", onClick: () => {
3382
3563
  setError("");
3383
3564
  setSurface(surface === "unlock" ? "none" : "unlock");
3384
- }, children: [_jsx5(Lock, {}), _jsx5("span", { children: "Comments" })] }) : _jsxs5(_Fragment3, { children: [_jsx5("button", { className: mode === "select" ? "cs-tool is-on is-accent" : "cs-tool", "data-cs-ui": "comment-mode", "data-tip": "Comment C", type: "button", "aria-label": "Add comment", "aria-pressed": mode === "select", onClick: startComment, children: _jsx5(AddComment, {}) }), _jsxs5("button", { className: surface === "inbox" ? "cs-tool is-on" : "cs-tool", "data-cs-ui": "launcher", "data-tip": "Comments I", type: "button", "aria-label": "Comments", "aria-expanded": surface === "inbox", onClick: () => {
3565
+ }, children: [_jsx6(Lock, {}), _jsx6("span", { children: "Comments" })] }) : _jsxs6(_Fragment3, { children: [_jsx6("button", { className: mode === "select" ? "cs-tool is-on is-accent" : "cs-tool", "data-cs-ui": "comment-mode", "data-tip": "Comment C", type: "button", "aria-label": "Add comment", "aria-pressed": mode === "select", onClick: startComment, children: _jsx6(AddComment, {}) }), _jsxs6("button", { className: surface === "inbox" ? "cs-tool is-on" : "cs-tool", "data-cs-ui": "launcher", "data-tip": "Comments I", type: "button", "aria-label": "Comments", "aria-expanded": surface === "inbox", onClick: () => {
3385
3566
  setError("");
3386
3567
  setMode("browse");
3568
+ setView(prefs.view ?? "list");
3387
3569
  setSurface(surface === "inbox" ? "none" : "inbox");
3388
- }, children: [_jsx5(Inbox, {}), counts.page > 0 ? _jsx5("span", { className: "cs-badge", children: counts.page }) : null] }), _jsx5("button", { className: pinsHidden ? "cs-tool is-on" : "cs-tool", "data-cs-ui": "pins-toggle", "data-tip": pinsHidden ? "Show pins H" : "Hide pins H", type: "button", "aria-label": pinsHidden ? "Show pins" : "Hide pins", "aria-pressed": pinsHidden, onClick: togglePins, children: pinsHidden ? _jsx5(EyeOff, {}) : _jsx5(Eye, {}) }), _jsx5("span", { className: "cs-divider" }), _jsx5("button", { className: surface === "menu" ? "cs-tool cs-me is-on" : "cs-tool cs-me", "data-cs-ui": "menu-button", "data-tip": memberName, type: "button", "aria-label": "You", "aria-expanded": surface === "menu", onClick: () => {
3570
+ }, children: [_jsx6(Inbox, {}), counts.page > 0 ? _jsx6("span", { className: "cs-badge", children: counts.page }) : null] }), _jsx6("button", { className: pinsHidden ? "cs-tool is-on" : "cs-tool", "data-cs-ui": "pins-toggle", "data-tip": pinsHidden ? "Show pins H" : "Hide pins H", type: "button", "aria-label": pinsHidden ? "Show pins" : "Hide pins", "aria-pressed": pinsHidden, onClick: togglePins, children: pinsHidden ? _jsx6(EyeOff, {}) : _jsx6(Eye, {}) }), _jsx6("span", { className: "cs-divider" }), _jsx6("button", { className: surface === "menu" ? "cs-tool cs-me is-on" : "cs-tool cs-me", "data-cs-ui": "menu-button", "data-tip": memberName, type: "button", "aria-label": "You", "aria-expanded": surface === "menu", onClick: () => {
3389
3571
  setConfirmReset(false);
3390
3572
  setRenaming(null);
3391
3573
  if (surface !== "menu" && member) {
3392
3574
  getProfile(session, member).then(setProfile).catch(() => void 0);
3393
3575
  }
3394
3576
  setSurface(surface === "menu" ? "none" : "menu");
3395
- }, children: _jsx5(Avatar, { name: memberName, size: 24 }) })] }) });
3396
- const unlockCard = _jsxs5("section", { className: "cs-card cs-unlock cs-hit", "data-cs-ui": "panel", "aria-label": "Unlock comments", children: [_jsx5("div", { className: "cs-unlock-icon", children: _jsx5(Lock, { size: 18 }) }), _jsx5("h2", { children: "Comments" }), _jsx5("p", { className: "cs-sub", children: invite ? `${readJwt(invite)?.name ?? "A teammate"} invited you to comment. Add your name and email to join.` : "Enter the team passphrase to see and add comments." }), _jsxs5("form", { onSubmit: (event) => {
3577
+ }, children: _jsx6(Avatar, { name: memberName, size: 24 }) })] }) });
3578
+ const unlockCard = _jsxs6("section", { className: "cs-card cs-unlock cs-hit", "data-cs-ui": "panel", "aria-label": "Unlock comments", children: [_jsx6("div", { className: "cs-unlock-icon", children: _jsx6(Lock, { size: 18 }) }), _jsx6("h2", { children: "Comments" }), _jsx6("p", { className: "cs-sub", children: invite ? `${readJwt(invite)?.name ?? "A teammate"} invited you to comment. Add your name and email to join.` : "Enter the team passphrase to see and add comments." }), _jsxs6("form", { onSubmit: (event) => {
3397
3579
  event.preventDefault();
3398
3580
  setBusy(true);
3399
3581
  setError("");
@@ -3406,16 +3588,16 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3406
3588
  localStorage.setItem(storageKey(fresh), token);
3407
3589
  setMember(token);
3408
3590
  setPassphrase("");
3409
- setInvite(null);
3591
+ dropInvite();
3410
3592
  setTab("page");
3411
3593
  setSurface("inbox");
3412
3594
  }).catch((caught) => {
3413
3595
  if (caught instanceof ApiError && caught.code === "invalid_invite")
3414
- setInvite(null);
3596
+ dropInvite();
3415
3597
  setError(caught instanceof Error ? caught.message : "Couldn\u2019t unlock.");
3416
3598
  }).finally(() => setBusy(false));
3417
- }, children: [_jsxs5("label", { className: "cs-field", children: [_jsx5("span", { children: "Your name" }), _jsx5("input", { "data-cs-ui": "unlock-name", value: name, onChange: (event) => setName(event.target.value), autoComplete: "name", required: true })] }), invite ? null : _jsxs5("label", { className: "cs-field", children: [_jsx5("span", { children: "Passphrase" }), _jsx5("input", { "data-cs-ui": "unlock-passphrase", type: "password", value: passphrase, onChange: (event) => setPassphrase(event.target.value), autoComplete: "current-password", required: true })] }), _jsxs5("label", { className: "cs-field", children: [_jsx5("span", { children: "Email" }), _jsx5("input", { "data-cs-ui": "unlock-email", type: "email", value: email, onChange: (event) => setEmail(event.target.value), autoComplete: "email", required: true }), _jsx5("small", { children: "So teammates can @mention you." })] }), error ? _jsx5("p", { className: "cs-error", "data-cs-ui": "error", children: error }) : null, _jsx5("button", { className: "cs-button is-primary is-wide", "data-cs-ui": "unlock-submit", type: "submit", disabled: busy, children: busy ? "Unlocking\u2026" : invite ? "Join" : "Unlock" })] })] });
3418
- const menuCard = _jsx5("section", { className: "cs-card cs-menu cs-hit", "data-cs-ui": "menu", "aria-label": "Your comment settings", children: confirmReset ? _jsxs5("div", { className: "cs-confirm", "data-cs-ui": "reset-confirm", children: [_jsx5("h2", { children: "Reset on this device?" }), _jsx5("p", { className: "cs-sub", children: "You\u2019ll be signed out and your name and preferences are cleared. Comments aren\u2019t affected." }), _jsxs5("div", { className: "cs-row-end", children: [_jsx5("button", { className: "cs-button", type: "button", onClick: () => setConfirmReset(false), children: "Cancel" }), _jsx5("button", { className: "cs-button is-danger", "data-cs-ui": "reset-submit", type: "button", onClick: reset, children: "Reset" })] })] }) : _jsxs5(_Fragment3, { children: [_jsxs5("div", { className: "cs-me-row", children: [_jsx5(Avatar, { name: renaming ?? memberName, size: 36 }), renaming != null ? _jsxs5("form", { className: "cs-rename", onSubmit: (event) => {
3599
+ }, children: [_jsxs6("label", { className: "cs-field", children: [_jsx6("span", { children: "Your name" }), _jsx6("input", { "data-cs-ui": "unlock-name", value: name, onChange: (event) => setName(event.target.value), autoComplete: "name", required: true })] }), invite ? null : _jsxs6("label", { className: "cs-field", children: [_jsx6("span", { children: "Passphrase" }), _jsx6("input", { "data-cs-ui": "unlock-passphrase", type: "password", value: passphrase, onChange: (event) => setPassphrase(event.target.value), autoComplete: "current-password", required: true })] }), _jsxs6("label", { className: "cs-field", children: [_jsx6("span", { children: "Email" }), _jsx6("input", { "data-cs-ui": "unlock-email", type: "email", value: email, onChange: (event) => setEmail(event.target.value), autoComplete: "email", required: true }), _jsx6("small", { children: "So teammates can @mention you." })] }), error ? _jsx6("p", { className: "cs-error", "data-cs-ui": "error", children: error }) : null, _jsx6("button", { className: "cs-button is-primary is-wide", "data-cs-ui": "unlock-submit", type: "submit", disabled: busy, children: busy ? "Unlocking\u2026" : invite ? "Join" : "Unlock" })] })] });
3600
+ const menuCard = _jsx6("section", { className: "cs-card cs-menu cs-hit", "data-cs-ui": "menu", "aria-label": "Your comment settings", children: confirmReset ? _jsxs6("div", { className: "cs-confirm", "data-cs-ui": "reset-confirm", children: [_jsx6("h2", { children: "Reset on this device?" }), _jsx6("p", { className: "cs-sub", children: "You\u2019ll be signed out and your name and preferences are cleared. Comments aren\u2019t affected." }), _jsxs6("div", { className: "cs-row-end", children: [_jsx6("button", { className: "cs-button", type: "button", onClick: () => setConfirmReset(false), children: "Cancel" }), _jsx6("button", { className: "cs-button is-danger", "data-cs-ui": "reset-submit", type: "button", onClick: reset, children: "Reset" })] })] }) : _jsxs6(_Fragment3, { children: [_jsxs6("div", { className: "cs-me-row", children: [_jsx6(Avatar, { name: renaming ?? memberName, size: 36 }), renaming != null ? _jsxs6("form", { className: "cs-rename", onSubmit: (event) => {
3419
3601
  event.preventDefault();
3420
3602
  const next = renaming.trim();
3421
3603
  if (!next || next === memberName || !member) {
@@ -3431,15 +3613,15 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3431
3613
  setRenaming(null);
3432
3614
  say("Name updated");
3433
3615
  }).catch((caught) => setError(caught instanceof Error ? caught.message : "Couldn\u2019t rename.")).finally(() => setBusy(false));
3434
- }, children: [_jsx5("input", { "data-cs-ui": "rename-input", "aria-label": "Your name", value: renaming, maxLength: 40, autoFocus: true, onChange: (event) => setRenaming(event.target.value), onKeyDown: (event) => {
3616
+ }, children: [_jsx6("input", { "data-cs-ui": "rename-input", "aria-label": "Your name", value: renaming, maxLength: 40, autoFocus: true, onChange: (event) => setRenaming(event.target.value), onKeyDown: (event) => {
3435
3617
  if (event.key === "Escape") {
3436
3618
  event.preventDefault();
3437
3619
  setRenaming(null);
3438
3620
  }
3439
- } }), _jsx5("button", { className: "cs-icon-button", type: "submit", "aria-label": "Save name", disabled: busy, children: _jsx5(Check, {}) })] }) : _jsxs5("div", { className: "cs-me-name", children: [_jsxs5("span", { className: "cs-me-lines", children: [_jsx5("strong", { children: memberName }), _jsx5("small", { children: profile?.email ?? readJwt(member ?? "")?.email ?? "" })] }), _jsx5("button", { className: "cs-icon-button", "data-cs-ui": "rename", type: "button", "aria-label": "Change name", onClick: () => {
3621
+ } }), _jsx6("button", { className: "cs-icon-button", type: "submit", "aria-label": "Save name", disabled: busy, children: _jsx6(Check, {}) })] }) : _jsxs6("div", { className: "cs-me-name", children: [_jsxs6("span", { className: "cs-me-lines", children: [_jsx6("strong", { children: memberName }), _jsx6("small", { children: profile?.email ?? readJwt(member ?? "")?.email ?? "" })] }), _jsx6("button", { className: "cs-icon-button", "data-cs-ui": "rename", type: "button", "aria-label": "Change name", onClick: () => {
3440
3622
  setError("");
3441
3623
  setRenaming(memberName);
3442
- }, children: _jsx5(Pencil, {}) })] })] }), error ? _jsx5("p", { className: "cs-error", children: error }) : null, _jsx5("div", { className: "cs-sep" }), _jsxs5("button", { className: "cs-item", type: "button", role: "switch", "aria-checked": !pinsHidden, onClick: togglePins, children: [_jsx5("span", { children: "Show pins" }), _jsx5("span", { className: pinsHidden ? "cs-switch" : "cs-switch is-on" })] }), _jsxs5("button", { className: "cs-item", "data-cs-ui": "mention-emails", type: "button", role: "switch", "aria-checked": profile?.mentionEmails ?? true, disabled: !profile, onClick: () => {
3624
+ }, children: _jsx6(Pencil, {}) })] })] }), error ? _jsx6("p", { className: "cs-error", children: error }) : null, _jsx6("div", { className: "cs-sep" }), _jsxs6("button", { className: "cs-item", type: "button", role: "switch", "aria-checked": !pinsHidden, onClick: togglePins, children: [_jsx6("span", { children: "Show pins" }), _jsx6("span", { className: pinsHidden ? "cs-switch" : "cs-switch is-on" })] }), _jsxs6("button", { className: "cs-item", "data-cs-ui": "mention-emails", type: "button", role: "switch", "aria-checked": profile?.mentionEmails ?? true, disabled: !profile, onClick: () => {
3443
3625
  if (!member || !profile)
3444
3626
  return;
3445
3627
  updateProfile(session, member, { mentionEmails: !profile.mentionEmails }).then((updated) => {
@@ -3448,39 +3630,46 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3448
3630
  setProfile(updated);
3449
3631
  say(updated.mentionEmails ? "Mention emails on" : "Mention emails off");
3450
3632
  }).catch((caught) => setError(caught instanceof Error ? caught.message : "Couldn\u2019t update."));
3451
- }, children: [_jsx5("span", { children: "Email me when mentioned" }), _jsx5("span", { className: profile?.mentionEmails ?? true ? "cs-switch is-on" : "cs-switch" })] }), _jsxs5("div", { className: "cs-item is-static", children: [_jsx5("span", { children: "Position" }), _jsx5("span", { className: "cs-segment", role: "radiogroup", "aria-label": "Toolbar position", children: positions.map((option) => _jsx5("button", { type: "button", role: "radio", "aria-checked": barPosition === option.value, className: barPosition === option.value ? "is-on" : "", onClick: () => savePrefs({ ...prefs, position: option.value }), children: option.label }, option.value)) })] }), _jsxs5("button", { className: "cs-item", "data-cs-ui": "settings-open", type: "button", onClick: () => {
3633
+ }, children: [_jsx6("span", { children: "Email me when mentioned" }), _jsx6("span", { className: profile?.mentionEmails ?? true ? "cs-switch is-on" : "cs-switch" })] }), _jsxs6("div", { className: "cs-item is-static", children: [_jsx6("span", { children: "Position" }), _jsx6("span", { className: "cs-segment", role: "radiogroup", "aria-label": "Toolbar position", children: positions.map((option) => _jsx6("button", { type: "button", role: "radio", "aria-checked": barPosition === option.value, className: barPosition === option.value ? "is-on" : "", onClick: () => savePrefs({ ...prefs, position: option.value }), children: option.label }, option.value)) })] }), _jsxs6("button", { className: "cs-item", "data-cs-ui": "settings-open", type: "button", onClick: () => {
3452
3634
  setError("");
3453
3635
  setSurface("settings");
3454
- }, children: [_jsx5("span", { children: "Comment fields" }), _jsx5("span", { className: "cs-hint", children: detailsEnabled(settings) ? "On" : "Off" })] }), _jsx5("div", { className: "cs-sep" }), _jsx5("button", { className: "cs-item", "data-cs-ui": "invite", type: "button", disabled: busy, onClick: () => {
3636
+ }, children: [_jsx6("span", { children: "Comment fields" }), _jsx6("span", { className: "cs-hint", children: detailsEnabled(settings) ? "On" : "Off" })] }), _jsx6("div", { className: "cs-sep" }), _jsx6("button", { className: "cs-item", "data-cs-ui": "invite", type: "button", disabled: busy, onClick: () => {
3455
3637
  if (!member)
3456
3638
  return;
3457
3639
  setBusy(true);
3458
3640
  createInvite(session, member).then(({ invite: code }) => {
3459
- const url = new URL(window.location.href);
3460
- url.search = "";
3461
- url.hash = "";
3462
- url.searchParams.set("cs-invite", code);
3463
- const link = url.toString();
3641
+ const link = linkWith(pageHref(), "cs-invite", code);
3464
3642
  setInviteLink(link);
3465
3643
  return navigator.clipboard.writeText(link).then(() => say("Invite link copied")).catch(() => say("Invite link ready"));
3466
3644
  }).catch((caught) => setError(caught instanceof Error ? caught.message : "Couldn\u2019t create an invite.")).finally(() => setBusy(false));
3467
- }, children: _jsx5("span", { children: "Invite someone" }) }), inviteLink ? _jsxs5("div", { className: "cs-invite", children: [_jsx5("input", { "data-cs-ui": "invite-link", "aria-label": "Invite link", readOnly: true, value: inviteLink, onFocus: (event) => event.currentTarget.select() }), _jsx5("p", { className: "cs-hint", children: "Anyone with this link can join for 7 days. Changing the passphrase cancels it." })] }) : null, _jsx5("button", { className: "cs-item", "data-cs-ui": "lock", type: "button", onClick: lock, children: _jsx5("span", { children: "Lock" }) }), _jsx5("button", { className: "cs-item is-danger", "data-cs-ui": "reset", type: "button", onClick: () => setConfirmReset(true), children: _jsx5("span", { children: "Reset on this device\u2026" }) }), _jsx5("p", { className: "cs-hint", children: "C comment \xB7 I list \xB7 H pins" })] }) });
3468
- const inbox = _jsxs5("section", { className: "cs-card cs-sheet cs-hit", "data-cs-ui": "panel", "aria-label": "Comments", children: [_jsxs5("header", { className: "cs-sheet-head", children: [_jsx5("h2", { children: "Comments" }), _jsx5("button", { className: "cs-icon-button", type: "button", "aria-label": "Close comments", onClick: () => setSurface("none"), children: _jsx5(Close, {}) })] }), _jsx5("div", { className: "cs-tabs", role: "tablist", children: [
3645
+ }, children: _jsx6("span", { children: "Invite someone" }) }), inviteLink ? _jsxs6("div", { className: "cs-invite", children: [_jsx6("input", { "data-cs-ui": "invite-link", "aria-label": "Invite link", readOnly: true, value: inviteLink, onFocus: (event) => event.currentTarget.select() }), _jsx6("p", { className: "cs-hint", children: "Anyone with this link can join for 7 days. Changing the passphrase cancels it." })] }) : null, _jsx6("button", { className: "cs-item", "data-cs-ui": "lock", type: "button", onClick: lock, children: _jsx6("span", { children: "Lock" }) }), _jsx6("button", { className: "cs-item is-danger", "data-cs-ui": "reset", type: "button", onClick: () => setConfirmReset(true), children: _jsx6("span", { children: "Reset on this device\u2026" }) }), _jsx6("p", { className: "cs-hint", children: "C comment \xB7 I list \xB7 H pins" })] }) });
3646
+ const tabsBar = _jsx6("div", { className: "cs-tabs", role: "tablist", children: [
3469
3647
  ["page", "This page", counts.page, "scope-page"],
3470
3648
  ["all", "All pages", counts.all, "scope-all"],
3471
3649
  ["resolved", "Resolved", counts.resolved, "scope-resolved"]
3472
- ].map(([value, label, count, hook]) => _jsxs5("button", { type: "button", role: "tab", "aria-selected": tab === value, "data-cs-ui": hook, className: tab === value ? "is-on" : "", onClick: () => setTab(value), children: [label, count > 0 ? _jsx5("span", { className: "cs-count", children: count }) : null] }, value)) }), error ? _jsx5("p", { className: "cs-error cs-pad", "data-cs-ui": "error", children: error }) : null, _jsxs5("div", { className: "cs-list", children: [listed.length === 0 ? _jsxs5("div", { className: "cs-empty", children: [_jsx5("p", { children: tab === "resolved" ? "Nothing resolved yet." : tab === "page" ? "No comments on this page." : "No open comments." }), tab !== "resolved" ? _jsxs5("button", { className: "cs-button", type: "button", onClick: startComment, children: [_jsx5(AddComment, {}), " Add a comment"] }) : null] }) : null, groups.map((group) => _jsxs5("div", { children: [group.route ? _jsx5("div", { className: "cs-group", children: group.route === route ? "This page" : group.route }) : null, group.items.map((item) => {
3650
+ ].map(([value, label, count, hook]) => _jsxs6("button", { type: "button", role: "tab", "aria-selected": tab === value, "data-cs-ui": hook, className: tab === value ? "is-on" : "", onClick: () => setTab(value), children: [label, count > 0 ? _jsx6("span", { className: "cs-count", children: count }) : null] }, value)) });
3651
+ const setViewPref = (next) => {
3652
+ setView(next);
3653
+ savePrefs({ ...prefs, view: next });
3654
+ };
3655
+ const table = _jsx6(CommentTable, { rows: listed, route, activeId, tabs: tabsBar, onList: () => setViewPref("list"), onClose: () => setSurface("none"), onSelect: (row) => {
3656
+ setView("list");
3657
+ const item = placed.find((candidate) => candidate.thread.id === row.thread.id);
3658
+ if (item)
3659
+ select(item, true);
3660
+ } });
3661
+ const inbox = _jsxs6("section", { className: "cs-card cs-sheet cs-hit", "data-cs-ui": "panel", "aria-label": "Comments", children: [_jsxs6("header", { className: "cs-sheet-head", children: [_jsx6("h2", { children: "Comments" }), _jsx6("button", { className: "cs-icon-button cs-push", "data-cs-ui": "table-view", type: "button", "aria-label": "Table view", onClick: () => setViewPref("table"), children: _jsx6(Table, {}) }), _jsx6("button", { className: "cs-icon-button", type: "button", "aria-label": "Close comments", onClick: () => setSurface("none"), children: _jsx6(Close, {}) })] }), tabsBar, error ? _jsx6("p", { className: "cs-error cs-pad", "data-cs-ui": "error", children: error }) : null, _jsxs6("div", { className: "cs-list", children: [listed.length === 0 ? _jsxs6("div", { className: "cs-empty", children: [_jsx6("p", { children: tab === "resolved" ? "Nothing resolved yet." : tab === "page" ? "No comments on this page." : "No open comments." }), tab !== "resolved" ? _jsxs6("button", { className: "cs-button", type: "button", onClick: startComment, children: [_jsx6(AddComment, {}), " Add a comment"] }) : null] }) : null, groups.map((group) => _jsxs6("div", { children: [group.route ? _jsx6("div", { className: "cs-group", children: group.route === route ? "This page" : group.route }) : null, group.items.map((item) => {
3473
3662
  const { thread } = item;
3474
3663
  const expanded = activeId === thread.id;
3475
3664
  const first = thread.messages[0];
3476
3665
  const note = statusNote(item.status, thread.anchor, thread.route === route);
3477
3666
  const onPage = item.status === "pinned" || item.status === "drifted";
3478
- return _jsxs5("article", { className: expanded ? "cs-thread is-open" : "cs-thread", "data-cs-ui": "thread", "data-thread-id": thread.id, "data-cs-status": item.status, children: [_jsxs5("div", { className: "cs-thread-main", role: "button", tabIndex: 0, "aria-expanded": expanded, "aria-label": `${thread.createdBy}: ${first?.body ?? ""}`, onClick: () => select(item), onKeyDown: (event) => {
3667
+ return _jsxs6("article", { className: expanded ? "cs-thread is-open" : "cs-thread", "data-cs-ui": "thread", "data-thread-id": thread.id, "data-cs-status": item.status, children: [_jsxs6("div", { className: "cs-thread-main", role: "button", tabIndex: 0, "aria-expanded": expanded, "aria-label": `${thread.createdBy}: ${first?.body ?? ""}`, onClick: () => select(item), onKeyDown: (event) => {
3479
3668
  if (event.key === "Enter" || event.key === " ") {
3480
3669
  event.preventDefault();
3481
3670
  select(item);
3482
3671
  }
3483
- }, onMouseEnter: () => setPeekId(null), children: [_jsx5(Avatar, { name: thread.createdBy }), _jsxs5("div", { className: "cs-thread-body", children: [_jsxs5("div", { className: "cs-meta", children: [_jsx5("strong", { children: thread.createdBy }), _jsx5("time", { dateTime: thread.createdAt, children: ago(thread.createdAt) }), _jsx5(RoleBadge, { role: thread.role })] }), first?.body ? _jsx5("p", { className: "cs-text", children: _jsx5(MessageText, { body: first.body, mentions: first.mentions }) }) : null, _jsx5(FieldValues, { fields: thread.fields, clamp: !expanded }), _jsx5(MessageAttachments, { attachments: first?.attachments }), first && deliveryText(deliveries[first.id]) ? _jsx5("div", { className: "cs-delivery", "data-cs-ui": "delivery", children: deliveryText(deliveries[first.id]) }) : null, _jsxs5("div", { className: "cs-target", children: [_jsx5("span", { title: thread.anchor.component?.file ?? void 0, children: targetName(thread.anchor) }), note ? _jsx5("span", { className: `cs-note is-${note.tone}`, children: note.text }) : null] }), !expanded && thread.messages.length > 1 ? _jsxs5("div", { className: "cs-replies", children: [thread.messages.length - 1, " ", thread.messages.length === 2 ? "reply" : "replies"] }) : null] })] }), expanded ? _jsxs5("div", { className: "cs-thread-more", children: [editingId === thread.id && settings ? _jsx5(DetailsEditor, { settings, thread, onClose: () => setEditingId(null), onSave: (patch) => updateThread(session, member, thread.id, patch).then(() => refresh()).then(() => say("Details saved")).catch((caught) => setError(caught instanceof Error ? caught.message : "Couldn\u2019t save.")) }) : null, thread.messages.slice(1).map((message) => _jsxs5("div", { className: "cs-message", children: [_jsx5(Avatar, { name: message.author, size: 20 }), _jsxs5("div", { children: [_jsxs5("div", { className: "cs-meta", children: [_jsx5("strong", { children: message.author }), _jsx5("time", { dateTime: message.createdAt, children: ago(message.createdAt) })] }), _jsx5("p", { className: "cs-text", children: _jsx5(MessageText, { body: message.body, mentions: message.mentions }) }), _jsx5(MessageAttachments, { attachments: message.attachments }), deliveryText(deliveries[message.id]) ? _jsx5("div", { className: "cs-delivery", "data-cs-ui": "delivery", children: deliveryText(deliveries[message.id]) }) : null] })] }, message.id)), _jsxs5("form", { className: "cs-reply", onSubmit: async (event) => {
3672
+ }, onMouseEnter: () => setPeekId(null), children: [_jsx6(Avatar, { name: thread.createdBy }), _jsxs6("div", { className: "cs-thread-body", children: [_jsxs6("div", { className: "cs-meta", children: [_jsx6("strong", { children: thread.createdBy }), _jsx6("time", { dateTime: thread.createdAt, children: ago(thread.createdAt) }), _jsx6(RoleBadge, { role: thread.role })] }), first?.body ? _jsx6("p", { className: "cs-text", children: _jsx6(MessageText, { body: first.body, mentions: first.mentions }) }) : null, _jsx6(FieldValues, { fields: thread.fields, clamp: !expanded }), _jsx6(MessageAttachments, { attachments: first?.attachments }), first && deliveryText(deliveries[first.id]) ? _jsx6("div", { className: "cs-delivery", "data-cs-ui": "delivery", children: deliveryText(deliveries[first.id]) }) : null, _jsxs6("div", { className: "cs-target", children: [_jsx6("span", { title: thread.anchor.component?.file ?? void 0, children: targetName(thread.anchor) }), note ? _jsx6("span", { className: `cs-note is-${note.tone}`, children: note.text }) : null] }), !expanded && thread.messages.length > 1 ? _jsxs6("div", { className: "cs-replies", children: [thread.messages.length - 1, " ", thread.messages.length === 2 ? "reply" : "replies"] }) : null] })] }), expanded ? _jsxs6("div", { className: "cs-thread-more", children: [editingId === thread.id && settings ? _jsx6(DetailsEditor, { settings, thread, onClose: () => setEditingId(null), onSave: (patch) => updateThread(session, member, thread.id, patch).then(() => refresh()).then(() => say("Details saved")).catch((caught) => setError(caught instanceof Error ? caught.message : "Couldn\u2019t save.")) }) : null, thread.messages.slice(1).map((message) => _jsxs6("div", { className: "cs-message", children: [_jsx6(Avatar, { name: message.author, size: 20 }), _jsxs6("div", { children: [_jsxs6("div", { className: "cs-meta", children: [_jsx6("strong", { children: message.author }), _jsx6("time", { dateTime: message.createdAt, children: ago(message.createdAt) })] }), _jsx6("p", { className: "cs-text", children: _jsx6(MessageText, { body: message.body, mentions: message.mentions }) }), _jsx6(MessageAttachments, { attachments: message.attachments }), deliveryText(deliveries[message.id]) ? _jsx6("div", { className: "cs-delivery", "data-cs-ui": "delivery", children: deliveryText(deliveries[message.id]) }) : null] })] }, message.id)), _jsxs6("form", { className: "cs-reply", onSubmit: async (event) => {
3484
3673
  event.preventDefault();
3485
3674
  if (!member || !reply.trim() && !replyFiles.ids.length || replyFiles.uploading)
3486
3675
  return;
@@ -3506,7 +3695,7 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3506
3695
  }
3507
3696
  await refresh();
3508
3697
  }).catch((caught) => setError(caught instanceof Error ? caught.message : "Couldn\u2019t reply.")).finally(() => setBusy(false));
3509
- }, children: [_jsx5(MentionTextarea, { "data-cs-ui": "reply-body", "aria-label": "Reply", placeholder: "Reply\u2026 (@ to mention)", rows: 1, value: reply, onValueChange: setReply, members, selfEmail: readJwt(member ?? "")?.email, onMention: (person) => {
3698
+ }, children: [_jsx6(MentionTextarea, { "data-cs-ui": "reply-body", "aria-label": "Reply", placeholder: "Reply\u2026 (@ to mention)", rows: 1, value: reply, onValueChange: setReply, members, selfEmail: readJwt(member ?? "")?.email, onMention: (person) => {
3510
3699
  replyPicked.current.set(person.id, person);
3511
3700
  const element = thread.route === route ? resolveInDocument(thread.anchor, route).element : null;
3512
3701
  if (element && !replyShot.current)
@@ -3517,25 +3706,25 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3517
3706
  event.preventDefault();
3518
3707
  replyFiles.add(files);
3519
3708
  }
3520
- } }), _jsx5(AttachButtons, { onFiles: replyFiles.add, capturing, onSnapshot: () => snapshot(thread.route === route ? resolveInDocument(thread.anchor, route).element : null, replyFiles.add) }), _jsx5("button", { className: "cs-send", "data-cs-ui": "reply-submit", type: "submit", "aria-label": "Post reply", disabled: busy || replyFiles.uploading || !reply.trim() && !replyFiles.ids.length, children: _jsx5(Send, {}) })] }), _jsx5(AttachmentTray, { items: replyFiles.items, onRemove: replyFiles.remove }), _jsxs5("div", { className: "cs-actions", children: [_jsxs5("button", { className: "cs-button", "data-cs-ui": "resolve", type: "button", onClick: () => {
3709
+ } }), _jsx6(AttachButtons, { onFiles: replyFiles.add, capturing, onSnapshot: () => snapshot(thread.route === route ? resolveInDocument(thread.anchor, route).element : null, replyFiles.add) }), _jsx6("button", { className: "cs-send", "data-cs-ui": "reply-submit", type: "submit", "aria-label": "Post reply", disabled: busy || replyFiles.uploading || !reply.trim() && !replyFiles.ids.length, children: _jsx6(Send, {}) })] }), _jsx6(AttachmentTray, { items: replyFiles.items, onRemove: replyFiles.remove }), _jsxs6("div", { className: "cs-actions", children: [_jsxs6("button", { className: "cs-button", "data-cs-ui": "resolve", type: "button", onClick: () => {
3521
3710
  if (!member)
3522
3711
  return;
3523
3712
  const next = thread.status === "resolved" ? "open" : "resolved";
3524
3713
  updateThread(session, member, thread.id, { status: next }).then(() => refresh()).then(() => say(next === "resolved" ? "Resolved" : "Reopened")).catch((caught) => setError(caught instanceof Error ? caught.message : "Couldn\u2019t update."));
3525
- }, children: [thread.status === "resolved" ? _jsx5(Undo, {}) : _jsx5(Check, {}), thread.status === "resolved" ? "Reopen" : "Resolve"] }), onPage && thread.status === "open" ? _jsxs5("button", { className: "cs-button", type: "button", onClick: () => showOnPage(thread), children: [_jsx5(Target, {}), " Show"] }) : null, detailsEnabled(settings) && editingId !== thread.id ? _jsxs5("button", { className: "cs-button", "data-cs-ui": "details-edit", type: "button", onClick: () => setEditingId(thread.id), children: [_jsx5(Pencil, {}), " Details"] }) : null, !onPage && thread.status === "open" && thread.route === route ? _jsxs5("button", { className: "cs-button", "data-cs-ui": "reattach", type: "button", onClick: () => {
3714
+ }, children: [thread.status === "resolved" ? _jsx6(Undo, {}) : _jsx6(Check, {}), thread.status === "resolved" ? "Reopen" : "Resolve"] }), onPage && thread.status === "open" ? _jsxs6("button", { className: "cs-button", type: "button", onClick: () => showOnPage(thread), children: [_jsx6(Target, {}), " Show"] }) : null, detailsEnabled(settings) && editingId !== thread.id ? _jsxs6("button", { className: "cs-button", "data-cs-ui": "details-edit", type: "button", onClick: () => setEditingId(thread.id), children: [_jsx6(Pencil, {}), " Details"] }) : null, !onPage && thread.status === "open" && thread.route === route ? _jsxs6("button", { className: "cs-button", "data-cs-ui": "reattach", type: "button", onClick: () => {
3526
3715
  setReattachId(thread.id);
3527
3716
  setMode("reattach");
3528
3717
  setSurface("none");
3529
- }, children: [_jsx5(Relink, {}), " Reattach"] }) : null] })] }) : null] }, thread.id);
3718
+ }, children: [_jsx6(Relink, {}), " Reattach"] }) : null] })] }) : null] }, thread.id);
3530
3719
  })] }, group.route ?? "all"))] })] });
3531
- const ui = _jsxs5("div", { id: "cs-root", className: [
3720
+ const ui = _jsxs6("div", { id: "cs-root", className: [
3532
3721
  inside ? "cs-inside" : "cs-fixed",
3533
3722
  `cs-at-${barPosition.replace("bottom-", "")}`,
3534
3723
  theme === "dark" || theme === "system" && systemDark ? "cs-dark" : ""
3535
- ].join(" "), children: [highlight ? _jsxs5(_Fragment3, { children: [_jsx5("div", { className: "cs-outline", style: { top: highlight.top, left: highlight.left, width: highlight.width, height: highlight.height } }), _jsx5("div", { className: "cs-outline-label", style: { top: Math.max(4, highlight.top - 26), left: highlight.left }, children: highlight.label })] }) : null, flash ? _jsx5("div", { className: "cs-outline is-flash", style: { top: flash.top, left: flash.left, width: flash.width, height: flash.height } }) : null, mode !== "browse" ? _jsxs5("div", { className: "cs-banner cs-hit", "data-cs-ui": "mode", children: [_jsx5(Cursor, {}), _jsx5("span", { children: mode === "reattach" ? "Click the element this comment belongs to" : "Click anything to comment" }), _jsx5("button", { type: "button", onClick: () => {
3724
+ ].join(" "), children: [highlight ? _jsxs6(_Fragment3, { children: [_jsx6("div", { className: "cs-outline", style: { top: highlight.top, left: highlight.left, width: highlight.width, height: highlight.height } }), _jsx6("div", { className: "cs-outline-label", style: { top: Math.max(4, highlight.top - 26), left: highlight.left }, children: highlight.label })] }) : null, flash ? _jsx6("div", { className: "cs-outline is-flash", style: { top: flash.top, left: flash.left, width: flash.width, height: flash.height } }) : null, mode !== "browse" ? _jsxs6("div", { className: "cs-banner cs-hit", "data-cs-ui": "mode", children: [_jsx6(Cursor, {}), _jsx6("span", { children: mode === "reattach" ? "Click the element this comment belongs to" : "Click anything to comment" }), _jsx6("button", { type: "button", onClick: () => {
3536
3725
  setMode("browse");
3537
3726
  setReattachId(null);
3538
- }, children: "Cancel" })] }) : null, pinsHidden ? null : placed.map((item) => item.top == null || item.left == null || item.status !== "pinned" && item.status !== "drifted" ? null : _jsxs5("button", { type: "button", className: [
3727
+ }, children: "Cancel" })] }) : null, pinsHidden ? null : placed.map((item) => item.top == null || item.left == null || item.status !== "pinned" && item.status !== "drifted" ? null : _jsxs6("button", { type: "button", className: [
3539
3728
  "cs-pin",
3540
3729
  item.status === "drifted" ? "is-drifted" : "",
3541
3730
  activeId === item.thread.id && surface === "inbox" ? "is-active" : ""
@@ -3544,7 +3733,7 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3544
3733
  setTab("page");
3545
3734
  setActiveId(item.thread.id);
3546
3735
  setSurface("inbox");
3547
- }, children: [_jsx5(Avatar, { name: item.thread.createdBy, size: 22 }), item.thread.messages.length > 1 ? _jsx5("span", { className: "cs-pin-count", children: item.thread.messages.length }) : null] }, item.thread.id)), peek && !pinsHidden && peek.top != null && peek.left != null ? _jsxs5("div", { className: "cs-peek", style: { top: peek.top + 18, left: Math.max(8, peek.left - 12) }, children: [_jsxs5("div", { className: "cs-meta", children: [_jsx5(Avatar, { name: peek.thread.createdBy, size: 18 }), _jsx5("strong", { children: peek.thread.createdBy }), _jsx5("time", { children: ago(peek.thread.createdAt) })] }), _jsx5("p", { className: "cs-text", children: _jsx5(MessageText, { body: peek.thread.messages[0]?.body ?? "", mentions: peek.thread.messages[0]?.mentions }) }), peek.thread.messages.length > 1 ? _jsxs5("div", { className: "cs-replies", children: [peek.thread.messages.length - 1, " ", peek.thread.messages.length === 2 ? "reply" : "replies"] }) : null] }) : null, draft ? _jsxs5("form", { className: "cs-card cs-composer cs-hit", "data-cs-ui": "composer", style: { top: draft.top, left: draft.left }, onSubmit: async (event) => {
3736
+ }, children: [_jsx6(Avatar, { name: item.thread.createdBy, size: 22 }), item.thread.messages.length > 1 ? _jsx6("span", { className: "cs-pin-count", children: item.thread.messages.length }) : null] }, item.thread.id)), peek && !pinsHidden && peek.top != null && peek.left != null ? _jsxs6("div", { className: "cs-peek", style: { top: peek.top + 18, left: Math.max(8, peek.left - 12) }, children: [_jsxs6("div", { className: "cs-meta", children: [_jsx6(Avatar, { name: peek.thread.createdBy, size: 18 }), _jsx6("strong", { children: peek.thread.createdBy }), _jsx6("time", { children: ago(peek.thread.createdAt) })] }), _jsx6("p", { className: "cs-text", children: _jsx6(MessageText, { body: peek.thread.messages[0]?.body ?? "", mentions: peek.thread.messages[0]?.mentions }) }), peek.thread.messages.length > 1 ? _jsxs6("div", { className: "cs-replies", children: [peek.thread.messages.length - 1, " ", peek.thread.messages.length === 2 ? "reply" : "replies"] }) : null] }) : null, draft ? _jsxs6("form", { className: "cs-card cs-composer cs-hit", "data-cs-ui": "composer", style: { top: draft.top, left: draft.left }, onSubmit: async (event) => {
3548
3737
  event.preventDefault();
3549
3738
  if (!member || !canPost || draftFiles.uploading)
3550
3739
  return;
@@ -3578,7 +3767,7 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3578
3767
  setSurface("inbox");
3579
3768
  await refresh();
3580
3769
  }).catch((caught) => setError(caught instanceof Error ? caught.message : "Couldn\u2019t post.")).finally(() => setBusy(false));
3581
- }, children: [_jsxs5("div", { className: "cs-composer-target", children: [_jsx5(Target, {}), _jsx5("span", { className: "cs-composer-name", children: targetName(draft.anchor) }), draft.anchor.component?.file ? _jsx5("code", { children: draft.anchor.component.file }) : null, _jsx5("button", { className: "cs-icon-button", type: "button", "aria-label": "Discard", onClick: () => setDraft(null), children: _jsx5(Close, {}) })] }), _jsxs5("div", { className: "cs-composer-body", children: [_jsx5(Avatar, { name: memberName, size: 24 }), _jsx5(MentionTextarea, { "data-cs-ui": "composer-body", "aria-label": "Comment", placeholder: "Add a comment\u2026 (@ to mention)", value: body, autoFocus: true, onValueChange: setBody, members, selfEmail: readJwt(member ?? "")?.email, onMention: (person) => {
3770
+ }, children: [_jsxs6("div", { className: "cs-composer-target", children: [_jsx6(Target, {}), _jsx6("span", { className: "cs-composer-name", children: targetName(draft.anchor) }), draft.anchor.component?.file ? _jsx6("code", { children: draft.anchor.component.file }) : null, _jsx6("button", { className: "cs-icon-button", type: "button", "aria-label": "Discard", onClick: () => setDraft(null), children: _jsx6(Close, {}) })] }), _jsxs6("div", { className: "cs-composer-body", children: [_jsx6(Avatar, { name: memberName, size: 24 }), _jsx6(MentionTextarea, { "data-cs-ui": "composer-body", "aria-label": "Comment", placeholder: "Add a comment\u2026 (@ to mention)", value: body, autoFocus: true, onValueChange: setBody, members, selfEmail: readJwt(member ?? "")?.email, onMention: (person) => {
3582
3771
  draftPicked.current.set(person.id, person);
3583
3772
  if (!draftShot.current)
3584
3773
  draftShot.current = captureAround(draft.element);
@@ -3588,7 +3777,7 @@ function CommentToolbar({ sessionPath = "/api/comment-service/session", pollMs =
3588
3777
  event.preventDefault();
3589
3778
  draftFiles.add(files);
3590
3779
  }
3591
- } })] }), _jsx5(DetailsInput, { settings, value: draftDetails, onChange: setDraftDetails, onKeyDown: submitOnCmdEnter }), _jsx5(AttachmentTray, { items: draftFiles.items, onRemove: draftFiles.remove }), error ? _jsx5("p", { className: "cs-error cs-pad", children: error }) : null, _jsxs5("div", { className: "cs-composer-foot", children: [_jsx5(AttachButtons, { onFiles: draftFiles.add, capturing, onSnapshot: () => snapshot(draft.element, draftFiles.add) }), _jsx5("span", { className: "cs-hint", children: capturing ? "Capturing\u2026" : draftFiles.uploading ? "Uploading\u2026" : busy ? "Posting\u2026" : "\u2318\u21B5 to post" }), _jsx5("button", { className: "cs-send", "data-cs-ui": "composer-submit", type: "submit", "aria-label": "Post comment", disabled: busy || draftFiles.uploading || !canPost, children: _jsx5(Send, {}) })] })] }) : null, surface === "unlock" && !member ? unlockCard : null, surface === "menu" && member ? menuCard : null, surface === "settings" && member ? _jsx5(SettingsPanel, { settings, onChange: changeSettings, onBack: () => setSurface("menu"), error }) : null, surface === "inbox" && member ? inbox : null, toast ? _jsx5("div", { className: "cs-toast", role: "status", children: toast }) : null, bar] });
3780
+ } })] }), _jsx6(DetailsInput, { settings, value: draftDetails, onChange: setDraftDetails, onKeyDown: submitOnCmdEnter }), _jsx6(AttachmentTray, { items: draftFiles.items, onRemove: draftFiles.remove }), error ? _jsx6("p", { className: "cs-error cs-pad", children: error }) : null, _jsxs6("div", { className: "cs-composer-foot", children: [_jsx6(AttachButtons, { onFiles: draftFiles.add, capturing, onSnapshot: () => snapshot(draft.element, draftFiles.add) }), _jsx6("span", { className: "cs-hint", children: capturing ? "Capturing\u2026" : draftFiles.uploading ? "Uploading\u2026" : busy ? "Posting\u2026" : "\u2318\u21B5 to post" }), _jsx6("button", { className: "cs-send", "data-cs-ui": "composer-submit", type: "submit", "aria-label": "Post comment", disabled: busy || draftFiles.uploading || !canPost, children: _jsx6(Send, {}) })] })] }) : null, surface === "unlock" && !member ? unlockCard : null, surface === "menu" && member ? menuCard : null, surface === "settings" && member ? _jsx6(SettingsPanel, { settings, onChange: changeSettings, onBack: () => setSurface("menu"), error }) : null, surface === "inbox" && member ? view === "table" ? table : inbox : null, toast ? _jsx6("div", { className: "cs-toast", role: "status", children: toast }) : null, bar] });
3592
3781
  return createPortal2(ui, host);
3593
3782
  }
3594
3783
  export {
@@ -0,0 +1,15 @@
1
+ export type Handoff = {
2
+ invite?: string;
3
+ thread?: string;
4
+ at: number;
5
+ };
6
+ export declare function readHandoff(): Handoff | null;
7
+ /**
8
+ * Saves invite and thread links for this tab before the app's router or sign-in flow rewrites the URL.
9
+ * Runs when the module loads, which is before hydration, and again when the toolbar mounts.
10
+ */
11
+ export declare function captureHandoff(): void;
12
+ export declare function dropHandoff(part: "invite" | "thread"): void;
13
+ /** Removes the link params from the address bar once they're saved. */
14
+ export declare function stripHandoffFromUrl(): void;
15
+ export declare function linkWith(href: string, name: "cs-invite" | "cs-thread", value: string): string;
@@ -17,3 +17,5 @@ export declare const Paperclip: () => import("react").JSX.Element;
17
17
  export declare const Camera: () => import("react").JSX.Element;
18
18
  export declare const FileIcon: () => import("react").JSX.Element;
19
19
  export declare const Back: () => import("react").JSX.Element;
20
+ export declare const Table: () => import("react").JSX.Element;
21
+ export declare const List: () => import("react").JSX.Element;
@@ -1 +1 @@
1
- export declare const toolbarCss = "\n#cs-root {\n --cs-text: #1d1d1f;\n --cs-text-2: #6e6e73;\n --cs-text-3: #a1a1a6;\n --cs-glass: rgba(251, 251, 253, 0.8);\n --cs-card: rgba(255, 255, 255, 0.94);\n --cs-fill: rgba(0, 0, 0, 0.05);\n --cs-fill-2: rgba(0, 0, 0, 0.08);\n --cs-line: rgba(0, 0, 0, 0.08);\n --cs-edge: rgba(0, 0, 0, 0.1);\n --cs-accent: #007aff;\n --cs-accent-soft: rgba(0, 122, 255, 0.12);\n --cs-danger: #ff3b30;\n --cs-warn: #ff9500;\n --cs-shadow: 0 0 0 0.5px var(--cs-edge), 0 10px 30px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n pointer-events: none;\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n color: var(--cs-text);\n font: 13px/1.4 -apple-system, BlinkMacSystemFont, \"SF Pro Text\", \"Helvetica Neue\", Inter, system-ui, sans-serif;\n letter-spacing: -0.005em;\n -webkit-font-smoothing: antialiased;\n text-align: left;\n}\n#cs-root.cs-dark {\n --cs-text: #f5f5f7;\n --cs-text-2: #a1a1a6;\n --cs-text-3: #6e6e73;\n --cs-glass: rgba(40, 40, 44, 0.78);\n --cs-card: rgba(36, 36, 40, 0.96);\n --cs-fill: rgba(255, 255, 255, 0.07);\n --cs-fill-2: rgba(255, 255, 255, 0.12);\n --cs-line: rgba(255, 255, 255, 0.08);\n --cs-edge: rgba(255, 255, 255, 0.12);\n --cs-accent: #0a84ff;\n --cs-accent-soft: rgba(10, 132, 255, 0.2);\n --cs-shadow: 0 0 0 0.5px var(--cs-edge), 0 10px 30px rgba(0, 0, 0, 0.45);\n}\n#cs-root.cs-inside { position: absolute; }\n#cs-root, #cs-root * { box-sizing: border-box; }\n#cs-root h2, #cs-root p { margin: 0; }\n#cs-root button, #cs-root input, #cs-root textarea {\n font: inherit; color: inherit; letter-spacing: inherit; margin: 0;\n}\n#cs-root button { background: none; border: 0; padding: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; }\n#cs-root button:disabled { cursor: default; opacity: 0.45; }\n#cs-root button:focus-visible, #cs-root [role=button]:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: 2px; }\n#cs-root .cs-hit { pointer-events: auto; }\n#cs-root .cs-icon { display: block; flex: none; }\n\n/* Bar */\n#cs-root .cs-bar {\n position: absolute;\n bottom: 16px;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 4px;\n border-radius: 999px;\n background: var(--cs-glass);\n -webkit-backdrop-filter: saturate(180%) blur(20px);\n backdrop-filter: saturate(180%) blur(20px);\n box-shadow: var(--cs-shadow);\n}\n#cs-root.cs-at-center .cs-bar { left: 50%; transform: translateX(-50%); }\n#cs-root.cs-at-left .cs-bar { left: 16px; }\n#cs-root.cs-at-right .cs-bar { right: 16px; }\n#cs-root .cs-tool {\n position: relative;\n width: 34px;\n height: 34px;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--cs-text);\n transition: background-color 0.15s ease, color 0.15s ease;\n}\n#cs-root .cs-tool:hover { background: var(--cs-fill); }\n#cs-root .cs-tool.is-on { background: var(--cs-fill-2); }\n#cs-root .cs-tool.is-accent { background: var(--cs-accent); color: #fff; }\n#cs-root .cs-tool[data-tip]::after {\n content: attr(data-tip);\n position: absolute;\n bottom: calc(100% + 10px);\n left: 50%;\n transform: translate(-50%, 2px);\n white-space: pre;\n padding: 4px 8px;\n border-radius: 7px;\n background: rgba(29, 29, 31, 0.92);\n color: #fff;\n font-size: 11.5px;\n font-weight: 500;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.12s ease, transform 0.12s ease;\n}\n#cs-root .cs-tool[data-tip]:hover::after { opacity: 1; transform: translate(-50%, 0); transition-delay: 0.35s; }\n#cs-root .cs-me { width: 34px; }\n#cs-root .cs-divider { width: 1px; height: 18px; background: var(--cs-line); margin: 0 3px; }\n#cs-root .cs-badge {\n position: absolute;\n top: 3px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n border-radius: 999px;\n background: var(--cs-accent);\n color: #fff;\n font-size: 10px;\n font-weight: 600;\n line-height: 16px;\n text-align: center;\n box-shadow: 0 0 0 2px var(--cs-glass);\n}\n#cs-root .cs-bar-lock {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n height: 34px;\n padding: 0 14px 0 12px;\n border-radius: 999px;\n font-weight: 500;\n}\n#cs-root .cs-bar-lock:hover { background: var(--cs-fill); }\n#cs-root .cs-avatar {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n border-radius: 999px;\n color: #fff;\n font-weight: 600;\n letter-spacing: 0;\n line-height: 1;\n user-select: none;\n}\n\n/* Cards */\n#cs-root .cs-card {\n position: absolute;\n background: var(--cs-card);\n -webkit-backdrop-filter: saturate(180%) blur(24px);\n backdrop-filter: saturate(180%) blur(24px);\n border-radius: 14px;\n box-shadow: var(--cs-shadow);\n}\n#cs-root .cs-unlock, #cs-root .cs-menu { bottom: 64px; }\n#cs-root.cs-at-center .cs-unlock, #cs-root.cs-at-center .cs-menu { left: 50%; transform: translateX(-50%); }\n#cs-root.cs-at-left .cs-unlock, #cs-root.cs-at-left .cs-menu { left: 16px; }\n#cs-root.cs-at-right .cs-unlock, #cs-root.cs-at-right .cs-menu { right: 16px; }\n#cs-root .cs-unlock { width: 280px; padding: 20px; text-align: center; }\n#cs-root .cs-unlock-icon {\n width: 40px; height: 40px; margin: 0 auto 10px; border-radius: 12px;\n display: flex; align-items: center; justify-content: center; background: var(--cs-fill); color: var(--cs-text-2);\n}\n#cs-root .cs-unlock h2 { font-size: 15px; font-weight: 600; }\n#cs-root .cs-sub { color: var(--cs-text-2); margin-top: 4px; }\n#cs-root .cs-unlock form { margin-top: 14px; display: grid; gap: 8px; text-align: left; }\n#cs-root .cs-field { display: grid; gap: 4px; }\n#cs-root .cs-field span { font-size: 12px; color: var(--cs-text-2); padding-left: 2px; }\n#cs-root input, #cs-root textarea {\n width: 100%;\n border: 0;\n border-radius: 9px;\n background: var(--cs-fill);\n padding: 8px 10px;\n outline: none;\n transition: box-shadow 0.15s ease, background-color 0.15s ease;\n}\n#cs-root input:focus, #cs-root textarea:focus { background: transparent; box-shadow: 0 0 0 1px var(--cs-accent), 0 0 0 4px var(--cs-accent-soft); }\n#cs-root textarea { resize: none; }\n#cs-root .cs-error { color: var(--cs-danger); font-size: 12px; }\n#cs-root .cs-pad { padding: 6px 14px 0; }\n#cs-root .cs-hint { color: var(--cs-text-3); font-size: 11.5px; }\n\n/* Buttons */\n#cs-root .cs-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n height: 28px;\n padding: 0 11px;\n border-radius: 8px;\n background: var(--cs-fill);\n font-size: 12.5px;\n font-weight: 500;\n transition: background-color 0.15s ease;\n}\n#cs-root .cs-button:hover { background: var(--cs-fill-2); }\n#cs-root .cs-button.is-primary { background: var(--cs-accent); color: #fff; }\n#cs-root .cs-button.is-primary:hover { filter: brightness(1.06); }\n#cs-root .cs-button.is-danger { background: var(--cs-danger); color: #fff; }\n#cs-root .cs-button.is-wide { width: 100%; height: 32px; margin-top: 4px; }\n#cs-root .cs-icon-button {\n width: 26px; height: 26px; border-radius: 999px; flex: none;\n display: inline-flex; align-items: center; justify-content: center; color: var(--cs-text-2);\n}\n#cs-root .cs-icon-button:hover { background: var(--cs-fill); color: var(--cs-text); }\n#cs-root .cs-send {\n width: 26px; height: 26px; border-radius: 999px; flex: none;\n display: inline-flex; align-items: center; justify-content: center; background: var(--cs-accent); color: #fff;\n}\n#cs-root .cs-send:disabled { background: var(--cs-fill-2); color: var(--cs-text-3); opacity: 1; }\n\n/* Menu */\n#cs-root .cs-menu { width: 264px; padding: 6px; }\n#cs-root .cs-me-row { display: flex; align-items: center; gap: 10px; padding: 8px 8px 10px; }\n#cs-root .cs-me-name { display: flex; align-items: center; gap: 4px; min-width: 0; }\n#cs-root .cs-me-name strong { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#cs-root .cs-rename { display: flex; align-items: center; gap: 4px; flex: 1; }\n#cs-root .cs-rename input { padding: 5px 8px; }\n#cs-root .cs-sep { height: 1px; background: var(--cs-line); margin: 4px 8px; }\n#cs-root .cs-item {\n display: flex; align-items: center; justify-content: space-between; gap: 10px;\n width: 100%; min-height: 32px; padding: 0 8px; border-radius: 8px; text-align: left;\n}\n#cs-root button.cs-item:hover { background: var(--cs-fill); }\n#cs-root .cs-item.is-danger { color: var(--cs-danger); }\n#cs-root .cs-switch { position: relative; width: 32px; height: 20px; border-radius: 999px; background: var(--cs-fill-2); transition: background-color 0.2s ease; flex: none; }\n#cs-root .cs-switch::after {\n content: \"\"; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 999px;\n background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); transition: transform 0.2s ease;\n}\n#cs-root .cs-switch.is-on { background: #34c759; }\n#cs-root .cs-switch.is-on::after { transform: translateX(12px); }\n#cs-root .cs-segment { display: inline-flex; padding: 2px; border-radius: 8px; background: var(--cs-fill); }\n#cs-root .cs-segment button { padding: 2px 8px; border-radius: 6px; font-size: 12px; color: var(--cs-text-2); }\n#cs-root .cs-segment button.is-on { background: var(--cs-card); color: var(--cs-text); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12); font-weight: 500; }\n#cs-root .cs-menu .cs-hint { padding: 6px 8px 4px; }\n#cs-root .cs-invite { padding: 2px 8px 6px; }\n#cs-root .cs-invite input { font: 11.5px ui-monospace, SFMono-Regular, Menlo, monospace; padding: 6px 8px; }\n#cs-root .cs-invite .cs-hint { padding: 4px 0 0; }\n#cs-root .cs-confirm { padding: 10px; }\n#cs-root .cs-confirm h2 { font-size: 14px; font-weight: 600; }\n#cs-root .cs-row-end { display: flex; justify-content: flex-end; gap: 6px; margin-top: 12px; }\n\n/* Sheet */\n#cs-root .cs-sheet {\n top: 12px; right: 12px; max-height: calc(100% - 88px); width: min(360px, calc(100vw - 24px));\n display: flex; flex-direction: column; overflow: hidden;\n}\n#cs-root .cs-sheet-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 10px 4px 16px; }\n#cs-root .cs-sheet-head h2 { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }\n#cs-root .cs-tabs { display: flex; gap: 2px; margin: 4px 12px 6px; padding: 2px; border-radius: 9px; background: var(--cs-fill); }\n#cs-root .cs-tabs button {\n flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 5px;\n height: 26px; border-radius: 7px; font-size: 12px; font-weight: 500; color: var(--cs-text-2);\n}\n#cs-root .cs-tabs button.is-on { background: var(--cs-card); color: var(--cs-text); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12); }\n#cs-root .cs-count { font-size: 11px; color: var(--cs-text-3); font-variant-numeric: tabular-nums; }\n#cs-root .cs-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 2px 6px 8px; overscroll-behavior: contain; }\n#cs-root .cs-group { padding: 10px 10px 4px; font-size: 11px; font-weight: 600; color: var(--cs-text-3); text-transform: uppercase; letter-spacing: 0.04em; }\n#cs-root .cs-empty { padding: 36px 16px; text-align: center; color: var(--cs-text-2); display: grid; gap: 12px; justify-items: center; }\n#cs-root .cs-thread { border-radius: 10px; }\n#cs-root .cs-thread + .cs-thread { margin-top: 1px; }\n#cs-root .cs-thread.is-open { background: var(--cs-fill); }\n#cs-root .cs-thread-main { display: flex; gap: 10px; padding: 10px; border-radius: 10px; cursor: pointer; }\n#cs-root .cs-thread:not(.is-open) .cs-thread-main:hover { background: var(--cs-fill); }\n#cs-root .cs-thread-body { min-width: 0; flex: 1; }\n#cs-root .cs-meta { display: flex; align-items: center; gap: 6px; font-size: 12.5px; }\n#cs-root .cs-meta strong { font-weight: 600; }\n#cs-root .cs-meta time { color: var(--cs-text-3); font-size: 12px; }\n#cs-root .cs-text { margin-top: 2px; white-space: pre-wrap; overflow-wrap: anywhere; }\n#cs-root .cs-target { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin-top: 4px; font-size: 11.5px; color: var(--cs-text-3); }\n#cs-root .cs-note { display: inline-flex; align-items: center; gap: 5px; font-weight: 500; }\n#cs-root .cs-note::before { content: \"\"; width: 6px; height: 6px; border-radius: 999px; background: currentColor; }\n#cs-root .cs-note.is-quiet { color: var(--cs-text-2); }\n#cs-root .cs-note.is-warn { color: var(--cs-warn); }\n#cs-root .cs-note.is-bad { color: var(--cs-danger); }\n#cs-root .cs-replies { margin-top: 4px; font-size: 12px; color: var(--cs-accent); font-weight: 500; }\n#cs-root .cs-thread-more { padding: 0 10px 10px 44px; display: grid; gap: 10px; }\n#cs-root .cs-message { display: flex; gap: 8px; }\n#cs-root .cs-reply { display: flex; align-items: flex-end; gap: 6px; padding: 4px 4px 4px 0; border-radius: 10px; }\n#cs-root .cs-reply textarea { min-height: 32px; max-height: 120px; field-sizing: content; }\n#cs-root .cs-thread.is-open .cs-reply textarea { background: var(--cs-card); }\n#cs-root .cs-actions { display: flex; flex-wrap: wrap; gap: 6px; }\n#cs-root .cs-thread.is-open .cs-button { background: var(--cs-card); box-shadow: 0 0 0 0.5px var(--cs-edge); }\n#cs-root .cs-thread.is-open .cs-button:hover { background: var(--cs-fill-2); }\n\n/* Mentions */\n#cs-root .cs-mention { color: var(--cs-accent); background: var(--cs-accent-soft); border-radius: 4px; padding: 0 3px; font-weight: 500; }\n#cs-root .cs-delivery { margin-top: 4px; font-size: 11.5px; color: var(--cs-text-3); display: flex; align-items: center; gap: 5px; }\n#cs-root .cs-delivery::before { content: \"\"; width: 6px; height: 6px; border-radius: 999px; background: #34c759; }\n#cs-root .cs-people {\n position: fixed; z-index: 1; width: 264px; padding: 5px; border-radius: 12px;\n background: var(--cs-card); box-shadow: var(--cs-shadow); pointer-events: auto;\n}\n#cs-root .cs-person { display: flex; align-items: center; gap: 9px; padding: 6px 8px; border-radius: 8px; cursor: pointer; }\n#cs-root .cs-person.is-on { background: var(--cs-accent); color: #fff; }\n#cs-root .cs-person-text { display: grid; line-height: 1.25; min-width: 0; }\n#cs-root .cs-person-text strong { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#cs-root .cs-person-text small { font-size: 11.5px; color: var(--cs-text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#cs-root .cs-person.is-on small { color: rgba(255, 255, 255, 0.8); }\n#cs-root .cs-field small { font-size: 11.5px; color: var(--cs-text-3); padding-left: 2px; }\n#cs-root .cs-me-lines { display: grid; line-height: 1.25; min-width: 0; }\n#cs-root .cs-me-lines small { font-size: 11.5px; color: var(--cs-text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n\n/* Composer */\n#cs-root .cs-composer { width: min(320px, calc(100% - 16px)); }\n#cs-root .cs-composer-target {\n display: flex; align-items: center; gap: 6px; padding: 6px 6px 6px 12px;\n border-bottom: 1px solid var(--cs-line); font-size: 12px; color: var(--cs-text-2);\n}\n#cs-root .cs-composer-name { font-weight: 500; color: var(--cs-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n#cs-root .cs-composer-target code {\n margin-left: auto; font: 11px ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--cs-text-3);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; min-width: 0; max-width: 45%;\n}\n#cs-root .cs-composer-body { display: flex; gap: 10px; padding: 12px 12px 4px; }\n#cs-root .cs-composer-body textarea { background: transparent; padding: 3px 0; min-height: 56px; box-shadow: none; border-radius: 0; }\n#cs-root .cs-composer-foot { display: flex; align-items: center; gap: 6px; padding: 6px 8px 8px 40px; }\n#cs-root .cs-composer-foot .cs-hint { margin-left: auto; }\n\n/* Roles and fields */\n#cs-root .cs-details-input { display: grid; gap: 8px; padding: 2px 12px 6px 46px; }\n#cs-root .cs-details-edit .cs-details-input { padding: 0; }\n#cs-root .cs-detail-field { display: grid; gap: 3px; }\n#cs-root .cs-detail-field span, #cs-root .cs-roles-label, #cs-root .cs-detail-list dt {\n font-size: 11px; font-weight: 600; color: var(--cs-text-3); text-transform: uppercase; letter-spacing: 0.03em;\n}\n#cs-root .cs-detail-field textarea { padding: 6px 8px; min-height: 30px; max-height: 120px; field-sizing: content; }\n#cs-root .cs-thread.is-open .cs-detail-field textarea { background: var(--cs-card); }\n#cs-root .cs-roles { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }\n#cs-root .cs-roles-label { margin-right: 4px; }\n#cs-root .cs-chip {\n display: inline-flex; align-items: center; gap: 2px; height: 24px; padding: 0 9px; border-radius: 999px;\n background: var(--cs-fill); font-size: 12px; font-weight: 500; color: var(--cs-text-2);\n}\n#cs-root button.cs-chip:hover { background: var(--cs-fill-2); }\n#cs-root .cs-chip.is-on, #cs-root button.cs-chip.is-on:hover { background: var(--cs-accent); color: #fff; }\n#cs-root .cs-chip.is-static { padding-right: 3px; color: var(--cs-text); }\n#cs-root .cs-chip.is-static button {\n width: 18px; height: 18px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; color: var(--cs-text-3);\n}\n#cs-root .cs-chip.is-static button:hover { background: var(--cs-fill-2); color: var(--cs-text); }\n#cs-root .cs-chip.is-static .cs-icon { width: 11px; height: 11px; }\n#cs-root .cs-chips { display: flex; flex-wrap: wrap; gap: 4px; }\n#cs-root .cs-role {\n display: inline-flex; align-items: center; height: 18px; padding: 0 7px; border-radius: 999px;\n background: var(--cs-accent-soft); color: var(--cs-accent); font-size: 11px; font-weight: 600;\n}\n#cs-root .cs-detail-list { display: grid; gap: 6px; margin: 6px 0 0; }\n#cs-root .cs-detail-list > div { padding: 6px 8px; border-radius: 8px; background: var(--cs-fill); }\n#cs-root .cs-thread.is-open .cs-detail-list > div { background: var(--cs-card); }\n#cs-root .cs-detail-list dd { margin: 1px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }\n#cs-root .cs-detail-list.is-clamped dd { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }\n#cs-root .cs-details-edit { display: grid; gap: 8px; }\n#cs-root .cs-details-edit .cs-row-end { margin-top: 0; }\n#cs-root .cs-settings { width: 280px; }\n#cs-root .cs-settings-head { display: flex; align-items: center; gap: 4px; padding: 4px 4px 6px; }\n#cs-root .cs-settings-head h2 { font-size: 14px; font-weight: 600; }\n#cs-root .cs-settings-body { display: grid; gap: 6px; padding: 2px 8px 8px; }\n#cs-root .cs-field-row { display: flex; align-items: center; justify-content: space-between; gap: 6px; min-height: 28px; padding-left: 2px; }\n#cs-root .cs-add-row { display: flex; align-items: center; gap: 4px; }\n#cs-root .cs-add-row input { padding: 5px 8px; }\n#cs-root .cs-settings .cs-hint { padding: 6px 8px 4px; }\n\n/* Attachments */\n#cs-root .cs-attach { display: inline-flex; gap: 0; flex: none; }\n#cs-root .cs-tray { display: flex; flex-wrap: wrap; gap: 6px; padding: 4px 12px 2px 46px; }\n#cs-root .cs-thread-more .cs-tray { padding: 0; }\n#cs-root .cs-pending {\n position: relative; display: inline-flex; align-items: center; gap: 6px; max-width: 170px; height: 34px;\n padding: 0 24px 0 4px; border-radius: 8px; background: var(--cs-fill); font-size: 11.5px; color: var(--cs-text-2);\n}\n#cs-root .cs-pending img { width: 26px; height: 26px; border-radius: 5px; object-fit: cover; flex: none; }\n#cs-root .cs-pending .cs-icon { margin-left: 4px; }\n#cs-root .cs-pending-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#cs-root .cs-pending.is-uploading { opacity: 0.6; }\n#cs-root .cs-pending.is-failed { box-shadow: inset 0 0 0 1px var(--cs-danger); }\n#cs-root .cs-pending-remove {\n position: absolute; right: 3px; top: 50%; transform: translateY(-50%); width: 18px; height: 18px; border-radius: 999px;\n display: inline-flex; align-items: center; justify-content: center; color: var(--cs-text-3);\n}\n#cs-root .cs-pending-remove:hover { background: var(--cs-fill-2); color: var(--cs-text); }\n#cs-root .cs-pending-remove .cs-icon { width: 11px; height: 11px; margin: 0; }\n#cs-root .cs-files { display: grid; gap: 6px; margin-top: 6px; }\n#cs-root .cs-thumbs { display: flex; flex-wrap: wrap; gap: 6px; }\n#cs-root .cs-thumb { display: block; width: 112px; height: 72px; border-radius: 8px; overflow: hidden; box-shadow: 0 0 0 0.5px var(--cs-edge); background: var(--cs-fill); }\n#cs-root .cs-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }\n#cs-root .cs-file {\n display: inline-flex; align-items: center; gap: 6px; max-width: 100%; padding: 6px 10px; border-radius: 8px;\n background: var(--cs-fill); color: var(--cs-text); text-decoration: none; font-size: 12px; justify-self: start;\n}\n#cs-root .cs-file:hover { background: var(--cs-fill-2); }\n#cs-root .cs-file-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#cs-root .cs-file-size { color: var(--cs-text-3); flex: none; }\n\n/* Page overlays */\n#cs-root .cs-pin {\n position: absolute;\n transform: translate(-50%, -50%);\n padding: 2px;\n border-radius: 999px;\n background: var(--cs-card);\n box-shadow: 0 0 0 0.5px var(--cs-edge), 0 3px 10px rgba(0, 0, 0, 0.18);\n pointer-events: auto;\n transition: transform 0.15s ease;\n}\n#cs-root .cs-pin:hover { transform: translate(-50%, -50%) scale(1.08); }\n#cs-root .cs-pin.is-active { box-shadow: 0 0 0 2px var(--cs-accent), 0 3px 10px rgba(0, 0, 0, 0.18); }\n#cs-root .cs-pin.is-drifted { box-shadow: 0 0 0 1.5px var(--cs-warn), 0 3px 10px rgba(0, 0, 0, 0.18); }\n#cs-root .cs-pin-count {\n position: absolute; top: -5px; right: -6px; min-width: 15px; height: 15px; padding: 0 4px;\n border-radius: 999px; background: var(--cs-text); color: var(--cs-card);\n font-size: 9.5px; font-weight: 700; line-height: 15px; text-align: center;\n}\n#cs-root .cs-peek {\n position: absolute; width: 240px; padding: 10px 12px; border-radius: 12px;\n background: var(--cs-card); box-shadow: var(--cs-shadow); pointer-events: none;\n}\n#cs-root .cs-peek .cs-text { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }\n#cs-root .cs-outline {\n position: absolute; border-radius: 8px; pointer-events: none;\n box-shadow: 0 0 0 2px var(--cs-accent); background: var(--cs-accent-soft);\n}\n#cs-root .cs-outline.is-flash { animation: cs-flash 1.4s ease forwards; }\n@keyframes cs-flash { 0%, 60% { opacity: 1; } 100% { opacity: 0; } }\n#cs-root .cs-outline-label {\n position: absolute; max-width: 360px; padding: 3px 8px; border-radius: 6px; pointer-events: none;\n background: var(--cs-accent); color: #fff; font-size: 11.5px; font-weight: 500;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n}\n#cs-root .cs-banner {\n position: absolute; top: 14px; left: 50%; transform: translateX(-50%);\n display: flex; align-items: center; gap: 8px; padding: 5px 5px 5px 12px; border-radius: 999px;\n background: var(--cs-glass); -webkit-backdrop-filter: saturate(180%) blur(20px); backdrop-filter: saturate(180%) blur(20px);\n box-shadow: var(--cs-shadow); font-weight: 500; white-space: nowrap;\n}\n#cs-root .cs-banner button { padding: 3px 10px; border-radius: 999px; background: var(--cs-fill); font-size: 12px; }\n#cs-root .cs-banner button:hover { background: var(--cs-fill-2); }\n#cs-root .cs-toast {\n position: absolute; top: 14px; left: 50%; transform: translateX(-50%); padding: 6px 12px; border-radius: 999px;\n background: rgba(29, 29, 31, 0.9); color: #fff; font-size: 12px; font-weight: 500;\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2); pointer-events: none; white-space: nowrap;\n}\n\n/* Docked inside an open <dialog> */\n#cs-root.cs-inside .cs-bar { bottom: 8px; }\n#cs-root.cs-inside.cs-at-left .cs-bar { left: 8px; }\n#cs-root.cs-inside.cs-at-right .cs-bar { right: 8px; }\n#cs-root.cs-inside .cs-sheet { top: 8px; right: 8px; bottom: auto; max-height: 46%; width: min(300px, calc(100% - 16px)); }\n#cs-root.cs-inside .cs-unlock, #cs-root.cs-inside .cs-menu { bottom: 52px; }\n#cs-root.cs-inside .cs-toast { top: 8px; }\n";
1
+ export declare const toolbarCss = "\n#cs-root {\n --cs-text: #1d1d1f;\n --cs-text-2: #6e6e73;\n --cs-text-3: #a1a1a6;\n --cs-glass: rgba(251, 251, 253, 0.8);\n --cs-card: rgba(255, 255, 255, 0.94);\n --cs-fill: rgba(0, 0, 0, 0.05);\n --cs-fill-2: rgba(0, 0, 0, 0.08);\n --cs-line: rgba(0, 0, 0, 0.08);\n --cs-edge: rgba(0, 0, 0, 0.1);\n --cs-accent: #007aff;\n --cs-accent-soft: rgba(0, 122, 255, 0.12);\n --cs-danger: #ff3b30;\n --cs-warn: #ff9500;\n --cs-shadow: 0 0 0 0.5px var(--cs-edge), 0 10px 30px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);\n position: fixed;\n inset: 0;\n z-index: 2147483000;\n pointer-events: none;\n margin: 0;\n padding: 0;\n border: 0;\n background: transparent;\n color: var(--cs-text);\n font: 13px/1.4 -apple-system, BlinkMacSystemFont, \"SF Pro Text\", \"Helvetica Neue\", Inter, system-ui, sans-serif;\n letter-spacing: -0.005em;\n -webkit-font-smoothing: antialiased;\n text-align: left;\n}\n#cs-root.cs-dark {\n --cs-text: #f5f5f7;\n --cs-text-2: #a1a1a6;\n --cs-text-3: #6e6e73;\n --cs-glass: rgba(40, 40, 44, 0.78);\n --cs-card: rgba(36, 36, 40, 0.96);\n --cs-fill: rgba(255, 255, 255, 0.07);\n --cs-fill-2: rgba(255, 255, 255, 0.12);\n --cs-line: rgba(255, 255, 255, 0.08);\n --cs-edge: rgba(255, 255, 255, 0.12);\n --cs-accent: #0a84ff;\n --cs-accent-soft: rgba(10, 132, 255, 0.2);\n --cs-shadow: 0 0 0 0.5px var(--cs-edge), 0 10px 30px rgba(0, 0, 0, 0.45);\n}\n#cs-root.cs-inside { position: absolute; }\n#cs-root, #cs-root * { box-sizing: border-box; }\n#cs-root h2, #cs-root p { margin: 0; }\n#cs-root button, #cs-root input, #cs-root textarea {\n font: inherit; color: inherit; letter-spacing: inherit; margin: 0;\n}\n#cs-root button { background: none; border: 0; padding: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; }\n#cs-root button:disabled { cursor: default; opacity: 0.45; }\n#cs-root button:focus-visible, #cs-root [role=button]:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: 2px; }\n#cs-root .cs-hit { pointer-events: auto; }\n#cs-root .cs-icon { display: block; flex: none; }\n\n/* Bar */\n#cs-root .cs-bar {\n position: absolute;\n bottom: 16px;\n display: flex;\n align-items: center;\n gap: 2px;\n padding: 4px;\n border-radius: 999px;\n background: var(--cs-glass);\n -webkit-backdrop-filter: saturate(180%) blur(20px);\n backdrop-filter: saturate(180%) blur(20px);\n box-shadow: var(--cs-shadow);\n}\n#cs-root.cs-at-center .cs-bar { left: 50%; transform: translateX(-50%); }\n#cs-root.cs-at-left .cs-bar { left: 16px; }\n#cs-root.cs-at-right .cs-bar { right: 16px; }\n#cs-root .cs-tool {\n position: relative;\n width: 34px;\n height: 34px;\n border-radius: 999px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n color: var(--cs-text);\n transition: background-color 0.15s ease, color 0.15s ease;\n}\n#cs-root .cs-tool:hover { background: var(--cs-fill); }\n#cs-root .cs-tool.is-on { background: var(--cs-fill-2); }\n#cs-root .cs-tool.is-accent { background: var(--cs-accent); color: #fff; }\n#cs-root .cs-tool[data-tip]::after {\n content: attr(data-tip);\n position: absolute;\n bottom: calc(100% + 10px);\n left: 50%;\n transform: translate(-50%, 2px);\n white-space: pre;\n padding: 4px 8px;\n border-radius: 7px;\n background: rgba(29, 29, 31, 0.92);\n color: #fff;\n font-size: 11.5px;\n font-weight: 500;\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.12s ease, transform 0.12s ease;\n}\n#cs-root .cs-tool[data-tip]:hover::after { opacity: 1; transform: translate(-50%, 0); transition-delay: 0.35s; }\n#cs-root .cs-me { width: 34px; }\n#cs-root .cs-divider { width: 1px; height: 18px; background: var(--cs-line); margin: 0 3px; }\n#cs-root .cs-badge {\n position: absolute;\n top: 3px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n padding: 0 4px;\n border-radius: 999px;\n background: var(--cs-accent);\n color: #fff;\n font-size: 10px;\n font-weight: 600;\n line-height: 16px;\n text-align: center;\n box-shadow: 0 0 0 2px var(--cs-glass);\n}\n#cs-root .cs-bar-lock {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n height: 34px;\n padding: 0 14px 0 12px;\n border-radius: 999px;\n font-weight: 500;\n}\n#cs-root .cs-bar-lock:hover { background: var(--cs-fill); }\n#cs-root .cs-avatar {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n border-radius: 999px;\n color: #fff;\n font-weight: 600;\n letter-spacing: 0;\n line-height: 1;\n user-select: none;\n}\n\n/* Cards */\n#cs-root .cs-card {\n position: absolute;\n background: var(--cs-card);\n -webkit-backdrop-filter: saturate(180%) blur(24px);\n backdrop-filter: saturate(180%) blur(24px);\n border-radius: 14px;\n box-shadow: var(--cs-shadow);\n}\n#cs-root .cs-unlock, #cs-root .cs-menu { bottom: 64px; }\n#cs-root.cs-at-center .cs-unlock, #cs-root.cs-at-center .cs-menu { left: 50%; transform: translateX(-50%); }\n#cs-root.cs-at-left .cs-unlock, #cs-root.cs-at-left .cs-menu { left: 16px; }\n#cs-root.cs-at-right .cs-unlock, #cs-root.cs-at-right .cs-menu { right: 16px; }\n#cs-root .cs-unlock { width: 280px; padding: 20px; text-align: center; }\n#cs-root .cs-unlock-icon {\n width: 40px; height: 40px; margin: 0 auto 10px; border-radius: 12px;\n display: flex; align-items: center; justify-content: center; background: var(--cs-fill); color: var(--cs-text-2);\n}\n#cs-root .cs-unlock h2 { font-size: 15px; font-weight: 600; }\n#cs-root .cs-sub { color: var(--cs-text-2); margin-top: 4px; }\n#cs-root .cs-unlock form { margin-top: 14px; display: grid; gap: 8px; text-align: left; }\n#cs-root .cs-field { display: grid; gap: 4px; }\n#cs-root .cs-field span { font-size: 12px; color: var(--cs-text-2); padding-left: 2px; }\n#cs-root input, #cs-root textarea {\n width: 100%;\n border: 0;\n border-radius: 9px;\n background: var(--cs-fill);\n padding: 8px 10px;\n outline: none;\n transition: box-shadow 0.15s ease, background-color 0.15s ease;\n}\n#cs-root input:focus, #cs-root textarea:focus { background: transparent; box-shadow: 0 0 0 1px var(--cs-accent), 0 0 0 4px var(--cs-accent-soft); }\n#cs-root textarea { resize: none; }\n#cs-root .cs-error { color: var(--cs-danger); font-size: 12px; }\n#cs-root .cs-pad { padding: 6px 14px 0; }\n#cs-root .cs-hint { color: var(--cs-text-3); font-size: 11.5px; }\n\n/* Buttons */\n#cs-root .cs-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 5px;\n height: 28px;\n padding: 0 11px;\n border-radius: 8px;\n background: var(--cs-fill);\n font-size: 12.5px;\n font-weight: 500;\n transition: background-color 0.15s ease;\n}\n#cs-root .cs-button:hover { background: var(--cs-fill-2); }\n#cs-root .cs-button.is-primary { background: var(--cs-accent); color: #fff; }\n#cs-root .cs-button.is-primary:hover { filter: brightness(1.06); }\n#cs-root .cs-button.is-danger { background: var(--cs-danger); color: #fff; }\n#cs-root .cs-button.is-wide { width: 100%; height: 32px; margin-top: 4px; }\n#cs-root .cs-icon-button {\n width: 26px; height: 26px; border-radius: 999px; flex: none;\n display: inline-flex; align-items: center; justify-content: center; color: var(--cs-text-2);\n}\n#cs-root .cs-icon-button:hover { background: var(--cs-fill); color: var(--cs-text); }\n#cs-root .cs-send {\n width: 26px; height: 26px; border-radius: 999px; flex: none;\n display: inline-flex; align-items: center; justify-content: center; background: var(--cs-accent); color: #fff;\n}\n#cs-root .cs-send:disabled { background: var(--cs-fill-2); color: var(--cs-text-3); opacity: 1; }\n\n/* Menu */\n#cs-root .cs-menu { width: 264px; padding: 6px; }\n#cs-root .cs-me-row { display: flex; align-items: center; gap: 10px; padding: 8px 8px 10px; }\n#cs-root .cs-me-name { display: flex; align-items: center; gap: 4px; min-width: 0; }\n#cs-root .cs-me-name strong { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#cs-root .cs-rename { display: flex; align-items: center; gap: 4px; flex: 1; }\n#cs-root .cs-rename input { padding: 5px 8px; }\n#cs-root .cs-sep { height: 1px; background: var(--cs-line); margin: 4px 8px; }\n#cs-root .cs-item {\n display: flex; align-items: center; justify-content: space-between; gap: 10px;\n width: 100%; min-height: 32px; padding: 0 8px; border-radius: 8px; text-align: left;\n}\n#cs-root button.cs-item:hover { background: var(--cs-fill); }\n#cs-root .cs-item.is-danger { color: var(--cs-danger); }\n#cs-root .cs-switch { position: relative; width: 32px; height: 20px; border-radius: 999px; background: var(--cs-fill-2); transition: background-color 0.2s ease; flex: none; }\n#cs-root .cs-switch::after {\n content: \"\"; position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: 999px;\n background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); transition: transform 0.2s ease;\n}\n#cs-root .cs-switch.is-on { background: #34c759; }\n#cs-root .cs-switch.is-on::after { transform: translateX(12px); }\n#cs-root .cs-segment { display: inline-flex; padding: 2px; border-radius: 8px; background: var(--cs-fill); }\n#cs-root .cs-segment button { padding: 2px 8px; border-radius: 6px; font-size: 12px; color: var(--cs-text-2); }\n#cs-root .cs-segment button.is-on { background: var(--cs-card); color: var(--cs-text); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12); font-weight: 500; }\n#cs-root .cs-menu .cs-hint { padding: 6px 8px 4px; }\n#cs-root .cs-invite { padding: 2px 8px 6px; }\n#cs-root .cs-invite input { font: 11.5px ui-monospace, SFMono-Regular, Menlo, monospace; padding: 6px 8px; }\n#cs-root .cs-invite .cs-hint { padding: 4px 0 0; }\n#cs-root .cs-confirm { padding: 10px; }\n#cs-root .cs-confirm h2 { font-size: 14px; font-weight: 600; }\n#cs-root .cs-row-end { display: flex; justify-content: flex-end; gap: 6px; margin-top: 12px; }\n\n/* Sheet */\n#cs-root .cs-sheet {\n top: 12px; right: 12px; max-height: calc(100% - 88px); width: min(360px, calc(100vw - 24px));\n display: flex; flex-direction: column; overflow: hidden;\n}\n#cs-root .cs-sheet-head { display: flex; align-items: center; justify-content: space-between; padding: 12px 10px 4px 16px; }\n#cs-root .cs-sheet-head .cs-push { margin-left: auto; }\n#cs-root .cs-sheet-head h2 { font-size: 15px; font-weight: 600; letter-spacing: -0.01em; }\n#cs-root .cs-tabs { display: flex; gap: 2px; margin: 4px 12px 6px; padding: 2px; border-radius: 9px; background: var(--cs-fill); }\n#cs-root .cs-tabs button {\n flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 5px;\n height: 26px; border-radius: 7px; font-size: 12px; font-weight: 500; color: var(--cs-text-2);\n}\n#cs-root .cs-tabs button.is-on { background: var(--cs-card); color: var(--cs-text); box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12); }\n#cs-root .cs-count { font-size: 11px; color: var(--cs-text-3); font-variant-numeric: tabular-nums; }\n#cs-root .cs-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 2px 6px 8px; overscroll-behavior: contain; }\n#cs-root .cs-group { padding: 10px 10px 4px; font-size: 11px; font-weight: 600; color: var(--cs-text-3); text-transform: uppercase; letter-spacing: 0.04em; }\n#cs-root .cs-empty { padding: 36px 16px; text-align: center; color: var(--cs-text-2); display: grid; gap: 12px; justify-items: center; }\n#cs-root .cs-thread { border-radius: 10px; }\n#cs-root .cs-thread + .cs-thread { margin-top: 1px; }\n#cs-root .cs-thread.is-open { background: var(--cs-fill); }\n#cs-root .cs-thread-main { display: flex; gap: 10px; padding: 10px; border-radius: 10px; cursor: pointer; }\n#cs-root .cs-thread:not(.is-open) .cs-thread-main:hover { background: var(--cs-fill); }\n#cs-root .cs-thread-body { min-width: 0; flex: 1; }\n#cs-root .cs-meta { display: flex; align-items: center; gap: 6px; font-size: 12.5px; }\n#cs-root .cs-meta strong { font-weight: 600; }\n#cs-root .cs-meta time { color: var(--cs-text-3); font-size: 12px; }\n#cs-root .cs-text { margin-top: 2px; white-space: pre-wrap; overflow-wrap: anywhere; }\n#cs-root .cs-target { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; margin-top: 4px; font-size: 11.5px; color: var(--cs-text-3); }\n#cs-root .cs-note { display: inline-flex; align-items: center; gap: 5px; font-weight: 500; }\n#cs-root .cs-note::before { content: \"\"; width: 6px; height: 6px; border-radius: 999px; background: currentColor; }\n#cs-root .cs-note.is-quiet { color: var(--cs-text-2); }\n#cs-root .cs-note.is-warn { color: var(--cs-warn); }\n#cs-root .cs-note.is-bad { color: var(--cs-danger); }\n#cs-root .cs-replies { margin-top: 4px; font-size: 12px; color: var(--cs-accent); font-weight: 500; }\n#cs-root .cs-thread-more { padding: 0 10px 10px 44px; display: grid; gap: 10px; }\n#cs-root .cs-message { display: flex; gap: 8px; }\n#cs-root .cs-reply { display: flex; align-items: flex-end; gap: 6px; padding: 4px 4px 4px 0; border-radius: 10px; }\n#cs-root .cs-reply textarea { min-height: 32px; max-height: 120px; field-sizing: content; }\n#cs-root .cs-thread.is-open .cs-reply textarea { background: var(--cs-card); }\n#cs-root .cs-actions { display: flex; flex-wrap: wrap; gap: 6px; }\n#cs-root .cs-thread.is-open .cs-button { background: var(--cs-card); box-shadow: 0 0 0 0.5px var(--cs-edge); }\n#cs-root .cs-thread.is-open .cs-button:hover { background: var(--cs-fill-2); }\n\n/* Mentions */\n#cs-root .cs-mention { color: var(--cs-accent); background: var(--cs-accent-soft); border-radius: 4px; padding: 0 3px; font-weight: 500; }\n#cs-root .cs-delivery { margin-top: 4px; font-size: 11.5px; color: var(--cs-text-3); display: flex; align-items: center; gap: 5px; }\n#cs-root .cs-delivery::before { content: \"\"; width: 6px; height: 6px; border-radius: 999px; background: #34c759; }\n#cs-root .cs-people {\n position: fixed; z-index: 1; width: 264px; padding: 5px; border-radius: 12px;\n background: var(--cs-card); box-shadow: var(--cs-shadow); pointer-events: auto;\n}\n#cs-root .cs-person { display: flex; align-items: center; gap: 9px; padding: 6px 8px; border-radius: 8px; cursor: pointer; }\n#cs-root .cs-person.is-on { background: var(--cs-accent); color: #fff; }\n#cs-root .cs-person-text { display: grid; line-height: 1.25; min-width: 0; }\n#cs-root .cs-person-text strong { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#cs-root .cs-person-text small { font-size: 11.5px; color: var(--cs-text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#cs-root .cs-person.is-on small { color: rgba(255, 255, 255, 0.8); }\n#cs-root .cs-field small { font-size: 11.5px; color: var(--cs-text-3); padding-left: 2px; }\n#cs-root .cs-me-lines { display: grid; line-height: 1.25; min-width: 0; }\n#cs-root .cs-me-lines small { font-size: 11.5px; color: var(--cs-text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n\n/* Composer */\n#cs-root .cs-composer { width: min(320px, calc(100% - 16px)); }\n#cs-root .cs-composer-target {\n display: flex; align-items: center; gap: 6px; padding: 6px 6px 6px 12px;\n border-bottom: 1px solid var(--cs-line); font-size: 12px; color: var(--cs-text-2);\n}\n#cs-root .cs-composer-name { font-weight: 500; color: var(--cs-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n#cs-root .cs-composer-target code {\n margin-left: auto; font: 11px ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--cs-text-3);\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; min-width: 0; max-width: 45%;\n}\n#cs-root .cs-composer-body { display: flex; gap: 10px; padding: 12px 12px 4px; }\n#cs-root .cs-composer-body textarea { background: transparent; padding: 3px 0; min-height: 56px; box-shadow: none; border-radius: 0; }\n#cs-root .cs-composer-foot { display: flex; align-items: center; gap: 6px; padding: 6px 8px 8px 40px; }\n#cs-root .cs-composer-foot .cs-hint { margin-left: auto; }\n\n/* Roles and fields */\n#cs-root .cs-details-input { display: grid; gap: 8px; padding: 2px 12px 6px 46px; }\n#cs-root .cs-details-edit .cs-details-input { padding: 0; }\n#cs-root .cs-detail-field { display: grid; gap: 3px; }\n#cs-root .cs-detail-field span, #cs-root .cs-roles-label, #cs-root .cs-detail-list dt {\n font-size: 11px; font-weight: 600; color: var(--cs-text-3); text-transform: uppercase; letter-spacing: 0.03em;\n}\n#cs-root .cs-detail-field textarea { padding: 6px 8px; min-height: 30px; max-height: 120px; field-sizing: content; }\n#cs-root .cs-thread.is-open .cs-detail-field textarea { background: var(--cs-card); }\n#cs-root .cs-roles { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }\n#cs-root .cs-roles-label { margin-right: 4px; }\n#cs-root .cs-chip {\n display: inline-flex; align-items: center; gap: 2px; height: 24px; padding: 0 9px; border-radius: 999px;\n background: var(--cs-fill); font-size: 12px; font-weight: 500; color: var(--cs-text-2);\n}\n#cs-root button.cs-chip:hover { background: var(--cs-fill-2); }\n#cs-root .cs-chip.is-on, #cs-root button.cs-chip.is-on:hover { background: var(--cs-accent); color: #fff; }\n#cs-root .cs-chip.is-static { padding-right: 3px; color: var(--cs-text); }\n#cs-root .cs-chip.is-static button {\n width: 18px; height: 18px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; color: var(--cs-text-3);\n}\n#cs-root .cs-chip.is-static button:hover { background: var(--cs-fill-2); color: var(--cs-text); }\n#cs-root .cs-chip.is-static .cs-icon { width: 11px; height: 11px; }\n#cs-root .cs-chips { display: flex; flex-wrap: wrap; gap: 4px; }\n#cs-root .cs-role {\n display: inline-flex; align-items: center; height: 18px; padding: 0 7px; border-radius: 999px;\n background: var(--cs-accent-soft); color: var(--cs-accent); font-size: 11px; font-weight: 600;\n}\n#cs-root .cs-detail-list { display: grid; gap: 6px; margin: 6px 0 0; }\n#cs-root .cs-detail-list > div { padding: 6px 8px; border-radius: 8px; background: var(--cs-fill); }\n#cs-root .cs-thread.is-open .cs-detail-list > div { background: var(--cs-card); }\n#cs-root .cs-detail-list dd { margin: 1px 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }\n#cs-root .cs-detail-list.is-clamped dd { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }\n#cs-root .cs-details-edit { display: grid; gap: 8px; }\n#cs-root .cs-details-edit .cs-row-end { margin-top: 0; }\n#cs-root .cs-settings { width: 280px; }\n#cs-root .cs-settings-head { display: flex; align-items: center; gap: 4px; padding: 4px 4px 6px; }\n#cs-root .cs-settings-head h2 { font-size: 14px; font-weight: 600; }\n#cs-root .cs-settings-body { display: grid; gap: 6px; padding: 2px 8px 8px; }\n#cs-root .cs-field-row { display: flex; align-items: center; justify-content: space-between; gap: 6px; min-height: 28px; padding-left: 2px; }\n#cs-root .cs-add-row { display: flex; align-items: center; gap: 4px; }\n#cs-root .cs-add-row input { padding: 5px 8px; }\n#cs-root .cs-settings .cs-hint { padding: 6px 8px 4px; }\n\n/* Table */\n#cs-root .cs-table-sheet {\n top: 12px; right: 12px; width: min(1100px, calc(100vw - 24px)); max-height: calc(100% - 88px);\n display: flex; flex-direction: column; overflow: hidden;\n}\n#cs-root .cs-table-sheet .cs-sheet-head { gap: 6px; }\n#cs-root .cs-table-sheet .cs-sheet-head h2 { margin-right: auto; }\n#cs-root .cs-table-search { width: 220px; padding: 5px 10px; }\n#cs-root .cs-table-sheet .cs-tabs { max-width: 420px; }\n#cs-root .cs-table-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; border-top: 1px solid var(--cs-line); overscroll-behavior: contain; }\n#cs-root .cs-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }\n#cs-root .cs-table th {\n position: sticky; top: 0; z-index: 1; background: var(--cs-card); text-align: left; font-weight: 600;\n font-size: 11px; color: var(--cs-text-3); text-transform: uppercase; letter-spacing: 0.03em;\n padding: 0; border-bottom: 1px solid var(--cs-line); white-space: nowrap;\n}\n#cs-root .cs-table th > button, #cs-root .cs-table th > span {\n display: inline-flex; align-items: center; gap: 4px; padding: 8px 10px; font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;\n}\n#cs-root .cs-table th > button:hover { color: var(--cs-text); }\n#cs-root .cs-sort { color: var(--cs-accent); }\n#cs-root .cs-table td { padding: 8px 10px; vertical-align: top; border-bottom: 1px solid var(--cs-line); max-width: 260px; }\n#cs-root .cs-table tbody tr { cursor: pointer; }\n#cs-root .cs-table tbody tr:hover { background: var(--cs-fill); }\n#cs-root .cs-table tbody tr.is-active { background: var(--cs-accent-soft); }\n#cs-root .cs-table tbody tr:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: -2px; }\n#cs-root .cs-cell-comment { min-width: 220px; }\n#cs-root .cs-cell-comment small, #cs-root .cs-table td small { display: block; margin-top: 2px; font-size: 11.5px; color: var(--cs-text-3); }\n#cs-root .cs-cell-clamp { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; white-space: pre-wrap; overflow-wrap: anywhere; }\n#cs-root .cs-cell-page { font: 11.5px ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--cs-text-2); max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#cs-root .cs-cell-nowrap { white-space: nowrap; }\n#cs-root .cs-cell-num { text-align: right; font-variant-numeric: tabular-nums; color: var(--cs-text-2); }\n#cs-root .cs-state { display: inline-flex; align-items: center; gap: 5px; font-weight: 500; }\n#cs-root .cs-state::before { content: \"\"; width: 6px; height: 6px; border-radius: 999px; background: #34c759; }\n#cs-root .cs-state.is-done { color: var(--cs-text-3); }\n#cs-root .cs-state.is-done::before { background: var(--cs-text-3); }\n#cs-root .cs-table .cs-note { display: flex; margin-top: 2px; font-size: 11px; }\n\n/* Attachments */\n#cs-root .cs-attach { display: inline-flex; gap: 0; flex: none; }\n#cs-root .cs-tray { display: flex; flex-wrap: wrap; gap: 6px; padding: 4px 12px 2px 46px; }\n#cs-root .cs-thread-more .cs-tray { padding: 0; }\n#cs-root .cs-pending {\n position: relative; display: inline-flex; align-items: center; gap: 6px; max-width: 170px; height: 34px;\n padding: 0 24px 0 4px; border-radius: 8px; background: var(--cs-fill); font-size: 11.5px; color: var(--cs-text-2);\n}\n#cs-root .cs-pending img { width: 26px; height: 26px; border-radius: 5px; object-fit: cover; flex: none; }\n#cs-root .cs-pending .cs-icon { margin-left: 4px; }\n#cs-root .cs-pending-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#cs-root .cs-pending.is-uploading { opacity: 0.6; }\n#cs-root .cs-pending.is-failed { box-shadow: inset 0 0 0 1px var(--cs-danger); }\n#cs-root .cs-pending-remove {\n position: absolute; right: 3px; top: 50%; transform: translateY(-50%); width: 18px; height: 18px; border-radius: 999px;\n display: inline-flex; align-items: center; justify-content: center; color: var(--cs-text-3);\n}\n#cs-root .cs-pending-remove:hover { background: var(--cs-fill-2); color: var(--cs-text); }\n#cs-root .cs-pending-remove .cs-icon { width: 11px; height: 11px; margin: 0; }\n#cs-root .cs-files { display: grid; gap: 6px; margin-top: 6px; }\n#cs-root .cs-thumbs { display: flex; flex-wrap: wrap; gap: 6px; }\n#cs-root .cs-thumb { display: block; width: 112px; height: 72px; border-radius: 8px; overflow: hidden; box-shadow: 0 0 0 0.5px var(--cs-edge); background: var(--cs-fill); }\n#cs-root .cs-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }\n#cs-root .cs-file {\n display: inline-flex; align-items: center; gap: 6px; max-width: 100%; padding: 6px 10px; border-radius: 8px;\n background: var(--cs-fill); color: var(--cs-text); text-decoration: none; font-size: 12px; justify-self: start;\n}\n#cs-root .cs-file:hover { background: var(--cs-fill-2); }\n#cs-root .cs-file-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n#cs-root .cs-file-size { color: var(--cs-text-3); flex: none; }\n\n/* Page overlays */\n#cs-root .cs-pin {\n position: absolute;\n transform: translate(-50%, -50%);\n padding: 2px;\n border-radius: 999px;\n background: var(--cs-card);\n box-shadow: 0 0 0 0.5px var(--cs-edge), 0 3px 10px rgba(0, 0, 0, 0.18);\n pointer-events: auto;\n transition: transform 0.15s ease;\n}\n#cs-root .cs-pin:hover { transform: translate(-50%, -50%) scale(1.08); }\n#cs-root .cs-pin.is-active { box-shadow: 0 0 0 2px var(--cs-accent), 0 3px 10px rgba(0, 0, 0, 0.18); }\n#cs-root .cs-pin.is-drifted { box-shadow: 0 0 0 1.5px var(--cs-warn), 0 3px 10px rgba(0, 0, 0, 0.18); }\n#cs-root .cs-pin-count {\n position: absolute; top: -5px; right: -6px; min-width: 15px; height: 15px; padding: 0 4px;\n border-radius: 999px; background: var(--cs-text); color: var(--cs-card);\n font-size: 9.5px; font-weight: 700; line-height: 15px; text-align: center;\n}\n#cs-root .cs-peek {\n position: absolute; width: 240px; padding: 10px 12px; border-radius: 12px;\n background: var(--cs-card); box-shadow: var(--cs-shadow); pointer-events: none;\n}\n#cs-root .cs-peek .cs-text { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }\n#cs-root .cs-outline {\n position: absolute; border-radius: 8px; pointer-events: none;\n box-shadow: 0 0 0 2px var(--cs-accent); background: var(--cs-accent-soft);\n}\n#cs-root .cs-outline.is-flash { animation: cs-flash 1.4s ease forwards; }\n@keyframes cs-flash { 0%, 60% { opacity: 1; } 100% { opacity: 0; } }\n#cs-root .cs-outline-label {\n position: absolute; max-width: 360px; padding: 3px 8px; border-radius: 6px; pointer-events: none;\n background: var(--cs-accent); color: #fff; font-size: 11.5px; font-weight: 500;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis;\n}\n#cs-root .cs-banner {\n position: absolute; top: 14px; left: 50%; transform: translateX(-50%);\n display: flex; align-items: center; gap: 8px; padding: 5px 5px 5px 12px; border-radius: 999px;\n background: var(--cs-glass); -webkit-backdrop-filter: saturate(180%) blur(20px); backdrop-filter: saturate(180%) blur(20px);\n box-shadow: var(--cs-shadow); font-weight: 500; white-space: nowrap;\n}\n#cs-root .cs-banner button { padding: 3px 10px; border-radius: 999px; background: var(--cs-fill); font-size: 12px; }\n#cs-root .cs-banner button:hover { background: var(--cs-fill-2); }\n#cs-root .cs-toast {\n position: absolute; top: 14px; left: 50%; transform: translateX(-50%); padding: 6px 12px; border-radius: 999px;\n background: rgba(29, 29, 31, 0.9); color: #fff; font-size: 12px; font-weight: 500;\n box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2); pointer-events: none; white-space: nowrap;\n}\n\n/* Docked inside an open <dialog> */\n#cs-root.cs-inside .cs-bar { bottom: 8px; }\n#cs-root.cs-inside.cs-at-left .cs-bar { left: 8px; }\n#cs-root.cs-inside.cs-at-right .cs-bar { right: 8px; }\n#cs-root.cs-inside .cs-sheet { top: 8px; right: 8px; bottom: auto; max-height: 46%; width: min(300px, calc(100% - 16px)); }\n#cs-root.cs-inside .cs-unlock, #cs-root.cs-inside .cs-menu { bottom: 52px; }\n#cs-root.cs-inside .cs-toast { top: 8px; }\n";
@@ -0,0 +1,16 @@
1
+ import { type ReactNode } from "react";
2
+ import type { Thread } from "./client.js";
3
+ import { type PlacedStatus } from "./format.js";
4
+ export type TableRow = {
5
+ thread: Thread;
6
+ status: PlacedStatus;
7
+ };
8
+ export declare function CommentTable({ rows, route, activeId, tabs, onSelect, onList, onClose, }: {
9
+ rows: TableRow[];
10
+ route: string;
11
+ activeId: string | null;
12
+ tabs: ReactNode;
13
+ onSelect: (row: TableRow) => void;
14
+ onList: () => void;
15
+ onClose: () => void;
16
+ }): import("react").JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devaccel-labs/comment-service",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "In-UI component comments for TanStack Start on Cloudflare. Anchors survive redeploys.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",
@@ -44,10 +44,10 @@
44
44
  "devDependencies": {
45
45
  "esbuild": "^0.28.1",
46
46
  "@devaccel/comment-core": "0.1.0",
47
- "@devaccel/comment-react": "0.1.0",
48
47
  "@devaccel/comment-compiler": "0.1.0",
49
- "@devaccel/comment-start": "0.1.0",
50
- "@devaccel/comment-server": "0.1.0"
48
+ "@devaccel/comment-react": "0.1.0",
49
+ "@devaccel/comment-server": "0.1.0",
50
+ "@devaccel/comment-start": "0.1.0"
51
51
  },
52
52
  "publishConfig": {
53
53
  "registry": "https://registry.npmjs.org/",