diff --git a/CHANGELOG.md b/CHANGELOG.md index 90b3461..eb25727 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 --- +## [Unreleased] — Add flatten-proof phase colour and a phase-services dynamic block (LS-4179) + +### Fixed + +- Phase page colour (hero buttons, breadcrumb "current page" text) no longer goes black/white when a phase section's pattern is flattened by the block editor, and no longer stays hardcoded to Discover's green on the other five phase pages. Added `--ls-phase-accent`/`--ls-phase-accent-on-dark` custom properties (`src/scss/structural/phase-journey-nav.scss`), set per phase via the existing `page-slug-{phase}` body class, so colour is resolved by CSS on every request instead of being computed in PHP or baked into a pattern's stored content. `styles/blocks/buttons/button-phase-primary.json`, `button-phase-outline.json`, `src/scss/structural/button-phase.scss`, and `src/scss/structural/phase-hero.scss` were hardwired directly to Discover's token — swapped all four to the new shared property. +- `patterns/sections/phase-services-in-phase.php` selected its "Services in this phase" cards via `get_queried_object()` inside the pattern's own PHP, which only re-evaluates while the pattern stays a live `wp:pattern` reference, falling back to Discover's services once flattened. Moved that selection into a new `ls-theme/phase-services` dynamic block (`blocks/phase-services/`), which resolves the current phase from block context at real render time and isn't affected by pattern flattening. + +([#72](https://github.com/lightspeedwp/ls-theme/pull/72)) + +--- + ## [Unreleased] — Refine Phase Where To Go Next section to match prototype (LS-4179) ### Changed diff --git a/assets/css/button-phase.css b/assets/css/button-phase.css index 0ee6cf4..6225899 100644 --- a/assets/css/button-phase.css +++ b/assets/css/button-phase.css @@ -1 +1 @@ -.wp-block-button.is-style-button-phase-primary,.wp-block-button.is-style-button-phase-outline{border-radius:var(--wp--preset--border-radius--500)}.wp-block-button.is-style-button-phase-primary:hover,.wp-block-button.is-style-button-phase-outline:hover{border-radius:var(--wp--preset--border-radius--300)}.wp-block-button.is-style-button-phase-primary .wp-block-button__link,.wp-block-button.is-style-button-phase-outline .wp-block-button__link{border-radius:inherit}.wp-block-button.is-style-button-phase-primary:hover .wp-block-button__link,.wp-block-button.is-style-button-phase-outline:hover .wp-block-button__link{border-radius:var(--wp--preset--border-radius--300)}.wp-block-button.is-style-button-phase-outline:hover .wp-block-button__link{color:var(--wp--custom--color--text--on-light);border-color:rgba(0,0,0,0)}.wp-block-button.is-style-button-phase-outline .wp-block-button__link::before{content:"";position:absolute;top:50%;left:50%;min-width:100%;min-height:100%;aspect-ratio:1;transform:translate(-50%, -50%) scale(0);border-radius:50%;background-color:var(--wp--custom--color--phase--discover-on-dark);opacity:0;z-index:-1}.wp-block-button.is-style-button-phase-outline:hover .wp-block-button__link::before{transform:translate(-50%, -50%) scale(1.42);opacity:1} +.wp-block-button.is-style-button-phase-primary,.wp-block-button.is-style-button-phase-outline{border-radius:var(--wp--preset--border-radius--500)}.wp-block-button.is-style-button-phase-primary:hover,.wp-block-button.is-style-button-phase-outline:hover{border-radius:var(--wp--preset--border-radius--300)}.wp-block-button.is-style-button-phase-primary .wp-block-button__link,.wp-block-button.is-style-button-phase-outline .wp-block-button__link{border-radius:inherit}.wp-block-button.is-style-button-phase-primary:hover .wp-block-button__link,.wp-block-button.is-style-button-phase-outline:hover .wp-block-button__link{border-radius:var(--wp--preset--border-radius--300)}.wp-block-button.is-style-button-phase-outline:hover .wp-block-button__link{color:var(--wp--custom--color--text--on-light);border-color:rgba(0,0,0,0)}.wp-block-button.is-style-button-phase-outline .wp-block-button__link::before{content:"";position:absolute;top:50%;left:50%;min-width:100%;min-height:100%;aspect-ratio:1;transform:translate(-50%, -50%) scale(0);border-radius:50%;background-color:var(--ls-phase-accent-on-dark);opacity:0;z-index:-1}.wp-block-button.is-style-button-phase-outline:hover .wp-block-button__link::before{transform:translate(-50%, -50%) scale(1.42);opacity:1} diff --git a/assets/css/phase-hero.css b/assets/css/phase-hero.css index efd1230..1d38367 100644 --- a/assets/css/phase-hero.css +++ b/assets/css/phase-hero.css @@ -1 +1 @@ -.ls-phase-hero{position:relative;overflow:hidden;background-image:linear-gradient(color-mix(in srgb, var(--wp--custom--color--text--on-dark) 2%, transparent) 1px, transparent 1px),linear-gradient(90deg, color-mix(in srgb, var(--wp--custom--color--text--on-dark) 2%, transparent) 1px, transparent 1px),radial-gradient(60% 50% at 50% 22%, color-mix(in srgb, var(--wp--custom--color--phase--discover-on-dark) 14%, transparent) 0%, transparent 70%),linear-gradient(158deg, var(--wp--custom--color--surface--band-start) 0%, var(--wp--custom--color--surface--band-end) 100%);background-position:0 0,0 0,0 0,0 0;background-repeat:repeat,repeat,no-repeat,no-repeat;background-size:32px 32px,32px 32px,auto,auto}.ls-phase-hero .ls-breadcrumbs-on-dark a{color:var(--wp--custom--color--text--on-dark-muted)}.ls-phase-hero .breadcrumb_last{color:var(--wp--custom--color--phase--discover-on-dark)}.ls-phase-hero__share{background-color:color-mix(in srgb, var(--wp--custom--color--text--on-dark) 5%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--text--on-dark) 8%, transparent);transition:background-color var(--wp--custom--animation--duration--base) var(--wp--custom--animation--easing--standard),border-color var(--wp--custom--animation--duration--base) var(--wp--custom--animation--easing--standard)}.ls-phase-hero__share:hover,.ls-phase-hero__share:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--text--on-dark) 9%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--text--on-dark) 16%, transparent)}@media(prefers-reduced-motion: reduce){.ls-phase-hero__share{transition:none}} +.ls-phase-hero{position:relative;overflow:hidden;background-image:linear-gradient(color-mix(in srgb, var(--wp--custom--color--text--on-dark) 2%, transparent) 1px, transparent 1px),linear-gradient(90deg, color-mix(in srgb, var(--wp--custom--color--text--on-dark) 2%, transparent) 1px, transparent 1px),radial-gradient(60% 50% at 50% 22%, color-mix(in srgb, var(--ls-phase-accent-on-dark) 14%, transparent) 0%, transparent 70%),linear-gradient(158deg, var(--wp--custom--color--surface--band-start) 0%, var(--wp--custom--color--surface--band-end) 100%);background-position:0 0,0 0,0 0,0 0;background-repeat:repeat,repeat,no-repeat,no-repeat;background-size:32px 32px,32px 32px,auto,auto}.ls-phase-hero .ls-breadcrumbs-on-dark a{color:var(--wp--custom--color--text--on-dark-muted)}.ls-phase-hero .breadcrumb_last{color:var(--ls-phase-accent-on-dark)}.ls-phase-hero__share{background-color:color-mix(in srgb, var(--wp--custom--color--text--on-dark) 5%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--text--on-dark) 8%, transparent);transition:background-color var(--wp--custom--animation--duration--base) var(--wp--custom--animation--easing--standard),border-color var(--wp--custom--animation--duration--base) var(--wp--custom--animation--easing--standard)}.ls-phase-hero__share:hover,.ls-phase-hero__share:focus-within{background-color:color-mix(in srgb, var(--wp--custom--color--text--on-dark) 9%, transparent);border-color:color-mix(in srgb, var(--wp--custom--color--text--on-dark) 16%, transparent)}@media(prefers-reduced-motion: reduce){.ls-phase-hero__share{transition:none}} diff --git a/assets/css/phase-journey-nav.css b/assets/css/phase-journey-nav.css index b9db564..5da286c 100644 --- a/assets/css/phase-journey-nav.css +++ b/assets/css/phase-journey-nav.css @@ -1 +1 @@ -.ls-phase-journey-nav__step--discover{--ls-phase-item-accent: var(--wp--custom--color--phase--discover-on-dark, var(--wp--custom--color--phase--discover))}.ls-phase-journey-nav__step--create{--ls-phase-item-accent: var(--wp--custom--color--phase--create-on-dark, var(--wp--custom--color--phase--create))}.ls-phase-journey-nav__step--build{--ls-phase-item-accent: var(--wp--custom--color--phase--build-on-dark, var(--wp--custom--color--phase--build))}.ls-phase-journey-nav__step--launch{--ls-phase-item-accent: var(--wp--custom--color--phase--launch-on-dark, var(--wp--custom--color--phase--launch))}.ls-phase-journey-nav__step--grow{--ls-phase-item-accent: var(--wp--custom--color--phase--grow-on-dark, var(--wp--custom--color--phase--grow))}.ls-phase-journey-nav__step--evolve{--ls-phase-item-accent: var(--wp--custom--color--phase--evolve-on-dark, var(--wp--custom--color--phase--evolve))}.ls-phase-journey-nav__link a{transition:color var(--wp--custom--animation--duration--base) var(--wp--custom--animation--easing--standard)}.ls-phase-journey-nav__link a{color:color-mix(in srgb, var(--wp--custom--color--text--on-dark-muted) 70%, transparent)}.ls-phase-journey-nav__link a:hover,.ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}.ls-phase-journey-nav__dot{display:none}body.page-slug-discover .ls-phase-journey-nav__step--discover .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-discover .ls-phase-journey-nav__step--discover .ls-phase-journey-nav__link a:hover,body.page-slug-discover .ls-phase-journey-nav__step--discover .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-discover .ls-phase-journey-nav__step--discover .ls-phase-journey-nav__dot{display:inline-flex}body.page-slug-create .ls-phase-journey-nav__step--create .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-create .ls-phase-journey-nav__step--create .ls-phase-journey-nav__link a:hover,body.page-slug-create .ls-phase-journey-nav__step--create .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-create .ls-phase-journey-nav__step--create .ls-phase-journey-nav__dot{display:inline-flex}body.page-slug-build .ls-phase-journey-nav__step--build .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-build .ls-phase-journey-nav__step--build .ls-phase-journey-nav__link a:hover,body.page-slug-build .ls-phase-journey-nav__step--build .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-build .ls-phase-journey-nav__step--build .ls-phase-journey-nav__dot{display:inline-flex}body.page-slug-launch .ls-phase-journey-nav__step--launch .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-launch .ls-phase-journey-nav__step--launch .ls-phase-journey-nav__link a:hover,body.page-slug-launch .ls-phase-journey-nav__step--launch .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-launch .ls-phase-journey-nav__step--launch .ls-phase-journey-nav__dot{display:inline-flex}body.page-slug-grow .ls-phase-journey-nav__step--grow .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-grow .ls-phase-journey-nav__step--grow .ls-phase-journey-nav__link a:hover,body.page-slug-grow .ls-phase-journey-nav__step--grow .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-grow .ls-phase-journey-nav__step--grow .ls-phase-journey-nav__dot{display:inline-flex}body.page-slug-evolve .ls-phase-journey-nav__step--evolve .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-evolve .ls-phase-journey-nav__step--evolve .ls-phase-journey-nav__link a:hover,body.page-slug-evolve .ls-phase-journey-nav__step--evolve .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-evolve .ls-phase-journey-nav__step--evolve .ls-phase-journey-nav__dot{display:inline-flex}.ls-phase-journey-nav__link a:focus-visible{outline:2px solid var(--wp--custom--color--text--on-dark);outline-offset:3px;border-radius:var(--wp--preset--border-radius--100)}@media(prefers-reduced-motion: reduce){.ls-phase-journey-nav__link a{transition:none}}@media(max-width: 781px){.ls-phase-journey-nav__items{overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}.ls-phase-journey-nav__items::-webkit-scrollbar{display:none}.ls-phase-journey-nav__step{flex-shrink:0}} +.ls-phase-journey-nav__step--discover{--ls-phase-item-accent: var(--wp--custom--color--phase--discover-on-dark, var(--wp--custom--color--phase--discover))}.ls-phase-journey-nav__step--create{--ls-phase-item-accent: var(--wp--custom--color--phase--create-on-dark, var(--wp--custom--color--phase--create))}.ls-phase-journey-nav__step--build{--ls-phase-item-accent: var(--wp--custom--color--phase--build-on-dark, var(--wp--custom--color--phase--build))}.ls-phase-journey-nav__step--launch{--ls-phase-item-accent: var(--wp--custom--color--phase--launch-on-dark, var(--wp--custom--color--phase--launch))}.ls-phase-journey-nav__step--grow{--ls-phase-item-accent: var(--wp--custom--color--phase--grow-on-dark, var(--wp--custom--color--phase--grow))}.ls-phase-journey-nav__step--evolve{--ls-phase-item-accent: var(--wp--custom--color--phase--evolve-on-dark, var(--wp--custom--color--phase--evolve))}.ls-phase-journey-nav__link a{transition:color var(--wp--custom--animation--duration--base) var(--wp--custom--animation--easing--standard)}.ls-phase-journey-nav__link a{color:color-mix(in srgb, var(--wp--custom--color--text--on-dark-muted) 70%, transparent)}.ls-phase-journey-nav__link a:hover,.ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}.ls-phase-journey-nav__dot{display:none}body.page-slug-discover{--ls-phase-accent-on-dark: var(--wp--custom--color--phase--discover-on-dark, var(--wp--custom--color--phase--discover))}body.page-slug-create{--ls-phase-accent-on-dark: var(--wp--custom--color--phase--create-on-dark, var(--wp--custom--color--phase--create))}body.page-slug-build{--ls-phase-accent-on-dark: var(--wp--custom--color--phase--build-on-dark, var(--wp--custom--color--phase--build))}body.page-slug-launch{--ls-phase-accent-on-dark: var(--wp--custom--color--phase--launch-on-dark, var(--wp--custom--color--phase--launch))}body.page-slug-grow{--ls-phase-accent-on-dark: var(--wp--custom--color--phase--grow-on-dark, var(--wp--custom--color--phase--grow))}body.page-slug-evolve{--ls-phase-accent-on-dark: var(--wp--custom--color--phase--evolve-on-dark, var(--wp--custom--color--phase--evolve))}body.page-slug-discover .ls-phase-journey-nav__step--discover .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-discover .ls-phase-journey-nav__step--discover .ls-phase-journey-nav__link a:hover,body.page-slug-discover .ls-phase-journey-nav__step--discover .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-discover .ls-phase-journey-nav__step--discover .ls-phase-journey-nav__dot{display:inline-flex}body.page-slug-create .ls-phase-journey-nav__step--create .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-create .ls-phase-journey-nav__step--create .ls-phase-journey-nav__link a:hover,body.page-slug-create .ls-phase-journey-nav__step--create .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-create .ls-phase-journey-nav__step--create .ls-phase-journey-nav__dot{display:inline-flex}body.page-slug-build .ls-phase-journey-nav__step--build .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-build .ls-phase-journey-nav__step--build .ls-phase-journey-nav__link a:hover,body.page-slug-build .ls-phase-journey-nav__step--build .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-build .ls-phase-journey-nav__step--build .ls-phase-journey-nav__dot{display:inline-flex}body.page-slug-launch .ls-phase-journey-nav__step--launch .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-launch .ls-phase-journey-nav__step--launch .ls-phase-journey-nav__link a:hover,body.page-slug-launch .ls-phase-journey-nav__step--launch .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-launch .ls-phase-journey-nav__step--launch .ls-phase-journey-nav__dot{display:inline-flex}body.page-slug-grow .ls-phase-journey-nav__step--grow .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-grow .ls-phase-journey-nav__step--grow .ls-phase-journey-nav__link a:hover,body.page-slug-grow .ls-phase-journey-nav__step--grow .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-grow .ls-phase-journey-nav__step--grow .ls-phase-journey-nav__dot{display:inline-flex}body.page-slug-evolve .ls-phase-journey-nav__step--evolve .ls-phase-journey-nav__link a{color:var(--ls-phase-item-accent)}body.page-slug-evolve .ls-phase-journey-nav__step--evolve .ls-phase-journey-nav__link a:hover,body.page-slug-evolve .ls-phase-journey-nav__step--evolve .ls-phase-journey-nav__link a:focus-visible{color:var(--wp--custom--color--text--on-dark)}body.page-slug-evolve .ls-phase-journey-nav__step--evolve .ls-phase-journey-nav__dot{display:inline-flex}.ls-phase-journey-nav__link a:focus-visible{outline:2px solid var(--wp--custom--color--text--on-dark);outline-offset:3px;border-radius:var(--wp--preset--border-radius--100)}@media(prefers-reduced-motion: reduce){.ls-phase-journey-nav__link a{transition:none}}@media(max-width: 781px){.ls-phase-journey-nav__items{overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none}.ls-phase-journey-nav__items::-webkit-scrollbar{display:none}.ls-phase-journey-nav__step{flex-shrink:0}} diff --git a/blocks/phase-services/block.json b/blocks/phase-services/block.json new file mode 100644 index 0000000..e64ee3e --- /dev/null +++ b/blocks/phase-services/block.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://schemas.wp.org/trunk/block.json", + "apiVersion": 3, + "name": "ls-theme/phase-services", + "title": "Phase Services", + "category": "text", + "description": "Renders the current lifecycle phase page's \"Services in this phase\" heading and service cards. Implements CodeRabbit's request-time rendering fix for patterns/sections/phase-services-in-phase.php: PHP phase-detection baked into a pattern's own content only re-evaluates while the pattern stays a live wp:pattern reference, and is lost if WordPress flattens it, so the phase-dependent selection and markup now live in this dynamic block's render.php instead, which runs at real request time regardless of how the surrounding pattern is stored.", + "textdomain": "ls-theme", + "usesContext": [ "postId" ], + "render": "file:./render.php" +} diff --git a/blocks/phase-services/index.js b/blocks/phase-services/index.js new file mode 100644 index 0000000..065d90f --- /dev/null +++ b/blocks/phase-services/index.js @@ -0,0 +1,34 @@ +/** + * Editor-side registration for ls-theme/phase-services. + * + * The PHP registration in inc/blocks.php (register_block_type against this folder's block.json) + * only tells WordPress how to render this block on the front end — the block editor's own JS + * registry is entirely separate, and needs its own wp.blocks.registerBlockType() call by the same + * name or it shows "Your site doesn't include support for this block" and renders nothing in the + * canvas. ServerSideRender is used for `edit` (rather than reimplementing the markup in JS) so the + * editor preview always matches render.php's actual output, including the current phase's real + * content and colour — no separate editor-only representation to keep in sync. + * + * Plain global-based script (no build step), per AGENTS.md "Avoid inventing a build pipeline". + * + * @package ls-theme + */ +( function ( blocks, element, serverSideRender ) { + var el = element.createElement; + + blocks.registerBlockType( 'ls-theme/phase-services', { + title: 'Phase Services', + category: 'text', + usesContext: [ 'postId' ], + description: 'Renders the current phase page\'s "Services in this phase" heading and service cards.', + edit: function ( props ) { + return el( serverSideRender, { + block: 'ls-theme/phase-services', + urlQueryArgs: { post_id: props.context ? props.context.postId : undefined }, + } ); + }, + save: function () { + return null; + }, + } ); +} )( window.wp.blocks, window.wp.element, window.wp.serverSideRender ); diff --git a/blocks/phase-services/render.php b/blocks/phase-services/render.php new file mode 100644 index 0000000..28bf9bc --- /dev/null +++ b/blocks/phase-services/render.php @@ -0,0 +1,213 @@ + array( + array( + 'label' => __( 'Discovery', 'ls-theme' ), + 'description' => __( 'Stakeholder workshops, audits, scoping and feasibility — the evidence layer that comes before design or build.', 'ls-theme' ), + 'url' => '/services/discovery/', + 'icon' => 'search', + ), + ), + 'create' => array( + array( + 'label' => __( 'Content', 'ls-theme' ), + 'description' => __( 'Content modelling, editorial workflow and governance that holds up at scale.', 'ls-theme' ), + 'url' => '/services/content/', + 'icon' => 'file-text', + ), + array( + 'label' => __( 'Design', 'ls-theme' ), + 'description' => __( 'Design systems, accessible patterns and Figma→WordPress parity. Already a deeper page.', 'ls-theme' ), + 'url' => '/services/design/', + 'icon' => 'paint-brush', + ), + ), + 'build' => array( + array( + 'label' => __( 'Development', 'ls-theme' ), + 'description' => __( 'Block themes, WooCommerce, integrations and platform refactors built for long-term health.', 'ls-theme' ), + 'url' => '/services/development/', + 'icon' => 'code', + ), + array( + 'label' => __( 'Migrations', 'ls-theme' ), + 'description' => __( 'Audits, mapping and redirects that take legacy platforms apart without losing traction.', 'ls-theme' ), + 'url' => '/services/migrations/', + 'icon' => 'arrows-left-right', + ), + ), + 'launch' => array( + array( + 'label' => __( 'Hosting', 'ls-theme' ), + 'description' => __( 'Managed environments that match the platform, the workflows and the support model around it.', 'ls-theme' ), + 'url' => '/services/hosting/', + 'icon' => 'cloud', + ), + array( + 'label' => __( 'Performance', 'ls-theme' ), + 'description' => __( 'Core Web Vitals, caching, query review and template optimisation against real production data.', 'ls-theme' ), + 'url' => '/services/performance/', + 'icon' => 'gauge', + ), + array( + 'label' => __( 'Security', 'ls-theme' ), + 'description' => __( 'Audits, hardening guidance, monitoring and recovery planning that reduces risk before incidents.', 'ls-theme' ), + 'url' => '/services/security/', + 'icon' => 'shield', + ), + array( + 'label' => __( 'Training', 'ls-theme' ), + 'description' => __( 'Role-specific training and reference materials that move teams from dependency to confidence.', 'ls-theme' ), + 'url' => '/services/training/', + 'icon' => 'graduation-cap', + ), + ), + 'grow' => array( + array( + 'label' => __( 'Support', 'ls-theme' ), + 'description' => __( 'Maintenance, incident response and quiet improvement so platforms keep getting easier to run.', 'ls-theme' ), + 'url' => '/services/support/', + 'icon' => 'lifebuoy', + ), + array( + 'label' => __( 'SEO', 'ls-theme' ), + 'description' => __( 'Technical SEO, internal linking, schema and the publishing discipline that supports visibility.', 'ls-theme' ), + 'url' => '/services/seo/', + 'icon' => 'chart-line-up', + ), + array( + 'label' => __( 'Accessibility', 'ls-theme' ), + 'description' => __( 'Audits, remediation and the semantic structure that helps WCAG 2.2 AA stick over time.', 'ls-theme' ), + 'url' => '/services/accessibility/', + 'icon' => 'wheelchair', + ), + array( + 'label' => __( 'Email marketing', 'ls-theme' ), + 'description' => __( 'Journey planning, consent flows and the connection between email and the WordPress platform behind it.', 'ls-theme' ), + 'url' => '/services/email-marketing/', + 'icon' => 'envelope', + ), + ), + 'evolve' => array( + array( + 'label' => __( 'AI', 'ls-theme' ), + 'description' => __( 'AI-readiness reviews, governance and workflow planning — practical use without messy adoption.', 'ls-theme' ), + 'url' => '/services/ai/', + 'icon' => 'special-interests', + ), + ), +); + +$ls_phase_labels = array( + 'discover' => __( 'Discover', 'ls-theme' ), + 'create' => __( 'Create', 'ls-theme' ), + 'build' => __( 'Build', 'ls-theme' ), + 'launch' => __( 'Launch', 'ls-theme' ), + 'grow' => __( 'Grow', 'ls-theme' ), + 'evolve' => __( 'Evolve', 'ls-theme' ), +); + +$ls_post_id = isset( $block->context['postId'] ) ? (int) $block->context['postId'] : (int) get_the_ID(); +if ( ! $ls_post_id ) { + $ls_post_id = (int) get_queried_object_id(); +} + +$ls_current_phase_slug = ''; +$ls_queried_post = get_post( $ls_post_id ); +if ( $ls_queried_post instanceof WP_Post ) { + $ls_current_phase_slug = $ls_queried_post->post_name; +} + +$ls_active_phase_slug = isset( $ls_phase_services_by_phase[ $ls_current_phase_slug ] ) ? $ls_current_phase_slug : 'discover'; +$ls_active_phase_label = $ls_phase_labels[ $ls_active_phase_slug ]; +$ls_active_services = $ls_phase_services_by_phase[ $ls_active_phase_slug ]; +$ls_service_rows = array_chunk( $ls_active_services, 4 ); +$ls_phase_accent = 'var(--wp--custom--color--phase--' . $ls_active_phase_slug . ')'; + +ob_start(); +?> + +