Skip to content

refactor(css): strangler migration — FL export CSS retired page-by-page at pixel parity#365

Merged
pftg merged 26 commits into
masterfrom
css-migration/strangler-run
Jul 18, 2026
Merged

refactor(css): strangler migration — FL export CSS retired page-by-page at pixel parity#365
pftg merged 26 commits into
masterfrom
css-migration/strangler-run

Conversation

@pftg

@pftg pftg commented Jul 12, 2026

Copy link
Copy Markdown
Member

CSS strangler migration — FL burn-down 16/16 complete

Retires every FL-Builder export CSS file (16 files, ~73k lines of generated CSS) and replaces them with 16 hand-maintained css/pages/*.css files, at pixel parity: zero snapdiff baseline changes across the entire run, on both macOS and Linux.

Evidence bar (held on every commit)

  • Converged production build ×2; only the target bundle's content-hash fingerprint changed per commit
  • Compiled fragment diff: every removed fragment keys a dead fl-node or an attribute absent from the rendered page
  • Headless old-vs-new render compare: RMSE 0 at desktop (1280) + mobile (390), first fold AND full page
  • bin/rake test:critical + bin/dtest green per commit, zero screenshot baseline changes (the unchanged baselines are the parity proof)
  • Orphan-guard unit test green per commit

Commits (per-page atomic)

Commit Page(s) FL file(s) retired gz
R1 privacy-policy, course-list 3059-layout 17.1→14.1K / 17.6→14.2K
R2 contact-us 706-layout 18.9→17.4K
R3a–d blog-single, course-single, single-client, single-career 3114-layout, fb2624…, e966db44… 19.3→12.9K / 25.4→16.1K / 22.0→18.3K
R4a–b blog-list, free-consultation homepage-layout, services-layout, fl-builder-grid, free-consultation-critical 19.5→15.0K / 20.6→16.2K
R5 about-us 701-layout 19.4→15.0K
R6 careers 3086-layout2 (byte-identical move) unchanged
R7 use-cases, single-use-cases 3021-layout, 3027-layout 25.4→17.0K / 23.8→18.8K
R8a–c clients, single-service, services 3082, 2949, 737 + bf72bba… deleted (last consumer) 24.0→18.7K / 24.2→19.1K / 25.8→19.9K
R9 homepage 590-layout (12.4k lines, the last one) 30.1→26.6K

Plus: post-rebase revalidation after master's course v2 merge (#361) with a skip_area fix for a bimodal text-wrap flake in the new lesson-meta blockquote; pre-coverage screenshots added before each risky swap (careers newsletter, mobile use-cases ×2, mobile services ×2); blog special-content tests (mermaid/code/inline-style/youtube) and the CSS orphan-guard unit test from Phase 0.

Techniques

  • Semantic rewrites where markup was page-owned (R1, R2, R3a–c, R4a–b)
  • Option-A delta ports where shared partials/tests anchor on fl-node markup: media-aware dead-node prune of the FL file into pages/*.css, generics kept verbatim (R3d, R5–R9)
  • The bf72bba shared bundle left one slice per commit; its only live contribution (header CTA button, 3 rules) ported into use-cases/clients/services; about/single-service criticals carried byte-identical copies

Docs

css-bundle-ownership-map.md (final gz table + technique per file) and TASK-TRACKER.md (Phase 0 4/4, rewrites R1–R9, update log) updated in the last commit.

Follow-ups (non-blocking)

  • Shared css/testimonials.css extraction (source hygiene, byte-identical gate)
  • Per-page semantic re-keying of delta-ported markup (R3c alias technique) as independent sprints

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added refreshed page layouts and styling across blog, courses, client pages, contact, services, use cases, careers, and consultation pages.
    • Improved responsive presentation for forms, galleries, cards, navigation, tabs, reviews, and content grids.
    • Added simplified privacy policy, blog, course, and contact page structures.
  • Bug Fixes

    • Improved skip-link visibility and course title wrapping.
  • Tests

    • Expanded desktop and mobile visual coverage for special blog content, privacy policy, courses, careers, and client pages.
    • Added checks to detect missing or unused styles.

@coderabbitai

coderabbitai Bot commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@pftg, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 8 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b09a634a-7416-409b-a7c1-56a1adf9f2ac

📥 Commits

Reviewing files that changed from the base of the PR and between 1a9319f and 031cc04.

⛔ Files ignored due to path filters (70)
  • test/fixtures/screenshots/linux/desktop/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/codeblocks/bare.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/codeblocks/html.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/codeblocks/indented.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/codeblocks/js.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/codeblocks/md.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/codeblocks/python.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/codeblocks/ruby.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/codeblocks/text.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/inline_style_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/youtube_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/careers/_newsletter.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/codeblocks/bare.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/codeblocks/html.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/codeblocks/indented.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/codeblocks/js.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/codeblocks/md.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/codeblocks/python.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/codeblocks/ruby.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/codeblocks/text.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/careers/junior-ruby-on-rails-developer.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/privacy-policy.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/services.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/services/fractional_cto.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/use_cases.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/use_cases/startup-mvp-prototyping-development.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/codeblocks/bare.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/codeblocks/html.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/codeblocks/indented.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/codeblocks/js.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/codeblocks/md.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/codeblocks/python.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/codeblocks/ruby.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/codeblocks/text.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/inline_style_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/youtube_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/careers/_newsletter.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/codeblocks/bare.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/codeblocks/html.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/codeblocks/indented.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/codeblocks/js.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/codeblocks/md.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/codeblocks/python.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/codeblocks/ruby.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/codeblocks/text.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/careers/junior-ruby-on-rails-developer.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/privacy-policy.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/services.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/services/fractional_cto.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/use_cases.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/use_cases/startup-mvp-prototyping-development.png is excluded by !**/*.png
📒 Files selected for processing (85)
  • content/blog/codeblock-styles-fixture/index.md
  • docs/projects/2509-css-migration/TASK-TRACKER.md
  • docs/projects/2509-css-migration/css-bundle-ownership-map.md
  • layouts/course/list.html
  • test/system/blog_special_content_test.rb
  • test/system/components/diagram_component_test.rb
  • test/system/desktop_site_test.rb
  • test/system/mobile_site_test.rb
  • test/unit/css_orphan_guard_test.rb
  • themes/beaver/assets/css/3021-layout.css
  • themes/beaver/assets/css/3059-layout.css
  • themes/beaver/assets/css/3114-layout.css
  • themes/beaver/assets/css/706-layout.css
  • themes/beaver/assets/css/bf72bba397177a0376baed325bffdc75-layout-bundle.css
  • themes/beaver/assets/css/components/blocks/c-card.css
  • themes/beaver/assets/css/components/blocks/c-nav.css
  • themes/beaver/assets/css/components/buttons.css
  • themes/beaver/assets/css/components/c-feature-card--row2.css
  • themes/beaver/assets/css/components/c-infobox.css
  • themes/beaver/assets/css/components/c-modal.css
  • themes/beaver/assets/css/components/c-pagination.css
  • themes/beaver/assets/css/components/c-spacer.css
  • themes/beaver/assets/css/components/c-testimonial-section.css
  • themes/beaver/assets/css/components/c-testimonial-slider.css
  • themes/beaver/assets/css/components/cards-migration.css
  • themes/beaver/assets/css/components/forms-migration.css
  • themes/beaver/assets/css/components/pp-content-grid.css
  • themes/beaver/assets/css/components/pp-list.css
  • themes/beaver/assets/css/components/pp-tabs.css
  • themes/beaver/assets/css/components/typography.css
  • themes/beaver/assets/css/critical/free-consultation-critical.css
  • themes/beaver/assets/css/critical/privacy-policy-critical.css
  • themes/beaver/assets/css/critical/single-clients.css
  • themes/beaver/assets/css/e966db44b09892b8d7d492247c67e86c-layout-bundle.css
  • themes/beaver/assets/css/fb2624e43f3c4277448abe268cde571e-layout-bundle.css
  • themes/beaver/assets/css/homepage-layout.css
  • themes/beaver/assets/css/navigation.css
  • themes/beaver/assets/css/pages/about-us.css
  • themes/beaver/assets/css/pages/blog-list.css
  • themes/beaver/assets/css/pages/blog-single.css
  • themes/beaver/assets/css/pages/careers.css
  • themes/beaver/assets/css/pages/clients.css
  • themes/beaver/assets/css/pages/contact-us.css
  • themes/beaver/assets/css/pages/course-list.css
  • themes/beaver/assets/css/pages/free-consultation.css
  • themes/beaver/assets/css/pages/homepage.css
  • themes/beaver/assets/css/pages/services.css
  • themes/beaver/assets/css/pages/simple-page.css
  • themes/beaver/assets/css/pages/single-career.css
  • themes/beaver/assets/css/pages/single-client.css
  • themes/beaver/assets/css/pages/single-service.css
  • themes/beaver/assets/css/pages/single-use-cases.css
  • themes/beaver/assets/css/pages/use-cases.css
  • themes/beaver/assets/css/services-layout.css
  • themes/beaver/assets/css/utilities/clearfix.css
  • themes/beaver/assets/css/utilities/color-accessibility.css
  • themes/beaver/assets/css/utilities/colors.css
  • themes/beaver/assets/css/utilities/colors/backgrounds.css
  • themes/beaver/assets/css/utilities/components/powerpack/content-grid.css
  • themes/beaver/assets/css/utilities/components/powerpack/infobox.css
  • themes/beaver/assets/css/utilities/components/powerpack/pp-icon.css
  • themes/beaver/assets/css/utilities/components/powerpack/pp-list.css
  • themes/beaver/assets/css/utilities/fl-builder-grid.css
  • themes/beaver/assets/css/utilities/opacity.css
  • themes/beaver/assets/css/utilities/typography/text-utilities.css
  • themes/beaver/layouts/blog/list.html
  • themes/beaver/layouts/clients/single.html
  • themes/beaver/layouts/course/single.html
  • themes/beaver/layouts/list.html
  • themes/beaver/layouts/page/about.html
  • themes/beaver/layouts/page/clients.html
  • themes/beaver/layouts/page/contact-us.html
  • themes/beaver/layouts/page/free-consultation.html
  • themes/beaver/layouts/page/services.html
  • themes/beaver/layouts/page/single.html
  • themes/beaver/layouts/page/use-cases.html
  • themes/beaver/layouts/partials/assets/blog-list-css-resources.html
  • themes/beaver/layouts/partials/assets/careers-css-resources.html
  • themes/beaver/layouts/partials/assets/contact-us-css-resources.html
  • themes/beaver/layouts/partials/assets/free-consultation-css-resources.html
  • themes/beaver/layouts/partials/assets/homepage-css-resources.html
  • themes/beaver/layouts/partials/assets/single-career-css-resources.html
  • themes/beaver/layouts/services/single.html
  • themes/beaver/layouts/single.html
  • themes/beaver/layouts/use-cases/single.html
