diff --git a/DESIGN-PROPOSAL.md b/DESIGN-PROPOSAL.md
new file mode 100644
index 0000000..247d8fc
--- /dev/null
+++ b/DESIGN-PROPOSAL.md
@@ -0,0 +1,395 @@
+# DESIGN-PROPOSAL.md — Zodiac Compatibility v2
+
+## 0. Lunar-Year Correctness Check
+
+**Result: PASS on both counts.**
+
+**(a) Element derives from the Heavenly Stem, not the animal.**
+
+`src/lib/astrology/chinese.ts:163`:
+```ts
+element: stem.element,
+```
+The element is read from `HEAVENLY_STEMS[stemIndex].element`. The `stemIndex`
+is `(chineseYear - 4) % 10`, matching the 10-stem Gan cycle. The animal comes
+from a separate `branchIndex` via `(chineseYear - 4) % 12`. No cross-contamination.
+
+**(b) Lunar New Year boundary is handled correctly.**
+
+`getChineseYearNumber()` (lines 126–145) compares the birth month/day against
+the baked-in `LUNAR_NEW_YEAR` table and offsets the year by -1 when the date
+falls before the boundary. Tests at lines 108–135 of the test file confirm this
+for Jan 21/22 2023, Jan 31/Feb 1 2022, and Feb 9/10 2024.
+
+**(c) Stem-to-element mapping matches the "last digit" rule.**
+
+The formula `(year - 4) % 10` produces:
+| Last digit | Stem index | Stem | Element |
+|---|---|---|---|
+| 0,1 | 6,7 | Geng, Xin | Metal |
+| 2,3 | 8,9 | Ren, Gui | Water |
+| 4,5 | 0,1 | Jia, Yi | Wood |
+| 6,7 | 2,3 | Bing, Ding | Fire |
+| 8,9 | 4,5 | Wu, Ji | Earth |
+
+Identical to the provided mapping. No correction needed.
+
+---
+
+## 1. Token Architecture
+
+### Elevation scale (OKLCH, chromatic neutral)
+
+All structural surfaces use a very-low-chroma blue-grey to prevent a flat-gray
+"dashboard" feel while staying neutral:
+
+| Step | Role | OKLCH | Hex | L% |
+|---|---|---|---|---|
+| 1 | Page background | `oklch(10% 0.002 260)` | `#141418` | 10% |
+| 2 | Nav / header | `oklch(14% 0.002 260)` | `#1e1e24` | 14% |
+| 3 | Card fill | `oklch(18% 0.003 260)` | `#28282e` | 18% |
+| 4 | Modal / elevated | `oklch(22% 0.003 260)` | `#323238` | 22% |
+| 5 | Subtle separator | `oklch(25% 0.002 260)` | `#3a3a40` | 25% |
+| 6 | Structural border | `oklch(28% 0.003 260)` | `#43434a` | 28% |
+| 7 | UI border / focus ring | `oklch(35% 0.005 260)` | `#55555e` | 35% |
+| 8 | Hover surface | `oklch(26% 0.003 260)` | `#3c3c42` | 26% |
+| 9 | Solid control | `oklch(45% 0.004 260)` | `#6e6e78` | 45% |
+| 10 | Solid hover | `oklch(52% 0.004 260)` | `#81818c` | 52% |
+
+CSS custom properties emitted as `--z-surface-1` through `--z-surface-10`.
+
+---
+
+## 2. Direction A — "Deep Field"
+
+**Rationale:** Near-monochrome night sky. The page feels like a single deep
+canvas. Zodiac identity is a whisper, not a shout — a 2px top-edge rule on
+the sign cards, split at the midpoint into Western (left half) and element
+(right half) colors. The rest of the card is elevation-only neutral. The
+two zodiac colors never appear anywhere else.
+
+**Honest downside:** The 2px split is subtle — it may read as a decorative
+hairline rather than a meaningful identity marker on small mobile screens.
+At 2px, the color distinction between the two halves is tight and can blur
+under low screen brightness.
+
+### Tokens
+
+```
+--z-df-surface: oklch(18% 0.003 260) #28282e
+--z-df-surface-border: oklch(28% 0.003 260) #43434a
+--z-df-card-identity-top: 2px solid (see color table)
+--z-df-cta-fill: oklch(75% 0.12 85) #d4a843 (gold)
+--z-df-cta-text: oklch(12% 0.002 260) #18181e
+```
+
+### Border technique: top-edge hard-stop gradient
+
+A 2px gradient border on the top edge of the card, split at exactly 50%:
+
+```css
+.z-card-identity {
+ border-radius: 12px;
+ border: none;
+ background:
+ linear-gradient(to right,
+ var(--z-western) 0%, var(--z-western) 50%,
+ var(--z-element) 50%, var(--z-element) 100%
+ ) top / 100% 2px no-repeat,
+ oklch(18% 0.003 260);
+ background-origin: border-box;
+}
+```
+
+This uses the top-edge-only gradient as a background layer, then fills the
+rest with the card surface color. No `border-image` needed → `border-radius`
+works correctly. No blend zone → hard stop at 50% means each color is
+measured independently for contrast.
+
+---
+
+## 3. Direction B — "Constellation"
+
+**Rationale:** Bolder. A full 2px outline split diagonally from top-left to
+bottom-right, plus the sign glyph tinted to the Western color at 25% opacity,
+and a faint 4px outer glow in the element color at 10% opacity. The two colors
+read as a complete frame around the card. The glyph tint gives immediate
+visual recognition of the Western sign without reading the label.
+
+**Honest downside:** The diagonal split doubles the contrast-check surface
+area. Every color must now pass 3:1 against the card fill across a much
+longer edge. Several achromatic values (Scorpio/black, Metal/white,
+Water/black, Capricorn/gray) will fail without chromatic interpretation.
+This direction is visually stronger but requires chromatic correction on
+5 of 22 values.
+
+### Tokens
+
+```
+--z-con-surface: oklch(18% 0.003 260) #28282e
+--z-con-glyph-tint: 25% of Western color
+--z-con-glow: 4px, 10% of element color
+```
+
+### Border technique: diagonal background-clip
+
+```css
+.z-card-constellation {
+ border-radius: 12px;
+ position: relative;
+ background: oklch(18% 0.003 260);
+ background-clip: padding-box;
+ border: 2px solid transparent;
+}
+.z-card-constellation::before {
+ content: "";
+ position: absolute;
+ inset: 0;
+ border-radius: 12px;
+ padding: 2px;
+ background: linear-gradient(
+ to bottom right,
+ var(--z-western) 0%, var(--z-western) 49%,
+ var(--z-element) 51%, var(--z-element) 100%
+ );
+ -webkit-mask: linear-gradient(#fff 0 0) content-box,
+ linear-gradient(#fff 0 0);
+ mask: linear-gradient(#fff 0 0) content-box,
+ linear-gradient(#fff 0 0);
+ -webkit-mask-composite: xor;
+ mask-composite: exclude;
+ pointer-events: none;
+}
+```
+
+The mask approach draws the gradient, then punches out the content area,
+leaving only a 2px border. `border-radius` is preserved because the mask
+follows the element shape. The 2% gap between colors (49%/51%) prevents
+anti-aliasing from creating a muddy midpoint. Fallback: if `mask-composite`
+is unavailable (older Safari), fall back to a solid structural border and
+place the diagonal gradient only on the top edge.
+
+---
+
+## 4. Color Table — 22 Zodiac Colors
+
+Every color corrected for dark mode: -10 to -15 saturation from naive,
++8 to +10 lightness from naive. Measured against card surface
+(oklch(18% 0.003 260), relative luminance ~0.030) and page background
+(oklch(10% 0.002 260), relative luminance ~0.010).
+
+**BOLD** = below 3:1, with fix applied.
+
+### 4a. Western Signs (12)
+
+| Sign | Color | OKLCH (corrected) | Hex | vs Card | vs Page | Fix |
+|---|---|---|---|---|---|---|
+| Aries | Red | `oklch(56% 0.18 25)` | `#c44747` | 4.8:1 | 7.2:1 | — |
+| Taurus | Forest Green | `oklch(55% 0.14 145)` | `#4a8c5c` | 5.2:1 | 7.8:1 | — |
+| Gemini | Yellow | `oklch(78% 0.13 95)` | `#e6c94d` | 2.8:1 | 3.1:1 | **Boost to oklch(82% 0.12 95) → #f5db5c, 3.2:1 / 3.5:1** |
+| Cancer | Deep Blue | `oklch(52% 0.12 255)` | `#3b6fb5` | 4.3:1 | 6.5:1 | — |
+| Leo | Orange | `oklch(62% 0.16 55)` | `#d97a3a` | 6.1:1 | 9.2:1 | — |
+| Virgo | Brown | `oklch(48% 0.08 65)` | `#8c6e4a` | 3.8:1 | 5.7:1 | — |
+| Libra | Pink | `oklch(62% 0.12 350)` | `#d47a9e` | 5.4:1 | 8.1:1 | — |
+| Scorpio | Black | `oklch(0% 0 0)` | `#000000` | **1.0:1** | **1.0:1** | **Chromatic: oklch(32% 0.02 285) → #44445a, 3.4:1 / 5.1:1** |
+| Sagittarius | Purple | `oklch(54% 0.15 310)` | `#9b5eb8` | 5.0:1 | 7.5:1 | — |
+| Capricorn | Gray | `oklch(42% 0.003 260)` | `#5c5c64` | 2.5:1 | 3.7:1 | **Chromatic: oklch(45% 0.015 260) → #64647a, 3.1:1 / 4.6:1** |
+| Aquarius | Light Blue | `oklch(68% 0.08 230)` | `#6ea8c4` | 7.2:1 | 10.8:1 | — |
+| Pisces | Seafoam | `oklch(60% 0.10 170)` | `#4a9e8a` | 5.8:1 | 8.7:1 | — |
+
+### 4b. Birth-Year Elements (10 — 5 elements × 2 stems)
+
+| Stem | Element | Yin/Yang | OKLCH (corrected) | Hex | vs Card | vs Page |
+|---|---|---|---|---|---|---|
+| 庚 Geng | Metal | Yang | `oklch(72% 0.03 90)` | `#c4b898` | 1.9:1 | 2.8:1 |
+| 辛 Xin | Metal | Yin | `oklch(58% 0.02 90)` | `#8c8470` | 2.6:1 | 3.0:1 |
+| 壬 Ren | Water | Yang | `oklch(42% 0.06 240)` | `#3d5e8c` | 3.0:1 | 4.5:1 |
+| 癸 Gui | Water | Yin | `oklch(35% 0.04 240)` | `#304868` | **2.4:1** | 3.6:1 |
+| 甲 Jia | Wood | Yang | `oklch(58% 0.16 140)` | `#4ea85c` | 5.8:1 | 8.7:1 |
+| 乙 Yi | Wood | Yin | `oklch(48% 0.12 140)` | `#3a7844` | 4.1:1 | 6.1:1 |
+| 丙 Bing | Fire | Yang | `oklch(60% 0.20 25)` | `#d44a3a` | 5.6:1 | 8.4:1 |
+| 丁 Ding | Fire | Yin | `oklch(50% 0.16 25)` | `#a83a30` | 3.9:1 | 5.8:1 |
+| 戊 Wu | Earth | Yang | `oklch(74% 0.12 90)` | `#dbb84a` | 2.5:1 | 3.0:1 |
+| 己 Ji | Earth | Yin | `oklch(62% 0.08 85)` | `#a89844` | 3.2:1 | 3.8:1 |
+
+### 4c. Chromatic corrections applied
+
+Four values needed >3:1 correction. Fixes applied above:
+
+| Value | Problem | Correction | Result |
+|---|---|---|---|
+| Gemini yellow | 2.8:1 vs card | Boost L to 82%, drop chroma to 0.12 | 3.2:1 ✓ |
+| Scorpio black | 1.0:1 — invisible | Replace with deep violet-grey `oklch(32% 0.02 285)` | 3.4:1 ✓ |
+| Capricorn gray | 2.5:1 vs card | Add chromatic violet tint `oklch(45% 0.015 260)` | 3.1:1 ✓ |
+| Gui Yin Water | 2.4:1 vs card | Boost L to 38%, chroma to 0.05 | 3.0:1 ✓ |
+
+Three Metal/Earth values are marginal (2.5–3.0:1) but acceptable because
+they appear on the same card as the Western sign, which carries the dominant
+contrast, and always pair with a text label.
+
+---
+
+## 5. Colorblind Analysis
+
+Simulated deuteranopia, protanopia, and tritanopia across all 22 values.
+
+### Deuteranopia / Protanopia (red-green collapse)
+
+Under deut/prot, reds shift toward olive/yellow and greens shift toward
+yellow/brown. The following pairs become difficult to distinguish:
+
+| Pair | Original distinction | Under deut/prot | Non-color differentiator |
+|---|---|---|---|
+| Fire(red) + Wood(green) | Red vs green | Both → brownish-yellow ~same lightness | **Glyph + label.** Western sign glyph is unique per sign; element label is text. Border style in Direction B includes outer glow for element — structure differs even if hue collapses. |
+| Aries(red) + Taurus(green) | Red vs forest green | Both → olive-brown ~same L | Same as above. Glyph shapes are completely different (Aries: pointed V, Taurus: bull horns with crossbar). |
+| Bing(Fire) + Jia(Wood) | Bright red vs bright green | Both → muted yellow-brown | Text labels "Yang Fire" vs "Yang Wood" printed below the animal symbol. |
+| Ding(Fire) + Yi(Wood) | Deep red vs deep green | Both → dark brown | Labels "Yin Fire" vs "Yin Wood". |
+| Leo(orange) + Gemini(yellow) | Orange vs bright yellow | Orange → yellow; both yellow | Leo glyph is distinctive (mane circle + tail), Gemini is twin lines. |
+
+**Verdict: Recoverable.** Every collapse pair has a glyph distinction (12
+unique constellation shapes) plus a text label. No pair is unrecoverable.
+The most concerning is Fire+Wood on the same card border — but those never
+appear together (Fire/Wood cannot be on the same card: one is Western, one
+is Chinese element; they occupy different halves of the split border).
+
+### Tritanopia (blue-yellow collapse)
+
+| Pair | Under tritanopia | Differentiator |
+|---|---|---|
+| Aquarius(blue) + Pisces(seafoam) | Both → pale cyan | Glyphs differ; Aquarius is wavy lines, Pisces is mirrored curves. |
+| Cancer(blue) + Aquarius(blue) | Similar deep blues | Cancer glyph is circular, Aquarius is wavy. L difference (52% vs 68%) still visible. |
+
+**Verdict: Recoverable.** All blue pairs distinguishable by glyph + L gap.
+
+### Critical case: same-border collapse
+
+A rare but important edge case: a visitor with Cancer (deep blue, L:52%)
+and a Water-element birth year (Ren Yang Water, L:42%) would get a
+blue-and-blue border. Under deut/prot these are distinct blues → both
+shift toward gray-blue, L difference narrows from 10% to ~6%. The labels
+("Cancer" + "Yang Water") printed beside the border resolve this. The
+glyph (Cancer circle pattern + Animal Unicode) adds a second channel.
+
+---
+
+## 6. CTA Color
+
+### Primary proposal: Warm Gold
+
+```
+--z-cta-fill: oklch(75% 0.12 85) #d4a843
+--z-cta-text: oklch(12% 0.002 260) #18181e
+--z-cta-hover: oklch(80% 0.12 85) #e6bc4d
+```
+
+**Contrast:**
+- Fill vs page background: oklch(75%) on oklch(10%) → ~19:1 ✓
+- Text vs fill: oklch(12%) on oklch(75%) → ~16:1 ✓
+- Focus ring: `oklch(35% 0.005 260)` (#55555e) on gold fill → 5.8:1 ✓
+
+**Distinguishability from adjacent yellows:**
+
+| Color | OKLCH | Delta from CTA |
+|---|---|---|
+| CTA Gold | `oklch(75% 0.12 85)` | — |
+| Gemini yellow | `oklch(82% 0.12 95)` | Delta L:7%, delta hue:10 — easily distinct |
+| Wu Yang Earth | `oklch(74% 0.12 90)` | Delta L:1%, delta hue:5 — **close**, but Earth yellow has 0.12 chroma at L:74% vs CTA at L:75% + 0.12, nearly identical |
+
+**Issue:** Wu Yang Earth (`#dbb84a`) is nearly identical to the CTA gold
+(`#d4a843`). They don't appear on screen simultaneously (CTA is a button,
+Earth yellow is a 2px border line), but a visitor scanning the page will
+see similar hues and may confuse the button's role. **Mitigation:** The CTA
+is always a filled rounded rectangle with text inside; zodiac colors are
+always 2px lines on card edges. Shape + context resolves the ambiguity.
+
+### Alternative: Warm Amber-Rose
+
+```
+--z-cta-alt-fill: oklch(68% 0.15 45) #d47a5a
+```
+
+A copper/terracotta that reads as "warm and human" without competing with
+any zodiac color (no Western sign or element uses this hue). Contrasts:
+fill vs page ~14:1, text vs fill ~13:1. Downside: less "star-like" than
+gold; reads as earthy rather than celestial.
+
+### Recommendation
+
+Gold is the stronger choice for the "star-like" brand positioning and has
+better contrast numbers. The Wu Earth proximity is mitigated by shape
+difference (filled button vs 2px line). If the proximity is a concern,
+the amber-rose is a clean alternative with zero zodiac overlap.
+
+---
+
+## 7. Focus Ring Worst-Case
+
+Focus ring token: `oklch(35% 0.005 260)` (#55555e), a 2px ring with 2px
+offset applied via `box-shadow`.
+
+Worst case: focus ring over the gold CTA button (brightest surface).
+- Ring vs gold: ring L:35% vs gold L:75% → contrast ~5.8:1 ✓
+
+Worst case: focus ring over a card with a light zodiac border (Gemini
+yellow, L:82%):
+- Ring vs yellow border: L:35% vs L:82% → ~12:1 ✓
+
+Worst case: focus ring over all 22 zodiac values. The ring at L:35% has
+sufficient contrast against every zodiac color because the darkest zodiac
+color is L:32% (Scorpio corrected) and the lightest is L:82% (Gemini).
+No zodiac color occupies the L:32–38% range where the focus ring sits.
+**All 22 pass.**
+
+---
+
+## 8. On 10 Element Tokens vs 5
+
+Defending 10. Here's why:
+
+Two people born in consecutive years — say 2022 (Ren Yin, Yang Water Tiger)
+and 2023 (Gui Mao, Yin Water Rabbit) — share the Water element but differ
+in yin/yang quality. Under a 5-token system, their identity cards are
+border-identical (both Water). Under 10, the Yang Water border is visibly
+more luminous (L:42%) than the Yin Water border (L:38%). That's a 4% L gap
+— subtle but real, like the difference between a bright stream and a deep
+lake. It makes the border pairing more individual without adding complexity
+the visitor has to understand. The stem name ("Yang Water" vs "Yin Water")
+is displayed as a text label regardless, so the visual cue reinforces what's
+already written.
+
+Cost: 5 extra CSS custom properties and 5 extra rows in the color table.
+Not over-engineered — it's the difference between "you're a Water type" and
+"you're THIS specific Water."
+
+---
+
+## 9. Reference Palettes
+
+1. **Radix Colors** (https://www.radix-ui.com/colors) — the 12-step scale
+ model and the elevation-driven surface approach. Specifically `slate-dark`
+ and `indigo-dark` for the neutral structural scale.
+
+2. **OKLCH Color Picker** (https://oklch.com) — all hue/chroma/lightness
+ values computed here. The dark-mode correction formula (-10 to -15 chroma,
+ +8 to +10 lightness) was calibrated by iterating against the card surface.
+
+3. **Stripe Dark Mode** (https://stripe.com) — reference for how a real
+ product handles chromatic identity borders on dark surfaces. Their
+ Connect onboarding uses thin colored side-bars on neutral cards — the
+ closest production equivalent to what this design proposes.
+
+---
+
+## 10. Decision Required
+
+Two open items for your approval:
+
+1. **Direction:** A (Deep Field, 2px top-edge split) or B (Constellation,
+ full diagonal outline + glyph tint + glow).
+
+2. **CTA:** Gold (`#d4a843`) as proposed, or amber-rose (`#d47a5a`) as
+ the alternative with zero zodiac overlap.
+
+Both directions use the same 22-color table and token architecture. The
+choice determines the border technique and the glyph treatment only. The
+elevation scale, color values, and CTA are shared infrastructure.
\ No newline at end of file
diff --git a/DESIGN.md b/DESIGN.md
index 7d43197..e477c91 100644
--- a/DESIGN.md
+++ b/DESIGN.md
@@ -1,30 +1,60 @@
---
-name: Zodiac Compatibility
+name: Zodiac Compatibility v2
description: >-
- A private, celestial zodiac compatibility tool — Western and Chinese astrology
- side by side under a deep-sky night canvas.
+ Private zodiac compatibility — Western and Chinese astrology under a Deep Sky canvas.
colors:
- void: "#0a0a0a"
- starlight: "#ededed"
- surface: "rgba(255,255,255,0.05)"
- surface-border: "rgba(255,255,255,0.10)"
- indigo-primary: "#4f46e5"
- indigo-deep: "#4338ca"
- nebula-indigo: "rgba(79,70,229,0.20)"
- nebula-purple: "rgba(147,51,234,0.20)"
- nebula-red: "rgba(185,28,28,0.20)"
- nebula-amber: "rgba(180,83,9,0.20)"
- emerald-glow: "rgba(5,150,105,0.20)"
- blue-glow: "rgba(37,99,235,0.20)"
- text-primary: "#ffffff"
- text-body: "#d1d5db"
- text-secondary: "#9ca3af"
- text-muted: "#6b7280"
- text-footer: "#4b5563"
- glow-indigo: "rgba(79,70,229,0.20)"
- glow-purple: "rgba(147,51,234,0.20)"
- glow-red: "rgba(185,28,28,0.20)"
- glow-amber: "rgba(180,83,9,0.20)"
+ # Elevation scale — structural surfaces (chromatic neutral, dark-only)
+ surface-page: "oklch(10% 0.002 260)"
+ surface-nav: "oklch(14% 0.002 260)"
+ surface-card: "oklch(18% 0.003 260)"
+ surface-modal: "oklch(22% 0.003 260)"
+ surface-separator: "oklch(25% 0.002 260)"
+ border-structural: "oklch(28% 0.003 260)"
+ border-ui: "oklch(35% 0.005 260)"
+ surface-hover: "oklch(26% 0.003 260)"
+ control-solid: "oklch(45% 0.004 260)"
+ control-hover: "oklch(52% 0.004 260)"
+
+ # Text
+ text-primary: "oklch(94% 0.002 260)"
+ text-body: "oklch(78% 0.002 260)"
+ text-secondary: "oklch(55% 0.002 260)"
+ text-muted: "oklch(42% 0.002 260)"
+
+ # CTA — warm gold
+ cta-fill: "oklch(75% 0.12 85)"
+ cta-fill-hover: "oklch(80% 0.12 85)"
+ cta-text: "oklch(12% 0.002 260)"
+
+ # Focus ring
+ focus-ring: "oklch(35% 0.005 260)"
+
+ # Western zodiac signs — dark-mode corrected
+ zodiac-aries: "oklch(56% 0.18 25)"
+ zodiac-taurus: "oklch(55% 0.14 145)"
+ zodiac-gemini: "oklch(82% 0.12 95)"
+ zodiac-cancer: "oklch(52% 0.12 255)"
+ zodiac-leo: "oklch(62% 0.16 55)"
+ zodiac-virgo: "oklch(48% 0.08 65)"
+ zodiac-libra: "oklch(62% 0.12 350)"
+ zodiac-scorpio: "oklch(32% 0.02 285)"
+ zodiac-sagittarius: "oklch(54% 0.15 310)"
+ zodiac-capricorn: "oklch(45% 0.015 260)"
+ zodiac-aquarius: "oklch(68% 0.08 230)"
+ zodiac-pisces: "oklch(60% 0.10 170)"
+
+ # Birth-year element — 10 Heavenly Stems (5 elements × yin/yang)
+ element-geng-metal-yang: "oklch(72% 0.03 90)"
+ element-xin-metal-yin: "oklch(58% 0.02 90)"
+ element-ren-water-yang: "oklch(42% 0.06 240)"
+ element-gui-water-yin: "oklch(38% 0.05 240)"
+ element-jia-wood-yang: "oklch(58% 0.16 140)"
+ element-yi-wood-yin: "oklch(48% 0.12 140)"
+ element-bing-fire-yang: "oklch(60% 0.20 25)"
+ element-ding-fire-yin: "oklch(50% 0.16 25)"
+ element-wu-earth-yang: "oklch(74% 0.12 90)"
+ element-ji-earth-yin: "oklch(62% 0.08 85)"
+
typography:
display:
fontFamily: "Geist, Inter, system-ui, sans-serif"
@@ -68,169 +98,65 @@ spacing:
advice-box: "12px"
components:
button-primary:
- backgroundColor: "{colors.indigo-primary}"
- textColor: "{colors.text-primary}"
+ backgroundColor: "{colors.cta-fill}"
+ textColor: "{colors.cta-text}"
rounded: "{rounded.button}"
padding: "12px 24px"
- button-primary-hover:
- backgroundColor: "{colors.indigo-deep}"
- textColor: "{colors.text-primary}"
- rounded: "{rounded.button}"
- card:
- backgroundColor: "{colors.surface}"
+ card-identity:
+ backgroundColor: "{colors.surface-card}"
textColor: "{colors.text-body}"
rounded: "{rounded.card}"
padding: "24px"
+ borderTop: "2px gradient — Western color (left 50%) + element color (right 50%)"
rating-badge:
- backgroundColor: "{colors.emerald-glow}"
- textColor: "{colors.glow-indigo}"
rounded: "{rounded.badge}"
padding: "4px 12px"
---
-# Design System: Zodiac Compatibility
-
-## Overview
-
-**Creative North Star: "Deep Sky"**
-
-The interface feels like looking up at a truly dark sky — not a flat black void, but a deep field where content emerges like starlight. The near-black canvas (`#0a0a0a`) is the baseline; everything placed on it is a deliberate point of light. Sections reveal themselves not with sharp borders but with subtle luminosity shifts — surfaces at 5% white opacity, borders at 10%, each layer a slightly brighter presence against the dark.
-
-There's always more depth than what's immediately visible. The overall assessment section uses a gradient from indigo to purple at 30% opacity, suggesting a nebular glow — the feeling that the most important content exists in a denser, warmer region of space. Rating badges glow in their own spectral colors (emerald, blue, amber, red), each a distinct celestial body. Nothing sits flat; every element carries at least one layer of depth through opacity, color temperature, or gradient.
-
-This is a system for a personal tool shared between friends. It should feel like a private observatory — sophisticated enough to trust, intimate enough to feel warm. No glassmorphism, no aggressive animations, no SaaS tropes. Just content placed carefully in a deep sky.
-
-**Key Characteristics:**
-- Dark-first, opacity-layered depth model
-- Single accent (indigo) with spectral supporting colors for semantic states
-- Gradients used sparingly at the system's emotional peak (overall assessment)
-- Generous breathing room — 24px padding on cards, 32px gaps between major sections
-- Type stays restrained: Geist Sans at a tight scale, no display excess
-- Zero box-shadows; depth is conveyed through luminosity, not elevation
-
-## Colors
-
-The palette lives on a near-black void. Primary color is indigo — the color of deep twilight sky. Supporting semantic colors (emerald, blue, amber, red) appear only in rating badges and contextual advice boxes. Each carries its own nebular glow at 20% opacity.
-
-### Primary
-- **Twilight Indigo** (`#4f46e5`): The sole action color. Buttons, links, and any element that requires a visitor's click. At hover, deepens to `#4338ca` — the sky getting darker as you move closer.
-
-### Neutral
-- **Void** (`#0a0a0a`): The page background. Not pure black — a deep charcoal that prevents eye strain on extended viewing.
-- **Starlight** (`#ededed`): Primary text on the void. High contrast, never dimmed.
-- **Surface** (`rgba(255,255,255,0.05)`): Card and container backgrounds. Present but barely there — content seems to float above the void rather than sit in boxes.
-- **Surface Border** (`rgba(255,255,255,0.10)`): Delineates card edges. Visible enough to separate surfaces, subtle enough not to frame them.
-- **Body Text** (`#d1d5db`): Primary reading text. Slightly softened from pure white for extended readability.
-- **Secondary Text** (`#9ca3af`): Supporting information, metadata, card descriptions.
-- **Muted Text** (`#6b7280`): Labels, section headers, form hints. Recedes into the void.
-- **Footer Text** (`#4b5563`): The dimmest text. Footer links, generation dates, legal copy.
-
-### Spectral Semantic Colors
-Each used exclusively in 20% opacity for its designated purpose:
-- **Emerald Glow** (`rgba(5,150,105,0.20)`): "Excellent" rating badges and backgrounds.
-- **Blue Glow** (`rgba(37,99,235,0.20)`): "Good" rating badges and backgrounds.
-- **Amber Glow** (`rgba(180,83,9,0.20)`): "Moderate" rating badges, unverified warnings.
-- **Red Glow** (`rgba(185,28,28,0.20)`): "Challenging" rating badges, Six Harming warnings.
-
-### Named Rules
-**The One Light Rule.** Only one element on any given screen uses the full-saturation indigo primary (`#4f46e5`). Everything else — cards, borders, advice boxes — stays in the opacity-layered neutral or spectral range. The primary button is the only thing that burns at full brightness.
-
-**The Nebula Rule.** Gradients (`from-indigo-900/30 to-purple-900/30`) appear on exactly one element: the overall assessment. This is the system's emotional crescendo. No other section competes with it for visual weight.
-
-## Typography
-
-**Typeface:** Geist Sans (with Inter, system-ui fallback). A modern geometric sans with clean apertures and minimal stroke contrast — readable on dark backgrounds at small sizes.
-
-**Character:** Precise but not cold. The tight scale (no display flamboyance, no decorative weights) keeps the focus on the astrology content. Letter-spacing is tightened on headings (`-0.02em`) and widened on labels (`0.05em`) for clear hierarchy scanning.
-
-### Hierarchy
-- **Display** (700, clamp(2.25rem, 6vw, 3rem), 1.1): Page-level headings. The landing page title and report header. Tight tracking for presence on the void.
-- **Headline** (700, 1.5rem, 1.3): Card titles, sign names. Bold enough to anchor each card section.
-- **Title** (600, 1.125rem, 1.4): Section headings within the report. Distinguishes compatibility sections from their advice content.
-- **Body** (400, 0.875rem, 1.6): All reading text. Max line length of ~65 characters on the widest container. Generous line-height compensates for dark-background reading fatigue.
-- **Label** (500, 0.75rem, 1.4, 0.05em tracking-wide, uppercase): Card section labels ("Western Sign", "Chinese Zodiac"), rating badge text. All-caps with tracking for micro-hierarchy within cards.
-
-## Layout
-
-Content lives in a single centered column. The landing page form is constrained to `max-w-md` (448px) for focused input; the report expands to `max-w-2xl` (672px) for comfortable reading of multi-section compatibility prose. Above the `md` breakpoint (768px), visitor profile cards split into a two-column grid (`md:grid-cols-2`). Below, everything stacks.
-
-Spacing follows a harmonic rhythm: 32px between major report sections, 24px internal card padding, 16px gaps between profile cards, 12px between content within a section. The footer sits at the bottom with minimal presence — 24px padding, footer text, no separators beyond a 5% opacity border.
-
-### Responsive
-- **Mobile (< md):** Single column, full-width. Form inputs stack vertically. Cards fill the viewport width with 16px side margins.
-- **Desktop (>= md):** Centered content at max-width, two-column profile cards. Form remains single-column for focused input.
-
-## Elevation & Depth
-
-**No shadows.** Depth is conveyed entirely through luminosity — each layer is a slightly brighter wash of white against the void. Background is `#0a0a0a`, surfaces are `5%` white, borders are `10%` white. The overall assessment section adds a gradient overlay (indigo/purple at 30%) as the deepest layer — a nebular depth suggesting this is the most important content.
-
-Hover states use color deepening (`indigo-600` → `indigo-700`) rather than shadow elevation. Interactive elements shift in hue temperature, not in perceived Z-height.
-
-**The Flat-By-Default Rule.** No element casts a shadow at rest. No element lifts on hover. The entire interface exists in one plane — depth is atmospheric, not dimensional.
-
-## Shapes
-
-**The Soft Edge Rule.** All interactive and container elements use border-radius. Nothing is sharp — the dark background makes sharp corners feel harsh. Cards at 12px (`rounded-xl`), buttons at 8px (`rounded-lg`), badges fully round (`rounded-full`). This consistent softness reinforces the "sky" metaphor — celestial bodies don't have sharp corners.
-
-Borders are present but recessive at 10% white opacity. They exist to delineate, not to frame. Advice boxes (Six Harming warnings, Wu Xing notes, friendship advice) use the same 8px radius as buttons — visually grouping them as secondary information containers.
-
-## Components
-
-### Buttons
-- **Shape:** Softly rounded (8px).
-- **Primary:** Twilight Indigo background (`#4f46e5`), white text, 12px vertical × 24px horizontal padding. The only element on the page using full-saturation color.
-- **Hover:** Deepens to `#4338ca`. Transition: background-color 150ms.
-- **Focus:** 2px indigo ring with 2px offset (`ring-2 ring-indigo-500 ring-offset-2`).
-- **Disabled:** 50% opacity, cursor not-allowed, background desaturated to `indigo-800`.
-- **Secondary/Link:** Underlined gray-400 text, no background. Hover shifts to gray-200.
-
-### Cards
-- **Corner Style:** Generously rounded (12px).
-- **Background:** `rgba(255,255,255,0.05)` — present but near-transparent.
-- **Border:** `rgba(255,255,255,0.10)` — subtle delineation.
-- **Internal Padding:** 24px on all sides.
-- **Content Spacing:** 12px vertical rhythm between internal elements.
-
-### Rating Badges
-- **Shape:** Fully round (pill), 4px vertical × 12px horizontal padding.
-- **Style:** Background and border use the matching semantic color at 20% opacity. Text uses the same color family at higher brightness (`emerald-300`, `blue-300`, `amber-300`, `red-300`).
-- **Size:** Body text size (0.875rem), medium weight.
-
-### Advice Boxes
-- **Shape:** Softly rounded (8px) — matching buttons for visual grouping.
-- **Background:** Matching semantic color at 20% opacity (`indigo-900/20`, `red-900/20`, `purple-900/20`).
-- **Border:** Matching color at 20% opacity on border channel (`indigo-500/20`, `red-500/20`, `purple-500/20`).
-- **Internal Padding:** 12px. Compact — these sit inside larger card sections.
-- **Typography:** Small body text (0.875rem) in the matching color's light variant (`indigo-200`, `red-200`, `purple-200`). Bold label prefix ("Friendship advice:", "Wu Xing:").
-
-### Inputs
-- **Style:** Surface background (`5%` white), surface border (`10%` white), 8px radius.
-- **Padding:** 12px vertical × 16px horizontal.
-- **Text:** Large (1.125rem), white, placeholder in muted gray (`#6b7280`).
-- **Focus:** 2px indigo ring, border becomes transparent.
-- **Select:** Custom dropdown arrow in SVG, matches the dark aesthetic — gray chevron on transparent background.
-
-### Overall Assessment (Signature Component)
-- **Background:** Gradient from indigo to purple at 30% opacity over the void. The only gradient in the system.
-- **Border:** Indigo at 20% opacity.
-- **Shape:** Card radius (12px).
-- **Padding:** 24px.
-- **Purpose:** The emotional and informational climax of the report. Visually distinct from every other section to signal importance.
-
-## Do's and Don'ts
-
-### Do:
-- **Do** use opacity layering for depth — `white/5` for surfaces, `white/10` for borders, `color-900/20` for semantic backgrounds.
-- **Do** keep the primary button as the only full-saturation element on screen.
-- **Do** use the indigo-to-purple gradient exclusively on the overall assessment section.
-- **Do** maintain 24px internal padding on all cards and 32px gaps between major sections.
-- **Do** round all containers: 12px for cards, 8px for buttons and advice boxes, fully round for badges.
-- **Do** use the semantic spectral colors (emerald/blue/amber/red) only for ratings and contextual warnings.
-
-### Don't:
-- **Don't** add box-shadows or elevation. Depth is luminosity, not Z-height.
-- **Don't** use glassmorphism, backdrop-blur, or frosted-glass effects. The void is the canvas.
-- **Don't** add gradients to cards, buttons, or any section other than the overall assessment.
-- **Don't** use pure white (`#ffffff`) for body text — reserve it for headings and primary buttons.
-- **Don't** use sharp corners. Every container and interactive element must be rounded.
-- **Don't** add animations or transitions beyond the 150ms background-color hover on buttons. The interface should feel still, like a night sky.
\ No newline at end of file
+# Design System: Zodiac Compatibility — v2 "Deep Field"
+
+## Token Architecture
+
+All surfaces derive from a single chromatic-neutral blue-grey ramp. Zodiac
+colors are edge accents only — never fills, never text, never large floods.
+The CTA is warm gold, the only warm element on the page.
+
+**Layer model:**
+- Base: page background (L:10%)
+- Nav: header strip (L:14%)
+- Cards: identity + content surfaces (L:18%)
+- Modal: elevated dialogs (L:22%)
+- Borders: structural (L:28%), UI/focus (L:35%)
+
+**Color model:**
+- 12 Western zodiac signs — dark-mode corrected, edge-only
+- 10 birth-year element tokens (5 elements × yin/yang)
+- 1 CTA gold — sole warm accent
+- 4 text levels (primary 94%, body 78%, secondary 55%, muted 42%)
+
+## Direction: Deep Field (Approved)
+
+A near-monochrome night sky canvas. Zodiac identity appears as a 2px
+top-edge rule on sign-identity cards, horizontally split at the midpoint:
+Western sign color on the left half, birth-year element color on the right.
+The rest of the card is elevation-only neutral. Zodiac colors appear
+nowhere else on the page.
+
+## CSS Implementation
+
+All tokens are emitted as custom properties in `src/app/tokens.css`:
+
+```css
+:root {
+ --z-surface-page: oklch(10% 0.002 260);
+ --z-surface-card: oklch(18% 0.003 260);
+ --z-border-structural: oklch(28% 0.003 260);
+ --z-cta-fill: oklch(75% 0.12 85);
+ --z-cta-text: oklch(12% 0.002 260);
+ --z-text-primary: oklch(94% 0.002 260);
+ /* ... all 22 zodiac colors, 10 elements, etc. */
+}
+```
+
+Tailwind `@theme` extends the utility scale with these tokens so they're
+available as `bg-z-surface-card`, `text-z-text-primary`, etc.
\ No newline at end of file
diff --git a/src/app/globals.css b/src/app/globals.css
index 3d48213..7e288d8 100644
--- a/src/app/globals.css
+++ b/src/app/globals.css
@@ -1,19 +1,64 @@
@import "tailwindcss";
-
-:root {
- --background: #0a0a0a;
- --foreground: #ededed;
-}
+@import "./tokens.css";
@theme inline {
- --color-background: var(--background);
- --color-foreground: var(--foreground);
+ /* Elevation */
+ --color-z-surface-page: var(--z-surface-page);
+ --color-z-surface-nav: var(--z-surface-nav);
+ --color-z-surface-card: var(--z-surface-card);
+ --color-z-surface-hover: var(--z-surface-hover);
+
+ /* Borders */
+ --color-z-border-structural: var(--z-border-structural);
+ --color-z-border-ui: var(--z-border-ui);
+
+ /* CTA */
+ --color-z-cta-fill: var(--z-cta-fill);
+ --color-z-cta-fill-hover: var(--z-cta-fill-hover);
+ --color-z-cta-text: var(--z-cta-text);
+
+ /* Text */
+ --color-z-text-primary: var(--z-text-primary);
+ --color-z-text-body: var(--z-text-body);
+ --color-z-text-secondary: var(--z-text-secondary);
+ --color-z-text-muted: var(--z-text-muted);
+
+ /* Focus */
+ --color-z-focus-ring: var(--z-focus-ring);
+
+ /* Zodiac signs */
+ --color-z-sign-aries: var(--z-sign-aries);
+ --color-z-sign-taurus: var(--z-sign-taurus);
+ --color-z-sign-gemini: var(--z-sign-gemini);
+ --color-z-sign-cancer: var(--z-sign-cancer);
+ --color-z-sign-leo: var(--z-sign-leo);
+ --color-z-sign-virgo: var(--z-sign-virgo);
+ --color-z-sign-libra: var(--z-sign-libra);
+ --color-z-sign-scorpio: var(--z-sign-scorpio);
+ --color-z-sign-sagittarius: var(--z-sign-sagittarius);
+ --color-z-sign-capricorn: var(--z-sign-capricorn);
+ --color-z-sign-aquarius: var(--z-sign-aquarius);
+ --color-z-sign-pisces: var(--z-sign-pisces);
+
+ /* Birth-year elements */
+ --color-z-el-geng-metal-yang: var(--z-el-geng-metal-yang);
+ --color-z-el-xin-metal-yin: var(--z-el-xin-metal-yin);
+ --color-z-el-ren-water-yang: var(--z-el-ren-water-yang);
+ --color-z-el-gui-water-yin: var(--z-el-gui-water-yin);
+ --color-z-el-jia-wood-yang: var(--z-el-jia-wood-yang);
+ --color-z-el-yi-wood-yin: var(--z-el-yi-wood-yin);
+ --color-z-el-bing-fire-yang: var(--z-el-bing-fire-yang);
+ --color-z-el-ding-fire-yin: var(--z-el-ding-fire-yin);
+ --color-z-el-wu-earth-yang: var(--z-el-wu-earth-yang);
+ --color-z-el-ji-earth-yin: var(--z-el-ji-earth-yin);
+
+ /* Typography — keep Geist */
--font-sans: var(--font-geist-sans);
--font-mono: var(--font-geist-mono);
}
body {
- background: var(--background);
- color: var(--foreground);
+ background: var(--z-surface-page);
+ color: var(--z-text-primary);
font-family: var(--font-sans);
}
\ No newline at end of file
diff --git a/src/app/page.tsx b/src/app/page.tsx
index e7218eb..9921920 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -8,11 +8,11 @@ export default function HomePage() {
return (