diff --git a/.github/reports/theme-colour-variables-google-doc.txt b/.github/reports/theme-colour-variables-google-doc.txt new file mode 100644 index 0000000..e72b7a6 --- /dev/null +++ b/.github/reports/theme-colour-variables-google-doc.txt @@ -0,0 +1,391 @@ +Theme Colour Variables + +- Base +Slug: base +Hex: #F8F8F8 +Variable: var(--wp--preset--color--base) + +- Contrast +Slug: contrast +Hex: #080808 +Variable: var(--wp--preset--color--contrast) + +- Neutral 100 +Slug: neutral-100 +Hex: #F8F8F8 +Variable: var(--wp--preset--color--neutral-100) + +- Neutral 200 +Slug: neutral-200 +Hex: #E8E8E8 +Variable: var(--wp--preset--color--neutral-200) + +- Neutral 300 +Slug: neutral-300 +Hex: #D8D8D8 +Variable: var(--wp--preset--color--neutral-300) + +- Neutral 400 +Slug: neutral-400 +Hex: #B8B8B8 +Variable: var(--wp--preset--color--neutral-400) + +- Neutral 500 +Slug: neutral-500 +Hex: #909090 +Variable: var(--wp--preset--color--neutral-500) + +- Neutral 600 +Slug: neutral-600 +Hex: #707070 +Variable: var(--wp--preset--color--neutral-600) + +- Neutral 700 +Slug: neutral-700 +Hex: #505050 +Variable: var(--wp--preset--color--neutral-700) + +- Neutral 800 +Slug: neutral-800 +Hex: #303030 +Variable: var(--wp--preset--color--neutral-800) + +- Neutral 900 +Slug: neutral-900 +Hex: #181818 +Variable: var(--wp--preset--color--neutral-900) + +- Surface 100 +Slug: surface-100 +Hex: #2A2A30 +Variable: var(--wp--preset--color--surface-100) + +- Surface 200 +Slug: surface-200 +Hex: #202028 +Variable: var(--wp--preset--color--surface-200) + +- Surface 300 +Slug: surface-300 +Hex: #181820 +Variable: var(--wp--preset--color--surface-300) + +- Surface 400 +Slug: surface-400 +Hex: #12121A +Variable: var(--wp--preset--color--surface-400) + +- Surface 500 +Slug: surface-500 +Hex: #101018 +Variable: var(--wp--preset--color--surface-500) + +- Surface 600 +Slug: surface-600 +Hex: #0C0C14 +Variable: var(--wp--preset--color--surface-600) + +- Surface 700 +Slug: surface-700 +Hex: #080810 +Variable: var(--wp--preset--color--surface-700) + +- Surface 800 +Slug: surface-800 +Hex: #05050A +Variable: var(--wp--preset--color--surface-800) + +- Surface 900 +Slug: surface-900 +Hex: #000000 +Variable: var(--wp--preset--color--surface-900) + +- Brand 100 +Slug: brand-100 +Hex: #D6E4FF +Variable: var(--wp--preset--color--brand-100) + +- Brand 200 +Slug: brand-200 +Hex: #ADC8FF +Variable: var(--wp--preset--color--brand-200) + +- Brand 300 +Slug: brand-300 +Hex: #85ACFF +Variable: var(--wp--preset--color--brand-300) + +- Brand 400 +Slug: brand-400 +Hex: #5C90FF +Variable: var(--wp--preset--color--brand-400) + +- Brand 500 +Slug: brand-500 +Hex: #1E6AFF +Variable: var(--wp--preset--color--brand-500) + +- Brand 600 +Slug: brand-600 +Hex: #1C5EE4 +Variable: var(--wp--preset--color--brand-600) + +- Brand 700 +Slug: brand-700 +Hex: #184FBF +Variable: var(--wp--preset--color--brand-700) + +- Brand 800 +Slug: brand-800 +Hex: #123B8F +Variable: var(--wp--preset--color--brand-800) + +- Brand 900 +Slug: brand-900 +Hex: #0B255F +Variable: var(--wp--preset--color--brand-900) + +- Cta 100 +Slug: cta-100 +Hex: #DDFBFF +Variable: var(--wp--preset--color--cta-100) + +- Cta 200 +Slug: cta-200 +Hex: #B8F5FF +Variable: var(--wp--preset--color--cta-200) + +- Cta 300 +Slug: cta-300 +Hex: #8DEEFF +Variable: var(--wp--preset--color--cta-300) + +- Cta 400 +Slug: cta-400 +Hex: #5AE3F5 +Variable: var(--wp--preset--color--cta-400) + +- Cta 500 +Slug: cta-500 +Hex: #00FCFC +Variable: var(--wp--preset--color--cta-500) + +- Cta 600 +Slug: cta-600 +Hex: #00D9D9 +Variable: var(--wp--preset--color--cta-600) + +- Cta 700 +Slug: cta-700 +Hex: #00A8A8 +Variable: var(--wp--preset--color--cta-700) + +- Cta 800 +Slug: cta-800 +Hex: #007476 +Variable: var(--wp--preset--color--cta-800) + +- Cta 900 +Slug: cta-900 +Hex: #003D3F +Variable: var(--wp--preset--color--cta-900) + +- Accent 100 +Slug: accent-100 +Hex: #DDFBF1 +Variable: var(--wp--preset--color--accent-100) + +- Accent 200 +Slug: accent-200 +Hex: #B8F5DE +Variable: var(--wp--preset--color--accent-200) + +- Accent 300 +Slug: accent-300 +Hex: #86EDC4 +Variable: var(--wp--preset--color--accent-300) + +- Accent 400 +Slug: accent-400 +Hex: #4FDEAA +Variable: var(--wp--preset--color--accent-400) + +- Accent 500 +Slug: accent-500 +Hex: #22C78A +Variable: var(--wp--preset--color--accent-500) + +- Accent 600 +Slug: accent-600 +Hex: #17A974 +Variable: var(--wp--preset--color--accent-600) + +- Accent 700 +Slug: accent-700 +Hex: #11865B +Variable: var(--wp--preset--color--accent-700) + +- Accent 800 +Slug: accent-800 +Hex: #0B6243 +Variable: var(--wp--preset--color--accent-800) + +- Accent 900 +Slug: accent-900 +Hex: #063828 +Variable: var(--wp--preset--color--accent-900) + +- Accent Two 100 +Slug: accent-two-100 +Hex: #FFDDFB +Variable: var(--wp--preset--color--accent-two-100) + +- Accent Two 200 +Slug: accent-two-200 +Hex: #FFB8F5 +Variable: var(--wp--preset--color--accent-two-200) + +- Accent Two 300 +Slug: accent-two-300 +Hex: #FF85EE +Variable: var(--wp--preset--color--accent-two-300) + +- Accent Two 400 +Slug: accent-two-400 +Hex: #FF4FE3 +Variable: var(--wp--preset--color--accent-two-400) + +- Accent Two 500 +Slug: accent-two-500 +Hex: #FC00FC +Variable: var(--wp--preset--color--accent-two-500) + +- Accent Two 600 +Slug: accent-two-600 +Hex: #D400D4 +Variable: var(--wp--preset--color--accent-two-600) + +- Accent Two 700 +Slug: accent-two-700 +Hex: #A600A6 +Variable: var(--wp--preset--color--accent-two-700) + +- Accent Two 800 +Slug: accent-two-800 +Hex: #760076 +Variable: var(--wp--preset--color--accent-two-800) + +- Accent Two 900 +Slug: accent-two-900 +Hex: #3F003F +Variable: var(--wp--preset--color--accent-two-900) + +- Accent Three 100 +Slug: accent-three-100 +Hex: #E5FFE5 +Variable: var(--wp--preset--color--accent-three-100) + +- Accent Three 200 +Slug: accent-three-200 +Hex: #BEFFBE +Variable: var(--wp--preset--color--accent-three-200) + +- Accent Three 300 +Slug: accent-three-300 +Hex: #8FFF8F +Variable: var(--wp--preset--color--accent-three-300) + +- Accent Three 400 +Slug: accent-three-400 +Hex: #4FFF4F +Variable: var(--wp--preset--color--accent-three-400) + +- Accent Three 500 +Slug: accent-three-500 +Hex: #00FC00 +Variable: var(--wp--preset--color--accent-three-500) + +- Accent Three 600 +Slug: accent-three-600 +Hex: #00D400 +Variable: var(--wp--preset--color--accent-three-600) + +- Accent Three 700 +Slug: accent-three-700 +Hex: #00A300 +Variable: var(--wp--preset--color--accent-three-700) + +- Accent Three 800 +Slug: accent-three-800 +Hex: #007000 +Variable: var(--wp--preset--color--accent-three-800) + +- Accent Three 900 +Slug: accent-three-900 +Hex: #003D00 +Variable: var(--wp--preset--color--accent-three-900) + +- Accent Four 100 +Slug: accent-four-100 +Hex: #FFFFDD +Variable: var(--wp--preset--color--accent-four-100) + +- Accent Four 200 +Slug: accent-four-200 +Hex: #FFFFB8 +Variable: var(--wp--preset--color--accent-four-200) + +- Accent Four 300 +Slug: accent-four-300 +Hex: #FFFF85 +Variable: var(--wp--preset--color--accent-four-300) + +- Accent Four 400 +Slug: accent-four-400 +Hex: #FFFF4F +Variable: var(--wp--preset--color--accent-four-400) + +- Accent Four 500 +Slug: accent-four-500 +Hex: #FCFC00 +Variable: var(--wp--preset--color--accent-four-500) + +- Accent Four 600 +Slug: accent-four-600 +Hex: #D4D400 +Variable: var(--wp--preset--color--accent-four-600) + +- Accent Four 700 +Slug: accent-four-700 +Hex: #A6A600 +Variable: var(--wp--preset--color--accent-four-700) + +- Accent Four 800 +Slug: accent-four-800 +Hex: #767600 +Variable: var(--wp--preset--color--accent-four-800) + +- Accent Four 900 +Slug: accent-four-900 +Hex: #3F3F00 +Variable: var(--wp--preset--color--accent-four-900) + +- Error Foreground +Slug: error-foreground +Hex: #EF4444 +Variable: var(--wp--preset--color--error-foreground) + +- Warning Foreground +Slug: warning-foreground +Hex: #F59E0B +Variable: var(--wp--preset--color--warning-foreground) + +- Information Foreground +Slug: information-foreground +Hex: #3B82F6 +Variable: var(--wp--preset--color--information-foreground) + +- Success Foreground +Slug: success-foreground +Hex: #10B981 +Variable: var(--wp--preset--color--success-foreground) \ No newline at end of file diff --git a/.github/reports/theme-colour-variables.md b/.github/reports/theme-colour-variables.md new file mode 100644 index 0000000..9879925 --- /dev/null +++ b/.github/reports/theme-colour-variables.md @@ -0,0 +1,393 @@ +# Theme Colour Variables + +Extracted from `theme.json` `settings.color.palette`. + +- Name: Base
+ Slug: base
+ Hex: #F8F8F8
+ Variable: var(--wp--preset--color--base) + +- Name: Contrast
+ Slug: contrast
+ Hex: #080808
+ Variable: var(--wp--preset--color--contrast) + +- Name: Neutral 100
+ Slug: neutral-100
+ Hex: #F8F8F8
+ Variable: var(--wp--preset--color--neutral-100) + +- Name: Neutral 200
+ Slug: neutral-200
+ Hex: #E8E8E8
+ Variable: var(--wp--preset--color--neutral-200) + +- Name: Neutral 300
+ Slug: neutral-300
+ Hex: #D8D8D8
+ Variable: var(--wp--preset--color--neutral-300) + +- Name: Neutral 400
+ Slug: neutral-400
+ Hex: #B8B8B8
+ Variable: var(--wp--preset--color--neutral-400) + +- Name: Neutral 500
+ Slug: neutral-500
+ Hex: #909090
+ Variable: var(--wp--preset--color--neutral-500) + +- Name: Neutral 600
+ Slug: neutral-600
+ Hex: #707070
+ Variable: var(--wp--preset--color--neutral-600) + +- Name: Neutral 700
+ Slug: neutral-700
+ Hex: #505050
+ Variable: var(--wp--preset--color--neutral-700) + +- Name: Neutral 800
+ Slug: neutral-800
+ Hex: #303030
+ Variable: var(--wp--preset--color--neutral-800) + +- Name: Neutral 900
+ Slug: neutral-900
+ Hex: #181818
+ Variable: var(--wp--preset--color--neutral-900) + +- Name: Surface 100
+ Slug: surface-100
+ Hex: #2A2A30
+ Variable: var(--wp--preset--color--surface-100) + +- Name: Surface 200
+ Slug: surface-200
+ Hex: #202028
+ Variable: var(--wp--preset--color--surface-200) + +- Name: Surface 300
+ Slug: surface-300
+ Hex: #181820
+ Variable: var(--wp--preset--color--surface-300) + +- Name: Surface 400
+ Slug: surface-400
+ Hex: #12121A
+ Variable: var(--wp--preset--color--surface-400) + +- Name: Surface 500
+ Slug: surface-500
+ Hex: #101018
+ Variable: var(--wp--preset--color--surface-500) + +- Name: Surface 600
+ Slug: surface-600
+ Hex: #0C0C14
+ Variable: var(--wp--preset--color--surface-600) + +- Name: Surface 700
+ Slug: surface-700
+ Hex: #080810
+ Variable: var(--wp--preset--color--surface-700) + +- Name: Surface 800
+ Slug: surface-800
+ Hex: #05050A
+ Variable: var(--wp--preset--color--surface-800) + +- Name: Surface 900
+ Slug: surface-900
+ Hex: #000000
+ Variable: var(--wp--preset--color--surface-900) + +- Name: Brand 100
+ Slug: brand-100
+ Hex: #D6E4FF
+ Variable: var(--wp--preset--color--brand-100) + +- Name: Brand 200
+ Slug: brand-200
+ Hex: #ADC8FF
+ Variable: var(--wp--preset--color--brand-200) + +- Name: Brand 300
+ Slug: brand-300
+ Hex: #85ACFF
+ Variable: var(--wp--preset--color--brand-300) + +- Name: Brand 400
+ Slug: brand-400
+ Hex: #5C90FF
+ Variable: var(--wp--preset--color--brand-400) + +- Name: Brand 500
+ Slug: brand-500
+ Hex: #1E6AFF
+ Variable: var(--wp--preset--color--brand-500) + +- Name: Brand 600
+ Slug: brand-600
+ Hex: #1C5EE4
+ Variable: var(--wp--preset--color--brand-600) + +- Name: Brand 700
+ Slug: brand-700
+ Hex: #184FBF
+ Variable: var(--wp--preset--color--brand-700) + +- Name: Brand 800
+ Slug: brand-800
+ Hex: #123B8F
+ Variable: var(--wp--preset--color--brand-800) + +- Name: Brand 900
+ Slug: brand-900
+ Hex: #0B255F
+ Variable: var(--wp--preset--color--brand-900) + +- Name: Cta 100
+ Slug: cta-100
+ Hex: #DDFBFF
+ Variable: var(--wp--preset--color--cta-100) + +- Name: Cta 200
+ Slug: cta-200
+ Hex: #B8F5FF
+ Variable: var(--wp--preset--color--cta-200) + +- Name: Cta 300
+ Slug: cta-300
+ Hex: #8DEEFF
+ Variable: var(--wp--preset--color--cta-300) + +- Name: Cta 400
+ Slug: cta-400
+ Hex: #5AE3F5
+ Variable: var(--wp--preset--color--cta-400) + +- Name: Cta 500
+ Slug: cta-500
+ Hex: #00FCFC
+ Variable: var(--wp--preset--color--cta-500) + +- Name: Cta 600
+ Slug: cta-600
+ Hex: #00D9D9
+ Variable: var(--wp--preset--color--cta-600) + +- Name: Cta 700
+ Slug: cta-700
+ Hex: #00A8A8
+ Variable: var(--wp--preset--color--cta-700) + +- Name: Cta 800
+ Slug: cta-800
+ Hex: #007476
+ Variable: var(--wp--preset--color--cta-800) + +- Name: Cta 900
+ Slug: cta-900
+ Hex: #003D3F
+ Variable: var(--wp--preset--color--cta-900) + +- Name: Accent 100
+ Slug: accent-100
+ Hex: #DDFBF1
+ Variable: var(--wp--preset--color--accent-100) + +- Name: Accent 200
+ Slug: accent-200
+ Hex: #B8F5DE
+ Variable: var(--wp--preset--color--accent-200) + +- Name: Accent 300
+ Slug: accent-300
+ Hex: #86EDC4
+ Variable: var(--wp--preset--color--accent-300) + +- Name: Accent 400
+ Slug: accent-400
+ Hex: #4FDEAA
+ Variable: var(--wp--preset--color--accent-400) + +- Name: Accent 500
+ Slug: accent-500
+ Hex: #22C78A
+ Variable: var(--wp--preset--color--accent-500) + +- Name: Accent 600
+ Slug: accent-600
+ Hex: #17A974
+ Variable: var(--wp--preset--color--accent-600) + +- Name: Accent 700
+ Slug: accent-700
+ Hex: #11865B
+ Variable: var(--wp--preset--color--accent-700) + +- Name: Accent 800
+ Slug: accent-800
+ Hex: #0B6243
+ Variable: var(--wp--preset--color--accent-800) + +- Name: Accent 900
+ Slug: accent-900
+ Hex: #063828
+ Variable: var(--wp--preset--color--accent-900) + +- Name: Accent Two 100
+ Slug: accent-two-100
+ Hex: #FFDDFB
+ Variable: var(--wp--preset--color--accent-two-100) + +- Name: Accent Two 200
+ Slug: accent-two-200
+ Hex: #FFB8F5
+ Variable: var(--wp--preset--color--accent-two-200) + +- Name: Accent Two 300
+ Slug: accent-two-300
+ Hex: #FF85EE
+ Variable: var(--wp--preset--color--accent-two-300) + +- Name: Accent Two 400
+ Slug: accent-two-400
+ Hex: #FF4FE3
+ Variable: var(--wp--preset--color--accent-two-400) + +- Name: Accent Two 500
+ Slug: accent-two-500
+ Hex: #FC00FC
+ Variable: var(--wp--preset--color--accent-two-500) + +- Name: Accent Two 600
+ Slug: accent-two-600
+ Hex: #D400D4
+ Variable: var(--wp--preset--color--accent-two-600) + +- Name: Accent Two 700
+ Slug: accent-two-700
+ Hex: #A600A6
+ Variable: var(--wp--preset--color--accent-two-700) + +- Name: Accent Two 800
+ Slug: accent-two-800
+ Hex: #760076
+ Variable: var(--wp--preset--color--accent-two-800) + +- Name: Accent Two 900
+ Slug: accent-two-900
+ Hex: #3F003F
+ Variable: var(--wp--preset--color--accent-two-900) + +- Name: Accent Three 100
+ Slug: accent-three-100
+ Hex: #E5FFE5
+ Variable: var(--wp--preset--color--accent-three-100) + +- Name: Accent Three 200
+ Slug: accent-three-200
+ Hex: #BEFFBE
+ Variable: var(--wp--preset--color--accent-three-200) + +- Name: Accent Three 300
+ Slug: accent-three-300
+ Hex: #8FFF8F
+ Variable: var(--wp--preset--color--accent-three-300) + +- Name: Accent Three 400
+ Slug: accent-three-400
+ Hex: #4FFF4F
+ Variable: var(--wp--preset--color--accent-three-400) + +- Name: Accent Three 500
+ Slug: accent-three-500
+ Hex: #00FC00
+ Variable: var(--wp--preset--color--accent-three-500) + +- Name: Accent Three 600
+ Slug: accent-three-600
+ Hex: #00D400
+ Variable: var(--wp--preset--color--accent-three-600) + +- Name: Accent Three 700
+ Slug: accent-three-700
+ Hex: #00A300
+ Variable: var(--wp--preset--color--accent-three-700) + +- Name: Accent Three 800
+ Slug: accent-three-800
+ Hex: #007000
+ Variable: var(--wp--preset--color--accent-three-800) + +- Name: Accent Three 900
+ Slug: accent-three-900
+ Hex: #003D00
+ Variable: var(--wp--preset--color--accent-three-900) + +- Name: Accent Four 100
+ Slug: accent-four-100
+ Hex: #FFFFDD
+ Variable: var(--wp--preset--color--accent-four-100) + +- Name: Accent Four 200
+ Slug: accent-four-200
+ Hex: #FFFFB8
+ Variable: var(--wp--preset--color--accent-four-200) + +- Name: Accent Four 300
+ Slug: accent-four-300
+ Hex: #FFFF85
+ Variable: var(--wp--preset--color--accent-four-300) + +- Name: Accent Four 400
+ Slug: accent-four-400
+ Hex: #FFFF4F
+ Variable: var(--wp--preset--color--accent-four-400) + +- Name: Accent Four 500
+ Slug: accent-four-500
+ Hex: #FCFC00
+ Variable: var(--wp--preset--color--accent-four-500) + +- Name: Accent Four 600
+ Slug: accent-four-600
+ Hex: #D4D400
+ Variable: var(--wp--preset--color--accent-four-600) + +- Name: Accent Four 700
+ Slug: accent-four-700
+ Hex: #A6A600
+ Variable: var(--wp--preset--color--accent-four-700) + +- Name: Accent Four 800
+ Slug: accent-four-800
+ Hex: #767600
+ Variable: var(--wp--preset--color--accent-four-800) + +- Name: Accent Four 900
+ Slug: accent-four-900
+ Hex: #3F3F00
+ Variable: var(--wp--preset--color--accent-four-900) + +- Name: Error Foreground
+ Slug: error-foreground
+ Hex: #EF4444
+ Variable: var(--wp--preset--color--error-foreground) + +- Name: Warning Foreground
+ Slug: warning-foreground
+ Hex: #F59E0B
+ Variable: var(--wp--preset--color--warning-foreground) + +- Name: Information Foreground
+ Slug: information-foreground
+ Hex: #3B82F6
+ Variable: var(--wp--preset--color--information-foreground) + +- Name: Success Foreground
+ Slug: success-foreground
+ Hex: #10B981
+ Variable: var(--wp--preset--color--success-foreground) diff --git a/.github/tasks/task-list.md b/.github/tasks/task-list.md index 70b329d..7d3edd0 100644 --- a/.github/tasks/task-list.md +++ b/.github/tasks/task-list.md @@ -20,6 +20,7 @@ Update this file as tasks are created, started, or completed. ## Development +- [ ] Execute the detailed Figma Make implementation plan in `.github/tasks/2026-04-07-figma-make-implementation-checklist.md` - [ ] Build `parts/header.html` - [ ] Build `parts/footer.html` - [ ] Build `templates/index.html` diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bd99a7..cb453e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,15 +11,29 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Registered the theme font-family presets as `body`, `heading`, and `monospace`, and applied the `monospace` preset to code elements in `theme.json`. - Added a GSAP asset bootstrap in `inc/gsap.php` for class-based interactive effects. - Added a GSAP-driven `is-style-card-spotlight` group effect using theme surface and accent colours. - Added usage documentation for the spotlight card class. - Added a registered `Card Spotlight` Group block style for easy editor application. - Added a CSS-only sliding icon treatment for the core outline button variation. +- Added a GSAP-powered front-page hero with rotating proof points, interactive network background, and primary / outline CTAs. +- Added a dedicated `front-page.html` template that renders the marketing hero before editable page content. ### Changed +- Enabled root-padding-aware alignments, added theme typography writing-mode support, and applied a default spacing-20 horizontal page gutter in `theme.json`. +- Moved block-style visual tokens into `theme.json` and `styles/blocks/**/*.json`, leaving `assets/css/animations.css` as the interaction layer for the heading, link, and button treatments. +- Re-aligned the home hero GSAP wiring to the reusable `Home Hero Section` block style and dropped the abandoned cycling heading path. +- Moved theme and heading line heights in `theme.json` onto shared custom tokens, with H1 using a tighter value and H2 through H6 sharing a common heading rhythm. - Refined the GSAP spotlight card glow alignment and switched the card shell to a lighter theme palette. +- Refined the GSAP front-page hero so the network background sits behind the headline, responds more directly to pointer movement, and swaps words with a right-to-left character stagger. +- Reduced the default H1 weight in `theme.json` and rebuilt the hero word loop so longer words no longer clip, overlap, or reset with a blank frame. +- Fixed the homepage template so sites using `show_on_front = posts` render the posts query beneath the hero instead of an empty static-page `post-content` block. +- Tightened the hero word-stage measurement, removed the empty transition frame, and added smaller-screen layout rules so the hero scales more cleanly on mobile. +- Softened the hero word transition so the letters stagger vertically from right to left without the word shifting too far sideways during the swap. +- Replaced the hero's stacked-word repeat timeline with a two-layer word controller so the active word sits slightly higher and the loop no longer starts with an empty frame. +- Added a subtle character gap to the animated hero word so the rotating terms read a little more cleanly. - Simplified the spotlight effect configuration so live tuning happens directly in `assets/css/gsap-animations.css`. - Moved GSAP-specific spotlight styling from `assets/css/animations.css` to `assets/css/gsap-animations.css`. - Removed glow hover styling from default and outline buttons so only the dedicated glow button style blooms. diff --git a/assets/css/animations.css b/assets/css/animations.css index 3ca5dac..6ac6d91 100644 --- a/assets/css/animations.css +++ b/assets/css/animations.css @@ -1,6 +1,6 @@ -/********** Text **********/ +/********** Text Motion **********/ -/* Gradient Text: Gradient Accent */ +/* Gradient Accent */ @keyframes ls-gradient-text-clip { to { background-position: var(--ls-gradient-end-position, 100%) center; @@ -62,17 +62,22 @@ } } -/********** Links **********/ -/* Paragraph Link: Link Underline Accent */ +/********** Link Motion **********/ + +/* Link Underline Accent */ .wp-block-paragraph.is-style-link-underline-accent a { - text-decoration: none; - padding-bottom: 5px; - background-image: linear-gradient(var(--wp--preset--color--brand-500), - var(--wp--preset--color--accent-500)); + padding-bottom: var(--ls-link-underline-padding-bottom, 5px); + background-image: var( + --ls-link-underline-image, + linear-gradient( + var(--wp--preset--color--brand-500), + var(--wp--preset--color--accent-500) + ) + ); background-position: 0 100%; background-repeat: no-repeat; - background-size: 0 2px; + background-size: 0 var(--ls-link-underline-thickness, 2px); transition: background-size 220ms ease, color 220ms ease; transition-delay: 0s; } @@ -83,10 +88,11 @@ .wp-block-paragraph.is-style-link-underline-accent a:hover, .wp-block-paragraph.is-style-link-underline-accent a:focus-visible { - background-size: 100% 2px; + background-size: 100% var(--ls-link-underline-thickness, 2px); } -/********** Buttons **********/ + +/********** Button Motion **********/ .wp-block-button:not([class*="is-style-"]), .wp-block-button.is-style-fill, @@ -94,7 +100,7 @@ max-inline-size: 100%; } -/* Shared Button Transition */ +/* Shared button motion primitives */ .wp-element-button, .wp-block-button__link { transition: @@ -105,23 +111,13 @@ outline-color 220ms ease, outline-offset 220ms ease, transform 180ms ease; - transition-delay: 0s; - box-shadow: none; - outline-offset: 0; - text-shadow: none; -} - - -.wp-element-button:hover, -.wp-block-button__link:hover { - transition-delay: 0s; + transition-delay: 80ms; } .wp-element-button:hover, .wp-element-button:focus-visible, .wp-block-button__link:hover, .wp-block-button__link:focus-visible { - box-shadow: none; outline-offset: 0; } @@ -130,9 +126,12 @@ transform: scale(var(--ls-button-active-scale, 0.98)); } -/* Default Fill Button */ -.wp-block-button:not([class*="is-style-"]) .wp-block-button__link, -.wp-block-button.is-style-fill .wp-block-button__link { +/* Shared button shell for the default fill and outline treatments. */ +:is( + .wp-block-button:not([class*="is-style-"]), + .wp-block-button.is-style-fill, + .wp-block-button.is-style-outline +) .wp-block-button__link { position: relative; display: inline-flex; align-items: center; @@ -141,24 +140,43 @@ white-space: nowrap; overflow: hidden; isolation: isolate; +} + +/* Fill button motion */ +:is( + .wp-block-button:not([class*="is-style-"]), + .wp-block-button.is-style-fill +) .wp-block-button__link { + --ls-button-fill-icon-well-size: 3rem; + --ls-button-fill-icon-inline-end: 0.625rem; + --ls-button-fill-icon-font-size: 1.25rem; + --ls-button-fill-icon-block-inset: calc( + 50% - (var(--ls-button-fill-icon-well-size) / 2) + ); + --ls-button-fill-icon-inline-start: calc( + 100% - var(--ls-button-fill-icon-well-size) - var(--ls-button-fill-icon-inline-end) + ); background: transparent; border: 0; - color: var(--ls-button-fill-text, var(--wp--preset--color--base)); transition: transform var(--ls-button-fill-duration, 500ms) cubic-bezier(0.4, 0, 0.2, 1), color var(--ls-button-fill-duration, 500ms) cubic-bezier(0.4, 0, 0.2, 1); - transition-delay: 0s; } -.wp-block-button:not([class*="is-style-"]) .wp-block-button__link::before, -.wp-block-button.is-style-fill .wp-block-button__link::before { +:is( + .wp-block-button:not([class*="is-style-"]), + .wp-block-button.is-style-fill +) .wp-block-button__link::before { content: ""; position: absolute; inset: 0; border-radius: inherit; - background: var(--ls-button-fill-background, var(--wp--preset--color--brand-500)); + background: var( + --ls-button-fill-background, + var(--wp--preset--color--brand-500) + ); transition: inset-inline-start 350ms cubic-bezier(0.4, 0, 0.2, 1), @@ -170,211 +188,121 @@ cubic-bezier(0.4, 0, 0.2, 1), border-radius 350ms cubic-bezier(0.4, 0, 0.2, 1); - transition-delay: 0s; - pointer-events: none; z-index: -1; } -.wp-block-button:not([class*="is-style-"]) .wp-block-button__link::after, -.wp-block-button.is-style-fill .wp-block-button__link::after { +:is( + .wp-block-button:not([class*="is-style-"]), + .wp-block-button.is-style-fill +) .wp-block-button__link::after { content: "\2192"; position: absolute; - inset-block-start: calc( - 50% - (var(--ls-button-fill-icon-well-size, 3rem) / 2) - ); - inset-block-end: calc( - 50% - (var(--ls-button-fill-icon-well-size, 3rem) / 2) - ); - inset-inline-end: 0.625rem; - width: var(--ls-button-fill-icon-well-size, 3rem); + inset-block: var(--ls-button-fill-icon-block-inset); + inset-inline-end: var(--ls-button-fill-icon-inline-end); + width: var(--ls-button-fill-icon-well-size); display: grid; place-items: center; - color: var(--ls-button-fill-icon-colour, var(--wp--preset--color--base)); - font-size: 1.25rem; + color: var(--ls-button-fill-icon-colour, currentColor); + font-size: var(--ls-button-fill-icon-font-size); font-weight: 700; line-height: 1; transition: color 500ms cubic-bezier(0.4, 0, 0.2, 1); - pointer-events: none; } -.wp-block-button:not([class*="is-style-"]) .wp-block-button__link:hover, -.wp-block-button:not([class*="is-style-"]) .wp-block-button__link:hover::before, -.wp-block-button.is-style-fill .wp-block-button__link:hover, -.wp-block-button.is-style-fill .wp-block-button__link:hover::before { +:is( + .wp-block-button:not([class*="is-style-"]), + .wp-block-button.is-style-fill +) .wp-block-button__link:hover, +:is( + .wp-block-button:not([class*="is-style-"]), + .wp-block-button.is-style-fill +) .wp-block-button__link:hover::before { transition-delay: var(--ls-button-fill-enter-delay, 80ms); } -.wp-block-button:not([class*="is-style-"]) .wp-block-button__link:hover::before, -.wp-block-button:not([class*="is-style-"]) - .wp-block-button__link:focus-visible::before, -.wp-block-button.is-style-fill .wp-block-button__link:hover::before, -.wp-block-button.is-style-fill .wp-block-button__link:focus-visible::before { - inset-block-start: calc( - 50% - (var(--ls-button-fill-icon-well-size, 3rem) / 2) - ); - inset-inline-end: 0.625rem; - inset-block-end: calc( - 50% - (var(--ls-button-fill-icon-well-size, 3rem) / 2) - ); - inset-inline-start: calc( - 100% - var(--ls-button-fill-icon-well-size, 3rem) - 0.625rem - ); - border-radius: var(--wp--preset--border-radius--200); +:is( + .wp-block-button:not([class*="is-style-"]), + .wp-block-button.is-style-fill +) .wp-block-button__link:hover::before, +:is( + .wp-block-button:not([class*="is-style-"]), + .wp-block-button.is-style-fill +) .wp-block-button__link:focus-visible::before { + inset-block: var(--ls-button-fill-icon-block-inset); + inset-inline-end: var(--ls-button-fill-icon-inline-end); + inset-inline-start: var(--ls-button-fill-icon-inline-start); + border-radius: inherit; } -.wp-block-button:not([class*="is-style-"]) .wp-block-button__link:hover, -.wp-block-button:not([class*="is-style-"]) - .wp-block-button__link:focus-visible, -.wp-block-button.is-style-fill .wp-block-button__link:hover, -.wp-block-button.is-style-fill .wp-block-button__link:focus-visible { +:is( + .wp-block-button:not([class*="is-style-"]), + .wp-block-button.is-style-fill +) .wp-block-button__link:hover, +:is( + .wp-block-button:not([class*="is-style-"]), + .wp-block-button.is-style-fill +) .wp-block-button__link:focus-visible { color: var(--ls-button-fill-hover-text, var(--wp--preset--color--contrast)); } -.wp-block-button:not([class*="is-style-"]) .wp-block-button__link:active, -.wp-block-button.is-style-fill .wp-block-button__link:active { - transform: scale(0.98); -} - -/* Outline Button */ +/* Outline button motion */ .wp-block-button.is-style-outline .wp-block-button__link { - position: relative; - display: inline-flex; - align-items: center; - box-sizing: border-box; - max-inline-size: 100%; - white-space: nowrap; - overflow: hidden; - isolation: isolate; - border: 2px solid var(--wp--preset--color--brand-500); - border-radius: var(--wp--preset--border-radius--200); - background-color: var(--wp--preset--color--base); - color: var(--wp--preset--color--contrast); + --ls-button-outline-icon-well-size: 3rem; + --ls-button-outline-icon-inset: 4px; + --ls-button-outline-icon-font-size: 1.25rem; + --ls-button-outline-hover-padding-start: 4rem; + --ls-button-outline-hover-padding-end: 1.5rem; + --ls-button-outline-icon-inline-start: calc( + 100% - var(--ls-button-outline-icon-well-size) - var(--ls-button-outline-icon-inset) + ); transition: padding-inline-start 500ms cubic-bezier(0.4, 0, 0.2, 1), padding-inline-end 500ms cubic-bezier(0.4, 0, 0.2, 1), - border-color 280ms ease, - color 280ms ease, - transform 180ms ease; - transition-delay: 0s; - box-shadow: none; + transform 500ms ease-in-out; } .wp-block-button.is-style-outline .wp-block-button__link::after { content: "\2192"; position: absolute; - inset-block: 4px; - inset-inline-end: 4px; - width: 3rem; + inset-block: var(--ls-button-outline-icon-inset); + inset-inline-end: var(--ls-button-outline-icon-inset); + width: var(--ls-button-outline-icon-well-size); display: grid; place-items: center; - border-radius: calc(var(--wp--preset--border-radius--200) - 2px); - background-color: var(--wp--preset--color--brand-500); - color: var(--wp--preset--color--base); - font-size: 1.25rem; + border-radius: var(--ls-button-outline-icon-radius, var(--wp--preset--border-radius--100)); + background-color: var( + --ls-button-outline-accent-background, + var(--wp--preset--color--brand-500) + ); + color: var(--ls-button-outline-accent-colour, var(--wp--preset--color--base)); + font-size: var(--ls-button-outline-icon-font-size); font-weight: 700; - line-height: 1.25; + line-height: 1; transition: inset-inline-end 500ms cubic-bezier(0.4, 0, 0.2, 1), background-color 280ms ease, color 280ms ease; - transition-delay: 0s; - pointer-events: none; z-index: 1; } .wp-block-button.is-style-outline .wp-block-button__link:hover, .wp-block-button.is-style-outline .wp-block-button__link:focus-visible { - padding-inline-start: 4rem; - padding-inline-end: 1.5rem; + padding-inline-start: var(--ls-button-outline-hover-padding-start); + padding-inline-end: var(--ls-button-outline-hover-padding-end); } .wp-block-button.is-style-outline .wp-block-button__link:hover::after, .wp-block-button.is-style-outline .wp-block-button__link:focus-visible::after { - inset-inline-end: calc(100% - 3rem - 4px); + inset-inline-end: var(--ls-button-outline-icon-inline-start); } -@media (max-width: 680px) { - .wp-block-button:not([class*="is-style-"]) .wp-block-button__link, - .wp-block-button.is-style-fill .wp-block-button__link { - --ls-button-fill-icon-well-size: 2.75rem; - max-inline-size: 100%; - white-space: normal; - text-wrap: pretty; - font-size: 0.95rem; - line-height: 1.35; - padding-top: 0.875rem; - padding-right: 3.5rem; - padding-bottom: 0.875rem; - padding-left: 1rem; - } - - .wp-block-button:not([class*="is-style-"]) .wp-block-button__link::after, - .wp-block-button.is-style-fill .wp-block-button__link::after { - inset-block-start: calc( - 50% - (var(--ls-button-fill-icon-well-size, 2.75rem) / 2) - ); - inset-block-end: calc( - 50% - (var(--ls-button-fill-icon-well-size, 2.75rem) / 2) - ); - inset-inline-end: 0.5rem; - width: var(--ls-button-fill-icon-well-size, 2.75rem); - font-size: 1.125rem; - } - - .wp-block-button:not([class*="is-style-"]) .wp-block-button__link:hover::before, - .wp-block-button:not([class*="is-style-"]) - .wp-block-button__link:focus-visible::before, - .wp-block-button.is-style-fill .wp-block-button__link:hover::before, - .wp-block-button.is-style-fill .wp-block-button__link:focus-visible::before { - inset-block-start: calc( - 50% - (var(--ls-button-fill-icon-well-size, 2.75rem) / 2) - ); - inset-inline-end: 0.5rem; - inset-block-end: calc( - 50% - (var(--ls-button-fill-icon-well-size, 2.75rem) / 2) - ); - inset-inline-start: calc( - 100% - var(--ls-button-fill-icon-well-size, 2.75rem) - 0.5rem - ); - } - .wp-block-button.is-style-outline .wp-block-button__link { - max-inline-size: 100%; - white-space: normal; - text-wrap: pretty; - font-size: 0.95rem; - line-height: 1.35; - padding-top: 0.875rem; - padding-right: 3.5rem; - padding-bottom: 0.875rem; - padding-left: 1rem; - } - - .wp-block-button.is-style-outline .wp-block-button__link::after { - inset-block: 3px; - inset-inline-end: 3px; - width: 2.75rem; - font-size: 1.125rem; - } - - .wp-block-button.is-style-outline .wp-block-button__link:hover, - .wp-block-button.is-style-outline .wp-block-button__link:focus-visible { - padding-inline-start: 3.5rem; - padding-inline-end: 1rem; - } - - .wp-block-button.is-style-outline .wp-block-button__link:hover::after, - .wp-block-button.is-style-outline .wp-block-button__link:focus-visible::after { - inset-inline-end: calc(100% - 2.75rem - 3px); - } -} - -/* Button Glow: Button Glow Accent */ +/* Button Glow Accent */ .wp-block-button.is-style-button-glow-accent .wp-block-button__link { transition: box-shadow 900ms cubic-bezier(0.19, 1, 0.22, 1), @@ -383,33 +311,50 @@ transform 180ms ease; transition-delay: 0s; box-shadow: inset 0 0 20px - color-mix(in srgb, var(--wp--preset--color--brand-500) 0%, transparent); - outline: 1px solid - color-mix(in srgb, var(--wp--preset--color--brand-500) 45%, transparent); - outline-offset: 0; - text-shadow: none; + color-mix( + in srgb, + var(--ls-button-glow-colour, var(--wp--preset--color--brand-500)) + var(--ls-button-glow-resting-strength, 0%), + transparent + ); + outline: var(--ls-button-glow-outline-width, 1px) solid + color-mix( + in srgb, + var(--ls-button-glow-colour, var(--wp--preset--color--brand-500)) + var(--ls-button-glow-outline-strength, 45%), + transparent + ); } .wp-block-button.is-style-button-glow-accent .wp-block-button__link:hover { - transition-delay: 80ms; + transition-delay: var(--ls-button-glow-enter-delay, 80ms); } .wp-block-button.is-style-button-glow-accent .wp-block-button__link:hover, .wp-block-button.is-style-button-glow-accent .wp-block-button__link:focus-visible { - background-color: var(--wp--preset--color--brand-500); - color: var(--wp--preset--color--base); + background-color: var( + --ls-button-glow-hover-background, + var(--wp--preset--color--brand-500) + ); + color: var(--ls-button-glow-hover-text, var(--wp--preset--color--base)); box-shadow: inset 0 0 20px - color-mix(in srgb, var(--wp--preset--color--brand-500) 35%, transparent), + color-mix( + in srgb, + var(--ls-button-glow-colour, var(--wp--preset--color--brand-500)) + var(--ls-button-glow-inner-strength, 35%), + transparent + ), 0 0 20px - color-mix(in srgb, var(--wp--preset--color--brand-500) 20%, transparent); + color-mix( + in srgb, + var(--ls-button-glow-colour, var(--wp--preset--color--brand-500)) + var(--ls-button-glow-outer-strength, 20%), + transparent + ); outline-color: transparent; - outline-offset: 12px; -} - -.wp-block-button.is-style-button-glow-accent .wp-block-button__link:active { - transform: scale(0.98); + outline-offset: var(--ls-button-glow-outline-offset, 12px); } diff --git a/assets/css/gsap-animations.css b/assets/css/gsap-animations.css index d3c5c49..f153b4c 100644 --- a/assets/css/gsap-animations.css +++ b/assets/css/gsap-animations.css @@ -134,4 +134,113 @@ .is-style-card-spotlight::after { transition: none; } +} + +/* Home Hero Section: background-only Group block style. */ +.is-style-home-hero-section { + --ls-home-hero-surface: var(--wp--preset--color--base); + --ls-home-hero-brand: var(--wp--preset--color--brand-500); + --ls-home-hero-cta: var(--wp--preset--color--cta-500); + --ls-home-hero-accent: var(--wp--preset--color--accent-two-500); + position: relative; + overflow: hidden; + isolation: isolate; + background: + radial-gradient( + circle at 16% 14%, + color-mix(in srgb, var(--ls-home-hero-brand) 12%, transparent) 0%, + transparent 34% + ), + radial-gradient( + circle at 84% 18%, + color-mix(in srgb, var(--ls-home-hero-cta) 14%, transparent) 0%, + transparent 28% + ), + radial-gradient( + circle at 50% 100%, + color-mix(in srgb, var(--ls-home-hero-accent) 7%, transparent) 0%, + transparent 36% + ), + linear-gradient( + 180deg, + color-mix(in srgb, var(--ls-home-hero-surface) 98%, #fff 2%) 0%, + var(--ls-home-hero-surface) 100% + ); +} + +.is-style-home-hero-section > :not(.ls-home-hero-section__background) { + position: relative; + z-index: 1; +} + +.ls-home-hero-section__background, +.ls-home-hero-section__network { + position: absolute; + inset: 0; + pointer-events: none; + overflow: hidden; +} + +.ls-home-hero-section__background { + z-index: 0; +} + +.ls-home-hero-section__network { + z-index: 1; + opacity: 0.92; +} + +.ls-home-hero-section__orb { + position: absolute; + border-radius: 999px; + filter: blur(80px); + opacity: 0.8; + transform: translate3d( 0, 0, 0 ); + will-change: transform; + z-index: 0; +} + +.ls-home-hero-section__orb--brand { + top: 8%; + left: -8rem; + width: 24rem; + height: 24rem; + background: color-mix(in srgb, var(--ls-home-hero-brand) 24%, transparent); +} + +.ls-home-hero-section__orb--cta { + right: -6rem; + bottom: 10%; + width: 20rem; + height: 20rem; + background: color-mix(in srgb, var(--ls-home-hero-cta) 22%, transparent); +} + +.ls-home-hero-section__canvas { + display: block; + inline-size: 100%; + block-size: 100%; +} + +@media (max-width: 781px) { + .ls-home-hero-section__network { + opacity: 1; + } + + .ls-home-hero-section__orb { + filter: blur(64px); + opacity: 0.62; + } + + .ls-home-hero-section__orb--brand { + left: -10rem; + width: 18rem; + height: 18rem; + } + + .ls-home-hero-section__orb--cta { + right: -8rem; + width: 16rem; + height: 16rem; + } } \ No newline at end of file diff --git a/assets/fonts/lexend/Lexend-100-normal.woff2 b/assets/fonts/lexend/Lexend-100-normal.woff2 deleted file mode 100644 index 30013a4..0000000 Binary files a/assets/fonts/lexend/Lexend-100-normal.woff2 and /dev/null differ diff --git a/assets/fonts/roboto-mono/roboto-mono-latin-ext-wght-normal.woff2 b/assets/fonts/roboto-mono/roboto-mono-latin-ext-wght-normal.woff2 new file mode 100644 index 0000000..532a888 Binary files /dev/null and b/assets/fonts/roboto-mono/roboto-mono-latin-ext-wght-normal.woff2 differ diff --git a/assets/fonts/roboto-mono/roboto-mono-latin-wght-normal.woff2 b/assets/fonts/roboto-mono/roboto-mono-latin-wght-normal.woff2 new file mode 100644 index 0000000..bfa169c Binary files /dev/null and b/assets/fonts/roboto-mono/roboto-mono-latin-wght-normal.woff2 differ diff --git a/assets/js/gsap-effects.js b/assets/js/gsap-effects.js index 4b017ca..9a24df2 100644 --- a/assets/js/gsap-effects.js +++ b/assets/js/gsap-effects.js @@ -53,6 +53,388 @@ } ); } + function parseCssColour( value ) { + const trimmedValue = value.trim(); + + if ( /^#(?:[0-9a-f]{3}){1,2}$/i.test( trimmedValue ) ) { + let normalisedValue = trimmedValue.slice( 1 ); + + if ( 3 === normalisedValue.length ) { + normalisedValue = normalisedValue + .split( '' ) + .map( ( character ) => character + character ) + .join( '' ); + } + + return { + r: Number.parseInt( normalisedValue.slice( 0, 2 ), 16 ), + g: Number.parseInt( normalisedValue.slice( 2, 4 ), 16 ), + b: Number.parseInt( normalisedValue.slice( 4, 6 ), 16 ), + }; + } + + const rgbMatch = trimmedValue.match( /^rgba?\(\s*([0-9.]+)\s*,\s*([0-9.]+)\s*,\s*([0-9.]+)/i ); + + if ( rgbMatch ) { + return { + r: Number( rgbMatch[ 1 ] ), + g: Number( rgbMatch[ 2 ] ), + b: Number( rgbMatch[ 3 ] ), + }; + } + + return { + r: 30, + g: 106, + b: 255, + }; + } + + function mixColours( startColour, endColour, amount ) { + const clampedAmount = Math.min( 1, Math.max( 0, amount ) ); + + return { + r: Math.round( startColour.r + ( ( endColour.r - startColour.r ) * clampedAmount ) ), + g: Math.round( startColour.g + ( ( endColour.g - startColour.g ) * clampedAmount ) ), + b: Math.round( startColour.b + ( ( endColour.b - startColour.b ) * clampedAmount ) ), + }; + } + + function rgbaString( colour, alpha ) { + return `rgba(${ colour.r }, ${ colour.g }, ${ colour.b }, ${ alpha })`; + } + + function getDirectChildByClass( element, className ) { + return Array.from( element.children ).find( ( child ) => { + return child.classList.contains( className ); + } ) || null; + } + + function createEffectCanvas( network ) { + const existingCanvas = network.querySelector( '.ls-home-hero-section__canvas' ); + + if ( existingCanvas ) { + return existingCanvas; + } + + const canvas = document.createElement( 'canvas' ); + + canvas.className = 'ls-home-hero-section__canvas'; + canvas.setAttribute( 'aria-hidden', 'true' ); + network.appendChild( canvas ); + + return canvas; + } + + function ensureHomeHeroSectionBackground( section ) { + let background = getDirectChildByClass( section, 'ls-home-hero-section__background' ); + + if ( ! background ) { + background = document.createElement( 'div' ); + background.className = 'ls-home-hero-section__background'; + section.insertBefore( background, section.firstChild ); + } + + if ( ! background.querySelector( '.ls-home-hero-section__orb--brand' ) ) { + const brandOrb = document.createElement( 'div' ); + + brandOrb.className = 'ls-home-hero-section__orb ls-home-hero-section__orb--brand'; + background.appendChild( brandOrb ); + } + + if ( ! background.querySelector( '.ls-home-hero-section__orb--cta' ) ) { + const ctaOrb = document.createElement( 'div' ); + + ctaOrb.className = 'ls-home-hero-section__orb ls-home-hero-section__orb--cta'; + background.appendChild( ctaOrb ); + } + + let network = background.querySelector( '.ls-home-hero-section__network' ); + + if ( ! network ) { + network = document.createElement( 'div' ); + network.className = 'ls-home-hero-section__network'; + background.appendChild( network ); + } + + return network; + } + + function initHomeHeroSectionNetwork( section, reduceMotion, finePointer ) { + const network = ensureHomeHeroSectionBackground( section ); + const canvas = createEffectCanvas( network ); + const context = canvas.getContext( '2d' ); + + if ( ! context ) { + return () => {}; + } + + const rootStyles = getComputedStyle( document.documentElement ); + const brandColour = parseCssColour( rootStyles.getPropertyValue( '--wp--preset--color--brand-600' ) || rootStyles.getPropertyValue( '--wp--preset--color--brand-500' ) || '#1E6AFF' ); + const ctaColour = parseCssColour( rootStyles.getPropertyValue( '--wp--preset--color--cta-600' ) || rootStyles.getPropertyValue( '--wp--preset--color--cta-500' ) || '#00FCFC' ); + const interaction = { + x: 0, + y: 0, + strength: 0, + }; + const moveX = gsapInstance.quickTo( interaction, 'x', { + duration: reduceMotion ? 0 : 0.18, + ease: 'power3.out', + } ); + const moveY = gsapInstance.quickTo( interaction, 'y', { + duration: reduceMotion ? 0 : 0.18, + ease: 'power3.out', + } ); + const moveStrength = gsapInstance.quickTo( interaction, 'strength', { + duration: reduceMotion ? 0 : 0.16, + ease: 'power2.out', + } ); + const size = { + width: 0, + height: 0, + dpr: 1, + }; + let particles = []; + let resizeObserver = null; + + function isCompactViewport() { + return size.width <= 781; + } + + function createParticles() { + const compactViewport = isCompactViewport(); + const particleCount = reduceMotion + ? Math.min( compactViewport ? 24 : 20, Math.max( compactViewport ? 16 : 12, Math.round( ( size.width * size.height ) / ( compactViewport ? 44000 : 52000 ) ) ) ) + : Math.min( compactViewport ? 56 : 48, Math.max( compactViewport ? 28 : 22, Math.round( ( size.width * size.height ) / ( compactViewport ? 18000 : 24000 ) ) ) ); + + particles = Array.from( { length: particleCount }, ( value, index ) => { + const driftX = reduceMotion ? 0 : ( ( Math.random() - 0.5 ) * 0.26 ); + const driftY = reduceMotion ? 0 : ( ( Math.random() - 0.5 ) * 0.26 ); + const mix = 1 === particleCount ? 0.5 : ( index / ( particleCount - 1 ) ); + + return { + x: Math.random() * size.width, + y: Math.random() * size.height, + vx: driftX, + vy: driftY, + baseVx: driftX, + baseVy: driftY, + radius: 1.55 + ( Math.random() * 2.1 ), + mix, + seed: Math.random() * Math.PI * 2, + }; + } ); + } + + function resizeCanvas() { + const bounds = network.getBoundingClientRect(); + + size.width = Math.max( Math.round( bounds.width ), 1 ); + size.height = Math.max( Math.round( bounds.height ), 1 ); + size.dpr = Math.min( window.devicePixelRatio || 1, 1.5 ); + + canvas.width = size.width * size.dpr; + canvas.height = size.height * size.dpr; + canvas.style.width = `${ size.width }px`; + canvas.style.height = `${ size.height }px`; + + context.setTransform( 1, 0, 0, 1, 0, 0 ); + context.scale( size.dpr, size.dpr ); + createParticles(); + + if ( ! interaction.strength ) { + moveX( size.width / 2 ); + moveY( size.height * 0.35 ); + } + } + + function drawFrame( time ) { + const compactViewport = isCompactViewport(); + const connectionDistance = compactViewport + ? Math.min( 250, Math.max( 150, Math.min( size.width, size.height ) * 0.42 ) ) + : Math.min( 220, Math.max( 130, Math.min( size.width, size.height ) * 0.3 ) ); + const connectionDistanceSquared = connectionDistance * connectionDistance; + const influenceRadius = compactViewport + ? Math.max( 260, Math.min( size.width, size.height ) * 0.46 ) + : Math.max( 220, Math.min( size.width, size.height ) * 0.36 ); + + context.clearRect( 0, 0, size.width, size.height ); + + for ( let index = 0; index < particles.length; index += 1 ) { + const particle = particles[ index ]; + + if ( ! reduceMotion ) { + const deltaX = particle.x - interaction.x; + const deltaY = particle.y - interaction.y; + const distance = Math.max( Math.hypot( deltaX, deltaY ), 1 ); + + if ( finePointer && interaction.strength > 0.01 && distance < influenceRadius ) { + const force = ( 1 - ( distance / influenceRadius ) ) * 0.11 * interaction.strength; + + particle.vx += ( deltaX / distance ) * force; + particle.vy += ( deltaY / distance ) * force; + } + + particle.vx += ( particle.baseVx - particle.vx ) * 0.03; + particle.vy += ( particle.baseVy - particle.vy ) * 0.03; + particle.x += particle.vx; + particle.y += particle.vy; + + if ( particle.x <= 0 || particle.x >= size.width ) { + particle.baseVx *= -1; + particle.vx *= -0.92; + particle.x = Math.min( Math.max( particle.x, 0 ), size.width ); + } + + if ( particle.y <= 0 || particle.y >= size.height ) { + particle.baseVy *= -1; + particle.vy *= -0.92; + particle.y = Math.min( Math.max( particle.y, 0 ), size.height ); + } + } + } + + for ( let sourceIndex = 0; sourceIndex < particles.length; sourceIndex += 1 ) { + for ( let targetIndex = sourceIndex + 1; targetIndex < particles.length; targetIndex += 1 ) { + const sourceParticle = particles[ sourceIndex ]; + const targetParticle = particles[ targetIndex ]; + const deltaX = sourceParticle.x - targetParticle.x; + const deltaY = sourceParticle.y - targetParticle.y; + const distanceSquared = ( deltaX * deltaX ) + ( deltaY * deltaY ); + + if ( distanceSquared > connectionDistanceSquared ) { + continue; + } + + const distance = Math.sqrt( distanceSquared ); + const connectionStrength = 1 - ( distance / connectionDistance ); + const lineColour = mixColours( + brandColour, + ctaColour, + ( ( sourceParticle.mix + targetParticle.mix ) / 2 ) + ( Math.sin( time + sourceParticle.seed + targetParticle.seed ) * 0.05 ) + ); + + context.beginPath(); + context.moveTo( sourceParticle.x, sourceParticle.y ); + context.lineTo( targetParticle.x, targetParticle.y ); + context.strokeStyle = rgbaString( + lineColour, + compactViewport + ? 0.2 + ( connectionStrength * 0.3 ) + ( interaction.strength * connectionStrength * 0.14 ) + : 0.13 + ( connectionStrength * 0.24 ) + ( interaction.strength * connectionStrength * 0.12 ) + ); + context.lineWidth = compactViewport + ? ( distance < ( connectionDistance * 0.4 ) ? 1.6 : 1.15 ) + : ( distance < ( connectionDistance * 0.4 ) ? 1.35 : 0.95 ); + context.stroke(); + } + } + + for ( let index = 0; index < particles.length; index += 1 ) { + const particle = particles[ index ]; + const dotColour = mixColours( + brandColour, + ctaColour, + particle.mix + ( Math.sin( time + particle.seed ) * 0.08 ) + ); + + context.beginPath(); + context.arc( particle.x, particle.y, particle.radius, 0, Math.PI * 2, false ); + context.fillStyle = rgbaString( + dotColour, + compactViewport + ? 0.84 + ( interaction.strength * 0.16 ) + : 0.72 + ( interaction.strength * 0.16 ) + ); + context.fill(); + } + } + + function handlePointerMove( event ) { + const bounds = network.getBoundingClientRect(); + const pointerX = event.clientX - bounds.left; + const pointerY = event.clientY - bounds.top; + + if ( pointerX < 0 || pointerY < 0 || pointerX > bounds.width || pointerY > bounds.height ) { + return; + } + + moveX( pointerX ); + moveY( pointerY ); + moveStrength( 1.2 ); + } + + function resetPointer() { + moveStrength( 0 ); + moveX( size.width / 2 ); + moveY( size.height * 0.35 ); + } + + resizeCanvas(); + + if ( window.ResizeObserver ) { + resizeObserver = new window.ResizeObserver( resizeCanvas ); + resizeObserver.observe( network ); + } else { + window.addEventListener( 'resize', resizeCanvas ); + } + + if ( finePointer && ! reduceMotion ) { + section.addEventListener( 'pointerenter', handlePointerMove ); + section.addEventListener( 'pointermove', handlePointerMove ); + section.addEventListener( 'pointerleave', resetPointer ); + } + + if ( reduceMotion ) { + drawFrame( 0 ); + } else { + gsapInstance.ticker.add( drawFrame ); + } + + return () => { + if ( resizeObserver ) { + resizeObserver.disconnect(); + } else { + window.removeEventListener( 'resize', resizeCanvas ); + } + + section.removeEventListener( 'pointerenter', handlePointerMove ); + section.removeEventListener( 'pointermove', handlePointerMove ); + section.removeEventListener( 'pointerleave', resetPointer ); + gsapInstance.ticker.remove( drawFrame ); + }; + } + + function initHomeHeroSection( section ) { + if ( section.dataset.lsHomeHeroSection === 'true' ) { + return; + } + + section.dataset.lsHomeHeroSection = 'true'; + + const media = gsapInstance.matchMedia ? gsapInstance.matchMedia( section ) : null; + + if ( ! media ) { + return; + } + + media.add( + { + reduceMotion: '(prefers-reduced-motion: reduce)', + finePointer: '(pointer: fine)', + }, + ( context ) => { + const reduceMotion = Boolean( context.conditions.reduceMotion ); + const finePointer = Boolean( context.conditions.finePointer ); + const teardownNetwork = initHomeHeroSectionNetwork( section, reduceMotion, finePointer ); + + return () => { + teardownNetwork(); + }; + } + ); + } + function setFocusState( card ) { const bounds = card.getBoundingClientRect(); @@ -118,6 +500,7 @@ function initEffects() { document.querySelectorAll( '.is-style-card-spotlight' ).forEach( initSpotlightCard ); + document.querySelectorAll( '.is-style-home-hero-section' ).forEach( initHomeHeroSection ); } function boot() { diff --git a/inc/animations.php b/inc/animations.php index d819ca2..453ee03 100644 --- a/inc/animations.php +++ b/inc/animations.php @@ -28,9 +28,6 @@ function ls_theme_get_local_asset_version( $path ) { /** * Returns effect stylesheet definitions. * - * Each effect can declare the contexts where it should load so the theme can - * later split or gate effects without changing the main bootstrap flow. - * * @param string $context Load context. Accepts 'front' or 'editor'. * @return array> */ diff --git a/inc/gsap.php b/inc/gsap.php index 5293b66..4d2cea3 100644 --- a/inc/gsap.php +++ b/inc/gsap.php @@ -143,6 +143,14 @@ function ls_theme_register_gsap_block_styles() { return; } + register_block_style( + 'core/group', + array( + 'name' => 'home-hero-section', + 'label' => __( 'Home Hero Section', 'ls-theme' ), + ) + ); + register_block_style( 'core/group', array( diff --git a/patterns/home-hero.php b/patterns/home-hero.php index cc5d4e2..7b89fa5 100644 --- a/patterns/home-hero.php +++ b/patterns/home-hero.php @@ -4,7 +4,19 @@ * Slug: ls-theme/hero * Categories: hero * Block Types: core/template-part/hero - * Description: A hero section for the homepage with a background image, title, and call-to-action button. + * Description: Minimal home hero section using the reusable GSAP section background style. */ -?> \ No newline at end of file +?> + + +
+ +
+ +




