# Bit.Blow theme Every colour of the flow - canvas, nodes, edges, handles and the add-ons drawn over them - is a CSS custom property on `.bit-blow`, read out of the shipped `bit-blow.css` below. Override them from your own stylesheet, loaded after `_content/Bit.Blow/bit-blow.css`, without touching a single library selector: ```css .bit-blow { --bit-blow-node-selected: #7c3aed; --bit-blow-edge-selected: #7c3aed; } .bit-blow { --bit-blow-dark-accent: #a78bfa; } ``` `BlowCanvas.ColorMode` picks the palette: `Light` (the default) uses the values below, `Dark` adds `bit-blow-dark` to the canvas and `System` adds `bit-blow-system`, which turns dark under `prefers-color-scheme: dark`. Dark mode does not have values of its own on the palette properties: it copies the `--bit-blow-dark-*` properties over them - so to restyle dark mode, override the property named in the Dark column, not the palette property. Call `GetBlowTheme(property: "...")` for one property in full: every rule that paints with it, and the component parameters that default to it. ## Palette | Property | Light | Dark | Paints | | --- | --- | --- | --- | | `--bit-blow-bg` | `#fafafa` | `#1a1a1a` via `--bit-blow-dark-bg` | `.bit-blow` | | `--bit-blow-node-bg` | `#ffffff` | `#2b2b2b` via `--bit-blow-dark-node-bg` | `.bit-blow-node` | | `--bit-blow-node-border` | `#1a192b` | `#555555` via `--bit-blow-dark-node-border` | `.bit-blow-node` | | `--bit-blow-node-input-border` | `#0041d0` | `#4d8bff` via `--bit-blow-dark-node-input-border` | `.bit-blow-node-input` | | `--bit-blow-node-output-border` | `#ff0072` | `#ff6aa8` via `--bit-blow-dark-node-output-border` | `.bit-blow-node-output` | | `--bit-blow-node-color` | `#222` | `#e6e6e6` via `--bit-blow-dark-node-color` | `.bit-blow-node`, `.bit-blow.bit-blow-dark`, `.bit-blow.bit-blow-system` | | `--bit-blow-node-selected` | `#2563eb` | `#60a5fa` via `--bit-blow-dark-accent` | `.bit-blow:focus-visible`, `.bit-blow-node.selected`, `.bit-blow-minimap-node.selected` +5 more | | `--bit-blow-edge-stroke` | `#b1b1b7` | `#6b6b6b` via `--bit-blow-dark-edge-stroke` | `BlowBaseEdge.Stroke`, `BlowEdgeRenderer` | | `--bit-blow-edge-selected` | `#2563eb` | `#60a5fa` via `--bit-blow-dark-accent` | `.bit-blow-edge.selected .bit-blow-edge-path`, `.bit-blow-edge:focus-visible .bit-blow-edge-path`, `.bit-blow-edge-reconnect` +1 more | | `--bit-blow-connection-stroke` | `#2563eb` | `#60a5fa` via `--bit-blow-dark-accent` | `.bit-blow-handle-connectingfrom, .bit-blow-handle-connectingfrom:hover`, `BlowCanvas` | | `--bit-blow-handle-bg` | `#1a192b` | `#cbd5e1` via `--bit-blow-dark-handle-bg` | `.bit-blow-handle` | | `--bit-blow-handle-valid` | `#22c55e` | same | `.bit-blow-handle.connectable:hover, .bit-blow-handle-valid` | | `--bit-blow-handle-invalid` | `#ef4444` | same | `.bit-blow-handle-invalid, .bit-blow-handle-invalid:hover` | > The add-ons - controls, minimap, toolbars, labels, the attribution badge - are chrome drawn over the flow rather than part of the graph, and they all share one palette. Naming it here is what lets a colour mode restyle the whole component and not just its canvas. | Property | Light | Dark | Paints | | --- | --- | --- | --- | | `--bit-blow-surface` | `#ffffff` | `#2b2b2b` via `--bit-blow-dark-surface` | `.bit-blow-edge-label-bg`, `.bit-blow-handle`, `.bit-blow-controls-button` +5 more | | `--bit-blow-surface-hover` | `#f4f4f4` | `#3a3a3a` via `--bit-blow-dark-surface-hover` | `.bit-blow-controls-button:hover` | | `--bit-blow-surface-muted` | `#f4f4f5` | `#3a3a3a` via `--bit-blow-dark-surface-muted` | `.bit-blow-node-toolbar button` | | `--bit-blow-surface-muted-hover` | `#e4e4e7` | `#4a4a4a` via `--bit-blow-dark-surface-muted-hover` | `.bit-blow-node-toolbar button:hover` | | `--bit-blow-surface-translucent` | `rgba(255, 255, 255, 0.9)` | `rgba(32, 32, 32, 0.9)` via `--bit-blow-dark-surface-translucent` | `.bit-blow-minimap`, `.bit-blow-attribution` | | `--bit-blow-border` | `#e2e2e2` | `#454545` via `--bit-blow-dark-border` | `.bit-blow-minimap`, `.bit-blow-node-toolbar`, `.bit-blow-edge-toolbar` | | `--bit-blow-border-subtle` | `#eeeeee` | `#383838` via `--bit-blow-dark-border-subtle` | `.bit-blow-controls-button`, `.bit-blow-controls.horizontal .bit-blow-controls-button` | | `--bit-blow-text` | `#333333` | `#e6e6e6` via `--bit-blow-dark-text` | `.bit-blow-edge-label`, `.bit-blow-controls-button`, `.bit-blow-node-toolbar button` +2 more | | `--bit-blow-text-muted` | `#6b7280` | `#9ca3af` via `--bit-blow-dark-text-muted` | `.bit-blow-node-group .bit-blow-node-label`, `.bit-blow-attribution` | | `--bit-blow-shadow` | `rgba(0, 0, 0, 0.15)` | `rgba(0, 0, 0, 0.5)` via `--bit-blow-dark-shadow` | `.bit-blow-node`, `.bit-blow-controls`, `.bit-blow-node-toolbar` +1 more | | `--bit-blow-group-bg` | `rgba(120, 120, 160, 0.08)` | `rgba(160, 170, 210, 0.07)` via `--bit-blow-dark-group-bg` | `.bit-blow-node-group` | | `--bit-blow-group-border` | `#9aa0b5` | `#5b6070` via `--bit-blow-dark-group-border` | `.bit-blow-node-group` | | `--bit-blow-background-pattern` | `#aaaaaa` | `#4a4a4a` via `--bit-blow-dark-background-pattern` | `BlowBackground` | | `--bit-blow-minimap-node` | `#e2e2e2` | `#4a4a4a` via `--bit-blow-dark-minimap-node` | `BlowMiniMap.NodeColor` | | `--bit-blow-minimap-mask` | `rgba(120, 120, 120, 0.25)` | `rgba(0, 0, 0, 0.45)` via `--bit-blow-dark-minimap-mask` | `BlowMiniMap.MaskColor` | ## Dark palette Dark color mode. Applied explicitly (.bit-blow-dark) or via OS preference (.bit-blow-system + prefers-color-scheme). The palette is written once, on the flow root, as a second set of properties; the two rules below are pure plumbing that copies it over the light one. CSS has no way to share a block of declarations between a class and a media query, and duplicating twenty colours in two places is exactly how a theme drifts out of step with itself. Copied over the palette by `.bit-blow.bit-blow-dark`, and by `.bit-blow.bit-blow-system` under `prefers-color-scheme: dark`. | Property | Value | Copied over | | --- | --- | --- | | `--bit-blow-dark-bg` | `#1a1a1a` | `--bit-blow-bg` | | `--bit-blow-dark-node-bg` | `#2b2b2b` | `--bit-blow-node-bg` | | `--bit-blow-dark-node-border` | `#555555` | `--bit-blow-node-border` | | `--bit-blow-dark-node-input-border` | `#4d8bff` | `--bit-blow-node-input-border` | | `--bit-blow-dark-node-output-border` | `#ff6aa8` | `--bit-blow-node-output-border` | | `--bit-blow-dark-node-color` | `#e6e6e6` | `--bit-blow-node-color` | | `--bit-blow-dark-accent` | `#60a5fa` | `--bit-blow-node-selected`, `--bit-blow-edge-selected`, `--bit-blow-connection-stroke` | | `--bit-blow-dark-edge-stroke` | `#6b6b6b` | `--bit-blow-edge-stroke` | | `--bit-blow-dark-handle-bg` | `#cbd5e1` | `--bit-blow-handle-bg` | | `--bit-blow-dark-surface` | `#2b2b2b` | `--bit-blow-surface` | | `--bit-blow-dark-surface-hover` | `#3a3a3a` | `--bit-blow-surface-hover` | | `--bit-blow-dark-surface-muted` | `#3a3a3a` | `--bit-blow-surface-muted` | | `--bit-blow-dark-surface-muted-hover` | `#4a4a4a` | `--bit-blow-surface-muted-hover` | | `--bit-blow-dark-surface-translucent` | `rgba(32, 32, 32, 0.9)` | `--bit-blow-surface-translucent` | | `--bit-blow-dark-border` | `#454545` | `--bit-blow-border` | | `--bit-blow-dark-border-subtle` | `#383838` | `--bit-blow-border-subtle` | | `--bit-blow-dark-text` | `#e6e6e6` | `--bit-blow-text` | | `--bit-blow-dark-text-muted` | `#9ca3af` | `--bit-blow-text-muted` | | `--bit-blow-dark-shadow` | `rgba(0, 0, 0, 0.5)` | `--bit-blow-shadow` | | `--bit-blow-dark-group-bg` | `rgba(160, 170, 210, 0.07)` | `--bit-blow-group-bg` | | `--bit-blow-dark-group-border` | `#5b6070` | `--bit-blow-group-border` | | `--bit-blow-dark-background-pattern` | `#4a4a4a` | `--bit-blow-background-pattern` | | `--bit-blow-dark-minimap-node` | `#4a4a4a` | `--bit-blow-minimap-node` | | `--bit-blow-dark-minimap-mask` | `rgba(0, 0, 0, 0.45)` | `--bit-blow-minimap-mask` |