# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

# Forum Press Zone - Development Rules

> **CRITICAL**: Follow these rules to avoid breaking the plugin.

---

## Default Operating Mode: Skill-Based Development

**When Claude Code opens this folder, use the skill-based architecture.**

### Core Principle
**Compose focused skills to solve tasks. The foundational skill is implicit in every task.**

---

## Skill-Based Architecture

### Foundational Skill (Always Applies)

**`wordpress-plugin-foundation-skill.md`** - Automatically applied to EVERY task

Contains:
- WordPress.org compliance (naming, prefixes, text domains)
- Security patterns (SQL injection, XSS, CSRF, authentication)
- Input validation and sanitization
- Permission checking and access control
- Nonce verification
- Output escaping
- Common mistakes across all domains

**You never need to explicitly reference this skill** - it's automatically applied.

### Specialized Skills (Load As Needed)

**Core Technology (6 skills):**
- `php-skill.md` - PHP patterns, WordPress PHP APIs
- `javascript-skill.md` - Vanilla JS, DOM manipulation, XSS prevention
- `css-scss-skill.md` - SCSS architecture, styling, dark mode
- `sql-skill.md` - Database queries, SQL injection prevention
- `rest-api-skill.md` - REST endpoint patterns
- `ajax-skill.md` - WordPress AJAX patterns

**Architecture (4 skills):**
- `caching-skill.md` - Caching strategies, invalidation
- `database-schema-skill.md` - Schema design, migrations
- `frontend-architecture-skill.md` - Component patterns, state management
- `accessibility-skill.md` - WCAG compliance, ARIA

**Domain (4 skills):**
- `user-engagement-skill.md` - Reactions, subscriptions, notifications
- `moderation-skill.md` - Bans, warnings, reports, content filtering
- `messaging-skill.md` - Private messaging, conversations
- `forum-structure-skill.md` - Nodes, threads, posts, nested replies

**Quality Assurance (1 skill):**
- `verification.md` - Playwright-based visual + functional verification skill. **MANDATORY** before committing changes to `admin/src-vanilla/styles/**`, `admin/src-vanilla/**/*.js`, `assets/scss/**`, `assets/js/**`, `templates/**/*.php`, REST endpoints, or shared components (`Modal.js`, `Tabs.js`, `Toast.js`). Also mandatory whenever a visual / layout / dark-mode bug is reported. Local env: WP at `http://localhost:8080`, container `devzone-wordpress`, admin creds `admin` / `admin123`. Always put test files, screenshots, verification docs in `./tests/e2e/` or `./tests/e2e/tmp/` — never in the root folder.

**Skill files location:** `.claude/skills/`

### Skill Selection Guide

| Task Type | Required Skills |
|-----------|----------------|
| **Add REST endpoint** | `php-skill`, `rest-api-skill` |
| **Add AJAX handler** | `php-skill`, `ajax-skill` |
| **Add frontend JS** | `javascript-skill` |
| **Add CSS styling** | `css-scss-skill` |
| **Database query** | `php-skill`, `sql-skill` |
| **Schema change** | `database-schema-skill`, `sql-skill` |
| **Moderation feature** | `php-skill`, `moderation-skill` |
| **Visual regression testing** | `verification` | `css-scss-skill` |
Foundation: wordpress-plugin-foundation-skill.md (always applies)

Specialized skills:
1. php-skill.md - PHP patterns
2. rest-api-skill.md - Endpoint structure
3. moderation-skill.md - Ban logic