📝 Walkthrough

Walkthrough

Changes

CSS migration completion

Layer / File(s) Summary
Migration inventory and reachability validation
docs/projects/2509-css-migration/*, test/unit/css_orphan_guard_test.rb
Migration records mark the 16-file burn-down complete, while tests validate CSS reachability, imports, mixins, and template references.
Template bundle wiring and markup migration
themes/beaver/layouts/**, layouts/course/list.html
Templates replace retired CSS resources and builder wrappers with page bundles, simplified markup, generated lists, and semantic hooks.
Page bundle CSS ports
themes/beaver/assets/css/pages/*, themes/beaver/assets/css/navigation.css
Page-specific styles provide migrated layout, component, responsive, form, review, grid, and accessibility rules.
Single-client semantic selector re-keying
themes/beaver/layouts/clients/single.html, themes/beaver/assets/css/critical/single-clients.css, themes/beaver/assets/css/pages/single-client.css
Single-client markup and CSS move from generated node selectors to cs-* section, metadata, gallery, CTA, and case-card hooks.
System screenshot and route coverage
test/system/*
Desktop and mobile system tests cover migrated blog, course, client, privacy, and special-content routes.
Estimated code review effort: 4 (Complex) ~60 minutes

Possibly related PRs

Suggested reviewers: dgorodnichy

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.79% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the PR’s main change: retiring FL export CSS through a page-by-page strangler migration at pixel parity.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch css-migration/strangler-run

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Base automatically changed from css-migration/docs-realignment to master July 12, 2026 20:28
@pftg
pftg force-pushed the css-migration/strangler-run branch from c2bc958 to cce7675 Compare July 17, 2026 15:35
@pftg
pftg marked this pull request as ready for review July 17, 2026 17:59

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (2)
themes/beaver/layouts/page/contact-us.html (1)

10-94: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Extract the duplicated contact panel into a parameterized partial.

Both templates now maintain parallel copies of the benefits list and Gravity Forms shell.

  • themes/beaver/layouts/page/contact-us.html#L10-L94: move the shared structure and benefit strings into the partial; pass contact-specific classes, heading, and form ID.
  • themes/beaver/layouts/page/free-consultation.html#L6-L92: invoke the same partial with consultation-specific classes, heading, and form ID.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@themes/beaver/layouts/page/contact-us.html` around lines 10 - 94, Extract the
duplicated contact panel markup, including the shared benefits list and Gravity
Forms shell, into a parameterized partial. In
themes/beaver/layouts/page/contact-us.html lines 10-94, replace the duplicated
structure with the partial and pass its contact-specific classes, heading, and
form ID; in themes/beaver/layouts/page/free-consultation.html lines 6-92, invoke
the same partial with the consultation-specific values while preserving each
page’s existing behavior.
themes/beaver/assets/css/pages/services.css (1)

1909-1910: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prune the remaining empty export blocks.

Stylelint reports many no-op selectors in these hand-maintained bundles. Remove all reported empty blocks; they have no cascade effect.

  • themes/beaver/assets/css/pages/services.css#L1909-L1910: remove this and the other reported empty selectors.
  • themes/beaver/assets/css/pages/single-career.css#L150-L151: remove this and the other reported empty selectors.
  • themes/beaver/assets/css/pages/single-service.css#L1609-L1610: remove this and the other reported empty selectors.
  • themes/beaver/assets/css/pages/single-use-cases.css#L1524-L1525: remove this and the other reported empty selectors.
  • themes/beaver/assets/css/pages/use-cases.css#L1962-L1963: remove this and the other reported empty selectors.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@themes/beaver/assets/css/pages/services.css` around lines 1909 - 1910, Remove
every reported empty CSS selector block, including the affected selectors in
themes/beaver/assets/css/pages/services.css lines 1909-1910,
themes/beaver/assets/css/pages/single-career.css lines 150-151,
themes/beaver/assets/css/pages/single-service.css lines 1609-1610,
themes/beaver/assets/css/pages/single-use-cases.css lines 1524-1525, and
themes/beaver/assets/css/pages/use-cases.css lines 1962-1963; do not alter
non-empty rules.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/unit/css_orphan_guard_test.rb`:
- Around line 12-27: Remove the existence and structural configuration
assertions from CssOrphanGuardTest, including
test_every_css_file_is_reachable_from_a_template and
test_every_template_css_reference_exists_on_disk. Move their validation logic
into a standalone CLI script, Rake task, or CI linter so the Minitest suite
remains behavior-focused.

In `@themes/beaver/assets/css/navigation.css`:
- Around line 9-18: Replace the deprecated clip declaration in the .sr-only
utility with an equivalent clip-path declaration, preserving the existing
visually hidden behavior. Review
docs/projects/2509-css-migration/css-loading-order-analysis.md before modifying
CSS, then run bin/test and bin/dtest.

In `@themes/beaver/assets/css/pages/homepage.css`:
- Around line 755-756: Remove every declaration-free selector block from
themes/beaver/assets/css/pages/homepage.css lines 755-756,
themes/beaver/assets/css/pages/about-us.css lines 2070-2093, and
themes/beaver/assets/css/pages/clients.css lines 2364-2391, including the empty
tab, infobox, review, post-grid, and review selectors. Preserve all rules that
contain declarations.
- Around line 2135-2139: Update the selector in the box-sizing rule to use the
`.fl-builder-content` class selector for the container and its
`:before`/`:after` descendants, ensuring ordinary Beaver Builder content
elements receive `border-box`.

In `@themes/beaver/assets/css/pages/services.css`:
- Around line 641-662: Restore visible keyboard focus styling across the listed
lightbox controls, infobox image links, and tab labels by preserving outlines or
adding a shared :focus-visible ring without removing existing visual states.
Apply the updates in themes/beaver/assets/css/pages/services.css at 641-662,
1663-1668, and 3606-3614; themes/beaver/assets/css/pages/single-service.css at
639-660; themes/beaver/assets/css/pages/single-use-cases.css at 636-657; and
themes/beaver/assets/css/pages/use-cases.css at 592-613, 1177-1185, and
2093-2098. Validate the CSS in Chrome DevTools with zero console errors and
asset 404s, and capture desktop and mobile screenshots.

In `@themes/beaver/assets/css/pages/single-career.css`:
- Around line 27-49: The social-share selectors in the flat, gradient, boxed,
and minimal skin rules reuse the background tokens for foreground colors,
causing icons and labels to disappear. Update the non-hover and hover foreground
declarations in the affected rules to use the appropriate contrasting color
tokens, while keeping the background declarations unchanged; then validate the
CSS in Chrome DevTools with no console errors or asset 404s and capture desktop
and mobile screenshots.

---

Nitpick comments:
In `@themes/beaver/assets/css/pages/services.css`:
- Around line 1909-1910: Remove every reported empty CSS selector block,
including the affected selectors in themes/beaver/assets/css/pages/services.css
lines 1909-1910, themes/beaver/assets/css/pages/single-career.css lines 150-151,
themes/beaver/assets/css/pages/single-service.css lines 1609-1610,
themes/beaver/assets/css/pages/single-use-cases.css lines 1524-1525, and
themes/beaver/assets/css/pages/use-cases.css lines 1962-1963; do not alter
non-empty rules.

In `@themes/beaver/layouts/page/contact-us.html`:
- Around line 10-94: Extract the duplicated contact panel markup, including the
shared benefits list and Gravity Forms shell, into a parameterized partial. In
themes/beaver/layouts/page/contact-us.html lines 10-94, replace the duplicated
structure with the partial and pass its contact-specific classes, heading, and
form ID; in themes/beaver/layouts/page/free-consultation.html lines 6-92, invoke
the same partial with the consultation-specific values while preserving each
page’s existing behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 043ea855-22f8-4064-b18e-f921b300e645

📥 Commits

Reviewing files that changed from the base of the PR and between cd1aeb1 and 1a9319f.

⛔ Files ignored due to path filters (38)
  • test/fixtures/screenshots/linux/desktop/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/inline_style_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/youtube_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/careers/_newsletter.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/careers/junior-ruby-on-rails-developer.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/privacy-policy.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/services.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/services/fractional_cto.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/use_cases.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/use_cases/startup-mvp-prototyping-development.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/inline_style_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/youtube_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/careers/_newsletter.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/careers/junior-ruby-on-rails-developer.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/privacy-policy.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/services.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/services/fractional_cto.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/use_cases.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/use_cases/startup-mvp-prototyping-development.png is excluded by !**/*.png
