- Shipped
- September 9, 2026 at 10:19 PM UTC
- Author
- Kamo
- Commit
- 63f8e6c
The signing UI existed twice — here, and hand-copied into kamo-internal's legal execution wizard — and the two had drifted in both directions. `@kamo/esign-core`, `@kamo/esign-ui` and `@kamo/doc-render` are published packages now, built and pushed to the Forgejo registry by this repo's CI, and kamo-internal consumes them instead of its fork. The merge took the better half of each: kamo-internal's store (format validation, storage guarded on `localStorage` rather than on the DELEGATED and NOT_YET reasons). Components take their strings as PROPS — the two apps translate out of two different dictionaries, and a component that picks its own keys can only live in one. FOUR defects, and one of them caused two of the others: - **Every contained MUI button in this app was transparent.** `AppProviders` passed `enableCssLayer: true`, so all MUI CSS landed in `@layer mui` — and Tailwind's preflight, loaded unlayered by `@tailwind base`, beats layered CSS outright whatever the specificity. Measured: `.MuiButton-containedPrimary` computed `background-color: rgba(0,0,0,0)` with `color: rgba(0,0,0,0.87)`. So "Agree & continue" rendered as plain text, and "Cancel" and "Adopt & sign" sat next to each other as two runs of grey text reading as one sentence — which is exactly how it was reported. Preflight's `p { margin: 0 }` was beating the consent card's `mb` for the same reason, which is why everything on that page ran together. kamo-internal has always mounted its Emotion cache unlayered; matching it fixes all of it at once. - **The logo was a broken image.** `ThemeLogo` fell back to `/img/logo-full.svg`, which this app does not serve, and painted the browser's torn-page glyph in the sender's place. It now walks the extension list for BOTH variants (an org whose mark is a .png had `.svg` requested, 404ed, and stopped there — `sign-pink` is exactly that org), and when nothing resolves it draws the org's short name as a wordmark, or nothing at all before a token has named an organization. - **The favicon and the tab title were never set — nor was the org's brand CSS.** `DynamicMetaLoader` computed `const slug = orgSlug || getThemeSlug()` ONCE, in the effect body, before any token had been validated: `''`. The `KAMO_THEME_REAPPLY` listener, raised the moment the inviting org WAS known, re-ran a closure over that same `''` and returned at the guard. config.json was therefore never fetched on the signing route at all. Resolved per apply now, favicons REPLACE rather than append, and the title is "Sign - {Org Short Name}" as asked. Verified against a real tenant: `Sign - Sign Pink`, four org favicons, the .png mark, and `--color-primary: #452d4e` reaching the tabs, checkboxes and buttons — the MUI palette cannot hold a `var()`, so every brand-bearing component is pointed at it explicitly. - **The language picker was a globe over a list of endonyms**, so a signer who reads none of the Latin scripts had nothing to aim at. Flags and native names now, the same table and the same emoji font stack as kamo-internal's NavTop. It also appears on the welcome and consent screens: it used to arrive only with the TopBar, after the signer had already read an English disclosure. Downloads offer all three copies wherever one was offered: the executed document, the certificate of completion, or both zipped (`/api/sign/download?what=`). The certificate is the half of the record that attributes a signature to a person; handing over only the PDF hands over the half that proves nothing. The consent gate now carries the six clauses 15 U.S.C. § 7001(c) requires a consumer to be shown BEFORE consenting, and the locale it was rendered in rides out with the consent so the certificate can state which of the twenty-two translations was actually read.