diff --git a/.agents/skills/opencloud-color-system/SKILL.md b/.agents/skills/opencloud-color-system/SKILL.md
deleted file mode 100644
index 4b46ffa..0000000
--- a/.agents/skills/opencloud-color-system/SKILL.md
+++ /dev/null
@@ -1,74 +0,0 @@
----
-name: opencloud-color-system
-description: "Use when modifying OpenCloud UI colors, visual hierarchy, Tailwind classes, buttons, cards, headers, gradients, status chips, or page-level visual design. Ensures the project keeps its current fresh sky/teal/white visual language and avoids inconsistent dark or purple defaults."
----
-
-# OpenCloud Color System
-
-Use this skill whenever changing OpenCloud visual design, component styling, or Tailwind color classes.
-
-## Visual Direction
-
-OpenCloud should feel like a clean sky atlas: airy, fresh, bright, and observational.
-
-- 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.
-
-## 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.
-
-Preferred combinations:
-
-- Page hero: `bg-[linear-gradient(180deg,#e0f2fe_0%,#f8fafc_100%)]`
-- Soft app page: `bg-[linear-gradient(180deg,#f0fdfa_0%,#f8fafc_100%)]`
-- Brand chip/avatar: `bg-[linear-gradient(135deg,#ecfeff_0%,#ccfbf1_100%)]`
-- Selected nav: `bg-teal-100 text-teal-800 ring-1 ring-teal-200`
-- Upload button: `border-sky-200 bg-sky-100 text-sky-800 shadow-[4px_4px_0_0_rgba(14,165,233,0.14)]`
-
-## Component Rules
-
-- Header navigation selected state should stay teal, not black.
-- Upload action should stay visually distinct from nav, preferably sky blue.
-- Username/account entry should be light and calm: white/teal, subtle border, subtle shadow.
-- Cards should generally use `bg-white`, `border-slate-200`, and light offset shadows.
-- Use gradients for page introductions instead of generic rounded white rectangles.
-- When adding hover states, prefer light fills (`hover:bg-teal-50`, `hover:bg-sky-50`) over dark inversion.
-
-## Status Colors
-
-- Approved/success: `emerald-100`, `emerald-700`.
-- Pending/review: `amber-100`, `amber-700`.
-- Rejected/destructive: `rose-100`, `rose-700` or Naive UI `type="error"`.
-- Hidden/private/neutral: `slate-100`, `slate-600`.
-
-## 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 has been intentionally moving toward sharper, atlas-like panels.
-- Do not mix random accent colors within the same feature. Pick one accent family and keep it consistent.
-
-## Validation
-
-After color/style changes, run:
-
-```bash
-npx vue-tsc -b
-```
-
-Run `npm run build` if the change touches routes, imported components, or package dependencies.
diff --git a/.agents/skills/opencloud-style/SKILL.md b/.agents/skills/opencloud-style/SKILL.md
new file mode 100644
index 0000000..87d6890
--- /dev/null
+++ b/.agents/skills/opencloud-style/SKILL.md
@@ -0,0 +1,354 @@
+---
+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."
+---
+
+# OpenCloud Visual Style
+
+Use this skill whenever changing OpenCloud visual design, component styling, Tailwind classes, layout, typography, or any page-level appearance.
+
+## Visual Direction
+
+OpenCloud should feel like a clean sky atlas: airy, fresh, bright, and observational.
+
+- 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.
+
+---
+
+## Typography
+
+**Font stack** (`src/style.css`, `App.vue`):
+```
+"IBM Plex Sans", "Noto Sans SC", "PingFang SC", sans-serif
+```
+Monospace: `"IBM Plex Mono", "SFMono-Regular", monospace`
+
+**Type scale:**
+
+| 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 |
+
+**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]`
+
+**Letter tracking:**
+
+| 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 |
+
+---
+
+## 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`
+
+---
+
+## Shadows
+
+**Signature pattern: hard offset box shadows** — `shadow-[Xpx_Xpx_0_0_rgba(...)]` with zero blur.
+
+| 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 |
+
+**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)
+
+**Standard Tailwind shadows** also used sparingly:
+- `shadow-sm` — stat cards, gallery cards, encyclopedia cards
+- `shadow-lg` — cloud card hover lift
+- `shadow-2xl` — modal shells
+
+---
+
+## 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
+```
+
+---
+
+## Layout
+
+**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
+
+**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)
+```
+
+**Horizontal padding:** `px-4` / `sm:px-6` / `lg:px-8`
+
+**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]`
+
+**Gap scale:** `gap-4`, `gap-5`, `gap-6` for card grids; `gap-2` for nav items; `space-y-6`/`space-y-8` between sections.
+
+---
+
+## Component Conventions
+
+### 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`
+
+---
+
+## 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`).
+
+---
+
+## Validation
+
+After style changes, run:
+
+```bash
+npx vue-tsc -b
+```
+
+Run `npm run build` if the change touches routes, imported components, or package dependencies.
diff --git a/.gitignore b/.gitignore
index 438657a..34a578b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,7 @@ dist-ssr
!.vscode/extensions.json
.idea
.DS_Store
+.claude
*.suo
*.ntvs*
*.njsproj