dashboard.css + docs: migrate MESS4GE FL0W body layout + final cookie scrub (#712 batch 13)

Second dashboard.css batch — scrubs all remaining #NNN cookies
(post-batch-12 dashboard.css went from 51 → 36 raw matches, mostly
hex colors). This batch zeroes out the actual issue refs.

Moved to docs/web-ui.md::FL0W page:
- **MESS4GE FL0W (extended)**: msgrow flex-wrap row + body
  flex-basis: 100% + min-width: 0 rationale (~10 lines new prose).
  Without flex-basis: 100% the body sat inline eating whatever the
  chips left, starting ~30ch in on long timestamps + agent names
  and wrapping awkwardly. Pushing it to its own line lets the body
  use the full row width.

Collapsed in dashboard.css (en passant cookie scrubs across many
small comments):
- #485 msgrow body flex (→ FL0W docs pointer)
- #450 inbox max-height (→ inline rationale only, cookie dropped)
- #451 side-panel drag-to-resize × 2 (→ Side panel docs pointer)
- #369 dashboard chrome (→ Tab strip pointer)
- #416 full-width layout (→ inline rationale, cookie dropped)
- #389 slug banner footer (→ inline rationale, cookie dropped)
- #369#issuecomment-3437 + #362 + #383 + #383 + #362 flow.html
  section (→ FL0W page pointer + per-agent header pills pointer)
- #375 tail pill stacking context (→ Per-agent page Terminal-wrap
  pointer to existing docs)
- #66 ctx badge thresholds (→ Container row Line 1 pointer)
- #541 panel-body column flex × 2 (→ inline rationale, cookie dropped)
- #188 / #192 image preview (→ Side panel pointer)
- #275 bulk select × 2 (→ inline, cookies dropped)
- #259 background meta-update (→ inline, cookie dropped)
- #474 inline edit button + form (→ inline, cookies dropped)
- #466 interval composer (→ inline, cookie dropped)
- #535 schedules-as-table × 2 (→ SCH3DUL3S tab pointer + inline)
- #564 inline create row (→ inline, cookie dropped)
- #443 selection bar (→ Selection bar pointer)
- #486 M0V3 → <pick> (→ Selection bar pointer)
- #459 scheduled prompts tab section (→ SCH3DUL3S tab pointer)

dashboard.css: ~20 issue refs scrubbed in this batch + ~10 lines
substantive prose migrated to MESS4GE FL0W. Total dashboard.css
across batches 12 + 13: 51 raw matches → 0 issue-ref cookies
(only hex colors remain).
This commit is contained in:
iris 2026-05-31 15:01:16 +02:00 committed by mara
commit 6c9b28903f
2 changed files with 98 additions and 112 deletions

View file