📒 Files selected for processing (84)
  • docs/projects/2509-css-migration/TASK-TRACKER.md
  • docs/projects/2509-css-migration/css-bundle-ownership-map.md
  • layouts/course/list.html
  • test/system/blog_special_content_test.rb
  • test/system/components/diagram_component_test.rb
  • test/system/desktop_site_test.rb
  • test/system/mobile_site_test.rb
  • test/unit/css_orphan_guard_test.rb
  • themes/beaver/assets/css/3021-layout.css
  • themes/beaver/assets/css/3059-layout.css
  • themes/beaver/assets/css/3114-layout.css
  • themes/beaver/assets/css/706-layout.css
  • themes/beaver/assets/css/bf72bba397177a0376baed325bffdc75-layout-bundle.css
  • themes/beaver/assets/css/components/blocks/c-card.css
  • themes/beaver/assets/css/components/blocks/c-nav.css
  • themes/beaver/assets/css/components/buttons.css
  • themes/beaver/assets/css/components/c-feature-card--row2.css
  • themes/beaver/assets/css/components/c-infobox.css
  • themes/beaver/assets/css/components/c-modal.css
  • themes/beaver/assets/css/components/c-pagination.css
  • themes/beaver/assets/css/components/c-spacer.css
  • themes/beaver/assets/css/components/c-testimonial-section.css
  • themes/beaver/assets/css/components/c-testimonial-slider.css
  • themes/beaver/assets/css/components/cards-migration.css
  • themes/beaver/assets/css/components/forms-migration.css
  • themes/beaver/assets/css/components/pp-content-grid.css
  • themes/beaver/assets/css/components/pp-list.css
  • themes/beaver/assets/css/components/pp-tabs.css
  • themes/beaver/assets/css/components/typography.css
  • themes/beaver/assets/css/critical/free-consultation-critical.css
  • themes/beaver/assets/css/critical/privacy-policy-critical.css
  • themes/beaver/assets/css/critical/single-clients.css
  • themes/beaver/assets/css/e966db44b09892b8d7d492247c67e86c-layout-bundle.css
  • themes/beaver/assets/css/fb2624e43f3c4277448abe268cde571e-layout-bundle.css
  • themes/beaver/assets/css/homepage-layout.css
  • themes/beaver/assets/css/navigation.css
  • themes/beaver/assets/css/pages/about-us.css
  • themes/beaver/assets/css/pages/blog-list.css
  • themes/beaver/assets/css/pages/blog-single.css
  • themes/beaver/assets/css/pages/careers.css
  • themes/beaver/assets/css/pages/clients.css
  • themes/beaver/assets/css/pages/contact-us.css
  • themes/beaver/assets/css/pages/course-list.css
  • themes/beaver/assets/css/pages/free-consultation.css
  • themes/beaver/assets/css/pages/homepage.css
  • themes/beaver/assets/css/pages/services.css
  • themes/beaver/assets/css/pages/simple-page.css
  • themes/beaver/assets/css/pages/single-career.css
  • themes/beaver/assets/css/pages/single-client.css
  • themes/beaver/assets/css/pages/single-service.css
  • themes/beaver/assets/css/pages/single-use-cases.css
  • themes/beaver/assets/css/pages/use-cases.css
  • themes/beaver/assets/css/services-layout.css
  • themes/beaver/assets/css/utilities/clearfix.css
  • themes/beaver/assets/css/utilities/color-accessibility.css
  • themes/beaver/assets/css/utilities/colors.css
  • themes/beaver/assets/css/utilities/colors/backgrounds.css
  • themes/beaver/assets/css/utilities/components/powerpack/content-grid.css
  • themes/beaver/assets/css/utilities/components/powerpack/infobox.css
  • themes/beaver/assets/css/utilities/components/powerpack/pp-icon.css
  • themes/beaver/assets/css/utilities/components/powerpack/pp-list.css
  • themes/beaver/assets/css/utilities/fl-builder-grid.css
  • themes/beaver/assets/css/utilities/opacity.css
  • themes/beaver/assets/css/utilities/typography/text-utilities.css
  • themes/beaver/layouts/blog/list.html
  • themes/beaver/layouts/clients/single.html
  • themes/beaver/layouts/course/single.html
  • themes/beaver/layouts/list.html
  • themes/beaver/layouts/page/about.html
  • themes/beaver/layouts/page/clients.html
  • themes/beaver/layouts/page/contact-us.html
  • themes/beaver/layouts/page/free-consultation.html
  • themes/beaver/layouts/page/services.html
  • themes/beaver/layouts/page/single.html
  • themes/beaver/layouts/page/use-cases.html
  • themes/beaver/layouts/partials/assets/blog-list-css-resources.html
  • themes/beaver/layouts/partials/assets/careers-css-resources.html
  • themes/beaver/layouts/partials/assets/contact-us-css-resources.html
  • themes/beaver/layouts/partials/assets/free-consultation-css-resources.html
  • themes/beaver/layouts/partials/assets/homepage-css-resources.html
  • themes/beaver/layouts/partials/assets/single-career-css-resources.html
  • themes/beaver/layouts/services/single.html
  • themes/beaver/layouts/single.html
  • themes/beaver/layouts/use-cases/single.html
