Reading all four files for an independent review of the Verdigris Gate skin and skin system.
Computing WCAG contrast ratios for Verdigris token pairs.
Checking image paths across pages and additional contrast edge cases (small text, hover states).
**Verdict:** Verdigris Gate is cleanly scoped and does not break ledger/midnight. Primary button and accent-text pass AA in both modes at rest. Real issues: small muted text on `surface-2` (including the gate-rail header), light-mode button hover, missing font weights 600/700, and stale skin-switcher copy. Confidence: **high** on tokens/contrast/JS; **medium** on live rendering (no browser pass).

---

### Ranked fix list

**1. [ERROR] `--ink-3` fails AA normal text on `surface-2` (both modes)**  
`styles.css:91,107` — Header uses `surface-2` (`styles.css:118-119`); `.brand__since` is `ink-3` at 0.66rem (`styles.css:233-234`). Also hits 0.72–0.78rem hints/captions on `surface-2`.

| Mode | Pair | Ratio | Need |
|------|------|-------|------|
| Light | `#5C6B65` / `#DFE5E1` | 4.39:1 | 4.5:1 |
| Dark | `#7A8A84` / `#25302C` | 3.77:1 | 4.5:1 |

**Corrected hex:** light `--ink-3: #4A5853` (5.84:1 on `#DFE5E1`, 6.32:1 on paper); dark `--ink-3: #8FA098` (4.97:1 on `#25302C`, 5.78:1 on surface).

---

**2. [ERROR] Font loading vs CSS weights — faux-bold on Verdigris**  
`index.html:11` loads `Fraunces:wght@400;500` and `IBM Plex Mono:wght@400;500`, but CSS uses **600–700**:

- Fraunces: `h1–h4`, `.btn`, `.brand__mark` at 600–700 (`styles.css:188-191,203,227,270`)
- IBM Plex Mono: `.tier__price`, `.calc__total .tnum`, `.trust__num` at 600–700 (`styles.css:304,360,459`)

Source Sans 3 loads 400;600 but `.nav__phone` uses `font-weight: 500` (`styles.css:240`) → synthesized medium.

**Fix:** load `Fraunces:wght@400;500;600;700`, `IBM Plex Mono:wght@400;500;600;700`, add `500` to Source Sans 3 (or change phone to 600).

---

**3. [WARN] Light primary button hover drops below AA**  
`styles.css:211` — `filter: brightness(1.05)` on `#2F7A6B` → `#F0F7F5` contrast **4.34:1** (need 4.5:1). Dark hover stays fine (7.05:1).

**At-rest button passes:** light `#F0F7F5` / `#2F7A6B` = 4.69:1; dark `#0D1614` / `#4DA896` = 6.44:1.

**Fix options:** drop hover brighten; darken hover fill to `#2A6F61` (5.45:1); or light `--on-accent: #FFFFFF` (5.10:1 rest, 4.60:1 hover).

---

**4. [WARN] `swapSkinImages` — path fragility + duplicate art**  
`app.js:63-69`

- Lookup is exact string on `data-orig-src`; resolved URLs, relative variants, or `?cache` params miss the map and stay on ledger art.
- `story.png` → `verdigris/hero.png` (`app.js:61`) duplicates hero latch on about (`about.html:66`) — likely unintentional; no dedicated `story` asset.
- `$$("img")` is broad but safe: non-mapped images restore via `orig`; `data-orig-src` caching is correct for the 3-skin cycle.
- Invalid/missing `data-skin` → `indexOf` = -1 → cycles to `ledger` (`app.js:86-87`) — OK but silent.

---

**5. [WARN] Skin switcher HTML still 2-skin**  
`index.html:46`, `calculator.html:33` — `title="Switch skin: Paper / Midnight"` while JS cycles three skins (`app.js:53-54`). `aria-label` updates at runtime; static `title` does not.

---

**6. [INFO] Double-rule inset frames — mostly fine; rate-card frame weak**  
`styles.css:124-127` — `inset 4px paper + 5px rule` on `.calc__shell`, `.rate-card`, `.contact__form`.

- `.calc__shell` / `.rate-card` have `overflow: hidden` (`styles.css:352,399`) — no scroll bleed.
- `.contact__form` has no overflow rule; inset shadows are paint-only — low risk.
- On `.rate-card`, child tiers fill the grid and likely **cover** most of the inset ring — frame may barely show. Calculator/contact are the visible wins.

---

**7. [INFO] Gate-rail header grain — no overflow concern**  
`styles.css:118-122` — Opaque `surface-2` + 3px repeating gradient; `backdrop-filter: none` correctly drops ledger glass. Subtle moiré possible on low-DPI; not a layout issue.

---

**8. [OK] Accent-as-text and muted body copy**  
Light: `--accent-ink #1F5F52` 6.31:1 on paper; `--ink-2 #3F4F49` 7.32:1 on paper.  
Dark: `--accent-ink #6BC4B0` 8.52:1 on paper; `--ink-2 #A8B5AF` 8.31:1 on paper.  
`::selection` accent/on-accent: 4.69:1 light, 6.44:1 dark.

---

**9. [OK] Ledger / Midnight isolation**  
Verdigris tokens and treatments are scoped to `html[data-skin="verdigris"]` (`styles.css:81-138`). `ledger` falls through to `:root`; `midnight` overrides stay separate (`styles.css:49-78`). Extra font families in the shared Google Fonts URL add weight for all skins but do not alter their palettes or typography tokens. Image swap only runs for `verdigris`; ledger/midnight always get `orig` src.

---

### Summary table (requested checks)

| Check | Result |
|-------|--------|
| Primary button AA | Pass at rest; light hover fail |
| Accent-as-text | Pass both modes |
| Muted text | `--ink-2` pass; `--ink-3` fail on `surface-2` |
| Font weights | Fail — load 600/700 (and 500 for Source Sans) |
| Image swap | Logic sound; path/exact-match + story duplicate |
| Double-rule / grain | No overflow; rate-card frame may be invisible |
| Other skins | Not broken |
