diff --git a/CHANGELOG.md b/CHANGELOG.md index 91454dd..a518f56 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Added 4 Work archive component patterns (LS-1616), each an individually insertable pattern built entirely from existing adaptive semantic tokens — no new `theme.json`/`dark.json` tokens were needed: + - `patterns/cards/work-project-card.php` — a case-study card bound to real Portfolio post data via WordPress block bindings (LS-1617): `core/post-title`, `core/post-excerpt`, `core/post-terms` (badge bound to `project-group`, tag pills bound to `project-tag`), and `core/read-more` for the permalink. Intended as the Post Template content inside a Query Loop scoped to the `project` post type. + - `patterns/cards/work-discuss-project-list.php` — a static checklist card reusing the existing `tick-accent` list style. + - `patterns/cards/work-engagement-stat.php` — a stat segment with a split-colour big number (accent-coloured suffix) and monospace uppercase labels. + - `patterns/cards/work-next-steps-card.php` — a compact related-route button. + - Matching section/block styles: `styles/sections/cards/card-case-study.json`, `card-banner-tint.json`, `card-chip.json`, `card-divider-top.json`, `card-checklist.json`, `stat-segment.json`, `card-link-row.json`, and two new `core/post-terms` block styles (`styles/blocks/post-terms/badge-brand.json`, `tag-pills.json`) for rendering dynamically-bound taxonomy terms as a badge bar and individual tag pills respectively. + - Colour, computed values (background tints, borders) are kept out of pattern-level block attributes and defined only in these external style files — WordPress's block validator can't reliably round-trip a raw `color-mix()` value placed directly in a block's own `style` attribute. + - Added hover-lift behaviour for the two interactive cards (`is-style-card-case-study`, `is-style-card-link-row`) to `assets/css/animations.css`, reusing the existing `card.hover` shadow contract, and extended the `is-style-link-arrow-accent` style/CSS to also support `core/read-more` (previously `core/paragraph` only). - Added a `Menu Item Card` pattern (`patterns/menu/menu-item-card.php`) as the single reusable source of the mega-menu list item structure (icon well, title/description, hover-reveal trailing arrow), used across the Work, Solutions, Pricing, Insights, and About mega menus — Services is excluded, it uses its own per-phase item style. Deliberately a plain registered pattern, not a Synced Pattern, so each insertion stays independently editable per menu item (LS-1618). - Added 6 real mega menu template parts for Ollie Menu Designer's Dropdown Menu block, each with final content, no shared placeholder scaffold: `parts/work-mega-menu.html`, `parts/solutions-mega-menu.html`, `parts/pricing-mega-menu.html`, `parts/insights-mega-menu.html`, `parts/about-mega-menu.html` (Default item styling), and `parts/services-mega-menu.html` (Service item styling, 6 lifecycle-phase columns). All registered in `theme.json` `templateParts` (LS-1618). - Added `Mega Menu Item - Default` and `Mega Menu Item - Service` block styles (`styles/blocks/groups/mega-menu-item-default.json`, `mega-menu-item-service.json`) as the single reusable, registered source of a row's structural styling (padding, radius) — the icon well itself carries no separate style, just plain inline block attributes, so it has no independent interactive behaviour of its own. diff --git a/assets/css/animations.css b/assets/css/animations.css index c1f0a93..705dd93 100644 --- a/assets/css/animations.css +++ b/assets/css/animations.css @@ -377,6 +377,35 @@ transform: rotate(-5deg) scale(0.98); } +/* Card - Work Category */ +.is-style-card-category { + --ls-card-category-border-rest: var(--wp--custom--color--border--card); + --ls-card-category-border-active: var(--wp--custom--color--link--accent); + --ls-card-category-shadow-rest: var(--wp--custom--shadow--elevation--100); + --ls-card-category-shadow-active: var(--wp--custom--shadow--card--hover); + --ls-card-category-lift: -4px; + position: relative; + overflow: hidden; + border: 1px solid var(--ls-card-category-border-rest); + border-radius: var(--wp--preset--border-radius--300); + background: var(--wp--custom--color--surface--card); + box-shadow: var(--ls-card-category-shadow-rest); + gap: var(--wp--preset--spacing--20); + padding: var(--wp--preset--spacing--20); + transition: border-color var(--wp--custom--animation--duration--base) var(--wp--custom--animation--easing--standard), box-shadow var(--wp--custom--animation--duration--medium) var(--wp--custom--animation--easing--standard), transform var(--wp--custom--animation--duration--medium) var(--wp--custom--animation--easing--emphasised); +} +.is-style-card-category:hover, .is-style-card-category:focus-within { + border-color: var(--ls-card-category-border-active); + box-shadow: var(--ls-card-category-shadow-active); + transform: translateY(var(--ls-card-category-lift)); +} +.is-style-card-category .ls-card-category__content { + flex: 1 1 auto; + display: flex; + flex-direction: column; + gap: var(--wp--preset--spacing--10); +} + /* Card - Services */ .is-style-card-services { --ls-card-services-border-rest: var(--wp--custom--color--border--card); @@ -600,12 +629,50 @@ margin: 0; } +/* Card - Link Row */ +.is-style-card-link-row { + --ls-card-link-row-border-rest: var(--wp--custom--color--border--card); + --ls-card-link-row-border-active: var(--wp--custom--color--link--accent); + --ls-card-link-row-background-active: color-mix(in srgb, var(--wp--custom--color--link--accent) 10%, transparent); + --ls-card-link-row-icon-active: var(--wp--custom--color--text--brand); + position: relative; + border-color: var(--ls-card-link-row-border-rest); + 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); +} +.is-style-card-link-row:hover, .is-style-card-link-row:focus-within { + background-color: var(--ls-card-link-row-background-active); + border-color: var(--ls-card-link-row-border-active); +} +.is-style-card-link-row:hover .wp-block-outermost-icon-block .icon-container, .is-style-card-link-row:focus-within .wp-block-outermost-icon-block .icon-container { + color: var(--ls-card-link-row-icon-active) !important; +} +.is-style-card-link-row { + /* Stretched-link pattern: the visible only wraps the title text, but its + * ::before covers the whole card so the entire row is clickable — while + * keeping a single real, keyboard-focusable link (not a fake click handler). */ +} +.is-style-card-link-row .ls-card-link-row__link { + color: inherit; + text-decoration: none; +} +.is-style-card-link-row .ls-card-link-row__link::before { + content: ""; + position: absolute; + inset: 0; +} +.is-style-card-link-row .ls-card-link-row__link:focus-visible { + outline: 2px solid var(--wp--custom--color--focus--ring); + outline-offset: 2px; +} + @media (prefers-reduced-motion: reduce) { .wp-block-paragraph.is-style-link-arrow-accent a, .wp-block-paragraph.is-style-link-arrow-accent a::after, .is-style-glass-card, .is-style-card-feature, .is-style-card-feature :is(.ls-card__icon-shell, .ls-card-feature__icon-shell), + .is-style-card-category, + .is-style-card-link-row, .is-style-card-services, .is-style-card-services::before, .is-style-card-services :is(.ls-card__icon-shell, .ls-card-services__icon-shell), @@ -618,6 +685,8 @@ .is-style-glass-card:focus-within, .is-style-card-feature:hover, .is-style-card-feature:focus-within, + .is-style-card-category:hover, + .is-style-card-category:focus-within, .is-style-card-services:hover, .is-style-card-services:focus-within { transform: none; @@ -643,6 +712,73 @@ transform: none; } } +/* + * Stat Segment: its border-inline-end divider (styles/sections/cards/stat-segment.json) reads as + * a vertical rule between adjacent columns in a `wp:columns` row. Below core/columns' own native + * stacking breakpoint (WP core hardcodes this at `max-width: 781px` in + * wp-includes/blocks/columns/style.css — mirrored here as the `columns-stack` entry in + * theme.json's settings.custom.layout.break-points), each column becomes full-width, so that same + * border would just show as a stray line down the right edge of every stacked segment. Drop it at + * that same breakpoint instead. + */ +@media (max-width: 781.98px) { + .is-style-stat-segment { + border-inline-end: none; + } +} +/* + * The last column in a stat row (e.g. "Tokens") reuses is-style-stat-segment for its shared + * spacing/colour contract like every sibling, but shouldn't carry a trailing divider — there's no + * column after it to divide from. Suppress it by position instead of duplicating the shared + * style's properties on a class-less wrapper. + */ +.wp-block-columns > .wp-block-column:last-child > .is-style-stat-segment { + border-inline-end: none; +} + +/* Card - Work Project (WooCommerce platform colour) */ +.is-style-card-banner-tint-woocommerce { + padding: var(--wp--preset--spacing--40) var(--wp--preset--spacing--20); + background-color: color-mix(in srgb, var(--wp--custom--color--card--platform--woocommerce) 7%, transparent); +} + +.is-style-badge-woocommerce { + width: 100%; + max-width: 100%; + box-sizing: border-box; + color: var(--wp--custom--color--card--platform--woocommerce); + font-family: var(--wp--preset--font-family--monospace); + font-size: var(--wp--preset--font-size--100); + font-weight: var(--wp--custom--typography--font-weight--bold); + text-transform: uppercase; + background-color: color-mix(in srgb, var(--wp--custom--color--card--platform--woocommerce) 8%, transparent); + border-radius: var(--wp--preset--border-radius--200); + padding: var(--wp--preset--spacing--5) var(--wp--preset--spacing--10); + letter-spacing: 1px; +} + +/* Badge - multi-term wrapping (WordPress and WooCommerce both bind to + project-group, which can carry more than one term per post; core/post-terms + forces its links to display:block by default, which stacks each term + onto its own line and leaves the ", " separator orphaned on its own row) */ +:is(.is-style-badge-brand, .is-style-badge-woocommerce) { + display: flex; + flex-wrap: wrap; + align-items: baseline; +} +:is(.is-style-badge-brand, .is-style-badge-woocommerce) a { + display: inline; + min-width: 0; + max-width: 100%; + white-space: normal; + overflow-wrap: anywhere; + color: inherit; + text-decoration: none; +} +:is(.is-style-badge-brand, .is-style-badge-woocommerce) .wp-block-post-terms__separator { + margin-inline-end: var(--wp--preset--spacing--5); +} + /********** Button Motion **********/ .wp-block-button:not([class*=is-style-]), .wp-block-button.is-style-fill, @@ -809,6 +945,24 @@ inset-inline-end: var(--ls-button-outline-icon-inline-start); } +/* Button - Secondary */ +.wp-block-button.is-style-button-secondary .wp-block-button__link:hover, +.wp-block-button.is-style-button-secondary .wp-block-button__link:focus-visible { + background-color: var(--wp--custom--color--button--fill--background-hover); + border-color: var(--wp--custom--color--button--fill--border-hover); + color: var(--wp--custom--color--button--fill--text-hover); +} + +.wp-block-button.is-style-button-secondary-outline .wp-block-button__link:hover, +.wp-block-button.is-style-button-secondary-outline .wp-block-button__link:focus-visible { + /* button.outline has no dedicated border-hover token — reuse background-hover (brand-500) so + * the border matches the solid fill it's transitioning to, same as the filled variant's border + * matching its own background-hover above. */ + background-color: var(--wp--custom--color--button--outline--background-hover); + border-color: var(--wp--custom--color--button--outline--background-hover); + color: var(--wp--custom--color--button--outline--text-hover); +} + /* Glass Button */ .wp-block-button.is-style-glass-button { max-inline-size: 100%; @@ -1478,6 +1632,21 @@ } } /********** Site Header **********/ +/* + * Below core/navigation's own native overlay-menu breakpoint (core WP hardcodes this at + * `min-width: 600px` in wp-includes/blocks/navigation/style.css — mirrored here as the + * `nav-toggle` entry in theme.json's settings.custom.layout.break-points, synced via + * `npm run sync:breakpoints`), the nav collapses to its own hamburger toggle automatically. + * Hide only the "Start a project" CTA button at that same breakpoint — not search, which stays + * the site's only search entry point on mobile (the nav overlay drawer doesn't include it). + * With `justifyContent:"space-between"` already set on the header row, hiding just the buttons + * still leaves enough room for the collapsed nav's hamburger to sit at the far right. + */ +@media (max-width: 599.98px) { + .site-header__actions .wp-block-buttons { + display: none; + } +} /* * Header icon buttons (search, light/dark toggle) and the gradient CTA. The base circular-button * shell (border/background/sizing) matches styles/blocks/groups/header-icon-button.json — kept @@ -1560,3 +1729,40 @@ transition: none; } } +/********** Taxonomy Filter (ls-plugin/taxonomy-filter) **********/ +.wp-block-ls-plugin-taxonomy-filter.taxonomy-filter--buttons { + display: flex; + flex-wrap: wrap; + gap: var(--wp--preset--spacing--10); +} +.wp-block-ls-plugin-taxonomy-filter.taxonomy-filter--buttons .wp-element-button { + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid var(--wp--preset--color--neutral-200); + border-radius: var(--wp--preset--border-radius--500); + padding: var(--wp--preset--spacing--10) var(--wp--preset--spacing--20); + background: transparent; + color: var(--wp--custom--color--text--muted); + font-family: var(--wp--preset--font-family--body); + font-weight: var(--wp--custom--typography--font-weight--semibold); + font-size: var(--wp--preset--font-size--100); + text-decoration: none; + white-space: nowrap; + 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), color var(--wp--custom--animation--duration--base) var(--wp--custom--animation--easing--standard); +} +.wp-block-ls-plugin-taxonomy-filter.taxonomy-filter--buttons .wp-element-button:hover, .wp-block-ls-plugin-taxonomy-filter.taxonomy-filter--buttons .wp-element-button:focus-visible { + border-color: var(--wp--custom--color--link--accent); + background-color: transparent; + color: var(--wp--custom--color--link--accent); +} +.wp-block-ls-plugin-taxonomy-filter.taxonomy-filter--buttons .wp-element-button.taxonomy-filter-current { + border-color: var(--wp--custom--color--card--platform--wordpress); + background-color: var(--wp--custom--color--card--platform--wordpress); + color: var(--wp--custom--color--text--on-dark); +} +.wp-block-ls-plugin-taxonomy-filter.taxonomy-filter--buttons .wp-element-button.taxonomy-filter-current:hover, .wp-block-ls-plugin-taxonomy-filter.taxonomy-filter--buttons .wp-element-button.taxonomy-filter-current:focus-visible { + border-color: var(--wp--custom--color--card--platform--wordpress); + background-color: var(--wp--custom--color--card--platform--wordpress); + color: var(--wp--custom--color--text--on-dark); +} diff --git a/functions.php b/functions.php index d1e7e1e..a13e320 100644 --- a/functions.php +++ b/functions.php @@ -21,6 +21,9 @@ /** Loads site header assets */ require get_template_directory() . '/inc/header.php'; +/** Loads Portfolio card platform-colour swapping */ +require get_template_directory() . '/inc/portfolio-card-colors.php'; + /** * Sets up theme supports. */ diff --git a/inc/animations.php b/inc/animations.php index ecae05e..8ebe1d2 100644 --- a/inc/animations.php +++ b/inc/animations.php @@ -137,6 +137,11 @@ function ls_theme_register_effect_block_styles() { 'name' => 'card-feature', 'label' => __( 'Card - Feature', 'ls-theme' ), ), + array( + 'block_name' => 'core/group', + 'name' => 'card-category', + 'label' => __( 'Card - Category', 'ls-theme' ), + ), array( 'block_name' => 'core/group', 'name' => 'card-solutions', diff --git a/inc/portfolio-card-colors.php b/inc/portfolio-card-colors.php new file mode 100644 index 0000000..23efe79 --- /dev/null +++ b/inc/portfolio-card-colors.php @@ -0,0 +1,59 @@ + 'slugs' ) ); + + if ( is_wp_error( $terms ) || empty( $terms ) || ! in_array( 'woocommerce', $terms, true ) ) { + return $block_content; + } + + if ( $is_banner ) { + return str_replace( 'is-style-card-banner-tint', 'is-style-card-banner-tint-woocommerce', $block_content ); + } + + return str_replace( 'is-style-badge-brand', 'is-style-badge-woocommerce', $block_content ); +} +add_filter( 'render_block', 'ls_theme_portfolio_card_platform_class', 10, 2 ); diff --git a/patterns/cards/work-capability-list.php b/patterns/cards/work-capability-list.php new file mode 100644 index 0000000..36bdb42 --- /dev/null +++ b/patterns/cards/work-capability-list.php @@ -0,0 +1,91 @@ + + +
+ + +
+ +
+ +
+ +
+ + + +
+ +

