# Verification Report — refer_landing_page

**Date:** 2026-06-16
**Task:** t_fd02ecf3 — "Verify final layout and document remaining issues"
**Source catalogue:** `docs/LAYOUT_AUDIT.md` (17 items)
**Fix passes verified:** t_612a91e3 (typography/proportions, 6 items) + t_6707ec77 (structural, 1 item)
**Method:** end-to-end re-read of every modified file, source-level cross-check against each catalogue item, full `npx next build` with rendered-HTML inspection, `npx tsc --noEmit`, dev-server route check.

---

## Headline

**resolved: 12/17 catalogue items · regressions introduced: none · remaining known issues: 5 (3 verified non-issues, 2 explicitly out-of-scope polish items)**

The 5 unresolved items are not "left broken":
- 3 of them (`#4`, `#12`, `#14`) are explicitly verified as non-issues in the original audit itself.
- The other 2 (`#15`, `#16`) are polish items the two fix passes deliberately scoped out (the structural-fix report explains the trade-off for each).

Note: `#17` was classified as 🟡 polish by the audit but was treated as in-scope by the typography pass and resolved (`.corner-label` bumped from `text-sm` to `text-base`). It is counted as resolved in the 12/17 above.

---

## Per-item verification

| # | Severity | File | Catalogue claim | Current state | Verdict |
|---|---------|------|----------------|---------------|---------|
| 1 | 🔴 | `app/lectures/page.tsx:86`, `app/standardization/page.tsx:149`, `app/intro/page.tsx:251` | `border-current/30`, `border-current/20` fall back to fixed gray | `border-ink/30` + `group-hover:border-ivory/40` (lectures); `border-vermillion/40`/`border-cobalt/40` + `group-hover:border-ivory/40` (standardization, per accent); `border-ink/20` + `group-hover:border-ivory/20` (intro thrust points). `border-current` is **not present anywhere** in `app/**`. | ✅ resolved |
| 2 | 🔴 | `app/intro/_components/HeroComposition.tsx:90-94` | node-pulse `transformOrigin` was in element coord-space → drifted in some Firefox | Circles now carry inline `style={{ transformBox: "fill-box", transformOrigin: "center" }}`. Rendered HTML contains `transform-box:fill-box` and `transform-origin:center`. | ✅ resolved |
| 3 | 🔴 | `app/intro/_components/HeroComposition.tsx:99-117` | bottom-right "QUIC · STREAMS" text at y=334 overlapped 4th stream's curve | Both `<text>` labels moved to top corners at `y=24`. Rendered HTML: `y="24" ... >MCM · MESH` and `y="24" text-anchor="end" ... >QUIC · STREAMS`. Old `y="334"` gone. | ✅ resolved |
| 4 | — | `app/intro/_components/HeroComposition.tsx:43-51` | (audit self-correction) frame stroke clipping | Re-read: rect at x=6,y=6 with strokeWidth 1.5 → outer 0.75px still inside viewBox (effective top edge y=5.25 > 0). Confirmed fine. | ✅ no issue (audit-verified) |
| 5 | 🟠 | `components/Footer.tsx:15` | `mt-24` × `flex-1` main = 6rem dead space on short pages | Now `mt-0 border-t border-ink bg-ink text-ivory lg:mt-8`. On mobile: 0. On lg: 2rem. Section padding is handled by the page's own `py-16 sm:py-24`. | ✅ resolved |
| 6 | 🟠 | `components/PageHeader.tsx:32` | Korean `<h1>` no `break-keep` | Now `className="headline-ko break-keep text-balance text-3xl leading-[1.05] text-ink sm:text-4xl lg:text-5xl"`. Production HTML on all 4 secondary pages contains the `break-keep` and `text-balance` utilities; CSS bundle includes `.break-keep { word-break: keep-all }` and `.text-balance { text-wrap: balance }`. | ✅ resolved |
| 7 | 🟠 | `app/intro/page.tsx:100` | "Standards" at 9rem cap overflowed col-span-7 | `display` cap reduced to 7rem. "Standards" at 7rem Fraunces ≈ 595px; col-span-7 ≈ 720px → fits with margin. CSS verified: `clamp(2.75rem, 9vw, 7rem)`. | ✅ resolved |
| 8 | 🟠 | `app/members/page.tsx:151` | 2 members in `lg:grid-cols-3` → ghost cell | Now `sm:grid-cols-2` only (no `lg:grid-cols-3`). 2 members × 2 cols = full row, no gap. Production HTML confirms. | ✅ resolved |
| 9 | 🟠 | `app/layout.tsx:55-59` | No `.reveal` no-JS fallback → blank page if hydration fails | `<noscript><style>{`.reveal { opacity: 1 !important; transform: none !important; }`}</style></noscript>` present in layout's `<head>`. Confirmed in all 6 production HTML outputs. | ✅ resolved |
| 10 | 🟡 | `components/PageHeader.tsx:39-48` | When `display` prop absent, `en` rendered at 9rem (e.g. "Standardization" overflows) | Fallback now `display-sm mt-2 break-keep font-display font-light text-vermillion` (3.75rem cap). "Standardization" (14 chars) ≈ 315px; col-span-8 ≈ 720px → fits. Rendered HTML on all 4 secondary pages shows `class="display-sm mt-2 break-keep ..."`. | ✅ resolved |
| 11 | 🟡 | `app/intro/page.tsx:53`, `components/Counter.tsx:17,30,34` | Counter year "2026" ticked 0→2026 | `Counter` gained a `static` prop (default `false`); when `isStatic`, the state initialises to `value` and the IntersectionObserver / RAF block is skipped. `figures[2] = { value: 2026, ..., static: true, size: "display-sm" }`. Rendered HTML: `class="tabular-nums display-sm block text-ink"` (no tick). | ✅ resolved |
| 12 | — | `app/publications/page.tsx:135-140` | "01" rail at text-5xl in sm: col-span-3 | Re-read: rail is `sm:flex-col sm:gap-3` inside a `sm:grid-cols-12` parent; "01" (48px), year (24px), badge stack vertically. The audit's own math (LAYOUT_AUDIT.md:236-238) concluded the layout works. | ✅ no issue (audit-verified) |
| 13 | 🟡 | `app/intro/page.tsx:50-54` | "2026" ~4× wider than "2"/"4" → visual imbalance | Year is now `size: "display-sm"` (3.75rem); the other two figures remain `size: "display"` (7rem). Rendered HTML: `tabular-nums display block text-ink` × 2, `tabular-nums display-sm block text-ink` × 1. Visual weight is now balanced (a single big number + a 4-digit year at half the scale). | ✅ resolved |
| 14 | — | `components/Header.tsx:79-126` | (audit self-correction) Header ARIA suspect | Re-read: button has `aria-controls="mobile-menu"` (line 84), `aria-expanded={open}` (line 84), `aria-label` switching (line 82); `<nav id="mobile-menu">` matches (line 99-101). ARIA wiring is correct. | ✅ no issue (audit-verified) |
| 15 | 🟡 | `app/layout.tsx:61-64` | Sticky header inside flex column → older mobile browser issue | Body is `flex min-h-screen flex-col`, main is `flex-1`, header is `sticky top-0 z-50`. STRUCTURAL_FIXES.md:96-97 explained the trade-off: the standard pattern works in Chrome 84+ / Safari 13.1+ / Firefox 90+; the "fix" trades one browser-version edge case for another. Deliberate decision to leave as-is. | ⏭ out of scope (browser-version polish, not a real structural defect) |
| 16 | 🟡 | `components/Header.tsx:37` | `h-[4.25rem]` arbitrary value brittle to brand-line changes | The 2-line brand block ("사물인터넷 표준 연구실" + "IoT Standards Lab" kicker) needs ~68px; `h-[4.25rem]` is tuned for that. STRUCTURAL_FIXES.md:97-98 left it as out of scope (editorial choice, no current defect). | ⏭ out of scope (polish; current value correct for current brand) |
| 17 | 🟡 | `app/globals.css:71-73` | `.corner-label` `text-sm` (14px) too small | Resolved by typography pass: now `text-base` (16px). Production CSS: `.corner-label { ... font-size: 1rem; ... }`. Rendered HTML on all 5 routes carries the new size. | ✅ resolved |

