diff --git a/.codex/skills/onboard/SKILL.md b/.codex/skills/onboard/SKILL.md
deleted file mode 100644
index fdf55acb49c..00000000000
--- a/.codex/skills/onboard/SKILL.md
+++ /dev/null
@@ -1,243 +0,0 @@
----
-name: onboard
-description: Design or improve onboarding flows, empty states, and first-time user experiences. Helps users get started successfully and understand value quickly.
-args:
- - name: target
- description: The feature or area needing onboarding (optional)
- required: false
-user-invokable: true
----
-
-Create or improve onboarding experiences that help users understand, adopt, and succeed with the product quickly.
-
-## Assess Onboarding Needs
-
-Understand what users need to learn and why:
-
-1. **Identify the challenge**:
- - What are users trying to accomplish?
- - What's confusing or unclear about current experience?
- - Where do users get stuck or drop off?
- - What's the "aha moment" we want users to reach?
-
-2. **Understand the users**:
- - What's their experience level? (Beginners, power users, mixed?)
- - What's their motivation? (Excited and exploring? Required by work?)
- - What's their time commitment? (5 minutes? 30 minutes?)
- - What alternatives do they know? (Coming from competitor? New to category?)
-
-3. **Define success**:
- - What's the minimum users need to learn to be successful?
- - What's the key action we want them to take? (First project? First invite?)
- - How do we know onboarding worked? (Completion rate? Time to value?)
-
-**CRITICAL**: Onboarding should get users to value as quickly as possible, not teach everything possible.
-
-## Onboarding Principles
-
-Follow these core principles:
-
-### Show, Don't Tell
-- Demonstrate with working examples, not just descriptions
-- Provide real functionality in onboarding, not separate tutorial mode
-- Use progressive disclosure - teach one thing at a time
-
-### Make It Optional (When Possible)
-- Let experienced users skip onboarding
-- Don't block access to product
-- Provide "Skip" or "I'll explore on my own" options
-
-### Time to Value
-- Get users to their "aha moment" ASAP
-- Front-load most important concepts
-- Teach 20% that delivers 80% of value
-- Save advanced features for contextual discovery
-
-### Context Over Ceremony
-- Teach features when users need them, not upfront
-- Empty states are onboarding opportunities
-- Tooltips and hints at point of use
-
-### Respect User Intelligence
-- Don't patronize or over-explain
-- Be concise and clear
-- Assume users can figure out standard patterns
-
-## Design Onboarding Experiences
-
-Create appropriate onboarding for the context:
-
-### Initial Product Onboarding
-
-**Welcome Screen**:
-- Clear value proposition (what is this product?)
-- What users will learn/accomplish
-- Time estimate (honest about commitment)
-- Option to skip (for experienced users)
-
-**Account Setup**:
-- Minimal required information (collect more later)
-- Explain why you're asking for each piece of information
-- Smart defaults where possible
-- Social login when appropriate
-
-**Core Concept Introduction**:
-- Introduce 1-3 core concepts (not everything)
-- Use simple language and examples
-- Interactive when possible (do, don't just read)
-- Progress indication (step 1 of 3)
-
-**First Success**:
-- Guide users to accomplish something real
-- Pre-populated examples or templates
-- Celebrate completion (but don't overdo it)
-- Clear next steps
-
-### Feature Discovery & Adoption
-
-**Empty States**:
-Instead of blank space, show:
-- What will appear here (description + screenshot/illustration)
-- Why it's valuable
-- Clear CTA to create first item
-- Example or template option
-
-Example:
-```
-No projects yet
-Projects help you organize your work and collaborate with your team.
-[Create your first project] or [Start from template]
-```
-
-**Contextual Tooltips**:
-- Appear at relevant moment (first time user sees feature)
-- Point directly at relevant UI element
-- Brief explanation + benefit
-- Dismissable (with "Don't show again" option)
-- Optional "Learn more" link
-
-**Feature Announcements**:
-- Highlight new features when they're released
-- Show what's new and why it matters
-- Let users try immediately
-- Dismissable
-
-**Progressive Onboarding**:
-- Teach features when users encounter them
-- Badges or indicators on new/unused features
-- Unlock complexity gradually (don't show all options immediately)
-
-### Guided Tours & Walkthroughs
-
-**When to use**:
-- Complex interfaces with many features
-- Significant changes to existing product
-- Industry-specific tools needing domain knowledge
-
-**How to design**:
-- Spotlight specific UI elements (dim rest of page)
-- Keep steps short (3-7 steps max per tour)
-- Allow users to click through tour freely
-- Include "Skip tour" option
-- Make replayable (help menu)
-
-**Best practices**:
-- Interactive > passive (let users click real buttons)
-- Focus on workflow, not features ("Create a project" not "This is the project button")
-- Provide sample data so actions work
-
-### Interactive Tutorials
-
-**When to use**:
-- Users need hands-on practice
-- Concepts are complex or unfamiliar
-- High stakes (better to practice in safe environment)
-
-**How to design**:
-- Sandbox environment with sample data
-- Clear objectives ("Create a chart showing sales by region")
-- Step-by-step guidance
-- Validation (confirm they did it right)
-- Graduation moment (you're ready!)
-
-### Documentation & Help
-
-**In-product help**:
-- Contextual help links throughout interface
-- Keyboard shortcut reference
-- Search-able help center
-- Video tutorials for complex workflows
-
-**Help patterns**:
-- `?` icon near complex features
-- "Learn more" links in tooltips
-- Keyboard shortcut hints (`⌘K` shown on search box)
-
-## Empty State Design
-
-Every empty state needs:
-
-### What Will Be Here
-"Your recent projects will appear here"
-
-### Why It Matters
-"Projects help you organize your work and collaborate with your team"
-
-### How to Get Started
-[Create project] or [Import from template]
-
-### Visual Interest
-Illustration or icon (not just text on blank page)
-
-### Contextual Help
-"Need help getting started? [Watch 2-min tutorial]"
-
-**Empty state types**:
-- **First use**: Never used this feature (emphasize value, provide template)
-- **User cleared**: Intentionally deleted everything (light touch, easy to recreate)
-- **No results**: Search or filter returned nothing (suggest different query, clear filters)
-- **No permissions**: Can't access (explain why, how to get access)
-- **Error state**: Failed to load (explain what happened, retry option)
-
-## Implementation Patterns
-
-### Technical approaches:
-
-**Tooltip libraries**: Tippy.js, Popper.js
-**Tour libraries**: Intro.js, Shepherd.js, React Joyride
-**Modal patterns**: Focus trap, backdrop, ESC to close
-**Progress tracking**: LocalStorage for "seen" states
-**Analytics**: Track completion, drop-off points
-
-**Storage patterns**:
-```javascript
-// Track which onboarding steps user has seen
-localStorage.setItem('onboarding-completed', 'true');
-localStorage.setItem('feature-tooltip-seen-reports', 'true');
-```
-
-**IMPORTANT**: Don't show same onboarding twice (annoying). Track completion and respect dismissals.
-
-**NEVER**:
-- Force users through long onboarding before they can use product
-- Patronize users with obvious explanations
-- Show same tooltip repeatedly (respect dismissals)
-- Block all UI during tour (let users explore)
-- Create separate tutorial mode disconnected from real product
-- Overwhelm with information upfront (progressive disclosure!)
-- Hide "Skip" or make it hard to find
-- Forget about returning users (don't show initial onboarding again)
-
-## Verify Onboarding Quality
-
-Test with real users:
-
-- **Time to completion**: Can users complete onboarding quickly?
-- **Comprehension**: Do users understand after completing?
-- **Action**: Do users take desired next step?
-- **Skip rate**: Are too many users skipping? (Maybe it's too long/not valuable)
-- **Completion rate**: Are users completing? (If low, simplify)
-- **Time to value**: How long until users get first value?
-
-Remember: You're a product educator with excellent teaching instincts. Get users to their "aha moment" as quickly as possible. Teach the essential, make it contextual, respect user time and intelligence.
-
diff --git a/.codex/skills/optimize/SKILL.md b/.codex/skills/optimize/SKILL.md
deleted file mode 100644
index 720ccc792d7..00000000000
--- a/.codex/skills/optimize/SKILL.md
+++ /dev/null
@@ -1,269 +0,0 @@
----
-name: optimize
-description: Improve interface performance across loading speed, rendering, animations, images, and bundle size. Makes experiences faster and smoother.
-args:
- - name: target
- description: The feature or area to optimize (optional)
- required: false
-user-invokable: true
----
-
-Identify and fix performance issues to create faster, smoother user experiences.
-
-## Assess Performance Issues
-
-Understand current performance and identify problems:
-
-1. **Measure current state**:
- - **Core Web Vitals**: LCP, FID/INP, CLS scores
- - **Load time**: Time to interactive, first contentful paint
- - **Bundle size**: JavaScript, CSS, image sizes
- - **Runtime performance**: Frame rate, memory usage, CPU usage
- - **Network**: Request count, payload sizes, waterfall
-
-2. **Identify bottlenecks**:
- - What's slow? (Initial load? Interactions? Animations?)
- - What's causing it? (Large images? Expensive JavaScript? Layout thrashing?)
- - How bad is it? (Perceivable? Annoying? Blocking?)
- - Who's affected? (All users? Mobile only? Slow connections?)
-
-**CRITICAL**: Measure before and after. Premature optimization wastes time. Optimize what actually matters.
-
-## Optimization Strategy
-
-Create systematic improvement plan:
-
-### Loading Performance
-
-**Optimize Images**:
-- Use modern formats (WebP, AVIF)
-- Proper sizing (don't load 3000px image for 300px display)
-- Lazy loading for below-fold images
-- Responsive images (`srcset`, `picture` element)
-- Compress images (80-85% quality is usually imperceptible)
-- Use CDN for faster delivery
-
-```html
-
-```
-
-**Reduce JavaScript Bundle**:
-- Code splitting (route-based, component-based)
-- Tree shaking (remove unused code)
-- Remove unused dependencies
-- Lazy load non-critical code
-- Use dynamic imports for large components
-
-```javascript
-// Lazy load heavy component
-const HeavyChart = lazy(() => import('./HeavyChart'));
-```
-
-**Optimize CSS**:
-- Remove unused CSS
-- Critical CSS inline, rest async
-- Minimize CSS files
-- Use CSS containment for independent regions
-
-**Optimize Fonts**:
-- Use `font-display: swap` or `optional`
-- Subset fonts (only characters you need)
-- Preload critical fonts
-- Use system fonts when appropriate
-- Limit font weights loaded
-
-```css
-@font-face {
- font-family: 'CustomFont';
- src: url('/fonts/custom.woff2') format('woff2');
- font-display: swap; /* Show fallback immediately */
- unicode-range: U+0020-007F; /* Basic Latin only */
-}
-```
-
-**Optimize Loading Strategy**:
-- Critical resources first (async/defer non-critical)
-- Preload critical assets
-- Prefetch likely next pages
-- Service worker for offline/caching
-- HTTP/2 or HTTP/3 for multiplexing
-
-### Rendering Performance
-
-**Avoid Layout Thrashing**:
-```javascript
-// ❌ Bad: Alternating reads and writes (causes reflows)
-elements.forEach(el => {
- const height = el.offsetHeight; // Read (forces layout)
- el.style.height = height * 2; // Write
-});
-
-// ✅ Good: Batch reads, then batch writes
-const heights = elements.map(el => el.offsetHeight); // All reads
-elements.forEach((el, i) => {
- el.style.height = heights[i] * 2; // All writes
-});
-```
-
-**Optimize Rendering**:
-- Use CSS `contain` property for independent regions
-- Minimize DOM depth (flatter is faster)
-- Reduce DOM size (fewer elements)
-- Use `content-visibility: auto` for long lists
-- Virtual scrolling for very long lists (react-window, react-virtualized)
-
-**Reduce Paint & Composite**:
-- Use `transform` and `opacity` for animations (GPU-accelerated)
-- Avoid animating layout properties (width, height, top, left)
-- Use `will-change` sparingly for known expensive operations
-- Minimize paint areas (smaller is faster)
-
-### Animation Performance
-
-**GPU Acceleration**:
-```css
-/* ✅ GPU-accelerated (fast) */
-.animated {
- transform: translateX(100px);
- opacity: 0.5;
-}
-
-/* ❌ CPU-bound (slow) */
-.animated {
- left: 100px;
- width: 300px;
-}
-```
-
-**Smooth 60fps**:
-- Target 16ms per frame (60fps)
-- Use `requestAnimationFrame` for JS animations
-- Debounce/throttle scroll handlers
-- Use CSS animations when possible
-- Avoid long-running JavaScript during animations
-
-**Intersection Observer**:
-```javascript
-// Efficiently detect when elements enter viewport
-const observer = new IntersectionObserver((entries) => {
- entries.forEach(entry => {
- if (entry.isIntersecting) {
- // Element is visible, lazy load or animate
- }
- });
-});
-```
-
-### React/Framework Optimization
-
-**React-specific**:
-- Use `memo()` for expensive components
-- `useMemo()` and `useCallback()` for expensive computations
-- Virtualize long lists
-- Code split routes
-- Avoid inline function creation in render
-- Use React DevTools Profiler
-
-**Framework-agnostic**:
-- Minimize re-renders
-- Debounce expensive operations
-- Memoize computed values
-- Lazy load routes and components
-
-### Network Optimization
-
-**Reduce Requests**:
-- Combine small files
-- Use SVG sprites for icons
-- Inline small critical assets
-- Remove unused third-party scripts
-
-**Optimize APIs**:
-- Use pagination (don't load everything)
-- GraphQL to request only needed fields
-- Response compression (gzip, brotli)
-- HTTP caching headers
-- CDN for static assets
-
-**Optimize for Slow Connections**:
-- Adaptive loading based on connection (navigator.connection)
-- Optimistic UI updates
-- Request prioritization
-- Progressive enhancement
-
-## Core Web Vitals Optimization
-
-### Largest Contentful Paint (LCP < 2.5s)
-- Optimize hero images
-- Inline critical CSS
-- Preload key resources
-- Use CDN
-- Server-side rendering
-
-### First Input Delay (FID < 100ms) / INP (< 200ms)
-- Break up long tasks
-- Defer non-critical JavaScript
-- Use web workers for heavy computation
-- Reduce JavaScript execution time
-
-### Cumulative Layout Shift (CLS < 0.1)
-- Set dimensions on images and videos
-- Don't inject content above existing content
-- Use `aspect-ratio` CSS property
-- Reserve space for ads/embeds
-- Avoid animations that cause layout shifts
-
-```css
-/* Reserve space for image */
-.image-container {
- aspect-ratio: 16 / 9;
-}
-```
-
-## Performance Monitoring
-
-**Tools to use**:
-- Chrome DevTools (Lighthouse, Performance panel)
-- WebPageTest
-- Core Web Vitals (Chrome UX Report)
-- Bundle analyzers (webpack-bundle-analyzer)
-- Performance monitoring (Sentry, DataDog, New Relic)
-
-**Key metrics**:
-- LCP, FID/INP, CLS (Core Web Vitals)
-- Time to Interactive (TTI)
-- First Contentful Paint (FCP)
-- Total Blocking Time (TBT)
-- Bundle size
-- Request count
-
-**IMPORTANT**: Measure on real devices with real network conditions. Desktop Chrome with fast connection isn't representative.
-
-**NEVER**:
-- Optimize without measuring (premature optimization)
-- Sacrifice accessibility for performance
-- Break functionality while optimizing
-- Use `will-change` everywhere (creates new layers, uses memory)
-- Lazy load above-fold content
-- Optimize micro-optimizations while ignoring major issues (optimize the biggest bottleneck first)
-- Forget about mobile performance (often slower devices, slower connections)
-
-## Verify Improvements
-
-Test that optimizations worked:
-
-- **Before/after metrics**: Compare Lighthouse scores
-- **Real user monitoring**: Track improvements for real users
-- **Different devices**: Test on low-end Android, not just flagship iPhone
-- **Slow connections**: Throttle to 3G, test experience
-- **No regressions**: Ensure functionality still works
-- **User perception**: Does it *feel* faster?
-
-Remember: Performance is a feature. Fast experiences feel more responsive, more polished, more professional. Optimize systematically, measure ruthlessly, and prioritize user-perceived performance.
-
diff --git a/.codex/skills/review/SKILL.md b/.codex/skills/review/SKILL.md
deleted file mode 100644
index 88f24150ccd..00000000000
--- a/.codex/skills/review/SKILL.md
+++ /dev/null
@@ -1,78 +0,0 @@
----
-name: review
-version: 1.0.0
-description: |
- Pre-landing PR review. Analyzes diff against main for SQL safety, LLM trust
- boundary violations, conditional side effects, and other structural issues.
-allowed-tools:
- - Bash
- - Read
- - Edit
- - Write
- - Grep
- - Glob
- - AskUserQuestion
----
-
-# Pre-Landing PR Review
-
-You are running the `/review` workflow. Analyze the current branch's diff against main for structural issues that tests don't catch.
-
----
-
-## Step 1: Check branch
-
-1. Run `git branch --show-current` to get the current branch.
-2. If on `main`, output: **"Nothing to review — you're on main or have no changes against main."** and stop.
-3. Run `git fetch origin main --quiet && git diff origin/main --stat` to check if there's a diff. If no diff, output the same message and stop.
-
----
-
-## Step 2: Read the checklist
-
-Read `checklist.md`.
-
-**If the file cannot be read, STOP and report the error.** Do not proceed without the checklist.
-
----
-
-## Step 3: Get the diff
-
-Fetch the latest main to avoid false positives from a stale local main:
-
-```bash
-git fetch origin main --quiet
-```
-
-Run `git diff origin/main` to get the full diff. This includes both committed and uncommitted changes against the latest main.
-
----
-
-## Step 4: Two-pass review
-
-Apply the checklist against the diff in two passes:
-
-1. **Pass 1 (CRITICAL):** SQL & Data Safety, LLM Output Trust Boundary
-2. **Pass 2 (INFORMATIONAL):** Conditional Side Effects, Magic Numbers & String Coupling, Dead Code & Consistency, LLM Prompt Issues, Test Gaps, View/Frontend
-
-Follow the output format specified in the checklist. Respect the suppressions — do NOT flag items listed in the "DO NOT flag" section.
-
----
-
-## Step 5: Output findings
-
-**Always output ALL findings** — both critical and informational. The user must see every issue.
-
-- If CRITICAL issues found: output all findings, then for EACH critical issue use a separate AskUserQuestion with the problem, your recommended fix, and options (A: Fix it now, B: Acknowledge, C: False positive — skip).
- After all critical questions are answered, output a summary of what the user chose for each issue. If the user chose A (fix) on any issue, apply the recommended fixes. If only B/C were chosen, no action needed.
-- If only non-critical issues found: output findings. No further action needed.
-- If no issues found: output `Pre-Landing Review: No issues found.`
-
----
-
-## Important Rules
-
-- **Read the FULL diff before commenting.** Do not flag issues already addressed in the diff.
-- **Read-only by default.** Only modify files if the user explicitly chooses "Fix it now" on a critical issue. Never commit, push, or create PRs.
-- **Be terse.** One line problem, one line fix. No preamble.
-- **Only flag real problems.** Skip anything that's fine.
diff --git a/.codex/skills/review/checklist.md b/.codex/skills/review/checklist.md
deleted file mode 100644
index e3218900b14..00000000000
--- a/.codex/skills/review/checklist.md
+++ /dev/null
@@ -1,125 +0,0 @@
-# Pre-Landing Review Checklist
-
-## Instructions
-
-Review the `git diff origin/main` output for the issues listed below. Be specific — cite `file:line` and suggest fixes. Skip anything that's fine. Only flag real problems.
-
-**Two-pass review:**
-- **Pass 1 (CRITICAL):** Run SQL & Data Safety and LLM Output Trust Boundary first. These can block `/ship`.
-- **Pass 2 (INFORMATIONAL):** Run all remaining categories. These are included in the PR body but do not block.
-
-**Output format:**
-
-```
-Pre-Landing Review: N issues (X critical, Y informational)
-
-**CRITICAL** (blocking /ship):
-- [file:line] Problem description
- Fix: suggested fix
-
-**Issues** (non-blocking):
-- [file:line] Problem description
- Fix: suggested fix
-```
-
-If no issues found: `Pre-Landing Review: No issues found.`
-
-Be terse. For each issue: one line describing the problem, one line with the fix. No preamble, no summaries, no "looks good overall."
-
----
-
-## Review Categories
-
-### Pass 1 — CRITICAL
-
-#### SQL & Data Safety
-- String interpolation in SQL (even if values are `.to_i`/`.to_f` — use `sanitize_sql_array` or Arel)
-- TOCTOU races: check-then-set patterns that should be atomic `WHERE` + `update_all`
-- `update_column`/`update_columns` bypassing validations on fields that have or should have constraints
-- N+1 queries: `.includes()` missing for associations used in loops/views (especially avatar, attachments)
-
-#### Race Conditions & Concurrency
-- Read-check-write without uniqueness constraint or `rescue RecordNotUnique; retry` (e.g., `where(hash:).first` then `save!` without handling concurrent insert)
-- `find_or_create_by` on columns without unique DB index — concurrent calls can create duplicates
-- Status transitions that don't use atomic `WHERE old_status = ? UPDATE SET new_status` — concurrent updates can skip or double-apply transitions
-- `html_safe` on user-controlled data (XSS) — check any `.html_safe`, `raw()`, or string interpolation into `html_safe` output
-
-#### LLM Output Trust Boundary
-- LLM-generated values (emails, URLs, names) written to DB or passed to mailers without format validation. Add lightweight guards (`EMAIL_REGEXP`, `URI.parse`, `.strip`) before persisting.
-- Structured tool output (arrays, hashes) accepted without type/shape checks before database writes.
-
-### Pass 2 — INFORMATIONAL
-
-#### Conditional Side Effects
-- Code paths that branch on a condition but forget to apply a side effect on one branch. Example: item promoted to verified but URL only attached when a secondary condition is true — the other branch promotes without the URL, creating an inconsistent record.
-- Log messages that claim an action happened but the action was conditionally skipped. The log should reflect what actually occurred.
-
-#### Magic Numbers & String Coupling
-- Bare numeric literals used in multiple files — should be named constants documented together
-- Error message strings used as query filters elsewhere (grep for the string — is anything matching on it?)
-
-#### Dead Code & Consistency
-- Variables assigned but never read
-- Version mismatch between PR title and VERSION/CHANGELOG files
-- CHANGELOG entries that describe changes inaccurately (e.g., "changed from X to Y" when X never existed)
-- Comments/docstrings that describe old behavior after the code changed
-
-#### LLM Prompt Issues
-- 0-indexed lists in prompts (LLMs reliably return 1-indexed)
-- Prompt text listing available tools/capabilities that don't match what's actually wired up in the `tool_classes`/`tools` array
-- Word/token limits stated in multiple places that could drift
-
-#### Test Gaps
-- Negative-path tests that assert type/status but not the side effects (URL attached? field populated? callback fired?)
-- Assertions on string content without checking format (e.g., asserting title present but not URL format)
-- `.expects(:something).never` missing when a code path should explicitly NOT call an external service
-- Security enforcement features (blocking, rate limiting, auth) without integration tests verifying the enforcement path works end-to-end
-
-#### Crypto & Entropy
-- Truncation of data instead of hashing (last N chars instead of SHA-256) — less entropy, easier collisions
-- `rand()` / `Random.rand` for security-sensitive values — use `SecureRandom` instead
-- Non-constant-time comparisons (`==`) on secrets or tokens — vulnerable to timing attacks
-
-#### Time Window Safety
-- Date-key lookups that assume "today" covers 24h — report at 8am PT only sees midnight→8am under today's key
-- Mismatched time windows between related features — one uses hourly buckets, another uses daily keys for the same data
-
-#### Type Coercion at Boundaries
-- Values crossing Ruby→JSON→JS boundaries where type could change (numeric vs string) — hash/digest inputs must normalize types
-- Hash/digest inputs that don't call `.to_s` or equivalent before serialization — `{ cores: 8 }` vs `{ cores: "8" }` produce different hashes
-
-#### View/Frontend
-- Inline `