SKILL.md
---
name: preflight
description: "Proactive code quality gate for IAM v2 website. Auto-validates architecture, component reuse, iframe patterns, state management, Tailwind/claymorphism design system compliance, and token efficiency BEFORE writing code. Triggers on any edit, create, fix, build, refactor, or improve task touching React/TSX files."
paths: src/app/**/*.tsx,src/app/**/*.ts
disable-model-invocation: false
user-invocable: true
---
# Preflight — Proactive Quality Gate
You are a silent quality monitor. BEFORE writing or editing any code in the IAM v2 directory, run through this checklist internally. **Only speak up when you catch an issue** that would waste tokens or cause bugs if implemented wrong. Be concise — flag the issue, state the fix, move on. If everything checks out, proceed silently.
## When to Apply
### Must Use (auto-trigger)
- Creating new pages or components in `src/app/iam-v2/`
- Editing existing IAM v2 components
- Fixing bugs in IAM v2 pages
- Refactoring or improving IAM v2 code
- Adding features to any IAM v2 page
### Skip
- Backend API work outside `src/app/iam-v2/`
- Database/Prisma changes
- Test files
- Configuration changes
---
## P0 — STOP THE BUILD (Architecture Traps)
These patterns cause hard-to-debug failures. Flag IMMEDIATELY before any code is written.
### Iframe & Embed Rules
| Rule | What Goes Wrong | Correct Pattern |
|------|----------------|-----------------|
| NEVER place `<iframe>` inside a collapsible/animated container (accordion, `max-h` transition, expandable card) | Iframe fails to load while parent dimensions are transitioning | **Selector/Viewer pattern**: grid of clickable cards as selectors, single persistent viewer component in a fixed DOM position below the grid |
| NEVER change iframe `src` without remounting | Stale content, loading failures | Use React `key={uniqueId}` on the iframe to force clean remount |
| NEVER reset loading state AFTER changing content index | Loading skeleton flashes incorrectly or doesn't appear | Reset `setIframeLoaded(false)` BEFORE calling `setSelectedIndex(newIndex)` |
| Google Drive embed URLs | Wrong URL pattern = blank iframe | `/preview` for iframe `src`, `/view` for "open in new tab" links |
### Component Reuse — Check BEFORE Creating
Before writing ANY new component, check if `src/app/shared.tsx` already exports it:
| Available Component | Purpose |
|---|---|
| `ClayCard` | Claymorphism card with soft shadows, optional hover effect |
| `ClayInput` | Styled form input |
| `ClayRadioGroup` | Radio button group |
| `ClayCheckbox` | Styled checkbox |
| `ClaySubmitButton` | Form submit button with loading state |
| `FormPageLayout` | Full page layout with title, subtitle, badge, back navigation |
| `FormSection` | Collapsible form section |
| `Tooltip` | Claymorphism tooltip with `group/tip` hover pattern, top/bottom positioning |
**If a component will be used on 2+ pages, add it to `shared.tsx` immediately.**
### State Management
- Don't create redundant state. If `selectedIndex !== null` means "open", don't also track `isOpen`.
- Reset dependent states atomically in the same handler, before the primary state change.
- Avoid `useEffect` for derived values — compute inline or use `useMemo`.
---
## P1 — QUALITY CHECKS (Run Every Time)
### Tailwind & Claymorphism Design System
| Token | Value | Notes |
|-------|-------|-------|
| Page background | `#FAF5F2` | Warm cream — all ring-offsets must match: `ring-offset-[#FAF5F2]` |
| Primary color | emerald-600 (`#059669`) | Buttons, links, active states |
| Accent color | amber-600 (`#D97706`) | Highlights, badges, warnings |
| Card style | `ClayCard` from shared.tsx | Never invent new shadow values |
| Small radius | `rounded-xl` | Buttons, inputs, small elements |
| Card radius | `rounded-2xl` | Cards, modals, large containers |
| Pill radius | `rounded-full` | Tags, badges, dot indicators |
| Font heading | `font-heading` class | All `<h1>` through `<h3>` elements |
| Icon library | Lucide React only | No emoji, no other icon libraries |
| Gradient icons | `bg-gradient-to-br from-{color}-500 to-{color}-600` | For icon background circles |
### CSS Patterns
- **Scoped hover**: Use `group/name` (e.g., `group/tip`) for nested hover states, not bare `group`.
- **z-index layers**: tooltips (`z-50`), modals (`z-[9999]`), overlays (`z-30`), loading skeletons (`z-10`).
- **Cursor**: `cursor-pointer` on all clickable non-link elements.
- **Transitions**: `transition-all duration-300` for most interactions; `duration-500` for iframe opacity fades.
- **Selection ring**: `ring-2 ring-emerald-500 ring-offset-2 ring-offset-[#FAF5F2]`.
- **Whitespace**: `whitespace-nowrap` on tooltip text.
### Accessibility Quick Wins
- Every `<button>` with only an icon needs `aria-label`.
- External links: `target="_blank" rel="noopener noreferrer"`.
- Loading states need descriptive text, not just a spinner.
- Images need meaningful `alt` text.
### Next.js / React
- `"use client"` directive required for any component using `useState`, `useEffect`, `useRef`, or event handlers.
- `import Link from "next/link"` for internal navigation; `<a>` for external links.
- `<img>` for external/dynamic URLs; Next.js `<Image>` for static assets only.
---
## P2 — TOKEN EFFICIENCY (Save Money)
### Before Writing Code
1. **READ the file first.** Never guess at structure, imports, or existing patterns.
2. **Check shared.tsx** before building anything custom.
3. **Plan the component tree mentally**: what's the simplest architecture that works?
4. **If a change touches 3+ files**, outline the plan before starting.
### While Writing Code
1. **Batch related edits** — don't make 5 small `Edit` calls to the same file when 1 comprehensive edit works.
2. **Match existing code style exactly** — indentation, naming conventions, import order.
3. **No noise** — no `console.log`, no comments explaining obvious code, no `TODO` comments.
4. **Surgical changes only** — don't refactor surrounding code unless asked.
### After Writing Code
1. **Don't re-read files you just wrote** — the Edit tool confirms success.
2. **One Playwright screenshot is enough** for visual verification.
3. **Don't take multiple screenshots** of the same thing from different angles.
---
## PROACTIVE INTERVENTIONS
When you detect the user is about to do any of the following, **flag it before writing code**:
| User is about to... | Say this |
|---|---|
| Put an iframe inside an accordion/collapsible | "Iframes in animated containers break. Use the Selector/Viewer pattern instead — cards select, persistent viewer below displays." |
| Create a tooltip component | "Tooltip already exists in shared.tsx. Import it: `import { Tooltip } from '../../shared'`" |
| Duplicate a pattern from another page | "This pattern exists in shared.tsx as `{ComponentName}`. Import it instead of duplicating." |
| Make multiple small edits to one file | "I'll batch these into a single edit to save tokens." |
| Read a file they just wrote | "No need to re-read — the Edit tool confirmed the write succeeded." |
| Add state derivable from existing state | "This is derivable from `{existingState}` — no need for separate state." |
| Use bare `group` for nested hover | "Use `group/name` for scoped hover to avoid conflicts with parent groups." |
| Use wrong ring-offset color | "Ring offset must match the page background: `ring-offset-[#FAF5F2]`" |
| Forget `cursor-pointer` on buttons | "Add `cursor-pointer` to clickable elements." |
| Forget `aria-label` on icon buttons | "Icon-only buttons need `aria-label` for accessibility." |