`
+- Use `.ps-container` for consistent max-width
+- Use existing component classes (`.ps-card`, `.ps-btn`, etc.)
+- Keep templates under 150 lines; extract complex parts to `template-parts/`
+
+### How to Add a New Plugin Integration
+
+**Scenario:** Integrate a new plugin (e.g., "Research Database") via shortcode
+
+1. **In front-page.php**, add a conditional shortcode block:
+ ```php
+
+
+
+ ```
+
+2. **In functions.php**, optionally add inline overrides if plugin CSS needs adjustment:
+ ```php
+ function peptide_starter_plugin_overrides() {
+ wp_add_inline_style( 'peptide-starter-style', '
+ /* Override plugin styles here */
+ .rdb-card { /* example */ }
+ ' );
+ }
+ add_action( 'wp_enqueue_scripts', 'peptide_starter_plugin_overrides', 99 );
+ ```
+
+3. **Document the integration** in CLAUDE.md:
+ - Plugin namespace (e.g., `.rdb-*`)
+ - Shortcode name and parameters
+ - Expected styling classes
+
+4. **If plugin needs dark mode coordination:**
+ - Ask plugin author to listen to `themechange` event (see ARCHITECTURE.md)
+ - Or have plugin read `html[data-theme]` attribute
+ - Provide plugin with CSS custom properties: `getComputedStyle(document.documentElement).getPropertyValue('--text-primary')`
+
+5. **Test:**
+ - Activate plugin and visit front page
+ - Verify shortcode renders
+ - Toggle dark mode; verify plugin responds
+ - Deactivate plugin; verify page still renders (fallback gracefully)
+
+**Important:** Always wrap shortcodes in `shortcode_exists()` checks so theme doesn't break if plugin is missing.
+
+### How to Add a New CSS Component
+
+**Scenario:** Create a new "pill" button style (small, rounded, inline)
+
+1. **In style.css**, find the Components section (around line 500)
+
+2. **Add new component class:**
+ ```css
+ /* Pill buttons */
+ .ps-btn-pill {
+ display: inline-block;
+ padding: var(--spacing-xs) var(--spacing-sm);
+ border-radius: 9999px;
+ font-size: 12px;
+ font-weight: 600;
+ text-transform: uppercase;
+ letter-spacing: 0.5px;
+ }
+
+ .ps-btn-pill.ps-btn-primary {
+ background-color: var(--color-primary);
+ color: white;
+ }
+
+ .ps-btn-pill.ps-btn-secondary {
+ background-color: transparent;
+ border: 1px solid var(--color-primary);
+ color: var(--color-primary);
+ }
+ ```
+
+3. **Add dark mode support** (in Dark Mode section, around line 1200):
+ ```css
+ html[data-theme="dark"] .ps-btn-pill.ps-btn-secondary {
+ border-color: var(--color-primary-dark);
+ color: var(--color-primary-dark);
+ }
+ ```
+
+4. **Add responsive sizes if needed** (in Responsive section, around line 1400):
+ ```css
+ @media (max-width: 767px) {
+ .ps-btn-pill {
+ padding: var(--spacing-xs) var(--spacing-xs);
+ }
+ }
+ ```
+
+5. **Usage in templates:**
+ ```html
+ Beta
+ ```
+
+6. **Test:**
+ - Light mode: verify colors, sizing, alignment
+ - Dark mode: toggle and verify contrast
+ - Mobile (480px): verify responsive adjustments
+ - Keyboard: focus state should be visible
+
+**Best practices:**
+- Use CSS variables (`var(--spacing-*)`, `var(--color-*)`) not hardcoded values
+- Avoid `!important` unless absolutely necessary
+- Include dark mode support immediately (no `.ps-*` is light-only)
+- Group related rules with comments
+- Keep component definitions self-contained (<100 lines)
+
+### How to Add a New Customizer Setting
+
+**Scenario:** Add a new "Primary Accent Color" customizer option
+
+1. **In functions.php** (around line 143), add a new section:
+ ```php
+ $wp_customize->add_section( 'peptide_starter_colors', array(
+ 'title' => esc_html__( 'Colors', 'peptide-starter' ),
+ 'priority' => 45,
+ ) );
+ ```
+
+2. **Add a setting:**
+ ```php
+ $wp_customize->add_setting( 'primary_accent_color', array(
+ 'default' => '#0066CC',
+ 'transport' => 'postMessage',
+ 'sanitize_callback' => 'sanitize_hex_color',
+ ) );
+ ```
+
+3. **Add a control:**
+ ```php
+ $wp_customize->add_control( new WP_Customize_Color_Control(
+ $wp_customize,
+ 'primary_accent_color',
+ array(
+ 'label' => esc_html__( 'Primary Accent Color', 'peptide-starter' ),
+ 'section' => 'peptide_starter_colors',
+ 'settings' => 'primary_accent_color',
+ )
+ ) );
+ ```
+
+4. **Create a getter function:**
+ ```php
+ function peptide_starter_get_primary_accent_color() {
+ return get_theme_mod( 'primary_accent_color', '#0066CC' );
+ }
+ ```
+
+5. **Output in front-end** (e.g., in footer.php):
+ ```php
+
+ ```
+
+ Or better, use inline style in `wp_head`:
+ ```php
+ function peptide_starter_custom_colors() {
+ $accent = peptide_starter_get_primary_accent_color();
+ ?>
+
+ 'postMessage'` — Instant preview (needs JS listener)
+- `'transport' => 'refresh'` — Full page refresh
+
+For color/text changes, use `postMessage` with a JS listener in theme.js:
+```javascript
+wp_customize.bind( 'setting:primary_accent_color', function( setting ) {
+ setting.bind( function( newval ) {
+ document.documentElement.style.setProperty('--color-accent', newval);
+ });
+});
+```
+
+## Error Handling Patterns
+
+### Theme Doesn't Break If Plugin Missing
+
+**Pattern: Graceful Degradation**
+```php
+// Good — shortcode_exists check
+if ( shortcode_exists( 'peptide_search' ) ) {
+ echo do_shortcode( '[peptide_search]' );
+} else {
+ get_search_form(); // Fallback to WordPress default
+}
+
+// Bad — assumes plugin exists
+echo do_shortcode( '[peptide_search]' ); // Renders [peptide_search] as text if missing
+```
+
+### Menu Fallback
+
+**In header.php:**
+```php
+wp_nav_menu( array(
+ 'theme_location' => 'primary',
+ 'fallback_cb' => 'peptide_starter_primary_menu_fallback', // Function defined in header
+ 'walker' => new Peptide_Starter_Nav_Walker(),
+) );
+
+function peptide_starter_primary_menu_fallback() {
+ // Renders Home, About, Peptides links if no menu assigned
+}
+```
+
+### Widget Area Check
+
+**In footer.php:**
+```php
+if ( is_active_sidebar( 'footer-1' ) ) {
+ dynamic_sidebar( 'footer-1' );
+} else {
+ // Render default content
+ echo '' . esc_html__( 'About', 'peptide-starter' ) . '
';
+}
+```
+
+### Class Existence Check
+
+**For WooCommerce:**
+```php
+if ( class_exists( 'WooCommerce' ) ) {
+ // Render cart icon
+}
+```
+
+**For post types:**
+```php
+if ( post_type_exists( 'peptide' ) ) {
+ echo '' . __( 'Peptides' ) . '';
+}
+```
+
+### Input Validation
+
+All user-facing output must be escaped:
+
+```php
+// Good
+echo esc_html( get_the_title() );
+echo esc_url( home_url( '/' ) );
+echo esc_attr( $html_attribute_value );
+
+// Bad
+echo get_the_title();
+echo home_url( '/' );
+```
+
+## Dark Mode Implementation Guide
+
+### How Dark Mode Works in Peptide Starter
+
+1. **Inline script in `wp_head`** (functions.php, line 406-422)
+ - Runs immediately before CSS loads
+ - Prevents white flash by setting `html[data-theme]` early
+ - Checks in order: localStorage → system pref → customizer default
+
+2. **CSS selectors** (style.css, line ~1200 "Dark Mode")
+ - Light mode: default colors in `:root`
+ - Dark mode: `html[data-theme="dark"]` selector overrides
+
+3. **JavaScript listener** (theme.js, line 47-63)
+ - Responds to dark mode toggle button
+ - Updates localStorage
+ - Dispatches `themechange` event to plugins
+ - Updates sun/moon icon visibility
+
+### Adding Dark Mode to a New Component
+
+**Example: New Alert Style**
+
+1. **Define light mode in CSS:**
+ ```css
+ .ps-alert-custom {
+ padding: var(--spacing-md);
+ background-color: #E3F2FD; /* Light blue */
+ color: #0D47A1; /* Dark blue text */
+ border: 1px solid #90CAF9;
+ }
+ ```
+
+2. **Add dark mode override:**
+ ```css
+ html[data-theme="dark"] .ps-alert-custom {
+ background-color: #1A237E; /* Dark blue bg */
+ color: #E3F2FD; /* Light text */
+ border-color: #3F51B5; /* Darker border */
+ }
+ ```
+
+3. **Test:**
+ - Load page in light mode → verify colors
+ - Toggle dark mode → verify override colors are applied
+ - Open DevTools → verify `html[data-theme="dark"]` attribute set
+ - Check localStorage `peptide-starter-theme` is updated
+
+### Helping Plugins Support Dark Mode
+
+**If a plugin doesn't listen to dark mode changes:**
+
+1. Ask plugin author to listen to the `themechange` event:
+ ```javascript
+ document.addEventListener('themechange', (e) => {
+ const theme = e.detail.theme;
+ // Update plugin styles based on theme
+ });
+ ```
+
+2. Or use a MutationObserver to watch for `data-theme` changes:
+ ```javascript
+ const observer = new MutationObserver(() => {
+ const theme = document.documentElement.getAttribute('data-theme');
+ // Update styles
+ });
+ observer.observe(document.documentElement, { attributes: true });
+ ```
+
+3. Or read CSS variables in the plugin stylesheet:
+ ```css
+ .plugin-card {
+ color: var(--text-primary);
+ background-color: var(--bg-secondary);
+ }
+ ```
+
+### CSS Variables for Dark Mode
+
+All available variables (defined in `:root`):
+
+```css
+--text-primary /* Main text (light: #111827, dark: #F9FAFB) */
+--text-secondary /* Secondary text (light: #6B7280, dark: #D1D5DB) */
+--bg-primary /* Main background (light: #FFFFFF, dark: #111827) */
+--bg-secondary /* Secondary bg (light: #F3F4F6, dark: #1F2937) */
+--color-primary /* Primary accent (light: #0066CC, dark: #3B82F6) */
+--border-color /* Border color (light: #E5E7EB, dark: #374151) */
+```
+
+## Testing Checklist
+
+When modifying the theme, verify:
+
+- [ ] **Light mode** — All text readable, colors correct
+- [ ] **Dark mode** — Toggle to dark, verify colors swap, no white flash on reload
+- [ ] **Mobile** (480px) — Navigation collapses, search/dark mode icons present
+- [ ] **Tablet** (768px) — Layout adapts, footer 2-column if needed
+- [ ] **Desktop** (1024px+) — Full layout renders correctly
+- [ ] **Plugins active** — Shortcodes render, no JS errors in console
+- [ ] **Plugins inactive** — Graceful fallbacks work (search form, no broken layout)
+- [ ] **Accessibility** — Tab through page, all interactive elements reachable
+- [ ] **Focus states** — Every button/link has visible focus outline
+- [ ] **Keyboard navigation** — Escape closes overlays, arrow keys in menu if relevant
+
+## Common Tasks & Commands
+
+**Check JavaScript syntax:**
+```bash
+node --check assets/js/theme.js
+node --check assets/js/navigation.js
+```
+
+**View theme version:**
+```php
+echo PEPTIDE_STARTER_VERSION; // Currently: 1.3.1
+```
+
+**Update theme version (when releasing):**
+1. Edit `style.css` line 7: `Version: X.Y.Z`
+2. Edit `functions.php` line 14: `define( 'PEPTIDE_STARTER_VERSION', 'X.Y.Z' )`
+
+**Deploy to production:**
+- Push to `main` branch on GitHub
+- GitHub Actions runs rsync to Hostinger via SSH
+- LiteSpeed cache clears automatically
+
+**Debug active plugins:**
+```php
+// In functions.php or template
+$active = get_option( 'active_plugins' );
+error_log( print_r( $active, true ) );
+```
+
+**View Customizer settings:**
+```php
+echo get_theme_mod( 'hero_title' );
+echo get_theme_mod( 'dark_mode_default', false );
+```
+
+## Related Documentation
+
+- **ARCHITECTURE.md** — System design, data flows, integrations
+- **CLAUDE.md** — Developer context and quick reference
+- **README.md** — User-facing feature documentation
+- **CHANGELOG.md** — Version history
diff --git a/README.md b/README.md
index ffe5238..f842578 100644
--- a/README.md
+++ b/README.md
@@ -1,267 +1,267 @@
-# Peptide Starter Theme
-
-A premium, accessible WordPress theme for the Peptide Repo scientific peptide reference database.
-
-## Features
-
-- **Modern Design** - Clean, minimalist aesthetic inspired by Apple's human interface guidelines
-- **Dark Mode Support** - Full dark mode via `prefers-color-scheme` and manual toggle
-- **Accessibility** - WCAG AA compliant with proper focus indicators and semantic HTML
-- **Plugin Harmony** - Respects plugin CSS namespaces (`.pn-*` for Peptide News plugin)
-- **Responsive Design** - Mobile-first approach with proper breakpoints (480px, 768px, 1024px, 1440px)
-- **Typography** - Inter font with 1.125x modular scale for excellent readability
-- **Component Library** - Pre-built buttons, cards, forms, badges, alerts, and pagination
-- **Customizer Support** - Theme options for hero title, subtitle, search placeholder, footer text
-- **Performance** - Lightweight CSS architecture using custom properties instead of !important
-
-## Installation
-
-1. Download `peptide-starter.zip`
-2. Go to WordPress Admin → Appearance → Themes
-3. Click "Add New" → "Upload Theme"
-4. Select the zip file and click "Install Now"
-5. Click "Activate" to use the theme
-
-## Theme Structure
-
-```
-peptide-starter/
-├── style.css # Main stylesheet with all CSS
-├── functions.php # Theme setup and functionality
-├── header.php # Global header with navigation
-├── footer.php # Global footer with widgets
-├── index.php # Fallback template
-├── front-page.php # Home page with hero + news feed
-├── page.php # Generic page template
-├── archive-peptide.php # Peptide archive/database view
-├── single-peptide.php # Single peptide detail page
-├── 404.php # 404 error page
-├── searchform.php # Search form template
-├── screenshot.png # Theme screenshot for WordPress
-├── assets/
-│ └── js/
-│ ├── navigation.js # Mobile menu and nav functionality
-│ └── theme.js # Dark mode toggle and utilities
-├── template-parts/
-│ ├── content.php # Post/page content template
-│ └── content-none.php # Empty state template
-└── languages/ # Translation files
-```
-
-## Design System
-
-### Color Palette
-
-**Light Mode:**
-- Primary: `#0066CC` (Blue)
-- Text Primary: `#111827` (Near Black)
-- Text Secondary: `#6B7280` (Gray)
-- Background: `#FFFFFF` (White)
-
-**Dark Mode:**
-- Primary: `#3B82F6` (Bright Blue)
-- Text Primary: `#F9FAFB` (Near White)
-- Text Secondary: `#D1D5DB` (Light Gray)
-- Background: `#111827` (Near Black)
-
-### Typography
-
-All sizes use a **1.125x modular scale** with **8px grid base**:
-
-- **H1**: 48px, 700 weight
-- **H2**: 40px, 700 weight
-- **H3**: 32px, 600 weight
-- **H4**: 24px, 600 weight
-- **H5**: 20px, 700 weight (fixed from 18px per Design Director)
-- **H6**: 16px, 500 weight
-- **Body**: 14px, 400 weight (fixed from 16px per Design Director)
-
-Font family: Inter (with system font fallback)
-
-### Spacing
-
-8px base unit grid:
-- `--spacing-xs`: 4px
-- `--spacing-sm`: 8px
-- `--spacing-md`: 16px
-- `--spacing-lg`: 24px
-- `--spacing-xl`: 32px
-- `--spacing-2xl`: 48px
-- `--spacing-3xl`: 64px
-- `--spacing-4xl`: 80px
-- `--spacing-5xl`: 96px
-
-### Components
-
-**Buttons:**
-- `.ps-btn` - Base button
-- `.ps-btn-primary` - Primary action (blue)
-- `.ps-btn-secondary` - Secondary action (outlined)
-- `.ps-btn-tertiary` - Tertiary action (transparent)
-- `.ps-btn-sm`, `.ps-btn-lg`, `.ps-btn-full` - Size variants
-
-**Cards:**
-- `.ps-card` - Standard card with border and hover effect
-
-**Forms:**
-- Proper focus states with 15% opacity focus ring
-- Error states with red border and light red background
-- Support for text, email, password, search, number, url inputs
-
-**Alerts:**
-- `.ps-alert-info` - Blue alert
-- `.ps-alert-success` - Green alert
-- `.ps-alert-warning` - Amber alert
-- `.ps-alert-error` - Red alert
-
-**Badges & Tags:**
-- `.ps-badge` - Static badge
-- `.ps-tag` - Dismissible tag
-
-## Dark Mode
-
-### How it Works
-
-The theme detects dark mode in this order:
-1. User's explicit choice via toggle (stored in `localStorage`)
-2. System preference via `prefers-color-scheme: dark`
-3. Default to light mode
-
-The theme applies dark colors via:
-- `@media (prefers-color-scheme: dark)` - System preference
-- `html[data-theme="dark"]` - User override (takes precedence)
-
-### Plugin Integration
-
-The theme broadcasts dark mode changes to plugins via:
-
-1. **Custom Event**: `themechange` event on `document`
- ```javascript
- document.addEventListener('themechange', (e) => {
- console.log('Theme is now:', e.detail.theme);
- });
- ```
-
-2. **Data Attribute**: `data-theme` on ``
- ```javascript
- const theme = document.documentElement.getAttribute('data-theme');
- ```
-
-3. **CSS Custom Properties**: All colors controlled via CSS variables
-
-## Plugin Compatibility
-
-### Peptide News Plugin
-The theme provides optimal styling for the Peptide News plugin:
-- News feed grid adapts to screen size (1-4 columns)
-- Plugin `.pn-*` classes are untouched by theme
-- Plugin handles its own card styling
-- Dark mode colors available via CSS custom properties
-
-### WooCommerce
-- Cart icon in header (if WooCommerce is active)
-- Lightweight integration without full theme styling
-
-## Customizer Options
-
-Go to **Appearance → Customize** to modify:
-- **Hero Title** - Main headline on home page
-- **Hero Subtitle** - Subheading under title
-- **Search Placeholder** - Text in search input
-- **Footer Copyright** - Copyright/attribution text
-- **Dark Mode Default** - Enable dark mode on first visit
-
-## Accessibility
-
-The theme meets **WCAG AA standards**:
-- All color combinations have 4.5:1+ contrast ratio
-- Proper heading hierarchy (H1-H6)
-- Focus indicators on all interactive elements (2px outline)
-- Keyboard navigation support
-- Skip-to-main-content link
-- Semantic HTML with proper landmarks
-- Form labels properly associated with inputs
-- Alt text for images
-
-## Responsive Breakpoints
-
-- **Mobile**: 320px - 479px
-- **Tablet**: 480px - 767px
-- **Desktop**: 768px - 1023px
-- **Large**: 1024px - 1439px
-- **Extra Large**: 1440px+
-
-The theme uses **mobile-first CSS** - styles start mobile and add complexity at larger breakpoints.
-
-## Performance
-
-- **No `!important` on global elements** - Prevents plugin conflicts
-- **CSS Custom Properties** - Single source of truth for design tokens
-- **Minimal JavaScript** - Only essential interactivity
-- **Font loading** - Inter from Google Fonts with `display=swap`
-- **Proper scoping** - Theme classes prefixed with `.ps-` to avoid conflicts
-
-## Development
-
-### Adding Custom Styles
-
-Modify `style.css` sections:
-1. Components - Add new component classes
-2. Pages - Add page-specific styles
-3. Responsive - Add mobile/tablet/desktop rules
-
-### CSS Architecture
-
-The stylesheet is organized in this order:
-1. Reset
-2. CSS Custom Properties (variables)
-3. Typography
-4. Global Styles
-5. Components
-6. Regions (header, footer)
-7. Pages
-8. Animations
-9. Accessibility
-10. Dark Mode
-11. Responsive
-
-### Adding New Templates
-
-Create new template files following WordPress standards:
-- `page-{slug}.php` - Specific page templates
-- `archive-{post-type}.php` - Archive templates
-- `single-{post-type}.php` - Single post templates
-- `template-parts/{name}.php` - Reusable template parts
-
-## Browser Support
-
-- Chrome/Edge (latest 2 versions)
-- Firefox (latest 2 versions)
-- Safari (latest 2 versions)
-- iOS Safari 12+
-- Chrome Android
-
-## License
-
-GPL v2 or later - See LICENSE file
-
-## Credits
-
-Designed with principles from:
-- Apple Human Interface Guidelines (2025)
-- Modern Scientific Databases (PubMed, Nature)
-- Premium SaaS Design (Linear, Stripe, Vercel)
-- WordPress Best Practices
-
-## Support
-
-For issues and feature requests, visit: https://github.com/peptiderepo/peptide-starter
-
-## Changelog
-
-### Version 1.0.0 (Initial Release)
-- Initial theme launch
-- All core features implemented
-- Full dark mode support
-- Plugin harmony architecture
-- Accessibility compliance (WCAG AA)
+# Peptide Starter Theme
+
+A premium, accessible WordPress theme for the Peptide Repo scientific peptide reference database.
+
+## Features
+
+- **Modern Design** - Clean, minimalist aesthetic inspired by Apple's human interface guidelines
+- **Dark Mode Support** - Full dark mode via `prefers-color-scheme` and manual toggle
+- **Accessibility** - WCAG AA compliant with proper focus indicators and semantic HTML
+- **Plugin Harmony** - Respects plugin CSS namespaces (`.pn-*` for Peptide News plugin)
+- **Responsive Design** - Mobile-first approach with proper breakpoints (480px, 768px, 1024px, 1440px)
+- **Typography** - Inter font with 1.125x modular scale for excellent readability
+- **Component Library** - Pre-built buttons, cards, forms, badges, alerts, and pagination
+- **Customizer Support** - Theme options for hero title, subtitle, search placeholder, footer text
+- **Performance** - Lightweight CSS architecture using custom properties instead of !important
+
+## Installation
+
+1. Download `peptide-starter.zip`
+2. Go to WordPress Admin → Appearance → Themes
+3. Click "Add New" → "Upload Theme"
+4. Select the zip file and click "Install Now"
+5. Click "Activate" to use the theme
+
+## Theme Structure
+
+```
+peptide-starter/
+├── style.css # Main stylesheet with all CSS
+├── functions.php # Theme setup and functionality
+├── header.php # Global header with navigation
+├── footer.php # Global footer with widgets
+├── index.php # Fallback template
+├── front-page.php # Home page with hero + news feed
+├── page.php # Generic page template
+├── archive-peptide.php # Peptide archive/database view
+├── single-peptide.php # Single peptide detail page
+├── 404.php # 404 error page
+├── searchform.php # Search form template
+├── screenshot.png # Theme screenshot for WordPress
+├── assets/
+│ └── js/
+│ ├── navigation.js # Mobile menu and nav functionality
+│ └── theme.js # Dark mode toggle and utilities
+├── template-parts/
+│ ├── content.php # Post/page content template
+│ └── content-none.php # Empty state template
+└── languages/ # Translation files
+```
+
+## Design System
+
+### Color Palette
+
+**Light Mode:**
+- Primary: `#0066CC` (Blue)
+- Text Primary: `#111827` (Near Black)
+- Text Secondary: `#6B7280` (Gray)
+- Background: `#FFFFFF` (White)
+
+**Dark Mode:**
+- Primary: `#3B82F6` (Bright Blue)
+- Text Primary: `#F9FAFB` (Near White)
+- Text Secondary: `#D1D5DB` (Light Gray)
+- Background: `#111827` (Near Black)
+
+### Typography
+
+All sizes use a **1.125x modular scale** with **8px grid base**:
+
+- **H1**: 48px, 700 weight
+- **H2**: 40px, 700 weight
+- **H3**: 32px, 600 weight
+- **H4**: 24px, 600 weight
+- **H5**: 20px, 700 weight (fixed from 18px per Design Director)
+- **H6**: 16px, 500 weight
+- **Body**: 14px, 400 weight (fixed from 16px per Design Director)
+
+Font family: Inter (with system font fallback)
+
+### Spacing
+
+8px base unit grid:
+- `--spacing-xs`: 4px
+- `--spacing-sm`: 8px
+- `--spacing-md`: 16px
+- `--spacing-lg`: 24px
+- `--spacing-xl`: 32px
+- `--spacing-2xl`: 48px
+- `--spacing-3xl`: 64px
+- `--spacing-4xl`: 80px
+- `--spacing-5xl`: 96px
+
+### Components
+
+**Buttons:**
+- `.ps-btn` - Base button
+- `.ps-btn-primary` - Primary action (blue)
+- `.ps-btn-secondary` - Secondary action (outlined)
+- `.ps-btn-tertiary` - Tertiary action (transparent)
+- `.ps-btn-sm`, `.ps-btn-lg`, `.ps-btn-full` - Size variants
+
+**Cards:**
+- `.ps-card` - Standard card with border and hover effect
+
+**Forms:**
+- Proper focus states with 15% opacity focus ring
+- Error states with red border and light red background
+- Support for text, email, password, search, number, url inputs
+
+**Alerts:**
+- `.ps-alert-info` - Blue alert
+- `.ps-alert-success` - Green alert
+- `.ps-alert-warning` - Amber alert
+- `.ps-alert-error` - Red alert
+
+**Badges & Tags:**
+- `.ps-badge` - Static badge
+- `.ps-tag` - Dismissible tag
+
+## Dark Mode
+
+### How it Works
+
+The theme detects dark mode in this order:
+1. User's explicit choice via toggle (stored in `localStorage`)
+2. System preference via `prefers-color-scheme: dark`
+3. Default to light mode
+
+The theme applies dark colors via:
+- `@media (prefers-color-scheme: dark)` - System preference
+- `html[data-theme="dark"]` - User override (takes precedence)
+
+### Plugin Integration
+
+The theme broadcasts dark mode changes to plugins via:
+
+1. **Custom Event**: `themechange` event on `document`
+ ```javascript
+ document.addEventListener('themechange', (e) => {
+ console.log('Theme is now:', e.detail.theme);
+ });
+ ```
+
+2. **Data Attribute**: `data-theme` on ``
+ ```javascript
+ const theme = document.documentElement.getAttribute('data-theme');
+ ```
+
+3. **CSS Custom Properties**: All colors controlled via CSS variables
+
+## Plugin Compatibility
+
+### Peptide News Plugin
+The theme provides optimal styling for the Peptide News plugin:
+- News feed grid adapts to screen size (1-4 columns)
+- Plugin `.pn-*` classes are untouched by theme
+- Plugin handles its own card styling
+- Dark mode colors available via CSS custom properties
+
+### WooCommerce
+- Cart icon in header (if WooCommerce is active)
+- Lightweight integration without full theme styling
+
+## Customizer Options
+
+Go to **Appearance → Customize** to modify:
+- **Hero Title** - Main headline on home page
+- **Hero Subtitle** - Subheading under title
+- **Search Placeholder** - Text in search input
+- **Footer Copyright** - Copyright/attribution text
+- **Dark Mode Default** - Enable dark mode on first visit
+
+## Accessibility
+
+The theme meets **WCAG AA standards**:
+- All color combinations have 4.5:1+ contrast ratio
+- Proper heading hierarchy (H1-H6)
+- Focus indicators on all interactive elements (2px outline)
+- Keyboard navigation support
+- Skip-to-main-content link
+- Semantic HTML with proper landmarks
+- Form labels properly associated with inputs
+- Alt text for images
+
+## Responsive Breakpoints
+
+- **Mobile**: 320px - 479px
+- **Tablet**: 480px - 767px
+- **Desktop**: 768px - 1023px
+- **Large**: 1024px - 1439px
+- **Extra Large**: 1440px+
+
+The theme uses **mobile-first CSS** - styles start mobile and add complexity at larger breakpoints.
+
+## Performance
+
+- **No `!important` on global elements** - Prevents plugin conflicts
+- **CSS Custom Properties** - Single source of truth for design tokens
+- **Minimal JavaScript** - Only essential interactivity
+- **Font loading** - Inter from Google Fonts with `display=swap`
+- **Proper scoping** - Theme classes prefixed with `.ps-` to avoid conflicts
+
+## Development
+
+### Adding Custom Styles
+
+Modify `style.css` sections:
+1. Components - Add new component classes
+2. Pages - Add page-specific styles
+3. Responsive - Add mobile/tablet/desktop rules
+
+### CSS Architecture
+
+The stylesheet is organized in this order:
+1. Reset
+2. CSS Custom Properties (variables)
+3. Typography
+4. Global Styles
+5. Components
+6. Regions (header, footer)
+7. Pages
+8. Animations
+9. Accessibility
+10. Dark Mode
+11. Responsive
+
+### Adding New Templates
+
+Create new template files following WordPress standards:
+- `page-{slug}.php` - Specific page templates
+- `archive-{post-type}.php` - Archive templates
+- `single-{post-type}.php` - Single post templates
+- `template-parts/{name}.php` - Reusable template parts
+
+## Browser Support
+
+- Chrome/Edge (latest 2 versions)
+- Firefox (latest 2 versions)
+- Safari (latest 2 versions)
+- iOS Safari 12+
+- Chrome Android
+
+## License
+
+GPL v2 or later - See LICENSE file
+
+## Credits
+
+Designed with principles from:
+- Apple Human Interface Guidelines (2025)
+- Modern Scientific Databases (PubMed, Nature)
+- Premium SaaS Design (Linear, Stripe, Vercel)
+- WordPress Best Practices
+
+## Support
+
+For issues and feature requests, visit: https://github.com/peptiderepo/peptide-starter
+
+## Changelog
+
+### Version 1.0.0 (Initial Release)
+- Initial theme launch
+- All core features implemented
+- Full dark mode support
+- Plugin harmony architecture
+- Accessibility compliance (WCAG AA)
diff --git a/assets/js/auth.js b/assets/js/auth.js
new file mode 100644
index 0000000..b393e93
--- /dev/null
+++ b/assets/js/auth.js
@@ -0,0 +1,192 @@
+/**
+ * Authentication Page — Form Toggle & Validation
+ * Peptide Starter Theme
+ *
+ * Handles:
+ * - Toggle between sign-in and register forms
+ * - Client-side form validation
+ * - Password strength indicator
+ * - AJAX form submission to avoid full page reload
+ *
+ * @see page-auth.php — renders the auth forms
+ * @see functions.php — AJAX handlers (ps_auth_login, ps_auth_register)
+ *
+ * Conditionally enqueued only on pages using the Sign In / Register template.
+ */
+
+(function() {
+ 'use strict';
+
+ var loginWrap = document.getElementById('ps-auth-login');
+ var registerWrap = document.getElementById('ps-auth-register');
+ var showRegister = document.getElementById('ps-show-register');
+ var showLogin = document.getElementById('ps-show-login');
+ var messages = document.getElementById('ps-auth-messages');
+ var loginForm = document.getElementById('ps-login-form');
+ var registerForm = document.getElementById('ps-register-form');
+
+ if (!loginWrap || !registerWrap) {
+ return;
+ }
+
+ /**
+ * Toggle between login and register views.
+ * @param {string} view - 'login' or 'register'.
+ */
+ function showView(view) {
+ clearMessages();
+ if (view === 'register') {
+ loginWrap.classList.add('ps-auth-form-wrap--hidden');
+ registerWrap.classList.remove('ps-auth-form-wrap--hidden');
+ } else {
+ registerWrap.classList.add('ps-auth-form-wrap--hidden');
+ loginWrap.classList.remove('ps-auth-form-wrap--hidden');
+ }
+ }
+
+ if (showRegister) {
+ showRegister.addEventListener('click', function(e) {
+ e.preventDefault();
+ showView('register');
+ });
+ }
+
+ if (showLogin) {
+ showLogin.addEventListener('click', function(e) {
+ e.preventDefault();
+ showView('login');
+ });
+ }
+
+ // Check URL hash on load for deep linking.
+ if (window.location.hash === '#register') {
+ showView('register');
+ }
+
+ /**
+ * Display a message in the auth messages area.
+ * @param {string} text - Message text.
+ * @param {string} type - 'success', 'error', or 'info'.
+ */
+ function showMessage(text, type) {
+ if (!messages) {
+ return;
+ }
+ var alertClass = 'ps-alert ps-alert-' + (type || 'info');
+ messages.innerHTML = '';
+ }
+
+ function clearMessages() {
+ if (messages) {
+ messages.innerHTML = '';
+ }
+ }
+
+ /**
+ * Escape HTML entities to prevent XSS in message display.
+ * @param {string} str - Raw string.
+ * @returns {string} Escaped string.
+ */
+ function escapeHtml(str) {
+ var div = document.createElement('div');
+ div.textContent = str;
+ return div.innerHTML;
+ }
+
+ /**
+ * Password strength indicator.
+ * Updates the #ps-password-strength element with a rating.
+ */
+ var passwordInput = document.getElementById('ps-reg-password');
+ var strengthEl = document.getElementById('ps-password-strength');
+
+ if (passwordInput && strengthEl) {
+ passwordInput.addEventListener('input', function() {
+ var val = passwordInput.value;
+ var score = 0;
+ var label = '';
+
+ if (val.length >= 8) { score++; }
+ if (val.length >= 12) { score++; }
+ if (/[a-z]/.test(val) && /[A-Z]/.test(val)) { score++; }
+ if (/\d/.test(val)) { score++; }
+ if (/[^a-zA-Z0-9]/.test(val)) { score++; }
+
+ if (val.length === 0) {
+ label = '';
+ } else if (score <= 1) {
+ label = 'Weak';
+ } else if (score <= 3) {
+ label = 'Fair';
+ } else {
+ label = 'Strong';
+ }
+
+ strengthEl.innerHTML = label;
+ });
+ }
+
+ /**
+ * AJAX form submission handler.
+ * @param {HTMLFormElement} form - The form to submit.
+ */
+ function submitForm(form) {
+ var formData = new FormData(form);
+ var btn = form.querySelector('button[type="submit"]');
+ var origText = btn.textContent;
+
+ btn.disabled = true;
+ btn.textContent = '...';
+ clearMessages();
+
+ var xhr = new XMLHttpRequest();
+ xhr.open('POST', (typeof peptideStarterData !== 'undefined' ? peptideStarterData.ajaxUrl : '/wp-admin/admin-ajax.php'));
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+
+ xhr.onload = function() {
+ btn.disabled = false;
+ btn.textContent = origText;
+
+ try {
+ var resp = JSON.parse(xhr.responseText);
+ if (resp.success && resp.data && resp.data.redirect) {
+ window.location.href = resp.data.redirect;
+ } else {
+ showMessage(resp.data && resp.data.message ? resp.data.message : 'An error occurred.', 'error');
+ }
+ } catch (e) {
+ showMessage('An unexpected error occurred. Please try again.', 'error');
+ }
+ };
+
+ xhr.onerror = function() {
+ btn.disabled = false;
+ btn.textContent = origText;
+ showMessage('Network error. Please check your connection.', 'error');
+ };
+
+ xhr.send(formData);
+ }
+
+ if (loginForm) {
+ loginForm.addEventListener('submit', function(e) {
+ e.preventDefault();
+ if (!loginForm.checkValidity()) {
+ loginForm.reportValidity();
+ return;
+ }
+ submitForm(loginForm);
+ });
+ }
+
+ if (registerForm) {
+ registerForm.addEventListener('submit', function(e) {
+ e.preventDefault();
+ if (!registerForm.checkValidity()) {
+ registerForm.reportValidity();
+ return;
+ }
+ submitForm(registerForm);
+ });
+ }
+})();
diff --git a/assets/js/documentation.js b/assets/js/documentation.js
new file mode 100644
index 0000000..d866fd1
--- /dev/null
+++ b/assets/js/documentation.js
@@ -0,0 +1,145 @@
+/**
+ * Documentation Page — Table of Contents & Scroll Spy
+ * Peptide Starter Theme
+ *
+ * Handles:
+ * - Auto-generates ToC from h2 headings in the documentation body
+ * - Scroll spy highlights the active section in the sidebar
+ * - Smooth scrolling on ToC link click
+ * - Collapses sidebar to dropdown on mobile
+ *
+ * @see page-documentation.php — renders the two-column layout
+ * @see style.css — .ps-docs-* classes
+ *
+ * Conditionally enqueued only on pages using the Documentation template.
+ */
+
+(function() {
+ 'use strict';
+
+ const docsBody = document.getElementById('ps-docs-body');
+ const tocList = document.getElementById('ps-docs-toc-list');
+ const sidebar = document.querySelector('.ps-docs-sidebar');
+
+ if (!docsBody || !tocList) {
+ return;
+ }
+
+ const headings = docsBody.querySelectorAll('h2');
+
+ if (headings.length === 0) {
+ // Hide the sidebar if there are no headings to navigate.
+ if (sidebar) {
+ sidebar.style.display = 'none';
+ }
+ return;
+ }
+
+ /**
+ * Build the Table of Contents from h2 headings.
+ * Assigns IDs to headings that lack one for anchor linking.
+ */
+ function buildToc() {
+ headings.forEach(function(heading, index) {
+ // Ensure every heading has an ID for anchor links.
+ if (!heading.id) {
+ heading.id = 'section-' + (index + 1);
+ }
+
+ var li = document.createElement('li');
+ var link = document.createElement('a');
+
+ link.href = '#' + heading.id;
+ link.textContent = heading.textContent;
+ link.className = 'ps-docs-toc-link';
+
+ link.addEventListener('click', function(e) {
+ e.preventDefault();
+ smoothScrollTo(heading);
+ });
+
+ li.appendChild(link);
+ tocList.appendChild(li);
+ });
+ }
+
+ /**
+ * Smooth scroll to a target element, accounting for the sticky header.
+ * @param {HTMLElement} target The element to scroll to.
+ */
+ function smoothScrollTo(target) {
+ var headerHeight = document.querySelector('.site-header')
+ ? document.querySelector('.site-header').offsetHeight
+ : 0;
+ var offset = 24; // Extra breathing room below header.
+ var top = target.getBoundingClientRect().top + window.pageYOffset - headerHeight - offset;
+
+ window.scrollTo({
+ top: top,
+ behavior: 'smooth'
+ });
+
+ // Update URL hash without jumping.
+ history.replaceState(null, '', '#' + target.id);
+ }
+
+ /**
+ * Scroll spy — highlights the ToC link corresponding to the
+ * currently visible section. Uses IntersectionObserver for performance.
+ */
+ function initScrollSpy() {
+ var tocLinks = tocList.querySelectorAll('.ps-docs-toc-link');
+
+ if (tocLinks.length === 0) {
+ return;
+ }
+
+ var headerHeight = document.querySelector('.site-header')
+ ? document.querySelector('.site-header').offsetHeight
+ : 0;
+
+ var observer = new IntersectionObserver(function(entries) {
+ entries.forEach(function(entry) {
+ if (entry.isIntersecting) {
+ var id = entry.target.id;
+ tocLinks.forEach(function(link) {
+ link.classList.remove('ps-docs-toc-link--active');
+ if (link.getAttribute('href') === '#' + id) {
+ link.classList.add('ps-docs-toc-link--active');
+ }
+ });
+ }
+ });
+ }, {
+ rootMargin: '-' + (headerHeight + 32) + 'px 0px -60% 0px',
+ threshold: 0
+ });
+
+ headings.forEach(function(heading) {
+ observer.observe(heading);
+ });
+ }
+
+ /**
+ * Mobile dropdown toggle for the sidebar ToC.
+ */
+ function initMobileToggle() {
+ var tocTitle = document.querySelector('.ps-docs-toc-title');
+
+ if (!tocTitle) {
+ return;
+ }
+
+ tocTitle.addEventListener('click', function() {
+ // Only toggle on mobile (sidebar is not sticky).
+ if (window.innerWidth < 1024) {
+ sidebar.classList.toggle('ps-docs-sidebar--open');
+ }
+ });
+ }
+
+ // Initialize.
+ buildToc();
+ initScrollSpy();
+ initMobileToggle();
+})();
diff --git a/assets/js/settings-panel.js b/assets/js/settings-panel.js
new file mode 100644
index 0000000..a797d7d
--- /dev/null
+++ b/assets/js/settings-panel.js
@@ -0,0 +1,163 @@
+/**
+ * Settings Panel — Open/Close & Contact Form
+ * Peptide Starter Theme
+ *
+ * Handles:
+ * - Toggle settings slide-out panel visibility
+ * - AJAX submission of the contact form
+ * - Overlay backdrop click to close
+ * - Escape key to close
+ * - Focus trap inside the panel for accessibility
+ *
+ * @see template-parts/settings-panel.php — panel HTML
+ * @see header.php — settings icon trigger button
+ * @see functions.php — AJAX handler for contact form
+ *
+ * Enqueued globally (lightweight — all listeners are passive until panel opens).
+ */
+
+(function() {
+ 'use strict';
+
+ var panel = document.getElementById('ps-settings-panel');
+ var overlay = document.getElementById('ps-settings-overlay');
+ var closeBtn = document.getElementById('ps-settings-close');
+ var openBtn = document.getElementById('ps-settings-toggle');
+ var contactForm = document.getElementById('ps-contact-form');
+ var statusEl = document.getElementById('ps-contact-status');
+
+ if (!panel || !overlay) {
+ return;
+ }
+
+ /**
+ * Open the settings panel.
+ */
+ function openPanel() {
+ panel.classList.add('ps-settings-panel--open');
+ panel.setAttribute('aria-hidden', 'false');
+ overlay.classList.add('ps-settings-overlay--active');
+ overlay.setAttribute('aria-hidden', 'false');
+ document.body.style.overflow = 'hidden';
+
+ // Focus the close button for keyboard users.
+ if (closeBtn) {
+ setTimeout(function() { closeBtn.focus(); }, 100);
+ }
+ }
+
+ /**
+ * Close the settings panel.
+ */
+ function closePanel() {
+ panel.classList.remove('ps-settings-panel--open');
+ panel.setAttribute('aria-hidden', 'true');
+ overlay.classList.remove('ps-settings-overlay--active');
+ overlay.setAttribute('aria-hidden', 'true');
+ document.body.style.overflow = '';
+
+ // Return focus to the trigger button.
+ if (openBtn) {
+ openBtn.focus();
+ }
+ }
+
+ // Bind open trigger.
+ if (openBtn) {
+ openBtn.addEventListener('click', openPanel);
+ }
+
+ // Bind close button.
+ if (closeBtn) {
+ closeBtn.addEventListener('click', closePanel);
+ }
+
+ // Bind overlay backdrop click.
+ overlay.addEventListener('click', closePanel);
+
+ // Close on Escape key.
+ document.addEventListener('keydown', function(e) {
+ if (e.key === 'Escape' && panel.classList.contains('ps-settings-panel--open')) {
+ closePanel();
+ }
+ });
+
+ /**
+ * Contact form AJAX submission.
+ */
+ if (contactForm) {
+ contactForm.addEventListener('submit', function(e) {
+ e.preventDefault();
+
+ if (!contactForm.checkValidity()) {
+ contactForm.reportValidity();
+ return;
+ }
+
+ var formData = new FormData(contactForm);
+ var btn = contactForm.querySelector('button[type="submit"]');
+ var origText = btn.textContent;
+
+ btn.disabled = true;
+ btn.textContent = '...';
+
+ if (statusEl) {
+ statusEl.innerHTML = '';
+ }
+
+ var xhr = new XMLHttpRequest();
+ var ajaxUrl = (typeof peptideStarterData !== 'undefined' && peptideStarterData.ajaxUrl)
+ ? peptideStarterData.ajaxUrl
+ : '/wp-admin/admin-ajax.php';
+
+ xhr.open('POST', ajaxUrl);
+ xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+
+ xhr.onload = function() {
+ btn.disabled = false;
+ btn.textContent = origText;
+
+ try {
+ var resp = JSON.parse(xhr.responseText);
+ if (resp.success) {
+ if (statusEl) {
+ statusEl.innerHTML = '' +
+ escapeHtml(resp.data.message || 'Message sent.') + '
';
+ }
+ contactForm.reset();
+ } else {
+ if (statusEl) {
+ statusEl.innerHTML = '' +
+ escapeHtml(resp.data.message || 'Failed to send.') + '
';
+ }
+ }
+ } catch (ex) {
+ if (statusEl) {
+ statusEl.innerHTML = 'An unexpected error occurred.
';
+ }
+ }
+ };
+
+ xhr.onerror = function() {
+ btn.disabled = false;
+ btn.textContent = origText;
+ if (statusEl) {
+ statusEl.innerHTML = 'Network error. Please try again.
';
+ }
+ };
+
+ xhr.send(formData);
+ });
+ }
+
+ /**
+ * Escape HTML for safe insertion.
+ * @param {string} str - Raw text.
+ * @returns {string} Escaped HTML.
+ */
+ function escapeHtml(str) {
+ var div = document.createElement('div');
+ div.textContent = str;
+ return div.innerHTML;
+ }
+})();
diff --git a/footer.php b/footer.php
index 87ce9cf..fe439a5 100644
--- a/footer.php
+++ b/footer.php
@@ -2,46 +2,33 @@
/**
* The footer for Peptide Starter theme
*
+ * Updated footer with disclaimer, language links, and settings panel.
+ *
+ * @see template-parts/settings-panel.php — slide-out support panel
+ * @see template-parts/newsletter-signup.php — newsletter CTA (on front page)
+ * @see functions.php — newsletter handler, contact form handler
+ *
* @package peptide-starter
*/
?>
-
+
+
+
+
+