- Shipped
- September 6, 2026 at 3:16 AM UTC
- Author
- Kamo
- Commit
- fbd28ea
Two additions to the same page, each in the pane it belongs to. **Custom Labels** grows a Ribbon Messages box: five rows, one per public pane screen, in the order a visitor meets them — sign in, or start signing up and branch into the member or team-member funnel; the apps site is its own front door. Each carries the Sync checkbox the label rows above it use, shown only for an org with a parent. The placeholder is the platform's own wording and is doing real work: an empty box does NOT produce a blank ribbon, it produces that line, and nothing else on the screen would say so. The read view falls back to it for the same reason — these screens always show a ribbon, so a blank row would describe something that does not happen. Unlike the label rows, the ribbons default to UNSYNCED for a child org. A branch inheriting its parent's word for "Business" is almost always what was meant; a branch that has never been asked has not implicitly asked to be greeted in its parent's words. Saving this pane now re-provisions the theme, because config.json is the only route these wordings take to kamo-login, kamo-register and kamo-apps. The server starts that and reports `reprovisioning`; we watch the org-scoped progress socket rather than firing our own /provision-theme, which a member with label rights but not branding rights would have been refused. **Branding** goes from two logo columns to three, on both the company and the software row. The switch under each is disabled until an icon is uploaded — greyed out with its reason beneath it, rather than vanishing, which reads as a bug — and accepting a file flips it on, matching what the upload endpoint does server-side. The caption under the SOFTWARE switch is computed live, and it is the reason tabIcon.ts exists as a tested module rather than a ternary buried in the JSX. That column's answer is a three-deep chain whose middle link is a switch in a DIFFERENT column of the same form ("Override company simple logo"), and the most likely case is the least guessable: that switch is off by default, so the usual answer is not "your software simple logo" but whatever the company column resolves to. Left unexplained the screen shows a disabled toggle and says nothing at all about what is used instead. It mirrors OrgThemeProvisionService's faviconSourceKey deliberately — this one runs against the unsaved form so the operator sees the outcome while deciding. faviconDir.ts picks which set to paint. Both conditions are required and the second is the one that matters: a surface selecting SOFTWARE for an org with no separate software icons must read favicon/, because favicon-software/ was never written and asking for it paints nothing at all. Tab icons preview correctly on a cold load, which the software simple logo still cannot — the stored extension is the existence marker that slot has never had.