+ +
+ +
+ \ No newline at end of file diff --git a/style.css b/style.css index 4b4a824..2ad7025 100644 --- a/style.css +++ b/style.css @@ -13,3 +13,9 @@ License URI: https://www.gnu.org/licenses/gpl-2.0.html Text Domain: ls-theme Tags: block-theme, full-site-editing, custom-colors, custom-typography */ + +code, +pre { + font-family: var(--wp--preset--font-family--monospace); + font-size: var(--wp--preset--font-size--200); +} \ No newline at end of file diff --git a/styles/blocks/buttons/button-glow-accent.json b/styles/blocks/buttons/button-glow-accent.json index 9f49dbb..aff27ab 100644 --- a/styles/blocks/buttons/button-glow-accent.json +++ b/styles/blocks/buttons/button-glow-accent.json @@ -31,6 +31,6 @@ "fontWeight": "600", "letterSpacing": "0.08em" }, - "css": "&{--ls-button-glow-enter-delay: 80ms;}" + "css": "&{--ls-button-glow-colour:var(--wp--preset--color--brand-500);--ls-button-glow-hover-background:var(--wp--preset--color--brand-500);--ls-button-glow-hover-text:var(--wp--preset--color--base);--ls-button-glow-enter-delay:80ms;--ls-button-glow-outline-width:1px;--ls-button-glow-outline-offset:12px;--ls-button-glow-resting-strength:0%;--ls-button-glow-outline-strength:45%;--ls-button-glow-inner-strength:35%;--ls-button-glow-outer-strength:20%;--ls-button-active-scale:0.98;}" } } diff --git a/styles/blocks/headings/gradient-accent.json b/styles/blocks/headings/gradient-accent.json index 805866f..7d4ae0e 100644 --- a/styles/blocks/headings/gradient-accent.json +++ b/styles/blocks/headings/gradient-accent.json @@ -9,15 +9,15 @@ "description": "Animated gradient text for headings using the LightSpeed Theme accent presets.", "styles": { "color": { - "text": "var:preset|color|accent-500" + "text": "var:preset|color|brand-500" }, "elements": { "link": { "color": { - "text": "var:preset|color|accent-500" + "text": "var:preset|color|brand-500" } } }, - "css": "&{--ls-gradient-image: linear-gradient(to right, var(--wp--preset--color--accent-500) 0%, var(--wp--preset--color--contrast) 25%, var(--wp--preset--color--accent-500) 50%, var(--wp--preset--color--contrast) 75%, var(--wp--preset--color--accent-500) 100%); --ls-gradient-size: 200% auto; --ls-gradient-start-position: 0%; --ls-gradient-end-position: 100%; --ls-gradient-duration: 6s; --ls-gradient-timing: ease-in-out; --ls-gradient-direction: alternate; --ls-gradient-focus-color: var(--wp--preset--color--contrast);}" + "css": "&{--ls-gradient-width:fit-content;--ls-gradient-image:linear-gradient(to right,var(--wp--preset--color--brand-500) 0%,var(--wp--preset--color--contrast) 25%,var(--wp--preset--color--brand-700) 50%,var(--wp--preset--color--contrast) 75%,var(--wp--preset--color--brand-500) 100%);--ls-gradient-size:200% auto;--ls-gradient-start-position:0%;--ls-gradient-end-position:100%;--ls-gradient-duration:6s;--ls-gradient-delay:0s;--ls-gradient-timing:ease-in-out;--ls-gradient-direction:alternate;--ls-gradient-focus-width:2px;--ls-gradient-focus-color:var(--wp--preset--color--contrast);--ls-gradient-focus-offset:4px;--ls-gradient-reduced-position:100%;}" } } diff --git a/styles/blocks/paragraphs/link-underline-accent.json b/styles/blocks/paragraphs/link-underline-accent.json index 5459fe1..16cd12f 100644 --- a/styles/blocks/paragraphs/link-underline-accent.json +++ b/styles/blocks/paragraphs/link-underline-accent.json @@ -18,6 +18,6 @@ } } }, - "css": "&{--ls-link-underline-enter-delay: 80ms;}" + "css": "&{--ls-link-underline-image:linear-gradient(var(--wp--preset--color--brand-500),var(--wp--preset--color--accent-500));--ls-link-underline-padding-bottom:5px;--ls-link-underline-thickness:2px;--ls-link-underline-enter-delay:80ms;}" } } diff --git a/styles/sections/home-hero-section.json b/styles/sections/home-hero-section.json new file mode 100644 index 0000000..19c4c96 --- /dev/null +++ b/styles/sections/home-hero-section.json @@ -0,0 +1,11 @@ +{ + "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "version": 3, + "title": "Home Hero Section", + "slug": "home-hero-section", + "blockTypes": [ + "core/group" + ], + "description": "Light full-width group style with the animated network background used for the homepage hero.", + "styles": {} +} \ No newline at end of file diff --git a/templates/front-page.html b/templates/front-page.html new file mode 100644 index 0000000..2415d6d --- /dev/null +++ b/templates/front-page.html @@ -0,0 +1,34 @@ + + + + + +
+ +
+ + +
+ + +
+ + + + + +