💤 Files with no reviewable changes (35)
  • themes/beaver/assets/css/utilities/components/powerpack/pp-list.css
  • themes/beaver/assets/css/components/c-spacer.css
  • themes/beaver/assets/css/components/c-testimonial-section.css
  • themes/beaver/assets/css/components/buttons.css
  • themes/beaver/assets/css/components/typography.css
  • themes/beaver/assets/css/utilities/components/powerpack/infobox.css
  • themes/beaver/assets/css/utilities/opacity.css
  • themes/beaver/assets/css/components/pp-content-grid.css
  • themes/beaver/assets/css/components/c-infobox.css
  • themes/beaver/assets/css/706-layout.css
  • themes/beaver/assets/css/components/pp-list.css
  • themes/beaver/assets/css/components/pp-tabs.css
  • themes/beaver/assets/css/components/blocks/c-nav.css
  • themes/beaver/assets/css/utilities/clearfix.css
  • themes/beaver/assets/css/components/cards-migration.css
  • themes/beaver/assets/css/utilities/fl-builder-grid.css
  • themes/beaver/assets/css/utilities/colors/backgrounds.css
  • themes/beaver/assets/css/components/c-modal.css
  • themes/beaver/assets/css/components/blocks/c-card.css
  • themes/beaver/assets/css/utilities/components/powerpack/content-grid.css
  • test/system/components/diagram_component_test.rb
  • themes/beaver/assets/css/utilities/typography/text-utilities.css
  • themes/beaver/assets/css/utilities/components/powerpack/pp-icon.css
  • themes/beaver/assets/css/services-layout.css
  • themes/beaver/assets/css/3059-layout.css
  • themes/beaver/assets/css/components/c-testimonial-slider.css
  • themes/beaver/assets/css/components/c-pagination.css
  • themes/beaver/assets/css/3114-layout.css
  • themes/beaver/assets/css/critical/free-consultation-critical.css
  • themes/beaver/assets/css/components/forms-migration.css
  • themes/beaver/assets/css/utilities/color-accessibility.css
  • themes/beaver/assets/css/bf72bba397177a0376baed325bffdc75-layout-bundle.css
  • themes/beaver/assets/css/homepage-layout.css
  • themes/beaver/assets/css/utilities/colors.css
  • themes/beaver/assets/css/components/c-feature-card--row2.css

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 6

🧹 Nitpick comments (2)
themes/beaver/layouts/page/contact-us.html (1)

10-94: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Extract the duplicated contact panel into a parameterized partial.

Both templates now maintain parallel copies of the benefits list and Gravity Forms shell.

  • themes/beaver/layouts/page/contact-us.html#L10-L94: move the shared structure and benefit strings into the partial; pass contact-specific classes, heading, and form ID.
  • themes/beaver/layouts/page/free-consultation.html#L6-L92: invoke the same partial with consultation-specific classes, heading, and form ID.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@themes/beaver/layouts/page/contact-us.html` around lines 10 - 94, Extract the
duplicated contact panel markup, including the shared benefits list and Gravity
Forms shell, into a parameterized partial. In
themes/beaver/layouts/page/contact-us.html lines 10-94, replace the duplicated
structure with the partial and pass its contact-specific classes, heading, and
form ID; in themes/beaver/layouts/page/free-consultation.html lines 6-92, invoke
the same partial with the consultation-specific values while preserving each
page’s existing behavior.
themes/beaver/assets/css/pages/services.css (1)

1909-1910: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prune the remaining empty export blocks.

Stylelint reports many no-op selectors in these hand-maintained bundles. Remove all reported empty blocks; they have no cascade effect.

  • themes/beaver/assets/css/pages/services.css#L1909-L1910: remove this and the other reported empty selectors.
  • themes/beaver/assets/css/pages/single-career.css#L150-L151: remove this and the other reported empty selectors.
  • themes/beaver/assets/css/pages/single-service.css#L1609-L1610: remove this and the other reported empty selectors.
  • themes/beaver/assets/css/pages/single-use-cases.css#L1524-L1525: remove this and the other reported empty selectors.
  • themes/beaver/assets/css/pages/use-cases.css#L1962-L1963: remove this and the other reported empty selectors.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@themes/beaver/assets/css/pages/services.css` around lines 1909 - 1910, Remove
