Problem
Editor presentation is assembled as a chain of symptom patches rather than a model of how an editor canvas differs from the frontend. NavigationStyleProjector::materializeEditorStaticStateStylesheet() currently holds six unrelated concerns, each guarded by its own ad-hoc condition, and each written with !important:
if ( '' !== $anchorProjectionCss ) { ... } // anchor projection
if ( preg_match('/animation.../', $authorCss) ) { ... } // freeze animations
if ( $runtimeBehavior->emptyRuntimeTargetGenerated() ) { ... } // dynamic-content placeholder
if ( $runtimeBehavior->emptyVisualGroupGenerated() ) { ... } // painted-layer placeholder
if ( preg_match('/\bbody\b[^{}]*\{[^}]*overflow.../', $authorCss) ) // body overflow repair
foreach ( $styleResolver->closedStateRepairCssRules() ... ) // closed-state repair
Two consequences:
- Coverage is limited to symptoms already discovered. Anything not yet reported stays misplaced, because there is no model that would predict it.
- Decisions are made by sniffing author CSS with regular expressions (for example matching
body { ... overflow ... } as text) rather than by consulting the site plan. That is fragile against equivalent-but-differently-written source CSS.
The method also lives in a class named for navigation while owning none of these concerns.
Expected contract
An editor canvas differs from the rendered frontend in exactly three ways. Derive the generated editor stylesheet from those, and have every emitted rule declare which one it addresses.
- Containment — the canvas is a bounded, non-viewport container. Geometry expressed against the viewport does not track it. This is the same class of defect as viewport-anchored media geometry: a value that is correct only while its container happens to match the viewport.
- Inert runtime — scripts are absent, so any runtime-driven state (entrance animation, open/closed disclosure, dynamically populated region) must resolve to a defined static state.
- Block chrome — the editor injects wrappers, placeholders, and variation pickers that the source composition never contained, and which occupy layout the source did not allocate.
Inputs should come from the site plan and the transform's own recorded behaviour, so the emitter reasons about known facts instead of re-detecting them from stylesheet text.
Acceptance
- Every generated editor rule is attributable to containment, inert runtime, or block chrome.
- Editor decisions read recorded transform/site-plan state rather than pattern-matching author CSS text.
- Editor projection lives in a class that owns editor presentation, not in the navigation projector.
- Rules stop relying on
!important to defeat author CSS, except where a source declaration is itself !important.
- The 292 parity fixtures pass unchanged.
- A generated site opens in the editor with source composition intact: no injected picker occupying source layout, and no element positioned by a viewport-anchored value inside the bounded canvas.
Related
AI assistance disclosure
This issue was researched and written with AI assistance: Claude Sonnet 4.5 running in the opencode CLI agent. The AI read the editor stylesheet assembly path, enumerated the six concerns and the regex-driven conditions quoted above, and drafted the proposed three-axis contract. A human reviewed and directed the simplification framing.
Problem
Editor presentation is assembled as a chain of symptom patches rather than a model of how an editor canvas differs from the frontend.
NavigationStyleProjector::materializeEditorStaticStateStylesheet()currently holds six unrelated concerns, each guarded by its own ad-hoc condition, and each written with!important:Two consequences:
body { ... overflow ... }as text) rather than by consulting the site plan. That is fragile against equivalent-but-differently-written source CSS.The method also lives in a class named for navigation while owning none of these concerns.
Expected contract
An editor canvas differs from the rendered frontend in exactly three ways. Derive the generated editor stylesheet from those, and have every emitted rule declare which one it addresses.
Inputs should come from the site plan and the transform's own recorded behaviour, so the emitter reasons about known facts instead of re-detecting them from stylesheet text.
Acceptance
!importantto defeat author CSS, except where a source declaration is itself!important.Related
AI assistance disclosure
This issue was researched and written with AI assistance: Claude Sonnet 4.5 running in the opencode CLI agent. The AI read the editor stylesheet assembly path, enumerated the six concerns and the regex-driven conditions quoted above, and drafted the proposed three-axis contract. A human reviewed and directed the simplification framing.