styles.go

   1package styles
   2
   3import (
   4	"image/color"
   5	"strings"
   6
   7	"charm.land/bubbles/v2/filepicker"
   8	"charm.land/bubbles/v2/help"
   9	"charm.land/bubbles/v2/textarea"
  10	"charm.land/bubbles/v2/textinput"
  11	tea "charm.land/bubbletea/v2"
  12	"charm.land/glamour/v2/ansi"
  13	"charm.land/lipgloss/v2"
  14	"github.com/alecthomas/chroma/v2"
  15	"github.com/charmbracelet/crush/internal/ui/diffview"
  16	"github.com/charmbracelet/x/exp/charmtone"
  17)
  18
  19const (
  20	CheckIcon   string = "βœ“"
  21	SpinnerIcon string = "β‹―"
  22	LoadingIcon string = "⟳"
  23	ModelIcon   string = "β—‡"
  24
  25	ArrowRightIcon string = "β†’"
  26
  27	ToolPending string = "●"
  28	ToolSuccess string = "βœ“"
  29	ToolError   string = "Γ—"
  30
  31	RadioOn  string = "β—‰"
  32	RadioOff string = "β—‹"
  33
  34	BorderThin  string = "β”‚"
  35	BorderThick string = "β–Œ"
  36
  37	SectionSeparator string = "─"
  38
  39	TodoCompletedIcon  string = "βœ“"
  40	TodoPendingIcon    string = "β€’"
  41	TodoInProgressIcon string = "β†’"
  42
  43	ImageIcon string = "β– "
  44	TextIcon  string = "≑"
  45
  46	ScrollbarThumb string = "┃"
  47	ScrollbarTrack string = "β”‚"
  48
  49	LSPErrorIcon   string = "E"
  50	LSPWarningIcon string = "W"
  51	LSPInfoIcon    string = "I"
  52	LSPHintIcon    string = "H"
  53)
  54
  55const (
  56	defaultMargin     = 2
  57	defaultListIndent = 2
  58)
  59
  60type Styles struct {
  61	// Header
  62	Header struct {
  63		Charm             lipgloss.Style // Style for "Charmβ„’" label
  64		Diagonals         lipgloss.Style // Style for diagonal separators (β•±)
  65		Percentage        lipgloss.Style // Style for context percentage
  66		Keystroke         lipgloss.Style // Style for keystroke hints (e.g., "ctrl+d")
  67		KeystrokeTip      lipgloss.Style // Style for keystroke action text (e.g., "open", "close")
  68		WorkingDir        lipgloss.Style // Style for current working directory
  69		Separator         lipgloss.Style // Style for separator dots (β€’)
  70		Wrapper           lipgloss.Style // Outer container for the entire header row
  71		LogoGradCanvas    lipgloss.Style // Canvas for the compact "CRUSH" gradient
  72		LogoGradFromColor color.Color    // "CRUSH" wordmark gradient start
  73		LogoGradToColor   color.Color    // "CRUSH" wordmark gradient end
  74	}
  75
  76	CompactDetails struct {
  77		View    lipgloss.Style
  78		Version lipgloss.Style
  79		Title   lipgloss.Style
  80	}
  81
  82	// Tool calls
  83	ToolCallSuccess lipgloss.Style
  84
  85	// Text selection
  86	TextSelection lipgloss.Style
  87
  88	// Markdown & Chroma
  89	Markdown      ansi.StyleConfig
  90	QuietMarkdown ansi.StyleConfig
  91
  92	// Inputs
  93	TextInput textinput.Styles
  94
  95	// Help
  96	Help help.Styles
  97
  98	// Diff
  99	Diff diffview.Style
 100
 101	// FilePicker
 102	FilePicker filepicker.Styles
 103
 104	// Buttons
 105	Button struct {
 106		Focused lipgloss.Style
 107		Blurred lipgloss.Style
 108	}
 109
 110	// Editor
 111	Editor struct {
 112		Textarea textarea.Styles
 113
 114		// Normal mode prompt (default "::: ").
 115		PromptNormalFocused lipgloss.Style
 116		PromptNormalBlurred lipgloss.Style
 117
 118		// YOLO mode prompt (" ! " icon + ":::" dots).
 119		PromptYoloIconFocused lipgloss.Style
 120		PromptYoloIconBlurred lipgloss.Style
 121		PromptYoloDotsFocused lipgloss.Style
 122		PromptYoloDotsBlurred lipgloss.Style
 123	}
 124
 125	// Radio
 126	Radio struct {
 127		On    lipgloss.Style
 128		Off   lipgloss.Style
 129		Label lipgloss.Style // Text next to a radio button
 130	}
 131
 132	// Background
 133	Background color.Color
 134
 135	// Logo
 136	Logo struct {
 137		FieldColor         color.Color
 138		TitleColorA        color.Color
 139		TitleColorB        color.Color
 140		CharmColor         color.Color
 141		VersionColor       color.Color
 142		SmallCharm         lipgloss.Style // "Charmβ„’" label in SmallRender
 143		SmallDiagonals     lipgloss.Style // Diagonal line fill in SmallRender
 144		GradCanvas         lipgloss.Style // Blank canvas for gradient painting
 145		SmallGradFromColor color.Color    // Small "Crush" wordmark gradient start
 146		SmallGradToColor   color.Color    // Small "Crush" wordmark gradient end
 147	}
 148
 149	// Working indicator gradient (spinners/shimmers on assistant "thinking",
 150	// tool-call pending, CLI generating, startup).
 151	WorkingGradFromColor color.Color
 152	WorkingGradToColor   color.Color
 153	WorkingLabelColor    color.Color // Label text color next to the indicator
 154
 155	// Section Title
 156	Section struct {
 157		Title lipgloss.Style
 158		Line  lipgloss.Style
 159	}
 160
 161	// Initialize
 162	Initialize struct {
 163		Header  lipgloss.Style
 164		Content lipgloss.Style
 165		Accent  lipgloss.Style
 166	}
 167
 168	// LSP
 169	LSP struct {
 170		ErrorDiagnostic   lipgloss.Style
 171		WarningDiagnostic lipgloss.Style
 172		HintDiagnostic    lipgloss.Style
 173		InfoDiagnostic    lipgloss.Style
 174	}
 175
 176	// Sidebar
 177	Sidebar struct {
 178		SessionTitle lipgloss.Style // Current session title at top of sidebar
 179		WorkingDir   lipgloss.Style // Working directory path (PrettyPath)
 180	}
 181
 182	// ModelInfo (model name, provider, reasoning, token/cost summary)
 183	ModelInfo struct {
 184		Icon             lipgloss.Style // Model icon (β—‡)
 185		Name             lipgloss.Style // Model name text
 186		Provider         lipgloss.Style // "via <provider>" text
 187		ProviderFallback lipgloss.Style // Provider on its own second line
 188		Reasoning        lipgloss.Style // Reasoning effort text
 189		TokenCount       lipgloss.Style // "(42K)" token count
 190		TokenPercentage  lipgloss.Style // "42%" percent of context window
 191		Cost             lipgloss.Style // "$0.42" cost readout
 192	}
 193
 194	// Resource styles the LSP/MCP/skills sidebar lists: their heading,
 195	// each row's status icon, name, status text, and truncation hints.
 196	Resource struct {
 197		Heading         lipgloss.Style // Section header ("LSPs", "MCPs", "Skills")
 198		Name            lipgloss.Style // Resource name (e.g. "gopls")
 199		StatusText      lipgloss.Style // Row status description (e.g. "starting...")
 200		OfflineIcon     lipgloss.Style // Offline/unstarted/stopped status icon
 201		DisabledIcon    lipgloss.Style // Disabled status icon
 202		BusyIcon        lipgloss.Style // Busy/starting status icon
 203		ErrorIcon       lipgloss.Style // Error status icon
 204		OnlineIcon      lipgloss.Style // Online/ready status icon
 205		AdditionalText  lipgloss.Style // "None" and "…and N more" text
 206		CapabilityCount lipgloss.Style // "N tools" / "N prompts" / "N resources"
 207		RowTitleBase    lipgloss.Style // Base style applied over row titles in common.Status
 208		RowDescBase     lipgloss.Style // Base style applied over row descriptions in common.Status
 209		DefaultTitleFg  color.Color    // Default title color when opt is zero
 210		DefaultDescFg   color.Color    // Default description color when opt is zero
 211	}
 212
 213	// Files
 214	Files struct {
 215		Path           lipgloss.Style
 216		Additions      lipgloss.Style
 217		Deletions      lipgloss.Style
 218		SectionTitle   lipgloss.Style // "Modified Files" heading
 219		EmptyMessage   lipgloss.Style // "None" placeholder when no files
 220		TruncationHint lipgloss.Style // "…and N more" message
 221	}
 222
 223	// Chat
 224	// Messages - chat message item styles
 225	Messages struct {
 226		UserBlurred      lipgloss.Style
 227		UserFocused      lipgloss.Style
 228		AssistantBlurred lipgloss.Style
 229		AssistantFocused lipgloss.Style
 230		NoContent        lipgloss.Style
 231		Thinking         lipgloss.Style
 232		ErrorTag         lipgloss.Style
 233		ErrorTitle       lipgloss.Style
 234		ErrorDetails     lipgloss.Style
 235		ToolCallFocused  lipgloss.Style
 236		ToolCallCompact  lipgloss.Style
 237		ToolCallBlurred  lipgloss.Style
 238		SectionHeader    lipgloss.Style
 239
 240		// Thinking section styles
 241		ThinkingBox            lipgloss.Style // Background for thinking content
 242		ThinkingTruncationHint lipgloss.Style // "… (N lines hidden)" hint
 243		ThinkingFooterTitle    lipgloss.Style // "Thought for" text
 244		ThinkingFooterDuration lipgloss.Style // Duration value
 245		AssistantInfoIcon      lipgloss.Style
 246		AssistantInfoModel     lipgloss.Style
 247		AssistantInfoProvider  lipgloss.Style
 248		AssistantInfoDuration  lipgloss.Style
 249		AssistantCanceled      lipgloss.Style // Italic "Canceled" footer
 250	}
 251
 252	// Tool - styles for tool call rendering
 253	Tool struct {
 254		// Icon styles with tool status
 255		IconPending   lipgloss.Style
 256		IconSuccess   lipgloss.Style
 257		IconError     lipgloss.Style
 258		IconCancelled lipgloss.Style
 259
 260		// Tool name styles
 261		NameNormal lipgloss.Style // Top-level tool name
 262		NameNested lipgloss.Style // Nested child tool name (inside Agent/Agentic Fetch)
 263
 264		// Parameter list styles
 265		ParamMain lipgloss.Style
 266		ParamKey  lipgloss.Style
 267
 268		// Content rendering styles
 269		ContentLine           lipgloss.Style // Individual content line with background and width
 270		ContentTruncation     lipgloss.Style // Truncation message "… (N lines)"
 271		ContentCodeLine       lipgloss.Style // Code line with background and width
 272		ContentCodeTruncation lipgloss.Style // Code truncation message with bgBase
 273		ContentCodeBg         color.Color    // Background color for syntax highlighting
 274		Body                  lipgloss.Style // Body content padding (PaddingLeft(2))
 275
 276		// Deprecated - kept for backward compatibility
 277		ContentBg         lipgloss.Style // Content background
 278		ContentText       lipgloss.Style // Content text
 279		ContentLineNumber lipgloss.Style // Line numbers in code
 280
 281		// State message styles
 282		StateWaiting   lipgloss.Style // "Waiting for tool response..."
 283		StateCancelled lipgloss.Style // "Canceled."
 284
 285		// Error styles
 286		ErrorTag     lipgloss.Style // ERROR tag
 287		ErrorMessage lipgloss.Style // Error message text
 288
 289		// Diff styles
 290		DiffTruncation lipgloss.Style // Diff truncation message with padding
 291
 292		// Multi-edit note styles
 293		NoteTag     lipgloss.Style // NOTE tag (yellow background)
 294		NoteMessage lipgloss.Style // Note message text
 295
 296		// Job header styles (for bash jobs)
 297		JobIconPending lipgloss.Style // Pending job icon (green dark)
 298		JobIconError   lipgloss.Style // Error job icon (red dark)
 299		JobIconSuccess lipgloss.Style // Success job icon (green)
 300		JobToolName    lipgloss.Style // Job tool name "Bash" (blue)
 301		JobAction      lipgloss.Style // Action text (Start, Output, Kill)
 302		JobPID         lipgloss.Style // PID text
 303		JobDescription lipgloss.Style // Description text
 304
 305		// Agent task styles
 306		AgentTaskTag lipgloss.Style // Agent task tag (blue background, bold)
 307		AgentPrompt  lipgloss.Style // Agent prompt text
 308
 309		// Agentic fetch styles
 310		AgenticFetchPromptTag lipgloss.Style // Agentic fetch prompt tag (green background, bold)
 311
 312		// Todo styles
 313		TodoRatio          lipgloss.Style // Todo ratio (e.g., "2/5")
 314		TodoCompletedIcon  lipgloss.Style // Completed todo icon
 315		TodoInProgressIcon lipgloss.Style // In-progress todo icon
 316		TodoPendingIcon    lipgloss.Style // Pending todo icon
 317		TodoStatusNote     lipgloss.Style // " Β· completed N" / " Β· starting task" trailing note
 318		TodoItem           lipgloss.Style // Default body text for todo list items
 319		TodoJustStarted    lipgloss.Style // Text of the just-started todo in tool-call bodies
 320
 321		// MCP tools
 322		MCPName     lipgloss.Style // The mcp name
 323		MCPToolName lipgloss.Style // The mcp tool name
 324		MCPArrow    lipgloss.Style // The mcp arrow icon
 325
 326		// Images and external resources
 327		ResourceLoadedText      lipgloss.Style
 328		ResourceLoadedIndicator lipgloss.Style
 329		ResourceName            lipgloss.Style
 330		ResourceSize            lipgloss.Style
 331		MediaType               lipgloss.Style
 332
 333		// Action verb colors for tool-call headers.
 334		ActionCreate  lipgloss.Style // Constructive actions (e.g. "Add", "Create")
 335		ActionDestroy lipgloss.Style // Destructive actions (e.g. "Remove", "Delete")
 336
 337		// Tool result helpers.
 338		ResultEmpty      lipgloss.Style // "No results" placeholder
 339		ResultTruncation lipgloss.Style // "… and N more" truncation line
 340		ResultItemName   lipgloss.Style // Item name (left column in result lists)
 341		ResultItemDesc   lipgloss.Style // Item description (right column)
 342	}
 343
 344	// Dialog styles
 345	Dialog struct {
 346		Title              lipgloss.Style
 347		TitleText          lipgloss.Style
 348		TitleError         lipgloss.Style
 349		TitleAccent        lipgloss.Style
 350		TitleLineBase      lipgloss.Style // Base for the gradient β•±β•±β•± next to dialog titles
 351		TitleGradFromColor color.Color    // Default dialog title β•±β•±β•± gradient start
 352		TitleGradToColor   color.Color    // Default dialog title β•±β•±β•± gradient end
 353		// View is the main content area style.
 354		View          lipgloss.Style
 355		PrimaryText   lipgloss.Style
 356		SecondaryText lipgloss.Style
 357		// HelpView is the line that contains the help.
 358		HelpView lipgloss.Style
 359		Help     struct {
 360			Ellipsis       lipgloss.Style
 361			ShortKey       lipgloss.Style
 362			ShortDesc      lipgloss.Style
 363			ShortSeparator lipgloss.Style
 364			FullKey        lipgloss.Style
 365			FullDesc       lipgloss.Style
 366			FullSeparator  lipgloss.Style
 367		}
 368
 369		NormalItem   lipgloss.Style
 370		SelectedItem lipgloss.Style
 371		InputPrompt  lipgloss.Style
 372
 373		List lipgloss.Style
 374
 375		Spinner lipgloss.Style
 376
 377		// ContentPanel is used for content blocks with subtle background.
 378		ContentPanel lipgloss.Style
 379
 380		// Scrollbar styles for scrollable content.
 381		ScrollbarThumb lipgloss.Style
 382		ScrollbarTrack lipgloss.Style
 383
 384		// Arguments
 385		Arguments struct {
 386			Content                  lipgloss.Style
 387			Description              lipgloss.Style
 388			InputLabelBlurred        lipgloss.Style
 389			InputLabelFocused        lipgloss.Style
 390			InputRequiredMarkBlurred lipgloss.Style
 391			InputRequiredMarkFocused lipgloss.Style
 392		}
 393
 394		// ListItem styles the info-text rendered alongside list items (commands,
 395		// models, reasoning options). Sessions have their own overrides below.
 396		ListItem struct {
 397			InfoBlurred lipgloss.Style
 398			InfoFocused lipgloss.Style
 399		}
 400
 401		Models struct {
 402			ConfiguredText lipgloss.Style // "Configured" badge shown on the ModelGroup header
 403		}
 404
 405		Permissions struct {
 406			KeyText   lipgloss.Style // Left key cell of a key/value row
 407			ValueText lipgloss.Style // Right value cell of a key/value row
 408			ParamsBg  color.Color    // Background color behind highlighted JSON parameters
 409		}
 410
 411		Quit struct {
 412			Content lipgloss.Style // Wrapper for the quit dialog's inner content
 413			Frame   lipgloss.Style // Outer rounded border framing the quit dialog
 414		}
 415
 416		APIKey struct {
 417			Spinner lipgloss.Style // Loading spinner while validating the key
 418		}
 419
 420		OAuth struct {
 421			Spinner      lipgloss.Style // Loading spinner
 422			Instructions lipgloss.Style // Emphasized instruction text
 423			UserCode     lipgloss.Style // Prominent user code display
 424			Success      lipgloss.Style // Positive status text (e.g. "Authentication successful!")
 425			Link         lipgloss.Style // Underlined verification URL
 426			Enter        lipgloss.Style // "enter" keyword highlight in instructions
 427			ErrorText    lipgloss.Style // Error message when authentication fails
 428			StatusText   lipgloss.Style // Narrative status text ("Initializing...", "Verifying...", etc.)
 429			UserCodeBg   color.Color    // Background color of the centered user-code box
 430		}
 431
 432		ImagePreview lipgloss.Style
 433
 434		Sessions struct {
 435			// styles for when we are in delete mode
 436			DeletingView                   lipgloss.Style
 437			DeletingItemFocused            lipgloss.Style
 438			DeletingItemBlurred            lipgloss.Style
 439			DeletingTitle                  lipgloss.Style
 440			DeletingMessage                lipgloss.Style
 441			DeletingTitleGradientFromColor color.Color
 442			DeletingTitleGradientToColor   color.Color
 443
 444			// styles for when we are in update mode
 445			RenamingView                   lipgloss.Style
 446			RenamingingItemFocused         lipgloss.Style
 447			RenamingItemBlurred            lipgloss.Style
 448			RenamingingTitle               lipgloss.Style
 449			RenamingingMessage             lipgloss.Style
 450			RenamingTitleGradientFromColor color.Color
 451			RenamingTitleGradientToColor   color.Color
 452			RenamingPlaceholder            lipgloss.Style
 453
 454			InfoBlurred lipgloss.Style // Timestamp text on unfocused session items
 455			InfoFocused lipgloss.Style // Timestamp text on the focused session item
 456		}
 457	}
 458
 459	// Status bar and help
 460	Status struct {
 461		Help lipgloss.Style
 462
 463		ErrorIndicator   lipgloss.Style
 464		WarnIndicator    lipgloss.Style
 465		InfoIndicator    lipgloss.Style
 466		UpdateIndicator  lipgloss.Style
 467		SuccessIndicator lipgloss.Style
 468
 469		ErrorMessage   lipgloss.Style
 470		WarnMessage    lipgloss.Style
 471		InfoMessage    lipgloss.Style
 472		UpdateMessage  lipgloss.Style
 473		SuccessMessage lipgloss.Style
 474	}
 475
 476	// Completions popup styles
 477	Completions struct {
 478		Normal  lipgloss.Style
 479		Focused lipgloss.Style
 480		Match   lipgloss.Style
 481	}
 482
 483	// Attachments styles
 484	Attachments struct {
 485		Normal   lipgloss.Style
 486		Image    lipgloss.Style
 487		Text     lipgloss.Style
 488		Deleting lipgloss.Style
 489	}
 490
 491	// Pills styles for todo/queue pills
 492	Pills struct {
 493		Base               lipgloss.Style // Base pill style with padding
 494		Focused            lipgloss.Style // Focused pill with visible border
 495		Blurred            lipgloss.Style // Blurred pill with hidden border
 496		QueueItemPrefix    lipgloss.Style // Prefix for queue list items
 497		QueueItemText      lipgloss.Style // Queue list item body text
 498		QueueLabel         lipgloss.Style // "N Queued" label text
 499		QueueIconBase      lipgloss.Style // Base style for queue gradient triangles
 500		QueueGradFromColor color.Color    // Start color for queue indicator gradient
 501		QueueGradToColor   color.Color    // End color for queue indicator gradient
 502		TodoLabel          lipgloss.Style // "To-Do" label
 503		TodoProgress       lipgloss.Style // Todo ratio (e.g. "2/5")
 504		TodoCurrentTask    lipgloss.Style // Current in-progress task name
 505		TodoSpinner        lipgloss.Style // Todo spinner style
 506		HelpKey            lipgloss.Style // Keystroke hint style
 507		HelpText           lipgloss.Style // Help action text style
 508		Area               lipgloss.Style // Pills area container
 509	}
 510}
 511
 512// ChromaTheme converts the current markdown chroma styles to a chroma
 513// StyleEntries map.
 514func (s *Styles) ChromaTheme() chroma.StyleEntries {
 515	rules := s.Markdown.CodeBlock
 516
 517	return chroma.StyleEntries{
 518		chroma.Text:                chromaStyle(rules.Chroma.Text),
 519		chroma.Error:               chromaStyle(rules.Chroma.Error),
 520		chroma.Comment:             chromaStyle(rules.Chroma.Comment),
 521		chroma.CommentPreproc:      chromaStyle(rules.Chroma.CommentPreproc),
 522		chroma.Keyword:             chromaStyle(rules.Chroma.Keyword),
 523		chroma.KeywordReserved:     chromaStyle(rules.Chroma.KeywordReserved),
 524		chroma.KeywordNamespace:    chromaStyle(rules.Chroma.KeywordNamespace),
 525		chroma.KeywordType:         chromaStyle(rules.Chroma.KeywordType),
 526		chroma.Operator:            chromaStyle(rules.Chroma.Operator),
 527		chroma.Punctuation:         chromaStyle(rules.Chroma.Punctuation),
 528		chroma.Name:                chromaStyle(rules.Chroma.Name),
 529		chroma.NameBuiltin:         chromaStyle(rules.Chroma.NameBuiltin),
 530		chroma.NameTag:             chromaStyle(rules.Chroma.NameTag),
 531		chroma.NameAttribute:       chromaStyle(rules.Chroma.NameAttribute),
 532		chroma.NameClass:           chromaStyle(rules.Chroma.NameClass),
 533		chroma.NameConstant:        chromaStyle(rules.Chroma.NameConstant),
 534		chroma.NameDecorator:       chromaStyle(rules.Chroma.NameDecorator),
 535		chroma.NameException:       chromaStyle(rules.Chroma.NameException),
 536		chroma.NameFunction:        chromaStyle(rules.Chroma.NameFunction),
 537		chroma.NameOther:           chromaStyle(rules.Chroma.NameOther),
 538		chroma.Literal:             chromaStyle(rules.Chroma.Literal),
 539		chroma.LiteralNumber:       chromaStyle(rules.Chroma.LiteralNumber),
 540		chroma.LiteralDate:         chromaStyle(rules.Chroma.LiteralDate),
 541		chroma.LiteralString:       chromaStyle(rules.Chroma.LiteralString),
 542		chroma.LiteralStringEscape: chromaStyle(rules.Chroma.LiteralStringEscape),
 543		chroma.GenericDeleted:      chromaStyle(rules.Chroma.GenericDeleted),
 544		chroma.GenericEmph:         chromaStyle(rules.Chroma.GenericEmph),
 545		chroma.GenericInserted:     chromaStyle(rules.Chroma.GenericInserted),
 546		chroma.GenericStrong:       chromaStyle(rules.Chroma.GenericStrong),
 547		chroma.GenericSubheading:   chromaStyle(rules.Chroma.GenericSubheading),
 548		chroma.Background:          chromaStyle(rules.Chroma.Background),
 549	}
 550}
 551
 552// DialogHelpStyles returns the styles for dialog help.
 553func (s *Styles) DialogHelpStyles() help.Styles {
 554	return help.Styles(s.Dialog.Help)
 555}
 556
 557// DefaultStyles returns the default styles for the UI.
 558func DefaultStyles() Styles {
 559	var (
 560		primary   = charmtone.Charple
 561		secondary = charmtone.Dolly
 562		tertiary  = charmtone.Bok
 563		// accent    = charmtone.Zest
 564
 565		// Backgrounds
 566		bgBase        = charmtone.Pepper
 567		bgBaseLighter = charmtone.BBQ
 568		bgSubtle      = charmtone.Charcoal
 569		bgOverlay     = charmtone.Iron
 570
 571		// Foregrounds
 572		fgBase      = charmtone.Ash
 573		fgMuted     = charmtone.Squid
 574		fgHalfMuted = charmtone.Smoke
 575		fgSubtle    = charmtone.Oyster
 576		// fgSelected  = charmtone.Salt
 577
 578		// Borders
 579		border      = charmtone.Charcoal
 580		borderFocus = charmtone.Charple
 581
 582		// Status
 583		error   = charmtone.Sriracha
 584		warning = charmtone.Zest
 585		info    = charmtone.Malibu
 586
 587		// Colors
 588		white = charmtone.Butter
 589
 590		blueLight = charmtone.Sardine
 591		blue      = charmtone.Malibu
 592		blueDark  = charmtone.Damson
 593
 594		// yellow = charmtone.Mustard
 595		yellow = charmtone.Mustard
 596		// citron = charmtone.Citron
 597
 598		greenLight = charmtone.Bok
 599		green      = charmtone.Julep
 600		greenDark  = charmtone.Guac
 601		// greenLight = charmtone.Bok
 602
 603		red     = charmtone.Coral
 604		redDark = charmtone.Sriracha
 605		// redLight = charmtone.Salmon
 606		// cherry   = charmtone.Cherry
 607	)
 608
 609	normalBorder := lipgloss.NormalBorder()
 610
 611	base := lipgloss.NewStyle().Foreground(fgBase)
 612	muted := lipgloss.NewStyle().Foreground(fgMuted)
 613	subtle := lipgloss.NewStyle().Foreground(fgSubtle)
 614
 615	s := Styles{}
 616
 617	s.Background = bgBase
 618
 619	// Populate color fields
 620	s.WorkingGradFromColor = primary
 621	s.WorkingGradToColor = secondary
 622	s.WorkingLabelColor = fgBase
 623
 624	s.TextInput = textinput.Styles{
 625		Focused: textinput.StyleState{
 626			Text:        base,
 627			Placeholder: base.Foreground(fgSubtle),
 628			Prompt:      base.Foreground(tertiary),
 629			Suggestion:  base.Foreground(fgSubtle),
 630		},
 631		Blurred: textinput.StyleState{
 632			Text:        base.Foreground(fgMuted),
 633			Placeholder: base.Foreground(fgSubtle),
 634			Prompt:      base.Foreground(fgMuted),
 635			Suggestion:  base.Foreground(fgSubtle),
 636		},
 637		Cursor: textinput.CursorStyle{
 638			Color: secondary,
 639			Shape: tea.CursorBlock,
 640			Blink: true,
 641		},
 642	}
 643
 644	s.Editor.Textarea = textarea.Styles{
 645		Focused: textarea.StyleState{
 646			Base:             base,
 647			Text:             base,
 648			LineNumber:       base.Foreground(fgSubtle),
 649			CursorLine:       base,
 650			CursorLineNumber: base.Foreground(fgSubtle),
 651			Placeholder:      base.Foreground(fgSubtle),
 652			Prompt:           base.Foreground(tertiary),
 653		},
 654		Blurred: textarea.StyleState{
 655			Base:             base,
 656			Text:             base.Foreground(fgMuted),
 657			LineNumber:       base.Foreground(fgMuted),
 658			CursorLine:       base,
 659			CursorLineNumber: base.Foreground(fgMuted),
 660			Placeholder:      base.Foreground(fgSubtle),
 661			Prompt:           base.Foreground(fgMuted),
 662		},
 663		Cursor: textarea.CursorStyle{
 664			Color: secondary,
 665			Shape: tea.CursorBlock,
 666			Blink: true,
 667		},
 668	}
 669
 670	s.Markdown = ansi.StyleConfig{
 671		Document: ansi.StyleBlock{
 672			StylePrimitive: ansi.StylePrimitive{
 673				// BlockPrefix: "\n",
 674				// BlockSuffix: "\n",
 675				Color: new(charmtone.Smoke.Hex()),
 676			},
 677			// Margin: new(uint(defaultMargin)),
 678		},
 679		BlockQuote: ansi.StyleBlock{
 680			StylePrimitive: ansi.StylePrimitive{},
 681			Indent:         new(uint(1)),
 682			IndentToken:    new("β”‚ "),
 683		},
 684		List: ansi.StyleList{
 685			LevelIndent: defaultListIndent,
 686		},
 687		Heading: ansi.StyleBlock{
 688			StylePrimitive: ansi.StylePrimitive{
 689				BlockSuffix: "\n",
 690				Color:       new(charmtone.Malibu.Hex()),
 691				Bold:        new(true),
 692			},
 693		},
 694		H1: ansi.StyleBlock{
 695			StylePrimitive: ansi.StylePrimitive{
 696				Prefix:          " ",
 697				Suffix:          " ",
 698				Color:           new(charmtone.Zest.Hex()),
 699				BackgroundColor: new(charmtone.Charple.Hex()),
 700				Bold:            new(true),
 701			},
 702		},
 703		H2: ansi.StyleBlock{
 704			StylePrimitive: ansi.StylePrimitive{
 705				Prefix: "## ",
 706			},
 707		},
 708		H3: ansi.StyleBlock{
 709			StylePrimitive: ansi.StylePrimitive{
 710				Prefix: "### ",
 711			},
 712		},
 713		H4: ansi.StyleBlock{
 714			StylePrimitive: ansi.StylePrimitive{
 715				Prefix: "#### ",
 716			},
 717		},
 718		H5: ansi.StyleBlock{
 719			StylePrimitive: ansi.StylePrimitive{
 720				Prefix: "##### ",
 721			},
 722		},
 723		H6: ansi.StyleBlock{
 724			StylePrimitive: ansi.StylePrimitive{
 725				Prefix: "###### ",
 726				Color:  new(charmtone.Guac.Hex()),
 727				Bold:   new(false),
 728			},
 729		},
 730		Strikethrough: ansi.StylePrimitive{
 731			CrossedOut: new(true),
 732		},
 733		Emph: ansi.StylePrimitive{
 734			Italic: new(true),
 735		},
 736		Strong: ansi.StylePrimitive{
 737			Bold: new(true),
 738		},
 739		HorizontalRule: ansi.StylePrimitive{
 740			Color:  new(charmtone.Charcoal.Hex()),
 741			Format: "\n--------\n",
 742		},
 743		Item: ansi.StylePrimitive{
 744			BlockPrefix: "β€’ ",
 745		},
 746		Enumeration: ansi.StylePrimitive{
 747			BlockPrefix: ". ",
 748		},
 749		Task: ansi.StyleTask{
 750			StylePrimitive: ansi.StylePrimitive{},
 751			Ticked:         "[βœ“] ",
 752			Unticked:       "[ ] ",
 753		},
 754		Link: ansi.StylePrimitive{
 755			Color:     new(charmtone.Zinc.Hex()),
 756			Underline: new(true),
 757		},
 758		LinkText: ansi.StylePrimitive{
 759			Color: new(charmtone.Guac.Hex()),
 760			Bold:  new(true),
 761		},
 762		Image: ansi.StylePrimitive{
 763			Color:     new(charmtone.Cheeky.Hex()),
 764			Underline: new(true),
 765		},
 766		ImageText: ansi.StylePrimitive{
 767			Color:  new(charmtone.Squid.Hex()),
 768			Format: "Image: {{.text}} β†’",
 769		},
 770		Code: ansi.StyleBlock{
 771			StylePrimitive: ansi.StylePrimitive{
 772				Prefix:          " ",
 773				Suffix:          " ",
 774				Color:           new(charmtone.Coral.Hex()),
 775				BackgroundColor: new(charmtone.Charcoal.Hex()),
 776			},
 777		},
 778		CodeBlock: ansi.StyleCodeBlock{
 779			StyleBlock: ansi.StyleBlock{
 780				StylePrimitive: ansi.StylePrimitive{
 781					Color: new(charmtone.Charcoal.Hex()),
 782				},
 783				Margin: new(uint(defaultMargin)),
 784			},
 785			Chroma: &ansi.Chroma{
 786				Text: ansi.StylePrimitive{
 787					Color: new(charmtone.Smoke.Hex()),
 788				},
 789				Error: ansi.StylePrimitive{
 790					Color:           new(charmtone.Butter.Hex()),
 791					BackgroundColor: new(charmtone.Sriracha.Hex()),
 792				},
 793				Comment: ansi.StylePrimitive{
 794					Color: new(charmtone.Oyster.Hex()),
 795				},
 796				CommentPreproc: ansi.StylePrimitive{
 797					Color: new(charmtone.Bengal.Hex()),
 798				},
 799				Keyword: ansi.StylePrimitive{
 800					Color: new(charmtone.Malibu.Hex()),
 801				},
 802				KeywordReserved: ansi.StylePrimitive{
 803					Color: new(charmtone.Pony.Hex()),
 804				},
 805				KeywordNamespace: ansi.StylePrimitive{
 806					Color: new(charmtone.Pony.Hex()),
 807				},
 808				KeywordType: ansi.StylePrimitive{
 809					Color: new(charmtone.Guppy.Hex()),
 810				},
 811				Operator: ansi.StylePrimitive{
 812					Color: new(charmtone.Salmon.Hex()),
 813				},
 814				Punctuation: ansi.StylePrimitive{
 815					Color: new(charmtone.Zest.Hex()),
 816				},
 817				Name: ansi.StylePrimitive{
 818					Color: new(charmtone.Smoke.Hex()),
 819				},
 820				NameBuiltin: ansi.StylePrimitive{
 821					Color: new(charmtone.Cheeky.Hex()),
 822				},
 823				NameTag: ansi.StylePrimitive{
 824					Color: new(charmtone.Mauve.Hex()),
 825				},
 826				NameAttribute: ansi.StylePrimitive{
 827					Color: new(charmtone.Hazy.Hex()),
 828				},
 829				NameClass: ansi.StylePrimitive{
 830					Color:     new(charmtone.Salt.Hex()),
 831					Underline: new(true),
 832					Bold:      new(true),
 833				},
 834				NameDecorator: ansi.StylePrimitive{
 835					Color: new(charmtone.Citron.Hex()),
 836				},
 837				NameFunction: ansi.StylePrimitive{
 838					Color: new(charmtone.Guac.Hex()),
 839				},
 840				LiteralNumber: ansi.StylePrimitive{
 841					Color: new(charmtone.Julep.Hex()),
 842				},
 843				LiteralString: ansi.StylePrimitive{
 844					Color: new(charmtone.Cumin.Hex()),
 845				},
 846				LiteralStringEscape: ansi.StylePrimitive{
 847					Color: new(charmtone.Bok.Hex()),
 848				},
 849				GenericDeleted: ansi.StylePrimitive{
 850					Color: new(charmtone.Coral.Hex()),
 851				},
 852				GenericEmph: ansi.StylePrimitive{
 853					Italic: new(true),
 854				},
 855				GenericInserted: ansi.StylePrimitive{
 856					Color: new(charmtone.Guac.Hex()),
 857				},
 858				GenericStrong: ansi.StylePrimitive{
 859					Bold: new(true),
 860				},
 861				GenericSubheading: ansi.StylePrimitive{
 862					Color: new(charmtone.Squid.Hex()),
 863				},
 864				Background: ansi.StylePrimitive{
 865					BackgroundColor: new(charmtone.Charcoal.Hex()),
 866				},
 867			},
 868		},
 869		Table: ansi.StyleTable{
 870			StyleBlock: ansi.StyleBlock{
 871				StylePrimitive: ansi.StylePrimitive{},
 872			},
 873		},
 874		DefinitionDescription: ansi.StylePrimitive{
 875			BlockPrefix: "\n ",
 876		},
 877	}
 878
 879	// QuietMarkdown style - muted colors on subtle background for thinking content.
 880	plainBg := new(bgBaseLighter.Hex())
 881	plainFg := new(fgMuted.Hex())
 882	s.QuietMarkdown = ansi.StyleConfig{
 883		Document: ansi.StyleBlock{
 884			StylePrimitive: ansi.StylePrimitive{
 885				Color:           plainFg,
 886				BackgroundColor: plainBg,
 887			},
 888		},
 889		BlockQuote: ansi.StyleBlock{
 890			StylePrimitive: ansi.StylePrimitive{
 891				Color:           plainFg,
 892				BackgroundColor: plainBg,
 893			},
 894			Indent:      new(uint(1)),
 895			IndentToken: new("β”‚ "),
 896		},
 897		List: ansi.StyleList{
 898			LevelIndent: defaultListIndent,
 899		},
 900		Heading: ansi.StyleBlock{
 901			StylePrimitive: ansi.StylePrimitive{
 902				BlockSuffix:     "\n",
 903				Bold:            new(true),
 904				Color:           plainFg,
 905				BackgroundColor: plainBg,
 906			},
 907		},
 908		H1: ansi.StyleBlock{
 909			StylePrimitive: ansi.StylePrimitive{
 910				Prefix:          " ",
 911				Suffix:          " ",
 912				Bold:            new(true),
 913				Color:           plainFg,
 914				BackgroundColor: plainBg,
 915			},
 916		},
 917		H2: ansi.StyleBlock{
 918			StylePrimitive: ansi.StylePrimitive{
 919				Prefix:          "## ",
 920				Color:           plainFg,
 921				BackgroundColor: plainBg,
 922			},
 923		},
 924		H3: ansi.StyleBlock{
 925			StylePrimitive: ansi.StylePrimitive{
 926				Prefix:          "### ",
 927				Color:           plainFg,
 928				BackgroundColor: plainBg,
 929			},
 930		},
 931		H4: ansi.StyleBlock{
 932			StylePrimitive: ansi.StylePrimitive{
 933				Prefix:          "#### ",
 934				Color:           plainFg,
 935				BackgroundColor: plainBg,
 936			},
 937		},
 938		H5: ansi.StyleBlock{
 939			StylePrimitive: ansi.StylePrimitive{
 940				Prefix:          "##### ",
 941				Color:           plainFg,
 942				BackgroundColor: plainBg,
 943			},
 944		},
 945		H6: ansi.StyleBlock{
 946			StylePrimitive: ansi.StylePrimitive{
 947				Prefix:          "###### ",
 948				Color:           plainFg,
 949				BackgroundColor: plainBg,
 950			},
 951		},
 952		Strikethrough: ansi.StylePrimitive{
 953			CrossedOut:      new(true),
 954			Color:           plainFg,
 955			BackgroundColor: plainBg,
 956		},
 957		Emph: ansi.StylePrimitive{
 958			Italic:          new(true),
 959			Color:           plainFg,
 960			BackgroundColor: plainBg,
 961		},
 962		Strong: ansi.StylePrimitive{
 963			Bold:            new(true),
 964			Color:           plainFg,
 965			BackgroundColor: plainBg,
 966		},
 967		HorizontalRule: ansi.StylePrimitive{
 968			Format:          "\n--------\n",
 969			Color:           plainFg,
 970			BackgroundColor: plainBg,
 971		},
 972		Item: ansi.StylePrimitive{
 973			BlockPrefix:     "β€’ ",
 974			Color:           plainFg,
 975			BackgroundColor: plainBg,
 976		},
 977		Enumeration: ansi.StylePrimitive{
 978			BlockPrefix:     ". ",
 979			Color:           plainFg,
 980			BackgroundColor: plainBg,
 981		},
 982		Task: ansi.StyleTask{
 983			StylePrimitive: ansi.StylePrimitive{
 984				Color:           plainFg,
 985				BackgroundColor: plainBg,
 986			},
 987			Ticked:   "[βœ“] ",
 988			Unticked: "[ ] ",
 989		},
 990		Link: ansi.StylePrimitive{
 991			Underline:       new(true),
 992			Color:           plainFg,
 993			BackgroundColor: plainBg,
 994		},
 995		LinkText: ansi.StylePrimitive{
 996			Bold:            new(true),
 997			Color:           plainFg,
 998			BackgroundColor: plainBg,
 999		},
1000		Image: ansi.StylePrimitive{
1001			Underline:       new(true),
1002			Color:           plainFg,
1003			BackgroundColor: plainBg,
1004		},
1005		ImageText: ansi.StylePrimitive{
1006			Format:          "Image: {{.text}} β†’",
1007			Color:           plainFg,
1008			BackgroundColor: plainBg,
1009		},
1010		Code: ansi.StyleBlock{
1011			StylePrimitive: ansi.StylePrimitive{
1012				Prefix:          " ",
1013				Suffix:          " ",
1014				Color:           plainFg,
1015				BackgroundColor: plainBg,
1016			},
1017		},
1018		CodeBlock: ansi.StyleCodeBlock{
1019			StyleBlock: ansi.StyleBlock{
1020				StylePrimitive: ansi.StylePrimitive{
1021					Color:           plainFg,
1022					BackgroundColor: plainBg,
1023				},
1024				Margin: new(uint(defaultMargin)),
1025			},
1026		},
1027		Table: ansi.StyleTable{
1028			StyleBlock: ansi.StyleBlock{
1029				StylePrimitive: ansi.StylePrimitive{
1030					Color:           plainFg,
1031					BackgroundColor: plainBg,
1032				},
1033			},
1034		},
1035		DefinitionDescription: ansi.StylePrimitive{
1036			BlockPrefix:     "\n ",
1037			Color:           plainFg,
1038			BackgroundColor: plainBg,
1039		},
1040	}
1041
1042	s.Help = help.Styles{
1043		ShortKey:       base.Foreground(fgMuted),
1044		ShortDesc:      base.Foreground(fgSubtle),
1045		ShortSeparator: base.Foreground(border),
1046		Ellipsis:       base.Foreground(border),
1047		FullKey:        base.Foreground(fgMuted),
1048		FullDesc:       base.Foreground(fgSubtle),
1049		FullSeparator:  base.Foreground(border),
1050	}
1051
1052	s.Diff = diffview.Style{
1053		DividerLine: diffview.LineStyle{
1054			LineNumber: lipgloss.NewStyle().
1055				Foreground(fgHalfMuted).
1056				Background(bgBaseLighter),
1057			Code: lipgloss.NewStyle().
1058				Foreground(fgHalfMuted).
1059				Background(bgBaseLighter),
1060		},
1061		MissingLine: diffview.LineStyle{
1062			LineNumber: lipgloss.NewStyle().
1063				Background(bgBaseLighter),
1064			Code: lipgloss.NewStyle().
1065				Background(bgBaseLighter),
1066		},
1067		EqualLine: diffview.LineStyle{
1068			LineNumber: lipgloss.NewStyle().
1069				Foreground(fgMuted).
1070				Background(bgBase),
1071			Code: lipgloss.NewStyle().
1072				Foreground(fgMuted).
1073				Background(bgBase),
1074		},
1075		InsertLine: diffview.LineStyle{
1076			LineNumber: lipgloss.NewStyle().
1077				Foreground(lipgloss.Color("#629657")).
1078				Background(lipgloss.Color("#2b322a")),
1079			Symbol: lipgloss.NewStyle().
1080				Foreground(lipgloss.Color("#629657")).
1081				Background(lipgloss.Color("#323931")),
1082			Code: lipgloss.NewStyle().
1083				Background(lipgloss.Color("#323931")),
1084		},
1085		DeleteLine: diffview.LineStyle{
1086			LineNumber: lipgloss.NewStyle().
1087				Foreground(lipgloss.Color("#a45c59")).
1088				Background(lipgloss.Color("#312929")),
1089			Symbol: lipgloss.NewStyle().
1090				Foreground(lipgloss.Color("#a45c59")).
1091				Background(lipgloss.Color("#383030")),
1092			Code: lipgloss.NewStyle().
1093				Background(lipgloss.Color("#383030")),
1094		},
1095		Filename: diffview.LineStyle{
1096			LineNumber: lipgloss.NewStyle().
1097				Foreground(fgHalfMuted).
1098				Background(bgBaseLighter),
1099			Code: lipgloss.NewStyle().
1100				Foreground(fgHalfMuted).
1101				Background(bgBaseLighter),
1102		},
1103	}
1104
1105	s.FilePicker = filepicker.Styles{
1106		DisabledCursor:   base.Foreground(fgMuted),
1107		Cursor:           base.Foreground(fgBase),
1108		Symlink:          base.Foreground(fgSubtle),
1109		Directory:        base.Foreground(primary),
1110		File:             base.Foreground(fgBase),
1111		DisabledFile:     base.Foreground(fgMuted),
1112		DisabledSelected: base.Background(bgOverlay).Foreground(fgMuted),
1113		Permission:       base.Foreground(fgMuted),
1114		Selected:         base.Background(primary).Foreground(fgBase),
1115		FileSize:         base.Foreground(fgMuted),
1116		EmptyDirectory:   base.Foreground(fgMuted).PaddingLeft(2).SetString("Empty directory"),
1117	}
1118
1119	// borders
1120	s.ToolCallSuccess = lipgloss.NewStyle().Foreground(green).SetString(ToolSuccess)
1121
1122	s.Header.Charm = base.Foreground(secondary)
1123	s.Header.Diagonals = base.Foreground(primary)
1124	s.Header.Percentage = muted
1125	s.Header.Keystroke = muted
1126	s.Header.KeystrokeTip = subtle
1127	s.Header.WorkingDir = muted
1128	s.Header.Separator = subtle
1129	s.Header.Wrapper = lipgloss.NewStyle().Foreground(fgBase)
1130	s.Header.LogoGradCanvas = lipgloss.NewStyle()
1131	s.Header.LogoGradFromColor = secondary
1132	s.Header.LogoGradToColor = primary
1133
1134	s.CompactDetails.Title = base
1135	s.CompactDetails.View = base.Padding(0, 1, 1, 1).Border(lipgloss.RoundedBorder()).BorderForeground(borderFocus)
1136	s.CompactDetails.Version = lipgloss.NewStyle().Foreground(border)
1137
1138	// Tool rendering styles
1139	s.Tool.IconPending = base.Foreground(greenDark).SetString(ToolPending)
1140	s.Tool.IconSuccess = base.Foreground(green).SetString(ToolSuccess)
1141	s.Tool.IconError = base.Foreground(redDark).SetString(ToolError)
1142	s.Tool.IconCancelled = muted.SetString(ToolPending)
1143
1144	s.Tool.NameNormal = base.Foreground(blue)
1145	s.Tool.NameNested = base.Foreground(blue)
1146
1147	s.Tool.ParamMain = subtle
1148	s.Tool.ParamKey = subtle
1149
1150	// Content rendering - prepared styles that accept width parameter
1151	s.Tool.ContentLine = muted.Background(bgBaseLighter)
1152	s.Tool.ContentTruncation = muted.Background(bgBaseLighter)
1153	s.Tool.ContentCodeLine = base.Background(bgBase).PaddingLeft(2)
1154	s.Tool.ContentCodeTruncation = muted.Background(bgBase).PaddingLeft(2)
1155	s.Tool.ContentCodeBg = bgBase
1156	s.Tool.Body = base.PaddingLeft(2)
1157
1158	// Deprecated - kept for backward compatibility
1159	s.Tool.ContentBg = muted.Background(bgBaseLighter)
1160	s.Tool.ContentText = muted
1161	s.Tool.ContentLineNumber = base.Foreground(fgMuted).Background(bgBase).PaddingRight(1).PaddingLeft(1)
1162
1163	s.Tool.StateWaiting = base.Foreground(fgSubtle)
1164	s.Tool.StateCancelled = base.Foreground(fgSubtle)
1165
1166	s.Tool.ErrorTag = base.Padding(0, 1).Background(red).Foreground(white)
1167	s.Tool.ErrorMessage = base.Foreground(fgHalfMuted)
1168
1169	// Diff and multi-edit styles
1170	s.Tool.DiffTruncation = muted.Background(bgBaseLighter).PaddingLeft(2)
1171	s.Tool.NoteTag = base.Padding(0, 1).Background(info).Foreground(white)
1172	s.Tool.NoteMessage = base.Foreground(fgHalfMuted)
1173
1174	// Job header styles
1175	s.Tool.JobIconPending = base.Foreground(greenDark)
1176	s.Tool.JobIconError = base.Foreground(redDark)
1177	s.Tool.JobIconSuccess = base.Foreground(green)
1178	s.Tool.JobToolName = base.Foreground(blue)
1179	s.Tool.JobAction = base.Foreground(blueDark)
1180	s.Tool.JobPID = muted
1181	s.Tool.JobDescription = subtle
1182
1183	// Agent task styles
1184	s.Tool.AgentTaskTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(blueLight).Foreground(white)
1185	s.Tool.AgentPrompt = muted
1186
1187	// Agentic fetch styles
1188	s.Tool.AgenticFetchPromptTag = base.Bold(true).Padding(0, 1).MarginLeft(2).Background(green).Foreground(border)
1189
1190	// Todo styles
1191	s.Tool.TodoRatio = base.Foreground(blueDark)
1192	s.Tool.TodoCompletedIcon = base.Foreground(green)
1193	s.Tool.TodoInProgressIcon = base.Foreground(greenDark)
1194	s.Tool.TodoPendingIcon = base.Foreground(fgMuted)
1195	s.Tool.TodoStatusNote = lipgloss.NewStyle().Foreground(fgSubtle)
1196	s.Tool.TodoItem = lipgloss.NewStyle().Foreground(fgBase)
1197	s.Tool.TodoJustStarted = lipgloss.NewStyle().Foreground(fgBase)
1198
1199	// MCP styles
1200	s.Tool.MCPName = base.Foreground(blue)
1201	s.Tool.MCPToolName = base.Foreground(blueDark)
1202	s.Tool.MCPArrow = base.Foreground(blue).SetString(ArrowRightIcon)
1203
1204	// Loading indicators for images, skills
1205	s.Tool.ResourceLoadedText = base.Foreground(green)
1206	s.Tool.ResourceLoadedIndicator = base.Foreground(greenDark)
1207	s.Tool.ResourceName = base
1208	s.Tool.MediaType = base
1209	s.Tool.ResourceSize = base.Foreground(fgMuted)
1210
1211	// Tool-call action verbs and result-list styling.
1212	s.Tool.ActionCreate = lipgloss.NewStyle().Foreground(greenLight)
1213	s.Tool.ActionDestroy = lipgloss.NewStyle().Foreground(red)
1214	s.Tool.ResultEmpty = lipgloss.NewStyle().Foreground(fgSubtle)
1215	s.Tool.ResultTruncation = lipgloss.NewStyle().Foreground(fgSubtle)
1216	s.Tool.ResultItemName = lipgloss.NewStyle().Foreground(fgBase)
1217	s.Tool.ResultItemDesc = lipgloss.NewStyle().Foreground(fgSubtle)
1218
1219	// Buttons
1220	s.Button.Focused = lipgloss.NewStyle().Foreground(white).Background(secondary)
1221	s.Button.Blurred = lipgloss.NewStyle().Foreground(fgBase).Background(bgSubtle)
1222
1223	// Editor
1224	s.Editor.PromptNormalFocused = lipgloss.NewStyle().Foreground(greenDark).SetString("::: ")
1225	s.Editor.PromptNormalBlurred = s.Editor.PromptNormalFocused.Foreground(fgMuted)
1226	s.Editor.PromptYoloIconFocused = lipgloss.NewStyle().MarginRight(1).Foreground(charmtone.Oyster).Background(charmtone.Citron).Bold(true).SetString(" ! ")
1227	s.Editor.PromptYoloIconBlurred = s.Editor.PromptYoloIconFocused.Foreground(charmtone.Pepper).Background(charmtone.Squid)
1228	s.Editor.PromptYoloDotsFocused = lipgloss.NewStyle().MarginRight(1).Foreground(charmtone.Zest).SetString(":::")
1229	s.Editor.PromptYoloDotsBlurred = s.Editor.PromptYoloDotsFocused.Foreground(charmtone.Squid)
1230
1231	s.Radio.On = lipgloss.NewStyle().Foreground(fgHalfMuted).SetString(RadioOn)
1232	s.Radio.Off = lipgloss.NewStyle().Foreground(fgHalfMuted).SetString(RadioOff)
1233	s.Radio.Label = lipgloss.NewStyle().Foreground(fgHalfMuted)
1234
1235	// Logo
1236	s.Logo.FieldColor = primary
1237	s.Logo.TitleColorA = secondary
1238	s.Logo.TitleColorB = primary
1239	s.Logo.CharmColor = secondary
1240	s.Logo.VersionColor = primary
1241	s.Logo.SmallCharm = lipgloss.NewStyle().Foreground(secondary)
1242	s.Logo.SmallDiagonals = lipgloss.NewStyle().Foreground(primary)
1243	s.Logo.GradCanvas = lipgloss.NewStyle()
1244	s.Logo.SmallGradFromColor = secondary
1245	s.Logo.SmallGradToColor = primary
1246
1247	// Section
1248	s.Section.Title = subtle
1249	s.Section.Line = base.Foreground(charmtone.Charcoal)
1250
1251	// Initialize
1252	s.Initialize.Header = base
1253	s.Initialize.Content = muted
1254	s.Initialize.Accent = base.Foreground(greenDark)
1255
1256	// ResourceGroup (LSP/MCP/skills sidebar lists).
1257	s.Resource.Heading = lipgloss.NewStyle().Foreground(charmtone.Oyster)
1258	s.Resource.Name = lipgloss.NewStyle().Foreground(charmtone.Squid)
1259	s.Resource.StatusText = lipgloss.NewStyle().Foreground(charmtone.Oyster)
1260	s.Resource.OfflineIcon = lipgloss.NewStyle().Foreground(charmtone.Iron).SetString("●")
1261	s.Resource.BusyIcon = s.Resource.OfflineIcon.Foreground(charmtone.Citron)
1262	s.Resource.ErrorIcon = s.Resource.OfflineIcon.Foreground(charmtone.Coral)
1263	s.Resource.OnlineIcon = s.Resource.OfflineIcon.Foreground(charmtone.Guac)
1264	s.Resource.DisabledIcon = lipgloss.NewStyle().Foreground(fgMuted).SetString("●")
1265	s.Resource.AdditionalText = lipgloss.NewStyle().Foreground(charmtone.Oyster)
1266	s.Resource.CapabilityCount = lipgloss.NewStyle().Foreground(fgSubtle)
1267	s.Resource.RowTitleBase = lipgloss.NewStyle().Foreground(fgBase)
1268	s.Resource.RowDescBase = lipgloss.NewStyle().Foreground(fgBase)
1269	s.Resource.DefaultTitleFg = fgMuted
1270	s.Resource.DefaultDescFg = fgSubtle
1271
1272	// LSP
1273	s.LSP.ErrorDiagnostic = base.Foreground(redDark)
1274	s.LSP.WarningDiagnostic = base.Foreground(warning)
1275	s.LSP.HintDiagnostic = base.Foreground(fgHalfMuted)
1276	s.LSP.InfoDiagnostic = base.Foreground(info)
1277
1278	// Files
1279	s.Files.Path = lipgloss.NewStyle().Foreground(fgMuted)
1280	s.Files.Additions = lipgloss.NewStyle().Foreground(greenDark)
1281	s.Files.Deletions = lipgloss.NewStyle().Foreground(redDark)
1282	s.Files.SectionTitle = lipgloss.NewStyle().Foreground(fgSubtle)
1283	s.Files.EmptyMessage = lipgloss.NewStyle().Foreground(fgSubtle)
1284	s.Files.TruncationHint = lipgloss.NewStyle().Foreground(fgSubtle)
1285
1286	// Sidebar
1287	s.Sidebar.SessionTitle = lipgloss.NewStyle().Foreground(fgMuted)
1288	s.Sidebar.WorkingDir = lipgloss.NewStyle().Foreground(fgMuted)
1289
1290	// ModelInfo
1291	s.ModelInfo.Icon = lipgloss.NewStyle().Foreground(fgSubtle)
1292	s.ModelInfo.Name = lipgloss.NewStyle().Foreground(fgBase)
1293	s.ModelInfo.Provider = lipgloss.NewStyle().Foreground(fgMuted)
1294	s.ModelInfo.ProviderFallback = lipgloss.NewStyle().Foreground(fgMuted).PaddingLeft(2)
1295	s.ModelInfo.Reasoning = lipgloss.NewStyle().Foreground(fgSubtle).PaddingLeft(2)
1296	s.ModelInfo.TokenCount = lipgloss.NewStyle().Foreground(fgSubtle)
1297	s.ModelInfo.TokenPercentage = lipgloss.NewStyle().Foreground(fgMuted)
1298	s.ModelInfo.Cost = lipgloss.NewStyle().Foreground(fgMuted)
1299
1300	// ResourceGroup
1301	s.Resource.DefaultTitleFg = fgMuted
1302	s.Resource.DefaultDescFg = fgSubtle
1303
1304	// Chat
1305	messageFocussedBorder := lipgloss.Border{
1306		Left: "β–Œ",
1307	}
1308
1309	s.Messages.NoContent = lipgloss.NewStyle().Foreground(fgBase)
1310	s.Messages.UserBlurred = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
1311		BorderForeground(primary).BorderStyle(normalBorder)
1312	s.Messages.UserFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
1313		BorderForeground(primary).BorderStyle(messageFocussedBorder)
1314	s.Messages.AssistantBlurred = s.Messages.NoContent.PaddingLeft(2)
1315	s.Messages.AssistantFocused = s.Messages.NoContent.PaddingLeft(1).BorderLeft(true).
1316		BorderForeground(greenDark).BorderStyle(messageFocussedBorder)
1317	s.Messages.Thinking = lipgloss.NewStyle().MaxHeight(10)
1318	s.Messages.ErrorTag = lipgloss.NewStyle().Padding(0, 1).
1319		Background(red).Foreground(white)
1320	s.Messages.ErrorTitle = lipgloss.NewStyle().Foreground(fgHalfMuted)
1321	s.Messages.ErrorDetails = lipgloss.NewStyle().Foreground(fgSubtle)
1322
1323	// Message item styles
1324	s.Messages.ToolCallFocused = muted.PaddingLeft(1).
1325		BorderStyle(messageFocussedBorder).
1326		BorderLeft(true).
1327		BorderForeground(greenDark)
1328	s.Messages.ToolCallBlurred = muted.PaddingLeft(2)
1329	// No padding or border for compact tool calls within messages
1330	s.Messages.ToolCallCompact = muted
1331	s.Messages.SectionHeader = base.PaddingLeft(2)
1332	s.Messages.AssistantInfoIcon = subtle
1333	s.Messages.AssistantInfoModel = muted
1334	s.Messages.AssistantInfoProvider = subtle
1335	s.Messages.AssistantInfoDuration = subtle
1336	s.Messages.AssistantCanceled = lipgloss.NewStyle().Foreground(fgBase).Italic(true)
1337
1338	// Thinking section styles
1339	s.Messages.ThinkingBox = subtle.Background(bgBaseLighter)
1340	s.Messages.ThinkingTruncationHint = muted
1341	s.Messages.ThinkingFooterTitle = muted
1342	s.Messages.ThinkingFooterDuration = subtle
1343
1344	// Text selection.
1345	s.TextSelection = lipgloss.NewStyle().Foreground(charmtone.Salt).Background(charmtone.Charple)
1346
1347	// Dialog styles
1348	s.Dialog.Title = base.Padding(0, 1).Foreground(primary)
1349	s.Dialog.TitleText = base.Foreground(primary)
1350	s.Dialog.TitleError = base.Foreground(red)
1351	s.Dialog.TitleAccent = base.Foreground(green).Bold(true)
1352	s.Dialog.TitleLineBase = lipgloss.NewStyle()
1353	s.Dialog.TitleGradFromColor = primary
1354	s.Dialog.TitleGradToColor = secondary
1355
1356	// Dialog.ListItem (commands, reasoning, models)
1357	s.Dialog.ListItem.InfoBlurred = lipgloss.NewStyle().Foreground(fgBase)
1358	s.Dialog.ListItem.InfoFocused = lipgloss.NewStyle().Foreground(fgBase)
1359
1360	// Dialog.Models
1361	s.Dialog.Models.ConfiguredText = lipgloss.NewStyle().Foreground(fgSubtle)
1362
1363	// Dialog.Permissions
1364	s.Dialog.Permissions.KeyText = lipgloss.NewStyle().Foreground(fgMuted)
1365	s.Dialog.Permissions.ValueText = lipgloss.NewStyle().Foreground(fgBase)
1366	s.Dialog.Permissions.ParamsBg = bgSubtle
1367
1368	// Dialog.Quit
1369	s.Dialog.Quit.Content = lipgloss.NewStyle().Foreground(fgBase)
1370	s.Dialog.Quit.Frame = lipgloss.NewStyle().BorderForeground(borderFocus).Border(lipgloss.RoundedBorder()).Padding(1, 2)
1371	s.Dialog.View = base.Border(lipgloss.RoundedBorder()).BorderForeground(borderFocus)
1372	s.Dialog.PrimaryText = base.Padding(0, 1).Foreground(primary)
1373	s.Dialog.SecondaryText = base.Padding(0, 1).Foreground(fgSubtle)
1374	s.Dialog.HelpView = base.Padding(0, 1).AlignHorizontal(lipgloss.Left)
1375	s.Dialog.Help.ShortKey = base.Foreground(fgMuted)
1376	s.Dialog.Help.ShortDesc = base.Foreground(fgSubtle)
1377	s.Dialog.Help.ShortSeparator = base.Foreground(border)
1378	s.Dialog.Help.Ellipsis = base.Foreground(border)
1379	s.Dialog.Help.FullKey = base.Foreground(fgMuted)
1380	s.Dialog.Help.FullDesc = base.Foreground(fgSubtle)
1381	s.Dialog.Help.FullSeparator = base.Foreground(border)
1382	s.Dialog.NormalItem = base.Padding(0, 1).Foreground(fgBase)
1383	s.Dialog.SelectedItem = base.Padding(0, 1).Background(primary).Foreground(fgBase)
1384	s.Dialog.InputPrompt = base.Margin(1, 1)
1385
1386	s.Dialog.List = base.Margin(0, 0, 1, 0)
1387	s.Dialog.ContentPanel = base.Background(bgSubtle).Foreground(fgBase).Padding(1, 2)
1388	s.Dialog.Spinner = base.Foreground(secondary)
1389	s.Dialog.ScrollbarThumb = base.Foreground(secondary)
1390	s.Dialog.ScrollbarTrack = base.Foreground(border)
1391
1392	s.Dialog.ImagePreview = lipgloss.NewStyle().Padding(0, 1).Foreground(fgSubtle)
1393
1394	// API key input dialog
1395	s.Dialog.APIKey.Spinner = base.Foreground(green)
1396
1397	// OAuth dialog
1398	s.Dialog.OAuth.Spinner = base.Foreground(greenLight)
1399	s.Dialog.OAuth.Instructions = lipgloss.NewStyle().Foreground(white)
1400	s.Dialog.OAuth.UserCode = lipgloss.NewStyle().Bold(true).Foreground(white)
1401	s.Dialog.OAuth.Success = lipgloss.NewStyle().Foreground(greenLight)
1402	s.Dialog.OAuth.Link = lipgloss.NewStyle().Foreground(greenDark).Underline(true)
1403	s.Dialog.OAuth.Enter = lipgloss.NewStyle().Foreground(primary)
1404	s.Dialog.OAuth.ErrorText = lipgloss.NewStyle().Foreground(error)
1405	s.Dialog.OAuth.StatusText = lipgloss.NewStyle().Foreground(fgMuted)
1406	s.Dialog.OAuth.UserCodeBg = bgBaseLighter
1407
1408	s.Dialog.Arguments.Content = base.Padding(1)
1409	s.Dialog.Arguments.Description = base.MarginBottom(1).MaxHeight(3)
1410	s.Dialog.Arguments.InputLabelBlurred = base.Foreground(fgMuted)
1411	s.Dialog.Arguments.InputLabelFocused = base.Bold(true)
1412	s.Dialog.Arguments.InputRequiredMarkBlurred = base.Foreground(fgMuted).SetString("*")
1413	s.Dialog.Arguments.InputRequiredMarkFocused = base.Foreground(primary).Bold(true).SetString("*")
1414
1415	s.Dialog.Sessions.DeletingTitle = s.Dialog.Title.Foreground(red)
1416	s.Dialog.Sessions.DeletingView = s.Dialog.View.BorderForeground(red)
1417	s.Dialog.Sessions.DeletingMessage = base.Padding(1)
1418	s.Dialog.Sessions.DeletingTitleGradientFromColor = red
1419	s.Dialog.Sessions.DeletingTitleGradientToColor = primary
1420	s.Dialog.Sessions.DeletingItemBlurred = s.Dialog.NormalItem.Foreground(fgSubtle)
1421	s.Dialog.Sessions.DeletingItemFocused = s.Dialog.SelectedItem.Background(red).Foreground(charmtone.Butter)
1422
1423	s.Dialog.Sessions.RenamingingTitle = s.Dialog.Title.Foreground(charmtone.Zest)
1424	s.Dialog.Sessions.RenamingView = s.Dialog.View.BorderForeground(charmtone.Zest)
1425	s.Dialog.Sessions.RenamingingMessage = base.Padding(1)
1426	s.Dialog.Sessions.RenamingTitleGradientFromColor = charmtone.Zest
1427	s.Dialog.Sessions.RenamingTitleGradientToColor = charmtone.Bok
1428	s.Dialog.Sessions.RenamingItemBlurred = s.Dialog.NormalItem.Foreground(fgSubtle)
1429	s.Dialog.Sessions.RenamingingItemFocused = s.Dialog.SelectedItem.UnsetBackground().UnsetForeground()
1430	s.Dialog.Sessions.RenamingPlaceholder = base.Foreground(charmtone.Squid)
1431	s.Dialog.Sessions.InfoBlurred = lipgloss.NewStyle().Foreground(fgSubtle)
1432	s.Dialog.Sessions.InfoFocused = lipgloss.NewStyle().Foreground(fgBase)
1433
1434	s.Status.Help = lipgloss.NewStyle().Padding(0, 1)
1435	s.Status.SuccessIndicator = base.Foreground(bgSubtle).Background(green).Padding(0, 1).Bold(true).SetString("OKAY!")
1436	s.Status.InfoIndicator = s.Status.SuccessIndicator
1437	s.Status.UpdateIndicator = s.Status.SuccessIndicator.SetString("HEY!")
1438	s.Status.WarnIndicator = s.Status.SuccessIndicator.Foreground(bgOverlay).Background(yellow).SetString("WARNING")
1439	s.Status.ErrorIndicator = s.Status.SuccessIndicator.Foreground(bgBase).Background(red).SetString("ERROR")
1440	s.Status.SuccessMessage = base.Foreground(bgSubtle).Background(greenDark).Padding(0, 1)
1441	s.Status.InfoMessage = s.Status.SuccessMessage
1442	s.Status.UpdateMessage = s.Status.SuccessMessage
1443	s.Status.WarnMessage = s.Status.SuccessMessage.Foreground(bgOverlay).Background(warning)
1444	s.Status.ErrorMessage = s.Status.SuccessMessage.Foreground(white).Background(redDark)
1445
1446	// Completions styles
1447	s.Completions.Normal = base.Background(bgSubtle).Foreground(fgBase)
1448	s.Completions.Focused = base.Background(primary).Foreground(white)
1449	s.Completions.Match = base.Underline(true)
1450
1451	// Attachments styles
1452	attachmentIconStyle := base.Foreground(bgSubtle).Background(green).Padding(0, 1)
1453	s.Attachments.Image = attachmentIconStyle.SetString(ImageIcon)
1454	s.Attachments.Text = attachmentIconStyle.SetString(TextIcon)
1455	s.Attachments.Normal = base.Padding(0, 1).MarginRight(1).Background(fgMuted).Foreground(fgBase)
1456	s.Attachments.Deleting = base.Padding(0, 1).Bold(true).Background(red).Foreground(fgBase)
1457
1458	// Pills styles
1459	s.Pills.Base = base.Padding(0, 1)
1460	s.Pills.Focused = base.Padding(0, 1).BorderStyle(lipgloss.RoundedBorder()).BorderForeground(bgOverlay)
1461	s.Pills.Blurred = base.Padding(0, 1).BorderStyle(lipgloss.HiddenBorder())
1462	s.Pills.QueueItemPrefix = lipgloss.NewStyle().Foreground(fgMuted).SetString("  β€’")
1463	s.Pills.QueueItemText = lipgloss.NewStyle().Foreground(fgMuted)
1464	s.Pills.QueueLabel = lipgloss.NewStyle().Foreground(fgBase)
1465	s.Pills.QueueIconBase = lipgloss.NewStyle().Foreground(fgBase)
1466	s.Pills.QueueGradFromColor = redDark
1467	s.Pills.QueueGradToColor = secondary
1468	s.Pills.TodoLabel = lipgloss.NewStyle().Foreground(fgBase)
1469	s.Pills.TodoProgress = lipgloss.NewStyle().Foreground(fgMuted)
1470	s.Pills.TodoCurrentTask = lipgloss.NewStyle().Foreground(fgSubtle)
1471	s.Pills.TodoSpinner = lipgloss.NewStyle().Foreground(greenDark)
1472	s.Pills.HelpKey = lipgloss.NewStyle().Foreground(fgMuted)
1473	s.Pills.HelpText = lipgloss.NewStyle().Foreground(fgSubtle)
1474	s.Pills.Area = base
1475
1476	return s
1477}
1478
1479func chromaStyle(style ansi.StylePrimitive) string {
1480	var s strings.Builder
1481
1482	if style.Color != nil {
1483		s.WriteString(*style.Color)
1484	}
1485	if style.BackgroundColor != nil {
1486		if s.Len() > 0 {
1487			s.WriteString(" ")
1488		}
1489		s.WriteString("bg:")
1490		s.WriteString(*style.BackgroundColor)
1491	}
1492	if style.Italic != nil && *style.Italic {
1493		if s.Len() > 0 {
1494			s.WriteString(" ")
1495		}
1496		s.WriteString("italic")
1497	}
1498	if style.Bold != nil && *style.Bold {
1499		if s.Len() > 0 {
1500			s.WriteString(" ")
1501		}
1502		s.WriteString("bold")
1503	}
1504	if style.Underline != nil && *style.Underline {
1505		if s.Len() > 0 {
1506			s.WriteString(" ")
1507		}
1508		s.WriteString("underline")
1509	}
1510
1511	return s.String()
1512}