@ -383,7 +383,14 @@ newest-first.
**MESS4GE FL0W** — live broker tail wrapped in a `.terminal-wrap`.
Cold load backfills the last ~200 messages from `/dashboard/history`;
live frames arrive on `/dashboard/stream`. Each row is one broker
event — `sent` or `delivered` — with `from → to: body`. Sticky-
event — `sent` or `delivered` — with `from → to: body`. The row is
a `flex-wrap: wrap` container holding ts / arrow / from / sep / to
chips inline; the **body wraps to its own full-width line below**
the chips (`flex: 1 1 100%`) so the body always gets the full row
width down to the content edge — long timestamps + agent names
used to push the body ~30ch in and force awkward narrow-column
wraps. `min-width: 0` keeps `word-break: break-word` effective so
the body doesn't force the row wider than its container. Sticky-
bottom auto-scroll + "↓ N new" pill. Below the stream sits a
terminal-style compose box: `@name` picks the recipient (sticky via
localStorage; auto-complete from the live container list, Tab/Enter

View file

@ -3,19 +3,19 @@
@import "@hive/shared/base.css";
@import "@hive/shared/terminal.css";
/* tabbed dashboard chrome (#369)
Top-of-page sticky header with banner + tab strip. Tab routing is
hash-based; tab panes are show/hide via the `.tab-pane-active`
class. SSE stays alive across tab switches so count pills update
live on inactive tabs without losing pulse on what's happening
elsewhere. */
/* tabbed dashboard chrome
Top-of-page sticky header with banner + tab strip. SSE stays
alive across tab switches so count pills update live on inactive
tabs. See docs/web-ui.md::Chrome header + Tab strip for the
routing model. */
body.dashboard-shell {
/* Full-width layout (#416 mara: drop the 90em cap so wide screens
don't waste real estate on empty side margins). `padding: 0 1.5em
1.5em` keeps a small gutter on the left/right so cards don't kiss
the viewport edge; `.dashboard-chrome { margin: 0 -1.5em ... }`
still pulls the chrome bar edge-to-edge through that gutter. */
/* Full-width layout no max-width cap so wide screens don't
waste real estate on empty side margins. `padding: 0 1.5em
1.5em` keeps a small gutter on the left/right so cards don't
kiss the viewport edge; `.dashboard-chrome { margin: 0 -1.5em
... }` still pulls the chrome bar edge-to-edge through that
gutter. */
margin: 0;
padding: 0 1.5em 1.5em;
}
@ -427,11 +427,10 @@ a:hover {
color: var(--cyan); border-color: var(--cyan);
text-shadow: 0 0 6px rgba(137, 220, 235, 0.4);
}
/* Context-window usage badges on dashboard container rows. Thresholds
are derived per-container: yellow 50% and red 75% of the model's
context window (`ContainerView.context_window_tokens`), mirroring the
harness compaction watermarks. Falls back to fixed 100k / 150k when
the window is unknown. (issue #66) */
/* Context-window usage badges on dashboard container rows. See
docs/web-ui.md::Container row Line 1 for the per-container
threshold derivation (yellow 50% / red 75% of the model's
context window) and fallback values. */
.badge-ctx-ok {
color: var(--green); border-color: var(--green);
opacity: 0.85;
@ -464,10 +463,10 @@ a:hover {
/* Per-container journald viewer + applied-config viewer. Both open
in the side panel and lazy-fetch on open; output is monospace
inside a bordered <pre>, controls (unit select + refresh) above.
#541: the panel-body wrapper is a column flex container that fills
the side-panel-body so the <pre> can flex-grow into a single tall
scrollable surface instead of a short box at the top with the rest
of the panel empty. */
The panel-body wrapper is a column flex container that fills the
side-panel-body so the <pre> can flex-grow into a single tall
scrollable surface instead of a short box at the top with the
rest of the panel empty. */
.journal-body {
display: flex;
flex-direction: column;
@ -495,9 +494,9 @@ a:hover {
color: var(--fg);
border: 1px solid var(--purple-dim);
padding: 0.5em 0.7em;
/* #541: take all leftover panel height + scroll inside the pre so
long log fetches don't push the controls off-screen. `min-height:
0` is the canonical "let me actually flex-shrink for overflow"
/* Take all leftover panel height + scroll inside the pre so long
log fetches don't push the controls off-screen. `min-height: 0`
is the canonical "let me actually flex-shrink for overflow"
escape hatch on flex children. */
flex: 1 1 0;
min-height: 0;
@ -645,7 +644,8 @@ code {
border-color: var(--purple);
background: rgba(203, 166, 247, 0.08);
}
/* Image / tabbed file preview (issues #188, #192) */
/* Image / tabbed file preview see docs/web-ui.md::Side panel
for the type-aware preview shapes. */
.preview-host { margin-top: 0.5em; }
.img-preview {
display: block;
@ -719,7 +719,7 @@ code {
text-overflow: ellipsis;
white-space: nowrap;
}
/* Bulk select-all / -none control above the meta-inputs tree (#275). */
/* Bulk select-all / -none control above the meta-inputs tree. */
.meta-inputs-bulk {
margin: 0 0 0.5em;
font-size: 0.8em;
@ -739,7 +739,7 @@ code {
border-color: var(--cyan);
text-shadow: 0 0 6px currentColor;
}
/* Tree twig glyph prefixing a nested (sub-)input row (#275). */
/* Tree twig glyph prefixing a nested (sub-)input row. */
.meta-input-twig {
color: var(--purple-dim);
margin-right: 0.1em;
@ -765,7 +765,7 @@ code {
cursor: not-allowed;
}
/* In-progress banner for the META INPUTS panel: shown while a
dashboard-triggered meta-update runs in the background (issue #259). */
dashboard-triggered meta-update runs in the background. */
.meta-update-running {
margin: 0 0 0.7em;
padding: 0.4em 0.7em;
@ -941,7 +941,7 @@ ul form.inline { display: inline-block; }
text-shadow: 0 0 6px currentColor;
box-shadow: 0 0 8px -2px currentColor;
}
/* #474: inline edit button on each schedule row. Yellow reads as a
/* Inline edit button on each schedule row. Yellow reads as a
parallel destructive-adjacent action (edit changes state, but
isn't deletion). */
.btn-edit-schedule { color: var(--yellow, #f9e2af); border-color: var(--yellow, #f9e2af); }
@ -1206,10 +1206,8 @@ summary:hover { color: var(--purple); }
background: var(--bg-elev);
border: 1px solid var(--border);
padding: 0.5em 0.8em;
/* #450: no max-height cap let the inbox grow to fill the
side-panel-body which already scrolls (`overflow: auto`). The
pre-#450 24em cap clamped the list well short of the available
panel height even on tall viewports. */
/* No max-height cap let the inbox grow to fill the
side-panel-body which already scrolls. */
}
.inbox li {
padding: 0.25em 0;
@ -1245,17 +1243,9 @@ summary:hover { color: var(--purple); }
text-indent: 0;
}
.live .msgrow .msg-body {
/* #485: body takes a full flex line of its own beneath the
metadata chips (ts / arrow / from / sep / to). Previously the
body sat inline with `flex: 1 1 0`, eating whatever the chips
left which on a long timestamp + agent names + arrows meant
the body started ~30ch in and wrapped awkwardly. Pushing
`flex-basis: 100%` forces the body to wrap to its own line in
the existing `flex-wrap: wrap` row, where it can use the full
width down to the row's content edge.
`min-width: 0` still applies so `word-break: break-word`
actually kicks in instead of forcing the row wider than its
container. */
/* Body takes a full flex line of its own beneath the metadata
chips. See docs/web-ui.md::FL0W page (MESS4GE FL0W) for the
flex-basis: 100% + min-width: 0 rationale. */
flex: 1 1 100%;
min-width: 0;
}
@ -1354,9 +1344,9 @@ footer {
font-size: 0.9em;
}
footer a { color: var(--purple); }
/* Slug banner now lives at the page footer (#389 follow-up) give
it a slim top margin so it doesn't crash into the prior content,
and bottom margin separating from the divider/link line. */
/* Slug banner lives at the page footer slim top margin so it
doesn't crash into the prior content, bottom margin separating
from the divider/link line. */
footer .banner-thin {
margin-bottom: 0.8em;
}
@ -1402,13 +1392,11 @@ footer .banner-thin {
top: 0;
right: 0;
bottom: 0;
/* #451: width is a CSS variable so the drag handle (added by
Panel.bind) can update it live, and so localStorage-persisted
widths apply on first paint. Default min(760px, 94vw) preserves
the pre-#451 behaviour for operators who never drag. JS sets
`--side-panel-w` via inline style on the drawer; persistence
lives in localStorage (key `hyperhive:side-panel-width`),
replayed onto the var by `Panel.applyStoredWidth` at bind. */
/* Width is a CSS variable so the drag handle can update it live
(JS sets `--side-panel-w` on the drawer) and localStorage-
persisted widths apply on first paint. Default min(760px, 94vw)
covers operators who never drag. See docs/web-ui.md::Side panel
for the drag-to-resize mechanism + localStorage key. */
width: var(--side-panel-w, min(760px, 94vw));
/* Clamp so a stored width can never push the drawer off-screen
or shrink it past readability. min content width matches the
@ -1426,12 +1414,11 @@ footer .banner-thin {
.side-panel.open { pointer-events: auto; }
.side-panel.open .side-panel-backdrop { opacity: 1; }
.side-panel.open .side-panel-drawer { transform: translateX(0); }
/* #451: drag-to-resize handle on the drawer's left edge. The handle
itself is invisible until hover/drag so it doesn't compete with the
2px mauve `border-left` for the visual boundary. Pointer-cursor
tells the operator the edge is grabbable; the brighter glow during
drag (`body.side-panel-resizing`) is the affordance the eye
tracks. */
/* Drag-to-resize handle on the drawer's left edge. Invisible until
hover/drag so it doesn't compete with the 2px mauve border-left
for the visual boundary. Pointer-cursor tells the operator the
edge is grabbable; the brighter glow during drag
(body.side-panel-resizing) is the affordance the eye tracks. */
.side-panel-resize {
position: absolute;
top: 0;
@ -1529,22 +1516,17 @@ body.side-panel-resizing * { cursor: ew-resize !important; }
padding: 0.2em 0.5em;
}
/* /flow.html full-page chat (#369)
The all-agents chat surface lives on its own page so it can claim
full-viewport vibec0re styling (operator @ #369#issuecomment-3437).
Same shape as the per-agent live page (#362): frosted-glass header
at top, frosted composer docked at bottom, terminal scrolls
behind both. Operator inbox lives behind a header pill that opens
the side-panel flyout preserves the "inbox + chat in one view"
ergonomics without stealing terminal real estate. */
/* /flow.html full-page chat
See docs/web-ui.md::FL0W page for the page-vs-pane rationale
and the inbox-flyout-as-pill ergonomics. Shape mirrors the
per-agent live page (frosted-glass header + composer, full-
viewport terminal). */
:root {
/* Approximate height of the flow chrome (tabbar + dashboard-chrome
padding). The banner-thin slug used to live in the chrome and
padded this up to 4.7em; with the slug moved out (#389 follow-up:
slug lives at the page footer on /, simply omitted on /flow.html
since there's no normal-flow footer position in the full-viewport
terminal), the chrome is just tabs now and shrinks accordingly. */
padding). The slug banner lives at the page footer on /, omitted
on /flow.html since the full-viewport terminal has no normal-flow
footer position. */
--flow-header-h: 3.6em;
--flow-composer-h: 3.6em;
--flow-frost-bg: rgba(30, 30, 46, 0.74);
@ -1566,8 +1548,8 @@ body.flow-shell {
var(--bg);
}
/* Flow chrome (#383): reuses the dashboard's `.dashboard-chrome` +
tabbar so the operator can switch tabs from the flow page without
/* Flow chrome reuses the dashboard's `.dashboard-chrome` + tabbar
so the operator can switch tabs from the flow page without
navigating back first. The chrome must be fixed-position (vs
sticky on the dashboard) since flow-shell has `overflow: hidden`
on body and the main area absolute-positions the terminal. */
@ -1595,15 +1577,13 @@ body.flow-shell .tabbar .tab.active.tab-link {
border-color: var(--purple-dim);
box-shadow: 0 -2px 12px -4px rgba(203, 166, 247, 0.4);
}
/* Legacy `.flow-title` / `.flow-hint` / `.flow-back` rules were
removed in #383 the flow page now uses the shared chrome with
the dashboard tab strip, no need for FL0W-specific title/hint
elements. The `.notif-row` styling lives under the shared
`.tabbar #notif-row` selector earlier in the file. */
/* `.notif-row` styling lives under the shared `.tabbar #notif-row`
selector earlier in the file the flow page reuses the dashboard
tab strip rather than carrying its own title/hint/back chrome. */
/* Inbox pill operator inbox flyout trigger. Sits right under the
header so it stays in the operator's gaze without crowding the
chat. Same shape as the agent page's pills (#362). */
chat. Same shape as the agent page's header pills. */
.flow-pill {
position: fixed;
top: calc(var(--flow-header-h) + 0.8em);
@ -1672,11 +1652,10 @@ body.flow-shell .tabbar .tab.active.tab-link {
overflow: auto;
}
/* Tail pill ( N new): bottom offset clears the floating composer.
z-index escapes the stacking context the .terminal-wrap's
backdrop-filter creates (issue #375) tabs.js anchors the pill
on .flow-main now (not .terminal-wrap), so this z-index reaches
the root stacking context and properly floats above the
composer at z-index 30. */
Pill is anchored on .flow-main (not .terminal-wrap) so the
backdrop-filter stacking context doesn't trap its z-index see
docs/web-ui.md::Per-agent page (Terminal-wrap) for the same
gotcha on the agent page. */
.flow-main .tail-pill {
bottom: calc(var(--flow-composer-h) + 0.6em);
z-index: 35;
@ -1702,10 +1681,11 @@ body.flow-shell .tabbar .tab.active.tab-link {
surface the messages via the pill/flyout instead. */
.flow-inbox-headless { display: none !important; }
/* scheduled prompts tab (#459)
/* scheduled prompts tab
Creation form at the top, list of queued schedule cards below.
Cards show: id + source + due-in + cancel-all in the header,
the prompt body, then a targets table with per-row cancel. */
the prompt body, then a targets table with per-row cancel. See
docs/web-ui.md::SCH3DUL3S tab. */
.schedule-edit-form {
display: flex;
@ -1717,9 +1697,9 @@ body.flow-shell .tabbar .tab.active.tab-link {
padding: 0.8em 1em;
margin-bottom: 0.5em;
}
/* #474 inline edit form opens directly under the schedule row's
actions strip, indented slightly so it visually nests under the
row it edits. */
/* Inline edit form opens directly under the schedule row's
actions strip, indented slightly so it visually nests under
the row it edits. */
.schedule-edit-form-wrapper {
margin-top: 0.5em;
padding-left: 0.5em;
@ -1782,7 +1762,7 @@ body.flow-shell .tabbar .tab.active.tab-link {
justify-content: flex-end;
}
/* Interval composer (#466). Preset chip row + d/h/m/s inputs + live
/* Interval composer preset chip row + d/h/m/s inputs + live
preview, so the operator never has to multiply seconds by hand. */
.schedule-interval-presets {
display: flex;
@ -1826,10 +1806,9 @@ body.flow-shell .tabbar .tab.active.tab-link {
}
.schedule-interval-preview-oneshot { color: var(--muted); font-style: italic; }
/* #535 schedules-as-table. One row per schedule, attribute columns
/* Schedules-as-table one row per schedule, attribute columns
on the left, one / column per agent in the middle, actions
column on the right. Agent column headers tilt -45° so a stack of
short agent names fits in ~28px each. */
column on the right. See docs/web-ui.md::SCH3DUL3S tab. */
.schedules-table {
width: 100%;
border-collapse: collapse;
@ -1849,11 +1828,11 @@ body.flow-shell .tabbar .tab.active.tab-link {
.schedules-table-id { width: 3em; }
.schedules-table-body-th { min-width: 12em; }
.schedules-table-actions-th { width: 7em; }
/* Tilted agent column headers (#535). Header cell is narrow (~28px)
and tall (~90px); the inner <div> rotates -45° about its bottom-left
corner, with a translate to slide the text up alongside the cell
border. The inner <span> carries the actual baseline so the
underline (border-bottom on the cell) aligns with the rotated text. */
/* Tilted agent column headers narrow (~28px) and tall (~90px);
the inner <div> rotates -45° about its bottom-left corner, with
a translate to slide the text up alongside the cell border. The
inner <span> carries the actual baseline so the underline
(border-bottom on the cell) aligns with the rotated text. */
.schedules-table-agent-th {
width: 28px;
min-width: 28px;
@ -1937,8 +1916,8 @@ body.flow-shell .tabbar .tab.active.tab-link {
padding: 0.1em 0.45em;
}
/* #564 inline create row at the bottom of the schedules table.
Cells host inputs directly so the operator can fill + click to
/* Inline create row at the bottom of the schedules table. Cells
host inputs directly so the operator can fill + click to
queue a new schedule without leaving the table view. Slightly
different background tone so it reads as "this isn't a schedule
yet, it's the create form". */
@ -2040,11 +2019,11 @@ body.flow-shell .tabbar .tab.active.tab-link {
border-color: var(--border);
}
/* Selection bar (#443). Sticky-bottom strip that surfaces bulk
actions when 1 agent is selected (click the icon). Visually
echoes the flow composer's frosted-mauve treatment so the chrome
reads as part of the same vibecore family. Hidden when empty
leaves the page footer's normal-flow position untouched. */
/* Selection bar sticky-bottom strip that surfaces bulk actions
when 1 agent is selected (click the icon). Visually echoes the
flow composer's frosted-mauve treatment so the chrome reads as
part of the same vibecore family. Hidden when empty. See
docs/web-ui.md::Selection bar for the bulk-action semantics. */
.selection-bar {
position: fixed;
bottom: 0;
@ -2100,11 +2079,11 @@ body.flow-shell .tabbar .tab.active.tab-link {
selection set is non-empty). */
body.dashboard-shell.has-selection { padding-bottom: 4.5em; }
/* #486 M0V3 <pick> picker. Inline `<select>` + button pair
sitting alongside the bulk action buttons in the selection bar.
The select inherits the terminal-y monospace look so it doesn't
read as system-chrome popping out of the swarm aesthetic. Only
surfaces when exactly one agent is selected. */
/* M0V3 <pick> picker inline `<select>` + button pair sitting
alongside the bulk action buttons in the selection bar. The
select inherits the terminal-y monospace look so it doesn't read
as system-chrome popping out of the swarm aesthetic. See
docs/web-ui.md::Selection bar for the picker semantics. */
.move-picker {
display: inline-flex;
align-items: center;