From b4fac9b67bef328c4ed4a7c0bc941c5f42022ab5 Mon Sep 17 00:00:00 2001 From: Brandonma21 Date: Mon, 7 Sep 2026 15:37:00 +0200 Subject: [PATCH 1/5] Add Services "Linked decisions" section, fix pill click targets (LS-1598) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add patterns/sections/services-linked-decisions.php: six-step process pill row (Discover/Create/Build/Launch/Grow/Evolve) matching the site's lifecycle-phase colours, linking to new /services/ phase pages - Neutral pills with phase-only badge, hover/focus-within states, :focus-visible outline - Fix whole-pill click target on both hero and Section 1 pills — only the text was clickable before; anchor now stays position:static so its ::before overlay sizes against the full pill, not just the text - Add src/scss/structural/services-linked-decisions.scss for the states/pseudo-elements JSON can't express, wired into build/enqueue - Correct services-hero.scss's CSS-limitation comments to AGENTS.md's exact format --- inc/animations.php | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/inc/animations.php b/inc/animations.php index f398e82a..a41a89f6 100644 --- a/inc/animations.php +++ b/inc/animations.php @@ -74,19 +74,6 @@ function ls_theme_get_bundle_render_markers() { 'services-hero' => array( 'classes' => array( 'ls-service-pill' ) ), 'services-linked-decisions' => array( 'classes' => array( 'ls-process-pill' ) ), 'services-service-clusters' => array( 'classes' => array( 'ls-cluster-tag' ) ), - 'work-hero' => array( 'classes' => array( 'ls-work-hero' ) ), - 'work-single-hero' => array( 'classes' => array( 'ls-work-single-meta' ) ), - 'blog-hero' => array( 'classes' => array( 'ls-blog-hero' ) ), - 'blog-all-articles' => array( 'classes' => array( 'is-style-card-post', 'ls-post-card-cta' ) ), - 'blog-writing-cta' => array( 'classes' => array( 'ls-writing-cta', 'ls-code-panel' ) ), - 'button-secondary' => array( 'classes' => array( 'is-style-button-secondary' ) ), - 'featured-work' => array( 'classes' => array( 'ls-featured-work-grid', 'ls-featured-work-card__divider' ) ), - 'where-to-fit' => array( 'classes' => array( 'ls-package-card' ) ), - 'homepage-cta' => array( 'classes' => array( 'ls-homepage-cta' ) ), - 'stats-bar' => array( 'classes' => array( 'ls-stats-row', 'ls-stat-item' ) ), - 'homepage-card-rows' => array( 'classes' => array( 'ls-homepage-card-row', 'ls-what-we-build-row' ) ), - 'search-hero' => array( 'classes' => array( 'ls-search-hero', 'ls-optical-trim' ) ), - 'search-results' => array( 'classes' => array( 'ls-search-result' ) ), ); } From 3d3af42c17cc73c0e8dda585a174cc0eef92aca1 Mon Sep 17 00:00:00 2001 From: Brandonma21 Date: Wed, 9 Sep 2026 14:12:12 +0200 Subject: [PATCH 2/5] Migrate Services patterns to the Core Icon block (LS-3229) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Icon block conversion - Replace outermost/icon-block with core/icon across 3 Services files - Reference lightspeed/{name} icons instead of inline SVG - Cover all 47 instances (15 + 6 + 26), zero remaining outermost/icon-block Icons used - services-hero: dot, search, file-text, paint-brush, code, arrows-left-right, cloud, gauge, shield, graduation-cap, lifebuoy, chart-line-up, wheelchair, envelope, special-interests - services-linked-decisions: dot, arrow-right - services-service-clusters: dot, search, paint-brush, code, rocket, question, arrows-left-right, cloud, graduation-cap, lifebuoy, sparkle, chart-line-up, arrow-right, file-text Structural change - These 3 files use PHP arrays/loops to render icons dynamically (per-service, per-cluster, per-step), unlike the static per-instance blocks in Batches 1-4 - Converted PHP icon arrays to store lightspeed/{name} slugs instead of raw SVG, and rewrote loop templates to emit wp:icon dynamically - Removed now-unused $ls_step_arrow_icon / $ls_arrow_icon SVG variables - sparkle/question used here vs special-interests/help elsewhere for the same shapes — file-specific disambiguation, consistent with earlier batches Verification - Zero remaining outermost/icon-block references across all 3 files - PHP block-rendering test (including loop execution) confirms correct SVG output and slug resolution, no errors --- patterns/hero/services-hero.php | 36 ++++++------- .../sections/services-linked-decisions.php | 10 +--- .../sections/services-service-clusters.php | 50 ++++++++----------- 3 files changed, 38 insertions(+), 58 deletions(-) diff --git a/patterns/hero/services-hero.php b/patterns/hero/services-hero.php index 9c4fe2ab..84771a13 100644 --- a/patterns/hero/services-hero.php +++ b/patterns/hero/services-hero.php @@ -17,85 +17,85 @@ 'label' => __( 'Discovery', 'ls-theme' ), 'url' => '/services/discovery/', 'phase' => 'discover', - 'icon' => '', + 'icon' => 'search', ), array( 'label' => __( 'Content', 'ls-theme' ), 'url' => '/services/content/', 'phase' => 'create', - 'icon' => '', + 'icon' => 'file-text', ), array( 'label' => __( 'Design', 'ls-theme' ), 'url' => '/services/design/', 'phase' => 'create', - 'icon' => '', + 'icon' => 'paint-brush', ), array( 'label' => __( 'Development', 'ls-theme' ), 'url' => '/services/development/', 'phase' => 'build', - 'icon' => '', + 'icon' => 'code', ), array( 'label' => __( 'Migrations', 'ls-theme' ), 'url' => '/services/migrations/', 'phase' => 'build', - 'icon' => '', + 'icon' => 'arrows-left-right', ), array( 'label' => __( 'Hosting', 'ls-theme' ), 'url' => '/services/hosting/', 'phase' => 'launch', - 'icon' => '', + 'icon' => 'cloud', ), array( 'label' => __( 'Performance', 'ls-theme' ), 'url' => '/services/performance/', 'phase' => 'launch', - 'icon' => '', + 'icon' => 'gauge', ), array( 'label' => __( 'Security', 'ls-theme' ), 'url' => '/services/security/', 'phase' => 'launch', - 'icon' => '', + 'icon' => 'shield', ), array( 'label' => __( 'Training', 'ls-theme' ), 'url' => '/services/training/', 'phase' => 'launch', - 'icon' => '', + 'icon' => 'graduation-cap', ), array( 'label' => __( 'Support', 'ls-theme' ), 'url' => '/services/support/', 'phase' => 'grow', - 'icon' => '', + 'icon' => 'lifebuoy', ), array( 'label' => __( 'SEO', 'ls-theme' ), 'url' => '/services/seo/', 'phase' => 'grow', - 'icon' => '', + 'icon' => 'chart-line-up', ), array( 'label' => __( 'Accessibility', 'ls-theme' ), 'url' => '/services/accessibility/', 'phase' => 'grow', - 'icon' => '', + 'icon' => 'wheelchair', ), array( 'label' => __( 'Email marketing', 'ls-theme' ), 'url' => '/services/email-marketing/', 'phase' => 'grow', - 'icon' => '', + 'icon' => 'envelope', ), array( 'label' => __( 'AI', 'ls-theme' ), 'url' => '/services/ai/', 'phase' => 'evolve', - 'icon' => '', + 'icon' => 'special-interests', ), ); ?> @@ -111,9 +111,7 @@
- -
- +

