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.Hypercredit = base.Foreground(charmtone.Dolly)
581	s.Header.Keystroke = muted
582	s.Header.KeystrokeTip = subtle
583	s.Header.WorkingDir = muted
584	s.Header.Separator = subtle
585	s.Header.Wrapper = lipgloss.NewStyle().Foreground(o.fgBase)
586	s.Header.LogoGradCanvas = lipgloss.NewStyle()
587	s.Header.LogoGradFromColor = o.secondary
588	s.Header.LogoGradToColor = o.primary
589
590	s.CompactDetails.Title = base
591	s.CompactDetails.View = base.Padding(0, 1, 1, 1).Border(lipgloss.RoundedBorder()).BorderForeground(o.primary)
592	s.CompactDetails.Version = lipgloss.NewStyle().Foreground(o.separator)
593
594	// Tool rendering styles
595	s.Tool.IconPending = base.Foreground(o.successMostSubtle).SetString(ToolPending)
596	s.Tool.IconSuccess = base.Foreground(o.success).SetString(ToolSuccess)
597	s.Tool.IconError = base.Foreground(o.error).SetString(ToolError)
598	s.Tool.IconCancelled = muted.SetString(ToolPending)
599
600	s.Tool.NameNormal = base.Foreground(o.info)
601	s.Tool.NameNested = base.Foreground(o.info)
602
603	s.Tool.ParamMain = subtle
604	s.Tool.ParamKey = subtle
605
606	// Content rendering - prepared styles that accept width parameter
607	s.Tool.ContentLine = muted.Background(o.bgLeastVisible)
608	s.Tool.ContentTruncation = muted.Background(o.bgLeastVisible)
609	s.Tool.ContentCodeLine = base.Background(o.bgBase).PaddingLeft(2)
610	s.Tool.ContentCodeTruncation = muted.Background(o.bgBase).PaddingLeft(2)
611	s.Tool.ContentCodeBg = o.bgBase
612	s.Tool.Body = base.PaddingLeft(2)
613
614	// Deprecated - kept for backward compatibility
615	s.Tool.ContentBg = muted.Background(o.bgLeastVisible)
616	s.Tool.ContentText = muted
617	s.Tool.ContentLineNumber = base.Foreground(o.fgMoreSubtle).Background(o.bgBase).PaddingRight(1).PaddingLeft(1)
618
619	s.Tool.StateWaiting = base.Foreground(o.fgMostSubtle)
620	s.Tool.StateCancelled = base.Foreground(o.fgMostSubtle)
621
622	s.Tool.ErrorTag = base.Padding(0, 1).Background(o.destructive).Foreground(o.onPrimary)
623	s.Tool.ErrorMessage = base.Foreground(o.fgSubtle)
624
625	// Diff and multi-edit styles
626	s.Tool.DiffTruncation = muted.Background(o.bgLeastVisible).PaddingLeft(2)
627	s.Tool.NoteTag = base.Padding(0, 1).Background(o.info).Foreground(o.onPrimary)
628	s.Tool.NoteMessage = base.Foreground(o.fgSubtle)
629
630	// Job header styles
631	s.Tool.JobIconPending = base.Foreground(o.successMostSubtle)
632	s.Tool.JobIconError = base.Foreground(o.error)
633	s.Tool.JobIconSuccess = base.Foreground(o.success)
634	s.Tool.JobToolName = base.Foreground(o.info)
635	s.Tool.JobAction = base.Foreground(o.infoMostSubtle)
636	s.Tool.JobPID = muted
637	s.Tool.JobDescription = subtle
638
639	// Agent task styles
640	s.Tool.AgentTaskTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(o.infoMoreSubtle).Foreground(o.onPrimary)
641	s.Tool.AgentPrompt = muted
642
643	// Agentic fetch styles
644	s.Tool.AgenticFetchPromptTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(o.success).Foreground(o.separator)
645
646	// Todo styles
647	s.Tool.TodoRatio = base.Foreground(o.infoMostSubtle)
648	s.Tool.TodoCompletedIcon = base.Foreground(o.success)
649	s.Tool.TodoInProgressIcon = base.Foreground(o.successMostSubtle)
650	s.Tool.TodoPendingIcon = base.Foreground(o.fgMoreSubtle)
651	s.Tool.TodoStatusNote = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
652	s.Tool.TodoItem = lipgloss.NewStyle().Foreground(o.fgBase)
653	s.Tool.TodoJustStarted = lipgloss.NewStyle().Foreground(o.fgBase)
654
655	// MCP styles
656	s.Tool.MCPName = base.Foreground(o.info)
657	s.Tool.MCPToolName = base.Foreground(o.infoMostSubtle)
658	s.Tool.MCPArrow = base.Foreground(o.info).SetString(ArrowRightIcon)
659
660	// Loading indicators for images, skills
661	s.Tool.ResourceLoadedText = base.Foreground(o.success)
662	s.Tool.ResourceLoadedIndicator = base.Foreground(o.successMostSubtle)
663	s.Tool.ResourceName = base
664	s.Tool.MediaType = base
665	s.Tool.ResourceSize = base.Foreground(o.fgMoreSubtle)
666
667	// Hook styles
668	s.Tool.HookLabel = base.Foreground(o.successMoreSubtle)
669	s.Tool.HookName = base
670	s.Tool.HookMatcher = base.Foreground(o.fgMoreSubtle)
671	s.Tool.HookArrow = base.Foreground(o.successMoreSubtle)
672	s.Tool.HookDetail = base.Foreground(o.fgMoreSubtle)
673	s.Tool.HookOK = base.Foreground(o.successMostSubtle)
674	s.Tool.HookDenied = base.Foreground(o.error)
675	s.Tool.HookDeniedLabel = base.Foreground(o.destructive)
676	s.Tool.HookDeniedReason = base.Foreground(o.bgMostVisible)
677	s.Tool.HookRewrote = base.Foreground(o.bgMostVisible)
678
679	// Tool-call action verbs and result-list styling.
680	s.Tool.ActionCreate = lipgloss.NewStyle().Foreground(o.successMoreSubtle)
681	s.Tool.ActionDestroy = lipgloss.NewStyle().Foreground(o.destructive)
682	s.Tool.ResultEmpty = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
683	s.Tool.ResultTruncation = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
684	s.Tool.ResultItemName = lipgloss.NewStyle().Foreground(o.fgBase)
685	s.Tool.ResultItemDesc = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
686
687	// Buttons
688	s.Button.Focused = lipgloss.NewStyle().Foreground(o.onPrimary).Background(o.secondary)
689	s.Button.Blurred = lipgloss.NewStyle().Foreground(o.fgBase).Background(o.bgLessVisible)
690
691	// Editor
692	s.Editor.PromptNormalFocused = lipgloss.NewStyle().Foreground(o.successMostSubtle).SetString("::: ")
693	s.Editor.PromptNormalBlurred = s.Editor.PromptNormalFocused.Foreground(o.fgMoreSubtle)
694	s.Editor.PromptYoloIconFocused = lipgloss.NewStyle().MarginRight(1).Foreground(o.fgMostSubtle).Background(o.busy).Bold(true).SetString(" ! ")
695	s.Editor.PromptYoloIconBlurred = s.Editor.PromptYoloIconFocused.Foreground(o.bgBase).Background(o.fgMoreSubtle)
696	s.Editor.PromptYoloDotsFocused = lipgloss.NewStyle().MarginRight(1).Foreground(o.warningSubtle).SetString(":::")
697	s.Editor.PromptYoloDotsBlurred = s.Editor.PromptYoloDotsFocused.Foreground(o.fgMoreSubtle)
698
699	s.Radio.On = lipgloss.NewStyle().Foreground(o.fgSubtle).SetString(RadioOn)
700	s.Radio.Off = lipgloss.NewStyle().Foreground(o.fgSubtle).SetString(RadioOff)
701	s.Radio.Label = lipgloss.NewStyle().Foreground(o.fgSubtle)
702
703	// Logo
704	s.Logo.FieldColor = o.primary
705	s.Logo.TitleColorA = o.secondary
706	s.Logo.TitleColorB = o.primary
707	s.Logo.CharmColor = o.secondary
708	s.Logo.VersionColor = o.primary
709	s.Logo.SmallCharm = lipgloss.NewStyle().Foreground(o.secondary)
710	s.Logo.SmallDiagonals = lipgloss.NewStyle().Foreground(o.primary)
711	s.Logo.GradCanvas = lipgloss.NewStyle()
712	s.Logo.SmallGradFromColor = o.secondary
713	s.Logo.SmallGradToColor = o.primary
714
715	// Section
716	s.Section.Title = subtle
717	s.Section.Line = base.Foreground(o.separator)
718
719	// Initialize
720	s.Initialize.Header = base
721	s.Initialize.Content = muted
722	s.Initialize.Accent = base.Foreground(o.successMostSubtle)
723
724	// ResourceGroup (LSP/MCP/skills sidebar lists).
725	s.Resource.Heading = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
726	s.Resource.Name = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
727	s.Resource.StatusText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
728	s.Resource.OfflineIcon = lipgloss.NewStyle().Foreground(o.bgMostVisible).SetString("●")
729	s.Resource.BusyIcon = s.Resource.OfflineIcon.Foreground(o.busy)
730	s.Resource.ErrorIcon = s.Resource.OfflineIcon.Foreground(o.destructive)
731	s.Resource.OnlineIcon = s.Resource.OfflineIcon.Foreground(o.successMostSubtle)
732	s.Resource.DisabledIcon = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).SetString("●")
733	s.Resource.AdditionalText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
734	s.Resource.CapabilityCount = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
735	s.Resource.RowTitleBase = lipgloss.NewStyle().Foreground(o.fgBase)
736	s.Resource.RowDescBase = lipgloss.NewStyle().Foreground(o.fgBase)
737	s.Resource.DefaultTitleFg = o.fgMoreSubtle
738	s.Resource.DefaultDescFg = o.fgMostSubtle
739
740	// LSP
741	s.LSP.ErrorDiagnostic = base.Foreground(o.error)
742	s.LSP.WarningDiagnostic = base.Foreground(o.warningSubtle)
743	s.LSP.HintDiagnostic = base.Foreground(o.fgSubtle)
744	s.LSP.InfoDiagnostic = base.Foreground(o.info)
745
746	// Files
747	s.Files.Path = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
748	s.Files.Additions = lipgloss.NewStyle().Foreground(o.successMostSubtle)
749	s.Files.Deletions = lipgloss.NewStyle().Foreground(o.error)
750	s.Files.SectionTitle = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
751	s.Files.EmptyMessage = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
752	s.Files.TruncationHint = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
753
754	// Sidebar
755	s.Sidebar.SessionTitle = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
756	s.Sidebar.WorkingDir = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
757
758	// ModelInfo
759	s.ModelInfo.Icon = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
760	s.ModelInfo.Name = lipgloss.NewStyle().Foreground(o.fgBase)
761	s.ModelInfo.Provider = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
762	s.ModelInfo.ProviderFallback = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).PaddingLeft(2)
763	s.ModelInfo.Reasoning = lipgloss.NewStyle().Foreground(o.fgMostSubtle).PaddingLeft(2)
764	s.ModelInfo.TokenCount = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
765	s.ModelInfo.TokenPercentage = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
766	s.ModelInfo.Cost = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
767	s.ModelInfo.HypercreditIcon = lipgloss.NewStyle().Foreground(charmtone.Dolly)
768	s.ModelInfo.HypercreditText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
769
770	// ResourceGroup
771	s.Resource.DefaultTitleFg = o.fgMoreSubtle
772	s.Resource.DefaultDescFg = o.fgMostSubtle
773
774	// Chat
775	messageFocussedBorder := lipgloss.Border{
776		Left: "▌",
777	}
778
779	s.Messages.NoContent = lipgloss.NewStyle().Foreground(o.fgBase)
780	s.Messages.UserBlurred = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
781		BorderForeground(o.primary).BorderStyle(lipgloss.NormalBorder())
782	s.Messages.UserFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
783		BorderForeground(o.primary).BorderStyle(messageFocussedBorder)
784	s.Messages.AssistantBlurred = s.Messages.NoContent.PaddingLeft(2)
785	s.Messages.AssistantFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
786		BorderForeground(o.successMostSubtle).BorderStyle(messageFocussedBorder)
787	s.Messages.Thinking = lipgloss.NewStyle().MaxHeight(10)
788	s.Messages.ErrorTag = lipgloss.NewStyle().Padding(0, 1).
789		Background(o.destructive).Foreground(o.onPrimary)
790	s.Messages.ErrorTitle = lipgloss.NewStyle().Foreground(o.fgSubtle)
791	s.Messages.ErrorDetails = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
792
793	// Message item styles
794	s.Messages.ToolCallFocused = muted.PaddingLeft(1).
795		BorderStyle(messageFocussedBorder).
796		BorderLeft(true).
797		BorderForeground(o.successMostSubtle)
798	s.Messages.ToolCallBlurred = muted.PaddingLeft(2)
799	// No padding or border for compact tool calls within messages
800	s.Messages.ToolCallCompact = muted
801	s.Messages.SectionHeader = base.PaddingLeft(2)
802	s.Messages.AssistantInfoIcon = subtle
803	s.Messages.AssistantInfoModel = muted
804	s.Messages.AssistantInfoProvider = subtle
805	s.Messages.AssistantInfoDuration = subtle
806	s.Messages.AssistantCanceled = lipgloss.NewStyle().Foreground(o.fgBase).Italic(true)
807
808	// Thinking section styles
809	s.Messages.ThinkingBox = subtle.Background(o.bgLeastVisible)
810	s.Messages.ThinkingTruncationHint = muted
811	s.Messages.ThinkingFooterTitle = muted
812	s.Messages.ThinkingFooterDuration = subtle
813
814	// Text selection.
815	s.TextSelection = lipgloss.NewStyle().Foreground(o.onPrimary).Background(o.primary)
816
817	// Dialog styles
818	s.Dialog.Title = base.Padding(0, 1).Foreground(o.primary)
819	s.Dialog.TitleText = base.Foreground(o.primary)
820	s.Dialog.TitleError = base.Foreground(o.destructive)
821	s.Dialog.TitleAccent = base.Foreground(o.success).Bold(true)
822	s.Dialog.TitleLineBase = lipgloss.NewStyle()
823	s.Dialog.TitleGradFromColor = o.primary
824	s.Dialog.TitleGradToColor = o.secondary
825
826	// Dialog.ListItem (commands, reasoning, models)
827	s.Dialog.ListItem.InfoBlurred = lipgloss.NewStyle().Foreground(o.fgBase)
828	s.Dialog.ListItem.InfoFocused = lipgloss.NewStyle().Foreground(o.fgBase)
829
830	// Dialog.Models
831	s.Dialog.Models.ConfiguredText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
832
833	// Dialog.Permissions
834	s.Dialog.Permissions.KeyText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
835	s.Dialog.Permissions.ValueText = lipgloss.NewStyle().Foreground(o.fgBase)
836	s.Dialog.Permissions.ParamsBg = o.bgLessVisible
837
838	// Dialog.Quit
839	s.Dialog.Quit.Content = lipgloss.NewStyle().Foreground(o.fgBase)
840	s.Dialog.Quit.Frame = lipgloss.NewStyle().BorderForeground(o.primary).Border(lipgloss.RoundedBorder()).Padding(1, 2)
841	s.Dialog.View = base.Border(lipgloss.RoundedBorder()).BorderForeground(o.primary)
842	s.Dialog.PrimaryText = base.Padding(0, 1).Foreground(o.primary)
843	s.Dialog.SecondaryText = base.Padding(0, 1).Foreground(o.fgMostSubtle)
844	s.Dialog.HelpView = base.Padding(0, 1).AlignHorizontal(lipgloss.Left)
845	s.Dialog.Help.ShortKey = base.Foreground(o.fgMoreSubtle)
846	s.Dialog.Help.ShortDesc = base.Foreground(o.fgMostSubtle)
847	s.Dialog.Help.ShortSeparator = base.Foreground(o.separator)
848	s.Dialog.Help.Ellipsis = base.Foreground(o.separator)
849	s.Dialog.Help.FullKey = base.Foreground(o.fgMoreSubtle)
850	s.Dialog.Help.FullDesc = base.Foreground(o.fgMostSubtle)
851	s.Dialog.Help.FullSeparator = base.Foreground(o.separator)
852	s.Dialog.NormalItem = base.Padding(0, 1).Foreground(o.fgBase)
853	s.Dialog.SelectedItem = base.Padding(0, 1).Background(o.primary).Foreground(o.onPrimary)
854	s.Dialog.InputPrompt = base.Margin(1, 1)
855
856	s.Dialog.List = base.Margin(0, 0, 1, 0)
857	s.Dialog.ContentPanel = base.Background(o.bgLessVisible).Foreground(o.fgBase).Padding(1, 2)
858	s.Dialog.Spinner = base.Foreground(o.secondary)
859	s.Dialog.ScrollbarThumb = base.Foreground(o.secondary)
860	s.Dialog.ScrollbarTrack = base.Foreground(o.separator)
861
862	s.Dialog.ImagePreview = lipgloss.NewStyle().Padding(0, 1).Foreground(o.fgMostSubtle)
863
864	// API key input dialog
865	s.Dialog.APIKey.Spinner = base.Foreground(o.success)
866
867	// OAuth dialog
868	s.Dialog.OAuth.Spinner = base.Foreground(o.successMoreSubtle)
869	s.Dialog.OAuth.Instructions = lipgloss.NewStyle().Foreground(o.fgBase)
870	s.Dialog.OAuth.UserCode = lipgloss.NewStyle().Bold(true).Foreground(o.fgBase)
871	s.Dialog.OAuth.Success = lipgloss.NewStyle().Foreground(o.successMoreSubtle)
872	s.Dialog.OAuth.Link = lipgloss.NewStyle().Foreground(o.successMostSubtle).Underline(true)
873	s.Dialog.OAuth.Enter = lipgloss.NewStyle().Foreground(o.keyword)
874	s.Dialog.OAuth.ErrorText = lipgloss.NewStyle().Foreground(o.error)
875	s.Dialog.OAuth.StatusText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
876	s.Dialog.OAuth.UserCodeBg = o.bgLeastVisible
877
878	s.Dialog.Arguments.Content = base.Padding(1)
879	s.Dialog.Arguments.Description = base.MarginBottom(1).MaxHeight(3)
880	s.Dialog.Arguments.InputLabelBlurred = base.Foreground(o.fgMoreSubtle)
881	s.Dialog.Arguments.InputLabelFocused = base.Bold(true)
882	s.Dialog.Arguments.InputRequiredMarkBlurred = base.Foreground(o.fgMoreSubtle).SetString("*")
883	s.Dialog.Arguments.InputRequiredMarkFocused = base.Foreground(o.primary).Bold(true).SetString("*")
884
885	s.Dialog.Sessions.DeletingTitle = s.Dialog.Title.Foreground(o.destructive)
886	s.Dialog.Sessions.DeletingView = s.Dialog.View.BorderForeground(o.destructive)
887	s.Dialog.Sessions.DeletingMessage = base.Padding(1)
888	s.Dialog.Sessions.DeletingTitleGradientFromColor = o.destructive
889	s.Dialog.Sessions.DeletingTitleGradientToColor = o.primary
890	s.Dialog.Sessions.DeletingItemBlurred = s.Dialog.NormalItem.Foreground(o.fgMostSubtle)
891	s.Dialog.Sessions.DeletingItemFocused = s.Dialog.SelectedItem.Background(o.destructive).Foreground(o.onPrimary)
892
893	s.Dialog.Sessions.RenamingingTitle = s.Dialog.Title.Foreground(o.warningSubtle)
894	s.Dialog.Sessions.RenamingView = s.Dialog.View.BorderForeground(o.warningSubtle)
895	s.Dialog.Sessions.RenamingingMessage = base.Padding(1)
896	s.Dialog.Sessions.RenamingTitleGradientFromColor = o.warningSubtle
897	s.Dialog.Sessions.RenamingTitleGradientToColor = o.accent
898	s.Dialog.Sessions.RenamingItemBlurred = s.Dialog.NormalItem.Foreground(o.fgMostSubtle)
899	s.Dialog.Sessions.RenamingingItemFocused = s.Dialog.SelectedItem.UnsetBackground().UnsetForeground()
900	s.Dialog.Sessions.RenamingPlaceholder = base.Foreground(o.fgMoreSubtle)
901	s.Dialog.Sessions.InfoBlurred = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
902	s.Dialog.Sessions.InfoFocused = lipgloss.NewStyle().Foreground(o.fgBase)
903
904	s.Status.Help = lipgloss.NewStyle().Padding(0, 1)
905	s.Status.SuccessIndicator = base.Foreground(o.bgLessVisible).Background(o.success).Padding(0, 1).Bold(true).SetString("OKAY!")
906	s.Status.InfoIndicator = s.Status.SuccessIndicator
907	s.Status.UpdateIndicator = s.Status.SuccessIndicator.SetString("HEY!")
908	s.Status.WarnIndicator = s.Status.SuccessIndicator.Foreground(o.bgMostVisible).Background(o.warning).SetString("WARNING")
909	s.Status.ErrorIndicator = s.Status.SuccessIndicator.Foreground(o.bgBase).Background(o.destructive).SetString("ERROR")
910	s.Status.SuccessMessage = base.Foreground(o.bgLessVisible).Background(o.successMostSubtle).Padding(0, 1)
911	s.Status.InfoMessage = s.Status.SuccessMessage
912	s.Status.UpdateMessage = s.Status.SuccessMessage
913	s.Status.WarnMessage = s.Status.SuccessMessage.Foreground(o.bgMostVisible).Background(o.warningSubtle)
914	s.Status.ErrorMessage = s.Status.SuccessMessage.Foreground(o.onPrimary).Background(o.error)
915
916	// Completions styles
917	s.Completions.Normal = base.Background(o.bgLessVisible).Foreground(o.fgBase)
918	s.Completions.Focused = base.Background(o.primary).Foreground(o.onPrimary)
919	s.Completions.Match = base.Underline(true)
920
921	// Attachments styles
922	attachmentIconStyle := base.Foreground(o.bgLessVisible).Background(o.success).Padding(0, 1)
923	s.Attachments.Image = attachmentIconStyle.SetString(ImageIcon)
924	s.Attachments.Text = attachmentIconStyle.SetString(TextIcon)
925	s.Attachments.Normal = base.Padding(0, 1).MarginRight(1).Background(o.fgMoreSubtle).Foreground(o.fgBase)
926	s.Attachments.Deleting = base.Padding(0, 1).Bold(true).Background(o.destructive).Foreground(o.fgBase)
927
928	// Pills styles
929	s.Pills.Base = base.Padding(0, 1)
930	s.Pills.Focused = base.Padding(0, 1).BorderStyle(lipgloss.RoundedBorder()).BorderForeground(o.bgMostVisible)
931	s.Pills.Blurred = base.Padding(0, 1).BorderStyle(lipgloss.HiddenBorder())
932	s.Pills.QueueItemPrefix = lipgloss.NewStyle().Foreground(o.fgMoreSubtle).SetString("  •")
933	s.Pills.QueueItemText = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
934	s.Pills.QueueLabel = lipgloss.NewStyle().Foreground(o.fgBase)
935	s.Pills.QueueIconBase = lipgloss.NewStyle().Foreground(o.fgBase)
936	s.Pills.QueueGradFromColor = o.error
937	s.Pills.QueueGradToColor = o.secondary
938	s.Pills.TodoLabel = lipgloss.NewStyle().Foreground(o.fgBase)
939	s.Pills.TodoProgress = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
940	s.Pills.TodoCurrentTask = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
941	s.Pills.TodoSpinner = lipgloss.NewStyle().Foreground(o.successMostSubtle)
942	s.Pills.HelpKey = lipgloss.NewStyle().Foreground(o.fgMoreSubtle)
943	s.Pills.HelpText = lipgloss.NewStyle().Foreground(o.fgMostSubtle)
944	s.Pills.Area = base
945
946	return s
947}