diff --git a/COMPONENT_DEVELOPMENT_TENETS.md b/COMPONENT_DEVELOPMENT_TENETS.md
new file mode 100644
index 0000000000..338b29ba85
--- /dev/null
+++ b/COMPONENT_DEVELOPMENT_TENETS.md
@@ -0,0 +1,1076 @@
+# PIE Web Component Development Tenets
+
+This document outlines the core principles, patterns, and requirements for building web components in the PIE Design System. These tenets ensure consistency, quality, and maintainability across all components.
+
+---
+
+## Summary
+
+These tenets guide every decision in PIE component development:
+
+1. [**Controlled components**](#controlled-components) — State flows down, events flow up
+2. [**SSR compatible**](#ssr-compatibility) — No browser APIs during render
+3. [**Native APIs first**](#native-browser-apis-first) — Browser APIs over custom implementations
+4. [**Framework agnostic**](#framework-agnostic) — Web standards over framework abstractions
+5. [**Consistent APIs**](#property-naming-consistency) — Same names for same concepts
+6. [**Boolean naming**](#boolean-property-naming) — Use `is`/`has` prefixes for booleans
+7. [**Event conventions**](#event-conventions) — Prefix custom events with `pie-`
+8. [**Design tokens**](#design-token-usage) — Use tokens, not hardcoded values
+9. [**CSS variable overrides**](#css-variable-overrides) — Override variables, not properties
+10. [**CSS over JavaScript**](#css-over-javascript) — Prefer declarative CSS solutions
+11. [**Logical CSS properties**](#logical-css-properties) — Use logical properties for RTL support
+12. [**Reduced motion**](#reduced-motion-support) — Respect `prefers-reduced-motion`
+13. [**PIE icons only**](#icons-from-pie-icons-webc-only) — Use `pie-icons-webc`, nothing else
+14. [**Limited customisation**](#limited-style-customisation) — Consistency over flexibility
+15. [**Use the generator**](#use-the-component-generator) — Always scaffold new components with the generator
+16. [**Composition via mixins**](#mixin-based-composition) — Lean components, shared behaviours
+17. [**Reusable decorators**](#custom-decorators) — Extract property-level logic into decorators
+18. [**Bundle size awareness**](#bundle-size-awareness) — Monitor size, justify increases
+19. [**Semantic HTML**](#semantic-valid-html) — Valid, meaningful markup even inside shadow DOM
+20. [**JSDoc for slots/events**](#jsdoc-for-slots-and-events) — Required for manifest and React type generation
+21. [**Clean up listeners**](#event-listener-cleanup) — Use AbortController for event listener removal
+22. [**React types verified**](#react-integration) — Generated React interfaces must be inspected
+23. [**Browser-tested**](#browser-based-testing) — Real browsers, not simulated environments
+24. [**User-focused testing**](#user-focused-testing) — Test behaviour, not implementation
+25. [**Accessible by default**](#accessibility-testing) — WCAG 2.1 AA compliance
+26. [**Visual regression**](#visual-regression-testing) — Percy tests for visual changes
+27. [**Fully documented**](#storybook-documentation) — Storybook and README for every component
+28. [**Integration proven**](#integration-testing-pie-aperture) — Validated in pie-aperture across frameworks
+
+---
+
+## Core Philosophy
+
+### Controlled Components
+
+Components in PIE do not manage their own state. They are "views" of state provided by the consuming application.
+
+**The principle:** A component receives its state through properties and emits events to signal user intent. It never mutates its own state in response to user actions.
+
+**Example — Modal:**
+```typescript
+// The modal receives `isOpen` as a property
+...
+
+// When the user clicks the close button, the modal emits an event
+// but does NOT close itself
+this.dispatchEvent(new CustomEvent('pie-modal-close'));
+
+// The consumer handles the event and updates the state
+modal.addEventListener('pie-modal-close', () => {
+ this.isModalOpen = false; // Consumer controls the state
+});
+```
+
+**Why this matters:**
+- **Predictability:** State changes are explicit and traceable. There's no hidden internal state that can get out of sync with your application.
+- **Testability:** Tests control component state directly via properties and assert outputs. No need to simulate complex interaction sequences to reach a particular state.
+- **Framework integration:** Works naturally with React, Vue, Angular, and other frameworks' state management patterns. The component doesn't fight against unidirectional data flow.
+- **Debugging:** When something goes wrong, the state flow is clear. The component shows what it's told to show.
+
+**Internal UI state exception:** Purely visual, non-semantic state (hover effects, focus rings, animation progress) can be managed internally as it doesn't affect the component's "value" or semantic state.
+
+---
+
+### SSR Compatibility
+
+Every component must work with server-side rendering. Components must not rely on browser APIs during initial render.
+
+**The principle:** Components should render meaningful output on the server without access to `window`, `document`, `localStorage`, or other browser-only APIs.
+
+**Why this matters:**
+- PIE components are used in Next.js, Nuxt, and other SSR frameworks
+- Server-rendered pages improve performance and SEO
+- Hydration errors occur when server and client output differ
+
+**Guidelines:**
+- Never access browser APIs at the module level or during construction
+- Guard browser API usage behind lifecycle callbacks (`connectedCallback`, `firstUpdated`) or environment checks
+- Avoid side effects during property initialization
+
+```typescript
+// ❌ Bad: Browser API at construction
+constructor() {
+ super();
+ this.viewportWidth = window.innerWidth;
+}
+
+// ✅ Good: Browser API in lifecycle callback
+connectedCallback() {
+ super.connectedCallback();
+ if (typeof window !== 'undefined') {
+ this.viewportWidth = window.innerWidth;
+ }
+}
+```
+
+---
+
+### Native Browser APIs First
+
+When implementing component behaviour, prioritise native browser APIs over custom implementations.
+
+**The principle:** The browser provides well-tested, accessible, and performant APIs for many common behaviours. Custom implementations should only be used when native APIs are insufficient.
+
+**Examples:**
+
+| Behavior | Prefer | Avoid |
+|----------|--------|-------|
+| Form submission | `ElementInternals` API via `FormControlMixin` | Custom form handling |
+| Focus management | Native `focus()`, `tabindex`, `delegatesFocus` | Custom focus tracking |
+| Dialogs | `