{# The message chip (web-server-guide § Messaging): what wants your attention, and the way to read it. Lives in the fixed header inside `.app-who`, between the terminal and git chips — all three are state about *you* rather than about the page in the pane. There is no messages page, and that is the design. The spool exists so a *command* can tell staff something they must act on (`user` filing a key-authorization request), not so people can write to each other in a browser. So this chip reports, and every verb on it **types a real command into the web shell** — the same move the git chip's verbs and the account page's tool rows make, for the same reason: one execution path, one audit trail, and the command's own `requires()` is the boundary whatever this menu shows. Same <details class="menu"> chassis as Actions, git and the user pill: one menu idiom in the header, not four. `msg_spool` (render._context) is the switch: True only on a tier that actually serves /messages, so the auth service — which renders this same header and has no spool — gets the inert chip instead of a dead fetch. It is a plain flag, never a count: the header must not cost a spool read per navigation, so the number and the rows arrive from this element's own fetch a moment later. **This element swaps its CONTENTS, never itself** (`hx-swap="innerHTML"`, and the body lives in `_msg_menu.html`). With `outerHTML` the chip replaced the <details> on every fetch, and two things broke: the fresh element's own `hx-trigger="load"` fired again, so it re-fetched in a tight loop forever; and each swap reset `open`, so the menu shut a few milliseconds after any click. Keeping the element also keeps the `.term-offline` class site.js paints on it. The git chip has since settled on the same shape, for the second of those reasons: it too refreshes on being opened, and a chip that replaced itself would close the menu it had just been asked to answer. Three triggers, no polling: · `load` — once per document, so a full page load is always current; · `euler:message from:body` — the delivery nudge, pushed by euler-msg to this user's instance and relayed over the terminal's WebSocket as a TEXT frame (terminal.js → site.js). That is what makes a message arriving *now* show up now; · `toggle[this.open]` — opening the panel. The two above are pushes, and a push can be missed: the nudge rides the terminal's WebSocket, so a disconnected or hidden terminal silently drops it, and `load` has not fired since the last full document load. Opening the menu is the one moment a person is *asking* what is waiting, and it is exactly when the answer must not be a count from twenty minutes ago. The filter is what keeps it to opening — a bare `toggle` fires on close too, spending a fetch on a panel nobody is looking at any more. htmx calls the filter with the element as `this` (`r.call(elt, evt)`), so `this.open` reads the state the event just produced. `throttle:1s` because the trigger is a pointer away from being held down: it fires the first open and drops the rest of the second. Nobody reopens a menu inside a second expecting a different number, so it cannot show anything stale a person would notice. #}{%ifsubjectandmsg_spool%}<detailsid="msg-chip"class="menu msg-menu term-menu"hx-get="/messages"hx-swap="innerHTML"hx-trigger="load, euler:message from:body, toggle[this.open] throttle:1s">{%include"_msg_menu.html"%}</details>{%else%}{# Inert, never absent — signed out, or a tier with no spool. The header keeps its shape before the visitor is let in, exactly as the terminal and git chips do. No hx- attributes: the auth tier has no /messages route, and a dead fetch would be a promise nothing keeps. #}<spanclass="msg-chip is-locked"aria-disabled="true"title="no messages"><svgclass="msg-glyph"viewBox="0 0 24 24"aria-hidden="true"><rectx="2.5"y="5"width="19"height="14"rx="2"fill="none"stroke="currentColor"stroke-width="2"/><pathd="M3.5 7l8.5 6 8.5-6"fill="none"stroke="currentColor"stroke-width="2"stroke-linecap="round"stroke-linejoin="round"/></svg></span>{%endif%}