every reported empty CSS selector block, including the affected selectors in
themes/beaver/assets/css/pages/services.css lines 1909-1910,
themes/beaver/assets/css/pages/single-career.css lines 150-151,
themes/beaver/assets/css/pages/single-service.css lines 1609-1610,
themes/beaver/assets/css/pages/single-use-cases.css lines 1524-1525, and
themes/beaver/assets/css/pages/use-cases.css lines 1962-1963; do not alter
non-empty rules.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/unit/css_orphan_guard_test.rb`:
- Around line 12-27: Remove the existence and structural configuration
assertions from CssOrphanGuardTest, including
test_every_css_file_is_reachable_from_a_template and
test_every_template_css_reference_exists_on_disk. Move their validation logic
into a standalone CLI script, Rake task, or CI linter so the Minitest suite
remains behavior-focused.

In `@themes/beaver/assets/css/navigation.css`:
- Around line 9-18: Replace the deprecated clip declaration in the .sr-only
utility with an equivalent clip-path declaration, preserving the existing
visually hidden behavior. Review
docs/projects/2509-css-migration/css-loading-order-analysis.md before modifying
CSS, then run bin/test and bin/dtest.

In `@themes/beaver/assets/css/pages/homepage.css`:
- Around line 755-756: Remove every declaration-free selector block from
themes/beaver/assets/css/pages/homepage.css lines 755-756,
themes/beaver/assets/css/pages/about-us.css lines 2070-2093, and
themes/beaver/assets/css/pages/clients.css lines 2364-2391, including the empty
tab, infobox, review, post-grid, and review selectors. Preserve all rules that
contain declarations.
- Around line 2135-2139: Update the selector in the box-sizing rule to use the
`.fl-builder-content` class selector for the container and its
`:before`/`:after` descendants, ensuring ordinary Beaver Builder content
elements receive `border-box`.

In `@themes/beaver/assets/css/pages/services.css`:
- Around line 641-662: Restore visible keyboard focus styling across the listed
lightbox controls, infobox image links, and tab labels by preserving outlines or
adding a shared :focus-visible ring without removing existing visual states.
Apply the updates in themes/beaver/assets/css/pages/services.css at 641-662,
1663-1668, and 3606-3614; themes/beaver/assets/css/pages/single-service.css at
639-660; themes/beaver/assets/css/pages/single-use-cases.css at 636-657; and
themes/beaver/assets/css/pages/use-cases.css at 592-613, 1177-1185, and
2093-2098. Validate the CSS in Chrome DevTools with zero console errors and
asset 404s, and capture desktop and mobile screenshots.

In `@themes/beaver/assets/css/pages/single-career.css`:
- Around line 27-49: The social-share selectors in the flat, gradient, boxed,
and minimal skin rules reuse the background tokens for foreground colors,
causing icons and labels to disappear. Update the non-hover and hover foreground
declarations in the affected rules to use the appropriate contrasting color
tokens, while keeping the background declarations unchanged; then validate the
CSS in Chrome DevTools with no console errors or asset 404s and capture desktop
and mobile screenshots.

---

Nitpick comments:
In `@themes/beaver/assets/css/pages/services.css`:
- Around line 1909-1910: Remove every reported empty CSS selector block,
including the affected selectors in themes/beaver/assets/css/pages/services.css
lines 1909-1910, themes/beaver/assets/css/pages/single-career.css lines 150-151,
themes/beaver/assets/css/pages/single-service.css lines 1609-1610,
themes/beaver/assets/css/pages/single-use-cases.css lines 1524-1525, and
themes/beaver/assets/css/pages/use-cases.css lines 1962-1963; do not alter
non-empty rules.

In `@themes/beaver/layouts/page/contact-us.html`:
- Around line 10-94: Extract the duplicated contact panel markup, including the
shared benefits list and Gravity Forms shell, into a parameterized partial. In
themes/beaver/layouts/page/contact-us.html lines 10-94, replace the duplicated
structure with the partial and pass its contact-specific classes, heading, and
form ID; in themes/beaver/layouts/page/free-consultation.html lines 6-92, invoke
the same partial with the consultation-specific values while preserving each
page’s existing behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 043ea855-22f8-4064-b18e-f921b300e645

📥 Commits

Reviewing files that changed from the base of the PR and between cd1aeb1 and 1a9319f.

⛔ Files ignored due to path filters (38)
  • test/fixtures/screenshots/linux/desktop/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/inline_style_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/blog/special/youtube_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/careers/_newsletter.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/desktop/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/careers/junior-ruby-on-rails-developer.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/privacy-policy.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/services.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/services/fractional_cto.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/use_cases.png is excluded by !**/*.png
  • test/fixtures/screenshots/linux/mobile/use_cases/startup-mvp-prototyping-development.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/inline_style_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/blog/special/youtube_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/careers/_newsletter.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/desktop/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/code_highlight_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/blog/special/mermaid_post.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/careers/junior-ruby-on-rails-developer.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/clients/single-full.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/course/chapter.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/course/landing.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/privacy-policy.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/services.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/services/fractional_cto.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/use_cases.png is excluded by !**/*.png
  • test/fixtures/screenshots/macos/mobile/use_cases/startup-mvp-prototyping-development.png is excluded by !**/*.png
📒 Files selected for processing (84)
  • docs/projects/2509-css-migration/TASK-TRACKER.md
  • docs/projects/2509-css-migration/css-bundle-ownership-map.md
  • layouts/course/list.html
  • test/system/blog_special_content_test.rb
  • test/system/components/diagram_component_test.rb
  • test/system/desktop_site_test.rb
  • test/system/mobile_site_test.rb
  • test/unit/css_orphan_guard_test.rb
  • themes/beaver/assets/css/3021-layout.css
  • themes/beaver/assets/css/3059-layout.css
  • themes/beaver/assets/css/3114-layout.css
  • themes/beaver/assets/css/706-layout.css
  • themes/beaver/assets/css/bf72bba397177a0376baed325bffdc75-layout-bundle.css
  • themes/beaver/assets/css/components/blocks/c-card.css
  • themes/beaver/assets/css/components/blocks/c-nav.css
  • themes/beaver/assets/css/components/buttons.css
  • themes/beaver/assets/css/components/c-feature-card--row2.css
  • themes/beaver/assets/css/components/c-infobox.css
  • themes/beaver/assets/css/components/c-modal.css
  • themes/beaver/assets/css/components/c-pagination.css
  • themes/beaver/assets/css/components/c-spacer.css
  • themes/beaver/assets/css/components/c-testimonial-section.css
  • themes/beaver/assets/css/components/c-testimonial-slider.css
  • themes/beaver/assets/css/components/cards-migration.css
  • themes/beaver/assets/css/components/forms-migration.css
  • themes/beaver/assets/css/components/pp-content-grid.css
  • themes/beaver/assets/css/components/pp-list.css
  • themes/beaver/assets/css/components/pp-tabs.css
  • themes/beaver/assets/css/components/typography.css
  • themes/beaver/assets/css/critical/free-consultation-critical.css
  • themes/beaver/assets/css/critical/privacy-policy-critical.css
  • themes/beaver/assets/css/critical/single-clients.css
  • themes/beaver/assets/css/e966db44b09892b8d7d492247c67e86c-layout-bundle.css
  • themes/beaver/assets/css/fb2624e43f3c4277448abe268cde571e-layout-bundle.css
  • themes/beaver/assets/css/homepage-layout.css
  • themes/beaver/assets/css/navigation.css
  • themes/beaver/assets/css/pages/about-us.css
  • themes/beaver/assets/css/pages/blog-list.css
  • themes/beaver/assets/css/pages/blog-single.css
  • themes/beaver/assets/css/pages/careers.css
  • themes/beaver/assets/css/pages/clients.css
  • themes/beaver/assets/css/pages/contact-us.css
  • themes/beaver/assets/css/pages/course-list.css
  • themes/beaver/assets/css/pages/free-consultation.css
  • themes/beaver/assets/css/pages/homepage.css
  • themes/beaver/assets/css/pages/services.css
  • themes/beaver/assets/css/pages/simple-page.css
  • themes/beaver/assets/css/pages/single-career.css
  • themes/beaver/assets/css/pages/single-client.css
  • themes/beaver/assets/css/pages/single-service.css
  • themes/beaver/assets/css/pages/single-use-cases.css
  • themes/beaver/assets/css/pages/use-cases.css
  • themes/beaver/assets/css/services-layout.css
  • themes/beaver/assets/css/utilities/clearfix.css
  • themes/beaver/assets/css/utilities/color-accessibility.css
  • themes/beaver/assets/css/utilities/colors.css
  • themes/beaver/assets/css/utilities/colors/backgrounds.css
  • themes/beaver/assets/css/utilities/components/powerpack/content-grid.css
  • themes/beaver/assets/css/utilities/components/powerpack/infobox.css
  • themes/beaver/assets/css/utilities/components/powerpack/pp-icon.css
  • themes/beaver/assets/css/utilities/components/powerpack/pp-list.css
  • themes/beaver/assets/css/utilities/fl-builder-grid.css
  • themes/beaver/assets/css/utilities/opacity.css
  • themes/beaver/assets/css/utilities/typography/text-utilities.css
  • themes/beaver/layouts/blog/list.html
  • themes/beaver/layouts/clients/single.html
  • themes/beaver/layouts/course/single.html
  • themes/beaver/layouts/list.html
  • themes/beaver/layouts/page/about.html
  • themes/beaver/layouts/page/clients.html
  • themes/beaver/layouts/page/contact-us.html
  • themes/beaver/layouts/page/free-consultation.html
  • themes/beaver/layouts/page/services.html
  • themes/beaver/layouts/page/single.html
  • themes/beaver/layouts/page/use-cases.html
  • themes/beaver/layouts/partials/assets/blog-list-css-resources.html
  • themes/beaver/layouts/partials/assets/careers-css-resources.html
  • themes/beaver/layouts/partials/assets/contact-us-css-resources.html
  • themes/beaver/layouts/partials/assets/free-consultation-css-resources.html
  • themes/beaver/layouts/partials/assets/homepage-css-resources.html
  • themes/beaver/layouts/partials/assets/single-career-css-resources.html
  • themes/beaver/layouts/services/single.html
  • themes/beaver/layouts/single.html
  • themes/beaver/layouts/use-cases/single.html
💤 Files with no reviewable changes (35)
  • themes/beaver/assets/css/utilities/components/powerpack/pp-list.css
  • themes/beaver/assets/css/components/c-spacer.css
  • themes/beaver/assets/css/components/c-testimonial-section.css
  • themes/beaver/assets/css/components/buttons.css
  • themes/beaver/assets/css/components/typography.css
  • themes/beaver/assets/css/utilities/components/powerpack/infobox.css
  • themes/beaver/assets/css/utilities/opacity.css
  • themes/beaver/assets/css/components/pp-content-grid.css
  • themes/beaver/assets/css/components/c-infobox.css
  • themes/beaver/assets/css/706-layout.css
  • themes/beaver/assets/css/components/pp-list.css
  • themes/beaver/assets/css/components/pp-tabs.css
  • themes/beaver/assets/css/components/blocks/c-nav.css
  • themes/beaver/assets/css/utilities/clearfix.css
  • themes/beaver/assets/css/components/cards-migration.css
  • themes/beaver/assets/css/utilities/fl-builder-grid.css
  • themes/beaver/assets/css/utilities/colors/backgrounds.css
  • themes/beaver/assets/css/components/c-modal.css
  • themes/beaver/assets/css/components/blocks/c-card.css
  • themes/beaver/assets/css/utilities/components/powerpack/content-grid.css
  • test/system/components/diagram_component_test.rb
  • themes/beaver/assets/css/utilities/typography/text-utilities.css
  • themes/beaver/assets/css/utilities/components/powerpack/pp-icon.css
  • themes/beaver/assets/css/services-layout.css
  • themes/beaver/assets/css/3059-layout.css
  • themes/beaver/assets/css/components/c-testimonial-slider.css
  • themes/beaver/assets/css/components/c-pagination.css
  • themes/beaver/assets/css/3114-layout.css
  • themes/beaver/assets/css/critical/free-consultation-critical.css
  • themes/beaver/assets/css/components/forms-migration.css
  • themes/beaver/assets/css/utilities/color-accessibility.css
  • themes/beaver/assets/css/bf72bba397177a0376baed325bffdc75-layout-bundle.css
  • themes/beaver/assets/css/homepage-layout.css
  • themes/beaver/assets/css/utilities/colors.css
  • themes/beaver/assets/css/components/c-feature-card--row2.css
🛑 Comments failed to post (6)
test/unit/css_orphan_guard_test.rb (1)

12-27: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Avoid existence and configuration assertions in Minitest.

This test suite explicitly asserts the existence of files and validates structural configuration state (assert_empty orphans, assert_empty missing). As per coding guidelines, Minitest tests must be behavior-focused and avoid implementation, existence, or configuration assertions.

Consider moving this valuable validation out of the Minitest suite and into a standalone CLI script, a custom Rake task, or a linter hook in the CI pipeline.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/unit/css_orphan_guard_test.rb` around lines 12 - 27, Remove the
existence and structural configuration assertions from CssOrphanGuardTest,
including test_every_css_file_is_reachable_from_a_template and
test_every_template_css_reference_exists_on_disk. Move their validation logic
into a standalone CLI script, Rake task, or CI linter so the Minitest suite
remains behavior-focused.

Source: Coding guidelines

themes/beaver/assets/css/navigation.css (1)

9-18: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Replace the deprecated clip declaration.

Stylelint rejects Line 15. Use clip-path for the new global utility.

