@nanocollective/roster 0.1.0-alpha.5 → 0.1.0-alpha.6
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/docs/images/brain.jpg +0 -0
- package/docs/images/org.jpg +0 -0
- package/docs/images/prompt.jpg +0 -0
- package/docs/images/setup-org.jpg +0 -0
- package/docs/images/setup-plan.jpg +0 -0
- package/docs/images/staff.jpg +0 -0
- package/package.json +1 -1
- package/templates/portal/css/base.css +133 -73
- package/templates/portal/css/brain.css +23 -20
- package/templates/portal/css/diff.css +10 -9
- package/templates/portal/css/graph.css +12 -7
- package/templates/portal/css/health.css +12 -10
- package/templates/portal/css/inbox.css +24 -21
- package/templates/portal/css/layout.css +64 -46
- package/templates/portal/css/markdown.css +17 -14
- package/templates/portal/css/setup.css +38 -32
- package/templates/portal/index.html +1 -1
- package/templates/portal/js/views/graph.js +1 -1
package/docs/images/brain.jpg
CHANGED
|
Binary file
|
package/docs/images/org.jpg
CHANGED
|
Binary file
|
package/docs/images/prompt.jpg
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/docs/images/staff.jpg
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,30 +1,64 @@
|
|
|
1
1
|
/* Tokens, reset, and the primitives every screen uses: buttons, inputs, chips, meta text. */
|
|
2
2
|
|
|
3
3
|
:root{
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
--
|
|
9
|
-
--
|
|
10
|
-
--
|
|
4
|
+
/* iOS system colours, shared with the website, so the portal and the page that introduces
|
|
5
|
+
it are one product. The older names below are aliases, kept so every screen's stylesheet
|
|
6
|
+
reads the same tokens it always has. `--accent` is for text and lines; `--accent-fill`
|
|
7
|
+
is for solid fills, which on a light background want the brighter green. */
|
|
8
|
+
--bg:#000000; --bg-elev:#1c1c1e; --surface:#1c1c1e; --surface-2:#2c2c2e;
|
|
9
|
+
--border:rgba(255,255,255,.10); --border-strong:rgba(255,255,255,.16);
|
|
10
|
+
--text:#f5f5f7; --text-muted:#98989d; --text-faint:#636366;
|
|
11
|
+
--accent:#30d158; --accent-fill:#30d158; --accent-strong:#30d158;
|
|
12
|
+
--accent-soft:rgba(48,209,88,.15); --accent-ink:#000000; --accent-dim:rgba(48,209,88,.45);
|
|
13
|
+
--blue:#0a84ff; --amber:#ff9f0a; --red:#ff453a; --violet:#bf5af2;
|
|
14
|
+
--side:#161618; --sel:rgba(255,255,255,.10);
|
|
15
|
+
--hover:rgba(255,255,255,.05); --active:rgba(255,255,255,.10);
|
|
16
|
+
--shadow-sm:none; --shadow:none;
|
|
17
|
+
--shadow-lg:0 20px 48px rgba(0,0,0,.6);
|
|
18
|
+
--ease:cubic-bezier(.2,.8,.2,1);
|
|
19
|
+
--r-sm:6px; --r:10px; --r-lg:14px;
|
|
20
|
+
--scroll:rgba(255,255,255,.18); --scroll-hover:rgba(255,255,255,.3);
|
|
21
|
+
--mono:"SF Mono",ui-monospace,"JetBrains Mono",Menlo,monospace;
|
|
22
|
+
--sans:-apple-system,BlinkMacSystemFont,"SF Pro Text","Inter","Segoe UI",system-ui,sans-serif;
|
|
23
|
+
|
|
24
|
+
--panel:var(--surface); --panel-2:var(--surface-2); --line:var(--border);
|
|
25
|
+
--ink:var(--text); --ink-dim:var(--text-muted); --ink-faint:var(--text-faint);
|
|
26
|
+
--warn:var(--amber); --err:var(--red);
|
|
27
|
+
--ruled:var(--blue); --measured:var(--accent); --derived:var(--violet);
|
|
28
|
+
color-scheme:dark;
|
|
11
29
|
}
|
|
12
30
|
/* System preference wins unless the toggle has stamped data-theme on the root. */
|
|
13
31
|
@media (prefers-color-scheme:light){
|
|
14
32
|
:root:not([data-theme="dark"]){
|
|
15
|
-
--bg:#
|
|
16
|
-
--
|
|
17
|
-
--
|
|
18
|
-
--
|
|
19
|
-
--
|
|
33
|
+
--bg:#f5f5f7; --bg-elev:#ffffff; --surface:#ffffff; --surface-2:#f2f2f7;
|
|
34
|
+
--border:rgba(0,0,0,.08); --border-strong:rgba(0,0,0,.14);
|
|
35
|
+
--text:#1d1d1f; --text-muted:#6e6e73; --text-faint:#aeaeb2;
|
|
36
|
+
--accent:#248a3d; --accent-fill:#34c759; --accent-strong:#248a3d;
|
|
37
|
+
--accent-soft:rgba(52,199,89,.12); --accent-ink:#ffffff; --accent-dim:rgba(52,199,89,.45);
|
|
38
|
+
--blue:#007aff; --amber:#c77700; --red:#ff3b30; --violet:#af52de;
|
|
39
|
+
--side:#ebebf0; --sel:rgba(0,0,0,.07);
|
|
40
|
+
--hover:rgba(0,0,0,.04); --active:rgba(0,0,0,.07);
|
|
41
|
+
--shadow-sm:0 1px 2px rgba(0,0,0,.04),0 4px 16px rgba(0,0,0,.04);
|
|
42
|
+
--shadow:0 1px 2px rgba(0,0,0,.04),0 4px 16px rgba(0,0,0,.05);
|
|
43
|
+
--shadow-lg:0 4px 12px rgba(0,0,0,.06),0 20px 48px rgba(0,0,0,.12);
|
|
44
|
+
--scroll:rgba(0,0,0,.18); --scroll-hover:rgba(0,0,0,.3);
|
|
45
|
+
color-scheme:light;
|
|
20
46
|
}
|
|
21
47
|
}
|
|
22
48
|
:root[data-theme="light"]{
|
|
23
|
-
--bg:#
|
|
24
|
-
--
|
|
25
|
-
--
|
|
26
|
-
--
|
|
27
|
-
--
|
|
49
|
+
--bg:#f5f5f7; --bg-elev:#ffffff; --surface:#ffffff; --surface-2:#f2f2f7;
|
|
50
|
+
--border:rgba(0,0,0,.08); --border-strong:rgba(0,0,0,.14);
|
|
51
|
+
--text:#1d1d1f; --text-muted:#6e6e73; --text-faint:#aeaeb2;
|
|
52
|
+
--accent:#248a3d; --accent-fill:#34c759; --accent-strong:#248a3d;
|
|
53
|
+
--accent-soft:rgba(52,199,89,.12); --accent-ink:#ffffff; --accent-dim:rgba(52,199,89,.45);
|
|
54
|
+
--blue:#007aff; --amber:#c77700; --red:#ff3b30; --violet:#af52de;
|
|
55
|
+
--side:#ebebf0; --sel:rgba(0,0,0,.07);
|
|
56
|
+
--hover:rgba(0,0,0,.04); --active:rgba(0,0,0,.07);
|
|
57
|
+
--shadow-sm:0 1px 2px rgba(0,0,0,.04),0 4px 16px rgba(0,0,0,.04);
|
|
58
|
+
--shadow:0 1px 2px rgba(0,0,0,.04),0 4px 16px rgba(0,0,0,.05);
|
|
59
|
+
--shadow-lg:0 4px 12px rgba(0,0,0,.06),0 20px 48px rgba(0,0,0,.12);
|
|
60
|
+
--scroll:rgba(0,0,0,.18); --scroll-hover:rgba(0,0,0,.3);
|
|
61
|
+
color-scheme:light;
|
|
28
62
|
}
|
|
29
63
|
|
|
30
64
|
*{box-sizing:border-box}
|
|
@@ -34,47 +68,75 @@
|
|
|
34
68
|
just stayed on screen. Said once, here. */
|
|
35
69
|
[hidden]{display:none!important}
|
|
36
70
|
|
|
71
|
+
html{background:var(--bg)}
|
|
37
72
|
body{margin:0;background:var(--bg);color:var(--ink);font:14px/1.55 var(--sans);
|
|
38
|
-
-webkit-font-smoothing:antialiased
|
|
73
|
+
font-feature-settings:"cv11","ss01","ss03";-webkit-font-smoothing:antialiased;
|
|
74
|
+
-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}
|
|
39
75
|
a{color:inherit}
|
|
76
|
+
::selection{background:color-mix(in srgb,var(--accent) 28%,transparent)}
|
|
77
|
+
:focus-visible{outline:none}
|
|
78
|
+
|
|
79
|
+
/* Scrollbars that belong to the page rather than to the operating system of 2009. */
|
|
80
|
+
*{scrollbar-width:thin;scrollbar-color:var(--scroll) transparent}
|
|
81
|
+
::-webkit-scrollbar{width:10px;height:10px}
|
|
82
|
+
::-webkit-scrollbar-track{background:transparent}
|
|
83
|
+
::-webkit-scrollbar-thumb{background:var(--scroll);border-radius:10px;
|
|
84
|
+
border:3px solid transparent;background-clip:padding-box}
|
|
85
|
+
::-webkit-scrollbar-thumb:hover{background:var(--scroll-hover);background-clip:padding-box;
|
|
86
|
+
border:3px solid transparent}
|
|
87
|
+
::-webkit-scrollbar-corner{background:transparent}
|
|
40
88
|
|
|
41
|
-
h1{font:600
|
|
42
|
-
.sub{color:var(--ink-dim);margin:0 0
|
|
89
|
+
h1{font:600 22px/1.25 var(--sans);margin:0 0 6px;letter-spacing:-.022em;color:var(--ink)}
|
|
90
|
+
.sub{color:var(--ink-dim);margin:0 0 26px;font-size:13.5px}
|
|
43
91
|
.row{display:flex;gap:10px;flex-wrap:wrap;align-items:center}
|
|
44
|
-
.meta{color:var(--ink-faint);font:11.5px var(--mono)}
|
|
45
|
-
.empty{color:var(--ink-faint);padding:
|
|
92
|
+
.meta{color:var(--ink-faint);font:11.5px var(--mono);font-variant-numeric:tabular-nums}
|
|
93
|
+
.empty{color:var(--ink-faint);padding:32px 0;text-align:center;font-size:13px}
|
|
46
94
|
.err{color:var(--err)} .warn{color:var(--warn)} .ok{color:var(--accent)}
|
|
47
95
|
|
|
48
|
-
.card{background:var(--panel);border:1px solid var(--line);border-radius:
|
|
49
|
-
|
|
50
|
-
|
|
96
|
+
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);
|
|
97
|
+
padding:16px 18px;margin-bottom:12px;box-shadow:var(--shadow-sm);
|
|
98
|
+
transition:border-color .15s var(--ease),box-shadow .15s var(--ease)}
|
|
99
|
+
.card h3{margin:0 0 4px;font:600 14px var(--sans);letter-spacing:-.01em}
|
|
100
|
+
.grid{display:grid;gap:12px;grid-template-columns:repeat(auto-fill,minmax(250px,1fr))}
|
|
51
101
|
|
|
52
102
|
/* ---------- controls ---------- */
|
|
53
|
-
input[type=search],input[type=time],select{background:var(--
|
|
54
|
-
border:1px solid var(--
|
|
55
|
-
border-radius:
|
|
103
|
+
input[type=search],input[type=time],input[type=text],select{background:var(--bg-elev);
|
|
104
|
+
border:1px solid var(--border-strong);color:var(--ink);
|
|
105
|
+
border-radius:var(--r);padding:7px 11px;font:13px var(--sans);outline:none;
|
|
106
|
+
transition:border-color .15s var(--ease),box-shadow .15s var(--ease)}
|
|
56
107
|
input[type=search]{width:280px}
|
|
57
|
-
input
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
108
|
+
input::placeholder,textarea::placeholder{color:var(--ink-faint)}
|
|
109
|
+
input[type=search]:hover,input[type=time]:hover,input[type=text]:hover,select:hover,
|
|
110
|
+
textarea:hover{border-color:color-mix(in srgb,var(--ink) 20%,transparent)}
|
|
111
|
+
input[type=search]:focus,input[type=time]:focus,input[type=text]:focus,select:focus{
|
|
112
|
+
border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
|
|
113
|
+
textarea{width:100%;background:var(--bg-elev);border:1px solid var(--border-strong);color:var(--ink);
|
|
114
|
+
border-radius:var(--r);padding:10px 12px;font:13px/1.6 var(--sans);outline:none;resize:vertical;
|
|
115
|
+
transition:border-color .15s var(--ease),box-shadow .15s var(--ease)}
|
|
116
|
+
textarea:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
|
|
61
117
|
|
|
62
118
|
/* One size, whether it is a button or a link. They sit in rows together, and `a` taking its
|
|
63
119
|
line-height from the font shorthand while `button` set its own made every such row a set of
|
|
64
120
|
controls at two different heights. */
|
|
65
|
-
.ghbtn{display:inline-flex;align-items:center;justify-content:center;min-height:
|
|
66
|
-
padding:5px
|
|
67
|
-
|
|
68
|
-
.
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
.ghbtn
|
|
73
|
-
|
|
74
|
-
.ghbtn
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.
|
|
121
|
+
.ghbtn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:30px;
|
|
122
|
+
padding:5px 12px;border:1px solid transparent;border-radius:8px;
|
|
123
|
+
background:var(--surface-2);
|
|
124
|
+
font:500 12.5px/1.4 var(--sans);color:var(--ink);text-decoration:none;white-space:nowrap;
|
|
125
|
+
transition:background .15s var(--ease),color .15s var(--ease),opacity .15s var(--ease)}
|
|
126
|
+
.ghbtn:hover{color:var(--ink);background:color-mix(in srgb,var(--surface-2) 88%,var(--ink) 12%)}
|
|
127
|
+
.ghbtn:active{opacity:.8}
|
|
128
|
+
.ghbtn:focus-visible,.btn:focus-visible,.iconbtn:focus-visible{
|
|
129
|
+
border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
|
|
130
|
+
button.ghbtn{cursor:pointer;font-family:var(--sans);
|
|
131
|
+
-webkit-appearance:none;appearance:none;font-size:12.5px;line-height:1.4}
|
|
132
|
+
button.ghbtn:hover{background:color-mix(in srgb,var(--surface-2) 88%,var(--ink) 12%)}
|
|
133
|
+
.ghbtn.primary{background:var(--accent);border-color:transparent;color:var(--accent-ink);font-weight:600}
|
|
134
|
+
.ghbtn.primary:hover{background:var(--accent);color:var(--accent-ink);opacity:.88}
|
|
135
|
+
.ghbtn:disabled{opacity:.45;cursor:default}
|
|
136
|
+
.iconbtn{background:var(--surface-2);border:1px solid transparent;color:var(--ink-dim);
|
|
137
|
+
border-radius:8px;width:34px;height:34px;cursor:pointer;font-size:15px;line-height:1;
|
|
138
|
+
transition:background .15s var(--ease),color .15s var(--ease)}
|
|
139
|
+
.iconbtn:hover{color:var(--ink);background:color-mix(in srgb,var(--surface-2) 88%,var(--ink) 12%)}
|
|
78
140
|
.iconbtn{display:inline-flex;align-items:center;justify-content:center}
|
|
79
141
|
.iconbtn .sync{display:inline-flex;--ic:15px}
|
|
80
142
|
.iconbtn.spin .sync{animation:spin .9s linear infinite}
|
|
@@ -87,15 +149,17 @@ svg.ic{width:var(--ic,15px);height:var(--ic,15px);display:block;flex:none}
|
|
|
87
149
|
/* A slot that holds one, centred, wherever a text glyph used to sit on a baseline. */
|
|
88
150
|
.icslot{display:inline-flex;align-items:center;justify-content:center;flex:none}
|
|
89
151
|
|
|
90
|
-
.chip{font:
|
|
91
|
-
border:1px solid
|
|
92
|
-
|
|
93
|
-
.chip.
|
|
94
|
-
.chip.
|
|
95
|
-
.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
152
|
+
.chip{display:inline-flex;align-items:center;font:500 10.5px/1.5 var(--sans);letter-spacing:.01em;
|
|
153
|
+
padding:1px 8px;border-radius:999px;border:1px solid transparent;color:var(--ink-dim);
|
|
154
|
+
background:color-mix(in srgb,var(--ink) 7%,transparent);white-space:nowrap}
|
|
155
|
+
.chip.hot{color:var(--err);background:color-mix(in srgb,var(--err) 12%,transparent)}
|
|
156
|
+
.chip.warm{color:var(--warn);background:color-mix(in srgb,var(--warn) 13%,transparent)}
|
|
157
|
+
.chip.cool{color:var(--ruled);background:color-mix(in srgb,var(--ruled) 12%,transparent)}
|
|
158
|
+
.pill{font:11px var(--mono);color:var(--ink-dim);border:1px solid transparent;
|
|
159
|
+
background:color-mix(in srgb,var(--ink) 4%,transparent);
|
|
160
|
+
border-radius:999px;padding:2px 9px;font-variant-numeric:tabular-nums}
|
|
161
|
+
kbd{font:500 10.5px var(--mono);border:1px solid var(--border-strong);
|
|
162
|
+
border-radius:5px;padding:1px 5px;color:var(--ink-dim);background:var(--surface-2)}
|
|
99
163
|
|
|
100
164
|
/* ---------- waiting ----------
|
|
101
165
|
The inbox reads every repo in the org, which is seconds on a cold cache. What used to stand
|
|
@@ -103,15 +167,11 @@ kbd{font:11px var(--mono);border:1px solid var(--line);border-bottom-width:2px;b
|
|
|
103
167
|
which reads as a page that has failed rather than one that is working. These are the shape
|
|
104
168
|
of what is coming: rows in the list, a title and paragraphs in the viewer. */
|
|
105
169
|
.sk{--skbg:color-mix(in srgb,var(--ink) 7%,transparent);border-radius:6px;
|
|
106
|
-
background:
|
|
107
|
-
color-mix(in srgb,var(--ink) 12%,transparent) 37%,var(--skbg) 63%);
|
|
108
|
-
background-size:400% 100%;animation:shimmer 1.4s ease-in-out infinite}
|
|
170
|
+
background:var(--skbg);animation:pulse 1.4s ease-in-out infinite}
|
|
109
171
|
.sk-row{background:none;animation:none;padding:11px 10px;border-top:1px solid var(--line)}
|
|
110
172
|
.sk-row:first-of-type{border-top:0}
|
|
111
|
-
.sk-row .skbar{height:11px;border-radius:6px;
|
|
112
|
-
background:
|
|
113
|
-
color-mix(in srgb,var(--ink) 12%,transparent) 37%,var(--skbg) 63%);
|
|
114
|
-
background-size:400% 100%;animation:shimmer 1.4s ease-in-out infinite}
|
|
173
|
+
.sk-row .skbar{height:11px;border-radius:6px;
|
|
174
|
+
background:var(--skbg);animation:pulse 1.4s ease-in-out infinite}
|
|
115
175
|
.sk-row .skbar.t{width:84%}
|
|
116
176
|
.sk-row .skbar.m{width:38%;height:8px;margin-top:8px}
|
|
117
177
|
/* Staggered, so the list reads as several things loading rather than one block flashing. */
|
|
@@ -125,7 +185,6 @@ kbd{font:11px var(--mono);border:1px solid var(--line);border-bottom-width:2px;b
|
|
|
125
185
|
.sk-line:last-child{width:42%}
|
|
126
186
|
/* The word beside them. It is the only part a screen reader gets, so it stays real text. */
|
|
127
187
|
.skhead{color:var(--ink-faint);font-size:12.5px;padding:4px 10px 8px}
|
|
128
|
-
@keyframes shimmer{0%{background-position:100% 0}100%{background-position:0 0}}
|
|
129
188
|
/* A count that is still being fetched is not zero, and an empty badge reads as zero. */
|
|
130
189
|
.nav .n.wait{display:inline-block;width:15px;height:8px;border-radius:5px;
|
|
131
190
|
background:color-mix(in srgb,var(--ink) 10%,transparent);animation:pulse 1.3s ease-in-out infinite}
|
|
@@ -134,23 +193,24 @@ kbd{font:11px var(--mono);border:1px solid var(--line);border-bottom-width:2px;b
|
|
|
134
193
|
.sk,.sk-row .skbar,.nav .n.wait{animation:none}
|
|
135
194
|
}
|
|
136
195
|
|
|
137
|
-
.notice{background:color-mix(in srgb,var(--warn)
|
|
138
|
-
|
|
139
|
-
padding:10px 13px;margin-bottom:16px;font-size:12.5px;line-height:1.6}
|
|
196
|
+
.notice{background:color-mix(in srgb,var(--warn) 10%,transparent);border:1px solid transparent;color:var(--ink-dim);border-radius:var(--r);
|
|
197
|
+
padding:11px 14px;margin-bottom:16px;font-size:12.5px;line-height:1.6}
|
|
140
198
|
.notice b{color:var(--ink)}
|
|
141
199
|
|
|
142
200
|
/* ---------- a dialog that asks for more than a line ----------
|
|
143
201
|
Native <dialog>, so the backdrop, the focus trap and Escape are the browser's job. */
|
|
144
|
-
dialog.ask{border:1px solid var(--
|
|
145
|
-
color:var(--ink);padding:
|
|
146
|
-
box-shadow:
|
|
147
|
-
dialog.ask
|
|
148
|
-
|
|
149
|
-
dialog.ask
|
|
202
|
+
dialog.ask{border:1px solid var(--border-strong);border-radius:var(--r-lg);background:var(--bg-elev);
|
|
203
|
+
color:var(--ink);padding:22px 24px;width:min(560px,92vw);
|
|
204
|
+
box-shadow:var(--shadow-lg)}
|
|
205
|
+
dialog.ask[open]{animation:dlgin .18s var(--ease)}
|
|
206
|
+
@keyframes dlgin{from{opacity:0;transform:translateY(6px) scale(.985)}}
|
|
207
|
+
dialog.ask::backdrop{background:rgba(0,0,0,.35);backdrop-filter:blur(8px)}
|
|
208
|
+
dialog.ask h3{margin:0;font:600 16px var(--sans);letter-spacing:-.018em}
|
|
209
|
+
dialog.ask .askhint{margin:6px 0 14px;font:12.5px/1.55 var(--sans);color:var(--ink-dim)}
|
|
150
210
|
dialog.ask textarea{font:13.5px/1.6 var(--sans);min-height:96px;max-height:44vh}
|
|
151
211
|
/* The attach control, when the dialog is a reply rather than a question. */
|
|
152
212
|
dialog.ask .attach{margin-top:9px}
|
|
153
|
-
dialog.ask .askrow{margin-top:
|
|
213
|
+
dialog.ask .askrow{margin-top:14px;justify-content:flex-end}
|
|
154
214
|
dialog.ask .askrow .meta{margin-right:auto}
|
|
155
215
|
|
|
156
216
|
/* The lightbox: an image, over the page, that zooms.
|
|
@@ -159,7 +219,7 @@ dialog.ask .askrow .meta{margin-right:auto}
|
|
|
159
219
|
* from ::backdrop. 60 puts it over the `@` mention list (30) and over the dialog, which is
|
|
160
220
|
* correct: a picture opened from inside a reply box should still open. */
|
|
161
221
|
.lightbox{position:fixed;inset:0;z-index:60;display:flex;
|
|
162
|
-
background:rgba(0,0,0,.82)
|
|
222
|
+
background:rgba(0,0,0,.82)}
|
|
163
223
|
/* The stage is inset rather than the whole window, and that is not decoration.
|
|
164
224
|
Most images here are screenshots *of this interface*, and one fitted edge to edge reads as
|
|
165
225
|
the app having navigated rather than as a picture of it. The margin of backdrop around it,
|
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
/* ---------- navigator ----------
|
|
4
4
|
Memory and Files are two kinds of thing, so they are two boxes rather than one flat list
|
|
5
5
|
where a parsed section and a markdown file are told apart only by their typeface. */
|
|
6
|
-
.navgroup{border:
|
|
6
|
+
.navgroup{border:0;border-radius:var(--r);margin-bottom:6px;padding:2px 2px 4px}
|
|
7
|
+
.navgroup + .navgroup{border-top:1px solid var(--line);border-radius:0;padding-top:6px}
|
|
7
8
|
.navgroup:last-child{margin-bottom:0}
|
|
8
9
|
.ghead{display:flex;align-items:baseline;gap:8px;padding:6px 8px 6px;
|
|
9
|
-
font:600
|
|
10
|
+
font:600 11px var(--sans);letter-spacing:.08em;text-transform:uppercase;color:var(--ink-faint)}
|
|
10
11
|
.ghead i{font-style:normal;font:10.5px var(--mono);letter-spacing:0;text-transform:none;
|
|
11
12
|
margin-left:auto;color:var(--ink-faint)}
|
|
12
13
|
|
|
@@ -20,12 +21,12 @@
|
|
|
20
21
|
/* The section a focused fact belongs to stays lit, so opening one fact never loses your
|
|
21
22
|
place in the list. */
|
|
22
23
|
.tfile[data-within="true"] span.t{color:var(--ink)}
|
|
23
|
-
.tfile[data-within="true"]{background:
|
|
24
|
+
.tfile[data-within="true"]{background:var(--hover)}
|
|
24
25
|
|
|
25
26
|
.tsurface{display:flex;align-items:center;gap:7px;width:100%;text-align:left;background:none;
|
|
26
|
-
border:0;color:var(--ink-dim);font:11.5px var(--mono);padding:5px 8px;border-radius:
|
|
27
|
-
cursor:pointer}
|
|
28
|
-
.tsurface:hover{background:var(--
|
|
27
|
+
border:0;color:var(--ink-dim);font:11.5px var(--mono);padding:5px 8px;border-radius:6px;
|
|
28
|
+
cursor:pointer;transition:background .12s var(--ease),color .12s var(--ease)}
|
|
29
|
+
.tsurface:hover{background:var(--hover);color:var(--ink)}
|
|
29
30
|
.tsurface .caret{color:var(--ink-faint);--ic:12px;flex:none;transition:transform .12s ease}
|
|
30
31
|
.tsurface[aria-expanded="false"] .caret{transform:rotate(-90deg)}
|
|
31
32
|
.tsurface .t{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
@@ -35,21 +36,22 @@
|
|
|
35
36
|
.tsfiles .tfile{font-size:12px}
|
|
36
37
|
|
|
37
38
|
/* ---------- memory cards ---------- */
|
|
38
|
-
.fact{border-bottom:1px solid var(--line);padding:
|
|
39
|
+
.fact{border-bottom:1px solid var(--line);padding:15px 2px;scroll-margin-top:12px}
|
|
39
40
|
.fact:last-child{border-bottom:0}
|
|
40
|
-
.fact.lit{background:color-mix(in srgb,var(--warn)
|
|
41
|
-
|
|
42
|
-
.slug{font:12px var(--mono);color:var(--accent);cursor:pointer}
|
|
41
|
+
.fact.lit{background:color-mix(in srgb,var(--warn) 9%,transparent);
|
|
42
|
+
border-radius:8px;padding-left:12px}
|
|
43
|
+
.slug{font:500 12px var(--mono);color:var(--accent);cursor:pointer}
|
|
43
44
|
.slug:hover{text-decoration:underline}
|
|
44
|
-
.stmt{margin:
|
|
45
|
+
.stmt{margin:4px 0 0;font-size:14px;color:var(--ink);letter-spacing:-.003em}
|
|
45
46
|
.so{margin:4px 0 0;color:var(--ink-dim);font-size:13.2px}
|
|
46
47
|
.so b{color:var(--ink);font-weight:600}
|
|
47
48
|
.factsub{color:var(--ink-faint);font-size:12.5px;margin:0 0 14px}
|
|
48
|
-
.tag{display:inline-block;font:
|
|
49
|
-
border:
|
|
50
|
-
|
|
51
|
-
.tag.
|
|
52
|
-
.tag.
|
|
49
|
+
.tag{display:inline-block;font:500 10px/1.6 var(--sans);padding:0 7px;border-radius:999px;
|
|
50
|
+
border:0;color:var(--ink-dim);margin-left:6px;vertical-align:1px;
|
|
51
|
+
background:color-mix(in srgb,var(--ink) 7%,transparent)}
|
|
52
|
+
.tag.ruled{color:var(--ruled);background:color-mix(in srgb,var(--ruled) 12%,transparent)}
|
|
53
|
+
.tag.measured{color:var(--measured);background:color-mix(in srgb,var(--accent-fill) 14%,transparent)}
|
|
54
|
+
.tag.derived{color:var(--derived);background:color-mix(in srgb,var(--derived) 12%,transparent)}
|
|
53
55
|
.notelink{font:11.5px var(--mono);color:var(--ink-faint);cursor:pointer;margin-left:6px}
|
|
54
56
|
.notelink:hover{color:var(--accent)}
|
|
55
57
|
|
|
@@ -57,8 +59,8 @@
|
|
|
57
59
|
a way out, that read as the page breaking. */
|
|
58
60
|
.focusbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 12px;
|
|
59
61
|
background:color-mix(in srgb,var(--warn) 10%,transparent);
|
|
60
|
-
border:1px solid
|
|
61
|
-
border-radius:
|
|
62
|
+
border:1px solid transparent;
|
|
63
|
+
border-radius:var(--r);padding:7px 8px 7px 11px;font:12px var(--sans);color:var(--ink-dim)}
|
|
62
64
|
.focusbar .crumb{background:none;border:0;color:var(--ink-dim);cursor:pointer;
|
|
63
65
|
font:12px var(--sans);padding:0;text-align:left}
|
|
64
66
|
.focusbar .crumb:hover{color:var(--ink);text-decoration:underline}
|
|
@@ -98,7 +100,8 @@
|
|
|
98
100
|
|
|
99
101
|
/* A prompt audit finding. Not a tree row: it carries an explanation and two buttons, and
|
|
100
102
|
squeezing that into the navigator's row shape is how it would get ignored. */
|
|
101
|
-
.prob{border:1px solid var(--line);border-radius:
|
|
103
|
+
.prob{border:1px solid var(--line);border-radius:var(--r);padding:10px 11px;margin:0 3px 6px;
|
|
104
|
+
background:var(--bg-elev)}
|
|
102
105
|
.prob .ptitle{font:600 12.5px var(--sans);color:var(--ink)}
|
|
103
106
|
.prob .pdetail{margin-top:3px;font:11.5px/1.5 var(--sans);color:var(--ink-faint)}
|
|
104
107
|
.prob.error{border-color:color-mix(in srgb,var(--err) 45%,transparent)}
|
|
@@ -110,4 +113,4 @@
|
|
|
110
113
|
/* What an edit did to the composed prompt, which is the question you were actually asking. */
|
|
111
114
|
.effect{border:1px solid color-mix(in srgb,var(--accent) 35%,transparent);
|
|
112
115
|
background:color-mix(in srgb,var(--accent) 7%,transparent);
|
|
113
|
-
border-radius:
|
|
116
|
+
border-radius:var(--r);padding:11px 13px;margin-bottom:14px}
|
|
@@ -1,24 +1,25 @@
|
|
|
1
1
|
/* A unified diff, on the "what changed" screen. */
|
|
2
2
|
|
|
3
|
-
.dblock{border:1px solid var(--line);border-radius:
|
|
3
|
+
.dblock{border:1px solid var(--line);border-radius:var(--r);overflow:hidden;margin-bottom:14px;
|
|
4
|
+
box-shadow:var(--shadow-sm)}
|
|
4
5
|
.dblock:last-child{margin-bottom:0}
|
|
5
|
-
.diff{margin:0;font:12px/1.
|
|
6
|
+
.diff{margin:0;font:12px/1.65 var(--mono);background:var(--bg);overflow-x:auto}
|
|
6
7
|
.dline{display:grid;grid-template-columns:42px 42px 1fr;white-space:pre;min-width:max-content}
|
|
7
8
|
.dline .ln{color:var(--ink-faint);text-align:right;padding:0 7px 0 5px;font-size:11px;
|
|
8
|
-
user-select:none;background:color-mix(in srgb,var(--
|
|
9
|
+
user-select:none;background:color-mix(in srgb,var(--ink) 3%,transparent)}
|
|
9
10
|
.dline .tx{padding:0 14px 0 9px}
|
|
10
|
-
.dadd{background:color-mix(in srgb,var(--accent)
|
|
11
|
+
.dadd{background:color-mix(in srgb,var(--accent) 11%,transparent)}
|
|
11
12
|
.dadd .tx{color:var(--ink)}
|
|
12
|
-
.dadd .ln{background:color-mix(in srgb,var(--accent)
|
|
13
|
-
.ddel{background:color-mix(in srgb,var(--err)
|
|
13
|
+
.dadd .ln{background:color-mix(in srgb,var(--accent) 17%,transparent);color:var(--accent)}
|
|
14
|
+
.ddel{background:color-mix(in srgb,var(--err) 10%,transparent)}
|
|
14
15
|
.ddel .tx{color:var(--ink-dim)}
|
|
15
|
-
.ddel .ln{background:color-mix(in srgb,var(--err)
|
|
16
|
-
.dhunk{background:color-mix(in srgb,var(--ruled)
|
|
16
|
+
.ddel .ln{background:color-mix(in srgb,var(--err) 16%,transparent);color:var(--err)}
|
|
17
|
+
.dhunk{background:color-mix(in srgb,var(--ruled) 8%,transparent);
|
|
17
18
|
border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
|
|
18
19
|
.dhunk .tx{color:var(--ruled);font-size:11.5px}
|
|
19
20
|
.dmeta .tx{color:var(--ink-faint);font-size:11.5px}
|
|
20
21
|
.dfocus{box-shadow:inset 3px 0 0 var(--warn)}
|
|
21
|
-
.dfile{font:11.5px var(--mono);color:var(--ink-dim);background:var(--panel);padding:
|
|
22
|
+
.dfile{font:11.5px var(--mono);color:var(--ink-dim);background:var(--panel);padding:9px 13px;
|
|
22
23
|
border-bottom:1px solid var(--line);display:flex;gap:10px;align-items:baseline}
|
|
23
24
|
.dfile b{color:var(--ink);font-weight:600}
|
|
24
25
|
.dfile .p{color:var(--accent)} .dfile .m{color:var(--err)}
|
|
@@ -1,26 +1,31 @@
|
|
|
1
1
|
/* The link graph: canvas, its controls, and the sheet a selected fact opens. */
|
|
2
2
|
|
|
3
|
-
.graphwrap{position:relative;
|
|
3
|
+
.graphwrap{position:relative;border:1px solid var(--line);border-radius:var(--r-lg);overflow:hidden;
|
|
4
|
+
background:var(--panel);
|
|
5
|
+
box-shadow:var(--shadow-sm)}
|
|
4
6
|
#graph{display:block;width:100%;height:72vh;cursor:grab;touch-action:none}
|
|
5
7
|
#graph.grabbing{cursor:grabbing}
|
|
6
8
|
#graph.onnode{cursor:pointer}
|
|
7
9
|
|
|
8
10
|
.legend{position:absolute;left:12px;bottom:12px;font:11px var(--mono);color:var(--ink-dim);
|
|
9
|
-
background:
|
|
11
|
+
background:var(--bg-elev);
|
|
12
|
+
padding:9px 12px;border-radius:var(--r);box-shadow:var(--shadow);
|
|
10
13
|
border:1px solid var(--line);max-height:44%;overflow:auto}
|
|
11
14
|
.legend div{white-space:nowrap;line-height:1.75;cursor:pointer;opacity:.55}
|
|
12
15
|
.legend div.on{opacity:1}
|
|
13
16
|
.legend i{display:inline-block;width:9px;height:9px;border-radius:50%;margin-right:7px}
|
|
14
17
|
|
|
15
18
|
.gtools{position:absolute;right:12px;top:12px;display:flex;gap:7px;align-items:center}
|
|
16
|
-
.gtools button{background:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
.gtools button{background:var(--surface-2);
|
|
20
|
+
border:1px solid transparent;
|
|
21
|
+
color:var(--ink-dim);border-radius:8px;padding:5px 10px;font:11.5px var(--mono);cursor:pointer}
|
|
22
|
+
.gtools button:hover{color:var(--ink);background:color-mix(in srgb,var(--surface-2) 88%,var(--ink) 12%)}
|
|
19
23
|
.gtools input[type=search]{width:170px;padding:5px 10px;font:11.5px var(--mono)}
|
|
20
24
|
|
|
21
25
|
.sheet{position:absolute;right:0;top:0;bottom:0;width:370px;max-width:100%;
|
|
22
|
-
background:var(--
|
|
23
|
-
overflow:auto;box-shadow
|
|
26
|
+
background:var(--bg-elev);border-left:1px solid var(--border-strong);padding:22px 24px;
|
|
27
|
+
overflow:auto;box-shadow:var(--shadow-lg);animation:sheetin .2s var(--ease)}
|
|
28
|
+
@keyframes sheetin{from{transform:translateX(12px);opacity:0}}
|
|
24
29
|
.sheet .x{position:absolute;right:12px;top:12px;background:none;border:0;color:var(--ink-faint);
|
|
25
30
|
cursor:pointer;display:inline-flex;padding:4px;border-radius:6px;--ic:16px}
|
|
26
31
|
.sheet .x:hover{color:var(--ink);background:var(--panel-2)}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
/* The health screen's fact strip and lint cards. */
|
|
2
2
|
|
|
3
|
-
.kv{background:var(--panel);border:1px solid var(--line);border-radius:
|
|
4
|
-
|
|
5
|
-
.kv .
|
|
3
|
+
.kv{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);padding:14px 16px;
|
|
4
|
+
box-shadow:var(--shadow-sm)}
|
|
5
|
+
.kv .k{font:600 10.5px var(--sans);letter-spacing:.08em;text-transform:uppercase;color:var(--ink-faint)}
|
|
6
|
+
.kv .v{margin-top:6px;font:500 15px var(--sans);color:var(--ink);line-height:1.4;letter-spacing:-.01em;
|
|
7
|
+
font-variant-numeric:tabular-nums}
|
|
6
8
|
.kv .v small{display:block;color:var(--ink-faint);font-size:11.5px;margin-top:2px}
|
|
7
|
-
.kv.bad{border-color:color-mix(in srgb,var(--err)
|
|
9
|
+
.kv.bad{border-color:color-mix(in srgb,var(--err) 35%,transparent)}
|
|
8
10
|
.kv.bad .v{color:var(--err)}
|
|
9
11
|
.card .fix{margin-top:10px}
|
|
10
12
|
.card .fixed{color:var(--accent);font:11.5px var(--mono)}
|
|
@@ -15,8 +17,8 @@
|
|
|
15
17
|
shape now. A heading carries its own count, so the page can be read by scanning the left
|
|
16
18
|
edge, and each section's own actions sit at its end rather than above its findings. */
|
|
17
19
|
.hsect{display:flex;align-items:baseline;gap:10px;
|
|
18
|
-
font:600
|
|
19
|
-
color:var(--ink-faint);margin:
|
|
20
|
+
font:600 11px var(--sans);letter-spacing:.08em;text-transform:uppercase;
|
|
21
|
+
color:var(--ink-faint);margin:32px 0 0;padding-bottom:9px;
|
|
20
22
|
border-bottom:1px solid var(--line)}
|
|
21
23
|
.hsect i{margin-left:auto;font:11.5px var(--mono);font-style:normal;letter-spacing:0;
|
|
22
24
|
text-transform:none;color:var(--ink-faint)}
|
|
@@ -35,10 +37,10 @@
|
|
|
35
37
|
|
|
36
38
|
/* A plan, before anything happens. The two halves are deliberately equal in weight: "this is
|
|
37
39
|
what it keeps" is what somebody needs to believe before retiring anybody. */
|
|
38
|
-
.plan{border:1px solid var(--line);border-radius:
|
|
39
|
-
background:var(--panel)}
|
|
40
|
-
.plan h3{margin:0 0 10px;font:600 15px var(--sans)}
|
|
41
|
-
.planhead{font:600
|
|
40
|
+
.plan{border:1px solid var(--line);border-radius:var(--r-lg);padding:16px 18px;margin-top:14px;
|
|
41
|
+
background:var(--panel);box-shadow:var(--shadow-sm)}
|
|
42
|
+
.plan h3{margin:0 0 10px;font:600 15px var(--sans);letter-spacing:-.015em}
|
|
43
|
+
.planhead{font:600 11px var(--sans);letter-spacing:.08em;text-transform:uppercase;
|
|
42
44
|
color:var(--ink-faint);margin:14px 0 7px}
|
|
43
45
|
.planhead:first-of-type{margin-top:0}
|
|
44
46
|
.planhead.keep{color:var(--accent)}
|
|
@@ -5,15 +5,16 @@
|
|
|
5
5
|
the inbox hard to scan. The line is dropped either side of the selected row, whose own
|
|
6
6
|
background is already doing the separating. */
|
|
7
7
|
.irow{display:block;width:100%;text-align:left;background:none;border:0;cursor:pointer;
|
|
8
|
-
padding:11px
|
|
9
|
-
border-top:1px solid transparent}
|
|
8
|
+
padding:11px 12px;border-radius:var(--r);color:var(--ink-dim);
|
|
9
|
+
border-top:1px solid transparent;transition:background .12s var(--ease)}
|
|
10
10
|
.irow + .irow{border-top-color:var(--line)}
|
|
11
11
|
.irow[aria-current="true"],.irow[aria-current="true"] + .irow{border-top-color:transparent}
|
|
12
|
-
.irow:hover{background:var(--
|
|
12
|
+
.irow:hover{background:var(--hover)}
|
|
13
|
+
.irow:hover + .irow,.irow:hover{border-top-color:transparent}
|
|
13
14
|
.irow:focus{outline:none}
|
|
14
|
-
.irow:focus-visible{
|
|
15
|
-
.irow[aria-current="true"]{background:var(--
|
|
16
|
-
.ititle{font:13.5px/1.4 var(--sans);color:var(--ink);display:-webkit-box;-webkit-line-clamp:2;
|
|
15
|
+
.irow:focus-visible{box-shadow:inset 0 0 0 1px var(--accent-dim)}
|
|
16
|
+
.irow[aria-current="true"]{background:var(--accent-soft)}
|
|
17
|
+
.ititle{font:500 13.5px/1.4 var(--sans);letter-spacing:-.005em;color:var(--ink);display:-webkit-box;-webkit-line-clamp:2;
|
|
17
18
|
-webkit-box-orient:vertical;overflow:hidden}
|
|
18
19
|
.irow[aria-current="true"] .ititle{color:var(--accent)}
|
|
19
20
|
/* The rest of the row follows the title. The project label kept the flat grey it has when
|
|
@@ -25,7 +26,7 @@
|
|
|
25
26
|
.dot{display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--warn);
|
|
26
27
|
margin-right:6px;vertical-align:2px}
|
|
27
28
|
.imeta{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin-top:5px}
|
|
28
|
-
.imeta .repo{font:10px var(--sans);letter-spacing:.
|
|
29
|
+
.imeta .repo{font:600 10px var(--sans);letter-spacing:.06em;text-transform:uppercase;
|
|
29
30
|
color:var(--ink-faint);border-right:1px solid var(--line);padding-right:7px}
|
|
30
31
|
.imeta .num{font:10.5px var(--mono);color:var(--ink-faint)}
|
|
31
32
|
.imeta .when{font:10.5px var(--sans);color:var(--ink-faint);margin-left:auto}
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
|
|
49
50
|
/* ---------- thread ---------- */
|
|
50
51
|
.thead{border-bottom:1px solid var(--line);padding-bottom:16px}
|
|
51
|
-
.thead h3{margin:8px 0 0;font:600
|
|
52
|
+
.thead h3{margin:8px 0 0;font:600 19px/1.3 var(--sans);letter-spacing:-.02em;color:var(--ink)}
|
|
52
53
|
/* The same fact as the chip, said in full, once, at the top of the thread it applies to.
|
|
53
54
|
Tight to the title and a clear gap above the buttons: it is a statement about this pull
|
|
54
55
|
request, not a caption on the controls. At an even 10/16 it read as the latter. */
|
|
@@ -65,7 +66,7 @@
|
|
|
65
66
|
/* Reactions. Small, under the comment they belong to, the way GitHub puts them — an agent's
|
|
66
67
|
👀 is an acknowledgement and it should be readable at a glance rather than counted. */
|
|
67
68
|
.reacts{display:flex;gap:6px;flex-wrap:wrap;margin-top:10px}
|
|
68
|
-
.react{font:11px var(--sans);border:1px solid var(--line);border-radius:
|
|
69
|
+
.react{font:11px var(--sans);border:1px solid var(--line);border-radius:999px;padding:2px 9px;
|
|
69
70
|
color:var(--ink-dim);background:var(--panel-2);cursor:default}
|
|
70
71
|
/* Reply, close and merge, beside the title rather than under the last comment. A thread is
|
|
71
72
|
read newest-first and answered from the top, so nothing here is worth scrolling to. */
|
|
@@ -79,10 +80,11 @@
|
|
|
79
80
|
rather than three places to navigate to. */
|
|
80
81
|
.tabs{display:flex;gap:2px;border-bottom:1px solid var(--line);margin:2px 0 0}
|
|
81
82
|
.tab{background:none;border:0;border-bottom:2px solid transparent;cursor:pointer;
|
|
82
|
-
font:12.5px var(--sans);color:var(--ink-faint);padding:9px 12px;margin-bottom:-1px
|
|
83
|
+
font:500 12.5px var(--sans);color:var(--ink-faint);padding:9px 12px;margin-bottom:-1px;
|
|
84
|
+
transition:color .15s var(--ease),border-color .15s var(--ease)}
|
|
83
85
|
.tab:hover{color:var(--ink)}
|
|
84
86
|
.tab[aria-current="true"]{color:var(--ink);border-bottom-color:var(--accent)}
|
|
85
|
-
.tab:focus-visible{
|
|
87
|
+
.tab:focus-visible{box-shadow:inset 0 0 0 1px var(--accent-dim);border-radius:6px 6px 0 0}
|
|
86
88
|
|
|
87
89
|
.prcommit{display:flex;gap:10px;align-items:baseline;padding:8px 0;
|
|
88
90
|
border-top:1px solid var(--line);font-size:12.5px}
|
|
@@ -101,9 +103,9 @@
|
|
|
101
103
|
.labelpick .chips{display:flex;flex-wrap:wrap;gap:6px;margin-top:6px}
|
|
102
104
|
.chip.pick{background:none;cursor:pointer;padding:3px 9px;font-size:11px;color:var(--ink-dim)}
|
|
103
105
|
.chip.pick:hover{border-color:var(--ink-faint);color:var(--ink)}
|
|
104
|
-
.chip.pick:focus-visible{
|
|
105
|
-
.chip.pick[aria-pressed="true"]{background:
|
|
106
|
-
border-color:var(--accent-dim);color:var(--
|
|
106
|
+
.chip.pick:focus-visible{box-shadow:0 0 0 3px var(--accent-soft);border-color:var(--accent)}
|
|
107
|
+
.chip.pick[aria-pressed="true"]{background:var(--accent-soft);
|
|
108
|
+
border-color:var(--accent-dim);color:var(--accent)}
|
|
107
109
|
|
|
108
110
|
/* ---------- the @ list ----------
|
|
109
111
|
A mention is the mechanism: a staff member's workflow gates on their handle, so a misspelled
|
|
@@ -113,12 +115,12 @@
|
|
|
113
115
|
The height is capped well under a dialog's, because it is placed inside one and a dialog
|
|
114
116
|
scrolls its own box: anything taller is not long, it is cut off. */
|
|
115
117
|
.mentions{position:absolute;z-index:30;min-width:280px;max-width:min(420px,90%);max-height:196px;
|
|
116
|
-
overflow-y:auto;background:var(--
|
|
117
|
-
padding:4px;box-shadow:
|
|
118
|
+
overflow-y:auto;background:var(--bg-elev);border:1px solid var(--border-strong);border-radius:var(--r);
|
|
119
|
+
padding:4px;box-shadow:var(--shadow-lg)}
|
|
118
120
|
.mrow{display:grid;grid-template-columns:auto 1fr;gap:2px 8px;width:100%;text-align:left;
|
|
119
121
|
background:none;border:0;border-radius:6px;padding:6px 8px;cursor:pointer;font:inherit}
|
|
120
|
-
.mrow:hover{background:var(--
|
|
121
|
-
.mrow[aria-selected="true"]{background:var(--
|
|
122
|
+
.mrow:hover{background:var(--hover)}
|
|
123
|
+
.mrow[aria-selected="true"]{background:var(--accent-soft)}
|
|
122
124
|
.mrow .mat{font:12px var(--mono);color:var(--accent)}
|
|
123
125
|
.mrow .mname{font:12.5px var(--sans);color:var(--ink);overflow:hidden;text-overflow:ellipsis;
|
|
124
126
|
white-space:nowrap}
|
|
@@ -156,9 +158,10 @@ textarea.dropping{border-color:var(--accent);background:color-mix(in srgb,var(--
|
|
|
156
158
|
/* An item this thread points at, as a row you can open here rather than a link that throws
|
|
157
159
|
you out to GitHub. Open and closed read at a glance, which is the whole reason to show it. */
|
|
158
160
|
.xref{display:flex;gap:8px;align-items:baseline;width:100%;text-align:left;background:none;
|
|
159
|
-
border:1px solid var(--line);border-radius:
|
|
160
|
-
cursor:pointer;color:var(--ink-dim);font:12.5px var(--sans)
|
|
161
|
-
|
|
161
|
+
border:1px solid var(--line);border-radius:var(--r);padding:7px 11px;margin-top:6px;
|
|
162
|
+
cursor:pointer;color:var(--ink-dim);font:12.5px var(--sans);background:var(--bg-elev);
|
|
163
|
+
transition:border-color .15s var(--ease),background .15s var(--ease),color .15s var(--ease)}
|
|
164
|
+
.xref:hover{border-color:var(--border-strong);background:var(--surface-2);color:var(--ink)}
|
|
162
165
|
.xref .st{flex:none;display:inline-flex;--ic:14px;position:relative;top:2px}
|
|
163
166
|
.xref .st.open{color:var(--accent)} .xref .st.closed{color:var(--derived)}
|
|
164
167
|
.xref .st.merged{color:var(--derived)} .xref .st.draft{color:var(--ink-faint)}
|
|
@@ -1,86 +1,102 @@
|
|
|
1
1
|
/* The page frame: sidebar, main column, and the tree-beside-viewer split every screen uses. */
|
|
2
2
|
|
|
3
|
-
.app{display:grid;grid-template-columns:
|
|
3
|
+
.app{display:grid;grid-template-columns:252px 1fr;min-height:100vh}
|
|
4
4
|
/* ---------- sidebar ---------- */
|
|
5
|
-
.side{background:var(--
|
|
6
|
-
position:sticky;top:0;height:100vh;overflow-y:auto;display:flex;flex-direction:column
|
|
7
|
-
|
|
5
|
+
.side{background:var(--side);border-right:1px solid var(--line);padding:16px 10px 12px;
|
|
6
|
+
position:sticky;top:0;height:100vh;overflow-y:auto;display:flex;flex-direction:column;
|
|
7
|
+
gap:1px}
|
|
8
|
+
.brand{padding:4px 10px 16px;font:600 15px/1.2 var(--sans);letter-spacing:-.02em;
|
|
9
|
+
display:grid;grid-template-columns:auto 1fr;column-gap:10px;align-items:center}
|
|
8
10
|
/* The tab icon, in the corner it belongs in. Drawn rather than fetched so it takes the
|
|
9
11
|
theme's accent and costs no request. */
|
|
10
|
-
.brand .mark{display:inline-block;width:
|
|
11
|
-
background:var(--accent)
|
|
12
|
+
.brand .mark{grid-row:1/3;display:inline-block;width:24px;height:24px;border-radius:7px;
|
|
13
|
+
background:var(--accent-fill)}
|
|
12
14
|
.brand small{display:block;color:var(--ink-faint);font-weight:400;font-size:11.5px;
|
|
13
|
-
letter-spacing
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
letter-spacing:0;margin-top:2px;overflow:hidden;text-overflow:ellipsis;
|
|
16
|
+
white-space:nowrap}
|
|
17
|
+
.refreshall{display:flex;align-items:center;gap:8px;width:100%;margin:0 0 12px;
|
|
18
|
+
background:var(--hover);border:1px solid transparent;color:var(--ink-dim);
|
|
19
|
+
border-radius:8px;padding:6px 10px;cursor:pointer;font:11.5px var(--sans);text-align:left;
|
|
20
|
+
transition:color .15s var(--ease),background .15s var(--ease)}
|
|
21
|
+
.refreshall:hover{color:var(--ink);background:var(--active)}
|
|
18
22
|
.refreshall .sync{display:inline-flex;--ic:13px;flex:none}
|
|
19
23
|
.refreshall.spin .sync{animation:spin .9s linear infinite}
|
|
20
24
|
|
|
21
|
-
.sect{padding:
|
|
25
|
+
.sect{padding:16px 10px 6px;font:600 11px var(--sans);letter-spacing:.08em;
|
|
22
26
|
text-transform:uppercase;color:var(--ink-faint)}
|
|
23
27
|
/* The Staff heading is also the fold for the list under it, so it is a button — and has to
|
|
24
|
-
go on reading as a heading rather than as a control. The caret and the
|
|
28
|
+
go on reading as a heading rather than as a control. The caret and the left padding
|
|
25
29
|
are the staff rows' own, so the two carets line up in one column. */
|
|
26
30
|
.sectfold{display:flex;align-items:center;gap:7px;width:100%;background:none;border:0;
|
|
27
|
-
cursor:pointer;text-align:left;font:600
|
|
28
|
-
text-transform:uppercase;color:var(--ink-faint)
|
|
31
|
+
border-radius:6px;cursor:pointer;text-align:left;font:600 11px var(--sans);letter-spacing:.08em;
|
|
32
|
+
text-transform:uppercase;color:var(--ink-faint);margin-top:12px;
|
|
33
|
+
transition:color .15s var(--ease)}
|
|
29
34
|
.sectfold:hover{color:var(--ink-dim)}
|
|
30
|
-
.sectfold .caret{display:inline-flex;--ic:12px;flex:none;transition:transform .
|
|
35
|
+
.sectfold .caret{display:inline-flex;--ic:12px;flex:none;transition:transform .15s var(--ease)}
|
|
31
36
|
.sectfold[aria-expanded="false"] .caret{transform:rotate(-90deg)}
|
|
32
37
|
/* The count is a number, not a heading: mono, and none of the heading's letterspacing. */
|
|
33
|
-
.sectfold .n{font:10.5px var(--mono);letter-spacing:0;text-transform:none;color:var(--ink-faint)
|
|
38
|
+
.sectfold .n{font:10.5px var(--mono);letter-spacing:0;text-transform:none;color:var(--ink-faint);
|
|
39
|
+
font-variant-numeric:tabular-nums}
|
|
34
40
|
/* Flex, not block with a float. The icons are block-level SVGs and the trailing count has to
|
|
35
41
|
sit hard right; `float` does neither of those inside a flex row, and did neither of them
|
|
36
42
|
outside one once the icons arrived. */
|
|
37
|
-
.nav{display:flex;align-items:center;width:100%;text-align:left;background:none;
|
|
38
|
-
color:var(--ink-dim);font:
|
|
39
|
-
|
|
40
|
-
.
|
|
41
|
-
.nav
|
|
42
|
-
.nav
|
|
43
|
-
.nav
|
|
44
|
-
.nav.
|
|
43
|
+
.nav{position:relative;display:flex;align-items:center;width:100%;text-align:left;background:none;
|
|
44
|
+
border:0;border-radius:7px;color:var(--ink-dim);font:500 13.5px var(--sans);padding:6px 10px;
|
|
45
|
+
cursor:pointer;min-height:32px;
|
|
46
|
+
transition:background .15s var(--ease),color .15s var(--ease)}
|
|
47
|
+
.nav:hover{color:var(--ink);background:var(--hover)}
|
|
48
|
+
.nav:focus-visible{box-shadow:0 0 0 2px var(--accent-soft),inset 0 0 0 1px var(--accent-dim)}
|
|
49
|
+
.nav[aria-current="true"]{color:var(--ink);background:var(--sel)}
|
|
50
|
+
.nav .ic{color:var(--ink-faint);margin-right:10px;--ic:15px;flex:none;
|
|
51
|
+
transition:color .15s var(--ease)}
|
|
52
|
+
.nav:hover .ic{color:var(--ink-dim)}
|
|
53
|
+
.nav[aria-current="true"] .ic{color:var(--accent)}
|
|
54
|
+
.nav .n{margin-left:auto;padding-left:10px;color:var(--ink-faint);font:500 10.5px var(--mono);
|
|
55
|
+
font-variant-numeric:tabular-nums}
|
|
56
|
+
.nav .n:not(:empty):not(.wait){padding:1px 7px;border-radius:999px;margin-left:auto;
|
|
57
|
+
background:var(--sel);color:var(--ink-dim);min-width:20px;
|
|
58
|
+
text-align:center}
|
|
59
|
+
.nav .n.wait{margin-left:auto}
|
|
60
|
+
.nav.top{margin-bottom:0}
|
|
45
61
|
|
|
46
62
|
/* Staff are rows that unfold into their own views, rather than a dropdown plus a list you
|
|
47
63
|
have to connect for yourself. The nesting is the hierarchy, said out loud. */
|
|
48
|
-
.staffrow{display:flex;align-items:center;gap:7px;font:
|
|
49
|
-
padding-right:
|
|
50
|
-
.staffrow .caret{color:var(--ink-faint);--ic:12px;flex:none;transition:transform .
|
|
64
|
+
.staffrow{display:flex;align-items:center;gap:7px;font:500 13px var(--sans);color:var(--ink);
|
|
65
|
+
padding-right:10px}
|
|
66
|
+
.staffrow .caret{color:var(--ink-faint);--ic:12px;flex:none;transition:transform .15s var(--ease)}
|
|
51
67
|
.staffrow[aria-expanded="false"] .caret{transform:rotate(-90deg)}
|
|
52
68
|
.staffrow .t{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
53
69
|
.staffrow .hh{font:10.5px var(--mono);color:var(--ink-faint);flex:none}
|
|
54
70
|
.staffrow[aria-selected="true"]{color:var(--ink)}
|
|
55
|
-
.staffviews{padding-
|
|
56
|
-
/* `subnav`, not `sub`: `.sub` is the page subtitle and carries a
|
|
71
|
+
.staffviews{position:relative;padding:2px 0 6px;margin-left:12px}
|
|
72
|
+
/* `subnav`, not `sub`: `.sub` is the page subtitle and carries a bottom margin, which
|
|
57
73
|
these rows inherited as a gap you could park a car in. */
|
|
58
|
-
.nav.subnav{padding:
|
|
74
|
+
.nav.subnav{padding:4px 10px 4px 16px;font-size:12.5px;min-height:28px}
|
|
59
75
|
.nav.subnav .n{font-size:10px}
|
|
60
|
-
.sidefoot{margin-top:auto;padding-top:14px}
|
|
76
|
+
.sidefoot{margin-top:auto;padding-top:14px;border-top:1px solid var(--line)}
|
|
61
77
|
.sidefoot .nav{font-size:12.5px;color:var(--ink-faint)}
|
|
62
78
|
.sidefoot .nav:hover{color:var(--ink-dim)}
|
|
63
79
|
|
|
64
80
|
/* ---------- main ---------- */
|
|
65
|
-
main{padding:
|
|
81
|
+
main{padding:36px 44px 96px;max-width:1220px;overflow-x:hidden}
|
|
66
82
|
|
|
67
83
|
/* ---------- tree beside viewer ---------- */
|
|
68
84
|
.split{display:grid;grid-template-columns:314px 1fr;gap:16px;align-items:start}
|
|
69
85
|
@media (max-width:900px){.split{grid-template-columns:1fr}}
|
|
70
|
-
.tree{background:var(--panel);border:1px solid var(--line);border-radius:
|
|
71
|
-
max-height:74vh;overflow:auto}
|
|
72
|
-
.tdir{font:600 11px var(--mono);color:var(--ink-faint);padding:
|
|
73
|
-
.tdir.first{padding-top:
|
|
86
|
+
.tree{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);padding:6px;
|
|
87
|
+
max-height:74vh;overflow:auto;box-shadow:var(--shadow-sm)}
|
|
88
|
+
.tdir{font:600 11px var(--mono);color:var(--ink-faint);padding:9px 8px 4px;letter-spacing:.02em}
|
|
89
|
+
.tdir.first{padding-top:3px}
|
|
74
90
|
.tfile{display:flex;align-items:baseline;gap:10px;width:100%;text-align:left;background:none;
|
|
75
|
-
border:0;color:var(--ink-dim);font:12.5px var(--mono);padding:
|
|
76
|
-
cursor:pointer}
|
|
77
|
-
.tfile:hover{background:var(--
|
|
78
|
-
.tfile[aria-current="true"]{background:var(--
|
|
91
|
+
border:0;color:var(--ink-dim);font:12.5px var(--mono);padding:5px 8px;border-radius:6px;
|
|
92
|
+
cursor:pointer;transition:background .12s var(--ease),color .12s var(--ease)}
|
|
93
|
+
.tfile:hover{background:var(--hover);color:var(--ink)}
|
|
94
|
+
.tfile[aria-current="true"]{background:var(--accent-soft);color:var(--accent)}
|
|
79
95
|
.tfile span.t{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
80
96
|
.tfile i{color:var(--ink-faint);font-style:normal;font-size:10.5px;flex:none;
|
|
81
97
|
font-variant-numeric:tabular-nums}
|
|
82
98
|
.tfile:focus{outline:none}
|
|
83
|
-
.tfile:focus-visible{
|
|
99
|
+
.tfile:focus-visible{box-shadow:inset 0 0 0 1px var(--accent-dim)}
|
|
84
100
|
|
|
85
101
|
/* A search result: the page, and the lines the words were actually found in. Without the lines
|
|
86
102
|
this is a filter on titles, which is the thing that was not good enough. */
|
|
@@ -93,8 +109,8 @@ main{padding:28px 34px 80px;max-width:1180px;overflow-x:hidden}
|
|
|
93
109
|
.thit .hitline em{font-style:normal;color:var(--ink);background:color-mix(in srgb,var(--accent) 22%,transparent);
|
|
94
110
|
border-radius:3px;padding:0 2px}
|
|
95
111
|
|
|
96
|
-
.viewer{background:var(--panel);border:1px solid var(--line);border-radius:
|
|
97
|
-
min-height:340px;max-height:74vh;overflow:auto}
|
|
112
|
+
.viewer{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);padding:22px 26px;
|
|
113
|
+
min-height:340px;max-height:74vh;overflow:auto;box-shadow:var(--shadow-sm)}
|
|
98
114
|
.viewer pre{margin:0;white-space:pre-wrap;word-break:break-word;font:12.5px/1.65 var(--mono);color:var(--ink-dim)}
|
|
99
115
|
/* Source keeps its own line breaks and scrolls, rather than wrapping into soup. */
|
|
100
116
|
.viewer pre.code{white-space:pre;word-break:normal;overflow-x:auto}
|
|
@@ -105,12 +121,14 @@ main{padding:28px 34px 80px;max-width:1180px;overflow-x:hidden}
|
|
|
105
121
|
.viewer audio.player{background:none}
|
|
106
122
|
.viewer table{border-collapse:collapse;font:12px var(--mono);width:100%}
|
|
107
123
|
.viewer td,.viewer th{border:1px solid var(--line);padding:4px 8px;text-align:left;white-space:nowrap}
|
|
108
|
-
.viewer th{position:sticky;top:0;background:var(--panel-2);color:var(--ink)}
|
|
124
|
+
.viewer th{position:sticky;top:0;background:var(--panel-2);color:var(--ink);font-weight:600}
|
|
109
125
|
|
|
110
126
|
.gallery{display:grid;gap:10px;grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}
|
|
111
127
|
.gallery figure{margin:0;position:relative}
|
|
112
128
|
.gallery img,.gallery video{width:100%;aspect-ratio:4/3;object-fit:contain;background:var(--panel-2);
|
|
113
|
-
border-radius:
|
|
129
|
+
border-radius:var(--r);border:1px solid var(--line);cursor:pointer;display:block;
|
|
130
|
+
transition:border-color .15s var(--ease),transform .15s var(--ease)}
|
|
131
|
+
.gallery img:hover,.gallery video:hover{border-color:var(--border-strong)}
|
|
114
132
|
/* A still frame and a photograph look identical in a grid, so the video says which it is. */
|
|
115
133
|
.playmark{position:absolute;top:8px;right:8px;display:inline-flex;padding:4px;border-radius:50%;
|
|
116
134
|
background:color-mix(in srgb,#000 55%,transparent);color:#fff;--ic:12px;pointer-events:none}
|
|
@@ -1,34 +1,37 @@
|
|
|
1
1
|
/* One renderer, two sizes: .cbody is a comment in a thread, .doc is a file being read.
|
|
2
2
|
Everything shared lives on .md so a fix reaches both. */
|
|
3
3
|
|
|
4
|
-
.md{line-height:1.
|
|
4
|
+
.md{line-height:1.7}
|
|
5
5
|
.md>:first-child{margin-top:0}
|
|
6
6
|
.md p{margin:0 0 10px}
|
|
7
7
|
.md h1,.md h2,.md h3,.md h4,.md h5,.md h6{color:var(--ink);font-weight:600;line-height:1.3;
|
|
8
|
-
margin:
|
|
9
|
-
.md h1{font-size:
|
|
8
|
+
margin:26px 0 10px;letter-spacing:-.02em}
|
|
9
|
+
.md h1{font-size:22px} .md h2{font-size:17.5px} .md h3{font-size:15px}
|
|
10
10
|
.md h4,.md h5,.md h6{font-size:13.5px;color:var(--ink-dim)}
|
|
11
|
-
.md h1,.md h2{padding-bottom:
|
|
11
|
+
.md h1,.md h2{padding-bottom:8px;border-bottom:1px solid var(--line)}
|
|
12
12
|
.md ul,.md ol{margin:0 0 10px;padding-left:20px}
|
|
13
13
|
.md li{margin:3px 0}
|
|
14
14
|
.md li>ul,.md li>ol{margin:4px 0 0}
|
|
15
15
|
.md ul.tasks{list-style:none;padding-left:1px}
|
|
16
16
|
.md .box{color:var(--ink-faint);margin-right:6px;display:inline-flex;--ic:14px;
|
|
17
17
|
vertical-align:-3px}
|
|
18
|
-
.md code{font:12px var(--mono);color:var(--
|
|
19
|
-
padding:1px
|
|
20
|
-
.md pre{background:var(--
|
|
21
|
-
padding:
|
|
18
|
+
.md code{font:12px var(--mono);color:var(--ink);background:color-mix(in srgb,var(--ink) 7%,transparent);
|
|
19
|
+
padding:1px 5px;border-radius:5px;word-break:break-word}
|
|
20
|
+
.md pre{background:var(--surface-2);border:0;border-radius:var(--r);
|
|
21
|
+
padding:13px 15px;font:12px/1.62 var(--mono);margin:10px 0;color:var(--ink-dim);
|
|
22
22
|
overflow-x:auto;white-space:pre}
|
|
23
|
-
.md pre code{background:none;padding:0;color:inherit;font-size:inherit}
|
|
24
|
-
.md a{color:var(--
|
|
25
|
-
|
|
23
|
+
.md pre code{background:none;border:0;padding:0;color:inherit;font-size:inherit}
|
|
24
|
+
.md a{color:var(--accent);text-decoration:underline;text-decoration-color:var(--accent-dim);
|
|
25
|
+
text-underline-offset:3px;text-decoration-thickness:1px}
|
|
26
|
+
.md a:hover{text-decoration-color:var(--accent)}
|
|
27
|
+
.md blockquote{margin:12px 0;padding:2px 0 2px 14px;border-left:3px solid var(--line);color:var(--ink-dim)}
|
|
26
28
|
.md hr{border:0;border-top:1px solid var(--line);margin:16px 0}
|
|
27
29
|
.md img{max-width:100%;border-radius:6px;background:var(--panel-2)}
|
|
28
30
|
.md .ctable{overflow-x:auto;margin:10px 0;max-width:100%}
|
|
29
31
|
.md table{border-collapse:collapse;font-size:12.5px;width:100%}
|
|
30
|
-
.md th,.md td{border:1px solid var(--line);padding:
|
|
31
|
-
.md th{background:var(--panel-2);color:var(--ink);font-weight:600;white-space:nowrap
|
|
32
|
+
.md th,.md td{border:1px solid var(--line);padding:7px 10px;text-align:left;vertical-align:top}
|
|
33
|
+
.md th{background:var(--panel-2);color:var(--ink);font-weight:600;white-space:nowrap;
|
|
34
|
+
font-size:11.5px;letter-spacing:.02em}
|
|
32
35
|
.md td{color:var(--ink-dim)}
|
|
33
36
|
.md td b,.md td strong{color:var(--ink)}
|
|
34
37
|
.cbody{margin-top:8px;font-size:13.5px;max-width:74ch}
|
|
@@ -70,5 +73,5 @@ pre.yaml{color:var(--ink)}
|
|
|
70
73
|
Bordered and inset so it reads as a figure rather than the page bleeding into another one:
|
|
71
74
|
these are pictures of this same UI, and without a frame the two run together. */
|
|
72
75
|
.md img{display:block;max-width:100%;height:auto;margin:14px 0;
|
|
73
|
-
border:1px solid var(--line);border-radius:
|
|
76
|
+
border:1px solid var(--line);border-radius:var(--r);box-shadow:var(--shadow)}
|
|
74
77
|
.md img+em,.md p>img+em{display:block}
|
|
@@ -1,55 +1,60 @@
|
|
|
1
1
|
/* The setup screen, and the copy-a-prompt panel it shares with the authoring screens. */
|
|
2
2
|
|
|
3
|
-
.step{background:var(--panel);border:1px solid var(--line);border-radius:
|
|
4
|
-
padding:
|
|
5
|
-
.step.done{border-color:var(--accent
|
|
3
|
+
.step{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-lg);
|
|
4
|
+
padding:20px 22px 22px;margin-bottom:14px;box-shadow:var(--shadow-sm)}
|
|
5
|
+
.step.done{border-color:color-mix(in srgb,var(--accent) 30%,var(--line))}
|
|
6
6
|
.stephead{display:flex;align-items:center;gap:11px;margin-bottom:10px}
|
|
7
|
-
.stephead h2{margin:0;font:600 16px var(--sans);letter-spacing:-.
|
|
8
|
-
.stepn{flex:none;width:
|
|
9
|
-
background:var(--
|
|
7
|
+
.stephead h2{margin:0;font:600 16px var(--sans);letter-spacing:-.018em}
|
|
8
|
+
.stepn{flex:none;width:24px;height:24px;border-radius:50%;display:grid;place-items:center;
|
|
9
|
+
background:var(--surface-2);border:1px solid transparent;color:var(--ink-dim);
|
|
10
10
|
font:600 11px var(--mono)}
|
|
11
|
-
.step.done .stepn{background:var(--accent-
|
|
11
|
+
.step.done .stepn{background:var(--accent-fill);border-color:transparent;color:var(--accent-ink)}
|
|
12
12
|
|
|
13
13
|
/* ---------- the form ---------- */
|
|
14
14
|
|
|
15
15
|
.setupform{display:grid;gap:13px;margin:14px 0 18px;max-width:520px}
|
|
16
16
|
.field{display:grid;gap:4px}
|
|
17
17
|
.field>span{font:600 12px var(--sans);color:var(--ink-dim)}
|
|
18
|
-
.field input,.field select{background:var(--
|
|
19
|
-
border-radius:
|
|
20
|
-
|
|
18
|
+
.field input,.field select{background:var(--bg-elev);border:1px solid var(--border-strong);color:var(--ink);
|
|
19
|
+
border-radius:var(--r);padding:8px 11px;font:13px var(--sans);outline:none;width:100%;
|
|
20
|
+
transition:border-color .15s var(--ease),box-shadow .15s var(--ease)}
|
|
21
|
+
.field input:focus,.field select:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
|
|
21
22
|
.field small{color:var(--ink-faint);font-size:11.5px;line-height:1.45}
|
|
22
23
|
|
|
23
24
|
.choices{display:grid;gap:8px;margin:10px 0 4px;max-width:640px}
|
|
24
25
|
.choice{display:grid;grid-template-columns:auto 1fr;gap:3px 10px;align-items:start;
|
|
25
|
-
background:var(--
|
|
26
|
-
padding:
|
|
27
|
-
|
|
26
|
+
background:var(--bg-elev);border:1px solid var(--line);border-radius:var(--r);
|
|
27
|
+
padding:12px 14px;cursor:pointer;
|
|
28
|
+
transition:border-color .15s var(--ease),background .15s var(--ease),box-shadow .15s var(--ease)}
|
|
29
|
+
.choice:hover{border-color:var(--border-strong)}
|
|
30
|
+
.choice:has(input:checked){border-color:var(--accent-dim);background:var(--accent-soft)}
|
|
28
31
|
.choice input{grid-row:1/3;margin-top:3px;accent-color:var(--accent)}
|
|
29
32
|
.choice b{font:600 13px var(--sans)}
|
|
30
33
|
.choice small{color:var(--ink-dim);font-size:12px;line-height:1.45}
|
|
31
34
|
.choice code{grid-column:2;font:10.5px var(--mono);color:var(--ink-faint)}
|
|
32
35
|
|
|
33
36
|
.row{display:flex;gap:9px;align-items:center;flex-wrap:wrap;margin-top:6px}
|
|
34
|
-
.btn{background:var(--
|
|
35
|
-
padding:
|
|
36
|
-
.
|
|
37
|
+
.btn{background:var(--surface-2);border:1px solid transparent;color:var(--ink);border-radius:8px;
|
|
38
|
+
padding:7px 14px;font:500 13px var(--sans);cursor:pointer;text-decoration:none;display:inline-block;
|
|
39
|
+
transition:background .15s var(--ease),opacity .15s var(--ease)}
|
|
40
|
+
.btn:hover{background:color-mix(in srgb,var(--surface-2) 88%,var(--ink) 12%)}
|
|
41
|
+
.btn:active{opacity:.8}
|
|
37
42
|
/* The full accent, not the dim one. Dim on the page background is pale-green-on-white with
|
|
38
43
|
near-white text: the button that does the main thing on the screen read as disabled. */
|
|
39
|
-
.btn.primary{background:var(--accent);border-color:
|
|
40
|
-
.btn.primary:hover{
|
|
41
|
-
.btn[disabled]{opacity:.
|
|
44
|
+
.btn.primary{background:var(--accent-fill);border-color:transparent;color:var(--accent-ink);font-weight:600}
|
|
45
|
+
.btn.primary:hover{background:var(--accent-fill);opacity:.88}
|
|
46
|
+
.btn[disabled]{opacity:.45;cursor:default}
|
|
42
47
|
|
|
43
|
-
.cmd{background:var(--
|
|
48
|
+
.cmd{background:var(--bg);border:1px solid var(--line);border-radius:var(--r);padding:10px 12px;
|
|
44
49
|
font:12px/1.6 var(--mono);color:var(--ink);overflow-x:auto;white-space:pre-wrap;
|
|
45
50
|
word-break:break-word;margin:9px 0}
|
|
46
51
|
|
|
47
52
|
.planout{margin-top:12px}
|
|
48
53
|
.filelist{display:grid;gap:2px;margin:9px 0;max-height:240px;overflow-y:auto;
|
|
49
|
-
background:var(--
|
|
54
|
+
background:var(--bg);border:1px solid var(--line);border-radius:var(--r);padding:10px 12px}
|
|
50
55
|
.filelist code{font:11px var(--mono);color:var(--ink-dim)}
|
|
51
56
|
|
|
52
|
-
.manual{background:var(--
|
|
57
|
+
.manual{background:var(--bg-elev);border:1px solid var(--line);border-radius:var(--r);
|
|
53
58
|
padding:13px 15px;margin:11px 0}
|
|
54
59
|
.manual b{display:block;font:600 13px var(--sans);margin-bottom:4px}
|
|
55
60
|
.manual p{margin:0 0 6px;font-size:13px}
|
|
@@ -59,22 +64,23 @@
|
|
|
59
64
|
|
|
60
65
|
.paste{border-top:1px solid var(--line);margin-top:16px;padding-top:15px}
|
|
61
66
|
.paste h3{margin:0 0 5px;font:600 14px var(--sans)}
|
|
62
|
-
.briefpreview{background:var(--
|
|
67
|
+
.briefpreview{background:var(--bg);border:1px solid var(--line);border-radius:var(--r);
|
|
63
68
|
padding:12px 14px;font:11.5px/1.6 var(--mono);max-height:340px;overflow:auto;
|
|
64
69
|
white-space:pre-wrap;word-break:break-word;margin:10px 0}
|
|
65
|
-
.pastebox{width:100%;background:var(--
|
|
66
|
-
border-radius:
|
|
70
|
+
.pastebox{width:100%;background:var(--bg-elev);border:1px solid var(--border-strong);color:var(--ink);
|
|
71
|
+
border-radius:var(--r);padding:10px 12px;font:12px/1.6 var(--mono);outline:none;resize:vertical;
|
|
67
72
|
margin:4px 0}
|
|
68
|
-
.pastebox:focus{border-color:var(--accent-
|
|
73
|
+
.pastebox:focus{border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
|
|
69
74
|
|
|
70
75
|
.pasteresult{margin-top:12px}
|
|
71
76
|
/* A model that replied in prose is the common case and not the person's mistake, so this reads
|
|
72
77
|
as a next step rather than as a failure. */
|
|
73
|
-
.problem{background:
|
|
78
|
+
.problem{background:color-mix(in srgb,var(--warn) 9%,transparent);
|
|
79
|
+
border:1px solid transparent;border-radius:var(--r);
|
|
74
80
|
padding:12px 14px;margin-bottom:10px}
|
|
75
81
|
.problem b{display:block;font:600 13px var(--sans);margin-bottom:7px}
|
|
76
82
|
|
|
77
|
-
.pastefile{background:var(--
|
|
83
|
+
.pastefile{background:var(--bg-elev);border:1px solid var(--line);border-radius:var(--r);
|
|
78
84
|
padding:12px 14px;margin-bottom:10px}
|
|
79
85
|
.pastefile.saved{border-color:var(--accent-dim)}
|
|
80
86
|
.pastefile b{font:600 13px var(--mono)}
|
|
@@ -83,8 +89,8 @@
|
|
|
83
89
|
|
|
84
90
|
/* ---------- the doctor checklist ---------- */
|
|
85
91
|
|
|
86
|
-
.check{display:grid;grid-template-columns:auto 1fr;gap:2px
|
|
87
|
-
padding:
|
|
92
|
+
.check{display:grid;grid-template-columns:auto 1fr;gap:2px 12px;align-items:start;
|
|
93
|
+
padding:12px 0;border-top:1px solid var(--line)}
|
|
88
94
|
.check:first-child{border-top:none}
|
|
89
95
|
.checkmark{font:600 13px var(--mono);line-height:1.5}
|
|
90
96
|
.check.fail .checkmark{color:var(--err)}
|
|
@@ -95,7 +101,7 @@
|
|
|
95
101
|
/* ---------- the repo picker ---------- */
|
|
96
102
|
|
|
97
103
|
.repolist{display:grid;gap:1px;max-height:280px;overflow-y:auto;
|
|
98
|
-
border:1px solid var(--line);border-radius:
|
|
104
|
+
border:1px solid var(--line);border-radius:var(--r);background:var(--line)}
|
|
99
105
|
/* Scoped to the picker. Bare `.repo` also matched the project label on every inbox row,
|
|
100
106
|
which is where the white box and the stray padding behind MARKETING came from. */
|
|
101
107
|
.repolist .repo{display:flex;align-items:center;justify-content:space-between;gap:12px;
|
|
@@ -106,6 +112,6 @@
|
|
|
106
112
|
.repolist .repo .sub{margin:2px 0 0;font-size:11.5px}
|
|
107
113
|
|
|
108
114
|
/* Which of the two things this is: a new org, or one that already runs roster. */
|
|
109
|
-
.verdict{background:var(--
|
|
115
|
+
.verdict{background:var(--accent-soft);border:1px solid transparent;border-radius:var(--r);
|
|
110
116
|
padding:9px 12px;font-size:12.5px}
|
|
111
117
|
.verdict p{margin:0}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>roster</title>
|
|
7
7
|
<!-- Inline, so a local page with no network still has a tab icon and the console stays clean. -->
|
|
8
|
-
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0
|
|
8
|
+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%2334c759'/%3E%3C/svg%3E">
|
|
9
9
|
<!-- Stylesheets and modules are served from /assets by `roster portal`. No build step:
|
|
10
10
|
editing one of these files and reloading is the whole edit loop. -->
|
|
11
11
|
<link rel="stylesheet" href="/assets/css/base.css">
|
|
@@ -53,7 +53,7 @@ function drawGraph(canvas, wrap, s) {
|
|
|
53
53
|
}
|
|
54
54
|
const groups = [...members.keys()].sort((a, b) => members.get(b).length - members.get(a).length);
|
|
55
55
|
|
|
56
|
-
const PALETTE = ["#
|
|
56
|
+
const PALETTE = ["#30d158","#0a84ff","#bf5af2","#ff9f0a","#64d2ff","#ff453a","#ffcc00","#ff375f","#5e5ce6","#ac8e68"];
|
|
57
57
|
const colour = new Map(groups.map((g, i) => [g, PALETTE[i % PALETTE.length]]));
|
|
58
58
|
|
|
59
59
|
// The ring grows with the number of groups so they never crowd, and each group keeps its
|