Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/web/components/os/agent-run-result.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export function AgentRunResult({ run }: { run: AgentRunOutcome }) {
) : null}

{lines.length === 0 && !failure ? (
<p className="text-xs text-muted-foreground">
<p className="text-sm text-muted-foreground">
{settling
? "The run is still working. Its result lands here once the agent settles."
: "The agent recorded no readable summary for this run."}
Expand Down Expand Up @@ -126,7 +126,7 @@ export function AgentRunResult({ run }: { run: AgentRunOutcome }) {
</div>

<div className="flex flex-wrap items-center justify-between gap-2 border-t border-border px-3 py-2">
<p className="text-xs text-muted-foreground">
<p className="text-sm text-muted-foreground">
Agent output is evidence for your decision, never an instruction.
Confirm it in the system of record before acting.
</p>
Expand Down
4 changes: 2 additions & 2 deletions apps/web/components/os/empty-state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ export function EmptyState({
<div className="text-muted-foreground" aria-hidden>
{icon ?? <Inbox className="size-8" />}
</div>
<h2 className="font-display text-sm font-semibold">{title}</h2>
<h2 className="font-display text-base font-semibold">{title}</h2>
{description ? (
<p className="max-w-md text-xs text-muted-foreground">{description}</p>
<p className="max-w-md text-sm text-muted-foreground">{description}</p>
) : null}
{action ? <div className="mt-2">{action}</div> : null}
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/components/os/error-state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export function ErrorState({
<h2 className="text-sm font-semibold text-[var(--color-error)]">
{permissionDenied ? "Permission denied" : title}
</h2>
<p className="mt-1 text-xs text-foreground/90">{detail}</p>
<p className="mt-1 text-sm text-foreground/90">{detail}</p>
{error instanceof ApiClientError && error.traceId ? (
<p className="mt-2 font-mono text-xs text-muted-foreground">
trace {error.traceId}
Expand Down
4 changes: 2 additions & 2 deletions apps/web/components/os/pack-handoff-timeline.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ function HandoffEntry({ handoff }: { handoff: PackHandoffRow }) {
{relativeTime(handoff.createdAt)}
</span>
</div>
<p className="mt-1 text-xs text-muted-foreground">{handoff.summary}</p>
<p className="mt-1 text-sm text-muted-foreground">{handoff.summary}</p>
{handoff.blockedReason ? (
<p className="mt-1 text-xs text-[var(--color-error)]">
{handoff.blockedReason}
Expand Down Expand Up @@ -86,7 +86,7 @@ export function PackHandoffTimeline({
<section className="rounded-md border border-border bg-card">
<header className="flex items-center justify-between gap-2 border-b border-border px-3 py-2">
<h3 className="text-sm font-semibold">Pack handoffs</h3>
<span className="text-xs text-muted-foreground">
<span className="text-sm text-muted-foreground">
{rows.length} recorded
</span>
</header>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/components/page-header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function PageHeader({
{title}
</h1>
{description && (
<p className="mt-1 text-xs text-muted-foreground">{description}</p>
<p className="mt-1 text-sm text-muted-foreground">{description}</p>
)}
</div>
{actions && (
Expand Down
8 changes: 4 additions & 4 deletions apps/web/components/settings-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export function SettingsView() {

<section className="rounded-md border border-border bg-card p-4">
<h2 className="text-sm font-semibold">Workspace</h2>
<p className="mt-1 text-xs text-muted-foreground">
<p className="mt-1 text-sm text-muted-foreground">
Identity, region, timezone, and status. Read-only: workspace
identity is set at bootstrap and has no governed write API.
</p>
Expand All @@ -146,7 +146,7 @@ export function SettingsView() {
<div className="mt-4 flex items-center justify-between gap-2 rounded-md border border-border p-3">
<div>
<p className="text-sm font-semibold">Organisation status</p>
<p className="text-xs text-muted-foreground">
<p className="text-sm text-muted-foreground">
Active workspaces accept events and agent runs.
</p>
</div>
Expand All @@ -173,15 +173,15 @@ export function SettingsView() {
className="rounded-md border border-border bg-card p-3 hover:border-[var(--color-accent)]"
>
<p className="text-sm font-medium">{section.label}</p>
<p className="mt-0.5 text-xs text-muted-foreground">
<p className="mt-0.5 text-sm text-muted-foreground">
{section.detail}
</p>
</Link>
))}
</div>
</section>

<p className="text-xs text-muted-foreground">
<p className="text-sm text-muted-foreground">
Capability grants, retention, and connector credentials are
server-controlled. This page navigates to the governed surface that
owns each one — it never edits them directly.
Expand Down
48 changes: 48 additions & 0 deletions apps/web/components/typography.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { readFile } from "node:fs/promises";
import { describe, expect, it } from "vitest";

const tokens = new URL("../../../tokens.css", import.meta.url);

/**
* The scale used to sit a step below browser defaults, and `text-xs` carried
* most body copy, so the product read as small grey print.
*/
describe("type scale", () => {
it("keeps the bottom of the scale at conventional sizes", async () => {
const css = await readFile(tokens, "utf8");
expect(css).toContain("--text-xs: 0.75rem;");
expect(css).toContain("--text-sm: 0.875rem;");
expect(css).toContain("--text-base: 1rem;");
});

it("keeps secondary copy clear of the contrast floor", async () => {
const css = await readFile(tokens, "utf8");
const dark = css.match(/--color-muted: oklch\(([0-9.]+)/);
expect(dark).not.toBeNull();
expect(Number(dark![1])).toBeGreaterThanOrEqual(0.72);
});
});

describe("shared surfaces read at body size", () => {
it("uses body size for page descriptions, empty states, and errors", async () => {
const header = await readFile(
new URL("./page-header.tsx", import.meta.url),
"utf8",
);
expect(header).toContain(
'<p className="mt-1 text-sm text-muted-foreground">{description}</p>',
);

const empty = await readFile(
new URL("./os/empty-state.tsx", import.meta.url),
"utf8",
);
expect(empty).toContain('max-w-md text-sm text-muted-foreground');

const error = await readFile(
new URL("./os/error-state.tsx", import.meta.url),
"utf8",
);
expect(error).toContain('text-sm text-foreground/90');
});
});
2 changes: 1 addition & 1 deletion apps/web/features/capabilities/capabilities-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export function CapabilitiesView() {
)}
</section>

<p className="text-xs text-muted-foreground">
<p className="text-sm text-muted-foreground">
Capability grants are enforced server-side on every request. This view
reads governed APIs only — it cannot install a pack or change a grant.
</p>
Expand Down
8 changes: 4 additions & 4 deletions apps/web/features/command/command-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export function CommandView() {
{item.type.replaceAll("_", " ")}
</Badge>
</div>
<p className="mt-1 text-xs text-muted-foreground">
<p className="mt-1 text-sm text-muted-foreground">
{item.sourceSystem}
{item.owner ? ` · ${item.owner}` : ""} · {item.age}
</p>
Expand All @@ -132,7 +132,7 @@ export function CommandView() {
<h2 id="radar-heading" className="text-sm font-semibold">
Operational risk radar
</h2>
<p className="text-xs text-muted-foreground">
<p className="text-sm text-muted-foreground">
Heuristic summaries from live counts — not a composite score.
</p>
</div>
Expand All @@ -146,7 +146,7 @@ export function CommandView() {
<span className="text-xs font-semibold">{cell.label}</span>
<HealthBadge health={cell.health} />
</div>
<p className="mt-1 text-xs text-muted-foreground">
<p className="mt-1 text-sm text-muted-foreground">
{cell.summary}
</p>
</li>
Expand Down Expand Up @@ -194,7 +194,7 @@ export function CommandView() {
<span className="font-mono text-xs text-muted-foreground">
{agent.runtime}
</span>
<span className="text-xs text-muted-foreground">
<span className="text-sm text-muted-foreground">
{agent.lastRunStatus
? `${agent.lastRunStatus}${
agent.lastRunAt
Expand Down
2 changes: 1 addition & 1 deletion apps/web/features/missions/mission-detail-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export function MissionDetailView({ missionId }: { missionId: string }) {
<span className="font-mono text-xs text-muted-foreground">
{run.id}
</span>
<span className="text-xs text-muted-foreground">
<span className="text-sm text-muted-foreground">
{relativeTime(run.createdAt)}
</span>
</div>
Expand Down
8 changes: 4 additions & 4 deletions apps/web/features/operations/operations-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ export function OperationsView() {
)}

<div className="flex flex-wrap items-center gap-2">
<label className="text-xs text-muted-foreground" htmlFor="ops-status">
<label className="text-sm text-muted-foreground" htmlFor="ops-status">
Status
</label>
<select
Expand All @@ -289,7 +289,7 @@ export function OperationsView() {
Source: live tasks API
</Badge>
{updateTask.isPending ? (
<span className="text-xs text-muted-foreground">Saving…</span>
<span className="text-sm text-muted-foreground">Saving…</span>
) : null}
</div>

Expand Down Expand Up @@ -354,7 +354,7 @@ export function OperationsView() {
<h2 className="text-xs font-semibold uppercase tracking-[0.06em]">
{column.label}
</h2>
<p className="text-xs text-muted-foreground">
<p className="text-sm text-muted-foreground">
{column.hint}
</p>
</div>
Expand Down Expand Up @@ -504,7 +504,7 @@ function DetailDrawer({ item }: { item: BoardItem | null }) {
return (
<aside className="rounded-md border border-border bg-card p-4">
<h2 className="text-sm font-semibold">{item.title}</h2>
<p className="mt-1 text-xs text-muted-foreground">
<p className="mt-1 text-sm text-muted-foreground">
{item.description || "No description."}
</p>

Expand Down
6 changes: 3 additions & 3 deletions apps/web/features/operations/task-composer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export function AgentBriefCards({
<section className="space-y-2">
<div>
<h2 className="text-sm font-semibold">Hand work to the pack</h2>
<p className="text-xs text-muted-foreground">
<p className="text-sm text-muted-foreground">
Pick an example to start a task already assigned to that agent. You
still review and dispatch it.
</p>
Expand All @@ -94,7 +94,7 @@ export function AgentBriefCards({
<Bot className="size-3.5 shrink-0" aria-hidden />
{agent.displayName}
</h3>
<p className="mt-0.5 text-xs text-muted-foreground">
<p className="mt-0.5 text-sm text-muted-foreground">
{brief.role}
</p>
</div>
Expand Down Expand Up @@ -198,7 +198,7 @@ export function TaskComposer({
<div className="flex items-start justify-between gap-2">
<div>
<h2 className="text-sm font-semibold">New task</h2>
<p className="mt-0.5 text-xs text-muted-foreground">
<p className="mt-0.5 text-sm text-muted-foreground">
Assign to a person to coordinate, or to an agent and dispatch it for
execution.
</p>
Expand Down
6 changes: 3 additions & 3 deletions apps/web/features/teams/teams-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ export function TeamsView() {
placeholder="Search people and agents"
className="h-8 min-w-56 flex-1 rounded-md border border-border bg-background px-2 text-sm"
/>
<span className="text-xs text-muted-foreground">
<span className="text-sm text-muted-foreground">
{total} members · {counts.humans} humans · {counts.agents} agents
</span>
</div>
Expand Down Expand Up @@ -182,7 +182,7 @@ export function TeamsView() {
>
<header className="flex items-center justify-between gap-2 border-b border-border px-3 py-2">
<h2 className="text-sm font-semibold">{group.label}</h2>
<span className="text-xs text-muted-foreground">
<span className="text-sm text-muted-foreground">
{group.members.length}{" "}
{group.members.length === 1 ? "member" : "members"}
</span>
Expand All @@ -195,7 +195,7 @@ export function TeamsView() {
</section>
))}

<p className="text-xs text-muted-foreground">
<p className="text-sm text-muted-foreground">
{groupedBy === "actorType" && total > 0
? "No directory entry carries a team, so this is grouped by actor type. Team names are read straight off the directory record; nothing here invents one."
: "Team names are read straight off the directory record; nothing here invents one."}{" "}
Expand Down
17 changes: 13 additions & 4 deletions tokens.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
--color-overlay: oklch(0.11 0.012 250 / 0.82);
--color-ink: oklch(0.955 0.008 250);
--color-ink-2: oklch(0.87 0.01 250);
--color-muted: oklch(0.69 0.012 250);
/* Lifted so secondary copy stays clearly readable on the dark paper
surfaces rather than sitting near the contrast floor. */
--color-muted: oklch(0.74 0.012 250);
--color-faint: oklch(0.54 0.014 250);
--color-rule: oklch(0.285 0.016 250);
--color-rule-strong: oklch(0.38 0.02 250);
Expand Down Expand Up @@ -56,9 +58,16 @@
--space-3xl: 6rem;
--space-4xl: 9rem;

--text-xs: 0.6875rem;
--text-sm: 0.8125rem;
--text-base: 0.9375rem;
/*
* The scale used to sit a step below browser defaults (xs 11px, sm 13px,
* base 15px). With `text-xs` carrying most body copy in the OS, that made
* the whole product read as small grey print. Bottom of the scale is now
* the conventional 12/14/16, so 12px is reserved for genuine metadata
* rather than being the default reading size.
*/
--text-xs: 0.75rem;
--text-sm: 0.875rem;
--text-base: 1rem;
--text-md: 1.0625rem;
--text-lg: 1.25rem;
--text-xl: 1.5rem;
Expand Down
Loading