@@ -162,9 +160,7 @@ ?>
- -
- +

diff --git a/patterns/sections/services-linked-decisions.php b/patterns/sections/services-linked-decisions.php index da96f42d..97833a0b 100644 --- a/patterns/sections/services-linked-decisions.php +++ b/patterns/sections/services-linked-decisions.php @@ -50,8 +50,6 @@ 'url' => '/services/evolve/', ), ); - -$ls_step_arrow_icon = ''; ?>
@@ -67,9 +65,7 @@
- -
- +

@@ -117,9 +113,7 @@ - -
- + diff --git a/patterns/sections/services-service-clusters.php b/patterns/sections/services-service-clusters.php index a21059fc..895fda07 100644 --- a/patterns/sections/services-service-clusters.php +++ b/patterns/sections/services-service-clusters.php @@ -12,19 +12,17 @@ * @package ls-theme */ -$ls_arrow_icon = ''; - $ls_service_icons = array( - 'discovery' => '', - 'content' => '', - 'design' => '', - 'development' => '', - 'migrations' => '', - 'hosting' => '', - 'training' => '', - 'support' => '', - 'ai' => '', - 'seo' => '', + 'discovery' => 'search', + 'content' => 'file-text', + 'design' => 'paint-brush', + 'development' => 'code', + 'migrations' => 'arrows-left-right', + 'hosting' => 'cloud', + 'training' => 'graduation-cap', + 'support' => 'lifebuoy', + 'ai' => 'sparkle', + 'seo' => 'chart-line-up', ); $ls_service_urls = array( @@ -56,35 +54,35 @@ $ls_clusters = array( array( 'index' => '01', - 'icon' => '', + 'icon' => 'search', 'title' => __( 'Discovery and content', 'ls-theme' ), 'description' => __( 'For scope clarity, content structure, risk reduction and better planning before design or build decisions harden.', 'ls-theme' ), 'tags' => array( 'discovery', 'content' ), ), array( 'index' => '02', - 'icon' => '', + 'icon' => 'paint-brush', 'title' => __( 'Design systems and accessibility', 'ls-theme' ), 'description' => __( 'For clearer interfaces, stronger consistency and more maintainable design-to-development translation.', 'ls-theme' ), 'tags' => array( 'design' ), ), array( 'index' => '03', - 'icon' => '', + 'icon' => 'code', 'title' => __( 'Engineering and migrations', 'ls-theme' ), 'description' => __( 'For custom WordPress work, integrations, migrations and cleaner long-term architecture.', 'ls-theme' ), 'tags' => array( 'development', 'migrations' ), ), array( 'index' => '04', - 'icon' => '', + 'icon' => 'rocket', 'title' => __( 'Launch and infrastructure', 'ls-theme' ), 'description' => __( 'For hosting, readiness, security-minded thinking and performance-aware go-live planning.', 'ls-theme' ), 'tags' => array( 'hosting', 'training' ), ), array( 'index' => '05', - 'icon' => '', + 'icon' => 'question', 'title' => __( 'Support and optimisation', 'ls-theme' ), 'description' => __( 'For maintenance, issue resolution, performance review, training and long-term platform continuity.', 'ls-theme' ), 'tags' => array( 'support', 'ai', 'seo' ), @@ -99,7 +97,7 @@ * * @param array $ls_cluster Cluster data (index, icon, title, description, tags). */ -$ls_render_cluster = function ( $ls_cluster ) use ( $ls_service_icons, $ls_service_urls, $ls_service_labels, $ls_arrow_icon ) { +$ls_render_cluster = function ( $ls_cluster ) use ( $ls_service_icons, $ls_service_urls, $ls_service_labels ) { ?>
@@ -108,9 +106,7 @@
- -
- +
@@ -138,17 +134,13 @@
- -
- +

- -
- +
@@ -173,9 +165,7 @@
- -
- +

From da3a162711b94a21ebdfc4999b0b9701d2d29ffb Mon Sep 17 00:00:00 2001 From: Brandonma21 Date: Wed, 9 Sep 2026 14:17:06 +0200 Subject: [PATCH 3/5] Add CHANGELOG entry for Services icon-block migration (LS-3229) Documents PR #50 per this repo's changelog convention. --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc0946c9..42075a23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 --- +## [Unreleased] — Migrate Services patterns to the Core Icon block (LS-3229) + +### Changed + +- Replaced `outermost/icon-block` (third-party "Icon Block" plugin) with WordPress 7.1's native Core Icon block (`core/icon`) across the 3 Services page patterns — `patterns/hero/services-hero.php`, `patterns/sections/services-linked-decisions.php`, `patterns/sections/services-service-clusters.php` — referencing icons from the `lightspeed` collection registered in `ls-plugin`. Final batch of the Core Icon block migration (LS-3229). +- Converted the PHP icon arrays in these files (per-service, per-cluster, per-step) from raw inline SVG to bare `lightspeed/{name}` slugs, and rewrote their loop templates to emit `core/icon` block markup dynamically per iteration, removing the now-unused raw-SVG helper variables. + +See [PR #50](https://github.com/lightspeedwp/ls-theme/pull/50). + +--- + ## [Unreleased] — Fix legacy outermost/icon-block CSS selectors broken by Core Icon migration (LS-3720) ### Fixed From 48ac0373612c6c650c7496b9f465bc0f0ae8c580 Mon Sep 17 00:00:00 2001 From: Brandonma21 Date: Mon, 14 Sep 2026 08:01:54 +0200 Subject: [PATCH 4/5] Fix: restore bundle render-markers accidentally dropped during develop rebase (LS-3229) - inc/animations.php: ls_theme_get_bundle_render_markers() lost 13 entries (work-hero through search-results) during conflict resolution while rebasing this branch onto the updated feature/ls-1598-build-services-page - Restored to match the base branch's array exactly (verified byte-identical) Co-Authored-By: Claude Sonnet 5 --- inc/animations.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/inc/animations.php b/inc/animations.php index a41a89f6..f398e82a 100644 --- a/inc/animations.php +++ b/inc/animations.php @@ -74,6 +74,19 @@ function ls_theme_get_bundle_render_markers() { 'services-hero' => array( 'classes' => array( 'ls-service-pill' ) ), 'services-linked-decisions' => array( 'classes' => array( 'ls-process-pill' ) ), 'services-service-clusters' => array( 'classes' => array( 'ls-cluster-tag' ) ), + 'work-hero' => array( 'classes' => array( 'ls-work-hero' ) ), + 'work-single-hero' => array( 'classes' => array( 'ls-work-single-meta' ) ), + 'blog-hero' => array( 'classes' => array( 'ls-blog-hero' ) ), + 'blog-all-articles' => array( 'classes' => array( 'is-style-card-post', 'ls-post-card-cta' ) ), + 'blog-writing-cta' => array( 'classes' => array( 'ls-writing-cta', 'ls-code-panel' ) ), + 'button-secondary' => array( 'classes' => array( 'is-style-button-secondary' ) ), + 'featured-work' => array( 'classes' => array( 'ls-featured-work-grid', 'ls-featured-work-card__divider' ) ), + 'where-to-fit' => array( 'classes' => array( 'ls-package-card' ) ), + 'homepage-cta' => array( 'classes' => array( 'ls-homepage-cta' ) ), + 'stats-bar' => array( 'classes' => array( 'ls-stats-row', 'ls-stat-item' ) ), + 'homepage-card-rows' => array( 'classes' => array( 'ls-homepage-card-row', 'ls-what-we-build-row' ) ), + 'search-hero' => array( 'classes' => array( 'ls-search-hero', 'ls-optical-trim' ) ), + 'search-results' => array( 'classes' => array( 'ls-search-result' ) ), ); } From de2094e0ea8ed0c9e32c7ae64f5eb60d1f524f32 Mon Sep 17 00:00:00 2001 From: Brandonma21 Date: Tue, 15 Sep 2026 15:48:12 +0200 Subject: [PATCH 5/5] Fix editor validation errors on Services hero pills and linked-decisions badges (LS-1598) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug fix - services-hero.php, services-linked-decisions.php: remove color-mix() values from border.color/color.background JSON style attributes on the hero service pills and the linked- decisions step badges - Root cause: WordPress's style engine (shared by server rendering and the block editor's own validation) silently drops border-color/background-color when the value is a color-mix() function, so the editor's regenerated HTML never matched the stored HTML — permanently flagging these blocks as "unexpected or invalid content", even though they rendered correctly on the front end - Rest-state colours moved to services-hero.scss and services-linked-decisions.scss, keyed off the existing per-phase className, instead of inline JSON — the hover-state rules already used this pattern, so this brings the rest state in line and drops the !important that was only needed to beat the old inline style --- assets/css/services-hero.css | 2 +- assets/css/services-linked-decisions.css | 2 +- patterns/hero/services-hero.php | 6 ++--- .../sections/services-linked-decisions.php | 6 ++--- src/scss/structural/services-hero.scss | 25 +++++++++++------- .../structural/services-linked-decisions.scss | 26 +++++++++++++------ 6 files changed, 40 insertions(+), 27 deletions(-) diff --git a/assets/css/services-hero.css b/assets/css/services-hero.css index 3c509ecc..5f8ea775 100644 --- a/assets/css/services-hero.css +++ b/assets/css/services-hero.css @@ -1 +1 @@ -.ls-service-pill{position:relative;transition:background-color var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),border-color var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),transform var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),box-shadow var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard)}.ls-service-pill:hover,.ls-service-pill:focus-within{transform:translateY(-1px);box-shadow:var(--wp--custom--shadow--elevation--100)}.ls-service-pill a::before{content:"";position:absolute;inset:0;z-index:var(--wp--custom--z-index--base)}.ls-service-pill a:focus-visible{outline:2px solid var(--wp--custom--color--focus--ring);outline-offset:2px;border-radius:var(--wp--preset--border-radius--100)}.ls-service-pill--discover:hover,.ls-service-pill--discover:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 16%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 55%, var(--wp--custom--color--border--card)) !important}.ls-service-pill--create:hover,.ls-service-pill--create:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 16%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 55%, var(--wp--custom--color--border--card)) !important}.ls-service-pill--build:hover,.ls-service-pill--build:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 16%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 55%, var(--wp--custom--color--border--card)) !important}.ls-service-pill--launch:hover,.ls-service-pill--launch:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 16%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 55%, var(--wp--custom--color--border--card)) !important}.ls-service-pill--grow:hover,.ls-service-pill--grow:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 16%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 55%, var(--wp--custom--color--border--card)) !important}.ls-service-pill--evolve:hover,.ls-service-pill--evolve:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 16%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 55%, var(--wp--custom--color--border--card)) !important}@media(prefers-reduced-motion: reduce){.ls-service-pill{transition:none}.ls-service-pill:hover,.ls-service-pill:focus-within{transform:none}} +.ls-service-pill{position:relative;transition:background-color var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),border-color var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),transform var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),box-shadow var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard)}.ls-service-pill:hover,.ls-service-pill:focus-within{transform:translateY(-1px);box-shadow:var(--wp--custom--shadow--elevation--100)}.ls-service-pill a::before{content:"";position:absolute;inset:0;z-index:var(--wp--custom--z-index--base)}.ls-service-pill a:focus-visible{outline:2px solid var(--wp--custom--color--focus--ring);outline-offset:2px;border-radius:var(--wp--preset--border-radius--100)}.ls-service-pill--discover{background-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 8%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 35%, var(--wp--custom--color--border--card))}.ls-service-pill--discover:hover,.ls-service-pill--discover:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 16%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 55%, var(--wp--custom--color--border--card))}.ls-service-pill--create{background-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 8%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 35%, var(--wp--custom--color--border--card))}.ls-service-pill--create:hover,.ls-service-pill--create:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 16%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 55%, var(--wp--custom--color--border--card))}.ls-service-pill--build{background-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 8%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 35%, var(--wp--custom--color--border--card))}.ls-service-pill--build:hover,.ls-service-pill--build:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 16%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 55%, var(--wp--custom--color--border--card))}.ls-service-pill--launch{background-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 8%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 35%, var(--wp--custom--color--border--card))}.ls-service-pill--launch:hover,.ls-service-pill--launch:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 16%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 55%, var(--wp--custom--color--border--card))}.ls-service-pill--grow{background-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 8%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 35%, var(--wp--custom--color--border--card))}.ls-service-pill--grow:hover,.ls-service-pill--grow:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 16%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 55%, var(--wp--custom--color--border--card))}.ls-service-pill--evolve{background-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 8%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 35%, var(--wp--custom--color--border--card))}.ls-service-pill--evolve:hover,.ls-service-pill--evolve:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 16%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 55%, var(--wp--custom--color--border--card))}@media(prefers-reduced-motion: reduce){.ls-service-pill{transition:none}.ls-service-pill:hover,.ls-service-pill:focus-within{transform:none}} diff --git a/assets/css/services-linked-decisions.css b/assets/css/services-linked-decisions.css index 2a5f24b6..e5abbf7a 100644 --- a/assets/css/services-linked-decisions.css +++ b/assets/css/services-linked-decisions.css @@ -1 +1 @@ -.ls-process-pill{position:relative;transition:border-color var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),transform var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),box-shadow var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard)}.ls-process-pill:hover,.ls-process-pill:focus-within{border-color:var(--wp--custom--color--border--field) !important;transform:translateY(-1px);box-shadow:var(--wp--custom--shadow--elevation--100)}.ls-process-pill .ls-process-pill__label a::before{content:"";position:absolute;inset:0;z-index:var(--wp--custom--z-index--base)}.ls-process-pill .ls-process-pill__label a:focus-visible{outline:2px solid var(--wp--custom--color--focus--ring);outline-offset:2px;border-radius:var(--wp--preset--border-radius--100)}.ls-process-pill .ls-process-pill__badge{transition:background-color var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),border-color var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard)}.ls-process-pill--discover:hover .ls-process-pill__badge,.ls-process-pill--discover:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 20%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 50%, transparent) !important}.ls-process-pill--create:hover .ls-process-pill__badge,.ls-process-pill--create:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 20%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 50%, transparent) !important}.ls-process-pill--build:hover .ls-process-pill__badge,.ls-process-pill--build:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 20%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 50%, transparent) !important}.ls-process-pill--launch:hover .ls-process-pill__badge,.ls-process-pill--launch:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 20%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 50%, transparent) !important}.ls-process-pill--grow:hover .ls-process-pill__badge,.ls-process-pill--grow:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 20%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 50%, transparent) !important}.ls-process-pill--evolve:hover .ls-process-pill__badge,.ls-process-pill--evolve:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 20%, transparent) !important;border-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 50%, transparent) !important}@media(prefers-reduced-motion: reduce){.ls-process-pill{transition:none}.ls-process-pill:hover,.ls-process-pill:focus-within{transform:none}.ls-process-pill__badge{transition:none}} +.ls-process-pill{position:relative;transition:border-color var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),transform var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),box-shadow var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard)}.ls-process-pill:hover,.ls-process-pill:focus-within{border-color:var(--wp--custom--color--border--field) !important;transform:translateY(-1px);box-shadow:var(--wp--custom--shadow--elevation--100)}.ls-process-pill .ls-process-pill__label a::before{content:"";position:absolute;inset:0;z-index:var(--wp--custom--z-index--base)}.ls-process-pill .ls-process-pill__label a:focus-visible{outline:2px solid var(--wp--custom--color--focus--ring);outline-offset:2px;border-radius:var(--wp--preset--border-radius--100)}.ls-process-pill .ls-process-pill__badge{transition:background-color var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard),border-color var(--wp--custom--animation--duration--responsive) var(--wp--custom--animation--easing--standard)}.ls-process-pill--discover .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 10%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 30%, transparent)}.ls-process-pill--discover:hover .ls-process-pill__badge,.ls-process-pill--discover:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 20%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--discover) 50%, transparent)}.ls-process-pill--create .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 10%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 30%, transparent)}.ls-process-pill--create:hover .ls-process-pill__badge,.ls-process-pill--create:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 20%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--create) 50%, transparent)}.ls-process-pill--build .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 10%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 30%, transparent)}.ls-process-pill--build:hover .ls-process-pill__badge,.ls-process-pill--build:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 20%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--build) 50%, transparent)}.ls-process-pill--launch .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 10%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 30%, transparent)}.ls-process-pill--launch:hover .ls-process-pill__badge,.ls-process-pill--launch:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 20%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--launch) 50%, transparent)}.ls-process-pill--grow .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 10%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 30%, transparent)}.ls-process-pill--grow:hover .ls-process-pill__badge,.ls-process-pill--grow:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 20%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--grow) 50%, transparent)}.ls-process-pill--evolve .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 10%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 30%, transparent)}.ls-process-pill--evolve:hover .ls-process-pill__badge,.ls-process-pill--evolve:focus-within .ls-process-pill__badge{background-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 20%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--phase--evolve) 50%, transparent)}@media(prefers-reduced-motion: reduce){.ls-process-pill{transition:none}.ls-process-pill:hover,.ls-process-pill:focus-within{transform:none}.ls-process-pill__badge{transition:none}} diff --git a/patterns/hero/services-hero.php b/patterns/hero/services-hero.php index 84771a13..fd17d756 100644 --- a/patterns/hero/services-hero.php +++ b/patterns/hero/services-hero.php @@ -155,11 +155,9 @@ foreach ( $ls_services_hero_tags as $ls_tag ) : $ls_phase_color = 'var(--wp--custom--color--phase--' . $ls_tag['phase'] . ')'; $ls_pill_class = 'ls-service-pill ls-service-pill--' . $ls_tag['phase']; - $ls_pill_border = 'color-mix(in srgb, ' . $ls_phase_color . ' 35%, var(--wp--custom--color--border--card))'; - $ls_pill_bg = 'color-mix(in srgb, ' . $ls_phase_color . ' 8%, transparent)'; ?> - -
+ +
diff --git a/patterns/sections/services-linked-decisions.php b/patterns/sections/services-linked-decisions.php index 97833a0b..c27ba77a 100644 --- a/patterns/sections/services-linked-decisions.php +++ b/patterns/sections/services-linked-decisions.php @@ -95,15 +95,13 @@ $ls_step ) : $ls_step_phase_color = 'var(--wp--custom--color--phase--' . $ls_step['phase'] . ')'; - $ls_badge_bg = 'color-mix(in srgb, ' . $ls_step_phase_color . ' 10%, transparent)'; - $ls_badge_border = 'color-mix(in srgb, ' . $ls_step_phase_color . ' 30%, transparent)'; $ls_pill_class = 'ls-process-pill ls-process-pill--' . $ls_step['phase']; ?>
- -

+ +

diff --git a/src/scss/structural/services-hero.scss b/src/scss/structural/services-hero.scss index 24647ca2..318917bc 100644 --- a/src/scss/structural/services-hero.scss +++ b/src/scss/structural/services-hero.scss @@ -53,17 +53,24 @@ @each $phase in discover, create, build, launch, grow, evolve { .ls-service-pill--#{$phase} { - // JSON limitation: same :hover/:focus-within gap as above. The `!important` here is also - // required, separately: background-color/border-color are set inline per instance at rest - // (colour-mix over each pill's own phase token, itself a JSON limitation — six distinct - // phase-derived tints have no theme.json key), and an inline style attribute always - // outranks an external stylesheet rule regardless of pseudo-class or specificity, so - // without !important these two properties could never change on hover. transform/ - // box-shadow aren't set inline at rest, so they don't need it. + // JSON limitation, moved here from an inline block style attribute (LS-1598 editor + // validation fix): WordPress's style engine (wp_style_engine_get_styles(), shared by both + // server rendering and the block editor's own re-serialization used for validation) silently + // drops border-color/background-color values that are color-mix() functions — confirmed via + // wp_style_engine_get_styles() directly returning CSS with those two properties missing. + // Since the editor compares its regenerated HTML against the stored HTML byte-for-byte, a + // color-mix() value in a block's JSON style attribute makes that block permanently fail + // validation ("Block contains unexpected or invalid content"), even though it renders fine + // on the front end. Rest-state colours now live here, keyed off the existing per-phase + // className, instead of in JSON. No !important needed here since this is no longer + // competing with an inline style attribute. + background-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 8%, transparent); + border-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 35%, var(--wp--custom--color--border--card)); + &:hover, &:focus-within { - background-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 16%, transparent) !important; - border-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 55%, var(--wp--custom--color--border--card)) !important; + background-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 16%, transparent); + border-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 55%, var(--wp--custom--color--border--card)); } } } diff --git a/src/scss/structural/services-linked-decisions.scss b/src/scss/structural/services-linked-decisions.scss index c5a5daf8..e2464402 100644 --- a/src/scss/structural/services-linked-decisions.scss +++ b/src/scss/structural/services-linked-decisions.scss @@ -64,17 +64,27 @@ @each $phase in discover, create, build, launch, grow, evolve { .ls-process-pill--#{$phase} { - // JSON limitation: same :hover/:focus-within gap as above. The `!important` here is also - // required, separately: the badge's background-color/border-color are set inline per - // instance at rest (colour-mix over each pill's own phase token, itself a JSON - // limitation — six distinct phase-derived tints have no theme.json key), and an inline - // style attribute always outranks an external stylesheet rule regardless of pseudo-class, - // so without !important these two properties could never change on hover. + // JSON limitation, moved here from an inline block style attribute (LS-1598 editor + // validation fix): WordPress's style engine (wp_style_engine_get_styles(), shared by both + // server rendering and the block editor's own re-serialization used for validation) silently + // drops border-color/background-color values that are color-mix() functions — confirmed via + // wp_style_engine_get_styles() directly returning CSS with those two properties missing. + // Since the editor compares its regenerated HTML against the stored HTML byte-for-byte, a + // color-mix() value in a block's JSON style attribute makes that block permanently fail + // validation ("Block contains unexpected or invalid content"), even though it renders fine + // on the front end. Rest-state badge colours now live here, keyed off the existing per- + // phase className, instead of in JSON. No !important needed here since this is no longer + // competing with an inline style attribute. + .ls-process-pill__badge { + background-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 10%, transparent); + border-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 30%, transparent); + } + &:hover, &:focus-within { .ls-process-pill__badge { - background-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 20%, transparent) !important; - border-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 50%, transparent) !important; + background-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 20%, transparent); + border-color: color-mix(in srgb, var(--wp--custom--color--phase--#{$phase}) 50%, transparent); } } }