feat: implement Research Project PageView (v1.8) with static SSG pre-render and E2E gates

This commit is contained in:
2026-07-30 21:54:22 +09:00
parent 66fae1ebec
commit 1c772ae091
10 changed files with 623 additions and 21 deletions
+70 -5
View File
@@ -4,10 +4,10 @@
| 항목 | 내용 |
| :--- | :--- |
| **문서 ID** | `REQ-ANL-WEB-001` |
| **버전** | `1.6` |
| **버전** | `1.8` |
| **작성일** | 2026-07-30 |
| **작성자** | claude (`canary-projects-landing-page-creator-claude`) · Role: planner |
| **상태** | 승인 (Approved) — v1.5에서 **D-01** 확정(A·B안 기각 / `intl-conf` 폐기 · 3개 카테고리), v1.6에서 **D-06** 확정(레이아웃 컨테이너 3계층 분리). 잔여 미결 D-02·D-03·D-05는 🟡 등급으로 각 기본값이 적용되어 승인을 보류하지 않는다 |
| **상태** | 승인 (Approved) — v1.5에서 **D-01** 확정(A·B안 기각 / `intl-conf` 폐기 · 3개 카테고리), v1.6에서 **D-06** 확정(레이아웃 컨테이너 3계층 분리). v1.7에서 **§6.1.2 Research Project PageView** 신설 — 신규 미결 **D-07**(🔴 Funder 실데이터 부재)·**D-08**(🟡 프로젝트 집합 범위)은 각 기본값으로 구현을 차단하지 않는다. 잔여 미결 D-02·D-03·D-05는 🟡 등급으로 각 기본값이 적용되어 승인을 보류하지 않는다 |
| **대상 독자** | General Manager, Developer Team Leader(Agy), Reviewer Team Leader(Cline), 지도교수 |
| **선행 문서** | [`README.md`](./README.md), [`.agents/MULTI_AGENT_RULES.md`](./.agents/MULTI_AGENT_RULES.md), [`refer_landing_page/docs/DESIGN.md`](./refer_landing_page/docs/DESIGN.md) |
| **적용 범위** | `refer_landing_page/` (Next.js 14 App Router 애플리케이션) 전체 |
@@ -143,7 +143,7 @@ PR-03에 따라 **연구실 소개 · 주요 연구 분야 소개 · 오시는
| ID | 요구사항 | 수준 |
| :--- | :--- | :-- |
| H-01 | `app/page.tsx`를 신규 생성하고, 현행 `app/intro/page.tsx`의 섹션 구성(커버 스프레드 → 지표 카운터 → Mission 풀쿼트 → 핵심 연구 분야 → Focus Areas)을 이관한다 | MUST |
| H-02 | 커버 히어로는 현행 확정 카피를 유지한다: 킥커 `경북대학교 컴퓨터학부 · AI Agent Networking Lab (ANL)`, 헤드라인 `에이전트 네트워크의 / 미래를 짓다`, 디스플레이 `Agents / in Motion` | MUST |
| H-02 *(v1.7 개정)* | 킥커 `경북대학교 컴퓨터학부 · AI Agent Networking Lab (ANL)`는 유지한다. **슬로건 헤드라인(`에이전트 네트워크의 / 미래를 짓다`, 디스플레이 `Agents / in Motion`)은 §6.1.2 Research Project PageView로 교체할 수 있다.** 단 교체 시에도 **H-03(연구실 소개 서술 블록) · H-04(주요 연구 분야 그리드) · H-05(오시는 길) · H-06·H-07(지표 카운터) · H-10(`HeroComposition`)은 반드시 존속**한다 — 히어로 재구성 중 이들이 유실되면 **AC-02가 즉시 실패**한다 | MUST |
| H-03 | **[연구실 소개]** 연구실 개요·지도교수·비전을 서술하는 블록을 배치하고, 상세는 `/members`로 연결한다 | MUST |
| H-04 | **[주요 연구 분야]** §5의 핵심 연구 분야 전문을 매거진 조판으로 노출한다 | MUST |
| H-05 | **[오시는 길]** 아래 §6.1.1 요구사항을 충족하는 블록을 배치한다 | MUST |
@@ -168,6 +168,37 @@ PR-03에 따라 **연구실 소개 · 주요 연구 분야 소개 · 오시는
| H-17 | 주소는 시맨틱 `<address>` 요소로 마크업한다 | MUST |
| H-18 | 대중교통·주차 안내는 **레거시에 데이터가 없으므로 이번 범위에서 제외**한다. 필요 시 지도교수 확인 후 별도 잡으로 추가 | MUST |
#### 6.1.2 Research Project PageView *(v1.7 신설)*
Home의 슬로건 히어로를 **실제 연구 프로젝트 카드 뷰**로 전환한다(H-02 개정).
**레거시 실측 — 실재하는 프로젝트 3건**: `ISL-2026/index.html` `<section class="portfolio-block skills">``card-title`/`card-text` 및 이어지는 확장 섹션 2개가 유일한 원본이다. (`projects-cards` 클래스는 **표준화 기구 로고 그리드**이며 연구 프로젝트가 아니다 — 오독 주의.)
| # | Title | 확장 정보 |
| :-- | :--- | :--- |
| 1 | `IoT Standards` | — |
| 2 | `CCIS` | "This project is developing a series of standards in **IEC/TC 100/TA 17**" |
| 3 | `VLC-IoT` | "This project is purposed to develop a series of standards in **ITU-T SG20**." |
| ID | 요구사항 | 수준 |
| :--- | :--- | :-- |
| PJ-01 | 데이터는 `content/projects.ts`에 두고, 타입은 **`ResearchProject`** 로 명명한다. `StandardsBody.projects`(WG 단위 표준화 프로젝트)와 **의미가 다르므로 이름을 재사용하지 않는다** | MUST |
| PJ-02 | `content/projects.ts`**`scripts/extract/generate_all.py``parse_projects()`로 자동 생성**한다. 수작업 편집 금지(기존 `AUTO-GENERATED` 규약 · AC-24) | MUST |
| PJ-03 | `abstract`는 레거시 원문을 **바이트 동일하게 보존**한다(PR-01). 요약·재작성·`line-clamp`로 인한 정보 손실 금지 | MUST |
| PJ-04 | `period``content/standards.ts` `standardsBodies[].period`를 **조인해 도출**한다. 교차 검증 출처는 `ISL-2026/sjkoh/index.html`의 Project Editor 이력이다 | MUST |
| PJ-05 | `deliverables``content/standards.ts` `projects[].documents[]`를 **조인해 도출**한다. 임의 생성 금지 | MUST |
| PJ-06 | `keywords[]`**모든 원소는 해당 프로젝트 `abstract` 원문에 부분문자열로 실제 등장해야 한다.** 키워드 창작을 기계적으로 차단하기 위한 규칙이다 (→ AC-30) | MUST |
| PJ-07 | `funder`**옵셔널**이며 현재 전건 미확보다(§12.1 **D-07**). **값이 없으면 UI에 해당 행·라벨·자리표시자를 렌더하지 않는다**(R-9.18). 레거시가 실제로 명시하는 표준화 트랙은 `Funder`가 아닌 **`Standards Track`** 라벨로 노출한다 | MUST |
| PJ-08 **[금지]** | **활성 슬라이드만 마운트하는 캐러셀을 구현하지 않는다.** 프로젝트 전건이 항상 DOM에 존재해 정적 HTML에 포함되어야 한다(R-8.15 · AC-27) | MUST |
| PJ-09 **[금지]** | 슬라이드·페이지 상태를 **URL에 동기화하지 않는다.** `searchParams` prop은 라우트를 `ƒ Dynamic`으로 전환시키고(R-8.11), `useSearchParams()``<Suspense>` 경계를 요구하며 경계 안쪽 콘텐츠가 정적 HTML에서 누락된다(R-8.12·R-8.13). 상태는 컴포넌트 로컬로 유지한다 | MUST |
| PJ-10 **[금지]** | 캐러셀·슬라이더 **외부 라이브러리를 도입하지 않는다**(swiper·embla 등). 현행 런타임 의존성 3종(`next`/`react`/`react-dom`)을 유지한다(R-9.13) | MUST |
| PJ-11 | 트랙은 **CSS scroll-snap + 컨테이너 내부 `overflow-x-auto`** 로 구현해 **JS 비활성 상태에서도 전건 열람이 가능**해야 한다. 페이지 레벨 가로 스크롤을 유발해서는 안 되며(R-9.15·AC-19), full-bleed를 위해 `w-screen`을 쓰지 않는다(R-8.18) | MUST |
| PJ-12 | 데이터 렌더는 **서버 컴포넌트**, 인터랙션(버튼·인디케이터)만 `"use client"` 로 분리한다. 페이지네이션 인디케이터는 `<a href="#project-…">` 앵커로 두어 JS 없이도 동작하게 한다. 스크롤 애니메이션은 **`prefers-reduced-motion` 존중**(`components/Counter.tsx`·`globals.css` 선례) | MUST |
| PJ-13 *(v1.8 개정)* | 반응형 카드 노출: 360 px 1장 / `md` 2장(`w-[calc(50%-12px)]``2×(50%12px)+24px = 100%`**대수적 정확값**) / **`desktop`(1240 px)에서는 스크롤 트랙이 아니라 `desktop:grid desktop:grid-cols-3 desktop:overflow-visible` 정적 3열로 전환**하고 카드는 `desktop:w-full`로 둔다. **데스크톱 카드 폭에 퍼센트 연산을 사용하지 않는다.** 근거: Tailwind `grid-cols-3``repeat(3, minmax(0, 1fr))`로 전개되어 **min-content 넘침을 구조적으로 차단**하며, `overflow-visible`이 해당 요소를 **스크롤 컨테이너에서 해제**해 스크롤 잔재·불필요한 포커스 가능 스크롤 영역을 함께 제거한다(→ AC-34). 브레이크포인트는 `desktop` 토큰만 사용한다(R-8.20 · AC-26) | MUST |
| PJ-14 | 접근성: 트랙 `role="group"` + `aria-roledescription="carousel"`, 카드 `aria-roledescription="slide"` + `aria-label="N개 중 M번째"`, 버튼 `aria-label``aria-controls`, 카드 제목은 `<h3>` | MUST |
| PJ-15 *(v1.8 신설)* | 카드에 **`min-w-0`** 과 텍스트 줄바꿈(`break-words`, 국문은 R-9.16 `break-keep`)을 적용한다. **`flex-shrink: 0`인 플렉스 아이템은 콘텐츠의 min-content 폭 이하로 줄지 않으므로**, `standardsTrack`(`IEC/TC 100/TA 17``deliverables[].ref`(`ISO/IEC TR 30189`)처럼 `/`를 포함해 기본 줄바꿈 기회가 없는 문자열이 **폭 수식과 무관하게 트랙을 넘치게 할 수 있다.** PJ-13의 그리드 전환은 데스크톱만 보호하므로, 모바일·태블릿 구간은 이 규칙으로 보호한다 | MUST |
| PJ-16 *(v1.8 신설)* | 스크롤바를 숨기는 경우(`[scrollbar-width:none]` 등) 잔여 넘침이 **시각적 단서 없이 은폐**되므로, **AC-34 검증을 반드시 동반**한다 | MUST |
### 6.2 Members (`/members`) — PR-01 적용
**레거시 실측**: 재학 16명(교수 1 · Ph.D. 1 · Ph.D. Candidate 4 · Ph.D. Student 5 · M.S. Candidate 3 · M.S. Student 2), 졸업생 60명(2007~2026).
@@ -333,6 +364,26 @@ interface StandardsBody {
documents: { title: string; ref: string; status: DocStatus; publishedAt?: string }[];
}[];
}
// content/projects.ts (v1.7 신설 · §6.1.2)
// ⚠️ StandardsBody.projects(WG 단위 표준화 프로젝트)와 의미가 다르다. 이름 재사용 금지 (PJ-01).
interface ProjectDeliverable {
title: string; // standards.ts 문서 제목 원문
ref: string; // "IEC 63246" / "ISO/IEC TR 30189"
status: DocStatus; // 기존 유니온 재사용
}
interface ResearchProject {
slug: string; // "iot-standards" | "ccis" | "vlc-iot"
title: string; // 레거시 card-title 원문
abstract: string; // 레거시 card-text 원문 — 바이트 동일 보존 (PJ-03)
keywords: string[]; // 전 원소가 abstract 부분문자열이어야 함 (PJ-06)
standardsTrack?: string; // "IEC/TC 100/TA 17" — 레거시 확장 섹션 원문
standardsOrg?: string; // standards.ts `org` 조인 키
period?: string; // standards.ts `period` 에서 도출 (PJ-04)
deliverables: ProjectDeliverable[]; // standards.ts documents 에서 도출 (PJ-05)
funder?: string; // 현재 전건 미확보(D-07). 값 없으면 UI 미렌더 (PJ-07)
}
```
### 7.3 마이그레이션 절차
@@ -517,6 +568,16 @@ Job `343b5808` 검증에서 본문 좌우 여백·최대 폭 미적용(B1)이,
- [ ] AC-25 *(v1.6 신설 · R-8.19)* 빌드 산출 `.next/server/app/**/*.html`의 **모든 라우트**에서 `<main>` 하위에 `container-content`가 존재함을 자동 게이트로 확인. `<main>`에는 `max-w-*`/`px-*`가 **부여되지 않았음**을 함께 확인 (R-8.17)
- [ ] AC-26 *(v1.6 신설 · R-8.18·R-8.20)* 소스 전역에 `w-screen`·`-mx-[50vw]` 계열 탈출 기법과 임의값 클래스 `min-[1240px]:` 사용이 **0건**임을 grep으로 확인
**Research Project PageView (v1.7 신설 · §6.1.2)**
- [ ] AC-27 *(PJ-08 · R-8.15)* `content/projects.ts` **전건**의 `title`·`abstract``.next/server/app/index.html` **정적 HTML에 존재**함을 확인
- [ ] AC-28 *(PJ-09)* Home 라우트가 여전히 `○ (Static)`이며 빌드 전체에 `ƒ (Dynamic)`**0건**
- [ ] AC-29 *(PJ-03 · PR-01)*`abstract`가 레거시 원문과 **바이트 동일**함을 파서 재실행으로 확인
- [ ] AC-30 *(PJ-06)* 모든 `keywords[]` 원소가 해당 `abstract`의 **부분문자열**임을 `verify_counts.py`로 확인 (창작 차단)
- [ ] AC-31 *(PJ-07 · R-9.18)* `funder``undefined`인 프로젝트에 대해 산출 HTML에 `Funder` 라벨·자리표시자가 **렌더되지 않음**을 확인
- [ ] AC-32 *(PJ-05)* 모든 `deliverables[].ref``content/standards.ts`에 실재하는 문서 참조와 일치함을 조인 검증
- [ ] AC-33 *(H-02 개정 · AC-02 회귀 방어)* 히어로 재구성 후에도 **연구실 소개 서술 블록 · 주요 연구 분야 그리드 · 오시는 길 · 지표 카운터 3종 · `HeroComposition`** 이 Home 정적 HTML에 **전부 존속**함을 확인
- [ ] AC-34 *(v1.8 신설 · PJ-13·PJ-15·PJ-16)* 프로젝트 트랙의 넘침을 **브라우저 실측 수치로 판정**한다 — 데스크톱(≥1240 px)에서 `track.scrollWidth === track.clientWidth`(스크롤 잔재 **0**), 모바일·태블릿에서는 `scrollWidth > clientWidth`**정상 동작**이다. 어느 뷰포트에서도 **문서 레벨** 가로 스크롤은 0이어야 한다(AC-19 · R-9.15). 데스크톱 3카드 폭의 서브픽셀 거동은 브라우저 없이는 확정할 수 없으므로 **이 단정으로 판정을 이관**한다
---
## 11. 구현 계획 (Implementation Plan)
@@ -560,6 +621,8 @@ Publications(P4)는 데이터 규모(223건)와 필터·점진적 노출 요구
| **D-04** | 졸업생 기본 노출 범위(N년) | 🟢 위임 | 최근 3년 | M-06. 구현자 재량 |
| **D-05** | 연구실 GitHub 조직명(`github.com/iot-standards-laboratory`) 개명 여부 | 🟡 미결 | 현행 URL 유지 | 조직명이 구 정체성. 개명 시 기존 링크 무효화 위험 |
| **D-06** | 본문 여백·최대 폭 컨테이너를 **어느 계층에 부여**할 것인가 | ✅ **확정** (v1.6, 2026-07-30) | — | **결정: `<main>` 일괄 부여안 기각 → 라우트 래퍼 방식 + 자동 게이트 채택.** Planner 초안(`<main>``container-content`)은 1행 수정·누락 불가라는 장점이 있으나, 개발 팀장 이의제기(Job `2560771b`)대로 **full-bleed 밴드·마퀴 티커를 구조적으로 차단**한다. 래퍼 방식의 유일한 약점(신규 라우트 누락)은 **AC-25 게이트로 상쇄**되므로 래퍼 방식이 우월하다. → R-8.17~R-8.19 |
| **D-07** | Research Project 카드의 **`Funder/Sponsor` 실데이터 확보** 여부 | 🔴 **미결** | `funder` 미노출 + 실존하는 `Standards Track` 표기 | PJ-07. `ISL-2026/` 전체를 `과제·연구비·IITP·NRF·한국연구재단·정보통신기획평가원` 등으로 검색해 **0건**이다. **임의 생성은 MG-05·R-9.17·R-9.18 위반이며 실명·실제 이메일이 게시되는 페이지이므로 절대 불가.** 기본값으로 **구현 차단은 아니며**, 지도교수가 사업명·부처·기간을 제공하면 `content/projects.ts` 재생성만으로 반영된다 |
| **D-08** | Research Project 집합의 **정체성 범위** — 레거시 3건(IoT/CCIS/VLC)만인지, ANL 신규 과제를 포함할지 | 🟡 미결 | 레거시 3건 노출, 섹션 라벨 `Research Projects` | 레거시 3건은 IoT 시대 실적이고 현 정체성은 ANL이다. 신규 과제 추가는 지도교수 입력이 필요하다(MG-05). 레거시 3건 비노출은 PR-01에 역행하므로 배제 |
#### D-01 상세
@@ -646,6 +709,8 @@ PR-04에 명시된 4개 라벨 중 **1번과 2번의 범위가 논리적으로
| 1.1 | 2026-07-30 | claude (planner) | 개발 팀장(Agy) 기술 이의제기(Job `175860e4`) 반영. **§8.5 Next.js 렌더링 제약 신설**(실측 5종). IA-03을 라우트 세그먼트 방식으로 개정, P-06 개정 + P-06a·P-07a 신설, DM-03·NF-03·AC-05·AC-16 문구 정정, AC-22~24 및 R-08·R-09 신설. Job `45d05868` |
| 1.2 | 2026-07-30 | agy (creator) | 교차 리뷰 리포트(Job `3820bdc8`) 결함 피드백 전면 반영. **F1 §4.1 사이트맵 쿼리 표기를 라우트 세그먼트(`/publications/<slug>`)로 갱신**, **F2 §2.1·§2.2 연구 실적 수치 279건 → 223건 정정**, **F3 §10 수용 기준 AC-14~24 순서 및 그룹핑 정돈**. Job `f3e09780` |
| 1.3 | 2026-07-30 | agy (creator) | 교차 리뷰 리포트(Job `60c92d3a`) 결함 피드백 전면 반영. **G-1 417행 R-8.16 참조 AC-16 → AC-17 정정**, **G-4 575행 R-03 참조 AC-19 → AC-20 정정**, **G-2 576행 R-08 참조 AC-16/22/23 → AC-17/21/22 정정**, **G-3 577행 R-09 참조 AC-24 → AC-14 정정**. Job `a535ce20` |
| 1.6 | 2026-07-30 | claude (planner) | 개발 팀장(Agy) 기술 이의제기(Job `2560771b`) 반영. **§8.6 레이아웃 컨테이너 아키텍처·브레이크포인트 토큰 신설**(R-8.17~R-8.20) — `<main>` 일괄 부여안을 기각하고 3계층 분리(전체 폭 `<main>` / 라우트 래퍼 `container-content` / full-bleed 밴드)를 채택, `w-screen` 탈출 기법 금지(R-8.18) 및 `desktop: 1240px` 스크린 토큰화(R-8.20, Tailwind 정렬 동작 실측 확인). **D-06 신설·확정**, **AC-25·AC-26 신설**, R-9.14 검수 뷰포트 6종으로 확대. AC-21 정적 HTML 4개 → 3개, R-8.15 표준 문서 55 → 44건 실측치 정정. Job `019b7331` |
| 1.5 | 2026-07-30 | claude (planner) | **D-01 확정 및 문서 상태 `승인(Approved)` 전환.** commit `51aae14`(백로그 4건 반영)에 대한 검증 결과를 정본에 동기화: `intl-conf` 단독 카테고리 폐기(A·B안 기각, C안 채택 — §12.1 D-01 상세에 결정 근거 기록), §4.1 사이트맵·§7 `PubCategory` 유니온·P-01·P-03·IA-03·§11 P0 갱신, 사이트맵의 학기(45)·표준 문서(44) 실측치 정정. Job `343b5808` |
| 1.4 | 2026-07-30 | agy (creator) | 구현 교차 리뷰 리포트(Job `777c3ab8`) 피드백 전면 반영. **I1 전 파서 ISO 8601 정규화 100%**, **I2 Footer 주소/이메일 실주소 교체**, **I3 README 라우트 맵 갱신**, **I4 verify_counts.py 엄격 게이트로 강화 및 실측 수치(표준 44, 학기 45) 정정**, **I5 __pycache__ 제거 및 .gitignore 차단**, **I6/I7 Home 카운터 및 5대 기둥 영문 라벨 정본 정렬**. Job `a54723ce` |
| 1.5 | 2026-07-30 | claude (planner) | **D-01 확정 및 문서 상태 `승인(Approved)` 전환.** commit `51aae14`(백로그 4건 반영)에 대한 검증 결과를 정본에 동기화: `intl-conf` 단독 카테고리 폐기(A·B안 기각, C안 채택 — §12.1 D-01 상세에 결정 근거 기록), §4.1 사이트맵·§7 `PubCategory` 유니온·P-01·P-03·IA-03·§11 P0 갱신, 사이트맵의 학기(45)·표준 문서(44) 실측치 정정. Job `343b5808` |
| 1.6 | 2026-07-30 | claude (planner) | 개발 팀장(Agy) 기술 이의제기(Job `2560771b`) 반영. **§8.6 레이아웃 컨테이너 아키텍처·브레이크포인트 토큰 신설**(R-8.17~R-8.20) — `<main>` 일괄 부여안을 기각하고 3계층 분리(전체 폭 `<main>` / 라우트 래퍼 `container-content` / full-bleed 밴드)를 채택, `w-screen` 탈출 기법 금지(R-8.18) 및 `desktop: 1240px` 스크린 토큰화(R-8.20, Tailwind 정렬 동작 실측 확인). **D-06 신설·확정**, **AC-25·AC-26 신설**, R-9.14 검수 뷰포트 6종으로 확대. AC-21 정적 HTML 4개 → 3개, R-8.15 표준 문서 55 → 44건 실측치 정정. Job `019b7331` |
| 1.7 | 2026-07-30 | claude (planner) | Home Hero → Research Project PageView 전환 계획 반영. **§6.1.2 신설**(PJ-01~PJ-14) — 레거시 실재 프로젝트 3건(IoT Standards·CCIS·VLC-IoT) 확인, `period`·`deliverables``content/standards.ts` 조인으로 도출하는 무창작 설계, 활성 슬라이드 전용 캐러셀 금지(PJ-08)·URL 상태 동기화 금지(PJ-09)·캐러셀 라이브러리 금지(PJ-10)·scroll-snap 기반 JS-off 동작 보장(PJ-11) 규정. **H-02 개정**(슬로건 교체 허용 + H-03·H-04·H-05·H-06·H-07·H-10 존속 명시). **AC-27~AC-33 신설**, §7 `ResearchProject`·`ProjectDeliverable` 타입 추가, **D-07·D-08 신설**. Job `6b3840a1` |
| 1.8 | 2026-07-30 | claude (planner) | 개발 팀장(Agy) 기술 이의제기(Job `2299a6b9`) 반영. **PJ-13 개정** — 데스크톱 3카드를 flex 스크롤 트랙에서 **`grid-cols-3` 정적 3열 + `overflow-visible`** 로 전환하고 데스크톱 퍼센트 연산을 제거. **PJ-15·PJ-16 신설**(`min-w-0`+줄바꿈으로 `shrink-0` min-content 넘침 방어 / 스크롤바 은폐 시 AC-34 동반 의무), **AC-34 신설**(데스크톱 `scrollWidth === clientWidth` 실측 판정). 이의제기의 근거 수식은 정정 — `calc(33.333%-16px)`은 초과가 아니라 **0.0125 px 미달**이며, 대안 B의 분수식은 여유가 0이어서 해당 실패 모드에 오히려 더 취약하다. Tailwind가 `calc` 연산자 공백을 자동 삽입함과 `grid-cols-3``minmax(0,1fr)` 전개·미디어 쿼리 출력 순서를 실측 확인. Job `294570ab` |