Proposed fix
   padding: 0;
   overflow: hidden;
-  clip: rect(0, 0, 0, 0);
+  clip-path: inset(50%);
   white-space: nowrap;

As per coding guidelines, read docs/projects/2509-css-migration/css-loading-order-analysis.md before making CSS changes and run both bin/test and bin/dtest before committing.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
🧰 Tools
🪛 Stylelint (17.14.0)

[error] 15-15: Deprecated property "clip" (property-no-deprecated)

(property-no-deprecated)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@themes/beaver/assets/css/navigation.css` around lines 9 - 18, Replace the
deprecated clip declaration in the .sr-only utility with an equivalent clip-path
declaration, preserving the existing visually hidden behavior. Review
docs/projects/2509-css-migration/css-loading-order-analysis.md before modifying
CSS, then run bin/test and bin/dtest.

Sources: Coding guidelines, Linters/SAST tools

themes/beaver/assets/css/pages/homepage.css (2)

755-756: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Remove declaration-free rules from the migrated bundles.

The retained FL export shells add no behavior and cause widespread Stylelint block-no-empty errors.

  • themes/beaver/assets/css/pages/homepage.css#L755-L756: remove all empty selectors throughout the homepage bundle.
  • themes/beaver/assets/css/pages/about-us.css#L2070-L2093: remove all empty infobox and review selectors.
  • themes/beaver/assets/css/pages/clients.css#L2364-L2391: remove all empty post-grid and review selectors.
🧰 Tools
🪛 Stylelint (17.14.0)

[error] 755-756: Empty block (block-no-empty)

(block-no-empty)

📍 Affects 3 files
  • themes/beaver/assets/css/pages/homepage.css#L755-L756 (this comment)
  • themes/beaver/assets/css/pages/about-us.css#L2070-L2093
  • themes/beaver/assets/css/pages/clients.css#L2364-L2391
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@themes/beaver/assets/css/pages/homepage.css` around lines 755 - 756, Remove
every declaration-free selector block from
themes/beaver/assets/css/pages/homepage.css lines 755-756,
themes/beaver/assets/css/pages/about-us.css lines 2070-2093, and
themes/beaver/assets/css/pages/clients.css lines 2364-2391, including the empty
tab, infobox, review, post-grid, and review selectors. Preserve all rules that
contain declarations.

Source: Linters/SAST tools


2135-2139: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Restore the missing class selector.

Line 2135 targets a literal <fl-builder-content> element, so ordinary .fl-builder-content descendants do not receive this border-box declaration.