+ + + +

+ +
+ +
+ + + +
+ +
+ +
+ +
+ + + +
+ +

+ + + +

+ +
+ +
+ + + +
+ +
+ +
+ +
+ + + +
+ +

+ + + +

+ +
+ +
+ +
+ diff --git a/patterns/cards/work-discuss-project-list.php b/patterns/cards/work-discuss-project-list.php new file mode 100644 index 0000000..4d072de --- /dev/null +++ b/patterns/cards/work-discuss-project-list.php @@ -0,0 +1,38 @@ + + +
+ + + +
+ diff --git a/patterns/cards/work-engagement-stat.php b/patterns/cards/work-engagement-stat.php new file mode 100644 index 0000000..d5e1c9c --- /dev/null +++ b/patterns/cards/work-engagement-stat.php @@ -0,0 +1,39 @@ + + +
+ + +
+ +

+ + + +

+ +
+ + + +

+ + + +

+ +
+ diff --git a/patterns/cards/work-next-steps-card.php b/patterns/cards/work-next-steps-card.php new file mode 100644 index 0000000..6efce63 --- /dev/null +++ b/patterns/cards/work-next-steps-card.php @@ -0,0 +1,35 @@ + + +
+ diff --git a/patterns/cards/work-project-card.php b/patterns/cards/work-project-card.php new file mode 100644 index 0000000..7a5f5e9 --- /dev/null +++ b/patterns/cards/work-project-card.php @@ -0,0 +1,48 @@ + + +
+ + +
+ +
+ +
+ +
+ + + +
+ + + + + + + + +
+ +
+ + + +
+ +
+ diff --git a/patterns/content/eyebrow-badge.php b/patterns/content/eyebrow-badge.php new file mode 100644 index 0000000..f9ec0c7 --- /dev/null +++ b/patterns/content/eyebrow-badge.php @@ -0,0 +1,26 @@ + + +
+ +
+ + + +

