diff --git a/.agents/skills/opencloud-style/SKILL.md b/.agents/skills/opencloud-style/SKILL.md
index 87d6890..0ecd878 100644
--- a/.agents/skills/opencloud-style/SKILL.md
+++ b/.agents/skills/opencloud-style/SKILL.md
@@ -1,354 +1,235 @@
---
name: opencloud-style
-description: "Use when modifying OpenCloud visual design, Tailwind classes, component styling, layout, typography, or page-level visual hierarchy. Ensures the project keeps its current clean sky-atlas visual language — airy, fresh, bright, observational — and avoids inconsistent dark or purple defaults."
+description: "Maintain OpenCloud's current visual system when changing Vue templates, Tailwind classes, CSS, Naive UI theming, layout, typography, colors, buttons, cards, modals, maps, or responsive behavior. Preserve the clean sky-atlas language: airy sky-blue surfaces, fresh eucalyptus green, square atlas-like panels, pixel-cloud identity, and hard offset shadows."
---
# OpenCloud Visual Style
-Use this skill whenever changing OpenCloud visual design, component styling, Tailwind classes, layout, typography, or any page-level appearance.
+Treat the current design tokens and shared `oc-*` classes as the visual contract. Keep the interface airy, bright, observational, and slightly editorial—like a field atlas for clouds.
+
+## Start From the Sources of Truth
+
+Inspect these files before making a material visual change:
+
+1. `src/styles/tokens.css` — palette remapping, semantic colors, gradients, shadows, motion.
+2. `src/styles/base.css` — body baseline and the global square-corner rule.
+3. `src/styles/components.css` — reusable page, surface, form, and interaction contracts.
+4. `src/lib/theme.ts` — Naive UI overrides; keep semantic colors aligned with `tokens.css`.
+5. `docs/style-system.md` — naming and implementation guidance.
+6. `scripts/check-style-system.mjs` — prohibited legacy patterns.
+
+Use `src/style.css` only as the stylesheet assembly point. Put stable values in `tokens.css`, cross-page patterns in `components.css`, and truly component-specific behavior in scoped styles.
## Visual Direction
-OpenCloud should feel like a clean sky atlas: airy, fresh, bright, and observational.
+- Use white, slate-50, sky-50, and soft translucent white for primary surfaces.
+- Use sky blue for atmosphere, page heroes, upload/create actions, and the pixel-cloud brand surface.
+- Use fresh eucalyptus green for identity, navigation selection, account access, confirmation, and interactive hover states.
+- Use leaf green only for explicit success, approved, public, or completed states.
+- Use amber for pending/review/uncommon states and rose/red for destructive/rejected states.
+- Keep slate-900 text dominant. Do not turn normal page sections into dark panels.
+- Avoid purple, indigo, generic gray utilities, neon green, and decorative color proliferation.
-- Base surfaces: `white`, `slate-50`, `sky-50`, soft translucent white (`bg-white/80`, `bg-white/88`).
-- Main accent: teal/cyan for navigation, identity, account surfaces.
-- Secondary accent: sky blue for upload and action highlights.
-- Supporting accent: amber only for rarity, badges, pending/review states.
-- Danger accent: rose/red only for destructive or rejected states.
-- Avoid purple as a default accent.
-- Avoid black selected states except for text or rare high-contrast badges.
+## Current Palette
----
+Tailwind `teal-*` and `emerald-*` are compatibility names remapped in `tokens.css`; they are not Tailwind defaults.
+
+| Role | Main | Dark | Light surface |
+| --- | --- | --- | --- |
+| Eucalyptus brand/interaction | `#34745d` | `#274c40` | `#f2faf6` |
+| Leaf success | `#4d7f3b` | `#35522c` | `#f4faef` |
+| Sky information/action | `#0369a1` | `#075985` | `#e0f2fe` |
+| Canvas | `#eef4f8` | — | `#f8fbfd` |
+| Primary text | `#0f172a` | — | — |
+| Secondary text | `#334155` | — | — |
+| Muted text | `#64748b` | — | — |
+| Border | `#d9e3ee` | — | — |
+
+Rules:
+
+- Do not use Tailwind `green-*` or `lime-*`.
+- Do not reintroduce Tailwind's vivid teal values such as `#14b8a6` or `#0f766e`.
+- Use semantic tokens or existing `teal-*`/`emerald-*` compatibility utilities instead of new hard-coded greens.
+- Keep green text and actions dark enough for readable contrast; use pale green primarily as a surface.
+- Synchronize changes to brand or success colors between `tokens.css` and `src/lib/theme.ts`.
+
+## Shape and Border Rules
+
+The product is square by default. `src/styles/base.css` forces Tailwind `rounded*` utilities to `0px`.
+
+- Use square corners for page panels, cards, buttons, inputs, navigation, dropdowns, map controls, and ordinary modals.
+- Use a one-pixel slate or semantic-color border to define surfaces.
+- Do not add rounded rectangles as a generic polish treatment.
+
+Documented exceptions:
+
+- Circular close/overlay controls in `ImageDetailModal`.
+- Circular location/marker dots and AMap-generated marker bubbles.
+- The media-focused `ImageDetailModal` shell.
+- AMap-generated information cards and the deliberately organic timeline control details in `MapView`.
+
+Do not treat map floating buttons as exceptions: `.oc-map-button` is a square `40px × 40px` control with `0px` radius and a hard shadow, including its disabled state.
+
+## Shadows and Interaction
+
+Use hard offset shadows with zero blur as the signature depth treatment:
+
+| Token | Value | Typical use |
+| --- | --- | --- |
+| `--oc-shadow-xs` | `3px 3px` | Small controls and map buttons |
+| `--oc-shadow-sm` | `4px 4px` | Header logo and compact CTAs |
+| `--oc-shadow-md` | `6px 6px` | Standard cards and navigation |
+| `--oc-shadow-lg` | `8px 8px` | Menus and floating panels |
+| `--oc-shadow-xl` | `12px 12px` | Large system/auth cards |
+| `--oc-shadow-sky` | sky-tinted `4px 4px` | Sky actions |
+| `--oc-shadow-primary` | eucalyptus-tinted `4px 4px` | Green interactions |
+
+- On hover, interactive controls may move `translate(-1px, -1px)` and grow the hard shadow.
+- On active, return the control to its origin.
+- Preserve a visible `2px` sky focus outline with offset.
+- Do not replace the hard-shadow language with generic soft shadows across ordinary UI.
+- Soft/blurred shadows remain acceptable for media overlays, AMap internals, and image hover depth.
+
+## Backgrounds and Brand Identity
+
+Use the semantic gradients in `tokens.css`:
+
+- App shell: a subtle eucalyptus radial glow over the pale blue-gray canvas.
+- Standard page hero: `#e0f2fe` to `#f8fafc`.
+- Soft page hero: `#f2faf6` to `#f8fafc`.
+- App grid: subtle slate lines at `32px`.
+
+The header identity is fixed:
+
+- Use the pixel-style cloud/sun SVG, not an emoji or unrelated icon set.
+- Put the icon in a square `40px` container with `bg-sky-100`, `border-sky-200`, and a `4px 4px` neutral hard shadow.
+- Keep “LIVE SKY ATLAS” as the small tracked eyebrow and “OpenCloud” as the bold brand name.
+- Keep the header white/translucent; green belongs to navigation and account interaction, not the logo background.
## Typography
-**Font stack** (`src/style.css`, `App.vue`):
-```
+Use:
+
+```text
"IBM Plex Sans", "Noto Sans SC", "PingFang SC", sans-serif
```
-Monospace: `"IBM Plex Mono", "SFMono-Regular", monospace`
-**Type scale:**
+Use IBM Plex Mono for small atlas-like labels when a monospace accent is appropriate.
-| Size | Use |
-|------|-----|
-| `text-[11px]` | Header subtitle, heatmap weekday labels |
-| `text-xs` | Uppercase section labels, captions, metadata, tags, help text |
-| `text-sm` | Body text, descriptions, nav items, form labels, detail sections |
-| `text-base` | Hero description paragraphs |
-| `text-lg` | Logo brand name, card titles, item counters |
-| `text-xl` | Modal titles, subsection headings, stat cards |
-| `text-2xl` | Subsection headings, stat values, settings section titles |
-| `text-3xl` | Stat values, avatar initials |
-| `text-4xl` | Page H1 headings (all page heroes) |
-| `text-5xl` | Login/Register hero text only |
-| `text-6xl`+ | Decorative single characters, error page emoji |
+- Page eyebrow: `text-sm`, uppercase, `tracking-[0.24em]`, sky-700.
+- Page title: `text-4xl`, bold, slate-900.
+- Descriptions: `text-sm`, `leading-7`, slate-600.
+- Section/stat labels: `text-xs`, uppercase, tracking `0.18em–0.20em`, slate-500.
+- Header brand eyebrow: `text-[11px]`, uppercase, `tracking-[0.22em]`.
+- Reserve `font-black` and very large display text for authentication hero statements.
-**Font weights:**
-- `font-medium` (500) — body text, nav items, form labels, tags
-- `font-semibold` (600) — modal titles, item names, emphasis
-- `font-bold` (700) — headings, stat values, card titles
-- `font-black` (900) — Login/Register hero only, with `leading-[1.05]`
+## Layout and Responsive Behavior
-**Letter tracking:**
+Prefer the shared page structure:
-| Tracking | Where |
-|----------|-------|
-| `tracking-[0.12em]` | Nav links, upload/button text (uppercase) |
-| `tracking-[0.18em]` | Info panel section labels |
-| `tracking-[0.20em]` | Stat card labels |
-| `tracking-[0.22em]` | Header subtitle, modal subtitle, quick-upload header |
-| `tracking-[0.24em]` | Page hero section labels |
-| `tracking-[0.26em]` | Login/Register hero labels |
+```html
+
+
+
Cloud Upload
+
上传云图
+
页面描述
+
+
----
-
-## Border Radius
-
-**All border-radius is `0px` by default** — enforced via Naive UI theme override and global CSS:
-
-```css
-[class~='rounded'], [class*='rounded-'] { border-radius: 0 !important; }
+
+
+
```
-Only exceptions (all `!important` or explicit inline):
-- Close/map buttons: `rounded-full` / `border-radius: 9999px`
-- ImageDetailModal shell: `rounded-[30px]`
-- MapView info panel cards: `rounded-2xl`
-- MiniLocationMap marker dot: `rounded-full`
-- UploadView native inputs: `rounded-lg`
+Container widths:
----
+- `oc-container--narrow` — `max-w-4xl`
+- `oc-container--content` — `max-w-6xl`
+- `oc-container--wide` — `max-w-7xl`
-## Shadows
+Use `px-4 sm:px-6 lg:px-8` for page gutters. Validate at both desktop and a real `375px` mobile viewport. Do not accept horizontal overflow.
-**Signature pattern: hard offset box shadows** — `shadow-[Xpx_Xpx_0_0_rgba(...)]` with zero blur.
+## Reusable Component Contracts
-| Shadow | Offset | Use |
-|--------|--------|-----|
-| `shadow-[3px_3px_0_0_rgba(...)]` | 3/3 | Small header buttons, login button |
-| `shadow-[4px_4px_0_0_rgba(...)]` | 4/4 | Logo box, primary CTAs, hidden header, profile avatar |
-| `shadow-[6px_6px_0_0_rgba(...)]` | 6/6 | Navigation bar, search box |
-| `shadow-[8px_8px_0_0_rgba(...)]` | 8/8 | Dropdown menus, archive panel, account card |
-| `shadow-[10px_10px_0_0_rgba(...)]` | 10/10 | Login/Register hero sections |
-| `shadow-[12px_12px_0_0_rgba(...)]` | 12/12 | Login/Register cards, CommunityView section, AuthConfirm card |
+Use existing semantic classes before writing repeated Tailwind bundles:
-**Shadow colors by context:**
-- `rgba(15,23,42,...)` — slate-900, neutral (most common)
-- `rgba(14,165,233,...)` — sky-500 (sky-colored buttons)
-- `rgba(20,184,166,...)` — teal-500 (teal accents)
+- Page structure: `oc-page-hero`, `oc-page-hero--soft`, `oc-container`, `oc-page-content`.
+- Typography: `oc-page-eyebrow`, `oc-page-title`, `oc-page-description`, `oc-section-label`, `oc-stat-label`, `oc-stat-value`, `oc-meta`.
+- Forms: `oc-field-label`, `oc-field-required`, `oc-field-control`, `oc-field-help`, `oc-field-error`.
+- Surfaces: `oc-surface`, `oc-inset-panel`, `oc-panel-card`, `oc-panel-card-soft`, `oc-empty-card`.
+- Interaction: `oc-primary-button`, `oc-panel-button`, `oc-header-button`, `oc-icon-button`, `oc-map-button`, `oc-choice-button`, `oc-text-button`, `oc-menu-item`, `oc-nav-link`.
-**Standard Tailwind shadows** also used sparingly:
-- `shadow-sm` — stat cards, gallery cards, encyclopedia cards
-- `shadow-lg` — cloud card hover lift
-- `shadow-2xl` — modal shells
+Class names describe function. Keep modifiers attached to their base class, for example:
----
-
-## Gradients
-
-All page backgrounds use gradients — avoid flat single-color backgrounds.
-
-| Gradient | Where |
-|----------|-------|
-| `linear-gradient(180deg,#e0f2fe_0%,#f8fafc_100%)` | Page hero sections (standard) |
-| `linear-gradient(180deg,#f0fdfa_0%,#f8fafc_100%)` | Community page, soft app pages |
-| `linear-gradient(135deg,#f0fdfa_0%,#fff_48%,#eff6ff_100%)` | Login hero |
-| `linear-gradient(135deg,#eff6ff_0%,#fff_42%,#f0fdfa_100%)` | Register hero |
-| `linear-gradient(180deg,#f8fafc_0%,#eef6ff_55%,#f8fafc_100%)` | Admin page |
-| `linear-gradient(135deg,#ecfeff_0%,#ccfbf1_100%)` | Brand chip/avatar |
-| `linear-gradient(180deg,#f0fdfa_0%,#fff_100%)` | Account card header |
-
-**App shell background** (`App.vue`):
-```
-radial-gradient(circle_at_top_left, rgba(12,148,136,0.12), transparent 28%)
-linear-gradient(180deg, #f8fbfd 0%, #eef4f8 100%)
-```
-Plus a dotted grid overlay: `bg-[size:32px_32px] opacity-35`.
-
-**Body background** (`style.css`):
-```
-linear-gradient(180deg, rgba(15,23,42,0.02), rgba(15,23,42,0)), #eef4f8
+```html
+
+ 保存
+
```
----
+Available shared variants:
-## Layout
+- Primary: `oc-primary-button--teal`, `oc-primary-button--sky`
+- Panel: `--neutral`, `--sky`, `--teal`, `--amber`, `--danger`
+- Header: `--neutral`, `--sky`, `--teal`
+- Icon: `--small`, `--tiny`, `--sky`, `--danger`
+- Text/menu: muted, amber, and danger variants where defined
-**Page max-widths:**
-- `max-w-7xl` — AppHeader, GalleryView, AdminView
-- `max-w-6xl` — UploadView, ProfileView, EncyclopediaView
-- `max-w-4xl` — ProfileSettingsView, CommunityView
-- `max-w-3xl` — QuickUploadModal, MapPickerModal, AuthConfirmView
-- `max-w-2xl` — ResetPasswordView, NotFoundView, ForbiddenView, CloudEditModal
+## Button Semantics
-**Page hero pattern** (consistent across all views):
-```
-border-b border-sky-100 bg-[linear-gradient(180deg,#e0f2fe_0%,#f8fafc_100%)]
- max-w-{6xl|7xl} mx-auto px-4 py-10
- text-sm font-medium uppercase tracking-[0.24em] text-sky-700 (subtitle)
- h1 mt-3 text-4xl font-bold text-slate-900 (title)
- p mt-4 max-w-2xl text-sm leading-7 text-slate-600 (description)
-```
+- Teal/eucalyptus: login, account access, active toggle, confirm.
+- Sky: register, create, upload, forward action.
+- Neutral: cancel and utility actions.
+- Amber: pending/review/state-toggle actions.
+- Danger: deletion and destructive actions.
-**Horizontal padding:** `px-4` / `sm:px-6` / `lg:px-8`
+For Naive UI buttons:
-**Column systems:**
-- Gallery masonry: `columns-2 gap-3 md:columns-3 xl:columns-4 [column-gap:0.75rem]`
-- Card grids: `gap-4 md:grid-cols-2 xl:grid-cols-3` or `gap-4 md:grid-cols-4`
-- Two-column splits: `lg:grid-cols-[1.1fr_0.9fr]`, `lg:grid-cols-[1.4fr_0.9fr]`
+- Use `type="default"` with the shared `oc-*` class when a custom visual variant is intended.
+- Do not rely on Naive UI default primary/secondary styling for page CTAs or panel actions.
+- Keep `src/lib/theme.ts` as the global Naive UI contract; it is mounted by `App.vue`.
+- Use dark text on light primary surfaces. Do not assume primary buttons should have white text.
-**Gap scale:** `gap-4`, `gap-5`, `gap-6` for card grids; `gap-2` for nav items; `space-y-6`/`space-y-8` between sections.
+## Icons, Cards, and Modals
----
+- Use `@vicons/tabler` through `NIcon` for interface icons.
+- Preserve the pixel-cloud SVG for the primary brand mark.
+- Use one bordered surface and one appropriate hard-shadow token for ordinary cards.
+- Keep modal structure square unless it is a documented media exception.
+- Use `oc-overlay-button` for controls over dark media and `oc-icon-button` for controls on light surfaces.
+- Keep semantic status colors stable: emerald success, amber pending, rose rejected/destructive, slate hidden/neutral.
-## Component Conventions
+## Implementation Workflow
-### Buttons
-
-**Primary CTA (upload, action):**
-```
-inline-flex h-8 items-center border border-sky-200 bg-sky-100 px-3
-text-sm font-medium uppercase tracking-[0.12em] text-sky-800
-shadow-[4px_4px_0_0_rgba(14,165,233,0.14)]
-transition-colors hover:bg-sky-50 hover:text-sky-900
-```
-Mobile: `h-8 md:h-10 md:px-4`
-
-**Secondary/neutral:**
-```
-inline-flex h-8 items-center border border-slate-200 bg-white/80 px-3
-text-sm font-medium text-slate-700
-shadow-[3px_3px_0_0_rgba(15,23,42,0.06)]
-hover:border-teal-200 hover:bg-teal-50 hover:text-teal-800
-```
-
-**Danger/delete:** `text-rose-600 hover:bg-rose-50 hover:text-rose-700`
-
-**Map floating buttons:** `w-10 h-10 bg-white rounded-lg shadow-md flex items-center justify-center hover:bg-gray-50`
-
-**Naive UI buttons** use `secondary strong` as default; `type="primary"` for primary actions; `block size="large"` for block forms.
-
-### Cards
-
-**Standard card:**
-```
-border bg-white text-left shadow-sm
-transition-all hover:-translate-y-1 hover:shadow-lg
-```
-
-**Encyclopedia unlocked variant:** `border-amber-300 shadow-amber-100/60`
-
-**Naive UI NCard:** `class="border border-slate-200 shadow-sm"`
-
-### Modals
-
-**Overlay:** `fixed inset-0 z-[110|130] bg-slate-950/60` (or `bg-black/85` for image detail)
-
-**Shell:** `bg-white shadow-2xl` with max-w matching content width. ImageDetailModal uses `rounded-[30px]`; others are square.
-
-**Close button:** Circular (`rounded-full`, `border-radius: 9999px`), semi-transparent background.
-
-**Sections:** `border-b border-slate-200` separates header/body/footer.
-
-### Inputs & Forms
-
-**Native HTML inputs:**
-```
-border border-slate-300 px-3 py-2.5 text-sm
-focus:border-sky-500 focus:outline-none focus:ring-2 focus:ring-sky-500
-```
-
-**Labels:** `block text-sm font-medium text-slate-700 mb-1`
-
-**Required marker:** `*`
-
-**Error text:** `text-sm text-red-500 mt-1`
-
-**Checkboxes:** `h-5 w-5 border-slate-300 text-sky-500 focus:ring-sky-500`
-
-### Tags & Badges
-
-All use `inline-flex border px-3 py-1 text-xs font-medium` with color variants:
-
-- `common`: `bg-sky-100 text-sky-700 border-sky-200`
-- `uncommon`: `bg-amber-100 text-amber-700 border-amber-200`
-- `rare`: `bg-rose-100 text-rose-700 border-rose-200`
-- `approved`/`success`: `bg-emerald-100 text-emerald-700 border-emerald-200`
-- `pending`: `bg-amber-100 text-amber-700 border-amber-200`
-- `rejected`: `bg-rose-100 text-rose-700 border-rose-200`
-- `hidden`/neutral: `bg-slate-100 text-slate-600`
-
-### Menus & Dropdowns
-
-**Account dropdown:**
-```
-border border-slate-200 bg-white shadow-[8px_8px_0_0_rgba(15,23,42,0.08)]
-```
-
-**Menu items:**
-```
-flex items-center gap-3 px-4 py-2.5 text-sm font-medium text-slate-700
-transition-colors hover:bg-teal-50 hover:text-teal-800
-```
-
-**Danger menu item:** `text-rose-600 hover:bg-rose-50 hover:text-rose-700`
-
-### Navigation
-
-**Header:** `sticky top-0 z-50 h-28 md:h-16 bg-white/88 backdrop-blur-xl border-b border-slate-200/80`, scroll-hides with `transition-transform duration-300`.
-
-**Selected nav item:** `bg-teal-100 text-teal-800 ring-1 ring-teal-200`
-
----
-
-## Core Palette
-
-Use these Tailwind families first:
-
-- `slate` — text, borders, neutral panels
-- `sky` — page gradients, upload/action emphasis, map/cloud atmosphere
-- `teal` — navigation selected states, account identity, calm success-adjacent UI
-- `cyan` — subtle sky gradients and avatar/logo surfaces
-- `emerald` — explicit success/approved state only
-- `amber` — pending/review/uncommon rarity
-- `rose` — rejected/destructive/rare rarity
-
-**Key hex values:**
-
-| Role | Value |
-|------|-------|
-| Page background | `#eef4f8` / `#f3f7fb` |
-| Body text | `#0f172a` (slate-900) |
-| Secondary text | `#334155` (slate-700) |
-| Muted text | `#64748b` (slate-500) |
-| Borders | `#d9e3ee`, `#e2e8f0`, `#cbd5e1` |
-| Selection | `rgba(15,118,110,0.18)` (teal-700) |
-| Text on primary | `#0f172a` (dark, not white — Naive UI override) |
-
-**Naive UI theme tokens** (`App.vue`):
-```
-primaryColor: '#0f766e' (teal-700)
-infoColor: '#0369a1' (sky-700)
-successColor: '#0f766e' (teal-700)
-warningColor: '#d97706' (amber-600)
-errorColor: '#dc2626' (red-600)
-```
-
----
-
-## Animation & Transitions
-
-**Hover effects:**
-- Cards: `transition-all hover:-translate-y-1 hover:shadow-lg` (lift)
-- Images: `transition duration-500 group-hover:scale-[1.04]` (subtle zoom)
-- Gallery items: `transition-transform duration-300 hover:-translate-y-1`
-- Badges on cards: `transition-opacity md:opacity-0 md:group-hover:opacity-100`
-
-**Modal transitions:**
-- ImageDetailModal: opacity 180ms, shell scale+translateY 220ms, `cubic-bezier(0.22, 1, 0.36, 1)`
-- Other modals: default Vue transitions
-
-**Header scroll:** `transition-transform duration-300`
-
-**Image loading:** `transition-opacity duration-300` for thumbnail-to-hires crossfade, low-res preview gets `blur-[1px]` until full-res loads.
-
-**Skeleton shimmer:**
-```
-animate-pulse bg-[linear-gradient(110deg,#0f172a_0%,#1e293b_45%,#334155_55%,#0f172a_100%)]
-bg-[length:220%_100%]
-```
-
----
-
-## Icons
-
-**Library:** `@vicons/tabler` (Tabler Icons), rendered via `` from Naive UI.
-
-Common icons: `User`, `Settings`, `Logout`, `Shield`, `Search`, `X`, `Clock`, `Location`/`MapIcon`, `CloudUpload`, `Map`/`Satellite`, `Adjustments`, `Calendar`, `Refresh`, `InfoCircle`, `Lock`, `Check`, `Eye`/`EyeOff`, `Trash`
-
----
+1. Inspect the source-of-truth files and the target component.
+2. Reuse an existing semantic class if it expresses the intent.
+3. Use Tailwind only for one-off layout and responsive composition.
+4. Add a token before repeating a stable raw value.
+5. Add a shared `oc-*` class only for cross-page patterns or product-wide rules.
+6. Keep feature-specific AMap, slider, media, or transition details scoped to the component.
+7. When changing a global color, audit all matching Tailwind utilities, hard-coded hex/RGB values, gradients, shadows, canvas drawing, and Naive UI tokens.
+8. Preserve unrelated user changes in the worktree.
## Anti-Patterns
-- Do not use purple as a fallback visual direction.
-- Do not use `bg-slate-900 text-white` for ordinary selected navigation.
-- Do not introduce dark-mode-heavy sections unless the surrounding page already uses that language.
-- Do not overuse rounded rectangles; the project uses sharp, atlas-like panels.
-- Do not mix random accent colors within the same feature. Pick one accent family and keep it consistent.
-- Do not use flat single-color backgrounds where a gradient belongs.
-- Do not add border-radius without an explicit reason — `0px` is the project default.
-- Do not use white text on primary buttons — Naive UI primary buttons use dark text (`#0f172a`).
-
----
+- Default Tailwind `green-*`, `lime-*`, vivid teal, purple, indigo, or generic `gray-*`.
+- Ad hoc rounded cards, pills, or map buttons.
+- Soft drop shadows replacing hard atlas shadows across normal UI.
+- New button styling copied into templates instead of shared `oc-*` variants.
+- `NButton type="primary"` used as a shortcut around the shared button contract.
+- White text on pale green or sky action surfaces.
+- Emoji used as the site identity.
+- Flat page backgrounds where the shared hero/canvas gradient applies.
+- Green used indiscriminately for both brand interaction and success state.
## Validation
After style changes, run:
```bash
-npx vue-tsc -b
+npm run check:styles
+git diff --check
+npm run build
```
-Run `npm run build` if the change touches routes, imported components, or package dependencies.
+For material visual changes, render representative pages and inspect desktop and `375px` mobile screenshots. Check computed styles when shape, shadow, color token, or responsive overflow is part of the request.
diff --git a/AGENTS.md b/AGENTS.md
index 9bc3121..1137cf9 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -3,9 +3,11 @@
## Commands
- `npm run dev` — Vite dev server with HMR
+- `npm run check:styles` — validates shared style contracts and blocks deprecated palettes/classes
- `npm run build` — `vue-tsc -b && vite build` (typecheck must pass or build aborts)
- `npx vue-tsc -b` — standalone typecheck (no script in package.json)
-- No linter, formatter, or test runner exists
+- `npm run preview` — previews the production build on strict port `5173`
+- No general linter, formatter, or test runner exists; `check:styles` is the project-specific visual-system check
## Architecture
@@ -26,9 +28,13 @@
| `src/components/cloud/` | Cloud-related modals and widgets: ImageDetailModal, CloudEditModal, MapPickerModal, QuickUploadModal, MiniLocationMap |
| `src/components/layout/` | AppHeader (top nav bar with auth state) |
| `src/components/profile/` | ContributionHeatmap |
-| `src/style.css` | Global visual system hooks: shared button/card utility classes, base typography, body background |
+| `src/style.css` | Global stylesheet assembly point; imports Tailwind, tokens, base rules, and shared components |
+| `src/styles/` | Visual system source: semantic tokens, global square-corner baseline, shared `oc-*` component contracts |
+| `src/lib/theme.ts` | Naive UI theme overrides aligned with the semantic tokens |
| `src/views/` | Route-level page components (see Routes below) |
| `src/types/` | TypeScript types: domain models (`database.ts`), API DTOs (`api.ts`), AMap declarations (`amap.d.ts`), router meta (`router.d.ts`) |
+| `docs/style-system.md` | Concise implementation and naming guide for the visual system |
+| `scripts/check-style-system.mjs` | Automated guard against deprecated palettes and malformed shared classes |
## Routes
@@ -126,12 +132,33 @@ Optional:
Backend-only variables such as database credentials, JWT secrets, SMTP settings, cookie policy, CORS origins, and upload paths belong in `../opencloud-backend/.env`, never in the Vite environment.
+## Visual System
+
+- The design language is a clean sky atlas: airy sky-blue surfaces, fresh eucalyptus green, square editorial panels, pixel-cloud identity, and hard offset shadows.
+- Read `.agents/skills/opencloud-style/SKILL.md` before material visual changes. Treat `src/styles/tokens.css`, `src/styles/base.css`, `src/styles/components.css`, and `src/lib/theme.ts` as the implementation sources of truth.
+- Shared/stable decisions belong in layers:
+ - tokens and palette remapping → `src/styles/tokens.css`
+ - global baseline and square-corner policy → `src/styles/base.css`
+ - cross-page semantic classes → `src/styles/components.css`
+ - feature-specific map/slider/media details → the component's scoped style
+ - one-off layout and responsive composition → Tailwind in the template
+- The global interface is square by default. Ordinary cards, inputs, dropdowns, buttons, modals, and map controls use `0px` radius. Circular marker dots, media overlay controls, AMap-generated bubbles/cards, and the media-focused image-detail shell are explicit exceptions.
+- Use hard zero-blur offset shadows (`--oc-shadow-xs` through `--oc-shadow-xl`) for ordinary UI depth. Interactive controls may lift by `translate(-1px, -1px)` on hover.
+- Brand/interaction green is fresh eucalyptus: main `#34745d`, dark `#274c40`, light surface `#f2faf6`.
+- Success green is a distinct leaf green: main `#4d7f3b`, dark `#35522c`, light surface `#f4faef`.
+- Existing `teal-*` and `emerald-*` Tailwind class names are compatibility aliases remapped in `tokens.css`; do not assume Tailwind's default values.
+- Do not introduce Tailwind `green-*`/`lime-*`, vivid default teal, purple, indigo, or generic gray palettes. Use slate, sky, remapped teal/emerald, amber, and rose according to semantic purpose.
+- The header brand mark is the pixel cloud/sun SVG inside a square `40px` `sky-100` surface with a `sky-200` border and neutral `4px` hard shadow. Do not replace it with emoji or give it a green background.
+- Map floating buttons use `oc-map-button`: square `40px × 40px`, white background, slate border, `0px` radius, and a hard shadow even when disabled.
+- For material visual changes, inspect representative desktop and real `375px` mobile screenshots and verify there is no horizontal overflow.
+
## Naive UI
- Used for modals, buttons, inputs, tags, progress bars, alerts, dropdowns, empty states, skeletons, and message toasts.
- No SSR — pure client-side rendering.
- Custom CSS overrides via scoped `