The dropdown was in the HTML all along and still could not be seen. Three
separate causes, found by measuring the rendered element rather than
trusting that the markup existed:
1. Clipped off-screen. The h1 is a flex row with no wrap. Measured at an
800px viewport: the language span started at x=620 and ended at x=810,
past the viewport edge, so only its first few pixels were painted. The
project badge alone took 309px. Adding flex-shrink and truncating the
badge did not fix it - there is genuinely no room in that row. The
selector now gets its own bar directly under the header, and the
project name ellipsises. Verified visible: x=181, right=341 in an
800px viewport, 34px tall.
2. Empty on every other page. base.html rendered the select from a
`languages` variable that almost no page supplies, so the login page
and the rest of the app showed a 38px-wide dropdown with zero options -
effectively invisible, and a dead control. Pages now opt in by
overriding a header_bar block. Verified /, /speakers, /chapters-audio
and /login all still render.
3. Browser cache made my own screenshot lie. It showed a stale Japanese
string containing the word "decisiveness" that is in no file on disk.
A cache-busted fetch confirmed the server is clean. Worth remembering:
a screenshot taken through a warm cache is not evidence.
The screenshot also exposed a data bug. All 12 sample utterances carried
type "narration" - including Kainda, Duchess Victoria, Deal Hunter, Nanny
and Trader Romano, who are all speaking. Every row rendered a narration
badge and the file told UmbraTrans that six characters were not speaking.
SHAPE in build_sample_translations.py now marks 6 dialogue / 6 narration,
and the generated JSONs are regenerated to match.
Also removed a misleading issue. It reported "12 rendered clips have no
staleness marker" as a translation problem; the markers are absent because
render_lang_test.py does not write them, so it was sending the reader after
a defect that does not exist. Replaced with the honest one: only 12 of
4,319 translated and none confirmed - sample only, not publishable.
Suite: 721 passed, 8 pre-existing. ruff clean on changed regions.