Proposed fix
-fl-builder-content *, .fl-builder-content *:before, .fl-builder-content *:after {
+.fl-builder-content *, .fl-builder-content *:before, .fl-builder-content *:after {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

.fl-builder-content *, .fl-builder-content *:before, .fl-builder-content *:after {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@themes/beaver/assets/css/pages/homepage.css` around lines 2135 - 2139, Update
the selector in the box-sizing rule to use the `.fl-builder-content` class
selector for the container and its `:before`/`:after` descendants, ensuring
ordinary Beaver Builder content elements receive `border-box`.
themes/beaver/assets/css/pages/services.css (1)

641-662: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Restore visible keyboard focus on interactive controls.

These rules suppress browser focus indicators without providing a replacement. Add a shared :focus-visible ring or stop clearing outline.

  • themes/beaver/assets/css/pages/services.css#L641-L662: restore focus styling for lightbox arrows and close buttons.
  • themes/beaver/assets/css/pages/services.css#L1663-L1668: retain a focus ring on infobox image links.
  • themes/beaver/assets/css/pages/services.css#L3606-L3614: provide visible focus styling for tab labels.
  • themes/beaver/assets/css/pages/single-service.css#L639-L660: restore focus styling for lightbox controls.
  • themes/beaver/assets/css/pages/single-use-cases.css#L636-L657: restore focus styling for lightbox controls.
  • themes/beaver/assets/css/pages/use-cases.css#L592-L613: restore focus styling for lightbox controls.
  • themes/beaver/assets/css/pages/use-cases.css#L1177-L1185: provide visible focus styling for tab labels.
  • themes/beaver/assets/css/pages/use-cases.css#L2093-L2098: retain a focus ring on infobox image links.

As per coding guidelines, after CSS changes, validate in Chrome DevTools with zero console errors and zero asset 404s, and capture desktop and mobile screenshots.

📍 Affects 4 files
  • themes/beaver/assets/css/pages/services.css#L641-L662 (this comment)
  • themes/beaver/assets/css/pages/services.css#L1663-L1668
  • themes/beaver/assets/css/pages/services.css#L3606-L3614
  • themes/beaver/assets/css/pages/single-service.css#L639-L660
  • themes/beaver/assets/css/pages/single-use-cases.css#L636-L657
  • themes/beaver/assets/css/pages/use-cases.css#L592-L613
  • themes/beaver/assets/css/pages/use-cases.css#L1177-L1185
  • themes/beaver/assets/css/pages/use-cases.css#L2093-L2098
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@themes/beaver/assets/css/pages/services.css` around lines 641 - 662, Restore
visible keyboard focus styling across the listed lightbox controls, infobox
image links, and tab labels by preserving outlines or adding a shared
:focus-visible ring without removing existing visual states. Apply the updates
in themes/beaver/assets/css/pages/services.css at 641-662, 1663-1668, and
3606-3614; themes/beaver/assets/css/pages/single-service.css at 639-660;
themes/beaver/assets/css/pages/single-use-cases.css at 636-657; and
themes/beaver/assets/css/pages/use-cases.css at 592-613, 1177-1185, and
2093-2098. Validate the CSS in Chrome DevTools with zero console errors and
asset 404s, and capture desktop and mobile screenshots.

Source: Coding guidelines

themes/beaver/assets/css/pages/single-career.css (1)

27-49: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use contrasting foreground colors for the share buttons.

Lines 28 and 36 use --color-dark for both background and content; Lines 40 and 48 repeat this with --color-primary. The icons or labels therefore disappear in both states. Use the appropriate contrasting foreground token.

As per coding guidelines, after CSS changes, validate in Chrome DevTools with zero console errors and zero asset 404s, and capture desktop and mobile screenshots.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@themes/beaver/assets/css/pages/single-career.css` around lines 27 - 49, The
social-share selectors in the flat, gradient, boxed, and minimal skin rules
reuse the background tokens for foreground colors, causing icons and labels to
disappear. Update the non-hover and hover foreground declarations in the
affected rules to use the appropriate contrasting color tokens, while keeping
the background declarations unchanged; then validate the CSS in Chrome DevTools
with no console errors or asset 404s and capture desktop and mobile screenshots.

Source: Coding guidelines

Paul Keen and others added 24 commits July 18, 2026 23:14
… (Mermaid, Chroma, inline-style, youtube)

Desktop+mobile screenshots for one representative post per surface; volatile
regions (async Mermaid SVG, external iframe, images) skipped for determinism.
Replaces the dead skipped DiagramComponentTest (deleted; it was outside the
test:critical pattern anyway). Baselines committed for macOS AND Linux, both
suites 6/6 green; zero existing baselines touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…exposed

Guard walks resources.Get from all templates, transitive @import chains
(file-relative AND css-root-relative, postcss-import style), and
postcss-mixins usage (@mixin <basename> against mixinsDir) — the mixin class
was learned live: deleting mixins/responsive-visibility.css crashed the
production build (undefined mixin in 590-layout), so it stays and the guard
now models it. The 26 deleted files (components/ leftovers 'migrated from'
long ago, utilities/ trees, powerpack originals) are proven dead: clean
production builds before/after deletion have byte-identical CSS bundles.
Second assertion catches the inverse defect (template referencing a missing
file).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…le privacy-policy screenshots

P0.2 gate for the first rewrite targets: baselines captured from the UNCHANGED
pages on both OSes (4 new baselines; desktop privacy-policy already existed and
matched). Course-landing h1 assertion moved off the .fl-heading anchor to plain
h1 ahead of the semantic rewrite.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ist rewritten to semantic HTML at pixel parity

First FL file down (924 lines): both consumers rewritten in one atomic commit.
- page/single.html: FL row/col/module divs → main/article + css/pages/simple-page.css
  on the existing box model (hero 200/20/130 → 150@1115 → 100/50@860; 800px cap;
  h1 keeps skin's 70px strut with the clamp() span like .fl-heading-text did;
  fl-rich-text spacing cloned; single-content class kept for 586.css h2-h4 rules).
- layouts/course/list.html: FL wrapper dropped, h1.fl-heading → h1.course-title with
  the style.css/single-post.css rules cloned at identical specificity+order
  (css/pages/course-list.css).
- critical/privacy-policy-critical.css: page node rules stripped; FL header/nav
  rules stay until the header's own sprint.
- Both bundles drop bf72bba… too (7 consumers left).

Parity caught and fixed two real deltas: dropped single-content class (h2 sizing)
and a phantom 15px container padding (skin zeroes Bootstrap's trio under
.fl-builder). Verified: only the 2 target bundles changed bytes (17 others
md5-identical); privacy-policy 17.1→14.1KB gz, course-list 17.6→14.2KB gz;
bin/test + bin/dtest 54/54 green with ZERO baseline changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mantic HTML at pixel parity

Second FL file down (2,202 lines). FL row/col/module shell → semantic
contact-hero / contact-intro / contact-band / contact-list-panel /
contact-form-panel; the PowerPack infolist and Gravity Forms component markup
kept verbatim (5 checkmark items now a range loop). Live node rules ported
1:1 into css/pages/contact-us.css (~8 dead-node blocks + FL framework block
dropped with the file); 586.css's .contact-page height chain replicated
de-layered since the shared file must stay byte-identical.

Conversion-surface safety: compiled <form> element byte-identical pre/post
(md5 c34fac4d…); form partial untouched. All other bundles md5-identical
(only contact-us changed). bin/test + bin/dtest 54/54, 93 screenshots, ZERO
baseline changes — first-try parity.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ly moved site-wide

single.html (all 584 blog posts) drops 3114-layout.css + bf72bba… from its
slice: FL wrapper → .single-post-row, h1.fl-heading → h1.post-title (style.css
already covers post-title in its shared 43rem block; the one single-post.css
override cloned into css/pages/blog-single.css). .fl-rich-text class kept
until the shared single-post.css re-key sweep.

Parity gate caught a real trap: baseof's skip-link relies on .sr-only, which
only existed in FL layout files — dropping 3114 unhid 'Skip to main content'
and shifted every blog page 28px. .sr-only now lives in the site-wide inline
navigation.css so no future FL retirement can unhide it. Also fixed nested
<main> landmarks from R1/R2 (baseof already provides main#main-content) and
the mobile test's .fl-heading anchor.

Verified: only blog-single bundle changed bytes; all 8 blog screenshots
(special-content matrix + post) 0-diff; bin/test + bin/dtest 54/54, 93
screenshots, ZERO baseline changes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…apter coverage)

course/single.html (course chapters) mirrors R3a: drops 3114-layout.css +
bf72bba… from its slice, FL wrapper → .single-post-row, h1.fl-heading →
h1.post-title, reusing css/pages/blog-single.css. New desktop+mobile
course/chapter screenshots added FIRST from the unchanged page (P0.2), then
verified 0-diff after the rewrite. Only the course-single bundle changed
bytes (now hash-identical to blog-single — same slice). Both suites 56/56,
zero baseline changes.

3114-layout.css consumers remaining: single-career, single-client.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ntic node aliases at pixel parity

clients/single.html drops 3114-layout.css + fb2624… (6,523 lines, deleted —
this was its only consumer). fl-node-<id> classes renamed to semantic aliases
(cs-hero, cs-details, cs-cases, cs-gallery-mod, cs-cta-*…) via one map applied
uniformly to the template, the page-private critical/single-clients.css (the
FL framework backbone, stays), and the ported rules — same specificity
everywhere, parity by construction; data-node test anchors untouched.
css/pages/single-client.css = mechanical live-subset extraction from fb2624
(media-aware rule filter against the compiled page class set, deduped against
the re-keyed critical), 190 rules; dead grid-style/owl/woocommerce middle
(~250 lines) dropped.

New desktop+mobile clients/single-full screenshots captured pre-rewrite (P0.2)
and 0-diff after. Bundle 25.4→16.1KB gz (−36%). Only single-client changed
bytes; both suites 58/58, 95 screenshots, ZERO baseline changes.

3114-layout.css last consumer: single-career (next).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e-career delta port at pixel parity

R3 cluster complete: single-career was the last 3114 consumer. Both files
deleted (2,272 + 4,364 lines). Option-A port: the page-private
critical/single-careers.css already carries the page's real styles; the new
css/pages/single-career.css re-hosts only e966's delta (hero tablet
breakpoint, mobile share-label hide, share hover states, full Gravity-form
skin e966:3959-4348 verbatim) at the same cascade slot with identical
selectors — no markup change, no test re-anchors. New mobile career-page
screenshot captured pre-change on both OSes (re-verified from a guaranteed-
clean tree) and 0-diff after.

Bundle 22.0→18.3KB gz (−17%). Only single-career changed bytes; both suites
59/59, 97 screenshots, ZERO baseline changes.

FL burn-down: 16 → 11 (3059, 706, fb2624, 3114, e966 retired).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Post-rebase revalidation at HEAD (master merged course v2 #361): both
suites green on macOS + Linux with ZERO baseline changes. The one flake
was the new lesson-meta callout's bold+link line wrapping bimodally
across runs (font-swap race) — masked via skip_area in the desktop and
mobile chapter tests, verified stable across three consecutive runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… pixel parity

Both blog index templates (blog/list.html + tag-page list.html) drop the
FL shell for semantic wrappers; card styles port verbatim from the
homepage-layout block into pages/blog-list.css. The shared blog-list
slice drops services-layout.css + homepage-layout.css (both files stay —
free-consultation still consumes them until R4b).

Parity evidence: headless old-vs-new RMSE 0 at blog index + tag page,
desktop 1280x800 + mobile 390x844; bin/rake test:critical (59/0) and
bin/dtest (59/0) green with ZERO baseline changes; converged build x2;
only the blog-list bundle fingerprint changed (19.5 -> 15.0 KB gz,
-23%). One analyst-plan miss caught by the pre-gate: the generic
.fl-row-content-wrap{padding:20px} pads all four sides — top/bottom-only
port shifted mobile 20px left.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…age-layout, services-layout, fl-builder-grid, free-consultation-critical

free-consultation IS the contact layout: pages/free-consultation.css is
a byte-clone of pages/contact-us.css with .contact-* layout classes
renamed .fc-* and .contact-title dropped (H1 keeps .fl-heading/.fl-
heading-text; its clamp ported from style.css's .fl-row-bg-photo hook,
which left with the FL wrapper). Template mirrors page/contact-us.html;
form keeps gform_wrapper_8/gf_8 ids and the .contact-page scope. With
both consumers rewritten, homepage-layout.css, services-layout.css, its
fl-builder-grid.css satellite, and free-consultation-critical.css are
deleted (FL burn-down 11 -> 8 files).

Pre-gate caught three deltas the plan missed: four gform generics this
bundle inherited via the deleted FL copies of 586.css (required-legend
hide, gfield margin, gf_half two-column, textarea height), the @860
footer centering, and a contact-us-only @860 button margin-top that
free-consultation never had.

Parity evidence: headless old-vs-new RMSE 0 at desktop+mobile, first
fold AND full page; bin/rake test:critical (59/0) + bin/dtest (59/0)
green with ZERO baseline changes; converged build x2; only the
free-consultation bundle fingerprint changed (20.6 -> 16.2 KB gz, -21%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…el parity

Option A (single-career precedent): markup unchanged — page-private
about-us-critical.css already duplicates the node rules and the shared
header framework, so pages/about-us.css is 701 verbatim minus the 9
dead-node rule sets (media-aware source prune; dead ids verified absent
from the rendered page). bf72bba…-layout-bundle also leaves this slice:
its only rules matching this page are header-nav copies byte-identical
in the critical (compiled-diff shows zero header rules removed). bf72bba
consumers: 5 remain.

Parity evidence: compiled fragment diff — every removed fragment keys a
dead node or a theme-builder header attribute absent from the page;
headless old-vs-new RMSE 0 at desktop+mobile, first fold AND full page;
bin/rake test:critical (59/0) + bin/dtest (59/0) green with ZERO
baseline changes; converged build x2; only the about-us bundle
fingerprint changed (19.4 -> 15.0 KB gz, -23%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Baselines captured from the UNCHANGED page before the R6 careers CSS
swap; the newsletter Gravity-form panel is the highest-risk port and
was not framed by the existing overview/offers section shots.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… byte parity

Every fl-node in 3086-layout2.css is live on /careers/ (zero dead
nodes), so the file moves verbatim to pages/careers.css and the slice
points at the new path. The compiled careers bundle is BYTE-IDENTICAL —
unchanged content-hash fingerprint — so the rendered page cannot differ.
A purge-dead source-slimming pass was attempted and reverted: it changed
the bundle fingerprint (cssnano selector normalization defeats textual
matching), and byte parity outranks source cosmetics.

Gates: bin/rake test:critical (59/0, 99 screenshots incl. the new
newsletter section) + bin/dtest (59/0) green, ZERO baseline changes,
converged build, all bundle fingerprints unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oth OSes)

/use-cases/ had zero mobile coverage. Baselines captured from the
UNCHANGED pages before the R7 CSS swap.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…es pair delta ports at pixel parity

Option A both pages (shared partials + data-node test anchors stay
untouched). pages/use-cases.css = 3021 verbatim minus 58 dead-node rule
sets; pages/single-use-cases.css = 3027 verbatim minus 14 (media-aware
source prune vs the rendered pages). bf72bba…-layout-bundle left both
slices; that exposed the header CTA-button rules only bf72bba carried
for the landing (shared critical/base.css has no copies, unlike the
page-private criticals) — three rules ported verbatim. The
fl-builder-common-base.css satellite is NOT byte-redundant (dropping its
@import changed the bundle) — the import moves with the file; deletion
attempt reverted. Hero-node twins with single-use-cases critical keep
3027 cascade position (dedup-twin trap).

Parity evidence: compiled fragment diff — every removed fragment keys a
dead node or an absent theme-builder header attribute; headless RMSE 0
on both pages, desktop+mobile full page; test:critical (61/0) + dtest
(61/0) incl. the two new mobile screenshots, ZERO baseline changes;
converged build x2; only the two target bundles changed (use-cases
25.4 -> 17.0 KB gz, -33%; single-use-cases 23.8 -> 18.8 KB gz, -21%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…hots (both OSes)

The services 6-card mobile stack and single-service mobile body had no
coverage. Baselines captured from the UNCHANGED pages before the R8 swaps.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…xel parity

Option A: markup and tests untouched. pages/clients.css = 3082 verbatim
minus 35 dead-node rule sets; bf72bba…-layout-bundle left the slice with
the same header CTA-button port as R7 (clients-critical carries no
copies). bf72bba consumers: 2 remain (services, services/single).

Parity: compiled fragment diff clean (dead nodes + absent header attrs
only); headless RMSE 0 desktop+mobile full page; test:critical (63/0) +
dtest (63/0), ZERO baseline changes; converged; only the clients bundle
changed (24.0 -> 18.7 KB gz, -22%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t at pixel parity

Option A: markup and tests untouched (incl. the L242 .fl-row-content-wrap
anchor a semantic rewrite would break). pages/single-service.css = 2949
verbatim minus 26 dead-node rule sets, pruned against the UNION of all 8
rendered single-service pages. bf72bba…-layout-bundle left the slice
cleanly — zero live fragments missing, no header port needed (this
page-private critical carries the copies). bf72bba consumers: 1 remains
(services).

Parity: compiled fragment diff clean; headless RMSE 0 on fractional-cto
AND app-web-development, desktop+mobile full page; test:critical (63/0)
+ dtest (63/0), ZERO baseline changes; converged; only the
single-service bundle changed (24.2 -> 19.1 KB gz, -21%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…; services delta port at pixel parity

Option A: markup and tests untouched. pages/services.css = 737 verbatim
minus 41 dead-node rule sets; the header CTA-button trio ported verbatim
(services-critical carries no copies). services was bf72bba's LAST
consumer — the shared layout-bundle file is deleted; its per-page exits
were each verified by compiled fragment diff (about/single-service:
byte-covered by criticals; use-cases/clients/services: 3-rule header
port).

Parity: compiled fragment diff clean; headless RMSE 0 desktop+mobile
full page; test:critical (63/0) + dtest (63/0), ZERO baseline changes;
converged; only the services bundle changed (25.8 -> 19.9 KB gz, -23%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…el parity. FL burn-down 16/16 complete

The last and largest FL export (12,433 lines). Option A / Path A:
pages/homepage.css = 590 verbatim minus 47 dead-node rule sets (media-
aware source prune vs the rendered page); the postcss-mixins
responsive-visibility consumer stays intact; markup and tests untouched.

Parity: compiled fragment diff clean; headless RMSE 0 desktop+mobile
full page; test:critical (63/0) + dtest (63/0), ZERO baseline changes;
converged; only the homepage bundle changed (30.1 -> 26.6 KB gz, -11%).

Every numbered/hash FL-Builder layout export named in the burn-down
table is now retired.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…r R1-R9 log

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The mermaid_post screenshots never contained the diagram: the capture was
first-fold only (diagram below the fold) and the div.mermaid region was
skip_area-masked out of comparison anyway. Now the test waits for the
post-font-load svg injection (div.mermaid svg), scrolls the diagram into
frame, and compares it unmasked. 5 consecutive macOS captures were
byte-identical (RMSE 0), so the Caveat-font render is deterministic at
these settings. Baselines regenerated on both macOS and Linux.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Keen and others added 2 commits July 18, 2026 23:14
Adds content/blog/codeblock-styles-fixture (draft: true — test builds run
--buildDrafts, production never ships it) with one fence per rendering
path: text, md, ruby, python, js, html, bare (no language), and an
indented 4-space block. New test_codeblock_language_styles (desktop +
mobile) scrolls to each block and screenshots it — 32 baselines across
macOS/Linux.

Audit result: all recognized lexers already render identically (Chroma
inline Dracula styles, noClasses=true). The real risk is the bare/unknown
fallback, whose dark background survives only by bundle source order
(.blog pre after .single-content pre at equal specificity). These
baselines lock that path: a cascade flip to the light-bg/invisible-text
failure now breaks the suite. Hardening option documented in the
ownership map follow-ups.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lback

CodeRabbit flagged the deprecated clip property on the hand-authored
site-wide .sr-only utility. clip-path: inset(50%) is the modern
equivalent; clip stays as the fallback for older browsers. No rendered
change: full visual suites green on macOS and Linux with zero baseline
changes (65 runs / 119 screenshots each).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@pftg
pftg force-pushed the css-migration/strangler-run branch from 1a9319f to 031cc04 Compare July 18, 2026 21:29
@pftg

pftg commented Jul 18, 2026

Copy link
Copy Markdown
Member Author

CodeRabbit triage — all 8 findings verified against the worktree

Fixed (1):

  • navigation.css .sr-only deprecated clip → added clip-path: inset(50%) with the clip fallback retained. Full visual suites green on macOS + Linux with zero baseline changes.

Pre-existing in production, out of scope for a parity PR (2):

  • pages/homepage.css fl-builder-content * missing leading dot: the typo exists verbatim in the original 590-layout.css:2763 (pre-migration FL export) — it ships in production today. The block's live selectors (.fl-builder-content *:before/:after) are intact. "Fixing" the dot would add border-box to every homepage FL descendant — a real rendering change that violates the pixel-parity mandate. Left as-is deliberately.
  • outline: none on lightbox/tab controls (services/single-service/use-cases/single-use-cases): verbatim Magnific Popup / PowerPack export rules, identical to production. Legitimate a11y-debt item for a follow-up pass, not introduced here.

False positive (1):

  • single-career.css share-button "invisible icons": the original e966db44…-layout-bundle.css used var(--color-dark) for both background and icon color too; actual rendered colors come from the base PowerPack skin rules. Verbatim port, zero-diff confirmed by the parity gate.

By design / documented follow-ups (4):

  • Empty selector blocks (homepage/about-us/clients/services/use-cases): verbatim FL-export shells, zero cascade effect; cleanup is a documented non-goal of this PR (ownership-map follow-ups).
  • css_orphan_guard_test.rb "config test": intentional build-integrity guard — an orphaned/missing CSS file crashes the PostCSS production build (incident cited in the test header).
  • contact-us/free-consultation duplicated panel → parameterized partial: documented follow-up; cross-template dedup is an explicit non-goal of the strangler run.

Additional hardening landed alongside the triage: the bare/unknown-fence code-block background (cascade-order-dependent between 586.css and style.css) is now screenshot-locked by test_codeblock_language_styles (fixture post + 32 baselines), so any future cascade flip to the historical invisible-text failure breaks the suite.

🤖 Generated with Claude Code

@pftg
pftg merged commit 1df3333 into master Jul 18, 2026
3 checks passed
@pftg
pftg deleted the css-migration/strangler-run branch July 18, 2026 21:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant