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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,13 @@ for every approved plan. Desktop's version follows the engine generation, so it
a sticky header, or the suggestion list a field opens when it is filled.

### Fixed
- **The per-turn token count is readable in every theme.** It was faint text trailing at the right
edge, which put the smallest, palest thing on screen in the exact corner where the themes that
imitate a screen are darkest — measured at well under half the contrast it needed, and effectively
invisible on the CRT and amber terminal themes. It now sits in a small pill with its own
background and border, so it reads as a deliberate element rather than trailing text and survives
a busy chat wallpaper too. The corner shading on those themes was also too heavy in general and
has been eased, which helps ordinary text near the edges of the pane as well.
- **Secondary text is readable in every theme.** Timestamps, file paths, status lines and the hints
under headings were below the accessibility contrast floor in half the shipped themes — several
faithfully so, since palettes like Dracula and One Dark ship famously faint comment colours
Expand Down
28 changes: 23 additions & 5 deletions src/MandoCode.Desktop/Assets/web/transcript/transcript.css
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
linear-gradient(to bottom,
transparent calc(66.6% - 1px), rgba(0,0,0,0.30) 66.6%, transparent calc(66.6% + 1px)),
/* tube-edge vignette */
radial-gradient(ellipse 100% 100% at center, transparent 60%, rgba(0,0,0,0.55) 100%);
radial-gradient(ellipse 100% 100% at center, transparent 60%, rgba(0,0,0,0.34) 100%);
}
/* ---- Media-matched background image (Appearance toggle) -------------------------------
Opt-in, and off by default: a chat background in full colour sits perfectly well behind any of
Expand Down Expand Up @@ -279,7 +279,7 @@
content: ""; position: fixed; inset: 0; z-index: 9999; pointer-events: none;
background:
/* the smoked filter: darkest at the edges where the glass meets the bezel */
radial-gradient(ellipse 120% 120% at center, rgba(0,0,0,0) 55%, rgba(0,0,0,0.45) 100%),
radial-gradient(ellipse 120% 120% at center, rgba(0,0,0,0) 55%, rgba(0,0,0,0.28) 100%),
/* a faint vertical segment ruling — the grid the anodes are printed on */
repeating-linear-gradient(to right,
rgba(0,0,0,0.10) 0 1px, rgba(0,0,0,0) 1px 4px);
Expand Down Expand Up @@ -332,7 +332,7 @@
/* a scratch down the gate */
linear-gradient(to bottom, rgba(20,30,40,0.10) 0 100%),
/* the lens vignette — heavier than a tube's, because it is an optical edge, not a curve */
radial-gradient(ellipse 88% 92% at center, rgba(0,0,0,0) 42%, rgba(30,45,60,0.42) 100%);
radial-gradient(ellipse 88% 92% at center, rgba(0,0,0,0) 42%, rgba(30,45,60,0.26) 100%);
background-size: 100% 100%, 100% 100%, 100% 100%, 100% 100%, 100% 100%, 1px 100%, 100% 100%;
background-position: 0 0, 0 0, 0 0, 0 0, 0 0, 73% 0, 0 0;
background-repeat: no-repeat;
Expand Down Expand Up @@ -385,7 +385,7 @@
content: ""; position: fixed; inset: 0; z-index: 9999; pointer-events: none;
/* Tube glass only: a gentle centre-bright falloff, no grille and no scanlines. */
background: radial-gradient(ellipse 110% 110% at center,
rgba(120, 255, 160, 0.022) 0%, rgba(0,0,0,0) 55%, rgba(0,0,0,0.38) 100%);
rgba(120, 255, 160, 0.022) 0%, rgba(0,0,0,0) 55%, rgba(0,0,0,0.24) 100%);
}
/* Dense code under a wide bloom becomes a smear — same trade the CRT block makes. */
html[data-vector] pre, html[data-vector] pre *, html[data-vector] code,
Expand Down Expand Up @@ -563,7 +563,25 @@
.dim { color: var(--dim); }
.sky { color: var(--sky); }
.red { color: var(--red); }
.token-summary { text-align: right; font-size: 12px; }
/* The per-turn token metric. It used to be --dim text trailing at the right edge, and that put
the smallest, faintest thing in the app in the one place every themed overlay is darkest — its
corner vignette. Measured at 2.0-2.9:1 there, against a 4.5 floor.

A palette-level contrast floor cannot fix that, which is worth understanding: scanlines
attenuate UNIFORMLY, so a raised floor answers them, but a vignette attenuates by position, so
the very same colour passes mid-pane and fails in the corner. There is no value to pick.

So the metric gets a surface instead. On its own themed pill it carries its own background and
border, reads as a deliberate element rather than trailing text, and survives a busy chat
wallpaper — the same reasoning the plan-activity card already uses. De-emphasis now comes from
size and containment rather than from faintness, which is the durable way to do it: small and
bounded stays legible everywhere, whereas faint stops being legible the moment anything is
painted over it. */
.token-summary { text-align: right; margin: 2px 0; }
.token-chip { font-size: 11.5px; padding: 2px 11px; color: var(--fg);
/* The status-pill family pads to a shared 190px so those line up with each other. This one is
not part of that set and should hug its own text. */
min-width: 0; }

/* Live plan status is operationally important, not ordinary transcript narration. Give it a
high-opacity themed surface so a bright or busy chat wallpaper cannot wash out the active
Expand Down
12 changes: 11 additions & 1 deletion src/MandoCode.Desktop/Services/TranscriptHtmlBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -345,8 +345,18 @@ private static string ActivityIconAttribute(string? icon) =>
_ => "▶️",
};

/// <summary>
/// The per-turn token metric, as a pill rather than a trailing line of faint text.
///
/// <para>Note the wrapper is NOT <c>chip-row</c>, even though the pill inside is an ordinary
/// <c>chip</c>: <see cref="IsEphemeralStatus"/> drops every <c>chip-row</c> from a restored
/// session, on the grounds that status pills describe a dead process's live state. A token
/// count is the opposite — it is what that turn actually cost, and it belongs to the
/// conversation's history. Reusing the row class here would have silently deleted these from
/// every reopened session.</para>
/// </summary>
public string TokenSummary(string text) =>
$"<div class=\"line dim token-summary\">{E(text)}</div>";
$"<div class=\"token-summary\"><span class=\"chip token-chip\">{E(text)}</span></div>";

public string HelpCard(IEnumerable<(string Command, string Description)> rows)
{
Expand Down
Loading