quickstyle.go

  1package styles
  2
  3import (
  4	"image/color"
  5
  6	"charm.land/bubbles/v2/filepicker"
  7	"charm.land/bubbles/v2/help"
  8	"charm.land/bubbles/v2/textarea"
  9	"charm.land/bubbles/v2/textinput"
 10	tea "charm.land/bubbletea/v2"
 11	"charm.land/glamour/v2/ansi"
 12	"charm.land/lipgloss/v2"
 13	"github.com/charmbracelet/crush/internal/ui/diffview"
 14	"github.com/charmbracelet/x/exp/charmtone"
 15)
 16
 17// quickStyleOpts is the palette of colors used by quickStyle to simplify the
 18// process of building a theme.
 19type quickStyleOpts struct {
 20	// Brand.
 21	primary   color.Color
 22	secondary color.Color
 23	accent    color.Color
 24	keyword   color.Color
 25
 26	// Default foreground and background colors.
 27	fgBase color.Color
 28	bgBase color.Color
 29
 30	// Low-contrast dividers, separators, and rule lines.
 31	separator color.Color
 32
 33	fgSubtle     color.Color
 34	fgMoreSubtle color.Color
 35	fgMostSubtle color.Color
 36
 37	// Contrast pairings: foregrounds designed to sit on top of a
 38	// matching background role.
 39	onPrimary color.Color // foreground on primary backgrounds.
 40
 41	bgMostVisible  color.Color
 42	bgLessVisible  color.Color
 43	bgLeastVisible color.Color
 44
 45	// Statuses.
 46	destructive       color.Color
 47	error             color.Color
 48	warning           color.Color
 49	warningSubtle     color.Color
 50	busy              color.Color
 51	info              color.Color
 52	infoMoreSubtle    color.Color
 53	infoMostSubtle    color.Color
 54	success           color.Color
 55	successMoreSubtle color.Color
 56	successMostSubtle color.Color
 57}
 58
 59// quickStyle builds the default Styles (that is, the default theme, Charmtone
 60// Pantera) from a palette of semi-semanticly-named colors.
 61//
 62// The idea here is that you can do most of the work on a theme with quickStyle,
 63// then add overrides as needed.
 64func quickStyle(o quickStyleOpts) Styles {
 65	var (
 66		base   = lipgloss.NewStyle().Foreground(o.fgBase)
 67		muted  = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
 68		subtle = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
 69		s      Styles
 70	)
 71
 72	s.Background = o.bgBase
 73
 74	// Populate color fields
 75	s.WorkingGradFromColor = o.primary
 76	s.WorkingGradToColor = o.secondary
 77	s.WorkingLabelColor = o.fgBase
 78
 79	s.TextInput = textinput.Styles{
 80		Focused: textinput.StyleState{
 81			Text:        base,
 82			Placeholder: base.Foreground(o.fgMostSubtle),
 83			Prompt:      base.Foreground(o.accent),
 84			Suggestion:  base.Foreground(o.fgMostSubtle),
 85		},
 86		Blurred: textinput.StyleState{
 87			Text:        base.Foreground(o.fgMoreSubtle),
 88			Placeholder: base.Foreground(o.fgMostSubtle),
 89			Prompt:      base.Foreground(o.fgMoreSubtle),
 90			Suggestion:  base.Foreground(o.fgMostSubtle),
 91		},
 92		Cursor: textinput.CursorStyle{
 93			Color: o.secondary,
 94			Shape: tea.CursorBlock,
 95			Blink: true,
 96		},
 97	}
 98
 99	s.Editor.Textarea = textarea.Styles{
100		Focused: textarea.StyleState{
101			Base:             base,
102			Text:             base,
103			LineNumber:       base.Foreground(o.fgMostSubtle),
104			CursorLine:       base,
105			CursorLineNumber: base.Foreground(o.fgMostSubtle),
106			Placeholder:      base.Foreground(o.fgMostSubtle),
107			Prompt:           base.Foreground(o.accent),
108		},
109		Blurred: textarea.StyleState{
110			Base:             base,
111			Text:             base.Foreground(o.fgMoreSubtle),
112			LineNumber:       base.Foreground(o.fgMoreSubtle),
113			CursorLine:       base,
114			CursorLineNumber: base.Foreground(o.fgMoreSubtle),
115			Placeholder:      base.Foreground(o.fgMostSubtle),
116			Prompt:           base.Foreground(o.fgMoreSubtle),
117		},
118		Cursor: textarea.CursorStyle{
119			Color: o.secondary,
120			Shape: tea.CursorBlock,
121			Blink: true,
122		},
123	}
124
125	s.Markdown = ansi.StyleConfig{
126		Document: ansi.StyleBlock{
127			StylePrimitive: ansi.StylePrimitive{
128				// BlockPrefix: "\n",
129				// BlockSuffix: "\n",
130				Color: hex(o.fgSubtle),
131			},
132			// Margin: new(uint(defaultMargin)),
133		},
134		BlockQuote: ansi.StyleBlock{
135			StylePrimitive: ansi.StylePrimitive{},
136			Indent:         new(uint(1)),
137			IndentToken:    new("│ "),
138		},
139		List: ansi.StyleList{
140			LevelIndent: defaultListIndent,
141		},
142		Heading: ansi.StyleBlock{
143			StylePrimitive: ansi.StylePrimitive{
144				BlockSuffix: "\n",
145				Color:       hex(o.info),
146				Bold:        new(true),
147			},
148		},
149		H1: ansi.StyleBlock{
150			StylePrimitive: ansi.StylePrimitive{
151				Prefix:          " ",
152				Suffix:          " ",
153				Color:           hex(o.warningSubtle),
154				BackgroundColor: hex(o.primary),
155				Bold:            new(true),
156			},
157		},
158		H2: ansi.StyleBlock{
159			StylePrimitive: ansi.StylePrimitive{
160				Prefix: "## ",
161			},
162		},
163		H3: ansi.StyleBlock{
164			StylePrimitive: ansi.StylePrimitive{
165				Prefix: "### ",
166			},
167		},
168		H4: ansi.StyleBlock{
169			StylePrimitive: ansi.StylePrimitive{
170				Prefix: "#### ",
171			},
172		},
173		H5: ansi.StyleBlock{
174			StylePrimitive: ansi.StylePrimitive{
175				Prefix: "##### ",
176			},
177		},
178		H6: ansi.StyleBlock{
179			StylePrimitive: ansi.StylePrimitive{
180				Prefix: "###### ",
181				Color:  hex(o.successMostSubtle),
182				Bold:   new(false),
183			},
184		},
185		Strikethrough: ansi.StylePrimitive{
186			CrossedOut: new(true),
187		},
188		Emph: ansi.StylePrimitive{
189			Italic: new(true),
190		},
191		Strong: ansi.StylePrimitive{
192			Bold: new(true),
193		},
194		HorizontalRule: ansi.StylePrimitive{
195			Color:  hex(o.separator),
196			Format: "\n--------\n",
197		},
198		Item: ansi.StylePrimitive{
199			BlockPrefix: "• ",
200		},
201		Enumeration: ansi.StylePrimitive{
202			BlockPrefix: ". ",
203		},
204		Task: ansi.StyleTask{
205			StylePrimitive: ansi.StylePrimitive{},
206			Ticked:         "[✓] ",
207			Unticked:       "[ ] ",
208		},
209		Link: ansi.StylePrimitive{
210			Color:     hex(charmtone.Zinc),
211			Underline: new(true),
212		},
213		LinkText: ansi.StylePrimitive{
214			Color: hex(o.successMostSubtle),
215			Bold:  new(true),
216		},
217		Image: ansi.StylePrimitive{
218			Color:     hex(charmtone.Cheeky),
219			Underline: new(true),
220		},
221		ImageText: ansi.StylePrimitive{
222			Color:  hex(o.fgMoreSubtle),
223			Format: "Image: {{.text}} →",
224		},
225		Code: ansi.StyleBlock{
226			StylePrimitive: ansi.StylePrimitive{
227				Prefix:          " ",
228				Suffix:          " ",
229				Color:           hex(o.destructive),
230				BackgroundColor: hex(o.bgLessVisible),
231			},
232		},
233		CodeBlock: ansi.StyleCodeBlock{
234			StyleBlock: ansi.StyleBlock{
235				StylePrimitive: ansi.StylePrimitive{
236					Color: hex(o.bgLessVisible),
237				},
238				Margin: new(uint(defaultMargin)),
239			},
240			Chroma: &ansi.Chroma{
241				Text: ansi.StylePrimitive{
242					Color: hex(o.fgSubtle),
243				},
244				Error: ansi.StylePrimitive{
245					Color:           hex(o.onPrimary),
246					BackgroundColor: hex(o.error),
247				},
248				Comment: ansi.StylePrimitive{
249					Color: hex(o.fgMostSubtle),
250				},
251				CommentPreproc: ansi.StylePrimitive{
252					Color: hex(charmtone.Bengal),
253				},
254				Keyword: ansi.StylePrimitive{
255					Color: hex(o.info),
256				},
257				KeywordReserved: ansi.StylePrimitive{
258					Color: hex(charmtone.Pony),
259				},
260				KeywordNamespace: ansi.StylePrimitive{
261					Color: hex(charmtone.Pony),
262				},
263				KeywordType: ansi.StylePrimitive{
264					Color: hex(charmtone.Guppy),
265				},
266				Operator: ansi.StylePrimitive{
267					Color: hex(charmtone.Salmon),
268				},
269				Punctuation: ansi.StylePrimitive{
270					Color: hex(o.warningSubtle),
271				},
272				Name: ansi.StylePrimitive{
273					Color: hex(o.fgSubtle),
274				},
275				NameBuiltin: ansi.StylePrimitive{
276					Color: hex(charmtone.Cheeky),
277				},
278				NameTag: ansi.StylePrimitive{
279					Color: hex(charmtone.Mauve),
280				},
281				NameAttribute: ansi.StylePrimitive{
282					Color: hex(charmtone.Hazy),
283				},
284				NameClass: ansi.StylePrimitive{
285					Color:     hex(charmtone.Salt),
286					Underline: new(true),
287					Bold:      new(true),
288				},
289				NameDecorator: ansi.StylePrimitive{
290					Color: hex(charmtone.Citron),
291				},
292				NameFunction: ansi.StylePrimitive{
293					Color: hex(o.successMostSubtle),
294				},
295				LiteralNumber: ansi.StylePrimitive{
296					Color: hex(o.success),
297				},
298				LiteralString: ansi.StylePrimitive{
299					Color: hex(charmtone.Cumin),
300				},
301				LiteralStringEscape: ansi.StylePrimitive{
302					Color: hex(o.successMoreSubtle),
303				},
304				GenericDeleted: ansi.StylePrimitive{
305					Color: hex(o.destructive),
306				},
307				GenericEmph: ansi.StylePrimitive{
308					Italic: new(true),
309				},
310				GenericInserted: ansi.StylePrimitive{
311					Color: hex(o.successMostSubtle),
312				},
313				GenericStrong: ansi.StylePrimitive{
314					Bold: new(true),
315				},
316				GenericSubheading: ansi.StylePrimitive{
317					Color: hex(o.fgMoreSubtle),
318				},
319				Background: ansi.StylePrimitive{
320					BackgroundColor: hex(o.bgLessVisible),
321				},
322			},
323		},
324		Table: ansi.StyleTable{
325			StyleBlock: ansi.StyleBlock{
326				StylePrimitive: ansi.StylePrimitive{},
327			},
328		},
329		DefinitionDescription: ansi.StylePrimitive{
330			BlockPrefix: "\n ",
331		},
332	}
333
334	// QuietMarkdown style - muted colors on subtle background for thinking content.
335	plainBg := hex(o.bgLeastVisible)
336	plainFg := hex(o.fgMoreSubtle)
337	s.QuietMarkdown = ansi.StyleConfig{
338		Document: ansi.StyleBlock{
339			StylePrimitive: ansi.StylePrimitive{
340				Color:           plainFg,
341				BackgroundColor: plainBg,
342			},
343		},
344		BlockQuote: ansi.StyleBlock{
345			StylePrimitive: ansi.StylePrimitive{
346				Color:           plainFg,
347				BackgroundColor: plainBg,
348			},
349			Indent:      new(uint(1)),
350			IndentToken: new("│ "),
351		},
352		List: ansi.StyleList{
353			LevelIndent: defaultListIndent,
354		},
355		Heading: ansi.StyleBlock{
356			StylePrimitive: ansi.StylePrimitive{
357				BlockSuffix:     "\n",
358				Bold:            new(true),
359				Color:           plainFg,
360				BackgroundColor: plainBg,
361			},
362		},
363		H1: ansi.StyleBlock{
364			StylePrimitive: ansi.StylePrimitive{
365				Prefix:          " ",
366				Suffix:          " ",
367				Bold:            new(true),
368				Color:           plainFg,
369				BackgroundColor: plainBg,
370			},
371		},
372		H2: ansi.StyleBlock{
373			StylePrimitive: ansi.StylePrimitive{
374				Prefix:          "## ",
375				Color:           plainFg,
376				BackgroundColor: plainBg,
377			},
378		},
379		H3: ansi.StyleBlock{
380			StylePrimitive: ansi.StylePrimitive{
381				Prefix:          "### ",
382				Color:           plainFg,
383				BackgroundColor: plainBg,
384			},
385		},
386		H4: ansi.StyleBlock{
387			StylePrimitive: ansi.StylePrimitive{
388				Prefix:          "#### ",
389				Color:           plainFg,
390				BackgroundColor: plainBg,
391			},
392		},
393		H5: ansi.StyleBlock{
394			StylePrimitive: ansi.StylePrimitive{
395				Prefix:          "##### ",
396				Color:           plainFg,
397				BackgroundColor: plainBg,
398			},
399		},
400		H6: ansi.StyleBlock{
401			StylePrimitive: ansi.StylePrimitive{
402				Prefix:          "###### ",
403				Color:           plainFg,
404				BackgroundColor: plainBg,
405			},
406		},
407		Strikethrough: ansi.StylePrimitive{
408			CrossedOut:      new(true),
409			Color:           plainFg,
410			BackgroundColor: plainBg,
411		},
412		Emph: ansi.StylePrimitive{
413			Italic:          new(true),
414			Color:           plainFg,
415			BackgroundColor: plainBg,
416		},
417		Strong: ansi.StylePrimitive{
418			Bold:            new(true),
419			Color:           plainFg,
420			BackgroundColor: plainBg,
421		},
422		HorizontalRule: ansi.StylePrimitive{
423			Format:          "\n--------\n",
424			Color:           plainFg,
425			BackgroundColor: plainBg,
426		},
427		Item: ansi.StylePrimitive{
428			BlockPrefix:     "• ",
429			Color:           plainFg,
430			BackgroundColor: plainBg,
431		},
432		Enumeration: ansi.StylePrimitive{
433			BlockPrefix:     ". ",
434			Color:           plainFg,
435			BackgroundColor: plainBg,
436		},
437		Task: ansi.StyleTask{
438			StylePrimitive: ansi.StylePrimitive{
439				Color:           plainFg,
440				BackgroundColor: plainBg,
441			},
442			Ticked:   "[✓] ",
443			Unticked: "[ ] ",
444		},
445		Link: ansi.StylePrimitive{
446			Underline:       new(true),
447			Color:           plainFg,
448			BackgroundColor: plainBg,
449		},
450		LinkText: ansi.StylePrimitive{
451			Bold:            new(true),
452			Color:           plainFg,
453			BackgroundColor: plainBg,
454		},
455		Image: ansi.StylePrimitive{
456			Underline:       new(true),
457			Color:           plainFg,
458			BackgroundColor: plainBg,
459		},
460		ImageText: ansi.StylePrimitive{
461			Format:          "Image: {{.text}} →",
462			Color:           plainFg,
463			BackgroundColor: plainBg,
464		},
465		Code: ansi.StyleBlock{
466			StylePrimitive: ansi.StylePrimitive{
467				Prefix:          " ",
468				Suffix:          " ",
469				Color:           plainFg,
470				BackgroundColor: plainBg,
471			},
472		},
473		CodeBlock: ansi.StyleCodeBlock{
474			StyleBlock: ansi.StyleBlock{
475				StylePrimitive: ansi.StylePrimitive{
476					Color:           plainFg,
477					BackgroundColor: plainBg,
478				},
479				Margin: new(uint(defaultMargin)),
480			},
481		},
482		Table: ansi.StyleTable{
483			StyleBlock: ansi.StyleBlock{
484				StylePrimitive: ansi.StylePrimitive{
485					Color:           plainFg,
486					BackgroundColor: plainBg,
487				},
488			},
489		},
490		DefinitionDescription: ansi.StylePrimitive{
491			BlockPrefix:     "\n ",
492			Color:           plainFg,
493			BackgroundColor: plainBg,
494		},
495	}
496
497	s.Help = help.Styles{
498		ShortKey:       base.Foreground(o.fgMoreSubtle),
499		ShortDesc:      base.Foreground(o.fgMostSubtle),
500		ShortSeparator: base.Foreground(o.separator),
501		Ellipsis:       base.Foreground(o.separator),
502		FullKey:        base.Foreground(o.fgMoreSubtle),
503		FullDesc:       base.Foreground(o.fgMostSubtle),
504		FullSeparator:  base.Foreground(o.separator),
505	}
506
507	s.Diff = diffview.Style{
508		DividerLine: diffview.LineStyle{
509			LineNumber: lipgloss.NewStyle().
510				Foreground(o.fgSubtle).
511				Background(o.bgLeastVisible),
512			Code: lipgloss.NewStyle().
513				Foreground(o.fgSubtle).
514				Background(o.bgLeastVisible),
515		},
516		MissingLine: diffview.LineStyle{
517			LineNumber: lipgloss.NewStyle().
518				Background(o.bgLeastVisible),
519			Code: lipgloss.NewStyle().
520				Background(o.bgLeastVisible),
521		},
522		EqualLine: diffview.LineStyle{
523			LineNumber: lipgloss.NewStyle().
524				Foreground(o.fgMoreSubtle).
525				Background(o.bgBase),
526			Code: lipgloss.NewStyle().
527				Foreground(o.fgMoreSubtle).
528				Background(o.bgBase),
529		},
530		InsertLine: diffview.LineStyle{
531			LineNumber: lipgloss.NewStyle().
532				Foreground(lipgloss.Color("#629657")).
533				Background(lipgloss.Color("#2b322a")),
534			Symbol: lipgloss.NewStyle().
535				Foreground(lipgloss.Color("#629657")).
536				Background(lipgloss.Color("#323931")),
537			Code: lipgloss.NewStyle().
538				Background(lipgloss.Color("#323931")),
539		},
540		DeleteLine: diffview.LineStyle{
541			LineNumber: lipgloss.NewStyle().
542				Foreground(lipgloss.Color("#a45c59")).
543				Background(lipgloss.Color("#312929")),
544			Symbol: lipgloss.NewStyle().
545				Foreground(lipgloss.Color("#a45c59")).
546				Background(lipgloss.Color("#383030")),
547			Code: lipgloss.NewStyle().
548				Background(lipgloss.Color("#383030")),
549		},
550		Filename: diffview.LineStyle{
551			LineNumber: lipgloss.NewStyle().
552				Foreground(o.fgSubtle).
553				Background(o.bgLeastVisible),
554			Code: lipgloss.NewStyle().
555				Foreground(o.fgSubtle).
556				Background(o.bgLeastVisible),
557		},
558	}
559
560	s.FilePicker = filepicker.Styles{
561		DisabledCursor:   base.Foreground(o.fgMoreSubtle),
562		Cursor:           base.Foreground(o.fgBase),
563		Symlink:          base.Foreground(o.fgMostSubtle),
564		Directory:        base.Foreground(o.primary),
565		File:             base.Foreground(o.fgBase),
566		DisabledFile:     base.Foreground(o.fgMoreSubtle),
567		DisabledSelected: base.Background(o.bgMostVisible).Foreground(o.fgMoreSubtle),
568		Permission:       base.Foreground(o.fgMoreSubtle),
569		Selected:         base.Background(o.primary).Foreground(o.fgBase),
570		FileSize:         base.Foreground(o.fgMoreSubtle),
571		EmptyDirectory:   base.Foreground(o.fgMoreSubtle).PaddingLeft(2).SetString("Empty directory"),
572	}
573
574	// borders
575	s.ToolCallSuccess = lipgloss.NewStyle().Foreground(o.success).SetString(ToolSuccess)
576
577	s.Header.Charm = base.Foreground(o.secondary)
578	s.Header.Diagonals = base.Foreground(o.primary)
579	s.Header.Percentage = muted
580	s.Header.Keystroke = muted
581	s.Header.KeystrokeTip = subtle
582	s.Header.WorkingDir = muted
583	s.Header.Separator = subtle
584	s.Header.Wrapper = lipgloss.NewStyle().Foreground(o.fgBase)
585	s.Header.LogoGradCanvas = lipgloss.NewStyle()
586	s.Header.LogoGradFromColor = o.secondary
587	s.Header.LogoGradToColor = o.primary
588
589	s.CompactDetails.Title = base
590	s.CompactDetails.View = base.Padding(0, 1, 1, 1).Border(lipgloss.RoundedBorder()).BorderForeground(o.primary)
591	s.CompactDetails.Version = lipgloss.NewStyle().Foreground(o.separator)
592
593	// Tool rendering styles
594	s.Tool.IconPending = base.Foreground(o.successMostSubtle).SetString(ToolPending)
595	s.Tool.IconSuccess = base.Foreground(o.success).SetString(ToolSuccess)
596	s.Tool.IconError = base.Foreground(o.error).SetString(ToolError)
597	s.Tool.IconCancelled = muted.SetString(ToolPending)
598
599	s.Tool.NameNormal = base.Foreground(o.info)
600	s.Tool.NameNested = base.Foreground(o.info)
601
602	s.Tool.ParamMain = subtle
603	s.Tool.ParamKey = subtle
604
605	// Content rendering - prepared styles that accept width parameter
606	s.Tool.ContentLine = muted.Background(o.bgLeastVisible)
607	s.Tool.ContentTruncation = muted.Background(o.bgLeastVisible)
608	s.Tool.ContentCodeLine = base.Background(o.bgBase).PaddingLeft(2)
609	s.Tool.ContentCodeTruncation = muted.Background(o.bgBase).PaddingLeft(2)
610	s.Tool.ContentCodeBg = o.bgBase
611	s.Tool.Body = base.PaddingLeft(2)
612
613	// Deprecated - kept for backward compatibility
614	s.Tool.ContentBg = muted.Background(o.bgLeastVisible)
615	s.Tool.ContentText = muted
616	s.Tool.ContentLineNumber = base.Foreground(o.fgMoreSubtle).Background(o.bgBase).PaddingRight(1).PaddingLeft(1)
617
618	s.Tool.StateWaiting = base.Foreground(o.fgMostSubtle)
619	s.Tool.StateCancelled = base.Foreground(o.fgMostSubtle)
620
621	s.Tool.ErrorTag = base.Padding(0, 1).Background(o.destructive).Foreground(o.onPrimary)
622	s.Tool.ErrorMessage = base.Foreground(o.fgSubtle)
623
624	// Diff and multi-edit styles
625	s.Tool.DiffTruncation = muted.Background(o.bgLeastVisible).PaddingLeft(2)
626	s.Tool.NoteTag = base.Padding(0, 1).Background(o.info).Foreground(o.onPrimary)
627	s.Tool.NoteMessage = base.Foreground(o.fgSubtle)
628
629	// Job header styles
630	s.Tool.JobIconPending = base.Foreground(o.successMostSubtle)
631	s.Tool.JobIconError = base.Foreground(o.error)
632	s.Tool.JobIconSuccess = base.Foreground(o.success)
633	s.Tool.JobToolName = base.Foreground(o.info)
634	s.Tool.JobAction = base.Foreground(o.infoMostSubtle)
635	s.Tool.JobPID = muted
636	s.Tool.JobDescription = subtle
637
638	// Agent task styles
639	s.Tool.AgentTaskTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(o.infoMoreSubtle).Foreground(o.onPrimary)
640	s.Tool.AgentPrompt = muted
641
642	// Agentic fetch styles
643	s.Tool.AgenticFetchPromptTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(o.success).Foreground(o.separator)
644
645	// Todo styles
646	s.Tool.TodoRatio = base.Foreground(o.infoMostSubtle)
647	s.Tool.TodoCompletedIcon = base.Foreground(o.success)
648	s.Tool.TodoInProgressIcon = base.Foreground(o.successMostSubtle)
649	s.Tool.TodoPendingIcon = base.Foreground(o.fgMoreSubtle)
650	s.Tool.TodoStatusNote = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
651	s.Tool.TodoItem = lipgloss.NewStyle().Foreground(o.fgBase)
652	s.Tool.TodoJustStarted = lipgloss.NewStyle().Foreground(o.fgBase)
653
654	// MCP styles
655	s.Tool.MCPName = base.Foreground(o.info)
656	s.Tool.MCPToolName = base.Foreground(o.infoMostSubtle)
657	s.Tool.MCPArrow = base.Foreground(o.info).SetString(ArrowRightIcon)
658
659	// Loading indicators for images, skills
660	s.Tool.ResourceLoadedText = base.Foreground(o.success)
661	s.Tool.ResourceLoadedIndicator = base.Foreground(o.successMostSubtle)
662	s.Tool.ResourceName = base
663	s.Tool.MediaType = base
664	s.Tool.ResourceSize = base.Foreground(o.fgMoreSubtle)
665
666	// Hook styles
667	s.Tool.HookLabel = base.Foreground(o.successMoreSubtle)
668	s.Tool.HookName = base
669	s.Tool.HookMatcher = base.Foreground(o.fgMoreSubtle)
670	s.Tool.HookArrow = base.Foreground(o.successMoreSubtle)
671	s.Tool.HookDetail = base.Foreground(o.fgMoreSubtle)
672	s.Tool.HookOK = base.Foreground(o.successMostSubtle)
673	s.Tool.HookDenied = base.Foreground(o.error)
674	s.Tool.HookDeniedLabel = base.Foreground(o.destructive)
675	s.Tool.HookDeniedReason = base.Foreground(o.bgMostVisible)
676	s.Tool.HookRewrote = base.Foreground(o.bgMostVisible)
677
678	// Tool-call action verbs and result-list styling.
679	s.Tool.ActionCreate = lipgloss.NewStyle().Foreground(o.successMoreSubtle)
680	s.Tool.ActionDestroy = lipgloss.NewStyle().Foreground(o.destructive)
681	s.Tool.ResultEmpty = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
682	s.Tool.ResultTruncation = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
683	s.Tool.ResultItemName = lipgloss.NewStyle().Foreground(o.fgBase)
684	s.Tool.ResultItemDesc = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
685
686	// Buttons
687	s.Button.Focused = lipgloss.NewStyle().Foreground(o.onPrimary).Background(o.secondary)
688	s.Button.Blurred = lipgloss.NewStyle().Foreground(o.fgBase).Background(o.bgLessVisible)
689
690	// Editor
691	s.Editor.PromptNormalFocused = lipgloss.NewStyle().Foreground(o.successMostSubtle).SetString("::: ")
692	s.Editor.PromptNormalBlurred = s.Editor.PromptNormalFocused.Foreground(o.fgMoreSubtle)
693	s.Editor.PromptYoloIconFocused = lipgloss.NewStyle().MarginRight(1).Foreground(o.fgMostSubtle).Background(o.busy).Bold(true).SetString(" ! ")
694	s.Editor.PromptYoloIconBlurred = s.Editor.PromptYoloIconFocused.Foreground(o.bgBase).Background(o.fgMoreSubtle)
695	s.Editor.PromptYoloDotsFocused = lipgloss.NewStyle().MarginRight(1).Foreground(o.warningSubtle).SetString(":::")
696	s.Editor.PromptYoloDotsBlurred = s.Editor.PromptYoloDotsFocused.Foreground(o.fgMoreSubtle)
697
698	s.Radio.On = lipgloss.NewStyle().Foreground(o.fgSubtle).SetString(RadioOn)
699	s.Radio.Off = lipgloss.NewStyle().Foreground(o.fgSubtle).SetString(RadioOff)
700	s.Radio.Label = lipgloss.NewStyle().Foreground(o.fgSubtle)
701
702	// Logo
703	s.Logo.FieldColor = o.primary
704	s.Logo.TitleColorA = o.secondary
705	s.Logo.TitleColorB = o.primary
706	s.Logo.CharmColor = o.secondary
707	s.Logo.VersionColor = o.primary
708	s.Logo.SmallCharm = lipgloss.NewStyle().Foreground(o.secondary)
709	s.Logo.SmallDiagonals = lipgloss.NewStyle().Foreground(o.primary)
710	s.Logo.GradCanvas = lipgloss.NewStyle()
711	s.Logo.SmallGradFromColor = o.secondary
712	s.Logo.SmallGradToColor = o.primary
713
714	// Section
715	s.Section.Title = subtle
716	s.Section.Line = base.Foreground(o.separator)
717
718	// Initialize
719	s.Initialize.Header = base
720	s.Initialize.Content = muted
721	s.Initialize.Accent = base.Foreground(o.successMostSubtle)
722
723	// ResourceGroup (LSP/MCP/skills sidebar lists).
724	s.Resource.Heading = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
725	s.Resource.Name = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
726	s.Resource.StatusText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
727	s.Resource.OfflineIcon = lipgloss.NewStyle().Foreground(o.bgMostVisible).SetString("●")
728	s.Resource.BusyIcon = s.Resource.OfflineIcon.Foreground(o.busy)
729	s.Resource.ErrorIcon = s.Resource.OfflineIcon.Foreground(o.destructive)
730	s.Resource.OnlineIcon = s.Resource.OfflineIcon.Foreground(o.successMostSubtle)
731	s.Resource.DisabledIcon = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).SetString("●")
732	s.Resource.AdditionalText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
733	s.Resource.CapabilityCount = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
734	s.Resource.RowTitleBase = lipgloss.NewStyle().Foreground(o.fgBase)
735	s.Resource.RowDescBase = lipgloss.NewStyle().Foreground(o.fgBase)
736	s.Resource.DefaultTitleFg = o.fgMoreSubtle
737	s.Resource.DefaultDescFg = o.fgMostSubtle
738
739	// LSP
740	s.LSP.ErrorDiagnostic = base.Foreground(o.error)
741	s.LSP.WarningDiagnostic = base.Foreground(o.warningSubtle)
742	s.LSP.HintDiagnostic = base.Foreground(o.fgSubtle)
743	s.LSP.InfoDiagnostic = base.Foreground(o.info)
744
745	// Files
746	s.Files.Path = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
747	s.Files.Additions = lipgloss.NewStyle().Foreground(o.successMostSubtle)
748	s.Files.Deletions = lipgloss.NewStyle().Foreground(o.error)
749	s.Files.SectionTitle = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
750	s.Files.EmptyMessage = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
751	s.Files.TruncationHint = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
752
753	// Sidebar
754	s.Sidebar.SessionTitle = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
755	s.Sidebar.WorkingDir = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
756
757	// ModelInfo
758	s.ModelInfo.Icon = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
759	s.ModelInfo.Name = lipgloss.NewStyle().Foreground(o.fgBase)
760	s.ModelInfo.Provider = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
761	s.ModelInfo.ProviderFallback = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).PaddingLeft(2)
762	s.ModelInfo.Reasoning = lipgloss.NewStyle().Foreground(o.fgMostSubtle).PaddingLeft(2)
763	s.ModelInfo.TokenCount = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
764	s.ModelInfo.TokenPercentage = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
765	s.ModelInfo.Cost = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
766
767	// ResourceGroup
768	s.Resource.DefaultTitleFg = o.fgMoreSubtle
769	s.Resource.DefaultDescFg = o.fgMostSubtle
770
771	// Chat
772	messageFocussedBorder := lipgloss.Border{
773		Left: "▌",
774	}
775
776	s.Messages.NoContent = lipgloss.NewStyle().Foreground(o.fgBase)
777	s.Messages.UserBlurred = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
778		BorderForeground(o.primary).BorderStyle(lipgloss.NormalBorder())
779	s.Messages.UserFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
780		BorderForeground(o.primary).BorderStyle(messageFocussedBorder)
781	s.Messages.AssistantBlurred = s.Messages.NoContent.PaddingLeft(2)
782	s.Messages.AssistantFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
783		BorderForeground(o.successMostSubtle).BorderStyle(messageFocussedBorder)
784	s.Messages.Thinking = lipgloss.NewStyle().MaxHeight(10)
785	s.Messages.ErrorTag = lipgloss.NewStyle().Padding(0, 1).
786		Background(o.destructive).Foreground(o.onPrimary)
787	s.Messages.ErrorTitle = lipgloss.NewStyle().Foreground(o.fgSubtle)
788	s.Messages.ErrorDetails = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
789
790	// Message item styles
791	s.Messages.ToolCallFocused = muted.PaddingLeft(1).
792		BorderStyle(messageFocussedBorder).
793		BorderLeft(true).
794		BorderForeground(o.successMostSubtle)
795	s.Messages.ToolCallBlurred = muted.PaddingLeft(2)
796	// No padding or border for compact tool calls within messages
797	s.Messages.ToolCallCompact = muted
798	s.Messages.SectionHeader = base.PaddingLeft(2)
799	s.Messages.AssistantInfoIcon = subtle
800	s.Messages.AssistantInfoModel = muted
801	s.Messages.AssistantInfoProvider = subtle
802	s.Messages.AssistantInfoDuration = subtle
803	s.Messages.AssistantCanceled = lipgloss.NewStyle().Foreground(o.fgBase).Italic(true)
804
805	// Thinking section styles
806	s.Messages.ThinkingBox = subtle.Background(o.bgLeastVisible)
807	s.Messages.ThinkingTruncationHint = muted
808	s.Messages.ThinkingFooterTitle = muted
809	s.Messages.ThinkingFooterDuration = subtle
810
811	// Text selection.
812	s.TextSelection = lipgloss.NewStyle().Foreground(o.onPrimary).Background(o.primary)
813
814	// Dialog styles
815	s.Dialog.Title = base.Padding(0, 1).Foreground(o.primary)
816	s.Dialog.TitleText = base.Foreground(o.primary)
817	s.Dialog.TitleError = base.Foreground(o.destructive)
818	s.Dialog.TitleAccent = base.Foreground(o.success).Bold(true)
819	s.Dialog.TitleLineBase = lipgloss.NewStyle()
820	s.Dialog.TitleGradFromColor = o.primary
821	s.Dialog.TitleGradToColor = o.secondary
822
823	// Dialog.ListItem (commands, reasoning, models)
824	s.Dialog.ListItem.InfoBlurred = lipgloss.NewStyle().Foreground(o.fgBase)
825	s.Dialog.ListItem.InfoFocused = lipgloss.NewStyle().Foreground(o.fgBase)
826
827	// Dialog.Models
828	s.Dialog.Models.ConfiguredText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
829
830	// Dialog.Permissions
831	s.Dialog.Permissions.KeyText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
832	s.Dialog.Permissions.ValueText = lipgloss.NewStyle().Foreground(o.fgBase)
833	s.Dialog.Permissions.ParamsBg = o.bgLessVisible
834
835	// Dialog.Quit
836	s.Dialog.Quit.Content = lipgloss.NewStyle().Foreground(o.fgBase)
837	s.Dialog.Quit.Frame = lipgloss.NewStyle().BorderForeground(o.primary).Border(lipgloss.RoundedBorder()).Padding(1, 2)
838	s.Dialog.View = base.Border(lipgloss.RoundedBorder()).BorderForeground(o.primary)
839	s.Dialog.PrimaryText = base.Padding(0, 1).Foreground(o.primary)
840	s.Dialog.SecondaryText = base.Padding(0, 1).Foreground(o.fgMostSubtle)
841	s.Dialog.HelpView = base.Padding(0, 1).AlignHorizontal(lipgloss.Left)
842	s.Dialog.Help.ShortKey = base.Foreground(o.fgMoreSubtle)
843	s.Dialog.Help.ShortDesc = base.Foreground(o.fgMostSubtle)
844	s.Dialog.Help.ShortSeparator = base.Foreground(o.separator)
845	s.Dialog.Help.Ellipsis = base.Foreground(o.separator)
846	s.Dialog.Help.FullKey = base.Foreground(o.fgMoreSubtle)
847	s.Dialog.Help.FullDesc = base.Foreground(o.fgMostSubtle)
848	s.Dialog.Help.FullSeparator = base.Foreground(o.separator)
849	s.Dialog.NormalItem = base.Padding(0, 1).Foreground(o.fgBase)
850	s.Dialog.SelectedItem = base.Padding(0, 1).Background(o.primary).Foreground(o.onPrimary)
851	s.Dialog.InputPrompt = base.Margin(1, 1)
852
853	s.Dialog.List = base.Margin(0, 0, 1, 0)
854	s.Dialog.ContentPanel = base.Background(o.bgLessVisible).Foreground(o.fgBase).Padding(1, 2)
855	s.Dialog.Spinner = base.Foreground(o.secondary)
856	s.Dialog.ScrollbarThumb = base.Foreground(o.secondary)
857	s.Dialog.ScrollbarTrack = base.Foreground(o.separator)
858
859	s.Dialog.ImagePreview = lipgloss.NewStyle().Padding(0, 1).Foreground(o.fgMostSubtle)
860
861	// API key input dialog
862	s.Dialog.APIKey.Spinner = base.Foreground(o.success)
863
864	// OAuth dialog
865	s.Dialog.OAuth.Spinner = base.Foreground(o.successMoreSubtle)
866	s.Dialog.OAuth.Instructions = lipgloss.NewStyle().Foreground(o.fgBase)
867	s.Dialog.OAuth.UserCode = lipgloss.NewStyle().Bold(true).Foreground(o.fgBase)
868	s.Dialog.OAuth.Success = lipgloss.NewStyle().Foreground(o.successMoreSubtle)
869	s.Dialog.OAuth.Link = lipgloss.NewStyle().Foreground(o.successMostSubtle).Underline(true)
870	s.Dialog.OAuth.Enter = lipgloss.NewStyle().Foreground(o.keyword)
871	s.Dialog.OAuth.ErrorText = lipgloss.NewStyle().Foreground(o.error)
872	s.Dialog.OAuth.StatusText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
873	s.Dialog.OAuth.UserCodeBg = o.bgLeastVisible
874
875	s.Dialog.Arguments.Content = base.Padding(1)
876	s.Dialog.Arguments.Description = base.MarginBottom(1).MaxHeight(3)
877	s.Dialog.Arguments.InputLabelBlurred = base.Foreground(o.fgMoreSubtle)
878	s.Dialog.Arguments.InputLabelFocused = base.Bold(true)
879	s.Dialog.Arguments.InputRequiredMarkBlurred = base.Foreground(o.fgMoreSubtle).SetString("*")
880	s.Dialog.Arguments.InputRequiredMarkFocused = base.Foreground(o.primary).Bold(true).SetString("*")
881
882	s.Dialog.Sessions.DeletingTitle = s.Dialog.Title.Foreground(o.destructive)
883	s.Dialog.Sessions.DeletingView = s.Dialog.View.BorderForeground(o.destructive)
884	s.Dialog.Sessions.DeletingMessage = base.Padding(1)
885	s.Dialog.Sessions.DeletingTitleGradientFromColor = o.destructive
886	s.Dialog.Sessions.DeletingTitleGradientToColor = o.primary
887	s.Dialog.Sessions.DeletingItemBlurred = s.Dialog.NormalItem.Foreground(o.fgMostSubtle)
888	s.Dialog.Sessions.DeletingItemFocused = s.Dialog.SelectedItem.Background(o.destructive).Foreground(o.onPrimary)
889
890	s.Dialog.Sessions.RenamingingTitle = s.Dialog.Title.Foreground(o.warningSubtle)
891	s.Dialog.Sessions.RenamingView = s.Dialog.View.BorderForeground(o.warningSubtle)
892	s.Dialog.Sessions.RenamingingMessage = base.Padding(1)
893	s.Dialog.Sessions.RenamingTitleGradientFromColor = o.warningSubtle
894	s.Dialog.Sessions.RenamingTitleGradientToColor = o.accent
895	s.Dialog.Sessions.RenamingItemBlurred = s.Dialog.NormalItem.Foreground(o.fgMostSubtle)
896	s.Dialog.Sessions.RenamingingItemFocused = s.Dialog.SelectedItem.UnsetBackground().UnsetForeground()
897	s.Dialog.Sessions.RenamingPlaceholder = base.Foreground(o.fgMoreSubtle)
898	s.Dialog.Sessions.InfoBlurred = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
899	s.Dialog.Sessions.InfoFocused = lipgloss.NewStyle().Foreground(o.fgBase)
900
901	s.Status.Help = lipgloss.NewStyle().Padding(0, 1)
902	s.Status.SuccessIndicator = base.Foreground(o.bgLessVisible).Background(o.success).Padding(0, 1).Bold(true).SetString("OKAY!")
903	s.Status.InfoIndicator = s.Status.SuccessIndicator
904	s.Status.UpdateIndicator = s.Status.SuccessIndicator.SetString("HEY!")
905	s.Status.WarnIndicator = s.Status.SuccessIndicator.Foreground(o.bgMostVisible).Background(o.warning).SetString("WARNING")
906	s.Status.ErrorIndicator = s.Status.SuccessIndicator.Foreground(o.bgBase).Background(o.destructive).SetString("ERROR")
907	s.Status.SuccessMessage = base.Foreground(o.bgLessVisible).Background(o.successMostSubtle).Padding(0, 1)
908	s.Status.InfoMessage = s.Status.SuccessMessage
909	s.Status.UpdateMessage = s.Status.SuccessMessage
910	s.Status.WarnMessage = s.Status.SuccessMessage.Foreground(o.bgMostVisible).Background(o.warningSubtle)
911	s.Status.ErrorMessage = s.Status.SuccessMessage.Foreground(o.onPrimary).Background(o.error)
912
913	// Completions styles
914	s.Completions.Normal = base.Background(o.bgLessVisible).Foreground(o.fgBase)
915	s.Completions.Focused = base.Background(o.primary).Foreground(o.onPrimary)
916	s.Completions.Match = base.Underline(true)
917
918	// Attachments styles
919	attachmentIconStyle := base.Foreground(o.bgLessVisible).Background(o.success).Padding(0, 1)
920	s.Attachments.Image = attachmentIconStyle.SetString(ImageIcon)
921	s.Attachments.Text = attachmentIconStyle.SetString(TextIcon)
922	s.Attachments.Normal = base.Padding(0, 1).MarginRight(1).Background(o.fgMoreSubtle).Foreground(o.fgBase)
923	s.Attachments.Deleting = base.Padding(0, 1).Bold(true).Background(o.destructive).Foreground(o.fgBase)
924
925	// Pills styles
926	s.Pills.Base = base.Padding(0, 1)
927	s.Pills.Focused = base.Padding(0, 1).BorderStyle(lipgloss.RoundedBorder()).BorderForeground(o.bgMostVisible)
928	s.Pills.Blurred = base.Padding(0, 1).BorderStyle(lipgloss.HiddenBorder())
929	s.Pills.QueueItemPrefix = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).SetString("  •")
930	s.Pills.QueueItemText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
931	s.Pills.QueueLabel = lipgloss.NewStyle().Foreground(o.fgBase)
932	s.Pills.QueueIconBase = lipgloss.NewStyle().Foreground(o.fgBase)
933	s.Pills.QueueGradFromColor = o.error
934	s.Pills.QueueGradToColor = o.secondary
935	s.Pills.TodoLabel = lipgloss.NewStyle().Foreground(o.fgBase)
936	s.Pills.TodoProgress = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
937	s.Pills.TodoCurrentTask = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
938	s.Pills.TodoSpinner = lipgloss.NewStyle().Foreground(o.successMostSubtle)
939	s.Pills.HelpKey = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
940	s.Pills.HelpText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
941	s.Pills.Area = base
942
943	return s
944}