diff --git a/CHANGELOG.md b/CHANGELOG.md index c05aa7e..8d84459 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/src/MandoCode.Desktop/Assets/web/transcript/transcript.css b/src/MandoCode.Desktop/Assets/web/transcript/transcript.css index b5176af..412a73f 100644 --- a/src/MandoCode.Desktop/Assets/web/transcript/transcript.css +++ b/src/MandoCode.Desktop/Assets/web/transcript/transcript.css @@ -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 @@ -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); @@ -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; @@ -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, @@ -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 diff --git a/src/MandoCode.Desktop/Services/TranscriptHtmlBuilder.cs b/src/MandoCode.Desktop/Services/TranscriptHtmlBuilder.cs index b920cb2..57dee3f 100644 --- a/src/MandoCode.Desktop/Services/TranscriptHtmlBuilder.cs +++ b/src/MandoCode.Desktop/Services/TranscriptHtmlBuilder.cs @@ -345,8 +345,18 @@ private static string ActivityIconAttribute(string? icon) => _ => "▶️", }; + /// + /// The per-turn token metric, as a pill rather than a trailing line of faint text. + /// + /// Note the wrapper is NOT chip-row, even though the pill inside is an ordinary + /// chip: drops every chip-row 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. + /// public string TokenSummary(string text) => - $"
{E(text)}
"; + $"
{E(text)}
"; public string HelpCard(IEnumerable<(string Command, string Description)> rows) {