@nanocollective/roster 0.1.0-alpha.3 → 0.1.0-alpha.30
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/README.md +70 -84
- package/dist/cli.js +4817 -2374
- package/docs/README.md +19 -11
- package/docs/agents.md +328 -13
- package/docs/architecture.md +13 -5
- package/docs/charters/analyst.md +65 -0
- package/docs/charters/cmo.md +69 -0
- package/docs/charters/community.md +63 -0
- package/docs/charters/cto.md +71 -0
- package/docs/charters/designer.md +65 -0
- package/docs/charters/devops.md +65 -0
- package/docs/charters/pm.md +70 -0
- package/docs/charters/qa.md +65 -0
- package/docs/charters/support.md +60 -0
- package/docs/charters/writer.md +63 -0
- package/docs/commands.md +95 -11
- package/docs/concepts.md +64 -12
- package/docs/cost.md +39 -3
- package/docs/developing.md +16 -21
- package/docs/doctor-codes.md +21 -6
- package/docs/export.md +4 -1
- package/docs/extending.md +13 -4
- package/docs/getting-started.md +133 -79
- 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/docs/manual-steps.md +95 -101
- package/docs/memory.md +29 -8
- package/docs/org-yaml.md +76 -11
- package/docs/portal.md +290 -49
- package/docs/prompts.md +77 -11
- package/docs/security.md +51 -7
- package/docs/session-workflow.md +51 -21
- package/docs/staff-yaml.md +17 -7
- package/docs/troubleshooting.md +23 -20
- package/docs/upgrading.md +9 -3
- package/docs/writing-a-charter.md +46 -17
- package/package.json +1 -1
- package/templates/brain/.github/workflows/%%STAFF%%-daily.yaml +7 -0
- package/templates/brain/.github/workflows/%%STAFF%%-mention.yaml +16 -4
- package/templates/brain/CHARTER.md +3 -3
- package/templates/brain/README.md +1 -0
- package/templates/brain/log/decisions.md +3 -0
- package/templates/brain/staff.yaml +0 -1
- package/templates/brain/strategy/ideas.md +7 -0
- package/templates/briefs/priorities.md +46 -0
- package/templates/ops/.github/workflows/session.yaml +117 -40
- package/templates/ops/agents.mjs +127 -8
- package/templates/ops/compose.mjs +77 -7
- package/templates/ops/inflight.mjs +157 -0
- package/templates/ops/org/operating.md +21 -7
- package/templates/ops/org/voice.md +9 -0
- package/templates/ops/prompts/_identity.md +8 -1
- package/templates/ops/prompts/_inflight.md +14 -0
- package/templates/ops/prompts/_paths.md +2 -1
- package/templates/ops/prompts/daily.md +16 -7
- package/templates/ops/prompts/mention.md +18 -2
- package/templates/ops/run-record.mjs +144 -0
- package/templates/portal/css/base.css +245 -64
- package/templates/portal/css/brain.css +30 -20
- package/templates/portal/css/diff.css +15 -10
- package/templates/portal/css/graph.css +12 -7
- package/templates/portal/css/health.css +32 -11
- package/templates/portal/css/inbox.css +117 -14
- package/templates/portal/css/layout.css +114 -41
- package/templates/portal/css/markdown.css +57 -15
- package/templates/portal/css/runs.css +13 -0
- package/templates/portal/css/setup.css +126 -39
- package/templates/portal/index.html +25 -3
- package/templates/portal/js/api.js +74 -4
- package/templates/portal/js/app.js +156 -14
- package/templates/portal/js/dialog.js +129 -4
- package/templates/portal/js/dom.js +25 -0
- package/templates/portal/js/icons.js +45 -1
- package/templates/portal/js/inflight.js +18 -0
- package/templates/portal/js/lightbox.js +273 -0
- package/templates/portal/js/md.js +23 -6
- package/templates/portal/js/mdedit.js +84 -0
- package/templates/portal/js/mention.js +264 -0
- package/templates/portal/js/readiness.js +35 -0
- package/templates/portal/js/refresh.js +136 -6
- package/templates/portal/js/state.js +59 -8
- package/templates/portal/js/views/app.js +24 -7
- package/templates/portal/js/views/checklist.js +29 -10
- package/templates/portal/js/views/credential.js +84 -0
- package/templates/portal/js/views/docs.js +94 -4
- package/templates/portal/js/views/files.js +58 -14
- package/templates/portal/js/views/graph.js +1 -1
- package/templates/portal/js/views/health.js +178 -37
- package/templates/portal/js/views/hire.js +583 -0
- package/templates/portal/js/views/inbox.js +957 -126
- package/templates/portal/js/views/memory.js +16 -1
- package/templates/portal/js/views/org.js +124 -104
- package/templates/portal/js/views/orgedit.js +234 -0
- package/templates/portal/js/views/paste.js +87 -21
- package/templates/portal/js/views/prompt.js +61 -67
- package/templates/portal/js/views/repos.js +20 -15
- package/templates/portal/js/views/runonce.js +94 -0
- package/templates/portal/js/views/runs.js +165 -0
- package/templates/portal/js/views/setup.js +257 -75
- package/templates/portal/js/views/staff.js +157 -182
- package/templates/portal/js/views/todo.js +62 -0
- package/templates/portal/js/yaml.js +134 -0
- package/templates/brain/.github/workflows/%%STAFF%%-pr-mention.yaml +0 -50
- package/templates/ops/prompts/pr-mention.md +0 -57
|
@@ -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,42 +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],select{background:var(--
|
|
54
|
-
border
|
|
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)}
|
|
55
107
|
input[type=search]{width:280px}
|
|
56
|
-
input
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
button.
|
|
67
|
-
|
|
68
|
-
.
|
|
69
|
-
.ghbtn:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
.
|
|
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)}
|
|
117
|
+
|
|
118
|
+
/* One size, whether it is a button or a link. They sit in rows together, and `a` taking its
|
|
119
|
+
line-height from the font shorthand while `button` set its own made every such row a set of
|
|
120
|
+
controls at two different heights. */
|
|
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%)}
|
|
73
140
|
.iconbtn{display:inline-flex;align-items:center;justify-content:center}
|
|
74
141
|
.iconbtn .sync{display:inline-flex;--ic:15px}
|
|
75
142
|
.iconbtn.spin .sync{animation:spin .9s linear infinite}
|
|
@@ -82,29 +149,143 @@ svg.ic{width:var(--ic,15px);height:var(--ic,15px);display:block;flex:none}
|
|
|
82
149
|
/* A slot that holds one, centred, wherever a text glyph used to sit on a baseline. */
|
|
83
150
|
.icslot{display:inline-flex;align-items:center;justify-content:center;flex:none}
|
|
84
151
|
|
|
85
|
-
.chip{font:
|
|
86
|
-
border:1px solid
|
|
87
|
-
|
|
88
|
-
.chip.
|
|
89
|
-
.chip.
|
|
90
|
-
.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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)}
|
|
163
|
+
|
|
164
|
+
/* ---------- waiting ----------
|
|
165
|
+
The inbox reads every repo in the org, which is seconds on a cold cache. What used to stand
|
|
166
|
+
there was one line of grey text in an otherwise empty panel beside a second empty panel,
|
|
167
|
+
which reads as a page that has failed rather than one that is working. These are the shape
|
|
168
|
+
of what is coming: rows in the list, a title and paragraphs in the viewer. */
|
|
169
|
+
.sk{--skbg:color-mix(in srgb,var(--ink) 7%,transparent);border-radius:6px;
|
|
170
|
+
background:var(--skbg);animation:pulse 1.4s ease-in-out infinite}
|
|
171
|
+
.sk-row{background:none;animation:none;padding:11px 10px;border-top:1px solid var(--line)}
|
|
172
|
+
.sk-row:first-of-type{border-top:0}
|
|
173
|
+
.sk-row .skbar{height:11px;border-radius:6px;
|
|
174
|
+
background:var(--skbg);animation:pulse 1.4s ease-in-out infinite}
|
|
175
|
+
.sk-row .skbar.t{width:84%}
|
|
176
|
+
.sk-row .skbar.m{width:38%;height:8px;margin-top:8px}
|
|
177
|
+
/* Staggered, so the list reads as several things loading rather than one block flashing. */
|
|
178
|
+
.sk-row:nth-child(2n) .skbar.t{width:68%}
|
|
179
|
+
.sk-row:nth-child(3n) .skbar.t{width:92%}
|
|
180
|
+
.sk-row:nth-child(3n) .skbar.m{width:52%}
|
|
181
|
+
.sk-head{height:19px;width:56%;margin:6px 0 18px}
|
|
182
|
+
.sk-line{height:10px;width:100%;margin:9px 0}
|
|
183
|
+
.sk-line:nth-child(2n){width:88%}
|
|
184
|
+
.sk-line:nth-child(3n){width:94%}
|
|
185
|
+
.sk-line:last-child{width:42%}
|
|
186
|
+
/* The word beside them. It is the only part a screen reader gets, so it stays real text. */
|
|
187
|
+
.skhead{color:var(--ink-faint);font-size:12.5px;padding:4px 10px 8px}
|
|
188
|
+
/* A count that is still being fetched is not zero, and an empty badge reads as zero. */
|
|
189
|
+
.nav .n.wait{display:inline-block;width:15px;height:8px;border-radius:5px;
|
|
190
|
+
background:color-mix(in srgb,var(--ink) 10%,transparent);animation:pulse 1.3s ease-in-out infinite}
|
|
191
|
+
@keyframes pulse{0%,100%{opacity:.35}50%{opacity:.85}}
|
|
192
|
+
@media (prefers-reduced-motion:reduce){
|
|
193
|
+
.sk,.sk-row .skbar,.nav .n.wait{animation:none}
|
|
194
|
+
}
|
|
195
|
+
|
|
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}
|
|
98
198
|
.notice b{color:var(--ink)}
|
|
99
199
|
|
|
100
200
|
/* ---------- a dialog that asks for more than a line ----------
|
|
101
201
|
Native <dialog>, so the backdrop, the focus trap and Escape are the browser's job. */
|
|
102
|
-
dialog.ask{border:1px solid var(--
|
|
103
|
-
color:var(--ink);padding:
|
|
104
|
-
box-shadow:
|
|
105
|
-
dialog.ask
|
|
106
|
-
|
|
107
|
-
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)}
|
|
108
210
|
dialog.ask textarea{font:13.5px/1.6 var(--sans);min-height:96px;max-height:44vh}
|
|
109
|
-
dialog.
|
|
211
|
+
/* The attach control, when the dialog is a reply rather than a question. */
|
|
212
|
+
dialog.ask .attach{margin-top:9px}
|
|
213
|
+
dialog.ask .askrow{margin-top:14px;justify-content:flex-end}
|
|
110
214
|
dialog.ask .askrow .meta{margin-right:auto}
|
|
215
|
+
|
|
216
|
+
/* The lightbox: an image, over the page, that zooms.
|
|
217
|
+
*
|
|
218
|
+
* Not a <dialog>, so the stacking and the backdrop are declared here rather than inherited
|
|
219
|
+
* from ::backdrop. 60 puts it over the `@` mention list (30) and over the dialog, which is
|
|
220
|
+
* correct: a picture opened from inside a reply box should still open. */
|
|
221
|
+
.lightbox{position:fixed;inset:0;z-index:60;display:flex;
|
|
222
|
+
background:rgba(0,0,0,.82)}
|
|
223
|
+
/* The stage is inset rather than the whole window, and that is not decoration.
|
|
224
|
+
Most images here are screenshots *of this interface*, and one fitted edge to edge reads as
|
|
225
|
+
the app having navigated rather than as a picture of it. The margin of backdrop around it,
|
|
226
|
+
and the border on it, are the only things that say which you are looking at.
|
|
227
|
+
|
|
228
|
+
Fit and centring are arithmetic in the module rather than layout: the transform has to be
|
|
229
|
+
the single source of truth, or zooming fights the flexbox. The module measures this box, so
|
|
230
|
+
changing the inset here is all it takes to change what "fitted" means. */
|
|
231
|
+
.lightbox .lbstage{position:absolute;inset:46px 56px 52px;overflow:hidden}
|
|
232
|
+
.lightbox img{position:absolute;top:0;left:0;transform-origin:0 0;
|
|
233
|
+
max-width:none;max-height:none;border-radius:8px;
|
|
234
|
+
border:1px solid rgba(255,255,255,.14);
|
|
235
|
+
box-shadow:0 18px 50px rgba(0,0,0,.5);
|
|
236
|
+
cursor:zoom-in;user-select:none;-webkit-user-drag:none}
|
|
237
|
+
/* Zoomed past fitted it is being read, not looked at, so the frame comes off: a border and a
|
|
238
|
+
drop shadow in the middle of a diff you are inspecting is furniture in the way. */
|
|
239
|
+
.lightbox[data-zoomed="true"] img{border-radius:0;border-color:transparent;box-shadow:none}
|
|
240
|
+
.lightbox[data-zoomed="true"] img{cursor:grab}
|
|
241
|
+
.lightbox[data-zoomed="true"] img:active{cursor:grabbing}
|
|
242
|
+
|
|
243
|
+
.lightbox .lbx,.lightbox .lbctl{--ic:17px;
|
|
244
|
+
display:inline-flex;align-items:center;justify-content:center;
|
|
245
|
+
width:34px;height:34px;padding:0;border-radius:9px;
|
|
246
|
+
border:1px solid var(--line);background:var(--panel);color:var(--ink-dim);
|
|
247
|
+
cursor:pointer}
|
|
248
|
+
.lightbox .lbx{position:absolute;top:14px;right:16px;--ic:18px}
|
|
249
|
+
.lightbox .lbx:hover,.lightbox .lbctl:not(:disabled):hover{color:var(--ink);
|
|
250
|
+
border-color:var(--ink-faint)}
|
|
251
|
+
/* At a stop the button stays where it is and stops responding. Removing it would move the two
|
|
252
|
+
beside it, which reads as the control having changed rather than as a limit being reached. */
|
|
253
|
+
.lightbox .lbctl:disabled{opacity:.35;cursor:default}
|
|
254
|
+
|
|
255
|
+
/* Bottom right, which is the one corner nothing else uses: close is top right, the hint is top
|
|
256
|
+
centre and the caption is bottom centre. */
|
|
257
|
+
.lightbox .lbzoom{position:absolute;bottom:12px;right:16px;display:flex;gap:6px;align-items:center}
|
|
258
|
+
/* Wide enough for "1600%" so the group does not resize as the number grows, and tabular so the
|
|
259
|
+
digits do not shuffle while you hold the button down. */
|
|
260
|
+
.lightbox .lblevel{width:auto;min-width:60px;padding:0 9px;
|
|
261
|
+
font:12px var(--mono);font-variant-numeric:tabular-nums;
|
|
262
|
+
color:var(--ink-dim)}
|
|
263
|
+
|
|
264
|
+
/* Both of these are over the picture, so they are quiet and they do not take the pointer:
|
|
265
|
+
a click that lands on the caption still means "fit", not "nothing happened". */
|
|
266
|
+
.lightbox .lbhint,.lightbox .lbcap{position:absolute;left:0;right:0;margin:0;
|
|
267
|
+
pointer-events:none;text-align:center;
|
|
268
|
+
font:11.5px var(--sans);color:var(--ink-faint)}
|
|
269
|
+
.lightbox .lbhint{top:16px;padding:0 60px}
|
|
270
|
+
.lightbox .lbcap{bottom:19px;padding:0 200px;color:var(--ink-dim);font-size:12.5px;
|
|
271
|
+
white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
272
|
+
|
|
273
|
+
/* The page behind must not scroll under an overlay. A wheel event that misses the image
|
|
274
|
+
would otherwise scroll the document instead of doing nothing. */
|
|
275
|
+
body[data-lightbox] {overflow:hidden}
|
|
276
|
+
|
|
277
|
+
/* And the affordance on the document side: an image you can open should say so. */
|
|
278
|
+
.md img,img.zoomable{cursor:zoom-in}
|
|
279
|
+
|
|
280
|
+
/* ---------- a dialog for a whole task (sheet() in dialog.js) ---------- */
|
|
281
|
+
dialog.sheet{border:1px solid var(--border-strong);border-radius:var(--r-lg);background:var(--bg);
|
|
282
|
+
color:var(--ink);padding:0;width:min(860px,calc(100vw - 32px));max-height:calc(100vh - 48px);
|
|
283
|
+
box-shadow:var(--shadow-lg)}
|
|
284
|
+
dialog.sheet[open]{animation:dlgin .18s var(--ease)}
|
|
285
|
+
dialog.sheet::backdrop{background:rgba(0,0,0,.35);backdrop-filter:blur(8px)}
|
|
286
|
+
.sheetbody{padding:22px 24px 26px;overflow:auto;max-height:calc(100vh - 50px)}
|
|
287
|
+
.sheettitle{margin:0 0 14px;font:600 18px var(--sans);letter-spacing:-.02em}
|
|
288
|
+
.sheetloading{display:grid;place-items:center;min-height:260px}
|
|
289
|
+
.spinner{width:22px;height:22px;border-radius:50%;border:2px solid var(--line);border-top-color:var(--accent);
|
|
290
|
+
animation:spin .7s linear infinite}
|
|
291
|
+
@keyframes spin{to{transform:rotate(360deg)}}
|
|
@@ -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}
|
|
@@ -89,9 +91,17 @@
|
|
|
89
91
|
.editor{font:12.5px/1.7 var(--mono);min-height:340px;overflow:hidden;resize:none}
|
|
90
92
|
.editnote{margin:8px 0 0;font:11.5px var(--sans);color:var(--ink-faint)}
|
|
91
93
|
|
|
94
|
+
/* The path, then the controls, pushed to the far end. Editing these files is the whole point
|
|
95
|
+
of the Org screen, and the way in used to be a grey word in a row of grey words — which is
|
|
96
|
+
why "there is no easy way to edit the org docs" was fair about a screen that could. */
|
|
97
|
+
.filehead{margin-bottom:6px;gap:8px;align-items:center}
|
|
98
|
+
.filehead .meta{margin-right:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
99
|
+
.editbtn{gap:6px;--ic:13px}
|
|
100
|
+
|
|
92
101
|
/* A prompt audit finding. Not a tree row: it carries an explanation and two buttons, and
|
|
93
102
|
squeezing that into the navigator's row shape is how it would get ignored. */
|
|
94
|
-
.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)}
|
|
95
105
|
.prob .ptitle{font:600 12.5px var(--sans);color:var(--ink)}
|
|
96
106
|
.prob .pdetail{margin-top:3px;font:11.5px/1.5 var(--sans);color:var(--ink-faint)}
|
|
97
107
|
.prob.error{border-color:color-mix(in srgb,var(--err) 45%,transparent)}
|
|
@@ -103,4 +113,4 @@
|
|
|
103
113
|
/* What an edit did to the composed prompt, which is the question you were actually asking. */
|
|
104
114
|
.effect{border:1px solid color-mix(in srgb,var(--accent) 35%,transparent);
|
|
105
115
|
background:color-mix(in srgb,var(--accent) 7%,transparent);
|
|
106
|
-
border-radius:
|
|
116
|
+
border-radius:var(--r);padding:11px 13px;margin-bottom:14px}
|
|
@@ -1,27 +1,32 @@
|
|
|
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(--
|
|
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
|
-
.dhunk .tx{color:var(--
|
|
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)}
|
|
26
|
+
/* Pushed to the far end and kept faint: the diff is what this row is for, and a button that
|
|
27
|
+
competes with the filename for attention is one you stop reading past. */
|
|
28
|
+
.askfile{margin-left:auto;padding:1px 8px;font-size:11px;opacity:.55}
|
|
29
|
+
.dblock:hover .askfile,.askfile:focus-visible{opacity:1}
|
|
25
30
|
.dempty{padding:20px;color:var(--ink-faint);font-size:12.5px}
|
|
26
31
|
|
|
27
32
|
/* The learned/forgotten marker on a "what changed" row. */
|
|
@@ -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,25 +1,46 @@
|
|
|
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)}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
|
|
14
|
+
/* ---------- sections ----------
|
|
15
|
+
Doctor, the prompt audit and lint ask the same kind of question, and used to answer it in
|
|
16
|
+
three different shapes: hairline rows, bordered boxes, and cards with two buttons each. One
|
|
17
|
+
shape now. A heading carries its own count, so the page can be read by scanning the left
|
|
18
|
+
edge, and each section's own actions sit at its end rather than above its findings. */
|
|
19
|
+
.hsect{display:flex;align-items:baseline;gap:10px;
|
|
20
|
+
font:600 11px var(--sans);letter-spacing:.08em;text-transform:uppercase;
|
|
21
|
+
color:var(--ink-faint);margin:32px 0 0;padding-bottom:9px;
|
|
22
|
+
border-bottom:1px solid var(--line)}
|
|
23
|
+
.hsect i{margin-left:auto;font:11.5px var(--mono);font-style:normal;letter-spacing:0;
|
|
24
|
+
text-transform:none;color:var(--ink-faint)}
|
|
25
|
+
.hbody{padding-top:2px}
|
|
26
|
+
/* What the section is, in one line, before any of its findings. */
|
|
27
|
+
.hnote{margin:10px 0 0;font:12.5px/1.55 var(--sans);color:var(--ink-faint)}
|
|
28
|
+
.hacts{margin-top:12px}
|
|
29
|
+
.hacts:empty{margin-top:0}
|
|
30
|
+
/* Per-finding actions, in the text column rather than under the marker. */
|
|
31
|
+
.facts{margin-top:9px}
|
|
32
|
+
/* Two tags in a row read as one word without this: `too-longINDEX.md:49`. */
|
|
33
|
+
.hbody .check .meta + .meta{margin-left:8px}
|
|
13
34
|
|
|
14
35
|
/* ---------- the staff screen ---------- */
|
|
15
36
|
.staffcard .v small{margin-top:4px}
|
|
16
37
|
|
|
17
38
|
/* A plan, before anything happens. The two halves are deliberately equal in weight: "this is
|
|
18
39
|
what it keeps" is what somebody needs to believe before retiring anybody. */
|
|
19
|
-
.plan{border:1px solid var(--line);border-radius:
|
|
20
|
-
background:var(--panel)}
|
|
21
|
-
.plan h3{margin:0 0 10px;font:600 15px var(--sans)}
|
|
22
|
-
.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;
|
|
23
44
|
color:var(--ink-faint);margin:14px 0 7px}
|
|
24
45
|
.planhead:first-of-type{margin-top:0}
|
|
25
46
|
.planhead.keep{color:var(--accent)}
|
|
@@ -33,7 +54,7 @@
|
|
|
33
54
|
.planline.todo .ic{color:var(--warn)}
|
|
34
55
|
.planline.warn{color:var(--ink-faint)}
|
|
35
56
|
.planline.warn .ic{color:var(--warn)}
|
|
36
|
-
.planout{margin-top:14px;
|
|
57
|
+
.planout{margin-top:14px;font-size:11.5px}
|
|
37
58
|
|
|
38
59
|
.ffield{margin-bottom:10px}
|
|
39
60
|
.ffield label{display:block;font:600 11px var(--sans);letter-spacing:.05em;
|