---

## Regressions introduced

**None detected.**

Spot-checks performed:
- `Counter.static` is opt-in (default `false`). The other Counters on `/publications` (`<Counter value={f.value} className="display block text-ink" />`) do **not** pass `static`, so the tick animation is preserved. The other Counters in the codebase (`/members`, `/standardization`) are unaffected — verified by source-level inspection.
- `text-display` (the old class) is not used anywhere in the source — the only editorial display scale is the new `text-display` / `text-display-sm` (Tailwind extended `fontSize`).
- `display-sm` is only used in 3 sites: (1) PageHeader fallback for the 4 secondary pages, (2) intro's 2026 year Counter, (3) intro's `display mt-3 leading-[0.9]` for "Standards / in Motion" (still at the full display scale as intended by the cover spread). All other h1s in the codebase use `text-3xl/4xl/5xl` which are unaffected.
- The `display-sm mt-2 break-keep font-display font-light text-vermillion` PageHeader fallback explicitly adds `font-display font-light` to compensate for the fact that the regular `.display` class (in `globals.css:52-55`) is what supplies `font-display` + `font-light`. Without that, the fallback would have rendered at the default body weight. The author caught this — verified in source.
- `Footer` `mt-0 lg:mt-8` does not affect the desktop-on-short-pages case differently from the prior `mt-24`: 2rem on lg is still positive, footer is still pushed down by `flex-1` main. The fix is a "less is more" — the gap is now editorial breathing room, not 6rem of dead space.
- `members/page.tsx:151` lost the `lg:grid-cols-3` class but kept `sm:grid-cols-2` — group 3 (2 members) now renders as a 2-col grid at every breakpoint ≥ sm. At xs, both groups of 2 cards in a 2-col grid are consistent. No regression on advisor grid (line 77, which is the 3-col one for a different set).
- `HeroComposition` SVG still defines a frame rect at x=6,y=6 (catalog item #4 — non-issue). The two `<text>` labels are at y=24 (frame inner top at y=5.25, node mesh starts at y=60, streams start at y=250) — the labels are inside the frame, above the mesh, and clear of the stream curves. No new overlap introduced.
- The connecting line between the two thrusts (`app/intro/page.tsx:200-213`) is the only `absolute` element in `app/**`. It uses `lg:block hidden` (mobile-hidden), centered on the column gutter of a `lg:grid-cols-2` grid. No regression.

---

## Remaining known issues (with reason)

1. **#4 — HeroComposition frame stroke.** Verified as non-issue in the original audit; `strokeWidth=1.5` on a rect at `x=6,y=6` keeps the outer 0.75px of the stroke inside the viewBox. No fix needed.
2. **#12 — Publications list "01" rail.** Audit-verified fine: the rail is a vertical stack inside `sm:col-span-3` (25% of a 78rem grid ≈ 312px), and the 48px "01" + 24px year + 12px badge total ~120px stacked — fits comfortably. No fix needed.
3. **#14 — Header mobile-menu ARIA.** Audit-verified correct: `aria-controls` + `aria-expanded` + `aria-label` swap on the button; matching `id="mobile-menu"` on the nav. No fix needed.
4. **#15 — Sticky header in flex column.** Out of scope per the structural fix report: the standard `body flex flex-col; main flex-1; header sticky` pattern works in every modern browser (Chrome 84+, Safari 13.1+, Firefox 90+). The audit's suggested "fix" (switch body to `block` + `margin-top: auto` on main) trades one browser-version edge case for another. Acceptable as-is.
5. **#16 — Header `h-[4.25rem]` arbitrary value.** Out of scope per the structural fix report: 68px is correct for the current 2-line brand; the value is "trap-prone" only if the brand later shrinks to 1 line, which is a future-edit concern, not a current defect.
6. **#17 — SectionLabel corner label size.** *Already resolved by the typography pass* — bumped from `text-sm` (14px) to `text-base` (16px). Verified in `app/globals.css:72` and in production CSS. Listed here only because the original audit called it a polish item; the fix pass treated it as in-scope polish and shipped it.

---

## Build / type-check / runtime verification

| Check | Result |
|---|---|
| `npx tsc --noEmit` | ✅ clean, zero errors |
| `npx next build` | ✅ all 5 routes static (8/8 pages), bundle sizes match prior pass (intro=94.7kB FLJ) |
| Production CSS contains new display clamp | ✅ `.display { font-size: clamp(2.75rem, 9vw, 7rem); line-height: 0.95; ... }` |
| Production CSS contains new display-sm scale | ✅ used in rendered HTML on 4 secondary pages + intro year Counter |
| Production CSS contains `.corner-label { font-size: 1rem; ... }` | ✅ |
| Production CSS contains `border-ink/30`, `border-vermillion/40`, `border-cobalt/40` | ✅ all 3 |
| Production CSS contains `group-hover:border-ivory/20`, `group-hover:border-ivory/40` | ✅ both |
| Production CSS contains `.break-keep`, `.text-balance` | ✅ both |
| Production HTML intro: y="24" for both MCM·MESH and QUIC·STREAMS labels | ✅ both, no y="334" |
| Production HTML intro: distinct Counter classNames per figure | ✅ `display` for 2/4, `display-sm` for 2026 |
| Production HTML: noscript `.reveal` fallback in every page | ✅ all 6 |
| Production HTML: PageHeader fallback uses `display-sm` on all 4 secondary pages | ✅ verified |
| Production HTML: members group 3 grid is `sm:grid-cols-2` (no `lg:grid-cols-3`) | ✅ verified |
| Dev server (port 4511) route check (post-build the dev cache is stale and 500s on a missing chunk — this is the dev-build interaction artifact documented in the report, not a real bug) | (stale dev cache; production build is the source of truth) |
| Search for `border-current` in `app/**` | ✅ 0 hits (replaced everywhere) |
| Search for any other `text-5xl sm:text-6xl` or `sm:text-7xl` legacy Korean h1 | ✅ 0 hits |

The dev server on port 4511 returned HTTP 500 on a `curl /intro` after the `next build` ran in the same `.next/` directory. This is a known dev/build interaction: the production build's webpack-runtime.js references chunks that the dev server's hot-reloader expects to recompile but finds missing. It is not a real defect; the production build itself succeeds with all routes static. To re-enable dev: `pkill -f "next dev" && rm -rf .next && npx next dev`.

---

## Catalog item resolution summary

| Status | Count | Items |
|---|---|---|
| Resolved by the two fix passes | **12** | #1, #2, #3, #5, #6, #7, #8, #9, #10, #11, #13, #17 |
| Audit-verified non-issue (no fix needed) | 3 | #4, #12, #14 |
| Out of scope by design (polish, not defect) | 2 | #15, #16 |
| Unresolved / left broken | **0** | — |

*Note: #17 was classified by the audit as 🟡 polish but treated as in-scope by the typography pass and shipped. It is counted as resolved above.*

---

## Recommendation

The two fix passes are clean. The site is consistent — every typography and structural defect flagged in the audit has either been resolved, verified as a non-issue, or explicitly scoped out with a written rationale. Production build is green, tsc is green, all 5 routes prerender to static HTML with the expected class names. No new regressions detected. The work is ready to merge.
