Follow-up to #1016 (host clipping + svg { display: block }), which fixed the two overflow classes where they were user-visible. Three remaining items, in descending priority.
1. Four components still have the inline-SVG line-box gap
bearing-indicator, compass-indicator, gauge-horizontal, gauge-vertical render an in-flow inline <svg> with no display: block (audited on develop @ next.122, 2026-08-11 — these are the only four left). Same phantom-height mechanism #1016 fixed for watch, watch-flat and thruster: an inline svg participates in a text line box and reserves ~3–5px of descender space below the graphic, which surfaces as mystery scrollbars / extra height in overflow: auto cells. Their indicator/gauge siblings already carry display: block, so this is aligning stragglers with the established pattern. Expected: zero-pixel snapshot change (the gap is phantom layout height only), as verified for #1016's hunks.
2. One-line docs checklist addition
docs/agents/watch-radial-instruments.md now documents the mechanism ("Host clipping & the arrow-apex shave"), but the new-feature checklist at the bottom doesn't tell the author of a new instrument when the rule applies. Add a checklist line along the lines of: "Rotating an <svg> element box (transform="rotate(...)" on the element)? The host must clip — see Host clipping & the arrow-apex shave." (Edit the source in docs/agents/, then npm run agents:sync.)
3. Decide-by-measurement: inner-<g> rotation refactor
Recording the alternative considered and deliberately not taken in #1016, so it isn't re-discovered later without its trade-offs.
obc-watch (root svg) and obc-compass-sector (overlay svg) are the only two element-box rotations in the codebase. Moving the rotation into an inner <g> would keep the element box axis-aligned, so the svg's own viewport clip would contain all painted content by construction — removing the leak half of the host-clip requirement.
Why it wasn't done in #1016:
- Identical pixels. The svg viewport edge and the host box edge are the same edge — even the compass-sector arrow-apex shave is unchanged. Zero user-visible improvement.
- Baseline churn on the most sensitive shared file. Every rotating story risks AA-level shifts that each need review.
- Open performance question — the reason this item exists. A
transform on the svg element is a CSS transform: browsers can update it compositor-side without re-rasterizing vector content. Rotation inside a <g> forces a full SVG re-raster per heading update. With continuously streaming heading data and several instruments per screen on low-power bridge hardware, that difference may be material — or negligible. Nobody has measured it.
Exit criterion: profile both variants under realistic load (several rotating instruments at ~10 Hz heading updates on a low-end target). If inner-<g> is not measurably worse, it's a legitimate hardening refactor to schedule; if it is worse, close this item — the host-clip contract stays the long-term answer (a component never paints outside its box: :host { overflow: hidden }, plus display: block for in-flow svgs).
Context: the "Host clipping & the arrow-apex shave (PR #1016)" section in docs/agents/watch-radial-instruments.md, and the verification comments on #1016.
Follow-up to #1016 (host clipping +
svg { display: block }), which fixed the two overflow classes where they were user-visible. Three remaining items, in descending priority.1. Four components still have the inline-SVG line-box gap
bearing-indicator,compass-indicator,gauge-horizontal,gauge-verticalrender an in-flow inline<svg>with nodisplay: block(audited ondevelop@ next.122, 2026-08-11 — these are the only four left). Same phantom-height mechanism #1016 fixed for watch, watch-flat and thruster: an inline svg participates in a text line box and reserves ~3–5px of descender space below the graphic, which surfaces as mystery scrollbars / extra height inoverflow: autocells. Their indicator/gauge siblings already carrydisplay: block, so this is aligning stragglers with the established pattern. Expected: zero-pixel snapshot change (the gap is phantom layout height only), as verified for #1016's hunks.2. One-line docs checklist addition
docs/agents/watch-radial-instruments.mdnow documents the mechanism ("Host clipping & the arrow-apex shave"), but the new-feature checklist at the bottom doesn't tell the author of a new instrument when the rule applies. Add a checklist line along the lines of: "Rotating an<svg>element box (transform="rotate(...)"on the element)? The host must clip — see Host clipping & the arrow-apex shave." (Edit the source indocs/agents/, thennpm run agents:sync.)3. Decide-by-measurement: inner-
<g>rotation refactorRecording the alternative considered and deliberately not taken in #1016, so it isn't re-discovered later without its trade-offs.
obc-watch(root svg) andobc-compass-sector(overlay svg) are the only two element-box rotations in the codebase. Moving the rotation into an inner<g>would keep the element box axis-aligned, so the svg's own viewport clip would contain all painted content by construction — removing the leak half of the host-clip requirement.Why it wasn't done in #1016:
transformon the svg element is a CSS transform: browsers can update it compositor-side without re-rasterizing vector content. Rotation inside a<g>forces a full SVG re-raster per heading update. With continuously streaming heading data and several instruments per screen on low-power bridge hardware, that difference may be material — or negligible. Nobody has measured it.Exit criterion: profile both variants under realistic load (several rotating instruments at ~10 Hz heading updates on a low-end target). If inner-
<g>is not measurably worse, it's a legitimate hardening refactor to schedule; if it is worse, close this item — the host-clip contract stays the long-term answer (a component never paints outside its box::host { overflow: hidden }, plusdisplay: blockfor in-flow svgs).Context: the "Host clipping & the arrow-apex shave (PR #1016)" section in
docs/agents/watch-radial-instruments.md, and the verification comments on #1016.