` element with `text-lg lg:text-xl leading-relaxed` containing `wp_kses_post( $intro )`. No new fields, no new CSS file — Tailwind utilities cover the layout. ## page.php Wiring `page.php` changes from rendering the body directly to: 1. Output the article container (existing behavior). 2. If `get_field( 'intro' )` is non-empty, call `get_template_part( 'views/partials/page-intro' )` **as a sibling of** the `entry-content` div (not inside it). The intro must be a peer of the body in the layout flow, not a child, so the test's order assertion `introBox.y < contentBox.y` holds (when intro is a child of entry-content, the two bounding boxes share the same top y and the order check fails). 3. Render `the_content` (existing behavior). 4. Render the sidebar if `hasSidebar()` (existing behavior). The hero is still rendered by `header.php` before this template runs. No other behavior changes. ## Data Flow - Editor experience: on every page (and post) edit screen, the existing Page Heading meta box shows the existing fields plus two new ones (Hero Image, Vector). The editor uploads the assets, sets a background color if desired, writes the optional heading override, intro, and CTAs, then writes the body in the standard block editor. - Render: `header.php` loads the page-hero partial → `page.php` loads the page-intro partial (if intro is set) → `the_content` renders the body blocks. - Per-page variation: hero image, vector, intro text, and body content. Everything else is shared. ## Error Handling and Edge Cases - `hero_image` empty → hero uses the existing dark background color (or the default dark text-only style). - `hero_vector` empty → no vector renders; the right side of the hero is empty space. - `intro` empty → page-intro partial is not loaded; the page goes straight from hero to body. - `heading` empty → falls back to `getTheTitle()` (existing behavior, unchanged). - Background color set without a hero image → existing behavior; no change. - No sidebar field set → existing `hasSidebar()` filter returns false → no sidebar (existing behavior). - Lazy-loaded images must await `load`/`complete` before Playwright reads dimensions (existing project convention; see `tests/mobile-homepage.spec.js:641`). ## Out of Scope - New ACF blocks. This layout uses the existing Page Heading meta box, not the block editor. - Front page, single posts, archives, search, 404 changes. - Homepage-hero block changes. - The contact-block, pull-quote, our-work, or other existing blocks. - A new contact CTA block in the page body. The mockup's bottom dark block is the existing site footer. - Migration of existing pages' content. ## Verification - Add `tests/inner-page.spec.js` covering: - Desktop (1280px): hero, intro, body render in that order. When hero image is set, it is visible behind the hero. When vector is set, it sits on the right of the hero. - Mobile (402px): same order. Vector fills the lower portion of the hero. Intro is centered and within the 48rem max-width. No clipped text. - 320px and 767px: nothing clips, vector scales proportionally, intro remains readable. - A page with no `intro` field renders hero + body with no empty intro wrapper. - A page with no `hero_image` and no `hero_vector` renders the existing dark text-only hero unchanged. - Add a test page fixture (or use an existing page) to drive the test. If no fixture exists, the test seeds a page in a `beforeAll` and tears it down in `afterAll`. - Run `npm run build` to regenerate `static/dist/`. - Run the full Playwright suite (`npx playwright test`) — including the existing `tests/mobile-homepage.spec.js` and `tests/site-a11y.spec.js` — to confirm no regressions. - Run `composer lint` to catch PHPCS issues. - Capture a 1280px and a 402px full-page screenshot of the test fixture for visual comparison against `notes/inner-page-mockup.png`. ## Acceptance Criteria 1. Every WordPress page renders the new layout when the page-hero partial is active. 2. The hero shows the page title (or heading override) and, when supplied, a background image and a decorative vector on the right. 3. When the `intro` field is set, a centered narrow column appears under the hero. When empty, it is omitted entirely (no empty wrapper). 4. The body renders `the_content` as before, with the standard block editor. 5. The hero background image is masked so text on the left remains readable at all viewports. 6. The vector scales proportionally from 320px through desktop and is repositioned below 768px to fill the lower portion of the hero. 7. The page renders without console errors, axe violations, or PHPCS errors. 8. Existing single posts, archives, search, and 404 pages render the page-hero partial unchanged. 9. Existing tests (`mobile-homepage`, `site-a11y`) continue to pass.