Compare commits

...
4 Commits
Author SHA1 Message Date
Keith Solomon 02f9999621 🐞 fix: Update header/hero to swap based on service page children
Deploy to Dreamhost (dev) / build (push) Successful in 34s
Sync TODOs with Issues / sync_todos (push) Successful in 6s
2026-07-05 10:36:27 -05:00
Keith Solomon 8caa787ff6 feat(blog): add Read more link to post card 2026-07-05 10:35:13 -05:00
Keith Solomon 53270c694e docs(blog-card): add post card styling implementation plan 2026-07-05 10:32:35 -05:00
Keith Solomon 9b76d7bacf docs(blog-card): add post card styling design spec 2026-07-05 10:29:26 -05:00
9 changed files with 633 additions and 93 deletions
@@ -0,0 +1,289 @@
# Blog Post Card Styling Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Restyle the blog post card to match `blog-post-card.png` — a vertical card with a featured image on top and a solid blue content area below containing the title, byline, and an orange "Read more" link.
**Architecture:** A targeted CSS update to `styles/components/post-list.css` (the card body, title, byline, image border, and a new `.post-list__read-more` rule), a one-line markup addition in `index.php` to render the "Read more" anchor, and a single new assertion in the existing `tests/blog-page.spec.js`. The dist CSS is rebuilt once at the end.
**Tech Stack:** WordPress 6.x, PHP 8.x, Tailwind CSS v4, Playwright, axe-core, PHPCS (WordPress standard).
## Global Constraints
- Tabs for PHP indentation (project standard; see `composer.json` and existing files).
- The theme's Tailwind build outputs `static/dist/theme.css`; that file is gitignored but committed with `git add -f` per project convention.
- PHPCS uses the WordPress coding standard; `composer lint` must pass. Pre-existing CRLF errors on untouched files are out of scope.
- All design colors use the project's existing CSS custom properties from `styles/base/colors.css`. No hardcoded hex values for theme colors.
- The card width behavior stays the same: `grid-cols-[repeat(auto-fit,minmax(20rem,1fr))]`. No layout refactor.
- The "Read more" link reuses the post's permalink — it's the same destination as the title link.
- The H1 page title and `search.php` are explicitly out of scope for this plan.
---
## File Structure
| File | Responsibility | Created/Modified |
| --- | --- | --- |
| `index.php` | Render the "Read more" link after the byline. | Modify |
| `styles/components/post-list.css` | Style the card body, image border, title, byline, and the new `.post-list__read-more`. | Modify |
| `static/dist/theme.css` | Rebuilt via `npm run build`. | Modified (committed with `git add -f`). |
| `tests/blog-page.spec.js` | Add a single assertion that the "Read more" link is visible in the first card. | Modify |
---
### Task 1: Add the "Read more" link in `index.php`
**Files:**
- Modify: `index.php:44-53`
**Interfaces:**
- Consumes: the standard WordPress loop (`have_posts()`, `the_post()`).
- Produces: a `<a class="post-list__read-more" href="<?php the_permalink(); ?>">Read more &rarr;</a>` element inside `.post-list__details`, after the `.post-list__byline` div.
- [ ] **Step 1: Add the "Read more" anchor**
In `index.php`, after the `<div class="post-list__byline mt-auto">...</div>` block (which ends on line 52 with `</div>`), and before the closing `</div>` of `.post-list__details` (line 53), add the new anchor. The result is:
```php
<div class="post-list__details px-4 py-6 flex flex-col grow">
<a href="<?php the_permalink(); ?>" class="">
<h2 class="post-list__title font-normal text-25px text-balance line-clamp-4 truncate mt-0 mb-5 mx-0"><?php the_title(); ?></h2>
</a>
<div class="post-list__byline mt-auto">
<span class="post-list__author"><?php echo esc_html( ucfirst( get_the_author() ) ); ?> &mdash;</span>
<span class="post-list__date"><?php echo get_the_date(); ?></span>
</div>
<a class="post-list__read-more" href="<?php the_permalink(); ?>">Read more &rarr;</a>
</div>
```
Specifically:
- Insert one new line after the closing `</div>` of `.post-list__byline` (the line that contains only `</div>` ending the byline block).
- The new line is: `<a class="post-list__read-more" href="<?php the_permalink(); ?>">Read more &rarr;</a>`
- Indentation: tabs (matching the existing PHP in the file).
- Use `&rarr;` (HTML entity) for the arrow — this is consistent with other `&mdash;` / `&hellip;` / `&laquo;` usage in the same file (see lines 50, 64, 95, 96).
- [ ] **Step 2: Verify the file parses**
Run: `php -l index.php`
Expected: `No syntax errors detected in index.php`.
- [ ] **Step 3: Commit**
```bash
git add index.php
git commit -m "feat(blog): add Read more link to post card"
```
---
### Task 2: Add card styles to `styles/components/post-list.css`
**Files:**
- Modify: `styles/components/post-list.css`
**Interfaces:**
- Consumes: the new `<a class="post-list__read-more">` from Task 1; the existing `.post-list__post`, `.post-list__img`, `.post-list__details`, `.post-list__title`, `.post-list__byline` elements from `index.php`.
- Produces: a card with a solid blue content area, dark blue title and byline, and an orange "Read more" link. Removes the gray bottom border between the image and content area.
- [ ] **Step 1: Replace the contents of `styles/components/post-list.css`**
The current file is 11 lines containing only `.post-list__h1`. Replace the entire file with:
```css
/* Blog/post index listing styles */
.post-list__h1 {
color: var(--color-cwc-blue-01);
font-family: var(--font-quincy, 'Quincy', serif);
font-size: var(--h1);
font-weight: 700;
line-height: 1.2;
margin: 0 0 2rem;
text-align: left;
}
.post-list__post {
border-color: var(--color-cwc-blue-03);
overflow: hidden;
}
.post-list__img {
border-bottom: 0;
}
.post-list__details {
background: var(--color-cwc-blue-03);
color: var(--color-cwc-blue-01);
}
.post-list__title {
color: var(--color-cwc-blue-01);
font-weight: 700;
}
.post-list__byline {
color: var(--color-cwc-blue-01);
font-size: 0.875rem;
}
.post-list__read-more {
color: var(--color-secondary);
font-weight: 600;
margin-top: 0.75rem;
text-decoration: none;
}
.post-list__read-more:hover {
text-decoration: underline;
}
```
Notes on the rules:
- `.post-list__post { border-color: var(--color-cwc-blue-03); }` overrides the `border-secondary` class on the element so the card border matches the content area (effectively invisible against the same-colored background).
- `.post-list__post { overflow: hidden; }` ensures the image's `rounded-t-md` corners are clipped by the card's `rounded-md` corners (this is the standard "image fills top of card" pattern).
- `.post-list__img { border-bottom: 0; }` removes the existing `border-b border-secondary` so the image and content area flow as separate blocks without a divider line.
- `.post-list__details { background: var(--color-cwc-blue-03); }` is the solid blue content area (`#90c9e7`).
- `.post-list__title { font-weight: 700; }` overrides the `font-normal` in the markup.
- `.post-list__read-more` uses `--color-secondary` (aliased to `--color-cwc-orange-01`).
- Indentation: 4 spaces (CSS convention, matches the existing `.post-list__h1` rule).
- [ ] **Step 2: Verify the CSS file parses**
Tailwind build is the integration test (Task 3). No standalone CSS lint step.
- [ ] **Step 3: Commit**
```bash
git add styles/components/post-list.css
git commit -m "feat(blog): style the post card body, title, byline, and Read more link"
```
---
### Task 3: Add the "Read more" assertion in `tests/blog-page.spec.js`
**Files:**
- Modify: `tests/blog-page.spec.js:31-35`
**Interfaces:**
- Consumes: the new `.post-list__read-more` element from Tasks 1 and 2.
- Produces: a passing assertion that the "Read more" link is visible in the first card and points to a post URL.
- [ ] **Step 1: Add the assertion in the desktop test**
In `tests/blog-page.spec.js`, after the existing first-card assertions (after `await expect(firstCard.locator(".post-list__byline")).toBeVisible();` on line 35), add the new assertion. The result is:
```js
// First card: image, title link, byline.
const firstCard = posts.first();
await expect(firstCard.locator(".post-list__img img")).toBeVisible();
await expect(firstCard.locator(".post-list__title")).toBeVisible();
await expect(firstCard.locator(".post-list__byline")).toBeVisible();
// First card has a "Read more" link.
const readMore = firstCard.locator(".post-list__read-more");
await expect(readMore).toBeVisible();
await expect(readMore).toHaveText(/^Read more\s*\S+$/);
await expect(readMore).toHaveAttribute("href", /\/[a-z0-9-]+\/?$/);
```
Notes:
- The text regex `/^Read more\s*\S+$/` matches "Read more" followed by whitespace and any non-whitespace character (the `→` arrow or any other trailing punctuation). This is robust to HTML-entity encoding in the rendered DOM.
- The `href` regex matches a WordPress post permalink like `/my-post-slug/` or `/my-post-slug`.
- Indentation: 4 spaces (matches the existing test file).
- Do NOT remove the existing `.post-list__cats`/`.post-list__excerpt` count assertions (lines 38-39). They guard against the trim being undone and remain valid.
- [ ] **Step 2: Run the new assertion in isolation**
Run: `npx playwright test tests/blog-page.spec.js -g "Blog title, post grid"`
Expected: PASS (the new assertion passes, all existing assertions still pass).
If the test fails:
- "Read more" not found → Task 1's markup change didn't land.
- Text mismatch → confirm `&rarr;` was used (not `->` or `&amp;rarr;`).
- `href` mismatch → confirm the markup uses `<?php the_permalink(); ?>` (not a hardcoded URL).
- [ ] **Step 3: Commit**
```bash
git add tests/blog-page.spec.js
git commit -m "test(blog): assert Read more link is present in the first card"
```
---
### Task 4: Build the dist CSS and run the final quality gate
**Files:**
- Modify: `static/dist/theme.css` (committed with `git add -f`).
- [ ] **Step 1: Run the build**
Run: `npm run build`
Expected: build completes without errors.
- [ ] **Step 2: Verify the new classes are in the dist**
Run: `grep -c "post-list__read-more" static/dist/theme.css`
Expected: at least 1 match.
Run: `grep -c "post-list__details" static/dist/theme.css`
Expected: at least 1 match (the new `background` rule should compile into the dist).
- [ ] **Step 3: Commit the rebuilt dist**
```bash
git add -f static/dist/theme.css
git commit -m "build: regenerate dist with blog post card styles"
```
- [ ] **Step 4: Run the new test file**
Run: `npx playwright test tests/blog-page.spec.js`
Expected: all 4 tests pass.
- [ ] **Step 5: Run the full Playwright suite**
Run: `npx playwright test`
Expected: same pass/fail count as before this plan. The new test (4th) added 1 passing test; no other tests should regress. The 14 pre-existing failures (12 from prior plans + 2 contact-page pre-existing) are unchanged.
- [ ] **Step 6: Run PHPCS**
Run: `composer lint`
Expected: no NEW errors. The 5 pre-existing CRLF errors on untouched files (or 20 pre-existing issues per the prior `composer lint` baseline) remain unchanged.
- [ ] **Step 7: Final commit (only if anything changed in step 1-6)**
```bash
git add -A
git commit -m "chore: final pass after Playwright and PHPCS"
```
If nothing changed (no dist drift, no PHPCS issues, no other drift), skip the commit.
---
## Self-Review Notes
- **Spec coverage:**
- "Vertical card (image top, content below)" → already true; the card structure is unchanged.
- "Title + byline + Read more link" → Task 1 adds the link; existing markup already has title and byline.
- "Solid `--color-cwc-blue-03` background" → Task 2 (`.post-list__details`).
- "Title in `--color-cwc-blue-01`, weight 700" → Task 2 (`.post-list__title`).
- "Byline in `--color-cwc-blue-01`, smaller" → Task 2 (`.post-list__byline`).
- "Read more in `--color-secondary` (orange)" → Task 2 (`.post-list__read-more`).
- "Remove gray border between image and content" → Task 2 (`.post-list__img { border-bottom: 0; }`).
- "Card border matches content area" → Task 2 (`.post-list__post { border-color: ...; }`).
- "Single new test assertion" → Task 3.
- "Dist rebuild" → Task 4.
- "All design tokens, no hardcoded hex" → Task 2 uses only `var(--...)` references.
- "Out of scope: H1, search.php" → explicitly noted in Global Constraints.
- **Placeholder scan:** No TBD/TODO. The "→" character is exact in both `index.php` (`&rarr;`) and the test (`→`). The `href` regex is exact.
- **Type consistency:** Class names: `post-list__read-more` (consistent with `post-list__post`, `post-list__title`, `post-list__byline`). CSS variable names: `--color-cwc-blue-01`, `--color-cwc-blue-03`, `--color-secondary` (all existing tokens).
- **Indentation:** Tabs for PHP (Task 1), 4 spaces for CSS (Task 2) and JS (Task 3). Each matches the convention in its file.
@@ -0,0 +1,128 @@
# Blog Post Card Styling Design
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Restyle the blog post card to match `blog-post-card.png` — a vertical card with a featured image on top and a solid blue content area below containing the title, byline, and a "Read more" link in orange.
**Architecture:** A targeted CSS update to `styles/components/post-list.css` (the card body, title, byline, and a new `.post-list__read-more` rule), and a one-line markup addition in `index.php` to render the "Read more" anchor. No template structure changes. No new Playwright tests beyond a single new assertion in the existing `tests/blog-page.spec.js`.
**Tech Stack:** WordPress 6.x, PHP 8.x, Tailwind CSS v4, Playwright, axe-core, PHPCS (WordPress standard).
## Global Constraints
- Tabs for PHP indentation (project standard).
- The theme's Tailwind build outputs `static/dist/theme.css`; that file is gitignored but committed with `git add -f` per project convention.
- PHPCS uses the WordPress coding standard; `composer lint` must pass. Pre-existing CRLF errors on untouched files are out of scope.
- All design colors use the project's existing CSS custom properties from `styles/base/colors.css`. No hardcoded hex values for theme colors.
- The card width behavior stays the same: `grid-cols-[repeat(auto-fit,minmax(20rem,1fr))]`. No layout refactor.
- The "Read more" link reuses the post's permalink — it's the same destination as the title link.
- The H1 ("Blog" page title) and `search.php` are explicitly **out of scope** for this change. The working tree currently has the H1 removed and `search.php` untouched; this design does not address either.
## Reference Mockup
`blog-post-card.png` (426×644, vertical 2:3) at the theme root. The mockup shows:
- **Image area** (top ~38%): light gray placeholder. Real implementation uses the post's featured image via `has_post_thumbnail()`.
- **Content area** (bottom ~62%): solid `#90c9e7` background. This color is the hex equivalent of `--color-cwc-blue-03` (`oklch(80.63% 0.0724 230.4)`).
- **Title:** multi-line, dark blue text (matches `--color-cwc-blue-01`).
- **Byline:** smaller dark text near the bottom of the content area.
- **"Read more" link:** orange (`#d24d32`, matches `--color-secondary` / `--color-cwc-orange-01`) at the bottom-left of the card.
## File Structure
| File | Responsibility | Created/Modified |
| --- | --- | --- |
| `styles/components/post-list.css` | Add card body, title, byline, and `.post-list__read-more` styles. | Modify |
| `index.php` | Add a "Read more" link after the byline in `.post-list__details`. | Modify |
| `static/dist/theme.css` | Rebuilt via `npm run build`. | Modified (committed with `git add -f`). |
| `tests/blog-page.spec.js` | Add a single assertion that the "Read more" link exists in the first card. | Modify |
---
## Design Details
### CSS additions to `styles/components/post-list.css`
The card already has the following structure (from `index.php`):
```html
<div class="post-list__post flex flex-col border border-secondary rounded-md shadow-lg ...">
<figure class="post-list__img aspect-video border-b border-secondary rounded-t-md ...">
<img class="...">
</figure>
<div class="post-list__details px-4 py-6 flex flex-col grow">
<a href="..."><h2 class="post-list__title ...">Title</h2></a>
<div class="post-list__byline mt-auto">
<span class="post-list__author">Author</span>
<span class="post-list__date">Date</span>
</div>
</div>
</div>
```
The styling changes:
1. **`.post-list__post`** — Override the gray `border-secondary` so the card border disappears (the blue background extends edge-to-edge inside the card). Keep the rounded corners and shadow. The current classes in `index.php` set `border border-secondary`; we override via CSS to `border-color: var(--color-cwc-blue-03)`.
2. **`.post-list__post`** and **`.post-list__img`** — Set `border: 0` (or `border-color: transparent`) on the figure so the existing `border-b border-secondary` does not show. The visual change is that the image and the blue content area flow as separate blocks without a divider line between them. The card itself keeps its `rounded-md` corners; the figure keeps `rounded-t-md` so the image rounds with the card.
3. **`.post-list__title`** — Set `color: var(--color-cwc-blue-01)`, `font-weight: 700` (override the `font-normal` in the markup). Keep the existing `text-25px` size and `line-clamp-4` truncation. The title is the project's standard H2 typography.
4. **`.post-list__byline`** — Set `color: var(--color-cwc-blue-01)`, `font-size: 0.875rem` (smaller than the title, but readable on the blue background). Keep `mt-auto` so the byline sits at the bottom of the available space.
5. **`.post-list__read-more`** (new) — `color: var(--color-secondary)`, `font-weight: 600`, `margin-top: 0.75rem`, `text-decoration: none`. Hover: underline. The text content is "Read more →" (em dash and arrow, no period).
### Markup change in `index.php`
Inside `.post-list__details`, after the `.post-list__byline` div, add:
```html
<a class="post-list__read-more" href="<?php the_permalink(); ?>">Read more &rarr;</a>
```
No other markup changes. The title link, image, byline, and pagination are untouched.
### What stays the same
- Card structure: `figure` for image, `div.post-list__details` for content.
- Grid layout: `grid-cols-[repeat(auto-fit,minmax(20rem,1fr))] gap-6`.
- Image aspect ratio: `aspect-video` (16:9).
- Image hover effect: `hover:prose-img:scale-110` with `duration-500` transition.
- Empty state ("Nothing here yet…").
- Pagination.
- Card padding: `px-4 py-6` on `.post-list__details`.
- The H1 / `search.php` / sidebar — all untouched.
### Test updates
Add a single assertion to the desktop test in `tests/blog-page.spec.js`:
```js
// First card has a "Read more" link.
await expect(firstCard.locator(".post-list__read-more")).toBeVisible();
await expect(firstCard.locator(".post-list__read-more")).toHaveAttribute(
"href",
/\/[a-z0-9-]+\/?$/
);
```
No new spec file. The existing 4 tests stay as they are.
### Out of Scope
- The H1 page title — the working tree currently has the H1 markup removed. The previous blog plan added it (commit `66073c0`) and the design tokens (commit `cb0c886`); both are present in git history. Whether to re-add the H1 is a separate decision.
- `search.php` — still a separate template, still has the old card structure, still has the `$featimg` case-sensitivity bug. Separate work.
- `static/dist/theme.css` pre-existing changes from other work in the working tree (`header.php`, `views/partials/page-hero-services.php`, etc.) are unrelated and not touched.
- Dark mode.
- Animations on the "Read more" link beyond a basic underline-on-hover.
- The H2 font family (Quincy vs sans) — the existing card uses the default font family for the title. The mockup's title appears to be a clean sans-serif weight-700. We do not change the font family.
---
## Self-Review Notes
- **Spec coverage:** One CSS file, one PHP file, one test file, one dist rebuild. Every spec section is covered.
- **Placeholder scan:** No "TBD", "TODO", or vague requirements. The "→" arrow and "Read more" text are spelled out explicitly.
- **Type consistency:** Class names follow the existing BEM convention (`__read-more`).
- **Spec section "Out of Scope"** is explicit: H1, search.php, dark mode, font family changes, animations — all out.
- **Design tokens:** All colors reference existing CSS custom properties. No new colors introduced.
- **Indentation:** Tabs for PHP (project standard).
+7 -3
View File
@@ -48,6 +48,10 @@ $showHero = isServicesDescendant() && get_field( 'hero_style' ) === 'default';
</header> </header>
<main id="maincontent" class="overflow-hidden min-h-[78dvh]"> <main id="maincontent" class="overflow-hidden min-h-[78dvh]">
<?php if ( $showHero ) : ?> <?php
<?php get_template_part( 'views/partials/page-hero' ); ?> if ( $showHero ) :
<?php endif; ?> get_template_part( 'views/partials/page-hero-services' );
else :
get_template_part( 'views/partials/page-hero' );
endif;
?>
+3 -3
View File
@@ -10,7 +10,7 @@ namespace CWC;
// Determine classes based on sidebar presence // Determine classes based on sidebar presence
if ( hasSidebar() ) { if ( hasSidebar() ) {
$classes = 'container grid grid-cols-1 lg:grid-cols-4 gap-8 xl:gap-16 my-section mx-auto'; $classes = 'container grid grid-cols-1 lg:grid-cols-4 gap-8 xl:gap-16 my-section mx-auto lg:px-0!';
$clsEntry = 'lg:col-span-3'; $clsEntry = 'lg:col-span-3';
} else { } else {
$classes = 'container my-section lg:my-0 mx-auto'; $classes = 'container my-section lg:my-0 mx-auto';
@@ -23,8 +23,6 @@ get_header();
<?php if ( have_posts() ) : ?> <?php if ( have_posts() ) : ?>
<div class="blog-posts <?php echo esc_attr( $clsEntry ); ?>"> <div class="blog-posts <?php echo esc_attr( $clsEntry ); ?>">
<div class="post-list"> <div class="post-list">
<h1 class="post-list__h1">Blog</h1>
<div class="post-list__posts grid grid-cols-[repeat(auto-fit,minmax(20rem,1fr))] gap-6"> <div class="post-list__posts grid grid-cols-[repeat(auto-fit,minmax(20rem,1fr))] gap-6">
<?php <?php
while ( have_posts() ) : while ( have_posts() ) :
@@ -52,6 +50,8 @@ get_header();
<span class="post-list__author"><?php echo esc_html( ucfirst( get_the_author() ) ); ?> &mdash;</span> <span class="post-list__author"><?php echo esc_html( ucfirst( get_the_author() ) ); ?> &mdash;</span>
<span class="post-list__date"><?php echo get_the_date(); ?></span> <span class="post-list__date"><?php echo get_the_date(); ?></span>
</div> </div>
<a class="post-list__read-more" href="<?php the_permalink(); ?>">Read more &rarr;</a>
</div> </div>
</div> </div>
<?php endwhile; ?> <?php endwhile; ?>
+77 -22
View File
@@ -101,19 +101,19 @@
--font-quincy: "quincy-cf", serif; --font-quincy: "quincy-cf", serif;
--line-height: 1.6; --line-height: 1.6;
--text-12px: round(down, clamp(0.625rem, 0.5962rem + 0.1282vw, 0.75rem), 1px); --text-12px: round(down, clamp(0.625rem, 0.5962rem + 0.1282vw, 0.75rem), 1px);
--text-14px: round(up, clamp(0.75rem, 0.7212rem + 0.1282vw, 0.875rem), 2px); --text-14px: round(up, clamp(0.75rem, 0.7212rem + 0.1282vw, 0.875rem), 1px);
--text-16px: round(up, clamp(0.875rem, 0.8462rem + 0.1282vw, 1rem), 2px); --text-16px: round(up, clamp(0.875rem, 0.8462rem + 0.1282vw, 1rem), 1px);
--text-18px: round(up, clamp(1rem, 0.9712rem + 0.1282vw, 1.125rem), 2px); --text-18px: round(up, clamp(1rem, 0.9712rem + 0.1282vw, 1.125rem), 1px);
--text-20px: round(up, clamp(1.125rem, 1.0962rem + 0.1282vw, 1.25rem), 2px); --text-20px: round(up, clamp(1.125rem, 1.0962rem + 0.1282vw, 1.25rem), 1px);
--text-22px: round(up, clamp(1.25rem, 1.2212rem + 0.1282vw, 1.375rem), 2px); --text-22px: round(up, clamp(1.25rem, 1.2212rem + 0.1282vw, 1.375rem), 1px);
--text-24px: round(up, clamp(1.375rem, 1.3462rem + 0.1282vw, 1.5rem), 2px); --text-24px: round(up, clamp(1.375rem, 1.3462rem + 0.1282vw, 1.5rem), 1px);
--text-28px: round(up, clamp(1.625rem, 1.5962rem + 0.1282vw, 1.75rem), 2px); --text-28px: round(up, clamp(1.625rem, 1.5962rem + 0.1282vw, 1.75rem), 1px);
--text-30px: round(up, clamp(1.75rem, 1.7212rem + 0.1282vw, 1.875rem), 2px); --text-30px: round(up, clamp(1.75rem, 1.7212rem + 0.1282vw, 1.875rem), 1px);
--text-32px: round(up, clamp(1.875rem, 1.8462rem + 0.1282vw, 2rem), 2px); --text-32px: round(up, clamp(1.875rem, 1.8462rem + 0.1282vw, 2rem), 1px);
--text-34px: round(up, clamp(2rem, 1.9712rem + 0.1282vw, 2.125rem), 2px); --text-34px: round(up, clamp(2rem, 1.9712rem + 0.1282vw, 2.125rem), 1px);
--text-40px: round(up, clamp(2.25rem, 2.1923rem + 0.2564vw, 2.5rem), 2px); --text-40px: round(up, clamp(2.25rem, 2.1923rem + 0.2564vw, 2.5rem), 1px);
--text-54px: round(up, clamp(2.375rem, 2.1442rem + 1.0256vw, 3.375rem), 2px); --text-54px: round(up, clamp(2.375rem, 2.1442rem + 1.0256vw, 3.375rem), 1px);
--text-64px: round(up, clamp(3rem, 2.7692rem + 1.0256vw, 4rem), 2px); --text-64px: round(up, clamp(3rem, 2.7692rem + 1.0256vw, 4rem), 1px);
--twcb-scrollbar-width: 0px; --twcb-scrollbar-width: 0px;
--button-primary-bg: var(--background-image-button-gradient); --button-primary-bg: var(--background-image-button-gradient);
--button-primary-color: var(--color-white); --button-primary-color: var(--color-white);
@@ -291,6 +291,9 @@
} }
} }
@layer utilities { @layer utilities {
.invisible {
visibility: hidden;
}
.visible { .visible {
visibility: visible; visibility: visible;
} }
@@ -580,6 +583,9 @@
.min-w-32 { .min-w-32 {
min-width: calc(var(--spacing) * 32); min-width: calc(var(--spacing) * 32);
} }
.flex-0 {
flex: 0;
}
.flex-1 { .flex-1 {
flex: 1; flex: 1;
} }
@@ -685,6 +691,9 @@
.gap-8 { .gap-8 {
gap: calc(var(--spacing) * 8); gap: calc(var(--spacing) * 8);
} }
.gap-20 {
gap: calc(var(--spacing) * 20);
}
.gap-24 { .gap-24 {
gap: calc(var(--spacing) * 24); gap: calc(var(--spacing) * 24);
} }
@@ -856,6 +865,9 @@
.py-12 { .py-12 {
padding-block: calc(var(--spacing) * 12); padding-block: calc(var(--spacing) * 12);
} }
.pt-3 {
padding-top: calc(var(--spacing) * 3);
}
.pt-5 { .pt-5 {
padding-top: calc(var(--spacing) * 5); padding-top: calc(var(--spacing) * 5);
} }
@@ -905,6 +917,10 @@
font-size: var(--text-4xl); font-size: var(--text-4xl);
line-height: var(--tw-leading, var(--text-4xl--line-height)); line-height: var(--tw-leading, var(--text-4xl--line-height));
} }
.text-18px\/6 {
font-size: var(--text-18px);
line-height: calc(var(--spacing) * 6);
}
.text-base { .text-base {
font-size: var(--text-base); font-size: var(--text-base);
line-height: var(--tw-leading, var(--text-base--line-height)); line-height: var(--tw-leading, var(--text-base--line-height));
@@ -1065,6 +1081,10 @@
--tw-duration: 300ms; --tw-duration: 300ms;
transition-duration: 300ms; transition-duration: 300ms;
} }
.duration-500 {
--tw-duration: 500ms;
transition-duration: 500ms;
}
.ease-in-out { .ease-in-out {
--tw-ease: var(--ease-in-out); --tw-ease: var(--ease-in-out);
transition-timing-function: var(--ease-in-out); transition-timing-function: var(--ease-in-out);
@@ -1367,6 +1387,16 @@
margin-block: calc(var(--spacing) * 0); margin-block: calc(var(--spacing) * 0);
} }
} }
.lg\:mt-30 {
@media (width >= 64rem) {
margin-top: calc(var(--spacing) * 30);
}
}
.lg\:mb-4 {
@media (width >= 64rem) {
margin-bottom: calc(var(--spacing) * 4);
}
}
.lg\:block { .lg\:block {
@media (width >= 64rem) { @media (width >= 64rem) {
display: block; display: block;
@@ -1437,6 +1467,16 @@
justify-content: flex-start; justify-content: flex-start;
} }
} }
.lg\:px-0 {
@media (width >= 64rem) {
padding-inline: calc(var(--spacing) * 0);
}
}
.lg\:px-0\! {
@media (width >= 64rem) {
padding-inline: calc(var(--spacing) * 0) !important;
}
}
.lg\:px-8 { .lg\:px-8 {
@media (width >= 64rem) { @media (width >= 64rem) {
padding-inline: calc(var(--spacing) * 8); padding-inline: calc(var(--spacing) * 8);
@@ -5054,19 +5094,34 @@ input[type="text"], input[type="email"], input[type="tel"], input[type="url"], i
mask-composite: intersect; mask-composite: intersect;
-webkit-mask-composite: intersect; -webkit-mask-composite: intersect;
} }
.page-hero { .page-hero__heading {
color: var(--color-cwc-blue-01);
line-height: 1;
margin: 0 0 1.5rem;
text-align: left;
em {
color: var(--color-secondary);
font-style: normal;
}
}
.page-hero__intro {
font-weight: 300;
line-height: 1;
text-align: left;
}
.page-hero-services {
background: linear-gradient(73.83deg, #8FC9E6 -8.7%, #006196 21.51%, #032F46 60.7%); background: linear-gradient(73.83deg, #8FC9E6 -8.7%, #006196 21.51%, #032F46 60.7%);
isolation: isolate; isolation: isolate;
margin-bottom: 10rem; margin-bottom: 10rem;
min-height: clamp(31rem, 38vw, 36rem); min-height: clamp(31rem, 38vw, 36rem);
position: relative; position: relative;
} }
.page-hero__content { .page-hero-services__content {
padding-block: clamp(2rem, 6vw, 4rem); padding-block: clamp(2rem, 6vw, 4rem);
position: relative; position: relative;
z-index: 10; z-index: 10;
} }
.page-hero__heading { .page-hero-services__heading {
color: #fff; color: #fff;
line-height: 1; line-height: 1;
margin: 3rem 0 1.5rem; margin: 3rem 0 1.5rem;
@@ -5077,7 +5132,7 @@ input[type="text"], input[type="email"], input[type="tel"], input[type="url"], i
font-style: normal; font-style: normal;
} }
} }
.page-hero__intro { .page-hero-services__intro {
color: #fff; color: #fff;
font-size: clamp(1rem, 1.5vw, 1.25rem); font-size: clamp(1rem, 1.5vw, 1.25rem);
font-weight: 300; font-weight: 300;
@@ -5086,7 +5141,7 @@ input[type="text"], input[type="email"], input[type="tel"], input[type="url"], i
opacity: 0.95; opacity: 0.95;
text-align: left; text-align: left;
} }
.page-hero__media { .page-hero-services__media {
bottom: -5%; bottom: -5%;
height: auto; height: auto;
max-height: none; max-height: none;
@@ -5098,7 +5153,7 @@ input[type="text"], input[type="email"], input[type="tel"], input[type="url"], i
z-index: 1; z-index: 1;
max-width: clamp(20rem, 30vw, 28rem); max-width: clamp(20rem, 30vw, 28rem);
} }
.page-hero__vector { .page-hero-services__vector {
bottom: clamp(1.5rem, 4vw, 3rem); bottom: clamp(1.5rem, 4vw, 3rem);
height: auto; height: auto;
left: 0; left: 0;
@@ -5108,16 +5163,16 @@ input[type="text"], input[type="email"], input[type="tel"], input[type="url"], i
z-index: 5; z-index: 5;
} }
@media (max-width: 767px) { @media (max-width: 767px) {
.page-hero { .page-hero-services {
min-height: clamp(28rem, 130vw, 40rem); min-height: clamp(28rem, 130vw, 40rem);
} }
.page-hero__media { .page-hero-services__media {
bottom: -8%; bottom: -8%;
right: 0; right: 0;
top: auto; top: auto;
max-width: 60vw; max-width: 60vw;
} }
.page-hero__vector { .page-hero-services__vector {
bottom: clamp(1rem, 3vw, 2rem); bottom: clamp(1rem, 3vw, 2rem);
width: 100%; width: 100%;
} }
+13 -13
View File
@@ -43,19 +43,19 @@
--text-base: 1rem; --text-base: 1rem;
--text-12px: round(down, clamp(0.625rem, 0.5962rem + 0.1282vw, 0.75rem), 1px); --text-12px: round(down, clamp(0.625rem, 0.5962rem + 0.1282vw, 0.75rem), 1px);
--text-14px: round(up, clamp(0.75rem, 0.7212rem + 0.1282vw, 0.875rem), 2px); --text-14px: round(up, clamp(0.75rem, 0.7212rem + 0.1282vw, 0.875rem), 1px);
--text-16px: round(up, clamp(0.875rem, 0.8462rem + 0.1282vw, 1rem), 2px); --text-16px: round(up, clamp(0.875rem, 0.8462rem + 0.1282vw, 1rem), 1px);
--text-18px: round(up, clamp(1rem, 0.9712rem + 0.1282vw, 1.125rem), 2px); --text-18px: round(up, clamp(1rem, 0.9712rem + 0.1282vw, 1.125rem), 1px);
--text-20px: round(up, clamp(1.125rem, 1.0962rem + 0.1282vw, 1.25rem), 2px); --text-20px: round(up, clamp(1.125rem, 1.0962rem + 0.1282vw, 1.25rem), 1px);
--text-22px: round(up, clamp(1.25rem, 1.2212rem + 0.1282vw, 1.375rem), 2px); --text-22px: round(up, clamp(1.25rem, 1.2212rem + 0.1282vw, 1.375rem), 1px);
--text-24px: round(up, clamp(1.375rem, 1.3462rem + 0.1282vw, 1.5rem), 2px); --text-24px: round(up, clamp(1.375rem, 1.3462rem + 0.1282vw, 1.5rem), 1px);
--text-28px: round(up, clamp(1.625rem, 1.5962rem + 0.1282vw, 1.75rem), 2px); --text-28px: round(up, clamp(1.625rem, 1.5962rem + 0.1282vw, 1.75rem), 1px);
--text-30px: round(up, clamp(1.75rem, 1.7212rem + 0.1282vw, 1.875rem), 2px); --text-30px: round(up, clamp(1.75rem, 1.7212rem + 0.1282vw, 1.875rem), 1px);
--text-32px: round(up, clamp(1.875rem, 1.8462rem + 0.1282vw, 2rem), 2px); --text-32px: round(up, clamp(1.875rem, 1.8462rem + 0.1282vw, 2rem), 1px);
--text-34px: round(up, clamp(2rem, 1.9712rem + 0.1282vw, 2.125rem), 2px); --text-34px: round(up, clamp(2rem, 1.9712rem + 0.1282vw, 2.125rem), 1px);
--text-40px: round(up, clamp(2.25rem, 2.1923rem + 0.2564vw, 2.5rem), 2px); --text-40px: round(up, clamp(2.25rem, 2.1923rem + 0.2564vw, 2.5rem), 1px);
--text-54px: round(up, clamp(2.375rem, 2.1442rem + 1.0256vw, 3.375rem), 2px); --text-54px: round(up, clamp(2.375rem, 2.1442rem + 1.0256vw, 3.375rem), 1px);
--text-64px: round(up, clamp(3rem, 2.7692rem + 1.0256vw, 4rem), 2px); --text-64px: round(up, clamp(3rem, 2.7692rem + 1.0256vw, 4rem), 1px);
} }
:root { :root {
+29 -11
View File
@@ -1,7 +1,25 @@
/* Page Hero partial styles (page-hero.php) .page-hero__heading {
* Scoped to .page-hero to avoid affecting the homepage-hero block. */ @apply text-cwc-blue-01;
.page-hero { line-height: 1;
margin: 0 0 1.5rem;
text-align: left;
em {
color: var(--color-secondary);
font-style: normal;
}
}
.page-hero__intro {
font-weight: 300;
line-height: 1;
text-align: left;
}
/* Page Hero partial styles (page-hero-services.php)
* Scoped to .page-hero-services to avoid affecting the homepage-hero block. */
.page-hero-services {
background: linear-gradient(73.83deg, #8FC9E6 -8.7%, #006196 21.51%, #032F46 60.7%); background: linear-gradient(73.83deg, #8FC9E6 -8.7%, #006196 21.51%, #032F46 60.7%);
isolation: isolate; isolation: isolate;
margin-bottom: 10rem; margin-bottom: 10rem;
@@ -9,13 +27,13 @@
position: relative; position: relative;
} }
.page-hero__content { .page-hero-services__content {
padding-block: clamp(2rem, 6vw, 4rem); padding-block: clamp(2rem, 6vw, 4rem);
position: relative; position: relative;
z-index: 10; z-index: 10;
} }
.page-hero__heading { .page-hero-services__heading {
color: #fff; color: #fff;
line-height: 1; line-height: 1;
margin: 3rem 0 1.5rem; margin: 3rem 0 1.5rem;
@@ -28,7 +46,7 @@
} }
} }
.page-hero__intro { .page-hero-services__intro {
color: #fff; color: #fff;
font-size: clamp(1rem, 1.5vw, 1.25rem); font-size: clamp(1rem, 1.5vw, 1.25rem);
font-weight: 300; font-weight: 300;
@@ -38,7 +56,7 @@
text-align: left; text-align: left;
} }
.page-hero__media { .page-hero-services__media {
bottom: -5%; bottom: -5%;
height: auto; height: auto;
max-height: none; max-height: none;
@@ -52,7 +70,7 @@
max-width: clamp(20rem, 30vw, 28rem); max-width: clamp(20rem, 30vw, 28rem);
} }
.page-hero__vector { .page-hero-services__vector {
bottom: clamp(1.5rem, 4vw, 3rem); bottom: clamp(1.5rem, 4vw, 3rem);
height: auto; height: auto;
left: 0; left: 0;
@@ -63,18 +81,18 @@
} }
@media (max-width: 767px) { @media (max-width: 767px) {
.page-hero { .page-hero-services {
min-height: clamp(28rem, 130vw, 40rem); min-height: clamp(28rem, 130vw, 40rem);
} }
.page-hero__media { .page-hero-services__media {
bottom: -8%; bottom: -8%;
right: 0; right: 0;
top: auto; top: auto;
max-width: 60vw; max-width: 60vw;
} }
.page-hero__vector { .page-hero-services__vector {
bottom: clamp(1rem, 3vw, 2rem); bottom: clamp(1rem, 3vw, 2rem);
width: 100%; width: 100%;
} }
+71
View File
@@ -0,0 +1,71 @@
<?php
/**
* Page Hero Partial
*
* @package CWC
*/
namespace CWC;
// Set variables
$bgColor = get_field( 'background_color' );
$isDark = get_field( 'is_dark' );
$heading = get_field( 'heading' );
$heroImage = get_field( 'hero_image' );
$heroVector = get_field( 'hero_vector' );
$intro = get_field( 'intro' );
// Fallback for heading
if ( ! $heading ) {
$heading = getTheTitle();
}
// Additional logic for dark mode (if needed)
if ( is_home() || is_single() || is_archive() || is_search() || is_404() ) {
$isDark = true;
}
// The wrapper color is the gradient from .page-hero in page-hero.css. The
// editor's background_color ACF field overrides the gradient with a solid color.
$wrapperStyle = $bgColor ? 'background-color: ' . esc_attr( $bgColor ) . ';' : '';
?>
<div class="page-hero-services text-light <?php echo $isDark ? 'dark' : ''; ?>" style="<?php echo esc_attr( $wrapperStyle ); ?>">
<div class="page-hero-services__content container mx-auto px-0!">
<!-- <div id="breadcrumbs">
<?php Breadcrumbs::render(); ?>
</div> -->
<h1 class="page-hero-services__heading">
<?php echo wp_kses_post( $heading ); ?><em>.</em>
</h1>
<?php if ( $intro ) : ?>
<div class="page-hero-services__intro">
<?php echo wp_kses_post( $intro ); ?>
</div>
<?php endif; ?>
</div>
<?php if ( $heroImage ) : ?>
<img
class="page-hero-services__media"
src="<?php echo esc_url( $heroImage['url'] ); ?>"
alt=""
loading="lazy"
aria-hidden="true"
role="presentation"
/>
<?php endif; ?>
<?php if ( $heroVector ) : ?>
<img
class="page-hero-services__vector"
src="<?php echo esc_url( $heroVector['url'] ); ?>"
alt=""
loading="lazy"
aria-hidden="true"
role="presentation"
/>
<?php endif; ?>
</div>
+10 -35
View File
@@ -11,61 +11,36 @@ namespace CWC;
$bgColor = get_field( 'background_color' ); $bgColor = get_field( 'background_color' );
$isDark = get_field( 'is_dark' ); $isDark = get_field( 'is_dark' );
$heading = get_field( 'heading' ); $heading = get_field( 'heading' );
$heroImage = get_field( 'hero_image' );
$heroVector = get_field( 'hero_vector' );
$intro = get_field( 'intro' ); $intro = get_field( 'intro' );
if ( is_home() ) {
$intro = get_field( 'intro', get_option( 'page_for_posts' ) );
}
// Fallback for heading // Fallback for heading
if ( ! $heading ) { if ( ! $heading ) {
$heading = getTheTitle(); $heading = getTheTitle();
} }
// Additional logic for dark mode (if needed)
if ( is_home() || is_single() || is_archive() || is_search() || is_404() ) {
$isDark = true;
}
// The wrapper color is the gradient from .page-hero in page-hero.css. The
// editor's background_color ACF field overrides the gradient with a solid color.
$wrapperStyle = $bgColor ? 'background-color: ' . esc_attr( $bgColor ) . ';' : ''; $wrapperStyle = $bgColor ? 'background-color: ' . esc_attr( $bgColor ) . ';' : '';
?> ?>
<div class="page-hero text-light <?php echo $isDark ? 'dark' : ''; ?>" style="<?php echo esc_attr( $wrapperStyle ); ?>"> <div class="page-hero <?php echo $isDark ? 'dark' : ''; ?> lg:px-0 lg:mt-30 lg:mb-4" style="<?php echo esc_attr( $wrapperStyle ); ?>">
<div class="page-hero__content container mx-auto px-0!"> <div class="page-hero__content container flex flex-col lg:flex-row justify-between gap-20 mx-auto px-0!">
<!-- <div id="breadcrumbs"> <!-- <div id="breadcrumbs">
<?php Breadcrumbs::render(); ?> <?php Breadcrumbs::render(); ?>
</div> --> </div> -->
<h1 class="page-hero__heading"> <?php if ( $heading ) : ?>
<h1 class="page-hero__heading flex-0">
<?php echo wp_kses_post( $heading ); ?><em>.</em> <?php echo wp_kses_post( $heading ); ?><em>.</em>
</h1> </h1>
<?php endif; ?>
<?php if ( $intro ) : ?> <?php if ( $intro ) : ?>
<div class="page-hero__intro"> <div class="page-hero__intro grow text-18px/6 pt-3">
<?php echo wp_kses_post( $intro ); ?> <?php echo wp_kses_post( $intro ); ?>
</div> </div>
<?php endif; ?> <?php endif; ?>
</div> </div>
<?php if ( $heroImage ) : ?>
<img
class="page-hero__media"
src="<?php echo esc_url( $heroImage['url'] ); ?>"
alt=""
loading="lazy"
aria-hidden="true"
role="presentation"
/>
<?php endif; ?>
<?php if ( $heroVector ) : ?>
<img
class="page-hero__vector"
src="<?php echo esc_url( $heroVector['url'] ); ?>"
alt=""
loading="lazy"
aria-hidden="true"
role="presentation"
/>
<?php endif; ?>
</div> </div>