Compare commits

...
Author SHA1 Message Date
iris
c08f47a035 fix(core): add card styling for K3PT ST4T3 and 1NFR4 entries
Closes #2720 (partial — kept state + infra card layout).

core.html doesn't load dashboard.css so the .container-row styles from
the operator SPA weren't available. Add equivalent card rules directly in
core.css: .containers flex column, .container-row with bg-elev background
+ border + border-radius, .tombstone dashed variant, .head flex row with
badge + meta, .actions flex row for the action buttons. Matches the visual
weight of agent cards on the main dashboard.
2026-07-26 17:23:52 +02:00
iris
234822e810 fix(schedules,call): rotate agent columns 90° + coherent history cards
Closes #2720 (partial — schedules + call history fixes).

schedules:
- Agent-name column headers: switch from -45° CSS transform (which clipped
  names mid-glyph) to writing-mode:vertical-rl + rotate(180deg). Names now
  read bottom-to-top without truncation in their 28px column.
- Shrink 'next' column from 8em → 5.5em and 'every' from 7em → 5em;
  these only hold short duration strings so the wider widths wasted space.

call history:
- Approval history <li> items now get a lightweight card treatment
  (bg-elev background, 1px border, 3px left accent) matching the visual
  weight of the pending .approval-card items above them.
- Left border colour reflects outcome via :has(.glyph-*): green for
  approved, red for denied, amber for failed.
2026-07-26 17:22:52 +02:00
iris
a58816d17e fix(stats): move window selector into the page header tab bar
Closes #2720 (partial — stats tab placement + contrast).

The time-window nav was in <main> below the page title, so it controlled
hash routing but wasn't visually part of the page chrome. Move it into
<header> (same row as ← home / ST4TS), fill the remaining header space,
and right-align the buttons — consistent with the /logs.html tabbar pattern.
Also set explicit color/border on inactive buttons so they remain readable
on lower-contrast operator colour schemes (var(--subtext1) fallback to
var(--muted)).
2026-07-26 17:21:21 +02:00
iris
c8ed190ccc fix(logs): log output scrolls internally instead of scrolling the page
Closes #2720 (partial — logs scroll fix).

Make body.logs-shell a full-viewport flex column so the visible .logs-pane
fills the remaining height and .journal-output (already flex:1 overflow:auto)
scrolls its content. Also handle the AUDIT tab's <div> output the same way.
The tab bar and toolbar stay anchored at the top; only the log text scrolls.
2026-07-26 17:20:48 +02:00
5 changed files with 132 additions and 27 deletions

View file