Key foundation requirements:
- Permission callback required
- Input sanitization with absint/sanitize_text_field
- Administrator protection
```

### Legacy Agent System (Deprecated)

The following agents are deprecated in favor of skills but kept for reference:

| Agent | Replaced By |
|-------|-------------|
| `admin-panel-expert.md` | `php-skill` + `javascript-skill` + `rest-api-skill` |
| `frontend-php-expert.md` | `php-skill` + `accessibility-skill` |
| `frontend-js-expert.md` | `javascript-skill` + `frontend-architecture-skill` |
| `styling-expert.md` | `css-scss-skill` + `accessibility-skill` |
| `database-expert.md` | `sql-skill` + `caching-skill` + `database-schema-skill` |
| `users-permissions-expert.md` | `php-skill` + domain context |
| `moderation-expert.md` | `moderation-skill` + `php-skill` |
| `engagement-expert.md` | `user-engagement-skill` + `php-skill` |

**New orchestrator:** `.claude/agents/orchestrator-skill-based.md`

### Workflow
1. **Analyze** user request - identify affected domains
2. **Delegate** to appropriate expert agent(s) using Task tool
3. **Review** their work for compliance
4. **Report** results to user

Agent files location: `.claude/agents/`

### How to Delegate

**Before delegating, gather context by reading relevant files.** Then show the EXACT prompt:
```
🤖 Delegating to: [agent-name]
📋 Prompt: [full prompt text - the actual text you send]
```

**CRITICAL: The prompt you display MUST BE IDENTICAL to the Task tool's `prompt` parameter.**
- Do NOT show a detailed prompt then pass a short summary to the agent
- Do NOT paraphrase or shorten when calling Task tool
- Copy-paste the SAME text you displayed into the `prompt` parameter
- The agent receives ONLY what's in the `prompt` parameter, not what you displayed to the user

**Prompt MUST include (for agent efficiency):**
1. `Follow .claude/agents/[agent].md` (first line, required)
2. **Task title and goal** - what needs to be accomplished
3. **Full context** - why this change is needed, how it connects to other features
4. **Relevant code snippets** - copy actual code from files being modified (with line numbers)
5. **Existing patterns to follow** - show similar implementations from the codebase
6. **Specific files to modify** - full absolute paths
7. **Step-by-step requirements** - detailed instructions, not vague descriptions
8. **Constraints from CLAUDE.md** - relevant naming conventions, security rules
9. **Build commands to run** - exact commands after changes
10. **Verification criteria** - how to test the change works

**BAD prompt (too vague):**
```
Add a new setting to the admin panel.
```

**GOOD prompt (detailed):**
```
## Task: Add "Max Upload Size" setting to admin Settings page

### Context
Users need to configure max file upload size. Currently hardcoded to 5MB in PostCreator.php:234.

### Current Code (from settings.js:200-210)
[paste actual code snippet here]

### Pattern to Follow (from settings.js:180-195)
[paste similar setting implementation]

