create-pmos 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/package.json +1 -1
- package/payload/KIT-VERSION +1 -1
- package/workspace/README.md +44 -12
- package/workspace/design-parity.js +358 -0
- package/workspace/lib/find-browser.js +60 -0
- package/workspace/lib/four-panel.js +345 -0
- package/workspace/lib/git-info.js +28 -1
- package/workspace/lib/mobile-nav.js +32 -2
- package/workspace/package-lock.json +29 -2
- package/workspace/package.json +13 -5
- package/workspace/public/index.html +79 -409
- package/workspace/public/pm/app.js +242 -0
- package/workspace/public/pm/data.js +877 -0
- package/workspace/public/pm/dom.js +116 -0
- package/workspace/public/pm/fixture.js +979 -0
- package/workspace/public/pm/mobile.css +200 -0
- package/workspace/public/pm/mobile.js +403 -0
- package/workspace/public/pm/modes.js +1076 -0
- package/workspace/public/pm/panel-detail.js +648 -0
- package/workspace/public/pm/panel-initiatives.js +426 -0
- package/workspace/public/pm/panel-repos.js +460 -0
- package/workspace/public/pm/panel-tabs.js +487 -0
- package/workspace/public/pm/state.js +164 -0
- package/workspace/public/pm/tab-doc.js +279 -0
- package/workspace/public/pm/tab-task.js +83 -0
- package/workspace/public/pm/tab-term.js +560 -0
- package/workspace/public/pm/tokens.css +73 -0
- package/workspace/public/vendor/ibm-plex-mono-500.woff2 +0 -0
- package/workspace/server.js +158 -8
- package/workspace/focus.test.js +0 -650
- package/workspace/handoff.test.js +0 -443
- package/workspace/profiles.test.js +0 -362
- package/workspace/public/app.js +0 -5560
- package/workspace/public/styles.css +0 -2258
- package/workspace/repo-scan.test.js +0 -327
|
@@ -1,2258 +0,0 @@
|
|
|
1
|
-
/* PMOS Terminal Workspace — GUI client. D38 token layer.
|
|
2
|
-
────────────────────────────────────────────────────────────────────────────────────────────
|
|
3
|
-
The palette is the shadcn `radix-sera` style on the `mist` base colour, ported VERBATIM from
|
|
4
|
-
the sibling product's design system (its components.json + react-src/styles/app.css) so the
|
|
5
|
-
two surfaces read as one house. The port is CSS-only: the workspace stays a no-build local
|
|
6
|
-
companion app, so what comes across is the token layer + the component vocabulary, not React,
|
|
7
|
-
Tailwind or Radix.
|
|
8
|
-
Three things to know before editing:
|
|
9
|
-
1. --radius is 0. That is the style's signature, not an oversight. Everything derives from
|
|
10
|
-
it through the scale below, so re-rounding the whole app is a ONE-token change. Never
|
|
11
|
-
hardcode a px radius — the exceptions are 50% (dots) and 999px (pills/meters), which are
|
|
12
|
-
shapes rather than radii.
|
|
13
|
-
2. shadcn's --accent is a MUTED HOVER SURFACE, not a brand hue. The brand blue lives in
|
|
14
|
-
--primary (fills) and --brand (text/borders). Reaching for --accent to mean "blue" is the
|
|
15
|
-
one mistake this palette invites.
|
|
16
|
-
3. The --xt-* block must stay concrete hex/rgba: those values are read by xtheme() in app.js
|
|
17
|
-
and handed to xterm.js, whose colour parser does NOT understand oklch().
|
|
18
|
-
──────────────────────────────────────────────────────────────────────────────────────────── */
|
|
19
|
-
|
|
20
|
-
/* Vendored, not CDN-linked: this app has to render correctly with no network at all. */
|
|
21
|
-
@font-face{
|
|
22
|
-
font-family:"Space Grotesk Variable";
|
|
23
|
-
src:url("/vendor/space-grotesk-var.woff2") format("woff2-variations");
|
|
24
|
-
font-weight:300 700; font-style:normal; font-display:swap;
|
|
25
|
-
}
|
|
26
|
-
/* Plex Mono is the terminal's face, so `swap` would be wrong here: swapping the grid out from
|
|
27
|
-
under a live xterm re-flows every row mid-session. `block` holds a short invisible period and
|
|
28
|
-
then keeps the fallback forever if the face never arrives — and app.js re-measures on
|
|
29
|
-
document.fonts.ready either way, so the grid is correct in both outcomes.
|
|
30
|
-
Both weights are real files: xterm renders bold text, and a synthesised bold on a monospace
|
|
31
|
-
face is wider than the regular one, which breaks cell alignment. */
|
|
32
|
-
@font-face{
|
|
33
|
-
font-family:"IBM Plex Mono";
|
|
34
|
-
src:url("/vendor/ibm-plex-mono-400.woff2") format("woff2");
|
|
35
|
-
font-weight:400; font-style:normal; font-display:block;
|
|
36
|
-
}
|
|
37
|
-
@font-face{
|
|
38
|
-
font-family:"IBM Plex Mono";
|
|
39
|
-
src:url("/vendor/ibm-plex-mono-700.woff2") format("woff2");
|
|
40
|
-
font-weight:700; font-style:normal; font-display:block;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
:root{
|
|
44
|
-
/* ── shadcn radix-sera / mist — light ── */
|
|
45
|
-
--background:oklch(1 0 0);
|
|
46
|
-
--foreground:oklch(0.148 0.004 228.8);
|
|
47
|
-
--card:oklch(1 0 0);
|
|
48
|
-
--card-foreground:oklch(0.148 0.004 228.8);
|
|
49
|
-
--popover:oklch(1 0 0);
|
|
50
|
-
--popover-foreground:oklch(0.148 0.004 228.8);
|
|
51
|
-
--primary:oklch(0.488 0.243 264.376);
|
|
52
|
-
--primary-foreground:oklch(0.97 0.014 254.604);
|
|
53
|
-
--secondary:oklch(0.967 0.001 286.375);
|
|
54
|
-
--secondary-foreground:oklch(0.21 0.006 285.885);
|
|
55
|
-
--muted:oklch(0.963 0.002 197.1);
|
|
56
|
-
--muted-foreground:oklch(0.56 0.021 213.5);
|
|
57
|
-
--accent:oklch(0.963 0.002 197.1);
|
|
58
|
-
--accent-foreground:oklch(0.218 0.008 223.9);
|
|
59
|
-
--destructive:oklch(0.577 0.245 27.325);
|
|
60
|
-
--border:oklch(0.925 0.005 214.3);
|
|
61
|
-
--input:oklch(0.925 0.005 214.3);
|
|
62
|
-
--ring:oklch(0.723 0.014 214.4);
|
|
63
|
-
--sidebar:oklch(0.987 0.002 197.1);
|
|
64
|
-
--sidebar-foreground:oklch(0.148 0.004 228.8);
|
|
65
|
-
--sidebar-primary:oklch(0.546 0.245 262.881);
|
|
66
|
-
--sidebar-border:oklch(0.925 0.005 214.3);
|
|
67
|
-
|
|
68
|
-
/* --brand is the brand blue AS TEXT OR BORDER on the current surface. --primary is tuned to
|
|
69
|
-
be a filled background (it pairs with --primary-foreground), and in dark it is far too deep
|
|
70
|
-
to read as type — so the two are separate tokens rather than one reused in both roles. */
|
|
71
|
-
--brand:oklch(0.488 0.243 264.376);
|
|
72
|
-
--brand-wash:color-mix(in oklab, var(--brand) 7%, transparent);
|
|
73
|
-
|
|
74
|
-
/* Status hues. shadcn ships --destructive only; a workspace that reports agent state needs a
|
|
75
|
-
full set, so these are authored in the same oklch space to sit with the palette. Each is
|
|
76
|
-
picked to clear text contrast on THIS theme's surfaces — hence separate light/dark values
|
|
77
|
-
rather than one hue dimmed by opacity. */
|
|
78
|
-
--success:oklch(0.52 0.14 152);
|
|
79
|
-
--warning:oklch(0.55 0.12 72);
|
|
80
|
-
--info:oklch(0.52 0.09 195);
|
|
81
|
-
--purple:oklch(0.5 0.2 300);
|
|
82
|
-
--success-wash:color-mix(in oklab, var(--success) 10%, transparent);
|
|
83
|
-
--warning-wash:color-mix(in oklab, var(--warning) 10%, transparent);
|
|
84
|
-
--info-wash:color-mix(in oklab, var(--info) 10%, transparent);
|
|
85
|
-
--destructive-wash:color-mix(in oklab, var(--destructive) 8%, transparent);
|
|
86
|
-
|
|
87
|
-
--glass:color-mix(in oklab, var(--background) 80%, transparent);
|
|
88
|
-
--shadow:oklch(0.148 0.004 228.8 / 0.18);
|
|
89
|
-
--term-bg:oklch(0.148 0.004 228.8);
|
|
90
|
-
|
|
91
|
-
/* ── radius scale (shadcn) — derived, never hardcoded ── */
|
|
92
|
-
--radius:0rem;
|
|
93
|
-
--radius-sm:calc(var(--radius) * 0.6);
|
|
94
|
-
--radius-md:calc(var(--radius) * 0.8);
|
|
95
|
-
--radius-lg:var(--radius);
|
|
96
|
-
--radius-xl:calc(var(--radius) * 1.4);
|
|
97
|
-
|
|
98
|
-
/* ── motion vocabulary (shadcn): one house curve, three duration tiers ── */
|
|
99
|
-
--ease-emphasized:cubic-bezier(0.4, 0, 0.2, 1);
|
|
100
|
-
--duration-fast:150ms;
|
|
101
|
-
--duration-base:250ms;
|
|
102
|
-
--duration-slow:350ms;
|
|
103
|
-
|
|
104
|
-
/* ── type scale. The workspace used to label everything in 8.5–11px uppercase mono; that
|
|
105
|
-
density was the single loudest "dated terminal dashboard" signal. Chrome now speaks the
|
|
106
|
-
sans scale and mono is reserved for things that ARE code: the terminal, paths, branches,
|
|
107
|
-
diffs, code spans. ── */
|
|
108
|
-
--text-2xs:11px; --text-xs:12px; --text-sm:13px; --text-base:14px; --text-lg:16px;
|
|
109
|
-
/* Half-steps the design reference uses between those rungs. They are named for the ROLE they
|
|
110
|
-
play rather than continuing the t-shirt scale, because that is what they are: a fixed set of
|
|
111
|
-
jobs in the navigator and the detail panel, not a general-purpose ladder. Anything outside
|
|
112
|
-
those jobs should reach for a rung above, not add a step here. */
|
|
113
|
-
--text-label:9.5px; /* uppercase field labels — "evals", "sessions", "artifacts" */
|
|
114
|
-
--text-tiny:10px; /* section captions and stage keys */
|
|
115
|
-
--text-meta:10.5px; /* mono ids, counts, pills, badges */
|
|
116
|
-
--text-row:11.5px; /* the second line of a list row */
|
|
117
|
-
--text-body:12.5px; /* panel prose and session names */
|
|
118
|
-
--text-title:15px; /* the initiative name at the head of the detail panel */
|
|
119
|
-
--text-doc:21px; /* an <h1> inside a rendered document */
|
|
120
|
-
--mono:"IBM Plex Mono",ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
|
|
121
|
-
--sans:"Space Grotesk Variable",ui-sans-serif,system-ui,-apple-system,sans-serif;
|
|
122
|
-
|
|
123
|
-
/* layout knobs the JS adjusts (rail width, library/document split) */
|
|
124
|
-
--rail-w:400px;
|
|
125
|
-
|
|
126
|
-
/* xterm palette tokens — the single source for the JS terminal theme (xtheme()). Dark in BOTH
|
|
127
|
-
themes by design; the terminal is a terminal, not a themed surface. Concrete hex only (see
|
|
128
|
-
note 3 at the top of this file). */
|
|
129
|
-
--xt-bg:#090b0c; --xt-fg:#c4ccce; --xt-cursor:#47cf79; --xt-sel:rgba(43,127,255,.3);
|
|
130
|
-
--xt-black:#090b0c; --xt-red:#ff6467; --xt-green:#47cf79; --xt-yellow:#f4b93c;
|
|
131
|
-
--xt-blue:#2b7fff; --xt-magenta:#b48df4; --xt-cyan:#53d1d0; --xt-white:#d2d9db;
|
|
132
|
-
--xt-brblack:#6f7d81; --xt-brgreen:#81e8a0; --xt-accent-text:#2b7fff; --xt-brwhite:#f9fbfb;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/* ── shadcn radix-sera / mist — dark. This is the workspace's DEFAULT (index.html ships
|
|
136
|
-
data-theme="dark"); the light block above is the base the toggle falls back to. ── */
|
|
137
|
-
:root[data-theme="dark"]{
|
|
138
|
-
--background:oklch(0.148 0.004 228.8);
|
|
139
|
-
--foreground:oklch(0.987 0.002 197.1);
|
|
140
|
-
--card:oklch(0.218 0.008 223.9);
|
|
141
|
-
--card-foreground:oklch(0.987 0.002 197.1);
|
|
142
|
-
--popover:oklch(0.218 0.008 223.9);
|
|
143
|
-
--popover-foreground:oklch(0.987 0.002 197.1);
|
|
144
|
-
--primary:oklch(0.424 0.199 265.638);
|
|
145
|
-
--primary-foreground:oklch(0.97 0.014 254.604);
|
|
146
|
-
--secondary:oklch(0.274 0.006 286.033);
|
|
147
|
-
--secondary-foreground:oklch(0.985 0 0);
|
|
148
|
-
--muted:oklch(0.275 0.011 216.9);
|
|
149
|
-
--muted-foreground:oklch(0.723 0.014 214.4);
|
|
150
|
-
--accent:oklch(0.275 0.011 216.9);
|
|
151
|
-
--accent-foreground:oklch(0.987 0.002 197.1);
|
|
152
|
-
--destructive:oklch(0.704 0.191 22.216);
|
|
153
|
-
--border:oklch(1 0 0 / 10%);
|
|
154
|
-
--input:oklch(1 0 0 / 15%);
|
|
155
|
-
--ring:oklch(0.56 0.021 213.5);
|
|
156
|
-
--sidebar:oklch(0.218 0.008 223.9);
|
|
157
|
-
--sidebar-foreground:oklch(0.987 0.002 197.1);
|
|
158
|
-
--sidebar-primary:oklch(0.623 0.214 259.815);
|
|
159
|
-
--sidebar-border:oklch(1 0 0 / 10%);
|
|
160
|
-
|
|
161
|
-
--brand:oklch(0.623 0.214 259.815);
|
|
162
|
-
--brand-wash:color-mix(in oklab, var(--brand) 12%, transparent);
|
|
163
|
-
|
|
164
|
-
--success:oklch(0.76 0.17 152);
|
|
165
|
-
--warning:oklch(0.82 0.15 82);
|
|
166
|
-
--info:oklch(0.79 0.11 195);
|
|
167
|
-
--purple:oklch(0.72 0.15 300);
|
|
168
|
-
--success-wash:color-mix(in oklab, var(--success) 10%, transparent);
|
|
169
|
-
--warning-wash:color-mix(in oklab, var(--warning) 10%, transparent);
|
|
170
|
-
--info-wash:color-mix(in oklab, var(--info) 10%, transparent);
|
|
171
|
-
--destructive-wash:color-mix(in oklab, var(--destructive) 12%, transparent);
|
|
172
|
-
|
|
173
|
-
--glass:color-mix(in oklab, var(--background) 78%, transparent);
|
|
174
|
-
--shadow:oklch(0 0 0 / 0.6);
|
|
175
|
-
--term-bg:oklch(0.148 0.004 228.8);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
*{box-sizing:border-box;margin:0;padding:0}
|
|
179
|
-
html,body{height:100%}
|
|
180
|
-
body{background:var(--background); color:var(--foreground); font-family:var(--sans);
|
|
181
|
-
font-size:var(--text-sm); line-height:1.5; -webkit-font-smoothing:antialiased; overflow:hidden}
|
|
182
|
-
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
|
|
183
|
-
/* shadcn's focus ring: a soft halo in --ring rather than a hard outline */
|
|
184
|
-
:focus-visible{outline:2px solid var(--ring); outline-offset:2px; border-radius:var(--radius-sm)}
|
|
185
|
-
.mono{font-family:var(--mono)}
|
|
186
|
-
|
|
187
|
-
/* Motion, ported from the sibling design system: gentle fades and small lifts, no bounce. Every
|
|
188
|
-
one of these is neutralised by the reduced-motion guard at the bottom of this file. */
|
|
189
|
-
@keyframes motion-fade{from{opacity:0}to{opacity:1}}
|
|
190
|
-
@keyframes motion-rise{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
|
|
191
|
-
@keyframes motion-pop-in{from{opacity:0;transform:scale(.96)}to{opacity:1;transform:none}}
|
|
192
|
-
|
|
193
|
-
/* The rows are fixed and the middle row is minmax(0,1fr): without the 0 minimum a tall column
|
|
194
|
-
(a long needs strip, a long document) grows the row past the viewport and body{overflow:hidden}
|
|
195
|
-
silently clips the BOTTOM OF THE TERMINAL. Every nested column repeats the min-height:0. */
|
|
196
|
-
/* The COLUMN track is declared for the same reason the rows are. An implicit `auto` column sizes
|
|
197
|
-
to its widest child's min-content, so any pane that cannot shrink — a long branch chip, a deeply
|
|
198
|
-
indented navigator row — widens the whole shell and the status strip runs off the right edge of
|
|
199
|
-
a phone. minmax(0,…) makes the shell the authority on its own width. */
|
|
200
|
-
.app{display:grid; grid-template-columns:minmax(0,1fr); grid-template-rows:44px minmax(0,1fr) 28px;
|
|
201
|
-
height:100vh; height:100dvh}
|
|
202
|
-
|
|
203
|
-
/* ── top bar ── */
|
|
204
|
-
/* position+z-index so the header's own popover (the layout menu) paints ABOVE the body: the two
|
|
205
|
-
are grid siblings, and without this the later-in-DOM body wins the paint order and swallows
|
|
206
|
-
every click aimed at the menu. */
|
|
207
|
-
.bar{display:flex; align-items:center; gap:10px; padding:0 12px; min-width:0; position:relative; z-index:50;
|
|
208
|
-
border-bottom:1px solid var(--border); background:var(--glass); backdrop-filter:blur(8px)}
|
|
209
|
-
/* the product mark reads as a filled brand tile, the way a shadcn sidebar header does */
|
|
210
|
-
.mark{width:24px;height:24px;display:grid;place-items:center;border-radius:var(--radius-md);
|
|
211
|
-
background:var(--primary);color:var(--primary-foreground);font-size:var(--text-xs);font-weight:600}
|
|
212
|
-
.bar b{font-size:var(--text-base);font-weight:600;letter-spacing:-.01em}
|
|
213
|
-
.bar .sub{font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
214
|
-
.bar .conn{font-size:var(--text-xs);display:inline-flex;gap:6px;align-items:center;color:var(--muted-foreground)}
|
|
215
|
-
.bar .conn::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--muted-foreground)}
|
|
216
|
-
.bar .conn.live{color:var(--success)} .bar .conn.live::before{background:var(--success);animation:pulse 2.2s infinite}
|
|
217
|
-
.bar .conn.off{color:var(--warning)} .bar .conn.off::before{background:var(--warning)}
|
|
218
|
-
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
|
|
219
|
-
.bar .right{margin-left:auto;display:flex;gap:6px}
|
|
220
|
-
/* shadcn Button, `ghost` variant: no resting border or fill, the hover surface does the work */
|
|
221
|
-
.ibtn{min-height:32px;min-width:36px;padding:0 10px;display:grid;place-items:center;
|
|
222
|
-
border:1px solid transparent;background:transparent;border-radius:var(--radius-md);
|
|
223
|
-
color:var(--muted-foreground);font-size:var(--text-sm);font-weight:500;
|
|
224
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized),
|
|
225
|
-
color var(--duration-fast) var(--ease-emphasized)}
|
|
226
|
-
.ibtn:hover{background:var(--accent);color:var(--accent-foreground)}
|
|
227
|
-
.ibtn[aria-pressed="true"]{background:var(--accent);color:var(--brand)}
|
|
228
|
-
|
|
229
|
-
/* ── the arrangement (workspace-layout-system) ──────────────────────────────────────────────
|
|
230
|
-
The template is COMPUTED from the current layout by applyLayout() and written into these three
|
|
231
|
-
custom properties — never as a direct grid declaration. That is deliberate: an inline
|
|
232
|
-
`grid-template-columns` would outrank the ≤760px media query below and take the phone's
|
|
233
|
-
single-column switcher with it. Custom properties lose to a later direct declaration, so the
|
|
234
|
-
two responsive systems stay in charge of their own widths (R9). */
|
|
235
|
-
.body{display:grid; position:relative;
|
|
236
|
-
grid-template-columns:var(--lay-cols, 262px minmax(0,1fr) minmax(0,var(--rail-w)));
|
|
237
|
-
grid-template-rows:var(--lay-rows, minmax(0,1fr));
|
|
238
|
-
grid-template-areas:var(--lay-areas, "side term read");
|
|
239
|
-
min-height:0}
|
|
240
|
-
.side{grid-area:side} .term-col{grid-area:term} .rail{grid-area:read}
|
|
241
|
-
.body[data-side="off"]>.side{display:none}
|
|
242
|
-
|
|
243
|
-
/* ── collapsed column rails ────────────────────────────────────────────────────────────────
|
|
244
|
-
Collapsing is NOT the same verb as the layout system's `off`. `off` removes a column's track
|
|
245
|
-
entirely and is reached from the layout menu; collapse keeps the track at 36px and leaves a
|
|
246
|
-
labelled edge you click to get back. The distinction matters because the label is what makes
|
|
247
|
-
the column recoverable without opening a menu — a pane that vanishes with no visible way back
|
|
248
|
-
is the failure the layout engine's hasEscape() exists to prevent, and a collapse control has
|
|
249
|
-
to hold to the same standard. The rail is a real <button>, so it is tabbable and screen
|
|
250
|
-
readers announce it; the rotated text is decoration over an aria-label, never the only name. */
|
|
251
|
-
/* MUST come before the `display:flex` below, and must exist at all: a rule that sets `display`
|
|
252
|
-
silently defeats the UA's `[hidden]{display:none}`, so both rails stayed in the grid as extra
|
|
253
|
-
implicit columns and pushed the app 405px wider than the viewport at 1024px. */
|
|
254
|
-
.colrail[hidden]{display:none}
|
|
255
|
-
.colrail{grid-row:1;background:var(--sidebar);border-right:1px solid var(--border);
|
|
256
|
-
display:flex;justify-content:center;padding-top:14px;min-width:0;
|
|
257
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
258
|
-
.colrail:hover{background:var(--accent)}
|
|
259
|
-
.colrail>span{writing-mode:vertical-rl;font-size:var(--text-2xs);letter-spacing:.1em;
|
|
260
|
-
color:var(--muted-foreground);font-family:var(--mono);white-space:nowrap}
|
|
261
|
-
#col1Rail{grid-area:side} #col2Rail{grid-area:read}
|
|
262
|
-
.body[data-col1="closed"]>.side,.body[data-col2="closed"]>.rail{display:none}
|
|
263
|
-
/* the resize grips belong to an expanded column; a 36px rail has nothing to resize */
|
|
264
|
-
.body[data-col1="closed"] #sideEdge,.body[data-col2="closed"] .railgrip{display:none}
|
|
265
|
-
.body[data-side="right"]>.side{border-right:0;border-left:1px solid var(--border)}
|
|
266
|
-
/* the panel sits between the structure column and the terminal, so its own edge is the LEFT one */
|
|
267
|
-
.rail{border-left:0;border-right:1px solid var(--border)}
|
|
268
|
-
.railgrip{left:auto;right:-3px}
|
|
269
|
-
|
|
270
|
-
/* ── left column: the workspace — repos over running agents. Both panes fold and the column
|
|
271
|
-
resizes, which is the parity the rail always had and this one never did (R11). ── */
|
|
272
|
-
.side{border-right:1px solid var(--border);background:var(--sidebar);min-height:0;
|
|
273
|
-
display:flex;flex-direction:column;position:relative}
|
|
274
|
-
.side>.pane{flex:1 1 0}
|
|
275
|
-
.side>.pane[data-fold="off"]{flex:0 0 auto}
|
|
276
|
-
.side>.pane+.pane{border-top:1px solid var(--border)}
|
|
277
|
-
.pane{display:flex;flex-direction:column;min-height:0;min-width:0}
|
|
278
|
-
.pane-body{overflow-y:auto;overscroll-behavior:contain;flex:1;min-height:0;padding-bottom:10px}
|
|
279
|
-
.pane[data-fold="off"]>.pane-body{display:none}
|
|
280
|
-
.pane[data-fold="off"]{flex:0 0 auto}
|
|
281
|
-
|
|
282
|
-
/* Pane header = shadcn's SidebarGroupLabel: 12px medium in muted-foreground, sentence case. The
|
|
283
|
-
uppercase-tracked-mono caption this replaced was the loudest dated signal in the whole app. */
|
|
284
|
-
.cap{font-size:var(--text-xs);font-weight:500;
|
|
285
|
-
color:var(--muted-foreground);padding:10px 10px 8px 12px;display:flex;gap:8px;align-items:center;
|
|
286
|
-
min-height:38px;flex:none;background:var(--sidebar);border-bottom:1px solid var(--border)}
|
|
287
|
-
.cap .ct{color:var(--warning);font-size:var(--text-xs);font-weight:500}
|
|
288
|
-
.cap .mini{margin-left:auto;width:26px;height:26px;display:grid;place-items:center;border-radius:var(--radius-sm);
|
|
289
|
-
border:0;background:transparent;color:var(--muted-foreground);font-size:var(--text-base);
|
|
290
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized),
|
|
291
|
-
color var(--duration-fast) var(--ease-emphasized)}
|
|
292
|
-
.cap .mini:hover{background:var(--accent);color:var(--accent-foreground)}
|
|
293
|
-
/* a pane header that folds its body away */
|
|
294
|
-
.cap .fold{display:inline-flex;align-items:center;gap:6px;font:inherit;color:var(--muted-foreground)}
|
|
295
|
-
.cap .fold:hover{color:var(--foreground)}
|
|
296
|
-
.cap .fold .chev{font-size:var(--text-2xs);transition:transform var(--duration-fast) var(--ease-emphasized)}
|
|
297
|
-
.pane[data-fold="off"] .cap .fold .chev{transform:rotate(-90deg)}
|
|
298
|
-
@media (prefers-reduced-motion:reduce){.cap .fold .chev{transition:none}}
|
|
299
|
-
/* the move affordance every relocatable pane carries. Keyboard reaches every position it offers
|
|
300
|
-
through the layout menu's position controls (`.lay-pos`), so this is an accelerator and never
|
|
301
|
-
the only path (R12). That was asserted here before it was true — the menu had no position
|
|
302
|
-
controls at all, and `side:right` / `reader:bottom` were pointer-only. Review-Gate finding. */
|
|
303
|
-
.cap .grip{width:22px;min-height:26px;display:grid;place-items:center;border-radius:var(--radius-sm);flex:none;
|
|
304
|
-
color:var(--muted-foreground);cursor:grab;letter-spacing:-2px;margin-left:-4px;touch-action:none}
|
|
305
|
-
.cap .grip:hover{background:var(--accent);color:var(--brand)}
|
|
306
|
-
.cap .grip:active{cursor:grabbing}
|
|
307
|
-
|
|
308
|
-
/* a column's outer edge, dragged to resize. The rail's original .railgrip is one of these. */
|
|
309
|
-
.edge{position:absolute;top:0;bottom:0;width:7px;z-index:20;cursor:col-resize;touch-action:none}
|
|
310
|
-
.edge:hover,.edge.on{background:linear-gradient(90deg,transparent,var(--ring),transparent)}
|
|
311
|
-
.side>.edge{right:-3px}
|
|
312
|
-
.body[data-side="right"]>.side>.edge{right:auto;left:-3px}
|
|
313
|
-
|
|
314
|
-
/* drop targets — visible only while a grip is being dragged */
|
|
315
|
-
.drop{position:absolute;inset:0;z-index:40;display:none;grid-area:1/1/-1/-1}
|
|
316
|
-
.body.dragging>.drop{display:block}
|
|
317
|
-
.dz{position:absolute;border:1px dashed var(--input);border-radius:var(--radius-lg);
|
|
318
|
-
background:var(--brand-wash);display:grid;place-items:center;
|
|
319
|
-
font-size:var(--text-sm);font-weight:500;color:var(--muted-foreground)}
|
|
320
|
-
.dz.hot{border-style:solid;border-color:var(--brand);color:var(--brand);
|
|
321
|
-
background:var(--accent);box-shadow:0 0 0 1px var(--ring)}
|
|
322
|
-
.dz[data-z="left"]{left:8px;top:8px;bottom:8px;width:22%}
|
|
323
|
-
.dz[data-z="right"]{right:8px;top:8px;bottom:8px;width:22%}
|
|
324
|
-
.dz[data-z="bottom"]{left:26%;right:26%;bottom:8px;height:30%}
|
|
325
|
-
.dz[data-z="off"]{left:26%;right:26%;top:8px;height:20%}
|
|
326
|
-
.dz.no{display:none}
|
|
327
|
-
.laghost{position:fixed;z-index:70;pointer-events:none;padding:5px 10px;border-radius:var(--radius-md);
|
|
328
|
-
background:var(--popover);border:1px solid var(--border);color:var(--foreground);
|
|
329
|
-
font-size:var(--text-xs);box-shadow:0 8px 24px -8px var(--shadow)}
|
|
330
|
-
|
|
331
|
-
/* ── the layout control ── */
|
|
332
|
-
.ibtn.lay-chip{gap:7px;display:inline-flex;align-items:center;padding:0 11px}
|
|
333
|
-
.ibtn.lay-chip i{font-style:normal;color:var(--muted-foreground);font-size:var(--text-xs)}
|
|
334
|
-
.ibtn.lay-chip[aria-expanded="true"]{background:var(--accent);color:var(--accent-foreground)}
|
|
335
|
-
/* shadcn Popover: --popover surface, hairline border, one soft elevation shadow */
|
|
336
|
-
.lay-menu{position:absolute;top:40px;right:12px;z-index:60;width:272px;background:var(--popover);
|
|
337
|
-
color:var(--popover-foreground);border:1px solid var(--border);border-radius:var(--radius-lg);padding:6px;
|
|
338
|
-
box-shadow:0 10px 38px -10px var(--shadow);animation:motion-pop-in var(--duration-fast) var(--ease-emphasized)}
|
|
339
|
-
.lay-cap{font-size:var(--text-xs);font-weight:500;color:var(--muted-foreground);margin:4px 8px 6px}
|
|
340
|
-
/* shadcn DropdownMenuItem */
|
|
341
|
-
.lay-row{display:flex;align-items:center;gap:8px;width:100%;padding:6px 8px;border-radius:var(--radius-sm);
|
|
342
|
-
font-size:var(--text-sm);color:var(--popover-foreground);text-align:left;min-height:36px;
|
|
343
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
344
|
-
.lay-row:hover{background:var(--accent);color:var(--accent-foreground)}
|
|
345
|
-
.lay-row[aria-current="true"]{background:var(--accent);color:var(--brand);font-weight:500}
|
|
346
|
-
.lay-row .nm{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
347
|
-
/* a keyboard hint reads as a key — mono is right here, it IS a literal keystroke */
|
|
348
|
-
.lay-row .kbd{font-family:var(--mono);font-size:var(--text-2xs);color:var(--muted-foreground);
|
|
349
|
-
background:var(--muted);border-radius:var(--radius-sm);padding:1px 5px;flex:none}
|
|
350
|
-
/* a wireframe of the arrangement — the name alone does not say what you get */
|
|
351
|
-
.lay-mini{width:28px;height:18px;border:1px solid var(--input);border-radius:var(--radius-sm);
|
|
352
|
-
display:flex;gap:1px;padding:1px;flex:none;background:var(--background)}
|
|
353
|
-
.lay-mini span{background:var(--input);border-radius:var(--radius-sm)}
|
|
354
|
-
.lay-row[aria-current="true"] .lay-mini span{background:var(--brand)}
|
|
355
|
-
.lay-act{display:flex;align-items:center;justify-content:center;min-width:26px;min-height:26px;
|
|
356
|
-
border-radius:var(--radius-sm);color:var(--muted-foreground);font-size:var(--text-xs);flex:none}
|
|
357
|
-
.lay-act:hover{background:var(--secondary);color:var(--brand)}
|
|
358
|
-
.lay-act.del:hover{color:var(--destructive)}
|
|
359
|
-
|
|
360
|
-
/* R12 — the position controls. Every value the pointer drag can produce is a focusable button
|
|
361
|
-
here, which is what makes "the layout control can always bring a pane back" a fact about the
|
|
362
|
-
DOM rather than an argument about the grid template. */
|
|
363
|
-
.lay-pos{margin-top:6px;padding-top:6px;border-top:1px solid var(--border);display:grid;gap:4px}
|
|
364
|
-
.pos-row{display:flex;align-items:center;gap:3px}
|
|
365
|
-
.pos-lbl{font-size:var(--text-2xs);color:var(--muted-foreground);width:52px;flex:none}
|
|
366
|
-
.pos-btn{flex:1;min-height:34px;display:flex;flex-direction:column;align-items:center;justify-content:center;
|
|
367
|
-
gap:1px;border-radius:var(--radius-sm);border:1px solid transparent;color:var(--muted-foreground);
|
|
368
|
-
font-size:var(--text-2xs);line-height:1}
|
|
369
|
-
.pos-btn i{font-style:normal;font-size:var(--text-sm)}
|
|
370
|
-
.pos-btn:hover{background:var(--accent);color:var(--accent-foreground)}
|
|
371
|
-
.pos-btn:focus-visible{outline:2px solid var(--ring);outline-offset:1px}
|
|
372
|
-
.pos-btn[aria-pressed="true"]{background:var(--accent);color:var(--brand);border-color:var(--ring);font-weight:500}
|
|
373
|
-
/* a coarse pointer gets the 44px target R12 asks for; a mouse does not need the extra height */
|
|
374
|
-
@media (pointer:coarse){.pos-btn{min-height:44px}.lay-act{min-width:44px;min-height:44px}.lay-row{padding:11px 8px}}
|
|
375
|
-
.lay-add{display:block;width:100%;margin-top:4px;padding:9px;border:1px dashed var(--border);
|
|
376
|
-
border-radius:var(--radius-md);font-size:var(--text-sm);color:var(--muted-foreground);
|
|
377
|
-
transition:color var(--duration-fast) var(--ease-emphasized),
|
|
378
|
-
border-color var(--duration-fast) var(--ease-emphasized)}
|
|
379
|
-
.lay-add:hover{color:var(--foreground);border-color:var(--ring)}
|
|
380
|
-
.lay-new{padding:6px 5px 2px}
|
|
381
|
-
.lay-foot{font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.55;
|
|
382
|
-
margin:9px 8px 4px;padding-top:8px;border-top:1px solid var(--border)}
|
|
383
|
-
.lay-foot b{color:var(--foreground);font-weight:500}
|
|
384
|
-
|
|
385
|
-
/* workspaces — one server, many repos; the row carries the switch + a forget affordance.
|
|
386
|
-
The row is shadcn's SidebarMenuButton: no border, the --accent surface carries state. */
|
|
387
|
-
.wsrow{display:flex;align-items:stretch}
|
|
388
|
-
.ws{display:flex;align-items:center;gap:8px;flex:1;min-width:0;text-align:left;min-height:40px;padding:0 8px 0 12px;
|
|
389
|
-
font-size:var(--text-sm);color:var(--sidebar-foreground);border-left:2px solid transparent;
|
|
390
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
391
|
-
.ws:hover{background:var(--accent)}
|
|
392
|
-
.ws[aria-current="true"]{border-left-color:var(--brand);background:var(--accent);font-weight:500}
|
|
393
|
-
.ws .cue{color:var(--muted-foreground);font-size:var(--text-2xs);flex:none}
|
|
394
|
-
/* the repo NAME is a path fragment — mono earns its place here */
|
|
395
|
-
.ws .nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--mono);font-size:var(--text-xs)}
|
|
396
|
-
/* shadcn Badge, `outline` variant */
|
|
397
|
-
.ws .tag{font-size:var(--text-2xs);font-weight:500;color:var(--muted-foreground);
|
|
398
|
-
border:1px solid var(--border);border-radius:var(--radius-sm);padding:1px 6px;flex:none}
|
|
399
|
-
.ws small{margin-left:auto;font-size:var(--text-2xs);font-weight:500;color:var(--success);flex:none}
|
|
400
|
-
.wsrow .forget{width:30px;display:grid;place-items:center;color:var(--muted-foreground);font-size:var(--text-xs);opacity:0}
|
|
401
|
-
.wsrow:hover .forget,.wsrow .forget:focus-visible{opacity:1}
|
|
402
|
-
.wsrow .forget:hover{color:var(--destructive)}
|
|
403
|
-
|
|
404
|
-
/* one line, always: at 13px the full label wraps inside a 262px sidebar and the dashed box grows
|
|
405
|
-
into a two-line slab. It ellipsizes instead — the + and the first words carry the meaning. */
|
|
406
|
-
/* `display:flex` beats the UA's `[hidden]{display:none}`, so hiding this from JS silently did
|
|
407
|
-
nothing — the composer stayed on screen in every mode. Any rule that sets `display` on an
|
|
408
|
-
element the code also hides has to opt back into it explicitly. */
|
|
409
|
-
.newsess[hidden]{display:none}
|
|
410
|
-
.newsess{display:flex;gap:8px;align-items:center;margin:10px 12px 4px;min-height:38px;padding:0 12px;
|
|
411
|
-
border:1px dashed var(--border);border-radius:var(--radius-md);font-size:var(--text-xs);
|
|
412
|
-
color:var(--muted-foreground);width:calc(100% - 24px);
|
|
413
|
-
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
|
|
414
|
-
transition:color var(--duration-fast) var(--ease-emphasized),
|
|
415
|
-
border-color var(--duration-fast) var(--ease-emphasized)}
|
|
416
|
-
.newsess:hover{color:var(--foreground);border-color:var(--ring)}
|
|
417
|
-
.newsess i{font-style:normal}
|
|
418
|
-
|
|
419
|
-
/* ── inline forms: name a session before it starts · add a repo by picking a folder.
|
|
420
|
-
These are the shadcn Field/Label/Input/Button primitives: a 13px medium label above a
|
|
421
|
-
36px input with a hairline --input border, and a filled primary + ghost cancel below. ── */
|
|
422
|
-
.miniform{margin:8px 12px 6px;display:flex;flex-direction:column;gap:8px}
|
|
423
|
-
.miniform[hidden]{display:none}
|
|
424
|
-
.miniform .lbl{font-size:var(--text-sm);font-weight:500;color:var(--foreground)}
|
|
425
|
-
.miniform input{min-height:36px;padding:0 12px;border:1px solid var(--input);border-radius:var(--radius-md);
|
|
426
|
-
background:transparent;color:var(--foreground);font-family:var(--sans);font-size:var(--text-sm);
|
|
427
|
-
outline:none;width:100%;
|
|
428
|
-
transition:border-color var(--duration-fast) var(--ease-emphasized),
|
|
429
|
-
box-shadow var(--duration-fast) var(--ease-emphasized)}
|
|
430
|
-
.miniform input::placeholder{color:var(--muted-foreground)}
|
|
431
|
-
.miniform input:focus{border-color:var(--ring);box-shadow:0 0 0 3px var(--brand-wash)}
|
|
432
|
-
.miniform .row{display:flex;gap:8px}
|
|
433
|
-
/* Button, `default` variant — a filled brand action, not an outlined one */
|
|
434
|
-
.miniform button{min-height:36px;padding:0 14px;border:1px solid transparent;border-radius:var(--radius-md);
|
|
435
|
-
background:var(--primary);font-size:var(--text-sm);font-weight:500;color:var(--primary-foreground);
|
|
436
|
-
transition:opacity var(--duration-fast) var(--ease-emphasized),
|
|
437
|
-
background-color var(--duration-fast) var(--ease-emphasized)}
|
|
438
|
-
.miniform button:hover{opacity:.9}
|
|
439
|
-
/* `ghost` variant — the dismissive half of a pair never competes with the primary */
|
|
440
|
-
.miniform button.quiet{background:transparent;color:var(--muted-foreground)}
|
|
441
|
-
.miniform button.quiet:hover{background:var(--accent);color:var(--accent-foreground);opacity:1}
|
|
442
|
-
/* the primary way to add a repo: the machine's own folder chooser, not a typed path. `outline`
|
|
443
|
-
variant so it reads as a distinct choice rather than a second submit. */
|
|
444
|
-
.miniform .pick{min-height:40px;background:transparent;border-color:var(--input);
|
|
445
|
-
color:var(--foreground);font-size:var(--text-sm);display:flex;align-items:center;justify-content:center;gap:8px}
|
|
446
|
-
.miniform .pick:hover{background:var(--accent);opacity:1}
|
|
447
|
-
.miniform .hint{font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.5}
|
|
448
|
-
.miniform .hint code{font-family:var(--mono);font-size:var(--text-2xs);background:var(--muted);
|
|
449
|
-
padding:1px 5px;border-radius:var(--radius-sm);color:var(--foreground)}
|
|
450
|
-
/* shadcn ToggleGroup: one inset track, the selected item lifts onto the --background surface */
|
|
451
|
-
.seg{display:flex;gap:2px;border:1px solid var(--border);border-radius:var(--radius-md);
|
|
452
|
-
background:var(--muted);padding:2px}
|
|
453
|
-
.seg button{flex:1;min-height:30px;border:0;border-radius:var(--radius-sm);background:transparent;
|
|
454
|
-
color:var(--muted-foreground);font-size:var(--text-sm);font-weight:500;padding:0;
|
|
455
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized),
|
|
456
|
-
color var(--duration-fast) var(--ease-emphasized)}
|
|
457
|
-
.seg button:hover{color:var(--foreground)}
|
|
458
|
-
.seg button[aria-checked="true"]{background:var(--background);color:var(--foreground);
|
|
459
|
-
box-shadow:0 1px 2px var(--shadow)}
|
|
460
|
-
|
|
461
|
-
/* ── running agents ── */
|
|
462
|
-
.sessrow{display:flex;align-items:stretch;position:relative}
|
|
463
|
-
.sess{display:block;flex:1;min-width:0;text-align:left;padding:7px 4px 7px 11px;
|
|
464
|
-
border-left:3px solid transparent;min-height:44px}
|
|
465
|
-
.sess:hover,.sessrow:hover .sess{background:var(--accent)}
|
|
466
|
-
.sess[aria-current="true"]{background:var(--accent);border-left-color:var(--brand)}
|
|
467
|
-
.sessrow:has(.sess[aria-current="true"]){background:var(--accent)}
|
|
468
|
-
.sess .r1{display:flex;align-items:center;gap:7px}
|
|
469
|
-
.sess .st{width:11px;text-align:center;font-size:var(--text-xs);flex:none}
|
|
470
|
-
.sess[data-state="working"] .st{color:var(--success);animation:pulse 2.2s infinite}
|
|
471
|
-
/* The five presented states take five distinct hues, because R8 requires hue to carry the state
|
|
472
|
-
on its own (as shape and word each do). green working · yellow quiet · blue NEEDS YOU ·
|
|
473
|
-
red MAYBE BLOCKED · grey exited. `needs` takes the BRAND hue rather than a danger one: a
|
|
474
|
-
finished turn is an invitation, not a failure, and red is reserved for the state that may be a
|
|
475
|
-
problem. (It read `--accent` before the shadcn port; under that palette --accent is the muted
|
|
476
|
-
hover SURFACE, so the brand hue is now --brand. Same intent, correct token.)
|
|
477
|
-
`blocked` was styled --warn while it was dead code; it is defined for real now, and must not
|
|
478
|
-
share `quiet`'s hue — a weak claim that looks exactly like no claim communicates nothing. */
|
|
479
|
-
.sess[data-state="needs"] .st{color:var(--brand)}
|
|
480
|
-
.sess[data-state="blocked"] .st{color:var(--destructive)}
|
|
481
|
-
.sess[data-state="done"] .st{color:var(--info)}
|
|
482
|
-
.sess[data-state="idle"] .st,.sess[data-state="exited"] .st{color:var(--muted-foreground)}
|
|
483
|
-
@media (prefers-reduced-motion:reduce){.sess .st,.bar .conn.live::before{animation:none!important}}
|
|
484
|
-
.sess .nm{font-size:var(--text-sm);font-weight:500;color:var(--foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
485
|
-
.sess .sub{font-size:var(--text-xs);color:var(--muted-foreground);margin:2px 0 0 18px;display:block;
|
|
486
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
487
|
-
.sess[data-state="needs"] .sub{color:var(--brand)}
|
|
488
|
-
.sess[data-state="blocked"] .sub{color:var(--destructive)}
|
|
489
|
-
/* "opening focus" — the permanent lead label on the run-title sub-line. It states plainly that the
|
|
490
|
-
title is the run's FIRST prompt (frozen, no timestamp), never its current activity. */
|
|
491
|
-
.sess .sub .lead{font-size:var(--text-2xs);font-weight:500;color:var(--muted-foreground);margin-right:6px}
|
|
492
|
-
/* ── harness tower (workspace-harness-tower): the state chip, the agent's own last words,
|
|
493
|
-
and the per-session harness drill-in. State is carried by SHAPE (the glyph), HUE, and the
|
|
494
|
-
WORD in the chip — three channels, so nothing depends on colour alone. ── */
|
|
495
|
-
.sess[data-state="quiet"] .st{color:var(--warning)}
|
|
496
|
-
/* shadcn Badge, `secondary` variant — the state WORD, one of the three channels state travels on */
|
|
497
|
-
.sess .chip{margin-left:auto;flex:none;font-size:var(--text-2xs);font-weight:500;
|
|
498
|
-
color:var(--muted-foreground);white-space:nowrap;background:var(--muted);
|
|
499
|
-
border-radius:var(--radius-sm);padding:2px 7px}
|
|
500
|
-
.sess[data-state="working"] .chip{color:var(--success)}
|
|
501
|
-
.sess[data-state="quiet"] .chip{color:var(--warning)}
|
|
502
|
-
.sess[data-state="needs"] .chip{color:var(--brand)}
|
|
503
|
-
.sess[data-state="blocked"] .chip{color:var(--destructive)}
|
|
504
|
-
.sess[data-state="exited"] .chip{color:var(--muted-foreground)}
|
|
505
|
-
/* the last words WRAP — bounded to two lines here, in full in the terminal. The shipped .sub
|
|
506
|
-
stays nowrap; this is a separate line, so nothing existing changes shape. */
|
|
507
|
-
.sess .says{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
|
|
508
|
-
margin:4px 0 0 18px;font-size:var(--text-xs);line-height:1.5;color:var(--muted-foreground)}
|
|
509
|
-
.sess .says.na{color:var(--muted-foreground);font-style:italic}
|
|
510
|
-
.sess[aria-current="true"] .says{color:var(--foreground)}
|
|
511
|
-
|
|
512
|
-
details.hz{margin:0 8px 4px 14px}
|
|
513
|
-
details.hz>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:6px;
|
|
514
|
-
min-height:44px;font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
515
|
-
details.hz>summary::-webkit-details-marker{display:none}
|
|
516
|
-
details.hz>summary::before{content:"▸";font-size:var(--text-2xs)}
|
|
517
|
-
details.hz[open]>summary::before{content:"▾"}
|
|
518
|
-
details.hz>summary:hover{color:var(--foreground)}
|
|
519
|
-
details.hz .sr{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%)}
|
|
520
|
-
details.hz .kv{display:grid;grid-template-columns:72px minmax(0,1fr);gap:6px 10px;padding:0 0 10px 15px}
|
|
521
|
-
details.hz .kv dt{font-size:var(--text-xs);color:var(--muted-foreground);padding-top:1px}
|
|
522
|
-
details.hz .kv dd{font-size:var(--text-xs);line-height:1.5;color:var(--foreground);min-width:0;overflow-wrap:anywhere}
|
|
523
|
-
details.hz .kv dd b{color:var(--foreground);font-weight:500}
|
|
524
|
-
/* an unavailable fact is DRAWN as unavailable — never as a plausible constant */
|
|
525
|
-
details.hz .kv dd.na{color:var(--muted-foreground);font-style:italic}
|
|
526
|
-
details.hz .kv dd.na::before{content:"— ";font-style:normal}
|
|
527
|
-
details.hz .kv .src{font-family:var(--mono);font-size:var(--text-2xs);color:var(--muted-foreground)}
|
|
528
|
-
|
|
529
|
-
/* rename affordance — the name is a guess at creation; it must stay editable (R11) */
|
|
530
|
-
.sessrow .ren{width:30px;flex:none;display:grid;place-items:center;color:var(--muted-foreground);font-size:var(--text-xs);opacity:0}
|
|
531
|
-
.sessrow:hover .ren,.sessrow .ren:focus-visible{opacity:1}
|
|
532
|
-
.sessrow .ren:hover{color:var(--brand)}
|
|
533
|
-
.renbox{width:100%;min-height:44px;padding:0 10px;border:1px solid var(--brand);border-radius:var(--radius-md);
|
|
534
|
-
background:var(--secondary);color:var(--foreground);font-family:var(--mono);font-size:var(--text-xs);outline:none}
|
|
535
|
-
.sessrow .renbox{margin:0 8px}
|
|
536
|
-
|
|
537
|
-
/* ── terminal column ── */
|
|
538
|
-
.term-col{display:flex;flex-direction:column;min-width:0;min-height:0;background:var(--term-bg)}
|
|
539
|
-
/* Terminal GROUPS (R6): one by default, two side by side when the layout says split. Each group
|
|
540
|
-
owns a tab strip and a host; the #needs strip and the scratchpad stay with the column. */
|
|
541
|
-
/* Third rule in this file to need an explicit [hidden] because it sets `display` — the UA's
|
|
542
|
-
`[hidden]{display:none}` loses to any author display declaration, so hiding this from JS was
|
|
543
|
-
silently a no-op and the viewer opened UNDER a full-height terminal box. */
|
|
544
|
-
/* When a viewer tab is active the groups box collapses to just its tab strips: the terminals are
|
|
545
|
-
covered, never unmounted, so scrollback and PTYs survive, and the strip that got you here stays
|
|
546
|
-
on screen. A viewer that hides the strip hides its own way back. */
|
|
547
|
-
.groups[data-viewer="on"]{flex:none}
|
|
548
|
-
.groups[data-viewer="on"] .termhost{display:none}
|
|
549
|
-
.groups{flex:1;min-height:0;min-width:0;display:flex;flex-direction:row}
|
|
550
|
-
.group{flex:1 1 0;min-width:0;min-height:0;display:flex;flex-direction:column;background:var(--term-bg)}
|
|
551
|
-
.group[hidden]{display:none}
|
|
552
|
-
.group+.group{border-left:1px solid var(--border)}
|
|
553
|
-
.group[data-focus="true"] .stabs{box-shadow:inset 0 2px 0 var(--brand)}
|
|
554
|
-
.groups[data-split="off"] .group[data-focus="true"] .stabs{box-shadow:none}
|
|
555
|
-
.stabs{display:flex;gap:2px;padding:6px 8px 0;background:var(--muted);flex:none;
|
|
556
|
-
border-bottom:1px solid var(--border);overflow-x:auto;min-height:44px;align-items:flex-end}
|
|
557
|
-
/* tab = wrap of two SIBLING buttons (select + close) — valid interactive structure */
|
|
558
|
-
.stab-wrap{flex:none;display:inline-flex;align-items:center;gap:0;
|
|
559
|
-
border:1px solid transparent;border-bottom:0;border-radius:var(--radius-md) var(--radius-md) 0 0}
|
|
560
|
-
.stab-wrap[data-active="true"]{background:var(--term-bg);border-color:var(--border)}
|
|
561
|
-
.stab{display:inline-flex;align-items:center;gap:7px;min-height:38px;padding:0 6px 0 12px;
|
|
562
|
-
font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
563
|
-
/* The ACTIVE tab is painted in --term-bg so it reads as continuous with the terminal below it —
|
|
564
|
-
and --term-bg is dark in BOTH themes (the terminal is a terminal). So its label has to come
|
|
565
|
-
from the terminal's own foreground, not the page's: --foreground here is near-black in light
|
|
566
|
-
mode, which rendered the active tab as black text on a black tab. */
|
|
567
|
-
.stab-wrap[data-active="true"] .stab{color:var(--xt-brwhite)}
|
|
568
|
-
.stab .g{font-size:var(--text-xs)}
|
|
569
|
-
.stab-wrap[data-state="needs"] .g{color:var(--brand)} .stab-wrap[data-state="blocked"] .g{color:var(--destructive)}
|
|
570
|
-
.stab-wrap[data-state="working"] .g{color:var(--success)}
|
|
571
|
-
.stab-wrap[data-state="done"] .g{color:var(--info)}
|
|
572
|
-
.stab-wrap[data-state="quiet"] .g{color:var(--warning)}
|
|
573
|
-
.stab-wrap[data-state="idle"] .g,.stab-wrap[data-state="exited"] .g{color:var(--muted-foreground)}
|
|
574
|
-
.stab-wrap .x{width:26px;min-height:38px;display:grid;place-items:center;border-radius:var(--radius-sm);
|
|
575
|
-
color:var(--muted-foreground);font-size:var(--text-sm);margin-right:4px}
|
|
576
|
-
.stab-wrap .x:hover{background:var(--accent);color:var(--accent-foreground)}
|
|
577
|
-
/* on the dark active tab the hover surface has to be light, or the ✕ vanishes into it */
|
|
578
|
-
.stab-wrap[data-active="true"] .x{color:var(--xt-brblack)}
|
|
579
|
-
.stab-wrap[data-active="true"] .x:hover{background:rgba(255,255,255,.12);color:var(--xt-brwhite)}
|
|
580
|
-
.stab-wrap .renbox{min-height:32px;width:150px;margin:0 6px 3px}
|
|
581
|
-
|
|
582
|
-
.termhost{flex:1;position:relative;min-height:0;overflow:hidden}
|
|
583
|
-
.termpane{position:absolute;inset:0;padding:8px 8px 6px 10px;display:none}
|
|
584
|
-
.termpane.on{display:block}
|
|
585
|
-
.termpane .xterm{height:100%}
|
|
586
|
-
/* Touch scrollback: xterm's .xterm-viewport owns the scroll, but iOS Safari won't pan it by swipe
|
|
587
|
-
without an explicit touch-action + momentum flag (the terminal otherwise swallows the gesture).
|
|
588
|
-
Presentation-only; harmless on pointer devices. */
|
|
589
|
-
.termpane .xterm .xterm-viewport{touch-action:pan-y;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}
|
|
590
|
-
.termpane .xterm .xterm-screen{touch-action:pan-y}
|
|
591
|
-
/* scoped to termhost (its positioned ancestor) — sidebar/tabs/needs stay clickable */
|
|
592
|
-
.exited-overlay{position:absolute;inset:0;z-index:5;display:none;place-items:center;background:var(--glass)}
|
|
593
|
-
.exited-overlay.on{display:grid}
|
|
594
|
-
.exited-overlay .card{border:1px solid var(--input);border-radius:var(--radius-lg);background:var(--sidebar);
|
|
595
|
-
padding:16px 18px;text-align:center;max-width:340px}
|
|
596
|
-
.exited-overlay .card p{font-size:var(--text-sm);color:var(--foreground);margin-bottom:10px}
|
|
597
|
-
.exited-overlay .card .reason{display:block;margin-top:6px;font-family:var(--mono);font-size:var(--text-xs);
|
|
598
|
-
color:var(--warning);line-height:1.45;max-width:300px}
|
|
599
|
-
.exited-overlay .card .row{display:flex;gap:8px;justify-content:center;flex-wrap:wrap}
|
|
600
|
-
.exited-overlay .card button{min-height:44px;padding:0 16px;border:1px solid var(--brand);border-radius:var(--radius-md);
|
|
601
|
-
background:var(--secondary);font-family:var(--mono);font-size:var(--text-xs);color:var(--brand)}
|
|
602
|
-
.exited-overlay .card button.quiet{border-color:var(--input);color:var(--muted-foreground)}
|
|
603
|
-
.exited-overlay .card button.quiet:hover{border-color:var(--destructive);color:var(--foreground)}
|
|
604
|
-
/* a workspace with no sessions says so — it never shows another workspace's terminal */
|
|
605
|
-
.empty-overlay{position:absolute;inset:0;z-index:4;display:none;place-items:center;padding:20px}
|
|
606
|
-
.empty-overlay.on{display:grid}
|
|
607
|
-
.empty-overlay .card{border:1px dashed var(--input);border-radius:var(--radius-lg);background:var(--sidebar);
|
|
608
|
-
padding:16px 18px;text-align:center;max-width:360px}
|
|
609
|
-
.empty-overlay .card p{font-size:var(--text-sm);color:var(--foreground)}
|
|
610
|
-
.empty-overlay .card .reason{margin-top:6px;font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.45}
|
|
611
|
-
|
|
612
|
-
/* needs-you strips */
|
|
613
|
-
.needs{border-top:1px solid var(--warning);background:var(--warning-wash);padding:10px 14px 12px;flex:none;
|
|
614
|
-
max-height:38vh;overflow-y:auto}
|
|
615
|
-
.needs.accept{border-top-color:var(--info);background:var(--info-wash)}
|
|
616
|
-
.needs .k{font-size:var(--text-xs);color:var(--warning)}
|
|
617
|
-
.needs.accept .k{color:var(--info)}
|
|
618
|
-
.needs .q{font-size:var(--text-sm);color:var(--foreground);line-height:1.5;margin:4px 0 9px;max-width:90ch}
|
|
619
|
-
.needs .row{display:flex;flex-wrap:wrap;align-items:center;gap:8px;font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
620
|
-
.dlink{display:inline-flex;align-items:center;min-height:44px;padding:0 6px;color:var(--brand);text-decoration:underline}
|
|
621
|
-
.gbtn{display:inline-flex;align-items:center;gap:6px;min-height:44px;padding:0 16px;border:1px solid var(--input);
|
|
622
|
-
border-radius:var(--radius-lg);background:var(--secondary);font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
623
|
-
.gbtn:hover{border-color:var(--warning);color:var(--foreground)}
|
|
624
|
-
.needs.accept .gbtn:hover{border-color:var(--info)}
|
|
625
|
-
.gbtn.primary{border-color:var(--warning)} .needs.accept .gbtn.primary{border-color:var(--info)}
|
|
626
|
-
.wpath{width:100%;font-size:var(--text-xs);color:var(--muted-foreground);margin-top:2px}
|
|
627
|
-
|
|
628
|
-
/* ── the detail-panel column. It held the library OVER a document reader; documents are tabs in
|
|
629
|
-
the terminal column now (workspace-viewer-column), so this is one pane. ── */
|
|
630
|
-
.rail{border-left:1px solid var(--input);background:var(--sidebar);position:relative;
|
|
631
|
-
display:flex;flex-direction:column;min-height:0;min-width:0}
|
|
632
|
-
/* drag the rail's own edge — a document read at 340px is a column of ten words */
|
|
633
|
-
.railgrip{position:absolute;left:-4px;top:0;bottom:0;width:8px;z-index:5;cursor:col-resize}
|
|
634
|
-
.railgrip::after{content:"";position:absolute;inset:0 3px;border-radius:var(--radius-sm);background:transparent}
|
|
635
|
-
.railgrip:hover::after,.railgrip:focus-visible::after{background:var(--brand)}
|
|
636
|
-
.rail .lib-pane{flex:1 1 auto;min-height:34px}
|
|
637
|
-
.rail .pane[data-fold="off"]{flex:0 0 auto}
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
/* library — two lenses over one file set: initiatives (how the PM thinks) / folders (how the
|
|
641
|
-
repo is laid out). The initiative lens joins a unit of work's scattered artifacts. */
|
|
642
|
-
/* shadcn Tabs: an inset --muted track, the selected lens lifted onto --background. Four lenses
|
|
643
|
-
have to survive a narrow rail, so the group is allowed to SHRINK and scroll rather than push
|
|
644
|
-
the refresh control off the end of the header — which is what a fixed-width group did. */
|
|
645
|
-
.lens[hidden],.libfind[hidden],.reading[hidden],.librefresh[hidden]{display:none}
|
|
646
|
-
.lens{margin-left:auto;display:inline-flex;gap:2px;border-radius:var(--radius-md);
|
|
647
|
-
background:var(--muted);padding:2px;min-width:0;overflow-x:auto;scrollbar-width:none}
|
|
648
|
-
.lens::-webkit-scrollbar{display:none}
|
|
649
|
-
.lens button{min-height:24px;padding:0 7px;font-size:var(--text-2xs);font-weight:500;flex:none;
|
|
650
|
-
border-radius:var(--radius-sm);color:var(--muted-foreground);background:transparent;
|
|
651
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized),
|
|
652
|
-
color var(--duration-fast) var(--ease-emphasized)}
|
|
653
|
-
.lens button:hover{color:var(--foreground)}
|
|
654
|
-
.lens button[aria-selected="true"]{background:var(--background);color:var(--foreground);
|
|
655
|
-
box-shadow:0 1px 2px var(--shadow)}
|
|
656
|
-
/* shadcn Input */
|
|
657
|
-
.libfind{margin:8px 12px 4px;min-height:34px;padding:0 12px;width:calc(100% - 24px);
|
|
658
|
-
border:1px solid var(--input);border-radius:var(--radius-md);background:transparent;color:var(--foreground);
|
|
659
|
-
font-family:var(--sans);font-size:var(--text-sm);outline:none;
|
|
660
|
-
transition:border-color var(--duration-fast) var(--ease-emphasized),
|
|
661
|
-
box-shadow var(--duration-fast) var(--ease-emphasized)}
|
|
662
|
-
.libfind::placeholder{color:var(--muted-foreground)}
|
|
663
|
-
.libfind:focus{border-color:var(--ring);box-shadow:0 0 0 3px var(--brand-wash)}
|
|
664
|
-
.grp{font-size:var(--text-2xs);
|
|
665
|
-
color:var(--muted-foreground);padding:8px 14px 4px}
|
|
666
|
-
details.init{margin:0}
|
|
667
|
-
details.init>summary{list-style:none;cursor:pointer;min-height:38px;display:flex;align-items:center;gap:7px;
|
|
668
|
-
padding:0 14px;font-family:var(--mono);font-size:var(--text-xs);color:var(--foreground)}
|
|
669
|
-
details.init>summary::-webkit-details-marker{display:none}
|
|
670
|
-
details.init>summary::before{content:"▸";font-size:var(--text-2xs);color:var(--muted-foreground);transition:transform .12s;flex:none}
|
|
671
|
-
details.init[open]>summary::before{transform:rotate(90deg)}
|
|
672
|
-
@media (prefers-reduced-motion:reduce){details.init>summary::before{transition:none}}
|
|
673
|
-
details.init>summary:hover{background:var(--accent)}
|
|
674
|
-
details.init .iid{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
675
|
-
details.init .n{font-size:var(--text-2xs);color:var(--muted-foreground);border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 4px;flex:none}
|
|
676
|
-
details.init .ititle{display:none}
|
|
677
|
-
.doc.art{display:flex;align-items:center;gap:8px;padding-left:28px}
|
|
678
|
-
.doc.art .role{flex:none;width:66px;font-size:var(--text-2xs);color:var(--muted-foreground)}
|
|
679
|
-
.doc.art .role[data-role="PRD"]{color:var(--brand)}
|
|
680
|
-
.doc.art .role[data-role="rubric"],.doc.art .role[data-role="eval"]{color:var(--info)}
|
|
681
|
-
.doc.art .role[data-role="design brief"],.doc.art .role[data-role="design"]{color:var(--warning)}
|
|
682
|
-
.doc.art .dn{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
683
|
-
details.tree{margin:0}
|
|
684
|
-
details.tree>summary{list-style:none;cursor:pointer;min-height:38px;display:flex;align-items:center;gap:7px;
|
|
685
|
-
padding:0 14px;font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
686
|
-
details.tree>summary::-webkit-details-marker{display:none}
|
|
687
|
-
details.tree>summary::before{content:"▸";font-size:var(--text-2xs);color:var(--muted-foreground);transition:transform .12s;flex:none}
|
|
688
|
-
details.tree[open]>summary::before{transform:rotate(90deg)}
|
|
689
|
-
@media (prefers-reduced-motion:reduce){details.tree>summary::before{transition:none}}
|
|
690
|
-
details.tree>summary:hover{color:var(--foreground)}
|
|
691
|
-
.tree .tree>summary{padding-left:28px}
|
|
692
|
-
.tree .tree .tree>summary{padding-left:42px}
|
|
693
|
-
.doc{display:block;width:100%;text-align:left;color:var(--muted-foreground);font-size:var(--text-xs);
|
|
694
|
-
padding:5px 14px 5px 30px;min-height:36px;line-height:1.3;border-left:3px solid transparent;font-family:var(--mono)}
|
|
695
|
-
.tree .tree .doc{padding-left:44px}
|
|
696
|
-
.tree .tree .tree .doc{padding-left:58px}
|
|
697
|
-
.doc:hover{color:var(--foreground);background:var(--accent)}
|
|
698
|
-
.doc.on{color:var(--brand);border-left-color:var(--brand);font-weight:600}
|
|
699
|
-
/* a non-markdown file: shown so the folder map is complete, but inert (the reader is .md-only) */
|
|
700
|
-
.file{display:block;width:100%;text-align:left;color:var(--muted-foreground);font-size:var(--text-xs);
|
|
701
|
-
padding:5px 14px 5px 30px;min-height:36px;line-height:1.3;border-left:3px solid transparent;
|
|
702
|
-
font-family:var(--mono);opacity:.62;cursor:default}
|
|
703
|
-
.tree .tree .file{padding-left:44px}
|
|
704
|
-
.tree .tree .tree .file{padding-left:58px}
|
|
705
|
-
/* the library refresh (↻): hugs the lens toggle, spins briefly on click */
|
|
706
|
-
.cap .librefresh{margin-left:6px;width:26px;height:26px;flex:none}
|
|
707
|
-
.librefresh.spin{animation:libspin .5s linear}
|
|
708
|
-
@keyframes libspin{from{transform:rotate(0)}to{transform:rotate(360deg)}}
|
|
709
|
-
@media (prefers-reduced-motion:reduce){.librefresh.spin{animation:none}}
|
|
710
|
-
.empty{padding:10px 16px;font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.5}
|
|
711
|
-
.empty b{color:var(--foreground)}
|
|
712
|
-
|
|
713
|
-
/* ── the viewer: documents, images and summoned surfaces, as tabs in the terminal column ── */
|
|
714
|
-
.viewpane{flex:1;display:flex;flex-direction:column;min-height:0;min-width:0;background:var(--background)}
|
|
715
|
-
.viewpane[hidden]{display:none}
|
|
716
|
-
.viewpane>.cap{flex:none}
|
|
717
|
-
|
|
718
|
-
.viewpane .cap{padding-right:6px;gap:6px}
|
|
719
|
-
/* the crumb is a FILE PATH — mono earns its place. It yields space to the controls beside it
|
|
720
|
-
rather than shouldering them off the end of the header. */
|
|
721
|
-
.viewpane .crumb{margin-left:auto;font-family:var(--mono);font-size:var(--text-2xs);
|
|
722
|
-
color:var(--muted-foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
|
|
723
|
-
direction:rtl;text-align:right;max-width:50%;min-width:0;flex:0 1 auto}
|
|
724
|
-
/* `ghost` icon button, matching the other cap controls instead of being the one outlined box */
|
|
725
|
-
.viewpane .x{flex:none;width:28px;height:28px;display:grid;place-items:center;border-radius:var(--radius-sm);
|
|
726
|
-
border:0;background:transparent;color:var(--muted-foreground);font-size:var(--text-sm);
|
|
727
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized),
|
|
728
|
-
color var(--duration-fast) var(--ease-emphasized)}
|
|
729
|
-
.viewpane .x:hover{background:var(--destructive);color:var(--primary-foreground)}
|
|
730
|
-
.doc-body{overflow-y:auto;overscroll-behavior:contain;flex:1;min-height:0;
|
|
731
|
-
padding:18px 22px 64px;line-height:1.65;font-size:14px;color:var(--foreground)}
|
|
732
|
-
.doc-body>*{max-width:72ch}
|
|
733
|
-
.doc-body h1{font-size:21px;font-weight:600;line-height:1.3;margin:4px 0 12px;color:var(--foreground);text-wrap:balance}
|
|
734
|
-
.doc-body h2{font-size:16px;font-weight:600;line-height:1.35;margin:26px 0 8px;color:var(--foreground);
|
|
735
|
-
padding-bottom:5px;border-bottom:1px solid var(--border)}
|
|
736
|
-
.doc-body h3{font-size:14px;font-weight:600;margin:20px 0 6px;color:var(--foreground)}
|
|
737
|
-
.doc-body h4,.doc-body h5,.doc-body h6{font-size:var(--text-sm);font-weight:600;margin:16px 0 5px;color:var(--muted-foreground)}
|
|
738
|
-
.doc-body p{margin:0 0 12px}
|
|
739
|
-
.doc-body ul,.doc-body ol{margin:0 0 12px;padding-left:22px}
|
|
740
|
-
.doc-body li{margin:0 0 5px;padding-left:2px}
|
|
741
|
-
.doc-body li>ul,.doc-body li>ol{margin:5px 0 0}
|
|
742
|
-
.doc-body li::marker{color:var(--muted-foreground)}
|
|
743
|
-
.doc-body ul.task{list-style:none;padding-left:6px}
|
|
744
|
-
.doc-body ul.task li{display:flex;gap:8px;align-items:baseline}
|
|
745
|
-
.doc-body ul.task .box{flex:none;font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
746
|
-
.doc-body ul.task .box.done{color:var(--success)}
|
|
747
|
-
.doc-body code{font-family:var(--mono);font-size:var(--text-sm);color:var(--brand);background:var(--secondary);
|
|
748
|
-
padding:1.5px 5px;border-radius:var(--radius-sm);word-break:break-word}
|
|
749
|
-
.doc-body pre{background:var(--secondary);border:1px solid var(--border);border-radius:var(--radius-md);
|
|
750
|
-
padding:12px 14px;overflow-x:auto;margin:0 0 14px;max-width:100%}
|
|
751
|
-
.doc-body pre code{background:none;padding:0;color:var(--muted-foreground);font-size:var(--text-sm);line-height:1.6;word-break:normal}
|
|
752
|
-
.doc-body pre .lang{display:block;font-family:var(--mono);font-size:var(--text-2xs);
|
|
753
|
-
color:var(--muted-foreground);margin-bottom:7px}
|
|
754
|
-
.doc-body blockquote{border-left:3px solid var(--input);background:var(--card);
|
|
755
|
-
padding:9px 14px;margin:0 0 14px;border-radius:0 var(--radius-md) var(--radius-md) 0;color:var(--muted-foreground)}
|
|
756
|
-
.doc-body blockquote p:last-child{margin-bottom:0}
|
|
757
|
-
.doc-body hr{border:0;border-top:1px solid var(--border);margin:22px 0}
|
|
758
|
-
.doc-body a{color:var(--brand);text-decoration:underline;text-underline-offset:2px}
|
|
759
|
-
.doc-body a:hover{color:var(--brand)}
|
|
760
|
-
.doc-body strong{color:var(--foreground);font-weight:600}
|
|
761
|
-
.doc-body del{color:var(--muted-foreground)}
|
|
762
|
-
/* tables (rubrics ARE tables) — scroll inside their own box, never the page */
|
|
763
|
-
.doc-body .tablewrap{overflow-x:auto;margin:0 0 14px;border:1px solid var(--border);border-radius:var(--radius-md);max-width:100%}
|
|
764
|
-
.doc-body table{border-collapse:collapse;width:100%;font-size:var(--text-sm)}
|
|
765
|
-
.doc-body th,.doc-body td{text-align:left;padding:8px 11px;border-bottom:1px solid var(--border);vertical-align:top}
|
|
766
|
-
.doc-body th{background:var(--muted);color:var(--foreground);font-weight:600;font-size:var(--text-sm);
|
|
767
|
-
letter-spacing:.03em;white-space:nowrap}
|
|
768
|
-
.doc-body tbody tr:nth-child(even){background:var(--card)}
|
|
769
|
-
.doc-body tbody tr:last-child td{border-bottom:0}
|
|
770
|
-
/* the identity block every PMOS artifact opens with, as a card instead of raw YAML */
|
|
771
|
-
.doc-body .fm{border:1px solid var(--border);background:var(--card);border-radius:var(--radius-lg);
|
|
772
|
-
padding:10px 12px;margin:0 0 18px;display:grid;grid-template-columns:auto 1fr;gap:4px 12px;
|
|
773
|
-
font-size:var(--text-sm);max-width:72ch}
|
|
774
|
-
.doc-body .fm dt{font-size:var(--text-2xs);
|
|
775
|
-
color:var(--muted-foreground);padding-top:2px}
|
|
776
|
-
.doc-body .fm dd{color:var(--foreground);min-width:0;overflow-wrap:anywhere}
|
|
777
|
-
.doc-empty{padding:16px;color:var(--muted-foreground);font-size:var(--text-sm)}
|
|
778
|
-
|
|
779
|
-
/* ── ⌘K jump palette + the in-app folder browser ── */
|
|
780
|
-
.palette{position:fixed;inset:0;z-index:90;background:var(--glass);backdrop-filter:blur(3px);
|
|
781
|
-
display:grid;place-items:start center;padding-top:12vh}
|
|
782
|
-
.palette-box{width:min(560px,92vw);background:var(--sidebar);border:1px solid var(--input);
|
|
783
|
-
border-radius:var(--radius-xl);overflow:hidden;box-shadow:0 24px 80px -24px var(--shadow)}
|
|
784
|
-
.palette-box input{width:100%;min-height:48px;padding:0 16px;background:var(--muted);border:0;
|
|
785
|
-
border-bottom:1px solid var(--border);color:var(--foreground);font-family:var(--mono);font-size:var(--text-base);outline:none}
|
|
786
|
-
.palette-list{max-height:52vh;overflow-y:auto;padding:6px}
|
|
787
|
-
.pitem{display:flex;align-items:center;gap:9px;width:100%;text-align:left;min-height:40px;padding:0 12px;
|
|
788
|
-
border-radius:var(--radius-md);font-family:var(--mono);font-size:var(--text-sm);color:var(--muted-foreground)}
|
|
789
|
-
.pitem .kind{font-size:var(--text-2xs);color:var(--muted-foreground);margin-left:auto}
|
|
790
|
-
.pitem.sel,.pitem:hover{background:var(--accent);color:var(--foreground)}
|
|
791
|
-
.pitem .g{font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
792
|
-
.pitem .badge{font-size:var(--text-2xs);color:var(--success);
|
|
793
|
-
border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 4px;margin-left:auto}
|
|
794
|
-
.fs-head{display:flex;align-items:center;gap:8px;padding:8px 10px;background:var(--muted);
|
|
795
|
-
border-bottom:1px solid var(--border)}
|
|
796
|
-
.fs-up{width:34px;min-height:34px;display:grid;place-items:center;border:1px solid var(--border);
|
|
797
|
-
border-radius:var(--radius-md);background:var(--secondary);color:var(--muted-foreground)}
|
|
798
|
-
.fs-up:hover{border-color:var(--brand);color:var(--brand)}
|
|
799
|
-
.fs-crumb{flex:1;min-width:0;font-family:var(--mono);font-size:var(--text-xs);color:var(--foreground);
|
|
800
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap;direction:rtl;text-align:left}
|
|
801
|
-
.fs-use{min-height:34px;padding:0 12px;border:1px solid var(--brand);border-radius:var(--radius-md);
|
|
802
|
-
background:var(--brand-wash);color:var(--brand);font-family:var(--mono);font-size:var(--text-xs)}
|
|
803
|
-
.fs-head .x{width:34px;min-height:34px;display:grid;place-items:center;border:1px solid var(--border);
|
|
804
|
-
border-radius:var(--radius-md);background:var(--secondary);color:var(--muted-foreground);font-size:var(--text-sm)}/* ── status strip ── */
|
|
805
|
-
.strip{display:flex;align-items:center;gap:14px;padding:0 12px;border-top:1px solid var(--border);
|
|
806
|
-
background:var(--muted);font-size:var(--text-xs);color:var(--muted-foreground);min-width:0}
|
|
807
|
-
.strip span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
808
|
-
/* `flex:none` here would pin the hint list at its full width and push the page into a horizontal
|
|
809
|
-
scroll once the type got bigger than the 9.5px it was originally set at. It ellipsizes instead:
|
|
810
|
-
the strip is the lowest-priority text on screen and must never widen the app. */
|
|
811
|
-
.strip .right{margin-left:auto;color:var(--muted-foreground);flex:0 1 auto;min-width:0}
|
|
812
|
-
|
|
813
|
-
/* ── on-demand surfaces (Plan · Deliver · Measure · Report), rendered in the reader ── */
|
|
814
|
-
/* phase accents — status is NEVER hue-alone: every surface pairs colour with a glyph + label */
|
|
815
|
-
.sf-wrap{--plan:var(--brand);--deliver:var(--success);--measure:var(--info);--report:var(--warning)}
|
|
816
|
-
.sf-head{position:sticky;top:0;z-index:2;display:flex;align-items:center;gap:8px;flex-wrap:wrap;
|
|
817
|
-
padding:12px 22px;background:var(--muted);border-bottom:1px solid var(--border);margin:0 0 4px}
|
|
818
|
-
.sf-views{display:inline-flex;gap:6px;flex-wrap:wrap}
|
|
819
|
-
.sf-views button{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);border:1px solid var(--border);
|
|
820
|
-
border-radius:var(--radius-md);padding:4px 10px;background:var(--secondary)}
|
|
821
|
-
.sf-views button:hover{border-color:var(--input);color:var(--foreground)}
|
|
822
|
-
.sf-views button.on{border-color:var(--brand);color:var(--brand);background:var(--brand-wash)}
|
|
823
|
-
.sf-chip{margin-left:auto;display:inline-flex;gap:6px;align-items:center;font-size:var(--text-2xs);
|
|
824
|
-
letter-spacing:.05em;color:var(--success);border:1px solid var(--border);border-radius:99px;padding:3px 10px}
|
|
825
|
-
.sf-chip::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--success)}
|
|
826
|
-
.sf-body{padding:14px 22px 40px;display:flex;flex-direction:column;gap:16px}
|
|
827
|
-
.sf-body .untr{color:var(--muted-foreground);font-style:italic;opacity:.75;font-size:var(--text-xs)}
|
|
828
|
-
.sf-note{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.6;border-top:1px solid var(--border);padding-top:11px}
|
|
829
|
-
|
|
830
|
-
/* focal band: what needs you (leads) */
|
|
831
|
-
.sf-needs{border:1px solid var(--warning);border-radius:var(--radius-xl);overflow:hidden;
|
|
832
|
-
background:radial-gradient(120% 140% at 0 0,var(--warning-wash),transparent 60%),var(--card)}
|
|
833
|
-
.sf-needs .nh{display:flex;align-items:center;gap:9px;padding:12px 15px 9px}
|
|
834
|
-
.sf-needs .nh .dot{width:8px;height:8px;border-radius:50%;background:var(--warning);flex:none;box-shadow:0 0 0 4px var(--warning-wash)}
|
|
835
|
-
.sf-needs .nh b{font-size:var(--text-base);color:var(--foreground)}
|
|
836
|
-
.sf-needs .nh .sub{font-family:var(--mono);font-size:var(--text-xs);color:var(--warning);margin-left:auto}
|
|
837
|
-
.sf-needs .need{display:flex;align-items:center;gap:11px;padding:10px 15px;border-top:1px solid var(--border)}
|
|
838
|
-
.sf-needs .need .ph{width:3px;align-self:stretch;border-radius:var(--radius-sm);background:var(--warning);flex:none}
|
|
839
|
-
.sf-needs .need .txt{flex:1;min-width:0}
|
|
840
|
-
.sf-needs .need .t{font-size:var(--text-sm);color:var(--foreground);line-height:1.45}
|
|
841
|
-
.sf-needs .need .m{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);margin-top:3px}
|
|
842
|
-
.sf-needs .need .go{flex:none;min-height:36px;padding:0 13px;border:1px solid var(--warning);border-radius:var(--radius-md);
|
|
843
|
-
background:var(--secondary);font-family:var(--mono);font-size:var(--text-xs);color:var(--warning)}
|
|
844
|
-
.sf-needs .need .go:hover{background:var(--warning-wash);color:var(--foreground)}
|
|
845
|
-
.sf-needs.calm{border-color:var(--info)}
|
|
846
|
-
.sf-needs.calm .nh .dot{background:var(--info);box-shadow:0 0 0 4px var(--info-wash)}
|
|
847
|
-
.sf-needs.calm .nh .sub{color:var(--info)}
|
|
848
|
-
.sf-needs.calm .calm-body{padding:2px 15px 13px;font-size:var(--text-sm);color:var(--muted-foreground);line-height:1.5}
|
|
849
|
-
|
|
850
|
-
/* one restrained instrument (not a chart wall) */
|
|
851
|
-
.sf-pulse{display:flex;align-items:center;gap:13px;flex-wrap:wrap}
|
|
852
|
-
.sf-pulse .n{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
853
|
-
.sf-pulse .n b{color:var(--foreground);font-size:15px;font-weight:600}
|
|
854
|
-
.sf-dist{flex:1;min-width:150px;height:8px;border-radius:99px;overflow:hidden;display:flex;background:var(--accent)}
|
|
855
|
-
.sf-dist i{height:100%}
|
|
856
|
-
.sf-dist i[data-phase="plan"]{background:var(--plan)} .sf-dist i[data-phase="deliver"]{background:var(--deliver)}
|
|
857
|
-
.sf-dist i[data-phase="measure"]{background:var(--measure)} .sf-dist i[data-phase="report"]{background:var(--report)}
|
|
858
|
-
.sf-legend{display:flex;gap:12px;flex-wrap:wrap;font-size:var(--text-2xs);color:var(--muted-foreground)}
|
|
859
|
-
|
|
860
|
-
/* the list: rows with a phase spine,not a wall of identical cards */
|
|
861
|
-
.sf-grp{font-size:var(--text-2xs);color:var(--muted-foreground);padding:4px 2px 2px}
|
|
862
|
-
.sf-list{display:flex;flex-direction:column}
|
|
863
|
-
.sf-row{border-top:1px solid var(--border)}
|
|
864
|
-
.sf-row:first-child{border-top:0}
|
|
865
|
-
.sf-row>summary{list-style:none;cursor:pointer;display:grid;grid-template-columns:3px auto 1fr auto auto;gap:11px;
|
|
866
|
-
align-items:center;padding:11px 4px;min-height:54px}
|
|
867
|
-
.sf-row>summary::-webkit-details-marker{display:none}
|
|
868
|
-
.sf-row>summary:hover{background:var(--accent)}
|
|
869
|
-
.sf-spine{width:3px;align-self:stretch;border-radius:var(--radius-sm);background:var(--input)}
|
|
870
|
-
.sf-row[data-phase="plan"] .sf-spine,.sf-rcrow[data-phase="plan"] .sf-spine{background:var(--plan)}
|
|
871
|
-
.sf-row[data-phase="deliver"] .sf-spine,.sf-rcrow[data-phase="deliver"] .sf-spine{background:var(--deliver)}
|
|
872
|
-
.sf-row[data-phase="measure"] .sf-spine,.sf-rcrow[data-phase="measure"] .sf-spine{background:var(--measure)}
|
|
873
|
-
.sf-row[data-phase="report"] .sf-spine,.sf-rcrow[data-phase="report"] .sf-spine{background:var(--report)}
|
|
874
|
-
.sf-stat .g{font-size:var(--text-xs);color:var(--muted-foreground);white-space:nowrap}
|
|
875
|
-
.sf-id{font-family:var(--mono);font-size:var(--text-sm);color:var(--foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
|
|
876
|
-
.sf-id .ti{display:block;font-family:var(--sans);font-size:var(--text-xs);color:var(--muted-foreground);margin-top:2px;
|
|
877
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
878
|
-
.sf-metrics{display:flex;align-items:center;gap:13px;flex:none;font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
879
|
-
.sf-metrics .m{display:flex;flex-direction:column;gap:2px}
|
|
880
|
-
.sf-metrics .k{font-size:var(--text-2xs);color:var(--muted-foreground)}
|
|
881
|
-
.sf-metrics b{color:var(--brand);font-size:var(--text-base)}
|
|
882
|
-
.sf-prog{width:52px;height:5px;border-radius:99px;background:var(--accent);overflow:hidden;display:block}
|
|
883
|
-
.sf-prog i{display:block;height:100%;background:linear-gradient(90deg,var(--brand),var(--info))}
|
|
884
|
-
.sf-chev{color:var(--muted-foreground);font-size:var(--text-xs);transition:transform .14s}
|
|
885
|
-
.sf-row[open] .sf-chev{transform:rotate(90deg)}
|
|
886
|
-
@media (prefers-reduced-motion:reduce){.sf-chev{transition:none}}
|
|
887
|
-
.sf-detail{padding:2px 12px 15px 18px;display:grid;gap:11px;background:var(--muted)}
|
|
888
|
-
.sf-detail h4{font-size:var(--text-2xs);color:var(--muted-foreground);margin-bottom:4px}
|
|
889
|
-
.sf-detail p{font-size:var(--text-sm);color:var(--foreground);line-height:1.5}
|
|
890
|
-
.sf-arts{display:flex;flex-wrap:wrap;gap:6px}
|
|
891
|
-
.sf-art{display:inline-flex;align-items:center;gap:7px;font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);
|
|
892
|
-
border:1px solid var(--border);border-radius:var(--radius-md);padding:4px 9px;background:var(--secondary)}
|
|
893
|
-
.sf-art:hover{border-color:var(--brand);color:var(--brand)}
|
|
894
|
-
.sf-art .role{font-size:var(--text-2xs);color:var(--muted-foreground)}
|
|
895
|
-
|
|
896
|
-
/* roadmap (list-calendar) · okr · report */
|
|
897
|
-
.sf-rc h4{font-family:var(--mono);font-size:var(--text-2xs);color:var(--brand);
|
|
898
|
-
margin-bottom:6px;padding-bottom:5px;border-bottom:1px solid var(--border)}
|
|
899
|
-
.sf-rcrow{display:grid;grid-template-columns:3px 1fr auto;gap:10px;align-items:center;padding:7px 2px}
|
|
900
|
-
.sf-rcrow .nm{font-family:var(--mono);font-size:var(--text-xs);color:var(--foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
901
|
-
.sf-rcrow .st{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
902
|
-
.sf-kr{border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--card);padding:13px;margin-bottom:2px}
|
|
903
|
-
.sf-kr .obj{font-size:var(--text-base);color:var(--foreground);font-weight:600;margin-bottom:9px}
|
|
904
|
-
.sf-kr .krrow{padding:8px 0;border-top:1px solid var(--border)}
|
|
905
|
-
.sf-kr .krh{display:flex;gap:9px;align-items:baseline}
|
|
906
|
-
.sf-kr .krh .lab{font-family:var(--mono);font-size:var(--text-xs);color:var(--info);flex:none}
|
|
907
|
-
.sf-kr .krh span:last-child{font-size:var(--text-sm);color:var(--foreground)}
|
|
908
|
-
.sf-kr .lev{margin-top:5px}
|
|
909
|
-
.sf-rep .lead{font-size:var(--text-xs);color:var(--muted-foreground);margin-bottom:6px}
|
|
910
|
-
.sf-rep h3{font-size:var(--text-base);color:var(--foreground);font-weight:600;margin:16px 0 6px;padding-bottom:5px;border-bottom:1px solid var(--border)}
|
|
911
|
-
.sf-rep ul{margin:0;padding-left:20px}
|
|
912
|
-
.sf-rep li{margin-bottom:5px;font-size:var(--text-sm);color:var(--foreground);line-height:1.5}
|
|
913
|
-
|
|
914
|
-
/* honest can't-produce + loading */
|
|
915
|
-
.sf-fail{border:1px dashed var(--input);border-radius:var(--radius-xl);background:var(--card);padding:24px;text-align:center}
|
|
916
|
-
.sf-fail .mk{width:34px;height:34px;margin:0 auto 12px;display:grid;place-items:center;border-radius:var(--radius-lg);border:1px solid var(--input);color:var(--muted-foreground);font-size:16px}
|
|
917
|
-
.sf-fail h3{font-size:14px;color:var(--foreground);margin-bottom:6px}
|
|
918
|
-
.sf-fail p{font-size:var(--text-sm);color:var(--muted-foreground);line-height:1.6;max-width:48ch;margin:0 auto 5px}
|
|
919
|
-
.sf-fail .miss{font-size:var(--text-xs);color:var(--warning)}
|
|
920
|
-
.sf-fail code{font-family:var(--mono);color:var(--brand);background:var(--secondary);padding:1px 6px;border-radius:var(--radius-sm)}
|
|
921
|
-
.sf-skel{display:flex;flex-direction:column;gap:11px}
|
|
922
|
-
.sf-skel i{height:50px;border-radius:var(--radius-lg);background:linear-gradient(90deg,var(--card),var(--accent),var(--card));background-size:200% 100%;animation:sfsh 1.3s infinite}
|
|
923
|
-
@keyframes sfsh{0%{background-position:200% 0}100%{background-position:-200% 0}}
|
|
924
|
-
@media (prefers-reduced-motion:reduce){.sf-skel i{animation:none;opacity:.7}}
|
|
925
|
-
|
|
926
|
-
/* ── the scheduled lens (a persistent third library lens, in the library pane) ── */
|
|
927
|
-
.sc-load{padding:14px;color:var(--muted-foreground);font-size:var(--text-xs)}
|
|
928
|
-
.sc-wrap{--plan:var(--brand);padding:8px 10px 12px}
|
|
929
|
-
.sc-sum{display:flex;align-items:center;gap:9px;padding:9px 11px;border-radius:var(--radius-lg);background:var(--card);border:1px solid var(--border);margin-bottom:10px}
|
|
930
|
-
.sc-sum .dot{width:7px;height:7px;border-radius:50%;background:var(--success);flex:none;box-shadow:0 0 0 4px var(--info-wash)}
|
|
931
|
-
.sc-sum.warn .dot{background:var(--warning);box-shadow:0 0 0 4px var(--warning-wash)}
|
|
932
|
-
.sc-sum .t{font-size:var(--text-sm);color:var(--foreground);min-width:0}
|
|
933
|
-
.sc-sum .t b{color:var(--foreground)}
|
|
934
|
-
.sc-new{margin-left:auto;min-height:30px;padding:0 11px;border:1px solid var(--brand);border-radius:var(--radius-md);background:var(--brand-wash);color:var(--brand);font-family:var(--mono);font-size:var(--text-xs);flex:none}
|
|
935
|
-
.sc-list{display:flex;flex-direction:column;gap:7px}
|
|
936
|
-
.sc-row{border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--card);overflow:hidden}
|
|
937
|
-
.sc-main{display:grid;grid-template-columns:3px auto 1fr auto;gap:10px;align-items:center;padding:10px 11px}
|
|
938
|
-
.sc-rail{width:3px;align-self:stretch;border-radius:var(--radius-sm);background:var(--input)}
|
|
939
|
-
.sc-row[data-health="armed"] .sc-rail{background:var(--brand)}
|
|
940
|
-
.sc-row[data-health="running"] .sc-rail{background:var(--success);animation:pulse 1.6s infinite}
|
|
941
|
-
.sc-row[data-health="failed"] .sc-rail{background:var(--destructive)}
|
|
942
|
-
@media (prefers-reduced-motion:reduce){.sc-row[data-health="running"] .sc-rail{animation:none}}
|
|
943
|
-
.sc-tog{position:relative;width:34px;height:20px;border-radius:99px;background:var(--accent);border:1px solid var(--input);flex:none;cursor:pointer;transition:background .15s}
|
|
944
|
-
.sc-tog[aria-checked="true"]{background:var(--brand-wash);border-color:var(--brand)}
|
|
945
|
-
.sc-tog .knob{position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:var(--muted-foreground);transition:transform .15s,background .15s}
|
|
946
|
-
.sc-tog[aria-checked="true"] .knob{transform:translateX(14px);background:var(--brand)}
|
|
947
|
-
@media (prefers-reduced-motion:reduce){.sc-tog,.sc-tog .knob{transition:none}}
|
|
948
|
-
.sc-id{min-width:0}
|
|
949
|
-
.sc-id .nm{font-family:var(--mono);font-size:var(--text-sm);color:var(--foreground);display:flex;align-items:center;gap:6px;overflow:hidden}
|
|
950
|
-
.sc-id .nm .g{color:var(--muted-foreground);font-size:var(--text-2xs);flex:none}
|
|
951
|
-
.sc-id .nm .name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
952
|
-
.sc-id .nm .skill{font-size:var(--text-2xs);color:var(--purple);border:1px solid var(--border);border-radius:var(--radius-sm);padding:1px 5px;flex:none}
|
|
953
|
-
.sc-id .cad{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);margin-top:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
954
|
-
.sc-run{text-align:right;flex:none;font-size:var(--text-xs)}
|
|
955
|
-
.sc-run .next{color:var(--brand)}
|
|
956
|
-
.sc-run .fail{color:var(--destructive)}
|
|
957
|
-
.sc-run .off{color:var(--muted-foreground)}
|
|
958
|
-
.sc-more{display:flex;gap:6px;padding:0 11px 10px 24px}
|
|
959
|
-
.sc-more button{min-height:30px;padding:0 9px;border:1px solid var(--border);border-radius:var(--radius-md);background:var(--secondary);font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
960
|
-
.sc-more .rn{border-color:var(--brand);color:var(--brand)}
|
|
961
|
-
.sc-more button:hover{border-color:var(--input);color:var(--foreground)}
|
|
962
|
-
.sc-more .rn:hover{background:var(--brand-wash)}
|
|
963
|
-
.sc-empty{text-align:center;padding:22px 14px}
|
|
964
|
-
.sc-empty .mk{width:30px;height:30px;margin:0 auto 10px;display:grid;place-items:center;border-radius:var(--radius-md);border:1px dashed var(--input);color:var(--muted-foreground);font-size:14px}
|
|
965
|
-
.sc-empty p{font-size:var(--text-sm);color:var(--muted-foreground);line-height:1.55;max-width:32ch;margin:0 auto 11px}
|
|
966
|
-
.sc-note{font-family:var(--mono);font-size:var(--text-2xs);color:var(--muted-foreground);line-height:1.6;border-top:1px solid var(--border);margin-top:11px;padding-top:10px}
|
|
967
|
-
.sc-note b{color:var(--purple)}
|
|
968
|
-
/* create form */
|
|
969
|
-
.sc-form{border:1px solid var(--brand);border-radius:var(--radius-lg);background:var(--muted);padding:12px;display:grid;gap:9px;margin:0 0 10px}
|
|
970
|
-
.sc-form label{font-size:var(--text-2xs);color:var(--muted-foreground);display:block;margin-bottom:4px}
|
|
971
|
-
.sc-form input,.sc-form select{width:100%;min-height:34px;padding:0 9px;border:1px solid var(--input);border-radius:var(--radius-md);background:var(--secondary);color:var(--foreground);font-family:var(--mono);font-size:var(--text-xs);outline:none}
|
|
972
|
-
.sc-form input:focus,.sc-form select:focus{border-color:var(--brand)}
|
|
973
|
-
.sc-f2{display:grid;grid-template-columns:1fr 1fr;gap:8px}
|
|
974
|
-
.sc-seg{display:flex;border:1px solid var(--border);border-radius:var(--radius-md);overflow:hidden}
|
|
975
|
-
.sc-seg button{flex:1;min-height:32px;background:var(--secondary);color:var(--muted-foreground);font-family:var(--mono);font-size:var(--text-2xs)}
|
|
976
|
-
.sc-seg button+button{border-left:1px solid var(--border)}
|
|
977
|
-
.sc-seg button[aria-pressed="true"]{background:var(--accent);color:var(--brand)}
|
|
978
|
-
.sc-hint{font-size:var(--text-2xs);color:var(--muted-foreground);line-height:1.5}
|
|
979
|
-
.sc-hint b{color:var(--success)}
|
|
980
|
-
.sc-frow{display:flex;gap:8px}
|
|
981
|
-
.sc-form .save{min-height:36px;padding:0 13px;border:1px solid var(--brand);border-radius:var(--radius-md);background:var(--brand-wash);color:var(--brand);font-family:var(--mono);font-size:var(--text-xs)}
|
|
982
|
-
.sc-form .cancel{min-height:36px;padding:0 11px;border:1px solid var(--border);border-radius:var(--radius-md);background:var(--secondary);color:var(--muted-foreground);font-family:var(--mono);font-size:var(--text-xs)}
|
|
983
|
-
/* New Skill flow — the GUI that replaces editing server code (workspace-skill-authoring) */
|
|
984
|
-
.sc-acts{margin-left:auto;display:flex;gap:6px;flex:none}
|
|
985
|
-
.sc-new.ghost{border-color:var(--input);background:var(--secondary);color:var(--muted-foreground)}
|
|
986
|
-
.sc-new.ghost:hover{border-color:var(--purple);color:var(--purple)}
|
|
987
|
-
.sc-form textarea{width:100%;min-height:34px;padding:7px 9px;border:1px solid var(--input);border-radius:var(--radius-md);background:var(--secondary);color:var(--foreground);font-family:var(--mono);font-size:var(--text-xs);outline:none;resize:vertical;line-height:1.5}
|
|
988
|
-
.sc-form textarea:focus{border-color:var(--brand)}
|
|
989
|
-
.sk-form{border-color:var(--purple)}
|
|
990
|
-
.sk-head{font-family:var(--mono);font-size:var(--text-xs);color:var(--foreground);display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
|
|
991
|
-
.sk-head .sk-sub{font-size:var(--text-2xs);letter-spacing:.04em;color:var(--muted-foreground);text-transform:none}
|
|
992
|
-
.sc-ai{min-height:36px;padding:0 11px;border:1px solid var(--purple);border-radius:var(--radius-md);background:var(--accent);color:var(--purple);font-family:var(--mono);font-size:var(--text-xs)}
|
|
993
|
-
.sc-ai:hover{background:var(--brand-wash)}
|
|
994
|
-
.needs.report{border-top-color:var(--info);background:var(--info-wash)}
|
|
995
|
-
.needs.report .k{color:var(--info)}/* a session that fired from a schedule carries a small badge */
|
|
996
|
-
.sess .schtag{margin-left:6px;font-size:var(--text-2xs);color:var(--purple);
|
|
997
|
-
border:1px solid var(--border);border-radius:var(--radius-sm);padding:0 4px;vertical-align:middle}
|
|
998
|
-
|
|
999
|
-
/* Narrow: the rail floats over the terminal instead of squeezing it below a usable width. */
|
|
1000
|
-
@media (max-width:1100px){
|
|
1001
|
-
/* applyLayout() drops the panel's track from the template at this width and sets data-float, so
|
|
1002
|
-
the grid here is sidebar + terminal and the panel floats over the terminal rather than
|
|
1003
|
-
squeezing it below a usable width. */
|
|
1004
|
-
.body[data-float="on"]>.rail{position:absolute;top:0;bottom:0;left:0;right:auto;
|
|
1005
|
-
width:min(420px,86vw);z-index:30;box-shadow:18px 0 50px -30px var(--shadow)}/* Split is forced OFF below this width by applyLayout() — two terminal groups inside what is
|
|
1006
|
-
left of a narrow window is two unusable terminals. The layout menu says so rather than
|
|
1007
|
-
silently ignoring the choice (R9). */
|
|
1008
|
-
.lay-narrow{display:block}
|
|
1009
|
-
}
|
|
1010
|
-
.lay-narrow{display:none;font-size:var(--text-xs);color:var(--warning);
|
|
1011
|
-
line-height:1.5;margin:6px 5px 0}
|
|
1012
|
-
|
|
1013
|
-
/* history lens — episodic recall over this workspace's own session scrollback */
|
|
1014
|
-
.hi-hint{padding:14px;color:var(--muted-foreground);font-size:var(--text-xs);line-height:1.6}
|
|
1015
|
-
.hi-list{display:flex;flex-direction:column;gap:7px;padding:8px 10px 12px}
|
|
1016
|
-
.hi-row{border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--card);padding:9px 11px}
|
|
1017
|
-
.hi-head{display:flex;align-items:baseline;gap:8px;margin-bottom:5px}
|
|
1018
|
-
.hi-head b{font-size:var(--text-sm);color:var(--foreground)}
|
|
1019
|
-
.hi-meta{font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
1020
|
-
.hi-ctx{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);white-space:pre-wrap;word-break:break-word}
|
|
1021
|
-
.hi-hit{font-family:var(--mono);font-size:var(--text-xs);color:var(--foreground);white-space:pre-wrap;word-break:break-word;padding:2px 0}
|
|
1022
|
-
|
|
1023
|
-
/* ── reader: multi-format preview + local images (workspace-reader-preview) ── */
|
|
1024
|
-
.doc-src{margin:0;padding:12px 14px;font-family:var(--mono);font-size:var(--text-sm);line-height:1.6;
|
|
1025
|
-
color:var(--foreground);white-space:pre-wrap;word-break:break-word;background:var(--card);
|
|
1026
|
-
border:1px solid var(--border);border-radius:var(--radius-md);overflow-x:auto}
|
|
1027
|
-
.doc-body img.doc-img{max-width:100%;height:auto;border:1px solid var(--border);border-radius:var(--radius-md);
|
|
1028
|
-
background:var(--card);display:block;margin:10px 0}
|
|
1029
|
-
.img-view{padding:6px 2px}
|
|
1030
|
-
.img-view img.doc-img{margin:0}
|
|
1031
|
-
.html-view{display:flex;flex-direction:column;gap:8px}
|
|
1032
|
-
.html-bar{display:flex;gap:6px;align-items:center}
|
|
1033
|
-
.html-tab{font-family:var(--mono);font-size:var(--text-xs);letter-spacing:.02em;padding:3px 9px;
|
|
1034
|
-
border:1px solid var(--border);background:var(--secondary);color:var(--muted-foreground);border-radius:var(--radius-md);cursor:pointer}
|
|
1035
|
-
.html-tab:hover{border-color:var(--input);color:var(--foreground)}
|
|
1036
|
-
.html-tab.on{border-color:var(--brand);color:var(--brand);background:var(--accent)}
|
|
1037
|
-
.html-tab .sbx{font-size:var(--text-2xs);opacity:.7}
|
|
1038
|
-
.html-pane{min-height:0}
|
|
1039
|
-
.html-frame{width:100%;min-height:60vh;border:1px solid var(--border);border-radius:var(--radius-md);
|
|
1040
|
-
background:white} /* a standalone HTML doc assumes a light page; keyword, not hex (token-hygiene) */
|
|
1041
|
-
/* ── mobile (≤760px): ONE screen at a time — a back control at the top, a destination nav at the
|
|
1042
|
-
bottom, and exactly one of the three real column nodes on screen.
|
|
1043
|
-
The columns are never re-parented and never rebuilt; a screen chooses WHICH ONE is visible
|
|
1044
|
-
through `data-mscreen` on #bodyGrid — the same node and the same mechanism the retired
|
|
1045
|
-
`data-mview` used, renamed because the values now name a COLUMN (`side`/`term`/`rail`) rather
|
|
1046
|
-
than a tab. That is what makes a pushed screen, a pop and a destination switch survive without
|
|
1047
|
-
destroying the xterm instance or its PTY socket: the terminal is covered, never unmounted.
|
|
1048
|
-
`.mobtabs` is gone — rule and markup. A bottom destination nav with a leftover three-tab strip
|
|
1049
|
-
underneath it is two navigation systems at once, which is the exact condition the old partition
|
|
1050
|
-
check existed to prevent; keeping it alive as a shim would fail the thing it was protecting.
|
|
1051
|
-
Touch targets ≥44px; the control bar sends the keys a phone keyboard lacks straight to the PTY.
|
|
1052
|
-
The 3-column desktop layout above is untouched at wide widths — everything here is inside the
|
|
1053
|
-
≤760 query, or is a `display:none` above it (.mobmenu, .mob). ── */
|
|
1054
|
-
.mobmenu{display:none}
|
|
1055
|
-
/* Above the breakpoint the phone bar is ABSENT rather than merely invisible (R12): this removes
|
|
1056
|
-
its box, and app.js leaves the `hidden` attribute on so it is out of the accessibility tree too.
|
|
1057
|
-
Both, not either — a node that is only `hidden` still loses to any author `display` below. */
|
|
1058
|
-
.mob{display:none}
|
|
1059
|
-
@media (max-width:760px){
|
|
1060
|
-
/* five rows now: top bar · phone bar · content · control bar + destination nav · status strip.
|
|
1061
|
-
`height:100dvh` is load-bearing rather than decorative here — when the soft keyboard opens the
|
|
1062
|
-
visual viewport shrinks and the grid shrinks with it, so the destination nav stays on screen
|
|
1063
|
-
instead of sitting underneath the keys. */
|
|
1064
|
-
.app{grid-template-rows:44px auto minmax(0,1fr) auto 28px;height:100dvh}
|
|
1065
|
-
/* Placed EXPLICITLY rather than left to auto-placement. #mobShell ships `hidden` and only app.js
|
|
1066
|
-
takes the attribute off, so at this width the shell may legitimately be out of flow for a tick
|
|
1067
|
-
— and under auto-placement that shifts .body up into the `auto` row and hands minmax(0,1fr) to
|
|
1068
|
-
the control bar, which collapses the terminal to nothing. Naming the rows makes the phone
|
|
1069
|
-
layout independent of how many of these five children happen to be in flow. */
|
|
1070
|
-
.app>.bar{grid-row:1}
|
|
1071
|
-
.app>.mob{grid-row:2}
|
|
1072
|
-
.app>.body{grid-row:3}
|
|
1073
|
-
.app>.mobmenu{grid-row:4}
|
|
1074
|
-
.app>.strip{grid-row:5}
|
|
1075
|
-
/* collapse to a single column; the switcher decides which pane is shown. These are DIRECT
|
|
1076
|
-
declarations and the layout writes custom properties, so the phone's arrangement wins here
|
|
1077
|
-
whatever layout the desktop is on — the two systems never fight (R9). */
|
|
1078
|
-
/* minmax(0,1fr), not 1fr: a bare `1fr` is minmax(AUTO,1fr) and refuses to go below the pane's
|
|
1079
|
-
min-content width, which is what pushed the whole app sideways once the navigator gained a
|
|
1080
|
-
nesting level. The row track already had this; the column was the half that was missing. */
|
|
1081
|
-
.body{grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr);grid-template-areas:none;position:relative}
|
|
1082
|
-
/* the named areas are gone here, so the panes must stop asking for them — a stale `grid-area`
|
|
1083
|
-
places them on implicit tracks and the pane spills over the switcher it is covering */
|
|
1084
|
-
.body>.side,.body>.term-col,.body>.rail,.body>.drop{grid-area:auto}
|
|
1085
|
-
/* THE column switch, and the whole of the exclusivity guarantee. Two of the three are
|
|
1086
|
-
`display:none` at any moment, so "exactly one column has a non-zero client rect" is a property
|
|
1087
|
-
of this stylesheet rather than something the reducer has to remember to enforce. A screen's
|
|
1088
|
-
`column` is derived from its `kind` — list/more → side · detail → rail · terminal/doc → term —
|
|
1089
|
-
so every screen the reducer can reach lands on one of these three values and no other.
|
|
1090
|
-
These are DIRECT declarations and the layout engine writes custom properties, so the phone's
|
|
1091
|
-
arrangement wins here whatever layout the desktop is on — the two systems never fight (R9). */
|
|
1092
|
-
.body>.side,.body>.term-col,.body>.rail{display:none}
|
|
1093
|
-
.body[data-mscreen="side"]>.side{display:flex}
|
|
1094
|
-
.body[data-mscreen="term"]>.term-col{display:flex}
|
|
1095
|
-
.body[data-mscreen="rail"]>.rail{display:flex}
|
|
1096
|
-
/* the rail is a full-width pane here, not the floating overlay the ≤1100 rule makes it */
|
|
1097
|
-
.body[data-float="on"]>.rail,.rail{position:static;width:auto;box-shadow:none;z-index:auto;
|
|
1098
|
-
border-left:0;border-top:0}
|
|
1099
|
-
.railgrip,.side>.edge{display:none} /* edge-drag is a pointer affordance; the switcher owns layout on touch */
|
|
1100
|
-
.cap .grip,.lay-chip{display:none} /* and so is the whole layout control (R9) */
|
|
1101
|
-
.side>.pane{flex:1 1 0}
|
|
1102
|
-
/* one group on a phone, always — the split is a desktop arrangement */
|
|
1103
|
-
.groups{flex-direction:column}
|
|
1104
|
-
.group+.group{display:none}
|
|
1105
|
-
|
|
1106
|
-
/* ── the phone's top bar: back · the screen's name · theme ──────────────────────────────────
|
|
1107
|
-
Safe-area insets at BOTH ends. The shipped rule padded only the bottom, which is half the
|
|
1108
|
-
problem: on a notched device a bar pinned to the top of the viewport sits UNDER the notch, so
|
|
1109
|
-
the back control becomes unpressable. `min-height` includes the inset (box-sizing is
|
|
1110
|
-
border-box everywhere here), so the row itself stays a full 44px below it rather than being
|
|
1111
|
-
squeezed into whatever the notch leaves. The horizontal insets matter in landscape, where the
|
|
1112
|
-
rounded corners eat the two ends of the bar. */
|
|
1113
|
-
.mob{display:block}
|
|
1114
|
-
.mob-bar{display:flex;align-items:center;gap:8px;
|
|
1115
|
-
min-height:44px;padding:0 10px; /* the plain fallback: a browser without env() drops the
|
|
1116
|
-
declaration below entirely, and a bar with no padding at
|
|
1117
|
-
all is worse than one that ignores the notch */
|
|
1118
|
-
min-height:calc(44px + env(safe-area-inset-top));
|
|
1119
|
-
padding:env(safe-area-inset-top) max(10px,env(safe-area-inset-right)) 0 max(10px,env(safe-area-inset-left));
|
|
1120
|
-
background:var(--glass);backdrop-filter:blur(8px);border-bottom:1px solid var(--border)}
|
|
1121
|
-
/* back is `hidden` at a destination root and pops exactly one screen otherwise. It is not
|
|
1122
|
-
disabled-and-inert at a root: a control that looks available and does nothing is the thing
|
|
1123
|
-
this workspace refuses to ship, so it is absent instead. */
|
|
1124
|
-
.mob-back{flex:none;min-width:44px;min-height:44px;margin-left:-6px;
|
|
1125
|
-
color:var(--muted-foreground);font-size:var(--text-lg);line-height:1}
|
|
1126
|
-
.mob-back:active{color:var(--foreground)}
|
|
1127
|
-
/* the title ELLIPSIZES rather than pushing the bar sideways — a session name or a document title
|
|
1128
|
-
is arbitrary length and the two controls beside it must stay where the thumb expects them. */
|
|
1129
|
-
.mob-title{flex:1;min-width:0;font-size:var(--text-base);font-weight:600;letter-spacing:-.01em;
|
|
1130
|
-
color:var(--foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1131
|
-
/* `flex:none` on both trailing controls, so the ellipsizing title above yields to them rather
|
|
1132
|
-
than the other way round — that is what keeps the palette on screen at 390px. */
|
|
1133
|
-
.mob-pal,.mob-theme{flex:none;min-width:44px;min-height:44px;padding:0 8px;
|
|
1134
|
-
color:var(--muted-foreground);font-size:var(--text-xs)}
|
|
1135
|
-
.mob-pal:active,.mob-theme:active{color:var(--foreground)}
|
|
1136
|
-
|
|
1137
|
-
/* the mobile menu: a terminal control bar (terminal screen only) over the destination nav.
|
|
1138
|
-
min-width:0 lets this grid item shrink below its content min-size, so the control bar's
|
|
1139
|
-
fixed-width buttons scroll inside it instead of widening the whole page.
|
|
1140
|
-
The other end of the safe area lives here rather than on the nav, so the control bar gets the
|
|
1141
|
-
insets too — in landscape the rounded corners clip both. */
|
|
1142
|
-
.mobmenu{display:block;min-width:0;background:var(--muted);border-top:1px solid var(--border);
|
|
1143
|
-
padding-bottom:env(safe-area-inset-bottom);
|
|
1144
|
-
padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right)}
|
|
1145
|
-
.ctrlbar{display:none;min-width:0;gap:5px;padding:6px 8px;overflow-x:auto;-webkit-overflow-scrolling:touch;
|
|
1146
|
-
border-bottom:1px solid var(--border)}
|
|
1147
|
-
.mobmenu[data-view="terminal"] .ctrlbar{display:flex}
|
|
1148
|
-
.ctrlbar button{flex:1 0 auto;min-width:44px;min-height:44px;display:grid;place-items:center;
|
|
1149
|
-
border:1px solid var(--border);border-radius:var(--radius-md);background:var(--secondary);color:var(--foreground);
|
|
1150
|
-
font-family:var(--mono);font-size:14px}
|
|
1151
|
-
.ctrlbar button:active{background:var(--accent)}
|
|
1152
|
-
.ctrlbar button[aria-pressed="true"]{border-color:var(--brand);color:var(--brand);background:var(--brand-wash)}
|
|
1153
|
-
.ctrlbar .lbl{font-size:var(--text-xs);letter-spacing:.04em}
|
|
1154
|
-
/* Five destinations. `flex:1 1 0` with `min-width:0` is what lets "scheduled" sit beside four
|
|
1155
|
-
others at 390px: the buttons share the width evenly and a label that still does not fit
|
|
1156
|
-
ellipsizes inside its own button rather than widening the row. No glyph child — the LABEL is
|
|
1157
|
-
the affordance, and a five-way icon row on a phone is a guessing game. */
|
|
1158
|
-
.mobnav{display:flex;min-width:0}
|
|
1159
|
-
.mobnav-b{flex:1 1 0;min-width:0;min-height:52px;padding:0 4px;background:var(--muted);
|
|
1160
|
-
border-top:2px solid transparent;color:var(--muted-foreground);font-size:var(--text-2xs);
|
|
1161
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1162
|
-
.mobnav-b+.mobnav-b{border-left:1px solid var(--border)}
|
|
1163
|
-
/* current is carried on THREE channels — the top bar (a shape), the weight, and the hue — so
|
|
1164
|
-
which destination you are on survives being read without colour. */
|
|
1165
|
-
.mobnav-b[aria-current="page"]{color:var(--brand);border-top-color:var(--brand);
|
|
1166
|
-
background:var(--accent);font-weight:600}
|
|
1167
|
-
@media (prefers-reduced-motion:reduce){.mobnav-b,.ctrlbar button{transition:none}}
|
|
1168
|
-
|
|
1169
|
-
/* the header must fit a phone: drop the desktop "workspace" tag and let the status text ellipsize */
|
|
1170
|
-
.bar{gap:7px;padding:0 10px}
|
|
1171
|
-
.bar .sub{display:none}
|
|
1172
|
-
.bar .conn{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}
|
|
1173
|
-
/* the strip's right half is a list of KEYBOARD hints (⌘K, F2, Esc) — on a phone it advertises
|
|
1174
|
-
keys that are not there, so the connection state gets the whole strip instead */
|
|
1175
|
-
.strip .right{display:none}
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
/* R8 — hover-only reveals. `opacity:0` plus a `:hover` rule leaves a touch user with a control
|
|
1179
|
-
that exists, is focusable, and can never be seen: there is no hover to trigger. A coarse pointer
|
|
1180
|
-
gets them at full opacity instead.
|
|
1181
|
-
Keyed on (hover:none) rather than on a width, because a tablet at 900px has no hover either —
|
|
1182
|
-
this is a property of the POINTER, and tying it to the phone breakpoint would leave exactly the
|
|
1183
|
-
devices in between broken. Both `.wsrow .forget` and `.treerow .forget` are listed: the first is
|
|
1184
|
-
the repo row's affordance and the second is the tree row's, and which of the two survives
|
|
1185
|
-
§4.3's deletion of renderWorkspaces is not decidable from this file. */
|
|
1186
|
-
@media (hover:none){
|
|
1187
|
-
.wsrow .forget,.treerow .forget,.sessrow .ren{opacity:1}
|
|
1188
|
-
}
|
|
1189
|
-
|
|
1190
|
-
/* ── console surfaces (D64 Track B): needs-you · radar · metrics over file-mode state ────────── */
|
|
1191
|
-
/* Honesty by construction: error is unmistakably RED (--bad), empty is CALM (--teal), the loading
|
|
1192
|
-
skeleton (.sf-skel, reused) is neither. A broken read can only ever draw .cs-error. */
|
|
1193
|
-
.cs-error{border:1px solid var(--destructive);border-radius:var(--radius-xl);padding:16px 18px;
|
|
1194
|
-
background:radial-gradient(120% 140% at 0 0,rgba(242,101,95,.14),transparent 60%),var(--card)}
|
|
1195
|
-
.cs-err-head{display:flex;align-items:center;gap:9px}
|
|
1196
|
-
.cs-err-head .mk{width:22px;height:22px;display:grid;place-items:center;border-radius:var(--radius-md);
|
|
1197
|
-
background:var(--destructive);color:white;font-size:var(--text-sm);flex:none}
|
|
1198
|
-
.cs-err-head b{font-size:var(--text-base);color:var(--destructive)}
|
|
1199
|
-
.cs-err-why{margin-top:8px;font-size:var(--text-sm);color:var(--foreground);line-height:1.5}
|
|
1200
|
-
.cs-err-note{margin-top:7px;font-family:var(--mono);font-size:var(--text-xs);color:var(--destructive);opacity:.9;line-height:1.5}
|
|
1201
|
-
.cs-empty{border:1px solid var(--info);border-radius:var(--radius-xl);padding:16px 18px;
|
|
1202
|
-
background:radial-gradient(120% 140% at 0 0,var(--info-wash),transparent 60%),var(--card)}
|
|
1203
|
-
.cs-empty>.dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--info);
|
|
1204
|
-
box-shadow:0 0 0 4px var(--info-wash);margin-right:8px;vertical-align:middle}
|
|
1205
|
-
.cs-empty b{font-size:var(--text-base);color:var(--foreground)}
|
|
1206
|
-
.cs-empty p{margin-top:6px;font-size:var(--text-sm);color:var(--muted-foreground);line-height:1.5}
|
|
1207
|
-
.cs-empty-note{font-family:var(--mono);font-size:var(--text-xs);color:var(--info);opacity:.85}
|
|
1208
|
-
.cs-src{font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
1209
|
-
.sf-chip.src::before{background:var(--info)}
|
|
1210
|
-
/* needs-you */
|
|
1211
|
-
.cs-needs{border:1px solid var(--warning);border-radius:var(--radius-xl);overflow:hidden;
|
|
1212
|
-
background:radial-gradient(120% 140% at 0 0,var(--warning-wash),transparent 60%),var(--card)}
|
|
1213
|
-
.cs-needs .cs-h,.cs-wm .cs-h,.cs-per .cs-h{display:flex;align-items:center;gap:9px;padding:12px 15px 9px}
|
|
1214
|
-
.cs-needs .cs-h .dot{width:8px;height:8px;border-radius:50%;background:var(--warning);flex:none;box-shadow:0 0 0 4px var(--warning-wash)}
|
|
1215
|
-
.cs-h b{font-size:var(--text-base);color:var(--foreground)}
|
|
1216
|
-
.cs-h .src{font-size:var(--text-xs);color:var(--muted-foreground);margin-left:auto}
|
|
1217
|
-
.cs-need{display:flex;align-items:center;gap:11px;padding:10px 15px;border-top:1px solid var(--border)}
|
|
1218
|
-
.cs-need .ph{width:3px;align-self:stretch;border-radius:var(--radius-sm);background:var(--warning);flex:none}
|
|
1219
|
-
.cs-need[data-kind="accept"] .ph{background:var(--brand)}
|
|
1220
|
-
.cs-need .txt{flex:1;min-width:0}
|
|
1221
|
-
.cs-need .t{font-size:var(--text-sm);color:var(--foreground);line-height:1.45}
|
|
1222
|
-
.cs-need .m{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);margin-top:3px}
|
|
1223
|
-
/* radar + metrics cards */
|
|
1224
|
-
.cs-cards{display:flex;gap:12px;flex-wrap:wrap;margin:10px 0 4px}
|
|
1225
|
-
.cs-card{flex:1;min-width:150px;border:1px solid var(--border);border-radius:var(--radius-lg);background:var(--card);padding:13px 15px}
|
|
1226
|
-
.cs-card.warnedge{border-color:var(--warning)}
|
|
1227
|
-
.cs-card h4{font-size:var(--text-xs);color:var(--muted-foreground);margin-bottom:7px}
|
|
1228
|
-
.cs-big{font-size:26px;font-weight:600;color:var(--foreground);line-height:1;display:flex;align-items:baseline;gap:6px}
|
|
1229
|
-
.cs-big .u{font-size:var(--text-xs);font-weight:400;color:var(--muted-foreground);font-family:var(--mono)}
|
|
1230
|
-
.cs-sub{margin-top:7px;font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.5}
|
|
1231
|
-
.cs-caveat{margin-top:8px;font-size:var(--text-xs);color:var(--warning);line-height:1.5;border-top:1px solid var(--border);padding-top:7px}
|
|
1232
|
-
.cs-wm{margin-top:12px;border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden;background:var(--card)}
|
|
1233
|
-
.cs-wm .cs-h .dot{width:8px;height:8px;border-radius:50%;flex:none}
|
|
1234
|
-
.cs-wm .cs-h .dot.ok{background:var(--success);box-shadow:0 0 0 4px var(--info-wash)}
|
|
1235
|
-
.cs-wm .cs-h .dot.warn{background:var(--warning);box-shadow:0 0 0 4px var(--warning-wash)}
|
|
1236
|
-
.cs-wmrow{display:flex;align-items:center;gap:10px;padding:8px 15px;border-top:1px solid var(--border)}
|
|
1237
|
-
.cs-wmrow .rag{width:9px;height:9px;border-radius:50%;flex:none;background:var(--muted-foreground)}
|
|
1238
|
-
.cs-wmrow .rag.rag-green{background:var(--success)}
|
|
1239
|
-
.cs-wmrow .rag.rag-amber{background:var(--warning)}
|
|
1240
|
-
.cs-wmrow .rag.rag-red{background:var(--destructive)}
|
|
1241
|
-
.cs-wmrow .nm{flex:1;min-width:0;font-size:var(--text-sm);color:var(--foreground);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
1242
|
-
.cs-wmrow .nm .ti{color:var(--muted-foreground);margin-left:7px;font-size:var(--text-xs)}
|
|
1243
|
-
.cs-wmrow .st{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);flex:none}
|
|
1244
|
-
.cs-none,.cs-per .cs-none{padding:10px 15px;font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
1245
|
-
.cs-per{margin-top:12px;border:1px solid var(--border);border-radius:var(--radius-lg);overflow:hidden;background:var(--card)}
|
|
1246
|
-
.cs-perrow{display:flex;align-items:center;gap:10px;padding:6px 15px;border-top:1px solid var(--border)}
|
|
1247
|
-
.cs-perrow .nm{width:40%;min-width:0;font-size:var(--text-sm);color:var(--foreground);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
1248
|
-
.cs-perrow .bar{flex:1;height:6px;border-radius:var(--radius-sm);background:var(--secondary);overflow:hidden}
|
|
1249
|
-
.cs-perrow .bar i{display:block;height:100%;background:var(--brand);border-radius:var(--radius-sm)}
|
|
1250
|
-
.cs-perrow .v{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);flex:none;width:28px;text-align:right}
|
|
1251
|
-
|
|
1252
|
-
/* ── workflow ladder (workflow-enforcement) ──────────────────────────────────────────────────
|
|
1253
|
-
Where each in-flight initiative is, what is next, and what is blocking. Status is carried by a
|
|
1254
|
-
glyph AND a colour, never by colour alone — the whole surface has to survive being read by
|
|
1255
|
-
someone who cannot separate the red from the green, and `blocked` is the state that must never
|
|
1256
|
-
be missed. `unknown` is styled as its own thing rather than a dim `done`, because collapsing the
|
|
1257
|
-
two is precisely the false green this surface exists to prevent. */
|
|
1258
|
-
.cs-workflow>.cs-h{display:flex;align-items:center;gap:9px;padding:0 0 10px}
|
|
1259
|
-
.cs-workflow>.cs-h .dot{width:8px;height:8px;border-radius:50%;background:var(--success);flex:none;box-shadow:0 0 0 4px var(--info-wash)}
|
|
1260
|
-
.cs-workflow>.cs-h .dot.warn{background:var(--warning);box-shadow:0 0 0 4px var(--warning-wash)}
|
|
1261
|
-
.wf-degraded{border:1px solid var(--warning);border-radius:var(--radius-lg);background:var(--warning-wash);
|
|
1262
|
-
padding:10px 14px;margin-bottom:12px;font-size:var(--text-sm);color:var(--foreground);line-height:1.55}
|
|
1263
|
-
.wf-degraded b{color:var(--warning)}
|
|
1264
|
-
.wf-card{border:1px solid var(--border);border-radius:var(--radius-xl);background:var(--card);
|
|
1265
|
-
overflow:hidden;margin-bottom:12px}
|
|
1266
|
-
.wf-card[data-blocked="1"]{border-color:var(--destructive)}
|
|
1267
|
-
.wf-top{display:flex;align-items:center;gap:9px;padding:12px 15px 9px}
|
|
1268
|
-
.wf-id{font-family:var(--mono);font-size:var(--text-sm);color:var(--foreground);background:none;border:0;
|
|
1269
|
-
padding:0;cursor:pointer;text-align:left}
|
|
1270
|
-
.wf-id:hover{color:var(--brand);text-decoration:underline}
|
|
1271
|
-
.wf-lane{font-family:var(--mono);font-size:var(--text-xs);
|
|
1272
|
-
color:var(--muted-foreground);border:1px solid var(--border);border-radius:var(--radius-sm);padding:2px 7px;background:var(--secondary)}
|
|
1273
|
-
.wf-here{font-family:var(--mono);font-size:var(--text-2xs);
|
|
1274
|
-
color:var(--brand);border:1px solid var(--brand);border-radius:var(--radius-sm);padding:2px 7px;
|
|
1275
|
-
background:var(--brand-wash)}
|
|
1276
|
-
.wf-more{margin-top:2px;padding:10px 15px;border:1px dashed var(--input);border-radius:var(--radius-lg);
|
|
1277
|
-
font-size:var(--text-sm);color:var(--muted-foreground);line-height:1.5}
|
|
1278
|
-
.wf-anchor{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);margin-left:auto;
|
|
1279
|
-
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:45%}
|
|
1280
|
-
.wf-rail{display:flex;align-items:center;gap:5px;padding:0 15px 11px;flex-wrap:wrap}
|
|
1281
|
-
.wf-st{font-family:var(--mono);font-size:var(--text-xs);letter-spacing:.05em;color:var(--muted-foreground)}
|
|
1282
|
-
.wf-st.past{color:var(--muted-foreground)}
|
|
1283
|
-
.wf-st.at{color:var(--foreground);border-bottom:2px solid var(--brand);padding-bottom:1px}
|
|
1284
|
-
.wf-sep{width:12px;height:1px;background:var(--input);flex:none}
|
|
1285
|
-
.wf-steps{border-top:1px solid var(--border)}
|
|
1286
|
-
.wf-step{display:flex;align-items:baseline;gap:9px;padding:5px 15px}
|
|
1287
|
-
.wf-g{font-family:var(--mono);font-size:var(--text-xs);width:11px;flex:none;text-align:center;color:var(--muted-foreground)}
|
|
1288
|
-
.wf-step[data-st="done"] .wf-g{color:var(--success)}
|
|
1289
|
-
.wf-step[data-st="blocked"] .wf-g{color:var(--destructive)}
|
|
1290
|
-
.wf-step[data-st="unknown"] .wf-g{color:var(--warning)}
|
|
1291
|
-
.wf-k{font-family:var(--mono);font-size:var(--text-xs);width:74px;flex:none;color:var(--muted-foreground)}
|
|
1292
|
-
.wf-step[data-st="na"] .wf-k,.wf-step[data-st="pending"] .wf-k{color:var(--muted-foreground)}
|
|
1293
|
-
.wf-step[data-st="blocked"] .wf-k{color:var(--destructive)}
|
|
1294
|
-
.wf-e{flex:1;min-width:0;font-size:var(--text-sm);color:var(--muted-foreground);line-height:1.5}
|
|
1295
|
-
.wf-step[data-st="na"] .wf-e,.wf-step[data-st="pending"] .wf-e{color:var(--muted-foreground)}
|
|
1296
|
-
.wf-rule{font-family:var(--mono);font-size:var(--text-2xs);border:1px solid var(--destructive);border-radius:var(--radius-sm);
|
|
1297
|
-
padding:1px 5px;color:var(--destructive);margin-left:5px}
|
|
1298
|
-
.wf-next{padding:0 15px 6px 109px;font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.5}
|
|
1299
|
-
.wf-next[data-st="blocked"]{color:var(--warning)}
|
|
1300
|
-
.wf-do{border-top:1px solid var(--border);padding:10px 15px;font-size:var(--text-sm);color:var(--foreground);
|
|
1301
|
-
line-height:1.5;background:var(--warning-wash)}
|
|
1302
|
-
.wf-do b{font-family:var(--mono);font-size:var(--text-xs);
|
|
1303
|
-
color:var(--warning);margin-right:8px}
|
|
1304
|
-
.wf-do.ok{background:var(--info-wash)}
|
|
1305
|
-
.wf-do.ok b{color:var(--success)}
|
|
1306
|
-
|
|
1307
|
-
/* ── branch awareness (workspace-session-controls) ── */
|
|
1308
|
-
/* the branch name IS a git ref — mono. shadcn Badge `secondary`: a filled --muted chip with no
|
|
1309
|
-
border, so a long branch name sits quietly beside the product mark instead of drawing a box
|
|
1310
|
-
around itself. */
|
|
1311
|
-
.bar .branch{font-family:var(--mono);font-size:var(--text-2xs);color:var(--muted-foreground);
|
|
1312
|
-
padding:3px 8px;border:0;border-radius:var(--radius-sm);background:var(--muted);
|
|
1313
|
-
white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:26ch}
|
|
1314
|
-
.bar .branch[hidden]{display:none}
|
|
1315
|
-
/* a dirty tree is a real signal, but it is ambient — it tints the chip, it does not outline it */
|
|
1316
|
-
.bar .branch.dirty{color:var(--warning);background:var(--warning-wash)}
|
|
1317
|
-
|
|
1318
|
-
/* worktree housekeeping — folded away until a repo actually has extra working trees */
|
|
1319
|
-
.wtbox{margin-top:8px;font-size:var(--text-xs)}
|
|
1320
|
-
.wtbox[hidden]{display:none}
|
|
1321
|
-
.wtbox>summary{cursor:pointer;color:var(--muted-foreground);padding:3px 2px;list-style:none;
|
|
1322
|
-
display:flex;align-items:center;gap:5px}
|
|
1323
|
-
.wtbox>summary::-webkit-details-marker{display:none}
|
|
1324
|
-
.wtbox>summary:hover{color:var(--foreground)}
|
|
1325
|
-
.wtrow{display:flex;align-items:baseline;gap:6px;padding:4px 2px;border-top:1px solid var(--border)}
|
|
1326
|
-
/* a worktree row names a BRANCH and a PATH — mono earns its place */
|
|
1327
|
-
.wtrow .wtb{font-family:var(--mono);color:var(--foreground);flex:1;min-width:0;overflow-wrap:anywhere}
|
|
1328
|
-
.wtrow .wtwhy{color:var(--muted-foreground);font-size:var(--text-2xs);flex-basis:100%;line-height:1.35}
|
|
1329
|
-
/* shadcn Button, `outline` variant at the small size */
|
|
1330
|
-
.wtrow button{flex:none;border:1px solid var(--input);border-radius:var(--radius-sm);background:transparent;
|
|
1331
|
-
color:var(--foreground);font-size:var(--text-2xs);padding:2px 7px;cursor:pointer;
|
|
1332
|
-
transition:border-color var(--duration-fast) var(--ease-emphasized),
|
|
1333
|
-
color var(--duration-fast) var(--ease-emphasized)}
|
|
1334
|
-
/* removing a worktree deletes a folder — the hover states that intent in the warning hue */
|
|
1335
|
-
.wtrow button:hover:not(:disabled){border-color:var(--warning);color:var(--warning)}
|
|
1336
|
-
.wtrow button:disabled{opacity:.4;cursor:not-allowed}
|
|
1337
|
-
|
|
1338
|
-
/* new-session branch picker — matches the miniform vocabulary */
|
|
1339
|
-
.brwrap{display:flex;flex-direction:column;gap:6px}
|
|
1340
|
-
.brwrap[hidden]{display:none}
|
|
1341
|
-
.brwrap select{min-height:38px;padding:0 8px;border:1px solid var(--input);border-radius:var(--radius-md);
|
|
1342
|
-
background:var(--secondary);color:var(--foreground);font-family:var(--mono);font-size:var(--text-xs)}
|
|
1343
|
-
.brwrap select:focus{border-color:var(--brand)}
|
|
1344
|
-
.brwrap input[hidden]{display:none}
|
|
1345
|
-
.miniform .hint.warn{color:var(--warning)}
|
|
1346
|
-
.miniform .hint[hidden]{display:none}
|
|
1347
|
-
.miniform .lbl .opt{color:var(--muted-foreground);font-weight:400}
|
|
1348
|
-
/* the isolate toggle: the difference between "this session gets a branch" and "the whole repo
|
|
1349
|
-
moves" is one line, so it reads as a sentence rather than a settings row */
|
|
1350
|
-
.brwrap .chk{display:flex;align-items:flex-start;gap:7px;font-size:var(--text-xs);color:var(--foreground);
|
|
1351
|
-
line-height:1.35;cursor:pointer}
|
|
1352
|
-
.brwrap .chk[hidden]{display:none}
|
|
1353
|
-
/* accent-color paints the native checkbox — that is a FILL, so it takes --primary (the brand
|
|
1354
|
-
fill) and not --accent, which under this palette is the muted hover surface. */
|
|
1355
|
-
.brwrap .chk input{flex:none;margin:1px 0 0;accent-color:var(--primary);cursor:pointer}
|
|
1356
|
-
|
|
1357
|
-
/* ── scratchpad drawer: bottom of the terminal column, collapsible, never overlays anything ── */
|
|
1358
|
-
.scratch{flex:none;border-top:1px solid var(--border);background:var(--sidebar);display:flex;flex-direction:column;min-height:0}
|
|
1359
|
-
.scratch-head{display:flex;align-items:center;gap:8px;padding:5px 10px;min-height:34px;
|
|
1360
|
-
background:var(--muted);border-bottom:1px solid transparent}
|
|
1361
|
-
.scratch[data-open="true"] .scratch-head{border-bottom-color:var(--border)}
|
|
1362
|
-
.scratch-toggle{display:inline-flex;align-items:center;gap:7px;border:0;background:none;
|
|
1363
|
-
font-size:var(--text-2xs);color:var(--muted-foreground);cursor:pointer}
|
|
1364
|
-
.scratch-toggle:hover{color:var(--foreground)}
|
|
1365
|
-
.scratch-toggle .chev{display:inline-block;transition:transform .15s;font-size:var(--text-2xs)}
|
|
1366
|
-
.scratch[data-open="true"] .scratch-toggle .chev{transform:rotate(180deg)}
|
|
1367
|
-
/* whose pad this is — the pad is per TAB, so the drawer names the tab it is staging for */
|
|
1368
|
-
.scratch-who{font-family:var(--mono);font-size:var(--text-xs);color:var(--foreground);letter-spacing:.04em;
|
|
1369
|
-
max-width:22ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1370
|
-
.scratch-who:not(:empty)::before{content:"· "}
|
|
1371
|
-
.scratch-status{font-family:var(--mono);font-size:var(--text-xs);color:var(--muted-foreground);letter-spacing:.04em}
|
|
1372
|
-
.scratch-actions{margin-left:auto;display:flex;gap:6px}
|
|
1373
|
-
.scratch-actions .mini{min-height:28px;padding:0 10px;border:1px solid var(--border);border-radius:var(--radius-md);
|
|
1374
|
-
background:var(--secondary);color:var(--brand);font-family:var(--mono);font-size:var(--text-xs);letter-spacing:0;cursor:pointer}
|
|
1375
|
-
.scratch-actions .mini:hover{border-color:var(--brand)}
|
|
1376
|
-
.scratch-actions .mini:disabled{color:var(--muted-foreground);border-color:var(--border);cursor:not-allowed;opacity:.6}
|
|
1377
|
-
.scratch-text{display:none;width:100%;box-sizing:border-box;resize:vertical;height:22vh;min-height:90px;max-height:45vh;
|
|
1378
|
-
border:0;padding:10px 12px;background:var(--term-bg);color:var(--foreground);
|
|
1379
|
-
font-family:var(--mono);font-size:var(--text-sm);line-height:1.5;outline:none}
|
|
1380
|
-
.scratch[data-open="true"] .scratch-text{display:block}
|
|
1381
|
-
|
|
1382
|
-
/* The cap's controls carry TEXT labels, not icons, so they size to content. And `hidden` has to
|
|
1383
|
-
actually hide: `.cap .mini` sets display:grid, which beats the UA's [hidden]{display:none} — the
|
|
1384
|
-
attribute was being set correctly and doing nothing, so every control showed at once. Only the
|
|
1385
|
-
first control takes the margin-left:auto that pushes the group right. */
|
|
1386
|
-
.cap .mini[hidden],.cap .x[hidden]{display:none}
|
|
1387
|
-
.cap .docrev{width:auto;min-width:0;padding:0 9px;font-size:var(--text-xs)}
|
|
1388
|
-
.cap .mini ~ .mini{margin-left:0}
|
|
1389
|
-
|
|
1390
|
-
/* ── the document editor (workspace-doc-editor) ──────────────────────────────────────────────
|
|
1391
|
-
The reader gains an edit mode. Quiet on purpose: editing a document should feel local and
|
|
1392
|
-
undramatic, so there is no toolbar, no modal, and no mode banner — a control in the cap, a
|
|
1393
|
-
textarea in the reader's own type, and the diff shown beside it as you type. */
|
|
1394
|
-
.ed-wrap{display:grid;grid-template-rows:minmax(0,1fr) auto;height:100%;min-height:0}
|
|
1395
|
-
.ed-split{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:0;min-height:0;overflow:hidden}
|
|
1396
|
-
.ed-split[data-diff="off"]{grid-template-columns:minmax(0,1fr)}
|
|
1397
|
-
.ed-split[data-diff="off"] .ed-diff{display:none}
|
|
1398
|
-
.ed-ta{width:100%;height:100%;box-sizing:border-box;resize:none;border:0;outline:none;
|
|
1399
|
-
padding:14px 16px;background:var(--background);color:var(--foreground);
|
|
1400
|
-
font-family:var(--mono);font-size:var(--text-sm);line-height:1.8;tab-size:2}
|
|
1401
|
-
.ed-diff{border-left:1px solid var(--border);overflow-y:auto;background:var(--sidebar);
|
|
1402
|
-
font-family:var(--mono);font-size:var(--text-xs);line-height:1.75;padding:8px 0}
|
|
1403
|
-
.ed-l{display:grid;grid-template-columns:3px 1fr;align-items:start}
|
|
1404
|
-
.ed-l .g{align-self:stretch;border-radius:var(--radius-sm);background:transparent}
|
|
1405
|
-
.ed-l .t{padding:0 10px;white-space:pre-wrap;word-break:break-word;color:var(--muted-foreground)}
|
|
1406
|
-
.ed-l.del .g{background:var(--destructive)}
|
|
1407
|
-
.ed-l.del .t{color:var(--muted-foreground);text-decoration:line-through;text-decoration-color:rgba(242,101,95,.5)}
|
|
1408
|
-
.ed-l.add .g{background:var(--success)}
|
|
1409
|
-
.ed-l.add .t{color:var(--foreground)}
|
|
1410
|
-
.ed-l.ctx .t{color:var(--muted-foreground)}
|
|
1411
|
-
.ed-none{padding:14px 16px;font-size:var(--text-sm);color:var(--muted-foreground);line-height:1.6}
|
|
1412
|
-
.ed-bar{display:flex;align-items:center;gap:12px;padding:8px 14px;border-top:1px solid var(--border);
|
|
1413
|
-
background:var(--muted);font-size:var(--text-sm);color:var(--muted-foreground)}
|
|
1414
|
-
.ed-bar .n{font-family:var(--mono)}
|
|
1415
|
-
.ed-bar .n b{color:var(--success);font-weight:600}
|
|
1416
|
-
.ed-bar .n i{color:var(--destructive);font-style:normal;font-weight:600}
|
|
1417
|
-
.ed-bar input{flex:1;min-width:80px;border:1px solid var(--border);border-radius:var(--radius-md);
|
|
1418
|
-
padding:6px 10px;background:var(--secondary);color:var(--foreground);font-family:var(--sans);
|
|
1419
|
-
font-size:var(--text-sm);outline:none}
|
|
1420
|
-
.ed-bar input:focus{border-color:var(--brand)}
|
|
1421
|
-
.ed-bar .dirty{color:var(--warning)}
|
|
1422
|
-
.ed-err{margin:0 14px 8px;padding:8px 11px;border-radius:var(--radius-md);border:1px solid var(--destructive);
|
|
1423
|
-
background:rgba(242,101,95,.08);font-size:var(--text-sm);line-height:1.5;color:var(--foreground)}
|
|
1424
|
-
|
|
1425
|
-
/* the change log for one document — read, not managed */
|
|
1426
|
-
.hist{padding:16px 18px;max-width:640px}
|
|
1427
|
-
.hist h3{font-size:14px;font-weight:600;margin-bottom:3px}
|
|
1428
|
-
.hist .sub{font-size:var(--text-sm);color:var(--muted-foreground);margin-bottom:18px;line-height:1.6}
|
|
1429
|
-
.hist-row{padding:11px 0;border-top:1px solid var(--border)}
|
|
1430
|
-
.hist-row:first-of-type{border-top:0}
|
|
1431
|
-
.hist-when{font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
1432
|
-
.hist-when b{color:var(--success);font-weight:600}
|
|
1433
|
-
.hist-when i{color:var(--destructive);font-style:normal;font-weight:600}
|
|
1434
|
-
.hist-note{margin-top:4px;font-size:var(--text-sm);color:var(--foreground);line-height:1.55}
|
|
1435
|
-
.hist-none{font-size:var(--text-sm);color:var(--muted-foreground);line-height:1.6}
|
|
1436
|
-
|
|
1437
|
-
/* ── alignment (workspace-doc-editor R5–R7) ──────────────────────────────────────────────────
|
|
1438
|
-
Downstream of a save and offered, never blocking. The offer is one line that can be dismissed;
|
|
1439
|
-
nothing accumulates and nothing badges.
|
|
1440
|
-
Tokens follow the radix-sera port: --brand is the blue for text/borders, --primary is for fills,
|
|
1441
|
-
and --accent is a muted hover surface, not a hue. Radii come from the scale — never a px. */
|
|
1442
|
-
.al-offer{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:12px 14px;padding:10px 12px;
|
|
1443
|
-
border-radius:var(--radius-md);background:var(--brand-wash);border:1px solid var(--brand);
|
|
1444
|
-
font-size:var(--text-sm);line-height:1.5;color:var(--foreground)}
|
|
1445
|
-
.al-offer button{font-size:var(--text-sm);color:var(--brand);padding:2px 0}
|
|
1446
|
-
.al-offer button:hover{text-decoration:underline}
|
|
1447
|
-
.al-offer button.q{color:var(--muted-foreground);margin-left:auto}
|
|
1448
|
-
.al{padding:16px 18px 40px;max-width:660px}
|
|
1449
|
-
.al-lede{font-size:var(--text-base);line-height:1.5;color:var(--foreground);margin-bottom:5px}
|
|
1450
|
-
.al-sub{font-size:var(--text-sm);line-height:1.6;color:var(--muted-foreground);margin-bottom:16px}
|
|
1451
|
-
.al-c{display:flex;gap:9px;align-items:flex-start;padding:9px 0;border-top:1px solid var(--border);cursor:pointer}
|
|
1452
|
-
.al-c:first-of-type{border-top:0}
|
|
1453
|
-
.al-c input{margin-top:3px;accent-color:var(--primary);width:15px;height:15px;flex:none}
|
|
1454
|
-
.al-p{font-size:var(--text-sm);color:var(--foreground);display:block;word-break:break-all}
|
|
1455
|
-
.al-why{display:block;margin-top:2px;font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.5}
|
|
1456
|
-
.al-acts{display:flex;gap:15px;align-items:center;flex-wrap:wrap;margin-top:14px}
|
|
1457
|
-
.al-acts button{font-size:var(--text-sm);color:var(--brand);padding:3px 0;min-height:30px}
|
|
1458
|
-
.al-acts button:hover{text-decoration:underline}
|
|
1459
|
-
.al-acts button.q{color:var(--muted-foreground)}
|
|
1460
|
-
.al-acts button:disabled{color:var(--muted-foreground);text-decoration:none;cursor:default}
|
|
1461
|
-
.al-note{font-size:var(--text-xs);color:var(--muted-foreground)}
|
|
1462
|
-
.al-d{padding:13px 0;border-top:1px solid var(--border)}
|
|
1463
|
-
.al-d.done{opacity:.45}
|
|
1464
|
-
.al-d.done .al-code,.al-d.done .al-acts{display:none}
|
|
1465
|
-
.al-d.done .al-p::after{content:" · settled";color:var(--success);font-family:var(--sans);font-size:var(--text-xs)}
|
|
1466
|
-
.al-code{margin-top:9px;font-family:var(--mono);font-size:var(--text-xs);line-height:1.75;
|
|
1467
|
-
border-top:1px solid var(--border);border-bottom:1px solid var(--border);padding:6px 0}
|
|
1468
|
-
.al-err{margin-top:9px;padding:8px 11px;border-radius:var(--radius-md);border:1px solid var(--destructive);
|
|
1469
|
-
background:rgba(242,101,95,.08);font-size:var(--text-sm);line-height:1.5;color:var(--foreground)}
|
|
1470
|
-
|
|
1471
|
-
/* ── The sidebar tree (workspace-initiative-nav-build, R1–R6) ─────────────────────────────────
|
|
1472
|
-
Repository → its working trees, each labelled by the initiative on its branch → sessions.
|
|
1473
|
-
Replaces the old `workspaces` + `running agents` pair. Session-row styles are reused verbatim
|
|
1474
|
-
from that pane — only the nesting is new. Colours go through the D38 semantic tokens: a hex
|
|
1475
|
-
fallback here would be a second source of truth for a value the token layer owns, which is the
|
|
1476
|
-
drift `token-hygiene` exists to catch. */
|
|
1477
|
-
.repo-group{margin-bottom:6px}
|
|
1478
|
-
.repo-head{display:flex;align-items:center;gap:6px;width:100%;padding:4px 8px;background:none;
|
|
1479
|
-
border:0;color:var(--foreground);font:inherit;font-weight:600;font-size:var(--text-xs);
|
|
1480
|
-
cursor:default;text-align:left}
|
|
1481
|
-
.repo-head .cue{color:var(--muted-foreground);font-size:var(--text-2xs)}
|
|
1482
|
-
.repo-head small{margin-left:auto;color:var(--muted-foreground);font-family:var(--mono);font-size:var(--text-2xs)}
|
|
1483
|
-
|
|
1484
|
-
.treerow{border-left:2px solid transparent}
|
|
1485
|
-
.treerow[data-open="true"]{border-left-color:var(--border)}
|
|
1486
|
-
.tr-head{display:flex;align-items:flex-start}
|
|
1487
|
-
.tr-toggle{background:none;border:0;color:var(--muted-foreground);cursor:pointer;
|
|
1488
|
-
padding:6px 2px 6px 8px;font:inherit;line-height:1.2}
|
|
1489
|
-
.tr-toggle .cue{font-size:var(--text-2xs)}
|
|
1490
|
-
.tr{flex:1;min-width:0;display:block;text-align:left;background:none;border:0;color:inherit;
|
|
1491
|
-
font:inherit;padding:5px 6px 6px 0;cursor:pointer}
|
|
1492
|
-
.tr:hover,.tr-head:hover .tr{background:var(--accent)}
|
|
1493
|
-
.tr[aria-current="true"]{background:var(--accent);font-weight:500}
|
|
1494
|
-
.tr .r1{display:flex;align-items:baseline;gap:6px}
|
|
1495
|
-
.tr .r1 .g{font-size:var(--text-2xs);width:9px;flex:none}
|
|
1496
|
-
.treerow[data-st="working"] .r1 .g{color:var(--success)}
|
|
1497
|
-
.treerow[data-st="quiet"] .r1 .g,
|
|
1498
|
-
.treerow[data-st="idle"] .r1 .g,
|
|
1499
|
-
.treerow[data-st="exited"] .r1 .g{color:var(--muted-foreground)}
|
|
1500
|
-
.treerow[data-st="blocked"] .r1 .g{color:var(--destructive)}
|
|
1501
|
-
.tr .r1 .nm{font-size:var(--text-xs);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1502
|
-
.tr .r1 .dir{margin-left:auto;flex:none;font-family:var(--mono);font-size:var(--text-2xs);
|
|
1503
|
-
color:var(--muted-foreground)}
|
|
1504
|
-
.tr .r2{display:flex;flex-wrap:wrap;gap:6px;align-items:baseline;padding-left:15px;margin-top:2px;
|
|
1505
|
-
font-family:var(--mono);font-size:var(--text-2xs);color:var(--muted-foreground)}
|
|
1506
|
-
.tr .wf{display:inline-flex;gap:6px;align-items:baseline}
|
|
1507
|
-
.tr .wf .lane{color:var(--muted-foreground)}
|
|
1508
|
-
.tr .wf .stg{color:var(--brand)}
|
|
1509
|
-
.tr .wf .nx{color:var(--muted-foreground)}
|
|
1510
|
-
/* THE THREE-VALUED VOCABULARY (R2). Two renderings for three facts means one is always mislabelled
|
|
1511
|
-
— which is how an ordinary folder came to render as an alarm on the same surface that uses
|
|
1512
|
-
--destructive for a corrupt state queue. `.bl` keeps the alarm; `.gone` is the quiet, specific
|
|
1513
|
-
"the read succeeded and there is nothing here"; a value is styled as neither. */
|
|
1514
|
-
.tr .wf .bl,.tr .r2 .bl{color:var(--destructive)}
|
|
1515
|
-
.tr .wf .gone,.tr .r2 .gone{color:var(--muted-foreground);opacity:.8}
|
|
1516
|
-
.tr .wf .drv{color:var(--muted-foreground);font-style:italic}
|
|
1517
|
-
.tr .needs-n{color:var(--warning)}
|
|
1518
|
-
.tr .rollup{color:var(--muted-foreground)}
|
|
1519
|
-
/* R5 — the branch a ladder was derived from, and when. Never optional when a stage is shown. */
|
|
1520
|
-
.tr .attrib{display:block;padding-left:15px;margin-top:2px;font-family:var(--mono);
|
|
1521
|
-
font-size:var(--text-2xs);color:var(--muted-foreground)}
|
|
1522
|
-
.tr .attrib b{color:var(--foreground);font-weight:500}
|
|
1523
|
-
.tr-sessions{padding-left:14px}
|
|
1524
|
-
.tree-new{display:block;width:calc(100% - 8px);margin:2px 0 6px 4px;padding:4px 8px;background:none;
|
|
1525
|
-
border:1px dashed var(--border);border-radius:var(--radius-sm);color:var(--muted-foreground);
|
|
1526
|
-
font:inherit;font-size:var(--text-2xs);cursor:pointer;text-align:left}
|
|
1527
|
-
.tree-new:hover{color:var(--foreground);border-color:var(--input)}
|
|
1528
|
-
/* R5 — the composer's target. "run an agent here" named nothing once every repository was on
|
|
1529
|
-
screen at once; this is the referent, and it updates on every selection change. */
|
|
1530
|
-
.miniform .where{font-family:var(--mono);font-size:var(--text-2xs);color:var(--muted-foreground);
|
|
1531
|
-
margin:0 0 6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1532
|
-
.miniform .where[data-none="1"]{color:var(--warning)}
|
|
1533
|
-
.cap .ct[data-bad="1"]{color:var(--destructive)}
|
|
1534
|
-
|
|
1535
|
-
/* ── The rail's initiative dossier (R7·R8·R9) ────────────────────────────────────────────────── */
|
|
1536
|
-
.reading{font-family:var(--mono);font-size:var(--text-2xs);color:var(--muted-foreground);
|
|
1537
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:12ch}
|
|
1538
|
-
.reading[data-away="1"]{color:var(--warning);max-width:none}
|
|
1539
|
-
.dz-head{padding:10px 12px 8px;border-bottom:1px solid var(--border)}
|
|
1540
|
-
.dz-id{font-size:var(--text-sm);font-weight:600;letter-spacing:-.01em}
|
|
1541
|
-
.dz-t{font-size:var(--text-xs);color:var(--muted-foreground);margin-top:2px;line-height:1.4}
|
|
1542
|
-
.dz-meta{display:flex;gap:5px;flex-wrap:wrap;margin-top:7px}
|
|
1543
|
-
.dz-meta .pill{font-family:var(--mono);font-size:var(--text-2xs);padding:2px 5px;
|
|
1544
|
-
border-radius:var(--radius-sm);background:var(--secondary);color:var(--muted-foreground);
|
|
1545
|
-
border:1px solid var(--border)}
|
|
1546
|
-
.dz-meta .pill.lane{color:var(--purple)}
|
|
1547
|
-
/* R5 — the branch a ladder came from, never optional beside a stage */
|
|
1548
|
-
.dz-attrib{margin-top:7px;font-family:var(--mono);font-size:var(--text-2xs);
|
|
1549
|
-
color:var(--muted-foreground);line-height:1.5}
|
|
1550
|
-
.dz-attrib b{color:var(--foreground);font-weight:500}
|
|
1551
|
-
.dz-attrib .sub{display:block;opacity:.85}
|
|
1552
|
-
.dz-next{margin:9px 12px;padding:8px 10px;border-radius:var(--radius-md);background:var(--success-wash);
|
|
1553
|
-
border:1px solid var(--border);font-size:var(--text-xs);color:var(--foreground);line-height:1.5}
|
|
1554
|
-
.dz-next b{display:block;font-family:var(--mono);font-size:var(--text-2xs);letter-spacing:.12em;
|
|
1555
|
-
text-transform:uppercase;color:var(--success);margin-bottom:3px;font-weight:500}
|
|
1556
|
-
/* accepted AND owing, together — a green badge alone is the watermelon */
|
|
1557
|
-
.dz-next.owed{background:var(--warning-wash)}
|
|
1558
|
-
.dz-next.owed b{color:var(--warning)}
|
|
1559
|
-
.dz-next.done b{color:var(--muted-foreground)}
|
|
1560
|
-
.dz-wait{margin:9px 12px;font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.5}
|
|
1561
|
-
.dz-wait .sub{display:block;font-size:var(--text-2xs);margin-top:3px;opacity:.85}
|
|
1562
|
-
.dz-none{margin:9px 12px;font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.55}
|
|
1563
|
-
.dz-arts{padding:0 12px 14px}
|
|
1564
|
-
.dz-sec{padding-top:10px}
|
|
1565
|
-
.dz-sec+.dz-sec{border-top:1px solid var(--border);margin-top:8px}
|
|
1566
|
-
.dz-sec h5{display:flex;gap:7px;align-items:baseline;font-family:var(--mono);
|
|
1567
|
-
font-size:var(--text-2xs);letter-spacing:.13em;text-transform:uppercase;
|
|
1568
|
-
color:var(--muted-foreground);font-weight:500;margin-bottom:5px}
|
|
1569
|
-
.dz-sec h5 .c{opacity:.8;letter-spacing:0}
|
|
1570
|
-
.dz-art{display:flex;gap:7px;align-items:baseline;width:100%;text-align:left;padding:4px 7px;
|
|
1571
|
-
margin-bottom:3px;border-radius:var(--radius-sm);background:var(--card);border:1px solid var(--border);
|
|
1572
|
-
color:inherit;font:inherit;cursor:pointer}
|
|
1573
|
-
.dz-art:hover{border-color:var(--input);background:var(--accent)}
|
|
1574
|
-
.dz-art .role{font-family:var(--mono);font-size:var(--text-2xs);letter-spacing:.1em;
|
|
1575
|
-
text-transform:uppercase;color:var(--info);width:74px;flex:none}
|
|
1576
|
-
.dz-art .pth{font-family:var(--mono);font-size:var(--text-2xs);color:var(--muted-foreground);
|
|
1577
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1578
|
-
/* `n/a for this lane` must never look like `missing` — that difference is the whole of R8 */
|
|
1579
|
-
.dz-na{font-size:var(--text-2xs);color:var(--muted-foreground);font-style:italic;line-height:1.5;
|
|
1580
|
-
padding:2px 0 4px}
|
|
1581
|
-
|
|
1582
|
-
/* ── the PM spine (workspace-pm-spine) ─────────────────────────────────────────────────────────
|
|
1583
|
-
The resident navigator: Objective → Key Result → Initiative, with working trees and sessions
|
|
1584
|
-
nested INSIDE an initiative as attributes of it. Indentation carries the containment, so the
|
|
1585
|
-
levels are distinguished by weight and colour rather than by boxes — a box per level at four
|
|
1586
|
-
levels deep is a wall. Every value here comes from the merged token layer; token-hygiene fails
|
|
1587
|
-
the build on a raw hex. */
|
|
1588
|
-
.sp-obj{margin-bottom:10px}
|
|
1589
|
-
.sp-o{display:flex;align-items:baseline;gap:8px;padding:7px 10px 5px;position:sticky;top:0;z-index:1;
|
|
1590
|
-
background:var(--sidebar);border-bottom:1px solid var(--border)}
|
|
1591
|
-
.sp-o .id{font-family:var(--mono);font-size:var(--text-2xs);font-weight:600;color:var(--foreground);flex:none}
|
|
1592
|
-
.sp-o .nm{font-size:var(--text-xs);color:var(--muted-foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1593
|
-
.sp-o .ct{margin-left:auto;font-size:var(--text-2xs);color:var(--muted-foreground);background:var(--muted);
|
|
1594
|
-
border-radius:var(--radius-sm);padding:1px 6px;flex:none}
|
|
1595
|
-
/* health budgets are PEERS of objectives (D59), marked by hue, not by demotion */
|
|
1596
|
-
.sp-obj[data-health="1"] .sp-o .id{color:var(--info)}
|
|
1597
|
-
.sp-obj[data-warn="1"] .sp-o .id{color:var(--warning)}
|
|
1598
|
-
.sp-obj[data-plain="1"] .sp-o .id{color:var(--muted-foreground)}
|
|
1599
|
-
|
|
1600
|
-
.sp-kr{margin:0 0 2px}
|
|
1601
|
-
.sp-k{display:flex;align-items:baseline;gap:7px;padding:5px 10px 4px 18px}
|
|
1602
|
-
.sp-k .id{font-family:var(--mono);font-size:var(--text-2xs);color:var(--brand);flex:none}
|
|
1603
|
-
.sp-k .nm{font-size:var(--text-2xs);color:var(--muted-foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1604
|
-
.sp-k .ct{margin-left:auto;font-size:var(--text-2xs);color:var(--muted-foreground);flex:none}
|
|
1605
|
-
|
|
1606
|
-
/* the initiative — the unit of record, and now the unit you select */
|
|
1607
|
-
.sp-init{margin:0 0 1px}
|
|
1608
|
-
.sp-i{display:block;width:100%;text-align:left;padding:5px 10px 5px 26px;border-left:2px solid transparent;
|
|
1609
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
1610
|
-
.sp-i:hover{background:var(--accent)}
|
|
1611
|
-
.sp-init[data-current="1"]>.sp-i{background:var(--accent);border-left-color:var(--brand)}
|
|
1612
|
-
.sp-i .r1{display:flex;align-items:baseline;gap:7px;min-width:0}
|
|
1613
|
-
.sp-i .nm{font-family:var(--mono);font-size:var(--text-xs);color:var(--foreground);
|
|
1614
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1615
|
-
.sp-i .lane{font-size:var(--text-2xs);color:var(--muted-foreground);flex:none}
|
|
1616
|
-
/* an initiative with no checkout is a NORMAL state — it reads quiet, never as a fault */
|
|
1617
|
-
.sp-i .noit{margin-left:auto;font-size:var(--text-2xs);color:var(--muted-foreground);flex:none;font-style:italic}
|
|
1618
|
-
.sp-i .onit{margin-left:auto;font-size:var(--text-2xs);color:var(--muted-foreground);flex:none}
|
|
1619
|
-
.sp-i .r2{display:flex;align-items:baseline;gap:8px;margin-top:2px;font-size:var(--text-2xs)}
|
|
1620
|
-
.sp-i .stg{color:var(--muted-foreground)}
|
|
1621
|
-
.sp-i .nx{color:var(--brand)}
|
|
1622
|
-
.sp-i .bl{color:var(--destructive)}
|
|
1623
|
-
.sp-i .drv,.sp-i .rsn{color:var(--muted-foreground);font-style:italic;overflow:hidden;
|
|
1624
|
-
text-overflow:ellipsis;white-space:nowrap}
|
|
1625
|
-
/* trees nested under their initiative: the demotion made visible */
|
|
1626
|
-
.sp-trees{padding-left:10px}
|
|
1627
|
-
.sp-trees:empty{display:none}
|
|
1628
|
-
|
|
1629
|
-
/* R5 — a FAILED spine read is unmistakably red and says why. It is never a green empty tree. */
|
|
1630
|
-
.sp-bad{margin:8px 10px;padding:10px 12px;border:1px solid var(--destructive);border-radius:var(--radius-md);
|
|
1631
|
-
background:var(--destructive-wash);display:flex;flex-direction:column;gap:5px}
|
|
1632
|
-
.sp-bad b{font-size:var(--text-xs);color:var(--destructive)}
|
|
1633
|
-
.sp-bad span{font-size:var(--text-2xs);color:var(--foreground);line-height:1.5}
|
|
1634
|
-
.sp-bad .why{color:var(--muted-foreground)}
|
|
1635
|
-
|
|
1636
|
-
/* ── the initiative's sessions, inside its own panel (workspace-pm-spine) ──────────────────────
|
|
1637
|
-
The work happening ON an initiative belongs beside its ladder, not only under the checkout that
|
|
1638
|
-
happens to carry the branch. Selecting one here is what puts it in the terminal column. */
|
|
1639
|
-
.dz-sess{margin:14px 0 4px}
|
|
1640
|
-
.dz-cap{display:flex;align-items:baseline;gap:7px;font-size:var(--text-xs);font-weight:500;
|
|
1641
|
-
color:var(--muted-foreground);margin-bottom:6px}
|
|
1642
|
-
.dz-cap .ct{font-size:var(--text-2xs);background:var(--muted);border-radius:var(--radius-sm);padding:1px 6px}
|
|
1643
|
-
.dz-s{display:flex;align-items:baseline;gap:8px;width:100%;text-align:left;padding:6px 9px;
|
|
1644
|
-
border-radius:var(--radius-sm);border-left:2px solid transparent;
|
|
1645
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
1646
|
-
.dz-s:hover{background:var(--accent)}
|
|
1647
|
-
.dz-s[aria-current="true"]{background:var(--accent);border-left-color:var(--brand)}
|
|
1648
|
-
.dz-s .g{flex:none;font-size:var(--text-2xs)}
|
|
1649
|
-
.dz-s[data-state="working"] .g{color:var(--success)}
|
|
1650
|
-
.dz-s[data-state="quiet"] .g{color:var(--warning)}
|
|
1651
|
-
.dz-s[data-state="needs"] .g{color:var(--brand)}
|
|
1652
|
-
.dz-s[data-state="blocked"] .g{color:var(--destructive)}
|
|
1653
|
-
.dz-s[data-state="exited"] .g,.dz-s[data-state="idle"] .g{color:var(--muted-foreground)}
|
|
1654
|
-
.dz-s .nm{font-size:var(--text-sm);color:var(--foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1655
|
-
.dz-s .st{margin-left:auto;flex:none;font-size:var(--text-2xs);color:var(--muted-foreground);white-space:nowrap}
|
|
1656
|
-
/* an initiative with no tree or no sessions is a NORMAL state and reads as prose, not as an error */
|
|
1657
|
-
.dz-nosess{font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.55;padding:2px 0 4px}
|
|
1658
|
-
.dz-nosess b{font-family:var(--mono);color:var(--foreground);font-weight:400}
|
|
1659
|
-
.dz-start{display:inline-flex;align-items:center;margin-top:6px;min-height:30px;padding:0 11px;
|
|
1660
|
-
border:1px dashed var(--border);border-radius:var(--radius-md);font-size:var(--text-xs);
|
|
1661
|
-
color:var(--muted-foreground);
|
|
1662
|
-
transition:color var(--duration-fast) var(--ease-emphasized),border-color var(--duration-fast) var(--ease-emphasized)}
|
|
1663
|
-
.dz-start:hover{color:var(--foreground);border-color:var(--ring)}
|
|
1664
|
-
|
|
1665
|
-
/* ── the destinations (workspace-pm-spine) ────────────────────────────────────────────────────
|
|
1666
|
-
ON TOP OF the initiative list they scope, not a separate nav column. Everything here is
|
|
1667
|
-
PRODUCT-SPECIFIC — knowledge and scheduled tasks belong to the repository in view — so the menu
|
|
1668
|
-
sits inside the product's own column, where its scope cannot be misread. */
|
|
1669
|
-
.spmenu{display:grid;grid-template-columns:repeat(4,1fr);gap:2px;padding:8px 10px 8px;
|
|
1670
|
-
border-bottom:1px solid var(--border)}
|
|
1671
|
-
/* min-height 44px is the touch target, and it is what makes the two-row grid square up. These
|
|
1672
|
-
are MODES, not links: one is always current, so the pressed state is `aria-pressed`, styled
|
|
1673
|
-
here rather than left to the browser's default (which is nothing on a custom button). */
|
|
1674
|
-
.spm{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
|
|
1675
|
-
padding:7px 2px 6px;min-height:44px;
|
|
1676
|
-
border-radius:var(--radius-md);color:var(--muted-foreground);
|
|
1677
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized),
|
|
1678
|
-
color var(--duration-fast) var(--ease-emphasized)}
|
|
1679
|
-
.spm:hover{background:var(--accent);color:var(--accent-foreground)}
|
|
1680
|
-
.spm[aria-pressed="true"]{background:var(--accent);color:var(--foreground)}
|
|
1681
|
-
.spm .g{font-size:var(--text-base);line-height:1}
|
|
1682
|
-
.spm .l{font-size:var(--text-tiny);letter-spacing:.01em;line-height:1}
|
|
1683
|
-
|
|
1684
|
-
/* ── column 1: the search box, and the lists each mode renders ─────────────────────────────── */
|
|
1685
|
-
.spfind-wrap{padding:10px 12px 6px}
|
|
1686
|
-
.spfind{display:flex;align-items:center;gap:8px;padding:7px 10px;min-height:34px;
|
|
1687
|
-
border:1px solid var(--input);border-radius:var(--radius-md);background:var(--background);
|
|
1688
|
-
transition:border-color var(--duration-fast) var(--ease-emphasized)}
|
|
1689
|
-
.spfind:focus-within{border-color:var(--ring)}
|
|
1690
|
-
.spfind .g{color:var(--muted-foreground);font-size:var(--text-xs);flex:none}
|
|
1691
|
-
.spfind input{flex:1;min-width:0;font-size:var(--text-body);background:none;border:0;outline:none;
|
|
1692
|
-
color:var(--foreground);font-family:inherit}
|
|
1693
|
-
.spfind input::placeholder{color:var(--muted-foreground)}
|
|
1694
|
-
|
|
1695
|
-
/* One row shape, reused by every non-product mode. They differ in what they say, not in how they
|
|
1696
|
-
are built — which is why a new mode does not need a new set of rules. */
|
|
1697
|
-
.md-note{padding:8px 14px 4px;font-size:var(--text-row);color:var(--muted-foreground);line-height:1.5}
|
|
1698
|
-
.md-cap{padding:7px 14px 4px;font-family:var(--mono);font-size:var(--text-tiny);letter-spacing:.12em;
|
|
1699
|
-
text-transform:uppercase;color:var(--muted-foreground);border-bottom:1px solid var(--border)}
|
|
1700
|
-
.md-row{display:block;width:100%;padding:8px 14px;min-height:44px;
|
|
1701
|
-
border-bottom:1px solid var(--border);border-left:2px solid transparent;
|
|
1702
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
1703
|
-
.md-row:hover{background:var(--accent)}
|
|
1704
|
-
.md-row[aria-current="true"]{background:var(--accent);border-left-color:var(--brand)}
|
|
1705
|
-
.md-row .r1{display:flex;gap:8px;align-items:baseline;min-width:0}
|
|
1706
|
-
.md-row .nm{font-family:var(--mono);font-size:var(--text-xs);color:var(--foreground);
|
|
1707
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1708
|
-
.md-row .rt{margin-left:auto;flex:none;font-size:var(--text-meta);color:var(--muted-foreground)}
|
|
1709
|
-
.md-row .d{display:block;font-size:var(--text-row);color:var(--muted-foreground);
|
|
1710
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1711
|
-
.md-row .chain{display:block;font-family:var(--mono);font-size:var(--text-tiny);color:var(--info);
|
|
1712
|
-
margin-top:2px;overflow-wrap:anywhere}
|
|
1713
|
-
.md-row .dot{flex:none;font-size:var(--text-tiny)}
|
|
1714
|
-
.md-row[data-live="on"] .dot{color:var(--success)}
|
|
1715
|
-
.md-row[data-live="off"] .dot{color:var(--muted-foreground)}
|
|
1716
|
-
.md-add{display:inline-flex;align-items:center;margin:10px 14px;min-height:30px;padding:0 12px;
|
|
1717
|
-
background:var(--secondary);border:1px solid var(--border);border-radius:var(--radius-md);
|
|
1718
|
-
font-size:var(--text-xs);color:var(--foreground);
|
|
1719
|
-
transition:border-color var(--duration-fast) var(--ease-emphasized)}
|
|
1720
|
-
.md-add:hover{border-color:var(--ring)}
|
|
1721
|
-
/* A mode PMOS keeps no file for says so in full, and never renders a plausible-looking sample.
|
|
1722
|
-
Faking this list would make the workspace lie about what the repository contains, which is the
|
|
1723
|
-
one thing the honest-state contract forbids outright. */
|
|
1724
|
-
.md-none{margin:12px 14px;padding:11px 13px;border:1px dashed var(--input);
|
|
1725
|
-
border-radius:var(--radius-md);font-size:var(--text-xs);line-height:1.6;color:var(--muted-foreground)}
|
|
1726
|
-
.md-none b{color:var(--warning);font-weight:500}
|
|
1727
|
-
.md-none code{font-family:var(--mono);font-size:var(--text-meta);color:var(--foreground)}
|
|
1728
|
-
/* "matches elsewhere" — search results that are not initiatives */
|
|
1729
|
-
.sp-hit{display:block;width:100%;padding:6px 12px;min-height:40px;
|
|
1730
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
1731
|
-
.sp-hit:hover{background:var(--accent)}
|
|
1732
|
-
.sp-hit .k{display:block;font-family:var(--mono);font-size:var(--text-tiny);color:var(--info)}
|
|
1733
|
-
.sp-hit .l{display:block;font-family:var(--mono);font-size:var(--text-2xs);
|
|
1734
|
-
color:var(--muted-foreground);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1735
|
-
.sp-nomatch{padding:10px 14px;font-size:var(--text-xs);color:var(--muted-foreground);font-style:italic}
|
|
1736
|
-
|
|
1737
|
-
/* ── column 2 · the detail panel ───────────────────────────────────────────────────────────────
|
|
1738
|
-
The whole point of this column is the ANSWER to "where is this, what is next, what blocks it".
|
|
1739
|
-
So the sizes here are deliberately not uniform: the next-action line is 14px — larger than the
|
|
1740
|
-
stage names, the step descriptions and everything below it — because it is the one line the PM
|
|
1741
|
-
is scanning for. Making every section equal weight is exactly the flaw this redesign fixes.
|
|
1742
|
-
Everything else on the panel is reference material and is typed as such. */
|
|
1743
|
-
.d2{display:flex;flex-direction:column;min-height:0}
|
|
1744
|
-
.d2-head{position:sticky;top:0;z-index:2;background:var(--sidebar);
|
|
1745
|
-
border-bottom:1px solid var(--border);padding:6px 8px 6px 14px;
|
|
1746
|
-
font-size:var(--text-xs);font-weight:500;color:var(--muted-foreground);
|
|
1747
|
-
display:flex;align-items:center;gap:8px}
|
|
1748
|
-
.d2-head .x{margin-left:auto;color:var(--muted-foreground);padding:3px 7px;font-size:var(--text-xs);
|
|
1749
|
-
transition:color var(--duration-fast) var(--ease-emphasized)}
|
|
1750
|
-
.d2-head .x:hover{color:var(--foreground)}
|
|
1751
|
-
|
|
1752
|
-
.d2-title{padding:13px 14px 11px;border-bottom:1px solid var(--border)}
|
|
1753
|
-
.d2-title .nm{font-family:var(--mono);font-size:var(--text-title);font-weight:600;
|
|
1754
|
-
letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1755
|
-
.d2-title .tag{font-size:var(--text-xs);color:var(--muted-foreground);margin-top:2px}
|
|
1756
|
-
.d2-pills{display:flex;gap:5px;flex-wrap:wrap;margin-top:8px}
|
|
1757
|
-
.d2-pill{font-family:var(--mono);font-size:var(--text-tiny);padding:2px 6px;
|
|
1758
|
-
background:var(--secondary);border:1px solid var(--border);border-radius:var(--radius-sm);
|
|
1759
|
-
color:var(--muted-foreground)}
|
|
1760
|
-
.d2-pill[data-t="lane"]{color:var(--purple)}
|
|
1761
|
-
.d2-pill[data-t="anchor"]{color:var(--muted-foreground)}
|
|
1762
|
-
.d2-pill[data-t="flow"]{color:var(--info)}
|
|
1763
|
-
.d2-pill[data-t="bad"]{color:var(--destructive)}
|
|
1764
|
-
.d2-pill[data-t="warn"]{color:var(--warning)}
|
|
1765
|
-
|
|
1766
|
-
/* R5 — a failed read is RED and says why. Never a tidy empty state standing in for a broken one. */
|
|
1767
|
-
.d2-bad{margin:12px;padding:11px 13px;border:1px solid var(--destructive);
|
|
1768
|
-
border-radius:var(--radius-md);background:var(--destructive-wash)}
|
|
1769
|
-
.d2-bad .lbl{font-family:var(--mono);font-size:var(--text-tiny);letter-spacing:.14em;
|
|
1770
|
-
text-transform:uppercase;color:var(--destructive);margin-bottom:4px;font-weight:500;display:block}
|
|
1771
|
-
.d2-bad .why{font-size:var(--text-body);line-height:1.55}
|
|
1772
|
-
|
|
1773
|
-
/* the standing answer, when there is no ladder to hang it on */
|
|
1774
|
-
.d2-ans{margin:12px 12px 0;padding:9px 11px;font-size:var(--text-sm);line-height:1.5;
|
|
1775
|
-
border-left:2px solid var(--muted-foreground);background:var(--muted)}
|
|
1776
|
-
.d2-ans[data-tone="warn"]{border-left-color:var(--warning);background:var(--warning-wash)}
|
|
1777
|
-
.d2-ans[data-tone="bad"]{border-left-color:var(--destructive);background:var(--destructive-wash)}
|
|
1778
|
-
.d2-ans[data-tone="info"]{border-left-color:var(--info);background:var(--info-wash)}
|
|
1779
|
-
.d2-ans[data-tone="ok"]{border-left-color:var(--success);background:var(--success-wash)}
|
|
1780
|
-
.d2-noladder{margin:10px 12px 0;padding:9px 11px;border:1px dashed var(--input);
|
|
1781
|
-
border-radius:var(--radius-md);font-size:var(--text-xs);line-height:1.5;color:var(--muted-foreground)}
|
|
1782
|
-
|
|
1783
|
-
/* the "next" tag — one vocabulary, whether it sits on a step or on the standing answer */
|
|
1784
|
-
.d2-next{font-family:var(--mono);font-size:var(--text-tiny);letter-spacing:.14em;
|
|
1785
|
-
text-transform:uppercase;margin-right:8px;font-weight:500;color:var(--muted-foreground)}
|
|
1786
|
-
.d2-ans[data-tone="warn"] .d2-next,.d2-step[data-tone="warn"] .d2-next{color:var(--warning)}
|
|
1787
|
-
.d2-ans[data-tone="bad"] .d2-next,.d2-step[data-tone="bad"] .d2-next{color:var(--destructive)}
|
|
1788
|
-
.d2-ans[data-tone="info"] .d2-next,.d2-step[data-tone="info"] .d2-next{color:var(--info)}
|
|
1789
|
-
.d2-ans[data-tone="ok"] .d2-next,.d2-step[data-tone="ok"] .d2-next{color:var(--success)}
|
|
1790
|
-
|
|
1791
|
-
/* the ladder */
|
|
1792
|
-
.d2-rail{padding:10px 0 6px}
|
|
1793
|
-
.d2-step{display:flex;gap:10px;padding:7px 14px 7px 12px;border-left:2px solid transparent}
|
|
1794
|
-
.d2-step[data-here="1"][data-tone="warn"]{border-left-color:var(--warning);background:var(--warning-wash)}
|
|
1795
|
-
.d2-step[data-here="1"][data-tone="bad"]{border-left-color:var(--destructive);background:var(--destructive-wash)}
|
|
1796
|
-
.d2-step[data-here="1"][data-tone="info"]{border-left-color:var(--info);background:var(--info-wash)}
|
|
1797
|
-
.d2-step[data-here="1"][data-tone="ok"]{border-left-color:var(--success);background:var(--success-wash)}
|
|
1798
|
-
.d2-step .dot{flex:none;width:14px;text-align:center;font-family:var(--mono);
|
|
1799
|
-
font-size:var(--text-2xs);line-height:1.5}
|
|
1800
|
-
.d2-step[data-s="done"] .dot{color:var(--success)}
|
|
1801
|
-
.d2-step[data-s="current"] .dot{color:var(--brand)}
|
|
1802
|
-
.d2-step[data-s="pending"] .dot,.d2-step[data-s="na"] .dot{color:var(--muted-foreground)}
|
|
1803
|
-
.d2-step[data-s="blocked"] .dot{color:var(--destructive)}
|
|
1804
|
-
.d2-step .txt{min-width:0;flex:1}
|
|
1805
|
-
.d2-step .r1{display:flex;gap:9px;align-items:baseline;min-width:0}
|
|
1806
|
-
.d2-step .k{flex:none;font-family:var(--mono);font-size:var(--text-tiny);letter-spacing:.12em;
|
|
1807
|
-
text-transform:uppercase;color:var(--muted-foreground)}
|
|
1808
|
-
.d2-step[data-here="1"] .k,.d2-step[data-s="current"] .k{color:var(--foreground)}
|
|
1809
|
-
.d2-step .t{font-size:var(--text-xs);color:var(--muted-foreground);
|
|
1810
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1811
|
-
/* THE line the panel exists for — larger than anything around it, and allowed to wrap */
|
|
1812
|
-
.d2-act{margin-top:6px;font-size:var(--text-base);line-height:1.45;text-wrap:pretty}
|
|
1813
|
-
.d2-cmd{display:inline-block;margin-top:5px;font-family:var(--mono);font-size:var(--text-meta);
|
|
1814
|
-
padding:4px 8px;min-height:26px;background:var(--background);border:1px solid var(--border);
|
|
1815
|
-
border-radius:var(--radius-md);color:var(--info);max-width:100%;
|
|
1816
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom;
|
|
1817
|
-
transition:border-color var(--duration-fast) var(--ease-emphasized)}
|
|
1818
|
-
.d2-cmd:hover{border-color:var(--ring)}
|
|
1819
|
-
|
|
1820
|
-
/* the reference rows below the ladder — a fixed label gutter so they read as one table */
|
|
1821
|
-
.d2-field{display:grid;grid-template-columns:76px minmax(0,1fr);gap:10px;padding:8px 14px;
|
|
1822
|
-
border-bottom:1px solid var(--border)}
|
|
1823
|
-
.d2-field:last-of-type{border-bottom:0}
|
|
1824
|
-
.d2-field>.lbl{font-family:var(--mono);font-size:var(--text-label);letter-spacing:.12em;
|
|
1825
|
-
text-transform:uppercase;color:var(--muted-foreground);padding-top:2px}
|
|
1826
|
-
.d2-field>.val{display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
1827
|
-
.d2-evals{font-size:var(--text-xs);line-height:1.5;text-align:left;color:var(--warning)}
|
|
1828
|
-
.d2-evals[data-v="pass"]{color:var(--success)}
|
|
1829
|
-
.d2-evals[data-v="fail"]{color:var(--destructive)}
|
|
1830
|
-
.d2-evals:hover{text-decoration:underline}
|
|
1831
|
-
.d2-sess{display:flex;gap:8px;align-items:center;padding:5px 6px;margin:0 -6px;min-height:34px;
|
|
1832
|
-
border-left:2px solid transparent;
|
|
1833
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
1834
|
-
.d2-sess:hover{background:var(--accent)}
|
|
1835
|
-
.d2-sess[aria-current="true"]{border-left-color:var(--brand)}
|
|
1836
|
-
.d2-sess .g{flex:none;font-size:var(--text-tiny)}
|
|
1837
|
-
.d2-sess[data-state="working"] .g,.d2-sess[data-state="working"] .st{color:var(--success)}
|
|
1838
|
-
.d2-sess[data-state="quiet"] .g,.d2-sess[data-state="quiet"] .st{color:var(--warning)}
|
|
1839
|
-
.d2-sess[data-state="needs"] .g,.d2-sess[data-state="needs"] .st{color:var(--brand)}
|
|
1840
|
-
.d2-sess[data-state="blocked"] .g,.d2-sess[data-state="blocked"] .st{color:var(--destructive)}
|
|
1841
|
-
.d2-sess[data-state="exited"] .g,.d2-sess[data-state="exited"] .st{color:var(--muted-foreground)}
|
|
1842
|
-
.d2-sess .nm{font-size:var(--text-body);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1843
|
-
.d2-sess .st{margin-left:auto;flex:none;font-family:var(--mono);font-size:var(--text-tiny)}
|
|
1844
|
-
.d2-art{display:flex;gap:8px;align-items:center;padding:4px 6px;margin:0 -6px;min-width:0;
|
|
1845
|
-
min-height:30px;transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
1846
|
-
.d2-art:hover{background:var(--accent)}
|
|
1847
|
-
.d2-art .role{flex:none;width:52px;font-family:var(--mono);font-size:var(--text-tiny);
|
|
1848
|
-
letter-spacing:.1em;color:var(--info)}
|
|
1849
|
-
.d2-art .path{font-family:var(--mono);font-size:var(--text-tiny);color:var(--muted-foreground);
|
|
1850
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1851
|
-
.d2-quiet{font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.5}
|
|
1852
|
-
.d2-quiet.italic{font-size:var(--text-row);font-style:italic}
|
|
1853
|
-
.d2-btn{align-self:flex-start;margin-top:4px;display:inline-flex;align-items:center;
|
|
1854
|
-
min-height:30px;padding:0 12px;background:var(--secondary);border:1px solid var(--border);
|
|
1855
|
-
border-radius:var(--radius-md);font-size:var(--text-xs);color:var(--foreground);
|
|
1856
|
-
transition:border-color var(--duration-fast) var(--ease-emphasized)}
|
|
1857
|
-
.d2-btn:hover{border-color:var(--ring)}
|
|
1858
|
-
.d2-btn[data-kind="primary"]{background:var(--primary);color:var(--primary-foreground);
|
|
1859
|
-
border-color:transparent;font-weight:500}
|
|
1860
|
-
.d2-btn[data-kind="danger"]{background:none;border-color:var(--destructive);color:var(--destructive)}
|
|
1861
|
-
.d2-btn[data-kind="danger"]:hover{background:var(--destructive-wash)}
|
|
1862
|
-
.d2-acts{display:flex;gap:6px;flex-wrap:wrap;padding:12px 14px;border-bottom:1px solid var(--border)}
|
|
1863
|
-
.d2-acts .d2-btn{margin-top:0}
|
|
1864
|
-
.d2-body{padding:12px 14px;border-bottom:1px solid var(--border);font-size:var(--text-sm);line-height:1.55}
|
|
1865
|
-
.d2-sub{padding:10px 14px 4px;font-family:var(--mono);font-size:var(--text-label);
|
|
1866
|
-
letter-spacing:.12em;text-transform:uppercase;color:var(--muted-foreground)}
|
|
1867
|
-
.d2-list{display:flex;flex-direction:column;gap:2px;padding:4px 14px 10px}
|
|
1868
|
-
.d2-item{display:flex;gap:9px;align-items:center;min-height:34px;padding:0 9px;
|
|
1869
|
-
background:var(--background);border:1px solid var(--border);border-radius:var(--radius-md);
|
|
1870
|
-
transition:border-color var(--duration-fast) var(--ease-emphasized)}
|
|
1871
|
-
.d2-item:hover{border-color:var(--ring)}
|
|
1872
|
-
.d2-item .n{flex:none;font-family:var(--mono);font-size:var(--text-tiny);color:var(--muted-foreground)}
|
|
1873
|
-
.d2-item .k{font-family:var(--mono);font-size:var(--text-row);letter-spacing:.06em}
|
|
1874
|
-
.d2-item .kind{flex:none;width:86px;font-family:var(--mono);font-size:var(--text-label);
|
|
1875
|
-
letter-spacing:.1em;text-transform:uppercase;color:var(--muted-foreground)}
|
|
1876
|
-
.d2-item .id{font-family:var(--mono);font-size:var(--text-row);color:var(--brand)}
|
|
1877
|
-
.d2-item .d{font-size:var(--text-2xs);color:var(--muted-foreground);
|
|
1878
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1879
|
-
/* the panel always ends by naming where it read from — provenance, not decoration */
|
|
1880
|
-
.d2-foot{margin-top:auto;padding:8px 14px;border-top:1px solid var(--border);
|
|
1881
|
-
font-family:var(--mono);font-size:var(--text-tiny);color:var(--muted-foreground);
|
|
1882
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1883
|
-
.d2-empty{flex:1;display:grid;place-items:center;color:var(--muted-foreground);
|
|
1884
|
-
font-size:var(--text-body);padding:20px;text-align:center}
|
|
1885
|
-
|
|
1886
|
-
/* evals on the initiative panel — the Review-Gate record, and the honest absence of one */
|
|
1887
|
-
.dz-ev{margin:14px 0 4px}
|
|
1888
|
-
.dz-e{display:flex;align-items:baseline;gap:9px;padding:5px 0}
|
|
1889
|
-
.dz-e .v{font-size:var(--text-2xs);font-weight:500;border-radius:var(--radius-sm);padding:1px 7px;
|
|
1890
|
-
background:var(--muted);color:var(--muted-foreground)}
|
|
1891
|
-
.dz-e .v[data-v="pass"]{color:var(--success)}
|
|
1892
|
-
.dz-e .v[data-v="fail"]{color:var(--destructive)}
|
|
1893
|
-
.dz-e .sc,.dz-e .co{font-size:var(--text-2xs);color:var(--muted-foreground)}
|
|
1894
|
-
/* a rubric never run is NOT a pass — the sentence says so rather than leaving a green blank */
|
|
1895
|
-
.dz-noev{font-size:var(--text-xs);color:var(--muted-foreground);line-height:1.55}
|
|
1896
|
-
.dz-noev b{color:var(--warning);font-weight:500}
|
|
1897
|
-
|
|
1898
|
-
/* ═════════════════════════════════════════════════════════════════════════════════════════════
|
|
1899
|
-
BUNDLE 2 — focus · product switcher · repo ingest · profiles · handoff links
|
|
1900
|
-
Five feature vocabularies over the four this file already had (.sp-* .md-* .d2-* .cs-*). Each
|
|
1901
|
-
gets one short prefix and otherwise reuses what exists; none of them is a fifth GENERAL
|
|
1902
|
-
vocabulary. Every value goes through the D38 token layer — a literal hex, radius or font size
|
|
1903
|
-
here would be a second source of truth for something the tokens already own.
|
|
1904
|
-
The single rule the whole section is written around: four states, four renderings, never
|
|
1905
|
-
collapsed. A failed read is RED and carries the reader's own words; a successful read of nothing
|
|
1906
|
-
is calm; an absent MECHANISM is stated as an absence, in different words from "empty"; a read
|
|
1907
|
-
still in flight is its own third thing. Where two of those share a style below, that is a bug.
|
|
1908
|
-
═════════════════════════════════════════════════════════════════════════════════════════════ */
|
|
1909
|
-
|
|
1910
|
-
/* ── the [hidden] companions ──────────────────────────────────────────────────────────────────
|
|
1911
|
-
The UA's `[hidden]{display:none}` loses to ANY author `display` declaration, so a node the code
|
|
1912
|
-
hides stays on screen. This exact bug has shipped three times in this file — its scars are the
|
|
1913
|
-
rules at .colrail, .newsess, .miniform, .group and .cap .mini, each of which was written after
|
|
1914
|
-
the fact. So: every rule below that sets `display` has its companion here, up front, where the
|
|
1915
|
-
set can be read in one go instead of hunted for.
|
|
1916
|
-
The first ten are the set the wiring contract enumerates verbatim. They are at (0,1,1) and the
|
|
1917
|
-
rules they guard are at (0,1,0), so they win whatever the source order — including against the
|
|
1918
|
-
≤760px overrides at the bottom of this section. */
|
|
1919
|
-
.focusbtn[hidden]{display:none}
|
|
1920
|
-
.fc[hidden]{display:none}
|
|
1921
|
-
.psw[hidden]{display:none}
|
|
1922
|
-
.prof[hidden]{display:none}
|
|
1923
|
-
.profline[hidden]{display:none}
|
|
1924
|
-
.ing-src[hidden]{display:none}
|
|
1925
|
-
.ing-opt[hidden]{display:none}
|
|
1926
|
-
.mob[hidden]{display:none}
|
|
1927
|
-
.mob-back[hidden]{display:none}
|
|
1928
|
-
.d2-links[hidden]{display:none}
|
|
1929
|
-
/* and every other display-setting rule in this section, on the same principle */
|
|
1930
|
-
.fc-body[hidden],.fc-item[hidden],.fc-obj[hidden],.fc-run[hidden],.fc-del[hidden],
|
|
1931
|
-
.fc-budget[hidden],.psw-list[hidden],.psw-add[hidden],.psw-b[hidden],.ing-log[hidden],
|
|
1932
|
-
.ing-row[hidden],.ing-item[hidden],.ing-anchor[hidden],.ing-ev[hidden],.prof-chip[hidden],
|
|
1933
|
-
.d2-link[hidden],.d2-links a[hidden],.d2-notconn[hidden],.d2-inert[hidden],
|
|
1934
|
-
.mob-bar[hidden],.mobnav[hidden]{display:none}
|
|
1935
|
-
|
|
1936
|
-
/* ── focus (workspace-focus) ──────────────────────────────────────────────────────────────────
|
|
1937
|
-
The one surface in column 1 that is NOT scoped by the product switcher — it joins every
|
|
1938
|
-
registered repository — which is why it sits above it. Its whole value is that the list is
|
|
1939
|
-
short, so the states below have to stay distinguishable at a glance:
|
|
1940
|
-
failed read → .cs-error (the existing one; RED, the reader's own message)
|
|
1941
|
-
read of nothing → .fc-none calm, solid, the info hue
|
|
1942
|
-
absent mechanism → .fc-notconn dashed, no hue, different words
|
|
1943
|
-
still deriving → .fc-deriving its own hue and a shimmer, neither of the above
|
|
1944
|
-
.fc-none and .fc-notconn deliberately share NOTHING. An absence rendered as an empty list is
|
|
1945
|
-
the watermelon this bundle exists to prevent. */
|
|
1946
|
-
.focusbtn{display:flex;align-items:center;gap:8px;width:calc(100% - 24px);margin:10px 12px 2px;
|
|
1947
|
-
min-height:30px;padding:6px 10px;border:1px solid var(--border);border-radius:var(--radius-md);
|
|
1948
|
-
background:var(--card);color:var(--foreground);font-size:var(--text-xs);text-align:left;
|
|
1949
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized),
|
|
1950
|
-
border-color var(--duration-fast) var(--ease-emphasized)}
|
|
1951
|
-
.focusbtn:hover{background:var(--accent);border-color:var(--ring)}
|
|
1952
|
-
.focusbtn[aria-expanded="true"]{background:var(--accent);border-color:var(--brand);color:var(--brand)}
|
|
1953
|
-
.focusbtn .g{flex:none;font-size:var(--text-xs);color:var(--brand)}
|
|
1954
|
-
.focusbtn .l{flex:none}
|
|
1955
|
-
/* The badge prints badge.text — a SENTENCE ("4 need you · 1 product still deriving", "needs
|
|
1956
|
-
unreadable"), never a count. So it is styled to hold prose: it takes the remaining width and
|
|
1957
|
-
ellipsizes rather than widening the sidebar, and it is deliberately NOT a pill. A digit in a
|
|
1958
|
-
pill invites reading it as an exact tally of a world that may contain a read which failed. */
|
|
1959
|
-
.focusbtn .ct{margin-left:auto;min-width:0;font-size:var(--text-2xs);color:var(--warning);
|
|
1960
|
-
overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
1961
|
-
.focusbtn .ct[data-bad="1"]{color:var(--destructive)}
|
|
1962
|
-
|
|
1963
|
-
.fc{margin:2px 0 6px;background:var(--card);
|
|
1964
|
-
border-top:1px solid var(--border);border-bottom:1px solid var(--border)}
|
|
1965
|
-
/* its own scroll region, capped: the panel is a second reading of the same repositories and #tree
|
|
1966
|
-
below it is the first, so the panel must never push the structure it was derived from off the
|
|
1967
|
-
bottom of the column. */
|
|
1968
|
-
.fc-body{display:flex;flex-direction:column;max-height:min(58vh,540px);
|
|
1969
|
-
overflow-y:auto;overscroll-behavior:contain}
|
|
1970
|
-
.fc-sec{padding:2px 0 8px}
|
|
1971
|
-
.fc-sec+.fc-sec{border-top:1px solid var(--border)}
|
|
1972
|
-
/* same grammar as .md-cap — the sections of this panel are peers of the mode lists beside them */
|
|
1973
|
-
.fc-cap{padding:7px 14px 4px;font-family:var(--mono);font-size:var(--text-tiny);letter-spacing:.12em;
|
|
1974
|
-
text-transform:uppercase;color:var(--muted-foreground)}
|
|
1975
|
-
/* R3's contract line, first in the panel. It is prose, not a caption: the queue is only worth
|
|
1976
|
-
trusting if the rule that filled it is on the same screen as the rows it excluded. */
|
|
1977
|
-
.fc-intro{padding:8px 14px;font-size:var(--text-row);line-height:1.55;color:var(--muted-foreground)}
|
|
1978
|
-
|
|
1979
|
-
/* a queue row: rank + slug + product on line one, the why on line two, the read on line three.
|
|
1980
|
-
`margin-left:auto` on the product tag and `flex-basis:100%` on the two lines below it are what
|
|
1981
|
-
produce that shape from a flat run of siblings, with no wrapper the renderer has to remember. */
|
|
1982
|
-
.fc-item{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:8px;row-gap:3px;
|
|
1983
|
-
width:100%;min-height:34px;padding:8px 14px 8px 12px;text-align:left;
|
|
1984
|
-
border-top:1px solid var(--border);border-left:2px solid transparent;
|
|
1985
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
1986
|
-
.fc-item:hover{background:var(--accent)}
|
|
1987
|
-
/* the tier tints the spine and is never the only carrier: the row prints its own `why` and sits
|
|
1988
|
-
under a labelled section. Tier 1 is an integrity failure, so it takes the alarm hue. */
|
|
1989
|
-
.fc-item[data-tier="1"]{border-left-color:var(--destructive)}
|
|
1990
|
-
.fc-item[data-tier="2"]{border-left-color:var(--brand)}
|
|
1991
|
-
.fc-item[data-tier="2b"]{border-left-color:var(--warning)}
|
|
1992
|
-
.fc-item[data-tier="4"]{border-left-color:var(--muted-foreground)}
|
|
1993
|
-
.fc-rank{flex:none;width:16px;font-family:var(--mono);font-size:var(--text-meta);
|
|
1994
|
-
color:var(--muted-foreground)}
|
|
1995
|
-
.fc-nm{min-width:0;font-family:var(--mono);font-size:var(--text-xs);color:var(--foreground);
|
|
1996
|
-
overflow-wrap:anywhere}
|
|
1997
|
-
.fc-prod{margin-left:auto;flex:none;font-size:var(--text-2xs);color:var(--muted-foreground);
|
|
1998
|
-
border:1px solid var(--border);border-radius:var(--radius-sm);padding:1px 6px}
|
|
1999
|
-
.fc-why{flex-basis:100%;padding-left:24px;font-size:var(--text-row);line-height:1.5;
|
|
2000
|
-
color:var(--muted-foreground)}
|
|
2001
|
-
/* NOT decoration, and never dimmed below the `why` above it. This line names the files the row was
|
|
2002
|
-
derived from, which is the only thing that lets the PM check the queue instead of believing it —
|
|
2003
|
-
so it keeps a readable size and the mono face of the paths and timestamps it prints. */
|
|
2004
|
-
.fc-read{flex-basis:100%;padding-left:24px;font-family:var(--mono);font-size:var(--text-tiny);
|
|
2005
|
-
line-height:1.55;color:var(--muted-foreground);overflow-wrap:anywhere}
|
|
2006
|
-
|
|
2007
|
-
/* objectives. Four states, four renderings — and `none` (this product declares no objectives: a
|
|
2008
|
-
read that succeeded) is NOT `not-read` (PMOS never got to it). Collapsing those two is how a
|
|
2009
|
-
product with nothing to show and a product nobody looked at become the same row. */
|
|
2010
|
-
.fc-obj{display:flex;align-items:baseline;gap:8px;width:100%;min-height:30px;padding:5px 14px;
|
|
2011
|
-
text-align:left;font-size:var(--text-xs);line-height:1.5;overflow-wrap:anywhere}
|
|
2012
|
-
.fc-obj[data-state="objective"]{color:var(--foreground)}
|
|
2013
|
-
.fc-obj[data-state="none"]{color:var(--muted-foreground);font-style:italic}
|
|
2014
|
-
.fc-obj[data-state="not-read"]{color:var(--muted-foreground);
|
|
2015
|
-
border-left:2px dashed var(--input);padding-left:12px}
|
|
2016
|
-
.fc-obj[data-state="error"]{color:var(--destructive);background:var(--destructive-wash);
|
|
2017
|
-
border-left:2px solid var(--destructive);padding-left:12px}
|
|
2018
|
-
|
|
2019
|
-
/* an ABSENCE, said as one: PMOS holds no credential, runs no MCP client and has no sync path, so
|
|
2020
|
-
there is nothing here that could be empty. A dashed rule, no hue, no dot, and the module's own
|
|
2021
|
-
words. It must never be mistaken for .fc-none, which is a read that ran and found nothing. */
|
|
2022
|
-
.fc-notconn{margin:6px 14px 4px;padding:9px 11px;border:1px dashed var(--border);
|
|
2023
|
-
border-radius:var(--radius-md);font-size:var(--text-xs);line-height:1.55;
|
|
2024
|
-
color:var(--muted-foreground)}
|
|
2025
|
-
.fc-notconn::before{content:"— "}
|
|
2026
|
-
.fc-notconn b{color:var(--foreground);font-weight:500}
|
|
2027
|
-
/* the CALM zero: the reads worked and nothing is waiting on you. Solid hairline, the info hue this
|
|
2028
|
-
file already spends on a successful empty, and no dashes anywhere. */
|
|
2029
|
-
.fc-none{margin:6px 14px 4px;padding:9px 11px;border:1px solid var(--info);
|
|
2030
|
-
border-radius:var(--radius-md);background:var(--info-wash);
|
|
2031
|
-
font-size:var(--text-xs);line-height:1.55;color:var(--foreground)}
|
|
2032
|
-
.fc-none::before{content:"◦ ";color:var(--info)}
|
|
2033
|
-
/* the THIRD state — a board still being derived. Neither empty nor broken, so it takes neither of
|
|
2034
|
-
their treatments: its own hue, a heavier left edge, and a shimmer that says work is in flight
|
|
2035
|
-
rather than a spinner that says the app is busy. */
|
|
2036
|
-
.fc-deriving{margin:6px 14px 4px;padding:9px 11px;border:1px solid var(--purple);
|
|
2037
|
-
border-left-width:3px;border-radius:var(--radius-md);
|
|
2038
|
-
font-size:var(--text-xs);line-height:1.55;color:var(--foreground);
|
|
2039
|
-
background:linear-gradient(90deg,transparent,color-mix(in oklab,var(--purple) 12%,transparent),transparent);
|
|
2040
|
-
background-size:220% 100%;animation:sfsh 1.8s linear infinite}
|
|
2041
|
-
.fc-deriving::before{content:"◌ ";color:var(--purple)}
|
|
2042
|
-
@media (prefers-reduced-motion:reduce){.fc-deriving{animation:none}}
|
|
2043
|
-
|
|
2044
|
-
/* "12 of 105 scanned · 93 outside the board's in-flight cap" — the sentence that stops a short
|
|
2045
|
-
queue being read as a complete one. */
|
|
2046
|
-
.fc-cov{padding:3px 14px;font-family:var(--mono);font-size:var(--text-tiny);line-height:1.6;
|
|
2047
|
-
color:var(--muted-foreground);overflow-wrap:anywhere}
|
|
2048
|
-
.fc-run{display:flex;align-items:baseline;gap:8px;width:100%;min-height:30px;padding:5px 14px;
|
|
2049
|
-
text-align:left;font-size:var(--text-xs);color:var(--foreground);
|
|
2050
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
2051
|
-
.fc-run:hover{background:var(--accent)}
|
|
2052
|
-
/* Emitted ONLY for rows the module resolved a skill for. Where starts_state is 'not-resolved' the
|
|
2053
|
-
renderer prints the note and no button at all — an offer PMOS cannot honour is worse than no
|
|
2054
|
-
offer, so there is deliberately no disabled variant of this to reach for. */
|
|
2055
|
-
.fc-del{display:inline-flex;align-items:center;gap:6px;min-height:30px;margin:4px 14px 2px;
|
|
2056
|
-
padding:0 11px;border:1px solid var(--brand);border-radius:var(--radius-md);
|
|
2057
|
-
background:var(--brand-wash);color:var(--brand);font-size:var(--text-xs);
|
|
2058
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized)}
|
|
2059
|
-
.fc-del:hover{background:var(--accent)}
|
|
2060
|
-
.fc-budget{display:flex;align-items:baseline;gap:8px;padding:4px 14px;
|
|
2061
|
-
font-size:var(--text-xs);line-height:1.5;color:var(--foreground)}
|
|
2062
|
-
.fc-budget .n{margin-left:auto;flex:none;font-family:var(--mono);font-size:var(--text-tiny);
|
|
2063
|
-
color:var(--muted-foreground)}
|
|
2064
|
-
/* a cap the registry did not yield is ABSENT, not zero — it is drawn as unavailable, the way
|
|
2065
|
-
details.hz's `.na` already is, and never as a plausible number. */
|
|
2066
|
-
.fc-budget .na{margin-left:auto;flex:none;font-size:var(--text-tiny);font-style:italic;
|
|
2067
|
-
color:var(--muted-foreground)}
|
|
2068
|
-
|
|
2069
|
-
/* ── product switcher (workspace-product-switcher) ────────────────────────────────────────────
|
|
2070
|
-
One button per PRODUCT (a distinct repo_key), never per working tree. The buttons WRAP, and
|
|
2071
|
-
that is the whole mechanism: a horizontally scrolling strip hides products off-screen with
|
|
2072
|
-
nothing on screen saying they exist, which is the tidy-row-of-buttons failure this feature is
|
|
2073
|
-
named after. */
|
|
2074
|
-
.psw{display:flex;align-items:flex-start;gap:6px;padding:6px 12px 4px}
|
|
2075
|
-
.psw-list{display:flex;flex-wrap:wrap;gap:4px;flex:1;min-width:0}
|
|
2076
|
-
.psw-add{flex:none;display:grid;place-items:center;min-width:30px;min-height:30px;
|
|
2077
|
-
border:1px dashed var(--border);border-radius:var(--radius-md);color:var(--muted-foreground);
|
|
2078
|
-
font-size:var(--text-sm);
|
|
2079
|
-
transition:color var(--duration-fast) var(--ease-emphasized),
|
|
2080
|
-
border-color var(--duration-fast) var(--ease-emphasized)}
|
|
2081
|
-
.psw-add:hover{color:var(--foreground);border-color:var(--ring)}
|
|
2082
|
-
.psw-add[aria-expanded="true"]{border-style:solid;border-color:var(--brand);color:var(--brand)}
|
|
2083
|
-
.psw-b{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:6px;row-gap:1px;
|
|
2084
|
-
max-width:100%;min-width:0;min-height:30px;padding:5px 9px;text-align:left;
|
|
2085
|
-
border:1px solid var(--border);border-radius:var(--radius-md);background:var(--card);
|
|
2086
|
-
color:var(--muted-foreground);
|
|
2087
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized),
|
|
2088
|
-
border-color var(--duration-fast) var(--ease-emphasized)}
|
|
2089
|
-
.psw-b:hover{background:var(--accent);border-color:var(--ring)}
|
|
2090
|
-
.psw-b[aria-current="true"]{background:var(--accent);border-color:var(--brand);color:var(--foreground)}
|
|
2091
|
-
/* R2 — the selected product carries BOTH the hue and the ▸ mark. `visibility`, not `display`, so
|
|
2092
|
-
every button keeps the same width and the row does not re-wrap as you switch between them. */
|
|
2093
|
-
.psw-mk{flex:none;font-size:var(--text-2xs);color:var(--brand);visibility:hidden}
|
|
2094
|
-
.psw-b[aria-current="true"] .psw-mk{visibility:visible}
|
|
2095
|
-
/* NEVER `text-overflow:ellipsis`, `white-space:nowrap` or a `max-width` here. The browser suite
|
|
2096
|
-
asserts scrollWidth <= clientWidth on every label at the narrowest sidebar, and a product name
|
|
2097
|
-
truncated to "workspace-…" is a product you cannot tell from its sibling. It wraps instead. */
|
|
2098
|
-
.psw-nm{min-width:0;font-family:var(--mono);font-size:var(--text-xs);color:var(--foreground);
|
|
2099
|
-
overflow-wrap:anywhere}
|
|
2100
|
-
.psw-b[aria-current="true"] .psw-nm{font-weight:600}
|
|
2101
|
-
/* EXACTLY four states and no fifth. All four are declared even where two look alike, because the
|
|
2102
|
-
set is the contract: `reading…` is not `no initiative records`, and neither of them is `0`.
|
|
2103
|
-
`error` is the only one drawn as a fault — and the button stays clickable under it: an
|
|
2104
|
-
unreadable board is not an unreachable product. */
|
|
2105
|
-
.psw-ct{flex:none;font-size:var(--text-2xs);color:var(--muted-foreground)}
|
|
2106
|
-
.psw-ct[data-state="reading"]{color:var(--muted-foreground);font-style:italic}
|
|
2107
|
-
.psw-ct[data-state="empty"]{color:var(--muted-foreground)}
|
|
2108
|
-
.psw-ct[data-state="count"]{color:var(--muted-foreground)}
|
|
2109
|
-
.psw-ct[data-state="error"]{color:var(--destructive);font-weight:500}
|
|
2110
|
-
.psw-ct[data-state="error"]::before{content:"! ";font-family:var(--mono)}
|
|
2111
|
-
.psw-live{flex:none;font-size:var(--text-2xs);color:var(--success)}
|
|
2112
|
-
|
|
2113
|
-
/* ── repo ingest (workspace-repo-ingest) ──────────────────────────────────────────────────────
|
|
2114
|
-
The source choice states its consequence BEFORE the click — a folder is REGISTERED where it
|
|
2115
|
-
lies, a GitHub repo is cloned, scanned and PROPOSED — so both notes sit on screen at once, one
|
|
2116
|
-
under each option. `.ing-src` sets no `display` of its own (it wears `.seg`), but it still needs
|
|
2117
|
-
its `[hidden]` companion above, because `.seg` is what sets display:flex on it. */
|
|
2118
|
-
.ing-src{margin-bottom:2px}
|
|
2119
|
-
.ing-opt{display:flex;flex-direction:column;gap:8px}
|
|
2120
|
-
.ing-note{font-size:var(--text-xs);line-height:1.55;color:var(--muted-foreground)}
|
|
2121
|
-
/* the scan's own log, printed as it came. `error` is RED and carries the reader's message;
|
|
2122
|
-
`warn` is amber; `info` is the ordinary case and is not tinted at all — tinting everything is
|
|
2123
|
-
how nothing stands out. Each level also carries a MARK, so the level survives without colour. */
|
|
2124
|
-
.ing-log{display:flex;flex-direction:column;margin:8px 0 4px;overflow:hidden;
|
|
2125
|
-
border:1px solid var(--border);border-radius:var(--radius-md);background:var(--card)}
|
|
2126
|
-
.ing-row{display:flex;gap:8px;align-items:baseline;padding:5px 10px;
|
|
2127
|
-
font-family:var(--mono);font-size:var(--text-tiny);line-height:1.55;
|
|
2128
|
-
color:var(--muted-foreground);overflow-wrap:anywhere}
|
|
2129
|
-
.ing-row+.ing-row{border-top:1px solid var(--border)}
|
|
2130
|
-
.ing-row::before{flex:none;width:9px;text-align:center}
|
|
2131
|
-
.ing-row[data-level="info"]::before{content:"·"}
|
|
2132
|
-
.ing-row[data-level="warn"]::before{content:"!"}
|
|
2133
|
-
.ing-row[data-level="error"]::before{content:"✕"}
|
|
2134
|
-
.ing-row[data-level="warn"]{color:var(--warning)}
|
|
2135
|
-
.ing-row[data-level="error"]{color:var(--destructive);background:var(--destructive-wash)}
|
|
2136
|
-
/* one proposed record, confirmed or dismissed ON ITS OWN. There is no `.ing-confirm-all` and there
|
|
2137
|
-
must never be one: an anchor written across a dozen records nobody read is a dozen pieces of
|
|
2138
|
-
work anchored by nobody, every gate green. The tedium IS the gate. */
|
|
2139
|
-
.ing-item{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:8px;row-gap:4px;
|
|
2140
|
-
padding:9px 14px;border-top:1px solid var(--border)}
|
|
2141
|
-
.ing-item .pth{flex-basis:100%;font-family:var(--mono);font-size:var(--text-tiny);
|
|
2142
|
-
color:var(--muted-foreground);overflow-wrap:anywhere}
|
|
2143
|
-
/* a MARK and a WORD, never a hue on its own — the accessible name is written by the renderer.
|
|
2144
|
-
`guessed` is dashed and amber because it is a claim PMOS made up, and it must not look like the
|
|
2145
|
-
`declared` value beside it, which is a claim the repository made. */
|
|
2146
|
-
.ing-anchor{display:inline-flex;align-items:baseline;gap:5px;flex:none;padding:1px 6px;
|
|
2147
|
-
font-family:var(--mono);font-size:var(--text-tiny);color:var(--muted-foreground);
|
|
2148
|
-
border:1px solid var(--border);border-radius:var(--radius-sm)}
|
|
2149
|
-
.ing-anchor[data-a="declared"]{color:var(--foreground)}
|
|
2150
|
-
.ing-anchor[data-a="guessed"]{color:var(--warning);border-color:var(--warning);border-style:dashed}
|
|
2151
|
-
.ing-anchor[data-a="none"]{border-style:dashed}
|
|
2152
|
-
/* the same shape as .fc-read, for the same reason: this is the evidence the guess rests on, and a
|
|
2153
|
-
guess whose evidence you cannot see is indistinguishable from a fact. */
|
|
2154
|
-
.ing-ev{display:block;flex-basis:100%;font-family:var(--mono);font-size:var(--text-tiny);
|
|
2155
|
-
line-height:1.55;color:var(--muted-foreground);overflow-wrap:anywhere}
|
|
2156
|
-
.ing-bad{margin:8px 0;padding:9px 11px;border:1px solid var(--destructive);
|
|
2157
|
-
border-radius:var(--radius-md);background:var(--destructive-wash);
|
|
2158
|
-
font-size:var(--text-xs);line-height:1.55;color:var(--foreground)}
|
|
2159
|
-
.ing-bad b{color:var(--destructive);font-weight:500}
|
|
2160
|
-
/* how old the scan is. A proposal reviewed against a repository that has moved is the mismatch
|
|
2161
|
-
applyChange refuses, so the age is on screen before you confirm rather than after. */
|
|
2162
|
-
.ing-stamp{font-family:var(--mono);font-size:var(--text-tiny);color:var(--muted-foreground)}
|
|
2163
|
-
|
|
2164
|
-
/* ── profiles (workspace-profiles) ────────────────────────────────────────────────────────────
|
|
2165
|
-
NOTHING in this vocabulary may render a dot, a tick, or a colour that reads as "connected".
|
|
2166
|
-
PMOS has no credential store, no MCP client and no reachability check; a descriptor DECLARES mcp
|
|
2167
|
-
servers, and a declaration is a string a human typed into a JSON file. A status light over it
|
|
2168
|
-
would be a fabrication, whatever the file says.
|
|
2169
|
-
The chips are exactly the descriptors that were read — never a hard-coded pair. */
|
|
2170
|
-
.prof{display:flex;flex-wrap:wrap;gap:4px}
|
|
2171
|
-
/* the existing `.seg [role=radio]` look, at the size a wrapping group needs */
|
|
2172
|
-
.prof-chip{display:inline-flex;align-items:baseline;gap:6px;max-width:100%;min-width:0;
|
|
2173
|
-
min-height:30px;padding:5px 9px;text-align:left;
|
|
2174
|
-
border:1px solid var(--border);border-radius:var(--radius-md);background:var(--secondary);
|
|
2175
|
-
color:var(--muted-foreground);font-size:var(--text-xs);
|
|
2176
|
-
transition:background-color var(--duration-fast) var(--ease-emphasized),
|
|
2177
|
-
border-color var(--duration-fast) var(--ease-emphasized)}
|
|
2178
|
-
.prof-chip:hover{color:var(--foreground);border-color:var(--ring)}
|
|
2179
|
-
.prof-chip[aria-checked="true"]{background:var(--background);color:var(--foreground);
|
|
2180
|
-
border-color:var(--brand);font-weight:500;box-shadow:0 1px 2px var(--shadow)}
|
|
2181
|
-
/* the declared mcp names sit at the SAME weight as the account string beside them. They are two
|
|
2182
|
-
equally ordinary facts read out of one file, and typographic emphasis on the mcp list would read
|
|
2183
|
-
as a claim about reachability that nothing in this repository can make. */
|
|
2184
|
-
.prof-mcp{font-family:var(--mono);font-size:var(--text-tiny);font-weight:400;
|
|
2185
|
-
color:var(--muted-foreground);overflow-wrap:anywhere}
|
|
2186
|
-
.prof-note{font-size:var(--text-xs);line-height:1.55;color:var(--muted-foreground)}
|
|
2187
|
-
/* a descriptor that could not be used is RED and says why — and it is NOT offered as a choice,
|
|
2188
|
-
while every good chip beside it still is. */
|
|
2189
|
-
.prof-bad{margin-top:4px;padding:8px 10px;border:1px solid var(--destructive);
|
|
2190
|
-
border-radius:var(--radius-md);background:var(--destructive-wash);
|
|
2191
|
-
font-size:var(--text-xs);line-height:1.55;color:var(--foreground)}
|
|
2192
|
-
.prof-bad b{color:var(--destructive);font-weight:500}
|
|
2193
|
-
/* R6 — which profile a pane was started under, as WORKSPACE chrome between the tab strip and the
|
|
2194
|
-
terminal. It is never written into the pane: input written to a tmux pane goes to the AGENT, a
|
|
2195
|
-
ring-buffer append is erased on the next reattach, and a line injected into scrollback is
|
|
2196
|
-
indistinguishable from one the agent printed — which defeats a line whose entire purpose is
|
|
2197
|
-
provenance. It continues the `.stabs` band (same --muted surface) so it reads as chrome and not
|
|
2198
|
-
as the terminal's first row. The sentence is computed server-side and printed verbatim. */
|
|
2199
|
-
.profline{display:block;flex:none;padding:4px 10px;background:var(--muted);
|
|
2200
|
-
border-bottom:1px solid var(--border);
|
|
2201
|
-
font-family:var(--mono);font-size:var(--text-tiny);line-height:1.5;
|
|
2202
|
-
color:var(--muted-foreground);overflow-wrap:anywhere}
|
|
2203
|
-
/* collapses only when there is literally no pane to describe. `profile: not recorded` is a
|
|
2204
|
-
sentence and stays on screen; this is not a way to hide one. */
|
|
2205
|
-
.profline:empty{display:none}
|
|
2206
|
-
|
|
2207
|
-
/* ── handoff links (workspace-jira-handoff) ───────────────────────────────────────────────────
|
|
2208
|
-
`links.connected` is false on every code path in the module, so there is no connected variant
|
|
2209
|
-
to write here and none is coming. The one thing that must not happen on this surface is a
|
|
2210
|
-
declared string borrowing the authority of a reading. */
|
|
2211
|
-
.d2-links{display:flex;flex-direction:column;gap:2px;padding:4px 14px 10px}
|
|
2212
|
-
.d2-link{display:flex;flex-wrap:wrap;align-items:baseline;column-gap:8px;row-gap:2px;
|
|
2213
|
-
min-height:30px;margin:0 -3px;padding:6px 9px;
|
|
2214
|
-
background:var(--background);border:1px solid var(--border);border-radius:var(--radius-md)}
|
|
2215
|
-
.d2-links a{min-width:0;color:var(--brand);text-decoration:underline;text-underline-offset:2px;
|
|
2216
|
-
overflow-wrap:anywhere}
|
|
2217
|
-
/* MUST NOT be styled like .d2-pill. In this panel the pill grammar — the filled --secondary box
|
|
2218
|
-
with its hairline border — means "PMOS worked this out". A typed epic key is a string a human
|
|
2219
|
-
wrote into frontmatter. Lending it the derived marker's box is exactly how a declaration
|
|
2220
|
-
silently borrows the authority of a reading, and it is this feature's named FAIL. So: plain mono
|
|
2221
|
-
text. No background, no border, no padding, no box of any kind. */
|
|
2222
|
-
.d2-kind{flex:none;padding:0;background:none;border:0;white-space:nowrap;
|
|
2223
|
-
font-family:var(--mono);font-size:var(--text-tiny);letter-spacing:.06em;
|
|
2224
|
-
color:var(--muted-foreground)}
|
|
2225
|
-
/* VISIBLE TEXT inside every row — never a `title` tooltip, never one banner at the top of the
|
|
2226
|
-
section standing in for all of them, never colour alone. It is deliberately not shrunk below the
|
|
2227
|
-
row's own type and not dimmed further: judging this line repetitive and demoting it is the exact
|
|
2228
|
-
move that lets a declared string read as a live connection. */
|
|
2229
|
-
.d2-notconn{display:block;flex-basis:100%;font-size:var(--text-row);line-height:1.5;
|
|
2230
|
-
color:var(--muted-foreground)}
|
|
2231
|
-
.d2-notconn::before{content:"— "}
|
|
2232
|
-
/* a reference that is NOT a url — no href was constructed, because PMOS never builds a URL it was
|
|
2233
|
-
not given. It reads as text you can copy, never as a link you can follow: no link hue, no solid
|
|
2234
|
-
underline, and the copy control is the only thing in it that is pressable. */
|
|
2235
|
-
.d2-inert{display:inline-flex;align-items:baseline;gap:7px;max-width:100%;min-width:0;
|
|
2236
|
-
font-family:var(--mono);font-size:var(--text-tiny);color:var(--foreground);
|
|
2237
|
-
border-bottom:1px dashed var(--input);overflow-wrap:anywhere}
|
|
2238
|
-
.d2-inert button{flex:none;min-height:30px;padding:0 7px;font-size:var(--text-2xs);
|
|
2239
|
-
color:var(--muted-foreground);
|
|
2240
|
-
transition:color var(--duration-fast) var(--ease-emphasized)}
|
|
2241
|
-
.d2-inert button:hover{color:var(--brand)}
|
|
2242
|
-
/* the build/review annotation on a ladder step. An ANNOTATION, not a verdict: it never takes the
|
|
2243
|
-
step's tone hue, never the .d2-next label grammar, and nothing about it feeds `data-s` — a
|
|
2244
|
-
declared field may add context to a derived verdict, it may never become one. */
|
|
2245
|
-
.d2-anno{font-family:var(--mono);font-size:var(--text-tiny);letter-spacing:.06em;
|
|
2246
|
-
color:var(--muted-foreground)}
|
|
2247
|
-
|
|
2248
|
-
/* ── touch targets for everything above ───────────────────────────────────────────────────────
|
|
2249
|
-
≥30px with a pointer (declared inline above) and ≥44px on a phone. This block is LAST in the
|
|
2250
|
-
file on purpose: the per-component rules it raises are at the same specificity, so source order
|
|
2251
|
-
is what decides, and a ≤760px block written higher up would silently lose to them. */
|
|
2252
|
-
@media (max-width:760px){
|
|
2253
|
-
.focusbtn,.fc-item,.fc-obj,.fc-run,.fc-del,.psw-b,.psw-add,.prof-chip,
|
|
2254
|
-
.ing-src button,.ing-item button,.d2-inert button{min-height:44px}
|
|
2255
|
-
.d2-links a{display:inline-flex;align-items:center;min-height:44px}
|
|
2256
|
-
/* the panel has the whole screen's width here, so it can afford more of its height */
|
|
2257
|
-
.fc-body{max-height:min(70vh,640px)}
|
|
2258
|
-
}
|