@ -21,3 +21,51 @@ body.core-shell {
/* createTabStrip toggles the native `hidden` attribute on inactive
panes; ensure it wins over any inherited display. */
.core-pane[hidden] { display: none; }
/* K3PT ST4T3 + 1NFR4 container cards
core.html doesn't load dashboard.css (that's the operator SPA),
so the .container-row card styles aren't inherited. Redefine them
here so tombstone and infra entries look like proper cards (similar
to agent cards on the main dashboard) rather than bare list items. */
.containers {
list-style: none;
padding: 0;
margin: 0.5em 0 0;
display: flex;
flex-direction: column;
gap: 0.5em;
}
.container-row {
background: var(--bg-elev);
border: 1px solid var(--border);
border-radius: 4px;
padding: 0.55em 0.8em 0.5em;
}
.container-row.tombstone {
border-style: dashed;
background: color-mix(in srgb, var(--bg-elev) 35%, transparent);
opacity: 0.85;
}
.container-row .head {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.5em;
margin-bottom: 0.4em;
}
.container-row .head .name {
font-size: 1.05em;
font-weight: bold;
}
.container-row.tombstone .head .name { color: var(--muted); }
.container-row .head .meta {
margin-left: auto;
font-size: 0.88em;
color: var(--muted);
}
.container-row .actions {
display: flex;
flex-wrap: wrap;
gap: 0.4em;
}
.container-row .actions form.inline { display: inline-block; margin: 0; }

View file

@ -582,6 +582,20 @@ body.dashboard-shell {
background: color-mix(in srgb, var(--purple) 8%, transparent);
text-shadow: 0 0 4px currentColor;
}
/* History items: lighter card treatment so they're visually coherent with
the pending .approval-card items above them. Left accent colour reflects
the outcome via :has() on the per-status glyph span. */
.approvals-history li {
background: color-mix(in srgb, var(--bg-elev) 40%, transparent);
border: 1px solid var(--border);
border-left: 3px solid var(--subtext0);
border-radius: 3px;
padding: 0.35em 0.8em;
margin-bottom: 0.4em;
}
.approvals-history li:has(.glyph-approved) { border-left-color: var(--green); }
.approvals-history li:has(.glyph-denied) { border-left-color: var(--red); }
.approvals-history li:has(.glyph-failed) { border-left-color: var(--amber); }
.approvals-history .status { font-size: 0.85em; padding: 0 0.5em; }
.status-approved { color: var(--green); }
.status-denied { color: var(--red); }
@ -1023,34 +1037,41 @@ footer .banner-thin {
white-space: nowrap;
}
.schedules-table-id { width: 3em; text-align: center; }
.schedules-table-next-col { width: 8em; white-space: nowrap; }
.schedules-table-every-col { width: 7em; white-space: nowrap; }
/* next / every columns: sized to typical content (short durations).
Previous 8em / 7em wasted horizontal space. */
.schedules-table-next-col { width: 5.5em; white-space: nowrap; }
.schedules-table-every-col { width: 5em; white-space: nowrap; }
.schedules-table-body-th { min-width: 12em; }
.schedules-table-actions-th { width: 7em; }
/* Agent-name columns: 90° vertical text (writing-mode) so names are fully
readable without truncation. Previously used a -45° CSS transform which
clipped names mid-glyph. writing-mode + rotate(180deg) is in-flow and
needs no absolute positioning or overflow hacks. */
.schedules-table-agent-th {
width: 28px;
min-width: 28px;
height: 95px;
padding: 0 !important;
height: 8em;
padding: 4px 2px !important;
vertical-align: bottom;
white-space: nowrap;
text-transform: none !important;
letter-spacing: 0 !important;
position: relative;
overflow: hidden;
}
.schedules-table-agent-th > div {
position: absolute;
bottom: 4px;
left: 14px;
transform-origin: left bottom;
transform: rotate(-45deg);
font-family: ui-monospace, 'JetBrains Mono', monospace;
font-size: 0.9em;
font-size: 0.85em;
color: var(--fg);
/* Rotate 90° bottom-to-top (conventional rotated column header). */
writing-mode: vertical-rl;
transform: rotate(180deg);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-height: 7.5em;
}
.schedules-table-agent-th > div > span {
display: inline-block;
padding: 0 4px 1px;
padding: 0 2px;
}
/* Column for an agent no longer in the live roster its past schedules
linger but the agent is gone. Greyed + struck through so the operator

View file

@ -5,6 +5,14 @@
body.logs-shell {
margin: 0;
padding: 0;
/* Full-viewport flex column so the log pane can scroll internally
instead of the whole page scrolling. The sticky-top wrapper and
page-header shrink to their natural height; .logs-main takes the
rest and each visible .logs-pane fills it. */
height: 100dvh;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Base tab styling now lives in @hive/shared/tabs.css (.hive-tab*). The
@ -18,10 +26,28 @@ body.logs-shell {
}
.logs-main {
padding: 1.2em 1.5em 2em;
padding: 1.2em 1.5em 0;
flex: 1 1 0;
min-height: 0;
display: flex;
flex-direction: column;
}
.logs-pane[hidden] { display: none; }
.logs-pane {
flex: 1 1 0;
min-height: 0;
display: flex;
flex-direction: column;
padding-bottom: 1.2em;
}
/* The AUDIT tab uses a <div> for its list instead of a <pre>, so give
it the same flex-grow + internal scroll that .journal-output already has. */
#audit-list {
flex: 1 1 0;
min-height: 0;
overflow-y: auto;
}
.logs-toolbar {
display: flex;

View file

@ -16,14 +16,27 @@ body.stats-shell {
padding: 1.2em 1.5em 2em;
}
/* Window selector. Buttons keep the shared `.btn` pill look; the active
one is flagged by createTabStrip via `.hive-tab--active` (was a bespoke
`.active` toggle). */
/* Window selector now lives in the page-header (same row as home /
ST4TS title). Fills the remaining header space and right-aligns the
buttons. The shared `.btn` pill look is kept; createTabStrip flags the
active one with `.hive-tab--active`. */
.hive-stats-windows {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin: 12px 0;
flex: 1;
min-width: 0;
justify-content: flex-end;
/* Smaller than the default .btn so the pills fit comfortably in the
header without competing visually with the page title. */
font-size: 0.82em;
}
/* Inactive buttons: slightly muted to distinguish from the active window,
but readable even on low-contrast operator colour schemes. */
.hive-stats-windows .btn {
color: var(--subtext1, var(--muted));
border-color: var(--border);
font-size: 1em; /* relative to the .hive-stats-windows 0.82em */
}
.hive-stats-windows .btn.hive-tab--active {
border-color: var(--amber);

View file

@ -18,15 +18,8 @@
<header class="page-header">
<a class="page-back" href="/">← home</a>
<span class="page-title">ST4TS</span>
</header>
<main class="stats-main">
<p class="meta">hive-wide turn statistics, aggregated across every agent over the selected window. <strong>cost is a rough estimate</strong> from approximate per-model list prices — it drifts and is a ballpark, not a bill.</p>
<!-- Window selector — a hash-routed createTabStrip (#1h / #24h / …),
like the per-agent /stats page. Buttons keep the `.btn` pill
look; createTabStrip toggles `.hive-tab--active` and the page
re-fetches on change via onShow. -->
<!-- Window selector lives in the header so it behaves like a tab strip
(matches the pattern on /logs.html). Hash-routed via createTabStrip. -->
<nav class="hive-stats-windows" id="hive-stats-windows" role="tablist">
<button type="button" class="btn" data-tab="1h">1h</button>
<button type="button" class="btn" data-tab="4h">4h</button>
@ -36,6 +29,10 @@
<button type="button" class="btn" data-tab="30d">30d</button>
<button type="button" class="btn" data-tab="all">all</button>
</nav>
</header>
<main class="stats-main">
<p class="meta">hive-wide turn statistics, aggregated across every agent over the selected window. <strong>cost is a rough estimate</strong> from approximate per-model list prices — it drifts and is a ballpark, not a bill.</p>
<div class="hive-stats-chips" id="hive-stats-summary"></div>
<h3>◇ busiest agents</h3>