your-attention 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +2 -0
  2. package/bin/your-attention.js +6 -2
  3. package/dist/src/adapters/files.js +66 -0
  4. package/dist/src/adapters/mdns.js +53 -0
  5. package/dist/src/adapters/mermaid.js +50 -0
  6. package/dist/src/adapters/openui-body.js +40 -0
  7. package/dist/src/adapters/openui-library.js +3 -0
  8. package/dist/src/adapters/sqlite.js +68 -0
  9. package/dist/src/cli.js +814 -0
  10. package/dist/src/client.js +459 -0
  11. package/dist/src/cloudflare/collector.js +53 -0
  12. package/dist/src/cloudflare/inbox-object.js +338 -0
  13. package/dist/src/cloudflare/storage.js +151 -0
  14. package/dist/src/cloudflare/worker.js +189 -0
  15. package/dist/src/core/crypto.js +23 -0
  16. package/dist/src/core/diagrams.js +225 -0
  17. package/dist/src/core/expr.js +125 -0
  18. package/dist/src/core/file-links.js +48 -0
  19. package/dist/src/core/hooks.js +74 -0
  20. package/dist/src/core/http.js +651 -0
  21. package/dist/src/core/inbox.js +2463 -0
  22. package/dist/src/core/pin.js +234 -0
  23. package/dist/src/core/sealed.js +167 -0
  24. package/dist/src/core/session-link.js +13 -0
  25. package/dist/src/core/socket.js +88 -0
  26. package/dist/src/core/storage.js +102 -0
  27. package/dist/src/core/summary.js +149 -0
  28. package/dist/src/core/telemetry.js +221 -0
  29. package/dist/src/core/types.js +470 -0
  30. package/dist/src/core/version.js +2 -0
  31. package/dist/src/core/widgets.js +128 -0
  32. package/dist/src/extensions/triage.js +232 -0
  33. package/dist/src/integrations/claude/ask-hook.js +84 -0
  34. package/dist/src/integrations/claude/channel-flag.js +102 -0
  35. package/dist/src/integrations/claude/channel.js +276 -0
  36. package/dist/src/integrations/claude/session-name.js +32 -0
  37. package/dist/src/integrations/claude/turn-end-hook.js +84 -0
  38. package/dist/src/integrations/herdr/approve.js +71 -0
  39. package/dist/src/integrations/herdr/blocked.js +210 -0
  40. package/dist/src/integrations/herdr/dialog.js +64 -0
  41. package/dist/src/integrations/herdr/focus.js +31 -0
  42. package/dist/src/integrations/herdr/place.js +22 -0
  43. package/dist/src/integrations/images.js +43 -0
  44. package/dist/src/integrations/opencode/install.js +24 -0
  45. package/dist/src/integrations/opencode/plugin.js +157 -0
  46. package/dist/src/integrations/pi/extension.js +166 -0
  47. package/dist/src/integrations/run-tool.js +157 -0
  48. package/dist/src/integrations/secrets.js +63 -0
  49. package/dist/src/integrations/tags.js +27 -0
  50. package/dist/src/integrations/tools.js +147 -0
  51. package/dist/src/node/home.js +20 -0
  52. package/dist/src/node/install.js +225 -0
  53. package/dist/src/node/links.js +249 -0
  54. package/dist/src/node/pin-prompt.js +125 -0
  55. package/dist/src/node/server.js +320 -0
  56. package/dist/src/node/service.js +74 -0
  57. package/dist/src/node/telemetry.js +127 -0
  58. package/dist/src/owner-watch.js +49 -0
  59. package/dist/src/tui/api.js +203 -0
  60. package/dist/src/tui/app.js +586 -0
  61. package/dist/src/tui/body.js +727 -0
  62. package/dist/src/tui/cardview.js +453 -0
  63. package/dist/src/tui/doc.js +157 -0
  64. package/dist/src/tui/edit.js +119 -0
  65. package/dist/src/tui/input.js +192 -0
  66. package/dist/src/tui/md.js +196 -0
  67. package/dist/src/tui/screen.js +225 -0
  68. package/dist/src/tui/terminal.js +130 -0
  69. package/dist/src/tui/text.js +103 -0
  70. package/dist/src/tui/theme.js +105 -0
  71. package/dist/src/tui/view.js +314 -0
  72. package/dist/src/watch.js +104 -0
  73. package/dist/web/age.js +16 -0
  74. package/dist/web/answers.js +485 -0
  75. package/dist/web/app.js +739 -0
  76. package/dist/web/body-faults.js +69 -0
  77. package/dist/web/components.js +923 -0
  78. package/dist/web/copy.js +118 -0
  79. package/dist/web/details.js +59 -0
  80. package/dist/web/env.js +97 -0
  81. package/dist/web/favicon-waiting.svg +1 -0
  82. package/dist/web/favicon.svg +1 -0
  83. package/dist/web/index.html +16 -0
  84. package/dist/web/library-spec.js +33 -0
  85. package/dist/web/markdown.js +142 -0
  86. package/dist/web/paste-images.js +193 -0
  87. package/dist/web/pin-key.js +125 -0
  88. package/dist/web/pin.js +126 -0
  89. package/dist/web/queue.js +97 -0
  90. package/dist/web/sealed.js +13 -0
  91. package/dist/web/search.js +70 -0
  92. package/dist/web/stories/cards.stories.js +144 -0
  93. package/dist/web/stories/page.stories.js +54 -0
  94. package/dist/web/stories/render.js +16 -0
  95. package/dist/web/style.css +417 -0
  96. package/package.json +4 -2
  97. package/src/core/version.ts +1 -1
