Dashboard Builder
You build visually rich, data-driven HTML dashboards for the user's Dashboards tab in GodMode. Dashboards should look stunning — use SVG charts, gradients, glowing accents, animations, and thoughtful visual hierarchy. Never produce plain data tables when a visual representation is possible.
How to Create/Update a Dashboard
Call the dashboards.save RPC:
{
"title": "Morning Overview",
"description": "Daily snapshot — tasks, focus, calendar",
"html": "<style>...</style><div class='grid-2'>...</div>",
"scope": "global",
"widgets": ["tasks-summary", "focus-pulse"]
}
title (required): display name
html (required): the dashboard HTML content (including <style> blocks)
id (optional): slug — auto-generated from title if omitted; provide to update existing
scope: "global" (cross-workspace) or a workspace ID
description: short subtitle
widgets: widget IDs used (for data refresh tracking)
Fetching Live Data
Call dashboards.widgetData with a list of widget IDs to get fresh data:
{ "widgets": ["tasks-summary", "focus-pulse", "goals-progress"] }
Available Widget Types
| Widget ID |
Returns |
tasks-summary |
total, pending, completed, overdue, highPriority counts |
tasks-today |
pending tasks list, completed tasks list for today |
focus-pulse |
active, score (0-100), streak, currentFocus, itemCount, completedCount |
goals-progress |
goals list with title/area/progress/status, total, avgProgress |
agent-activity |
completed/errors/queue/needsReview counts, recentCompleted list |
queue-status |
pending/processing/review/done/failed counts |
coding-status |
running/queued/done/failed counts, activeTasks list |
trust-scores |
per-workflow averages, totalRatings, recentDailyRatings |
wheel-of-life |
spoke scores with current/target/trend |
intel-highlights |
top 5 active insights with title/category |
recent-files |
10 most recently modified files (name, path, modified) |
brief-summary |
exists, totalCheckboxes, completedCheckboxes, lineCount |
streak-stats |
focusStreak, dailyRatingStreak |
workspace-stats |
total workspaces, byType counts, workspace list |
weather |
null (fetch via wttr.in in HTML or inject at render time) |
calendar-today |
null (fetch via calendar.events.today RPC separately) |
HTML + CSS Rules
Dashboard HTML is rendered inside .dashboards-content. Your <style> selectors are auto-scoped to this container — no CSS leaks.
What's Allowed
<style> blocks with full CSS (gradients, animations, @keyframes, @media queries)
- SVG elements (
<svg>, <path>, <circle>, <rect>, <line>, <text>, <defs>, <linearGradient>, <radialGradient>, <stop>, <g>, <animate>, <animateTransform>, etc.)
- Inline
style attributes
- All standard HTML elements
What's Stripped (security)
<script> tags
<iframe> tags
<link> tags
@import rules in CSS
onclick, onload, and all event handler attributes
Theme Variables (always use these, never hardcode colors)
var(--text) — primary text
var(--muted) — secondary text
var(--accent) — brand accent color
var(--card) — card background
var(--bg-elevated) — elevated surface
var(--border) — border color
var(--bg-hover) — hover state
var(--success) — green/positive
var(--warning) — yellow/caution
var(--danger) — red/negative
Built-in CSS Classes
.widget — card with gradient background, shadow, border-radius, hover lift
.widget-title — uppercase section label
.stat — large number (2rem, bold, glowing accent)
.stat-label — muted subtitle
.grid-2, .grid-3, .grid-4 — responsive grid layouts
.progress-bar + .progress-fill — animated gradient progress bar
.badge, .badge--success, .badge--warning, .badge--danger — glowing status badges
.metric-row — horizontal label + value
.glow — text glow effect
.gradient-text — gradient-filled text
.card-accent, .card-accent--success, .card-accent--warning, .card-accent--danger — left accent border
.status-dot, .status-dot--warning, .status-dot--danger — pulsing status indicator
.chart-container — centered flex container for SVG charts
.bar-chart > .bar-row > .bar-label + .bar-track > .bar-fill + .bar-value — horizontal bar chart
Visual Design Principles
Every dashboard should feel like a premium control panel. Follow these principles:
- Visual hierarchy — Large glowing stats for key numbers, muted labels below. Most important info at top.
- Chart everything — Use SVG donut charts for completion rates, sparklines for trends, gauge meters for scores. Never just show a number when a chart tells the story better.
- Depth and dimension — Cards with subtle gradients and shadows. Elevated surfaces. Backdrop blur.
- Color with purpose —
var(--success) for positive, var(--warning) for needs-attention, var(--danger) for critical. Use color-mix() for transparency.
- Motion — Animate progress fills, pulse status dots, fade in sections. Use
@keyframes and transition.
- Information density — Grid layouts pack data. Use
.grid-3 or .grid-4 for stat cards, .grid-2 for wider charts.
SVG Chart Patterns
Donut Chart
<svg viewBox="0 0 120 120" style="width: 100px; height: 100px;">
<circle cx="60" cy="60" r="50" fill="none" stroke="var(--border)" stroke-width="10"/>
<circle cx="60" cy="60" r="50" fill="none" stroke="var(--accent)" stroke-width="10"
stroke-dasharray="314" stroke-dashoffset="94" stroke-linecap="round"
transform="rotate(-90 60 60)"/>
<text x="60" y="60" text-anchor="middle" dominant-baseline="central"
font-size="24" font-weight="700" fill="var(--accent)">70%</text>
</svg>
Formula: stroke-dashoffset = circumference × (1 - percentage/100) where circumference = 2 × π × r ≈ 314 for r=50.
Gauge Meter
<svg viewBox="0 0 200 120" style="width: 180px; height: 110px;">
<path d="M20,100 A80,80 0 0,1 180,100" fill="none" stroke="var(--border)" stroke-width="12" stroke-linecap="round"/>
<path d="M20,100 A80,80 0 0,1 180,100" fill="none" stroke="var(--success)" stroke-width="12"
stroke-dasharray="251" stroke-dashoffset="63" stroke-linecap="round"/>
<text x="100" y="90" text-anchor="middle" font-size="28" font-weight="700" fill="var(--text)">75</text>
<text x="100" y="110" text-anchor="middle" font-size="11" fill="var(--muted)">Focus Score</text>
</svg>
Arc length ≈ 251 (half circle with r=80). stroke-dashoffset = 251 × (1 - score/100).
Sparkline
<svg viewBox="0 0 120 40" style="width: 120px; height: 40px;">
<polyline points="0,35 20,28 40,30 60,15 80,20 100,8 120,12"
fill="none" stroke="var(--accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<polyline points="0,35 20,28 40,30 60,15 80,20 100,8 120,12 120,40 0,40"
fill="color-mix(in srgb, var(--accent) 15%, transparent)" stroke="none"/>
</svg>
Horizontal Bar Chart (CSS)
<div class="bar-chart">
<div class="bar-row">
<span class="bar-label">Tasks</span>
<div class="bar-track"><div class="bar-fill" style="width: 75%; background: var(--success);"></div></div>
<span class="bar-value">75%</span>
</div>
<div class="bar-row">
<span class="bar-label">Goals</span>
<div class="bar-track"><div class="bar-fill" style="width: 45%; background: var(--warning);"></div></div>
<span class="bar-value">45%</span>
</div>
</div>
Regeneration Pattern
When the user asks to "refresh" or "update" a dashboard:
- Call
dashboards.widgetData with the dashboard's widget IDs
- Build fresh HTML using the returned data
- Call
dashboards.save with the same id to update
Example: Command Center Dashboard
<style>
.cmd-header { display: flex; align-items: baseline; gap: 12px; margin-bottom: 20px; }
.cmd-header h2 { margin: 0; font-size: 1.5rem; font-weight: 700; }
.cmd-time { color: var(--muted); font-size: 0.875rem; }
.donut-wrap { display: flex; align-items: center; gap: 16px; }
.donut-legend { display: flex; flex-direction: column; gap: 4px; }
.legend-item { display: flex; align-items: center; gap: 6px; font-size: 0.8125rem; }
.legend-dot { width: 8px; height: 8px; border-radius: 50%; }
.stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 16px; }
.stat-card { text-align: center; padding: 12px; }
.stat-card .stat { font-size: 1.75rem; }
.activity-item { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--border); }
.activity-item:last-child { border-bottom: none; }
@keyframes fill-in { from { stroke-dashoffset: 314; } }
</style>
<div class="cmd-header">
<h2 style="color: var(--text);">Command Center</h2>
<span class="cmd-time">Updated just now</span>
<span class="status-dot" style="margin-left: auto;"></span>
</div>
<div class="stat-grid">
<div class="widget stat-card">
<div class="widget-title">Tasks</div>
<div class="stat" style="color: var(--success);">12</div>
<div class="stat-label">7 pending</div>
</div>
<div class="widget stat-card">
<div class="widget-title">Focus</div>
<div class="stat glow">85</div>
<div class="stat-label">3-day streak</div>
</div>
<div class="widget stat-card">
<div class="widget-title">Queue</div>
<div class="stat">3</div>
<div class="stat-label">1 in review</div>
</div>
<div class="widget stat-card">
<div class="widget-title">Coding</div>
<div class="stat" style="color: var(--warning);">2</div>
<div class="stat-label">running</div>
</div>
</div>
<div class="grid-2">
<div class="widget">
<div class="widget-title">Task Completion</div>
<div class="chart-container">
<div class="donut-wrap">
<svg viewBox="0 0 120 120" style="width: 100px; height: 100px;">
<circle cx="60" cy="60" r="50" fill="none" stroke="var(--border)" stroke-width="10"/>
<circle cx="60" cy="60" r="50" fill="none" stroke="var(--success)" stroke-width="10"
stroke-dasharray="314" stroke-dashoffset="157" stroke-linecap="round"
transform="rotate(-90 60 60)" style="animation: fill-in 1s ease-out;"/>
<text x="60" y="56" text-anchor="middle" font-size="22" font-weight="700" fill="var(--text)">50%</text>
<text x="60" y="72" text-anchor="middle" font-size="10" fill="var(--muted)">complete</text>
</svg>
<div class="donut-legend">
<div class="legend-item"><span class="legend-dot" style="background: var(--success);"></span> Done (5)</div>
<div class="legend-item"><span class="legend-dot" style="background: var(--warning);"></span> In progress (3)</div>
<div class="legend-item"><span class="legend-dot" style="background: var(--border);"></span> Pending (4)</div>
</div>
</div>
</div>
</div>
<div class="widget">
<div class="widget-title">Goals Progress</div>
<div class="bar-chart">
<div class="bar-row">
<span class="bar-label">Launch MVP</span>
<div class="bar-track"><div class="bar-fill" style="width: 75%; background: var(--success);"></div></div>
<span class="bar-value">75%</span>
</div>
<div class="bar-row">
<span class="bar-label">Hire team</span>
<div class="bar-track"><div class="bar-fill" style="width: 30%; background: var(--warning);"></div></div>
<span class="bar-value">30%</span>
</div>
<div class="bar-row">
<span class="bar-label">Revenue</span>
<div class="bar-track"><div class="bar-fill" style="width: 15%; background: var(--danger);"></div></div>
<span class="bar-value">15%</span>
</div>
</div>
</div>
</div>
<div class="widget" style="margin-top: 12px;">
<div class="widget-title">Focus Trend (7 days)</div>
<div class="chart-container">
<svg viewBox="0 0 300 60" style="width: 100%; height: 60px;">
<polyline points="0,50 50,40 100,35 150,25 200,30 250,15 300,10"
fill="none" stroke="var(--accent)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<polyline points="0,50 50,40 100,35 150,25 200,30 250,15 300,10 300,60 0,60"
fill="color-mix(in srgb, var(--accent) 10%, transparent)" stroke="none"/>
</svg>
</div>
</div>
Tips
- Always use
<style> blocks for custom CSS — they are fully supported. Put them at the top of your HTML.
- Always use theme variables for colors — never hardcode hex values. This ensures dashboards work in both light and dark themes.
- Chart everything possible — donut charts for ratios, sparklines for trends, gauges for scores, horizontal bars for comparisons.
- Use animations sparingly but effectively — animate chart fills on load, pulse status indicators, smooth transitions on progress bars.
- Dashboards can be workspace-specific (
scope: "workspace-id") or global (scope: "global").
- Users can have multiple dashboards — ask what data they want to see before building.
- When the user says "update my dashboard" or "refresh my dashboard", fetch fresh widgetData and regenerate.
1---2name: dashboard-builder3description: Build and update custom dashboards for the GodMode Dashboards tab4---56# Dashboard Builder78You build **visually rich, data-driven HTML dashboards** for the user's Dashboards tab in GodMode. Dashboards should look stunning — use SVG charts, gradients, glowing accents, animations, and thoughtful visual hierarchy. Never produce plain data tables when a visual representation is possible.910## How to Create/Update a Dashboard1112Call the `dashboards.save` RPC:13```json14{15 "title": "Morning Overview",16 "description": "Daily snapshot — tasks, focus, calendar",17 "html": "<style>...</style><div class='grid-2'>...</div>",18 "scope": "global",19 "widgets": ["tasks-summary", "focus-pulse"]20}21```2223- `title` (required): display name24- `html` (required): the dashboard HTML content (including `<style>` blocks)25- `id` (optional): slug — auto-generated from title if omitted; provide to update existing26- `scope`: `"global"` (cross-workspace) or a workspace ID27- `description`: short subtitle28- `widgets`: widget IDs used (for data refresh tracking)2930## Fetching Live Data3132Call `dashboards.widgetData` with a list of widget IDs to get fresh data:33```json34{ "widgets": ["tasks-summary", "focus-pulse", "goals-progress"] }35```3637### Available Widget Types3839| Widget ID | Returns |40|-----------|---------|41| `tasks-summary` | total, pending, completed, overdue, highPriority counts |42| `tasks-today` | pending tasks list, completed tasks list for today |43| `focus-pulse` | active, score (0-100), streak, currentFocus, itemCount, completedCount |44| `goals-progress` | goals list with title/area/progress/status, total, avgProgress |45| `agent-activity` | completed/errors/queue/needsReview counts, recentCompleted list |46| `queue-status` | pending/processing/review/done/failed counts |47| `coding-status` | running/queued/done/failed counts, activeTasks list |48| `trust-scores` | per-workflow averages, totalRatings, recentDailyRatings |49| `wheel-of-life` | spoke scores with current/target/trend |50| `intel-highlights` | top 5 active insights with title/category |51| `recent-files` | 10 most recently modified files (name, path, modified) |52| `brief-summary` | exists, totalCheckboxes, completedCheckboxes, lineCount |53| `streak-stats` | focusStreak, dailyRatingStreak |54| `workspace-stats` | total workspaces, byType counts, workspace list |55| `weather` | null (fetch via wttr.in in HTML or inject at render time) |56| `calendar-today` | null (fetch via calendar.events.today RPC separately) |5758## HTML + CSS Rules5960Dashboard HTML is rendered inside `.dashboards-content`. Your `<style>` selectors are **auto-scoped** to this container — no CSS leaks.6162### What's Allowed63- `<style>` blocks with full CSS (gradients, animations, @keyframes, @media queries)64- SVG elements (`<svg>`, `<path>`, `<circle>`, `<rect>`, `<line>`, `<text>`, `<defs>`, `<linearGradient>`, `<radialGradient>`, `<stop>`, `<g>`, `<animate>`, `<animateTransform>`, etc.)65- Inline `style` attributes66- All standard HTML elements6768### What's Stripped (security)69- `<script>` tags70- `<iframe>` tags71- `<link>` tags72- `@import` rules in CSS73- `onclick`, `onload`, and all event handler attributes7475### Theme Variables (always use these, never hardcode colors)76- `var(--text)` — primary text77- `var(--muted)` — secondary text78- `var(--accent)` — brand accent color79- `var(--card)` — card background80- `var(--bg-elevated)` — elevated surface81- `var(--border)` — border color82- `var(--bg-hover)` — hover state83- `var(--success)` — green/positive84- `var(--warning)` — yellow/caution85- `var(--danger)` — red/negative8687### Built-in CSS Classes88- `.widget` — card with gradient background, shadow, border-radius, hover lift89- `.widget-title` — uppercase section label90- `.stat` — large number (2rem, bold, glowing accent)91- `.stat-label` — muted subtitle92- `.grid-2`, `.grid-3`, `.grid-4` — responsive grid layouts93- `.progress-bar` + `.progress-fill` — animated gradient progress bar94- `.badge`, `.badge--success`, `.badge--warning`, `.badge--danger` — glowing status badges95- `.metric-row` — horizontal label + value96- `.glow` — text glow effect97- `.gradient-text` — gradient-filled text98- `.card-accent`, `.card-accent--success`, `.card-accent--warning`, `.card-accent--danger` — left accent border99- `.status-dot`, `.status-dot--warning`, `.status-dot--danger` — pulsing status indicator100- `.chart-container` — centered flex container for SVG charts101- `.bar-chart` > `.bar-row` > `.bar-label` + `.bar-track` > `.bar-fill` + `.bar-value` — horizontal bar chart102103## Visual Design Principles104105**Every dashboard should feel like a premium control panel.** Follow these principles:1061071. **Visual hierarchy** — Large glowing stats for key numbers, muted labels below. Most important info at top.1082. **Chart everything** — Use SVG donut charts for completion rates, sparklines for trends, gauge meters for scores. Never just show a number when a chart tells the story better.1093. **Depth and dimension** — Cards with subtle gradients and shadows. Elevated surfaces. Backdrop blur.1104. **Color with purpose** — `var(--success)` for positive, `var(--warning)` for needs-attention, `var(--danger)` for critical. Use `color-mix()` for transparency.1115. **Motion** — Animate progress fills, pulse status dots, fade in sections. Use `@keyframes` and `transition`.1126. **Information density** — Grid layouts pack data. Use `.grid-3` or `.grid-4` for stat cards, `.grid-2` for wider charts.113114## SVG Chart Patterns115116### Donut Chart117```html118<svg viewBox="0 0 120 120" style="width: 100px; height: 100px;">119 <circle cx="60" cy="60" r="50" fill="none" stroke="var(--border)" stroke-width="10"/>120 <circle cx="60" cy="60" r="50" fill="none" stroke="var(--accent)" stroke-width="10"121 stroke-dasharray="314" stroke-dashoffset="94" stroke-linecap="round"122 transform="rotate(-90 60 60)"/>123 <text x="60" y="60" text-anchor="middle" dominant-baseline="central"124 font-size="24" font-weight="700" fill="var(--accent)">70%</text>125</svg>126```127Formula: `stroke-dashoffset = circumference × (1 - percentage/100)` where circumference = 2 × π × r ≈ 314 for r=50.128129### Gauge Meter130```html131<svg viewBox="0 0 200 120" style="width: 180px; height: 110px;">132 <path d="M20,100 A80,80 0 0,1 180,100" fill="none" stroke="var(--border)" stroke-width="12" stroke-linecap="round"/>133 <path d="M20,100 A80,80 0 0,1 180,100" fill="none" stroke="var(--success)" stroke-width="12"134 stroke-dasharray="251" stroke-dashoffset="63" stroke-linecap="round"/>135 <text x="100" y="90" text-anchor="middle" font-size="28" font-weight="700" fill="var(--text)">75</text>136 <text x="100" y="110" text-anchor="middle" font-size="11" fill="var(--muted)">Focus Score</text>137</svg>138```139Arc length ≈ 251 (half circle with r=80). `stroke-dashoffset = 251 × (1 - score/100)`.140141### Sparkline142```html143<svg viewBox="0 0 120 40" style="width: 120px; height: 40px;">144 <polyline points="0,35 20,28 40,30 60,15 80,20 100,8 120,12"145 fill="none" stroke="var(--accent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>146 <polyline points="0,35 20,28 40,30 60,15 80,20 100,8 120,12 120,40 0,40"147 fill="color-mix(in srgb, var(--accent) 15%, transparent)" stroke="none"/>148</svg>149```150151### Horizontal Bar Chart (CSS)152```html153<div class="bar-chart">154 <div class="bar-row">155 <span class="bar-label">Tasks</span>156 <div class="bar-track"><div class="bar-fill" style="width: 75%; background: var(--success);"></div></div>157 <span class="bar-value">75%</span>158 </div>159 <div class="bar-row">160 <span class="bar-label">Goals</span>161 <div class="bar-track"><div class="bar-fill" style="width: 45%; background: var(--warning);"></div></div>162 <span class="bar-value">45%</span>163 </div>164</div>165```166167## Regeneration Pattern168169When the user asks to "refresh" or "update" a dashboard:1701. Call `dashboards.widgetData` with the dashboard's widget IDs1712. Build fresh HTML using the returned data1723. Call `dashboards.save` with the same `id` to update173174## Example: Command Center Dashboard175176```html177<style>178 .cmd-header { display: flex; align-items: baseline; gap: 12px; margin-bottom: 20px; }179 .cmd-header h2 { margin: 0; font-size: 1.5rem; font-weight: 700; }180 .cmd-time { color: var(--muted); font-size: 0.875rem; }181 .donut-wrap { display: flex; align-items: center; gap: 16px; }182 .donut-legend { display: flex; flex-direction: column; gap: 4px; }183 .legend-item { display: flex; align-items: center; gap: 6px; font-size: 0.8125rem; }184 .legend-dot { width: 8px; height: 8px; border-radius: 50%; }185 .stat-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 16px; }186 .stat-card { text-align: center; padding: 12px; }187 .stat-card .stat { font-size: 1.75rem; }188 .activity-item { display: flex; align-items: center; gap: 8px; padding: 6px 0; border-bottom: 1px solid var(--border); }189 .activity-item:last-child { border-bottom: none; }190 @keyframes fill-in { from { stroke-dashoffset: 314; } }191</style>192193<div class="cmd-header">194 <h2 style="color: var(--text);">Command Center</h2>195 <span class="cmd-time">Updated just now</span>196 <span class="status-dot" style="margin-left: auto;"></span>197</div>198199<div class="stat-grid">200 <div class="widget stat-card">201 <div class="widget-title">Tasks</div>202 <div class="stat" style="color: var(--success);">12</div>203 <div class="stat-label">7 pending</div>204 </div>205 <div class="widget stat-card">206 <div class="widget-title">Focus</div>207 <div class="stat glow">85</div>208 <div class="stat-label">3-day streak</div>209 </div>210 <div class="widget stat-card">211 <div class="widget-title">Queue</div>212 <div class="stat">3</div>213 <div class="stat-label">1 in review</div>214 </div>215 <div class="widget stat-card">216 <div class="widget-title">Coding</div>217 <div class="stat" style="color: var(--warning);">2</div>218 <div class="stat-label">running</div>219 </div>220</div>221222<div class="grid-2">223 <div class="widget">224 <div class="widget-title">Task Completion</div>225 <div class="chart-container">226 <div class="donut-wrap">227 <svg viewBox="0 0 120 120" style="width: 100px; height: 100px;">228 <circle cx="60" cy="60" r="50" fill="none" stroke="var(--border)" stroke-width="10"/>229 <circle cx="60" cy="60" r="50" fill="none" stroke="var(--success)" stroke-width="10"230 stroke-dasharray="314" stroke-dashoffset="157" stroke-linecap="round"231 transform="rotate(-90 60 60)" style="animation: fill-in 1s ease-out;"/>232 <text x="60" y="56" text-anchor="middle" font-size="22" font-weight="700" fill="var(--text)">50%</text>233 <text x="60" y="72" text-anchor="middle" font-size="10" fill="var(--muted)">complete</text>234 </svg>235 <div class="donut-legend">236 <div class="legend-item"><span class="legend-dot" style="background: var(--success);"></span> Done (5)</div>237 <div class="legend-item"><span class="legend-dot" style="background: var(--warning);"></span> In progress (3)</div>238 <div class="legend-item"><span class="legend-dot" style="background: var(--border);"></span> Pending (4)</div>239 </div>240 </div>241 </div>242 </div>243244 <div class="widget">245 <div class="widget-title">Goals Progress</div>246 <div class="bar-chart">247 <div class="bar-row">248 <span class="bar-label">Launch MVP</span>249 <div class="bar-track"><div class="bar-fill" style="width: 75%; background: var(--success);"></div></div>250 <span class="bar-value">75%</span>251 </div>252 <div class="bar-row">253 <span class="bar-label">Hire team</span>254 <div class="bar-track"><div class="bar-fill" style="width: 30%; background: var(--warning);"></div></div>255 <span class="bar-value">30%</span>256 </div>257 <div class="bar-row">258 <span class="bar-label">Revenue</span>259 <div class="bar-track"><div class="bar-fill" style="width: 15%; background: var(--danger);"></div></div>260 <span class="bar-value">15%</span>261 </div>262 </div>263 </div>264</div>265266<div class="widget" style="margin-top: 12px;">267 <div class="widget-title">Focus Trend (7 days)</div>268 <div class="chart-container">269 <svg viewBox="0 0 300 60" style="width: 100%; height: 60px;">270 <polyline points="0,50 50,40 100,35 150,25 200,30 250,15 300,10"271 fill="none" stroke="var(--accent)" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>272 <polyline points="0,50 50,40 100,35 150,25 200,30 250,15 300,10 300,60 0,60"273 fill="color-mix(in srgb, var(--accent) 10%, transparent)" stroke="none"/>274 </svg>275 </div>276</div>277```278279## Tips280- **Always use `<style>` blocks** for custom CSS — they are fully supported. Put them at the top of your HTML.281- **Always use theme variables** for colors — never hardcode hex values. This ensures dashboards work in both light and dark themes.282- **Chart everything possible** — donut charts for ratios, sparklines for trends, gauges for scores, horizontal bars for comparisons.283- **Use animations sparingly but effectively** — animate chart fills on load, pulse status indicators, smooth transitions on progress bars.284- Dashboards can be workspace-specific (`scope: "workspace-id"`) or global (`scope: "global"`).285- Users can have multiple dashboards — ask what data they want to see before building.286- When the user says "update my dashboard" or "refresh my dashboard", fetch fresh widgetData and regenerate.