All styles live in src/ui.rs inside the render_styles() function. There are no external CSS files.
--s-1: 4px --s-2: 8px --s-3: 12px --s-4: 16px
--s-5: 24px --s-6: 32px --s-7: 48px --s-8: 64px
| Variable | Purpose |
|---|---|
--bg |
Page background |
--panel |
Panel/nav background |
--panel-strong |
Card/block background |
--ink |
Primary text color |
--muted |
Secondary/dimmed text |
--line |
Borders and dividers |
--accent |
Primary accent (blue) |
--accent-soft |
Light accent background |
--surface-hover |
Hover state background |
--input-bg |
Form input background |
--button-bg / --button-ink |
Standard button colors |
--hero-button-bg / --hero-button-ink |
Prominent button colors (blue fill) |
--font-sans— body text, UI labels--font-mono— code, textareas, metadata--radius— standard border radius for cards and inputs
Two canonical size classes that can be combined with any color/style class:
28x28px square icon buttons. border-radius: 5px, no padding, inline-flex centered, flex-shrink: 0.
Use for: icon-only action buttons in headers, toolbars, chat panes.
48px min-height with padding: var(--s-3) var(--s-4), 16px font.
Use for: full form buttons, prominent actions. This matches the default <button> sizing but provides an explicit class when needed.
Blue-filled oval buttons used for primary actions in page headers.
CSS: min-height: 44px, padding: 0 var(--s-5), border-radius: 999px, font-weight: 700, font-size: 0.95rem. Background is --hero-button-bg, text is --hero-button-ink. Hover lifts 1px (translateY(-1px)) with slight opacity reduction.
Examples:
- "Search", "Audit", "History" buttons in the project header
- "Ask" button in the librarian panel
- "Back to project" links on audit/history pages
- "Copy" buttons on the Agents page
- "Save" / "Cancel" in the project title rename form
Usage: Page-level actions, navigation between major views, primary form actions in headers.
Small square icon-only buttons used on block headers.
CSS: width: 28px, height: 28px, border-radius: 6px, border: 1px solid transparent, background: transparent, color: var(--muted). Hover shows --accent-soft background with --accent border and color. The .danger variant shows red on hover.
Examples:
- Copy link button (chain-link icon) on each block
- Edit button (pencil icon) on each block
- Delete button (X icon) on each block
Usage: Per-item actions on blocks. Always grouped together in a .block-header-actions flex container on the right side of the block header. Order: copy, edit, delete.
Small inline buttons used in the project tree sidebar.
CSS: border: 1px solid var(--line), border-radius: var(--radius), padding: 2px 8px, font-size: 0.85rem, color: var(--muted), background: none. Hover shows --surface-hover background with --ink color.
Examples:
- "+" button to create a child project under a tree node
- "+ New project" button at the bottom of the tree
- Burger/grip handle for drag-and-drop reordering
Usage: Compact actions alongside tree rows. The drag handle uses cursor: grab / cursor: grabbing.
Circular "+" button that appears between blocks on hover.
CSS: width: 32px, height: 32px, border-radius: 50%, border: 2px solid var(--line), background: var(--panel-strong), font-size: 1.2rem. Hidden by default (opacity: 0), shown on hover via .inserter-hover-zone:hover .inserter-btn. Has a subtle box-shadow. Hover shows accent colors.
Examples:
- The "+" that appears between any two blocks when hovering the gap
Usage: Only used in the block timeline for inserting new blocks.
Small rectangular buttons for choosing block type in the inserter form.
CSS: padding: var(--s-2) var(--s-4), border: 1px solid var(--line), border-radius: var(--radius), font-size: 0.85rem, font-weight: 600, color: var(--muted). Active/hover shows accent border and text.
Examples:
- "Markdown", "SVG", "Image" type selector buttons inside the block inserter
Usage: Only inside the expanded block inserter.
Default <button> elements inside forms.
CSS (global): width: 100%, min-height: 44px, border-radius: var(--radius), background: var(--button-bg), color: var(--button-ink), font-weight: 600.
Examples:
- "Sign in" on the login page
- "Save" / "Cancel" in block edit forms (overridden to
width: autovia.block-edit-actions button) - "Create" in the admin token form
Usage: Full-width form submission buttons, or auto-width inside edit forms.
All icons are inline SVGs using a consistent style:
width="14" height="14"(fits inside 28px icon buttons)viewBox="0 0 24 24"fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
This matches the Lucide/Feather icon style. Use currentColor for stroke so icons inherit the parent's text color and respond to hover states.
| Icon | SVG Path Summary | Used For |
|---|---|---|
| Pencil (edit) | M17 3a2.83 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z + m15 5 4 4 |
Block edit button |
| X (delete) | Two diagonal lines: (18,6)-(6,18) and (6,6)-(18,18) |
Block delete button |
| Chain link (copy link) | Two curved paths forming interlocking chain links | Block/project copy-link button |
| Burger menu (drag handle) | Three horizontal lines at y=6, y=12, y=18 | Project tree drag handle |
- Use the same SVG attributes:
width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" - Source paths from Lucide (https://lucide.dev) for consistency
- Place inline in the Rust format string, not as external files
A standard pattern for any list where items can be selected and a detail panel appears below. Used for admin users, endpoints, agents, and any future list-with-detail UI.
<div class="sel-list">
<div class="sel-item" data-sel-id="item-1">
<div>
<span class="sel-item-name">Item Name</span>
<span class="sel-item-meta"><span class="pill">badge</span> · extra info</span>
</div>
<span class="sel-item-actions">
<button class="btn-sm" title="Action"><!-- SVG glyph --></button>
</span>
</div>
</div>
<div class="sel-detail" data-sel-id="item-1" style="display:none">
<!-- detail content shown when item is selected -->
</div>| Class | Purpose |
|---|---|
.sel-list |
Container. Bordered, rounded, column flex. No margin (panel provides edge spacing). |
.sel-item |
Row. Flex between, padded var(--s-3) var(--s-4), bottom border, hover highlight. |
.sel-item.active |
Selected state: var(--bg-hover) background + 4px var(--accent) left border. |
.sel-item-name |
Primary label. font-weight: 600, mono font, 0.9rem. |
.sel-item-meta |
Secondary text/badges. 0.82rem, var(--fg-muted), flex with gap. |
.sel-item-actions |
Right-side button group. Flex, gap: var(--s-1), no shrink. Use btn-sm buttons with SVG glyphs and title tooltips. |
.sel-detail |
Detail panel below list. Fully bordered with full border-radius. Hidden by default (display:none), shown when parent .sel-item is active. |
Use data-sel-id on both .sel-item and .sel-detail elements with matching values. The standard initialiser wires up click-to-toggle:
function initSelList(scope) {
var items = scope.querySelectorAll('.sel-list .sel-item');
var details = scope.querySelectorAll('.sel-detail');
items.forEach(function(item) {
item.addEventListener('click', function() {
var id = item.getAttribute('data-sel-id');
var wasActive = item.classList.contains('active');
items.forEach(function(i) { i.classList.remove('active'); });
details.forEach(function(d) { d.style.display = 'none'; });
if (!wasActive) {
item.classList.add('active');
var detail = scope.querySelector('.sel-detail[data-sel-id="' + id + '"]');
if (detail) detail.style.display = '';
}
});
});
}Call initSelList(scopeElement) where scopeElement is the nearest container that holds both the list and its detail panels (e.g. a [data-panel] section). On the admin page this is auto-initialised for all [data-panel] sections.
Buttons inside .sel-item-actions should use btn-sm (28x28 icon buttons) with:
- Inline SVG glyphs (14x14, Lucide style)
- A
titleattribute for the tooltip event.stopPropagation()in onclick to prevent triggering item selection
- Admin users list — username items with role badge, detail panel for password/session management
- Admin endpoints list — provider endpoints with kind badge, detail panel for config/test/delete
- Agents page — agent list with status badge and stop/restart buttons, detail panel for grants and setup
A bordered, rounded container used to group related content throughout the UI.
CSS: background: var(--panel), border: 1px solid var(--line), border-radius: var(--radius), box-shadow: var(--shadow), backdrop-filter: blur(8px), padding: var(--s-5).
Rule: internal content must never touch the panel borders. The panel provides var(--s-5) padding on all sides. Children should not add their own side margins or padding to create edge spacing — the panel handles it. Use only top margins between sibling elements inside a panel for vertical spacing.
<section class="panel">
<div class="panel-title">Title</div>
<!-- content: sel-list, forms, text, etc. -->
</section>Panels can omit .panel-title entirely — they just have no title. When present, .panel-title provides consistent bottom spacing (var(--s-3)) before the content.
Small uppercase label inside a panel. font-size: 0.75em, font-weight: 600, text-transform: uppercase, letter-spacing: 0.05em, color: var(--fg), opacity: 0.35. Always the first child inside the panel. Do NOT place titles outside panels — the title is part of the panel.
The title area inside a panel. display: grid, gap: var(--s-2), no padding (panel provides it). Contains an <h2> and optional <p> description. Used for admin sections with richer headings.
- Admin page sections (Users, Endpoints, Roles, etc.)
- Settings page sections
- Agent detail panels
- Project document and agent-context sections
The header row of each block. Uses display: flex, align-items: center, justify-content: space-between. Left side holds the type .pill, right side holds .block-header-actions (copy, edit, delete buttons).
Type label badge. border-radius: 999px, background: var(--accent-soft), color: var(--accent), font-weight: 700, font-size: 0.8rem, text-transform: uppercase.
Content block card. padding: var(--s-5), border: 1px solid var(--line), border-radius: var(--s-5), background: var(--panel-strong). Blocks are spaced with gap: 6px in the .timeline grid.
The vertical stack of blocks. display: grid, gap: 6px. Block inserters sit in between blocks with height: 0 and overlay on hover.
A project row in the tree. display: flex, gap: var(--s-3), padding: var(--s-2) var(--s-3). Contains the link (.tree-link, flex: 1), permission label, and action buttons in .tree-row-right.
Internal links use the lore:// protocol with standard markdown syntax. Rendered with CSS pseudo-elements:
.lore-link-project::before— document emoji prefix.lore-link-block::before— link emoji prefix.lore-link-broken— red, strikethrough,cursor: not-allowed
Single breakpoint at max-width: 860px:
.layout,.admin-layout,.agents-optionscollapse to single column.shellwidth becomesmin(100vw - 16px, 1080px)- Block header buttons keep 28px size