+ +
+ diff --git a/patterns/hero/work-hero.php b/patterns/hero/work-hero.php new file mode 100644 index 0000000..ea9afe9 --- /dev/null +++ b/patterns/hero/work-hero.php @@ -0,0 +1,76 @@ + + +
+ + +
+ + + + + + +
+ + +
+ + +
+ +
+ + + +

+ +
+ + + +

+ + + +

+ + + +
+ +
+ + + +
+ +
+ +
+ + + +
+ +
+ +
+ +
+ +
+ diff --git a/patterns/section-stats-grid.php b/patterns/section-stats-grid.php index 33d8188..68da9ca 100644 --- a/patterns/section-stats-grid.php +++ b/patterns/section-stats-grid.php @@ -4,8 +4,141 @@ * Slug: ls-theme/section-stats-grid * Categories: stats * Block Types: core/pattern - * Description: A grid section for displaying statistics with icons, numbers, and descriptions. - + * Description: A generic 4-column stat/segment row with a heading, intro copy, and a small pill badge, wrapped in a top-and-bottom divider band. Used on the Work archive as "Across every engagement," but not tied to that page — content is edited per instance. + * Keywords: stats, grid, segment, metrics, section + * Viewport Width: 1280 + * Inserter: true + * + * @package ls-theme */ -?> \ No newline at end of file +?> + +
+ + +
+ + +
+ + +
+ +

+ + + +

+ +
+ + + +
+ +

+ +
+ +
+ + + +
+ + +
+ +
+ +
+ +

+ + + +

+ +
+ + + +

+ + + +

+ +
+ +
+ + + +
+ +
+ + + +
+ +
+ +
+ +

+ + + +

+ +
+ + + +

+ + + +

+ +
+ +
+ + + +
+ +
+ +
+ +

+ + + +

+ +
+ + + +

+ + + +

+ +
+ +
+ +
+ +
+ +
+ diff --git a/patterns/sections/work-categories.php b/patterns/sections/work-categories.php new file mode 100644 index 0000000..0e196a0 --- /dev/null +++ b/patterns/sections/work-categories.php @@ -0,0 +1,148 @@ + + +
+ + +
+ + +
+ + +
+ + + +

+ +
+ + + +
+ +

+ +
+ +
+ + + +
+ + +
+ +
+ +
+ +
+ +
+ + + +
+ +

+ + + +

+ +
+ + + + + +
+ +
+ + + +
+ +
+ +
+ +
+ +
+ + + +
+ +

+ + + +

+ +
+ + + + + +
+ +
+ + + +
+ +
+ +
+ +
+ +
+ + + +
+ +

+ + + +

+ +
+ + + + + +
+ +
+ +
+ +
+ +
+ diff --git a/patterns/sections/work-discuss-project.php b/patterns/sections/work-discuss-project.php new file mode 100644 index 0000000..121408b --- /dev/null +++ b/patterns/sections/work-discuss-project.php @@ -0,0 +1,72 @@ + + +
+ + +
+ + +
+ + +
+ + +
+ +
+ + + +

+ +
+ + + +

+ + + +

+ + + +
+ +
+ + + +
+ +
+ +
+ + + +
+ +
+ +
+ +
+ +
+ diff --git a/patterns/sections/work-related-routes.php b/patterns/sections/work-related-routes.php new file mode 100644 index 0000000..0faaee2 --- /dev/null +++ b/patterns/sections/work-related-routes.php @@ -0,0 +1,187 @@ + + +
+ + +
+ + +
+ +
+ + + +

+ +
+ + + +

+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ diff --git a/patterns/sections/work-selected-projects.php b/patterns/sections/work-selected-projects.php new file mode 100644 index 0000000..3da705a --- /dev/null +++ b/patterns/sections/work-selected-projects.php @@ -0,0 +1,74 @@ + + +
+ + +
+ + +
+ + +
+ +
+ +
+ + + +

+ +
+ + + +

+ +
+ + + +
+ +