### Requirements
1. Add number field after "Max Attachments" setting
2. Use same renderSettingsField() pattern as line 185
3. Backend already has 'max_attachment_size' option (default: 5242880)
...
```

**Orchestrator must read files BEFORE delegating** to provide code snippets and patterns.

### Handle Directly (No Delegation)
- Questions about codebase structure
- Explaining existing code
- Read-only exploration
- User explicitly says "don't delegate" or "do it yourself"

### NEVER Investigate Code Directly
**Orchestrator must ALWAYS delegate code investigation to agents.**
Even for "quick checks" - delegate. No exceptions unless user explicitly says otherwise.

### Self-Learning (Only When Relevant)
Run `/learn-from-mistakes` ONLY after tasks where you:
- Found and fixed DRY violations (duplicated code that should be shared)
- Discovered conventions not yet documented in CLAUDE.md
- Fixed bugs caused by anti-patterns worth documenting
- Found reusable components that weren't listed

**Skip self-learning for:**
- Simple feature additions (new badge, new translation, new setting)
- Routine CRUD operations
- Config or content changes

### Full Orchestrator Specification
See `.claude/agents/orchestrator.md` for:
- Detailed workflow phases
- Delegation prompt templates
- Compliance review checklists
- Error handling patterns

### Visual Verification Workflow (REQUIRED for CSS/Visual Issues)

**CRITICAL**: When presented with a visual problem (text color, font, CSS, visibility, layout, styling issues - anything visually verifiable), you MUST use the Playwright verification loop workflow:

**Workflow:**
1. **Create Playwright test script** that:
   - Navigates to affected page(s)
   - Checks computed styles (colors, display, opacity, etc.)
   - Takes before/after screenshots
   - Validates specific CSS properties
   - Reports PASS/FAIL with specific values

2. **Run verification BEFORE fixing** to confirm the issue

3. **Apply the fix** to CSS/SCSS files

4. **Build CSS**: `npm run build:css`

5. **Run verification AGAIN** to confirm fix worked

6. **If tests still fail**:
   - Revert changes: `git checkout -- assets/css/`
   - Analyze test output
   - Try different approach
   - Repeat until verification passes

7. **Only commit when ALL tests pass**

**Example test structure:**
```javascript
// Check computed color is white
const color = await element.evaluate(el =>
  window.getComputedStyle(el).color
);
const isWhite = color === 'rgb(255, 255, 255)';
console.log(isWhite ? '✅ PASS' : '❌ FAIL');
```

**Why this works:**
- Eliminates "looks fixed but isn't" false positives
- Catches CSS specificity issues immediately
- Provides concrete proof of fix
- Prevents committing broken CSS

**Use `/verify` command** to run this workflow automatically.

---

## 1. Build Commands (MUST RUN AFTER CHANGES)

### Frontend SCSS (from plugin root)
```bash
npm run build:css      # After ANY SCSS/CSS changes (REQUIRED)
npm run build:core     # Just core styles
npm run build:page-*   # Specific page styles
npm run watch:css      # Development mode
```

### Admin SPA (from admin/ directory)
```bash
cd admin && npm run build   # After ANY admin JS/CSS changes (REQUIRED)
cd admin && npm run start   # Development watch mode
```

**Frontend JS needs no build** - vanilla JS, production-ready in `assets/js/`

### Static Analysis (from plugin root)
```bash
./vendor/bin/phpcs --standard=.dev-config/phpcs.xml includes/  # PHP CodeSniffer
./vendor/bin/psalm -c .dev-config/psalm.xml                     # Psalm type checking
cd admin && npm run lint:js                                      # ESLint for admin JS
```

---

## Architecture Overview

**Dual Frontend System:**
- **Admin**: Webpack-built vanilla JS SPA (`admin/src-vanilla/` → `admin/build/`)
- **Frontend**: SCSS compiled CSS + vanilla JS (`assets/scss/` → `assets/css/`, `assets/js/` no build)

**Custom SQL Schema** (not WordPress post meta):
- `presszone_forum_nodes` - Categories/forums tree
- `presszone_forum_threads` - Thread registry
- `presszone_forum_posts` - Posts with nested reply support
- `presszone_forum_users_extended` - User profiles/reputation
- `presszone_forum_conversations` - Private messaging

**Key Classes:**
- `Plugin` (`class-presszone-forum-plugin.php`) - Main orchestrator, asset loading
- `Query` (`class-presszone-forum-query.php`) - All database operations
- `Roles` (`class-presszone-forum-roles.php`) - Permissions/capabilities
- `PostCreator` (`class-presszone-forum-post-creator.php`) - Content validation/creation

**REST API:** `includes/api/` - Admin, Public, and Messenger endpoints

---

## 2. PHP Conventions

### Namespace
```php
// CORRECT
namespace PresszoneForumPlugin;
namespace PresszoneForumPlugin\Api;
namespace PresszoneForumPlugin\Auth;
namespace PresszoneForumPlugin\Admin;
```

### File Naming
| File Name | Class Name |
|-----------|------------|
| `class-presszone-forum-post-creator.php` | `class PostCreator` |
| `class-presszone-forum-roles.php` | `class Roles` |

### Required File Header
```php
<?php
declare(strict_types=1);

namespace PresszoneForumPlugin;

if (!defined('ABSPATH')) {
    exit;
}
```

### Constants
- Plugin constants: `PRESSZONE_FORUM_*`
- Class constants: `public const CAP_*`, `public const ROLE_*`

---

## 3. Translation (i18n)

### Text Domain: `'forum-press-zone'` - ALWAYS
```php
// CORRECT
__('Hello', 'forum-press-zone')
esc_html__('Hello', 'forum-press-zone')
esc_attr__('Hello', 'forum-press-zone')
_e('Hello', 'forum-press-zone')
sprintf(__('Hello %s', 'forum-press-zone'), $name)

// WRONG
__('Hello')                    // Missing text domain
__('Hello', 'other-domain')    // Wrong text domain
```

### JavaScript Strings
Pass through wp_localize_script, never hardcode:
```php
wp_localize_script('presszone-forum-frontend', 'presszoneForumData', [
    'strings' => [
        'reply' => __('Reply', 'forum-press-zone'),
        'cancel' => __('Cancel', 'forum-press-zone'),
    ],
]);
```

### File Locations
- `languages/forum-press-zone-{locale}.po`
- `languages/forum-press-zone-{locale}-presszone-forum-admin-app.json`

### Translation Maintenance Rules
| Action | Requirement |
|--------|-------------|
| **Adding new UI string** | Add to all `.po` files, translate to all languages |
| **Removing UI string** | Remove from all `.po` files to avoid bloat |
| **Editing UI string** | Update in all `.po` files, retranslate appropriately |

---

## 4. Security Rules

### Output Escaping (ALWAYS)
```php
esc_html($text)           // HTML content
esc_attr($value)          // HTML attributes
esc_url($url)             // URLs
wp_kses_post($html)       // Post content with allowed HTML
```

### Input Sanitization (ALWAYS)
```php
sanitize_text_field(wp_unslash($_POST['field']))
sanitize_textarea_field(wp_unslash($_POST['content']))
sanitize_key($key)
absint($id)
```

### Nonce Verification
```php
// REST API: X-WP-Nonce header (automatic)

