@tiagojct/subsub 0.5.0 → 0.6.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/web/app.css ADDED
@@ -0,0 +1,203 @@
1
+ /* Sub-Sub web view. Glauca tokens (glauca.css); the librarian gets the Try-Works orange. */
2
+
3
+ @font-face { font-family: "IBM Plex Sans"; src: url("/fonts/IBMPlexSans.woff2") format("woff2"); font-weight: 100 700; font-display: swap; }
4
+ @font-face { font-family: "IBM Plex Serif"; src: url("/fonts/IBMPlexSerif.woff2") format("woff2"); font-weight: 100 700; font-display: swap; }
5
+ @font-face { font-family: "IBM Plex Mono"; src: url("/fonts/IBMPlexMono.woff2") format("woff2"); font-weight: 100 700; font-display: swap; }
6
+
7
+ :root {
8
+ --mode: var(--gl-accent);
9
+ --mode-deep: var(--gl-accent-deep);
10
+ --on-mode: var(--gl-on-accent);
11
+ --add: #1d7a3a;
12
+ --rem: #b3261e;
13
+ --warn: #8a5a00;
14
+ --side-w: 17rem;
15
+ }
16
+ @media (prefers-color-scheme: dark) {
17
+ :root {
18
+ --gl-bg: #10161c;
19
+ --gl-surface: #171f26;
20
+ --gl-surface-raised: #1f2932;
21
+ --gl-text: #e8eef2;
22
+ --gl-text-muted: #9aa4ab;
23
+ --gl-border: #2a3540;
24
+ --gl-accent: #3d97ff;
25
+ --gl-accent-bright: #6cb2ff;
26
+ --gl-accent-deep: #007aff;
27
+ --gl-on-accent: #0b1218;
28
+ --gl-tint-pale: #93b7c9;
29
+ --add: #8fcf9a;
30
+ --rem: #f0a39c;
31
+ --warn: #e3b35c;
32
+ }
33
+ }
34
+ body[data-mode="librarian"] { --mode: #a8520f; --mode-deep: #7f3d09; --on-mode: #fff8f0; }
35
+ @media (prefers-color-scheme: dark) {
36
+ body[data-mode="librarian"] { --mode: #e0832a; --mode-deep: #f09a48; --on-mode: #140c04; }
37
+ }
38
+
39
+ *, *::before, *::after { box-sizing: border-box; }
40
+ html, body { height: 100%; }
41
+ body {
42
+ margin: 0; background: var(--gl-bg); color: var(--gl-text);
43
+ font-family: var(--gl-font-sans); font-size: 1rem; line-height: 1.55;
44
+ }
45
+ button, input, select, textarea { font: inherit; color: inherit; }
46
+ a { color: var(--gl-accent); }
47
+ .visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
48
+ [hidden] { display: none !important; }
49
+ :focus-visible { outline: 2px solid var(--mode); outline-offset: 2px; }
50
+
51
+ /* ---- buttons */
52
+ button { cursor: pointer; border-radius: var(--gl-radius-md); border: 1px solid transparent; padding: 0.45rem 0.9rem; background: none; }
53
+ button:disabled { opacity: 0.5; cursor: default; }
54
+ .primary { background: var(--mode); color: var(--on-mode); font-weight: 600; }
55
+ .primary:hover:not(:disabled) { background: var(--mode-deep); }
56
+ .secondary { border-color: var(--gl-border); background: var(--gl-surface-raised); }
57
+ .secondary:hover:not(:disabled) { border-color: var(--mode); }
58
+ .ghost { color: var(--gl-text-muted); }
59
+ .ghost:hover { color: var(--gl-text); background: var(--gl-surface); }
60
+ .small { font-size: 0.85rem; }
61
+ .muted { color: var(--gl-text-muted); }
62
+ .block { width: 100%; }
63
+
64
+ /* ---- layout */
65
+ .app { display: grid; grid-template-columns: var(--side-w) minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); height: 100vh; height: 100dvh; }
66
+ .top {
67
+ grid-column: 1 / -1; display: flex; align-items: center; gap: 0.75rem 1.25rem; flex-wrap: wrap;
68
+ padding: 0.6rem 1rem; border-bottom: 1px solid var(--gl-border); background: var(--gl-surface);
69
+ }
70
+ .brand { font-family: var(--gl-font-serif); font-weight: 600; font-size: 1.15rem; display: flex; align-items: center; gap: 0.45rem; }
71
+ .mark { font-family: var(--gl-font-mono); font-size: 0.75rem; font-weight: 600; background: #12161b; color: #e0832a; padding: 0.15rem 0.35rem; border-radius: var(--gl-radius-md); }
72
+ .menu-btn { display: none; }
73
+ .modes { display: inline-flex; border: 1px solid var(--gl-border); border-radius: var(--gl-radius-pill); padding: 2px; background: var(--gl-bg); }
74
+ .modes button { border-radius: var(--gl-radius-pill); padding: 0.3rem 0.9rem; color: var(--gl-text-muted); }
75
+ .modes button[aria-pressed="true"] { background: var(--mode); color: var(--on-mode); font-weight: 600; }
76
+ .status { margin-left: auto; display: flex; align-items: center; gap: 0.5rem 0.9rem; flex-wrap: wrap; font-size: 0.88rem; }
77
+ .library { color: var(--gl-text-muted); }
78
+ .library.down { color: var(--rem); font-weight: 600; }
79
+ .status select { border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); background: var(--gl-surface-raised); padding: 0.3rem 0.5rem; }
80
+ .model-btn { font-family: var(--gl-font-mono); font-size: 0.8rem; border: 1px solid var(--gl-border); }
81
+
82
+ .side { border-right: 1px solid var(--gl-border); background: var(--gl-surface); padding: 1rem; display: flex; flex-direction: column; gap: 1.25rem; overflow-y: auto; }
83
+ .side h2 { font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--gl-text-muted); margin: 0 0 0.5rem; font-weight: 600; }
84
+ .side .grow { flex: 1; }
85
+ .actions { display: flex; flex-direction: column; gap: 0.25rem; }
86
+ .actions button { text-align: left; padding: 0.35rem 0.6rem; border-radius: var(--gl-radius-md); }
87
+ .actions button:hover { background: var(--gl-bg); }
88
+ .actions hr { border: 0; border-top: 1px solid var(--gl-border); margin: 0.35rem 0; width: 100%; }
89
+ .sessions { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.15rem; }
90
+ .sessions button { width: 100%; text-align: left; padding: 0.4rem 0.6rem; display: block; }
91
+ .sessions button:hover { background: var(--gl-bg); }
92
+ .sessions .current button { background: var(--gl-bg); border-color: var(--gl-border); }
93
+ .sessions .when { display: block; font-size: 0.75rem; color: var(--gl-text-muted); }
94
+ .sessions .what { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; font-size: 0.88rem; }
95
+ .side-foot { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; }
96
+ .version { font-size: 0.75rem; color: var(--gl-text-muted); font-family: var(--gl-font-mono); }
97
+
98
+ /* ---- conversation */
99
+ .chat { display: flex; flex-direction: column; min-height: 0; }
100
+ .banner { margin: 0.75rem 1rem 0; padding: 0.6rem 0.9rem; border: 1px solid var(--gl-border); border-left: 3px solid var(--warn); border-radius: var(--gl-radius-md); background: var(--gl-surface); display: flex; gap: 0.75rem; align-items: center; flex-wrap: wrap; }
101
+ .log { flex: 1; overflow-y: auto; padding: 1.25rem 1rem 2rem; }
102
+ .log > * { max-width: 48rem; margin-left: auto; margin-right: auto; }
103
+ .msg { margin-top: 1.1rem; }
104
+ .msg.user { display: flex; justify-content: flex-end; }
105
+ .msg.user .bubble { background: var(--gl-surface-raised); border: 1px solid var(--gl-border); border-radius: 12px 12px 3px 12px; padding: 0.55rem 0.9rem; max-width: 85%; white-space: pre-wrap; overflow-wrap: anywhere; }
106
+ .msg.assistant .md { overflow-wrap: anywhere; }
107
+ .md > :first-child { margin-top: 0; }
108
+ .md > :last-child { margin-bottom: 0; }
109
+ .md p, .md ul, .md ol { margin: 0.6rem 0; }
110
+ .md h1, .md h2, .md h3 { font-family: var(--gl-font-serif); line-height: 1.25; margin: 1.1rem 0 0.4rem; }
111
+ .md h1 { font-size: 1.35rem; } .md h2 { font-size: 1.2rem; } .md h3 { font-size: 1.05rem; }
112
+ .md code { font-family: var(--gl-font-mono); font-size: 0.86em; background: var(--gl-surface); border: 1px solid var(--gl-border); border-radius: var(--gl-radius-sm); padding: 0.05em 0.3em; }
113
+ .md pre { background: var(--gl-surface); border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); padding: 0.75rem; overflow-x: auto; font-size: 0.85rem; }
114
+ .md pre code { background: none; border: 0; padding: 0; }
115
+ .md blockquote { margin: 0.6rem 0; padding-left: 0.9rem; border-left: 3px solid var(--gl-tint-pale); color: var(--gl-text-muted); }
116
+ .md table { border-collapse: collapse; display: block; overflow-x: auto; font-size: 0.9rem; }
117
+ .md th, .md td { border-bottom: 1px solid var(--gl-border); padding: 0.3rem 0.6rem; text-align: left; vertical-align: top; }
118
+ .md th { font-size: 0.82rem; color: var(--gl-text-muted); }
119
+ .tool { margin-top: 0.5rem; font-size: 0.86rem; color: var(--gl-text-muted); }
120
+ .tool summary { cursor: pointer; list-style: none; display: flex; gap: 0.5rem; align-items: baseline; flex-wrap: wrap; }
121
+ .tool summary::-webkit-details-marker { display: none; }
122
+ .tool summary::before { content: ""; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--gl-border); flex: none; align-self: center; }
123
+ .tool.running summary::before { background: var(--mode); animation: pulse 1.2s ease-in-out infinite; }
124
+ .tool.done summary::before { background: var(--add); }
125
+ .tool.error summary::before { background: var(--rem); }
126
+ .tool .args { font-family: var(--gl-font-mono); font-size: 0.78rem; overflow-wrap: anywhere; }
127
+ .tool pre { white-space: pre-wrap; overflow-wrap: anywhere; font-size: 0.78rem; max-height: 18rem; overflow-y: auto; background: var(--gl-surface); border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); padding: 0.6rem; color: var(--gl-text); }
128
+ .tool .open { margin-left: 0.25rem; padding: 0.1rem 0.5rem; border: 1px solid var(--gl-border); font-size: 0.78rem; }
129
+ .note { margin-top: 1rem; padding: 0.6rem 0.9rem; border-radius: var(--gl-radius-md); background: var(--gl-surface); border: 1px solid var(--gl-border); font-size: 0.9rem; white-space: pre-wrap; overflow-wrap: anywhere; }
130
+ .note.warning { border-left: 3px solid var(--warn); }
131
+ .note.error { border-left: 3px solid var(--rem); }
132
+ .note.mono { font-family: var(--gl-font-mono); font-size: 0.82rem; }
133
+ .working { margin-top: 0.75rem; color: var(--gl-text-muted); font-size: 0.88rem; display: flex; gap: 0.5rem; align-items: center; }
134
+ .working::before { content: ""; width: 0.5rem; height: 0.5rem; border-radius: 50%; background: var(--mode); animation: pulse 1.2s ease-in-out infinite; }
135
+ @keyframes pulse { 50% { opacity: 0.3; } }
136
+ @media (prefers-reduced-motion: reduce) { .working::before, .tool.running summary::before { animation: none; } }
137
+
138
+ .empty { text-align: center; padding-top: 12vh; }
139
+ .empty h1 { font-family: var(--gl-font-serif); font-weight: 600; font-size: 1.6rem; margin: 0 0 1rem; }
140
+ .chips { display: flex; flex-wrap: wrap; gap: 0.5rem; justify-content: center; }
141
+ .chips button { border: 1px solid var(--gl-border); border-radius: var(--gl-radius-pill); background: var(--gl-surface-raised); padding: 0.4rem 0.9rem; }
142
+ .chips button:hover { border-color: var(--mode); }
143
+
144
+ /* ---- composer */
145
+ .composer { position: relative; display: flex; gap: 0.6rem; align-items: flex-end; padding: 0.75rem 1rem 1rem; border-top: 1px solid var(--gl-border); background: var(--gl-bg); }
146
+ .composer textarea {
147
+ flex: 1; resize: none; max-height: 40vh; min-height: 2.8rem; padding: 0.6rem 0.8rem;
148
+ border: 1px solid var(--gl-border); border-radius: var(--gl-radius-lg); background: var(--gl-surface-raised);
149
+ }
150
+ .composer textarea:focus { outline: none; border-color: var(--mode); box-shadow: 0 0 0 1px var(--mode); }
151
+ .composer-buttons { display: flex; gap: 0.4rem; }
152
+ .suggest { position: absolute; left: 1rem; right: 1rem; bottom: calc(100% - 0.25rem); max-width: 30rem; max-height: 16rem; overflow-y: auto; background: var(--gl-surface-raised); border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); box-shadow: 0 8px 24px -12px rgba(0,0,0,0.35); padding: 0.25rem; }
153
+ .suggest button { display: block; width: 100%; text-align: left; padding: 0.35rem 0.6rem; }
154
+ .suggest button[aria-selected="true"], .suggest button:hover { background: var(--gl-bg); }
155
+ .suggest .name { font-family: var(--gl-font-mono); font-size: 0.85rem; }
156
+ .suggest .desc { color: var(--gl-text-muted); font-size: 0.8rem; margin-left: 0.5rem; }
157
+
158
+ /* ---- dialogs */
159
+ .modal { border: 1px solid var(--gl-border); border-radius: var(--gl-radius-lg); background: var(--gl-surface-raised); color: var(--gl-text); padding: 1.25rem 1.4rem; width: min(40rem, calc(100vw - 2rem)); max-height: calc(100dvh - 2rem); overflow-y: auto; box-shadow: 0 24px 60px -20px rgba(0,0,0,0.5); }
160
+ .modal.wide { width: min(46rem, calc(100vw - 2rem)); }
161
+ .modal::backdrop { background: rgba(16, 22, 28, 0.55); }
162
+ .modal h2 { font-family: var(--gl-font-serif); font-size: 1.25rem; margin: 0 0 0.25rem; }
163
+ .modal h3 { font-size: 0.95rem; margin: 1.25rem 0 0.5rem; }
164
+ .modal .hint { color: var(--gl-text-muted); margin: 0 0 0.75rem; font-size: 0.9rem; }
165
+ .preview { font-family: var(--gl-font-mono); font-size: 0.82rem; line-height: 1.5; white-space: pre-wrap; overflow-wrap: anywhere; background: var(--gl-surface); border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); padding: 0.75rem; max-height: 55vh; overflow-y: auto; margin: 0 0 1rem; }
166
+ .preview .add { color: var(--add); font-weight: 600; }
167
+ .preview .rem { color: var(--rem); font-weight: 600; }
168
+ .modal-buttons { display: flex; justify-content: flex-end; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.5rem; }
169
+ .modal-head { display: flex; justify-content: space-between; align-items: center; }
170
+ .modal input[type="text"], .modal input[type="password"], .modal textarea, .modal select { width: 100%; padding: 0.5rem 0.6rem; border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); background: var(--gl-bg); }
171
+ .modal textarea { min-height: 12rem; font-family: var(--gl-font-mono); font-size: 0.85rem; }
172
+ .login { display: grid; gap: 0.6rem; }
173
+ .login label { display: grid; gap: 0.25rem; font-size: 0.9rem; }
174
+ .login p { margin: 0; }
175
+ .check { display: flex; gap: 0.4rem; align-items: center; font-size: 0.88rem; margin-bottom: 0.5rem; }
176
+ .models { list-style: none; margin: 0; padding: 0; max-height: 16rem; overflow-y: auto; border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); }
177
+ .models li + li { border-top: 1px solid var(--gl-border); }
178
+ .models button { width: 100%; text-align: left; border-radius: 0; font-family: var(--gl-font-mono); font-size: 0.85rem; padding: 0.45rem 0.7rem; }
179
+ .models button:hover { background: var(--gl-bg); }
180
+ .models .current { font-weight: 700; color: var(--mode); }
181
+ .models .empty-models { padding: 0.6rem 0.7rem; color: var(--gl-text-muted); font-size: 0.9rem; }
182
+
183
+ .side .phone-only { display: none; }
184
+ .settings { display: grid; gap: 0.6rem; }
185
+ .settings label { display: grid; gap: 0.25rem; font-size: 0.85rem; color: var(--gl-text-muted); }
186
+ .settings select { border: 1px solid var(--gl-border); border-radius: var(--gl-radius-md); background: var(--gl-surface-raised); padding: 0.4rem 0.5rem; color: var(--gl-text); }
187
+ .settings .model-btn { text-align: left; color: var(--gl-text); }
188
+
189
+ /* ---- phone */
190
+ @media (max-width: 52rem) {
191
+ .app { grid-template-columns: minmax(0, 1fr); }
192
+ .menu-btn { display: inline-block; border: 1px solid var(--gl-border); }
193
+ .side { position: fixed; z-index: 20; top: 0; bottom: 0; left: 0; width: min(20rem, 85vw); transform: translateX(-100%); transition: transform 0.2s ease; box-shadow: 0 0 40px -10px rgba(0,0,0,0.5); }
194
+ .side.open { transform: none; }
195
+ .status { margin-left: 0; width: 100%; }
196
+ .status .profile, .status .model-btn { display: none; }
197
+ .side .phone-only { display: grid; }
198
+ .top { gap: 0.5rem 0.75rem; }
199
+ .log { padding: 1rem 0.75rem 1.5rem; }
200
+ .composer { padding: 0.6rem 0.75rem 0.75rem; }
201
+ .composer-buttons { flex-direction: column; }
202
+ }
203
+ @media (prefers-reduced-motion: reduce) { .side { transition: none; } }