+ +
+ +
+ + + +
+ + + + + + + + + + + + +
+ +
+ +
+ diff --git a/patterns/template-work-archive.php b/patterns/template-work-archive.php new file mode 100644 index 0000000..e37e662 --- /dev/null +++ b/patterns/template-work-archive.php @@ -0,0 +1,24 @@ + + + +
+ + + + + + +
+ diff --git a/src/scss/abstracts/mixins/_breakpoints-theme.scss b/src/scss/abstracts/mixins/_breakpoints-theme.scss index 4d45625..b4c780f 100644 --- a/src/scss/abstracts/mixins/_breakpoints-theme.scss +++ b/src/scss/abstracts/mixins/_breakpoints-theme.scss @@ -8,5 +8,7 @@ $ls-breakpoints: ( tablet-portrait: 768px, mobile-landscape: 640px, mobile-portrait: 390px, - mobile-compact: 320px + mobile-compact: 320px, + nav-toggle: 600px, + columns-stack: 782px ); diff --git a/src/scss/animations.scss b/src/scss/animations.scss index 17fc0c5..15d5124 100644 --- a/src/scss/animations.scss +++ b/src/scss/animations.scss @@ -7,4 +7,5 @@ @use "animations/faq-motion"; @use "animations/menu-motion"; @use "animations/footer-motion"; -@use "animations/header-motion"; \ No newline at end of file +@use "animations/header-motion"; +@use "animations/taxonomy-filter"; \ No newline at end of file diff --git a/src/scss/animations/_button-motion.scss b/src/scss/animations/_button-motion.scss index 2db0818..91a5b3b 100644 --- a/src/scss/animations/_button-motion.scss +++ b/src/scss/animations/_button-motion.scss @@ -239,6 +239,24 @@ inset-inline-end: var(--ls-button-outline-icon-inline-start); } +/* Button - Secondary */ +.wp-block-button.is-style-button-secondary .wp-block-button__link:hover, +.wp-block-button.is-style-button-secondary .wp-block-button__link:focus-visible { + background-color: var(--wp--custom--color--button--fill--background-hover); + border-color: var(--wp--custom--color--button--fill--border-hover); + color: var(--wp--custom--color--button--fill--text-hover); +} + +.wp-block-button.is-style-button-secondary-outline .wp-block-button__link:hover, +.wp-block-button.is-style-button-secondary-outline .wp-block-button__link:focus-visible { + /* button.outline has no dedicated border-hover token — reuse background-hover (brand-500) so + * the border matches the solid fill it's transitioning to, same as the filled variant's border + * matching its own background-hover above. */ + background-color: var(--wp--custom--color--button--outline--background-hover); + border-color: var(--wp--custom--color--button--outline--background-hover); + color: var(--wp--custom--color--button--outline--text-hover); +} + /* Glass Button */ .wp-block-button.is-style-glass-button { max-inline-size: 100%; diff --git a/src/scss/animations/_card-motion.scss b/src/scss/animations/_card-motion.scss index adcf600..80d77fd 100644 --- a/src/scss/animations/_card-motion.scss +++ b/src/scss/animations/_card-motion.scss @@ -1,6 +1,7 @@ @use "../abstracts/mixins/glass"; @use "../abstracts/mixins/motion"; @use "../abstracts/mixins/surface"; +@use "../abstracts/mixins/mq"; /********** Card Motion **********/ @@ -202,6 +203,44 @@ } } +/* Card - Work Category */ +.is-style-card-category { + --ls-card-category-border-rest: var(--wp--custom--color--border--card); + --ls-card-category-border-active: var(--wp--custom--color--link--accent); + --ls-card-category-shadow-rest: var(--wp--custom--shadow--elevation--100); + --ls-card-category-shadow-active: var(--wp--custom--shadow--card--hover); + --ls-card-category-lift: -4px; + @include surface.surface-card( + $radius: var(--wp--preset--border-radius--300), + $border: 1px solid var(--ls-card-category-border-rest), + $background: var(--wp--custom--color--surface--card), + $shadow: var(--ls-card-category-shadow-rest) + ); + gap: var(--wp--preset--spacing--20); + padding: var(--wp--preset--spacing--20); + transition: + border-color var(--wp--custom--animation--duration--base) + var(--wp--custom--animation--easing--standard), + box-shadow var(--wp--custom--animation--duration--medium) + var(--wp--custom--animation--easing--standard), + transform var(--wp--custom--animation--duration--medium) + var(--wp--custom--animation--easing--emphasised); + + &:hover, + &:focus-within { + border-color: var(--ls-card-category-border-active); + box-shadow: var(--ls-card-category-shadow-active); + transform: translateY(var(--ls-card-category-lift)); + } + + .ls-card-category__content { + flex: 1 1 auto; + display: flex; + flex-direction: column; + gap: var(--wp--preset--spacing--10); + } +} + /* Card - Services */ .is-style-card-services { --ls-card-services-border-rest: var(--wp--custom--color--border--card); @@ -480,12 +519,59 @@ } } +/* Card - Link Row */ +.is-style-card-link-row { + --ls-card-link-row-border-rest: var(--wp--custom--color--border--card); + --ls-card-link-row-border-active: var(--wp--custom--color--link--accent); + --ls-card-link-row-background-active: color-mix(in srgb, var(--wp--custom--color--link--accent) 10%, transparent); + --ls-card-link-row-icon-active: var(--wp--custom--color--text--brand); + position: relative; + border-color: var(--ls-card-link-row-border-rest); + 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); + + &:hover, + &:focus-within { + background-color: var(--ls-card-link-row-background-active); + border-color: var(--ls-card-link-row-border-active); + } + + &:hover .wp-block-outermost-icon-block .icon-container, + &:focus-within .wp-block-outermost-icon-block .icon-container { + color: var(--ls-card-link-row-icon-active) !important; + } + + /* Stretched-link pattern: the visible only wraps the title text, but its + * ::before covers the whole card so the entire row is clickable — while + * keeping a single real, keyboard-focusable link (not a fake click handler). */ + .ls-card-link-row__link { + color: inherit; + text-decoration: none; + + &::before { + content: ""; + position: absolute; + inset: 0; + } + + &:focus-visible { + outline: 2px solid var(--wp--custom--color--focus--ring); + outline-offset: 2px; + } + } +} + @include motion.reduced-motion { .wp-block-paragraph.is-style-link-arrow-accent a, .wp-block-paragraph.is-style-link-arrow-accent a::after, .is-style-glass-card, .is-style-card-feature, .is-style-card-feature :is(.ls-card__icon-shell, .ls-card-feature__icon-shell), + .is-style-card-category, + .is-style-card-link-row, .is-style-card-services, .is-style-card-services::before, .is-style-card-services :is(.ls-card__icon-shell, .ls-card-services__icon-shell), @@ -500,6 +586,8 @@ .is-style-glass-card:focus-within, .is-style-card-feature:hover, .is-style-card-feature:focus-within, + .is-style-card-category:hover, + .is-style-card-category:focus-within, .is-style-card-services:hover, .is-style-card-services:focus-within { transform: none; @@ -529,4 +617,74 @@ .is-style-icon-frame-glow { transform: none; } +} + +/* + * Stat Segment: its border-inline-end divider (styles/sections/cards/stat-segment.json) reads as + * a vertical rule between adjacent columns in a `wp:columns` row. Below core/columns' own native + * stacking breakpoint (WP core hardcodes this at `max-width: 781px` in + * wp-includes/blocks/columns/style.css — mirrored here as the `columns-stack` entry in + * theme.json's settings.custom.layout.break-points), each column becomes full-width, so that same + * border would just show as a stray line down the right edge of every stacked segment. Drop it at + * that same breakpoint instead. + */ +@include mq.mq($until: "columns-stack") { + .is-style-stat-segment { + border-inline-end: none; + } +} + +/* + * The last column in a stat row (e.g. "Tokens") reuses is-style-stat-segment for its shared + * spacing/colour contract like every sibling, but shouldn't carry a trailing divider — there's no + * column after it to divide from. Suppress it by position instead of duplicating the shared + * style's properties on a class-less wrapper. + */ +.wp-block-columns > .wp-block-column:last-child > .is-style-stat-segment { + border-inline-end: none; +} + +/* Card - Work Project (WooCommerce platform colour) */ +.is-style-card-banner-tint-woocommerce { + padding: var(--wp--preset--spacing--40) var(--wp--preset--spacing--20); + background-color: color-mix(in srgb, var(--wp--custom--color--card--platform--woocommerce) 7%, transparent); +} + +.is-style-badge-woocommerce { + width: 100%; + max-width: 100%; + box-sizing: border-box; + color: var(--wp--custom--color--card--platform--woocommerce); + font-family: var(--wp--preset--font-family--monospace); + font-size: var(--wp--preset--font-size--100); + font-weight: var(--wp--custom--typography--font-weight--bold); + text-transform: uppercase; + background-color: color-mix(in srgb, var(--wp--custom--color--card--platform--woocommerce) 8%, transparent); + border-radius: var(--wp--preset--border-radius--200); + padding: var(--wp--preset--spacing--5) var(--wp--preset--spacing--10); + letter-spacing: 1px; +} + +/* Badge - multi-term wrapping (WordPress and WooCommerce both bind to + project-group, which can carry more than one term per post; core/post-terms + forces its links to display:block by default, which stacks each term + onto its own line and leaves the ", " separator orphaned on its own row) */ +:is(.is-style-badge-brand, .is-style-badge-woocommerce) { + display: flex; + flex-wrap: wrap; + align-items: baseline; + + a { + display: inline; + min-width: 0; + max-width: 100%; + white-space: normal; + overflow-wrap: anywhere; + color: inherit; + text-decoration: none; + } + + .wp-block-post-terms__separator { + margin-inline-end: var(--wp--preset--spacing--5); + } } \ No newline at end of file diff --git a/src/scss/animations/_header-motion.scss b/src/scss/animations/_header-motion.scss index 0228da4..653d637 100644 --- a/src/scss/animations/_header-motion.scss +++ b/src/scss/animations/_header-motion.scss @@ -1,7 +1,24 @@ @use "../abstracts/mixins/motion"; +@use "../abstracts/mixins/mq"; /********** Site Header **********/ +/* + * Below core/navigation's own native overlay-menu breakpoint (core WP hardcodes this at + * `min-width: 600px` in wp-includes/blocks/navigation/style.css — mirrored here as the + * `nav-toggle` entry in theme.json's settings.custom.layout.break-points, synced via + * `npm run sync:breakpoints`), the nav collapses to its own hamburger toggle automatically. + * Hide only the "Start a project" CTA button at that same breakpoint — not search, which stays + * the site's only search entry point on mobile (the nav overlay drawer doesn't include it). + * With `justifyContent:"space-between"` already set on the header row, hiding just the buttons + * still leaves enough room for the collapsed nav's hamburger to sit at the far right. + */ +@include mq.mq($until: "nav-toggle") { + .site-header__actions .wp-block-buttons { + display: none; + } +} + /* * Header icon buttons (search, light/dark toggle) and the gradient CTA. The base circular-button * shell (border/background/sizing) matches styles/blocks/groups/header-icon-button.json — kept diff --git a/src/scss/animations/_taxonomy-filter.scss b/src/scss/animations/_taxonomy-filter.scss new file mode 100644 index 0000000..87108b5 --- /dev/null +++ b/src/scss/animations/_taxonomy-filter.scss @@ -0,0 +1,47 @@ +/********** Taxonomy Filter (ls-plugin/taxonomy-filter) **********/ + +.wp-block-ls-plugin-taxonomy-filter.taxonomy-filter--buttons { + display: flex; + flex-wrap: wrap; + gap: var(--wp--preset--spacing--10); + + .wp-element-button { + display: inline-flex; + align-items: center; + justify-content: center; + border: 1px solid var(--wp--preset--color--neutral-200); + border-radius: var(--wp--preset--border-radius--500); + padding: var(--wp--preset--spacing--10) var(--wp--preset--spacing--20); + background: transparent; + color: var(--wp--custom--color--text--muted); + font-family: var(--wp--preset--font-family--body); + font-weight: var(--wp--custom--typography--font-weight--semibold); + font-size: var(--wp--preset--font-size--100); + text-decoration: none; + white-space: nowrap; + 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), + color var(--wp--custom--animation--duration--base) var(--wp--custom--animation--easing--standard); + + &:hover, + &:focus-visible { + border-color: var(--wp--custom--color--link--accent); + background-color: transparent; + color: var(--wp--custom--color--link--accent); + } + + &.taxonomy-filter-current { + border-color: var(--wp--custom--color--card--platform--wordpress); + background-color: var(--wp--custom--color--card--platform--wordpress); + color: var(--wp--custom--color--text--on-dark); + + &:hover, + &:focus-visible { + border-color: var(--wp--custom--color--card--platform--wordpress); + background-color: var(--wp--custom--color--card--platform--wordpress); + color: var(--wp--custom--color--text--on-dark); + } + } + } +} diff --git a/styles/blocks/buttons/button-secondary-outline.json b/styles/blocks/buttons/button-secondary-outline.json new file mode 100644 index 0000000..4fceabe --- /dev/null +++ b/styles/blocks/buttons/button-secondary-outline.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Button - Secondary Outline", + "slug": "button-secondary-outline", + "blockTypes": [ + "core/button" + ], + "description": "Outline pill button for CTAs outside the header, paired with Button - Secondary — transparent background (not the default outline button's surface-400 fill, which reads as solid black against a light section), reusing the default outline button's border/text colour tokens. Pill-shaped with tighter padding and non-uppercase type. Hover contract in src/scss/animations/_button-motion.scss.", + "styles": { + "color": { + "background": "transparent", + "text": "var:custom|color|button|outline|text" + }, + "border": { + "color": "var:custom|color|button|outline|border", + "radius": "var:preset|border-radius|500", + "style": "solid", + "width": "1px" + }, + "spacing": { + "padding": { + "top": "var:preset|spacing|20", + "right": "var:preset|spacing|40", + "bottom": "var:preset|spacing|20", + "left": "var:preset|spacing|40" + } + }, + "typography": { + "fontSize": "var:preset|font-size|200", + "fontWeight": "var:custom|typography|font-weight|bold", + "letterSpacing": "normal" + } + } +} diff --git a/styles/blocks/buttons/button-secondary.json b/styles/blocks/buttons/button-secondary.json new file mode 100644 index 0000000..d6d2e95 --- /dev/null +++ b/styles/blocks/buttons/button-secondary.json @@ -0,0 +1,35 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Button - Secondary", + "slug": "button-secondary", + "blockTypes": [ + "core/button" + ], + "description": "Filled pill button for CTAs outside the header — reuses the default button's fill colour tokens, just pill-shaped with tighter padding and non-uppercase type. Hover contract in src/scss/animations/_button-motion.scss.", + "styles": { + "color": { + "background": "var:custom|color|button|fill|background", + "text": "var:custom|color|button|fill|text" + }, + "border": { + "color": "var:custom|color|button|fill|border", + "radius": "var:preset|border-radius|500", + "style": "solid", + "width": "1px" + }, + "spacing": { + "padding": { + "top": "var:preset|spacing|20", + "right": "var:preset|spacing|40", + "bottom": "var:preset|spacing|20", + "left": "var:preset|spacing|40" + } + }, + "typography": { + "fontSize": "var:preset|font-size|200", + "fontWeight": "var:custom|typography|font-weight|bold", + "letterSpacing": "normal" + } + } +} diff --git a/styles/blocks/groups/icon-well-accent.json b/styles/blocks/groups/icon-well-accent.json new file mode 100644 index 0000000..b1e8315 --- /dev/null +++ b/styles/blocks/groups/icon-well-accent.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Icon Well - Accent", + "slug": "icon-well-accent", + "blockTypes": [ + "core/group" + ], + "description": "Compact tinted square icon well in the accent colour, for capability-list rows.", + "styles": { + "css": "&{display:flex;align-items:center;justify-content:center;inline-size:2.25rem;block-size:2.25rem;flex-shrink:0;border-radius:var(--wp--preset--border-radius--300);background-color:color-mix(in srgb, var(--wp--custom--color--card--solutions--accent) 12%, transparent);color:var(--wp--custom--color--card--solutions--accent);}" + } +} diff --git a/styles/blocks/groups/icon-well-brand.json b/styles/blocks/groups/icon-well-brand.json new file mode 100644 index 0000000..5fba316 --- /dev/null +++ b/styles/blocks/groups/icon-well-brand.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Icon Well - Brand", + "slug": "icon-well-brand", + "blockTypes": [ + "core/group" + ], + "description": "Compact tinted square icon well in the brand colour, for capability-list rows.", + "styles": { + "css": "&{display:flex;align-items:center;justify-content:center;inline-size:2.25rem;block-size:2.25rem;flex-shrink:0;border-radius:var(--wp--preset--border-radius--300);background-color:color-mix(in srgb, var(--wp--custom--color--card--solutions--brand) 10%, transparent);color:var(--wp--custom--color--card--solutions--brand);}" + } +} diff --git a/styles/blocks/groups/icon-well-commerce.json b/styles/blocks/groups/icon-well-commerce.json new file mode 100644 index 0000000..b941194 --- /dev/null +++ b/styles/blocks/groups/icon-well-commerce.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Icon Well - Commerce", + "slug": "icon-well-commerce", + "blockTypes": [ + "core/group" + ], + "description": "Compact tinted square icon well in the commerce (warning/amber) colour, for capability-list rows.", + "styles": { + "css": "&{display:flex;align-items:center;justify-content:center;inline-size:2.25rem;block-size:2.25rem;flex-shrink:0;border-radius:var(--wp--preset--border-radius--300);background-color:color-mix(in srgb, var(--wp--custom--color--icon--commerce) 10%, transparent);color:var(--wp--custom--color--icon--commerce);}" + } +} diff --git a/styles/blocks/paragraphs/link-arrow-accent.json b/styles/blocks/paragraphs/link-arrow-accent.json index f2dcbb1..647ecb3 100644 --- a/styles/blocks/paragraphs/link-arrow-accent.json +++ b/styles/blocks/paragraphs/link-arrow-accent.json @@ -4,9 +4,10 @@ "title": "Link Arrow Accent", "slug": "link-arrow-accent", "blockTypes": [ - "core/paragraph" + "core/paragraph", + "core/read-more" ], - "description": "Paragraph links with an inline arrow accent for compact card CTAs.", + "description": "Paragraph or Read More links with an inline arrow accent for compact card CTAs.", "styles": { "elements": { "link": { diff --git a/styles/blocks/post-terms/badge-brand.json b/styles/blocks/post-terms/badge-brand.json new file mode 100644 index 0000000..4d2bc3e --- /dev/null +++ b/styles/blocks/post-terms/badge-brand.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Badge - Brand", + "slug": "badge-brand", + "blockTypes": [ + "core/post-terms" + ], + "description": "Renders linked terms as a full-width WordPress-tinted bar, for the Work Project Card's platform badge (bound to the Portfolio project-group taxonomy). Default/fallback variant for any project-group term other than WooCommerce.", + "styles": { + "color": { + "text": "var:custom|color|card|platform|wordpress" + }, + "typography": { + "fontFamily": "var:preset|font-family|monospace", + "fontSize": "var:preset|font-size|100", + "fontWeight": "var:custom|typography|font-weight|bold", + "textTransform": "uppercase" + }, + "css": "&{display:flex;flex-wrap:wrap;align-items:baseline;width:100%;max-width:100%;box-sizing:border-box;background-color:color-mix(in srgb, var(--wp--custom--color--card--platform--wordpress) 8%, transparent);border-radius:var(--wp--preset--border-radius--200);padding:var(--wp--preset--spacing--5) var(--wp--preset--spacing--10);letter-spacing:1px;} & a{display:inline;min-width:0;max-width:100%;white-space:normal;overflow-wrap:anywhere;color:inherit;text-decoration:none;} & .wp-block-post-terms__separator{margin-inline-end:var(--wp--preset--spacing--5);}" + } +} diff --git a/styles/blocks/post-terms/badge-woocommerce.json b/styles/blocks/post-terms/badge-woocommerce.json new file mode 100644 index 0000000..1a9f02d --- /dev/null +++ b/styles/blocks/post-terms/badge-woocommerce.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Badge - WooCommerce", + "slug": "badge-woocommerce", + "blockTypes": [ + "core/post-terms" + ], + "description": "Renders linked terms as a full-width WooCommerce-tinted bar, for the Work Project Card's platform badge (bound to the Portfolio project-group taxonomy) when the post's term is WooCommerce.", + "styles": { + "color": { + "text": "var:custom|color|card|platform|woocommerce" + }, + "typography": { + "fontFamily": "var:preset|font-family|monospace", + "fontSize": "var:preset|font-size|100", + "fontWeight": "var:custom|typography|font-weight|bold", + "textTransform": "uppercase" + }, + "css": "&{display:flex;flex-wrap:wrap;align-items:baseline;width:100%;max-width:100%;box-sizing:border-box;background-color:color-mix(in srgb, var(--wp--custom--color--card--platform--woocommerce) 8%, transparent);border-radius:var(--wp--preset--border-radius--200);padding:var(--wp--preset--spacing--5) var(--wp--preset--spacing--10);letter-spacing:1px;} & a{display:inline;min-width:0;max-width:100%;white-space:normal;overflow-wrap:anywhere;color:inherit;text-decoration:none;} & .wp-block-post-terms__separator{margin-inline-end:var(--wp--preset--spacing--5);}" + } +} diff --git a/styles/blocks/post-terms/tag-pills.json b/styles/blocks/post-terms/tag-pills.json new file mode 100644 index 0000000..5688273 --- /dev/null +++ b/styles/blocks/post-terms/tag-pills.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Tag Pills", + "slug": "tag-pills", + "blockTypes": [ + "core/post-terms" + ], + "description": "Renders each linked term as an individual pill chip, for the Work Project Card tag row (bound to the project-tag taxonomy).", + "styles": { + "color": { + "text": "var:custom|color|text|muted" + }, + "typography": { + "fontFamily": "var:preset|font-family|monospace", + "fontSize": "var:preset|font-size|100", + "fontWeight": "var:custom|typography|font-weight|bold" + }, + "css": "&{display:flex;flex-wrap:wrap;gap:var(--wp--preset--spacing--5);max-width:100%;} & a{display:inline-block;min-width:0;max-width:100%;box-sizing:border-box;white-space:normal;overflow-wrap:anywhere;background-color:var(--wp--custom--color--surface--card-raised);color:var(--wp--custom--color--text--muted);border-radius:var(--wp--preset--border-radius--100);padding:var(--wp--preset--spacing--5) var(--wp--preset--spacing--10);text-decoration:none;}" + } +} diff --git a/styles/dark.json b/styles/dark.json index 5a1caf5..bc08418 100644 --- a/styles/dark.json +++ b/styles/dark.json @@ -36,12 +36,17 @@ }, "icon": { "background": "var:preset|color|cta-500", - "color": "var:preset|color|contrast" + "color": "var:preset|color|contrast", + "commerce": "var:preset|color|warning-foreground" }, "card": { "solutions": { "brand": "var:preset|color|cta-500", "accent": "var:preset|color|accent-three-500" + }, + "platform": { + "wordpress": "var:preset|color|brand-400", + "woocommerce": "var:preset|color|cta-400" } }, "phase": { diff --git a/styles/sections/cards/card-banner-tint-woocommerce.json b/styles/sections/cards/card-banner-tint-woocommerce.json new file mode 100644 index 0000000..9a7c0b5 --- /dev/null +++ b/styles/sections/cards/card-banner-tint-woocommerce.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Card - Banner Tint (WooCommerce)", + "slug": "card-banner-tint-woocommerce", + "blockTypes": [ + "core/group" + ], + "description": "WooCommerce-tinted banner zone for the Work Project Card, applied when the post's project-group term is WooCommerce.", + "styles": { + "spacing": { + "padding": { + "top": "var:preset|spacing|40", + "right": "var:preset|spacing|20", + "bottom": "var:preset|spacing|40", + "left": "var:preset|spacing|20" + } + }, + "css": "&{background-color:color-mix(in srgb, var(--wp--custom--color--card--platform--woocommerce) 7%, transparent);}" + } +} diff --git a/styles/sections/cards/card-banner-tint.json b/styles/sections/cards/card-banner-tint.json new file mode 100644 index 0000000..192e062 --- /dev/null +++ b/styles/sections/cards/card-banner-tint.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Card - Banner Tint", + "slug": "card-banner-tint", + "blockTypes": [ + "core/group" + ], + "description": "WordPress-tinted banner zone for the Work Project Card. Default/fallback variant for any project-group term other than WooCommerce. Background colour lives here (not inline in the pattern) so the block's saved HTML stays a plain className the validator can round-trip cleanly.", + "styles": { + "spacing": { + "padding": { + "top": "var:preset|spacing|40", + "right": "var:preset|spacing|20", + "bottom": "var:preset|spacing|40", + "left": "var:preset|spacing|20" + } + }, + "css": "&{background-color:color-mix(in srgb, var(--wp--custom--color--card--platform--wordpress) 7%, transparent);}" + } +} diff --git a/styles/sections/cards/card-case-study.json b/styles/sections/cards/card-case-study.json new file mode 100644 index 0000000..c73d458 --- /dev/null +++ b/styles/sections/cards/card-case-study.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Card - Case Study", + "slug": "card-case-study", + "blockTypes": [ + "core/group" + ], + "description": "Case-study card shell for the Work archive: banner zone, content body, and tag row. Adapts between light and dark mode like every other card style — border uses a translucent tint of the shared card border token.", + "styles": { + "color": { + "background": "var:custom|color|surface|card", + "text": "var:custom|color|text|default" + }, + "border": { + "color": "var:custom|color|border|card", + "radius": "var:preset|border-radius|300", + "style": "solid", + "width": "1px" + }, + "shadow": "var:preset|shadow|100", + "spacing": { + "blockGap": "0" + }, + "css": "&{overflow:hidden;border-color:color-mix(in srgb, var(--wp--custom--color--border--card) 55%, transparent);}" + } +} diff --git a/styles/sections/cards/card-category.json b/styles/sections/cards/card-category.json new file mode 100644 index 0000000..8d8e1e8 --- /dev/null +++ b/styles/sections/cards/card-category.json @@ -0,0 +1,32 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Card - Category", + "slug": "card-category", + "blockTypes": [ + "core/group" + ], + "description": "Compact card shell with a tinted icon well, H3 heading, supporting copy, and inline CTA sitting close to the copy (no bottom-anchored CTA, unlike Card - Feature). Used by the Work archive's category row.", + "styles": { + "color": { + "background": "var:custom|color|surface|card", + "text": "var:custom|color|text|default" + }, + "border": { + "color": "var:custom|color|border|card", + "radius": "var:preset|border-radius|300", + "style": "solid", + "width": "1px" + }, + "shadow": "var:preset|shadow|100", + "spacing": { + "blockGap": "var:preset|spacing|20", + "padding": { + "top": "var:preset|spacing|20", + "right": "var:preset|spacing|20", + "bottom": "var:preset|spacing|20", + "left": "var:preset|spacing|20" + } + } + } +} diff --git a/styles/sections/cards/card-checklist.json b/styles/sections/cards/card-checklist.json new file mode 100644 index 0000000..480bc88 --- /dev/null +++ b/styles/sections/cards/card-checklist.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Card - Checklist", + "slug": "card-checklist", + "blockTypes": [ + "core/group" + ], + "description": "Card shell wrapping a tick-accent checklist for Work archive CTA panels. Adapts between light and dark mode.", + "styles": { + "color": { + "background": "var:custom|color|surface|card", + "text": "var:custom|color|text|default" + }, + "border": { + "color": "var:custom|color|border|card", + "radius": "var:preset|border-radius|300", + "style": "solid", + "width": "1px" + }, + "spacing": { + "blockGap": "var:preset|spacing|10", + "padding": { + "top": "var:preset|spacing|30", + "right": "var:preset|spacing|30", + "bottom": "var:preset|spacing|30", + "left": "var:preset|spacing|30" + } + } + } +} diff --git a/styles/sections/cards/card-chip.json b/styles/sections/cards/card-chip.json new file mode 100644 index 0000000..50f6ba1 --- /dev/null +++ b/styles/sections/cards/card-chip.json @@ -0,0 +1,27 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Card - Chip", + "slug": "card-chip", + "blockTypes": [ + "core/group" + ], + "description": "Floating translucent chip shell for the Work Project Card's platform/industry label, sitting on top of the banner tint.", + "styles": { + "border": { + "color": "var:custom|color|border|card", + "radius": "var:preset|border-radius|200", + "style": "solid", + "width": "1px" + }, + "spacing": { + "padding": { + "top": "var:preset|spacing|10", + "right": "var:preset|spacing|10", + "bottom": "var:preset|spacing|10", + "left": "var:preset|spacing|10" + } + }, + "css": "&{background-color:color-mix(in srgb, var(--wp--custom--color--surface--canvas) 85%, transparent);}" + } +} diff --git a/styles/sections/cards/card-divider-both.json b/styles/sections/cards/card-divider-both.json new file mode 100644 index 0000000..5147dac --- /dev/null +++ b/styles/sections/cards/card-divider-both.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Card - Divider Both", + "slug": "card-divider-both", + "blockTypes": [ + "core/columns" + ], + "description": "Row wrapper with top and bottom dividers only, for a horizontal band of stat/segment columns. Sets border-width explicitly on all four sides to avoid the has-border-color utility class defaulting the other two sides to the browser's default border. Also stretches each column's own child to the column's full (flexbox-equalised) height, so a per-segment border-inline-end divider spans the whole row instead of stopping at its own content height.", + "styles": { + "css": "&{border-style:solid;border-color:var(--wp--custom--color--border--card);border-width:1px 0;} &>.wp-block-column{display:flex;flex-direction:column;} &>.wp-block-column>*{flex:1 1 auto;}" + } +} diff --git a/styles/sections/cards/card-divider-bottom.json b/styles/sections/cards/card-divider-bottom.json new file mode 100644 index 0000000..367772e --- /dev/null +++ b/styles/sections/cards/card-divider-bottom.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Card - Divider Bottom", + "slug": "card-divider-bottom", + "blockTypes": [ + "core/group" + ], + "description": "Single capability-list row with a bottom-only divider. Sets border-width explicitly on all four sides to avoid the has-border-color utility class defaulting the other three sides to the browser's default border. Not applied to the last row in a list.", + "styles": { + "spacing": { + "padding": { + "bottom": "var:preset|spacing|20" + } + }, + "css": "&{border-style:solid;border-color:var(--wp--custom--color--border--card);border-width:0 0 1px 0;}" + } +} diff --git a/styles/sections/cards/card-divider-top.json b/styles/sections/cards/card-divider-top.json new file mode 100644 index 0000000..c2db1f8 --- /dev/null +++ b/styles/sections/cards/card-divider-top.json @@ -0,0 +1,19 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Card - Divider Top", + "slug": "card-divider-top", + "blockTypes": [ + "core/group" + ], + "description": "Row wrapper with a single top divider only. Sets border-width explicitly on all four sides to avoid the has-border-color utility class defaulting the other three sides to the browser's default border. Used by the Work Project Card's tag row.", + "styles": { + "spacing": { + "padding": { + "top": "var:preset|spacing|10", + "bottom": "var:preset|spacing|10" + } + }, + "css": "&{border-style:solid;border-color:var(--wp--custom--color--border--card);border-width:1px 0 0 0;}" + } +} diff --git a/styles/sections/cards/card-link-row.json b/styles/sections/cards/card-link-row.json new file mode 100644 index 0000000..5d598bf --- /dev/null +++ b/styles/sections/cards/card-link-row.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Card - Link Row", + "slug": "card-link-row", + "blockTypes": [ + "core/group" + ], + "description": "Compact horizontal related-route button for the Work archive: white card surface, solid border, trailing arrow.", + "styles": { + "color": { + "background": "var:custom|color|surface|card", + "text": "var:custom|color|text|default" + }, + "border": { + "color": "var:custom|color|border|card", + "radius": "var:preset|border-radius|400", + "style": "solid", + "width": "1px" + }, + "spacing": { + "blockGap": "var:preset|spacing|10", + "padding": { + "top": "var:preset|spacing|20", + "right": "var:preset|spacing|20", + "bottom": "var:preset|spacing|20", + "left": "var:preset|spacing|20" + } + } + } +} diff --git a/styles/sections/cards/card-list-shell.json b/styles/sections/cards/card-list-shell.json new file mode 100644 index 0000000..b6f4d20 --- /dev/null +++ b/styles/sections/cards/card-list-shell.json @@ -0,0 +1,31 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Card - List Shell", + "slug": "card-list-shell", + "blockTypes": [ + "core/group" + ], + "description": "Bordered card shell wrapping a 3-row icon/title/description capability list, for the Work archive hero.", + "styles": { + "color": { + "background": "var:custom|color|surface|card", + "text": "var:custom|color|text|default" + }, + "border": { + "color": "var:custom|color|border|card", + "radius": "var:preset|border-radius|400", + "style": "solid", + "width": "1px" + }, + "spacing": { + "padding": { + "top": "var:preset|spacing|30", + "right": "var:preset|spacing|30", + "bottom": "var:preset|spacing|30", + "left": "var:preset|spacing|30" + } + }, + "css": "&{inline-size:100%;} & > .wp-block-group > *:last-child{min-width:0;flex:1 1 auto;}" + } +} diff --git a/styles/sections/cards/stat-segment.json b/styles/sections/cards/stat-segment.json new file mode 100644 index 0000000..1690937 --- /dev/null +++ b/styles/sections/cards/stat-segment.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Stat Segment", + "slug": "stat-segment", + "blockTypes": [ + "core/group" + ], + "description": "Stat segment for the Work archive engagement row: transparent background with a translucent trailing divider border.", + "styles": { + "color": { + "text": "var:custom|color|text|muted" + }, + "spacing": { + "blockGap": "var:preset|spacing|10", + "padding": { + "top": "var:preset|spacing|40", + "right": "var:preset|spacing|30", + "bottom": "var:preset|spacing|40", + "left": "var:preset|spacing|30" + } + }, + "css": "&{border-inline-end:1px solid var(--wp--custom--color--border--card);}" + } +} diff --git a/styles/sections/content/content-band.json b/styles/sections/content/content-band.json new file mode 100644 index 0000000..b0d6178 --- /dev/null +++ b/styles/sections/content/content-band.json @@ -0,0 +1,23 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Content Band", + "slug": "content-band", + "blockTypes": [ + "core/group" + ], + "description": "Full-width content band for a page section: flat canvas background, standard section padding. Generic — shared by every Work archive section (Categories, Selected Projects, Stats Grid, Discuss Project, Related Routes) and any future section with the same plain band treatment.", + "styles": { + "color": { + "background": "var:custom|color|surface|canvas" + }, + "spacing": { + "padding": { + "top": "var:preset|spacing|80", + "right": "var:preset|spacing|30", + "bottom": "var:preset|spacing|90", + "left": "var:preset|spacing|30" + } + } + } +} diff --git a/styles/sections/hero/work-hero.json b/styles/sections/hero/work-hero.json new file mode 100644 index 0000000..e49cc07 --- /dev/null +++ b/styles/sections/hero/work-hero.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Work Hero", + "slug": "work-hero", + "blockTypes": [ + "core/group" + ], + "description": "Full-width hero section shell for the Work archive: two soft radial-gradient glows using the existing hero effect tokens, reused from the CTA band's colour family.", + "styles": { + "spacing": { + "padding": { + "top": "var:preset|spacing|80", + "right": "var:preset|spacing|30", + "bottom": "var:preset|spacing|90", + "left": "var:preset|spacing|30" + } + }, + "css": "&{background-image:radial-gradient(circle at 14% -10%, color-mix(in srgb, var(--wp--custom--color--effect--hero--brand) 16%, transparent) 0%, transparent 60%), radial-gradient(circle at 86% 110%, color-mix(in srgb, var(--wp--custom--color--effect--hero--accent) 12%, transparent) 0%, transparent 60%);background-repeat:no-repeat;}" + } +} diff --git a/templates/page-work-archive.html b/templates/page-work-archive.html new file mode 100644 index 0000000..cc2ac46 --- /dev/null +++ b/templates/page-work-archive.html @@ -0,0 +1,5 @@ + + + + + diff --git a/theme.json b/theme.json index 47b2d30..1f2b7e9 100644 --- a/theme.json +++ b/theme.json @@ -471,7 +471,9 @@ "tablet-portrait": "768px", "mobile-landscape": "640px", "mobile-portrait": "390px", - "mobile-compact": "320px" + "mobile-compact": "320px", + "nav-toggle": "600px", + "columns-stack": "782px" } }, "color": { @@ -506,12 +508,17 @@ }, "icon": { "background": "var:preset|color|brand-500", - "color": "var:preset|color|base" + "color": "var:preset|color|base", + "commerce": "var:preset|color|warning-foreground" }, "card": { "solutions": { "brand": "var:preset|color|brand-500", "accent": "var:preset|color|accent-500" + }, + "platform": { + "wordpress": "var:preset|color|brand-500", + "woocommerce": "var:preset|color|cta-800" } }, "phase": { @@ -719,6 +726,13 @@ "postTypes": [ "page" ] + }, + { + "name": "page-work-archive", + "title": "Work Archive", + "postTypes": [ + "page" + ] } ] } \ No newline at end of file