// AJAX
check_ajax_referer('presszone_forum_{action}', 'nonce');

// Forms
wp_nonce_field('presszone_forum_{action}');
wp_verify_nonce($_POST['_wpnonce'], 'presszone_forum_{action}');
```

### Permission Checks
```php
Roles::canModerate($user_id)        // Moderator check
current_user_can('manage_options')  // Admin check
is_user_logged_in()                 // Auth check
```

---

## 5. Common Mistakes to Avoid

> **CRITICAL**: Always implement robust, class-based approaches. NEVER use fragile CSS selectors like `[style*="block"]` or `:has([style*="..."])`. Always use explicit class toggles in JS with corresponding CSS rules.

| Mistake | Fix |
|---------|-----|
| **Using fragile CSS selectors like `[style*="block"]`** | **Use explicit class toggles: JS adds/removes class, CSS targets class** |
| **JS: Missing window reference in IIFE** | **Get from window: `const PresszoneForumApp = window.PresszoneForumApp`** |
| **Styling generic elements on `body.presszone-forum-template`** | **Scope ALL element styling to `.presszone-forum-wrapper`** |
| **`body.presszone-forum-template :where(h1...)` selectors** | **Use `.presszone-forum-wrapper :where(h1...)` instead - leaks to header/footer!** |
| **`body.dark-mode h1 { }` direct element styling** | **Dark mode must target prefixed classes: `body.dark-mode .presszone-forum-*`** |
| **Hardcoded colors (even in dark mode!)** | **Use SCSS variables: `$presszone-forum-*` and `$presszone-forum-*-dark`** |
| **Not checking existing variables** | **Search `_variables.scss` or `main.css` first** |
| **Using short CSS prefixes (<4 chars)** | **Use `.presszone-forum-*` for classes, `$presszone-forum-*` for SCSS variables** |
| Missing text domain | Add `'forum-press-zone'` |
| **Forgetting CSS build after SCSS changes** | **Run `npm run build:css` from plugin root** |
| **Forgetting admin build after changes** | **Run `cd admin && npm run build`** |
| Missing output escaping | Use `esc_html()`, etc. |
| Missing input sanitization | Use `sanitize_*()` |
| Wrong table names | Use `presszone_forum_` prefix |
| Skipping nonce checks | Always verify nonces |
| Direct DB queries | Use `Query` class |
| Creating stubs/placeholders | Implement full functionality |
| **Writing inline toast code** | **Use `Toast.js` component** |
| **Duplicating animation keyframes** | **Use shared ones from `_animations.css`** |
| **Hardcoded animation durations** | **Use `$presszone-forum-duration-*` SCSS variables** |
| **Missing reduced motion support** | **Add `@media (prefers-reduced-motion)` rules** |
| **Duplicating validation logic** | **Use `PostCreator->checkExternalLinks()` and `checkWordFilter()`** |
| **Using `.*?` for nested BBCode** | **Use `(?:(?!\[quote).)*?` negative lookahead** |
| **Hash navigation without reload** | **Add `window.location.reload()` after `href` change** |
| **Bare `presszoneForumData` access** | **Use `window.presszoneForumData?.prop \|\| fallback`** |
| **Only inline errors, no toast** | **Always show toast for user-facing errors** |
| **Private validation methods** | **Make reusable validators `public`** |
| **Not syncing TinyMCE before submit** | **Call `tinymce.triggerSave()` first** |
| **Regex for nested HTML structures** | **Use DOMDocument - regex can't handle arbitrary nesting** |
| **forEach on nested DOM elements** | **Use while loop with innermost-first filtering** |
| **Processing outer elements first** | **Always process innermost first, then work outward** |
| **Styling `<a>` as button without specificity** | **Use `a.classname` selector + `color: #fff !important` to override link styles** |
| **Removing animation class on animationend** | **Keep class - removal breaks CSS rules that depend on it (causes secondary animations)** |
| **JS inserting content that PHP also renders** | **Check if PHP template already displays it - avoid double rendering** |
| **Adding JS-generated HTML without CSS** | **Always add corresponding CSS for new element classes created in JS** |
| **Tab slide CSS suppression via class** | **Don't remove slide class after animation - child suppression rules stop working** |
| innerHTML with API data | Use DOMParser or textContent, or add SECURITY comment if server-sanitized |
| **Using `wp_add_inline_style()`** | **Write to static CSS file in `wp-content/uploads/presszone-forum/`** |
| **`<style>` tags in PHP templates** | **Move styles to SCSS files under `assets/scss/`** |
| **Inline `style=` attributes** | **Use CSS utility classes or component classes** |
| `outline: none` without alternative | Use visible `outline: 2px solid` with `:focus-visible` |
| Missing nonce action parameter | Always pass action string: `verifyNonce($nonce, 'action_name')` |
| `file_put_contents()` usage | Use WP Filesystem API |
| SVG icons without aria-label | Add `aria-label` or `role="img" aria-label="..."` to all icon SVGs |
| `javascript:void(0)` links | Use `<button>` elements instead |
| Modal without focus trap | Implement focus trap: trap focus inside, return on close |
| `unserialize()` usage | Use `json_encode()`/`json_decode()` instead |
| Missing `@media (prefers-reduced-motion)` | Add reduced motion media query to disable animations |
| Dropdown without aria-expanded | Add `aria-expanded="true/false"` to all dropdown triggers |
| **Using undefined SCSS variable** | **Add to `_variables.scss` with static hex value + `-dark` variant for dark mode** |
| **Hardcoded `rgba()` colors in SCSS** | **Create SCSS variable with static value in `_variables.scss`** |
| **Using `var(--presszone-forum-*)` anywhere** | **STRICTLY FORBIDDEN - Use `$presszone-forum-*` SCSS variables only** |
| **Defining color without dark mode variant** | **EVERY color needs both `$presszone-forum-*` AND `$presszone-forum-*-dark` definitions** |
| **Editing one SCSS file, missing duplicates** | **Search ALL scss files: `threads.scss`, `frontend.scss`, `_legacy-frontend.scss`, `compiled/*.scss`, `extracted/*.scss`** |
| **Adding state color without variable** | **Create semantic variables: `--sticky-bg`, `--unread-bg`, etc. with light/dark values** |
| **Renaming CSS variable without checking custom.css** | **Check `writeCustomCss()` in Plugin.php - admin Design page colors will break** |
| **Not verifying Design page after CSS changes** | **Test `/wp-admin/admin.php?page=forum-press-zone#/design` colors still work** |
| **Using `<table>` elements** | **NEVER use `<table>` - always use `<div>` with CSS Grid/Flexbox** |
| **Using `wp_is_mobile()` for layouts** | **Use CSS media queries - never user-agent detection for responsive design** |
| **Global CSS selectors (`*`, `html`, `body`)** | **ALWAYS scope to `.presszone-forum-wrapper` - plugin must not leak styles** |
| **Unscoped element selectors (`code`, `pre`, `mark`)** | **Wrap in `.presszone-forum-wrapper { }` block** |
| **Global reduced-motion `*` selector** | **Scope to `.presszone-forum-wrapper *`** |

---

## 6. CSS Scoping (CRITICAL for WordPress.org)

> **RULE**: The plugin must be self-contained. ALL styles must be scoped to prevent affecting host themes.

### Scoping Architecture

| Context | Selector Pattern | When to Use |
|---------|------------------|-------------|
| **All visual styles** | `.presszone-forum-wrapper { ... }` | Default for all component styles |
| **Template-level body styles** | `body.presszone-forum-template { ... }` | Background, color-scheme on forum pages |
| **Dark mode variables** | `body.dark-mode { ... }` | CSS variable overrides only |
| **CSS variables** | STRICTLY FORBIDDEN | Never use `:root {}`, `var()`, or `--presszone-forum-*` |

### NEVER Use Global Selectors
```scss
// ❌ WRONG - Affects entire site
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { min-height: 100vh; }
code { font-family: monospace; }

// ✅ CORRECT - Scoped to wrapper
.presszone-forum-wrapper {
  * { box-sizing: border-box; }
  code { font-family: monospace; }
}

body.presszone-forum-template {
  scroll-behavior: smooth;
  min-height: 100vh;
}
```

### Exception: Embed Page
`assets/scss/pages/_embed.scss` is intentionally global because embeds load in iframes as standalone pages.

---

## 7. Development Workflow

1. **PHP changes** -> Test immediately
2. **Frontend SCSS** -> `npm run build:css` -> Test
3. **Frontend JS** -> Hard refresh -> Test (no build)
4. **Admin SPA** -> `cd admin && npm run build` -> Test
5. **Translations** -> Correct text domain -> Regenerate PO
6. **Database** -> Use migrations in `includes/migrations/`

---

## 8. CSS Architecture Rules (ABSOLUTE BAN ON INLINE CSS)

> **CRITICAL**: NEVER use inline CSS for ANY reason. There are NO exceptions. If you think inline CSS is required, you are wrong - use CSS classes or custom.css instead.

### CSS CUSTOM PROPERTIES ARE STRICTLY FORBIDDEN (ZERO TOLERANCE)

> **ABSOLUTE BAN**: CSS custom properties (`var(--*)`, `:root {}`, `--variable:`) are **STRICTLY FORBIDDEN** everywhere in the entire codebase. No exceptions. No justifications. No legacy code excuses.

**This applies to ALL files:**
- ❌ **FORBIDDEN in SCSS files** (`.scss`)
- ❌ **FORBIDDEN in CSS files** (`.css`)
- ❌ **FORBIDDEN in JavaScript** (inline styles, template literals)
- ❌ **FORBIDDEN in PHP templates** (inline styles)
- ❌ **FORBIDDEN in admin panel** (`admin/src-vanilla/styles/`)

**ZERO-TOLERANCE enforcement:**
- 🚫 `var(--presszone-forum-*)` - NEVER use anywhere
- 🚫 `var(--anything)` - NEVER use anywhere
- 🚫 `:root { --var: value; }` - NEVER define
- 🚫 `body.dark-mode { --var: value; }` - NEVER define
- 🚫 Inline styles with `var()` - NEVER use

```scss
// ❌ ABSOLUTELY FORBIDDEN - CSS custom properties
.presszone-forum-button {
  background: var(--presszone-forum-primary);     // FORBIDDEN
  color: var(--presszone-forum-text-on-primary);  // FORBIDDEN
}

:root {
  --presszone-forum-primary: #1f71dd;             // FORBIDDEN
}

// ❌ FORBIDDEN in JavaScript
style: 'background: var(--presszone-forum-surface);'  // FORBIDDEN

// ✅ CORRECT - SCSS variables with static values
.presszone-forum-button {
  background: $presszone-forum-primary;           // REQUIRED
  color: $presszone-forum-text-on-primary;        // REQUIRED
}

// ✅ CORRECT - Dark mode with explicit overrides
body.dark-mode .presszone-forum-button {
  background: $presszone-forum-primary-dark;      // Static value
}
```

**Why this matters:**
- SCSS variables compile to static values - better performance
- No runtime CSS variable resolution overhead
- Explicit dark mode rules are easier to audit and debug
- Type safety and IDE autocomplete work better
- Easier refactoring and global find/replace
- WordPress.org plugin compliance

**Enforcement:**
- If you see `var(--*)` ANYWHERE during ANY task, it is WRONG and must be removed
- If you see `:root { }` blocks, they are WRONG and must be removed
- The admin panel's `main.css` currently violates this rule - it needs a full SCSS refactor
- There are NO legacy exceptions - all code must use pure SCSS variables

**Source of truth for SCSS:**
- SCSS variables with static hex values: `assets/css/abstracts/_variables.scss`
- Light mode: `$presszone-forum-primary: #1f71dd;`
- Dark mode: `$presszone-forum-primary-dark: #60a5fa;`
- All `.scss` files use `$presszone-forum-*` variables with explicit `body.dark-mode` overrides

### STRICT CSS CONTAINMENT RULES (MUST FOLLOW)

The plugin must be **self-contained** and sit harmlessly between the site's Header and Footer without touching them.

**Scope Hierarchy:**
1. `body.presszone-forum-template` - ONLY for body-level properties (background, color-scheme, min-height)
2. `body.dark-mode .presszone-forum-*` - Dark mode overrides for prefixed classes only
3. `.presszone-forum-wrapper` - ALL element styling (typography, colors, layouts) MUST be scoped here
4. `.presszone-forum-widget` - Same containment for widgets that appear outside the wrapper

**ABSOLUTELY FORBIDDEN:**
```scss
// ❌ WRONG - Leaks to header/footer
body.presszone-forum-template {
  :where(h1, h2, h3) { color: red; }  // AFFECTS ENTIRE PAGE!
  p { font-size: 14px; }              // AFFECTS ENTIRE PAGE!
}

// ❌ WRONG - Dark mode styling elements directly
body.dark-mode h1 { color: white; }  // AFFECTS ENTIRE PAGE!

// ✅ CORRECT - Scoped to wrapper
.presszone-forum-wrapper {
  :where(h1, h2, h3) { color: $presszone-forum-text; }
  p { font-size: 14px; }
}

// ✅ CORRECT - Dark mode with explicit SCSS variable overrides
body.dark-mode .presszone-forum-wrapper {
  :where(h1, h2, h3) { color: $presszone-forum-text-dark; }  // Static dark value
}

// ✅ CORRECT - Dark mode targets prefixed classes
body.dark-mode .presszone-forum-navbar {
  background: $presszone-forum-surface;  // Use SCSS variable!
}
```

**Allowed on `body.presszone-forum-template`:**
- `background`, `background-attachment`, `background-color`
- `color-scheme`
- `min-height`, `scroll-behavior`
- `padding-bottom` (for mobile nav)

**NOT Allowed on `body.presszone-forum-template`:**
- Any `:where()` selectors targeting generic elements
- Any direct styling of `h1-h6`, `p`, `a`, `ul`, `ol`, `li`, `table`, `td`, `th`, `div`, `span`
- Any descendant selectors affecting generic HTML elements

### ABSOLUTELY FORBIDDEN - No Exceptions, No Excuses
```php
// ❌ FORBIDDEN - wp_add_inline_style() - NEVER USE
wp_add_inline_style('handle', $css);  // WRONG - Always use static CSS files

// ❌ FORBIDDEN - <style> tags in templates - NEVER USE
<style>.my-class { color: red; }</style>  // WRONG - Move to SCSS files

// ❌ FORBIDDEN - style="" attributes - NEVER USE
<div style="margin-top: 10px;">  // WRONG - Use CSS classes

// ❌ FORBIDDEN - Any form of dynamic inline CSS - NEVER USE
echo '<div style="color: ' . $color . '">';  // WRONG - Use CSS classes
```

**Why this matters:**
- Inline CSS breaks cacheability
- Inline CSS increases page weight
- Inline CSS makes theming impossible
- Inline CSS violates WordPress.org guidelines
- There is ALWAYS a better solution using classes

### Required Patterns (The ONLY Acceptable Ways)
```php
// ✅ CORRECT - All styles in SCSS files
// assets/scss/components/_my-component.scss
.presszone-forum-my-component {
    margin-top: 10px;
}

// ✅ CORRECT - Use utility classes in templates
<div class="presszone-forum-mt-sm">

// ✅ CORRECT - Dynamic values: Use data attributes + CSS
<div data-depth="<?php echo esc_attr($depth); ?>" class="presszone-forum-post">
// Then in CSS: .presszone-forum-post[data-depth="1"] { margin-left: 12px; }

// ✅ CORRECT - Admin-customized colors: Write to static file
$css_file = wp_upload_dir()['basedir'] . '/presszone-forum/custom.css';
file_put_contents($css_file, $css_content);
wp_enqueue_style('presszone-forum-custom', $css_url);
```

### NO EXCEPTIONS - Solutions for "But I need inline CSS because..."

| "Reason" for inline CSS | Correct Solution |
|-------------------------|------------------|
| "Dynamic color from admin" | Write to `custom.css` file on settings save |
| "User-specific value" | Use CSS classes with predefined values |
| "Calculated dimension" | Use CSS `calc()` with variables |
| "Conditional styling" | Add/remove CSS classes with PHP/JS |
| "One-off override" | Create a specific CSS class |
| "Performance" | Static CSS is MORE performant |
| "Quick fix" | Take time to do it right |

For dynamic values like nesting depth, use CSS classes:
```php
// CORRECT - depth class in HTML
<div class="presszone-forum-post presszone-forum-depth-<?php echo esc_attr($depth); ?>">

// CORRECT - CSS defines each level (depth capped at 6)
.presszone-forum-depth-1 { margin-left: 12px; }
.presszone-forum-depth-2 { margin-left: 24px; }
.presszone-forum-depth-3 { margin-left: 36px; }
```

### File Locations
| Style Type | Location |
|------------|----------|
| Base styles | `assets/scss/base/` |
| Components | `assets/scss/components/` |
| Pages | `assets/scss/pages/` |
| Utilities | `assets/scss/utilities/` |
| Variables | `assets/scss/abstracts/_variables.scss` |
| Admin-customized colors | `wp-content/uploads/presszone-forum/custom.css` |

### SCSS Variable Architecture (CRITICAL - NO CSS CUSTOM PROPERTIES)

**Source of truth: `assets/css/abstracts/_variables.scss`**

> **ABSOLUTE RULE**: CSS custom properties (`--presszone-forum-*`, `var()`, `:root {}`) are **STRICTLY FORBIDDEN**. No exceptions. No justifications.

All colors are defined as pure SCSS variables with static hex values:
1. Light mode: `$presszone-forum-primary: #1f71dd;`
2. Dark mode: `$presszone-forum-primary-dark: #60a5fa;`

Components use light mode by default, with explicit `body.dark-mode` overrides.

### Adding New Colors

```scss
// In _variables.scss

// Light mode value
$presszone-forum-new-color: #hex-light;

// Dark mode value (with -dark suffix)
$presszone-forum-new-color-dark: #hex-dark;
```

### Using Colors in Components

```scss
// CORRECT - Light mode default + explicit dark mode override
.presszone-forum-component {
    background: $presszone-forum-new-color;
}

body.dark-mode .presszone-forum-component {
    background: $presszone-forum-new-color-dark;
}

// FORBIDDEN - CSS custom properties (NEVER USE)
background: var(--presszone-forum-new-color);  // NEVER
:root { --presszone-forum-*: value; }          // NEVER
$var: var(--presszone-forum-*);                // NEVER
```

### Admin Design Page & custom.css

**Admin Design page: `/wp-admin/admin.php?page=forum-press-zone#/design`**

The Design page generates `wp-content/uploads/presszone-forum/custom.css` with explicit CSS rules (not CSS custom properties).

**SCSS files with duplicate styles (check ALL when editing):**
- `pages/threads.scss` - main source
- `frontend.scss` - legacy compiled
- `_legacy-frontend.scss` - legacy backup
- `compiled/*.scss` - extracted/compiled
- `extracted/*.scss` - extracted CSS

---

## 9. Key Files Reference

| Purpose | File |
|---------|------|
| Main plugin | `forum-press-zone.php` |
| Plugin orchestrator | `includes/class-presszone-forum-plugin.php` |
| REST base | `includes/api/class-presszone-forum-rest-base.php` |
| Database queries | `includes/class-presszone-forum-query.php` |
| Post creation | `includes/class-presszone-forum-post-creator.php` |
| Permissions | `includes/class-presszone-forum-roles.php` |
| **SCSS Variables (SOURCE OF TRUTH)** | **`assets/css/abstracts/_variables.scss`** |
| Admin CSS | `admin/src-vanilla/styles/main.css` (explicit colors, no CSS custom properties) |
| Admin shared animations | `admin/src-vanilla/styles/_animations.css` |
| Admin tab slide animations | `admin/src-vanilla/styles/_tab-slide-animations.css` |
| Admin Tabs component | `admin/src-vanilla/components/Tabs.js` |
| Admin Toast component | `admin/src-vanilla/components/Toast.js` |
| Build config (frontend) | `package.json` |
| Build config (admin) | `admin/package.json` |

---

## 10. Quick Reference - Prefixes (WordPress.org Compliant)

| Context | Prefix | Example |
|---------|--------|---------|
| SCSS variables (light mode) | `$presszone-forum-` | `$presszone-forum-primary: #1f71dd;` |
| SCSS variables (dark mode) | `$presszone-forum-*-dark` | `$presszone-forum-primary-dark: #60a5fa;` |
| CSS classes | `presszone-forum-` | `.presszone-forum-btn` |
| CSS state classes | `presszone-forum-` | `.presszone-forum-active`, `.presszone-forum-is-open` |
| Dark mode class | `dark-mode` | `body.dark-mode` |
| Keyframes | `presszone-forum-` | `@keyframes presszone-forum-spin` |
| JS globals | `presszoneForumCamelCase` | `presszoneForumData` |
| JS app object | `PresszoneForumApp` | `window.PresszoneForumApp.showToast()` |
| JS dark mode API | `PresszoneForumDarkMode` | `window.PresszoneForumDarkMode.toggle()` |
| PHP namespace | `PresszoneForumPlugin` | `namespace PresszoneForumPlugin;` |
| DB tables | `presszone_forum_` | `wp_presszone_forum_posts` |
| WP options | `presszone_forum_` | `presszone_forum_board_title` |
| Text domain | `forum-press-zone` | `__('Text', 'forum-press-zone')` |

**WordPress.org requires 4+ character prefixes. All code uses `presszone-forum-` prefix.**

Always use role colors when you have a link to a user name in the forum.
