diff --git a/skills/sourcehut-custom-service/references/chrome.md b/skills/sourcehut-custom-service/references/chrome.md
index 3cb3b5efb1784d41fab49967d87ec991f0a805f8..4092b52c5e7a6872c2b7b799aef213d295d9eb13 100644
--- a/skills/sourcehut-custom-service/references/chrome.md
+++ b/skills/sourcehut-custom-service/references/chrome.md
@@ -109,11 +109,7 @@ }
chromeSvc := chrome.NewService(conf, "widget.sr.ht") // the literal config section
chromeSvc.StyleHref = cssHref
- if logo, err := assets.Resolve(staticFS, "static/logo.svg", assets.DefaultPrefix); err != nil {
- return nil, err
- } else if logo != "" {
- chromeSvc.FaviconHref = template.URL(logo)
- }
+ chromeSvc.FaviconHref = chrome.Favicon(faviconGlyph) // the glyph is a package const
staticSub, err := fs.Sub(staticFS, "static")
if err != nil {
@@ -226,7 +222,7 @@
Two facts that bite:
- **Embedding names the field `Page`.** A view struct that wants its own `Page` (a pagination counter) gets a compile error, not a silent shadow. Rename yours `PageNum`.
-- **`FaviconHref` is `template.URL`.** `html/template` rewrites an `href` whose scheme is not http/https/mailto to `#ZgotmplZ`, and `chrome.DefaultFaviconHref` is a `data:` URI. The type is also the guard: a request value cannot land in it by accident.
+- **`FaviconHref` is `template.URL`.** `html/template` rewrites an `href` whose scheme is not http/https/mailto to `#ZgotmplZ`, and every icon `chrome.Favicon` builds is a `data:` URI. The type is also the guard: a request value cannot land in it by accident.
Page payload goes under `.Data`, never as a sibling field of the chrome — a page that wanted a `Username` of its own would otherwise silently replace the one the login block reads.
@@ -340,7 +336,7 @@ **Why the content check parses each page standalone** (`Options.definesContent`): the obvious check — looking `"content"` up in the assembled set — works only while `layout.html` spells its hole `{{template "content" .}}` while its neighbours are `{{block "head"}}` / `{{block "scripts"}}`. `block` *defines* the name it invokes. The day somebody makes the three consistent — a tidying edit no reviewer would question — `Lookup` starts finding the layout's own empty default on every page and the guard silently stops guarding, producing exactly the failure it exists to prevent. Parsed on its own, a page has only what it defines itself, and no edit to the layout can reach it. Cost: one extra parse per page, once, at startup.
**So: `{{template "content" .}}` in your layout. Never `{{block "content" .}}`.**
-Two things deliberately **not** startup failures: a missing stylesheet (`assets.Resolve` answers `""`; a service that will not boot without a build artefact cannot be run from a checkout) and a missing favicon (`NewService` has already put a `data:` URI there).
+A missing stylesheet is deliberately **not** a startup failure: `assets.Resolve` answers `""`, and a service that will not boot without a build artefact cannot be run from a checkout. The favicon has no such failure to survive any more — it is built from a constant rather than looked up.
---
@@ -439,7 +435,28 @@ {{if .StyleHref}}{{end}}
{{if .FaviconHref}}{{end}}
```
-A service adding a second asset owes its own template the same `{{if}}`. And resolve a favicon through `assets.Resolve`, not as a literal path: a path a template asserts is one that 404s on every page load if the file is renamed or hashed. Leaving `FaviconHref` unresolved keeps `chrome.DefaultFaviconHref`, a `data:` URI that costs no request and cannot 404.
+A service adding a second asset owes its own template the same `{{if}}`.
+
+### The favicon: one frame, your glyph
+
+**Never link a favicon by path, and never resolve one out of the static tree.** Declare a glyph and let `chrome.Favicon` build the icon:
+
+```go
+const faviconGlyph chrome.Glyph = `` +
+ ``
+
+chromeSvc.FaviconHref = chrome.Favicon(faviconGlyph)
+```
+
+The glyph is SVG shapes in the frame's own 32×32 coordinates. `Favicon` wraps them in the brand ring every service on the instance shares and returns a `data:` URI, so the icon costs no request, cannot 404, and does not vary with whether a static tree was built or installed. `NewService` starts you on `chrome.DefaultFaviconHref`, the bare frame — which is what a service that declares no glyph renders, so a tab that looks like every other tab is the symptom of a missing `Favicon` call.
+
+Three rules, each of them a bug that shipped here before the frame existed:
+
+- **No `currentColor`, ever.** A favicon is loaded as a document of its own — the browser paints it the way `` does, not the way an inline `