char-slop/berry

multipurpose self-modifiable agentic harness

git clone https://git.t4t.associates/char-slop/berry

Charlotte Somallow project reorderingb4fc6cf

main
56.1 KiB2790 linesraw
1@font-face {
2  font-family: "InterVariable";
3  src: local("Inter Variable"), local("InterVariable"), url("/fonts/inter/InterVariable.woff2")
4    format("woff2");
5  font-weight: 100 900;
6  font-style: normal;
7  font-display: swap;
8}
9@font-face {
10  font-family: "InterVariable";
11  src: local("Inter Variable Italic"), local("InterVariableItalic"),
12    url("/fonts/inter/InterVariable-Italic.woff2") format("woff2");
13  font-weight: 100 900;
14  font-style: italic;
15  font-display: swap;
16}
17@supports (font-variation-settings: normal) {
18  @font-face {
19    font-family: "iocgnMonoVariable";
20    src: url("/fonts/iocgnMono/iocgnMono-Variable.woff2") format("woff2");
21    font-weight: 200 800;
22    font-style: normal;
23    font-display: swap;
24  }
25}
26@font-face {
27  font-family: "iocgnMono";
28  src: url("/fonts/iocgnMono/iocgnMono-Regular.woff2") format("woff2");
29  font-weight: 400;
30  font-display: swap;
31}
32@font-face {
33  font-family: "iocgnMono";
34  src: url("/fonts/iocgnMono/iocgnMono-Medium.woff2") format("woff2");
35  font-weight: 500;
36  font-display: swap;
37}
38@font-face {
39  font-family: "iocgnMono";
40  src: url("/fonts/iocgnMono/iocgnMono-SemiBold.woff2") format("woff2");
41  font-weight: 600;
42  font-display: swap;
43}
44@font-face {
45  font-family: "iocgnMono";
46  src: url("/fonts/iocgnMono/iocgnMono-Bold.woff2") format("woff2");
47  font-weight: 700;
48  font-display: swap;
49}
50
51/* palette & syntax colours as sorcery's, lifted from char.lt */
52:root {
53  --bg: #100e11;
54  --panel: #181419;
55  --raised: #211a22;
56  --text: #f3eef2;
57  --muted: #958792;
58  --accent: #ff9df5;
59  --accent-fade: #ffd0fb;
60  /* rules: --line between rows, --line-strong where structure divides */
61  --line: #493045;
62  --line-strong: #b86caf;
63
64  --hl-comment: #9da8bb;
65  --hl-keyword: #9bedff;
66  --hl-builtin: #ff94d1;
67  --hl-string: #95ffc3;
68  --hl-ident: #d8a8ff;
69  --hl-number: var(--hl-string);
70
71  --ok: var(--hl-string);
72  /* the terminal palette's red and yellow, so a failure never reads as the accent */
73  --error: #fa5565;
74  --warn: #fde965;
75  --running: var(--accent);
76  /* what a diff adds and removes */
77  --added: var(--ok);
78  --removed: var(--hl-builtin);
79
80  /* a chosen row, as a completion or the tree's focus; hover stays neutral, on --raised */
81  --selected: color-mix(in srgb, var(--accent) 18%, transparent);
82  --selected-hover: color-mix(in srgb, var(--accent-fade) 18%, transparent);
83  --selection: #6d3567;
84  /* what floats over the page, and what dims it behind a dialog */
85  --shadow: 0 8px 24px rgb(0 0 0 / 0.4);
86  --scrim: rgb(0 0 0 / 0.5);
87
88  --mono: "iocgnMonoVariable", "iocgnMono", ui-monospace, "SF Mono", "Cascadia Code", monospace;
89
90  /* type in even pixels, where iocgn Mono's half-em cells are whole */
91  --text-small: 12px;
92  --text-ui: 14px;
93  --text-body: 16px;
94  --text-title: 20px;
95  --text-display: 24px;
96  /* a line 1.4 times its text, on the 4px grid: 12/16, 14/20, 16/24, 20/28, 24/32 */
97  --leading: round(nearest, 1.4em, 4px);
98
99  /* space is in pixels on a 4px grid (2px where something only needs nudging); and the sidebar, the
100     transcript's column (its text 48px narrower), and a finger's target */
101  --sidebar: 320px;
102  --column: 800px;
103  --target: 44px;
104
105  color-scheme: dark;
106  font-family: "InterVariable", "Inter", sans-serif;
107  font-size: var(--text-body);
108  text-rendering: optimizeLegibility;
109  -webkit-text-size-adjust: 100%;
110  text-size-adjust: 100%;
111  color: var(--text);
112  background: var(--bg);
113  scrollbar-color: var(--line) transparent;
114}
115
116* {
117  box-sizing: border-box;
118}
119/* each element's own rather than inherited, so it holds whatever size the element's text is; a block takes
120   more room with padding rather than a taller line */
121*,
122::before,
123::after {
124  line-height: var(--leading);
125}
126
127body {
128  margin: 0;
129  height: 100dvh;
130  overflow: hidden;
131}
132
133::selection {
134  background-color: var(--selection);
135}
136
137[hidden] {
138  display: none !important;
139}
140
141/* chrome links are bare and signal with colour; only prose underlines */
142a {
143  color: var(--accent);
144  text-decoration: none;
145}
146a:hover {
147  color: var(--accent-fade);
148}
149
150:where(button, input, select, textarea) {
151  font: inherit;
152  line-height: var(--leading);
153  color: inherit;
154  border-radius: 0;
155}
156input,
157select,
158textarea {
159  background: var(--raised);
160  border: 1px solid var(--line);
161  padding: 4px 8px;
162}
163/* firefox lays a select's line out at its font's own height, so it would sit shorter than a field beside it */
164select {
165  height: calc(var(--leading) + 10px);
166}
167/* a button is the words for what it does, quiet until pointed at, and a form's main action is in the accent. at no
168   specificity, so that a component's own buttons are what it says they are */
169:where(button) {
170  padding: 5px 0;
171  background: none;
172  border: 0;
173  color: var(--muted);
174  cursor: pointer;
175}
176:where(button:hover:not(:disabled)) {
177  color: var(--accent);
178}
179:where(button.danger:hover:not(:disabled)) {
180  color: var(--error);
181}
182:where(button.primary) {
183  color: var(--accent);
184  font-weight: 600;
185}
186:where(button.primary:hover:not(:disabled)) {
187  color: var(--accent-fade);
188}
189/* a form's only action, alone beside its fields, takes an underline to aim at */
190:where(button.primary:only-of-type) {
191  color: var(--text);
192  text-decoration: underline 2px var(--accent);
193  text-underline-offset: 5px;
194}
195:where(button.primary:only-of-type:hover:not(:disabled)) {
196  color: var(--accent);
197}
198:where(button:disabled) {
199  opacity: 0.4;
200  cursor: default;
201}
202:is(input, select, textarea):focus {
203  outline: none;
204  border-color: var(--line-strong);
205}
206:is(button, a, summary):focus-visible {
207  outline: 1px solid var(--accent);
208  outline-offset: 2px;
209}
210input:is([type="checkbox"], [type="radio"]) {
211  padding: 0;
212  accent-color: var(--accent);
213}
214/* a button among words, as tall as they are */
215:where(button.link) {
216  padding: 0;
217}
218
219/* ioskeley-alike mono has a larger x-height than inter, so it sits a step down */
220/* on an even pixel: 16 to 14, 14 to 12 */
221pre,
222code,
223kbd {
224  font-family: var(--mono);
225  font-size: round(nearest, 0.875em, 2px);
226  font-weight: 500;
227}
228pre {
229  margin: 8px 0;
230  padding: 8px 16px;
231  background: var(--panel);
232  border-left: 2px solid var(--line-strong);
233  overflow-x: auto;
234  white-space: pre-wrap;
235  overflow-wrap: anywhere;
236}
237/* source, as sorcery's blob view: each line shares a grid row with its gutter, so wrapped
238   source makes its row taller without displacing the gutter below */
239pre.code {
240  display: grid;
241  grid-template-columns: max-content minmax(0, 1fr);
242  padding: 8px 0;
243}
244pre.code.bare {
245  grid-template-columns: minmax(0, 1fr);
246}
247.code-line {
248  display: contents;
249}
250pre.code .ln {
251  padding: 0 8px 0 12px;
252  text-align: right;
253  color: var(--muted);
254  white-space: pre;
255  user-select: none;
256  border-right: 1px solid var(--line);
257}
258.code-text {
259  min-width: 0;
260  min-height: 1lh;
261  padding: 0 16px;
262  white-space: pre-wrap;
263  overflow-wrap: anywhere;
264}
265
266/* syntax highlighting, as sorcery's and char.lt */
267a-c,
268a-cd,
269a-er {
270  color: var(--hl-comment);
271}
272a-k,
273a-kc,
274a-ko,
275a-kd,
276a-ke,
277a-kf,
278a-ki,
279a-kp,
280a-kr,
281a-kt,
282a-ky,
283a-km,
284a-dr,
285a-in,
286a-sc,
287a-rp,
288a-cn,
289a-ex,
290a-pp,
291a-co,
292a-cb,
293a-m,
294a-tu,
295a-tr {
296  color: var(--hl-keyword);
297  font-weight: 600;
298}
299/* builtins & types */
300a-t,
301a-tb,
302a-tq,
303a-tf,
304a-fb {
305  color: var(--hl-builtin);
306}
307a-s,
308a-ss,
309a-se,
310a-rx,
311a-ch,
312a-cs {
313  color: var(--hl-string);
314}
315a-n {
316  color: var(--hl-number);
317}
318a-f,
319a-fm,
320a-fd,
321a-fc,
322a-cr,
323a-ns,
324a-tg,
325a-td,
326a-at,
327a-pr,
328a-vm,
329a-l {
330  color: var(--hl-ident);
331}
332a-da {
333  color: var(--hl-string);
334}
335a-dd {
336  color: var(--hl-comment);
337}
338a-em {
339  font-style: italic;
340}
341a-st,
342a-tt {
343  font-weight: 600;
344}
345a-tx {
346  text-decoration: line-through;
347}
348
349/* a key, a step below code; its line is its own size, so a line of small hints keeps its height */
350kbd {
351  font-size: round(nearest, 0.75em, 2px);
352  line-height: 1;
353  background: var(--raised);
354  border: 1px solid var(--line);
355  padding: 0 4px;
356}
357time {
358  font-variant-numeric: tabular-nums;
359}
360
361.error {
362  color: var(--error);
363}
364/* an error's place takes no room until there is one */
365.error:empty {
366  display: none;
367}
368
369/* a chevron, as sorcery's diffs and chordpad's disclosures */
370details > summary {
371  list-style: none;
372  cursor: pointer;
373}
374details > summary::-webkit-details-marker {
375  display: none;
376}
377details > summary::before {
378  content: "";
379  display: inline-block;
380  position: relative;
381  top: -0.25em;
382  flex: none;
383  width: 0.4em;
384  height: 0.4em;
385  margin-right: 8px;
386  border-right: 1.5px solid currentColor;
387  border-bottom: 1.5px solid currentColor;
388  transform: rotate(45deg);
389}
390details:not([open]) > summary::before {
391  top: -0.05em;
392  transform: rotate(-45deg);
393}
394
395/* login */
396
397.login {
398  display: flex;
399  flex-direction: column;
400  gap: 12px;
401  width: 288px;
402  margin: 30vh auto 0;
403}
404.login h1 {
405  margin: 0;
406  font-size: var(--text-display);
407  font-weight: 520;
408}
409
410/* layout */
411
412/* one grid: the bars share a row, so they share a height */
413.app {
414  display: grid;
415  grid-template:
416    "brand bar" auto
417    "side pane" minmax(0, 1fr)
418    / var(--sidebar) minmax(0, 1fr);
419  height: 100dvh;
420}
421/* a view's bar and pane are the app's grid items */
422.view {
423  display: contents;
424}
425
426/* toolbars, as chordpad's */
427.brand-bar,
428.bar {
429  display: flex;
430  flex-wrap: wrap;
431  align-items: center;
432  gap: 8px 8px;
433  padding: 8px 12px;
434  background: var(--panel);
435  border-bottom: 1px solid var(--line);
436  font-size: var(--text-ui);
437}
438.brand-bar {
439  grid-area: brand;
440  gap: 8px;
441  padding-left: 16px;
442  border-right: 1px solid var(--line);
443}
444.bar {
445  grid-area: bar;
446  min-width: 0;
447}
448.bar-title {
449  font-weight: 650;
450}
451.start-blank {
452  margin-left: auto;
453}
454.pane {
455  grid-area: pane;
456  min-width: 0;
457  min-height: 0;
458}
459
460/* an extension's view takes the main pane, and its conversation the sidebar's place */
461.app.viewing {
462  grid-template-columns: clamp(352px, 30vw, 544px) minmax(0, 1fr);
463}
464.app.viewing > .sidebar {
465  display: none;
466}
467.app.viewing .pane.conversation {
468  grid-area: side;
469  border-right: 1px solid var(--line);
470}
471.extension-view {
472  overflow: auto;
473}
474.view-missing {
475  margin: 32px;
476  color: var(--muted);
477}
478.view-links {
479  display: inline-flex;
480  gap: 8px;
481}
482.view-links a {
483  color: var(--muted);
484}
485.view-links a:hover,
486.view-links a[aria-current="page"] {
487  color: var(--accent);
488}
489.view-links a[aria-current="page"]:hover {
490  color: var(--accent-fade);
491}
492
493.sidebar {
494  grid-area: side;
495  display: flex;
496  flex-direction: column;
497  min-height: 0;
498  background: var(--panel);
499  border-right: 1px solid var(--line);
500  font-size: var(--text-ui);
501}
502.brand {
503  flex: 1;
504  font-size: var(--text-title);
505  font-weight: 520;
506}
507.brand-bar a {
508  color: var(--muted);
509}
510.brand-bar a:hover,
511.brand-bar a.active {
512  color: var(--accent);
513}
514.brand-bar a.active:hover {
515  color: var(--accent-fade);
516}
517
518/* hollow while the socket is down */
519.dot {
520  width: 7px;
521  height: 7px;
522  border: 1.5px solid var(--muted);
523  border-radius: 50%;
524}
525.dot.up {
526  border-color: var(--ok);
527  background: var(--ok);
528}
529
530/* the way to a new conversation, at the top of the list */
531.sidebar > .new {
532  display: flex;
533  align-items: baseline;
534  padding: 8px 16px;
535  border-bottom: 1px solid var(--line);
536}
537.sidebar > .new::before {
538  content: "+";
539  width: 16px;
540  color: var(--muted);
541}
542.sidebar > .new.active {
543  background: var(--raised);
544  box-shadow: inset 2px 0 var(--accent);
545}
546
547/* what the chosen extensions ask of a new conversation */
548:is(.seed, .configuration, .project-picker) {
549  display: flex;
550  flex-direction: column;
551  gap: 4px;
552  margin: 0;
553  padding: 0;
554  border: 0;
555}
556:is(.seed, .configuration) legend {
557  margin-bottom: 4px;
558  padding: 0;
559  color: var(--hl-ident);
560  font-family: var(--mono);
561  font-weight: 500;
562}
563:is(.seed, .configuration, .project-picker, .project-dialog, .system-prompt) .field {
564  display: flex;
565  flex-direction: column;
566  gap: 2px;
567}
568:is(.seed, .configuration, .project-picker, .project-dialog, .system-prompt) .field > :is(span, label) {
569  color: var(--muted);
570}
571:is(.seed, .configuration) .toggle {
572  display: flex;
573  gap: 4px;
574  align-items: center;
575}
576/* a long list of choices, such as every model, scrolls rather than pushing the form away */
577:is(.seed, .configuration) .choices {
578  max-height: 160px;
579  overflow-y: auto;
580  margin: 0;
581  padding: 4px 8px;
582  border: 1px solid var(--line);
583}
584
585.toggles {
586  display: flex;
587  flex-wrap: wrap;
588  gap: 4px 12px;
589}
590.toggles label {
591  display: flex;
592  gap: 4px;
593  align-items: center;
594}
595
596/* rows carry their top edge, as sorcery's catalog; forks sit under their parents, a step in */
597.conversations {
598  overflow-y: auto;
599  padding: 0 0 16px;
600}
601.conversations .item {
602  position: relative;
603  display: flex;
604  align-items: center;
605  /* a step of 16px puts a fork's text under its project's name */
606  padding-left: calc(var(--depth) * 16px);
607  border-top: 1px solid var(--line);
608}
609.conversations .item:first-child {
610  border-top: 0;
611}
612@media (hover: hover) {
613  .conversations .item:hover {
614    background: var(--raised);
615  }
616}
617.conversations .item.active {
618  background: var(--raised);
619  box-shadow: inset 2px 0 var(--accent);
620}
621.conversations .item.active:hover {
622  box-shadow: inset 2px 0 var(--accent-fade);
623}
624.conversations a {
625  flex: 1;
626  min-width: 0;
627  display: flex;
628  gap: 8px;
629  align-items: baseline;
630  padding: 4px 8px 4px 0;
631  color: var(--text);
632}
633.conversations .item:not(.active, .unread):not(:has(.busy.on)) > a {
634  opacity: 0.4;
635}
636.conversations .conversation-name {
637  flex: 1;
638  min-width: 0;
639  width: 0;
640  margin: 2px 8px 2px 0;
641}
642.conversations .conversation-name[aria-invalid="true"] {
643  border-color: var(--error);
644}
645.conversations .item > .conversation-name:not([hidden]) ~ .archive {
646  display: none;
647}
648.conversations .tid {
649  font-family: var(--mono);
650  font-weight: 500;
651  color: var(--hl-ident);
652}
653.conversations .forks {
654  color: var(--muted);
655  font-variant-numeric: tabular-nums;
656}
657.conversations time {
658  margin-left: auto;
659  color: var(--muted);
660}
661.conversations .preview {
662  min-width: 0;
663  overflow: hidden;
664  text-overflow: ellipsis;
665  white-space: nowrap;
666}
667.conversations time,
668.conversations .forks {
669  flex: none;
670}
671/* there while it answers */
672.conversations .busy {
673  display: none;
674  flex: none;
675  align-self: center;
676  width: 6px;
677  height: 6px;
678  margin-left: auto;
679  border-radius: 50%;
680  background: var(--accent);
681}
682.conversations .busy:is(.on, .unread) {
683  display: block;
684}
685.conversations .busy:is(.on, .unread) + time {
686  margin-left: 0;
687}
688.conversations .busy.on {
689  background: transparent;
690  box-shadow: inset 0 0 0 1px var(--accent);
691}
692.conversations .item.unread .preview {
693  font-weight: 600;
694}
695/* over the row's end, where its time is, while the pointer is on it */
696.conversations .archive {
697  display: none;
698  position: absolute;
699  top: 0;
700  right: 0;
701  bottom: 0;
702  border: 0;
703  padding: 0 8px 0 16px;
704  background: linear-gradient(to right, transparent, var(--raised) 12px);
705  color: var(--muted);
706  font-size: var(--text-small);
707}
708@media (hover: hover) {
709  .conversations .item:hover .archive {
710    display: block;
711  }
712}
713.conversations .archive:hover {
714  color: var(--accent);
715}
716.conversations .conversation-actions {
717  display: none;
718}
719
720/* a project's conversations under its name, which a little air sets apart */
721.project-group {
722  display: flex;
723  align-items: baseline;
724  border-top: 1px solid var(--line);
725}
726.project-group[data-drop="before"] {
727  box-shadow: inset 0 2px var(--accent);
728}
729.project-group[data-drop="after"] {
730  box-shadow: inset 0 -2px var(--accent);
731}
732.conversations > .project-group:first-child {
733  border-top: 0;
734}
735.conversations .project-group + .item {
736  border-top: 0;
737}
738.project-toggle {
739  flex: 1;
740  min-width: 0;
741  display: flex;
742  align-items: baseline;
743  gap: 8px;
744  padding: 8px 8px 8px 16px;
745  border: 0;
746  background: none;
747  text-align: left;
748  color: var(--text);
749}
750/* the mark and the name line up with the new conversation's */
751.project-toggle::before {
752  margin-right: 0;
753  color: var(--muted);
754}
755.project-toggle:hover::before {
756  color: var(--accent);
757}
758.project-name {
759  min-width: 0;
760  overflow: hidden;
761  text-overflow: ellipsis;
762  white-space: nowrap;
763  font-weight: 600;
764}
765.project-count {
766  flex: none;
767  color: var(--muted);
768  font-variant-numeric: tabular-nums;
769}
770.conversations .project-toggle .busy {
771  margin-left: 0;
772}
773.project-action {
774  flex: none;
775  width: 28px;
776  padding: 8px 0 4px;
777  font-size: var(--text-body);
778}
779@media (hover: hover) {
780  .project-group:not(:hover, :focus-within) .project-action {
781    visibility: hidden;
782  }
783}
784
785/* a fork that left its parent's project, with the way back to it */
786.conversations .item > .parent-link {
787  flex: none;
788  padding: 4px;
789  color: var(--muted);
790}
791.conversations .item > .parent-link:hover {
792  color: var(--accent);
793}
794
795.sidebar-footer {
796  display: flex;
797  flex-wrap: wrap;
798  gap: 4px 16px;
799  margin-top: auto;
800  padding: 8px 16px 12px;
801  border-top: 1px solid var(--line);
802}
803/* the disclosures' chevron, on a button: a row is a link, which may not hold one */
804.chevron {
805  align-self: stretch;
806  /* so a row's text starts on the sidebar's 16px line, under its project's chevron, hanging out from the name */
807  width: 16px;
808  padding: 0;
809  border: 0;
810  background: none;
811  color: var(--muted);
812}
813.chevron:disabled {
814  visibility: hidden;
815}
816.chevron:hover {
817  color: var(--accent);
818}
819/* a background subagent's mark, ahead of its name: delegated from the conversation above, which a chevron
820 * on a nested row would not say */
821.conversations .delegated {
822  flex: none;
823  color: var(--muted);
824}
825.chevron::before,
826.project-toggle::before,
827.tool-header::before {
828  content: "";
829  flex: none;
830  display: inline-block;
831  position: relative;
832  top: -0.17em;
833  width: 0.4em;
834  height: 0.4em;
835  border-right: 1.5px solid currentColor;
836  border-bottom: 1.5px solid currentColor;
837  transform: rotate(45deg);
838}
839.chevron[aria-expanded="false"]::before,
840.project-toggle[aria-expanded="false"]::before,
841.tool-header[aria-expanded="false"]::before {
842  top: -0.05em;
843  transform: rotate(-45deg);
844}
845/* a project's mark sits on the baseline rather than centred in a button, so it is raised to the capitals' middle */
846.project-toggle::before {
847  top: -0.27em;
848}
849.project-toggle[aria-expanded="false"]::before {
850  top: -0.17em;
851}
852
853/* the list, from a view, on screens too narrow for both */
854.back {
855  display: none;
856  grid-area: back;
857  align-items: center;
858  gap: 8px;
859  padding: 0 8px 0 16px;
860  background: var(--panel);
861  border-bottom: 1px solid var(--line);
862  color: var(--muted);
863}
864.back::before {
865  content: "";
866  width: 8px;
867  height: 8px;
868  border-left: 1.5px solid currentColor;
869  border-bottom: 1.5px solid currentColor;
870  transform: rotate(45deg);
871}
872/* another conversation has something new */
873.back.unread::after {
874  content: "";
875  width: 6px;
876  height: 6px;
877  border-radius: 50%;
878  background: var(--accent);
879}
880
881.empty {
882  display: grid;
883  place-items: center;
884  color: var(--muted);
885}
886.empty p {
887  margin: 0;
888}
889
890/* a new conversation: where it works, how it thinks, and with what, from the top, so that options appearing below
891   move nothing above them; and the composer that starts it, where a conversation's is */
892.start-pane {
893  display: flex;
894  flex-direction: column;
895}
896.start {
897  display: flex;
898  flex-direction: column;
899  gap: 24px;
900  font-size: var(--text-ui);
901  max-width: var(--column);
902  margin: 0 auto;
903  padding: 32px 24px;
904}
905.start-row {
906  display: flex;
907  flex-direction: column;
908  gap: 8px;
909}
910.start-row > h3 {
911  margin: 0;
912  color: var(--muted);
913  font-size: var(--text-ui);
914  font-weight: 600;
915}
916.start-fields {
917  display: flex;
918  flex-wrap: wrap;
919  align-items: flex-end;
920  gap: 12px;
921  min-width: 0;
922}
923.start-hint {
924  margin: 0;
925  color: var(--muted);
926}
927.start-where:not(:has(.project-picker:not([hidden]), .start-environment:not(:empty))) {
928  display: none;
929}
930/* a place is a line of fields, the folder taking what room is left */
931.start :is(.project-picker, .start-environment, .start-environment .seed) {
932  display: flex;
933  flex-direction: row;
934  flex-wrap: wrap;
935  align-items: flex-end;
936  gap: 12px;
937}
938.start-environment {
939  flex: 1 1 320px;
940}
941.start-environment .seed {
942  flex: 1;
943}
944.start-environment .field:has(.folder-input) {
945  flex: 1 1 240px;
946}
947.start .model {
948  max-width: 320px;
949}
950.start-options {
951  display: grid;
952  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
953  gap: 16px 24px;
954  width: 100%;
955}
956.start-options:empty,
957/* an extension's own view of its options, while it has nothing to ask */ .start-options > div:not(:has(> :not([hidden]))) {
958  display: none;
959}
960
961/* conversation */
962
963.conversation {
964  display: flex;
965  flex-direction: column;
966}
967
968.conversation-header :is(.model, .thinking-level) {
969  font-size: var(--text-small);
970}
971.conversation-header .model {
972  max-width: 320px;
973}
974/* the right-hand group moves to a second row as a unit, flush right wherever it lands */
975.conversation-header .trailing {
976  display: flex;
977  flex-wrap: wrap;
978  justify-content: flex-end;
979  align-items: center;
980  gap: 8px;
981  margin-left: auto;
982}
983.draft-header .spacer {
984  flex: 1;
985}
986.draft-header .tid {
987  font-family: var(--mono);
988  font-weight: 500;
989  color: var(--hl-ident);
990}
991.draft-header .note {
992  color: var(--muted);
993}
994.extension-headers {
995  display: inline-flex;
996  align-items: center;
997  gap: 8px;
998}
999.extension-headers > :empty,
1000.extension-headers:not(:has(> :not(:empty, [hidden]))) {
1001  display: none;
1002}
1003.view-links,
1004.extension-headers {
1005  font-size: var(--text-small);
1006}
1007
1008.conversation-header .usage {
1009  color: var(--muted);
1010  font-family: var(--mono);
1011  font-variant-numeric: tabular-nums;
1012}
1013.conversation-header .usage .ctx-warn {
1014  color: var(--warn);
1015}
1016.conversation-header .usage .ctx-high {
1017  color: var(--error);
1018}
1019.conversation-header .extensions {
1020  position: relative;
1021}
1022.conversation-header .extensions > summary {
1023  color: var(--muted);
1024}
1025.conversation-header .extensions > summary:hover {
1026  color: var(--accent);
1027}
1028.conversation-header .extensions .extension-options {
1029  position: absolute;
1030  z-index: 2;
1031  top: calc(100% + 8px);
1032  left: 0;
1033  flex-direction: column;
1034  display: flex;
1035  gap: 8px;
1036  min-width: 288px;
1037  max-height: min(70vh, 576px);
1038  overflow-y: auto;
1039  padding: 8px 12px;
1040  background: var(--panel);
1041  border: 1px solid var(--line);
1042  box-shadow: var(--shadow);
1043  white-space: nowrap;
1044}
1045.extension-choice > label {
1046  display: flex;
1047  gap: 4px;
1048  align-items: center;
1049}
1050.extension-choice > label + .configuration {
1051  margin: 4px 0 0 20px;
1052}
1053.configuration-status {
1054  font-size: var(--text-small);
1055  white-space: normal;
1056}
1057.configuration-status:empty {
1058  display: none;
1059}
1060
1061.scroller {
1062  container: transcript-pane / inline-size;
1063  flex: 1;
1064  min-height: 0;
1065  overflow-y: auto;
1066  /* the transcript keeps its place whether or not it is long enough to scroll */
1067  scrollbar-gutter: stable both-edges;
1068}
1069/* takes no room after the transcript, and holds its button to the bottom of the view */
1070.jump-to-bottom {
1071  position: sticky;
1072  bottom: 0;
1073  height: 0;
1074}
1075.jump-to-bottom > button {
1076  position: absolute;
1077  bottom: 24px;
1078  /* in the margin just past the transcript's text where there is room, else at the pane's edge */
1079  left: min(50% + var(--column) / 2 - 16px, 100% - var(--target) - 8px);
1080  width: var(--target);
1081  height: var(--target);
1082  padding: 0;
1083  font-size: var(--text-title);
1084  background: var(--panel);
1085  border: 1px solid var(--line);
1086  box-shadow: var(--shadow);
1087}
1088.jump-to-bottom > button::before {
1089  content: "↓";
1090}
1091.jump-to-bottom > button:hover {
1092  border-color: var(--line-strong);
1093  color: var(--accent);
1094}
1095/* the transcript fades out above the composer, rather than stopping at its edge */
1096.pane.conversation > .scroller {
1097  mask-image: linear-gradient(to top, transparent, black 24px);
1098}
1099.transcript {
1100  max-width: var(--column);
1101  margin: 0 auto;
1102  padding: 16px 24px 32px;
1103}
1104.entries > * {
1105  contain: layout style;
1106}
1107/* which keeps their content's margins from collapsing through their own, so a message's content has none at its edges */
1108.message > .blocks > :first-child,
1109.message > .blocks > :first-child > :first-child {
1110  margin-top: 0;
1111}
1112.message > .blocks > :last-child,
1113.message > .blocks > :last-child > :last-child {
1114  margin-bottom: 0;
1115}
1116
1117.message {
1118  position: relative;
1119  margin: 16px 0;
1120}
1121.message-time {
1122  display: block;
1123  margin-top: 4px;
1124  color: var(--muted);
1125  font-size: var(--text-small);
1126  line-height: 16px;
1127  white-space: nowrap;
1128}
1129@container transcript-pane (min-width: 960px) {
1130  .message-time {
1131    position: absolute;
1132    right: calc(100% + 12px);
1133    bottom: 4px;
1134    width: 80px;
1135    margin: 0;
1136    text-align: right;
1137  }
1138  .message.user > .message-time {
1139    bottom: 12px;
1140  }
1141}
1142.message.user {
1143  padding: 8px 16px;
1144  background: var(--panel);
1145  border-left: 2px solid var(--accent);
1146}
1147.message.user .text {
1148  white-space: pre-wrap;
1149}
1150.message .image {
1151  max-width: 100%;
1152  max-height: 320px;
1153}
1154.message .note {
1155  color: var(--muted);
1156  font-size: var(--text-ui);
1157}
1158.message > .error {
1159  font-size: var(--text-ui);
1160}
1161
1162/* prose, as sorcery's readmes */
1163.markdown {
1164  overflow-wrap: anywhere;
1165}
1166.markdown > :first-child {
1167  margin-top: 0;
1168}
1169.markdown > :last-child {
1170  margin-bottom: 0;
1171}
1172.markdown a {
1173  text-decoration: underline;
1174  text-decoration-thickness: 1px;
1175  text-underline-offset: 0.2em;
1176}
1177.markdown :is(h1, h2, h3, h4) {
1178  font-weight: 650;
1179  line-height: round(nearest, 1.2em, 4px);
1180  margin: 24px 0 8px;
1181}
1182.markdown h1 {
1183  font-size: var(--text-display);
1184}
1185.markdown h2 {
1186  font-size: var(--text-title);
1187}
1188.markdown :is(h3, h4) {
1189  font-size: var(--text-body);
1190}
1191.markdown code {
1192  background: var(--panel);
1193  padding: 2px 4px;
1194  margin: 0 2px;
1195}
1196.markdown pre code {
1197  background: none;
1198  padding: 0;
1199  margin: 0;
1200  font-size: inherit;
1201}
1202.markdown blockquote {
1203  margin: 12px 0;
1204  padding-left: 16px;
1205  border-left: 2px solid var(--line-strong);
1206  color: var(--muted);
1207}
1208/* wide tables scroll rather than widen the transcript */
1209.markdown table {
1210  display: block;
1211  overflow-x: auto;
1212  border-collapse: collapse;
1213}
1214.markdown :is(th, td) {
1215  border: 1px solid var(--line);
1216  padding: 4px 8px;
1217}
1218.markdown img {
1219  max-width: 100%;
1220}
1221
1222.thinking,
1223.system {
1224  margin: 8px 0;
1225  color: var(--muted);
1226  font-size: var(--text-ui);
1227}
1228.thinking > summary:hover,
1229.system > summary:hover {
1230  color: var(--accent);
1231}
1232.thinking .markdown {
1233  margin: 8px 0 0 16px;
1234}
1235.thinking-pending {
1236  margin: 8px 0;
1237  color: var(--muted);
1238  font-size: var(--text-ui);
1239}
1240.thinking-pending > span {
1241  display: inline-block;
1242  animation: thinking-wave 1s ease-in-out infinite alternate;
1243}
1244@keyframes thinking-wave {
1245  from {
1246    transform: translateY(0.18em);
1247  }
1248  to {
1249    transform: translateY(-0.18em);
1250  }
1251}
1252/* a flex row, so the groups sit beside the chevron rather than wrapping under it */
1253.system > summary {
1254  display: flex;
1255  align-items: baseline;
1256}
1257.system-label {
1258  margin-right: 12px;
1259  font-weight: 600;
1260}
1261.system-groups {
1262  display: grid;
1263  grid-template-columns: auto 1fr;
1264  gap: 2px 12px;
1265  align-items: baseline;
1266  min-width: 0;
1267}
1268.system-kind {
1269  text-align: right;
1270}
1271.system-name {
1272  font-family: var(--mono);
1273  white-space: nowrap;
1274  color: color-mix(in srgb, var(--text) 55%, var(--muted));
1275}
1276.system h4 {
1277  margin: 8px 0 0;
1278  font-size: var(--text-small);
1279  font-weight: 650;
1280}
1281
1282.event {
1283  margin: 8px 0;
1284  color: var(--muted);
1285  font-size: var(--text-ui);
1286}
1287.event .event-ext {
1288  margin-right: 8px;
1289  color: var(--hl-ident);
1290}
1291
1292/* a background subagent's report: not a message, but what it was asked and how it ended */
1293.report {
1294  margin: 8px 0;
1295  padding: 8px 12px;
1296  border: 1px solid var(--line);
1297  font-size: var(--text-ui);
1298}
1299.report .subagent-meta {
1300  color: var(--muted);
1301}
1302.report-task {
1303  white-space: pre-wrap;
1304  overflow-wrap: anywhere;
1305}
1306.report .markdown {
1307  margin-top: 4px;
1308}
1309
1310.divider {
1311  margin: 24px 0;
1312  padding-top: 8px;
1313  border-top: 1px solid var(--line-strong);
1314  color: var(--muted);
1315  font-size: var(--text-ui);
1316  text-align: center;
1317}
1318
1319/* tool cards, as sorcery's file diffs */
1320.tool {
1321  position: relative;
1322  margin: 8px 0;
1323  border: 1px solid var(--line);
1324}
1325.tool + .tool {
1326  margin-top: 8px;
1327}
1328.tool-header {
1329  display: flex;
1330  align-items: baseline;
1331  gap: 8px;
1332  width: 100%;
1333  padding: 4px 12px;
1334  border: 0;
1335  border-bottom: 1px solid var(--line);
1336  background: var(--panel);
1337  color: var(--muted);
1338  font-size: var(--text-ui);
1339  text-align: left;
1340}
1341.tool-header:hover {
1342  color: var(--text);
1343}
1344/* a preview, faded where it is cut off, until the reader expands it */
1345.tool-preview {
1346  position: relative;
1347}
1348.tool[data-view="preview"] > .tool-preview {
1349  max-height: 120px;
1350  overflow: hidden;
1351}
1352.tool[data-view="closed"] > .tool-preview {
1353  display: none;
1354}
1355.tool[data-view="closed"] > .tool-header {
1356  border-bottom: 0;
1357}
1358.tool-blur {
1359  position: absolute;
1360  bottom: 0;
1361  left: 0;
1362  width: 100%;
1363  height: 64px;
1364  overflow: hidden;
1365  pointer-events: none;
1366}
1367.tool-blur > span {
1368  --blur: 1px;
1369  --start: 0%;
1370  --end: 40%;
1371  position: absolute;
1372  inset: 0;
1373  backdrop-filter: blur(var(--blur));
1374  mask-image: linear-gradient(to bottom, transparent var(--start), black var(--end));
1375}
1376.tool-blur > span:nth-child(2) {
1377  --blur: 2px;
1378  --start: 20%;
1379  --end: 60%;
1380}
1381.tool-blur > span:nth-child(3) {
1382  --blur: 4px;
1383  --start: 40%;
1384  --end: 80%;
1385}
1386.tool-blur > span:nth-child(4) {
1387  --blur: 8px;
1388  --start: 60%;
1389  --end: 100%;
1390}
1391.tool-more {
1392  position: absolute;
1393  inset: 0;
1394  display: flex;
1395  align-items: flex-end;
1396  justify-content: center;
1397  padding: 2px;
1398  border: 0;
1399  /* the label reads over the page rather than over the text it cuts off */
1400  background: linear-gradient(to bottom, transparent 50%, var(--bg));
1401  color: var(--muted);
1402  font-size: var(--text-small);
1403}
1404.tool-less {
1405  display: block;
1406  width: 100%;
1407  padding: 2px;
1408  border: 0;
1409  background: none;
1410  color: var(--muted);
1411  font-size: var(--text-small);
1412}
1413.tool-more:hover,
1414.tool-less:hover {
1415  color: var(--accent);
1416}
1417.tool-images {
1418  display: flex;
1419  flex-direction: column;
1420  align-items: flex-start;
1421  gap: 12px;
1422  padding: 12px;
1423}
1424.tool-images:empty {
1425  display: none;
1426}
1427.tool-name {
1428  font-family: var(--mono);
1429  font-weight: 600;
1430  color: var(--text);
1431}
1432.tool-summary {
1433  flex: 1;
1434  min-width: 0;
1435  font-family: var(--mono);
1436  font-weight: 500;
1437  overflow: hidden;
1438  text-overflow: ellipsis;
1439  white-space: nowrap;
1440}
1441.tool-status {
1442  font-variant-numeric: tabular-nums;
1443}
1444.tool-time {
1445  color: var(--muted);
1446  font-variant-numeric: tabular-nums;
1447}
1448.tool[data-status="ok"] > .tool-header .tool-status {
1449  color: var(--ok);
1450}
1451.tool[data-status="error"] > .tool-header .tool-status {
1452  color: var(--error);
1453}
1454.tool:is([data-status="running"], [data-status="streaming"], [data-status="pending"]) > .tool-header .tool-status {
1455  color: var(--running);
1456}
1457.tool:is([data-status="running"], [data-status="streaming"]) {
1458  border-color: var(--line-strong);
1459}
1460.tool-body {
1461  padding: 4px 12px 8px;
1462}
1463.tool-body pre {
1464  margin: 8px 0;
1465}
1466.tool-body .note {
1467  margin: 4px 0 0;
1468  color: var(--muted);
1469  font-size: var(--text-ui);
1470}
1471.tool-body pre.error {
1472  color: var(--error);
1473  border-left-color: var(--error);
1474}
1475/* a script's calls read as one list */
1476.nested {
1477  margin: 8px 0;
1478}
1479.nested > .tool,
1480.nested > .tool + .tool {
1481  margin: 0;
1482}
1483.nested > .tool + .tool {
1484  border-top: 0;
1485}
1486.nested > .tool > .tool-header {
1487  background: none;
1488}
1489.subagent-meta {
1490  display: flex;
1491  align-items: baseline;
1492  flex-wrap: wrap;
1493  gap: 8px 16px;
1494  padding: 0 0 4px;
1495  font-size: var(--text-ui);
1496}
1497.subagent-meta .tid {
1498  margin-left: auto;
1499}
1500.subagent-history {
1501  max-height: 384px;
1502  overscroll-behavior: contain;
1503  border-top: 1px solid var(--line);
1504}
1505.subagent-history .transcript {
1506  padding: 0 4px 8px;
1507}
1508.codemode-text[data-view="preview"] > .tool-preview {
1509  max-height: 96px;
1510}
1511.codemode-text pre {
1512  margin: 0;
1513  border-left: 0;
1514}
1515
1516/* composer */
1517
1518.inbox {
1519  flex-shrink: 0;
1520  max-height: 35vh;
1521  overflow-y: auto;
1522}
1523.queued-content {
1524  white-space: pre-wrap;
1525  overflow-wrap: anywhere;
1526}
1527.queued-actions {
1528  display: flex;
1529  flex-wrap: wrap;
1530  gap: 8px;
1531  margin: 4px 0;
1532}
1533.queued-editor textarea {
1534  width: 100%;
1535  resize: vertical;
1536  min-height: 64px;
1537}
1538.queued-error {
1539  color: var(--error);
1540  overflow-wrap: anywhere;
1541}
1542.working {
1543  display: flex;
1544  align-items: center;
1545  flex-shrink: 0;
1546  gap: 8px;
1547  width: 100%;
1548  max-width: var(--column);
1549  margin: 0 auto;
1550  padding: 4px 24px;
1551  color: var(--muted);
1552  font-size: var(--text-ui);
1553}
1554.working-spinner {
1555  width: 12px;
1556  height: 12px;
1557  border: 2px solid var(--line);
1558  border-top-color: var(--running);
1559  border-radius: 50%;
1560  animation: working-spin 0.8s linear infinite;
1561}
1562@keyframes working-spin {
1563  to {
1564    transform: rotate(360deg);
1565  }
1566}
1567@media (prefers-reduced-motion: reduce) {
1568  .working-spinner,
1569  .tree-entry[aria-busy="true"] .tree-row::after,
1570  .thinking-pending > span {
1571    animation: none;
1572  }
1573}
1574
1575.inbox .queued {
1576  max-width: var(--column);
1577  margin: 0 auto;
1578  padding: 4px 24px;
1579  color: var(--muted);
1580  font-size: var(--text-ui);
1581}
1582/* a queued message keeps what can be done to it at its line's end */
1583.inbox .queued:has(> .queued-actions) {
1584  display: grid;
1585  grid-template-columns: minmax(0, 1fr) auto;
1586  column-gap: 12px;
1587  align-items: baseline;
1588}
1589.inbox .queued > :is(.queued-editor, .queued-error) {
1590  grid-column: 1 / -1;
1591}
1592.inbox .queued > .queued-actions {
1593  margin: 0;
1594}
1595.inbox .queued > .queued-actions button {
1596  padding: 0;
1597  font-size: var(--text-small);
1598}
1599.inbox .mode {
1600  margin-right: 8px;
1601  color: var(--hl-ident);
1602}
1603
1604.notice {
1605  align-self: center;
1606  width: calc(100% - 48px);
1607  max-width: calc(var(--column) - 48px);
1608  margin-bottom: 8px;
1609  padding: 8px 12px;
1610  background: var(--panel);
1611  border-left: 2px solid var(--line-strong);
1612  font-family: var(--mono);
1613  font-size: var(--text-small);
1614  white-space: pre-wrap;
1615}
1616.notice.error {
1617  border-left-color: var(--error);
1618}
1619
1620.composer {
1621  position: relative;
1622  display: flex;
1623  flex-direction: column;
1624  gap: 4px;
1625  width: 100%;
1626  max-width: var(--column);
1627  margin: 0 auto;
1628  padding: 0 24px 12px;
1629}
1630.attachments {
1631  display: flex;
1632  gap: 8px;
1633  overflow-x: auto;
1634  padding: 4px 0;
1635}
1636.attachment {
1637  position: relative;
1638  flex: 0 0 112px;
1639  display: flex;
1640  flex-direction: column;
1641  gap: 4px;
1642  padding: 4px;
1643  border: 1px solid var(--line);
1644  background: var(--panel);
1645  font-size: var(--text-small);
1646}
1647.attachment img {
1648  width: 100%;
1649  height: 72px;
1650  object-fit: contain;
1651}
1652.attachment-name {
1653  overflow: hidden;
1654  text-overflow: ellipsis;
1655  white-space: nowrap;
1656  color: var(--muted);
1657}
1658.attachment button {
1659  position: absolute;
1660  top: 0;
1661  right: 0;
1662  width: 28px;
1663  height: 28px;
1664  padding: 0;
1665  background: var(--panel);
1666  line-height: 1;
1667}
1668.attachment-status {
1669  overflow-wrap: anywhere;
1670  color: var(--muted);
1671}
1672.attachment[data-status="error"] {
1673  border-color: var(--error);
1674}
1675.attachment[data-status="error"] .attachment-status,
1676.attachment-error {
1677  color: var(--error);
1678  font-size: var(--text-small);
1679}
1680.composer-input {
1681  display: flex;
1682  /* a one-row text area is shorter than the controls, and its text should sit centered against them */
1683  align-items: center;
1684  gap: 8px;
1685  padding: 4px;
1686  background: var(--panel);
1687  border: 1px solid var(--line);
1688}
1689.composer-input:focus-within {
1690  border-color: var(--line-strong);
1691}
1692.composer-input.stacked {
1693  flex-direction: column;
1694  align-items: stretch;
1695  gap: 0;
1696}
1697.composer-controls {
1698  display: none;
1699  flex: none;
1700  align-self: flex-end;
1701  gap: 8px;
1702}
1703.composer-input:has(.abort:not([hidden])) .composer-controls {
1704  display: flex;
1705}
1706.composer-input .abort {
1707  flex: none;
1708  display: grid;
1709  place-items: center;
1710  width: var(--target);
1711  height: var(--target);
1712  padding: 0;
1713  background: var(--panel);
1714  border: 1px solid var(--line);
1715  color: var(--muted);
1716}
1717.composer-input .abort::before {
1718  content: "";
1719  width: 10px;
1720  height: 10px;
1721  background: currentColor;
1722  border-radius: 1px;
1723}
1724.composer-input .abort:hover:not(:disabled) {
1725  border-color: var(--error);
1726  color: var(--error);
1727}
1728.composer textarea {
1729  flex: 1;
1730  min-width: 0;
1731  resize: none;
1732  max-height: 40vh;
1733  padding: 8px 8px;
1734  border: 0;
1735  background: none;
1736}
1737.composer textarea.shell {
1738  font-family: var(--mono);
1739}
1740.composer-input.stacked textarea {
1741  flex: none;
1742  width: 100%;
1743}
1744
1745/* the keys' work, for screens without them */
1746.composer .actions {
1747  display: none;
1748  flex: none;
1749  gap: 8px;
1750}
1751/* a finger's targets, so boxes */
1752.composer .actions button {
1753  height: var(--target);
1754  padding: 4px 12px;
1755  border: 1px solid var(--line);
1756  white-space: nowrap;
1757}
1758.composer .actions :is(.primary, .send-more) {
1759  border-color: var(--accent);
1760}
1761.composer .actions .send {
1762  width: var(--target);
1763  padding: 0;
1764  font-size: 0;
1765}
1766.composer .actions .send::before {
1767  content: "↑";
1768  font-size: var(--text-title);
1769}
1770.send-options {
1771  position: relative;
1772  display: flex;
1773}
1774.composer .actions .send-more {
1775  width: var(--target);
1776  padding: 0;
1777  border-left: 0;
1778}
1779.composer .actions .send-more[aria-expanded="true"] {
1780  color: var(--accent);
1781}
1782.send-menu {
1783  position: absolute;
1784  z-index: 3;
1785  right: 0;
1786  bottom: calc(100% + 8px);
1787  min-width: 160px;
1788  padding: 4px;
1789  background: var(--panel);
1790  border: 1px solid var(--line-strong);
1791  box-shadow: var(--shadow);
1792}
1793.composer .actions .send-menu button {
1794  display: block;
1795  width: 100%;
1796  border: 0;
1797  background: none;
1798  text-align: left;
1799}
1800.composer .actions .send-menu button:hover {
1801  background: var(--raised);
1802  color: var(--accent);
1803}
1804
1805/* keys and what they do, as chordpad's */
1806.hints {
1807  display: flex;
1808  flex-wrap: wrap;
1809  gap: 2px 16px;
1810  color: var(--muted);
1811  font-size: var(--text-small);
1812}
1813.hints kbd + kbd {
1814  margin-left: 2px;
1815}
1816
1817.suggestions {
1818  position: absolute;
1819  bottom: calc(100% - 4px);
1820  left: 24px;
1821  right: 24px;
1822  z-index: 2;
1823  max-height: 288px;
1824  overflow-y: auto;
1825  display: flex;
1826  flex-direction: column;
1827  padding: 4px;
1828  background: var(--panel);
1829  border: 1px solid var(--line);
1830  box-shadow: var(--shadow);
1831}
1832.suggestions button {
1833  display: flex;
1834  gap: 16px;
1835  align-items: center;
1836  border: 0;
1837  background: none;
1838  padding: 4px 12px;
1839  text-align: left;
1840}
1841.suggestions button:hover {
1842  background: var(--raised);
1843}
1844.suggestions button.selected {
1845  background: var(--selected);
1846}
1847.suggestions button.selected:hover {
1848  background: var(--selected-hover);
1849}
1850.suggestions .command {
1851  flex: none;
1852  max-width: 50%;
1853  overflow: hidden;
1854  text-overflow: ellipsis;
1855  white-space: nowrap;
1856  font-family: var(--mono);
1857  font-weight: 600;
1858  color: var(--text);
1859}
1860.suggestions .description {
1861  min-width: 0;
1862  overflow-wrap: anywhere;
1863  color: var(--muted);
1864  font-size: var(--text-ui);
1865}
1866
1867/* a folder field's completions, as the composer's */
1868.folder-input {
1869  position: relative;
1870}
1871.folder-input > input {
1872  width: 100%;
1873}
1874.folder-menu {
1875  position: absolute;
1876  z-index: 20;
1877  top: calc(100% + 2px);
1878  left: 0;
1879  right: 0;
1880  max-height: 240px;
1881  overflow-y: auto;
1882  padding: 4px;
1883  background: var(--panel);
1884  border: 1px solid var(--line);
1885  box-shadow: var(--shadow);
1886  white-space: normal;
1887}
1888/* in the bar's options, which scroll, they push down what follows rather than scroll within */
1889.extension-options .folder-menu {
1890  position: static;
1891  margin-top: 2px;
1892  box-shadow: none;
1893}
1894.folder-options {
1895  display: flex;
1896  flex-direction: column;
1897}
1898.folder-options > button {
1899  display: flex;
1900  gap: 12px;
1901  align-items: baseline;
1902  border: 0;
1903  background: none;
1904  padding: 4px 8px;
1905  text-align: left;
1906  color: var(--text);
1907}
1908.folder-options > button:hover {
1909  background: var(--raised);
1910}
1911.folder-options > button[aria-selected="true"] {
1912  background: var(--selected);
1913}
1914.folder-options > button[aria-selected="true"]:hover {
1915  background: var(--selected-hover);
1916}
1917.folder-path {
1918  flex: 1;
1919  min-width: 0;
1920  overflow-wrap: anywhere;
1921}
1922.folder-project {
1923  flex: none;
1924  max-width: 45%;
1925  overflow: hidden;
1926  text-overflow: ellipsis;
1927  white-space: nowrap;
1928  color: var(--muted);
1929  font-size: var(--text-small);
1930}
1931.folder-status {
1932  margin: 0;
1933  padding: 4px 8px;
1934  color: var(--muted);
1935  font-size: var(--text-small);
1936  overflow-wrap: anywhere;
1937}
1938.folder-status:empty {
1939  display: none;
1940}
1941
1942/* settings, as sorcery's pages: a heading, a description, rows that carry their top edge */
1943
1944/* the pane scrolls; its content is centred by padding, so the scrollbar stays at the edge */
1945.settings {
1946  overflow-y: auto;
1947  padding: 8px max(24px, calc((100% - var(--column)) / 2 + 24px)) 64px;
1948}
1949.settings h2 {
1950  margin: 24px 0 4px;
1951  font-size: var(--text-title);
1952  font-weight: 650;
1953}
1954.settings .desc {
1955  margin: 0 0 12px;
1956  color: var(--muted);
1957}
1958.settings > fieldset {
1959  border: 0;
1960  padding: 0;
1961  margin: 0;
1962  min-width: 0;
1963}
1964.system-prompt {
1965  display: flex;
1966  flex-direction: column;
1967  gap: 12px;
1968}
1969.system-prompt textarea {
1970  field-sizing: content;
1971  min-height: 2lh;
1972  resize: none;
1973}
1974.system-prompt :is(input, textarea) {
1975  background: transparent;
1976}
1977.settings .filter {
1978  width: 100%;
1979  margin-bottom: 8px;
1980}
1981.settings .desc kbd {
1982  margin: 0 1px;
1983}
1984
1985/* the enabled models, in order: rows with a grip, as chordpad's tracks are dragged by their heads */
1986.enabled-list {
1987  margin: 0 0 16px;
1988  padding: 0;
1989  list-style: none;
1990  border-bottom: 1px solid var(--line);
1991}
1992.enabled-list .model-row {
1993  grid-template-columns: auto auto 240px minmax(0, 1fr) 240px;
1994  cursor: grab;
1995}
1996.enabled-list .model-row:focus-visible {
1997  outline: 1px solid var(--accent);
1998  outline-offset: -1px;
1999}
2000.grip {
2001  align-self: center;
2002  /* a touch on it drags the row, rather than scrolling the page */
2003  touch-action: none;
2004  width: 7px;
2005  height: 12px;
2006  background-image: radial-gradient(circle, var(--muted) 1px, transparent 1.4px);
2007  background-size: 4px 4px;
2008}
2009.model-row:hover .grip {
2010  background-image: radial-gradient(circle, var(--accent) 1px, transparent 1.4px);
2011}
2012.model-row.dragging {
2013  opacity: 0.4;
2014}
2015/* keep the grabbing cursor wherever the drag goes, as chordpad does */
2016body.reordering,
2017body.reordering * {
2018  cursor: grabbing !important;
2019  user-select: none;
2020}
2021/* where the row lands, as chordpad's reorder line */
2022.model-row.drop-before {
2023  box-shadow: inset 0 2px var(--accent);
2024}
2025.model-row.drop-after {
2026  box-shadow: inset 0 -2px var(--accent);
2027}
2028
2029.provider {
2030  margin-top: 8px;
2031}
2032.provider > summary {
2033  padding: 4px 0;
2034  font-weight: 650;
2035}
2036.provider > summary:hover {
2037  color: var(--accent);
2038}
2039.provider .count {
2040  margin-left: 12px;
2041  color: var(--muted);
2042  font-size: var(--text-ui);
2043  font-weight: 400;
2044}
2045
2046/* fixed, not auto: each row is its own grid, so its columns line up only at fixed widths, as sorcery's catalog */
2047.model-row {
2048  display: grid;
2049  grid-template-columns: auto 240px minmax(0, 1fr) 240px;
2050  gap: 12px;
2051  align-items: baseline;
2052  padding: 4px 8px;
2053  border-top: 1px solid var(--line);
2054  cursor: pointer;
2055}
2056.model-row:hover {
2057  background: var(--panel);
2058}
2059.notify-row {
2060  display: flex;
2061  gap: 12px;
2062  align-items: center;
2063  padding: 4px 8px;
2064  border-top: 1px solid var(--line);
2065  cursor: pointer;
2066}
2067.notify-row:hover {
2068  background: var(--panel);
2069}
2070.model-row code {
2071  color: var(--muted);
2072  overflow: hidden;
2073  text-overflow: ellipsis;
2074  white-space: nowrap;
2075}
2076/* small circle separators between segments, as sorcery's */
2077.model-meta {
2078  display: inline-flex;
2079  justify-content: flex-end;
2080  align-items: center;
2081  gap: 8px;
2082  color: var(--muted);
2083  font-size: var(--text-small);
2084  font-variant-numeric: tabular-nums;
2085  white-space: nowrap;
2086}
2087.model-meta > span {
2088  display: inline-flex;
2089  align-items: center;
2090}
2091.model-meta > span + span::before {
2092  content: "";
2093  width: 3px;
2094  height: 3px;
2095  margin-right: 8px;
2096  border: 1.5px solid var(--muted);
2097  border-radius: 50%;
2098  background: var(--muted);
2099}
2100
2101.ok {
2102  color: var(--ok);
2103}
2104
2105/* providers, as the model rows */
2106.provider-list {
2107  margin-bottom: 8px;
2108  border-bottom: 1px solid var(--line);
2109}
2110.provider-row {
2111  display: grid;
2112  grid-template-columns: 240px minmax(0, 1fr) auto auto;
2113  gap: 12px;
2114  align-items: center;
2115  padding: 4px 8px;
2116  border-top: 1px solid var(--line);
2117}
2118.provider-list > .provider-row:first-child {
2119  border-top: 0;
2120}
2121.provider-row code {
2122  color: var(--muted);
2123}
2124.provider-row .actions {
2125  display: flex;
2126  justify-content: flex-end;
2127  gap: 8px;
2128}
2129/* a row's action is a button, so it takes a box rather than sitting as a bare word among the row's labels */
2130.provider-row button {
2131  padding: 2px 8px;
2132  background: var(--raised);
2133  border: 1px solid var(--line);
2134  color: var(--text);
2135  font-size: var(--text-small);
2136}
2137.provider-row button:hover:not(:disabled) {
2138  border-color: var(--line-strong);
2139  color: var(--accent);
2140}
2141.provider-row button.danger:hover:not(:disabled) {
2142  color: var(--error);
2143}
2144.provider-list > .provider {
2145  margin: 4px 0;
2146}
2147
2148/* dialogs, as chordpad's */
2149.dialog {
2150  width: min(560px, 90vw);
2151  padding: 16px;
2152  color: var(--text);
2153  background: var(--panel);
2154  border: 1px solid var(--line);
2155}
2156.dialog::backdrop {
2157  background: var(--scrim);
2158}
2159.dialog h2 {
2160  margin: 0;
2161  font-size: var(--text-title);
2162  font-weight: 650;
2163}
2164.dialog .desc {
2165  margin: 4px 0 12px;
2166  color: var(--muted);
2167}
2168.dialog p {
2169  margin: 8px 0;
2170  overflow-wrap: anywhere;
2171}
2172.dialog .user-code {
2173  padding: 2px 8px;
2174  font-size: var(--text-display);
2175  letter-spacing: 0.1em;
2176  color: var(--accent);
2177}
2178.dialog .question {
2179  display: flex;
2180  flex-direction: column;
2181  gap: 8px;
2182  margin: 12px 0;
2183}
2184.dialog input.secret {
2185  -webkit-text-security: disc;
2186}
2187/* one of several answers, which a box keeps together */
2188.dialog .question .option {
2189  display: flex;
2190  flex-direction: column;
2191  align-items: flex-start;
2192  gap: 2px;
2193  padding: 8px 12px;
2194  background: var(--raised);
2195  border: 1px solid var(--line);
2196  color: var(--text);
2197  text-align: left;
2198}
2199.dialog .question .option:hover {
2200  border-color: var(--line-strong);
2201}
2202.dialog .question .option span {
2203  color: var(--muted);
2204  font-size: var(--text-ui);
2205}
2206.dialog-actions {
2207  display: flex;
2208  justify-content: flex-end;
2209  gap: 8px;
2210  margin-top: 12px;
2211}
2212.dialog .question .primary {
2213  align-self: flex-end;
2214}
2215
2216/* a project: its name, then its workspaces a row each, the marked one where new conversations start;
2217   unclipped, so a folder's completions can hang below it */
2218.project-dialog {
2219  overflow: visible;
2220}
2221.project-controls {
2222  display: flex;
2223  flex-direction: column;
2224  gap: 12px;
2225  min-width: 0;
2226  margin: 12px 0 0;
2227  padding: 0;
2228  border: 0;
2229}
2230.project-details {
2231  display: flex;
2232  flex-direction: column;
2233  gap: 12px;
2234}
2235.project-dialog-header {
2236  display: flex;
2237  justify-content: space-between;
2238  align-items: baseline;
2239}
2240.project-order .link {
2241  width: 32px;
2242  font-size: var(--text-body);
2243}
2244.project-dialog .desc {
2245  margin: 0 0 4px;
2246}
2247.project-roots {
2248  display: flex;
2249  flex-direction: column;
2250  gap: 8px;
2251}
2252.project-root {
2253  display: grid;
2254  grid-template-columns: auto auto minmax(0, 1fr) 24px;
2255  gap: 8px;
2256  align-items: center;
2257}
2258.project-root > .link {
2259  align-self: stretch;
2260  font-size: var(--text-body);
2261}
2262.project-root > .link:disabled {
2263  visibility: hidden;
2264}
2265.project-roots + .link {
2266  align-self: flex-start;
2267  margin-top: 2px;
2268}
2269.project-dialog .error {
2270  margin: 0;
2271}
2272.project-dialog .dialog-actions {
2273  margin-top: 4px;
2274}
2275.project-delete {
2276  margin-right: auto;
2277}
2278
2279/* where a move along the tree went: the notice's column, the tree's row */
2280.continuation {
2281  display: flex;
2282  align-items: baseline;
2283  gap: 8px;
2284  align-self: center;
2285  width: calc(100% - 48px);
2286  max-width: calc(var(--column) - 48px);
2287  margin-bottom: 8px;
2288  padding: 4px 4px 4px 12px;
2289  background: var(--panel);
2290  border-left: 2px solid var(--accent);
2291  font-size: var(--text-ui);
2292}
2293.continuation .point {
2294  display: flex;
2295  align-items: baseline;
2296  gap: 8px;
2297  flex: 1;
2298  min-width: 0;
2299  white-space: nowrap;
2300}
2301.continuation :is(.verb, .label) {
2302  flex: none;
2303  color: var(--muted);
2304}
2305.continuation .text {
2306  min-width: 0;
2307  overflow: hidden;
2308  text-overflow: ellipsis;
2309}
2310.continuation button {
2311  flex: none;
2312  padding: 0 8px;
2313}
2314
2315/* the tree: one line per entry, tree(1)'s rules in the mono face so they meet */
2316.tree-dialog {
2317  width: min(960px, 94vw);
2318}
2319.tree-filters {
2320  display: flex;
2321  gap: 12px;
2322  margin-bottom: 8px;
2323}
2324.tree-filters label {
2325  display: flex;
2326  gap: 4px;
2327  align-items: center;
2328}
2329.tree-rows {
2330  display: flex;
2331  flex-direction: column;
2332  max-height: 65vh;
2333  overflow-y: auto;
2334  margin-bottom: 8px;
2335  border-top: 1px solid var(--line);
2336  border-bottom: 1px solid var(--line);
2337  font-size: var(--text-ui);
2338}
2339.tree-entry {
2340  display: flex;
2341  align-items: baseline;
2342  flex: none;
2343}
2344
2345.tree-regenerate {
2346  flex: none;
2347  margin: 2px 4px;
2348  padding: 0 4px;
2349  font-size: var(--text-small);
2350}
2351
2352.tree-row {
2353  display: flex;
2354  align-items: baseline;
2355  flex: 1;
2356  min-width: 0;
2357  padding: 0 8px;
2358  border: 0;
2359  background: none;
2360  text-align: left;
2361  white-space: nowrap;
2362  padding-block: 2px;
2363  color: var(--text);
2364}
2365.tree-row:hover {
2366  background: var(--raised);
2367}
2368.tree-row:focus {
2369  outline: none;
2370  background: var(--selected);
2371}
2372.tree-row:focus:hover {
2373  background: var(--selected-hover);
2374}
2375.tree-row .lead {
2376  font-family: var(--mono);
2377  white-space: pre;
2378  color: var(--line-strong);
2379}
2380.tree-row .label {
2381  flex: none;
2382  margin-right: 8px;
2383  color: var(--muted);
2384}
2385:is(.tree-row, .continuation)[data-kind="pi.user"] .label {
2386  color: var(--accent);
2387}
2388:is(.tree-row, .continuation)[data-kind="pi.assistant"] .label {
2389  color: var(--ok);
2390}
2391.tree-row[data-error="true"] .text {
2392  color: var(--error);
2393}
2394.tree-row:not([data-kind="pi.user"], [data-kind="pi.assistant"]) .text {
2395  color: var(--muted);
2396}
2397.tree-row .text {
2398  flex: 1;
2399  min-width: 0;
2400  overflow: hidden;
2401  text-overflow: ellipsis;
2402}
2403.tree-row.here .text {
2404  font-weight: 600;
2405}
2406.tree-row .branch {
2407  flex: none;
2408  margin-left: 8px;
2409  padding: 0 4px;
2410  border: 1px solid var(--line);
2411  color: var(--muted);
2412  font-size: var(--text-small);
2413}
2414.tree-entry .time {
2415  flex: none;
2416  margin: 0 8px;
2417  color: var(--muted);
2418  font-size: var(--text-small);
2419  font-variant-numeric: tabular-nums;
2420}
2421.tree-row .branch.current {
2422  border-color: var(--accent);
2423  color: var(--accent);
2424}
2425.tree-rows:has([aria-busy="true"]) {
2426  cursor: progress;
2427}
2428.tree-entry[aria-busy="true"] .tree-row::after {
2429  content: "";
2430  flex: none;
2431  align-self: center;
2432  width: 12px;
2433  height: 12px;
2434  margin-left: 8px;
2435  border: 2px solid var(--line);
2436  border-top-color: var(--running);
2437  border-radius: 50%;
2438  animation: working-spin 0.8s linear infinite;
2439}
2440.dialog .tree-error {
2441  margin: 0 0 8px;
2442  color: var(--error);
2443}
2444
2445/* environments, as the providers, with a form for another */
2446.environments {
2447  display: grid;
2448  grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
2449  column-gap: 8px;
2450}
2451.environment-list,
2452.environment-row,
2453.environment-form {
2454  display: grid;
2455  grid-template-columns: subgrid;
2456  grid-column: 1 / -1;
2457  align-items: center;
2458}
2459.environment-row {
2460  padding: 4px 0;
2461}
2462.environment-row + .environment-row {
2463  border-top: 1px solid var(--line);
2464}
2465.environment-row > :is(span, code),
2466.environment-form input {
2467  min-width: 0;
2468  overflow: hidden;
2469  text-overflow: ellipsis;
2470  white-space: nowrap;
2471}
2472.environment-row code {
2473  color: var(--muted);
2474}
2475.environment-row button {
2476  padding: 2px 0;
2477  font-size: var(--text-small);
2478}
2479.environment-form {
2480  margin: 8px 0;
2481}
2482.environments > :is(.local-environment, .desc, .error) {
2483  grid-column: 1 / -1;
2484}
2485.local-environment {
2486  display: flex;
2487  gap: 4px;
2488  align-items: center;
2489  cursor: pointer;
2490}
2491.environments > .desc {
2492  margin: 2px 0 12px;
2493}
2494
2495/* extensions, as the providers, but one grid so that the names take only the room they need */
2496.extension-list {
2497  display: grid;
2498  grid-template-columns: auto minmax(0, 1fr) auto auto auto;
2499  column-gap: 12px;
2500}
2501.extension,
2502.extension .provider-row {
2503  display: grid;
2504  grid-template-columns: subgrid;
2505  grid-column: 1 / -1;
2506}
2507.extension + .extension {
2508  border-top: 1px solid var(--line);
2509}
2510.extension .provider-row {
2511  grid-template-areas: "name description timing status actions"
2512    "name directory timing status actions";
2513  border-top: 0;
2514  row-gap: 0;
2515}
2516.extension .provider-row > .model-name {
2517  grid-area: name;
2518}
2519.extension .provider-row > .description {
2520  grid-area: description;
2521}
2522.extension .provider-row > :is(.ok, .error) {
2523  grid-area: status;
2524}
2525.extension .provider-row > .actions {
2526  grid-area: actions;
2527}
2528.extension .provider-row > :is(.description, code) {
2529  overflow: hidden;
2530  color: var(--muted);
2531  text-overflow: ellipsis;
2532  white-space: nowrap;
2533}
2534.extension .provider-row > code {
2535  grid-area: directory;
2536  font-size: var(--text-small);
2537  opacity: 0.8;
2538}
2539.extension-startup {
2540  grid-area: timing;
2541  color: var(--muted);
2542  font-size: var(--text-small);
2543}
2544.extension-startup > summary {
2545  cursor: pointer;
2546  white-space: nowrap;
2547}
2548.extension-startup dl {
2549  display: grid;
2550  grid-template-columns: auto auto;
2551  gap: 4px 12px;
2552  margin: 8px 0;
2553}
2554.extension-startup dd {
2555  margin: 0;
2556  text-align: right;
2557  font-variant-numeric: tabular-nums;
2558}
2559.extension pre.error {
2560  grid-column: 1 / -1;
2561  margin: 0 8px 8px;
2562  border-left-color: var(--error);
2563  max-height: 256px;
2564  overflow-y: auto;
2565}
2566/* an extension's editable prose, collapsed so long defaults don't dominate the list */
2567.extension > details {
2568  grid-column: 1 / -1;
2569  margin: 0 8px 8px;
2570}
2571.extension > details > summary {
2572  cursor: pointer;
2573  color: var(--muted);
2574}
2575.extension .system-prompt textarea {
2576  width: 100%;
2577  resize: vertical;
2578}
2579
2580/* touch screens: room for fingers, and no hover to reveal things */
2581
2582@media (pointer: coarse) {
2583  .conversations a {
2584    padding-top: 8px;
2585    padding-bottom: 8px;
2586    user-select: none;
2587  }
2588  .chevron {
2589    width: 36px;
2590  }
2591  .tool-header {
2592    padding-top: 8px;
2593    padding-bottom: 8px;
2594  }
2595  .tool-more {
2596    padding: 8px;
2597  }
2598  .grip {
2599    padding: 0 8px;
2600    background-clip: content-box;
2601  }
2602  .tree-row {
2603    padding-block: 8px;
2604  }
2605  .composer-controls,
2606  .composer .actions {
2607    display: flex;
2608  }
2609  .hints {
2610    display: none;
2611  }
2612}
2613@media (pointer: coarse), (hover: none) {
2614  .conversations .item {
2615    flex-wrap: wrap;
2616    padding-right: var(--target);
2617    touch-action: manipulation;
2618  }
2619  .conversations .archive {
2620    display: none;
2621  }
2622  .project-action {
2623    width: var(--target);
2624  }
2625  .conversations .conversation-actions {
2626    display: block;
2627    flex-basis: 100%;
2628    min-width: 0;
2629  }
2630  .conversations .conversation-actions > summary {
2631    position: absolute;
2632    top: 0;
2633    right: 0;
2634    display: flex;
2635    align-items: center;
2636    justify-content: center;
2637    width: var(--target);
2638    min-height: var(--target);
2639    color: var(--muted);
2640    font-size: var(--text-title);
2641  }
2642  .conversations .conversation-actions > summary::before {
2643    content: none;
2644  }
2645  .conversations .conversation-menu {
2646    display: flex;
2647    gap: 16px;
2648    padding: 0 8px 8px 36px;
2649  }
2650  .conversations .conversation-menu button {
2651    min-height: var(--target);
2652  }
2653  .conversations .conversation-name {
2654    font-size: var(--text-body);
2655    min-height: var(--target);
2656  }
2657}
2658
2659/* narrow screens: the list, or a view, with a way back to the list */
2660
2661@media (max-width: 700px) {
2662  .app {
2663    grid-template:
2664      "back bar" auto
2665      "pane pane" minmax(0, 1fr)
2666      / auto minmax(0, 1fr);
2667  }
2668  .app.listing {
2669    grid-template:
2670      "brand" auto
2671      "side" minmax(0, 1fr)
2672      / minmax(0, 1fr);
2673  }
2674  .app.listing > :is(.view, .back),
2675  .app:not(.listing) > :is(.brand-bar, .sidebar) {
2676    display: none;
2677  }
2678  /* the view alone; its link in the bar goes back to the conversation */
2679  .app.viewing {
2680    grid-template-columns: auto minmax(0, 1fr);
2681  }
2682  .app.viewing .pane.conversation {
2683    display: none;
2684  }
2685  .back {
2686    display: flex;
2687  }
2688  .brand-bar,
2689  .sidebar {
2690    border-right: 0;
2691  }
2692
2693  /* the extensions' options drop below the whole bar */
2694  .bar {
2695    position: relative;
2696  }
2697  .conversation-header > label {
2698    display: none;
2699  }
2700  .conversation-header > label + :is(input, select) {
2701    margin-right: 0;
2702  }
2703  .conversation-header .model {
2704    flex: 1 1 112px;
2705    min-width: 0;
2706  }
2707  .conversation-header .extensions {
2708    position: static;
2709  }
2710  .conversation-header .extensions .extension-options {
2711    left: 8px;
2712    right: 8px;
2713    min-width: 0;
2714    white-space: normal;
2715  }
2716
2717  .transcript {
2718    padding: 8px 12px 24px;
2719  }
2720  .start {
2721    padding: 24px 12px;
2722  }
2723  .message.user {
2724    padding: 8px 12px;
2725  }
2726  pre {
2727    padding: 8px 12px;
2728  }
2729  pre.code .ln {
2730    padding: 0 8px 0 8px;
2731  }
2732  .code-text {
2733    padding: 0 8px;
2734  }
2735  .tool-header {
2736    padding-left: 8px;
2737    padding-right: 8px;
2738  }
2739  .tool-body {
2740    padding: 4px 8px 8px;
2741  }
2742  .inbox .queued {
2743    padding: 4px 12px;
2744  }
2745  .working {
2746    padding: 4px 12px;
2747  }
2748  .notice,
2749  .continuation {
2750    width: calc(100% - 24px);
2751  }
2752  .composer {
2753    padding: 0 12px 8px;
2754  }
2755  .suggestions {
2756    left: 12px;
2757    right: 12px;
2758  }
2759
2760  /* settings' rows put their ids on a line of their own */
2761  .settings {
2762    padding: 8px 12px 48px;
2763  }
2764  .model-row {
2765    grid-template-columns: auto minmax(0, 1fr) auto;
2766    row-gap: 0;
2767  }
2768  .enabled-list .model-row {
2769    grid-template-columns: auto auto minmax(0, 1fr) auto;
2770  }
2771  .model-row code {
2772    grid-row: 2;
2773    grid-column: -3 / -1;
2774  }
2775  .provider-row {
2776    grid-template-columns: minmax(0, 1fr) auto auto;
2777    row-gap: 0;
2778  }
2779  .provider-row > :is(code, .description) {
2780    grid-row: 2;
2781    grid-column: 1 / -1;
2782  }
2783  .extension-list {
2784    grid-template-columns: minmax(0, 1fr) auto auto;
2785  }
2786  .extension .provider-row {
2787    grid-template-areas: "name status actions" "description description description"
2788      "directory directory directory" "timing timing timing";
2789  }
2790}