@@ -0,0 +1,417 @@
1
+ :root {
2
+ --bg: #f6f6f4; --panel: #ffffff; --ink: #1d1d1b; --muted: #6b6b66; --line: #e3e3de;
3
+ --ok: #1f7a4d; --ok-bg: #e4f4ea; --warn: #8a5a00; --warn-bg: #fdf1d8; --bad: #a3261b; --bad-bg: #fbe4e1;
4
+ --info: #2a4fb0; --info-bg: #e3eafb; --accent: #3b4cca;
5
+ --font-text: "Gill Sans", "Gill Sans MT", sans-serif;
6
+ --font-code: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
7
+ --text-scale: 1.2;
8
+ }
9
+ @media (prefers-color-scheme: dark) {
10
+ :root:not([data-theme="light"]) {
11
+ --bg: #141413; --panel: #1d1d1b; --ink: #ececea; --muted: #a3a39d; --line: #33332f;
12
+ --ok: #6fd3a0; --ok-bg: #173325; --warn: #f0c36a; --warn-bg: #3a2d12; --bad: #f19287; --bad-bg: #3d1c18;
13
+ --info: #9db4ff; --info-bg: #1c2645; --accent: #8f9bff;
14
+ }
15
+ }
16
+ :root[data-theme="dark"] {
17
+ --bg: #141413; --panel: #1d1d1b; --ink: #ececea; --muted: #a3a39d; --line: #33332f;
18
+ --ok: #6fd3a0; --ok-bg: #173325; --warn: #f0c36a; --warn-bg: #3a2d12; --bad: #f19287; --bad-bg: #3d1c18;
19
+ --info: #9db4ff; --info-bg: #1c2645; --accent: #8f9bff;
20
+ }
21
+ * { box-sizing: border-box; }
22
+ /* The text color of a card's body: the dim color, moved toward the bright one by about 5% of lightness. */
23
+ :root { --body-text: color-mix(in srgb, var(--muted) 78%, var(--ink)); }
24
+ body { margin: 0; background: var(--bg); color: var(--ink); font: calc(15px * var(--text-scale))/1.5 var(--font-text); }
25
+ .bar { position: sticky; top: 0; z-index: 10; background: var(--panel); border-bottom: 1px solid var(--line); }
26
+ .bar-inner { padding: 12px 16px; display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: center; }
27
+ .bar h1 { font-size: calc(17px * var(--text-scale)); margin: 0; flex: 1 1 auto; }
28
+ .pasted-strip { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 10px; }
29
+ .pasted-thumb { position: relative; margin: 0; }
30
+ .pasted-thumb img { display: block; max-width: 140px; max-height: 100px; border: 1px solid var(--line); border-radius: 6px; background: var(--panel); }
31
+ .pasted-remove { position: absolute; top: 2px; right: 2px; width: 20px; height: 20px; padding: 0; border: 1px solid var(--line); border-radius: 50%; background: var(--panel); color: var(--ink); font: inherit; line-height: 1; cursor: pointer; }
32
+ .notify { display: inline-flex; align-items: center; gap: 6px; font-size: calc(13px * var(--text-scale)); color: var(--muted); cursor: pointer; }
33
+ .notify input { accent-color: var(--accent); }
34
+ /* The search field is as quiet as the other bar controls: small, hairline outline, no fill, muted until it has focus. */
35
+ .bar-search { flex: 0 1 190px; min-width: 110px; margin-left: auto; height: 28px; padding: 0 12px; border: 1px solid var(--line); border-radius: 999px; background: transparent; color: var(--ink); font: inherit; font-size: calc(13px * var(--text-scale)); transition: border-color .15s; }
36
+ .bar-search::placeholder { color: var(--muted); }
37
+ .bar-search:hover { border-color: color-mix(in srgb, var(--muted) 60%, transparent); }
38
+ .bar-search:focus-visible { outline: none; border-color: var(--accent); }
39
+ .bar h1 { margin-right: 0; }
40
+ .queue mark { background: color-mix(in srgb, var(--accent) 28%, transparent); color: inherit; border-radius: 2px; }
41
+ .q .snippet { display: block; margin-top: 2px; color: var(--muted); font-size: calc(12px * var(--text-scale)); }
42
+ .q .snippet-label { text-transform: uppercase; letter-spacing: .05em; font-size: calc(11px * var(--text-scale)); }
43
+ .search-count { margin: 4px 8px 0; color: var(--muted); font-size: calc(12px * var(--text-scale)); }
44
+ .repo { display: inline-flex; color: var(--muted); }
45
+ .usage-notice { margin: 16px 16px 0; padding: 12px 16px; border: 1px solid var(--line); border-left: 3px solid var(--info); border-radius: 8px; background: var(--panel); font-size: calc(14px * var(--text-scale)); }
46
+ .usage-notice p { margin: 0 0 8px; }
47
+ .usage-notice pre { font: calc(12px * var(--text-scale))/1.4 var(--font-code); background: var(--bg); padding: 8px; border-radius: 6px; overflow: auto; }
48
+ .usage-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
49
+ .usage-toggle { margin: 16px 8px 4px; }
50
+ .repo:hover, .repo:focus-visible { color: var(--ink); }
51
+ .pill { display: inline-flex; align-items: center; gap: 8px; padding: 4px 10px; border-radius: 999px; font-size: calc(13px * var(--text-scale)); font-weight: 600; white-space: nowrap; }
52
+ .pill::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
53
+ .on { color: var(--ok); background: var(--ok-bg); }
54
+ .busy { color: var(--info); background: var(--info-bg); }
55
+ .off { color: var(--warn); background: var(--warn-bg); }
56
+ .down { color: var(--bad); background: var(--bad-bg); }
57
+ .layout { position: relative; padding: 16px; display: grid; grid-template-columns: var(--queue-w, 290px) 1fr; gap: 20px; align-items: start; }
58
+ @media (max-width: 760px) { .layout { grid-template-columns: 1fr; } .queue { order: 2; position: static; max-height: none; } .resizer { display: none; } }
59
+ .queue { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 8px; position: sticky; top: 72px; max-height: calc(100vh - 90px); overflow: auto; scrollbar-color: var(--line) transparent; scrollbar-width: thin; }
60
+ .queue h3 { font-size: calc(12px * var(--text-scale)); text-transform: uppercase; letter-spacing: .06em; color: var(--ink); margin: 20px 8px 4px; }
61
+ .queue h3.sent { border-top: 1px solid var(--line); padding-top: 12px; }
62
+ .queue h3 { display: flex; align-items: center; gap: 8px; border-bottom: 1px solid color-mix(in srgb, var(--muted) 60%, transparent); padding-bottom: 0; margin-bottom: 6px; }
63
+ /* The whole heading toggles a group, and the triangle at the left of its name turns from right to down. */
64
+ .queue h3 .fold { display: flex; align-items: center; gap: 5px; flex: 1; min-width: 0; padding: 0; border: 0; background: none; font: inherit; letter-spacing: inherit; text-transform: inherit; color: inherit; text-align: left; cursor: pointer; border-radius: 4px; }
65
+ .queue h3 .fold:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
66
+ .queue h3 .fold-tri { font-size: calc(10px * var(--text-scale)); transform: rotate(90deg); transition: transform .18s ease; }
67
+ .queue h3 .fold[aria-expanded="false"] .fold-tri { transform: rotate(0deg); }
68
+ @media (prefers-reduced-motion: reduce) { .queue h3 .fold-tri { transition: none; } }
69
+ .icon-btn { margin-left: auto; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px; padding: 0; border: 1px solid transparent; border-radius: 6px; background: none; color: var(--muted); cursor: pointer; }
70
+ .icon-btn:hover, .icon-btn:focus-visible { color: var(--ink); border-color: var(--line); }
71
+ .icon-btn svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
72
+ .q { display: flex; gap: 8px; align-items: baseline; width: 100%; text-align: left; border: 0; background: none; color: var(--ink); padding: 6px 8px; border-radius: 8px; cursor: pointer; font: inherit; font-size: calc(13px * var(--text-scale)); }
73
+ .q:hover { background: var(--bg); }
74
+ .q.focus { background: var(--info-bg); }
75
+ .q.dim { color: var(--muted); }
76
+ .q .n { color: var(--muted); min-width: 20px; }
77
+ .q .t { flex: 1; }
78
+ .q .s { font-size: calc(12px * var(--text-scale)); white-space: nowrap; }
79
+ .reply-msg { margin: 0 0 12px; padding: 10px 12px; border-left: 3px solid var(--info); background: var(--info-bg); border-radius: 0 8px 8px 0; font-size: calc(14px * var(--text-scale)); white-space: pre-wrap; }
80
+ .reply-msg b { color: var(--info); display: block; font-size: calc(12px * var(--text-scale)); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 2px; }
81
+ .s.todo { color: var(--muted); } .s.revised { color: var(--warn); } .s.stored { color: var(--warn); } .s.delivered { color: var(--info); } .s.read { color: var(--ok); } .s.closed { color: var(--muted); }
82
+ .new { margin-left: 6px; font-size: calc(11px * var(--text-scale)); font-weight: 700; padding: 1px 6px; border-radius: 999px; background: var(--info); color: var(--bg); animation: pop .4s ease; }
83
+ @keyframes pop { from { transform: scale(.6); opacity: 0; } to { transform: scale(1); opacity: 1; } }
84
+ @media (prefers-reduced-motion: reduce) { .new { animation: none; } }
85
+ .empty { color: var(--muted); font-size: calc(13px * var(--text-scale)); padding: 4px 8px; }
86
+ main { min-width: 0; }
87
+ .focus-card pre, .focus-card code { max-width: 100%; overflow-x: auto; scrollbar-color: var(--line) transparent; scrollbar-width: thin; }
88
+ /* The code block sets white-space inline, so wrapping the source of a body that did not draw needs !important. */
89
+ .body-source .openui-code-block-syntax-highlighter, .body-source .openui-code-block-syntax-highlighter code { white-space: pre-wrap !important; overflow-wrap: anywhere; }
90
+ .closed-line .o { overflow-wrap: anywhere; }
91
+ .focus-card { min-width: 0; overflow-x: hidden; background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 16px; }
92
+ /* A card's body reads in a dim text color, 5% brighter than the cards you sent, so it reads well without glare. The title, headings, bold words, card
93
+ headers and question labels keep the bright one, so they stand out. The choices under a question read as body text. OpenUI's own text takes the same colors. */
94
+ .focus-card { --openui-text-neutral-primary: var(--body-text); --openui-text-neutral-secondary: var(--body-text); }
95
+ .card-text, .file .markdown { color: var(--body-text); }
96
+ .card-text :is(strong, b, h1, h2, h3, h4, h5, h6), .file .markdown :is(strong, b, h1, h2, h3, h4, h5, h6), .card-body :is(strong, b, h1, h2, h3, h4, h5, h6),
97
+ .focus-card :is(.openui-header-top-left, .openui-label, .openui-callout-title) { color: var(--ink); }
98
+ /* Each question of a card that asks several opens with its question as a heading, a step larger than the field labels under it. */
99
+ .card-body h3 { font-size: calc(18px * var(--text-scale)); line-height: 1.3; margin: 12px 0 4px; }
100
+ .meta .age { margin-left: auto; white-space: nowrap; }
101
+ /* A card's tags, under the meta row. The pin sits right after each label: dim until the value is pinned. */
102
+ .tags { display: flex; flex-wrap: wrap; gap: 6px 12px; margin-bottom: 8px; font-size: calc(13px * var(--text-scale)); color: var(--body-text); }
103
+ .tags .tag { display: inline-flex; align-items: center; gap: 2px; border: 1px solid var(--line); border-radius: 6px; padding: 0 2px 0 8px; }
104
+ .tag-pin { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; padding: 0; border: 1px solid transparent; border-radius: 6px; background: none; color: var(--muted); opacity: .45; cursor: pointer; }
105
+ .tag-pin.on { color: var(--ink); opacity: 1; }
106
+ .tag-pin:hover, .tag-pin:focus-visible { opacity: 1; border-color: var(--line); }
107
+ .tag-pin svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
108
+ .tag-pin.on svg { fill: currentColor; }
109
+ .queue h3 .tag-pin { margin: -4px 0; }
110
+ .meta { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin-bottom: 8px; font-size: calc(13px * var(--text-scale)); color: var(--muted); }
111
+ .prio { font-weight: 700; white-space: nowrap; padding: 2px 8px; border-radius: 6px; font-size: calc(12px * var(--text-scale)); }
112
+ .prio.now { color: var(--bad); background: var(--bad-bg); }
113
+ .prio.soon { color: var(--warn); background: var(--warn-bg); }
114
+ .prio.later { color: var(--muted); background: var(--bg); }
115
+ .note { margin: 8px 0; padding: 10px 12px; border-radius: 8px; font-size: calc(14px * var(--text-scale)); white-space: pre-wrap; }
116
+ .note.warn { background: var(--warn-bg); color: var(--warn); }
117
+ .note.ok { background: var(--ok-bg); color: var(--ok); }
118
+ .html-gate { white-space: normal; }
119
+ .html-gate p { margin: 0 0 10px; }
120
+ .html-gate-actions { display: flex; flex-wrap: wrap; gap: 8px; }
121
+ button.link { background: none; border: 0; padding: 6px 0; color: var(--muted); text-decoration: underline; cursor: pointer; font: inherit; font-size: calc(13px * var(--text-scale)); }
122
+ button.link:hover { color: inherit; }
123
+ .receipt { margin-top: 10px; font-size: calc(13px * var(--text-scale)); color: var(--muted); display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }
124
+ .receipt .btn { margin-left: 8px; }
125
+ .receipt:empty { display: none; }
126
+ .receipt b { color: var(--ink); }
127
+ .receipt .error { color: var(--bad); font-weight: 600; }
128
+ .nav { display: flex; gap: 8px; margin-top: 12px; }
129
+ .btn { border: 1px solid var(--line); background: var(--panel); color: var(--ink); border-radius: 8px; padding: 6px 12px; cursor: pointer; font: inherit; font-size: calc(13px * var(--text-scale)); }
130
+ .done { padding: 24px; text-align: center; color: var(--muted); }
131
+ .closed-line { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; padding: 12px 16px; border-radius: 12px; border: 1px solid var(--line); background: var(--panel); }
132
+ .closed-line .tag { font-size: calc(12px * var(--text-scale)); font-weight: 700; padding: 2px 8px; border-radius: 6px; background: var(--info-bg); color: var(--info); }
133
+ .closed-line .o { flex: 1; min-width: 200px; }
134
+ .followup { margin: 0 0 12px; padding: 10px 12px; border-left: 3px solid var(--info); background: var(--info-bg); color: var(--ink); border-radius: 0 8px 8px 0; font-size: calc(14px * var(--text-scale)); }
135
+ .followup b { color: var(--info); display: block; font-size: calc(12px * var(--text-scale)); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 2px; }
136
+ details.earlier { margin-top: 14px; border-top: 1px solid var(--line); padding-top: 10px; }
137
+ details.earlier summary { cursor: pointer; color: var(--muted); font-size: calc(13px * var(--text-scale)); }
138
+ .turn { margin-top: 10px; padding: 12px; border: 1px solid var(--line); border-radius: 10px; opacity: .85; }
139
+ .turn h4 { margin: 0 0 6px; font-size: calc(15px * var(--text-scale)); }
140
+ .turn p { margin: 0 0 10px; }
141
+ .turn .ans { padding: 8px 10px; border-radius: 8px; background: var(--bg); }
142
+ .turn .chip { display: inline-block; font-size: calc(13px * var(--text-scale)); font-weight: 600; padding: 2px 10px; border: 1px solid var(--line); border-radius: 999px; margin-bottom: 6px; }
143
+ .turn .cmt { white-space: pre-wrap; font-size: calc(14px * var(--text-scale)); }
144
+ .focus-card textarea { field-sizing: content; min-height: 4.5em; max-height: none; overflow: hidden; resize: none; }
145
+ .ico { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 6px; cursor: default; }
146
+ .ico svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
147
+ .ico.dim { opacity: .35; }
148
+ .ico path.fill { fill: currentColor; }
149
+ .ico path.gap { stroke: var(--info-bg); stroke-width: 1.5; }
150
+ .ico:hover::after, .ico:focus-visible::after { content: attr(data-tip); position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%); white-space: nowrap; background: var(--ink); color: var(--bg); font-size: calc(12px * var(--text-scale)); font-weight: 500; padding: 4px 8px; border-radius: 6px; z-index: 20; pointer-events: none; }
151
+ .q .ico:hover::after { left: auto; right: 0; transform: none; }
152
+ .collapse { overflow: hidden; transition: max-height .6s ease, opacity .6s ease; }
153
+ @media (prefers-reduced-motion: reduce) { .collapse { transition: none; } }
154
+ .origin { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 10px; font-size: calc(13px * var(--text-scale)); color: var(--muted); }
155
+ .origin .btn { padding: 2px 10px; }
156
+ .origin .herdr-place { flex-basis: 100%; }
157
+ .from { margin: 0 0 4px; font-weight: 600; font-size: calc(13px * var(--text-scale)); }
158
+ .pill.small { font-size: calc(12px * var(--text-scale)); padding: 2px 8px; }
159
+ .chain { margin: 0 0 12px; font-size: calc(13px * var(--text-scale)); }
160
+ .chain a { color: var(--accent); cursor: pointer; text-decoration: underline; }
161
+ .signin { max-width: 560px; margin: 64px auto; padding: 24px; background: var(--panel); border: 1px solid var(--line); border-radius: 12px; }
162
+ .signin code { background: var(--bg); padding: 2px 6px; border-radius: 4px; }
163
+ .pin-row { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; margin: 8px 0; }
164
+ .pin-row label { display: inline-flex; align-items: center; gap: 8px; }
165
+ .pin-input { font: calc(16px * var(--text-scale))/1.2 var(--font-code); letter-spacing: .3em; padding: 6px 10px; width: 7.5em; border: 1px solid var(--line); border-radius: 8px; background: var(--bg); color: var(--ink); }
166
+ .pin-input:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
167
+ .pin-error { color: var(--bad); margin: 8px 0; }
168
+ .pin-help { color: var(--muted); }
169
+ .pin-help code { white-space: nowrap; }
170
+ .pin-controls { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px; }
171
+ .html-answer { display: grid; gap: 12px; margin-top: 14px; }
172
+ .secret { display: grid; gap: 6px; }
173
+ .html-answer-actions { display: flex; flex-wrap: wrap; gap: 8px; }
174
+ .html-answer label { display: grid; gap: 4px; font-size: calc(14px * var(--text-scale)); font-weight: 600; }
175
+ .html-answer textarea,
176
+ .secret input { font: inherit; font-weight: 400; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--line); background: var(--bg); color: var(--ink); }
177
+ .secret .secret-field { position: relative; display: block; }
178
+ .secret .secret-field input { width: 100%; box-sizing: border-box; padding-left: 34px; }
179
+ .secret .key-icon { position: absolute; left: 10px; top: 50%; width: 16px; height: 16px; transform: translateY(-50%); color: var(--muted); pointer-events: none; }
180
+ .secret .hint { font-size: calc(13px * var(--text-scale)); color: var(--muted); }
181
+ .btn.primary { background: var(--accent); color: var(--bg); border-color: var(--accent); }
182
+ .btn.danger { background: var(--bad); color: var(--bg); border-color: var(--bad); }
183
+ .btn:disabled { opacity: .5; cursor: default; }
184
+ /* An icon button inside a row of card buttons, such as Dismiss: it keeps its own tooltip, so the span carries it. */
185
+ .ib-titled { display: inline-flex; }
186
+ /* What the person had typed on a card they dismissed. Only they read it. */
187
+ .dismiss-draft { margin: 10px 0 0; padding: 10px 12px; border: 1px dashed var(--line); border-radius: 10px; background: var(--bg); }
188
+ .dismiss-draft-head { font-size: calc(12px * var(--text-scale)); font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 4px; }
189
+ .dismiss-draft-body { white-space: pre-wrap; font-size: calc(14px * var(--text-scale)); }
190
+ .group-by { display: flex; gap: 6px; align-items: center; font-size: calc(12px * var(--text-scale)); color: var(--muted); padding: 4px 8px; }
191
+ .group-by select { font: inherit; background: var(--bg); color: var(--ink); border: 1px solid var(--line); border-radius: 6px; padding: 2px 4px; }
192
+ .prio.small { font-size: calc(11px * var(--text-scale)); padding: 0 6px; margin-left: 6px; }
193
+ .prio:not(.now):not(.soon):not(.later) { color: var(--info); background: var(--info-bg); }
194
+ .status { font-size: calc(12px * var(--text-scale)); padding: 2px 8px; border-radius: 6px; background: var(--bg); border: 1px solid var(--line); }
195
+ .status.warn { color: var(--warn); background: var(--warn-bg); border-color: transparent; }
196
+ .card-text { white-space: pre-wrap; margin: 0 0 12px; }
197
+ .card-text > :first-child { margin-top: 0; }
198
+ .card-text p, .card-text ul, .card-text ol { margin: 0 0 8px; }
199
+ .recommendation { border-left: 3px solid var(--accent); padding: 2px 0 2px 12px; margin: 0 0 12px; }
200
+ .check-with-text .row { display: flex; align-items: center; gap: 8px; }
201
+ .check-with-text .reveal { background: none; border: 0; padding: 0; color: var(--accent); font: inherit; text-decoration: underline dotted; text-underline-offset: 3px; cursor: pointer; text-align: left; }
202
+ .check-with-text .revealed { margin-top: 8px; }
203
+ .recommendation .label { display: block; color: var(--accent); margin-bottom: 4px; }
204
+ .recommendation .card-text, .recommendation .card-text > :last-child { margin-bottom: 0; }
205
+ /* The recommended option: a tag and the recommendation below its description, with the callout's accent line and no fill, so it never reads as a pick. */
206
+ .openui-option-card__top:has(> .rec-in-option) { order: 1; align-self: stretch; width: auto; height: auto; border-radius: 0; background: none; color: inherit; display: block; }
207
+ .rec-in-option { border-left: 3px solid var(--accent); padding: 0 0 0 10px; }
208
+ .rec-tag { display: block; color: var(--accent); font-size: calc(13px * var(--text-scale)); margin-bottom: 2px; }
209
+ .rec-in-option .card-text { font: var(--openui-text-body-sm); color: var(--body-text); }
210
+ .rec-in-option .card-text, .rec-in-option .card-text > :last-child { margin-bottom: 0; }
211
+ .card-link { color: var(--accent); cursor: pointer; text-decoration: underline; }
212
+ /* A link to another agent's session, in a card's text, body or file. A click opens it in herdr. */
213
+ a[href^="https://herdr.invalid/v1/"] { color: var(--accent); cursor: pointer; text-decoration: none; border: 1px solid var(--line); border-radius: 6px; padding: 0 .35em; white-space: nowrap; display: inline-flex; align-items: center; gap: .3em; vertical-align: bottom; }
214
+ a[href^="https://herdr.invalid/v1/"]::before { content: ''; flex: none; width: .9em; height: .9em; background: currentColor; -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m7 11 2-2-2-2'/%3E%3Cpath d='M11 13h4'/%3E%3Crect width='18' height='18' x='3' y='3' rx='2'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m7 11 2-2-2-2'/%3E%3Cpath d='M11 13h4'/%3E%3Crect width='18' height='18' x='3' y='3' rx='2'/%3E%3C/svg%3E") center / contain no-repeat; }
215
+ a[href^="https://herdr.invalid/v1/"]:hover { border-color: var(--accent); }
216
+ a[href^="https://herdr.invalid/v1/"][data-failed]:not([data-failed=""])::after { content: ' · ' attr(data-failed); color: var(--bad); white-space: normal; }
217
+ /* A file a card names, as a chip: its type icon and name, and a button that copies its path. Hovering the name shows the path. */
218
+ .file-chip { display: inline-flex; align-items: center; gap: .15em; max-width: 100%; border: 1px solid var(--line); border-radius: 6px; padding: 0 .1em 0 .35em; white-space: nowrap; vertical-align: bottom; }
219
+ .file-chip:hover, .file-chip:focus-within { border-color: var(--accent); }
220
+ .file-chip .file-link { display: inline-flex; align-items: center; gap: .3em; min-width: 0; color: var(--accent); text-decoration: none; }
221
+ .file-chip-name { overflow: hidden; text-overflow: ellipsis; }
222
+ .file-chip svg { flex: none; width: .9em; height: .9em; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
223
+ .file-copy { display: inline-flex; align-items: center; padding: .15em; border: 0; border-radius: 4px; background: none; color: var(--muted); cursor: pointer; }
224
+ .file-copy:hover, .file-copy:focus-visible { color: var(--ink); }
225
+ .file-copy[data-copied="Copied"] { color: var(--ok); }
226
+ .cleared-link, .unknown-link { color: var(--muted); }
227
+ .cleared-link { text-decoration: underline dotted; text-underline-offset: 3px; cursor: help; }
228
+ .attachments { display: grid; gap: 12px; margin: 0 0 12px; }
229
+ .gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 8px; }
230
+ .gallery img { width: 100%; height: 140px; object-fit: cover; border-radius: 8px; border: 1px solid var(--line); background: var(--bg); }
231
+ .file { border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
232
+ .file-head { display: flex; gap: 8px; align-items: baseline; padding: 6px 10px; background: var(--bg); font-size: calc(13px * var(--text-scale)); }
233
+ .file-name { color: var(--accent); font-weight: 600; overflow-wrap: anywhere; }
234
+ .file-size { color: var(--muted); }
235
+ /* An attachment grows with the card, so the page is the only vertical scroll. Wide code and tables scroll sideways. */
236
+ .file pre, .file .markdown, .file table { margin: 0; padding: 10px; overflow-x: auto; }
237
+ .file iframe.pdf { width: 100%; height: 520px; border: 0; display: block; }
238
+ .markdown table, .file table.csv { border-collapse: collapse; }
239
+ /* OpenUI keeps each table cell on one line, so a long cell pushed the table past the card. Cells wrap at word breaks. */
240
+ .openui-table-cell { white-space: normal; vertical-align: top; }
241
+ .markdown th, .markdown td, .file table.csv th, .file table.csv td { border: 1px solid var(--line); padding: 4px 8px; }
242
+ /* A diagram shrinks to the card's width and never grows past its own. Its labels keep mermaid's line breaks, not the text's. */
243
+ .diagram { margin: 8px 0 12px; white-space: normal; overflow-x: auto; }
244
+ .diagram svg { display: block; max-width: 100%; height: auto; margin: 0 auto; }
245
+ .markdown blockquote { margin: 0; padding-left: 10px; border-left: 3px solid var(--line); color: var(--muted); }
246
+ .html-card { display: block; width: 100%; height: 360px; border: 1px solid var(--line); border-radius: 8px; background: var(--panel); }
247
+ details.changes { margin: 0 0 12px; font-size: calc(13px * var(--text-scale)); }
248
+ details.changes .del { color: var(--bad); white-space: pre-wrap; }
249
+ details.changes .add { color: var(--ok); white-space: pre-wrap; }
250
+ details.changes mark { color: inherit; border-radius: 3px; padding: 0 2px; }
251
+ details.changes .del mark { background: var(--bad-bg); }
252
+ details.changes .add mark { background: var(--ok-bg); }
253
+ .broadcast .field { color: var(--muted); font-size: calc(13px * var(--text-scale)); }
254
+ .broadcast .guidance-diff { background: var(--bg); padding: 10px; border-radius: 8px; margin: 6px 0; font-size: calc(13px * var(--text-scale)); }
255
+ .broadcast .guidance-diff > div { white-space: pre-wrap; }
256
+ .broadcast .guidance-diff .del { color: var(--bad); }
257
+ .broadcast .guidance-diff .add { color: var(--ok); }
258
+ .broadcast .guidance-diff .same-run, .broadcast .guidance-diff .undone { color: var(--muted); font-style: italic; }
259
+ .broadcast .guidance-diff mark { color: inherit; border-radius: 3px; padding: 0 2px; }
260
+ .broadcast .guidance-diff .del mark { background: var(--bad-bg); }
261
+ .broadcast .guidance-diff .add mark { background: var(--ok-bg); }
262
+ .broadcast .broadcast-message { margin: 8px 0 0; white-space: pre-wrap; font-size: calc(14px * var(--text-scale)); }
263
+ .broadcast .agents { display: grid; gap: 4px; margin: 8px 0; padding: 0; border: 0; font-size: calc(14px * var(--text-scale)); }
264
+ .broadcast .agents legend { font-weight: 600 !important; padding: 0; margin-bottom: 4px; }
265
+ .broadcast .agents .all { font-weight: 600 !important; border-bottom: 1px solid var(--line); padding-bottom: 4px; }
266
+ .broadcast .agents .hint { color: var(--muted); font-size: calc(13px * var(--text-scale)); }
267
+ .markdown a, .card-text a, .focus-card label a { color: var(--accent); }
268
+ .card-title { font-size: calc(18px * var(--text-scale)); margin: 4px 0 8px; }
269
+ details.changes .step { margin: 6px 0; }
270
+ details.changes .step-head { font-weight: 600; }
271
+ details.changes .field { color: var(--muted); margin-top: 2px; }
272
+
273
+ /* Light Gill Sans, a little larger and spaced out, for easier reading. OpenUI sets the font on
274
+ each of its elements, so these rules override it with !important. Code stays monospace.
275
+ Sizes scale by --text-scale rather than CSS zoom, which misplaces clicks inside an HTML card's frame. */
276
+ body, body * { font-family: var(--font-text) !important; font-weight: 200 !important; letter-spacing: .02em !important; }
277
+ h1, h2, h3, h4, h5, h6, strong, b, th { font-weight: 300 !important; }
278
+ code, code *, pre, pre *, kbd, samp, .qr-address,
279
+ .openui-tool-call__request, .openui-tool-call__response, .openui-tool-code-block__code, .openui-tool-result__output {
280
+ font-family: var(--font-code) !important; letter-spacing: normal !important;
281
+ }
282
+ /* The PIN field is monospace with wide tracking, so each typed digit shows as its own dot. */
283
+ .pin-input { font-family: var(--font-code) !important; letter-spacing: .3em !important; }
284
+ :root {
285
+ --openui-text-body-default: 400 calc(16px * var(--text-scale))/1.5 var(--font-text);
286
+ --openui-text-body-default-heavy: 560 calc(16px * var(--text-scale))/1.5 var(--font-text);
287
+ --openui-text-body-lg: 400 calc(18px * var(--text-scale))/1.5 var(--font-text);
288
+ --openui-text-body-lg-heavy: 560 calc(18px * var(--text-scale))/1.5 var(--font-text);
289
+ --openui-text-body-sm: 400 calc(14px * var(--text-scale))/1.5 var(--font-text);
290
+ --openui-text-body-sm-heavy: 560 calc(14px * var(--text-scale))/1.5 var(--font-text);
291
+ --openui-text-body-xs: 400 calc(12px * var(--text-scale))/1.5 var(--font-text);
292
+ --openui-text-body-xs-heavy: 560 calc(12px * var(--text-scale))/1.5 var(--font-text);
293
+ --openui-text-code-default: 400 calc(14px * var(--text-scale))/1.5 var(--font-code);
294
+ --openui-text-code-default-heavy: 700 calc(14px * var(--text-scale))/1.5 var(--font-code);
295
+ --openui-text-code-sm: 400 calc(12px * var(--text-scale))/1.5 var(--font-code);
296
+ --openui-text-code-sm-heavy: 700 calc(12px * var(--text-scale))/1.5 var(--font-code);
297
+ --openui-text-heading-lg: 600 calc(28px * var(--text-scale))/1.1 var(--font-text);
298
+ --openui-text-heading-md: 600 calc(24px * var(--text-scale))/1.1 var(--font-text);
299
+ --openui-text-heading-sm: 600 calc(18px * var(--text-scale))/1.25 var(--font-text);
300
+ --openui-text-heading-xl: 700 calc(32px * var(--text-scale))/1.1 var(--font-text);
301
+ --openui-text-heading-xs: 600 calc(16px * var(--text-scale))/1.25 var(--font-text);
302
+ --openui-text-label-default: 400 calc(16px * var(--text-scale))/1.25 var(--font-text);
303
+ --openui-text-label-default-heavy: 560 calc(16px * var(--text-scale))/1.25 var(--font-text);
304
+ --openui-text-label-lg: 400 calc(18px * var(--text-scale))/1.25 var(--font-text);
305
+ --openui-text-label-lg-heavy: 560 calc(18px * var(--text-scale))/1.25 var(--font-text);
306
+ --openui-text-label-sm: 400 calc(14px * var(--text-scale))/1.25 var(--font-text);
307
+ --openui-text-label-sm-heavy: 560 calc(14px * var(--text-scale))/1.25 var(--font-text);
308
+ --openui-text-label-xs: 400 calc(12px * var(--text-scale))/1.25 var(--font-text);
309
+ --openui-text-label-xs-heavy: 560 calc(12px * var(--text-scale))/1.25 var(--font-text);
310
+ --openui-text-numbers-default: 400 calc(16px * var(--text-scale))/1.5 var(--font-text);
311
+ --openui-text-numbers-default-heavy: 560 calc(16px * var(--text-scale))/1.5 var(--font-text);
312
+ --openui-text-numbers-heading-lg: 600 calc(28px * var(--text-scale))/1.1 var(--font-text);
313
+ --openui-text-numbers-heading-md: 600 calc(24px * var(--text-scale))/1.1 var(--font-text);
314
+ --openui-text-numbers-heading-sm: 600 calc(18px * var(--text-scale))/1.25 var(--font-text);
315
+ --openui-text-numbers-heading-xl: 600 calc(32px * var(--text-scale))/1.1 var(--font-text);
316
+ --openui-text-numbers-lg: 400 calc(18px * var(--text-scale))/1.5 var(--font-text);
317
+ --openui-text-numbers-lg-heavy: 560 calc(18px * var(--text-scale))/1.5 var(--font-text);
318
+ --openui-text-numbers-sm: 400 calc(14px * var(--text-scale))/1.5 var(--font-text);
319
+ --openui-text-numbers-sm-heavy: 560 calc(14px * var(--text-scale))/1.5 var(--font-text);
320
+ --openui-text-numbers-xs: 400 calc(12px * var(--text-scale))/1.5 var(--font-text);
321
+ --openui-text-numbers-xs-heavy: 560 calc(12px * var(--text-scale))/1.5 var(--font-text);
322
+ }
323
+ .queue h3 { font-weight: 600 !important; }
324
+ /* The border between the queue and the card. Drag it, or focus it and press the arrow keys. */
325
+ .resizer { position: absolute; top: 16px; bottom: 16px; left: calc(16px + var(--queue-w, 290px) + 4px); width: 12px; cursor: col-resize; touch-action: none; }
326
+ .resizer::after { content: ""; position: absolute; top: 0; bottom: 0; left: 5px; width: 2px; border-radius: 1px; }
327
+ .resizer:hover::after, .resizer:focus-visible::after, .resizer.dragging::after { background: var(--accent); }
328
+ .resizer:focus-visible { outline: none; }
329
+ .clear-dealt { display: block; margin: 16px 0 4px; }
330
+ .phone, .devices-open { display: inline-flex; color: var(--muted); background: none; border: 0; padding: 0; cursor: pointer; }
331
+ .phone:hover, .phone:focus-visible, .devices-open:hover, .devices-open:focus-visible { color: var(--ink); }
332
+ .muted { color: var(--muted); }
333
+ .qr-dialog { border: 1px solid var(--line); border-radius: 12px; background: var(--panel); color: var(--ink); padding: 20px; width: min(560px, calc(100vw - 32px)); max-height: calc(100dvh - 32px); overflow: auto; }
334
+ .qr-dialog::backdrop { background: rgb(0 0 0 / .45); }
335
+ .qr-dialog h2 { font-size: calc(18px * var(--text-scale)); margin: 0 0 4px; }
336
+ .qr-dialog p { margin: 0 0 8px; }
337
+ .qr { display: flex; justify-content: center; margin: 12px 0; min-height: 120px; align-items: center; }
338
+ .qr svg { width: min(260px, 100%); height: auto; aspect-ratio: 1; border-radius: 8px; }
339
+ .qr-address { font-family: var(--font-code); font-size: 13px; overflow-wrap: anywhere; user-select: all; }
340
+ .qr-actions { display: flex; gap: 8px; justify-content: flex-end; flex-wrap: wrap; margin-top: 12px; }
341
+ .to-queue { display: none; }
342
+ .qr-dialog code { font-size: .85em; overflow-wrap: anywhere; }
343
+ .devices-dialog .devices { list-style: none; margin: 10px 0 4px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
344
+ .devices-dialog .device { display: flex; gap: 10px; align-items: center; justify-content: space-between; flex-wrap: wrap; border: 1px solid var(--line); border-radius: 8px; padding: 8px 10px; }
345
+ .devices-dialog .device-what { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
346
+ .devices-dialog .device-name { overflow-wrap: anywhere; }
347
+ .devices-dialog .device-facts { font-size: calc(12px * var(--text-scale)); color: var(--muted); }
348
+ .devices-dialog .device-actions { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; justify-content: flex-end; flex-basis: 100%; }
349
+ .devices-dialog .device-actions .note { font-size: calc(12px * var(--text-scale)); margin: 0; flex-basis: 100%; }
350
+ .qr-dialog .note, .qr-dialog .muted { font-size: calc(13px * var(--text-scale)); }
351
+ /* A phone: the bar scrolls away, the title, the status and the links share the first row, and every control is big enough for a thumb. */
352
+ @media (max-width: 760px) {
353
+ /* One page scroll on a phone: the queue grows with its cards instead of scrolling inside itself. */
354
+ .queue { position: static; max-height: none; overflow: visible; }
355
+ .bar { position: static; }
356
+ .bar-inner { padding: 6px 16px 8px; gap: 0 12px; }
357
+ .bar h1 { order: 0; }
358
+ .status-pill { order: 1; }
359
+ .phone, .devices-open, .repo { order: 1; min-width: 44px; min-height: 44px; align-items: center; justify-content: center; }
360
+ .bar-inner::after { content: ""; order: 2; flex-basis: 100%; height: 0; }
361
+ .bar-search { order: 4; flex: 1 1 100%; margin: 6px 0 4px; height: 36px; font-size: 16px; }
362
+ .notify { order: 3; min-height: 40px; }
363
+ .notify input { width: 20px; height: 20px; }
364
+ /* Connected shows as its dot alone; a lost connection keeps its words. */
365
+ .status-pill.on { padding: 6px; }
366
+ .status-pill.on .pill-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
367
+ .pill { white-space: normal; }
368
+ .pill::before { flex: none; }
369
+ .to-queue { display: block; width: 100%; margin: 0 0 12px; min-height: 40px; }
370
+ /* iOS zooms the page into a field whose text is under 16px. */
371
+ input, textarea, select { font-size: max(16px, 1em); }
372
+ .queue select, .group-by select { min-height: 36px; font-size: 16px; }
373
+ .queue h3 .fold { min-height: 36px; }
374
+ /* A terminal screen keeps its lines, so it scrolls sideways; smaller text and padding show more of each line. The highlighter sets both inline or as important. */
375
+ .layout .openui-code-block-syntax-highlighter { padding: 12px !important; }
376
+ .layout .openui-code-block-syntax-highlighter, .layout .openui-code-block-syntax-highlighter code { font-size: 11px !important; }
377
+ .qr-dialog { padding: 16px; }
378
+ .qr { margin: 8px 0; }
379
+ .qr svg { width: min(220px, 60vw); }
380
+ }
381
+
382
+ /* Code copies with a click: a block through its Copy button at its top right, inline code by a click on it. web/copy.js
383
+ The button stays dim until the pointer is over the block or the button has focus. OpenUI's own button looks the same. */
384
+ .code-block { position: relative; }
385
+ .copy-button, .openui-code-block-wrapper > .openui-code-block-copy-button {
386
+ position: absolute; top: 6px; right: 6px; z-index: 1; display: inline-flex; align-items: center; gap: 4px;
387
+ min-width: 0; height: auto; padding: 4px; border: 1px solid var(--line); border-radius: 6px;
388
+ background: var(--panel); color: var(--muted); cursor: pointer; opacity: .45; transition: opacity .15s ease;
389
+ }
390
+ .code-block:hover > .copy-button, .copy-button:focus, .copy-button[data-copied],
391
+ .openui-code-block-wrapper:hover > .openui-code-block-copy-button, .openui-code-block-wrapper > .openui-code-block-copy-button:focus,
392
+ .openui-code-block-wrapper > .openui-code-block-copy-button[data-copied] { opacity: 1; }
393
+ .copy-button:focus-visible, .openui-code-block-copy-button:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
394
+ .copy-button svg { display: block; width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
395
+ .copy-button .check-icon, .copy-button[data-copied="Copied"] .copy-icon { display: none; }
396
+ .copy-button[data-copied="Copied"] .check-icon { display: block; }
397
+ .copy-button[data-copied]::before, .openui-code-block-copy-button[data-copied]::before { content: attr(data-copied); font-size: calc(12px * var(--text-scale)); line-height: 1; padding: 0 2px; }
398
+ .copy-button[data-copied="Copied"], .openui-code-block-copy-button[data-copied="Copied"] { color: var(--ok); }
399
+ .copy-button[data-copied="Copy failed"], .openui-code-block-copy-button[data-copied="Copy failed"] { color: var(--bad); }
400
+ @media (prefers-reduced-motion: reduce) { .copy-button, .openui-code-block-copy-button { transition: none; } }
401
+ code:not(pre code, a code, .openui-code-block-wrapper code) { cursor: pointer; }
402
+ .copy-toast { position: fixed; z-index: 30; transform: translate(-50%, calc(-100% - 6px)); padding: 2px 8px; border-radius: 6px; background: var(--ink); color: var(--panel); font-size: calc(12px * var(--text-scale)); line-height: 1.4; white-space: nowrap; pointer-events: none; }
403
+ .copy-toast[data-tone="bad"] { background: var(--bad); }
404
+ .copy-toast:not([data-show]) { opacity: 0; }
405
+ /* An approval: the sentence the inbox types into a pane, its toggle and its pane link beside it, then the pane it goes to. */
406
+ .approvals { margin: 0 0 12px; display: flex; flex-direction: column; gap: 12px; }
407
+ .approval-label { color: var(--ink); margin-bottom: 4px; }
408
+ .approval-row { display: flex; gap: 10px; align-items: flex-start; flex-wrap: wrap; }
409
+ .approval-row > .code-block { flex: 1 1 260px; min-width: 0; }
410
+ .approval-row pre { margin: 0; padding: 10px 40px 10px 12px; border: 1px solid var(--line); border-radius: 8px; white-space: pre-wrap; overflow-wrap: anywhere; }
411
+ .approval-actions { display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
412
+ .approval-toggle { min-width: 96px; }
413
+ .approval-toggle.on { color: var(--ok); background: var(--ok-bg); border-color: var(--ok); }
414
+ .approval-toggle:disabled { opacity: 1; }
415
+ .approval-place, .approval-result { color: var(--muted); margin-top: 4px; }
416
+ .approval-result { color: var(--ok); }
417
+ .approval-result.failed { color: var(--bad); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "your-attention",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "One inbox where all your coding agents ask you questions as cards, and your answers reach them at once.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -19,6 +19,7 @@
19
19
  },
20
20
  "files": [
21
21
  "bin",
22
+ "dist",
22
23
  "src",
23
24
  "web",
24
25
  "LICENSE",
@@ -45,7 +46,8 @@
45
46
  "cloudflare:check": "npm run cloudflare:build && wrangler deploy --dry-run --outdir .cloudflare/dist",
46
47
  "cpu-budget": "node --disable-warning=ExperimentalWarning scripts/cpu-budget.ts",
47
48
  "check:principles": "node --disable-warning=ExperimentalWarning scripts/check-principle-links.ts",
48
- "test:cloudflare": "npm run cloudflare:build && node --test --test-concurrency=1 --disable-warning=ExperimentalWarning \"test/cloudflare/**/*.test.ts\""
49
+ "test:cloudflare": "npm run cloudflare:build && node --test --test-concurrency=1 --disable-warning=ExperimentalWarning \"test/cloudflare/**/*.test.ts\"",
50
+ "prepack": "node scripts/pack-sources.js"
49
51
  },
50
52
  "dependencies": {
51
53
  "@modelcontextprotocol/sdk": "1.32.2",
@@ -1,2 +1,2 @@
1
1
  // The release in package.json. A unit test keeps the two in step, so the core needs no JSON import.
2
- export const VERSION = '0.1.0';
2
+ export const VERSION = '0.1.1';