No posts found.

+ + + + + + + + +
+ +
+ + + \ No newline at end of file diff --git a/templates/home.html b/templates/home.html deleted file mode 100644 index 3ef6d44..0000000 --- a/templates/home.html +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/theme.json b/theme.json index cbe4c87..a32c28d 100644 --- a/theme.json +++ b/theme.json @@ -1,5 +1,5 @@ { - "$schema": "https://schemas.wp.org/wp/6.9/theme.json", + "$schema": "https://schemas.wp.org/trunk/theme.json", "version": 3, "settings": { "appearanceTools": true, @@ -473,20 +473,14 @@ }, "typography": { "defaultFontSizes": false, + "fluid": true, + "writingMode": true, "fontFamilies": [ { "name": "Lexend", "slug": "heading", "fontFamily": "Lexend, sans-serif", "fontFace": [ - { - "fontFamily": "Lexend", - "fontStyle": "normal", - "fontWeight": "100", - "src": [ - "file:./assets/fonts/lexend/Lexend-100-normal.woff2" - ] - }, { "fontFamily": "Lexend", "fontStyle": "normal", @@ -615,6 +609,31 @@ ] } ] + }, + { + "name": "Roboto Mono", + "slug": "monospace", + "fontFamily": "Roboto Mono, monospace", + "fontFace": [ + { + "fontFamily": "Roboto Mono", + "fontStyle": "normal", + "fontWeight": "100 700", + "unicodeRange": "U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF", + "src": [ + "file:./assets/fonts/roboto-mono/roboto-mono-latin-ext-wght-normal.woff2" + ] + }, + { + "fontFamily": "Roboto Mono", + "fontStyle": "normal", + "fontWeight": "100 700", + "unicodeRange": "U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD", + "src": [ + "file:./assets/fonts/roboto-mono/roboto-mono-latin-wght-normal.woff2" + ] + } + ] } ], "fontSizes": [ @@ -684,29 +703,36 @@ { "name": "Gigantic", "slug": "800", - "size": "4rem", + "size": "3.75rem", "fluid": { "min": "2.625rem", - "max": "4rem" + "max": "3.75rem" } }, { "name": "Colossal", "slug": "900", - "size": "5rem", + "size": "4.5rem", "fluid": { - "min": "3rem", - "max": "5rem" + "min": "2.75rem", + "max": "4.5rem" } } ] }, "custom": { - "lineHeight": { - "large-heading": "125%", - "small-heading": "135%", - "button": "130%", - "paragraph": "150%" + "line-height": { + "heading-snug": "1.1", + "heading-default": "1.25", + "heading-loose": "1.35", + "button": "1.3", + "paragraph": "1.5" + }, + "button-padding": { + "top": "1rem", + "right": "4rem", + "bottom": "1rem", + "left": "1.5rem" } }, "shadow": { @@ -778,9 +804,9 @@ "size": "9999px" } ] - } + }, + "useRootPaddingAwareAlignments": true }, - "blocks": {}, "styles": { "color": { "background": "var(--wp--preset--color--base)", @@ -789,11 +815,17 @@ "typography": { "fontFamily": "var(--wp--preset--font-family--body, system-ui, sans-serif)", "fontSize": "var(--wp--preset--font-size--200)", - "lineHeight": "1.6" + "lineHeight": "var(--wp--custom--line-height--paragraph)" }, "spacing": { - "blockGap": "var(--wp--preset--spacing--30)" - }, + "blockGap": "var(--wp--preset--spacing--30)", + "padding": { + "bottom": "0", + "left": "var(--wp--preset--spacing--20)", + "right": "var(--wp--preset--spacing--20)", + "top": "0" + } + }, "elements": { "button": { "color": { @@ -814,7 +846,8 @@ "fontSize": "var:preset|font-size|200", "fontWeight": "700", "letterSpacing": "0.08em" - } + }, + "css": "&{--ls-button-fill-background:var(--wp--preset--color--brand-500);--ls-button-fill-icon-colour:var(--wp--preset--color--base);--ls-button-fill-hover-text:var(--wp--preset--color--contrast);--ls-button-fill-duration:500ms;--ls-button-fill-enter-delay:80ms;--ls-button-active-scale:0.98;}" }, "link": { "color": { @@ -826,22 +859,52 @@ } } }, + "heading": { + "typography": { + "fontFamily": "var(--wp--preset--font-family--heading, sans-serif)" + } + }, "h1": { "typography": { - "fontSize": "var(--wp--preset--font-size--600)", - "lineHeight": "1.2" + "fontSize": "var(--wp--preset--font-size--900)", + "fontWeight": "700", + "lineHeight": "var(--wp--custom--line-height--heading-snug)" } }, "h2": { "typography": { - "fontSize": "var(--wp--preset--font-size--500)", - "lineHeight": "1.25" + "fontSize": "var(--wp--preset--font-size--700)", + "fontWeight": "600", + "lineHeight": "var(--wp--custom--line-height--heading-default)" } }, "h3": { + "typography": { + "fontSize": "var(--wp--preset--font-size--500)", + "fontWeight": "500", + "lineHeight": "var(--wp--custom--line-height--heading-default)" + } + }, + "h4": { "typography": { "fontSize": "var(--wp--preset--font-size--400)", - "lineHeight": "1.3" + "fontWeight": "500", + "lineHeight": "var(--wp--custom--line-height--heading-loose)" + } + }, + "h5": { + "typography": { + "fontSize": "var(--wp--preset--font-size--300)", + "fontWeight": "500", + "lineHeight": "var(--wp--custom--line-height--heading-loose)" + } + }, + "h6": { + "typography": { + "fontSize": "var(--wp--preset--font-size--300)", + "fontWeight": "500", + "lineHeight": "var(--wp--custom--line-height--heading-default)", + "textDecoration": "uppercase" } } }, @@ -850,6 +913,9 @@ "variations": { "outline": { "border": { + "color": "var:preset|color|brand-500", + "style": "solid", + "width": "2px", "radius": "var:preset|border-radius|200" }, "color": { @@ -868,7 +934,8 @@ "fontSize": "var:preset|font-size|200", "fontWeight": "700", "letterSpacing": "0.08em" - } + }, + "css": "&{--ls-button-outline-accent-background:var(--wp--preset--color--brand-500);--ls-button-outline-accent-colour:var(--wp--preset--color--base);--ls-button-outline-icon-radius:var(--wp--preset--border-radius--100);}" } } }