diff --git a/docs/web-ui.md b/docs/web-ui.md index 7a6cd6d7..9f91d8c2 100644 --- a/docs/web-ui.md +++ b/docs/web-ui.md @@ -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 diff --git a/frontend/packages/dashboard/src/dashboard.css b/frontend/packages/dashboard/src/dashboard.css index f08bb5d8..343f338f 100644 --- a/frontend/packages/dashboard/src/dashboard.css +++ b/frontend/packages/dashboard/src/dashboard.css @@ -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
, controls (unit select + refresh) above.
-   #541: the panel-body wrapper is a column flex container that fills
-   the side-panel-body so the 
 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 
 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 
rotates -45° about its bottom-left - corner, with a translate to slide the text up alongside the cell - border. The inner 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
rotates -45° about its bottom-left corner, with + a translate to slide the text up alongside the cell border. The + inner 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 → picker. Inline `` + 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;